1 /////////////////////////////////////////////////////////////////////////////
2 // Name: treelistctrl.cpp
3 // Purpose: multi column tree control implementation
4 // Author: Robert Roebling
5 // Maintainer: Otto Wyss
8 // Copyright: (c) 2004 Robert Roebling, Julian Smart, Alberto Griggio,
9 // Vadim Zeitlin, Otto Wyss
11 /////////////////////////////////////////////////////////////////////////////
13 // ===========================================================================
15 // ===========================================================================
17 // ---------------------------------------------------------------------------
19 // ---------------------------------------------------------------------------
21 #if defined(__GNUG__) && !defined(__APPLE__)
22 #pragma implementation "treelistctrl.h"
25 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
33 #include <wx/treebase.h>
35 #include <wx/textctrl.h>
36 #include <wx/imaglist.h>
37 #include <wx/settings.h>
38 #include <wx/dcclient.h>
39 #include <wx/dcscreen.h>
40 #include <wx/scrolwin.h>
41 #if wxCHECK_VERSION(2, 7, 0)
42 #include <wx/renderer.h>
46 #include "wx/mac/private.h"
49 #include "wx/treelistctrl.h"
52 // ---------------------------------------------------------------------------
54 // ---------------------------------------------------------------------------
58 #if !wxCHECK_VERSION(2, 5, 0)
59 WX_DEFINE_ARRAY(wxTreeListItem
*, wxArrayTreeListItems
);
61 WX_DEFINE_ARRAY_PTR(wxTreeListItem
*, wxArrayTreeListItems
);
64 #include <wx/dynarray.h>
65 WX_DECLARE_OBJARRAY(wxTreeListColumnInfo
, wxArrayTreeListColumnInfo
);
66 #include <wx/arrimpl.cpp>
67 WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo
);
70 // --------------------------------------------------------------------------
72 // --------------------------------------------------------------------------
74 static const int NO_IMAGE
= -1;
76 static const int LINEHEIGHT
= 10;
77 static const int LINEATROOT
= 5;
78 static const int MARGIN
= 2;
79 static const int MININDENT
= 16;
80 static const int BTNWIDTH
= 9;
81 static const int BTNHEIGHT
= 9;
82 static const int EXTRA_WIDTH
= 4;
83 static const int EXTRA_HEIGHT
= 4;
84 static const int HEADER_OFFSET_X
= 1;
85 static const int HEADER_OFFSET_Y
= 1;
87 static const int DRAG_TIMER_TICKS
= 250; // minimum drag wait time in ms
88 static const int FIND_TIMER_TICKS
= 500; // minimum find wait time in ms
89 static const int RENAME_TIMER_TICKS
= 250; // minimum rename wait time in ms
91 const wxChar
* wxTreeListCtrlNameStr
= _T("treelistctrl");
93 static wxTreeListColumnInfo wxInvalidTreeListColumnInfo
;
96 // ---------------------------------------------------------------------------
98 // ---------------------------------------------------------------------------
99 //-----------------------------------------------------------------------------
100 // wxTreeListHeaderWindow (internal)
101 //-----------------------------------------------------------------------------
103 class wxTreeListHeaderWindow
: public wxWindow
106 wxTreeListMainWindow
*m_owner
;
107 const wxCursor
*m_currentCursor
;
108 const wxCursor
*m_resizeCursor
;
111 // column being resized
114 // divider line position in logical (unscrolled) coords
117 // minimal position beyond which the divider line can't be dragged in
121 wxArrayTreeListColumnInfo m_columns
;
123 // total width of the columns
124 int m_total_col_width
;
128 wxTreeListHeaderWindow();
130 wxTreeListHeaderWindow( wxWindow
*win
,
132 wxTreeListMainWindow
*owner
,
133 const wxPoint
&pos
= wxDefaultPosition
,
134 const wxSize
&size
= wxDefaultSize
,
136 const wxString
&name
= _T("wxtreelistctrlcolumntitles") );
138 virtual ~wxTreeListHeaderWindow();
140 void DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
);
142 void AdjustDC(wxDC
& dc
);
144 void OnPaint( wxPaintEvent
&event
);
145 void OnMouse( wxMouseEvent
&event
);
146 void OnSetFocus( wxFocusEvent
&event
);
148 // total width of all columns
149 int GetWidth() const { return m_total_col_width
; }
151 // column manipulation
152 int GetColumnCount() const { return m_columns
.GetCount(); }
154 void AddColumn (const wxTreeListColumnInfo
& colInfo
);
156 void InsertColumn (int before
, const wxTreeListColumnInfo
& colInfo
);
158 void RemoveColumn (int column
);
160 // column information manipulation
161 const wxTreeListColumnInfo
& GetColumn (int column
) const{
162 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
163 wxInvalidTreeListColumnInfo
, _T("Invalid column"));
164 return m_columns
[column
];
166 wxTreeListColumnInfo
& GetColumn (int column
) {
167 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
168 wxInvalidTreeListColumnInfo
, _T("Invalid column"));
169 return m_columns
[column
];
171 void SetColumn (int column
, const wxTreeListColumnInfo
& info
);
173 wxString
GetColumnText (int column
) const {
174 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
175 wxEmptyString
, _T("Invalid column"));
176 return m_columns
[column
].GetText();
178 void SetColumnText (int column
, const wxString
& text
) {
179 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()),
180 _T("Invalid column"));
181 m_columns
[column
].SetText (text
);
184 int GetColumnAlignment (int column
) const {
185 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
186 wxALIGN_LEFT
, _T("Invalid column"));
187 return m_columns
[column
].GetAlignment();
189 void SetColumnAlignment (int column
, int flag
) {
190 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()),
191 _T("Invalid column"));
192 m_columns
[column
].SetAlignment (flag
);
195 int GetColumnWidth (int column
) const {
196 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
197 -1, _T("Invalid column"));
198 return m_columns
[column
].GetWidth();
200 void SetColumnWidth (int column
, int width
);
202 bool IsColumnEditable (int column
) const {
203 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
204 false, _T("Invalid column"));
205 return m_columns
[column
].IsEditable();
208 bool IsColumnShown (int column
) const {
209 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
210 true, _T("Invalid column"));
211 return m_columns
[column
].IsShown();
218 // common part of all ctors
221 void SendListEvent(wxEventType type
, wxPoint pos
);
223 DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow
)
224 DECLARE_EVENT_TABLE()
228 // this is the "true" control
229 class wxTreeListMainWindow
: public wxScrolledWindow
234 wxTreeListMainWindow() { Init(); }
236 wxTreeListMainWindow (wxTreeListCtrl
*parent
, wxWindowID id
= -1,
237 const wxPoint
& pos
= wxDefaultPosition
,
238 const wxSize
& size
= wxDefaultSize
,
239 long style
= wxTR_DEFAULT_STYLE
,
240 const wxValidator
&validator
= wxDefaultValidator
,
241 const wxString
& name
= _T("wxtreelistmainwindow"))
244 Create (parent
, id
, pos
, size
, style
, validator
, name
);
247 virtual ~wxTreeListMainWindow();
249 bool Create(wxTreeListCtrl
*parent
, wxWindowID id
= -1,
250 const wxPoint
& pos
= wxDefaultPosition
,
251 const wxSize
& size
= wxDefaultSize
,
252 long style
= wxTR_DEFAULT_STYLE
,
253 const wxValidator
&validator
= wxDefaultValidator
,
254 const wxString
& name
= _T("wxtreelistctrl"));
259 // return true if this is a virtual list control
260 bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL
); }
262 // get the total number of items in the control
263 size_t GetCount() const;
265 // indent is the number of pixels the children are indented relative to
266 // the parents position. SetIndent() also redraws the control
268 unsigned int GetIndent() const { return m_indent
; }
269 void SetIndent(unsigned int indent
);
271 // see wxTreeListCtrl for the meaning
272 unsigned int GetLineSpacing() const { return m_linespacing
; }
273 void SetLineSpacing(unsigned int spacing
);
275 // image list: these functions allow to associate an image list with
276 // the control and retrieve it. Note that when assigned with
277 // SetImageList, the control does _not_ delete
278 // the associated image list when it's deleted in order to allow image
279 // lists to be shared between different controls. If you use
280 // AssignImageList, the control _does_ delete the image list.
282 // The normal image list is for the icons which correspond to the
283 // normal tree item state (whether it is selected or not).
284 // Additionally, the application might choose to show a state icon
285 // which corresponds to an app-defined item state (for example,
286 // checked/unchecked) which are taken from the state image list.
287 wxImageList
*GetImageList() const { return m_imageListNormal
; }
288 wxImageList
*GetStateImageList() const { return m_imageListState
; }
289 wxImageList
*GetButtonsImageList() const { return m_imageListButtons
; }
291 void SetImageList(wxImageList
*imageList
);
292 void SetStateImageList(wxImageList
*imageList
);
293 void SetButtonsImageList(wxImageList
*imageList
);
294 void AssignImageList(wxImageList
*imageList
);
295 void AssignStateImageList(wxImageList
*imageList
);
296 void AssignButtonsImageList(wxImageList
*imageList
);
298 // Functions to work with tree ctrl items.
303 // retrieve item's label
304 wxString
GetItemText (const wxTreeItemId
& item
) const
305 { return GetItemText (item
, GetMainColumn()); }
306 wxString
GetItemText (const wxTreeItemId
& item
, int column
) const;
307 wxString
GetItemText (wxTreeItemData
* item
, int column
) const;
309 // get one of the images associated with the item (normal by default)
310 int GetItemImage (const wxTreeItemId
& item
,
311 wxTreeItemIcon which
= wxTreeItemIcon_Normal
) const
312 { return GetItemImage (item
, GetMainColumn(), which
); }
313 int GetItemImage (const wxTreeItemId
& item
, int column
,
314 wxTreeItemIcon which
= wxTreeItemIcon_Normal
) const;
316 // get the data associated with the item
317 wxTreeItemData
*GetItemData(const wxTreeItemId
& item
) const;
319 bool GetItemBold(const wxTreeItemId
& item
) const;
320 wxColour
GetItemTextColour(const wxTreeItemId
& item
) const;
321 wxColour
GetItemBackgroundColour(const wxTreeItemId
& item
) const;
322 wxFont
GetItemFont(const wxTreeItemId
& item
) const;
328 void SetItemText (const wxTreeItemId
& item
, const wxString
& text
)
329 { SetItemText (item
, GetMainColumn(), text
); }
330 void SetItemText (const wxTreeItemId
& item
, int column
, const wxString
& text
);
332 // get one of the images associated with the item (normal by default)
333 void SetItemImage (const wxTreeItemId
& item
, int image
,
334 wxTreeItemIcon which
= wxTreeItemIcon_Normal
)
335 { SetItemImage (item
, GetMainColumn(), image
, which
); }
336 void SetItemImage (const wxTreeItemId
& item
, int column
, int image
,
337 wxTreeItemIcon which
= wxTreeItemIcon_Normal
);
339 // associate some data with the item
340 void SetItemData(const wxTreeItemId
& item
, wxTreeItemData
*data
);
342 // force appearance of [+] button near the item. This is useful to
343 // allow the user to expand the items which don't have any children now
344 // - but instead add them only when needed, thus minimizing memory
345 // usage and loading time.
346 void SetItemHasChildren(const wxTreeItemId
& item
, bool has
= true);
348 // the item will be shown in bold
349 void SetItemBold(const wxTreeItemId
& item
, bool bold
= true);
351 // set the item's text colour
352 void SetItemTextColour(const wxTreeItemId
& item
, const wxColour
& colour
);
354 // set the item's background colour
355 void SetItemBackgroundColour(const wxTreeItemId
& item
, const wxColour
& colour
);
357 // set the item's font (should be of the same height for all items)
358 void SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
);
360 // set the window font
361 virtual bool SetFont( const wxFont
&font
);
363 // set the styles. No need to specify a GetWindowStyle here since
364 // the base wxWindow member function will do it for us
365 void SetWindowStyle(const long styles
);
367 // item status inquiries
368 // ---------------------
370 // is the item visible (it might be outside the view or not expanded)?
371 bool IsVisible(const wxTreeItemId
& item
, bool fullRow
) const;
372 // does the item has any children?
373 bool HasChildren(const wxTreeItemId
& item
) const;
374 // is the item expanded (only makes sense if HasChildren())?
375 bool IsExpanded(const wxTreeItemId
& item
) const;
376 // is this item currently selected (the same as has focus)?
377 bool IsSelected(const wxTreeItemId
& item
) const;
378 // is item text in bold font?
379 bool IsBold(const wxTreeItemId
& item
) const;
380 // does the layout include space for a button?
382 // number of children
383 // ------------------
385 // if 'recursively' is false, only immediate children count, otherwise
386 // the returned number is the number of all items in this branch
387 size_t GetChildrenCount(const wxTreeItemId
& item
, bool recursively
= true);
392 // wxTreeItemId.IsOk() will return false if there is no such item
394 // get the root tree item
395 wxTreeItemId
GetRootItem() const { return m_rootItem
; }
397 // get the item currently selected, only if a single item is selected
398 wxTreeItemId
GetSelection() const { return m_selectItem
; }
400 // get all the items currently selected, return count of items
401 size_t GetSelections(wxArrayTreeItemIds
&) const;
403 // get the parent of this item (may return NULL if root)
404 wxTreeItemId
GetItemParent(const wxTreeItemId
& item
) const;
406 // for this enumeration function you must pass in a "cookie" parameter
407 // which is opaque for the application but is necessary for the library
408 // to make these functions reentrant (i.e. allow more than one
409 // enumeration on one and the same object simultaneously). Of course,
410 // the "cookie" passed to GetFirstChild() and GetNextChild() should be
413 // get child of this item
414 #if !wxCHECK_VERSION(2, 5, 0)
415 wxTreeItemId
GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const;
416 wxTreeItemId
GetNextChild(const wxTreeItemId
& item
, long& cookie
) const;
417 wxTreeItemId
GetPrevChild(const wxTreeItemId
& item
, long& cookie
) const;
418 wxTreeItemId
GetLastChild(const wxTreeItemId
& item
, long& cookie
) const;
420 wxTreeItemId
GetFirstChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
421 wxTreeItemId
GetNextChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
422 wxTreeItemId
GetPrevChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
423 wxTreeItemId
GetLastChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
426 // get sibling of this item
427 wxTreeItemId
GetNextSibling(const wxTreeItemId
& item
) const;
428 wxTreeItemId
GetPrevSibling(const wxTreeItemId
& item
) const;
430 // get item in the full tree (currently only for internal use)
431 wxTreeItemId
GetNext(const wxTreeItemId
& item
, bool fulltree
= true) const;
432 wxTreeItemId
GetPrev(const wxTreeItemId
& item
, bool fulltree
= true) const;
434 // get expanded item, see IsExpanded()
435 wxTreeItemId
GetFirstExpandedItem() const;
436 wxTreeItemId
GetNextExpanded(const wxTreeItemId
& item
) const;
437 wxTreeItemId
GetPrevExpanded(const wxTreeItemId
& item
) const;
439 // get visible item, see IsVisible()
440 wxTreeItemId
GetFirstVisibleItem(bool fullRow
) const;
441 wxTreeItemId
GetNextVisible(const wxTreeItemId
& item
, bool fullRow
) const;
442 wxTreeItemId
GetPrevVisible(const wxTreeItemId
& item
, bool fullRow
) const;
447 // add the root node to the tree
448 wxTreeItemId
AddRoot (const wxString
& text
,
449 int image
= -1, int selectedImage
= -1,
450 wxTreeItemData
*data
= NULL
);
452 // insert a new item in as the first child of the parent
453 wxTreeItemId
PrependItem(const wxTreeItemId
& parent
,
454 const wxString
& text
,
455 int image
= -1, int selectedImage
= -1,
456 wxTreeItemData
*data
= NULL
);
458 // insert a new item after a given one
459 wxTreeItemId
InsertItem(const wxTreeItemId
& parent
,
460 const wxTreeItemId
& idPrevious
,
461 const wxString
& text
,
462 int image
= -1, int selectedImage
= -1,
463 wxTreeItemData
*data
= NULL
);
465 // insert a new item before the one with the given index
466 wxTreeItemId
InsertItem(const wxTreeItemId
& parent
,
468 const wxString
& text
,
469 int image
= -1, int selectedImage
= -1,
470 wxTreeItemData
*data
= NULL
);
472 // insert a new item in as the last child of the parent
473 wxTreeItemId
AppendItem(const wxTreeItemId
& parent
,
474 const wxString
& text
,
475 int image
= -1, int selectedImage
= -1,
476 wxTreeItemData
*data
= NULL
);
478 // delete this item and associated data if any
479 void Delete(const wxTreeItemId
& item
);
480 // delete all children (but don't delete the item itself)
481 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
482 void DeleteChildren(const wxTreeItemId
& item
);
483 // delete the root and all its children from the tree
484 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
488 void Expand(const wxTreeItemId
& item
);
489 // expand this item and all subitems recursively
490 void ExpandAll(const wxTreeItemId
& item
);
491 // collapse the item without removing its children
492 void Collapse(const wxTreeItemId
& item
);
493 // collapse the item and remove all children
494 void CollapseAndReset(const wxTreeItemId
& item
);
495 // toggles the current state
496 void Toggle(const wxTreeItemId
& item
);
498 // remove the selection from currently selected item (if any)
502 void SelectItem(const wxTreeItemId
& item
, const wxTreeItemId
& prev
= (wxTreeItemId
*)NULL
,
503 bool unselect_others
= true);
505 // make sure this item is visible (expanding the parent item and/or
506 // scrolling to this item if necessary)
507 void EnsureVisible(const wxTreeItemId
& item
);
508 // scroll to this item (but don't expand its parent)
509 void ScrollTo(const wxTreeItemId
& item
);
510 void AdjustMyScrollbars();
512 // The first function is more portable (because easier to implement
513 // on other platforms), but the second one returns some extra info.
514 wxTreeItemId
HitTest (const wxPoint
& point
)
515 { int flags
; int column
; return HitTest (point
, flags
, column
); }
516 wxTreeItemId
HitTest (const wxPoint
& point
, int& flags
)
517 { int column
; return HitTest (point
, flags
, column
); }
518 wxTreeItemId
HitTest (const wxPoint
& point
, int& flags
, int& column
);
521 // get the bounding rectangle of the item (or of its label only)
522 bool GetBoundingRect(const wxTreeItemId
& item
,
524 bool textOnly
= false) const;
526 // Start editing the item label: this (temporarily) replaces the item
527 // with a one line edit control. The item will be selected if it hadn't
529 void EditLabel (const wxTreeItemId
& item
, int column
);
532 // this function is called to compare 2 items and should return -1, 0
533 // or +1 if the first item is less than, equal to or greater than the
534 // second one. The base class version performs alphabetic comparaison
535 // of item labels (GetText)
536 virtual int OnCompareItems(const wxTreeItemId
& item1
,
537 const wxTreeItemId
& item2
);
538 // sort the children of this item using OnCompareItems
540 // NB: this function is not reentrant and not MT-safe (FIXME)!
541 void SortChildren(const wxTreeItemId
& item
);
544 wxTreeItemId
FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
= 0);
546 // implementation only from now on
548 // overridden base class virtuals
549 virtual bool SetBackgroundColour(const wxColour
& colour
);
550 virtual bool SetForegroundColour(const wxColour
& colour
);
553 void SetDragItem (const wxTreeItemId
& item
= (wxTreeItemId
*)NULL
);
556 void OnPaint( wxPaintEvent
&event
);
557 void OnSetFocus( wxFocusEvent
&event
);
558 void OnKillFocus( wxFocusEvent
&event
);
559 void OnChar( wxKeyEvent
&event
);
560 void OnMouse( wxMouseEvent
&event
);
561 void OnIdle( wxIdleEvent
&event
);
562 void OnScroll(wxScrollWinEvent
& event
);
564 // implementation helpers
565 void SendDeleteEvent(wxTreeListItem
*itemBeingDeleted
);
567 int GetColumnCount() const
568 { return m_owner
->GetHeaderWindow()->GetColumnCount(); }
570 void SetMainColumn (int column
)
571 { if ((column
>= 0) && (column
< GetColumnCount())) m_main_column
= column
; }
573 int GetMainColumn() const { return m_main_column
; }
575 int GetBestColumnWidth (int column
, wxTreeItemId parent
= wxTreeItemId());
576 int GetItemWidth (int column
, wxTreeListItem
*item
);
577 wxFont
GetItemFont (wxTreeListItem
*item
);
582 wxTreeListCtrl
* m_owner
;
586 friend class wxTreeListItem
;
587 friend class wxTreeListRenameTimer
;
588 friend class wxEditTextCtrl
;
593 wxTreeListItem
*m_rootItem
; // root item
594 wxTreeListItem
*m_curItem
; // current item, either selected or marked
595 wxTreeListItem
*m_shiftItem
; // item, where the shift key was pressed
596 wxTreeListItem
*m_editItem
; // item, which is currently edited
597 wxTreeListItem
*m_selectItem
; // current selected item, not with wxTR_MULTIPLE
601 int m_btnWidth
, m_btnWidth2
;
602 int m_btnHeight
, m_btnHeight2
;
603 int m_imgWidth
, m_imgWidth2
;
604 int m_imgHeight
, m_imgHeight2
;
605 unsigned short m_indent
;
607 unsigned short m_linespacing
;
609 wxBrush
*m_hilightBrush
,
610 *m_hilightUnfocusedBrush
;
615 bool m_ownsImageListNormal
,
616 m_ownsImageListState
,
617 m_ownsImageListButtons
;
618 bool m_isDragging
; // true between BEGIN/END drag events
620 bool m_lastOnSame
; // last click on the same item as prev
621 bool m_left_down_selection
;
623 wxImageList
*m_imageListNormal
,
628 wxTimer
*m_dragTimer
;
629 wxTreeListItem
*m_dragItem
;
631 wxTimer
*m_renameTimer
;
632 wxString m_renameRes
;
635 wxTimer
*m_findTimer
;
638 // the common part of all ctors
642 wxTreeItemId
DoInsertItem(const wxTreeItemId
& parent
,
644 const wxString
& text
,
645 int image
, int selectedImage
,
646 wxTreeItemData
*data
);
647 bool HasButtons(void) const
648 { return (m_imageListButtons
) || HasFlag (wxTR_TWIST_BUTTONS
|wxTR_HAS_BUTTONS
); }
651 void CalculateLineHeight();
652 int GetLineHeight(wxTreeListItem
*item
) const;
653 void PaintLevel( wxTreeListItem
*item
, wxDC
& dc
, int level
, int &y
,
655 void PaintItem( wxTreeListItem
*item
, wxDC
& dc
);
657 void CalculateLevel( wxTreeListItem
*item
, wxDC
&dc
, int level
, int &y
,
659 void CalculatePositions();
660 void CalculateSize( wxTreeListItem
*item
, wxDC
&dc
);
662 void RefreshSubtree (wxTreeListItem
*item
);
663 void RefreshLine (wxTreeListItem
*item
);
665 // redraw all selected items
666 void RefreshSelected();
668 // RefreshSelected() recursive helper
669 void RefreshSelectedUnder (wxTreeListItem
*item
);
671 void OnRenameTimer();
672 void OnRenameAccept();
674 void FillArray(wxTreeListItem
*, wxArrayTreeItemIds
&) const;
675 bool TagAllChildrenUntilLast (wxTreeListItem
*crt_item
, wxTreeListItem
*last_item
);
676 bool TagNextChildren (wxTreeListItem
*crt_item
, wxTreeListItem
*last_item
);
677 void UnselectAllChildren (wxTreeListItem
*item
);
680 DECLARE_EVENT_TABLE()
681 DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow
)
685 // timer used for enabling in-place edit
686 class wxTreeListRenameTimer
: public wxTimer
689 wxTreeListRenameTimer( wxTreeListMainWindow
*owner
);
694 wxTreeListMainWindow
*m_owner
;
697 // control used for in-place edit
698 class wxEditTextCtrl
: public wxTextCtrl
701 wxEditTextCtrl (wxWindow
*parent
,
705 wxTreeListMainWindow
*owner
,
706 const wxString
&value
= wxEmptyString
,
707 const wxPoint
&pos
= wxDefaultPosition
,
708 const wxSize
&size
= wxDefaultSize
,
710 const wxValidator
& validator
= wxDefaultValidator
,
711 const wxString
&name
= wxTextCtrlNameStr
);
713 void OnChar( wxKeyEvent
&event
);
714 void OnKeyUp( wxKeyEvent
&event
);
715 void OnKillFocus( wxFocusEvent
&event
);
720 wxTreeListMainWindow
*m_owner
;
721 wxString m_startValue
;
724 DECLARE_EVENT_TABLE()
732 wxTreeListItem() { m_data
= NULL
; }
733 wxTreeListItem( wxTreeListMainWindow
*owner
,
734 wxTreeListItem
*parent
,
735 const wxArrayString
& text
,
738 wxTreeItemData
*data
);
743 wxArrayTreeListItems
& GetChildren() { return m_children
; }
745 const wxString
GetText() const
749 const wxString
GetText (int column
) const
751 if(m_text
.GetCount() > 0)
753 if( IsVirtual() ) return m_owner
->GetItemText( m_data
, column
);
754 else return m_text
[column
];
756 return wxEmptyString
;
759 int GetImage (wxTreeItemIcon which
= wxTreeItemIcon_Normal
) const
760 { return m_images
[which
]; }
761 int GetImage (int column
, wxTreeItemIcon which
=wxTreeItemIcon_Normal
) const
763 if(column
== m_owner
->GetMainColumn()) return m_images
[which
];
764 if(column
< (int)m_col_images
.GetCount()) return m_col_images
[column
];
768 wxTreeItemData
*GetData() const { return m_data
; }
770 // returns the current image for the item (depending on its
771 // selected/expanded/whatever state)
772 int GetCurrentImage() const;
774 void SetText (const wxString
&text
);
775 void SetText (int column
, const wxString
& text
)
777 if (column
< (int)m_text
.GetCount()) {
778 m_text
[column
] = text
;
779 }else if (column
< m_owner
->GetColumnCount()) {
780 int howmany
= m_owner
->GetColumnCount();
781 for (int i
= m_text
.GetCount(); i
< howmany
; ++i
) m_text
.Add (wxEmptyString
);
782 m_text
[column
] = text
;
785 void SetImage (int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; }
786 void SetImage (int column
, int image
, wxTreeItemIcon which
)
788 if (column
== m_owner
->GetMainColumn()) {
789 m_images
[which
] = image
;
790 }else if (column
< (int)m_col_images
.GetCount()) {
791 m_col_images
[column
] = image
;
792 }else if (column
< m_owner
->GetColumnCount()) {
793 int howmany
= m_owner
->GetColumnCount();
794 for (int i
= m_col_images
.GetCount(); i
< howmany
; ++i
) m_col_images
.Add (NO_IMAGE
);
795 m_col_images
[column
] = image
;
799 void SetData(wxTreeItemData
*data
) { m_data
= data
; }
801 void SetHasPlus(bool has
= true) { m_hasPlus
= has
; }
803 void SetBold(bool bold
) { m_isBold
= bold
; }
805 int GetX() const { return m_x
; }
806 int GetY() const { return m_y
; }
808 void SetX (int x
) { m_x
= x
; }
809 void SetY (int y
) { m_y
= y
; }
811 int GetHeight() const { return m_height
; }
812 int GetWidth() const { return m_width
; }
814 void SetHeight (int height
) { m_height
= height
; }
815 void SetWidth (int width
) { m_width
= width
; }
817 int GetTextX() const { return m_text_x
; }
818 void SetTextX (int text_x
) { m_text_x
= text_x
; }
820 wxTreeListItem
*GetItemParent() const { return m_parent
; }
823 // deletes all children notifying the treectrl about it if !NULL
825 void DeleteChildren(wxTreeListMainWindow
*tree
= NULL
);
827 // get count of all children (and grand children if 'recursively')
828 size_t GetChildrenCount(bool recursively
= true) const;
830 void Insert(wxTreeListItem
*child
, size_t index
)
831 { m_children
.Insert(child
, index
); }
833 void GetSize( int &x
, int &y
, const wxTreeListMainWindow
* );
835 // return the item at given position (or NULL if no item), onButton is
836 // true if the point belongs to the item's button, otherwise it lies
837 // on the button's label
838 wxTreeListItem
*HitTest (const wxPoint
& point
,
839 const wxTreeListMainWindow
*,
840 int &flags
, int& column
, int level
);
842 void Expand() { m_isCollapsed
= false; }
843 void Collapse() { m_isCollapsed
= true; }
845 void SetHilight( bool set
= true ) { m_hasHilight
= set
; }
848 bool HasChildren() const { return !m_children
.IsEmpty(); }
849 bool IsSelected() const { return m_hasHilight
!= 0; }
850 bool IsExpanded() const { return !m_isCollapsed
; }
851 bool HasPlus() const { return m_hasPlus
|| HasChildren(); }
852 bool IsBold() const { return m_isBold
!= 0; }
853 bool IsVirtual() const { return m_owner
->IsVirtual(); }
856 // get them - may be NULL
857 wxTreeItemAttr
*GetAttributes() const { return m_attr
; }
858 // get them ensuring that the pointer is not NULL
859 wxTreeItemAttr
& Attr()
863 m_attr
= new wxTreeItemAttr
;
869 void SetAttributes(wxTreeItemAttr
*attr
)
871 if ( m_ownsAttr
) delete m_attr
;
875 // set them and delete when done
876 void AssignAttributes(wxTreeItemAttr
*attr
)
883 wxTreeListMainWindow
*m_owner
; // control the item belongs to
885 // since there can be very many of these, we save size by chosing
886 // the smallest representation for the elements and by ordering
887 // the members to avoid padding.
888 wxArrayString m_text
; // labels to be rendered for item
890 wxTreeItemData
*m_data
; // user-provided data
892 wxArrayTreeListItems m_children
; // list of children
893 wxTreeListItem
*m_parent
; // parent of this item
895 wxTreeItemAttr
*m_attr
; // attributes???
897 // tree ctrl images for the normal, selected, expanded and
898 // expanded+selected states
899 short m_images
[wxTreeItemIcon_Max
];
900 wxArrayShort m_col_images
; // images for the various columns (!= main)
902 // main column item positions
903 wxCoord m_x
; // (virtual) offset from left (vertical line)
904 wxCoord m_y
; // (virtual) offset from top
905 wxCoord m_text_x
; // item offset from left
906 short m_width
; // width of this item
907 unsigned char m_height
; // height of this item
909 // use bitfields to save size
910 int m_isCollapsed
:1;
911 int m_hasHilight
:1; // same as focused
912 int m_hasPlus
:1; // used for item which doesn't have
913 // children but has a [+] button
914 int m_isBold
:1; // render the label in bold font
915 int m_ownsAttr
:1; // delete attribute when done
918 // ===========================================================================
920 // ===========================================================================
922 // ---------------------------------------------------------------------------
923 // wxTreeListRenameTimer (internal)
924 // ---------------------------------------------------------------------------
926 wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow
*owner
)
931 void wxTreeListRenameTimer::Notify()
933 m_owner
->OnRenameTimer();
936 //-----------------------------------------------------------------------------
937 // wxEditTextCtrl (internal)
938 //-----------------------------------------------------------------------------
940 BEGIN_EVENT_TABLE (wxEditTextCtrl
,wxTextCtrl
)
941 EVT_CHAR (wxEditTextCtrl::OnChar
)
942 EVT_KEY_UP (wxEditTextCtrl::OnKeyUp
)
943 EVT_KILL_FOCUS (wxEditTextCtrl::OnKillFocus
)
946 wxEditTextCtrl::wxEditTextCtrl (wxWindow
*parent
,
950 wxTreeListMainWindow
*owner
,
951 const wxString
&value
,
955 const wxValidator
& validator
,
956 const wxString
&name
)
957 : wxTextCtrl (parent
, id
, value
, pos
, size
, style
|wxSIMPLE_BORDER
, validator
, name
)
963 (*m_res
) = wxEmptyString
;
964 m_startValue
= value
;
968 void wxEditTextCtrl::OnChar( wxKeyEvent
&event
)
970 if (event
.GetKeyCode() == WXK_RETURN
)
973 (*m_res
) = GetValue();
975 if ((*m_res
) != m_startValue
)
976 m_owner
->OnRenameAccept();
978 if (!wxPendingDelete
.Member(this))
979 wxPendingDelete
.Append(this);
982 m_owner
->SetFocus(); // This doesn't work. TODO.
986 if (event
.GetKeyCode() == WXK_ESCAPE
)
989 (*m_res
) = wxEmptyString
;
991 if (!wxPendingDelete
.Member(this))
992 wxPendingDelete
.Append(this);
995 m_owner
->SetFocus(); // This doesn't work. TODO.
1002 void wxEditTextCtrl::OnKeyUp( wxKeyEvent
&event
)
1010 // auto-grow the textctrl:
1011 wxSize parentSize
= m_owner
->GetSize();
1012 wxPoint myPos
= GetPosition();
1013 wxSize mySize
= GetSize();
1015 GetTextExtent(GetValue() + _T("M"), &sx
, &sy
);
1016 if (myPos
.x
+ sx
> parentSize
.x
) sx
= parentSize
.x
- myPos
.x
;
1017 if (mySize
.x
> sx
) sx
= mySize
.x
;
1023 void wxEditTextCtrl::OnKillFocus( wxFocusEvent
&event
)
1031 if (!wxPendingDelete
.Member(this))
1032 wxPendingDelete
.Append(this);
1035 (*m_res
) = GetValue();
1037 if ((*m_res
) != m_startValue
)
1038 m_owner
->OnRenameAccept();
1041 //-----------------------------------------------------------------------------
1042 // wxTreeListHeaderWindow
1043 //-----------------------------------------------------------------------------
1045 IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow
,wxWindow
);
1047 BEGIN_EVENT_TABLE(wxTreeListHeaderWindow
,wxWindow
)
1048 EVT_PAINT (wxTreeListHeaderWindow::OnPaint
)
1049 EVT_MOUSE_EVENTS (wxTreeListHeaderWindow::OnMouse
)
1050 EVT_SET_FOCUS (wxTreeListHeaderWindow::OnSetFocus
)
1053 void wxTreeListHeaderWindow::Init()
1055 m_currentCursor
= (wxCursor
*) NULL
;
1056 m_isDragging
= false;
1058 m_total_col_width
= 0;
1061 wxTreeListHeaderWindow::wxTreeListHeaderWindow()
1065 m_owner
= (wxTreeListMainWindow
*) NULL
;
1066 m_resizeCursor
= (wxCursor
*) NULL
;
1069 wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow
*win
,
1071 wxTreeListMainWindow
*owner
,
1075 const wxString
&name
)
1076 : wxWindow( win
, id
, pos
, size
, style
, name
)
1081 m_resizeCursor
= new wxCursor(wxCURSOR_SIZEWE
);
1083 #if !wxCHECK_VERSION(2, 5, 0)
1084 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNFACE
));
1086 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE
));
1090 wxTreeListHeaderWindow::~wxTreeListHeaderWindow()
1092 delete m_resizeCursor
;
1095 void wxTreeListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1097 #if !wxCHECK_VERSION(2, 5, 0)
1098 wxPen
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1100 wxPen
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1103 const int m_corner
= 1;
1105 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1106 #if defined( __WXMAC__ )
1109 dc
->SetPen( *wxBLACK_PEN
);
1111 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1112 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1114 #if defined( __WXMAC__ )
1115 wxPen
pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1118 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1119 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1121 dc
->SetPen( *wxWHITE_PEN
);
1122 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1123 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1124 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1125 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1128 // shift the DC origin to match the position of the main window horz
1129 // scrollbar: this allows us to always use logical coords
1130 void wxTreeListHeaderWindow::AdjustDC(wxDC
& dc
)
1133 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1135 m_owner
->GetViewStart( &x
, NULL
);
1137 // account for the horz scrollbar offset
1138 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1141 void wxTreeListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1144 wxClientDC
dc( this );
1146 wxPaintDC
dc( this );
1151 dc
.SetFont( GetFont() );
1153 // width and height of the entire header window
1155 GetClientSize( &w
, &h
);
1156 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1157 dc
.SetBackgroundMode(wxTRANSPARENT
);
1159 // do *not* use the listctrl colour for headers - one day we will have a
1160 // function to set it separately
1161 //dc.SetTextForeground( *wxBLACK );
1162 #if !wxCHECK_VERSION(2, 5, 0)
1163 dc
.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1165 dc
.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT
));
1168 int x
= HEADER_OFFSET_X
;
1170 int numColumns
= GetColumnCount();
1171 for ( int i
= 0; i
< numColumns
&& x
< w
; i
++ )
1173 if (!IsColumnShown (i
)) continue; // do next colume if not shown
1175 wxTreeListColumnInfo
& column
= GetColumn(i
);
1176 int wCol
= column
.GetWidth();
1178 // the width of the rect to draw: make it smaller to fit entirely
1179 // inside the column rect
1182 #if !wxCHECK_VERSION(2, 7, 0)
1183 dc
.SetPen( *wxWHITE_PEN
);
1184 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1186 wxRect
rect(x
, HEADER_OFFSET_Y
, cw
, h
-2);
1187 wxRendererNative::GetDefault().DrawHeaderButton (this, dc
, rect
);
1190 // if we have an image, draw it on the right of the label
1191 int image
= column
.GetImage(); //item.m_image;
1192 int ix
= -2, iy
= 0;
1193 wxImageList
* imageList
= m_owner
->GetImageList();
1194 if ((image
!= -1) && imageList
) {
1195 imageList
->GetSize (image
, ix
, iy
);
1198 // extra margins around the text label
1201 int image_offset
= cw
- ix
- 1;
1203 switch(column
.GetAlignment()) {
1205 text_x
+= EXTRA_WIDTH
;
1209 dc
.GetTextExtent (column
.GetText(), &text_width
, NULL
);
1210 text_x
+= cw
- text_width
- EXTRA_WIDTH
- MARGIN
;
1213 case wxALIGN_CENTER
:
1214 dc
.GetTextExtent(column
.GetText(), &text_width
, NULL
);
1215 text_x
+= (cw
- text_width
)/2 + ix
+ 2;
1216 image_offset
= (cw
- text_width
- ix
- 2)/2 - MARGIN
;
1221 if ((image
!= -1) && imageList
) {
1222 imageList
->Draw (image
, dc
, x
+ image_offset
/*cw - ix - 1*/,
1223 HEADER_OFFSET_Y
+ (h
- 4 - iy
)/2,
1224 wxIMAGELIST_DRAW_TRANSPARENT
);
1227 // draw the text clipping it so that it doesn't overwrite the column boundary
1228 wxDCClipper
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h
- 4 );
1229 dc
.DrawText (column
.GetText(), text_x
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1235 int more_w
= m_owner
->GetSize().x
- x
- HEADER_OFFSET_X
;
1237 #if !wxCHECK_VERSION(2, 7, 0)
1238 DoDrawRect (&dc
, x
, HEADER_OFFSET_Y
, more_w
, h
-2 );
1240 wxRect
rect (x
, HEADER_OFFSET_Y
, more_w
, h
-2);
1241 wxRendererNative::GetDefault().DrawHeaderButton (this, dc
, rect
);
1247 void wxTreeListHeaderWindow::DrawCurrent()
1249 int x1
= m_currentX
;
1251 ClientToScreen (&x1
, &y1
);
1253 int x2
= m_currentX
-1;
1255 ++x2
; // but why ????
1258 m_owner
->GetClientSize( NULL
, &y2
);
1259 m_owner
->ClientToScreen( &x2
, &y2
);
1262 dc
.SetLogicalFunction (wxINVERT
);
1263 dc
.SetPen (wxPen (*wxBLACK
, 2, wxSOLID
));
1264 dc
.SetBrush (*wxTRANSPARENT_BRUSH
);
1267 dc
.DrawLine (x1
, y1
, x2
, y2
);
1268 dc
.SetLogicalFunction (wxCOPY
);
1269 dc
.SetPen (wxNullPen
);
1270 dc
.SetBrush (wxNullBrush
);
1273 void wxTreeListHeaderWindow::OnMouse (wxMouseEvent
&event
) {
1275 // we want to work with logical coords
1277 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1278 int y
= event
.GetY();
1282 SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition());
1284 // we don't draw the line beyond our window, but we allow dragging it
1287 GetClientSize( &w
, NULL
);
1288 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1291 // erase the line if it was drawn
1292 if (m_currentX
< w
) DrawCurrent();
1294 if (event
.ButtonUp()) {
1295 m_isDragging
= false;
1296 if (HasCapture()) ReleaseMouse();
1298 SetColumnWidth (m_column
, m_currentX
- m_minX
);
1300 SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition());
1302 m_currentX
= wxMax (m_minX
+ 7, x
);
1304 // draw in the new location
1305 if (m_currentX
< w
) DrawCurrent();
1308 }else{ // not dragging
1311 bool hit_border
= false;
1313 // end of the current column
1316 // find the column where this event occured
1317 int countCol
= GetColumnCount();
1318 for (int column
= 0; column
< countCol
; column
++) {
1319 if (!IsColumnShown (column
)) continue; // do next if not shown
1321 xpos
+= GetColumnWidth (column
);
1323 if ((abs (x
-xpos
) < 3) && (y
< 22)) {
1324 // near the column border
1330 // inside the column
1337 if (event
.LeftDown() || event
.RightUp()) {
1338 if (hit_border
&& event
.LeftDown()) {
1339 m_isDragging
= true;
1343 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, event
.GetPosition());
1344 }else{ // click on a column
1345 wxEventType evt
= event
.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK
:
1346 wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
;
1347 SendListEvent (evt
, event
.GetPosition());
1349 }else if (event
.LeftDClick() && hit_border
) {
1350 SetColumnWidth (m_column
, m_owner
->GetBestColumnWidth (m_column
));
1353 }else if (event
.Moving()) {
1356 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
1357 m_currentCursor
= m_resizeCursor
;
1359 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
1360 m_currentCursor
= wxSTANDARD_CURSOR
;
1362 if (setCursor
) SetCursor (*m_currentCursor
);
1368 void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent
&WXUNUSED(event
)) {
1369 m_owner
->SetFocus();
1372 void wxTreeListHeaderWindow::SendListEvent (wxEventType type
, wxPoint pos
) {
1373 wxWindow
*parent
= GetParent();
1374 wxListEvent
le (type
, parent
->GetId());
1375 le
.SetEventObject (parent
);
1376 le
.m_pointDrag
= pos
;
1378 // the position should be relative to the parent window, not
1379 // this one for compatibility with MSW and common sense: the
1380 // user code doesn't know anything at all about this header
1381 // window, so why should it get positions relative to it?
1382 le
.m_pointDrag
.y
-= GetSize().y
;
1383 le
.m_col
= m_column
;
1384 parent
->GetEventHandler()->ProcessEvent (le
);
1387 void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo
& colInfo
) {
1388 m_columns
.Add (colInfo
);
1389 m_total_col_width
+= colInfo
.GetWidth();
1390 m_owner
->AdjustMyScrollbars();
1391 m_owner
->m_dirty
= true;
1394 void wxTreeListHeaderWindow::SetColumnWidth (int column
, int width
) {
1395 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()), _T("Invalid column"));
1396 m_total_col_width
-= m_columns
[column
].GetWidth();
1397 m_columns
[column
].SetWidth(width
);
1398 m_total_col_width
+= width
;
1399 m_owner
->AdjustMyScrollbars();
1400 m_owner
->m_dirty
= true;
1403 void wxTreeListHeaderWindow::InsertColumn (int before
, const wxTreeListColumnInfo
& colInfo
) {
1404 wxCHECK_RET ((before
>= 0) && (before
< GetColumnCount()), _T("Invalid column"));
1405 m_columns
.Insert (colInfo
, before
);
1406 m_total_col_width
+= colInfo
.GetWidth();
1407 m_owner
->AdjustMyScrollbars();
1408 m_owner
->m_dirty
= true;
1411 void wxTreeListHeaderWindow::RemoveColumn (int column
) {
1412 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()), _T("Invalid column"));
1413 m_total_col_width
-= m_columns
[column
].GetWidth();
1414 m_columns
.RemoveAt (column
);
1415 m_owner
->AdjustMyScrollbars();
1416 m_owner
->m_dirty
= true;
1419 void wxTreeListHeaderWindow::SetColumn (int column
, const wxTreeListColumnInfo
& info
) {
1420 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()), _T("Invalid column"));
1421 int w
= m_columns
[column
].GetWidth();
1422 m_columns
[column
] = info
;
1423 if (w
!= info
.GetWidth()) {
1424 m_total_col_width
+= info
.GetWidth() - w
;
1425 m_owner
->AdjustMyScrollbars();
1427 m_owner
->m_dirty
= true;
1430 // ---------------------------------------------------------------------------
1432 // ---------------------------------------------------------------------------
1434 wxTreeListItem::wxTreeListItem (wxTreeListMainWindow
*owner
,
1435 wxTreeListItem
*parent
,
1436 const wxArrayString
& text
,
1437 int image
, int selImage
,
1438 wxTreeItemData
*data
)
1441 m_images
[wxTreeItemIcon_Normal
] = image
;
1442 m_images
[wxTreeItemIcon_Selected
] = selImage
;
1443 m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
;
1444 m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
;
1451 m_isCollapsed
= true;
1452 m_hasHilight
= false;
1459 m_attr
= (wxTreeItemAttr
*)NULL
;
1462 // We don't know the height here yet.
1467 wxTreeListItem::~wxTreeListItem() {
1469 if (m_ownsAttr
) delete m_attr
;
1471 wxASSERT_MSG( m_children
.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1474 void wxTreeListItem::DeleteChildren (wxTreeListMainWindow
*tree
) {
1475 size_t count
= m_children
.Count();
1476 for (size_t n
= 0; n
< count
; n
++) {
1477 wxTreeListItem
*child
= m_children
[n
];
1479 tree
->SendDeleteEvent (child
);
1480 if (tree
->m_selectItem
== child
) tree
->m_selectItem
= (wxTreeListItem
*)NULL
;
1482 child
->DeleteChildren (tree
);
1488 void wxTreeListItem::SetText (const wxString
&text
) {
1489 if (m_text
.GetCount() > 0) {
1496 size_t wxTreeListItem::GetChildrenCount (bool recursively
) const {
1497 size_t count
= m_children
.Count();
1498 if (!recursively
) return count
;
1500 size_t total
= count
;
1501 for (size_t n
= 0; n
< count
; ++n
) {
1502 total
+= m_children
[n
]->GetChildrenCount();
1507 void wxTreeListItem::GetSize (int &x
, int &y
, const wxTreeListMainWindow
*theButton
) {
1508 int bottomY
= m_y
+ theButton
->GetLineHeight (this);
1509 if (y
< bottomY
) y
= bottomY
;
1510 int width
= m_x
+ m_width
;
1511 if ( x
< width
) x
= width
;
1514 size_t count
= m_children
.Count();
1515 for (size_t n
= 0; n
< count
; ++n
) {
1516 m_children
[n
]->GetSize (x
, y
, theButton
);
1521 wxTreeListItem
*wxTreeListItem::HitTest (const wxPoint
& point
,
1522 const wxTreeListMainWindow
*theCtrl
,
1523 int &flags
, int& column
, int level
) {
1525 // for a hidden root node, don't evaluate it, but do evaluate children
1526 if (!theCtrl
->HasFlag(wxTR_HIDE_ROOT
) || (level
> 0)) {
1528 // reset any previous hit infos
1531 wxTreeListHeaderWindow
* header_win
= theCtrl
->m_owner
->GetHeaderWindow();
1533 // check for right of all columns (outside)
1534 if (point
.x
> header_win
->GetWidth()) return (wxTreeListItem
*) NULL
;
1536 // evaluate if y-pos is okay
1537 int h
= theCtrl
->GetLineHeight (this);
1538 if ((point
.y
>= m_y
) && (point
.y
<= m_y
+ h
)) {
1540 int maincol
= theCtrl
->GetMainColumn();
1542 // check for above/below middle
1543 int y_mid
= m_y
+ h
/2;
1544 if (point
.y
< y_mid
) {
1545 flags
|= wxTREE_HITTEST_ONITEMUPPERPART
;
1547 flags
|= wxTREE_HITTEST_ONITEMLOWERPART
;
1550 // check for button hit
1551 if (HasPlus() && theCtrl
->HasButtons()) {
1552 int bntX
= m_x
- theCtrl
->m_btnWidth2
;
1553 int bntY
= y_mid
- theCtrl
->m_btnHeight2
;
1554 if ((point
.x
>= bntX
) && (point
.x
<= (bntX
+ theCtrl
->m_btnWidth
)) &&
1555 (point
.y
>= bntY
) && (point
.y
<= (bntY
+ theCtrl
->m_btnHeight
))) {
1556 flags
|= wxTREE_HITTEST_ONITEMBUTTON
;
1562 // check for image hit
1563 if (theCtrl
->m_imgWidth
> 0) {
1564 int imgX
= m_text_x
- theCtrl
->m_imgWidth
- MARGIN
;
1565 int imgY
= y_mid
- theCtrl
->m_imgHeight2
;
1566 if ((point
.x
>= imgX
) && (point
.x
<= (imgX
+ theCtrl
->m_imgWidth
)) &&
1567 (point
.y
>= imgY
) && (point
.y
<= (imgY
+ theCtrl
->m_imgHeight
))) {
1568 flags
|= wxTREE_HITTEST_ONITEMICON
;
1574 // check for label hit
1575 if ((point
.x
>= m_text_x
) && (point
.x
<= (m_text_x
+ m_width
))) {
1576 flags
|= wxTREE_HITTEST_ONITEMLABEL
;
1581 // check for indent hit after button and image hit
1582 if (point
.x
< m_x
) {
1583 flags
|= wxTREE_HITTEST_ONITEMINDENT
;
1584 column
= -1; // considered not belonging to main column
1588 // check for right of label
1590 for (int i
= 0; i
<= maincol
; ++i
) end
+= header_win
->GetColumnWidth (i
);
1591 if ((point
.x
> (m_text_x
+ m_width
)) && (point
.x
<= end
)) {
1592 flags
|= wxTREE_HITTEST_ONITEMRIGHT
;
1593 column
= -1; // considered not belonging to main column
1597 // else check for each column except main
1599 for (int j
= 0; j
< theCtrl
->GetColumnCount(); ++j
) {
1600 if (!header_win
->IsColumnShown(j
)) continue;
1601 int w
= header_win
->GetColumnWidth (j
);
1602 if ((j
!= maincol
) && (point
.x
>= x
&& point
.x
< x
+w
)) {
1603 flags
|= wxTREE_HITTEST_ONITEMCOLUMN
;
1610 // no special flag or column found
1615 // if children not expanded, return no item
1616 if (!IsExpanded()) return (wxTreeListItem
*) NULL
;
1619 // in any case evaluate children
1620 wxTreeListItem
*child
;
1621 size_t count
= m_children
.Count();
1622 for (size_t n
= 0; n
< count
; n
++) {
1623 child
= m_children
[n
]->HitTest (point
, theCtrl
, flags
, column
, level
+1);
1624 if (child
) return child
;
1628 return (wxTreeListItem
*) NULL
;
1631 int wxTreeListItem::GetCurrentImage() const {
1632 int image
= NO_IMAGE
;
1635 image
= GetImage (wxTreeItemIcon_SelectedExpanded
);
1637 image
= GetImage (wxTreeItemIcon_Expanded
);
1639 }else{ // not expanded
1641 image
= GetImage (wxTreeItemIcon_Selected
);
1643 image
= GetImage (wxTreeItemIcon_Normal
);
1647 // maybe it doesn't have the specific image, try the default one instead
1648 if (image
== NO_IMAGE
) image
= GetImage();
1653 // ---------------------------------------------------------------------------
1654 // wxTreeListMainWindow implementation
1655 // ---------------------------------------------------------------------------
1657 IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow
, wxScrolledWindow
)
1659 BEGIN_EVENT_TABLE(wxTreeListMainWindow
, wxScrolledWindow
)
1660 EVT_PAINT (wxTreeListMainWindow::OnPaint
)
1661 EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse
)
1662 EVT_CHAR (wxTreeListMainWindow::OnChar
)
1663 EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus
)
1664 EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus
)
1665 EVT_IDLE (wxTreeListMainWindow::OnIdle
)
1666 EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll
)
1670 // ---------------------------------------------------------------------------
1671 // construction/destruction
1672 // ---------------------------------------------------------------------------
1674 void wxTreeListMainWindow::Init() {
1676 m_rootItem
= (wxTreeListItem
*)NULL
;
1677 m_curItem
= (wxTreeListItem
*)NULL
;
1678 m_shiftItem
= (wxTreeListItem
*)NULL
;
1679 m_editItem
= (wxTreeListItem
*)NULL
;
1680 m_selectItem
= (wxTreeListItem
*)NULL
;
1682 m_curColumn
= -1; // no current column
1687 m_lineHeight
= LINEHEIGHT
;
1688 m_indent
= MININDENT
; // min. indent
1691 #if !wxCHECK_VERSION(2, 5, 0)
1692 m_hilightBrush
= new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
1693 m_hilightUnfocusedBrush
= new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW
), wxSOLID
);
1695 m_hilightBrush
= new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
1696 m_hilightUnfocusedBrush
= new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW
), wxSOLID
);
1699 m_imageListNormal
= (wxImageList
*) NULL
;
1700 m_imageListButtons
= (wxImageList
*) NULL
;
1701 m_imageListState
= (wxImageList
*) NULL
;
1702 m_ownsImageListNormal
= m_ownsImageListButtons
=
1703 m_ownsImageListState
= false;
1705 m_imgWidth
= 0, m_imgWidth2
= 0;
1706 m_imgHeight
= 0, m_imgHeight2
= 0;
1707 m_btnWidth
= 0, m_btnWidth2
= 0;
1708 m_btnHeight
= 0, m_btnHeight2
= 0;
1711 m_isDragging
= false;
1712 m_dragTimer
= new wxTimer (this, -1);
1713 m_dragItem
= (wxTreeListItem
*)NULL
;
1715 m_renameTimer
= new wxTreeListRenameTimer (this);
1716 m_lastOnSame
= false;
1717 m_left_down_selection
= false;
1719 m_findTimer
= new wxTimer (this, -1);
1721 #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
1722 m_normalFont
.MacCreateThemeFont (kThemeViewsFont
);
1724 m_normalFont
= wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT
);
1726 m_boldFont
= wxFont( m_normalFont
.GetPointSize(),
1727 m_normalFont
.GetFamily(),
1728 m_normalFont
.GetStyle(),
1730 m_normalFont
.GetUnderlined(),
1731 m_normalFont
.GetFaceName(),
1732 m_normalFont
.GetEncoding());
1735 bool wxTreeListMainWindow::Create (wxTreeListCtrl
*parent
,
1740 const wxValidator
&validator
,
1741 const wxString
& name
) {
1744 if (style
& wxTR_HAS_BUTTONS
) style
|= wxTR_MAC_BUTTONS
;
1745 if (style
& wxTR_HAS_BUTTONS
) style
&= ~wxTR_HAS_BUTTONS
;
1746 style
&= ~wxTR_LINES_AT_ROOT
;
1747 style
|= wxTR_NO_LINES
;
1750 wxGetOsVersion( &major
, &minor
);
1751 if (major
< 10) style
|= wxTR_ROW_LINES
;
1754 wxScrolledWindow::Create (parent
, id
, pos
, size
, style
|wxHSCROLL
|wxVSCROLL
, name
);
1756 #if wxUSE_VALIDATORS
1757 SetValidator(validator
);
1760 #if !wxCHECK_VERSION(2, 5, 0)
1761 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX
));
1763 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX
));
1771 bdc
.SelectObject(bmp
);
1772 bdc
.SetPen(*wxGREY_PEN
);
1773 bdc
.DrawRectangle(-1, -1, 10, 10);
1774 for (i
= 0; i
< 8; i
++) {
1775 for (j
= 0; j
< 8; j
++) {
1776 if (!((i
+ j
) & 1)) {
1777 bdc
.DrawPoint(i
, j
);
1782 m_dottedPen
= wxPen(bmp
, 1);
1785 //? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86
1786 m_dottedPen
= wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
1795 wxTreeListMainWindow::~wxTreeListMainWindow() {
1796 delete m_hilightBrush
;
1797 delete m_hilightUnfocusedBrush
;
1800 delete m_renameTimer
;
1802 if (m_ownsImageListNormal
) delete m_imageListNormal
;
1803 if (m_ownsImageListState
) delete m_imageListState
;
1804 if (m_ownsImageListButtons
) delete m_imageListButtons
;
1810 //-----------------------------------------------------------------------------
1812 //-----------------------------------------------------------------------------
1814 size_t wxTreeListMainWindow::GetCount() const {
1815 return m_rootItem
== NULL
? 0: m_rootItem
->GetChildrenCount();
1818 void wxTreeListMainWindow::SetIndent (unsigned int indent
) {
1819 m_indent
= wxMax ((unsigned)MININDENT
, indent
);
1823 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing
) {
1824 m_linespacing
= spacing
;
1826 CalculateLineHeight();
1829 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId
& item
,
1831 wxCHECK_MSG (item
.IsOk(), 0u, _T("invalid tree item"));
1832 return ((wxTreeListItem
*)item
.m_pItem
)->GetChildrenCount (recursively
);
1835 void wxTreeListMainWindow::SetWindowStyle (const long styles
) {
1836 // right now, just sets the styles. Eventually, we may
1837 // want to update the inherited styles, but right now
1838 // none of the parents has updatable styles
1839 m_windowStyle
= styles
;
1843 //-----------------------------------------------------------------------------
1844 // functions to work with tree items
1845 //-----------------------------------------------------------------------------
1847 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId
& item
, int column
,
1848 wxTreeItemIcon which
) const {
1849 wxCHECK_MSG (item
.IsOk(), -1, _T("invalid tree item"));
1850 return ((wxTreeListItem
*) item
.m_pItem
)->GetImage (column
, which
);
1853 wxTreeItemData
*wxTreeListMainWindow::GetItemData (const wxTreeItemId
& item
) const {
1854 wxCHECK_MSG (item
.IsOk(), NULL
, _T("invalid tree item"));
1855 return ((wxTreeListItem
*) item
.m_pItem
)->GetData();
1858 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId
& item
) const {
1859 wxCHECK_MSG(item
.IsOk(), false, _T("invalid tree item"));
1860 return ((wxTreeListItem
*)item
.m_pItem
)->IsBold();
1863 wxColour
wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId
& item
) const {
1864 wxCHECK_MSG (item
.IsOk(), wxNullColour
, _T("invalid tree item"));
1865 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1866 return pItem
->Attr().GetTextColour();
1869 wxColour
wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId
& item
) const {
1870 wxCHECK_MSG (item
.IsOk(), wxNullColour
, _T("invalid tree item"));
1871 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1872 return pItem
->Attr().GetBackgroundColour();
1875 wxFont
wxTreeListMainWindow::GetItemFont (const wxTreeItemId
& item
) const {
1876 wxCHECK_MSG (item
.IsOk(), wxNullFont
, _T("invalid tree item"));
1877 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1878 return pItem
->Attr().GetFont();
1881 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId
& item
, int column
,
1882 int image
, wxTreeItemIcon which
) {
1883 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
1884 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1885 pItem
->SetImage (column
, image
, which
);
1886 wxClientDC
dc (this);
1887 CalculateSize (pItem
, dc
);
1888 RefreshLine (pItem
);
1891 void wxTreeListMainWindow::SetItemData (const wxTreeItemId
& item
,
1892 wxTreeItemData
*data
) {
1893 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
1894 ((wxTreeListItem
*) item
.m_pItem
)->SetData(data
);
1897 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId
& item
,
1899 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
1900 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1901 pItem
->SetHasPlus (has
);
1902 RefreshLine (pItem
);
1905 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId
& item
, bool bold
) {
1906 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
1907 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1908 if (pItem
->IsBold() != bold
) { // avoid redrawing if no real change
1909 pItem
->SetBold (bold
);
1910 RefreshLine (pItem
);
1914 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId
& item
,
1915 const wxColour
& colour
) {
1916 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
1917 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1918 pItem
->Attr().SetTextColour (colour
);
1919 RefreshLine (pItem
);
1922 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId
& item
,
1923 const wxColour
& colour
) {
1924 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
1925 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1926 pItem
->Attr().SetBackgroundColour (colour
);
1927 RefreshLine (pItem
);
1930 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId
& item
,
1931 const wxFont
& font
) {
1932 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
1933 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1934 pItem
->Attr().SetFont (font
);
1935 RefreshLine (pItem
);
1938 bool wxTreeListMainWindow::SetFont (const wxFont
&font
) {
1939 wxScrolledWindow::SetFont (font
);
1940 m_normalFont
= font
;
1941 m_boldFont
= wxFont (m_normalFont
.GetPointSize(),
1942 m_normalFont
.GetFamily(),
1943 m_normalFont
.GetStyle(),
1945 m_normalFont
.GetUnderlined(),
1946 m_normalFont
.GetFaceName());
1947 CalculateLineHeight();
1952 // ----------------------------------------------------------------------------
1953 // item status inquiries
1954 // ----------------------------------------------------------------------------
1956 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId
& item
, bool fullRow
) const {
1957 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
1959 // An item is only visible if it's not a descendant of a collapsed item
1960 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1961 wxTreeListItem
* parent
= pItem
->GetItemParent();
1963 if (parent
== m_rootItem
&& HasFlag(wxTR_HIDE_ROOT
)) break;
1964 if (!parent
->IsExpanded()) return false;
1965 parent
= parent
->GetItemParent();
1968 wxSize clientSize
= GetClientSize();
1970 if ((!GetBoundingRect (item
, rect
)) ||
1971 ((!fullRow
&& rect
.GetWidth() == 0) || rect
.GetHeight() == 0) ||
1972 (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) ||
1973 (!fullRow
&& (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
))) return false;
1978 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId
& item
) const {
1979 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
1981 // consider that the item does have children if it has the "+" button: it
1982 // might not have them (if it had never been expanded yet) but then it
1983 // could have them as well and it's better to err on this side rather than
1984 // disabling some operations which are restricted to the items with
1985 // children for an item which does have them
1986 return ((wxTreeListItem
*) item
.m_pItem
)->HasPlus();
1989 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId
& item
) const {
1990 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
1991 return ((wxTreeListItem
*) item
.m_pItem
)->IsExpanded();
1994 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId
& item
) const {
1995 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
1996 return ((wxTreeListItem
*) item
.m_pItem
)->IsSelected();
1999 bool wxTreeListMainWindow::IsBold (const wxTreeItemId
& item
) const {
2000 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2001 return ((wxTreeListItem
*) item
.m_pItem
)->IsBold();
2004 // ----------------------------------------------------------------------------
2006 // ----------------------------------------------------------------------------
2008 wxTreeItemId
wxTreeListMainWindow::GetItemParent (const wxTreeItemId
& item
) const {
2009 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2010 return ((wxTreeListItem
*) item
.m_pItem
)->GetItemParent();
2013 #if !wxCHECK_VERSION(2, 5, 0)
2014 wxTreeItemId
wxTreeListMainWindow::GetFirstChild (const wxTreeItemId
& item
,
2015 long& cookie
) const {
2017 wxTreeItemId
wxTreeListMainWindow::GetFirstChild (const wxTreeItemId
& item
,
2018 wxTreeItemIdValue
& cookie
) const {
2020 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2021 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2023 return (!children
.IsEmpty())? wxTreeItemId(children
.Item(0)): wxTreeItemId();
2026 #if !wxCHECK_VERSION(2, 5, 0)
2027 wxTreeItemId
wxTreeListMainWindow::GetNextChild (const wxTreeItemId
& item
,
2028 long& cookie
) const {
2030 wxTreeItemId
wxTreeListMainWindow::GetNextChild (const wxTreeItemId
& item
,
2031 wxTreeItemIdValue
& cookie
) const {
2033 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2034 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2035 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2036 long *pIndex
= ((long*)&cookie
);
2037 return ((*pIndex
)+1 < (long)children
.Count())? wxTreeItemId(children
.Item(++(*pIndex
))): wxTreeItemId();
2040 #if !wxCHECK_VERSION(2, 5, 0)
2041 wxTreeItemId
wxTreeListMainWindow::GetPrevChild (const wxTreeItemId
& item
,
2042 long& cookie
) const {
2044 wxTreeItemId
wxTreeListMainWindow::GetPrevChild (const wxTreeItemId
& item
,
2045 wxTreeItemIdValue
& cookie
) const {
2047 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2048 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2049 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2050 long *pIndex
= (long*)&cookie
;
2051 return ((*pIndex
)-1 >= 0)? wxTreeItemId(children
.Item(--(*pIndex
))): wxTreeItemId();
2054 #if !wxCHECK_VERSION(2, 5, 0)
2055 wxTreeItemId
wxTreeListMainWindow::GetLastChild (const wxTreeItemId
& item
,
2056 long& cookie
) const {
2058 wxTreeItemId
wxTreeListMainWindow::GetLastChild (const wxTreeItemId
& item
,
2059 wxTreeItemIdValue
& cookie
) const {
2061 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2062 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2063 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2064 long *pIndex
= ((long*)&cookie
);
2065 (*pIndex
) = children
.Count();
2066 return (!children
.IsEmpty())? wxTreeItemId(children
.Last()): wxTreeItemId();
2069 wxTreeItemId
wxTreeListMainWindow::GetNextSibling (const wxTreeItemId
& item
) const {
2070 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2073 wxTreeListItem
*i
= (wxTreeListItem
*) item
.m_pItem
;
2074 wxTreeListItem
*parent
= i
->GetItemParent();
2075 if (!parent
) return wxTreeItemId(); // root item doesn't have any siblings
2078 wxArrayTreeListItems
& siblings
= parent
->GetChildren();
2079 size_t index
= siblings
.Index (i
);
2080 wxASSERT (index
!= (size_t)wxNOT_FOUND
); // I'm not a child of my parent?
2081 return (index
< siblings
.Count()-1)? wxTreeItemId(siblings
[index
+1]): wxTreeItemId();
2084 wxTreeItemId
wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId
& item
) const {
2085 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2088 wxTreeListItem
*i
= (wxTreeListItem
*) item
.m_pItem
;
2089 wxTreeListItem
*parent
= i
->GetItemParent();
2090 if (!parent
) return wxTreeItemId(); // root item doesn't have any siblings
2093 wxArrayTreeListItems
& siblings
= parent
->GetChildren();
2094 size_t index
= siblings
.Index(i
);
2095 wxASSERT (index
!= (size_t)wxNOT_FOUND
); // I'm not a child of my parent?
2096 return (index
>= 1)? wxTreeItemId(siblings
[index
-1]): wxTreeItemId();
2099 // Only for internal use right now, but should probably be public
2100 wxTreeItemId
wxTreeListMainWindow::GetNext (const wxTreeItemId
& item
, bool fulltree
) const {
2101 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2103 // if there are any children, return first child
2104 if (fulltree
|| ((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) {
2105 wxArrayTreeListItems
& children
= ((wxTreeListItem
*)item
.m_pItem
)->GetChildren();
2106 if (children
.GetCount() > 0) return children
.Item (0);
2109 // get sibling of this item or of the ancestors instead
2111 wxTreeItemId parent
= item
;
2113 next
= GetNextSibling (parent
);
2114 parent
= GetItemParent (parent
);
2115 } while (!next
.IsOk() && parent
.IsOk());
2119 // Only for internal use right now, but should probably be public
2120 wxTreeItemId
wxTreeListMainWindow::GetPrev (const wxTreeItemId
& item
, bool fulltree
) const {
2121 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2123 // if there are any children, return last child
2124 if (fulltree
|| ((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) {
2125 wxArrayTreeListItems
& children
= ((wxTreeListItem
*)item
.m_pItem
)->GetChildren();
2126 if (children
.GetCount() > 0) return children
.Item (children
.GetCount()-1);
2129 // get sibling of this item or of the ancestors instead
2131 wxTreeItemId parent
= item
;
2133 next
= GetPrevSibling (parent
);
2134 parent
= GetItemParent (parent
);
2135 } while (!next
.IsOk() && parent
.IsOk());
2139 wxTreeItemId
wxTreeListMainWindow::GetFirstExpandedItem() const {
2140 return GetNextExpanded (GetRootItem());
2143 wxTreeItemId
wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId
& item
) const {
2144 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2145 return GetNext (item
, false);
2148 wxTreeItemId
wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId
& item
) const {
2149 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2150 return GetPrev (item
, false);
2153 wxTreeItemId
wxTreeListMainWindow::GetFirstVisibleItem (bool fullRow
) const {
2154 return GetNextVisible (GetRootItem(), fullRow
);
2157 wxTreeItemId
wxTreeListMainWindow::GetNextVisible (const wxTreeItemId
& item
, bool fullRow
) const {
2158 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2159 wxTreeItemId id
= GetNext (item
, false);
2161 if (IsVisible (id
, fullRow
)) return id
;
2162 id
= GetNext (id
, false);
2164 return wxTreeItemId();
2167 wxTreeItemId
wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId
& item
, bool fullRow
) const {
2168 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2169 wxTreeItemId id
= GetPrev (item
, true);
2171 if (IsVisible (id
, fullRow
)) return id
;
2172 id
= GetPrev(id
, true);
2174 return wxTreeItemId();
2177 // ----------------------------------------------------------------------------
2179 // ----------------------------------------------------------------------------
2181 wxTreeItemId
wxTreeListMainWindow::DoInsertItem (const wxTreeItemId
& parentId
,
2183 const wxString
& text
,
2184 int image
, int selImage
,
2185 wxTreeItemData
*data
) {
2186 wxTreeListItem
*parent
= (wxTreeListItem
*)parentId
.m_pItem
;
2187 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2188 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2191 arr
.Alloc (GetColumnCount());
2192 for (int i
= 0; i
< (int)GetColumnCount(); ++i
) arr
.Add (wxEmptyString
);
2193 arr
[m_main_column
] = text
;
2194 wxTreeListItem
*item
= new wxTreeListItem (this, parent
, arr
, image
, selImage
, data
);
2196 #if !wxCHECK_VERSION(2, 5, 0)
2197 data
->SetId ((long)item
);
2202 parent
->Insert (item
, previous
);
2207 wxTreeItemId
wxTreeListMainWindow::AddRoot (const wxString
& text
,
2208 int image
, int selImage
,
2209 wxTreeItemData
*data
) {
2210 wxCHECK_MSG(!m_rootItem
, wxTreeItemId(), _T("tree can have only one root"));
2211 wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2212 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2215 arr
.Alloc (GetColumnCount());
2216 for (int i
= 0; i
< (int)GetColumnCount(); ++i
) arr
.Add (wxEmptyString
);
2217 arr
[m_main_column
] = text
;
2218 m_rootItem
= new wxTreeListItem (this, (wxTreeListItem
*)NULL
, arr
, image
, selImage
, data
);
2220 #if !wxCHECK_VERSION(2, 5, 0)
2221 data
->SetId((long)m_rootItem
);
2223 data
->SetId(m_rootItem
);
2226 if (HasFlag(wxTR_HIDE_ROOT
)) {
2227 // if we will hide the root, make sure children are visible
2228 m_rootItem
->SetHasPlus();
2229 m_rootItem
->Expand();
2230 #if !wxCHECK_VERSION(2, 5, 0)
2233 wxTreeItemIdValue cookie
= 0;
2235 m_curItem
= (wxTreeListItem
*)GetFirstChild (m_rootItem
, cookie
).m_pItem
;
2240 wxTreeItemId
wxTreeListMainWindow::PrependItem (const wxTreeItemId
& parent
,
2241 const wxString
& text
,
2242 int image
, int selImage
,
2243 wxTreeItemData
*data
) {
2244 return DoInsertItem (parent
, 0u, text
, image
, selImage
, data
);
2247 wxTreeItemId
wxTreeListMainWindow::InsertItem (const wxTreeItemId
& parentId
,
2248 const wxTreeItemId
& idPrevious
,
2249 const wxString
& text
,
2250 int image
, int selImage
,
2251 wxTreeItemData
*data
) {
2252 wxTreeListItem
*parent
= (wxTreeListItem
*)parentId
.m_pItem
;
2253 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2255 int index
= parent
->GetChildren().Index((wxTreeListItem
*) idPrevious
.m_pItem
);
2256 wxASSERT_MSG( index
!= wxNOT_FOUND
,
2257 _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
2259 return DoInsertItem (parentId
, ++index
, text
, image
, selImage
, data
);
2262 wxTreeItemId
wxTreeListMainWindow::InsertItem (const wxTreeItemId
& parentId
,
2264 const wxString
& text
,
2265 int image
, int selImage
,
2266 wxTreeItemData
*data
) {
2267 wxTreeListItem
*parent
= (wxTreeListItem
*)parentId
.m_pItem
;
2268 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2270 return DoInsertItem (parentId
, before
, text
, image
, selImage
, data
);
2273 wxTreeItemId
wxTreeListMainWindow::AppendItem (const wxTreeItemId
& parentId
,
2274 const wxString
& text
,
2275 int image
, int selImage
,
2276 wxTreeItemData
*data
) {
2277 wxTreeListItem
*parent
= (wxTreeListItem
*) parentId
.m_pItem
;
2278 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2280 return DoInsertItem (parent
, parent
->GetChildren().Count(), text
, image
, selImage
, data
);
2283 void wxTreeListMainWindow::SendDeleteEvent (wxTreeListItem
*item
) {
2284 // send event to user code
2285 wxTreeEvent
event (wxEVT_COMMAND_TREE_DELETE_ITEM
, m_owner
->GetId());
2286 #if !wxCHECK_VERSION(2, 5, 0)
2287 event
.SetItem ((long)item
);
2289 event
.SetItem (item
);
2291 event
.SetEventObject (m_owner
);
2292 m_owner
->ProcessEvent (event
);
2295 void wxTreeListMainWindow::Delete (const wxTreeItemId
& itemId
) {
2296 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2297 wxCHECK_RET (item
!= m_rootItem
, _T("invalid item, root may not be deleted this way!"));
2298 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2300 // don't stay with invalid m_shiftItem or we will crash in the next call to OnChar()
2301 bool changeKeyCurrent
= false;
2302 wxTreeListItem
*itemKey
= m_shiftItem
;
2304 if (itemKey
== item
) { // m_shiftItem is a descendant of the item being deleted
2305 changeKeyCurrent
= true;
2308 itemKey
= itemKey
->GetItemParent();
2311 wxTreeListItem
*parent
= item
->GetItemParent();
2313 parent
->GetChildren().Remove (item
); // remove by value
2315 if (changeKeyCurrent
) m_shiftItem
= parent
;
2317 SendDeleteEvent (item
);
2318 if (m_selectItem
== item
) m_selectItem
= (wxTreeListItem
*)NULL
;
2319 item
->DeleteChildren (this);
2323 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId
& itemId
) {
2324 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2325 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2327 item
->DeleteChildren (this);
2330 void wxTreeListMainWindow::DeleteRoot() {
2333 SendDeleteEvent (m_rootItem
);
2334 m_curItem
= (wxTreeListItem
*)NULL
;
2335 m_selectItem
= (wxTreeListItem
*)NULL
;
2336 m_rootItem
->DeleteChildren (this);
2342 void wxTreeListMainWindow::Expand (const wxTreeItemId
& itemId
) {
2343 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2344 wxCHECK_RET (item
, _T("invalid item in wxTreeListMainWindow::Expand") );
2346 if (!item
->HasPlus() || item
->IsExpanded()) return;
2348 // send event to user code
2349 wxTreeEvent
event (wxEVT_COMMAND_TREE_ITEM_EXPANDING
, m_owner
->GetId());
2350 #if !wxCHECK_VERSION(2, 5, 0)
2351 event
.SetItem ((long)item
);
2353 event
.SetItem (item
);
2355 event
.SetEventObject (m_owner
);
2356 if (m_owner
->ProcessEvent (event
) && !event
.IsAllowed()) return; // expand canceled
2361 // send event to user code
2362 event
.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED
);
2363 m_owner
->ProcessEvent (event
);
2366 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId
& itemId
) {
2368 if (!IsExpanded (itemId
)) return;
2369 #if !wxCHECK_VERSION(2, 5, 0)
2372 wxTreeItemIdValue cookie
;
2374 wxTreeItemId child
= GetFirstChild (itemId
, cookie
);
2375 while (child
.IsOk()) {
2377 child
= GetNextChild (itemId
, cookie
);
2381 void wxTreeListMainWindow::Collapse (const wxTreeItemId
& itemId
) {
2382 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2383 wxCHECK_RET (item
, _T("invalid item in wxTreeListMainWindow::Collapse") );
2385 if (!item
->HasPlus() || !item
->IsExpanded()) return;
2387 // send event to user code
2388 wxTreeEvent
event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, m_owner
->GetId() );
2389 #if !wxCHECK_VERSION(2, 5, 0)
2390 event
.SetItem ((long)item
);
2392 event
.SetItem (item
);
2394 event
.SetEventObject (m_owner
);
2395 if (m_owner
->ProcessEvent (event
) && !event
.IsAllowed()) return; // collapse canceled
2400 // send event to user code
2401 event
.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED
);
2402 ProcessEvent (event
);
2405 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId
& item
) {
2407 DeleteChildren (item
);
2410 void wxTreeListMainWindow::Toggle (const wxTreeItemId
& itemId
) {
2411 if (IsExpanded (itemId
)) {
2418 void wxTreeListMainWindow::Unselect() {
2420 m_selectItem
->SetHilight (false);
2421 RefreshLine (m_selectItem
);
2422 m_selectItem
= (wxTreeListItem
*)NULL
;
2426 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem
*item
) {
2427 if (item
->IsSelected()) {
2428 item
->SetHilight (false);
2430 if (item
== m_selectItem
) m_selectItem
= (wxTreeListItem
*)NULL
;
2432 if (item
->HasChildren()) {
2433 wxArrayTreeListItems
& children
= item
->GetChildren();
2434 size_t count
= children
.Count();
2435 for (size_t n
= 0; n
< count
; ++n
) {
2436 UnselectAllChildren (children
[n
]);
2441 void wxTreeListMainWindow::UnselectAll() {
2442 UnselectAllChildren ((wxTreeListItem
*)GetRootItem().m_pItem
);
2445 // Recursive function !
2446 // To stop we must have crt_item<last_item
2448 // Tag all next children, when no more children,
2449 // Move to parent (not to tag)
2450 // Keep going... if we found last_item, we stop.
2451 bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem
*crt_item
,
2452 wxTreeListItem
*last_item
) {
2453 wxTreeListItem
*parent
= crt_item
->GetItemParent();
2455 if (!parent
) {// This is root item
2456 return TagAllChildrenUntilLast (crt_item
, last_item
);
2459 wxArrayTreeListItems
& children
= parent
->GetChildren();
2460 int index
= children
.Index(crt_item
);
2461 wxASSERT (index
!= wxNOT_FOUND
); // I'm not a child of my parent?
2463 if ((parent
->HasChildren() && parent
->IsExpanded()) ||
2464 ((parent
== (wxTreeListItem
*)GetRootItem().m_pItem
) && HasFlag(wxTR_HIDE_ROOT
))) {
2465 size_t count
= children
.Count();
2466 for (size_t n
= (index
+1); n
< count
; ++n
) {
2467 if (TagAllChildrenUntilLast (children
[n
], last_item
)) return true;
2471 return TagNextChildren (parent
, last_item
);
2474 bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem
*crt_item
,
2475 wxTreeListItem
*last_item
) {
2476 crt_item
->SetHilight (true);
2477 RefreshLine(crt_item
);
2479 if (crt_item
==last_item
) return true;
2481 if (crt_item
->HasChildren() && crt_item
->IsExpanded()) {
2482 wxArrayTreeListItems
& children
= crt_item
->GetChildren();
2483 size_t count
= children
.Count();
2484 for (size_t n
= 0; n
< count
; ++n
) {
2485 if (TagAllChildrenUntilLast (children
[n
], last_item
)) return true;
2492 void wxTreeListMainWindow::SelectItem (const wxTreeItemId
& itemId
,
2493 const wxTreeItemId
& lastId
,
2494 bool unselect_others
) {
2495 wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item") );
2497 bool is_single
= !HasFlag(wxTR_MULTIPLE
);
2498 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2500 // single selection requires unselect others
2501 if (is_single
) unselect_others
= true;
2503 // send event to the user code
2504 wxTreeEvent
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, m_owner
->GetId() );
2505 #if !wxCHECK_VERSION(2, 5, 0)
2506 event
.SetItem ((long)item
);
2507 event
.SetOldItem ((long)m_curItem
);
2509 event
.SetItem (item
);
2510 event
.SetOldItem (m_curItem
);
2512 event
.SetEventObject (m_owner
);
2513 if (m_owner
->GetEventHandler()->ProcessEvent (event
) && !event
.IsAllowed()) return;
2515 // unselect all if unselect other items
2516 bool unselected
= false; // see that UnselectAll is done only once
2517 if (unselect_others
) {
2519 Unselect(); // to speed up thing
2526 // select item or item range
2527 if (lastId
.IsOk() && (itemId
!= lastId
)) {
2529 if (!unselected
) UnselectAll();
2530 wxTreeListItem
*last
= (wxTreeListItem
*) lastId
.m_pItem
;
2532 // ensure that the position of the item it calculated in any case
2533 if (m_dirty
) CalculatePositions();
2535 // select item range according Y-position
2536 if (last
->GetY() < item
->GetY()) {
2537 if (!TagAllChildrenUntilLast (last
, item
)) {
2538 TagNextChildren (last
, item
);
2541 if (!TagAllChildrenUntilLast (item
, last
)) {
2542 TagNextChildren (item
, last
);
2548 // select item according its old selection
2549 item
->SetHilight (!item
->IsSelected());
2551 if (unselect_others
) {
2552 m_selectItem
= (item
->IsSelected())? item
: (wxTreeListItem
*)NULL
;
2557 // send event to user code
2558 event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
);
2559 m_owner
->GetEventHandler()->ProcessEvent (event
);
2562 void wxTreeListMainWindow::SelectAll() {
2563 wxCHECK_RET (HasFlag(wxTR_MULTIPLE
), _T("invalid tree style"));
2565 // send event to user code
2566 wxTreeEvent
event (wxEVT_COMMAND_TREE_SEL_CHANGING
, m_owner
->GetId());
2567 event
.SetItem (GetRootItem());
2568 #if !wxCHECK_VERSION(2, 5, 0)
2569 event
.SetOldItem ((long)m_curItem
);
2571 event
.SetOldItem (m_curItem
);
2573 event
.SetEventObject (m_owner
);
2574 if (m_owner
->GetEventHandler()->ProcessEvent (event
) && !event
.IsAllowed()) return;
2576 #if !wxCHECK_VERSION(2, 5, 0)
2579 wxTreeItemIdValue cookie
= 0;
2581 wxTreeItemId root
= GetRootItem();
2582 wxTreeListItem
*first
= (wxTreeListItem
*)GetFirstChild (root
, cookie
).m_pItem
;
2583 wxTreeListItem
*last
= (wxTreeListItem
*)GetLastChild (root
, cookie
).m_pItem
;
2584 if (!TagAllChildrenUntilLast (first
, last
)) {
2585 TagNextChildren (first
, last
);
2588 // send event to user code
2589 event
.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED
);
2590 m_owner
->GetEventHandler()->ProcessEvent (event
);
2593 void wxTreeListMainWindow::FillArray (wxTreeListItem
*item
,
2594 wxArrayTreeItemIds
&array
) const {
2595 if (item
->IsSelected()) array
.Add (wxTreeItemId(item
));
2597 if (item
->HasChildren()) {
2598 wxArrayTreeListItems
& children
= item
->GetChildren();
2599 size_t count
= children
.GetCount();
2600 for (size_t n
= 0; n
< count
; ++n
) FillArray (children
[n
], array
);
2604 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds
&array
) const {
2606 wxTreeItemId idRoot
= GetRootItem();
2607 if (idRoot
.IsOk()) FillArray ((wxTreeListItem
*) idRoot
.m_pItem
, array
);
2608 return array
.Count();
2611 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId
& item
) {
2612 if (!item
.IsOk()) return; // do nothing if no item
2614 // first expand all parent branches
2615 wxTreeListItem
*gitem
= (wxTreeListItem
*) item
.m_pItem
;
2616 wxTreeListItem
*parent
= gitem
->GetItemParent();
2619 parent
= parent
->GetItemParent();
2623 RefreshLine (gitem
);
2626 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId
&item
) {
2627 if (!item
.IsOk()) return; // do nothing if no item
2629 // ensure that the position of the item it calculated in any case
2630 if (m_dirty
) CalculatePositions();
2632 wxTreeListItem
*gitem
= (wxTreeListItem
*) item
.m_pItem
;
2634 // now scroll to the item
2635 int item_y
= gitem
->GetY();
2638 GetScrollPixelsPerUnit (&xUnit
, &yUnit
);
2641 GetViewStart (&start_x
, &start_y
);
2646 GetClientSize (&client_w
, &client_h
);
2650 m_rootItem
->GetSize (x
, y
, this);
2651 x
= m_owner
->GetHeaderWindow()->GetWidth();
2652 y
+= yUnit
+ 2; // one more scrollbar unit + 2 pixels
2653 int x_pos
= GetScrollPos( wxHORIZONTAL
);
2655 if (item_y
< start_y
+3) {
2656 // going down, item should appear at top
2657 SetScrollbars (xUnit
, yUnit
, xUnit
? x
/xUnit
: 0, yUnit
? y
/yUnit
: 0, x_pos
, yUnit
? item_y
/yUnit
: 0);
2658 }else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) {
2659 // going up, item should appear at bottom
2660 item_y
+= yUnit
+ 2;
2661 SetScrollbars (xUnit
, yUnit
, xUnit
? x
/xUnit
: 0, yUnit
? y
/yUnit
: 0, x_pos
, yUnit
? (item_y
+GetLineHeight(gitem
)-client_h
)/yUnit
: 0 );
2665 // FIXME: tree sorting functions are not reentrant and not MT-safe!
2666 static wxTreeListMainWindow
*s_treeBeingSorted
= NULL
;
2668 static int LINKAGEMODE
tree_ctrl_compare_func(wxTreeListItem
**item1
,
2669 wxTreeListItem
**item2
)
2671 wxCHECK_MSG (s_treeBeingSorted
, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
2673 return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
);
2676 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId
& item1
,
2677 const wxTreeItemId
& item2
)
2679 return m_owner
->OnCompareItems (item1
, item2
);
2682 void wxTreeListMainWindow::SortChildren (const wxTreeItemId
& itemId
) {
2683 wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item"));
2685 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2687 wxCHECK_RET (!s_treeBeingSorted
,
2688 _T("wxTreeListMainWindow::SortChildren is not reentrant") );
2690 wxArrayTreeListItems
& children
= item
->GetChildren();
2691 if ( children
.Count() > 1 ) {
2693 s_treeBeingSorted
= this;
2694 children
.Sort(tree_ctrl_compare_func
);
2695 s_treeBeingSorted
= NULL
;
2699 wxTreeItemId
wxTreeListMainWindow::FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
) {
2701 // determine start item
2702 wxTreeItemId next
= item
;
2704 if (mode
& wxTL_MODE_NAV_LEVEL
) {
2705 next
= GetNextSibling (next
);
2706 }else if (mode
& wxTL_MODE_NAV_VISIBLE
) { //
2707 next
= GetNextVisible (next
, false);
2708 }else if (mode
& wxTL_MODE_NAV_EXPANDED
) {
2709 next
= GetNextExpanded (next
);
2710 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2711 next
= GetNext (next
, true);
2715 #if !wxCHECK_VERSION(2, 5, 0)
2718 wxTreeItemIdValue cookie
= 0;
2721 next
= (wxTreeListItem
*)GetRootItem().m_pItem
;
2722 if (HasFlag(wxTR_HIDE_ROOT
)) {
2723 next
= (wxTreeListItem
*)GetFirstChild (GetRootItem().m_pItem
, cookie
).m_pItem
;
2726 if (!next
.IsOk()) return (wxTreeItemId
*)NULL
;
2728 // start checking the next items
2729 while (next
.IsOk() && (next
!= item
)) {
2730 if (mode
& wxTL_MODE_FIND_PARTIAL
) {
2731 itemText
= GetItemText (next
).Mid (0, str
.Length());
2733 itemText
= GetItemText (next
);
2735 if (mode
& wxTL_MODE_FIND_NOCASE
) {
2736 if (itemText
.CmpNoCase (str
) == 0) return next
;
2738 if (itemText
.Cmp (str
) == 0) return next
;
2740 if (mode
& wxTL_MODE_NAV_LEVEL
) {
2741 next
= GetNextSibling (next
);
2742 }else if (mode
& wxTL_MODE_NAV_VISIBLE
) { //
2743 next
= GetNextVisible (next
, false);
2744 }else if (mode
& wxTL_MODE_NAV_EXPANDED
) {
2745 next
= GetNextExpanded (next
);
2746 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2747 next
= GetNext (next
, true);
2749 if (!next
.IsOk() && item
.IsOk()) {
2750 next
= (wxTreeListItem
*)GetRootItem().m_pItem
;
2751 if (HasFlag(wxTR_HIDE_ROOT
)) {
2752 next
= (wxTreeListItem
*)GetNextChild (GetRootItem().m_pItem
, cookie
).m_pItem
;
2756 return (wxTreeItemId
*)NULL
;
2759 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId
& item
) {
2760 wxTreeListItem
*prevItem
= m_dragItem
;
2761 m_dragItem
= (wxTreeListItem
*) item
.m_pItem
;
2762 if (prevItem
) RefreshLine (prevItem
);
2763 if (m_dragItem
) RefreshLine (m_dragItem
);
2766 void wxTreeListMainWindow::CalculateLineHeight() {
2767 wxClientDC
dc (this);
2768 dc
.SetFont (m_normalFont
);
2769 m_lineHeight
= (int)(dc
.GetCharHeight() + m_linespacing
);
2771 if (m_imageListNormal
) {
2772 // Calculate a m_lineHeight value from the normal Image sizes.
2773 // May be toggle off. Then wxTreeListMainWindow will spread when
2774 // necessary (which might look ugly).
2775 int n
= m_imageListNormal
->GetImageCount();
2776 for (int i
= 0; i
< n
; i
++) {
2777 int width
= 0, height
= 0;
2778 m_imageListNormal
->GetSize(i
, width
, height
);
2779 if (height
> m_lineHeight
) m_lineHeight
= height
+ m_linespacing
;
2783 if (m_imageListButtons
) {
2784 // Calculate a m_lineHeight value from the Button image sizes.
2785 // May be toggle off. Then wxTreeListMainWindow will spread when
2786 // necessary (which might look ugly).
2787 int n
= m_imageListButtons
->GetImageCount();
2788 for (int i
= 0; i
< n
; i
++) {
2789 int width
= 0, height
= 0;
2790 m_imageListButtons
->GetSize(i
, width
, height
);
2791 if (height
> m_lineHeight
) m_lineHeight
= height
+ m_linespacing
;
2795 if (m_lineHeight
< 30) { // add 10% space if greater than 30 pixels
2796 m_lineHeight
+= 2; // minimal 2 pixel space
2798 m_lineHeight
+= m_lineHeight
/ 10; // otherwise 10% space
2802 void wxTreeListMainWindow::SetImageList (wxImageList
*imageList
) {
2803 if (m_ownsImageListNormal
) delete m_imageListNormal
;
2804 m_imageListNormal
= imageList
;
2805 m_ownsImageListNormal
= false;
2807 CalculateLineHeight();
2810 void wxTreeListMainWindow::SetStateImageList (wxImageList
*imageList
) {
2811 if (m_ownsImageListState
) delete m_imageListState
;
2812 m_imageListState
= imageList
;
2813 m_ownsImageListState
= false;
2816 void wxTreeListMainWindow::SetButtonsImageList (wxImageList
*imageList
) {
2817 if (m_ownsImageListButtons
) delete m_imageListButtons
;
2818 m_imageListButtons
= imageList
;
2819 m_ownsImageListButtons
= false;
2821 CalculateLineHeight();
2824 void wxTreeListMainWindow::AssignImageList (wxImageList
*imageList
) {
2825 SetImageList(imageList
);
2826 m_ownsImageListNormal
= true;
2829 void wxTreeListMainWindow::AssignStateImageList (wxImageList
*imageList
) {
2830 SetStateImageList(imageList
);
2831 m_ownsImageListState
= true;
2834 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList
*imageList
) {
2835 SetButtonsImageList(imageList
);
2836 m_ownsImageListButtons
= true;
2839 // ----------------------------------------------------------------------------
2841 // ----------------------------------------------------------------------------
2843 void wxTreeListMainWindow::AdjustMyScrollbars() {
2846 GetScrollPixelsPerUnit (&xUnit
, &yUnit
);
2847 if (xUnit
== 0) xUnit
= GetCharWidth();
2848 if (yUnit
== 0) yUnit
= m_lineHeight
;
2850 m_rootItem
->GetSize (x
, y
, this);
2851 y
+= yUnit
+ 2; // one more scrollbar unit + 2 pixels
2852 int x_pos
= GetScrollPos (wxHORIZONTAL
);
2853 int y_pos
= GetScrollPos (wxVERTICAL
);
2854 x
= m_owner
->GetHeaderWindow()->GetWidth() + 2;
2855 if (x
< GetClientSize().GetWidth()) x_pos
= 0;
2856 SetScrollbars (xUnit
, yUnit
, x
/xUnit
, y
/yUnit
, x_pos
, y_pos
);
2858 SetScrollbars (0, 0, 0, 0);
2862 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem
*item
) const {
2863 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) {
2864 return item
->GetHeight();
2866 return m_lineHeight
;
2870 void wxTreeListMainWindow::PaintItem (wxTreeListItem
*item
, wxDC
& dc
) {
2872 wxTreeItemAttr
*attr
= item
->GetAttributes();
2874 dc
.SetFont (GetItemFont (item
));
2877 if (attr
&& attr
->HasTextColour()) {
2878 colText
= attr
->GetTextColour();
2880 colText
= GetForegroundColour();
2882 #if !wxCHECK_VERSION(2, 5, 0)
2883 wxColour colTextHilight
= wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT
);
2885 wxColour colTextHilight
= wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT
);
2888 int total_w
= m_owner
->GetHeaderWindow()->GetWidth();
2889 int total_h
= GetLineHeight(item
);
2890 int off_h
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0;
2891 int off_w
= HasFlag(wxTR_COLUMN_LINES
) ? 1 : 0;
2892 wxDCClipper
clipper (dc
, 0, item
->GetY(), total_w
, total_h
); // only within line
2894 int text_w
= 0, text_h
= 0;
2895 dc
.GetTextExtent( item
->GetText(GetMainColumn()), &text_w
, &text_h
);
2897 // determine background and show it
2899 if (attr
&& attr
->HasBackgroundColour()) {
2900 colBg
= attr
->GetBackgroundColour();
2902 colBg
= m_backgroundColour
;
2904 dc
.SetBrush (wxBrush (colBg
, wxSOLID
));
2905 dc
.SetPen (*wxTRANSPARENT_PEN
);
2906 if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT
)) {
2907 if (item
== m_dragItem
) {
2908 dc
.SetBrush (*m_hilightBrush
);
2909 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
2910 dc
.SetPen ((item
== m_dragItem
)? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
2911 #endif // !__WXMAC__
2912 dc
.SetTextForeground (colTextHilight
);
2913 }else if (item
->IsSelected()) {
2914 if (!m_isDragging
&& m_hasFocus
) {
2915 dc
.SetBrush (*m_hilightBrush
);
2916 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
2917 dc
.SetPen (*wxBLACK_PEN
);
2918 #endif // !__WXMAC__
2920 dc
.SetBrush (*m_hilightUnfocusedBrush
);
2921 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
2922 dc
.SetPen (*wxTRANSPARENT_PEN
);
2923 #endif // !__WXMAC__
2925 dc
.SetTextForeground (colTextHilight
);
2926 }else if (item
== m_curItem
) {
2927 dc
.SetPen (m_hasFocus
? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
2929 dc
.SetTextForeground (colText
);
2931 dc
.DrawRectangle (0, item
->GetY() + off_h
, total_w
, total_h
- off_h
);
2933 dc
.SetTextForeground (colText
);
2936 int text_extraH
= (total_h
> text_h
) ? (total_h
- text_h
)/2 : 0;
2937 int img_extraH
= (total_h
> m_imgHeight
)? (total_h
-m_imgHeight
)/2: 0;
2939 for (int i
= 0; i
< GetColumnCount(); ++i
) {
2940 if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue;
2942 int col_w
= m_owner
->GetHeaderWindow()->GetColumnWidth(i
);
2943 wxDCClipper
clipper (dc
, x_colstart
, item
->GetY(), col_w
, total_h
); // only within column
2946 int image
= NO_IMAGE
;
2948 if(i
== GetMainColumn()) {
2949 x
= item
->GetX() + MARGIN
;
2951 x
+= (m_btnWidth
-m_btnWidth2
) + LINEATROOT
;
2955 if (m_imageListNormal
) image
= item
->GetCurrentImage();
2957 x
= x_colstart
+ MARGIN
;
2958 image
= item
->GetImage(i
);
2960 if (image
!= NO_IMAGE
) image_w
= m_imgWidth
+ MARGIN
;
2962 // honor text alignment
2963 wxString text
= item
->GetText(i
);
2965 switch ( m_owner
->GetHeaderWindow()->GetColumn(i
).GetAlignment() ) {
2967 // nothing to do, already left aligned
2970 dc
.GetTextExtent (text
, &text_w
, NULL
);
2971 w
= col_w
- (image_w
+ text_w
+ off_w
+ MARGIN
);
2974 case wxALIGN_CENTER
:
2975 dc
.GetTextExtent(text
, &text_w
, NULL
);
2976 w
= (col_w
- (image_w
+ text_w
+ off_w
+ MARGIN
))/2;
2980 int text_x
= x
+ image_w
;
2981 if (i
== GetMainColumn()) item
->SetTextX (text_x
);
2983 if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT
)) {
2984 if (i
== GetMainColumn()) {
2985 if (item
== m_dragItem
) {
2986 dc
.SetBrush (*m_hilightBrush
);
2987 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
2988 dc
.SetPen ((item
== m_dragItem
)? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
2989 #endif // !__WXMAC__
2990 dc
.SetTextForeground (colTextHilight
);
2991 }else if (item
->IsSelected()) {
2992 if (!m_isDragging
&& m_hasFocus
) {
2993 dc
.SetBrush (*m_hilightBrush
);
2994 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
2995 dc
.SetPen (*wxBLACK_PEN
);
2996 #endif // !__WXMAC__
2998 dc
.SetBrush (*m_hilightUnfocusedBrush
);
2999 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3000 dc
.SetPen (*wxTRANSPARENT_PEN
);
3001 #endif // !__WXMAC__
3003 dc
.SetTextForeground (colTextHilight
);
3004 }else if (item
== m_curItem
) {
3005 dc
.SetPen (m_hasFocus
? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
3007 dc
.SetTextForeground (colText
);
3009 dc
.DrawRectangle (text_x
, item
->GetY() + off_h
, text_w
, total_h
- off_h
);
3011 dc
.SetTextForeground (colText
);
3015 if (HasFlag(wxTR_COLUMN_LINES
)) { // vertical lines between columns
3016 #if !wxCHECK_VERSION(2, 5, 0)
3017 wxPen
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3019 wxPen
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3021 dc
.SetPen ((GetBackgroundColour() == *wxWHITE
)? pen
: *wxWHITE_PEN
);
3022 dc
.DrawLine (x_colstart
+col_w
-1, item
->GetY(), x_colstart
+col_w
-1, item
->GetY()+total_h
);
3025 dc
.SetBackgroundMode (wxTRANSPARENT
);
3027 if (image
!= NO_IMAGE
) {
3028 int y
= item
->GetY() + img_extraH
;
3029 m_imageListNormal
->Draw (image
, dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3031 int text_y
= item
->GetY() + text_extraH
;
3032 dc
.DrawText (text
, (wxCoord
)text_x
, (wxCoord
)text_y
);
3034 x_colstart
+= col_w
;
3037 // restore normal font
3038 dc
.SetFont( m_normalFont
);
3041 // Now y stands for the top of the item, whereas it used to stand for middle !
3042 void wxTreeListMainWindow::PaintLevel (wxTreeListItem
*item
, wxDC
&dc
,
3043 int level
, int &y
, int x_maincol
) {
3045 // Handle hide root (only level 0)
3046 if (HasFlag(wxTR_HIDE_ROOT
) && (level
== 0)) {
3047 wxArrayTreeListItems
& children
= item
->GetChildren();
3048 for (size_t n
= 0; n
< children
.Count(); n
++) {
3049 PaintLevel (children
[n
], dc
, 1, y
, x_maincol
);
3051 // end after expanding root
3055 // calculate position of vertical lines
3056 int x
= x_maincol
+ MARGIN
; // start of column
3057 if (HasFlag(wxTR_LINES_AT_ROOT
)) x
+= LINEATROOT
; // space for lines at root
3059 x
+= (m_btnWidth
-m_btnWidth2
); // half button space
3061 x
+= (m_indent
-m_indent
/2);
3063 if (HasFlag(wxTR_HIDE_ROOT
)) {
3064 x
+= m_indent
* (level
-1); // indent but not level 1
3066 x
+= m_indent
* level
; // indent according to level
3069 // set position of vertical line
3073 int h
= GetLineHeight (item
);
3075 int y_mid
= y_top
+ (h
/2);
3078 int exposed_x
= dc
.LogicalToDeviceX(0);
3079 int exposed_y
= dc
.LogicalToDeviceY(y_top
);
3081 if (IsExposed(exposed_x
, exposed_y
, 10000, h
)) { // 10000 = very much
3083 if (HasFlag(wxTR_ROW_LINES
)) { // horizontal lines between rows
3084 //dc.DestroyClippingRegion();
3085 int total_width
= m_owner
->GetHeaderWindow()->GetWidth();
3086 // if the background colour is white, choose a
3087 // contrasting color for the lines
3088 #if !wxCHECK_VERSION(2, 5, 0)
3089 wxPen
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3091 wxPen
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3093 dc
.SetPen ((GetBackgroundColour() == *wxWHITE
)? pen
: *wxWHITE_PEN
);
3094 dc
.DrawLine (0, y_top
, total_width
, y_top
);
3095 dc
.DrawLine (0, y_top
+h
, total_width
, y_top
+h
);
3099 PaintItem (item
, dc
);
3101 // restore DC objects
3102 dc
.SetBrush(*wxWHITE_BRUSH
);
3103 dc
.SetPen(m_dottedPen
);
3105 // clip to the column width
3106 int clip_width
= m_owner
->GetHeaderWindow()->
3107 GetColumn(m_main_column
).GetWidth();
3108 wxDCClipper
clipper(dc
, x_maincol
, y_top
, clip_width
, 10000);
3110 if (!HasFlag(wxTR_NO_LINES
)) { // connection lines
3112 // draw the horizontal line here
3113 dc
.SetPen(m_dottedPen
);
3114 int x2
= x
- m_indent
;
3115 if (x2
< (x_maincol
+ MARGIN
)) x2
= x_maincol
+ MARGIN
;
3116 int x3
= x
+ (m_btnWidth
-m_btnWidth2
);
3118 if (item
->HasPlus()) {
3119 dc
.DrawLine (x2
, y_mid
, x
- m_btnWidth2
, y_mid
);
3120 dc
.DrawLine (x3
, y_mid
, x3
+ LINEATROOT
, y_mid
);
3122 dc
.DrawLine (x2
, y_mid
, x3
+ LINEATROOT
, y_mid
);
3125 dc
.DrawLine (x2
, y_mid
, x
- m_indent
/2, y_mid
);
3129 if (item
->HasPlus() && HasButtons()) { // should the item show a button?
3131 if (m_imageListButtons
) {
3133 // draw the image button here
3134 int image
= wxTreeItemIcon_Normal
;
3135 if (item
->IsExpanded()) image
= wxTreeItemIcon_Expanded
;
3136 if (item
->IsSelected()) image
+= wxTreeItemIcon_Selected
- wxTreeItemIcon_Normal
;
3137 int xx
= x
- m_btnWidth2
+ MARGIN
;
3138 int yy
= y_mid
- m_btnHeight2
;
3139 dc
.SetClippingRegion(xx
, yy
, m_btnWidth
, m_btnHeight
);
3140 m_imageListButtons
->Draw (image
, dc
, xx
, yy
, wxIMAGELIST_DRAW_TRANSPARENT
);
3141 dc
.DestroyClippingRegion();
3143 }else if (HasFlag (wxTR_TWIST_BUTTONS
)) {
3145 // draw the twisty button here
3146 dc
.SetPen(*wxBLACK_PEN
);
3147 dc
.SetBrush(*m_hilightBrush
);
3149 if (item
->IsExpanded()) {
3150 button
[0].x
= x
- (m_btnWidth2
+1);
3151 button
[0].y
= y_mid
- (m_btnHeight
/3);
3152 button
[1].x
= x
+ (m_btnWidth2
+1);
3153 button
[1].y
= button
[0].y
;
3155 button
[2].y
= button
[0].y
+ (m_btnHeight2
+1);
3157 button
[0].x
= x
- (m_btnWidth
/3);
3158 button
[0].y
= y_mid
- (m_btnHeight2
+1);
3159 button
[1].x
= button
[0].x
;
3160 button
[1].y
= y_mid
+ (m_btnHeight2
+1);
3161 button
[2].x
= button
[0].x
+ (m_btnWidth2
+1);
3162 button
[2].y
= y_mid
;
3164 dc
.DrawPolygon(3, button
);
3166 }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3168 // draw the plus sign here
3169 #if !wxCHECK_VERSION(2, 7, 0)
3170 dc
.SetPen(*wxGREY_PEN
);
3171 dc
.SetBrush(*wxWHITE_BRUSH
);
3172 dc
.DrawRectangle (x
-m_btnWidth2
, y_mid
-m_btnHeight2
, m_btnWidth
, m_btnHeight
);
3173 dc
.SetPen(*wxBLACK_PEN
);
3174 dc
.DrawLine (x
-(m_btnWidth2
-2), y_mid
, x
+(m_btnWidth2
-1), y_mid
);
3175 if (!item
->IsExpanded()) { // change "-" to "+"
3176 dc
.DrawLine (x
, y_mid
-(m_btnHeight2
-2), x
, y_mid
+(m_btnHeight2
-1));
3179 wxRect
rect (x
-m_btnWidth2
, y_mid
-m_btnHeight2
, m_btnWidth
, m_btnHeight
);
3180 int flag
= item
->IsExpanded()? wxCONTROL_EXPANDED
: 0;
3181 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc
, rect
, flag
);
3190 // restore DC objects
3191 dc
.SetBrush(*wxWHITE_BRUSH
);
3192 dc
.SetPen(m_dottedPen
);
3193 dc
.SetTextForeground(*wxBLACK
);
3195 if (item
->IsExpanded())
3197 wxArrayTreeListItems
& children
= item
->GetChildren();
3199 // clip to the column width
3200 int clip_width
= m_owner
->GetHeaderWindow()->
3201 GetColumn(m_main_column
).GetWidth();
3203 // process lower levels
3205 if (m_imgWidth
> 0) {
3206 oldY
= y_mid
+ m_imgHeight2
;
3211 for (size_t n
= 0; n
< children
.Count(); ++n
) {
3214 PaintLevel (children
[n
], dc
, level
+1, y
, x_maincol
);
3216 // draw vertical line
3217 wxDCClipper
clipper(dc
, x_maincol
, y_top
, clip_width
, 10000);
3218 if (!HasFlag (wxTR_NO_LINES
)) {
3220 dc
.DrawLine (x
, oldY
, x
, y2
);
3228 // ----------------------------------------------------------------------------
3229 // wxWindows callbacks
3230 // ----------------------------------------------------------------------------
3232 void wxTreeListMainWindow::OnPaint (wxPaintEvent
&WXUNUSED(event
)) {
3234 wxPaintDC
dc (this);
3237 if (!m_rootItem
|| (GetColumnCount() <= 0)) return;
3239 // calculate button size
3240 if (m_imageListButtons
) {
3241 m_imageListButtons
->GetSize (0, m_btnWidth
, m_btnHeight
);
3242 }else if (HasButtons()) {
3243 m_btnWidth
= BTNWIDTH
;
3244 m_btnHeight
= BTNHEIGHT
;
3246 m_btnWidth2
= m_btnWidth
/2;
3247 m_btnHeight2
= m_btnHeight
/2;
3249 // calculate image size
3250 if (m_imageListNormal
) {
3251 m_imageListNormal
->GetSize (0, m_imgWidth
, m_imgHeight
);
3253 m_imgWidth2
= m_imgWidth
/2;
3254 m_imgHeight2
= m_imgHeight
/2;
3256 // calculate indent size
3257 if (m_imageListButtons
) {
3258 m_indent
= wxMax (MININDENT
, m_btnWidth
+ MARGIN
);
3259 }else if (HasButtons()) {
3260 m_indent
= wxMax (MININDENT
, m_btnWidth
+ LINEATROOT
);
3263 // set default values
3264 dc
.SetFont( m_normalFont
);
3265 dc
.SetPen( m_dottedPen
);
3267 // calculate column start and paint
3270 for (i
= 0; i
< (int)GetMainColumn(); ++i
) {
3271 if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue;
3272 x_maincol
+= m_owner
->GetHeaderWindow()->GetColumnWidth (i
);
3275 PaintLevel (m_rootItem
, dc
, 0, y
, x_maincol
);
3278 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent
&event
) {
3282 if (m_curItem
) RefreshLine (m_curItem
);
3286 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent
&event
)
3290 if (m_curItem
) RefreshLine (m_curItem
);
3294 void wxTreeListMainWindow::OnChar (wxKeyEvent
&event
) {
3295 // send event to user code
3296 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_KEY_DOWN
, m_owner
->GetId());
3297 nevent
.SetKeyEvent (event
);
3298 nevent
.SetEventObject (m_owner
);
3299 if (m_owner
->GetEventHandler()->ProcessEvent (nevent
)) return; // handled in user code
3301 // determine first current if none
3302 bool curItemSet
= false;
3304 m_curItem
= (wxTreeListItem
*)GetRootItem().m_pItem
;
3305 if (HasFlag(wxTR_HIDE_ROOT
)) {
3306 #if !wxCHECK_VERSION(2, 5, 0)
3309 wxTreeItemIdValue cookie
= 0;
3311 m_curItem
= (wxTreeListItem
*)GetFirstChild (m_curItem
, cookie
).m_pItem
;
3315 if (!m_curItem
) return; // do nothing if empty tree
3317 // remember item at shift down
3318 if (HasFlag(wxTR_MULTIPLE
) && event
.ShiftDown()) {
3319 if (!m_shiftItem
) m_shiftItem
= m_curItem
;
3321 m_shiftItem
= (wxTreeListItem
*)NULL
;
3324 // process all cases
3325 wxTreeItemId newItem
= (wxTreeItemId
*)NULL
;
3326 switch (event
.GetKeyCode()) {
3328 // '+': Expand subtree
3331 if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) Expand (m_curItem
);
3334 // '-': collapse subtree
3336 case WXK_SUBTRACT
: {
3337 if (m_curItem
->HasPlus() && IsExpanded (m_curItem
)) Collapse (m_curItem
);
3340 // '*': expand/collapse all subtrees // TODO: Mak it more useful
3342 case WXK_MULTIPLY
: {
3343 if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) {
3344 ExpandAll (m_curItem
);
3345 }else if (m_curItem
->HasPlus()) {
3346 Collapse (m_curItem
); // TODO: CollapseAll
3350 // ' ': toggle current item
3352 SelectItem (m_curItem
, (wxTreeListItem
*)NULL
, false);
3355 // <RETURN>: activate current item
3357 wxTreeEvent
aevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, m_owner
->GetId());
3358 #if !wxCHECK_VERSION(2, 5, 0)
3359 aevent
.SetItem ((long)m_curItem
);
3361 aevent
.SetItem (m_curItem
);
3363 aevent
.SetEventObject (m_owner
);
3364 m_owner
->GetEventHandler()->ProcessEvent (aevent
);
3367 // <BKSP>: go to the parent without collapsing
3369 newItem
= GetItemParent (m_curItem
);
3370 if ((newItem
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) {
3371 newItem
= GetPrevSibling (m_curItem
); // get sibling instead of root
3375 // <UP>: go to the previous sibling or to the last of its children, to the parent
3377 newItem
= GetPrevSibling (m_curItem
);
3379 #if !wxCHECK_VERSION(2, 5, 0)
3382 wxTreeItemIdValue cookie
= 0;
3384 while (IsExpanded (newItem
) && HasChildren (newItem
)) {
3385 newItem
= GetLastChild (newItem
, cookie
);
3388 newItem
= GetItemParent (m_curItem
);
3389 if ((newItem
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) {
3390 newItem
= (wxTreeItemId
*)NULL
; // don't go to root if it is hidden
3395 // <LEFT>: if expanded collapse subtree, else go to the parent
3397 if (IsExpanded (m_curItem
)) {
3398 Collapse (m_curItem
);
3400 newItem
= GetItemParent (m_curItem
);
3401 if ((newItem
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) {
3402 newItem
= GetPrevSibling (m_curItem
); // go to sibling if it is hidden
3407 // <RIGHT>: if possible expand subtree, else go go to the first child
3409 if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) {
3412 if (IsExpanded (m_curItem
) && HasChildren (m_curItem
)) {
3413 #if !wxCHECK_VERSION(2, 5, 0)
3416 wxTreeItemIdValue cookie
= 0;
3418 newItem
= GetFirstChild (m_curItem
, cookie
);
3423 // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3426 newItem
= m_curItem
;
3428 if (IsExpanded (m_curItem
) && HasChildren (m_curItem
)) {
3429 #if !wxCHECK_VERSION(2, 5, 0)
3432 wxTreeItemIdValue cookie
= 0;
3434 newItem
= GetFirstChild( m_curItem
, cookie
);
3437 wxTreeItemId parent
= m_curItem
;
3439 newItem
= GetNextSibling (parent
);
3440 parent
= GetItemParent (parent
);
3441 } while (!newItem
&& parent
);
3446 // <END>: go to last item of the root
3448 #if !wxCHECK_VERSION(2, 5, 0)
3451 wxTreeItemIdValue cookie
= 0;
3453 newItem
= GetLastChild (GetRootItem(), cookie
);
3456 // <HOME>: go to root
3458 newItem
= GetRootItem();
3459 if (HasFlag(wxTR_HIDE_ROOT
)) {
3460 #if !wxCHECK_VERSION(2, 5, 0)
3463 wxTreeItemIdValue cookie
= 0;
3465 newItem
= GetFirstChild (newItem
, cookie
);
3469 // any char: go to the next matching string
3471 if (event
.GetKeyCode() >= (int)' ') {
3472 if (!m_findTimer
->IsRunning()) m_findStr
.Clear();
3473 m_findStr
.Append (event
.GetKeyCode());
3474 m_findTimer
->Start (FIND_TIMER_TICKS
, wxTIMER_ONE_SHOT
);
3475 wxTreeItemId prev
= m_curItem
? (wxTreeItemId
*)m_curItem
: (wxTreeItemId
*)NULL
;
3477 newItem
= FindItem (prev
, m_findStr
, wxTL_MODE_NAV_EXPANDED
|
3478 wxTL_MODE_FIND_PARTIAL
|
3479 wxTL_MODE_FIND_NOCASE
);
3480 if (newItem
|| (m_findStr
.Length() <= 1)) break;
3481 m_findStr
.RemoveLast();
3488 // select and show the new item
3490 if (!event
.ControlDown()) {
3491 bool unselect_others
= !((event
.ShiftDown() || event
.ControlDown()) &&
3492 HasFlag(wxTR_MULTIPLE
));
3493 SelectItem (newItem
, m_shiftItem
, unselect_others
);
3495 EnsureVisible (newItem
);
3496 wxTreeListItem
*oldItem
= m_curItem
;
3497 m_curItem
= (wxTreeListItem
*)newItem
.m_pItem
; // make the new item the current item
3498 RefreshLine (oldItem
);
3503 wxTreeItemId
wxTreeListMainWindow::HitTest (const wxPoint
& point
, int& flags
, int& column
) {
3509 if (point
.x
<0) flags
|= wxTREE_HITTEST_TOLEFT
;
3510 if (point
.x
>w
) flags
|= wxTREE_HITTEST_TORIGHT
;
3511 if (point
.y
<0) flags
|= wxTREE_HITTEST_ABOVE
;
3512 if (point
.y
>h
) flags
|= wxTREE_HITTEST_BELOW
;
3513 if (flags
) return wxTreeItemId();
3516 flags
= wxTREE_HITTEST_NOWHERE
;
3518 return wxTreeItemId();
3521 wxTreeListItem
*hit
= m_rootItem
->HitTest (CalcUnscrolledPosition(point
),
3522 this, flags
, column
, 0);
3524 flags
= wxTREE_HITTEST_NOWHERE
;
3526 return wxTreeItemId();
3531 // get the bounding rectangle of the item (or of its label only)
3532 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId
& itemId
, wxRect
& rect
,
3533 bool WXUNUSED(textOnly
)) const {
3534 wxCHECK_MSG (itemId
.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
3536 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
3539 GetScrollPixelsPerUnit (&xUnit
, &yUnit
);
3541 GetViewStart(& startX
, & startY
);
3543 rect
.x
= item
->GetX() - startX
* xUnit
;
3544 rect
.y
= item
->GetY() - startY
* yUnit
;
3545 rect
.width
= item
->GetWidth();
3546 rect
.height
= GetLineHeight (item
);
3553 void wxTreeListMainWindow::EditLabel (const wxTreeItemId
& item
, int column
) {
3554 if (!item
.IsOk()) return;
3555 if (!((column
>= 0) && (column
< GetColumnCount()))) return;
3557 m_editItem
= (wxTreeListItem
*) item
.m_pItem
;
3559 wxTreeEvent
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, m_owner
->GetId() );
3560 #if !wxCHECK_VERSION(2, 5, 0)
3561 te
.SetItem ((long)m_editItem
);
3563 te
.SetItem (m_editItem
);
3566 te
.SetEventObject (m_owner
);
3567 m_owner
->GetEventHandler()->ProcessEvent (te
);
3569 if (!te
.IsAllowed()) return;
3571 // ensure that the position of the item it calculated in any case
3572 if (m_dirty
) CalculatePositions();
3574 wxTreeListHeaderWindow
* header_win
= m_owner
->GetHeaderWindow();
3576 int y
= m_editItem
->GetY() + 1; // wxTextCtrl needs 1 pixels above the text
3578 int h
= m_editItem
->GetHeight();
3580 if (column
== GetMainColumn()) {
3581 x
+= m_editItem
->GetTextX() - 2; // wxTextCtrl needs 2 pixels before the text
3582 w
= wxMin (m_editItem
->GetWidth(), m_owner
->GetHeaderWindow()->GetWidth() - x
);
3584 for (int i
= 0; i
< column
; ++i
) x
+= header_win
->GetColumnWidth (i
); // start of column
3585 switch (header_win
->GetColumnAlignment (column
)) {
3586 case wxALIGN_LEFT
: {style
= wxTE_LEFT
; break;}
3587 case wxALIGN_RIGHT
: {style
= wxTE_RIGHT
; break;}
3588 case wxALIGN_CENTER
: {style
= wxTE_CENTER
; break;}
3590 w
= header_win
->GetColumnWidth (column
); // width of column
3593 wxClientDC
dc (this);
3595 x
= dc
.LogicalToDeviceX (x
);
3596 y
= dc
.LogicalToDeviceY (y
);
3598 wxEditTextCtrl
*text
= new wxEditTextCtrl (this, -1, &m_renameAccept
, &m_renameRes
,
3599 this, m_editItem
->GetText (column
),
3600 wxPoint (x
, y
), wxSize (w
, h
), style
);
3604 void wxTreeListMainWindow::OnRenameTimer() {
3605 EditLabel (m_curItem
, m_curColumn
);
3608 void wxTreeListMainWindow::OnRenameAccept() {
3610 // TODO if the validator fails this causes a crash
3611 wxTreeEvent
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, m_owner
->GetId() );
3612 #if !wxCHECK_VERSION(2, 5, 0)
3613 le
.SetItem((long)m_editItem
);
3615 le
.SetItem(m_editItem
);
3617 le
.SetEventObject( /*this*/m_owner
);
3618 le
.SetLabel( m_renameRes
);
3619 m_owner
->GetEventHandler()->ProcessEvent( le
);
3621 if (!le
.IsAllowed()) return;
3623 SetItemText (m_editItem
, m_curColumn
, m_renameRes
);
3626 void wxTreeListMainWindow::OnMouse (wxMouseEvent
&event
) {
3627 if (!m_rootItem
) return;
3629 // we process left mouse up event (enables in-place edit), right down
3630 // (pass to the user code), left dbl click (activate item) and
3631 // dragging/moving events for items drag-and-drop
3632 if (!(event
.LeftDown() ||
3634 event
.RightDown() ||
3636 event
.LeftDClick() ||
3638 (event
.GetWheelRotation() != 0 )/*? TODO ||
3639 event.Moving()?*/)) {
3640 m_owner
->GetEventHandler()->ProcessEvent (event
);
3644 // set focus if window clicked
3645 if (event
.LeftDown() || event
.RightDown()) SetFocus();
3648 wxPoint p
= wxPoint (event
.GetX(), event
.GetY());
3650 wxTreeListItem
*item
= m_rootItem
->HitTest (CalcUnscrolledPosition (p
),
3651 this, flags
, m_curColumn
, 0);
3653 // we only process dragging here
3654 if (event
.Dragging()){
3655 if (m_isDragging
) return; // nothing to do, already done
3656 if (item
== NULL
) return; // we need an item to dragging
3658 // determine drag start
3659 if (m_dragCount
== 0) {
3660 m_dragTimer
->Start (DRAG_TIMER_TICKS
, wxTIMER_ONE_SHOT
);
3663 if (m_dragCount
< 3) return; // minimum drag 3 pixel
3664 if (m_dragTimer
->IsRunning()) return;
3666 // we're going to drag
3668 m_isDragging
= true;
3672 // send drag start event
3673 wxEventType command
= event
.LeftIsDown()
3674 ? wxEVT_COMMAND_TREE_BEGIN_DRAG
3675 : wxEVT_COMMAND_TREE_BEGIN_RDRAG
;
3676 wxTreeEvent
nevent (command
, m_owner
->GetId());
3677 nevent
.SetEventObject (m_owner
);
3678 #if !wxCHECK_VERSION(2, 5, 0)
3679 nevent
.SetItem ((long)item
); // the item the drag is ended
3681 nevent
.SetItem (item
); // the item the drag is ended
3683 nevent
.Veto(); // dragging must be explicit allowed!
3684 m_owner
->GetEventHandler()->ProcessEvent (nevent
);
3686 }else if (m_isDragging
) { // any other event but not event.Dragging()
3690 m_isDragging
= false;
3691 if (HasCapture()) ReleaseMouse();
3694 // send drag end event event
3695 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_END_DRAG
, m_owner
->GetId());
3696 nevent
.SetEventObject (m_owner
);
3697 #if !wxCHECK_VERSION(2, 5, 0)
3698 nevent
.SetItem ((long)item
); // the item the drag is started
3700 nevent
.SetItem (item
); // the item the drag is started
3702 nevent
.SetPoint (p
);
3703 m_owner
->GetEventHandler()->ProcessEvent (nevent
);
3705 }else if (m_dragCount
> 0) { // just in case dragging is initiated
3712 // we process only the messages which happen on tree items
3714 m_owner
->GetEventHandler()->ProcessEvent (event
);
3718 // remember item at shift down
3719 if (event
.ShiftDown()) {
3720 if (!m_shiftItem
) m_shiftItem
= m_curItem
;
3722 m_shiftItem
= (wxTreeListItem
*)NULL
;
3725 if (event
.RightUp()) {
3728 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
, m_owner
->GetId());
3729 nevent
.SetEventObject (m_owner
);
3730 #if !wxCHECK_VERSION(2, 5, 0)
3731 nevent
.SetItem ((long)item
); // the item clicked
3733 nevent
.SetItem (item
); // the item clicked
3735 nevent
.SetInt (m_curColumn
); // the colum clicked
3736 nevent
.SetPoint (p
);
3737 m_owner
->GetEventHandler()->ProcessEvent (nevent
);
3739 }else if (event
.LeftUp()) {
3742 if ((item
== m_curItem
) && (m_curColumn
!= -1) &&
3743 (m_owner
->GetHeaderWindow()->IsColumnEditable (m_curColumn
)) &&
3744 (flags
& (wxTREE_HITTEST_ONITEMLABEL
| wxTREE_HITTEST_ONITEMCOLUMN
))){
3745 m_renameTimer
->Start (RENAME_TIMER_TICKS
, wxTIMER_ONE_SHOT
);
3747 m_lastOnSame
= false;
3750 if (((flags
& wxTREE_HITTEST_ONITEMBUTTON
) ||
3751 (flags
& wxTREE_HITTEST_ONITEMICON
)) &&
3752 HasButtons() && item
->HasPlus()) {
3754 // only toggle the item for a single click, double click on
3755 // the button doesn't do anything (it toggles the item twice)
3756 if (event
.LeftDown()) Toggle (item
);
3758 // don't select the item if the button was clicked
3762 // determine the selection if not done by left down
3763 if (!m_left_down_selection
) {
3764 bool unselect_others
= !((event
.ShiftDown() || event
.ControlDown()) &&
3765 HasFlag(wxTR_MULTIPLE
));
3766 SelectItem (item
, m_shiftItem
, unselect_others
);
3767 EnsureVisible (item
);
3768 m_curItem
= item
; // make the new item the current item
3770 m_left_down_selection
= false;
3773 }else if (event
.LeftDown() || event
.RightDown() || event
.LeftDClick()) {
3775 if (event
.LeftDown() || event
.RightDown()) {
3777 m_lastOnSame
= item
== m_curItem
;
3780 if (((flags
& wxTREE_HITTEST_ONITEMBUTTON
) ||
3781 (flags
& wxTREE_HITTEST_ONITEMICON
)) &&
3784 // only toggle the item for a single click, double click on
3785 // the button doesn't do anything (it toggles the item twice)
3786 if (event
.LeftDown()) Toggle (item
);
3788 // don't select the item if the button was clicked
3792 // determine the selection if the current item is not selected
3793 if (!item
->IsSelected()) {
3794 bool unselect_others
= !((event
.ShiftDown() || event
.ControlDown()) &&
3795 HasFlag(wxTR_MULTIPLE
));
3796 SelectItem (item
, m_shiftItem
, unselect_others
);
3797 EnsureVisible (item
);
3798 m_curItem
= item
; // make the new item the current item
3799 m_left_down_selection
= true;
3802 // For some reason, Windows isn't recognizing a left double-click,
3803 // so we need to simulate it here. Allow 200 milliseconds for now.
3804 if (event
.LeftDClick()) {
3806 // double clicking should not start editing the item label
3807 m_renameTimer
->Stop();
3808 m_lastOnSame
= false;
3810 // send activate event first
3811 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, m_owner
->GetId());
3812 nevent
.SetEventObject (m_owner
);
3813 #if !wxCHECK_VERSION(2, 5, 0)
3814 nevent
.SetItem ((long)item
); // the item clicked
3816 nevent
.SetItem (item
); // the item clicked
3818 nevent
.SetInt (m_curColumn
); // the colum clicked
3819 nevent
.SetPoint (p
);
3820 if (!m_owner
->GetEventHandler()->ProcessEvent (nevent
)) {
3822 // if the user code didn't process the activate event,
3823 // handle it ourselves by toggling the item when it is
3825 if (item
->HasPlus()) Toggle(item
);
3829 }else{ // any other event skip just in case
3836 void wxTreeListMainWindow::OnIdle (wxIdleEvent
&WXUNUSED(event
)) {
3837 /* after all changes have been done to the tree control,
3838 * we actually redraw the tree when everything is over */
3840 if (!m_dirty
) return;
3844 CalculatePositions();
3846 AdjustMyScrollbars();
3849 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent
& event
) {
3851 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
3852 wxScrolledWindow::OnScroll(event
);
3854 HandleOnScroll( event
);
3857 if(event
.GetOrientation() == wxHORIZONTAL
) {
3858 m_owner
->GetHeaderWindow()->Refresh();
3859 m_owner
->GetHeaderWindow()->Update();
3863 void wxTreeListMainWindow::CalculateSize (wxTreeListItem
*item
, wxDC
&dc
) {
3867 dc
.SetFont (GetItemFont (item
));
3869 dc
.GetTextExtent (item
->GetText (m_main_column
), &text_w
, &text_h
);
3871 // restore normal font
3872 dc
.SetFont (m_normalFont
);
3874 int total_h
= (m_imgHeight
> text_h
) ? m_imgHeight
: text_h
;
3875 if (total_h
< 30) { // add 10% space if greater than 30 pixels
3876 total_h
+= 2; // minimal 2 pixel space
3878 total_h
+= total_h
/ 10; // otherwise 10% space
3881 item
->SetHeight (total_h
);
3882 if (total_h
> m_lineHeight
) m_lineHeight
= total_h
;
3883 item
->SetWidth(m_imgWidth
+ text_w
+2);
3886 // -----------------------------------------------------------------------------
3887 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem
*item
, wxDC
&dc
,
3888 int level
, int &y
, int x_colstart
) {
3890 // calculate position of vertical lines
3891 int x
= x_colstart
+ MARGIN
; // start of column
3892 if (HasFlag(wxTR_LINES_AT_ROOT
)) x
+= LINEATROOT
; // space for lines at root
3894 x
+= (m_btnWidth
-m_btnWidth2
); // half button space
3896 x
+= (m_indent
-m_indent
/2);
3898 if (HasFlag(wxTR_HIDE_ROOT
)) {
3899 x
+= m_indent
* (level
-1); // indent but not level 1
3901 x
+= m_indent
* level
; // indent according to level
3904 // a hidden root is not evaluated, but its children are always
3905 if (HasFlag(wxTR_HIDE_ROOT
) && (level
== 0)) goto Recurse
;
3907 CalculateSize( item
, dc
);
3912 y
+= GetLineHeight(item
);
3914 // we don't need to calculate collapsed branches
3915 if ( !item
->IsExpanded() ) return;
3918 wxArrayTreeListItems
& children
= item
->GetChildren();
3919 long n
, count
= (long)children
.Count();
3921 for (n
= 0; n
< count
; ++n
) {
3922 CalculateLevel( children
[n
], dc
, level
, y
, x_colstart
); // recurse
3926 void wxTreeListMainWindow::CalculatePositions() {
3927 if ( !m_rootItem
) return;
3929 wxClientDC
dc(this);
3932 dc
.SetFont( m_normalFont
);
3934 dc
.SetPen( m_dottedPen
);
3935 //if(GetImageList() == NULL)
3936 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
3940 for (int i
= 0; i
< (int)GetMainColumn(); ++i
) {
3941 if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue;
3942 x_colstart
+= m_owner
->GetHeaderWindow()->GetColumnWidth(i
);
3944 CalculateLevel( m_rootItem
, dc
, 0, y
, x_colstart
); // start recursion
3947 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem
*item
) {
3948 if (m_dirty
) return;
3950 wxClientDC
dc(this);
3955 GetVirtualSize( &cw
, &ch
);
3958 rect
.x
= dc
.LogicalToDeviceX( 0 );
3960 rect
.y
= dc
.LogicalToDeviceY( item
->GetY() - 2 );
3963 Refresh (true, &rect
);
3964 AdjustMyScrollbars();
3967 void wxTreeListMainWindow::RefreshLine (wxTreeListItem
*item
) {
3968 if (m_dirty
) return;
3970 wxClientDC
dc(this);
3975 GetVirtualSize( &cw
, &ch
);
3978 rect
.x
= dc
.LogicalToDeviceX( 0 );
3979 rect
.y
= dc
.LogicalToDeviceY( item
->GetY() );
3981 rect
.height
= GetLineHeight(item
); //dc.GetCharHeight() + 6;
3983 Refresh (true, &rect
);
3986 void wxTreeListMainWindow::RefreshSelected() {
3987 // TODO: this is awfully inefficient, we should keep the list of all
3988 // selected items internally, should be much faster
3990 RefreshSelectedUnder (m_rootItem
);
3994 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem
*item
) {
3995 if (item
->IsSelected()) {
3999 const wxArrayTreeListItems
& children
= item
->GetChildren();
4000 long count
= children
.GetCount();
4001 for (long n
= 0; n
< count
; n
++ ) {
4002 RefreshSelectedUnder (children
[n
]);
4006 // ----------------------------------------------------------------------------
4007 // changing colours: we need to refresh the tree control
4008 // ----------------------------------------------------------------------------
4010 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour
& colour
) {
4011 if (!wxWindow::SetBackgroundColour(colour
)) return false;
4017 bool wxTreeListMainWindow::SetForegroundColour (const wxColour
& colour
) {
4018 if (!wxWindow::SetForegroundColour(colour
)) return false;
4024 void wxTreeListMainWindow::SetItemText (const wxTreeItemId
& itemId
, int column
,
4025 const wxString
& text
) {
4026 wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item"));
4028 wxClientDC
dc (this);
4029 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
4030 item
->SetText (column
, text
);
4031 CalculateSize (item
, dc
);
4035 wxString
wxTreeListMainWindow::GetItemText (const wxTreeItemId
& itemId
,
4037 wxCHECK_MSG (itemId
.IsOk(), _T(""), _T("invalid tree item") );
4039 if( IsVirtual() ) return m_owner
->OnGetItemText(((wxTreeListItem
*) itemId
.m_pItem
)->GetData(),column
);
4040 else return ((wxTreeListItem
*) itemId
.m_pItem
)->GetText (column
);
4043 wxString
wxTreeListMainWindow::GetItemText (wxTreeItemData
* item
,
4045 wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4046 return m_owner
->OnGetItemText(item
,column
);
4049 void wxTreeListMainWindow::SetFocus() {
4050 wxWindow::SetFocus();
4053 wxFont
wxTreeListMainWindow::GetItemFont (wxTreeListItem
*item
) {
4054 wxTreeItemAttr
*attr
= item
->GetAttributes();
4056 if (attr
&& attr
->HasFont()) {
4057 return attr
->GetFont();
4058 }else if (item
->IsBold()) {
4061 return m_normalFont
;
4065 int wxTreeListMainWindow::GetItemWidth (int column
, wxTreeListItem
*item
) {
4066 if (!item
) return 0;
4068 // determine item width
4070 wxFont font
= GetItemFont (item
);
4071 GetTextExtent (item
->GetText (column
), &w
, &h
, NULL
, NULL
, font
.Ok()? &font
: NULL
);
4075 int width
= w
+ 2*MARGIN
;
4076 if (column
== GetMainColumn()) {
4078 if (HasFlag(wxTR_LINES_AT_ROOT
)) width
+= LINEATROOT
;
4079 if (HasButtons()) width
+= m_btnWidth
+ LINEATROOT
;
4080 if (item
->GetCurrentImage() != NO_IMAGE
) width
+= m_imgWidth
;
4082 // count indent level
4084 wxTreeListItem
*parent
= item
->GetItemParent();
4085 wxTreeListItem
*root
= (wxTreeListItem
*)GetRootItem().m_pItem
;
4086 while (parent
&& (!HasFlag(wxTR_HIDE_ROOT
) || (parent
!= root
))) {
4088 parent
= parent
->GetItemParent();
4090 if (level
) width
+= level
* GetIndent();
4096 int wxTreeListMainWindow::GetBestColumnWidth (int column
, wxTreeItemId parent
) {
4098 GetClientSize (&maxWidth
, &h
);
4101 // get root if on item
4102 if (!parent
.IsOk()) parent
= GetRootItem();
4105 if (!HasFlag(wxTR_HIDE_ROOT
)) {
4106 int w
= GetItemWidth (column
, (wxTreeListItem
*)parent
.m_pItem
);
4107 if (width
< w
) width
= w
;
4108 if (width
> maxWidth
) return maxWidth
;
4111 wxTreeItemIdValue cookie
= 0;
4112 wxTreeItemId item
= GetFirstChild (parent
, cookie
);
4113 while (item
.IsOk()) {
4114 int w
= GetItemWidth (column
, (wxTreeListItem
*)item
.m_pItem
);
4115 if (width
< w
) width
= w
;
4116 if (width
> maxWidth
) return maxWidth
;
4118 // check the children of this item
4119 if (((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) {
4120 int w
= GetBestColumnWidth (column
, item
);
4121 if (width
< w
) width
= w
;
4122 if (width
> maxWidth
) return maxWidth
;
4126 item
= GetNextChild (parent
, cookie
);
4133 //-----------------------------------------------------------------------------
4135 //-----------------------------------------------------------------------------
4137 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl
, wxControl
);
4139 BEGIN_EVENT_TABLE(wxTreeListCtrl
, wxControl
)
4140 EVT_SIZE(wxTreeListCtrl::OnSize
)
4143 bool wxTreeListCtrl::Create(wxWindow
*parent
, wxWindowID id
,
4146 long style
, const wxValidator
&validator
,
4147 const wxString
& name
)
4149 long main_style
= style
& ~(wxSIMPLE_BORDER
|wxSUNKEN_BORDER
|wxDOUBLE_BORDER
|
4150 wxRAISED_BORDER
|wxSTATIC_BORDER
);
4151 long ctrl_style
= style
& ~(wxVSCROLL
|wxHSCROLL
);
4153 if (!wxControl::Create(parent
, id
, pos
, size
, ctrl_style
, validator
, name
)) {
4156 m_main_win
= new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size
,
4157 main_style
, validator
);
4158 m_header_win
= new wxTreeListHeaderWindow (this, -1, m_main_win
,
4159 wxPoint(0, 0), wxDefaultSize
,
4161 CalculateAndSetHeaderHeight();
4165 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4169 // we use 'g' to get the descent, too
4171 m_header_win
->GetTextExtent(_T("Hg"), &w
, &h
, &d
);
4172 h
+= d
+ 2 * HEADER_OFFSET_Y
+ EXTRA_HEIGHT
;
4174 // only update if changed
4175 if (h
!= m_headerHeight
) {
4182 void wxTreeListCtrl::DoHeaderLayout()
4185 GetClientSize(&w
, &h
);
4187 m_header_win
->SetSize (0, 0, w
, m_headerHeight
);
4188 m_header_win
->Refresh();
4191 m_main_win
->SetSize (0, m_headerHeight
+ 1, w
, h
- m_headerHeight
- 1);
4195 void wxTreeListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
))
4200 size_t wxTreeListCtrl::GetCount() const { return m_main_win
->GetCount(); }
4202 unsigned int wxTreeListCtrl::GetIndent() const
4203 { return m_main_win
->GetIndent(); }
4205 void wxTreeListCtrl::SetIndent(unsigned int indent
)
4206 { m_main_win
->SetIndent(indent
); }
4208 unsigned int wxTreeListCtrl::GetLineSpacing() const
4209 { return m_main_win
->GetLineSpacing(); }
4211 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing
)
4212 { m_main_win
->SetLineSpacing(spacing
); }
4214 wxImageList
* wxTreeListCtrl::GetImageList() const
4215 { return m_main_win
->GetImageList(); }
4217 wxImageList
* wxTreeListCtrl::GetStateImageList() const
4218 { return m_main_win
->GetStateImageList(); }
4220 wxImageList
* wxTreeListCtrl::GetButtonsImageList() const
4221 { return m_main_win
->GetButtonsImageList(); }
4223 void wxTreeListCtrl::SetImageList(wxImageList
* imageList
)
4224 { m_main_win
->SetImageList(imageList
); }
4226 void wxTreeListCtrl::SetStateImageList(wxImageList
* imageList
)
4227 { m_main_win
->SetStateImageList(imageList
); }
4229 void wxTreeListCtrl::SetButtonsImageList(wxImageList
* imageList
)
4230 { m_main_win
->SetButtonsImageList(imageList
); }
4232 void wxTreeListCtrl::AssignImageList(wxImageList
* imageList
)
4233 { m_main_win
->AssignImageList(imageList
); }
4235 void wxTreeListCtrl::AssignStateImageList(wxImageList
* imageList
)
4236 { m_main_win
->AssignStateImageList(imageList
); }
4238 void wxTreeListCtrl::AssignButtonsImageList(wxImageList
* imageList
)
4239 { m_main_win
->AssignButtonsImageList(imageList
); }
4241 wxString
wxTreeListCtrl::GetItemText(const wxTreeItemId
& item
, int column
) const
4242 { return m_main_win
->GetItemText (item
, column
); }
4244 int wxTreeListCtrl::GetItemImage(const wxTreeItemId
& item
, int column
,
4245 wxTreeItemIcon which
) const
4246 { return m_main_win
->GetItemImage(item
, column
, which
); }
4248 wxTreeItemData
* wxTreeListCtrl::GetItemData(const wxTreeItemId
& item
) const
4249 { return m_main_win
->GetItemData(item
); }
4251 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId
& item
) const
4252 { return m_main_win
->GetItemBold(item
); }
4254 wxColour
wxTreeListCtrl::GetItemTextColour(const wxTreeItemId
& item
) const
4255 { return m_main_win
->GetItemTextColour(item
); }
4257 wxColour
wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId
& item
)
4259 { return m_main_win
->GetItemBackgroundColour(item
); }
4261 wxFont
wxTreeListCtrl::GetItemFont(const wxTreeItemId
& item
) const
4262 { return m_main_win
->GetItemFont(item
); }
4265 void wxTreeListCtrl::SetItemText(const wxTreeItemId
& item
, int column
,
4266 const wxString
& text
)
4267 { m_main_win
->SetItemText (item
, column
, text
); }
4269 void wxTreeListCtrl::SetItemImage(const wxTreeItemId
& item
,
4272 wxTreeItemIcon which
)
4273 { m_main_win
->SetItemImage(item
, column
, image
, which
); }
4275 void wxTreeListCtrl::SetItemData(const wxTreeItemId
& item
,
4276 wxTreeItemData
* data
)
4277 { m_main_win
->SetItemData(item
, data
); }
4279 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
)
4280 { m_main_win
->SetItemHasChildren(item
, has
); }
4282 void wxTreeListCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
)
4283 { m_main_win
->SetItemBold(item
, bold
); }
4285 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId
& item
,
4286 const wxColour
& colour
)
4287 { m_main_win
->SetItemTextColour(item
, colour
); }
4289 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
,
4290 const wxColour
& colour
)
4291 { m_main_win
->SetItemBackgroundColour(item
, colour
); }
4293 void wxTreeListCtrl::SetItemFont(const wxTreeItemId
& item
,
4295 { m_main_win
->SetItemFont(item
, font
); }
4297 bool wxTreeListCtrl::SetFont(const wxFont
& font
)
4300 m_header_win
->SetFont(font
);
4301 CalculateAndSetHeaderHeight();
4302 m_header_win
->Refresh();
4305 return m_main_win
->SetFont(font
);
4311 void wxTreeListCtrl::SetWindowStyle(const long style
)
4314 m_main_win
->SetWindowStyle(style
);
4315 m_windowStyle
= style
;
4316 // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4319 long wxTreeListCtrl::GetWindowStyle() const
4321 long style
= m_windowStyle
;
4323 style
|= m_main_win
->GetWindowStyle();
4327 bool wxTreeListCtrl::IsVisible(const wxTreeItemId
& item
, bool fullRow
) const
4328 { return m_main_win
->IsVisible(item
, fullRow
); }
4330 bool wxTreeListCtrl::HasChildren(const wxTreeItemId
& item
) const
4331 { return m_main_win
->HasChildren(item
); }
4333 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId
& item
) const
4334 { return m_main_win
->IsExpanded(item
); }
4336 bool wxTreeListCtrl::IsSelected(const wxTreeItemId
& item
) const
4337 { return m_main_win
->IsSelected(item
); }
4339 bool wxTreeListCtrl::IsBold(const wxTreeItemId
& item
) const
4340 { return m_main_win
->IsBold(item
); }
4342 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool rec
)
4343 { return m_main_win
->GetChildrenCount(item
, rec
); }
4345 wxTreeItemId
wxTreeListCtrl::GetRootItem() const
4346 { return m_main_win
->GetRootItem(); }
4348 wxTreeItemId
wxTreeListCtrl::GetSelection() const
4349 { return m_main_win
->GetSelection(); }
4351 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds
& arr
) const
4352 { return m_main_win
->GetSelections(arr
); }
4354 wxTreeItemId
wxTreeListCtrl::GetItemParent(const wxTreeItemId
& item
) const
4355 { return m_main_win
->GetItemParent(item
); }
4357 #if !wxCHECK_VERSION(2, 5, 0)
4358 wxTreeItemId
wxTreeListCtrl::GetFirstChild (const wxTreeItemId
& item
,
4361 wxTreeItemId
wxTreeListCtrl::GetFirstChild (const wxTreeItemId
& item
,
4362 wxTreeItemIdValue
& cookie
) const
4364 { return m_main_win
->GetFirstChild(item
, cookie
); }
4366 #if !wxCHECK_VERSION(2, 5, 0)
4367 wxTreeItemId
wxTreeListCtrl::GetNextChild (const wxTreeItemId
& item
,
4370 wxTreeItemId
wxTreeListCtrl::GetNextChild (const wxTreeItemId
& item
,
4371 wxTreeItemIdValue
& cookie
) const
4373 { return m_main_win
->GetNextChild(item
, cookie
); }
4375 #if !wxCHECK_VERSION(2, 5, 0)
4376 wxTreeItemId
wxTreeListCtrl::GetPrevChild (const wxTreeItemId
& item
,
4379 wxTreeItemId
wxTreeListCtrl::GetPrevChild (const wxTreeItemId
& item
,
4380 wxTreeItemIdValue
& cookie
) const
4382 { return m_main_win
->GetPrevChild(item
, cookie
); }
4384 #if !wxCHECK_VERSION(2, 5, 0)
4385 wxTreeItemId
wxTreeListCtrl::GetLastChild (const wxTreeItemId
& item
,
4388 wxTreeItemId
wxTreeListCtrl::GetLastChild (const wxTreeItemId
& item
,
4389 wxTreeItemIdValue
& cookie
) const
4391 { return m_main_win
->GetLastChild(item
, cookie
); }
4394 wxTreeItemId
wxTreeListCtrl::GetNextSibling(const wxTreeItemId
& item
) const
4395 { return m_main_win
->GetNextSibling(item
); }
4397 wxTreeItemId
wxTreeListCtrl::GetPrevSibling(const wxTreeItemId
& item
) const
4398 { return m_main_win
->GetPrevSibling(item
); }
4400 wxTreeItemId
wxTreeListCtrl::GetNext(const wxTreeItemId
& item
) const
4401 { return m_main_win
->GetNext(item
, true); }
4403 wxTreeItemId
wxTreeListCtrl::GetPrev(const wxTreeItemId
& item
) const
4404 { return m_main_win
->GetPrev(item
, true); }
4406 wxTreeItemId
wxTreeListCtrl::GetFirstExpandedItem() const
4407 { return m_main_win
->GetFirstExpandedItem(); }
4409 wxTreeItemId
wxTreeListCtrl::GetNextExpanded(const wxTreeItemId
& item
) const
4410 { return m_main_win
->GetNextExpanded(item
); }
4412 wxTreeItemId
wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId
& item
) const
4413 { return m_main_win
->GetPrevExpanded(item
); }
4415 wxTreeItemId
wxTreeListCtrl::GetFirstVisibleItem(bool fullRow
) const
4416 { return m_main_win
->GetFirstVisibleItem(fullRow
); }
4418 wxTreeItemId
wxTreeListCtrl::GetNextVisible(const wxTreeItemId
& item
, bool fullRow
) const
4419 { return m_main_win
->GetNextVisible(item
, fullRow
); }
4421 wxTreeItemId
wxTreeListCtrl::GetPrevVisible(const wxTreeItemId
& item
, bool fullRow
) const
4422 { return m_main_win
->GetPrevVisible(item
, fullRow
); }
4424 wxTreeItemId
wxTreeListCtrl::AddRoot (const wxString
& text
, int image
,
4425 int selectedImage
, wxTreeItemData
* data
)
4426 { return m_main_win
->AddRoot (text
, image
, selectedImage
, data
); }
4428 wxTreeItemId
wxTreeListCtrl::PrependItem(const wxTreeItemId
& parent
,
4429 const wxString
& text
, int image
,
4431 wxTreeItemData
* data
)
4432 { return m_main_win
->PrependItem(parent
, text
, image
, selectedImage
, data
); }
4434 wxTreeItemId
wxTreeListCtrl::InsertItem(const wxTreeItemId
& parent
,
4435 const wxTreeItemId
& previous
,
4436 const wxString
& text
, int image
,
4438 wxTreeItemData
* data
)
4440 return m_main_win
->InsertItem(parent
, previous
, text
, image
,
4441 selectedImage
, data
);
4444 wxTreeItemId
wxTreeListCtrl::InsertItem(const wxTreeItemId
& parent
,
4446 const wxString
& text
, int image
,
4448 wxTreeItemData
* data
)
4450 return m_main_win
->InsertItem(parent
, index
, text
, image
,
4451 selectedImage
, data
);
4454 wxTreeItemId
wxTreeListCtrl::AppendItem(const wxTreeItemId
& parent
,
4455 const wxString
& text
, int image
,
4457 wxTreeItemData
* data
)
4458 { return m_main_win
->AppendItem(parent
, text
, image
, selectedImage
, data
); }
4460 void wxTreeListCtrl::Delete(const wxTreeItemId
& item
)
4461 { m_main_win
->Delete(item
); }
4463 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId
& item
)
4464 { m_main_win
->DeleteChildren(item
); }
4466 void wxTreeListCtrl::DeleteRoot()
4467 { m_main_win
->DeleteRoot(); }
4469 void wxTreeListCtrl::Expand(const wxTreeItemId
& item
)
4470 { m_main_win
->Expand(item
); }
4472 void wxTreeListCtrl::ExpandAll(const wxTreeItemId
& item
)
4473 { m_main_win
->ExpandAll(item
); }
4475 void wxTreeListCtrl::Collapse(const wxTreeItemId
& item
)
4476 { m_main_win
->Collapse(item
); }
4478 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId
& item
)
4479 { m_main_win
->CollapseAndReset(item
); }
4481 void wxTreeListCtrl::Toggle(const wxTreeItemId
& item
)
4482 { m_main_win
->Toggle(item
); }
4484 void wxTreeListCtrl::Unselect()
4485 { m_main_win
->Unselect(); }
4487 void wxTreeListCtrl::UnselectAll()
4488 { m_main_win
->UnselectAll(); }
4490 void wxTreeListCtrl::SelectItem(const wxTreeItemId
& item
, const wxTreeItemId
& last
,
4491 bool unselect_others
)
4492 { m_main_win
->SelectItem (item
, last
, unselect_others
); }
4494 void wxTreeListCtrl::SelectAll()
4495 { m_main_win
->SelectAll(); }
4497 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId
& item
)
4498 { m_main_win
->EnsureVisible(item
); }
4500 void wxTreeListCtrl::ScrollTo(const wxTreeItemId
& item
)
4501 { m_main_win
->ScrollTo(item
); }
4503 wxTreeItemId
wxTreeListCtrl::HitTest(const wxPoint
& pos
, int& flags
, int& column
)
4505 wxPoint p
= m_main_win
->ScreenToClient (ClientToScreen (pos
));
4506 return m_main_win
->HitTest (p
, flags
, column
);
4509 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId
& item
, wxRect
& rect
,
4510 bool textOnly
) const
4511 { return m_main_win
->GetBoundingRect(item
, rect
, textOnly
); }
4513 void wxTreeListCtrl::EditLabel (const wxTreeItemId
& item
, int column
)
4514 { m_main_win
->EditLabel (item
, column
); }
4516 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId
& item1
,
4517 const wxTreeItemId
& item2
)
4519 // do the comparison here, and not delegate to m_main_win, in order
4520 // to let the user override it
4521 //return m_main_win->OnCompareItems(item1, item2);
4522 return wxStrcmp(GetItemText(item1
), GetItemText(item2
));
4525 void wxTreeListCtrl::SortChildren(const wxTreeItemId
& item
)
4526 { m_main_win
->SortChildren(item
); }
4528 wxTreeItemId
wxTreeListCtrl::FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
)
4529 { return m_main_win
->FindItem (item
, str
, mode
); }
4531 void wxTreeListCtrl::SetDragItem (const wxTreeItemId
& item
)
4532 { m_main_win
->SetDragItem (item
); }
4534 bool wxTreeListCtrl::SetBackgroundColour(const wxColour
& colour
)
4536 if (!m_main_win
) return false;
4537 return m_main_win
->SetBackgroundColour(colour
);
4540 bool wxTreeListCtrl::SetForegroundColour(const wxColour
& colour
)
4542 if (!m_main_win
) return false;
4543 return m_main_win
->SetForegroundColour(colour
);
4546 int wxTreeListCtrl::GetColumnCount() const
4547 { return m_main_win
->GetColumnCount(); }
4549 void wxTreeListCtrl::SetColumnWidth(int column
, int width
)
4551 m_header_win
->SetColumnWidth (column
, width
);
4552 m_header_win
->Refresh();
4555 int wxTreeListCtrl::GetColumnWidth(int column
) const
4556 { return m_header_win
->GetColumnWidth(column
); }
4558 void wxTreeListCtrl::SetMainColumn(int column
)
4559 { m_main_win
->SetMainColumn(column
); }
4561 int wxTreeListCtrl::GetMainColumn() const
4562 { return m_main_win
->GetMainColumn(); }
4564 void wxTreeListCtrl::SetColumnText(int column
, const wxString
& text
)
4566 m_header_win
->SetColumnText (column
, text
);
4567 m_header_win
->Refresh();
4570 wxString
wxTreeListCtrl::GetColumnText(int column
) const
4571 { return m_header_win
->GetColumnText(column
); }
4573 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo
& colInfo
)
4575 m_header_win
->AddColumn (colInfo
);
4579 void wxTreeListCtrl::InsertColumn(int before
, const wxTreeListColumnInfo
& colInfo
)
4581 m_header_win
->InsertColumn (before
, colInfo
);
4582 m_header_win
->Refresh();
4585 void wxTreeListCtrl::RemoveColumn(int column
)
4587 m_header_win
->RemoveColumn (column
);
4588 m_header_win
->Refresh();
4591 void wxTreeListCtrl::SetColumn(int column
, const wxTreeListColumnInfo
& colInfo
)
4593 m_header_win
->SetColumn (column
, colInfo
);
4594 m_header_win
->Refresh();
4597 const wxTreeListColumnInfo
& wxTreeListCtrl::GetColumn(int column
) const
4598 { return m_header_win
->GetColumn(column
); }
4600 wxTreeListColumnInfo
& wxTreeListCtrl::GetColumn(int column
)
4601 { return m_header_win
->GetColumn(column
); }
4603 void wxTreeListCtrl::SetColumnImage(int column
, int image
)
4605 m_header_win
->SetColumn (column
, GetColumn(column
).SetImage(image
));
4606 m_header_win
->Refresh();
4609 int wxTreeListCtrl::GetColumnImage(int column
) const
4611 return m_header_win
->GetColumn(column
).GetImage();
4614 void wxTreeListCtrl::SetColumnEditable(int column
, bool shown
)
4616 m_header_win
->SetColumn (column
, GetColumn(column
).SetEditable(shown
));
4619 void wxTreeListCtrl::SetColumnShown(int column
, bool shown
)
4621 wxASSERT_MSG (column
!= GetMainColumn(), _T("The main column may not be hidden") );
4622 m_header_win
->SetColumn (column
, GetColumn(column
).SetShown(GetMainColumn()==column
? true: shown
));
4623 m_header_win
->Refresh();
4626 bool wxTreeListCtrl::IsColumnEditable(int column
) const
4628 return m_header_win
->GetColumn(column
).IsEditable();
4631 bool wxTreeListCtrl::IsColumnShown(int column
) const
4633 return m_header_win
->GetColumn(column
).IsShown();
4636 void wxTreeListCtrl::SetColumnAlignment (int column
, int flag
)
4638 m_header_win
->SetColumn(column
, GetColumn(column
).SetAlignment(flag
));
4639 m_header_win
->Refresh();
4642 int wxTreeListCtrl::GetColumnAlignment(int column
) const
4644 return m_header_win
->GetColumn(column
).GetAlignment();
4647 void wxTreeListCtrl::Refresh(bool erase
, const wxRect
* rect
)
4649 m_main_win
->Refresh (erase
, rect
);
4650 m_header_win
->Refresh (erase
, rect
);
4653 void wxTreeListCtrl::SetFocus()
4654 { m_main_win
->SetFocus(); }
4656 wxSize
wxTreeListCtrl::DoGetBestSize() const
4658 // something is better than nothing...
4659 return wxSize (200,200); // but it should be specified values! FIXME
4662 wxString
wxTreeListCtrl::OnGetItemText( wxTreeItemData
* WXUNUSED(item
), long WXUNUSED(column
)) const
4664 return wxEmptyString
;