]> git.saurik.com Git - wxWidgets.git/blob - wxPython/contrib/gizmos/wxCode/src/treelistctrl.cpp
KeyCode --> GetKeyCode
[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 style &= ~wxTR_LINES_AT_ROOT;
1860 style |= wxTR_NO_LINES;
1861
1862 int major,minor;
1863 wxGetOsVersion( &major, &minor );
1864 if (major < 10) style |= wxTR_ROW_LINES;
1865 #endif
1866
1867 wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
1868
1869 #if wxUSE_VALIDATORS
1870 SetValidator(validator);
1871 #endif
1872
1873 #if !wxCHECK_VERSION(2, 5, 0)
1874 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX));
1875 #else
1876 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX));
1877 #endif
1878
1879 #ifdef __WXMSW__
1880 {
1881 int i, j;
1882 wxBitmap bmp(8, 8);
1883 wxMemoryDC bdc;
1884 bdc.SelectObject(bmp);
1885 bdc.SetPen(*wxGREY_PEN);
1886 bdc.DrawRectangle(-1, -1, 10, 10);
1887 for (i = 0; i < 8; i++) {
1888 for (j = 0; j < 8; j++) {
1889 if (!((i + j) & 1)) {
1890 bdc.DrawPoint(i, j);
1891 }
1892 }
1893 }
1894
1895 m_dottedPen = wxPen(bmp, 1);
1896 }
1897 #else
1898 //? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86
1899 m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
1900 #endif
1901
1902 m_owner = parent;
1903 m_main_column = 0;
1904
1905 return true;
1906 }
1907
1908 wxTreeListMainWindow::~wxTreeListMainWindow() {
1909 delete m_hilightBrush;
1910 delete m_hilightUnfocusedBrush;
1911
1912 delete m_dragTimer;
1913 delete m_renameTimer;
1914 delete m_findTimer;
1915 if (m_ownsImageListNormal) delete m_imageListNormal;
1916 if (m_ownsImageListState) delete m_imageListState;
1917 if (m_ownsImageListButtons) delete m_imageListButtons;
1918
1919 DeleteRoot();
1920 }
1921
1922
1923 //-----------------------------------------------------------------------------
1924 // accessors
1925 //-----------------------------------------------------------------------------
1926
1927 size_t wxTreeListMainWindow::GetCount() const {
1928 return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount();
1929 }
1930
1931 void wxTreeListMainWindow::SetIndent (unsigned int indent) {
1932 m_indent = wxMax ((unsigned)MININDENT, indent);
1933 m_dirty = true;
1934 }
1935
1936 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) {
1937 m_linespacing = spacing;
1938 m_dirty = true;
1939 CalculateLineHeight();
1940 }
1941
1942 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item,
1943 bool recursively) {
1944 wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item"));
1945 return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively);
1946 }
1947
1948 void wxTreeListMainWindow::SetWindowStyle (const long styles) {
1949 // right now, just sets the styles. Eventually, we may
1950 // want to update the inherited styles, but right now
1951 // none of the parents has updatable styles
1952 m_windowStyle = styles;
1953 m_dirty = true;
1954 }
1955
1956 //-----------------------------------------------------------------------------
1957 // functions to work with tree items
1958 //-----------------------------------------------------------------------------
1959
1960 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column,
1961 wxTreeItemIcon which) const {
1962 wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item"));
1963 return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which);
1964 }
1965
1966 wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const {
1967 wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
1968 return ((wxTreeListItem*) item.m_pItem)->GetData();
1969 }
1970
1971 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const {
1972 wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
1973 return ((wxTreeListItem *)item.m_pItem)->IsBold();
1974 }
1975
1976 wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const {
1977 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1978 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1979 return pItem->Attr().GetTextColour();
1980 }
1981
1982 wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const {
1983 wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
1984 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1985 return pItem->Attr().GetBackgroundColour();
1986 }
1987
1988 wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const {
1989 wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
1990 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1991 return pItem->Attr().GetFont();
1992 }
1993
1994 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column,
1995 int image, wxTreeItemIcon which) {
1996 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
1997 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
1998 pItem->SetImage (column, image, which);
1999 wxClientDC dc (this);
2000 CalculateSize (pItem, dc);
2001 RefreshLine (pItem);
2002 }
2003
2004 void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item,
2005 wxTreeItemData *data) {
2006 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2007 ((wxTreeListItem*) item.m_pItem)->SetData(data);
2008 }
2009
2010 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item,
2011 bool has) {
2012 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2013 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2014 pItem->SetHasPlus (has);
2015 RefreshLine (pItem);
2016 }
2017
2018 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, bool bold) {
2019 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2020 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2021 if (pItem->IsBold() != bold) { // avoid redrawing if no real change
2022 pItem->SetBold (bold);
2023 RefreshLine (pItem);
2024 }
2025 }
2026
2027 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item,
2028 const wxColour& colour) {
2029 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2030 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2031 pItem->Attr().SetTextColour (colour);
2032 RefreshLine (pItem);
2033 }
2034
2035 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item,
2036 const wxColour& colour) {
2037 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2038 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2039 pItem->Attr().SetBackgroundColour (colour);
2040 RefreshLine (pItem);
2041 }
2042
2043 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item,
2044 const wxFont& font) {
2045 wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2046 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2047 pItem->Attr().SetFont (font);
2048 RefreshLine (pItem);
2049 }
2050
2051 bool wxTreeListMainWindow::SetFont (const wxFont &font) {
2052 wxScrolledWindow::SetFont (font);
2053 m_normalFont = font;
2054 m_boldFont = wxFont (m_normalFont.GetPointSize(),
2055 m_normalFont.GetFamily(),
2056 m_normalFont.GetStyle(),
2057 wxBOLD,
2058 m_normalFont.GetUnderlined(),
2059 m_normalFont.GetFaceName());
2060 CalculateLineHeight();
2061 return true;
2062 }
2063
2064
2065 // ----------------------------------------------------------------------------
2066 // item status inquiries
2067 // ----------------------------------------------------------------------------
2068
2069 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow) const {
2070 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2071
2072 // An item is only visible if it's not a descendant of a collapsed item
2073 wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2074 wxTreeListItem* parent = pItem->GetItemParent();
2075 while (parent) {
2076 if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break;
2077 if (!parent->IsExpanded()) return false;
2078 parent = parent->GetItemParent();
2079 }
2080
2081 wxSize clientSize = GetClientSize();
2082 wxRect rect;
2083 if ((!GetBoundingRect (item, rect)) ||
2084 ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
2085 (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y) ||
2086 (!fullRow && (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x))) return false;
2087
2088 return true;
2089 }
2090
2091 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const {
2092 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2093
2094 // consider that the item does have children if it has the "+" button: it
2095 // might not have them (if it had never been expanded yet) but then it
2096 // could have them as well and it's better to err on this side rather than
2097 // disabling some operations which are restricted to the items with
2098 // children for an item which does have them
2099 return ((wxTreeListItem*) item.m_pItem)->HasPlus();
2100 }
2101
2102 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const {
2103 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2104 return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
2105 }
2106
2107 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const {
2108 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2109 return ((wxTreeListItem*) item.m_pItem)->IsSelected();
2110 }
2111
2112 bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item) const {
2113 wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2114 return ((wxTreeListItem*) item.m_pItem)->IsBold();
2115 }
2116
2117 // ----------------------------------------------------------------------------
2118 // navigation
2119 // ----------------------------------------------------------------------------
2120
2121 wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const {
2122 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2123 return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
2124 }
2125
2126 #if !wxCHECK_VERSION(2, 5, 0)
2127 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2128 long& cookie) const {
2129 #else
2130 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2131 wxTreeItemIdValue& cookie) const {
2132 #endif
2133 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2134 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2135 cookie = 0;
2136 return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId();
2137 }
2138
2139 #if !wxCHECK_VERSION(2, 5, 0)
2140 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2141 long& cookie) const {
2142 #else
2143 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2144 wxTreeItemIdValue& cookie) const {
2145 #endif
2146 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2147 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2148 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2149 long *pIndex = ((long*)&cookie);
2150 return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId();
2151 }
2152
2153 #if !wxCHECK_VERSION(2, 5, 0)
2154 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2155 long& cookie) const {
2156 #else
2157 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2158 wxTreeItemIdValue& cookie) const {
2159 #endif
2160 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2161 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2162 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2163 long *pIndex = (long*)&cookie;
2164 return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId();
2165 }
2166
2167 #if !wxCHECK_VERSION(2, 5, 0)
2168 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2169 long& cookie) const {
2170 #else
2171 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2172 wxTreeItemIdValue& cookie) const {
2173 #endif
2174 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2175 wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2176 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2177 long *pIndex = ((long*)&cookie);
2178 (*pIndex) = children.Count();
2179 return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId();
2180 }
2181
2182 wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const {
2183 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2184
2185 // get parent
2186 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2187 wxTreeListItem *parent = i->GetItemParent();
2188 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2189
2190 // get index
2191 wxArrayTreeListItems& siblings = parent->GetChildren();
2192 size_t index = siblings.Index (i);
2193 wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2194 return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId();
2195 }
2196
2197 wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const {
2198 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2199
2200 // get parent
2201 wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2202 wxTreeListItem *parent = i->GetItemParent();
2203 if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2204
2205 // get index
2206 wxArrayTreeListItems& siblings = parent->GetChildren();
2207 size_t index = siblings.Index(i);
2208 wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2209 return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId();
2210 }
2211
2212 // Only for internal use right now, but should probably be public
2213 wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const {
2214 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2215
2216 // if there are any children, return first child
2217 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2218 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2219 if (children.GetCount() > 0) return children.Item (0);
2220 }
2221
2222 // get sibling of this item or of the ancestors instead
2223 wxTreeItemId next;
2224 wxTreeItemId parent = item;
2225 do {
2226 next = GetNextSibling (parent);
2227 parent = GetItemParent (parent);
2228 } while (!next.IsOk() && parent.IsOk());
2229 return next;
2230 }
2231
2232 // Only for internal use right now, but should probably be public
2233 wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const {
2234 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2235
2236 // if there are any children, return last child
2237 if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2238 wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2239 if (children.GetCount() > 0) return children.Item (children.GetCount()-1);
2240 }
2241
2242 // get sibling of this item or of the ancestors instead
2243 wxTreeItemId next;
2244 wxTreeItemId parent = item;
2245 do {
2246 next = GetPrevSibling (parent);
2247 parent = GetItemParent (parent);
2248 } while (!next.IsOk() && parent.IsOk());
2249 return next;
2250 }
2251
2252 wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
2253 return GetNextExpanded (GetRootItem());
2254 }
2255
2256 wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const {
2257 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2258 return GetNext (item, false);
2259 }
2260
2261 wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const {
2262 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2263 return GetPrev (item, false);
2264 }
2265
2266 wxTreeItemId wxTreeListMainWindow::GetFirstVisibleItem (bool fullRow) const {
2267 return GetNextVisible (GetRootItem(), fullRow);
2268 }
2269
2270 wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow) const {
2271 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2272 wxTreeItemId id = GetNext (item, false);
2273 while (id.IsOk()) {
2274 if (IsVisible (id, fullRow)) return id;
2275 id = GetNext (id, false);
2276 }
2277 return wxTreeItemId();
2278 }
2279
2280 wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow) const {
2281 wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2282 wxTreeItemId id = GetPrev (item, true);
2283 while (id.IsOk()) {
2284 if (IsVisible (id, fullRow)) return id;
2285 id = GetPrev(id, true);
2286 }
2287 return wxTreeItemId();
2288 }
2289
2290 // ----------------------------------------------------------------------------
2291 // operations
2292 // ----------------------------------------------------------------------------
2293
2294 wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId,
2295 size_t previous,
2296 const wxString& text,
2297 int image, int selImage,
2298 wxTreeItemData *data) {
2299 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2300 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2301 m_dirty = true; // do this first so stuff below doesn't cause flicker
2302
2303 wxArrayString arr;
2304 arr.Alloc (GetColumnCount());
2305 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2306 arr[m_main_column] = text;
2307 wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data);
2308 if (data != NULL) {
2309 #if !wxCHECK_VERSION(2, 5, 0)
2310 data->SetId ((long)item);
2311 #else
2312 data->SetId (item);
2313 #endif
2314 }
2315 parent->Insert (item, previous);
2316
2317 return item;
2318 }
2319
2320 wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text,
2321 int image, int selImage,
2322 wxTreeItemData *data) {
2323 wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
2324 wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2325 m_dirty = true; // do this first so stuff below doesn't cause flicker
2326
2327 wxArrayString arr;
2328 arr.Alloc (GetColumnCount());
2329 for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2330 arr[m_main_column] = text;
2331 m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data);
2332 if (data != NULL) {
2333 #if !wxCHECK_VERSION(2, 5, 0)
2334 data->SetId((long)m_rootItem);
2335 #else
2336 data->SetId(m_rootItem);
2337 #endif
2338 }
2339 if (HasFlag(wxTR_HIDE_ROOT)) {
2340 // if we will hide the root, make sure children are visible
2341 m_rootItem->SetHasPlus();
2342 m_rootItem->Expand();
2343 #if !wxCHECK_VERSION(2, 5, 0)
2344 long cookie = 0;
2345 #else
2346 wxTreeItemIdValue cookie = 0;
2347 #endif
2348 m_curItem = (wxTreeListItem*)GetFirstChild (m_rootItem, cookie).m_pItem;
2349 }
2350 return m_rootItem;
2351 }
2352
2353 wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent,
2354 const wxString& text,
2355 int image, int selImage,
2356 wxTreeItemData *data) {
2357 return DoInsertItem (parent, 0u, text, image, selImage, data);
2358 }
2359
2360 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2361 const wxTreeItemId& idPrevious,
2362 const wxString& text,
2363 int image, int selImage,
2364 wxTreeItemData *data) {
2365 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2366 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2367
2368 int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
2369 wxASSERT_MSG( index != wxNOT_FOUND,
2370 _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
2371
2372 return DoInsertItem (parentId, ++index, text, image, selImage, data);
2373 }
2374
2375 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2376 size_t before,
2377 const wxString& text,
2378 int image, int selImage,
2379 wxTreeItemData *data) {
2380 wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2381 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2382
2383 return DoInsertItem (parentId, before, text, image, selImage, data);
2384 }
2385
2386 wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId,
2387 const wxString& text,
2388 int image, int selImage,
2389 wxTreeItemData *data) {
2390 wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
2391 wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2392
2393 return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data);
2394 }
2395
2396 void wxTreeListMainWindow::SendDeleteEvent (wxTreeListItem *item) {
2397 // send event to user code
2398 wxTreeEvent event (wxEVT_COMMAND_TREE_DELETE_ITEM, m_owner->GetId());
2399 #if !wxCHECK_VERSION(2, 5, 0)
2400 event.SetItem ((long)item);
2401 #else
2402 event.SetItem (item);
2403 #endif
2404 event.SetEventObject (m_owner);
2405 m_owner->ProcessEvent (event);
2406 }
2407
2408 void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
2409 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2410 wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
2411 m_dirty = true; // do this first so stuff below doesn't cause flicker
2412
2413 // don't stay with invalid m_shiftItem or we will crash in the next call to OnChar()
2414 bool changeKeyCurrent = false;
2415 wxTreeListItem *itemKey = m_shiftItem;
2416 while (itemKey) {
2417 if (itemKey == item) { // m_shiftItem is a descendant of the item being deleted
2418 changeKeyCurrent = true;
2419 break;
2420 }
2421 itemKey = itemKey->GetItemParent();
2422 }
2423
2424 wxTreeListItem *parent = item->GetItemParent();
2425 if (parent) {
2426 parent->GetChildren().Remove (item); // remove by value
2427 }
2428 if (changeKeyCurrent) m_shiftItem = parent;
2429
2430 SendDeleteEvent (item);
2431 if (m_selectItem == item) m_selectItem = (wxTreeListItem*)NULL;
2432 item->DeleteChildren (this);
2433 delete item;
2434 }
2435
2436 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
2437 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2438 m_dirty = true; // do this first so stuff below doesn't cause flicker
2439
2440 item->DeleteChildren (this);
2441 }
2442
2443 void wxTreeListMainWindow::DeleteRoot() {
2444 if (m_rootItem) {
2445 m_dirty = true;
2446 SendDeleteEvent (m_rootItem);
2447 m_curItem = (wxTreeListItem*)NULL;
2448 m_selectItem= (wxTreeListItem*)NULL;
2449 m_rootItem->DeleteChildren (this);
2450 delete m_rootItem;
2451 m_rootItem = NULL;
2452 }
2453 }
2454
2455 void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
2456 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2457 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
2458
2459 if (!item->HasPlus() || item->IsExpanded()) return;
2460
2461 // send event to user code
2462 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_EXPANDING, m_owner->GetId());
2463 #if !wxCHECK_VERSION(2, 5, 0)
2464 event.SetItem ((long)item);
2465 #else
2466 event.SetItem (item);
2467 #endif
2468 event.SetEventObject (m_owner);
2469 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // expand canceled
2470
2471 item->Expand();
2472 m_dirty = true;
2473
2474 // send event to user code
2475 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
2476 m_owner->ProcessEvent (event);
2477 }
2478
2479 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
2480 Expand (itemId);
2481 if (!IsExpanded (itemId)) return;
2482 #if !wxCHECK_VERSION(2, 5, 0)
2483 long cookie;
2484 #else
2485 wxTreeItemIdValue cookie;
2486 #endif
2487 wxTreeItemId child = GetFirstChild (itemId, cookie);
2488 while (child.IsOk()) {
2489 ExpandAll (child);
2490 child = GetNextChild (itemId, cookie);
2491 }
2492 }
2493
2494 void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
2495 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2496 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
2497
2498 if (!item->HasPlus() || !item->IsExpanded()) return;
2499
2500 // send event to user code
2501 wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, m_owner->GetId() );
2502 #if !wxCHECK_VERSION(2, 5, 0)
2503 event.SetItem ((long)item);
2504 #else
2505 event.SetItem (item);
2506 #endif
2507 event.SetEventObject (m_owner);
2508 if (m_owner->ProcessEvent (event) && !event.IsAllowed()) return; // collapse canceled
2509
2510 item->Collapse();
2511 m_dirty = true;
2512
2513 // send event to user code
2514 event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
2515 ProcessEvent (event);
2516 }
2517
2518 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
2519 Collapse (item);
2520 DeleteChildren (item);
2521 }
2522
2523 void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
2524 if (IsExpanded (itemId)) {
2525 Collapse (itemId);
2526 }else{
2527 Expand (itemId);
2528 }
2529 }
2530
2531 void wxTreeListMainWindow::Unselect() {
2532 if (m_selectItem) {
2533 m_selectItem->SetHilight (false);
2534 RefreshLine (m_selectItem);
2535 m_selectItem = (wxTreeListItem*)NULL;
2536 }
2537 }
2538
2539 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
2540 if (item->IsSelected()) {
2541 item->SetHilight (false);
2542 RefreshLine (item);
2543 if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
2544 }
2545 if (item->HasChildren()) {
2546 wxArrayTreeListItems& children = item->GetChildren();
2547 size_t count = children.Count();
2548 for (size_t n = 0; n < count; ++n) {
2549 UnselectAllChildren (children[n]);
2550 }
2551 }
2552 }
2553
2554 void wxTreeListMainWindow::UnselectAll() {
2555 UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
2556 }
2557
2558 // Recursive function !
2559 // To stop we must have crt_item<last_item
2560 // Algorithm :
2561 // Tag all next children, when no more children,
2562 // Move to parent (not to tag)
2563 // Keep going... if we found last_item, we stop.
2564 bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem *crt_item,
2565 wxTreeListItem *last_item) {
2566 wxTreeListItem *parent = crt_item->GetItemParent();
2567
2568 if (!parent) {// This is root item
2569 return TagAllChildrenUntilLast (crt_item, last_item);
2570 }
2571
2572 wxArrayTreeListItems& children = parent->GetChildren();
2573 int index = children.Index(crt_item);
2574 wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2575
2576 if ((parent->HasChildren() && parent->IsExpanded()) ||
2577 ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
2578 size_t count = children.Count();
2579 for (size_t n = (index+1); n < count; ++n) {
2580 if (TagAllChildrenUntilLast (children[n], last_item)) return true;
2581 }
2582 }
2583
2584 return TagNextChildren (parent, last_item);
2585 }
2586
2587 bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem *crt_item,
2588 wxTreeListItem *last_item) {
2589 crt_item->SetHilight (true);
2590 RefreshLine(crt_item);
2591
2592 if (crt_item==last_item) return true;
2593
2594 if (crt_item->HasChildren() && crt_item->IsExpanded()) {
2595 wxArrayTreeListItems& children = crt_item->GetChildren();
2596 size_t count = children.Count();
2597 for (size_t n = 0; n < count; ++n) {
2598 if (TagAllChildrenUntilLast (children[n], last_item)) return true;
2599 }
2600 }
2601
2602 return false;
2603 }
2604
2605 void wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
2606 const wxTreeItemId& lastId,
2607 bool unselect_others) {
2608 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item") );
2609
2610 bool is_single = !HasFlag(wxTR_MULTIPLE);
2611 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2612
2613 // single selection requires unselect others
2614 if (is_single) unselect_others = true;
2615
2616 // send event to the user code
2617 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId() );
2618 #if !wxCHECK_VERSION(2, 5, 0)
2619 event.SetItem ((long)item);
2620 event.SetOldItem ((long)m_curItem);
2621 #else
2622 event.SetItem (item);
2623 event.SetOldItem (m_curItem);
2624 #endif
2625 event.SetEventObject (m_owner);
2626 if (m_owner->GetEventHandler()->ProcessEvent (event) && !event.IsAllowed()) return;
2627
2628 // unselect all if unselect other items
2629 bool unselected = false; // see that UnselectAll is done only once
2630 if (unselect_others) {
2631 if (is_single) {
2632 Unselect(); // to speed up thing
2633 }else{
2634 UnselectAll();
2635 unselected = true;
2636 }
2637 }
2638
2639 // select item or item range
2640 if (lastId.IsOk() && (itemId != lastId)) {
2641
2642 if (!unselected) UnselectAll();
2643 wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
2644
2645 // ensure that the position of the item it calculated in any case
2646 if (m_dirty) CalculatePositions();
2647
2648 // select item range according Y-position
2649 if (last->GetY() < item->GetY()) {
2650 if (!TagAllChildrenUntilLast (last, item)) {
2651 TagNextChildren (last, item);
2652 }
2653 }else{
2654 if (!TagAllChildrenUntilLast (item, last)) {
2655 TagNextChildren (item, last);
2656 }
2657 }
2658
2659 }else{
2660
2661 // select item according its old selection
2662 item->SetHilight (!item->IsSelected());
2663 RefreshLine (item);
2664 if (unselect_others) {
2665 m_selectItem = (item->IsSelected())? item: (wxTreeListItem*)NULL;
2666 }
2667
2668 }
2669
2670 // send event to user code
2671 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
2672 m_owner->GetEventHandler()->ProcessEvent (event);
2673 }
2674
2675 void wxTreeListMainWindow::SelectAll() {
2676 wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
2677
2678 // send event to user code
2679 wxTreeEvent event (wxEVT_COMMAND_TREE_SEL_CHANGING, m_owner->GetId());
2680 event.SetItem (GetRootItem());
2681 #if !wxCHECK_VERSION(2, 5, 0)
2682 event.SetOldItem ((long)m_curItem);
2683 #else
2684 event.SetOldItem (m_curItem);
2685 #endif
2686 event.SetEventObject (m_owner);
2687 if (m_owner->GetEventHandler()->ProcessEvent (event) && !event.IsAllowed()) return;
2688
2689 #if !wxCHECK_VERSION(2, 5, 0)
2690 long cookie = 0;
2691 #else
2692 wxTreeItemIdValue cookie = 0;
2693 #endif
2694 wxTreeItemId root = GetRootItem();
2695 wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
2696 wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
2697 if (!TagAllChildrenUntilLast (first, last)) {
2698 TagNextChildren (first, last);
2699 }
2700
2701 // send event to user code
2702 event.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED);
2703 m_owner->GetEventHandler()->ProcessEvent (event);
2704 }
2705
2706 void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
2707 wxArrayTreeItemIds &array) const {
2708 if (item->IsSelected()) array.Add (wxTreeItemId(item));
2709
2710 if (item->HasChildren()) {
2711 wxArrayTreeListItems& children = item->GetChildren();
2712 size_t count = children.GetCount();
2713 for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
2714 }
2715 }
2716
2717 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
2718 array.Empty();
2719 wxTreeItemId idRoot = GetRootItem();
2720 if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
2721 return array.Count();
2722 }
2723
2724 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
2725 if (!item.IsOk()) return; // do nothing if no item
2726
2727 // first expand all parent branches
2728 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2729 wxTreeListItem *parent = gitem->GetItemParent();
2730 while (parent) {
2731 Expand (parent);
2732 parent = parent->GetItemParent();
2733 }
2734
2735 ScrollTo (item);
2736 RefreshLine (gitem);
2737 }
2738
2739 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
2740 if (!item.IsOk()) return; // do nothing if no item
2741
2742 // ensure that the position of the item it calculated in any case
2743 if (m_dirty) CalculatePositions();
2744
2745 wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2746
2747 // now scroll to the item
2748 int item_y = gitem->GetY();
2749
2750 int xUnit, yUnit;
2751 GetScrollPixelsPerUnit (&xUnit, &yUnit);
2752 int start_x = 0;
2753 int start_y = 0;
2754 GetViewStart (&start_x, &start_y);
2755 start_y *= yUnit;
2756
2757 int client_h = 0;
2758 int client_w = 0;
2759 GetClientSize (&client_w, &client_h);
2760
2761 int x = 0;
2762 int y = 0;
2763 m_rootItem->GetSize (x, y, this);
2764 x = m_owner->GetHeaderWindow()->GetWidth();
2765 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2766 int x_pos = GetScrollPos( wxHORIZONTAL );
2767
2768 if (item_y < start_y+3) {
2769 // going down, item should appear at top
2770 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
2771 }else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
2772 // going up, item should appear at bottom
2773 item_y += yUnit + 2;
2774 SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
2775 }
2776 }
2777
2778 // FIXME: tree sorting functions are not reentrant and not MT-safe!
2779 static wxTreeListMainWindow *s_treeBeingSorted = NULL;
2780
2781 static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1,
2782 wxTreeListItem **item2)
2783 {
2784 wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
2785
2786 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
2787 }
2788
2789 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1,
2790 const wxTreeItemId& item2)
2791 {
2792 return m_owner->OnCompareItems (item1, item2);
2793 }
2794
2795 void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId) {
2796 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
2797
2798 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2799
2800 wxCHECK_RET (!s_treeBeingSorted,
2801 _T("wxTreeListMainWindow::SortChildren is not reentrant") );
2802
2803 wxArrayTreeListItems& children = item->GetChildren();
2804 if ( children.Count() > 1 ) {
2805 m_dirty = true;
2806 s_treeBeingSorted = this;
2807 children.Sort(tree_ctrl_compare_func);
2808 s_treeBeingSorted = NULL;
2809 }
2810 }
2811
2812 wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, const wxString& str, int mode) {
2813 wxString itemText;
2814 // determine start item
2815 wxTreeItemId next = item;
2816 if (next.IsOk()) {
2817 if (mode & wxTL_MODE_NAV_LEVEL) {
2818 next = GetNextSibling (next);
2819 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2820 next = GetNextVisible (next, false);
2821 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2822 next = GetNextExpanded (next);
2823 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2824 next = GetNext (next, true);
2825 }
2826 }
2827
2828 #if !wxCHECK_VERSION(2, 5, 0)
2829 long cookie = 0;
2830 #else
2831 wxTreeItemIdValue cookie = 0;
2832 #endif
2833 if (!next.IsOk()) {
2834 next = (wxTreeListItem*)GetRootItem().m_pItem;
2835 if (HasFlag(wxTR_HIDE_ROOT)) {
2836 next = (wxTreeListItem*)GetFirstChild (GetRootItem().m_pItem, cookie).m_pItem;
2837 }
2838 }
2839 if (!next.IsOk()) return (wxTreeItemId*)NULL;
2840
2841 // start checking the next items
2842 while (next.IsOk() && (next != item)) {
2843 if (mode & wxTL_MODE_FIND_PARTIAL) {
2844 itemText = GetItemText (next).Mid (0, str.Length());
2845 }else{
2846 itemText = GetItemText (next);
2847 }
2848 if (mode & wxTL_MODE_FIND_NOCASE) {
2849 if (itemText.CmpNoCase (str) == 0) return next;
2850 }else{
2851 if (itemText.Cmp (str) == 0) return next;
2852 }
2853 if (mode & wxTL_MODE_NAV_LEVEL) {
2854 next = GetNextSibling (next);
2855 }else if (mode & wxTL_MODE_NAV_VISIBLE) { //
2856 next = GetNextVisible (next, false);
2857 }else if (mode & wxTL_MODE_NAV_EXPANDED) {
2858 next = GetNextExpanded (next);
2859 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2860 next = GetNext (next, true);
2861 }
2862 if (!next.IsOk() && item.IsOk()) {
2863 next = (wxTreeListItem*)GetRootItem().m_pItem;
2864 if (HasFlag(wxTR_HIDE_ROOT)) {
2865 next = (wxTreeListItem*)GetNextChild (GetRootItem().m_pItem, cookie).m_pItem;
2866 }
2867 }
2868 }
2869 return (wxTreeItemId*)NULL;
2870 }
2871
2872 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
2873 wxTreeListItem *prevItem = m_dragItem;
2874 m_dragItem = (wxTreeListItem*) item.m_pItem;
2875 if (prevItem) RefreshLine (prevItem);
2876 if (m_dragItem) RefreshLine (m_dragItem);
2877 }
2878
2879 void wxTreeListMainWindow::CalculateLineHeight() {
2880 wxClientDC dc (this);
2881 dc.SetFont (m_normalFont);
2882 m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
2883
2884 if (m_imageListNormal) {
2885 // Calculate a m_lineHeight value from the normal Image sizes.
2886 // May be toggle off. Then wxTreeListMainWindow will spread when
2887 // necessary (which might look ugly).
2888 int n = m_imageListNormal->GetImageCount();
2889 for (int i = 0; i < n ; i++) {
2890 int width = 0, height = 0;
2891 m_imageListNormal->GetSize(i, width, height);
2892 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
2893 }
2894 }
2895
2896 if (m_imageListButtons) {
2897 // Calculate a m_lineHeight value from the Button image sizes.
2898 // May be toggle off. Then wxTreeListMainWindow will spread when
2899 // necessary (which might look ugly).
2900 int n = m_imageListButtons->GetImageCount();
2901 for (int i = 0; i < n ; i++) {
2902 int width = 0, height = 0;
2903 m_imageListButtons->GetSize(i, width, height);
2904 if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
2905 }
2906 }
2907
2908 if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
2909 m_lineHeight += 2; // minimal 2 pixel space
2910 }else{
2911 m_lineHeight += m_lineHeight / 10; // otherwise 10% space
2912 }
2913 }
2914
2915 void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
2916 if (m_ownsImageListNormal) delete m_imageListNormal;
2917 m_imageListNormal = imageList;
2918 m_ownsImageListNormal = false;
2919 m_dirty = true;
2920 CalculateLineHeight();
2921 }
2922
2923 void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
2924 if (m_ownsImageListState) delete m_imageListState;
2925 m_imageListState = imageList;
2926 m_ownsImageListState = false;
2927 }
2928
2929 void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
2930 if (m_ownsImageListButtons) delete m_imageListButtons;
2931 m_imageListButtons = imageList;
2932 m_ownsImageListButtons = false;
2933 m_dirty = true;
2934 CalculateLineHeight();
2935 }
2936
2937 void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
2938 SetImageList(imageList);
2939 m_ownsImageListNormal = true;
2940 }
2941
2942 void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
2943 SetStateImageList(imageList);
2944 m_ownsImageListState = true;
2945 }
2946
2947 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
2948 SetButtonsImageList(imageList);
2949 m_ownsImageListButtons = true;
2950 }
2951
2952 // ----------------------------------------------------------------------------
2953 // helpers
2954 // ----------------------------------------------------------------------------
2955
2956 void wxTreeListMainWindow::AdjustMyScrollbars() {
2957 if (m_rootItem) {
2958 int xUnit, yUnit;
2959 GetScrollPixelsPerUnit (&xUnit, &yUnit);
2960 if (xUnit == 0) xUnit = GetCharWidth();
2961 if (yUnit == 0) yUnit = m_lineHeight;
2962 int x = 0, y = 0;
2963 m_rootItem->GetSize (x, y, this);
2964 y += yUnit + 2; // one more scrollbar unit + 2 pixels
2965 int x_pos = GetScrollPos (wxHORIZONTAL);
2966 int y_pos = GetScrollPos (wxVERTICAL);
2967 x = m_owner->GetHeaderWindow()->GetWidth() + 2;
2968 if (x < GetClientSize().GetWidth()) x_pos = 0;
2969 SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
2970 }else{
2971 SetScrollbars (0, 0, 0, 0);
2972 }
2973 }
2974
2975 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
2976 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
2977 return item->GetHeight();
2978 }else{
2979 return m_lineHeight;
2980 }
2981 }
2982
2983 void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
2984
2985 wxTreeItemAttr *attr = item->GetAttributes();
2986
2987 dc.SetFont (GetItemFont (item));
2988
2989 wxColour colText;
2990 if (attr && attr->HasTextColour()) {
2991 colText = attr->GetTextColour();
2992 }else{
2993 colText = GetForegroundColour();
2994 }
2995 #if !wxCHECK_VERSION(2, 5, 0)
2996 wxColour colTextHilight = wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2997 #else
2998 wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
2999 #endif
3000
3001 int total_w = m_owner->GetHeaderWindow()->GetWidth();
3002 int total_h = GetLineHeight(item);
3003 int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
3004 int off_w = HasFlag(wxTR_COLUMN_LINES) ? 1 : 0;
3005 wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
3006
3007 int text_w = 0, text_h = 0;
3008 dc.GetTextExtent( item->GetText(GetMainColumn()), &text_w, &text_h );
3009
3010 // determine background and show it
3011 wxColour colBg;
3012 if (attr && attr->HasBackgroundColour()) {
3013 colBg = attr->GetBackgroundColour();
3014 }else{
3015 colBg = m_backgroundColour;
3016 }
3017 dc.SetBrush (wxBrush (colBg, wxSOLID));
3018 dc.SetPen (*wxTRANSPARENT_PEN);
3019 if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3020 if (item == m_dragItem) {
3021 dc.SetBrush (*m_hilightBrush);
3022 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3023 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3024 #endif // !__WXMAC__
3025 dc.SetTextForeground (colTextHilight);
3026 }else if (item->IsSelected()) {
3027 if (!m_isDragging && m_hasFocus) {
3028 dc.SetBrush (*m_hilightBrush);
3029 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3030 dc.SetPen (*wxBLACK_PEN);
3031 #endif // !__WXMAC__
3032 }else{
3033 dc.SetBrush (*m_hilightUnfocusedBrush);
3034 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3035 dc.SetPen (*wxTRANSPARENT_PEN);
3036 #endif // !__WXMAC__
3037 }
3038 dc.SetTextForeground (colTextHilight);
3039 }else if (item == m_curItem) {
3040 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3041 }else{
3042 dc.SetTextForeground (colText);
3043 }
3044 dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
3045 }else{
3046 dc.SetTextForeground (colText);
3047 }
3048
3049 int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
3050 int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
3051 int x_colstart = 0;
3052 for (int i = 0; i < GetColumnCount(); ++i ) {
3053 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3054
3055 int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
3056 wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
3057
3058 int x = 0;
3059 int image = NO_IMAGE;
3060 int image_w = 0;
3061 if(i == GetMainColumn()) {
3062 x = item->GetX() + MARGIN;
3063 if (HasButtons()) {
3064 x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
3065 }else{
3066 x -= m_indent/2;
3067 }
3068 if (m_imageListNormal) image = item->GetCurrentImage();
3069 }else{
3070 x = x_colstart + MARGIN;
3071 image = item->GetImage(i);
3072 }
3073 if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
3074
3075 // honor text alignment
3076 wxString text = item->GetText(i);
3077 int w = 0;
3078 switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
3079 case wxALIGN_LEFT:
3080 // nothing to do, already left aligned
3081 break;
3082 case wxALIGN_RIGHT:
3083 dc.GetTextExtent (text, &text_w, NULL);
3084 w = col_w - (image_w + text_w + off_w + MARGIN);
3085 x += (w > 0)? w: 0;
3086 break;
3087 case wxALIGN_CENTER:
3088 dc.GetTextExtent(text, &text_w, NULL);
3089 w = (col_w - (image_w + text_w + off_w + MARGIN))/2;
3090 x += (w > 0)? w: 0;
3091 break;
3092 }
3093 int text_x = x + image_w;
3094 if (i == GetMainColumn()) item->SetTextX (text_x);
3095
3096 if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3097 if (i == GetMainColumn()) {
3098 if (item == m_dragItem) {
3099 dc.SetBrush (*m_hilightBrush);
3100 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3101 dc.SetPen ((item == m_dragItem)? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3102 #endif // !__WXMAC__
3103 dc.SetTextForeground (colTextHilight);
3104 }else if (item->IsSelected()) {
3105 if (!m_isDragging && m_hasFocus) {
3106 dc.SetBrush (*m_hilightBrush);
3107 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3108 dc.SetPen (*wxBLACK_PEN);
3109 #endif // !__WXMAC__
3110 }else{
3111 dc.SetBrush (*m_hilightUnfocusedBrush);
3112 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3113 dc.SetPen (*wxTRANSPARENT_PEN);
3114 #endif // !__WXMAC__
3115 }
3116 dc.SetTextForeground (colTextHilight);
3117 }else if (item == m_curItem) {
3118 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3119 }else{
3120 dc.SetTextForeground (colText);
3121 }
3122 dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3123 }else{
3124 dc.SetTextForeground (colText);
3125 }
3126 }
3127
3128 if (HasFlag(wxTR_COLUMN_LINES)) { // vertical lines between columns
3129 #if !wxCHECK_VERSION(2, 5, 0)
3130 wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3131 #else
3132 wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3133 #endif
3134 dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3135 dc.DrawLine (x_colstart+col_w-1, item->GetY(), x_colstart+col_w-1, item->GetY()+total_h);
3136 }
3137
3138 dc.SetBackgroundMode (wxTRANSPARENT);
3139
3140 if (image != NO_IMAGE) {
3141 int y = item->GetY() + img_extraH;
3142 m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3143 }
3144 int text_y = item->GetY() + text_extraH;
3145 dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
3146
3147 x_colstart += col_w;
3148 }
3149
3150 // restore normal font
3151 dc.SetFont( m_normalFont );
3152 }
3153
3154 // Now y stands for the top of the item, whereas it used to stand for middle !
3155 void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
3156 int level, int &y, int x_maincol) {
3157
3158 // Handle hide root (only level 0)
3159 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
3160 wxArrayTreeListItems& children = item->GetChildren();
3161 for (size_t n = 0; n < children.Count(); n++) {
3162 PaintLevel (children[n], dc, 1, y, x_maincol);
3163 }
3164 // end after expanding root
3165 return;
3166 }
3167
3168 // calculate position of vertical lines
3169 int x = x_maincol + MARGIN; // start of column
3170 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
3171 if (HasButtons()) {
3172 x += (m_btnWidth-m_btnWidth2); // half button space
3173 }else{
3174 x += (m_indent-m_indent/2);
3175 }
3176 if (HasFlag(wxTR_HIDE_ROOT)) {
3177 x += m_indent * (level-1); // indent but not level 1
3178 }else{
3179 x += m_indent * level; // indent according to level
3180 }
3181
3182 // set position of vertical line
3183 item->SetX (x);
3184 item->SetY (y);
3185
3186 int h = GetLineHeight (item);
3187 int y_top = y;
3188 int y_mid = y_top + (h/2);
3189 y += h;
3190
3191 int exposed_x = dc.LogicalToDeviceX(0);
3192 int exposed_y = dc.LogicalToDeviceY(y_top);
3193
3194 if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
3195
3196 if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
3197 //dc.DestroyClippingRegion();
3198 int total_width = m_owner->GetHeaderWindow()->GetWidth();
3199 // if the background colour is white, choose a
3200 // contrasting color for the lines
3201 #if !wxCHECK_VERSION(2, 5, 0)
3202 wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3203 #else
3204 wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
3205 #endif
3206 dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3207 dc.DrawLine (0, y_top, total_width, y_top);
3208 dc.DrawLine (0, y_top+h, total_width, y_top+h);
3209 }
3210
3211 // draw item
3212 PaintItem (item, dc);
3213
3214 // restore DC objects
3215 dc.SetBrush(*wxWHITE_BRUSH);
3216 dc.SetPen(m_dottedPen);
3217
3218 // clip to the column width
3219 int clip_width = m_owner->GetHeaderWindow()->
3220 GetColumn(m_main_column).GetWidth();
3221 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3222
3223 if (!HasFlag(wxTR_NO_LINES)) { // connection lines
3224
3225 // draw the horizontal line here
3226 dc.SetPen(m_dottedPen);
3227 int x2 = x - m_indent;
3228 if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
3229 int x3 = x + (m_btnWidth-m_btnWidth2);
3230 if (HasButtons()) {
3231 if (item->HasPlus()) {
3232 dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
3233 dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
3234 }else{
3235 dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
3236 }
3237 }else{
3238 dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
3239 }
3240 }
3241
3242 if (item->HasPlus() && HasButtons()) { // should the item show a button?
3243
3244 if (m_imageListButtons) {
3245
3246 // draw the image button here
3247 int image = wxTreeItemIcon_Normal;
3248 if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
3249 if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
3250 int xx = x - m_btnWidth2 + MARGIN;
3251 int yy = y_mid - m_btnHeight2;
3252 dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
3253 m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
3254 dc.DestroyClippingRegion();
3255
3256 }else if (HasFlag (wxTR_TWIST_BUTTONS)) {
3257
3258 // draw the twisty button here
3259 dc.SetPen(*wxBLACK_PEN);
3260 dc.SetBrush(*m_hilightBrush);
3261 wxPoint button[3];
3262 if (item->IsExpanded()) {
3263 button[0].x = x - (m_btnWidth2+1);
3264 button[0].y = y_mid - (m_btnHeight/3);
3265 button[1].x = x + (m_btnWidth2+1);
3266 button[1].y = button[0].y;
3267 button[2].x = x;
3268 button[2].y = button[0].y + (m_btnHeight2+1);
3269 }else{
3270 button[0].x = x - (m_btnWidth/3);
3271 button[0].y = y_mid - (m_btnHeight2+1);
3272 button[1].x = button[0].x;
3273 button[1].y = y_mid + (m_btnHeight2+1);
3274 button[2].x = button[0].x + (m_btnWidth2+1);
3275 button[2].y = y_mid;
3276 }
3277 dc.DrawPolygon(3, button);
3278
3279 }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3280
3281 // draw the plus sign here
3282 #if !wxCHECK_VERSION(2, 7, 0)
3283 dc.SetPen(*wxGREY_PEN);
3284 dc.SetBrush(*wxWHITE_BRUSH);
3285 dc.DrawRectangle (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3286 dc.SetPen(*wxBLACK_PEN);
3287 dc.DrawLine (x-(m_btnWidth2-2), y_mid, x+(m_btnWidth2-1), y_mid);
3288 if (!item->IsExpanded()) { // change "-" to "+"
3289 dc.DrawLine (x, y_mid-(m_btnHeight2-2), x, y_mid+(m_btnHeight2-1));
3290 }
3291 #else
3292 wxRect rect (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3293 int flag = item->IsExpanded()? wxCONTROL_EXPANDED: 0;
3294 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc, rect, flag);
3295 #endif
3296
3297 }
3298
3299 }
3300
3301 }
3302
3303 // restore DC objects
3304 dc.SetBrush(*wxWHITE_BRUSH);
3305 dc.SetPen(m_dottedPen);
3306 dc.SetTextForeground(*wxBLACK);
3307
3308 if (item->IsExpanded())
3309 {
3310 wxArrayTreeListItems& children = item->GetChildren();
3311
3312 // clip to the column width
3313 int clip_width = m_owner->GetHeaderWindow()->
3314 GetColumn(m_main_column).GetWidth();
3315
3316 // process lower levels
3317 int oldY;
3318 if (m_imgWidth > 0) {
3319 oldY = y_mid + m_imgHeight2;
3320 }else{
3321 oldY = y_mid + h/2;
3322 }
3323 int y2;
3324 for (size_t n = 0; n < children.Count(); ++n) {
3325
3326 y2 = y + h/2;
3327 PaintLevel (children[n], dc, level+1, y, x_maincol);
3328
3329 // draw vertical line
3330 wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3331 if (!HasFlag (wxTR_NO_LINES)) {
3332 x = item->GetX();
3333 dc.DrawLine (x, oldY, x, y2);
3334 oldY = y2;
3335 }
3336 }
3337 }
3338 }
3339
3340
3341 // ----------------------------------------------------------------------------
3342 // wxWindows callbacks
3343 // ----------------------------------------------------------------------------
3344
3345 void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
3346
3347 wxPaintDC dc (this);
3348 PrepareDC (dc);
3349
3350 if (!m_rootItem || (GetColumnCount() <= 0)) return;
3351
3352 // calculate button size
3353 if (m_imageListButtons) {
3354 m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
3355 }else if (HasButtons()) {
3356 m_btnWidth = BTNWIDTH;
3357 m_btnHeight = BTNHEIGHT;
3358 }
3359 m_btnWidth2 = m_btnWidth/2;
3360 m_btnHeight2 = m_btnHeight/2;
3361
3362 // calculate image size
3363 if (m_imageListNormal) {
3364 m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
3365 }
3366 m_imgWidth2 = m_imgWidth/2;
3367 m_imgHeight2 = m_imgHeight/2;
3368
3369 // calculate indent size
3370 if (m_imageListButtons) {
3371 m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
3372 }else if (HasButtons()) {
3373 m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
3374 }
3375
3376 // set default values
3377 dc.SetFont( m_normalFont );
3378 dc.SetPen( m_dottedPen );
3379
3380 // calculate column start and paint
3381 int x_maincol = 0;
3382 int i = 0;
3383 for (i = 0; i < (int)GetMainColumn(); ++i) {
3384 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3385 x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
3386 }
3387 int y = 0;
3388 PaintLevel (m_rootItem, dc, 0, y, x_maincol);
3389 }
3390
3391 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
3392
3393 m_hasFocus = true;
3394 RefreshSelected();
3395 if (m_curItem) RefreshLine (m_curItem);
3396 event.Skip();
3397 }
3398
3399 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
3400 {
3401 m_hasFocus = false;
3402 RefreshSelected();
3403 if (m_curItem) RefreshLine (m_curItem);
3404 event.Skip();
3405 }
3406
3407 void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
3408 // send event to user code
3409 wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, m_owner->GetId());
3410 nevent.SetKeyEvent (event);
3411 nevent.SetEventObject (m_owner);
3412 if (m_owner->GetEventHandler()->ProcessEvent (nevent)) return; // handled in user code
3413
3414 // determine first current if none
3415 bool curItemSet = false;
3416 if (!m_curItem) {
3417 m_curItem = (wxTreeListItem*)GetRootItem().m_pItem;
3418 if (HasFlag(wxTR_HIDE_ROOT)) {
3419 #if !wxCHECK_VERSION(2, 5, 0)
3420 long cookie = 0;
3421 #else
3422 wxTreeItemIdValue cookie = 0;
3423 #endif
3424 m_curItem = (wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem;
3425 }
3426 curItemSet = true;
3427 }
3428 if (!m_curItem) return; // do nothing if empty tree
3429
3430 // remember item at shift down
3431 if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
3432 if (!m_shiftItem) m_shiftItem = m_curItem;
3433 }else{
3434 m_shiftItem = (wxTreeListItem*)NULL;
3435 }
3436
3437 // process all cases
3438 wxTreeItemId newItem = (wxTreeItemId*)NULL;
3439 switch (event.GetKeyCode()) {
3440
3441 // '+': Expand subtree
3442 case '+':
3443 case WXK_ADD: {
3444 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
3445 }break;
3446
3447 // '-': collapse subtree
3448 case '-':
3449 case WXK_SUBTRACT: {
3450 if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
3451 }break;
3452
3453 // '*': expand/collapse all subtrees // TODO: Mak it more useful
3454 case '*':
3455 case WXK_MULTIPLY: {
3456 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3457 ExpandAll (m_curItem);
3458 }else if (m_curItem->HasPlus()) {
3459 Collapse (m_curItem); // TODO: CollapseAll
3460 }
3461 }break;
3462
3463 // ' ': toggle current item
3464 case ' ': {
3465 SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
3466 }break;
3467
3468 // <RETURN>: activate current item
3469 case WXK_RETURN: {
3470 wxTreeEvent aevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
3471 #if !wxCHECK_VERSION(2, 5, 0)
3472 aevent.SetItem ((long)m_curItem);
3473 #else
3474 aevent.SetItem (m_curItem);
3475 #endif
3476 aevent.SetEventObject (m_owner);
3477 m_owner->GetEventHandler()->ProcessEvent (aevent);
3478 }break;
3479
3480 // <BKSP>: go to the parent without collapsing
3481 case WXK_BACK: {
3482 newItem = GetItemParent (m_curItem);
3483 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3484 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
3485 }
3486 }break;
3487
3488 // <UP>: go to the previous sibling or to the last of its children, to the parent
3489 case WXK_UP: {
3490 newItem = GetPrevSibling (m_curItem);
3491 if (newItem) {
3492 #if !wxCHECK_VERSION(2, 5, 0)
3493 long cookie = 0;
3494 #else
3495 wxTreeItemIdValue cookie = 0;
3496 #endif
3497 while (IsExpanded (newItem) && HasChildren (newItem)) {
3498 newItem = GetLastChild (newItem, cookie);
3499 }
3500 }else {
3501 newItem = GetItemParent (m_curItem);
3502 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3503 newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
3504 }
3505 }
3506 }break;
3507
3508 // <LEFT>: if expanded collapse subtree, else go to the parent
3509 case WXK_LEFT: {
3510 if (IsExpanded (m_curItem)) {
3511 Collapse (m_curItem);
3512 }else{
3513 newItem = GetItemParent (m_curItem);
3514 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3515 newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
3516 }
3517 }
3518 }break;
3519
3520 // <RIGHT>: if possible expand subtree, else go go to the first child
3521 case WXK_RIGHT: {
3522 if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3523 Expand (m_curItem);
3524 }else{
3525 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3526 #if !wxCHECK_VERSION(2, 5, 0)
3527 long cookie = 0;
3528 #else
3529 wxTreeItemIdValue cookie = 0;
3530 #endif
3531 newItem = GetFirstChild (m_curItem, cookie);
3532 }
3533 }
3534 }break;
3535
3536 // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3537 case WXK_DOWN: {
3538 if (curItemSet) {
3539 newItem = m_curItem;
3540 }else{
3541 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3542 #if !wxCHECK_VERSION(2, 5, 0)
3543 long cookie = 0;
3544 #else
3545 wxTreeItemIdValue cookie = 0;
3546 #endif
3547 newItem = GetFirstChild( m_curItem, cookie );
3548 }
3549 if (!newItem) {
3550 wxTreeItemId parent = m_curItem;
3551 do {
3552 newItem = GetNextSibling (parent);
3553 parent = GetItemParent (parent);
3554 } while (!newItem && parent);
3555 }
3556 }
3557 }break;
3558
3559 // <END>: go to last item of the root
3560 case WXK_END: {
3561 #if !wxCHECK_VERSION(2, 5, 0)
3562 long cookie = 0;
3563 #else
3564 wxTreeItemIdValue cookie = 0;
3565 #endif
3566 newItem = GetLastChild (GetRootItem(), cookie);
3567 }break;
3568
3569 // <HOME>: go to root
3570 case WXK_HOME: {
3571 newItem = GetRootItem();
3572 if (HasFlag(wxTR_HIDE_ROOT)) {
3573 #if !wxCHECK_VERSION(2, 5, 0)
3574 long cookie = 0;
3575 #else
3576 wxTreeItemIdValue cookie = 0;
3577 #endif
3578 newItem = GetFirstChild (newItem, cookie);
3579 }
3580 }break;
3581
3582 // any char: go to the next matching string
3583 default:
3584 if (event.GetKeyCode() >= (int)' ') {
3585 if (!m_findTimer->IsRunning()) m_findStr.Clear();
3586 m_findStr.Append (event.GetKeyCode());
3587 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
3588 wxTreeItemId prev = m_curItem? (wxTreeItemId*)m_curItem: (wxTreeItemId*)NULL;
3589 while (true) {
3590 newItem = FindItem (prev, m_findStr, wxTL_MODE_NAV_EXPANDED |
3591 wxTL_MODE_FIND_PARTIAL |
3592 wxTL_MODE_FIND_NOCASE);
3593 if (newItem || (m_findStr.Length() <= 1)) break;
3594 m_findStr.RemoveLast();
3595 };
3596 }
3597 event.Skip();
3598
3599 }
3600
3601 // select and show the new item
3602 if (newItem) {
3603 if (!event.ControlDown()) {
3604 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3605 HasFlag(wxTR_MULTIPLE));
3606 SelectItem (newItem, m_shiftItem, unselect_others);
3607 }
3608 EnsureVisible (newItem);
3609 wxTreeListItem *oldItem = m_curItem;
3610 m_curItem = (wxTreeListItem*)newItem.m_pItem; // make the new item the current item
3611 RefreshLine (oldItem);
3612 }
3613
3614 }
3615
3616 wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
3617
3618 int w, h;
3619 GetSize(&w, &h);
3620 flags=0;
3621 column = -1;
3622 if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
3623 if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
3624 if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
3625 if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
3626 if (flags) return wxTreeItemId();
3627
3628 if (!m_rootItem) {
3629 flags = wxTREE_HITTEST_NOWHERE;
3630 column = -1;
3631 return wxTreeItemId();
3632 }
3633
3634 wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
3635 this, flags, column, 0);
3636 if (!hit) {
3637 flags = wxTREE_HITTEST_NOWHERE;
3638 column = -1;
3639 return wxTreeItemId();
3640 }
3641 return hit;
3642 }
3643
3644 // get the bounding rectangle of the item (or of its label only)
3645 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
3646 bool WXUNUSED(textOnly)) const {
3647 wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
3648
3649 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
3650
3651 int xUnit, yUnit;
3652 GetScrollPixelsPerUnit (&xUnit, &yUnit);
3653 int startX, startY;
3654 GetViewStart(& startX, & startY);
3655
3656 rect.x = item->GetX() - startX * xUnit;
3657 rect.y = item->GetY() - startY * yUnit;
3658 rect.width = item->GetWidth();
3659 rect.height = GetLineHeight (item);
3660
3661 return true;
3662 }
3663
3664 /* **** */
3665
3666 void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
3667 if (!item.IsOk()) return;
3668 if (!((column >= 0) && (column < GetColumnCount()))) return;
3669
3670 m_editItem = (wxTreeListItem*) item.m_pItem;
3671
3672 wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, m_owner->GetId() );
3673 #if !wxCHECK_VERSION(2, 5, 0)
3674 te.SetItem ((long)m_editItem);
3675 #else
3676 te.SetItem (m_editItem);
3677 #endif
3678 te.SetInt (column);
3679 te.SetEventObject (m_owner );
3680 m_owner->GetEventHandler()->ProcessEvent (te);
3681
3682 if (!te.IsAllowed()) return;
3683
3684 // ensure that the position of the item it calculated in any case
3685 if (m_dirty) CalculatePositions();
3686
3687 wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
3688 int x = 0;
3689 int y = m_editItem->GetY() + 1; // wxTextCtrl needs 1 pixels above the text
3690 int w = 0;
3691 int h = m_editItem->GetHeight();
3692 long style = 0;
3693 if (column == GetMainColumn()) {
3694 x += m_editItem->GetTextX() - 2; // wxTextCtrl needs 2 pixels before the text
3695 w = wxMin (m_editItem->GetWidth(), m_owner->GetHeaderWindow()->GetWidth() - x);
3696 }else{
3697 for (int i = 0; i < column; ++i) x += header_win->GetColumnWidth (i); // start of column
3698 switch (header_win->GetColumnAlignment (column)) {
3699 case wxALIGN_LEFT: {style = wxTE_LEFT; break;}
3700 case wxALIGN_RIGHT: {style = wxTE_RIGHT; break;}
3701 case wxALIGN_CENTER: {style = wxTE_CENTER; break;}
3702 }
3703 w = header_win->GetColumnWidth (column); // width of column
3704 }
3705
3706 wxClientDC dc (this);
3707 PrepareDC (dc);
3708 x = dc.LogicalToDeviceX (x);
3709 y = dc.LogicalToDeviceY (y);
3710
3711 wxEditTextCtrl *text = new wxEditTextCtrl (this, -1, &m_renameAccept, &m_renameRes,
3712 this, m_editItem->GetText (column),
3713 wxPoint (x, y), wxSize (w, h), style);
3714 text->SetFocus();
3715 }
3716
3717 void wxTreeListMainWindow::OnRenameTimer() {
3718 EditLabel (m_curItem, m_curColumn);
3719 }
3720
3721 void wxTreeListMainWindow::OnRenameAccept() {
3722
3723 // TODO if the validator fails this causes a crash
3724 wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, m_owner->GetId() );
3725 #if !wxCHECK_VERSION(2, 5, 0)
3726 le.SetItem((long)m_editItem);
3727 #else
3728 le.SetItem(m_editItem);
3729 #endif
3730 le.SetEventObject( /*this*/m_owner );
3731 le.SetLabel( m_renameRes );
3732 m_owner->GetEventHandler()->ProcessEvent( le );
3733
3734 if (!le.IsAllowed()) return;
3735
3736 SetItemText (m_editItem, m_curColumn, m_renameRes);
3737 }
3738
3739 void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
3740 if (!m_rootItem) return;
3741
3742 // we process left mouse up event (enables in-place edit), right down
3743 // (pass to the user code), left dbl click (activate item) and
3744 // dragging/moving events for items drag-and-drop
3745 if (!(event.LeftDown() ||
3746 event.LeftUp() ||
3747 event.RightDown() ||
3748 event.RightUp() ||
3749 event.LeftDClick() ||
3750 event.Dragging() ||
3751 (event.GetWheelRotation() != 0 )/*? TODO ||
3752 event.Moving()?*/)) {
3753 m_owner->GetEventHandler()->ProcessEvent (event);
3754 return;
3755 }
3756
3757 // set focus if window clicked
3758 if (event.LeftDown() || event.RightDown()) SetFocus();
3759
3760 // determine event
3761 wxPoint p = wxPoint (event.GetX(), event.GetY());
3762 int flags = 0;
3763 wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
3764 this, flags, m_curColumn, 0);
3765
3766 // we only process dragging here
3767 if (event.Dragging()){
3768 if (m_isDragging) return; // nothing to do, already done
3769 if (item == NULL) return; // we need an item to dragging
3770
3771 // determine drag start
3772 if (m_dragCount == 0) {
3773 m_dragTimer->Start (DRAG_TIMER_TICKS, wxTIMER_ONE_SHOT);
3774 }
3775 m_dragCount++;
3776 if (m_dragCount < 3) return; // minimum drag 3 pixel
3777 if (m_dragTimer->IsRunning()) return;
3778
3779 // we're going to drag
3780 m_dragCount = 0;
3781 m_isDragging = true;
3782 CaptureMouse();
3783 RefreshSelected();
3784
3785 // send drag start event
3786 wxEventType command = event.LeftIsDown()
3787 ? wxEVT_COMMAND_TREE_BEGIN_DRAG
3788 : wxEVT_COMMAND_TREE_BEGIN_RDRAG;
3789 wxTreeEvent nevent (command, m_owner->GetId());
3790 nevent.SetEventObject (m_owner);
3791 #if !wxCHECK_VERSION(2, 5, 0)
3792 nevent.SetItem ((long)item); // the item the drag is ended
3793 #else
3794 nevent.SetItem (item); // the item the drag is ended
3795 #endif
3796 nevent.Veto(); // dragging must be explicit allowed!
3797 m_owner->GetEventHandler()->ProcessEvent (nevent);
3798
3799 }else if (m_isDragging) { // any other event but not event.Dragging()
3800
3801 // end dragging
3802 m_dragCount = 0;
3803 m_isDragging = false;
3804 if (HasCapture()) ReleaseMouse();
3805 RefreshSelected();
3806
3807 // send drag end event event
3808 wxTreeEvent nevent (wxEVT_COMMAND_TREE_END_DRAG, m_owner->GetId());
3809 nevent.SetEventObject (m_owner);
3810 #if !wxCHECK_VERSION(2, 5, 0)
3811 nevent.SetItem ((long)item); // the item the drag is started
3812 #else
3813 nevent.SetItem (item); // the item the drag is started
3814 #endif
3815 nevent.SetPoint (p);
3816 m_owner->GetEventHandler()->ProcessEvent (nevent);
3817
3818 }else if (m_dragCount > 0) { // just in case dragging is initiated
3819
3820 // end dragging
3821 m_dragCount = 0;
3822
3823 }
3824
3825 // we process only the messages which happen on tree items
3826 if (item == NULL) {
3827 m_owner->GetEventHandler()->ProcessEvent (event);
3828 return;
3829 }
3830
3831 // remember item at shift down
3832 if (event.ShiftDown()) {
3833 if (!m_shiftItem) m_shiftItem = m_curItem;
3834 }else{
3835 m_shiftItem = (wxTreeListItem*)NULL;
3836 }
3837
3838 if (event.RightUp()) {
3839
3840 SetFocus();
3841 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, m_owner->GetId());
3842 nevent.SetEventObject (m_owner);
3843 #if !wxCHECK_VERSION(2, 5, 0)
3844 nevent.SetItem ((long)item); // the item clicked
3845 #else
3846 nevent.SetItem (item); // the item clicked
3847 #endif
3848 nevent.SetInt (m_curColumn); // the colum clicked
3849 nevent.SetPoint (p);
3850 m_owner->GetEventHandler()->ProcessEvent (nevent);
3851
3852 }else if (event.LeftUp()) {
3853
3854 if (m_lastOnSame) {
3855 if ((item == m_curItem) && (m_curColumn != -1) &&
3856 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
3857 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))){
3858 m_renameTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
3859 }
3860 m_lastOnSame = false;
3861 }
3862
3863 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3864 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3865 HasButtons() && item->HasPlus()) {
3866
3867 // only toggle the item for a single click, double click on
3868 // the button doesn't do anything (it toggles the item twice)
3869 if (event.LeftDown()) Toggle (item);
3870
3871 // don't select the item if the button was clicked
3872 return;
3873 }
3874
3875 // determine the selection if not done by left down
3876 if (!m_left_down_selection) {
3877 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3878 HasFlag(wxTR_MULTIPLE));
3879 SelectItem (item, m_shiftItem, unselect_others);
3880 EnsureVisible (item);
3881 m_curItem = item; // make the new item the current item
3882 }else{
3883 m_left_down_selection = false;
3884 }
3885
3886 }else if (event.LeftDown() || event.RightDown() || event.LeftDClick()) {
3887
3888 if (event.LeftDown() || event.RightDown()) {
3889 SetFocus();
3890 m_lastOnSame = item == m_curItem;
3891 }
3892
3893 if (((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
3894 (flags & wxTREE_HITTEST_ONITEMICON)) &&
3895 item->HasPlus()) {
3896
3897 // only toggle the item for a single click, double click on
3898 // the button doesn't do anything (it toggles the item twice)
3899 if (event.LeftDown()) Toggle (item);
3900
3901 // don't select the item if the button was clicked
3902 return;
3903 }
3904
3905 // determine the selection if the current item is not selected
3906 if (!item->IsSelected()) {
3907 bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3908 HasFlag(wxTR_MULTIPLE));
3909 SelectItem (item, m_shiftItem, unselect_others);
3910 EnsureVisible (item);
3911 m_curItem = item; // make the new item the current item
3912 m_left_down_selection = true;
3913 }
3914
3915 // For some reason, Windows isn't recognizing a left double-click,
3916 // so we need to simulate it here. Allow 200 milliseconds for now.
3917 if (event.LeftDClick()) {
3918
3919 // double clicking should not start editing the item label
3920 m_renameTimer->Stop();
3921 m_lastOnSame = false;
3922
3923 // send activate event first
3924 wxTreeEvent nevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_owner->GetId());
3925 nevent.SetEventObject (m_owner);
3926 #if !wxCHECK_VERSION(2, 5, 0)
3927 nevent.SetItem ((long)item); // the item clicked
3928 #else
3929 nevent.SetItem (item); // the item clicked
3930 #endif
3931 nevent.SetInt (m_curColumn); // the colum clicked
3932 nevent.SetPoint (p);
3933 if (!m_owner->GetEventHandler()->ProcessEvent (nevent)) {
3934
3935 // if the user code didn't process the activate event,
3936 // handle it ourselves by toggling the item when it is
3937 // double clicked
3938 if (item->HasPlus()) Toggle(item);
3939 }
3940 }
3941
3942 }else{ // any other event skip just in case
3943
3944 event.Skip();
3945
3946 }
3947 }
3948
3949 void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
3950 /* after all changes have been done to the tree control,
3951 * we actually redraw the tree when everything is over */
3952
3953 if (!m_dirty) return;
3954
3955 m_dirty = false;
3956
3957 CalculatePositions();
3958 Refresh();
3959 AdjustMyScrollbars();
3960 }
3961
3962 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
3963 // FIXME
3964 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
3965 wxScrolledWindow::OnScroll(event);
3966 #else
3967 HandleOnScroll( event );
3968 #endif
3969
3970 if(event.GetOrientation() == wxHORIZONTAL) {
3971 m_owner->GetHeaderWindow()->Refresh();
3972 m_owner->GetHeaderWindow()->Update();
3973 }
3974 }
3975
3976 void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
3977 wxCoord text_w = 0;
3978 wxCoord text_h = 0;
3979
3980 dc.SetFont (GetItemFont (item));
3981
3982 dc.GetTextExtent (item->GetText (m_main_column), &text_w, &text_h);
3983
3984 // restore normal font
3985 dc.SetFont (m_normalFont);
3986
3987 int total_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
3988 if (total_h < 30) { // add 10% space if greater than 30 pixels
3989 total_h += 2; // minimal 2 pixel space
3990 }else{
3991 total_h += total_h / 10; // otherwise 10% space
3992 }
3993
3994 item->SetHeight (total_h);
3995 if (total_h > m_lineHeight) m_lineHeight = total_h;
3996 item->SetWidth(m_imgWidth + text_w+2);
3997 }
3998
3999 // -----------------------------------------------------------------------------
4000 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
4001 int level, int &y, int x_colstart) {
4002
4003 // calculate position of vertical lines
4004 int x = x_colstart + MARGIN; // start of column
4005 if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
4006 if (HasButtons()) {
4007 x += (m_btnWidth-m_btnWidth2); // half button space
4008 }else{
4009 x += (m_indent-m_indent/2);
4010 }
4011 if (HasFlag(wxTR_HIDE_ROOT)) {
4012 x += m_indent * (level-1); // indent but not level 1
4013 }else{
4014 x += m_indent * level; // indent according to level
4015 }
4016
4017 // a hidden root is not evaluated, but its children are always
4018 if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
4019
4020 CalculateSize( item, dc );
4021
4022 // set its position
4023 item->SetX (x);
4024 item->SetY (y);
4025 y += GetLineHeight(item);
4026
4027 // we don't need to calculate collapsed branches
4028 if ( !item->IsExpanded() ) return;
4029
4030 Recurse:
4031 wxArrayTreeListItems& children = item->GetChildren();
4032 long n, count = (long)children.Count();
4033 ++level;
4034 for (n = 0; n < count; ++n) {
4035 CalculateLevel( children[n], dc, level, y, x_colstart ); // recurse
4036 }
4037 }
4038
4039 void wxTreeListMainWindow::CalculatePositions() {
4040 if ( !m_rootItem ) return;
4041
4042 wxClientDC dc(this);
4043 PrepareDC( dc );
4044
4045 dc.SetFont( m_normalFont );
4046
4047 dc.SetPen( m_dottedPen );
4048 //if(GetImageList() == NULL)
4049 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
4050
4051 int y = 2;
4052 int x_colstart = 0;
4053 for (int i = 0; i < (int)GetMainColumn(); ++i) {
4054 if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
4055 x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
4056 }
4057 CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
4058 }
4059
4060 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
4061 if (m_dirty) return;
4062
4063 wxClientDC dc(this);
4064 PrepareDC(dc);
4065
4066 int cw = 0;
4067 int ch = 0;
4068 GetVirtualSize( &cw, &ch );
4069
4070 wxRect rect;
4071 rect.x = dc.LogicalToDeviceX( 0 );
4072 rect.width = cw;
4073 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
4074 rect.height = ch;
4075
4076 Refresh (true, &rect );
4077 AdjustMyScrollbars();
4078 }
4079
4080 void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
4081 if (m_dirty) return;
4082
4083 wxClientDC dc(this);
4084 PrepareDC( dc );
4085
4086 int cw = 0;
4087 int ch = 0;
4088 GetVirtualSize( &cw, &ch );
4089
4090 wxRect rect;
4091 rect.x = dc.LogicalToDeviceX( 0 );
4092 rect.y = dc.LogicalToDeviceY( item->GetY() );
4093 rect.width = cw;
4094 rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
4095
4096 Refresh (true, &rect);
4097 }
4098
4099 void wxTreeListMainWindow::RefreshSelected() {
4100 // TODO: this is awfully inefficient, we should keep the list of all
4101 // selected items internally, should be much faster
4102 if (m_rootItem) {
4103 RefreshSelectedUnder (m_rootItem);
4104 }
4105 }
4106
4107 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
4108 if (item->IsSelected()) {
4109 RefreshLine (item);
4110 }
4111
4112 const wxArrayTreeListItems& children = item->GetChildren();
4113 long count = children.GetCount();
4114 for (long n = 0; n < count; n++ ) {
4115 RefreshSelectedUnder (children[n]);
4116 }
4117 }
4118
4119 // ----------------------------------------------------------------------------
4120 // changing colours: we need to refresh the tree control
4121 // ----------------------------------------------------------------------------
4122
4123 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
4124 if (!wxWindow::SetBackgroundColour(colour)) return false;
4125
4126 Refresh();
4127 return true;
4128 }
4129
4130 bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
4131 if (!wxWindow::SetForegroundColour(colour)) return false;
4132
4133 Refresh();
4134 return true;
4135 }
4136
4137 void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column,
4138 const wxString& text) {
4139 wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
4140
4141 wxClientDC dc (this);
4142 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
4143 item->SetText (column, text);
4144 CalculateSize (item, dc);
4145 RefreshLine (item);
4146 }
4147
4148 wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId,
4149 int column) const {
4150 wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
4151
4152 if( IsVirtual() ) return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
4153 else return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
4154 }
4155
4156 wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item,
4157 int column) const {
4158 wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4159 return m_owner->OnGetItemText(item,column);
4160 }
4161
4162 void wxTreeListMainWindow::SetFocus() {
4163 wxWindow::SetFocus();
4164 }
4165
4166 wxFont wxTreeListMainWindow::GetItemFont (wxTreeListItem *item) {
4167 wxTreeItemAttr *attr = item->GetAttributes();
4168
4169 if (attr && attr->HasFont()) {
4170 return attr->GetFont();
4171 }else if (item->IsBold()) {
4172 return m_boldFont;
4173 }else{
4174 return m_normalFont;
4175 }
4176 }
4177
4178 int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
4179 if (!item) return 0;
4180
4181 // determine item width
4182 int w = 0, h = 0;
4183 wxFont font = GetItemFont (item);
4184 GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
4185 w += 2*MARGIN;
4186
4187 // calculate width
4188 int width = w + 2*MARGIN;
4189 if (column == GetMainColumn()) {
4190 width += MARGIN;
4191 if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
4192 if (HasButtons()) width += m_btnWidth + LINEATROOT;
4193 if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
4194
4195 // count indent level
4196 int level = 0;
4197 wxTreeListItem *parent = item->GetItemParent();
4198 wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
4199 while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
4200 level++;
4201 parent = parent->GetItemParent();
4202 }
4203 if (level) width += level * GetIndent();
4204 }
4205
4206 return width;
4207 }
4208
4209 int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
4210 int maxWidth, h;
4211 GetClientSize (&maxWidth, &h);
4212 int width = 0;
4213
4214 // get root if on item
4215 if (!parent.IsOk()) parent = GetRootItem();
4216
4217 // add root width
4218 if (!HasFlag(wxTR_HIDE_ROOT)) {
4219 int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
4220 if (width < w) width = w;
4221 if (width > maxWidth) return maxWidth;
4222 }
4223
4224 wxTreeItemIdValue cookie = 0;
4225 wxTreeItemId item = GetFirstChild (parent, cookie);
4226 while (item.IsOk()) {
4227 int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
4228 if (width < w) width = w;
4229 if (width > maxWidth) return maxWidth;
4230
4231 // check the children of this item
4232 if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
4233 int w = GetBestColumnWidth (column, item);
4234 if (width < w) width = w;
4235 if (width > maxWidth) return maxWidth;
4236 }
4237
4238 // next sibling
4239 item = GetNextChild (parent, cookie);
4240 }
4241
4242 return width;
4243 }
4244
4245
4246 //-----------------------------------------------------------------------------
4247 // wxTreeListCtrl
4248 //-----------------------------------------------------------------------------
4249
4250 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
4251
4252 BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
4253 EVT_SIZE(wxTreeListCtrl::OnSize)
4254 END_EVENT_TABLE();
4255
4256 bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
4257 const wxPoint& pos,
4258 const wxSize& size,
4259 long style, const wxValidator &validator,
4260 const wxString& name)
4261 {
4262 long main_style = style & ~(wxSIMPLE_BORDER|wxSUNKEN_BORDER|wxDOUBLE_BORDER|
4263 wxRAISED_BORDER|wxSTATIC_BORDER);
4264 long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
4265
4266 if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
4267 return false;
4268 }
4269 m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
4270 main_style, validator);
4271 m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
4272 wxPoint(0, 0), wxDefaultSize,
4273 wxTAB_TRAVERSAL);
4274 CalculateAndSetHeaderHeight();
4275 return true;
4276 }
4277
4278 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4279 {
4280 if (m_header_win) {
4281 int h;
4282 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
4283 h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win);
4284 #else
4285 // we use 'g' to get the descent, too
4286 int w, d;
4287 m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
4288 h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
4289 #endif
4290 // only update if changed
4291 if (h != m_headerHeight) {
4292 m_headerHeight = h;
4293 DoHeaderLayout();
4294 }
4295 }
4296 }
4297
4298 void wxTreeListCtrl::DoHeaderLayout()
4299 {
4300 int w, h;
4301 GetClientSize(&w, &h);
4302 if (m_header_win) {
4303 m_header_win->SetSize (0, 0, w, m_headerHeight);
4304 m_header_win->Refresh();
4305 }
4306 if (m_main_win) {
4307 m_main_win->SetSize (0, m_headerHeight + 1, w, h - m_headerHeight - 1);
4308 }
4309 }
4310
4311 void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
4312 {
4313 DoHeaderLayout();
4314 }
4315
4316 size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
4317
4318 unsigned int wxTreeListCtrl::GetIndent() const
4319 { return m_main_win->GetIndent(); }
4320
4321 void wxTreeListCtrl::SetIndent(unsigned int indent)
4322 { m_main_win->SetIndent(indent); }
4323
4324 unsigned int wxTreeListCtrl::GetLineSpacing() const
4325 { return m_main_win->GetLineSpacing(); }
4326
4327 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
4328 { m_main_win->SetLineSpacing(spacing); }
4329
4330 wxImageList* wxTreeListCtrl::GetImageList() const
4331 { return m_main_win->GetImageList(); }
4332
4333 wxImageList* wxTreeListCtrl::GetStateImageList() const
4334 { return m_main_win->GetStateImageList(); }
4335
4336 wxImageList* wxTreeListCtrl::GetButtonsImageList() const
4337 { return m_main_win->GetButtonsImageList(); }
4338
4339 void wxTreeListCtrl::SetImageList(wxImageList* imageList)
4340 { m_main_win->SetImageList(imageList); }
4341
4342 void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
4343 { m_main_win->SetStateImageList(imageList); }
4344
4345 void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
4346 { m_main_win->SetButtonsImageList(imageList); }
4347
4348 void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
4349 { m_main_win->AssignImageList(imageList); }
4350
4351 void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
4352 { m_main_win->AssignStateImageList(imageList); }
4353
4354 void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
4355 { m_main_win->AssignButtonsImageList(imageList); }
4356
4357 wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
4358 { return m_main_win->GetItemText (item, column); }
4359
4360 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column,
4361 wxTreeItemIcon which) const
4362 { return m_main_win->GetItemImage(item, column, which); }
4363
4364 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
4365 { return m_main_win->GetItemData(item); }
4366
4367 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
4368 { return m_main_win->GetItemBold(item); }
4369
4370 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
4371 { return m_main_win->GetItemTextColour(item); }
4372
4373 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item)
4374 const
4375 { return m_main_win->GetItemBackgroundColour(item); }
4376
4377 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
4378 { return m_main_win->GetItemFont(item); }
4379
4380
4381 void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column,
4382 const wxString& text)
4383 { m_main_win->SetItemText (item, column, text); }
4384
4385 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item,
4386 int column,
4387 int image,
4388 wxTreeItemIcon which)
4389 { m_main_win->SetItemImage(item, column, image, which); }
4390
4391 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,
4392 wxTreeItemData* data)
4393 { m_main_win->SetItemData(item, data); }
4394
4395 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
4396 { m_main_win->SetItemHasChildren(item, has); }
4397
4398 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
4399 { m_main_win->SetItemBold(item, bold); }
4400
4401 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,
4402 const wxColour& colour)
4403 { m_main_win->SetItemTextColour(item, colour); }
4404
4405 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,
4406 const wxColour& colour)
4407 { m_main_win->SetItemBackgroundColour(item, colour); }
4408
4409 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,
4410 const wxFont& font)
4411 { m_main_win->SetItemFont(item, font); }
4412
4413 bool wxTreeListCtrl::SetFont(const wxFont& font)
4414 {
4415 if (m_header_win) {
4416 m_header_win->SetFont(font);
4417 CalculateAndSetHeaderHeight();
4418 m_header_win->Refresh();
4419 }
4420 if (m_main_win) {
4421 return m_main_win->SetFont(font);
4422 }else{
4423 return false;
4424 }
4425 }
4426
4427 void wxTreeListCtrl::SetWindowStyle(const long style)
4428 {
4429 if(m_main_win)
4430 m_main_win->SetWindowStyle(style);
4431 m_windowStyle = style;
4432 // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4433 }
4434
4435 long wxTreeListCtrl::GetWindowStyle() const
4436 {
4437 long style = m_windowStyle;
4438 if(m_main_win)
4439 style |= m_main_win->GetWindowStyle();
4440 return style;
4441 }
4442
4443 bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow) const
4444 { return m_main_win->IsVisible(item, fullRow); }
4445
4446 bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
4447 { return m_main_win->HasChildren(item); }
4448
4449 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
4450 { return m_main_win->IsExpanded(item); }
4451
4452 bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
4453 { return m_main_win->IsSelected(item); }
4454
4455 bool wxTreeListCtrl::IsBold(const wxTreeItemId& item) const
4456 { return m_main_win->IsBold(item); }
4457
4458 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
4459 { return m_main_win->GetChildrenCount(item, rec); }
4460
4461 wxTreeItemId wxTreeListCtrl::GetRootItem() const
4462 { return m_main_win->GetRootItem(); }
4463
4464 wxTreeItemId wxTreeListCtrl::GetSelection() const
4465 { return m_main_win->GetSelection(); }
4466
4467 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
4468 { return m_main_win->GetSelections(arr); }
4469
4470 wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
4471 { return m_main_win->GetItemParent(item); }
4472
4473 #if !wxCHECK_VERSION(2, 5, 0)
4474 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4475 long& cookie) const
4476 #else
4477 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4478 wxTreeItemIdValue& cookie) const
4479 #endif
4480 { return m_main_win->GetFirstChild(item, cookie); }
4481
4482 #if !wxCHECK_VERSION(2, 5, 0)
4483 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4484 long& cookie) const
4485 #else
4486 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4487 wxTreeItemIdValue& cookie) const
4488 #endif
4489 { return m_main_win->GetNextChild(item, cookie); }
4490
4491 #if !wxCHECK_VERSION(2, 5, 0)
4492 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4493 long& cookie) const
4494 #else
4495 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4496 wxTreeItemIdValue& cookie) const
4497 #endif
4498 { return m_main_win->GetPrevChild(item, cookie); }
4499
4500 #if !wxCHECK_VERSION(2, 5, 0)
4501 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4502 long& cookie) const
4503 #else
4504 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4505 wxTreeItemIdValue& cookie) const
4506 #endif
4507 { return m_main_win->GetLastChild(item, cookie); }
4508
4509
4510 wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
4511 { return m_main_win->GetNextSibling(item); }
4512
4513 wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
4514 { return m_main_win->GetPrevSibling(item); }
4515
4516 wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
4517 { return m_main_win->GetNext(item, true); }
4518
4519 wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
4520 { return m_main_win->GetPrev(item, true); }
4521
4522 wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
4523 { return m_main_win->GetFirstExpandedItem(); }
4524
4525 wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
4526 { return m_main_win->GetNextExpanded(item); }
4527
4528 wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
4529 { return m_main_win->GetPrevExpanded(item); }
4530
4531 wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
4532 { return m_main_win->GetFirstVisibleItem(fullRow); }
4533
4534 wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow) const
4535 { return m_main_win->GetNextVisible(item, fullRow); }
4536
4537 wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow) const
4538 { return m_main_win->GetPrevVisible(item, fullRow); }
4539
4540 wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
4541 int selectedImage, wxTreeItemData* data)
4542 { return m_main_win->AddRoot (text, image, selectedImage, data); }
4543
4544 wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
4545 const wxString& text, int image,
4546 int selectedImage,
4547 wxTreeItemData* data)
4548 { return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
4549
4550 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4551 const wxTreeItemId& previous,
4552 const wxString& text, int image,
4553 int selectedImage,
4554 wxTreeItemData* data)
4555 {
4556 return m_main_win->InsertItem(parent, previous, text, image,
4557 selectedImage, data);
4558 }
4559
4560 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4561 size_t index,
4562 const wxString& text, int image,
4563 int selectedImage,
4564 wxTreeItemData* data)
4565 {
4566 return m_main_win->InsertItem(parent, index, text, image,
4567 selectedImage, data);
4568 }
4569
4570 wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
4571 const wxString& text, int image,
4572 int selectedImage,
4573 wxTreeItemData* data)
4574 { return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
4575
4576 void wxTreeListCtrl::Delete(const wxTreeItemId& item)
4577 { m_main_win->Delete(item); }
4578
4579 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
4580 { m_main_win->DeleteChildren(item); }
4581
4582 void wxTreeListCtrl::DeleteRoot()
4583 { m_main_win->DeleteRoot(); }
4584
4585 void wxTreeListCtrl::Expand(const wxTreeItemId& item)
4586 { m_main_win->Expand(item); }
4587
4588 void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
4589 { m_main_win->ExpandAll(item); }
4590
4591 void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
4592 { m_main_win->Collapse(item); }
4593
4594 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
4595 { m_main_win->CollapseAndReset(item); }
4596
4597 void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
4598 { m_main_win->Toggle(item); }
4599
4600 void wxTreeListCtrl::Unselect()
4601 { m_main_win->Unselect(); }
4602
4603 void wxTreeListCtrl::UnselectAll()
4604 { m_main_win->UnselectAll(); }
4605
4606 void wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
4607 bool unselect_others)
4608 { m_main_win->SelectItem (item, last, unselect_others); }
4609
4610 void wxTreeListCtrl::SelectAll()
4611 { m_main_win->SelectAll(); }
4612
4613 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
4614 { m_main_win->EnsureVisible(item); }
4615
4616 void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
4617 { m_main_win->ScrollTo(item); }
4618
4619 wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
4620 {
4621 wxPoint p = m_main_win->ScreenToClient (ClientToScreen (pos));
4622 return m_main_win->HitTest (p, flags, column);
4623 }
4624
4625 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
4626 bool textOnly) const
4627 { return m_main_win->GetBoundingRect(item, rect, textOnly); }
4628
4629 void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
4630 { m_main_win->EditLabel (item, column); }
4631
4632 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1,
4633 const wxTreeItemId& item2)
4634 {
4635 // do the comparison here, and not delegate to m_main_win, in order
4636 // to let the user override it
4637 //return m_main_win->OnCompareItems(item1, item2);
4638 return wxStrcmp(GetItemText(item1), GetItemText(item2));
4639 }
4640
4641 void wxTreeListCtrl::SortChildren(const wxTreeItemId& item)
4642 { m_main_win->SortChildren(item); }
4643
4644 wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, const wxString& str, int mode)
4645 { return m_main_win->FindItem (item, str, mode); }
4646
4647 void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
4648 { m_main_win->SetDragItem (item); }
4649
4650 bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
4651 {
4652 if (!m_main_win) return false;
4653 return m_main_win->SetBackgroundColour(colour);
4654 }
4655
4656 bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
4657 {
4658 if (!m_main_win) return false;
4659 return m_main_win->SetForegroundColour(colour);
4660 }
4661
4662 int wxTreeListCtrl::GetColumnCount() const
4663 { return m_main_win->GetColumnCount(); }
4664
4665 void wxTreeListCtrl::SetColumnWidth(int column, int width)
4666 {
4667 m_header_win->SetColumnWidth (column, width);
4668 m_header_win->Refresh();
4669 }
4670
4671 int wxTreeListCtrl::GetColumnWidth(int column) const
4672 { return m_header_win->GetColumnWidth(column); }
4673
4674 void wxTreeListCtrl::SetMainColumn(int column)
4675 { m_main_win->SetMainColumn(column); }
4676
4677 int wxTreeListCtrl::GetMainColumn() const
4678 { return m_main_win->GetMainColumn(); }
4679
4680 void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
4681 {
4682 m_header_win->SetColumnText (column, text);
4683 m_header_win->Refresh();
4684 }
4685
4686 wxString wxTreeListCtrl::GetColumnText(int column) const
4687 { return m_header_win->GetColumnText(column); }
4688
4689 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
4690 {
4691 m_header_win->AddColumn (colInfo);
4692 DoHeaderLayout();
4693 }
4694
4695 void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
4696 {
4697 m_header_win->InsertColumn (before, colInfo);
4698 m_header_win->Refresh();
4699 }
4700
4701 void wxTreeListCtrl::RemoveColumn(int column)
4702 {
4703 m_header_win->RemoveColumn (column);
4704 m_header_win->Refresh();
4705 }
4706
4707 void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
4708 {
4709 m_header_win->SetColumn (column, colInfo);
4710 m_header_win->Refresh();
4711 }
4712
4713 const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
4714 { return m_header_win->GetColumn(column); }
4715
4716 wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column)
4717 { return m_header_win->GetColumn(column); }
4718
4719 void wxTreeListCtrl::SetColumnImage(int column, int image)
4720 {
4721 m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
4722 m_header_win->Refresh();
4723 }
4724
4725 int wxTreeListCtrl::GetColumnImage(int column) const
4726 {
4727 return m_header_win->GetColumn(column).GetImage();
4728 }
4729
4730 void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
4731 {
4732 m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
4733 }
4734
4735 void wxTreeListCtrl::SetColumnShown(int column, bool shown)
4736 {
4737 wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
4738 m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
4739 m_header_win->Refresh();
4740 }
4741
4742 bool wxTreeListCtrl::IsColumnEditable(int column) const
4743 {
4744 return m_header_win->GetColumn(column).IsEditable();
4745 }
4746
4747 bool wxTreeListCtrl::IsColumnShown(int column) const
4748 {
4749 return m_header_win->GetColumn(column).IsShown();
4750 }
4751
4752 void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
4753 {
4754 m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
4755 m_header_win->Refresh();
4756 }
4757
4758 int wxTreeListCtrl::GetColumnAlignment(int column) const
4759 {
4760 return m_header_win->GetColumn(column).GetAlignment();
4761 }
4762
4763 void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
4764 {
4765 m_main_win->Refresh (erase, rect);
4766 m_header_win->Refresh (erase, rect);
4767 }
4768
4769 void wxTreeListCtrl::SetFocus()
4770 { m_main_win->SetFocus(); }
4771
4772 wxSize wxTreeListCtrl::DoGetBestSize() const
4773 {
4774 // something is better than nothing...
4775 return wxSize (200,200); // but it should be specified values! FIXME
4776 }
4777
4778 wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
4779 {
4780 return wxEmptyString;
4781 }