1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        treelistctrl.cpp
3 // Purpose:     multi column tree control implementation
4 // Created:     01/02/97
5 // Author:      Robert Roebling
6 // Maintainer:  Ronan Chartois (pgriddev)
7 // Version:     $Id: treelistctrl.cpp 10771 2016-02-06 14:29:31Z mortenmacfly $
8 // Copyright:   (c) 2004-2011 Robert Roebling, Julian Smart, Alberto Griggio,
9 //              Vadim Zeitlin, Otto Wyss, Ronan Chartois
10 // Licence:     wxWindows
11 /////////////////////////////////////////////////////////////////////////////
12 
13 // ===========================================================================
14 // declarations
15 // ===========================================================================
16 
17 // ---------------------------------------------------------------------------
18 // headers
19 // ---------------------------------------------------------------------------
20 
21 #if defined(__GNUG__) && !defined(__APPLE__)
22   #pragma implementation "treelistctrl.h"
23 #endif
24 
25 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
27 
28 #ifdef __BORLANDC__
29     #pragma hdrstop
30 #endif
31 
32 
33 #include <wx/app.h>
34 #include <wx/treebase.h>
35 #include <wx/timer.h>
36 #include <wx/textctrl.h>
37 #include <wx/imaglist.h>
38 #include <wx/settings.h>
39 #include <wx/dcclient.h>
40 #include <wx/dcscreen.h>
41 #include <wx/scrolwin.h>
42 #include <wx/dcmemory.h>
43 #include <wx/renderer.h>
44 #include <wx/apptrait.h>
45 #include <wx/dcbuffer.h>
46 #include <wx/tooltip.h>
47 #include <wx/hashmap.h>
48 
49 #ifdef __WXMAC__
50 #if wxCHECK_VERSION(3, 0, 0)
51 #include "wx/osx/private.h"
52 #else
53 #include "wx/mac/private.h"
54 #endif
55 #endif
56 
57 #include "wx/treelistctrl.h"
58 
59 #include <wx/log.h>  // only required for debugging purpose
60 #include <wx/msgdlg.h>  // only required for debugging purpose
61 
62 // ---------------------------------------------------------------------------
63 // array types
64 // ---------------------------------------------------------------------------
65 
66 class wxTreeListItem;
67 class wxTreeListItemCellAttr;
68 
69 WX_DEFINE_ARRAY_PTR(wxTreeListItem *, wxArrayTreeListItems);
70 
71 #include <wx/dynarray.h>
72 WX_DECLARE_OBJARRAY(wxTreeListColumnInfo, wxArrayTreeListColumnInfo);
73 #include <wx/arrimpl.cpp>
74 WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo);
75 
76 
77 WX_DECLARE_HASH_MAP( int, wxTreeListItemCellAttr *, wxIntegerHash, wxIntegerEqual, wxTreeListItemCellAttrHash );
78 
79 // --------------------------------------------------------------------------
80 // constants
81 // --------------------------------------------------------------------------
82 
83 static const int NO_IMAGE = -1;
84 
85 static const int LINEHEIGHT = 10;
86 static const int LINEATROOT = 5;
87 static const int MARGIN = 2;
88 static const int MININDENT = 16;
89 static const int BTNWIDTH = 9;
90 static const int BTNHEIGHT = 9;
91 static const int EXTRA_WIDTH = 4;
92 static const int EXTRA_HEIGHT = 4;
93 static const int HEADER_OFFSET_X = 0;  // changed from 1 to 0 on 2009.03.10 for Windows (other OS untested)
94 static const int HEADER_OFFSET_Y = 1;
95 
96 static const int DRAG_TIMER_TICKS = 250; // minimum drag wait time in ms
97 static const int FIND_TIMER_TICKS = 500; // minimum find wait time in ms
98 static const int RENAME_TIMER_TICKS = 250; // minimum rename wait time in ms
99 
100 const wxChar* wxTreeListCtrlNameStr = _T("treelistctrl");
101 
102 static wxTreeListColumnInfo wxInvalidTreeListColumnInfo;
103 
104 
105 // ---------------------------------------------------------------------------
106 // private classes
107 // ---------------------------------------------------------------------------
108 
109 class  wxTreeListHeaderWindow : public wxWindow
110 {
111 protected:
112     wxTreeListMainWindow *m_owner;
113     const wxCursor *m_currentCursor;
114     const wxCursor *m_resizeCursor;
115     bool m_isDragging;
116 
117     // column being resized
118     int m_column;
119 
120     // divider line position in logical (unscrolled) coords
121     int m_currentX;
122 
123     // minimal position beyond which the divider line can't be dragged in
124     // logical coords
125     int m_minX;
126 
127     wxArrayTreeListColumnInfo m_columns;
128 
129     // total width of the columns
130     int m_total_col_width;
131 
132 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
133     // which col header is currently highlighted with mouse-over
134     int m_hotTrackCol;
135     int XToCol(int x);
136     void RefreshColLabel(int col);
137 #endif
138 
139 public:
140     wxTreeListHeaderWindow();
141 
142     wxTreeListHeaderWindow( wxWindow *win,
143                             wxWindowID id,
144                             wxTreeListMainWindow *owner,
145                             const wxPoint &pos = wxDefaultPosition,
146                             const wxSize &size = wxDefaultSize,
147                             long style = 0,
148                             const wxString &name = _T("wxtreelistctrlcolumntitles") );
149 
150     virtual ~wxTreeListHeaderWindow();
151 
152     void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
153     void DrawCurrent();
154     void AdjustDC(wxDC& dc);
155 
156     void OnPaint( wxPaintEvent &event );
OnEraseBackground(wxEraseEvent & WXUNUSED (event))157     void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; } // reduce flicker
158     void OnMouse( wxMouseEvent &event );
159     void OnSetFocus( wxFocusEvent &event );
160 
161     // total width of all columns
GetWidth() const162     int GetWidth() const { return m_total_col_width; }
163 
164     // column manipulation
GetColumnCount() const165     int GetColumnCount() const { return (int)m_columns.GetCount(); }
166 
167     void AddColumn (const wxTreeListColumnInfo& colInfo);
168 
169     void InsertColumn (int before, const wxTreeListColumnInfo& colInfo);
170 
171     void RemoveColumn (int column);
172 
173     // column information manipulation
GetColumn(int column) const174     const wxTreeListColumnInfo& GetColumn (int column) const{
175         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
176                      wxInvalidTreeListColumnInfo, _T("Invalid column"));
177         return m_columns[column];
178     }
GetColumn(int column)179     wxTreeListColumnInfo& GetColumn (int column) {
180         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
181                      wxInvalidTreeListColumnInfo, _T("Invalid column"));
182         return m_columns[column];
183     }
184     void SetColumn (int column, const wxTreeListColumnInfo& info);
185 
GetColumnText(int column) const186     wxString GetColumnText (int column) const {
187         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
188                      wxEmptyString, _T("Invalid column"));
189         return m_columns[column].GetText();
190     }
SetColumnText(int column,const wxString & text)191     void SetColumnText (int column, const wxString& text) {
192         wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
193                      _T("Invalid column"));
194         m_columns[column].SetText (text);
195     }
196 
GetColumnAlignment(int column) const197     int GetColumnAlignment (int column) const {
198         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
199                      wxALIGN_LEFT, _T("Invalid column"));
200         return m_columns[column].GetAlignment();
201     }
SetColumnAlignment(int column,int flag)202     void SetColumnAlignment (int column, int flag) {
203         wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
204                      _T("Invalid column"));
205         m_columns[column].SetAlignment (flag);
206     }
207 
GetColumnWidth(int column) const208     int GetColumnWidth (int column) const {
209         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
210                      -1, _T("Invalid column"));
211         return m_columns[column].GetWidth();
212     }
213     void SetColumnWidth (int column, int width);
214 
IsColumnEditable(int column) const215     bool IsColumnEditable (int column) const {
216         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
217                      false, _T("Invalid column"));
218         return m_columns[column].IsEditable();
219     }
220 
IsColumnShown(int column) const221     bool IsColumnShown (int column) const {
222         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
223                      true, _T("Invalid column"));
224         return m_columns[column].IsShown();
225     }
226 
227     // needs refresh
228     bool m_dirty;
229 
230 private:
231     // common part of all ctors
232     void Init();
233 
234     void SendListEvent(wxEventType type, wxPoint pos);
235 
236     DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow)
237     DECLARE_EVENT_TABLE()
238 };
239 
240 
241 //-----------------------------------------------------------------------------
242 
243 class wxEditTextCtrl;
244 
245 
246 // this is the "true" control
247 class  wxTreeListMainWindow: public wxScrolledWindow
248 {
249 public:
250     // creation
251     // --------
wxTreeListMainWindow()252     wxTreeListMainWindow() { Init(); }
253 
wxTreeListMainWindow(wxTreeListCtrl * parent,wxWindowID id=-1,const wxPoint & pos=wxDefaultPosition,const wxSize & size=wxDefaultSize,long style=wxTR_DEFAULT_STYLE,const wxValidator & validator=wxDefaultValidator,const wxString & name=_T ("wxtreelistmainwindow"))254     wxTreeListMainWindow (wxTreeListCtrl *parent, wxWindowID id = -1,
255                const wxPoint& pos = wxDefaultPosition,
256                const wxSize& size = wxDefaultSize,
257                long style = wxTR_DEFAULT_STYLE,
258                const wxValidator &validator = wxDefaultValidator,
259                const wxString& name = _T("wxtreelistmainwindow"))
260     {
261         Init();
262         Create (parent, id, pos, size, style, validator, name);
263     }
264 
265     virtual ~wxTreeListMainWindow();
266 
267     bool Create(wxTreeListCtrl *parent, wxWindowID id = -1,
268                 const wxPoint& pos = wxDefaultPosition,
269                 const wxSize& size = wxDefaultSize,
270                 long style = wxTR_DEFAULT_STYLE,
271                 const wxValidator &validator = wxDefaultValidator,
272                 const wxString& name = _T("wxtreelistctrl"));
273 
274     // accessors
275     // ---------
276 
277     // return true if this is a virtual list control
IsVirtual() const278     bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL); }
279 
280     // get the total number of items in the control
281     size_t GetCount() const;
282 
283     // indent is the number of pixels the children are indented relative to
284     // the parents position. SetIndent() also redraws the control
285     // immediately.
GetIndent() const286     unsigned int GetIndent() const { return m_indent; }
287     void SetIndent(unsigned int indent);
288 
289     // see wxTreeListCtrl for the meaning
GetLineSpacing() const290     unsigned int GetLineSpacing() const { return m_linespacing; }
291     void SetLineSpacing(unsigned int spacing);
292 
293     // image list: these functions allow to associate an image list with
294     // the control and retrieve it. Note that when assigned with
295     // SetImageList, the control does _not_ delete
296     // the associated image list when it's deleted in order to allow image
297     // lists to be shared between different controls. If you use
298     // AssignImageList, the control _does_ delete the image list.
299 
300     // The normal image list is for the icons which correspond to the
301     // normal tree item state (whether it is selected or not).
302     // Additionally, the application might choose to show a state icon
303     // which corresponds to an app-defined item state (for example,
304     // checked/unchecked) which are taken from the state image list.
GetImageList() const305     wxImageList *GetImageList() const { return m_imageListNormal; }
GetStateImageList() const306     wxImageList *GetStateImageList() const { return m_imageListState; }
GetButtonsImageList() const307     wxImageList *GetButtonsImageList() const { return m_imageListButtons; }
308 
309     void SetImageList(wxImageList *imageList);
310     void SetStateImageList(wxImageList *imageList);
311     void SetButtonsImageList(wxImageList *imageList);
312     void AssignImageList(wxImageList *imageList);
313     void AssignStateImageList(wxImageList *imageList);
314     void AssignButtonsImageList(wxImageList *imageList);
315 
316     void SetToolTip(const wxString& tip);
317     void SetToolTip(wxToolTip *tip);
318     void SetItemToolTip(const wxTreeItemId& item, const wxString &tip);
319 
320     // Functions to work with tree ctrl items.
321 
322 
323 
324     // accessors (most props have a default at row/item level *and* a default at cell level)
325     // ---------
326 
327     wxString GetItemText (const wxTreeItemId& item, int column) const;
328     wxString GetItemText (wxTreeItemData* item, int column) const;
329 
330     // ItemImage is special: main col has multiple images
GetItemImage(const wxTreeItemId & item,wxTreeItemIcon which=wxTreeItemIcon_Normal) const331     int GetItemImage (const wxTreeItemId& item,             wxTreeItemIcon which = wxTreeItemIcon_Normal) const  { return GetItemImage (item, GetMainColumn(), which); }
332     int GetItemImage (const wxTreeItemId& item, int column, wxTreeItemIcon which = wxTreeItemIcon_Normal) const;
333 
334     // ItemData is special, there is a separate default at row/item level
335     wxTreeItemData *GetItemData(const wxTreeItemId& item) const;
336     wxTreeItemData *GetItemData(const wxTreeItemId& item, int column) const;
337 
338     bool GetItemBold(const wxTreeItemId& item)             const;
339     bool GetItemBold(const wxTreeItemId& item, int column) const;
340 
341     wxColour GetItemTextColour(const wxTreeItemId& item)             const;
342     wxColour GetItemTextColour(const wxTreeItemId& item, int column) const;
343 
344     wxColour GetItemBackgroundColour(const wxTreeItemId& item)             const;
345     wxColour GetItemBackgroundColour(const wxTreeItemId& item, int column) const;
346 
347     wxFont GetItemFont(const wxTreeItemId& item) const;
348     wxFont GetItemFont(const wxTreeItemId& item, int column) const;
349 
350 
351 
352     // modifiers (most properties have a default at row/item level *and* a default at cell level)
353     // ---------
354 
355     // force appearance of [+] button near the item. This is useful to
356     // allow the user to expand the items which don't have any children now
357     // - but instead add them only when needed, thus minimizing memory
358     // usage and loading time.
359     void SetItemHasChildren(const wxTreeItemId& item, bool has = true);
360 
361     // set item's label
362     void SetItemText (const wxTreeItemId& item, int column, const wxString& text);
363 
364     // get one of the images associated with the item (normal by default)
SetItemImage(const wxTreeItemId & item,int image,wxTreeItemIcon which=wxTreeItemIcon_Normal)365     void SetItemImage (const wxTreeItemId& item,             int image, wxTreeItemIcon which = wxTreeItemIcon_Normal) { SetItemImage (item, GetMainColumn(), image, which); }
366     void SetItemImage (const wxTreeItemId& item, int column, int image, wxTreeItemIcon which = wxTreeItemIcon_Normal);
367 
368     // associate some data with the item
369     void SetItemData(const wxTreeItemId& item,             wxTreeItemData *data);
370     void SetItemData(const wxTreeItemId& item, int column, wxTreeItemData *data);
371 
372     // the item will be shown in bold
373     void SetItemBold(const wxTreeItemId& item,             bool bold = true);
374     void SetItemBold(const wxTreeItemId& item, int column, bool bold = true);
375 
376     // set the item's text colour
377     void SetItemTextColour(const wxTreeItemId& item,             const wxColour& colour);
378     void SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour);
379 
380     // set the item's background colour
381     void SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour);
382     void SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour);
383 
384     // set the item's font (should be of the same height for all items)
385     void SetItemFont(const wxTreeItemId& item,             const wxFont& font);
386     void SetItemFont(const wxTreeItemId& item, int column, const wxFont& font);
387 
388 
389 
390     // item status inquiries
391     // ---------------------
392 
393     // is the item visible (it might be outside the view or not expanded)?
394     bool IsVisible(const wxTreeItemId& item, bool fullRow, bool within = true) const;
395     // does the item has any children?
396     bool HasChildren(const wxTreeItemId& item) const;
397     // is the item expanded (only makes sense if HasChildren())?
398     bool IsExpanded(const wxTreeItemId& item) const;
399     // is this item currently selected (the same as has focus)?
400     bool IsSelected(const wxTreeItemId& item) const;
401     // is item text in bold font?
402     bool IsBold(const wxTreeItemId& item)             const;
403     bool IsBold(const wxTreeItemId& item, int column) const;
404 
405 
406 
407     // set the window font
408     virtual bool SetFont( const wxFont &font );
409 
410     // set the styles.  No need to specify a GetWindowStyle here since
411     // the base wxWindow member function will do it for us
412     void SetWindowStyle(const long styles);
413 
414     // number of children
415     // ------------------
416 
417     // if 'recursively' is false, only immediate children count, otherwise
418     // the returned number is the number of all items in this branch
419     size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true);
420 
421     // navigation
422     // ----------
423 
424     // wxTreeItemId.IsOk() will return false if there is no such item
425 
426     // get the root tree item
GetRootItem() const427     wxTreeItemId GetRootItem() const { return m_rootItem; }  // implict cast from wxTreeListItem *
428 
429     // get the item currently selected, only if a single item is selected
GetSelection() const430     wxTreeItemId GetSelection() const { return m_selectItem; }
431 
432     // get all the items currently selected, return count of items
433     size_t GetSelections(wxArrayTreeItemIds&) const;
434 
435     // get the parent of this item (may return NULL if root)
436     wxTreeItemId GetItemParent(const wxTreeItemId& item) const;
437 
438     // for this enumeration function you must pass in a "cookie" parameter
439     // which is opaque for the application but is necessary for the library
440     // to make these functions reentrant (i.e. allow more than one
441     // enumeration on one and the same object simultaneously). Of course,
442     // the "cookie" passed to GetFirstChild() and GetNextChild() should be
443     // the same!
444 
445     // get child of this item
446     wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
447     wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
448     wxTreeItemId GetPrevChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
449     wxTreeItemId GetLastChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
450 
451     // get sibling of this item
452     wxTreeItemId GetNextSibling(const wxTreeItemId& item) const;
453     wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const;
454 
455     // get item in the full tree (currently only for internal use)
456     wxTreeItemId GetNext(const wxTreeItemId& item, bool fulltree = true) const;
457     wxTreeItemId GetPrev(const wxTreeItemId& item, bool fulltree = true) const;
458 
459     // get expanded item, see IsExpanded()
460     wxTreeItemId GetFirstExpandedItem() const;
461     wxTreeItemId GetNextExpanded(const wxTreeItemId& item) const;
462     wxTreeItemId GetPrevExpanded(const wxTreeItemId& item) const;
463 
464     // get visible item, see IsVisible()
465     wxTreeItemId GetFirstVisible(                          bool fullRow, bool within) const;
466     wxTreeItemId GetNextVisible (const wxTreeItemId& item, bool fullRow, bool within) const;
467     wxTreeItemId GetPrevVisible (const wxTreeItemId& item, bool fullRow, bool within) const;
468     wxTreeItemId GetLastVisible (                          bool fullRow, bool within) const;
469 
470     // operations
471     // ----------
472 
473     // add the root node to the tree
474     wxTreeItemId AddRoot (const wxString& text,
475                           int image = -1, int selectedImage = -1,
476                           wxTreeItemData *data = NULL);
477 
478     // insert a new item in as the first child of the parent
479     wxTreeItemId PrependItem(const wxTreeItemId& parent,
480                              const wxString& text,
481                              int image = -1, int selectedImage = -1,
482                              wxTreeItemData *data = NULL);
483 
484     // insert a new item after a given one
485     wxTreeItemId InsertItem(const wxTreeItemId& parent,
486                             const wxTreeItemId& idPrevious,
487                             const wxString& text,
488                             int image = -1, int selectedImage = -1,
489                             wxTreeItemData *data = NULL);
490 
491     // insert a new item before the one with the given index
492     wxTreeItemId InsertItem(const wxTreeItemId& parent,
493                             size_t index,
494                             const wxString& text,
495                             int image = -1, int selectedImage = -1,
496                             wxTreeItemData *data = NULL);
497 
498     // insert a new item in as the last child of the parent
499     wxTreeItemId AppendItem(const wxTreeItemId& parent,
500                             const wxString& text,
501                             int image = -1, int selectedImage = -1,
502                             wxTreeItemData *data = NULL);
503 
504     // delete this item and associated data if any
505     void Delete(const wxTreeItemId& item);
506     // delete all children (but don't delete the item itself)
507     // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
508     void DeleteChildren(const wxTreeItemId& item);
509     // delete the root and all its children from the tree
510     // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
511     void DeleteRoot();
512 
513     // expand this item
514     void Expand(const wxTreeItemId& item);
515     // expand this item and all subitems recursively
516     void ExpandAll(const wxTreeItemId& item);
517     // collapse the item without removing its children
518     void Collapse(const wxTreeItemId& item);
519     // collapse the item and remove all children
520     void CollapseAndReset(const wxTreeItemId& item);
521     // toggles the current state
522     void Toggle(const wxTreeItemId& item);
523 
524     // set cursor item (indicated by black rectangle)
525     void SetCurrentItem(const wxTreeItemId& item);
526 
527     // remove the selection from currently selected item (if any)
528     void Unselect();
529     void UnselectAll();
530     // select this item
531     bool SelectItem(const wxTreeItemId& item, const wxTreeItemId& prev = (wxTreeItemId*)NULL,
532                     bool unselect_others = true);
533     void SelectAll();
534     // make sure this item is visible (expanding the parent item and/or
535     // scrolling to this item if necessary)
536     void EnsureVisible(const wxTreeItemId& item);
537     // scroll to this item (but don't expand its parent)
538     void ScrollTo(const wxTreeItemId& item);
539     void AdjustMyScrollbars();
540 
541     // The first function is more portable (because easier to implement
542     // on other platforms), but the second one returns some extra info.
HitTest(const wxPoint & point)543     wxTreeItemId HitTest (const wxPoint& point)
544         { int flags; int column; return HitTest (point, flags, column); }
HitTest(const wxPoint & point,int & flags)545     wxTreeItemId HitTest (const wxPoint& point, int& flags)
546         { int column; return HitTest (point, flags, column); }
547     wxTreeItemId HitTest (const wxPoint& point, int& flags, int& column);
548 
549 
550     // get the bounding rectangle of the item (or of its label only)
551     bool GetBoundingRect(const wxTreeItemId& item,
552                          wxRect& rect,
553                          bool textOnly = false) const;
554 
555     // Start editing the item label: this (temporarily) replaces the item
556     // with a one line edit control. The item will be selected if it hadn't
557     // been before.
558     void EditLabel (const wxTreeItemId& item, int column);
559     void EndEdit(bool isCancelled);
560 
561     // sorting
562     // this function is called to compare 2 items and should return -1, 0
563     // or +1 if the first item is less than, equal to or greater than the
564     // second one. The base class version performs alphabetic comparaison
565     // of item labels (GetText)
566     virtual int OnCompareItems(const wxTreeItemId& item1,
567                                const wxTreeItemId& item2);
568     // sort the children of this item using OnCompareItems
569     //
570     // NB: this function is not reentrant and not MT-safe (TODO)!
571     void SortChildren(const wxTreeItemId& item, int column, bool reverseOrder);
572 
573     // searching
574     wxTreeItemId FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode = 0);
575 
576     // implementation only from now on
577 
578     // overridden base class virtuals
579     virtual bool SetBackgroundColour(const wxColour& colour);
580     virtual bool SetForegroundColour(const wxColour& colour);
581 
582     // drop over item
583     void SetDragItem (const wxTreeItemId& item = (wxTreeItemId*)NULL);
584 
585     // callbacks
586     void OnPaint( wxPaintEvent &event );
OnEraseBackground(wxEraseEvent & WXUNUSED (event))587     void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; } // to reduce flicker
588     void OnSetFocus( wxFocusEvent &event );
589     void OnKillFocus( wxFocusEvent &event );
590     void OnChar( wxKeyEvent &event );
591     void OnMouse( wxMouseEvent &event );
592     void OnIdle( wxIdleEvent &event );
593     void OnScroll(wxScrollWinEvent& event);
OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED (event))594     void OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event)) { ;; }
595 
596     // implementation helpers
GetColumnCount() const597     int GetColumnCount() const
598     { return m_owner->GetHeaderWindow()->GetColumnCount(); }
599 
SetMainColumn(int column)600     void SetMainColumn (int column)
601     { if ((column >= 0) && (column < GetColumnCount())) m_main_column = column; }
602 
GetMainColumn() const603     int GetMainColumn() const { return m_main_column; }
GetCurrentColumn() const604     int GetCurrentColumn() const { return m_curColumn >= 0 ? m_curColumn : m_main_column; }
605 
606     int GetBestColumnWidth (int column, wxTreeItemId parent = wxTreeItemId());
607     int GetItemWidth (int column, wxTreeListItem *item);
608 
609     void SetFocus();
610 
611 protected:
612     wxTreeListCtrl* m_owner;
613 
614     int m_main_column;
615 
616     friend class wxTreeListItem;
617     friend class wxTreeListRenameTimer;
618     friend class wxEditTextCtrl;
619 
620     wxFont               m_normalFont;
621     wxFont               m_boldFont;
622 
623     wxTreeListItem       *m_rootItem; // root item
624     wxTreeListItem       *m_curItem; // current item, either selected or marked
625     wxTreeListItem       *m_shiftItem; // item, where the shift key was pressed
626     wxTreeListItem       *m_selectItem; // current selected item, not with wxTR_MULTIPLE
627 
628     int                  m_curColumn;
629     int                  m_sortColumn;
630     bool                 m_ReverseSortOrder;
631 
632     int                  m_btnWidth, m_btnWidth2;
633     int                  m_btnHeight, m_btnHeight2;
634     int                  m_imgWidth, m_imgWidth2;
635     int                  m_imgHeight, m_imgHeight2;
636     unsigned short       m_indent;
637     int                  m_lineHeight;
638     unsigned short       m_linespacing;
639     wxPen                m_dottedPen;
640     wxBrush             *m_hilightBrush,
641                         *m_hilightUnfocusedBrush;
642     bool                 m_hasFocus;
643 public:
644     bool                 m_dirty;
645 protected:
646     bool                 m_ownsImageListNormal,
647                          m_ownsImageListState,
648                          m_ownsImageListButtons;
649     bool                 m_lastOnSame;  // last click on the same item as prev
650     bool                 m_left_down_selection;
651 
652     wxImageList         *m_imageListNormal,
653                         *m_imageListState,
654                         *m_imageListButtons;
655 
656     bool                 m_isDragStarted;  // set at the very beginning of dragging
657     bool                 m_isDragging; // set once a drag begin event was fired
658     wxPoint              m_dragStartPos;  // set whenever m_isDragStarted is set to true
659     wxTreeListItem      *m_dragItem;
660     int                  m_dragCol;
661 
662     wxTreeListItem       *m_editItem; // item, which is currently edited
663     wxTimer             *m_editTimer;
664     bool                 m_editAccept;  // currently unused, OnRenameAccept() argument makes it redundant
665     wxString             m_editRes;
666     int                  m_editCol;
667     wxEditTextCtrl      *m_editControl;
668 
669     // char navigation
670     wxTimer             *m_findTimer;
671     wxString             m_findStr;
672 
673     bool                 m_isItemToolTip;  // true if individual item tooltips were set (disable global tooltip)
674     wxString             m_toolTip;  // global tooltip
675     wxTreeListItem      *m_toolTipItem;  // item whose tip is currently shown (NULL==global, -1==not displayed)
676 
677     // the common part of all ctors
678     void Init();
679 
680     // misc helpers
681     wxTreeItemId DoInsertItem(const wxTreeItemId& parent,
682                               size_t previous,
683                               const wxString& text,
684                               int image, int selectedImage,
685                               wxTreeItemData *data);
686     void DoDeleteItem (wxTreeListItem *item);
687     void SetCurrentItem(wxTreeListItem *item);
HasButtons(void) const688     bool HasButtons(void) const
689         { return (m_imageListButtons) || HasFlag (wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); }
690 
691     void CalculateLineHeight();
692     int  GetLineHeight(wxTreeListItem *item) const;
693     void PaintLevel( wxTreeListItem *item, wxDC& dc, int level, int &y,
694                      int x_maincol);
695     void PaintItem( wxTreeListItem *item, wxDC& dc);
696 
697     void CalculateLevel( wxTreeListItem *item, wxDC &dc, int level, int &y,
698                          int x_maincol);
699     void CalculatePositions();
700     void CalculateSize( wxTreeListItem *item, wxDC &dc );
701 
702     void RefreshSubtree (wxTreeListItem *item);
703     void RefreshLine (wxTreeListItem *item);
704     // redraw all selected items
705     void RefreshSelected();
706     // RefreshSelected() recursive helper
707     void RefreshSelectedUnder (wxTreeListItem *item);
708 
709     void OnRenameTimer();
710     void OnRenameAccept(bool isCancelled);
711 
712     void FillArray(wxTreeListItem*, wxArrayTreeItemIds&) const;
713     bool TagAllChildrenUntilLast (wxTreeListItem *crt_item, wxTreeListItem *last_item);
714     bool TagNextChildren (wxTreeListItem *crt_item, wxTreeListItem *last_item);
715     void UnselectAllChildren (wxTreeListItem *item );
716     bool SendEvent(wxEventType event_type, wxTreeListItem *item = NULL, wxTreeEvent *event = NULL);  // returns true if processed
717 
718 private:
719     DECLARE_EVENT_TABLE()
720     DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow)
721 };
722 
723 
724 //-----------------------------------------------------------------------------
725 
726 // timer used for enabling in-place edit
727 class  wxTreeListRenameTimer: public wxTimer
728 {
729 public:
730     wxTreeListRenameTimer( wxTreeListMainWindow *owner );
731 
732     void Notify();
733 
734 private:
735     wxTreeListMainWindow   *m_owner;
736 };
737 
738 
739 //-----------------------------------------------------------------------------
740 
741 // control used for in-place edit
742 class  wxEditTextCtrl: public wxTextCtrl
743 {
744 public:
745     wxEditTextCtrl (wxWindow *parent,
746                     const wxWindowID id,
747                     bool *accept,
748                     wxString *res,
749                     wxTreeListMainWindow *owner,
750                     const wxString &value = wxEmptyString,
751                     const wxPoint &pos = wxDefaultPosition,
752                     const wxSize &size = wxDefaultSize,
753                     int style = 0,
754                     const wxValidator& validator = wxDefaultValidator,
755                     const wxString &name = wxTextCtrlNameStr );
756     ~wxEditTextCtrl();
757 
758     virtual bool Destroy();  // wxWindow override
759     void EndEdit(bool isCancelled);
SetOwner(wxTreeListMainWindow * owner)760     void SetOwner(wxTreeListMainWindow *owner) { m_owner = owner; }
761 
762     void OnChar( wxKeyEvent &event );
763     void OnKeyUp( wxKeyEvent &event );
764     void OnKillFocus( wxFocusEvent &event );
765 
766 
767 private:
768     wxTreeListMainWindow  *m_owner;
769     bool               *m_accept;
770     wxString           *m_res;
771     wxString            m_startValue;
772     bool                m_finished;  // true==deleting, don't process events anymore
773 
774     DECLARE_EVENT_TABLE()
775 };
776 
777 
778 //-----------------------------------------------------------------------------
779 
780 // list of per-column attributes for an item (wxTreeListItem)
781 // since there can be very many of these, we save size by chosing
782 // the smallest representation for the elements and by ordering
783 // the members to avoid padding.
784 class  wxTreeListItemCellAttr
785 {
786 public:
wxTreeListItemCellAttr()787     wxTreeListItemCellAttr() {
788         m_attr = NULL;
789         m_data = NULL;
790         m_isBold = 0;
791         m_isBoldSet = 0;
792         m_ownsAttr = 0;
793         m_image = NO_IMAGE;
794     };
~wxTreeListItemCellAttr()795     ~wxTreeListItemCellAttr() {
796         if (m_ownsAttr) delete m_attr;
797     }
798 
799     // generic attribute from wxWidgets lib
800     wxTreeItemAttr      *m_attr;
801 
802     // other attributes
803     wxTreeItemData      *m_data;        // user-provided data
804     short                m_image;       // images for the various columns (!= main)
805     int                  m_isBold :1;   // render the label in bold font
806     int                  m_isBoldSet :1;   // was 'm_isBold' set ?
807     int                  m_ownsAttr :1; // delete attribute when done
808 };
809 
810 
811 //-----------------------------------------------------------------------------
812 
813 // a tree item (NOTE: this class is storage only, does not generate events)
814 class  wxTreeListItem
815 {
816 public:
817     // ctors & dtor
818     // ------------
wxTreeListItem()819     wxTreeListItem() { m_toolTip = NULL; }
820     wxTreeListItem( wxTreeListMainWindow *owner,
821                     wxTreeListItem *parent,
822                     const wxArrayString& text,
823                     int image,
824                     int selImage,
825                     wxTreeItemData *data );
826 
827     ~wxTreeListItem();
828 
829 
830     // accessors (most properties have a default at row/item level)
831     // ---------
GetChildren()832     wxArrayTreeListItems& GetChildren() { return m_children; }
833 
834 //    const wxString GetText (          ) const { return GetText(m_owner->GetMainColumn());  }
GetText(int column) const835     const wxString GetText (int column) const
836     {
837         if ( IsVirtual() )   return m_owner->GetItemText( m_props_row.m_data, column );
838         if (column < (signed)m_text.GetCount()) return m_text[column];
839         return wxEmptyString;
840     };
841 
GetImage(wxTreeItemIcon which=wxTreeItemIcon_Normal) const842     int GetImage (            wxTreeItemIcon which = wxTreeItemIcon_Normal) const { return m_images[which]; };
GetImage(int column,wxTreeItemIcon which=wxTreeItemIcon_Normal) const843     int GetImage (int column, wxTreeItemIcon which = wxTreeItemIcon_Normal) const
844     {
845         // main column is special, more images available
846         if(column == m_owner->GetMainColumn()) return m_images[which];
847 
848         // other columns ignore the 'which' parameter
849         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
850         if (entry == m_props_cell.end()) return NO_IMAGE;
851         return entry->second->m_image;
852     };
853 
854     // data is special: it has a default value at row/item level
GetData() const855     wxTreeItemData *GetData()           const { return m_props_row.m_data; };
GetData(int column) const856     wxTreeItemData *GetData(int column) const {
857         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
858         if (entry == m_props_cell.end()) return NULL;
859         return entry->second->m_data;
860     };
861 
GetToolTip() const862     const wxString * GetToolTip() const  {  return m_toolTip;  };
863 
864     // returns the current image for the item (depending on its
865     // selected/expanded/whatever state)
866     int GetCurrentImage() const;
867 
868 
869     // modifiers (most properties have a default at row/item level)
870     // ---------
SetHasPlus(bool has=true)871     void SetHasPlus(bool has = true) { m_hasPlus = has; };
872 
SetText(int column,const wxString & text)873     void SetText (int column, const wxString& text)
874     {
875         if (column < (int)m_text.GetCount()) {
876             m_text[column] = text;
877         } else if (column < m_owner->GetColumnCount()) {
878             int howmany = m_owner->GetColumnCount();
879             for (int i = (int)m_text.GetCount(); i < howmany; ++i) m_text.Add (wxEmptyString);
880             m_text[column] = text;
881         }
882     };
SetImage(int image,wxTreeItemIcon which)883     void SetImage (            int image, wxTreeItemIcon which) { m_images[which] = image; };
SetImage(int column,int image,wxTreeItemIcon which)884     void SetImage (int column, int image, wxTreeItemIcon which)
885     {
886         // main column is special, more images available
887         if (column == m_owner->GetMainColumn()) m_images[which] = image;
888         // other columns ignore the 'which' parameter
889         else {
890             wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
891             if (entry == m_props_cell.end()) {
892                 m_props_cell[column] = new wxTreeListItemCellAttr();
893                 m_props_cell[column]->m_image = image;
894             } else {
895                 entry->second->m_image = image;
896             }
897         }
898     };
899 
900     // data is special: it has a default value at row/item level
SetData(wxTreeItemData * data)901     void SetData(            wxTreeItemData *data) { m_props_row.m_data = data; };
SetData(int column,wxTreeItemData * data)902     void SetData(int column, wxTreeItemData *data)
903     {
904         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
905         if (entry == m_props_cell.end()) {
906             m_props_cell[column] = new wxTreeListItemCellAttr();
907             m_props_cell[column]->m_data = data;
908         } else {
909             entry->second->m_data = data;
910         }
911     }
912 
SetBold(bool bold)913     void SetBold(            bool bold) { m_props_row.m_isBold = bold; }
SetBold(int column,bool bold)914     void SetBold(int column, bool bold)
915     {
916         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
917         if (entry == m_props_cell.end()) {
918             m_props_cell[column] = new wxTreeListItemCellAttr();
919             m_props_cell[column]->m_isBold = bold;
920             m_props_cell[column]->m_isBoldSet = 1;
921         } else {
922             entry->second->m_isBold = bold;
923             entry->second->m_isBoldSet = 1;
924         }
925     }
926 
927 
SetToolTip(const wxString & tip)928     void SetToolTip(const wxString &tip) {
929         if (m_toolTip)  { delete m_toolTip; m_toolTip = NULL; }
930         if (tip.length() > 0) { m_toolTip = new wxString(tip); }
931     };
932 
933 
934     // status inquiries
935     // ----------------
HasChildren() const936     bool HasChildren() const        { return !m_children.IsEmpty(); }
IsSelected() const937     bool IsSelected()  const        { return m_hasHilight != 0; }
IsExpanded() const938     bool IsExpanded()  const        { return !m_isCollapsed; }
HasPlus() const939     bool HasPlus()     const        { return m_hasPlus || HasChildren(); }
IsBold() const940     bool IsBold()      const        { return m_props_row.m_isBold; }
IsBold(int column) const941     bool IsBold(int column) const
942     {
943         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
944         if (entry == m_props_cell.end() || ! entry->second->m_isBoldSet) return IsBold();
945         return (entry->second->m_isBold != 0);
946     }
IsVirtual() const947     bool IsVirtual()   const        { return m_owner->IsVirtual(); }
948 
949 
950 
GetX() const951     int GetX() const { return m_x; }
GetY() const952     int GetY() const { return m_y; }
953 
SetX(int x)954     void SetX (int x) { m_x = x; }
SetY(int y)955     void SetY (int y) { m_y = y; }
956 
GetHeight() const957     int  GetHeight() const { return m_height; }
GetWidth() const958     int  GetWidth()  const { return m_width; }
959 
SetHeight(int height)960     void SetHeight (int height) { m_height = height; }
SetWidth(int width)961     void SetWidth (int width) { m_width = width; }
962 
GetTextX() const963     int GetTextX() const { return m_text_x; }
SetTextX(int text_x)964     void SetTextX (int text_x) { m_text_x = text_x; }
965 
GetItemParent() const966     wxTreeListItem *GetItemParent() const { return m_parent; }
967 
968     // get count of all children (and grand children if 'recursively')
969     size_t GetChildrenCount(bool recursively = true) const;
970 
971     void GetSize( int &x, int &y, const wxTreeListMainWindow* );
972 
973     // return the item at given position (or NULL if no item), onButton is
974     // true if the point belongs to the item's button, otherwise it lies
975     // on the button's label
976     wxTreeListItem *HitTest (const wxPoint& point,
977                              const wxTreeListMainWindow *,
978                              int &flags, int& column, int level);
979 
980 
981     // operations
982     // ----------
983     // deletes all children
984     void DeleteChildren();
985 
Insert(wxTreeListItem * child,size_t index)986     void Insert(wxTreeListItem *child, size_t index)
987     { m_children.Insert(child, index); }
988 
Expand()989     void Expand() { m_isCollapsed = false; }
Collapse()990     void Collapse() { m_isCollapsed = true; }
991 
SetHilight(bool set=true)992     void SetHilight( bool set = true ) { m_hasHilight = set; }
993 
994 
995     // attributes
996     // ----------
997 
998     // get them - may be NULL (used to read attributes)
999     // NOTE: fall back on default at row/item level is not defined for cell
GetAttributes(int column) const1000     wxTreeItemAttr *GetAttributes(int column) const
1001     {
1002         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
1003         if (entry == m_props_cell.end()) return GetAttributes();
1004         return entry->second->m_attr;
1005     }
GetAttributes() const1006     wxTreeItemAttr *GetAttributes() const { return m_props_row.m_attr; }
1007 
1008     // get them ensuring that the pointer is not NULL (used to write attributes)
Attr(int column)1009     wxTreeItemAttr& Attr(int column) {
1010         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
1011         if (entry == m_props_cell.end()) {
1012             m_props_cell[column] = new wxTreeListItemCellAttr();
1013             m_props_cell[column]->m_attr = new wxTreeItemAttr;
1014             m_props_cell[column]->m_ownsAttr = 1;
1015             return *(m_props_cell[column]->m_attr);
1016         } else {
1017             return *(entry->second->m_attr);
1018         }
1019     }
Attr()1020     wxTreeItemAttr& Attr()
1021     {
1022         if ( !m_props_row.m_attr )
1023         {
1024             m_props_row.m_attr = new wxTreeItemAttr;
1025             m_props_row.m_ownsAttr = 1;
1026         }
1027         return *m_props_row.m_attr;
1028     }
1029 /* ----- unused -----
1030     // set them
1031     void SetAttributes(wxTreeItemAttr *attr)
1032     {
1033         if ( m_props_row.m_ownsAttr ) delete m_props_row.m_attr;
1034         m_props_row.m_attr = attr;
1035         m_props_row.m_ownsAttr = 0;
1036     }
1037     // set them and delete when done
1038     void AssignAttributes(wxTreeItemAttr *attr)
1039     {
1040         SetAttributes(attr);
1041         m_props_row.m_ownsAttr = 1;
1042     }
1043 */
1044 
1045 private:
1046     wxTreeListMainWindow       *m_owner;        // control the item belongs to
1047 
1048     wxArrayTreeListItems        m_children;     // list of children
1049     wxTreeListItem             *m_parent;       // parent of this item
1050 
1051     // main column item positions
1052     wxCoord                     m_x;            // (virtual) offset from left (vertical line)
1053     wxCoord                     m_y;            // (virtual) offset from top
1054     wxCoord                     m_text_x;       // item offset from left
1055     short                       m_width;        // width of this item
1056     unsigned char               m_height;       // height of this item
1057 
1058     // for the normal, selected, expanded and expanded+selected states
1059     short                       m_images[wxTreeItemIcon_Max];
1060     // currently there is no tooltip at cell level
1061     wxString                   *m_toolTip;
1062 
1063     // use bitfields to save size
1064     int                         m_isCollapsed :1;
1065     int                         m_hasHilight  :1; // same as focused
1066     int                         m_hasPlus     :1; // used for item which doesn't have
1067                                                     // children but has a [+] button
1068 
1069     // here are all the properties which can be set per column
1070     wxArrayString               m_text;        // labels to be rendered for item
1071     wxTreeListItemCellAttr      m_props_row;   // default at row/item level for: data, attr
1072     wxTreeListItemCellAttrHash  m_props_cell;
1073 };
1074 
1075 
1076 // ===========================================================================
1077 // implementation
1078 // ===========================================================================
1079 
1080 // ---------------------------------------------------------------------------
1081 // wxTreeListRenameTimer (internal)
1082 // ---------------------------------------------------------------------------
1083 
wxTreeListRenameTimer(wxTreeListMainWindow * owner)1084 wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow *owner )
1085 {
1086     m_owner = owner;
1087 }
1088 
Notify()1089 void wxTreeListRenameTimer::Notify()
1090 {
1091     m_owner->OnRenameTimer();
1092 }
1093 
1094 //-----------------------------------------------------------------------------
1095 // wxEditTextCtrl (internal)
1096 //-----------------------------------------------------------------------------
1097 
BEGIN_EVENT_TABLE(wxEditTextCtrl,wxTextCtrl)1098 BEGIN_EVENT_TABLE (wxEditTextCtrl,wxTextCtrl)
1099     EVT_CHAR           (wxEditTextCtrl::OnChar)
1100     EVT_KEY_UP         (wxEditTextCtrl::OnKeyUp)
1101     EVT_KILL_FOCUS     (wxEditTextCtrl::OnKillFocus)
1102 END_EVENT_TABLE()
1103 
1104 wxEditTextCtrl::wxEditTextCtrl (wxWindow *parent,
1105                                 const wxWindowID id,
1106                                 bool *accept,
1107                                 wxString *res,
1108                                 wxTreeListMainWindow *owner,
1109                                 const wxString &value,
1110                                 const wxPoint &pos,
1111                                 const wxSize &size,
1112                                 int style,
1113                                 const wxValidator& validator,
1114                                 const wxString &name)
1115     : wxTextCtrl (parent, id, value, pos, size, style | wxSIMPLE_BORDER, validator, name)
1116 {
1117     m_res = res;
1118     m_accept = accept;
1119     m_owner = owner;
1120     (*m_accept) = false;
1121     (*m_res) = wxEmptyString;
1122     m_startValue = value;
1123     m_finished = false;
1124 }
1125 
~wxEditTextCtrl()1126 wxEditTextCtrl::~wxEditTextCtrl() {
1127     EndEdit(true); // cancelled
1128 }
1129 
EndEdit(bool isCancelled)1130 void wxEditTextCtrl::EndEdit(bool isCancelled) {
1131     if (m_finished) return;
1132     m_finished = true;
1133 
1134     if (m_owner) {
1135         (*m_accept) = ! isCancelled;
1136         (*m_res) = isCancelled ? m_startValue : GetValue();
1137         m_owner->OnRenameAccept(*m_res == m_startValue);
1138         m_owner->m_editControl = NULL;
1139         m_owner->m_editItem = NULL;
1140         m_owner->SetFocus(); // This doesn't work. TODO.
1141         m_owner = NULL;
1142     }
1143 
1144     Destroy();
1145 }
1146 
Destroy()1147 bool wxEditTextCtrl::Destroy() {
1148     Hide();
1149 #if wxCHECK_VERSION(3, 0, 0)
1150     wxTheApp->ScheduleForDestruction(this);
1151 #else
1152     wxTheApp->GetTraits()->ScheduleForDestroy(this);
1153 #endif
1154     return true;
1155 }
1156 
OnChar(wxKeyEvent & event)1157 void wxEditTextCtrl::OnChar( wxKeyEvent &event )
1158 {
1159     if (m_finished)
1160     {
1161         event.Skip();
1162         return;
1163     }
1164     if (event.GetKeyCode() == WXK_RETURN)
1165     {
1166         EndEdit(false);  // not cancelled
1167         return;
1168     }
1169     if (event.GetKeyCode() == WXK_ESCAPE)
1170     {
1171         EndEdit(true);  // cancelled
1172         return;
1173     }
1174     event.Skip();
1175 }
1176 
OnKeyUp(wxKeyEvent & event)1177 void wxEditTextCtrl::OnKeyUp( wxKeyEvent &event )
1178 {
1179     if (m_finished)
1180     {
1181         event.Skip();
1182         return;
1183     }
1184 
1185     // auto-grow the textctrl:
1186     wxSize parentSize = m_owner->GetSize();
1187     wxPoint myPos = GetPosition();
1188     wxSize mySize = GetSize();
1189     int sx, sy;
1190     GetTextExtent(GetValue() + _T("M"), &sx, &sy);
1191     if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
1192     if (mySize.x > sx) sx = mySize.x;
1193     SetSize(sx, -1);
1194 
1195     event.Skip();
1196 }
1197 
OnKillFocus(wxFocusEvent & event)1198 void wxEditTextCtrl::OnKillFocus( wxFocusEvent &event )
1199 {
1200     if (m_finished)
1201     {
1202         event.Skip();
1203         return;
1204     }
1205 
1206     EndEdit(false);  // not cancelled
1207 }
1208 
1209 //-----------------------------------------------------------------------------
1210 //  wxTreeListHeaderWindow
1211 //-----------------------------------------------------------------------------
1212 
1213 IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow,wxWindow);
1214 
BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow)1215 BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow)
1216     EVT_PAINT         (wxTreeListHeaderWindow::OnPaint)
1217     EVT_ERASE_BACKGROUND(wxTreeListHeaderWindow::OnEraseBackground) // reduce flicker
1218     EVT_MOUSE_EVENTS  (wxTreeListHeaderWindow::OnMouse)
1219     EVT_SET_FOCUS     (wxTreeListHeaderWindow::OnSetFocus)
1220 END_EVENT_TABLE()
1221 
1222 
1223 void wxTreeListHeaderWindow::Init()
1224 {
1225     m_currentCursor = (wxCursor *) NULL;
1226     m_isDragging = false;
1227     m_dirty = false;
1228     m_total_col_width = 0;
1229 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1230     m_hotTrackCol = -1;
1231 #endif
1232 
1233     // prevent any background repaint in order to reducing flicker
1234     SetBackgroundStyle(wxBG_STYLE_CUSTOM);
1235 }
1236 
wxTreeListHeaderWindow()1237 wxTreeListHeaderWindow::wxTreeListHeaderWindow()
1238 {
1239     Init();
1240 
1241     m_owner = (wxTreeListMainWindow *) NULL;
1242     m_resizeCursor = (wxCursor *) NULL;
1243 }
1244 
wxTreeListHeaderWindow(wxWindow * win,wxWindowID id,wxTreeListMainWindow * owner,const wxPoint & pos,const wxSize & size,long style,const wxString & name)1245 wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow *win,
1246                                                 wxWindowID id,
1247                                                 wxTreeListMainWindow *owner,
1248                                                 const wxPoint& pos,
1249                                                 const wxSize& size,
1250                                                 long style,
1251                                                 const wxString &name )
1252     : wxWindow( win, id, pos, size, style, name )
1253 {
1254     Init();
1255 
1256     m_owner = owner;
1257     m_resizeCursor = new wxCursor(wxCURSOR_SIZEWE);
1258 
1259     SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE));
1260 }
1261 
~wxTreeListHeaderWindow()1262 wxTreeListHeaderWindow::~wxTreeListHeaderWindow()
1263 {
1264     delete m_resizeCursor;
1265 }
1266 
DoDrawRect(wxDC * dc,int x,int y,int w,int h)1267 void wxTreeListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
1268 {
1269     wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
1270 
1271     const int m_corner = 1;
1272 
1273     dc->SetBrush( *wxTRANSPARENT_BRUSH );
1274 #if defined( __WXMAC__  )
1275     dc->SetPen (pen);
1276 #else // !GTK, !Mac
1277     dc->SetPen( *wxBLACK_PEN );
1278 #endif
1279     dc->DrawLine( x+w-m_corner+1, y, x+w, y+h );  // right (outer)
1280     dc->DrawRectangle( x, y+h, w+1, 1 );          // bottom (outer)
1281 
1282 #if defined( __WXMAC__  )
1283     pen = wxPen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
1284 #endif
1285     dc->SetPen( pen );
1286     dc->DrawLine( x+w-m_corner, y, x+w-1, y+h );  // right (inner)
1287     dc->DrawRectangle( x+1, y+h-1, w-2, 1 );      // bottom (inner)
1288 
1289     dc->SetPen( *wxWHITE_PEN );
1290     dc->DrawRectangle( x, y, w-m_corner+1, 1 );   // top (outer)
1291     dc->DrawRectangle( x, y, 1, h );              // left (outer)
1292     dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1293     dc->DrawLine( x+w-1, y, x+w-1, y+1 );
1294 }
1295 
1296 // shift the DC origin to match the position of the main window horz
1297 // scrollbar: this allows us to always use logical coords
AdjustDC(wxDC & dc)1298 void wxTreeListHeaderWindow::AdjustDC(wxDC& dc)
1299 {
1300     int xpix;
1301     m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1302     int x;
1303     m_owner->GetViewStart( &x, NULL );
1304 
1305     // account for the horz scrollbar offset
1306     dc.SetDeviceOrigin( -x * xpix, 0 );
1307 }
1308 
OnPaint(wxPaintEvent & WXUNUSED (event))1309 void wxTreeListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1310 {
1311     wxAutoBufferedPaintDC dc( this );
1312     AdjustDC( dc );
1313 
1314     int x = HEADER_OFFSET_X;
1315 
1316     // width and height of the entire header window
1317     int w, h;
1318     GetClientSize( &w, &h );
1319     m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1320     dc.SetBackgroundMode(wxTRANSPARENT);
1321 
1322 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1323     int numColumns = GetColumnCount();
1324     for ( int i = 0; i < numColumns && x < w; i++ )
1325     {
1326         if (!IsColumnShown (i)) continue; // do next column if not shown
1327 
1328         wxHeaderButtonParams params;
1329 
1330         // TODO: columnInfo should have label colours...
1331         params.m_labelColour = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
1332         params.m_labelFont = GetFont();
1333 
1334         wxTreeListColumnInfo& column = GetColumn(i);
1335         int wCol = column.GetWidth();
1336         int flags = 0;
1337         wxRect rect(x, 0, wCol, h);
1338         x += wCol;
1339 
1340         if ( i == m_hotTrackCol)
1341             flags |= wxCONTROL_CURRENT;
1342 
1343         params.m_labelText = column.GetText();
1344         params.m_labelAlignment = column.GetAlignment();
1345 
1346         int image = column.GetImage();
1347         wxImageList* imageList = m_owner->GetImageList();
1348         if ((image != -1) && imageList)
1349             params.m_labelBitmap = imageList->GetBitmap(image);
1350 
1351         wxRendererNative::Get().DrawHeaderButton(this, dc, rect, flags, wxHDR_SORT_ICON_NONE, &params);
1352     }
1353 
1354     if (x < w) {
1355         wxRect rect(x, 0, w-x, h);
1356         wxRendererNative::Get().DrawHeaderButton(this, dc, rect);
1357     }
1358 
1359 #else  // not 2.7.0.1+
1360 
1361     dc.SetFont( GetFont() );
1362 
1363     // do *not* use the listctrl colour for headers - one day we will have a
1364     // function to set it separately
1365     //dc.SetTextForeground( *wxBLACK );
1366     dc.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ));
1367 
1368     int numColumns = GetColumnCount();
1369     for ( int i = 0; i < numColumns && x < w; i++ )
1370     {
1371         if (!IsColumnShown (i)) continue; // do next column if not shown
1372 
1373         wxTreeListColumnInfo& column = GetColumn(i);
1374         int wCol = column.GetWidth();
1375 
1376         // the width of the rect to draw: make it smaller to fit entirely
1377         // inside the column rect
1378         int cw = wCol - 2;
1379 
1380         wxRect rect(x, HEADER_OFFSET_Y, cw, h-2);
1381         wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect);
1382 
1383         // if we have an image, draw it on the right of the label
1384         int image = column.GetImage(); //item.m_image;
1385         int ix = -2, iy = 0;
1386         wxImageList* imageList = m_owner->GetImageList();
1387         if ((image != -1) && imageList) {
1388             imageList->GetSize (image, ix, iy);
1389         }
1390 
1391         // extra margins around the text label
1392         int text_width = 0;
1393         int text_x = x;
1394         int image_offset = cw - ix - 1;
1395 
1396         switch(column.GetAlignment()) {
1397         case wxALIGN_LEFT:
1398             text_x += EXTRA_WIDTH;
1399             cw -= ix + 2;
1400             break;
1401         case wxALIGN_RIGHT:
1402             dc.GetTextExtent (column.GetText(), &text_width, NULL);
1403             text_x += cw - text_width - EXTRA_WIDTH - MARGIN;
1404             image_offset = 0;
1405             break;
1406         case wxALIGN_CENTER:
1407             dc.GetTextExtent(column.GetText(), &text_width, NULL);
1408             text_x += (cw - text_width)/2 + ix + 2;
1409             image_offset = (cw - text_width - ix - 2)/2 - MARGIN;
1410             break;
1411         }
1412 
1413         // draw the image
1414         if ((image != -1) && imageList) {
1415             imageList->Draw (image, dc, x + image_offset/*cw - ix - 1*/,
1416                              HEADER_OFFSET_Y + (h - 4 - iy)/2,
1417                              wxIMAGELIST_DRAW_TRANSPARENT);
1418         }
1419 
1420         // draw the text clipping it so that it doesn't overwrite the column boundary
1421         wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
1422         dc.DrawText (column.GetText(), text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT );
1423 
1424         // next column
1425         x += wCol;
1426     }
1427 
1428     int more_w = m_owner->GetSize().x - x - HEADER_OFFSET_X;
1429     if (more_w > 0) {
1430         wxRect rect (x, HEADER_OFFSET_Y, more_w, h-2);
1431         wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect);
1432     }
1433 
1434 #endif // 2.7.0.1
1435 }
1436 
DrawCurrent()1437 void wxTreeListHeaderWindow::DrawCurrent()
1438 {
1439     int x1 = m_currentX;
1440     int y1 = 0;
1441     ClientToScreen (&x1, &y1);
1442 
1443     int x2 = m_currentX-1;
1444 #ifdef __WXMSW__
1445     ++x2; // but why ????
1446 #endif
1447     int y2 = 0;
1448     m_owner->GetClientSize( NULL, &y2 );
1449     m_owner->ClientToScreen( &x2, &y2 );
1450 
1451     wxScreenDC dc;
1452     dc.SetLogicalFunction (wxINVERT);
1453     dc.SetPen (wxPen (*wxBLACK, 2, wxSOLID));
1454     dc.SetBrush (*wxTRANSPARENT_BRUSH);
1455 
1456     AdjustDC(dc);
1457     dc.DrawLine (x1, y1, x2, y2);
1458     dc.SetLogicalFunction (wxCOPY);
1459     dc.SetPen (wxNullPen);
1460     dc.SetBrush (wxNullBrush);
1461 }
1462 
1463 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
XToCol(int x)1464 int wxTreeListHeaderWindow::XToCol(int x)
1465 {
1466     int colLeft = 0;
1467     int numColumns = GetColumnCount();
1468     for ( int col = 0; col < numColumns; col++ )
1469     {
1470         if (!IsColumnShown(col)) continue;
1471         wxTreeListColumnInfo& column = GetColumn(col);
1472 
1473         if ( x < (colLeft + column.GetWidth()) )
1474              return col;
1475 
1476         colLeft += column.GetWidth();
1477     }
1478     return -1;
1479 }
1480 
RefreshColLabel(int col)1481 void wxTreeListHeaderWindow::RefreshColLabel(int col)
1482 {
1483     if ( col > GetColumnCount() )
1484         return;
1485 
1486     int x = 0;
1487     int width = 0;
1488     int idx = 0;
1489     do {
1490         if (!IsColumnShown(idx)) continue;
1491         wxTreeListColumnInfo& column = GetColumn(idx);
1492         x += width;
1493         width = column.GetWidth();
1494     } while (++idx <= col);
1495 
1496     m_owner->CalcScrolledPosition(x, 0, &x, NULL);
1497     RefreshRect(wxRect(x, 0, width, GetSize().GetHeight()));
1498 }
1499 #endif
1500 
OnMouse(wxMouseEvent & event)1501 void wxTreeListHeaderWindow::OnMouse (wxMouseEvent &event) {
1502 
1503     // we want to work with logical coords
1504     int x;
1505     m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1506 
1507 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1508     if ( event.Moving() )
1509     {
1510         int col = XToCol(x);
1511         if ( col != m_hotTrackCol )
1512         {
1513             // Refresh the col header so it will be painted with hot tracking
1514             // (if supported by the native renderer.)
1515             RefreshColLabel(col);
1516 
1517             // Also refresh the old hot header
1518             if ( m_hotTrackCol >= 0 )
1519                 RefreshColLabel(m_hotTrackCol);
1520 
1521             m_hotTrackCol = col;
1522         }
1523     }
1524 
1525     if ( event.Leaving() && m_hotTrackCol >= 0 )
1526     {
1527         // Leaving the window so clear any hot tracking indicator that may be present
1528         RefreshColLabel(m_hotTrackCol);
1529         m_hotTrackCol = -1;
1530     }
1531 #endif
1532 
1533     if (m_isDragging) {
1534 
1535         SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
1536 
1537         // we don't draw the line beyond our window, but we allow dragging it
1538         // there
1539         int w = 0;
1540         GetClientSize( &w, NULL );
1541         m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1542         w -= 6;
1543 
1544         // erase the line if it was drawn
1545         if (m_currentX < w) DrawCurrent();
1546 
1547         if (event.ButtonUp()) {
1548             m_isDragging = false;
1549             if (HasCapture()) ReleaseMouse();
1550             m_dirty = true;
1551             SetColumnWidth (m_column, m_currentX - m_minX);
1552             Refresh();
1553             SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
1554         }else{
1555             m_currentX = wxMax (m_minX + 7, x);
1556 
1557             // draw in the new location
1558             if (m_currentX < w) DrawCurrent();
1559         }
1560 
1561     }else{ // not dragging
1562 
1563         m_minX = 0;
1564         bool hit_border = false;
1565 
1566         // end of the current column
1567         int xpos = 0;
1568 
1569         // find the column where this event occured
1570         int countCol = GetColumnCount();
1571         for (int column = 0; column < countCol; column++) {
1572             if (!IsColumnShown (column)) continue; // do next if not shown
1573 
1574             xpos += GetColumnWidth (column);
1575             m_column = column;
1576             if (abs (x-xpos) < 3) {
1577                 // near the column border
1578                 hit_border = true;
1579                 break;
1580             }
1581 
1582             if (x < xpos) {
1583                 // inside the column
1584                 break;
1585             }
1586 
1587             m_minX = xpos;
1588         }
1589 
1590         if (event.LeftDown() || event.RightUp()) {
1591             m_owner->EndEdit(true);  // cancelled
1592 
1593             if (hit_border && event.LeftDown()) {
1594                 m_isDragging = true;
1595                 CaptureMouse();
1596                 m_currentX = x;
1597                 DrawCurrent();
1598                 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition());
1599             }else{ // click on a column
1600                 wxEventType evt = event.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK:
1601                                                     wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
1602                 SendListEvent (evt, event.GetPosition());
1603             }
1604         }else if (event.LeftDClick() && hit_border) {
1605             SetColumnWidth (m_column, m_owner->GetBestColumnWidth (m_column));
1606             Refresh();
1607 
1608         }else if (event.Moving()) {
1609             bool setCursor;
1610             if (hit_border) {
1611                 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
1612                 m_currentCursor = m_resizeCursor;
1613             }else{
1614                 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
1615                 m_currentCursor = wxSTANDARD_CURSOR;
1616             }
1617             if (setCursor) SetCursor (*m_currentCursor);
1618         }
1619 
1620     }
1621 }
1622 
OnSetFocus(wxFocusEvent & WXUNUSED (event))1623 void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent &WXUNUSED(event)) {
1624     m_owner->SetFocus();
1625 }
1626 
SendListEvent(wxEventType type,wxPoint pos)1627 void wxTreeListHeaderWindow::SendListEvent (wxEventType type, wxPoint pos) {
1628     wxWindow *parent = GetParent();
1629     wxListEvent le (type, parent->GetId());
1630     le.SetEventObject (parent);
1631     le.m_pointDrag = pos;
1632 
1633     // the position should be relative to the parent window, not
1634     // this one for compatibility with MSW and common sense: the
1635     // user code doesn't know anything at all about this header
1636     // window, so why should it get positions relative to it?
1637     le.m_pointDrag.y -= GetSize().y;
1638     le.m_col = m_column;
1639     parent->GetEventHandler()->ProcessEvent (le);
1640 }
1641 
AddColumn(const wxTreeListColumnInfo & colInfo)1642 void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo& colInfo) {
1643     m_columns.Add (colInfo);
1644     m_total_col_width += colInfo.GetWidth();
1645     m_owner->AdjustMyScrollbars();
1646     m_owner->m_dirty = true;
1647 }
1648 
SetColumnWidth(int column,int width)1649 void wxTreeListHeaderWindow::SetColumnWidth (int column, int width) {
1650     wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1651     m_total_col_width -= m_columns[column].GetWidth();
1652     m_columns[column].SetWidth(width);
1653     m_total_col_width += width;
1654     m_owner->AdjustMyScrollbars();
1655     m_owner->m_dirty = true;
1656 }
1657 
InsertColumn(int before,const wxTreeListColumnInfo & colInfo)1658 void wxTreeListHeaderWindow::InsertColumn (int before, const wxTreeListColumnInfo& colInfo) {
1659     wxCHECK_RET ((before >= 0) && (before < GetColumnCount()), _T("Invalid column"));
1660     m_columns.Insert (colInfo, before);
1661     m_total_col_width += colInfo.GetWidth();
1662     m_owner->AdjustMyScrollbars();
1663     m_owner->m_dirty = true;
1664 }
1665 
RemoveColumn(int column)1666 void wxTreeListHeaderWindow::RemoveColumn (int column) {
1667     wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1668     m_total_col_width -= m_columns[column].GetWidth();
1669     m_columns.RemoveAt (column);
1670     m_owner->AdjustMyScrollbars();
1671     m_owner->m_dirty = true;
1672 }
1673 
SetColumn(int column,const wxTreeListColumnInfo & info)1674 void wxTreeListHeaderWindow::SetColumn (int column, const wxTreeListColumnInfo& info) {
1675     wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1676     int w = m_columns[column].GetWidth();
1677     m_columns[column] = info;
1678     if (w != info.GetWidth()) {
1679         m_total_col_width += info.GetWidth() - w;
1680         m_owner->AdjustMyScrollbars();
1681     }
1682     m_owner->m_dirty = true;
1683 }
1684 
1685 // ---------------------------------------------------------------------------
1686 // wxTreeListItem
1687 // ---------------------------------------------------------------------------
1688 
wxTreeListItem(wxTreeListMainWindow * owner,wxTreeListItem * parent,const wxArrayString & text,int image,int selImage,wxTreeItemData * data)1689 wxTreeListItem::wxTreeListItem (wxTreeListMainWindow *owner,
1690                                 wxTreeListItem *parent,
1691                                 const wxArrayString& text,
1692                                 int image, int selImage,
1693                                 wxTreeItemData *data)
1694               : m_text (text) {
1695 
1696     m_images[wxTreeItemIcon_Normal] = image;
1697     m_images[wxTreeItemIcon_Selected] = selImage;
1698     m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
1699     m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
1700 
1701     m_props_row.m_data = data;
1702     m_toolTip = NULL;
1703     m_x = 0;
1704     m_y = 0;
1705     m_text_x = 0;
1706 
1707     m_isCollapsed = true;
1708     m_hasHilight = false;
1709     m_hasPlus = false;
1710 
1711     m_owner = owner;
1712     m_parent = parent;
1713 
1714     // We don't know the height here yet.
1715     m_width = 0;
1716     m_height = 0;
1717 }
1718 
~wxTreeListItem()1719 wxTreeListItem::~wxTreeListItem() {
1720     if (m_toolTip) delete m_toolTip;
1721 
1722     wxTreeListItemCellAttrHash::iterator entry = m_props_cell.begin();
1723     while (entry != m_props_cell.end()) {
1724         if (entry->second) delete entry->second;
1725         entry++;
1726     }
1727 
1728     wxASSERT_MSG( m_children.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1729 }
1730 
DeleteChildren()1731 void wxTreeListItem::DeleteChildren () {
1732     m_children.Empty();
1733 }
1734 
GetChildrenCount(bool recursively) const1735 size_t wxTreeListItem::GetChildrenCount (bool recursively) const {
1736     size_t count = m_children.Count();
1737     if (!recursively) return count;
1738 
1739     size_t total = count;
1740     for (size_t n = 0; n < count; ++n) {
1741         total += m_children[n]->GetChildrenCount();
1742     }
1743     return total;
1744 }
1745 
GetSize(int & x,int & y,const wxTreeListMainWindow * theButton)1746 void wxTreeListItem::GetSize (int &x, int &y, const wxTreeListMainWindow *theButton) {
1747     int bottomY = m_y + theButton->GetLineHeight (this);
1748     if (y < bottomY) y = bottomY;
1749     int width = m_x +  m_width;
1750     if ( x < width ) x = width;
1751 
1752     if (IsExpanded()) {
1753         size_t count = m_children.Count();
1754         for (size_t n = 0; n < count; ++n ) {
1755             m_children[n]->GetSize (x, y, theButton);
1756         }
1757     }
1758 }
1759 
HitTest(const wxPoint & point,const wxTreeListMainWindow * theCtrl,int & flags,int & column,int level)1760 wxTreeListItem *wxTreeListItem::HitTest (const wxPoint& point,
1761                                          const wxTreeListMainWindow *theCtrl,
1762                                          int &flags, int& column, int level) {
1763 
1764     // reset any previous hit infos
1765     flags = 0;
1766     column = -1;
1767 
1768     // for a hidden root node, don't evaluate it, but do evaluate children
1769     if (!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) {
1770 
1771         wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow();
1772 
1773         // check for right of all columns (outside)
1774         if (point.x > header_win->GetWidth()) return (wxTreeListItem*) NULL;
1775         // else find column
1776         for (int x = 0, j = 0; j < theCtrl->GetColumnCount(); ++j) {
1777             if (!header_win->IsColumnShown(j)) continue;
1778             int w = header_win->GetColumnWidth (j);
1779             if (point.x >= x && point.x < x+w) {
1780                 column = j;
1781                 break;
1782             }
1783             x += w;
1784         }
1785 
1786         // evaluate if y-pos is okay
1787         int h = theCtrl->GetLineHeight (this);
1788         if ((point.y >= m_y) && (point.y <= m_y + h)) {
1789 
1790             // check for above/below middle
1791             int y_mid = m_y + h/2;
1792             if (point.y < y_mid) {
1793                 flags |= wxTREE_HITTEST_ONITEMUPPERPART;
1794             }else{
1795                 flags |= wxTREE_HITTEST_ONITEMLOWERPART;
1796             }
1797 
1798             // check for button hit
1799             if (HasPlus() && theCtrl->HasButtons()) {
1800                 int bntX = m_x - theCtrl->m_btnWidth2;
1801                 int bntY = y_mid - theCtrl->m_btnHeight2;
1802                 if ((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) &&
1803                     (point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) {
1804                     flags |= wxTREE_HITTEST_ONITEMBUTTON;
1805                     return this;
1806                 }
1807             }
1808 
1809             // check for image hit
1810             if (theCtrl->m_imgWidth > 0) {
1811                 int imgX = m_text_x - theCtrl->m_imgWidth - MARGIN;
1812                 int imgY = y_mid - theCtrl->m_imgHeight2;
1813                 if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) &&
1814                     (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) {
1815                     flags |= wxTREE_HITTEST_ONITEMICON;
1816                     return this;
1817                 }
1818             }
1819 
1820             // check for label hit
1821             if ((point.x >= m_text_x) && (point.x <= (m_text_x + m_width))) {
1822                 flags |= wxTREE_HITTEST_ONITEMLABEL;
1823                 return this;
1824             }
1825 
1826             // check for indent hit after button and image hit
1827             if (point.x < m_x) {
1828                 flags |= wxTREE_HITTEST_ONITEMINDENT;
1829 // Ronan, 2008.07.17: removed, not consistent               column = -1; // considered not belonging to main column
1830                 return this;
1831             }
1832 
1833             // check for right of label
1834             int end = 0;
1835             for (int i = 0; i <= theCtrl->GetMainColumn(); ++i) end += header_win->GetColumnWidth (i);
1836             if ((point.x > (m_text_x + m_width)) && (point.x <= end)) {
1837                 flags |= wxTREE_HITTEST_ONITEMRIGHT;
1838 // Ronan, 2008.07.17: removed, not consistent                column = -1; // considered not belonging to main column
1839                 return this;
1840             }
1841 
1842             // else check for each column except main
1843             if (column >= 0 && column != theCtrl->GetMainColumn()) {
1844                 flags |= wxTREE_HITTEST_ONITEMCOLUMN;
1845                 return this;
1846             }
1847 
1848             // no special flag or column found
1849             return this;
1850 
1851         }
1852 
1853         // if children not expanded, return no item
1854         if (!IsExpanded()) return (wxTreeListItem*) NULL;
1855     }
1856 
1857     // in any case evaluate children
1858     wxTreeListItem *child;
1859     size_t count = m_children.Count();
1860     for (size_t n = 0; n < count; n++) {
1861         child = m_children[n]->HitTest (point, theCtrl, flags, column, level+1);
1862         if (child) return child;
1863     }
1864 
1865     // not found
1866     return (wxTreeListItem*) NULL;
1867 }
1868 
GetCurrentImage() const1869 int wxTreeListItem::GetCurrentImage() const {
1870     int image = NO_IMAGE;
1871     if (IsExpanded()) {
1872         if (IsSelected()) {
1873             image = GetImage (wxTreeItemIcon_SelectedExpanded);
1874         }else{
1875             image = GetImage (wxTreeItemIcon_Expanded);
1876         }
1877     }else{ // not expanded
1878         if (IsSelected()) {
1879             image = GetImage (wxTreeItemIcon_Selected);
1880         }else{
1881             image = GetImage (wxTreeItemIcon_Normal);
1882         }
1883     }
1884 
1885     // maybe it doesn't have the specific image, try the default one instead
1886     if (image == NO_IMAGE) image = GetImage();
1887 
1888     return image;
1889 }
1890 
1891 // ---------------------------------------------------------------------------
1892 // wxTreeListMainWindow implementation
1893 // ---------------------------------------------------------------------------
1894 
IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow,wxScrolledWindow)1895 IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow)
1896 
1897 BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow)
1898     EVT_PAINT          (wxTreeListMainWindow::OnPaint)
1899     EVT_ERASE_BACKGROUND(wxTreeListMainWindow::OnEraseBackground) // to reduce flicker
1900     EVT_MOUSE_EVENTS   (wxTreeListMainWindow::OnMouse)
1901     EVT_CHAR           (wxTreeListMainWindow::OnChar)
1902     EVT_SET_FOCUS      (wxTreeListMainWindow::OnSetFocus)
1903     EVT_KILL_FOCUS     (wxTreeListMainWindow::OnKillFocus)
1904     EVT_IDLE           (wxTreeListMainWindow::OnIdle)
1905     EVT_SCROLLWIN      (wxTreeListMainWindow::OnScroll)
1906     EVT_MOUSE_CAPTURE_LOST(wxTreeListMainWindow::OnCaptureLost)
1907 END_EVENT_TABLE()
1908 
1909 
1910 // ---------------------------------------------------------------------------
1911 // construction/destruction
1912 // ---------------------------------------------------------------------------
1913 
1914 
1915 void wxTreeListMainWindow::Init() {
1916 
1917     m_rootItem = (wxTreeListItem*)NULL;
1918     m_curItem = (wxTreeListItem*)NULL;
1919     m_shiftItem = (wxTreeListItem*)NULL;
1920     m_editItem = (wxTreeListItem*)NULL;
1921     m_selectItem = (wxTreeListItem*)NULL;
1922 
1923     m_curColumn = -1; // no current column
1924 
1925     m_hasFocus = false;
1926     m_dirty = false;
1927 
1928     m_lineHeight = LINEHEIGHT;
1929     m_indent = MININDENT; // min. indent
1930     m_linespacing = 4;
1931 
1932     m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
1933     m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
1934 
1935     m_imageListNormal = (wxImageList *) NULL;
1936     m_imageListButtons = (wxImageList *) NULL;
1937     m_imageListState = (wxImageList *) NULL;
1938     m_ownsImageListNormal = m_ownsImageListButtons =
1939     m_ownsImageListState = false;
1940 
1941     m_imgWidth = 0, m_imgWidth2 = 0;
1942     m_imgHeight = 0, m_imgHeight2 = 0;
1943     m_btnWidth = 0, m_btnWidth2 = 0;
1944     m_btnHeight = 0, m_btnHeight2 = 0;
1945 
1946     m_isDragStarted = m_isDragging = false;
1947     m_dragItem = NULL;
1948     m_dragCol = -1;
1949 
1950     m_editTimer = new wxTreeListRenameTimer (this);
1951     m_editControl = NULL;
1952 
1953     m_lastOnSame = false;
1954     m_left_down_selection = false;
1955 
1956     m_findTimer = new wxTimer (this, -1);
1957 
1958 #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
1959     m_normalFont.MacCreateThemeFont (kThemeViewsFont);
1960 #else
1961     m_normalFont = wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT);
1962 #endif
1963     m_boldFont = wxFont( m_normalFont.GetPointSize(),
1964                          m_normalFont.GetFamily(),
1965                          m_normalFont.GetStyle(),
1966                          wxFONTWEIGHT_BOLD,
1967                          m_normalFont.GetUnderlined(),
1968                          m_normalFont.GetFaceName(),
1969                          m_normalFont.GetEncoding());
1970 
1971     m_toolTip.clear();
1972     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed
1973     m_isItemToolTip = false;  // so far no item-specific tooltip
1974 }
1975 
Create(wxTreeListCtrl * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)1976 bool wxTreeListMainWindow::Create (wxTreeListCtrl *parent,
1977                                    wxWindowID id,
1978                                    const wxPoint& pos,
1979                                    const wxSize& size,
1980                                    long style,
1981                                    const wxValidator &validator,
1982                                    const wxString& name) {
1983 
1984 #ifdef __WXMAC__
1985     style &= ~wxTR_LINES_AT_ROOT;
1986     style |= wxTR_NO_LINES;
1987 #endif
1988 
1989     wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
1990 
1991 #if wxUSE_VALIDATORS
1992     SetValidator(validator);
1993 #endif
1994 
1995     SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX));
1996     // prevent any background repaint in order to reducing flicker
1997     SetBackgroundStyle(wxBG_STYLE_CUSTOM);
1998 
1999 #ifdef __WXMSW__
2000     {
2001         int i, j;
2002         wxBitmap bmp(8, 8);
2003         wxMemoryDC bdc;
2004         bdc.SelectObject(bmp);
2005         bdc.SetPen(*wxGREY_PEN);
2006         bdc.DrawRectangle(-1, -1, 10, 10);
2007         for (i = 0; i < 8; i++) {
2008             for (j = 0; j < 8; j++) {
2009                 if (!((i + j) & 1)) {
2010                     bdc.DrawPoint(i, j);
2011                 }
2012             }
2013         }
2014 
2015         m_dottedPen = wxPen(bmp, 1);
2016     }
2017 #else
2018 //?    m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT );  // too slow under XFree86
2019     m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
2020 #endif
2021 
2022     m_owner = parent;
2023     m_main_column = 0;
2024 
2025     return true;
2026 }
2027 
~wxTreeListMainWindow()2028 wxTreeListMainWindow::~wxTreeListMainWindow() {
2029     delete m_hilightBrush;
2030     delete m_hilightUnfocusedBrush;
2031 
2032     delete m_editTimer;
2033     delete m_findTimer;
2034     if (m_ownsImageListNormal) delete m_imageListNormal;
2035     if (m_ownsImageListState) delete m_imageListState;
2036     if (m_ownsImageListButtons) delete m_imageListButtons;
2037 
2038     if (m_editControl) {
2039         m_editControl->SetOwner(NULL);    // prevent control from calling us during delete
2040         delete m_editControl;
2041     }
2042 
2043     DeleteRoot();
2044 }
2045 
2046 
2047 //-----------------------------------------------------------------------------
2048 // accessors
2049 //-----------------------------------------------------------------------------
2050 
GetCount() const2051 size_t wxTreeListMainWindow::GetCount() const {
2052     return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount();
2053 }
2054 
SetIndent(unsigned int indent)2055 void wxTreeListMainWindow::SetIndent (unsigned int indent) {
2056     m_indent = wxMax ((unsigned)MININDENT, indent);
2057     m_dirty = true;
2058 }
2059 
SetLineSpacing(unsigned int spacing)2060 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) {
2061     m_linespacing = spacing;
2062     m_dirty = true;
2063     CalculateLineHeight();
2064 }
2065 
GetChildrenCount(const wxTreeItemId & item,bool recursively)2066 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item,
2067                                                bool recursively) {
2068     wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item"));
2069     return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively);
2070 }
2071 
SetWindowStyle(const long styles)2072 void wxTreeListMainWindow::SetWindowStyle (const long styles) {
2073     // change to selection mode, reset selection
2074     if ((styles ^ m_windowStyle) & wxTR_MULTIPLE) { UnselectAll(); }
2075     // right now, just sets the styles.  Eventually, we may
2076     // want to update the inherited styles, but right now
2077     // none of the parents has updatable styles
2078     m_windowStyle = styles;
2079     m_dirty = true;
2080 }
2081 
SetToolTip(const wxString & tip)2082 void wxTreeListMainWindow::SetToolTip(const wxString& tip) {
2083     m_isItemToolTip = false;
2084     m_toolTip = tip;
2085     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed (force refresh)
2086 }
SetToolTip(wxToolTip * tip)2087 void wxTreeListMainWindow::SetToolTip(wxToolTip *tip) {
2088     m_isItemToolTip = false;
2089     m_toolTip = (tip == NULL) ? wxString() : tip->GetTip();
2090     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed (force refresh)
2091 }
2092 
SetItemToolTip(const wxTreeItemId & item,const wxString & tip)2093 void wxTreeListMainWindow::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
2094     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2095     m_isItemToolTip = true;
2096     ((wxTreeListItem*) item.m_pItem)->SetToolTip(tip);
2097     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed (force refresh)
2098 }
2099 
2100 
2101 //-----------------------------------------------------------------------------
2102 // functions to work with tree items
2103 //-----------------------------------------------------------------------------
2104 
GetItemImage(const wxTreeItemId & item,int column,wxTreeItemIcon which) const2105 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column, wxTreeItemIcon which) const {
2106     wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item"));
2107     return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which);
2108 }
2109 
GetItemData(const wxTreeItemId & item) const2110 wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const {
2111     wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
2112     return ((wxTreeListItem*) item.m_pItem)->GetData();
2113 }
GetItemData(const wxTreeItemId & item,int column) const2114 wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item, int column) const {
2115     wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
2116     return ((wxTreeListItem*) item.m_pItem)->GetData(column);
2117 }
2118 
GetItemBold(const wxTreeItemId & item) const2119 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const {
2120     wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
2121     return ((wxTreeListItem *)item.m_pItem)->IsBold();
2122 }
GetItemBold(const wxTreeItemId & item,int column) const2123 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item, int column) const {
2124     wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
2125     return ((wxTreeListItem *)item.m_pItem)->IsBold(column);
2126 }
2127 
GetItemTextColour(const wxTreeItemId & item) const2128 wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const {
2129     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2130     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2131     wxTreeItemAttr *attr = pItem->GetAttributes();
2132     if (attr && attr->HasTextColour()) {
2133         return attr->GetTextColour();
2134     } else {
2135         return GetForegroundColour();
2136     }
2137 }
GetItemTextColour(const wxTreeItemId & item,int column) const2138 wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item, int column) const {
2139     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2140     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2141     wxTreeItemAttr *attr = pItem->GetAttributes(column);
2142     if (attr && attr->HasTextColour()) {
2143         return attr->GetTextColour();
2144     } else {
2145         return GetItemTextColour(item);
2146     }
2147 }
2148 
GetItemBackgroundColour(const wxTreeItemId & item) const2149 wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const {
2150     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2151     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2152     wxTreeItemAttr *attr = pItem->GetAttributes();
2153     if (attr && attr->HasBackgroundColour()) {
2154         return attr->GetBackgroundColour();
2155     } else {
2156         return GetBackgroundColour();
2157     }
2158 }
GetItemBackgroundColour(const wxTreeItemId & item,int column) const2159 wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item, int column) const {
2160     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2161     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2162     wxTreeItemAttr *attr = pItem->GetAttributes(column);
2163     if (attr && attr->HasBackgroundColour()) {
2164         return attr->GetBackgroundColour();
2165     } else {
2166         return GetItemBackgroundColour(item);
2167     }
2168 }
2169 
GetItemFont(const wxTreeItemId & item) const2170 wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const {
2171     wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
2172     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2173     wxTreeItemAttr *attr = pItem->GetAttributes();
2174     if (attr && attr->HasFont()) {
2175         return attr->GetFont();
2176     }else if (pItem->IsBold()) {
2177         return m_boldFont;
2178     } else {
2179         return m_normalFont;
2180     }
2181 }
GetItemFont(const wxTreeItemId & item,int column) const2182 wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item, int column) const {
2183     wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
2184     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2185     wxTreeItemAttr *attr_cell = pItem->GetAttributes(column);
2186     wxTreeItemAttr *attr_row = pItem->GetAttributes();
2187     if (attr_cell && attr_cell->HasFont()) {
2188         return attr_cell->GetFont();
2189     } else if (attr_row && attr_row->HasFont()) {
2190         return attr_row->GetFont();
2191     } else if (pItem->IsBold(column)) {
2192         return m_boldFont;
2193     } else {
2194         return m_normalFont;
2195     }
2196 }
2197 
SetItemHasChildren(const wxTreeItemId & item,bool has)2198 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item, bool has) {
2199     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2200     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2201     pItem->SetHasPlus (has);
2202     RefreshLine (pItem);
2203 }
2204 
SetItemImage(const wxTreeItemId & item,int column,int image,wxTreeItemIcon which)2205 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column, int image, wxTreeItemIcon which) {
2206     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2207     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2208     pItem->SetImage (column, image, which);
2209     wxClientDC dc (this);
2210     CalculateSize (pItem, dc);
2211     RefreshLine (pItem);
2212 }
2213 
SetItemData(const wxTreeItemId & item,wxTreeItemData * data)2214 void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item,             wxTreeItemData *data) {
2215     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2216     ((wxTreeListItem*) item.m_pItem)->SetData(data);
2217 }
SetItemData(const wxTreeItemId & item,int column,wxTreeItemData * data)2218 void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item, int column, wxTreeItemData *data) {
2219     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2220     ((wxTreeListItem*) item.m_pItem)->SetData(column, data);
2221 }
2222 
SetItemBold(const wxTreeItemId & item,bool bold)2223 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item,             bool bold) {
2224     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2225     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2226     if (pItem->IsBold() != bold) { // avoid redrawing if no real change
2227         pItem->SetBold (bold);
2228         RefreshLine (pItem);
2229     }
2230 }
SetItemBold(const wxTreeItemId & item,int column,bool bold)2231 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, int column, bool bold) {
2232     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2233     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2234 //    if (pItem->IsBold(column) != bold) { // avoid redrawing if no real change
2235         pItem->SetBold (column, bold);
2236         RefreshLine (pItem);
2237 //    }
2238 }
2239 
SetItemTextColour(const wxTreeItemId & item,const wxColour & colour)2240 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item,             const wxColour& colour) {
2241     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2242     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2243     pItem->Attr().SetTextColour (colour);
2244     RefreshLine (pItem);
2245 }
SetItemTextColour(const wxTreeItemId & item,int column,const wxColour & colour)2246 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item, int column, const wxColour& colour) {
2247     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2248     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2249     pItem->Attr(column).SetTextColour (colour);
2250     RefreshLine (pItem);
2251 }
2252 
SetItemBackgroundColour(const wxTreeItemId & item,const wxColour & colour)2253 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item,             const wxColour& colour) {
2254     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2255     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2256     pItem->Attr().SetBackgroundColour (colour);
2257     RefreshLine (pItem);
2258 }
SetItemBackgroundColour(const wxTreeItemId & item,int column,const wxColour & colour)2259 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item, int column, const wxColour& colour) {
2260     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2261     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2262     pItem->Attr(column).SetBackgroundColour (colour);
2263     RefreshLine (pItem);
2264 }
2265 
SetItemFont(const wxTreeItemId & item,const wxFont & font)2266 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item,             const wxFont& font) {
2267     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2268     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2269     pItem->Attr().SetFont (font);
2270     RefreshLine (pItem);
2271 }
SetItemFont(const wxTreeItemId & item,int column,const wxFont & font)2272 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item, int column, const wxFont& font) {
2273     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2274     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2275     pItem->Attr(column).SetFont (font);
2276     RefreshLine (pItem);
2277 }
2278 
2279 
SetFont(const wxFont & font)2280 bool wxTreeListMainWindow::SetFont (const wxFont &font) {
2281     wxScrolledWindow::SetFont (font);
2282     m_normalFont = font;
2283     m_boldFont = wxFont (m_normalFont.GetPointSize(),
2284                          m_normalFont.GetFamily(),
2285                          m_normalFont.GetStyle(),
2286                          wxFONTWEIGHT_BOLD,
2287                          m_normalFont.GetUnderlined(),
2288                          m_normalFont.GetFaceName());
2289     CalculateLineHeight();
2290     return true;
2291 }
2292 
2293 
2294 // ----------------------------------------------------------------------------
2295 // item status inquiries
2296 // ----------------------------------------------------------------------------
2297 
IsVisible(const wxTreeItemId & item,bool fullRow,bool within) const2298 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
2299     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2300 
2301     // An item is only visible if it's not a descendant of a collapsed item
2302     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2303     wxTreeListItem* parent = pItem->GetItemParent();
2304     while (parent) {
2305         if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break;
2306         if (!parent->IsExpanded()) return false;
2307         parent = parent->GetItemParent();
2308     }
2309 
2310     // and the item is only visible if it is currently (fully) within the view
2311     if (within) {
2312         wxSize clientSize = GetClientSize();
2313         wxRect rect;
2314         if ((!GetBoundingRect (item, rect)) ||
2315             ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
2316             (rect.GetTop() < 0 || rect.GetBottom() >= clientSize.y) ||
2317             (!fullRow && (rect.GetLeft() < 0 || rect.GetRight() >= clientSize.x))) return false;
2318     }
2319 
2320     return true;
2321 }
2322 
HasChildren(const wxTreeItemId & item) const2323 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const {
2324     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2325 
2326     // consider that the item does have children if it has the "+" button: it
2327     // might not have them (if it had never been expanded yet) but then it
2328     // could have them as well and it's better to err on this side rather than
2329     // disabling some operations which are restricted to the items with
2330     // children for an item which does have them
2331     return ((wxTreeListItem*) item.m_pItem)->HasPlus();
2332 }
2333 
IsExpanded(const wxTreeItemId & item) const2334 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const {
2335     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2336     return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
2337 }
2338 
IsSelected(const wxTreeItemId & item) const2339 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const {
2340     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2341     return ((wxTreeListItem*) item.m_pItem)->IsSelected();
2342 }
2343 
IsBold(const wxTreeItemId & item,int column) const2344 bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item, int column) const {
2345     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2346     return ((wxTreeListItem*) item.m_pItem)->IsBold(column);
2347 }
2348 
2349 // ----------------------------------------------------------------------------
2350 // navigation
2351 // ----------------------------------------------------------------------------
2352 
GetItemParent(const wxTreeItemId & item) const2353 wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const {
2354     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2355     return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
2356 }
2357 
GetFirstChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const2358 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2359                                                   wxTreeItemIdValue& cookie) const {
2360     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2361     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2362     cookie = 0;
2363     return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId();
2364 }
2365 
GetNextChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const2366 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2367                                                  wxTreeItemIdValue& cookie) const {
2368     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2369     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2370     // it's ok to cast cookie to long, we never have indices which overflow "void*"
2371     long *pIndex = ((long*)&cookie);
2372     return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId();
2373 }
2374 
GetPrevChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const2375 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2376                                                  wxTreeItemIdValue& cookie) const {
2377     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2378     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2379     // it's ok to cast cookie to long, we never have indices which overflow "void*"
2380     long *pIndex = (long*)&cookie;
2381     return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId();
2382 }
2383 
GetLastChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const2384 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2385                                                  wxTreeItemIdValue& cookie) const {
2386     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2387     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2388     // it's ok to cast cookie to long, we never have indices which overflow "void*"
2389     long *pIndex = ((long*)&cookie);
2390     (*pIndex) = (long)children.Count();
2391     return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId();
2392 }
2393 
GetNextSibling(const wxTreeItemId & item) const2394 wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const {
2395     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2396 
2397     // get parent
2398     wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2399     wxTreeListItem *parent = i->GetItemParent();
2400     if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2401 
2402     // get index
2403     wxArrayTreeListItems& siblings = parent->GetChildren();
2404     size_t index = siblings.Index (i);
2405     wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2406     return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId();
2407 }
2408 
GetPrevSibling(const wxTreeItemId & item) const2409 wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const {
2410     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2411 
2412     // get parent
2413     wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2414     wxTreeListItem *parent = i->GetItemParent();
2415     if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2416 
2417     // get index
2418     wxArrayTreeListItems& siblings = parent->GetChildren();
2419     size_t index = siblings.Index(i);
2420     wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2421     return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId();
2422 }
2423 
2424 // Only for internal use right now, but should probably be public
GetNext(const wxTreeItemId & item,bool fulltree) const2425 wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const {
2426     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2427 
2428     // if there are any children, return first child
2429     if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2430         wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2431         if (children.GetCount() > 0) return children.Item (0);
2432     }
2433 
2434     // get sibling of this item or of the ancestors instead
2435     wxTreeItemId next;
2436     wxTreeItemId parent = item;
2437     do {
2438         next = GetNextSibling (parent);
2439         parent = GetItemParent (parent);
2440     } while (!next.IsOk() && parent.IsOk());
2441     return next;
2442 }
2443 
2444 // Only for internal use right now, but should probably be public
GetPrev(const wxTreeItemId & item,bool fulltree) const2445 wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const {
2446     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2447 
2448     // if there are no previous sibling get parent
2449     wxTreeItemId prev = GetPrevSibling (item);
2450     if (! prev.IsOk()) return GetItemParent (item);
2451 
2452     // while previous sibling has children, return last
2453     while (fulltree || ((wxTreeListItem*)prev.m_pItem)->IsExpanded()) {
2454         wxArrayTreeListItems& children = ((wxTreeListItem*)prev.m_pItem)->GetChildren();
2455         if (children.GetCount() == 0) break;
2456         prev = children.Item (children.GetCount() - 1);
2457     }
2458 
2459     return prev;
2460 }
2461 
GetFirstExpandedItem() const2462 wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
2463     return GetNextExpanded (GetRootItem());
2464 }
2465 
GetNextExpanded(const wxTreeItemId & item) const2466 wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const {
2467     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2468     return GetNext (item, false);
2469 }
2470 
GetPrevExpanded(const wxTreeItemId & item) const2471 wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const {
2472     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2473     return GetPrev (item, false);
2474 }
2475 
GetFirstVisible(bool fullRow,bool within) const2476 wxTreeItemId wxTreeListMainWindow::GetFirstVisible(bool fullRow, bool within) const {
2477     if (HasFlag(wxTR_HIDE_ROOT) || ! IsVisible(GetRootItem(), fullRow, within)) {
2478         return GetNextVisible (GetRootItem(), fullRow, within);
2479     } else {
2480         return GetRootItem();
2481     }
2482 }
2483 
GetNextVisible(const wxTreeItemId & item,bool fullRow,bool within) const2484 wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
2485     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2486     wxTreeItemId id = GetNext (item, false);
2487     while (id.IsOk()) {
2488         if (IsVisible (id, fullRow, within)) return id;
2489         id = GetNext (id, false);
2490     }
2491     return wxTreeItemId();
2492 }
2493 
GetLastVisible(bool fullRow,bool within) const2494 wxTreeItemId wxTreeListMainWindow::GetLastVisible ( bool fullRow, bool within) const {
2495     wxCHECK_MSG (GetRootItem().IsOk(), wxTreeItemId(), _T("invalid tree item"));
2496     wxTreeItemId id = GetRootItem();
2497     wxTreeItemId res = id;
2498     while ((id = GetNext (id, false)).IsOk()) {
2499         if (IsVisible (id, fullRow, within)) res = id;
2500     }
2501     return res;
2502 }
2503 
GetPrevVisible(const wxTreeItemId & item,bool fullRow,bool within) const2504 wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
2505     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2506     wxTreeItemId id = GetPrev (item, true);
2507     while (id.IsOk()) {
2508         if (IsVisible (id, fullRow, within)) return id;
2509         id = GetPrev(id, true);
2510     }
2511     return wxTreeItemId();
2512 }
2513 
2514 // ----------------------------------------------------------------------------
2515 // operations
2516 // ----------------------------------------------------------------------------
2517 
2518 // ----------------------------  ADD OPERATION  -------------------------------
2519 
DoInsertItem(const wxTreeItemId & parentId,size_t previous,const wxString & text,int image,int selImage,wxTreeItemData * data)2520 wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId,
2521                                                  size_t previous,
2522                                                  const wxString& text,
2523                                                  int image, int selImage,
2524                                                  wxTreeItemData *data) {
2525     wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2526     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2527     m_dirty = true; // do this first so stuff below doesn't cause flicker
2528 
2529     wxArrayString arr;
2530     arr.Alloc (GetColumnCount());
2531     for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2532     arr[m_main_column] = text;
2533     wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data);
2534     if (data != NULL) {
2535         data->SetId (item);
2536     }
2537     parent->Insert (item, previous);
2538 
2539     return item;
2540 }
2541 
AddRoot(const wxString & text,int image,int selImage,wxTreeItemData * data)2542 wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text,
2543                                             int image, int selImage,
2544                                             wxTreeItemData *data) {
2545     wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
2546     wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2547     m_dirty = true; // do this first so stuff below doesn't cause flicker
2548 
2549     wxArrayString arr;
2550     arr.Alloc (GetColumnCount());
2551     for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2552     arr[m_main_column] = text;
2553     m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data);
2554     if (data != NULL) {
2555         data->SetId(m_rootItem);
2556     }
2557     if (HasFlag(wxTR_HIDE_ROOT)) {
2558         // if we will hide the root, make sure children are visible
2559         m_rootItem->SetHasPlus();
2560         m_rootItem->Expand();
2561         wxTreeItemIdValue cookie = 0;
2562         SetCurrentItem(GetFirstChild(m_rootItem, cookie));
2563     }
2564     return m_rootItem;
2565 }
2566 
PrependItem(const wxTreeItemId & parent,const wxString & text,int image,int selImage,wxTreeItemData * data)2567 wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent,
2568                                                 const wxString& text,
2569                                                 int image, int selImage,
2570                                                 wxTreeItemData *data) {
2571     return DoInsertItem (parent, 0u, text, image, selImage, data);
2572 }
2573 
InsertItem(const wxTreeItemId & parentId,const wxTreeItemId & idPrevious,const wxString & text,int image,int selImage,wxTreeItemData * data)2574 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2575                                                const wxTreeItemId& idPrevious,
2576                                                const wxString& text,
2577                                                int image, int selImage,
2578                                                wxTreeItemData *data) {
2579     wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2580     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2581 
2582     int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
2583     wxASSERT_MSG( index != wxNOT_FOUND,
2584                   _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
2585 
2586     return DoInsertItem (parentId, ++index, text, image, selImage, data);
2587 }
2588 
InsertItem(const wxTreeItemId & parentId,size_t before,const wxString & text,int image,int selImage,wxTreeItemData * data)2589 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2590                                                size_t before,
2591                                                const wxString& text,
2592                                                int image, int selImage,
2593                                                wxTreeItemData *data) {
2594     wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2595     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2596 
2597     return DoInsertItem (parentId, before, text, image, selImage, data);
2598 }
2599 
AppendItem(const wxTreeItemId & parentId,const wxString & text,int image,int selImage,wxTreeItemData * data)2600 wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId,
2601                                                const wxString& text,
2602                                                int image, int selImage,
2603                                                wxTreeItemData *data) {
2604     wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
2605     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2606 
2607     return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data);
2608 }
2609 
2610 
2611 // --------------------------  DELETE OPERATION  ------------------------------
2612 
Delete(const wxTreeItemId & itemId)2613 void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
2614     if (! itemId.IsOk()) return;
2615     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2616     wxTreeListItem *parent = item->GetItemParent();
2617     wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
2618 
2619     // recursive delete
2620     DoDeleteItem(item);
2621 
2622     // update parent --CAUTION: must come after delete itself, so that item's
2623     //  siblings may be found
2624     if (parent) {
2625         parent->GetChildren().Remove (item);  // remove by value
2626     }
2627 }
2628 
2629 
DeleteRoot()2630 void wxTreeListMainWindow::DeleteRoot() {
2631     if (! m_rootItem) return;
2632 
2633     SetCurrentItem((wxTreeListItem*)NULL);
2634     m_selectItem = (wxTreeListItem*)NULL;
2635     m_shiftItem = (wxTreeListItem*)NULL;
2636 
2637     DeleteChildren (m_rootItem);
2638     SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, m_rootItem);
2639     delete m_rootItem; m_rootItem = NULL;
2640 }
2641 
2642 
DeleteChildren(const wxTreeItemId & itemId)2643 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
2644     if (! itemId.IsOk()) return;
2645     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2646 
2647     // recursive delete on all children, starting from the right to prevent
2648     //  multiple selection changes (see m_curItem handling in DoDeleteItem() )
2649     wxArrayTreeListItems& children = item->GetChildren();
2650     for (size_t n = children.GetCount(); n>0; n--) {
2651         DoDeleteItem(children[n-1]);
2652         // immediately remove child from array, otherwise it might get selected
2653         // as current item (see m_curItem handling in DoDeleteItem() )
2654         children.RemoveAt(n-1);
2655     }
2656 }
2657 
2658 
DoDeleteItem(wxTreeListItem * item)2659 void wxTreeListMainWindow::DoDeleteItem(wxTreeListItem *item) {
2660     wxCHECK_RET (item, _T("invalid item for delete!"));
2661 
2662     m_dirty = true; // do this first so stuff below doesn't cause flicker
2663 
2664     // cancel any editing
2665 
2666     if (m_editControl) { m_editControl->EndEdit(true); }  // cancelled
2667 
2668     // cancel any dragging
2669     if (item == m_dragItem) {
2670         // stop dragging
2671         m_isDragStarted = m_isDragging = false;
2672         if (HasCapture()) ReleaseMouse();
2673     }
2674 
2675     // don't stay with invalid m_curItem: take next sibling or reset to NULL
2676     // NOTE: this might be slighty inefficient when deleting a whole tree
2677     //  but has the advantage that all deletion side-effects are handled here
2678     if (item == m_curItem) {
2679         SetCurrentItem(item->GetItemParent());
2680         if (m_curItem) {
2681             wxArrayTreeListItems& siblings = m_curItem->GetChildren();
2682             size_t index = siblings.Index (item);
2683             wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2684             SetCurrentItem(index < siblings.Count()-1 ? siblings[index+1]: (wxTreeListItem*)NULL);
2685         }
2686     }
2687     // don't stay with invalid m_shiftItem: reset it to NULL
2688     if (item == m_shiftItem) m_shiftItem = (wxTreeListItem*)NULL;
2689     // don't stay with invalid m_selectItem: default to current item
2690     if (item == m_selectItem) {
2691         m_selectItem = m_curItem;
2692         SelectItem(m_selectItem, (wxTreeItemId*)NULL, true);  // unselect others
2693     }
2694 
2695     // recurse children, starting from the right to prevent multiple selection
2696     //  changes (see m_curItem handling above)
2697     wxArrayTreeListItems& children = item->GetChildren();
2698     for (size_t n = children.GetCount(); n>0; n--) {
2699         DoDeleteItem(children[n-1]);
2700         // immediately remove child from array, otherwise it might get selected
2701         // as current item (see m_curItem handling above)
2702         children.RemoveAt(n-1);
2703     }
2704 
2705     // delete item itself
2706     SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, item);
2707     delete item;
2708 }
2709 
2710 
2711 // ----------------------------------------------------------------------------
2712 
SetCurrentItem(const wxTreeItemId & itemId)2713 void wxTreeListMainWindow::SetCurrentItem(const wxTreeItemId& itemId) {
2714   SetCurrentItem((wxTreeListItem *)(itemId ? itemId.m_pItem : NULL));
2715 }
SetCurrentItem(wxTreeListItem * item)2716 void wxTreeListMainWindow::SetCurrentItem(wxTreeListItem *item) {
2717 wxTreeListItem *old_item;
2718 
2719     old_item = m_curItem; m_curItem = item;
2720 
2721     // change of item, redraw previous
2722     if (old_item != NULL && old_item != item) {
2723         RefreshLine(old_item);
2724     }
2725 
2726 }
2727 
2728 // ----------------------------------------------------------------------------
2729 
Expand(const wxTreeItemId & itemId)2730 void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
2731     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2732     wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
2733 
2734     if (!item->HasPlus() || item->IsExpanded()) return;
2735 
2736     // send event to user code
2737     wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, 0);
2738     event.SetInt(m_curColumn);
2739     if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // expand canceled
2740 
2741     item->Expand();
2742     m_dirty = true;
2743 
2744     // send event to user code
2745     event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
2746     SendEvent(0, NULL, &event);
2747 }
2748 
ExpandAll(const wxTreeItemId & itemId)2749 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
2750     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
2751 
2752     Expand (itemId);
2753     if (!IsExpanded (itemId)) return;
2754     wxTreeItemIdValue cookie;
2755     wxTreeItemId child = GetFirstChild (itemId, cookie);
2756     while (child.IsOk()) {
2757         ExpandAll (child);
2758         child = GetNextChild (itemId, cookie);
2759     }
2760 }
2761 
Collapse(const wxTreeItemId & itemId)2762 void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
2763     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2764     wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
2765 
2766     if (!item->HasPlus() || !item->IsExpanded()) return;
2767 
2768     // send event to user code
2769     wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 0 );
2770     event.SetInt(m_curColumn);
2771     if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // collapse canceled
2772 
2773     item->Collapse();
2774     m_dirty = true;
2775 
2776     // send event to user code
2777     event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
2778     SendEvent(0, NULL, &event);
2779 }
2780 
CollapseAndReset(const wxTreeItemId & item)2781 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
2782     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2783 
2784     Collapse (item);
2785     DeleteChildren (item);
2786 }
2787 
Toggle(const wxTreeItemId & itemId)2788 void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
2789     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
2790 
2791     if (IsExpanded (itemId)) {
2792         Collapse (itemId);
2793     }else{
2794         Expand (itemId);
2795     }
2796 }
2797 
Unselect()2798 void wxTreeListMainWindow::Unselect() {
2799     if (m_selectItem) {
2800         m_selectItem->SetHilight (false);
2801         RefreshLine (m_selectItem);
2802         m_selectItem = (wxTreeListItem*)NULL;
2803     }
2804 }
2805 
UnselectAllChildren(wxTreeListItem * item)2806 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
2807     wxCHECK_RET (item, _T("invalid tree item"));
2808 
2809     if (item->IsSelected()) {
2810         item->SetHilight (false);
2811         RefreshLine (item);
2812         if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
2813         if (item != m_curItem) m_lastOnSame = false;  // selection change, so reset edit marker
2814     }
2815     if (item->HasChildren()) {
2816         wxArrayTreeListItems& children = item->GetChildren();
2817         size_t count = children.Count();
2818         for (size_t n = 0; n < count; ++n) {
2819             UnselectAllChildren (children[n]);
2820         }
2821     }
2822 }
2823 
UnselectAll()2824 void wxTreeListMainWindow::UnselectAll() {
2825     UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
2826 }
2827 
2828 // Recursive function !
2829 // To stop we must have crt_item<last_item
2830 // Algorithm :
2831 // Tag all next children, when no more children,
2832 // Move to parent (not to tag)
2833 // Keep going... if we found last_item, we stop.
TagNextChildren(wxTreeListItem * crt_item,wxTreeListItem * last_item)2834 bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem *crt_item,
2835                                             wxTreeListItem *last_item) {
2836     wxTreeListItem *parent = crt_item->GetItemParent();
2837 
2838     if (!parent) {// This is root item
2839         return TagAllChildrenUntilLast (crt_item, last_item);
2840     }
2841 
2842     wxArrayTreeListItems& children = parent->GetChildren();
2843     int index = children.Index(crt_item);
2844     wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2845 
2846     if ((parent->HasChildren() && parent->IsExpanded()) ||
2847         ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
2848         size_t count = children.Count();
2849         for (size_t n = (index+1); n < count; ++n) {
2850             if (TagAllChildrenUntilLast (children[n], last_item)) return true;
2851         }
2852     }
2853 
2854     return TagNextChildren (parent, last_item);
2855 }
2856 
TagAllChildrenUntilLast(wxTreeListItem * crt_item,wxTreeListItem * last_item)2857 bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem *crt_item,
2858                                                     wxTreeListItem *last_item) {
2859     crt_item->SetHilight (true);
2860     RefreshLine(crt_item);
2861 
2862     if (crt_item==last_item) return true;
2863 
2864     if (crt_item->HasChildren() && crt_item->IsExpanded()) {
2865         wxArrayTreeListItems& children = crt_item->GetChildren();
2866         size_t count = children.Count();
2867         for (size_t n = 0; n < count; ++n) {
2868             if (TagAllChildrenUntilLast (children[n], last_item)) return true;
2869         }
2870     }
2871 
2872     return false;
2873 }
2874 
SelectItem(const wxTreeItemId & itemId,const wxTreeItemId & lastId,bool unselect_others)2875 bool wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
2876                                        const wxTreeItemId& lastId,
2877                                        bool unselect_others) {
2878 
2879     wxTreeListItem *item = itemId.IsOk() ? (wxTreeListItem*) itemId.m_pItem : NULL;
2880 
2881     // send selecting event to the user code
2882     wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
2883     event.SetInt(m_curColumn);
2884     event.SetOldItem (m_curItem);
2885     if (SendEvent(0, item, &event) && !event.IsAllowed()) return false;  // veto on selection change
2886 
2887     // unselect all if unselect other items
2888     bool bUnselectedAll = false; // see that UnselectAll is done only once
2889     if (unselect_others) {
2890         if (HasFlag(wxTR_MULTIPLE)) {
2891             UnselectAll(); bUnselectedAll = true;
2892         }else{
2893             Unselect(); // to speed up thing
2894         }
2895     }
2896 
2897     // select item range
2898     if (lastId.IsOk() && itemId.IsOk() && (itemId != lastId)) {
2899 
2900         if (! bUnselectedAll) UnselectAll();
2901         wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
2902 
2903         // ensure that the position of the item it calculated in any case
2904         if (m_dirty) CalculatePositions();
2905 
2906         // select item range according Y-position
2907         if (last->GetY() < item->GetY()) {
2908             if (!TagAllChildrenUntilLast (last, item)) {
2909                 TagNextChildren (last, item);
2910             }
2911         }else{
2912             if (!TagAllChildrenUntilLast (item, last)) {
2913                 TagNextChildren (item, last);
2914             }
2915         }
2916 
2917     // or select single item
2918     }else if (itemId.IsOk()) {
2919 
2920         // select item according its old selection
2921         item->SetHilight (!item->IsSelected());
2922         RefreshLine (item);
2923         if (unselect_others) {
2924             m_selectItem = (item->IsSelected())? item: (wxTreeListItem*)NULL;
2925         }
2926 
2927     // or select nothing
2928     } else {
2929         if (! bUnselectedAll) UnselectAll();
2930     }
2931 
2932     // send event to user code
2933     event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
2934     SendEvent(0, NULL, &event);
2935 
2936     return true;
2937 }
2938 
SelectAll()2939 void wxTreeListMainWindow::SelectAll() {
2940     wxTreeItemId root = GetRootItem();
2941     wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
2942     wxCHECK_RET (root.IsOk(), _T("no tree"));
2943 
2944     // send event to user code
2945     wxTreeEvent event (wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
2946     event.SetOldItem (m_curItem);
2947     event.SetInt (-1); // no colum clicked
2948     if (SendEvent(0, m_rootItem, &event) && !event.IsAllowed()) return;  // selection change vetoed
2949 
2950     wxTreeItemIdValue cookie = 0;
2951     wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
2952     wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
2953     if (!TagAllChildrenUntilLast (first, last)) {
2954         TagNextChildren (first, last);
2955     }
2956 
2957     // send event to user code
2958     event.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED);
2959     SendEvent(0, NULL, &event);
2960 }
2961 
FillArray(wxTreeListItem * item,wxArrayTreeItemIds & array) const2962 void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
2963                                       wxArrayTreeItemIds &array) const {
2964     if (item->IsSelected()) array.Add (wxTreeItemId(item));
2965 
2966     if (item->HasChildren()) {
2967         wxArrayTreeListItems& children = item->GetChildren();
2968         size_t count = children.GetCount();
2969         for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
2970     }
2971 }
2972 
GetSelections(wxArrayTreeItemIds & array) const2973 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
2974     array.Empty();
2975     wxTreeItemId idRoot = GetRootItem();
2976     if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
2977     return array.Count();
2978 }
2979 
EnsureVisible(const wxTreeItemId & item)2980 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
2981     if (!item.IsOk()) return; // do nothing if no item
2982 
2983     // first expand all parent branches
2984     wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2985     wxTreeListItem *parent = gitem->GetItemParent();
2986     while (parent) {
2987         Expand (parent);
2988         parent = parent->GetItemParent();
2989     }
2990 
2991     ScrollTo (item);
2992     RefreshLine (gitem);
2993 }
2994 
ScrollTo(const wxTreeItemId & item)2995 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
2996     if (!item.IsOk()) return; // do nothing if no item
2997 
2998     // ensure that the position of the item it calculated in any case
2999     if (m_dirty) CalculatePositions();
3000 
3001     wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
3002 
3003     // now scroll to the item
3004     int item_y = gitem->GetY();
3005 
3006     int xUnit, yUnit;
3007     GetScrollPixelsPerUnit (&xUnit, &yUnit);
3008     int start_x = 0;
3009     int start_y = 0;
3010     GetViewStart (&start_x, &start_y);
3011     start_y *= yUnit;
3012 
3013     int client_h = 0;
3014     int client_w = 0;
3015     GetClientSize (&client_w, &client_h);
3016 
3017     int x = 0;
3018     int y = 0;
3019     m_rootItem->GetSize (x, y, this);
3020     x = m_owner->GetHeaderWindow()->GetWidth();
3021     y += yUnit + 2; // one more scrollbar unit + 2 pixels
3022     int x_pos = GetScrollPos( wxHORIZONTAL );
3023 
3024     if (item_y < start_y+3) {
3025         // going down, item should appear at top
3026         SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
3027     }else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
3028         // going up, item should appear at bottom
3029         item_y += yUnit + 2;
3030         SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
3031     }
3032 }
3033 
3034 // TODO: tree sorting functions are not reentrant and not MT-safe!
3035 static wxTreeListMainWindow *s_treeBeingSorted = NULL;
3036 
tree_ctrl_compare_func(wxTreeListItem ** item1,wxTreeListItem ** item2)3037 static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1, wxTreeListItem **item2)
3038 {
3039     wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
3040     return s_treeBeingSorted->OnCompareItems(*item1, *item2);
3041 }
3042 
OnCompareItems(const wxTreeItemId & item1,const wxTreeItemId & item2)3043 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
3044 {
3045     return (m_sortColumn == -1
3046         ? m_owner->OnCompareItems (item1, item2)
3047         : (m_ReverseSortOrder
3048             ? m_owner->OnCompareItems (item2, item1, m_sortColumn)
3049             : m_owner->OnCompareItems (item1, item2, m_sortColumn)
3050         )
3051     );
3052 }
3053 
SortChildren(const wxTreeItemId & itemId,int column,bool reverseOrder)3054 void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId, int column, bool reverseOrder) {
3055     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
3056 
3057     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
3058 
3059     wxCHECK_RET (!s_treeBeingSorted,
3060                  _T("wxTreeListMainWindow::SortChildren is not reentrant") );
3061 
3062     wxArrayTreeListItems& children = item->GetChildren();
3063     if ( children.Count() > 1 ) {
3064         m_dirty = true;
3065         s_treeBeingSorted = this;
3066         m_sortColumn = column;  // -1 indicates legacy mode
3067         m_ReverseSortOrder = reverseOrder;
3068         children.Sort(tree_ctrl_compare_func);
3069         s_treeBeingSorted = NULL;
3070     }
3071 }
3072 
FindItem(const wxTreeItemId & item,int column,const wxString & str,int mode)3073 wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode) {
3074     wxString itemText;
3075     // determine start item
3076     wxTreeItemId next = item;
3077     if (next.IsOk()) {
3078         if (mode & wxTL_MODE_NAV_LEVEL) {
3079             next = GetNextSibling (next);
3080         }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
3081             next = GetNextVisible (next, false, true);
3082         }else if (mode & wxTL_MODE_NAV_EXPANDED) {
3083             next = GetNextExpanded (next);
3084         }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
3085             next = GetNext (next, true);
3086         }
3087     }
3088 
3089     wxTreeItemIdValue cookie = 0;
3090     if (!next.IsOk()) {
3091         next = GetRootItem();
3092         if (next.IsOk() && HasFlag(wxTR_HIDE_ROOT)) {
3093             next = GetFirstChild (GetRootItem(), cookie);
3094         }
3095     }
3096     if (!next.IsOk()) return (wxTreeItemId*)NULL;
3097 
3098     // start checking the next items
3099     while (next.IsOk() && (next != item)) {
3100         if (mode & wxTL_MODE_FIND_PARTIAL) {
3101             itemText = GetItemText (next, column).Mid (0, str.Length());
3102         }else{
3103             itemText = GetItemText (next, column);
3104         }
3105         if (mode & wxTL_MODE_FIND_NOCASE) {
3106             if (itemText.CmpNoCase (str) == 0) return next;
3107         }else{
3108             if (itemText.Cmp (str) == 0) return next;
3109         }
3110         if (mode & wxTL_MODE_NAV_LEVEL) {
3111             next = GetNextSibling (next);
3112         }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
3113             next = GetNextVisible (next, false, true);
3114         }else if (mode & wxTL_MODE_NAV_EXPANDED) {
3115             next = GetNextExpanded (next);
3116         }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
3117             next = GetNext (next, true);
3118         }
3119         if (!next.IsOk() && item.IsOk()) {
3120             next = (wxTreeListItem*)GetRootItem().m_pItem;
3121             if (HasFlag(wxTR_HIDE_ROOT)) {
3122                 next = (wxTreeListItem*)GetNextChild (GetRootItem().m_pItem, cookie).m_pItem;
3123             }
3124         }
3125     }
3126     return (wxTreeItemId*)NULL;
3127 }
3128 
SetDragItem(const wxTreeItemId & item)3129 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
3130     wxTreeListItem *prevItem = m_dragItem;
3131     m_dragItem = (wxTreeListItem*) item.m_pItem;
3132     if (prevItem) RefreshLine (prevItem);
3133     if (m_dragItem) RefreshLine (m_dragItem);
3134 }
3135 
CalculateLineHeight()3136 void wxTreeListMainWindow::CalculateLineHeight() {
3137     wxClientDC dc (this);
3138     dc.SetFont (m_normalFont);
3139     m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
3140 
3141     if (m_imageListNormal) {
3142         // Calculate a m_lineHeight value from the normal Image sizes.
3143         // May be toggle off. Then wxTreeListMainWindow will spread when
3144         // necessary (which might look ugly).
3145         int n = m_imageListNormal->GetImageCount();
3146         for (int i = 0; i < n ; i++) {
3147             int width = 0, height = 0;
3148             m_imageListNormal->GetSize(i, width, height);
3149             if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
3150         }
3151     }
3152 
3153     if (m_imageListButtons) {
3154         // Calculate a m_lineHeight value from the Button image sizes.
3155         // May be toggle off. Then wxTreeListMainWindow will spread when
3156         // necessary (which might look ugly).
3157         int n = m_imageListButtons->GetImageCount();
3158         for (int i = 0; i < n ; i++) {
3159             int width = 0, height = 0;
3160             m_imageListButtons->GetSize(i, width, height);
3161             if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
3162         }
3163     }
3164 
3165     if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
3166         m_lineHeight += 2; // minimal 2 pixel space
3167     }else{
3168         m_lineHeight += m_lineHeight / 10; // otherwise 10% space
3169     }
3170 }
3171 
SetImageList(wxImageList * imageList)3172 void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
3173     if (m_ownsImageListNormal) delete m_imageListNormal;
3174     m_imageListNormal = imageList;
3175     m_ownsImageListNormal = false;
3176     m_dirty = true;
3177     CalculateLineHeight();
3178 }
3179 
SetStateImageList(wxImageList * imageList)3180 void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
3181     if (m_ownsImageListState) delete m_imageListState;
3182     m_imageListState = imageList;
3183     m_ownsImageListState = false;
3184 }
3185 
SetButtonsImageList(wxImageList * imageList)3186 void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
3187     if (m_ownsImageListButtons) delete m_imageListButtons;
3188     m_imageListButtons = imageList;
3189     m_ownsImageListButtons = false;
3190     m_dirty = true;
3191     CalculateLineHeight();
3192 }
3193 
AssignImageList(wxImageList * imageList)3194 void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
3195     SetImageList(imageList);
3196     m_ownsImageListNormal = true;
3197 }
3198 
AssignStateImageList(wxImageList * imageList)3199 void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
3200     SetStateImageList(imageList);
3201     m_ownsImageListState = true;
3202 }
3203 
AssignButtonsImageList(wxImageList * imageList)3204 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
3205     SetButtonsImageList(imageList);
3206     m_ownsImageListButtons = true;
3207 }
3208 
3209 // ----------------------------------------------------------------------------
3210 // helpers
3211 // ----------------------------------------------------------------------------
3212 
AdjustMyScrollbars()3213 void wxTreeListMainWindow::AdjustMyScrollbars() {
3214     if (m_rootItem) {
3215         int xUnit, yUnit;
3216         GetScrollPixelsPerUnit (&xUnit, &yUnit);
3217         if (xUnit == 0) xUnit = GetCharWidth();
3218         if (yUnit == 0) yUnit = m_lineHeight;
3219         int x = 0, y = 0;
3220         m_rootItem->GetSize (x, y, this);
3221         y += yUnit + 2; // one more scrollbar unit + 2 pixels
3222         int x_pos = GetScrollPos (wxHORIZONTAL);
3223         int y_pos = GetScrollPos (wxVERTICAL);
3224         x = m_owner->GetHeaderWindow()->GetWidth() + 2;
3225         if (x < GetClientSize().GetWidth()) x_pos = 0;
3226         SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
3227     }else{
3228         SetScrollbars (0, 0, 0, 0);
3229     }
3230 }
3231 
GetLineHeight(wxTreeListItem * item) const3232 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
3233     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
3234         return item->GetHeight();
3235     }else{
3236         return m_lineHeight;
3237     }
3238 }
3239 
PaintItem(wxTreeListItem * item,wxDC & dc)3240 void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
3241 
3242 // read attributes constant for all item cells
3243     wxColour colText = GetItemTextColour(item);
3244     wxColour colBg = GetItemBackgroundColour(item);
3245     wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
3246     int total_w = m_owner->GetHeaderWindow()->GetWidth();
3247     int total_h = GetLineHeight(item);
3248     int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
3249     int off_w = HasFlag(wxTR_COLUMN_LINES) ? 1 : 0;
3250     wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
3251     // compute text height based on main col
3252     int text_h = 0;
3253     dc.GetTextExtent( item->GetText(GetMainColumn()).size() > 0
3254             ? item->GetText(GetMainColumn())
3255             : _T("M"),  // dummy text to avoid zero height and no highlight width
3256         NULL, &text_h );
3257 
3258 // determine background and show it
3259 // in wxTR_FULL_ROW_HIGHLIGHT mode, some drawing can be done already now
3260     dc.SetBrush (wxBrush ( colBg, wxSOLID));
3261     dc.SetPen (*wxTRANSPARENT_PEN);
3262     if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3263         if (item->IsSelected()) {
3264             if (! m_isDragging && m_hasFocus) {
3265                 dc.SetBrush (*m_hilightBrush);
3266 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3267                 dc.SetPen (*wxBLACK_PEN);
3268 #endif // !__WXMAC__
3269             }else{
3270                 dc.SetBrush (*m_hilightUnfocusedBrush);
3271 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3272                 dc.SetPen (*wxTRANSPARENT_PEN);
3273 #endif // !__WXMAC__
3274             }
3275             dc.SetTextForeground (colTextHilight);
3276         }else {
3277             dc.SetTextForeground (GetItemTextColour(item));
3278             if (item == m_curItem) {
3279                 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3280             }
3281         }
3282         dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
3283     }
3284 
3285 // iterate through all cells
3286     int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
3287     int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
3288     int x_colstart = 0;
3289     for (int i = 0; i < GetColumnCount(); ++i ) {
3290         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3291         int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
3292         if (col_w <= 0) continue;  // workaround for probable GTK2 bug [wxCode-Bugs-#3061215]
3293         wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
3294 
3295         // read variable attributes
3296         dc.SetFont (GetItemFont (item, i));
3297         colText = GetItemTextColour(item, i);
3298         colBg = GetItemBackgroundColour(item, i);
3299 
3300         //
3301         int x = 0;
3302         int image = NO_IMAGE;
3303         int image_w = 0;
3304         if(i == GetMainColumn()) {
3305             x = item->GetX() + MARGIN;
3306             if (HasButtons()) {
3307                 x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
3308             }else{
3309                 x -= m_indent/2;
3310             }
3311             if (m_imageListNormal) image = item->GetCurrentImage();
3312         }else{
3313             x = x_colstart + MARGIN;
3314             image = item->GetImage(i);
3315         }
3316         if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
3317 
3318         // honor text alignment
3319         int w = 0, text_w = 0;
3320         wxString text = item->GetText(i);
3321         dc.GetTextExtent (text, &text_w, NULL);
3322         switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
3323         case wxALIGN_LEFT:
3324             // nothing to do, already left aligned
3325             break;
3326         case wxALIGN_RIGHT:
3327             w = col_w - (image_w + text_w + off_w + MARGIN);
3328             x += (w > 0)? w: 0;
3329             break;
3330         case wxALIGN_CENTER:
3331             w = (col_w - (image_w + text_w + off_w + MARGIN))/2;
3332             x += (w > 0)? w: 0;
3333             break;
3334         }
3335         int text_x = x + image_w;
3336         if (i == GetMainColumn()) item->SetTextX (text_x);
3337 
3338         // draw background (in non wxTR_FULL_ROW_HIGHLIGHT mode)
3339         // cell-specific settings are used --excepted for selection:
3340         if ( ! HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3341             // cursor: indicate current cell
3342             bool drawCursor = false;
3343 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3344             drawCursor = (item == m_curItem && i == m_curColumn && !m_isDragging && m_hasFocus);
3345 #endif // !__WXMAC__
3346             // selection: main col only, overrides colors + separate draw
3347             if (item->IsSelected() && i == GetMainColumn()) {
3348                 // draw normal background
3349                 dc.SetPen (*wxTRANSPARENT_PEN);
3350                 dc.SetBrush (wxBrush ( colBg, wxSOLID));
3351                 dc.DrawRectangle (x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
3352                 // draw selection & optionally cursor
3353                 dc.SetPen (drawCursor ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
3354                 dc.SetBrush(!m_isDragging && m_hasFocus ? *m_hilightBrush : *m_hilightUnfocusedBrush);
3355                 dc.SetTextForeground (colTextHilight);
3356                 dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3357             // normal FG / BG from attributes
3358             } else {
3359                 // draw normal background & optionally cursor
3360                 dc.SetPen (drawCursor && i != GetMainColumn() ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
3361                 dc.SetBrush (wxBrush ( colBg, wxSOLID));
3362                 dc.SetTextForeground (colText);
3363                 dc.DrawRectangle (x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
3364                 // on main col draw a separate cursor
3365                 if (drawCursor && i == GetMainColumn()) {
3366                     dc.SetPen (*wxBLACK_PEN);
3367                     dc.SetBackgroundMode (wxTRANSPARENT);
3368                     dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3369                 }
3370             }
3371         }
3372 
3373         // draw vertical column lines
3374         if (HasFlag(wxTR_COLUMN_LINES)) { // vertical lines between columns
3375             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3376             dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3377             dc.DrawLine (x_colstart+col_w-1, item->GetY(), x_colstart+col_w-1, item->GetY()+total_h);
3378         }
3379 
3380         dc.SetBackgroundMode (wxTRANSPARENT);
3381 
3382         // draw image
3383         if (image != NO_IMAGE && m_imageListNormal && image < m_imageListNormal->GetImageCount()) {
3384             int y = item->GetY() + img_extraH;
3385             m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3386         }
3387 
3388         // draw text
3389         int text_y = item->GetY() + text_extraH;
3390         dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
3391 
3392         x_colstart += col_w;
3393     }
3394 
3395     // restore normal font
3396     dc.SetFont( m_normalFont );
3397 }
3398 
3399 // Now y stands for the top of the item, whereas it used to stand for middle !
PaintLevel(wxTreeListItem * item,wxDC & dc,int level,int & y,int x_maincol)3400 void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
3401                                        int level, int &y, int x_maincol) {
3402 
3403     // Handle hide root (only level 0)
3404     if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
3405         wxArrayTreeListItems& children = item->GetChildren();
3406         for (size_t n = 0; n < children.Count(); n++) {
3407             PaintLevel (children[n], dc, 1, y, x_maincol);
3408         }
3409         // end after expanding root
3410         return;
3411     }
3412 
3413     // calculate position of vertical lines
3414     int x = x_maincol + MARGIN; // start of column
3415     if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
3416     if (HasButtons()) {
3417         x += (m_btnWidth-m_btnWidth2); // half button space
3418     }else{
3419         x += (m_indent-m_indent/2);
3420     }
3421     if (HasFlag(wxTR_HIDE_ROOT)) {
3422         x += m_indent * (level-1); // indent but not level 1
3423     }else{
3424         x += m_indent * level; // indent according to level
3425     }
3426 
3427     // set position of vertical line
3428     item->SetX (x);
3429     item->SetY (y);
3430 
3431     int h = GetLineHeight (item);
3432     int y_top = y;
3433     int y_mid = y_top + (h/2);
3434     y += h;
3435 
3436     int exposed_x = dc.LogicalToDeviceX(0);
3437     int exposed_y = dc.LogicalToDeviceY(y_top);
3438 
3439     if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
3440 
3441         if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
3442             //dc.DestroyClippingRegion();
3443             int total_width = m_owner->GetHeaderWindow()->GetWidth();
3444             // if the background colour is white, choose a
3445             // contrasting color for the lines
3446             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3447             dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3448             dc.DrawLine (0, y_top, total_width, y_top);
3449             dc.DrawLine (0, y_top+h, total_width, y_top+h);
3450         }
3451 
3452         // draw item
3453         PaintItem (item, dc);
3454 
3455         // restore DC objects
3456         dc.SetBrush(*wxWHITE_BRUSH);
3457         dc.SetPen(m_dottedPen);
3458 
3459         // clip to the column width
3460         int clip_width = m_owner->GetHeaderWindow()->
3461                             GetColumn(m_main_column).GetWidth();
3462         wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3463 
3464         if (!HasFlag(wxTR_NO_LINES)) { // connection lines
3465 
3466             // draw the horizontal line here
3467             dc.SetPen(m_dottedPen);
3468             int x2 = x - m_indent;
3469             if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
3470             int x3 = x + (m_btnWidth-m_btnWidth2);
3471             if (HasButtons()) {
3472                 if (item->HasPlus()) {
3473                     dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
3474                     dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
3475                 }else{
3476                     dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
3477                 }
3478             }else{
3479                 dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
3480             }
3481         }
3482 
3483         if (item->HasPlus() && HasButtons()) { // should the item show a button?
3484 
3485             if (m_imageListButtons) {
3486 
3487                 // draw the image button here
3488                 int image = wxTreeItemIcon_Normal;
3489                 if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
3490                 if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
3491                 int xx = x - m_btnWidth2 + MARGIN;
3492                 int yy = y_mid - m_btnHeight2;
3493                 dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
3494                 m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
3495                 dc.DestroyClippingRegion();
3496 
3497             }else if (HasFlag (wxTR_TWIST_BUTTONS)) {
3498 
3499                 // draw the twisty button here
3500                 dc.SetPen(*wxBLACK_PEN);
3501                 dc.SetBrush(*m_hilightBrush);
3502                 wxPoint button[3];
3503                 if (item->IsExpanded()) {
3504                     button[0].x = x - (m_btnWidth2+1);
3505                     button[0].y = y_mid - (m_btnHeight/3);
3506                     button[1].x = x + (m_btnWidth2+1);
3507                     button[1].y = button[0].y;
3508                     button[2].x = x;
3509                     button[2].y = button[0].y + (m_btnHeight2+1);
3510                 }else{
3511                     button[0].x = x - (m_btnWidth/3);
3512                     button[0].y = y_mid - (m_btnHeight2+1);
3513                     button[1].x = button[0].x;
3514                     button[1].y = y_mid + (m_btnHeight2+1);
3515                     button[2].x = button[0].x + (m_btnWidth2+1);
3516                     button[2].y = y_mid;
3517                 }
3518                 dc.DrawPolygon(3, button);
3519 
3520             }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3521 
3522                 // draw the plus sign here
3523                 wxRect rect (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3524                 int flag = item->IsExpanded()? wxCONTROL_EXPANDED: 0;
3525                 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc, rect, flag);
3526 
3527             }
3528 
3529         }
3530 
3531     }
3532 
3533     // restore DC objects
3534     dc.SetBrush(*wxWHITE_BRUSH);
3535     dc.SetPen(m_dottedPen);
3536     dc.SetTextForeground(*wxBLACK);
3537 
3538     if (item->IsExpanded())
3539     {
3540         wxArrayTreeListItems& children = item->GetChildren();
3541 
3542         // clip to the column width
3543         int clip_width = m_owner->GetHeaderWindow()->
3544                             GetColumn(m_main_column).GetWidth();
3545 
3546         // process lower levels
3547         int oldY;
3548         if (m_imgWidth > 0) {
3549             oldY = y_mid + m_imgHeight2;
3550         }else{
3551             oldY = y_mid + h/2;
3552         }
3553         int y2;
3554         for (size_t n = 0; n < children.Count(); ++n) {
3555 
3556             y2 = y + h/2;
3557             PaintLevel (children[n], dc, level+1, y, x_maincol);
3558 
3559             // draw vertical line
3560             wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3561             if (!HasFlag (wxTR_NO_LINES)) {
3562                 x = item->GetX();
3563                 dc.DrawLine (x, oldY, x, y2);
3564                 oldY = y2;
3565             }
3566         }
3567     }
3568 }
3569 
3570 
3571 // ----------------------------------------------------------------------------
3572 // wxWindows callbacks
3573 // ----------------------------------------------------------------------------
3574 
OnPaint(wxPaintEvent & WXUNUSED (event))3575 void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
3576 
3577     // init device context, clear background (BEFORE changing DC origin...)
3578     wxAutoBufferedPaintDC dc (this);
3579     wxBrush brush(GetBackgroundColour(), wxSOLID);
3580     dc.SetBackground(brush);
3581     dc.Clear();
3582     DoPrepareDC (dc);
3583 
3584     if (!m_rootItem || (GetColumnCount() <= 0)) return;
3585 
3586     // calculate button size
3587     if (m_imageListButtons) {
3588         m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
3589     }else if (HasButtons()) {
3590         m_btnWidth = BTNWIDTH;
3591         m_btnHeight = BTNHEIGHT;
3592     }
3593     m_btnWidth2 = m_btnWidth/2;
3594     m_btnHeight2 = m_btnHeight/2;
3595 
3596     // calculate image size
3597     if (m_imageListNormal) {
3598         m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
3599     }
3600     m_imgWidth2 = m_imgWidth/2;
3601     m_imgHeight2 = m_imgHeight/2;
3602 
3603     // calculate indent size
3604     if (m_imageListButtons) {
3605         m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
3606     }else if (HasButtons()) {
3607         m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
3608     }
3609 
3610     // set default values
3611     dc.SetFont( m_normalFont );
3612     dc.SetPen( m_dottedPen );
3613 
3614     // calculate column start and paint
3615     int x_maincol = 0;
3616     int i = 0;
3617     for (i = 0; i < (int)GetMainColumn(); ++i) {
3618         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3619         x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
3620     }
3621     int y = 0;
3622     PaintLevel (m_rootItem, dc, 0, y, x_maincol);
3623 }
3624 
OnSetFocus(wxFocusEvent & event)3625 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
3626     m_hasFocus = true;
3627     RefreshSelected();
3628     if (m_curItem) RefreshLine (m_curItem);
3629     event.Skip();
3630 }
3631 
OnKillFocus(wxFocusEvent & event)3632 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
3633 {
3634     m_hasFocus = false;
3635     RefreshSelected();
3636     if (m_curItem) RefreshLine (m_curItem);
3637     event.Skip();
3638 }
3639 
OnChar(wxKeyEvent & event)3640 void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
3641     // send event to user code
3642     wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, 0 );
3643     nevent.SetInt(m_curColumn);
3644     nevent.SetKeyEvent (event);
3645     if (SendEvent(0, NULL, &nevent)) return; // char event handled in user code
3646 
3647     // if no item current, select root
3648     bool curItemSet = false;
3649     if (!m_curItem) {
3650         if (! GetRootItem().IsOk()) return;
3651         SetCurrentItem((wxTreeListItem*)GetRootItem().m_pItem);
3652         if (HasFlag(wxTR_HIDE_ROOT)) {
3653             wxTreeItemIdValue cookie = 0;
3654             SetCurrentItem((wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem);
3655         }
3656         SelectItem(m_curItem, (wxTreeItemId*)NULL, true);  // unselect others
3657         curItemSet = true;
3658     }
3659 
3660     // remember item at shift down
3661     if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
3662         if (!m_shiftItem) m_shiftItem = m_curItem;
3663     }else{
3664         m_shiftItem = (wxTreeListItem*)NULL;
3665     }
3666 
3667     if (curItemSet) return;  // if no item was current until now, do nothing more
3668 
3669     // process all cases
3670     wxTreeItemId newItem = (wxTreeItemId*)NULL;
3671     switch (event.GetKeyCode()) {
3672 
3673         // '+': Expand subtree
3674         case '+':
3675         case WXK_ADD: {
3676             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
3677         }break;
3678 
3679         // '-': collapse subtree
3680         case '-':
3681         case WXK_SUBTRACT: {
3682             if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
3683         }break;
3684 
3685         // '*': expand/collapse all subtrees // TODO: Mak it more useful
3686         case '*':
3687         case WXK_MULTIPLY: {
3688             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3689                 ExpandAll (m_curItem);
3690             }else if (m_curItem->HasPlus()) {
3691                 Collapse (m_curItem); // TODO: CollapseAll
3692             }
3693         }break;
3694 
3695         // ' ': toggle current item
3696         case ' ': {
3697             SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
3698         }break;
3699 
3700         // <RETURN>: activate current item
3701         case WXK_RETURN: {
3702             if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_curItem)) {
3703 
3704                 // if the user code didn't process the activate event,
3705                 // handle it ourselves by toggling the item when it is
3706                 // double clicked
3707                 if (m_curItem && m_curItem->HasPlus()) Toggle(m_curItem);
3708             }
3709         }break;
3710 
3711         // <BKSP>: go to the parent without collapsing
3712         case WXK_BACK: {
3713             newItem = GetItemParent (m_curItem);
3714             if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3715                 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
3716             }
3717         }break;
3718 
3719         // <HOME>: go to first visible
3720         case WXK_HOME: {
3721             newItem = GetFirstVisible(false, false);
3722         }break;
3723 
3724         // <PAGE-UP>: go to the top of the page, or if we already are then one page back
3725         case WXK_PAGEUP: {
3726         int flags = 0;
3727         int col = 0;
3728         wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,1));
3729         // PAGE-UP: first go the the first visible row
3730             newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3731             newItem = GetFirstVisible(false, true);
3732         // if we are already there then scroll back one page
3733             if (newItem == m_curItem) {
3734                 abs_p.y -= GetClientSize().GetHeight() - m_curItem->GetHeight();
3735                 if (abs_p.y < 0) abs_p.y = 0;
3736                 newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3737             }
3738             // newItem should never be NULL
3739         } break;
3740 
3741         // <UP>: go to the previous sibling or for the last of its children, to the parent
3742         case WXK_UP: {
3743             newItem = GetPrevSibling (m_curItem);
3744             if (newItem) {
3745                 wxTreeItemIdValue cookie = 0;
3746                 while (IsExpanded (newItem) && HasChildren (newItem)) {
3747                     newItem = GetLastChild (newItem, cookie);
3748                 }
3749             }else {
3750                 newItem = GetItemParent (m_curItem);
3751                 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3752                     newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
3753                 }
3754             }
3755         }break;
3756 
3757         // <LEFT>: if expanded collapse subtree, else go to the parent
3758         case WXK_LEFT: {
3759             if (IsExpanded (m_curItem)) {
3760                 Collapse (m_curItem);
3761             }else{
3762                 newItem = GetItemParent (m_curItem);
3763                 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3764                     newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
3765                 }
3766             }
3767         }break;
3768 
3769         // <RIGHT>: if possible expand subtree, else go go to the first child
3770         case WXK_RIGHT: {
3771             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3772                 Expand (m_curItem);
3773             }else{
3774                 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3775                     wxTreeItemIdValue cookie = 0;
3776                     newItem = GetFirstChild (m_curItem, cookie);
3777                 }
3778             }
3779         }break;
3780 
3781         // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3782         case WXK_DOWN: {
3783             if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3784                 wxTreeItemIdValue cookie = 0;
3785                 newItem = GetFirstChild( m_curItem, cookie );
3786             }
3787             if (!newItem) {
3788                 wxTreeItemId parent = m_curItem;
3789                 do {
3790                     newItem = GetNextSibling (parent);
3791                     parent = GetItemParent (parent);
3792                 } while (!newItem && parent);
3793             }
3794         }break;
3795 
3796         // <PAGE-DOWN>: go to the bottom of the page, or if we already are then one page further
3797         case WXK_PAGEDOWN: {
3798         int flags = 0;
3799         int col = 0;
3800         wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,GetClientSize().GetHeight() - m_curItem->GetHeight()));
3801         // PAGE-UP: first go the the first visible row
3802             newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3803             newItem = GetLastVisible(false, true);
3804         // if we are already there then scroll down one page
3805             if (newItem == m_curItem) {
3806                 abs_p.y += GetClientSize().GetHeight() - m_curItem->GetHeight();
3807 //                if (abs_p.y >= GetVirtualSize().GetHeight()) abs_p.y = GetVirtualSize().GetHeight() - 1;
3808                 newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3809             }
3810         // if we reached the empty area below the rows, return last item instead
3811             if (! newItem) newItem = GetLastVisible(false, false);
3812         } break;
3813 
3814         // <END>: go to last item of the root
3815         case WXK_END: {
3816             newItem = GetLastVisible (false, false);
3817         }break;
3818 
3819         // any char: go to the next matching string
3820         default:
3821             if (event.GetKeyCode() >= (int)' ') {
3822                 if (!m_findTimer->IsRunning()) m_findStr.Clear();
3823                 m_findStr << event.GetKeyCode();
3824                 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
3825                 wxTreeItemId prev = m_curItem? (wxTreeItemId*)m_curItem: (wxTreeItemId*)NULL;
3826                 while (true) {
3827                     newItem = FindItem (prev, GetCurrentColumn(), m_findStr, wxTL_MODE_NAV_EXPANDED | wxTL_MODE_FIND_PARTIAL | wxTL_MODE_FIND_NOCASE);
3828                     if (newItem || (m_findStr.Length() <= 1)) break;
3829                     m_findStr.RemoveLast();
3830                 };
3831             }
3832             event.Skip();
3833 
3834     }
3835 
3836     // select and show the new item
3837     if (newItem) {
3838         if (!event.ControlDown()) {
3839             bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3840                                       HasFlag(wxTR_MULTIPLE));
3841             SelectItem (newItem, m_shiftItem, unselect_others);
3842         }
3843         EnsureVisible (newItem);
3844         wxTreeListItem *oldItem = m_curItem;
3845         SetCurrentItem((wxTreeListItem*)newItem.m_pItem); // make the new item the current item
3846         RefreshLine (oldItem);
3847     }
3848 
3849 }
3850 
HitTest(const wxPoint & point,int & flags,int & column)3851 wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
3852 
3853     int w, h;
3854     GetSize(&w, &h);
3855     flags=0;
3856     column = -1;
3857     if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
3858     if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
3859     if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
3860     if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
3861     if (flags) return wxTreeItemId();
3862 
3863     if (!m_rootItem) {
3864         flags = wxTREE_HITTEST_NOWHERE;
3865         column = -1;
3866         return wxTreeItemId();
3867     }
3868 
3869     wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
3870                                                this, flags, column, 0);
3871     if (!hit) {
3872         flags = wxTREE_HITTEST_NOWHERE;
3873         column = -1;
3874         return wxTreeItemId();
3875     }
3876     return hit;
3877 }
3878 
3879 // get the bounding rectangle of the item (or of its label only)
GetBoundingRect(const wxTreeItemId & itemId,wxRect & rect,bool WXUNUSED (textOnly)) const3880 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
3881                                             bool WXUNUSED(textOnly)) const {
3882     wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
3883 
3884     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
3885 
3886     int xUnit, yUnit;
3887     GetScrollPixelsPerUnit (&xUnit, &yUnit);
3888     int startX, startY;
3889     GetViewStart(& startX, & startY);
3890 
3891     rect.x = item->GetX() - startX * xUnit;
3892     rect.y = item->GetY() - startY * yUnit;
3893     rect.width = item->GetWidth();
3894     rect.height = GetLineHeight (item);
3895 
3896     return true;
3897 }
3898 
3899 /* **** */
3900 
EditLabel(const wxTreeItemId & item,int column)3901 void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
3902 
3903 // validate
3904     if (!item.IsOk()) return;
3905     if (!((column >= 0) && (column < GetColumnCount()))) return;
3906 
3907 // cancel any editing
3908     if (m_editControl) { m_editControl->EndEdit(true); }  // cancelled
3909 
3910 // prepare edit (position)
3911     m_editItem = (wxTreeListItem*) item.m_pItem;
3912 
3913     wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 0 );
3914     te.SetInt (column);
3915     SendEvent(0, m_editItem, &te); if (!te.IsAllowed()) return;
3916 
3917     // ensure that the position of the item it calculated in any case
3918     if (m_dirty) CalculatePositions();
3919 
3920     wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
3921 
3922     // position & size are rather unpredictable (tsssk, tssssk) so were
3923     //  set by trial & error (on Win 2003 pre-XP style)
3924     int x = 0;
3925     int w = +4;  // +4 is necessary, don't know why (simple border erronously counted somewhere ?)
3926     int y = m_editItem->GetY() + 1;  // this is cell, not text
3927     int h = m_editItem->GetHeight() - 1;  // consequence from above
3928     long style = 0;
3929     if (column == GetMainColumn()) {
3930         x += m_editItem->GetTextX() - 2;  // wrong by 2, don't know why
3931         w += m_editItem->GetWidth();
3932     } else {
3933         for (int i = 0; i < column; ++i) {
3934             if ( header_win->IsColumnShown(i) ) {
3935                 x += header_win->GetColumnWidth (i); // start of column
3936             }
3937 		}
3938         w += header_win->GetColumnWidth (column);  // currently non-main column width not pre-computed
3939     }
3940     switch (header_win->GetColumnAlignment (column)) {
3941         case wxALIGN_LEFT:   {style = wxTE_LEFT;   x -= 1; break;}
3942         case wxALIGN_CENTER: {style = wxTE_CENTER; x -= 1; break;}
3943         case wxALIGN_RIGHT:  {style = wxTE_RIGHT;  x += 0; break;}  // yes, strange but that's the way it is
3944     }
3945     // wxTextCtrl simple border style requires 2 extra pixels before and after
3946     //  (measured by changing to style wxNO_BORDER in wxEditTextCtrl::wxEditTextCtrl() )
3947     y -= 2; x -= 2;
3948     w += 4; h += 4;
3949 
3950     wxClientDC dc (this);
3951     PrepareDC (dc);
3952     x = dc.LogicalToDeviceX (x);
3953     y = dc.LogicalToDeviceY (y);
3954 
3955 // now do edit (change state, show control)
3956     m_editCol = column;  // only used in OnRenameAccept()
3957     m_editControl = new wxEditTextCtrl (this, -1, &m_editAccept, &m_editRes,
3958                                                this, m_editItem->GetText (column),
3959                                                wxPoint (x, y), wxSize (w, h), style);
3960     m_editControl->SetFocus();
3961 }
3962 
OnRenameTimer()3963 void wxTreeListMainWindow::OnRenameTimer() {
3964     EditLabel (m_curItem, GetCurrentColumn());
3965 }
3966 
OnRenameAccept(bool isCancelled)3967 void wxTreeListMainWindow::OnRenameAccept(bool isCancelled) {
3968 
3969     // TODO if the validator fails this causes a crash
3970     wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, 0 );
3971     le.SetLabel( m_editRes );
3972     le.SetEditCanceled(isCancelled);
3973     le.SetInt(m_editCol);
3974     SendEvent(0, m_editItem, &le); if (! isCancelled  && le.IsAllowed())
3975     {
3976         SetItemText (m_editItem, le.GetInt(), le.GetLabel());
3977     }
3978 }
3979 
EndEdit(bool isCancelled)3980 void wxTreeListMainWindow::EndEdit(bool isCancelled) {
3981     if (m_editControl) { m_editControl->EndEdit(true); }
3982 }
3983 
OnMouse(wxMouseEvent & event)3984 void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
3985 bool mayDrag = true;
3986 bool maySelect = true;  // may change selection
3987 bool mayClick = true;  // may process DOWN clicks to expand, send click events
3988 bool mayDoubleClick = true;  // implies mayClick
3989 bool bSkip = true;
3990 
3991     // send event to user code
3992     if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
3993     if (!m_rootItem) return;
3994 
3995 
3996 // ---------- DETERMINE EVENT ----------
3997 /*
3998 wxLogMessage("OnMouse: LMR down=<%d, %d, %d> up=<%d, %d, %d> LDblClick=<%d> dragging=<%d>",
3999     event.LeftDown(), event.MiddleDown(), event.RightDown(),
4000     event.LeftUp(), event.MiddleUp(), event.RightUp(),
4001     event.LeftDClick(), event.Dragging());
4002 */
4003     wxPoint p = wxPoint (event.GetX(), event.GetY());
4004     int flags = 0;
4005     wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
4006                                                 this, flags, m_curColumn, 0);
4007     bool bCrosshair = (item && item->HasPlus() && (flags & wxTREE_HITTEST_ONITEMBUTTON));
4008     // we were dragging
4009     if (m_isDragging) {
4010         maySelect = mayDoubleClick = false;
4011     }
4012     // we are starting or continuing to drag
4013     if (event.Dragging()) {
4014         maySelect = mayDoubleClick = mayClick = false;
4015     }
4016     // crosshair area is special
4017     if (bCrosshair) {
4018         // left click does not select
4019         if (event.LeftDown()) maySelect = false;
4020         // double click is ignored
4021         mayDoubleClick = false;
4022     }
4023     // double click only if simple click
4024     if (mayDoubleClick) mayDoubleClick = mayClick;
4025     // selection conditions --remember also that selection exludes editing
4026     if (maySelect) maySelect = mayClick;  // yes, select/unselect requires a click
4027     if (maySelect) {
4028 
4029         // multiple selection mode complicates things, sometimes we
4030         //  select on button-up instead of down:
4031         if (HasFlag(wxTR_MULTIPLE)) {
4032 
4033             // CONTROL/SHIFT key used, don't care about anything else, will
4034             //  toggle on key down
4035             if (event.ControlDown() || event.ShiftDown()) {
4036                 maySelect = maySelect && (event.LeftDown() || event.RightDown());
4037                 m_lastOnSame = false;  // prevent editing when keys are used
4038 
4039             // already selected item: to allow drag or contextual menu for multiple
4040             //  items, we only select/unselect on click-up --and only on LEFT
4041             // click, right is reserved for contextual menu
4042             } else if ((item != NULL && item->IsSelected())) {
4043                 maySelect = maySelect && event.LeftUp();
4044 
4045             // non-selected items: select on click-down like simple select (so
4046             //  that a right-click contextual menu may be chained)
4047             } else {
4048                 maySelect = maySelect && (event.LeftDown() || event.RightDown());
4049             }
4050 
4051         // single-select is simply on left or right click-down
4052         } else {
4053             maySelect = maySelect && (event.LeftDown() || event.RightDown());
4054         }
4055     }
4056 
4057 
4058 // ----------  GENERAL ACTIONS  ----------
4059 
4060     // set focus if window clicked
4061     if (event.LeftDown() || event.MiddleDown() || event.RightDown()) SetFocus();
4062 
4063     // tooltip change ?
4064     if (item != m_toolTipItem) {
4065 
4066         // not over an item, use global tip
4067         if (item == NULL) {
4068             m_toolTipItem = NULL;
4069             wxScrolledWindow::SetToolTip(m_toolTip);
4070 
4071         // over an item
4072         } else {
4073             const wxString *tip = item->GetToolTip();
4074 
4075             // is there an item-specific tip ?
4076             if (tip) {
4077                 m_toolTipItem = item;
4078                 wxScrolledWindow::SetToolTip(*tip);
4079 
4080             // no item tip, but we are in item-specific mode (SetItemToolTip()
4081             //  was called after SetToolTip() )
4082             } else if (m_isItemToolTip) {
4083                 m_toolTipItem = item;
4084                 wxScrolledWindow::SetToolTip(wxString());
4085 
4086             // no item tip, display global tip instead; item change ignored
4087             } else if (m_toolTipItem != NULL) {
4088                 m_toolTipItem = NULL;
4089                 wxScrolledWindow::SetToolTip(m_toolTip);
4090             }
4091         }
4092     }
4093 
4094 
4095 // ----------  HANDLE SIMPLE-CLICKS  (selection change, contextual menu) ----------
4096     if (mayClick) {
4097 
4098         // 2nd left-click on an item might trigger edit
4099         if (event.LeftDown()) m_lastOnSame = (item == m_curItem);
4100 
4101         // left-click on haircross is expand (and no select)
4102         if (bCrosshair && event.LeftDown()) {
4103 
4104             bSkip = false;
4105 
4106             // note that we only toggle the item for a single click, double
4107             // click on the button doesn't do anything
4108             Toggle (item);
4109         }
4110 
4111         if (maySelect) {
4112             bSkip = false;
4113 
4114             // set / remember item at shift down before current item gets changed
4115             if (event.LeftDown() && HasFlag(wxTR_MULTIPLE) && event.ShiftDown())  {
4116                 if (!m_shiftItem) m_shiftItem = m_curItem;
4117             }else{
4118                 m_shiftItem = (wxTreeListItem*)NULL;
4119             }
4120 
4121             // how is selection altered
4122             // keep or discard already selected ?
4123             bool unselect_others = ! (HasFlag(wxTR_MULTIPLE) && (
4124                 event.ShiftDown()
4125              || event.ControlDown()
4126             ));
4127 
4128             // check is selection change is not vetoed
4129             if (SelectItem(item, m_shiftItem, unselect_others)) {
4130                 // make the new item the current item
4131                 EnsureVisible (item);
4132                 SetCurrentItem(item);
4133             }
4134         }
4135 
4136         // generate click & menu events
4137         if (event.MiddleDown()) {
4138             bSkip = false;
4139             SendEvent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, item);
4140         }
4141         if (event.RightDown()) {
4142             bSkip = false;
4143             SendEvent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, item);
4144         }
4145         if (event.RightUp()) {
4146             wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_MENU, 0);
4147             nevent.SetPoint(p);
4148             nevent.SetInt(m_curColumn);
4149             SendEvent(0, item, &nevent);
4150         }
4151 
4152         // if 2nd left click finishes on same item, will edit it
4153         if (m_lastOnSame && event.LeftUp()) {
4154             if ((item == m_curItem) && (m_curColumn != -1) &&
4155                 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
4156                 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))
4157             ){
4158                 m_editTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
4159                 bSkip = false;
4160             }
4161             m_lastOnSame = false;
4162         }
4163     }
4164 
4165 
4166 // ----------  HANDLE DOUBLE-CLICKS  ----------
4167     if (mayDoubleClick && event.LeftDClick()) {
4168 
4169         bSkip = false;
4170 
4171         // double clicking should not start editing the item label
4172         m_editTimer->Stop();
4173         m_lastOnSame = false;
4174 
4175         // selection reset to that single item which was double-clicked
4176         if (SelectItem(item, (wxTreeItemId*)NULL, true)) {  // unselect others --return false if vetoed
4177 
4178             // selection change not vetoed, send activate event
4179             if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, item)) {
4180 
4181                 // if the user code didn't process the activate event,
4182                 // handle it ourselves by toggling the item when it is
4183                 // double clicked
4184                 if (item && item->HasPlus()) Toggle(item);
4185             }
4186         }
4187     }
4188 
4189 
4190 // ----------  HANDLE DRAGGING  ----------
4191 // NOTE: drag itself makes no change to selection
4192     if (mayDrag) {  // actually this is always true
4193 
4194         // CASE 1: we were dragging => continue, end, abort
4195         if (m_isDragging) {
4196 
4197             // CASE 1.1: click aborts drag:
4198             if (event.LeftDown() || event.MiddleDown() || event.RightDown()) {
4199 
4200                 bSkip = false;
4201 
4202                 // stop dragging
4203                 m_isDragStarted = m_isDragging = false;
4204                 if (HasCapture()) ReleaseMouse();
4205                 RefreshSelected();
4206 
4207             // CASE 1.2: still dragging
4208             } else if (event.Dragging()) {
4209 
4210                 ;; // nothing to do
4211 
4212             // CASE 1.3: dragging now ends normally
4213             } else {
4214 
4215                 bSkip = false;
4216 
4217                 // stop dragging
4218                 m_isDragStarted = m_isDragging = false;
4219                 if (HasCapture()) ReleaseMouse();
4220                 RefreshSelected();
4221 
4222                 // send drag end event
4223                 wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, 0);
4224                 event.SetPoint(p);
4225                 event.SetInt(m_curColumn);
4226                 SendEvent(0, item, &event);
4227             }
4228 
4229         // CASE 2: not were not dragging => continue, start
4230         } else if (event.Dragging()) {
4231 
4232             // We will really start dragging if we've moved beyond a few pixels
4233             if (m_isDragStarted) {
4234                 const int tolerance = 3;
4235                 int dx = abs(p.x - m_dragStartPos.x);
4236                 int dy = abs(p.y - m_dragStartPos.y);
4237                 if (dx <= tolerance && dy <= tolerance)
4238                     return;
4239             // determine drag start
4240             } else {
4241                 m_dragStartPos = p;
4242                 m_dragCol = GetCurrentColumn();
4243                 m_dragItem = item;
4244                 m_isDragStarted = true;
4245                 return;
4246             }
4247 
4248             bSkip = false;
4249 
4250             // we are now dragging
4251             m_isDragging = true;
4252             RefreshSelected();
4253             CaptureMouse(); // TODO: usefulness unclear
4254 
4255             wxTreeEvent nevent(event.LeftIsDown()
4256                                   ? wxEVT_COMMAND_TREE_BEGIN_DRAG
4257                                   : wxEVT_COMMAND_TREE_BEGIN_RDRAG, 0);
4258             nevent.SetPoint(p);
4259             nevent.SetInt(m_dragCol);
4260             nevent.Veto();
4261             SendEvent(0, m_dragItem, &nevent);
4262         }
4263     }
4264 
4265 
4266     if (bSkip) event.Skip();
4267 }
4268 
4269 
OnIdle(wxIdleEvent & WXUNUSED (event))4270 void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
4271     /* after all changes have been done to the tree control,
4272      * we actually redraw the tree when everything is over */
4273 
4274     if (!m_dirty) return;
4275 
4276     m_dirty = false;
4277 
4278     CalculatePositions();
4279     Refresh();
4280     AdjustMyScrollbars();
4281 }
4282 
OnScroll(wxScrollWinEvent & event)4283 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
4284 
4285     // send event to wxTreeListCtrl (for user code)
4286     if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
4287 
4288 #if !wxCHECK_VERSION(3, 0, 0) && defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4289     wxScrolledWindow::OnScroll(event);
4290 #else
4291     HandleOnScroll( event );
4292 #endif
4293 
4294     if(event.GetOrientation() == wxHORIZONTAL) {
4295         m_owner->GetHeaderWindow()->Refresh();
4296         m_owner->GetHeaderWindow()->Update();
4297     }
4298 }
4299 
CalculateSize(wxTreeListItem * item,wxDC & dc)4300 void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
4301     wxCoord text_w = 0;
4302     wxCoord text_h = 0;
4303 
4304     dc.SetFont (GetItemFont (item));
4305     dc.GetTextExtent (item->GetText(m_main_column).size() > 0
4306             ? item->GetText (m_main_column)
4307             : _T(" "),  // blank to avoid zero height and no highlight width
4308         &text_w, &text_h);
4309     // restore normal font
4310     dc.SetFont (m_normalFont);
4311 
4312     int max_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
4313     if (max_h < 30) { // add 10% space if greater than 30 pixels
4314         max_h += 2; // minimal 2 pixel space
4315     }else{
4316         max_h += max_h / 10; // otherwise 10% space
4317     }
4318 
4319     item->SetHeight (max_h);
4320     if (max_h > m_lineHeight) m_lineHeight = max_h;
4321     item->SetWidth(m_imgWidth + text_w+2);
4322 }
4323 
4324 // -----------------------------------------------------------------------------
CalculateLevel(wxTreeListItem * item,wxDC & dc,int level,int & y,int x_colstart)4325 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
4326                                            int level, int &y, int x_colstart) {
4327 
4328     // calculate position of vertical lines
4329     int x = x_colstart + MARGIN; // start of column
4330     if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
4331     if (HasButtons()) {
4332         x += (m_btnWidth-m_btnWidth2); // half button space
4333     }else{
4334         x += (m_indent-m_indent/2);
4335     }
4336     if (HasFlag(wxTR_HIDE_ROOT)) {
4337         x += m_indent * (level-1); // indent but not level 1
4338     }else{
4339         x += m_indent * level; // indent according to level
4340     }
4341 
4342     // a hidden root is not evaluated, but its children are always
4343     if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
4344 
4345     CalculateSize( item, dc );
4346 
4347     // set its position
4348     item->SetX (x);
4349     item->SetY (y);
4350     y += GetLineHeight(item);
4351 
4352     // we don't need to calculate collapsed branches
4353     if ( !item->IsExpanded() ) return;
4354 
4355 Recurse:
4356     wxArrayTreeListItems& children = item->GetChildren();
4357     long n, count = (long)children.Count();
4358     ++level;
4359     for (n = 0; n < count; ++n) {
4360         CalculateLevel( children[n], dc, level, y, x_colstart );  // recurse
4361     }
4362 }
4363 
CalculatePositions()4364 void wxTreeListMainWindow::CalculatePositions() {
4365     if ( !m_rootItem ) return;
4366 
4367     wxClientDC dc(this);
4368     PrepareDC( dc );
4369 
4370     dc.SetFont( m_normalFont );
4371 
4372     dc.SetPen( m_dottedPen );
4373     //if(GetImageList() == NULL)
4374     // m_lineHeight = (int)(dc.GetCharHeight() + 4);
4375 
4376     int y = 2;
4377     int x_colstart = 0;
4378     for (int i = 0; i < (int)GetMainColumn(); ++i) {
4379         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
4380         x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
4381     }
4382     CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
4383 }
4384 
RefreshSubtree(wxTreeListItem * item)4385 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
4386     if (m_dirty) return;
4387 
4388     wxClientDC dc(this);
4389     PrepareDC(dc);
4390 
4391     int cw = 0;
4392     int ch = 0;
4393     GetVirtualSize( &cw, &ch );
4394 
4395     wxRect rect;
4396     rect.x = dc.LogicalToDeviceX( 0 );
4397     rect.width = cw;
4398     rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
4399     rect.height = ch;
4400 
4401     Refresh (true, &rect );
4402     AdjustMyScrollbars();
4403 }
4404 
RefreshLine(wxTreeListItem * item)4405 void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
4406     if (m_dirty) return;
4407 
4408     wxClientDC dc(this);
4409     PrepareDC( dc );
4410 
4411     int cw = 0;
4412     int ch = 0;
4413     GetVirtualSize( &cw, &ch );
4414 
4415     wxRect rect;
4416     rect.x = dc.LogicalToDeviceX( 0 );
4417     rect.y = dc.LogicalToDeviceY( item->GetY() );
4418     rect.width = cw;
4419     rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
4420 
4421     Refresh (true, &rect);
4422 }
4423 
RefreshSelected()4424 void wxTreeListMainWindow::RefreshSelected() {
4425     // TODO: this is awfully inefficient, we should keep the list of all
4426     //       selected items internally, should be much faster
4427     if (m_rootItem) {
4428         RefreshSelectedUnder (m_rootItem);
4429     }
4430 }
4431 
RefreshSelectedUnder(wxTreeListItem * item)4432 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
4433     if (item->IsSelected()) {
4434         RefreshLine (item);
4435     }
4436 
4437     const wxArrayTreeListItems& children = item->GetChildren();
4438     long count = (long)children.GetCount();
4439     for (long n = 0; n < count; n++ ) {
4440         RefreshSelectedUnder (children[n]);
4441     }
4442 }
4443 
4444 // ----------------------------------------------------------------------------
4445 // changing colours: we need to refresh the tree control
4446 // ----------------------------------------------------------------------------
4447 
SetBackgroundColour(const wxColour & colour)4448 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
4449     if (!wxWindow::SetBackgroundColour(colour)) return false;
4450 
4451     Refresh();
4452     return true;
4453 }
4454 
SetForegroundColour(const wxColour & colour)4455 bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
4456     if (!wxWindow::SetForegroundColour(colour)) return false;
4457 
4458     Refresh();
4459     return true;
4460 }
4461 
SetItemText(const wxTreeItemId & itemId,int column,const wxString & text)4462 void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column, const wxString& text) {
4463     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
4464 
4465     wxClientDC dc (this);
4466     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
4467     item->SetText (column, text);
4468     CalculateSize (item, dc);
4469     RefreshLine (item);
4470 }
4471 
GetItemText(const wxTreeItemId & itemId,int column) const4472 wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId, int column) const {
4473     wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
4474 
4475     if( IsVirtual() )   return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
4476     else                return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
4477 }
4478 
GetItemText(wxTreeItemData * item,int column) const4479 wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item, int column) const {
4480    wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4481    return m_owner->OnGetItemText(item, column);
4482 }
4483 
SetFocus()4484 void wxTreeListMainWindow::SetFocus() {
4485     wxWindow::SetFocus();
4486 }
4487 
4488 
GetItemWidth(int column,wxTreeListItem * item)4489 int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
4490     if (!item) return 0;
4491 
4492     // determine item width
4493     int w = 0, h = 0;
4494     wxFont font = GetItemFont (item);
4495     GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
4496     w += 2*MARGIN;
4497 
4498     // calculate width
4499     int width = w + 2*MARGIN;
4500     if (column == GetMainColumn()) {
4501         width += MARGIN;
4502         if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
4503         if (HasButtons()) width += m_btnWidth + LINEATROOT;
4504         if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
4505 
4506         // count indent level
4507         int level = 0;
4508         wxTreeListItem *parent = item->GetItemParent();
4509         wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
4510         while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
4511             level++;
4512             parent = parent->GetItemParent();
4513         }
4514         if (level) width += level * GetIndent();
4515     }
4516 
4517     return width;
4518 }
4519 
GetBestColumnWidth(int column,wxTreeItemId parent)4520 int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
4521     int maxWidth, h;
4522     GetClientSize (&maxWidth, &h);
4523     int width = 0;
4524 
4525     // get root if on item
4526     if (!parent.IsOk()) parent = GetRootItem();
4527 
4528     // add root width
4529     if (!HasFlag(wxTR_HIDE_ROOT)) {
4530         int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
4531         if (width < w) width = w;
4532         if (width > maxWidth) return maxWidth;
4533     }
4534 
4535     wxTreeItemIdValue cookie = 0;
4536     wxTreeItemId item = GetFirstChild (parent, cookie);
4537     while (item.IsOk()) {
4538         int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
4539         if (width < w) width = w;
4540         if (width > maxWidth) return maxWidth;
4541 
4542         // check the children of this item
4543         if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
4544             int w = GetBestColumnWidth (column, item);
4545             if (width < w) width = w;
4546             if (width > maxWidth) return maxWidth;
4547         }
4548 
4549         // next sibling
4550         item = GetNextChild (parent, cookie);
4551     }
4552 
4553     return width;
4554 }
4555 
4556 
SendEvent(wxEventType event_type,wxTreeListItem * item,wxTreeEvent * event)4557 bool wxTreeListMainWindow::SendEvent(wxEventType event_type, wxTreeListItem *item, wxTreeEvent *event) {
4558 wxTreeEvent nevent (event_type, 0);
4559 
4560     if (event == NULL) {
4561         event = &nevent;
4562         event->SetInt (m_curColumn); // the mouse colum
4563     }
4564 
4565     event->SetEventObject (m_owner);
4566     event->SetId(m_owner->GetId());
4567     if (item) {
4568         event->SetItem (item);
4569     }
4570 
4571     return m_owner->GetEventHandler()->ProcessEvent (*event);
4572 }
4573 
4574 
4575 //-----------------------------------------------------------------------------
4576 //  wxTreeListCtrl
4577 //-----------------------------------------------------------------------------
4578 
4579 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
4580 
4581 BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
4582     EVT_SIZE(wxTreeListCtrl::OnSize)
4583 END_EVENT_TABLE();
4584 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)4585 bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
4586                             const wxPoint& pos,
4587                             const wxSize& size,
4588                             long style, const wxValidator &validator,
4589                             const wxString& name)
4590 {
4591     long main_style = style & ~(wxSIMPLE_BORDER|wxSUNKEN_BORDER|wxDOUBLE_BORDER|
4592                                 wxRAISED_BORDER|wxSTATIC_BORDER);
4593          main_style |= wxWANTS_CHARS ;
4594     long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
4595 
4596     if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
4597        return false;
4598     }
4599     m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
4600                                            main_style, validator);
4601     m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
4602                                                wxPoint(0, 0), wxDefaultSize,
4603                                                wxTAB_TRAVERSAL);
4604     CalculateAndSetHeaderHeight();
4605     return true;
4606 }
4607 
CalculateAndSetHeaderHeight()4608 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4609 {
4610     if (m_header_win) {
4611 
4612         // we use 'g' to get the descent, too
4613         int h;
4614 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
4615 #ifdef __WXMSW__
4616         h = (int)(wxRendererNative::Get().GetHeaderButtonHeight(m_header_win) * 0.8) + 2;
4617 #else
4618         h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win);
4619 #endif
4620 #else
4621         int w, d;
4622         m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
4623         h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
4624 #endif
4625 
4626         // only update if changed
4627         if (h != m_headerHeight) {
4628             m_headerHeight = h;
4629             DoHeaderLayout();
4630         }
4631     }
4632 }
4633 
DoHeaderLayout()4634 void wxTreeListCtrl::DoHeaderLayout()
4635 {
4636     int w, h;
4637     GetClientSize(&w, &h);
4638     if (m_header_win) {
4639         m_header_win->SetSize (0, 0, w, m_headerHeight);
4640         m_header_win->Refresh();
4641     }
4642     if (m_main_win) {
4643         m_main_win->SetSize (0, m_headerHeight, w, h - m_headerHeight);
4644     }
4645 }
4646 
OnSize(wxSizeEvent & WXUNUSED (event))4647 void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
4648 {
4649     DoHeaderLayout();
4650 }
4651 
GetCount() const4652 size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
4653 
GetIndent() const4654 unsigned int wxTreeListCtrl::GetIndent() const
4655 { return m_main_win->GetIndent(); }
4656 
SetIndent(unsigned int indent)4657 void wxTreeListCtrl::SetIndent(unsigned int indent)
4658 { m_main_win->SetIndent(indent); }
4659 
GetLineSpacing() const4660 unsigned int wxTreeListCtrl::GetLineSpacing() const
4661 { return m_main_win->GetLineSpacing(); }
4662 
SetLineSpacing(unsigned int spacing)4663 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
4664 { m_main_win->SetLineSpacing(spacing); }
4665 
GetImageList() const4666 wxImageList* wxTreeListCtrl::GetImageList() const
4667 { return m_main_win->GetImageList(); }
4668 
GetStateImageList() const4669 wxImageList* wxTreeListCtrl::GetStateImageList() const
4670 { return m_main_win->GetStateImageList(); }
4671 
GetButtonsImageList() const4672 wxImageList* wxTreeListCtrl::GetButtonsImageList() const
4673 { return m_main_win->GetButtonsImageList(); }
4674 
SetImageList(wxImageList * imageList)4675 void wxTreeListCtrl::SetImageList(wxImageList* imageList)
4676 { m_main_win->SetImageList(imageList); }
4677 
SetStateImageList(wxImageList * imageList)4678 void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
4679 { m_main_win->SetStateImageList(imageList); }
4680 
SetButtonsImageList(wxImageList * imageList)4681 void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
4682 { m_main_win->SetButtonsImageList(imageList); }
4683 
AssignImageList(wxImageList * imageList)4684 void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
4685 { m_main_win->AssignImageList(imageList); }
4686 
AssignStateImageList(wxImageList * imageList)4687 void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
4688 { m_main_win->AssignStateImageList(imageList); }
4689 
AssignButtonsImageList(wxImageList * imageList)4690 void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
4691 { m_main_win->AssignButtonsImageList(imageList); }
4692 
4693 
4694 
GetItemText(const wxTreeItemId & item,int column) const4695 wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
4696 { return m_main_win->GetItemText (item, column); }
4697 
GetItemImage(const wxTreeItemId & item,wxTreeItemIcon which) const4698 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, wxTreeItemIcon which) const
4699 { return m_main_win->GetItemImage(item, which); }
GetItemImage(const wxTreeItemId & item,int column) const4700 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column) const
4701 { return m_main_win->GetItemImage(item, column); }
4702 
GetItemData(const wxTreeItemId & item) const4703 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
4704 { return m_main_win->GetItemData(item); }
GetItemData(const wxTreeItemId & item,int column) const4705 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item, int column) const
4706 { return m_main_win->GetItemData(item, column); }
4707 
GetItemBold(const wxTreeItemId & item) const4708 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
4709 { return m_main_win->GetItemBold(item); }
GetItemBold(const wxTreeItemId & item,int column) const4710 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item, int column) const
4711 { return m_main_win->GetItemBold(item, column); }
4712 
GetItemTextColour(const wxTreeItemId & item) const4713 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
4714 { return m_main_win->GetItemTextColour(item); }
GetItemTextColour(const wxTreeItemId & item,int column) const4715 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item, int column) const
4716 { return m_main_win->GetItemTextColour(item, column); }
4717 
GetItemBackgroundColour(const wxTreeItemId & item) const4718 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const
4719 { return m_main_win->GetItemBackgroundColour(item); }
GetItemBackgroundColour(const wxTreeItemId & item,int column) const4720 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item, int column) const
4721 { return m_main_win->GetItemBackgroundColour(item, column); }
4722 
GetItemFont(const wxTreeItemId & item) const4723 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
4724 { return m_main_win->GetItemFont(item); }
GetItemFont(const wxTreeItemId & item,int column) const4725 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item, int column) const
4726 { return m_main_win->GetItemFont(item, column); }
4727 
4728 
4729 
SetItemHasChildren(const wxTreeItemId & item,bool has)4730 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
4731 { m_main_win->SetItemHasChildren(item, has); }
4732 
SetItemText(const wxTreeItemId & item,int column,const wxString & text)4733 void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column, const wxString& text)
4734 { m_main_win->SetItemText (item, column, text); }
4735 
SetItemImage(const wxTreeItemId & item,int image,wxTreeItemIcon which)4736 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int image, wxTreeItemIcon which)
4737 { m_main_win->SetItemImage(item, image, which); }
SetItemImage(const wxTreeItemId & item,int column,int image)4738 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int column, int image)
4739 { m_main_win->SetItemImage(item, column, image); }
4740 
SetItemData(const wxTreeItemId & item,wxTreeItemData * data)4741 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,             wxTreeItemData* data)
4742 { m_main_win->SetItemData(item, data); }
SetItemData(const wxTreeItemId & item,int column,wxTreeItemData * data)4743 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item, int column, wxTreeItemData* data)
4744 { m_main_win->SetItemData(item, column, data); }
4745 
SetItemBold(const wxTreeItemId & item,bool bold)4746 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item,             bool bold)
4747 { m_main_win->SetItemBold(item, bold); }
SetItemBold(const wxTreeItemId & item,int column,bool bold)4748 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, int column, bool bold)
4749 { m_main_win->SetItemBold(item, column, bold); }
4750 
SetItemTextColour(const wxTreeItemId & item,const wxColour & colour)4751 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,              const wxColour& colour)
4752 { m_main_win->SetItemTextColour(item, colour); }
SetItemTextColour(const wxTreeItemId & item,int column,const wxColour & colour)4753 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour)
4754 { m_main_win->SetItemTextColour(item, column, colour); }
4755 
SetItemBackgroundColour(const wxTreeItemId & item,const wxColour & colour)4756 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour)
4757 { m_main_win->SetItemBackgroundColour(item, colour); }
SetItemBackgroundColour(const wxTreeItemId & item,int column,const wxColour & colour)4758 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour)
4759 { m_main_win->SetItemBackgroundColour(item, column, colour); }
4760 
SetItemFont(const wxTreeItemId & item,const wxFont & font)4761 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,             const wxFont& font)
4762 { m_main_win->SetItemFont(item, font); }
SetItemFont(const wxTreeItemId & item,int column,const wxFont & font)4763 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item, int column, const wxFont& font)
4764 { m_main_win->SetItemFont(item, column, font); }
4765 
4766 
4767 
SetFont(const wxFont & font)4768 bool wxTreeListCtrl::SetFont(const wxFont& font)
4769 {
4770     if (m_header_win) {
4771         m_header_win->SetFont(font);
4772         CalculateAndSetHeaderHeight();
4773         m_header_win->Refresh();
4774     }
4775     if (m_main_win) {
4776         return m_main_win->SetFont(font);
4777     }else{
4778         return false;
4779     }
4780 }
4781 
SetWindowStyle(const long style)4782 void wxTreeListCtrl::SetWindowStyle(const long style)
4783 {
4784     if(m_main_win)
4785         m_main_win->SetWindowStyle(style);
4786     m_windowStyle = style;
4787     // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4788 }
4789 
GetWindowStyle() const4790 long wxTreeListCtrl::GetWindowStyle() const
4791 {
4792     long style = m_windowStyle;
4793     if(m_main_win)
4794         style |= m_main_win->GetWindowStyle();
4795     return style;
4796 }
4797 
IsVisible(const wxTreeItemId & item,bool fullRow,bool within) const4798 bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow, bool within) const
4799 { return m_main_win->IsVisible(item, fullRow, within); }
4800 
HasChildren(const wxTreeItemId & item) const4801 bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
4802 { return m_main_win->HasChildren(item); }
4803 
IsExpanded(const wxTreeItemId & item) const4804 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
4805 { return m_main_win->IsExpanded(item); }
4806 
IsSelected(const wxTreeItemId & item) const4807 bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
4808 { return m_main_win->IsSelected(item); }
4809 
GetChildrenCount(const wxTreeItemId & item,bool rec)4810 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
4811 { return m_main_win->GetChildrenCount(item, rec); }
4812 
GetRootItem() const4813 wxTreeItemId wxTreeListCtrl::GetRootItem() const
4814 { return m_main_win->GetRootItem(); }
4815 
GetSelection() const4816 wxTreeItemId wxTreeListCtrl::GetSelection() const
4817 { return m_main_win->GetSelection(); }
4818 
GetSelections(wxArrayTreeItemIds & arr) const4819 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
4820 { return m_main_win->GetSelections(arr); }
4821 
GetItemParent(const wxTreeItemId & item) const4822 wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
4823 { return m_main_win->GetItemParent(item); }
4824 
GetFirstChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const4825 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4826                                             wxTreeItemIdValue& cookie) const
4827 { return m_main_win->GetFirstChild(item, cookie); }
4828 
GetNextChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const4829 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4830                                            wxTreeItemIdValue& cookie) const
4831 { return m_main_win->GetNextChild(item, cookie); }
4832 
GetPrevChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const4833 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4834                                            wxTreeItemIdValue& cookie) const
4835 { return m_main_win->GetPrevChild(item, cookie); }
4836 
GetLastChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const4837 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4838                                            wxTreeItemIdValue& cookie) const
4839 { return m_main_win->GetLastChild(item, cookie); }
4840 
4841 
GetNextSibling(const wxTreeItemId & item) const4842 wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
4843 { return m_main_win->GetNextSibling(item); }
4844 
GetPrevSibling(const wxTreeItemId & item) const4845 wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
4846 { return m_main_win->GetPrevSibling(item); }
4847 
GetNext(const wxTreeItemId & item) const4848 wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
4849 { return m_main_win->GetNext(item, true); }
4850 
GetPrev(const wxTreeItemId & item) const4851 wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
4852 { return m_main_win->GetPrev(item, true); }
4853 
GetFirstExpandedItem() const4854 wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
4855 { return m_main_win->GetFirstExpandedItem(); }
4856 
GetNextExpanded(const wxTreeItemId & item) const4857 wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
4858 { return m_main_win->GetNextExpanded(item); }
4859 
GetPrevExpanded(const wxTreeItemId & item) const4860 wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
4861 { return m_main_win->GetPrevExpanded(item); }
4862 
GetFirstVisibleItem(bool fullRow) const4863 wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
4864 { return GetFirstVisible(fullRow); }
GetFirstVisible(bool fullRow,bool within) const4865 wxTreeItemId wxTreeListCtrl::GetFirstVisible(bool fullRow, bool within) const
4866 { return m_main_win->GetFirstVisible(fullRow, within); }
4867 
GetLastVisible(bool fullRow,bool within) const4868 wxTreeItemId wxTreeListCtrl::GetLastVisible(bool fullRow, bool within) const
4869 { return m_main_win->GetLastVisible(fullRow, within); }
4870 
GetNextVisible(const wxTreeItemId & item,bool fullRow,bool within) const4871 wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow, bool within) const
4872 { return m_main_win->GetNextVisible(item, fullRow, within); }
4873 
GetPrevVisible(const wxTreeItemId & item,bool fullRow,bool within) const4874 wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow, bool within) const
4875 { return m_main_win->GetPrevVisible(item, fullRow, within); }
4876 
AddRoot(const wxString & text,int image,int selectedImage,wxTreeItemData * data)4877 wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
4878                                       int selectedImage, wxTreeItemData* data)
4879 { return m_main_win->AddRoot (text, image, selectedImage, data); }
4880 
PrependItem(const wxTreeItemId & parent,const wxString & text,int image,int selectedImage,wxTreeItemData * data)4881 wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
4882                                          const wxString& text, int image,
4883                                          int selectedImage,
4884                                          wxTreeItemData* data)
4885 { return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
4886 
InsertItem(const wxTreeItemId & parent,const wxTreeItemId & previous,const wxString & text,int image,int selectedImage,wxTreeItemData * data)4887 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4888                                         const wxTreeItemId& previous,
4889                                         const wxString& text, int image,
4890                                         int selectedImage,
4891                                         wxTreeItemData* data)
4892 {
4893     return m_main_win->InsertItem(parent, previous, text, image,
4894                                   selectedImage, data);
4895 }
4896 
InsertItem(const wxTreeItemId & parent,size_t index,const wxString & text,int image,int selectedImage,wxTreeItemData * data)4897 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4898                                         size_t index,
4899                                         const wxString& text, int image,
4900                                         int selectedImage,
4901                                         wxTreeItemData* data)
4902 {
4903     return m_main_win->InsertItem(parent, index, text, image,
4904                                   selectedImage, data);
4905 }
4906 
AppendItem(const wxTreeItemId & parent,const wxString & text,int image,int selectedImage,wxTreeItemData * data)4907 wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
4908                                         const wxString& text, int image,
4909                                         int selectedImage,
4910                                         wxTreeItemData* data)
4911 { return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
4912 
Delete(const wxTreeItemId & item)4913 void wxTreeListCtrl::Delete(const wxTreeItemId& item)
4914 { m_main_win->Delete(item); }
4915 
DeleteChildren(const wxTreeItemId & item)4916 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
4917 { m_main_win->DeleteChildren(item); }
4918 
DeleteRoot()4919 void wxTreeListCtrl::DeleteRoot()
4920 { m_main_win->DeleteRoot(); }
4921 
Expand(const wxTreeItemId & item)4922 void wxTreeListCtrl::Expand(const wxTreeItemId& item)
4923 { m_main_win->Expand(item); }
4924 
ExpandAll(const wxTreeItemId & item)4925 void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
4926 { m_main_win->ExpandAll(item); }
4927 
Collapse(const wxTreeItemId & item)4928 void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
4929 { m_main_win->Collapse(item); }
4930 
CollapseAndReset(const wxTreeItemId & item)4931 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
4932 { m_main_win->CollapseAndReset(item); }
4933 
Toggle(const wxTreeItemId & item)4934 void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
4935 { m_main_win->Toggle(item); }
4936 
Unselect()4937 void wxTreeListCtrl::Unselect()
4938 { m_main_win->Unselect(); }
4939 
UnselectAll()4940 void wxTreeListCtrl::UnselectAll()
4941 { m_main_win->UnselectAll(); }
4942 
SelectItem(const wxTreeItemId & item,const wxTreeItemId & last,bool unselect_others)4943 bool wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
4944                                 bool unselect_others)
4945 { return m_main_win->SelectItem (item, last, unselect_others); }
4946 
SelectAll()4947 void wxTreeListCtrl::SelectAll()
4948 { m_main_win->SelectAll(); }
4949 
EnsureVisible(const wxTreeItemId & item)4950 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
4951 { m_main_win->EnsureVisible(item); }
4952 
ScrollTo(const wxTreeItemId & item)4953 void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
4954 { m_main_win->ScrollTo(item); }
4955 
HitTest(const wxPoint & pos,int & flags,int & column)4956 wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
4957 {
4958     wxPoint p = m_main_win->ScreenToClient (ClientToScreen (pos));
4959     return m_main_win->HitTest (p, flags, column);
4960 }
4961 
GetBoundingRect(const wxTreeItemId & item,wxRect & rect,bool textOnly) const4962 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
4963                                      bool textOnly) const
4964 { return m_main_win->GetBoundingRect(item, rect, textOnly); }
4965 
EditLabel(const wxTreeItemId & item,int column)4966 void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
4967     { m_main_win->EditLabel (item, column); }
EndEdit(bool isCancelled)4968 void wxTreeListCtrl::EndEdit(bool isCancelled)
4969     { m_main_win->EndEdit(isCancelled); }
4970 
OnCompareItems(const wxTreeItemId & item1,const wxTreeItemId & item2)4971 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
4972 {
4973     // do the comparison here and not in m_main_win in order to allow
4974     // override in child class
4975     return wxStrcmp(GetItemText(item1), GetItemText(item2));
4976 }
OnCompareItems(const wxTreeItemId & item1,const wxTreeItemId & item2,int column)4977 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2, int column)
4978 {
4979     // do the comparison here and not in m_main_win in order to allow
4980     // override in child class
4981     return wxStrcmp(GetItemText(item1, column), GetItemText(item2, column));
4982 }
4983 
SortChildren(const wxTreeItemId & item,int column,bool reverseOrder)4984 void wxTreeListCtrl::SortChildren(const wxTreeItemId& item, int column, bool reverseOrder)
4985 { m_main_win->SortChildren(item, column, reverseOrder); }
4986 
FindItem(const wxTreeItemId & item,int column,const wxString & str,int mode)4987 wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode)
4988 { return m_main_win->FindItem (item, column, str, mode); }
4989 
SetDragItem(const wxTreeItemId & item)4990 void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
4991 { m_main_win->SetDragItem (item); }
4992 
SetBackgroundColour(const wxColour & colour)4993 bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
4994 {
4995     if (!m_main_win) return false;
4996     return m_main_win->SetBackgroundColour(colour);
4997 }
4998 
SetForegroundColour(const wxColour & colour)4999 bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
5000 {
5001     if (!m_main_win) return false;
5002     return m_main_win->SetForegroundColour(colour);
5003 }
5004 
GetColumnCount() const5005 int wxTreeListCtrl::GetColumnCount() const
5006 { return m_main_win->GetColumnCount(); }
5007 
SetColumnWidth(int column,int width)5008 void wxTreeListCtrl::SetColumnWidth(int column, int width)
5009 {
5010     m_header_win->SetColumnWidth (column, width);
5011     m_header_win->Refresh();
5012 }
5013 
GetColumnWidth(int column) const5014 int wxTreeListCtrl::GetColumnWidth(int column) const
5015 { return m_header_win->GetColumnWidth(column); }
5016 
SetMainColumn(int column)5017 void wxTreeListCtrl::SetMainColumn(int column)
5018 { m_main_win->SetMainColumn(column); }
5019 
GetMainColumn() const5020 int wxTreeListCtrl::GetMainColumn() const
5021 { return m_main_win->GetMainColumn(); }
5022 
SetColumnText(int column,const wxString & text)5023 void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
5024 {
5025     m_header_win->SetColumnText (column, text);
5026     m_header_win->Refresh();
5027 }
5028 
GetColumnText(int column) const5029 wxString wxTreeListCtrl::GetColumnText(int column) const
5030 { return m_header_win->GetColumnText(column); }
5031 
AddColumn(const wxTreeListColumnInfo & colInfo)5032 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
5033 {
5034     m_header_win->AddColumn (colInfo);
5035     DoHeaderLayout();
5036 }
5037 
InsertColumn(int before,const wxTreeListColumnInfo & colInfo)5038 void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
5039 {
5040     m_header_win->InsertColumn (before, colInfo);
5041     m_header_win->Refresh();
5042 }
5043 
RemoveColumn(int column)5044 void wxTreeListCtrl::RemoveColumn(int column)
5045 {
5046     m_header_win->RemoveColumn (column);
5047     m_header_win->Refresh();
5048 }
5049 
SetColumn(int column,const wxTreeListColumnInfo & colInfo)5050 void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
5051 {
5052     m_header_win->SetColumn (column, colInfo);
5053     m_header_win->Refresh();
5054 }
5055 
GetColumn(int column) const5056 const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
5057 { return m_header_win->GetColumn(column); }
5058 
GetColumn(int column)5059 wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column)
5060 { return m_header_win->GetColumn(column); }
5061 
SetColumnImage(int column,int image)5062 void wxTreeListCtrl::SetColumnImage(int column, int image)
5063 {
5064     m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
5065     m_header_win->Refresh();
5066 }
5067 
GetColumnImage(int column) const5068 int wxTreeListCtrl::GetColumnImage(int column) const
5069 {
5070     return m_header_win->GetColumn(column).GetImage();
5071 }
5072 
SetColumnEditable(int column,bool shown)5073 void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
5074 {
5075     m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
5076 }
5077 
SetColumnShown(int column,bool shown)5078 void wxTreeListCtrl::SetColumnShown(int column, bool shown)
5079 {
5080     wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
5081     m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
5082     m_header_win->Refresh();
5083 }
5084 
IsColumnEditable(int column) const5085 bool wxTreeListCtrl::IsColumnEditable(int column) const
5086 {
5087     return m_header_win->GetColumn(column).IsEditable();
5088 }
5089 
IsColumnShown(int column) const5090 bool wxTreeListCtrl::IsColumnShown(int column) const
5091 {
5092     return m_header_win->GetColumn(column).IsShown();
5093 }
5094 
SetColumnAlignment(int column,int flag)5095 void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
5096 {
5097     m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
5098     m_header_win->Refresh();
5099 }
5100 
GetColumnAlignment(int column) const5101 int wxTreeListCtrl::GetColumnAlignment(int column) const
5102 {
5103     return m_header_win->GetColumn(column).GetAlignment();
5104 }
5105 
Refresh(bool erase,const wxRect * rect)5106 void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
5107 {
5108     m_main_win->Refresh (erase, rect);
5109     m_header_win->Refresh (erase, rect);
5110 }
5111 
SetFocus()5112 void wxTreeListCtrl::SetFocus()
5113 { m_main_win->SetFocus(); }
5114 
DoGetBestSize() const5115 wxSize wxTreeListCtrl::DoGetBestSize() const
5116 {
5117     wxSize bestSizeHeader = m_header_win->GetBestSize();
5118     wxSize bestSizeMain = m_main_win->GetBestSize();
5119     return wxSize (bestSizeHeader.x > bestSizeMain.x ? bestSizeHeader.x : bestSizeMain.x, bestSizeHeader.y + bestSizeMain.y);
5120 }
5121 
OnGetItemText(wxTreeItemData * WXUNUSED (item),long WXUNUSED (column)) const5122 wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
5123 {
5124     return wxEmptyString;
5125 }
5126 
SetToolTip(const wxString & tip)5127 void wxTreeListCtrl::SetToolTip(const wxString& tip) {
5128     m_header_win->SetToolTip(tip);
5129     m_main_win->SetToolTip(tip);
5130 }
SetToolTip(wxToolTip * tip)5131 void wxTreeListCtrl::SetToolTip(wxToolTip *tip) {
5132     m_header_win->SetToolTip(tip);
5133     m_main_win->SetToolTip(tip);
5134 }
5135 
SetItemToolTip(const wxTreeItemId & item,const wxString & tip)5136 void wxTreeListCtrl::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
5137     m_main_win->SetItemToolTip(item, tip);
5138 }
5139 
SetCurrentItem(const wxTreeItemId & itemId)5140 void wxTreeListCtrl::SetCurrentItem(const wxTreeItemId& itemId) {
5141     m_main_win->SetCurrentItem(itemId);
5142 }
5143