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/mac/private.h" 
  48 // ----------------------------------------------------------------------------- 
  50 // ----------------------------------------------------------------------------- 
  52 class WXDLLEXPORT wxGenericTreeItem
; 
  54 WX_DEFINE_EXPORTED_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 image and the item text 
  65 static const int MARGIN_BETWEEN_IMAGE_AND_TEXT 
= 4; 
  67 // ----------------------------------------------------------------------------- 
  69 // ----------------------------------------------------------------------------- 
  71 // timer used for enabling in-place edit 
  72 class WXDLLEXPORT wxTreeRenameTimer
: public wxTimer
 
  75     // start editing the current item after half a second (if the mouse hasn't 
  76     // been clicked/moved) 
  79     wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
); 
  81     virtual void Notify(); 
  84     wxGenericTreeCtrl 
*m_owner
; 
  86     DECLARE_NO_COPY_CLASS(wxTreeRenameTimer
) 
  89 // control used for in-place edit 
  90 class WXDLLEXPORT wxTreeTextCtrl
: public wxTextCtrl
 
  93     wxTreeTextCtrl(wxGenericTreeCtrl 
*owner
, wxGenericTreeItem 
*item
); 
  95     void EndEdit(bool discardChanges 
= false) 
 103             m_aboutToFinish 
= true; 
 105             // Notify the owner about the changes 
 108             // Even if vetoed, close the control (consistent with MSW) 
 116         m_owner
->OnRenameCancelled(m_itemEdited
); 
 118     const wxGenericTreeItem
* item() const { return m_itemEdited
; } 
 121     void OnChar( wxKeyEvent 
&event 
); 
 122     void OnKeyUp( wxKeyEvent 
&event 
); 
 123     void OnKillFocus( wxFocusEvent 
&event 
); 
 125     bool AcceptChanges(); 
 129     wxGenericTreeCtrl  
*m_owner
; 
 130     wxGenericTreeItem  
*m_itemEdited
; 
 131     wxString            m_startValue
; 
 133     bool                m_aboutToFinish
; 
 135     DECLARE_EVENT_TABLE() 
 136     DECLARE_NO_COPY_CLASS(wxTreeTextCtrl
) 
 139 // timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed 
 140 // for a sufficiently long time 
 141 class WXDLLEXPORT wxTreeFindTimer 
: public wxTimer
 
 144     // reset the current prefix after half a second of inactivity 
 145     enum { DELAY 
= 500 }; 
 147     wxTreeFindTimer( wxGenericTreeCtrl 
*owner 
) { m_owner 
= owner
; } 
 149     virtual void Notify() { m_owner
->m_findPrefix
.clear(); } 
 152     wxGenericTreeCtrl 
*m_owner
; 
 154     DECLARE_NO_COPY_CLASS(wxTreeFindTimer
) 
 158 class WXDLLEXPORT wxGenericTreeItem
 
 162     wxGenericTreeItem() { m_data 
= NULL
; } 
 163     wxGenericTreeItem( wxGenericTreeItem 
*parent
, 
 164                        const wxString
& text
, 
 167                        wxTreeItemData 
*data 
); 
 169     ~wxGenericTreeItem(); 
 172     wxArrayGenericTreeItems
& GetChildren() { return m_children
; } 
 174     const wxString
& GetText() const { return m_text
; } 
 175     int GetImage(wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) const 
 176         { return m_images
[which
]; } 
 177     wxTreeItemData 
*GetData() const { return m_data
; } 
 179     // returns the current image for the item (depending on its 
 180     // selected/expanded/whatever state) 
 181     int GetCurrentImage() const; 
 183     void SetText( const wxString 
&text 
); 
 184     void SetImage(int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; } 
 185     void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
 187     void SetHasPlus(bool has 
= true) { m_hasPlus 
= has
; } 
 189     void SetBold(bool bold
) { m_isBold 
= bold
; } 
 191     int GetX() const { return m_x
; } 
 192     int GetY() const { return m_y
; } 
 194     void SetX(int x
) { m_x 
= x
; } 
 195     void SetY(int y
) { m_y 
= y
; } 
 197     int  GetHeight() const { return m_height
; } 
 198     int  GetWidth()  const { return m_width
; } 
 200     void SetHeight(int h
) { m_height 
= h
; } 
 201     void SetWidth(int w
) { m_width 
= w
; } 
 203     wxGenericTreeItem 
*GetParent() const { return m_parent
; } 
 207     // deletes all children notifying the treectrl about it 
 208     void DeleteChildren(wxGenericTreeCtrl 
*tree
); 
 210     // get count of all children (and grand children if 'recursively') 
 211     size_t GetChildrenCount(bool recursively 
= true) const; 
 213     void Insert(wxGenericTreeItem 
*child
, size_t index
) 
 214     { m_children
.Insert(child
, index
); } 
 216     void GetSize( int &x
, int &y
, const wxGenericTreeCtrl
* ); 
 218         // return the item at given position (or NULL if no item), onButton is 
 219         // true if the point belongs to the item's button, otherwise it lies 
 220         // on the item's label 
 221     wxGenericTreeItem 
*HitTest( const wxPoint
& point
, 
 222                                 const wxGenericTreeCtrl 
*, 
 226     void Expand() { m_isCollapsed 
= false; } 
 227     void Collapse() { m_isCollapsed 
= true; } 
 229     void SetHilight( bool set 
= true ) { m_hasHilight 
= set
; } 
 232     bool HasChildren() const { return !m_children
.IsEmpty(); } 
 233     bool IsSelected()  const { return m_hasHilight 
!= 0; } 
 234     bool IsExpanded()  const { return !m_isCollapsed
; } 
 235     bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 236     bool IsBold()      const { return m_isBold 
!= 0; } 
 239         // get them - may be NULL 
 240     wxTreeItemAttr 
*GetAttributes() const { return m_attr
; } 
 241         // get them ensuring that the pointer is not NULL 
 242     wxTreeItemAttr
& Attr() 
 246             m_attr 
= new wxTreeItemAttr
; 
 252     void SetAttributes(wxTreeItemAttr 
*attr
) 
 254         if ( m_ownsAttr 
) delete m_attr
; 
 258         // set them and delete when done 
 259     void AssignAttributes(wxTreeItemAttr 
*attr
) 
 266     // since there can be very many of these, we save size by chosing 
 267     // the smallest representation for the elements and by ordering 
 268     // the members to avoid padding. 
 269     wxString            m_text
;         // label to be rendered for item 
 271     wxTreeItemData     
*m_data
;         // user-provided data 
 273     wxArrayGenericTreeItems m_children
; // list of children 
 274     wxGenericTreeItem  
*m_parent
;       // parent of this item 
 276     wxTreeItemAttr     
*m_attr
;         // attributes??? 
 278     // tree ctrl images for the normal, selected, expanded and 
 279     // expanded+selected states 
 280     int                 m_images
[wxTreeItemIcon_Max
]; 
 282     wxCoord             m_x
;            // (virtual) offset from top 
 283     wxCoord             m_y
;            // (virtual) offset from left 
 284     int                 m_width
;        // width of this item 
 285     int                 m_height
;       // height of this item 
 287     // use bitfields to save size 
 288     unsigned int        m_isCollapsed 
:1; 
 289     unsigned int        m_hasHilight  
:1; // same as focused 
 290     unsigned int        m_hasPlus     
:1; // used for item which doesn't have 
 291                                           // children but has a [+] button 
 292     unsigned int        m_isBold      
:1; // render the label in bold font 
 293     unsigned int        m_ownsAttr    
:1; // delete attribute when done 
 295     DECLARE_NO_COPY_CLASS(wxGenericTreeItem
) 
 298 // ============================================================================= 
 300 // ============================================================================= 
 302 // ---------------------------------------------------------------------------- 
 304 // ---------------------------------------------------------------------------- 
 306 // translate the key or mouse event flags to the type of selection we're 
 308 static void EventFlagsToSelType(long style
, 
 312                                 bool &extended_select
, 
 313                                 bool &unselect_others
) 
 315     is_multiple 
= (style 
& wxTR_MULTIPLE
) != 0; 
 316     extended_select 
= shiftDown 
&& is_multiple
; 
 317     unselect_others 
= !(extended_select 
|| (ctrlDown 
&& is_multiple
)); 
 320 // check if the given item is under another one 
 321 static bool IsDescendantOf(const wxGenericTreeItem 
*parent
, const wxGenericTreeItem 
*item
) 
 325         if ( item 
== parent 
) 
 327             // item is a descendant of parent 
 331         item 
= item
->GetParent(); 
 337 // ----------------------------------------------------------------------------- 
 338 // wxTreeRenameTimer (internal) 
 339 // ----------------------------------------------------------------------------- 
 341 wxTreeRenameTimer::wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
) 
 346 void wxTreeRenameTimer::Notify() 
 348     m_owner
->OnRenameTimer(); 
 351 //----------------------------------------------------------------------------- 
 352 // wxTreeTextCtrl (internal) 
 353 //----------------------------------------------------------------------------- 
 355 BEGIN_EVENT_TABLE(wxTreeTextCtrl
,wxTextCtrl
) 
 356     EVT_CHAR           (wxTreeTextCtrl::OnChar
) 
 357     EVT_KEY_UP         (wxTreeTextCtrl::OnKeyUp
) 
 358     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus
) 
 361 wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl 
*owner
, 
 362                                wxGenericTreeItem 
*item
) 
 363               : m_itemEdited(item
), m_startValue(item
->GetText()) 
 367     m_aboutToFinish 
= false; 
 369     int w 
= m_itemEdited
->GetWidth(), 
 370         h 
= m_itemEdited
->GetHeight(); 
 373     m_owner
->CalcScrolledPosition(item
->GetX(), item
->GetY(), &x
, &y
); 
 378     int image 
= item
->GetCurrentImage(); 
 379     if ( image 
!= NO_IMAGE 
) 
 381         if ( m_owner
->m_imageListNormal 
) 
 383             m_owner
->m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
 384             image_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
 388             wxFAIL_MSG(_T("you must create an image list to use images!")); 
 392     // FIXME: what are all these hardcoded 4, 8 and 11s really? 
 396     wxSize bs 
= DoGetBestSize() ; 
 397     // edit control height 
 400         int diff 
= h 
- ( bs
.y 
- 8 ) ; 
 406     (void)Create(m_owner
, wxID_ANY
, m_startValue
, 
 407                  wxPoint(x 
- 4, y 
- 4), wxSize(w 
+ 11, h 
+ 8)); 
 410 bool wxTreeTextCtrl::AcceptChanges() 
 412     const wxString value 
= GetValue(); 
 414     if ( value 
== m_startValue 
) 
 416         // nothing changed, always accept 
 417         // when an item remains unchanged, the owner 
 418         // needs to be notified that the user decided 
 419         // not to change the tree item label, and that 
 420         // the edit has been cancelled 
 422         m_owner
->OnRenameCancelled(m_itemEdited
); 
 426     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
 428         // vetoed by the user 
 432     // accepted, do rename the item 
 433     m_owner
->SetItemText(m_itemEdited
, value
); 
 438 void wxTreeTextCtrl::Finish() 
 442         m_owner
->ResetTextControl(); 
 444         wxPendingDelete
.Append(this); 
 452 void wxTreeTextCtrl::OnChar( wxKeyEvent 
&event 
) 
 454     switch ( event
.m_keyCode 
) 
 469 void wxTreeTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
 473         // auto-grow the textctrl: 
 474         wxSize parentSize 
= m_owner
->GetSize(); 
 475         wxPoint myPos 
= GetPosition(); 
 476         wxSize mySize 
= GetSize(); 
 478         GetTextExtent(GetValue() + _T("M"), &sx
, &sy
); 
 479         if (myPos
.x 
+ sx 
> parentSize
.x
) 
 480             sx 
= parentSize
.x 
- myPos
.x
; 
 483         SetSize(sx
, wxDefaultCoord
); 
 489 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
 491     if ( !m_finished 
&& !m_aboutToFinish 
) 
 493         // We must finish regardless of success, otherwise we'll get 
 497         if ( !AcceptChanges() ) 
 498             m_owner
->OnRenameCancelled( m_itemEdited 
); 
 501     // We must let the native text control handle focus, too, otherwise 
 502     // it could have problems with the cursor (e.g., in wxGTK). 
 506 // ----------------------------------------------------------------------------- 
 508 // ----------------------------------------------------------------------------- 
 510 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 511                                      const wxString
& text
, 
 512                                      int image
, int selImage
, 
 513                                      wxTreeItemData 
*data
) 
 516     m_images
[wxTreeItemIcon_Normal
] = image
; 
 517     m_images
[wxTreeItemIcon_Selected
] = selImage
; 
 518     m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
; 
 519     m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
; 
 524     m_isCollapsed 
= true; 
 525     m_hasHilight 
= false; 
 531     m_attr 
= (wxTreeItemAttr 
*)NULL
; 
 534     // We don't know the height here yet. 
 539 wxGenericTreeItem::~wxGenericTreeItem() 
 543     if (m_ownsAttr
) delete m_attr
; 
 545     wxASSERT_MSG( m_children
.IsEmpty(), 
 546                   wxT("please call DeleteChildren() before deleting the item") ); 
 549 void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl 
*tree
) 
 551     size_t count 
= m_children
.Count(); 
 552     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 554         wxGenericTreeItem 
*child 
= m_children
[n
]; 
 555         tree
->SendDeleteEvent(child
); 
 557         child
->DeleteChildren(tree
); 
 558         if ( child 
== tree
->m_select_me 
) 
 559             tree
->m_select_me 
= NULL
; 
 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             int xCross 
= m_x 
- theCtrl
->GetSpacing(); 
 624             // according to the drawing code the triangels are drawn 
 625             // at -4 , -4  from the position up to +10/+10 max 
 626             if ((point
.x 
> xCross
-4) && (point
.x 
< xCross
+10) && 
 627                 (point
.y 
> y_mid
-4) && (point
.y 
< y_mid
+10) && 
 628                 HasPlus() && theCtrl
->HasButtons() ) 
 630             // 5 is the size of the plus sign 
 631             if ((point
.x 
> xCross
-6) && (point
.x 
< xCross
+6) && 
 632                 (point
.y 
> y_mid
-6) && (point
.y 
< y_mid
+6) && 
 633                 HasPlus() && theCtrl
->HasButtons() ) 
 636                 flags 
|= wxTREE_HITTEST_ONITEMBUTTON
; 
 640             if ((point
.x 
>= m_x
) && (point
.x 
<= m_x
+m_width
)) 
 645                 // assuming every image (normal and selected) has the same size! 
 646                 if ( (GetImage() != NO_IMAGE
) && theCtrl
->m_imageListNormal 
) 
 647                     theCtrl
->m_imageListNormal
->GetSize(GetImage(), 
 650                 if ((image_w 
!= -1) && (point
.x 
<= m_x 
+ image_w 
+ 1)) 
 651                     flags 
|= wxTREE_HITTEST_ONITEMICON
; 
 653                     flags 
|= wxTREE_HITTEST_ONITEMLABEL
; 
 659                 flags 
|= wxTREE_HITTEST_ONITEMINDENT
; 
 660             if (point
.x 
> m_x
+m_width
) 
 661                 flags 
|= wxTREE_HITTEST_ONITEMRIGHT
; 
 666         // if children are expanded, fall through to evaluate them 
 667         if (m_isCollapsed
) return (wxGenericTreeItem
*) NULL
; 
 671     size_t count 
= m_children
.Count(); 
 672     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 674         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, 
 682     return (wxGenericTreeItem
*) NULL
; 
 685 int wxGenericTreeItem::GetCurrentImage() const 
 687     int image 
= NO_IMAGE
; 
 692             image 
= GetImage(wxTreeItemIcon_SelectedExpanded
); 
 695         if ( image 
== NO_IMAGE 
) 
 697             // we usually fall back to the normal item, but try just the 
 698             // expanded one (and not selected) first in this case 
 699             image 
= GetImage(wxTreeItemIcon_Expanded
); 
 705             image 
= GetImage(wxTreeItemIcon_Selected
); 
 708     // maybe it doesn't have the specific image we want, 
 709     // try the default one instead 
 710     if ( image 
== NO_IMAGE 
) image 
= GetImage(); 
 715 // ----------------------------------------------------------------------------- 
 716 // wxGenericTreeCtrl implementation 
 717 // ----------------------------------------------------------------------------- 
 719 IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl
, wxControl
) 
 721 BEGIN_EVENT_TABLE(wxGenericTreeCtrl
, wxTreeCtrlBase
) 
 722     EVT_PAINT          (wxGenericTreeCtrl::OnPaint
) 
 723     EVT_MOUSE_EVENTS   (wxGenericTreeCtrl::OnMouse
) 
 724     EVT_CHAR           (wxGenericTreeCtrl::OnChar
) 
 725     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus
) 
 726     EVT_KILL_FOCUS     (wxGenericTreeCtrl::OnKillFocus
) 
 727     EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY
, wxGenericTreeCtrl::OnGetToolTip
) 
 730 #if !defined(__WXMSW__) || defined(__WXUNIVERSAL__) 
 732  * wxTreeCtrl has to be a real class or we have problems with 
 733  * the run-time information. 
 736 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxGenericTreeCtrl
) 
 739 // ----------------------------------------------------------------------------- 
 740 // construction/destruction 
 741 // ----------------------------------------------------------------------------- 
 743 void wxGenericTreeCtrl::Init() 
 748     m_select_me 
= (wxGenericTreeItem 
*) NULL
; 
 756     m_hilightBrush 
= new wxBrush
 
 758                             wxSystemSettings::GetColour
 
 760                                 wxSYS_COLOUR_HIGHLIGHT
 
 765     m_hilightUnfocusedBrush 
= new wxBrush
 
 767                                  wxSystemSettings::GetColour
 
 769                                      wxSYS_COLOUR_BTNSHADOW
 
 774     m_imageListButtons 
= NULL
; 
 775     m_ownsImageListButtons 
= false; 
 778     m_isDragging 
= false; 
 779     m_dropTarget 
= m_oldSelection 
= NULL
; 
 783     m_renameTimer 
= NULL
; 
 788     m_dropEffectAboveItem 
= false; 
 790     m_lastOnSame 
= false; 
 792 #ifdef __WXMAC_CARBON__ 
 793     m_normalFont
.MacCreateThemeFont( kThemeViewsFont 
) ; 
 795     m_normalFont 
= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT 
); 
 797     m_boldFont 
= wxFont(m_normalFont
.GetPointSize(), 
 798                         m_normalFont
.GetFamily(), 
 799                         m_normalFont
.GetStyle(), 
 801                         m_normalFont
.GetUnderlined(), 
 802                         m_normalFont
.GetFaceName(), 
 803                         m_normalFont
.GetEncoding()); 
 806 bool wxGenericTreeCtrl::Create(wxWindow 
*parent
, 
 811                                const wxValidator
& validator
, 
 812                                const wxString
& name 
) 
 816     wxGetOsVersion( &major
, &minor 
); 
 818     style 
&= ~wxTR_LINES_AT_ROOT
; 
 819     style 
|= wxTR_NO_LINES
; 
 821         style 
|= wxTR_ROW_LINES
; 
 824     if ( !wxControl::Create( parent
, id
, pos
, size
, 
 825                              style
|wxHSCROLL
|wxVSCROLL
, 
 830     // If the tree display has no buttons, but does have 
 831     // connecting lines, we can use a narrower layout. 
 832     // It may not be a good idea to force this... 
 833     if (!HasButtons() && !HasFlag(wxTR_NO_LINES
)) 
 839     wxVisualAttributes attr 
= GetDefaultAttributes(); 
 840     SetOwnForegroundColour( attr
.colFg 
); 
 841     SetOwnBackgroundColour( attr
.colBg 
); 
 843         SetOwnFont(attr
.font
); 
 845     m_dottedPen 
= wxPen( wxT("grey"), 0, 0 ); 
 852 wxGenericTreeCtrl::~wxGenericTreeCtrl() 
 854     delete m_hilightBrush
; 
 855     delete m_hilightUnfocusedBrush
; 
 859     delete m_renameTimer
; 
 862     if (m_ownsImageListButtons
) 
 863         delete m_imageListButtons
; 
 866 // ----------------------------------------------------------------------------- 
 868 // ----------------------------------------------------------------------------- 
 870 unsigned int wxGenericTreeCtrl::GetCount() const 
 878     unsigned int count 
= m_anchor
->GetChildrenCount(); 
 879     if ( !HasFlag(wxTR_HIDE_ROOT
) ) 
 881         // take the root itself into account 
 888 void wxGenericTreeCtrl::SetIndent(unsigned int indent
) 
 890     m_indent 
= (unsigned short) indent
; 
 895 wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, 
 896                                     bool recursively
) const 
 898     wxCHECK_MSG( item
.IsOk(), 0u, wxT("invalid tree item") ); 
 900     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildrenCount(recursively
); 
 903 void wxGenericTreeCtrl::SetWindowStyle(const long styles
) 
 905     // Do not try to expand the root node if it hasn't been created yet 
 906     if (m_anchor 
&& !HasFlag(wxTR_HIDE_ROOT
) && (styles 
& wxTR_HIDE_ROOT
)) 
 908         // if we will hide the root, make sure children are visible 
 909         m_anchor
->SetHasPlus(); 
 911         CalculatePositions(); 
 914     // right now, just sets the styles.  Eventually, we may 
 915     // want to update the inherited styles, but right now 
 916     // none of the parents has updatable styles 
 917     m_windowStyle 
= styles
; 
 921 // ----------------------------------------------------------------------------- 
 922 // functions to work with tree items 
 923 // ----------------------------------------------------------------------------- 
 925 wxString 
wxGenericTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 927     wxCHECK_MSG( item
.IsOk(), wxEmptyString
, wxT("invalid tree item") ); 
 929     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetText(); 
 932 int wxGenericTreeCtrl::GetItemImage(const wxTreeItemId
& item
, 
 933                              wxTreeItemIcon which
) const 
 935     wxCHECK_MSG( item
.IsOk(), -1, wxT("invalid tree item") ); 
 937     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetImage(which
); 
 940 wxTreeItemData 
*wxGenericTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 942     wxCHECK_MSG( item
.IsOk(), NULL
, wxT("invalid tree item") ); 
 944     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetData(); 
 947 wxColour 
wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId
& item
) const 
 949     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
 951     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 952     return pItem
->Attr().GetTextColour(); 
 955 wxColour 
wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId
& item
) const 
 957     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
 959     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 960     return pItem
->Attr().GetBackgroundColour(); 
 963 wxFont 
wxGenericTreeCtrl::GetItemFont(const wxTreeItemId
& item
) const 
 965     wxCHECK_MSG( item
.IsOk(), wxNullFont
, wxT("invalid tree item") ); 
 967     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 968     return pItem
->Attr().GetFont(); 
 971 void wxGenericTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 973     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 976     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 977     pItem
->SetText(text
); 
 978     CalculateSize(pItem
, dc
); 
 982 void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId
& item
, 
 984                               wxTreeItemIcon which
) 
 986     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 988     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 989     pItem
->SetImage(image
, which
); 
 992     CalculateSize(pItem
, dc
); 
 996 void wxGenericTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 998     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1001         data
->SetId( item 
); 
1003     ((wxGenericTreeItem
*) item
.m_pItem
)->SetData(data
); 
1006 void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
1008     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1010     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1011     pItem
->SetHasPlus(has
); 
1015 void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
1017     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1019     // avoid redrawing the tree if no real change 
1020     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1021     if ( pItem
->IsBold() != bold 
) 
1023         pItem
->SetBold(bold
); 
1025         // recalculate the item size as bold and non bold fonts have different 
1027         wxClientDC 
dc(this); 
1028         CalculateSize(pItem
, dc
); 
1034 void wxGenericTreeCtrl::SetItemDropHighlight(const wxTreeItemId
& item
, 
1037     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1043         bg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
); 
1044         fg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1047     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1048     pItem
->Attr().SetTextColour(fg
); 
1049     pItem
->Attr().SetBackgroundColour(bg
); 
1053 void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId
& item
, 
1054                                    const wxColour
& col
) 
1056     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1058     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1059     pItem
->Attr().SetTextColour(col
); 
1063 void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
, 
1064                                          const wxColour
& col
) 
1066     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1068     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1069     pItem
->Attr().SetBackgroundColour(col
); 
1073 void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
) 
1075     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1077     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1078     pItem
->Attr().SetFont(font
); 
1082 bool wxGenericTreeCtrl::SetFont( const wxFont 
&font 
) 
1084     wxTreeCtrlBase::SetFont(font
); 
1086     m_normalFont 
= font 
; 
1087     m_boldFont 
= wxFont(m_normalFont
.GetPointSize(), 
1088                         m_normalFont
.GetFamily(), 
1089                         m_normalFont
.GetStyle(), 
1091                         m_normalFont
.GetUnderlined(), 
1092                         m_normalFont
.GetFaceName(), 
1093                         m_normalFont
.GetEncoding()); 
1099 // ----------------------------------------------------------------------------- 
1100 // item status inquiries 
1101 // ----------------------------------------------------------------------------- 
1103 bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId
& item
) const 
1105     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1107     // An item is only visible if it's not a descendant of a collapsed item 
1108     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1109     wxGenericTreeItem
* parent 
= pItem
->GetParent(); 
1112         if (!parent
->IsExpanded()) 
1114         parent 
= parent
->GetParent(); 
1118     GetViewStart(& startX
, & startY
); 
1120     wxSize clientSize 
= GetClientSize(); 
1123     if (!GetBoundingRect(item
, rect
)) 
1125     if (rect
.GetWidth() == 0 || rect
.GetHeight() == 0) 
1127     if (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) 
1129     if (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
) 
1135 bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
1137     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1139     // consider that the item does have children if it has the "+" button: it 
1140     // might not have them (if it had never been expanded yet) but then it 
1141     // could have them as well and it's better to err on this side rather than 
1142     // disabling some operations which are restricted to the items with 
1143     // children for an item which does have them 
1144     return ((wxGenericTreeItem
*) item
.m_pItem
)->HasPlus(); 
1147 bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
1149     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1151     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsExpanded(); 
1154 bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
1156     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1158     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsSelected(); 
1161 bool wxGenericTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
1163     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1165     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsBold(); 
1168 // ----------------------------------------------------------------------------- 
1170 // ----------------------------------------------------------------------------- 
1172 wxTreeItemId 
wxGenericTreeCtrl::GetItemParent(const wxTreeItemId
& item
) const 
1174     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1176     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetParent(); 
1179 wxTreeItemId 
wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, 
1180                                               wxTreeItemIdValue
& cookie
) const 
1182     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1185     return GetNextChild(item
, cookie
); 
1188 wxTreeItemId 
wxGenericTreeCtrl::GetNextChild(const wxTreeItemId
& item
, 
1189                                              wxTreeItemIdValue
& cookie
) const 
1191     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1193     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1195     // it's ok to cast cookie to size_t, we never have indices big enough to 
1196     // overflow "void *" 
1197     size_t *pIndex 
= (size_t *)&cookie
; 
1198     if ( *pIndex 
< children
.Count() ) 
1200         return children
.Item((*pIndex
)++); 
1204         // there are no more of them 
1205         return wxTreeItemId(); 
1209 #if WXWIN_COMPATIBILITY_2_4 
1211 wxTreeItemId 
wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, 
1214     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1217     return GetNextChild(item
, cookie
); 
1220 wxTreeItemId 
wxGenericTreeCtrl::GetNextChild(const wxTreeItemId
& item
, 
1223     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1225     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1226     if ( (size_t)cookie 
< children
.Count() ) 
1228         return children
.Item((size_t)cookie
++); 
1232         // there are no more of them 
1233         return wxTreeItemId(); 
1237 #endif // WXWIN_COMPATIBILITY_2_4 
1239 wxTreeItemId 
wxGenericTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
1241     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1243     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1244     return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
1247 wxTreeItemId 
wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
1249     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1251     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1252     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1253     if ( parent 
== NULL 
) 
1255         // root item doesn't have any siblings 
1256         return wxTreeItemId(); 
1259     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1260     int index 
= siblings
.Index(i
); 
1261     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1263     size_t n 
= (size_t)(index 
+ 1); 
1264     return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
1267 wxTreeItemId 
wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
1269     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1271     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1272     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1273     if ( parent 
== NULL 
) 
1275         // root item doesn't have any siblings 
1276         return wxTreeItemId(); 
1279     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1280     int index 
= siblings
.Index(i
); 
1281     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1283     return index 
== 0 ? wxTreeItemId() 
1284                       : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
1287 // Only for internal use right now, but should probably be public 
1288 wxTreeItemId 
wxGenericTreeCtrl::GetNext(const wxTreeItemId
& item
) const 
1290     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1292     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1294     // First see if there are any children. 
1295     wxArrayGenericTreeItems
& children 
= i
->GetChildren(); 
1296     if (children
.GetCount() > 0) 
1298          return children
.Item(0); 
1302          // Try a sibling of this or ancestor instead 
1303          wxTreeItemId p 
= item
; 
1304          wxTreeItemId toFind
; 
1307               toFind 
= GetNextSibling(p
); 
1308               p 
= GetItemParent(p
); 
1309          } while (p
.IsOk() && !toFind
.IsOk()); 
1314 wxTreeItemId 
wxGenericTreeCtrl::GetFirstVisibleItem() const 
1316     wxTreeItemId id 
= GetRootItem(); 
1325     } while (id
.IsOk()); 
1327     return wxTreeItemId(); 
1330 wxTreeItemId 
wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
1332     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1334     wxTreeItemId id 
= item
; 
1337         while (id 
= GetNext(id
), id
.IsOk()) 
1343     return wxTreeItemId(); 
1346 wxTreeItemId 
wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
1348     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1350     wxFAIL_MSG(wxT("not implemented")); 
1352     return wxTreeItemId(); 
1355 // called by wxTextTreeCtrl when it marks itself for deletion 
1356 void wxGenericTreeCtrl::ResetTextControl() 
1361 // find the first item starting with the given prefix after the given item 
1362 wxTreeItemId 
wxGenericTreeCtrl::FindItem(const wxTreeItemId
& idParent
, 
1363                                          const wxString
& prefixOrig
) const 
1365     // match is case insensitive as this is more convenient to the user: having 
1366     // to press Shift-letter to go to the item starting with a capital letter 
1367     // would be too bothersome 
1368     wxString prefix 
= prefixOrig
.Lower(); 
1370     // determine the starting point: we shouldn't take the current item (this 
1371     // allows to switch between two items starting with the same letter just by 
1372     // pressing it) but we shouldn't jump to the next one if the user is 
1373     // continuing to type as otherwise he might easily skip the item he wanted 
1374     wxTreeItemId id 
= idParent
; 
1375     if ( prefix
.length() == 1 ) 
1380     // look for the item starting with the given prefix after it 
1381     while ( id
.IsOk() && !GetItemText(id
).Lower().StartsWith(prefix
) ) 
1386     // if we haven't found anything... 
1389         // ... wrap to the beginning 
1391         if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1393             // can't select virtual root 
1397         // and try all the items (stop when we get to the one we started from) 
1398         while ( id 
!= idParent 
&& !GetItemText(id
).Lower().StartsWith(prefix
) ) 
1407 // ----------------------------------------------------------------------------- 
1409 // ----------------------------------------------------------------------------- 
1411 wxTreeItemId 
wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
1413                                              const wxString
& text
, 
1416                                              wxTreeItemData 
*data
) 
1418     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1421         // should we give a warning here? 
1422         return AddRoot(text
, image
, selImage
, data
); 
1425     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1427     wxGenericTreeItem 
*item 
= 
1428         new wxGenericTreeItem( parent
, text
, image
, selImage
, data 
); 
1432         data
->m_pItem 
= item
; 
1435     parent
->Insert( item
, previous 
== (size_t)-1 ? parent
->GetChildren().size() 
1441 wxTreeItemId 
wxGenericTreeCtrl::AddRoot(const wxString
& text
, 
1444                                         wxTreeItemData 
*data
) 
1446     wxCHECK_MSG( !m_anchor
, wxTreeItemId(), wxT("tree can have only one root") ); 
1448     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1450     m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, 
1451                                    image
, selImage
, data
); 
1454         data
->m_pItem 
= m_anchor
; 
1457     if (HasFlag(wxTR_HIDE_ROOT
)) 
1459         // if root is hidden, make sure we can navigate 
1461         m_anchor
->SetHasPlus(); 
1463         CalculatePositions(); 
1466     if (!HasFlag(wxTR_MULTIPLE
)) 
1468         m_current 
= m_key_current 
= m_anchor
; 
1469         m_current
->SetHilight( true ); 
1475 wxTreeItemId 
wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId
& parentId
, 
1476                                               const wxTreeItemId
& idPrevious
, 
1477                                               const wxString
& text
, 
1478                                               int image
, int selImage
, 
1479                                               wxTreeItemData 
*data
) 
1481     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1484         // should we give a warning here? 
1485         return AddRoot(text
, image
, selImage
, data
); 
1489     if (idPrevious
.IsOk()) 
1491         index 
= parent
->GetChildren().Index((wxGenericTreeItem
*) idPrevious
.m_pItem
); 
1492         wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
1493                       wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") ); 
1496     return DoInsertItem(parentId
, (size_t)++index
, text
, image
, selImage
, data
); 
1500 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
1502     wxTreeEvent 
event(wxEVT_COMMAND_TREE_DELETE_ITEM
, this, item
); 
1503     ProcessEvent( event 
); 
1506 // Don't leave edit or selection on a child which is about to disappear 
1507 void wxGenericTreeCtrl::ChildrenClosing(wxGenericTreeItem
* item
) 
1509     if (m_textCtrl 
!= NULL 
&& item 
!= m_textCtrl
->item() && IsDescendantOf(item
, m_textCtrl
->item())) { 
1510         m_textCtrl
->StopEditing(); 
1512     if (item 
!= m_key_current 
&& IsDescendantOf(item
, m_key_current
)) { 
1513         m_key_current 
= NULL
; 
1515     if (IsDescendantOf(item
, m_select_me
)) { 
1518     if (item 
!= m_current 
&& IsDescendantOf(item
, m_current
)) { 
1519         m_current
->SetHilight( false ); 
1525 void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
1527     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1529     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1530     ChildrenClosing(item
); 
1531     item
->DeleteChildren(this); 
1534 void wxGenericTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
1536     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1538     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1540     if (m_textCtrl 
!= NULL 
&& IsDescendantOf(item
, m_textCtrl
->item())) 
1542         // can't delete the item being edited, cancel editing it first 
1543         m_textCtrl
->StopEditing(); 
1546     wxGenericTreeItem 
*parent 
= item
->GetParent(); 
1548     // don't keep stale pointers around! 
1549     if ( IsDescendantOf(item
, m_key_current
) ) 
1551         // Don't silently change the selection: 
1552         // do it properly in idle time, so event 
1553         // handlers get called. 
1555         // m_key_current = parent; 
1556         m_key_current 
= NULL
; 
1559     // m_select_me records whether we need to select 
1560     // a different item, in idle time. 
1561     if ( m_select_me 
&& IsDescendantOf(item
, m_select_me
) ) 
1563         m_select_me 
= parent
; 
1566     if ( IsDescendantOf(item
, m_current
) ) 
1568         // Don't silently change the selection: 
1569         // do it properly in idle time, so event 
1570         // handlers get called. 
1572         // m_current = parent; 
1574         m_select_me 
= parent
; 
1577     // remove the item from the tree 
1580         parent
->GetChildren().Remove( item 
);  // remove by value 
1582     else // deleting the root 
1584         // nothing will be left in the tree 
1588     // and delete all of its children and the item itself now 
1589     item
->DeleteChildren(this); 
1590     SendDeleteEvent(item
); 
1592     if (item 
== m_select_me
) 
1598 void wxGenericTreeCtrl::DeleteAllItems() 
1606 void wxGenericTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
1608     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1610     wxCHECK_RET( item
, _T("invalid item in wxGenericTreeCtrl::Expand") ); 
1611     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1612                  _T("can't expand hidden root") ); 
1614     if ( !item
->HasPlus() ) 
1617     if ( item
->IsExpanded() ) 
1620     wxTreeEvent 
event(wxEVT_COMMAND_TREE_ITEM_EXPANDING
, this, item
); 
1622     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1624         // cancelled by program 
1629     CalculatePositions(); 
1631     RefreshSubtree(item
); 
1633     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
1634     ProcessEvent( event 
); 
1637 void wxGenericTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
1639     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1640                  _T("can't collapse hidden root") ); 
1642     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1644     if ( !item
->IsExpanded() ) 
1647     wxTreeEvent 
event(wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, this, item
); 
1648     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1650         // cancelled by program 
1654     ChildrenClosing(item
); 
1657 #if 0  // TODO why should items be collapsed recursively? 
1658     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1659     size_t count 
= children
.Count(); 
1660     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1662         Collapse(children
[n
]); 
1666     CalculatePositions(); 
1668     RefreshSubtree(item
); 
1670     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
1671     ProcessEvent( event 
); 
1674 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
1677     DeleteChildren(item
); 
1680 void wxGenericTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
1682     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1684     if (item
->IsExpanded()) 
1690 void wxGenericTreeCtrl::Unselect() 
1694         m_current
->SetHilight( false ); 
1695         RefreshLine( m_current 
); 
1702 void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem 
*item
) 
1704     if (item
->IsSelected()) 
1706         item
->SetHilight(false); 
1710     if (item
->HasChildren()) 
1712         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1713         size_t count 
= children
.Count(); 
1714         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1716             UnselectAllChildren(children
[n
]); 
1721 void wxGenericTreeCtrl::UnselectAll() 
1723     wxTreeItemId rootItem 
= GetRootItem(); 
1725     // the tree might not have the root item at all 
1728         UnselectAllChildren((wxGenericTreeItem
*) rootItem
.m_pItem
); 
1732 // Recursive function ! 
1733 // To stop we must have crt_item<last_item 
1735 // Tag all next children, when no more children, 
1736 // Move to parent (not to tag) 
1737 // Keep going... if we found last_item, we stop. 
1738 bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1740     wxGenericTreeItem 
*parent 
= crt_item
->GetParent(); 
1742     if (parent 
== NULL
) // This is root item 
1743         return TagAllChildrenUntilLast(crt_item
, last_item
, select
); 
1745     wxArrayGenericTreeItems
& children 
= parent
->GetChildren(); 
1746     int index 
= children
.Index(crt_item
); 
1747     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1749     size_t count 
= children
.Count(); 
1750     for (size_t n
=(size_t)(index
+1); n
<count
; ++n
) 
1752         if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return true; 
1755     return TagNextChildren(parent
, last_item
, select
); 
1758 bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1760     crt_item
->SetHilight(select
); 
1761     RefreshLine(crt_item
); 
1763     if (crt_item
==last_item
) 
1766     if (crt_item
->HasChildren()) 
1768         wxArrayGenericTreeItems
& children 
= crt_item
->GetChildren(); 
1769         size_t count 
= children
.Count(); 
1770         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1772             if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) 
1780 void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem 
*item1
, wxGenericTreeItem 
*item2
) 
1784     // item2 is not necessary after item1 
1785     // choice first' and 'last' between item1 and item2 
1786     wxGenericTreeItem 
*first
= (item1
->GetY()<item2
->GetY()) ? item1 
: item2
; 
1787     wxGenericTreeItem 
*last 
= (item1
->GetY()<item2
->GetY()) ? item2 
: item1
; 
1789     bool select 
= m_current
->IsSelected(); 
1791     if ( TagAllChildrenUntilLast(first
,last
,select
) ) 
1794     TagNextChildren(first
,last
,select
); 
1797 void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId
& itemId
, 
1798                                      bool unselect_others
, 
1799                                      bool extended_select
) 
1801     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1805     bool is_single
=!(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1806     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1808     //wxCHECK_RET( ( (!unselect_others) && is_single), 
1809     //           wxT("this is a single selection tree") ); 
1811     // to keep going anyhow !!! 
1814         if (item
->IsSelected()) 
1815             return; // nothing to do 
1816         unselect_others 
= true; 
1817         extended_select 
= false; 
1819     else if ( unselect_others 
&& item
->IsSelected() ) 
1821         // selection change if there is more than one item currently selected 
1822         wxArrayTreeItemIds selected_items
; 
1823         if ( GetSelections(selected_items
) == 1 ) 
1827     wxTreeEvent 
event(wxEVT_COMMAND_TREE_SEL_CHANGING
, this, item
); 
1828     event
.m_itemOld 
= m_current
; 
1829     // TODO : Here we don't send any selection mode yet ! 
1831     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
1834     wxTreeItemId parent 
= GetItemParent( itemId 
); 
1835     while (parent
.IsOk()) 
1837         if (!IsExpanded(parent
)) 
1840         parent 
= GetItemParent( parent 
); 
1844     if (unselect_others
) 
1846         if (is_single
) Unselect(); // to speed up thing 
1851     if (extended_select
) 
1855             m_current 
= m_key_current 
= (wxGenericTreeItem
*) GetRootItem().m_pItem
; 
1858         // don't change the mark (m_current) 
1859         SelectItemRange(m_current
, item
); 
1863         bool select 
= true; // the default 
1865         // Check if we need to toggle hilight (ctrl mode) 
1866         if (!unselect_others
) 
1867             select
=!item
->IsSelected(); 
1869         m_current 
= m_key_current 
= item
; 
1870         m_current
->SetHilight(select
); 
1871         RefreshLine( m_current 
); 
1874     // This can cause idle processing to select the root 
1875     // if no item is selected, so it must be after the 
1877     EnsureVisible( itemId 
); 
1879     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
1880     GetEventHandler()->ProcessEvent( event 
); 
1883 void wxGenericTreeCtrl::SelectItem(const wxTreeItemId
& itemId
, bool select
) 
1887         DoSelectItem(itemId
, !HasFlag(wxTR_MULTIPLE
)); 
1891         wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1892         wxCHECK_RET( item
, wxT("SelectItem(): invalid tree item") ); 
1894         item
->SetHilight(false); 
1899 void wxGenericTreeCtrl::FillArray(wxGenericTreeItem 
*item
, 
1900                                   wxArrayTreeItemIds 
&array
) const 
1902     if ( item
->IsSelected() ) 
1903         array
.Add(wxTreeItemId(item
)); 
1905     if ( item
->HasChildren() ) 
1907         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1908         size_t count 
= children
.GetCount(); 
1909         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1910             FillArray(children
[n
], array
); 
1914 size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds 
&array
) const 
1917     wxTreeItemId idRoot 
= GetRootItem(); 
1918     if ( idRoot
.IsOk() ) 
1920         FillArray((wxGenericTreeItem
*) idRoot
.m_pItem
, array
); 
1922     //else: the tree is empty, so no selections 
1924     return array
.Count(); 
1927 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
1929     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1931     if (!item
.IsOk()) return; 
1933     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1935     // first expand all parent branches 
1936     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
1938     if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1940         while ( parent 
&& parent 
!= m_anchor 
) 
1943             parent 
= parent
->GetParent(); 
1951             parent 
= parent
->GetParent(); 
1955     //if (parent) CalculatePositions(); 
1960 void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId 
&item
) 
1962     if (!item
.IsOk()) return; 
1964     // We have to call this here because the label in 
1965     // question might just have been added and no screen 
1966     // update taken place. 
1968 #if defined( __WXMSW__ ) || defined(__WXMAC__) 
1971         DoDirtyProcessing(); 
1973     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1975     // now scroll to the item 
1976     int item_y 
= gitem
->GetY(); 
1980     GetViewStart( &start_x
, &start_y 
); 
1981     start_y 
*= PIXELS_PER_UNIT
; 
1985     GetClientSize( &client_w
, &client_h 
); 
1987     if (item_y 
< start_y
+3) 
1992         m_anchor
->GetSize( x
, y
, this ); 
1993         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1994         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1995         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1996         // Item should appear at top 
1997         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, item_y
/PIXELS_PER_UNIT 
); 
1999     else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) 
2004         m_anchor
->GetSize( x
, y
, this ); 
2005         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2006         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2007         item_y 
+= PIXELS_PER_UNIT
+2; 
2008         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2009         // Item should appear at bottom 
2010         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 
); 
2014 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
2015 static wxGenericTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
2017 static int LINKAGEMODE 
tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
2018                                   wxGenericTreeItem 
**item2
) 
2020     wxCHECK_MSG( s_treeBeingSorted
, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") ); 
2022     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
2025 void wxGenericTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
2027     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
2029     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
2031     wxCHECK_RET( !s_treeBeingSorted
, 
2032                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") ); 
2034     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2035     if ( children
.Count() > 1 ) 
2039         s_treeBeingSorted 
= this; 
2040         children
.Sort(tree_ctrl_compare_func
); 
2041         s_treeBeingSorted 
= NULL
; 
2043     //else: don't make the tree dirty as nothing changed 
2046 void wxGenericTreeCtrl::CalculateLineHeight() 
2048     wxClientDC 
dc(this); 
2049     m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
2051     if ( m_imageListNormal 
) 
2053         // Calculate a m_lineHeight value from the normal Image sizes. 
2054         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2055         // necessary (which might look ugly). 
2056         int n 
= m_imageListNormal
->GetImageCount(); 
2057         for (int i 
= 0; i 
< n 
; i
++) 
2059             int width 
= 0, height 
= 0; 
2060             m_imageListNormal
->GetSize(i
, width
, height
); 
2061             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2065     if (m_imageListButtons
) 
2067         // Calculate a m_lineHeight value from the Button image sizes. 
2068         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2069         // necessary (which might look ugly). 
2070         int n 
= m_imageListButtons
->GetImageCount(); 
2071         for (int i 
= 0; i 
< n 
; i
++) 
2073             int width 
= 0, height 
= 0; 
2074             m_imageListButtons
->GetSize(i
, width
, height
); 
2075             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2079     if (m_lineHeight 
< 30) 
2080         m_lineHeight 
+= 2;                 // at least 2 pixels 
2082         m_lineHeight 
+= m_lineHeight
/10;   // otherwise 10% extra spacing 
2085 void wxGenericTreeCtrl::SetImageList(wxImageList 
*imageList
) 
2087     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
2088     m_imageListNormal 
= imageList
; 
2089     m_ownsImageListNormal 
= false; 
2091     // Don't do any drawing if we're setting the list to NULL, 
2092     // since we may be in the process of deleting the tree control. 
2094         CalculateLineHeight(); 
2097 void wxGenericTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
2099     if (m_ownsImageListState
) delete m_imageListState
; 
2100     m_imageListState 
= imageList
; 
2101     m_ownsImageListState 
= false; 
2104 void wxGenericTreeCtrl::SetButtonsImageList(wxImageList 
*imageList
) 
2106     if (m_ownsImageListButtons
) delete m_imageListButtons
; 
2107     m_imageListButtons 
= imageList
; 
2108     m_ownsImageListButtons 
= false; 
2110     CalculateLineHeight(); 
2113 void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList 
*imageList
) 
2115     SetButtonsImageList(imageList
); 
2116     m_ownsImageListButtons 
= true; 
2119 // ----------------------------------------------------------------------------- 
2121 // ----------------------------------------------------------------------------- 
2123 void wxGenericTreeCtrl::AdjustMyScrollbars() 
2128         m_anchor
->GetSize( x
, y
, this ); 
2129         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2130         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2131         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2132         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
2133         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, y_pos 
); 
2137         SetScrollbars( 0, 0, 0, 0 ); 
2141 int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem 
*item
) const 
2143     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
2144         return item
->GetHeight(); 
2146         return m_lineHeight
; 
2149 void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
2151     // TODO implement "state" icon on items 
2153     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2154     if ( attr 
&& attr
->HasFont() ) 
2155         dc
.SetFont(attr
->GetFont()); 
2156     else if (item
->IsBold()) 
2157         dc
.SetFont(m_boldFont
); 
2159     long text_w 
= 0, text_h 
= 0; 
2160     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
2162     int image_h 
= 0, image_w 
= 0; 
2163     int image 
= item
->GetCurrentImage(); 
2164     if ( image 
!= NO_IMAGE 
) 
2166         if ( m_imageListNormal 
) 
2168             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
2169             image_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
2177     int total_h 
= GetLineHeight(item
); 
2178     bool drawItemBackground 
= false; 
2180     if ( item
->IsSelected() ) 
2182 // under mac selections are only a rectangle in case they don't have the focus 
2186             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
) ; 
2187             dc
.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT 
) , 1 , wxSOLID 
) ) ; 
2191             dc
.SetBrush( *m_hilightBrush 
) ; 
2194         dc
.SetBrush(*(m_hasFocus 
? m_hilightBrush 
: m_hilightUnfocusedBrush
)); 
2196         drawItemBackground 
= true; 
2201         if ( attr 
&& attr
->HasBackgroundColour() ) 
2203             drawItemBackground 
= true; 
2204             colBg 
= attr
->GetBackgroundColour(); 
2208             colBg 
= GetBackgroundColour(); 
2210         dc
.SetBrush(wxBrush(colBg
, wxSOLID
)); 
2213     int offset 
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0; 
2215     if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT
) ) 
2219         DoGetPosition(&x
, &y
); 
2221         dc
.DrawRectangle(x
, item
->GetY()+offset
, w
, total_h
-offset
); 
2225         if ( item
->IsSelected() && image 
!= NO_IMAGE 
) 
2227             // If it's selected, and there's an image, then we should 
2228             // take care to leave the area under the image painted in the 
2229             // background colour. 
2230             dc
.DrawRectangle( item
->GetX() + image_w 
- 2, item
->GetY()+offset
, 
2231                               item
->GetWidth() - image_w 
+ 2, total_h
-offset 
); 
2233         // On GTK+ 2, drawing a 'normal' background is wrong for themes that 
2234         // don't allow backgrounds to be customized. Not drawing the background, 
2235         // except for custom item backgrounds, works for both kinds of theme. 
2236         else if (drawItemBackground
) 
2238             dc
.DrawRectangle( item
->GetX()-2, item
->GetY()+offset
, 
2239                               item
->GetWidth()+2, total_h
-offset 
); 
2243     if ( image 
!= NO_IMAGE 
) 
2245         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
2246         m_imageListNormal
->Draw( image
, dc
, 
2248                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
2249                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
2250         dc
.DestroyClippingRegion(); 
2253     dc
.SetBackgroundMode(wxTRANSPARENT
); 
2254     int extraH 
= (total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0; 
2255     dc
.DrawText( item
->GetText(), 
2256                  (wxCoord
)(image_w 
+ item
->GetX()), 
2257                  (wxCoord
)(item
->GetY() + extraH
)); 
2259     // restore normal font 
2260     dc
.SetFont( m_normalFont 
); 
2263 // Now y stands for the top of the item, whereas it used to stand for middle ! 
2264 void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
2266     int x 
= level
*m_indent
; 
2267     if (!HasFlag(wxTR_HIDE_ROOT
)) 
2271     else if (level 
== 0) 
2273         // always expand hidden root 
2275         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2276         int count 
= children
.Count(); 
2282                 PaintLevel(children
[n
], dc
, 1, y
); 
2283             } while (++n 
< count
); 
2285             if (!HasFlag(wxTR_NO_LINES
) && HasFlag(wxTR_LINES_AT_ROOT
) && count 
> 0) 
2287                 // draw line down to last child 
2288                 origY 
+= GetLineHeight(children
[0])>>1; 
2289                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2290                 dc
.DrawLine(3, origY
, 3, oldY
); 
2296     item
->SetX(x
+m_spacing
); 
2299     int h 
= GetLineHeight(item
); 
2301     int y_mid 
= y_top 
+ (h
>>1); 
2304     int exposed_x 
= dc
.LogicalToDeviceX(0); 
2305     int exposed_y 
= dc
.LogicalToDeviceY(y_top
); 
2307     if (IsExposed(exposed_x
, exposed_y
, 10000, h
))  // 10000 = very much 
2311             // don't draw rect outline if we already have the 
2312             // background color under Mac 
2313             (item
->IsSelected() && m_hasFocus
) ? wxBLACK_PEN 
: 
2314 #endif // !__WXMAC__ 
2318         if ( item
->IsSelected() 
2320             // On wxMac, if the tree doesn't have the focus we draw an empty 
2321             // rectangle, so we want to make sure that the text is visible 
2322             // against the normal background, not the highlightbackground, so 
2323             // don't use the highlight text colour unless we have the focus. 
2328             colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
2332             wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2333             if (attr 
&& attr
->HasTextColour()) 
2334                 colText 
= attr
->GetTextColour(); 
2336                 colText 
= GetForegroundColour(); 
2340         dc
.SetTextForeground(colText
); 
2344         PaintItem(item
, dc
); 
2346         if (HasFlag(wxTR_ROW_LINES
)) 
2348             // if the background colour is white, choose a 
2349             // contrasting color for the lines 
2350             dc
.SetPen(*((GetBackgroundColour() == *wxWHITE
) 
2351                          ? wxMEDIUM_GREY_PEN 
: wxWHITE_PEN
)); 
2352             dc
.DrawLine(0, y_top
, 10000, y_top
); 
2353             dc
.DrawLine(0, y
, 10000, y
); 
2356         // restore DC objects 
2357         dc
.SetBrush(*wxWHITE_BRUSH
); 
2358         dc
.SetPen(m_dottedPen
); 
2359         dc
.SetTextForeground(*wxBLACK
); 
2361         if ( !HasFlag(wxTR_NO_LINES
) ) 
2363             // draw the horizontal line here 
2365             if (x 
> (signed)m_indent
) 
2366                 x_start 
-= m_indent
; 
2367             else if (HasFlag(wxTR_LINES_AT_ROOT
)) 
2369             dc
.DrawLine(x_start
, y_mid
, x 
+ m_spacing
, y_mid
); 
2372         // should the item show a button? 
2373         if ( item
->HasPlus() && HasButtons() ) 
2375             if ( m_imageListButtons 
) 
2377                 // draw the image button here 
2380                 int image 
= item
->IsExpanded() ? wxTreeItemIcon_Expanded
 
2381                                                : wxTreeItemIcon_Normal
; 
2382                 if ( item
->IsSelected() ) 
2383                     image 
+= wxTreeItemIcon_Selected 
- wxTreeItemIcon_Normal
; 
2385                 m_imageListButtons
->GetSize(image
, image_w
, image_h
); 
2386                 int xx 
= x 
- image_w
/2; 
2387                 int yy 
= y_mid 
- image_h
/2; 
2389                 wxDCClipper 
clip(dc
, xx
, yy
, image_w
, image_h
); 
2390                 wxPrintf( wxT("hi\n") ); 
2391                 m_imageListButtons
->Draw(image
, dc
, xx
, yy
, 
2392                                          wxIMAGELIST_DRAW_TRANSPARENT
); 
2394             else // no custom buttons 
2396                 static const int wImage 
= 9; 
2397                 static const int hImage 
= 9; 
2400                 if (item
->IsExpanded()) 
2401                     flag 
|= wxCONTROL_EXPANDED
; 
2402                 if (item 
== m_underMouse
) 
2403                     flag 
|= wxCONTROL_CURRENT
; 
2405                 wxRendererNative::Get().DrawTreeItemButton
 
2409                                             wxRect(x 
- wImage
/2, 
2418     if (item
->IsExpanded()) 
2420         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2421         int count 
= children
.Count(); 
2428                 PaintLevel(children
[n
], dc
, level
, y
); 
2429             } while (++n 
< count
); 
2431             if (!HasFlag(wxTR_NO_LINES
) && count 
> 0) 
2433                 // draw line down to last child 
2434                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2435                 if (HasButtons()) y_mid 
+= 5; 
2437                 // Only draw the portion of the line that is visible, in case it is huge 
2438                 wxCoord xOrigin
=0, yOrigin
=0, width
, height
; 
2439                 dc
.GetDeviceOrigin(&xOrigin
, &yOrigin
); 
2440                 yOrigin 
= abs(yOrigin
); 
2441                 GetClientSize(&width
, &height
); 
2443                 // Move end points to the begining/end of the view? 
2444                 if (y_mid 
< yOrigin
) 
2446                 if (oldY 
> yOrigin 
+ height
) 
2447                     oldY 
= yOrigin 
+ height
; 
2449                 // after the adjustments if y_mid is larger than oldY then the line 
2450                 // isn't visible at all so don't draw anything 
2452                     dc
.DrawLine(x
, y_mid
, x
, oldY
); 
2458 void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem 
*item
) 
2462         if ( item
->HasPlus() ) 
2464             // it's a folder, indicate it by a border 
2469             // draw a line under the drop target because the item will be 
2471             DrawLine(item
, !m_dropEffectAboveItem 
); 
2474         SetCursor(wxCURSOR_BULLSEYE
); 
2479         SetCursor(wxCURSOR_NO_ENTRY
); 
2483 void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId 
&item
) 
2485     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2487     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2489     wxClientDC 
dc(this); 
2491     dc
.SetLogicalFunction(wxINVERT
); 
2492     dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
2494     int w 
= i
->GetWidth() + 2; 
2495     int h 
= GetLineHeight(i
) + 2; 
2497     dc
.DrawRectangle( i
->GetX() - 1, i
->GetY() - 1, w
, h
); 
2500 void wxGenericTreeCtrl::DrawLine(const wxTreeItemId 
&item
, bool below
) 
2502     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2504     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2506     wxClientDC 
dc(this); 
2508     dc
.SetLogicalFunction(wxINVERT
); 
2514         y 
+= GetLineHeight(i
) - 1; 
2517     dc
.DrawLine( x
, y
, x 
+ i
->GetWidth(), y
); 
2520 // ----------------------------------------------------------------------------- 
2521 // wxWidgets callbacks 
2522 // ----------------------------------------------------------------------------- 
2524 void wxGenericTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2532     dc
.SetFont( m_normalFont 
); 
2533     dc
.SetPen( m_dottedPen 
); 
2535     // this is now done dynamically 
2536     //if(GetImageList() == NULL) 
2537     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
2540     PaintLevel( m_anchor
, dc
, 0, y 
); 
2543 void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent 
&event 
) 
2552 void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2561 void wxGenericTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
2563     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, this); 
2564     te
.m_evtKey 
= event
; 
2565     if ( GetEventHandler()->ProcessEvent( te 
) ) 
2567         // intercepted by the user code 
2571     if ( (m_current 
== 0) || (m_key_current 
== 0) ) 
2577     // how should the selection work for this event? 
2578     bool is_multiple
, extended_select
, unselect_others
; 
2579     EventFlagsToSelType(GetWindowStyleFlag(), 
2582                         is_multiple
, extended_select
, unselect_others
); 
2584     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
2586         if (event
.GetKeyCode() == WXK_RIGHT
) 
2587             event
.m_keyCode 
= WXK_LEFT
; 
2588         else if (event
.GetKeyCode() == WXK_LEFT
) 
2589             event
.m_keyCode 
= WXK_RIGHT
; 
2594     // * : Expand all/Collapse all 
2595     // ' ' | return : activate 
2596     // up    : go up (not last children!) 
2598     // left  : go to parent 
2599     // right : open if parent and go next 
2600     // home  : go to root 
2601     // end   : go to last item without opening parents 
2602     // alnum : start or continue searching for the item with this prefix 
2603     int keyCode 
= event
.GetKeyCode(); 
2608             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
2616             if ( !IsExpanded(m_current
) ) 
2619                 ExpandAllChildren(m_current
); 
2622             //else: fall through to Collapse() it 
2626             if (IsExpanded(m_current
)) 
2628                 Collapse(m_current
); 
2634                 // Use the item's bounding rectangle to determine position for the event 
2636                 GetBoundingRect(m_current
, ItemRect
, true); 
2638                 wxTreeEvent 
eventMenu(wxEVT_COMMAND_TREE_ITEM_MENU
, this, m_current
); 
2639                 // Use the left edge, vertical middle 
2640                 eventMenu
.m_pointDrag 
= wxPoint(ItemRect
.GetX(), 
2641                                                 ItemRect
.GetY() + ItemRect
.GetHeight() / 2); 
2642                 GetEventHandler()->ProcessEvent( eventMenu 
); 
2648             if ( !event
.HasModifiers() ) 
2650                 wxTreeEvent 
eventAct(wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, this, m_current
); 
2651                 GetEventHandler()->ProcessEvent( eventAct 
); 
2654             // in any case, also generate the normal key event for this key, 
2655             // even if we generated the ACTIVATED event above: this is what 
2656             // wxMSW does and it makes sense because you might not want to 
2657             // process ACTIVATED event at all and handle Space and Return 
2658             // directly (and differently) which would be impossible otherwise 
2662             // up goes to the previous sibling or to the last 
2663             // of its children if it's expanded 
2666                 wxTreeItemId prev 
= GetPrevSibling( m_key_current 
); 
2669                     prev 
= GetItemParent( m_key_current 
); 
2670                     if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2672                         break;  // don't go to root if it is hidden 
2676                         wxTreeItemIdValue cookie
; 
2677                         wxTreeItemId current 
= m_key_current
; 
2678                         // TODO: Huh?  If we get here, we'd better be the first child of our parent.  How else could it be? 
2679                         if (current 
== GetFirstChild( prev
, cookie 
)) 
2681                             // otherwise we return to where we came from 
2682                             DoSelectItem( prev
, unselect_others
, extended_select 
); 
2683                             m_key_current
= (wxGenericTreeItem
*) prev
.m_pItem
; 
2690                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
2692                         wxTreeItemId child 
= GetLastChild(prev
); 
2699                     DoSelectItem( prev
, unselect_others
, extended_select 
); 
2700                     m_key_current
=(wxGenericTreeItem
*) prev
.m_pItem
; 
2705             // left arrow goes to the parent 
2708                 wxTreeItemId prev 
= GetItemParent( m_current 
); 
2709                 if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2711                     // don't go to root if it is hidden 
2712                     prev 
= GetPrevSibling( m_current 
); 
2716                     DoSelectItem( prev
, unselect_others
, extended_select 
); 
2722             // this works the same as the down arrow except that we 
2723             // also expand the item if it wasn't expanded yet 
2729                 if (IsExpanded(m_key_current
) && HasChildren(m_key_current
)) 
2731                     wxTreeItemIdValue cookie
; 
2732                     wxTreeItemId child 
= GetFirstChild( m_key_current
, cookie 
); 
2733                     DoSelectItem( child
, unselect_others
, extended_select 
); 
2734                     m_key_current
=(wxGenericTreeItem
*) child
.m_pItem
; 
2738                     wxTreeItemId next 
= GetNextSibling( m_key_current 
); 
2741                         wxTreeItemId current 
= m_key_current
; 
2742                         while (current
.IsOk() && !next
) 
2744                             current 
= GetItemParent( current 
); 
2745                             if (current
) next 
= GetNextSibling( current 
); 
2750                         DoSelectItem( next
, unselect_others
, extended_select 
); 
2751                         m_key_current
=(wxGenericTreeItem
*) next
.m_pItem
; 
2757             // <End> selects the last visible tree item 
2760                 wxTreeItemId last 
= GetRootItem(); 
2762                 while ( last
.IsOk() && IsExpanded(last
) ) 
2764                     wxTreeItemId lastChild 
= GetLastChild(last
); 
2766                     // it may happen if the item was expanded but then all of 
2767                     // its children have been deleted - so IsExpanded() returned 
2768                     // true, but GetLastChild() returned invalid item 
2777                     DoSelectItem( last
, unselect_others
, extended_select 
); 
2782             // <Home> selects the root item 
2785                 wxTreeItemId prev 
= GetRootItem(); 
2789                 if ( HasFlag(wxTR_HIDE_ROOT
) ) 
2791                     wxTreeItemIdValue cookie
; 
2792                     prev 
= GetFirstChild(prev
, cookie
); 
2797                 DoSelectItem( prev
, unselect_others
, extended_select 
); 
2802             // do not use wxIsalnum() here 
2803             if ( !event
.HasModifiers() && 
2804                  ((keyCode 
>= '0' && keyCode 
<= '9') || 
2805                   (keyCode 
>= 'a' && keyCode 
<= 'z') || 
2806                   (keyCode 
>= 'A' && keyCode 
<= 'Z' ))) 
2808                 // find the next item starting with the given prefix 
2809                 wxChar ch 
= (wxChar
)keyCode
; 
2811                 wxTreeItemId id 
= FindItem(m_current
, m_findPrefix 
+ ch
); 
2822                 // also start the timer to reset the current prefix if the user 
2823                 // doesn't press any more alnum keys soon -- we wouldn't want 
2824                 // to use this prefix for a new item search 
2827                     m_findTimer 
= new wxTreeFindTimer(this); 
2830                 m_findTimer
->Start(wxTreeFindTimer::DELAY
, wxTIMER_ONE_SHOT
); 
2840 wxGenericTreeCtrl::DoTreeHitTest(const wxPoint
& point
, int& flags
) const 
2845     if (point
.x
<0) flags 
|= wxTREE_HITTEST_TOLEFT
; 
2846     if (point
.x
>w
) flags 
|= wxTREE_HITTEST_TORIGHT
; 
2847     if (point
.y
<0) flags 
|= wxTREE_HITTEST_ABOVE
; 
2848     if (point
.y
>h
) flags 
|= wxTREE_HITTEST_BELOW
; 
2849     if (flags
) return wxTreeItemId(); 
2851     if (m_anchor 
== NULL
) 
2853         flags 
= wxTREE_HITTEST_NOWHERE
; 
2854         return wxTreeItemId(); 
2857     wxGenericTreeItem 
*hit 
=  m_anchor
->HitTest(CalcUnscrolledPosition(point
), 
2861         flags 
= wxTREE_HITTEST_NOWHERE
; 
2862         return wxTreeItemId(); 
2867 // get the bounding rectangle of the item (or of its label only) 
2868 bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
, 
2870                                         bool textOnly
) const 
2872     wxCHECK_MSG( item
.IsOk(), false, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") ); 
2874     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2879         rect
.width 
= i
->GetWidth(); 
2881         if ( m_imageListNormal 
) 
2883             int image_w
, image_h
; 
2884             m_imageListNormal
->GetSize( 0, image_w
, image_h 
); 
2885             rect
.width 
+= image_w 
+ MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
2888     else // the entire line 
2891         rect
.width 
= GetClientSize().x
; 
2895     rect
.height 
= GetLineHeight(i
); 
2897     // we have to return the logical coordinates, not physical ones 
2898     rect
.SetTopLeft(CalcScrolledPosition(rect
.GetTopLeft())); 
2903 wxTextCtrl 
*wxGenericTreeCtrl::EditLabel(const wxTreeItemId
& item
, 
2904                                   wxClassInfo 
* WXUNUSED(textCtrlClass
)) 
2906     wxCHECK_MSG( item
.IsOk(), NULL
, _T("can't edit an invalid item") ); 
2908     wxGenericTreeItem 
*itemEdit 
= (wxGenericTreeItem 
*)item
.m_pItem
; 
2910     wxTreeEvent 
te(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, this, itemEdit
); 
2911     if ( GetEventHandler()->ProcessEvent( te 
) && !te
.IsAllowed() ) 
2917     // We have to call this here because the label in 
2918     // question might just have been added and no screen 
2919     // update taken place. 
2921 #if defined( __WXMSW__ ) || defined(__WXMAC__) 
2924         DoDirtyProcessing(); 
2927     // TODO: use textCtrlClass here to create the control of correct class 
2928     m_textCtrl 
= new wxTreeTextCtrl(this, itemEdit
); 
2930     m_textCtrl
->SetFocus(); 
2935 // returns a pointer to the text edit control if the item is being 
2936 // edited, NULL otherwise (it's assumed that no more than one item may 
2937 // be edited simultaneously) 
2938 wxTextCtrl
* wxGenericTreeCtrl::GetEditControl() const 
2943 void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId
& WXUNUSED(item
), 
2944                                      bool discardChanges
) 
2946     wxCHECK_RET( m_textCtrl
, _T("not editing label") ); 
2948     m_textCtrl
->EndEdit(discardChanges
); 
2951 bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem 
*item
, 
2952                                        const wxString
& value
) 
2954     wxTreeEvent 
le(wxEVT_COMMAND_TREE_END_LABEL_EDIT
, this, item
); 
2956     le
.m_editCancelled 
= false; 
2958     return !GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
2961 void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem 
*item
) 
2963     // let owner know that the edit was cancelled 
2964     wxTreeEvent 
le(wxEVT_COMMAND_TREE_END_LABEL_EDIT
, this, item
); 
2965     le
.m_label 
= wxEmptyString
; 
2966     le
.m_editCancelled 
= true; 
2968     GetEventHandler()->ProcessEvent( le 
); 
2971 void wxGenericTreeCtrl::OnRenameTimer() 
2973     EditLabel( m_current 
); 
2976 void wxGenericTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
2978     if ( !m_anchor 
)return; 
2980     wxPoint pt 
= CalcUnscrolledPosition(event
.GetPosition()); 
2982     // Is the mouse over a tree item button? 
2984     wxGenericTreeItem 
*thisItem 
= m_anchor
->HitTest(pt
, this, flags
, 0); 
2985     wxGenericTreeItem 
*underMouse 
= thisItem
; 
2987     bool underMouseChanged 
= (underMouse 
!= m_underMouse
) ; 
2988 #endif // wxUSE_TOOLTIPS 
2991         (flags 
& wxTREE_HITTEST_ONITEMBUTTON
) && 
2992         (!event
.LeftIsDown()) && 
2994         (!m_renameTimer 
|| !m_renameTimer
->IsRunning())) 
3002     if (underMouse 
!= m_underMouse
) 
3006             // unhighlight old item 
3007             wxGenericTreeItem 
*tmp 
= m_underMouse
; 
3008             m_underMouse 
= NULL
; 
3012          m_underMouse 
= underMouse
; 
3014             RefreshLine( m_underMouse 
); 
3018     // Determines what item we are hovering over and need a tooltip for 
3019     wxTreeItemId hoverItem 
= thisItem
; 
3021     // We do not want a tooltip if we are dragging, or if the rename timer is running 
3022     if (underMouseChanged 
&& hoverItem
.IsOk() && !m_isDragging 
&& (!m_renameTimer 
|| !m_renameTimer
->IsRunning())) 
3024         // Ask the tree control what tooltip (if any) should be shown 
3025         wxTreeEvent 
hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP
,  this, hoverItem
); 
3027         if ( GetEventHandler()->ProcessEvent(hevent
) && hevent
.IsAllowed() ) 
3029             SetToolTip(hevent
.m_label
); 
3034     // we process left mouse up event (enables in-place edit), middle/right down 
3035     // (pass to the user code), left dbl click (activate item) and 
3036     // dragging/moving events for items drag-and-drop 
3037     if ( !(event
.LeftDown() || 
3039            event
.MiddleDown() || 
3040            event
.RightDown() || 
3041            event
.LeftDClick() || 
3043            ((event
.Moving() || event
.RightUp()) && m_isDragging
)) ) 
3052     wxGenericTreeItem 
*item 
= m_anchor
->HitTest(pt
, this, flags
, 0); 
3054     if ( event
.Dragging() && !m_isDragging 
) 
3056         if (m_dragCount 
== 0) 
3061         if (m_dragCount 
!= 3) 
3063             // wait until user drags a bit further... 
3067         wxEventType command 
= event
.RightIsDown() 
3068                               ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
 
3069                               : wxEVT_COMMAND_TREE_BEGIN_DRAG
; 
3071         wxTreeEvent 
nevent(command
,  this, m_current
); 
3072         nevent
.SetPoint(CalcScrolledPosition(pt
)); 
3074         // by default the dragging is not supported, the user code must 
3075         // explicitly allow the event for it to take place 
3078         if ( GetEventHandler()->ProcessEvent(nevent
) && nevent
.IsAllowed() ) 
3080             // we're going to drag this item 
3081             m_isDragging 
= true; 
3083             // remember the old cursor because we will change it while 
3085             m_oldCursor 
= m_cursor
; 
3087             // in a single selection control, hide the selection temporarily 
3088             if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE
) ) 
3090                 m_oldSelection 
= (wxGenericTreeItem
*) GetSelection().m_pItem
; 
3092                 if ( m_oldSelection 
) 
3094                     m_oldSelection
->SetHilight(false); 
3095                     RefreshLine(m_oldSelection
); 
3102     else if ( event
.Dragging() ) 
3104         if ( item 
!= m_dropTarget 
) 
3106             // unhighlight the previous drop target 
3107             DrawDropEffect(m_dropTarget
); 
3109             m_dropTarget 
= item
; 
3111             // highlight the current drop target if any 
3112             DrawDropEffect(m_dropTarget
); 
3114 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__) 
3121     else if ( (event
.LeftUp() || event
.RightUp()) && m_isDragging 
) 
3125         // erase the highlighting 
3126         DrawDropEffect(m_dropTarget
); 
3128         if ( m_oldSelection 
) 
3130             m_oldSelection
->SetHilight(true); 
3131             RefreshLine(m_oldSelection
); 
3132             m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
3135         // generate the drag end event 
3136         wxTreeEvent 
eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG
,  this, item
); 
3138         eventEndDrag
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3140         (void)GetEventHandler()->ProcessEvent(eventEndDrag
); 
3142         m_isDragging 
= false; 
3143         m_dropTarget 
= (wxGenericTreeItem 
*)NULL
; 
3145         SetCursor(m_oldCursor
); 
3147 #if defined( __WXMSW__ ) || defined(__WXMAC__) 
3155         // If we got to this point, we are not dragging or moving the mouse. 
3156         // Because the code in carbon/toplevel.cpp will only set focus to the tree 
3157         // if we skip for EVT_LEFT_DOWN, we MUST skip this event here for focus to work. 
3158         // We skip even if we didn't hit an item because we still should 
3159         // restore focus to the tree control even if we didn't exactly hit an item. 
3160         if ( event
.LeftDown() ) 
3165         // here we process only the messages which happen on tree items 
3169         if (item 
== NULL
) return;  /* we hit the blank area */ 
3171         if ( event
.RightDown() ) 
3173             // If the item is already selected, do not update the selection. 
3174             // Multi-selections should not be cleared if a selected item is clicked. 
3175             if (!IsSelected(item
)) 
3177                 DoSelectItem(item
, true, false); 
3180             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
,  this, item
); 
3181             nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3182             event
.Skip(!GetEventHandler()->ProcessEvent(nevent
)); 
3184             // Consistent with MSW (for now), send the ITEM_MENU *after* 
3185             // the RIGHT_CLICK event. TODO: This behavior may change. 
3186             wxTreeEvent 
nevent2(wxEVT_COMMAND_TREE_ITEM_MENU
,  this, item
); 
3187             nevent2
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3188             GetEventHandler()->ProcessEvent(nevent2
); 
3190         else if ( event
.MiddleDown() ) 
3192             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK
,  this, item
); 
3193             nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3194             event
.Skip(!GetEventHandler()->ProcessEvent(nevent
)); 
3196         else if ( event
.LeftUp() ) 
3198             // this facilitates multiple-item drag-and-drop 
3200             if ( /* item && */ HasFlag(wxTR_MULTIPLE
)) 
3202                 wxArrayTreeItemIds selections
; 
3203                 size_t count 
= GetSelections(selections
); 
3209                     DoSelectItem(item
, true, false); 
3215                 if ( (item 
== m_current
) && 
3216                      (flags 
& wxTREE_HITTEST_ONITEMLABEL
) && 
3217                      HasFlag(wxTR_EDIT_LABELS
) ) 
3219                     if ( m_renameTimer 
) 
3221                         if ( m_renameTimer
->IsRunning() ) 
3222                             m_renameTimer
->Stop(); 
3226                         m_renameTimer 
= new wxTreeRenameTimer( this ); 
3229                     m_renameTimer
->Start( wxTreeRenameTimer::DELAY
, true ); 
3232                 m_lastOnSame 
= false; 
3235         else // !RightDown() && !MiddleDown() && !LeftUp() ==> LeftDown() || LeftDClick() 
3237             if ( event
.LeftDown() ) 
3239                 m_lastOnSame 
= item 
== m_current
; 
3242             if ( flags 
& wxTREE_HITTEST_ONITEMBUTTON 
) 
3244                 // only toggle the item for a single click, double click on 
3245                 // the button doesn't do anything (it toggles the item twice) 
3246                 if ( event
.LeftDown() ) 
3251                 // don't select the item if the button was clicked 
3256             // clear the previously selected items, if the 
3257             // user clicked outside of the present selection. 
3258             // otherwise, perform the deselection on mouse-up. 
3259             // this allows multiple drag and drop to work. 
3260             // but if Cmd is down, toggle selection of the clicked item 
3261             if (!IsSelected(item
) || event
.CmdDown()) 
3263                 // how should the selection work for this event? 
3264                 bool is_multiple
, extended_select
, unselect_others
; 
3265                 EventFlagsToSelType(GetWindowStyleFlag(), 
3268                                     is_multiple
, extended_select
, unselect_others
); 
3270                 DoSelectItem(item
, unselect_others
, extended_select
); 
3274             // For some reason, Windows isn't recognizing a left double-click, 
3275             // so we need to simulate it here.  Allow 200 milliseconds for now. 
3276             if ( event
.LeftDClick() ) 
3278                 // double clicking should not start editing the item label 
3279                 if ( m_renameTimer 
) 
3280                     m_renameTimer
->Stop(); 
3282                 m_lastOnSame 
= false; 
3284                 // send activate event first 
3285                 wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED
,  this, item
); 
3286                 nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3287                 if ( !GetEventHandler()->ProcessEvent( nevent 
) ) 
3289                     // if the user code didn't process the activate event, 
3290                     // handle it ourselves by toggling the item when it is 
3292                     if ( item
->HasPlus() ) 
3302 void wxGenericTreeCtrl::OnInternalIdle() 
3304     wxWindow::OnInternalIdle(); 
3306     // Check if we need to select the root item 
3307     // because nothing else has been selected. 
3308     // Delaying it means that we can invoke event handlers 
3309     // as required, when a first item is selected. 
3310     if (!HasFlag(wxTR_MULTIPLE
) && !GetSelection().IsOk()) 
3313             SelectItem(m_select_me
); 
3314         else if (GetRootItem().IsOk()) 
3315             SelectItem(GetRootItem()); 
3318     // after all changes have been done to the tree control, 
3319     // actually redraw the tree when everything is over 
3321         DoDirtyProcessing(); 
3324 void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem 
*item
, wxDC 
&dc 
) 
3329     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
3330     if ( attr 
&& attr
->HasFont() ) 
3331         dc
.SetFont(attr
->GetFont()); 
3332     else if ( item
->IsBold() ) 
3333         dc
.SetFont(m_boldFont
); 
3335         dc
.SetFont(m_normalFont
); 
3337     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
3340     // restore normal font 
3341     dc
.SetFont( m_normalFont 
); 
3345     int image 
= item
->GetCurrentImage(); 
3346     if ( image 
!= NO_IMAGE 
) 
3348         if ( m_imageListNormal 
) 
3350             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
3351             image_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
3355     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
3358         total_h 
+= 2;            // at least 2 pixels 
3360         total_h 
+= total_h
/10;   // otherwise 10% extra spacing 
3362     item
->SetHeight(total_h
); 
3363     if (total_h
>m_lineHeight
) 
3364         m_lineHeight
=total_h
; 
3366     item
->SetWidth(image_w
+text_w
+2); 
3369 // ----------------------------------------------------------------------------- 
3370 // for developper : y is now the top of the level 
3371 // not the middle of it ! 
3372 void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
3374     int x 
= level
*m_indent
; 
3375     if (!HasFlag(wxTR_HIDE_ROOT
)) 
3379     else if (level 
== 0) 
3381         // a hidden root is not evaluated, but its 
3382         // children are always calculated 
3386     CalculateSize( item
, dc 
); 
3389     item
->SetX( x
+m_spacing 
); 
3391     y 
+= GetLineHeight(item
); 
3393     if ( !item
->IsExpanded() ) 
3395         // we don't need to calculate collapsed branches 
3400     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3401     size_t n
, count 
= children
.Count(); 
3403     for (n 
= 0; n 
< count
; ++n 
) 
3404         CalculateLevel( children
[n
], dc
, level
, y 
);  // recurse 
3407 void wxGenericTreeCtrl::CalculatePositions() 
3409     if ( !m_anchor 
) return; 
3411     wxClientDC 
dc(this); 
3414     dc
.SetFont( m_normalFont 
); 
3416     dc
.SetPen( m_dottedPen 
); 
3417     //if(GetImageList() == NULL) 
3418     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
3421     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
3424 void wxGenericTreeCtrl::Refresh(bool eraseBackground
, const wxRect 
*rect
) 
3426     if ( !m_freezeCount 
) 
3427         wxTreeCtrlBase::Refresh(eraseBackground
, rect
); 
3430 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
3432     if (m_dirty 
|| m_freezeCount
) 
3435     wxSize client 
= GetClientSize(); 
3438     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3439     rect
.width 
= client
.x
; 
3440     rect
.height 
= client
.y
; 
3442     Refresh(true, &rect
); 
3444     AdjustMyScrollbars(); 
3447 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
3449     if (m_dirty 
|| m_freezeCount
) 
3453     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3454     rect
.width 
= GetClientSize().x
; 
3455     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
3457     Refresh(true, &rect
); 
3460 void wxGenericTreeCtrl::RefreshSelected() 
3465     // TODO: this is awfully inefficient, we should keep the list of all 
3466     //       selected items internally, should be much faster 
3468         RefreshSelectedUnder(m_anchor
); 
3471 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem 
*item
) 
3476     if ( item
->IsSelected() ) 
3479     const wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3480     size_t count 
= children
.GetCount(); 
3481     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3483         RefreshSelectedUnder(children
[n
]); 
3487 void wxGenericTreeCtrl::Freeze() 
3492 void wxGenericTreeCtrl::Thaw() 
3494     wxCHECK_RET( m_freezeCount 
> 0, _T("thawing unfrozen tree control?") ); 
3496     if ( --m_freezeCount 
== 0 ) 
3502 // ---------------------------------------------------------------------------- 
3503 // changing colours: we need to refresh the tree control 
3504 // ---------------------------------------------------------------------------- 
3506 bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour
& colour
) 
3508     if ( !wxWindow::SetBackgroundColour(colour
) ) 
3516 bool wxGenericTreeCtrl::SetForegroundColour(const wxColour
& colour
) 
3518     if ( !wxWindow::SetForegroundColour(colour
) ) 
3526 // Process the tooltip event, to speed up event processing. 
3527 // Doesn't actually get a tooltip. 
3528 void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent 
&event 
) 
3534 // NOTE: If using the wxListBox visual attributes works everywhere then this can 
3535 // be removed, as well as the #else case below. 
3536 #define _USE_VISATTR 0 
3541 wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
3543 wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
3547     // Use the same color scheme as wxListBox 
3548     return wxListBox::GetClassDefaultAttributes(variant
); 
3550     wxVisualAttributes attr
; 
3551     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
); 
3552     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
3553     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
3558 #if WXWIN_COMPATIBILITY_2_4 
3560 int wxGenericTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const 
3562     return GetItemImage(item
, wxTreeItemIcon_Selected
); 
3565 void wxGenericTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
) 
3567     SetItemImage(item
, image
, wxTreeItemIcon_Selected
); 
3570 #endif // WXWIN_COMPATIBILITY_2_4 
3572 void wxGenericTreeCtrl::DoDirtyProcessing() 
3579     CalculatePositions(); 
3581     AdjustMyScrollbars(); 
3584 #endif // wxUSE_TREECTRL