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
;
126 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
127 // which col header is currently highlighted with mouse-over
131 void RefreshColLabel(int col
);
135 wxTreeListHeaderWindow();
137 wxTreeListHeaderWindow( wxWindow
*win
,
139 wxTreeListMainWindow
*owner
,
140 const wxPoint
&pos
= wxDefaultPosition
,
141 const wxSize
&size
= wxDefaultSize
,
143 const wxString
&name
= _T("wxtreelistctrlcolumntitles") );
145 virtual ~wxTreeListHeaderWindow();
147 void DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
);
149 void AdjustDC(wxDC
& dc
);
151 void OnPaint( wxPaintEvent
&event
);
152 void OnMouse( wxMouseEvent
&event
);
153 void OnSetFocus( wxFocusEvent
&event
);
155 // total width of all columns
156 int GetWidth() const { return m_total_col_width
; }
158 // column manipulation
159 int GetColumnCount() const { return m_columns
.GetCount(); }
161 void AddColumn (const wxTreeListColumnInfo
& colInfo
);
163 void InsertColumn (int before
, const wxTreeListColumnInfo
& colInfo
);
165 void RemoveColumn (int column
);
167 // column information manipulation
168 const wxTreeListColumnInfo
& GetColumn (int column
) const{
169 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
170 wxInvalidTreeListColumnInfo
, _T("Invalid column"));
171 return m_columns
[column
];
173 wxTreeListColumnInfo
& GetColumn (int column
) {
174 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
175 wxInvalidTreeListColumnInfo
, _T("Invalid column"));
176 return m_columns
[column
];
178 void SetColumn (int column
, const wxTreeListColumnInfo
& info
);
180 wxString
GetColumnText (int column
) const {
181 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
182 wxEmptyString
, _T("Invalid column"));
183 return m_columns
[column
].GetText();
185 void SetColumnText (int column
, const wxString
& text
) {
186 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()),
187 _T("Invalid column"));
188 m_columns
[column
].SetText (text
);
191 int GetColumnAlignment (int column
) const {
192 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
193 wxALIGN_LEFT
, _T("Invalid column"));
194 return m_columns
[column
].GetAlignment();
196 void SetColumnAlignment (int column
, int flag
) {
197 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()),
198 _T("Invalid column"));
199 m_columns
[column
].SetAlignment (flag
);
202 int GetColumnWidth (int column
) const {
203 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
204 -1, _T("Invalid column"));
205 return m_columns
[column
].GetWidth();
207 void SetColumnWidth (int column
, int width
);
209 bool IsColumnEditable (int column
) const {
210 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
211 false, _T("Invalid column"));
212 return m_columns
[column
].IsEditable();
215 bool IsColumnShown (int column
) const {
216 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
217 true, _T("Invalid column"));
218 return m_columns
[column
].IsShown();
225 // common part of all ctors
228 void SendListEvent(wxEventType type
, wxPoint pos
);
230 DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow
)
231 DECLARE_EVENT_TABLE()
235 // this is the "true" control
236 class wxTreeListMainWindow
: public wxScrolledWindow
241 wxTreeListMainWindow() { Init(); }
243 wxTreeListMainWindow (wxTreeListCtrl
*parent
, wxWindowID id
= -1,
244 const wxPoint
& pos
= wxDefaultPosition
,
245 const wxSize
& size
= wxDefaultSize
,
246 long style
= wxTR_DEFAULT_STYLE
,
247 const wxValidator
&validator
= wxDefaultValidator
,
248 const wxString
& name
= _T("wxtreelistmainwindow"))
251 Create (parent
, id
, pos
, size
, style
, validator
, name
);
254 virtual ~wxTreeListMainWindow();
256 bool Create(wxTreeListCtrl
*parent
, wxWindowID id
= -1,
257 const wxPoint
& pos
= wxDefaultPosition
,
258 const wxSize
& size
= wxDefaultSize
,
259 long style
= wxTR_DEFAULT_STYLE
,
260 const wxValidator
&validator
= wxDefaultValidator
,
261 const wxString
& name
= _T("wxtreelistctrl"));
266 // return true if this is a virtual list control
267 bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL
); }
269 // get the total number of items in the control
270 size_t GetCount() const;
272 // indent is the number of pixels the children are indented relative to
273 // the parents position. SetIndent() also redraws the control
275 unsigned int GetIndent() const { return m_indent
; }
276 void SetIndent(unsigned int indent
);
278 // see wxTreeListCtrl for the meaning
279 unsigned int GetLineSpacing() const { return m_linespacing
; }
280 void SetLineSpacing(unsigned int spacing
);
282 // image list: these functions allow to associate an image list with
283 // the control and retrieve it. Note that when assigned with
284 // SetImageList, the control does _not_ delete
285 // the associated image list when it's deleted in order to allow image
286 // lists to be shared between different controls. If you use
287 // AssignImageList, the control _does_ delete the image list.
289 // The normal image list is for the icons which correspond to the
290 // normal tree item state (whether it is selected or not).
291 // Additionally, the application might choose to show a state icon
292 // which corresponds to an app-defined item state (for example,
293 // checked/unchecked) which are taken from the state image list.
294 wxImageList
*GetImageList() const { return m_imageListNormal
; }
295 wxImageList
*GetStateImageList() const { return m_imageListState
; }
296 wxImageList
*GetButtonsImageList() const { return m_imageListButtons
; }
298 void SetImageList(wxImageList
*imageList
);
299 void SetStateImageList(wxImageList
*imageList
);
300 void SetButtonsImageList(wxImageList
*imageList
);
301 void AssignImageList(wxImageList
*imageList
);
302 void AssignStateImageList(wxImageList
*imageList
);
303 void AssignButtonsImageList(wxImageList
*imageList
);
305 // Functions to work with tree ctrl items.
310 // retrieve item's label
311 wxString
GetItemText (const wxTreeItemId
& item
) const
312 { return GetItemText (item
, GetMainColumn()); }
313 wxString
GetItemText (const wxTreeItemId
& item
, int column
) const;
314 wxString
GetItemText (wxTreeItemData
* item
, int column
) const;
316 // get one of the images associated with the item (normal by default)
317 int GetItemImage (const wxTreeItemId
& item
,
318 wxTreeItemIcon which
= wxTreeItemIcon_Normal
) const
319 { return GetItemImage (item
, GetMainColumn(), which
); }
320 int GetItemImage (const wxTreeItemId
& item
, int column
,
321 wxTreeItemIcon which
= wxTreeItemIcon_Normal
) const;
323 // get the data associated with the item
324 wxTreeItemData
*GetItemData(const wxTreeItemId
& item
) const;
326 bool GetItemBold(const wxTreeItemId
& item
) const;
327 wxColour
GetItemTextColour(const wxTreeItemId
& item
) const;
328 wxColour
GetItemBackgroundColour(const wxTreeItemId
& item
) const;
329 wxFont
GetItemFont(const wxTreeItemId
& item
) const;
335 void SetItemText (const wxTreeItemId
& item
, const wxString
& text
)
336 { SetItemText (item
, GetMainColumn(), text
); }
337 void SetItemText (const wxTreeItemId
& item
, int column
, const wxString
& text
);
339 // get one of the images associated with the item (normal by default)
340 void SetItemImage (const wxTreeItemId
& item
, int image
,
341 wxTreeItemIcon which
= wxTreeItemIcon_Normal
)
342 { SetItemImage (item
, GetMainColumn(), image
, which
); }
343 void SetItemImage (const wxTreeItemId
& item
, int column
, int image
,
344 wxTreeItemIcon which
= wxTreeItemIcon_Normal
);
346 // associate some data with the item
347 void SetItemData(const wxTreeItemId
& item
, wxTreeItemData
*data
);
349 // force appearance of [+] button near the item. This is useful to
350 // allow the user to expand the items which don't have any children now
351 // - but instead add them only when needed, thus minimizing memory
352 // usage and loading time.
353 void SetItemHasChildren(const wxTreeItemId
& item
, bool has
= true);
355 // the item will be shown in bold
356 void SetItemBold(const wxTreeItemId
& item
, bool bold
= true);
358 // set the item's text colour
359 void SetItemTextColour(const wxTreeItemId
& item
, const wxColour
& colour
);
361 // set the item's background colour
362 void SetItemBackgroundColour(const wxTreeItemId
& item
, const wxColour
& colour
);
364 // set the item's font (should be of the same height for all items)
365 void SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
);
367 // set the window font
368 virtual bool SetFont( const wxFont
&font
);
370 // set the styles. No need to specify a GetWindowStyle here since
371 // the base wxWindow member function will do it for us
372 void SetWindowStyle(const long styles
);
374 // item status inquiries
375 // ---------------------
377 // is the item visible (it might be outside the view or not expanded)?
378 bool IsVisible(const wxTreeItemId
& item
, bool fullRow
) const;
379 // does the item has any children?
380 bool HasChildren(const wxTreeItemId
& item
) const;
381 // is the item expanded (only makes sense if HasChildren())?
382 bool IsExpanded(const wxTreeItemId
& item
) const;
383 // is this item currently selected (the same as has focus)?
384 bool IsSelected(const wxTreeItemId
& item
) const;
385 // is item text in bold font?
386 bool IsBold(const wxTreeItemId
& item
) const;
387 // does the layout include space for a button?
389 // number of children
390 // ------------------
392 // if 'recursively' is false, only immediate children count, otherwise
393 // the returned number is the number of all items in this branch
394 size_t GetChildrenCount(const wxTreeItemId
& item
, bool recursively
= true);
399 // wxTreeItemId.IsOk() will return false if there is no such item
401 // get the root tree item
402 wxTreeItemId
GetRootItem() const { return m_rootItem
; }
404 // get the item currently selected, only if a single item is selected
405 wxTreeItemId
GetSelection() const { return m_selectItem
; }
407 // get all the items currently selected, return count of items
408 size_t GetSelections(wxArrayTreeItemIds
&) const;
410 // get the parent of this item (may return NULL if root)
411 wxTreeItemId
GetItemParent(const wxTreeItemId
& item
) const;
413 // for this enumeration function you must pass in a "cookie" parameter
414 // which is opaque for the application but is necessary for the library
415 // to make these functions reentrant (i.e. allow more than one
416 // enumeration on one and the same object simultaneously). Of course,
417 // the "cookie" passed to GetFirstChild() and GetNextChild() should be
420 // get child of this item
421 #if !wxCHECK_VERSION(2, 5, 0)
422 wxTreeItemId
GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const;
423 wxTreeItemId
GetNextChild(const wxTreeItemId
& item
, long& cookie
) const;
424 wxTreeItemId
GetPrevChild(const wxTreeItemId
& item
, long& cookie
) const;
425 wxTreeItemId
GetLastChild(const wxTreeItemId
& item
, long& cookie
) const;
427 wxTreeItemId
GetFirstChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
428 wxTreeItemId
GetNextChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
429 wxTreeItemId
GetPrevChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
430 wxTreeItemId
GetLastChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
433 // get sibling of this item
434 wxTreeItemId
GetNextSibling(const wxTreeItemId
& item
) const;
435 wxTreeItemId
GetPrevSibling(const wxTreeItemId
& item
) const;
437 // get item in the full tree (currently only for internal use)
438 wxTreeItemId
GetNext(const wxTreeItemId
& item
, bool fulltree
= true) const;
439 wxTreeItemId
GetPrev(const wxTreeItemId
& item
, bool fulltree
= true) const;
441 // get expanded item, see IsExpanded()
442 wxTreeItemId
GetFirstExpandedItem() const;
443 wxTreeItemId
GetNextExpanded(const wxTreeItemId
& item
) const;
444 wxTreeItemId
GetPrevExpanded(const wxTreeItemId
& item
) const;
446 // get visible item, see IsVisible()
447 wxTreeItemId
GetFirstVisibleItem(bool fullRow
) const;
448 wxTreeItemId
GetNextVisible(const wxTreeItemId
& item
, bool fullRow
) const;
449 wxTreeItemId
GetPrevVisible(const wxTreeItemId
& item
, bool fullRow
) const;
454 // add the root node to the tree
455 wxTreeItemId
AddRoot (const wxString
& text
,
456 int image
= -1, int selectedImage
= -1,
457 wxTreeItemData
*data
= NULL
);
459 // insert a new item in as the first child of the parent
460 wxTreeItemId
PrependItem(const wxTreeItemId
& parent
,
461 const wxString
& text
,
462 int image
= -1, int selectedImage
= -1,
463 wxTreeItemData
*data
= NULL
);
465 // insert a new item after a given one
466 wxTreeItemId
InsertItem(const wxTreeItemId
& parent
,
467 const wxTreeItemId
& idPrevious
,
468 const wxString
& text
,
469 int image
= -1, int selectedImage
= -1,
470 wxTreeItemData
*data
= NULL
);
472 // insert a new item before the one with the given index
473 wxTreeItemId
InsertItem(const wxTreeItemId
& parent
,
475 const wxString
& text
,
476 int image
= -1, int selectedImage
= -1,
477 wxTreeItemData
*data
= NULL
);
479 // insert a new item in as the last child of the parent
480 wxTreeItemId
AppendItem(const wxTreeItemId
& parent
,
481 const wxString
& text
,
482 int image
= -1, int selectedImage
= -1,
483 wxTreeItemData
*data
= NULL
);
485 // delete this item and associated data if any
486 void Delete(const wxTreeItemId
& item
);
487 // delete all children (but don't delete the item itself)
488 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
489 void DeleteChildren(const wxTreeItemId
& item
);
490 // delete the root and all its children from the tree
491 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
495 void Expand(const wxTreeItemId
& item
);
496 // expand this item and all subitems recursively
497 void ExpandAll(const wxTreeItemId
& item
);
498 // collapse the item without removing its children
499 void Collapse(const wxTreeItemId
& item
);
500 // collapse the item and remove all children
501 void CollapseAndReset(const wxTreeItemId
& item
);
502 // toggles the current state
503 void Toggle(const wxTreeItemId
& item
);
505 // remove the selection from currently selected item (if any)
509 void SelectItem(const wxTreeItemId
& item
, const wxTreeItemId
& prev
= (wxTreeItemId
*)NULL
,
510 bool unselect_others
= true);
512 // make sure this item is visible (expanding the parent item and/or
513 // scrolling to this item if necessary)
514 void EnsureVisible(const wxTreeItemId
& item
);
515 // scroll to this item (but don't expand its parent)
516 void ScrollTo(const wxTreeItemId
& item
);
517 void AdjustMyScrollbars();
519 // The first function is more portable (because easier to implement
520 // on other platforms), but the second one returns some extra info.
521 wxTreeItemId
HitTest (const wxPoint
& point
)
522 { int flags
; int column
; return HitTest (point
, flags
, column
); }
523 wxTreeItemId
HitTest (const wxPoint
& point
, int& flags
)
524 { int column
; return HitTest (point
, flags
, column
); }
525 wxTreeItemId
HitTest (const wxPoint
& point
, int& flags
, int& column
);
528 // get the bounding rectangle of the item (or of its label only)
529 bool GetBoundingRect(const wxTreeItemId
& item
,
531 bool textOnly
= false) const;
533 // Start editing the item label: this (temporarily) replaces the item
534 // with a one line edit control. The item will be selected if it hadn't
536 void EditLabel (const wxTreeItemId
& item
, int column
);
539 // this function is called to compare 2 items and should return -1, 0
540 // or +1 if the first item is less than, equal to or greater than the
541 // second one. The base class version performs alphabetic comparaison
542 // of item labels (GetText)
543 virtual int OnCompareItems(const wxTreeItemId
& item1
,
544 const wxTreeItemId
& item2
);
545 // sort the children of this item using OnCompareItems
547 // NB: this function is not reentrant and not MT-safe (FIXME)!
548 void SortChildren(const wxTreeItemId
& item
);
551 wxTreeItemId
FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
= 0);
553 // implementation only from now on
555 // overridden base class virtuals
556 virtual bool SetBackgroundColour(const wxColour
& colour
);
557 virtual bool SetForegroundColour(const wxColour
& colour
);
560 void SetDragItem (const wxTreeItemId
& item
= (wxTreeItemId
*)NULL
);
563 void OnPaint( wxPaintEvent
&event
);
564 void OnSetFocus( wxFocusEvent
&event
);
565 void OnKillFocus( wxFocusEvent
&event
);
566 void OnChar( wxKeyEvent
&event
);
567 void OnMouse( wxMouseEvent
&event
);
568 void OnIdle( wxIdleEvent
&event
);
569 void OnScroll(wxScrollWinEvent
& event
);
571 // implementation helpers
572 void SendDeleteEvent(wxTreeListItem
*itemBeingDeleted
);
574 int GetColumnCount() const
575 { return m_owner
->GetHeaderWindow()->GetColumnCount(); }
577 void SetMainColumn (int column
)
578 { if ((column
>= 0) && (column
< GetColumnCount())) m_main_column
= column
; }
580 int GetMainColumn() const { return m_main_column
; }
582 int GetBestColumnWidth (int column
, wxTreeItemId parent
= wxTreeItemId());
583 int GetItemWidth (int column
, wxTreeListItem
*item
);
584 wxFont
GetItemFont (wxTreeListItem
*item
);
589 wxTreeListCtrl
* m_owner
;
593 friend class wxTreeListItem
;
594 friend class wxTreeListRenameTimer
;
595 friend class wxEditTextCtrl
;
600 wxTreeListItem
*m_rootItem
; // root item
601 wxTreeListItem
*m_curItem
; // current item, either selected or marked
602 wxTreeListItem
*m_shiftItem
; // item, where the shift key was pressed
603 wxTreeListItem
*m_editItem
; // item, which is currently edited
604 wxTreeListItem
*m_selectItem
; // current selected item, not with wxTR_MULTIPLE
608 int m_btnWidth
, m_btnWidth2
;
609 int m_btnHeight
, m_btnHeight2
;
610 int m_imgWidth
, m_imgWidth2
;
611 int m_imgHeight
, m_imgHeight2
;
612 unsigned short m_indent
;
614 unsigned short m_linespacing
;
616 wxBrush
*m_hilightBrush
,
617 *m_hilightUnfocusedBrush
;
622 bool m_ownsImageListNormal
,
623 m_ownsImageListState
,
624 m_ownsImageListButtons
;
625 bool m_isDragging
; // true between BEGIN/END drag events
627 bool m_lastOnSame
; // last click on the same item as prev
628 bool m_left_down_selection
;
630 wxImageList
*m_imageListNormal
,
635 wxTimer
*m_dragTimer
;
636 wxTreeListItem
*m_dragItem
;
638 wxTimer
*m_renameTimer
;
639 wxString m_renameRes
;
642 wxTimer
*m_findTimer
;
645 // the common part of all ctors
649 wxTreeItemId
DoInsertItem(const wxTreeItemId
& parent
,
651 const wxString
& text
,
652 int image
, int selectedImage
,
653 wxTreeItemData
*data
);
654 bool HasButtons(void) const
655 { return (m_imageListButtons
) || HasFlag (wxTR_TWIST_BUTTONS
|wxTR_HAS_BUTTONS
); }
658 void CalculateLineHeight();
659 int GetLineHeight(wxTreeListItem
*item
) const;
660 void PaintLevel( wxTreeListItem
*item
, wxDC
& dc
, int level
, int &y
,
662 void PaintItem( wxTreeListItem
*item
, wxDC
& dc
);
664 void CalculateLevel( wxTreeListItem
*item
, wxDC
&dc
, int level
, int &y
,
666 void CalculatePositions();
667 void CalculateSize( wxTreeListItem
*item
, wxDC
&dc
);
669 void RefreshSubtree (wxTreeListItem
*item
);
670 void RefreshLine (wxTreeListItem
*item
);
672 // redraw all selected items
673 void RefreshSelected();
675 // RefreshSelected() recursive helper
676 void RefreshSelectedUnder (wxTreeListItem
*item
);
678 void OnRenameTimer();
679 void OnRenameAccept();
681 void FillArray(wxTreeListItem
*, wxArrayTreeItemIds
&) const;
682 bool TagAllChildrenUntilLast (wxTreeListItem
*crt_item
, wxTreeListItem
*last_item
);
683 bool TagNextChildren (wxTreeListItem
*crt_item
, wxTreeListItem
*last_item
);
684 void UnselectAllChildren (wxTreeListItem
*item
);
687 DECLARE_EVENT_TABLE()
688 DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow
)
692 // timer used for enabling in-place edit
693 class wxTreeListRenameTimer
: public wxTimer
696 wxTreeListRenameTimer( wxTreeListMainWindow
*owner
);
701 wxTreeListMainWindow
*m_owner
;
704 // control used for in-place edit
705 class wxEditTextCtrl
: public wxTextCtrl
708 wxEditTextCtrl (wxWindow
*parent
,
712 wxTreeListMainWindow
*owner
,
713 const wxString
&value
= wxEmptyString
,
714 const wxPoint
&pos
= wxDefaultPosition
,
715 const wxSize
&size
= wxDefaultSize
,
717 const wxValidator
& validator
= wxDefaultValidator
,
718 const wxString
&name
= wxTextCtrlNameStr
);
720 void OnChar( wxKeyEvent
&event
);
721 void OnKeyUp( wxKeyEvent
&event
);
722 void OnKillFocus( wxFocusEvent
&event
);
727 wxTreeListMainWindow
*m_owner
;
728 wxString m_startValue
;
731 DECLARE_EVENT_TABLE()
739 wxTreeListItem() { m_data
= NULL
; }
740 wxTreeListItem( wxTreeListMainWindow
*owner
,
741 wxTreeListItem
*parent
,
742 const wxArrayString
& text
,
745 wxTreeItemData
*data
);
750 wxArrayTreeListItems
& GetChildren() { return m_children
; }
752 const wxString
GetText() const
756 const wxString
GetText (int column
) const
758 if(m_text
.GetCount() > 0)
760 if( IsVirtual() ) return m_owner
->GetItemText( m_data
, column
);
761 else return m_text
[column
];
763 return wxEmptyString
;
766 int GetImage (wxTreeItemIcon which
= wxTreeItemIcon_Normal
) const
767 { return m_images
[which
]; }
768 int GetImage (int column
, wxTreeItemIcon which
=wxTreeItemIcon_Normal
) const
770 if(column
== m_owner
->GetMainColumn()) return m_images
[which
];
771 if(column
< (int)m_col_images
.GetCount()) return m_col_images
[column
];
775 wxTreeItemData
*GetData() const { return m_data
; }
777 // returns the current image for the item (depending on its
778 // selected/expanded/whatever state)
779 int GetCurrentImage() const;
781 void SetText (const wxString
&text
);
782 void SetText (int column
, const wxString
& text
)
784 if (column
< (int)m_text
.GetCount()) {
785 m_text
[column
] = text
;
786 }else if (column
< m_owner
->GetColumnCount()) {
787 int howmany
= m_owner
->GetColumnCount();
788 for (int i
= m_text
.GetCount(); i
< howmany
; ++i
) m_text
.Add (wxEmptyString
);
789 m_text
[column
] = text
;
792 void SetImage (int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; }
793 void SetImage (int column
, int image
, wxTreeItemIcon which
)
795 if (column
== m_owner
->GetMainColumn()) {
796 m_images
[which
] = image
;
797 }else if (column
< (int)m_col_images
.GetCount()) {
798 m_col_images
[column
] = image
;
799 }else if (column
< m_owner
->GetColumnCount()) {
800 int howmany
= m_owner
->GetColumnCount();
801 for (int i
= m_col_images
.GetCount(); i
< howmany
; ++i
) m_col_images
.Add (NO_IMAGE
);
802 m_col_images
[column
] = image
;
806 void SetData(wxTreeItemData
*data
) { m_data
= data
; }
808 void SetHasPlus(bool has
= true) { m_hasPlus
= has
; }
810 void SetBold(bool bold
) { m_isBold
= bold
; }
812 int GetX() const { return m_x
; }
813 int GetY() const { return m_y
; }
815 void SetX (int x
) { m_x
= x
; }
816 void SetY (int y
) { m_y
= y
; }
818 int GetHeight() const { return m_height
; }
819 int GetWidth() const { return m_width
; }
821 void SetHeight (int height
) { m_height
= height
; }
822 void SetWidth (int width
) { m_width
= width
; }
824 int GetTextX() const { return m_text_x
; }
825 void SetTextX (int text_x
) { m_text_x
= text_x
; }
827 wxTreeListItem
*GetItemParent() const { return m_parent
; }
830 // deletes all children notifying the treectrl about it if !NULL
832 void DeleteChildren(wxTreeListMainWindow
*tree
= NULL
);
834 // get count of all children (and grand children if 'recursively')
835 size_t GetChildrenCount(bool recursively
= true) const;
837 void Insert(wxTreeListItem
*child
, size_t index
)
838 { m_children
.Insert(child
, index
); }
840 void GetSize( int &x
, int &y
, const wxTreeListMainWindow
* );
842 // return the item at given position (or NULL if no item), onButton is
843 // true if the point belongs to the item's button, otherwise it lies
844 // on the button's label
845 wxTreeListItem
*HitTest (const wxPoint
& point
,
846 const wxTreeListMainWindow
*,
847 int &flags
, int& column
, int level
);
849 void Expand() { m_isCollapsed
= false; }
850 void Collapse() { m_isCollapsed
= true; }
852 void SetHilight( bool set
= true ) { m_hasHilight
= set
; }
855 bool HasChildren() const { return !m_children
.IsEmpty(); }
856 bool IsSelected() const { return m_hasHilight
!= 0; }
857 bool IsExpanded() const { return !m_isCollapsed
; }
858 bool HasPlus() const { return m_hasPlus
|| HasChildren(); }
859 bool IsBold() const { return m_isBold
!= 0; }
860 bool IsVirtual() const { return m_owner
->IsVirtual(); }
863 // get them - may be NULL
864 wxTreeItemAttr
*GetAttributes() const { return m_attr
; }
865 // get them ensuring that the pointer is not NULL
866 wxTreeItemAttr
& Attr()
870 m_attr
= new wxTreeItemAttr
;
876 void SetAttributes(wxTreeItemAttr
*attr
)
878 if ( m_ownsAttr
) delete m_attr
;
882 // set them and delete when done
883 void AssignAttributes(wxTreeItemAttr
*attr
)
890 wxTreeListMainWindow
*m_owner
; // control the item belongs to
892 // since there can be very many of these, we save size by chosing
893 // the smallest representation for the elements and by ordering
894 // the members to avoid padding.
895 wxArrayString m_text
; // labels to be rendered for item
897 wxTreeItemData
*m_data
; // user-provided data
899 wxArrayTreeListItems m_children
; // list of children
900 wxTreeListItem
*m_parent
; // parent of this item
902 wxTreeItemAttr
*m_attr
; // attributes???
904 // tree ctrl images for the normal, selected, expanded and
905 // expanded+selected states
906 short m_images
[wxTreeItemIcon_Max
];
907 wxArrayShort m_col_images
; // images for the various columns (!= main)
909 // main column item positions
910 wxCoord m_x
; // (virtual) offset from left (vertical line)
911 wxCoord m_y
; // (virtual) offset from top
912 wxCoord m_text_x
; // item offset from left
913 short m_width
; // width of this item
914 unsigned char m_height
; // height of this item
916 // use bitfields to save size
917 int m_isCollapsed
:1;
918 int m_hasHilight
:1; // same as focused
919 int m_hasPlus
:1; // used for item which doesn't have
920 // children but has a [+] button
921 int m_isBold
:1; // render the label in bold font
922 int m_ownsAttr
:1; // delete attribute when done
925 // ===========================================================================
927 // ===========================================================================
929 // ---------------------------------------------------------------------------
930 // wxTreeListRenameTimer (internal)
931 // ---------------------------------------------------------------------------
933 wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow
*owner
)
938 void wxTreeListRenameTimer::Notify()
940 m_owner
->OnRenameTimer();
943 //-----------------------------------------------------------------------------
944 // wxEditTextCtrl (internal)
945 //-----------------------------------------------------------------------------
947 BEGIN_EVENT_TABLE (wxEditTextCtrl
,wxTextCtrl
)
948 EVT_CHAR (wxEditTextCtrl::OnChar
)
949 EVT_KEY_UP (wxEditTextCtrl::OnKeyUp
)
950 EVT_KILL_FOCUS (wxEditTextCtrl::OnKillFocus
)
953 wxEditTextCtrl::wxEditTextCtrl (wxWindow
*parent
,
957 wxTreeListMainWindow
*owner
,
958 const wxString
&value
,
962 const wxValidator
& validator
,
963 const wxString
&name
)
964 : wxTextCtrl (parent
, id
, value
, pos
, size
, style
|wxSIMPLE_BORDER
, validator
, name
)
970 (*m_res
) = wxEmptyString
;
971 m_startValue
= value
;
975 void wxEditTextCtrl::OnChar( wxKeyEvent
&event
)
977 if (event
.GetKeyCode() == WXK_RETURN
)
980 (*m_res
) = GetValue();
982 if ((*m_res
) != m_startValue
)
983 m_owner
->OnRenameAccept();
985 if (!wxPendingDelete
.Member(this))
986 wxPendingDelete
.Append(this);
989 m_owner
->SetFocus(); // This doesn't work. TODO.
993 if (event
.GetKeyCode() == WXK_ESCAPE
)
996 (*m_res
) = wxEmptyString
;
998 if (!wxPendingDelete
.Member(this))
999 wxPendingDelete
.Append(this);
1002 m_owner
->SetFocus(); // This doesn't work. TODO.
1009 void wxEditTextCtrl::OnKeyUp( wxKeyEvent
&event
)
1017 // auto-grow the textctrl:
1018 wxSize parentSize
= m_owner
->GetSize();
1019 wxPoint myPos
= GetPosition();
1020 wxSize mySize
= GetSize();
1022 GetTextExtent(GetValue() + _T("M"), &sx
, &sy
);
1023 if (myPos
.x
+ sx
> parentSize
.x
) sx
= parentSize
.x
- myPos
.x
;
1024 if (mySize
.x
> sx
) sx
= mySize
.x
;
1030 void wxEditTextCtrl::OnKillFocus( wxFocusEvent
&event
)
1038 if (!wxPendingDelete
.Member(this))
1039 wxPendingDelete
.Append(this);
1042 (*m_res
) = GetValue();
1044 if ((*m_res
) != m_startValue
)
1045 m_owner
->OnRenameAccept();
1048 //-----------------------------------------------------------------------------
1049 // wxTreeListHeaderWindow
1050 //-----------------------------------------------------------------------------
1052 IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow
,wxWindow
);
1054 BEGIN_EVENT_TABLE(wxTreeListHeaderWindow
,wxWindow
)
1055 EVT_PAINT (wxTreeListHeaderWindow::OnPaint
)
1056 EVT_MOUSE_EVENTS (wxTreeListHeaderWindow::OnMouse
)
1057 EVT_SET_FOCUS (wxTreeListHeaderWindow::OnSetFocus
)
1060 void wxTreeListHeaderWindow::Init()
1062 m_currentCursor
= (wxCursor
*) NULL
;
1063 m_isDragging
= false;
1065 m_total_col_width
= 0;
1069 wxTreeListHeaderWindow::wxTreeListHeaderWindow()
1073 m_owner
= (wxTreeListMainWindow
*) NULL
;
1074 m_resizeCursor
= (wxCursor
*) NULL
;
1077 wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow
*win
,
1079 wxTreeListMainWindow
*owner
,
1083 const wxString
&name
)
1084 : wxWindow( win
, id
, pos
, size
, style
, name
)
1089 m_resizeCursor
= new wxCursor(wxCURSOR_SIZEWE
);
1091 #if !wxCHECK_VERSION(2, 5, 0)
1092 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNFACE
));
1094 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE
));
1098 wxTreeListHeaderWindow::~wxTreeListHeaderWindow()
1100 delete m_resizeCursor
;
1103 void wxTreeListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1105 #if !wxCHECK_VERSION(2, 5, 0)
1106 wxPen
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1108 wxPen
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1111 const int m_corner
= 1;
1113 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1114 #if defined( __WXMAC__ )
1117 dc
->SetPen( *wxBLACK_PEN
);
1119 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1120 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1122 #if defined( __WXMAC__ )
1123 pen
= wxPen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1126 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1127 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1129 dc
->SetPen( *wxWHITE_PEN
);
1130 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1131 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1132 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1133 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1136 // shift the DC origin to match the position of the main window horz
1137 // scrollbar: this allows us to always use logical coords
1138 void wxTreeListHeaderWindow::AdjustDC(wxDC
& dc
)
1141 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1143 m_owner
->GetViewStart( &x
, NULL
);
1145 // account for the horz scrollbar offset
1146 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1149 void wxTreeListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1152 wxClientDC
dc( this );
1154 wxPaintDC
dc( this );
1160 int x
= HEADER_OFFSET_X
;
1162 // width and height of the entire header window
1164 GetClientSize( &w
, &h
);
1165 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1166 dc
.SetBackgroundMode(wxTRANSPARENT
);
1168 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1169 int numColumns
= GetColumnCount();
1170 for ( int i
= 0; i
< numColumns
&& x
< w
; i
++ )
1172 if (!IsColumnShown (i
)) continue; // do next column if not shown
1174 wxHeaderButtonParams params
;
1176 // TODO: columnInfo should have label colours...
1177 params
.m_labelColour
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT
);
1178 params
.m_labelFont
= GetFont();
1180 wxTreeListColumnInfo
& column
= GetColumn(i
);
1181 int wCol
= column
.GetWidth();
1183 wxRect
rect(x
, 0, wCol
, h
);
1186 if ( i
== m_hotTrackCol
)
1187 flags
|= wxCONTROL_CURRENT
;
1189 params
.m_labelText
= column
.GetText();
1190 params
.m_labelAlignment
= column
.GetAlignment();
1192 int image
= column
.GetImage();
1193 wxImageList
* imageList
= m_owner
->GetImageList();
1194 if ((image
!= -1) && imageList
)
1195 params
.m_labelBitmap
= imageList
->GetBitmap(image
);
1197 wxRendererNative::Get().DrawHeaderButton(this, dc
, rect
, flags
,
1198 wxHDR_SORT_ICON_NONE
, ¶ms
);
1202 wxRect
rect(x
, 0, w
-x
, h
);
1203 wxRendererNative::Get().DrawHeaderButton(this, dc
, rect
);
1206 #else // not 2.7.0.1+
1208 dc
.SetFont( GetFont() );
1210 // do *not* use the listctrl colour for headers - one day we will have a
1211 // function to set it separately
1212 //dc.SetTextForeground( *wxBLACK );
1213 #if !wxCHECK_VERSION(2, 5, 0)
1214 dc
.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1216 dc
.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT
));
1219 int numColumns
= GetColumnCount();
1220 for ( int i
= 0; i
< numColumns
&& x
< w
; i
++ )
1222 if (!IsColumnShown (i
)) continue; // do next column if not shown
1224 wxTreeListColumnInfo
& column
= GetColumn(i
);
1225 int wCol
= column
.GetWidth();
1227 // the width of the rect to draw: make it smaller to fit entirely
1228 // inside the column rect
1231 #if !wxCHECK_VERSION(2, 7, 0)
1232 dc
.SetPen( *wxWHITE_PEN
);
1233 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1235 wxRect
rect(x
, HEADER_OFFSET_Y
, cw
, h
-2);
1236 wxRendererNative::GetDefault().DrawHeaderButton (this, dc
, rect
);
1239 // if we have an image, draw it on the right of the label
1240 int image
= column
.GetImage(); //item.m_image;
1241 int ix
= -2, iy
= 0;
1242 wxImageList
* imageList
= m_owner
->GetImageList();
1243 if ((image
!= -1) && imageList
) {
1244 imageList
->GetSize (image
, ix
, iy
);
1247 // extra margins around the text label
1250 int image_offset
= cw
- ix
- 1;
1252 switch(column
.GetAlignment()) {
1254 text_x
+= EXTRA_WIDTH
;
1258 dc
.GetTextExtent (column
.GetText(), &text_width
, NULL
);
1259 text_x
+= cw
- text_width
- EXTRA_WIDTH
- MARGIN
;
1262 case wxALIGN_CENTER
:
1263 dc
.GetTextExtent(column
.GetText(), &text_width
, NULL
);
1264 text_x
+= (cw
- text_width
)/2 + ix
+ 2;
1265 image_offset
= (cw
- text_width
- ix
- 2)/2 - MARGIN
;
1270 if ((image
!= -1) && imageList
) {
1271 imageList
->Draw (image
, dc
, x
+ image_offset
/*cw - ix - 1*/,
1272 HEADER_OFFSET_Y
+ (h
- 4 - iy
)/2,
1273 wxIMAGELIST_DRAW_TRANSPARENT
);
1276 // draw the text clipping it so that it doesn't overwrite the column boundary
1277 wxDCClipper
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h
- 4 );
1278 dc
.DrawText (column
.GetText(), text_x
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1284 int more_w
= m_owner
->GetSize().x
- x
- HEADER_OFFSET_X
;
1286 #if !wxCHECK_VERSION(2, 7, 0)
1287 DoDrawRect (&dc
, x
, HEADER_OFFSET_Y
, more_w
, h
-2 );
1289 wxRect
rect (x
, HEADER_OFFSET_Y
, more_w
, h
-2);
1290 wxRendererNative::GetDefault().DrawHeaderButton (this, dc
, rect
);
1296 void wxTreeListHeaderWindow::DrawCurrent()
1298 int x1
= m_currentX
;
1300 ClientToScreen (&x1
, &y1
);
1302 int x2
= m_currentX
-1;
1304 ++x2
; // but why ????
1307 m_owner
->GetClientSize( NULL
, &y2
);
1308 m_owner
->ClientToScreen( &x2
, &y2
);
1311 dc
.SetLogicalFunction (wxINVERT
);
1312 dc
.SetPen (wxPen (*wxBLACK
, 2, wxSOLID
));
1313 dc
.SetBrush (*wxTRANSPARENT_BRUSH
);
1316 dc
.DrawLine (x1
, y1
, x2
, y2
);
1317 dc
.SetLogicalFunction (wxCOPY
);
1318 dc
.SetPen (wxNullPen
);
1319 dc
.SetBrush (wxNullBrush
);
1322 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1323 int wxTreeListHeaderWindow::XToCol(int x
)
1326 int numColumns
= GetColumnCount();
1327 for ( int col
= 0; col
< numColumns
; col
++ )
1329 if (!IsColumnShown(col
)) continue;
1330 wxTreeListColumnInfo
& column
= GetColumn(col
);
1332 if ( x
< (colLeft
+ column
.GetWidth()) )
1335 colLeft
+= column
.GetWidth();
1341 void wxTreeListHeaderWindow::RefreshColLabel(int col
)
1343 if ( col
> GetColumnCount() )
1350 if (!IsColumnShown(idx
)) continue;
1351 wxTreeListColumnInfo
& column
= GetColumn(idx
);
1353 width
= column
.GetWidth();
1354 } while (++idx
<= col
);
1356 m_owner
->CalcScrolledPosition(x
, 0, &x
, NULL
);
1357 RefreshRect(wxRect(x
, 0, width
, GetSize().GetHeight()));
1362 void wxTreeListHeaderWindow::OnMouse (wxMouseEvent
&event
) {
1364 // we want to work with logical coords
1366 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1367 int y
= event
.GetY();
1369 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1370 if ( event
.Moving() )
1372 int col
= XToCol(x
);
1373 if ( col
!= m_hotTrackCol
)
1375 // Refresh the col header so it will be painted with hot tracking
1376 // (if supported by the native renderer.)
1377 RefreshColLabel(col
);
1379 // Also refresh the old hot header
1380 if ( m_hotTrackCol
>= 0 )
1381 RefreshColLabel(m_hotTrackCol
);
1383 m_hotTrackCol
= col
;
1387 if ( event
.Leaving() && m_hotTrackCol
>= 0 )
1389 // Leaving the window so clear any hot tracking indicator that may be present
1390 RefreshColLabel(m_hotTrackCol
);
1397 SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition());
1399 // we don't draw the line beyond our window, but we allow dragging it
1402 GetClientSize( &w
, NULL
);
1403 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1406 // erase the line if it was drawn
1407 if (m_currentX
< w
) DrawCurrent();
1409 if (event
.ButtonUp()) {
1410 m_isDragging
= false;
1411 if (HasCapture()) ReleaseMouse();
1413 SetColumnWidth (m_column
, m_currentX
- m_minX
);
1415 SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition());
1417 m_currentX
= wxMax (m_minX
+ 7, x
);
1419 // draw in the new location
1420 if (m_currentX
< w
) DrawCurrent();
1423 }else{ // not dragging
1426 bool hit_border
= false;
1428 // end of the current column
1431 // find the column where this event occured
1432 int countCol
= GetColumnCount();
1433 for (int column
= 0; column
< countCol
; column
++) {
1434 if (!IsColumnShown (column
)) continue; // do next if not shown
1436 xpos
+= GetColumnWidth (column
);
1438 if ((abs (x
-xpos
) < 3) && (y
< 22)) {
1439 // near the column border
1445 // inside the column
1452 if (event
.LeftDown() || event
.RightUp()) {
1453 if (hit_border
&& event
.LeftDown()) {
1454 m_isDragging
= true;
1458 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, event
.GetPosition());
1459 }else{ // click on a column
1460 wxEventType evt
= event
.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK
:
1461 wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
;
1462 SendListEvent (evt
, event
.GetPosition());
1464 }else if (event
.LeftDClick() && hit_border
) {
1465 SetColumnWidth (m_column
, m_owner
->GetBestColumnWidth (m_column
));
1468 }else if (event
.Moving()) {
1471 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
1472 m_currentCursor
= m_resizeCursor
;
1474 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
1475 m_currentCursor
= wxSTANDARD_CURSOR
;
1477 if (setCursor
) SetCursor (*m_currentCursor
);
1483 void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent
&WXUNUSED(event
)) {
1484 m_owner
->SetFocus();
1487 void wxTreeListHeaderWindow::SendListEvent (wxEventType type
, wxPoint pos
) {
1488 wxWindow
*parent
= GetParent();
1489 wxListEvent
le (type
, parent
->GetId());
1490 le
.SetEventObject (parent
);
1491 le
.m_pointDrag
= pos
;
1493 // the position should be relative to the parent window, not
1494 // this one for compatibility with MSW and common sense: the
1495 // user code doesn't know anything at all about this header
1496 // window, so why should it get positions relative to it?
1497 le
.m_pointDrag
.y
-= GetSize().y
;
1498 le
.m_col
= m_column
;
1499 parent
->GetEventHandler()->ProcessEvent (le
);
1502 void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo
& colInfo
) {
1503 m_columns
.Add (colInfo
);
1504 m_total_col_width
+= colInfo
.GetWidth();
1505 m_owner
->AdjustMyScrollbars();
1506 m_owner
->m_dirty
= true;
1509 void wxTreeListHeaderWindow::SetColumnWidth (int column
, int width
) {
1510 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()), _T("Invalid column"));
1511 m_total_col_width
-= m_columns
[column
].GetWidth();
1512 m_columns
[column
].SetWidth(width
);
1513 m_total_col_width
+= width
;
1514 m_owner
->AdjustMyScrollbars();
1515 m_owner
->m_dirty
= true;
1518 void wxTreeListHeaderWindow::InsertColumn (int before
, const wxTreeListColumnInfo
& colInfo
) {
1519 wxCHECK_RET ((before
>= 0) && (before
< GetColumnCount()), _T("Invalid column"));
1520 m_columns
.Insert (colInfo
, before
);
1521 m_total_col_width
+= colInfo
.GetWidth();
1522 m_owner
->AdjustMyScrollbars();
1523 m_owner
->m_dirty
= true;
1526 void wxTreeListHeaderWindow::RemoveColumn (int column
) {
1527 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()), _T("Invalid column"));
1528 m_total_col_width
-= m_columns
[column
].GetWidth();
1529 m_columns
.RemoveAt (column
);
1530 m_owner
->AdjustMyScrollbars();
1531 m_owner
->m_dirty
= true;
1534 void wxTreeListHeaderWindow::SetColumn (int column
, const wxTreeListColumnInfo
& info
) {
1535 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()), _T("Invalid column"));
1536 int w
= m_columns
[column
].GetWidth();
1537 m_columns
[column
] = info
;
1538 if (w
!= info
.GetWidth()) {
1539 m_total_col_width
+= info
.GetWidth() - w
;
1540 m_owner
->AdjustMyScrollbars();
1542 m_owner
->m_dirty
= true;
1545 // ---------------------------------------------------------------------------
1547 // ---------------------------------------------------------------------------
1549 wxTreeListItem::wxTreeListItem (wxTreeListMainWindow
*owner
,
1550 wxTreeListItem
*parent
,
1551 const wxArrayString
& text
,
1552 int image
, int selImage
,
1553 wxTreeItemData
*data
)
1556 m_images
[wxTreeItemIcon_Normal
] = image
;
1557 m_images
[wxTreeItemIcon_Selected
] = selImage
;
1558 m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
;
1559 m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
;
1566 m_isCollapsed
= true;
1567 m_hasHilight
= false;
1574 m_attr
= (wxTreeItemAttr
*)NULL
;
1577 // We don't know the height here yet.
1582 wxTreeListItem::~wxTreeListItem() {
1584 if (m_ownsAttr
) delete m_attr
;
1586 wxASSERT_MSG( m_children
.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1589 void wxTreeListItem::DeleteChildren (wxTreeListMainWindow
*tree
) {
1590 size_t count
= m_children
.Count();
1591 for (size_t n
= 0; n
< count
; n
++) {
1592 wxTreeListItem
*child
= m_children
[n
];
1594 tree
->SendDeleteEvent (child
);
1595 if (tree
->m_selectItem
== child
) tree
->m_selectItem
= (wxTreeListItem
*)NULL
;
1597 child
->DeleteChildren (tree
);
1603 void wxTreeListItem::SetText (const wxString
&text
) {
1604 if (m_text
.GetCount() > 0) {
1611 size_t wxTreeListItem::GetChildrenCount (bool recursively
) const {
1612 size_t count
= m_children
.Count();
1613 if (!recursively
) return count
;
1615 size_t total
= count
;
1616 for (size_t n
= 0; n
< count
; ++n
) {
1617 total
+= m_children
[n
]->GetChildrenCount();
1622 void wxTreeListItem::GetSize (int &x
, int &y
, const wxTreeListMainWindow
*theButton
) {
1623 int bottomY
= m_y
+ theButton
->GetLineHeight (this);
1624 if (y
< bottomY
) y
= bottomY
;
1625 int width
= m_x
+ m_width
;
1626 if ( x
< width
) x
= width
;
1629 size_t count
= m_children
.Count();
1630 for (size_t n
= 0; n
< count
; ++n
) {
1631 m_children
[n
]->GetSize (x
, y
, theButton
);
1636 wxTreeListItem
*wxTreeListItem::HitTest (const wxPoint
& point
,
1637 const wxTreeListMainWindow
*theCtrl
,
1638 int &flags
, int& column
, int level
) {
1640 // for a hidden root node, don't evaluate it, but do evaluate children
1641 if (!theCtrl
->HasFlag(wxTR_HIDE_ROOT
) || (level
> 0)) {
1643 // reset any previous hit infos
1646 wxTreeListHeaderWindow
* header_win
= theCtrl
->m_owner
->GetHeaderWindow();
1648 // check for right of all columns (outside)
1649 if (point
.x
> header_win
->GetWidth()) return (wxTreeListItem
*) NULL
;
1651 // evaluate if y-pos is okay
1652 int h
= theCtrl
->GetLineHeight (this);
1653 if ((point
.y
>= m_y
) && (point
.y
<= m_y
+ h
)) {
1655 int maincol
= theCtrl
->GetMainColumn();
1657 // check for above/below middle
1658 int y_mid
= m_y
+ h
/2;
1659 if (point
.y
< y_mid
) {
1660 flags
|= wxTREE_HITTEST_ONITEMUPPERPART
;
1662 flags
|= wxTREE_HITTEST_ONITEMLOWERPART
;
1665 // check for button hit
1666 if (HasPlus() && theCtrl
->HasButtons()) {
1667 int bntX
= m_x
- theCtrl
->m_btnWidth2
;
1668 int bntY
= y_mid
- theCtrl
->m_btnHeight2
;
1669 if ((point
.x
>= bntX
) && (point
.x
<= (bntX
+ theCtrl
->m_btnWidth
)) &&
1670 (point
.y
>= bntY
) && (point
.y
<= (bntY
+ theCtrl
->m_btnHeight
))) {
1671 flags
|= wxTREE_HITTEST_ONITEMBUTTON
;
1677 // check for image hit
1678 if (theCtrl
->m_imgWidth
> 0) {
1679 int imgX
= m_text_x
- theCtrl
->m_imgWidth
- MARGIN
;
1680 int imgY
= y_mid
- theCtrl
->m_imgHeight2
;
1681 if ((point
.x
>= imgX
) && (point
.x
<= (imgX
+ theCtrl
->m_imgWidth
)) &&
1682 (point
.y
>= imgY
) && (point
.y
<= (imgY
+ theCtrl
->m_imgHeight
))) {
1683 flags
|= wxTREE_HITTEST_ONITEMICON
;
1689 // check for label hit
1690 if ((point
.x
>= m_text_x
) && (point
.x
<= (m_text_x
+ m_width
))) {
1691 flags
|= wxTREE_HITTEST_ONITEMLABEL
;
1696 // check for indent hit after button and image hit
1697 if (point
.x
< m_x
) {
1698 flags
|= wxTREE_HITTEST_ONITEMINDENT
;
1699 column
= -1; // considered not belonging to main column
1703 // check for right of label
1705 for (int i
= 0; i
<= maincol
; ++i
) end
+= header_win
->GetColumnWidth (i
);
1706 if ((point
.x
> (m_text_x
+ m_width
)) && (point
.x
<= end
)) {
1707 flags
|= wxTREE_HITTEST_ONITEMRIGHT
;
1708 column
= -1; // considered not belonging to main column
1712 // else check for each column except main
1714 for (int j
= 0; j
< theCtrl
->GetColumnCount(); ++j
) {
1715 if (!header_win
->IsColumnShown(j
)) continue;
1716 int w
= header_win
->GetColumnWidth (j
);
1717 if ((j
!= maincol
) && (point
.x
>= x
&& point
.x
< x
+w
)) {
1718 flags
|= wxTREE_HITTEST_ONITEMCOLUMN
;
1725 // no special flag or column found
1730 // if children not expanded, return no item
1731 if (!IsExpanded()) return (wxTreeListItem
*) NULL
;
1734 // in any case evaluate children
1735 wxTreeListItem
*child
;
1736 size_t count
= m_children
.Count();
1737 for (size_t n
= 0; n
< count
; n
++) {
1738 child
= m_children
[n
]->HitTest (point
, theCtrl
, flags
, column
, level
+1);
1739 if (child
) return child
;
1743 return (wxTreeListItem
*) NULL
;
1746 int wxTreeListItem::GetCurrentImage() const {
1747 int image
= NO_IMAGE
;
1750 image
= GetImage (wxTreeItemIcon_SelectedExpanded
);
1752 image
= GetImage (wxTreeItemIcon_Expanded
);
1754 }else{ // not expanded
1756 image
= GetImage (wxTreeItemIcon_Selected
);
1758 image
= GetImage (wxTreeItemIcon_Normal
);
1762 // maybe it doesn't have the specific image, try the default one instead
1763 if (image
== NO_IMAGE
) image
= GetImage();
1768 // ---------------------------------------------------------------------------
1769 // wxTreeListMainWindow implementation
1770 // ---------------------------------------------------------------------------
1772 IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow
, wxScrolledWindow
)
1774 BEGIN_EVENT_TABLE(wxTreeListMainWindow
, wxScrolledWindow
)
1775 EVT_PAINT (wxTreeListMainWindow::OnPaint
)
1776 EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse
)
1777 EVT_CHAR (wxTreeListMainWindow::OnChar
)
1778 EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus
)
1779 EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus
)
1780 EVT_IDLE (wxTreeListMainWindow::OnIdle
)
1781 EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll
)
1785 // ---------------------------------------------------------------------------
1786 // construction/destruction
1787 // ---------------------------------------------------------------------------
1789 void wxTreeListMainWindow::Init() {
1791 m_rootItem
= (wxTreeListItem
*)NULL
;
1792 m_curItem
= (wxTreeListItem
*)NULL
;
1793 m_shiftItem
= (wxTreeListItem
*)NULL
;
1794 m_editItem
= (wxTreeListItem
*)NULL
;
1795 m_selectItem
= (wxTreeListItem
*)NULL
;
1797 m_curColumn
= -1; // no current column
1802 m_lineHeight
= LINEHEIGHT
;
1803 m_indent
= MININDENT
; // min. indent
1806 #if !wxCHECK_VERSION(2, 5, 0)
1807 m_hilightBrush
= new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
1808 m_hilightUnfocusedBrush
= new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW
), wxSOLID
);
1810 m_hilightBrush
= new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
1811 m_hilightUnfocusedBrush
= new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW
), wxSOLID
);
1814 m_imageListNormal
= (wxImageList
*) NULL
;
1815 m_imageListButtons
= (wxImageList
*) NULL
;
1816 m_imageListState
= (wxImageList
*) NULL
;
1817 m_ownsImageListNormal
= m_ownsImageListButtons
=
1818 m_ownsImageListState
= false;
1820 m_imgWidth
= 0, m_imgWidth2
= 0;
1821 m_imgHeight
= 0, m_imgHeight2
= 0;
1822 m_btnWidth
= 0, m_btnWidth2
= 0;
1823 m_btnHeight
= 0, m_btnHeight2
= 0;
1826 m_isDragging
= false;
1827 m_dragTimer
= new wxTimer (this, -1);
1828 m_dragItem
= (wxTreeListItem
*)NULL
;
1830 m_renameTimer
= new wxTreeListRenameTimer (this);
1831 m_lastOnSame
= false;
1832 m_left_down_selection
= false;
1834 m_findTimer
= new wxTimer (this, -1);
1836 #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
1837 m_normalFont
.MacCreateThemeFont (kThemeViewsFont
);
1839 m_normalFont
= wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT
);
1841 m_boldFont
= wxFont( m_normalFont
.GetPointSize(),
1842 m_normalFont
.GetFamily(),
1843 m_normalFont
.GetStyle(),
1845 m_normalFont
.GetUnderlined(),
1846 m_normalFont
.GetFaceName(),
1847 m_normalFont
.GetEncoding());
1850 bool wxTreeListMainWindow::Create (wxTreeListCtrl
*parent
,
1855 const wxValidator
&validator
,
1856 const wxString
& name
) {
1859 if (style
& wxTR_HAS_BUTTONS
) style
|= wxTR_MAC_BUTTONS
;
1860 if (style
& wxTR_HAS_BUTTONS
) style
&= ~wxTR_HAS_BUTTONS
;
1861 style
&= ~wxTR_LINES_AT_ROOT
;
1862 style
|= wxTR_NO_LINES
;
1865 wxGetOsVersion( &major
, &minor
);
1866 if (major
< 10) style
|= wxTR_ROW_LINES
;
1869 wxScrolledWindow::Create (parent
, id
, pos
, size
, style
|wxHSCROLL
|wxVSCROLL
, name
);
1871 #if wxUSE_VALIDATORS
1872 SetValidator(validator
);
1875 #if !wxCHECK_VERSION(2, 5, 0)
1876 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX
));
1878 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX
));
1886 bdc
.SelectObject(bmp
);
1887 bdc
.SetPen(*wxGREY_PEN
);
1888 bdc
.DrawRectangle(-1, -1, 10, 10);
1889 for (i
= 0; i
< 8; i
++) {
1890 for (j
= 0; j
< 8; j
++) {
1891 if (!((i
+ j
) & 1)) {
1892 bdc
.DrawPoint(i
, j
);
1897 m_dottedPen
= wxPen(bmp
, 1);
1900 //? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86
1901 m_dottedPen
= wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
1910 wxTreeListMainWindow::~wxTreeListMainWindow() {
1911 delete m_hilightBrush
;
1912 delete m_hilightUnfocusedBrush
;
1915 delete m_renameTimer
;
1917 if (m_ownsImageListNormal
) delete m_imageListNormal
;
1918 if (m_ownsImageListState
) delete m_imageListState
;
1919 if (m_ownsImageListButtons
) delete m_imageListButtons
;
1925 //-----------------------------------------------------------------------------
1927 //-----------------------------------------------------------------------------
1929 size_t wxTreeListMainWindow::GetCount() const {
1930 return m_rootItem
== NULL
? 0: m_rootItem
->GetChildrenCount();
1933 void wxTreeListMainWindow::SetIndent (unsigned int indent
) {
1934 m_indent
= wxMax ((unsigned)MININDENT
, indent
);
1938 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing
) {
1939 m_linespacing
= spacing
;
1941 CalculateLineHeight();
1944 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId
& item
,
1946 wxCHECK_MSG (item
.IsOk(), 0u, _T("invalid tree item"));
1947 return ((wxTreeListItem
*)item
.m_pItem
)->GetChildrenCount (recursively
);
1950 void wxTreeListMainWindow::SetWindowStyle (const long styles
) {
1951 // right now, just sets the styles. Eventually, we may
1952 // want to update the inherited styles, but right now
1953 // none of the parents has updatable styles
1954 m_windowStyle
= styles
;
1958 //-----------------------------------------------------------------------------
1959 // functions to work with tree items
1960 //-----------------------------------------------------------------------------
1962 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId
& item
, int column
,
1963 wxTreeItemIcon which
) const {
1964 wxCHECK_MSG (item
.IsOk(), -1, _T("invalid tree item"));
1965 return ((wxTreeListItem
*) item
.m_pItem
)->GetImage (column
, which
);
1968 wxTreeItemData
*wxTreeListMainWindow::GetItemData (const wxTreeItemId
& item
) const {
1969 wxCHECK_MSG (item
.IsOk(), NULL
, _T("invalid tree item"));
1970 return ((wxTreeListItem
*) item
.m_pItem
)->GetData();
1973 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId
& item
) const {
1974 wxCHECK_MSG(item
.IsOk(), false, _T("invalid tree item"));
1975 return ((wxTreeListItem
*)item
.m_pItem
)->IsBold();
1978 wxColour
wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId
& item
) const {
1979 wxCHECK_MSG (item
.IsOk(), wxNullColour
, _T("invalid tree item"));
1980 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1981 return pItem
->Attr().GetTextColour();
1984 wxColour
wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId
& item
) const {
1985 wxCHECK_MSG (item
.IsOk(), wxNullColour
, _T("invalid tree item"));
1986 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1987 return pItem
->Attr().GetBackgroundColour();
1990 wxFont
wxTreeListMainWindow::GetItemFont (const wxTreeItemId
& item
) const {
1991 wxCHECK_MSG (item
.IsOk(), wxNullFont
, _T("invalid tree item"));
1992 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
1993 return pItem
->Attr().GetFont();
1996 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId
& item
, int column
,
1997 int image
, wxTreeItemIcon which
) {
1998 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
1999 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2000 pItem
->SetImage (column
, image
, which
);
2001 wxClientDC
dc (this);
2002 CalculateSize (pItem
, dc
);
2003 RefreshLine (pItem
);
2006 void wxTreeListMainWindow::SetItemData (const wxTreeItemId
& item
,
2007 wxTreeItemData
*data
) {
2008 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2009 ((wxTreeListItem
*) item
.m_pItem
)->SetData(data
);
2012 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId
& item
,
2014 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2015 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2016 pItem
->SetHasPlus (has
);
2017 RefreshLine (pItem
);
2020 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId
& item
, bool bold
) {
2021 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2022 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2023 if (pItem
->IsBold() != bold
) { // avoid redrawing if no real change
2024 pItem
->SetBold (bold
);
2025 RefreshLine (pItem
);
2029 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId
& item
,
2030 const wxColour
& colour
) {
2031 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2032 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2033 pItem
->Attr().SetTextColour (colour
);
2034 RefreshLine (pItem
);
2037 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId
& item
,
2038 const wxColour
& colour
) {
2039 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2040 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2041 pItem
->Attr().SetBackgroundColour (colour
);
2042 RefreshLine (pItem
);
2045 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId
& item
,
2046 const wxFont
& font
) {
2047 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2048 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2049 pItem
->Attr().SetFont (font
);
2050 RefreshLine (pItem
);
2053 bool wxTreeListMainWindow::SetFont (const wxFont
&font
) {
2054 wxScrolledWindow::SetFont (font
);
2055 m_normalFont
= font
;
2056 m_boldFont
= wxFont (m_normalFont
.GetPointSize(),
2057 m_normalFont
.GetFamily(),
2058 m_normalFont
.GetStyle(),
2060 m_normalFont
.GetUnderlined(),
2061 m_normalFont
.GetFaceName());
2062 CalculateLineHeight();
2067 // ----------------------------------------------------------------------------
2068 // item status inquiries
2069 // ----------------------------------------------------------------------------
2071 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId
& item
, bool fullRow
) const {
2072 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2074 // An item is only visible if it's not a descendant of a collapsed item
2075 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2076 wxTreeListItem
* parent
= pItem
->GetItemParent();
2078 if (parent
== m_rootItem
&& HasFlag(wxTR_HIDE_ROOT
)) break;
2079 if (!parent
->IsExpanded()) return false;
2080 parent
= parent
->GetItemParent();
2083 wxSize clientSize
= GetClientSize();
2085 if ((!GetBoundingRect (item
, rect
)) ||
2086 ((!fullRow
&& rect
.GetWidth() == 0) || rect
.GetHeight() == 0) ||
2087 (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) ||
2088 (!fullRow
&& (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
))) return false;
2093 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId
& item
) const {
2094 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2096 // consider that the item does have children if it has the "+" button: it
2097 // might not have them (if it had never been expanded yet) but then it
2098 // could have them as well and it's better to err on this side rather than
2099 // disabling some operations which are restricted to the items with
2100 // children for an item which does have them
2101 return ((wxTreeListItem
*) item
.m_pItem
)->HasPlus();
2104 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId
& item
) const {
2105 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2106 return ((wxTreeListItem
*) item
.m_pItem
)->IsExpanded();
2109 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId
& item
) const {
2110 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2111 return ((wxTreeListItem
*) item
.m_pItem
)->IsSelected();
2114 bool wxTreeListMainWindow::IsBold (const wxTreeItemId
& item
) const {
2115 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2116 return ((wxTreeListItem
*) item
.m_pItem
)->IsBold();
2119 // ----------------------------------------------------------------------------
2121 // ----------------------------------------------------------------------------
2123 wxTreeItemId
wxTreeListMainWindow::GetItemParent (const wxTreeItemId
& item
) const {
2124 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2125 return ((wxTreeListItem
*) item
.m_pItem
)->GetItemParent();
2128 #if !wxCHECK_VERSION(2, 5, 0)
2129 wxTreeItemId
wxTreeListMainWindow::GetFirstChild (const wxTreeItemId
& item
,
2130 long& cookie
) const {
2132 wxTreeItemId
wxTreeListMainWindow::GetFirstChild (const wxTreeItemId
& item
,
2133 wxTreeItemIdValue
& cookie
) const {
2135 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2136 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2138 return (!children
.IsEmpty())? wxTreeItemId(children
.Item(0)): wxTreeItemId();
2141 #if !wxCHECK_VERSION(2, 5, 0)
2142 wxTreeItemId
wxTreeListMainWindow::GetNextChild (const wxTreeItemId
& item
,
2143 long& cookie
) const {
2145 wxTreeItemId
wxTreeListMainWindow::GetNextChild (const wxTreeItemId
& item
,
2146 wxTreeItemIdValue
& cookie
) const {
2148 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2149 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2150 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2151 long *pIndex
= ((long*)&cookie
);
2152 return ((*pIndex
)+1 < (long)children
.Count())? wxTreeItemId(children
.Item(++(*pIndex
))): wxTreeItemId();
2155 #if !wxCHECK_VERSION(2, 5, 0)
2156 wxTreeItemId
wxTreeListMainWindow::GetPrevChild (const wxTreeItemId
& item
,
2157 long& cookie
) const {
2159 wxTreeItemId
wxTreeListMainWindow::GetPrevChild (const wxTreeItemId
& item
,
2160 wxTreeItemIdValue
& cookie
) const {
2162 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2163 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2164 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2165 long *pIndex
= (long*)&cookie
;
2166 return ((*pIndex
)-1 >= 0)? wxTreeItemId(children
.Item(--(*pIndex
))): wxTreeItemId();
2169 #if !wxCHECK_VERSION(2, 5, 0)
2170 wxTreeItemId
wxTreeListMainWindow::GetLastChild (const wxTreeItemId
& item
,
2171 long& cookie
) const {
2173 wxTreeItemId
wxTreeListMainWindow::GetLastChild (const wxTreeItemId
& item
,
2174 wxTreeItemIdValue
& cookie
) const {
2176 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2177 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2178 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2179 long *pIndex
= ((long*)&cookie
);
2180 (*pIndex
) = children
.Count();
2181 return (!children
.IsEmpty())? wxTreeItemId(children
.Last()): wxTreeItemId();
2184 wxTreeItemId
wxTreeListMainWindow::GetNextSibling (const wxTreeItemId
& item
) const {
2185 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2188 wxTreeListItem
*i
= (wxTreeListItem
*) item
.m_pItem
;
2189 wxTreeListItem
*parent
= i
->GetItemParent();
2190 if (!parent
) return wxTreeItemId(); // root item doesn't have any siblings
2193 wxArrayTreeListItems
& siblings
= parent
->GetChildren();
2194 size_t index
= siblings
.Index (i
);
2195 wxASSERT (index
!= (size_t)wxNOT_FOUND
); // I'm not a child of my parent?
2196 return (index
< siblings
.Count()-1)? wxTreeItemId(siblings
[index
+1]): wxTreeItemId();
2199 wxTreeItemId
wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId
& item
) const {
2200 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2203 wxTreeListItem
*i
= (wxTreeListItem
*) item
.m_pItem
;
2204 wxTreeListItem
*parent
= i
->GetItemParent();
2205 if (!parent
) return wxTreeItemId(); // root item doesn't have any siblings
2208 wxArrayTreeListItems
& siblings
= parent
->GetChildren();
2209 size_t index
= siblings
.Index(i
);
2210 wxASSERT (index
!= (size_t)wxNOT_FOUND
); // I'm not a child of my parent?
2211 return (index
>= 1)? wxTreeItemId(siblings
[index
-1]): wxTreeItemId();
2214 // Only for internal use right now, but should probably be public
2215 wxTreeItemId
wxTreeListMainWindow::GetNext (const wxTreeItemId
& item
, bool fulltree
) const {
2216 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2218 // if there are any children, return first child
2219 if (fulltree
|| ((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) {
2220 wxArrayTreeListItems
& children
= ((wxTreeListItem
*)item
.m_pItem
)->GetChildren();
2221 if (children
.GetCount() > 0) return children
.Item (0);
2224 // get sibling of this item or of the ancestors instead
2226 wxTreeItemId parent
= item
;
2228 next
= GetNextSibling (parent
);
2229 parent
= GetItemParent (parent
);
2230 } while (!next
.IsOk() && parent
.IsOk());
2234 // Only for internal use right now, but should probably be public
2235 wxTreeItemId
wxTreeListMainWindow::GetPrev (const wxTreeItemId
& item
, bool fulltree
) const {
2236 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2238 // if there are any children, return last child
2239 if (fulltree
|| ((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) {
2240 wxArrayTreeListItems
& children
= ((wxTreeListItem
*)item
.m_pItem
)->GetChildren();
2241 if (children
.GetCount() > 0) return children
.Item (children
.GetCount()-1);
2244 // get sibling of this item or of the ancestors instead
2246 wxTreeItemId parent
= item
;
2248 next
= GetPrevSibling (parent
);
2249 parent
= GetItemParent (parent
);
2250 } while (!next
.IsOk() && parent
.IsOk());
2254 wxTreeItemId
wxTreeListMainWindow::GetFirstExpandedItem() const {
2255 return GetNextExpanded (GetRootItem());
2258 wxTreeItemId
wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId
& item
) const {
2259 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2260 return GetNext (item
, false);
2263 wxTreeItemId
wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId
& item
) const {
2264 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2265 return GetPrev (item
, false);
2268 wxTreeItemId
wxTreeListMainWindow::GetFirstVisibleItem (bool fullRow
) const {
2269 return GetNextVisible (GetRootItem(), fullRow
);
2272 wxTreeItemId
wxTreeListMainWindow::GetNextVisible (const wxTreeItemId
& item
, bool fullRow
) const {
2273 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2274 wxTreeItemId id
= GetNext (item
, false);
2276 if (IsVisible (id
, fullRow
)) return id
;
2277 id
= GetNext (id
, false);
2279 return wxTreeItemId();
2282 wxTreeItemId
wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId
& item
, bool fullRow
) const {
2283 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2284 wxTreeItemId id
= GetPrev (item
, true);
2286 if (IsVisible (id
, fullRow
)) return id
;
2287 id
= GetPrev(id
, true);
2289 return wxTreeItemId();
2292 // ----------------------------------------------------------------------------
2294 // ----------------------------------------------------------------------------
2296 wxTreeItemId
wxTreeListMainWindow::DoInsertItem (const wxTreeItemId
& parentId
,
2298 const wxString
& text
,
2299 int image
, int selImage
,
2300 wxTreeItemData
*data
) {
2301 wxTreeListItem
*parent
= (wxTreeListItem
*)parentId
.m_pItem
;
2302 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2303 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2306 arr
.Alloc (GetColumnCount());
2307 for (int i
= 0; i
< (int)GetColumnCount(); ++i
) arr
.Add (wxEmptyString
);
2308 arr
[m_main_column
] = text
;
2309 wxTreeListItem
*item
= new wxTreeListItem (this, parent
, arr
, image
, selImage
, data
);
2311 #if !wxCHECK_VERSION(2, 5, 0)
2312 data
->SetId ((long)item
);
2317 parent
->Insert (item
, previous
);
2322 wxTreeItemId
wxTreeListMainWindow::AddRoot (const wxString
& text
,
2323 int image
, int selImage
,
2324 wxTreeItemData
*data
) {
2325 wxCHECK_MSG(!m_rootItem
, wxTreeItemId(), _T("tree can have only one root"));
2326 wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2327 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2330 arr
.Alloc (GetColumnCount());
2331 for (int i
= 0; i
< (int)GetColumnCount(); ++i
) arr
.Add (wxEmptyString
);
2332 arr
[m_main_column
] = text
;
2333 m_rootItem
= new wxTreeListItem (this, (wxTreeListItem
*)NULL
, arr
, image
, selImage
, data
);
2335 #if !wxCHECK_VERSION(2, 5, 0)
2336 data
->SetId((long)m_rootItem
);
2338 data
->SetId(m_rootItem
);
2341 if (HasFlag(wxTR_HIDE_ROOT
)) {
2342 // if we will hide the root, make sure children are visible
2343 m_rootItem
->SetHasPlus();
2344 m_rootItem
->Expand();
2345 #if !wxCHECK_VERSION(2, 5, 0)
2348 wxTreeItemIdValue cookie
= 0;
2350 m_curItem
= (wxTreeListItem
*)GetFirstChild (m_rootItem
, cookie
).m_pItem
;
2355 wxTreeItemId
wxTreeListMainWindow::PrependItem (const wxTreeItemId
& parent
,
2356 const wxString
& text
,
2357 int image
, int selImage
,
2358 wxTreeItemData
*data
) {
2359 return DoInsertItem (parent
, 0u, text
, image
, selImage
, data
);
2362 wxTreeItemId
wxTreeListMainWindow::InsertItem (const wxTreeItemId
& parentId
,
2363 const wxTreeItemId
& idPrevious
,
2364 const wxString
& text
,
2365 int image
, int selImage
,
2366 wxTreeItemData
*data
) {
2367 wxTreeListItem
*parent
= (wxTreeListItem
*)parentId
.m_pItem
;
2368 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2370 int index
= parent
->GetChildren().Index((wxTreeListItem
*) idPrevious
.m_pItem
);
2371 wxASSERT_MSG( index
!= wxNOT_FOUND
,
2372 _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
2374 return DoInsertItem (parentId
, ++index
, text
, image
, selImage
, data
);
2377 wxTreeItemId
wxTreeListMainWindow::InsertItem (const wxTreeItemId
& parentId
,
2379 const wxString
& text
,
2380 int image
, int selImage
,
2381 wxTreeItemData
*data
) {
2382 wxTreeListItem
*parent
= (wxTreeListItem
*)parentId
.m_pItem
;
2383 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2385 return DoInsertItem (parentId
, before
, text
, image
, selImage
, data
);
2388 wxTreeItemId
wxTreeListMainWindow::AppendItem (const wxTreeItemId
& parentId
,
2389 const wxString
& text
,
2390 int image
, int selImage
,
2391 wxTreeItemData
*data
) {
2392 wxTreeListItem
*parent
= (wxTreeListItem
*) parentId
.m_pItem
;
2393 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2395 return DoInsertItem (parent
, parent
->GetChildren().Count(), text
, image
, selImage
, data
);
2398 void wxTreeListMainWindow::SendDeleteEvent (wxTreeListItem
*item
) {
2399 // send event to user code
2400 wxTreeEvent
event (wxEVT_COMMAND_TREE_DELETE_ITEM
, m_owner
->GetId());
2401 #if !wxCHECK_VERSION(2, 5, 0)
2402 event
.SetItem ((long)item
);
2404 event
.SetItem (item
);
2406 event
.SetEventObject (m_owner
);
2407 m_owner
->ProcessEvent (event
);
2410 void wxTreeListMainWindow::Delete (const wxTreeItemId
& itemId
) {
2411 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2412 wxCHECK_RET (item
!= m_rootItem
, _T("invalid item, root may not be deleted this way!"));
2413 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2415 // don't stay with invalid m_shiftItem or we will crash in the next call to OnChar()
2416 bool changeKeyCurrent
= false;
2417 wxTreeListItem
*itemKey
= m_shiftItem
;
2419 if (itemKey
== item
) { // m_shiftItem is a descendant of the item being deleted
2420 changeKeyCurrent
= true;
2423 itemKey
= itemKey
->GetItemParent();
2426 wxTreeListItem
*parent
= item
->GetItemParent();
2428 parent
->GetChildren().Remove (item
); // remove by value
2430 if (changeKeyCurrent
) m_shiftItem
= parent
;
2432 SendDeleteEvent (item
);
2433 if (m_selectItem
== item
) m_selectItem
= (wxTreeListItem
*)NULL
;
2434 item
->DeleteChildren (this);
2438 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId
& itemId
) {
2439 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2440 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2442 item
->DeleteChildren (this);
2445 void wxTreeListMainWindow::DeleteRoot() {
2448 SendDeleteEvent (m_rootItem
);
2449 m_curItem
= (wxTreeListItem
*)NULL
;
2450 m_selectItem
= (wxTreeListItem
*)NULL
;
2451 m_rootItem
->DeleteChildren (this);
2457 void wxTreeListMainWindow::Expand (const wxTreeItemId
& itemId
) {
2458 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2459 wxCHECK_RET (item
, _T("invalid item in wxTreeListMainWindow::Expand") );
2461 if (!item
->HasPlus() || item
->IsExpanded()) return;
2463 // send event to user code
2464 wxTreeEvent
event (wxEVT_COMMAND_TREE_ITEM_EXPANDING
, m_owner
->GetId());
2465 #if !wxCHECK_VERSION(2, 5, 0)
2466 event
.SetItem ((long)item
);
2468 event
.SetItem (item
);
2470 event
.SetEventObject (m_owner
);
2471 if (m_owner
->ProcessEvent (event
) && !event
.IsAllowed()) return; // expand canceled
2476 // send event to user code
2477 event
.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED
);
2478 m_owner
->ProcessEvent (event
);
2481 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId
& itemId
) {
2483 if (!IsExpanded (itemId
)) return;
2484 #if !wxCHECK_VERSION(2, 5, 0)
2487 wxTreeItemIdValue cookie
;
2489 wxTreeItemId child
= GetFirstChild (itemId
, cookie
);
2490 while (child
.IsOk()) {
2492 child
= GetNextChild (itemId
, cookie
);
2496 void wxTreeListMainWindow::Collapse (const wxTreeItemId
& itemId
) {
2497 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2498 wxCHECK_RET (item
, _T("invalid item in wxTreeListMainWindow::Collapse") );
2500 if (!item
->HasPlus() || !item
->IsExpanded()) return;
2502 // send event to user code
2503 wxTreeEvent
event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, m_owner
->GetId() );
2504 #if !wxCHECK_VERSION(2, 5, 0)
2505 event
.SetItem ((long)item
);
2507 event
.SetItem (item
);
2509 event
.SetEventObject (m_owner
);
2510 if (m_owner
->ProcessEvent (event
) && !event
.IsAllowed()) return; // collapse canceled
2515 // send event to user code
2516 event
.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED
);
2517 ProcessEvent (event
);
2520 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId
& item
) {
2522 DeleteChildren (item
);
2525 void wxTreeListMainWindow::Toggle (const wxTreeItemId
& itemId
) {
2526 if (IsExpanded (itemId
)) {
2533 void wxTreeListMainWindow::Unselect() {
2535 m_selectItem
->SetHilight (false);
2536 RefreshLine (m_selectItem
);
2537 m_selectItem
= (wxTreeListItem
*)NULL
;
2541 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem
*item
) {
2542 if (item
->IsSelected()) {
2543 item
->SetHilight (false);
2545 if (item
== m_selectItem
) m_selectItem
= (wxTreeListItem
*)NULL
;
2547 if (item
->HasChildren()) {
2548 wxArrayTreeListItems
& children
= item
->GetChildren();
2549 size_t count
= children
.Count();
2550 for (size_t n
= 0; n
< count
; ++n
) {
2551 UnselectAllChildren (children
[n
]);
2556 void wxTreeListMainWindow::UnselectAll() {
2557 UnselectAllChildren ((wxTreeListItem
*)GetRootItem().m_pItem
);
2560 // Recursive function !
2561 // To stop we must have crt_item<last_item
2563 // Tag all next children, when no more children,
2564 // Move to parent (not to tag)
2565 // Keep going... if we found last_item, we stop.
2566 bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem
*crt_item
,
2567 wxTreeListItem
*last_item
) {
2568 wxTreeListItem
*parent
= crt_item
->GetItemParent();
2570 if (!parent
) {// This is root item
2571 return TagAllChildrenUntilLast (crt_item
, last_item
);
2574 wxArrayTreeListItems
& children
= parent
->GetChildren();
2575 int index
= children
.Index(crt_item
);
2576 wxASSERT (index
!= wxNOT_FOUND
); // I'm not a child of my parent?
2578 if ((parent
->HasChildren() && parent
->IsExpanded()) ||
2579 ((parent
== (wxTreeListItem
*)GetRootItem().m_pItem
) && HasFlag(wxTR_HIDE_ROOT
))) {
2580 size_t count
= children
.Count();
2581 for (size_t n
= (index
+1); n
< count
; ++n
) {
2582 if (TagAllChildrenUntilLast (children
[n
], last_item
)) return true;
2586 return TagNextChildren (parent
, last_item
);
2589 bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem
*crt_item
,
2590 wxTreeListItem
*last_item
) {
2591 crt_item
->SetHilight (true);
2592 RefreshLine(crt_item
);
2594 if (crt_item
==last_item
) return true;
2596 if (crt_item
->HasChildren() && crt_item
->IsExpanded()) {
2597 wxArrayTreeListItems
& children
= crt_item
->GetChildren();
2598 size_t count
= children
.Count();
2599 for (size_t n
= 0; n
< count
; ++n
) {
2600 if (TagAllChildrenUntilLast (children
[n
], last_item
)) return true;
2607 void wxTreeListMainWindow::SelectItem (const wxTreeItemId
& itemId
,
2608 const wxTreeItemId
& lastId
,
2609 bool unselect_others
) {
2610 wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item") );
2612 bool is_single
= !HasFlag(wxTR_MULTIPLE
);
2613 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2615 // single selection requires unselect others
2616 if (is_single
) unselect_others
= true;
2618 // send event to the user code
2619 wxTreeEvent
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, m_owner
->GetId() );
2620 #if !wxCHECK_VERSION(2, 5, 0)
2621 event
.SetItem ((long)item
);
2622 event
.SetOldItem ((long)m_curItem
);
2624 event
.SetItem (item
);
2625 event
.SetOldItem (m_curItem
);
2627 event
.SetEventObject (m_owner
);
2628 if (m_owner
->GetEventHandler()->ProcessEvent (event
) && !event
.IsAllowed()) return;
2630 // unselect all if unselect other items
2631 bool unselected
= false; // see that UnselectAll is done only once
2632 if (unselect_others
) {
2634 Unselect(); // to speed up thing
2641 // select item or item range
2642 if (lastId
.IsOk() && (itemId
!= lastId
)) {
2644 if (!unselected
) UnselectAll();
2645 wxTreeListItem
*last
= (wxTreeListItem
*) lastId
.m_pItem
;
2647 // ensure that the position of the item it calculated in any case
2648 if (m_dirty
) CalculatePositions();
2650 // select item range according Y-position
2651 if (last
->GetY() < item
->GetY()) {
2652 if (!TagAllChildrenUntilLast (last
, item
)) {
2653 TagNextChildren (last
, item
);
2656 if (!TagAllChildrenUntilLast (item
, last
)) {
2657 TagNextChildren (item
, last
);
2663 // select item according its old selection
2664 item
->SetHilight (!item
->IsSelected());
2666 if (unselect_others
) {
2667 m_selectItem
= (item
->IsSelected())? item
: (wxTreeListItem
*)NULL
;
2672 // send event to user code
2673 event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
);
2674 m_owner
->GetEventHandler()->ProcessEvent (event
);
2677 void wxTreeListMainWindow::SelectAll() {
2678 wxCHECK_RET (HasFlag(wxTR_MULTIPLE
), _T("invalid tree style"));
2680 // send event to user code
2681 wxTreeEvent
event (wxEVT_COMMAND_TREE_SEL_CHANGING
, m_owner
->GetId());
2682 event
.SetItem (GetRootItem());
2683 #if !wxCHECK_VERSION(2, 5, 0)
2684 event
.SetOldItem ((long)m_curItem
);
2686 event
.SetOldItem (m_curItem
);
2688 event
.SetEventObject (m_owner
);
2689 if (m_owner
->GetEventHandler()->ProcessEvent (event
) && !event
.IsAllowed()) return;
2691 #if !wxCHECK_VERSION(2, 5, 0)
2694 wxTreeItemIdValue cookie
= 0;
2696 wxTreeItemId root
= GetRootItem();
2697 wxTreeListItem
*first
= (wxTreeListItem
*)GetFirstChild (root
, cookie
).m_pItem
;
2698 wxTreeListItem
*last
= (wxTreeListItem
*)GetLastChild (root
, cookie
).m_pItem
;
2699 if (!TagAllChildrenUntilLast (first
, last
)) {
2700 TagNextChildren (first
, last
);
2703 // send event to user code
2704 event
.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED
);
2705 m_owner
->GetEventHandler()->ProcessEvent (event
);
2708 void wxTreeListMainWindow::FillArray (wxTreeListItem
*item
,
2709 wxArrayTreeItemIds
&array
) const {
2710 if (item
->IsSelected()) array
.Add (wxTreeItemId(item
));
2712 if (item
->HasChildren()) {
2713 wxArrayTreeListItems
& children
= item
->GetChildren();
2714 size_t count
= children
.GetCount();
2715 for (size_t n
= 0; n
< count
; ++n
) FillArray (children
[n
], array
);
2719 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds
&array
) const {
2721 wxTreeItemId idRoot
= GetRootItem();
2722 if (idRoot
.IsOk()) FillArray ((wxTreeListItem
*) idRoot
.m_pItem
, array
);
2723 return array
.Count();
2726 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId
& item
) {
2727 if (!item
.IsOk()) return; // do nothing if no item
2729 // first expand all parent branches
2730 wxTreeListItem
*gitem
= (wxTreeListItem
*) item
.m_pItem
;
2731 wxTreeListItem
*parent
= gitem
->GetItemParent();
2734 parent
= parent
->GetItemParent();
2738 RefreshLine (gitem
);
2741 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId
&item
) {
2742 if (!item
.IsOk()) return; // do nothing if no item
2744 // ensure that the position of the item it calculated in any case
2745 if (m_dirty
) CalculatePositions();
2747 wxTreeListItem
*gitem
= (wxTreeListItem
*) item
.m_pItem
;
2749 // now scroll to the item
2750 int item_y
= gitem
->GetY();
2753 GetScrollPixelsPerUnit (&xUnit
, &yUnit
);
2756 GetViewStart (&start_x
, &start_y
);
2761 GetClientSize (&client_w
, &client_h
);
2765 m_rootItem
->GetSize (x
, y
, this);
2766 x
= m_owner
->GetHeaderWindow()->GetWidth();
2767 y
+= yUnit
+ 2; // one more scrollbar unit + 2 pixels
2768 int x_pos
= GetScrollPos( wxHORIZONTAL
);
2770 if (item_y
< start_y
+3) {
2771 // going down, item should appear at top
2772 SetScrollbars (xUnit
, yUnit
, xUnit
? x
/xUnit
: 0, yUnit
? y
/yUnit
: 0, x_pos
, yUnit
? item_y
/yUnit
: 0);
2773 }else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) {
2774 // going up, item should appear at bottom
2775 item_y
+= yUnit
+ 2;
2776 SetScrollbars (xUnit
, yUnit
, xUnit
? x
/xUnit
: 0, yUnit
? y
/yUnit
: 0, x_pos
, yUnit
? (item_y
+GetLineHeight(gitem
)-client_h
)/yUnit
: 0 );
2780 // FIXME: tree sorting functions are not reentrant and not MT-safe!
2781 static wxTreeListMainWindow
*s_treeBeingSorted
= NULL
;
2783 static int LINKAGEMODE
tree_ctrl_compare_func(wxTreeListItem
**item1
,
2784 wxTreeListItem
**item2
)
2786 wxCHECK_MSG (s_treeBeingSorted
, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
2788 return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
);
2791 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId
& item1
,
2792 const wxTreeItemId
& item2
)
2794 return m_owner
->OnCompareItems (item1
, item2
);
2797 void wxTreeListMainWindow::SortChildren (const wxTreeItemId
& itemId
) {
2798 wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item"));
2800 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2802 wxCHECK_RET (!s_treeBeingSorted
,
2803 _T("wxTreeListMainWindow::SortChildren is not reentrant") );
2805 wxArrayTreeListItems
& children
= item
->GetChildren();
2806 if ( children
.Count() > 1 ) {
2808 s_treeBeingSorted
= this;
2809 children
.Sort(tree_ctrl_compare_func
);
2810 s_treeBeingSorted
= NULL
;
2814 wxTreeItemId
wxTreeListMainWindow::FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
) {
2816 // determine start item
2817 wxTreeItemId next
= item
;
2819 if (mode
& wxTL_MODE_NAV_LEVEL
) {
2820 next
= GetNextSibling (next
);
2821 }else if (mode
& wxTL_MODE_NAV_VISIBLE
) { //
2822 next
= GetNextVisible (next
, false);
2823 }else if (mode
& wxTL_MODE_NAV_EXPANDED
) {
2824 next
= GetNextExpanded (next
);
2825 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2826 next
= GetNext (next
, true);
2830 #if !wxCHECK_VERSION(2, 5, 0)
2833 wxTreeItemIdValue cookie
= 0;
2836 next
= (wxTreeListItem
*)GetRootItem().m_pItem
;
2837 if (HasFlag(wxTR_HIDE_ROOT
)) {
2838 next
= (wxTreeListItem
*)GetFirstChild (GetRootItem().m_pItem
, cookie
).m_pItem
;
2841 if (!next
.IsOk()) return (wxTreeItemId
*)NULL
;
2843 // start checking the next items
2844 while (next
.IsOk() && (next
!= item
)) {
2845 if (mode
& wxTL_MODE_FIND_PARTIAL
) {
2846 itemText
= GetItemText (next
).Mid (0, str
.Length());
2848 itemText
= GetItemText (next
);
2850 if (mode
& wxTL_MODE_FIND_NOCASE
) {
2851 if (itemText
.CmpNoCase (str
) == 0) return next
;
2853 if (itemText
.Cmp (str
) == 0) return next
;
2855 if (mode
& wxTL_MODE_NAV_LEVEL
) {
2856 next
= GetNextSibling (next
);
2857 }else if (mode
& wxTL_MODE_NAV_VISIBLE
) { //
2858 next
= GetNextVisible (next
, false);
2859 }else if (mode
& wxTL_MODE_NAV_EXPANDED
) {
2860 next
= GetNextExpanded (next
);
2861 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2862 next
= GetNext (next
, true);
2864 if (!next
.IsOk() && item
.IsOk()) {
2865 next
= (wxTreeListItem
*)GetRootItem().m_pItem
;
2866 if (HasFlag(wxTR_HIDE_ROOT
)) {
2867 next
= (wxTreeListItem
*)GetNextChild (GetRootItem().m_pItem
, cookie
).m_pItem
;
2871 return (wxTreeItemId
*)NULL
;
2874 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId
& item
) {
2875 wxTreeListItem
*prevItem
= m_dragItem
;
2876 m_dragItem
= (wxTreeListItem
*) item
.m_pItem
;
2877 if (prevItem
) RefreshLine (prevItem
);
2878 if (m_dragItem
) RefreshLine (m_dragItem
);
2881 void wxTreeListMainWindow::CalculateLineHeight() {
2882 wxClientDC
dc (this);
2883 dc
.SetFont (m_normalFont
);
2884 m_lineHeight
= (int)(dc
.GetCharHeight() + m_linespacing
);
2886 if (m_imageListNormal
) {
2887 // Calculate a m_lineHeight value from the normal Image sizes.
2888 // May be toggle off. Then wxTreeListMainWindow will spread when
2889 // necessary (which might look ugly).
2890 int n
= m_imageListNormal
->GetImageCount();
2891 for (int i
= 0; i
< n
; i
++) {
2892 int width
= 0, height
= 0;
2893 m_imageListNormal
->GetSize(i
, width
, height
);
2894 if (height
> m_lineHeight
) m_lineHeight
= height
+ m_linespacing
;
2898 if (m_imageListButtons
) {
2899 // Calculate a m_lineHeight value from the Button image sizes.
2900 // May be toggle off. Then wxTreeListMainWindow will spread when
2901 // necessary (which might look ugly).
2902 int n
= m_imageListButtons
->GetImageCount();
2903 for (int i
= 0; i
< n
; i
++) {
2904 int width
= 0, height
= 0;
2905 m_imageListButtons
->GetSize(i
, width
, height
);
2906 if (height
> m_lineHeight
) m_lineHeight
= height
+ m_linespacing
;
2910 if (m_lineHeight
< 30) { // add 10% space if greater than 30 pixels
2911 m_lineHeight
+= 2; // minimal 2 pixel space
2913 m_lineHeight
+= m_lineHeight
/ 10; // otherwise 10% space
2917 void wxTreeListMainWindow::SetImageList (wxImageList
*imageList
) {
2918 if (m_ownsImageListNormal
) delete m_imageListNormal
;
2919 m_imageListNormal
= imageList
;
2920 m_ownsImageListNormal
= false;
2922 CalculateLineHeight();
2925 void wxTreeListMainWindow::SetStateImageList (wxImageList
*imageList
) {
2926 if (m_ownsImageListState
) delete m_imageListState
;
2927 m_imageListState
= imageList
;
2928 m_ownsImageListState
= false;
2931 void wxTreeListMainWindow::SetButtonsImageList (wxImageList
*imageList
) {
2932 if (m_ownsImageListButtons
) delete m_imageListButtons
;
2933 m_imageListButtons
= imageList
;
2934 m_ownsImageListButtons
= false;
2936 CalculateLineHeight();
2939 void wxTreeListMainWindow::AssignImageList (wxImageList
*imageList
) {
2940 SetImageList(imageList
);
2941 m_ownsImageListNormal
= true;
2944 void wxTreeListMainWindow::AssignStateImageList (wxImageList
*imageList
) {
2945 SetStateImageList(imageList
);
2946 m_ownsImageListState
= true;
2949 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList
*imageList
) {
2950 SetButtonsImageList(imageList
);
2951 m_ownsImageListButtons
= true;
2954 // ----------------------------------------------------------------------------
2956 // ----------------------------------------------------------------------------
2958 void wxTreeListMainWindow::AdjustMyScrollbars() {
2961 GetScrollPixelsPerUnit (&xUnit
, &yUnit
);
2962 if (xUnit
== 0) xUnit
= GetCharWidth();
2963 if (yUnit
== 0) yUnit
= m_lineHeight
;
2965 m_rootItem
->GetSize (x
, y
, this);
2966 y
+= yUnit
+ 2; // one more scrollbar unit + 2 pixels
2967 int x_pos
= GetScrollPos (wxHORIZONTAL
);
2968 int y_pos
= GetScrollPos (wxVERTICAL
);
2969 x
= m_owner
->GetHeaderWindow()->GetWidth() + 2;
2970 if (x
< GetClientSize().GetWidth()) x_pos
= 0;
2971 SetScrollbars (xUnit
, yUnit
, x
/xUnit
, y
/yUnit
, x_pos
, y_pos
);
2973 SetScrollbars (0, 0, 0, 0);
2977 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem
*item
) const {
2978 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) {
2979 return item
->GetHeight();
2981 return m_lineHeight
;
2985 void wxTreeListMainWindow::PaintItem (wxTreeListItem
*item
, wxDC
& dc
) {
2987 wxTreeItemAttr
*attr
= item
->GetAttributes();
2989 dc
.SetFont (GetItemFont (item
));
2992 if (attr
&& attr
->HasTextColour()) {
2993 colText
= attr
->GetTextColour();
2995 colText
= GetForegroundColour();
2997 #if !wxCHECK_VERSION(2, 5, 0)
2998 wxColour colTextHilight
= wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT
);
3000 wxColour colTextHilight
= wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT
);
3003 int total_w
= m_owner
->GetHeaderWindow()->GetWidth();
3004 int total_h
= GetLineHeight(item
);
3005 int off_h
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0;
3006 int off_w
= HasFlag(wxTR_COLUMN_LINES
) ? 1 : 0;
3007 wxDCClipper
clipper (dc
, 0, item
->GetY(), total_w
, total_h
); // only within line
3009 int text_w
= 0, text_h
= 0;
3010 dc
.GetTextExtent( item
->GetText(GetMainColumn()), &text_w
, &text_h
);
3012 // determine background and show it
3014 if (attr
&& attr
->HasBackgroundColour()) {
3015 colBg
= attr
->GetBackgroundColour();
3017 colBg
= m_backgroundColour
;
3019 dc
.SetBrush (wxBrush (colBg
, wxSOLID
));
3020 dc
.SetPen (*wxTRANSPARENT_PEN
);
3021 if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT
)) {
3022 if (item
== m_dragItem
) {
3023 dc
.SetBrush (*m_hilightBrush
);
3024 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3025 dc
.SetPen ((item
== m_dragItem
)? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
3026 #endif // !__WXMAC__
3027 dc
.SetTextForeground (colTextHilight
);
3028 }else if (item
->IsSelected()) {
3029 if (!m_isDragging
&& m_hasFocus
) {
3030 dc
.SetBrush (*m_hilightBrush
);
3031 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3032 dc
.SetPen (*wxBLACK_PEN
);
3033 #endif // !__WXMAC__
3035 dc
.SetBrush (*m_hilightUnfocusedBrush
);
3036 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3037 dc
.SetPen (*wxTRANSPARENT_PEN
);
3038 #endif // !__WXMAC__
3040 dc
.SetTextForeground (colTextHilight
);
3041 }else if (item
== m_curItem
) {
3042 dc
.SetPen (m_hasFocus
? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
3044 dc
.SetTextForeground (colText
);
3046 dc
.DrawRectangle (0, item
->GetY() + off_h
, total_w
, total_h
- off_h
);
3048 dc
.SetTextForeground (colText
);
3051 int text_extraH
= (total_h
> text_h
) ? (total_h
- text_h
)/2 : 0;
3052 int img_extraH
= (total_h
> m_imgHeight
)? (total_h
-m_imgHeight
)/2: 0;
3054 for (int i
= 0; i
< GetColumnCount(); ++i
) {
3055 if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue;
3057 int col_w
= m_owner
->GetHeaderWindow()->GetColumnWidth(i
);
3058 wxDCClipper
clipper (dc
, x_colstart
, item
->GetY(), col_w
, total_h
); // only within column
3061 int image
= NO_IMAGE
;
3063 if(i
== GetMainColumn()) {
3064 x
= item
->GetX() + MARGIN
;
3066 x
+= (m_btnWidth
-m_btnWidth2
) + LINEATROOT
;
3070 if (m_imageListNormal
) image
= item
->GetCurrentImage();
3072 x
= x_colstart
+ MARGIN
;
3073 image
= item
->GetImage(i
);
3075 if (image
!= NO_IMAGE
) image_w
= m_imgWidth
+ MARGIN
;
3077 // honor text alignment
3078 wxString text
= item
->GetText(i
);
3080 switch ( m_owner
->GetHeaderWindow()->GetColumn(i
).GetAlignment() ) {
3082 // nothing to do, already left aligned
3085 dc
.GetTextExtent (text
, &text_w
, NULL
);
3086 w
= col_w
- (image_w
+ text_w
+ off_w
+ MARGIN
);
3089 case wxALIGN_CENTER
:
3090 dc
.GetTextExtent(text
, &text_w
, NULL
);
3091 w
= (col_w
- (image_w
+ text_w
+ off_w
+ MARGIN
))/2;
3095 int text_x
= x
+ image_w
;
3096 if (i
== GetMainColumn()) item
->SetTextX (text_x
);
3098 if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT
)) {
3099 if (i
== GetMainColumn()) {
3100 if (item
== m_dragItem
) {
3101 dc
.SetBrush (*m_hilightBrush
);
3102 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3103 dc
.SetPen ((item
== m_dragItem
)? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
3104 #endif // !__WXMAC__
3105 dc
.SetTextForeground (colTextHilight
);
3106 }else if (item
->IsSelected()) {
3107 if (!m_isDragging
&& m_hasFocus
) {
3108 dc
.SetBrush (*m_hilightBrush
);
3109 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3110 dc
.SetPen (*wxBLACK_PEN
);
3111 #endif // !__WXMAC__
3113 dc
.SetBrush (*m_hilightUnfocusedBrush
);
3114 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3115 dc
.SetPen (*wxTRANSPARENT_PEN
);
3116 #endif // !__WXMAC__
3118 dc
.SetTextForeground (colTextHilight
);
3119 }else if (item
== m_curItem
) {
3120 dc
.SetPen (m_hasFocus
? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
3122 dc
.SetTextForeground (colText
);
3124 dc
.DrawRectangle (text_x
, item
->GetY() + off_h
, text_w
, total_h
- off_h
);
3126 dc
.SetTextForeground (colText
);
3130 if (HasFlag(wxTR_COLUMN_LINES
)) { // vertical lines between columns
3131 #if !wxCHECK_VERSION(2, 5, 0)
3132 wxPen
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3134 wxPen
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3136 dc
.SetPen ((GetBackgroundColour() == *wxWHITE
)? pen
: *wxWHITE_PEN
);
3137 dc
.DrawLine (x_colstart
+col_w
-1, item
->GetY(), x_colstart
+col_w
-1, item
->GetY()+total_h
);
3140 dc
.SetBackgroundMode (wxTRANSPARENT
);
3142 if (image
!= NO_IMAGE
) {
3143 int y
= item
->GetY() + img_extraH
;
3144 m_imageListNormal
->Draw (image
, dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3146 int text_y
= item
->GetY() + text_extraH
;
3147 dc
.DrawText (text
, (wxCoord
)text_x
, (wxCoord
)text_y
);
3149 x_colstart
+= col_w
;
3152 // restore normal font
3153 dc
.SetFont( m_normalFont
);
3156 // Now y stands for the top of the item, whereas it used to stand for middle !
3157 void wxTreeListMainWindow::PaintLevel (wxTreeListItem
*item
, wxDC
&dc
,
3158 int level
, int &y
, int x_maincol
) {
3160 // Handle hide root (only level 0)
3161 if (HasFlag(wxTR_HIDE_ROOT
) && (level
== 0)) {
3162 wxArrayTreeListItems
& children
= item
->GetChildren();
3163 for (size_t n
= 0; n
< children
.Count(); n
++) {
3164 PaintLevel (children
[n
], dc
, 1, y
, x_maincol
);
3166 // end after expanding root
3170 // calculate position of vertical lines
3171 int x
= x_maincol
+ MARGIN
; // start of column
3172 if (HasFlag(wxTR_LINES_AT_ROOT
)) x
+= LINEATROOT
; // space for lines at root
3174 x
+= (m_btnWidth
-m_btnWidth2
); // half button space
3176 x
+= (m_indent
-m_indent
/2);
3178 if (HasFlag(wxTR_HIDE_ROOT
)) {
3179 x
+= m_indent
* (level
-1); // indent but not level 1
3181 x
+= m_indent
* level
; // indent according to level
3184 // set position of vertical line
3188 int h
= GetLineHeight (item
);
3190 int y_mid
= y_top
+ (h
/2);
3193 int exposed_x
= dc
.LogicalToDeviceX(0);
3194 int exposed_y
= dc
.LogicalToDeviceY(y_top
);
3196 if (IsExposed(exposed_x
, exposed_y
, 10000, h
)) { // 10000 = very much
3198 if (HasFlag(wxTR_ROW_LINES
)) { // horizontal lines between rows
3199 //dc.DestroyClippingRegion();
3200 int total_width
= m_owner
->GetHeaderWindow()->GetWidth();
3201 // if the background colour is white, choose a
3202 // contrasting color for the lines
3203 #if !wxCHECK_VERSION(2, 5, 0)
3204 wxPen
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3206 wxPen
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3208 dc
.SetPen ((GetBackgroundColour() == *wxWHITE
)? pen
: *wxWHITE_PEN
);
3209 dc
.DrawLine (0, y_top
, total_width
, y_top
);
3210 dc
.DrawLine (0, y_top
+h
, total_width
, y_top
+h
);
3214 PaintItem (item
, dc
);
3216 // restore DC objects
3217 dc
.SetBrush(*wxWHITE_BRUSH
);
3218 dc
.SetPen(m_dottedPen
);
3220 // clip to the column width
3221 int clip_width
= m_owner
->GetHeaderWindow()->
3222 GetColumn(m_main_column
).GetWidth();
3223 wxDCClipper
clipper(dc
, x_maincol
, y_top
, clip_width
, 10000);
3225 if (!HasFlag(wxTR_NO_LINES
)) { // connection lines
3227 // draw the horizontal line here
3228 dc
.SetPen(m_dottedPen
);
3229 int x2
= x
- m_indent
;
3230 if (x2
< (x_maincol
+ MARGIN
)) x2
= x_maincol
+ MARGIN
;
3231 int x3
= x
+ (m_btnWidth
-m_btnWidth2
);
3233 if (item
->HasPlus()) {
3234 dc
.DrawLine (x2
, y_mid
, x
- m_btnWidth2
, y_mid
);
3235 dc
.DrawLine (x3
, y_mid
, x3
+ LINEATROOT
, y_mid
);
3237 dc
.DrawLine (x2
, y_mid
, x3
+ LINEATROOT
, y_mid
);
3240 dc
.DrawLine (x2
, y_mid
, x
- m_indent
/2, y_mid
);
3244 if (item
->HasPlus() && HasButtons()) { // should the item show a button?
3246 if (m_imageListButtons
) {
3248 // draw the image button here
3249 int image
= wxTreeItemIcon_Normal
;
3250 if (item
->IsExpanded()) image
= wxTreeItemIcon_Expanded
;
3251 if (item
->IsSelected()) image
+= wxTreeItemIcon_Selected
- wxTreeItemIcon_Normal
;
3252 int xx
= x
- m_btnWidth2
+ MARGIN
;
3253 int yy
= y_mid
- m_btnHeight2
;
3254 dc
.SetClippingRegion(xx
, yy
, m_btnWidth
, m_btnHeight
);
3255 m_imageListButtons
->Draw (image
, dc
, xx
, yy
, wxIMAGELIST_DRAW_TRANSPARENT
);
3256 dc
.DestroyClippingRegion();
3258 }else if (HasFlag (wxTR_TWIST_BUTTONS
)) {
3260 // draw the twisty button here
3261 dc
.SetPen(*wxBLACK_PEN
);
3262 dc
.SetBrush(*m_hilightBrush
);
3264 if (item
->IsExpanded()) {
3265 button
[0].x
= x
- (m_btnWidth2
+1);
3266 button
[0].y
= y_mid
- (m_btnHeight
/3);
3267 button
[1].x
= x
+ (m_btnWidth2
+1);
3268 button
[1].y
= button
[0].y
;
3270 button
[2].y
= button
[0].y
+ (m_btnHeight2
+1);
3272 button
[0].x
= x
- (m_btnWidth
/3);
3273 button
[0].y
= y_mid
- (m_btnHeight2
+1);
3274 button
[1].x
= button
[0].x
;
3275 button
[1].y
= y_mid
+ (m_btnHeight2
+1);
3276 button
[2].x
= button
[0].x
+ (m_btnWidth2
+1);
3277 button
[2].y
= y_mid
;
3279 dc
.DrawPolygon(3, button
);
3281 }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3283 // draw the plus sign here
3284 #if !wxCHECK_VERSION(2, 7, 0)
3285 dc
.SetPen(*wxGREY_PEN
);
3286 dc
.SetBrush(*wxWHITE_BRUSH
);
3287 dc
.DrawRectangle (x
-m_btnWidth2
, y_mid
-m_btnHeight2
, m_btnWidth
, m_btnHeight
);
3288 dc
.SetPen(*wxBLACK_PEN
);
3289 dc
.DrawLine (x
-(m_btnWidth2
-2), y_mid
, x
+(m_btnWidth2
-1), y_mid
);
3290 if (!item
->IsExpanded()) { // change "-" to "+"
3291 dc
.DrawLine (x
, y_mid
-(m_btnHeight2
-2), x
, y_mid
+(m_btnHeight2
-1));
3294 wxRect
rect (x
-m_btnWidth2
, y_mid
-m_btnHeight2
, m_btnWidth
, m_btnHeight
);
3295 int flag
= item
->IsExpanded()? wxCONTROL_EXPANDED
: 0;
3296 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc
, rect
, flag
);
3305 // restore DC objects
3306 dc
.SetBrush(*wxWHITE_BRUSH
);
3307 dc
.SetPen(m_dottedPen
);
3308 dc
.SetTextForeground(*wxBLACK
);
3310 if (item
->IsExpanded())
3312 wxArrayTreeListItems
& children
= item
->GetChildren();
3314 // clip to the column width
3315 int clip_width
= m_owner
->GetHeaderWindow()->
3316 GetColumn(m_main_column
).GetWidth();
3318 // process lower levels
3320 if (m_imgWidth
> 0) {
3321 oldY
= y_mid
+ m_imgHeight2
;
3326 for (size_t n
= 0; n
< children
.Count(); ++n
) {
3329 PaintLevel (children
[n
], dc
, level
+1, y
, x_maincol
);
3331 // draw vertical line
3332 wxDCClipper
clipper(dc
, x_maincol
, y_top
, clip_width
, 10000);
3333 if (!HasFlag (wxTR_NO_LINES
)) {
3335 dc
.DrawLine (x
, oldY
, x
, y2
);
3343 // ----------------------------------------------------------------------------
3344 // wxWindows callbacks
3345 // ----------------------------------------------------------------------------
3347 void wxTreeListMainWindow::OnPaint (wxPaintEvent
&WXUNUSED(event
)) {
3349 wxPaintDC
dc (this);
3352 if (!m_rootItem
|| (GetColumnCount() <= 0)) return;
3354 // calculate button size
3355 if (m_imageListButtons
) {
3356 m_imageListButtons
->GetSize (0, m_btnWidth
, m_btnHeight
);
3357 }else if (HasButtons()) {
3358 m_btnWidth
= BTNWIDTH
;
3359 m_btnHeight
= BTNHEIGHT
;
3361 m_btnWidth2
= m_btnWidth
/2;
3362 m_btnHeight2
= m_btnHeight
/2;
3364 // calculate image size
3365 if (m_imageListNormal
) {
3366 m_imageListNormal
->GetSize (0, m_imgWidth
, m_imgHeight
);
3368 m_imgWidth2
= m_imgWidth
/2;
3369 m_imgHeight2
= m_imgHeight
/2;
3371 // calculate indent size
3372 if (m_imageListButtons
) {
3373 m_indent
= wxMax (MININDENT
, m_btnWidth
+ MARGIN
);
3374 }else if (HasButtons()) {
3375 m_indent
= wxMax (MININDENT
, m_btnWidth
+ LINEATROOT
);
3378 // set default values
3379 dc
.SetFont( m_normalFont
);
3380 dc
.SetPen( m_dottedPen
);
3382 // calculate column start and paint
3385 for (i
= 0; i
< (int)GetMainColumn(); ++i
) {
3386 if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue;
3387 x_maincol
+= m_owner
->GetHeaderWindow()->GetColumnWidth (i
);
3390 PaintLevel (m_rootItem
, dc
, 0, y
, x_maincol
);
3393 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent
&event
) {
3397 if (m_curItem
) RefreshLine (m_curItem
);
3401 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent
&event
)
3405 if (m_curItem
) RefreshLine (m_curItem
);
3409 void wxTreeListMainWindow::OnChar (wxKeyEvent
&event
) {
3410 // send event to user code
3411 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_KEY_DOWN
, m_owner
->GetId());
3412 nevent
.SetKeyEvent (event
);
3413 nevent
.SetEventObject (m_owner
);
3414 if (m_owner
->GetEventHandler()->ProcessEvent (nevent
)) return; // handled in user code
3416 // determine first current if none
3417 bool curItemSet
= false;
3419 m_curItem
= (wxTreeListItem
*)GetRootItem().m_pItem
;
3420 if (HasFlag(wxTR_HIDE_ROOT
)) {
3421 #if !wxCHECK_VERSION(2, 5, 0)
3424 wxTreeItemIdValue cookie
= 0;
3426 m_curItem
= (wxTreeListItem
*)GetFirstChild (m_curItem
, cookie
).m_pItem
;
3430 if (!m_curItem
) return; // do nothing if empty tree
3432 // remember item at shift down
3433 if (HasFlag(wxTR_MULTIPLE
) && event
.ShiftDown()) {
3434 if (!m_shiftItem
) m_shiftItem
= m_curItem
;
3436 m_shiftItem
= (wxTreeListItem
*)NULL
;
3439 // process all cases
3440 wxTreeItemId newItem
= (wxTreeItemId
*)NULL
;
3441 switch (event
.GetKeyCode()) {
3443 // '+': Expand subtree
3446 if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) Expand (m_curItem
);
3449 // '-': collapse subtree
3451 case WXK_SUBTRACT
: {
3452 if (m_curItem
->HasPlus() && IsExpanded (m_curItem
)) Collapse (m_curItem
);
3455 // '*': expand/collapse all subtrees // TODO: Mak it more useful
3457 case WXK_MULTIPLY
: {
3458 if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) {
3459 ExpandAll (m_curItem
);
3460 }else if (m_curItem
->HasPlus()) {
3461 Collapse (m_curItem
); // TODO: CollapseAll
3465 // ' ': toggle current item
3467 SelectItem (m_curItem
, (wxTreeListItem
*)NULL
, false);
3470 // <RETURN>: activate current item
3472 wxTreeEvent
aevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, m_owner
->GetId());
3473 #if !wxCHECK_VERSION(2, 5, 0)
3474 aevent
.SetItem ((long)m_curItem
);
3476 aevent
.SetItem (m_curItem
);
3478 aevent
.SetEventObject (m_owner
);
3479 m_owner
->GetEventHandler()->ProcessEvent (aevent
);
3482 // <BKSP>: go to the parent without collapsing
3484 newItem
= GetItemParent (m_curItem
);
3485 if ((newItem
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) {
3486 newItem
= GetPrevSibling (m_curItem
); // get sibling instead of root
3490 // <UP>: go to the previous sibling or to the last of its children, to the parent
3492 newItem
= GetPrevSibling (m_curItem
);
3494 #if !wxCHECK_VERSION(2, 5, 0)
3497 wxTreeItemIdValue cookie
= 0;
3499 while (IsExpanded (newItem
) && HasChildren (newItem
)) {
3500 newItem
= GetLastChild (newItem
, cookie
);
3503 newItem
= GetItemParent (m_curItem
);
3504 if ((newItem
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) {
3505 newItem
= (wxTreeItemId
*)NULL
; // don't go to root if it is hidden
3510 // <LEFT>: if expanded collapse subtree, else go to the parent
3512 if (IsExpanded (m_curItem
)) {
3513 Collapse (m_curItem
);
3515 newItem
= GetItemParent (m_curItem
);
3516 if ((newItem
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) {
3517 newItem
= GetPrevSibling (m_curItem
); // go to sibling if it is hidden
3522 // <RIGHT>: if possible expand subtree, else go go to the first child
3524 if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) {
3527 if (IsExpanded (m_curItem
) && HasChildren (m_curItem
)) {
3528 #if !wxCHECK_VERSION(2, 5, 0)
3531 wxTreeItemIdValue cookie
= 0;
3533 newItem
= GetFirstChild (m_curItem
, cookie
);
3538 // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3541 newItem
= m_curItem
;
3543 if (IsExpanded (m_curItem
) && HasChildren (m_curItem
)) {
3544 #if !wxCHECK_VERSION(2, 5, 0)
3547 wxTreeItemIdValue cookie
= 0;
3549 newItem
= GetFirstChild( m_curItem
, cookie
);
3552 wxTreeItemId parent
= m_curItem
;
3554 newItem
= GetNextSibling (parent
);
3555 parent
= GetItemParent (parent
);
3556 } while (!newItem
&& parent
);
3561 // <END>: go to last item of the root
3563 #if !wxCHECK_VERSION(2, 5, 0)
3566 wxTreeItemIdValue cookie
= 0;
3568 newItem
= GetLastChild (GetRootItem(), cookie
);
3571 // <HOME>: go to root
3573 newItem
= GetRootItem();
3574 if (HasFlag(wxTR_HIDE_ROOT
)) {
3575 #if !wxCHECK_VERSION(2, 5, 0)
3578 wxTreeItemIdValue cookie
= 0;
3580 newItem
= GetFirstChild (newItem
, cookie
);
3584 // any char: go to the next matching string
3586 if (event
.GetKeyCode() >= (int)' ') {
3587 if (!m_findTimer
->IsRunning()) m_findStr
.Clear();
3588 m_findStr
.Append (event
.GetKeyCode());
3589 m_findTimer
->Start (FIND_TIMER_TICKS
, wxTIMER_ONE_SHOT
);
3590 wxTreeItemId prev
= m_curItem
? (wxTreeItemId
*)m_curItem
: (wxTreeItemId
*)NULL
;
3592 newItem
= FindItem (prev
, m_findStr
, wxTL_MODE_NAV_EXPANDED
|
3593 wxTL_MODE_FIND_PARTIAL
|
3594 wxTL_MODE_FIND_NOCASE
);
3595 if (newItem
|| (m_findStr
.Length() <= 1)) break;
3596 m_findStr
.RemoveLast();
3603 // select and show the new item
3605 if (!event
.ControlDown()) {
3606 bool unselect_others
= !((event
.ShiftDown() || event
.ControlDown()) &&
3607 HasFlag(wxTR_MULTIPLE
));
3608 SelectItem (newItem
, m_shiftItem
, unselect_others
);
3610 EnsureVisible (newItem
);
3611 wxTreeListItem
*oldItem
= m_curItem
;
3612 m_curItem
= (wxTreeListItem
*)newItem
.m_pItem
; // make the new item the current item
3613 RefreshLine (oldItem
);
3618 wxTreeItemId
wxTreeListMainWindow::HitTest (const wxPoint
& point
, int& flags
, int& column
) {
3624 if (point
.x
<0) flags
|= wxTREE_HITTEST_TOLEFT
;
3625 if (point
.x
>w
) flags
|= wxTREE_HITTEST_TORIGHT
;
3626 if (point
.y
<0) flags
|= wxTREE_HITTEST_ABOVE
;
3627 if (point
.y
>h
) flags
|= wxTREE_HITTEST_BELOW
;
3628 if (flags
) return wxTreeItemId();
3631 flags
= wxTREE_HITTEST_NOWHERE
;
3633 return wxTreeItemId();
3636 wxTreeListItem
*hit
= m_rootItem
->HitTest (CalcUnscrolledPosition(point
),
3637 this, flags
, column
, 0);
3639 flags
= wxTREE_HITTEST_NOWHERE
;
3641 return wxTreeItemId();
3646 // get the bounding rectangle of the item (or of its label only)
3647 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId
& itemId
, wxRect
& rect
,
3648 bool WXUNUSED(textOnly
)) const {
3649 wxCHECK_MSG (itemId
.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
3651 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
3654 GetScrollPixelsPerUnit (&xUnit
, &yUnit
);
3656 GetViewStart(& startX
, & startY
);
3658 rect
.x
= item
->GetX() - startX
* xUnit
;
3659 rect
.y
= item
->GetY() - startY
* yUnit
;
3660 rect
.width
= item
->GetWidth();
3661 rect
.height
= GetLineHeight (item
);
3668 void wxTreeListMainWindow::EditLabel (const wxTreeItemId
& item
, int column
) {
3669 if (!item
.IsOk()) return;
3670 if (!((column
>= 0) && (column
< GetColumnCount()))) return;
3672 m_editItem
= (wxTreeListItem
*) item
.m_pItem
;
3674 wxTreeEvent
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, m_owner
->GetId() );
3675 #if !wxCHECK_VERSION(2, 5, 0)
3676 te
.SetItem ((long)m_editItem
);
3678 te
.SetItem (m_editItem
);
3681 te
.SetEventObject (m_owner
);
3682 m_owner
->GetEventHandler()->ProcessEvent (te
);
3684 if (!te
.IsAllowed()) return;
3686 // ensure that the position of the item it calculated in any case
3687 if (m_dirty
) CalculatePositions();
3689 wxTreeListHeaderWindow
* header_win
= m_owner
->GetHeaderWindow();
3691 int y
= m_editItem
->GetY() + 1; // wxTextCtrl needs 1 pixels above the text
3693 int h
= m_editItem
->GetHeight();
3695 if (column
== GetMainColumn()) {
3696 x
+= m_editItem
->GetTextX() - 2; // wxTextCtrl needs 2 pixels before the text
3697 w
= wxMin (m_editItem
->GetWidth(), m_owner
->GetHeaderWindow()->GetWidth() - x
);
3699 for (int i
= 0; i
< column
; ++i
) x
+= header_win
->GetColumnWidth (i
); // start of column
3700 switch (header_win
->GetColumnAlignment (column
)) {
3701 case wxALIGN_LEFT
: {style
= wxTE_LEFT
; break;}
3702 case wxALIGN_RIGHT
: {style
= wxTE_RIGHT
; break;}
3703 case wxALIGN_CENTER
: {style
= wxTE_CENTER
; break;}
3705 w
= header_win
->GetColumnWidth (column
); // width of column
3708 wxClientDC
dc (this);
3710 x
= dc
.LogicalToDeviceX (x
);
3711 y
= dc
.LogicalToDeviceY (y
);
3713 wxEditTextCtrl
*text
= new wxEditTextCtrl (this, -1, &m_renameAccept
, &m_renameRes
,
3714 this, m_editItem
->GetText (column
),
3715 wxPoint (x
, y
), wxSize (w
, h
), style
);
3719 void wxTreeListMainWindow::OnRenameTimer() {
3720 EditLabel (m_curItem
, m_curColumn
);
3723 void wxTreeListMainWindow::OnRenameAccept() {
3725 // TODO if the validator fails this causes a crash
3726 wxTreeEvent
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, m_owner
->GetId() );
3727 #if !wxCHECK_VERSION(2, 5, 0)
3728 le
.SetItem((long)m_editItem
);
3730 le
.SetItem(m_editItem
);
3732 le
.SetEventObject( /*this*/m_owner
);
3733 le
.SetLabel( m_renameRes
);
3734 m_owner
->GetEventHandler()->ProcessEvent( le
);
3736 if (!le
.IsAllowed()) return;
3738 SetItemText (m_editItem
, m_curColumn
, m_renameRes
);
3741 void wxTreeListMainWindow::OnMouse (wxMouseEvent
&event
) {
3742 if (!m_rootItem
) return;
3744 // we process left mouse up event (enables in-place edit), right down
3745 // (pass to the user code), left dbl click (activate item) and
3746 // dragging/moving events for items drag-and-drop
3747 if (!(event
.LeftDown() ||
3749 event
.RightDown() ||
3751 event
.LeftDClick() ||
3753 (event
.GetWheelRotation() != 0 )/*? TODO ||
3754 event.Moving()?*/)) {
3755 m_owner
->GetEventHandler()->ProcessEvent (event
);
3759 // set focus if window clicked
3760 if (event
.LeftDown() || event
.RightDown()) SetFocus();
3763 wxPoint p
= wxPoint (event
.GetX(), event
.GetY());
3765 wxTreeListItem
*item
= m_rootItem
->HitTest (CalcUnscrolledPosition (p
),
3766 this, flags
, m_curColumn
, 0);
3768 // we only process dragging here
3769 if (event
.Dragging()){
3770 if (m_isDragging
) return; // nothing to do, already done
3771 if (item
== NULL
) return; // we need an item to dragging
3773 // determine drag start
3774 if (m_dragCount
== 0) {
3775 m_dragTimer
->Start (DRAG_TIMER_TICKS
, wxTIMER_ONE_SHOT
);
3778 if (m_dragCount
< 3) return; // minimum drag 3 pixel
3779 if (m_dragTimer
->IsRunning()) return;
3781 // we're going to drag
3783 m_isDragging
= true;
3787 // send drag start event
3788 wxEventType command
= event
.LeftIsDown()
3789 ? wxEVT_COMMAND_TREE_BEGIN_DRAG
3790 : wxEVT_COMMAND_TREE_BEGIN_RDRAG
;
3791 wxTreeEvent
nevent (command
, m_owner
->GetId());
3792 nevent
.SetEventObject (m_owner
);
3793 #if !wxCHECK_VERSION(2, 5, 0)
3794 nevent
.SetItem ((long)item
); // the item the drag is ended
3796 nevent
.SetItem (item
); // the item the drag is ended
3798 nevent
.Veto(); // dragging must be explicit allowed!
3799 m_owner
->GetEventHandler()->ProcessEvent (nevent
);
3801 }else if (m_isDragging
) { // any other event but not event.Dragging()
3805 m_isDragging
= false;
3806 if (HasCapture()) ReleaseMouse();
3809 // send drag end event event
3810 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_END_DRAG
, m_owner
->GetId());
3811 nevent
.SetEventObject (m_owner
);
3812 #if !wxCHECK_VERSION(2, 5, 0)
3813 nevent
.SetItem ((long)item
); // the item the drag is started
3815 nevent
.SetItem (item
); // the item the drag is started
3817 nevent
.SetPoint (p
);
3818 m_owner
->GetEventHandler()->ProcessEvent (nevent
);
3820 }else if (m_dragCount
> 0) { // just in case dragging is initiated
3827 // we process only the messages which happen on tree items
3829 m_owner
->GetEventHandler()->ProcessEvent (event
);
3833 // remember item at shift down
3834 if (event
.ShiftDown()) {
3835 if (!m_shiftItem
) m_shiftItem
= m_curItem
;
3837 m_shiftItem
= (wxTreeListItem
*)NULL
;
3840 if (event
.RightUp()) {
3843 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
, m_owner
->GetId());
3844 nevent
.SetEventObject (m_owner
);
3845 #if !wxCHECK_VERSION(2, 5, 0)
3846 nevent
.SetItem ((long)item
); // the item clicked
3848 nevent
.SetItem (item
); // the item clicked
3850 nevent
.SetInt (m_curColumn
); // the colum clicked
3851 nevent
.SetPoint (p
);
3852 m_owner
->GetEventHandler()->ProcessEvent (nevent
);
3854 }else if (event
.LeftUp()) {
3857 if ((item
== m_curItem
) && (m_curColumn
!= -1) &&
3858 (m_owner
->GetHeaderWindow()->IsColumnEditable (m_curColumn
)) &&
3859 (flags
& (wxTREE_HITTEST_ONITEMLABEL
| wxTREE_HITTEST_ONITEMCOLUMN
))){
3860 m_renameTimer
->Start (RENAME_TIMER_TICKS
, wxTIMER_ONE_SHOT
);
3862 m_lastOnSame
= false;
3865 if (((flags
& wxTREE_HITTEST_ONITEMBUTTON
) ||
3866 (flags
& wxTREE_HITTEST_ONITEMICON
)) &&
3867 HasButtons() && item
->HasPlus()) {
3869 // only toggle the item for a single click, double click on
3870 // the button doesn't do anything (it toggles the item twice)
3871 if (event
.LeftDown()) Toggle (item
);
3873 // don't select the item if the button was clicked
3877 // determine the selection if not done by left down
3878 if (!m_left_down_selection
) {
3879 bool unselect_others
= !((event
.ShiftDown() || event
.ControlDown()) &&
3880 HasFlag(wxTR_MULTIPLE
));
3881 SelectItem (item
, m_shiftItem
, unselect_others
);
3882 EnsureVisible (item
);
3883 m_curItem
= item
; // make the new item the current item
3885 m_left_down_selection
= false;
3888 }else if (event
.LeftDown() || event
.RightDown() || event
.LeftDClick()) {
3890 if (event
.LeftDown() || event
.RightDown()) {
3892 m_lastOnSame
= item
== m_curItem
;
3895 if (((flags
& wxTREE_HITTEST_ONITEMBUTTON
) ||
3896 (flags
& wxTREE_HITTEST_ONITEMICON
)) &&
3899 // only toggle the item for a single click, double click on
3900 // the button doesn't do anything (it toggles the item twice)
3901 if (event
.LeftDown()) Toggle (item
);
3903 // don't select the item if the button was clicked
3907 // determine the selection if the current item is not selected
3908 if (!item
->IsSelected()) {
3909 bool unselect_others
= !((event
.ShiftDown() || event
.ControlDown()) &&
3910 HasFlag(wxTR_MULTIPLE
));
3911 SelectItem (item
, m_shiftItem
, unselect_others
);
3912 EnsureVisible (item
);
3913 m_curItem
= item
; // make the new item the current item
3914 m_left_down_selection
= true;
3917 // For some reason, Windows isn't recognizing a left double-click,
3918 // so we need to simulate it here. Allow 200 milliseconds for now.
3919 if (event
.LeftDClick()) {
3921 // double clicking should not start editing the item label
3922 m_renameTimer
->Stop();
3923 m_lastOnSame
= false;
3925 // send activate event first
3926 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, m_owner
->GetId());
3927 nevent
.SetEventObject (m_owner
);
3928 #if !wxCHECK_VERSION(2, 5, 0)
3929 nevent
.SetItem ((long)item
); // the item clicked
3931 nevent
.SetItem (item
); // the item clicked
3933 nevent
.SetInt (m_curColumn
); // the colum clicked
3934 nevent
.SetPoint (p
);
3935 if (!m_owner
->GetEventHandler()->ProcessEvent (nevent
)) {
3937 // if the user code didn't process the activate event,
3938 // handle it ourselves by toggling the item when it is
3940 if (item
->HasPlus()) Toggle(item
);
3944 }else{ // any other event skip just in case
3951 void wxTreeListMainWindow::OnIdle (wxIdleEvent
&WXUNUSED(event
)) {
3952 /* after all changes have been done to the tree control,
3953 * we actually redraw the tree when everything is over */
3955 if (!m_dirty
) return;
3959 CalculatePositions();
3961 AdjustMyScrollbars();
3964 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent
& event
) {
3966 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
3967 wxScrolledWindow::OnScroll(event
);
3969 HandleOnScroll( event
);
3972 if(event
.GetOrientation() == wxHORIZONTAL
) {
3973 m_owner
->GetHeaderWindow()->Refresh();
3974 m_owner
->GetHeaderWindow()->Update();
3978 void wxTreeListMainWindow::CalculateSize (wxTreeListItem
*item
, wxDC
&dc
) {
3982 dc
.SetFont (GetItemFont (item
));
3984 dc
.GetTextExtent (item
->GetText (m_main_column
), &text_w
, &text_h
);
3986 // restore normal font
3987 dc
.SetFont (m_normalFont
);
3989 int total_h
= (m_imgHeight
> text_h
) ? m_imgHeight
: text_h
;
3990 if (total_h
< 30) { // add 10% space if greater than 30 pixels
3991 total_h
+= 2; // minimal 2 pixel space
3993 total_h
+= total_h
/ 10; // otherwise 10% space
3996 item
->SetHeight (total_h
);
3997 if (total_h
> m_lineHeight
) m_lineHeight
= total_h
;
3998 item
->SetWidth(m_imgWidth
+ text_w
+2);
4001 // -----------------------------------------------------------------------------
4002 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem
*item
, wxDC
&dc
,
4003 int level
, int &y
, int x_colstart
) {
4005 // calculate position of vertical lines
4006 int x
= x_colstart
+ MARGIN
; // start of column
4007 if (HasFlag(wxTR_LINES_AT_ROOT
)) x
+= LINEATROOT
; // space for lines at root
4009 x
+= (m_btnWidth
-m_btnWidth2
); // half button space
4011 x
+= (m_indent
-m_indent
/2);
4013 if (HasFlag(wxTR_HIDE_ROOT
)) {
4014 x
+= m_indent
* (level
-1); // indent but not level 1
4016 x
+= m_indent
* level
; // indent according to level
4019 // a hidden root is not evaluated, but its children are always
4020 if (HasFlag(wxTR_HIDE_ROOT
) && (level
== 0)) goto Recurse
;
4022 CalculateSize( item
, dc
);
4027 y
+= GetLineHeight(item
);
4029 // we don't need to calculate collapsed branches
4030 if ( !item
->IsExpanded() ) return;
4033 wxArrayTreeListItems
& children
= item
->GetChildren();
4034 long n
, count
= (long)children
.Count();
4036 for (n
= 0; n
< count
; ++n
) {
4037 CalculateLevel( children
[n
], dc
, level
, y
, x_colstart
); // recurse
4041 void wxTreeListMainWindow::CalculatePositions() {
4042 if ( !m_rootItem
) return;
4044 wxClientDC
dc(this);
4047 dc
.SetFont( m_normalFont
);
4049 dc
.SetPen( m_dottedPen
);
4050 //if(GetImageList() == NULL)
4051 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
4055 for (int i
= 0; i
< (int)GetMainColumn(); ++i
) {
4056 if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue;
4057 x_colstart
+= m_owner
->GetHeaderWindow()->GetColumnWidth(i
);
4059 CalculateLevel( m_rootItem
, dc
, 0, y
, x_colstart
); // start recursion
4062 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem
*item
) {
4063 if (m_dirty
) return;
4065 wxClientDC
dc(this);
4070 GetVirtualSize( &cw
, &ch
);
4073 rect
.x
= dc
.LogicalToDeviceX( 0 );
4075 rect
.y
= dc
.LogicalToDeviceY( item
->GetY() - 2 );
4078 Refresh (true, &rect
);
4079 AdjustMyScrollbars();
4082 void wxTreeListMainWindow::RefreshLine (wxTreeListItem
*item
) {
4083 if (m_dirty
) return;
4085 wxClientDC
dc(this);
4090 GetVirtualSize( &cw
, &ch
);
4093 rect
.x
= dc
.LogicalToDeviceX( 0 );
4094 rect
.y
= dc
.LogicalToDeviceY( item
->GetY() );
4096 rect
.height
= GetLineHeight(item
); //dc.GetCharHeight() + 6;
4098 Refresh (true, &rect
);
4101 void wxTreeListMainWindow::RefreshSelected() {
4102 // TODO: this is awfully inefficient, we should keep the list of all
4103 // selected items internally, should be much faster
4105 RefreshSelectedUnder (m_rootItem
);
4109 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem
*item
) {
4110 if (item
->IsSelected()) {
4114 const wxArrayTreeListItems
& children
= item
->GetChildren();
4115 long count
= children
.GetCount();
4116 for (long n
= 0; n
< count
; n
++ ) {
4117 RefreshSelectedUnder (children
[n
]);
4121 // ----------------------------------------------------------------------------
4122 // changing colours: we need to refresh the tree control
4123 // ----------------------------------------------------------------------------
4125 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour
& colour
) {
4126 if (!wxWindow::SetBackgroundColour(colour
)) return false;
4132 bool wxTreeListMainWindow::SetForegroundColour (const wxColour
& colour
) {
4133 if (!wxWindow::SetForegroundColour(colour
)) return false;
4139 void wxTreeListMainWindow::SetItemText (const wxTreeItemId
& itemId
, int column
,
4140 const wxString
& text
) {
4141 wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item"));
4143 wxClientDC
dc (this);
4144 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
4145 item
->SetText (column
, text
);
4146 CalculateSize (item
, dc
);
4150 wxString
wxTreeListMainWindow::GetItemText (const wxTreeItemId
& itemId
,
4152 wxCHECK_MSG (itemId
.IsOk(), _T(""), _T("invalid tree item") );
4154 if( IsVirtual() ) return m_owner
->OnGetItemText(((wxTreeListItem
*) itemId
.m_pItem
)->GetData(),column
);
4155 else return ((wxTreeListItem
*) itemId
.m_pItem
)->GetText (column
);
4158 wxString
wxTreeListMainWindow::GetItemText (wxTreeItemData
* item
,
4160 wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4161 return m_owner
->OnGetItemText(item
,column
);
4164 void wxTreeListMainWindow::SetFocus() {
4165 wxWindow::SetFocus();
4168 wxFont
wxTreeListMainWindow::GetItemFont (wxTreeListItem
*item
) {
4169 wxTreeItemAttr
*attr
= item
->GetAttributes();
4171 if (attr
&& attr
->HasFont()) {
4172 return attr
->GetFont();
4173 }else if (item
->IsBold()) {
4176 return m_normalFont
;
4180 int wxTreeListMainWindow::GetItemWidth (int column
, wxTreeListItem
*item
) {
4181 if (!item
) return 0;
4183 // determine item width
4185 wxFont font
= GetItemFont (item
);
4186 GetTextExtent (item
->GetText (column
), &w
, &h
, NULL
, NULL
, font
.Ok()? &font
: NULL
);
4190 int width
= w
+ 2*MARGIN
;
4191 if (column
== GetMainColumn()) {
4193 if (HasFlag(wxTR_LINES_AT_ROOT
)) width
+= LINEATROOT
;
4194 if (HasButtons()) width
+= m_btnWidth
+ LINEATROOT
;
4195 if (item
->GetCurrentImage() != NO_IMAGE
) width
+= m_imgWidth
;
4197 // count indent level
4199 wxTreeListItem
*parent
= item
->GetItemParent();
4200 wxTreeListItem
*root
= (wxTreeListItem
*)GetRootItem().m_pItem
;
4201 while (parent
&& (!HasFlag(wxTR_HIDE_ROOT
) || (parent
!= root
))) {
4203 parent
= parent
->GetItemParent();
4205 if (level
) width
+= level
* GetIndent();
4211 int wxTreeListMainWindow::GetBestColumnWidth (int column
, wxTreeItemId parent
) {
4213 GetClientSize (&maxWidth
, &h
);
4216 // get root if on item
4217 if (!parent
.IsOk()) parent
= GetRootItem();
4220 if (!HasFlag(wxTR_HIDE_ROOT
)) {
4221 int w
= GetItemWidth (column
, (wxTreeListItem
*)parent
.m_pItem
);
4222 if (width
< w
) width
= w
;
4223 if (width
> maxWidth
) return maxWidth
;
4226 wxTreeItemIdValue cookie
= 0;
4227 wxTreeItemId item
= GetFirstChild (parent
, cookie
);
4228 while (item
.IsOk()) {
4229 int w
= GetItemWidth (column
, (wxTreeListItem
*)item
.m_pItem
);
4230 if (width
< w
) width
= w
;
4231 if (width
> maxWidth
) return maxWidth
;
4233 // check the children of this item
4234 if (((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) {
4235 int w
= GetBestColumnWidth (column
, item
);
4236 if (width
< w
) width
= w
;
4237 if (width
> maxWidth
) return maxWidth
;
4241 item
= GetNextChild (parent
, cookie
);
4248 //-----------------------------------------------------------------------------
4250 //-----------------------------------------------------------------------------
4252 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl
, wxControl
);
4254 BEGIN_EVENT_TABLE(wxTreeListCtrl
, wxControl
)
4255 EVT_SIZE(wxTreeListCtrl::OnSize
)
4258 bool wxTreeListCtrl::Create(wxWindow
*parent
, wxWindowID id
,
4261 long style
, const wxValidator
&validator
,
4262 const wxString
& name
)
4264 long main_style
= style
& ~(wxSIMPLE_BORDER
|wxSUNKEN_BORDER
|wxDOUBLE_BORDER
|
4265 wxRAISED_BORDER
|wxSTATIC_BORDER
);
4266 long ctrl_style
= style
& ~(wxVSCROLL
|wxHSCROLL
);
4268 if (!wxControl::Create(parent
, id
, pos
, size
, ctrl_style
, validator
, name
)) {
4271 m_main_win
= new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size
,
4272 main_style
, validator
);
4273 m_header_win
= new wxTreeListHeaderWindow (this, -1, m_main_win
,
4274 wxPoint(0, 0), wxDefaultSize
,
4276 CalculateAndSetHeaderHeight();
4280 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4284 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
4285 h
= wxRendererNative::Get().GetHeaderButtonHeight(m_header_win
);
4287 // we use 'g' to get the descent, too
4289 m_header_win
->GetTextExtent(_T("Hg"), &w
, &h
, &d
);
4290 h
+= d
+ 2 * HEADER_OFFSET_Y
+ EXTRA_HEIGHT
;
4292 // only update if changed
4293 if (h
!= m_headerHeight
) {
4300 void wxTreeListCtrl::DoHeaderLayout()
4303 GetClientSize(&w
, &h
);
4305 m_header_win
->SetSize (0, 0, w
, m_headerHeight
);
4306 m_header_win
->Refresh();
4309 m_main_win
->SetSize (0, m_headerHeight
+ 1, w
, h
- m_headerHeight
- 1);
4313 void wxTreeListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
))
4318 size_t wxTreeListCtrl::GetCount() const { return m_main_win
->GetCount(); }
4320 unsigned int wxTreeListCtrl::GetIndent() const
4321 { return m_main_win
->GetIndent(); }
4323 void wxTreeListCtrl::SetIndent(unsigned int indent
)
4324 { m_main_win
->SetIndent(indent
); }
4326 unsigned int wxTreeListCtrl::GetLineSpacing() const
4327 { return m_main_win
->GetLineSpacing(); }
4329 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing
)
4330 { m_main_win
->SetLineSpacing(spacing
); }
4332 wxImageList
* wxTreeListCtrl::GetImageList() const
4333 { return m_main_win
->GetImageList(); }
4335 wxImageList
* wxTreeListCtrl::GetStateImageList() const
4336 { return m_main_win
->GetStateImageList(); }
4338 wxImageList
* wxTreeListCtrl::GetButtonsImageList() const
4339 { return m_main_win
->GetButtonsImageList(); }
4341 void wxTreeListCtrl::SetImageList(wxImageList
* imageList
)
4342 { m_main_win
->SetImageList(imageList
); }
4344 void wxTreeListCtrl::SetStateImageList(wxImageList
* imageList
)
4345 { m_main_win
->SetStateImageList(imageList
); }
4347 void wxTreeListCtrl::SetButtonsImageList(wxImageList
* imageList
)
4348 { m_main_win
->SetButtonsImageList(imageList
); }
4350 void wxTreeListCtrl::AssignImageList(wxImageList
* imageList
)
4351 { m_main_win
->AssignImageList(imageList
); }
4353 void wxTreeListCtrl::AssignStateImageList(wxImageList
* imageList
)
4354 { m_main_win
->AssignStateImageList(imageList
); }
4356 void wxTreeListCtrl::AssignButtonsImageList(wxImageList
* imageList
)
4357 { m_main_win
->AssignButtonsImageList(imageList
); }
4359 wxString
wxTreeListCtrl::GetItemText(const wxTreeItemId
& item
, int column
) const
4360 { return m_main_win
->GetItemText (item
, column
); }
4362 int wxTreeListCtrl::GetItemImage(const wxTreeItemId
& item
, int column
,
4363 wxTreeItemIcon which
) const
4364 { return m_main_win
->GetItemImage(item
, column
, which
); }
4366 wxTreeItemData
* wxTreeListCtrl::GetItemData(const wxTreeItemId
& item
) const
4367 { return m_main_win
->GetItemData(item
); }
4369 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId
& item
) const
4370 { return m_main_win
->GetItemBold(item
); }
4372 wxColour
wxTreeListCtrl::GetItemTextColour(const wxTreeItemId
& item
) const
4373 { return m_main_win
->GetItemTextColour(item
); }
4375 wxColour
wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId
& item
)
4377 { return m_main_win
->GetItemBackgroundColour(item
); }
4379 wxFont
wxTreeListCtrl::GetItemFont(const wxTreeItemId
& item
) const
4380 { return m_main_win
->GetItemFont(item
); }
4383 void wxTreeListCtrl::SetItemText(const wxTreeItemId
& item
, int column
,
4384 const wxString
& text
)
4385 { m_main_win
->SetItemText (item
, column
, text
); }
4387 void wxTreeListCtrl::SetItemImage(const wxTreeItemId
& item
,
4390 wxTreeItemIcon which
)
4391 { m_main_win
->SetItemImage(item
, column
, image
, which
); }
4393 void wxTreeListCtrl::SetItemData(const wxTreeItemId
& item
,
4394 wxTreeItemData
* data
)
4395 { m_main_win
->SetItemData(item
, data
); }
4397 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
)
4398 { m_main_win
->SetItemHasChildren(item
, has
); }
4400 void wxTreeListCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
)
4401 { m_main_win
->SetItemBold(item
, bold
); }
4403 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId
& item
,
4404 const wxColour
& colour
)
4405 { m_main_win
->SetItemTextColour(item
, colour
); }
4407 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
,
4408 const wxColour
& colour
)
4409 { m_main_win
->SetItemBackgroundColour(item
, colour
); }
4411 void wxTreeListCtrl::SetItemFont(const wxTreeItemId
& item
,
4413 { m_main_win
->SetItemFont(item
, font
); }
4415 bool wxTreeListCtrl::SetFont(const wxFont
& font
)
4418 m_header_win
->SetFont(font
);
4419 CalculateAndSetHeaderHeight();
4420 m_header_win
->Refresh();
4423 return m_main_win
->SetFont(font
);
4429 void wxTreeListCtrl::SetWindowStyle(const long style
)
4432 m_main_win
->SetWindowStyle(style
);
4433 m_windowStyle
= style
;
4434 // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4437 long wxTreeListCtrl::GetWindowStyle() const
4439 long style
= m_windowStyle
;
4441 style
|= m_main_win
->GetWindowStyle();
4445 bool wxTreeListCtrl::IsVisible(const wxTreeItemId
& item
, bool fullRow
) const
4446 { return m_main_win
->IsVisible(item
, fullRow
); }
4448 bool wxTreeListCtrl::HasChildren(const wxTreeItemId
& item
) const
4449 { return m_main_win
->HasChildren(item
); }
4451 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId
& item
) const
4452 { return m_main_win
->IsExpanded(item
); }
4454 bool wxTreeListCtrl::IsSelected(const wxTreeItemId
& item
) const
4455 { return m_main_win
->IsSelected(item
); }
4457 bool wxTreeListCtrl::IsBold(const wxTreeItemId
& item
) const
4458 { return m_main_win
->IsBold(item
); }
4460 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool rec
)
4461 { return m_main_win
->GetChildrenCount(item
, rec
); }
4463 wxTreeItemId
wxTreeListCtrl::GetRootItem() const
4464 { return m_main_win
->GetRootItem(); }
4466 wxTreeItemId
wxTreeListCtrl::GetSelection() const
4467 { return m_main_win
->GetSelection(); }
4469 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds
& arr
) const
4470 { return m_main_win
->GetSelections(arr
); }
4472 wxTreeItemId
wxTreeListCtrl::GetItemParent(const wxTreeItemId
& item
) const
4473 { return m_main_win
->GetItemParent(item
); }
4475 #if !wxCHECK_VERSION(2, 5, 0)
4476 wxTreeItemId
wxTreeListCtrl::GetFirstChild (const wxTreeItemId
& item
,
4479 wxTreeItemId
wxTreeListCtrl::GetFirstChild (const wxTreeItemId
& item
,
4480 wxTreeItemIdValue
& cookie
) const
4482 { return m_main_win
->GetFirstChild(item
, cookie
); }
4484 #if !wxCHECK_VERSION(2, 5, 0)
4485 wxTreeItemId
wxTreeListCtrl::GetNextChild (const wxTreeItemId
& item
,
4488 wxTreeItemId
wxTreeListCtrl::GetNextChild (const wxTreeItemId
& item
,
4489 wxTreeItemIdValue
& cookie
) const
4491 { return m_main_win
->GetNextChild(item
, cookie
); }
4493 #if !wxCHECK_VERSION(2, 5, 0)
4494 wxTreeItemId
wxTreeListCtrl::GetPrevChild (const wxTreeItemId
& item
,
4497 wxTreeItemId
wxTreeListCtrl::GetPrevChild (const wxTreeItemId
& item
,
4498 wxTreeItemIdValue
& cookie
) const
4500 { return m_main_win
->GetPrevChild(item
, cookie
); }
4502 #if !wxCHECK_VERSION(2, 5, 0)
4503 wxTreeItemId
wxTreeListCtrl::GetLastChild (const wxTreeItemId
& item
,
4506 wxTreeItemId
wxTreeListCtrl::GetLastChild (const wxTreeItemId
& item
,
4507 wxTreeItemIdValue
& cookie
) const
4509 { return m_main_win
->GetLastChild(item
, cookie
); }
4512 wxTreeItemId
wxTreeListCtrl::GetNextSibling(const wxTreeItemId
& item
) const
4513 { return m_main_win
->GetNextSibling(item
); }
4515 wxTreeItemId
wxTreeListCtrl::GetPrevSibling(const wxTreeItemId
& item
) const
4516 { return m_main_win
->GetPrevSibling(item
); }
4518 wxTreeItemId
wxTreeListCtrl::GetNext(const wxTreeItemId
& item
) const
4519 { return m_main_win
->GetNext(item
, true); }
4521 wxTreeItemId
wxTreeListCtrl::GetPrev(const wxTreeItemId
& item
) const
4522 { return m_main_win
->GetPrev(item
, true); }
4524 wxTreeItemId
wxTreeListCtrl::GetFirstExpandedItem() const
4525 { return m_main_win
->GetFirstExpandedItem(); }
4527 wxTreeItemId
wxTreeListCtrl::GetNextExpanded(const wxTreeItemId
& item
) const
4528 { return m_main_win
->GetNextExpanded(item
); }
4530 wxTreeItemId
wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId
& item
) const
4531 { return m_main_win
->GetPrevExpanded(item
); }
4533 wxTreeItemId
wxTreeListCtrl::GetFirstVisibleItem(bool fullRow
) const
4534 { return m_main_win
->GetFirstVisibleItem(fullRow
); }
4536 wxTreeItemId
wxTreeListCtrl::GetNextVisible(const wxTreeItemId
& item
, bool fullRow
) const
4537 { return m_main_win
->GetNextVisible(item
, fullRow
); }
4539 wxTreeItemId
wxTreeListCtrl::GetPrevVisible(const wxTreeItemId
& item
, bool fullRow
) const
4540 { return m_main_win
->GetPrevVisible(item
, fullRow
); }
4542 wxTreeItemId
wxTreeListCtrl::AddRoot (const wxString
& text
, int image
,
4543 int selectedImage
, wxTreeItemData
* data
)
4544 { return m_main_win
->AddRoot (text
, image
, selectedImage
, data
); }
4546 wxTreeItemId
wxTreeListCtrl::PrependItem(const wxTreeItemId
& parent
,
4547 const wxString
& text
, int image
,
4549 wxTreeItemData
* data
)
4550 { return m_main_win
->PrependItem(parent
, text
, image
, selectedImage
, data
); }
4552 wxTreeItemId
wxTreeListCtrl::InsertItem(const wxTreeItemId
& parent
,
4553 const wxTreeItemId
& previous
,
4554 const wxString
& text
, int image
,
4556 wxTreeItemData
* data
)
4558 return m_main_win
->InsertItem(parent
, previous
, text
, image
,
4559 selectedImage
, data
);
4562 wxTreeItemId
wxTreeListCtrl::InsertItem(const wxTreeItemId
& parent
,
4564 const wxString
& text
, int image
,
4566 wxTreeItemData
* data
)
4568 return m_main_win
->InsertItem(parent
, index
, text
, image
,
4569 selectedImage
, data
);
4572 wxTreeItemId
wxTreeListCtrl::AppendItem(const wxTreeItemId
& parent
,
4573 const wxString
& text
, int image
,
4575 wxTreeItemData
* data
)
4576 { return m_main_win
->AppendItem(parent
, text
, image
, selectedImage
, data
); }
4578 void wxTreeListCtrl::Delete(const wxTreeItemId
& item
)
4579 { m_main_win
->Delete(item
); }
4581 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId
& item
)
4582 { m_main_win
->DeleteChildren(item
); }
4584 void wxTreeListCtrl::DeleteRoot()
4585 { m_main_win
->DeleteRoot(); }
4587 void wxTreeListCtrl::Expand(const wxTreeItemId
& item
)
4588 { m_main_win
->Expand(item
); }
4590 void wxTreeListCtrl::ExpandAll(const wxTreeItemId
& item
)
4591 { m_main_win
->ExpandAll(item
); }
4593 void wxTreeListCtrl::Collapse(const wxTreeItemId
& item
)
4594 { m_main_win
->Collapse(item
); }
4596 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId
& item
)
4597 { m_main_win
->CollapseAndReset(item
); }
4599 void wxTreeListCtrl::Toggle(const wxTreeItemId
& item
)
4600 { m_main_win
->Toggle(item
); }
4602 void wxTreeListCtrl::Unselect()
4603 { m_main_win
->Unselect(); }
4605 void wxTreeListCtrl::UnselectAll()
4606 { m_main_win
->UnselectAll(); }
4608 void wxTreeListCtrl::SelectItem(const wxTreeItemId
& item
, const wxTreeItemId
& last
,
4609 bool unselect_others
)
4610 { m_main_win
->SelectItem (item
, last
, unselect_others
); }
4612 void wxTreeListCtrl::SelectAll()
4613 { m_main_win
->SelectAll(); }
4615 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId
& item
)
4616 { m_main_win
->EnsureVisible(item
); }
4618 void wxTreeListCtrl::ScrollTo(const wxTreeItemId
& item
)
4619 { m_main_win
->ScrollTo(item
); }
4621 wxTreeItemId
wxTreeListCtrl::HitTest(const wxPoint
& pos
, int& flags
, int& column
)
4623 wxPoint p
= m_main_win
->ScreenToClient (ClientToScreen (pos
));
4624 return m_main_win
->HitTest (p
, flags
, column
);
4627 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId
& item
, wxRect
& rect
,
4628 bool textOnly
) const
4629 { return m_main_win
->GetBoundingRect(item
, rect
, textOnly
); }
4631 void wxTreeListCtrl::EditLabel (const wxTreeItemId
& item
, int column
)
4632 { m_main_win
->EditLabel (item
, column
); }
4634 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId
& item1
,
4635 const wxTreeItemId
& item2
)
4637 // do the comparison here, and not delegate to m_main_win, in order
4638 // to let the user override it
4639 //return m_main_win->OnCompareItems(item1, item2);
4640 return wxStrcmp(GetItemText(item1
), GetItemText(item2
));
4643 void wxTreeListCtrl::SortChildren(const wxTreeItemId
& item
)
4644 { m_main_win
->SortChildren(item
); }
4646 wxTreeItemId
wxTreeListCtrl::FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
)
4647 { return m_main_win
->FindItem (item
, str
, mode
); }
4649 void wxTreeListCtrl::SetDragItem (const wxTreeItemId
& item
)
4650 { m_main_win
->SetDragItem (item
); }
4652 bool wxTreeListCtrl::SetBackgroundColour(const wxColour
& colour
)
4654 if (!m_main_win
) return false;
4655 return m_main_win
->SetBackgroundColour(colour
);
4658 bool wxTreeListCtrl::SetForegroundColour(const wxColour
& colour
)
4660 if (!m_main_win
) return false;
4661 return m_main_win
->SetForegroundColour(colour
);
4664 int wxTreeListCtrl::GetColumnCount() const
4665 { return m_main_win
->GetColumnCount(); }
4667 void wxTreeListCtrl::SetColumnWidth(int column
, int width
)
4669 m_header_win
->SetColumnWidth (column
, width
);
4670 m_header_win
->Refresh();
4673 int wxTreeListCtrl::GetColumnWidth(int column
) const
4674 { return m_header_win
->GetColumnWidth(column
); }
4676 void wxTreeListCtrl::SetMainColumn(int column
)
4677 { m_main_win
->SetMainColumn(column
); }
4679 int wxTreeListCtrl::GetMainColumn() const
4680 { return m_main_win
->GetMainColumn(); }
4682 void wxTreeListCtrl::SetColumnText(int column
, const wxString
& text
)
4684 m_header_win
->SetColumnText (column
, text
);
4685 m_header_win
->Refresh();
4688 wxString
wxTreeListCtrl::GetColumnText(int column
) const
4689 { return m_header_win
->GetColumnText(column
); }
4691 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo
& colInfo
)
4693 m_header_win
->AddColumn (colInfo
);
4697 void wxTreeListCtrl::InsertColumn(int before
, const wxTreeListColumnInfo
& colInfo
)
4699 m_header_win
->InsertColumn (before
, colInfo
);
4700 m_header_win
->Refresh();
4703 void wxTreeListCtrl::RemoveColumn(int column
)
4705 m_header_win
->RemoveColumn (column
);
4706 m_header_win
->Refresh();
4709 void wxTreeListCtrl::SetColumn(int column
, const wxTreeListColumnInfo
& colInfo
)
4711 m_header_win
->SetColumn (column
, colInfo
);
4712 m_header_win
->Refresh();
4715 const wxTreeListColumnInfo
& wxTreeListCtrl::GetColumn(int column
) const
4716 { return m_header_win
->GetColumn(column
); }
4718 wxTreeListColumnInfo
& wxTreeListCtrl::GetColumn(int column
)
4719 { return m_header_win
->GetColumn(column
); }
4721 void wxTreeListCtrl::SetColumnImage(int column
, int image
)
4723 m_header_win
->SetColumn (column
, GetColumn(column
).SetImage(image
));
4724 m_header_win
->Refresh();
4727 int wxTreeListCtrl::GetColumnImage(int column
) const
4729 return m_header_win
->GetColumn(column
).GetImage();
4732 void wxTreeListCtrl::SetColumnEditable(int column
, bool shown
)
4734 m_header_win
->SetColumn (column
, GetColumn(column
).SetEditable(shown
));
4737 void wxTreeListCtrl::SetColumnShown(int column
, bool shown
)
4739 wxASSERT_MSG (column
!= GetMainColumn(), _T("The main column may not be hidden") );
4740 m_header_win
->SetColumn (column
, GetColumn(column
).SetShown(GetMainColumn()==column
? true: shown
));
4741 m_header_win
->Refresh();
4744 bool wxTreeListCtrl::IsColumnEditable(int column
) const
4746 return m_header_win
->GetColumn(column
).IsEditable();
4749 bool wxTreeListCtrl::IsColumnShown(int column
) const
4751 return m_header_win
->GetColumn(column
).IsShown();
4754 void wxTreeListCtrl::SetColumnAlignment (int column
, int flag
)
4756 m_header_win
->SetColumn(column
, GetColumn(column
).SetAlignment(flag
));
4757 m_header_win
->Refresh();
4760 int wxTreeListCtrl::GetColumnAlignment(int column
) const
4762 return m_header_win
->GetColumn(column
).GetAlignment();
4765 void wxTreeListCtrl::Refresh(bool erase
, const wxRect
* rect
)
4767 m_main_win
->Refresh (erase
, rect
);
4768 m_header_win
->Refresh (erase
, rect
);
4771 void wxTreeListCtrl::SetFocus()
4772 { m_main_win
->SetFocus(); }
4774 wxSize
wxTreeListCtrl::DoGetBestSize() const
4776 // something is better than nothing...
4777 return wxSize (200,200); // but it should be specified values! FIXME
4780 wxString
wxTreeListCtrl::OnGetItemText( wxTreeItemData
* WXUNUSED(item
), long WXUNUSED(column
)) const
4782 return wxEmptyString
;