1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     generic tree control implementation 
   4 // Author:      Robert Roebling 
   6 // Modified:    22/10/98 - almost total rewrite, simpler interface (VZ) 
   8 // Copyright:   (c) 1998 Robert Roebling and Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================= 
  14 // ============================================================================= 
  16 // ----------------------------------------------------------------------------- 
  18 // ----------------------------------------------------------------------------- 
  21   #pragma implementation "treectlg.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  33 #include "wx/treebase.h" 
  34 #include "wx/generic/treectlg.h" 
  36 #include "wx/textctrl.h" 
  37 #include "wx/imaglist.h" 
  38 #include "wx/settings.h" 
  39 #include "wx/dcclient.h" 
  42     #include "wx/mac/private.h" 
  45 // ----------------------------------------------------------------------------- 
  47 // ----------------------------------------------------------------------------- 
  49 class WXDLLEXPORT wxGenericTreeItem
; 
  51 WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem 
*, wxArrayGenericTreeItems
); 
  53 // ---------------------------------------------------------------------------- 
  55 // ---------------------------------------------------------------------------- 
  57 static const int NO_IMAGE 
= -1; 
  59 static const int PIXELS_PER_UNIT 
= 10; 
  61 // ---------------------------------------------------------------------------- 
  63 // ---------------------------------------------------------------------------- 
  66 static const char *aqua_arrow_right
[] = { 
  67 /* columns rows colors chars-per-pixel */ 
  88 static const char *aqua_arrow_down
[] = { 
  89 /* columns rows colors chars-per-pixel */ 
 109 // ----------------------------------------------------------------------------- 
 111 // ----------------------------------------------------------------------------- 
 113 // timer used for enabling in-place edit 
 114 class WXDLLEXPORT wxTreeRenameTimer
: public wxTimer
 
 117     // start editing the current item after half a second (if the mouse hasn't 
 118     // been clicked/moved) 
 119     enum { DELAY 
= 500 }; 
 121     wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
); 
 123     virtual void Notify(); 
 126     wxGenericTreeCtrl 
*m_owner
; 
 128     DECLARE_NO_COPY_CLASS(wxTreeRenameTimer
) 
 131 // control used for in-place edit 
 132 class WXDLLEXPORT wxTreeTextCtrl
: public wxTextCtrl
 
 135     wxTreeTextCtrl(wxGenericTreeCtrl 
*owner
, wxGenericTreeItem 
*item
); 
 138     void OnChar( wxKeyEvent 
&event 
); 
 139     void OnKeyUp( wxKeyEvent 
&event 
); 
 140     void OnKillFocus( wxFocusEvent 
&event 
); 
 142     bool AcceptChanges(); 
 146     wxGenericTreeCtrl  
*m_owner
; 
 147     wxGenericTreeItem  
*m_itemEdited
; 
 148     wxString            m_startValue
; 
 151     DECLARE_EVENT_TABLE() 
 152     DECLARE_NO_COPY_CLASS(wxTreeTextCtrl
) 
 155 // timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed 
 156 // for a sufficiently long time 
 157 class WXDLLEXPORT wxTreeFindTimer 
: public wxTimer
 
 160     // reset the current prefix after half a second of inactivity 
 161     enum { DELAY 
= 500 }; 
 163     wxTreeFindTimer( wxGenericTreeCtrl 
*owner 
) { m_owner 
= owner
; } 
 165     virtual void Notify() { m_owner
->m_findPrefix
.clear(); } 
 168     wxGenericTreeCtrl 
*m_owner
; 
 170     DECLARE_NO_COPY_CLASS(wxTreeFindTimer
) 
 174 class WXDLLEXPORT wxGenericTreeItem
 
 178     wxGenericTreeItem() { m_data 
= NULL
; } 
 179     wxGenericTreeItem( wxGenericTreeItem 
*parent
, 
 180                        const wxString
& text
, 
 183                        wxTreeItemData 
*data 
); 
 185     ~wxGenericTreeItem(); 
 188     wxArrayGenericTreeItems
& GetChildren() { return m_children
; } 
 190     const wxString
& GetText() const { return m_text
; } 
 191     int GetImage(wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) const 
 192         { return m_images
[which
]; } 
 193     wxTreeItemData 
*GetData() const { return m_data
; } 
 195     // returns the current image for the item (depending on its 
 196     // selected/expanded/whatever state) 
 197     int GetCurrentImage() const; 
 199     void SetText( const wxString 
&text 
); 
 200     void SetImage(int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; } 
 201     void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
 203     void SetHasPlus(bool has 
= TRUE
) { m_hasPlus 
= has
; } 
 205     void SetBold(bool bold
) { m_isBold 
= bold
; } 
 207     int GetX() const { return m_x
; } 
 208     int GetY() const { return m_y
; } 
 210     void SetX(int x
) { m_x 
= x
; } 
 211     void SetY(int y
) { m_y 
= y
; } 
 213     int  GetHeight() const { return m_height
; } 
 214     int  GetWidth()  const { return m_width
; } 
 216     void SetHeight(int h
) { m_height 
= h
; } 
 217     void SetWidth(int w
) { m_width 
= w
; } 
 219     wxGenericTreeItem 
*GetParent() const { return m_parent
; } 
 222         // deletes all children notifying the treectrl about it if !NULL 
 224     void DeleteChildren(wxGenericTreeCtrl 
*tree 
= NULL
); 
 226     // get count of all children (and grand children if 'recursively') 
 227     size_t GetChildrenCount(bool recursively 
= TRUE
) const; 
 229     void Insert(wxGenericTreeItem 
*child
, size_t index
) 
 230     { m_children
.Insert(child
, index
); } 
 232     void GetSize( int &x
, int &y
, const wxGenericTreeCtrl
* ); 
 234         // return the item at given position (or NULL if no item), onButton is 
 235         // TRUE if the point belongs to the item's button, otherwise it lies 
 236         // on the button's label 
 237     wxGenericTreeItem 
*HitTest( const wxPoint
& point
, 
 238                                 const wxGenericTreeCtrl 
*, 
 242     void Expand() { m_isCollapsed 
= FALSE
; } 
 243     void Collapse() { m_isCollapsed 
= TRUE
; } 
 245     void SetHilight( bool set 
= TRUE 
) { m_hasHilight 
= set
; } 
 248     bool HasChildren() const { return !m_children
.IsEmpty(); } 
 249     bool IsSelected()  const { return m_hasHilight 
!= 0; } 
 250     bool IsExpanded()  const { return !m_isCollapsed
; } 
 251     bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 252     bool IsBold()      const { return m_isBold 
!= 0; } 
 255         // get them - may be NULL 
 256     wxTreeItemAttr 
*GetAttributes() const { return m_attr
; } 
 257         // get them ensuring that the pointer is not NULL 
 258     wxTreeItemAttr
& Attr() 
 262             m_attr 
= new wxTreeItemAttr
; 
 268     void SetAttributes(wxTreeItemAttr 
*attr
) 
 270         if ( m_ownsAttr 
) delete m_attr
; 
 274         // set them and delete when done 
 275     void AssignAttributes(wxTreeItemAttr 
*attr
) 
 282     // since there can be very many of these, we save size by chosing 
 283     // the smallest representation for the elements and by ordering 
 284     // the members to avoid padding. 
 285     wxString            m_text
;         // label to be rendered for item 
 287     wxTreeItemData     
*m_data
;         // user-provided data 
 289     wxArrayGenericTreeItems m_children
; // list of children 
 290     wxGenericTreeItem  
*m_parent
;       // parent of this item 
 292     wxTreeItemAttr     
*m_attr
;         // attributes??? 
 294     // tree ctrl images for the normal, selected, expanded and 
 295     // expanded+selected states 
 296     short               m_images
[wxTreeItemIcon_Max
]; 
 298     wxCoord             m_x
;            // (virtual) offset from top 
 299     wxCoord             m_y
;            // (virtual) offset from left 
 300     short               m_width
;        // width of this item 
 301     unsigned char       m_height
;       // height of this item 
 303     // use bitfields to save size 
 304     int                 m_isCollapsed 
:1; 
 305     int                 m_hasHilight  
:1; // same as focused 
 306     int                 m_hasPlus     
:1; // used for item which doesn't have 
 307                                           // children but has a [+] button 
 308     int                 m_isBold      
:1; // render the label in bold font 
 309     int                 m_ownsAttr    
:1; // delete attribute when done 
 311     DECLARE_NO_COPY_CLASS(wxGenericTreeItem
) 
 314 // ============================================================================= 
 316 // ============================================================================= 
 318 // ---------------------------------------------------------------------------- 
 320 // ---------------------------------------------------------------------------- 
 322 // translate the key or mouse event flags to the type of selection we're 
 324 static void EventFlagsToSelType(long style
, 
 328                                 bool &extended_select
, 
 329                                 bool &unselect_others
) 
 331     is_multiple 
= (style 
& wxTR_MULTIPLE
) != 0; 
 332     extended_select 
= shiftDown 
&& is_multiple
; 
 333     unselect_others 
= !(extended_select 
|| (ctrlDown 
&& is_multiple
)); 
 336 // check if the given item is under another one 
 337 static bool IsDescendantOf(wxGenericTreeItem 
*parent
, wxGenericTreeItem 
*item
) 
 341         if ( item 
== parent 
) 
 343             // item is a descendant of parent 
 347         item 
= item
->GetParent(); 
 353 // ----------------------------------------------------------------------------- 
 354 // wxTreeRenameTimer (internal) 
 355 // ----------------------------------------------------------------------------- 
 357 wxTreeRenameTimer::wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
) 
 362 void wxTreeRenameTimer::Notify() 
 364     m_owner
->OnRenameTimer(); 
 367 //----------------------------------------------------------------------------- 
 368 // wxTreeTextCtrl (internal) 
 369 //----------------------------------------------------------------------------- 
 371 BEGIN_EVENT_TABLE(wxTreeTextCtrl
,wxTextCtrl
) 
 372     EVT_CHAR           (wxTreeTextCtrl::OnChar
) 
 373     EVT_KEY_UP         (wxTreeTextCtrl::OnKeyUp
) 
 374     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus
) 
 377 wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl 
*owner
, 
 378                                wxGenericTreeItem 
*item
) 
 379               : m_itemEdited(item
), m_startValue(item
->GetText()) 
 384     int w 
= m_itemEdited
->GetWidth(), 
 385         h 
= m_itemEdited
->GetHeight(); 
 388     m_owner
->CalcScrolledPosition(item
->GetX(), item
->GetY(), &x
, &y
); 
 393     int image 
= item
->GetCurrentImage(); 
 394     if ( image 
!= NO_IMAGE 
) 
 396         if ( m_owner
->m_imageListNormal 
) 
 398             m_owner
->m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
 403             wxFAIL_MSG(_T("you must create an image list to use images!")); 
 407     // FIXME: what are all these hardcoded 4, 8 and 11s really? 
 411     (void)Create(m_owner
, wxID_ANY
, m_startValue
, 
 412                  wxPoint(x 
- 4, y 
- 4), wxSize(w 
+ 11, h 
+ 8)); 
 415 bool wxTreeTextCtrl::AcceptChanges() 
 417     const wxString value 
= GetValue(); 
 419     if ( value 
== m_startValue 
) 
 421         // nothing changed, always accept 
 425     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
 427         // vetoed by the user 
 431     // accepted, do rename the item 
 432     m_owner
->SetItemText(m_itemEdited
, value
); 
 437 void wxTreeTextCtrl::Finish() 
 441         m_owner
->ResetTextControl(); 
 443         wxPendingDelete
.Append(this); 
 447         m_owner
->SetFocus(); // This doesn't work. TODO. 
 451 void wxTreeTextCtrl::OnChar( wxKeyEvent 
&event 
) 
 453     switch ( event
.m_keyCode 
) 
 456             if ( !AcceptChanges() ) 
 458                 // vetoed by the user, don't disappear 
 465             m_owner
->OnRenameCancelled(m_itemEdited
); 
 473 void wxTreeTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
 477         // auto-grow the textctrl: 
 478         wxSize parentSize 
= m_owner
->GetSize(); 
 479         wxPoint myPos 
= GetPosition(); 
 480         wxSize mySize 
= GetSize(); 
 482         GetTextExtent(GetValue() + _T("M"), &sx
, &sy
); 
 483         if (myPos
.x 
+ sx 
> parentSize
.x
) 
 484             sx 
= parentSize
.x 
- myPos
.x
; 
 493 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
 501     if ( AcceptChanges() ) 
 507 // ----------------------------------------------------------------------------- 
 509 // ----------------------------------------------------------------------------- 
 511 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 512                                      const wxString
& text
, 
 513                                      int image
, int selImage
, 
 514                                      wxTreeItemData 
*data
) 
 517     m_images
[wxTreeItemIcon_Normal
] = image
; 
 518     m_images
[wxTreeItemIcon_Selected
] = selImage
; 
 519     m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
; 
 520     m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
; 
 525     m_isCollapsed 
= TRUE
; 
 526     m_hasHilight 
= FALSE
; 
 532     m_attr 
= (wxTreeItemAttr 
*)NULL
; 
 535     // We don't know the height here yet. 
 540 wxGenericTreeItem::~wxGenericTreeItem() 
 544     if (m_ownsAttr
) delete m_attr
; 
 546     wxASSERT_MSG( m_children
.IsEmpty(), 
 547                   wxT("please call DeleteChildren() before deleting the item") ); 
 550 void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl 
*tree
) 
 552     size_t count 
= m_children
.Count(); 
 553     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 555         wxGenericTreeItem 
*child 
= m_children
[n
]; 
 557             tree
->SendDeleteEvent(child
); 
 559         child
->DeleteChildren(tree
); 
 566 void wxGenericTreeItem::SetText( const wxString 
&text 
) 
 571 size_t wxGenericTreeItem::GetChildrenCount(bool recursively
) const 
 573     size_t count 
= m_children
.Count(); 
 577     size_t total 
= count
; 
 578     for (size_t n 
= 0; n 
< count
; ++n
) 
 580         total 
+= m_children
[n
]->GetChildrenCount(); 
 586 void wxGenericTreeItem::GetSize( int &x
, int &y
, 
 587                                  const wxGenericTreeCtrl 
*theButton 
) 
 589     int bottomY
=m_y
+theButton
->GetLineHeight(this); 
 590     if ( y 
< bottomY 
) y 
= bottomY
; 
 591     int width 
= m_x 
+  m_width
; 
 592     if ( x 
< width 
) x 
= width
; 
 596         size_t count 
= m_children
.Count(); 
 597         for ( size_t n 
= 0; n 
< count
; ++n 
) 
 599             m_children
[n
]->GetSize( x
, y
, theButton 
); 
 604 wxGenericTreeItem 
*wxGenericTreeItem::HitTest(const wxPoint
& point
, 
 605                                               const wxGenericTreeCtrl 
*theCtrl
, 
 609     // for a hidden root node, don't evaluate it, but do evaluate children 
 610     if ( !(level 
== 0 && theCtrl
->HasFlag(wxTR_HIDE_ROOT
)) ) 
 613         int h 
= theCtrl
->GetLineHeight(this); 
 614         if ((point
.y 
> m_y
) && (point
.y 
< m_y 
+ h
)) 
 616             int y_mid 
= m_y 
+ h
/2; 
 617             if (point
.y 
< y_mid 
) 
 618                 flags 
|= wxTREE_HITTEST_ONITEMUPPERPART
; 
 620                 flags 
|= wxTREE_HITTEST_ONITEMLOWERPART
; 
 622             // 5 is the size of the plus sign 
 623             int xCross 
= m_x 
- theCtrl
->GetSpacing(); 
 624             if ((point
.x 
> xCross
-5) && (point
.x 
< xCross
+5) && 
 625                 (point
.y 
> y_mid
-5) && (point
.y 
< y_mid
+5) && 
 626                 HasPlus() && theCtrl
->HasButtons() ) 
 628                 flags 
|= wxTREE_HITTEST_ONITEMBUTTON
; 
 632             if ((point
.x 
>= m_x
) && (point
.x 
<= m_x
+m_width
)) 
 637                 // assuming every image (normal and selected) has the same size! 
 638                 if ( (GetImage() != NO_IMAGE
) && theCtrl
->m_imageListNormal 
) 
 639                     theCtrl
->m_imageListNormal
->GetSize(GetImage(), 
 642                 if ((image_w 
!= -1) && (point
.x 
<= m_x 
+ image_w 
+ 1)) 
 643                     flags 
|= wxTREE_HITTEST_ONITEMICON
; 
 645                     flags 
|= wxTREE_HITTEST_ONITEMLABEL
; 
 651                 flags 
|= wxTREE_HITTEST_ONITEMINDENT
; 
 652             if (point
.x 
> m_x
+m_width
) 
 653                 flags 
|= wxTREE_HITTEST_ONITEMRIGHT
; 
 658         // if children are expanded, fall through to evaluate them 
 659         if (m_isCollapsed
) return (wxGenericTreeItem
*) NULL
; 
 663     size_t count 
= m_children
.Count(); 
 664     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 666         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, 
 674     return (wxGenericTreeItem
*) NULL
; 
 677 int wxGenericTreeItem::GetCurrentImage() const 
 679     int image 
= NO_IMAGE
; 
 684             image 
= GetImage(wxTreeItemIcon_SelectedExpanded
); 
 687         if ( image 
== NO_IMAGE 
) 
 689             // we usually fall back to the normal item, but try just the 
 690             // expanded one (and not selected) first in this case 
 691             image 
= GetImage(wxTreeItemIcon_Expanded
); 
 697             image 
= GetImage(wxTreeItemIcon_Selected
); 
 700     // maybe it doesn't have the specific image we want, 
 701     // try the default one instead 
 702     if ( image 
== NO_IMAGE 
) image 
= GetImage(); 
 707 // ----------------------------------------------------------------------------- 
 708 // wxGenericTreeCtrl implementation 
 709 // ----------------------------------------------------------------------------- 
 711 IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl
, wxScrolledWindow
) 
 713 BEGIN_EVENT_TABLE(wxGenericTreeCtrl
,wxScrolledWindow
) 
 714     EVT_PAINT          (wxGenericTreeCtrl::OnPaint
) 
 715     EVT_MOUSE_EVENTS   (wxGenericTreeCtrl::OnMouse
) 
 716     EVT_CHAR           (wxGenericTreeCtrl::OnChar
) 
 717     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus
) 
 718     EVT_KILL_FOCUS     (wxGenericTreeCtrl::OnKillFocus
) 
 719     EVT_IDLE           (wxGenericTreeCtrl::OnIdle
) 
 722 #if !defined(__WXMSW__) || defined(__WIN16__) || defined(__WXUNIVERSAL__) 
 724  * wxTreeCtrl has to be a real class or we have problems with 
 725  * the run-time information. 
 728 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxGenericTreeCtrl
) 
 731 // ----------------------------------------------------------------------------- 
 732 // construction/destruction 
 733 // ----------------------------------------------------------------------------- 
 735 void wxGenericTreeCtrl::Init() 
 737     m_current 
= m_key_current 
= m_anchor 
= (wxGenericTreeItem 
*) NULL
; 
 745     m_hilightBrush 
= new wxBrush
 
 747                             wxSystemSettings::GetColour
 
 749                                 wxSYS_COLOUR_HIGHLIGHT
 
 754     m_hilightUnfocusedBrush 
= new wxBrush
 
 756                                  wxSystemSettings::GetColour
 
 758                                      wxSYS_COLOUR_BTNSHADOW
 
 763     m_imageListNormal 
= m_imageListButtons 
= 
 764     m_imageListState 
= (wxImageList 
*) NULL
; 
 765     m_ownsImageListNormal 
= m_ownsImageListButtons 
= 
 766     m_ownsImageListState 
= FALSE
; 
 769     m_isDragging 
= FALSE
; 
 770     m_dropTarget 
= m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
 773     m_renameTimer 
= NULL
; 
 776     m_lastOnSame 
= FALSE
; 
 778     m_normalFont 
= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT 
); 
 779     m_boldFont 
= wxFont(m_normalFont
.GetPointSize(), 
 780                         m_normalFont
.GetFamily(), 
 781                         m_normalFont
.GetStyle(), 
 783                         m_normalFont
.GetUnderlined(), 
 784                         m_normalFont
.GetFaceName(), 
 785                         m_normalFont
.GetEncoding()); 
 788 bool wxGenericTreeCtrl::Create(wxWindow 
*parent
, 
 793                                const wxValidator 
&validator
, 
 794                                const wxString
& name 
) 
 798     wxGetOsVersion( &major
, &minor 
); 
 800     if (style 
& wxTR_HAS_BUTTONS
) style 
|= wxTR_MAC_BUTTONS
; 
 801     if (style 
& wxTR_HAS_BUTTONS
) style 
&= ~wxTR_HAS_BUTTONS
; 
 802     style 
&= ~wxTR_LINES_AT_ROOT
; 
 803     style 
|= wxTR_NO_LINES
; 
 805         style 
|= wxTR_ROW_LINES
; 
 807         style 
|= wxTR_AQUA_BUTTONS
; 
 810     if (style 
& wxTR_AQUA_BUTTONS
) 
 812         m_arrowRight 
= new wxBitmap( aqua_arrow_right 
); 
 813         m_arrowDown 
= new wxBitmap( aqua_arrow_down 
); 
 821     wxScrolledWindow::Create( parent
, id
, pos
, size
, 
 822                               style
|wxHSCROLL
|wxVSCROLL
, name 
); 
 824     // If the tree display has no buttons, but does have 
 825     // connecting lines, we can use a narrower layout. 
 826     // It may not be a good idea to force this... 
 827     if (!HasButtons() && !HasFlag(wxTR_NO_LINES
)) 
 834     SetValidator( validator 
); 
 837     SetForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
) ); 
 838     SetBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
) ); 
 840 //  m_dottedPen = wxPen( "grey", 0, wxDOT );  too slow under XFree86 
 841     m_dottedPen 
= wxPen( wxT("grey"), 0, 0 ); 
 846 wxGenericTreeCtrl::~wxGenericTreeCtrl() 
 848     delete m_hilightBrush
; 
 849     delete m_hilightUnfocusedBrush
; 
 856     delete m_renameTimer
; 
 859     if (m_ownsImageListNormal
) 
 860         delete m_imageListNormal
; 
 861     if (m_ownsImageListState
) 
 862         delete m_imageListState
; 
 863     if (m_ownsImageListButtons
) 
 864         delete m_imageListButtons
; 
 867 // ----------------------------------------------------------------------------- 
 869 // ----------------------------------------------------------------------------- 
 871 size_t wxGenericTreeCtrl::GetCount() const 
 873     return m_anchor 
== NULL 
? 0u : m_anchor
->GetChildrenCount(); 
 876 void wxGenericTreeCtrl::SetIndent(unsigned int indent
) 
 878     m_indent 
= (unsigned short) indent
; 
 882 void wxGenericTreeCtrl::SetSpacing(unsigned int spacing
) 
 884     m_spacing 
= (unsigned short) spacing
; 
 888 size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
) 
 890     wxCHECK_MSG( item
.IsOk(), 0u, wxT("invalid tree item") ); 
 892     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildrenCount(recursively
); 
 895 void wxGenericTreeCtrl::SetWindowStyle(const long styles
) 
 897     if (!HasFlag(wxTR_HIDE_ROOT
) && (styles 
& wxTR_HIDE_ROOT
)) 
 899         // if we will hide the root, make sure children are visible 
 900         m_anchor
->SetHasPlus(); 
 902         CalculatePositions(); 
 905     // right now, just sets the styles.  Eventually, we may 
 906     // want to update the inherited styles, but right now 
 907     // none of the parents has updatable styles 
 908     m_windowStyle 
= styles
; 
 912 // ----------------------------------------------------------------------------- 
 913 // functions to work with tree items 
 914 // ----------------------------------------------------------------------------- 
 916 wxString 
wxGenericTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 918     wxCHECK_MSG( item
.IsOk(), wxT(""), wxT("invalid tree item") ); 
 920     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetText(); 
 923 int wxGenericTreeCtrl::GetItemImage(const wxTreeItemId
& item
, 
 924                              wxTreeItemIcon which
) const 
 926     wxCHECK_MSG( item
.IsOk(), -1, wxT("invalid tree item") ); 
 928     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetImage(which
); 
 931 wxTreeItemData 
*wxGenericTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 933     wxCHECK_MSG( item
.IsOk(), NULL
, wxT("invalid tree item") ); 
 935     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetData(); 
 938 wxColour 
wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId
& item
) const 
 940     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
 942     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 943     return pItem
->Attr().GetTextColour(); 
 946 wxColour 
wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId
& item
) const 
 948     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
 950     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 951     return pItem
->Attr().GetBackgroundColour(); 
 954 wxFont 
wxGenericTreeCtrl::GetItemFont(const wxTreeItemId
& item
) const 
 956     wxCHECK_MSG( item
.IsOk(), wxNullFont
, wxT("invalid tree item") ); 
 958     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 959     return pItem
->Attr().GetFont(); 
 962 void wxGenericTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 964     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 967     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 968     pItem
->SetText(text
); 
 969     CalculateSize(pItem
, dc
); 
 973 void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId
& item
, 
 975                               wxTreeItemIcon which
) 
 977     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 979     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 980     pItem
->SetImage(image
, which
); 
 983     CalculateSize(pItem
, dc
); 
 987 void wxGenericTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 989     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 991     ((wxGenericTreeItem
*) item
.m_pItem
)->SetData(data
); 
 994 void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
 996     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 998     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 999     pItem
->SetHasPlus(has
); 
1003 void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
1005     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1007     // avoid redrawing the tree if no real change 
1008     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1009     if ( pItem
->IsBold() != bold 
) 
1011         pItem
->SetBold(bold
); 
1016 void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId
& item
, 
1017                                    const wxColour
& col
) 
1019     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1021     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1022     pItem
->Attr().SetTextColour(col
); 
1026 void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
, 
1027                                          const wxColour
& col
) 
1029     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1031     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1032     pItem
->Attr().SetBackgroundColour(col
); 
1036 void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
) 
1038     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1040     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1041     pItem
->Attr().SetFont(font
); 
1045 bool wxGenericTreeCtrl::SetFont( const wxFont 
&font 
) 
1047     wxScrolledWindow::SetFont(font
); 
1049     m_normalFont 
= font 
; 
1050     m_boldFont 
= wxFont(m_normalFont
.GetPointSize(), 
1051                         m_normalFont
.GetFamily(), 
1052                         m_normalFont
.GetStyle(), 
1054                         m_normalFont
.GetUnderlined(), 
1055                         m_normalFont
.GetFaceName(), 
1056                         m_normalFont
.GetEncoding()); 
1062 // ----------------------------------------------------------------------------- 
1063 // item status inquiries 
1064 // ----------------------------------------------------------------------------- 
1066 bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId
& item
) const 
1068     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1070     // An item is only visible if it's not a descendant of a collapsed item 
1071     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1072     wxGenericTreeItem
* parent 
= pItem
->GetParent(); 
1075         if (!parent
->IsExpanded()) 
1077         parent 
= parent
->GetParent(); 
1081     GetViewStart(& startX
, & startY
); 
1083     wxSize clientSize 
= GetClientSize(); 
1086     if (!GetBoundingRect(item
, rect
)) 
1088     if (rect
.GetWidth() == 0 || rect
.GetHeight() == 0) 
1090     if (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) 
1092     if (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
) 
1098 bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
1100     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1102     // consider that the item does have children if it has the "+" button: it 
1103     // might not have them (if it had never been expanded yet) but then it 
1104     // could have them as well and it's better to err on this side rather than 
1105     // disabling some operations which are restricted to the items with 
1106     // children for an item which does have them 
1107     return ((wxGenericTreeItem
*) item
.m_pItem
)->HasPlus(); 
1110 bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
1112     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1114     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsExpanded(); 
1117 bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
1119     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1121     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsSelected(); 
1124 bool wxGenericTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
1126     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1128     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsBold(); 
1131 // ----------------------------------------------------------------------------- 
1133 // ----------------------------------------------------------------------------- 
1135 wxTreeItemId 
wxGenericTreeCtrl::GetItemParent(const wxTreeItemId
& item
) const 
1137     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1139     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetParent(); 
1142 wxTreeItemId 
wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const 
1144     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1147     return GetNextChild(item
, cookie
); 
1150 wxTreeItemId 
wxGenericTreeCtrl::GetNextChild(const wxTreeItemId
& item
, long& cookie
) const 
1152     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1154     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1155     if ( (size_t)cookie 
< children
.Count() ) 
1157         return children
.Item((size_t)cookie
++); 
1161         // there are no more of them 
1162         return wxTreeItemId(); 
1166 wxTreeItemId 
wxGenericTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
1168     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1170     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1171     return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
1174 wxTreeItemId 
wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
1176     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1178     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1179     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1180     if ( parent 
== NULL 
) 
1182         // root item doesn't have any siblings 
1183         return wxTreeItemId(); 
1186     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1187     int index 
= siblings
.Index(i
); 
1188     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1190     size_t n 
= (size_t)(index 
+ 1); 
1191     return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
1194 wxTreeItemId 
wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
1196     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1198     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1199     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1200     if ( parent 
== NULL 
) 
1202         // root item doesn't have any siblings 
1203         return wxTreeItemId(); 
1206     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1207     int index 
= siblings
.Index(i
); 
1208     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1210     return index 
== 0 ? wxTreeItemId() 
1211                       : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
1214 // Only for internal use right now, but should probably be public 
1215 wxTreeItemId 
wxGenericTreeCtrl::GetNext(const wxTreeItemId
& item
) const 
1217     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1219     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1221     // First see if there are any children. 
1222     wxArrayGenericTreeItems
& children 
= i
->GetChildren(); 
1223     if (children
.GetCount() > 0) 
1225          return children
.Item(0); 
1229          // Try a sibling of this or ancestor instead 
1230          wxTreeItemId p 
= item
; 
1231          wxTreeItemId toFind
; 
1234               toFind 
= GetNextSibling(p
); 
1235               p 
= GetItemParent(p
); 
1236          } while (p
.IsOk() && !toFind
.IsOk()); 
1241 wxTreeItemId 
wxGenericTreeCtrl::GetFirstVisibleItem() const 
1243     wxTreeItemId id 
= GetRootItem(); 
1252     } while (id
.IsOk()); 
1254     return wxTreeItemId(); 
1257 wxTreeItemId 
wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
1259     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1261     wxTreeItemId id 
= item
; 
1264         while (id 
= GetNext(id
), id
.IsOk()) 
1270     return wxTreeItemId(); 
1273 wxTreeItemId 
wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
1275     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1277     wxFAIL_MSG(wxT("not implemented")); 
1279     return wxTreeItemId(); 
1282 // called by wxTextTreeCtrl when it marks itself for deletion 
1283 void wxGenericTreeCtrl::ResetTextControl() 
1288 // find the first item starting with the given prefix after the given item 
1289 wxTreeItemId 
wxGenericTreeCtrl::FindItem(const wxTreeItemId
& idParent
, 
1290                                          const wxString
& prefixOrig
) const 
1292     // match is case insensitive as this is more convenient to the user: having 
1293     // to press Shift-letter to go to the item starting with a capital letter 
1294     // would be too bothersome 
1295     wxString prefix 
= prefixOrig
.Lower(); 
1297     // determine the starting point: we shouldn't take the current item (this 
1298     // allows to switch between two items starting with the same letter just by 
1299     // pressing it) but we shouldn't jump to the next one if the user is 
1300     // continuing to type as otherwise he might easily skip the item he wanted 
1301     wxTreeItemId id 
= idParent
; 
1302     if ( prefix
.length() == 1 ) 
1307     // look for the item starting with the given prefix after it 
1308     while ( id
.IsOk() && !GetItemText(id
).Lower().StartsWith(prefix
) ) 
1313     // if we haven't found anything... 
1316         // ... wrap to the beginning 
1318         if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1320             // can't select virtual root 
1324         // and try all the items (stop when we get to the one we started from) 
1325         while ( id 
!= idParent 
&& !GetItemText(id
).Lower().StartsWith(prefix
) ) 
1334 // ----------------------------------------------------------------------------- 
1336 // ----------------------------------------------------------------------------- 
1338 wxTreeItemId 
wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
1340                                       const wxString
& text
, 
1341                                       int image
, int selImage
, 
1342                                       wxTreeItemData 
*data
) 
1344     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1347         // should we give a warning here? 
1348         return AddRoot(text
, image
, selImage
, data
); 
1351     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1353     wxGenericTreeItem 
*item 
= 
1354         new wxGenericTreeItem( parent
, text
, image
, selImage
, data 
); 
1358         data
->m_pItem 
= (long) item
; 
1361     parent
->Insert( item
, previous 
); 
1366 wxTreeItemId 
wxGenericTreeCtrl::AddRoot(const wxString
& text
, 
1367                                  int image
, int selImage
, 
1368                                  wxTreeItemData 
*data
) 
1370     wxCHECK_MSG( !m_anchor
, wxTreeItemId(), wxT("tree can have only one root") ); 
1372     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1374     m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, 
1375                                    image
, selImage
, data
); 
1378         data
->m_pItem 
= (long) m_anchor
; 
1381     if (HasFlag(wxTR_HIDE_ROOT
)) 
1383         // if root is hidden, make sure we can navigate 
1385         m_anchor
->SetHasPlus(); 
1387         CalculatePositions(); 
1390     if (!HasFlag(wxTR_MULTIPLE
)) 
1392         m_current 
= m_key_current 
= m_anchor
; 
1393         m_current
->SetHilight( TRUE 
); 
1399 wxTreeItemId 
wxGenericTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
1400                                      const wxString
& text
, 
1401                                      int image
, int selImage
, 
1402                                      wxTreeItemData 
*data
) 
1404     return DoInsertItem(parent
, 0u, text
, image
, selImage
, data
); 
1407 wxTreeItemId 
wxGenericTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
1408                                     const wxTreeItemId
& idPrevious
, 
1409                                     const wxString
& text
, 
1410                                     int image
, int selImage
, 
1411                                     wxTreeItemData 
*data
) 
1413     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1416         // should we give a warning here? 
1417         return AddRoot(text
, image
, selImage
, data
); 
1421     if (idPrevious
.IsOk()) 
1423         index 
= parent
->GetChildren().Index((wxGenericTreeItem
*) idPrevious
.m_pItem
); 
1424         wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
1425                       wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") ); 
1428     return DoInsertItem(parentId
, (size_t)++index
, text
, image
, selImage
, data
); 
1431 wxTreeItemId 
wxGenericTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
1433                                     const wxString
& text
, 
1434                                     int image
, int selImage
, 
1435                                     wxTreeItemData 
*data
) 
1437     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1440         // should we give a warning here? 
1441         return AddRoot(text
, image
, selImage
, data
); 
1444     return DoInsertItem(parentId
, before
, text
, image
, selImage
, data
); 
1447 wxTreeItemId 
wxGenericTreeCtrl::AppendItem(const wxTreeItemId
& parentId
, 
1448                                     const wxString
& text
, 
1449                                     int image
, int selImage
, 
1450                                     wxTreeItemData 
*data
) 
1452     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1455         // should we give a warning here? 
1456         return AddRoot(text
, image
, selImage
, data
); 
1459     return DoInsertItem( parent
, parent
->GetChildren().Count(), text
, 
1460                          image
, selImage
, data
); 
1463 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
1465     wxTreeEvent 
event( wxEVT_COMMAND_TREE_DELETE_ITEM
, GetId() ); 
1466     event
.m_item 
= (long) item
; 
1467     event
.SetEventObject( this ); 
1468     ProcessEvent( event 
); 
1471 void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
1473     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1475     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1476     item
->DeleteChildren(this); 
1479 void wxGenericTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
1481     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1483     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1485     wxGenericTreeItem 
*parent 
= item
->GetParent(); 
1487     // don't keep stale pointers around! 
1488     if ( IsDescendantOf(item
, m_key_current
) ) 
1490         m_key_current 
= parent
; 
1493     if ( IsDescendantOf(item
, m_current
) ) 
1498     // remove the item from the tree 
1501         parent
->GetChildren().Remove( item 
);  // remove by value 
1503     else // deleting the root 
1505         // nothing will be left in the tree 
1509     // and delete all of its children and the item itself now 
1510     item
->DeleteChildren(this); 
1511     SendDeleteEvent(item
); 
1515 void wxGenericTreeCtrl::DeleteAllItems() 
1523 void wxGenericTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
1525     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1527     wxCHECK_RET( item
, _T("invalid item in wxGenericTreeCtrl::Expand") ); 
1528     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1529                  _T("can't expand hidden root") ); 
1531     if ( !item
->HasPlus() ) 
1534     if ( item
->IsExpanded() ) 
1537     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
1538     event
.m_item 
= (long) item
; 
1539     event
.SetEventObject( this ); 
1541     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1543         // cancelled by program 
1548     CalculatePositions(); 
1550     RefreshSubtree(item
); 
1552     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
1553     ProcessEvent( event 
); 
1556 void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId
& item
) 
1558     if ( !HasFlag(wxTR_HIDE_ROOT
) || item 
!= GetRootItem()) 
1561         if ( !IsExpanded(item
) ) 
1566     wxTreeItemId child 
= GetFirstChild(item
, cookie
); 
1567     while ( child
.IsOk() ) 
1571         child 
= GetNextChild(item
, cookie
); 
1575 void wxGenericTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
1577     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1578                  _T("can't collapse hidden root") ); 
1580     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1582     if ( !item
->IsExpanded() ) 
1585     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
1586     event
.m_item 
= (long) item
; 
1587     event
.SetEventObject( this ); 
1588     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1590         // cancelled by program 
1596 #if 0  // TODO why should items be collapsed recursively? 
1597     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1598     size_t count 
= children
.Count(); 
1599     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1601         Collapse(children
[n
]); 
1605     CalculatePositions(); 
1607     RefreshSubtree(item
); 
1609     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
1610     ProcessEvent( event 
); 
1613 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
1616     DeleteChildren(item
); 
1619 void wxGenericTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
1621     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1623     if (item
->IsExpanded()) 
1629 void wxGenericTreeCtrl::Unselect() 
1633         m_current
->SetHilight( FALSE 
); 
1634         RefreshLine( m_current 
); 
1640 void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem 
*item
) 
1642     if (item
->IsSelected()) 
1644         item
->SetHilight(FALSE
); 
1648     if (item
->HasChildren()) 
1650         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1651         size_t count 
= children
.Count(); 
1652         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1654             UnselectAllChildren(children
[n
]); 
1659 void wxGenericTreeCtrl::UnselectAll() 
1661     wxTreeItemId rootItem 
= GetRootItem(); 
1663     // the tree might not have the root item at all 
1666         UnselectAllChildren((wxGenericTreeItem
*) rootItem
.m_pItem
); 
1670 // Recursive function ! 
1671 // To stop we must have crt_item<last_item 
1673 // Tag all next children, when no more children, 
1674 // Move to parent (not to tag) 
1675 // Keep going... if we found last_item, we stop. 
1676 bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1678     wxGenericTreeItem 
*parent 
= crt_item
->GetParent(); 
1680     if (parent 
== NULL
) // This is root item 
1681         return TagAllChildrenUntilLast(crt_item
, last_item
, select
); 
1683     wxArrayGenericTreeItems
& children 
= parent
->GetChildren(); 
1684     int index 
= children
.Index(crt_item
); 
1685     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1687     size_t count 
= children
.Count(); 
1688     for (size_t n
=(size_t)(index
+1); n
<count
; ++n
) 
1690         if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return TRUE
; 
1693     return TagNextChildren(parent
, last_item
, select
); 
1696 bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1698     crt_item
->SetHilight(select
); 
1699     RefreshLine(crt_item
); 
1701     if (crt_item
==last_item
) 
1704     if (crt_item
->HasChildren()) 
1706         wxArrayGenericTreeItems
& children 
= crt_item
->GetChildren(); 
1707         size_t count 
= children
.Count(); 
1708         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1710             if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) 
1718 void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem 
*item1
, wxGenericTreeItem 
*item2
) 
1720     // item2 is not necessary after item1 
1721     wxGenericTreeItem 
*first
=NULL
, *last
=NULL
; 
1723     // choice first' and 'last' between item1 and item2 
1724     if (item1
->GetY()<item2
->GetY()) 
1735     bool select 
= m_current
->IsSelected(); 
1737     if ( TagAllChildrenUntilLast(first
,last
,select
) ) 
1740     TagNextChildren(first
,last
,select
); 
1743 void wxGenericTreeCtrl::SelectItem(const wxTreeItemId
& itemId
, 
1744                                    bool unselect_others
, 
1745                                    bool extended_select
) 
1747     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1749     bool is_single
=!(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1750     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1752     //wxCHECK_RET( ( (!unselect_others) && is_single), 
1753     //           wxT("this is a single selection tree") ); 
1755     // to keep going anyhow !!! 
1758         if (item
->IsSelected()) 
1759             return; // nothing to do 
1760         unselect_others 
= TRUE
; 
1761         extended_select 
= FALSE
; 
1763     else if ( unselect_others 
&& item
->IsSelected() ) 
1765         // selection change if there is more than one item currently selected 
1766         wxArrayTreeItemIds selected_items
; 
1767         if ( GetSelections(selected_items
) == 1 ) 
1771     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
1772     event
.m_item 
= (long) item
; 
1773     event
.m_itemOld 
= (long) m_current
; 
1774     event
.SetEventObject( this ); 
1775     // TODO : Here we don't send any selection mode yet ! 
1777     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
1780     wxTreeItemId parent 
= GetItemParent( itemId 
); 
1781     while (parent
.IsOk()) 
1783         if (!IsExpanded(parent
)) 
1786         parent 
= GetItemParent( parent 
); 
1789     EnsureVisible( itemId 
); 
1792     if (unselect_others
) 
1794         if (is_single
) Unselect(); // to speed up thing 
1799     if (extended_select
) 
1803             m_current 
= m_key_current 
= (wxGenericTreeItem
*) GetRootItem().m_pItem
; 
1806         // don't change the mark (m_current) 
1807         SelectItemRange(m_current
, item
); 
1811         bool select
=TRUE
; // the default 
1813         // Check if we need to toggle hilight (ctrl mode) 
1814         if (!unselect_others
) 
1815             select
=!item
->IsSelected(); 
1817         m_current 
= m_key_current 
= item
; 
1818         m_current
->SetHilight(select
); 
1819         RefreshLine( m_current 
); 
1822     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
1823     GetEventHandler()->ProcessEvent( event 
); 
1826 void wxGenericTreeCtrl::FillArray(wxGenericTreeItem 
*item
, 
1827                                   wxArrayTreeItemIds 
&array
) const 
1829     if ( item
->IsSelected() ) 
1830         array
.Add(wxTreeItemId(item
)); 
1832     if ( item
->HasChildren() ) 
1834         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1835         size_t count 
= children
.GetCount(); 
1836         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1837             FillArray(children
[n
], array
); 
1841 size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds 
&array
) const 
1844     wxTreeItemId idRoot 
= GetRootItem(); 
1845     if ( idRoot
.IsOk() ) 
1847         FillArray((wxGenericTreeItem
*) idRoot
.m_pItem
, array
); 
1849     //else: the tree is empty, so no selections 
1851     return array
.Count(); 
1854 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
1856     if (!item
.IsOk()) return; 
1858     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1860     // first expand all parent branches 
1861     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
1863     if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1865         while ( parent 
!= m_anchor 
) 
1868             parent 
= parent
->GetParent(); 
1876             parent 
= parent
->GetParent(); 
1880     //if (parent) CalculatePositions(); 
1885 void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId 
&item
) 
1887     if (!item
.IsOk()) return; 
1889     // We have to call this here because the label in 
1890     // question might just have been added and no screen 
1891     // update taken place. 
1892     if (m_dirty
) wxYieldIfNeeded(); 
1894     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1896     // now scroll to the item 
1897     int item_y 
= gitem
->GetY(); 
1901     GetViewStart( &start_x
, &start_y 
); 
1902     start_y 
*= PIXELS_PER_UNIT
; 
1906     GetClientSize( &client_w
, &client_h 
); 
1908     if (item_y 
< start_y
+3) 
1913         m_anchor
->GetSize( x
, y
, this ); 
1914         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1915         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1916         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1917         // Item should appear at top 
1918         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, item_y
/PIXELS_PER_UNIT 
); 
1920     else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) 
1925         m_anchor
->GetSize( x
, y
, this ); 
1926         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1927         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1928         item_y 
+= PIXELS_PER_UNIT
+2; 
1929         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1930         // Item should appear at bottom 
1931         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, (item_y
+GetLineHeight(gitem
)-client_h
)/PIXELS_PER_UNIT 
); 
1935 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
1936 static wxGenericTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
1938 static int LINKAGEMODE 
tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
1939                                   wxGenericTreeItem 
**item2
) 
1941     wxCHECK_MSG( s_treeBeingSorted
, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") ); 
1943     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
1946 int wxGenericTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
1947                                const wxTreeItemId
& item2
) 
1949     return wxStrcmp(GetItemText(item1
), GetItemText(item2
)); 
1952 void wxGenericTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
1954     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1956     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1958     wxCHECK_RET( !s_treeBeingSorted
, 
1959                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") ); 
1961     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1962     if ( children
.Count() > 1 ) 
1966         s_treeBeingSorted 
= this; 
1967         children
.Sort(tree_ctrl_compare_func
); 
1968         s_treeBeingSorted 
= NULL
; 
1970     //else: don't make the tree dirty as nothing changed 
1973 wxImageList 
*wxGenericTreeCtrl::GetImageList() const 
1975     return m_imageListNormal
; 
1978 wxImageList 
*wxGenericTreeCtrl::GetButtonsImageList() const 
1980     return m_imageListButtons
; 
1983 wxImageList 
*wxGenericTreeCtrl::GetStateImageList() const 
1985     return m_imageListState
; 
1988 void wxGenericTreeCtrl::CalculateLineHeight() 
1990     wxClientDC 
dc(this); 
1991     m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1993     if ( m_imageListNormal 
) 
1995         // Calculate a m_lineHeight value from the normal Image sizes. 
1996         // May be toggle off. Then wxGenericTreeCtrl will spread when 
1997         // necessary (which might look ugly). 
1998         int n 
= m_imageListNormal
->GetImageCount(); 
1999         for (int i 
= 0; i 
< n 
; i
++) 
2001             int width 
= 0, height 
= 0; 
2002             m_imageListNormal
->GetSize(i
, width
, height
); 
2003             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2007     if (m_imageListButtons
) 
2009         // Calculate a m_lineHeight value from the Button image sizes. 
2010         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2011         // necessary (which might look ugly). 
2012         int n 
= m_imageListButtons
->GetImageCount(); 
2013         for (int i 
= 0; i 
< n 
; i
++) 
2015             int width 
= 0, height 
= 0; 
2016             m_imageListButtons
->GetSize(i
, width
, height
); 
2017             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2021     if (m_lineHeight 
< 30) 
2022         m_lineHeight 
+= 2;                 // at least 2 pixels 
2024         m_lineHeight 
+= m_lineHeight
/10;   // otherwise 10% extra spacing 
2027 void wxGenericTreeCtrl::SetImageList(wxImageList 
*imageList
) 
2029     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
2030     m_imageListNormal 
= imageList
; 
2031     m_ownsImageListNormal 
= FALSE
; 
2033     // Don't do any drawing if we're setting the list to NULL, 
2034     // since we may be in the process of deleting the tree control. 
2036         CalculateLineHeight(); 
2039 void wxGenericTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
2041     if (m_ownsImageListState
) delete m_imageListState
; 
2042     m_imageListState 
= imageList
; 
2043     m_ownsImageListState 
= FALSE
; 
2046 void wxGenericTreeCtrl::SetButtonsImageList(wxImageList 
*imageList
) 
2048     if (m_ownsImageListButtons
) delete m_imageListButtons
; 
2049     m_imageListButtons 
= imageList
; 
2050     m_ownsImageListButtons 
= FALSE
; 
2052     CalculateLineHeight(); 
2055 void wxGenericTreeCtrl::AssignImageList(wxImageList 
*imageList
) 
2057     SetImageList(imageList
); 
2058     m_ownsImageListNormal 
= TRUE
; 
2061 void wxGenericTreeCtrl::AssignStateImageList(wxImageList 
*imageList
) 
2063     SetStateImageList(imageList
); 
2064     m_ownsImageListState 
= TRUE
; 
2067 void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList 
*imageList
) 
2069     SetButtonsImageList(imageList
); 
2070     m_ownsImageListButtons 
= TRUE
; 
2073 // ----------------------------------------------------------------------------- 
2075 // ----------------------------------------------------------------------------- 
2077 void wxGenericTreeCtrl::AdjustMyScrollbars() 
2082         m_anchor
->GetSize( x
, y
, this ); 
2083         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2084         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2085         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2086         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
2087         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, y_pos 
); 
2091         SetScrollbars( 0, 0, 0, 0 ); 
2095 int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem 
*item
) const 
2097     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
2098         return item
->GetHeight(); 
2100         return m_lineHeight
; 
2103 void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
2105     // TODO implement "state" icon on items 
2107     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2108     if ( attr 
&& attr
->HasFont() ) 
2109         dc
.SetFont(attr
->GetFont()); 
2110     else if (item
->IsBold()) 
2111         dc
.SetFont(m_boldFont
); 
2113     long text_w 
= 0, text_h 
= 0; 
2114     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
2116     int image_h 
= 0, image_w 
= 0; 
2117     int image 
= item
->GetCurrentImage(); 
2118     if ( image 
!= NO_IMAGE 
) 
2120         if ( m_imageListNormal 
) 
2122             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
2131     int total_h 
= GetLineHeight(item
); 
2133     if ( item
->IsSelected() ) 
2135 // under mac selections are only a rectangle in case they don't have the focus 
2139             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
) ; 
2140             dc
.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT 
) , 1 , wxSOLID 
) ) ; 
2144             dc
.SetBrush( *m_hilightBrush 
) ; 
2147         dc
.SetBrush(*(m_hasFocus 
? m_hilightBrush 
: m_hilightUnfocusedBrush
)); 
2153         if ( attr 
&& attr
->HasBackgroundColour() ) 
2154             colBg 
= attr
->GetBackgroundColour(); 
2156             colBg 
= m_backgroundColour
; 
2157         dc
.SetBrush(wxBrush(colBg
, wxSOLID
)); 
2160     int offset 
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0; 
2162     if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT
) ) 
2166         DoGetPosition(&x
, &y
); 
2168         dc
.DrawRectangle(x
, item
->GetY()+offset
, w
, total_h
-offset
); 
2172         if ( item
->IsSelected() && image 
!= NO_IMAGE 
) 
2174             // If it's selected, and there's an image, then we should 
2175             // take care to leave the area under the image painted in the 
2176             // background colour. 
2177             dc
.DrawRectangle( item
->GetX() + image_w 
- 2, item
->GetY()+offset
, 
2178                               item
->GetWidth() - image_w 
+ 2, total_h
-offset 
); 
2182             dc
.DrawRectangle( item
->GetX()-2, item
->GetY()+offset
, 
2183                               item
->GetWidth()+2, total_h
-offset 
); 
2187     if ( image 
!= NO_IMAGE 
) 
2189         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
2190         m_imageListNormal
->Draw( image
, dc
, 
2192                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
2193                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
2194         dc
.DestroyClippingRegion(); 
2197     dc
.SetBackgroundMode(wxTRANSPARENT
); 
2198     int extraH 
= (total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0; 
2199     dc
.DrawText( item
->GetText(), 
2200                  (wxCoord
)(image_w 
+ item
->GetX()), 
2201                  (wxCoord
)(item
->GetY() + extraH
)); 
2203     // restore normal font 
2204     dc
.SetFont( m_normalFont 
); 
2207 // Now y stands for the top of the item, whereas it used to stand for middle ! 
2208 void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
2210     int x 
= level
*m_indent
; 
2211     if (!HasFlag(wxTR_HIDE_ROOT
)) 
2215     else if (level 
== 0) 
2217         // always expand hidden root 
2219         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2220         int count 
= children
.Count(); 
2226                 PaintLevel(children
[n
], dc
, 1, y
); 
2227             } while (++n 
< count
); 
2229             if (!HasFlag(wxTR_NO_LINES
) && HasFlag(wxTR_LINES_AT_ROOT
) && count 
> 0) 
2231                 // draw line down to last child 
2232                 origY 
+= GetLineHeight(children
[0])>>1; 
2233                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2234                 dc
.DrawLine(3, origY
, 3, oldY
); 
2240     item
->SetX(x
+m_spacing
); 
2243     int h 
= GetLineHeight(item
); 
2245     int y_mid 
= y_top 
+ (h
>>1); 
2248     int exposed_x 
= dc
.LogicalToDeviceX(0); 
2249     int exposed_y 
= dc
.LogicalToDeviceY(y_top
); 
2251     if (IsExposed(exposed_x
, exposed_y
, 10000, h
))  // 10000 = very much 
2255             // don't draw rect outline if we already have the 
2256             // background color under Mac 
2257             (item
->IsSelected() && m_hasFocus
) ? wxBLACK_PEN 
: 
2258 #endif // !__WXMAC__ 
2262         if ( item
->IsSelected() ) 
2264             colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
2268             wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2269             if (attr 
&& attr
->HasTextColour()) 
2270                 colText 
= attr
->GetTextColour(); 
2272                 colText 
= GetForegroundColour(); 
2276         dc
.SetTextForeground(colText
); 
2280         PaintItem(item
, dc
); 
2282         if (HasFlag(wxTR_ROW_LINES
)) 
2284             // if the background colour is white, choose a 
2285             // contrasting color for the lines 
2286             dc
.SetPen(*((GetBackgroundColour() == *wxWHITE
) 
2287                          ? wxMEDIUM_GREY_PEN 
: wxWHITE_PEN
)); 
2288             dc
.DrawLine(0, y_top
, 10000, y_top
); 
2289             dc
.DrawLine(0, y
, 10000, y
); 
2292         // restore DC objects 
2293         dc
.SetBrush(*wxWHITE_BRUSH
); 
2294         dc
.SetPen(m_dottedPen
); 
2295         dc
.SetTextForeground(*wxBLACK
); 
2297         if (item
->HasPlus() && HasButtons())  // should the item show a button? 
2299             if (!HasFlag(wxTR_NO_LINES
)) 
2301                 if (x 
> (signed)m_indent
) 
2302                     dc
.DrawLine(x 
- m_indent
, y_mid
, x 
- 5, y_mid
); 
2303                 else if (HasFlag(wxTR_LINES_AT_ROOT
)) 
2304                     dc
.DrawLine(3, y_mid
, x 
- 5, y_mid
); 
2305                 dc
.DrawLine(x 
+ 5, y_mid
, x 
+ m_spacing
, y_mid
); 
2308             if (m_imageListButtons 
!= NULL
) 
2310                 // draw the image button here 
2311                 int image_h 
= 0, image_w 
= 0, image 
= wxTreeItemIcon_Normal
; 
2312                 if (item
->IsExpanded()) image 
= wxTreeItemIcon_Expanded
; 
2313                 if (item
->IsSelected()) 
2314                     image 
+= wxTreeItemIcon_Selected 
- wxTreeItemIcon_Normal
; 
2315                 m_imageListButtons
->GetSize(image
, image_w
, image_h
); 
2316                 int xx 
= x 
- (image_w
>>1); 
2317                 int yy 
= y_mid 
- (image_h
>>1); 
2318                 dc
.SetClippingRegion(xx
, yy
, image_w
, image_h
); 
2319                 m_imageListButtons
->Draw(image
, dc
, xx
, yy
, 
2320                                          wxIMAGELIST_DRAW_TRANSPARENT
); 
2321                 dc
.DestroyClippingRegion(); 
2323             else if (HasFlag(wxTR_TWIST_BUTTONS
)) 
2325                 // draw the twisty button here 
2327                 if (HasFlag(wxTR_AQUA_BUTTONS
)) 
2329                     // This causes update problems, so disabling for now. 
2330 #if 0 // def __WXMAC__ 
2331                     wxMacPortSetter 
helper(&dc
) ; 
2332                     wxMacWindowClipper 
clipper(this) ; 
2333                     wxDC::MacSetupBackgroundForCurrentPort( MacGetBackgroundBrush() ) ; 
2336                     int loc_y 
= y_mid 
- 6 ; 
2337                     MacWindowToRootWindow( & loc_x 
, & loc_y 
) ; 
2338                     Rect bounds 
= { loc_y 
, loc_x 
, loc_y 
+ 18 , loc_x 
+ 12 } ; 
2339                     ThemeButtonDrawInfo info 
= { kThemeStateActive 
, item
->IsExpanded() ? kThemeDisclosureDown 
: kThemeDisclosureRight 
, 
2340                         kThemeAdornmentNone 
};  
2341                     DrawThemeButton( &bounds
, kThemeDisclosureButton 
,  
2342                         &info 
, NULL 
, NULL 
, NULL 
, NULL 
) ; 
2344                     if (item
->IsExpanded()) 
2345                         dc
.DrawBitmap( *m_arrowDown
, x
-5, y_mid
-6, TRUE 
); 
2347                         dc
.DrawBitmap( *m_arrowRight
, x
-5, y_mid
-6, TRUE 
); 
2352                     dc
.SetBrush(*m_hilightBrush
); 
2353                     dc
.SetPen(*wxBLACK_PEN
); 
2356                     if (item
->IsExpanded()) 
2359                         button
[0].y 
= y_mid
-2; 
2361                         button
[1].y 
= y_mid
-2; 
2363                         button
[2].y 
= y_mid
+3; 
2367                         button
[0].y 
= y_mid
-5; 
2369                         button
[1].y 
= y_mid
+5; 
2371                         button
[2].y 
= y_mid
; 
2374                     dc
.DrawPolygon(3, button
); 
2375                     dc
.SetPen(m_dottedPen
); 
2378             else // if (HasFlag(wxTR_HAS_BUTTONS)) 
2380                 // draw the plus sign here 
2381                 dc
.SetPen(*wxGREY_PEN
); 
2382                 dc
.SetBrush(*wxWHITE_BRUSH
); 
2383                 dc
.DrawRectangle(x
-5, y_mid
-4, 11, 9); 
2384                 dc
.SetPen(*wxBLACK_PEN
); 
2385                 dc
.DrawLine(x
-2, y_mid
, x
+3, y_mid
); 
2386                 if (!item
->IsExpanded()) 
2387                     dc
.DrawLine(x
, y_mid
-2, x
, y_mid
+3); 
2388                 dc
.SetPen(m_dottedPen
); 
2391         else if (!HasFlag(wxTR_NO_LINES
))  // no button; maybe a line? 
2393             // draw the horizontal line here 
2395             if (x 
> (signed)m_indent
) 
2396                 x_start 
-= m_indent
; 
2397             else if (HasFlag(wxTR_LINES_AT_ROOT
)) 
2399             dc
.DrawLine(x_start
, y_mid
, x 
+ m_spacing
, y_mid
); 
2403     if (item
->IsExpanded()) 
2405         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2406         int count 
= children
.Count(); 
2413                 PaintLevel(children
[n
], dc
, level
, y
); 
2414             } while (++n 
< count
); 
2416             if (!HasFlag(wxTR_NO_LINES
) && count 
> 0) 
2418                 // draw line down to last child 
2419                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2420                 if (HasButtons()) y_mid 
+= 5; 
2422                 // Only draw the portion of the line that is visible, in case it is huge 
2423                 wxCoord xOrigin
=0, yOrigin
=0, width
, height
; 
2424                 dc
.GetDeviceOrigin(&xOrigin
, &yOrigin
); 
2425                 yOrigin 
= abs(yOrigin
); 
2426                 GetClientSize(&width
, &height
); 
2428                 // Move end points to the begining/end of the view? 
2429                 if (y_mid 
< yOrigin
) 
2431                 if (oldY 
> yOrigin 
+ height
) 
2432                     oldY 
= yOrigin 
+ height
; 
2434                 // after the adjustments if y_mid is larger than oldY then the line 
2435                 // isn't visible at all so don't draw anything 
2437                     dc
.DrawLine(x
, y_mid
, x
, oldY
); 
2443 void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem 
*item
) 
2447         if ( item
->HasPlus() ) 
2449             // it's a folder, indicate it by a border 
2454             // draw a line under the drop target because the item will be 
2456             DrawLine(item
, TRUE 
/* below */); 
2459         SetCursor(wxCURSOR_BULLSEYE
); 
2464         SetCursor(wxCURSOR_NO_ENTRY
); 
2468 void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId 
&item
) 
2470     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2472     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2474     wxClientDC 
dc(this); 
2476     dc
.SetLogicalFunction(wxINVERT
); 
2477     dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
2479     int w 
= i
->GetWidth() + 2; 
2480     int h 
= GetLineHeight(i
) + 2; 
2482     dc
.DrawRectangle( i
->GetX() - 1, i
->GetY() - 1, w
, h
); 
2485 void wxGenericTreeCtrl::DrawLine(const wxTreeItemId 
&item
, bool below
) 
2487     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2489     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2491     wxClientDC 
dc(this); 
2493     dc
.SetLogicalFunction(wxINVERT
); 
2499         y 
+= GetLineHeight(i
) - 1; 
2502     dc
.DrawLine( x
, y
, x 
+ i
->GetWidth(), y
); 
2505 // ----------------------------------------------------------------------------- 
2506 // wxWindows callbacks 
2507 // ----------------------------------------------------------------------------- 
2509 void wxGenericTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2517     dc
.SetFont( m_normalFont 
); 
2518     dc
.SetPen( m_dottedPen 
); 
2520     // this is now done dynamically 
2521     //if(GetImageList() == NULL) 
2522     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
2525     PaintLevel( m_anchor
, dc
, 0, y 
); 
2528 void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent 
&event 
) 
2537 void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2546 void wxGenericTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
2548     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
2549     te
.m_evtKey 
= event
; 
2550     te
.SetEventObject( this ); 
2551     if ( GetEventHandler()->ProcessEvent( te 
) ) 
2553         // intercepted by the user code 
2557     if ( (m_current 
== 0) || (m_key_current 
== 0) ) 
2563     // how should the selection work for this event? 
2564     bool is_multiple
, extended_select
, unselect_others
; 
2565     EventFlagsToSelType(GetWindowStyleFlag(), 
2567                         event
.ControlDown(), 
2568                         is_multiple
, extended_select
, unselect_others
); 
2572     // * : Expand all/Collapse all 
2573     // ' ' | return : activate 
2574     // up    : go up (not last children!) 
2576     // left  : go to parent 
2577     // right : open if parent and go next 
2578     // home  : go to root 
2579     // end   : go to last item without opening parents 
2580     // alnum : start or continue searching for the item with this prefix 
2581     int keyCode 
= event
.GetKeyCode(); 
2586             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
2594             if ( !IsExpanded(m_current
) ) 
2597                 ExpandAll(m_current
); 
2600             //else: fall through to Collapse() it 
2604             if (IsExpanded(m_current
)) 
2606                 Collapse(m_current
); 
2612             if ( !event
.HasModifiers() ) 
2614                 wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
2615                 event
.m_item 
= (long) m_current
; 
2616                 event
.SetEventObject( this ); 
2617                 GetEventHandler()->ProcessEvent( event 
); 
2620             // in any case, also generate the normal key event for this key, 
2621             // even if we generated the ACTIVATED event above: this is what 
2622             // wxMSW does and it makes sense because you might not want to 
2623             // process ACTIVATED event at all and handle Space and Return 
2624             // directly (and differently) which would be impossible otherwise 
2628             // up goes to the previous sibling or to the last 
2629             // of its children if it's expanded 
2632                 wxTreeItemId prev 
= GetPrevSibling( m_key_current 
); 
2635                     prev 
= GetItemParent( m_key_current 
); 
2636                     if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2638                         break;  // don't go to root if it is hidden 
2643                         wxTreeItemId current 
= m_key_current
; 
2644                         // TODO: Huh?  If we get here, we'd better be the first child of our parent.  How else could it be? 
2645                         if (current 
== GetFirstChild( prev
, cookie 
)) 
2647                             // otherwise we return to where we came from 
2648                             SelectItem( prev
, unselect_others
, extended_select 
); 
2649                             m_key_current
= (wxGenericTreeItem
*) prev
.m_pItem
; 
2656                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
2658                         wxTreeItemId child 
= GetLastChild(prev
); 
2665                     SelectItem( prev
, unselect_others
, extended_select 
); 
2666                     m_key_current
=(wxGenericTreeItem
*) prev
.m_pItem
; 
2671             // left arrow goes to the parent 
2674                 wxTreeItemId prev 
= GetItemParent( m_current 
); 
2675                 if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2677                     // don't go to root if it is hidden 
2678                     prev 
= GetPrevSibling( m_current 
); 
2682                     SelectItem( prev
, unselect_others
, extended_select 
); 
2688             // this works the same as the down arrow except that we 
2689             // also expand the item if it wasn't expanded yet 
2695                 if (IsExpanded(m_key_current
) && HasChildren(m_key_current
)) 
2698                     wxTreeItemId child 
= GetFirstChild( m_key_current
, cookie 
); 
2699                     SelectItem( child
, unselect_others
, extended_select 
); 
2700                     m_key_current
=(wxGenericTreeItem
*) child
.m_pItem
; 
2704                     wxTreeItemId next 
= GetNextSibling( m_key_current 
); 
2707                         wxTreeItemId current 
= m_key_current
; 
2708                         while (current 
&& !next
) 
2710                             current 
= GetItemParent( current 
); 
2711                             if (current
) next 
= GetNextSibling( current 
); 
2716                         SelectItem( next
, unselect_others
, extended_select 
); 
2717                         m_key_current
=(wxGenericTreeItem
*) next
.m_pItem
; 
2723             // <End> selects the last visible tree item 
2726                 wxTreeItemId last 
= GetRootItem(); 
2728                 while ( last
.IsOk() && IsExpanded(last
) ) 
2730                     wxTreeItemId lastChild 
= GetLastChild(last
); 
2732                     // it may happen if the item was expanded but then all of 
2733                     // its children have been deleted - so IsExpanded() returned 
2734                     // TRUE, but GetLastChild() returned invalid item 
2743                     SelectItem( last
, unselect_others
, extended_select 
); 
2748             // <Home> selects the root item 
2751                 wxTreeItemId prev 
= GetRootItem(); 
2755                 if ( HasFlag(wxTR_HIDE_ROOT
) ) 
2758                     prev 
= GetFirstChild(prev
, dummy
); 
2763                 SelectItem( prev
, unselect_others
, extended_select 
); 
2768             // do not use wxIsalnum() here 
2769             if ( !event
.HasModifiers() && 
2770                  ((keyCode 
>= '0' && keyCode 
<= '9') || 
2771                   (keyCode 
>= 'a' && keyCode 
<= 'z') || 
2772                   (keyCode 
>= 'A' && keyCode 
<= 'Z' ))) 
2774                 // find the next item starting with the given prefix 
2775                 char ch 
= (char)keyCode
; 
2777                 wxTreeItemId id 
= FindItem(m_current
, m_findPrefix 
+ (wxChar
)ch
); 
2788                 // also start the timer to reset the current prefix if the user 
2789                 // doesn't press any more alnum keys soon -- we wouldn't want 
2790                 // to use this prefix for a new item search 
2793                     m_findTimer 
= new wxTreeFindTimer(this); 
2796                 m_findTimer
->Start(wxTreeFindTimer::DELAY
, wxTIMER_ONE_SHOT
); 
2805 wxTreeItemId 
wxGenericTreeCtrl::HitTest(const wxPoint
& point
, int& flags
) 
2807     // JACS: removed wxYieldIfNeeded() because it can cause the window 
2808     // to be deleted from under us if a close window event is pending 
2813     if (point
.x
<0) flags 
|= wxTREE_HITTEST_TOLEFT
; 
2814     if (point
.x
>w
) flags 
|= wxTREE_HITTEST_TORIGHT
; 
2815     if (point
.y
<0) flags 
|= wxTREE_HITTEST_ABOVE
; 
2816     if (point
.y
>h
) flags 
|= wxTREE_HITTEST_BELOW
; 
2817     if (flags
) return wxTreeItemId(); 
2819     if (m_anchor 
== NULL
) 
2821         flags 
= wxTREE_HITTEST_NOWHERE
; 
2822         return wxTreeItemId(); 
2825     wxGenericTreeItem 
*hit 
=  m_anchor
->HitTest(CalcUnscrolledPosition(point
), 
2829         flags 
= wxTREE_HITTEST_NOWHERE
; 
2830         return wxTreeItemId(); 
2835 // get the bounding rectangle of the item (or of its label only) 
2836 bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
, 
2838                                         bool WXUNUSED(textOnly
)) const 
2840     wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") ); 
2842     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2845     GetViewStart(& startX
, & startY
); 
2847     rect
.x 
= i
->GetX() - startX
*PIXELS_PER_UNIT
; 
2848     rect
.y 
= i
->GetY() - startY
*PIXELS_PER_UNIT
; 
2849     rect
.width 
= i
->GetWidth(); 
2850     //rect.height = i->GetHeight(); 
2851     rect
.height 
= GetLineHeight(i
); 
2856 void wxGenericTreeCtrl::Edit( const wxTreeItemId
& item 
) 
2858     wxCHECK_RET( item
.IsOk(), _T("can't edit an invalid item") ); 
2860     wxGenericTreeItem 
*itemEdit 
= (wxGenericTreeItem 
*)item
.m_pItem
; 
2862     wxTreeEvent 
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, GetId() ); 
2863     te
.m_item 
= (long) itemEdit
; 
2864     te
.SetEventObject( this ); 
2865     if ( GetEventHandler()->ProcessEvent( te 
) && !te
.IsAllowed() ) 
2871     // We have to call this here because the label in 
2872     // question might just have been added and no screen 
2873     // update taken place. 
2877     m_textCtrl 
= new wxTreeTextCtrl(this, itemEdit
); 
2879     m_textCtrl
->SetFocus(); 
2882 // returns a pointer to the text edit control if the item is being 
2883 // edited, NULL otherwise (it's assumed that no more than one item may 
2884 // be edited simultaneously) 
2885 wxTextCtrl
* wxGenericTreeCtrl::GetEditControl() const 
2890 bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem 
*item
, 
2891                                        const wxString
& value
) 
2893     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
2894     le
.m_item 
= (long) item
; 
2895     le
.SetEventObject( this ); 
2897     le
.m_editCancelled 
= FALSE
; 
2899     return !GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
2902 void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem 
*item
) 
2904     // let owner know that the edit was cancelled 
2905     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
2906     le
.m_item 
= (long) item
; 
2907     le
.SetEventObject( this ); 
2908     le
.m_label 
= wxEmptyString
; 
2909     le
.m_editCancelled 
= FALSE
; 
2911     GetEventHandler()->ProcessEvent( le 
); 
2917 void wxGenericTreeCtrl::OnRenameTimer() 
2922 void wxGenericTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
2924     if ( !m_anchor 
) return; 
2926     // we process left mouse up event (enables in-place edit), right down 
2927     // (pass to the user code), left dbl click (activate item) and 
2928     // dragging/moving events for items drag-and-drop 
2929     if ( !(event
.LeftDown() || 
2931            event
.RightDown() || 
2932            event
.LeftDClick() || 
2934            ((event
.Moving() || event
.RightUp()) && m_isDragging
)) ) 
2941     wxPoint pt 
= CalcUnscrolledPosition(event
.GetPosition()); 
2944     wxGenericTreeItem 
*item 
= m_anchor
->HitTest(pt
, this, flags
, 0); 
2946     if ( event
.Dragging() && !m_isDragging 
) 
2948         if (m_dragCount 
== 0) 
2953         if (m_dragCount 
!= 3) 
2955             // wait until user drags a bit further... 
2959         wxEventType command 
= event
.RightIsDown() 
2960                               ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
 
2961                               : wxEVT_COMMAND_TREE_BEGIN_DRAG
; 
2963         wxTreeEvent 
nevent( command
, GetId() ); 
2964         nevent
.m_item 
= (long) m_current
; 
2965         nevent
.SetEventObject(this); 
2967         // by default the dragging is not supported, the user code must 
2968         // explicitly allow the event for it to take place 
2971         if ( GetEventHandler()->ProcessEvent(nevent
) && nevent
.IsAllowed() ) 
2973             // we're going to drag this item 
2974             m_isDragging 
= TRUE
; 
2976             // remember the old cursor because we will change it while 
2978             m_oldCursor 
= m_cursor
; 
2980             // in a single selection control, hide the selection temporarily 
2981             if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE
) ) 
2983                 m_oldSelection 
= (wxGenericTreeItem
*) GetSelection().m_pItem
; 
2985                 if ( m_oldSelection 
) 
2987                     m_oldSelection
->SetHilight(FALSE
); 
2988                     RefreshLine(m_oldSelection
); 
2995     else if ( event
.Moving() ) 
2997         if ( item 
!= m_dropTarget 
) 
2999             // unhighlight the previous drop target 
3000             DrawDropEffect(m_dropTarget
); 
3002             m_dropTarget 
= item
; 
3004             // highlight the current drop target if any 
3005             DrawDropEffect(m_dropTarget
); 
3010     else if ( (event
.LeftUp() || event
.RightUp()) && m_isDragging 
) 
3012         // erase the highlighting 
3013         DrawDropEffect(m_dropTarget
); 
3015         if ( m_oldSelection 
) 
3017             m_oldSelection
->SetHilight(TRUE
); 
3018             RefreshLine(m_oldSelection
); 
3019             m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
3022         // generate the drag end event 
3023         wxTreeEvent 
event(wxEVT_COMMAND_TREE_END_DRAG
, GetId()); 
3025         event
.m_item 
= (long) item
; 
3026         event
.m_pointDrag 
= pt
; 
3027         event
.SetEventObject(this); 
3029         (void)GetEventHandler()->ProcessEvent(event
); 
3031         m_isDragging 
= FALSE
; 
3032         m_dropTarget 
= (wxGenericTreeItem 
*)NULL
; 
3036         SetCursor(m_oldCursor
); 
3042         // here we process only the messages which happen on tree items 
3046         if (item 
== NULL
) return;  /* we hit the blank area */ 
3048         if ( event
.RightDown() ) 
3050             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
, GetId()); 
3051             nevent
.m_item 
= (long) item
; 
3052             nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3053             nevent
.SetEventObject(this); 
3054             GetEventHandler()->ProcessEvent(nevent
); 
3056         else if ( event
.LeftUp() ) 
3060                 if ( (item 
== m_current
) && 
3061                      (flags 
& wxTREE_HITTEST_ONITEMLABEL
) && 
3062                      HasFlag(wxTR_EDIT_LABELS
) ) 
3064                     if ( m_renameTimer 
) 
3066                         if ( m_renameTimer
->IsRunning() ) 
3067                             m_renameTimer
->Stop(); 
3071                         m_renameTimer 
= new wxTreeRenameTimer( this ); 
3074                     m_renameTimer
->Start( wxTreeRenameTimer::DELAY
, TRUE 
); 
3077                 m_lastOnSame 
= FALSE
; 
3080         else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick() 
3082             if ( event
.LeftDown() ) 
3084                 m_lastOnSame 
= item 
== m_current
; 
3087             if ( flags 
& wxTREE_HITTEST_ONITEMBUTTON 
) 
3089                 // only toggle the item for a single click, double click on 
3090                 // the button doesn't do anything (it toggles the item twice) 
3091                 if ( event
.LeftDown() ) 
3096                 // don't select the item if the button was clicked 
3100             // how should the selection work for this event? 
3101             bool is_multiple
, extended_select
, unselect_others
; 
3102             EventFlagsToSelType(GetWindowStyleFlag(), 
3104                                 event
.ControlDown(), 
3105                                 is_multiple
, extended_select
, unselect_others
); 
3107             SelectItem(item
, unselect_others
, extended_select
); 
3109             // For some reason, Windows isn't recognizing a left double-click, 
3110             // so we need to simulate it here.  Allow 200 milliseconds for now. 
3111             if ( event
.LeftDClick() ) 
3113                 // double clicking should not start editing the item label 
3114                 if ( m_renameTimer 
) 
3115                     m_renameTimer
->Stop(); 
3117                 m_lastOnSame 
= FALSE
; 
3119                 // send activate event first 
3120                 wxTreeEvent 
nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
3121                 nevent
.m_item 
= (long) item
; 
3122                 nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3123                 nevent
.SetEventObject( this ); 
3124                 if ( !GetEventHandler()->ProcessEvent( nevent 
) ) 
3126                     // if the user code didn't process the activate event, 
3127                     // handle it ourselves by toggling the item when it is 
3129                     if ( item
->HasPlus() ) 
3139 void wxGenericTreeCtrl::OnIdle( wxIdleEvent 
&WXUNUSED(event
) ) 
3141     /* after all changes have been done to the tree control, 
3142      * we actually redraw the tree when everything is over */ 
3144     if (!m_dirty
) return; 
3148     CalculatePositions(); 
3150     AdjustMyScrollbars(); 
3153 void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem 
*item
, wxDC 
&dc 
) 
3158     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
3159     if ( attr 
&& attr
->HasFont() ) 
3160         dc
.SetFont(attr
->GetFont()); 
3161     else if ( item
->IsBold() ) 
3162         dc
.SetFont(m_boldFont
); 
3164     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
3167     // restore normal font 
3168     dc
.SetFont( m_normalFont 
); 
3172     int image 
= item
->GetCurrentImage(); 
3173     if ( image 
!= NO_IMAGE 
) 
3175         if ( m_imageListNormal 
) 
3177             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
3182     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
3185         total_h 
+= 2;            // at least 2 pixels 
3187         total_h 
+= total_h
/10;   // otherwise 10% extra spacing 
3189     item
->SetHeight(total_h
); 
3190     if (total_h
>m_lineHeight
) 
3191         m_lineHeight
=total_h
; 
3193     item
->SetWidth(image_w
+text_w
+2); 
3196 // ----------------------------------------------------------------------------- 
3197 // for developper : y is now the top of the level 
3198 // not the middle of it ! 
3199 void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
3201     int x 
= level
*m_indent
; 
3202     if (!HasFlag(wxTR_HIDE_ROOT
)) 
3206     else if (level 
== 0) 
3208         // a hidden root is not evaluated, but its 
3209         // children are always calculated 
3213     CalculateSize( item
, dc 
); 
3216     item
->SetX( x
+m_spacing 
); 
3218     y 
+= GetLineHeight(item
); 
3220     if ( !item
->IsExpanded() ) 
3222         // we don't need to calculate collapsed branches 
3227     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3228     size_t n
, count 
= children
.Count(); 
3230     for (n 
= 0; n 
< count
; ++n 
) 
3231         CalculateLevel( children
[n
], dc
, level
, y 
);  // recurse 
3234 void wxGenericTreeCtrl::CalculatePositions() 
3236     if ( !m_anchor 
) return; 
3238     wxClientDC 
dc(this); 
3241     dc
.SetFont( m_normalFont 
); 
3243     dc
.SetPen( m_dottedPen 
); 
3244     //if(GetImageList() == NULL) 
3245     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
3248     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
3251 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
3253     if (m_dirty
) return; 
3255     wxSize client 
= GetClientSize(); 
3258     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3259     rect
.width 
= client
.x
; 
3260     rect
.height 
= client
.y
; 
3262     Refresh(TRUE
, &rect
); 
3264     AdjustMyScrollbars(); 
3267 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
3269     if (m_dirty
) return; 
3272     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3273     rect
.width 
= GetClientSize().x
; 
3274     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
3276     Refresh(TRUE
, &rect
); 
3279 void wxGenericTreeCtrl::RefreshSelected() 
3281     // TODO: this is awfully inefficient, we should keep the list of all 
3282     //       selected items internally, should be much faster 
3284         RefreshSelectedUnder(m_anchor
); 
3287 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem 
*item
) 
3289     if ( item
->IsSelected() ) 
3292     const wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3293     size_t count 
= children
.GetCount(); 
3294     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3296         RefreshSelectedUnder(children
[n
]); 
3300 // ---------------------------------------------------------------------------- 
3301 // changing colours: we need to refresh the tree control 
3302 // ---------------------------------------------------------------------------- 
3304 bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour
& colour
) 
3306     if ( !wxWindow::SetBackgroundColour(colour
) ) 
3314 bool wxGenericTreeCtrl::SetForegroundColour(const wxColour
& colour
) 
3316     if ( !wxWindow::SetForegroundColour(colour
) ) 
3324 #endif // wxUSE_TREECTRL