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