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