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, Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================= 
  14 // ============================================================================= 
  16 // ----------------------------------------------------------------------------- 
  18 // ----------------------------------------------------------------------------- 
  21   #pragma implementation "treectlg.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  33 #include "wx/treebase.h" 
  34 #include "wx/generic/treectlg.h" 
  36 #include "wx/textctrl.h" 
  37 #include "wx/imaglist.h" 
  38 #include "wx/settings.h" 
  39 #include "wx/dcclient.h" 
  41 // ----------------------------------------------------------------------------- 
  43 // ----------------------------------------------------------------------------- 
  45 class WXDLLEXPORT wxGenericTreeItem
; 
  47 WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem 
*, wxArrayGenericTreeItems
); 
  48 //WX_DEFINE_OBJARRAY(wxArrayTreeItemIds); 
  50 // ---------------------------------------------------------------------------- 
  52 // ---------------------------------------------------------------------------- 
  54 static const int NO_IMAGE 
= -1; 
  56 #define PIXELS_PER_UNIT 10 
  58 // ---------------------------------------------------------------------------- 
  60 // ---------------------------------------------------------------------------- 
  63 static const char *aqua_arrow_right
[] = { 
  64 /* columns rows colors chars-per-pixel */ 
  85 static const char *aqua_arrow_down
[] = { 
  86 /* columns rows colors chars-per-pixel */ 
 106 // ----------------------------------------------------------------------------- 
 108 // ----------------------------------------------------------------------------- 
 110 // timer used for enabling in-place edit 
 111 class WXDLLEXPORT wxTreeRenameTimer
: public wxTimer
 
 114     wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
); 
 119     wxGenericTreeCtrl   
*m_owner
; 
 122 // control used for in-place edit 
 123 class WXDLLEXPORT wxTreeTextCtrl
: public wxTextCtrl
 
 126     wxTreeTextCtrl( wxWindow 
*parent
, 
 130                     wxGenericTreeCtrl 
*owner
, 
 131                     const wxString 
&value 
= wxEmptyString
, 
 132                     const wxPoint 
&pos 
= wxDefaultPosition
, 
 133                     const wxSize 
&size 
= wxDefaultSize
, 
 134                     int style 
= wxSIMPLE_BORDER
, 
 135                     const wxValidator
& validator 
= wxDefaultValidator
, 
 136                     const wxString 
&name 
= wxTextCtrlNameStr 
); 
 138     void OnChar( wxKeyEvent 
&event 
); 
 139     void OnKeyUp( wxKeyEvent 
&event 
); 
 140     void OnKillFocus( wxFocusEvent 
&event 
); 
 145     wxGenericTreeCtrl  
*m_owner
; 
 146     wxString            m_startValue
; 
 149     DECLARE_EVENT_TABLE() 
 153 class WXDLLEXPORT wxGenericTreeItem
 
 157     wxGenericTreeItem() { m_data 
= NULL
; } 
 158     wxGenericTreeItem( wxGenericTreeItem 
*parent
, 
 159                        const wxString
& text
, 
 162                        wxTreeItemData 
*data 
); 
 164     ~wxGenericTreeItem(); 
 167     wxArrayGenericTreeItems
& GetChildren() { return m_children
; } 
 169     const wxString
& GetText() const { return m_text
; } 
 170     int GetImage(wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) const 
 171         { return m_images
[which
]; } 
 172     wxTreeItemData 
*GetData() const { return m_data
; } 
 174     // returns the current image for the item (depending on its 
 175     // selected/expanded/whatever state) 
 176     int GetCurrentImage() const; 
 178     void SetText( const wxString 
&text 
); 
 179     void SetImage(int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; } 
 180     void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
 182     void SetHasPlus(bool has 
= TRUE
) { m_hasPlus 
= has
; } 
 184     void SetBold(bool bold
) { m_isBold 
= bold
; } 
 186     int GetX() const { return m_x
; } 
 187     int GetY() const { return m_y
; } 
 189     void SetX(int x
) { m_x 
= x
; } 
 190     void SetY(int y
) { m_y 
= y
; } 
 192     int  GetHeight() const { return m_height
; } 
 193     int  GetWidth()  const { return m_width
; } 
 195     void SetHeight(int h
) { m_height 
= h
; } 
 196     void SetWidth(int w
) { m_width 
= w
; } 
 198     wxGenericTreeItem 
*GetParent() const { return m_parent
; } 
 201         // deletes all children notifying the treectrl about it if !NULL 
 203     void DeleteChildren(wxGenericTreeCtrl 
*tree 
= NULL
); 
 205     // get count of all children (and grand children if 'recursively') 
 206     size_t GetChildrenCount(bool recursively 
= TRUE
) const; 
 208     void Insert(wxGenericTreeItem 
*child
, size_t index
) 
 209     { m_children
.Insert(child
, index
); } 
 211     void GetSize( int &x
, int &y
, const wxGenericTreeCtrl
* ); 
 213         // return the item at given position (or NULL if no item), onButton is 
 214         // TRUE if the point belongs to the item's button, otherwise it lies 
 215         // on the button's label 
 216     wxGenericTreeItem 
*HitTest( const wxPoint
& point
, 
 217                                 const wxGenericTreeCtrl 
*, 
 221     void Expand() { m_isCollapsed 
= FALSE
; } 
 222     void Collapse() { m_isCollapsed 
= TRUE
; } 
 224     void SetHilight( bool set 
= TRUE 
) { m_hasHilight 
= set
; } 
 227     bool HasChildren() const { return !m_children
.IsEmpty(); } 
 228     bool IsSelected()  const { return m_hasHilight 
!= 0; } 
 229     bool IsExpanded()  const { return !m_isCollapsed
; } 
 230     bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 231     bool IsBold()      const { return m_isBold 
!= 0; } 
 234         // get them - may be NULL 
 235     wxTreeItemAttr 
*GetAttributes() const { return m_attr
; } 
 236         // get them ensuring that the pointer is not NULL 
 237     wxTreeItemAttr
& Attr() 
 241             m_attr 
= new wxTreeItemAttr
; 
 247     void SetAttributes(wxTreeItemAttr 
*attr
) 
 249         if ( m_ownsAttr 
) delete m_attr
; 
 253         // set them and delete when done 
 254     void AssignAttributes(wxTreeItemAttr 
*attr
) 
 261     // since there can be very many of these, we save size by chosing 
 262     // the smallest representation for the elements and by ordering 
 263     // the members to avoid padding. 
 264     wxString            m_text
;         // label to be rendered for item 
 266     wxTreeItemData     
*m_data
;         // user-provided data 
 268     wxArrayGenericTreeItems m_children
; // list of children 
 269     wxGenericTreeItem  
*m_parent
;       // parent of this item 
 271     wxTreeItemAttr     
*m_attr
;         // attributes??? 
 273     // tree ctrl images for the normal, selected, expanded and 
 274     // expanded+selected states 
 275     short               m_images
[wxTreeItemIcon_Max
]; 
 277     wxCoord             m_x
;            // (virtual) offset from top 
 278     short               m_y
;            // (virtual) offset from left 
 279     short               m_width
;        // width of this item 
 280     unsigned char       m_height
;       // height of this item 
 282     // use bitfields to save size 
 283     int                 m_isCollapsed 
:1; 
 284     int                 m_hasHilight  
:1; // same as focused 
 285     int                 m_hasPlus     
:1; // used for item which doesn't have 
 286                                           // children but has a [+] button 
 287     int                 m_isBold      
:1; // render the label in bold font 
 288     int                 m_ownsAttr    
:1; // delete attribute when done 
 291 // ============================================================================= 
 293 // ============================================================================= 
 295 // ---------------------------------------------------------------------------- 
 297 // ---------------------------------------------------------------------------- 
 299 // translate the key or mouse event flags to the type of selection we're 
 301 static void EventFlagsToSelType(long style
, 
 305                                 bool &extended_select
, 
 306                                 bool &unselect_others
) 
 308     is_multiple 
= (style 
& wxTR_MULTIPLE
) != 0; 
 309     extended_select 
= shiftDown 
&& is_multiple
; 
 310     unselect_others 
= !(extended_select 
|| (ctrlDown 
&& is_multiple
)); 
 313 // ----------------------------------------------------------------------------- 
 314 // wxTreeRenameTimer (internal) 
 315 // ----------------------------------------------------------------------------- 
 317 wxTreeRenameTimer::wxTreeRenameTimer( wxGenericTreeCtrl 
*owner 
) 
 322 void wxTreeRenameTimer::Notify() 
 324     m_owner
->OnRenameTimer(); 
 327 //----------------------------------------------------------------------------- 
 328 // wxTreeTextCtrl (internal) 
 329 //----------------------------------------------------------------------------- 
 331 BEGIN_EVENT_TABLE(wxTreeTextCtrl
,wxTextCtrl
) 
 332     EVT_CHAR           (wxTreeTextCtrl::OnChar
) 
 333     EVT_KEY_UP         (wxTreeTextCtrl::OnKeyUp
) 
 334     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus
) 
 337 wxTreeTextCtrl::wxTreeTextCtrl( wxWindow 
*parent
, 
 341                                 wxGenericTreeCtrl 
*owner
, 
 342                                 const wxString 
&value
, 
 346                                 const wxValidator
& validator
, 
 347                                 const wxString 
&name 
) 
 348     : wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name 
) 
 354     (*m_res
) = wxEmptyString
; 
 355     m_startValue 
= value
; 
 359 void wxTreeTextCtrl::OnChar( wxKeyEvent 
&event 
) 
 361     if (event
.m_keyCode 
== WXK_RETURN
) 
 364         (*m_res
) = GetValue(); 
 366         if ((*m_res
) != m_startValue
) 
 367             m_owner
->OnRenameAccept(); 
 369         if (!wxPendingDelete
.Member(this)) 
 370             wxPendingDelete
.Append(this); 
 373         m_owner
->SetFocus(); // This doesn't work. TODO. 
 377     if (event
.m_keyCode 
== WXK_ESCAPE
) 
 382         if (!wxPendingDelete
.Member(this)) 
 383             wxPendingDelete
.Append(this); 
 386         m_owner
->SetFocus(); // This doesn't work. TODO. 
 393 void wxTreeTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
 401     // auto-grow the textctrl: 
 402     wxSize parentSize 
= m_owner
->GetSize(); 
 403     wxPoint myPos 
= GetPosition(); 
 404     wxSize mySize 
= GetSize(); 
 406     GetTextExtent(GetValue() + _T("M"), &sx
, &sy
); 
 407     if (myPos
.x 
+ sx 
> parentSize
.x
) sx 
= parentSize
.x 
- myPos
.x
; 
 408     if (mySize
.x 
> sx
) sx 
= mySize
.x
; 
 414 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
 422     if (!wxPendingDelete
.Member(this)) 
 423         wxPendingDelete
.Append(this); 
 426     (*m_res
) = GetValue(); 
 428     if ((*m_res
) != m_startValue
) 
 429         m_owner
->OnRenameAccept(); 
 432 // ----------------------------------------------------------------------------- 
 434 // ----------------------------------------------------------------------------- 
 436 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 437                                      const wxString
& text
, 
 438                                      int image
, int selImage
, 
 439                                      wxTreeItemData 
*data
) 
 442     m_images
[wxTreeItemIcon_Normal
] = image
; 
 443     m_images
[wxTreeItemIcon_Selected
] = selImage
; 
 444     m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
; 
 445     m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
; 
 450     m_isCollapsed 
= TRUE
; 
 451     m_hasHilight 
= FALSE
; 
 457     m_attr 
= (wxTreeItemAttr 
*)NULL
; 
 460     // We don't know the height here yet. 
 465 wxGenericTreeItem::~wxGenericTreeItem() 
 469     if (m_ownsAttr
) delete m_attr
; 
 471     wxASSERT_MSG( m_children
.IsEmpty(), 
 472                   wxT("please call DeleteChildren() before deleting the item") ); 
 475 void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl 
*tree
) 
 477     size_t count 
= m_children
.Count(); 
 478     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 480         wxGenericTreeItem 
*child 
= m_children
[n
]; 
 482             tree
->SendDeleteEvent(child
); 
 484         child
->DeleteChildren(tree
); 
 491 void wxGenericTreeItem::SetText( const wxString 
&text 
) 
 496 size_t wxGenericTreeItem::GetChildrenCount(bool recursively
) const 
 498     size_t count 
= m_children
.Count(); 
 502     size_t total 
= count
; 
 503     for (size_t n 
= 0; n 
< count
; ++n
) 
 505         total 
+= m_children
[n
]->GetChildrenCount(); 
 511 void wxGenericTreeItem::GetSize( int &x
, int &y
, 
 512                                  const wxGenericTreeCtrl 
*theButton 
) 
 514     int bottomY
=m_y
+theButton
->GetLineHeight(this); 
 515     if ( y 
< bottomY 
) y 
= bottomY
; 
 516     int width 
= m_x 
+  m_width
; 
 517     if ( x 
< width 
) x 
= width
; 
 521         size_t count 
= m_children
.Count(); 
 522         for ( size_t n 
= 0; n 
< count
; ++n 
) 
 524             m_children
[n
]->GetSize( x
, y
, theButton 
); 
 529 wxGenericTreeItem 
*wxGenericTreeItem::HitTest(const wxPoint
& point
, 
 530                                               const wxGenericTreeCtrl 
*theCtrl
, 
 534     // for a hidden root node, don't evaluate it, but do evaluate children 
 535     if ( !(level 
== 0 && theCtrl
->HasFlag(wxTR_HIDE_ROOT
)) ) 
 538         int h 
= theCtrl
->GetLineHeight(this); 
 539         if ((point
.y 
> m_y
) && (point
.y 
< m_y 
+ h
)) 
 541             int y_mid 
= m_y 
+ h
/2; 
 542             if (point
.y 
< y_mid 
) 
 543                 flags 
|= wxTREE_HITTEST_ONITEMUPPERPART
; 
 545                 flags 
|= wxTREE_HITTEST_ONITEMLOWERPART
; 
 547             // 5 is the size of the plus sign 
 548             int xCross 
= m_x 
- theCtrl
->GetSpacing(); 
 549             if ((point
.x 
> xCross
-5) && (point
.x 
< xCross
+5) && 
 550                 (point
.y 
> y_mid
-5) && (point
.y 
< y_mid
+5) && 
 551                 HasPlus() && theCtrl
->HasButtons() ) 
 553                 flags 
|= wxTREE_HITTEST_ONITEMBUTTON
; 
 557             if ((point
.x 
>= m_x
) && (point
.x 
<= m_x
+m_width
)) 
 562                 // assuming every image (normal and selected) has the same size! 
 563                 if ( (GetImage() != NO_IMAGE
) && theCtrl
->m_imageListNormal 
) 
 564                     theCtrl
->m_imageListNormal
->GetSize(GetImage(), 
 567                 if ((image_w 
!= -1) && (point
.x 
<= m_x 
+ image_w 
+ 1)) 
 568                     flags 
|= wxTREE_HITTEST_ONITEMICON
; 
 570                     flags 
|= wxTREE_HITTEST_ONITEMLABEL
; 
 576                 flags 
|= wxTREE_HITTEST_ONITEMINDENT
; 
 577             if (point
.x 
> m_x
+m_width
) 
 578                 flags 
|= wxTREE_HITTEST_ONITEMRIGHT
; 
 583         // if children are expanded, fall through to evaluate them 
 584         if (m_isCollapsed
) return (wxGenericTreeItem
*) NULL
; 
 588     size_t count 
= m_children
.Count(); 
 589     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 591         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, 
 599     return (wxGenericTreeItem
*) NULL
; 
 602 int wxGenericTreeItem::GetCurrentImage() const 
 604     int image 
= NO_IMAGE
; 
 609             image 
= GetImage(wxTreeItemIcon_SelectedExpanded
); 
 612         if ( image 
== NO_IMAGE 
) 
 614             // we usually fall back to the normal item, but try just the 
 615             // expanded one (and not selected) first in this case 
 616             image 
= GetImage(wxTreeItemIcon_Expanded
); 
 622             image 
= GetImage(wxTreeItemIcon_Selected
); 
 625     // maybe it doesn't have the specific image we want, 
 626     // try the default one instead 
 627     if ( image 
== NO_IMAGE 
) image 
= GetImage(); 
 632 // ----------------------------------------------------------------------------- 
 633 // wxGenericTreeCtrl implementation 
 634 // ----------------------------------------------------------------------------- 
 636 IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl
, wxScrolledWindow
) 
 638 BEGIN_EVENT_TABLE(wxGenericTreeCtrl
,wxScrolledWindow
) 
 639     EVT_PAINT          (wxGenericTreeCtrl::OnPaint
) 
 640     EVT_MOUSE_EVENTS   (wxGenericTreeCtrl::OnMouse
) 
 641     EVT_CHAR           (wxGenericTreeCtrl::OnChar
) 
 642     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus
) 
 643     EVT_KILL_FOCUS     (wxGenericTreeCtrl::OnKillFocus
) 
 644     EVT_IDLE           (wxGenericTreeCtrl::OnIdle
) 
 647 #if !defined(__WXMSW__) || defined(__WIN16__) || defined(__WXUNIVERSAL__) 
 649  * wxTreeCtrl has to be a real class or we have problems with 
 650  * the run-time information. 
 653 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxGenericTreeCtrl
) 
 656 // ----------------------------------------------------------------------------- 
 657 // construction/destruction 
 658 // ----------------------------------------------------------------------------- 
 660 void wxGenericTreeCtrl::Init() 
 662     m_current 
= m_key_current 
= m_anchor 
= (wxGenericTreeItem 
*) NULL
; 
 670     m_hilightBrush 
= new wxBrush
 
 672                             wxSystemSettings::GetColour
 
 674                                 wxSYS_COLOUR_HIGHLIGHT
 
 679     m_hilightUnfocusedBrush 
= new wxBrush
 
 681                                  wxSystemSettings::GetColour
 
 683                                      wxSYS_COLOUR_BTNSHADOW
 
 688     m_imageListNormal 
= m_imageListButtons 
= 
 689     m_imageListState 
= (wxImageList 
*) NULL
; 
 690     m_ownsImageListNormal 
= m_ownsImageListButtons 
= 
 691     m_ownsImageListState 
= FALSE
; 
 694     m_isDragging 
= FALSE
; 
 695     m_dropTarget 
= m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
 697     m_renameTimer 
= new wxTreeRenameTimer( this ); 
 698     m_lastOnSame 
= FALSE
; 
 700     m_normalFont 
= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT 
); 
 701     m_boldFont 
= wxFont( m_normalFont
.GetPointSize(), 
 702                          m_normalFont
.GetFamily(), 
 703                          m_normalFont
.GetStyle(), 
 705                          m_normalFont
.GetUnderlined()); 
 708 bool wxGenericTreeCtrl::Create(wxWindow 
*parent
, 
 713                                const wxValidator 
&validator
, 
 714                                const wxString
& name 
) 
 718     wxGetOsVersion( &major
, &minor 
); 
 720     if (style 
& wxTR_HAS_BUTTONS
) style 
|= wxTR_MAC_BUTTONS
; 
 721     if (style 
& wxTR_HAS_BUTTONS
) style 
&= ~wxTR_HAS_BUTTONS
; 
 722     style 
&= ~wxTR_LINES_AT_ROOT
; 
 723     style 
|= wxTR_NO_LINES
; 
 725         style 
|= wxTR_ROW_LINES
; 
 727         style 
|= wxTR_AQUA_BUTTONS
; 
 730     if (style 
& wxTR_AQUA_BUTTONS
) 
 732         m_arrowRight 
= new wxBitmap( aqua_arrow_right 
); 
 733         m_arrowDown 
= new wxBitmap( aqua_arrow_down 
); 
 741     wxScrolledWindow::Create( parent
, id
, pos
, size
, 
 742                               style
|wxHSCROLL
|wxVSCROLL
, name 
); 
 744         // If the tree display has no buttons, but does have 
 745         // connecting lines, we can use a narrower layout. 
 746         // It may not be a good idea to force this... 
 747     if (!HasButtons() && !HasFlag(wxTR_NO_LINES
)) 
 754     SetValidator( validator 
); 
 757     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX 
) ); 
 759 //  m_dottedPen = wxPen( "grey", 0, wxDOT );  too slow under XFree86 
 760     m_dottedPen 
= wxPen( wxT("grey"), 0, 0 ); 
 765 wxGenericTreeCtrl::~wxGenericTreeCtrl() 
 767     delete m_hilightBrush
; 
 768     delete m_hilightUnfocusedBrush
; 
 770     if (m_arrowRight
) delete m_arrowRight
; 
 771     if (m_arrowDown
) delete m_arrowDown
; 
 775     delete m_renameTimer
; 
 776     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
 777     if (m_ownsImageListState
) delete m_imageListState
; 
 778     if (m_ownsImageListButtons
) delete m_imageListButtons
; 
 781 // ----------------------------------------------------------------------------- 
 783 // ----------------------------------------------------------------------------- 
 785 size_t wxGenericTreeCtrl::GetCount() const 
 787     return m_anchor 
== NULL 
? 0u : m_anchor
->GetChildrenCount(); 
 790 void wxGenericTreeCtrl::SetIndent(unsigned int indent
) 
 792     m_indent 
= (unsigned short) indent
; 
 796 void wxGenericTreeCtrl::SetSpacing(unsigned int spacing
) 
 798     m_spacing 
= (unsigned short) spacing
; 
 802 size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
) 
 804     wxCHECK_MSG( item
.IsOk(), 0u, wxT("invalid tree item") ); 
 806     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildrenCount(recursively
); 
 809 void wxGenericTreeCtrl::SetWindowStyle(const long styles
) 
 811         // right now, just sets the styles.  Eventually, we may 
 812         // want to update the inherited styles, but right now 
 813         // none of the parents has updatable styles 
 814     m_windowStyle 
= styles
; 
 818 // ----------------------------------------------------------------------------- 
 819 // functions to work with tree items 
 820 // ----------------------------------------------------------------------------- 
 822 wxString 
wxGenericTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 824     wxCHECK_MSG( item
.IsOk(), wxT(""), wxT("invalid tree item") ); 
 826     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetText(); 
 829 int wxGenericTreeCtrl::GetItemImage(const wxTreeItemId
& item
, 
 830                              wxTreeItemIcon which
) const 
 832     wxCHECK_MSG( item
.IsOk(), -1, wxT("invalid tree item") ); 
 834     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetImage(which
); 
 837 wxTreeItemData 
*wxGenericTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 839     wxCHECK_MSG( item
.IsOk(), NULL
, wxT("invalid tree item") ); 
 841     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetData(); 
 844 void wxGenericTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 846     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 849     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 850     pItem
->SetText(text
); 
 851     CalculateSize(pItem
, dc
); 
 855 void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId
& item
, 
 857                               wxTreeItemIcon which
) 
 859     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 861     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 862     pItem
->SetImage(image
, which
); 
 865     CalculateSize(pItem
, dc
); 
 869 void wxGenericTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 871     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 873     ((wxGenericTreeItem
*) item
.m_pItem
)->SetData(data
); 
 876 void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
 878     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 880     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 881     pItem
->SetHasPlus(has
); 
 885 void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
 887     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 889     // avoid redrawing the tree if no real change 
 890     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 891     if ( pItem
->IsBold() != bold 
) 
 893         pItem
->SetBold(bold
); 
 898 void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId
& item
, 
 901     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 903     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 904     pItem
->Attr().SetTextColour(col
); 
 908 void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
, 
 911     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 913     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 914     pItem
->Attr().SetBackgroundColour(col
); 
 918 void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
) 
 920     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 922     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 923     pItem
->Attr().SetFont(font
); 
 927 bool wxGenericTreeCtrl::SetFont( const wxFont 
&font 
) 
 929     wxScrolledWindow::SetFont(font
); 
 931     m_normalFont 
= font 
; 
 932     m_boldFont 
= wxFont( m_normalFont
.GetPointSize(), 
 933                             m_normalFont
.GetFamily(), 
 934                             m_normalFont
.GetStyle(), 
 936                             m_normalFont
.GetUnderlined()); 
 942 // ----------------------------------------------------------------------------- 
 943 // item status inquiries 
 944 // ----------------------------------------------------------------------------- 
 946 bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId
& item
) const 
 948     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
 950     // An item is only visible if it's not a descendant of a collapsed item 
 951     wxGenericTreeItem 
*pItem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
 952     wxGenericTreeItem
* parent 
= pItem
->GetParent(); 
 955         if (!parent
->IsExpanded()) 
 957         parent 
= parent
->GetParent(); 
 961     GetViewStart(& startX
, & startY
); 
 963     wxSize clientSize 
= GetClientSize(); 
 966     if (!GetBoundingRect(item
, rect
)) 
 968     if (rect
.GetWidth() == 0 || rect
.GetHeight() == 0) 
 970     if (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) 
 972     if (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
) 
 978 bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
 980     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
 982     // consider that the item does have children if it has the "+" button: it 
 983     // might not have them (if it had never been expanded yet) but then it 
 984     // could have them as well and it's better to err on this side rather than 
 985     // disabling some operations which are restricted to the items with 
 986     // children for an item which does have them 
 987     return ((wxGenericTreeItem
*) item
.m_pItem
)->HasPlus(); 
 990 bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
 992     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
 994     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsExpanded(); 
 997 bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
 999     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1001     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsSelected(); 
1004 bool wxGenericTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
1006     wxCHECK_MSG( item
.IsOk(), FALSE
, wxT("invalid tree item") ); 
1008     return ((wxGenericTreeItem
*) item
.m_pItem
)->IsBold(); 
1011 // ----------------------------------------------------------------------------- 
1013 // ----------------------------------------------------------------------------- 
1015 wxTreeItemId 
wxGenericTreeCtrl::GetParent(const wxTreeItemId
& item
) const 
1017     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1019     return ((wxGenericTreeItem
*) item
.m_pItem
)->GetParent(); 
1022 wxTreeItemId 
wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const 
1024     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1027     return GetNextChild(item
, cookie
); 
1030 wxTreeItemId 
wxGenericTreeCtrl::GetNextChild(const wxTreeItemId
& item
, long& cookie
) const 
1032     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1034     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1035     if ( (size_t)cookie 
< children
.Count() ) 
1037         return children
.Item((size_t)cookie
++); 
1041         // there are no more of them 
1042         return wxTreeItemId(); 
1046 wxTreeItemId 
wxGenericTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
1048     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1050     wxArrayGenericTreeItems
& children 
= ((wxGenericTreeItem
*) item
.m_pItem
)->GetChildren(); 
1051     return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
1054 wxTreeItemId 
wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
1056     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1058     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1059     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1060     if ( parent 
== NULL 
) 
1062         // root item doesn't have any siblings 
1063         return wxTreeItemId(); 
1066     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1067     int index 
= siblings
.Index(i
); 
1068     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1070     size_t n 
= (size_t)(index 
+ 1); 
1071     return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
1074 wxTreeItemId 
wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
1076     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1078     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1079     wxGenericTreeItem 
*parent 
= i
->GetParent(); 
1080     if ( parent 
== NULL 
) 
1082         // root item doesn't have any siblings 
1083         return wxTreeItemId(); 
1086     wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
1087     int index 
= siblings
.Index(i
); 
1088     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1090     return index 
== 0 ? wxTreeItemId() 
1091                       : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
1094 // Only for internal use right now, but should probably be public 
1095 wxTreeItemId 
wxGenericTreeCtrl::GetNext(const wxTreeItemId
& item
) const 
1097     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1099     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1101     // First see if there are any children. 
1102     wxArrayGenericTreeItems
& children 
= i
->GetChildren(); 
1103     if (children
.GetCount() > 0) 
1105          return children
.Item(0); 
1109          // Try a sibling of this or ancestor instead 
1110          wxTreeItemId p 
= item
; 
1111          wxTreeItemId toFind
; 
1114               toFind 
= GetNextSibling(p
); 
1116          } while (p
.IsOk() && !toFind
.IsOk()); 
1121 wxTreeItemId 
wxGenericTreeCtrl::GetFirstVisibleItem() const 
1123     wxTreeItemId id 
= GetRootItem(); 
1132     } while (id
.IsOk()); 
1134     return wxTreeItemId(); 
1137 wxTreeItemId 
wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
1139     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1141     wxTreeItemId id 
= item
; 
1144         while (id 
= GetNext(id
), id
.IsOk()) 
1150     return wxTreeItemId(); 
1153 wxTreeItemId 
wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
1155     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1157     wxFAIL_MSG(wxT("not implemented")); 
1159     return wxTreeItemId(); 
1162 // ----------------------------------------------------------------------------- 
1164 // ----------------------------------------------------------------------------- 
1166 wxTreeItemId 
wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
1168                                       const wxString
& text
, 
1169                                       int image
, int selImage
, 
1170                                       wxTreeItemData 
*data
) 
1172     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1175         // should we give a warning here? 
1176         return AddRoot(text
, image
, selImage
, data
); 
1179     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1181     wxGenericTreeItem 
*item 
= 
1182         new wxGenericTreeItem( parent
, text
, image
, selImage
, data 
); 
1186         data
->m_pItem 
= (long) item
; 
1189     parent
->Insert( item
, previous 
); 
1194 wxTreeItemId 
wxGenericTreeCtrl::AddRoot(const wxString
& text
, 
1195                                  int image
, int selImage
, 
1196                                  wxTreeItemData 
*data
) 
1198     wxCHECK_MSG( !m_anchor
, wxTreeItemId(), wxT("tree can have only one root") ); 
1200     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1202     m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, 
1203                                    image
, selImage
, data
); 
1206         data
->m_pItem 
= (long) m_anchor
; 
1209     if (HasFlag(wxTR_HIDE_ROOT
)) 
1211         // if root is hidden, make sure we can navigate 
1213         m_anchor
->SetHasPlus(); 
1217     if (!HasFlag(wxTR_MULTIPLE
)) 
1219         m_current 
= m_key_current 
= m_anchor
; 
1220         m_current
->SetHilight( TRUE 
); 
1226 wxTreeItemId 
wxGenericTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
1227                                      const wxString
& text
, 
1228                                      int image
, int selImage
, 
1229                                      wxTreeItemData 
*data
) 
1231     return DoInsertItem(parent
, 0u, text
, image
, selImage
, data
); 
1234 wxTreeItemId 
wxGenericTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
1235                                     const wxTreeItemId
& idPrevious
, 
1236                                     const wxString
& text
, 
1237                                     int image
, int selImage
, 
1238                                     wxTreeItemData 
*data
) 
1240     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1243         // should we give a warning here? 
1244         return AddRoot(text
, image
, selImage
, data
); 
1247     int index 
= parent
->GetChildren().Index((wxGenericTreeItem
*) idPrevious
.m_pItem
); 
1248     wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
1249                   wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") ); 
1251     return DoInsertItem(parentId
, (size_t)++index
, text
, image
, selImage
, data
); 
1254 wxTreeItemId 
wxGenericTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
1256                                     const wxString
& text
, 
1257                                     int image
, int selImage
, 
1258                                     wxTreeItemData 
*data
) 
1260     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1263         // should we give a warning here? 
1264         return AddRoot(text
, image
, selImage
, data
); 
1267     return DoInsertItem(parentId
, before
, text
, image
, selImage
, data
); 
1270 wxTreeItemId 
wxGenericTreeCtrl::AppendItem(const wxTreeItemId
& parentId
, 
1271                                     const wxString
& text
, 
1272                                     int image
, int selImage
, 
1273                                     wxTreeItemData 
*data
) 
1275     wxGenericTreeItem 
*parent 
= (wxGenericTreeItem
*) parentId
.m_pItem
; 
1278         // should we give a warning here? 
1279         return AddRoot(text
, image
, selImage
, data
); 
1282     return DoInsertItem( parent
, parent
->GetChildren().Count(), text
, 
1283                          image
, selImage
, data
); 
1286 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
1288     wxTreeEvent 
event( wxEVT_COMMAND_TREE_DELETE_ITEM
, GetId() ); 
1289     event
.m_item 
= (long) item
; 
1290     event
.SetEventObject( this ); 
1291     ProcessEvent( event 
); 
1294 void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
1296     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1298     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1299     item
->DeleteChildren(this); 
1302 void wxGenericTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
1304     m_dirty 
= TRUE
;     // do this first so stuff below doesn't cause flicker 
1306     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1308     // don't stay with invalid m_key_current or we will crash in 
1309     // the next call to OnChar() 
1310     bool changeKeyCurrent 
= FALSE
; 
1311     wxGenericTreeItem 
*itemKey 
= m_key_current
; 
1314         if ( itemKey 
== item 
) 
1316             // m_key_current is a descendant of the item being deleted 
1317             changeKeyCurrent 
= TRUE
; 
1320         itemKey 
= itemKey
->GetParent(); 
1323     wxGenericTreeItem 
*parent 
= item
->GetParent(); 
1326         parent
->GetChildren().Remove( item 
);  // remove by value 
1329     if ( changeKeyCurrent 
) 
1331         // may be NULL or not 
1332         m_key_current 
= parent
; 
1335     item
->DeleteChildren(this); 
1336     SendDeleteEvent(item
); 
1340 void wxGenericTreeCtrl::DeleteAllItems() 
1346         m_anchor
->DeleteChildren(this); 
1353 void wxGenericTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
1355     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1357     wxCHECK_RET( item
, _T("invalid item in wxGenericTreeCtrl::Expand") ); 
1359     if ( !item
->HasPlus() ) 
1362     if ( item
->IsExpanded() ) 
1365     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
1366     event
.m_item 
= (long) item
; 
1367     event
.SetEventObject( this ); 
1369     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1371         // cancelled by program 
1376     CalculatePositions(); 
1378     RefreshSubtree(item
); 
1380     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
1381     ProcessEvent( event 
); 
1384 void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId
& item
) 
1387     if ( IsExpanded(item
) ) 
1390         wxTreeItemId child 
= GetFirstChild(item
, cookie
); 
1391         while ( child
.IsOk() ) 
1395             child 
= GetNextChild(item
, cookie
); 
1400 void wxGenericTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
1402     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1404     if ( !item
->IsExpanded() ) 
1407     wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
1408     event
.m_item 
= (long) item
; 
1409     event
.SetEventObject( this ); 
1410     if ( ProcessEvent( event 
) && !event
.IsAllowed() ) 
1412         // cancelled by program 
1418 #if 0  // TODO why should items be collapsed recursively? 
1419     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1420     size_t count 
= children
.Count(); 
1421     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1423         Collapse(children
[n
]); 
1427     CalculatePositions(); 
1429     RefreshSubtree(item
); 
1431     event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
1432     ProcessEvent( event 
); 
1435 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
1438     DeleteChildren(item
); 
1441 void wxGenericTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
1443     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1445     if (item
->IsExpanded()) 
1451 void wxGenericTreeCtrl::Unselect() 
1455         m_current
->SetHilight( FALSE 
); 
1456         RefreshLine( m_current 
); 
1460 void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem 
*item
) 
1462     if (item
->IsSelected()) 
1464         item
->SetHilight(FALSE
); 
1468     if (item
->HasChildren()) 
1470         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1471         size_t count 
= children
.Count(); 
1472         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1474             UnselectAllChildren(children
[n
]); 
1479 void wxGenericTreeCtrl::UnselectAll() 
1481     wxTreeItemId rootItem 
= GetRootItem(); 
1483     // the tree might not have the root item at all 
1486         UnselectAllChildren((wxGenericTreeItem
*) rootItem
.m_pItem
); 
1490 // Recursive function ! 
1491 // To stop we must have crt_item<last_item 
1493 // Tag all next children, when no more children, 
1494 // Move to parent (not to tag) 
1495 // Keep going... if we found last_item, we stop. 
1496 bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1498     wxGenericTreeItem 
*parent 
= crt_item
->GetParent(); 
1500     if (parent 
== NULL
) // This is root item 
1501         return TagAllChildrenUntilLast(crt_item
, last_item
, select
); 
1503     wxArrayGenericTreeItems
& children 
= parent
->GetChildren(); 
1504     int index 
= children
.Index(crt_item
); 
1505     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1507     size_t count 
= children
.Count(); 
1508     for (size_t n
=(size_t)(index
+1); n
<count
; ++n
) 
1510         if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return TRUE
; 
1513     return TagNextChildren(parent
, last_item
, select
); 
1516 bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1518     crt_item
->SetHilight(select
); 
1519     RefreshLine(crt_item
); 
1521     if (crt_item
==last_item
) 
1524     if (crt_item
->HasChildren()) 
1526         wxArrayGenericTreeItems
& children 
= crt_item
->GetChildren(); 
1527         size_t count 
= children
.Count(); 
1528         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1530             if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) 
1538 void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem 
*item1
, wxGenericTreeItem 
*item2
) 
1540     // item2 is not necessary after item1 
1541     wxGenericTreeItem 
*first
=NULL
, *last
=NULL
; 
1543     // choice first' and 'last' between item1 and item2 
1544     if (item1
->GetY()<item2
->GetY()) 
1555     bool select 
= m_current
->IsSelected(); 
1557     if ( TagAllChildrenUntilLast(first
,last
,select
) ) 
1560     TagNextChildren(first
,last
,select
); 
1563 void wxGenericTreeCtrl::SelectItem(const wxTreeItemId
& itemId
, 
1564                             bool unselect_others
, 
1565                             bool extended_select
) 
1567     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1569     bool is_single
=!(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1570     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1572     //wxCHECK_RET( ( (!unselect_others) && is_single), 
1573     //           wxT("this is a single selection tree") ); 
1575     // to keep going anyhow !!! 
1578         if (item
->IsSelected()) 
1579             return; // nothing to do 
1580         unselect_others 
= TRUE
; 
1581         extended_select 
= FALSE
; 
1583     else if ( unselect_others 
&& item
->IsSelected() ) 
1585         // selection change if there is more than one item currently selected 
1586         wxArrayTreeItemIds selected_items
; 
1587         if ( GetSelections(selected_items
) == 1 ) 
1591     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
1592     event
.m_item 
= (long) item
; 
1593     event
.m_itemOld 
= (long) m_current
; 
1594     event
.SetEventObject( this ); 
1595     // TODO : Here we don't send any selection mode yet ! 
1597     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
1600     wxTreeItemId parent 
= GetParent( itemId 
); 
1601     while (parent
.IsOk()) 
1603         if (!IsExpanded(parent
)) 
1606         parent 
= GetParent( parent 
); 
1609     EnsureVisible( itemId 
); 
1612     if (unselect_others
) 
1614         if (is_single
) Unselect(); // to speed up thing 
1619     if (extended_select
) 
1623             m_current 
= m_key_current 
= (wxGenericTreeItem
*) GetRootItem().m_pItem
; 
1626         // don't change the mark (m_current) 
1627         SelectItemRange(m_current
, item
); 
1631         bool select
=TRUE
; // the default 
1633         // Check if we need to toggle hilight (ctrl mode) 
1634         if (!unselect_others
) 
1635             select
=!item
->IsSelected(); 
1637         m_current 
= m_key_current 
= item
; 
1638         m_current
->SetHilight(select
); 
1639         RefreshLine( m_current 
); 
1642     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
1643     GetEventHandler()->ProcessEvent( event 
); 
1646 void wxGenericTreeCtrl::FillArray(wxGenericTreeItem 
*item
, 
1647                            wxArrayTreeItemIds 
&array
) const 
1649     if ( item
->IsSelected() ) 
1650         array
.Add(wxTreeItemId(item
)); 
1652     if ( item
->HasChildren() ) 
1654         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1655         size_t count 
= children
.GetCount(); 
1656         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1657             FillArray(children
[n
], array
); 
1661 size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds 
&array
) const 
1664     wxTreeItemId idRoot 
= GetRootItem(); 
1665     if ( idRoot
.IsOk() ) 
1667         FillArray((wxGenericTreeItem
*) idRoot
.m_pItem
, array
); 
1669     //else: the tree is empty, so no selections 
1671     return array
.Count(); 
1674 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
1676     if (!item
.IsOk()) return; 
1678     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1680     // first expand all parent branches 
1681     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
1685         parent 
= parent
->GetParent(); 
1688     //if (parent) CalculatePositions(); 
1693 void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId 
&item
) 
1695     if (!item
.IsOk()) return; 
1697     // We have to call this here because the label in 
1698     // question might just have been added and no screen 
1699     // update taken place. 
1700     if (m_dirty
) wxYieldIfNeeded(); 
1702     wxGenericTreeItem 
*gitem 
= (wxGenericTreeItem
*) item
.m_pItem
; 
1704     // now scroll to the item 
1705     int item_y 
= gitem
->GetY(); 
1709     GetViewStart( &start_x
, &start_y 
); 
1710     start_y 
*= PIXELS_PER_UNIT
; 
1714     GetClientSize( &client_w
, &client_h 
); 
1716     if (item_y 
< start_y
+3) 
1721         m_anchor
->GetSize( x
, y
, this ); 
1722         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1723         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1724         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1725         // Item should appear at top 
1726         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, item_y
/PIXELS_PER_UNIT 
); 
1728     else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) 
1733         m_anchor
->GetSize( x
, y
, this ); 
1734         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1735         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1736         item_y 
+= PIXELS_PER_UNIT
+2; 
1737         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1738         // Item should appear at bottom 
1739         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 
); 
1743 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
1744 static wxGenericTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
1746 static int LINKAGEMODE 
tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
1747                                   wxGenericTreeItem 
**item2
) 
1749     wxCHECK_MSG( s_treeBeingSorted
, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") ); 
1751     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
1754 int wxGenericTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
1755                                const wxTreeItemId
& item2
) 
1757     return wxStrcmp(GetItemText(item1
), GetItemText(item2
)); 
1760 void wxGenericTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
1762     wxCHECK_RET( itemId
.IsOk(), wxT("invalid tree item") ); 
1764     wxGenericTreeItem 
*item 
= (wxGenericTreeItem
*) itemId
.m_pItem
; 
1766     wxCHECK_RET( !s_treeBeingSorted
, 
1767                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") ); 
1769     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1770     if ( children
.Count() > 1 ) 
1774         s_treeBeingSorted 
= this; 
1775         children
.Sort(tree_ctrl_compare_func
); 
1776         s_treeBeingSorted 
= NULL
; 
1778     //else: don't make the tree dirty as nothing changed 
1781 wxImageList 
*wxGenericTreeCtrl::GetImageList() const 
1783     return m_imageListNormal
; 
1786 wxImageList 
*wxGenericTreeCtrl::GetButtonsImageList() const 
1788     return m_imageListButtons
; 
1791 wxImageList 
*wxGenericTreeCtrl::GetStateImageList() const 
1793     return m_imageListState
; 
1796 void wxGenericTreeCtrl::CalculateLineHeight() 
1798     wxClientDC 
dc(this); 
1799     m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1801     if ( m_imageListNormal 
) 
1803         // Calculate a m_lineHeight value from the normal Image sizes. 
1804         // May be toggle off. Then wxGenericTreeCtrl will spread when 
1805         // necessary (which might look ugly). 
1806         int n 
= m_imageListNormal
->GetImageCount(); 
1807         for (int i 
= 0; i 
< n 
; i
++) 
1809             int width 
= 0, height 
= 0; 
1810             m_imageListNormal
->GetSize(i
, width
, height
); 
1811             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
1815     if (m_imageListButtons
) 
1817         // Calculate a m_lineHeight value from the Button image sizes. 
1818         // May be toggle off. Then wxGenericTreeCtrl will spread when 
1819         // necessary (which might look ugly). 
1820         int n 
= m_imageListButtons
->GetImageCount(); 
1821         for (int i 
= 0; i 
< n 
; i
++) 
1823             int width 
= 0, height 
= 0; 
1824             m_imageListButtons
->GetSize(i
, width
, height
); 
1825             if (height 
> m_lineHeight
) m_lineHeight 
= height
; 
1829     if (m_lineHeight 
< 30) 
1830         m_lineHeight 
+= 2;                 // at least 2 pixels 
1832         m_lineHeight 
+= m_lineHeight
/10;   // otherwise 10% extra spacing 
1835 void wxGenericTreeCtrl::SetImageList(wxImageList 
*imageList
) 
1837     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
1838     m_imageListNormal 
= imageList
; 
1839     m_ownsImageListNormal 
= FALSE
; 
1841     CalculateLineHeight(); 
1844 void wxGenericTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
1846     if (m_ownsImageListState
) delete m_imageListState
; 
1847     m_imageListState 
= imageList
; 
1848     m_ownsImageListState 
= FALSE
; 
1851 void wxGenericTreeCtrl::SetButtonsImageList(wxImageList 
*imageList
) 
1853     if (m_ownsImageListButtons
) delete m_imageListButtons
; 
1854     m_imageListButtons 
= imageList
; 
1855     m_ownsImageListButtons 
= FALSE
; 
1857     CalculateLineHeight(); 
1860 void wxGenericTreeCtrl::AssignImageList(wxImageList 
*imageList
) 
1862     SetImageList(imageList
); 
1863     m_ownsImageListNormal 
= TRUE
; 
1866 void wxGenericTreeCtrl::AssignStateImageList(wxImageList 
*imageList
) 
1868     SetStateImageList(imageList
); 
1869     m_ownsImageListState 
= TRUE
; 
1872 void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList 
*imageList
) 
1874     SetButtonsImageList(imageList
); 
1875     m_ownsImageListButtons 
= TRUE
; 
1878 // ----------------------------------------------------------------------------- 
1880 // ----------------------------------------------------------------------------- 
1882 void wxGenericTreeCtrl::AdjustMyScrollbars() 
1887         m_anchor
->GetSize( x
, y
, this ); 
1888         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1889         x 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1890         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1891         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
1892         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, y_pos 
); 
1896         SetScrollbars( 0, 0, 0, 0 ); 
1900 int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem 
*item
) const 
1902     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
1903         return item
->GetHeight(); 
1905         return m_lineHeight
; 
1908 void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
1910     // TODO implement "state" icon on items 
1912     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
1913     if ( attr 
&& attr
->HasFont() ) 
1914         dc
.SetFont(attr
->GetFont()); 
1915     else if (item
->IsBold()) 
1916         dc
.SetFont(m_boldFont
); 
1918     long text_w 
= 0, text_h 
= 0; 
1919     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
1921     int image_h 
= 0, image_w 
= 0; 
1922     int image 
= item
->GetCurrentImage(); 
1923     if ( image 
!= NO_IMAGE 
) 
1925         if ( m_imageListNormal 
) 
1927             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
1936     int total_h 
= GetLineHeight(item
); 
1938     if ( item
->IsSelected() ) 
1940         dc
.SetBrush(*(m_hasFocus 
? m_hilightBrush 
: m_hilightUnfocusedBrush
)); 
1945         if ( attr 
&& attr
->HasBackgroundColour() ) 
1946             colBg 
= attr
->GetBackgroundColour(); 
1948             colBg 
= m_backgroundColour
; 
1949         dc
.SetBrush(wxBrush(colBg
, wxSOLID
)); 
1952     int offset 
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0; 
1954     if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT
) ) 
1958         DoGetPosition(&x
, &y
); 
1960         dc
.DrawRectangle(x
, item
->GetY()+offset
, w
, total_h
-offset
); 
1964         if ( item
->IsSelected() && image 
!= NO_IMAGE 
) 
1966             // If it's selected, and there's an image, then we should 
1967             // take care to leave the area under the image painted in the 
1968             // background colour. 
1969             dc
.DrawRectangle( item
->GetX() + image_w 
- 2, item
->GetY()+offset
, 
1970                               item
->GetWidth() - image_w 
+ 2, total_h
-offset 
); 
1974             dc
.DrawRectangle( item
->GetX()-2, item
->GetY()+offset
, 
1975                               item
->GetWidth()+2, total_h
-offset 
); 
1979     if ( image 
!= NO_IMAGE 
) 
1981         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
1982         m_imageListNormal
->Draw( image
, dc
, 
1984                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
1985                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
1986         dc
.DestroyClippingRegion(); 
1989     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1990     int extraH 
= (total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0; 
1991     dc
.DrawText( item
->GetText(), 
1992                  (wxCoord
)(image_w 
+ item
->GetX()), 
1993                  (wxCoord
)(item
->GetY() + extraH
)); 
1995     // restore normal font 
1996     dc
.SetFont( m_normalFont 
); 
1999 // Now y stands for the top of the item, whereas it used to stand for middle ! 
2000 void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
2002     int x 
= level
*m_indent
; 
2003     if (!HasFlag(wxTR_HIDE_ROOT
)) 
2007     else if (level 
== 0) 
2009         // always expand hidden root 
2011         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2012         int count 
= children
.Count(); 
2018                 PaintLevel(children
[n
], dc
, 1, y
); 
2019             } while (++n 
< count
); 
2021             if (!HasFlag(wxTR_NO_LINES
) && HasFlag(wxTR_LINES_AT_ROOT
) && count 
> 0) 
2023                 // draw line down to last child 
2024                 origY 
+= GetLineHeight(children
[0])>>1; 
2025                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2026                 dc
.DrawLine(3, origY
, 3, oldY
); 
2032     item
->SetX(x
+m_spacing
); 
2035     int h 
= GetLineHeight(item
); 
2037     int y_mid 
= y_top 
+ (h
>>1); 
2040     int exposed_x 
= dc
.LogicalToDeviceX(0); 
2041     int exposed_y 
= dc
.LogicalToDeviceY(y_top
); 
2043     if (IsExposed(exposed_x
, exposed_y
, 10000, h
))  // 10000 = very much 
2047             // don't draw rect outline if we already have the 
2048             // background color under Mac 
2049             (item
->IsSelected() && m_hasFocus
) ? wxBLACK_PEN 
: 
2050 #endif // !__WXMAC__ 
2054         if ( item
->IsSelected() ) 
2056             colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
2060             wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2061             if (attr 
&& attr
->HasTextColour()) 
2062                 colText 
= attr
->GetTextColour(); 
2064                 colText 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
); 
2068         dc
.SetTextForeground(colText
); 
2072         PaintItem(item
, dc
); 
2074         if (HasFlag(wxTR_ROW_LINES
)) 
2076             // if the background colour is white, choose a 
2077             // contrasting color for the lines 
2078             dc
.SetPen(*((GetBackgroundColour() == *wxWHITE
) 
2079                          ? wxMEDIUM_GREY_PEN 
: wxWHITE_PEN
)); 
2080             dc
.DrawLine(0, y_top
, 10000, y_top
); 
2081             dc
.DrawLine(0, y
, 10000, y
); 
2084         // restore DC objects 
2085         dc
.SetBrush(*wxWHITE_BRUSH
); 
2086         dc
.SetPen(m_dottedPen
); 
2087         dc
.SetTextForeground(*wxBLACK
); 
2089         if (item
->HasPlus() && HasButtons())  // should the item show a button? 
2091             if (!HasFlag(wxTR_NO_LINES
)) 
2093                 if (x 
> (signed)m_indent
) 
2094                     dc
.DrawLine(x 
- m_indent
, y_mid
, x 
- 5, y_mid
); 
2095                 else if (HasFlag(wxTR_LINES_AT_ROOT
)) 
2096                     dc
.DrawLine(3, y_mid
, x 
- 5, y_mid
); 
2097                 dc
.DrawLine(x 
+ 5, y_mid
, x 
+ m_spacing
, y_mid
); 
2100             if (m_imageListButtons 
!= NULL
) 
2102                 // draw the image button here 
2103                 int image_h 
= 0, image_w 
= 0, image 
= wxTreeItemIcon_Normal
; 
2104                 if (item
->IsExpanded()) image 
= wxTreeItemIcon_Expanded
; 
2105                 if (item
->IsSelected()) 
2106                     image 
+= wxTreeItemIcon_Selected 
- wxTreeItemIcon_Normal
; 
2107                 m_imageListButtons
->GetSize(image
, image_w
, image_h
); 
2108                 int xx 
= x 
- (image_w
>>1); 
2109                 int yy 
= y_mid 
- (image_h
>>1); 
2110                 dc
.SetClippingRegion(xx
, yy
, image_w
, image_h
); 
2111                 m_imageListButtons
->Draw(image
, dc
, xx
, yy
, 
2112                                          wxIMAGELIST_DRAW_TRANSPARENT
); 
2113                 dc
.DestroyClippingRegion(); 
2115             else if (HasFlag(wxTR_TWIST_BUTTONS
)) 
2117                 // draw the twisty button here 
2119                 if (HasFlag(wxTR_AQUA_BUTTONS
)) 
2121                     if (item
->IsExpanded()) 
2122                         dc
.DrawBitmap( *m_arrowDown
, x
-5, y_mid
-6, TRUE 
); 
2124                         dc
.DrawBitmap( *m_arrowRight
, x
-5, y_mid
-6, TRUE 
); 
2128                     dc
.SetBrush(*m_hilightBrush
); 
2129                     dc
.SetPen(*wxBLACK_PEN
); 
2132                     if (item
->IsExpanded()) 
2135                         button
[0].y 
= y_mid
-2; 
2137                         button
[1].y 
= y_mid
-2; 
2139                         button
[2].y 
= y_mid
+3; 
2143                         button
[0].y 
= y_mid
-5; 
2145                         button
[1].y 
= y_mid
+5; 
2147                         button
[2].y 
= y_mid
; 
2150                     dc
.DrawPolygon(3, button
); 
2151                     dc
.SetPen(m_dottedPen
); 
2154             else // if (HasFlag(wxTR_HAS_BUTTONS)) 
2156                 // draw the plus sign here 
2157                 dc
.SetPen(*wxGREY_PEN
); 
2158                 dc
.SetBrush(*wxWHITE_BRUSH
); 
2159                 dc
.DrawRectangle(x
-5, y_mid
-4, 11, 9); 
2160                 dc
.SetPen(*wxBLACK_PEN
); 
2161                 dc
.DrawLine(x
-2, y_mid
, x
+3, y_mid
); 
2162                 if (!item
->IsExpanded()) 
2163                     dc
.DrawLine(x
, y_mid
-2, x
, y_mid
+3); 
2164                 dc
.SetPen(m_dottedPen
); 
2167         else if (!HasFlag(wxTR_NO_LINES
))  // no button; maybe a line? 
2169             // draw the horizontal line here 
2171             if (x 
> (signed)m_indent
) 
2172                 x_start 
-= m_indent
; 
2173             else if (HasFlag(wxTR_LINES_AT_ROOT
)) 
2175             dc
.DrawLine(x_start
, y_mid
, x 
+ m_spacing
, y_mid
); 
2179     if (item
->IsExpanded()) 
2181         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2182         int count 
= children
.Count(); 
2189                 PaintLevel(children
[n
], dc
, level
, y
); 
2190             } while (++n 
< count
); 
2192             if (!HasFlag(wxTR_NO_LINES
) && count 
> 0) 
2194                 // draw line down to last child 
2195                 oldY 
+= GetLineHeight(children
[n
-1])>>1; 
2196                 if (HasButtons()) y_mid 
+= 5; 
2197                 dc
.DrawLine(x
, y_mid
, x
, oldY
); 
2203 void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem 
*item
) 
2207         if ( item
->HasPlus() ) 
2209             // it's a folder, indicate it by a border 
2214             // draw a line under the drop target because the item will be 
2216             DrawLine(item
, TRUE 
/* below */); 
2219         SetCursor(wxCURSOR_BULLSEYE
); 
2224         SetCursor(wxCURSOR_NO_ENTRY
); 
2228 void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId 
&item
) 
2230     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2232     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2234     wxClientDC 
dc(this); 
2236     dc
.SetLogicalFunction(wxINVERT
); 
2237     dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
2239     int w 
= i
->GetWidth() + 2; 
2240     int h 
= GetLineHeight(i
) + 2; 
2242     dc
.DrawRectangle( i
->GetX() - 1, i
->GetY() - 1, w
, h
); 
2245 void wxGenericTreeCtrl::DrawLine(const wxTreeItemId 
&item
, bool below
) 
2247     wxCHECK_RET( item
.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); 
2249     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2251     wxClientDC 
dc(this); 
2253     dc
.SetLogicalFunction(wxINVERT
); 
2259         y 
+= GetLineHeight(i
) - 1; 
2262     dc
.DrawLine( x
, y
, x 
+ i
->GetWidth(), y
); 
2265 // ----------------------------------------------------------------------------- 
2266 // wxWindows callbacks 
2267 // ----------------------------------------------------------------------------- 
2269 void wxGenericTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
2277     dc
.SetFont( m_normalFont 
); 
2278     dc
.SetPen( m_dottedPen 
); 
2280     // this is now done dynamically 
2281     //if(GetImageList() == NULL) 
2282     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
2285     PaintLevel( m_anchor
, dc
, 0, y 
); 
2288 void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent 
&event 
) 
2297 void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
2306 void wxGenericTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
2308     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
2309     te
.m_evtKey 
= event
; 
2310     te
.SetEventObject( this ); 
2311     if ( GetEventHandler()->ProcessEvent( te 
) ) 
2313         // intercepted by the user code 
2317     if ( (m_current 
== 0) || (m_key_current 
== 0) ) 
2323     // how should the selection work for this event? 
2324     bool is_multiple
, extended_select
, unselect_others
; 
2325     EventFlagsToSelType(GetWindowStyleFlag(), 
2327                         event
.ControlDown(), 
2328                         is_multiple
, extended_select
, unselect_others
); 
2332     // * : Expand all/Collapse all 
2333     // ' ' | return : activate 
2334     // up    : go up (not last children!) 
2336     // left  : go to parent 
2337     // right : open if parent and go next 
2338     // home  : go to root 
2339     // end   : go to last item without opening parents 
2340     switch (event
.KeyCode()) 
2344             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
2352             if ( !IsExpanded(m_current
) ) 
2355                 ExpandAll(m_current
); 
2358             //else: fall through to Collapse() it 
2362             if (IsExpanded(m_current
)) 
2364                 Collapse(m_current
); 
2371                 wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
2372                 event
.m_item 
= (long) m_current
; 
2373                 event
.SetEventObject( this ); 
2374                 GetEventHandler()->ProcessEvent( event 
); 
2378             // up goes to the previous sibling or to the last 
2379             // of its children if it's expanded 
2382                 wxTreeItemId prev 
= GetPrevSibling( m_key_current 
); 
2385                     prev 
= GetParent( m_key_current 
); 
2386                     if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2388                         break;  // don't go to root if it is hidden 
2393                         wxTreeItemId current 
= m_key_current
; 
2394                         // TODO: Huh?  If we get here, we'd better be the first child of our parent.  How else could it be? 
2395                         if (current 
== GetFirstChild( prev
, cookie 
)) 
2397                             // otherwise we return to where we came from 
2398                             SelectItem( prev
, unselect_others
, extended_select 
); 
2399                             m_key_current
= (wxGenericTreeItem
*) prev
.m_pItem
; 
2400                             EnsureVisible( prev 
); 
2407                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
2409                         wxTreeItemId child 
= GetLastChild(prev
); 
2416                     SelectItem( prev
, unselect_others
, extended_select 
); 
2417                     m_key_current
=(wxGenericTreeItem
*) prev
.m_pItem
; 
2418                     EnsureVisible( prev 
); 
2423             // left arrow goes to the parent 
2426                 wxTreeItemId prev 
= GetParent( m_current 
); 
2427                 if ((prev 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) 
2429                     // don't go to root if it is hidden 
2430                     prev 
= GetPrevSibling( m_current 
); 
2434                     EnsureVisible( prev 
); 
2435                     SelectItem( prev
, unselect_others
, extended_select 
); 
2441             // this works the same as the down arrow except that we 
2442             // also expand the item if it wasn't expanded yet 
2448                 if (IsExpanded(m_key_current
) && HasChildren(m_key_current
)) 
2451                     wxTreeItemId child 
= GetFirstChild( m_key_current
, cookie 
); 
2452                     SelectItem( child
, unselect_others
, extended_select 
); 
2453                     m_key_current
=(wxGenericTreeItem
*) child
.m_pItem
; 
2454                     EnsureVisible( child 
); 
2458                     wxTreeItemId next 
= GetNextSibling( m_key_current 
); 
2461                         wxTreeItemId current 
= m_key_current
; 
2462                         while (current 
&& !next
) 
2464                             current 
= GetParent( current 
); 
2465                             if (current
) next 
= GetNextSibling( current 
); 
2470                         SelectItem( next
, unselect_others
, extended_select 
); 
2471                         m_key_current
=(wxGenericTreeItem
*) next
.m_pItem
; 
2472                         EnsureVisible( next 
); 
2478             // <End> selects the last visible tree item 
2481                 wxTreeItemId last 
= GetRootItem(); 
2483                 while ( last
.IsOk() && IsExpanded(last
) ) 
2485                     wxTreeItemId lastChild 
= GetLastChild(last
); 
2487                     // it may happen if the item was expanded but then all of 
2488                     // its children have been deleted - so IsExpanded() returned 
2489                     // TRUE, but GetLastChild() returned invalid item 
2498                     EnsureVisible( last 
); 
2499                     SelectItem( last
, unselect_others
, extended_select 
); 
2504             // <Home> selects the root item 
2507                 wxTreeItemId prev 
= GetRootItem(); 
2509                 if (HasFlag(wxTR_HIDE_ROOT
)) 
2512                     prev 
= GetFirstChild(prev
, dummy
); 
2515                 EnsureVisible( prev 
); 
2516                 SelectItem( prev
, unselect_others
, extended_select 
); 
2525 wxTreeItemId 
wxGenericTreeCtrl::HitTest(const wxPoint
& point
, int& flags
) 
2527     // JACS: removed wxYieldIfNeeded() because it can cause the window 
2528     // to be deleted from under us if a close window event is pending 
2533     if (point
.x
<0) flags 
|= wxTREE_HITTEST_TOLEFT
; 
2534     if (point
.x
>w
) flags 
|= wxTREE_HITTEST_TORIGHT
; 
2535     if (point
.y
<0) flags 
|= wxTREE_HITTEST_ABOVE
; 
2536     if (point
.y
>h
) flags 
|= wxTREE_HITTEST_BELOW
; 
2537     if (flags
) return wxTreeItemId(); 
2539     if (m_anchor 
== NULL
) 
2541         flags 
= wxTREE_HITTEST_NOWHERE
; 
2542         return wxTreeItemId(); 
2545     wxClientDC 
dc(this); 
2547     wxCoord x 
= dc
.DeviceToLogicalX( point
.x 
); 
2548     wxCoord y 
= dc
.DeviceToLogicalY( point
.y 
); 
2549     wxGenericTreeItem 
*hit 
=  m_anchor
->HitTest(wxPoint(x
, y
), 
2555         flags 
= wxTREE_HITTEST_NOWHERE
; 
2556         return wxTreeItemId(); 
2561 // get the bounding rectangle of the item (or of its label only) 
2562 bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
, 
2564                          bool WXUNUSED(textOnly
)) const 
2566     wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") ); 
2568     wxGenericTreeItem 
*i 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2571     GetViewStart(& startX
, & startY
); 
2573     rect
.x 
= i
->GetX() - startX
*PIXELS_PER_UNIT
; 
2574     rect
.y 
= i
->GetY() - startY
*PIXELS_PER_UNIT
; 
2575     rect
.width 
= i
->GetWidth(); 
2576     //rect.height = i->GetHeight(); 
2577     rect
.height 
= GetLineHeight(i
); 
2584 void wxGenericTreeCtrl::Edit( const wxTreeItemId
& item 
) 
2586     if (!item
.IsOk()) return; 
2588     m_currentEdit 
= (wxGenericTreeItem
*) item
.m_pItem
; 
2590     wxTreeEvent 
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, GetId() ); 
2591     te
.m_item 
= (long) m_currentEdit
; 
2592     te
.SetEventObject( this ); 
2593     GetEventHandler()->ProcessEvent( te 
); 
2595     if (!te
.IsAllowed()) return; 
2597     // We have to call this here because the label in 
2598     // question might just have been added and no screen 
2599     // update taken place. 
2600     if (m_dirty
) wxYieldIfNeeded(); 
2602     wxString s 
= m_currentEdit
->GetText(); 
2603     int x 
= m_currentEdit
->GetX(); 
2604     int y 
= m_currentEdit
->GetY(); 
2605     int w 
= m_currentEdit
->GetWidth(); 
2606     int h 
= m_currentEdit
->GetHeight(); 
2611     int image 
= m_currentEdit
->GetCurrentImage(); 
2612     if ( image 
!= NO_IMAGE 
) 
2614         if ( m_imageListNormal 
) 
2616             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
2621             wxFAIL_MSG(_T("you must create an image list to use images!")); 
2625     w 
-= image_w 
+ 4; // I don't know why +4 is needed 
2627     wxClientDC 
dc(this); 
2629     x 
= dc
.LogicalToDeviceX( x 
); 
2630     y 
= dc
.LogicalToDeviceY( y 
); 
2632     wxTreeTextCtrl 
*text 
= new wxTreeTextCtrl(this, -1, 
2642 void wxGenericTreeCtrl::OnRenameTimer() 
2647 void wxGenericTreeCtrl::OnRenameAccept() 
2649     // TODO if the validator fails this causes a crash 
2650     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
2651     le
.m_item 
= (long) m_currentEdit
; 
2652     le
.SetEventObject( this ); 
2653     le
.m_label 
= m_renameRes
; 
2654     GetEventHandler()->ProcessEvent( le 
); 
2656     if (!le
.IsAllowed()) return; 
2658     SetItemText( m_currentEdit
, m_renameRes 
); 
2661 void wxGenericTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
2663     if ( !m_anchor 
) return; 
2665     // we process left mouse up event (enables in-place edit), right down 
2666     // (pass to the user code), left dbl click (activate item) and 
2667     // dragging/moving events for items drag-and-drop 
2668     if ( !(event
.LeftDown() || 
2670            event
.RightDown() || 
2671            event
.LeftDClick() || 
2673            ((event
.Moving() || event
.RightUp()) && m_isDragging
)) ) 
2680     wxClientDC 
dc(this); 
2682     wxCoord x 
= dc
.DeviceToLogicalX( event
.GetX() ); 
2683     wxCoord y 
= dc
.DeviceToLogicalY( event
.GetY() ); 
2686     wxGenericTreeItem 
*item 
= m_anchor
->HitTest( wxPoint(x
,y
), 
2691     if ( event
.Dragging() && !m_isDragging 
) 
2693         if (m_dragCount 
== 0) 
2694             m_dragStart 
= wxPoint(x
,y
); 
2698         if (m_dragCount 
!= 3) 
2700             // wait until user drags a bit further... 
2704         wxEventType command 
= event
.RightIsDown() 
2705                               ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
 
2706                               : wxEVT_COMMAND_TREE_BEGIN_DRAG
; 
2708         wxTreeEvent 
nevent( command
, GetId() ); 
2709         nevent
.m_item 
= (long) m_current
; 
2710         nevent
.SetEventObject(this); 
2712         // by default the dragging is not supported, the user code must 
2713         // explicitly allow the event for it to take place 
2716         if ( GetEventHandler()->ProcessEvent(nevent
) && nevent
.IsAllowed() ) 
2718             // we're going to drag this item 
2719             m_isDragging 
= TRUE
; 
2721             // remember the old cursor because we will change it while 
2723             m_oldCursor 
= m_cursor
; 
2725             // in a single selection control, hide the selection temporarily 
2726             if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE
) ) 
2728                 m_oldSelection 
= (wxGenericTreeItem
*) GetSelection().m_pItem
; 
2730                 if ( m_oldSelection 
) 
2732                     m_oldSelection
->SetHilight(FALSE
); 
2733                     RefreshLine(m_oldSelection
); 
2740     else if ( event
.Moving() ) 
2742         if ( item 
!= m_dropTarget 
) 
2744             // unhighlight the previous drop target 
2745             DrawDropEffect(m_dropTarget
); 
2747             m_dropTarget 
= item
; 
2749             // highlight the current drop target if any 
2750             DrawDropEffect(m_dropTarget
); 
2755     else if ( (event
.LeftUp() || event
.RightUp()) && m_isDragging 
) 
2757         // erase the highlighting 
2758         DrawDropEffect(m_dropTarget
); 
2760         if ( m_oldSelection 
) 
2762             m_oldSelection
->SetHilight(TRUE
); 
2763             RefreshLine(m_oldSelection
); 
2764             m_oldSelection 
= (wxGenericTreeItem 
*)NULL
; 
2767         // generate the drag end event 
2768         wxTreeEvent 
event(wxEVT_COMMAND_TREE_END_DRAG
, GetId()); 
2770         event
.m_item 
= (long) item
; 
2771         event
.m_pointDrag 
= wxPoint(x
, y
); 
2772         event
.SetEventObject(this); 
2774         (void)GetEventHandler()->ProcessEvent(event
); 
2776         m_isDragging 
= FALSE
; 
2777         m_dropTarget 
= (wxGenericTreeItem 
*)NULL
; 
2781         SetCursor(m_oldCursor
); 
2787         // here we process only the messages which happen on tree items 
2791         if (item 
== NULL
) return;  /* we hit the blank area */ 
2793         if ( event
.RightDown() ) 
2795             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
, GetId()); 
2796             nevent
.m_item 
= (long) item
; 
2797             CalcScrolledPosition(x
, y
, 
2798                                  &nevent
.m_pointDrag
.x
, 
2799                                  &nevent
.m_pointDrag
.y
); 
2800             nevent
.SetEventObject(this); 
2801             GetEventHandler()->ProcessEvent(nevent
); 
2803         else if ( event
.LeftUp() ) 
2807                 if ( (item 
== m_current
) && 
2808                      (flags 
& wxTREE_HITTEST_ONITEMLABEL
) && 
2809                      HasFlag(wxTR_EDIT_LABELS
) ) 
2811                     if ( m_renameTimer
->IsRunning() ) 
2812                         m_renameTimer
->Stop(); 
2814                     m_renameTimer
->Start( 100, TRUE 
); 
2817                 m_lastOnSame 
= FALSE
; 
2820         else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick() 
2822             if ( event
.LeftDown() ) 
2824                 m_lastOnSame 
= item 
== m_current
; 
2827             if ( flags 
& wxTREE_HITTEST_ONITEMBUTTON 
) 
2829                 // only toggle the item for a single click, double click on 
2830                 // the button doesn't do anything (it toggles the item twice) 
2831                 if ( event
.LeftDown() ) 
2836                 // don't select the item if the button was clicked 
2840             // how should the selection work for this event? 
2841             bool is_multiple
, extended_select
, unselect_others
; 
2842             EventFlagsToSelType(GetWindowStyleFlag(), 
2844                                 event
.ControlDown(), 
2845                                 is_multiple
, extended_select
, unselect_others
); 
2847             SelectItem(item
, unselect_others
, extended_select
); 
2849             // For some reason, Windows isn't recognizing a left double-click, 
2850             // so we need to simulate it here.  Allow 200 milliseconds for now. 
2851             if ( event
.LeftDClick() ) 
2853                 // double clicking should not start editing the item label 
2854                 m_renameTimer
->Stop(); 
2855                 m_lastOnSame 
= FALSE
; 
2857                 // send activate event first 
2858                 wxTreeEvent 
nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
2859                 nevent
.m_item 
= (long) item
; 
2860                 CalcScrolledPosition(x
, y
, 
2861                                      &nevent
.m_pointDrag
.x
, 
2862                                      &nevent
.m_pointDrag
.y
); 
2863                 nevent
.SetEventObject( this ); 
2864                 if ( !GetEventHandler()->ProcessEvent( nevent 
) ) 
2866                     // if the user code didn't process the activate event, 
2867                     // handle it ourselves by toggling the item when it is 
2869                     if ( item
->HasPlus() ) 
2879 void wxGenericTreeCtrl::OnIdle( wxIdleEvent 
&WXUNUSED(event
) ) 
2881     /* after all changes have been done to the tree control, 
2882      * we actually redraw the tree when everything is over */ 
2884     if (!m_dirty
) return; 
2888     CalculatePositions(); 
2890     AdjustMyScrollbars(); 
2893 void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem 
*item
, wxDC 
&dc 
) 
2899         dc
.SetFont(m_boldFont
); 
2901     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
2904     // restore normal font 
2905     dc
.SetFont( m_normalFont 
); 
2909     int image 
= item
->GetCurrentImage(); 
2910     if ( image 
!= NO_IMAGE 
) 
2912         if ( m_imageListNormal 
) 
2914             m_imageListNormal
->GetSize( image
, image_w
, image_h 
); 
2919     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
2922         total_h 
+= 2;            // at least 2 pixels 
2924         total_h 
+= total_h
/10;   // otherwise 10% extra spacing 
2926     item
->SetHeight(total_h
); 
2927     if (total_h
>m_lineHeight
) 
2928         m_lineHeight
=total_h
; 
2930     item
->SetWidth(image_w
+text_w
+2); 
2933 // ----------------------------------------------------------------------------- 
2934 // for developper : y is now the top of the level 
2935 // not the middle of it ! 
2936 void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
2938     int x 
= level
*m_indent
; 
2939     if (!HasFlag(wxTR_HIDE_ROOT
)) 
2943     else if (level 
== 0) 
2945         // a hidden root is not evaluated, but its 
2946         // children are always calculated 
2950     CalculateSize( item
, dc 
); 
2953     item
->SetX( x
+m_spacing 
); 
2955     y 
+= GetLineHeight(item
); 
2957     if ( !item
->IsExpanded() ) 
2959         // we don't need to calculate collapsed branches 
2964     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2965     size_t n
, count 
= children
.Count(); 
2967     for (n 
= 0; n 
< count
; ++n 
) 
2968         CalculateLevel( children
[n
], dc
, level
, y 
);  // recurse 
2971 void wxGenericTreeCtrl::CalculatePositions() 
2973     if ( !m_anchor 
) return; 
2975     wxClientDC 
dc(this); 
2978     dc
.SetFont( m_normalFont 
); 
2980     dc
.SetPen( m_dottedPen 
); 
2981     //if(GetImageList() == NULL) 
2982     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
2985     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
2988 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
2990     if (m_dirty
) return; 
2992     wxClientDC 
dc(this); 
2997     GetClientSize( &cw
, &ch 
); 
3000     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
3002     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
3005     Refresh( TRUE
, &rect 
); 
3007     AdjustMyScrollbars(); 
3010 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
3012     if (m_dirty
) return; 
3014     wxClientDC 
dc(this); 
3019     GetClientSize( &cw
, &ch 
); 
3022     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
3023     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
3025     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
3027     Refresh( TRUE
, &rect 
); 
3030 void wxGenericTreeCtrl::RefreshSelected() 
3032     // TODO: this is awfully inefficient, we should keep the list of all 
3033     //       selected items internally, should be much faster 
3035         RefreshSelectedUnder(m_anchor
); 
3038 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem 
*item
) 
3040     if ( item
->IsSelected() ) 
3043     const wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
3044     size_t count 
= children
.GetCount(); 
3045     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3047         RefreshSelectedUnder(children
[n
]); 
3051 // ---------------------------------------------------------------------------- 
3052 // changing colours: we need to refresh the tree control 
3053 // ---------------------------------------------------------------------------- 
3055 bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour
& colour
) 
3057     if ( !wxWindow::SetBackgroundColour(colour
) ) 
3065 bool wxGenericTreeCtrl::SetForegroundColour(const wxColour
& colour
) 
3067     if ( !wxWindow::SetForegroundColour(colour
) ) 
3075 #endif // wxUSE_TREECTRL