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
); 
1028 void wxGenericTreeCtrl::SetItemDropHighlight(const wxTreeItemId
& item
, 
1031     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1037         bg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
); 
1038         fg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1041     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1042     pItem
->Attr().SetTextColour(fg
); 
1043     pItem
->Attr().SetBackgroundColour(bg
); 
1047 void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId
& item
, 
1048                                    const wxColour
& col
) 
1050     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1052     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1053     pItem
->Attr().SetTextColour(col
); 
1057 void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
, 
1058                                          const wxColour
& col
) 
1060     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1062     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1063     pItem
->Attr().SetBackgroundColour(col
); 
1067 void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
) 
1069     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1071     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1072     pItem
->Attr().SetFont(font
); 
1076 bool wxGenericTreeCtrl::SetFont( const wxFont 
&font 
) 
1078     wxTreeCtrlBase::SetFont(font
); 
1080     m_normalFont 
= font 
; 
1081     m_boldFont 
= wxFont(m_normalFont
.GetPointSize(), 
1082                         m_normalFont
.GetFamily(), 
1083                         m_normalFont
.GetStyle(), 
1085                         m_normalFont
.GetUnderlined(), 
1086                         m_normalFont
.GetFaceName(), 
1087                         m_normalFont
.GetEncoding()); 
1093 // ----------------------------------------------------------------------------- 
1094 // item status inquiries 
1095 // ----------------------------------------------------------------------------- 
1097 bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId
& item
) const 
1099     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1101     // An item is only visible if it's not a descendant of a collapsed item 
1102     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1103     wxGenericTreeItem
* parent 
= pItem
->GetParent(); 
1106         if (!parent
->IsExpanded()) 
1108         parent 
= parent
->GetParent(); 
1112     GetViewStart(& startX
, & startY
); 
1114     wxSize clientSize 
= GetClientSize(); 
1117     if (!GetBoundingRect(item
, rect
)) 
1119     if (rect
.GetWidth() == 0 || rect
.GetHeight() == 0) 
1121     if (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) 
1123     if (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
) 
1129 bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
1131     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1133     // consider that the item does have children if it has the "+" button: it 
1134     // might not have them (if it had never been expanded yet) but then it 
1135     // could have them as well and it's better to err on this side rather than 
1136     // disabling some operations which are restricted to the items with 
1137     // children for an item which does have them 
1138     return ((wxGenericTreeItem
*) item
.m_pItem
)->HasPlus(); 
1141 bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
1143     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1145     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsExpanded(); 
1148 bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
1150     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1152     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsSelected(); 
1155 bool wxGenericTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
1157     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1159     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsBold(); 
1162 // ----------------------------------------------------------------------------- 
1164 // ----------------------------------------------------------------------------- 
1166 wxTreeItemId 
wxGenericTreeCtrl::GetItemParent(const wxTreeItemId
& item
) const 
1168     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1170     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetParent(); 
1173 wxTreeItemId 
wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, 
1174                                               wxTreeItemIdValue
& cookie
) const 
1176     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1179     return GetNextChild(item
, cookie
); 
1182 wxTreeItemId 
wxGenericTreeCtrl::GetNextChild(const wxTreeItemId
& item
, 
1183                                              wxTreeItemIdValue
& cookie
) const 
1185     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1187     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1189     // it's ok to cast cookie to size_t, we never have indices big enough to 
1190     // overflow "void *" 
1191     size_t *pIndex 
= (size_t *)&cookie
; 
1192     if ( *pIndex 
< children
.Count() ) 
1194         return children
.Item((*pIndex
)++); 
1198         // there are no more of them 
1199         return wxTreeItemId(); 
1203 #if WXWIN_COMPATIBILITY_2_4 
1205 wxTreeItemId 
wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, 
1208     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1211     return GetNextChild(item
, cookie
); 
1214 wxTreeItemId 
wxGenericTreeCtrl::GetNextChild(const wxTreeItemId
& item
, 
1217     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1219     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1220     if ( (size_t)cookie 
< children
.Count() ) 
1222         return children
.Item((size_t)cookie
++); 
1226         // there are no more of them 
1227         return wxTreeItemId(); 
1231 #endif // WXWIN_COMPATIBILITY_2_4 
1233 wxTreeItemId 
wxGenericTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
1235     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1237     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1238     return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
1241 wxTreeItemId 
wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
1243     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1245     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1246     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1247     if ( parent 
== NULL 
) 
1249         // root item doesn't have any siblings 
1250         return wxTreeItemId(); 
1253     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1254     int index 
= siblings
.Index(i
); 
1255     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1257     size_t n 
= (size_t)(index 
+ 1); 
1258     return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
1261 wxTreeItemId 
wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
1263     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1265     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1266     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1267     if ( parent 
== NULL 
) 
1269         // root item doesn't have any siblings 
1270         return wxTreeItemId(); 
1273     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1274     int index 
= siblings
.Index(i
); 
1275     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1277     return index 
== 0 ? wxTreeItemId() 
1278                       : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
1281 // Only for internal use right now, but should probably be public 
1282 wxTreeItemId 
wxGenericTreeCtrl::GetNext(const wxTreeItemId
& item
) const 
1284     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1286     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1288     // First see if there are any children. 
1289     wxArrayGenericTreeItems
& children 
= i
->GetChildren(); 
1290     if (children
.GetCount() > 0) 
1292          return children
.Item(0); 
1296          // Try a sibling of this or ancestor instead 
1297          wxTreeItemId p 
= item
; 
1298          wxTreeItemId toFind
; 
1301               toFind 
= GetNextSibling(p
); 
1302               p 
= GetItemParent(p
); 
1303          } while (p
.IsOk() && !toFind
.IsOk()); 
1308 wxTreeItemId 
wxGenericTreeCtrl::GetFirstVisibleItem() const 
1310     wxTreeItemId id 
= GetRootItem(); 
1319     } while (id
.IsOk()); 
1321     return wxTreeItemId(); 
1324 wxTreeItemId 
wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
1326     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1328     wxTreeItemId id 
= item
; 
1331         while (id 
= GetNext(id
), id
.IsOk()) 
1337     return wxTreeItemId(); 
1340 wxTreeItemId 
wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
1342     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1344     wxFAIL_MSG(wxT("not implemented")); 
1346     return wxTreeItemId(); 
1349 // called by wxTextTreeCtrl when it marks itself for deletion 
1350 void wxGenericTreeCtrl::ResetTextControl() 
1355 // find the first item starting with the given prefix after the given item 
1356 wxTreeItemId 
wxGenericTreeCtrl::FindItem(const wxTreeItemId
& idParent
, 
1357                                          const wxString
& prefixOrig
) const 
1359     // match is case insensitive as this is more convenient to the user: having 
1360     // to press Shift-letter to go to the item starting with a capital letter 
1361     // would be too bothersome 
1362     wxString prefix 
= prefixOrig
.Lower(); 
1364     // determine the starting point: we shouldn't take the current item (this 
1365     // allows to switch between two items starting with the same letter just by 
1366     // pressing it) but we shouldn't jump to the next one if the user is 
1367     // continuing to type as otherwise he might easily skip the item he wanted 
1368     wxTreeItemId id 
= idParent
; 
1369     if ( prefix
.length() == 1 ) 
1374     // look for the item starting with the given prefix after it 
1375     while ( id
.IsOk() && !GetItemText(id
).Lower().StartsWith(prefix
) ) 
1380     // if we haven't found anything... 
1383         // ... wrap to the beginning 
1385         if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1387             // can't select virtual root 
1391         // and try all the items (stop when we get to the one we started from) 
1392         while ( id 
!= idParent 
&& !GetItemText(id
).Lower().StartsWith(prefix
) ) 
1401 // ----------------------------------------------------------------------------- 
1403 // ----------------------------------------------------------------------------- 
1405 wxTreeItemId 
wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
1407                                              const wxString
& text
, 
1410                                              wxTreeItemData 
*data
) 
1412     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1415         // should we give a warning here? 
1416         return AddRoot(text
, image
, selImage
, data
); 
1419     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1421     wxGenericTreeItem 
*item 
= 
1422         new wxGenericTreeItem( parent
, text
, image
, selImage
, data 
); 
1426         data
->m_pItem 
= item
; 
1429     parent
->Insert( item
, previous 
== (size_t)-1 ? parent
->GetChildren().size() 
1435 wxTreeItemId 
wxGenericTreeCtrl::AddRoot(const wxString
& text
, 
1438                                         wxTreeItemData 
*data
) 
1440     wxCHECK_MSG( !m_anchor
, wxTreeItemId(), wxT("tree can have only one root") ); 
1442     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1444     m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, 
1445                                    image
, selImage
, data
); 
1448         data
->m_pItem 
= m_anchor
; 
1451     if (HasFlag(wxTR_HIDE_ROOT
)) 
1453         // if root is hidden, make sure we can navigate 
1455         m_anchor
->SetHasPlus(); 
1457         CalculatePositions(); 
1460     if (!HasFlag(wxTR_MULTIPLE
)) 
1462         m_current 
= m_key_current 
= m_anchor
; 
1463         m_current
->SetHilight( true ); 
1469 wxTreeItemId 
wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId
& parentId
, 
1470                                               const wxTreeItemId
& idPrevious
, 
1471                                               const wxString
& text
, 
1472                                               int image
, int selImage
, 
1473                                               wxTreeItemData 
*data
) 
1475     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1478         // should we give a warning here? 
1479         return AddRoot(text
, image
, selImage
, data
); 
1483     if (idPrevious
.IsOk()) 
1485         index 
= parent
->GetChildren().Index((wxGenericTreeItem
*) idPrevious
.m_pItem
); 
1486         wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
1487                       wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") ); 
1490     return DoInsertItem(parentId
, (size_t)++index
, text
, image
, selImage
, data
); 
1494 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
1496     wxTreeEvent 
event( wxEVT_COMMAND_TREE_DELETE_ITEM
, GetId() ); 
1497     event
.m_item 
= item
; 
1498     event
.SetEventObject( this ); 
1499     ProcessEvent( event 
); 
1502 // Don't leave edit or selection on a child which is about to disappear 
1503 void wxGenericTreeCtrl::ChildrenClosing(wxGenericTreeItem
* item
) 
1505     if (m_textCtrl 
!= NULL 
&& item 
!= m_textCtrl
->item() && IsDescendantOf(item
, m_textCtrl
->item())) { 
1506         m_textCtrl
->StopEditing(); 
1508     if (item 
!= m_key_current 
&& IsDescendantOf(item
, m_key_current
)) { 
1509         m_key_current 
= NULL
; 
1511     if (IsDescendantOf(item
, m_select_me
)) { 
1514     if (item 
!= m_current 
&& IsDescendantOf(item
, m_current
)) { 
1515         m_current
->SetHilight( false ); 
1521 void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
1523     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1525     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1526     ChildrenClosing(item
); 
1527     item
->DeleteChildren(this); 
1530 void wxGenericTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
1532     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1534     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1536     if (m_textCtrl 
!= NULL 
&& IsDescendantOf(item
, m_textCtrl
->item())) 
1538         // can't delete the item being edited, cancel editing it first 
1539         m_textCtrl
->StopEditing(); 
1542     wxGenericTreeItem 
*parent 
= item
->GetParent(); 
1544     // don't keep stale pointers around! 
1545     if ( IsDescendantOf(item
, m_key_current
) ) 
1547         // Don't silently change the selection: 
1548         // do it properly in idle time, so event 
1549         // handlers get called. 
1551         // m_key_current = parent; 
1552         m_key_current 
= NULL
; 
1555     // m_select_me records whether we need to select 
1556     // a different item, in idle time. 
1557     if ( m_select_me 
&& IsDescendantOf(item
, m_select_me
) ) 
1559         m_select_me 
= parent
; 
1562     if ( IsDescendantOf(item
, m_current
) ) 
1564         // Don't silently change the selection: 
1565         // do it properly in idle time, so event 
1566         // handlers get called. 
1568         // m_current = parent; 
1570         m_select_me 
= parent
; 
1573     // remove the item from the tree 
1576         parent
->GetChildren().Remove( item 
);  // remove by value 
1578     else // deleting the root 
1580         // nothing will be left in the tree 
1584     // and delete all of its children and the item itself now 
1585     item
->DeleteChildren(this); 
1586     SendDeleteEvent(item
); 
1588     if (item 
== m_select_me
) 
1594 void wxGenericTreeCtrl::DeleteAllItems() 
1602 void wxGenericTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
1604     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1606     wxCHECK_RET( item
, _T("invalid item in wxGenericTreeCtrl::Expand") ); 
1607     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1608                  _T("can't expand hidden root") ); 
1610     if ( !item
->HasPlus() ) 
1613     if ( item
->IsExpanded() ) 
1616     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
1617     event
.m_item 
= item
; 
1618     event
.SetEventObject( this ); 
1620     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1622         // cancelled by program 
1627     CalculatePositions(); 
1629     RefreshSubtree(item
); 
1631     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
1632     ProcessEvent( event 
); 
1635 void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId
& item
) 
1637     if ( !HasFlag(wxTR_HIDE_ROOT
) || item 
!= GetRootItem()) 
1640         if ( !IsExpanded(item
) ) 
1644     wxTreeItemIdValue cookie
; 
1645     wxTreeItemId child 
= GetFirstChild(item
, cookie
); 
1646     while ( child
.IsOk() ) 
1650         child 
= GetNextChild(item
, cookie
); 
1654 void wxGenericTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
1656     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1657                  _T("can't collapse hidden root") ); 
1659     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1661     if ( !item
->IsExpanded() ) 
1664     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
1665     event
.m_item 
= item
; 
1666     event
.SetEventObject( this ); 
1667     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1669         // cancelled by program 
1673     ChildrenClosing(item
); 
1676 #if 0  // TODO why should items be collapsed recursively? 
1677     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1678     size_t count 
= children
.Count(); 
1679     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1681         Collapse(children
[n
]); 
1685     CalculatePositions(); 
1687     RefreshSubtree(item
); 
1689     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
1690     ProcessEvent( event 
); 
1693 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
1696     DeleteChildren(item
); 
1699 void wxGenericTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
1701     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1703     if (item
->IsExpanded()) 
1709 void wxGenericTreeCtrl::Unselect() 
1713         m_current
->SetHilight( false ); 
1714         RefreshLine( m_current 
); 
1721 void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem 
*item
) 
1723     if (item
->IsSelected()) 
1725         item
->SetHilight(false); 
1729     if (item
->HasChildren()) 
1731         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1732         size_t count 
= children
.Count(); 
1733         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1735             UnselectAllChildren(children
[n
]); 
1740 void wxGenericTreeCtrl::UnselectAll() 
1742     wxTreeItemId rootItem 
= GetRootItem(); 
1744     // the tree might not have the root item at all 
1747         UnselectAllChildren((wxGenericTreeItem
*) rootItem
.m_pItem
); 
1751 // Recursive function ! 
1752 // To stop we must have crt_item<last_item 
1754 // Tag all next children, when no more children, 
1755 // Move to parent (not to tag) 
1756 // Keep going... if we found last_item, we stop. 
1757 bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1759     wxGenericTreeItem 
*parent 
= crt_item
->GetParent(); 
1761     if (parent 
== NULL
) // This is root item 
1762         return TagAllChildrenUntilLast(crt_item
, last_item
, select
); 
1764     wxArrayGenericTreeItems
& children 
= parent
->GetChildren(); 
1765     int index 
= children
.Index(crt_item
); 
1766     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1768     size_t count 
= children
.Count(); 
1769     for (size_t n
=(size_t)(index
+1); n
<count
; ++n
) 
1771         if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return true; 
1774     return TagNextChildren(parent
, last_item
, select
); 
1777 bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1779     crt_item
->SetHilight(select
); 
1780     RefreshLine(crt_item
); 
1782     if (crt_item
==last_item
) 
1785     if (crt_item
->HasChildren()) 
1787         wxArrayGenericTreeItems
& children 
= crt_item
->GetChildren(); 
1788         size_t count 
= children
.Count(); 
1789         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1791             if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) 
1799 void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem 
*item1
, wxGenericTreeItem 
*item2
) 
1803     // item2 is not necessary after item1 
1804     // choice first' and 'last' between item1 and item2 
1805     wxGenericTreeItem 
*first
= (item1
->GetY()<item2
->GetY()) ? item1 
: item2
; 
1806     wxGenericTreeItem 
*last 
= (item1
->GetY()<item2
->GetY()) ? item2 
: item1
; 
1808     bool select 
= m_current
->IsSelected(); 
1810     if ( TagAllChildrenUntilLast(first
,last
,select
) ) 
1813     TagNextChildren(first
,last
,select
); 
1816 void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId
& itemId
, 
1817                                      bool unselect_others
, 
1818                                      bool extended_select
) 
1820     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1824     bool is_single
=!(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1825     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1827     //wxCHECK_RET( ( (!unselect_others) && is_single), 
1828     //           wxT("this is a single selection tree") ); 
1830     // to keep going anyhow !!! 
1833         if (item
->IsSelected()) 
1834             return; // nothing to do 
1835         unselect_others 
= true; 
1836         extended_select 
= false; 
1838     else if ( unselect_others 
&& item
->IsSelected() ) 
1840         // selection change if there is more than one item currently selected 
1841         wxArrayTreeItemIds selected_items
; 
1842         if ( GetSelections(selected_items
) == 1 ) 
1846     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
1847     event
.m_item 
= item
; 
1848     event
.m_itemOld 
= m_current
; 
1849     event
.SetEventObject( this ); 
1850     // TODO : Here we don't send any selection mode yet ! 
1852     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
1855     wxTreeItemId parent 
= GetItemParent( itemId 
); 
1856     while (parent
.IsOk()) 
1858         if (!IsExpanded(parent
)) 
1861         parent 
= GetItemParent( parent 
); 
1865     if (unselect_others
) 
1867         if (is_single
) Unselect(); // to speed up thing 
1872     if (extended_select
) 
1876             m_current 
= m_key_current 
= (wxGenericTreeItem
*) GetRootItem().m_pItem
; 
1879         // don't change the mark (m_current) 
1880         SelectItemRange(m_current
, item
); 
1884         bool select 
= true; // the default 
1886         // Check if we need to toggle hilight (ctrl mode) 
1887         if (!unselect_others
) 
1888             select
=!item
->IsSelected(); 
1890         m_current 
= m_key_current 
= item
; 
1891         m_current
->SetHilight(select
); 
1892         RefreshLine( m_current 
); 
1895     // This can cause idle processing to select the root 
1896     // if no item is selected, so it must be after the 
1898     EnsureVisible( itemId 
); 
1900     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
1901     GetEventHandler()->ProcessEvent( event 
); 
1904 void wxGenericTreeCtrl::SelectItem(const wxTreeItemId
& itemId
, bool select
) 
1908         DoSelectItem(itemId
, !HasFlag(wxTR_MULTIPLE
)); 
1912         wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1913         wxCHECK_RET( item
, wxT("SelectItem(): invalid tree item") ); 
1915         item
->SetHilight(false); 
1920 void wxGenericTreeCtrl::FillArray(wxGenericTreeItem 
*item
, 
1921                                   wxArrayTreeItemIds 
&array
) const 
1923     if ( item
->IsSelected() ) 
1924         array
.Add(wxTreeItemId(item
)); 
1926     if ( item
->HasChildren() ) 
1928         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1929         size_t count 
= children
.GetCount(); 
1930         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1931             FillArray(children
[n
], array
); 
1935 size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds 
&array
) const 
1938     wxTreeItemId idRoot 
= GetRootItem(); 
1939     if ( idRoot
.IsOk() ) 
1941         FillArray((wxGenericTreeItem
*) idRoot
.m_pItem
, array
); 
1943     //else: the tree is empty, so no selections 
1945     return array
.Count(); 
1948 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
1950     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1952     if (!item
.IsOk()) return; 
1954     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1956     // first expand all parent branches 
1957     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
1959     if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1961         while ( parent 
&& parent 
!= m_anchor 
) 
1964             parent 
= parent
->GetParent(); 
1972             parent 
= parent
->GetParent(); 
1976     //if (parent) CalculatePositions(); 
1981 void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId 
&item
) 
1983     if (!item
.IsOk()) return; 
1985     // We have to call this here because the label in 
1986     // question might just have been added and no screen 
1987     // update taken place. 
1989 #if defined( __WXMSW__ ) || defined(__WXMAC__) 
1994     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1996     // now scroll to the item 
1997     int item_y 
= gitem
->GetY(); 
2001     GetViewStart( &start_x
, &start_y 
); 
2002     start_y 
*= PIXELS_PER_UNIT
; 
2006     GetClientSize( &client_w
, &client_h 
); 
2008     if (item_y 
< start_y
+3) 
2013         m_anchor
->GetSize( x
, y
, this ); 
2014         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2015         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2016         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2017         // Item should appear at top 
2018         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, item_y
/PIXELS_PER_UNIT 
); 
2020     else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) 
2025         m_anchor
->GetSize( x
, y
, this ); 
2026         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2027         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2028         item_y 
+= PIXELS_PER_UNIT
+2; 
2029         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2030         // Item should appear at bottom 
2031         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 
); 
2035 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
2036 static wxGenericTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
2038 static int LINKAGEMODE 
tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
2039                                   wxGenericTreeItem 
**item2
) 
2041     wxCHECK_MSG( s_treeBeingSorted
, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") ); 
2043     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
2046 void wxGenericTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
2048     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
2050     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
2052     wxCHECK_RET( !s_treeBeingSorted
, 
2053                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") ); 
2055     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2056     if ( children
.Count() > 1 ) 
2060         s_treeBeingSorted 
= this; 
2061         children
.Sort(tree_ctrl_compare_func
); 
2062         s_treeBeingSorted 
= NULL
; 
2064     //else: don't make the tree dirty as nothing changed 
2067 void wxGenericTreeCtrl::CalculateLineHeight() 
2069     wxClientDC 
dc(this); 
2070     m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
2072     if ( m_imageListNormal 
) 
2074         // Calculate a m_lineHeight value from the normal Image sizes. 
2075         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2076         // necessary (which might look ugly). 
2077         int n 
= m_imageListNormal
->GetImageCount(); 
2078         for (int i 
= 0; i 
< n 
; i
++) 
2080             int width 
= 0, height 
= 0; 
2081             m_imageListNormal
->GetSize(i
, width
, height
); 
2082             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2086     if (m_imageListButtons
) 
2088         // Calculate a m_lineHeight value from the Button image sizes. 
2089         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2090         // necessary (which might look ugly). 
2091         int n 
= m_imageListButtons
->GetImageCount(); 
2092         for (int i 
= 0; i 
< n 
; i
++) 
2094             int width 
= 0, height 
= 0; 
2095             m_imageListButtons
->GetSize(i
, width
, height
); 
2096             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2100     if (m_lineHeight 
< 30) 
2101         m_lineHeight 
+= 2;                 // at least 2 pixels 
2103         m_lineHeight 
+= m_lineHeight
/10;   // otherwise 10% extra spacing 
2106 void wxGenericTreeCtrl::SetImageList(wxImageList 
*imageList
) 
2108     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
2109     m_imageListNormal 
= imageList
; 
2110     m_ownsImageListNormal 
= false; 
2112     // Don't do any drawing if we're setting the list to NULL, 
2113     // since we may be in the process of deleting the tree control. 
2115         CalculateLineHeight(); 
2118 void wxGenericTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
2120     if (m_ownsImageListState
) delete m_imageListState
; 
2121     m_imageListState 
= imageList
; 
2122     m_ownsImageListState 
= false; 
2125 void wxGenericTreeCtrl::SetButtonsImageList(wxImageList 
*imageList
) 
2127     if (m_ownsImageListButtons
) delete m_imageListButtons
; 
2128     m_imageListButtons 
= imageList
; 
2129     m_ownsImageListButtons 
= false; 
2131     CalculateLineHeight(); 
2134 void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList 
*imageList
) 
2136     SetButtonsImageList(imageList
); 
2137     m_ownsImageListButtons 
= true; 
2140 // ----------------------------------------------------------------------------- 
2142 // ----------------------------------------------------------------------------- 
2144 void wxGenericTreeCtrl::AdjustMyScrollbars() 
2149         m_anchor
->GetSize( x
, y
, this ); 
2150         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2151         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2152         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2153         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
2154         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, y_pos 
); 
2158         SetScrollbars( 0, 0, 0, 0 ); 
2162 int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem 
*item
) const 
2164     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
2165         return item
->GetHeight(); 
2167         return m_lineHeight
; 
2170 void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
2172     // TODO implement "state" icon on items 
2174     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2175     if ( attr 
&& attr
->HasFont() ) 
2176         dc
.SetFont(attr
->GetFont()); 
2177     else if (item
->IsBold()) 
2178         dc
.SetFont(m_boldFont
); 
2180     long text_w 
= 0, text_h 
= 0; 
2181     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
2183     int image_h 
= 0, image_w 
= 0; 
2184     int image 
= item
->GetCurrentImage(); 
2185     if ( image 
!= NO_IMAGE 
) 
2187         if ( m_imageListNormal 
) 
2189             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
2190             image_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
2198     int total_h 
= GetLineHeight(item
); 
2199     bool drawItemBackground 
= false; 
2201     if ( item
->IsSelected() ) 
2203 // under mac selections are only a rectangle in case they don't have the focus 
2207             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
) ; 
2208             dc
.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT 
) , 1 , wxSOLID 
) ) ; 
2212             dc
.SetBrush( *m_hilightBrush 
) ; 
2215         dc
.SetBrush(*(m_hasFocus 
? m_hilightBrush 
: m_hilightUnfocusedBrush
)); 
2217         drawItemBackground 
= true; 
2222         if ( attr 
&& attr
->HasBackgroundColour() ) 
2224             drawItemBackground 
= true; 
2225             colBg 
= attr
->GetBackgroundColour(); 
2229             colBg 
= GetBackgroundColour(); 
2231         dc
.SetBrush(wxBrush(colBg
, wxSOLID
)); 
2234     int offset 
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0; 
2236     if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT
) ) 
2240         DoGetPosition(&x
, &y
); 
2242         dc
.DrawRectangle(x
, item
->GetY()+offset
, w
, total_h
-offset
); 
2246         if ( item
->IsSelected() && image 
!= NO_IMAGE 
) 
2248             // If it's selected, and there's an image, then we should 
2249             // take care to leave the area under the image painted in the 
2250             // background colour. 
2251             dc
.DrawRectangle( item
->GetX() + image_w 
- 2, item
->GetY()+offset
, 
2252                               item
->GetWidth() - image_w 
+ 2, total_h
-offset 
); 
2254         // On GTK+ 2, drawing a 'normal' background is wrong for themes that 
2255         // don't allow backgrounds to be customized. Not drawing the background, 
2256         // except for custom item backgrounds, works for both kinds of theme. 
2257         else if (drawItemBackground
) 
2259             dc
.DrawRectangle( item
->GetX()-2, item
->GetY()+offset
, 
2260                               item
->GetWidth()+2, total_h
-offset 
); 
2264     if ( image 
!= NO_IMAGE 
) 
2266         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
2267         m_imageListNormal
->Draw( image
, dc
, 
2269                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
2270                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
2271         dc
.DestroyClippingRegion(); 
2274     dc
.SetBackgroundMode(wxTRANSPARENT
); 
2275     int extraH 
= (total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0; 
2276     dc
.DrawText( item
->GetText(), 
2277                  (wxCoord
)(image_w 
+ item
->GetX()), 
2278                  (wxCoord
)(item
->GetY() + extraH
)); 
2280     // restore normal font 
2281     dc
.SetFont( m_normalFont 
); 
2284 // Now y stands for the top of the item, whereas it used to stand for middle ! 
2285 void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
2287     int x 
= level
*m_indent
; 
2288     if (!HasFlag(wxTR_HIDE_ROOT
)) 
2292     else if (level 
== 0) 
2294         // always expand hidden root 
2296         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2297         int count 
= children
.Count(); 
2303                 PaintLevel(children
[n
], dc
, 1, y
); 
2304             } while (++n 
< count
); 
2306             if (!HasFlag(wxTR_NO_LINES
) && HasFlag(wxTR_LINES_AT_ROOT
) && count 
> 0) 
2308                 // draw line down to last child 
2309                 origY 
+= GetLineHeight(children
[0])>>1; 
2310                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2311                 dc
.DrawLine(3, origY
, 3, oldY
); 
2317     item
->SetX(x
+m_spacing
); 
2320     int h 
= GetLineHeight(item
); 
2322     int y_mid 
= y_top 
+ (h
>>1); 
2325     int exposed_x 
= dc
.LogicalToDeviceX(0); 
2326     int exposed_y 
= dc
.LogicalToDeviceY(y_top
); 
2328     if (IsExposed(exposed_x
, exposed_y
, 10000, h
))  // 10000 = very much 
2332             // don't draw rect outline if we already have the 
2333             // background color under Mac 
2334             (item
->IsSelected() && m_hasFocus
) ? wxBLACK_PEN 
: 
2335 #endif // !__WXMAC__ 
2339         if ( item
->IsSelected() 
2341             // On wxMac, if the tree doesn't have the focus we draw an empty 
2342             // rectangle, so we want to make sure that the text is visible 
2343             // against the normal background, not the highlightbackground, so 
2344             // don't use the highlight text colour unless we have the focus. 
2349             colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
2353             wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2354             if (attr 
&& attr
->HasTextColour()) 
2355                 colText 
= attr
->GetTextColour(); 
2357                 colText 
= GetForegroundColour(); 
2361         dc
.SetTextForeground(colText
); 
2365         PaintItem(item
, dc
); 
2367         if (HasFlag(wxTR_ROW_LINES
)) 
2369             // if the background colour is white, choose a 
2370             // contrasting color for the lines 
2371             dc
.SetPen(*((GetBackgroundColour() == *wxWHITE
) 
2372                          ? wxMEDIUM_GREY_PEN 
: wxWHITE_PEN
)); 
2373             dc
.DrawLine(0, y_top
, 10000, y_top
); 
2374             dc
.DrawLine(0, y
, 10000, y
); 
2377         // restore DC objects 
2378         dc
.SetBrush(*wxWHITE_BRUSH
); 
2379         dc
.SetPen(m_dottedPen
); 
2380         dc
.SetTextForeground(*wxBLACK
); 
2382         if ( !HasFlag(wxTR_NO_LINES
) ) 
2384             // draw the horizontal line here 
2386             if (x 
> (signed)m_indent
) 
2387                 x_start 
-= m_indent
; 
2388             else if (HasFlag(wxTR_LINES_AT_ROOT
)) 
2390             dc
.DrawLine(x_start
, y_mid
, x 
+ m_spacing
, y_mid
); 
2393         // should the item show a button? 
2394         if ( item
->HasPlus() && HasButtons() ) 
2396             if ( m_imageListButtons 
) 
2398                 // draw the image button here 
2401                 int image 
= item
->IsExpanded() ? wxTreeItemIcon_Expanded
 
2402                                                : wxTreeItemIcon_Normal
; 
2403                 if ( item
->IsSelected() ) 
2404                     image 
+= wxTreeItemIcon_Selected 
- wxTreeItemIcon_Normal
; 
2406                 m_imageListButtons
->GetSize(image
, image_w
, image_h
); 
2407                 int xx 
= x 
- image_w
/2; 
2408                 int yy 
= y_mid 
- image_h
/2; 
2410                 wxDCClipper 
clip(dc
, xx
, yy
, image_w
, image_h
); 
2411                 m_imageListButtons
->Draw(image
, dc
, xx
, yy
, 
2412                                          wxIMAGELIST_DRAW_TRANSPARENT
); 
2414             else // no custom buttons 
2416                 static const int wImage 
= 9; 
2417                 static const int hImage 
= 9; 
2420                 if (item
->IsExpanded()) 
2421                     flag 
|= wxCONTROL_EXPANDED
; 
2422                 if (item 
== m_underMouse
) 
2423                     flag 
|= wxCONTROL_CURRENT
; 
2425                 wxRendererNative::Get().DrawTreeItemButton
 
2429                                             wxRect(x 
- wImage
/2, 
2438     if (item
->IsExpanded()) 
2440         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2441         int count 
= children
.Count(); 
2448                 PaintLevel(children
[n
], dc
, level
, y
); 
2449             } while (++n 
< count
); 
2451             if (!HasFlag(wxTR_NO_LINES
) && count 
> 0) 
2453                 // draw line down to last child 
2454                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2455                 if (HasButtons()) y_mid 
+= 5; 
2457                 // Only draw the portion of the line that is visible, in case it is huge 
2458                 wxCoord xOrigin
=0, yOrigin
=0, width
, height
; 
2459                 dc
.GetDeviceOrigin(&xOrigin
, &yOrigin
); 
2460                 yOrigin 
= abs(yOrigin
); 
2461                 GetClientSize(&width
, &height
); 
2463                 // Move end points to the begining/end of the view? 
2464                 if (y_mid 
< yOrigin
) 
2466                 if (oldY 
> yOrigin 
+ height
) 
2467                     oldY 
= yOrigin 
+ height
; 
2469                 // after the adjustments if y_mid is larger than oldY then the line 
2470                 // isn't visible at all so don't draw anything 
2472                     dc
.DrawLine(x
, y_mid
, x
, oldY
); 
2478 void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem 
*item
) 
2482         if ( item
->HasPlus() ) 
2484             // it's a folder, indicate it by a border 
2489             // draw a line under the drop target because the item will be 
2491             DrawLine(item
, !m_dropEffectAboveItem 
); 
2494         SetCursor(wxCURSOR_BULLSEYE
); 
2499         SetCursor(wxCURSOR_NO_ENTRY
); 
2503 void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId 
&item
) 
2505     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2507     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2509     wxClientDC 
dc(this); 
2511     dc
.SetLogicalFunction(wxINVERT
); 
2512     dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
2514     int w 
= i
->GetWidth() + 2; 
2515     int h 
= GetLineHeight(i
) + 2; 
2517     dc
.DrawRectangle( i
->GetX() - 1, i
->GetY() - 1, w
, h
); 
2520 void wxGenericTreeCtrl::DrawLine(const wxTreeItemId 
&item
, bool below
) 
2522     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2524     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2526     wxClientDC 
dc(this); 
2528     dc
.SetLogicalFunction(wxINVERT
); 
2534         y 
+= GetLineHeight(i
) - 1; 
2537     dc
.DrawLine( x
, y
, x 
+ i
->GetWidth(), y
); 
2540 // ----------------------------------------------------------------------------- 
2541 // wxWidgets callbacks 
2542 // ----------------------------------------------------------------------------- 
2544 void wxGenericTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2552     dc
.SetFont( m_normalFont 
); 
2553     dc
.SetPen( m_dottedPen 
); 
2555     // this is now done dynamically 
2556     //if(GetImageList() == NULL) 
2557     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
2560     PaintLevel( m_anchor
, dc
, 0, y 
); 
2563 void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent 
&event 
) 
2572 void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2581 void wxGenericTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
2583     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
2584     te
.m_evtKey 
= event
; 
2585     te
.SetEventObject( this ); 
2586     if ( GetEventHandler()->ProcessEvent( te 
) ) 
2588         // intercepted by the user code 
2592     if ( (m_current 
== 0) || (m_key_current 
== 0) ) 
2598     // how should the selection work for this event? 
2599     bool is_multiple
, extended_select
, unselect_others
; 
2600     EventFlagsToSelType(GetWindowStyleFlag(), 
2603                         is_multiple
, extended_select
, unselect_others
); 
2607     // * : Expand all/Collapse all 
2608     // ' ' | return : activate 
2609     // up    : go up (not last children!) 
2611     // left  : go to parent 
2612     // right : open if parent and go next 
2613     // home  : go to root 
2614     // end   : go to last item without opening parents 
2615     // alnum : start or continue searching for the item with this prefix 
2616     int keyCode 
= event
.GetKeyCode(); 
2621             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
2629             if ( !IsExpanded(m_current
) ) 
2632                 ExpandAll(m_current
); 
2635             //else: fall through to Collapse() it 
2639             if (IsExpanded(m_current
)) 
2641                 Collapse(m_current
); 
2647                 // Use the item's bounding rectangle to determine position for the event 
2649                 GetBoundingRect(m_current
, ItemRect
, true); 
2651                 wxTreeEvent 
eventMenu( wxEVT_COMMAND_TREE_ITEM_MENU
, GetId() ); 
2652                 eventMenu
.m_item 
= m_current
; 
2653                 // Use the left edge, vertical middle 
2654                 eventMenu
.m_pointDrag 
= wxPoint(ItemRect
.GetX(), 
2655                                                 ItemRect
.GetY() + ItemRect
.GetHeight() / 2); 
2656                 eventMenu
.SetEventObject( this ); 
2657                 GetEventHandler()->ProcessEvent( eventMenu 
); 
2662             if ( !event
.HasModifiers() ) 
2664                 wxTreeEvent 
eventAct( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
2665                 eventAct
.m_item 
= m_current
; 
2666                 eventAct
.SetEventObject( this ); 
2667                 GetEventHandler()->ProcessEvent( eventAct 
); 
2670             // in any case, also generate the normal key event for this key, 
2671             // even if we generated the ACTIVATED event above: this is what 
2672             // wxMSW does and it makes sense because you might not want to 
2673             // process ACTIVATED event at all and handle Space and Return 
2674             // directly (and differently) which would be impossible otherwise 
2678             // up goes to the previous sibling or to the last 
2679             // of its children if it's expanded 
2682                 wxTreeItemId prev 
= GetPrevSibling( m_key_current 
); 
2685                     prev 
= GetItemParent( m_key_current 
); 
2686                     if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2688                         break;  // don't go to root if it is hidden 
2692                         wxTreeItemIdValue cookie
; 
2693                         wxTreeItemId current 
= m_key_current
; 
2694                         // TODO: Huh?  If we get here, we'd better be the first child of our parent.  How else could it be? 
2695                         if (current 
== GetFirstChild( prev
, cookie 
)) 
2697                             // otherwise we return to where we came from 
2698                             DoSelectItem( prev
, unselect_others
, extended_select 
); 
2699                             m_key_current
= (wxGenericTreeItem
*) prev
.m_pItem
; 
2706                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
2708                         wxTreeItemId child 
= GetLastChild(prev
); 
2715                     DoSelectItem( prev
, unselect_others
, extended_select 
); 
2716                     m_key_current
=(wxGenericTreeItem
*) prev
.m_pItem
; 
2721             // left arrow goes to the parent 
2724                 wxTreeItemId prev 
= GetItemParent( m_current 
); 
2725                 if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2727                     // don't go to root if it is hidden 
2728                     prev 
= GetPrevSibling( m_current 
); 
2732                     DoSelectItem( prev
, unselect_others
, extended_select 
); 
2738             // this works the same as the down arrow except that we 
2739             // also expand the item if it wasn't expanded yet 
2745                 if (IsExpanded(m_key_current
) && HasChildren(m_key_current
)) 
2747                     wxTreeItemIdValue cookie
; 
2748                     wxTreeItemId child 
= GetFirstChild( m_key_current
, cookie 
); 
2749                     DoSelectItem( child
, unselect_others
, extended_select 
); 
2750                     m_key_current
=(wxGenericTreeItem
*) child
.m_pItem
; 
2754                     wxTreeItemId next 
= GetNextSibling( m_key_current 
); 
2757                         wxTreeItemId current 
= m_key_current
; 
2758                         while (current
.IsOk() && !next
) 
2760                             current 
= GetItemParent( current 
); 
2761                             if (current
) next 
= GetNextSibling( current 
); 
2766                         DoSelectItem( next
, unselect_others
, extended_select 
); 
2767                         m_key_current
=(wxGenericTreeItem
*) next
.m_pItem
; 
2773             // <End> selects the last visible tree item 
2776                 wxTreeItemId last 
= GetRootItem(); 
2778                 while ( last
.IsOk() && IsExpanded(last
) ) 
2780                     wxTreeItemId lastChild 
= GetLastChild(last
); 
2782                     // it may happen if the item was expanded but then all of 
2783                     // its children have been deleted - so IsExpanded() returned 
2784                     // true, but GetLastChild() returned invalid item 
2793                     DoSelectItem( last
, unselect_others
, extended_select 
); 
2798             // <Home> selects the root item 
2801                 wxTreeItemId prev 
= GetRootItem(); 
2805                 if ( HasFlag(wxTR_HIDE_ROOT
) ) 
2807                     wxTreeItemIdValue cookie
; 
2808                     prev 
= GetFirstChild(prev
, cookie
); 
2813                 DoSelectItem( prev
, unselect_others
, extended_select 
); 
2818             // do not use wxIsalnum() here 
2819             if ( !event
.HasModifiers() && 
2820                  ((keyCode 
>= '0' && keyCode 
<= '9') || 
2821                   (keyCode 
>= 'a' && keyCode 
<= 'z') || 
2822                   (keyCode 
>= 'A' && keyCode 
<= 'Z' ))) 
2824                 // find the next item starting with the given prefix 
2825                 wxChar ch 
= (wxChar
)keyCode
; 
2827                 wxTreeItemId id 
= FindItem(m_current
, m_findPrefix 
+ ch
); 
2838                 // also start the timer to reset the current prefix if the user 
2839                 // doesn't press any more alnum keys soon -- we wouldn't want 
2840                 // to use this prefix for a new item search 
2843                     m_findTimer 
= new wxTreeFindTimer(this); 
2846                 m_findTimer
->Start(wxTreeFindTimer::DELAY
, wxTIMER_ONE_SHOT
); 
2856 wxGenericTreeCtrl::DoTreeHitTest(const wxPoint
& point
, int& flags
) const 
2861     if (point
.x
<0) flags 
|= wxTREE_HITTEST_TOLEFT
; 
2862     if (point
.x
>w
) flags 
|= wxTREE_HITTEST_TORIGHT
; 
2863     if (point
.y
<0) flags 
|= wxTREE_HITTEST_ABOVE
; 
2864     if (point
.y
>h
) flags 
|= wxTREE_HITTEST_BELOW
; 
2865     if (flags
) return wxTreeItemId(); 
2867     if (m_anchor 
== NULL
) 
2869         flags 
= wxTREE_HITTEST_NOWHERE
; 
2870         return wxTreeItemId(); 
2873     wxGenericTreeItem 
*hit 
=  m_anchor
->HitTest(CalcUnscrolledPosition(point
), 
2877         flags 
= wxTREE_HITTEST_NOWHERE
; 
2878         return wxTreeItemId(); 
2883 // get the bounding rectangle of the item (or of its label only) 
2884 bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
, 
2886                                         bool textOnly
) const 
2888     wxCHECK_MSG( item
.IsOk(), false, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") ); 
2890     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2895         rect
.width 
= i
->GetWidth(); 
2897         if ( m_imageListNormal 
) 
2899             int image_w
, image_h
; 
2900             m_imageListNormal
->GetSize( 0, image_w
, image_h 
); 
2901             rect
.width 
+= image_w 
+ MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
2904     else // the entire line 
2907         rect
.width 
= GetClientSize().x
; 
2911     rect
.height 
= GetLineHeight(i
); 
2913     // we have to return the logical coordinates, not physical ones 
2914     rect
.SetTopLeft(CalcScrolledPosition(rect
.GetTopLeft())); 
2919 wxTextCtrl 
*wxGenericTreeCtrl::EditLabel(const wxTreeItemId
& item
, 
2920                                   wxClassInfo 
* WXUNUSED(textCtrlClass
)) 
2922     wxCHECK_MSG( item
.IsOk(), NULL
, _T("can't edit an invalid item") ); 
2924     wxGenericTreeItem 
*itemEdit 
= (wxGenericTreeItem 
*)item
.m_pItem
; 
2926     wxTreeEvent 
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, GetId() ); 
2927     te
.m_item 
= itemEdit
; 
2928     te
.SetEventObject( this ); 
2929     if ( GetEventHandler()->ProcessEvent( te 
) && !te
.IsAllowed() ) 
2935     // We have to call this here because the label in 
2936     // question might just have been added and no screen 
2937     // update taken place. 
2939 #if defined( __WXMSW__ ) || defined(__WXMAC__) 
2945     // TODO: use textCtrlClass here to create the control of correct class 
2946     m_textCtrl 
= new wxTreeTextCtrl(this, itemEdit
); 
2948     m_textCtrl
->SetFocus(); 
2953 // returns a pointer to the text edit control if the item is being 
2954 // edited, NULL otherwise (it's assumed that no more than one item may 
2955 // be edited simultaneously) 
2956 wxTextCtrl
* wxGenericTreeCtrl::GetEditControl() const 
2961 void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId
& WXUNUSED(item
), 
2962                                      bool discardChanges
) 
2964     wxCHECK_RET( m_textCtrl
, _T("not editing label") ); 
2966     m_textCtrl
->EndEdit(discardChanges
); 
2969 bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem 
*item
, 
2970                                        const wxString
& value
) 
2972     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
2974     le
.SetEventObject( this ); 
2976     le
.m_editCancelled 
= false; 
2978     return !GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
2981 void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem 
*item
) 
2983     // let owner know that the edit was cancelled 
2984     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
2986     le
.SetEventObject( this ); 
2987     le
.m_label 
= wxEmptyString
; 
2988     le
.m_editCancelled 
= true; 
2990     GetEventHandler()->ProcessEvent( le 
); 
2993 void wxGenericTreeCtrl::OnRenameTimer() 
2995     EditLabel( m_current 
); 
2998 void wxGenericTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
3000     if ( !m_anchor 
) return; 
3002     wxPoint pt 
= CalcUnscrolledPosition(event
.GetPosition()); 
3004     // Is the mouse over a tree item button? 
3006     wxGenericTreeItem 
*thisItem 
= m_anchor
->HitTest(pt
, this, flags
, 0); 
3007     wxGenericTreeItem 
*underMouse 
= thisItem
; 
3009     bool underMouseChanged 
= (underMouse 
!= m_underMouse
) ; 
3010 #endif // wxUSE_TOOLTIPS 
3013         (flags 
& wxTREE_HITTEST_ONITEMBUTTON
) && 
3014         (!event
.LeftIsDown()) && 
3016         (!m_renameTimer 
|| !m_renameTimer
->IsRunning())) 
3024     if (underMouse 
!= m_underMouse
) 
3028             // unhighlight old item 
3029             wxGenericTreeItem 
*tmp 
= m_underMouse
; 
3030             m_underMouse 
= NULL
; 
3034          m_underMouse 
= underMouse
; 
3036             RefreshLine( m_underMouse 
); 
3040     // Determines what item we are hovering over and need a tooltip for 
3041     wxTreeItemId hoverItem 
= thisItem
; 
3043     // We do not want a tooltip if we are dragging, or if the rename timer is running 
3044     if (underMouseChanged 
&& hoverItem
.IsOk() && !m_isDragging 
&& (!m_renameTimer 
|| !m_renameTimer
->IsRunning())) 
3046         // Ask the tree control what tooltip (if any) should be shown 
3047         wxTreeEvent 
hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP
, GetId()); 
3048         hevent
.m_item 
= hoverItem
; 
3049         hevent
.SetEventObject(this); 
3051         if ( GetEventHandler()->ProcessEvent(hevent
) && hevent
.IsAllowed() ) 
3053             SetToolTip(hevent
.m_label
); 
3058     // we process left mouse up event (enables in-place edit), right down 
3059     // (pass to the user code), left dbl click (activate item) and 
3060     // dragging/moving events for items drag-and-drop 
3061     if ( !(event
.LeftDown() || 
3063            event
.RightDown() || 
3064            event
.LeftDClick() || 
3066            ((event
.Moving() || event
.RightUp()) && m_isDragging
)) ) 
3075     wxGenericTreeItem 
*item 
= m_anchor
->HitTest(pt
, this, flags
, 0); 
3077     if ( event
.Dragging() && !m_isDragging 
) 
3079         if (m_dragCount 
== 0) 
3084         if (m_dragCount 
!= 3) 
3086             // wait until user drags a bit further... 
3090         wxEventType command 
= event
.RightIsDown() 
3091                               ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
 
3092                               : wxEVT_COMMAND_TREE_BEGIN_DRAG
; 
3094         wxTreeEvent 
nevent( command
, GetId() ); 
3095         nevent
.m_item 
= m_current
; 
3096         nevent
.SetEventObject(this); 
3097         nevent
.SetPoint(CalcScrolledPosition(pt
)); 
3099         // by default the dragging is not supported, the user code must 
3100         // explicitly allow the event for it to take place 
3103         if ( GetEventHandler()->ProcessEvent(nevent
) && nevent
.IsAllowed() ) 
3105             // we're going to drag this item 
3106             m_isDragging 
= true; 
3108             // remember the old cursor because we will change it while 
3110             m_oldCursor 
= m_cursor
; 
3112             // in a single selection control, hide the selection temporarily 
3113             if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE
) ) 
3115                 m_oldSelection 
= (wxGenericTreeItem
*) GetSelection().m_pItem
; 
3117                 if ( m_oldSelection 
) 
3119                     m_oldSelection
->SetHilight(false); 
3120                     RefreshLine(m_oldSelection
); 
3127     else if ( event
.Dragging() ) 
3129         if ( item 
!= m_dropTarget 
) 
3131             // unhighlight the previous drop target 
3132             DrawDropEffect(m_dropTarget
); 
3134             m_dropTarget 
= item
; 
3136             // highlight the current drop target if any 
3137             DrawDropEffect(m_dropTarget
); 
3139 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__) 
3146     else if ( (event
.LeftUp() || event
.RightUp()) && m_isDragging 
) 
3150         // erase the highlighting 
3151         DrawDropEffect(m_dropTarget
); 
3153         if ( m_oldSelection 
) 
3155             m_oldSelection
->SetHilight(true); 
3156             RefreshLine(m_oldSelection
); 
3157             m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
3160         // generate the drag end event 
3161         wxTreeEvent 
eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG
, GetId()); 
3163         eventEndDrag
.m_item 
= item
; 
3164         eventEndDrag
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3165         eventEndDrag
.SetEventObject(this); 
3167         (void)GetEventHandler()->ProcessEvent(eventEndDrag
); 
3169         m_isDragging 
= false; 
3170         m_dropTarget 
= (wxGenericTreeItem 
*)NULL
; 
3172         SetCursor(m_oldCursor
); 
3174 #if defined( __WXMSW__ ) || defined(__WXMAC__) 
3182         // If we got to this point, we are not dragging or moving the mouse. 
3183         // Because the code in carbon/toplevel.cpp will only set focus to the tree 
3184         // if we skip for EVT_LEFT_DOWN, we MUST skip this event here for focus to work. 
3185         // We skip even if we didn't hit an item because we still should 
3186         // restore focus to the tree control even if we didn't exactly hit an item. 
3187         if ( event
.LeftDown() ) 
3192         // here we process only the messages which happen on tree items 
3196         if (item 
== NULL
) return;  /* we hit the blank area */ 
3198         if ( event
.RightDown() ) 
3200             // If the item is already selected, do not update the selection. 
3201             // Multi-selections should not be cleared if a selected item is clicked. 
3202             if (!IsSelected(item
)) 
3204                 DoSelectItem(item
, true, false); 
3207             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
, GetId()); 
3208             nevent
.m_item 
= item
; 
3209             nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3210             nevent
.SetEventObject(this); 
3211             event
.Skip(!GetEventHandler()->ProcessEvent(nevent
)); 
3213             // Consistent with MSW (for now), send the ITEM_MENU *after* 
3214             // the RIGHT_CLICK event. TODO: This behavior may change. 
3215             wxTreeEvent 
nevent2(wxEVT_COMMAND_TREE_ITEM_MENU
, GetId()); 
3216             nevent2
.m_item 
= item
; 
3217             nevent2
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3218             nevent2
.SetEventObject(this); 
3219             GetEventHandler()->ProcessEvent(nevent2
); 
3221         else if ( event
.LeftUp() ) 
3223             // this facilitates multiple-item drag-and-drop 
3225             if ( /* item && */ HasFlag(wxTR_MULTIPLE
)) 
3227                 wxArrayTreeItemIds selections
; 
3228                 size_t count 
= GetSelections(selections
); 
3234                     DoSelectItem(item
, true, false); 
3240                 if ( (item 
== m_current
) && 
3241                      (flags 
& wxTREE_HITTEST_ONITEMLABEL
) && 
3242                      HasFlag(wxTR_EDIT_LABELS
) ) 
3244                     if ( m_renameTimer 
) 
3246                         if ( m_renameTimer
->IsRunning() ) 
3247                             m_renameTimer
->Stop(); 
3251                         m_renameTimer 
= new wxTreeRenameTimer( this ); 
3254                     m_renameTimer
->Start( wxTreeRenameTimer::DELAY
, true ); 
3257                 m_lastOnSame 
= false; 
3260         else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick() 
3262             if ( event
.LeftDown() ) 
3264                 m_lastOnSame 
= item 
== m_current
; 
3267             if ( flags 
& wxTREE_HITTEST_ONITEMBUTTON 
) 
3269                 // only toggle the item for a single click, double click on 
3270                 // the button doesn't do anything (it toggles the item twice) 
3271                 if ( event
.LeftDown() ) 
3276                 // don't select the item if the button was clicked 
3281             // clear the previously selected items, if the 
3282             // user clicked outside of the present selection. 
3283             // otherwise, perform the deselection on mouse-up. 
3284             // this allows multiple drag and drop to work. 
3285             // but if Cmd is down, toggle selection of the clicked item 
3286             if (!IsSelected(item
) || event
.CmdDown()) 
3288                 // how should the selection work for this event? 
3289                 bool is_multiple
, extended_select
, unselect_others
; 
3290                 EventFlagsToSelType(GetWindowStyleFlag(), 
3293                                     is_multiple
, extended_select
, unselect_others
); 
3295                 DoSelectItem(item
, unselect_others
, extended_select
); 
3299             // For some reason, Windows isn't recognizing a left double-click, 
3300             // so we need to simulate it here.  Allow 200 milliseconds for now. 
3301             if ( event
.LeftDClick() ) 
3303                 // double clicking should not start editing the item label 
3304                 if ( m_renameTimer 
) 
3305                     m_renameTimer
->Stop(); 
3307                 m_lastOnSame 
= false; 
3309                 // send activate event first 
3310                 wxTreeEvent 
nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
3311                 nevent
.m_item 
= item
; 
3312                 nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3313                 nevent
.SetEventObject( this ); 
3314                 if ( !GetEventHandler()->ProcessEvent( nevent 
) ) 
3316                     // if the user code didn't process the activate event, 
3317                     // handle it ourselves by toggling the item when it is 
3319                     if ( item
->HasPlus() ) 
3329 void wxGenericTreeCtrl::OnInternalIdle() 
3331     wxWindow::OnInternalIdle(); 
3333     // Check if we need to select the root item 
3334     // because nothing else has been selected. 
3335     // Delaying it means that we can invoke event handlers 
3336     // as required, when a first item is selected. 
3337     if (!HasFlag(wxTR_MULTIPLE
) && !GetSelection().IsOk()) 
3340             SelectItem(m_select_me
); 
3341         else if (GetRootItem().IsOk()) 
3342             SelectItem(GetRootItem()); 
3345     /* after all changes have been done to the tree control, 
3346      * we actually redraw the tree when everything is over */ 
3348     if (!m_dirty
) return; 
3349     if (m_freezeCount
) return; 
3353     CalculatePositions(); 
3355     AdjustMyScrollbars(); 
3358 void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem 
*item
, wxDC 
&dc 
) 
3363     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
3364     if ( attr 
&& attr
->HasFont() ) 
3365         dc
.SetFont(attr
->GetFont()); 
3366     else if ( item
->IsBold() ) 
3367         dc
.SetFont(m_boldFont
); 
3369         dc
.SetFont(m_normalFont
); 
3371     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
3374     // restore normal font 
3375     dc
.SetFont( m_normalFont 
); 
3379     int image 
= item
->GetCurrentImage(); 
3380     if ( image 
!= NO_IMAGE 
) 
3382         if ( m_imageListNormal 
) 
3384             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
3385             image_w 
+= MARGIN_BETWEEN_IMAGE_AND_TEXT
; 
3389     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
3392         total_h 
+= 2;            // at least 2 pixels 
3394         total_h 
+= total_h
/10;   // otherwise 10% extra spacing 
3396     item
->SetHeight(total_h
); 
3397     if (total_h
>m_lineHeight
) 
3398         m_lineHeight
=total_h
; 
3400     item
->SetWidth(image_w
+text_w
+2); 
3403 // ----------------------------------------------------------------------------- 
3404 // for developper : y is now the top of the level 
3405 // not the middle of it ! 
3406 void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
3408     int x 
= level
*m_indent
; 
3409     if (!HasFlag(wxTR_HIDE_ROOT
)) 
3413     else if (level 
== 0) 
3415         // a hidden root is not evaluated, but its 
3416         // children are always calculated 
3420     CalculateSize( item
, dc 
); 
3423     item
->SetX( x
+m_spacing 
); 
3425     y 
+= GetLineHeight(item
); 
3427     if ( !item
->IsExpanded() ) 
3429         // we don't need to calculate collapsed branches 
3434     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3435     size_t n
, count 
= children
.Count(); 
3437     for (n 
= 0; n 
< count
; ++n 
) 
3438         CalculateLevel( children
[n
], dc
, level
, y 
);  // recurse 
3441 void wxGenericTreeCtrl::CalculatePositions() 
3443     if ( !m_anchor 
) return; 
3445     wxClientDC 
dc(this); 
3448     dc
.SetFont( m_normalFont 
); 
3450     dc
.SetPen( m_dottedPen 
); 
3451     //if(GetImageList() == NULL) 
3452     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
3455     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
3458 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
3460     if (m_dirty
) return; 
3461     if (m_freezeCount
) return; 
3463     wxSize client 
= GetClientSize(); 
3466     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3467     rect
.width 
= client
.x
; 
3468     rect
.height 
= client
.y
; 
3470     Refresh(true, &rect
); 
3472     AdjustMyScrollbars(); 
3475 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
3477     if (m_dirty
) return; 
3478     if (m_freezeCount
) return; 
3481     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3482     rect
.width 
= GetClientSize().x
; 
3483     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
3485     Refresh(true, &rect
); 
3488 void wxGenericTreeCtrl::RefreshSelected() 
3490     if (m_freezeCount
) return; 
3492     // TODO: this is awfully inefficient, we should keep the list of all 
3493     //       selected items internally, should be much faster 
3495         RefreshSelectedUnder(m_anchor
); 
3498 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem 
*item
) 
3500     if (m_freezeCount
) return; 
3502     if ( item
->IsSelected() ) 
3505     const wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3506     size_t count 
= children
.GetCount(); 
3507     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3509         RefreshSelectedUnder(children
[n
]); 
3513 void wxGenericTreeCtrl::Freeze() 
3518 void wxGenericTreeCtrl::Thaw() 
3520     wxCHECK_RET( m_freezeCount 
> 0, _T("thawing unfrozen tree control?") ); 
3522     if ( --m_freezeCount 
== 0 ) 
3528 // ---------------------------------------------------------------------------- 
3529 // changing colours: we need to refresh the tree control 
3530 // ---------------------------------------------------------------------------- 
3532 bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour
& colour
) 
3534     if ( !wxWindow::SetBackgroundColour(colour
) ) 
3537     if (m_freezeCount
) return true; 
3544 bool wxGenericTreeCtrl::SetForegroundColour(const wxColour
& colour
) 
3546     if ( !wxWindow::SetForegroundColour(colour
) ) 
3549     if (m_freezeCount
) return true; 
3556 // Process the tooltip event, to speed up event processing. 
3557 // Doesn't actually get a tooltip. 
3558 void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent 
&event 
) 
3564 // NOTE: If using the wxListBox visual attributes works everywhere then this can 
3565 // be removed, as well as the #else case below. 
3566 #define _USE_VISATTR 0 
3571 wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
3573 wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
3577     // Use the same color scheme as wxListBox 
3578     return wxListBox::GetClassDefaultAttributes(variant
); 
3580     wxVisualAttributes attr
; 
3581     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
); 
3582     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
3583     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
3588 #if WXWIN_COMPATIBILITY_2_4 
3590 int wxGenericTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const 
3592     return GetItemImage(item
, wxTreeItemIcon_Selected
); 
3595 void wxGenericTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
) 
3597     SetItemImage(item
, image
, wxTreeItemIcon_Selected
); 
3600 #endif // WXWIN_COMPATIBILITY_2_4 
3602 #endif // wxUSE_TREECTRL