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