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