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