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