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