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