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