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