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 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
29 #include <wx/treebase.h>
31 #include <wx/textctrl.h>
32 #include <wx/imaglist.h>
33 #include <wx/settings.h>
34 #include <wx/dcclient.h>
35 #include <wx/dcscreen.h>
36 #include <wx/scrolwin.h>
37 #if wxCHECK_VERSION(2, 7, 0)
38 #include <wx/renderer.h>
42 #include "wx/mac/private.h"
45 #include "wx/treelistctrl.h"
48 // ---------------------------------------------------------------------------
50 // ---------------------------------------------------------------------------
54 #if !wxCHECK_VERSION(2, 5, 0)
55 WX_DEFINE_ARRAY(wxTreeListItem
*, wxArrayTreeListItems
);
57 WX_DEFINE_ARRAY_PTR(wxTreeListItem
*, wxArrayTreeListItems
);
60 #include <wx/dynarray.h>
61 WX_DECLARE_OBJARRAY(wxTreeListColumnInfo
, wxArrayTreeListColumnInfo
);
62 #include <wx/arrimpl.cpp>
63 WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo
);
66 // --------------------------------------------------------------------------
68 // --------------------------------------------------------------------------
70 static const int NO_IMAGE
= -1;
72 static const int LINEHEIGHT
= 10;
73 static const int LINEATROOT
= 5;
74 static const int MARGIN
= 2;
75 static const int MININDENT
= 16;
76 static const int BTNWIDTH
= 9;
77 static const int BTNHEIGHT
= 9;
78 static const int EXTRA_WIDTH
= 4;
79 static const int EXTRA_HEIGHT
= 4;
80 static const int HEADER_OFFSET_X
= 1;
81 static const int HEADER_OFFSET_Y
= 1;
83 static const int DRAG_TIMER_TICKS
= 250; // minimum drag wait time in ms
84 static const int FIND_TIMER_TICKS
= 500; // minimum find wait time in ms
85 static const int RENAME_TIMER_TICKS
= 250; // minimum rename wait time in ms
87 const wxChar
* wxTreeListCtrlNameStr
= _T("treelistctrl");
89 static wxTreeListColumnInfo wxInvalidTreeListColumnInfo
;
92 // ---------------------------------------------------------------------------
94 // ---------------------------------------------------------------------------
95 //-----------------------------------------------------------------------------
96 // wxTreeListHeaderWindow (internal)
97 //-----------------------------------------------------------------------------
99 class wxTreeListHeaderWindow
: public wxWindow
102 wxTreeListMainWindow
*m_owner
;
103 const wxCursor
*m_currentCursor
;
104 const wxCursor
*m_resizeCursor
;
107 // column being resized
110 // divider line position in logical (unscrolled) coords
113 // minimal position beyond which the divider line can't be dragged in
117 wxArrayTreeListColumnInfo m_columns
;
119 // total width of the columns
120 int m_total_col_width
;
122 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
123 // which col header is currently highlighted with mouse-over
127 void RefreshColLabel(int col
);
131 wxTreeListHeaderWindow();
133 wxTreeListHeaderWindow( wxWindow
*win
,
135 wxTreeListMainWindow
*owner
,
136 const wxPoint
&pos
= wxDefaultPosition
,
137 const wxSize
&size
= wxDefaultSize
,
139 const wxString
&name
= _T("wxtreelistctrlcolumntitles") );
141 virtual ~wxTreeListHeaderWindow();
143 void DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
);
145 void AdjustDC(wxDC
& dc
);
147 void OnPaint( wxPaintEvent
&event
);
148 void OnMouse( wxMouseEvent
&event
);
149 void OnSetFocus( wxFocusEvent
&event
);
151 // total width of all columns
152 int GetWidth() const { return m_total_col_width
; }
154 // column manipulation
155 int GetColumnCount() const { return m_columns
.GetCount(); }
157 void AddColumn (const wxTreeListColumnInfo
& colInfo
);
159 void InsertColumn (int before
, const wxTreeListColumnInfo
& colInfo
);
161 void RemoveColumn (int column
);
163 // column information manipulation
164 const wxTreeListColumnInfo
& GetColumn (int column
) const{
165 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
166 wxInvalidTreeListColumnInfo
, _T("Invalid column"));
167 return m_columns
[column
];
169 wxTreeListColumnInfo
& GetColumn (int column
) {
170 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
171 wxInvalidTreeListColumnInfo
, _T("Invalid column"));
172 return m_columns
[column
];
174 void SetColumn (int column
, const wxTreeListColumnInfo
& info
);
176 wxString
GetColumnText (int column
) const {
177 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
178 wxEmptyString
, _T("Invalid column"));
179 return m_columns
[column
].GetText();
181 void SetColumnText (int column
, const wxString
& text
) {
182 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()),
183 _T("Invalid column"));
184 m_columns
[column
].SetText (text
);
187 int GetColumnAlignment (int column
) const {
188 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
189 wxALIGN_LEFT
, _T("Invalid column"));
190 return m_columns
[column
].GetAlignment();
192 void SetColumnAlignment (int column
, int flag
) {
193 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()),
194 _T("Invalid column"));
195 m_columns
[column
].SetAlignment (flag
);
198 int GetColumnWidth (int column
) const {
199 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
200 -1, _T("Invalid column"));
201 return m_columns
[column
].GetWidth();
203 void SetColumnWidth (int column
, int width
);
205 bool IsColumnEditable (int column
) const {
206 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
207 false, _T("Invalid column"));
208 return m_columns
[column
].IsEditable();
211 bool IsColumnShown (int column
) const {
212 wxCHECK_MSG ((column
>= 0) && (column
< GetColumnCount()),
213 true, _T("Invalid column"));
214 return m_columns
[column
].IsShown();
221 // common part of all ctors
224 void SendListEvent(wxEventType type
, wxPoint pos
);
226 DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow
)
227 DECLARE_EVENT_TABLE()
231 // this is the "true" control
232 class wxTreeListMainWindow
: public wxScrolledWindow
237 wxTreeListMainWindow() { Init(); }
239 wxTreeListMainWindow (wxTreeListCtrl
*parent
, wxWindowID id
= -1,
240 const wxPoint
& pos
= wxDefaultPosition
,
241 const wxSize
& size
= wxDefaultSize
,
242 long style
= wxTR_DEFAULT_STYLE
,
243 const wxValidator
&validator
= wxDefaultValidator
,
244 const wxString
& name
= _T("wxtreelistmainwindow"))
247 Create (parent
, id
, pos
, size
, style
, validator
, name
);
250 virtual ~wxTreeListMainWindow();
252 bool Create(wxTreeListCtrl
*parent
, wxWindowID id
= -1,
253 const wxPoint
& pos
= wxDefaultPosition
,
254 const wxSize
& size
= wxDefaultSize
,
255 long style
= wxTR_DEFAULT_STYLE
,
256 const wxValidator
&validator
= wxDefaultValidator
,
257 const wxString
& name
= _T("wxtreelistctrl"));
262 // return true if this is a virtual list control
263 bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL
); }
265 // get the total number of items in the control
266 size_t GetCount() const;
268 // indent is the number of pixels the children are indented relative to
269 // the parents position. SetIndent() also redraws the control
271 unsigned int GetIndent() const { return m_indent
; }
272 void SetIndent(unsigned int indent
);
274 // see wxTreeListCtrl for the meaning
275 unsigned int GetLineSpacing() const { return m_linespacing
; }
276 void SetLineSpacing(unsigned int spacing
);
278 // image list: these functions allow to associate an image list with
279 // the control and retrieve it. Note that when assigned with
280 // SetImageList, the control does _not_ delete
281 // the associated image list when it's deleted in order to allow image
282 // lists to be shared between different controls. If you use
283 // AssignImageList, the control _does_ delete the image list.
285 // The normal image list is for the icons which correspond to the
286 // normal tree item state (whether it is selected or not).
287 // Additionally, the application might choose to show a state icon
288 // which corresponds to an app-defined item state (for example,
289 // checked/unchecked) which are taken from the state image list.
290 wxImageList
*GetImageList() const { return m_imageListNormal
; }
291 wxImageList
*GetStateImageList() const { return m_imageListState
; }
292 wxImageList
*GetButtonsImageList() const { return m_imageListButtons
; }
294 void SetImageList(wxImageList
*imageList
);
295 void SetStateImageList(wxImageList
*imageList
);
296 void SetButtonsImageList(wxImageList
*imageList
);
297 void AssignImageList(wxImageList
*imageList
);
298 void AssignStateImageList(wxImageList
*imageList
);
299 void AssignButtonsImageList(wxImageList
*imageList
);
301 // Functions to work with tree ctrl items.
306 // retrieve item's label
307 wxString
GetItemText (const wxTreeItemId
& item
) const
308 { return GetItemText (item
, GetMainColumn()); }
309 wxString
GetItemText (const wxTreeItemId
& item
, int column
) const;
310 wxString
GetItemText (wxTreeItemData
* item
, int column
) const;
312 // get one of the images associated with the item (normal by default)
313 int GetItemImage (const wxTreeItemId
& item
,
314 wxTreeItemIcon which
= wxTreeItemIcon_Normal
) const
315 { return GetItemImage (item
, GetMainColumn(), which
); }
316 int GetItemImage (const wxTreeItemId
& item
, int column
,
317 wxTreeItemIcon which
= wxTreeItemIcon_Normal
) const;
319 // get the data associated with the item
320 wxTreeItemData
*GetItemData(const wxTreeItemId
& item
) const;
322 bool GetItemBold(const wxTreeItemId
& item
) const;
323 wxColour
GetItemTextColour(const wxTreeItemId
& item
) const;
324 wxColour
GetItemBackgroundColour(const wxTreeItemId
& item
) const;
325 wxFont
GetItemFont(const wxTreeItemId
& item
) const;
331 void SetItemText (const wxTreeItemId
& item
, const wxString
& text
)
332 { SetItemText (item
, GetMainColumn(), text
); }
333 void SetItemText (const wxTreeItemId
& item
, int column
, const wxString
& text
);
335 // get one of the images associated with the item (normal by default)
336 void SetItemImage (const wxTreeItemId
& item
, int image
,
337 wxTreeItemIcon which
= wxTreeItemIcon_Normal
)
338 { SetItemImage (item
, GetMainColumn(), image
, which
); }
339 void SetItemImage (const wxTreeItemId
& item
, int column
, int image
,
340 wxTreeItemIcon which
= wxTreeItemIcon_Normal
);
342 // associate some data with the item
343 void SetItemData(const wxTreeItemId
& item
, wxTreeItemData
*data
);
345 // force appearance of [+] button near the item. This is useful to
346 // allow the user to expand the items which don't have any children now
347 // - but instead add them only when needed, thus minimizing memory
348 // usage and loading time.
349 void SetItemHasChildren(const wxTreeItemId
& item
, bool has
= true);
351 // the item will be shown in bold
352 void SetItemBold(const wxTreeItemId
& item
, bool bold
= true);
354 // set the item's text colour
355 void SetItemTextColour(const wxTreeItemId
& item
, const wxColour
& colour
);
357 // set the item's background colour
358 void SetItemBackgroundColour(const wxTreeItemId
& item
, const wxColour
& colour
);
360 // set the item's font (should be of the same height for all items)
361 void SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
);
363 // set the window font
364 virtual bool SetFont( const wxFont
&font
);
366 // set the styles. No need to specify a GetWindowStyle here since
367 // the base wxWindow member function will do it for us
368 void SetWindowStyle(const long styles
);
370 // item status inquiries
371 // ---------------------
373 // is the item visible (it might be outside the view or not expanded)?
374 bool IsVisible(const wxTreeItemId
& item
, bool fullRow
) const;
375 // does the item has any children?
376 bool HasChildren(const wxTreeItemId
& item
) const;
377 // is the item expanded (only makes sense if HasChildren())?
378 bool IsExpanded(const wxTreeItemId
& item
) const;
379 // is this item currently selected (the same as has focus)?
380 bool IsSelected(const wxTreeItemId
& item
) const;
381 // is item text in bold font?
382 bool IsBold(const wxTreeItemId
& item
) const;
383 // does the layout include space for a button?
385 // number of children
386 // ------------------
388 // if 'recursively' is false, only immediate children count, otherwise
389 // the returned number is the number of all items in this branch
390 size_t GetChildrenCount(const wxTreeItemId
& item
, bool recursively
= true);
395 // wxTreeItemId.IsOk() will return false if there is no such item
397 // get the root tree item
398 wxTreeItemId
GetRootItem() const { return m_rootItem
; }
400 // get the item currently selected, only if a single item is selected
401 wxTreeItemId
GetSelection() const { return m_selectItem
; }
403 // get all the items currently selected, return count of items
404 size_t GetSelections(wxArrayTreeItemIds
&) const;
406 // get the parent of this item (may return NULL if root)
407 wxTreeItemId
GetItemParent(const wxTreeItemId
& item
) const;
409 // for this enumeration function you must pass in a "cookie" parameter
410 // which is opaque for the application but is necessary for the library
411 // to make these functions reentrant (i.e. allow more than one
412 // enumeration on one and the same object simultaneously). Of course,
413 // the "cookie" passed to GetFirstChild() and GetNextChild() should be
416 // get child of this item
417 #if !wxCHECK_VERSION(2, 5, 0)
418 wxTreeItemId
GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const;
419 wxTreeItemId
GetNextChild(const wxTreeItemId
& item
, long& cookie
) const;
420 wxTreeItemId
GetPrevChild(const wxTreeItemId
& item
, long& cookie
) const;
421 wxTreeItemId
GetLastChild(const wxTreeItemId
& item
, long& cookie
) const;
423 wxTreeItemId
GetFirstChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
424 wxTreeItemId
GetNextChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
425 wxTreeItemId
GetPrevChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
426 wxTreeItemId
GetLastChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const;
429 // get sibling of this item
430 wxTreeItemId
GetNextSibling(const wxTreeItemId
& item
) const;
431 wxTreeItemId
GetPrevSibling(const wxTreeItemId
& item
) const;
433 // get item in the full tree (currently only for internal use)
434 wxTreeItemId
GetNext(const wxTreeItemId
& item
, bool fulltree
= true) const;
435 wxTreeItemId
GetPrev(const wxTreeItemId
& item
, bool fulltree
= true) const;
437 // get expanded item, see IsExpanded()
438 wxTreeItemId
GetFirstExpandedItem() const;
439 wxTreeItemId
GetNextExpanded(const wxTreeItemId
& item
) const;
440 wxTreeItemId
GetPrevExpanded(const wxTreeItemId
& item
) const;
442 // get visible item, see IsVisible()
443 wxTreeItemId
GetFirstVisibleItem(bool fullRow
) const;
444 wxTreeItemId
GetNextVisible(const wxTreeItemId
& item
, bool fullRow
) const;
445 wxTreeItemId
GetPrevVisible(const wxTreeItemId
& item
, bool fullRow
) const;
450 // add the root node to the tree
451 wxTreeItemId
AddRoot (const wxString
& text
,
452 int image
= -1, int selectedImage
= -1,
453 wxTreeItemData
*data
= NULL
);
455 // insert a new item in as the first child of the parent
456 wxTreeItemId
PrependItem(const wxTreeItemId
& parent
,
457 const wxString
& text
,
458 int image
= -1, int selectedImage
= -1,
459 wxTreeItemData
*data
= NULL
);
461 // insert a new item after a given one
462 wxTreeItemId
InsertItem(const wxTreeItemId
& parent
,
463 const wxTreeItemId
& idPrevious
,
464 const wxString
& text
,
465 int image
= -1, int selectedImage
= -1,
466 wxTreeItemData
*data
= NULL
);
468 // insert a new item before the one with the given index
469 wxTreeItemId
InsertItem(const wxTreeItemId
& parent
,
471 const wxString
& text
,
472 int image
= -1, int selectedImage
= -1,
473 wxTreeItemData
*data
= NULL
);
475 // insert a new item in as the last child of the parent
476 wxTreeItemId
AppendItem(const wxTreeItemId
& parent
,
477 const wxString
& text
,
478 int image
= -1, int selectedImage
= -1,
479 wxTreeItemData
*data
= NULL
);
481 // delete this item and associated data if any
482 void Delete(const wxTreeItemId
& item
);
483 // delete all children (but don't delete the item itself)
484 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
485 void DeleteChildren(const wxTreeItemId
& item
);
486 // delete the root and all its children from the tree
487 // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
491 void Expand(const wxTreeItemId
& item
);
492 // expand this item and all subitems recursively
493 void ExpandAll(const wxTreeItemId
& item
);
494 // collapse the item without removing its children
495 void Collapse(const wxTreeItemId
& item
);
496 // collapse the item and remove all children
497 void CollapseAndReset(const wxTreeItemId
& item
);
498 // toggles the current state
499 void Toggle(const wxTreeItemId
& item
);
501 // remove the selection from currently selected item (if any)
505 void SelectItem(const wxTreeItemId
& item
, const wxTreeItemId
& prev
= (wxTreeItemId
*)NULL
,
506 bool unselect_others
= true);
508 // make sure this item is visible (expanding the parent item and/or
509 // scrolling to this item if necessary)
510 void EnsureVisible(const wxTreeItemId
& item
);
511 // scroll to this item (but don't expand its parent)
512 void ScrollTo(const wxTreeItemId
& item
);
513 void AdjustMyScrollbars();
515 // The first function is more portable (because easier to implement
516 // on other platforms), but the second one returns some extra info.
517 wxTreeItemId
HitTest (const wxPoint
& point
)
518 { int flags
; int column
; return HitTest (point
, flags
, column
); }
519 wxTreeItemId
HitTest (const wxPoint
& point
, int& flags
)
520 { int column
; return HitTest (point
, flags
, column
); }
521 wxTreeItemId
HitTest (const wxPoint
& point
, int& flags
, int& column
);
524 // get the bounding rectangle of the item (or of its label only)
525 bool GetBoundingRect(const wxTreeItemId
& item
,
527 bool textOnly
= false) const;
529 // Start editing the item label: this (temporarily) replaces the item
530 // with a one line edit control. The item will be selected if it hadn't
532 void EditLabel (const wxTreeItemId
& item
, int column
);
535 // this function is called to compare 2 items and should return -1, 0
536 // or +1 if the first item is less than, equal to or greater than the
537 // second one. The base class version performs alphabetic comparaison
538 // of item labels (GetText)
539 virtual int OnCompareItems(const wxTreeItemId
& item1
,
540 const wxTreeItemId
& item2
);
541 // sort the children of this item using OnCompareItems
543 // NB: this function is not reentrant and not MT-safe (FIXME)!
544 void SortChildren(const wxTreeItemId
& item
);
547 wxTreeItemId
FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
= 0);
549 // implementation only from now on
551 // overridden base class virtuals
552 virtual bool SetBackgroundColour(const wxColour
& colour
);
553 virtual bool SetForegroundColour(const wxColour
& colour
);
556 void SetDragItem (const wxTreeItemId
& item
= (wxTreeItemId
*)NULL
);
559 void OnPaint( wxPaintEvent
&event
);
560 void OnSetFocus( wxFocusEvent
&event
);
561 void OnKillFocus( wxFocusEvent
&event
);
562 void OnChar( wxKeyEvent
&event
);
563 void OnMouse( wxMouseEvent
&event
);
564 void OnIdle( wxIdleEvent
&event
);
565 void OnScroll(wxScrollWinEvent
& event
);
567 // implementation helpers
568 void SendDeleteEvent(wxTreeListItem
*itemBeingDeleted
);
570 int GetColumnCount() const
571 { return m_owner
->GetHeaderWindow()->GetColumnCount(); }
573 void SetMainColumn (int column
)
574 { if ((column
>= 0) && (column
< GetColumnCount())) m_main_column
= column
; }
576 int GetMainColumn() const { return m_main_column
; }
578 int GetBestColumnWidth (int column
, wxTreeItemId parent
= wxTreeItemId());
579 int GetItemWidth (int column
, wxTreeListItem
*item
);
580 wxFont
GetItemFont (wxTreeListItem
*item
);
585 wxTreeListCtrl
* m_owner
;
589 friend class wxTreeListItem
;
590 friend class wxTreeListRenameTimer
;
591 friend class wxEditTextCtrl
;
596 wxTreeListItem
*m_rootItem
; // root item
597 wxTreeListItem
*m_curItem
; // current item, either selected or marked
598 wxTreeListItem
*m_shiftItem
; // item, where the shift key was pressed
599 wxTreeListItem
*m_editItem
; // item, which is currently edited
600 wxTreeListItem
*m_selectItem
; // current selected item, not with wxTR_MULTIPLE
601 wxTreeListItem
*m_select_me
;
605 int m_btnWidth
, m_btnWidth2
;
606 int m_btnHeight
, m_btnHeight2
;
607 int m_imgWidth
, m_imgWidth2
;
608 int m_imgHeight
, m_imgHeight2
;
609 unsigned short m_indent
;
611 unsigned short m_linespacing
;
613 wxBrush
*m_hilightBrush
,
614 *m_hilightUnfocusedBrush
;
619 bool m_ownsImageListNormal
,
620 m_ownsImageListState
,
621 m_ownsImageListButtons
;
622 bool m_isDragging
; // true between BEGIN/END drag events
624 bool m_lastOnSame
; // last click on the same item as prev
625 bool m_left_down_selection
;
627 wxImageList
*m_imageListNormal
,
632 wxTimer
*m_dragTimer
;
633 wxTreeListItem
*m_dragItem
;
635 wxTimer
*m_renameTimer
;
636 wxString m_renameRes
;
639 wxTimer
*m_findTimer
;
642 // the common part of all ctors
646 wxTreeItemId
DoInsertItem(const wxTreeItemId
& parent
,
648 const wxString
& text
,
649 int image
, int selectedImage
,
650 wxTreeItemData
*data
);
651 bool HasButtons(void) const
652 { return (m_imageListButtons
) || HasFlag (wxTR_TWIST_BUTTONS
|wxTR_HAS_BUTTONS
); }
655 void CalculateLineHeight();
656 int GetLineHeight(wxTreeListItem
*item
) const;
657 void PaintLevel( wxTreeListItem
*item
, wxDC
& dc
, int level
, int &y
,
659 void PaintItem( wxTreeListItem
*item
, wxDC
& dc
);
661 void CalculateLevel( wxTreeListItem
*item
, wxDC
&dc
, int level
, int &y
,
663 void CalculatePositions();
664 void CalculateSize( wxTreeListItem
*item
, wxDC
&dc
);
666 void RefreshSubtree (wxTreeListItem
*item
);
667 void RefreshLine (wxTreeListItem
*item
);
669 // redraw all selected items
670 void RefreshSelected();
672 // RefreshSelected() recursive helper
673 void RefreshSelectedUnder (wxTreeListItem
*item
);
675 void OnRenameTimer();
676 void OnRenameAccept();
678 void FillArray(wxTreeListItem
*, wxArrayTreeItemIds
&) const;
679 bool TagAllChildrenUntilLast (wxTreeListItem
*crt_item
, wxTreeListItem
*last_item
);
680 bool TagNextChildren (wxTreeListItem
*crt_item
, wxTreeListItem
*last_item
);
681 void UnselectAllChildren (wxTreeListItem
*item
);
684 DECLARE_EVENT_TABLE()
685 DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow
)
689 // timer used for enabling in-place edit
690 class wxTreeListRenameTimer
: public wxTimer
693 wxTreeListRenameTimer( wxTreeListMainWindow
*owner
);
698 wxTreeListMainWindow
*m_owner
;
701 // control used for in-place edit
702 class wxEditTextCtrl
: public wxTextCtrl
705 wxEditTextCtrl (wxWindow
*parent
,
709 wxTreeListMainWindow
*owner
,
710 const wxString
&value
= wxEmptyString
,
711 const wxPoint
&pos
= wxDefaultPosition
,
712 const wxSize
&size
= wxDefaultSize
,
714 const wxValidator
& validator
= wxDefaultValidator
,
715 const wxString
&name
= wxTextCtrlNameStr
);
717 void OnChar( wxKeyEvent
&event
);
718 void OnKeyUp( wxKeyEvent
&event
);
719 void OnKillFocus( wxFocusEvent
&event
);
724 wxTreeListMainWindow
*m_owner
;
725 wxString m_startValue
;
728 DECLARE_EVENT_TABLE()
736 wxTreeListItem() { m_data
= NULL
; }
737 wxTreeListItem( wxTreeListMainWindow
*owner
,
738 wxTreeListItem
*parent
,
739 const wxArrayString
& text
,
742 wxTreeItemData
*data
);
747 wxArrayTreeListItems
& GetChildren() { return m_children
; }
749 const wxString
GetText() const
753 const wxString
GetText (int column
) const
755 if(m_text
.GetCount() > 0)
757 if( IsVirtual() ) return m_owner
->GetItemText( m_data
, column
);
758 else return m_text
[column
];
760 return wxEmptyString
;
763 int GetImage (wxTreeItemIcon which
= wxTreeItemIcon_Normal
) const
764 { return m_images
[which
]; }
765 int GetImage (int column
, wxTreeItemIcon which
=wxTreeItemIcon_Normal
) const
767 if(column
== m_owner
->GetMainColumn()) return m_images
[which
];
768 if(column
< (int)m_col_images
.GetCount()) return m_col_images
[column
];
772 wxTreeItemData
*GetData() const { return m_data
; }
774 // returns the current image for the item (depending on its
775 // selected/expanded/whatever state)
776 int GetCurrentImage() const;
778 void SetText (const wxString
&text
);
779 void SetText (int column
, const wxString
& text
)
781 if (column
< (int)m_text
.GetCount()) {
782 m_text
[column
] = text
;
783 }else if (column
< m_owner
->GetColumnCount()) {
784 int howmany
= m_owner
->GetColumnCount();
785 for (int i
= m_text
.GetCount(); i
< howmany
; ++i
) m_text
.Add (wxEmptyString
);
786 m_text
[column
] = text
;
789 void SetImage (int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; }
790 void SetImage (int column
, int image
, wxTreeItemIcon which
)
792 if (column
== m_owner
->GetMainColumn()) {
793 m_images
[which
] = image
;
794 }else if (column
< (int)m_col_images
.GetCount()) {
795 m_col_images
[column
] = image
;
796 }else if (column
< m_owner
->GetColumnCount()) {
797 int howmany
= m_owner
->GetColumnCount();
798 for (int i
= m_col_images
.GetCount(); i
< howmany
; ++i
) m_col_images
.Add (NO_IMAGE
);
799 m_col_images
[column
] = image
;
803 void SetData(wxTreeItemData
*data
) { m_data
= data
; }
805 void SetHasPlus(bool has
= true) { m_hasPlus
= has
; }
807 void SetBold(bool bold
) { m_isBold
= bold
; }
809 int GetX() const { return m_x
; }
810 int GetY() const { return m_y
; }
812 void SetX (int x
) { m_x
= x
; }
813 void SetY (int y
) { m_y
= y
; }
815 int GetHeight() const { return m_height
; }
816 int GetWidth() const { return m_width
; }
818 void SetHeight (int height
) { m_height
= height
; }
819 void SetWidth (int width
) { m_width
= width
; }
821 int GetTextX() const { return m_text_x
; }
822 void SetTextX (int text_x
) { m_text_x
= text_x
; }
824 wxTreeListItem
*GetItemParent() const { return m_parent
; }
827 // deletes all children notifying the treectrl about it if !NULL
829 void DeleteChildren(wxTreeListMainWindow
*tree
= NULL
);
831 // get count of all children (and grand children if 'recursively')
832 size_t GetChildrenCount(bool recursively
= true) const;
834 void Insert(wxTreeListItem
*child
, size_t index
)
835 { m_children
.Insert(child
, index
); }
837 void GetSize( int &x
, int &y
, const wxTreeListMainWindow
* );
839 // return the item at given position (or NULL if no item), onButton is
840 // true if the point belongs to the item's button, otherwise it lies
841 // on the button's label
842 wxTreeListItem
*HitTest (const wxPoint
& point
,
843 const wxTreeListMainWindow
*,
844 int &flags
, int& column
, int level
);
846 void Expand() { m_isCollapsed
= false; }
847 void Collapse() { m_isCollapsed
= true; }
849 void SetHilight( bool set
= true ) { m_hasHilight
= set
; }
852 bool HasChildren() const { return !m_children
.IsEmpty(); }
853 bool IsSelected() const { return m_hasHilight
!= 0; }
854 bool IsExpanded() const { return !m_isCollapsed
; }
855 bool HasPlus() const { return m_hasPlus
|| HasChildren(); }
856 bool IsBold() const { return m_isBold
!= 0; }
857 bool IsVirtual() const { return m_owner
->IsVirtual(); }
860 // get them - may be NULL
861 wxTreeItemAttr
*GetAttributes() const { return m_attr
; }
862 // get them ensuring that the pointer is not NULL
863 wxTreeItemAttr
& Attr()
867 m_attr
= new wxTreeItemAttr
;
873 void SetAttributes(wxTreeItemAttr
*attr
)
875 if ( m_ownsAttr
) delete m_attr
;
879 // set them and delete when done
880 void AssignAttributes(wxTreeItemAttr
*attr
)
887 wxTreeListMainWindow
*m_owner
; // control the item belongs to
889 // since there can be very many of these, we save size by chosing
890 // the smallest representation for the elements and by ordering
891 // the members to avoid padding.
892 wxArrayString m_text
; // labels to be rendered for item
894 wxTreeItemData
*m_data
; // user-provided data
896 wxArrayTreeListItems m_children
; // list of children
897 wxTreeListItem
*m_parent
; // parent of this item
899 wxTreeItemAttr
*m_attr
; // attributes???
901 // tree ctrl images for the normal, selected, expanded and
902 // expanded+selected states
903 short m_images
[wxTreeItemIcon_Max
];
904 wxArrayShort m_col_images
; // images for the various columns (!= main)
906 // main column item positions
907 wxCoord m_x
; // (virtual) offset from left (vertical line)
908 wxCoord m_y
; // (virtual) offset from top
909 wxCoord m_text_x
; // item offset from left
910 short m_width
; // width of this item
911 unsigned char m_height
; // height of this item
913 // use bitfields to save size
914 int m_isCollapsed
:1;
915 int m_hasHilight
:1; // same as focused
916 int m_hasPlus
:1; // used for item which doesn't have
917 // children but has a [+] button
918 int m_isBold
:1; // render the label in bold font
919 int m_ownsAttr
:1; // delete attribute when done
922 // ===========================================================================
924 // ===========================================================================
927 // ---------------------------------------------------------------------------
929 // ---------------------------------------------------------------------------
931 // check if the given item is under another one
932 static bool IsDescendantOf(const wxTreeListItem
*parent
, const wxTreeListItem
*item
)
936 if ( item
== parent
)
938 // item is a descendant of parent
942 item
= item
->GetItemParent();
949 // ---------------------------------------------------------------------------
950 // wxTreeListRenameTimer (internal)
951 // ---------------------------------------------------------------------------
953 wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow
*owner
)
958 void wxTreeListRenameTimer::Notify()
960 m_owner
->OnRenameTimer();
963 //-----------------------------------------------------------------------------
964 // wxEditTextCtrl (internal)
965 //-----------------------------------------------------------------------------
967 BEGIN_EVENT_TABLE (wxEditTextCtrl
,wxTextCtrl
)
968 EVT_CHAR (wxEditTextCtrl::OnChar
)
969 EVT_KEY_UP (wxEditTextCtrl::OnKeyUp
)
970 EVT_KILL_FOCUS (wxEditTextCtrl::OnKillFocus
)
973 wxEditTextCtrl::wxEditTextCtrl (wxWindow
*parent
,
977 wxTreeListMainWindow
*owner
,
978 const wxString
&value
,
982 const wxValidator
& validator
,
983 const wxString
&name
)
984 : wxTextCtrl (parent
, id
, value
, pos
, size
, style
|wxSIMPLE_BORDER
, validator
, name
)
990 (*m_res
) = wxEmptyString
;
991 m_startValue
= value
;
995 void wxEditTextCtrl::OnChar( wxKeyEvent
&event
)
997 if (event
.GetKeyCode() == WXK_RETURN
)
1000 (*m_res
) = GetValue();
1002 if ((*m_res
) != m_startValue
)
1003 m_owner
->OnRenameAccept();
1005 if (!wxPendingDelete
.Member(this))
1006 wxPendingDelete
.Append(this);
1009 m_owner
->SetFocus(); // This doesn't work. TODO.
1013 if (event
.GetKeyCode() == WXK_ESCAPE
)
1015 (*m_accept
) = false;
1016 (*m_res
) = wxEmptyString
;
1018 if (!wxPendingDelete
.Member(this))
1019 wxPendingDelete
.Append(this);
1022 m_owner
->SetFocus(); // This doesn't work. TODO.
1029 void wxEditTextCtrl::OnKeyUp( wxKeyEvent
&event
)
1037 // auto-grow the textctrl:
1038 wxSize parentSize
= m_owner
->GetSize();
1039 wxPoint myPos
= GetPosition();
1040 wxSize mySize
= GetSize();
1042 GetTextExtent(GetValue() + _T("M"), &sx
, &sy
);
1043 if (myPos
.x
+ sx
> parentSize
.x
) sx
= parentSize
.x
- myPos
.x
;
1044 if (mySize
.x
> sx
) sx
= mySize
.x
;
1050 void wxEditTextCtrl::OnKillFocus( wxFocusEvent
&event
)
1058 if (!wxPendingDelete
.Member(this))
1059 wxPendingDelete
.Append(this);
1062 (*m_res
) = GetValue();
1064 if ((*m_res
) != m_startValue
)
1065 m_owner
->OnRenameAccept();
1068 //-----------------------------------------------------------------------------
1069 // wxTreeListHeaderWindow
1070 //-----------------------------------------------------------------------------
1072 IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow
,wxWindow
);
1074 BEGIN_EVENT_TABLE(wxTreeListHeaderWindow
,wxWindow
)
1075 EVT_PAINT (wxTreeListHeaderWindow::OnPaint
)
1076 EVT_MOUSE_EVENTS (wxTreeListHeaderWindow::OnMouse
)
1077 EVT_SET_FOCUS (wxTreeListHeaderWindow::OnSetFocus
)
1080 void wxTreeListHeaderWindow::Init()
1082 m_currentCursor
= (wxCursor
*) NULL
;
1083 m_isDragging
= false;
1085 m_total_col_width
= 0;
1089 wxTreeListHeaderWindow::wxTreeListHeaderWindow()
1093 m_owner
= (wxTreeListMainWindow
*) NULL
;
1094 m_resizeCursor
= (wxCursor
*) NULL
;
1097 wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow
*win
,
1099 wxTreeListMainWindow
*owner
,
1103 const wxString
&name
)
1104 : wxWindow( win
, id
, pos
, size
, style
, name
)
1109 m_resizeCursor
= new wxCursor(wxCURSOR_SIZEWE
);
1111 #if !wxCHECK_VERSION(2, 5, 0)
1112 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNFACE
));
1114 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE
));
1118 wxTreeListHeaderWindow::~wxTreeListHeaderWindow()
1120 delete m_resizeCursor
;
1123 void wxTreeListHeaderWindow::DoDrawRect( wxDC
*dc
, int x
, int y
, int w
, int h
)
1125 #if !wxCHECK_VERSION(2, 5, 0)
1126 wxPen
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1128 wxPen
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW
), 1, wxSOLID
);
1131 const int m_corner
= 1;
1133 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1134 #if defined( __WXMAC__ )
1137 dc
->SetPen( *wxBLACK_PEN
);
1139 dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h
); // right (outer)
1140 dc
->DrawRectangle( x
, y
+h
, w
+1, 1 ); // bottom (outer)
1142 #if defined( __WXMAC__ )
1143 pen
= wxPen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID
);
1146 dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h
); // right (inner)
1147 dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 ); // bottom (inner)
1149 dc
->SetPen( *wxWHITE_PEN
);
1150 dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 ); // top (outer)
1151 dc
->DrawRectangle( x
, y
, 1, h
); // left (outer)
1152 dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 );
1153 dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 );
1156 // shift the DC origin to match the position of the main window horz
1157 // scrollbar: this allows us to always use logical coords
1158 void wxTreeListHeaderWindow::AdjustDC(wxDC
& dc
)
1161 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1163 m_owner
->GetViewStart( &x
, NULL
);
1165 // account for the horz scrollbar offset
1166 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1169 void wxTreeListHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1172 wxClientDC
dc( this );
1174 wxPaintDC
dc( this );
1180 int x
= HEADER_OFFSET_X
;
1182 // width and height of the entire header window
1184 GetClientSize( &w
, &h
);
1185 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1186 dc
.SetBackgroundMode(wxTRANSPARENT
);
1188 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1189 int numColumns
= GetColumnCount();
1190 for ( int i
= 0; i
< numColumns
&& x
< w
; i
++ )
1192 if (!IsColumnShown (i
)) continue; // do next column if not shown
1194 wxHeaderButtonParams params
;
1196 // TODO: columnInfo should have label colours...
1197 params
.m_labelColour
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT
);
1198 params
.m_labelFont
= GetFont();
1200 wxTreeListColumnInfo
& column
= GetColumn(i
);
1201 int wCol
= column
.GetWidth();
1203 wxRect
rect(x
, 0, wCol
, h
);
1206 if ( i
== m_hotTrackCol
)
1207 flags
|= wxCONTROL_CURRENT
;
1209 params
.m_labelText
= column
.GetText();
1210 params
.m_labelAlignment
= column
.GetAlignment();
1212 int image
= column
.GetImage();
1213 wxImageList
* imageList
= m_owner
->GetImageList();
1214 if ((image
!= -1) && imageList
)
1215 params
.m_labelBitmap
= imageList
->GetBitmap(image
);
1217 wxRendererNative::Get().DrawHeaderButton(this, dc
, rect
, flags
,
1218 wxHDR_SORT_ICON_NONE
, ¶ms
);
1222 wxRect
rect(x
, 0, w
-x
, h
);
1223 wxRendererNative::Get().DrawHeaderButton(this, dc
, rect
);
1226 #else // not 2.7.0.1+
1228 dc
.SetFont( GetFont() );
1230 // do *not* use the listctrl colour for headers - one day we will have a
1231 // function to set it separately
1232 //dc.SetTextForeground( *wxBLACK );
1233 #if !wxCHECK_VERSION(2, 5, 0)
1234 dc
.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT
));
1236 dc
.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT
));
1239 int numColumns
= GetColumnCount();
1240 for ( int i
= 0; i
< numColumns
&& x
< w
; i
++ )
1242 if (!IsColumnShown (i
)) continue; // do next column if not shown
1244 wxTreeListColumnInfo
& column
= GetColumn(i
);
1245 int wCol
= column
.GetWidth();
1247 // the width of the rect to draw: make it smaller to fit entirely
1248 // inside the column rect
1251 #if !wxCHECK_VERSION(2, 7, 0)
1252 dc
.SetPen( *wxWHITE_PEN
);
1253 DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 );
1255 wxRect
rect(x
, HEADER_OFFSET_Y
, cw
, h
-2);
1256 wxRendererNative::GetDefault().DrawHeaderButton (this, dc
, rect
);
1259 // if we have an image, draw it on the right of the label
1260 int image
= column
.GetImage(); //item.m_image;
1261 int ix
= -2, iy
= 0;
1262 wxImageList
* imageList
= m_owner
->GetImageList();
1263 if ((image
!= -1) && imageList
) {
1264 imageList
->GetSize (image
, ix
, iy
);
1267 // extra margins around the text label
1270 int image_offset
= cw
- ix
- 1;
1272 switch(column
.GetAlignment()) {
1274 text_x
+= EXTRA_WIDTH
;
1278 dc
.GetTextExtent (column
.GetText(), &text_width
, NULL
);
1279 text_x
+= cw
- text_width
- EXTRA_WIDTH
- MARGIN
;
1282 case wxALIGN_CENTER
:
1283 dc
.GetTextExtent(column
.GetText(), &text_width
, NULL
);
1284 text_x
+= (cw
- text_width
)/2 + ix
+ 2;
1285 image_offset
= (cw
- text_width
- ix
- 2)/2 - MARGIN
;
1290 if ((image
!= -1) && imageList
) {
1291 imageList
->Draw (image
, dc
, x
+ image_offset
/*cw - ix - 1*/,
1292 HEADER_OFFSET_Y
+ (h
- 4 - iy
)/2,
1293 wxIMAGELIST_DRAW_TRANSPARENT
);
1296 // draw the text clipping it so that it doesn't overwrite the column boundary
1297 wxDCClipper
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h
- 4 );
1298 dc
.DrawText (column
.GetText(), text_x
, HEADER_OFFSET_Y
+ EXTRA_HEIGHT
);
1304 int more_w
= m_owner
->GetSize().x
- x
- HEADER_OFFSET_X
;
1306 #if !wxCHECK_VERSION(2, 7, 0)
1307 DoDrawRect (&dc
, x
, HEADER_OFFSET_Y
, more_w
, h
-2 );
1309 wxRect
rect (x
, HEADER_OFFSET_Y
, more_w
, h
-2);
1310 wxRendererNative::GetDefault().DrawHeaderButton (this, dc
, rect
);
1316 void wxTreeListHeaderWindow::DrawCurrent()
1318 int x1
= m_currentX
;
1320 ClientToScreen (&x1
, &y1
);
1322 int x2
= m_currentX
-1;
1324 ++x2
; // but why ????
1327 m_owner
->GetClientSize( NULL
, &y2
);
1328 m_owner
->ClientToScreen( &x2
, &y2
);
1331 dc
.SetLogicalFunction (wxINVERT
);
1332 dc
.SetPen (wxPen (*wxBLACK
, 2, wxSOLID
));
1333 dc
.SetBrush (*wxTRANSPARENT_BRUSH
);
1336 dc
.DrawLine (x1
, y1
, x2
, y2
);
1337 dc
.SetLogicalFunction (wxCOPY
);
1338 dc
.SetPen (wxNullPen
);
1339 dc
.SetBrush (wxNullBrush
);
1342 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1343 int wxTreeListHeaderWindow::XToCol(int x
)
1346 int numColumns
= GetColumnCount();
1347 for ( int col
= 0; col
< numColumns
; col
++ )
1349 if (!IsColumnShown(col
)) continue;
1350 wxTreeListColumnInfo
& column
= GetColumn(col
);
1352 if ( x
< (colLeft
+ column
.GetWidth()) )
1355 colLeft
+= column
.GetWidth();
1361 void wxTreeListHeaderWindow::RefreshColLabel(int col
)
1363 if ( col
>= GetColumnCount() )
1370 if (!IsColumnShown(idx
)) continue;
1371 wxTreeListColumnInfo
& column
= GetColumn(idx
);
1373 width
= column
.GetWidth();
1374 } while (++idx
<= col
);
1376 m_owner
->CalcScrolledPosition(x
, 0, &x
, NULL
);
1377 RefreshRect(wxRect(x
, 0, width
, GetSize().GetHeight()));
1382 void wxTreeListHeaderWindow::OnMouse (wxMouseEvent
&event
) {
1384 // we want to work with logical coords
1386 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1387 int y
= event
.GetY();
1389 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
1390 if ( event
.Moving() )
1392 int col
= XToCol(x
);
1393 if ( col
!= m_hotTrackCol
)
1395 // Refresh the col header so it will be painted with hot tracking
1396 // (if supported by the native renderer.)
1397 RefreshColLabel(col
);
1399 // Also refresh the old hot header
1400 if ( m_hotTrackCol
>= 0 )
1401 RefreshColLabel(m_hotTrackCol
);
1403 m_hotTrackCol
= col
;
1407 if ( event
.Leaving() && m_hotTrackCol
>= 0 )
1409 // Leaving the window so clear any hot tracking indicator that may be present
1410 RefreshColLabel(m_hotTrackCol
);
1417 SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition());
1419 // we don't draw the line beyond our window, but we allow dragging it
1422 GetClientSize( &w
, NULL
);
1423 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1426 // erase the line if it was drawn
1427 if (m_currentX
< w
) DrawCurrent();
1429 if (event
.ButtonUp()) {
1430 m_isDragging
= false;
1431 if (HasCapture()) ReleaseMouse();
1433 SetColumnWidth (m_column
, m_currentX
- m_minX
);
1435 SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition());
1437 m_currentX
= wxMax (m_minX
+ 7, x
);
1439 // draw in the new location
1440 if (m_currentX
< w
) DrawCurrent();
1443 }else{ // not dragging
1446 bool hit_border
= false;
1448 // end of the current column
1451 // find the column where this event occured
1452 int countCol
= GetColumnCount();
1453 for (int column
= 0; column
< countCol
; column
++) {
1454 if (!IsColumnShown (column
)) continue; // do next if not shown
1456 xpos
+= GetColumnWidth (column
);
1458 if ((abs (x
-xpos
) < 3) && (y
< 22)) {
1459 // near the column border
1465 // inside the column
1472 if (event
.LeftDown() || event
.RightUp()) {
1473 if (hit_border
&& event
.LeftDown()) {
1474 m_isDragging
= true;
1478 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, event
.GetPosition());
1479 }else{ // click on a column
1480 wxEventType evt
= event
.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK
:
1481 wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
;
1482 SendListEvent (evt
, event
.GetPosition());
1484 }else if (event
.LeftDClick() && hit_border
) {
1485 SetColumnWidth (m_column
, m_owner
->GetBestColumnWidth (m_column
));
1488 }else if (event
.Moving()) {
1491 setCursor
= m_currentCursor
== wxSTANDARD_CURSOR
;
1492 m_currentCursor
= m_resizeCursor
;
1494 setCursor
= m_currentCursor
!= wxSTANDARD_CURSOR
;
1495 m_currentCursor
= wxSTANDARD_CURSOR
;
1497 if (setCursor
) SetCursor (*m_currentCursor
);
1503 void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent
&WXUNUSED(event
)) {
1504 m_owner
->SetFocus();
1507 void wxTreeListHeaderWindow::SendListEvent (wxEventType type
, wxPoint pos
) {
1508 wxWindow
*parent
= GetParent();
1509 wxListEvent
le (type
, parent
->GetId());
1510 le
.SetEventObject (parent
);
1511 le
.m_pointDrag
= pos
;
1513 // the position should be relative to the parent window, not
1514 // this one for compatibility with MSW and common sense: the
1515 // user code doesn't know anything at all about this header
1516 // window, so why should it get positions relative to it?
1517 le
.m_pointDrag
.y
-= GetSize().y
;
1518 le
.m_col
= m_column
;
1519 parent
->GetEventHandler()->ProcessEvent (le
);
1522 void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo
& colInfo
) {
1523 m_columns
.Add (colInfo
);
1524 m_total_col_width
+= colInfo
.GetWidth();
1525 m_owner
->AdjustMyScrollbars();
1526 m_owner
->m_dirty
= true;
1529 void wxTreeListHeaderWindow::SetColumnWidth (int column
, int width
) {
1530 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()), _T("Invalid column"));
1531 m_total_col_width
-= m_columns
[column
].GetWidth();
1532 m_columns
[column
].SetWidth(width
);
1533 m_total_col_width
+= width
;
1534 m_owner
->AdjustMyScrollbars();
1535 m_owner
->m_dirty
= true;
1538 void wxTreeListHeaderWindow::InsertColumn (int before
, const wxTreeListColumnInfo
& colInfo
) {
1539 wxCHECK_RET ((before
>= 0) && (before
< GetColumnCount()), _T("Invalid column"));
1540 m_columns
.Insert (colInfo
, before
);
1541 m_total_col_width
+= colInfo
.GetWidth();
1542 m_owner
->AdjustMyScrollbars();
1543 m_owner
->m_dirty
= true;
1546 void wxTreeListHeaderWindow::RemoveColumn (int column
) {
1547 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()), _T("Invalid column"));
1548 m_total_col_width
-= m_columns
[column
].GetWidth();
1549 m_columns
.RemoveAt (column
);
1550 m_owner
->AdjustMyScrollbars();
1551 m_owner
->m_dirty
= true;
1554 void wxTreeListHeaderWindow::SetColumn (int column
, const wxTreeListColumnInfo
& info
) {
1555 wxCHECK_RET ((column
>= 0) && (column
< GetColumnCount()), _T("Invalid column"));
1556 int w
= m_columns
[column
].GetWidth();
1557 m_columns
[column
] = info
;
1558 if (w
!= info
.GetWidth()) {
1559 m_total_col_width
+= info
.GetWidth() - w
;
1560 m_owner
->AdjustMyScrollbars();
1562 m_owner
->m_dirty
= true;
1565 // ---------------------------------------------------------------------------
1567 // ---------------------------------------------------------------------------
1569 wxTreeListItem::wxTreeListItem (wxTreeListMainWindow
*owner
,
1570 wxTreeListItem
*parent
,
1571 const wxArrayString
& text
,
1572 int image
, int selImage
,
1573 wxTreeItemData
*data
)
1576 m_images
[wxTreeItemIcon_Normal
] = image
;
1577 m_images
[wxTreeItemIcon_Selected
] = selImage
;
1578 m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
;
1579 m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
;
1586 m_isCollapsed
= true;
1587 m_hasHilight
= false;
1594 m_attr
= (wxTreeItemAttr
*)NULL
;
1597 // We don't know the height here yet.
1602 wxTreeListItem::~wxTreeListItem() {
1604 if (m_ownsAttr
) delete m_attr
;
1606 wxASSERT_MSG( m_children
.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1609 void wxTreeListItem::DeleteChildren (wxTreeListMainWindow
*tree
) {
1610 size_t count
= m_children
.Count();
1611 for (size_t n
= 0; n
< count
; n
++) {
1612 wxTreeListItem
*child
= m_children
[n
];
1614 tree
->SendDeleteEvent (child
);
1615 if (tree
->m_selectItem
== child
) tree
->m_selectItem
= (wxTreeListItem
*)NULL
;
1617 child
->DeleteChildren (tree
);
1623 void wxTreeListItem::SetText (const wxString
&text
) {
1624 if (m_text
.GetCount() > 0) {
1631 size_t wxTreeListItem::GetChildrenCount (bool recursively
) const {
1632 size_t count
= m_children
.Count();
1633 if (!recursively
) return count
;
1635 size_t total
= count
;
1636 for (size_t n
= 0; n
< count
; ++n
) {
1637 total
+= m_children
[n
]->GetChildrenCount();
1642 void wxTreeListItem::GetSize (int &x
, int &y
, const wxTreeListMainWindow
*theButton
) {
1643 int bottomY
= m_y
+ theButton
->GetLineHeight (this);
1644 if (y
< bottomY
) y
= bottomY
;
1645 int width
= m_x
+ m_width
;
1646 if ( x
< width
) x
= width
;
1649 size_t count
= m_children
.Count();
1650 for (size_t n
= 0; n
< count
; ++n
) {
1651 m_children
[n
]->GetSize (x
, y
, theButton
);
1656 wxTreeListItem
*wxTreeListItem::HitTest (const wxPoint
& point
,
1657 const wxTreeListMainWindow
*theCtrl
,
1658 int &flags
, int& column
, int level
) {
1660 // for a hidden root node, don't evaluate it, but do evaluate children
1661 if (!theCtrl
->HasFlag(wxTR_HIDE_ROOT
) || (level
> 0)) {
1663 // reset any previous hit infos
1666 wxTreeListHeaderWindow
* header_win
= theCtrl
->m_owner
->GetHeaderWindow();
1668 // check for right of all columns (outside)
1669 if (point
.x
> header_win
->GetWidth()) return (wxTreeListItem
*) NULL
;
1671 // evaluate if y-pos is okay
1672 int h
= theCtrl
->GetLineHeight (this);
1673 if ((point
.y
>= m_y
) && (point
.y
<= m_y
+ h
)) {
1675 int maincol
= theCtrl
->GetMainColumn();
1677 // check for above/below middle
1678 int y_mid
= m_y
+ h
/2;
1679 if (point
.y
< y_mid
) {
1680 flags
|= wxTREE_HITTEST_ONITEMUPPERPART
;
1682 flags
|= wxTREE_HITTEST_ONITEMLOWERPART
;
1685 // check for button hit
1686 if (HasPlus() && theCtrl
->HasButtons()) {
1687 int bntX
= m_x
- theCtrl
->m_btnWidth2
;
1688 int bntY
= y_mid
- theCtrl
->m_btnHeight2
;
1689 if ((point
.x
>= bntX
) && (point
.x
<= (bntX
+ theCtrl
->m_btnWidth
)) &&
1690 (point
.y
>= bntY
) && (point
.y
<= (bntY
+ theCtrl
->m_btnHeight
))) {
1691 flags
|= wxTREE_HITTEST_ONITEMBUTTON
;
1697 // check for image hit
1698 if (theCtrl
->m_imgWidth
> 0) {
1699 int imgX
= m_text_x
- theCtrl
->m_imgWidth
- MARGIN
;
1700 int imgY
= y_mid
- theCtrl
->m_imgHeight2
;
1701 if ((point
.x
>= imgX
) && (point
.x
<= (imgX
+ theCtrl
->m_imgWidth
)) &&
1702 (point
.y
>= imgY
) && (point
.y
<= (imgY
+ theCtrl
->m_imgHeight
))) {
1703 flags
|= wxTREE_HITTEST_ONITEMICON
;
1709 // check for label hit
1710 if ((point
.x
>= m_text_x
) && (point
.x
<= (m_text_x
+ m_width
))) {
1711 flags
|= wxTREE_HITTEST_ONITEMLABEL
;
1716 // check for indent hit after button and image hit
1717 if (point
.x
< m_x
) {
1718 flags
|= wxTREE_HITTEST_ONITEMINDENT
;
1719 column
= -1; // considered not belonging to main column
1723 // check for right of label
1725 for (int i
= 0; i
<= maincol
; ++i
) end
+= header_win
->GetColumnWidth (i
);
1726 if ((point
.x
> (m_text_x
+ m_width
)) && (point
.x
<= end
)) {
1727 flags
|= wxTREE_HITTEST_ONITEMRIGHT
;
1728 column
= -1; // considered not belonging to main column
1732 // else check for each column except main
1734 for (int j
= 0; j
< theCtrl
->GetColumnCount(); ++j
) {
1735 if (!header_win
->IsColumnShown(j
)) continue;
1736 int w
= header_win
->GetColumnWidth (j
);
1737 if ((j
!= maincol
) && (point
.x
>= x
&& point
.x
< x
+w
)) {
1738 flags
|= wxTREE_HITTEST_ONITEMCOLUMN
;
1745 // no special flag or column found
1750 // if children not expanded, return no item
1751 if (!IsExpanded()) return (wxTreeListItem
*) NULL
;
1754 // in any case evaluate children
1755 wxTreeListItem
*child
;
1756 size_t count
= m_children
.Count();
1757 for (size_t n
= 0; n
< count
; n
++) {
1758 child
= m_children
[n
]->HitTest (point
, theCtrl
, flags
, column
, level
+1);
1759 if (child
) return child
;
1763 return (wxTreeListItem
*) NULL
;
1766 int wxTreeListItem::GetCurrentImage() const {
1767 int image
= NO_IMAGE
;
1770 image
= GetImage (wxTreeItemIcon_SelectedExpanded
);
1772 image
= GetImage (wxTreeItemIcon_Expanded
);
1774 }else{ // not expanded
1776 image
= GetImage (wxTreeItemIcon_Selected
);
1778 image
= GetImage (wxTreeItemIcon_Normal
);
1782 // maybe it doesn't have the specific image, try the default one instead
1783 if (image
== NO_IMAGE
) image
= GetImage();
1788 // ---------------------------------------------------------------------------
1789 // wxTreeListMainWindow implementation
1790 // ---------------------------------------------------------------------------
1792 IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow
, wxScrolledWindow
)
1794 BEGIN_EVENT_TABLE(wxTreeListMainWindow
, wxScrolledWindow
)
1795 EVT_PAINT (wxTreeListMainWindow::OnPaint
)
1796 EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse
)
1797 EVT_CHAR (wxTreeListMainWindow::OnChar
)
1798 EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus
)
1799 EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus
)
1800 EVT_IDLE (wxTreeListMainWindow::OnIdle
)
1801 EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll
)
1805 // ---------------------------------------------------------------------------
1806 // construction/destruction
1807 // ---------------------------------------------------------------------------
1809 void wxTreeListMainWindow::Init() {
1811 m_rootItem
= (wxTreeListItem
*)NULL
;
1812 m_curItem
= (wxTreeListItem
*)NULL
;
1813 m_shiftItem
= (wxTreeListItem
*)NULL
;
1814 m_editItem
= (wxTreeListItem
*)NULL
;
1815 m_selectItem
= (wxTreeListItem
*)NULL
;
1816 m_select_me
= (wxTreeListItem
*)NULL
;
1818 m_curColumn
= -1; // no current column
1823 m_lineHeight
= LINEHEIGHT
;
1824 m_indent
= MININDENT
; // min. indent
1827 #if !wxCHECK_VERSION(2, 5, 0)
1828 m_hilightBrush
= new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
1829 m_hilightUnfocusedBrush
= new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW
), wxSOLID
);
1831 m_hilightBrush
= new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
);
1832 m_hilightUnfocusedBrush
= new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW
), wxSOLID
);
1835 m_imageListNormal
= (wxImageList
*) NULL
;
1836 m_imageListButtons
= (wxImageList
*) NULL
;
1837 m_imageListState
= (wxImageList
*) NULL
;
1838 m_ownsImageListNormal
= m_ownsImageListButtons
=
1839 m_ownsImageListState
= false;
1841 m_imgWidth
= 0, m_imgWidth2
= 0;
1842 m_imgHeight
= 0, m_imgHeight2
= 0;
1843 m_btnWidth
= 0, m_btnWidth2
= 0;
1844 m_btnHeight
= 0, m_btnHeight2
= 0;
1847 m_isDragging
= false;
1848 m_dragTimer
= new wxTimer (this, -1);
1849 m_dragItem
= (wxTreeListItem
*)NULL
;
1851 m_renameTimer
= new wxTreeListRenameTimer (this);
1852 m_lastOnSame
= false;
1853 m_left_down_selection
= false;
1855 m_findTimer
= new wxTimer (this, -1);
1857 #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
1858 m_normalFont
.MacCreateThemeFont (kThemeViewsFont
);
1860 m_normalFont
= wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT
);
1862 m_boldFont
= wxFont( m_normalFont
.GetPointSize(),
1863 m_normalFont
.GetFamily(),
1864 m_normalFont
.GetStyle(),
1866 m_normalFont
.GetUnderlined(),
1867 m_normalFont
.GetFaceName(),
1868 m_normalFont
.GetEncoding());
1871 bool wxTreeListMainWindow::Create (wxTreeListCtrl
*parent
,
1876 const wxValidator
&validator
,
1877 const wxString
& name
) {
1880 style
&= ~wxTR_LINES_AT_ROOT
;
1881 style
|= wxTR_NO_LINES
;
1884 wxGetOsVersion( &major
, &minor
);
1885 if (major
< 10) style
|= wxTR_ROW_LINES
;
1888 wxScrolledWindow::Create (parent
, id
, pos
, size
, style
|wxHSCROLL
|wxVSCROLL
|wxWANTS_CHARS
, name
);
1890 #if wxUSE_VALIDATORS
1891 SetValidator(validator
);
1894 #if !wxCHECK_VERSION(2, 5, 0)
1895 SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX
));
1897 SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX
));
1905 bdc
.SelectObject(bmp
);
1906 bdc
.SetPen(*wxGREY_PEN
);
1907 bdc
.DrawRectangle(-1, -1, 10, 10);
1908 for (i
= 0; i
< 8; i
++) {
1909 for (j
= 0; j
< 8; j
++) {
1910 if (!((i
+ j
) & 1)) {
1911 bdc
.DrawPoint(i
, j
);
1916 m_dottedPen
= wxPen(bmp
, 1);
1919 //? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86
1920 m_dottedPen
= wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
1929 wxTreeListMainWindow::~wxTreeListMainWindow() {
1930 delete m_hilightBrush
;
1931 delete m_hilightUnfocusedBrush
;
1934 delete m_renameTimer
;
1936 if (m_ownsImageListNormal
) delete m_imageListNormal
;
1937 if (m_ownsImageListState
) delete m_imageListState
;
1938 if (m_ownsImageListButtons
) delete m_imageListButtons
;
1944 //-----------------------------------------------------------------------------
1946 //-----------------------------------------------------------------------------
1948 size_t wxTreeListMainWindow::GetCount() const {
1949 return m_rootItem
== NULL
? 0: m_rootItem
->GetChildrenCount();
1952 void wxTreeListMainWindow::SetIndent (unsigned int indent
) {
1953 m_indent
= wxMax ((unsigned)MININDENT
, indent
);
1957 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing
) {
1958 m_linespacing
= spacing
;
1960 CalculateLineHeight();
1963 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId
& item
,
1965 wxCHECK_MSG (item
.IsOk(), 0u, _T("invalid tree item"));
1966 return ((wxTreeListItem
*)item
.m_pItem
)->GetChildrenCount (recursively
);
1969 void wxTreeListMainWindow::SetWindowStyle (const long styles
) {
1970 // right now, just sets the styles. Eventually, we may
1971 // want to update the inherited styles, but right now
1972 // none of the parents has updatable styles
1973 m_windowStyle
= styles
;
1977 //-----------------------------------------------------------------------------
1978 // functions to work with tree items
1979 //-----------------------------------------------------------------------------
1981 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId
& item
, int column
,
1982 wxTreeItemIcon which
) const {
1983 wxCHECK_MSG (item
.IsOk(), -1, _T("invalid tree item"));
1984 return ((wxTreeListItem
*) item
.m_pItem
)->GetImage (column
, which
);
1987 wxTreeItemData
*wxTreeListMainWindow::GetItemData (const wxTreeItemId
& item
) const {
1988 wxCHECK_MSG (item
.IsOk(), NULL
, _T("invalid tree item"));
1989 return ((wxTreeListItem
*) item
.m_pItem
)->GetData();
1992 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId
& item
) const {
1993 wxCHECK_MSG(item
.IsOk(), false, _T("invalid tree item"));
1994 return ((wxTreeListItem
*)item
.m_pItem
)->IsBold();
1997 wxColour
wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId
& item
) const {
1998 wxCHECK_MSG (item
.IsOk(), wxNullColour
, _T("invalid tree item"));
1999 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2000 return pItem
->Attr().GetTextColour();
2003 wxColour
wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId
& item
) const {
2004 wxCHECK_MSG (item
.IsOk(), wxNullColour
, _T("invalid tree item"));
2005 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2006 return pItem
->Attr().GetBackgroundColour();
2009 wxFont
wxTreeListMainWindow::GetItemFont (const wxTreeItemId
& item
) const {
2010 wxCHECK_MSG (item
.IsOk(), wxNullFont
, _T("invalid tree item"));
2011 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2012 return pItem
->Attr().GetFont();
2015 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId
& item
, int column
,
2016 int image
, wxTreeItemIcon which
) {
2017 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2018 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2019 pItem
->SetImage (column
, image
, which
);
2020 wxClientDC
dc (this);
2021 CalculateSize (pItem
, dc
);
2022 RefreshLine (pItem
);
2025 void wxTreeListMainWindow::SetItemData (const wxTreeItemId
& item
,
2026 wxTreeItemData
*data
) {
2027 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2028 ((wxTreeListItem
*) item
.m_pItem
)->SetData(data
);
2031 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId
& item
,
2033 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2034 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2035 pItem
->SetHasPlus (has
);
2036 RefreshLine (pItem
);
2039 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId
& item
, bool bold
) {
2040 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2041 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2042 if (pItem
->IsBold() != bold
) { // avoid redrawing if no real change
2043 pItem
->SetBold (bold
);
2044 RefreshLine (pItem
);
2048 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId
& item
,
2049 const wxColour
& colour
) {
2050 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2051 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2052 pItem
->Attr().SetTextColour (colour
);
2053 RefreshLine (pItem
);
2056 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId
& item
,
2057 const wxColour
& colour
) {
2058 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2059 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2060 pItem
->Attr().SetBackgroundColour (colour
);
2061 RefreshLine (pItem
);
2064 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId
& item
,
2065 const wxFont
& font
) {
2066 wxCHECK_RET (item
.IsOk(), _T("invalid tree item"));
2067 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2068 pItem
->Attr().SetFont (font
);
2069 RefreshLine (pItem
);
2072 bool wxTreeListMainWindow::SetFont (const wxFont
&font
) {
2073 wxScrolledWindow::SetFont (font
);
2074 m_normalFont
= font
;
2075 m_boldFont
= wxFont (m_normalFont
.GetPointSize(),
2076 m_normalFont
.GetFamily(),
2077 m_normalFont
.GetStyle(),
2079 m_normalFont
.GetUnderlined(),
2080 m_normalFont
.GetFaceName());
2081 CalculateLineHeight();
2086 // ----------------------------------------------------------------------------
2087 // item status inquiries
2088 // ----------------------------------------------------------------------------
2090 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId
& item
, bool fullRow
) const {
2091 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2093 // An item is only visible if it's not a descendant of a collapsed item
2094 wxTreeListItem
*pItem
= (wxTreeListItem
*) item
.m_pItem
;
2095 wxTreeListItem
* parent
= pItem
->GetItemParent();
2097 if (parent
== m_rootItem
&& HasFlag(wxTR_HIDE_ROOT
)) break;
2098 if (!parent
->IsExpanded()) return false;
2099 parent
= parent
->GetItemParent();
2102 wxSize clientSize
= GetClientSize();
2104 if ((!GetBoundingRect (item
, rect
)) ||
2105 ((!fullRow
&& rect
.GetWidth() == 0) || rect
.GetHeight() == 0) ||
2106 (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) ||
2107 (!fullRow
&& (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
))) return false;
2112 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId
& item
) const {
2113 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2115 // consider that the item does have children if it has the "+" button: it
2116 // might not have them (if it had never been expanded yet) but then it
2117 // could have them as well and it's better to err on this side rather than
2118 // disabling some operations which are restricted to the items with
2119 // children for an item which does have them
2120 return ((wxTreeListItem
*) item
.m_pItem
)->HasPlus();
2123 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId
& item
) const {
2124 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2125 return ((wxTreeListItem
*) item
.m_pItem
)->IsExpanded();
2128 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId
& item
) const {
2129 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2130 return ((wxTreeListItem
*) item
.m_pItem
)->IsSelected();
2133 bool wxTreeListMainWindow::IsBold (const wxTreeItemId
& item
) const {
2134 wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item"));
2135 return ((wxTreeListItem
*) item
.m_pItem
)->IsBold();
2138 // ----------------------------------------------------------------------------
2140 // ----------------------------------------------------------------------------
2142 wxTreeItemId
wxTreeListMainWindow::GetItemParent (const wxTreeItemId
& item
) const {
2143 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2144 return ((wxTreeListItem
*) item
.m_pItem
)->GetItemParent();
2147 #if !wxCHECK_VERSION(2, 5, 0)
2148 wxTreeItemId
wxTreeListMainWindow::GetFirstChild (const wxTreeItemId
& item
,
2149 long& cookie
) const {
2151 wxTreeItemId
wxTreeListMainWindow::GetFirstChild (const wxTreeItemId
& item
,
2152 wxTreeItemIdValue
& cookie
) const {
2154 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2155 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2157 return (!children
.IsEmpty())? wxTreeItemId(children
.Item(0)): wxTreeItemId();
2160 #if !wxCHECK_VERSION(2, 5, 0)
2161 wxTreeItemId
wxTreeListMainWindow::GetNextChild (const wxTreeItemId
& item
,
2162 long& cookie
) const {
2164 wxTreeItemId
wxTreeListMainWindow::GetNextChild (const wxTreeItemId
& item
,
2165 wxTreeItemIdValue
& cookie
) const {
2167 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2168 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2169 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2170 long *pIndex
= ((long*)&cookie
);
2171 return ((*pIndex
)+1 < (long)children
.Count())? wxTreeItemId(children
.Item(++(*pIndex
))): wxTreeItemId();
2174 #if !wxCHECK_VERSION(2, 5, 0)
2175 wxTreeItemId
wxTreeListMainWindow::GetPrevChild (const wxTreeItemId
& item
,
2176 long& cookie
) const {
2178 wxTreeItemId
wxTreeListMainWindow::GetPrevChild (const wxTreeItemId
& item
,
2179 wxTreeItemIdValue
& cookie
) const {
2181 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2182 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2183 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2184 long *pIndex
= (long*)&cookie
;
2185 return ((*pIndex
)-1 >= 0)? wxTreeItemId(children
.Item(--(*pIndex
))): wxTreeItemId();
2188 #if !wxCHECK_VERSION(2, 5, 0)
2189 wxTreeItemId
wxTreeListMainWindow::GetLastChild (const wxTreeItemId
& item
,
2190 long& cookie
) const {
2192 wxTreeItemId
wxTreeListMainWindow::GetLastChild (const wxTreeItemId
& item
,
2193 wxTreeItemIdValue
& cookie
) const {
2195 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2196 wxArrayTreeListItems
& children
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren();
2197 // it's ok to cast cookie to long, we never have indices which overflow "void*"
2198 long *pIndex
= ((long*)&cookie
);
2199 (*pIndex
) = children
.Count();
2200 return (!children
.IsEmpty())? wxTreeItemId(children
.Last()): wxTreeItemId();
2203 wxTreeItemId
wxTreeListMainWindow::GetNextSibling (const wxTreeItemId
& item
) const {
2204 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2207 wxTreeListItem
*i
= (wxTreeListItem
*) item
.m_pItem
;
2208 wxTreeListItem
*parent
= i
->GetItemParent();
2209 if (!parent
) return wxTreeItemId(); // root item doesn't have any siblings
2212 wxArrayTreeListItems
& siblings
= parent
->GetChildren();
2213 size_t index
= siblings
.Index (i
);
2214 wxASSERT (index
!= (size_t)wxNOT_FOUND
); // I'm not a child of my parent?
2215 return (index
< siblings
.Count()-1)? wxTreeItemId(siblings
[index
+1]): wxTreeItemId();
2218 wxTreeItemId
wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId
& item
) const {
2219 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2222 wxTreeListItem
*i
= (wxTreeListItem
*) item
.m_pItem
;
2223 wxTreeListItem
*parent
= i
->GetItemParent();
2224 if (!parent
) return wxTreeItemId(); // root item doesn't have any siblings
2227 wxArrayTreeListItems
& siblings
= parent
->GetChildren();
2228 size_t index
= siblings
.Index(i
);
2229 wxASSERT (index
!= (size_t)wxNOT_FOUND
); // I'm not a child of my parent?
2230 return (index
>= 1)? wxTreeItemId(siblings
[index
-1]): wxTreeItemId();
2233 // Only for internal use right now, but should probably be public
2234 wxTreeItemId
wxTreeListMainWindow::GetNext (const wxTreeItemId
& item
, bool fulltree
) const {
2235 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2237 // if there are any children, return first child
2238 if (fulltree
|| ((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) {
2239 wxArrayTreeListItems
& children
= ((wxTreeListItem
*)item
.m_pItem
)->GetChildren();
2240 if (children
.GetCount() > 0) return children
.Item (0);
2243 // get sibling of this item or of the ancestors instead
2245 wxTreeItemId parent
= item
;
2247 next
= GetNextSibling (parent
);
2248 parent
= GetItemParent (parent
);
2249 } while (!next
.IsOk() && parent
.IsOk());
2253 // Only for internal use right now, but should probably be public
2254 wxTreeItemId
wxTreeListMainWindow::GetPrev (const wxTreeItemId
& item
, bool fulltree
) const {
2255 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2257 // if there are any children, return last child
2258 if (fulltree
|| ((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) {
2259 wxArrayTreeListItems
& children
= ((wxTreeListItem
*)item
.m_pItem
)->GetChildren();
2260 if (children
.GetCount() > 0) return children
.Item (children
.GetCount()-1);
2263 // get sibling of this item or of the ancestors instead
2265 wxTreeItemId parent
= item
;
2267 next
= GetPrevSibling (parent
);
2268 parent
= GetItemParent (parent
);
2269 } while (!next
.IsOk() && parent
.IsOk());
2273 wxTreeItemId
wxTreeListMainWindow::GetFirstExpandedItem() const {
2274 return GetNextExpanded (GetRootItem());
2277 wxTreeItemId
wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId
& item
) const {
2278 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2279 return GetNext (item
, false);
2282 wxTreeItemId
wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId
& item
) const {
2283 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2284 return GetPrev (item
, false);
2287 wxTreeItemId
wxTreeListMainWindow::GetFirstVisibleItem (bool fullRow
) const {
2288 return GetNextVisible (GetRootItem(), fullRow
);
2291 wxTreeItemId
wxTreeListMainWindow::GetNextVisible (const wxTreeItemId
& item
, bool fullRow
) const {
2292 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2293 wxTreeItemId id
= GetNext (item
, false);
2295 if (IsVisible (id
, fullRow
)) return id
;
2296 id
= GetNext (id
, false);
2298 return wxTreeItemId();
2301 wxTreeItemId
wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId
& item
, bool fullRow
) const {
2302 wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2303 wxTreeItemId id
= GetPrev (item
, true);
2305 if (IsVisible (id
, fullRow
)) return id
;
2306 id
= GetPrev(id
, true);
2308 return wxTreeItemId();
2311 // ----------------------------------------------------------------------------
2313 // ----------------------------------------------------------------------------
2315 wxTreeItemId
wxTreeListMainWindow::DoInsertItem (const wxTreeItemId
& parentId
,
2317 const wxString
& text
,
2318 int image
, int selImage
,
2319 wxTreeItemData
*data
) {
2320 wxTreeListItem
*parent
= (wxTreeListItem
*)parentId
.m_pItem
;
2321 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2322 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2325 arr
.Alloc (GetColumnCount());
2326 for (int i
= 0; i
< (int)GetColumnCount(); ++i
) arr
.Add (wxEmptyString
);
2327 arr
[m_main_column
] = text
;
2328 wxTreeListItem
*item
= new wxTreeListItem (this, parent
, arr
, image
, selImage
, data
);
2330 #if !wxCHECK_VERSION(2, 5, 0)
2331 data
->SetId ((long)item
);
2336 parent
->Insert (item
, previous
);
2341 wxTreeItemId
wxTreeListMainWindow::AddRoot (const wxString
& text
,
2342 int image
, int selImage
,
2343 wxTreeItemData
*data
) {
2344 wxCHECK_MSG(!m_rootItem
, wxTreeItemId(), _T("tree can have only one root"));
2345 wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2346 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2349 arr
.Alloc (GetColumnCount());
2350 for (int i
= 0; i
< (int)GetColumnCount(); ++i
) arr
.Add (wxEmptyString
);
2351 arr
[m_main_column
] = text
;
2352 m_rootItem
= new wxTreeListItem (this, (wxTreeListItem
*)NULL
, arr
, image
, selImage
, data
);
2354 #if !wxCHECK_VERSION(2, 5, 0)
2355 data
->SetId((long)m_rootItem
);
2357 data
->SetId(m_rootItem
);
2360 if (HasFlag(wxTR_HIDE_ROOT
)) {
2361 // if we will hide the root, make sure children are visible
2362 m_rootItem
->SetHasPlus();
2363 m_rootItem
->Expand();
2364 #if !wxCHECK_VERSION(2, 5, 0)
2367 wxTreeItemIdValue cookie
= 0;
2369 m_curItem
= (wxTreeListItem
*)GetFirstChild (m_rootItem
, cookie
).m_pItem
;
2374 wxTreeItemId
wxTreeListMainWindow::PrependItem (const wxTreeItemId
& parent
,
2375 const wxString
& text
,
2376 int image
, int selImage
,
2377 wxTreeItemData
*data
) {
2378 return DoInsertItem (parent
, 0u, text
, image
, selImage
, data
);
2381 wxTreeItemId
wxTreeListMainWindow::InsertItem (const wxTreeItemId
& parentId
,
2382 const wxTreeItemId
& idPrevious
,
2383 const wxString
& text
,
2384 int image
, int selImage
,
2385 wxTreeItemData
*data
) {
2386 wxTreeListItem
*parent
= (wxTreeListItem
*)parentId
.m_pItem
;
2387 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2389 int index
= parent
->GetChildren().Index((wxTreeListItem
*) idPrevious
.m_pItem
);
2390 wxASSERT_MSG( index
!= wxNOT_FOUND
,
2391 _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
2393 return DoInsertItem (parentId
, ++index
, text
, image
, selImage
, data
);
2396 wxTreeItemId
wxTreeListMainWindow::InsertItem (const wxTreeItemId
& parentId
,
2398 const wxString
& text
,
2399 int image
, int selImage
,
2400 wxTreeItemData
*data
) {
2401 wxTreeListItem
*parent
= (wxTreeListItem
*)parentId
.m_pItem
;
2402 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2404 return DoInsertItem (parentId
, before
, text
, image
, selImage
, data
);
2407 wxTreeItemId
wxTreeListMainWindow::AppendItem (const wxTreeItemId
& parentId
,
2408 const wxString
& text
,
2409 int image
, int selImage
,
2410 wxTreeItemData
*data
) {
2411 wxTreeListItem
*parent
= (wxTreeListItem
*) parentId
.m_pItem
;
2412 wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") );
2414 return DoInsertItem (parent
, parent
->GetChildren().Count(), text
, image
, selImage
, data
);
2417 void wxTreeListMainWindow::SendDeleteEvent (wxTreeListItem
*item
) {
2418 // send event to user code
2419 wxTreeEvent
event (wxEVT_COMMAND_TREE_DELETE_ITEM
, m_owner
->GetId());
2420 #if !wxCHECK_VERSION(2, 5, 0)
2421 event
.SetItem ((long)item
);
2423 event
.SetItem (item
);
2425 event
.SetEventObject (m_owner
);
2426 m_owner
->ProcessEvent (event
);
2429 void wxTreeListMainWindow::Delete (const wxTreeItemId
& itemId
) {
2430 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2431 wxCHECK_RET (item
!= m_rootItem
, _T("invalid item, root may not be deleted this way!"));
2432 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2434 // don't stay with invalid m_shiftItem or we will crash in the next call to OnChar()
2435 bool changeKeyCurrent
= false;
2436 wxTreeListItem
*itemKey
= m_shiftItem
;
2438 if (itemKey
== item
) { // m_shiftItem is a descendant of the item being deleted
2439 changeKeyCurrent
= true;
2442 itemKey
= itemKey
->GetItemParent();
2445 wxTreeListItem
*parent
= item
->GetItemParent();
2448 // m_select_me records whether we need to select
2449 // a different item, in idle time.
2450 if ( m_select_me
&& IsDescendantOf(item
, m_select_me
) )
2452 m_select_me
= parent
;
2455 if ( IsDescendantOf(item
, m_curItem
) )
2457 // Don't silently change the selection:
2458 // do it properly in idle time, so event
2459 // handlers get called.
2461 // m_current = parent;
2463 m_select_me
= parent
;
2466 // remove the item from the tree
2468 parent
->GetChildren().Remove (item
); // remove by value
2470 if (changeKeyCurrent
) m_shiftItem
= parent
;
2472 SendDeleteEvent (item
);
2473 if (m_selectItem
== item
) m_selectItem
= (wxTreeListItem
*)NULL
;
2474 item
->DeleteChildren (this);
2476 if (item
== m_select_me
)
2482 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId
& itemId
) {
2483 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2484 m_dirty
= true; // do this first so stuff below doesn't cause flicker
2486 item
->DeleteChildren (this);
2489 void wxTreeListMainWindow::DeleteRoot() {
2492 SendDeleteEvent (m_rootItem
);
2493 m_curItem
= (wxTreeListItem
*)NULL
;
2494 m_selectItem
= (wxTreeListItem
*)NULL
;
2495 m_rootItem
->DeleteChildren (this);
2501 void wxTreeListMainWindow::Expand (const wxTreeItemId
& itemId
) {
2502 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2503 wxCHECK_RET (item
, _T("invalid item in wxTreeListMainWindow::Expand") );
2505 if (!item
->HasPlus() || item
->IsExpanded()) return;
2507 // send event to user code
2508 wxTreeEvent
event (wxEVT_COMMAND_TREE_ITEM_EXPANDING
, m_owner
->GetId());
2509 #if !wxCHECK_VERSION(2, 5, 0)
2510 event
.SetItem ((long)item
);
2512 event
.SetItem (item
);
2514 event
.SetEventObject (m_owner
);
2515 if (m_owner
->ProcessEvent (event
) && !event
.IsAllowed()) return; // expand canceled
2520 // send event to user code
2521 event
.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED
);
2522 m_owner
->ProcessEvent (event
);
2525 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId
& itemId
) {
2527 if (!IsExpanded (itemId
)) return;
2528 #if !wxCHECK_VERSION(2, 5, 0)
2531 wxTreeItemIdValue cookie
;
2533 wxTreeItemId child
= GetFirstChild (itemId
, cookie
);
2534 while (child
.IsOk()) {
2536 child
= GetNextChild (itemId
, cookie
);
2540 void wxTreeListMainWindow::Collapse (const wxTreeItemId
& itemId
) {
2541 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2542 wxCHECK_RET (item
, _T("invalid item in wxTreeListMainWindow::Collapse") );
2544 if (!item
->HasPlus() || !item
->IsExpanded()) return;
2546 // send event to user code
2547 wxTreeEvent
event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, m_owner
->GetId() );
2548 #if !wxCHECK_VERSION(2, 5, 0)
2549 event
.SetItem ((long)item
);
2551 event
.SetItem (item
);
2553 event
.SetEventObject (m_owner
);
2554 if (m_owner
->ProcessEvent (event
) && !event
.IsAllowed()) return; // collapse canceled
2559 // send event to user code
2560 event
.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED
);
2561 ProcessEvent (event
);
2564 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId
& item
) {
2566 DeleteChildren (item
);
2569 void wxTreeListMainWindow::Toggle (const wxTreeItemId
& itemId
) {
2570 if (IsExpanded (itemId
)) {
2577 void wxTreeListMainWindow::Unselect() {
2579 m_selectItem
->SetHilight (false);
2580 RefreshLine (m_selectItem
);
2581 m_selectItem
= (wxTreeListItem
*)NULL
;
2585 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem
*item
) {
2586 if (item
->IsSelected()) {
2587 item
->SetHilight (false);
2589 if (item
== m_selectItem
) m_selectItem
= (wxTreeListItem
*)NULL
;
2591 if (item
->HasChildren()) {
2592 wxArrayTreeListItems
& children
= item
->GetChildren();
2593 size_t count
= children
.Count();
2594 for (size_t n
= 0; n
< count
; ++n
) {
2595 UnselectAllChildren (children
[n
]);
2600 void wxTreeListMainWindow::UnselectAll() {
2601 UnselectAllChildren ((wxTreeListItem
*)GetRootItem().m_pItem
);
2604 // Recursive function !
2605 // To stop we must have crt_item<last_item
2607 // Tag all next children, when no more children,
2608 // Move to parent (not to tag)
2609 // Keep going... if we found last_item, we stop.
2610 bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem
*crt_item
,
2611 wxTreeListItem
*last_item
) {
2612 wxTreeListItem
*parent
= crt_item
->GetItemParent();
2614 if (!parent
) {// This is root item
2615 return TagAllChildrenUntilLast (crt_item
, last_item
);
2618 wxArrayTreeListItems
& children
= parent
->GetChildren();
2619 int index
= children
.Index(crt_item
);
2620 wxASSERT (index
!= wxNOT_FOUND
); // I'm not a child of my parent?
2622 if ((parent
->HasChildren() && parent
->IsExpanded()) ||
2623 ((parent
== (wxTreeListItem
*)GetRootItem().m_pItem
) && HasFlag(wxTR_HIDE_ROOT
))) {
2624 size_t count
= children
.Count();
2625 for (size_t n
= (index
+1); n
< count
; ++n
) {
2626 if (TagAllChildrenUntilLast (children
[n
], last_item
)) return true;
2630 return TagNextChildren (parent
, last_item
);
2633 bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem
*crt_item
,
2634 wxTreeListItem
*last_item
) {
2635 crt_item
->SetHilight (true);
2636 RefreshLine(crt_item
);
2638 if (crt_item
==last_item
) return true;
2640 if (crt_item
->HasChildren() && crt_item
->IsExpanded()) {
2641 wxArrayTreeListItems
& children
= crt_item
->GetChildren();
2642 size_t count
= children
.Count();
2643 for (size_t n
= 0; n
< count
; ++n
) {
2644 if (TagAllChildrenUntilLast (children
[n
], last_item
)) return true;
2651 void wxTreeListMainWindow::SelectItem (const wxTreeItemId
& itemId
,
2652 const wxTreeItemId
& lastId
,
2653 bool unselect_others
) {
2654 wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item") );
2656 bool is_single
= !HasFlag(wxTR_MULTIPLE
);
2657 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2659 // single selection requires unselect others
2660 if (is_single
) unselect_others
= true;
2662 // send event to the user code
2663 wxTreeEvent
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, m_owner
->GetId() );
2664 #if !wxCHECK_VERSION(2, 5, 0)
2665 event
.SetItem ((long)item
);
2666 event
.SetOldItem ((long)m_curItem
);
2668 event
.SetItem (item
);
2669 event
.SetOldItem (m_curItem
);
2671 event
.SetEventObject (m_owner
);
2672 if (m_owner
->GetEventHandler()->ProcessEvent (event
) && !event
.IsAllowed()) return;
2674 // unselect all if unselect other items
2675 bool unselected
= false; // see that UnselectAll is done only once
2676 if (unselect_others
) {
2678 Unselect(); // to speed up thing
2685 // select item or item range
2686 if (lastId
.IsOk() && (itemId
!= lastId
)) {
2688 if (!unselected
) UnselectAll();
2689 wxTreeListItem
*last
= (wxTreeListItem
*) lastId
.m_pItem
;
2691 // ensure that the position of the item it calculated in any case
2692 if (m_dirty
) CalculatePositions();
2694 // select item range according Y-position
2695 if (last
->GetY() < item
->GetY()) {
2696 if (!TagAllChildrenUntilLast (last
, item
)) {
2697 TagNextChildren (last
, item
);
2700 if (!TagAllChildrenUntilLast (item
, last
)) {
2701 TagNextChildren (item
, last
);
2707 // select item according its old selection
2708 item
->SetHilight (!item
->IsSelected());
2710 if (unselect_others
) {
2711 m_selectItem
= (item
->IsSelected())? item
: (wxTreeListItem
*)NULL
;
2715 // send event to user code
2716 event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
);
2717 m_owner
->GetEventHandler()->ProcessEvent (event
);
2720 void wxTreeListMainWindow::SelectAll() {
2721 wxCHECK_RET (HasFlag(wxTR_MULTIPLE
), _T("invalid tree style, must have wxTR_MULTIPLE style to select all items"));
2723 // send event to user code
2724 wxTreeEvent
event (wxEVT_COMMAND_TREE_SEL_CHANGING
, m_owner
->GetId());
2725 event
.SetItem (GetRootItem());
2726 #if !wxCHECK_VERSION(2, 5, 0)
2727 event
.SetOldItem ((long)m_curItem
);
2729 event
.SetOldItem (m_curItem
);
2731 event
.SetEventObject (m_owner
);
2732 if (m_owner
->GetEventHandler()->ProcessEvent (event
) && !event
.IsAllowed()) return;
2734 #if !wxCHECK_VERSION(2, 5, 0)
2737 wxTreeItemIdValue cookie
= 0;
2739 wxTreeItemId root
= GetRootItem();
2740 wxTreeListItem
*first
= (wxTreeListItem
*)GetFirstChild (root
, cookie
).m_pItem
;
2741 wxTreeListItem
*last
= (wxTreeListItem
*)GetLastChild (root
, cookie
).m_pItem
;
2742 if (!first
|| !last
) return;
2743 if (!TagAllChildrenUntilLast (first
, last
)) {
2744 TagNextChildren (first
, last
);
2747 // send event to user code
2748 event
.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED
);
2749 m_owner
->GetEventHandler()->ProcessEvent (event
);
2752 void wxTreeListMainWindow::FillArray (wxTreeListItem
*item
,
2753 wxArrayTreeItemIds
&array
) const {
2754 if (item
->IsSelected()) array
.Add (wxTreeItemId(item
));
2756 if (item
->HasChildren()) {
2757 wxArrayTreeListItems
& children
= item
->GetChildren();
2758 size_t count
= children
.GetCount();
2759 for (size_t n
= 0; n
< count
; ++n
) FillArray (children
[n
], array
);
2763 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds
&array
) const {
2765 wxTreeItemId idRoot
= GetRootItem();
2766 if (idRoot
.IsOk()) FillArray ((wxTreeListItem
*) idRoot
.m_pItem
, array
);
2767 return array
.Count();
2770 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId
& item
) {
2771 if (!item
.IsOk()) return; // do nothing if no item
2773 // first expand all parent branches
2774 wxTreeListItem
*gitem
= (wxTreeListItem
*) item
.m_pItem
;
2775 wxTreeListItem
*parent
= gitem
->GetItemParent();
2778 parent
= parent
->GetItemParent();
2782 RefreshLine (gitem
);
2785 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId
&item
) {
2786 if (!item
.IsOk()) return; // do nothing if no item
2788 // ensure that the position of the item it calculated in any case
2789 if (m_dirty
) CalculatePositions();
2791 wxTreeListItem
*gitem
= (wxTreeListItem
*) item
.m_pItem
;
2793 // now scroll to the item
2794 int item_y
= gitem
->GetY();
2797 GetScrollPixelsPerUnit (&xUnit
, &yUnit
);
2800 GetViewStart (&start_x
, &start_y
);
2805 GetClientSize (&client_w
, &client_h
);
2809 m_rootItem
->GetSize (x
, y
, this);
2810 x
= m_owner
->GetHeaderWindow()->GetWidth();
2811 y
+= yUnit
+ 2; // one more scrollbar unit + 2 pixels
2812 int x_pos
= GetScrollPos( wxHORIZONTAL
);
2814 if (item_y
< start_y
+3) {
2815 // going down, item should appear at top
2816 SetScrollbars (xUnit
, yUnit
, xUnit
? x
/xUnit
: 0, yUnit
? y
/yUnit
: 0, x_pos
, yUnit
? item_y
/yUnit
: 0);
2817 }else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) {
2818 // going up, item should appear at bottom
2819 item_y
+= yUnit
+ 2;
2820 SetScrollbars (xUnit
, yUnit
, xUnit
? x
/xUnit
: 0, yUnit
? y
/yUnit
: 0, x_pos
, yUnit
? (item_y
+GetLineHeight(gitem
)-client_h
)/yUnit
: 0 );
2824 // FIXME: tree sorting functions are not reentrant and not MT-safe!
2825 static wxTreeListMainWindow
*s_treeBeingSorted
= NULL
;
2827 static int LINKAGEMODE
tree_ctrl_compare_func(wxTreeListItem
**item1
,
2828 wxTreeListItem
**item2
)
2830 wxCHECK_MSG (s_treeBeingSorted
, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
2832 return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
);
2835 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId
& item1
,
2836 const wxTreeItemId
& item2
)
2838 return m_owner
->OnCompareItems (item1
, item2
);
2841 void wxTreeListMainWindow::SortChildren (const wxTreeItemId
& itemId
) {
2842 wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item"));
2844 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
2846 wxCHECK_RET (!s_treeBeingSorted
,
2847 _T("wxTreeListMainWindow::SortChildren is not reentrant") );
2849 wxArrayTreeListItems
& children
= item
->GetChildren();
2850 if ( children
.Count() > 1 ) {
2852 s_treeBeingSorted
= this;
2853 children
.Sort(tree_ctrl_compare_func
);
2854 s_treeBeingSorted
= NULL
;
2858 wxTreeItemId
wxTreeListMainWindow::FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
) {
2860 // determine start item
2861 wxTreeItemId next
= item
;
2863 if (mode
& wxTL_MODE_NAV_LEVEL
) {
2864 next
= GetNextSibling (next
);
2865 }else if (mode
& wxTL_MODE_NAV_VISIBLE
) { //
2866 next
= GetNextVisible (next
, false);
2867 }else if (mode
& wxTL_MODE_NAV_EXPANDED
) {
2868 next
= GetNextExpanded (next
);
2869 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2870 next
= GetNext (next
, true);
2874 #if !wxCHECK_VERSION(2, 5, 0)
2877 wxTreeItemIdValue cookie
= 0;
2880 next
= (wxTreeListItem
*)GetRootItem().m_pItem
;
2881 if (HasFlag(wxTR_HIDE_ROOT
)) {
2882 next
= (wxTreeListItem
*)GetFirstChild (GetRootItem().m_pItem
, cookie
).m_pItem
;
2885 if (!next
.IsOk()) return (wxTreeItemId
*)NULL
;
2887 // start checking the next items
2888 while (next
.IsOk() && (next
!= item
)) {
2889 if (mode
& wxTL_MODE_FIND_PARTIAL
) {
2890 itemText
= GetItemText (next
).Mid (0, str
.Length());
2892 itemText
= GetItemText (next
);
2894 if (mode
& wxTL_MODE_FIND_NOCASE
) {
2895 if (itemText
.CmpNoCase (str
) == 0) return next
;
2897 if (itemText
.Cmp (str
) == 0) return next
;
2899 if (mode
& wxTL_MODE_NAV_LEVEL
) {
2900 next
= GetNextSibling (next
);
2901 }else if (mode
& wxTL_MODE_NAV_VISIBLE
) { //
2902 next
= GetNextVisible (next
, false);
2903 }else if (mode
& wxTL_MODE_NAV_EXPANDED
) {
2904 next
= GetNextExpanded (next
);
2905 }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
2906 next
= GetNext (next
, true);
2908 if (!next
.IsOk() && item
.IsOk()) {
2909 next
= (wxTreeListItem
*)GetRootItem().m_pItem
;
2910 if (HasFlag(wxTR_HIDE_ROOT
)) {
2911 next
= (wxTreeListItem
*)GetNextChild (GetRootItem().m_pItem
, cookie
).m_pItem
;
2915 return (wxTreeItemId
*)NULL
;
2918 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId
& item
) {
2919 wxTreeListItem
*prevItem
= m_dragItem
;
2920 m_dragItem
= (wxTreeListItem
*) item
.m_pItem
;
2921 if (prevItem
) RefreshLine (prevItem
);
2922 if (m_dragItem
) RefreshLine (m_dragItem
);
2925 void wxTreeListMainWindow::CalculateLineHeight() {
2926 wxClientDC
dc (this);
2927 dc
.SetFont (m_normalFont
);
2928 m_lineHeight
= (int)(dc
.GetCharHeight() + m_linespacing
);
2930 if (m_imageListNormal
) {
2931 // Calculate a m_lineHeight value from the normal Image sizes.
2932 // May be toggle off. Then wxTreeListMainWindow will spread when
2933 // necessary (which might look ugly).
2934 int n
= m_imageListNormal
->GetImageCount();
2935 for (int i
= 0; i
< n
; i
++) {
2936 int width
= 0, height
= 0;
2937 m_imageListNormal
->GetSize(i
, width
, height
);
2938 if (height
> m_lineHeight
) m_lineHeight
= height
+ m_linespacing
;
2942 if (m_imageListButtons
) {
2943 // Calculate a m_lineHeight value from the Button image sizes.
2944 // May be toggle off. Then wxTreeListMainWindow will spread when
2945 // necessary (which might look ugly).
2946 int n
= m_imageListButtons
->GetImageCount();
2947 for (int i
= 0; i
< n
; i
++) {
2948 int width
= 0, height
= 0;
2949 m_imageListButtons
->GetSize(i
, width
, height
);
2950 if (height
> m_lineHeight
) m_lineHeight
= height
+ m_linespacing
;
2954 if (m_lineHeight
< 30) { // add 10% space if greater than 30 pixels
2955 m_lineHeight
+= 2; // minimal 2 pixel space
2957 m_lineHeight
+= m_lineHeight
/ 10; // otherwise 10% space
2961 void wxTreeListMainWindow::SetImageList (wxImageList
*imageList
) {
2962 if (m_ownsImageListNormal
) delete m_imageListNormal
;
2963 m_imageListNormal
= imageList
;
2964 m_ownsImageListNormal
= false;
2966 CalculateLineHeight();
2969 void wxTreeListMainWindow::SetStateImageList (wxImageList
*imageList
) {
2970 if (m_ownsImageListState
) delete m_imageListState
;
2971 m_imageListState
= imageList
;
2972 m_ownsImageListState
= false;
2975 void wxTreeListMainWindow::SetButtonsImageList (wxImageList
*imageList
) {
2976 if (m_ownsImageListButtons
) delete m_imageListButtons
;
2977 m_imageListButtons
= imageList
;
2978 m_ownsImageListButtons
= false;
2980 CalculateLineHeight();
2983 void wxTreeListMainWindow::AssignImageList (wxImageList
*imageList
) {
2984 SetImageList(imageList
);
2985 m_ownsImageListNormal
= true;
2988 void wxTreeListMainWindow::AssignStateImageList (wxImageList
*imageList
) {
2989 SetStateImageList(imageList
);
2990 m_ownsImageListState
= true;
2993 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList
*imageList
) {
2994 SetButtonsImageList(imageList
);
2995 m_ownsImageListButtons
= true;
2998 // ----------------------------------------------------------------------------
3000 // ----------------------------------------------------------------------------
3002 void wxTreeListMainWindow::AdjustMyScrollbars() {
3005 GetScrollPixelsPerUnit (&xUnit
, &yUnit
);
3006 if (xUnit
== 0) xUnit
= GetCharWidth();
3007 if (yUnit
== 0) yUnit
= m_lineHeight
;
3009 m_rootItem
->GetSize (x
, y
, this);
3010 y
+= yUnit
+ 2; // one more scrollbar unit + 2 pixels
3011 int x_pos
= GetScrollPos (wxHORIZONTAL
);
3012 int y_pos
= GetScrollPos (wxVERTICAL
);
3013 x
= m_owner
->GetHeaderWindow()->GetWidth() + 2;
3014 if (x
< GetClientSize().GetWidth()) x_pos
= 0;
3015 SetScrollbars (xUnit
, yUnit
, x
/xUnit
, y
/yUnit
, x_pos
, y_pos
);
3017 SetScrollbars (0, 0, 0, 0);
3021 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem
*item
) const {
3022 if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) {
3023 return item
->GetHeight();
3025 return m_lineHeight
;
3029 void wxTreeListMainWindow::PaintItem (wxTreeListItem
*item
, wxDC
& dc
) {
3031 wxTreeItemAttr
*attr
= item
->GetAttributes();
3033 dc
.SetFont (GetItemFont (item
));
3036 if (attr
&& attr
->HasTextColour()) {
3037 colText
= attr
->GetTextColour();
3039 colText
= GetForegroundColour();
3041 #if !wxCHECK_VERSION(2, 5, 0)
3042 wxColour colTextHilight
= wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT
);
3044 wxColour colTextHilight
= wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT
);
3047 int total_w
= m_owner
->GetHeaderWindow()->GetWidth();
3048 int total_h
= GetLineHeight(item
);
3049 int off_h
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0;
3050 int off_w
= HasFlag(wxTR_COLUMN_LINES
) ? 1 : 0;
3051 wxDCClipper
clipper (dc
, 0, item
->GetY(), total_w
, total_h
); // only within line
3053 int text_w
= 0, text_h
= 0;
3054 dc
.GetTextExtent( item
->GetText(GetMainColumn()), &text_w
, &text_h
);
3056 // determine background and show it
3058 if (attr
&& attr
->HasBackgroundColour()) {
3059 colBg
= attr
->GetBackgroundColour();
3061 colBg
= m_backgroundColour
;
3063 dc
.SetBrush (wxBrush (colBg
, wxSOLID
));
3064 dc
.SetPen (*wxTRANSPARENT_PEN
);
3065 if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT
)) {
3066 if (item
== m_dragItem
) {
3067 dc
.SetBrush (*m_hilightBrush
);
3068 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3069 dc
.SetPen ((item
== m_dragItem
)? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
3070 #endif // !__WXMAC__
3071 dc
.SetTextForeground (colTextHilight
);
3072 }else if (item
->IsSelected()) {
3073 #if defined(__WXGTK2__) || defined(__WXMAC__)
3074 int flags
= wxCONTROL_SELECTED
;
3077 flags
|= wxCONTROL_FOCUSED
;
3079 dc
.SetTextForeground( *wxWHITE
);
3082 wxRendererNative::GetDefault().DrawItemSelectionRect( m_owner
, dc
, wxRect( 0, item
->GetY() + off_h
, total_w
, total_h
- off_h
), flags
);
3084 if (!m_isDragging
&& m_hasFocus
) {
3085 dc
.SetBrush (*m_hilightBrush
);
3086 dc
.SetPen (*wxBLACK_PEN
);
3088 dc
.SetBrush (*m_hilightUnfocusedBrush
);
3089 dc
.SetPen (*wxTRANSPARENT_PEN
);
3091 dc
.SetTextForeground (colTextHilight
);
3092 #endif // defined(__WXGTK2__) || defined(__WXMAC__)
3093 }else if (item
== m_curItem
) {
3094 dc
.SetPen (m_hasFocus
? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
3096 dc
.SetTextForeground (colText
);
3098 #if !defined(__WXGTK2__) && !defined(__WXMAC__)
3099 dc
.DrawRectangle (0, item
->GetY() + off_h
, total_w
, total_h
- off_h
);
3102 dc
.SetTextForeground (colText
);
3105 int text_extraH
= (total_h
> text_h
) ? (total_h
- text_h
)/2 : 0;
3106 int img_extraH
= (total_h
> m_imgHeight
)? (total_h
-m_imgHeight
)/2: 0;
3108 for (int i
= 0; i
< GetColumnCount(); ++i
) {
3109 if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue;
3111 int col_w
= m_owner
->GetHeaderWindow()->GetColumnWidth(i
);
3112 wxDCClipper
clipper (dc
, x_colstart
, item
->GetY(), col_w
, total_h
); // only within column
3115 int image
= NO_IMAGE
;
3117 if(i
== GetMainColumn()) {
3118 x
= item
->GetX() + MARGIN
;
3120 x
+= (m_btnWidth
-m_btnWidth2
) + LINEATROOT
;
3124 if (m_imageListNormal
) image
= item
->GetCurrentImage();
3126 x
= x_colstart
+ MARGIN
;
3127 image
= item
->GetImage(i
);
3129 if (image
!= NO_IMAGE
) image_w
= m_imgWidth
+ MARGIN
;
3131 // honor text alignment
3132 wxString text
= item
->GetText(i
);
3134 switch ( m_owner
->GetHeaderWindow()->GetColumn(i
).GetAlignment() ) {
3136 // nothing to do, already left aligned
3139 dc
.GetTextExtent (text
, &text_w
, NULL
);
3140 w
= col_w
- (image_w
+ text_w
+ off_w
+ MARGIN
);
3143 case wxALIGN_CENTER
:
3144 dc
.GetTextExtent(text
, &text_w
, NULL
);
3145 w
= (col_w
- (image_w
+ text_w
+ off_w
+ MARGIN
))/2;
3149 int text_x
= x
+ image_w
;
3150 if (i
== GetMainColumn()) item
->SetTextX (text_x
);
3152 if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT
)) {
3153 if (i
== GetMainColumn()) {
3154 if (item
== m_dragItem
) {
3155 dc
.SetBrush (*m_hilightBrush
);
3156 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3157 dc
.SetPen ((item
== m_dragItem
)? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
3158 #endif // !__WXMAC__
3159 dc
.SetTextForeground (colTextHilight
);
3160 }else if (item
->IsSelected()) {
3161 #if defined(__WXGTK2__) || defined(__WXMAC__)
3162 int flags
= wxCONTROL_SELECTED
;
3165 flags
|= wxCONTROL_FOCUSED
;
3167 dc
.SetTextForeground( *wxWHITE
);
3170 wxRendererNative::GetDefault().DrawItemSelectionRect( m_owner
, dc
, wxRect( 0, item
->GetY() + off_h
, total_w
, total_h
- off_h
), flags
);
3172 if (!m_isDragging
&& m_hasFocus
) {
3173 dc
.SetBrush (*m_hilightBrush
);
3174 dc
.SetPen (*wxBLACK_PEN
);
3176 dc
.SetBrush (*m_hilightUnfocusedBrush
);
3177 dc
.SetPen (*wxTRANSPARENT_PEN
);
3179 dc
.SetTextForeground (colTextHilight
);
3180 #endif // defined(__WXGTK2__) || defined(__WXMAC__)
3181 }else if (item
== m_curItem
) {
3182 dc
.SetPen (m_hasFocus
? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
);
3184 dc
.SetTextForeground (colText
);
3186 #if !defined(__WXGTK2__) && !defined(__WXMAC__)
3187 dc
.DrawRectangle (text_x
, item
->GetY() + off_h
, text_w
, total_h
- off_h
);
3190 dc
.SetTextForeground (colText
);
3194 if (HasFlag(wxTR_COLUMN_LINES
)) { // vertical lines between columns
3195 #if !wxCHECK_VERSION(2, 5, 0)
3196 wxPen
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3198 wxPen
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3200 dc
.SetPen ((GetBackgroundColour() == *wxWHITE
)? pen
: *wxWHITE_PEN
);
3201 dc
.DrawLine (x_colstart
+col_w
-1, item
->GetY(), x_colstart
+col_w
-1, item
->GetY()+total_h
);
3204 dc
.SetBackgroundMode (wxTRANSPARENT
);
3206 if (image
!= NO_IMAGE
) {
3207 int y
= item
->GetY() + img_extraH
;
3208 m_imageListNormal
->Draw (image
, dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT
);
3210 int text_y
= item
->GetY() + text_extraH
;
3211 dc
.DrawText (text
, (wxCoord
)text_x
, (wxCoord
)text_y
);
3213 x_colstart
+= col_w
;
3216 // restore normal font
3217 dc
.SetFont( m_normalFont
);
3220 // Now y stands for the top of the item, whereas it used to stand for middle !
3221 void wxTreeListMainWindow::PaintLevel (wxTreeListItem
*item
, wxDC
&dc
,
3222 int level
, int &y
, int x_maincol
) {
3224 // Handle hide root (only level 0)
3225 if (HasFlag(wxTR_HIDE_ROOT
) && (level
== 0)) {
3226 wxArrayTreeListItems
& children
= item
->GetChildren();
3227 for (size_t n
= 0; n
< children
.Count(); n
++) {
3228 PaintLevel (children
[n
], dc
, 1, y
, x_maincol
);
3230 // end after expanding root
3234 // calculate position of vertical lines
3235 int x
= x_maincol
+ MARGIN
; // start of column
3236 if (HasFlag(wxTR_LINES_AT_ROOT
)) x
+= LINEATROOT
; // space for lines at root
3238 x
+= (m_btnWidth
-m_btnWidth2
); // half button space
3240 x
+= (m_indent
-m_indent
/2);
3242 if (HasFlag(wxTR_HIDE_ROOT
)) {
3243 x
+= m_indent
* (level
-1); // indent but not level 1
3245 x
+= m_indent
* level
; // indent according to level
3248 // set position of vertical line
3252 int h
= GetLineHeight (item
);
3254 int y_mid
= y_top
+ (h
/2);
3257 int exposed_x
= dc
.LogicalToDeviceX(0);
3258 int exposed_y
= dc
.LogicalToDeviceY(y_top
);
3260 if (IsExposed(exposed_x
, exposed_y
, 10000, h
)) { // 10000 = very much
3262 if (HasFlag(wxTR_ROW_LINES
)) { // horizontal lines between rows
3263 //dc.DestroyClippingRegion();
3264 int total_width
= m_owner
->GetHeaderWindow()->GetWidth();
3265 // if the background colour is white, choose a
3266 // contrasting color for the lines
3267 #if !wxCHECK_VERSION(2, 5, 0)
3268 wxPen
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3270 wxPen
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
3272 dc
.SetPen ((GetBackgroundColour() == *wxWHITE
)? pen
: *wxWHITE_PEN
);
3273 dc
.DrawLine (0, y_top
, total_width
, y_top
);
3274 dc
.DrawLine (0, y_top
+h
, total_width
, y_top
+h
);
3278 PaintItem (item
, dc
);
3280 // restore DC objects
3281 dc
.SetBrush(*wxWHITE_BRUSH
);
3282 dc
.SetPen(m_dottedPen
);
3284 // clip to the column width
3285 int clip_width
= m_owner
->GetHeaderWindow()->
3286 GetColumn(m_main_column
).GetWidth();
3287 wxDCClipper
clipper(dc
, x_maincol
, y_top
, clip_width
, 10000);
3289 if (!HasFlag(wxTR_NO_LINES
)) { // connection lines
3291 // draw the horizontal line here
3292 dc
.SetPen(m_dottedPen
);
3293 int x2
= x
- m_indent
;
3294 if (x2
< (x_maincol
+ MARGIN
)) x2
= x_maincol
+ MARGIN
;
3295 int x3
= x
+ (m_btnWidth
-m_btnWidth2
);
3297 if (item
->HasPlus()) {
3298 dc
.DrawLine (x2
, y_mid
, x
- m_btnWidth2
, y_mid
);
3299 dc
.DrawLine (x3
, y_mid
, x3
+ LINEATROOT
, y_mid
);
3301 dc
.DrawLine (x2
, y_mid
, x3
+ LINEATROOT
, y_mid
);
3304 dc
.DrawLine (x2
, y_mid
, x
- m_indent
/2, y_mid
);
3308 if (item
->HasPlus() && HasButtons()) { // should the item show a button?
3310 if (m_imageListButtons
) {
3312 // draw the image button here
3313 int image
= wxTreeItemIcon_Normal
;
3314 if (item
->IsExpanded()) image
= wxTreeItemIcon_Expanded
;
3315 if (item
->IsSelected()) image
+= wxTreeItemIcon_Selected
- wxTreeItemIcon_Normal
;
3316 int xx
= x
- m_btnWidth2
+ MARGIN
;
3317 int yy
= y_mid
- m_btnHeight2
;
3318 dc
.SetClippingRegion(xx
, yy
, m_btnWidth
, m_btnHeight
);
3319 m_imageListButtons
->Draw (image
, dc
, xx
, yy
, wxIMAGELIST_DRAW_TRANSPARENT
);
3320 dc
.DestroyClippingRegion();
3322 }else if (HasFlag (wxTR_TWIST_BUTTONS
)) {
3324 // draw the twisty button here
3325 dc
.SetPen(*wxBLACK_PEN
);
3326 dc
.SetBrush(*m_hilightBrush
);
3328 if (item
->IsExpanded()) {
3329 button
[0].x
= x
- (m_btnWidth2
+1);
3330 button
[0].y
= y_mid
- (m_btnHeight
/3);
3331 button
[1].x
= x
+ (m_btnWidth2
+1);
3332 button
[1].y
= button
[0].y
;
3334 button
[2].y
= button
[0].y
+ (m_btnHeight2
+1);
3336 button
[0].x
= x
- (m_btnWidth
/3);
3337 button
[0].y
= y_mid
- (m_btnHeight2
+1);
3338 button
[1].x
= button
[0].x
;
3339 button
[1].y
= y_mid
+ (m_btnHeight2
+1);
3340 button
[2].x
= button
[0].x
+ (m_btnWidth2
+1);
3341 button
[2].y
= y_mid
;
3343 dc
.DrawPolygon(3, button
);
3345 }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3347 // draw the plus sign here
3348 #if !wxCHECK_VERSION(2, 7, 0)
3349 dc
.SetPen(*wxGREY_PEN
);
3350 dc
.SetBrush(*wxWHITE_BRUSH
);
3351 dc
.DrawRectangle (x
-m_btnWidth2
, y_mid
-m_btnHeight2
, m_btnWidth
, m_btnHeight
);
3352 dc
.SetPen(*wxBLACK_PEN
);
3353 dc
.DrawLine (x
-(m_btnWidth2
-2), y_mid
, x
+(m_btnWidth2
-1), y_mid
);
3354 if (!item
->IsExpanded()) { // change "-" to "+"
3355 dc
.DrawLine (x
, y_mid
-(m_btnHeight2
-2), x
, y_mid
+(m_btnHeight2
-1));
3358 wxRect
rect (x
-m_btnWidth2
, y_mid
-m_btnHeight2
, m_btnWidth
, m_btnHeight
);
3359 int flag
= item
->IsExpanded()? wxCONTROL_EXPANDED
: 0;
3360 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc
, rect
, flag
);
3369 // restore DC objects
3370 dc
.SetBrush(*wxWHITE_BRUSH
);
3371 dc
.SetPen(m_dottedPen
);
3372 dc
.SetTextForeground(*wxBLACK
);
3374 if (item
->IsExpanded())
3376 wxArrayTreeListItems
& children
= item
->GetChildren();
3378 // clip to the column width
3379 int clip_width
= m_owner
->GetHeaderWindow()->
3380 GetColumn(m_main_column
).GetWidth();
3382 // process lower levels
3384 if (m_imgWidth
> 0) {
3385 oldY
= y_mid
+ m_imgHeight2
;
3390 for (size_t n
= 0; n
< children
.Count(); ++n
) {
3393 PaintLevel (children
[n
], dc
, level
+1, y
, x_maincol
);
3395 // draw vertical line
3396 wxDCClipper
clipper(dc
, x_maincol
, y_top
, clip_width
, 10000);
3397 if (!HasFlag (wxTR_NO_LINES
)) {
3399 dc
.DrawLine (x
, oldY
, x
, y2
);
3407 // ----------------------------------------------------------------------------
3408 // wxWindows callbacks
3409 // ----------------------------------------------------------------------------
3411 void wxTreeListMainWindow::OnPaint (wxPaintEvent
&WXUNUSED(event
)) {
3413 wxPaintDC
dc (this);
3416 if (!m_rootItem
|| (GetColumnCount() <= 0)) return;
3418 // calculate button size
3419 if (m_imageListButtons
) {
3420 m_imageListButtons
->GetSize (0, m_btnWidth
, m_btnHeight
);
3421 }else if (HasButtons()) {
3422 m_btnWidth
= BTNWIDTH
;
3423 m_btnHeight
= BTNHEIGHT
;
3425 m_btnWidth2
= m_btnWidth
/2;
3426 m_btnHeight2
= m_btnHeight
/2;
3428 // calculate image size
3429 if (m_imageListNormal
) {
3430 m_imageListNormal
->GetSize (0, m_imgWidth
, m_imgHeight
);
3432 m_imgWidth2
= m_imgWidth
/2;
3433 m_imgHeight2
= m_imgHeight
/2;
3435 // calculate indent size
3436 if (m_imageListButtons
) {
3437 m_indent
= wxMax (MININDENT
, m_btnWidth
+ MARGIN
);
3438 }else if (HasButtons()) {
3439 m_indent
= wxMax (MININDENT
, m_btnWidth
+ LINEATROOT
);
3442 // set default values
3443 dc
.SetFont( m_normalFont
);
3444 dc
.SetPen( m_dottedPen
);
3446 // calculate column start and paint
3449 for (i
= 0; i
< (int)GetMainColumn(); ++i
) {
3450 if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue;
3451 x_maincol
+= m_owner
->GetHeaderWindow()->GetColumnWidth (i
);
3454 PaintLevel (m_rootItem
, dc
, 0, y
, x_maincol
);
3457 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent
&event
) {
3461 if (m_curItem
) RefreshLine (m_curItem
);
3465 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent
&event
)
3469 if (m_curItem
) RefreshLine (m_curItem
);
3473 void wxTreeListMainWindow::OnChar (wxKeyEvent
&event
) {
3474 // send event to user code
3475 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_KEY_DOWN
, m_owner
->GetId());
3476 nevent
.SetKeyEvent (event
);
3477 nevent
.SetEventObject (m_owner
);
3478 if (m_owner
->GetEventHandler()->ProcessEvent (nevent
)) return; // handled in user code
3480 // determine first current if none
3481 bool curItemSet
= false;
3483 m_curItem
= (wxTreeListItem
*)GetRootItem().m_pItem
;
3484 if (HasFlag(wxTR_HIDE_ROOT
)) {
3485 #if !wxCHECK_VERSION(2, 5, 0)
3488 wxTreeItemIdValue cookie
= 0;
3490 m_curItem
= (wxTreeListItem
*)GetFirstChild (m_curItem
, cookie
).m_pItem
;
3494 if (!m_curItem
) return; // do nothing if empty tree
3496 // remember item at shift down
3497 if (HasFlag(wxTR_MULTIPLE
) && event
.ShiftDown()) {
3498 if (!m_shiftItem
) m_shiftItem
= m_curItem
;
3500 m_shiftItem
= (wxTreeListItem
*)NULL
;
3503 // process all cases
3504 wxTreeItemId newItem
= (wxTreeItemId
*)NULL
;
3505 switch (event
.GetKeyCode()) {
3507 // '+': Expand subtree
3510 if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) Expand (m_curItem
);
3513 // '-': collapse subtree
3515 case WXK_SUBTRACT
: {
3516 if (m_curItem
->HasPlus() && IsExpanded (m_curItem
)) Collapse (m_curItem
);
3519 // '*': expand/collapse all subtrees // TODO: Mak it more useful
3521 case WXK_MULTIPLY
: {
3522 if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) {
3523 ExpandAll (m_curItem
);
3524 }else if (m_curItem
->HasPlus()) {
3525 Collapse (m_curItem
); // TODO: CollapseAll
3529 // ' ': toggle current item
3531 SelectItem (m_curItem
, (wxTreeListItem
*)NULL
, false);
3534 // <RETURN>: activate current item
3536 wxTreeEvent
aevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, m_owner
->GetId());
3537 #if !wxCHECK_VERSION(2, 5, 0)
3538 aevent
.SetItem ((long)m_curItem
);
3540 aevent
.SetItem (m_curItem
);
3542 aevent
.SetEventObject (m_owner
);
3543 m_owner
->GetEventHandler()->ProcessEvent (aevent
);
3546 // <BKSP>: go to the parent without collapsing
3548 newItem
= GetItemParent (m_curItem
);
3549 if ((newItem
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) {
3550 newItem
= GetPrevSibling (m_curItem
); // get sibling instead of root
3554 // <UP>: go to the previous sibling or to the last of its children, to the parent
3556 newItem
= GetPrevSibling (m_curItem
);
3558 #if !wxCHECK_VERSION(2, 5, 0)
3561 wxTreeItemIdValue cookie
= 0;
3563 while (IsExpanded (newItem
) && HasChildren (newItem
)) {
3564 newItem
= GetLastChild (newItem
, cookie
);
3567 newItem
= GetItemParent (m_curItem
);
3568 if ((newItem
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) {
3569 newItem
= (wxTreeItemId
*)NULL
; // don't go to root if it is hidden
3574 // <LEFT>: if expanded collapse subtree, else go to the parent
3576 if (IsExpanded (m_curItem
)) {
3577 Collapse (m_curItem
);
3579 newItem
= GetItemParent (m_curItem
);
3580 if ((newItem
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) {
3581 newItem
= GetPrevSibling (m_curItem
); // go to sibling if it is hidden
3586 // <RIGHT>: if possible expand subtree, else go go to the first child
3588 if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) {
3591 if (IsExpanded (m_curItem
) && HasChildren (m_curItem
)) {
3592 #if !wxCHECK_VERSION(2, 5, 0)
3595 wxTreeItemIdValue cookie
= 0;
3597 newItem
= GetFirstChild (m_curItem
, cookie
);
3602 // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3605 newItem
= m_curItem
;
3607 if (IsExpanded (m_curItem
) && HasChildren (m_curItem
)) {
3608 #if !wxCHECK_VERSION(2, 5, 0)
3611 wxTreeItemIdValue cookie
= 0;
3613 newItem
= GetFirstChild( m_curItem
, cookie
);
3616 wxTreeItemId parent
= m_curItem
;
3618 newItem
= GetNextSibling (parent
);
3619 parent
= GetItemParent (parent
);
3620 } while (!newItem
&& parent
);
3625 // <END>: go to last item of the root
3627 #if !wxCHECK_VERSION(2, 5, 0)
3630 wxTreeItemIdValue cookie
= 0;
3632 newItem
= GetLastChild (GetRootItem(), cookie
);
3635 // <HOME>: go to root
3637 newItem
= GetRootItem();
3638 if (HasFlag(wxTR_HIDE_ROOT
)) {
3639 #if !wxCHECK_VERSION(2, 5, 0)
3642 wxTreeItemIdValue cookie
= 0;
3644 newItem
= GetFirstChild (newItem
, cookie
);
3648 // any char: go to the next matching string
3650 if (event
.GetKeyCode() >= (int)' ') {
3651 if (!m_findTimer
->IsRunning()) m_findStr
.Clear();
3652 m_findStr
.Append ((char)event
.GetKeyCode());
3653 m_findTimer
->Start (FIND_TIMER_TICKS
, wxTIMER_ONE_SHOT
);
3654 wxTreeItemId prev
= m_curItem
? (wxTreeItemId
*)m_curItem
: (wxTreeItemId
*)NULL
;
3656 newItem
= FindItem (prev
, m_findStr
, wxTL_MODE_NAV_EXPANDED
|
3657 wxTL_MODE_FIND_PARTIAL
|
3658 wxTL_MODE_FIND_NOCASE
);
3659 if (newItem
|| (m_findStr
.Length() <= 1)) break;
3660 m_findStr
.RemoveLast();
3667 // select and show the new item
3669 if (!event
.ControlDown()) {
3670 bool unselect_others
= !((event
.ShiftDown() || event
.ControlDown()) &&
3671 HasFlag(wxTR_MULTIPLE
));
3672 SelectItem (newItem
, m_shiftItem
, unselect_others
);
3674 EnsureVisible (newItem
);
3675 wxTreeListItem
*oldItem
= m_curItem
;
3676 m_curItem
= (wxTreeListItem
*)newItem
.m_pItem
; // make the new item the current item
3677 RefreshLine (oldItem
);
3681 wxTreeItemId
wxTreeListMainWindow::HitTest (const wxPoint
& point
, int& flags
, int& column
) {
3687 if (point
.x
<0) flags
|= wxTREE_HITTEST_TOLEFT
;
3688 if (point
.x
>w
) flags
|= wxTREE_HITTEST_TORIGHT
;
3689 if (point
.y
<0) flags
|= wxTREE_HITTEST_ABOVE
;
3690 if (point
.y
>h
) flags
|= wxTREE_HITTEST_BELOW
;
3691 if (flags
) return wxTreeItemId();
3694 flags
= wxTREE_HITTEST_NOWHERE
;
3696 return wxTreeItemId();
3699 wxTreeListItem
*hit
= m_rootItem
->HitTest (CalcUnscrolledPosition(point
),
3700 this, flags
, column
, 0);
3702 flags
= wxTREE_HITTEST_NOWHERE
;
3704 return wxTreeItemId();
3709 // get the bounding rectangle of the item (or of its label only)
3710 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId
& itemId
, wxRect
& rect
,
3711 bool WXUNUSED(textOnly
)) const {
3712 wxCHECK_MSG (itemId
.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
3714 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
3717 GetScrollPixelsPerUnit (&xUnit
, &yUnit
);
3719 GetViewStart(& startX
, & startY
);
3721 rect
.x
= item
->GetX() - startX
* xUnit
;
3722 rect
.y
= item
->GetY() - startY
* yUnit
;
3723 rect
.width
= item
->GetWidth();
3724 rect
.height
= GetLineHeight (item
);
3731 void wxTreeListMainWindow::EditLabel (const wxTreeItemId
& item
, int column
) {
3732 if (!item
.IsOk()) return;
3733 if (!((column
>= 0) && (column
< GetColumnCount()))) return;
3735 m_editItem
= (wxTreeListItem
*) item
.m_pItem
;
3737 wxTreeEvent
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, m_owner
->GetId() );
3738 #if !wxCHECK_VERSION(2, 5, 0)
3739 te
.SetItem ((long)m_editItem
);
3741 te
.SetItem (m_editItem
);
3744 te
.SetEventObject (m_owner
);
3745 m_owner
->GetEventHandler()->ProcessEvent (te
);
3747 if (!te
.IsAllowed()) return;
3749 // ensure that the position of the item it calculated in any case
3750 if (m_dirty
) CalculatePositions();
3752 wxTreeListHeaderWindow
* header_win
= m_owner
->GetHeaderWindow();
3754 int y
= m_editItem
->GetY() + 1; // wxTextCtrl needs 1 pixels above the text
3756 int h
= m_editItem
->GetHeight();
3758 if (column
== GetMainColumn()) {
3759 x
+= m_editItem
->GetTextX() - 2; // wxTextCtrl needs 2 pixels before the text
3760 w
= wxMin (m_editItem
->GetWidth(), m_owner
->GetHeaderWindow()->GetWidth() - x
);
3762 for (int i
= 0; i
< column
; ++i
) x
+= header_win
->GetColumnWidth (i
); // start of column
3763 switch (header_win
->GetColumnAlignment (column
)) {
3764 case wxALIGN_LEFT
: {style
= wxTE_LEFT
; break;}
3765 case wxALIGN_RIGHT
: {style
= wxTE_RIGHT
; break;}
3766 case wxALIGN_CENTER
: {style
= wxTE_CENTER
; break;}
3768 w
= header_win
->GetColumnWidth (column
); // width of column
3771 wxClientDC
dc (this);
3773 x
= dc
.LogicalToDeviceX (x
);
3774 y
= dc
.LogicalToDeviceY (y
);
3776 wxEditTextCtrl
*text
= new wxEditTextCtrl (this, -1, &m_renameAccept
, &m_renameRes
,
3777 this, m_editItem
->GetText (column
),
3778 wxPoint (x
, y
), wxSize (w
, h
), style
);
3782 void wxTreeListMainWindow::OnRenameTimer() {
3783 EditLabel (m_curItem
, m_curColumn
);
3786 void wxTreeListMainWindow::OnRenameAccept() {
3788 // TODO if the validator fails this causes a crash
3789 wxTreeEvent
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, m_owner
->GetId() );
3790 #if !wxCHECK_VERSION(2, 5, 0)
3791 le
.SetItem((long)m_editItem
);
3793 le
.SetItem(m_editItem
);
3795 le
.SetEventObject( /*this*/m_owner
);
3796 le
.SetLabel( m_renameRes
);
3797 m_owner
->GetEventHandler()->ProcessEvent( le
);
3799 if (!le
.IsAllowed()) return;
3801 SetItemText (m_editItem
, m_curColumn
, m_renameRes
);
3804 void wxTreeListMainWindow::OnMouse (wxMouseEvent
&event
) {
3805 if (!m_rootItem
) return;
3807 // we process left mouse up event (enables in-place edit), right down
3808 // (pass to the user code), left dbl click (activate item) and
3809 // dragging/moving events for items drag-and-drop
3810 if (!(event
.LeftDown() ||
3812 event
.RightDown() ||
3814 event
.LeftDClick() ||
3816 (event
.GetWheelRotation() != 0 )/*? TODO ||
3817 event.Moving()?*/)) {
3818 m_owner
->GetEventHandler()->ProcessEvent (event
);
3822 // set focus if window clicked
3823 if (event
.LeftDown() || event
.RightDown()) SetFocus();
3826 wxPoint p
= wxPoint (event
.GetX(), event
.GetY());
3828 wxTreeListItem
*item
= m_rootItem
->HitTest (CalcUnscrolledPosition (p
),
3829 this, flags
, m_curColumn
, 0);
3831 // we only process dragging here
3832 if (event
.Dragging()){
3833 if (m_isDragging
) return; // nothing to do, already done
3834 if (item
== NULL
) return; // we need an item to dragging
3836 // determine drag start
3837 if (m_dragCount
== 0) {
3838 m_dragTimer
->Start (DRAG_TIMER_TICKS
, wxTIMER_ONE_SHOT
);
3841 if (m_dragCount
< 3) return; // minimum drag 3 pixel
3842 if (m_dragTimer
->IsRunning()) return;
3844 // we're going to drag
3846 m_isDragging
= true;
3850 // send drag start event
3851 wxEventType command
= event
.LeftIsDown()
3852 ? wxEVT_COMMAND_TREE_BEGIN_DRAG
3853 : wxEVT_COMMAND_TREE_BEGIN_RDRAG
;
3854 wxTreeEvent
nevent (command
, m_owner
->GetId());
3855 nevent
.SetEventObject (m_owner
);
3856 #if !wxCHECK_VERSION(2, 5, 0)
3857 nevent
.SetItem ((long)item
); // the item the drag is ended
3859 nevent
.SetItem (item
); // the item the drag is ended
3861 nevent
.SetPoint (p
);
3862 nevent
.Veto(); // dragging must be explicit allowed!
3863 m_owner
->GetEventHandler()->ProcessEvent (nevent
);
3865 }else if (m_isDragging
) { // any other event but not event.Dragging()
3869 m_isDragging
= false;
3870 if (HasCapture()) ReleaseMouse();
3873 // send drag end event event
3874 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_END_DRAG
, m_owner
->GetId());
3875 nevent
.SetEventObject (m_owner
);
3876 #if !wxCHECK_VERSION(2, 5, 0)
3877 nevent
.SetItem ((long)item
); // the item the drag is started
3879 nevent
.SetItem (item
); // the item the drag is started
3881 nevent
.SetPoint (p
);
3882 m_owner
->GetEventHandler()->ProcessEvent (nevent
);
3884 }else if (m_dragCount
> 0) { // just in case dragging is initiated
3891 // we process only the messages which happen on tree items
3893 m_owner
->GetEventHandler()->ProcessEvent (event
);
3897 // remember item at shift down
3898 if (event
.ShiftDown()) {
3899 if (!m_shiftItem
) m_shiftItem
= m_curItem
;
3901 m_shiftItem
= (wxTreeListItem
*)NULL
;
3904 if (event
.RightUp()) {
3907 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
, m_owner
->GetId());
3908 nevent
.SetEventObject (m_owner
);
3909 #if !wxCHECK_VERSION(2, 5, 0)
3910 nevent
.SetItem ((long)item
); // the item clicked
3912 nevent
.SetItem (item
); // the item clicked
3914 nevent
.SetInt (m_curColumn
); // the colum clicked
3915 nevent
.SetPoint (p
);
3916 m_owner
->GetEventHandler()->ProcessEvent (nevent
);
3918 }else if (event
.LeftUp()) {
3921 if ((item
== m_curItem
) && (m_curColumn
!= -1) &&
3922 (m_owner
->GetHeaderWindow()->IsColumnEditable (m_curColumn
)) &&
3923 (flags
& (wxTREE_HITTEST_ONITEMLABEL
| wxTREE_HITTEST_ONITEMCOLUMN
))){
3924 m_renameTimer
->Start (RENAME_TIMER_TICKS
, wxTIMER_ONE_SHOT
);
3926 m_lastOnSame
= false;
3929 if (((flags
& wxTREE_HITTEST_ONITEMBUTTON
) ||
3930 (flags
& wxTREE_HITTEST_ONITEMICON
)) &&
3931 HasButtons() && item
->HasPlus()) {
3933 // only toggle the item for a single click, double click on
3934 // the button doesn't do anything (it toggles the item twice)
3935 if (event
.LeftDown()) Toggle (item
);
3937 // don't select the item if the button was clicked
3941 // determine the selection if not done by left down
3942 if (!m_left_down_selection
) {
3943 bool unselect_others
= !((event
.ShiftDown() || event
.ControlDown()) &&
3944 HasFlag(wxTR_MULTIPLE
));
3945 SelectItem (item
, m_shiftItem
, unselect_others
);
3946 EnsureVisible (item
);
3947 m_curItem
= item
; // make the new item the current item
3949 m_left_down_selection
= false;
3952 }else if (event
.LeftDown() || event
.RightDown() || event
.LeftDClick()) {
3954 if (event
.LeftDown() || event
.RightDown()) {
3956 m_lastOnSame
= item
== m_curItem
;
3959 if (((flags
& wxTREE_HITTEST_ONITEMBUTTON
) ||
3960 (flags
& wxTREE_HITTEST_ONITEMICON
)) &&
3963 // only toggle the item for a single click, double click on
3964 // the button doesn't do anything (it toggles the item twice)
3965 if (event
.LeftDown()) Toggle (item
);
3967 // don't select the item if the button was clicked
3971 // determine the selection if the current item is not selected
3972 if (!item
->IsSelected()) {
3973 bool unselect_others
= !((event
.ShiftDown() || event
.ControlDown()) &&
3974 HasFlag(wxTR_MULTIPLE
));
3975 SelectItem (item
, m_shiftItem
, unselect_others
);
3976 EnsureVisible (item
);
3977 m_curItem
= item
; // make the new item the current item
3978 m_left_down_selection
= true;
3981 // For some reason, Windows isn't recognizing a left double-click,
3982 // so we need to simulate it here. Allow 200 milliseconds for now.
3983 if (event
.LeftDClick()) {
3985 // double clicking should not start editing the item label
3986 m_renameTimer
->Stop();
3987 m_lastOnSame
= false;
3989 // send activate event first
3990 wxTreeEvent
nevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, m_owner
->GetId());
3991 nevent
.SetEventObject (m_owner
);
3992 #if !wxCHECK_VERSION(2, 5, 0)
3993 nevent
.SetItem ((long)item
); // the item clicked
3995 nevent
.SetItem (item
); // the item clicked
3997 nevent
.SetInt (m_curColumn
); // the colum clicked
3998 nevent
.SetPoint (p
);
3999 if (!m_owner
->GetEventHandler()->ProcessEvent (nevent
)) {
4001 // if the user code didn't process the activate event,
4002 // handle it ourselves by toggling the item when it is
4004 if (item
->HasPlus()) Toggle(item
);
4008 }else{ // any other event skip just in case
4015 void wxTreeListMainWindow::OnIdle (wxIdleEvent
&WXUNUSED(event
)) {
4016 /* after all changes have been done to the tree control,
4017 * we actually redraw the tree when everything is over */
4019 if (!m_dirty
) return;
4022 // Check if we need to select the root item
4023 // because nothing else has been selected.
4024 // Delaying it means that we can invoke event handlers
4025 // as required, when a first item is selected.
4026 if (!m_owner
->HasFlag(wxTR_MULTIPLE
) && !m_owner
->GetSelection().IsOk())
4029 m_owner
->SelectItem(m_select_me
);
4030 else if (m_owner
->GetRootItem().IsOk())
4031 m_owner
->SelectItem(m_owner
->GetRootItem());
4033 m_curItem
= (wxTreeListItem
*)m_owner
->GetSelection().m_pItem
;
4037 CalculatePositions();
4039 AdjustMyScrollbars();
4042 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent
& event
) {
4044 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
4045 wxScrolledWindow::OnScroll(event
);
4047 HandleOnScroll( event
);
4050 if(event
.GetOrientation() == wxHORIZONTAL
) {
4051 m_owner
->GetHeaderWindow()->Refresh();
4052 m_owner
->GetHeaderWindow()->Update();
4056 void wxTreeListMainWindow::CalculateSize (wxTreeListItem
*item
, wxDC
&dc
) {
4060 dc
.SetFont (GetItemFont (item
));
4062 dc
.GetTextExtent (item
->GetText (m_main_column
), &text_w
, &text_h
);
4064 // restore normal font
4065 dc
.SetFont (m_normalFont
);
4067 int total_h
= (m_imgHeight
> text_h
) ? m_imgHeight
: text_h
;
4068 if (total_h
< 30) { // add 10% space if greater than 30 pixels
4069 total_h
+= 2; // minimal 2 pixel space
4071 total_h
+= total_h
/ 10; // otherwise 10% space
4074 item
->SetHeight (total_h
);
4075 if (total_h
> m_lineHeight
) m_lineHeight
= total_h
;
4076 item
->SetWidth(m_imgWidth
+ text_w
+2);
4079 // -----------------------------------------------------------------------------
4080 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem
*item
, wxDC
&dc
,
4081 int level
, int &y
, int x_colstart
) {
4083 // calculate position of vertical lines
4084 int x
= x_colstart
+ MARGIN
; // start of column
4085 if (HasFlag(wxTR_LINES_AT_ROOT
)) x
+= LINEATROOT
; // space for lines at root
4087 x
+= (m_btnWidth
-m_btnWidth2
); // half button space
4089 x
+= (m_indent
-m_indent
/2);
4091 if (HasFlag(wxTR_HIDE_ROOT
)) {
4092 x
+= m_indent
* (level
-1); // indent but not level 1
4094 x
+= m_indent
* level
; // indent according to level
4097 // a hidden root is not evaluated, but its children are always
4098 if (HasFlag(wxTR_HIDE_ROOT
) && (level
== 0)) goto Recurse
;
4100 CalculateSize( item
, dc
);
4105 y
+= GetLineHeight(item
);
4107 // we don't need to calculate collapsed branches
4108 if ( !item
->IsExpanded() ) return;
4111 wxArrayTreeListItems
& children
= item
->GetChildren();
4112 long n
, count
= (long)children
.Count();
4114 for (n
= 0; n
< count
; ++n
) {
4115 CalculateLevel( children
[n
], dc
, level
, y
, x_colstart
); // recurse
4119 void wxTreeListMainWindow::CalculatePositions() {
4120 if ( !m_rootItem
) return;
4122 wxClientDC
dc(this);
4125 dc
.SetFont( m_normalFont
);
4127 dc
.SetPen( m_dottedPen
);
4128 //if(GetImageList() == NULL)
4129 // m_lineHeight = (int)(dc.GetCharHeight() + 4);
4133 for (int i
= 0; i
< (int)GetMainColumn(); ++i
) {
4134 if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue;
4135 x_colstart
+= m_owner
->GetHeaderWindow()->GetColumnWidth(i
);
4137 CalculateLevel( m_rootItem
, dc
, 0, y
, x_colstart
); // start recursion
4140 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem
*item
) {
4141 if (m_dirty
) return;
4143 wxClientDC
dc(this);
4148 GetVirtualSize( &cw
, &ch
);
4151 rect
.x
= dc
.LogicalToDeviceX( 0 );
4153 rect
.y
= dc
.LogicalToDeviceY( item
->GetY() - 2 );
4156 Refresh (true, &rect
);
4157 AdjustMyScrollbars();
4160 void wxTreeListMainWindow::RefreshLine (wxTreeListItem
*item
) {
4161 if (m_dirty
) return;
4163 wxClientDC
dc(this);
4168 GetVirtualSize( &cw
, &ch
);
4171 rect
.x
= dc
.LogicalToDeviceX( 0 );
4172 rect
.y
= dc
.LogicalToDeviceY( item
->GetY() );
4174 rect
.height
= GetLineHeight(item
); //dc.GetCharHeight() + 6;
4176 Refresh (true, &rect
);
4179 void wxTreeListMainWindow::RefreshSelected() {
4180 // TODO: this is awfully inefficient, we should keep the list of all
4181 // selected items internally, should be much faster
4183 RefreshSelectedUnder (m_rootItem
);
4187 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem
*item
) {
4188 if (item
->IsSelected()) {
4192 const wxArrayTreeListItems
& children
= item
->GetChildren();
4193 long count
= children
.GetCount();
4194 for (long n
= 0; n
< count
; n
++ ) {
4195 RefreshSelectedUnder (children
[n
]);
4199 // ----------------------------------------------------------------------------
4200 // changing colours: we need to refresh the tree control
4201 // ----------------------------------------------------------------------------
4203 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour
& colour
) {
4204 if (!wxWindow::SetBackgroundColour(colour
)) return false;
4210 bool wxTreeListMainWindow::SetForegroundColour (const wxColour
& colour
) {
4211 if (!wxWindow::SetForegroundColour(colour
)) return false;
4217 void wxTreeListMainWindow::SetItemText (const wxTreeItemId
& itemId
, int column
,
4218 const wxString
& text
) {
4219 wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item"));
4221 wxClientDC
dc (this);
4222 wxTreeListItem
*item
= (wxTreeListItem
*) itemId
.m_pItem
;
4223 item
->SetText (column
, text
);
4224 CalculateSize (item
, dc
);
4228 wxString
wxTreeListMainWindow::GetItemText (const wxTreeItemId
& itemId
,
4230 wxCHECK_MSG (itemId
.IsOk(), _T(""), _T("invalid tree item") );
4232 if( IsVirtual() ) return m_owner
->OnGetItemText(((wxTreeListItem
*) itemId
.m_pItem
)->GetData(),column
);
4233 else return ((wxTreeListItem
*) itemId
.m_pItem
)->GetText (column
);
4236 wxString
wxTreeListMainWindow::GetItemText (wxTreeItemData
* item
,
4238 wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4239 return m_owner
->OnGetItemText(item
,column
);
4242 void wxTreeListMainWindow::SetFocus() {
4243 wxWindow::SetFocus();
4246 wxFont
wxTreeListMainWindow::GetItemFont (wxTreeListItem
*item
) {
4247 wxTreeItemAttr
*attr
= item
->GetAttributes();
4249 if (attr
&& attr
->HasFont()) {
4250 return attr
->GetFont();
4251 }else if (item
->IsBold()) {
4254 return m_normalFont
;
4258 int wxTreeListMainWindow::GetItemWidth (int column
, wxTreeListItem
*item
) {
4259 if (!item
) return 0;
4261 // determine item width
4263 wxFont font
= GetItemFont (item
);
4264 GetTextExtent (item
->GetText (column
), &w
, &h
, NULL
, NULL
, font
.Ok()? &font
: NULL
);
4268 int width
= w
+ 2*MARGIN
;
4269 if (column
== GetMainColumn()) {
4271 if (HasFlag(wxTR_LINES_AT_ROOT
)) width
+= LINEATROOT
;
4272 if (HasButtons()) width
+= m_btnWidth
+ LINEATROOT
;
4273 if (item
->GetCurrentImage() != NO_IMAGE
) width
+= m_imgWidth
;
4275 // count indent level
4277 wxTreeListItem
*parent
= item
->GetItemParent();
4278 wxTreeListItem
*root
= (wxTreeListItem
*)GetRootItem().m_pItem
;
4279 while (parent
&& (!HasFlag(wxTR_HIDE_ROOT
) || (parent
!= root
))) {
4281 parent
= parent
->GetItemParent();
4283 if (level
) width
+= level
* GetIndent();
4289 int wxTreeListMainWindow::GetBestColumnWidth (int column
, wxTreeItemId parent
) {
4291 GetClientSize (&maxWidth
, &h
);
4294 // get root if on item
4295 if (!parent
.IsOk()) parent
= GetRootItem();
4298 if (!HasFlag(wxTR_HIDE_ROOT
)) {
4299 int w
= GetItemWidth (column
, (wxTreeListItem
*)parent
.m_pItem
);
4300 if (width
< w
) width
= w
;
4301 if (width
> maxWidth
) return maxWidth
;
4304 wxTreeItemIdValue cookie
= 0;
4305 wxTreeItemId item
= GetFirstChild (parent
, cookie
);
4306 while (item
.IsOk()) {
4307 int w
= GetItemWidth (column
, (wxTreeListItem
*)item
.m_pItem
);
4308 if (width
< w
) width
= w
;
4309 if (width
> maxWidth
) return maxWidth
;
4311 // check the children of this item
4312 if (((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) {
4313 int w
= GetBestColumnWidth (column
, item
);
4314 if (width
< w
) width
= w
;
4315 if (width
> maxWidth
) return maxWidth
;
4319 item
= GetNextChild (parent
, cookie
);
4326 //-----------------------------------------------------------------------------
4328 //-----------------------------------------------------------------------------
4330 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl
, wxControl
);
4332 BEGIN_EVENT_TABLE(wxTreeListCtrl
, wxControl
)
4333 EVT_SIZE(wxTreeListCtrl::OnSize
)
4336 bool wxTreeListCtrl::Create(wxWindow
*parent
, wxWindowID id
,
4339 long style
, const wxValidator
&validator
,
4340 const wxString
& name
)
4342 long main_style
= style
& ~(wxSIMPLE_BORDER
|wxSUNKEN_BORDER
|wxDOUBLE_BORDER
|
4343 wxRAISED_BORDER
|wxSTATIC_BORDER
);
4344 long ctrl_style
= style
& ~(wxVSCROLL
|wxHSCROLL
);
4346 if (!wxControl::Create(parent
, id
, pos
, size
, ctrl_style
, validator
, name
)) {
4349 m_main_win
= new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size
,
4350 main_style
, validator
);
4351 m_header_win
= new wxTreeListHeaderWindow (this, -1, m_main_win
,
4352 wxPoint(0, 0), wxDefaultSize
,
4354 CalculateAndSetHeaderHeight();
4358 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4362 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
4363 h
= wxRendererNative::Get().GetHeaderButtonHeight(m_header_win
);
4365 // we use 'g' to get the descent, too
4367 m_header_win
->GetTextExtent(_T("Hg"), &w
, &h
, &d
);
4368 h
+= d
+ 2 * HEADER_OFFSET_Y
+ EXTRA_HEIGHT
;
4370 // only update if changed
4371 if (h
!= m_headerHeight
) {
4378 void wxTreeListCtrl::DoHeaderLayout()
4381 GetClientSize(&w
, &h
);
4383 m_header_win
->SetSize (0, 0, w
, m_headerHeight
);
4384 m_header_win
->Refresh();
4387 m_main_win
->SetSize (0, m_headerHeight
+ 1, w
, h
- m_headerHeight
- 1);
4391 void wxTreeListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
))
4396 size_t wxTreeListCtrl::GetCount() const { return m_main_win
->GetCount(); }
4398 unsigned int wxTreeListCtrl::GetIndent() const
4399 { return m_main_win
->GetIndent(); }
4401 void wxTreeListCtrl::SetIndent(unsigned int indent
)
4402 { m_main_win
->SetIndent(indent
); }
4404 unsigned int wxTreeListCtrl::GetLineSpacing() const
4405 { return m_main_win
->GetLineSpacing(); }
4407 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing
)
4408 { m_main_win
->SetLineSpacing(spacing
); }
4410 wxImageList
* wxTreeListCtrl::GetImageList() const
4411 { return m_main_win
->GetImageList(); }
4413 wxImageList
* wxTreeListCtrl::GetStateImageList() const
4414 { return m_main_win
->GetStateImageList(); }
4416 wxImageList
* wxTreeListCtrl::GetButtonsImageList() const
4417 { return m_main_win
->GetButtonsImageList(); }
4419 void wxTreeListCtrl::SetImageList(wxImageList
* imageList
)
4420 { m_main_win
->SetImageList(imageList
); }
4422 void wxTreeListCtrl::SetStateImageList(wxImageList
* imageList
)
4423 { m_main_win
->SetStateImageList(imageList
); }
4425 void wxTreeListCtrl::SetButtonsImageList(wxImageList
* imageList
)
4426 { m_main_win
->SetButtonsImageList(imageList
); }
4428 void wxTreeListCtrl::AssignImageList(wxImageList
* imageList
)
4429 { m_main_win
->AssignImageList(imageList
); }
4431 void wxTreeListCtrl::AssignStateImageList(wxImageList
* imageList
)
4432 { m_main_win
->AssignStateImageList(imageList
); }
4434 void wxTreeListCtrl::AssignButtonsImageList(wxImageList
* imageList
)
4435 { m_main_win
->AssignButtonsImageList(imageList
); }
4437 wxString
wxTreeListCtrl::GetItemText(const wxTreeItemId
& item
, int column
) const
4438 { return m_main_win
->GetItemText (item
, column
); }
4440 int wxTreeListCtrl::GetItemImage(const wxTreeItemId
& item
, int column
,
4441 wxTreeItemIcon which
) const
4442 { return m_main_win
->GetItemImage(item
, column
, which
); }
4444 wxTreeItemData
* wxTreeListCtrl::GetItemData(const wxTreeItemId
& item
) const
4445 { return m_main_win
->GetItemData(item
); }
4447 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId
& item
) const
4448 { return m_main_win
->GetItemBold(item
); }
4450 wxColour
wxTreeListCtrl::GetItemTextColour(const wxTreeItemId
& item
) const
4451 { return m_main_win
->GetItemTextColour(item
); }
4453 wxColour
wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId
& item
)
4455 { return m_main_win
->GetItemBackgroundColour(item
); }
4457 wxFont
wxTreeListCtrl::GetItemFont(const wxTreeItemId
& item
) const
4458 { return m_main_win
->GetItemFont(item
); }
4461 void wxTreeListCtrl::SetItemText(const wxTreeItemId
& item
, int column
,
4462 const wxString
& text
)
4463 { m_main_win
->SetItemText (item
, column
, text
); }
4465 void wxTreeListCtrl::SetItemImage(const wxTreeItemId
& item
,
4468 wxTreeItemIcon which
)
4469 { m_main_win
->SetItemImage(item
, column
, image
, which
); }
4471 void wxTreeListCtrl::SetItemData(const wxTreeItemId
& item
,
4472 wxTreeItemData
* data
)
4473 { m_main_win
->SetItemData(item
, data
); }
4475 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
)
4476 { m_main_win
->SetItemHasChildren(item
, has
); }
4478 void wxTreeListCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
)
4479 { m_main_win
->SetItemBold(item
, bold
); }
4481 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId
& item
,
4482 const wxColour
& colour
)
4483 { m_main_win
->SetItemTextColour(item
, colour
); }
4485 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
,
4486 const wxColour
& colour
)
4487 { m_main_win
->SetItemBackgroundColour(item
, colour
); }
4489 void wxTreeListCtrl::SetItemFont(const wxTreeItemId
& item
,
4491 { m_main_win
->SetItemFont(item
, font
); }
4493 bool wxTreeListCtrl::SetFont(const wxFont
& font
)
4496 m_header_win
->SetFont(font
);
4497 CalculateAndSetHeaderHeight();
4498 m_header_win
->Refresh();
4501 return m_main_win
->SetFont(font
);
4507 void wxTreeListCtrl::SetWindowStyle(const long style
)
4510 m_main_win
->SetWindowStyle(style
);
4511 m_windowStyle
= style
;
4512 // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4515 long wxTreeListCtrl::GetWindowStyle() const
4517 long style
= m_windowStyle
;
4519 style
|= m_main_win
->GetWindowStyle();
4523 bool wxTreeListCtrl::IsVisible(const wxTreeItemId
& item
, bool fullRow
) const
4524 { return m_main_win
->IsVisible(item
, fullRow
); }
4526 bool wxTreeListCtrl::HasChildren(const wxTreeItemId
& item
) const
4527 { return m_main_win
->HasChildren(item
); }
4529 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId
& item
) const
4530 { return m_main_win
->IsExpanded(item
); }
4532 bool wxTreeListCtrl::IsSelected(const wxTreeItemId
& item
) const
4533 { return m_main_win
->IsSelected(item
); }
4535 bool wxTreeListCtrl::IsBold(const wxTreeItemId
& item
) const
4536 { return m_main_win
->IsBold(item
); }
4538 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool rec
)
4539 { return m_main_win
->GetChildrenCount(item
, rec
); }
4541 wxTreeItemId
wxTreeListCtrl::GetRootItem() const
4542 { return m_main_win
->GetRootItem(); }
4544 wxTreeItemId
wxTreeListCtrl::GetSelection() const
4545 { return m_main_win
->GetSelection(); }
4547 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds
& arr
) const
4548 { return m_main_win
->GetSelections(arr
); }
4550 wxTreeItemId
wxTreeListCtrl::GetItemParent(const wxTreeItemId
& item
) const
4551 { return m_main_win
->GetItemParent(item
); }
4553 #if !wxCHECK_VERSION(2, 5, 0)
4554 wxTreeItemId
wxTreeListCtrl::GetFirstChild (const wxTreeItemId
& item
,
4557 wxTreeItemId
wxTreeListCtrl::GetFirstChild (const wxTreeItemId
& item
,
4558 wxTreeItemIdValue
& cookie
) const
4560 { return m_main_win
->GetFirstChild(item
, cookie
); }
4562 #if !wxCHECK_VERSION(2, 5, 0)
4563 wxTreeItemId
wxTreeListCtrl::GetNextChild (const wxTreeItemId
& item
,
4566 wxTreeItemId
wxTreeListCtrl::GetNextChild (const wxTreeItemId
& item
,
4567 wxTreeItemIdValue
& cookie
) const
4569 { return m_main_win
->GetNextChild(item
, cookie
); }
4571 #if !wxCHECK_VERSION(2, 5, 0)
4572 wxTreeItemId
wxTreeListCtrl::GetPrevChild (const wxTreeItemId
& item
,
4575 wxTreeItemId
wxTreeListCtrl::GetPrevChild (const wxTreeItemId
& item
,
4576 wxTreeItemIdValue
& cookie
) const
4578 { return m_main_win
->GetPrevChild(item
, cookie
); }
4580 #if !wxCHECK_VERSION(2, 5, 0)
4581 wxTreeItemId
wxTreeListCtrl::GetLastChild (const wxTreeItemId
& item
,
4584 wxTreeItemId
wxTreeListCtrl::GetLastChild (const wxTreeItemId
& item
,
4585 wxTreeItemIdValue
& cookie
) const
4587 { return m_main_win
->GetLastChild(item
, cookie
); }
4590 wxTreeItemId
wxTreeListCtrl::GetNextSibling(const wxTreeItemId
& item
) const
4591 { return m_main_win
->GetNextSibling(item
); }
4593 wxTreeItemId
wxTreeListCtrl::GetPrevSibling(const wxTreeItemId
& item
) const
4594 { return m_main_win
->GetPrevSibling(item
); }
4596 wxTreeItemId
wxTreeListCtrl::GetNext(const wxTreeItemId
& item
) const
4597 { return m_main_win
->GetNext(item
, true); }
4599 wxTreeItemId
wxTreeListCtrl::GetPrev(const wxTreeItemId
& item
) const
4600 { return m_main_win
->GetPrev(item
, true); }
4602 wxTreeItemId
wxTreeListCtrl::GetFirstExpandedItem() const
4603 { return m_main_win
->GetFirstExpandedItem(); }
4605 wxTreeItemId
wxTreeListCtrl::GetNextExpanded(const wxTreeItemId
& item
) const
4606 { return m_main_win
->GetNextExpanded(item
); }
4608 wxTreeItemId
wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId
& item
) const
4609 { return m_main_win
->GetPrevExpanded(item
); }
4611 wxTreeItemId
wxTreeListCtrl::GetFirstVisibleItem(bool fullRow
) const
4612 { return m_main_win
->GetFirstVisibleItem(fullRow
); }
4614 wxTreeItemId
wxTreeListCtrl::GetNextVisible(const wxTreeItemId
& item
, bool fullRow
) const
4615 { return m_main_win
->GetNextVisible(item
, fullRow
); }
4617 wxTreeItemId
wxTreeListCtrl::GetPrevVisible(const wxTreeItemId
& item
, bool fullRow
) const
4618 { return m_main_win
->GetPrevVisible(item
, fullRow
); }
4620 wxTreeItemId
wxTreeListCtrl::AddRoot (const wxString
& text
, int image
,
4621 int selectedImage
, wxTreeItemData
* data
)
4622 { return m_main_win
->AddRoot (text
, image
, selectedImage
, data
); }
4624 wxTreeItemId
wxTreeListCtrl::PrependItem(const wxTreeItemId
& parent
,
4625 const wxString
& text
, int image
,
4627 wxTreeItemData
* data
)
4628 { return m_main_win
->PrependItem(parent
, text
, image
, selectedImage
, data
); }
4630 wxTreeItemId
wxTreeListCtrl::InsertItem(const wxTreeItemId
& parent
,
4631 const wxTreeItemId
& previous
,
4632 const wxString
& text
, int image
,
4634 wxTreeItemData
* data
)
4636 return m_main_win
->InsertItem(parent
, previous
, text
, image
,
4637 selectedImage
, data
);
4640 wxTreeItemId
wxTreeListCtrl::InsertItem(const wxTreeItemId
& parent
,
4642 const wxString
& text
, int image
,
4644 wxTreeItemData
* data
)
4646 return m_main_win
->InsertItem(parent
, index
, text
, image
,
4647 selectedImage
, data
);
4650 wxTreeItemId
wxTreeListCtrl::AppendItem(const wxTreeItemId
& parent
,
4651 const wxString
& text
, int image
,
4653 wxTreeItemData
* data
)
4654 { return m_main_win
->AppendItem(parent
, text
, image
, selectedImage
, data
); }
4656 void wxTreeListCtrl::Delete(const wxTreeItemId
& item
)
4657 { m_main_win
->Delete(item
); }
4659 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId
& item
)
4660 { m_main_win
->DeleteChildren(item
); }
4662 void wxTreeListCtrl::DeleteRoot()
4663 { m_main_win
->DeleteRoot(); }
4665 void wxTreeListCtrl::Expand(const wxTreeItemId
& item
)
4666 { m_main_win
->Expand(item
); }
4668 void wxTreeListCtrl::ExpandAll(const wxTreeItemId
& item
)
4669 { m_main_win
->ExpandAll(item
); }
4671 void wxTreeListCtrl::Collapse(const wxTreeItemId
& item
)
4672 { m_main_win
->Collapse(item
); }
4674 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId
& item
)
4675 { m_main_win
->CollapseAndReset(item
); }
4677 void wxTreeListCtrl::Toggle(const wxTreeItemId
& item
)
4678 { m_main_win
->Toggle(item
); }
4680 void wxTreeListCtrl::Unselect()
4681 { m_main_win
->Unselect(); }
4683 void wxTreeListCtrl::UnselectAll()
4684 { m_main_win
->UnselectAll(); }
4686 void wxTreeListCtrl::SelectItem(const wxTreeItemId
& item
, const wxTreeItemId
& last
,
4687 bool unselect_others
)
4688 { m_main_win
->SelectItem (item
, last
, unselect_others
); }
4690 void wxTreeListCtrl::SelectAll()
4691 { m_main_win
->SelectAll(); }
4693 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId
& item
)
4694 { m_main_win
->EnsureVisible(item
); }
4696 void wxTreeListCtrl::ScrollTo(const wxTreeItemId
& item
)
4697 { m_main_win
->ScrollTo(item
); }
4699 wxTreeItemId
wxTreeListCtrl::HitTest(const wxPoint
& pos
, int& flags
, int& column
)
4701 return m_main_win
->HitTest (pos
, flags
, column
);
4704 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId
& item
, wxRect
& rect
,
4705 bool textOnly
) const
4706 { return m_main_win
->GetBoundingRect(item
, rect
, textOnly
); }
4708 void wxTreeListCtrl::EditLabel (const wxTreeItemId
& item
, int column
)
4709 { m_main_win
->EditLabel (item
, column
); }
4711 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId
& item1
,
4712 const wxTreeItemId
& item2
)
4714 // do the comparison here, and not delegate to m_main_win, in order
4715 // to let the user override it
4716 //return m_main_win->OnCompareItems(item1, item2);
4717 return wxStrcmp(GetItemText(item1
), GetItemText(item2
));
4720 void wxTreeListCtrl::SortChildren(const wxTreeItemId
& item
)
4721 { m_main_win
->SortChildren(item
); }
4723 wxTreeItemId
wxTreeListCtrl::FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
)
4724 { return m_main_win
->FindItem (item
, str
, mode
); }
4726 void wxTreeListCtrl::SetDragItem (const wxTreeItemId
& item
)
4727 { m_main_win
->SetDragItem (item
); }
4729 bool wxTreeListCtrl::SetBackgroundColour(const wxColour
& colour
)
4731 if (!m_main_win
) return false;
4732 return m_main_win
->SetBackgroundColour(colour
);
4735 bool wxTreeListCtrl::SetForegroundColour(const wxColour
& colour
)
4737 if (!m_main_win
) return false;
4738 return m_main_win
->SetForegroundColour(colour
);
4741 int wxTreeListCtrl::GetColumnCount() const
4742 { return m_main_win
->GetColumnCount(); }
4744 void wxTreeListCtrl::SetColumnWidth(int column
, int width
)
4746 if (width
== wxLIST_AUTOSIZE_USEHEADER
)
4748 wxFont font
= m_header_win
->GetFont();
4749 m_header_win
->GetTextExtent(m_header_win
->GetColumnText(column
), &width
, NULL
, NULL
, NULL
, font
.Ok()? &font
: NULL
);
4750 //search wxTreeListHeaderWindow::OnPaint to understand this:
4751 width
+= 2*EXTRA_WIDTH
+ MARGIN
;
4753 else if (width
== wxLIST_AUTOSIZE
)
4755 width
= m_main_win
->GetBestColumnWidth(column
);
4758 m_header_win
->SetColumnWidth (column
, width
);
4759 m_header_win
->Refresh();
4762 int wxTreeListCtrl::GetColumnWidth(int column
) const
4763 { return m_header_win
->GetColumnWidth(column
); }
4765 void wxTreeListCtrl::SetMainColumn(int column
)
4766 { m_main_win
->SetMainColumn(column
); }
4768 int wxTreeListCtrl::GetMainColumn() const
4769 { return m_main_win
->GetMainColumn(); }
4771 void wxTreeListCtrl::SetColumnText(int column
, const wxString
& text
)
4773 m_header_win
->SetColumnText (column
, text
);
4774 m_header_win
->Refresh();
4777 wxString
wxTreeListCtrl::GetColumnText(int column
) const
4778 { return m_header_win
->GetColumnText(column
); }
4780 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo
& colInfo
)
4782 m_header_win
->AddColumn (colInfo
);
4786 void wxTreeListCtrl::InsertColumn(int before
, const wxTreeListColumnInfo
& colInfo
)
4788 m_header_win
->InsertColumn (before
, colInfo
);
4789 m_header_win
->Refresh();
4792 void wxTreeListCtrl::RemoveColumn(int column
)
4794 m_header_win
->RemoveColumn (column
);
4795 m_header_win
->Refresh();
4798 void wxTreeListCtrl::SetColumn(int column
, const wxTreeListColumnInfo
& colInfo
)
4800 m_header_win
->SetColumn (column
, colInfo
);
4801 m_header_win
->Refresh();
4804 const wxTreeListColumnInfo
& wxTreeListCtrl::GetColumn(int column
) const
4805 { return m_header_win
->GetColumn(column
); }
4807 wxTreeListColumnInfo
& wxTreeListCtrl::GetColumn(int column
)
4808 { return m_header_win
->GetColumn(column
); }
4810 void wxTreeListCtrl::SetColumnImage(int column
, int image
)
4812 m_header_win
->SetColumn (column
, GetColumn(column
).SetImage(image
));
4813 m_header_win
->Refresh();
4816 int wxTreeListCtrl::GetColumnImage(int column
) const
4818 return m_header_win
->GetColumn(column
).GetImage();
4821 void wxTreeListCtrl::SetColumnEditable(int column
, bool shown
)
4823 m_header_win
->SetColumn (column
, GetColumn(column
).SetEditable(shown
));
4826 void wxTreeListCtrl::SetColumnShown(int column
, bool shown
)
4828 wxASSERT_MSG (column
!= GetMainColumn(), _T("The main column may not be hidden") );
4829 m_header_win
->SetColumn (column
, GetColumn(column
).SetShown(GetMainColumn()==column
? true: shown
));
4830 m_header_win
->Refresh();
4833 bool wxTreeListCtrl::IsColumnEditable(int column
) const
4835 return m_header_win
->GetColumn(column
).IsEditable();
4838 bool wxTreeListCtrl::IsColumnShown(int column
) const
4840 return m_header_win
->GetColumn(column
).IsShown();
4843 void wxTreeListCtrl::SetColumnAlignment (int column
, int flag
)
4845 m_header_win
->SetColumn(column
, GetColumn(column
).SetAlignment(flag
));
4846 m_header_win
->Refresh();
4849 int wxTreeListCtrl::GetColumnAlignment(int column
) const
4851 return m_header_win
->GetColumn(column
).GetAlignment();
4854 void wxTreeListCtrl::Refresh(bool erase
, const wxRect
* rect
)
4856 m_main_win
->Refresh (erase
, rect
);
4857 m_header_win
->Refresh (erase
, rect
);
4860 void wxTreeListCtrl::SetFocus()
4861 { m_main_win
->SetFocus(); }
4863 wxSize
wxTreeListCtrl::DoGetBestSize() const
4865 // something is better than nothing...
4866 return wxSize (200,200); // but it should be specified values! FIXME
4869 wxString
wxTreeListCtrl::OnGetItemText( wxTreeItemData
* WXUNUSED(item
), long WXUNUSED(column
)) const
4871 return wxEmptyString
;