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.3 2008/10/01 14:23:59 guigues 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__ )
1136 wxPen pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
1139 dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner)
1140 dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner)
1142 dc->SetPen( *wxWHITE_PEN );
1143 dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer)
1144 dc->DrawRectangle( x, y, 1, h ); // left (outer)
1145 dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1146 dc->DrawLine( x+w-1, y, x+w-1, y+1 );
1149 // shift the DC origin to match the position of the main window horz
1150 // scrollbar: this allows us to always use logical coords
1151 void wxTreeListHeaderWindow::AdjustDC(wxDC& dc)
1154 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1156 m_owner->GetViewStart( &x, NULL );
1158 // account for the horz scrollbar offset
1159 dc.SetDeviceOrigin( -x * xpix, 0 );
1162 void wxTreeListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1165 wxClientDC dc( this );
1167 wxPaintDC dc( this );
1172 dc.SetFont( GetFont() );
1174 // width and height of the entire header window
1176 GetClientSize( &w, &h );
1177 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1178 dc.SetBackgroundMode(wxTRANSPARENT);
1180 // do *not* use the listctrl colour for headers - one day we will have a
1181 // function to set it separately
1182 //dc.SetTextForeground( *wxBLACK );
1183 #if !wxCHECK_VERSION(2, 5, 0)
1184 dc.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT ));
1186 dc.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ));
1189 int x = HEADER_OFFSET_X;
1191 int numColumns = GetColumnCount();
1192 for ( int i = 0; i < numColumns && x < w; i++ )
1194 if (!IsColumnShown (i)) continue; // do next colume if not shown
1196 wxTreeListColumnInfo& column = GetColumn(i);
1197 int wCol = column.GetWidth();
1199 // the width of the rect to draw: make it smaller to fit entirely
1200 // inside the column rect
1203 dc.SetPen( *wxWHITE_PEN );
1204 DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
1206 // if we have an image, draw it on the right of the label
1207 int image = column.GetImage(); //item.m_image;
1208 int ix = -2, iy = 0;
1209 wxImageList* imageList = m_owner->GetImageList();
1210 if ((image != -1) && imageList) {
1211 imageList->GetSize (image, ix, iy);
1214 // extra margins around the text label
1217 int image_offset = cw - ix - 1;
1219 switch(column.GetAlignment()) {
1221 text_x += EXTRA_WIDTH;
1225 dc.GetTextExtent (column.GetText(), &text_width, NULL);
1226 text_x += cw - text_width - EXTRA_WIDTH - MARGIN;
1229 case wxALIGN_CENTER:
1230 dc.GetTextExtent(column.GetText(), &text_width, NULL);
1231 text_x += (cw - text_width)/2 + ix + 2;
1232 image_offset = (cw - text_width - ix - 2)/2 - MARGIN;
1237 if ((image != -1) && imageList) {
1238 imageList->Draw (image, dc, x + image_offset/*cw - ix - 1*/,
1239 HEADER_OFFSET_Y + (h - 4 - iy)/2,
1240 wxIMAGELIST_DRAW_TRANSPARENT);
1243 // draw the text clipping it so that it doesn't overwrite the column boundary
1244 wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
1245 dc.DrawText (column.GetText(), text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT );
1251 int more_w = m_owner->GetSize().x - x - HEADER_OFFSET_X;
1253 DoDrawRect (&dc, x, HEADER_OFFSET_Y, more_w, h-2 );
1258 void wxTreeListHeaderWindow::DrawCurrent()
1260 int x1 = m_currentX;
1262 ClientToScreen (&x1, &y1);
1264 int x2 = m_currentX-1;
1266 ++x2; // but why ????
1269 m_owner->GetClientSize( NULL, &y2 );
1270 m_owner->ClientToScreen( &x2, &y2 );
1273 dc.SetLogicalFunction (wxINVERT);
1274 dc.SetPen (wxPen (*wxBLACK, 2, wxSOLID));
1275 dc.SetBrush (*wxTRANSPARENT_BRUSH);
1278 dc.DrawLine (x1, y1, x2, y2);
1279 dc.SetLogicalFunction (wxCOPY);
1280 dc.SetPen (wxNullPen);
1281 dc.SetBrush (wxNullBrush);
1284 void wxTreeListHeaderWindow::OnMouse (wxMouseEvent &event) {
1286 // we want to work with logical coords
1288 m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1289 int y = event.GetY();
1293 SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
1295 // we don't draw the line beyond our window, but we allow dragging it
1298 GetClientSize( &w, NULL );
1299 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1302 // erase the line if it was drawn
1303 if (m_currentX < w) DrawCurrent();
1305 if (event.ButtonUp()) {
1306 m_isDragging = false;
1307 if (HasCapture()) ReleaseMouse();
1309 SetColumnWidth (m_column, m_currentX - m_minX);
1311 SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
1313 m_currentX = wxMax (m_minX + 7, x);
1315 // draw in the new location
1316 if (m_currentX < w) DrawCurrent();
1319 }else{ // not dragging
1322 bool hit_border = false;
1324 // end of the current column
1327 // find the column where this event occured
1328 int countCol = GetColumnCount();
1329 for (int column = 0; column < countCol; column++) {
1330 if (!IsColumnShown (column)) continue; // do next if not shown
1332 xpos += GetColumnWidth (column);
1334 if ((abs (x-xpos) < 3) && (y < 22)) {
1335 // near the column border
1341 // inside the column
1348 if (event.LeftDown() || event.RightUp()) {
1349 if (hit_border && event.LeftDown()) {
1350 m_isDragging = true;
1354 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition());
1355 }else{ // click on a column
1356 wxEventType evt = event.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK:
1357 wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
1358 SendListEvent (evt, event.GetPosition());
1360 }else if (event.LeftDClick() && hit_border) {
1361 SetColumnWidth (m_column, m_owner->GetBestColumnWidth (m_column));
1364 }else if (event.Moving()) {
1367 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
1368 m_currentCursor = m_resizeCursor;
1370 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
1371 m_currentCursor = wxSTANDARD_CURSOR;
1373 if (setCursor) SetCursor (*m_currentCursor);
1379 void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent &WXUNUSED(event)) {
1380 m_owner->SetFocus();
1383 void wxTreeListHeaderWindow::SendListEvent (wxEventType type, wxPoint pos) {
1384 wxWindow *parent = GetParent();
1385 wxListEvent le (type, parent->GetId());
1386 le.SetEventObject (parent);
1387 le.m_pointDrag = pos;
1389 // the position should be relative to the parent window, not
1390 // this one for compatibility with MSW and common sense: the
1391 // user code doesn't know anything at all about this header
1392 // window, so why should it get positions relative to it?
1393 le.m_pointDrag.y -= GetSize().y;
1394 le.m_col = m_column;
1395 parent->GetEventHandler()->ProcessEvent (le);
1398 void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo& colInfo) {
1399 m_columns.Add (colInfo);
1400 m_total_col_width += colInfo.GetWidth();
1401 m_owner->AdjustMyScrollbars();
1402 m_owner->m_dirty = true;
1405 void wxTreeListHeaderWindow::SetColumnWidth (int column, int width) {
1406 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1407 m_total_col_width -= m_columns[column].GetWidth();
1408 m_columns[column].SetWidth(width);
1409 m_total_col_width += width;
1410 m_owner->AdjustMyScrollbars();
1411 m_owner->m_dirty = true;
1414 void wxTreeListHeaderWindow::InsertColumn (int before, const wxTreeListColumnInfo& colInfo) {
1415 wxCHECK_RET ((before >= 0) && (before < GetColumnCount()), _T("Invalid column"));
1416 m_columns.Insert (colInfo, before);
1417 m_total_col_width += colInfo.GetWidth();
1418 m_owner->AdjustMyScrollbars();
1419 m_owner->m_dirty = true;
1422 void wxTreeListHeaderWindow::RemoveColumn (int column) {
1423 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1424 m_total_col_width -= m_columns[column].GetWidth();
1425 m_columns.RemoveAt (column);
1426 m_owner->AdjustMyScrollbars();
1427 m_owner->m_dirty = true;
1430 void wxTreeListHeaderWindow::SetColumn (int column, const wxTreeListColumnInfo& info) {
1431 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1432 int w = m_columns[column].GetWidth();
1433 m_columns[column] = info;
1434 if (w != info.GetWidth()) {
1435 m_total_col_width += info.GetWidth() - w;
1436 m_owner->AdjustMyScrollbars();
1438 m_owner->m_dirty = true;
1441 // ---------------------------------------------------------------------------
1443 // ---------------------------------------------------------------------------
1445 wxTreeListItem::wxTreeListItem (wxTreeListMainWindow *owner,
1446 wxTreeListItem *parent,
1447 const wxArrayString& text,
1448 int image, int selImage,
1449 wxTreeItemData *data)
1452 m_images[wxTreeItemIcon_Normal] = image;
1453 m_images[wxTreeItemIcon_Selected] = selImage;
1454 m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
1455 m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
1462 m_isCollapsed = true;
1463 m_hasHilight = false;
1470 m_attr = (wxTreeItemAttr *)NULL;
1473 // We don't know the height here yet.
1478 wxTreeListItem::~wxTreeListItem() {
1480 if (m_ownsAttr) delete m_attr;
1482 wxASSERT_MSG( m_children.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1485 void wxTreeListItem::DeleteChildren (wxTreeListMainWindow *tree) {
1486 size_t count = m_children.Count();
1487 for (size_t n = 0; n < count; n++) {
1488 wxTreeListItem *child = m_children[n];
1490 tree->SendDeleteEvent (child);
1492 tree->RemoveFromSelection(child);
1494 if (child->IsSelected())
1496 tree->Unselect(child);
1499 // if (tree->m_selectItem == child) tree->m_selectItem = (wxTreeListItem*)NULL;
1501 child->DeleteChildren (tree);
1507 void wxTreeListItem::SetText (const wxString &text) {
1508 if (m_text.GetCount() > 0) {
1515 size_t wxTreeListItem::GetChildrenCount (bool recursively) const {
1516 size_t count = m_children.Count();
1517 if (!recursively) return count;
1519 size_t total = count;
1520 for (size_t n = 0; n < count; ++n) {
1521 total += m_children[n]->GetChildrenCount();
1526 void wxTreeListItem::GetSize (int &x, int &y, const wxTreeListMainWindow *theButton) {
1527 int bottomY = m_y + theButton->GetLineHeight (this);
1528 if (y < bottomY) y = bottomY;
1529 int width = m_x + m_width;
1530 if ( x < width ) x = width;
1533 size_t count = m_children.Count();
1534 for (size_t n = 0; n < count; ++n ) {
1535 m_children[n]->GetSize (x, y, theButton);
1540 wxTreeListItem *wxTreeListItem::HitTest (const wxPoint& point,
1541 const wxTreeListMainWindow *theCtrl,
1542 int &flags, int& column, int level) {
1544 // for a hidden root node, don't evaluate it, but do evaluate children
1545 if (!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) {
1547 // reset any previous hit infos
1550 wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow();
1552 // check for right of all columns (outside)
1553 if (point.x > header_win->GetWidth()) return (wxTreeListItem*) NULL;
1555 // evaluate if y-pos is okay
1556 int h = theCtrl->GetLineHeight (this);
1557 if ((point.y >= m_y) && (point.y <= m_y + h)) {
1559 int maincol = theCtrl->GetMainColumn();
1561 // check for above/below middle
1562 int y_mid = m_y + h/2;
1563 if (point.y < y_mid) {
1564 flags |= wxTREE_HITTEST_ONITEMUPPERPART;
1566 flags |= wxTREE_HITTEST_ONITEMLOWERPART;
1569 // check for button hit
1570 if (HasPlus() && theCtrl->HasButtons()) {
1571 int bntX = m_x - theCtrl->m_btnWidth2;
1572 int bntY = y_mid - theCtrl->m_btnHeight2;
1573 if ((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) &&
1574 (point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) {
1575 flags |= wxTREE_HITTEST_ONITEMBUTTON;
1581 // check for image hit
1582 if (theCtrl->m_imgWidth > 0) {
1583 int imgX = m_text_x - theCtrl->m_imgWidth - MARGIN;
1584 int imgY = y_mid - theCtrl->m_imgHeight2;
1585 if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) &&
1586 (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) {
1587 flags |= wxTREE_HITTEST_ONITEMICON;
1593 // check for label hit
1594 if ((point.x >= m_text_x) && (point.x <= (m_text_x + m_width))) {
1595 flags |= wxTREE_HITTEST_ONITEMLABEL;
1600 // check for indent hit after button and image hit
1601 if (point.x < m_x) {
1602 flags |= wxTREE_HITTEST_ONITEMINDENT;
1603 column = -1; // considered not belonging to main column
1607 // check for right of label
1609 for (int i = 0; i <= maincol; ++i) end += header_win->GetColumnWidth (i);
1610 if ((point.x > (m_text_x + m_width)) && (point.x <= end)) {
1611 flags |= wxTREE_HITTEST_ONITEMRIGHT;
1612 column = -1; // considered not belonging to main column
1616 // else check for each column except main
1618 for (int j = 0; j < theCtrl->GetColumnCount(); ++j) {
1619 if (!header_win->IsColumnShown(j)) continue;
1620 int w = header_win->GetColumnWidth (j);
1621 if ((j != maincol) && (point.x >= x && point.x < x+w)) {
1622 flags |= wxTREE_HITTEST_ONITEMCOLUMN;
1629 // no special flag or column found
1634 // if children not expanded, return no item
1635 if (!IsExpanded()) return (wxTreeListItem*) NULL;
1638 // in any case evaluate children
1639 wxTreeListItem *child;
1640 size_t count = m_children.Count();
1641 for (size_t n = 0; n < count; n++) {
1642 child = m_children[n]->HitTest (point, theCtrl, flags, column, level+1);
1643 if (child) return child;
1647 return (wxTreeListItem*) NULL;
1650 int wxTreeListItem::GetCurrentImage() const {
1651 int image = NO_IMAGE;
1654 image = GetImage (wxTreeItemIcon_SelectedExpanded);
1656 image = GetImage (wxTreeItemIcon_Expanded);
1658 }else{ // not expanded
1660 image = GetImage (wxTreeItemIcon_Selected);
1662 image = GetImage (wxTreeItemIcon_Normal);
1666 // maybe it doesn't have the specific image, try the default one instead
1667 if (image == NO_IMAGE) image = GetImage();
1672 // ---------------------------------------------------------------------------
1673 // wxTreeListMainWindow implementation
1674 // ---------------------------------------------------------------------------
1676 IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow)
1678 BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow)
1679 EVT_PAINT (wxTreeListMainWindow::OnPaint)
1680 EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse)
1681 EVT_CHAR (wxTreeListMainWindow::OnChar)
1682 EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus)
1683 EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus)
1684 EVT_IDLE (wxTreeListMainWindow::OnIdle)
1685 EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll)
1689 // ---------------------------------------------------------------------------
1690 // construction/destruction
1691 // ---------------------------------------------------------------------------
1693 void wxTreeListMainWindow::Init() {
1695 m_rootItem = (wxTreeListItem*)NULL;
1696 m_curItem = (wxTreeListItem*)NULL;
1697 m_shiftItem = (wxTreeListItem*)NULL;
1698 m_editItem = (wxTreeListItem*)NULL;
1700 // m_selectItem = (wxTreeListItem*)NULL;
1702 m_curColumn = -1; // no current column
1707 m_lineHeight = LINEHEIGHT;
1708 m_indent = MININDENT; // min. indent
1711 #if !wxCHECK_VERSION(2, 5, 0)
1712 m_hilightBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1713 m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1715 m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1716 m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1719 m_imageListNormal = (wxImageList *) NULL;
1720 m_imageListButtons = (wxImageList *) NULL;
1721 m_imageListState = (wxImageList *) NULL;
1722 m_ownsImageListNormal = m_ownsImageListButtons =
1723 m_ownsImageListState = false;
1725 m_imgWidth = 0, m_imgWidth2 = 0;
1726 m_imgHeight = 0, m_imgHeight2 = 0;
1727 m_btnWidth = 0, m_btnWidth2 = 0;
1728 m_btnHeight = 0, m_btnHeight2 = 0;
1731 m_isDragging = false;
1732 m_dragTimer = new wxTimer (this, -1);
1733 m_dragItem = (wxTreeListItem*)NULL;
1735 m_renameTimer = new wxTreeListRenameTimer (this);
1736 m_lastOnSame = false;
1737 m_left_down_selection = false;
1739 m_findTimer = new wxTimer (this, -1);
1741 #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
1742 m_normalFont.MacCreateThemeFont (kThemeViewsFont);
1744 m_normalFont = wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT);
1746 m_boldFont = wxFont( m_normalFont.GetPointSize(),
1747 m_normalFont.GetFamily(),
1748 m_normalFont.GetStyle(),
1750 m_normalFont.GetUnderlined(),
1751 m_normalFont.GetFaceName(),
1752 m_normalFont.GetEncoding());
1755 bool wxTreeListMainWindow::Create (wxTreeListCtrl *parent,
1760 const wxValidator &validator,
1761 const wxString& name) {
1764 if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS;
1765 if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS;
1766 style &= ~wxTR_LINES_AT_ROOT;
1767 style |= wxTR_NO_LINES;
1770 wxGetOsVersion( &major, &minor );
1771 if (major < 10) style |= wxTR_ROW_LINES;
1774 wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
1776 #if wxUSE_VALIDATORS
1777 SetValidator(validator);
1780 #if !wxCHECK_VERSION(2, 5, 0)
1781 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX));
1783 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX));
1791 bdc.SelectObject(bmp);
1792 bdc.SetPen(*wxGREY_PEN);
1793 bdc.DrawRectangle(-1, -1, 10, 10);
1794 for (i = 0; i < 8; i++) {
1795 for (j = 0; j < 8; j++) {
1796 if (!((i + j) & 1)) {
1797 bdc.DrawPoint(i, j);
1802 m_dottedPen = wxPen(bmp, 1);
1805 //? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86
1806 m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
1815 wxTreeListMainWindow::~wxTreeListMainWindow() {
1816 delete m_hilightBrush;
1817 delete m_hilightUnfocusedBrush;
1820 delete m_renameTimer;
1822 if (m_ownsImageListNormal) delete m_imageListNormal;
1823 if (m_ownsImageListState) delete m_imageListState;
1824 if (m_ownsImageListButtons) delete m_imageListButtons;
1830 //-----------------------------------------------------------------------------
1832 //-----------------------------------------------------------------------------
1834 size_t wxTreeListMainWindow::GetCount() const {
1835 return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount();
1838 void wxTreeListMainWindow::SetIndent (unsigned int indent) {
1839 m_indent = wxMax (MININDENT, indent);
1843 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) {
1844 m_linespacing = spacing;
1846 CalculateLineHeight();
1849 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item,
1851 wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item"));
1852 return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively);
1855 void wxTreeListMainWindow::SetWindowStyle (const long styles) {
1856 // right now, just sets the styles. Eventually, we may
1857 // want to update the inherited styles, but right now
1858 // none of the parents has updatable styles
1859 m_windowStyle = styles;
1863 //-----------------------------------------------------------------------------
1864 // functions to work with tree items
1865 //-----------------------------------------------------------------------------
1867 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column,
1868 wxTreeItemIcon which) const {
1869 wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item"));
1870 return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which);
1873 wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const {
1874 wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
1875 return ((wxTreeListItem*) item.m_pItem)->GetData();
1878 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const {
1879 wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
1880 return ((wxTreeListItem *)item.m_pItem)->IsBold();
1883 wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const {
1884 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1885 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1886 return pItem->Attr().GetTextColour();
1889 wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const {
1890 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1891 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1892 return pItem->Attr().GetBackgroundColour();
1895 wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const {
1896 wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
1897 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1898 return pItem->Attr().GetFont();
1901 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column,
1902 int image, wxTreeItemIcon which) {
1903 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1904 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1905 pItem->SetImage (column, image, which);
1906 wxClientDC dc (this);
1907 CalculateSize (pItem, dc);
1908 RefreshLine (pItem);
1911 void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item,
1912 wxTreeItemData *data) {
1913 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1914 ((wxTreeListItem*) item.m_pItem)->SetData(data);
1917 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item,
1919 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1920 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1921 pItem->SetHasPlus (has);
1922 RefreshLine (pItem);
1925 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, bool bold) {
1926 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1927 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1928 if (pItem->IsBold() != bold) { // avoid redrawing if no real change
1929 pItem->SetBold (bold);
1930 RefreshLine (pItem);
1934 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item,
1935 const wxColour& colour) {
1936 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1937 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1938 pItem->Attr().SetTextColour (colour);
1939 RefreshLine (pItem);
1942 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item,
1943 const wxColour& colour) {
1944 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1945 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1946 pItem->Attr().SetBackgroundColour (colour);
1947 RefreshLine (pItem);
1950 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item,
1951 const wxFont& font) {
1952 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1953 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1954 pItem->Attr().SetFont (font);
1955 RefreshLine (pItem);
1958 bool wxTreeListMainWindow::SetFont (const wxFont &font) {
1959 wxScrolledWindow::SetFont (font);
1960 m_normalFont = font;
1961 m_boldFont = wxFont (m_normalFont.GetPointSize(),
1962 m_normalFont.GetFamily(),
1963 m_normalFont.GetStyle(),
1965 m_normalFont.GetUnderlined(),
1966 m_normalFont.GetFaceName());
1967 CalculateLineHeight();
1972 // ----------------------------------------------------------------------------
1973 // item status inquiries
1974 // ----------------------------------------------------------------------------
1976 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow) const {
1977 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1979 // An item is only visible if it's not a descendant of a collapsed item
1980 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1981 wxTreeListItem* parent = pItem->GetItemParent();
1983 if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break;
1984 if (!parent->IsExpanded()) return false;
1985 parent = parent->GetItemParent();
1988 wxSize clientSize = GetClientSize();
1990 if ((!GetBoundingRect (item, rect)) ||
1991 ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
1992 (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y) ||
1993 (!fullRow && (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x))) return false;
1998 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const {
1999 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2001 // consider that the item does have children if it has the "+" button: it
2002 // might not have them (if it had never been expanded yet) but then it
2003 // could have them as well and it's better to err on this side rather than
2004 // disabling some operations which are restricted to the items with
2005 // children for an item which does have them
2006 return ((wxTreeListItem*) item.m_pItem)->HasPlus();
2009 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const {
2010 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2011 return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
2014 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const {
2015 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2016 return ((wxTreeListItem*) item.m_pItem)->IsSelected();
2019 bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item) const {
2020 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2021 return ((wxTreeListItem*) item.m_pItem)->IsBold();
2024 // ----------------------------------------------------------------------------
2026 // ----------------------------------------------------------------------------
2028 wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const {
2029 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2030 return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
2033 #if !wxCHECK_VERSION(2, 5, 0)
2034 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2035 long& cookie) const {
2037 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2038 wxTreeItemIdValue& cookie) const {
2040 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2041 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2043 return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId();
2046 #if !wxCHECK_VERSION(2, 5, 0)
2047 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2048 long& cookie) const {
2050 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2051 wxTreeItemIdValue& cookie) const {
2053 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2054 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2055 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2056 long *pIndex = ((long*)&cookie);
2057 return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId();
2060 #if !wxCHECK_VERSION(2, 5, 0)
2061 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2062 long& cookie) const {
2064 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2065 wxTreeItemIdValue& cookie) const {
2067 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2068 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2069 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2070 long *pIndex = (long*)&cookie;
2071 return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId();
2074 #if !wxCHECK_VERSION(2, 5, 0)
2075 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2076 long& cookie) const {
2078 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2079 wxTreeItemIdValue& cookie) const {
2081 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2082 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2083 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2084 long *pIndex = ((long*)&cookie);
2085 (*pIndex) = children.Count();
2086 return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId();
2089 wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const {
2090 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2093 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2094 wxTreeListItem *parent = i->GetItemParent();
2095 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2098 wxArrayTreeListItems& siblings = parent->GetChildren();
2099 size_t index = siblings.Index (i);
2100 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2101 return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId();
2104 wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const {
2105 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2108 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2109 wxTreeListItem *parent = i->GetItemParent();
2110 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2113 wxArrayTreeListItems& siblings = parent->GetChildren();
2114 size_t index = siblings.Index(i);
2115 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2116 return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId();
2119 // Only for internal use right now, but should probably be public
2120 wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const {
2121 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2123 // if there are any children, return first child
2124 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2125 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2126 if (children.GetCount() > 0) return children.Item (0);
2129 // get sibling of this item or of the ancestors instead
2131 wxTreeItemId parent = item;
2133 next = GetNextSibling (parent);
2134 parent = GetItemParent (parent);
2135 } while (!next.IsOk() && parent.IsOk());
2139 // Only for internal use right now, but should probably be public
2140 wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const {
2141 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2143 // if there are any children, return last child
2144 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2145 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2146 if (children.GetCount() > 0) return children.Item (children.GetCount()-1);
2149 // get sibling of this item or of the ancestors instead
2151 wxTreeItemId parent = item;
2153 next = GetPrevSibling (parent);
2154 parent = GetItemParent (parent);
2155 } while (!next.IsOk() && parent.IsOk());
2159 wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
2160 return GetNextExpanded (GetRootItem());
2163 wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const {
2164 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2165 return GetNext (item, false);
2168 wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const {
2169 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2170 return GetPrev (item, false);
2173 wxTreeItemId wxTreeListMainWindow::GetFirstVisibleItem (bool fullRow) const {
2174 return GetNextVisible (GetRootItem(), fullRow);
2177 wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow) const {
2178 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2179 wxTreeItemId id = GetNext (item, false);
2181 if (IsVisible (id, fullRow)) return id;
2182 id = GetNext (id, false);
2184 return wxTreeItemId();
2187 wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow) const {
2188 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2189 wxTreeItemId id = GetPrev (item, true);
2191 if (IsVisible (id, fullRow)) return id;
2192 id = GetPrev(id, true);
2194 return wxTreeItemId();
2197 // ----------------------------------------------------------------------------
2199 // ----------------------------------------------------------------------------
2201 wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId,
2203 const wxString& text,
2204 int image, int selImage,
2205 wxTreeItemData *data) {
2206 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2207 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2208 m_dirty = true; // do this first so stuff below doesn't cause flicker
2211 arr.Alloc (GetColumnCount());
2212 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2213 arr[m_main_column] = text;
2214 wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data);
2216 #if !wxCHECK_VERSION(2, 5, 0)
2217 data->SetId ((long)item);
2222 parent->Insert (item, previous);
2227 wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text,
2228 int image, int selImage,
2229 wxTreeItemData *data) {
2230 wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
2231 wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2232 m_dirty = true; // do this first so stuff below doesn't cause flicker
2235 arr.Alloc (GetColumnCount());
2236 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2237 arr[m_main_column] = text;
2238 m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data);
2240 #if !wxCHECK_VERSION(2, 5, 0)
2241 data->SetId((long)m_rootItem);
2243 data->SetId(m_rootItem);
2246 if (HasFlag(wxTR_HIDE_ROOT)) {
2247 // if we will hide the root, make sure children are visible
2248 m_rootItem->SetHasPlus();
2249 m_rootItem->Expand();
2250 #if !wxCHECK_VERSION(2, 5, 0)
2253 wxTreeItemIdValue cookie = 0;
2255 m_curItem = (wxTreeListItem*)GetFirstChild (m_rootItem, cookie).m_pItem;
2260 wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent,
2261 const wxString& text,
2262 int image, int selImage,
2263 wxTreeItemData *data) {
2264 return DoInsertItem (parent, 0u, text, image, selImage, data);
2267 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2268 const wxTreeItemId& idPrevious,
2269 const wxString& text,
2270 int image, int selImage,
2271 wxTreeItemData *data) {
2272 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2273 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2275 int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
2276 wxASSERT_MSG( index != wxNOT_FOUND,
2277 _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
2279 return DoInsertItem (parentId, ++index, text, image, selImage, data);
2282 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2284 const wxString& text,
2285 int image, int selImage,
2286 wxTreeItemData *data) {
2287 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2288 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2290 return DoInsertItem (parentId, before, text, image, selImage, data);
2293 wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId,
2294 const wxString& text,
2295 int image, int selImage,
2296 wxTreeItemData *data) {
2297 wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
2298 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2300 return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data);
2303 void wxTreeListMainWindow::SendDeleteEvent (wxTreeListItem *item) {
2304 // send event to user code
2305 wxTreeEvent event (wxEVT_COMMAND_TREE_DELETE_ITEM, m_owner->GetId());
2306 #if !wxCHECK_VERSION(2, 5, 0)
2307 event.SetItem ((long)item);
2309 event.SetItem (item);
2311 event.SetEventObject (m_owner);
2312 m_owner->ProcessEvent (event);
2315 void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
2316 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2317 wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
2318 m_dirty = true; // do this first so stuff below doesn't cause flicker
2320 // don't stay with invalid m_shiftItem or we will crash in the next call to OnChar()
2321 bool changeKeyCurrent = false;
2322 wxTreeListItem *itemKey = m_shiftItem;
2324 if (itemKey == item) { // m_shiftItem is a descendant of the item being deleted
2325 changeKeyCurrent = true;
2328 itemKey = itemKey->GetItemParent();
2331 wxTreeListItem *parent = item->GetItemParent();
2333 parent->GetChildren().Remove (item); // remove by value
2335 if (changeKeyCurrent) m_shiftItem = parent;
2337 SendDeleteEvent (item);
2339 RemoveFromSelection(item);
2340 // if (item->IsSelected()) Unselect(item);
2341 //if (m_selectItem == item) m_selectItem = (wxTreeListItem*)NULL;
2342 item->DeleteChildren (this);
2346 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
2347 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2348 m_dirty = true; // do this first so stuff below doesn't cause flicker
2350 item->DeleteChildren (this);
2353 void wxTreeListMainWindow::DeleteRoot() {
2356 SendDeleteEvent (m_rootItem);
2357 m_curItem = (wxTreeListItem*)NULL;
2359 // m_selectItem= (wxTreeListItem*)NULL;
2361 m_rootItem->DeleteChildren (this);
2367 void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
2368 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2369 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
2371 if (!item->HasPlus() || item->IsExpanded()) return;
2373 // send event to user code
2374 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_EXPANDING, m_owner->GetId());
2375 #if !wxCHECK_VERSION(2, 5, 0)
2376 event.SetItem ((long)item);
2378 event.SetItem (item);
2380 event.SetEventObject (m_owner);
2381 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // expand canceled
2386 // send event to user code
2387 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
2388 m_owner->ProcessEvent (event);
2391 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
2393 if (!IsExpanded (itemId)) return;
2394 #if !wxCHECK_VERSION(2, 5, 0)
2397 wxTreeItemIdValue cookie;
2399 wxTreeItemId child = GetFirstChild (itemId, cookie);
2400 while (child.IsOk()) {
2402 child = GetNextChild (itemId, cookie);
2406 void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
2407 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2408 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
2410 if (!item->HasPlus() || !item->IsExpanded()) return;
2412 // send event to user code
2413 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, m_owner->GetId() );
2414 #if !wxCHECK_VERSION(2, 5, 0)
2415 event.SetItem ((long)item);
2417 event.SetItem (item);
2419 event.SetEventObject (m_owner);
2420 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // collapse canceled
2425 // send event to user code
2426 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
2427 ProcessEvent (event);
2430 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
2432 DeleteChildren (item);
2435 void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
2436 if (IsExpanded (itemId)) {
2443 void wxTreeListMainWindow::Unselect() {
2445 m_selectItem->SetHilight (false);
2446 RefreshLine (m_selectItem);
2447 m_selectItem = (wxTreeListItem*)NULL;
2451 // LG 19/09/08 : Added
2453 void wxTreeListMainWindow::Unselect(wxTreeListItem* item)
2455 if (item->IsSelected()) {
2456 item->SetSelected (false);
2458 m_selected.Remove(item);
2459 // LG : TODO : Remove from array
2460 // if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
2465 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
2466 if (item->IsSelected()) {
2467 item->SetHilight (false);
2469 if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
2471 if (item->HasChildren()) {
2472 wxArrayTreeListItems& children = item->GetChildren();
2473 size_t count = children.Count();
2474 for (size_t n = 0; n < count; ++n) {
2475 UnselectAllChildren (children[n]);
2480 void wxTreeListMainWindow::UnselectAll() {
2482 size_t count = m_selected.Count();
2483 for (size_t n = 0; n < count; ++n)
2485 m_selected[n]->SetSelected (false);
2486 RefreshLine (m_selected[n]);
2490 //UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
2493 // Recursive function !
2494 // To stop we must have crt_item<last_item
2496 // Tag all next children, when no more children,
2497 // Move to parent (not to tag)
2498 // Keep going... if we found last_item, we stop.
2499 bool wxTreeListMainWindow::SelectNextChildren (wxTreeListItem *crt_item,
2500 wxTreeListItem *last_item) {
2501 wxTreeListItem *parent = crt_item->GetItemParent();
2503 if (!parent) {// This is root item
2504 return SelectAllChildrenUntilLast (crt_item, last_item);
2507 wxArrayTreeListItems& children = parent->GetChildren();
2508 int index = children.Index(crt_item);
2509 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2511 if ((parent->HasChildren() && parent->IsExpanded()) ||
2512 ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
2513 size_t count = children.Count();
2514 for (size_t n = (index+1); n < count; ++n) {
2515 if (SelectAllChildrenUntilLast (children[n], last_item)) return true;
2519 return SelectNextChildren (parent, last_item);
2522 bool wxTreeListMainWindow::SelectAllChildrenUntilLast (wxTreeListItem *crt_item,
2523 wxTreeListItem *last_item) {
2524 if (!crt_item->IsSelected())
2526 // LG : Send event to user to know is selection is accepted
2527 // send event to the user code
2528 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId() );
2529 #if !wxCHECK_VERSION(2, 5, 0)
2530 event.SetItem ((long)crt_item);
2532 event.SetItem (crt_item);
2534 event.SetEventObject (m_owner);
2535 if (m_owner->GetEventHandler()->ProcessEvent (event) && event.IsAllowed())
2537 AddToSelection(crt_item);
2541 if (crt_item==last_item) return true;
2543 if (crt_item->HasChildren() && crt_item->IsExpanded()) {
2544 wxArrayTreeListItems& children = crt_item->GetChildren();
2545 size_t count = children.Count();
2546 for (size_t n = 0; n < count; ++n) {
2547 if (SelectAllChildrenUntilLast (children[n], last_item)) return true;
2554 void wxTreeListMainWindow::RemoveFromSelection( wxTreeListItem *item )
2556 if (!item->IsSelected()) return;
2557 item->SetSelected(false);
2558 m_selected.Remove(item);
2562 void wxTreeListMainWindow::AddToSelection( wxTreeListItem *item )
2564 if (item->IsSelected()) return;
2565 item->SetSelected(true);
2566 m_selected.Add(item);
2570 void wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
2571 const wxTreeItemId& lastId,
2572 bool unselect_others) {
2573 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item") );
2575 bool is_single = !HasFlag(wxTR_MULTIPLE);
2576 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2579 // single selection requires unselect others
2580 if (is_single) unselect_others = true;
2582 // unselect all if unselect other items
2583 bool unselected = false; // see that UnselectAll is done only once
2584 if (unselect_others) {
2587 Unselect(); // to speed up thing
2595 // LG : Update current item
2596 wxTreeListItem *old_curItem = m_curItem;
2598 if (old_curItem) RefreshLine (old_curItem);
2600 // select item or item range
2601 if (lastId.IsOk() && (itemId != lastId))
2605 if (!unselected) UnselectAll();
2606 wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
2608 // LG : Update current item
2609 // wxTreeListItem *old_curItem = m_curItem;
2610 // m_curItem = last;
2611 // if (old_curItem) RefreshLine (old_curItem);
2613 // ensure that the position of the item it calculated in any case
2614 if (m_dirty) CalculatePositions();
2616 // select item range according Y-position
2617 if (last->GetY() < item->GetY()) {
2618 if (!SelectAllChildrenUntilLast (last, item)) {
2619 SelectNextChildren (last, item);
2622 if (!SelectAllChildrenUntilLast (item, last)) {
2623 SelectNextChildren (item, last);
2631 // send event to the user code
2632 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId() );
2633 #if !wxCHECK_VERSION(2, 5, 0)
2634 event.SetItem ((long)item);
2635 event.SetOldItem ((long)m_curItem);
2637 event.SetItem (item);
2638 event.SetOldItem (m_curItem);
2640 event.SetEventObject (m_owner);
2644 if (m_owner->GetEventHandler()->ProcessEvent (event) &&
2647 // select item according its old selection
2648 if (item->IsSelected())
2649 RemoveFromSelection(item);
2651 AddToSelection(item);
2655 // send event to user code
2656 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGED, m_owner->GetId() );
2657 m_owner->GetEventHandler()->ProcessEvent (event);
2660 void wxTreeListMainWindow::SelectAll() {
2661 wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
2663 #if !wxCHECK_VERSION(2, 5, 0)
2666 wxTreeItemIdValue cookie = 0;
2668 wxTreeItemId root = GetRootItem();
2669 wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
2670 wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
2671 if (!SelectAllChildrenUntilLast (first, last)) {
2672 SelectNextChildren (first, last);
2675 // send event to user code
2676 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGED, m_owner->GetId() );
2677 m_owner->GetEventHandler()->ProcessEvent (event);
2680 void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
2681 wxArrayTreeItemIds &array) const {
2682 if (item->IsSelected()) array.Add (wxTreeItemId(item));
2684 if (item->HasChildren()) {
2685 wxArrayTreeListItems& children = item->GetChildren();
2686 size_t count = children.GetCount();
2687 for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
2692 // returns the number of currently selected items
2693 size_t wxTreeListMainWindow::GetSelectionSize() const
2695 return m_selected.GetCount();
2698 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
2700 LG : NOT OK AS IS NOT IN TREE ORDER
2702 size_t count = m_selected.GetCount();
2703 for (size_t n = 0; n < count; ++n) array.Add(m_selected[n]);
2705 wxTreeItemId idRoot = GetRootItem();
2706 if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
2707 return array.Count();
2710 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
2711 if (!item.IsOk()) return; // do nothing if no item
2713 // first expand all parent branches
2714 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2715 wxTreeListItem *parent = gitem->GetItemParent();
2718 parent = parent->GetItemParent();
2722 RefreshLine (gitem);
2725 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
2726 if (!item.IsOk()) return; // do nothing if no item
2728 // ensure that the position of the item it calculated in any case
2729 if (m_dirty) CalculatePositions();
2731 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2733 // now scroll to the item
2734 int item_y = gitem->GetY();
2737 GetScrollPixelsPerUnit (&xUnit, &yUnit);
2740 GetViewStart (&start_x, &start_y);
2745 GetClientSize (&client_w, &client_h);
2749 m_rootItem->GetSize (x, y, this);
2750 x = m_owner->GetHeaderWindow()->GetWidth();
2751 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2752 int x_pos = GetScrollPos( wxHORIZONTAL );
2754 if (item_y < start_y+3) {
2755 // going down, item should appear at top
2756 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
2757 }else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
2758 // going up, item should appear at bottom
2759 item_y += yUnit + 2;
2760 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
2764 // FIXME: tree sorting functions are not reentrant and not MT-safe!
2765 static wxTreeListMainWindow *s_treeBeingSorted = NULL;
2767 static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1,
2768 wxTreeListItem **item2)
2770 wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
2772 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
2775 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1,
2776 const wxTreeItemId& item2)
2778 return m_owner->OnCompareItems (item1, item2);
2781 void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId) {
2782 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
2784 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2786 wxCHECK_RET (!s_treeBeingSorted,
2787 _T("wxTreeListMainWindow::SortChildren is not reentrant") );
2789 wxArrayTreeListItems& children = item->GetChildren();
2790 if ( children.Count() > 1 ) {
2792 s_treeBeingSorted = this;
2793 children.Sort(tree_ctrl_compare_func);
2794 s_treeBeingSorted = NULL;
2798 wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, const wxString& str, int mode) {
2800 // determine start item
2801 wxTreeItemId next = item;
2803 if (mode & wxTL_MODE_NAV_LEVEL) {
2804 next = GetNextSibling (next);
2805 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2806 next = GetNextVisible (next, false);
2807 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2808 next = GetNextExpanded (next);
2809 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2810 next = GetNext (next, true);
2814 #if !wxCHECK_VERSION(2, 5, 0)
2817 wxTreeItemIdValue cookie = 0;
2820 next = (wxTreeListItem*)GetRootItem().m_pItem;
2821 if (HasFlag(wxTR_HIDE_ROOT)) {
2822 next = (wxTreeListItem*)GetFirstChild (GetRootItem().m_pItem, cookie).m_pItem;
2825 if (!next.IsOk()) return (wxTreeItemId*)NULL;
2827 // start checking the next items
2828 while (next.IsOk() && (next != item)) {
2829 if (mode & wxTL_MODE_FIND_PARTIAL) {
2830 itemText = GetItemText (next).Mid (0, str.Length());
2832 itemText = GetItemText (next);
2834 if (mode & wxTL_MODE_FIND_NOCASE) {
2835 if (itemText.CmpNoCase (str) == 0) return next;
2837 if (itemText.Cmp (str) == 0) return next;
2839 if (mode & wxTL_MODE_NAV_LEVEL) {
2840 next = GetNextSibling (next);
2841 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2842 next = GetNextVisible (next, false);
2843 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2844 next = GetNextExpanded (next);
2845 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2846 next = GetNext (next, true);
2848 if (!next.IsOk() && item.IsOk()) {
2849 next = (wxTreeListItem*)GetRootItem().m_pItem;
2850 if (HasFlag(wxTR_HIDE_ROOT)) {
2851 next = (wxTreeListItem*)GetNextChild (GetRootItem().m_pItem, cookie).m_pItem;
2855 return (wxTreeItemId*)NULL;
2858 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
2859 wxTreeListItem *prevItem = m_dragItem;
2860 m_dragItem = (wxTreeListItem*) item.m_pItem;
2861 if (prevItem) RefreshLine (prevItem);
2862 if (m_dragItem) RefreshLine (m_dragItem);
2865 void wxTreeListMainWindow::CalculateLineHeight() {
2866 wxClientDC dc (this);
2867 dc.SetFont (m_normalFont);
2868 m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
2870 if (m_imageListNormal) {
2871 // Calculate a m_lineHeight value from the normal Image sizes.
2872 // May be toggle off. Then wxTreeListMainWindow will spread when
2873 // necessary (which might look ugly).
2874 int n = m_imageListNormal->GetImageCount();
2875 for (int i = 0; i < n ; i++) {
2876 int width = 0, height = 0;
2877 m_imageListNormal->GetSize(i, width, height);
2878 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
2882 if (m_imageListButtons) {
2883 // Calculate a m_lineHeight value from the Button image sizes.
2884 // May be toggle off. Then wxTreeListMainWindow will spread when
2885 // necessary (which might look ugly).
2886 int n = m_imageListButtons->GetImageCount();
2887 for (int i = 0; i < n ; i++) {
2888 int width = 0, height = 0;
2889 m_imageListButtons->GetSize(i, width, height);
2890 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
2894 if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
2895 m_lineHeight += 2; // minimal 2 pixel space
2897 m_lineHeight += m_lineHeight / 10; // otherwise 10% space
2901 void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
2902 if (m_ownsImageListNormal) delete m_imageListNormal;
2903 m_imageListNormal = imageList;
2904 m_ownsImageListNormal = false;
2906 CalculateLineHeight();
2909 void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
2910 if (m_ownsImageListState) delete m_imageListState;
2911 m_imageListState = imageList;
2912 m_ownsImageListState = false;
2915 void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
2916 if (m_ownsImageListButtons) delete m_imageListButtons;
2917 m_imageListButtons = imageList;
2918 m_ownsImageListButtons = false;
2920 CalculateLineHeight();
2923 void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
2924 SetImageList(imageList);
2925 m_ownsImageListNormal = true;
2928 void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
2929 SetStateImageList(imageList);
2930 m_ownsImageListState = true;
2933 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
2934 SetButtonsImageList(imageList);
2935 m_ownsImageListButtons = true;
2938 // ----------------------------------------------------------------------------
2940 // ----------------------------------------------------------------------------
2942 void wxTreeListMainWindow::AdjustMyScrollbars() {
2945 GetScrollPixelsPerUnit (&xUnit, &yUnit);
2946 if (xUnit == 0) xUnit = GetCharWidth();
2947 if (yUnit == 0) yUnit = m_lineHeight;
2949 m_rootItem->GetSize (x, y, this);
2950 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2951 int x_pos = GetScrollPos (wxHORIZONTAL);
2952 int y_pos = GetScrollPos (wxVERTICAL);
2953 x = m_owner->GetHeaderWindow()->GetWidth() + 2;
2954 if (x < GetClientSize().GetWidth()) x_pos = 0;
2955 SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
2957 SetScrollbars (0, 0, 0, 0);
2961 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
2962 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
2963 return item->GetHeight();
2965 return m_lineHeight;
2969 void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
2971 wxTreeItemAttr *attr = item->GetAttributes();
2973 dc.SetFont (GetItemFont (item));
2976 if (attr && attr->HasTextColour()) {
2977 colText = attr->GetTextColour();
2979 colText = GetForegroundColour();
2981 #if !wxCHECK_VERSION(2, 5, 0)
2982 wxColour colTextHilight = wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2984 wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2987 int total_w = m_owner->GetHeaderWindow()->GetWidth();
2988 int total_h = GetLineHeight(item);
2989 int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
2990 // std::cout << "off_h="<<off_h<<std::endl;
2992 wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
2994 int text_w = 0, text_h = 0;
2995 dc.GetTextExtent( item->GetText(GetMainColumn()), &text_w, &text_h );
2997 // determine background and show it
2999 if (attr && attr->HasBackgroundColour()) {
3000 colBg = attr->GetBackgroundColour();
3002 colBg = m_backgroundColour;
3004 dc.SetBrush (wxBrush (colBg, wxSOLID));
3005 dc.SetPen (*wxTRANSPARENT_PEN);
3006 if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3007 if (item == m_dragItem) {
3008 dc.SetBrush (*m_hilightBrush);
3009 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3010 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3011 #endif // !__WXMAC__
3012 dc.SetTextForeground (colTextHilight);
3013 }else if (item->IsSelected()) {
3014 if (!m_isDragging && m_hasFocus) {
3015 dc.SetBrush (*m_hilightBrush);
3016 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3017 // LG : dc.SetPen (*wxBLACK_PEN);
3018 dc.SetPen (*wxTRANSPARENT_PEN);
3019 #endif // !__WXMAC__
3021 dc.SetBrush (*m_hilightUnfocusedBrush);
3022 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3023 dc.SetPen (*wxTRANSPARENT_PEN);
3024 #endif // !__WXMAC__
3026 dc.SetTextForeground (colTextHilight);
3029 else if (item == m_curItem) {
3030 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3033 dc.SetTextForeground (colText);
3036 dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
3038 dc.SetTextForeground (colText);
3041 int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
3042 int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
3044 for (int i = 0; i < GetColumnCount(); ++i ) {
3045 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3047 int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
3048 wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
3051 int image = NO_IMAGE;
3053 if(i == GetMainColumn()) {
3054 x = item->GetX() + MARGIN;
3056 x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
3060 if (m_imageListNormal) image = item->GetCurrentImage();
3062 x = x_colstart + MARGIN;
3063 image = item->GetImage(i);
3065 if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
3067 // honor text alignment
3068 wxString text = item->GetText(i);
3070 switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
3072 // nothing to do, already left aligned
3075 dc.GetTextExtent (text, &text_w, NULL);
3076 w = col_w - (image_w + text_w + MARGIN);
3079 case wxALIGN_CENTER:
3080 dc.GetTextExtent(text, &text_w, NULL);
3081 w = (col_w - (image_w + text_w + MARGIN))/2;
3085 int text_x = x + image_w;
3086 if (i == GetMainColumn()) item->SetTextX (text_x);
3088 if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3089 if (i == GetMainColumn()) {
3090 if (item == m_dragItem) {
3091 dc.SetBrush (*m_hilightBrush);
3092 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3093 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3094 #endif // !__WXMAC__
3095 dc.SetTextForeground (colTextHilight);
3096 }else if (item->IsSelected()) {
3097 if (!m_isDragging && m_hasFocus) {
3098 dc.SetBrush (*m_hilightBrush);
3099 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3100 dc.SetPen (*wxBLACK_PEN);
3101 #endif // !__WXMAC__
3103 dc.SetBrush (*m_hilightUnfocusedBrush);
3104 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3105 dc.SetPen (*wxTRANSPARENT_PEN);
3106 #endif // !__WXMAC__
3108 dc.SetTextForeground (colTextHilight);
3111 else if (item == m_curItem) {
3112 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3115 dc.SetTextForeground (colText);
3117 dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3119 dc.SetTextForeground (colText);
3123 dc.SetBackgroundMode (wxTRANSPARENT);
3125 if (image != NO_IMAGE) {
3126 int y = item->GetY() + img_extraH;
3127 m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3129 int text_y = item->GetY() + text_extraH;
3130 dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
3132 x_colstart += col_w;
3135 // restore normal font
3136 dc.SetFont( m_normalFont );
3139 // Now y stands for the top of the item, whereas it used to stand for middle !
3140 void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
3141 int level, int &y, int x_maincol) {
3143 // Handle hide root (only level 0)
3146 //if (HasFlag(wxTR_HIDE_ROOT) && (level < nth)) {
3147 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
3149 wxArrayTreeListItems& children = item->GetChildren();
3150 for (size_t n = 0; n < children.Count(); n++) {
3151 PaintLevel (children[n], dc, 1, y, x_maincol);
3153 // end after expanding root
3157 // calculate position of vertical lines
3158 int x = x_maincol + MARGIN; // start of column
3159 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
3161 x += (m_btnWidth-m_btnWidth2); // half button space
3163 x += (m_indent-m_indent/2);
3165 if (HasFlag(wxTR_HIDE_ROOT)) {
3167 // x += m_indent * (level-nth); // indent but not level 1
3168 x += m_indent * (level-1); // indent but not level 1
3171 x += m_indent * level; // indent according to level
3174 // set position of vertical line
3178 int h = GetLineHeight (item);
3180 int y_mid = y_top + (h/2);
3183 int exposed_x = dc.LogicalToDeviceX(0);
3184 int exposed_y = dc.LogicalToDeviceY(y_top);
3186 if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
3188 if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
3189 //dc.DestroyClippingRegion();
3190 int total_width = m_owner->GetHeaderWindow()->GetWidth();
3191 // if the background colour is white, choose a
3192 // contrasting color for the lines
3193 dc.SetPen (*((GetBackgroundColour() == *wxWHITE)?
3194 wxMEDIUM_GREY_PEN : wxWHITE_PEN));
3195 dc.DrawLine(0, y_top, total_width, y_top);
3196 dc.DrawLine(0, y_top+h, total_width, y_top+h);
3200 PaintItem (item, dc);
3202 // restore DC objects
3203 dc.SetBrush(*wxWHITE_BRUSH);
3204 dc.SetPen(m_dottedPen);
3206 // clip to the column width
3207 int clip_width = m_owner->GetHeaderWindow()->
3208 GetColumn(m_main_column).GetWidth();
3209 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3211 if (!HasFlag(wxTR_NO_LINES)) { // connection lines
3213 // draw the horizontal line here
3214 dc.SetPen(m_dottedPen);
3215 int x2 = x - m_indent;
3216 if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
3217 int x3 = x + (m_btnWidth-m_btnWidth2);
3219 if (item->HasPlus()) {
3220 dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
3221 dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
3223 dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
3226 dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
3230 if (item->HasPlus() && HasButtons()) { // should the item show a button?
3232 if (m_imageListButtons) {
3234 // draw the image button here
3235 int image = wxTreeItemIcon_Normal;
3236 if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
3237 if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
3238 int xx = x - m_btnWidth2 + MARGIN;
3239 int yy = y_mid - m_btnHeight2;
3240 dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
3241 m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
3242 dc.DestroyClippingRegion();
3244 }else if (HasFlag (wxTR_TWIST_BUTTONS)) {
3246 // draw the twisty button here
3247 dc.SetPen(*wxBLACK_PEN);
3248 dc.SetBrush(*m_hilightBrush);
3250 if (item->IsExpanded()) {
3251 button[0].x = x - (m_btnWidth2+1);
3252 button[0].y = y_mid - (m_btnHeight/3);
3253 button[1].x = x + (m_btnWidth2+1);
3254 button[1].y = button[0].y;
3256 button[2].y = button[0].y + (m_btnHeight2+1);
3258 button[0].x = x - (m_btnWidth/3);
3259 button[0].y = y_mid - (m_btnHeight2+1);
3260 button[1].x = button[0].x;
3261 button[1].y = y_mid + (m_btnHeight2+1);
3262 button[2].x = button[0].x + (m_btnWidth2+1);
3263 button[2].y = y_mid;
3265 dc.DrawPolygon(3, button);
3267 }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3269 // draw the plus sign here
3270 dc.SetPen(*wxGREY_PEN);
3271 dc.SetBrush(*wxWHITE_BRUSH);
3272 dc.DrawRectangle (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3273 dc.SetPen(*wxBLACK_PEN);
3274 dc.DrawLine (x-(m_btnWidth2-2), y_mid, x+(m_btnWidth2-1), y_mid);
3275 if (!item->IsExpanded()) { // change "-" to "+"
3276 dc.DrawLine (x, y_mid-(m_btnHeight2-2), x, y_mid+(m_btnHeight2-1));
3285 // restore DC objects
3286 dc.SetBrush(*wxWHITE_BRUSH);
3287 dc.SetPen(m_dottedPen);
3288 dc.SetTextForeground(*wxBLACK);
3290 if (item->IsExpanded())
3292 wxArrayTreeListItems& children = item->GetChildren();
3294 // clip to the column width
3295 int clip_width = m_owner->GetHeaderWindow()->
3296 GetColumn(m_main_column).GetWidth();
3298 // process lower levels
3300 if (m_imgWidth > 0) {
3301 oldY = y_mid + m_imgHeight2;
3306 for (size_t n = 0; n < children.Count(); ++n) {
3309 PaintLevel (children[n], dc, level+1, y, x_maincol);
3311 // draw vertical line
3312 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3313 if (!HasFlag (wxTR_NO_LINES)) {
3315 dc.DrawLine (x, oldY, x, y2);
3323 // ----------------------------------------------------------------------------
3324 // wxWindows callbacks
3325 // ----------------------------------------------------------------------------
3327 void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
3329 wxPaintDC dc (this);
3332 if (!m_rootItem || (GetColumnCount() <= 0)) return;
3334 // calculate button size
3335 if (m_imageListButtons) {
3336 m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
3337 }else if (HasButtons()) {
3338 m_btnWidth = BTNWIDTH;
3339 m_btnHeight = BTNHEIGHT;
3341 m_btnWidth2 = m_btnWidth/2;
3342 m_btnHeight2 = m_btnHeight/2;
3344 // calculate image size
3345 if (m_imageListNormal) {
3346 m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
3348 m_imgWidth2 = m_imgWidth/2;
3349 m_imgHeight2 = m_imgHeight/2;
3351 // calculate indent size
3352 if (m_imageListButtons) {
3353 m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
3354 }else if (HasButtons()) {
3355 m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
3358 // set default values
3359 dc.SetFont( m_normalFont );
3360 dc.SetPen( m_dottedPen );
3362 // calculate column start and paint
3365 for (i = 0; i < (int)GetMainColumn(); ++i) {
3366 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3367 x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
3370 PaintLevel (m_rootItem, dc, 0, y, x_maincol);
3373 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
3377 if (m_curItem) RefreshLine (m_curItem);
3381 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
3385 if (m_curItem) RefreshLine (m_curItem);
3389 void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
3390 // send event to user code
3391 wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, m_owner->GetId());
3392 nevent.SetKeyEvent (event);
3393 nevent.SetEventObject (m_owner);
3394 if (m_owner->GetEventHandler()->ProcessEvent (nevent)) return; // handled in user code
3396 // determine first current if none
3397 bool curItemSet = false;
3399 m_curItem = (wxTreeListItem*)GetRootItem().m_pItem;
3400 if (HasFlag(wxTR_HIDE_ROOT)) {
3401 #if !wxCHECK_VERSION(2, 5, 0)
3404 wxTreeItemIdValue cookie = 0;
3406 m_curItem = (wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem;
3410 if (!m_curItem) return; // do nothing if empty tree
3412 // remember item at shift down
3413 if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
3414 if (!m_shiftItem) m_shiftItem = m_curItem;
3416 m_shiftItem = (wxTreeListItem*)NULL;
3419 // process all cases
3420 wxTreeItemId newItem = (wxTreeItemId*)NULL;
3421 switch (event.GetKeyCode()) {
3423 // '+': Expand subtree
3426 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
3429 // '-': collapse subtree
3431 case WXK_SUBTRACT: {
3432 if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
3435 // '*': expand/collapse all subtrees // TODO: Mak it more useful
3437 case WXK_MULTIPLY: {
3438 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3439 ExpandAll (m_curItem);
3440 }else if (m_curItem->HasPlus()) {
3441 Collapse (m_curItem); // TODO: CollapseAll
3445 // ' ': toggle current item
3447 SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
3450 // <RETURN>: activate current item
3452 wxTreeEvent aevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
3453 #if !wxCHECK_VERSION(2, 5, 0)
3454 aevent.SetItem ((long)m_curItem);
3456 aevent.SetItem (m_curItem);
3458 aevent.SetEventObject (m_owner);
3459 m_owner->GetEventHandler()->ProcessEvent (aevent);
3462 // <BKSP>: go to the parent without collapsing
3464 newItem = GetItemParent (m_curItem);
3465 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3466 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
3470 // <UP>: go to the previous sibling or to the last of its children, to the parent
3472 newItem = GetPrevSibling (m_curItem);
3474 #if !wxCHECK_VERSION(2, 5, 0)
3477 wxTreeItemIdValue cookie = 0;
3479 while (IsExpanded (newItem) && HasChildren (newItem)) {
3480 newItem = GetLastChild (newItem, cookie);
3483 newItem = GetItemParent (m_curItem);
3484 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3485 newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
3490 // <LEFT>: if expanded collapse subtree, else go to the parent
3492 if (IsExpanded (m_curItem)) {
3493 Collapse (m_curItem);
3495 newItem = GetItemParent (m_curItem);
3496 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3497 newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
3502 // <RIGHT>: if possible expand subtree, else go go to the first child
3504 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3507 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3508 #if !wxCHECK_VERSION(2, 5, 0)
3511 wxTreeItemIdValue cookie = 0;
3513 newItem = GetFirstChild (m_curItem, cookie);
3518 // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3521 newItem = m_curItem;
3523 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3524 #if !wxCHECK_VERSION(2, 5, 0)
3527 wxTreeItemIdValue cookie = 0;
3529 newItem = GetFirstChild( m_curItem, cookie );
3532 wxTreeItemId parent = m_curItem;
3534 newItem = GetNextSibling (parent);
3535 parent = GetItemParent (parent);
3536 } while (!newItem && parent);
3541 // <END>: go to last item of the root
3543 #if !wxCHECK_VERSION(2, 5, 0)
3546 wxTreeItemIdValue cookie = 0;
3548 newItem = GetLastChild (GetRootItem(), cookie);
3551 // <HOME>: go to root
3553 newItem = GetRootItem();
3554 if (HasFlag(wxTR_HIDE_ROOT)) {
3555 #if !wxCHECK_VERSION(2, 5, 0)
3558 wxTreeItemIdValue cookie = 0;
3560 newItem = GetFirstChild (newItem, cookie);
3564 // any char: go to the next matching string
3566 if (event.GetKeyCode() >= (int)' ') {
3567 if (!m_findTimer->IsRunning()) m_findStr.Clear();
3568 m_findStr.Append (event.GetKeyCode());
3569 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
3570 wxTreeItemId prev = m_curItem? (wxTreeItemId*)m_curItem: (wxTreeItemId*)NULL;
3572 newItem = FindItem (prev, m_findStr, wxTL_MODE_NAV_EXPANDED |
3573 wxTL_MODE_FIND_PARTIAL |
3574 wxTL_MODE_FIND_NOCASE);
3575 if (newItem || (m_findStr.Length() <= 1)) break;
3576 m_findStr.RemoveLast();
3583 // select and show the new item
3585 if (!event.ControlDown()) {
3586 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3587 HasFlag(wxTR_MULTIPLE));
3588 SelectItem (newItem, m_shiftItem, unselect_others);
3590 EnsureVisible (newItem);
3591 wxTreeListItem *oldItem = m_curItem;
3592 m_curItem = (wxTreeListItem*)newItem.m_pItem; // make the new item the current item
3593 RefreshLine (oldItem);
3598 wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
3604 if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
3605 if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
3606 if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
3607 if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
3608 if (flags) return wxTreeItemId();
3611 flags = wxTREE_HITTEST_NOWHERE;
3613 return wxTreeItemId();
3616 wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
3617 this, flags, column, 0);
3619 flags = wxTREE_HITTEST_NOWHERE;
3621 return wxTreeItemId();
3626 // get the bounding rectangle of the item (or of its label only)
3627 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
3628 bool WXUNUSED(textOnly)) const {
3629 wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
3631 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
3634 GetScrollPixelsPerUnit (&xUnit, &yUnit);
3636 GetViewStart(& startX, & startY);
3638 rect.x = item->GetX() - startX * xUnit;
3639 rect.y = item->GetY() - startY * yUnit;
3640 rect.width = item->GetWidth();
3641 rect.height = GetLineHeight (item);
3648 void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
3649 if (!item.IsOk()) return;
3650 if (!((column >= 0) && (column < GetColumnCount()))) return;
3652 m_editItem = (wxTreeListItem*) item.m_pItem;
3654 wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, m_owner->GetId() );
3655 #if !wxCHECK_VERSION(2, 5, 0)
3656 te.SetItem ((long)m_editItem);
3658 te.SetItem (m_editItem);
3661 te.SetEventObject (m_owner );
3662 m_owner->GetEventHandler()->ProcessEvent (te);
3664 if (!te.IsAllowed()) return;
3666 // ensure that the position of the item it calculated in any case
3667 if (m_dirty) CalculatePositions();
3669 wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
3671 int y = m_editItem->GetY() + 1; // wxTextCtrl needs 1 pixels above the text
3673 int h = m_editItem->GetHeight();
3675 if (column == GetMainColumn()) {
3676 x += m_editItem->GetTextX() - 2; // wxTextCtrl needs 2 pixels before the text
3677 w = wxMin (m_editItem->GetWidth(), m_owner->GetHeaderWindow()->GetWidth() - x);
3679 for (int i = 0; i < column; ++i) x += header_win->GetColumnWidth (i); // start of column
3680 switch (header_win->GetColumnAlignment (column)) {
3681 case wxALIGN_LEFT: {style = wxTE_LEFT; break;}
3682 case wxALIGN_RIGHT: {style = wxTE_RIGHT; break;}
3683 case wxALIGN_CENTER: {style = wxTE_CENTER; break;}
3685 w = header_win->GetColumnWidth (column); // width of column
3688 wxClientDC dc (this);
3690 x = dc.LogicalToDeviceX (x);
3691 y = dc.LogicalToDeviceY (y);
3693 wxEditTextCtrl *text = new wxEditTextCtrl (this, -1, &m_renameAccept, &m_renameRes,
3694 this, m_editItem->GetText (column),
3695 wxPoint (x, y), wxSize (w, h), style);
3699 void wxTreeListMainWindow::OnRenameTimer() {
3700 EditLabel (m_curItem, m_curColumn);
3703 void wxTreeListMainWindow::OnRenameAccept() {
3705 // TODO if the validator fails this causes a crash
3706 wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, m_owner->GetId() );
3707 #if !wxCHECK_VERSION(2, 5, 0)
3708 le.SetItem((long)m_editItem);
3710 le.SetItem(m_editItem);
3712 le.SetEventObject( /*this*/m_owner );
3713 le.SetLabel( m_renameRes );
3714 m_owner->GetEventHandler()->ProcessEvent( le );
3716 if (!le.IsAllowed()) return;
3718 SetItemText (m_editItem, m_curColumn, m_renameRes);
3721 void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
3722 if (!m_rootItem) return;
3724 // we process left mouse up event (enables in-place edit), right down
3725 // (pass to the user code), left dbl click (activate item) and
3726 // dragging/moving events for items drag-and-drop
3727 if (!(event.LeftDown() ||
3729 event.RightDown() ||
3731 event.LeftDClick() ||
3733 (event.GetWheelRotation() != 0 )/*? TODO ||
3734 event.Moving()?*/)) {
3735 m_owner->GetEventHandler()->ProcessEvent (event);
3739 // set focus if window clicked
3740 if (event.LeftDown() || event.RightDown()) SetFocus();
3743 wxPoint p = wxPoint (event.GetX(), event.GetY());
3745 wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
3746 this, flags, m_curColumn, 0);
3748 // we only process dragging here
3749 if (event.Dragging()){
3750 if (m_isDragging) return; // nothing to do, already done
3751 if (item == NULL) return; // we need an item to dragging
3753 // determine drag start
3754 if (m_dragCount == 0) {
3755 m_dragTimer->Start (DRAG_TIMER_TICKS, wxTIMER_ONE_SHOT);
3758 if (m_dragCount < 3) return; // minimum drag 3 pixel
3759 if (m_dragTimer->IsRunning()) return;
3761 // we're going to drag
3763 m_isDragging = true;
3767 // send drag start event
3768 wxEventType command = event.LeftIsDown()
3769 ? wxEVT_COMMAND_TREE_BEGIN_DRAG
3770 : wxEVT_COMMAND_TREE_BEGIN_RDRAG;
3771 wxTreeEvent nevent (command, m_owner->GetId());
3772 nevent.SetEventObject (m_owner);
3773 #if !wxCHECK_VERSION(2, 5, 0)
3774 nevent.SetItem ((long)item); // the item the drag is ended
3776 nevent.SetItem (item); // the item the drag is ended
3778 nevent.Veto(); // dragging must be explicit allowed!
3779 m_owner->GetEventHandler()->ProcessEvent (nevent);
3781 }else if (m_isDragging) { // any other event but not event.Dragging()
3785 m_isDragging = false;
3786 if (HasCapture()) ReleaseMouse();
3789 // send drag end event event
3790 wxTreeEvent nevent (wxEVT_COMMAND_TREE_END_DRAG, m_owner->GetId());
3791 nevent.SetEventObject (m_owner);
3792 #if !wxCHECK_VERSION(2, 5, 0)
3793 nevent.SetItem ((long)item); // the item the drag is started
3795 nevent.SetItem (item); // the item the drag is started
3797 nevent.SetPoint (p);
3798 m_owner->GetEventHandler()->ProcessEvent (nevent);
3800 }else if (m_dragCount > 0) { // just in case dragging is initiated
3807 // we process only the messages which happen on tree items
3809 m_owner->GetEventHandler()->ProcessEvent (event);
3813 // remember item at shift down
3814 if (event.ShiftDown()) {
3815 if (!m_shiftItem) m_shiftItem = m_curItem;
3817 m_shiftItem = (wxTreeListItem*)NULL;
3820 if (event.RightUp()) {
3823 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, m_owner->GetId());
3824 nevent.SetEventObject (m_owner);
3825 #if !wxCHECK_VERSION(2, 5, 0)
3826 nevent.SetItem ((long)item); // the item clicked
3828 nevent.SetItem (item); // the item clicked
3830 nevent.SetInt (m_curColumn); // the colum clicked
3831 nevent.SetPoint (p);
3832 m_owner->GetEventHandler()->ProcessEvent (nevent);
3834 }else if (event.LeftUp()) {
3837 if ((item == m_curItem) && (m_curColumn != -1) &&
3838 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
3839 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))){
3840 m_renameTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
3842 m_lastOnSame = false;
3845 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3846 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3847 HasButtons() && item->HasPlus()) {
3850 // only toggle the item for a single click, double click on
3851 // the button doesn't do anything (it toggles the item twice)
3852 if (event.LeftDown()) Toggle (item);
3854 // don't select the item if the button was clicked
3858 // determine the selection if not done by left down
3859 if (!m_left_down_selection) {
3860 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3861 HasFlag(wxTR_MULTIPLE));
3863 SelectItem (item, m_shiftItem, unselect_others);
3864 EnsureVisible (item);
3865 // LG m_curItem = item; // make the new item the current item
3867 m_left_down_selection = false;
3870 }else if (event.LeftDown() || event.RightDown() || event.LeftDClick()) {
3872 if (event.LeftDown() || event.RightDown()) {
3874 m_lastOnSame = item == m_curItem;
3877 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3878 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3881 // only toggle the item for a single click, double click on
3882 // the button doesn't do anything (it toggles the item twice)
3884 if (event.LeftDown()) Toggle (item);
3886 // don't select the item if the button was clicked
3890 // determine the selection if the current item is not selected
3891 if (!item->IsSelected()) {
3892 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3893 HasFlag(wxTR_MULTIPLE));
3894 SelectItem (item, m_shiftItem, unselect_others);
3895 EnsureVisible (item);
3896 // LG m_curItem = item; // make the new item the current item
3897 m_left_down_selection = true;
3900 // For some reason, Windows isn't recognizing a left double-click,
3901 // so we need to simulate it here. Allow 200 milliseconds for now.
3902 if (event.LeftDClick()) {
3904 // double clicking should not start editing the item label
3905 m_renameTimer->Stop();
3906 m_lastOnSame = false;
3908 // send activate event first
3909 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
3910 nevent.SetEventObject (m_owner);
3911 #if !wxCHECK_VERSION(2, 5, 0)
3912 nevent.SetItem ((long)item); // the item clicked
3914 nevent.SetItem (item); // the item clicked
3916 nevent.SetInt (m_curColumn); // the colum clicked
3917 nevent.SetPoint (p);
3918 if (!m_owner->GetEventHandler()->ProcessEvent (nevent)) {
3920 // if the user code didn't process the activate event,
3921 // handle it ourselves by toggling the item when it is
3924 if (item->HasPlus()) Toggle(item);
3928 }else{ // any other event skip just in case
3935 void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
3936 /* after all changes have been done to the tree control,
3937 * we actually redraw the tree when everything is over */
3939 if (!m_dirty) return;
3943 CalculatePositions();
3945 AdjustMyScrollbars();
3948 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
3950 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
3951 wxScrolledWindow::OnScroll(event);
3953 HandleOnScroll( event );
3956 if(event.GetOrientation() == wxHORIZONTAL) {
3957 m_owner->GetHeaderWindow()->Refresh();
3958 m_owner->GetHeaderWindow()->Update();
3962 void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
3966 dc.SetFont (GetItemFont (item));
3968 dc.GetTextExtent (item->GetText (m_main_column), &text_w, &text_h);
3970 // restore normal font
3971 dc.SetFont (m_normalFont);
3973 int total_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
3974 if (total_h < 30) { // add 10% space if greater than 30 pixels
3975 total_h += 2; // minimal 2 pixel space
3977 total_h += total_h / 10; // otherwise 10% space
3980 item->SetHeight (total_h);
3981 if (total_h > m_lineHeight) m_lineHeight = total_h;
3982 item->SetWidth(m_imgWidth + text_w +2);
3985 // -----------------------------------------------------------------------------
3986 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
3987 int level, int &y, int x_colstart) {
3989 // calculate position of vertical lines
3990 int x = x_colstart + MARGIN; // start of column
3991 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
3993 x += (m_btnWidth-m_btnWidth2); // half button space
3995 x += (m_indent-m_indent/2);
3997 if (HasFlag(wxTR_HIDE_ROOT)) {
3999 // x += m_indent * (level-2); // indent but not level 1
4000 x += m_indent * (level-1); // indent but not level 1
4003 x += m_indent * level; // indent according to level
4006 // a hidden root is not evaluated, but its children are always
4007 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
4009 CalculateSize( item, dc );
4014 y += GetLineHeight(item);
4016 // we don't need to calculate collapsed branches
4017 if ( !item->IsExpanded() ) return;
4020 wxArrayTreeListItems& children = item->GetChildren();
4021 long n, count = (long)children.Count();
4023 for (n = 0; n < count; ++n) {
4024 CalculateLevel( children[n], dc, level, y, x_colstart ); // recurse
4028 void wxTreeListMainWindow::CalculatePositions() {
4029 if ( !m_rootItem ) return;
4031 wxClientDC dc(this);
4034 dc.SetFont( m_normalFont );
4036 dc.SetPen( m_dottedPen );
4037 //if(GetImageList() == NULL)
4038 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
4042 for (int i = 0; i < (int)GetMainColumn(); ++i) {
4043 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
4044 x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
4046 CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
4049 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
4050 if (m_dirty) return;
4052 wxClientDC dc(this);
4057 GetVirtualSize( &cw, &ch );
4060 rect.x = dc.LogicalToDeviceX( 0 );
4062 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
4065 Refresh (true, &rect );
4066 AdjustMyScrollbars();
4069 void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
4072 // std::cout << "RefreshLine = "<<item<<std::endl;
4075 if (m_dirty) return;
4077 wxClientDC dc(this);
4082 GetVirtualSize( &cw, &ch );
4085 rect.x = dc.LogicalToDeviceX( 0 );
4086 rect.y = dc.LogicalToDeviceY( item->GetY() );
4088 rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
4090 Refresh (true, &rect);
4093 void wxTreeListMainWindow::RefreshSelected()
4096 long count = m_selected.GetCount();
4097 for (long n = 0; n < count; n++ )
4099 RefreshLine (m_selected[n]);
4104 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
4105 if (item->IsSelected()) {
4109 const wxArrayTreeListItems& children = item->GetChildren();
4110 long count = children.GetCount();
4111 for (long n = 0; n < count; n++ ) {
4112 RefreshSelectedUnder (children[n]);
4117 // ----------------------------------------------------------------------------
4118 // changing colours: we need to refresh the tree control
4119 // ----------------------------------------------------------------------------
4121 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
4122 if (!wxWindow::SetBackgroundColour(colour)) return false;
4128 bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
4129 if (!wxWindow::SetForegroundColour(colour)) return false;
4135 void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column,
4136 const wxString& text) {
4137 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
4139 wxClientDC dc (this);
4140 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
4141 item->SetText (column, text);
4142 CalculateSize (item, dc);
4146 wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId,
4148 wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
4150 if( IsVirtual() ) return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
4151 else return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
4154 wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item,
4156 wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4157 return m_owner->OnGetItemText(item,column);
4160 void wxTreeListMainWindow::SetFocus() {
4161 wxWindow::SetFocus();
4164 wxFont wxTreeListMainWindow::GetItemFont (wxTreeListItem *item) {
4165 wxTreeItemAttr *attr = item->GetAttributes();
4167 if (attr && attr->HasFont()) {
4168 return attr->GetFont();
4169 }else if (item->IsBold()) {
4172 return m_normalFont;
4176 int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
4177 if (!item) return 0;
4179 // determine item width
4181 wxFont font = GetItemFont (item);
4182 GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
4186 int width = w + 2*MARGIN;
4187 if (column == GetMainColumn()) {
4189 if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
4190 if (HasButtons()) width += m_btnWidth + LINEATROOT;
4191 if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
4193 // count indent level
4195 wxTreeListItem *parent = item->GetItemParent();
4196 wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
4197 while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
4199 parent = parent->GetItemParent();
4201 if (level) width += level * GetIndent();
4207 int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
4209 GetClientSize (&maxWidth, &h);
4212 // get root if on item
4213 if (!parent.IsOk()) parent = GetRootItem();
4216 if (!HasFlag(wxTR_HIDE_ROOT)) {
4217 int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
4218 if (width < w) width = w;
4219 if (width > maxWidth) return maxWidth;
4222 wxTreeItemIdValue cookie = 0;
4223 wxTreeItemId item = GetFirstChild (parent, cookie);
4224 while (item.IsOk()) {
4225 int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
4226 if (width < w) width = w;
4227 if (width > maxWidth) return maxWidth;
4229 // check the children of this item
4230 if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
4231 int w = GetBestColumnWidth (column, item);
4232 if (width < w) width = w;
4233 if (width > maxWidth) return maxWidth;
4237 item = GetNextChild (parent, cookie);
4244 //-----------------------------------------------------------------------------
4246 //-----------------------------------------------------------------------------
4248 //IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
4249 //IMPLEMENT_CLASS(wxTreeListCtrl, wxControl);
4251 BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
4252 EVT_SIZE(wxTreeListCtrl::OnSize)
4255 bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
4258 long style, const wxValidator &validator,
4259 const wxString& name)
4261 long main_style = style & ~(wxSIMPLE_BORDER|wxSUNKEN_BORDER|wxDOUBLE_BORDER|
4262 wxRAISED_BORDER|wxSTATIC_BORDER);
4263 long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
4265 if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
4268 m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
4269 main_style, validator);
4270 m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
4271 wxPoint(0, 0), wxDefaultSize,
4273 CalculateAndSetHeaderHeight();
4277 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4281 // we use 'g' to get the descent, too
4283 m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
4284 h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
4286 // only update if changed
4287 if (h != m_headerHeight) {
4294 void wxTreeListCtrl::DoHeaderLayout()
4297 GetClientSize(&w, &h);
4299 m_header_win->SetSize (0, 0, w, m_headerHeight);
4300 m_header_win->Refresh();
4303 m_main_win->SetSize (0, m_headerHeight + 1, w, h - m_headerHeight - 1);
4307 void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
4312 size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
4314 unsigned int wxTreeListCtrl::GetIndent() const
4315 { return m_main_win->GetIndent(); }
4317 void wxTreeListCtrl::SetIndent(unsigned int indent)
4318 { m_main_win->SetIndent(indent); }
4320 unsigned int wxTreeListCtrl::GetLineSpacing() const
4321 { return m_main_win->GetLineSpacing(); }
4323 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
4324 { m_main_win->SetLineSpacing(spacing); }
4326 wxImageList* wxTreeListCtrl::GetImageList() const
4327 { return m_main_win->GetImageList(); }
4329 wxImageList* wxTreeListCtrl::GetStateImageList() const
4330 { return m_main_win->GetStateImageList(); }
4332 wxImageList* wxTreeListCtrl::GetButtonsImageList() const
4333 { return m_main_win->GetButtonsImageList(); }
4335 void wxTreeListCtrl::SetImageList(wxImageList* imageList)
4336 { m_main_win->SetImageList(imageList); }
4338 void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
4339 { m_main_win->SetStateImageList(imageList); }
4341 void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
4342 { m_main_win->SetButtonsImageList(imageList); }
4344 void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
4345 { m_main_win->AssignImageList(imageList); }
4347 void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
4348 { m_main_win->AssignStateImageList(imageList); }
4350 void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
4351 { m_main_win->AssignButtonsImageList(imageList); }
4353 wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
4354 { return m_main_win->GetItemText (item, column); }
4356 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column,
4357 wxTreeItemIcon which) const
4358 { return m_main_win->GetItemImage(item, column, which); }
4360 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
4361 { return m_main_win->GetItemData(item); }
4363 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
4364 { return m_main_win->GetItemBold(item); }
4366 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
4367 { return m_main_win->GetItemTextColour(item); }
4369 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item)
4371 { return m_main_win->GetItemBackgroundColour(item); }
4373 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
4374 { return m_main_win->GetItemFont(item); }
4377 void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column,
4378 const wxString& text)
4379 { m_main_win->SetItemText (item, column, text); }
4381 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item,
4384 wxTreeItemIcon which)
4385 { m_main_win->SetItemImage(item, column, image, which); }
4387 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,
4388 wxTreeItemData* data)
4389 { m_main_win->SetItemData(item, data); }
4391 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
4392 { m_main_win->SetItemHasChildren(item, has); }
4394 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
4395 { m_main_win->SetItemBold(item, bold); }
4397 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,
4398 const wxColour& colour)
4399 { m_main_win->SetItemTextColour(item, colour); }
4401 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
4402 const wxColour& colour)
4403 { m_main_win->SetItemBackgroundColour(item, colour); }
4405 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,
4407 { m_main_win->SetItemFont(item, font); }
4409 bool wxTreeListCtrl::SetFont(const wxFont& font)
4412 m_header_win->SetFont(font);
4413 CalculateAndSetHeaderHeight();
4414 m_header_win->Refresh();
4417 return m_main_win->SetFont(font);
4423 void wxTreeListCtrl::SetWindowStyle(const long style)
4426 m_main_win->SetWindowStyle(style);
4427 m_windowStyle = style;
4428 // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4431 long wxTreeListCtrl::GetWindowStyle() const
4433 long style = m_windowStyle;
4435 style |= m_main_win->GetWindowStyle();
4439 bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow) const
4440 { return m_main_win->IsVisible(item, fullRow); }
4442 bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
4443 { return m_main_win->HasChildren(item); }
4445 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
4446 { return m_main_win->IsExpanded(item); }
4448 bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
4449 { return m_main_win->IsSelected(item); }
4451 bool wxTreeListCtrl::IsBold(const wxTreeItemId& item) const
4452 { return m_main_win->IsBold(item); }
4454 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
4455 { return m_main_win->GetChildrenCount(item, rec); }
4457 wxTreeItemId wxTreeListCtrl::GetRootItem() const
4458 { return m_main_win->GetRootItem(); }
4460 //wxTreeItemId wxTreeListCtrl::GetSelection() const
4461 //{ return m_main_win->GetSelection(); }
4462 wxTreeItemId wxTreeListCtrl::GetCurrent() const
4463 { return m_main_win->GetCurrent(); }
4465 // returns the number of currently selected items
4466 size_t wxTreeListCtrl::GetSelectionSize() const
4467 { return m_main_win->GetSelectionSize(); }
4469 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
4470 { return m_main_win->GetSelections(arr); }
4472 wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
4473 { return m_main_win->GetItemParent(item); }
4475 #if !wxCHECK_VERSION(2, 5, 0)
4476 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4479 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4480 wxTreeItemIdValue& cookie) const
4482 { return m_main_win->GetFirstChild(item, cookie); }
4484 #if !wxCHECK_VERSION(2, 5, 0)
4485 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4488 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4489 wxTreeItemIdValue& cookie) const
4491 { return m_main_win->GetNextChild(item, cookie); }
4493 #if !wxCHECK_VERSION(2, 5, 0)
4494 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4497 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4498 wxTreeItemIdValue& cookie) const
4500 { return m_main_win->GetPrevChild(item, cookie); }
4502 #if !wxCHECK_VERSION(2, 5, 0)
4503 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4506 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4507 wxTreeItemIdValue& cookie) const
4509 { return m_main_win->GetLastChild(item, cookie); }
4512 wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
4513 { return m_main_win->GetNextSibling(item); }
4515 wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
4516 { return m_main_win->GetPrevSibling(item); }
4518 wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
4519 { return m_main_win->GetNext(item, true); }
4521 wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
4522 { return m_main_win->GetPrev(item, true); }
4524 wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
4525 { return m_main_win->GetFirstExpandedItem(); }
4527 wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
4528 { return m_main_win->GetNextExpanded(item); }
4530 wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
4531 { return m_main_win->GetPrevExpanded(item); }
4533 wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
4534 { return m_main_win->GetFirstVisibleItem(fullRow); }
4536 wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow) const
4537 { return m_main_win->GetNextVisible(item, fullRow); }
4539 wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow) const
4540 { return m_main_win->GetPrevVisible(item, fullRow); }
4542 wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
4543 int selectedImage, wxTreeItemData* data)
4544 { return m_main_win->AddRoot (text, image, selectedImage, data); }
4546 wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
4547 const wxString& text, int image,
4549 wxTreeItemData* data)
4550 { return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
4552 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4553 const wxTreeItemId& previous,
4554 const wxString& text, int image,
4556 wxTreeItemData* data)
4558 return m_main_win->InsertItem(parent, previous, text, image,
4559 selectedImage, data);
4562 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4564 const wxString& text, int image,
4566 wxTreeItemData* data)
4568 return m_main_win->InsertItem(parent, index, text, image,
4569 selectedImage, data);
4572 wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
4573 const wxString& text, int image,
4575 wxTreeItemData* data)
4576 { return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
4578 void wxTreeListCtrl::Delete(const wxTreeItemId& item)
4579 { m_main_win->Delete(item); }
4581 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
4582 { m_main_win->DeleteChildren(item); }
4584 void wxTreeListCtrl::DeleteRoot()
4585 { m_main_win->DeleteRoot(); }
4587 void wxTreeListCtrl::Expand(const wxTreeItemId& item)
4588 { m_main_win->Expand(item); }
4590 void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
4591 { m_main_win->ExpandAll(item); }
4593 void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
4594 { m_main_win->Collapse(item); }
4596 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
4597 { m_main_win->CollapseAndReset(item); }
4599 void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
4600 { m_main_win->Toggle(item); }
4602 //void wxTreeListCtrl::Unselect()
4603 //{ m_main_win->Unselect(); }
4605 // LG 19/09/08 : Added
4606 //void wxTreeListCtrl::Unselect(wxTreeItemId& item)
4607 //{ m_main_win->Unselect((wxTreeListItem*)item.m_pItem); }
4609 void wxTreeListCtrl::UnselectAll()
4610 { m_main_win->UnselectAll(); }
4612 void wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
4613 bool unselect_others)
4614 { m_main_win->SelectItem (item, last, unselect_others); }
4616 void wxTreeListCtrl::SelectAll()
4617 { m_main_win->SelectAll(); }
4619 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
4620 { m_main_win->EnsureVisible(item); }
4622 void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
4623 { m_main_win->ScrollTo(item); }
4625 wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
4627 wxPoint p = m_main_win->ScreenToClient (ClientToScreen (pos));
4628 return m_main_win->HitTest (p, flags, column);
4631 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
4632 bool textOnly) const
4633 { return m_main_win->GetBoundingRect(item, rect, textOnly); }
4635 void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
4636 { m_main_win->EditLabel (item, column); }
4638 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1,
4639 const wxTreeItemId& item2)
4641 // do the comparison here, and not delegate to m_main_win, in order
4642 // to let the user override it
4643 //return m_main_win->OnCompareItems(item1, item2);
4644 return wxStrcmp(GetItemText(item1), GetItemText(item2));
4647 void wxTreeListCtrl::SortChildren(const wxTreeItemId& item)
4648 { m_main_win->SortChildren(item); }
4650 wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, const wxString& str, int mode)
4651 { return m_main_win->FindItem (item, str, mode); }
4653 void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
4654 { m_main_win->SetDragItem (item); }
4656 bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
4658 if (!m_main_win) return false;
4659 return m_main_win->SetBackgroundColour(colour);
4662 bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
4664 if (!m_main_win) return false;
4665 return m_main_win->SetForegroundColour(colour);
4668 int wxTreeListCtrl::GetColumnCount() const
4669 { return m_main_win->GetColumnCount(); }
4671 void wxTreeListCtrl::SetColumnWidth(int column, int width)
4673 m_header_win->SetColumnWidth (column, width);
4674 m_header_win->Refresh();
4677 int wxTreeListCtrl::GetColumnWidth(int column) const
4678 { return m_header_win->GetColumnWidth(column); }
4680 void wxTreeListCtrl::SetMainColumn(int column)
4681 { m_main_win->SetMainColumn(column); }
4683 int wxTreeListCtrl::GetMainColumn() const
4684 { return m_main_win->GetMainColumn(); }
4686 void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
4688 m_header_win->SetColumnText (column, text);
4689 m_header_win->Refresh();
4692 wxString wxTreeListCtrl::GetColumnText(int column) const
4693 { return m_header_win->GetColumnText(column); }
4695 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
4697 m_header_win->AddColumn (colInfo);
4701 void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
4703 m_header_win->InsertColumn (before, colInfo);
4704 m_header_win->Refresh();
4707 void wxTreeListCtrl::RemoveColumn(int column)
4709 m_header_win->RemoveColumn (column);
4710 m_header_win->Refresh();
4713 void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
4715 m_header_win->SetColumn (column, colInfo);
4716 m_header_win->Refresh();
4719 const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
4720 { return m_header_win->GetColumn(column); }
4722 wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column)
4723 { return m_header_win->GetColumn(column); }
4725 void wxTreeListCtrl::SetColumnImage(int column, int image)
4727 m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
4728 m_header_win->Refresh();
4731 int wxTreeListCtrl::GetColumnImage(int column) const
4733 return m_header_win->GetColumn(column).GetImage();
4736 void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
4738 m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
4741 void wxTreeListCtrl::SetColumnShown(int column, bool shown)
4743 wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
4744 m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
4745 m_header_win->Refresh();
4748 bool wxTreeListCtrl::IsColumnEditable(int column) const
4750 return m_header_win->GetColumn(column).IsEditable();
4753 bool wxTreeListCtrl::IsColumnShown(int column) const
4755 return m_header_win->GetColumn(column).IsShown();
4758 void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
4760 m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
4761 m_header_win->Refresh();
4764 int wxTreeListCtrl::GetColumnAlignment(int column) const
4766 return m_header_win->GetColumn(column).GetAlignment();
4769 void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
4771 m_main_win->Refresh (erase, rect);
4772 m_header_win->Refresh (erase, rect);
4775 void wxTreeListCtrl::SetFocus()
4776 { m_main_win->SetFocus(); }
4778 wxSize wxTreeListCtrl::DoGetBestSize() const
4780 // something is better than nothing...
4781 return wxSize (200,200); // but it should be specified values! FIXME
4784 wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
4786 return wxEmptyString;