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