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