1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     generic tree control implementation 
   4 // Author:      Robert Roebling 
   6 // Modified:    22/10/98 - almost total rewrite, simpler interface (VZ) 
   8 // Copyright:   (c) 1998 Robert Roebling and Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================= 
  14 // ============================================================================= 
  16 // ----------------------------------------------------------------------------- 
  18 // ----------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21   #pragma implementation "treectlg.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  33 #include "wx/treebase.h" 
  34 #include "wx/generic/treectlg.h" 
  36 #include "wx/textctrl.h" 
  37 #include "wx/imaglist.h" 
  38 #include "wx/settings.h" 
  39 #include "wx/dcclient.h" 
  41 #include "wx/renderer.h" 
  44     #include "wx/mac/private.h" 
  47 // ----------------------------------------------------------------------------- 
  49 // ----------------------------------------------------------------------------- 
  51 class WXDLLEXPORT wxGenericTreeItem
; 
  53 WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem 
*, wxArrayGenericTreeItems
); 
  55 // ---------------------------------------------------------------------------- 
  57 // ---------------------------------------------------------------------------- 
  59 static const int NO_IMAGE 
= -1; 
  61 static const int PIXELS_PER_UNIT 
= 10; 
  63 // ----------------------------------------------------------------------------- 
  65 // ----------------------------------------------------------------------------- 
  67 // timer used for enabling in-place edit 
  68 class WXDLLEXPORT wxTreeRenameTimer
: public wxTimer
 
  71     // start editing the current item after half a second (if the mouse hasn't 
  72     // been clicked/moved) 
  75     wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
); 
  77     virtual void Notify(); 
  80     wxGenericTreeCtrl 
*m_owner
; 
  82     DECLARE_NO_COPY_CLASS(wxTreeRenameTimer
) 
  85 // control used for in-place edit 
  86 class WXDLLEXPORT wxTreeTextCtrl
: public wxTextCtrl
 
  89     wxTreeTextCtrl(wxGenericTreeCtrl 
*owner
, wxGenericTreeItem 
*item
); 
  94         m_owner
->OnRenameCancelled(m_itemEdited
); 
  96     const wxGenericTreeItem
* item() const { return m_itemEdited
; } 
  99     void OnChar( wxKeyEvent 
&event 
); 
 100     void OnKeyUp( wxKeyEvent 
&event 
); 
 101     void OnKillFocus( wxFocusEvent 
&event 
); 
 103     bool AcceptChanges(); 
 107     wxGenericTreeCtrl  
*m_owner
; 
 108     wxGenericTreeItem  
*m_itemEdited
; 
 109     wxString            m_startValue
; 
 112     DECLARE_EVENT_TABLE() 
 113     DECLARE_NO_COPY_CLASS(wxTreeTextCtrl
) 
 116 // timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed 
 117 // for a sufficiently long time 
 118 class WXDLLEXPORT wxTreeFindTimer 
: public wxTimer
 
 121     // reset the current prefix after half a second of inactivity 
 122     enum { DELAY 
= 500 }; 
 124     wxTreeFindTimer( wxGenericTreeCtrl 
*owner 
) { m_owner 
= owner
; } 
 126     virtual void Notify() { m_owner
->m_findPrefix
.clear(); } 
 129     wxGenericTreeCtrl 
*m_owner
; 
 131     DECLARE_NO_COPY_CLASS(wxTreeFindTimer
) 
 135 class WXDLLEXPORT wxGenericTreeItem
 
 139     wxGenericTreeItem() { m_data 
= NULL
; } 
 140     wxGenericTreeItem( wxGenericTreeItem 
*parent
, 
 141                        const wxString
& text
, 
 144                        wxTreeItemData 
*data 
); 
 146     ~wxGenericTreeItem(); 
 149     wxArrayGenericTreeItems
& GetChildren() { return m_children
; } 
 151     const wxString
& GetText() const { return m_text
; } 
 152     int GetImage(wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) const 
 153         { return m_images
[which
]; } 
 154     wxTreeItemData 
*GetData() const { return m_data
; } 
 156     // returns the current image for the item (depending on its 
 157     // selected/expanded/whatever state) 
 158     int GetCurrentImage() const; 
 160     void SetText( const wxString 
&text 
); 
 161     void SetImage(int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; } 
 162     void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
 164     void SetHasPlus(bool has 
= true) { m_hasPlus 
= has
; } 
 166     void SetBold(bool bold
) { m_isBold 
= bold
; } 
 168     int GetX() const { return m_x
; } 
 169     int GetY() const { return m_y
; } 
 171     void SetX(int x
) { m_x 
= x
; } 
 172     void SetY(int y
) { m_y 
= y
; } 
 174     int  GetHeight() const { return m_height
; } 
 175     int  GetWidth()  const { return m_width
; } 
 177     void SetHeight(int h
) { m_height 
= h
; } 
 178     void SetWidth(int w
) { m_width 
= w
; } 
 180     wxGenericTreeItem 
*GetParent() const { return m_parent
; } 
 183         // deletes all children notifying the treectrl about it if !NULL 
 185     void DeleteChildren(wxGenericTreeCtrl 
*tree 
= NULL
); 
 187     // get count of all children (and grand children if 'recursively') 
 188     size_t GetChildrenCount(bool recursively 
= true) const; 
 190     void Insert(wxGenericTreeItem 
*child
, size_t index
) 
 191     { m_children
.Insert(child
, index
); } 
 193     void GetSize( int &x
, int &y
, const wxGenericTreeCtrl
* ); 
 195         // return the item at given position (or NULL if no item), onButton is 
 196         // true if the point belongs to the item's button, otherwise it lies 
 197         // on the item's label 
 198     wxGenericTreeItem 
*HitTest( const wxPoint
& point
, 
 199                                 const wxGenericTreeCtrl 
*, 
 203     void Expand() { m_isCollapsed 
= false; } 
 204     void Collapse() { m_isCollapsed 
= true; } 
 206     void SetHilight( bool set 
= true ) { m_hasHilight 
= set
; } 
 209     bool HasChildren() const { return !m_children
.IsEmpty(); } 
 210     bool IsSelected()  const { return m_hasHilight 
!= 0; } 
 211     bool IsExpanded()  const { return !m_isCollapsed
; } 
 212     bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 213     bool IsBold()      const { return m_isBold 
!= 0; } 
 216         // get them - may be NULL 
 217     wxTreeItemAttr 
*GetAttributes() const { return m_attr
; } 
 218         // get them ensuring that the pointer is not NULL 
 219     wxTreeItemAttr
& Attr() 
 223             m_attr 
= new wxTreeItemAttr
; 
 229     void SetAttributes(wxTreeItemAttr 
*attr
) 
 231         if ( m_ownsAttr 
) delete m_attr
; 
 235         // set them and delete when done 
 236     void AssignAttributes(wxTreeItemAttr 
*attr
) 
 243     // since there can be very many of these, we save size by chosing 
 244     // the smallest representation for the elements and by ordering 
 245     // the members to avoid padding. 
 246     wxString            m_text
;         // label to be rendered for item 
 248     wxTreeItemData     
*m_data
;         // user-provided data 
 250     wxArrayGenericTreeItems m_children
; // list of children 
 251     wxGenericTreeItem  
*m_parent
;       // parent of this item 
 253     wxTreeItemAttr     
*m_attr
;         // attributes??? 
 255     // tree ctrl images for the normal, selected, expanded and 
 256     // expanded+selected states 
 257     int                 m_images
[wxTreeItemIcon_Max
]; 
 259     wxCoord             m_x
;            // (virtual) offset from top 
 260     wxCoord             m_y
;            // (virtual) offset from left 
 261     int                 m_width
;        // width of this item 
 262     int                 m_height
;       // height of this item 
 264     // use bitfields to save size 
 265     int                 m_isCollapsed 
:1; 
 266     int                 m_hasHilight  
:1; // same as focused 
 267     int                 m_hasPlus     
:1; // used for item which doesn't have 
 268                                           // children but has a [+] button 
 269     int                 m_isBold      
:1; // render the label in bold font 
 270     int                 m_ownsAttr    
:1; // delete attribute when done 
 272     DECLARE_NO_COPY_CLASS(wxGenericTreeItem
) 
 275 // ============================================================================= 
 277 // ============================================================================= 
 279 // ---------------------------------------------------------------------------- 
 281 // ---------------------------------------------------------------------------- 
 283 // translate the key or mouse event flags to the type of selection we're 
 285 static void EventFlagsToSelType(long style
, 
 289                                 bool &extended_select
, 
 290                                 bool &unselect_others
) 
 292     is_multiple 
= (style 
& wxTR_MULTIPLE
) != 0; 
 293     extended_select 
= shiftDown 
&& is_multiple
; 
 294     unselect_others 
= !(extended_select 
|| (ctrlDown 
&& is_multiple
)); 
 297 // check if the given item is under another one 
 298 static bool IsDescendantOf(const wxGenericTreeItem 
*parent
, const wxGenericTreeItem 
*item
) 
 302         if ( item 
== parent 
) 
 304             // item is a descendant of parent 
 308         item 
= item
->GetParent(); 
 314 // ----------------------------------------------------------------------------- 
 315 // wxTreeRenameTimer (internal) 
 316 // ----------------------------------------------------------------------------- 
 318 wxTreeRenameTimer::wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
) 
 323 void wxTreeRenameTimer::Notify() 
 325     m_owner
->OnRenameTimer(); 
 328 //----------------------------------------------------------------------------- 
 329 // wxTreeTextCtrl (internal) 
 330 //----------------------------------------------------------------------------- 
 332 BEGIN_EVENT_TABLE(wxTreeTextCtrl
,wxTextCtrl
) 
 333     EVT_CHAR           (wxTreeTextCtrl::OnChar
) 
 334     EVT_KEY_UP         (wxTreeTextCtrl::OnKeyUp
) 
 335     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus
) 
 338 wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl 
*owner
, 
 339                                wxGenericTreeItem 
*item
) 
 340               : m_itemEdited(item
), m_startValue(item
->GetText()) 
 345     int w 
= m_itemEdited
->GetWidth(), 
 346         h 
= m_itemEdited
->GetHeight(); 
 349     m_owner
->CalcScrolledPosition(item
->GetX(), item
->GetY(), &x
, &y
); 
 354     int image 
= item
->GetCurrentImage(); 
 355     if ( image 
!= NO_IMAGE 
) 
 357         if ( m_owner
->m_imageListNormal 
) 
 359             m_owner
->m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
 364             wxFAIL_MSG(_T("you must create an image list to use images!")); 
 368     // FIXME: what are all these hardcoded 4, 8 and 11s really? 
 372     wxSize bs 
= DoGetBestSize() ; 
 373     // edit control height 
 376         int diff 
= h 
- ( bs
.y 
- 8 ) ; 
 382     (void)Create(m_owner
, wxID_ANY
, m_startValue
, 
 383                  wxPoint(x 
- 4, y 
- 4), wxSize(w 
+ 11, h 
+ 8)); 
 386 bool wxTreeTextCtrl::AcceptChanges() 
 388     const wxString value 
= GetValue(); 
 390     if ( value 
== m_startValue 
) 
 392         // nothing changed, always accept 
 393         // when an item remains unchanged, the owner 
 394         // needs to be notified that the user decided 
 395         // not to change the tree item label, and that 
 396         // the edit has been cancelled 
 398         m_owner
->OnRenameCancelled(m_itemEdited
); 
 402     if ( !m_owner
->OnRenameAccept(m_itemEdited
, value
) ) 
 404         // vetoed by the user 
 408     // accepted, do rename the item 
 409     m_owner
->SetItemText(m_itemEdited
, value
); 
 414 void wxTreeTextCtrl::Finish() 
 418         m_owner
->ResetTextControl(); 
 420         wxPendingDelete
.Append(this); 
 424         m_owner
->SetFocusIgnoringChildren(); 
 428 void wxTreeTextCtrl::OnChar( wxKeyEvent 
&event 
) 
 430     switch ( event
.m_keyCode 
) 
 433             // Notify the owner about the changes 
 436             // Even if vetoed, close the control (consistent with MSW) 
 450 void wxTreeTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
 454         // auto-grow the textctrl: 
 455         wxSize parentSize 
= m_owner
->GetSize(); 
 456         wxPoint myPos 
= GetPosition(); 
 457         wxSize mySize 
= GetSize(); 
 459         GetTextExtent(GetValue() + _T("M"), &sx
, &sy
); 
 460         if (myPos
.x 
+ sx 
> parentSize
.x
) 
 461             sx 
= parentSize
.x 
- myPos
.x
; 
 464         SetSize(sx
, wxDefaultCoord
); 
 470 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
 475         // We must finish regardless of success, otherwise we'll get 
 480     // We must let the native text control handle focus, too, otherwise 
 481     // it could have problems with the cursor (e.g., in wxGTK): 
 485 // ----------------------------------------------------------------------------- 
 487 // ----------------------------------------------------------------------------- 
 489 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 490                                      const wxString
& text
, 
 491                                      int image
, int selImage
, 
 492                                      wxTreeItemData 
*data
) 
 495     m_images
[wxTreeItemIcon_Normal
] = image
; 
 496     m_images
[wxTreeItemIcon_Selected
] = selImage
; 
 497     m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
; 
 498     m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
; 
 503     m_isCollapsed 
= true; 
 504     m_hasHilight 
= false; 
 510     m_attr 
= (wxTreeItemAttr 
*)NULL
; 
 513     // We don't know the height here yet. 
 518 wxGenericTreeItem::~wxGenericTreeItem() 
 522     if (m_ownsAttr
) delete m_attr
; 
 524     wxASSERT_MSG( m_children
.IsEmpty(), 
 525                   wxT("please call DeleteChildren() before deleting the item") ); 
 528 void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl 
*tree
) 
 530     size_t count 
= m_children
.Count(); 
 531     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 533         wxGenericTreeItem 
*child 
= m_children
[n
]; 
 535             tree
->SendDeleteEvent(child
); 
 537         child
->DeleteChildren(tree
); 
 538         if (child 
== tree
->m_select_me
) 
 539             tree
->m_select_me 
= NULL
; 
 546 void wxGenericTreeItem::SetText( const wxString 
&text 
) 
 551 size_t wxGenericTreeItem::GetChildrenCount(bool recursively
) const 
 553     size_t count 
= m_children
.Count(); 
 557     size_t total 
= count
; 
 558     for (size_t n 
= 0; n 
< count
; ++n
) 
 560         total 
+= m_children
[n
]->GetChildrenCount(); 
 566 void wxGenericTreeItem::GetSize( int &x
, int &y
, 
 567                                  const wxGenericTreeCtrl 
*theButton 
) 
 569     int bottomY
=m_y
+theButton
->GetLineHeight(this); 
 570     if ( y 
< bottomY 
) y 
= bottomY
; 
 571     int width 
= m_x 
+  m_width
; 
 572     if ( x 
< width 
) x 
= width
; 
 576         size_t count 
= m_children
.Count(); 
 577         for ( size_t n 
= 0; n 
< count
; ++n 
) 
 579             m_children
[n
]->GetSize( x
, y
, theButton 
); 
 584 wxGenericTreeItem 
*wxGenericTreeItem::HitTest(const wxPoint
& point
, 
 585                                               const wxGenericTreeCtrl 
*theCtrl
, 
 589     // for a hidden root node, don't evaluate it, but do evaluate children 
 590     if ( !(level 
== 0 && theCtrl
->HasFlag(wxTR_HIDE_ROOT
)) ) 
 593         int h 
= theCtrl
->GetLineHeight(this); 
 594         if ((point
.y 
> m_y
) && (point
.y 
< m_y 
+ h
)) 
 596             int y_mid 
= m_y 
+ h
/2; 
 597             if (point
.y 
< y_mid 
) 
 598                 flags 
|= wxTREE_HITTEST_ONITEMUPPERPART
; 
 600                 flags 
|= wxTREE_HITTEST_ONITEMLOWERPART
; 
 602             int xCross 
= m_x 
- theCtrl
->GetSpacing(); 
 604             // according to the drawing code the triangels are drawn 
 605             // at -4 , -4  from the position up to +10/+10 max 
 606             if ((point
.x 
> xCross
-4) && (point
.x 
< xCross
+10) && 
 607                 (point
.y 
> y_mid
-4) && (point
.y 
< y_mid
+10) && 
 608                 HasPlus() && theCtrl
->HasButtons() ) 
 610             // 5 is the size of the plus sign 
 611             if ((point
.x 
> xCross
-6) && (point
.x 
< xCross
+6) && 
 612                 (point
.y 
> y_mid
-6) && (point
.y 
< y_mid
+6) && 
 613                 HasPlus() && theCtrl
->HasButtons() ) 
 616                 flags 
|= wxTREE_HITTEST_ONITEMBUTTON
; 
 620             if ((point
.x 
>= m_x
) && (point
.x 
<= m_x
+m_width
)) 
 625                 // assuming every image (normal and selected) has the same size! 
 626                 if ( (GetImage() != NO_IMAGE
) && theCtrl
->m_imageListNormal 
) 
 627                     theCtrl
->m_imageListNormal
->GetSize(GetImage(), 
 630                 if ((image_w 
!= -1) && (point
.x 
<= m_x 
+ image_w 
+ 1)) 
 631                     flags 
|= wxTREE_HITTEST_ONITEMICON
; 
 633                     flags 
|= wxTREE_HITTEST_ONITEMLABEL
; 
 639                 flags 
|= wxTREE_HITTEST_ONITEMINDENT
; 
 640             if (point
.x 
> m_x
+m_width
) 
 641                 flags 
|= wxTREE_HITTEST_ONITEMRIGHT
; 
 646         // if children are expanded, fall through to evaluate them 
 647         if (m_isCollapsed
) return (wxGenericTreeItem
*) NULL
; 
 651     size_t count 
= m_children
.Count(); 
 652     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 654         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, 
 662     return (wxGenericTreeItem
*) NULL
; 
 665 int wxGenericTreeItem::GetCurrentImage() const 
 667     int image 
= NO_IMAGE
; 
 672             image 
= GetImage(wxTreeItemIcon_SelectedExpanded
); 
 675         if ( image 
== NO_IMAGE 
) 
 677             // we usually fall back to the normal item, but try just the 
 678             // expanded one (and not selected) first in this case 
 679             image 
= GetImage(wxTreeItemIcon_Expanded
); 
 685             image 
= GetImage(wxTreeItemIcon_Selected
); 
 688     // maybe it doesn't have the specific image we want, 
 689     // try the default one instead 
 690     if ( image 
== NO_IMAGE 
) image 
= GetImage(); 
 695 // ----------------------------------------------------------------------------- 
 696 // wxGenericTreeCtrl implementation 
 697 // ----------------------------------------------------------------------------- 
 699 IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl
, wxScrolledWindow
) 
 701 BEGIN_EVENT_TABLE(wxGenericTreeCtrl
,wxScrolledWindow
) 
 702     EVT_PAINT          (wxGenericTreeCtrl::OnPaint
) 
 703     EVT_MOUSE_EVENTS   (wxGenericTreeCtrl::OnMouse
) 
 704     EVT_CHAR           (wxGenericTreeCtrl::OnChar
) 
 705     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus
) 
 706     EVT_KILL_FOCUS     (wxGenericTreeCtrl::OnKillFocus
) 
 707     EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY
, wxGenericTreeCtrl::OnGetToolTip
) 
 710 #if !defined(__WXMSW__) || defined(__WXUNIVERSAL__) 
 712  * wxTreeCtrl has to be a real class or we have problems with 
 713  * the run-time information. 
 716 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxGenericTreeCtrl
) 
 719 // ----------------------------------------------------------------------------- 
 720 // construction/destruction 
 721 // ----------------------------------------------------------------------------- 
 723 void wxGenericTreeCtrl::Init() 
 725     m_current 
= m_key_current 
= m_anchor 
= m_select_me 
= (wxGenericTreeItem 
*) NULL
; 
 733     m_hilightBrush 
= new wxBrush
 
 735                             wxSystemSettings::GetColour
 
 737                                 wxSYS_COLOUR_HIGHLIGHT
 
 742     m_hilightUnfocusedBrush 
= new wxBrush
 
 744                                  wxSystemSettings::GetColour
 
 746                                      wxSYS_COLOUR_BTNSHADOW
 
 751     m_imageListNormal 
= m_imageListButtons 
= 
 752     m_imageListState 
= (wxImageList 
*) NULL
; 
 753     m_ownsImageListNormal 
= m_ownsImageListButtons 
= 
 754     m_ownsImageListState 
= false; 
 757     m_isDragging 
= false; 
 758     m_dropTarget 
= m_oldSelection 
= NULL
; 
 762     m_renameTimer 
= NULL
; 
 767     m_dropEffectAboveItem 
= false; 
 769     m_lastOnSame 
= false; 
 771 #ifdef __WXMAC_CARBON__ 
 772     m_normalFont
.MacCreateThemeFont( kThemeViewsFont 
) ; 
 774     m_normalFont 
= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT 
); 
 776     m_boldFont 
= wxFont(m_normalFont
.GetPointSize(), 
 777                         m_normalFont
.GetFamily(), 
 778                         m_normalFont
.GetStyle(), 
 780                         m_normalFont
.GetUnderlined(), 
 781                         m_normalFont
.GetFaceName(), 
 782                         m_normalFont
.GetEncoding()); 
 785 bool wxGenericTreeCtrl::Create(wxWindow 
*parent
, 
 790                                const wxValidator
& wxVALIDATOR_PARAM(validator
), 
 791                                const wxString
& name 
) 
 795     wxGetOsVersion( &major
, &minor 
); 
 797     style 
&= ~wxTR_LINES_AT_ROOT
; 
 798     style 
|= wxTR_NO_LINES
; 
 800         style 
|= wxTR_ROW_LINES
; 
 803     wxScrolledWindow::Create( parent
, id
, pos
, size
, 
 804                               style
|wxHSCROLL
|wxVSCROLL
, name 
); 
 806     // If the tree display has no buttons, but does have 
 807     // connecting lines, we can use a narrower layout. 
 808     // It may not be a good idea to force this... 
 809     if (!HasButtons() && !HasFlag(wxTR_NO_LINES
)) 
 816     SetValidator( validator 
); 
 819     wxVisualAttributes attr 
= GetDefaultAttributes(); 
 820     SetOwnForegroundColour( attr
.colFg 
); 
 821     SetOwnBackgroundColour( attr
.colBg 
); 
 823         SetOwnFont(attr
.font
); 
 825 //  m_dottedPen = wxPen( "grey", 0, wxDOT );  too slow under XFree86 
 826     m_dottedPen 
= wxPen( wxT("grey"), 0, 0 ); 
 833 wxGenericTreeCtrl::~wxGenericTreeCtrl() 
 835     delete m_hilightBrush
; 
 836     delete m_hilightUnfocusedBrush
; 
 840     delete m_renameTimer
; 
 843     if (m_ownsImageListNormal
) 
 844         delete m_imageListNormal
; 
 845     if (m_ownsImageListState
) 
 846         delete m_imageListState
; 
 847     if (m_ownsImageListButtons
) 
 848         delete m_imageListButtons
; 
 851 // ----------------------------------------------------------------------------- 
 853 // ----------------------------------------------------------------------------- 
 855 size_t wxGenericTreeCtrl::GetCount() const 
 863     size_t count 
= m_anchor
->GetChildrenCount(); 
 864     if ( !HasFlag(wxTR_HIDE_ROOT
) ) 
 866         // take the root itself into account 
 873 void wxGenericTreeCtrl::SetIndent(unsigned int indent
) 
 875     m_indent 
= (unsigned short) indent
; 
 879 void wxGenericTreeCtrl::SetSpacing(unsigned int spacing
) 
 881     m_spacing 
= (unsigned short) spacing
; 
 886 wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, 
 887                                     bool recursively
) const 
 889     wxCHECK_MSG( item
.IsOk(), 0u, wxT("invalid tree item") ); 
 891     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildrenCount(recursively
); 
 894 void wxGenericTreeCtrl::SetWindowStyle(const long styles
) 
 896     if (!HasFlag(wxTR_HIDE_ROOT
) && (styles 
& wxTR_HIDE_ROOT
)) 
 898         // if we will hide the root, make sure children are visible 
 899         m_anchor
->SetHasPlus(); 
 901         CalculatePositions(); 
 904     // right now, just sets the styles.  Eventually, we may 
 905     // want to update the inherited styles, but right now 
 906     // none of the parents has updatable styles 
 907     m_windowStyle 
= styles
; 
 911 // ----------------------------------------------------------------------------- 
 912 // functions to work with tree items 
 913 // ----------------------------------------------------------------------------- 
 915 wxString 
wxGenericTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 917     wxCHECK_MSG( item
.IsOk(), wxEmptyString
, wxT("invalid tree item") ); 
 919     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetText(); 
 922 int wxGenericTreeCtrl::GetItemImage(const wxTreeItemId
& item
, 
 923                              wxTreeItemIcon which
) const 
 925     wxCHECK_MSG( item
.IsOk(), -1, wxT("invalid tree item") ); 
 927     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetImage(which
); 
 930 wxTreeItemData 
*wxGenericTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 932     wxCHECK_MSG( item
.IsOk(), NULL
, wxT("invalid tree item") ); 
 934     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetData(); 
 937 wxColour 
wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId
& item
) const 
 939     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
 941     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 942     return pItem
->Attr().GetTextColour(); 
 945 wxColour 
wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId
& item
) const 
 947     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
 949     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 950     return pItem
->Attr().GetBackgroundColour(); 
 953 wxFont 
wxGenericTreeCtrl::GetItemFont(const wxTreeItemId
& item
) const 
 955     wxCHECK_MSG( item
.IsOk(), wxNullFont
, wxT("invalid tree item") ); 
 957     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 958     return pItem
->Attr().GetFont(); 
 961 void wxGenericTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 963     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 966     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 967     pItem
->SetText(text
); 
 968     CalculateSize(pItem
, dc
); 
 972 void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId
& item
, 
 974                               wxTreeItemIcon which
) 
 976     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 978     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 979     pItem
->SetImage(image
, which
); 
 982     CalculateSize(pItem
, dc
); 
 986 void wxGenericTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 988     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 993     ((wxGenericTreeItem
*) item
.m_pItem
)->SetData(data
); 
 996 void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
 998     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1000     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1001     pItem
->SetHasPlus(has
); 
1005 void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
1007     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1009     // avoid redrawing the tree if no real change 
1010     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1011     if ( pItem
->IsBold() != bold 
) 
1013         pItem
->SetBold(bold
); 
1018 void wxGenericTreeCtrl::SetItemDropHighlight(const wxTreeItemId
& item
, 
1021     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1027         bg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
); 
1028         fg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
1031     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1032     pItem
->Attr().SetTextColour(fg
); 
1033     pItem
->Attr().SetBackgroundColour(bg
); 
1037 void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId
& item
, 
1038                                    const wxColour
& col
) 
1040     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1042     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1043     pItem
->Attr().SetTextColour(col
); 
1047 void wxGenericTreeCtrl::SetItemBackgroundColour(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().SetBackgroundColour(col
); 
1057 void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
) 
1059     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1061     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1062     pItem
->Attr().SetFont(font
); 
1066 bool wxGenericTreeCtrl::SetFont( const wxFont 
&font 
) 
1068     wxScrolledWindow::SetFont(font
); 
1070     m_normalFont 
= font 
; 
1071     m_boldFont 
= wxFont(m_normalFont
.GetPointSize(), 
1072                         m_normalFont
.GetFamily(), 
1073                         m_normalFont
.GetStyle(), 
1075                         m_normalFont
.GetUnderlined(), 
1076                         m_normalFont
.GetFaceName(), 
1077                         m_normalFont
.GetEncoding()); 
1083 // ----------------------------------------------------------------------------- 
1084 // item status inquiries 
1085 // ----------------------------------------------------------------------------- 
1087 bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId
& item
) const 
1089     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1091     // An item is only visible if it's not a descendant of a collapsed item 
1092     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1093     wxGenericTreeItem
* parent 
= pItem
->GetParent(); 
1096         if (!parent
->IsExpanded()) 
1098         parent 
= parent
->GetParent(); 
1102     GetViewStart(& startX
, & startY
); 
1104     wxSize clientSize 
= GetClientSize(); 
1107     if (!GetBoundingRect(item
, rect
)) 
1109     if (rect
.GetWidth() == 0 || rect
.GetHeight() == 0) 
1111     if (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) 
1113     if (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
) 
1119 bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
1121     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1123     // consider that the item does have children if it has the "+" button: it 
1124     // might not have them (if it had never been expanded yet) but then it 
1125     // could have them as well and it's better to err on this side rather than 
1126     // disabling some operations which are restricted to the items with 
1127     // children for an item which does have them 
1128     return ((wxGenericTreeItem
*) item
.m_pItem
)->HasPlus(); 
1131 bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
1133     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1135     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsExpanded(); 
1138 bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
1140     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1142     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsSelected(); 
1145 bool wxGenericTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
1147     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1149     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsBold(); 
1152 // ----------------------------------------------------------------------------- 
1154 // ----------------------------------------------------------------------------- 
1156 wxTreeItemId 
wxGenericTreeCtrl::GetItemParent(const wxTreeItemId
& item
) const 
1158     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1160     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetParent(); 
1163 wxTreeItemId 
wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, 
1164                                               wxTreeItemIdValue
& cookie
) const 
1166     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1169     return GetNextChild(item
, cookie
); 
1172 wxTreeItemId 
wxGenericTreeCtrl::GetNextChild(const wxTreeItemId
& item
, 
1173                                              wxTreeItemIdValue
& cookie
) const 
1175     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1177     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1179     // it's ok to cast cookie to size_t, we never have indices big enough to 
1180     // overflow "void *" 
1181     size_t *pIndex 
= (size_t *)&cookie
; 
1182     if ( *pIndex 
< children
.Count() ) 
1184         return children
.Item((*pIndex
)++); 
1188         // there are no more of them 
1189         return wxTreeItemId(); 
1193 #if WXWIN_COMPATIBILITY_2_4 
1195 wxTreeItemId 
wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, 
1198     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1201     return GetNextChild(item
, cookie
); 
1204 wxTreeItemId 
wxGenericTreeCtrl::GetNextChild(const wxTreeItemId
& item
, 
1207     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1209     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1210     if ( (size_t)cookie 
< children
.Count() ) 
1212         return children
.Item((size_t)cookie
++); 
1216         // there are no more of them 
1217         return wxTreeItemId(); 
1221 #endif // WXWIN_COMPATIBILITY_2_4 
1223 wxTreeItemId 
wxGenericTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
1225     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1227     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1228     return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
1231 wxTreeItemId 
wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
1233     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1235     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1236     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1237     if ( parent 
== NULL 
) 
1239         // root item doesn't have any siblings 
1240         return wxTreeItemId(); 
1243     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1244     int index 
= siblings
.Index(i
); 
1245     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1247     size_t n 
= (size_t)(index 
+ 1); 
1248     return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
1251 wxTreeItemId 
wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
1253     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1255     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1256     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1257     if ( parent 
== NULL 
) 
1259         // root item doesn't have any siblings 
1260         return wxTreeItemId(); 
1263     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1264     int index 
= siblings
.Index(i
); 
1265     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1267     return index 
== 0 ? wxTreeItemId() 
1268                       : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
1271 // Only for internal use right now, but should probably be public 
1272 wxTreeItemId 
wxGenericTreeCtrl::GetNext(const wxTreeItemId
& item
) const 
1274     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1276     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1278     // First see if there are any children. 
1279     wxArrayGenericTreeItems
& children 
= i
->GetChildren(); 
1280     if (children
.GetCount() > 0) 
1282          return children
.Item(0); 
1286          // Try a sibling of this or ancestor instead 
1287          wxTreeItemId p 
= item
; 
1288          wxTreeItemId toFind
; 
1291               toFind 
= GetNextSibling(p
); 
1292               p 
= GetItemParent(p
); 
1293          } while (p
.IsOk() && !toFind
.IsOk()); 
1298 wxTreeItemId 
wxGenericTreeCtrl::GetFirstVisibleItem() const 
1300     wxTreeItemId id 
= GetRootItem(); 
1309     } while (id
.IsOk()); 
1311     return wxTreeItemId(); 
1314 wxTreeItemId 
wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
1316     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1318     wxTreeItemId id 
= item
; 
1321         while (id 
= GetNext(id
), id
.IsOk()) 
1327     return wxTreeItemId(); 
1330 wxTreeItemId 
wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
1332     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1334     wxFAIL_MSG(wxT("not implemented")); 
1336     return wxTreeItemId(); 
1339 // called by wxTextTreeCtrl when it marks itself for deletion 
1340 void wxGenericTreeCtrl::ResetTextControl() 
1345 // find the first item starting with the given prefix after the given item 
1346 wxTreeItemId 
wxGenericTreeCtrl::FindItem(const wxTreeItemId
& idParent
, 
1347                                          const wxString
& prefixOrig
) const 
1349     // match is case insensitive as this is more convenient to the user: having 
1350     // to press Shift-letter to go to the item starting with a capital letter 
1351     // would be too bothersome 
1352     wxString prefix 
= prefixOrig
.Lower(); 
1354     // determine the starting point: we shouldn't take the current item (this 
1355     // allows to switch between two items starting with the same letter just by 
1356     // pressing it) but we shouldn't jump to the next one if the user is 
1357     // continuing to type as otherwise he might easily skip the item he wanted 
1358     wxTreeItemId id 
= idParent
; 
1359     if ( prefix
.length() == 1 ) 
1364     // look for the item starting with the given prefix after it 
1365     while ( id
.IsOk() && !GetItemText(id
).Lower().StartsWith(prefix
) ) 
1370     // if we haven't found anything... 
1373         // ... wrap to the beginning 
1375         if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1377             // can't select virtual root 
1381         // and try all the items (stop when we get to the one we started from) 
1382         while ( id 
!= idParent 
&& !GetItemText(id
).Lower().StartsWith(prefix
) ) 
1391 // ----------------------------------------------------------------------------- 
1393 // ----------------------------------------------------------------------------- 
1395 wxTreeItemId 
wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
1397                                       const wxString
& text
, 
1398                                       int image
, int selImage
, 
1399                                       wxTreeItemData 
*data
) 
1401     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1404         // should we give a warning here? 
1405         return AddRoot(text
, image
, selImage
, data
); 
1408     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1410     wxGenericTreeItem 
*item 
= 
1411         new wxGenericTreeItem( parent
, text
, image
, selImage
, data 
); 
1415         data
->m_pItem 
= item
; 
1418     parent
->Insert( item
, previous 
); 
1423 wxTreeItemId 
wxGenericTreeCtrl::AddRoot(const wxString
& text
, 
1424                                  int image
, int selImage
, 
1425                                  wxTreeItemData 
*data
) 
1427     wxCHECK_MSG( !m_anchor
, wxTreeItemId(), wxT("tree can have only one root") ); 
1429     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1431     m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, 
1432                                    image
, selImage
, data
); 
1435         data
->m_pItem 
= m_anchor
; 
1438     if (HasFlag(wxTR_HIDE_ROOT
)) 
1440         // if root is hidden, make sure we can navigate 
1442         m_anchor
->SetHasPlus(); 
1444         CalculatePositions(); 
1447     if (!HasFlag(wxTR_MULTIPLE
)) 
1449         m_current 
= m_key_current 
= m_anchor
; 
1450         m_current
->SetHilight( true ); 
1456 wxTreeItemId 
wxGenericTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
1457                                      const wxString
& text
, 
1458                                      int image
, int selImage
, 
1459                                      wxTreeItemData 
*data
) 
1461     return DoInsertItem(parent
, 0u, text
, image
, selImage
, data
); 
1464 wxTreeItemId 
wxGenericTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
1465                                     const wxTreeItemId
& idPrevious
, 
1466                                     const wxString
& text
, 
1467                                     int image
, int selImage
, 
1468                                     wxTreeItemData 
*data
) 
1470     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1473         // should we give a warning here? 
1474         return AddRoot(text
, image
, selImage
, data
); 
1478     if (idPrevious
.IsOk()) 
1480         index 
= parent
->GetChildren().Index((wxGenericTreeItem
*) idPrevious
.m_pItem
); 
1481         wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
1482                       wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") ); 
1485     return DoInsertItem(parentId
, (size_t)++index
, text
, image
, selImage
, data
); 
1488 wxTreeItemId 
wxGenericTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
1490                                     const wxString
& text
, 
1491                                     int image
, int selImage
, 
1492                                     wxTreeItemData 
*data
) 
1494     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1497         // should we give a warning here? 
1498         return AddRoot(text
, image
, selImage
, data
); 
1501     return DoInsertItem(parentId
, before
, text
, image
, selImage
, data
); 
1504 wxTreeItemId 
wxGenericTreeCtrl::AppendItem(const wxTreeItemId
& parentId
, 
1505                                     const wxString
& text
, 
1506                                     int image
, int selImage
, 
1507                                     wxTreeItemData 
*data
) 
1509     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1512         // should we give a warning here? 
1513         return AddRoot(text
, image
, selImage
, data
); 
1516     return DoInsertItem( parent
, parent
->GetChildren().Count(), text
, 
1517                          image
, selImage
, data
); 
1520 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
1522     wxTreeEvent 
event( wxEVT_COMMAND_TREE_DELETE_ITEM
, GetId() ); 
1523     event
.m_item 
= item
; 
1524     event
.SetEventObject( this ); 
1525     ProcessEvent( event 
); 
1528 // Don't leave edit or selection on a child which is about to disappear 
1529 void wxGenericTreeCtrl::ChildrenClosing(wxGenericTreeItem
* item
) 
1531     if (m_textCtrl 
!= NULL 
&& item 
!= m_textCtrl
->item() && IsDescendantOf(item
, m_textCtrl
->item())) { 
1532         m_textCtrl
->StopEditing(); 
1534     if (item 
!= m_key_current 
&& IsDescendantOf(item
, m_key_current
)) { 
1535         m_key_current 
= NULL
; 
1537     if (IsDescendantOf(item
, m_select_me
)) { 
1540     if (item 
!= m_current 
&& IsDescendantOf(item
, m_current
)) { 
1541         m_current
->SetHilight( false ); 
1547 void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
1549     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1551     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1552     ChildrenClosing(item
); 
1553     item
->DeleteChildren(this); 
1556 void wxGenericTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
1558     m_dirty 
= true;     // do this first so stuff below doesn't cause flicker 
1560     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1562     if (m_textCtrl 
!= NULL 
&& IsDescendantOf(item
, m_textCtrl
->item())) 
1564         // can't delete the item being edited, cancel editing it first 
1565         m_textCtrl
->StopEditing(); 
1568     wxGenericTreeItem 
*parent 
= item
->GetParent(); 
1570     // don't keep stale pointers around! 
1571     if ( IsDescendantOf(item
, m_key_current
) ) 
1573         // Don't silently change the selection: 
1574         // do it properly in idle time, so event 
1575         // handlers get called. 
1577         // m_key_current = parent; 
1578         m_key_current 
= NULL
; 
1581     // m_select_me records whether we need to select 
1582     // a different item, in idle time. 
1583     if ( m_select_me 
&& IsDescendantOf(item
, m_select_me
) ) 
1585         m_select_me 
= parent
; 
1588     if ( IsDescendantOf(item
, m_current
) ) 
1590         // Don't silently change the selection: 
1591         // do it properly in idle time, so event 
1592         // handlers get called. 
1594         // m_current = parent; 
1596         m_select_me 
= parent
; 
1599     // remove the item from the tree 
1602         parent
->GetChildren().Remove( item 
);  // remove by value 
1604     else // deleting the root 
1606         // nothing will be left in the tree 
1610     // and delete all of its children and the item itself now 
1611     item
->DeleteChildren(this); 
1612     SendDeleteEvent(item
); 
1614     if (item 
== m_select_me
) 
1620 void wxGenericTreeCtrl::DeleteAllItems() 
1628 void wxGenericTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
1630     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1632     wxCHECK_RET( item
, _T("invalid item in wxGenericTreeCtrl::Expand") ); 
1633     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1634                  _T("can't expand hidden root") ); 
1636     if ( !item
->HasPlus() ) 
1639     if ( item
->IsExpanded() ) 
1642     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
1643     event
.m_item 
= item
; 
1644     event
.SetEventObject( this ); 
1646     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1648         // cancelled by program 
1653     CalculatePositions(); 
1655     RefreshSubtree(item
); 
1657     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
1658     ProcessEvent( event 
); 
1661 void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId
& item
) 
1663     if ( !HasFlag(wxTR_HIDE_ROOT
) || item 
!= GetRootItem()) 
1666         if ( !IsExpanded(item
) ) 
1670     wxTreeItemIdValue cookie
; 
1671     wxTreeItemId child 
= GetFirstChild(item
, cookie
); 
1672     while ( child
.IsOk() ) 
1676         child 
= GetNextChild(item
, cookie
); 
1680 void wxGenericTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
1682     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT
) || itemId 
!= GetRootItem(), 
1683                  _T("can't collapse hidden root") ); 
1685     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1687     if ( !item
->IsExpanded() ) 
1690     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
1691     event
.m_item 
= item
; 
1692     event
.SetEventObject( this ); 
1693     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1695         // cancelled by program 
1699     ChildrenClosing(item
); 
1702 #if 0  // TODO why should items be collapsed recursively? 
1703     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1704     size_t count 
= children
.Count(); 
1705     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1707         Collapse(children
[n
]); 
1711     CalculatePositions(); 
1713     RefreshSubtree(item
); 
1715     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
1716     ProcessEvent( event 
); 
1719 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
1722     DeleteChildren(item
); 
1725 void wxGenericTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
1727     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1729     if (item
->IsExpanded()) 
1735 void wxGenericTreeCtrl::Unselect() 
1739         m_current
->SetHilight( false ); 
1740         RefreshLine( m_current 
); 
1747 void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem 
*item
) 
1749     if (item
->IsSelected()) 
1751         item
->SetHilight(false); 
1755     if (item
->HasChildren()) 
1757         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1758         size_t count 
= children
.Count(); 
1759         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1761             UnselectAllChildren(children
[n
]); 
1766 void wxGenericTreeCtrl::UnselectAll() 
1768     wxTreeItemId rootItem 
= GetRootItem(); 
1770     // the tree might not have the root item at all 
1773         UnselectAllChildren((wxGenericTreeItem
*) rootItem
.m_pItem
); 
1777 // Recursive function ! 
1778 // To stop we must have crt_item<last_item 
1780 // Tag all next children, when no more children, 
1781 // Move to parent (not to tag) 
1782 // Keep going... if we found last_item, we stop. 
1783 bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1785     wxGenericTreeItem 
*parent 
= crt_item
->GetParent(); 
1787     if (parent 
== NULL
) // This is root item 
1788         return TagAllChildrenUntilLast(crt_item
, last_item
, select
); 
1790     wxArrayGenericTreeItems
& children 
= parent
->GetChildren(); 
1791     int index 
= children
.Index(crt_item
); 
1792     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1794     size_t count 
= children
.Count(); 
1795     for (size_t n
=(size_t)(index
+1); n
<count
; ++n
) 
1797         if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return true; 
1800     return TagNextChildren(parent
, last_item
, select
); 
1803 bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1805     crt_item
->SetHilight(select
); 
1806     RefreshLine(crt_item
); 
1808     if (crt_item
==last_item
) 
1811     if (crt_item
->HasChildren()) 
1813         wxArrayGenericTreeItems
& children 
= crt_item
->GetChildren(); 
1814         size_t count 
= children
.Count(); 
1815         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1817             if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) 
1825 void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem 
*item1
, wxGenericTreeItem 
*item2
) 
1829     // item2 is not necessary after item1 
1830     // choice first' and 'last' between item1 and item2 
1831     wxGenericTreeItem 
*first
= (item1
->GetY()<item2
->GetY()) ? item1 
: item2
; 
1832     wxGenericTreeItem 
*last 
= (item1
->GetY()<item2
->GetY()) ? item2 
: item1
; 
1834     bool select 
= m_current
->IsSelected(); 
1836     if ( TagAllChildrenUntilLast(first
,last
,select
) ) 
1839     TagNextChildren(first
,last
,select
); 
1842 void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId
& itemId
, 
1843                                      bool unselect_others
, 
1844                                      bool extended_select
) 
1846     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1850     bool is_single
=!(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1851     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1853     //wxCHECK_RET( ( (!unselect_others) && is_single), 
1854     //           wxT("this is a single selection tree") ); 
1856     // to keep going anyhow !!! 
1859         if (item
->IsSelected()) 
1860             return; // nothing to do 
1861         unselect_others 
= true; 
1862         extended_select 
= false; 
1864     else if ( unselect_others 
&& item
->IsSelected() ) 
1866         // selection change if there is more than one item currently selected 
1867         wxArrayTreeItemIds selected_items
; 
1868         if ( GetSelections(selected_items
) == 1 ) 
1872     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
1873     event
.m_item 
= item
; 
1874     event
.m_itemOld 
= m_current
; 
1875     event
.SetEventObject( this ); 
1876     // TODO : Here we don't send any selection mode yet ! 
1878     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
1881     wxTreeItemId parent 
= GetItemParent( itemId 
); 
1882     while (parent
.IsOk()) 
1884         if (!IsExpanded(parent
)) 
1887         parent 
= GetItemParent( parent 
); 
1890     EnsureVisible( itemId 
); 
1893     if (unselect_others
) 
1895         if (is_single
) Unselect(); // to speed up thing 
1900     if (extended_select
) 
1904             m_current 
= m_key_current 
= (wxGenericTreeItem
*) GetRootItem().m_pItem
; 
1907         // don't change the mark (m_current) 
1908         SelectItemRange(m_current
, item
); 
1912         bool select 
= true; // the default 
1914         // Check if we need to toggle hilight (ctrl mode) 
1915         if (!unselect_others
) 
1916             select
=!item
->IsSelected(); 
1918         m_current 
= m_key_current 
= item
; 
1919         m_current
->SetHilight(select
); 
1920         RefreshLine( m_current 
); 
1923     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
1924     GetEventHandler()->ProcessEvent( event 
); 
1927 void wxGenericTreeCtrl::SelectItem(const wxTreeItemId
& itemId
, bool select
) 
1931         DoSelectItem(itemId
); 
1935         wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1936         wxCHECK_RET( item
, wxT("SelectItem(): invalid tree item") ); 
1938         item
->SetHilight(false); 
1943 void wxGenericTreeCtrl::FillArray(wxGenericTreeItem 
*item
, 
1944                                   wxArrayTreeItemIds 
&array
) const 
1946     if ( item
->IsSelected() ) 
1947         array
.Add(wxTreeItemId(item
)); 
1949     if ( item
->HasChildren() ) 
1951         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1952         size_t count 
= children
.GetCount(); 
1953         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1954             FillArray(children
[n
], array
); 
1958 size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds 
&array
) const 
1961     wxTreeItemId idRoot 
= GetRootItem(); 
1962     if ( idRoot
.IsOk() ) 
1964         FillArray((wxGenericTreeItem
*) idRoot
.m_pItem
, array
); 
1966     //else: the tree is empty, so no selections 
1968     return array
.Count(); 
1971 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
1973     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1975     if (!item
.IsOk()) return; 
1977     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1979     // first expand all parent branches 
1980     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
1982     if ( HasFlag(wxTR_HIDE_ROOT
) ) 
1984         while ( parent 
&& parent 
!= m_anchor 
) 
1987             parent 
= parent
->GetParent(); 
1995             parent 
= parent
->GetParent(); 
1999     //if (parent) CalculatePositions(); 
2004 void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId 
&item
) 
2006     if (!item
.IsOk()) return; 
2008     // We have to call this here because the label in 
2009     // question might just have been added and no screen 
2010     // update taken place. 
2012 #if defined( __WXMSW__ ) || defined(__WXMAC__) 
2017     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2019     // now scroll to the item 
2020     int item_y 
= gitem
->GetY(); 
2024     GetViewStart( &start_x
, &start_y 
); 
2025     start_y 
*= PIXELS_PER_UNIT
; 
2029     GetClientSize( &client_w
, &client_h 
); 
2031     if (item_y 
< start_y
+3) 
2036         m_anchor
->GetSize( x
, y
, this ); 
2037         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2038         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2039         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2040         // Item should appear at top 
2041         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, item_y
/PIXELS_PER_UNIT 
); 
2043     else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) 
2048         m_anchor
->GetSize( x
, y
, this ); 
2049         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2050         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2051         item_y 
+= PIXELS_PER_UNIT
+2; 
2052         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2053         // Item should appear at bottom 
2054         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 
); 
2058 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
2059 static wxGenericTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
2061 static int LINKAGEMODE 
tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
2062                                   wxGenericTreeItem 
**item2
) 
2064     wxCHECK_MSG( s_treeBeingSorted
, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") ); 
2066     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
2069 int wxGenericTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
2070                                const wxTreeItemId
& item2
) 
2072     return wxStrcmp(GetItemText(item1
), GetItemText(item2
)); 
2075 void wxGenericTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
2077     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
2079     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
2081     wxCHECK_RET( !s_treeBeingSorted
, 
2082                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") ); 
2084     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2085     if ( children
.Count() > 1 ) 
2089         s_treeBeingSorted 
= this; 
2090         children
.Sort(tree_ctrl_compare_func
); 
2091         s_treeBeingSorted 
= NULL
; 
2093     //else: don't make the tree dirty as nothing changed 
2096 wxImageList 
*wxGenericTreeCtrl::GetImageList() const 
2098     return m_imageListNormal
; 
2101 wxImageList 
*wxGenericTreeCtrl::GetButtonsImageList() const 
2103     return m_imageListButtons
; 
2106 wxImageList 
*wxGenericTreeCtrl::GetStateImageList() const 
2108     return m_imageListState
; 
2111 void wxGenericTreeCtrl::CalculateLineHeight() 
2113     wxClientDC 
dc(this); 
2114     m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
2116     if ( m_imageListNormal 
) 
2118         // Calculate a m_lineHeight value from the normal Image sizes. 
2119         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2120         // necessary (which might look ugly). 
2121         int n 
= m_imageListNormal
->GetImageCount(); 
2122         for (int i 
= 0; i 
< n 
; i
++) 
2124             int width 
= 0, height 
= 0; 
2125             m_imageListNormal
->GetSize(i
, width
, height
); 
2126             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2130     if (m_imageListButtons
) 
2132         // Calculate a m_lineHeight value from the Button image sizes. 
2133         // May be toggle off. Then wxGenericTreeCtrl will spread when 
2134         // necessary (which might look ugly). 
2135         int n 
= m_imageListButtons
->GetImageCount(); 
2136         for (int i 
= 0; i 
< n 
; i
++) 
2138             int width 
= 0, height 
= 0; 
2139             m_imageListButtons
->GetSize(i
, width
, height
); 
2140             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
2144     if (m_lineHeight 
< 30) 
2145         m_lineHeight 
+= 2;                 // at least 2 pixels 
2147         m_lineHeight 
+= m_lineHeight
/10;   // otherwise 10% extra spacing 
2150 void wxGenericTreeCtrl::SetImageList(wxImageList 
*imageList
) 
2152     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
2153     m_imageListNormal 
= imageList
; 
2154     m_ownsImageListNormal 
= false; 
2156     // Don't do any drawing if we're setting the list to NULL, 
2157     // since we may be in the process of deleting the tree control. 
2159         CalculateLineHeight(); 
2162 void wxGenericTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
2164     if (m_ownsImageListState
) delete m_imageListState
; 
2165     m_imageListState 
= imageList
; 
2166     m_ownsImageListState 
= false; 
2169 void wxGenericTreeCtrl::SetButtonsImageList(wxImageList 
*imageList
) 
2171     if (m_ownsImageListButtons
) delete m_imageListButtons
; 
2172     m_imageListButtons 
= imageList
; 
2173     m_ownsImageListButtons 
= false; 
2175     CalculateLineHeight(); 
2178 void wxGenericTreeCtrl::AssignImageList(wxImageList 
*imageList
) 
2180     SetImageList(imageList
); 
2181     m_ownsImageListNormal 
= true; 
2184 void wxGenericTreeCtrl::AssignStateImageList(wxImageList 
*imageList
) 
2186     SetStateImageList(imageList
); 
2187     m_ownsImageListState 
= true; 
2190 void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList 
*imageList
) 
2192     SetButtonsImageList(imageList
); 
2193     m_ownsImageListButtons 
= true; 
2196 // ----------------------------------------------------------------------------- 
2198 // ----------------------------------------------------------------------------- 
2200 void wxGenericTreeCtrl::AdjustMyScrollbars() 
2205         m_anchor
->GetSize( x
, y
, this ); 
2206         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2207         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
2208         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2209         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
2210         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, y_pos 
); 
2214         SetScrollbars( 0, 0, 0, 0 ); 
2218 int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem 
*item
) const 
2220     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
2221         return item
->GetHeight(); 
2223         return m_lineHeight
; 
2226 void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
2228     // TODO implement "state" icon on items 
2230     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2231     if ( attr 
&& attr
->HasFont() ) 
2232         dc
.SetFont(attr
->GetFont()); 
2233     else if (item
->IsBold()) 
2234         dc
.SetFont(m_boldFont
); 
2236     long text_w 
= 0, text_h 
= 0; 
2237     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
2239     int image_h 
= 0, image_w 
= 0; 
2240     int image 
= item
->GetCurrentImage(); 
2241     if ( image 
!= NO_IMAGE 
) 
2243         if ( m_imageListNormal 
) 
2245             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
2254     int total_h 
= GetLineHeight(item
); 
2256     if ( item
->IsSelected() ) 
2258 // under mac selections are only a rectangle in case they don't have the focus 
2262             dc
.SetBrush( *wxTRANSPARENT_BRUSH 
) ; 
2263             dc
.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT 
) , 1 , wxSOLID 
) ) ; 
2267             dc
.SetBrush( *m_hilightBrush 
) ; 
2270         dc
.SetBrush(*(m_hasFocus 
? m_hilightBrush 
: m_hilightUnfocusedBrush
)); 
2276         if ( attr 
&& attr
->HasBackgroundColour() ) 
2277             colBg 
= attr
->GetBackgroundColour(); 
2279             colBg 
= m_backgroundColour
; 
2280         dc
.SetBrush(wxBrush(colBg
, wxSOLID
)); 
2283     int offset 
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0; 
2285     if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT
) ) 
2289         DoGetPosition(&x
, &y
); 
2291         dc
.DrawRectangle(x
, item
->GetY()+offset
, w
, total_h
-offset
); 
2295         if ( item
->IsSelected() && image 
!= NO_IMAGE 
) 
2297             // If it's selected, and there's an image, then we should 
2298             // take care to leave the area under the image painted in the 
2299             // background colour. 
2300             dc
.DrawRectangle( item
->GetX() + image_w 
- 2, item
->GetY()+offset
, 
2301                               item
->GetWidth() - image_w 
+ 2, total_h
-offset 
); 
2305             dc
.DrawRectangle( item
->GetX()-2, item
->GetY()+offset
, 
2306                               item
->GetWidth()+2, total_h
-offset 
); 
2310     if ( image 
!= NO_IMAGE 
) 
2312         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
2313         m_imageListNormal
->Draw( image
, dc
, 
2315                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
2316                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
2317         dc
.DestroyClippingRegion(); 
2320     dc
.SetBackgroundMode(wxTRANSPARENT
); 
2321     int extraH 
= (total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0; 
2322     dc
.DrawText( item
->GetText(), 
2323                  (wxCoord
)(image_w 
+ item
->GetX()), 
2324                  (wxCoord
)(item
->GetY() + extraH
)); 
2326     // restore normal font 
2327     dc
.SetFont( m_normalFont 
); 
2330 // Now y stands for the top of the item, whereas it used to stand for middle ! 
2331 void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
2333     int x 
= level
*m_indent
; 
2334     if (!HasFlag(wxTR_HIDE_ROOT
)) 
2338     else if (level 
== 0) 
2340         // always expand hidden root 
2342         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2343         int count 
= children
.Count(); 
2349                 PaintLevel(children
[n
], dc
, 1, y
); 
2350             } while (++n 
< count
); 
2352             if (!HasFlag(wxTR_NO_LINES
) && HasFlag(wxTR_LINES_AT_ROOT
) && count 
> 0) 
2354                 // draw line down to last child 
2355                 origY 
+= GetLineHeight(children
[0])>>1; 
2356                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2357                 dc
.DrawLine(3, origY
, 3, oldY
); 
2363     item
->SetX(x
+m_spacing
); 
2366     int h 
= GetLineHeight(item
); 
2368     int y_mid 
= y_top 
+ (h
>>1); 
2371     int exposed_x 
= dc
.LogicalToDeviceX(0); 
2372     int exposed_y 
= dc
.LogicalToDeviceY(y_top
); 
2374     if (IsExposed(exposed_x
, exposed_y
, 10000, h
))  // 10000 = very much 
2378             // don't draw rect outline if we already have the 
2379             // background color under Mac 
2380             (item
->IsSelected() && m_hasFocus
) ? wxBLACK_PEN 
: 
2381 #endif // !__WXMAC__ 
2385         if ( item
->IsSelected() ) 
2387             colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
2391             wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2392             if (attr 
&& attr
->HasTextColour()) 
2393                 colText 
= attr
->GetTextColour(); 
2395                 colText 
= GetForegroundColour(); 
2399         dc
.SetTextForeground(colText
); 
2403         PaintItem(item
, dc
); 
2405         if (HasFlag(wxTR_ROW_LINES
)) 
2407             // if the background colour is white, choose a 
2408             // contrasting color for the lines 
2409             dc
.SetPen(*((GetBackgroundColour() == *wxWHITE
) 
2410                          ? wxMEDIUM_GREY_PEN 
: wxWHITE_PEN
)); 
2411             dc
.DrawLine(0, y_top
, 10000, y_top
); 
2412             dc
.DrawLine(0, y
, 10000, y
); 
2415         // restore DC objects 
2416         dc
.SetBrush(*wxWHITE_BRUSH
); 
2417         dc
.SetPen(m_dottedPen
); 
2418         dc
.SetTextForeground(*wxBLACK
); 
2420         if ( !HasFlag(wxTR_NO_LINES
) ) 
2422             // draw the horizontal line here 
2424             if (x 
> (signed)m_indent
) 
2425                 x_start 
-= m_indent
; 
2426             else if (HasFlag(wxTR_LINES_AT_ROOT
)) 
2428             dc
.DrawLine(x_start
, y_mid
, x 
+ m_spacing
, y_mid
); 
2431         // should the item show a button? 
2432         if ( item
->HasPlus() && HasButtons() ) 
2434             if ( m_imageListButtons 
) 
2436                 // draw the image button here 
2439                 int image 
= item
->IsExpanded() ? wxTreeItemIcon_Expanded
 
2440                                                : wxTreeItemIcon_Normal
; 
2441                 if ( item
->IsSelected() ) 
2442                     image 
+= wxTreeItemIcon_Selected 
- wxTreeItemIcon_Normal
; 
2444                 m_imageListButtons
->GetSize(image
, image_w
, image_h
); 
2445                 int xx 
= x 
- image_w
/2; 
2446                 int yy 
= y_mid 
- image_h
/2; 
2448                 wxDCClipper 
clip(dc
, xx
, yy
, image_w
, image_h
); 
2449                 m_imageListButtons
->Draw(image
, dc
, xx
, yy
, 
2450                                          wxIMAGELIST_DRAW_TRANSPARENT
); 
2452             else // no custom buttons 
2454                 static const int wImage 
= 9; 
2455                 static const int hImage 
= 9; 
2458                 if (item
->IsExpanded()) 
2459                     flag 
|= wxCONTROL_EXPANDED
; 
2460                 if (item 
== m_underMouse
) 
2461                     flag 
|= wxCONTROL_CURRENT
; 
2463                 wxRendererNative::Get().DrawTreeItemButton
 
2467                                             wxRect(x 
- wImage
/2, 
2476     if (item
->IsExpanded()) 
2478         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2479         int count 
= children
.Count(); 
2486                 PaintLevel(children
[n
], dc
, level
, y
); 
2487             } while (++n 
< count
); 
2489             if (!HasFlag(wxTR_NO_LINES
) && count 
> 0) 
2491                 // draw line down to last child 
2492                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2493                 if (HasButtons()) y_mid 
+= 5; 
2495                 // Only draw the portion of the line that is visible, in case it is huge 
2496                 wxCoord xOrigin
=0, yOrigin
=0, width
, height
; 
2497                 dc
.GetDeviceOrigin(&xOrigin
, &yOrigin
); 
2498                 yOrigin 
= abs(yOrigin
); 
2499                 GetClientSize(&width
, &height
); 
2501                 // Move end points to the begining/end of the view? 
2502                 if (y_mid 
< yOrigin
) 
2504                 if (oldY 
> yOrigin 
+ height
) 
2505                     oldY 
= yOrigin 
+ height
; 
2507                 // after the adjustments if y_mid is larger than oldY then the line 
2508                 // isn't visible at all so don't draw anything 
2510                     dc
.DrawLine(x
, y_mid
, x
, oldY
); 
2516 void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem 
*item
) 
2520         if ( item
->HasPlus() ) 
2522             // it's a folder, indicate it by a border 
2527             // draw a line under the drop target because the item will be 
2529             DrawLine(item
, !m_dropEffectAboveItem 
); 
2532         SetCursor(wxCURSOR_BULLSEYE
); 
2537         SetCursor(wxCURSOR_NO_ENTRY
); 
2541 void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId 
&item
) 
2543     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2545     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2547     wxClientDC 
dc(this); 
2549     dc
.SetLogicalFunction(wxINVERT
); 
2550     dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
2552     int w 
= i
->GetWidth() + 2; 
2553     int h 
= GetLineHeight(i
) + 2; 
2555     dc
.DrawRectangle( i
->GetX() - 1, i
->GetY() - 1, w
, h
); 
2558 void wxGenericTreeCtrl::DrawLine(const wxTreeItemId 
&item
, bool below
) 
2560     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2562     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2564     wxClientDC 
dc(this); 
2566     dc
.SetLogicalFunction(wxINVERT
); 
2572         y 
+= GetLineHeight(i
) - 1; 
2575     dc
.DrawLine( x
, y
, x 
+ i
->GetWidth(), y
); 
2578 // ----------------------------------------------------------------------------- 
2579 // wxWidgets callbacks 
2580 // ----------------------------------------------------------------------------- 
2582 void wxGenericTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2590     dc
.SetFont( m_normalFont 
); 
2591     dc
.SetPen( m_dottedPen 
); 
2593     // this is now done dynamically 
2594     //if(GetImageList() == NULL) 
2595     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
2598     PaintLevel( m_anchor
, dc
, 0, y 
); 
2601 void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent 
&event 
) 
2610 void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2619 void wxGenericTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
2621     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
2622     te
.m_evtKey 
= event
; 
2623     te
.SetEventObject( this ); 
2624     if ( GetEventHandler()->ProcessEvent( te 
) ) 
2626         // intercepted by the user code 
2630     if ( (m_current 
== 0) || (m_key_current 
== 0) ) 
2636     // how should the selection work for this event? 
2637     bool is_multiple
, extended_select
, unselect_others
; 
2638     EventFlagsToSelType(GetWindowStyleFlag(), 
2640                         event
.ControlDown(), 
2641                         is_multiple
, extended_select
, unselect_others
); 
2645     // * : Expand all/Collapse all 
2646     // ' ' | return : activate 
2647     // up    : go up (not last children!) 
2649     // left  : go to parent 
2650     // right : open if parent and go next 
2651     // home  : go to root 
2652     // end   : go to last item without opening parents 
2653     // alnum : start or continue searching for the item with this prefix 
2654     int keyCode 
= event
.GetKeyCode(); 
2659             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
2667             if ( !IsExpanded(m_current
) ) 
2670                 ExpandAll(m_current
); 
2673             //else: fall through to Collapse() it 
2677             if (IsExpanded(m_current
)) 
2679                 Collapse(m_current
); 
2685                 wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_MENU
, GetId() ); 
2686                 event
.m_item 
= m_current
; 
2687                 event
.SetEventObject( this ); 
2688                 GetEventHandler()->ProcessEvent( event 
); 
2693             if ( !event
.HasModifiers() ) 
2695                 wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
2696                 event
.m_item 
= m_current
; 
2697                 event
.SetEventObject( this ); 
2698                 GetEventHandler()->ProcessEvent( event 
); 
2701             // in any case, also generate the normal key event for this key, 
2702             // even if we generated the ACTIVATED event above: this is what 
2703             // wxMSW does and it makes sense because you might not want to 
2704             // process ACTIVATED event at all and handle Space and Return 
2705             // directly (and differently) which would be impossible otherwise 
2709             // up goes to the previous sibling or to the last 
2710             // of its children if it's expanded 
2713                 wxTreeItemId prev 
= GetPrevSibling( m_key_current 
); 
2716                     prev 
= GetItemParent( m_key_current 
); 
2717                     if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2719                         break;  // don't go to root if it is hidden 
2723                         wxTreeItemIdValue cookie
; 
2724                         wxTreeItemId current 
= m_key_current
; 
2725                         // TODO: Huh?  If we get here, we'd better be the first child of our parent.  How else could it be? 
2726                         if (current 
== GetFirstChild( prev
, cookie 
)) 
2728                             // otherwise we return to where we came from 
2729                             DoSelectItem( prev
, unselect_others
, extended_select 
); 
2730                             m_key_current
= (wxGenericTreeItem
*) prev
.m_pItem
; 
2737                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
2739                         wxTreeItemId child 
= GetLastChild(prev
); 
2746                     DoSelectItem( prev
, unselect_others
, extended_select 
); 
2747                     m_key_current
=(wxGenericTreeItem
*) prev
.m_pItem
; 
2752             // left arrow goes to the parent 
2755                 wxTreeItemId prev 
= GetItemParent( m_current 
); 
2756                 if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2758                     // don't go to root if it is hidden 
2759                     prev 
= GetPrevSibling( m_current 
); 
2763                     DoSelectItem( prev
, unselect_others
, extended_select 
); 
2769             // this works the same as the down arrow except that we 
2770             // also expand the item if it wasn't expanded yet 
2776                 if (IsExpanded(m_key_current
) && HasChildren(m_key_current
)) 
2778                     wxTreeItemIdValue cookie
; 
2779                     wxTreeItemId child 
= GetFirstChild( m_key_current
, cookie 
); 
2780                     DoSelectItem( child
, unselect_others
, extended_select 
); 
2781                     m_key_current
=(wxGenericTreeItem
*) child
.m_pItem
; 
2785                     wxTreeItemId next 
= GetNextSibling( m_key_current 
); 
2788                         wxTreeItemId current 
= m_key_current
; 
2789                         while (current
.IsOk() && !next
) 
2791                             current 
= GetItemParent( current 
); 
2792                             if (current
) next 
= GetNextSibling( current 
); 
2797                         DoSelectItem( next
, unselect_others
, extended_select 
); 
2798                         m_key_current
=(wxGenericTreeItem
*) next
.m_pItem
; 
2804             // <End> selects the last visible tree item 
2807                 wxTreeItemId last 
= GetRootItem(); 
2809                 while ( last
.IsOk() && IsExpanded(last
) ) 
2811                     wxTreeItemId lastChild 
= GetLastChild(last
); 
2813                     // it may happen if the item was expanded but then all of 
2814                     // its children have been deleted - so IsExpanded() returned 
2815                     // true, but GetLastChild() returned invalid item 
2824                     DoSelectItem( last
, unselect_others
, extended_select 
); 
2829             // <Home> selects the root item 
2832                 wxTreeItemId prev 
= GetRootItem(); 
2836                 if ( HasFlag(wxTR_HIDE_ROOT
) ) 
2838                     wxTreeItemIdValue cookie
; 
2839                     prev 
= GetFirstChild(prev
, cookie
); 
2844                 DoSelectItem( prev
, unselect_others
, extended_select 
); 
2849             // do not use wxIsalnum() here 
2850             if ( !event
.HasModifiers() && 
2851                  ((keyCode 
>= '0' && keyCode 
<= '9') || 
2852                   (keyCode 
>= 'a' && keyCode 
<= 'z') || 
2853                   (keyCode 
>= 'A' && keyCode 
<= 'Z' ))) 
2855                 // find the next item starting with the given prefix 
2856                 wxChar ch 
= (wxChar
)keyCode
; 
2858                 wxTreeItemId id 
= FindItem(m_current
, m_findPrefix 
+ ch
); 
2869                 // also start the timer to reset the current prefix if the user 
2870                 // doesn't press any more alnum keys soon -- we wouldn't want 
2871                 // to use this prefix for a new item search 
2874                     m_findTimer 
= new wxTreeFindTimer(this); 
2877                 m_findTimer
->Start(wxTreeFindTimer::DELAY
, wxTIMER_ONE_SHOT
); 
2886 wxTreeItemId 
wxGenericTreeCtrl::HitTest(const wxPoint
& point
, int& flags
) 
2888     // JACS: removed wxYieldIfNeeded() because it can cause the window 
2889     // to be deleted from under us if a close window event is pending 
2894     if (point
.x
<0) flags 
|= wxTREE_HITTEST_TOLEFT
; 
2895     if (point
.x
>w
) flags 
|= wxTREE_HITTEST_TORIGHT
; 
2896     if (point
.y
<0) flags 
|= wxTREE_HITTEST_ABOVE
; 
2897     if (point
.y
>h
) flags 
|= wxTREE_HITTEST_BELOW
; 
2898     if (flags
) return wxTreeItemId(); 
2900     if (m_anchor 
== NULL
) 
2902         flags 
= wxTREE_HITTEST_NOWHERE
; 
2903         return wxTreeItemId(); 
2906     wxGenericTreeItem 
*hit 
=  m_anchor
->HitTest(CalcUnscrolledPosition(point
), 
2910         flags 
= wxTREE_HITTEST_NOWHERE
; 
2911         return wxTreeItemId(); 
2916 // get the bounding rectangle of the item (or of its label only) 
2917 bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
, 
2919                                         bool WXUNUSED(textOnly
)) const 
2921     wxCHECK_MSG( item
.IsOk(), false, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") ); 
2923     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2926     GetViewStart(& startX
, & startY
); 
2928     rect
.x 
= i
->GetX() - startX
*PIXELS_PER_UNIT
; 
2929     rect
.y 
= i
->GetY() - startY
*PIXELS_PER_UNIT
; 
2930     rect
.width 
= i
->GetWidth(); 
2931     //rect.height = i->GetHeight(); 
2932     rect
.height 
= GetLineHeight(i
); 
2937 void wxGenericTreeCtrl::Edit( const wxTreeItemId
& item 
) 
2939     wxCHECK_RET( item
.IsOk(), _T("can't edit an invalid item") ); 
2941     wxGenericTreeItem 
*itemEdit 
= (wxGenericTreeItem 
*)item
.m_pItem
; 
2943     wxTreeEvent 
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, GetId() ); 
2944     te
.m_item 
= itemEdit
; 
2945     te
.SetEventObject( this ); 
2946     if ( GetEventHandler()->ProcessEvent( te 
) && !te
.IsAllowed() ) 
2952     // We have to call this here because the label in 
2953     // question might just have been added and no screen 
2954     // update taken place. 
2956 #if defined( __WXMSW__ ) || defined(__WXMAC__) 
2962     m_textCtrl 
= new wxTreeTextCtrl(this, itemEdit
); 
2964     m_textCtrl
->SetFocus(); 
2967 // returns a pointer to the text edit control if the item is being 
2968 // edited, NULL otherwise (it's assumed that no more than one item may 
2969 // be edited simultaneously) 
2970 wxTextCtrl
* wxGenericTreeCtrl::GetEditControl() const 
2975 bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem 
*item
, 
2976                                        const wxString
& value
) 
2978     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
2980     le
.SetEventObject( this ); 
2982     le
.m_editCancelled 
= false; 
2984     return !GetEventHandler()->ProcessEvent( le 
) || le
.IsAllowed(); 
2987 void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem 
*item
) 
2989     // let owner know that the edit was cancelled 
2990     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
2992     le
.SetEventObject( this ); 
2993     le
.m_label 
= wxEmptyString
; 
2994     le
.m_editCancelled 
= true; 
2996     GetEventHandler()->ProcessEvent( le 
); 
2999 void wxGenericTreeCtrl::OnRenameTimer() 
3004 void wxGenericTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
3006     if ( !m_anchor 
) return; 
3008     wxPoint pt 
= CalcUnscrolledPosition(event
.GetPosition()); 
3010     // Is the mouse over a tree item button? 
3012     wxGenericTreeItem 
*thisItem 
= m_anchor
->HitTest(pt
, this, flags
, 0); 
3013     wxGenericTreeItem 
*underMouse 
= thisItem
; 
3015     bool underMouseChanged 
= (underMouse 
!= m_underMouse
) ; 
3016 #endif // wxUSE_TOOLTIPS 
3019         (flags 
& wxTREE_HITTEST_ONITEMBUTTON
) && 
3020         (!event
.LeftIsDown()) && 
3022         (!m_renameTimer 
|| !m_renameTimer
->IsRunning())) 
3030     if (underMouse 
!= m_underMouse
) 
3034             // unhighlight old item 
3035             wxGenericTreeItem 
*tmp 
= m_underMouse
; 
3036             m_underMouse 
= NULL
; 
3040          m_underMouse 
= underMouse
; 
3042             RefreshLine( m_underMouse 
); 
3046     // Determines what item we are hovering over and need a tooltip for 
3047     wxTreeItemId hoverItem 
= thisItem
; 
3049     // We do not want a tooltip if we are dragging, or if the rename timer is running 
3050     if (underMouseChanged 
&& hoverItem
.IsOk() && !m_isDragging 
&& (!m_renameTimer 
|| !m_renameTimer
->IsRunning())) 
3052         // Ask the tree control what tooltip (if any) should be shown 
3053         wxTreeEvent 
hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP
, GetId()); 
3054         hevent
.m_item 
= hoverItem
; 
3055         hevent
.SetEventObject(this); 
3057         if ( GetEventHandler()->ProcessEvent(hevent
) && hevent
.IsAllowed() ) 
3059             SetToolTip(hevent
.m_label
); 
3064     // we process left mouse up event (enables in-place edit), right down 
3065     // (pass to the user code), left dbl click (activate item) and 
3066     // dragging/moving events for items drag-and-drop 
3067     if ( !(event
.LeftDown() || 
3069            event
.RightDown() || 
3070            event
.LeftDClick() || 
3072            ((event
.Moving() || event
.RightUp()) && m_isDragging
)) ) 
3081     wxGenericTreeItem 
*item 
= m_anchor
->HitTest(pt
, this, flags
, 0); 
3083     if ( event
.Dragging() && !m_isDragging 
) 
3085         if (m_dragCount 
== 0) 
3090         if (m_dragCount 
!= 3) 
3092             // wait until user drags a bit further... 
3096         wxEventType command 
= event
.RightIsDown() 
3097                               ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
 
3098                               : wxEVT_COMMAND_TREE_BEGIN_DRAG
; 
3100         wxTreeEvent 
nevent( command
, GetId() ); 
3101         nevent
.m_item 
= m_current
; 
3102         nevent
.SetEventObject(this); 
3104         // by default the dragging is not supported, the user code must 
3105         // explicitly allow the event for it to take place 
3108         if ( GetEventHandler()->ProcessEvent(nevent
) && nevent
.IsAllowed() ) 
3110             // we're going to drag this item 
3111             m_isDragging 
= true; 
3113             // remember the old cursor because we will change it while 
3115             m_oldCursor 
= m_cursor
; 
3117             // in a single selection control, hide the selection temporarily 
3118             if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE
) ) 
3120                 m_oldSelection 
= (wxGenericTreeItem
*) GetSelection().m_pItem
; 
3122                 if ( m_oldSelection 
) 
3124                     m_oldSelection
->SetHilight(false); 
3125                     RefreshLine(m_oldSelection
); 
3132     else if ( event
.Dragging() ) 
3134         if ( item 
!= m_dropTarget 
) 
3136             // unhighlight the previous drop target 
3137             DrawDropEffect(m_dropTarget
); 
3139             m_dropTarget 
= item
; 
3141             // highlight the current drop target if any 
3142             DrawDropEffect(m_dropTarget
); 
3144 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__) 
3151     else if ( (event
.LeftUp() || event
.RightUp()) && m_isDragging 
) 
3153         // erase the highlighting 
3154         DrawDropEffect(m_dropTarget
); 
3156         if ( m_oldSelection 
) 
3158             m_oldSelection
->SetHilight(true); 
3159             RefreshLine(m_oldSelection
); 
3160             m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
3163         // generate the drag end event 
3164         wxTreeEvent 
event(wxEVT_COMMAND_TREE_END_DRAG
, GetId()); 
3166         event
.m_item 
= item
; 
3167         event
.m_pointDrag 
= pt
; 
3168         event
.SetEventObject(this); 
3170         (void)GetEventHandler()->ProcessEvent(event
); 
3172         m_isDragging 
= false; 
3173         m_dropTarget 
= (wxGenericTreeItem 
*)NULL
; 
3177         SetCursor(m_oldCursor
); 
3179 #if defined( __WXMSW__ ) || defined(__WXMAC__) 
3187         // If we got to this point, we are not dragging or moving the mouse. 
3188         // Because the code in carbon/toplevel.cpp will only set focus to the tree 
3189         // if we skip for EVT_LEFT_DOWN, we MUST skip this event here for focus to work. 
3190         // We skip even if we didn't hit an item because we still should 
3191         // restore focus to the tree control even if we didn't exactly hit an item. 
3192         if ( event
.LeftDown() ) 
3197         // here we process only the messages which happen on tree items 
3201         if (item 
== NULL
) return;  /* we hit the blank area */ 
3203         if ( event
.RightDown() ) 
3205             // If the item is already selected, do not update the selection. 
3206             // Multi-selections should not be cleared if a selected item is clicked. 
3207             if (!IsSelected(item
)) 
3209                 DoSelectItem(item
, true, false); 
3212             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
, GetId()); 
3213             nevent
.m_item 
= item
; 
3214             nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3215             nevent
.SetEventObject(this); 
3216             event
.Skip(!GetEventHandler()->ProcessEvent(nevent
)); 
3218         else if ( event
.LeftUp() ) 
3220             // this facilitates multiple-item drag-and-drop 
3222             if (item 
&& HasFlag(wxTR_MULTIPLE
)) 
3224                 wxArrayTreeItemIds selections
; 
3225                 size_t count 
= GetSelections(selections
); 
3228                     !event
.ControlDown() && 
3231                     DoSelectItem(item
, true, false); 
3237                 if ( (item 
== m_current
) && 
3238                      (flags 
& wxTREE_HITTEST_ONITEMLABEL
) && 
3239                      HasFlag(wxTR_EDIT_LABELS
) ) 
3241                     if ( m_renameTimer 
) 
3243                         if ( m_renameTimer
->IsRunning() ) 
3244                             m_renameTimer
->Stop(); 
3248                         m_renameTimer 
= new wxTreeRenameTimer( this ); 
3251                     m_renameTimer
->Start( wxTreeRenameTimer::DELAY
, true ); 
3254                 m_lastOnSame 
= false; 
3257         else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick() 
3259             if ( event
.LeftDown() ) 
3261                 m_lastOnSame 
= item 
== m_current
; 
3264             if ( flags 
& wxTREE_HITTEST_ONITEMBUTTON 
) 
3266                 // only toggle the item for a single click, double click on 
3267                 // the button doesn't do anything (it toggles the item twice) 
3268                 if ( event
.LeftDown() ) 
3273                 // don't select the item if the button was clicked 
3278             // clear the previously selected items, if the 
3279             // user clicked outside of the present selection. 
3280             // otherwise, perform the deselection on mouse-up. 
3281             // this allows multiple drag and drop to work. 
3283             if (!IsSelected(item
)) 
3285                 // how should the selection work for this event? 
3286                 bool is_multiple
, extended_select
, unselect_others
; 
3287                 EventFlagsToSelType(GetWindowStyleFlag(), 
3289                                     event
.ControlDown(), 
3290                                     is_multiple
, extended_select
, unselect_others
); 
3292                 DoSelectItem(item
, unselect_others
, extended_select
); 
3296             // For some reason, Windows isn't recognizing a left double-click, 
3297             // so we need to simulate it here.  Allow 200 milliseconds for now. 
3298             if ( event
.LeftDClick() ) 
3300                 // double clicking should not start editing the item label 
3301                 if ( m_renameTimer 
) 
3302                     m_renameTimer
->Stop(); 
3304                 m_lastOnSame 
= false; 
3306                 // send activate event first 
3307                 wxTreeEvent 
nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
3308                 nevent
.m_item 
= item
; 
3309                 nevent
.m_pointDrag 
= CalcScrolledPosition(pt
); 
3310                 nevent
.SetEventObject( this ); 
3311                 if ( !GetEventHandler()->ProcessEvent( nevent 
) ) 
3313                     // if the user code didn't process the activate event, 
3314                     // handle it ourselves by toggling the item when it is 
3316                     if ( item
->HasPlus() ) 
3326 void wxGenericTreeCtrl::OnInternalIdle() 
3328     wxWindow::OnInternalIdle(); 
3330     // Check if we need to select the root item 
3331     // because nothing else has been selected. 
3332     // Delaying it means that we can invoke event handlers 
3333     // as required, when a first item is selected. 
3334     if (!HasFlag(wxTR_MULTIPLE
) && !GetSelection().IsOk()) 
3337             SelectItem(m_select_me
); 
3338         else if (GetRootItem().IsOk()) 
3339             SelectItem(GetRootItem()); 
3342     /* after all changes have been done to the tree control, 
3343      * we actually redraw the tree when everything is over */ 
3345     if (!m_dirty
) return; 
3346     if (m_freezeCount
) return; 
3350     CalculatePositions(); 
3352     AdjustMyScrollbars(); 
3355 void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem 
*item
, wxDC 
&dc 
) 
3360     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
3361     if ( attr 
&& attr
->HasFont() ) 
3362         dc
.SetFont(attr
->GetFont()); 
3363     else if ( item
->IsBold() ) 
3364         dc
.SetFont(m_boldFont
); 
3366         dc
.SetFont(m_normalFont
); 
3368     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
3371     // restore normal font 
3372     dc
.SetFont( m_normalFont 
); 
3376     int image 
= item
->GetCurrentImage(); 
3377     if ( image 
!= NO_IMAGE 
) 
3379         if ( m_imageListNormal 
) 
3381             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
3386     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
3389         total_h 
+= 2;            // at least 2 pixels 
3391         total_h 
+= total_h
/10;   // otherwise 10% extra spacing 
3393     item
->SetHeight(total_h
); 
3394     if (total_h
>m_lineHeight
) 
3395         m_lineHeight
=total_h
; 
3397     item
->SetWidth(image_w
+text_w
+2); 
3400 // ----------------------------------------------------------------------------- 
3401 // for developper : y is now the top of the level 
3402 // not the middle of it ! 
3403 void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
3405     int x 
= level
*m_indent
; 
3406     if (!HasFlag(wxTR_HIDE_ROOT
)) 
3410     else if (level 
== 0) 
3412         // a hidden root is not evaluated, but its 
3413         // children are always calculated 
3417     CalculateSize( item
, dc 
); 
3420     item
->SetX( x
+m_spacing 
); 
3422     y 
+= GetLineHeight(item
); 
3424     if ( !item
->IsExpanded() ) 
3426         // we don't need to calculate collapsed branches 
3431     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3432     size_t n
, count 
= children
.Count(); 
3434     for (n 
= 0; n 
< count
; ++n 
) 
3435         CalculateLevel( children
[n
], dc
, level
, y 
);  // recurse 
3438 void wxGenericTreeCtrl::CalculatePositions() 
3440     if ( !m_anchor 
) return; 
3442     wxClientDC 
dc(this); 
3445     dc
.SetFont( m_normalFont 
); 
3447     dc
.SetPen( m_dottedPen 
); 
3448     //if(GetImageList() == NULL) 
3449     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
3452     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
3455 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
3457     if (m_dirty
) return; 
3458     if (m_freezeCount
) return; 
3460     wxSize client 
= GetClientSize(); 
3463     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3464     rect
.width 
= client
.x
; 
3465     rect
.height 
= client
.y
; 
3467     Refresh(true, &rect
); 
3469     AdjustMyScrollbars(); 
3472 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
3474     if (m_dirty
) return; 
3475     if (m_freezeCount
) return; 
3478     CalcScrolledPosition(0, item
->GetY(), NULL
, &rect
.y
); 
3479     rect
.width 
= GetClientSize().x
; 
3480     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
3482     Refresh(true, &rect
); 
3485 void wxGenericTreeCtrl::RefreshSelected() 
3487     if (m_freezeCount
) return; 
3489     // TODO: this is awfully inefficient, we should keep the list of all 
3490     //       selected items internally, should be much faster 
3492         RefreshSelectedUnder(m_anchor
); 
3495 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem 
*item
) 
3497     if (m_freezeCount
) return; 
3499     if ( item
->IsSelected() ) 
3502     const wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3503     size_t count 
= children
.GetCount(); 
3504     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3506         RefreshSelectedUnder(children
[n
]); 
3510 void wxGenericTreeCtrl::Freeze() 
3515 void wxGenericTreeCtrl::Thaw() 
3517     wxCHECK_RET( m_freezeCount 
> 0, _T("thawing unfrozen tree control?") ); 
3519     if ( !--m_freezeCount 
) 
3525 // ---------------------------------------------------------------------------- 
3526 // changing colours: we need to refresh the tree control 
3527 // ---------------------------------------------------------------------------- 
3529 bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour
& colour
) 
3531     if ( !wxWindow::SetBackgroundColour(colour
) ) 
3534     if (m_freezeCount
) return true; 
3541 bool wxGenericTreeCtrl::SetForegroundColour(const wxColour
& colour
) 
3543     if ( !wxWindow::SetForegroundColour(colour
) ) 
3546     if (m_freezeCount
) return true; 
3553 // Process the tooltip event, to speed up event processing. 
3554 // Doesn't actually get a tooltip. 
3555 void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent 
&event 
) 
3561 wxSize 
wxGenericTreeCtrl::DoGetBestSize() const 
3563     // something is better than nothing... 
3564     // 100x80 is what the MSW version will get from the default 
3565     // wxControl::DoGetBestSize 
3566     return wxSize(100,80); 
3570 // NOTE: If using the wxListBox visual attributes works everywhere then this can 
3571 // be removed, as well as the #else case below. 
3572 #define _USE_VISATTR 0 
3575 #include "wx/listbox.h" 
3581 wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
3583 wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
3587     // Use the same color scheme as wxListBox 
3588     return wxListBox::GetClassDefaultAttributes(variant
); 
3590     wxVisualAttributes attr
; 
3591     attr
.colFg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
); 
3592     attr
.colBg 
= wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX
); 
3593     attr
.font  
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
3598 #if WXWIN_COMPATIBILITY_2_4 
3600 int wxGenericTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const 
3602     return GetItemImage(item
, wxTreeItemIcon_Selected
); 
3605 void wxGenericTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
) 
3607     SetItemImage(item
, image
, wxTreeItemIcon_Selected
); 
3610 #endif // WXWIN_COMPATIBILITY_2_4 
3612 #if WXWIN_COMPATIBILITY_2_2 
3614 wxTreeItemId 
wxGenericTreeCtrl::GetParent(const wxTreeItemId
& item
) const 
3616     return GetItemParent( item 
); 
3619 #endif  // WXWIN_COMPATIBILITY_2_2 
3621 #endif // wxUSE_TREECTRL