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