1 /////////////////////////////////////////////////////////////////////////////
2 // Name: treelistctrl.cpp
3 // Purpose: multi column tree control implementation
4 // Author: Robert Roebling
5 // Maintainer: Otto Wyss
7 // RCS-ID: $Id: treelistctrl.cpp,v 1.4 2009/03/20 14:43:12 davila Exp $
8 // Copyright: (c) 2004 Robert Roebling, Julian Smart, Alberto Griggio,
9 // Vadim Zeitlin, Otto Wyss
11 /////////////////////////////////////////////////////////////////////////////
13 // ===========================================================================
15 // ===========================================================================
17 // ---------------------------------------------------------------------------
19 // ---------------------------------------------------------------------------
24 #if defined(__GNUG__) && !defined(__APPLE__)
25 #pragma implementation "treelistctrl.h"
30 #include <wx/treebase.h>
32 #include <wx/textctrl.h>
33 #include <wx/imaglist.h>
34 #include <wx/settings.h>
35 #include <wx/dcclient.h>
36 #include <wx/dcscreen.h>
37 #include <wx/scrolwin.h>
42 //#include "wx/treelistctrl.h"
43 #include "treelistctrl.h"
46 #include "wx/mac/private.h"
50 // ---------------------------------------------------------------------------
52 // ---------------------------------------------------------------------------
56 #if !wxCHECK_VERSION(2, 5, 0)
57 WX_DEFINE_ARRAY(wxTreeListItem *, wxArrayTreeListItems);
59 WX_DEFINE_ARRAY_PTR(wxTreeListItem *, wxArrayTreeListItems);
62 #include <wx/dynarray.h>
63 WX_DECLARE_OBJARRAY(wxTreeListColumnInfo, wxArrayTreeListColumnInfo);
64 #include <wx/arrimpl.cpp>
65 WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo);
67 #if !wxCHECK_VERSION(2, 3, 3)
68 WX_DEFINE_ARRAY(short, wxArrayShort);
72 // --------------------------------------------------------------------------
74 // --------------------------------------------------------------------------
76 static const int NO_IMAGE = -1;
78 static const int LINEHEIGHT = 10;
79 static const int LINEATROOT = 5;
80 static const int MARGIN = 2;
81 static const int MININDENT = 16;
82 static const int BTNWIDTH = 9;
83 static const int BTNHEIGHT = 9;
84 static const int EXTRA_WIDTH = 4;
85 static const int EXTRA_HEIGHT = 4;
86 static const int HEADER_OFFSET_X = 1;
87 static const int HEADER_OFFSET_Y = 1;
89 static const int DRAG_TIMER_TICKS = 250; // minimum drag wait time in ms
90 static const int FIND_TIMER_TICKS = 500; // minimum find wait time in ms
91 static const int RENAME_TIMER_TICKS = 250; // minimum rename wait time in ms
93 const wxChar* wxTreeListCtrlNameStr = _T("treelistctrl");
95 static wxTreeListColumnInfo wxInvalidTreeListColumnInfo;
98 // ---------------------------------------------------------------------------
100 // ---------------------------------------------------------------------------
101 //-----------------------------------------------------------------------------
102 // wxTreeListHeaderWindow (internal)
103 //-----------------------------------------------------------------------------
105 class CREAIMAGEIO_EXPORT wxTreeListHeaderWindow : public wxWindow
108 wxTreeListMainWindow *m_owner;
109 const wxCursor *m_currentCursor;
110 const wxCursor *m_resizeCursor;
113 // column being resized
116 // divider line position in logical (unscrolled) coords
119 // minimal position beyond which the divider line can't be dragged in
123 wxArrayTreeListColumnInfo m_columns;
125 // total width of the columns
126 int m_total_col_width;
130 wxTreeListHeaderWindow();
132 wxTreeListHeaderWindow( wxWindow *win,
134 wxTreeListMainWindow *owner,
135 const wxPoint &pos = wxDefaultPosition,
136 const wxSize &size = wxDefaultSize,
138 const wxString &name = _T("wxtreelistctrlcolumntitles") );
140 virtual ~wxTreeListHeaderWindow();
142 void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
144 void AdjustDC(wxDC& dc);
146 void OnPaint( wxPaintEvent &event );
147 void OnMouse( wxMouseEvent &event );
148 void OnSetFocus( wxFocusEvent &event );
150 // total width of all columns
151 int GetWidth() const { return m_total_col_width; }
153 // column manipulation
154 int GetColumnCount() const { return m_columns.GetCount(); }
156 void AddColumn (const wxTreeListColumnInfo& colInfo);
158 void InsertColumn (int before, const wxTreeListColumnInfo& colInfo);
160 void RemoveColumn (int column);
162 // column information manipulation
163 const wxTreeListColumnInfo& GetColumn (int column) const{
164 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
165 wxInvalidTreeListColumnInfo, _T("Invalid column"));
166 return m_columns[column];
168 wxTreeListColumnInfo& GetColumn (int column) {
169 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
170 wxInvalidTreeListColumnInfo, _T("Invalid column"));
171 return m_columns[column];
173 void SetColumn (int column, const wxTreeListColumnInfo& info);
175 wxString GetColumnText (int column) const {
176 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
177 wxEmptyString, _T("Invalid column"));
178 return m_columns[column].GetText();
180 void SetColumnText (int column, const wxString& text) {
181 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
182 _T("Invalid column"));
183 m_columns[column].SetText (text);
186 int GetColumnAlignment (int column) const {
187 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
188 wxALIGN_LEFT, _T("Invalid column"));
189 return m_columns[column].GetAlignment();
191 void SetColumnAlignment (int column, int flag) {
192 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
193 _T("Invalid column"));
194 m_columns[column].SetAlignment (flag);
197 int GetColumnWidth (int column) const {
198 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
199 -1, _T("Invalid column"));
200 return m_columns[column].GetWidth();
202 void SetColumnWidth (int column, int width);
204 bool IsColumnEditable (int column) const {
205 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
206 false, _T("Invalid column"));
207 return m_columns[column].IsEditable();
210 bool IsColumnShown (int column) const {
211 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
212 true, _T("Invalid column"));
213 return m_columns[column].IsShown();
220 // common part of all ctors
223 void SendListEvent(wxEventType type, wxPoint pos);
226 // DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow)
227 DECLARE_CLASS(wxTreeListHeaderWindow)
228 DECLARE_EVENT_TABLE()
232 // this is the "true" control
233 class wxTreeListMainWindow: public wxScrolledWindow
238 wxTreeListMainWindow() { Init(); }
240 wxTreeListMainWindow (wxTreeListCtrl *parent, wxWindowID id = -1,
241 const wxPoint& pos = wxDefaultPosition,
242 const wxSize& size = wxDefaultSize,
243 long style = wxTR_DEFAULT_STYLE,
244 const wxValidator &validator = wxDefaultValidator,
245 const wxString& name = _T("wxtreelistmainwindow"))
248 Create (parent, id, pos, size, style, validator, name);
251 virtual ~wxTreeListMainWindow();
253 bool Create(wxTreeListCtrl *parent, wxWindowID id = -1,
254 const wxPoint& pos = wxDefaultPosition,
255 const wxSize& size = wxDefaultSize,
256 long style = wxTR_DEFAULT_STYLE,
257 const wxValidator &validator = wxDefaultValidator,
258 const wxString& name = _T("wxtreelistctrl"));
263 // return true if this is a virtual list control
264 bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL); }
266 // get the total number of items in the control
267 size_t GetCount() const;
269 // indent is the number of pixels the children are indented relative to
270 // the parents position. SetIndent() also redraws the control
272 unsigned int GetIndent() const { return m_indent; }
273 void SetIndent(unsigned int indent);
275 // see wxTreeListCtrl for the meaning
276 unsigned int GetLineSpacing() const { return m_linespacing; }
277 void SetLineSpacing(unsigned int spacing);
279 // image list: these functions allow to associate an image list with
280 // the control and retrieve it. Note that when assigned with
281 // SetImageList, the control does _not_ delete
282 // the associated image list when it's deleted in order to allow image
283 // lists to be shared between different controls. If you use
284 // AssignImageList, the control _does_ delete the image list.
286 // The normal image list is for the icons which correspond to the
287 // normal tree item state (whether it is selected or not).
288 // Additionally, the application might choose to show a state icon
289 // which corresponds to an app-defined item state (for example,
290 // checked/unchecked) which are taken from the state image list.
291 wxImageList *GetImageList() const { return m_imageListNormal; }
292 wxImageList *GetStateImageList() const { return m_imageListState; }
293 wxImageList *GetButtonsImageList() const { return m_imageListButtons; }
295 void SetImageList(wxImageList *imageList);
296 void SetStateImageList(wxImageList *imageList);
297 void SetButtonsImageList(wxImageList *imageList);
298 void AssignImageList(wxImageList *imageList);
299 void AssignStateImageList(wxImageList *imageList);
300 void AssignButtonsImageList(wxImageList *imageList);
302 // Functions to work with tree ctrl items.
307 // retrieve item's label
308 wxString GetItemText (const wxTreeItemId& item) const
309 { return GetItemText (item, GetMainColumn()); }
310 wxString GetItemText (const wxTreeItemId& item, int column) const;
311 wxString GetItemText (wxTreeItemData* item, int column) const;
313 // get one of the images associated with the item (normal by default)
314 int GetItemImage (const wxTreeItemId& item,
315 wxTreeItemIcon which = wxTreeItemIcon_Normal) const
316 { return GetItemImage (item, GetMainColumn(), which); }
317 int GetItemImage (const wxTreeItemId& item, int column,
318 wxTreeItemIcon which = wxTreeItemIcon_Normal) const;
320 // get the data associated with the item
321 wxTreeItemData *GetItemData(const wxTreeItemId& item) const;
323 bool GetItemBold(const wxTreeItemId& item) const;
324 wxColour GetItemTextColour(const wxTreeItemId& item) const;
325 wxColour GetItemBackgroundColour(const wxTreeItemId& item) const;
326 wxFont GetItemFont(const wxTreeItemId& item) const;
332 void SetItemText (const wxTreeItemId& item, const wxString& text)
333 { SetItemText (item, GetMainColumn(), text); }
334 void SetItemText (const wxTreeItemId& item, int column, const wxString& text);
336 // get one of the images associated with the item (normal by default)
337 void SetItemImage (const wxTreeItemId& item, int image,
338 wxTreeItemIcon which = wxTreeItemIcon_Normal)
339 { SetItemImage (item, GetMainColumn(), image, which); }
340 void SetItemImage (const wxTreeItemId& item, int column, int image,
341 wxTreeItemIcon which = wxTreeItemIcon_Normal);
343 // associate some data with the item
344 void SetItemData(const wxTreeItemId& item, wxTreeItemData *data);
346 // force appearance of [+] button near the item. This is useful to
347 // allow the user to expand the items which don't have any children now
348 // - but instead add them only when needed, thus minimizing memory
349 // usage and loading time.
350 void SetItemHasChildren(const wxTreeItemId& item, bool has = true);
352 // the item will be shown in bold
353 void SetItemBold(const wxTreeItemId& item, bool bold = true);
355 // set the item's text colour
356 void SetItemTextColour(const wxTreeItemId& item, const wxColour& colour);
358 // set the item's background colour
359 void SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& colour);
361 // set the item's font (should be of the same height for all items)
362 void SetItemFont(const wxTreeItemId& item, const wxFont& font);
364 // set the window font
365 virtual bool SetFont( const wxFont &font );
367 // set the styles. No need to specify a GetWindowStyle here since
368 // the base wxWindow member function will do it for us
369 void SetWindowStyle(const long styles);
371 // item status inquiries
372 // ---------------------
374 // is the item visible (it might be outside the view or not expanded)?
375 bool IsVisible(const wxTreeItemId& item, bool fullRow) const;
376 // does the item has any children?
377 bool HasChildren(const wxTreeItemId& item) const;
378 // is the item expanded (only makes sense if HasChildren())?
379 bool IsExpanded(const wxTreeItemId& item) const;
380 // is this item currently selected (the same as has focus)?
381 bool IsSelected(const wxTreeItemId& item) const;
382 // is item text in bold font?
383 bool IsBold(const wxTreeItemId& item) const;
384 // does the layout include space for a button?
386 // number of children
387 // ------------------
389 // if 'recursively' is false, only immediate children count, otherwise
390 // the returned number is the number of all items in this branch
391 size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true);
396 // wxTreeItemId.IsOk() will return false if there is no such item
398 // get the root tree item
399 wxTreeItemId GetRootItem() const { return m_rootItem; }
401 // get the item currently selected, only if a single item is selected
402 // wxTreeItemId GetSelection() const { return m_selectItem; }
403 wxTreeItemId GetCurrent() const { return m_curItem; }
405 // get all the items currently selected, return count of items
406 size_t GetSelections(wxArrayTreeItemIds&) const;
408 // returns the number of currently selected items
409 size_t GetSelectionSize() const;
411 // get the parent of this item (may return NULL if root)
412 wxTreeItemId GetItemParent(const wxTreeItemId& item) const;
414 // for this enumeration function you must pass in a "cookie" parameter
415 // which is opaque for the application but is necessary for the library
416 // to make these functions reentrant (i.e. allow more than one
417 // enumeration on one and the same object simultaneously). Of course,
418 // the "cookie" passed to GetFirstChild() and GetNextChild() should be
421 // get child of this item
422 #if !wxCHECK_VERSION(2, 5, 0)
423 wxTreeItemId GetFirstChild(const wxTreeItemId& item, long& cookie) const;
424 wxTreeItemId GetNextChild(const wxTreeItemId& item, long& cookie) const;
425 wxTreeItemId GetPrevChild(const wxTreeItemId& item, long& cookie) const;
426 wxTreeItemId GetLastChild(const wxTreeItemId& item, long& cookie) const;
428 wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
429 wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
430 wxTreeItemId GetPrevChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
431 wxTreeItemId GetLastChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
434 // get sibling of this item
435 wxTreeItemId GetNextSibling(const wxTreeItemId& item) const;
436 wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const;
438 // get item in the full tree (currently only for internal use)
439 wxTreeItemId GetNext(const wxTreeItemId& item, bool fulltree = true) const;
440 wxTreeItemId GetPrev(const wxTreeItemId& item, bool fulltree = true) const;
442 // get expanded item, see IsExpanded()
443 wxTreeItemId GetFirstExpandedItem() const;
444 wxTreeItemId GetNextExpanded(const wxTreeItemId& item) const;
445 wxTreeItemId GetPrevExpanded(const wxTreeItemId& item) const;
447 // get visible item, see IsVisible()
448 wxTreeItemId GetFirstVisibleItem(bool fullRow) const;
449 wxTreeItemId GetNextVisible(const wxTreeItemId& item, bool fullRow) const;
450 wxTreeItemId GetPrevVisible(const wxTreeItemId& item, bool fullRow) const;
455 // add the root node to the tree
456 wxTreeItemId AddRoot (const wxString& text,
457 int image = -1, int selectedImage = -1,
458 wxTreeItemData *data = NULL);
460 // insert a new item in as the first child of the parent
461 wxTreeItemId PrependItem(const wxTreeItemId& parent,
462 const wxString& text,
463 int image = -1, int selectedImage = -1,
464 wxTreeItemData *data = NULL);
466 // insert a new item after a given one
467 wxTreeItemId InsertItem(const wxTreeItemId& parent,
468 const wxTreeItemId& idPrevious,
469 const wxString& text,
470 int image = -1, int selectedImage = -1,
471 wxTreeItemData *data = NULL);
473 // insert a new item before the one with the given index
474 wxTreeItemId InsertItem(const wxTreeItemId& parent,
476 const wxString& text,
477 int image = -1, int selectedImage = -1,
478 wxTreeItemData *data = NULL);
480 // insert a new item in as the last child of the parent
481 wxTreeItemId AppendItem(const wxTreeItemId& parent,
482 const wxString& text,
483 int image = -1, int selectedImage = -1,
484 wxTreeItemData *data = NULL);
486 // delete this item and associated data if any
487 void Delete(const wxTreeItemId& item);
488 // delete all children (but don't delete the item itself)
489 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
490 void DeleteChildren(const wxTreeItemId& item);
491 // delete the root and all its children from the tree
492 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
496 void Expand(const wxTreeItemId& item);
497 // expand this item and all subitems recursively
498 void ExpandAll(const wxTreeItemId& item);
499 // collapse the item without removing its children
500 void Collapse(const wxTreeItemId& item);
501 // collapse the item and remove all children
502 void CollapseAndReset(const wxTreeItemId& item);
503 // toggles the current state
504 void Toggle(const wxTreeItemId& item);
506 // remove the selection from currently selected item (if any)
507 // void Unselect(wxTreeListItem* item);
511 void SelectItem(const wxTreeItemId& item, const wxTreeItemId& prev = (wxTreeItemId*)NULL,
512 bool unselect_others = true);
514 void RemoveFromSelection( wxTreeListItem *item );
515 void AddToSelection( wxTreeListItem *item );
517 // make sure this item is visible (expanding the parent item and/or
518 // scrolling to this item if necessary)
519 void EnsureVisible(const wxTreeItemId& item);
520 // scroll to this item (but don't expand its parent)
521 void ScrollTo(const wxTreeItemId& item);
522 void AdjustMyScrollbars();
524 // The first function is more portable (because easier to implement
525 // on other platforms), but the second one returns some extra info.
526 wxTreeItemId HitTest (const wxPoint& point)
527 { int flags; int column; return HitTest (point, flags, column); }
528 wxTreeItemId HitTest (const wxPoint& point, int& flags)
529 { int column; return HitTest (point, flags, column); }
530 wxTreeItemId HitTest (const wxPoint& point, int& flags, int& column);
533 // get the bounding rectangle of the item (or of its label only)
534 bool GetBoundingRect(const wxTreeItemId& item,
536 bool textOnly = false) const;
538 // Start editing the item label: this (temporarily) replaces the item
539 // with a one line edit control. The item will be selected if it hadn't
541 void EditLabel (const wxTreeItemId& item, int column);
544 // this function is called to compare 2 items and should return -1, 0
545 // or +1 if the first item is less than, equal to or greater than the
546 // second one. The base class version performs alphabetic comparaison
547 // of item labels (GetText)
548 virtual int OnCompareItems(const wxTreeItemId& item1,
549 const wxTreeItemId& item2);
550 // sort the children of this item using OnCompareItems
552 // NB: this function is not reentrant and not MT-safe (FIXME)!
553 void SortChildren(const wxTreeItemId& item);
556 wxTreeItemId FindItem (const wxTreeItemId& item, const wxString& str, int mode = 0);
558 // implementation only from now on
560 // overridden base class virtuals
561 virtual bool SetBackgroundColour(const wxColour& colour);
562 virtual bool SetForegroundColour(const wxColour& colour);
565 void SetDragItem (const wxTreeItemId& item = (wxTreeItemId*)NULL);
568 void OnPaint( wxPaintEvent &event );
569 void OnSetFocus( wxFocusEvent &event );
570 void OnKillFocus( wxFocusEvent &event );
571 void OnChar( wxKeyEvent &event );
572 void OnMouse( wxMouseEvent &event );
573 void OnIdle( wxIdleEvent &event );
574 void OnScroll(wxScrollWinEvent& event);
576 // implementation helpers
577 void SendDeleteEvent(wxTreeListItem *itemBeingDeleted);
579 int GetColumnCount() const
580 { return m_owner->GetHeaderWindow()->GetColumnCount(); }
582 void SetMainColumn (int column)
583 { if ((column >= 0) && (column < GetColumnCount())) m_main_column = column; }
585 int GetMainColumn() const { return m_main_column; }
587 int GetBestColumnWidth (int column, wxTreeItemId parent = wxTreeItemId());
588 int GetItemWidth (int column, wxTreeListItem *item);
589 wxFont GetItemFont (wxTreeListItem *item);
594 wxTreeListCtrl* m_owner;
598 friend class wxTreeListItem;
599 friend class wxTreeListRenameTimer;
600 friend class wxEditTextCtrl;
605 wxTreeListItem *m_rootItem; // root item
606 wxTreeListItem *m_curItem; // current item, either selected or marked
607 wxTreeListItem *m_shiftItem; // item, where the shift key was pressed
608 wxTreeListItem *m_editItem; // item, which is currently edited
609 // wxTreeListItem *m_selectItem; // current selected item, not with wxTR_MULTIPLE
611 wxArrayTreeListItems m_selected; // currently selected items
615 int m_btnWidth, m_btnWidth2;
616 int m_btnHeight, m_btnHeight2;
617 int m_imgWidth, m_imgWidth2;
618 int m_imgHeight, m_imgHeight2;
619 unsigned short m_indent;
621 unsigned short m_linespacing;
623 wxBrush *m_hilightBrush,
624 *m_hilightUnfocusedBrush;
629 bool m_ownsImageListNormal,
630 m_ownsImageListState,
631 m_ownsImageListButtons;
632 bool m_isDragging; // true between BEGIN/END drag events
634 bool m_lastOnSame; // last click on the same item as prev
635 bool m_left_down_selection;
637 wxImageList *m_imageListNormal,
642 wxTimer *m_dragTimer;
643 wxTreeListItem *m_dragItem;
645 wxTimer *m_renameTimer;
646 wxString m_renameRes;
649 wxTimer *m_findTimer;
652 // the common part of all ctors
656 wxTreeItemId DoInsertItem(const wxTreeItemId& parent,
658 const wxString& text,
659 int image, int selectedImage,
660 wxTreeItemData *data);
661 bool HasButtons(void) const
662 { return (m_imageListButtons) || HasFlag (wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); }
665 void CalculateLineHeight();
666 int GetLineHeight(wxTreeListItem *item) const;
667 void PaintLevel( wxTreeListItem *item, wxDC& dc, int level, int &y,
669 void PaintItem( wxTreeListItem *item, wxDC& dc);
671 void CalculateLevel( wxTreeListItem *item, wxDC &dc, int level, int &y,
673 void CalculatePositions();
674 void CalculateSize( wxTreeListItem *item, wxDC &dc );
676 void RefreshSubtree (wxTreeListItem *item);
677 void RefreshLine (wxTreeListItem *item);
679 // redraw all selected items
680 void RefreshSelected();
682 // RefreshSelected() recursive helper
683 void RefreshSelectedUnder (wxTreeListItem *item);
685 void OnRenameTimer();
686 void OnRenameAccept();
688 void FillArray(wxTreeListItem*, wxArrayTreeItemIds&) const;
689 bool SelectAllChildrenUntilLast (wxTreeListItem *crt_item, wxTreeListItem *last_item);
690 bool SelectNextChildren (wxTreeListItem *crt_item, wxTreeListItem *last_item);
691 // void UnselectAllChildren (wxTreeListItem *item );
694 DECLARE_EVENT_TABLE()
695 DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow)
699 // timer used for enabling in-place edit
700 class wxTreeListRenameTimer: public wxTimer
703 wxTreeListRenameTimer( wxTreeListMainWindow *owner );
708 wxTreeListMainWindow *m_owner;
711 // control used for in-place edit
712 class wxEditTextCtrl: public wxTextCtrl
715 wxEditTextCtrl (wxWindow *parent,
719 wxTreeListMainWindow *owner,
720 const wxString &value = wxEmptyString,
721 const wxPoint &pos = wxDefaultPosition,
722 const wxSize &size = wxDefaultSize,
724 const wxValidator& validator = wxDefaultValidator,
725 const wxString &name = wxTextCtrlNameStr );
727 void OnChar( wxKeyEvent &event );
728 void OnKeyUp( wxKeyEvent &event );
729 void OnKillFocus( wxFocusEvent &event );
734 wxTreeListMainWindow *m_owner;
735 wxString m_startValue;
738 DECLARE_EVENT_TABLE()
746 wxTreeListItem() { m_data = NULL; }
747 wxTreeListItem( wxTreeListMainWindow *owner,
748 wxTreeListItem *parent,
749 const wxArrayString& text,
752 wxTreeItemData *data );
757 wxArrayTreeListItems& GetChildren() { return m_children; }
759 const wxString GetText() const
763 const wxString GetText (int column) const
765 if(m_text.GetCount() > 0)
767 if( IsVirtual() ) return m_owner->GetItemText( m_data, column );
768 else return m_text[column];
770 return wxEmptyString;
773 int GetImage (wxTreeItemIcon which = wxTreeItemIcon_Normal) const
774 { return m_images[which]; }
775 int GetImage (int column, wxTreeItemIcon which=wxTreeItemIcon_Normal) const
777 if(column == m_owner->GetMainColumn()) return m_images[which];
778 if(column < (int)m_col_images.GetCount()) return m_col_images[column];
782 wxTreeItemData *GetData() const { return m_data; }
784 // returns the current image for the item (depending on its
785 // selected/expanded/whatever state)
786 int GetCurrentImage() const;
788 void SetText (const wxString &text );
789 void SetText (int column, const wxString& text)
791 if (column < (int)m_text.GetCount()) {
792 m_text[column] = text;
793 }else if (column < m_owner->GetColumnCount()) {
794 int howmany = m_owner->GetColumnCount();
795 for (int i = m_text.GetCount(); i < howmany; ++i) m_text.Add (wxEmptyString);
796 m_text[column] = text;
799 void SetImage (int image, wxTreeItemIcon which) { m_images[which] = image; }
800 void SetImage (int column, int image, wxTreeItemIcon which)
802 if (column == m_owner->GetMainColumn()) {
803 m_images[which] = image;
804 }else if (column < (int)m_col_images.GetCount()) {
805 m_col_images[column] = image;
806 }else if (column < m_owner->GetColumnCount()) {
807 int howmany = m_owner->GetColumnCount();
808 for (int i = m_col_images.GetCount(); i < howmany; ++i) m_col_images.Add (NO_IMAGE);
809 m_col_images[column] = image;
813 void SetData(wxTreeItemData *data) { m_data = data; }
815 void SetHasPlus(bool has = true) { m_hasPlus = has; }
817 void SetBold(bool bold) { m_isBold = bold; }
819 int GetX() const { return m_x; }
820 int GetY() const { return m_y; }
822 void SetX (int x) { m_x = x; }
823 void SetY (int y) { m_y = y; }
825 int GetHeight() const { return m_height; }
826 int GetWidth() const { return m_width; }
828 void SetHeight (int height) { m_height = height; }
829 void SetWidth (int width) { m_width = width; }
831 int GetTextX() const { return m_text_x; }
832 void SetTextX (int text_x) { m_text_x = text_x; }
834 wxTreeListItem *GetItemParent() const { return m_parent; }
837 // deletes all children notifying the treectrl about it if !NULL
839 void DeleteChildren(wxTreeListMainWindow *tree = NULL);
841 // get count of all children (and grand children if 'recursively')
842 size_t GetChildrenCount(bool recursively = true) const;
844 void Insert(wxTreeListItem *child, size_t index)
845 { m_children.Insert(child, index); }
847 void GetSize( int &x, int &y, const wxTreeListMainWindow* );
849 // return the item at given position (or NULL if no item), onButton is
850 // true if the point belongs to the item's button, otherwise it lies
851 // on the button's label
852 wxTreeListItem *HitTest (const wxPoint& point,
853 const wxTreeListMainWindow *,
854 int &flags, int& column, int level);
856 void Expand() { m_isCollapsed = false; }
857 void Collapse() { m_isCollapsed = true; }
859 void SetSelected( bool set = true ) { m_hasHilight = set; }
862 bool HasChildren() const { return !m_children.IsEmpty(); }
863 bool IsSelected() const { return m_hasHilight != 0; }
864 bool IsExpanded() const { return !m_isCollapsed; }
865 bool HasPlus() const { return m_hasPlus || HasChildren(); }
866 bool IsBold() const { return m_isBold != 0; }
867 bool IsVirtual() const { return m_owner->IsVirtual(); }
870 // get them - may be NULL
871 wxTreeItemAttr *GetAttributes() const { return m_attr; }
872 // get them ensuring that the pointer is not NULL
873 wxTreeItemAttr& Attr()
877 m_attr = new wxTreeItemAttr;
883 void SetAttributes(wxTreeItemAttr *attr)
885 if ( m_ownsAttr ) delete m_attr;
889 // set them and delete when done
890 void AssignAttributes(wxTreeItemAttr *attr)
897 wxTreeListMainWindow *m_owner; // control the item belongs to
899 // since there can be very many of these, we save size by chosing
900 // the smallest representation for the elements and by ordering
901 // the members to avoid padding.
902 wxArrayString m_text; // labels to be rendered for item
904 wxTreeItemData *m_data; // user-provided data
906 wxArrayTreeListItems m_children; // list of children
907 wxTreeListItem *m_parent; // parent of this item
909 wxTreeItemAttr *m_attr; // attributes???
911 // tree ctrl images for the normal, selected, expanded and
912 // expanded+selected states
913 short m_images[wxTreeItemIcon_Max];
914 wxArrayShort m_col_images; // images for the various columns (!= main)
916 // main column item positions
917 wxCoord m_x; // (virtual) offset from left (vertical line)
918 wxCoord m_y; // (virtual) offset from top
919 wxCoord m_text_x; // item offset from left
920 short m_width; // width of this item
921 unsigned char m_height; // height of this item
923 // use bitfields to save size
924 int m_isCollapsed :1;
925 int m_hasHilight :1; // same as focused
926 int m_hasPlus :1; // used for item which doesn't have
927 // children but has a [+] button
928 int m_isBold :1; // render the label in bold font
929 int m_ownsAttr :1; // delete attribute when done
932 // ===========================================================================
934 // ===========================================================================
936 // ---------------------------------------------------------------------------
937 // wxTreeListRenameTimer (internal)
938 // ---------------------------------------------------------------------------
940 wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow *owner )
945 void wxTreeListRenameTimer::Notify()
947 m_owner->OnRenameTimer();
950 //-----------------------------------------------------------------------------
951 // wxEditTextCtrl (internal)
952 //-----------------------------------------------------------------------------
954 BEGIN_EVENT_TABLE (wxEditTextCtrl,wxTextCtrl)
955 EVT_CHAR (wxEditTextCtrl::OnChar)
956 EVT_KEY_UP (wxEditTextCtrl::OnKeyUp)
957 EVT_KILL_FOCUS (wxEditTextCtrl::OnKillFocus)
960 wxEditTextCtrl::wxEditTextCtrl (wxWindow *parent,
964 wxTreeListMainWindow *owner,
965 const wxString &value,
969 const wxValidator& validator,
970 const wxString &name)
971 : wxTextCtrl (parent, id, value, pos, size, style|wxSIMPLE_BORDER, validator, name)
977 (*m_res) = wxEmptyString;
978 m_startValue = value;
982 void wxEditTextCtrl::OnChar( wxKeyEvent &event )
984 if (event.GetKeyCode() == WXK_RETURN)
987 (*m_res) = GetValue();
989 if ((*m_res) != m_startValue)
990 m_owner->OnRenameAccept();
992 if (!wxPendingDelete.Member(this))
993 wxPendingDelete.Append(this);
996 m_owner->SetFocus(); // This doesn't work. TODO.
1000 if (event.GetKeyCode() == WXK_ESCAPE)
1002 (*m_accept) = false;
1003 (*m_res) = wxEmptyString;
1005 if (!wxPendingDelete.Member(this))
1006 wxPendingDelete.Append(this);
1009 m_owner->SetFocus(); // This doesn't work. TODO.
1016 void wxEditTextCtrl::OnKeyUp( wxKeyEvent &event )
1024 // auto-grow the textctrl:
1025 wxSize parentSize = m_owner->GetSize();
1026 wxPoint myPos = GetPosition();
1027 wxSize mySize = GetSize();
1029 GetTextExtent(GetValue() + _T("M"), &sx, &sy);
1030 if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
1031 if (mySize.x > sx) sx = mySize.x;
1037 void wxEditTextCtrl::OnKillFocus( wxFocusEvent &event )
1045 if (!wxPendingDelete.Member(this))
1046 wxPendingDelete.Append(this);
1049 (*m_res) = GetValue();
1051 if ((*m_res) != m_startValue)
1052 m_owner->OnRenameAccept();
1055 //-----------------------------------------------------------------------------
1056 // wxTreeListHeaderWindow
1057 //-----------------------------------------------------------------------------
1062 //IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow,wxNotifyEvent);
1063 IMPLEMENT_CLASS(wxTreeListHeaderWindow,wxNotifyEvent);
1065 BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow)
1066 EVT_PAINT (wxTreeListHeaderWindow::OnPaint)
1067 EVT_MOUSE_EVENTS (wxTreeListHeaderWindow::OnMouse)
1068 EVT_SET_FOCUS (wxTreeListHeaderWindow::OnSetFocus)
1074 void wxTreeListHeaderWindow::Init()
1076 m_currentCursor = (wxCursor *) NULL;
1077 m_isDragging = false;
1079 m_total_col_width = 0;
1082 wxTreeListHeaderWindow::wxTreeListHeaderWindow()
1086 m_owner = (wxTreeListMainWindow *) NULL;
1087 m_resizeCursor = (wxCursor *) NULL;
1090 wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow *win,
1092 wxTreeListMainWindow *owner,
1096 const wxString &name )
1097 : wxWindow( win, id, pos, size, style, name )
1102 m_resizeCursor = new wxCursor(wxCURSOR_SIZEWE);
1104 #if !wxCHECK_VERSION(2, 5, 0)
1105 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNFACE));
1107 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE));
1111 wxTreeListHeaderWindow::~wxTreeListHeaderWindow()
1113 delete m_resizeCursor;
1116 void wxTreeListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
1118 #if !wxCHECK_VERSION(2, 5, 0)
1119 wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
1121 wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
1124 const int m_corner = 1;
1126 dc->SetBrush( *wxTRANSPARENT_BRUSH );
1127 #if defined( __WXMAC__ )
1130 dc->SetPen( *wxBLACK_PEN );
1132 dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer)
1133 dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer)
1135 #if defined( __WXMAC__ )
1138 // wxPen pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
1139 pen.SetColour( wxColour( 0x88 , 0x88 , 0x88 ) );
1143 dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner)
1144 dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner)
1146 dc->SetPen( *wxWHITE_PEN );
1147 dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer)
1148 dc->DrawRectangle( x, y, 1, h ); // left (outer)
1149 dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1150 dc->DrawLine( x+w-1, y, x+w-1, y+1 );
1153 // shift the DC origin to match the position of the main window horz
1154 // scrollbar: this allows us to always use logical coords
1155 void wxTreeListHeaderWindow::AdjustDC(wxDC& dc)
1158 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1160 m_owner->GetViewStart( &x, NULL );
1162 // account for the horz scrollbar offset
1163 dc.SetDeviceOrigin( -x * xpix, 0 );
1166 void wxTreeListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1169 wxClientDC dc( this );
1171 wxPaintDC dc( this );
1176 dc.SetFont( GetFont() );
1178 // width and height of the entire header window
1180 GetClientSize( &w, &h );
1181 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1182 dc.SetBackgroundMode(wxTRANSPARENT);
1184 // do *not* use the listctrl colour for headers - one day we will have a
1185 // function to set it separately
1186 //dc.SetTextForeground( *wxBLACK );
1187 #if !wxCHECK_VERSION(2, 5, 0)
1188 dc.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT ));
1190 dc.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ));
1193 int x = HEADER_OFFSET_X;
1195 int numColumns = GetColumnCount();
1196 for ( int i = 0; i < numColumns && x < w; i++ )
1198 if (!IsColumnShown (i)) continue; // do next colume if not shown
1200 wxTreeListColumnInfo& column = GetColumn(i);
1201 int wCol = column.GetWidth();
1203 // the width of the rect to draw: make it smaller to fit entirely
1204 // inside the column rect
1207 dc.SetPen( *wxWHITE_PEN );
1208 DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
1210 // if we have an image, draw it on the right of the label
1211 int image = column.GetImage(); //item.m_image;
1212 int ix = -2, iy = 0;
1213 wxImageList* imageList = m_owner->GetImageList();
1214 if ((image != -1) && imageList) {
1215 imageList->GetSize (image, ix, iy);
1218 // extra margins around the text label
1221 int image_offset = cw - ix - 1;
1223 switch(column.GetAlignment()) {
1225 text_x += EXTRA_WIDTH;
1229 dc.GetTextExtent (column.GetText(), &text_width, NULL);
1230 text_x += cw - text_width - EXTRA_WIDTH - MARGIN;
1233 case wxALIGN_CENTER:
1234 dc.GetTextExtent(column.GetText(), &text_width, NULL);
1235 text_x += (cw - text_width)/2 + ix + 2;
1236 image_offset = (cw - text_width - ix - 2)/2 - MARGIN;
1241 if ((image != -1) && imageList) {
1242 imageList->Draw (image, dc, x + image_offset/*cw - ix - 1*/,
1243 HEADER_OFFSET_Y + (h - 4 - iy)/2,
1244 wxIMAGELIST_DRAW_TRANSPARENT);
1247 // draw the text clipping it so that it doesn't overwrite the column boundary
1248 wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
1249 dc.DrawText (column.GetText(), text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT );
1255 int more_w = m_owner->GetSize().x - x - HEADER_OFFSET_X;
1257 DoDrawRect (&dc, x, HEADER_OFFSET_Y, more_w, h-2 );
1262 void wxTreeListHeaderWindow::DrawCurrent()
1264 int x1 = m_currentX;
1266 ClientToScreen (&x1, &y1);
1268 int x2 = m_currentX-1;
1270 ++x2; // but why ????
1273 m_owner->GetClientSize( NULL, &y2 );
1274 m_owner->ClientToScreen( &x2, &y2 );
1277 dc.SetLogicalFunction (wxINVERT);
1278 dc.SetPen (wxPen (*wxBLACK, 2, wxSOLID));
1279 dc.SetBrush (*wxTRANSPARENT_BRUSH);
1282 dc.DrawLine (x1, y1, x2, y2);
1283 dc.SetLogicalFunction (wxCOPY);
1284 dc.SetPen (wxNullPen);
1285 dc.SetBrush (wxNullBrush);
1288 void wxTreeListHeaderWindow::OnMouse (wxMouseEvent &event) {
1290 // we want to work with logical coords
1292 m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1293 int y = event.GetY();
1297 SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
1299 // we don't draw the line beyond our window, but we allow dragging it
1302 GetClientSize( &w, NULL );
1303 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1306 // erase the line if it was drawn
1307 if (m_currentX < w) DrawCurrent();
1309 if (event.ButtonUp()) {
1310 m_isDragging = false;
1311 if (HasCapture()) ReleaseMouse();
1313 SetColumnWidth (m_column, m_currentX - m_minX);
1315 SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
1317 m_currentX = wxMax (m_minX + 7, x);
1319 // draw in the new location
1320 if (m_currentX < w) DrawCurrent();
1323 }else{ // not dragging
1326 bool hit_border = false;
1328 // end of the current column
1331 // find the column where this event occured
1332 int countCol = GetColumnCount();
1333 for (int column = 0; column < countCol; column++) {
1334 if (!IsColumnShown (column)) continue; // do next if not shown
1336 xpos += GetColumnWidth (column);
1338 if ((abs (x-xpos) < 3) && (y < 22)) {
1339 // near the column border
1345 // inside the column
1352 if (event.LeftDown() || event.RightUp()) {
1353 if (hit_border && event.LeftDown()) {
1354 m_isDragging = true;
1358 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition());
1359 }else{ // click on a column
1360 wxEventType evt = event.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK:
1361 wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
1362 SendListEvent (evt, event.GetPosition());
1364 }else if (event.LeftDClick() && hit_border) {
1365 SetColumnWidth (m_column, m_owner->GetBestColumnWidth (m_column));
1368 }else if (event.Moving()) {
1371 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
1372 m_currentCursor = m_resizeCursor;
1374 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
1375 m_currentCursor = wxSTANDARD_CURSOR;
1377 if (setCursor) SetCursor (*m_currentCursor);
1383 void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent &WXUNUSED(event)) {
1384 m_owner->SetFocus();
1387 void wxTreeListHeaderWindow::SendListEvent (wxEventType type, wxPoint pos) {
1388 wxWindow *parent = GetParent();
1389 wxListEvent le (type, parent->GetId());
1390 le.SetEventObject (parent);
1391 le.m_pointDrag = pos;
1393 // the position should be relative to the parent window, not
1394 // this one for compatibility with MSW and common sense: the
1395 // user code doesn't know anything at all about this header
1396 // window, so why should it get positions relative to it?
1397 le.m_pointDrag.y -= GetSize().y;
1398 le.m_col = m_column;
1399 parent->GetEventHandler()->ProcessEvent (le);
1402 void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo& colInfo) {
1403 m_columns.Add (colInfo);
1404 m_total_col_width += colInfo.GetWidth();
1405 m_owner->AdjustMyScrollbars();
1406 m_owner->m_dirty = true;
1409 void wxTreeListHeaderWindow::SetColumnWidth (int column, int width) {
1410 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1411 m_total_col_width -= m_columns[column].GetWidth();
1412 m_columns[column].SetWidth(width);
1413 m_total_col_width += width;
1414 m_owner->AdjustMyScrollbars();
1415 m_owner->m_dirty = true;
1418 void wxTreeListHeaderWindow::InsertColumn (int before, const wxTreeListColumnInfo& colInfo) {
1419 wxCHECK_RET ((before >= 0) && (before < GetColumnCount()), _T("Invalid column"));
1420 m_columns.Insert (colInfo, before);
1421 m_total_col_width += colInfo.GetWidth();
1422 m_owner->AdjustMyScrollbars();
1423 m_owner->m_dirty = true;
1426 void wxTreeListHeaderWindow::RemoveColumn (int column) {
1427 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1428 m_total_col_width -= m_columns[column].GetWidth();
1429 m_columns.RemoveAt (column);
1430 m_owner->AdjustMyScrollbars();
1431 m_owner->m_dirty = true;
1434 void wxTreeListHeaderWindow::SetColumn (int column, const wxTreeListColumnInfo& info) {
1435 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1436 int w = m_columns[column].GetWidth();
1437 m_columns[column] = info;
1438 if (w != info.GetWidth()) {
1439 m_total_col_width += info.GetWidth() - w;
1440 m_owner->AdjustMyScrollbars();
1442 m_owner->m_dirty = true;
1445 // ---------------------------------------------------------------------------
1447 // ---------------------------------------------------------------------------
1449 wxTreeListItem::wxTreeListItem (wxTreeListMainWindow *owner,
1450 wxTreeListItem *parent,
1451 const wxArrayString& text,
1452 int image, int selImage,
1453 wxTreeItemData *data)
1456 m_images[wxTreeItemIcon_Normal] = image;
1457 m_images[wxTreeItemIcon_Selected] = selImage;
1458 m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
1459 m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
1466 m_isCollapsed = true;
1467 m_hasHilight = false;
1474 m_attr = (wxTreeItemAttr *)NULL;
1477 // We don't know the height here yet.
1482 wxTreeListItem::~wxTreeListItem() {
1484 if (m_ownsAttr) delete m_attr;
1486 wxASSERT_MSG( m_children.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1489 void wxTreeListItem::DeleteChildren (wxTreeListMainWindow *tree) {
1490 size_t count = m_children.Count();
1491 for (size_t n = 0; n < count; n++) {
1492 wxTreeListItem *child = m_children[n];
1494 tree->SendDeleteEvent (child);
1496 tree->RemoveFromSelection(child);
1498 if (child->IsSelected())
1500 tree->Unselect(child);
1503 // if (tree->m_selectItem == child) tree->m_selectItem = (wxTreeListItem*)NULL;
1505 child->DeleteChildren (tree);
1511 void wxTreeListItem::SetText (const wxString &text) {
1512 if (m_text.GetCount() > 0) {
1519 size_t wxTreeListItem::GetChildrenCount (bool recursively) const {
1520 size_t count = m_children.Count();
1521 if (!recursively) return count;
1523 size_t total = count;
1524 for (size_t n = 0; n < count; ++n) {
1525 total += m_children[n]->GetChildrenCount();
1530 void wxTreeListItem::GetSize (int &x, int &y, const wxTreeListMainWindow *theButton) {
1531 int bottomY = m_y + theButton->GetLineHeight (this);
1532 if (y < bottomY) y = bottomY;
1533 int width = m_x + m_width;
1534 if ( x < width ) x = width;
1537 size_t count = m_children.Count();
1538 for (size_t n = 0; n < count; ++n ) {
1539 m_children[n]->GetSize (x, y, theButton);
1544 wxTreeListItem *wxTreeListItem::HitTest (const wxPoint& point,
1545 const wxTreeListMainWindow *theCtrl,
1546 int &flags, int& column, int level) {
1548 // for a hidden root node, don't evaluate it, but do evaluate children
1549 if (!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) {
1551 // reset any previous hit infos
1554 wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow();
1556 // check for right of all columns (outside)
1557 if (point.x > header_win->GetWidth()) return (wxTreeListItem*) NULL;
1559 // evaluate if y-pos is okay
1560 int h = theCtrl->GetLineHeight (this);
1561 if ((point.y >= m_y) && (point.y <= m_y + h)) {
1563 int maincol = theCtrl->GetMainColumn();
1565 // check for above/below middle
1566 int y_mid = m_y + h/2;
1567 if (point.y < y_mid) {
1568 flags |= wxTREE_HITTEST_ONITEMUPPERPART;
1570 flags |= wxTREE_HITTEST_ONITEMLOWERPART;
1573 // check for button hit
1574 if (HasPlus() && theCtrl->HasButtons()) {
1575 int bntX = m_x - theCtrl->m_btnWidth2;
1576 int bntY = y_mid - theCtrl->m_btnHeight2;
1577 if ((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) &&
1578 (point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) {
1579 flags |= wxTREE_HITTEST_ONITEMBUTTON;
1585 // check for image hit
1586 if (theCtrl->m_imgWidth > 0) {
1587 int imgX = m_text_x - theCtrl->m_imgWidth - MARGIN;
1588 int imgY = y_mid - theCtrl->m_imgHeight2;
1589 if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) &&
1590 (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) {
1591 flags |= wxTREE_HITTEST_ONITEMICON;
1597 // check for label hit
1598 if ((point.x >= m_text_x) && (point.x <= (m_text_x + m_width))) {
1599 flags |= wxTREE_HITTEST_ONITEMLABEL;
1604 // check for indent hit after button and image hit
1605 if (point.x < m_x) {
1606 flags |= wxTREE_HITTEST_ONITEMINDENT;
1607 column = -1; // considered not belonging to main column
1611 // check for right of label
1613 for (int i = 0; i <= maincol; ++i) end += header_win->GetColumnWidth (i);
1614 if ((point.x > (m_text_x + m_width)) && (point.x <= end)) {
1615 flags |= wxTREE_HITTEST_ONITEMRIGHT;
1616 column = -1; // considered not belonging to main column
1620 // else check for each column except main
1622 for (int j = 0; j < theCtrl->GetColumnCount(); ++j) {
1623 if (!header_win->IsColumnShown(j)) continue;
1624 int w = header_win->GetColumnWidth (j);
1625 if ((j != maincol) && (point.x >= x && point.x < x+w)) {
1626 flags |= wxTREE_HITTEST_ONITEMCOLUMN;
1633 // no special flag or column found
1638 // if children not expanded, return no item
1639 if (!IsExpanded()) return (wxTreeListItem*) NULL;
1642 // in any case evaluate children
1643 wxTreeListItem *child;
1644 size_t count = m_children.Count();
1645 for (size_t n = 0; n < count; n++) {
1646 child = m_children[n]->HitTest (point, theCtrl, flags, column, level+1);
1647 if (child) return child;
1651 return (wxTreeListItem*) NULL;
1654 int wxTreeListItem::GetCurrentImage() const {
1655 int image = NO_IMAGE;
1658 image = GetImage (wxTreeItemIcon_SelectedExpanded);
1660 image = GetImage (wxTreeItemIcon_Expanded);
1662 }else{ // not expanded
1664 image = GetImage (wxTreeItemIcon_Selected);
1666 image = GetImage (wxTreeItemIcon_Normal);
1670 // maybe it doesn't have the specific image, try the default one instead
1671 if (image == NO_IMAGE) image = GetImage();
1676 // ---------------------------------------------------------------------------
1677 // wxTreeListMainWindow implementation
1678 // ---------------------------------------------------------------------------
1680 IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow)
1682 BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow)
1683 EVT_PAINT (wxTreeListMainWindow::OnPaint)
1684 EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse)
1685 EVT_CHAR (wxTreeListMainWindow::OnChar)
1686 EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus)
1687 EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus)
1688 EVT_IDLE (wxTreeListMainWindow::OnIdle)
1689 EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll)
1693 // ---------------------------------------------------------------------------
1694 // construction/destruction
1695 // ---------------------------------------------------------------------------
1697 void wxTreeListMainWindow::Init() {
1699 m_rootItem = (wxTreeListItem*)NULL;
1700 m_curItem = (wxTreeListItem*)NULL;
1701 m_shiftItem = (wxTreeListItem*)NULL;
1702 m_editItem = (wxTreeListItem*)NULL;
1704 // m_selectItem = (wxTreeListItem*)NULL;
1706 m_curColumn = -1; // no current column
1711 m_lineHeight = LINEHEIGHT;
1712 m_indent = MININDENT; // min. indent
1715 #if !wxCHECK_VERSION(2, 5, 0)
1716 m_hilightBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1717 m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1719 m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1720 m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1723 m_imageListNormal = (wxImageList *) NULL;
1724 m_imageListButtons = (wxImageList *) NULL;
1725 m_imageListState = (wxImageList *) NULL;
1726 m_ownsImageListNormal = m_ownsImageListButtons =
1727 m_ownsImageListState = false;
1729 m_imgWidth = 0, m_imgWidth2 = 0;
1730 m_imgHeight = 0, m_imgHeight2 = 0;
1731 m_btnWidth = 0, m_btnWidth2 = 0;
1732 m_btnHeight = 0, m_btnHeight2 = 0;
1735 m_isDragging = false;
1736 m_dragTimer = new wxTimer (this, -1);
1737 m_dragItem = (wxTreeListItem*)NULL;
1739 m_renameTimer = new wxTreeListRenameTimer (this);
1740 m_lastOnSame = false;
1741 m_left_down_selection = false;
1743 m_findTimer = new wxTimer (this, -1);
1745 #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
1746 m_normalFont.MacCreateThemeFont (kThemeViewsFont);
1748 m_normalFont = wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT);
1750 m_boldFont = wxFont( m_normalFont.GetPointSize(),
1751 m_normalFont.GetFamily(),
1752 m_normalFont.GetStyle(),
1754 m_normalFont.GetUnderlined(),
1755 m_normalFont.GetFaceName(),
1756 m_normalFont.GetEncoding());
1759 bool wxTreeListMainWindow::Create (wxTreeListCtrl *parent,
1764 const wxValidator &validator,
1765 const wxString& name) {
1768 if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS;
1769 if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS;
1770 style &= ~wxTR_LINES_AT_ROOT;
1771 style |= wxTR_NO_LINES;
1774 wxGetOsVersion( &major, &minor );
1775 if (major < 10) style |= wxTR_ROW_LINES;
1778 wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
1780 #if wxUSE_VALIDATORS
1781 SetValidator(validator);
1784 #if !wxCHECK_VERSION(2, 5, 0)
1785 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX));
1787 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX));
1795 bdc.SelectObject(bmp);
1796 bdc.SetPen(*wxGREY_PEN);
1797 bdc.DrawRectangle(-1, -1, 10, 10);
1798 for (i = 0; i < 8; i++) {
1799 for (j = 0; j < 8; j++) {
1800 if (!((i + j) & 1)) {
1801 bdc.DrawPoint(i, j);
1806 m_dottedPen = wxPen(bmp, 1);
1809 //? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86
1810 m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
1819 wxTreeListMainWindow::~wxTreeListMainWindow() {
1820 delete m_hilightBrush;
1821 delete m_hilightUnfocusedBrush;
1824 delete m_renameTimer;
1826 if (m_ownsImageListNormal) delete m_imageListNormal;
1827 if (m_ownsImageListState) delete m_imageListState;
1828 if (m_ownsImageListButtons) delete m_imageListButtons;
1834 //-----------------------------------------------------------------------------
1836 //-----------------------------------------------------------------------------
1838 size_t wxTreeListMainWindow::GetCount() const {
1839 return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount();
1842 void wxTreeListMainWindow::SetIndent (unsigned int indent) {
1843 m_indent = wxMax (MININDENT, indent);
1847 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) {
1848 m_linespacing = spacing;
1850 CalculateLineHeight();
1853 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item,
1855 wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item"));
1856 return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively);
1859 void wxTreeListMainWindow::SetWindowStyle (const long styles) {
1860 // right now, just sets the styles. Eventually, we may
1861 // want to update the inherited styles, but right now
1862 // none of the parents has updatable styles
1863 m_windowStyle = styles;
1867 //-----------------------------------------------------------------------------
1868 // functions to work with tree items
1869 //-----------------------------------------------------------------------------
1871 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column,
1872 wxTreeItemIcon which) const {
1873 wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item"));
1874 return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which);
1877 wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const {
1878 wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
1879 return ((wxTreeListItem*) item.m_pItem)->GetData();
1882 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const {
1883 wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
1884 return ((wxTreeListItem *)item.m_pItem)->IsBold();
1887 wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const {
1888 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1889 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1890 return pItem->Attr().GetTextColour();
1893 wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const {
1894 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1895 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1896 return pItem->Attr().GetBackgroundColour();
1899 wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const {
1900 wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
1901 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1902 return pItem->Attr().GetFont();
1905 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column,
1906 int image, wxTreeItemIcon which) {
1907 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1908 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1909 pItem->SetImage (column, image, which);
1910 wxClientDC dc (this);
1911 CalculateSize (pItem, dc);
1912 RefreshLine (pItem);
1915 void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item,
1916 wxTreeItemData *data) {
1917 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1918 ((wxTreeListItem*) item.m_pItem)->SetData(data);
1921 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item,
1923 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1924 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1925 pItem->SetHasPlus (has);
1926 RefreshLine (pItem);
1929 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, bool bold) {
1930 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1931 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1932 if (pItem->IsBold() != bold) { // avoid redrawing if no real change
1933 pItem->SetBold (bold);
1934 RefreshLine (pItem);
1938 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item,
1939 const wxColour& colour) {
1940 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1941 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1942 pItem->Attr().SetTextColour (colour);
1943 RefreshLine (pItem);
1946 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item,
1947 const wxColour& colour) {
1948 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1949 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1950 pItem->Attr().SetBackgroundColour (colour);
1951 RefreshLine (pItem);
1954 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item,
1955 const wxFont& font) {
1956 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1957 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1958 pItem->Attr().SetFont (font);
1959 RefreshLine (pItem);
1962 bool wxTreeListMainWindow::SetFont (const wxFont &font) {
1963 wxScrolledWindow::SetFont (font);
1964 m_normalFont = font;
1965 m_boldFont = wxFont (m_normalFont.GetPointSize(),
1966 m_normalFont.GetFamily(),
1967 m_normalFont.GetStyle(),
1969 m_normalFont.GetUnderlined(),
1970 m_normalFont.GetFaceName());
1971 CalculateLineHeight();
1976 // ----------------------------------------------------------------------------
1977 // item status inquiries
1978 // ----------------------------------------------------------------------------
1980 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow) const {
1981 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1983 // An item is only visible if it's not a descendant of a collapsed item
1984 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1985 wxTreeListItem* parent = pItem->GetItemParent();
1987 if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break;
1988 if (!parent->IsExpanded()) return false;
1989 parent = parent->GetItemParent();
1992 wxSize clientSize = GetClientSize();
1994 if ((!GetBoundingRect (item, rect)) ||
1995 ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
1996 (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y) ||
1997 (!fullRow && (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x))) return false;
2002 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const {
2003 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2005 // consider that the item does have children if it has the "+" button: it
2006 // might not have them (if it had never been expanded yet) but then it
2007 // could have them as well and it's better to err on this side rather than
2008 // disabling some operations which are restricted to the items with
2009 // children for an item which does have them
2010 return ((wxTreeListItem*) item.m_pItem)->HasPlus();
2013 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const {
2014 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2015 return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
2018 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const {
2019 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2020 return ((wxTreeListItem*) item.m_pItem)->IsSelected();
2023 bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item) const {
2024 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2025 return ((wxTreeListItem*) item.m_pItem)->IsBold();
2028 // ----------------------------------------------------------------------------
2030 // ----------------------------------------------------------------------------
2032 wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const {
2033 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2034 return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
2037 #if !wxCHECK_VERSION(2, 5, 0)
2038 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2039 long& cookie) const {
2041 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2042 wxTreeItemIdValue& cookie) const {
2044 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2045 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2047 return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId();
2050 #if !wxCHECK_VERSION(2, 5, 0)
2051 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2052 long& cookie) const {
2054 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2055 wxTreeItemIdValue& cookie) const {
2057 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2058 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2059 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2060 long *pIndex = ((long*)&cookie);
2061 return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId();
2064 #if !wxCHECK_VERSION(2, 5, 0)
2065 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2066 long& cookie) const {
2068 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2069 wxTreeItemIdValue& cookie) const {
2071 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2072 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2073 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2074 long *pIndex = (long*)&cookie;
2075 return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId();
2078 #if !wxCHECK_VERSION(2, 5, 0)
2079 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2080 long& cookie) const {
2082 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2083 wxTreeItemIdValue& cookie) const {
2085 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2086 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2087 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2088 long *pIndex = ((long*)&cookie);
2089 (*pIndex) = children.Count();
2090 return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId();
2093 wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const {
2094 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2097 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2098 wxTreeListItem *parent = i->GetItemParent();
2099 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2102 wxArrayTreeListItems& siblings = parent->GetChildren();
2103 size_t index = siblings.Index (i);
2104 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2105 return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId();
2108 wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const {
2109 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2112 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2113 wxTreeListItem *parent = i->GetItemParent();
2114 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2117 wxArrayTreeListItems& siblings = parent->GetChildren();
2118 size_t index = siblings.Index(i);
2119 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2120 return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId();
2123 // Only for internal use right now, but should probably be public
2124 wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const {
2125 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2127 // if there are any children, return first child
2128 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2129 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2130 if (children.GetCount() > 0) return children.Item (0);
2133 // get sibling of this item or of the ancestors instead
2135 wxTreeItemId parent = item;
2137 next = GetNextSibling (parent);
2138 parent = GetItemParent (parent);
2139 } while (!next.IsOk() && parent.IsOk());
2143 // Only for internal use right now, but should probably be public
2144 wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const {
2145 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2147 // if there are any children, return last child
2148 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2149 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2150 if (children.GetCount() > 0) return children.Item (children.GetCount()-1);
2153 // get sibling of this item or of the ancestors instead
2155 wxTreeItemId parent = item;
2157 next = GetPrevSibling (parent);
2158 parent = GetItemParent (parent);
2159 } while (!next.IsOk() && parent.IsOk());
2163 wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
2164 return GetNextExpanded (GetRootItem());
2167 wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const {
2168 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2169 return GetNext (item, false);
2172 wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const {
2173 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2174 return GetPrev (item, false);
2177 wxTreeItemId wxTreeListMainWindow::GetFirstVisibleItem (bool fullRow) const {
2178 return GetNextVisible (GetRootItem(), fullRow);
2181 wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow) const {
2182 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2183 wxTreeItemId id = GetNext (item, false);
2185 if (IsVisible (id, fullRow)) return id;
2186 id = GetNext (id, false);
2188 return wxTreeItemId();
2191 wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow) const {
2192 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2193 wxTreeItemId id = GetPrev (item, true);
2195 if (IsVisible (id, fullRow)) return id;
2196 id = GetPrev(id, true);
2198 return wxTreeItemId();
2201 // ----------------------------------------------------------------------------
2203 // ----------------------------------------------------------------------------
2205 wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId,
2207 const wxString& text,
2208 int image, int selImage,
2209 wxTreeItemData *data) {
2210 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2211 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2212 m_dirty = true; // do this first so stuff below doesn't cause flicker
2215 arr.Alloc (GetColumnCount());
2216 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2217 arr[m_main_column] = text;
2218 wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data);
2220 #if !wxCHECK_VERSION(2, 5, 0)
2221 data->SetId ((long)item);
2226 parent->Insert (item, previous);
2231 wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text,
2232 int image, int selImage,
2233 wxTreeItemData *data) {
2234 wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
2235 wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2236 m_dirty = true; // do this first so stuff below doesn't cause flicker
2239 arr.Alloc (GetColumnCount());
2240 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2241 arr[m_main_column] = text;
2242 m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data);
2244 #if !wxCHECK_VERSION(2, 5, 0)
2245 data->SetId((long)m_rootItem);
2247 data->SetId(m_rootItem);
2250 if (HasFlag(wxTR_HIDE_ROOT)) {
2251 // if we will hide the root, make sure children are visible
2252 m_rootItem->SetHasPlus();
2253 m_rootItem->Expand();
2254 #if !wxCHECK_VERSION(2, 5, 0)
2257 wxTreeItemIdValue cookie = 0;
2259 m_curItem = (wxTreeListItem*)GetFirstChild (m_rootItem, cookie).m_pItem;
2264 wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent,
2265 const wxString& text,
2266 int image, int selImage,
2267 wxTreeItemData *data) {
2268 return DoInsertItem (parent, 0u, text, image, selImage, data);
2271 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2272 const wxTreeItemId& idPrevious,
2273 const wxString& text,
2274 int image, int selImage,
2275 wxTreeItemData *data) {
2276 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2277 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2279 int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
2280 wxASSERT_MSG( index != wxNOT_FOUND,
2281 _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
2283 return DoInsertItem (parentId, ++index, text, image, selImage, data);
2286 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2288 const wxString& text,
2289 int image, int selImage,
2290 wxTreeItemData *data) {
2291 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2292 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2294 return DoInsertItem (parentId, before, text, image, selImage, data);
2297 wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId,
2298 const wxString& text,
2299 int image, int selImage,
2300 wxTreeItemData *data) {
2301 wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
2302 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2304 return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data);
2307 void wxTreeListMainWindow::SendDeleteEvent (wxTreeListItem *item) {
2308 // send event to user code
2309 wxTreeEvent event (wxEVT_COMMAND_TREE_DELETE_ITEM, m_owner->GetId());
2310 #if !wxCHECK_VERSION(2, 5, 0)
2311 event.SetItem ((long)item);
2313 event.SetItem (item);
2315 event.SetEventObject (m_owner);
2316 m_owner->ProcessEvent (event);
2319 void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
2320 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2321 wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
2322 m_dirty = true; // do this first so stuff below doesn't cause flicker
2324 // don't stay with invalid m_shiftItem or we will crash in the next call to OnChar()
2325 bool changeKeyCurrent = false;
2326 wxTreeListItem *itemKey = m_shiftItem;
2328 if (itemKey == item) { // m_shiftItem is a descendant of the item being deleted
2329 changeKeyCurrent = true;
2332 itemKey = itemKey->GetItemParent();
2335 wxTreeListItem *parent = item->GetItemParent();
2337 parent->GetChildren().Remove (item); // remove by value
2339 if (changeKeyCurrent) m_shiftItem = parent;
2341 SendDeleteEvent (item);
2343 RemoveFromSelection(item);
2344 // if (item->IsSelected()) Unselect(item);
2345 //if (m_selectItem == item) m_selectItem = (wxTreeListItem*)NULL;
2346 item->DeleteChildren (this);
2350 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
2351 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2352 m_dirty = true; // do this first so stuff below doesn't cause flicker
2354 item->DeleteChildren (this);
2357 void wxTreeListMainWindow::DeleteRoot() {
2360 SendDeleteEvent (m_rootItem);
2361 m_curItem = (wxTreeListItem*)NULL;
2363 // m_selectItem= (wxTreeListItem*)NULL;
2365 m_rootItem->DeleteChildren (this);
2371 void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
2372 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2373 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
2375 if (!item->HasPlus() || item->IsExpanded()) return;
2377 // send event to user code
2378 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_EXPANDING, m_owner->GetId());
2379 #if !wxCHECK_VERSION(2, 5, 0)
2380 event.SetItem ((long)item);
2382 event.SetItem (item);
2384 event.SetEventObject (m_owner);
2385 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // expand canceled
2390 // send event to user code
2391 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
2392 m_owner->ProcessEvent (event);
2395 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
2397 if (!IsExpanded (itemId)) return;
2398 #if !wxCHECK_VERSION(2, 5, 0)
2401 wxTreeItemIdValue cookie;
2403 wxTreeItemId child = GetFirstChild (itemId, cookie);
2404 while (child.IsOk()) {
2406 child = GetNextChild (itemId, cookie);
2410 void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
2411 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2412 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
2414 if (!item->HasPlus() || !item->IsExpanded()) return;
2416 // send event to user code
2417 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, m_owner->GetId() );
2418 #if !wxCHECK_VERSION(2, 5, 0)
2419 event.SetItem ((long)item);
2421 event.SetItem (item);
2423 event.SetEventObject (m_owner);
2424 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // collapse canceled
2429 // send event to user code
2430 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
2431 ProcessEvent (event);
2434 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
2436 DeleteChildren (item);
2439 void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
2440 if (IsExpanded (itemId)) {
2447 void wxTreeListMainWindow::Unselect() {
2449 m_selectItem->SetHilight (false);
2450 RefreshLine (m_selectItem);
2451 m_selectItem = (wxTreeListItem*)NULL;
2455 // LG 19/09/08 : Added
2457 void wxTreeListMainWindow::Unselect(wxTreeListItem* item)
2459 if (item->IsSelected()) {
2460 item->SetSelected (false);
2462 m_selected.Remove(item);
2463 // LG : TODO : Remove from array
2464 // if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
2469 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
2470 if (item->IsSelected()) {
2471 item->SetHilight (false);
2473 if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
2475 if (item->HasChildren()) {
2476 wxArrayTreeListItems& children = item->GetChildren();
2477 size_t count = children.Count();
2478 for (size_t n = 0; n < count; ++n) {
2479 UnselectAllChildren (children[n]);
2484 void wxTreeListMainWindow::UnselectAll() {
2486 size_t count = m_selected.Count();
2487 for (size_t n = 0; n < count; ++n)
2489 m_selected[n]->SetSelected (false);
2490 RefreshLine (m_selected[n]);
2494 //UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
2497 // Recursive function !
2498 // To stop we must have crt_item<last_item
2500 // Tag all next children, when no more children,
2501 // Move to parent (not to tag)
2502 // Keep going... if we found last_item, we stop.
2503 bool wxTreeListMainWindow::SelectNextChildren (wxTreeListItem *crt_item,
2504 wxTreeListItem *last_item) {
2505 wxTreeListItem *parent = crt_item->GetItemParent();
2507 if (!parent) {// This is root item
2508 return SelectAllChildrenUntilLast (crt_item, last_item);
2511 wxArrayTreeListItems& children = parent->GetChildren();
2512 int index = children.Index(crt_item);
2513 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2515 if ((parent->HasChildren() && parent->IsExpanded()) ||
2516 ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
2517 size_t count = children.Count();
2518 for (size_t n = (index+1); n < count; ++n) {
2519 if (SelectAllChildrenUntilLast (children[n], last_item)) return true;
2523 return SelectNextChildren (parent, last_item);
2526 bool wxTreeListMainWindow::SelectAllChildrenUntilLast (wxTreeListItem *crt_item,
2527 wxTreeListItem *last_item) {
2528 if (!crt_item->IsSelected())
2530 // LG : Send event to user to know is selection is accepted
2531 // send event to the user code
2532 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId() );
2533 #if !wxCHECK_VERSION(2, 5, 0)
2534 event.SetItem ((long)crt_item);
2536 event.SetItem (crt_item);
2538 event.SetEventObject (m_owner);
2539 if (m_owner->GetEventHandler()->ProcessEvent (event) && event.IsAllowed())
2541 AddToSelection(crt_item);
2545 if (crt_item==last_item) return true;
2547 if (crt_item->HasChildren() && crt_item->IsExpanded()) {
2548 wxArrayTreeListItems& children = crt_item->GetChildren();
2549 size_t count = children.Count();
2550 for (size_t n = 0; n < count; ++n) {
2551 if (SelectAllChildrenUntilLast (children[n], last_item)) return true;
2558 void wxTreeListMainWindow::RemoveFromSelection( wxTreeListItem *item )
2560 if (!item->IsSelected()) return;
2561 item->SetSelected(false);
2562 m_selected.Remove(item);
2566 void wxTreeListMainWindow::AddToSelection( wxTreeListItem *item )
2568 if (item->IsSelected()) return;
2569 item->SetSelected(true);
2570 m_selected.Add(item);
2574 void wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
2575 const wxTreeItemId& lastId,
2576 bool unselect_others) {
2577 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item") );
2579 bool is_single = !HasFlag(wxTR_MULTIPLE);
2580 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2583 // single selection requires unselect others
2584 if (is_single) unselect_others = true;
2586 // unselect all if unselect other items
2587 bool unselected = false; // see that UnselectAll is done only once
2588 if (unselect_others) {
2591 Unselect(); // to speed up thing
2599 // LG : Update current item
2600 wxTreeListItem *old_curItem = m_curItem;
2602 if (old_curItem) RefreshLine (old_curItem);
2604 // select item or item range
2605 if (lastId.IsOk() && (itemId != lastId))
2609 if (!unselected) UnselectAll();
2610 wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
2612 // LG : Update current item
2613 // wxTreeListItem *old_curItem = m_curItem;
2614 // m_curItem = last;
2615 // if (old_curItem) RefreshLine (old_curItem);
2617 // ensure that the position of the item it calculated in any case
2618 if (m_dirty) CalculatePositions();
2620 // select item range according Y-position
2621 if (last->GetY() < item->GetY()) {
2622 if (!SelectAllChildrenUntilLast (last, item)) {
2623 SelectNextChildren (last, item);
2626 if (!SelectAllChildrenUntilLast (item, last)) {
2627 SelectNextChildren (item, last);
2635 // send event to the user code
2636 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId() );
2637 #if !wxCHECK_VERSION(2, 5, 0)
2638 event.SetItem ((long)item);
2639 event.SetOldItem ((long)m_curItem);
2641 event.SetItem (item);
2642 event.SetOldItem (m_curItem);
2644 event.SetEventObject (m_owner);
2648 if (m_owner->GetEventHandler()->ProcessEvent (event) &&
2651 // select item according its old selection
2652 if (item->IsSelected())
2653 RemoveFromSelection(item);
2655 AddToSelection(item);
2659 // send event to user code
2660 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGED, m_owner->GetId() );
2661 m_owner->GetEventHandler()->ProcessEvent (event);
2664 void wxTreeListMainWindow::SelectAll() {
2665 wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
2667 #if !wxCHECK_VERSION(2, 5, 0)
2670 wxTreeItemIdValue cookie = 0;
2672 wxTreeItemId root = GetRootItem();
2673 wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
2674 wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
2675 if (!SelectAllChildrenUntilLast (first, last)) {
2676 SelectNextChildren (first, last);
2679 // send event to user code
2680 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGED, m_owner->GetId() );
2681 m_owner->GetEventHandler()->ProcessEvent (event);
2684 void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
2685 wxArrayTreeItemIds &array) const {
2686 if (item->IsSelected()) array.Add (wxTreeItemId(item));
2688 if (item->HasChildren()) {
2689 wxArrayTreeListItems& children = item->GetChildren();
2690 size_t count = children.GetCount();
2691 for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
2696 // returns the number of currently selected items
2697 size_t wxTreeListMainWindow::GetSelectionSize() const
2699 return m_selected.GetCount();
2702 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
2704 LG : NOT OK AS IS NOT IN TREE ORDER
2706 size_t count = m_selected.GetCount();
2707 for (size_t n = 0; n < count; ++n) array.Add(m_selected[n]);
2709 wxTreeItemId idRoot = GetRootItem();
2710 if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
2711 return array.Count();
2714 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
2715 if (!item.IsOk()) return; // do nothing if no item
2717 // first expand all parent branches
2718 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2719 wxTreeListItem *parent = gitem->GetItemParent();
2722 parent = parent->GetItemParent();
2726 RefreshLine (gitem);
2729 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
2730 if (!item.IsOk()) return; // do nothing if no item
2732 // ensure that the position of the item it calculated in any case
2733 if (m_dirty) CalculatePositions();
2735 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2737 // now scroll to the item
2738 int item_y = gitem->GetY();
2741 GetScrollPixelsPerUnit (&xUnit, &yUnit);
2744 GetViewStart (&start_x, &start_y);
2749 GetClientSize (&client_w, &client_h);
2753 m_rootItem->GetSize (x, y, this);
2754 x = m_owner->GetHeaderWindow()->GetWidth();
2755 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2756 int x_pos = GetScrollPos( wxHORIZONTAL );
2758 if (item_y < start_y+3) {
2759 // going down, item should appear at top
2760 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
2761 }else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
2762 // going up, item should appear at bottom
2763 item_y += yUnit + 2;
2764 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
2768 // FIXME: tree sorting functions are not reentrant and not MT-safe!
2769 static wxTreeListMainWindow *s_treeBeingSorted = NULL;
2771 static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1,
2772 wxTreeListItem **item2)
2774 wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
2776 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
2779 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1,
2780 const wxTreeItemId& item2)
2782 return m_owner->OnCompareItems (item1, item2);
2785 void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId) {
2786 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
2788 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2790 wxCHECK_RET (!s_treeBeingSorted,
2791 _T("wxTreeListMainWindow::SortChildren is not reentrant") );
2793 wxArrayTreeListItems& children = item->GetChildren();
2794 if ( children.Count() > 1 ) {
2796 s_treeBeingSorted = this;
2797 children.Sort(tree_ctrl_compare_func);
2798 s_treeBeingSorted = NULL;
2802 wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, const wxString& str, int mode) {
2804 // determine start item
2805 wxTreeItemId next = item;
2807 if (mode & wxTL_MODE_NAV_LEVEL) {
2808 next = GetNextSibling (next);
2809 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2810 next = GetNextVisible (next, false);
2811 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2812 next = GetNextExpanded (next);
2813 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2814 next = GetNext (next, true);
2818 #if !wxCHECK_VERSION(2, 5, 0)
2821 wxTreeItemIdValue cookie = 0;
2824 next = (wxTreeListItem*)GetRootItem().m_pItem;
2825 if (HasFlag(wxTR_HIDE_ROOT)) {
2826 next = (wxTreeListItem*)GetFirstChild (GetRootItem().m_pItem, cookie).m_pItem;
2829 if (!next.IsOk()) return (wxTreeItemId*)NULL;
2831 // start checking the next items
2832 while (next.IsOk() && (next != item)) {
2833 if (mode & wxTL_MODE_FIND_PARTIAL) {
2834 itemText = GetItemText (next).Mid (0, str.Length());
2836 itemText = GetItemText (next);
2838 if (mode & wxTL_MODE_FIND_NOCASE) {
2839 if (itemText.CmpNoCase (str) == 0) return next;
2841 if (itemText.Cmp (str) == 0) return next;
2843 if (mode & wxTL_MODE_NAV_LEVEL) {
2844 next = GetNextSibling (next);
2845 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2846 next = GetNextVisible (next, false);
2847 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2848 next = GetNextExpanded (next);
2849 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2850 next = GetNext (next, true);
2852 if (!next.IsOk() && item.IsOk()) {
2853 next = (wxTreeListItem*)GetRootItem().m_pItem;
2854 if (HasFlag(wxTR_HIDE_ROOT)) {
2855 next = (wxTreeListItem*)GetNextChild (GetRootItem().m_pItem, cookie).m_pItem;
2859 return (wxTreeItemId*)NULL;
2862 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
2863 wxTreeListItem *prevItem = m_dragItem;
2864 m_dragItem = (wxTreeListItem*) item.m_pItem;
2865 if (prevItem) RefreshLine (prevItem);
2866 if (m_dragItem) RefreshLine (m_dragItem);
2869 void wxTreeListMainWindow::CalculateLineHeight() {
2870 wxClientDC dc (this);
2871 dc.SetFont (m_normalFont);
2872 m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
2874 if (m_imageListNormal) {
2875 // Calculate a m_lineHeight value from the normal Image sizes.
2876 // May be toggle off. Then wxTreeListMainWindow will spread when
2877 // necessary (which might look ugly).
2878 int n = m_imageListNormal->GetImageCount();
2879 for (int i = 0; i < n ; i++) {
2880 int width = 0, height = 0;
2881 m_imageListNormal->GetSize(i, width, height);
2882 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
2886 if (m_imageListButtons) {
2887 // Calculate a m_lineHeight value from the Button image sizes.
2888 // May be toggle off. Then wxTreeListMainWindow will spread when
2889 // necessary (which might look ugly).
2890 int n = m_imageListButtons->GetImageCount();
2891 for (int i = 0; i < n ; i++) {
2892 int width = 0, height = 0;
2893 m_imageListButtons->GetSize(i, width, height);
2894 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
2898 if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
2899 m_lineHeight += 2; // minimal 2 pixel space
2901 m_lineHeight += m_lineHeight / 10; // otherwise 10% space
2905 void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
2906 if (m_ownsImageListNormal) delete m_imageListNormal;
2907 m_imageListNormal = imageList;
2908 m_ownsImageListNormal = false;
2910 CalculateLineHeight();
2913 void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
2914 if (m_ownsImageListState) delete m_imageListState;
2915 m_imageListState = imageList;
2916 m_ownsImageListState = false;
2919 void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
2920 if (m_ownsImageListButtons) delete m_imageListButtons;
2921 m_imageListButtons = imageList;
2922 m_ownsImageListButtons = false;
2924 CalculateLineHeight();
2927 void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
2928 SetImageList(imageList);
2929 m_ownsImageListNormal = true;
2932 void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
2933 SetStateImageList(imageList);
2934 m_ownsImageListState = true;
2937 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
2938 SetButtonsImageList(imageList);
2939 m_ownsImageListButtons = true;
2942 // ----------------------------------------------------------------------------
2944 // ----------------------------------------------------------------------------
2946 void wxTreeListMainWindow::AdjustMyScrollbars() {
2949 GetScrollPixelsPerUnit (&xUnit, &yUnit);
2950 if (xUnit == 0) xUnit = GetCharWidth();
2951 if (yUnit == 0) yUnit = m_lineHeight;
2953 m_rootItem->GetSize (x, y, this);
2954 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2955 int x_pos = GetScrollPos (wxHORIZONTAL);
2956 int y_pos = GetScrollPos (wxVERTICAL);
2957 x = m_owner->GetHeaderWindow()->GetWidth() + 2;
2958 if (x < GetClientSize().GetWidth()) x_pos = 0;
2959 SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
2961 SetScrollbars (0, 0, 0, 0);
2965 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
2966 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
2967 return item->GetHeight();
2969 return m_lineHeight;
2973 void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
2975 wxTreeItemAttr *attr = item->GetAttributes();
2977 dc.SetFont (GetItemFont (item));
2980 if (attr && attr->HasTextColour()) {
2981 colText = attr->GetTextColour();
2983 colText = GetForegroundColour();
2985 #if !wxCHECK_VERSION(2, 5, 0)
2986 wxColour colTextHilight = wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2988 wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2991 int total_w = m_owner->GetHeaderWindow()->GetWidth();
2992 int total_h = GetLineHeight(item);
2993 int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
2994 // std::cout << "off_h="<<off_h<<std::endl;
2996 wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
2998 int text_w = 0, text_h = 0;
2999 dc.GetTextExtent( item->GetText(GetMainColumn()), &text_w, &text_h );
3001 // determine background and show it
3003 if (attr && attr->HasBackgroundColour()) {
3004 colBg = attr->GetBackgroundColour();
3006 colBg = m_backgroundColour;
3008 dc.SetBrush (wxBrush (colBg, wxSOLID));
3009 dc.SetPen (*wxTRANSPARENT_PEN);
3010 if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3011 if (item == m_dragItem) {
3012 dc.SetBrush (*m_hilightBrush);
3013 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3014 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3015 #endif // !__WXMAC__
3016 dc.SetTextForeground (colTextHilight);
3017 }else if (item->IsSelected()) {
3018 if (!m_isDragging && m_hasFocus) {
3019 dc.SetBrush (*m_hilightBrush);
3020 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3021 // LG : dc.SetPen (*wxBLACK_PEN);
3022 dc.SetPen (*wxTRANSPARENT_PEN);
3023 #endif // !__WXMAC__
3025 dc.SetBrush (*m_hilightUnfocusedBrush);
3026 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3027 dc.SetPen (*wxTRANSPARENT_PEN);
3028 #endif // !__WXMAC__
3030 dc.SetTextForeground (colTextHilight);
3033 else if (item == m_curItem) {
3034 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3037 dc.SetTextForeground (colText);
3040 dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
3042 dc.SetTextForeground (colText);
3045 int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
3046 int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
3048 for (int i = 0; i < GetColumnCount(); ++i ) {
3049 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3051 int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
3052 wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
3055 int image = NO_IMAGE;
3057 if(i == GetMainColumn()) {
3058 x = item->GetX() + MARGIN;
3060 x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
3064 if (m_imageListNormal) image = item->GetCurrentImage();
3066 x = x_colstart + MARGIN;
3067 image = item->GetImage(i);
3069 if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
3071 // honor text alignment
3072 wxString text = item->GetText(i);
3074 switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
3076 // nothing to do, already left aligned
3079 dc.GetTextExtent (text, &text_w, NULL);
3080 w = col_w - (image_w + text_w + MARGIN);
3083 case wxALIGN_CENTER:
3084 dc.GetTextExtent(text, &text_w, NULL);
3085 w = (col_w - (image_w + text_w + MARGIN))/2;
3089 int text_x = x + image_w;
3090 if (i == GetMainColumn()) item->SetTextX (text_x);
3092 if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3093 if (i == GetMainColumn()) {
3094 if (item == m_dragItem) {
3095 dc.SetBrush (*m_hilightBrush);
3096 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3097 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3098 #endif // !__WXMAC__
3099 dc.SetTextForeground (colTextHilight);
3100 }else if (item->IsSelected()) {
3101 if (!m_isDragging && m_hasFocus) {
3102 dc.SetBrush (*m_hilightBrush);
3103 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3104 dc.SetPen (*wxBLACK_PEN);
3105 #endif // !__WXMAC__
3107 dc.SetBrush (*m_hilightUnfocusedBrush);
3108 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3109 dc.SetPen (*wxTRANSPARENT_PEN);
3110 #endif // !__WXMAC__
3112 dc.SetTextForeground (colTextHilight);
3115 else if (item == m_curItem) {
3116 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3119 dc.SetTextForeground (colText);
3121 dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3123 dc.SetTextForeground (colText);
3127 dc.SetBackgroundMode (wxTRANSPARENT);
3129 if (image != NO_IMAGE) {
3130 int y = item->GetY() + img_extraH;
3131 m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3133 int text_y = item->GetY() + text_extraH;
3134 dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
3136 x_colstart += col_w;
3139 // restore normal font
3140 dc.SetFont( m_normalFont );
3143 // Now y stands for the top of the item, whereas it used to stand for middle !
3144 void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
3145 int level, int &y, int x_maincol) {
3147 // Handle hide root (only level 0)
3150 //if (HasFlag(wxTR_HIDE_ROOT) && (level < nth)) {
3151 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
3153 wxArrayTreeListItems& children = item->GetChildren();
3154 for (size_t n = 0; n < children.Count(); n++) {
3155 PaintLevel (children[n], dc, 1, y, x_maincol);
3157 // end after expanding root
3161 // calculate position of vertical lines
3162 int x = x_maincol + MARGIN; // start of column
3163 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
3165 x += (m_btnWidth-m_btnWidth2); // half button space
3167 x += (m_indent-m_indent/2);
3169 if (HasFlag(wxTR_HIDE_ROOT)) {
3171 // x += m_indent * (level-nth); // indent but not level 1
3172 x += m_indent * (level-1); // indent but not level 1
3175 x += m_indent * level; // indent according to level
3178 // set position of vertical line
3182 int h = GetLineHeight (item);
3184 int y_mid = y_top + (h/2);
3187 int exposed_x = dc.LogicalToDeviceX(0);
3188 int exposed_y = dc.LogicalToDeviceY(y_top);
3190 if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
3192 if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
3193 //dc.DestroyClippingRegion();
3194 int total_width = m_owner->GetHeaderWindow()->GetWidth();
3195 // if the background colour is white, choose a
3196 // contrasting color for the lines
3197 dc.SetPen (*((GetBackgroundColour() == *wxWHITE)?
3198 wxMEDIUM_GREY_PEN : wxWHITE_PEN));
3199 dc.DrawLine(0, y_top, total_width, y_top);
3200 dc.DrawLine(0, y_top+h, total_width, y_top+h);
3204 PaintItem (item, dc);
3206 // restore DC objects
3207 dc.SetBrush(*wxWHITE_BRUSH);
3208 dc.SetPen(m_dottedPen);
3210 // clip to the column width
3211 int clip_width = m_owner->GetHeaderWindow()->
3212 GetColumn(m_main_column).GetWidth();
3213 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3215 if (!HasFlag(wxTR_NO_LINES)) { // connection lines
3217 // draw the horizontal line here
3218 dc.SetPen(m_dottedPen);
3219 int x2 = x - m_indent;
3220 if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
3221 int x3 = x + (m_btnWidth-m_btnWidth2);
3223 if (item->HasPlus()) {
3224 dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
3225 dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
3227 dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
3230 dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
3234 if (item->HasPlus() && HasButtons()) { // should the item show a button?
3236 if (m_imageListButtons) {
3238 // draw the image button here
3239 int image = wxTreeItemIcon_Normal;
3240 if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
3241 if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
3242 int xx = x - m_btnWidth2 + MARGIN;
3243 int yy = y_mid - m_btnHeight2;
3244 dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
3245 m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
3246 dc.DestroyClippingRegion();
3248 }else if (HasFlag (wxTR_TWIST_BUTTONS)) {
3250 // draw the twisty button here
3251 dc.SetPen(*wxBLACK_PEN);
3252 dc.SetBrush(*m_hilightBrush);
3254 if (item->IsExpanded()) {
3255 button[0].x = x - (m_btnWidth2+1);
3256 button[0].y = y_mid - (m_btnHeight/3);
3257 button[1].x = x + (m_btnWidth2+1);
3258 button[1].y = button[0].y;
3260 button[2].y = button[0].y + (m_btnHeight2+1);
3262 button[0].x = x - (m_btnWidth/3);
3263 button[0].y = y_mid - (m_btnHeight2+1);
3264 button[1].x = button[0].x;
3265 button[1].y = y_mid + (m_btnHeight2+1);
3266 button[2].x = button[0].x + (m_btnWidth2+1);
3267 button[2].y = y_mid;
3269 dc.DrawPolygon(3, button);
3271 }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3273 // draw the plus sign here
3274 dc.SetPen(*wxGREY_PEN);
3275 dc.SetBrush(*wxWHITE_BRUSH);
3276 dc.DrawRectangle (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3277 dc.SetPen(*wxBLACK_PEN);
3278 dc.DrawLine (x-(m_btnWidth2-2), y_mid, x+(m_btnWidth2-1), y_mid);
3279 if (!item->IsExpanded()) { // change "-" to "+"
3280 dc.DrawLine (x, y_mid-(m_btnHeight2-2), x, y_mid+(m_btnHeight2-1));
3289 // restore DC objects
3290 dc.SetBrush(*wxWHITE_BRUSH);
3291 dc.SetPen(m_dottedPen);
3292 dc.SetTextForeground(*wxBLACK);
3294 if (item->IsExpanded())
3296 wxArrayTreeListItems& children = item->GetChildren();
3298 // clip to the column width
3299 int clip_width = m_owner->GetHeaderWindow()->
3300 GetColumn(m_main_column).GetWidth();
3302 // process lower levels
3304 if (m_imgWidth > 0) {
3305 oldY = y_mid + m_imgHeight2;
3310 for (size_t n = 0; n < children.Count(); ++n) {
3313 PaintLevel (children[n], dc, level+1, y, x_maincol);
3315 // draw vertical line
3316 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3317 if (!HasFlag (wxTR_NO_LINES)) {
3319 dc.DrawLine (x, oldY, x, y2);
3327 // ----------------------------------------------------------------------------
3328 // wxWindows callbacks
3329 // ----------------------------------------------------------------------------
3331 void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
3333 wxPaintDC dc (this);
3336 if (!m_rootItem || (GetColumnCount() <= 0)) return;
3338 // calculate button size
3339 if (m_imageListButtons) {
3340 m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
3341 }else if (HasButtons()) {
3342 m_btnWidth = BTNWIDTH;
3343 m_btnHeight = BTNHEIGHT;
3345 m_btnWidth2 = m_btnWidth/2;
3346 m_btnHeight2 = m_btnHeight/2;
3348 // calculate image size
3349 if (m_imageListNormal) {
3350 m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
3352 m_imgWidth2 = m_imgWidth/2;
3353 m_imgHeight2 = m_imgHeight/2;
3355 // calculate indent size
3356 if (m_imageListButtons) {
3357 m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
3358 }else if (HasButtons()) {
3359 m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
3362 // set default values
3363 dc.SetFont( m_normalFont );
3364 dc.SetPen( m_dottedPen );
3366 // calculate column start and paint
3369 for (i = 0; i < (int)GetMainColumn(); ++i) {
3370 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3371 x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
3374 PaintLevel (m_rootItem, dc, 0, y, x_maincol);
3377 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
3381 if (m_curItem) RefreshLine (m_curItem);
3385 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
3389 if (m_curItem) RefreshLine (m_curItem);
3393 void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
3394 // send event to user code
3395 wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, m_owner->GetId());
3396 nevent.SetKeyEvent (event);
3397 nevent.SetEventObject (m_owner);
3398 if (m_owner->GetEventHandler()->ProcessEvent (nevent)) return; // handled in user code
3400 // determine first current if none
3401 bool curItemSet = false;
3403 m_curItem = (wxTreeListItem*)GetRootItem().m_pItem;
3404 if (HasFlag(wxTR_HIDE_ROOT)) {
3405 #if !wxCHECK_VERSION(2, 5, 0)
3408 wxTreeItemIdValue cookie = 0;
3410 m_curItem = (wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem;
3414 if (!m_curItem) return; // do nothing if empty tree
3416 // remember item at shift down
3417 if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
3418 if (!m_shiftItem) m_shiftItem = m_curItem;
3420 m_shiftItem = (wxTreeListItem*)NULL;
3423 // process all cases
3424 wxTreeItemId newItem = (wxTreeItemId*)NULL;
3425 switch (event.GetKeyCode()) {
3427 // '+': Expand subtree
3430 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
3433 // '-': collapse subtree
3435 case WXK_SUBTRACT: {
3436 if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
3439 // '*': expand/collapse all subtrees // TODO: Mak it more useful
3441 case WXK_MULTIPLY: {
3442 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3443 ExpandAll (m_curItem);
3444 }else if (m_curItem->HasPlus()) {
3445 Collapse (m_curItem); // TODO: CollapseAll
3449 // ' ': toggle current item
3451 SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
3454 // <RETURN>: activate current item
3456 wxTreeEvent aevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
3457 #if !wxCHECK_VERSION(2, 5, 0)
3458 aevent.SetItem ((long)m_curItem);
3460 aevent.SetItem (m_curItem);
3462 aevent.SetEventObject (m_owner);
3463 m_owner->GetEventHandler()->ProcessEvent (aevent);
3466 // <BKSP>: go to the parent without collapsing
3468 newItem = GetItemParent (m_curItem);
3469 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3470 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
3474 // <UP>: go to the previous sibling or to the last of its children, to the parent
3476 newItem = GetPrevSibling (m_curItem);
3478 #if !wxCHECK_VERSION(2, 5, 0)
3481 wxTreeItemIdValue cookie = 0;
3483 while (IsExpanded (newItem) && HasChildren (newItem)) {
3484 newItem = GetLastChild (newItem, cookie);
3487 newItem = GetItemParent (m_curItem);
3488 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3489 newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
3494 // <LEFT>: if expanded collapse subtree, else go to the parent
3496 if (IsExpanded (m_curItem)) {
3497 Collapse (m_curItem);
3499 newItem = GetItemParent (m_curItem);
3500 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3501 newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
3506 // <RIGHT>: if possible expand subtree, else go go to the first child
3508 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3511 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3512 #if !wxCHECK_VERSION(2, 5, 0)
3515 wxTreeItemIdValue cookie = 0;
3517 newItem = GetFirstChild (m_curItem, cookie);
3522 // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3525 newItem = m_curItem;
3527 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3528 #if !wxCHECK_VERSION(2, 5, 0)
3531 wxTreeItemIdValue cookie = 0;
3533 newItem = GetFirstChild( m_curItem, cookie );
3536 wxTreeItemId parent = m_curItem;
3538 newItem = GetNextSibling (parent);
3539 parent = GetItemParent (parent);
3540 } while (!newItem && parent);
3545 // <END>: go to last item of the root
3547 #if !wxCHECK_VERSION(2, 5, 0)
3550 wxTreeItemIdValue cookie = 0;
3552 newItem = GetLastChild (GetRootItem(), cookie);
3555 // <HOME>: go to root
3557 newItem = GetRootItem();
3558 if (HasFlag(wxTR_HIDE_ROOT)) {
3559 #if !wxCHECK_VERSION(2, 5, 0)
3562 wxTreeItemIdValue cookie = 0;
3564 newItem = GetFirstChild (newItem, cookie);
3568 // any char: go to the next matching string
3570 if (event.GetKeyCode() >= (int)' ') {
3571 if (!m_findTimer->IsRunning()) m_findStr.Clear();
3572 m_findStr.Append (event.GetKeyCode());
3573 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
3574 wxTreeItemId prev = m_curItem? (wxTreeItemId*)m_curItem: (wxTreeItemId*)NULL;
3576 newItem = FindItem (prev, m_findStr, wxTL_MODE_NAV_EXPANDED |
3577 wxTL_MODE_FIND_PARTIAL |
3578 wxTL_MODE_FIND_NOCASE);
3579 if (newItem || (m_findStr.Length() <= 1)) break;
3580 m_findStr.RemoveLast();
3587 // select and show the new item
3589 if (!event.ControlDown()) {
3590 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3591 HasFlag(wxTR_MULTIPLE));
3592 SelectItem (newItem, m_shiftItem, unselect_others);
3594 EnsureVisible (newItem);
3595 wxTreeListItem *oldItem = m_curItem;
3596 m_curItem = (wxTreeListItem*)newItem.m_pItem; // make the new item the current item
3597 RefreshLine (oldItem);
3602 wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
3608 if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
3609 if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
3610 if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
3611 if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
3612 if (flags) return wxTreeItemId();
3615 flags = wxTREE_HITTEST_NOWHERE;
3617 return wxTreeItemId();
3620 wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
3621 this, flags, column, 0);
3623 flags = wxTREE_HITTEST_NOWHERE;
3625 return wxTreeItemId();
3630 // get the bounding rectangle of the item (or of its label only)
3631 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
3632 bool WXUNUSED(textOnly)) const {
3633 wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
3635 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
3638 GetScrollPixelsPerUnit (&xUnit, &yUnit);
3640 GetViewStart(& startX, & startY);
3642 rect.x = item->GetX() - startX * xUnit;
3643 rect.y = item->GetY() - startY * yUnit;
3644 rect.width = item->GetWidth();
3645 rect.height = GetLineHeight (item);
3652 void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
3653 if (!item.IsOk()) return;
3654 if (!((column >= 0) && (column < GetColumnCount()))) return;
3656 m_editItem = (wxTreeListItem*) item.m_pItem;
3658 wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, m_owner->GetId() );
3659 #if !wxCHECK_VERSION(2, 5, 0)
3660 te.SetItem ((long)m_editItem);
3662 te.SetItem (m_editItem);
3665 te.SetEventObject (m_owner );
3666 m_owner->GetEventHandler()->ProcessEvent (te);
3668 if (!te.IsAllowed()) return;
3670 // ensure that the position of the item it calculated in any case
3671 if (m_dirty) CalculatePositions();
3673 wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
3675 int y = m_editItem->GetY() + 1; // wxTextCtrl needs 1 pixels above the text
3677 int h = m_editItem->GetHeight();
3679 if (column == GetMainColumn()) {
3680 x += m_editItem->GetTextX() - 2; // wxTextCtrl needs 2 pixels before the text
3681 w = wxMin (m_editItem->GetWidth(), m_owner->GetHeaderWindow()->GetWidth() - x);
3683 for (int i = 0; i < column; ++i) x += header_win->GetColumnWidth (i); // start of column
3684 switch (header_win->GetColumnAlignment (column)) {
3685 case wxALIGN_LEFT: {style = wxTE_LEFT; break;}
3686 case wxALIGN_RIGHT: {style = wxTE_RIGHT; break;}
3687 case wxALIGN_CENTER: {style = wxTE_CENTER; break;}
3689 w = header_win->GetColumnWidth (column); // width of column
3692 wxClientDC dc (this);
3694 x = dc.LogicalToDeviceX (x);
3695 y = dc.LogicalToDeviceY (y);
3697 wxEditTextCtrl *text = new wxEditTextCtrl (this, -1, &m_renameAccept, &m_renameRes,
3698 this, m_editItem->GetText (column),
3699 wxPoint (x, y), wxSize (w, h), style);
3703 void wxTreeListMainWindow::OnRenameTimer() {
3704 EditLabel (m_curItem, m_curColumn);
3707 void wxTreeListMainWindow::OnRenameAccept() {
3709 // TODO if the validator fails this causes a crash
3710 wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, m_owner->GetId() );
3711 #if !wxCHECK_VERSION(2, 5, 0)
3712 le.SetItem((long)m_editItem);
3714 le.SetItem(m_editItem);
3716 le.SetEventObject( /*this*/m_owner );
3717 le.SetLabel( m_renameRes );
3718 m_owner->GetEventHandler()->ProcessEvent( le );
3720 if (!le.IsAllowed()) return;
3722 SetItemText (m_editItem, m_curColumn, m_renameRes);
3725 void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
3726 if (!m_rootItem) return;
3728 // we process left mouse up event (enables in-place edit), right down
3729 // (pass to the user code), left dbl click (activate item) and
3730 // dragging/moving events for items drag-and-drop
3731 if (!(event.LeftDown() ||
3733 event.RightDown() ||
3735 event.LeftDClick() ||
3737 (event.GetWheelRotation() != 0 )/*? TODO ||
3738 event.Moving()?*/)) {
3739 m_owner->GetEventHandler()->ProcessEvent (event);
3743 // set focus if window clicked
3744 if (event.LeftDown() || event.RightDown()) SetFocus();
3747 wxPoint p = wxPoint (event.GetX(), event.GetY());
3749 wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
3750 this, flags, m_curColumn, 0);
3752 // we only process dragging here
3753 if (event.Dragging()){
3754 if (m_isDragging) return; // nothing to do, already done
3755 if (item == NULL) return; // we need an item to dragging
3757 // determine drag start
3758 if (m_dragCount == 0) {
3759 m_dragTimer->Start (DRAG_TIMER_TICKS, wxTIMER_ONE_SHOT);
3762 if (m_dragCount < 3) return; // minimum drag 3 pixel
3763 if (m_dragTimer->IsRunning()) return;
3765 // we're going to drag
3767 m_isDragging = true;
3771 // send drag start event
3772 wxEventType command = event.LeftIsDown()
3773 ? wxEVT_COMMAND_TREE_BEGIN_DRAG
3774 : wxEVT_COMMAND_TREE_BEGIN_RDRAG;
3775 wxTreeEvent nevent (command, m_owner->GetId());
3776 nevent.SetEventObject (m_owner);
3777 #if !wxCHECK_VERSION(2, 5, 0)
3778 nevent.SetItem ((long)item); // the item the drag is ended
3780 nevent.SetItem (item); // the item the drag is ended
3782 nevent.Veto(); // dragging must be explicit allowed!
3783 m_owner->GetEventHandler()->ProcessEvent (nevent);
3785 }else if (m_isDragging) { // any other event but not event.Dragging()
3789 m_isDragging = false;
3790 if (HasCapture()) ReleaseMouse();
3793 // send drag end event event
3794 wxTreeEvent nevent (wxEVT_COMMAND_TREE_END_DRAG, m_owner->GetId());
3795 nevent.SetEventObject (m_owner);
3796 #if !wxCHECK_VERSION(2, 5, 0)
3797 nevent.SetItem ((long)item); // the item the drag is started
3799 nevent.SetItem (item); // the item the drag is started
3801 nevent.SetPoint (p);
3802 m_owner->GetEventHandler()->ProcessEvent (nevent);
3804 }else if (m_dragCount > 0) { // just in case dragging is initiated
3811 // we process only the messages which happen on tree items
3813 m_owner->GetEventHandler()->ProcessEvent (event);
3817 // remember item at shift down
3818 if (event.ShiftDown()) {
3819 if (!m_shiftItem) m_shiftItem = m_curItem;
3821 m_shiftItem = (wxTreeListItem*)NULL;
3824 if (event.RightUp()) {
3827 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, m_owner->GetId());
3828 nevent.SetEventObject (m_owner);
3829 #if !wxCHECK_VERSION(2, 5, 0)
3830 nevent.SetItem ((long)item); // the item clicked
3832 nevent.SetItem (item); // the item clicked
3834 nevent.SetInt (m_curColumn); // the colum clicked
3835 nevent.SetPoint (p);
3836 m_owner->GetEventHandler()->ProcessEvent (nevent);
3838 }else if (event.LeftUp()) {
3841 if ((item == m_curItem) && (m_curColumn != -1) &&
3842 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
3843 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))){
3844 m_renameTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
3846 m_lastOnSame = false;
3849 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3850 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3851 HasButtons() && item->HasPlus()) {
3854 // only toggle the item for a single click, double click on
3855 // the button doesn't do anything (it toggles the item twice)
3856 if (event.LeftDown()) Toggle (item);
3858 // don't select the item if the button was clicked
3862 // determine the selection if not done by left down
3863 if (!m_left_down_selection) {
3864 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3865 HasFlag(wxTR_MULTIPLE));
3867 SelectItem (item, m_shiftItem, unselect_others);
3868 EnsureVisible (item);
3869 // LG m_curItem = item; // make the new item the current item
3871 m_left_down_selection = false;
3874 }else if (event.LeftDown() || event.RightDown() || event.LeftDClick()) {
3876 if (event.LeftDown() || event.RightDown()) {
3878 m_lastOnSame = item == m_curItem;
3881 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3882 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3885 // only toggle the item for a single click, double click on
3886 // the button doesn't do anything (it toggles the item twice)
3888 if (event.LeftDown()) Toggle (item);
3890 // don't select the item if the button was clicked
3894 // determine the selection if the current item is not selected
3895 if (!item->IsSelected()) {
3896 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3897 HasFlag(wxTR_MULTIPLE));
3898 SelectItem (item, m_shiftItem, unselect_others);
3899 EnsureVisible (item);
3900 // LG m_curItem = item; // make the new item the current item
3901 m_left_down_selection = true;
3904 // For some reason, Windows isn't recognizing a left double-click,
3905 // so we need to simulate it here. Allow 200 milliseconds for now.
3906 if (event.LeftDClick()) {
3908 // double clicking should not start editing the item label
3909 m_renameTimer->Stop();
3910 m_lastOnSame = false;
3912 // send activate event first
3913 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
3914 nevent.SetEventObject (m_owner);
3915 #if !wxCHECK_VERSION(2, 5, 0)
3916 nevent.SetItem ((long)item); // the item clicked
3918 nevent.SetItem (item); // the item clicked
3920 nevent.SetInt (m_curColumn); // the colum clicked
3921 nevent.SetPoint (p);
3922 if (!m_owner->GetEventHandler()->ProcessEvent (nevent)) {
3924 // if the user code didn't process the activate event,
3925 // handle it ourselves by toggling the item when it is
3928 if (item->HasPlus()) Toggle(item);
3932 }else{ // any other event skip just in case
3939 void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
3940 /* after all changes have been done to the tree control,
3941 * we actually redraw the tree when everything is over */
3943 if (!m_dirty) return;
3947 CalculatePositions();
3949 AdjustMyScrollbars();
3952 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
3954 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
3955 wxScrolledWindow::OnScroll(event);
3957 HandleOnScroll( event );
3960 if(event.GetOrientation() == wxHORIZONTAL) {
3961 m_owner->GetHeaderWindow()->Refresh();
3962 m_owner->GetHeaderWindow()->Update();
3966 void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
3970 dc.SetFont (GetItemFont (item));
3972 dc.GetTextExtent (item->GetText (m_main_column), &text_w, &text_h);
3974 // restore normal font
3975 dc.SetFont (m_normalFont);
3977 int total_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
3978 if (total_h < 30) { // add 10% space if greater than 30 pixels
3979 total_h += 2; // minimal 2 pixel space
3981 total_h += total_h / 10; // otherwise 10% space
3984 item->SetHeight (total_h);
3985 if (total_h > m_lineHeight) m_lineHeight = total_h;
3986 item->SetWidth(m_imgWidth + text_w +2);
3989 // -----------------------------------------------------------------------------
3990 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
3991 int level, int &y, int x_colstart) {
3993 // calculate position of vertical lines
3994 int x = x_colstart + MARGIN; // start of column
3995 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
3997 x += (m_btnWidth-m_btnWidth2); // half button space
3999 x += (m_indent-m_indent/2);
4001 if (HasFlag(wxTR_HIDE_ROOT)) {
4003 // x += m_indent * (level-2); // indent but not level 1
4004 x += m_indent * (level-1); // indent but not level 1
4007 x += m_indent * level; // indent according to level
4010 // a hidden root is not evaluated, but its children are always
4011 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
4013 CalculateSize( item, dc );
4018 y += GetLineHeight(item);
4020 // we don't need to calculate collapsed branches
4021 if ( !item->IsExpanded() ) return;
4024 wxArrayTreeListItems& children = item->GetChildren();
4025 long n, count = (long)children.Count();
4027 for (n = 0; n < count; ++n) {
4028 CalculateLevel( children[n], dc, level, y, x_colstart ); // recurse
4032 void wxTreeListMainWindow::CalculatePositions() {
4033 if ( !m_rootItem ) return;
4035 wxClientDC dc(this);
4038 dc.SetFont( m_normalFont );
4040 dc.SetPen( m_dottedPen );
4041 //if(GetImageList() == NULL)
4042 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
4046 for (int i = 0; i < (int)GetMainColumn(); ++i) {
4047 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
4048 x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
4050 CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
4053 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
4054 if (m_dirty) return;
4056 wxClientDC dc(this);
4061 GetVirtualSize( &cw, &ch );
4064 rect.x = dc.LogicalToDeviceX( 0 );
4066 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
4069 Refresh (true, &rect );
4070 AdjustMyScrollbars();
4073 void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
4076 // std::cout << "RefreshLine = "<<item<<std::endl;
4079 if (m_dirty) return;
4081 wxClientDC dc(this);
4086 GetVirtualSize( &cw, &ch );
4089 rect.x = dc.LogicalToDeviceX( 0 );
4090 rect.y = dc.LogicalToDeviceY( item->GetY() );
4092 rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
4094 Refresh (true, &rect);
4097 void wxTreeListMainWindow::RefreshSelected()
4100 long count = m_selected.GetCount();
4101 for (long n = 0; n < count; n++ )
4103 RefreshLine (m_selected[n]);
4108 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
4109 if (item->IsSelected()) {
4113 const wxArrayTreeListItems& children = item->GetChildren();
4114 long count = children.GetCount();
4115 for (long n = 0; n < count; n++ ) {
4116 RefreshSelectedUnder (children[n]);
4121 // ----------------------------------------------------------------------------
4122 // changing colours: we need to refresh the tree control
4123 // ----------------------------------------------------------------------------
4125 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
4126 if (!wxWindow::SetBackgroundColour(colour)) return false;
4132 bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
4133 if (!wxWindow::SetForegroundColour(colour)) return false;
4139 void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column,
4140 const wxString& text) {
4141 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
4143 wxClientDC dc (this);
4144 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
4145 item->SetText (column, text);
4146 CalculateSize (item, dc);
4150 wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId,
4152 wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
4154 if( IsVirtual() ) return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
4155 else return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
4158 wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item,
4160 wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4161 return m_owner->OnGetItemText(item,column);
4164 void wxTreeListMainWindow::SetFocus() {
4165 wxWindow::SetFocus();
4168 wxFont wxTreeListMainWindow::GetItemFont (wxTreeListItem *item) {
4169 wxTreeItemAttr *attr = item->GetAttributes();
4171 if (attr && attr->HasFont()) {
4172 return attr->GetFont();
4173 }else if (item->IsBold()) {
4176 return m_normalFont;
4180 int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
4181 if (!item) return 0;
4183 // determine item width
4185 wxFont font = GetItemFont (item);
4186 GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
4190 int width = w + 2*MARGIN;
4191 if (column == GetMainColumn()) {
4193 if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
4194 if (HasButtons()) width += m_btnWidth + LINEATROOT;
4195 if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
4197 // count indent level
4199 wxTreeListItem *parent = item->GetItemParent();
4200 wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
4201 while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
4203 parent = parent->GetItemParent();
4205 if (level) width += level * GetIndent();
4211 int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
4213 GetClientSize (&maxWidth, &h);
4216 // get root if on item
4217 if (!parent.IsOk()) parent = GetRootItem();
4220 if (!HasFlag(wxTR_HIDE_ROOT)) {
4221 int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
4222 if (width < w) width = w;
4223 if (width > maxWidth) return maxWidth;
4226 wxTreeItemIdValue cookie = 0;
4227 wxTreeItemId item = GetFirstChild (parent, cookie);
4228 while (item.IsOk()) {
4229 int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
4230 if (width < w) width = w;
4231 if (width > maxWidth) return maxWidth;
4233 // check the children of this item
4234 if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
4235 int w = GetBestColumnWidth (column, item);
4236 if (width < w) width = w;
4237 if (width > maxWidth) return maxWidth;
4241 item = GetNextChild (parent, cookie);
4248 //-----------------------------------------------------------------------------
4250 //-----------------------------------------------------------------------------
4252 //IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
4253 //IMPLEMENT_CLASS(wxTreeListCtrl, wxControl);
4255 BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
4256 EVT_SIZE(wxTreeListCtrl::OnSize)
4259 bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
4262 long style, const wxValidator &validator,
4263 const wxString& name)
4265 long main_style = style & ~(wxSIMPLE_BORDER|wxSUNKEN_BORDER|wxDOUBLE_BORDER|
4266 wxRAISED_BORDER|wxSTATIC_BORDER);
4267 long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
4269 if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
4272 m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
4273 main_style, validator);
4274 m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
4275 wxPoint(0, 0), wxDefaultSize,
4277 CalculateAndSetHeaderHeight();
4281 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4285 // we use 'g' to get the descent, too
4287 m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
4288 h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
4290 // only update if changed
4291 if (h != m_headerHeight) {
4298 void wxTreeListCtrl::DoHeaderLayout()
4301 GetClientSize(&w, &h);
4303 m_header_win->SetSize (0, 0, w, m_headerHeight);
4304 m_header_win->Refresh();
4307 m_main_win->SetSize (0, m_headerHeight + 1, w, h - m_headerHeight - 1);
4311 void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
4316 size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
4318 unsigned int wxTreeListCtrl::GetIndent() const
4319 { return m_main_win->GetIndent(); }
4321 void wxTreeListCtrl::SetIndent(unsigned int indent)
4322 { m_main_win->SetIndent(indent); }
4324 unsigned int wxTreeListCtrl::GetLineSpacing() const
4325 { return m_main_win->GetLineSpacing(); }
4327 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
4328 { m_main_win->SetLineSpacing(spacing); }
4330 wxImageList* wxTreeListCtrl::GetImageList() const
4331 { return m_main_win->GetImageList(); }
4333 wxImageList* wxTreeListCtrl::GetStateImageList() const
4334 { return m_main_win->GetStateImageList(); }
4336 wxImageList* wxTreeListCtrl::GetButtonsImageList() const
4337 { return m_main_win->GetButtonsImageList(); }
4339 void wxTreeListCtrl::SetImageList(wxImageList* imageList)
4340 { m_main_win->SetImageList(imageList); }
4342 void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
4343 { m_main_win->SetStateImageList(imageList); }
4345 void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
4346 { m_main_win->SetButtonsImageList(imageList); }
4348 void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
4349 { m_main_win->AssignImageList(imageList); }
4351 void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
4352 { m_main_win->AssignStateImageList(imageList); }
4354 void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
4355 { m_main_win->AssignButtonsImageList(imageList); }
4357 wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
4358 { return m_main_win->GetItemText (item, column); }
4360 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column,
4361 wxTreeItemIcon which) const
4362 { return m_main_win->GetItemImage(item, column, which); }
4364 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
4365 { return m_main_win->GetItemData(item); }
4367 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
4368 { return m_main_win->GetItemBold(item); }
4370 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
4371 { return m_main_win->GetItemTextColour(item); }
4373 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item)
4375 { return m_main_win->GetItemBackgroundColour(item); }
4377 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
4378 { return m_main_win->GetItemFont(item); }
4381 void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column,
4382 const wxString& text)
4383 { m_main_win->SetItemText (item, column, text); }
4385 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item,
4388 wxTreeItemIcon which)
4389 { m_main_win->SetItemImage(item, column, image, which); }
4391 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,
4392 wxTreeItemData* data)
4393 { m_main_win->SetItemData(item, data); }
4395 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
4396 { m_main_win->SetItemHasChildren(item, has); }
4398 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
4399 { m_main_win->SetItemBold(item, bold); }
4401 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,
4402 const wxColour& colour)
4403 { m_main_win->SetItemTextColour(item, colour); }
4405 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
4406 const wxColour& colour)
4407 { m_main_win->SetItemBackgroundColour(item, colour); }
4409 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,
4411 { m_main_win->SetItemFont(item, font); }
4413 bool wxTreeListCtrl::SetFont(const wxFont& font)
4416 m_header_win->SetFont(font);
4417 CalculateAndSetHeaderHeight();
4418 m_header_win->Refresh();
4421 return m_main_win->SetFont(font);
4427 void wxTreeListCtrl::SetWindowStyle(const long style)
4430 m_main_win->SetWindowStyle(style);
4431 m_windowStyle = style;
4432 // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4435 long wxTreeListCtrl::GetWindowStyle() const
4437 long style = m_windowStyle;
4439 style |= m_main_win->GetWindowStyle();
4443 bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow) const
4444 { return m_main_win->IsVisible(item, fullRow); }
4446 bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
4447 { return m_main_win->HasChildren(item); }
4449 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
4450 { return m_main_win->IsExpanded(item); }
4452 bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
4453 { return m_main_win->IsSelected(item); }
4455 bool wxTreeListCtrl::IsBold(const wxTreeItemId& item) const
4456 { return m_main_win->IsBold(item); }
4458 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
4459 { return m_main_win->GetChildrenCount(item, rec); }
4461 wxTreeItemId wxTreeListCtrl::GetRootItem() const
4462 { return m_main_win->GetRootItem(); }
4464 //wxTreeItemId wxTreeListCtrl::GetSelection() const
4465 //{ return m_main_win->GetSelection(); }
4466 wxTreeItemId wxTreeListCtrl::GetCurrent() const
4467 { return m_main_win->GetCurrent(); }
4469 // returns the number of currently selected items
4470 size_t wxTreeListCtrl::GetSelectionSize() const
4471 { return m_main_win->GetSelectionSize(); }
4473 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
4474 { return m_main_win->GetSelections(arr); }
4476 wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
4477 { return m_main_win->GetItemParent(item); }
4479 #if !wxCHECK_VERSION(2, 5, 0)
4480 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4483 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4484 wxTreeItemIdValue& cookie) const
4486 { return m_main_win->GetFirstChild(item, cookie); }
4488 #if !wxCHECK_VERSION(2, 5, 0)
4489 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4492 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4493 wxTreeItemIdValue& cookie) const
4495 { return m_main_win->GetNextChild(item, cookie); }
4497 #if !wxCHECK_VERSION(2, 5, 0)
4498 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4501 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4502 wxTreeItemIdValue& cookie) const
4504 { return m_main_win->GetPrevChild(item, cookie); }
4506 #if !wxCHECK_VERSION(2, 5, 0)
4507 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4510 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4511 wxTreeItemIdValue& cookie) const
4513 { return m_main_win->GetLastChild(item, cookie); }
4516 wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
4517 { return m_main_win->GetNextSibling(item); }
4519 wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
4520 { return m_main_win->GetPrevSibling(item); }
4522 wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
4523 { return m_main_win->GetNext(item, true); }
4525 wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
4526 { return m_main_win->GetPrev(item, true); }
4528 wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
4529 { return m_main_win->GetFirstExpandedItem(); }
4531 wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
4532 { return m_main_win->GetNextExpanded(item); }
4534 wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
4535 { return m_main_win->GetPrevExpanded(item); }
4537 wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
4538 { return m_main_win->GetFirstVisibleItem(fullRow); }
4540 wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow) const
4541 { return m_main_win->GetNextVisible(item, fullRow); }
4543 wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow) const
4544 { return m_main_win->GetPrevVisible(item, fullRow); }
4546 wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
4547 int selectedImage, wxTreeItemData* data)
4548 { return m_main_win->AddRoot (text, image, selectedImage, data); }
4550 wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
4551 const wxString& text, int image,
4553 wxTreeItemData* data)
4554 { return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
4556 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4557 const wxTreeItemId& previous,
4558 const wxString& text, int image,
4560 wxTreeItemData* data)
4562 return m_main_win->InsertItem(parent, previous, text, image,
4563 selectedImage, data);
4566 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4568 const wxString& text, int image,
4570 wxTreeItemData* data)
4572 return m_main_win->InsertItem(parent, index, text, image,
4573 selectedImage, data);
4576 wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
4577 const wxString& text, int image,
4579 wxTreeItemData* data)
4580 { return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
4582 void wxTreeListCtrl::Delete(const wxTreeItemId& item)
4583 { m_main_win->Delete(item); }
4585 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
4586 { m_main_win->DeleteChildren(item); }
4588 void wxTreeListCtrl::DeleteRoot()
4589 { m_main_win->DeleteRoot(); }
4591 void wxTreeListCtrl::Expand(const wxTreeItemId& item)
4592 { m_main_win->Expand(item); }
4594 void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
4595 { m_main_win->ExpandAll(item); }
4597 void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
4598 { m_main_win->Collapse(item); }
4600 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
4601 { m_main_win->CollapseAndReset(item); }
4603 void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
4604 { m_main_win->Toggle(item); }
4606 //void wxTreeListCtrl::Unselect()
4607 //{ m_main_win->Unselect(); }
4609 // LG 19/09/08 : Added
4610 //void wxTreeListCtrl::Unselect(wxTreeItemId& item)
4611 //{ m_main_win->Unselect((wxTreeListItem*)item.m_pItem); }
4613 void wxTreeListCtrl::UnselectAll()
4614 { m_main_win->UnselectAll(); }
4616 void wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
4617 bool unselect_others)
4618 { m_main_win->SelectItem (item, last, unselect_others); }
4620 void wxTreeListCtrl::SelectAll()
4621 { m_main_win->SelectAll(); }
4623 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
4624 { m_main_win->EnsureVisible(item); }
4626 void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
4627 { m_main_win->ScrollTo(item); }
4629 wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
4631 wxPoint p = m_main_win->ScreenToClient (ClientToScreen (pos));
4632 return m_main_win->HitTest (p, flags, column);
4635 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
4636 bool textOnly) const
4637 { return m_main_win->GetBoundingRect(item, rect, textOnly); }
4639 void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
4640 { m_main_win->EditLabel (item, column); }
4642 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1,
4643 const wxTreeItemId& item2)
4645 // do the comparison here, and not delegate to m_main_win, in order
4646 // to let the user override it
4647 //return m_main_win->OnCompareItems(item1, item2);
4648 return wxStrcmp(GetItemText(item1), GetItemText(item2));
4651 void wxTreeListCtrl::SortChildren(const wxTreeItemId& item)
4652 { m_main_win->SortChildren(item); }
4654 wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, const wxString& str, int mode)
4655 { return m_main_win->FindItem (item, str, mode); }
4657 void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
4658 { m_main_win->SetDragItem (item); }
4660 bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
4662 if (!m_main_win) return false;
4663 return m_main_win->SetBackgroundColour(colour);
4666 bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
4668 if (!m_main_win) return false;
4669 return m_main_win->SetForegroundColour(colour);
4672 int wxTreeListCtrl::GetColumnCount() const
4673 { return m_main_win->GetColumnCount(); }
4675 void wxTreeListCtrl::SetColumnWidth(int column, int width)
4677 m_header_win->SetColumnWidth (column, width);
4678 m_header_win->Refresh();
4681 int wxTreeListCtrl::GetColumnWidth(int column) const
4682 { return m_header_win->GetColumnWidth(column); }
4684 void wxTreeListCtrl::SetMainColumn(int column)
4685 { m_main_win->SetMainColumn(column); }
4687 int wxTreeListCtrl::GetMainColumn() const
4688 { return m_main_win->GetMainColumn(); }
4690 void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
4692 m_header_win->SetColumnText (column, text);
4693 m_header_win->Refresh();
4696 wxString wxTreeListCtrl::GetColumnText(int column) const
4697 { return m_header_win->GetColumnText(column); }
4699 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
4701 m_header_win->AddColumn (colInfo);
4705 void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
4707 m_header_win->InsertColumn (before, colInfo);
4708 m_header_win->Refresh();
4711 void wxTreeListCtrl::RemoveColumn(int column)
4713 m_header_win->RemoveColumn (column);
4714 m_header_win->Refresh();
4717 void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
4719 m_header_win->SetColumn (column, colInfo);
4720 m_header_win->Refresh();
4723 const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
4724 { return m_header_win->GetColumn(column); }
4726 wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column)
4727 { return m_header_win->GetColumn(column); }
4729 void wxTreeListCtrl::SetColumnImage(int column, int image)
4731 m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
4732 m_header_win->Refresh();
4735 int wxTreeListCtrl::GetColumnImage(int column) const
4737 return m_header_win->GetColumn(column).GetImage();
4740 void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
4742 m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
4745 void wxTreeListCtrl::SetColumnShown(int column, bool shown)
4747 wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
4748 m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
4749 m_header_win->Refresh();
4752 bool wxTreeListCtrl::IsColumnEditable(int column) const
4754 return m_header_win->GetColumn(column).IsEditable();
4757 bool wxTreeListCtrl::IsColumnShown(int column) const
4759 return m_header_win->GetColumn(column).IsShown();
4762 void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
4764 m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
4765 m_header_win->Refresh();
4768 int wxTreeListCtrl::GetColumnAlignment(int column) const
4770 return m_header_win->GetColumn(column).GetAlignment();
4773 void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
4775 m_main_win->Refresh (erase, rect);
4776 m_header_win->Refresh (erase, rect);
4779 void wxTreeListCtrl::SetFocus()
4780 { m_main_win->SetFocus(); }
4782 wxSize wxTreeListCtrl::DoGetBestSize() const
4784 // something is better than nothing...
4785 return wxSize (200,200); // but it should be specified values! FIXME
4788 wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
4790 return wxEmptyString;