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.1.1.1 2008/09/26 14:15:48 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"
28 // For compilers that support precompilation, includes "wx.h".
29 #include "wx/wxprec.h"
36 #include <wx/treebase.h>
38 #include <wx/textctrl.h>
39 #include <wx/imaglist.h>
40 #include <wx/settings.h>
41 #include <wx/dcclient.h>
42 #include <wx/dcscreen.h>
43 #include <wx/scrolwin.h>
48 //#include "wx/treelistctrl.h"
49 #include "treelistctrl.h"
52 #include "wx/mac/private.h"
56 // ---------------------------------------------------------------------------
58 // ---------------------------------------------------------------------------
62 #if !wxCHECK_VERSION(2, 5, 0)
63 WX_DEFINE_ARRAY(wxTreeListItem *, wxArrayTreeListItems);
65 WX_DEFINE_ARRAY_PTR(wxTreeListItem *, wxArrayTreeListItems);
68 #include <wx/dynarray.h>
69 WX_DECLARE_OBJARRAY(wxTreeListColumnInfo, wxArrayTreeListColumnInfo);
70 #include <wx/arrimpl.cpp>
71 WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo);
73 #if !wxCHECK_VERSION(2, 3, 3)
74 WX_DEFINE_ARRAY(short, wxArrayShort);
78 // --------------------------------------------------------------------------
80 // --------------------------------------------------------------------------
82 static const int NO_IMAGE = -1;
84 static const int LINEHEIGHT = 10;
85 static const int LINEATROOT = 5;
86 static const int MARGIN = 2;
87 static const int MININDENT = 16;
88 static const int BTNWIDTH = 9;
89 static const int BTNHEIGHT = 9;
90 static const int EXTRA_WIDTH = 4;
91 static const int EXTRA_HEIGHT = 4;
92 static const int HEADER_OFFSET_X = 1;
93 static const int HEADER_OFFSET_Y = 1;
95 static const int DRAG_TIMER_TICKS = 250; // minimum drag wait time in ms
96 static const int FIND_TIMER_TICKS = 500; // minimum find wait time in ms
97 static const int RENAME_TIMER_TICKS = 250; // minimum rename wait time in ms
99 const wxChar* wxTreeListCtrlNameStr = _T("treelistctrl");
101 static wxTreeListColumnInfo wxInvalidTreeListColumnInfo;
104 // ---------------------------------------------------------------------------
106 // ---------------------------------------------------------------------------
107 //-----------------------------------------------------------------------------
108 // wxTreeListHeaderWindow (internal)
109 //-----------------------------------------------------------------------------
111 class CREAIMAGEIO_EXPORT wxTreeListHeaderWindow : public wxWindow
114 wxTreeListMainWindow *m_owner;
115 const wxCursor *m_currentCursor;
116 const wxCursor *m_resizeCursor;
119 // column being resized
122 // divider line position in logical (unscrolled) coords
125 // minimal position beyond which the divider line can't be dragged in
129 wxArrayTreeListColumnInfo m_columns;
131 // total width of the columns
132 int m_total_col_width;
136 wxTreeListHeaderWindow();
138 wxTreeListHeaderWindow( wxWindow *win,
140 wxTreeListMainWindow *owner,
141 const wxPoint &pos = wxDefaultPosition,
142 const wxSize &size = wxDefaultSize,
144 const wxString &name = _T("wxtreelistctrlcolumntitles") );
146 virtual ~wxTreeListHeaderWindow();
148 void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
150 void AdjustDC(wxDC& dc);
152 void OnPaint( wxPaintEvent &event );
153 void OnMouse( wxMouseEvent &event );
154 void OnSetFocus( wxFocusEvent &event );
156 // total width of all columns
157 int GetWidth() const { return m_total_col_width; }
159 // column manipulation
160 int GetColumnCount() const { return m_columns.GetCount(); }
162 void AddColumn (const wxTreeListColumnInfo& colInfo);
164 void InsertColumn (int before, const wxTreeListColumnInfo& colInfo);
166 void RemoveColumn (int column);
168 // column information manipulation
169 const wxTreeListColumnInfo& GetColumn (int column) const{
170 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
171 wxInvalidTreeListColumnInfo, _T("Invalid column"));
172 return m_columns[column];
174 wxTreeListColumnInfo& GetColumn (int column) {
175 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
176 wxInvalidTreeListColumnInfo, _T("Invalid column"));
177 return m_columns[column];
179 void SetColumn (int column, const wxTreeListColumnInfo& info);
181 wxString GetColumnText (int column) const {
182 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
183 wxEmptyString, _T("Invalid column"));
184 return m_columns[column].GetText();
186 void SetColumnText (int column, const wxString& text) {
187 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
188 _T("Invalid column"));
189 m_columns[column].SetText (text);
192 int GetColumnAlignment (int column) const {
193 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
194 wxALIGN_LEFT, _T("Invalid column"));
195 return m_columns[column].GetAlignment();
197 void SetColumnAlignment (int column, int flag) {
198 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
199 _T("Invalid column"));
200 m_columns[column].SetAlignment (flag);
203 int GetColumnWidth (int column) const {
204 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
205 -1, _T("Invalid column"));
206 return m_columns[column].GetWidth();
208 void SetColumnWidth (int column, int width);
210 bool IsColumnEditable (int column) const {
211 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
212 false, _T("Invalid column"));
213 return m_columns[column].IsEditable();
216 bool IsColumnShown (int column) const {
217 wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
218 true, _T("Invalid column"));
219 return m_columns[column].IsShown();
226 // common part of all ctors
229 void SendListEvent(wxEventType type, wxPoint pos);
232 // DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow)
233 DECLARE_CLASS(wxTreeListHeaderWindow)
234 DECLARE_EVENT_TABLE()
238 // this is the "true" control
239 class wxTreeListMainWindow: public wxScrolledWindow
244 wxTreeListMainWindow() { Init(); }
246 wxTreeListMainWindow (wxTreeListCtrl *parent, wxWindowID id = -1,
247 const wxPoint& pos = wxDefaultPosition,
248 const wxSize& size = wxDefaultSize,
249 long style = wxTR_DEFAULT_STYLE,
250 const wxValidator &validator = wxDefaultValidator,
251 const wxString& name = _T("wxtreelistmainwindow"))
254 Create (parent, id, pos, size, style, validator, name);
257 virtual ~wxTreeListMainWindow();
259 bool Create(wxTreeListCtrl *parent, wxWindowID id = -1,
260 const wxPoint& pos = wxDefaultPosition,
261 const wxSize& size = wxDefaultSize,
262 long style = wxTR_DEFAULT_STYLE,
263 const wxValidator &validator = wxDefaultValidator,
264 const wxString& name = _T("wxtreelistctrl"));
269 // return true if this is a virtual list control
270 bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL); }
272 // get the total number of items in the control
273 size_t GetCount() const;
275 // indent is the number of pixels the children are indented relative to
276 // the parents position. SetIndent() also redraws the control
278 unsigned int GetIndent() const { return m_indent; }
279 void SetIndent(unsigned int indent);
281 // see wxTreeListCtrl for the meaning
282 unsigned int GetLineSpacing() const { return m_linespacing; }
283 void SetLineSpacing(unsigned int spacing);
285 // image list: these functions allow to associate an image list with
286 // the control and retrieve it. Note that when assigned with
287 // SetImageList, the control does _not_ delete
288 // the associated image list when it's deleted in order to allow image
289 // lists to be shared between different controls. If you use
290 // AssignImageList, the control _does_ delete the image list.
292 // The normal image list is for the icons which correspond to the
293 // normal tree item state (whether it is selected or not).
294 // Additionally, the application might choose to show a state icon
295 // which corresponds to an app-defined item state (for example,
296 // checked/unchecked) which are taken from the state image list.
297 wxImageList *GetImageList() const { return m_imageListNormal; }
298 wxImageList *GetStateImageList() const { return m_imageListState; }
299 wxImageList *GetButtonsImageList() const { return m_imageListButtons; }
301 void SetImageList(wxImageList *imageList);
302 void SetStateImageList(wxImageList *imageList);
303 void SetButtonsImageList(wxImageList *imageList);
304 void AssignImageList(wxImageList *imageList);
305 void AssignStateImageList(wxImageList *imageList);
306 void AssignButtonsImageList(wxImageList *imageList);
308 // Functions to work with tree ctrl items.
313 // retrieve item's label
314 wxString GetItemText (const wxTreeItemId& item) const
315 { return GetItemText (item, GetMainColumn()); }
316 wxString GetItemText (const wxTreeItemId& item, int column) const;
317 wxString GetItemText (wxTreeItemData* item, int column) const;
319 // get one of the images associated with the item (normal by default)
320 int GetItemImage (const wxTreeItemId& item,
321 wxTreeItemIcon which = wxTreeItemIcon_Normal) const
322 { return GetItemImage (item, GetMainColumn(), which); }
323 int GetItemImage (const wxTreeItemId& item, int column,
324 wxTreeItemIcon which = wxTreeItemIcon_Normal) const;
326 // get the data associated with the item
327 wxTreeItemData *GetItemData(const wxTreeItemId& item) const;
329 bool GetItemBold(const wxTreeItemId& item) const;
330 wxColour GetItemTextColour(const wxTreeItemId& item) const;
331 wxColour GetItemBackgroundColour(const wxTreeItemId& item) const;
332 wxFont GetItemFont(const wxTreeItemId& item) const;
338 void SetItemText (const wxTreeItemId& item, const wxString& text)
339 { SetItemText (item, GetMainColumn(), text); }
340 void SetItemText (const wxTreeItemId& item, int column, const wxString& text);
342 // get one of the images associated with the item (normal by default)
343 void SetItemImage (const wxTreeItemId& item, int image,
344 wxTreeItemIcon which = wxTreeItemIcon_Normal)
345 { SetItemImage (item, GetMainColumn(), image, which); }
346 void SetItemImage (const wxTreeItemId& item, int column, int image,
347 wxTreeItemIcon which = wxTreeItemIcon_Normal);
349 // associate some data with the item
350 void SetItemData(const wxTreeItemId& item, wxTreeItemData *data);
352 // force appearance of [+] button near the item. This is useful to
353 // allow the user to expand the items which don't have any children now
354 // - but instead add them only when needed, thus minimizing memory
355 // usage and loading time.
356 void SetItemHasChildren(const wxTreeItemId& item, bool has = true);
358 // the item will be shown in bold
359 void SetItemBold(const wxTreeItemId& item, bool bold = true);
361 // set the item's text colour
362 void SetItemTextColour(const wxTreeItemId& item, const wxColour& colour);
364 // set the item's background colour
365 void SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& colour);
367 // set the item's font (should be of the same height for all items)
368 void SetItemFont(const wxTreeItemId& item, const wxFont& font);
370 // set the window font
371 virtual bool SetFont( const wxFont &font );
373 // set the styles. No need to specify a GetWindowStyle here since
374 // the base wxWindow member function will do it for us
375 void SetWindowStyle(const long styles);
377 // item status inquiries
378 // ---------------------
380 // is the item visible (it might be outside the view or not expanded)?
381 bool IsVisible(const wxTreeItemId& item, bool fullRow) const;
382 // does the item has any children?
383 bool HasChildren(const wxTreeItemId& item) const;
384 // is the item expanded (only makes sense if HasChildren())?
385 bool IsExpanded(const wxTreeItemId& item) const;
386 // is this item currently selected (the same as has focus)?
387 bool IsSelected(const wxTreeItemId& item) const;
388 // is item text in bold font?
389 bool IsBold(const wxTreeItemId& item) const;
390 // does the layout include space for a button?
392 // number of children
393 // ------------------
395 // if 'recursively' is false, only immediate children count, otherwise
396 // the returned number is the number of all items in this branch
397 size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true);
402 // wxTreeItemId.IsOk() will return false if there is no such item
404 // get the root tree item
405 wxTreeItemId GetRootItem() const { return m_rootItem; }
407 // get the item currently selected, only if a single item is selected
408 // wxTreeItemId GetSelection() const { return m_selectItem; }
409 wxTreeItemId GetCurrent() const { return m_curItem; }
411 // get all the items currently selected, return count of items
412 size_t GetSelections(wxArrayTreeItemIds&) const;
414 // get the parent of this item (may return NULL if root)
415 wxTreeItemId GetItemParent(const wxTreeItemId& item) const;
417 // for this enumeration function you must pass in a "cookie" parameter
418 // which is opaque for the application but is necessary for the library
419 // to make these functions reentrant (i.e. allow more than one
420 // enumeration on one and the same object simultaneously). Of course,
421 // the "cookie" passed to GetFirstChild() and GetNextChild() should be
424 // get child of this item
425 #if !wxCHECK_VERSION(2, 5, 0)
426 wxTreeItemId GetFirstChild(const wxTreeItemId& item, long& cookie) const;
427 wxTreeItemId GetNextChild(const wxTreeItemId& item, long& cookie) const;
428 wxTreeItemId GetPrevChild(const wxTreeItemId& item, long& cookie) const;
429 wxTreeItemId GetLastChild(const wxTreeItemId& item, long& cookie) const;
431 wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
432 wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
433 wxTreeItemId GetPrevChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
434 wxTreeItemId GetLastChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
437 // get sibling of this item
438 wxTreeItemId GetNextSibling(const wxTreeItemId& item) const;
439 wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const;
441 // get item in the full tree (currently only for internal use)
442 wxTreeItemId GetNext(const wxTreeItemId& item, bool fulltree = true) const;
443 wxTreeItemId GetPrev(const wxTreeItemId& item, bool fulltree = true) const;
445 // get expanded item, see IsExpanded()
446 wxTreeItemId GetFirstExpandedItem() const;
447 wxTreeItemId GetNextExpanded(const wxTreeItemId& item) const;
448 wxTreeItemId GetPrevExpanded(const wxTreeItemId& item) const;
450 // get visible item, see IsVisible()
451 wxTreeItemId GetFirstVisibleItem(bool fullRow) const;
452 wxTreeItemId GetNextVisible(const wxTreeItemId& item, bool fullRow) const;
453 wxTreeItemId GetPrevVisible(const wxTreeItemId& item, bool fullRow) const;
458 // add the root node to the tree
459 wxTreeItemId AddRoot (const wxString& text,
460 int image = -1, int selectedImage = -1,
461 wxTreeItemData *data = NULL);
463 // insert a new item in as the first child of the parent
464 wxTreeItemId PrependItem(const wxTreeItemId& parent,
465 const wxString& text,
466 int image = -1, int selectedImage = -1,
467 wxTreeItemData *data = NULL);
469 // insert a new item after a given one
470 wxTreeItemId InsertItem(const wxTreeItemId& parent,
471 const wxTreeItemId& idPrevious,
472 const wxString& text,
473 int image = -1, int selectedImage = -1,
474 wxTreeItemData *data = NULL);
476 // insert a new item before the one with the given index
477 wxTreeItemId InsertItem(const wxTreeItemId& parent,
479 const wxString& text,
480 int image = -1, int selectedImage = -1,
481 wxTreeItemData *data = NULL);
483 // insert a new item in as the last child of the parent
484 wxTreeItemId AppendItem(const wxTreeItemId& parent,
485 const wxString& text,
486 int image = -1, int selectedImage = -1,
487 wxTreeItemData *data = NULL);
489 // delete this item and associated data if any
490 void Delete(const wxTreeItemId& item);
491 // delete all children (but don't delete the item itself)
492 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
493 void DeleteChildren(const wxTreeItemId& item);
494 // delete the root and all its children from the tree
495 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
499 void Expand(const wxTreeItemId& item);
500 // expand this item and all subitems recursively
501 void ExpandAll(const wxTreeItemId& item);
502 // collapse the item without removing its children
503 void Collapse(const wxTreeItemId& item);
504 // collapse the item and remove all children
505 void CollapseAndReset(const wxTreeItemId& item);
506 // toggles the current state
507 void Toggle(const wxTreeItemId& item);
509 // remove the selection from currently selected item (if any)
510 // void Unselect(wxTreeListItem* item);
514 void SelectItem(const wxTreeItemId& item, const wxTreeItemId& prev = (wxTreeItemId*)NULL,
515 bool unselect_others = true);
517 void RemoveFromSelection( wxTreeListItem *item );
518 void AddToSelection( wxTreeListItem *item );
520 // make sure this item is visible (expanding the parent item and/or
521 // scrolling to this item if necessary)
522 void EnsureVisible(const wxTreeItemId& item);
523 // scroll to this item (but don't expand its parent)
524 void ScrollTo(const wxTreeItemId& item);
525 void AdjustMyScrollbars();
527 // The first function is more portable (because easier to implement
528 // on other platforms), but the second one returns some extra info.
529 wxTreeItemId HitTest (const wxPoint& point)
530 { int flags; int column; return HitTest (point, flags, column); }
531 wxTreeItemId HitTest (const wxPoint& point, int& flags)
532 { int column; return HitTest (point, flags, column); }
533 wxTreeItemId HitTest (const wxPoint& point, int& flags, int& column);
536 // get the bounding rectangle of the item (or of its label only)
537 bool GetBoundingRect(const wxTreeItemId& item,
539 bool textOnly = false) const;
541 // Start editing the item label: this (temporarily) replaces the item
542 // with a one line edit control. The item will be selected if it hadn't
544 void EditLabel (const wxTreeItemId& item, int column);
547 // this function is called to compare 2 items and should return -1, 0
548 // or +1 if the first item is less than, equal to or greater than the
549 // second one. The base class version performs alphabetic comparaison
550 // of item labels (GetText)
551 virtual int OnCompareItems(const wxTreeItemId& item1,
552 const wxTreeItemId& item2);
553 // sort the children of this item using OnCompareItems
555 // NB: this function is not reentrant and not MT-safe (FIXME)!
556 void SortChildren(const wxTreeItemId& item);
559 wxTreeItemId FindItem (const wxTreeItemId& item, const wxString& str, int mode = 0);
561 // implementation only from now on
563 // overridden base class virtuals
564 virtual bool SetBackgroundColour(const wxColour& colour);
565 virtual bool SetForegroundColour(const wxColour& colour);
568 void SetDragItem (const wxTreeItemId& item = (wxTreeItemId*)NULL);
571 void OnPaint( wxPaintEvent &event );
572 void OnSetFocus( wxFocusEvent &event );
573 void OnKillFocus( wxFocusEvent &event );
574 void OnChar( wxKeyEvent &event );
575 void OnMouse( wxMouseEvent &event );
576 void OnIdle( wxIdleEvent &event );
577 void OnScroll(wxScrollWinEvent& event);
579 // implementation helpers
580 void SendDeleteEvent(wxTreeListItem *itemBeingDeleted);
582 int GetColumnCount() const
583 { return m_owner->GetHeaderWindow()->GetColumnCount(); }
585 void SetMainColumn (int column)
586 { if ((column >= 0) && (column < GetColumnCount())) m_main_column = column; }
588 int GetMainColumn() const { return m_main_column; }
590 int GetBestColumnWidth (int column, wxTreeItemId parent = wxTreeItemId());
591 int GetItemWidth (int column, wxTreeListItem *item);
592 wxFont GetItemFont (wxTreeListItem *item);
597 wxTreeListCtrl* m_owner;
601 friend class wxTreeListItem;
602 friend class wxTreeListRenameTimer;
603 friend class wxEditTextCtrl;
608 wxTreeListItem *m_rootItem; // root item
609 wxTreeListItem *m_curItem; // current item, either selected or marked
610 wxTreeListItem *m_shiftItem; // item, where the shift key was pressed
611 wxTreeListItem *m_editItem; // item, which is currently edited
612 // wxTreeListItem *m_selectItem; // current selected item, not with wxTR_MULTIPLE
614 wxArrayTreeListItems m_selected; // currently selected items
618 int m_btnWidth, m_btnWidth2;
619 int m_btnHeight, m_btnHeight2;
620 int m_imgWidth, m_imgWidth2;
621 int m_imgHeight, m_imgHeight2;
622 unsigned short m_indent;
624 unsigned short m_linespacing;
626 wxBrush *m_hilightBrush,
627 *m_hilightUnfocusedBrush;
632 bool m_ownsImageListNormal,
633 m_ownsImageListState,
634 m_ownsImageListButtons;
635 bool m_isDragging; // true between BEGIN/END drag events
637 bool m_lastOnSame; // last click on the same item as prev
638 bool m_left_down_selection;
640 wxImageList *m_imageListNormal,
645 wxTimer *m_dragTimer;
646 wxTreeListItem *m_dragItem;
648 wxTimer *m_renameTimer;
649 wxString m_renameRes;
652 wxTimer *m_findTimer;
655 // the common part of all ctors
659 wxTreeItemId DoInsertItem(const wxTreeItemId& parent,
661 const wxString& text,
662 int image, int selectedImage,
663 wxTreeItemData *data);
664 bool HasButtons(void) const
665 { return (m_imageListButtons) || HasFlag (wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); }
668 void CalculateLineHeight();
669 int GetLineHeight(wxTreeListItem *item) const;
670 void PaintLevel( wxTreeListItem *item, wxDC& dc, int level, int &y,
672 void PaintItem( wxTreeListItem *item, wxDC& dc);
674 void CalculateLevel( wxTreeListItem *item, wxDC &dc, int level, int &y,
676 void CalculatePositions();
677 void CalculateSize( wxTreeListItem *item, wxDC &dc );
679 void RefreshSubtree (wxTreeListItem *item);
680 void RefreshLine (wxTreeListItem *item);
682 // redraw all selected items
683 void RefreshSelected();
685 // RefreshSelected() recursive helper
686 void RefreshSelectedUnder (wxTreeListItem *item);
688 void OnRenameTimer();
689 void OnRenameAccept();
691 void FillArray(wxTreeListItem*, wxArrayTreeItemIds&) const;
692 bool SelectAllChildrenUntilLast (wxTreeListItem *crt_item, wxTreeListItem *last_item);
693 bool SelectNextChildren (wxTreeListItem *crt_item, wxTreeListItem *last_item);
694 // void UnselectAllChildren (wxTreeListItem *item );
697 DECLARE_EVENT_TABLE()
698 DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow)
702 // timer used for enabling in-place edit
703 class wxTreeListRenameTimer: public wxTimer
706 wxTreeListRenameTimer( wxTreeListMainWindow *owner );
711 wxTreeListMainWindow *m_owner;
714 // control used for in-place edit
715 class wxEditTextCtrl: public wxTextCtrl
718 wxEditTextCtrl (wxWindow *parent,
722 wxTreeListMainWindow *owner,
723 const wxString &value = wxEmptyString,
724 const wxPoint &pos = wxDefaultPosition,
725 const wxSize &size = wxDefaultSize,
727 const wxValidator& validator = wxDefaultValidator,
728 const wxString &name = wxTextCtrlNameStr );
730 void OnChar( wxKeyEvent &event );
731 void OnKeyUp( wxKeyEvent &event );
732 void OnKillFocus( wxFocusEvent &event );
737 wxTreeListMainWindow *m_owner;
738 wxString m_startValue;
741 DECLARE_EVENT_TABLE()
749 wxTreeListItem() { m_data = NULL; }
750 wxTreeListItem( wxTreeListMainWindow *owner,
751 wxTreeListItem *parent,
752 const wxArrayString& text,
755 wxTreeItemData *data );
760 wxArrayTreeListItems& GetChildren() { return m_children; }
762 const wxString GetText() const
766 const wxString GetText (int column) const
768 if(m_text.GetCount() > 0)
770 if( IsVirtual() ) return m_owner->GetItemText( m_data, column );
771 else return m_text[column];
773 return wxEmptyString;
776 int GetImage (wxTreeItemIcon which = wxTreeItemIcon_Normal) const
777 { return m_images[which]; }
778 int GetImage (int column, wxTreeItemIcon which=wxTreeItemIcon_Normal) const
780 if(column == m_owner->GetMainColumn()) return m_images[which];
781 if(column < (int)m_col_images.GetCount()) return m_col_images[column];
785 wxTreeItemData *GetData() const { return m_data; }
787 // returns the current image for the item (depending on its
788 // selected/expanded/whatever state)
789 int GetCurrentImage() const;
791 void SetText (const wxString &text );
792 void SetText (int column, const wxString& text)
794 if (column < (int)m_text.GetCount()) {
795 m_text[column] = text;
796 }else if (column < m_owner->GetColumnCount()) {
797 int howmany = m_owner->GetColumnCount();
798 for (int i = m_text.GetCount(); i < howmany; ++i) m_text.Add (wxEmptyString);
799 m_text[column] = text;
802 void SetImage (int image, wxTreeItemIcon which) { m_images[which] = image; }
803 void SetImage (int column, int image, wxTreeItemIcon which)
805 if (column == m_owner->GetMainColumn()) {
806 m_images[which] = image;
807 }else if (column < (int)m_col_images.GetCount()) {
808 m_col_images[column] = image;
809 }else if (column < m_owner->GetColumnCount()) {
810 int howmany = m_owner->GetColumnCount();
811 for (int i = m_col_images.GetCount(); i < howmany; ++i) m_col_images.Add (NO_IMAGE);
812 m_col_images[column] = image;
816 void SetData(wxTreeItemData *data) { m_data = data; }
818 void SetHasPlus(bool has = true) { m_hasPlus = has; }
820 void SetBold(bool bold) { m_isBold = bold; }
822 int GetX() const { return m_x; }
823 int GetY() const { return m_y; }
825 void SetX (int x) { m_x = x; }
826 void SetY (int y) { m_y = y; }
828 int GetHeight() const { return m_height; }
829 int GetWidth() const { return m_width; }
831 void SetHeight (int height) { m_height = height; }
832 void SetWidth (int width) { m_width = width; }
834 int GetTextX() const { return m_text_x; }
835 void SetTextX (int text_x) { m_text_x = text_x; }
837 wxTreeListItem *GetItemParent() const { return m_parent; }
840 // deletes all children notifying the treectrl about it if !NULL
842 void DeleteChildren(wxTreeListMainWindow *tree = NULL);
844 // get count of all children (and grand children if 'recursively')
845 size_t GetChildrenCount(bool recursively = true) const;
847 void Insert(wxTreeListItem *child, size_t index)
848 { m_children.Insert(child, index); }
850 void GetSize( int &x, int &y, const wxTreeListMainWindow* );
852 // return the item at given position (or NULL if no item), onButton is
853 // true if the point belongs to the item's button, otherwise it lies
854 // on the button's label
855 wxTreeListItem *HitTest (const wxPoint& point,
856 const wxTreeListMainWindow *,
857 int &flags, int& column, int level);
859 void Expand() { m_isCollapsed = false; }
860 void Collapse() { m_isCollapsed = true; }
862 void SetSelected( bool set = true ) { m_hasHilight = set; }
865 bool HasChildren() const { return !m_children.IsEmpty(); }
866 bool IsSelected() const { return m_hasHilight != 0; }
867 bool IsExpanded() const { return !m_isCollapsed; }
868 bool HasPlus() const { return m_hasPlus || HasChildren(); }
869 bool IsBold() const { return m_isBold != 0; }
870 bool IsVirtual() const { return m_owner->IsVirtual(); }
873 // get them - may be NULL
874 wxTreeItemAttr *GetAttributes() const { return m_attr; }
875 // get them ensuring that the pointer is not NULL
876 wxTreeItemAttr& Attr()
880 m_attr = new wxTreeItemAttr;
886 void SetAttributes(wxTreeItemAttr *attr)
888 if ( m_ownsAttr ) delete m_attr;
892 // set them and delete when done
893 void AssignAttributes(wxTreeItemAttr *attr)
900 wxTreeListMainWindow *m_owner; // control the item belongs to
902 // since there can be very many of these, we save size by chosing
903 // the smallest representation for the elements and by ordering
904 // the members to avoid padding.
905 wxArrayString m_text; // labels to be rendered for item
907 wxTreeItemData *m_data; // user-provided data
909 wxArrayTreeListItems m_children; // list of children
910 wxTreeListItem *m_parent; // parent of this item
912 wxTreeItemAttr *m_attr; // attributes???
914 // tree ctrl images for the normal, selected, expanded and
915 // expanded+selected states
916 short m_images[wxTreeItemIcon_Max];
917 wxArrayShort m_col_images; // images for the various columns (!= main)
919 // main column item positions
920 wxCoord m_x; // (virtual) offset from left (vertical line)
921 wxCoord m_y; // (virtual) offset from top
922 wxCoord m_text_x; // item offset from left
923 short m_width; // width of this item
924 unsigned char m_height; // height of this item
926 // use bitfields to save size
927 int m_isCollapsed :1;
928 int m_hasHilight :1; // same as focused
929 int m_hasPlus :1; // used for item which doesn't have
930 // children but has a [+] button
931 int m_isBold :1; // render the label in bold font
932 int m_ownsAttr :1; // delete attribute when done
935 // ===========================================================================
937 // ===========================================================================
939 // ---------------------------------------------------------------------------
940 // wxTreeListRenameTimer (internal)
941 // ---------------------------------------------------------------------------
943 wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow *owner )
948 void wxTreeListRenameTimer::Notify()
950 m_owner->OnRenameTimer();
953 //-----------------------------------------------------------------------------
954 // wxEditTextCtrl (internal)
955 //-----------------------------------------------------------------------------
957 BEGIN_EVENT_TABLE (wxEditTextCtrl,wxTextCtrl)
958 EVT_CHAR (wxEditTextCtrl::OnChar)
959 EVT_KEY_UP (wxEditTextCtrl::OnKeyUp)
960 EVT_KILL_FOCUS (wxEditTextCtrl::OnKillFocus)
963 wxEditTextCtrl::wxEditTextCtrl (wxWindow *parent,
967 wxTreeListMainWindow *owner,
968 const wxString &value,
972 const wxValidator& validator,
973 const wxString &name)
974 : wxTextCtrl (parent, id, value, pos, size, style|wxSIMPLE_BORDER, validator, name)
980 (*m_res) = wxEmptyString;
981 m_startValue = value;
985 void wxEditTextCtrl::OnChar( wxKeyEvent &event )
987 if (event.GetKeyCode() == WXK_RETURN)
990 (*m_res) = GetValue();
992 if ((*m_res) != m_startValue)
993 m_owner->OnRenameAccept();
995 if (!wxPendingDelete.Member(this))
996 wxPendingDelete.Append(this);
999 m_owner->SetFocus(); // This doesn't work. TODO.
1003 if (event.GetKeyCode() == WXK_ESCAPE)
1005 (*m_accept) = false;
1006 (*m_res) = wxEmptyString;
1008 if (!wxPendingDelete.Member(this))
1009 wxPendingDelete.Append(this);
1012 m_owner->SetFocus(); // This doesn't work. TODO.
1019 void wxEditTextCtrl::OnKeyUp( wxKeyEvent &event )
1027 // auto-grow the textctrl:
1028 wxSize parentSize = m_owner->GetSize();
1029 wxPoint myPos = GetPosition();
1030 wxSize mySize = GetSize();
1032 GetTextExtent(GetValue() + _T("M"), &sx, &sy);
1033 if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
1034 if (mySize.x > sx) sx = mySize.x;
1040 void wxEditTextCtrl::OnKillFocus( wxFocusEvent &event )
1048 if (!wxPendingDelete.Member(this))
1049 wxPendingDelete.Append(this);
1052 (*m_res) = GetValue();
1054 if ((*m_res) != m_startValue)
1055 m_owner->OnRenameAccept();
1058 //-----------------------------------------------------------------------------
1059 // wxTreeListHeaderWindow
1060 //-----------------------------------------------------------------------------
1065 //IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow,wxNotifyEvent);
1066 IMPLEMENT_CLASS(wxTreeListHeaderWindow,wxNotifyEvent);
1068 BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow)
1069 EVT_PAINT (wxTreeListHeaderWindow::OnPaint)
1070 EVT_MOUSE_EVENTS (wxTreeListHeaderWindow::OnMouse)
1071 EVT_SET_FOCUS (wxTreeListHeaderWindow::OnSetFocus)
1077 void wxTreeListHeaderWindow::Init()
1079 m_currentCursor = (wxCursor *) NULL;
1080 m_isDragging = false;
1082 m_total_col_width = 0;
1085 wxTreeListHeaderWindow::wxTreeListHeaderWindow()
1089 m_owner = (wxTreeListMainWindow *) NULL;
1090 m_resizeCursor = (wxCursor *) NULL;
1093 wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow *win,
1095 wxTreeListMainWindow *owner,
1099 const wxString &name )
1100 : wxWindow( win, id, pos, size, style, name )
1105 m_resizeCursor = new wxCursor(wxCURSOR_SIZEWE);
1107 #if !wxCHECK_VERSION(2, 5, 0)
1108 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNFACE));
1110 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE));
1114 wxTreeListHeaderWindow::~wxTreeListHeaderWindow()
1116 delete m_resizeCursor;
1119 void wxTreeListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
1121 #if !wxCHECK_VERSION(2, 5, 0)
1122 wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
1124 wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
1127 const int m_corner = 1;
1129 dc->SetBrush( *wxTRANSPARENT_BRUSH );
1130 #if defined( __WXMAC__ )
1133 dc->SetPen( *wxBLACK_PEN );
1135 dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer)
1136 dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer)
1138 #if defined( __WXMAC__ )
1139 wxPen pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
1142 dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner)
1143 dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner)
1145 dc->SetPen( *wxWHITE_PEN );
1146 dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer)
1147 dc->DrawRectangle( x, y, 1, h ); // left (outer)
1148 dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1149 dc->DrawLine( x+w-1, y, x+w-1, y+1 );
1152 // shift the DC origin to match the position of the main window horz
1153 // scrollbar: this allows us to always use logical coords
1154 void wxTreeListHeaderWindow::AdjustDC(wxDC& dc)
1157 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1159 m_owner->GetViewStart( &x, NULL );
1161 // account for the horz scrollbar offset
1162 dc.SetDeviceOrigin( -x * xpix, 0 );
1165 void wxTreeListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1168 wxClientDC dc( this );
1170 wxPaintDC dc( this );
1175 dc.SetFont( GetFont() );
1177 // width and height of the entire header window
1179 GetClientSize( &w, &h );
1180 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1181 dc.SetBackgroundMode(wxTRANSPARENT);
1183 // do *not* use the listctrl colour for headers - one day we will have a
1184 // function to set it separately
1185 //dc.SetTextForeground( *wxBLACK );
1186 #if !wxCHECK_VERSION(2, 5, 0)
1187 dc.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT ));
1189 dc.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ));
1192 int x = HEADER_OFFSET_X;
1194 int numColumns = GetColumnCount();
1195 for ( int i = 0; i < numColumns && x < w; i++ )
1197 if (!IsColumnShown (i)) continue; // do next colume if not shown
1199 wxTreeListColumnInfo& column = GetColumn(i);
1200 int wCol = column.GetWidth();
1202 // the width of the rect to draw: make it smaller to fit entirely
1203 // inside the column rect
1206 dc.SetPen( *wxWHITE_PEN );
1207 DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
1209 // if we have an image, draw it on the right of the label
1210 int image = column.GetImage(); //item.m_image;
1211 int ix = -2, iy = 0;
1212 wxImageList* imageList = m_owner->GetImageList();
1213 if ((image != -1) && imageList) {
1214 imageList->GetSize (image, ix, iy);
1217 // extra margins around the text label
1220 int image_offset = cw - ix - 1;
1222 switch(column.GetAlignment()) {
1224 text_x += EXTRA_WIDTH;
1228 dc.GetTextExtent (column.GetText(), &text_width, NULL);
1229 text_x += cw - text_width - EXTRA_WIDTH - MARGIN;
1232 case wxALIGN_CENTER:
1233 dc.GetTextExtent(column.GetText(), &text_width, NULL);
1234 text_x += (cw - text_width)/2 + ix + 2;
1235 image_offset = (cw - text_width - ix - 2)/2 - MARGIN;
1240 if ((image != -1) && imageList) {
1241 imageList->Draw (image, dc, x + image_offset/*cw - ix - 1*/,
1242 HEADER_OFFSET_Y + (h - 4 - iy)/2,
1243 wxIMAGELIST_DRAW_TRANSPARENT);
1246 // draw the text clipping it so that it doesn't overwrite the column boundary
1247 wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
1248 dc.DrawText (column.GetText(), text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT );
1254 int more_w = m_owner->GetSize().x - x - HEADER_OFFSET_X;
1256 DoDrawRect (&dc, x, HEADER_OFFSET_Y, more_w, h-2 );
1261 void wxTreeListHeaderWindow::DrawCurrent()
1263 int x1 = m_currentX;
1265 ClientToScreen (&x1, &y1);
1267 int x2 = m_currentX-1;
1269 ++x2; // but why ????
1272 m_owner->GetClientSize( NULL, &y2 );
1273 m_owner->ClientToScreen( &x2, &y2 );
1276 dc.SetLogicalFunction (wxINVERT);
1277 dc.SetPen (wxPen (*wxBLACK, 2, wxSOLID));
1278 dc.SetBrush (*wxTRANSPARENT_BRUSH);
1281 dc.DrawLine (x1, y1, x2, y2);
1282 dc.SetLogicalFunction (wxCOPY);
1283 dc.SetPen (wxNullPen);
1284 dc.SetBrush (wxNullBrush);
1287 void wxTreeListHeaderWindow::OnMouse (wxMouseEvent &event) {
1289 // we want to work with logical coords
1291 m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1292 int y = event.GetY();
1296 SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
1298 // we don't draw the line beyond our window, but we allow dragging it
1301 GetClientSize( &w, NULL );
1302 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1305 // erase the line if it was drawn
1306 if (m_currentX < w) DrawCurrent();
1308 if (event.ButtonUp()) {
1309 m_isDragging = false;
1310 if (HasCapture()) ReleaseMouse();
1312 SetColumnWidth (m_column, m_currentX - m_minX);
1314 SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
1316 m_currentX = wxMax (m_minX + 7, x);
1318 // draw in the new location
1319 if (m_currentX < w) DrawCurrent();
1322 }else{ // not dragging
1325 bool hit_border = false;
1327 // end of the current column
1330 // find the column where this event occured
1331 int countCol = GetColumnCount();
1332 for (int column = 0; column < countCol; column++) {
1333 if (!IsColumnShown (column)) continue; // do next if not shown
1335 xpos += GetColumnWidth (column);
1337 if ((abs (x-xpos) < 3) && (y < 22)) {
1338 // near the column border
1344 // inside the column
1351 if (event.LeftDown() || event.RightUp()) {
1352 if (hit_border && event.LeftDown()) {
1353 m_isDragging = true;
1357 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition());
1358 }else{ // click on a column
1359 wxEventType evt = event.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK:
1360 wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
1361 SendListEvent (evt, event.GetPosition());
1363 }else if (event.LeftDClick() && hit_border) {
1364 SetColumnWidth (m_column, m_owner->GetBestColumnWidth (m_column));
1367 }else if (event.Moving()) {
1370 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
1371 m_currentCursor = m_resizeCursor;
1373 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
1374 m_currentCursor = wxSTANDARD_CURSOR;
1376 if (setCursor) SetCursor (*m_currentCursor);
1382 void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent &WXUNUSED(event)) {
1383 m_owner->SetFocus();
1386 void wxTreeListHeaderWindow::SendListEvent (wxEventType type, wxPoint pos) {
1387 wxWindow *parent = GetParent();
1388 wxListEvent le (type, parent->GetId());
1389 le.SetEventObject (parent);
1390 le.m_pointDrag = pos;
1392 // the position should be relative to the parent window, not
1393 // this one for compatibility with MSW and common sense: the
1394 // user code doesn't know anything at all about this header
1395 // window, so why should it get positions relative to it?
1396 le.m_pointDrag.y -= GetSize().y;
1397 le.m_col = m_column;
1398 parent->GetEventHandler()->ProcessEvent (le);
1401 void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo& colInfo) {
1402 m_columns.Add (colInfo);
1403 m_total_col_width += colInfo.GetWidth();
1404 m_owner->AdjustMyScrollbars();
1405 m_owner->m_dirty = true;
1408 void wxTreeListHeaderWindow::SetColumnWidth (int column, int width) {
1409 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1410 m_total_col_width -= m_columns[column].GetWidth();
1411 m_columns[column].SetWidth(width);
1412 m_total_col_width += width;
1413 m_owner->AdjustMyScrollbars();
1414 m_owner->m_dirty = true;
1417 void wxTreeListHeaderWindow::InsertColumn (int before, const wxTreeListColumnInfo& colInfo) {
1418 wxCHECK_RET ((before >= 0) && (before < GetColumnCount()), _T("Invalid column"));
1419 m_columns.Insert (colInfo, before);
1420 m_total_col_width += colInfo.GetWidth();
1421 m_owner->AdjustMyScrollbars();
1422 m_owner->m_dirty = true;
1425 void wxTreeListHeaderWindow::RemoveColumn (int column) {
1426 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1427 m_total_col_width -= m_columns[column].GetWidth();
1428 m_columns.RemoveAt (column);
1429 m_owner->AdjustMyScrollbars();
1430 m_owner->m_dirty = true;
1433 void wxTreeListHeaderWindow::SetColumn (int column, const wxTreeListColumnInfo& info) {
1434 wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1435 int w = m_columns[column].GetWidth();
1436 m_columns[column] = info;
1437 if (w != info.GetWidth()) {
1438 m_total_col_width += info.GetWidth() - w;
1439 m_owner->AdjustMyScrollbars();
1441 m_owner->m_dirty = true;
1444 // ---------------------------------------------------------------------------
1446 // ---------------------------------------------------------------------------
1448 wxTreeListItem::wxTreeListItem (wxTreeListMainWindow *owner,
1449 wxTreeListItem *parent,
1450 const wxArrayString& text,
1451 int image, int selImage,
1452 wxTreeItemData *data)
1455 m_images[wxTreeItemIcon_Normal] = image;
1456 m_images[wxTreeItemIcon_Selected] = selImage;
1457 m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
1458 m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
1465 m_isCollapsed = true;
1466 m_hasHilight = false;
1473 m_attr = (wxTreeItemAttr *)NULL;
1476 // We don't know the height here yet.
1481 wxTreeListItem::~wxTreeListItem() {
1483 if (m_ownsAttr) delete m_attr;
1485 wxASSERT_MSG( m_children.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1488 void wxTreeListItem::DeleteChildren (wxTreeListMainWindow *tree) {
1489 size_t count = m_children.Count();
1490 for (size_t n = 0; n < count; n++) {
1491 wxTreeListItem *child = m_children[n];
1493 tree->SendDeleteEvent (child);
1495 tree->RemoveFromSelection(child);
1497 if (child->IsSelected())
1499 tree->Unselect(child);
1502 // if (tree->m_selectItem == child) tree->m_selectItem = (wxTreeListItem*)NULL;
1504 child->DeleteChildren (tree);
1510 void wxTreeListItem::SetText (const wxString &text) {
1511 if (m_text.GetCount() > 0) {
1518 size_t wxTreeListItem::GetChildrenCount (bool recursively) const {
1519 size_t count = m_children.Count();
1520 if (!recursively) return count;
1522 size_t total = count;
1523 for (size_t n = 0; n < count; ++n) {
1524 total += m_children[n]->GetChildrenCount();
1529 void wxTreeListItem::GetSize (int &x, int &y, const wxTreeListMainWindow *theButton) {
1530 int bottomY = m_y + theButton->GetLineHeight (this);
1531 if (y < bottomY) y = bottomY;
1532 int width = m_x + m_width;
1533 if ( x < width ) x = width;
1536 size_t count = m_children.Count();
1537 for (size_t n = 0; n < count; ++n ) {
1538 m_children[n]->GetSize (x, y, theButton);
1543 wxTreeListItem *wxTreeListItem::HitTest (const wxPoint& point,
1544 const wxTreeListMainWindow *theCtrl,
1545 int &flags, int& column, int level) {
1547 // for a hidden root node, don't evaluate it, but do evaluate children
1548 if (!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) {
1550 // reset any previous hit infos
1553 wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow();
1555 // check for right of all columns (outside)
1556 if (point.x > header_win->GetWidth()) return (wxTreeListItem*) NULL;
1558 // evaluate if y-pos is okay
1559 int h = theCtrl->GetLineHeight (this);
1560 if ((point.y >= m_y) && (point.y <= m_y + h)) {
1562 int maincol = theCtrl->GetMainColumn();
1564 // check for above/below middle
1565 int y_mid = m_y + h/2;
1566 if (point.y < y_mid) {
1567 flags |= wxTREE_HITTEST_ONITEMUPPERPART;
1569 flags |= wxTREE_HITTEST_ONITEMLOWERPART;
1572 // check for button hit
1573 if (HasPlus() && theCtrl->HasButtons()) {
1574 int bntX = m_x - theCtrl->m_btnWidth2;
1575 int bntY = y_mid - theCtrl->m_btnHeight2;
1576 if ((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) &&
1577 (point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) {
1578 flags |= wxTREE_HITTEST_ONITEMBUTTON;
1584 // check for image hit
1585 if (theCtrl->m_imgWidth > 0) {
1586 int imgX = m_text_x - theCtrl->m_imgWidth - MARGIN;
1587 int imgY = y_mid - theCtrl->m_imgHeight2;
1588 if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) &&
1589 (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) {
1590 flags |= wxTREE_HITTEST_ONITEMICON;
1596 // check for label hit
1597 if ((point.x >= m_text_x) && (point.x <= (m_text_x + m_width))) {
1598 flags |= wxTREE_HITTEST_ONITEMLABEL;
1603 // check for indent hit after button and image hit
1604 if (point.x < m_x) {
1605 flags |= wxTREE_HITTEST_ONITEMINDENT;
1606 column = -1; // considered not belonging to main column
1610 // check for right of label
1612 for (int i = 0; i <= maincol; ++i) end += header_win->GetColumnWidth (i);
1613 if ((point.x > (m_text_x + m_width)) && (point.x <= end)) {
1614 flags |= wxTREE_HITTEST_ONITEMRIGHT;
1615 column = -1; // considered not belonging to main column
1619 // else check for each column except main
1621 for (int j = 0; j < theCtrl->GetColumnCount(); ++j) {
1622 if (!header_win->IsColumnShown(j)) continue;
1623 int w = header_win->GetColumnWidth (j);
1624 if ((j != maincol) && (point.x >= x && point.x < x+w)) {
1625 flags |= wxTREE_HITTEST_ONITEMCOLUMN;
1632 // no special flag or column found
1637 // if children not expanded, return no item
1638 if (!IsExpanded()) return (wxTreeListItem*) NULL;
1641 // in any case evaluate children
1642 wxTreeListItem *child;
1643 size_t count = m_children.Count();
1644 for (size_t n = 0; n < count; n++) {
1645 child = m_children[n]->HitTest (point, theCtrl, flags, column, level+1);
1646 if (child) return child;
1650 return (wxTreeListItem*) NULL;
1653 int wxTreeListItem::GetCurrentImage() const {
1654 int image = NO_IMAGE;
1657 image = GetImage (wxTreeItemIcon_SelectedExpanded);
1659 image = GetImage (wxTreeItemIcon_Expanded);
1661 }else{ // not expanded
1663 image = GetImage (wxTreeItemIcon_Selected);
1665 image = GetImage (wxTreeItemIcon_Normal);
1669 // maybe it doesn't have the specific image, try the default one instead
1670 if (image == NO_IMAGE) image = GetImage();
1675 // ---------------------------------------------------------------------------
1676 // wxTreeListMainWindow implementation
1677 // ---------------------------------------------------------------------------
1679 IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow)
1681 BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow)
1682 EVT_PAINT (wxTreeListMainWindow::OnPaint)
1683 EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse)
1684 EVT_CHAR (wxTreeListMainWindow::OnChar)
1685 EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus)
1686 EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus)
1687 EVT_IDLE (wxTreeListMainWindow::OnIdle)
1688 EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll)
1692 // ---------------------------------------------------------------------------
1693 // construction/destruction
1694 // ---------------------------------------------------------------------------
1696 void wxTreeListMainWindow::Init() {
1698 m_rootItem = (wxTreeListItem*)NULL;
1699 m_curItem = (wxTreeListItem*)NULL;
1700 m_shiftItem = (wxTreeListItem*)NULL;
1701 m_editItem = (wxTreeListItem*)NULL;
1703 // m_selectItem = (wxTreeListItem*)NULL;
1705 m_curColumn = -1; // no current column
1710 m_lineHeight = LINEHEIGHT;
1711 m_indent = MININDENT; // min. indent
1714 #if !wxCHECK_VERSION(2, 5, 0)
1715 m_hilightBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1716 m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1718 m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1719 m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1722 m_imageListNormal = (wxImageList *) NULL;
1723 m_imageListButtons = (wxImageList *) NULL;
1724 m_imageListState = (wxImageList *) NULL;
1725 m_ownsImageListNormal = m_ownsImageListButtons =
1726 m_ownsImageListState = false;
1728 m_imgWidth = 0, m_imgWidth2 = 0;
1729 m_imgHeight = 0, m_imgHeight2 = 0;
1730 m_btnWidth = 0, m_btnWidth2 = 0;
1731 m_btnHeight = 0, m_btnHeight2 = 0;
1734 m_isDragging = false;
1735 m_dragTimer = new wxTimer (this, -1);
1736 m_dragItem = (wxTreeListItem*)NULL;
1738 m_renameTimer = new wxTreeListRenameTimer (this);
1739 m_lastOnSame = false;
1740 m_left_down_selection = false;
1742 m_findTimer = new wxTimer (this, -1);
1744 #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
1745 m_normalFont.MacCreateThemeFont (kThemeViewsFont);
1747 m_normalFont = wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT);
1749 m_boldFont = wxFont( m_normalFont.GetPointSize(),
1750 m_normalFont.GetFamily(),
1751 m_normalFont.GetStyle(),
1753 m_normalFont.GetUnderlined(),
1754 m_normalFont.GetFaceName(),
1755 m_normalFont.GetEncoding());
1758 bool wxTreeListMainWindow::Create (wxTreeListCtrl *parent,
1763 const wxValidator &validator,
1764 const wxString& name) {
1767 if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS;
1768 if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS;
1769 style &= ~wxTR_LINES_AT_ROOT;
1770 style |= wxTR_NO_LINES;
1773 wxGetOsVersion( &major, &minor );
1774 if (major < 10) style |= wxTR_ROW_LINES;
1777 wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
1779 #if wxUSE_VALIDATORS
1780 SetValidator(validator);
1783 #if !wxCHECK_VERSION(2, 5, 0)
1784 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX));
1786 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX));
1794 bdc.SelectObject(bmp);
1795 bdc.SetPen(*wxGREY_PEN);
1796 bdc.DrawRectangle(-1, -1, 10, 10);
1797 for (i = 0; i < 8; i++) {
1798 for (j = 0; j < 8; j++) {
1799 if (!((i + j) & 1)) {
1800 bdc.DrawPoint(i, j);
1805 m_dottedPen = wxPen(bmp, 1);
1808 //? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86
1809 m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
1818 wxTreeListMainWindow::~wxTreeListMainWindow() {
1819 delete m_hilightBrush;
1820 delete m_hilightUnfocusedBrush;
1823 delete m_renameTimer;
1825 if (m_ownsImageListNormal) delete m_imageListNormal;
1826 if (m_ownsImageListState) delete m_imageListState;
1827 if (m_ownsImageListButtons) delete m_imageListButtons;
1833 //-----------------------------------------------------------------------------
1835 //-----------------------------------------------------------------------------
1837 size_t wxTreeListMainWindow::GetCount() const {
1838 return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount();
1841 void wxTreeListMainWindow::SetIndent (unsigned int indent) {
1842 m_indent = wxMax (MININDENT, indent);
1846 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) {
1847 m_linespacing = spacing;
1849 CalculateLineHeight();
1852 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item,
1854 wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item"));
1855 return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively);
1858 void wxTreeListMainWindow::SetWindowStyle (const long styles) {
1859 // right now, just sets the styles. Eventually, we may
1860 // want to update the inherited styles, but right now
1861 // none of the parents has updatable styles
1862 m_windowStyle = styles;
1866 //-----------------------------------------------------------------------------
1867 // functions to work with tree items
1868 //-----------------------------------------------------------------------------
1870 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column,
1871 wxTreeItemIcon which) const {
1872 wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item"));
1873 return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which);
1876 wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const {
1877 wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
1878 return ((wxTreeListItem*) item.m_pItem)->GetData();
1881 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const {
1882 wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
1883 return ((wxTreeListItem *)item.m_pItem)->IsBold();
1886 wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const {
1887 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1888 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1889 return pItem->Attr().GetTextColour();
1892 wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const {
1893 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1894 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1895 return pItem->Attr().GetBackgroundColour();
1898 wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const {
1899 wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
1900 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1901 return pItem->Attr().GetFont();
1904 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column,
1905 int image, wxTreeItemIcon which) {
1906 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1907 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1908 pItem->SetImage (column, image, which);
1909 wxClientDC dc (this);
1910 CalculateSize (pItem, dc);
1911 RefreshLine (pItem);
1914 void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item,
1915 wxTreeItemData *data) {
1916 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1917 ((wxTreeListItem*) item.m_pItem)->SetData(data);
1920 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item,
1922 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1923 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1924 pItem->SetHasPlus (has);
1925 RefreshLine (pItem);
1928 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, bool bold) {
1929 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1930 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1931 if (pItem->IsBold() != bold) { // avoid redrawing if no real change
1932 pItem->SetBold (bold);
1933 RefreshLine (pItem);
1937 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item,
1938 const wxColour& colour) {
1939 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1940 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1941 pItem->Attr().SetTextColour (colour);
1942 RefreshLine (pItem);
1945 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item,
1946 const wxColour& colour) {
1947 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1948 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1949 pItem->Attr().SetBackgroundColour (colour);
1950 RefreshLine (pItem);
1953 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item,
1954 const wxFont& font) {
1955 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1956 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1957 pItem->Attr().SetFont (font);
1958 RefreshLine (pItem);
1961 bool wxTreeListMainWindow::SetFont (const wxFont &font) {
1962 wxScrolledWindow::SetFont (font);
1963 m_normalFont = font;
1964 m_boldFont = wxFont (m_normalFont.GetPointSize(),
1965 m_normalFont.GetFamily(),
1966 m_normalFont.GetStyle(),
1968 m_normalFont.GetUnderlined(),
1969 m_normalFont.GetFaceName());
1970 CalculateLineHeight();
1975 // ----------------------------------------------------------------------------
1976 // item status inquiries
1977 // ----------------------------------------------------------------------------
1979 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow) const {
1980 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
1982 // An item is only visible if it's not a descendant of a collapsed item
1983 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1984 wxTreeListItem* parent = pItem->GetItemParent();
1986 if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break;
1987 if (!parent->IsExpanded()) return false;
1988 parent = parent->GetItemParent();
1991 wxSize clientSize = GetClientSize();
1993 if ((!GetBoundingRect (item, rect)) ||
1994 ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
1995 (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y) ||
1996 (!fullRow && (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x))) return false;
2001 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const {
2002 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2004 // consider that the item does have children if it has the "+" button: it
2005 // might not have them (if it had never been expanded yet) but then it
2006 // could have them as well and it's better to err on this side rather than
2007 // disabling some operations which are restricted to the items with
2008 // children for an item which does have them
2009 return ((wxTreeListItem*) item.m_pItem)->HasPlus();
2012 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const {
2013 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2014 return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
2017 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const {
2018 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2019 return ((wxTreeListItem*) item.m_pItem)->IsSelected();
2022 bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item) const {
2023 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2024 return ((wxTreeListItem*) item.m_pItem)->IsBold();
2027 // ----------------------------------------------------------------------------
2029 // ----------------------------------------------------------------------------
2031 wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const {
2032 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2033 return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
2036 #if !wxCHECK_VERSION(2, 5, 0)
2037 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2038 long& cookie) const {
2040 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2041 wxTreeItemIdValue& cookie) const {
2043 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2044 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2046 return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId();
2049 #if !wxCHECK_VERSION(2, 5, 0)
2050 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2051 long& cookie) const {
2053 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2054 wxTreeItemIdValue& cookie) const {
2056 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2057 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2058 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2059 long *pIndex = ((long*)&cookie);
2060 return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId();
2063 #if !wxCHECK_VERSION(2, 5, 0)
2064 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2065 long& cookie) const {
2067 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2068 wxTreeItemIdValue& cookie) const {
2070 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2071 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2072 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2073 long *pIndex = (long*)&cookie;
2074 return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId();
2077 #if !wxCHECK_VERSION(2, 5, 0)
2078 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2079 long& cookie) const {
2081 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2082 wxTreeItemIdValue& cookie) const {
2084 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2085 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2086 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2087 long *pIndex = ((long*)&cookie);
2088 (*pIndex) = children.Count();
2089 return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId();
2092 wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const {
2093 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2096 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2097 wxTreeListItem *parent = i->GetItemParent();
2098 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2101 wxArrayTreeListItems& siblings = parent->GetChildren();
2102 size_t index = siblings.Index (i);
2103 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2104 return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId();
2107 wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const {
2108 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2111 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2112 wxTreeListItem *parent = i->GetItemParent();
2113 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2116 wxArrayTreeListItems& siblings = parent->GetChildren();
2117 size_t index = siblings.Index(i);
2118 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2119 return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId();
2122 // Only for internal use right now, but should probably be public
2123 wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const {
2124 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2126 // if there are any children, return first child
2127 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2128 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2129 if (children.GetCount() > 0) return children.Item (0);
2132 // get sibling of this item or of the ancestors instead
2134 wxTreeItemId parent = item;
2136 next = GetNextSibling (parent);
2137 parent = GetItemParent (parent);
2138 } while (!next.IsOk() && parent.IsOk());
2142 // Only for internal use right now, but should probably be public
2143 wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const {
2144 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2146 // if there are any children, return last child
2147 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2148 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2149 if (children.GetCount() > 0) return children.Item (children.GetCount()-1);
2152 // get sibling of this item or of the ancestors instead
2154 wxTreeItemId parent = item;
2156 next = GetPrevSibling (parent);
2157 parent = GetItemParent (parent);
2158 } while (!next.IsOk() && parent.IsOk());
2162 wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
2163 return GetNextExpanded (GetRootItem());
2166 wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const {
2167 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2168 return GetNext (item, false);
2171 wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const {
2172 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2173 return GetPrev (item, false);
2176 wxTreeItemId wxTreeListMainWindow::GetFirstVisibleItem (bool fullRow) const {
2177 return GetNextVisible (GetRootItem(), fullRow);
2180 wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow) const {
2181 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2182 wxTreeItemId id = GetNext (item, false);
2184 if (IsVisible (id, fullRow)) return id;
2185 id = GetNext (id, false);
2187 return wxTreeItemId();
2190 wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow) const {
2191 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2192 wxTreeItemId id = GetPrev (item, true);
2194 if (IsVisible (id, fullRow)) return id;
2195 id = GetPrev(id, true);
2197 return wxTreeItemId();
2200 // ----------------------------------------------------------------------------
2202 // ----------------------------------------------------------------------------
2204 wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId,
2206 const wxString& text,
2207 int image, int selImage,
2208 wxTreeItemData *data) {
2209 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2210 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2211 m_dirty = true; // do this first so stuff below doesn't cause flicker
2214 arr.Alloc (GetColumnCount());
2215 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2216 arr[m_main_column] = text;
2217 wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data);
2219 #if !wxCHECK_VERSION(2, 5, 0)
2220 data->SetId ((long)item);
2225 parent->Insert (item, previous);
2230 wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text,
2231 int image, int selImage,
2232 wxTreeItemData *data) {
2233 wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
2234 wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2235 m_dirty = true; // do this first so stuff below doesn't cause flicker
2238 arr.Alloc (GetColumnCount());
2239 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2240 arr[m_main_column] = text;
2241 m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data);
2243 #if !wxCHECK_VERSION(2, 5, 0)
2244 data->SetId((long)m_rootItem);
2246 data->SetId(m_rootItem);
2249 if (HasFlag(wxTR_HIDE_ROOT)) {
2250 // if we will hide the root, make sure children are visible
2251 m_rootItem->SetHasPlus();
2252 m_rootItem->Expand();
2253 #if !wxCHECK_VERSION(2, 5, 0)
2256 wxTreeItemIdValue cookie = 0;
2258 m_curItem = (wxTreeListItem*)GetFirstChild (m_rootItem, cookie).m_pItem;
2263 wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent,
2264 const wxString& text,
2265 int image, int selImage,
2266 wxTreeItemData *data) {
2267 return DoInsertItem (parent, 0u, text, image, selImage, data);
2270 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2271 const wxTreeItemId& idPrevious,
2272 const wxString& text,
2273 int image, int selImage,
2274 wxTreeItemData *data) {
2275 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2276 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2278 int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
2279 wxASSERT_MSG( index != wxNOT_FOUND,
2280 _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
2282 return DoInsertItem (parentId, ++index, text, image, selImage, data);
2285 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2287 const wxString& text,
2288 int image, int selImage,
2289 wxTreeItemData *data) {
2290 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2291 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2293 return DoInsertItem (parentId, before, text, image, selImage, data);
2296 wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId,
2297 const wxString& text,
2298 int image, int selImage,
2299 wxTreeItemData *data) {
2300 wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
2301 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2303 return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data);
2306 void wxTreeListMainWindow::SendDeleteEvent (wxTreeListItem *item) {
2307 // send event to user code
2308 wxTreeEvent event (wxEVT_COMMAND_TREE_DELETE_ITEM, m_owner->GetId());
2309 #if !wxCHECK_VERSION(2, 5, 0)
2310 event.SetItem ((long)item);
2312 event.SetItem (item);
2314 event.SetEventObject (m_owner);
2315 m_owner->ProcessEvent (event);
2318 void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
2319 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2320 wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
2321 m_dirty = true; // do this first so stuff below doesn't cause flicker
2323 // don't stay with invalid m_shiftItem or we will crash in the next call to OnChar()
2324 bool changeKeyCurrent = false;
2325 wxTreeListItem *itemKey = m_shiftItem;
2327 if (itemKey == item) { // m_shiftItem is a descendant of the item being deleted
2328 changeKeyCurrent = true;
2331 itemKey = itemKey->GetItemParent();
2334 wxTreeListItem *parent = item->GetItemParent();
2336 parent->GetChildren().Remove (item); // remove by value
2338 if (changeKeyCurrent) m_shiftItem = parent;
2340 SendDeleteEvent (item);
2342 RemoveFromSelection(item);
2343 // if (item->IsSelected()) Unselect(item);
2344 //if (m_selectItem == item) m_selectItem = (wxTreeListItem*)NULL;
2345 item->DeleteChildren (this);
2349 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
2350 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2351 m_dirty = true; // do this first so stuff below doesn't cause flicker
2353 item->DeleteChildren (this);
2356 void wxTreeListMainWindow::DeleteRoot() {
2359 SendDeleteEvent (m_rootItem);
2360 m_curItem = (wxTreeListItem*)NULL;
2362 // m_selectItem= (wxTreeListItem*)NULL;
2364 m_rootItem->DeleteChildren (this);
2370 void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
2371 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2372 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
2374 if (!item->HasPlus() || item->IsExpanded()) return;
2376 // send event to user code
2377 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_EXPANDING, m_owner->GetId());
2378 #if !wxCHECK_VERSION(2, 5, 0)
2379 event.SetItem ((long)item);
2381 event.SetItem (item);
2383 event.SetEventObject (m_owner);
2384 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // expand canceled
2389 // send event to user code
2390 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
2391 m_owner->ProcessEvent (event);
2394 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
2396 if (!IsExpanded (itemId)) return;
2397 #if !wxCHECK_VERSION(2, 5, 0)
2400 wxTreeItemIdValue cookie;
2402 wxTreeItemId child = GetFirstChild (itemId, cookie);
2403 while (child.IsOk()) {
2405 child = GetNextChild (itemId, cookie);
2409 void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
2410 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2411 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
2413 if (!item->HasPlus() || !item->IsExpanded()) return;
2415 // send event to user code
2416 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, m_owner->GetId() );
2417 #if !wxCHECK_VERSION(2, 5, 0)
2418 event.SetItem ((long)item);
2420 event.SetItem (item);
2422 event.SetEventObject (m_owner);
2423 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // collapse canceled
2428 // send event to user code
2429 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
2430 ProcessEvent (event);
2433 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
2435 DeleteChildren (item);
2438 void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
2439 if (IsExpanded (itemId)) {
2446 void wxTreeListMainWindow::Unselect() {
2448 m_selectItem->SetHilight (false);
2449 RefreshLine (m_selectItem);
2450 m_selectItem = (wxTreeListItem*)NULL;
2454 // LG 19/09/08 : Added
2456 void wxTreeListMainWindow::Unselect(wxTreeListItem* item)
2458 if (item->IsSelected()) {
2459 item->SetSelected (false);
2461 m_selected.Remove(item);
2462 // LG : TODO : Remove from array
2463 // if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
2468 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
2469 if (item->IsSelected()) {
2470 item->SetHilight (false);
2472 if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
2474 if (item->HasChildren()) {
2475 wxArrayTreeListItems& children = item->GetChildren();
2476 size_t count = children.Count();
2477 for (size_t n = 0; n < count; ++n) {
2478 UnselectAllChildren (children[n]);
2483 void wxTreeListMainWindow::UnselectAll() {
2485 size_t count = m_selected.Count();
2486 for (size_t n = 0; n < count; ++n)
2488 m_selected[n]->SetSelected (false);
2489 RefreshLine (m_selected[n]);
2493 //UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
2496 // Recursive function !
2497 // To stop we must have crt_item<last_item
2499 // Tag all next children, when no more children,
2500 // Move to parent (not to tag)
2501 // Keep going... if we found last_item, we stop.
2502 bool wxTreeListMainWindow::SelectNextChildren (wxTreeListItem *crt_item,
2503 wxTreeListItem *last_item) {
2504 wxTreeListItem *parent = crt_item->GetItemParent();
2506 if (!parent) {// This is root item
2507 return SelectAllChildrenUntilLast (crt_item, last_item);
2510 wxArrayTreeListItems& children = parent->GetChildren();
2511 int index = children.Index(crt_item);
2512 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2514 if ((parent->HasChildren() && parent->IsExpanded()) ||
2515 ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
2516 size_t count = children.Count();
2517 for (size_t n = (index+1); n < count; ++n) {
2518 if (SelectAllChildrenUntilLast (children[n], last_item)) return true;
2522 return SelectNextChildren (parent, last_item);
2525 bool wxTreeListMainWindow::SelectAllChildrenUntilLast (wxTreeListItem *crt_item,
2526 wxTreeListItem *last_item) {
2527 if (!crt_item->IsSelected())
2529 // LG : Send event to user to know is selection is accepted
2530 // send event to the user code
2531 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId() );
2532 #if !wxCHECK_VERSION(2, 5, 0)
2533 event.SetItem ((long)crt_item);
2535 event.SetItem (crt_item);
2537 event.SetEventObject (m_owner);
2538 if (m_owner->GetEventHandler()->ProcessEvent (event) && event.IsAllowed())
2540 AddToSelection(crt_item);
2544 if (crt_item==last_item) return true;
2546 if (crt_item->HasChildren() && crt_item->IsExpanded()) {
2547 wxArrayTreeListItems& children = crt_item->GetChildren();
2548 size_t count = children.Count();
2549 for (size_t n = 0; n < count; ++n) {
2550 if (SelectAllChildrenUntilLast (children[n], last_item)) return true;
2557 void wxTreeListMainWindow::RemoveFromSelection( wxTreeListItem *item )
2559 if (!item->IsSelected()) return;
2560 item->SetSelected(false);
2561 m_selected.Remove(item);
2565 void wxTreeListMainWindow::AddToSelection( wxTreeListItem *item )
2567 if (item->IsSelected()) return;
2568 item->SetSelected(true);
2569 m_selected.Add(item);
2573 void wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
2574 const wxTreeItemId& lastId,
2575 bool unselect_others) {
2576 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item") );
2578 bool is_single = !HasFlag(wxTR_MULTIPLE);
2579 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2582 // single selection requires unselect others
2583 if (is_single) unselect_others = true;
2585 // unselect all if unselect other items
2586 bool unselected = false; // see that UnselectAll is done only once
2587 if (unselect_others) {
2590 Unselect(); // to speed up thing
2598 // LG : Update current item
2599 wxTreeListItem *old_curItem = m_curItem;
2601 if (old_curItem) RefreshLine (old_curItem);
2603 // select item or item range
2604 if (lastId.IsOk() && (itemId != lastId))
2608 if (!unselected) UnselectAll();
2609 wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
2611 // LG : Update current item
2612 // wxTreeListItem *old_curItem = m_curItem;
2613 // m_curItem = last;
2614 // if (old_curItem) RefreshLine (old_curItem);
2616 // ensure that the position of the item it calculated in any case
2617 if (m_dirty) CalculatePositions();
2619 // select item range according Y-position
2620 if (last->GetY() < item->GetY()) {
2621 if (!SelectAllChildrenUntilLast (last, item)) {
2622 SelectNextChildren (last, item);
2625 if (!SelectAllChildrenUntilLast (item, last)) {
2626 SelectNextChildren (item, last);
2634 // send event to the user code
2635 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId() );
2636 #if !wxCHECK_VERSION(2, 5, 0)
2637 event.SetItem ((long)item);
2638 event.SetOldItem ((long)m_curItem);
2640 event.SetItem (item);
2641 event.SetOldItem (m_curItem);
2643 event.SetEventObject (m_owner);
2647 if (m_owner->GetEventHandler()->ProcessEvent (event) &&
2650 // select item according its old selection
2651 if (item->IsSelected())
2652 RemoveFromSelection(item);
2654 AddToSelection(item);
2658 // send event to user code
2659 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGED, m_owner->GetId() );
2660 m_owner->GetEventHandler()->ProcessEvent (event);
2663 void wxTreeListMainWindow::SelectAll() {
2664 wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
2666 #if !wxCHECK_VERSION(2, 5, 0)
2669 wxTreeItemIdValue cookie = 0;
2671 wxTreeItemId root = GetRootItem();
2672 wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
2673 wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
2674 if (!SelectAllChildrenUntilLast (first, last)) {
2675 SelectNextChildren (first, last);
2678 // send event to user code
2679 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGED, m_owner->GetId() );
2680 m_owner->GetEventHandler()->ProcessEvent (event);
2683 void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
2684 wxArrayTreeItemIds &array) const {
2685 if (item->IsSelected()) array.Add (wxTreeItemId(item));
2687 if (item->HasChildren()) {
2688 wxArrayTreeListItems& children = item->GetChildren();
2689 size_t count = children.GetCount();
2690 for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
2694 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
2696 LG : NOT OK AS IS NOT IN TREE ORDER
2698 size_t count = m_selected.GetCount();
2699 for (size_t n = 0; n < count; ++n) array.Add(m_selected[n]);
2701 wxTreeItemId idRoot = GetRootItem();
2702 if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
2703 return array.Count();
2706 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
2707 if (!item.IsOk()) return; // do nothing if no item
2709 // first expand all parent branches
2710 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2711 wxTreeListItem *parent = gitem->GetItemParent();
2714 parent = parent->GetItemParent();
2718 RefreshLine (gitem);
2721 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
2722 if (!item.IsOk()) return; // do nothing if no item
2724 // ensure that the position of the item it calculated in any case
2725 if (m_dirty) CalculatePositions();
2727 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2729 // now scroll to the item
2730 int item_y = gitem->GetY();
2733 GetScrollPixelsPerUnit (&xUnit, &yUnit);
2736 GetViewStart (&start_x, &start_y);
2741 GetClientSize (&client_w, &client_h);
2745 m_rootItem->GetSize (x, y, this);
2746 x = m_owner->GetHeaderWindow()->GetWidth();
2747 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2748 int x_pos = GetScrollPos( wxHORIZONTAL );
2750 if (item_y < start_y+3) {
2751 // going down, item should appear at top
2752 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
2753 }else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
2754 // going up, item should appear at bottom
2755 item_y += yUnit + 2;
2756 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
2760 // FIXME: tree sorting functions are not reentrant and not MT-safe!
2761 static wxTreeListMainWindow *s_treeBeingSorted = NULL;
2763 static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1,
2764 wxTreeListItem **item2)
2766 wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
2768 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
2771 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1,
2772 const wxTreeItemId& item2)
2774 return m_owner->OnCompareItems (item1, item2);
2777 void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId) {
2778 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
2780 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2782 wxCHECK_RET (!s_treeBeingSorted,
2783 _T("wxTreeListMainWindow::SortChildren is not reentrant") );
2785 wxArrayTreeListItems& children = item->GetChildren();
2786 if ( children.Count() > 1 ) {
2788 s_treeBeingSorted = this;
2789 children.Sort(tree_ctrl_compare_func);
2790 s_treeBeingSorted = NULL;
2794 wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, const wxString& str, int mode) {
2796 // determine start item
2797 wxTreeItemId next = item;
2799 if (mode & wxTL_MODE_NAV_LEVEL) {
2800 next = GetNextSibling (next);
2801 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2802 next = GetNextVisible (next, false);
2803 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2804 next = GetNextExpanded (next);
2805 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2806 next = GetNext (next, true);
2810 #if !wxCHECK_VERSION(2, 5, 0)
2813 wxTreeItemIdValue cookie = 0;
2816 next = (wxTreeListItem*)GetRootItem().m_pItem;
2817 if (HasFlag(wxTR_HIDE_ROOT)) {
2818 next = (wxTreeListItem*)GetFirstChild (GetRootItem().m_pItem, cookie).m_pItem;
2821 if (!next.IsOk()) return (wxTreeItemId*)NULL;
2823 // start checking the next items
2824 while (next.IsOk() && (next != item)) {
2825 if (mode & wxTL_MODE_FIND_PARTIAL) {
2826 itemText = GetItemText (next).Mid (0, str.Length());
2828 itemText = GetItemText (next);
2830 if (mode & wxTL_MODE_FIND_NOCASE) {
2831 if (itemText.CmpNoCase (str) == 0) return next;
2833 if (itemText.Cmp (str) == 0) return next;
2835 if (mode & wxTL_MODE_NAV_LEVEL) {
2836 next = GetNextSibling (next);
2837 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2838 next = GetNextVisible (next, false);
2839 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2840 next = GetNextExpanded (next);
2841 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2842 next = GetNext (next, true);
2844 if (!next.IsOk() && item.IsOk()) {
2845 next = (wxTreeListItem*)GetRootItem().m_pItem;
2846 if (HasFlag(wxTR_HIDE_ROOT)) {
2847 next = (wxTreeListItem*)GetNextChild (GetRootItem().m_pItem, cookie).m_pItem;
2851 return (wxTreeItemId*)NULL;
2854 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
2855 wxTreeListItem *prevItem = m_dragItem;
2856 m_dragItem = (wxTreeListItem*) item.m_pItem;
2857 if (prevItem) RefreshLine (prevItem);
2858 if (m_dragItem) RefreshLine (m_dragItem);
2861 void wxTreeListMainWindow::CalculateLineHeight() {
2862 wxClientDC dc (this);
2863 dc.SetFont (m_normalFont);
2864 m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
2866 if (m_imageListNormal) {
2867 // Calculate a m_lineHeight value from the normal Image sizes.
2868 // May be toggle off. Then wxTreeListMainWindow will spread when
2869 // necessary (which might look ugly).
2870 int n = m_imageListNormal->GetImageCount();
2871 for (int i = 0; i < n ; i++) {
2872 int width = 0, height = 0;
2873 m_imageListNormal->GetSize(i, width, height);
2874 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
2878 if (m_imageListButtons) {
2879 // Calculate a m_lineHeight value from the Button image sizes.
2880 // May be toggle off. Then wxTreeListMainWindow will spread when
2881 // necessary (which might look ugly).
2882 int n = m_imageListButtons->GetImageCount();
2883 for (int i = 0; i < n ; i++) {
2884 int width = 0, height = 0;
2885 m_imageListButtons->GetSize(i, width, height);
2886 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
2890 if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
2891 m_lineHeight += 2; // minimal 2 pixel space
2893 m_lineHeight += m_lineHeight / 10; // otherwise 10% space
2897 void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
2898 if (m_ownsImageListNormal) delete m_imageListNormal;
2899 m_imageListNormal = imageList;
2900 m_ownsImageListNormal = false;
2902 CalculateLineHeight();
2905 void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
2906 if (m_ownsImageListState) delete m_imageListState;
2907 m_imageListState = imageList;
2908 m_ownsImageListState = false;
2911 void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
2912 if (m_ownsImageListButtons) delete m_imageListButtons;
2913 m_imageListButtons = imageList;
2914 m_ownsImageListButtons = false;
2916 CalculateLineHeight();
2919 void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
2920 SetImageList(imageList);
2921 m_ownsImageListNormal = true;
2924 void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
2925 SetStateImageList(imageList);
2926 m_ownsImageListState = true;
2929 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
2930 SetButtonsImageList(imageList);
2931 m_ownsImageListButtons = true;
2934 // ----------------------------------------------------------------------------
2936 // ----------------------------------------------------------------------------
2938 void wxTreeListMainWindow::AdjustMyScrollbars() {
2941 GetScrollPixelsPerUnit (&xUnit, &yUnit);
2942 if (xUnit == 0) xUnit = GetCharWidth();
2943 if (yUnit == 0) yUnit = m_lineHeight;
2945 m_rootItem->GetSize (x, y, this);
2946 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2947 int x_pos = GetScrollPos (wxHORIZONTAL);
2948 int y_pos = GetScrollPos (wxVERTICAL);
2949 x = m_owner->GetHeaderWindow()->GetWidth() + 2;
2950 if (x < GetClientSize().GetWidth()) x_pos = 0;
2951 SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
2953 SetScrollbars (0, 0, 0, 0);
2957 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
2958 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
2959 return item->GetHeight();
2961 return m_lineHeight;
2965 void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
2967 wxTreeItemAttr *attr = item->GetAttributes();
2969 dc.SetFont (GetItemFont (item));
2972 if (attr && attr->HasTextColour()) {
2973 colText = attr->GetTextColour();
2975 colText = GetForegroundColour();
2977 #if !wxCHECK_VERSION(2, 5, 0)
2978 wxColour colTextHilight = wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2980 wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2983 int total_w = m_owner->GetHeaderWindow()->GetWidth();
2984 int total_h = GetLineHeight(item);
2985 int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
2986 // std::cout << "off_h="<<off_h<<std::endl;
2988 wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
2990 int text_w = 0, text_h = 0;
2991 dc.GetTextExtent( item->GetText(GetMainColumn()), &text_w, &text_h );
2993 // determine background and show it
2995 if (attr && attr->HasBackgroundColour()) {
2996 colBg = attr->GetBackgroundColour();
2998 colBg = m_backgroundColour;
3000 dc.SetBrush (wxBrush (colBg, wxSOLID));
3001 dc.SetPen (*wxTRANSPARENT_PEN);
3002 if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3003 if (item == m_dragItem) {
3004 dc.SetBrush (*m_hilightBrush);
3005 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3006 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3007 #endif // !__WXMAC__
3008 dc.SetTextForeground (colTextHilight);
3009 }else if (item->IsSelected()) {
3010 if (!m_isDragging && m_hasFocus) {
3011 dc.SetBrush (*m_hilightBrush);
3012 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3013 // LG : dc.SetPen (*wxBLACK_PEN);
3014 dc.SetPen (*wxTRANSPARENT_PEN);
3015 #endif // !__WXMAC__
3017 dc.SetBrush (*m_hilightUnfocusedBrush);
3018 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3019 dc.SetPen (*wxTRANSPARENT_PEN);
3020 #endif // !__WXMAC__
3022 dc.SetTextForeground (colTextHilight);
3025 else if (item == m_curItem) {
3026 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3029 dc.SetTextForeground (colText);
3032 dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
3034 dc.SetTextForeground (colText);
3037 int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
3038 int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
3040 for (int i = 0; i < GetColumnCount(); ++i ) {
3041 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3043 int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
3044 wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
3047 int image = NO_IMAGE;
3049 if(i == GetMainColumn()) {
3050 x = item->GetX() + MARGIN;
3052 x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
3056 if (m_imageListNormal) image = item->GetCurrentImage();
3058 x = x_colstart + MARGIN;
3059 image = item->GetImage(i);
3061 if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
3063 // honor text alignment
3064 wxString text = item->GetText(i);
3066 switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
3068 // nothing to do, already left aligned
3071 dc.GetTextExtent (text, &text_w, NULL);
3072 w = col_w - (image_w + text_w + MARGIN);
3075 case wxALIGN_CENTER:
3076 dc.GetTextExtent(text, &text_w, NULL);
3077 w = (col_w - (image_w + text_w + MARGIN))/2;
3081 int text_x = x + image_w;
3082 if (i == GetMainColumn()) item->SetTextX (text_x);
3084 if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3085 if (i == GetMainColumn()) {
3086 if (item == m_dragItem) {
3087 dc.SetBrush (*m_hilightBrush);
3088 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3089 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3090 #endif // !__WXMAC__
3091 dc.SetTextForeground (colTextHilight);
3092 }else if (item->IsSelected()) {
3093 if (!m_isDragging && m_hasFocus) {
3094 dc.SetBrush (*m_hilightBrush);
3095 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3096 dc.SetPen (*wxBLACK_PEN);
3097 #endif // !__WXMAC__
3099 dc.SetBrush (*m_hilightUnfocusedBrush);
3100 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3101 dc.SetPen (*wxTRANSPARENT_PEN);
3102 #endif // !__WXMAC__
3104 dc.SetTextForeground (colTextHilight);
3107 else if (item == m_curItem) {
3108 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3111 dc.SetTextForeground (colText);
3113 dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3115 dc.SetTextForeground (colText);
3119 dc.SetBackgroundMode (wxTRANSPARENT);
3121 if (image != NO_IMAGE) {
3122 int y = item->GetY() + img_extraH;
3123 m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3125 int text_y = item->GetY() + text_extraH;
3126 dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
3128 x_colstart += col_w;
3131 // restore normal font
3132 dc.SetFont( m_normalFont );
3135 // Now y stands for the top of the item, whereas it used to stand for middle !
3136 void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
3137 int level, int &y, int x_maincol) {
3139 // Handle hide root (only level 0)
3142 //if (HasFlag(wxTR_HIDE_ROOT) && (level < nth)) {
3143 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
3145 wxArrayTreeListItems& children = item->GetChildren();
3146 for (size_t n = 0; n < children.Count(); n++) {
3147 PaintLevel (children[n], dc, 1, y, x_maincol);
3149 // end after expanding root
3153 // calculate position of vertical lines
3154 int x = x_maincol + MARGIN; // start of column
3155 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
3157 x += (m_btnWidth-m_btnWidth2); // half button space
3159 x += (m_indent-m_indent/2);
3161 if (HasFlag(wxTR_HIDE_ROOT)) {
3163 // x += m_indent * (level-nth); // indent but not level 1
3164 x += m_indent * (level-1); // indent but not level 1
3167 x += m_indent * level; // indent according to level
3170 // set position of vertical line
3174 int h = GetLineHeight (item);
3176 int y_mid = y_top + (h/2);
3179 int exposed_x = dc.LogicalToDeviceX(0);
3180 int exposed_y = dc.LogicalToDeviceY(y_top);
3182 if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
3184 if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
3185 //dc.DestroyClippingRegion();
3186 int total_width = m_owner->GetHeaderWindow()->GetWidth();
3187 // if the background colour is white, choose a
3188 // contrasting color for the lines
3189 dc.SetPen (*((GetBackgroundColour() == *wxWHITE)?
3190 wxMEDIUM_GREY_PEN : wxWHITE_PEN));
3191 dc.DrawLine(0, y_top, total_width, y_top);
3192 dc.DrawLine(0, y_top+h, total_width, y_top+h);
3196 PaintItem (item, dc);
3198 // restore DC objects
3199 dc.SetBrush(*wxWHITE_BRUSH);
3200 dc.SetPen(m_dottedPen);
3202 // clip to the column width
3203 int clip_width = m_owner->GetHeaderWindow()->
3204 GetColumn(m_main_column).GetWidth();
3205 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3207 if (!HasFlag(wxTR_NO_LINES)) { // connection lines
3209 // draw the horizontal line here
3210 dc.SetPen(m_dottedPen);
3211 int x2 = x - m_indent;
3212 if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
3213 int x3 = x + (m_btnWidth-m_btnWidth2);
3215 if (item->HasPlus()) {
3216 dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
3217 dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
3219 dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
3222 dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
3226 if (item->HasPlus() && HasButtons()) { // should the item show a button?
3228 if (m_imageListButtons) {
3230 // draw the image button here
3231 int image = wxTreeItemIcon_Normal;
3232 if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
3233 if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
3234 int xx = x - m_btnWidth2 + MARGIN;
3235 int yy = y_mid - m_btnHeight2;
3236 dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
3237 m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
3238 dc.DestroyClippingRegion();
3240 }else if (HasFlag (wxTR_TWIST_BUTTONS)) {
3242 // draw the twisty button here
3243 dc.SetPen(*wxBLACK_PEN);
3244 dc.SetBrush(*m_hilightBrush);
3246 if (item->IsExpanded()) {
3247 button[0].x = x - (m_btnWidth2+1);
3248 button[0].y = y_mid - (m_btnHeight/3);
3249 button[1].x = x + (m_btnWidth2+1);
3250 button[1].y = button[0].y;
3252 button[2].y = button[0].y + (m_btnHeight2+1);
3254 button[0].x = x - (m_btnWidth/3);
3255 button[0].y = y_mid - (m_btnHeight2+1);
3256 button[1].x = button[0].x;
3257 button[1].y = y_mid + (m_btnHeight2+1);
3258 button[2].x = button[0].x + (m_btnWidth2+1);
3259 button[2].y = y_mid;
3261 dc.DrawPolygon(3, button);
3263 }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3265 // draw the plus sign here
3266 dc.SetPen(*wxGREY_PEN);
3267 dc.SetBrush(*wxWHITE_BRUSH);
3268 dc.DrawRectangle (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3269 dc.SetPen(*wxBLACK_PEN);
3270 dc.DrawLine (x-(m_btnWidth2-2), y_mid, x+(m_btnWidth2-1), y_mid);
3271 if (!item->IsExpanded()) { // change "-" to "+"
3272 dc.DrawLine (x, y_mid-(m_btnHeight2-2), x, y_mid+(m_btnHeight2-1));
3281 // restore DC objects
3282 dc.SetBrush(*wxWHITE_BRUSH);
3283 dc.SetPen(m_dottedPen);
3284 dc.SetTextForeground(*wxBLACK);
3286 if (item->IsExpanded())
3288 wxArrayTreeListItems& children = item->GetChildren();
3290 // clip to the column width
3291 int clip_width = m_owner->GetHeaderWindow()->
3292 GetColumn(m_main_column).GetWidth();
3294 // process lower levels
3296 if (m_imgWidth > 0) {
3297 oldY = y_mid + m_imgHeight2;
3302 for (size_t n = 0; n < children.Count(); ++n) {
3305 PaintLevel (children[n], dc, level+1, y, x_maincol);
3307 // draw vertical line
3308 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3309 if (!HasFlag (wxTR_NO_LINES)) {
3311 dc.DrawLine (x, oldY, x, y2);
3319 // ----------------------------------------------------------------------------
3320 // wxWindows callbacks
3321 // ----------------------------------------------------------------------------
3323 void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
3325 wxPaintDC dc (this);
3328 if (!m_rootItem || (GetColumnCount() <= 0)) return;
3330 // calculate button size
3331 if (m_imageListButtons) {
3332 m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
3333 }else if (HasButtons()) {
3334 m_btnWidth = BTNWIDTH;
3335 m_btnHeight = BTNHEIGHT;
3337 m_btnWidth2 = m_btnWidth/2;
3338 m_btnHeight2 = m_btnHeight/2;
3340 // calculate image size
3341 if (m_imageListNormal) {
3342 m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
3344 m_imgWidth2 = m_imgWidth/2;
3345 m_imgHeight2 = m_imgHeight/2;
3347 // calculate indent size
3348 if (m_imageListButtons) {
3349 m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
3350 }else if (HasButtons()) {
3351 m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
3354 // set default values
3355 dc.SetFont( m_normalFont );
3356 dc.SetPen( m_dottedPen );
3358 // calculate column start and paint
3361 for (i = 0; i < (int)GetMainColumn(); ++i) {
3362 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3363 x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
3366 PaintLevel (m_rootItem, dc, 0, y, x_maincol);
3369 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
3373 if (m_curItem) RefreshLine (m_curItem);
3377 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
3381 if (m_curItem) RefreshLine (m_curItem);
3385 void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
3386 // send event to user code
3387 wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, m_owner->GetId());
3388 nevent.SetKeyEvent (event);
3389 nevent.SetEventObject (m_owner);
3390 if (m_owner->GetEventHandler()->ProcessEvent (nevent)) return; // handled in user code
3392 // determine first current if none
3393 bool curItemSet = false;
3395 m_curItem = (wxTreeListItem*)GetRootItem().m_pItem;
3396 if (HasFlag(wxTR_HIDE_ROOT)) {
3397 #if !wxCHECK_VERSION(2, 5, 0)
3400 wxTreeItemIdValue cookie = 0;
3402 m_curItem = (wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem;
3406 if (!m_curItem) return; // do nothing if empty tree
3408 // remember item at shift down
3409 if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
3410 if (!m_shiftItem) m_shiftItem = m_curItem;
3412 m_shiftItem = (wxTreeListItem*)NULL;
3415 // process all cases
3416 wxTreeItemId newItem = (wxTreeItemId*)NULL;
3417 switch (event.GetKeyCode()) {
3419 // '+': Expand subtree
3422 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
3425 // '-': collapse subtree
3427 case WXK_SUBTRACT: {
3428 if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
3431 // '*': expand/collapse all subtrees // TODO: Mak it more useful
3433 case WXK_MULTIPLY: {
3434 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3435 ExpandAll (m_curItem);
3436 }else if (m_curItem->HasPlus()) {
3437 Collapse (m_curItem); // TODO: CollapseAll
3441 // ' ': toggle current item
3443 SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
3446 // <RETURN>: activate current item
3448 wxTreeEvent aevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
3449 #if !wxCHECK_VERSION(2, 5, 0)
3450 aevent.SetItem ((long)m_curItem);
3452 aevent.SetItem (m_curItem);
3454 aevent.SetEventObject (m_owner);
3455 m_owner->GetEventHandler()->ProcessEvent (aevent);
3458 // <BKSP>: go to the parent without collapsing
3460 newItem = GetItemParent (m_curItem);
3461 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3462 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
3466 // <UP>: go to the previous sibling or to the last of its children, to the parent
3468 newItem = GetPrevSibling (m_curItem);
3470 #if !wxCHECK_VERSION(2, 5, 0)
3473 wxTreeItemIdValue cookie = 0;
3475 while (IsExpanded (newItem) && HasChildren (newItem)) {
3476 newItem = GetLastChild (newItem, cookie);
3479 newItem = GetItemParent (m_curItem);
3480 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3481 newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
3486 // <LEFT>: if expanded collapse subtree, else go to the parent
3488 if (IsExpanded (m_curItem)) {
3489 Collapse (m_curItem);
3491 newItem = GetItemParent (m_curItem);
3492 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3493 newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
3498 // <RIGHT>: if possible expand subtree, else go go to the first child
3500 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3503 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3504 #if !wxCHECK_VERSION(2, 5, 0)
3507 wxTreeItemIdValue cookie = 0;
3509 newItem = GetFirstChild (m_curItem, cookie);
3514 // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3517 newItem = m_curItem;
3519 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3520 #if !wxCHECK_VERSION(2, 5, 0)
3523 wxTreeItemIdValue cookie = 0;
3525 newItem = GetFirstChild( m_curItem, cookie );
3528 wxTreeItemId parent = m_curItem;
3530 newItem = GetNextSibling (parent);
3531 parent = GetItemParent (parent);
3532 } while (!newItem && parent);
3537 // <END>: go to last item of the root
3539 #if !wxCHECK_VERSION(2, 5, 0)
3542 wxTreeItemIdValue cookie = 0;
3544 newItem = GetLastChild (GetRootItem(), cookie);
3547 // <HOME>: go to root
3549 newItem = GetRootItem();
3550 if (HasFlag(wxTR_HIDE_ROOT)) {
3551 #if !wxCHECK_VERSION(2, 5, 0)
3554 wxTreeItemIdValue cookie = 0;
3556 newItem = GetFirstChild (newItem, cookie);
3560 // any char: go to the next matching string
3562 if (event.GetKeyCode() >= (int)' ') {
3563 if (!m_findTimer->IsRunning()) m_findStr.Clear();
3564 m_findStr.Append (event.GetKeyCode());
3565 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
3566 wxTreeItemId prev = m_curItem? (wxTreeItemId*)m_curItem: (wxTreeItemId*)NULL;
3568 newItem = FindItem (prev, m_findStr, wxTL_MODE_NAV_EXPANDED |
3569 wxTL_MODE_FIND_PARTIAL |
3570 wxTL_MODE_FIND_NOCASE);
3571 if (newItem || (m_findStr.Length() <= 1)) break;
3572 m_findStr.RemoveLast();
3579 // select and show the new item
3581 if (!event.ControlDown()) {
3582 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3583 HasFlag(wxTR_MULTIPLE));
3584 SelectItem (newItem, m_shiftItem, unselect_others);
3586 EnsureVisible (newItem);
3587 wxTreeListItem *oldItem = m_curItem;
3588 m_curItem = (wxTreeListItem*)newItem.m_pItem; // make the new item the current item
3589 RefreshLine (oldItem);
3594 wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
3600 if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
3601 if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
3602 if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
3603 if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
3604 if (flags) return wxTreeItemId();
3607 flags = wxTREE_HITTEST_NOWHERE;
3609 return wxTreeItemId();
3612 wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
3613 this, flags, column, 0);
3615 flags = wxTREE_HITTEST_NOWHERE;
3617 return wxTreeItemId();
3622 // get the bounding rectangle of the item (or of its label only)
3623 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
3624 bool WXUNUSED(textOnly)) const {
3625 wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
3627 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
3630 GetScrollPixelsPerUnit (&xUnit, &yUnit);
3632 GetViewStart(& startX, & startY);
3634 rect.x = item->GetX() - startX * xUnit;
3635 rect.y = item->GetY() - startY * yUnit;
3636 rect.width = item->GetWidth();
3637 rect.height = GetLineHeight (item);
3644 void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
3645 if (!item.IsOk()) return;
3646 if (!((column >= 0) && (column < GetColumnCount()))) return;
3648 m_editItem = (wxTreeListItem*) item.m_pItem;
3650 wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, m_owner->GetId() );
3651 #if !wxCHECK_VERSION(2, 5, 0)
3652 te.SetItem ((long)m_editItem);
3654 te.SetItem (m_editItem);
3657 te.SetEventObject (m_owner );
3658 m_owner->GetEventHandler()->ProcessEvent (te);
3660 if (!te.IsAllowed()) return;
3662 // ensure that the position of the item it calculated in any case
3663 if (m_dirty) CalculatePositions();
3665 wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
3667 int y = m_editItem->GetY() + 1; // wxTextCtrl needs 1 pixels above the text
3669 int h = m_editItem->GetHeight();
3671 if (column == GetMainColumn()) {
3672 x += m_editItem->GetTextX() - 2; // wxTextCtrl needs 2 pixels before the text
3673 w = wxMin (m_editItem->GetWidth(), m_owner->GetHeaderWindow()->GetWidth() - x);
3675 for (int i = 0; i < column; ++i) x += header_win->GetColumnWidth (i); // start of column
3676 switch (header_win->GetColumnAlignment (column)) {
3677 case wxALIGN_LEFT: {style = wxTE_LEFT; break;}
3678 case wxALIGN_RIGHT: {style = wxTE_RIGHT; break;}
3679 case wxALIGN_CENTER: {style = wxTE_CENTER; break;}
3681 w = header_win->GetColumnWidth (column); // width of column
3684 wxClientDC dc (this);
3686 x = dc.LogicalToDeviceX (x);
3687 y = dc.LogicalToDeviceY (y);
3689 wxEditTextCtrl *text = new wxEditTextCtrl (this, -1, &m_renameAccept, &m_renameRes,
3690 this, m_editItem->GetText (column),
3691 wxPoint (x, y), wxSize (w, h), style);
3695 void wxTreeListMainWindow::OnRenameTimer() {
3696 EditLabel (m_curItem, m_curColumn);
3699 void wxTreeListMainWindow::OnRenameAccept() {
3701 // TODO if the validator fails this causes a crash
3702 wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, m_owner->GetId() );
3703 #if !wxCHECK_VERSION(2, 5, 0)
3704 le.SetItem((long)m_editItem);
3706 le.SetItem(m_editItem);
3708 le.SetEventObject( /*this*/m_owner );
3709 le.SetLabel( m_renameRes );
3710 m_owner->GetEventHandler()->ProcessEvent( le );
3712 if (!le.IsAllowed()) return;
3714 SetItemText (m_editItem, m_curColumn, m_renameRes);
3717 void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
3718 if (!m_rootItem) return;
3720 // we process left mouse up event (enables in-place edit), right down
3721 // (pass to the user code), left dbl click (activate item) and
3722 // dragging/moving events for items drag-and-drop
3723 if (!(event.LeftDown() ||
3725 event.RightDown() ||
3727 event.LeftDClick() ||
3729 (event.GetWheelRotation() != 0 )/*? TODO ||
3730 event.Moving()?*/)) {
3731 m_owner->GetEventHandler()->ProcessEvent (event);
3735 // set focus if window clicked
3736 if (event.LeftDown() || event.RightDown()) SetFocus();
3739 wxPoint p = wxPoint (event.GetX(), event.GetY());
3741 wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
3742 this, flags, m_curColumn, 0);
3744 // we only process dragging here
3745 if (event.Dragging()){
3746 if (m_isDragging) return; // nothing to do, already done
3747 if (item == NULL) return; // we need an item to dragging
3749 // determine drag start
3750 if (m_dragCount == 0) {
3751 m_dragTimer->Start (DRAG_TIMER_TICKS, wxTIMER_ONE_SHOT);
3754 if (m_dragCount < 3) return; // minimum drag 3 pixel
3755 if (m_dragTimer->IsRunning()) return;
3757 // we're going to drag
3759 m_isDragging = true;
3763 // send drag start event
3764 wxEventType command = event.LeftIsDown()
3765 ? wxEVT_COMMAND_TREE_BEGIN_DRAG
3766 : wxEVT_COMMAND_TREE_BEGIN_RDRAG;
3767 wxTreeEvent nevent (command, m_owner->GetId());
3768 nevent.SetEventObject (m_owner);
3769 #if !wxCHECK_VERSION(2, 5, 0)
3770 nevent.SetItem ((long)item); // the item the drag is ended
3772 nevent.SetItem (item); // the item the drag is ended
3774 nevent.Veto(); // dragging must be explicit allowed!
3775 m_owner->GetEventHandler()->ProcessEvent (nevent);
3777 }else if (m_isDragging) { // any other event but not event.Dragging()
3781 m_isDragging = false;
3782 if (HasCapture()) ReleaseMouse();
3785 // send drag end event event
3786 wxTreeEvent nevent (wxEVT_COMMAND_TREE_END_DRAG, m_owner->GetId());
3787 nevent.SetEventObject (m_owner);
3788 #if !wxCHECK_VERSION(2, 5, 0)
3789 nevent.SetItem ((long)item); // the item the drag is started
3791 nevent.SetItem (item); // the item the drag is started
3793 nevent.SetPoint (p);
3794 m_owner->GetEventHandler()->ProcessEvent (nevent);
3796 }else if (m_dragCount > 0) { // just in case dragging is initiated
3803 // we process only the messages which happen on tree items
3805 m_owner->GetEventHandler()->ProcessEvent (event);
3809 // remember item at shift down
3810 if (event.ShiftDown()) {
3811 if (!m_shiftItem) m_shiftItem = m_curItem;
3813 m_shiftItem = (wxTreeListItem*)NULL;
3816 if (event.RightUp()) {
3819 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, m_owner->GetId());
3820 nevent.SetEventObject (m_owner);
3821 #if !wxCHECK_VERSION(2, 5, 0)
3822 nevent.SetItem ((long)item); // the item clicked
3824 nevent.SetItem (item); // the item clicked
3826 nevent.SetInt (m_curColumn); // the colum clicked
3827 nevent.SetPoint (p);
3828 m_owner->GetEventHandler()->ProcessEvent (nevent);
3830 }else if (event.LeftUp()) {
3833 if ((item == m_curItem) && (m_curColumn != -1) &&
3834 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
3835 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))){
3836 m_renameTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
3838 m_lastOnSame = false;
3841 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3842 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3843 HasButtons() && item->HasPlus()) {
3846 // only toggle the item for a single click, double click on
3847 // the button doesn't do anything (it toggles the item twice)
3848 if (event.LeftDown()) Toggle (item);
3850 // don't select the item if the button was clicked
3854 // determine the selection if not done by left down
3855 if (!m_left_down_selection) {
3856 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3857 HasFlag(wxTR_MULTIPLE));
3859 SelectItem (item, m_shiftItem, unselect_others);
3860 EnsureVisible (item);
3861 // LG m_curItem = item; // make the new item the current item
3863 m_left_down_selection = false;
3866 }else if (event.LeftDown() || event.RightDown() || event.LeftDClick()) {
3868 if (event.LeftDown() || event.RightDown()) {
3870 m_lastOnSame = item == m_curItem;
3873 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3874 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3877 // only toggle the item for a single click, double click on
3878 // the button doesn't do anything (it toggles the item twice)
3880 if (event.LeftDown()) Toggle (item);
3882 // don't select the item if the button was clicked
3886 // determine the selection if the current item is not selected
3887 if (!item->IsSelected()) {
3888 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3889 HasFlag(wxTR_MULTIPLE));
3890 SelectItem (item, m_shiftItem, unselect_others);
3891 EnsureVisible (item);
3892 // LG m_curItem = item; // make the new item the current item
3893 m_left_down_selection = true;
3896 // For some reason, Windows isn't recognizing a left double-click,
3897 // so we need to simulate it here. Allow 200 milliseconds for now.
3898 if (event.LeftDClick()) {
3900 // double clicking should not start editing the item label
3901 m_renameTimer->Stop();
3902 m_lastOnSame = false;
3904 // send activate event first
3905 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
3906 nevent.SetEventObject (m_owner);
3907 #if !wxCHECK_VERSION(2, 5, 0)
3908 nevent.SetItem ((long)item); // the item clicked
3910 nevent.SetItem (item); // the item clicked
3912 nevent.SetInt (m_curColumn); // the colum clicked
3913 nevent.SetPoint (p);
3914 if (!m_owner->GetEventHandler()->ProcessEvent (nevent)) {
3916 // if the user code didn't process the activate event,
3917 // handle it ourselves by toggling the item when it is
3920 if (item->HasPlus()) Toggle(item);
3924 }else{ // any other event skip just in case
3931 void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
3932 /* after all changes have been done to the tree control,
3933 * we actually redraw the tree when everything is over */
3935 if (!m_dirty) return;
3939 CalculatePositions();
3941 AdjustMyScrollbars();
3944 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
3946 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
3947 wxScrolledWindow::OnScroll(event);
3949 HandleOnScroll( event );
3952 if(event.GetOrientation() == wxHORIZONTAL) {
3953 m_owner->GetHeaderWindow()->Refresh();
3954 m_owner->GetHeaderWindow()->Update();
3958 void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
3962 dc.SetFont (GetItemFont (item));
3964 dc.GetTextExtent (item->GetText (m_main_column), &text_w, &text_h);
3966 // restore normal font
3967 dc.SetFont (m_normalFont);
3969 int total_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
3970 if (total_h < 30) { // add 10% space if greater than 30 pixels
3971 total_h += 2; // minimal 2 pixel space
3973 total_h += total_h / 10; // otherwise 10% space
3976 item->SetHeight (total_h);
3977 if (total_h > m_lineHeight) m_lineHeight = total_h;
3978 item->SetWidth(m_imgWidth + text_w +2);
3981 // -----------------------------------------------------------------------------
3982 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
3983 int level, int &y, int x_colstart) {
3985 // calculate position of vertical lines
3986 int x = x_colstart + MARGIN; // start of column
3987 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
3989 x += (m_btnWidth-m_btnWidth2); // half button space
3991 x += (m_indent-m_indent/2);
3993 if (HasFlag(wxTR_HIDE_ROOT)) {
3995 // x += m_indent * (level-2); // indent but not level 1
3996 x += m_indent * (level-1); // indent but not level 1
3999 x += m_indent * level; // indent according to level
4002 // a hidden root is not evaluated, but its children are always
4003 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
4005 CalculateSize( item, dc );
4010 y += GetLineHeight(item);
4012 // we don't need to calculate collapsed branches
4013 if ( !item->IsExpanded() ) return;
4016 wxArrayTreeListItems& children = item->GetChildren();
4017 long n, count = (long)children.Count();
4019 for (n = 0; n < count; ++n) {
4020 CalculateLevel( children[n], dc, level, y, x_colstart ); // recurse
4024 void wxTreeListMainWindow::CalculatePositions() {
4025 if ( !m_rootItem ) return;
4027 wxClientDC dc(this);
4030 dc.SetFont( m_normalFont );
4032 dc.SetPen( m_dottedPen );
4033 //if(GetImageList() == NULL)
4034 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
4038 for (int i = 0; i < (int)GetMainColumn(); ++i) {
4039 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
4040 x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
4042 CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
4045 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
4046 if (m_dirty) return;
4048 wxClientDC dc(this);
4053 GetVirtualSize( &cw, &ch );
4056 rect.x = dc.LogicalToDeviceX( 0 );
4058 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
4061 Refresh (true, &rect );
4062 AdjustMyScrollbars();
4065 void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
4068 // std::cout << "RefreshLine = "<<item<<std::endl;
4071 if (m_dirty) return;
4073 wxClientDC dc(this);
4078 GetVirtualSize( &cw, &ch );
4081 rect.x = dc.LogicalToDeviceX( 0 );
4082 rect.y = dc.LogicalToDeviceY( item->GetY() );
4084 rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
4086 Refresh (true, &rect);
4089 void wxTreeListMainWindow::RefreshSelected()
4092 long count = m_selected.GetCount();
4093 for (long n = 0; n < count; n++ )
4095 RefreshLine (m_selected[n]);
4100 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
4101 if (item->IsSelected()) {
4105 const wxArrayTreeListItems& children = item->GetChildren();
4106 long count = children.GetCount();
4107 for (long n = 0; n < count; n++ ) {
4108 RefreshSelectedUnder (children[n]);
4113 // ----------------------------------------------------------------------------
4114 // changing colours: we need to refresh the tree control
4115 // ----------------------------------------------------------------------------
4117 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
4118 if (!wxWindow::SetBackgroundColour(colour)) return false;
4124 bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
4125 if (!wxWindow::SetForegroundColour(colour)) return false;
4131 void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column,
4132 const wxString& text) {
4133 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
4135 wxClientDC dc (this);
4136 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
4137 item->SetText (column, text);
4138 CalculateSize (item, dc);
4142 wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId,
4144 wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
4146 if( IsVirtual() ) return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
4147 else return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
4150 wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item,
4152 wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4153 return m_owner->OnGetItemText(item,column);
4156 void wxTreeListMainWindow::SetFocus() {
4157 wxWindow::SetFocus();
4160 wxFont wxTreeListMainWindow::GetItemFont (wxTreeListItem *item) {
4161 wxTreeItemAttr *attr = item->GetAttributes();
4163 if (attr && attr->HasFont()) {
4164 return attr->GetFont();
4165 }else if (item->IsBold()) {
4168 return m_normalFont;
4172 int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
4173 if (!item) return 0;
4175 // determine item width
4177 wxFont font = GetItemFont (item);
4178 GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
4182 int width = w + 2*MARGIN;
4183 if (column == GetMainColumn()) {
4185 if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
4186 if (HasButtons()) width += m_btnWidth + LINEATROOT;
4187 if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
4189 // count indent level
4191 wxTreeListItem *parent = item->GetItemParent();
4192 wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
4193 while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
4195 parent = parent->GetItemParent();
4197 if (level) width += level * GetIndent();
4203 int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
4205 GetClientSize (&maxWidth, &h);
4208 // get root if on item
4209 if (!parent.IsOk()) parent = GetRootItem();
4212 if (!HasFlag(wxTR_HIDE_ROOT)) {
4213 int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
4214 if (width < w) width = w;
4215 if (width > maxWidth) return maxWidth;
4218 wxTreeItemIdValue cookie = 0;
4219 wxTreeItemId item = GetFirstChild (parent, cookie);
4220 while (item.IsOk()) {
4221 int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
4222 if (width < w) width = w;
4223 if (width > maxWidth) return maxWidth;
4225 // check the children of this item
4226 if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
4227 int w = GetBestColumnWidth (column, item);
4228 if (width < w) width = w;
4229 if (width > maxWidth) return maxWidth;
4233 item = GetNextChild (parent, cookie);
4240 //-----------------------------------------------------------------------------
4242 //-----------------------------------------------------------------------------
4244 //IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
4245 //IMPLEMENT_CLASS(wxTreeListCtrl, wxControl);
4247 BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
4248 EVT_SIZE(wxTreeListCtrl::OnSize)
4251 bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
4254 long style, const wxValidator &validator,
4255 const wxString& name)
4257 long main_style = style & ~(wxSIMPLE_BORDER|wxSUNKEN_BORDER|wxDOUBLE_BORDER|
4258 wxRAISED_BORDER|wxSTATIC_BORDER);
4259 long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
4261 if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
4264 m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
4265 main_style, validator);
4266 m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
4267 wxPoint(0, 0), wxDefaultSize,
4269 CalculateAndSetHeaderHeight();
4273 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4277 // we use 'g' to get the descent, too
4279 m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
4280 h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
4282 // only update if changed
4283 if (h != m_headerHeight) {
4290 void wxTreeListCtrl::DoHeaderLayout()
4293 GetClientSize(&w, &h);
4295 m_header_win->SetSize (0, 0, w, m_headerHeight);
4296 m_header_win->Refresh();
4299 m_main_win->SetSize (0, m_headerHeight + 1, w, h - m_headerHeight - 1);
4303 void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
4308 size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
4310 unsigned int wxTreeListCtrl::GetIndent() const
4311 { return m_main_win->GetIndent(); }
4313 void wxTreeListCtrl::SetIndent(unsigned int indent)
4314 { m_main_win->SetIndent(indent); }
4316 unsigned int wxTreeListCtrl::GetLineSpacing() const
4317 { return m_main_win->GetLineSpacing(); }
4319 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
4320 { m_main_win->SetLineSpacing(spacing); }
4322 wxImageList* wxTreeListCtrl::GetImageList() const
4323 { return m_main_win->GetImageList(); }
4325 wxImageList* wxTreeListCtrl::GetStateImageList() const
4326 { return m_main_win->GetStateImageList(); }
4328 wxImageList* wxTreeListCtrl::GetButtonsImageList() const
4329 { return m_main_win->GetButtonsImageList(); }
4331 void wxTreeListCtrl::SetImageList(wxImageList* imageList)
4332 { m_main_win->SetImageList(imageList); }
4334 void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
4335 { m_main_win->SetStateImageList(imageList); }
4337 void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
4338 { m_main_win->SetButtonsImageList(imageList); }
4340 void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
4341 { m_main_win->AssignImageList(imageList); }
4343 void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
4344 { m_main_win->AssignStateImageList(imageList); }
4346 void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
4347 { m_main_win->AssignButtonsImageList(imageList); }
4349 wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
4350 { return m_main_win->GetItemText (item, column); }
4352 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column,
4353 wxTreeItemIcon which) const
4354 { return m_main_win->GetItemImage(item, column, which); }
4356 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
4357 { return m_main_win->GetItemData(item); }
4359 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
4360 { return m_main_win->GetItemBold(item); }
4362 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
4363 { return m_main_win->GetItemTextColour(item); }
4365 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item)
4367 { return m_main_win->GetItemBackgroundColour(item); }
4369 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
4370 { return m_main_win->GetItemFont(item); }
4373 void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column,
4374 const wxString& text)
4375 { m_main_win->SetItemText (item, column, text); }
4377 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item,
4380 wxTreeItemIcon which)
4381 { m_main_win->SetItemImage(item, column, image, which); }
4383 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,
4384 wxTreeItemData* data)
4385 { m_main_win->SetItemData(item, data); }
4387 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
4388 { m_main_win->SetItemHasChildren(item, has); }
4390 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
4391 { m_main_win->SetItemBold(item, bold); }
4393 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,
4394 const wxColour& colour)
4395 { m_main_win->SetItemTextColour(item, colour); }
4397 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
4398 const wxColour& colour)
4399 { m_main_win->SetItemBackgroundColour(item, colour); }
4401 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,
4403 { m_main_win->SetItemFont(item, font); }
4405 bool wxTreeListCtrl::SetFont(const wxFont& font)
4408 m_header_win->SetFont(font);
4409 CalculateAndSetHeaderHeight();
4410 m_header_win->Refresh();
4413 return m_main_win->SetFont(font);
4419 void wxTreeListCtrl::SetWindowStyle(const long style)
4422 m_main_win->SetWindowStyle(style);
4423 m_windowStyle = style;
4424 // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4427 long wxTreeListCtrl::GetWindowStyle() const
4429 long style = m_windowStyle;
4431 style |= m_main_win->GetWindowStyle();
4435 bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow) const
4436 { return m_main_win->IsVisible(item, fullRow); }
4438 bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
4439 { return m_main_win->HasChildren(item); }
4441 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
4442 { return m_main_win->IsExpanded(item); }
4444 bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
4445 { return m_main_win->IsSelected(item); }
4447 bool wxTreeListCtrl::IsBold(const wxTreeItemId& item) const
4448 { return m_main_win->IsBold(item); }
4450 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
4451 { return m_main_win->GetChildrenCount(item, rec); }
4453 wxTreeItemId wxTreeListCtrl::GetRootItem() const
4454 { return m_main_win->GetRootItem(); }
4456 //wxTreeItemId wxTreeListCtrl::GetSelection() const
4457 //{ return m_main_win->GetSelection(); }
4458 wxTreeItemId wxTreeListCtrl::GetCurrent() const
4459 { return m_main_win->GetCurrent(); }
4461 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
4462 { return m_main_win->GetSelections(arr); }
4464 wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
4465 { return m_main_win->GetItemParent(item); }
4467 #if !wxCHECK_VERSION(2, 5, 0)
4468 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4471 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4472 wxTreeItemIdValue& cookie) const
4474 { return m_main_win->GetFirstChild(item, cookie); }
4476 #if !wxCHECK_VERSION(2, 5, 0)
4477 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4480 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4481 wxTreeItemIdValue& cookie) const
4483 { return m_main_win->GetNextChild(item, cookie); }
4485 #if !wxCHECK_VERSION(2, 5, 0)
4486 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4489 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4490 wxTreeItemIdValue& cookie) const
4492 { return m_main_win->GetPrevChild(item, cookie); }
4494 #if !wxCHECK_VERSION(2, 5, 0)
4495 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4498 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4499 wxTreeItemIdValue& cookie) const
4501 { return m_main_win->GetLastChild(item, cookie); }
4504 wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
4505 { return m_main_win->GetNextSibling(item); }
4507 wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
4508 { return m_main_win->GetPrevSibling(item); }
4510 wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
4511 { return m_main_win->GetNext(item, true); }
4513 wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
4514 { return m_main_win->GetPrev(item, true); }
4516 wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
4517 { return m_main_win->GetFirstExpandedItem(); }
4519 wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
4520 { return m_main_win->GetNextExpanded(item); }
4522 wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
4523 { return m_main_win->GetPrevExpanded(item); }
4525 wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
4526 { return m_main_win->GetFirstVisibleItem(fullRow); }
4528 wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow) const
4529 { return m_main_win->GetNextVisible(item, fullRow); }
4531 wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow) const
4532 { return m_main_win->GetPrevVisible(item, fullRow); }
4534 wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
4535 int selectedImage, wxTreeItemData* data)
4536 { return m_main_win->AddRoot (text, image, selectedImage, data); }
4538 wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
4539 const wxString& text, int image,
4541 wxTreeItemData* data)
4542 { return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
4544 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4545 const wxTreeItemId& previous,
4546 const wxString& text, int image,
4548 wxTreeItemData* data)
4550 return m_main_win->InsertItem(parent, previous, text, image,
4551 selectedImage, data);
4554 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4556 const wxString& text, int image,
4558 wxTreeItemData* data)
4560 return m_main_win->InsertItem(parent, index, text, image,
4561 selectedImage, data);
4564 wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
4565 const wxString& text, int image,
4567 wxTreeItemData* data)
4568 { return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
4570 void wxTreeListCtrl::Delete(const wxTreeItemId& item)
4571 { m_main_win->Delete(item); }
4573 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
4574 { m_main_win->DeleteChildren(item); }
4576 void wxTreeListCtrl::DeleteRoot()
4577 { m_main_win->DeleteRoot(); }
4579 void wxTreeListCtrl::Expand(const wxTreeItemId& item)
4580 { m_main_win->Expand(item); }
4582 void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
4583 { m_main_win->ExpandAll(item); }
4585 void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
4586 { m_main_win->Collapse(item); }
4588 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
4589 { m_main_win->CollapseAndReset(item); }
4591 void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
4592 { m_main_win->Toggle(item); }
4594 //void wxTreeListCtrl::Unselect()
4595 //{ m_main_win->Unselect(); }
4597 // LG 19/09/08 : Added
4598 //void wxTreeListCtrl::Unselect(wxTreeItemId& item)
4599 //{ m_main_win->Unselect((wxTreeListItem*)item.m_pItem); }
4601 void wxTreeListCtrl::UnselectAll()
4602 { m_main_win->UnselectAll(); }
4604 void wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
4605 bool unselect_others)
4606 { m_main_win->SelectItem (item, last, unselect_others); }
4608 void wxTreeListCtrl::SelectAll()
4609 { m_main_win->SelectAll(); }
4611 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
4612 { m_main_win->EnsureVisible(item); }
4614 void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
4615 { m_main_win->ScrollTo(item); }
4617 wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
4619 wxPoint p = m_main_win->ScreenToClient (ClientToScreen (pos));
4620 return m_main_win->HitTest (p, flags, column);
4623 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
4624 bool textOnly) const
4625 { return m_main_win->GetBoundingRect(item, rect, textOnly); }
4627 void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
4628 { m_main_win->EditLabel (item, column); }
4630 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1,
4631 const wxTreeItemId& item2)
4633 // do the comparison here, and not delegate to m_main_win, in order
4634 // to let the user override it
4635 //return m_main_win->OnCompareItems(item1, item2);
4636 return wxStrcmp(GetItemText(item1), GetItemText(item2));
4639 void wxTreeListCtrl::SortChildren(const wxTreeItemId& item)
4640 { m_main_win->SortChildren(item); }
4642 wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, const wxString& str, int mode)
4643 { return m_main_win->FindItem (item, str, mode); }
4645 void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
4646 { m_main_win->SetDragItem (item); }
4648 bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
4650 if (!m_main_win) return false;
4651 return m_main_win->SetBackgroundColour(colour);
4654 bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
4656 if (!m_main_win) return false;
4657 return m_main_win->SetForegroundColour(colour);
4660 int wxTreeListCtrl::GetColumnCount() const
4661 { return m_main_win->GetColumnCount(); }
4663 void wxTreeListCtrl::SetColumnWidth(int column, int width)
4665 m_header_win->SetColumnWidth (column, width);
4666 m_header_win->Refresh();
4669 int wxTreeListCtrl::GetColumnWidth(int column) const
4670 { return m_header_win->GetColumnWidth(column); }
4672 void wxTreeListCtrl::SetMainColumn(int column)
4673 { m_main_win->SetMainColumn(column); }
4675 int wxTreeListCtrl::GetMainColumn() const
4676 { return m_main_win->GetMainColumn(); }
4678 void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
4680 m_header_win->SetColumnText (column, text);
4681 m_header_win->Refresh();
4684 wxString wxTreeListCtrl::GetColumnText(int column) const
4685 { return m_header_win->GetColumnText(column); }
4687 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
4689 m_header_win->AddColumn (colInfo);
4693 void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
4695 m_header_win->InsertColumn (before, colInfo);
4696 m_header_win->Refresh();
4699 void wxTreeListCtrl::RemoveColumn(int column)
4701 m_header_win->RemoveColumn (column);
4702 m_header_win->Refresh();
4705 void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
4707 m_header_win->SetColumn (column, colInfo);
4708 m_header_win->Refresh();
4711 const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
4712 { return m_header_win->GetColumn(column); }
4714 wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column)
4715 { return m_header_win->GetColumn(column); }
4717 void wxTreeListCtrl::SetColumnImage(int column, int image)
4719 m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
4720 m_header_win->Refresh();
4723 int wxTreeListCtrl::GetColumnImage(int column) const
4725 return m_header_win->GetColumn(column).GetImage();
4728 void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
4730 m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
4733 void wxTreeListCtrl::SetColumnShown(int column, bool shown)
4735 wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
4736 m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
4737 m_header_win->Refresh();
4740 bool wxTreeListCtrl::IsColumnEditable(int column) const
4742 return m_header_win->GetColumn(column).IsEditable();
4745 bool wxTreeListCtrl::IsColumnShown(int column) const
4747 return m_header_win->GetColumn(column).IsShown();
4750 void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
4752 m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
4753 m_header_win->Refresh();
4756 int wxTreeListCtrl::GetColumnAlignment(int column) const
4758 return m_header_win->GetColumn(column).GetAlignment();
4761 void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
4763 m_main_win->Refresh (erase, rect);
4764 m_header_win->Refresh (erase, rect);
4767 void wxTreeListCtrl::SetFocus()
4768 { m_main_win->SetFocus(); }
4770 wxSize wxTreeListCtrl::DoGetBestSize() const
4772 // something is better than nothing...
4773 return wxSize (200,200); // but it should be specified values! FIXME
4776 wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
4778 return wxEmptyString;