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