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