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 and Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================= 
  14 // ============================================================================= 
  16 // ----------------------------------------------------------------------------- 
  18 // ----------------------------------------------------------------------------- 
  21   #pragma implementation "treectlg.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  33 #include "wx/treebase.h" 
  34 #include "wx/generic/treectlg.h" 
  36 #include "wx/textctrl.h" 
  37 #include "wx/imaglist.h" 
  38 #include "wx/settings.h" 
  39 #include "wx/dcclient.h" 
  41 // ----------------------------------------------------------------------------- 
  43 // ----------------------------------------------------------------------------- 
  45 class WXDLLEXPORT wxGenericTreeItem
; 
  47 WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem 
*, wxArrayGenericTreeItems
); 
  49 // ---------------------------------------------------------------------------- 
  51 // ---------------------------------------------------------------------------- 
  53 static const int NO_IMAGE 
= -1; 
  55 static const int PIXELS_PER_UNIT 
= 10; 
  57 // ---------------------------------------------------------------------------- 
  59 // ---------------------------------------------------------------------------- 
  62 static const char *aqua_arrow_right
[] = { 
  63 /* columns rows colors chars-per-pixel */ 
  84 static const char *aqua_arrow_down
[] = { 
  85 /* columns rows colors chars-per-pixel */ 
 105 // ----------------------------------------------------------------------------- 
 107 // ----------------------------------------------------------------------------- 
 109 // timer used for enabling in-place edit 
 110 class WXDLLEXPORT wxTreeRenameTimer
: public wxTimer
 
 113     // start editing the current item after half a second (if the mouse hasn't 
 114     // been clicked/moved) 
 115     enum { DELAY 
= 500 }; 
 117     wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
); 
 119     virtual void Notify(); 
 122     wxGenericTreeCtrl 
*m_owner
; 
 124     DECLARE_NO_COPY_CLASS(wxTreeRenameTimer
) 
 127 // control used for in-place edit 
 128 class WXDLLEXPORT wxTreeTextCtrl
: public wxTextCtrl
 
 131     wxTreeTextCtrl(wxGenericTreeCtrl 
*owner
, wxGenericTreeItem 
*item
); 
 134     void OnChar( wxKeyEvent 
&event 
); 
 135     void OnKeyUp( wxKeyEvent 
&event 
); 
 136     void OnKillFocus( wxFocusEvent 
&event 
); 
 138     bool AcceptChanges(); 
 142     wxGenericTreeCtrl  
*m_owner
; 
 143     wxGenericTreeItem  
*m_itemEdited
; 
 144     wxString            m_startValue
; 
 147     DECLARE_EVENT_TABLE() 
 148     DECLARE_NO_COPY_CLASS(wxTreeTextCtrl
) 
 151 // timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed 
 152 // for a sufficiently long time 
 153 class WXDLLEXPORT wxTreeFindTimer 
: public wxTimer
 
 156     // reset the current prefix after half a second of inactivity 
 157     enum { DELAY 
= 500 }; 
 159     wxTreeFindTimer( wxGenericTreeCtrl 
*owner 
) { m_owner 
= owner
; } 
 161     virtual void Notify() { m_owner
->m_findPrefix
.clear(); } 
 164     wxGenericTreeCtrl 
*m_owner
; 
 166     DECLARE_NO_COPY_CLASS(wxTreeFindTimer
) 
 170 class WXDLLEXPORT wxGenericTreeItem
 
 174     wxGenericTreeItem() { m_data 
= NULL
; } 
 175     wxGenericTreeItem( wxGenericTreeItem 
*parent
, 
 176                        const wxString
& text
, 
 179                        wxTreeItemData 
*data 
); 
 181     ~wxGenericTreeItem(); 
 184     wxArrayGenericTreeItems
& GetChildren() { return m_children
; } 
 186     const wxString
& GetText() const { return m_text
; } 
 187     int GetImage(wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) const 
 188         { return m_images
[which
]; } 
 189     wxTreeItemData 
*GetData() const { return m_data
; } 
 191     // returns the current image for the item (depending on its 
 192     // selected/expanded/whatever state) 
 193     int GetCurrentImage() const; 
 195     void SetText( const wxString 
&text 
); 
 196     void SetImage(int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; } 
 197     void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
 199     void SetHasPlus(bool has 
= TRUE
) { m_hasPlus 
= has
; } 
 201     void SetBold(bool bold
) { m_isBold 
= bold
; } 
 203     int GetX() const { return m_x
; } 
 204     int GetY() const { return m_y
; } 
 206     void SetX(int x
) { m_x 
= x
; } 
 207     void SetY(int y
) { m_y 
= y
; } 
 209     int  GetHeight() const { return m_height
; } 
 210     int  GetWidth()  const { return m_width
; } 
 212     void SetHeight(int h
) { m_height 
= h
; } 
 213     void SetWidth(int w
) { m_width 
= w
; } 
 215     wxGenericTreeItem 
*GetParent() const { return m_parent
; } 
 218         // deletes all children notifying the treectrl about it if !NULL 
 220     void DeleteChildren(wxGenericTreeCtrl 
*tree 
= NULL
); 
 222     // get count of all children (and grand children if 'recursively') 
 223     size_t GetChildrenCount(bool recursively 
= TRUE
) const; 
 225     void Insert(wxGenericTreeItem 
*child
, size_t index
) 
 226     { m_children
.Insert(child
, index
); } 
 228     void GetSize( int &x
, int &y
, const wxGenericTreeCtrl
* ); 
 230         // return the item at given position (or NULL if no item), onButton is 
 231         // TRUE if the point belongs to the item's button, otherwise it lies 
 232         // on the button's label 
 233     wxGenericTreeItem 
*HitTest( const wxPoint
& point
, 
 234                                 const wxGenericTreeCtrl 
*, 
 238     void Expand() { m_isCollapsed 
= FALSE
; } 
 239     void Collapse() { m_isCollapsed 
= TRUE
; } 
 241     void SetHilight( bool set 
= TRUE 
) { m_hasHilight 
= set
; } 
 244     bool HasChildren() const { return !m_children
.IsEmpty(); } 
 245     bool IsSelected()  const { return m_hasHilight 
!= 0; } 
 246     bool IsExpanded()  const { return !m_isCollapsed
; } 
 247     bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 248     bool IsBold()      const { return m_isBold 
!= 0; } 
 251         // get them - may be NULL 
 252     wxTreeItemAttr 
*GetAttributes() const { return m_attr
; } 
 253         // get them ensuring that the pointer is not NULL 
 254     wxTreeItemAttr
& Attr() 
 258             m_attr 
= new wxTreeItemAttr
; 
 264     void SetAttributes(wxTreeItemAttr 
*attr
) 
 266         if ( m_ownsAttr 
) delete m_attr
; 
 270         // set them and delete when done 
 271     void AssignAttributes(wxTreeItemAttr 
*attr
) 
 278     // since there can be very many of these, we save size by chosing 
 279     // the smallest representation for the elements and by ordering 
 280     // the members to avoid padding. 
 281     wxString            m_text
;         // label to be rendered for item 
 283     wxTreeItemData     
*m_data
;         // user-provided data 
 285     wxArrayGenericTreeItems m_children
; // list of children 
 286     wxGenericTreeItem  
*m_parent
;       // parent of this item 
 288     wxTreeItemAttr     
*m_attr
;         // attributes??? 
 290     // tree ctrl images for the normal, selected, expanded and 
 291     // expanded+selected states 
 292     short               m_images
[wxTreeItemIcon_Max
]; 
 294     wxCoord             m_x
;            // (virtual) offset from top 
 295     wxCoord             m_y
;            // (virtual) offset from left 
 296     short               m_width
;        // width of this item 
 297     unsigned char       m_height
;       // height of this item 
 299     // use bitfields to save size 
 300     int                 m_isCollapsed 
:1; 
 301     int                 m_hasHilight  
:1; // same as focused 
 302     int                 m_hasPlus     
:1; // used for item which doesn't have 
 303                                           // children but has a [+] button 
 304     int                 m_isBold      
:1; // render the label in bold font 
 305     int                 m_ownsAttr    
:1; // delete attribute when done 
 307     DECLARE_NO_COPY_CLASS(wxGenericTreeItem
) 
 310 // ============================================================================= 
 312 // ============================================================================= 
 314 // ---------------------------------------------------------------------------- 
 316 // ---------------------------------------------------------------------------- 
 318 // translate the key or mouse event flags to the type of selection we're 
 320 static void EventFlagsToSelType(long style
, 
 324                                 bool &extended_select
, 
 325                                 bool &unselect_others
) 
 327     is_multiple 
= (style 
& wxTR_MULTIPLE
) != 0; 
 328     extended_select 
= shiftDown 
&& is_multiple
; 
 329     unselect_others 
= !(extended_select 
|| (ctrlDown 
&& is_multiple
)); 
 332 // check if the given item is under another one 
 333 static bool IsDescendantOf(wxGenericTreeItem 
*parent
, wxGenericTreeItem 
*item
) 
 337         if ( item 
== parent 
) 
 339             // item is a descendant of parent 
 343         item 
= item
->GetParent(); 
 349 // ----------------------------------------------------------------------------- 
 350 // wxTreeRenameTimer (internal) 
 351 // ----------------------------------------------------------------------------- 
 353 wxTreeRenameTimer::wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
) 
 358 void wxTreeRenameTimer::Notify() 
 360     m_owner
->OnRenameTimer(); 
 363 //----------------------------------------------------------------------------- 
 364 // wxTreeTextCtrl (internal) 
 365 //----------------------------------------------------------------------------- 
 367 BEGIN_EVENT_TABLE(wxTreeTextCtrl
,wxTextCtrl
) 
 368     EVT_CHAR           (wxTreeTextCtrl::OnChar
) 
 369     EVT_KEY_UP         (wxTreeTextCtrl::OnKeyUp
) 
 370     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus
) 
 373 wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl 
*owner
, 
 374                                wxGenericTreeItem 
*item
) 
 375               : m_itemEdited(item
), m_startValue(item
->GetText()) 
 380     int w 
= m_itemEdited
->GetWidth(), 
 381         h 
= m_itemEdited
->GetHeight(); 
 384     m_owner
->CalcScrolledPosition(item
->GetX(), item
->GetY(), &x
, &y
); 
 389     int image 
= item
->GetCurrentImage(); 
 390     if ( image 
!= NO_IMAGE 
) 
 392         if ( m_owner
->m_imageListNormal 
) 
 394             m_owner
->m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
 399             wxFAIL_MSG(_T("you must create an image list to use images!")); 
 403     // FIXME: what are all these hardcoded 4, 8 and 11s really? 
 407     (void)Create(m_owner
, wxID_ANY
, m_startValue
, 
 408                  wxPoint(x 
- 4, y 
- 4), wxSize(w 
+ 11, h 
+ 8)); 
 411 bool wxTreeTextCtrl::AcceptChanges() 
 413     const wxString value 
= GetValue(); 
 415     if ( value 
== m_startValue 
) 
 417         // nothing changed, always accept 
 421     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
 423         // vetoed by the user 
 427     // accepted, do rename the item 
 428     m_owner
->SetItemText(m_itemEdited
, value
); 
 433 void wxTreeTextCtrl::Finish() 
 437         m_owner
->ResetTextControl(); 
 439         wxPendingDelete
.Append(this); 
 443         m_owner
->SetFocus(); // This doesn't work. TODO. 
 447 void wxTreeTextCtrl::OnChar( wxKeyEvent 
&event 
) 
 449     switch ( event
.m_keyCode 
) 
 452             if ( !AcceptChanges() ) 
 454                 // vetoed by the user, don't disappear 
 461             m_owner
->OnRenameCancelled(m_itemEdited
); 
 469 void wxTreeTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
 473         // auto-grow the textctrl: 
 474         wxSize parentSize 
= m_owner
->GetSize(); 
 475         wxPoint myPos 
= GetPosition(); 
 476         wxSize mySize 
= GetSize(); 
 478         GetTextExtent(GetValue() + _T("M"), &sx
, &sy
); 
 479         if (myPos
.x 
+ sx 
> parentSize
.x
) 
 480             sx 
= parentSize
.x 
- myPos
.x
; 
 489 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
 497     if ( AcceptChanges() ) 
 503 // ----------------------------------------------------------------------------- 
 505 // ----------------------------------------------------------------------------- 
 507 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 508                                      const wxString
& text
, 
 509                                      int image
, int selImage
, 
 510                                      wxTreeItemData 
*data
) 
 513     m_images
[wxTreeItemIcon_Normal
] = image
; 
 514     m_images
[wxTreeItemIcon_Selected
] = selImage
; 
 515     m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
; 
 516     m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
; 
 521     m_isCollapsed 
= TRUE
; 
 522     m_hasHilight 
= FALSE
; 
 528     m_attr 
= (wxTreeItemAttr 
*)NULL
; 
 531     // We don't know the height here yet. 
 536 wxGenericTreeItem::~wxGenericTreeItem() 
 540     if (m_ownsAttr
) delete m_attr
; 
 542     wxASSERT_MSG( m_children
.IsEmpty(), 
 543                   wxT("please call DeleteChildren() before deleting the item") ); 
 546 void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl 
*tree
) 
 548     size_t count 
= m_children
.Count(); 
 549     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 551         wxGenericTreeItem 
*child 
= m_children
[n
]; 
 553             tree
->SendDeleteEvent(child
); 
 555         child
->DeleteChildren(tree
); 
 562 void wxGenericTreeItem::SetText( const wxString 
&text 
) 
 567 size_t wxGenericTreeItem::GetChildrenCount(bool recursively
) const 
 569     size_t count 
= m_children
.Count(); 
 573     size_t total 
= count
; 
 574     for (size_t n 
= 0; n 
< count
; ++n
) 
 576         total 
+= m_children
[n
]->GetChildrenCount(); 
 582 void wxGenericTreeItem::GetSize( int &x
, int &y
, 
 583                                  const wxGenericTreeCtrl 
*theButton 
) 
 585     int bottomY
=m_y
+theButton
->GetLineHeight(this); 
 586     if ( y 
< bottomY 
) y 
= bottomY
; 
 587     int width 
= m_x 
+  m_width
; 
 588     if ( x 
< width 
) x 
= width
; 
 592         size_t count 
= m_children
.Count(); 
 593         for ( size_t n 
= 0; n 
< count
; ++n 
) 
 595             m_children
[n
]->GetSize( x
, y
, theButton 
); 
 600 wxGenericTreeItem 
*wxGenericTreeItem::HitTest(const wxPoint
& point
, 
 601                                               const wxGenericTreeCtrl 
*theCtrl
, 
 605     // for a hidden root node, don't evaluate it, but do evaluate children 
 606     if ( !(level 
== 0 && theCtrl
->HasFlag(wxTR_HIDE_ROOT
)) ) 
 609         int h 
= theCtrl
->GetLineHeight(this); 
 610         if ((point
.y 
> m_y
) && (point
.y 
< m_y 
+ h
)) 
 612             int y_mid 
= m_y 
+ h
/2; 
 613             if (point
.y 
< y_mid 
) 
 614                 flags 
|= wxTREE_HITTEST_ONITEMUPPERPART
; 
 616                 flags 
|= wxTREE_HITTEST_ONITEMLOWERPART
; 
 618             // 5 is the size of the plus sign 
 619             int xCross 
= m_x 
- theCtrl
->GetSpacing(); 
 620             if ((point
.x 
> xCross
-5) && (point
.x 
< xCross
+5) && 
 621                 (point
.y 
> y_mid
-5) && (point
.y 
< y_mid
+5) && 
 622                 HasPlus() && theCtrl
->HasButtons() ) 
 624                 flags 
|= wxTREE_HITTEST_ONITEMBUTTON
; 
 628             if ((point
.x 
>= m_x
) && (point
.x 
<= m_x
+m_width
)) 
 633                 // assuming every image (normal and selected) has the same size! 
 634                 if ( (GetImage() != NO_IMAGE
) && theCtrl
->m_imageListNormal 
) 
 635                     theCtrl
->m_imageListNormal
->GetSize(GetImage(), 
 638                 if ((image_w 
!= -1) && (point
.x 
<= m_x 
+ image_w 
+ 1)) 
 639                     flags 
|= wxTREE_HITTEST_ONITEMICON
; 
 641                     flags 
|= wxTREE_HITTEST_ONITEMLABEL
; 
 647                 flags 
|= wxTREE_HITTEST_ONITEMINDENT
; 
 648             if (point
.x 
> m_x
+m_width
) 
 649                 flags 
|= wxTREE_HITTEST_ONITEMRIGHT
; 
 654         // if children are expanded, fall through to evaluate them 
 655         if (m_isCollapsed
) return (wxGenericTreeItem
*) NULL
; 
 659     size_t count 
= m_children
.Count(); 
 660     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 662         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, 
 670     return (wxGenericTreeItem
*) NULL
; 
 673 int wxGenericTreeItem::GetCurrentImage() const 
 675     int image 
= NO_IMAGE
; 
 680             image 
= GetImage(wxTreeItemIcon_SelectedExpanded
); 
 683         if ( image 
== NO_IMAGE 
) 
 685             // we usually fall back to the normal item, but try just the 
 686             // expanded one (and not selected) first in this case 
 687             image 
= GetImage(wxTreeItemIcon_Expanded
); 
 693             image 
= GetImage(wxTreeItemIcon_Selected
); 
 696     // maybe it doesn't have the specific image we want, 
 697     // try the default one instead 
 698     if ( image 
== NO_IMAGE 
) image 
= GetImage(); 
 703 // ----------------------------------------------------------------------------- 
 704 // wxGenericTreeCtrl implementation 
 705 // ----------------------------------------------------------------------------- 
 707 IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl
, wxScrolledWindow
) 
 709 BEGIN_EVENT_TABLE(wxGenericTreeCtrl
,wxScrolledWindow
) 
 710     EVT_PAINT          (wxGenericTreeCtrl::OnPaint
) 
 711     EVT_MOUSE_EVENTS   (wxGenericTreeCtrl::OnMouse
) 
 712     EVT_CHAR           (wxGenericTreeCtrl::OnChar
) 
 713     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus
) 
 714     EVT_KILL_FOCUS     (wxGenericTreeCtrl::OnKillFocus
) 
 715     EVT_IDLE           (wxGenericTreeCtrl::OnIdle
) 
 718 #if !defined(__WXMSW__) || defined(__WIN16__) || defined(__WXUNIVERSAL__) 
 720  * wxTreeCtrl has to be a real class or we have problems with 
 721  * the run-time information. 
 724 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxGenericTreeCtrl
) 
 727 // ----------------------------------------------------------------------------- 
 728 // construction/destruction 
 729 // ----------------------------------------------------------------------------- 
 731 void wxGenericTreeCtrl::Init() 
 733     m_current 
= m_key_current 
= m_anchor 
= (wxGenericTreeItem 
*) NULL
; 
 741     m_hilightBrush 
= new wxBrush
 
 743                             wxSystemSettings::GetColour
 
 745                                 wxSYS_COLOUR_HIGHLIGHT
 
 750     m_hilightUnfocusedBrush 
= new wxBrush
 
 752                                  wxSystemSettings::GetColour
 
 754                                      wxSYS_COLOUR_BTNSHADOW
 
 759     m_imageListNormal 
= m_imageListButtons 
= 
 760     m_imageListState 
= (wxImageList 
*) NULL
; 
 761     m_ownsImageListNormal 
= m_ownsImageListButtons 
= 
 762     m_ownsImageListState 
= FALSE
; 
 765     m_isDragging 
= FALSE
; 
 766     m_dropTarget 
= m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
 769     m_renameTimer 
= NULL
; 
 772     m_lastOnSame 
= FALSE
; 
 774     m_normalFont 
= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT 
); 
 775     m_boldFont 
= wxFont(m_normalFont
.GetPointSize(), 
 776                         m_normalFont
.GetFamily(), 
 777                         m_normalFont
.GetStyle(), 
 779                         m_normalFont
.GetUnderlined(), 
 780                         m_normalFont
.GetFaceName(), 
 781                         m_normalFont
.GetEncoding()); 
 784 bool wxGenericTreeCtrl::Create(wxWindow 
*parent
, 
 789                                const wxValidator 
&validator
, 
 790                                const wxString
& name 
) 
 794     wxGetOsVersion( &major
, &minor 
); 
 796     if (style 
& wxTR_HAS_BUTTONS
) style 
|= wxTR_MAC_BUTTONS
; 
 797     if (style 
& wxTR_HAS_BUTTONS
) style 
&= ~wxTR_HAS_BUTTONS
; 
 798     style 
&= ~wxTR_LINES_AT_ROOT
; 
 799     style 
|= wxTR_NO_LINES
; 
 801         style 
|= wxTR_ROW_LINES
; 
 803         style 
|= wxTR_AQUA_BUTTONS
; 
 806     if (style 
& wxTR_AQUA_BUTTONS
) 
 808         m_arrowRight 
= new wxBitmap( aqua_arrow_right 
); 
 809         m_arrowDown 
= new wxBitmap( aqua_arrow_down 
); 
 817     wxScrolledWindow::Create( parent
, id
, pos
, size
, 
 818                               style
|wxHSCROLL
|wxVSCROLL
, name 
); 
 820     // If the tree display has no buttons, but does have 
 821     // connecting lines, we can use a narrower layout. 
 822     // It may not be a good idea to force this... 
 823     if (!HasButtons() && !HasFlag(wxTR_NO_LINES
)) 
 830     SetValidator( validator 
); 
 833     SetForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
) ); 
 834     SetBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
) ); 
 836 //  m_dottedPen = wxPen( "grey", 0, wxDOT );  too slow under XFree86 
 837     m_dottedPen 
= wxPen( wxT("grey"), 0, 0 ); 
 842 wxGenericTreeCtrl::~wxGenericTreeCtrl() 
 844     delete m_hilightBrush
; 
 845     delete m_hilightUnfocusedBrush
; 
 852     delete m_renameTimer
; 
 855     if (m_ownsImageListNormal
) 
 856         delete m_imageListNormal
; 
 857     if (m_ownsImageListState
) 
 858         delete m_imageListState
; 
 859     if (m_ownsImageListButtons
) 
 860         delete m_imageListButtons
; 
 863 // ----------------------------------------------------------------------------- 
 865 // ----------------------------------------------------------------------------- 
 867 size_t wxGenericTreeCtrl::GetCount() const 
 869     return m_anchor 
== NULL 
? 0u : m_anchor
->GetChildrenCount(); 
 872 void wxGenericTreeCtrl::SetIndent(unsigned int indent
) 
 874     m_indent 
= (unsigned short) indent
; 
 878 void wxGenericTreeCtrl::SetSpacing(unsigned int spacing
) 
 880     m_spacing 
= (unsigned short) spacing
; 
 884 size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
) 
 886     wxCHECK_MSG( item
.IsOk(), 0u, wxT("invalid tree item") ); 
 888     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildrenCount(recursively
); 
 891 void wxGenericTreeCtrl::SetWindowStyle(const long styles
) 
 893     if (!HasFlag(wxTR_HIDE_ROOT
) && (styles 
& wxTR_HIDE_ROOT
)) 
 895         // if we will hide the root, make sure children are visible 
 896         m_anchor
->SetHasPlus(); 
 898         CalculatePositions(); 
 901     // right now, just sets the styles.  Eventually, we may 
 902     // want to update the inherited styles, but right now 
 903     // none of the parents has updatable styles 
 904     m_windowStyle 
= styles
; 
 908 // ----------------------------------------------------------------------------- 
 909 // functions to work with tree items 
 910 // ----------------------------------------------------------------------------- 
 912 wxString 
wxGenericTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 914     wxCHECK_MSG( item
.IsOk(), wxT(""), wxT("invalid tree item") ); 
 916     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetText(); 
 919 int wxGenericTreeCtrl::GetItemImage(const wxTreeItemId
& item
, 
 920                              wxTreeItemIcon which
) const 
 922     wxCHECK_MSG( item
.IsOk(), -1, wxT("invalid tree item") ); 
 924     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetImage(which
); 
 927 wxTreeItemData 
*wxGenericTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 929     wxCHECK_MSG( item
.IsOk(), NULL
, wxT("invalid tree item") ); 
 931     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetData(); 
 934 wxColour 
wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId
& item
) const 
 936     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
 938     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 939     return pItem
->Attr().GetTextColour(); 
 942 wxColour 
wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId
& item
) const 
 944     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
 946     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 947     return pItem
->Attr().GetBackgroundColour(); 
 950 wxFont 
wxGenericTreeCtrl::GetItemFont(const wxTreeItemId
& item
) const 
 952     wxCHECK_MSG( item
.IsOk(), wxNullFont
, wxT("invalid tree item") ); 
 954     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 955     return pItem
->Attr().GetFont(); 
 958 void wxGenericTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 960     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 963     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 964     pItem
->SetText(text
); 
 965     CalculateSize(pItem
, dc
); 
 969 void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId
& item
, 
 971                               wxTreeItemIcon which
) 
 973     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 975     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 976     pItem
->SetImage(image
, which
); 
 979     CalculateSize(pItem
, dc
); 
 983 void wxGenericTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 985     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 987     ((wxGenericTreeItem
*) item
.m_pItem
)->SetData(data
); 
 990 void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
 992     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 994     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 995     pItem
->SetHasPlus(has
); 
 999 void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
1001     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1003     // avoid redrawing the tree if no real change 
1004     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1005     if ( pItem
->IsBold() != bold 
) 
1007         pItem
->SetBold(bold
); 
1012 void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId
& item
, 
1013                                    const wxColour
& col
) 
1015     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1017     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1018     pItem
->Attr().SetTextColour(col
); 
1022 void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
, 
1023                                          const wxColour
& col
) 
1025     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1027     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1028     pItem
->Attr().SetBackgroundColour(col
); 
1032 void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
) 
1034     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1036     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1037     pItem
->Attr().SetFont(font
); 
1041 bool wxGenericTreeCtrl::SetFont( const wxFont 
&font 
) 
1043     wxScrolledWindow::SetFont(font
); 
1045     m_normalFont 
= font 
; 
1046     m_boldFont 
= wxFont(m_normalFont
.GetPointSize(), 
1047                         m_normalFont
.GetFamily(), 
1048                         m_normalFont
.GetStyle(), 
1050                         m_normalFont
.GetUnderlined(), 
1051                         m_normalFont
.GetFaceName(), 
1052                         m_normalFont
.GetEncoding()); 
1058 // ----------------------------------------------------------------------------- 
1059 // item status inquiries 
1060 // ----------------------------------------------------------------------------- 
1062 bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId
& item
) const 
1064     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1066     // An item is only visible if it's not a descendant of a collapsed item 
1067     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1068     wxGenericTreeItem
* parent 
= pItem
->GetParent(); 
1071         if (!parent
->IsExpanded()) 
1073         parent 
= parent
->GetParent(); 
1077     GetViewStart(& startX
, & startY
); 
1079     wxSize clientSize 
= GetClientSize(); 
1082     if (!GetBoundingRect(item
, rect
)) 
1084     if (rect
.GetWidth() == 0 || rect
.GetHeight() == 0) 
1086     if (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) 
1088     if (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
) 
1094 bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
1096     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1098     // consider that the item does have children if it has the "+" button: it 
1099     // might not have them (if it had never been expanded yet) but then it 
1100     // could have them as well and it's better to err on this side rather than 
1101     // disabling some operations which are restricted to the items with 
1102     // children for an item which does have them 
1103     return ((wxGenericTreeItem
*) item
.m_pItem
)->HasPlus(); 
1106 bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
1108     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1110     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsExpanded(); 
1113 bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
1115     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1117     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsSelected(); 
1120 bool wxGenericTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
1122     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1124     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsBold(); 
1127 // ----------------------------------------------------------------------------- 
1129 // ----------------------------------------------------------------------------- 
1131 wxTreeItemId 
wxGenericTreeCtrl::GetItemParent(const wxTreeItemId
& item
) const 
1133     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1135     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetParent(); 
1138 wxTreeItemId 
wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const 
1140     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1143     return GetNextChild(item
, cookie
); 
1146 wxTreeItemId 
wxGenericTreeCtrl::GetNextChild(const wxTreeItemId
& item
, long& cookie
) const 
1148     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1150     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1151     if ( (size_t)cookie 
< children
.Count() ) 
1153         return children
.Item((size_t)cookie
++); 
1157         // there are no more of them 
1158         return wxTreeItemId(); 
1162 wxTreeItemId 
wxGenericTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
1164     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1166     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1167     return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
1170 wxTreeItemId 
wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
1172     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1174     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1175     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1176     if ( parent 
== NULL 
) 
1178         // root item doesn't have any siblings 
1179         return wxTreeItemId(); 
1182     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1183     int index 
= siblings
.Index(i
); 
1184     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1186     size_t n 
= (size_t)(index 
+ 1); 
1187     return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
1190 wxTreeItemId 
wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
1192     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1194     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1195     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1196     if ( parent 
== NULL 
) 
1198         // root item doesn't have any siblings 
1199         return wxTreeItemId(); 
1202     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1203     int index 
= siblings
.Index(i
); 
1204     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1206     return index 
== 0 ? wxTreeItemId() 
1207                       : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
1210 // Only for internal use right now, but should probably be public 
1211 wxTreeItemId 
wxGenericTreeCtrl::GetNext(const wxTreeItemId
& item
) const 
1213     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1215     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1217     // First see if there are any children. 
1218     wxArrayGenericTreeItems
& children 
= i
->GetChildren(); 
1219     if (children
.GetCount() > 0) 
1221          return children
.Item(0); 
1225          // Try a sibling of this or ancestor instead 
1226          wxTreeItemId p 
= item
; 
1227          wxTreeItemId toFind
; 
1230               toFind 
= GetNextSibling(p
); 
1231               p 
= GetItemParent(p
); 
1232          } while (p
.IsOk() && !toFind
.IsOk()); 
1237 wxTreeItemId 
wxGenericTreeCtrl::GetFirstVisibleItem() const 
1239     wxTreeItemId id 
= GetRootItem(); 
1248     } while (id
.IsOk()); 
1250     return wxTreeItemId(); 
1253 wxTreeItemId 
wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
1255     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1257     wxTreeItemId id 
= item
; 
1260         while (id 
= GetNext(id
), id
.IsOk()) 
1266     return wxTreeItemId(); 
1269 wxTreeItemId 
wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
1271     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1273     wxFAIL_MSG(wxT("not implemented")); 
1275     return wxTreeItemId(); 
1278 // called by wxTextTreeCtrl when it marks itself for deletion 
1279 void wxGenericTreeCtrl::ResetTextControl() 
1284 // find the first item starting with the given prefix after the given item 
1285 wxTreeItemId 
wxGenericTreeCtrl::FindItem(const wxTreeItemId
& idParent
, 
1286                                          const wxString
& prefixOrig
) const 
1288     // match is case insensitive as this is more convenient to the user: having 
1289     // to press Shift-letter to go to the item starting with a capital letter 
1290     // would be too bothersome 
1291     wxString prefix 
= prefixOrig
.Lower(); 
1293     // determine the starting point: we shouldn't take the current item (this 
1294     // allows to switch between two items starting with the same letter just by 
1295     // pressing it) but we shouldn't jump to the next one if the user is 
1296     // continuing to type as otherwise he might easily skip the item he wanted 
1297     wxTreeItemId id 
= idParent
; 
1298     if ( prefix
.length() == 1 ) 
1303     // look for the item starting with the given prefix after it 
1304     while ( id
.IsOk() && !GetItemText(id
).Lower().StartsWith(prefix
) ) 
1309     // if we haven't found anything... 
1312         // ... wrap to the beginning 
1314         if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1316             // can't select virtual root 
1320         // and try all the items (stop when we get to the one we started from) 
1321         while ( id 
!= idParent 
&& !GetItemText(id
).Lower().StartsWith(prefix
) ) 
1330 // ----------------------------------------------------------------------------- 
1332 // ----------------------------------------------------------------------------- 
1334 wxTreeItemId 
wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
1336                                       const wxString
& text
, 
1337                                       int image
, int selImage
, 
1338                                       wxTreeItemData 
*data
) 
1340     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1343         // should we give a warning here? 
1344         return AddRoot(text
, image
, selImage
, data
); 
1347     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1349     wxGenericTreeItem 
*item 
= 
1350         new wxGenericTreeItem( parent
, text
, image
, selImage
, data 
); 
1354         data
->m_pItem 
= (long) item
; 
1357     parent
->Insert( item
, previous 
); 
1362 wxTreeItemId 
wxGenericTreeCtrl::AddRoot(const wxString
& text
, 
1363                                  int image
, int selImage
, 
1364                                  wxTreeItemData 
*data
) 
1366     wxCHECK_MSG( !m_anchor
, wxTreeItemId(), wxT("tree can have only one root") ); 
1368     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1370     m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, 
1371                                    image
, selImage
, data
); 
1374         data
->m_pItem 
= (long) m_anchor
; 
1377     if (HasFlag(wxTR_HIDE_ROOT
)) 
1379         // if root is hidden, make sure we can navigate 
1381         m_anchor
->SetHasPlus(); 
1383         CalculatePositions(); 
1386     if (!HasFlag(wxTR_MULTIPLE
)) 
1388         m_current 
= m_key_current 
= m_anchor
; 
1389         m_current
->SetHilight( TRUE 
); 
1395 wxTreeItemId 
wxGenericTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
1396                                      const wxString
& text
, 
1397                                      int image
, int selImage
, 
1398                                      wxTreeItemData 
*data
) 
1400     return DoInsertItem(parent
, 0u, text
, image
, selImage
, data
); 
1403 wxTreeItemId 
wxGenericTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
1404                                     const wxTreeItemId
& idPrevious
, 
1405                                     const wxString
& text
, 
1406                                     int image
, int selImage
, 
1407                                     wxTreeItemData 
*data
) 
1409     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1412         // should we give a warning here? 
1413         return AddRoot(text
, image
, selImage
, data
); 
1417     if (idPrevious
.IsOk()) 
1419         index 
= parent
->GetChildren().Index((wxGenericTreeItem
*) idPrevious
.m_pItem
); 
1420         wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
1421                       wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") ); 
1424     return DoInsertItem(parentId
, (size_t)++index
, text
, image
, selImage
, data
); 
1427 wxTreeItemId 
wxGenericTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
1429                                     const wxString
& text
, 
1430                                     int image
, int selImage
, 
1431                                     wxTreeItemData 
*data
) 
1433     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1436         // should we give a warning here? 
1437         return AddRoot(text
, image
, selImage
, data
); 
1440     return DoInsertItem(parentId
, before
, text
, image
, selImage
, data
); 
1443 wxTreeItemId 
wxGenericTreeCtrl::AppendItem(const wxTreeItemId
& parentId
, 
1444                                     const wxString
& text
, 
1445                                     int image
, int selImage
, 
1446                                     wxTreeItemData 
*data
) 
1448     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1451         // should we give a warning here? 
1452         return AddRoot(text
, image
, selImage
, data
); 
1455     return DoInsertItem( parent
, parent
->GetChildren().Count(), text
, 
1456                          image
, selImage
, data
); 
1459 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
1461     wxTreeEvent 
event( wxEVT_COMMAND_TREE_DELETE_ITEM
, GetId() ); 
1462     event
.m_item 
= (long) item
; 
1463     event
.SetEventObject( this ); 
1464     ProcessEvent( event 
); 
1467 void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
1469     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1471     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1472     item
->DeleteChildren(this); 
1475 void wxGenericTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
1477     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1479     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1481     wxGenericTreeItem 
*parent 
= item
->GetParent(); 
1483     // don't keep stale pointers around! 
1484     if ( IsDescendantOf(item
, m_key_current
) ) 
1486         m_key_current 
= parent
; 
1489     if ( IsDescendantOf(item
, m_current
) ) 
1494     // remove the item from the tree 
1497         parent
->GetChildren().Remove( item 
);  // remove by value 
1499     else // deleting the root 
1501         // nothing will be left in the tree 
1505     // and delete all of its children and the item itself now 
1506     item
->DeleteChildren(this); 
1507     SendDeleteEvent(item
); 
1511 void wxGenericTreeCtrl::DeleteAllItems() 
1519 void wxGenericTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
1521     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1523     wxCHECK_RET( item
, _T("invalid item in wxGenericTreeCtrl::Expand") ); 
1524     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1525                  _T("can't expand hidden root") ); 
1527     if ( !item
->HasPlus() ) 
1530     if ( item
->IsExpanded() ) 
1533     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
1534     event
.m_item 
= (long) item
; 
1535     event
.SetEventObject( this ); 
1537     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1539         // cancelled by program 
1544     CalculatePositions(); 
1546     RefreshSubtree(item
); 
1548     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
1549     ProcessEvent( event 
); 
1552 void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId
& item
) 
1554     if ( !HasFlag(wxTR_HIDE_ROOT
) || item 
!= GetRootItem()) 
1557         if ( !IsExpanded(item
) ) 
1562     wxTreeItemId child 
= GetFirstChild(item
, cookie
); 
1563     while ( child
.IsOk() ) 
1567         child 
= GetNextChild(item
, cookie
); 
1571 void wxGenericTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
1573     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1574                  _T("can't collapse hidden root") ); 
1576     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1578     if ( !item
->IsExpanded() ) 
1581     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
1582     event
.m_item 
= (long) item
; 
1583     event
.SetEventObject( this ); 
1584     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1586         // cancelled by program 
1592 #if 0  // TODO why should items be collapsed recursively? 
1593     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1594     size_t count 
= children
.Count(); 
1595     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1597         Collapse(children
[n
]); 
1601     CalculatePositions(); 
1603     RefreshSubtree(item
); 
1605     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
1606     ProcessEvent( event 
); 
1609 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
1612     DeleteChildren(item
); 
1615 void wxGenericTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
1617     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1619     if (item
->IsExpanded()) 
1625 void wxGenericTreeCtrl::Unselect() 
1629         m_current
->SetHilight( FALSE 
); 
1630         RefreshLine( m_current 
); 
1636 void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem 
*item
) 
1638     if (item
->IsSelected()) 
1640         item
->SetHilight(FALSE
); 
1644     if (item
->HasChildren()) 
1646         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1647         size_t count 
= children
.Count(); 
1648         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1650             UnselectAllChildren(children
[n
]); 
1655 void wxGenericTreeCtrl::UnselectAll() 
1657     wxTreeItemId rootItem 
= GetRootItem(); 
1659     // the tree might not have the root item at all 
1662         UnselectAllChildren((wxGenericTreeItem
*) rootItem
.m_pItem
); 
1666 // Recursive function ! 
1667 // To stop we must have crt_item<last_item 
1669 // Tag all next children, when no more children, 
1670 // Move to parent (not to tag) 
1671 // Keep going... if we found last_item, we stop. 
1672 bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1674     wxGenericTreeItem 
*parent 
= crt_item
->GetParent(); 
1676     if (parent 
== NULL
) // This is root item 
1677         return TagAllChildrenUntilLast(crt_item
, last_item
, select
); 
1679     wxArrayGenericTreeItems
& children 
= parent
->GetChildren(); 
1680     int index 
= children
.Index(crt_item
); 
1681     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1683     size_t count 
= children
.Count(); 
1684     for (size_t n
=(size_t)(index
+1); n
<count
; ++n
) 
1686         if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return TRUE
; 
1689     return TagNextChildren(parent
, last_item
, select
); 
1692 bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1694     crt_item
->SetHilight(select
); 
1695     RefreshLine(crt_item
); 
1697     if (crt_item
==last_item
) 
1700     if (crt_item
->HasChildren()) 
1702         wxArrayGenericTreeItems
& children 
= crt_item
->GetChildren(); 
1703         size_t count 
= children
.Count(); 
1704         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1706             if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) 
1714 void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem 
*item1
, wxGenericTreeItem 
*item2
) 
1716     // item2 is not necessary after item1 
1717     wxGenericTreeItem 
*first
=NULL
, *last
=NULL
; 
1719     // choice first' and 'last' between item1 and item2 
1720     if (item1
->GetY()<item2
->GetY()) 
1731     bool select 
= m_current
->IsSelected(); 
1733     if ( TagAllChildrenUntilLast(first
,last
,select
) ) 
1736     TagNextChildren(first
,last
,select
); 
1739 void wxGenericTreeCtrl::SelectItem(const wxTreeItemId
& itemId
, 
1740                                    bool unselect_others
, 
1741                                    bool extended_select
) 
1743     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1745     bool is_single
=!(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1746     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1748     //wxCHECK_RET( ( (!unselect_others) && is_single), 
1749     //           wxT("this is a single selection tree") ); 
1751     // to keep going anyhow !!! 
1754         if (item
->IsSelected()) 
1755             return; // nothing to do 
1756         unselect_others 
= TRUE
; 
1757         extended_select 
= FALSE
; 
1759     else if ( unselect_others 
&& item
->IsSelected() ) 
1761         // selection change if there is more than one item currently selected 
1762         wxArrayTreeItemIds selected_items
; 
1763         if ( GetSelections(selected_items
) == 1 ) 
1767     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
1768     event
.m_item 
= (long) item
; 
1769     event
.m_itemOld 
= (long) m_current
; 
1770     event
.SetEventObject( this ); 
1771     // TODO : Here we don't send any selection mode yet ! 
1773     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
1776     wxTreeItemId parent 
= GetItemParent( itemId 
); 
1777     while (parent
.IsOk()) 
1779         if (!IsExpanded(parent
)) 
1782         parent 
= GetItemParent( parent 
); 
1785     EnsureVisible( itemId 
); 
1788     if (unselect_others
) 
1790         if (is_single
) Unselect(); // to speed up thing 
1795     if (extended_select
) 
1799             m_current 
= m_key_current 
= (wxGenericTreeItem
*) GetRootItem().m_pItem
; 
1802         // don't change the mark (m_current) 
1803         SelectItemRange(m_current
, item
); 
1807         bool select
=TRUE
; // the default 
1809         // Check if we need to toggle hilight (ctrl mode) 
1810         if (!unselect_others
) 
1811             select
=!item
->IsSelected(); 
1813         m_current 
= m_key_current 
= item
; 
1814         m_current
->SetHilight(select
); 
1815         RefreshLine( m_current 
); 
1818     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
1819     GetEventHandler()->ProcessEvent( event 
); 
1822 void wxGenericTreeCtrl::FillArray(wxGenericTreeItem 
*item
, 
1823                                   wxArrayTreeItemIds 
&array
) const 
1825     if ( item
->IsSelected() ) 
1826         array
.Add(wxTreeItemId(item
)); 
1828     if ( item
->HasChildren() ) 
1830         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1831         size_t count 
= children
.GetCount(); 
1832         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1833             FillArray(children
[n
], array
); 
1837 size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds 
&array
) const 
1840     wxTreeItemId idRoot 
= GetRootItem(); 
1841     if ( idRoot
.IsOk() ) 
1843         FillArray((wxGenericTreeItem
*) idRoot
.m_pItem
, array
); 
1845     //else: the tree is empty, so no selections 
1847     return array
.Count(); 
1850 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
1852     if (!item
.IsOk()) return; 
1854     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1856     // first expand all parent branches 
1857     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
1859     if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1861         while ( parent 
!= m_anchor 
) 
1864             parent 
= parent
->GetParent(); 
1872             parent 
= parent
->GetParent(); 
1876     //if (parent) CalculatePositions(); 
1881 void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId 
&item
) 
1883     if (!item
.IsOk()) return; 
1885     // We have to call this here because the label in 
1886     // question might just have been added and no screen 
1887     // update taken place. 
1888     if (m_dirty
) wxYieldIfNeeded(); 
1890     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1892     // now scroll to the item 
1893     int item_y 
= gitem
->GetY(); 
1897     GetViewStart( &start_x
, &start_y 
); 
1898     start_y 
*= PIXELS_PER_UNIT
; 
1902     GetClientSize( &client_w
, &client_h 
); 
1904     if (item_y 
< start_y
+3) 
1909         m_anchor
->GetSize( x
, y
, this ); 
1910         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1911         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1912         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1913         // Item should appear at top 
1914         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, item_y
/PIXELS_PER_UNIT 
); 
1916     else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) 
1921         m_anchor
->GetSize( x
, y
, this ); 
1922         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1923         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1924         item_y 
+= PIXELS_PER_UNIT
+2; 
1925         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1926         // Item should appear at bottom 
1927         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 
); 
1931 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
1932 static wxGenericTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
1934 static int LINKAGEMODE 
tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
1935                                   wxGenericTreeItem 
**item2
) 
1937     wxCHECK_MSG( s_treeBeingSorted
, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") ); 
1939     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
1942 int wxGenericTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
1943                                const wxTreeItemId
& item2
) 
1945     return wxStrcmp(GetItemText(item1
), GetItemText(item2
)); 
1948 void wxGenericTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
1950     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1952     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1954     wxCHECK_RET( !s_treeBeingSorted
, 
1955                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") ); 
1957     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1958     if ( children
.Count() > 1 ) 
1962         s_treeBeingSorted 
= this; 
1963         children
.Sort(tree_ctrl_compare_func
); 
1964         s_treeBeingSorted 
= NULL
; 
1966     //else: don't make the tree dirty as nothing changed 
1969 wxImageList 
*wxGenericTreeCtrl::GetImageList() const 
1971     return m_imageListNormal
; 
1974 wxImageList 
*wxGenericTreeCtrl::GetButtonsImageList() const 
1976     return m_imageListButtons
; 
1979 wxImageList 
*wxGenericTreeCtrl::GetStateImageList() const 
1981     return m_imageListState
; 
1984 void wxGenericTreeCtrl::CalculateLineHeight() 
1986     wxClientDC 
dc(this); 
1987     m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1989     if ( m_imageListNormal 
) 
1991         // Calculate a m_lineHeight value from the normal Image sizes. 
1992         // May be toggle off. Then wxGenericTreeCtrl will spread when 
1993         // necessary (which might look ugly). 
1994         int n 
= m_imageListNormal
->GetImageCount(); 
1995         for (int i 
= 0; i 
< n 
; i
++) 
1997             int width 
= 0, height 
= 0; 
1998             m_imageListNormal
->GetSize(i
, width
, height
); 
1999             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2003     if (m_imageListButtons
) 
2005         // Calculate a m_lineHeight value from the Button image sizes. 
2006         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2007         // necessary (which might look ugly). 
2008         int n 
= m_imageListButtons
->GetImageCount(); 
2009         for (int i 
= 0; i 
< n 
; i
++) 
2011             int width 
= 0, height 
= 0; 
2012             m_imageListButtons
->GetSize(i
, width
, height
); 
2013             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2017     if (m_lineHeight 
< 30) 
2018         m_lineHeight 
+= 2;                 // at least 2 pixels 
2020         m_lineHeight 
+= m_lineHeight
/10;   // otherwise 10% extra spacing 
2023 void wxGenericTreeCtrl::SetImageList(wxImageList 
*imageList
) 
2025     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
2026     m_imageListNormal 
= imageList
; 
2027     m_ownsImageListNormal 
= FALSE
; 
2029     // Don't do any drawing if we're setting the list to NULL, 
2030     // since we may be in the process of deleting the tree control. 
2032         CalculateLineHeight(); 
2035 void wxGenericTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
2037     if (m_ownsImageListState
) delete m_imageListState
; 
2038     m_imageListState 
= imageList
; 
2039     m_ownsImageListState 
= FALSE
; 
2042 void wxGenericTreeCtrl::SetButtonsImageList(wxImageList 
*imageList
) 
2044     if (m_ownsImageListButtons
) delete m_imageListButtons
; 
2045     m_imageListButtons 
= imageList
; 
2046     m_ownsImageListButtons 
= FALSE
; 
2048     CalculateLineHeight(); 
2051 void wxGenericTreeCtrl::AssignImageList(wxImageList 
*imageList
) 
2053     SetImageList(imageList
); 
2054     m_ownsImageListNormal 
= TRUE
; 
2057 void wxGenericTreeCtrl::AssignStateImageList(wxImageList 
*imageList
) 
2059     SetStateImageList(imageList
); 
2060     m_ownsImageListState 
= TRUE
; 
2063 void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList 
*imageList
) 
2065     SetButtonsImageList(imageList
); 
2066     m_ownsImageListButtons 
= TRUE
; 
2069 // ----------------------------------------------------------------------------- 
2071 // ----------------------------------------------------------------------------- 
2073 void wxGenericTreeCtrl::AdjustMyScrollbars() 
2078         m_anchor
->GetSize( x
, y
, this ); 
2079         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2080         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2081         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2082         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
2083         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, y_pos 
); 
2087         SetScrollbars( 0, 0, 0, 0 ); 
2091 int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem 
*item
) const 
2093     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
2094         return item
->GetHeight(); 
2096         return m_lineHeight
; 
2099 void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
2101     // TODO implement "state" icon on items 
2103     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2104     if ( attr 
&& attr
->HasFont() ) 
2105         dc
.SetFont(attr
->GetFont()); 
2106     else if (item
->IsBold()) 
2107         dc
.SetFont(m_boldFont
); 
2109     long text_w 
= 0, text_h 
= 0; 
2110     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
2112     int image_h 
= 0, image_w 
= 0; 
2113     int image 
= item
->GetCurrentImage(); 
2114     if ( image 
!= NO_IMAGE 
) 
2116         if ( m_imageListNormal 
) 
2118             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
2127     int total_h 
= GetLineHeight(item
); 
2129     if ( item
->IsSelected() ) 
2131         dc
.SetBrush(*(m_hasFocus 
? m_hilightBrush 
: m_hilightUnfocusedBrush
)); 
2136         if ( attr 
&& attr
->HasBackgroundColour() ) 
2137             colBg 
= attr
->GetBackgroundColour(); 
2139             colBg 
= m_backgroundColour
; 
2140         dc
.SetBrush(wxBrush(colBg
, wxSOLID
)); 
2143     int offset 
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0; 
2145     if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT
) ) 
2149         DoGetPosition(&x
, &y
); 
2151         dc
.DrawRectangle(x
, item
->GetY()+offset
, w
, total_h
-offset
); 
2155         if ( item
->IsSelected() && image 
!= NO_IMAGE 
) 
2157             // If it's selected, and there's an image, then we should 
2158             // take care to leave the area under the image painted in the 
2159             // background colour. 
2160             dc
.DrawRectangle( item
->GetX() + image_w 
- 2, item
->GetY()+offset
, 
2161                               item
->GetWidth() - image_w 
+ 2, total_h
-offset 
); 
2165             dc
.DrawRectangle( item
->GetX()-2, item
->GetY()+offset
, 
2166                               item
->GetWidth()+2, total_h
-offset 
); 
2170     if ( image 
!= NO_IMAGE 
) 
2172         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
2173         m_imageListNormal
->Draw( image
, dc
, 
2175                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
2176                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
2177         dc
.DestroyClippingRegion(); 
2180     dc
.SetBackgroundMode(wxTRANSPARENT
); 
2181     int extraH 
= (total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0; 
2182     dc
.DrawText( item
->GetText(), 
2183                  (wxCoord
)(image_w 
+ item
->GetX()), 
2184                  (wxCoord
)(item
->GetY() + extraH
)); 
2186     // restore normal font 
2187     dc
.SetFont( m_normalFont 
); 
2190 // Now y stands for the top of the item, whereas it used to stand for middle ! 
2191 void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
2193     int x 
= level
*m_indent
; 
2194     if (!HasFlag(wxTR_HIDE_ROOT
)) 
2198     else if (level 
== 0) 
2200         // always expand hidden root 
2202         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2203         int count 
= children
.Count(); 
2209                 PaintLevel(children
[n
], dc
, 1, y
); 
2210             } while (++n 
< count
); 
2212             if (!HasFlag(wxTR_NO_LINES
) && HasFlag(wxTR_LINES_AT_ROOT
) && count 
> 0) 
2214                 // draw line down to last child 
2215                 origY 
+= GetLineHeight(children
[0])>>1; 
2216                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2217                 dc
.DrawLine(3, origY
, 3, oldY
); 
2223     item
->SetX(x
+m_spacing
); 
2226     int h 
= GetLineHeight(item
); 
2228     int y_mid 
= y_top 
+ (h
>>1); 
2231     int exposed_x 
= dc
.LogicalToDeviceX(0); 
2232     int exposed_y 
= dc
.LogicalToDeviceY(y_top
); 
2234     if (IsExposed(exposed_x
, exposed_y
, 10000, h
))  // 10000 = very much 
2238             // don't draw rect outline if we already have the 
2239             // background color under Mac 
2240             (item
->IsSelected() && m_hasFocus
) ? wxBLACK_PEN 
: 
2241 #endif // !__WXMAC__ 
2245         if ( item
->IsSelected() ) 
2247             colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
2251             wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2252             if (attr 
&& attr
->HasTextColour()) 
2253                 colText 
= attr
->GetTextColour(); 
2255                 colText 
= GetForegroundColour(); 
2259         dc
.SetTextForeground(colText
); 
2263         PaintItem(item
, dc
); 
2265         if (HasFlag(wxTR_ROW_LINES
)) 
2267             // if the background colour is white, choose a 
2268             // contrasting color for the lines 
2269             dc
.SetPen(*((GetBackgroundColour() == *wxWHITE
) 
2270                          ? wxMEDIUM_GREY_PEN 
: wxWHITE_PEN
)); 
2271             dc
.DrawLine(0, y_top
, 10000, y_top
); 
2272             dc
.DrawLine(0, y
, 10000, y
); 
2275         // restore DC objects 
2276         dc
.SetBrush(*wxWHITE_BRUSH
); 
2277         dc
.SetPen(m_dottedPen
); 
2278         dc
.SetTextForeground(*wxBLACK
); 
2280         if (item
->HasPlus() && HasButtons())  // should the item show a button? 
2282             if (!HasFlag(wxTR_NO_LINES
)) 
2284                 if (x 
> (signed)m_indent
) 
2285                     dc
.DrawLine(x 
- m_indent
, y_mid
, x 
- 5, y_mid
); 
2286                 else if (HasFlag(wxTR_LINES_AT_ROOT
)) 
2287                     dc
.DrawLine(3, y_mid
, x 
- 5, y_mid
); 
2288                 dc
.DrawLine(x 
+ 5, y_mid
, x 
+ m_spacing
, y_mid
); 
2291             if (m_imageListButtons 
!= NULL
) 
2293                 // draw the image button here 
2294                 int image_h 
= 0, image_w 
= 0, image 
= wxTreeItemIcon_Normal
; 
2295                 if (item
->IsExpanded()) image 
= wxTreeItemIcon_Expanded
; 
2296                 if (item
->IsSelected()) 
2297                     image 
+= wxTreeItemIcon_Selected 
- wxTreeItemIcon_Normal
; 
2298                 m_imageListButtons
->GetSize(image
, image_w
, image_h
); 
2299                 int xx 
= x 
- (image_w
>>1); 
2300                 int yy 
= y_mid 
- (image_h
>>1); 
2301                 dc
.SetClippingRegion(xx
, yy
, image_w
, image_h
); 
2302                 m_imageListButtons
->Draw(image
, dc
, xx
, yy
, 
2303                                          wxIMAGELIST_DRAW_TRANSPARENT
); 
2304                 dc
.DestroyClippingRegion(); 
2306             else if (HasFlag(wxTR_TWIST_BUTTONS
)) 
2308                 // draw the twisty button here 
2310                 if (HasFlag(wxTR_AQUA_BUTTONS
)) 
2312                     if (item
->IsExpanded()) 
2313                         dc
.DrawBitmap( *m_arrowDown
, x
-5, y_mid
-6, TRUE 
); 
2315                         dc
.DrawBitmap( *m_arrowRight
, x
-5, y_mid
-6, TRUE 
); 
2319                     dc
.SetBrush(*m_hilightBrush
); 
2320                     dc
.SetPen(*wxBLACK_PEN
); 
2323                     if (item
->IsExpanded()) 
2326                         button
[0].y 
= y_mid
-2; 
2328                         button
[1].y 
= y_mid
-2; 
2330                         button
[2].y 
= y_mid
+3; 
2334                         button
[0].y 
= y_mid
-5; 
2336                         button
[1].y 
= y_mid
+5; 
2338                         button
[2].y 
= y_mid
; 
2341                     dc
.DrawPolygon(3, button
); 
2342                     dc
.SetPen(m_dottedPen
); 
2345             else // if (HasFlag(wxTR_HAS_BUTTONS)) 
2347                 // draw the plus sign here 
2348                 dc
.SetPen(*wxGREY_PEN
); 
2349                 dc
.SetBrush(*wxWHITE_BRUSH
); 
2350                 dc
.DrawRectangle(x
-5, y_mid
-4, 11, 9); 
2351                 dc
.SetPen(*wxBLACK_PEN
); 
2352                 dc
.DrawLine(x
-2, y_mid
, x
+3, y_mid
); 
2353                 if (!item
->IsExpanded()) 
2354                     dc
.DrawLine(x
, y_mid
-2, x
, y_mid
+3); 
2355                 dc
.SetPen(m_dottedPen
); 
2358         else if (!HasFlag(wxTR_NO_LINES
))  // no button; maybe a line? 
2360             // draw the horizontal line here 
2362             if (x 
> (signed)m_indent
) 
2363                 x_start 
-= m_indent
; 
2364             else if (HasFlag(wxTR_LINES_AT_ROOT
)) 
2366             dc
.DrawLine(x_start
, y_mid
, x 
+ m_spacing
, y_mid
); 
2370     if (item
->IsExpanded()) 
2372         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2373         int count 
= children
.Count(); 
2380                 PaintLevel(children
[n
], dc
, level
, y
); 
2381             } while (++n 
< count
); 
2383             if (!HasFlag(wxTR_NO_LINES
) && count 
> 0) 
2385                 // draw line down to last child 
2386                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2387                 if (HasButtons()) y_mid 
+= 5; 
2389                 // Only draw the portion of the line that is visible, in case it is huge 
2390                 wxCoord xOrigin
=0, yOrigin
=0, width
, height
; 
2391                 dc
.GetDeviceOrigin(&xOrigin
, &yOrigin
); 
2392                 yOrigin 
= abs(yOrigin
); 
2393                 GetClientSize(&width
, &height
); 
2395                 // Move end points to the begining/end of the view? 
2396                 if (y_mid 
< yOrigin
) 
2398                 if (oldY 
> yOrigin 
+ height
) 
2399                     oldY 
= yOrigin 
+ height
; 
2401                 // after the adjustments if y_mid is larger than oldY then the line 
2402                 // isn't visible at all so don't draw anything 
2404                     dc
.DrawLine(x
, y_mid
, x
, oldY
); 
2410 void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem 
*item
) 
2414         if ( item
->HasPlus() ) 
2416             // it's a folder, indicate it by a border 
2421             // draw a line under the drop target because the item will be 
2423             DrawLine(item
, TRUE 
/* below */); 
2426         SetCursor(wxCURSOR_BULLSEYE
); 
2431         SetCursor(wxCURSOR_NO_ENTRY
); 
2435 void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId 
&item
) 
2437     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2439     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2441     wxClientDC 
dc(this); 
2443     dc
.SetLogicalFunction(wxINVERT
); 
2444     dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
2446     int w 
= i
->GetWidth() + 2; 
2447     int h 
= GetLineHeight(i
) + 2; 
2449     dc
.DrawRectangle( i
->GetX() - 1, i
->GetY() - 1, w
, h
); 
2452 void wxGenericTreeCtrl::DrawLine(const wxTreeItemId 
&item
, bool below
) 
2454     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2456     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2458     wxClientDC 
dc(this); 
2460     dc
.SetLogicalFunction(wxINVERT
); 
2466         y 
+= GetLineHeight(i
) - 1; 
2469     dc
.DrawLine( x
, y
, x 
+ i
->GetWidth(), y
); 
2472 // ----------------------------------------------------------------------------- 
2473 // wxWindows callbacks 
2474 // ----------------------------------------------------------------------------- 
2476 void wxGenericTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2484     dc
.SetFont( m_normalFont 
); 
2485     dc
.SetPen( m_dottedPen 
); 
2487     // this is now done dynamically 
2488     //if(GetImageList() == NULL) 
2489     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
2492     PaintLevel( m_anchor
, dc
, 0, y 
); 
2495 void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent 
&event 
) 
2504 void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2513 void wxGenericTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
2515     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
2516     te
.m_evtKey 
= event
; 
2517     te
.SetEventObject( this ); 
2518     if ( GetEventHandler()->ProcessEvent( te 
) ) 
2520         // intercepted by the user code 
2524     if ( (m_current 
== 0) || (m_key_current 
== 0) ) 
2530     // how should the selection work for this event? 
2531     bool is_multiple
, extended_select
, unselect_others
; 
2532     EventFlagsToSelType(GetWindowStyleFlag(), 
2534                         event
.ControlDown(), 
2535                         is_multiple
, extended_select
, unselect_others
); 
2539     // * : Expand all/Collapse all 
2540     // ' ' | return : activate 
2541     // up    : go up (not last children!) 
2543     // left  : go to parent 
2544     // right : open if parent and go next 
2545     // home  : go to root 
2546     // end   : go to last item without opening parents 
2547     // alnum : start or continue searching for the item with this prefix 
2548     int keyCode 
= event
.GetKeyCode(); 
2553             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
2561             if ( !IsExpanded(m_current
) ) 
2564                 ExpandAll(m_current
); 
2567             //else: fall through to Collapse() it 
2571             if (IsExpanded(m_current
)) 
2573                 Collapse(m_current
); 
2579             if ( !event
.HasModifiers() ) 
2581                 wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
2582                 event
.m_item 
= (long) m_current
; 
2583                 event
.SetEventObject( this ); 
2584                 GetEventHandler()->ProcessEvent( event 
); 
2587             // in any case, also generate the normal key event for this key, 
2588             // even if we generated the ACTIVATED event above: this is what 
2589             // wxMSW does and it makes sense because you might not want to 
2590             // process ACTIVATED event at all and handle Space and Return 
2591             // directly (and differently) which would be impossible otherwise 
2595             // up goes to the previous sibling or to the last 
2596             // of its children if it's expanded 
2599                 wxTreeItemId prev 
= GetPrevSibling( m_key_current 
); 
2602                     prev 
= GetItemParent( m_key_current 
); 
2603                     if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2605                         break;  // don't go to root if it is hidden 
2610                         wxTreeItemId current 
= m_key_current
; 
2611                         // TODO: Huh?  If we get here, we'd better be the first child of our parent.  How else could it be? 
2612                         if (current 
== GetFirstChild( prev
, cookie 
)) 
2614                             // otherwise we return to where we came from 
2615                             SelectItem( prev
, unselect_others
, extended_select 
); 
2616                             m_key_current
= (wxGenericTreeItem
*) prev
.m_pItem
; 
2623                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
2625                         wxTreeItemId child 
= GetLastChild(prev
); 
2632                     SelectItem( prev
, unselect_others
, extended_select 
); 
2633                     m_key_current
=(wxGenericTreeItem
*) prev
.m_pItem
; 
2638             // left arrow goes to the parent 
2641                 wxTreeItemId prev 
= GetItemParent( m_current 
); 
2642                 if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2644                     // don't go to root if it is hidden 
2645                     prev 
= GetPrevSibling( m_current 
); 
2649                     SelectItem( prev
, unselect_others
, extended_select 
); 
2655             // this works the same as the down arrow except that we 
2656             // also expand the item if it wasn't expanded yet 
2662                 if (IsExpanded(m_key_current
) && HasChildren(m_key_current
)) 
2665                     wxTreeItemId child 
= GetFirstChild( m_key_current
, cookie 
); 
2666                     SelectItem( child
, unselect_others
, extended_select 
); 
2667                     m_key_current
=(wxGenericTreeItem
*) child
.m_pItem
; 
2671                     wxTreeItemId next 
= GetNextSibling( m_key_current 
); 
2674                         wxTreeItemId current 
= m_key_current
; 
2675                         while (current 
&& !next
) 
2677                             current 
= GetItemParent( current 
); 
2678                             if (current
) next 
= GetNextSibling( current 
); 
2683                         SelectItem( next
, unselect_others
, extended_select 
); 
2684                         m_key_current
=(wxGenericTreeItem
*) next
.m_pItem
; 
2690             // <End> selects the last visible tree item 
2693                 wxTreeItemId last 
= GetRootItem(); 
2695                 while ( last
.IsOk() && IsExpanded(last
) ) 
2697                     wxTreeItemId lastChild 
= GetLastChild(last
); 
2699                     // it may happen if the item was expanded but then all of 
2700                     // its children have been deleted - so IsExpanded() returned 
2701                     // TRUE, but GetLastChild() returned invalid item 
2710                     SelectItem( last
, unselect_others
, extended_select 
); 
2715             // <Home> selects the root item 
2718                 wxTreeItemId prev 
= GetRootItem(); 
2722                 if ( HasFlag(wxTR_HIDE_ROOT
) ) 
2725                     prev 
= GetFirstChild(prev
, dummy
); 
2730                 SelectItem( prev
, unselect_others
, extended_select 
); 
2735             // do not use wxIsalnum() here 
2736             if ( !event
.HasModifiers() && 
2737                  ((keyCode 
>= '0' && keyCode 
<= '9') || 
2738                   (keyCode 
>= 'a' && keyCode 
<= 'z') || 
2739                   (keyCode 
>= 'A' && keyCode 
<= 'Z' ))) 
2741                 // find the next item starting with the given prefix 
2742                 char ch 
= (char)keyCode
; 
2744                 wxTreeItemId id 
= FindItem(m_current
, m_findPrefix 
+ (wxChar
)ch
); 
2755                 // also start the timer to reset the current prefix if the user 
2756                 // doesn't press any more alnum keys soon -- we wouldn't want 
2757                 // to use this prefix for a new item search 
2760                     m_findTimer 
= new wxTreeFindTimer(this); 
2763                 m_findTimer
->Start(wxTreeFindTimer::DELAY
, wxTIMER_ONE_SHOT
); 
2772 wxTreeItemId 
wxGenericTreeCtrl::HitTest(const wxPoint
& point
, int& flags
) 
2774     // JACS: removed wxYieldIfNeeded() because it can cause the window 
2775     // to be deleted from under us if a close window event is pending 
2780     if (point
.x
<0) flags 
|= wxTREE_HITTEST_TOLEFT
; 
2781     if (point
.x
>w
) flags 
|= wxTREE_HITTEST_TORIGHT
; 
2782     if (point
.y
<0) flags 
|= wxTREE_HITTEST_ABOVE
; 
2783     if (point
.y
>h
) flags 
|= wxTREE_HITTEST_BELOW
; 
2784     if (flags
) return wxTreeItemId(); 
2786     if (m_anchor 
== NULL
) 
2788         flags 
= wxTREE_HITTEST_NOWHERE
; 
2789         return wxTreeItemId(); 
2792     wxGenericTreeItem 
*hit 
=  m_anchor
->HitTest(CalcUnscrolledPosition(point
), 
2796         flags 
= wxTREE_HITTEST_NOWHERE
; 
2797         return wxTreeItemId(); 
2802 // get the bounding rectangle of the item (or of its label only) 
2803 bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
, 
2805                                         bool WXUNUSED(textOnly
)) const 
2807     wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") ); 
2809     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2812     GetViewStart(& startX
, & startY
); 
2814     rect
.x 
= i
->GetX() - startX
*PIXELS_PER_UNIT
; 
2815     rect
.y 
= i
->GetY() - startY
*PIXELS_PER_UNIT
; 
2816     rect
.width 
= i
->GetWidth(); 
2817     //rect.height = i->GetHeight(); 
2818     rect
.height 
= GetLineHeight(i
); 
2823 void wxGenericTreeCtrl::Edit( const wxTreeItemId
& item 
) 
2825     wxCHECK_RET( item
.IsOk(), _T("can't edit an invalid item") ); 
2827     wxGenericTreeItem 
*itemEdit 
= (wxGenericTreeItem 
*)item
.m_pItem
; 
2829     wxTreeEvent 
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, GetId() ); 
2830     te
.m_item 
= (long) itemEdit
; 
2831     te
.SetEventObject( this ); 
2832     if ( GetEventHandler()->ProcessEvent( te 
) && !te
.IsAllowed() ) 
2838     // We have to call this here because the label in 
2839     // question might just have been added and no screen 
2840     // update taken place. 
2844     m_textCtrl 
= new wxTreeTextCtrl(this, itemEdit
); 
2846     m_textCtrl
->SetFocus(); 
2849 // returns a pointer to the text edit control if the item is being 
2850 // edited, NULL otherwise (it's assumed that no more than one item may 
2851 // be edited simultaneously) 
2852 wxTextCtrl
* wxGenericTreeCtrl::GetEditControl() const 
2857 bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem 
*item
, 
2858                                        const wxString
& value
) 
2860     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
2861     le
.m_item 
= (long) item
; 
2862     le
.SetEventObject( this ); 
2864     le
.m_editCancelled 
= FALSE
; 
2866     return !GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
2869 void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem 
*item
) 
2871     // let owner know that the edit was cancelled 
2872     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
2873     le
.m_item 
= (long) item
; 
2874     le
.SetEventObject( this ); 
2875     le
.m_label 
= wxEmptyString
; 
2876     le
.m_editCancelled 
= FALSE
; 
2878     GetEventHandler()->ProcessEvent( le 
); 
2884 void wxGenericTreeCtrl::OnRenameTimer() 
2889 void wxGenericTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
2891     if ( !m_anchor 
) return; 
2893     // we process left mouse up event (enables in-place edit), right down 
2894     // (pass to the user code), left dbl click (activate item) and 
2895     // dragging/moving events for items drag-and-drop 
2896     if ( !(event
.LeftDown() || 
2898            event
.RightDown() || 
2899            event
.LeftDClick() || 
2901            ((event
.Moving() || event
.RightUp()) && m_isDragging
)) ) 
2908     wxPoint pt 
= CalcUnscrolledPosition(event
.GetPosition()); 
2911     wxGenericTreeItem 
*item 
= m_anchor
->HitTest(pt
, this, flags
, 0); 
2913     if ( event
.Dragging() && !m_isDragging 
) 
2915         if (m_dragCount 
== 0) 
2920         if (m_dragCount 
!= 3) 
2922             // wait until user drags a bit further... 
2926         wxEventType command 
= event
.RightIsDown() 
2927                               ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
 
2928                               : wxEVT_COMMAND_TREE_BEGIN_DRAG
; 
2930         wxTreeEvent 
nevent( command
, GetId() ); 
2931         nevent
.m_item 
= (long) m_current
; 
2932         nevent
.SetEventObject(this); 
2934         // by default the dragging is not supported, the user code must 
2935         // explicitly allow the event for it to take place 
2938         if ( GetEventHandler()->ProcessEvent(nevent
) && nevent
.IsAllowed() ) 
2940             // we're going to drag this item 
2941             m_isDragging 
= TRUE
; 
2943             // remember the old cursor because we will change it while 
2945             m_oldCursor 
= m_cursor
; 
2947             // in a single selection control, hide the selection temporarily 
2948             if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE
) ) 
2950                 m_oldSelection 
= (wxGenericTreeItem
*) GetSelection().m_pItem
; 
2952                 if ( m_oldSelection 
) 
2954                     m_oldSelection
->SetHilight(FALSE
); 
2955                     RefreshLine(m_oldSelection
); 
2962     else if ( event
.Moving() ) 
2964         if ( item 
!= m_dropTarget 
) 
2966             // unhighlight the previous drop target 
2967             DrawDropEffect(m_dropTarget
); 
2969             m_dropTarget 
= item
; 
2971             // highlight the current drop target if any 
2972             DrawDropEffect(m_dropTarget
); 
2977     else if ( (event
.LeftUp() || event
.RightUp()) && m_isDragging 
) 
2979         // erase the highlighting 
2980         DrawDropEffect(m_dropTarget
); 
2982         if ( m_oldSelection 
) 
2984             m_oldSelection
->SetHilight(TRUE
); 
2985             RefreshLine(m_oldSelection
); 
2986             m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
2989         // generate the drag end event 
2990         wxTreeEvent 
event(wxEVT_COMMAND_TREE_END_DRAG
, GetId()); 
2992         event
.m_item 
= (long) item
; 
2993         event
.m_pointDrag 
= pt
; 
2994         event
.SetEventObject(this); 
2996         (void)GetEventHandler()->ProcessEvent(event
); 
2998         m_isDragging 
= FALSE
; 
2999         m_dropTarget 
= (wxGenericTreeItem 
*)NULL
; 
3003         SetCursor(m_oldCursor
); 
3009         // here we process only the messages which happen on tree items 
3013         if (item 
== NULL
) return;  /* we hit the blank area */ 
3015         if ( event
.RightDown() ) 
3017             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
, GetId()); 
3018             nevent
.m_item 
= (long) item
; 
3019             nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3020             nevent
.SetEventObject(this); 
3021             GetEventHandler()->ProcessEvent(nevent
); 
3023         else if ( event
.LeftUp() ) 
3027                 if ( (item 
== m_current
) && 
3028                      (flags 
& wxTREE_HITTEST_ONITEMLABEL
) && 
3029                      HasFlag(wxTR_EDIT_LABELS
) ) 
3031                     if ( m_renameTimer 
) 
3033                         if ( m_renameTimer
->IsRunning() ) 
3034                             m_renameTimer
->Stop(); 
3038                         m_renameTimer 
= new wxTreeRenameTimer( this ); 
3041                     m_renameTimer
->Start( wxTreeRenameTimer::DELAY
, TRUE 
); 
3044                 m_lastOnSame 
= FALSE
; 
3047         else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick() 
3049             if ( event
.LeftDown() ) 
3051                 m_lastOnSame 
= item 
== m_current
; 
3054             if ( flags 
& wxTREE_HITTEST_ONITEMBUTTON 
) 
3056                 // only toggle the item for a single click, double click on 
3057                 // the button doesn't do anything (it toggles the item twice) 
3058                 if ( event
.LeftDown() ) 
3063                 // don't select the item if the button was clicked 
3067             // how should the selection work for this event? 
3068             bool is_multiple
, extended_select
, unselect_others
; 
3069             EventFlagsToSelType(GetWindowStyleFlag(), 
3071                                 event
.ControlDown(), 
3072                                 is_multiple
, extended_select
, unselect_others
); 
3074             SelectItem(item
, unselect_others
, extended_select
); 
3076             // For some reason, Windows isn't recognizing a left double-click, 
3077             // so we need to simulate it here.  Allow 200 milliseconds for now. 
3078             if ( event
.LeftDClick() ) 
3080                 // double clicking should not start editing the item label 
3081                 if ( m_renameTimer 
) 
3082                     m_renameTimer
->Stop(); 
3084                 m_lastOnSame 
= FALSE
; 
3086                 // send activate event first 
3087                 wxTreeEvent 
nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
3088                 nevent
.m_item 
= (long) item
; 
3089                 nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3090                 nevent
.SetEventObject( this ); 
3091                 if ( !GetEventHandler()->ProcessEvent( nevent 
) ) 
3093                     // if the user code didn't process the activate event, 
3094                     // handle it ourselves by toggling the item when it is 
3096                     if ( item
->HasPlus() ) 
3106 void wxGenericTreeCtrl::OnIdle( wxIdleEvent 
&WXUNUSED(event
) ) 
3108     /* after all changes have been done to the tree control, 
3109      * we actually redraw the tree when everything is over */ 
3111     if (!m_dirty
) return; 
3115     CalculatePositions(); 
3117     AdjustMyScrollbars(); 
3120 void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem 
*item
, wxDC 
&dc 
) 
3125     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
3126     if ( attr 
&& attr
->HasFont() ) 
3127         dc
.SetFont(attr
->GetFont()); 
3128     else if ( item
->IsBold() ) 
3129         dc
.SetFont(m_boldFont
); 
3131     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
3134     // restore normal font 
3135     dc
.SetFont( m_normalFont 
); 
3139     int image 
= item
->GetCurrentImage(); 
3140     if ( image 
!= NO_IMAGE 
) 
3142         if ( m_imageListNormal 
) 
3144             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
3149     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
3152         total_h 
+= 2;            // at least 2 pixels 
3154         total_h 
+= total_h
/10;   // otherwise 10% extra spacing 
3156     item
->SetHeight(total_h
); 
3157     if (total_h
>m_lineHeight
) 
3158         m_lineHeight
=total_h
; 
3160     item
->SetWidth(image_w
+text_w
+2); 
3163 // ----------------------------------------------------------------------------- 
3164 // for developper : y is now the top of the level 
3165 // not the middle of it ! 
3166 void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
3168     int x 
= level
*m_indent
; 
3169     if (!HasFlag(wxTR_HIDE_ROOT
)) 
3173     else if (level 
== 0) 
3175         // a hidden root is not evaluated, but its 
3176         // children are always calculated 
3180     CalculateSize( item
, dc 
); 
3183     item
->SetX( x
+m_spacing 
); 
3185     y 
+= GetLineHeight(item
); 
3187     if ( !item
->IsExpanded() ) 
3189         // we don't need to calculate collapsed branches 
3194     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3195     size_t n
, count 
= children
.Count(); 
3197     for (n 
= 0; n 
< count
; ++n 
) 
3198         CalculateLevel( children
[n
], dc
, level
, y 
);  // recurse 
3201 void wxGenericTreeCtrl::CalculatePositions() 
3203     if ( !m_anchor 
) return; 
3205     wxClientDC 
dc(this); 
3208     dc
.SetFont( m_normalFont 
); 
3210     dc
.SetPen( m_dottedPen 
); 
3211     //if(GetImageList() == NULL) 
3212     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
3215     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
3218 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
3220     if (m_dirty
) return; 
3222     wxSize client 
= GetClientSize(); 
3225     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3226     rect
.width 
= client
.x
; 
3227     rect
.height 
= client
.y
; 
3229     Refresh(TRUE
, &rect
); 
3231     AdjustMyScrollbars(); 
3234 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
3236     if (m_dirty
) return; 
3239     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3240     rect
.width 
= GetClientSize().x
; 
3241     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
3243     Refresh(TRUE
, &rect
); 
3246 void wxGenericTreeCtrl::RefreshSelected() 
3248     // TODO: this is awfully inefficient, we should keep the list of all 
3249     //       selected items internally, should be much faster 
3251         RefreshSelectedUnder(m_anchor
); 
3254 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem 
*item
) 
3256     if ( item
->IsSelected() ) 
3259     const wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3260     size_t count 
= children
.GetCount(); 
3261     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3263         RefreshSelectedUnder(children
[n
]); 
3267 // ---------------------------------------------------------------------------- 
3268 // changing colours: we need to refresh the tree control 
3269 // ---------------------------------------------------------------------------- 
3271 bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour
& colour
) 
3273     if ( !wxWindow::SetBackgroundColour(colour
) ) 
3281 bool wxGenericTreeCtrl::SetForegroundColour(const wxColour
& colour
) 
3283     if ( !wxWindow::SetForegroundColour(colour
) ) 
3291 #endif // wxUSE_TREECTRL