1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/generic/treectlg.cpp 
   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 // ----------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  29 #include "wx/treectrl.h" 
  32     #include "wx/dcclient.h" 
  34     #include "wx/settings.h" 
  35     #include "wx/listbox.h" 
  36     #include "wx/textctrl.h" 
  39 #include "wx/generic/treectlg.h" 
  40 #include "wx/imaglist.h" 
  42 #include "wx/renderer.h" 
  45     #include "wx/osx/private.h" 
  48 // ----------------------------------------------------------------------------- 
  50 // ----------------------------------------------------------------------------- 
  52 class WXDLLIMPEXP_FWD_CORE wxGenericTreeItem
; 
  54 WX_DEFINE_ARRAY_PTR(wxGenericTreeItem 
*, wxArrayGenericTreeItems
); 
  56 // ---------------------------------------------------------------------------- 
  58 // ---------------------------------------------------------------------------- 
  60 static const int NO_IMAGE 
= -1; 
  62 static const int PIXELS_PER_UNIT 
= 10; 
  64 // the margin between the item state image and the item normal image 
  65 static const int MARGIN_BETWEEN_STATE_AND_IMAGE 
= 2; 
  67 // the margin between the item image and the item text 
  68 static const int MARGIN_BETWEEN_IMAGE_AND_TEXT 
= 4; 
  70 // ----------------------------------------------------------------------------- 
  72 // ----------------------------------------------------------------------------- 
  74 // timer used for enabling in-place edit 
  75 class WXDLLEXPORT wxTreeRenameTimer
: public wxTimer
 
  78     // start editing the current item after half a second (if the mouse hasn't 
  79     // been clicked/moved) 
  82     wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
); 
  84     virtual void Notify(); 
  87     wxGenericTreeCtrl 
*m_owner
; 
  89     wxDECLARE_NO_COPY_CLASS(wxTreeRenameTimer
); 
  92 // control used for in-place edit 
  93 class WXDLLEXPORT wxTreeTextCtrl
: public wxTextCtrl
 
  96     wxTreeTextCtrl(wxGenericTreeCtrl 
*owner
, wxGenericTreeItem 
*item
); 
  98     void EndEdit( bool discardChanges 
); 
 100     const wxGenericTreeItem
* item() const { return m_itemEdited
; } 
 103     void OnChar( wxKeyEvent 
&event 
); 
 104     void OnKeyUp( wxKeyEvent 
&event 
); 
 105     void OnKillFocus( wxFocusEvent 
&event 
); 
 107     bool AcceptChanges(); 
 108     void Finish( bool setfocus 
); 
 111     wxGenericTreeCtrl  
*m_owner
; 
 112     wxGenericTreeItem  
*m_itemEdited
; 
 113     wxString            m_startValue
; 
 114     bool                m_aboutToFinish
; 
 116     DECLARE_EVENT_TABLE() 
 117     wxDECLARE_NO_COPY_CLASS(wxTreeTextCtrl
); 
 120 // timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed 
 121 // for a sufficiently long time 
 122 class WXDLLEXPORT wxTreeFindTimer 
: public wxTimer
 
 125     // reset the current prefix after half a second of inactivity 
 126     enum { DELAY 
= 500 }; 
 128     wxTreeFindTimer( wxGenericTreeCtrl 
*owner 
) { m_owner 
= owner
; } 
 130     virtual void Notify() { m_owner
->m_findPrefix
.clear(); } 
 133     wxGenericTreeCtrl 
*m_owner
; 
 135     wxDECLARE_NO_COPY_CLASS(wxTreeFindTimer
); 
 139 class WXDLLEXPORT wxGenericTreeItem
 
 150     wxGenericTreeItem( wxGenericTreeItem 
*parent
, 
 151                        const wxString
& text
, 
 154                        wxTreeItemData 
*data 
); 
 156     ~wxGenericTreeItem(); 
 159     wxArrayGenericTreeItems
& GetChildren() { return m_children
; } 
 161     const wxString
& GetText() const { return m_text
; } 
 162     int GetImage(wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) const 
 163         { return m_images
[which
]; } 
 164     wxTreeItemData 
*GetData() const { return m_data
; } 
 165     int GetState() const { return m_state
; } 
 167     // returns the current image for the item (depending on its 
 168     // selected/expanded/whatever state) 
 169     int GetCurrentImage() const; 
 171     void SetText(const wxString
& text
) 
 178     void SetImage(int image
, wxTreeItemIcon which
) 
 180         m_images
[which
] = image
; 
 184     void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
 185     void SetState(int state
) { m_state 
= state
; m_width 
= 0; } 
 187     void SetHasPlus(bool has 
= true) { m_hasPlus 
= has
; } 
 189     void SetBold(bool bold
) 
 196     int GetX() const { return m_x
; } 
 197     int GetY() const { return m_y
; } 
 199     void SetX(int x
) { m_x 
= x
; } 
 200     void SetY(int y
) { m_y 
= y
; } 
 202     int GetHeight() const { return m_height
; } 
 203     int GetWidth() const { return m_width
; } 
 205     int GetTextHeight() const 
 207         wxASSERT_MSG( m_heightText 
!= -1, "must call CalculateSize() first" ); 
 212     int GetTextWidth() const 
 214         wxASSERT_MSG( m_widthText 
!= -1, "must call CalculateSize() first" ); 
 219     wxGenericTreeItem 
*GetParent() const { return m_parent
; } 
 221     // sets the items font for the specified DC if it uses any special font or 
 222     // simply returns false otherwise 
 223     bool SetFont(wxGenericTreeCtrl 
*control
, wxDC
& dc
) const 
 227         wxTreeItemAttr 
* const attr 
= GetAttributes(); 
 228         if ( attr 
&& attr
->HasFont() ) 
 229             font 
= attr
->GetFont(); 
 231             font 
= control
->m_boldFont
; 
 241     // deletes all children notifying the treectrl about it 
 242     void DeleteChildren(wxGenericTreeCtrl 
*tree
); 
 244     // get count of all children (and grand children if 'recursively') 
 245     size_t GetChildrenCount(bool recursively 
= true) const; 
 247     void Insert(wxGenericTreeItem 
*child
, size_t index
) 
 248         { m_children
.Insert(child
, index
); } 
 250     // calculate and cache the item size using either the provided DC (which is 
 251     // supposed to have wxGenericTreeCtrl::m_normalFont selected into it!) or a 
 252     // wxClientDC on the control window 
 253     void CalculateSize(wxGenericTreeCtrl 
*control
, wxDC
& dc
) 
 254         { DoCalculateSize(control
, dc
, true /* dc uses normal font */); } 
 255     void CalculateSize(wxGenericTreeCtrl 
*control
); 
 257     void GetSize( int &x
, int &y
, const wxGenericTreeCtrl
* ); 
 259     void ResetSize() { m_width 
= 0; } 
 260     void ResetTextSize() { m_width 
= 0; m_widthText 
= -1; } 
 261     void RecursiveResetSize(); 
 262     void RecursiveResetTextSize(); 
 264         // return the item at given position (or NULL if no item), onButton is 
 265         // true if the point belongs to the item's button, otherwise it lies 
 266         // on the item's label 
 267     wxGenericTreeItem 
*HitTest( const wxPoint
& point
, 
 268                                 const wxGenericTreeCtrl 
*, 
 272     void Expand() { m_isCollapsed 
= false; } 
 273     void Collapse() { m_isCollapsed 
= true; } 
 275     void SetHilight( bool set 
= true ) { m_hasHilight 
= set
; } 
 278     bool HasChildren() const { return !m_children
.IsEmpty(); } 
 279     bool IsSelected()  const { return m_hasHilight 
!= 0; } 
 280     bool IsExpanded()  const { return !m_isCollapsed
; } 
 281     bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 282     bool IsBold()      const { return m_isBold 
!= 0; } 
 285         // get them - may be NULL 
 286     wxTreeItemAttr 
*GetAttributes() const { return m_attr
; } 
 287         // get them ensuring that the pointer is not NULL 
 288     wxTreeItemAttr
& Attr() 
 292             m_attr 
= new wxTreeItemAttr
; 
 298     void SetAttributes(wxTreeItemAttr 
*attr
) 
 300         if ( m_ownsAttr 
) delete m_attr
; 
 306         // set them and delete when done 
 307     void AssignAttributes(wxTreeItemAttr 
*attr
) 
 316     // calculate the size of this item, i.e. set m_width, m_height and 
 317     // m_widthText and m_heightText properly 
 319     // if dcUsesNormalFont is true, the current dc font must be the normal tree 
 321     void DoCalculateSize(wxGenericTreeCtrl 
*control
, 
 323                          bool dcUsesNormalFont
); 
 325     // since there can be very many of these, we save size by chosing 
 326     // the smallest representation for the elements and by ordering 
 327     // the members to avoid padding. 
 328     wxString            m_text
;         // label to be rendered for item 
 332     wxTreeItemData     
*m_data
;         // user-provided data 
 334     int                 m_state
;        // item state 
 336     wxArrayGenericTreeItems m_children
; // list of children 
 337     wxGenericTreeItem  
*m_parent
;       // parent of this item 
 339     wxTreeItemAttr     
*m_attr
;         // attributes??? 
 341     // tree ctrl images for the normal, selected, expanded and 
 342     // expanded+selected states 
 343     int                 m_images
[wxTreeItemIcon_Max
]; 
 345     wxCoord             m_x
;            // (virtual) offset from top 
 346     wxCoord             m_y
;            // (virtual) offset from left 
 347     int                 m_width
;        // width of this item 
 348     int                 m_height
;       // height of this item 
 350     // use bitfields to save size 
 351     unsigned int        m_isCollapsed 
:1; 
 352     unsigned int        m_hasHilight  
:1; // same as focused 
 353     unsigned int        m_hasPlus     
:1; // used for item which doesn't have 
 354                                           // children but has a [+] button 
 355     unsigned int        m_isBold      
:1; // render the label in bold font 
 356     unsigned int        m_ownsAttr    
:1; // delete attribute when done 
 358     wxDECLARE_NO_COPY_CLASS(wxGenericTreeItem
); 
 361 // ============================================================================= 
 363 // ============================================================================= 
 365 // ---------------------------------------------------------------------------- 
 367 // ---------------------------------------------------------------------------- 
 369 // translate the key or mouse event flags to the type of selection we're 
 371 static void EventFlagsToSelType(long style
, 
 375                                 bool &extended_select
, 
 376                                 bool &unselect_others
) 
 378     is_multiple 
= (style 
& wxTR_MULTIPLE
) != 0; 
 379     extended_select 
= shiftDown 
&& is_multiple
; 
 380     unselect_others 
= !(extended_select 
|| (ctrlDown 
&& is_multiple
)); 
 383 // check if the given item is under another one 
 385 IsDescendantOf(const wxGenericTreeItem 
*parent
, const wxGenericTreeItem 
*item
) 
 389         if ( item 
== parent 
) 
 391             // item is a descendant of parent 
 395         item 
= item
->GetParent(); 
 401 // ----------------------------------------------------------------------------- 
 402 // wxTreeRenameTimer (internal) 
 403 // ----------------------------------------------------------------------------- 
 405 wxTreeRenameTimer::wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
) 
 410 void wxTreeRenameTimer::Notify() 
 412     m_owner
->OnRenameTimer(); 
 415 //----------------------------------------------------------------------------- 
 416 // wxTreeTextCtrl (internal) 
 417 //----------------------------------------------------------------------------- 
 419 BEGIN_EVENT_TABLE(wxTreeTextCtrl
,wxTextCtrl
) 
 420     EVT_CHAR           (wxTreeTextCtrl::OnChar
) 
 421     EVT_KEY_UP         (wxTreeTextCtrl::OnKeyUp
) 
 422     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus
) 
 425 wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl 
*owner
, 
 426                                wxGenericTreeItem 
*itm
) 
 427               : m_itemEdited(itm
), m_startValue(itm
->GetText()) 
 430     m_aboutToFinish 
= false; 
 433     m_owner
->GetBoundingRect(m_itemEdited
, rect
, true); 
 435     // corrects position and size for better appearance 
 439 #elif defined(__WXGTK__) 
 444 #elif defined(wxOSX_USE_CARBON) && wxOSX_USE_CARBON 
 445     int bestHeight 
= GetBestSize().y 
- 8; 
 446     if ( rect
.height 
> bestHeight 
) 
 448         int diff 
= rect
.height 
- bestHeight
; 
 454     (void)Create(m_owner
, wxID_ANY
, m_startValue
, 
 455                  rect
.GetPosition(), rect
.GetSize()); 
 460 void wxTreeTextCtrl::EndEdit(bool discardChanges
) 
 462     m_aboutToFinish 
= true; 
 464     if ( discardChanges 
) 
 466         m_owner
->OnRenameCancelled(m_itemEdited
); 
 472         // Notify the owner about the changes 
 475         // Even if vetoed, close the control (consistent with MSW) 
 480 bool wxTreeTextCtrl::AcceptChanges() 
 482     const wxString value 
= GetValue(); 
 484     if ( value 
== m_startValue 
) 
 486         // nothing changed, always accept 
 487         // when an item remains unchanged, the owner 
 488         // needs to be notified that the user decided 
 489         // not to change the tree item label, and that 
 490         // the edit has been cancelled 
 492         m_owner
->OnRenameCancelled(m_itemEdited
); 
 496     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
 498         // vetoed by the user 
 502     // accepted, do rename the item 
 503     m_owner
->SetItemText(m_itemEdited
, value
); 
 508 void wxTreeTextCtrl::Finish( bool setfocus 
) 
 510     m_owner
->ResetTextControl(); 
 512     wxPendingDelete
.Append(this); 
 518 void wxTreeTextCtrl::OnChar( wxKeyEvent 
&event 
) 
 520     switch ( event
.m_keyCode 
) 
 535 void wxTreeTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
 537     if ( !m_aboutToFinish 
) 
 539         // auto-grow the textctrl: 
 540         wxSize parentSize 
= m_owner
->GetSize(); 
 541         wxPoint myPos 
= GetPosition(); 
 542         wxSize mySize 
= GetSize(); 
 544         GetTextExtent(GetValue() + wxT("M"), &sx
, &sy
); 
 545         if (myPos
.x 
+ sx 
> parentSize
.x
) 
 546             sx 
= parentSize
.x 
- myPos
.x
; 
 549         SetSize(sx
, wxDefaultCoord
); 
 555 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
 557     if ( !m_aboutToFinish 
) 
 559         if ( !AcceptChanges() ) 
 560             m_owner
->OnRenameCancelled( m_itemEdited 
); 
 565     // We should let the native text control handle focus, too. 
 569 // ----------------------------------------------------------------------------- 
 571 // ----------------------------------------------------------------------------- 
 573 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 574                                      const wxString
& text
, 
 575                                      int image
, int selImage
, 
 576                                      wxTreeItemData 
*data
) 
 579     m_images
[wxTreeItemIcon_Normal
] = image
; 
 580     m_images
[wxTreeItemIcon_Selected
] = selImage
; 
 581     m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
; 
 582     m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
; 
 585     m_state 
= wxTREE_ITEMSTATE_NONE
; 
 588     m_isCollapsed 
= true; 
 589     m_hasHilight 
= false; 
 598     // We don't know the height here yet. 
 606 wxGenericTreeItem::~wxGenericTreeItem() 
 610     if (m_ownsAttr
) delete m_attr
; 
 612     wxASSERT_MSG( m_children
.IsEmpty(), 
 613                   "must call DeleteChildren() before deleting the item" ); 
 616 void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl 
*tree
) 
 618     size_t count 
= m_children
.GetCount(); 
 619     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 621         wxGenericTreeItem 
*child 
= m_children
[n
]; 
 622         tree
->SendDeleteEvent(child
); 
 624         child
->DeleteChildren(tree
); 
 625         if ( child 
== tree
->m_select_me 
) 
 626             tree
->m_select_me 
= NULL
; 
 633 size_t wxGenericTreeItem::GetChildrenCount(bool recursively
) const 
 635     size_t count 
= m_children
.GetCount(); 
 639     size_t total 
= count
; 
 640     for (size_t n 
= 0; n 
< count
; ++n
) 
 642         total 
+= m_children
[n
]->GetChildrenCount(); 
 648 void wxGenericTreeItem::GetSize( int &x
, int &y
, 
 649                                  const wxGenericTreeCtrl 
*theButton 
) 
 651     int bottomY
=m_y
+theButton
->GetLineHeight(this); 
 652     if ( y 
< bottomY 
) y 
= bottomY
; 
 653     int width 
= m_x 
+  m_width
; 
 654     if ( x 
< width 
) x 
= width
; 
 658         size_t count 
= m_children
.GetCount(); 
 659         for ( size_t n 
= 0; n 
< count
; ++n 
) 
 661             m_children
[n
]->GetSize( x
, y
, theButton 
); 
 666 wxGenericTreeItem 
*wxGenericTreeItem::HitTest(const wxPoint
& point
, 
 667                                               const wxGenericTreeCtrl 
*theCtrl
, 
 671     // for a hidden root node, don't evaluate it, but do evaluate children 
 672     if ( !(level 
== 0 && theCtrl
->HasFlag(wxTR_HIDE_ROOT
)) ) 
 675         int h 
= theCtrl
->GetLineHeight(this); 
 676         if ((point
.y 
> m_y
) && (point
.y 
< m_y 
+ h
)) 
 678             int y_mid 
= m_y 
+ h
/2; 
 679             if (point
.y 
< y_mid 
) 
 680                 flags 
|= wxTREE_HITTEST_ONITEMUPPERPART
; 
 682                 flags 
|= wxTREE_HITTEST_ONITEMLOWERPART
; 
 684             int xCross 
= m_x 
- theCtrl
->GetSpacing(); 
 686             // according to the drawing code the triangels are drawn 
 687             // at -4 , -4  from the position up to +10/+10 max 
 688             if ((point
.x 
> xCross
-4) && (point
.x 
< xCross
+10) && 
 689                 (point
.y 
> y_mid
-4) && (point
.y 
< y_mid
+10) && 
 690                 HasPlus() && theCtrl
->HasButtons() ) 
 692             // 5 is the size of the plus sign 
 693             if ((point
.x 
> xCross
-6) && (point
.x 
< xCross
+6) && 
 694                 (point
.y 
> y_mid
-6) && (point
.y 
< y_mid
+6) && 
 695                 HasPlus() && theCtrl
->HasButtons() ) 
 698                 flags 
|= wxTREE_HITTEST_ONITEMBUTTON
; 
 702             if ((point
.x 
>= m_x
) && (point
.x 
<= m_x
+m_width
)) 
 707                 // assuming every image (normal and selected) has the same size! 
 708                 if ( (GetImage() != NO_IMAGE
) && theCtrl
->m_imageListNormal 
) 
 710                     theCtrl
->m_imageListNormal
->GetSize(GetImage(), 
 717                 if ( (GetState() != wxTREE_ITEMSTATE_NONE
) && 
 718                         theCtrl
->m_imageListState 
) 
 720                     theCtrl
->m_imageListState
->GetSize(GetState(), 
 724                 if ((state_w 
!= -1) && (point
.x 
<= m_x 
+ state_w 
+ 1)) 
 725                     flags 
|= wxTREE_HITTEST_ONITEMSTATEICON
; 
 726                 else if ((image_w 
!= -1) && 
 728                             (state_w 
!= -1 ? state_w 
+ 
 729                                                 MARGIN_BETWEEN_STATE_AND_IMAGE
 
 732                     flags 
|= wxTREE_HITTEST_ONITEMICON
; 
 734                     flags 
|= wxTREE_HITTEST_ONITEMLABEL
; 
 740                 flags 
|= wxTREE_HITTEST_ONITEMINDENT
; 
 741             if (point
.x 
> m_x
+m_width
) 
 742                 flags 
|= wxTREE_HITTEST_ONITEMRIGHT
; 
 747         // if children are expanded, fall through to evaluate them 
 748         if (m_isCollapsed
) return NULL
; 
 752     size_t count 
= m_children
.GetCount(); 
 753     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 755         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, 
 766 int wxGenericTreeItem::GetCurrentImage() const 
 768     int image 
= NO_IMAGE
; 
 773             image 
= GetImage(wxTreeItemIcon_SelectedExpanded
); 
 776         if ( image 
== NO_IMAGE 
) 
 778             // we usually fall back to the normal item, but try just the 
 779             // expanded one (and not selected) first in this case 
 780             image 
= GetImage(wxTreeItemIcon_Expanded
); 
 786             image 
= GetImage(wxTreeItemIcon_Selected
); 
 789     // maybe it doesn't have the specific image we want, 
 790     // try the default one instead 
 791     if ( image 
== NO_IMAGE 
) image 
= GetImage(); 
 796 void wxGenericTreeItem::CalculateSize(wxGenericTreeCtrl
* control
) 
 798     // check if we need to do anything before creating the DC 
 802     wxClientDC 
dc(control
); 
 803     DoCalculateSize(control
, dc
, false /* normal font not used */); 
 807 wxGenericTreeItem::DoCalculateSize(wxGenericTreeCtrl
* control
, 
 809                                    bool dcUsesNormalFont
) 
 811     if ( m_width 
!= 0 ) // Size known, nothing to do 
 814     if ( m_widthText 
== -1 ) 
 817         if ( SetFont(control
, dc
) ) 
 821         else // we have no special font 
 823            if ( !dcUsesNormalFont 
) 
 825                // but we do need to ensure that the normal font is used: notice 
 826                // that this doesn't count as changing the font as we don't need 
 828                dc
.SetFont(control
->m_normalFont
); 
 834         dc
.GetTextExtent( GetText(), &m_widthText
, &m_heightText 
); 
 836         // restore normal font if the DC used it previously and we changed it 
 838              dc
.SetFont(control
->m_normalFont
); 
 841     int text_h 
= m_heightText 
+ 2; 
 843     int image_h 
= 0, image_w 
= 0; 
 844     int image 
= GetCurrentImage(); 
 845     if ( image 
!= NO_IMAGE 
&& control
->m_imageListNormal 
) 
 847         control
->m_imageListNormal
->GetSize(image
, image_w
, image_h
); 
 848         image_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
 851     int state_h 
= 0, state_w 
= 0; 
 852     int state 
= GetState(); 
 853     if ( state 
!= wxTREE_ITEMSTATE_NONE 
&& control
->m_imageListState 
) 
 855         control
->m_imageListState
->GetSize(state
, state_w
, state_h
); 
 857             state_w 
+= MARGIN_BETWEEN_STATE_AND_IMAGE
; 
 859             state_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
 862     int img_h 
= wxMax(state_h
, image_h
); 
 863     m_height 
= wxMax(img_h
, text_h
); 
 866         m_height 
+= 2;            // at least 2 pixels 
 868         m_height 
+= m_height 
/ 10;   // otherwise 10% extra spacing 
 870     if (m_height 
> control
->m_lineHeight
) 
 871         control
->m_lineHeight 
= m_height
; 
 873     m_width 
= state_w 
+ image_w 
+ m_widthText 
+ 2; 
 876 void wxGenericTreeItem::RecursiveResetSize() 
 880     const size_t count 
= m_children
.Count(); 
 881     for (size_t i 
= 0; i 
< count
; i
++ ) 
 882         m_children
[i
]->RecursiveResetSize(); 
 885 void wxGenericTreeItem::RecursiveResetTextSize() 
 890     const size_t count 
= m_children
.Count(); 
 891     for (size_t i 
= 0; i 
< count
; i
++ ) 
 892         m_children
[i
]->RecursiveResetTextSize(); 
 895 // ----------------------------------------------------------------------------- 
 896 // wxGenericTreeCtrl implementation 
 897 // ----------------------------------------------------------------------------- 
 899 IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl
, wxControl
) 
 901 BEGIN_EVENT_TABLE(wxGenericTreeCtrl
, wxTreeCtrlBase
) 
 902     EVT_PAINT          (wxGenericTreeCtrl::OnPaint
) 
 903     EVT_SIZE           (wxGenericTreeCtrl::OnSize
) 
 904     EVT_MOUSE_EVENTS   (wxGenericTreeCtrl::OnMouse
) 
 905     EVT_KEY_DOWN       (wxGenericTreeCtrl::OnKeyDown
) 
 906     EVT_CHAR           (wxGenericTreeCtrl::OnChar
) 
 907     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus
) 
 908     EVT_KILL_FOCUS     (wxGenericTreeCtrl::OnKillFocus
) 
 909     EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY
, wxGenericTreeCtrl::OnGetToolTip
) 
 912 // ----------------------------------------------------------------------------- 
 913 // construction/destruction 
 914 // ----------------------------------------------------------------------------- 
 916 void wxGenericTreeCtrl::Init() 
 929     m_hilightBrush 
= new wxBrush
 
 931                             wxSystemSettings::GetColour
 
 933                                 wxSYS_COLOUR_HIGHLIGHT
 
 938     m_hilightUnfocusedBrush 
= new wxBrush
 
 940                                  wxSystemSettings::GetColour
 
 942                                      wxSYS_COLOUR_BTNSHADOW
 
 947     m_imageListButtons 
= NULL
; 
 948     m_ownsImageListButtons 
= false; 
 951     m_isDragging 
= false; 
 952     m_dropTarget 
= m_oldSelection 
= NULL
; 
 956     m_renameTimer 
= NULL
; 
 960     m_dropEffectAboveItem 
= false; 
 962     m_dndEffect 
= NoEffect
; 
 963     m_dndEffectItem 
= NULL
; 
 965     m_lastOnSame 
= false; 
 967 #if defined( __WXMAC__ ) 
 968     m_normalFont 
= wxFont(wxOSX_SYSTEM_FONT_VIEWS
); 
 970     m_normalFont 
= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT 
); 
 972     m_boldFont 
= m_normalFont
.Bold(); 
 975 bool wxGenericTreeCtrl::Create(wxWindow 
*parent
, 
 980                                const wxValidator
& validator
, 
 981                                const wxString
& name 
) 
 985     wxGetOsVersion(&major
, &minor
); 
 988         style 
|= wxTR_ROW_LINES
; 
 990     if (style 
& wxTR_HAS_BUTTONS
) 
 991         style 
|= wxTR_NO_LINES
; 
 995     if (style 
& wxTR_HAS_BUTTONS
) 
 996         style 
|= wxTR_NO_LINES
; 
 999     if ( !wxControl::Create( parent
, id
, pos
, size
, 
1000                              style
|wxHSCROLL
|wxVSCROLL
|wxWANTS_CHARS
, 
1005     // If the tree display has no buttons, but does have 
1006     // connecting lines, we can use a narrower layout. 
1007     // It may not be a good idea to force this... 
1008     if (!HasButtons() && !HasFlag(wxTR_NO_LINES
)) 
1014     wxVisualAttributes attr 
= GetDefaultAttributes(); 
1015     SetOwnForegroundColour( attr
.colFg 
); 
1016     SetOwnBackgroundColour( attr
.colBg 
); 
1018         SetOwnFont(attr
.font
); 
1020     // this is a misnomer: it's called "dotted pen" but uses (default) wxSOLID 
1021     // style because we apparently get performance problems when using dotted 
1022     // pen for drawing in some ports -- but under MSW it seems to work fine 
1024     m_dottedPen 
= wxPen(*wxLIGHT_GREY
, 0, wxPENSTYLE_DOT
); 
1026     m_dottedPen 
= *wxGREY_PEN
; 
1029     SetInitialSize(size
); 
1034 wxGenericTreeCtrl::~wxGenericTreeCtrl() 
1036     delete m_hilightBrush
; 
1037     delete m_hilightUnfocusedBrush
; 
1041     delete m_renameTimer
; 
1044     if (m_ownsImageListButtons
) 
1045         delete m_imageListButtons
; 
1048 // ----------------------------------------------------------------------------- 
1050 // ----------------------------------------------------------------------------- 
1052 unsigned int wxGenericTreeCtrl::GetCount() const 
1056         // the tree is empty 
1060     unsigned int count 
= m_anchor
->GetChildrenCount(); 
1061     if ( !HasFlag(wxTR_HIDE_ROOT
) ) 
1063         // take the root itself into account 
1070 void wxGenericTreeCtrl::SetIndent(unsigned int indent
) 
1072     m_indent 
= (unsigned short) indent
; 
1077 wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, 
1078                                     bool recursively
) const 
1080     wxCHECK_MSG( item
.IsOk(), 0u, wxT("invalid tree item") ); 
1082     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildrenCount(recursively
); 
1085 void wxGenericTreeCtrl::SetWindowStyle(const long styles
) 
1087     // Do not try to expand the root node if it hasn't been created yet 
1088     if (m_anchor 
&& !HasFlag(wxTR_HIDE_ROOT
) && (styles 
& wxTR_HIDE_ROOT
)) 
1090         // if we will hide the root, make sure children are visible 
1091         m_anchor
->SetHasPlus(); 
1093         CalculatePositions(); 
1096     // right now, just sets the styles.  Eventually, we may 
1097     // want to update the inherited styles, but right now 
1098     // none of the parents has updatable styles 
1099     m_windowStyle 
= styles
; 
1103 // ----------------------------------------------------------------------------- 
1104 // functions to work with tree items 
1105 // ----------------------------------------------------------------------------- 
1107 wxString 
wxGenericTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
1109     wxCHECK_MSG( item
.IsOk(), wxEmptyString
, wxT("invalid tree item") ); 
1111     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetText(); 
1114 int wxGenericTreeCtrl::GetItemImage(const wxTreeItemId
& item
, 
1115                              wxTreeItemIcon which
) const 
1117     wxCHECK_MSG( item
.IsOk(), -1, wxT("invalid tree item") ); 
1119     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetImage(which
); 
1122 wxTreeItemData 
*wxGenericTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
1124     wxCHECK_MSG( item
.IsOk(), NULL
, wxT("invalid tree item") ); 
1126     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetData(); 
1129 int wxGenericTreeCtrl::DoGetItemState(const wxTreeItemId
& item
) const 
1131     wxCHECK_MSG( item
.IsOk(), wxTREE_ITEMSTATE_NONE
, wxT("invalid tree item") ); 
1133     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1134     return pItem
->GetState(); 
1137 wxColour 
wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId
& item
) const 
1139     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
1141     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1142     return pItem
->Attr().GetTextColour(); 
1146 wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId
& item
) const 
1148     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
1150     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1151     return pItem
->Attr().GetBackgroundColour(); 
1154 wxFont 
wxGenericTreeCtrl::GetItemFont(const wxTreeItemId
& item
) const 
1156     wxCHECK_MSG( item
.IsOk(), wxNullFont
, wxT("invalid tree item") ); 
1158     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1159     return pItem
->Attr().GetFont(); 
1163 wxGenericTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
1165     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1167     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1168     pItem
->SetText(text
); 
1169     pItem
->CalculateSize(this); 
1173 void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId
& item
, 
1175                               wxTreeItemIcon which
) 
1177     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1179     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1180     pItem
->SetImage(image
, which
); 
1181     pItem
->CalculateSize(this); 
1186 wxGenericTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
1188     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1191         data
->SetId( item 
); 
1193     ((wxGenericTreeItem
*) item
.m_pItem
)->SetData(data
); 
1196 void wxGenericTreeCtrl::DoSetItemState(const wxTreeItemId
& item
, int state
) 
1198     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1200     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1201     pItem
->SetState(state
); 
1202     pItem
->CalculateSize(this); 
1206 void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
1208     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1210     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1211     pItem
->SetHasPlus(has
); 
1215 void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
1217     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1219     // avoid redrawing the tree if no real change 
1220     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1221     if ( pItem
->IsBold() != bold 
) 
1223         pItem
->SetBold(bold
); 
1225         // recalculate the item size as bold and non bold fonts have different 
1227         pItem
->CalculateSize(this); 
1232 void wxGenericTreeCtrl::SetItemDropHighlight(const wxTreeItemId
& item
, 
1235     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1241         bg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
); 
1242         fg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1245     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1246     pItem
->Attr().SetTextColour(fg
); 
1247     pItem
->Attr().SetBackgroundColour(bg
); 
1251 void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId
& item
, 
1252                                    const wxColour
& col
) 
1254     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1256     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1257     pItem
->Attr().SetTextColour(col
); 
1261 void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
, 
1262                                          const wxColour
& col
) 
1264     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1266     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1267     pItem
->Attr().SetBackgroundColour(col
); 
1272 wxGenericTreeCtrl::SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
) 
1274     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1276     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1277     pItem
->Attr().SetFont(font
); 
1278     pItem
->ResetTextSize(); 
1279     pItem
->CalculateSize(this); 
1283 bool wxGenericTreeCtrl::SetFont( const wxFont 
&font 
) 
1285     wxTreeCtrlBase::SetFont(font
); 
1287     m_normalFont 
= font
; 
1288     m_boldFont 
= m_normalFont
.Bold(); 
1291         m_anchor
->RecursiveResetTextSize(); 
1297 // ----------------------------------------------------------------------------- 
1298 // item status inquiries 
1299 // ----------------------------------------------------------------------------- 
1301 bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId
& item
) const 
1303     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1305     // An item is only visible if it's not a descendant of a collapsed item 
1306     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1307     wxGenericTreeItem
* parent 
= pItem
->GetParent(); 
1310         if (!parent
->IsExpanded()) 
1312         parent 
= parent
->GetParent(); 
1316     GetViewStart(& startX
, & startY
); 
1318     wxSize clientSize 
= GetClientSize(); 
1321     if (!GetBoundingRect(item
, rect
)) 
1323     if (rect
.GetWidth() == 0 || rect
.GetHeight() == 0) 
1325     if (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) 
1327     if (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
) 
1333 bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
1335     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1337     // consider that the item does have children if it has the "+" button: it 
1338     // might not have them (if it had never been expanded yet) but then it 
1339     // could have them as well and it's better to err on this side rather than 
1340     // disabling some operations which are restricted to the items with 
1341     // children for an item which does have them 
1342     return ((wxGenericTreeItem
*) item
.m_pItem
)->HasPlus(); 
1345 bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
1347     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1349     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsExpanded(); 
1352 bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
1354     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1356     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsSelected(); 
1359 bool wxGenericTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
1361     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1363     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsBold(); 
1366 // ----------------------------------------------------------------------------- 
1368 // ----------------------------------------------------------------------------- 
1370 wxTreeItemId 
wxGenericTreeCtrl::GetItemParent(const wxTreeItemId
& item
) const 
1372     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1374     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetParent(); 
1377 wxTreeItemId 
wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, 
1378                                               wxTreeItemIdValue
& cookie
) const 
1380     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1383     return GetNextChild(item
, cookie
); 
1386 wxTreeItemId 
wxGenericTreeCtrl::GetNextChild(const wxTreeItemId
& item
, 
1387                                              wxTreeItemIdValue
& cookie
) const 
1389     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1391     wxArrayGenericTreeItems
& 
1392         children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1394     // it's ok to cast cookie to size_t, we never have indices big enough to 
1395     // overflow "void *" 
1396     size_t *pIndex 
= (size_t *)&cookie
; 
1397     if ( *pIndex 
< children
.GetCount() ) 
1399         return children
.Item((*pIndex
)++); 
1403         // there are no more of them 
1404         return wxTreeItemId(); 
1408 wxTreeItemId 
wxGenericTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
1410     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1412     wxArrayGenericTreeItems
& 
1413         children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1414     return children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last()); 
1417 wxTreeItemId 
wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
1419     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1421     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1422     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1423     if ( parent 
== NULL 
) 
1425         // root item doesn't have any siblings 
1426         return wxTreeItemId(); 
1429     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1430     int index 
= siblings
.Index(i
); 
1431     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1433     size_t n 
= (size_t)(index 
+ 1); 
1434     return n 
== siblings
.GetCount() ? wxTreeItemId() 
1435                                     : wxTreeItemId(siblings
[n
]); 
1438 wxTreeItemId 
wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
1440     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1442     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1443     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1444     if ( parent 
== NULL 
) 
1446         // root item doesn't have any siblings 
1447         return wxTreeItemId(); 
1450     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1451     int index 
= siblings
.Index(i
); 
1452     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1454     return index 
== 0 ? wxTreeItemId() 
1455                       : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
1458 // Only for internal use right now, but should probably be public 
1459 wxTreeItemId 
wxGenericTreeCtrl::GetNext(const wxTreeItemId
& item
) const 
1461     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1463     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1465     // First see if there are any children. 
1466     wxArrayGenericTreeItems
& children 
= i
->GetChildren(); 
1467     if (children
.GetCount() > 0) 
1469          return children
.Item(0); 
1473          // Try a sibling of this or ancestor instead 
1474          wxTreeItemId p 
= item
; 
1475          wxTreeItemId toFind
; 
1478               toFind 
= GetNextSibling(p
); 
1479               p 
= GetItemParent(p
); 
1480          } while (p
.IsOk() && !toFind
.IsOk()); 
1485 wxTreeItemId 
wxGenericTreeCtrl::GetFirstVisibleItem() const 
1487     wxTreeItemId itemid 
= GetRootItem(); 
1493         if (IsVisible(itemid
)) 
1495         itemid 
= GetNext(itemid
); 
1496     } while (itemid
.IsOk()); 
1498     return wxTreeItemId(); 
1501 wxTreeItemId 
wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
1503     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1504     wxASSERT_MSG( IsVisible(item
), wxT("this item itself should be visible") ); 
1506     wxTreeItemId id 
= item
; 
1509         while (id 
= GetNext(id
), id
.IsOk()) 
1515     return wxTreeItemId(); 
1518 wxTreeItemId 
wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
1520     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1521     wxASSERT_MSG( IsVisible(item
), wxT("this item itself should be visible") ); 
1523     // find out the starting point 
1524     wxTreeItemId prevItem 
= GetPrevSibling(item
); 
1525     if ( !prevItem
.IsOk() ) 
1527         prevItem 
= GetItemParent(item
); 
1530     // find the first visible item after it 
1531     while ( prevItem
.IsOk() && !IsVisible(prevItem
) ) 
1533         prevItem 
= GetNext(prevItem
); 
1534         if ( !prevItem
.IsOk() || prevItem 
== item 
) 
1536             // there are no visible items before item 
1537             return wxTreeItemId(); 
1541     // from there we must be able to navigate until this item 
1542     while ( prevItem
.IsOk() ) 
1544         const wxTreeItemId nextItem 
= GetNextVisible(prevItem
); 
1545         if ( !nextItem
.IsOk() || nextItem 
== item 
) 
1548         prevItem 
= nextItem
; 
1554 // called by wxTextTreeCtrl when it marks itself for deletion 
1555 void wxGenericTreeCtrl::ResetTextControl() 
1560 // find the first item starting with the given prefix after the given item 
1561 wxTreeItemId 
wxGenericTreeCtrl::FindItem(const wxTreeItemId
& idParent
, 
1562                                          const wxString
& prefixOrig
) const 
1564     // match is case insensitive as this is more convenient to the user: having 
1565     // to press Shift-letter to go to the item starting with a capital letter 
1566     // would be too bothersome 
1567     wxString prefix 
= prefixOrig
.Lower(); 
1569     // determine the starting point: we shouldn't take the current item (this 
1570     // allows to switch between two items starting with the same letter just by 
1571     // pressing it) but we shouldn't jump to the next one if the user is 
1572     // continuing to type as otherwise he might easily skip the item he wanted 
1573     wxTreeItemId itemid 
= idParent
; 
1574     if ( prefix
.length() == 1 ) 
1576         itemid 
= GetNext(itemid
); 
1579     // look for the item starting with the given prefix after it 
1580     while ( itemid
.IsOk() && !GetItemText(itemid
).Lower().StartsWith(prefix
) ) 
1582         itemid 
= GetNext(itemid
); 
1585     // if we haven't found anything... 
1586     if ( !itemid
.IsOk() ) 
1588         // ... wrap to the beginning 
1589         itemid 
= GetRootItem(); 
1590         if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1592             // can't select virtual root 
1593             itemid 
= GetNext(itemid
); 
1596         // and try all the items (stop when we get to the one we started from) 
1597         while ( itemid
.IsOk() && itemid 
!= idParent 
&& 
1598                     !GetItemText(itemid
).Lower().StartsWith(prefix
) ) 
1600             itemid 
= GetNext(itemid
); 
1602         // If we haven't found the item, id.IsOk() will be false, as per 
1609 // ----------------------------------------------------------------------------- 
1611 // ----------------------------------------------------------------------------- 
1613 wxTreeItemId 
wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
1615                                              const wxString
& text
, 
1618                                              wxTreeItemData 
*data
) 
1620     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1623         // should we give a warning here? 
1624         return AddRoot(text
, image
, selImage
, data
); 
1627     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1629     wxGenericTreeItem 
*item 
= 
1630         new wxGenericTreeItem( parent
, text
, image
, selImage
, data 
); 
1634         data
->m_pItem 
= item
; 
1637     parent
->Insert( item
, previous 
== (size_t)-1 ? parent
->GetChildren().size() 
1640     InvalidateBestSize(); 
1644 wxTreeItemId 
wxGenericTreeCtrl::AddRoot(const wxString
& text
, 
1647                                         wxTreeItemData 
*data
) 
1649     wxCHECK_MSG( !m_anchor
, wxTreeItemId(), "tree can have only one root" ); 
1651     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1653     m_anchor 
= new wxGenericTreeItem(NULL
, text
, 
1654                                    image
, selImage
, data
); 
1657         data
->m_pItem 
= m_anchor
; 
1660     if (HasFlag(wxTR_HIDE_ROOT
)) 
1662         // if root is hidden, make sure we can navigate 
1664         m_anchor
->SetHasPlus(); 
1666         CalculatePositions(); 
1669     if (!HasFlag(wxTR_MULTIPLE
)) 
1671         m_current 
= m_key_current 
= m_anchor
; 
1672         m_current
->SetHilight( true ); 
1675     InvalidateBestSize(); 
1679 wxTreeItemId 
wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId
& parentId
, 
1680                                               const wxTreeItemId
& idPrevious
, 
1681                                               const wxString
& text
, 
1682                                               int image
, int selImage
, 
1683                                               wxTreeItemData 
*data
) 
1685     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1688         // should we give a warning here? 
1689         return AddRoot(text
, image
, selImage
, data
); 
1693     if (idPrevious
.IsOk()) 
1695         index 
= parent
->GetChildren().Index( 
1696                     (wxGenericTreeItem
*) idPrevious
.m_pItem
); 
1697         wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
1698                       "previous item in wxGenericTreeCtrl::InsertItem() " 
1699                       "is not a sibling" ); 
1702     return DoInsertItem(parentId
, (size_t)++index
, text
, image
, selImage
, data
); 
1706 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
1708     wxTreeEvent 
event(wxEVT_COMMAND_TREE_DELETE_ITEM
, this, item
); 
1709     GetEventHandler()->ProcessEvent( event 
); 
1712 // Don't leave edit or selection on a child which is about to disappear 
1713 void wxGenericTreeCtrl::ChildrenClosing(wxGenericTreeItem
* item
) 
1715     if ( m_textCtrl 
&& item 
!= m_textCtrl
->item() && 
1716             IsDescendantOf(item
, m_textCtrl
->item()) ) 
1718         m_textCtrl
->EndEdit( true ); 
1721     if ( item 
!= m_key_current 
&& IsDescendantOf(item
, m_key_current
) ) 
1723         m_key_current 
= NULL
; 
1726     if ( IsDescendantOf(item
, m_select_me
) ) 
1731     if ( item 
!= m_current 
&& IsDescendantOf(item
, m_current
) ) 
1733         m_current
->SetHilight( false ); 
1739 void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
1741     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1743     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1744     ChildrenClosing(item
); 
1745     item
->DeleteChildren(this); 
1746     InvalidateBestSize(); 
1749 void wxGenericTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
1751     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1753     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1755     if (m_textCtrl 
!= NULL 
&& IsDescendantOf(item
, m_textCtrl
->item())) 
1757         // can't delete the item being edited, cancel editing it first 
1758         m_textCtrl
->EndEdit( true ); 
1761     wxGenericTreeItem 
*parent 
= item
->GetParent(); 
1763     // if the selected item will be deleted, select the parent ... 
1764     wxGenericTreeItem 
*to_be_selected 
= parent
; 
1767         // .. unless there is a next sibling like wxMSW does it 
1768         int pos 
= parent
->GetChildren().Index( item 
); 
1769         if ((int)(parent
->GetChildren().GetCount()) > pos
+1) 
1770             to_be_selected 
= parent
->GetChildren().Item( pos
+1 ); 
1773     // don't keep stale pointers around! 
1774     if ( IsDescendantOf(item
, m_key_current
) ) 
1776         // Don't silently change the selection: 
1777         // do it properly in idle time, so event 
1778         // handlers get called. 
1780         // m_key_current = parent; 
1781         m_key_current 
= NULL
; 
1784     // m_select_me records whether we need to select 
1785     // a different item, in idle time. 
1786     if ( m_select_me 
&& IsDescendantOf(item
, m_select_me
) ) 
1788         m_select_me 
= to_be_selected
; 
1791     if ( IsDescendantOf(item
, m_current
) ) 
1793         // Don't silently change the selection: 
1794         // do it properly in idle time, so event 
1795         // handlers get called. 
1797         // m_current = parent; 
1799         m_select_me 
= to_be_selected
; 
1802     // remove the item from the tree 
1805         parent
->GetChildren().Remove( item 
);  // remove by value 
1807     else // deleting the root 
1809         // nothing will be left in the tree 
1813     // and delete all of its children and the item itself now 
1814     item
->DeleteChildren(this); 
1815     SendDeleteEvent(item
); 
1817     if (item 
== m_select_me
) 
1822     InvalidateBestSize(); 
1825 void wxGenericTreeCtrl::DeleteAllItems() 
1833 void wxGenericTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
1835     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1837     wxCHECK_RET( item
, wxT("invalid item in wxGenericTreeCtrl::Expand") ); 
1838     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1839                  wxT("can't expand hidden root") ); 
1841     if ( !item
->HasPlus() ) 
1844     if ( item
->IsExpanded() ) 
1847     wxTreeEvent 
event(wxEVT_COMMAND_TREE_ITEM_EXPANDING
, this, item
); 
1849     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
1851         // cancelled by program 
1858         CalculatePositions(); 
1860         RefreshSubtree(item
); 
1867     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
1868     GetEventHandler()->ProcessEvent( event 
); 
1871 void wxGenericTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
1873     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1874                  wxT("can't collapse hidden root") ); 
1876     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1878     if ( !item
->IsExpanded() ) 
1881     wxTreeEvent 
event(wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, this, item
); 
1882     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
1884         // cancelled by program 
1888     ChildrenClosing(item
); 
1891 #if 0  // TODO why should items be collapsed recursively? 
1892     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1893     size_t count 
= children
.GetCount(); 
1894     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1896         Collapse(children
[n
]); 
1900     CalculatePositions(); 
1902     RefreshSubtree(item
); 
1904     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
1905     GetEventHandler()->ProcessEvent( event 
); 
1908 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
1911     DeleteChildren(item
); 
1914 void wxGenericTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
1916     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1918     if (item
->IsExpanded()) 
1924 void wxGenericTreeCtrl::Unselect() 
1928         m_current
->SetHilight( false ); 
1929         RefreshLine( m_current 
); 
1936 void wxGenericTreeCtrl::ClearFocusedItem() 
1938     wxTreeItemId item 
= GetFocusedItem(); 
1940         SelectItem(item
, false); 
1943 void wxGenericTreeCtrl::SetFocusedItem(const wxTreeItemId
& item
) 
1945     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1947     SelectItem(item
, true); 
1950 void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem 
*item
) 
1952     if (item
->IsSelected()) 
1954         item
->SetHilight(false); 
1958     if (item
->HasChildren()) 
1960         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1961         size_t count 
= children
.GetCount(); 
1962         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1964             UnselectAllChildren(children
[n
]); 
1969 void wxGenericTreeCtrl::UnselectAll() 
1971     wxTreeItemId rootItem 
= GetRootItem(); 
1973     // the tree might not have the root item at all 
1976         UnselectAllChildren((wxGenericTreeItem
*) rootItem
.m_pItem
); 
1980 void wxGenericTreeCtrl::SelectChildren(const wxTreeItemId
& parent
) 
1982     wxCHECK_RET( HasFlag(wxTR_MULTIPLE
), 
1983                  "this only works with multiple selection controls" ); 
1987     if ( !HasChildren(parent
) ) 
1991     wxArrayGenericTreeItems
& 
1992         children 
= ((wxGenericTreeItem
*) parent
.m_pItem
)->GetChildren(); 
1993     size_t count 
= children
.GetCount(); 
1996         item 
= (wxGenericTreeItem
*) ((wxTreeItemId
)children
[0]).m_pItem
; 
1997     wxTreeEvent 
event(wxEVT_COMMAND_TREE_SEL_CHANGING
, this, item
); 
1998     event
.m_itemOld 
= m_current
; 
2000     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
2003     for ( size_t n 
= 0; n 
< count
; ++n 
) 
2005         m_current 
= m_key_current 
= children
[n
]; 
2006         m_current
->SetHilight(true); 
2011     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
2012     GetEventHandler()->ProcessEvent( event 
); 
2016 // Recursive function ! 
2017 // To stop we must have crt_item<last_item 
2019 // Tag all next children, when no more children, 
2020 // Move to parent (not to tag) 
2021 // Keep going... if we found last_item, we stop. 
2023 wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem 
*crt_item
, 
2024                                    wxGenericTreeItem 
*last_item
, 
2027     wxGenericTreeItem 
*parent 
= crt_item
->GetParent(); 
2029     if (parent 
== NULL
) // This is root item 
2030         return TagAllChildrenUntilLast(crt_item
, last_item
, select
); 
2032     wxArrayGenericTreeItems
& children 
= parent
->GetChildren(); 
2033     int index 
= children
.Index(crt_item
); 
2034     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
2036     size_t count 
= children
.GetCount(); 
2037     for (size_t n
=(size_t)(index
+1); n
<count
; ++n
) 
2039         if ( TagAllChildrenUntilLast(children
[n
], last_item
, select
) ) 
2043     return TagNextChildren(parent
, last_item
, select
); 
2047 wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem 
*crt_item
, 
2048                                            wxGenericTreeItem 
*last_item
, 
2051     crt_item
->SetHilight(select
); 
2052     RefreshLine(crt_item
); 
2054     if (crt_item
==last_item
) 
2057     // We should leave the not shown children of collapsed items alone. 
2058     if (crt_item
->HasChildren() && crt_item
->IsExpanded()) 
2060         wxArrayGenericTreeItems
& children 
= crt_item
->GetChildren(); 
2061         size_t count 
= children
.GetCount(); 
2062         for ( size_t n 
= 0; n 
< count
; ++n 
) 
2064             if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) 
2073 wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem 
*item1
, 
2074                                    wxGenericTreeItem 
*item2
) 
2078     // item2 is not necessary after item1 
2079     // choice first' and 'last' between item1 and item2 
2080     wxGenericTreeItem 
*first
= (item1
->GetY()<item2
->GetY()) ? item1 
: item2
; 
2081     wxGenericTreeItem 
*last 
= (item1
->GetY()<item2
->GetY()) ? item2 
: item1
; 
2083     bool select 
= m_current
->IsSelected(); 
2085     if ( TagAllChildrenUntilLast(first
,last
,select
) ) 
2088     TagNextChildren(first
,last
,select
); 
2091 void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId
& itemId
, 
2092                                      bool unselect_others
, 
2093                                      bool extended_select
) 
2095     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
2099     bool is_single
=!(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
2100     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
2102     //wxCHECK_RET( ( (!unselect_others) && is_single), 
2103     //           wxT("this is a single selection tree") ); 
2105     // to keep going anyhow !!! 
2108         if (item
->IsSelected()) 
2109             return; // nothing to do 
2110         unselect_others 
= true; 
2111         extended_select 
= false; 
2113     else if ( unselect_others 
&& item
->IsSelected() ) 
2115         // selection change if there is more than one item currently selected 
2116         wxArrayTreeItemIds selected_items
; 
2117         if ( GetSelections(selected_items
) == 1 ) 
2121     wxTreeEvent 
event(wxEVT_COMMAND_TREE_SEL_CHANGING
, this, item
); 
2122     event
.m_itemOld 
= m_current
; 
2123     // TODO : Here we don't send any selection mode yet ! 
2125     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
2128     wxTreeItemId parent 
= GetItemParent( itemId 
); 
2129     while (parent
.IsOk()) 
2131         if (!IsExpanded(parent
)) 
2134         parent 
= GetItemParent( parent 
); 
2138     if (unselect_others
) 
2140         if (is_single
) Unselect(); // to speed up thing 
2145     if (extended_select
) 
2150             m_key_current 
= (wxGenericTreeItem
*) GetRootItem().m_pItem
; 
2153         // don't change the mark (m_current) 
2154         SelectItemRange(m_current
, item
); 
2158         bool select 
= true; // the default 
2160         // Check if we need to toggle hilight (ctrl mode) 
2161         if (!unselect_others
) 
2162             select
=!item
->IsSelected(); 
2164         m_current 
= m_key_current 
= item
; 
2165         m_current
->SetHilight(select
); 
2166         RefreshLine( m_current 
); 
2169     // This can cause idle processing to select the root 
2170     // if no item is selected, so it must be after the 
2172     EnsureVisible( itemId 
); 
2174     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
2175     GetEventHandler()->ProcessEvent( event 
); 
2178 void wxGenericTreeCtrl::SelectItem(const wxTreeItemId
& itemId
, bool select
) 
2180     wxGenericTreeItem 
* const item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
2181     wxCHECK_RET( item
, wxT("SelectItem(): invalid tree item") ); 
2185         if ( !item
->IsSelected() ) 
2186             DoSelectItem(itemId
, !HasFlag(wxTR_MULTIPLE
)); 
2190         wxTreeEvent 
event(wxEVT_COMMAND_TREE_SEL_CHANGING
, this, item
); 
2191         if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
2194         item
->SetHilight(false); 
2197         event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
2198         GetEventHandler()->ProcessEvent( event 
); 
2202 void wxGenericTreeCtrl::FillArray(wxGenericTreeItem 
*item
, 
2203                                   wxArrayTreeItemIds 
&array
) const 
2205     if ( item
->IsSelected() ) 
2206         array
.Add(wxTreeItemId(item
)); 
2208     if ( item
->HasChildren() ) 
2210         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2211         size_t count 
= children
.GetCount(); 
2212         for ( size_t n 
= 0; n 
< count
; ++n 
) 
2213             FillArray(children
[n
], array
); 
2217 size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds 
&array
) const 
2220     wxTreeItemId idRoot 
= GetRootItem(); 
2221     if ( idRoot
.IsOk() ) 
2223         FillArray((wxGenericTreeItem
*) idRoot
.m_pItem
, array
); 
2225     //else: the tree is empty, so no selections 
2227     return array
.GetCount(); 
2230 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
2232     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
2234     if (!item
.IsOk()) return; 
2236     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2238     // first expand all parent branches 
2239     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
2241     if ( HasFlag(wxTR_HIDE_ROOT
) ) 
2243         while ( parent 
&& parent 
!= m_anchor 
) 
2246             parent 
= parent
->GetParent(); 
2254             parent 
= parent
->GetParent(); 
2258     //if (parent) CalculatePositions(); 
2263 void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId 
&item
) 
2268     // update the control before scrolling it 
2271 #if defined( __WXMSW__ )  
2273 #elif defined(__WXMAC__) 
2275         DoDirtyProcessing(); 
2277         DoDirtyProcessing(); 
2281     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2283     int itemY 
= gitem
->GetY(); 
2287     GetViewStart( &start_x
, &start_y 
); 
2289     const int clientHeight 
= GetClientSize().y
; 
2291     const int itemHeight 
= GetLineHeight(gitem
) + 2; 
2293     if ( itemY 
+ itemHeight 
> start_y
*PIXELS_PER_UNIT 
+ clientHeight 
) 
2295         // need to scroll up by enough to show this item fully 
2296         itemY 
+= itemHeight 
- clientHeight
; 
2298         // because itemY below will be divided by PIXELS_PER_UNIT it may 
2299         // be rounded down, with the result of the item still only being  
2300         // partially visible, so make sure we are rounding up 
2301         itemY 
+= PIXELS_PER_UNIT
-1; 
2304     else if ( itemY 
> start_y
*PIXELS_PER_UNIT 
) 
2306         // item is already fully visible, don't do anything 
2309     //else: scroll down to make this item the top one displayed 
2311     Scroll(-1, itemY
/PIXELS_PER_UNIT
); 
2314 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
2315 static wxGenericTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
2317 static int LINKAGEMODE 
tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
2318                                   wxGenericTreeItem 
**item2
) 
2320     wxCHECK_MSG( s_treeBeingSorted
, 0, 
2321                  "bug in wxGenericTreeCtrl::SortChildren()" ); 
2323     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
2326 void wxGenericTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
2328     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
2330     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
2332     wxCHECK_RET( !s_treeBeingSorted
, 
2333                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") ); 
2335     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2336     if ( children
.GetCount() > 1 ) 
2340         s_treeBeingSorted 
= this; 
2341         children
.Sort(tree_ctrl_compare_func
); 
2342         s_treeBeingSorted 
= NULL
; 
2344     //else: don't make the tree dirty as nothing changed 
2347 void wxGenericTreeCtrl::CalculateLineHeight() 
2349     wxClientDC 
dc(this); 
2350     m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
2352     if ( m_imageListNormal 
) 
2354         // Calculate a m_lineHeight value from the normal Image sizes. 
2355         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2356         // necessary (which might look ugly). 
2357         int n 
= m_imageListNormal
->GetImageCount(); 
2358         for (int i 
= 0; i 
< n 
; i
++) 
2360             int width 
= 0, height 
= 0; 
2361             m_imageListNormal
->GetSize(i
, width
, height
); 
2362             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2366     if ( m_imageListState 
) 
2368         // Calculate a m_lineHeight value from the state Image sizes. 
2369         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2370         // necessary (which might look ugly). 
2371         int n 
= m_imageListState
->GetImageCount(); 
2372         for (int i 
= 0; i 
< n 
; i
++) 
2374             int width 
= 0, height 
= 0; 
2375             m_imageListState
->GetSize(i
, width
, height
); 
2376             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2380     if (m_imageListButtons
) 
2382         // Calculate a m_lineHeight value from the Button image sizes. 
2383         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2384         // necessary (which might look ugly). 
2385         int n 
= m_imageListButtons
->GetImageCount(); 
2386         for (int i 
= 0; i 
< n 
; i
++) 
2388             int width 
= 0, height 
= 0; 
2389             m_imageListButtons
->GetSize(i
, width
, height
); 
2390             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2394     if (m_lineHeight 
< 30) 
2395         m_lineHeight 
+= 2;                 // at least 2 pixels 
2397         m_lineHeight 
+= m_lineHeight
/10;   // otherwise 10% extra spacing 
2400 void wxGenericTreeCtrl::SetImageList(wxImageList 
*imageList
) 
2402     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
2403     m_imageListNormal 
= imageList
; 
2404     m_ownsImageListNormal 
= false; 
2408         m_anchor
->RecursiveResetSize(); 
2410     // Don't do any drawing if we're setting the list to NULL, 
2411     // since we may be in the process of deleting the tree control. 
2413         CalculateLineHeight(); 
2416 void wxGenericTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
2418     if (m_ownsImageListState
) delete m_imageListState
; 
2419     m_imageListState 
= imageList
; 
2420     m_ownsImageListState 
= false; 
2424         m_anchor
->RecursiveResetSize(); 
2426     // Don't do any drawing if we're setting the list to NULL, 
2427     // since we may be in the process of deleting the tree control. 
2429         CalculateLineHeight(); 
2432 void wxGenericTreeCtrl::SetButtonsImageList(wxImageList 
*imageList
) 
2434     if (m_ownsImageListButtons
) delete m_imageListButtons
; 
2435     m_imageListButtons 
= imageList
; 
2436     m_ownsImageListButtons 
= false; 
2440         m_anchor
->RecursiveResetSize(); 
2442     CalculateLineHeight(); 
2445 void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList 
*imageList
) 
2447     SetButtonsImageList(imageList
); 
2448     m_ownsImageListButtons 
= true; 
2451 // ----------------------------------------------------------------------------- 
2453 // ----------------------------------------------------------------------------- 
2455 void wxGenericTreeCtrl::AdjustMyScrollbars() 
2460         m_anchor
->GetSize( x
, y
, this ); 
2461         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2462         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2463         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2464         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
2465         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, 
2466                        x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, 
2471         SetScrollbars( 0, 0, 0, 0 ); 
2475 int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem 
*item
) const 
2477     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
2478         return item
->GetHeight(); 
2480         return m_lineHeight
; 
2483 void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
2485     item
->SetFont(this, dc
); 
2486     item
->CalculateSize(this, dc
); 
2488     wxCoord text_h 
= item
->GetTextHeight(); 
2490     int image_h 
= 0, image_w 
= 0; 
2491     int image 
= item
->GetCurrentImage(); 
2492     if ( image 
!= NO_IMAGE 
) 
2494         if ( m_imageListNormal 
) 
2496             m_imageListNormal
->GetSize(image
, image_w
, image_h
); 
2497             image_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
2505     int state_h 
= 0, state_w 
= 0; 
2506     int state 
= item
->GetState(); 
2507     if ( state 
!= wxTREE_ITEMSTATE_NONE 
) 
2509         if ( m_imageListState 
) 
2511             m_imageListState
->GetSize(state
, state_w
, state_h
); 
2513                 state_w 
+= MARGIN_BETWEEN_STATE_AND_IMAGE
; 
2515                 state_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
2519             state 
= wxTREE_ITEMSTATE_NONE
; 
2523     int total_h 
= GetLineHeight(item
); 
2524     bool drawItemBackground 
= false, 
2525          hasBgColour 
= false; 
2527     if ( item
->IsSelected() ) 
2529         dc
.SetBrush(*(m_hasFocus 
? m_hilightBrush 
: m_hilightUnfocusedBrush
)); 
2530         drawItemBackground 
= true; 
2535         wxTreeItemAttr 
* const attr 
= item
->GetAttributes(); 
2536         if ( attr 
&& attr
->HasBackgroundColour() ) 
2538             drawItemBackground 
= 
2540             colBg 
= attr
->GetBackgroundColour(); 
2544             colBg 
= GetBackgroundColour(); 
2546         dc
.SetBrush(wxBrush(colBg
, wxBRUSHSTYLE_SOLID
)); 
2549     int offset 
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0; 
2551     if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT
) ) 
2555         GetVirtualSize(&w
, &h
); 
2556         wxRect 
rect( x
, item
->GetY()+offset
, w
, total_h
-offset
); 
2557         if (!item
->IsSelected()) 
2559             dc
.DrawRectangle(rect
); 
2563             int flags 
= wxCONTROL_SELECTED
; 
2565 #if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON // TODO CS 
2566                 && IsControlActive( (ControlRef
)GetHandle() ) 
2569                 flags 
|= wxCONTROL_FOCUSED
; 
2570             if ((item 
== m_current
) && (m_hasFocus
)) 
2571                 flags 
|= wxCONTROL_CURRENT
; 
2573             wxRendererNative::Get(). 
2574                 DrawItemSelectionRect(this, dc
, rect
, flags
); 
2577     else // no full row highlight 
2579         if ( item
->IsSelected() && 
2580                 (state 
!= wxTREE_ITEMSTATE_NONE 
|| image 
!= NO_IMAGE
) ) 
2582             // If it's selected, and there's an state image or normal image, 
2583             // then we should take care to leave the area under the image 
2584             // painted in the background colour. 
2585             wxRect 
rect( item
->GetX() + state_w 
+ image_w 
- 2, 
2586                          item
->GetY() + offset
, 
2587                          item
->GetWidth() - state_w 
- image_w 
+ 2, 
2589 #if !defined(__WXGTK20__) && !defined(__WXMAC__) 
2590             dc
.DrawRectangle( rect 
); 
2595             int flags 
= wxCONTROL_SELECTED
; 
2597                 flags 
|= wxCONTROL_FOCUSED
; 
2598             if ((item 
== m_current
) && (m_hasFocus
)) 
2599                 flags 
|= wxCONTROL_CURRENT
; 
2600             wxRendererNative::Get(). 
2601                 DrawItemSelectionRect(this, dc
, rect
, flags
); 
2604         // On GTK+ 2, drawing a 'normal' background is wrong for themes that 
2605         // don't allow backgrounds to be customized. Not drawing the background, 
2606         // except for custom item backgrounds, works for both kinds of theme. 
2607         else if (drawItemBackground
) 
2609             wxRect 
rect( item
->GetX() + state_w 
+ image_w 
- 2, 
2610                          item
->GetY() + offset
, 
2611                          item
->GetWidth() - state_w 
- image_w 
+ 2, 
2615                 dc
.DrawRectangle( rect 
); 
2617             else // no specific background colour 
2622                 int flags 
= wxCONTROL_SELECTED
; 
2624                     flags 
|= wxCONTROL_FOCUSED
; 
2625                 if ((item 
== m_current
) && (m_hasFocus
)) 
2626                     flags 
|= wxCONTROL_CURRENT
; 
2627                 wxRendererNative::Get(). 
2628                     DrawItemSelectionRect(this, dc
, rect
, flags
); 
2633     if ( state 
!= wxTREE_ITEMSTATE_NONE 
) 
2635         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), state_w
, total_h 
); 
2636         m_imageListState
->Draw( state
, dc
, 
2639                                     (total_h 
> state_h 
? (total_h
-state_h
)/2 
2641                                 wxIMAGELIST_DRAW_TRANSPARENT 
); 
2642         dc
.DestroyClippingRegion(); 
2645     if ( image 
!= NO_IMAGE 
) 
2647         dc
.SetClippingRegion(item
->GetX() + state_w
, item
->GetY(), 
2649         m_imageListNormal
->Draw( image
, dc
, 
2650                                  item
->GetX() + state_w
, 
2652                                     (total_h 
> image_h 
? (total_h
-image_h
)/2 
2654                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
2655         dc
.DestroyClippingRegion(); 
2658     dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
); 
2659     int extraH 
= (total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0; 
2660     dc
.DrawText( item
->GetText(), 
2661                  (wxCoord
)(state_w 
+ image_w 
+ item
->GetX()), 
2662                  (wxCoord
)(item
->GetY() + extraH
)); 
2664     // restore normal font 
2665     dc
.SetFont( m_normalFont 
); 
2667     if (item 
== m_dndEffectItem
) 
2669         dc
.SetPen( *wxBLACK_PEN 
); 
2670         // DnD visual effects 
2671         switch (m_dndEffect
) 
2675                 dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
2676                 int w 
= item
->GetWidth() + 2; 
2677                 int h 
= total_h 
+ 2; 
2678                 dc
.DrawRectangle( item
->GetX() - 1, item
->GetY() - 1, w
, h
); 
2683                 int x 
= item
->GetX(), 
2685                 dc
.DrawLine( x
, y
, x 
+ item
->GetWidth(), y
); 
2690                 int x 
= item
->GetX(), 
2693                 dc
.DrawLine( x
, y
, x 
+ item
->GetWidth(), y
); 
2703 wxGenericTreeCtrl::PaintLevel(wxGenericTreeItem 
*item
, 
2708     int x 
= level
*m_indent
; 
2709     if (!HasFlag(wxTR_HIDE_ROOT
)) 
2713     else if (level 
== 0) 
2715         // always expand hidden root 
2717         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2718         int count 
= children
.GetCount(); 
2724                 PaintLevel(children
[n
], dc
, 1, y
); 
2725             } while (++n 
< count
); 
2727             if ( !HasFlag(wxTR_NO_LINES
) && HasFlag(wxTR_LINES_AT_ROOT
) 
2730                 // draw line down to last child 
2731                 origY 
+= GetLineHeight(children
[0])>>1; 
2732                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2733                 dc
.DrawLine(3, origY
, 3, oldY
); 
2739     item
->SetX(x
+m_spacing
); 
2742     int h 
= GetLineHeight(item
); 
2744     int y_mid 
= y_top 
+ (h
>>1); 
2747     int exposed_x 
= dc
.LogicalToDeviceX(0); 
2748     int exposed_y 
= dc
.LogicalToDeviceY(y_top
); 
2750     if (IsExposed(exposed_x
, exposed_y
, 10000, h
))  // 10000 = very much 
2754             // don't draw rect outline if we already have the 
2755             // background color under Mac 
2756             (item
->IsSelected() && m_hasFocus
) ? wxBLACK_PEN 
: 
2757 #endif // !__WXMAC__ 
2761         if ( item
->IsSelected() 
2762 #if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON // TODO CS 
2763             // On wxMac, if the tree doesn't have the focus we draw an empty 
2764             // rectangle, so we want to make sure that the text is visible 
2765             // against the normal background, not the highlightbackground, so 
2766             // don't use the highlight text colour unless we have the focus. 
2767              && m_hasFocus 
&& IsControlActive( (ControlRef
)GetHandle() ) 
2775                 colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
2777                 colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT
); 
2782             wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2783             if (attr 
&& attr
->HasTextColour()) 
2784                 colText 
= attr
->GetTextColour(); 
2786                 colText 
= GetForegroundColour(); 
2790         dc
.SetTextForeground(colText
); 
2794         PaintItem(item
, dc
); 
2796         if (HasFlag(wxTR_ROW_LINES
)) 
2798             // if the background colour is white, choose a 
2799             // contrasting color for the lines 
2800             dc
.SetPen(*((GetBackgroundColour() == *wxWHITE
) 
2801                          ? wxMEDIUM_GREY_PEN 
: wxWHITE_PEN
)); 
2802             dc
.DrawLine(0, y_top
, 10000, y_top
); 
2803             dc
.DrawLine(0, y
, 10000, y
); 
2806         // restore DC objects 
2807         dc
.SetBrush(*wxWHITE_BRUSH
); 
2808         dc
.SetPen(m_dottedPen
); 
2809         dc
.SetTextForeground(*wxBLACK
); 
2811         if ( !HasFlag(wxTR_NO_LINES
) ) 
2813             // draw the horizontal line here 
2815             if (x 
> (signed)m_indent
) 
2816                 x_start 
-= m_indent
; 
2817             else if (HasFlag(wxTR_LINES_AT_ROOT
)) 
2819             dc
.DrawLine(x_start
, y_mid
, x 
+ m_spacing
, y_mid
); 
2822         // should the item show a button? 
2823         if ( item
->HasPlus() && HasButtons() ) 
2825             if ( m_imageListButtons 
) 
2827                 // draw the image button here 
2830                 int image 
= item
->IsExpanded() ? wxTreeItemIcon_Expanded
 
2831                                                : wxTreeItemIcon_Normal
; 
2832                 if ( item
->IsSelected() ) 
2833                     image 
+= wxTreeItemIcon_Selected 
- wxTreeItemIcon_Normal
; 
2835                 m_imageListButtons
->GetSize(image
, image_w
, image_h
); 
2836                 int xx 
= x 
- image_w
/2; 
2837                 int yy 
= y_mid 
- image_h
/2; 
2839                 wxDCClipper 
clip(dc
, xx
, yy
, image_w
, image_h
); 
2840                 m_imageListButtons
->Draw(image
, dc
, xx
, yy
, 
2841                                          wxIMAGELIST_DRAW_TRANSPARENT
); 
2843             else // no custom buttons 
2845                 static const int wImage 
= 9; 
2846                 static const int hImage 
= 9; 
2849                 if (item
->IsExpanded()) 
2850                     flag 
|= wxCONTROL_EXPANDED
; 
2851                 if (item 
== m_underMouse
) 
2852                     flag 
|= wxCONTROL_CURRENT
; 
2854                 wxRendererNative::Get().DrawTreeItemButton
 
2858                                             wxRect(x 
- wImage
/2, 
2867     if (item
->IsExpanded()) 
2869         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2870         int count 
= children
.GetCount(); 
2877                 PaintLevel(children
[n
], dc
, level
, y
); 
2878             } while (++n 
< count
); 
2880             if (!HasFlag(wxTR_NO_LINES
) && count 
> 0) 
2882                 // draw line down to last child 
2883                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2884                 if (HasButtons()) y_mid 
+= 5; 
2886                 // Only draw the portion of the line that is visible, in case 
2888                 wxCoord xOrigin
=0, yOrigin
=0, width
, height
; 
2889                 dc
.GetDeviceOrigin(&xOrigin
, &yOrigin
); 
2890                 yOrigin 
= abs(yOrigin
); 
2891                 GetClientSize(&width
, &height
); 
2893                 // Move end points to the beginning/end of the view? 
2894                 if (y_mid 
< yOrigin
) 
2896                 if (oldY 
> yOrigin 
+ height
) 
2897                     oldY 
= yOrigin 
+ height
; 
2899                 // after the adjustments if y_mid is larger than oldY then the 
2900                 // line isn't visible at all so don't draw anything 
2902                     dc
.DrawLine(x
, y_mid
, x
, oldY
); 
2908 void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem 
*item
) 
2912         if ( item
->HasPlus() ) 
2914             // it's a folder, indicate it by a border 
2919             // draw a line under the drop target because the item will be 
2921             DrawLine(item
, !m_dropEffectAboveItem 
); 
2924         SetCursor(*wxSTANDARD_CURSOR
); 
2929         SetCursor(wxCURSOR_NO_ENTRY
); 
2933 void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId 
&item
) 
2935     wxCHECK_RET( item
.IsOk(), "invalid item in wxGenericTreeCtrl::DrawLine" ); 
2937     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2939     if (m_dndEffect 
== NoEffect
) 
2941         m_dndEffect 
= BorderEffect
; 
2942         m_dndEffectItem 
= i
; 
2946         m_dndEffect 
= NoEffect
; 
2947         m_dndEffectItem 
= NULL
; 
2950     wxRect 
rect( i
->GetX()-1, i
->GetY()-1, i
->GetWidth()+2, GetLineHeight(i
)+2 ); 
2951     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2952     RefreshRect( rect 
); 
2955 void wxGenericTreeCtrl::DrawLine(const wxTreeItemId 
&item
, bool below
) 
2957     wxCHECK_RET( item
.IsOk(), "invalid item in wxGenericTreeCtrl::DrawLine" ); 
2959     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2961     if (m_dndEffect 
== NoEffect
) 
2964             m_dndEffect 
= BelowEffect
; 
2966             m_dndEffect 
= AboveEffect
; 
2967         m_dndEffectItem 
= i
; 
2971         m_dndEffect 
= NoEffect
; 
2972         m_dndEffectItem 
= NULL
; 
2975     wxRect 
rect( i
->GetX()-1, i
->GetY()-1, i
->GetWidth()+2, GetLineHeight(i
)+2 ); 
2976     CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2977     RefreshRect( rect 
); 
2980 // ----------------------------------------------------------------------------- 
2981 // wxWidgets callbacks 
2982 // ----------------------------------------------------------------------------- 
2984 void wxGenericTreeCtrl::OnSize( wxSizeEvent 
&event 
) 
2987     if (HasFlag( wxTR_FULL_ROW_HIGHLIGHT
) && m_current
) 
2988         RefreshLine( m_current 
); 
2994 void wxGenericTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
3002     dc
.SetFont( m_normalFont 
); 
3003     dc
.SetPen( m_dottedPen 
); 
3005     // this is now done dynamically 
3006     //if(GetImageList() == NULL) 
3007     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
3010     PaintLevel( m_anchor
, dc
, 0, y 
); 
3013 void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent 
&event 
) 
3022 void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
3031 void wxGenericTreeCtrl::OnKeyDown( wxKeyEvent 
&event 
) 
3033     // send a tree event 
3034     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, this); 
3035     te
.m_evtKey 
= event
; 
3036     if ( GetEventHandler()->ProcessEvent( te 
) ) 
3042 void wxGenericTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
3044     if ( (m_current 
== 0) || (m_key_current 
== 0) ) 
3050     // how should the selection work for this event? 
3051     bool is_multiple
, extended_select
, unselect_others
; 
3052     EventFlagsToSelType(GetWindowStyleFlag(), 
3055                         is_multiple
, extended_select
, unselect_others
); 
3057     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
3059         if (event
.GetKeyCode() == WXK_RIGHT
) 
3060             event
.m_keyCode 
= WXK_LEFT
; 
3061         else if (event
.GetKeyCode() == WXK_LEFT
) 
3062             event
.m_keyCode 
= WXK_RIGHT
; 
3067     // * : Expand all/Collapse all 
3068     // ' ' | return : activate 
3069     // up    : go up (not last children!) 
3071     // left  : go to parent 
3072     // right : open if parent and go next 
3073     // home  : go to root 
3074     // end   : go to last item without opening parents 
3075     // alnum : start or continue searching for the item with this prefix 
3076     int keyCode 
= event
.GetKeyCode(); 
3079     // Make the keys work as they do in the native control: 
3081     // left => collapse if current item is expanded 
3082     if (keyCode 
== WXK_RIGHT
) 
3086     else if (keyCode 
== WXK_LEFT 
&& IsExpanded(m_current
)) 
3096             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
3104             if ( !IsExpanded(m_current
) ) 
3107                 ExpandAllChildren(m_current
); 
3110             //else: fall through to Collapse() it 
3114             if (IsExpanded(m_current
)) 
3116                 Collapse(m_current
); 
3122                 // Use the item's bounding rectangle to determine position for 
3125                 GetBoundingRect(m_current
, ItemRect
, true); 
3128                     eventMenu(wxEVT_COMMAND_TREE_ITEM_MENU
, this, m_current
); 
3129                 // Use the left edge, vertical middle 
3130                 eventMenu
.m_pointDrag 
= wxPoint(ItemRect
.GetX(), 
3132                                                     ItemRect
.GetHeight() / 2); 
3133                 GetEventHandler()->ProcessEvent( eventMenu 
); 
3139             if ( !event
.HasModifiers() ) 
3142                    eventAct(wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, this, m_current
); 
3143                 GetEventHandler()->ProcessEvent( eventAct 
); 
3146             // in any case, also generate the normal key event for this key, 
3147             // even if we generated the ACTIVATED event above: this is what 
3148             // wxMSW does and it makes sense because you might not want to 
3149             // process ACTIVATED event at all and handle Space and Return 
3150             // directly (and differently) which would be impossible otherwise 
3154             // up goes to the previous sibling or to the last 
3155             // of its children if it's expanded 
3158                 wxTreeItemId prev 
= GetPrevSibling( m_key_current 
); 
3161                     prev 
= GetItemParent( m_key_current 
); 
3162                     if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
3164                         break;  // don't go to root if it is hidden 
3168                         wxTreeItemIdValue cookie
; 
3169                         wxTreeItemId current 
= m_key_current
; 
3170                         // TODO: Huh?  If we get here, we'd better be the first 
3171                         // child of our parent.  How else could it be? 
3172                         if (current 
== GetFirstChild( prev
, cookie 
)) 
3174                             // otherwise we return to where we came from 
3178                             m_key_current 
= (wxGenericTreeItem
*) prev
.m_pItem
; 
3185                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
3187                         wxTreeItemId child 
= GetLastChild(prev
); 
3194                     DoSelectItem( prev
, unselect_others
, extended_select 
); 
3195                     m_key_current
=(wxGenericTreeItem
*) prev
.m_pItem
; 
3200             // left arrow goes to the parent 
3203                 wxTreeItemId prev 
= GetItemParent( m_current 
); 
3204                 if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
3206                     // don't go to root if it is hidden 
3207                     prev 
= GetPrevSibling( m_current 
); 
3211                     DoSelectItem( prev
, unselect_others
, extended_select 
); 
3217             // this works the same as the down arrow except that we 
3218             // also expand the item if it wasn't expanded yet 
3219             if (m_current 
!= GetRootItem().m_pItem 
|| !HasFlag(wxTR_HIDE_ROOT
)) 
3221             //else: don't try to expand hidden root item (which can be the 
3222             //      current one when the tree is empty) 
3228                 if (IsExpanded(m_key_current
) && HasChildren(m_key_current
)) 
3230                     wxTreeItemIdValue cookie
; 
3231                     wxTreeItemId child 
= GetFirstChild( m_key_current
, cookie 
); 
3235                     DoSelectItem( child
, unselect_others
, extended_select 
); 
3236                     m_key_current
=(wxGenericTreeItem
*) child
.m_pItem
; 
3240                     wxTreeItemId next 
= GetNextSibling( m_key_current 
); 
3243                         wxTreeItemId current 
= m_key_current
; 
3244                         while (current
.IsOk() && !next
) 
3246                             current 
= GetItemParent( current 
); 
3247                             if (current
) next 
= GetNextSibling( current 
); 
3252                         DoSelectItem( next
, unselect_others
, extended_select 
); 
3253                         m_key_current
=(wxGenericTreeItem
*) next
.m_pItem
; 
3259             // <End> selects the last visible tree item 
3262                 wxTreeItemId last 
= GetRootItem(); 
3264                 while ( last
.IsOk() && IsExpanded(last
) ) 
3266                     wxTreeItemId lastChild 
= GetLastChild(last
); 
3268                     // it may happen if the item was expanded but then all of 
3269                     // its children have been deleted - so IsExpanded() returned 
3270                     // true, but GetLastChild() returned invalid item 
3279                     DoSelectItem( last
, unselect_others
, extended_select 
); 
3284             // <Home> selects the root item 
3287                 wxTreeItemId prev 
= GetRootItem(); 
3291                 if ( HasFlag(wxTR_HIDE_ROOT
) ) 
3293                     wxTreeItemIdValue cookie
; 
3294                     prev 
= GetFirstChild(prev
, cookie
); 
3299                 DoSelectItem( prev
, unselect_others
, extended_select 
); 
3304             // do not use wxIsalnum() here 
3305             if ( !event
.HasModifiers() && 
3306                  ((keyCode 
>= '0' && keyCode 
<= '9') || 
3307                   (keyCode 
>= 'a' && keyCode 
<= 'z') || 
3308                   (keyCode 
>= 'A' && keyCode 
<= 'Z' ))) 
3310                 // find the next item starting with the given prefix 
3311                 wxChar ch 
= (wxChar
)keyCode
; 
3313                 wxTreeItemId id 
= FindItem(m_current
, m_findPrefix 
+ ch
); 
3324                 // also start the timer to reset the current prefix if the user 
3325                 // doesn't press any more alnum keys soon -- we wouldn't want 
3326                 // to use this prefix for a new item search 
3329                     m_findTimer 
= new wxTreeFindTimer(this); 
3332                 m_findTimer
->Start(wxTreeFindTimer::DELAY
, wxTIMER_ONE_SHOT
); 
3342 wxGenericTreeCtrl::DoTreeHitTest(const wxPoint
& point
, int& flags
) const 
3347     if (point
.x
<0) flags 
|= wxTREE_HITTEST_TOLEFT
; 
3348     if (point
.x
>w
) flags 
|= wxTREE_HITTEST_TORIGHT
; 
3349     if (point
.y
<0) flags 
|= wxTREE_HITTEST_ABOVE
; 
3350     if (point
.y
>h
) flags 
|= wxTREE_HITTEST_BELOW
; 
3351     if (flags
) return wxTreeItemId(); 
3353     if (m_anchor 
== NULL
) 
3355         flags 
= wxTREE_HITTEST_NOWHERE
; 
3356         return wxTreeItemId(); 
3359     wxGenericTreeItem 
*hit 
=  m_anchor
->HitTest(CalcUnscrolledPosition(point
), 
3363         flags 
= wxTREE_HITTEST_NOWHERE
; 
3364         return wxTreeItemId(); 
3369 // get the bounding rectangle of the item (or of its label only) 
3370 bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
, 
3372                                         bool textOnly
) const 
3374     wxCHECK_MSG( item
.IsOk(), false, 
3375                  "invalid item in wxGenericTreeCtrl::GetBoundingRect" ); 
3377     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
3381         int image_h 
= 0, image_w 
= 0; 
3382         int image 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetCurrentImage(); 
3383         if ( image 
!= NO_IMAGE 
&& m_imageListNormal 
) 
3385             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
3386             image_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
3389         int state_h 
= 0, state_w 
= 0; 
3390         int state 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetState(); 
3391         if ( state 
!= wxTREE_ITEMSTATE_NONE 
&& m_imageListState 
) 
3393             m_imageListState
->GetSize( state
, state_w
, state_h 
); 
3395                 state_w 
+= MARGIN_BETWEEN_STATE_AND_IMAGE
; 
3397                 state_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
3400         rect
.x 
= i
->GetX() + state_w 
+ image_w
; 
3401         rect
.width 
= i
->GetWidth() - state_w 
- image_w
; 
3404     else // the entire line 
3407         rect
.width 
= GetClientSize().x
; 
3411     rect
.height 
= GetLineHeight(i
); 
3413     // we have to return the logical coordinates, not physical ones 
3414     rect
.SetTopLeft(CalcScrolledPosition(rect
.GetTopLeft())); 
3419 wxTextCtrl 
*wxGenericTreeCtrl::EditLabel(const wxTreeItemId
& item
, 
3420                                   wxClassInfo 
* WXUNUSED(textCtrlClass
)) 
3422     wxCHECK_MSG( item
.IsOk(), NULL
, wxT("can't edit an invalid item") ); 
3424     wxGenericTreeItem 
*itemEdit 
= (wxGenericTreeItem 
*)item
.m_pItem
; 
3426     wxTreeEvent 
te(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, this, itemEdit
); 
3427     if ( GetEventHandler()->ProcessEvent( te 
) && !te
.IsAllowed() ) 
3433     // We have to call this here because the label in 
3434     // question might just have been added and no screen 
3435     // update taken place. 
3437 #if defined( __WXMSW__ ) || defined(__WXMAC__) 
3440         DoDirtyProcessing(); 
3443     // TODO: use textCtrlClass here to create the control of correct class 
3444     m_textCtrl 
= new wxTreeTextCtrl(this, itemEdit
); 
3446     m_textCtrl
->SetFocus(); 
3451 // returns a pointer to the text edit control if the item is being 
3452 // edited, NULL otherwise (it's assumed that no more than one item may 
3453 // be edited simultaneously) 
3454 wxTextCtrl
* wxGenericTreeCtrl::GetEditControl() const 
3459 void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId
& WXUNUSED(item
), 
3460                                      bool discardChanges
) 
3462     wxCHECK_RET( m_textCtrl
, wxT("not editing label") ); 
3464     m_textCtrl
->EndEdit(discardChanges
); 
3467 bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem 
*item
, 
3468                                        const wxString
& value
) 
3470     wxTreeEvent 
le(wxEVT_COMMAND_TREE_END_LABEL_EDIT
, this, item
); 
3472     le
.m_editCancelled 
= false; 
3474     return !GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
3477 void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem 
*item
) 
3479     // let owner know that the edit was cancelled 
3480     wxTreeEvent 
le(wxEVT_COMMAND_TREE_END_LABEL_EDIT
, this, item
); 
3481     le
.m_label 
= wxEmptyString
; 
3482     le
.m_editCancelled 
= true; 
3484     GetEventHandler()->ProcessEvent( le 
); 
3487 void wxGenericTreeCtrl::OnRenameTimer() 
3489     EditLabel( m_current 
); 
3492 void wxGenericTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
3494     if ( !m_anchor 
)return; 
3496     wxPoint pt 
= CalcUnscrolledPosition(event
.GetPosition()); 
3498     // Is the mouse over a tree item button? 
3500     wxGenericTreeItem 
*thisItem 
= m_anchor
->HitTest(pt
, this, flags
, 0); 
3501     wxGenericTreeItem 
*underMouse 
= thisItem
; 
3503     bool underMouseChanged 
= (underMouse 
!= m_underMouse
) ; 
3504 #endif // wxUSE_TOOLTIPS 
3507         (flags 
& wxTREE_HITTEST_ONITEMBUTTON
) && 
3508         (!event
.LeftIsDown()) && 
3510         (!m_renameTimer 
|| !m_renameTimer
->IsRunning())) 
3518     if (underMouse 
!= m_underMouse
) 
3522             // unhighlight old item 
3523             wxGenericTreeItem 
*tmp 
= m_underMouse
; 
3524             m_underMouse 
= NULL
; 
3528          m_underMouse 
= underMouse
; 
3530             RefreshLine( m_underMouse 
); 
3534     // Determines what item we are hovering over and need a tooltip for 
3535     wxTreeItemId hoverItem 
= thisItem
; 
3537     // We do not want a tooltip if we are dragging, or if the rename timer is 
3539     if ( underMouseChanged 
&& 
3542                 (!m_renameTimer 
|| !m_renameTimer
->IsRunning()) ) 
3544         // Ask the tree control what tooltip (if any) should be shown 
3546             hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP
,  this, hoverItem
); 
3548         if ( GetEventHandler()->ProcessEvent(hevent
) ) 
3550             // If the user permitted the tooltip change, update it, otherwise 
3551             // remove any old tooltip we might have. 
3552             if ( hevent
.IsAllowed() ) 
3553                 SetToolTip(hevent
.m_label
); 
3560     // we process left mouse up event (enables in-place edit), middle/right down 
3561     // (pass to the user code), left dbl click (activate item) and 
3562     // dragging/moving events for items drag-and-drop 
3563     if ( !(event
.LeftDown() || 
3565            event
.MiddleDown() || 
3566            event
.RightDown() || 
3567            event
.LeftDClick() || 
3569            ((event
.Moving() || event
.RightUp()) && m_isDragging
)) ) 
3578     wxGenericTreeItem 
*item 
= m_anchor
->HitTest(pt
, this, flags
, 0); 
3580     if ( event
.Dragging() && !m_isDragging 
) 
3582         if (m_dragCount 
== 0) 
3587         if (m_dragCount 
!= 3) 
3589             // wait until user drags a bit further... 
3593         wxEventType command 
= event
.RightIsDown() 
3594                               ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
 
3595                               : wxEVT_COMMAND_TREE_BEGIN_DRAG
; 
3597         wxTreeEvent 
nevent(command
,  this, m_current
); 
3598         nevent
.SetPoint(CalcScrolledPosition(pt
)); 
3600         // by default the dragging is not supported, the user code must 
3601         // explicitly allow the event for it to take place 
3604         if ( GetEventHandler()->ProcessEvent(nevent
) && nevent
.IsAllowed() ) 
3606             // we're going to drag this item 
3607             m_isDragging 
= true; 
3609             // remember the old cursor because we will change it while 
3611             m_oldCursor 
= m_cursor
; 
3613             // in a single selection control, hide the selection temporarily 
3614             if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE
) ) 
3616                 m_oldSelection 
= (wxGenericTreeItem
*) GetSelection().m_pItem
; 
3618                 if ( m_oldSelection 
) 
3620                     m_oldSelection
->SetHilight(false); 
3621                     RefreshLine(m_oldSelection
); 
3628     else if ( event
.Dragging() ) 
3630         if ( item 
!= m_dropTarget 
) 
3632             // unhighlight the previous drop target 
3633             DrawDropEffect(m_dropTarget
); 
3635             m_dropTarget 
= item
; 
3637             // highlight the current drop target if any 
3638             DrawDropEffect(m_dropTarget
); 
3640 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__) 
3643             // TODO: remove this call or use wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI) 
3644             //       instead (needs to be tested!) 
3649     else if ( (event
.LeftUp() || event
.RightUp()) && m_isDragging 
) 
3653         // erase the highlighting 
3654         DrawDropEffect(m_dropTarget
); 
3656         if ( m_oldSelection 
) 
3658             m_oldSelection
->SetHilight(true); 
3659             RefreshLine(m_oldSelection
); 
3660             m_oldSelection 
= NULL
; 
3663         // generate the drag end event 
3664         wxTreeEvent 
eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG
,  this, item
); 
3666         eventEndDrag
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3668         (void)GetEventHandler()->ProcessEvent(eventEndDrag
); 
3670         m_isDragging 
= false; 
3671         m_dropTarget 
= NULL
; 
3673         SetCursor(m_oldCursor
); 
3675 #if defined( __WXMSW__ ) || defined(__WXMAC__) || defined(__WXGTK20__) 
3678         // TODO: remove this call or use wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI) 
3679         //       instead (needs to be tested!) 
3685         // If we got to this point, we are not dragging or moving the mouse. 
3686         // Because the code in carbon/toplevel.cpp will only set focus to the 
3687         // tree if we skip for EVT_LEFT_DOWN, we MUST skip this event here for 
3689         // We skip even if we didn't hit an item because we still should 
3690         // restore focus to the tree control even if we didn't exactly hit an 
3692         if ( event
.LeftDown() ) 
3697         // here we process only the messages which happen on tree items 
3701         if (item 
== NULL
) return;  /* we hit the blank area */ 
3703         if ( event
.RightDown() ) 
3705             // If the item is already selected, do not update the selection. 
3706             // Multi-selections should not be cleared if a selected item is 
3708             if (!IsSelected(item
)) 
3710                 DoSelectItem(item
, true, false); 
3714                 nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
,  this, item
); 
3715             nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3716             event
.Skip(!GetEventHandler()->ProcessEvent(nevent
)); 
3718             // Consistent with MSW (for now), send the ITEM_MENU *after* 
3719             // the RIGHT_CLICK event. TODO: This behaviour may change. 
3720             wxTreeEvent 
nevent2(wxEVT_COMMAND_TREE_ITEM_MENU
,  this, item
); 
3721             nevent2
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3722             GetEventHandler()->ProcessEvent(nevent2
); 
3724         else if ( event
.MiddleDown() ) 
3727                 nevent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK
,  this, item
); 
3728             nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3729             event
.Skip(!GetEventHandler()->ProcessEvent(nevent
)); 
3731         else if ( event
.LeftUp() ) 
3733             if (flags 
& wxTREE_HITTEST_ONITEMSTATEICON
) 
3736                     nevent(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK
, this, item
); 
3737                 GetEventHandler()->ProcessEvent(nevent
); 
3740             // this facilitates multiple-item drag-and-drop 
3742             if ( /* item && */ HasFlag(wxTR_MULTIPLE
)) 
3744                 wxArrayTreeItemIds selections
; 
3745                 size_t count 
= GetSelections(selections
); 
3751                     DoSelectItem(item
, true, false); 
3757                 if ( (item 
== m_current
) && 
3758                      (flags 
& wxTREE_HITTEST_ONITEMLABEL
) && 
3759                      HasFlag(wxTR_EDIT_LABELS
) ) 
3761                     if ( m_renameTimer 
) 
3763                         if ( m_renameTimer
->IsRunning() ) 
3764                             m_renameTimer
->Stop(); 
3768                         m_renameTimer 
= new wxTreeRenameTimer( this ); 
3771                     m_renameTimer
->Start( wxTreeRenameTimer::DELAY
, true ); 
3774                 m_lastOnSame 
= false; 
3777         else // !RightDown() && !MiddleDown() && !LeftUp() 
3779             // ==> LeftDown() || LeftDClick() 
3780             if ( event
.LeftDown() ) 
3782                 m_lastOnSame 
= item 
== m_current
; 
3785             if ( flags 
& wxTREE_HITTEST_ONITEMBUTTON 
) 
3787                 // only toggle the item for a single click, double click on 
3788                 // the button doesn't do anything (it toggles the item twice) 
3789                 if ( event
.LeftDown() ) 
3794                 // don't select the item if the button was clicked 
3799             // clear the previously selected items, if the 
3800             // user clicked outside of the present selection. 
3801             // otherwise, perform the deselection on mouse-up. 
3802             // this allows multiple drag and drop to work. 
3803             // but if Cmd is down, toggle selection of the clicked item 
3804             if (!IsSelected(item
) || event
.CmdDown()) 
3806                 // how should the selection work for this event? 
3807                 bool is_multiple
, extended_select
, unselect_others
; 
3808                 EventFlagsToSelType(GetWindowStyleFlag(), 
3815                 DoSelectItem(item
, unselect_others
, extended_select
); 
3819             // For some reason, Windows isn't recognizing a left double-click, 
3820             // so we need to simulate it here.  Allow 200 milliseconds for now. 
3821             if ( event
.LeftDClick() ) 
3823                 // double clicking should not start editing the item label 
3824                 if ( m_renameTimer 
) 
3825                     m_renameTimer
->Stop(); 
3827                 m_lastOnSame 
= false; 
3829                 // send activate event first 
3831                     nevent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED
,  this, item
); 
3832                 nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3833                 if ( !GetEventHandler()->ProcessEvent( nevent 
) ) 
3835                     // if the user code didn't process the activate event, 
3836                     // handle it ourselves by toggling the item when it is 
3838                     if ( item
->HasPlus() ) 
3848 void wxGenericTreeCtrl::OnInternalIdle() 
3850     wxWindow::OnInternalIdle(); 
3852     // Check if we need to select the root item 
3853     // because nothing else has been selected. 
3854     // Delaying it means that we can invoke event handlers 
3855     // as required, when a first item is selected. 
3856     if (!HasFlag(wxTR_MULTIPLE
) && !GetSelection().IsOk()) 
3859             SelectItem(m_select_me
); 
3860         else if (GetRootItem().IsOk()) 
3861             SelectItem(GetRootItem()); 
3864     // after all changes have been done to the tree control, 
3865     // actually redraw the tree when everything is over 
3867         DoDirtyProcessing(); 
3871 wxGenericTreeCtrl::CalculateLevel(wxGenericTreeItem 
*item
, 
3876     int x 
= level
*m_indent
; 
3877     if (!HasFlag(wxTR_HIDE_ROOT
)) 
3881     else if (level 
== 0) 
3883         // a hidden root is not evaluated, but its 
3884         // children are always calculated 
3888     item
->CalculateSize(this, dc
); 
3891     item
->SetX( x
+m_spacing 
); 
3893     y 
+= GetLineHeight(item
); 
3895     if ( !item
->IsExpanded() ) 
3897         // we don't need to calculate collapsed branches 
3902     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3903     size_t n
, count 
= children
.GetCount(); 
3905     for (n 
= 0; n 
< count
; ++n 
) 
3906         CalculateLevel( children
[n
], dc
, level
, y 
);  // recurse 
3909 void wxGenericTreeCtrl::CalculatePositions() 
3911     if ( !m_anchor 
) return; 
3913     wxClientDC 
dc(this); 
3916     dc
.SetFont( m_normalFont 
); 
3918     dc
.SetPen( m_dottedPen 
); 
3919     //if(GetImageList() == NULL) 
3920     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
3923     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
3926 void wxGenericTreeCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
3929         wxTreeCtrlBase::Refresh(eraseBackground
, rect
); 
3932 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
3934     if (m_dirty 
|| IsFrozen() ) 
3937     wxSize client 
= GetClientSize(); 
3940     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3941     rect
.width 
= client
.x
; 
3942     rect
.height 
= client
.y
; 
3944     Refresh(true, &rect
); 
3946     AdjustMyScrollbars(); 
3949 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
3951     if (m_dirty 
|| IsFrozen() ) 
3955     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3956     rect
.width 
= GetClientSize().x
; 
3957     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
3959     Refresh(true, &rect
); 
3962 void wxGenericTreeCtrl::RefreshSelected() 
3967     // TODO: this is awfully inefficient, we should keep the list of all 
3968     //       selected items internally, should be much faster 
3970         RefreshSelectedUnder(m_anchor
); 
3973 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem 
*item
) 
3978     if ( item
->IsSelected() ) 
3981     const wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3982     size_t count 
= children
.GetCount(); 
3983     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3985         RefreshSelectedUnder(children
[n
]); 
3989 void wxGenericTreeCtrl::DoThaw() 
3991     wxTreeCtrlBase::DoThaw(); 
3994         DoDirtyProcessing(); 
3999 // ---------------------------------------------------------------------------- 
4000 // changing colours: we need to refresh the tree control 
4001 // ---------------------------------------------------------------------------- 
4003 bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour
& colour
) 
4005     if ( !wxWindow::SetBackgroundColour(colour
) ) 
4013 bool wxGenericTreeCtrl::SetForegroundColour(const wxColour
& colour
) 
4015     if ( !wxWindow::SetForegroundColour(colour
) ) 
4023 void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent 
&event 
) 
4026     wxTreeItemId itemId 
= event
.GetItem(); 
4027     const wxGenericTreeItem
* const pItem 
= (wxGenericTreeItem
*)itemId
.m_pItem
; 
4029     // Check if the item fits into the client area: 
4030     if ( pItem
->GetX() + pItem
->GetWidth() > GetClientSize().x 
) 
4032         // If it doesn't, show its full text in the tooltip. 
4033         event
.SetLabel(pItem
->GetText()); 
4036 #endif // wxUSE_TOOLTIPS 
4038         // veto processing the event, nixing any tooltip 
4044 // NOTE: If using the wxListBox visual attributes works everywhere then this can 
4045 // be removed, as well as the #else case below. 
4046 #define _USE_VISATTR 0 
4051 wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
4053 wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
4057     // Use the same color scheme as wxListBox 
4058     return wxListBox::GetClassDefaultAttributes(variant
); 
4060     wxVisualAttributes attr
; 
4061     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT
); 
4062     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
4063     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
4068 void wxGenericTreeCtrl::DoDirtyProcessing() 
4075     CalculatePositions(); 
4077     AdjustMyScrollbars(); 
4080 wxSize 
wxGenericTreeCtrl::DoGetBestSize() const 
4082     // make sure all positions are calculated as normally this only done during 
4083     // idle time but we need them for base class DoGetBestSize() to return the 
4085     wxConstCast(this, wxGenericTreeCtrl
)->CalculatePositions(); 
4087     wxSize size 
= wxTreeCtrlBase::DoGetBestSize(); 
4089     // there seems to be an implicit extra border around the items, although 
4090     // I'm not really sure where does it come from -- but without this, the 
4091     // scrollbars appear in a tree with default/best size 
4094     // and the border has to be rounded up to a multiple of PIXELS_PER_UNIT or 
4095     // scrollbars still appear 
4096     const wxSize
& borderSize 
= GetWindowBorderSize(); 
4098     int dx 
= (size
.x 
- borderSize
.x
) % PIXELS_PER_UNIT
; 
4100         size
.x 
+= PIXELS_PER_UNIT 
- dx
; 
4101     int dy 
= (size
.y 
- borderSize
.y
) % PIXELS_PER_UNIT
; 
4103         size
.y 
+= PIXELS_PER_UNIT 
- dy
; 
4105     // we need to update the cache too as the base class cached its own value 
4106     CacheBestSize(size
); 
4111 #endif // wxUSE_TREECTRL