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