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