1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     generic tree control implementation 
   4 // Author:      Robert Roebling 
   6 // Modified:    22/10/98 - almost total rewrite, simpler interface (VZ) 
   8 // Copyright:   (c) 1998 Robert Roebling, Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================= 
  14 // ============================================================================= 
  16 // ----------------------------------------------------------------------------- 
  18 // ----------------------------------------------------------------------------- 
  21   #pragma implementation "treectrl.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  31 #include "wx/treectrl.h" 
  32 #include "wx/generic/imaglist.h" 
  33 #include "wx/settings.h" 
  36 #include "wx/dynarray.h" 
  37 #include "wx/arrimpl.cpp" 
  38 #include "wx/dcclient.h" 
  39 #include "wx/msgdlg.h" 
  41 // ----------------------------------------------------------------------------- 
  43 // ----------------------------------------------------------------------------- 
  45 class WXDLLEXPORT wxGenericTreeItem
; 
  47 WX_DEFINE_ARRAY(wxGenericTreeItem 
*, wxArrayGenericTreeItems
); 
  48 WX_DEFINE_OBJARRAY(wxArrayTreeItemIds
); 
  50 // ---------------------------------------------------------------------------- 
  52 // ---------------------------------------------------------------------------- 
  54 static const int NO_IMAGE 
= -1; 
  56 #define PIXELS_PER_UNIT 10 
  58 // ----------------------------------------------------------------------------- 
  60 // ----------------------------------------------------------------------------- 
  62 // timer used for enabling in-place edit 
  63 class WXDLLEXPORT wxTreeRenameTimer
: public wxTimer
 
  66     wxTreeRenameTimer( wxTreeCtrl 
*owner 
); 
  74 // control used for in-place edit 
  75 class WXDLLEXPORT wxTreeTextCtrl
: public wxTextCtrl
 
  79     wxTreeTextCtrl( wxWindow 
*parent
, 
  84                     const wxString 
&value 
= wxEmptyString
, 
  85                     const wxPoint 
&pos 
= wxDefaultPosition
, 
  86                     const wxSize 
&size 
= wxDefaultSize
, 
  88                     const wxValidator
& validator 
= wxDefaultValidator
, 
  89                     const wxString 
&name 
= wxTextCtrlNameStr 
); 
  91     void OnChar( wxKeyEvent 
&event 
); 
  92     void OnKillFocus( wxFocusEvent 
&event 
); 
  98     wxString            m_startValue
; 
 100     DECLARE_EVENT_TABLE() 
 101     DECLARE_DYNAMIC_CLASS(wxTreeTextCtrl
); 
 105 class WXDLLEXPORT wxGenericTreeItem
 
 109     wxGenericTreeItem() { m_data 
= NULL
; } 
 110     wxGenericTreeItem( wxGenericTreeItem 
*parent
, 
 111             const wxString
& text
, 
 113             int image
, int selImage
, 
 114             wxTreeItemData 
*data 
); 
 116     ~wxGenericTreeItem(); 
 119     wxArrayGenericTreeItems
& GetChildren() { return m_children
; } 
 121     const wxString
& GetText() const { return m_text
; } 
 122     int GetImage(wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) const 
 123         { return m_images
[which
]; } 
 124     wxTreeItemData 
*GetData() const { return m_data
; } 
 126     // returns the current image for the item (depending on its 
 127     // selected/expanded/whatever state) 
 128     int GetCurrentImage() const; 
 130     void SetText( const wxString 
&text 
); 
 131     void SetImage(int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; } 
 132     void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
 134     void SetHasPlus(bool has 
= TRUE
) { m_hasPlus 
= has
; } 
 136     void SetBold(bool bold
) { m_isBold 
= bold
; } 
 138     int GetX() const { return m_x
; } 
 139     int GetY() const { return m_y
; } 
 141     void SetX(int x
) { m_x 
= x
; } 
 142     void SetY(int y
) { m_y 
= y
; } 
 144     int  GetHeight() const { return m_height
; } 
 145     int  GetWidth()  const { return m_width
; } 
 147     void SetHeight(int h
) { m_height 
= h
; } 
 148     void SetWidth(int w
) { m_width 
= w
; } 
 151     wxGenericTreeItem 
*GetParent() const { return m_parent
; } 
 154         // deletes all children notifying the treectrl about it if !NULL 
 156     void DeleteChildren(wxTreeCtrl 
*tree 
= NULL
); 
 157         // FIXME don't know what is it for 
 160     // get count of all children (and grand children if 'recursively') 
 161     size_t GetChildrenCount(bool recursively 
= TRUE
) const; 
 163     void Insert(wxGenericTreeItem 
*child
, size_t index
) 
 164     { m_children
.Insert(child
, index
); } 
 166     void SetCross( int x
, int y 
); 
 167     void GetSize( int &x
, int &y
, const wxTreeCtrl
* ); 
 169         // return the item at given position (or NULL if no item), onButton is 
 170         // TRUE if the point belongs to the item's button, otherwise it lies 
 171         // on the button's label 
 172     wxGenericTreeItem 
*HitTest( const wxPoint
& point
, const wxTreeCtrl 
*, int &flags
); 
 174     void Expand() { m_isCollapsed 
= FALSE
; } 
 175     void Collapse() { m_isCollapsed 
= TRUE
; } 
 177     void SetHilight( bool set 
= TRUE 
) { m_hasHilight 
= set
; } 
 180     bool HasChildren() const { return !m_children
.IsEmpty(); } 
 181     bool IsSelected()  const { return m_hasHilight
; } 
 182     bool IsExpanded()  const { return !m_isCollapsed
; } 
 183     bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 184     bool IsBold()      const { return m_isBold
; } 
 187         // get them - may be NULL 
 188     wxTreeItemAttr 
*GetAttributes() const { return m_attr
; } 
 189         // get them ensuring that the pointer is not NULL 
 190     wxTreeItemAttr
& Attr() 
 193             m_attr 
= new wxTreeItemAttr
; 
 201     // tree ctrl images for the normal, selected, expanded and 
 202     // expanded+selected states 
 203     int                 m_images
[wxTreeItemIcon_Max
]; 
 205     wxTreeItemData     
*m_data
; 
 207     // use bitfields to save size 
 208     int                 m_isCollapsed 
:1; 
 209     int                 m_hasHilight  
:1; // same as focused 
 210     int                 m_hasPlus     
:1; // used for item which doesn't have 
 211                                           // children but has a [+] button 
 212     int                 m_isBold      
:1; // render the label in bold font 
 215     wxCoord             m_height
, m_width
; 
 216     int                 m_xCross
, m_yCross
; 
 219     wxArrayGenericTreeItems m_children
; 
 220     wxGenericTreeItem  
*m_parent
; 
 222     wxTreeItemAttr     
*m_attr
; 
 225 // ============================================================================= 
 227 // ============================================================================= 
 229 // ---------------------------------------------------------------------------- 
 231 // ---------------------------------------------------------------------------- 
 233 // translate the key or mouse event flags to the type of selection we're 
 235 static void EventFlagsToSelType(long style
, 
 239                                 bool *extended_select
, 
 240                                 bool *unselect_others
) 
 242     *is_multiple 
= (style 
& wxTR_MULTIPLE
) != 0; 
 243     *extended_select 
= shiftDown 
&& is_multiple
; 
 244     *unselect_others 
= !(extended_select 
|| (ctrlDown 
&& is_multiple
)); 
 247 // ----------------------------------------------------------------------------- 
 248 // wxTreeRenameTimer (internal) 
 249 // ----------------------------------------------------------------------------- 
 251 wxTreeRenameTimer::wxTreeRenameTimer( wxTreeCtrl 
*owner 
) 
 256 void wxTreeRenameTimer::Notify() 
 258     m_owner
->OnRenameTimer(); 
 261 //----------------------------------------------------------------------------- 
 262 // wxTreeTextCtrl (internal) 
 263 //----------------------------------------------------------------------------- 
 265 IMPLEMENT_DYNAMIC_CLASS(wxTreeTextCtrl
,wxTextCtrl
); 
 267 BEGIN_EVENT_TABLE(wxTreeTextCtrl
,wxTextCtrl
) 
 268     EVT_CHAR           (wxTreeTextCtrl::OnChar
) 
 269     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus
) 
 272 wxTreeTextCtrl::wxTreeTextCtrl( wxWindow 
*parent
, 
 277                                 const wxString 
&value
, 
 281                                 const wxValidator
& validator
, 
 282                                 const wxString 
&name 
) 
 283               : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name 
) 
 289     (*m_res
) = wxEmptyString
; 
 290     m_startValue 
= value
; 
 293 void wxTreeTextCtrl::OnChar( wxKeyEvent 
&event 
) 
 295     if (event
.m_keyCode 
== WXK_RETURN
) 
 298         (*m_res
) = GetValue(); 
 300         if (!wxPendingDelete
.Member(this)) 
 301             wxPendingDelete
.Append(this); 
 303         if ((*m_accept
) && ((*m_res
) != m_startValue
)) 
 304             m_owner
->OnRenameAccept(); 
 308     if (event
.m_keyCode 
== WXK_ESCAPE
) 
 313         if (!wxPendingDelete
.Member(this)) 
 314             wxPendingDelete
.Append(this); 
 321 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
 323     if (!wxPendingDelete
.Member(this)) 
 324         wxPendingDelete
.Append(this); 
 326     if ((*m_accept
) && ((*m_res
) != m_startValue
)) 
 327         m_owner
->OnRenameAccept(); 
 330 // ----------------------------------------------------------------------------- 
 332 // ----------------------------------------------------------------------------- 
 334 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent
, wxNotifyEvent
) 
 336 wxTreeEvent::wxTreeEvent( wxEventType commandType
, int id 
) 
 337            : wxNotifyEvent( commandType
, id 
) 
 340     m_itemOld 
= (wxGenericTreeItem 
*)NULL
; 
 343 // ----------------------------------------------------------------------------- 
 345 // ----------------------------------------------------------------------------- 
 347 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 348                                      const wxString
& text
, 
 350                                      int image
, int selImage
, 
 351                                      wxTreeItemData 
*data
) 
 354     m_images
[wxTreeItemIcon_Normal
] = image
; 
 355     m_images
[wxTreeItemIcon_Selected
] = selImage
; 
 356     m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
; 
 357     m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
; 
 361     m_xCross 
= m_yCross 
= 0; 
 365     m_isCollapsed 
= TRUE
; 
 366     m_hasHilight 
= FALSE
; 
 372     m_attr 
= (wxTreeItemAttr 
*)NULL
; 
 374     // We don't know the height here yet. 
 379 wxGenericTreeItem::~wxGenericTreeItem() 
 385     wxASSERT_MSG( m_children
.IsEmpty(), 
 386                   wxT("please call DeleteChildren() before deleting the item") ); 
 389 void wxGenericTreeItem::DeleteChildren(wxTreeCtrl 
*tree
) 
 391     size_t count 
= m_children
.Count(); 
 392     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 394         wxGenericTreeItem 
*child 
= m_children
[n
]; 
 396             tree
->SendDeleteEvent(child
); 
 398         child
->DeleteChildren(tree
); 
 405 void wxGenericTreeItem::SetText( const wxString 
&text 
) 
 410 void wxGenericTreeItem::Reset() 
 413     for ( int i 
= 0; i 
< wxTreeItemIcon_Max
; i
++ ) 
 415         m_images
[i
] = NO_IMAGE
; 
 420     m_height 
= m_width 
= 0; 
 427     m_isCollapsed 
= TRUE
; 
 429     m_parent 
= (wxGenericTreeItem 
*)NULL
; 
 432 size_t wxGenericTreeItem::GetChildrenCount(bool recursively
) const 
 434     size_t count 
= m_children
.Count(); 
 438     size_t total 
= count
; 
 439     for (size_t n 
= 0; n 
< count
; ++n
) 
 441         total 
+= m_children
[n
]->GetChildrenCount(); 
 447 void wxGenericTreeItem::SetCross( int x
, int y 
) 
 453 void wxGenericTreeItem::GetSize( int &x
, int &y
, const wxTreeCtrl 
*theTree 
) 
 455     int bottomY
=m_y
+theTree
->GetLineHeight(this); 
 456     if ( y 
< bottomY 
) y 
= bottomY
; 
 457     int width 
= m_x 
+  m_width
; 
 458     if ( x 
< width 
) x 
= width
; 
 462         size_t count 
= m_children
.Count(); 
 463         for ( size_t n 
= 0; n 
< count
; ++n 
) 
 465             m_children
[n
]->GetSize( x
, y
, theTree 
); 
 470 wxGenericTreeItem 
*wxGenericTreeItem::HitTest( const wxPoint
& point
, 
 471                                                const wxTreeCtrl 
*theTree
, 
 474     if ((point
.y 
> m_y
) && (point
.y 
< m_y 
+ theTree
->GetLineHeight(this))) 
 476         if (point
.y 
< m_y
+theTree
->GetLineHeight(this)/2 ) 
 477             flags 
|= wxTREE_HITTEST_ONITEMUPPERPART
; 
 479             flags 
|= wxTREE_HITTEST_ONITEMLOWERPART
; 
 481         // 5 is the size of the plus sign 
 482         if ((point
.x 
> m_xCross
-5) && (point
.x 
< m_xCross
+5) && 
 483             (point
.y 
> m_yCross
-5) && (point
.y 
< m_yCross
+5) && 
 484             (IsExpanded() || HasPlus())) 
 486             flags
|=wxTREE_HITTEST_ONITEMBUTTON
; 
 490         if ((point
.x 
>= m_x
) && (point
.x 
<= m_x
+m_width
)) 
 495             // assuming every image (normal and selected ) has the same size ! 
 496             if ( (GetImage() != NO_IMAGE
) && theTree
->m_imageListNormal 
) 
 497                 theTree
->m_imageListNormal
->GetSize(GetImage(), image_w
, image_h
); 
 499             if ((image_w 
!= -1) && (point
.x 
<= m_x 
+ image_w 
+ 1)) 
 500                 flags 
|= wxTREE_HITTEST_ONITEMICON
; 
 502                 flags 
|= wxTREE_HITTEST_ONITEMLABEL
; 
 508             flags 
|= wxTREE_HITTEST_ONITEMINDENT
; 
 509         if (point
.x 
> m_x
+m_width
) 
 510             flags 
|= wxTREE_HITTEST_ONITEMRIGHT
; 
 518             size_t count 
= m_children
.Count(); 
 519             for ( size_t n 
= 0; n 
< count
; n
++ ) 
 521                 wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, theTree
, flags 
); 
 528     flags
|=wxTREE_HITTEST_NOWHERE
; 
 530     return (wxGenericTreeItem
*) NULL
; 
 533 int wxGenericTreeItem::GetCurrentImage() const 
 535     int image 
= NO_IMAGE
; 
 540             image 
= GetImage(wxTreeItemIcon_SelectedExpanded
); 
 543         if ( image 
== NO_IMAGE 
) 
 545             // we usually fall back to the normal item, but try just the 
 546             // expanded one (and not selected) first in this case 
 547             image 
= GetImage(wxTreeItemIcon_Expanded
); 
 553             image 
= GetImage(wxTreeItemIcon_Selected
); 
 556     // may be it doesn't have the specific image we want, try the default one 
 558     if ( image 
== NO_IMAGE 
) 
 566 // ----------------------------------------------------------------------------- 
 567 // wxTreeCtrl implementation 
 568 // ----------------------------------------------------------------------------- 
 570 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxScrolledWindow
) 
 572 BEGIN_EVENT_TABLE(wxTreeCtrl
,wxScrolledWindow
) 
 573     EVT_PAINT          (wxTreeCtrl::OnPaint
) 
 574     EVT_MOUSE_EVENTS   (wxTreeCtrl::OnMouse
) 
 575     EVT_CHAR           (wxTreeCtrl::OnChar
) 
 576     EVT_SET_FOCUS      (wxTreeCtrl::OnSetFocus
) 
 577     EVT_KILL_FOCUS     (wxTreeCtrl::OnKillFocus
) 
 578     EVT_IDLE           (wxTreeCtrl::OnIdle
) 
 581 // ----------------------------------------------------------------------------- 
 582 // construction/destruction 
 583 // ----------------------------------------------------------------------------- 
 585 void wxTreeCtrl::Init() 
 589     m_anchor 
= (wxGenericTreeItem 
*) NULL
; 
 599     m_hilightBrush 
= new wxBrush
 
 601       wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), 
 606     m_imageListState 
= (wxImageList 
*) NULL
; 
 609     m_isDragging 
= FALSE
; 
 611     m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
 613     m_renameTimer 
= new wxTreeRenameTimer( this ); 
 615     m_normalFont 
= wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT 
); 
 616     m_boldFont 
= wxFont( m_normalFont
.GetPointSize(), 
 617                             m_normalFont
.GetFamily(), 
 618                             m_normalFont
.GetStyle(), 
 620                             m_normalFont
.GetUnderlined()); 
 623 bool wxTreeCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 624                         const wxPoint
& pos
, const wxSize
& size
, 
 626                         const wxValidator 
&validator
, 
 627                         const wxString
& name 
) 
 631     wxScrolledWindow::Create( parent
, id
, pos
, size
, style
|wxHSCROLL
|wxVSCROLL
, name 
); 
 634     SetValidator( validator 
); 
 637     SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX 
) ); 
 638 //  m_dottedPen = wxPen( "grey", 0, wxDOT );  too slow under XFree86 
 639     m_dottedPen 
= wxPen( "grey", 0, 0 ); 
 644 wxTreeCtrl::~wxTreeCtrl() 
 646     wxDELETE( m_hilightBrush 
); 
 650     delete m_renameTimer
; 
 653 // ----------------------------------------------------------------------------- 
 655 // ----------------------------------------------------------------------------- 
 657 size_t wxTreeCtrl::GetCount() const 
 659     return m_anchor 
== NULL 
? 0u : m_anchor
->GetChildrenCount(); 
 662 void wxTreeCtrl::SetIndent(unsigned int indent
) 
 668 void wxTreeCtrl::SetSpacing(unsigned int spacing
) 
 674 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
) 
 676     wxCHECK_MSG( item
.IsOk(), 0u, wxT("invalid tree item") ); 
 678     return item
.m_pItem
->GetChildrenCount(recursively
); 
 681 // ----------------------------------------------------------------------------- 
 682 // functions to work with tree items 
 683 // ----------------------------------------------------------------------------- 
 685 wxString 
wxTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 687     wxCHECK_MSG( item
.IsOk(), wxT(""), wxT("invalid tree item") ); 
 689     return item
.m_pItem
->GetText(); 
 692 int wxTreeCtrl::GetItemImage(const wxTreeItemId
& item
, 
 693                              wxTreeItemIcon which
) const 
 695     wxCHECK_MSG( item
.IsOk(), -1, wxT("invalid tree item") ); 
 697     return item
.m_pItem
->GetImage(which
); 
 700 wxTreeItemData 
*wxTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 702     wxCHECK_MSG( item
.IsOk(), NULL
, wxT("invalid tree item") ); 
 704     return item
.m_pItem
->GetData(); 
 707 void wxTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 709     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 712     wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 713     pItem
->SetText(text
); 
 714     CalculateSize(pItem
, dc
); 
 718 void wxTreeCtrl::SetItemImage(const wxTreeItemId
& item
, 
 720                               wxTreeItemIcon which
) 
 722     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 724     wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 725     pItem
->SetImage(image
, which
); 
 728     CalculateSize(pItem
, dc
); 
 732 void wxTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 734     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 736     item
.m_pItem
->SetData(data
); 
 739 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
 741     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 743     wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 744     pItem
->SetHasPlus(has
); 
 748 void wxTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
 750     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 752     // avoid redrawing the tree if no real change 
 753     wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 754     if ( pItem
->IsBold() != bold 
) 
 756         pItem
->SetBold(bold
); 
 761 void wxTreeCtrl::SetItemTextColour(const wxTreeItemId
& item
, 
 764     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 766     wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 767     pItem
->Attr().SetTextColour(col
); 
 771 void wxTreeCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
, 
 774     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 776     wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 777     pItem
->Attr().SetBackgroundColour(col
); 
 781 void wxTreeCtrl::SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
) 
 783     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 785     wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 786     pItem
->Attr().SetFont(font
); 
 790 // ----------------------------------------------------------------------------- 
 791 // item status inquiries 
 792 // ----------------------------------------------------------------------------- 
 794 bool wxTreeCtrl::IsVisible(const wxTreeItemId
& WXUNUSED(item
)) const 
 796     wxFAIL_MSG(wxT("not implemented")); 
 801 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
 803     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
 805     return !item
.m_pItem
->GetChildren().IsEmpty(); 
 808 bool wxTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
 810     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
 812     return item
.m_pItem
->IsExpanded(); 
 815 bool wxTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
 817     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
 819     return item
.m_pItem
->IsSelected(); 
 822 bool wxTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
 824     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
 826     return item
.m_pItem
->IsBold(); 
 829 // ----------------------------------------------------------------------------- 
 831 // ----------------------------------------------------------------------------- 
 833 wxTreeItemId 
wxTreeCtrl::GetParent(const wxTreeItemId
& item
) const 
 835   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
 837   return item
.m_pItem
->GetParent(); 
 840 wxTreeItemId 
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const 
 842   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
 845   return GetNextChild(item
, cookie
); 
 848 wxTreeItemId 
wxTreeCtrl::GetNextChild(const wxTreeItemId
& item
, long& cookie
) const 
 850   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
 852   wxArrayGenericTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 853   if ( (size_t)cookie 
< children
.Count() ) 
 855     return children
.Item((size_t)cookie
++); 
 859     // there are no more of them 
 860     return wxTreeItemId(); 
 864 wxTreeItemId 
wxTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
 866   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
 868   wxArrayGenericTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 869   return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
 872 wxTreeItemId 
wxTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
 874   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
 876   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 877   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 878   if ( parent 
== NULL 
) 
 880     // root item doesn't have any siblings 
 881     return wxTreeItemId(); 
 884   wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
 885   int index 
= siblings
.Index(i
); 
 886   wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 888   size_t n 
= (size_t)(index 
+ 1); 
 889   return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
 892 wxTreeItemId 
wxTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
 894   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
 896   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 897   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 898   if ( parent 
== NULL 
) 
 900     // root item doesn't have any siblings 
 901     return wxTreeItemId(); 
 904   wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
 905   int index 
= siblings
.Index(i
); 
 906   wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 908   return index 
== 0 ? wxTreeItemId() 
 909                     : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
 912 wxTreeItemId 
wxTreeCtrl::GetFirstVisibleItem() const 
 914   wxFAIL_MSG(wxT("not implemented")); 
 916   return wxTreeItemId(); 
 919 wxTreeItemId 
wxTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
 921   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
 923   wxFAIL_MSG(wxT("not implemented")); 
 925   return wxTreeItemId(); 
 928 wxTreeItemId 
wxTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
 930   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
 932   wxFAIL_MSG(wxT("not implemented")); 
 934   return wxTreeItemId(); 
 937 // ----------------------------------------------------------------------------- 
 939 // ----------------------------------------------------------------------------- 
 941 wxTreeItemId 
wxTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
 943                                       const wxString
& text
, 
 944                                       int image
, int selImage
, 
 945                                       wxTreeItemData 
*data
) 
 947     wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 950         // should we give a warning here? 
 951         return AddRoot(text
, image
, selImage
, data
); 
 955     wxGenericTreeItem 
*item 
= 
 956         new wxGenericTreeItem( parent
, text
, dc
, image
, selImage
, data 
); 
 960         data
->m_pItem 
= item
; 
 963     parent
->Insert( item
, previous 
); 
 970 wxTreeItemId 
wxTreeCtrl::AddRoot(const wxString
& text
, 
 971                                  int image
, int selImage
, 
 972                                  wxTreeItemData 
*data
) 
 974     wxCHECK_MSG( !m_anchor
, wxTreeItemId(), wxT("tree can have only one root") ); 
 977     m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, dc
, 
 978                                    image
, selImage
, data
); 
 981         data
->m_pItem 
= m_anchor
; 
 984     if (!HasFlag(wxTR_MULTIPLE
)) 
 986         m_current 
= m_key_current 
= m_anchor
; 
 987         m_current
->SetHilight( TRUE 
); 
 991     AdjustMyScrollbars(); 
 996 wxTreeItemId 
wxTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
 997                                      const wxString
& text
, 
 998                                      int image
, int selImage
, 
 999                                      wxTreeItemData 
*data
) 
1001     return DoInsertItem(parent
, 0u, text
, image
, selImage
, data
); 
1004 wxTreeItemId 
wxTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
1005                                     const wxTreeItemId
& idPrevious
, 
1006                                     const wxString
& text
, 
1007                                     int image
, int selImage
, 
1008                                     wxTreeItemData 
*data
) 
1010     wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
1013         // should we give a warning here? 
1014         return AddRoot(text
, image
, selImage
, data
); 
1017     int index 
= parent
->GetChildren().Index(idPrevious
.m_pItem
); 
1018     wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
1019                   wxT("previous item in wxTreeCtrl::InsertItem() is not a sibling") ); 
1021     return DoInsertItem(parentId
, (size_t)++index
, text
, image
, selImage
, data
); 
1024 wxTreeItemId 
wxTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
1026                                     const wxString
& text
, 
1027                                     int image
, int selImage
, 
1028                                     wxTreeItemData 
*data
) 
1030     wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
1033         // should we give a warning here? 
1034         return AddRoot(text
, image
, selImage
, data
); 
1037     return DoInsertItem(parentId
, before
, text
, image
, selImage
, data
); 
1040 wxTreeItemId 
wxTreeCtrl::AppendItem(const wxTreeItemId
& parentId
, 
1041                                     const wxString
& text
, 
1042                                     int image
, int selImage
, 
1043                                     wxTreeItemData 
*data
) 
1045     wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
1048         // should we give a warning here? 
1049         return AddRoot(text
, image
, selImage
, data
); 
1052     return DoInsertItem( parent
, parent
->GetChildren().Count(), text
, 
1053                          image
, selImage
, data
); 
1056 void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
1058     wxTreeEvent 
event( wxEVT_COMMAND_TREE_DELETE_ITEM
, GetId() ); 
1059     event
.m_item 
= item
; 
1060     event
.SetEventObject( this ); 
1061     ProcessEvent( event 
); 
1064 void wxTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
1066     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1067     item
->DeleteChildren(this); 
1072 void wxTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
1074     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1075     wxGenericTreeItem 
*parent 
= item
->GetParent(); 
1079         parent
->GetChildren().Remove( item 
);  // remove by value 
1082     item
->DeleteChildren(this); 
1083     SendDeleteEvent(item
); 
1089 void wxTreeCtrl::DeleteAllItems() 
1093         m_anchor
->DeleteChildren(this); 
1102 void wxTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
1104     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1106     if ( !item
->HasPlus() ) 
1109     if ( item
->IsExpanded() ) 
1112     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
1113     event
.m_item 
= item
; 
1114     event
.SetEventObject( this ); 
1116 //  if ( ProcessEvent( event ) && event.m_code )  TODO: Was this a typo ? 
1117     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1119         // cancelled by program 
1124     CalculatePositions(); 
1126     RefreshSubtree(item
); 
1128     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
1129     ProcessEvent( event 
); 
1132 void wxTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
1134     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1136     if ( !item
->IsExpanded() ) 
1139     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
1140     event
.m_item 
= item
; 
1141     event
.SetEventObject( this ); 
1142     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1144         // cancelled by program 
1150     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1151     size_t count 
= children
.Count(); 
1152     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1154         Collapse(children
[n
]); 
1157     CalculatePositions(); 
1159     RefreshSubtree(item
); 
1161     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
1162     ProcessEvent( event 
); 
1165 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
1168     DeleteChildren(item
); 
1171 void wxTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
1173     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1175     if (item
->IsExpanded()) 
1181 void wxTreeCtrl::Unselect() 
1185         m_current
->SetHilight( FALSE 
); 
1186         RefreshLine( m_current 
); 
1190 void wxTreeCtrl::UnselectAllChildren(wxGenericTreeItem 
*item
) 
1192     if (item
->IsSelected()) 
1194         item
->SetHilight(FALSE
); 
1198     if (item
->HasChildren()) 
1200         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1201         size_t count 
= children
.Count(); 
1202         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1204             UnselectAllChildren(children
[n
]); 
1209 void wxTreeCtrl::UnselectAll() 
1211     UnselectAllChildren(GetRootItem().m_pItem
); 
1214 // Recursive function ! 
1215 // To stop we must have crt_item<last_item 
1217 // Tag all next children, when no more children, 
1218 // Move to parent (not to tag) 
1219 // Keep going... if we found last_item, we stop. 
1220 bool wxTreeCtrl::TagNextChildren(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1222     wxGenericTreeItem 
*parent 
= crt_item
->GetParent(); 
1224     if (parent 
== NULL
) // This is root item 
1225         return TagAllChildrenUntilLast(crt_item
, last_item
, select
); 
1227     wxArrayGenericTreeItems
& children 
= parent
->GetChildren(); 
1228     int index 
= children
.Index(crt_item
); 
1229     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1231     size_t count 
= children
.Count(); 
1232     for (size_t n
=(size_t)(index
+1); n
<count
; ++n
) 
1234         if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return TRUE
; 
1237     return TagNextChildren(parent
, last_item
, select
); 
1240 bool wxTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1242     crt_item
->SetHilight(select
); 
1243     RefreshLine(crt_item
); 
1245     if (crt_item
==last_item
) 
1248     if (crt_item
->HasChildren()) 
1250         wxArrayGenericTreeItems
& children 
= crt_item
->GetChildren(); 
1251         size_t count 
= children
.Count(); 
1252         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1254             if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) 
1262 void wxTreeCtrl::SelectItemRange(wxGenericTreeItem 
*item1
, wxGenericTreeItem 
*item2
) 
1264     // item2 is not necessary after item1 
1265     wxGenericTreeItem 
*first
=NULL
, *last
=NULL
; 
1267     // choice first' and 'last' between item1 and item2 
1268     if (item1
->GetY()<item2
->GetY()) 
1279     bool select 
= m_current
->IsSelected(); 
1281     if ( TagAllChildrenUntilLast(first
,last
,select
) ) 
1284     TagNextChildren(first
,last
,select
); 
1287 void wxTreeCtrl::SelectItem(const wxTreeItemId
& itemId
, 
1288                             bool unselect_others
, 
1289                             bool extended_select
) 
1291     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1293     bool is_single
=!(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1294     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1296     //wxCHECK_RET( ( (!unselect_others) && is_single), 
1297     //           wxT("this is a single selection tree") ); 
1299     // to keep going anyhow !!! 
1302         if (item
->IsSelected()) 
1303             return; // nothing to do 
1304         unselect_others 
= TRUE
; 
1305         extended_select 
= FALSE
; 
1307     else if ( unselect_others 
&& item
->IsSelected() ) 
1309         // selection change if there is more than one item currently selected 
1310         wxArrayTreeItemIds selected_items
; 
1311         if ( GetSelections(selected_items
) == 1 ) 
1315     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
1316     event
.m_item 
= item
; 
1317     event
.m_itemOld 
= m_current
; 
1318     event
.SetEventObject( this ); 
1319     // TODO : Here we don't send any selection mode yet ! 
1321     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
1325     if (unselect_others
) 
1327         if (is_single
) Unselect(); // to speed up thing 
1332     if (extended_select
) 
1334         if (m_current 
== NULL
) m_current
=m_key_current
=GetRootItem().m_pItem
; 
1335         // don't change the mark (m_current) 
1336         SelectItemRange(m_current
, item
); 
1340         bool select
=TRUE
; // the default 
1342         // Check if we need to toggle hilight (ctrl mode) 
1343         if (!unselect_others
) 
1344           select
=!item
->IsSelected(); 
1346         m_current 
= m_key_current 
= item
; 
1347         m_current
->SetHilight(select
); 
1348         RefreshLine( m_current 
); 
1351     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
1352     GetEventHandler()->ProcessEvent( event 
); 
1355 void wxTreeCtrl::FillArray(wxGenericTreeItem 
*item
, 
1356                            wxArrayTreeItemIds 
&array
) const 
1358     if ( item
->IsSelected() ) 
1359         array
.Add(wxTreeItemId(item
)); 
1361     if ( item
->HasChildren() ) 
1363         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1364         size_t count 
= children
.GetCount(); 
1365         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1366             FillArray(children
[n
],array
); 
1370 size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds 
&array
) const 
1373   FillArray(GetRootItem().m_pItem
, array
); 
1375   return array
.Count(); 
1378 void wxTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
1380     if (!item
.IsOk()) return; 
1382     wxGenericTreeItem 
*gitem 
= item
.m_pItem
; 
1384     // first expand all parent branches 
1385     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
1389         parent 
= parent
->GetParent(); 
1392     //if (parent) CalculatePositions(); 
1397 void wxTreeCtrl::ScrollTo(const wxTreeItemId 
&item
) 
1399     if (!item
.IsOk()) return; 
1401     // We have to call this here because the label in 
1402     // question might just have been added and no screen 
1403     // update taken place. 
1404     if (m_dirty
) wxYield(); 
1406     wxGenericTreeItem 
*gitem 
= item
.m_pItem
; 
1408     // now scroll to the item 
1409     int item_y 
= gitem
->GetY(); 
1413     ViewStart( &start_x
, &start_y 
); 
1414     start_y 
*= PIXELS_PER_UNIT
; 
1418     GetClientSize( &client_w
, &client_h 
); 
1420     if (item_y 
< start_y
+3) 
1425         m_anchor
->GetSize( x
, y
, this ); 
1426         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1427         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1428         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1429         // Item should appear at top 
1430         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, item_y
/PIXELS_PER_UNIT 
); 
1432     else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) 
1437         m_anchor
->GetSize( x
, y
, this ); 
1438         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1439         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1440         item_y 
+= PIXELS_PER_UNIT
+2; 
1441         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1442         // Item should appear at bottom 
1443         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, (item_y
+GetLineHeight(gitem
)-client_h
)/PIXELS_PER_UNIT 
); 
1447 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
1448 static wxTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
1450 static int LINKAGEMODE 
tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
1451                                   wxGenericTreeItem 
**item2
) 
1453     wxCHECK_MSG( s_treeBeingSorted
, 0, wxT("bug in wxTreeCtrl::SortChildren()") ); 
1455     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
1458 int wxTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
1459                                const wxTreeItemId
& item2
) 
1461     return wxStrcmp(GetItemText(item1
), GetItemText(item2
)); 
1464 void wxTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
1466     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1468     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1470     wxCHECK_RET( !s_treeBeingSorted
, 
1471                  wxT("wxTreeCtrl::SortChildren is not reentrant") ); 
1473     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1474     if ( children
.Count() > 1 ) 
1476         s_treeBeingSorted 
= this; 
1477         children
.Sort(tree_ctrl_compare_func
); 
1478         s_treeBeingSorted 
= NULL
; 
1482     //else: don't make the tree dirty as nothing changed 
1485 wxImageList 
*wxTreeCtrl::GetImageList() const 
1487     return m_imageListNormal
; 
1490 wxImageList 
*wxTreeCtrl::GetStateImageList() const 
1492     return m_imageListState
; 
1495 void wxTreeCtrl::SetImageList(wxImageList 
*imageList
) 
1497     m_imageListNormal 
= imageList
; 
1499     // Calculate a m_lineHeight value from the image sizes. 
1500     // May be toggle off. Then wxTreeCtrl will spread when 
1501     // necessary (which might look ugly). 
1503     wxClientDC 
dc(this); 
1504     m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1505     int width 
= 0, height 
= 0, 
1506         n 
= m_imageListNormal
->GetImageCount(); 
1508     for (int i 
= 0; i 
< n 
; i
++) 
1510         m_imageListNormal
->GetSize(i
, width
, height
); 
1511         if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
1514     if (m_lineHeight 
< 40) 
1515         m_lineHeight 
+= 2;                 // at least 2 pixels 
1517         m_lineHeight 
+= m_lineHeight
/10;   // otherwise 10% extra spacing 
1521 void wxTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
1523     m_imageListState 
= imageList
; 
1526 // ----------------------------------------------------------------------------- 
1528 // ----------------------------------------------------------------------------- 
1530 void wxTreeCtrl::AdjustMyScrollbars() 
1536         m_anchor
->GetSize( x
, y
, this ); 
1537         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1538         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1539         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1540         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
1541         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, y_pos 
); 
1545         SetScrollbars( 0, 0, 0, 0 ); 
1549 int wxTreeCtrl::GetLineHeight(wxGenericTreeItem 
*item
) const 
1551     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
1552         return item
->GetHeight(); 
1554         return m_lineHeight
; 
1557 void wxTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
1559     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
1560     if ( attr 
&& attr
->HasFont() ) 
1561         dc
.SetFont(attr
->GetFont()); 
1562     else if (item
->IsBold()) 
1563         dc
.SetFont(m_boldFont
); 
1567     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
1571     int image 
= item
->GetCurrentImage(); 
1572     if ( image 
!= NO_IMAGE 
) 
1574         m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
1578     int total_h 
= GetLineHeight(item
); 
1580     if (item
->IsSelected()) 
1581         dc
.SetBrush(*m_hilightBrush
); 
1585         if ( attr 
&& attr
->HasBackgroundColour() ) 
1586             colBg 
= attr
->GetBackgroundColour(); 
1588             colBg 
= m_backgroundColour
; 
1589         dc
.SetBrush(wxBrush(colBg
, wxSOLID
)); 
1592     dc
.DrawRectangle( item
->GetX()-2, item
->GetY(), item
->GetWidth()+2, total_h 
); 
1594     if ( image 
!= NO_IMAGE 
) 
1596         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
1597         m_imageListNormal
->Draw( image
, dc
, 
1599                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
1600                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
1601         dc
.DestroyClippingRegion(); 
1604     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1605     dc
.DrawText( item
->GetText(), image_w 
+ item
->GetX(), (wxCoord
)item
->GetY() 
1606                  + ((total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0)); 
1608     // restore normal font 
1609     dc
.SetFont( m_normalFont 
); 
1612 // Now y stands for the top of the item, whereas it used to stand for middle ! 
1613 void wxTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
1615     int horizX 
= level
*m_indent
; 
1617     item
->SetX( horizX
+m_indent
+m_spacing 
); 
1621     y
+=GetLineHeight(item
)/2; 
1623     item
->SetCross( horizX
+m_indent
, y 
); 
1625     int exposed_x 
= dc
.LogicalToDeviceX( 0 ); 
1626     int exposed_y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
1628     if (IsExposed( exposed_x
, exposed_y
, 10000, GetLineHeight(item
) ))  // 10000 = very much 
1630         int startX 
= horizX
; 
1631         int endX 
= horizX 
+ (m_indent
-5); 
1633 //        if (!item->HasChildren()) endX += (m_indent+5); 
1634         if (!item
->HasChildren()) endX 
+= 20; 
1636         dc
.DrawLine( startX
, y
, endX
, y 
); 
1638         if (item
->HasPlus()) 
1640             dc
.DrawLine( horizX
+(m_indent
+5), y
, horizX
+(m_indent
+15), y 
); 
1641             dc
.SetPen( *wxGREY_PEN 
); 
1642             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1643             dc
.DrawRectangle( horizX
+(m_indent
-5), y
-4, 11, 9 ); 
1645             dc
.SetPen( *wxBLACK_PEN 
); 
1646             dc
.DrawLine( horizX
+(m_indent
-2), y
, horizX
+(m_indent
+3), y 
); 
1647             if (!item
->IsExpanded()) 
1648                 dc
.DrawLine( horizX
+m_indent
, y
-2, horizX
+m_indent
, y
+3 ); 
1650             dc
.SetPen( m_dottedPen 
); 
1653         wxPen 
*pen 
= wxTRANSPARENT_PEN
; 
1656         if ( item
->IsSelected() ) 
1658             colText 
= wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
); 
1666             wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
1667             if ( attr 
&& attr
->HasTextColour() ) 
1668                 colText 
= attr
->GetTextColour(); 
1674         dc
.SetTextForeground(colText
); 
1678         PaintItem(item
, dc
); 
1680         // restore DC objects 
1681         dc
.SetBrush( *wxWHITE_BRUSH 
); 
1682         dc
.SetPen( m_dottedPen 
); 
1683         dc
.SetTextForeground( *wxBLACK 
); 
1686     y 
= oldY
+GetLineHeight(item
); 
1688     if (item
->IsExpanded()) 
1690         oldY
+=GetLineHeight(item
)/2; 
1693         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1694         size_t n
, count 
= children
.Count(); 
1695         for ( n 
= 0; n 
< count
; ++n 
) 
1698             PaintLevel( children
[n
], dc
, level
+1, y 
); 
1701         // it may happen that the item is expanded but has no items (when you 
1702         // delete all its children for example) - don't draw the vertical line 
1706             semiOldY
+=GetLineHeight(children
[--n
])/2; 
1707             dc
.DrawLine( horizX
+m_indent
, oldY
+5, horizX
+m_indent
, semiOldY 
); 
1712 void wxTreeCtrl::DrawDropEffect(wxGenericTreeItem 
*item
) 
1716         if ( item
->HasPlus() ) 
1718             // it's a folder, indicate it by a border 
1723             // draw a line under the drop target because the item will be 
1725             DrawLine(item
, TRUE 
/* below */); 
1728         SetCursor(wxCURSOR_BULLSEYE
); 
1733         SetCursor(wxCURSOR_NO_ENTRY
); 
1737 void wxTreeCtrl::DrawBorder(const wxTreeItemId 
&item
) 
1739     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxTreeCtrl::DrawLine") ); 
1741     wxGenericTreeItem 
*i 
= item
.m_pItem
; 
1743     wxClientDC 
dc(this); 
1745     dc
.SetLogicalFunction(wxINVERT
); 
1746     dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1748     int w 
= i
->GetWidth() + 2; 
1749     int h 
= GetLineHeight(i
) + 2; 
1751     dc
.DrawRectangle( i
->GetX() - 1, i
->GetY() - 1, w
, h
); 
1754 void wxTreeCtrl::DrawLine(const wxTreeItemId 
&item
, bool below
) 
1756     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxTreeCtrl::DrawLine") ); 
1758     wxGenericTreeItem 
*i 
= item
.m_pItem
; 
1760     wxClientDC 
dc(this); 
1762     dc
.SetLogicalFunction(wxINVERT
); 
1768         y 
+= GetLineHeight(i
) - 1; 
1771     dc
.DrawLine( x
, y
, x 
+ i
->GetWidth(), y
); 
1774 // ----------------------------------------------------------------------------- 
1775 // wxWindows callbacks 
1776 // ----------------------------------------------------------------------------- 
1778 void wxTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1786     dc
.SetFont( m_normalFont 
); 
1787     dc
.SetPen( m_dottedPen 
); 
1789     // this is now done dynamically 
1790     //if(GetImageList() == NULL) 
1791     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
1794     PaintLevel( m_anchor
, dc
, 0, y 
); 
1797 void wxTreeCtrl::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1801     if (m_current
) RefreshLine( m_current 
); 
1804 void wxTreeCtrl::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1808     if (m_current
) RefreshLine( m_current 
); 
1811 void wxTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
1813     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
1814     te
.m_code 
= (int)event
.KeyCode(); 
1815     te
.SetEventObject( this ); 
1816     GetEventHandler()->ProcessEvent( te 
); 
1818     if ( (m_current 
== 0) || (m_key_current 
== 0) ) 
1824     // how should the selection work for this event? 
1825     bool is_multiple
, extended_select
, unselect_others
; 
1826     EventFlagsToSelType(GetWindowStyleFlag(), 
1828                         event
.ControlDown(), 
1829                         &is_multiple
, &extended_select
, &unselect_others
); 
1831     switch (event
.KeyCode()) 
1835             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
1843             if (IsExpanded(m_current
)) 
1845                 Collapse(m_current
); 
1857                 wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
1858                 event
.m_item 
= m_current
; 
1860                 event
.SetEventObject( this ); 
1861                 GetEventHandler()->ProcessEvent( event 
); 
1865             // up goes to the previous sibling or to the last of its children if 
1869                 wxTreeItemId prev 
= GetPrevSibling( m_key_current 
); 
1872                     prev 
= GetParent( m_key_current 
); 
1876                         wxTreeItemId current 
= m_key_current
; 
1877                         if (current 
== GetFirstChild( prev
, cockie 
)) 
1879                             // otherwise we return to where we came from 
1880                             SelectItem( prev
, unselect_others
, extended_select 
); 
1881                             m_key_current
=prev
.m_pItem
; 
1882                             EnsureVisible( prev 
); 
1889                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
1891                         wxTreeItemId child 
= GetLastChild(prev
); 
1898                     SelectItem( prev
, unselect_others
, extended_select 
); 
1899                     m_key_current
=prev
.m_pItem
; 
1900                     EnsureVisible( prev 
); 
1905             // left arrow goes to the parent 
1908                 wxTreeItemId prev 
= GetParent( m_current 
); 
1911                     EnsureVisible( prev 
); 
1912                     SelectItem( prev
, unselect_others
, extended_select 
); 
1918             // this works the same as the down arrow except that we also expand the 
1919             // item if it wasn't expanded yet 
1925                 if (IsExpanded(m_key_current
) && HasChildren(m_key_current
)) 
1928                     wxTreeItemId child 
= GetFirstChild( m_key_current
, cookie 
); 
1929                     SelectItem( child
, unselect_others
, extended_select 
); 
1930                     m_key_current
=child
.m_pItem
; 
1931                     EnsureVisible( child 
); 
1935                     wxTreeItemId next 
= GetNextSibling( m_key_current 
); 
1939                         wxTreeItemId current 
= m_key_current
; 
1940                         while (current 
&& !next
) 
1942                             current 
= GetParent( current 
); 
1943                             if (current
) next 
= GetNextSibling( current 
); 
1949                         SelectItem( next
, unselect_others
, extended_select 
); 
1950                         m_key_current
=next
.m_pItem
; 
1951                         EnsureVisible( next 
); 
1957             // <End> selects the last visible tree item 
1960                 wxTreeItemId last 
= GetRootItem(); 
1962                 while ( last
.IsOk() && IsExpanded(last
) ) 
1964                     wxTreeItemId lastChild 
= GetLastChild(last
); 
1966                     // it may happen if the item was expanded but then all of 
1967                     // its children have been deleted - so IsExpanded() returned 
1968                     // TRUE, but GetLastChild() returned invalid item 
1977                     EnsureVisible( last 
); 
1978                     SelectItem( last
, unselect_others
, extended_select 
); 
1983             // <Home> selects the root item 
1986                 wxTreeItemId prev 
= GetRootItem(); 
1989                     EnsureVisible( prev 
); 
1990                     SelectItem( prev
, unselect_others
, extended_select 
); 
2000 wxTreeItemId 
wxTreeCtrl::HitTest(const wxPoint
& point
, int& flags
) 
2002     // We have to call this here because the label in 
2003     // question might just have been added and no screen 
2004     // update taken place. 
2005     if (m_dirty
) wxYield(); 
2007     wxClientDC 
dc(this); 
2009     wxCoord x 
= dc
.DeviceToLogicalX( point
.x 
); 
2010     wxCoord y 
= dc
.DeviceToLogicalY( point
.y 
); 
2015     if (point
.x
<0) flags
|=wxTREE_HITTEST_TOLEFT
; 
2016     if (point
.x
>w
) flags
|=wxTREE_HITTEST_TORIGHT
; 
2017     if (point
.y
<0) flags
|=wxTREE_HITTEST_ABOVE
; 
2018     if (point
.y
>h
) flags
|=wxTREE_HITTEST_BELOW
; 
2020     return m_anchor
->HitTest( wxPoint(x
, y
), this, flags
); 
2025 void wxTreeCtrl::Edit( const wxTreeItemId
& item 
) 
2027     if (!item
.IsOk()) return; 
2029     m_currentEdit 
= item
.m_pItem
; 
2031     wxTreeEvent 
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, GetId() ); 
2032     te
.m_item 
= m_currentEdit
; 
2033     te
.SetEventObject( this ); 
2034     GetEventHandler()->ProcessEvent( te 
); 
2036     if (!te
.IsAllowed()) return; 
2038     // We have to call this here because the label in 
2039     // question might just have been added and no screen 
2040     // update taken place. 
2041     if (m_dirty
) wxYield(); 
2043     wxString s 
= m_currentEdit
->GetText(); 
2044     int x 
= m_currentEdit
->GetX(); 
2045     int y 
= m_currentEdit
->GetY(); 
2046     int w 
= m_currentEdit
->GetWidth(); 
2047     int h 
= m_currentEdit
->GetHeight(); 
2052     int image 
= m_currentEdit
->GetCurrentImage(); 
2053     if ( image 
!= NO_IMAGE 
) 
2055         m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
2059     w 
-= image_w 
+ 4; // I don't know why +4 is needed 
2061     wxClientDC 
dc(this); 
2063     x 
= dc
.LogicalToDeviceX( x 
); 
2064     y 
= dc
.LogicalToDeviceY( y 
); 
2066     wxTreeTextCtrl 
*text 
= new wxTreeTextCtrl( 
2067       this, -1, &m_renameAccept
, &m_renameRes
, this, s
, wxPoint(x
-4,y
-4), wxSize(w
+11,h
+8) ); 
2071 void wxTreeCtrl::OnRenameTimer() 
2076 void wxTreeCtrl::OnRenameAccept() 
2078     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
2079     le
.m_item 
= m_currentEdit
; 
2080     le
.SetEventObject( this ); 
2081     le
.m_label 
= m_renameRes
; 
2082     GetEventHandler()->ProcessEvent( le 
); 
2084     if (!le
.IsAllowed()) return; 
2086     SetItemText( m_currentEdit
, m_renameRes 
); 
2089 void wxTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
2091     if ( !m_anchor 
) return; 
2093     // we process left mouse up event (enables in-place edit), right down 
2094     // (pass to the user code), left dbl click (activate item) and 
2095     // dragging/moving events for items drag-and-drop 
2096     if ( !(event
.LeftUp() || 
2097            event
.RightDown() || 
2098            event
.LeftDClick() || 
2100            ((event
.Moving() || event
.RightUp()) && m_isDragging
)) ) 
2107     wxClientDC 
dc(this); 
2109     wxCoord x 
= dc
.DeviceToLogicalX( event
.GetX() ); 
2110     wxCoord y 
= dc
.DeviceToLogicalY( event
.GetY() ); 
2113     wxGenericTreeItem 
*item 
= m_anchor
->HitTest( wxPoint(x
,y
), this, flags
); 
2115     bool onButton 
= flags 
& wxTREE_HITTEST_ONITEMBUTTON
; 
2117     if ( event
.Dragging() && !m_isDragging 
) 
2119         if (m_dragCount 
== 0) 
2120             m_dragStart 
= wxPoint(x
,y
); 
2124         if (m_dragCount 
!= 3) 
2126             // wait until user drags a bit further... 
2130         wxEventType command 
= event
.RightIsDown() 
2131                               ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
 
2132                               : wxEVT_COMMAND_TREE_BEGIN_DRAG
; 
2134         wxTreeEvent 
nevent( command
, GetId() ); 
2135         nevent
.m_item 
= m_current
; 
2136         nevent
.SetEventObject(this); 
2138         // by default the dragging is not supported, the user code must 
2139         // explicitly allow the event for it to take place 
2142         if ( GetEventHandler()->ProcessEvent(nevent
) && nevent
.IsAllowed() ) 
2144             // we're going to drag this item 
2145             m_isDragging 
= TRUE
; 
2147             // remember the old cursor because we will change it while 
2149             m_oldCursor 
= m_cursor
; 
2151             // in a single selection control, hide the selection temporarily 
2152             if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE
) ) 
2154                 m_oldSelection 
= GetSelection().m_pItem
; 
2156                 if ( m_oldSelection 
) 
2158                     m_oldSelection
->SetHilight(FALSE
); 
2159                     RefreshLine(m_oldSelection
); 
2166     else if ( event
.Moving() ) 
2168         if ( item 
!= m_dropTarget 
) 
2170             // unhighlight the previous drop target 
2171             DrawDropEffect(m_dropTarget
); 
2173             m_dropTarget 
= item
; 
2175             // highlight the current drop target if any 
2176             DrawDropEffect(m_dropTarget
); 
2181     else if ( (event
.LeftUp() || event
.RightUp()) && m_isDragging 
) 
2183         // erase the highlighting 
2184         DrawDropEffect(m_dropTarget
); 
2186         // generate the drag end event 
2187         wxTreeEvent 
event(wxEVT_COMMAND_TREE_END_DRAG
, GetId()); 
2189         event
.m_item 
= item
; 
2190         event
.m_pointDrag 
= wxPoint(x
, y
); 
2191         event
.SetEventObject(this); 
2193         (void)GetEventHandler()->ProcessEvent(event
); 
2195         m_isDragging 
= FALSE
; 
2196         m_dropTarget 
= (wxGenericTreeItem 
*)NULL
; 
2198         if ( m_oldSelection 
) 
2200             m_oldSelection
->SetHilight(TRUE
); 
2201             RefreshLine(m_oldSelection
); 
2202             m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
2207         SetCursor(m_oldCursor
); 
2213         // here we process only the messages which happen on tree items 
2217         if (item 
== NULL
) return;  /* we hit the blank area */ 
2219         if ( event
.RightDown() ) 
2221             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
, GetId()); 
2222             nevent
.m_item 
= item
; 
2224             nevent
.SetEventObject(this); 
2225             GetEventHandler()->ProcessEvent(nevent
); 
2227         else if ( event
.LeftUp() && (item 
== m_current
) && 
2228                  (flags 
& wxTREE_HITTEST_ONITEMLABEL
) && 
2229                  HasFlag(wxTR_EDIT_LABELS
) ) 
2231             m_renameTimer
->Start( 100, TRUE 
); 
2235             // how should the selection work for this event? 
2236             bool is_multiple
, extended_select
, unselect_others
; 
2237             EventFlagsToSelType(GetWindowStyleFlag(), 
2239                                 event
.ControlDown(), 
2240                                 &is_multiple
, &extended_select
, &unselect_others
); 
2249             SelectItem(item
, unselect_others
, extended_select
); 
2251             if ( event
.LeftDClick() ) 
2253                 wxTreeEvent 
nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
2254                 nevent
.m_item 
= item
; 
2256                 nevent
.SetEventObject( this ); 
2257                 GetEventHandler()->ProcessEvent( nevent 
); 
2263 void wxTreeCtrl::OnIdle( wxIdleEvent 
&WXUNUSED(event
) ) 
2265     /* after all changes have been done to the tree control, 
2266      * we actually redraw the tree when everything is over */ 
2273     CalculatePositions(); 
2275     AdjustMyScrollbars(); 
2278 void wxTreeCtrl::CalculateSize( wxGenericTreeItem 
*item
, wxDC 
&dc 
) 
2284         dc
.SetFont(m_boldFont
); 
2286     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
2289     // restore normal font 
2290     dc
.SetFont( m_normalFont 
); 
2294     int image 
= item
->GetCurrentImage(); 
2295     if ( image 
!= NO_IMAGE 
) 
2297         m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
2301     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
2304         total_h 
+= 2;            // at least 2 pixels 
2306         total_h 
+= total_h
/10;   // otherwise 10% extra spacing 
2308     item
->SetHeight(total_h
); 
2309     if (total_h
>m_lineHeight
) 
2310         m_lineHeight
=total_h
; 
2312     item
->SetWidth(image_w
+text_w
+2); 
2315 // ----------------------------------------------------------------------------- 
2316 // for developper : y is now the top of the level 
2317 // not the middle of it ! 
2318 void wxTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
2320     int horizX 
= level
*m_indent
; 
2322     CalculateSize( item
, dc 
); 
2325     item
->SetX( horizX
+m_indent
+m_spacing 
); 
2327     y
+=GetLineHeight(item
); 
2329     if ( !item
->IsExpanded() ) 
2331         // we dont need to calculate collapsed branches 
2335     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2336     size_t n
, count 
= children
.Count(); 
2337     for (n 
= 0; n 
< count
; ++n 
) 
2338         CalculateLevel( children
[n
], dc
, level
+1, y 
);  // recurse 
2341 void wxTreeCtrl::CalculatePositions() 
2343     if ( !m_anchor 
) return; 
2345     wxClientDC 
dc(this); 
2348     dc
.SetFont( m_normalFont 
); 
2350     dc
.SetPen( m_dottedPen 
); 
2351     //if(GetImageList() == NULL) 
2352     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
2355     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
2358 void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
2360     if (m_dirty
) return; 
2362     wxClientDC 
dc(this); 
2367     GetClientSize( &cw
, &ch 
); 
2370     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
2372     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
2375     Refresh( TRUE
, &rect 
); 
2377     AdjustMyScrollbars(); 
2380 void wxTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
2382     if (m_dirty
) return; 
2384     wxClientDC 
dc(this); 
2389     GetClientSize( &cw
, &ch 
); 
2392     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
2393     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
2395     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
2397     Refresh( TRUE
, &rect 
);