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