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 "treectrl.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  31 #include "wx/generic/treectrl.h" 
  32 #include "wx/generic/imaglist.h" 
  33 #include "wx/settings.h" 
  36 #include "wx/dynarray.h" 
  37 #include "wx/dcclient.h" 
  38 #include "wx/msgdlg.h" 
  40 // ----------------------------------------------------------------------------- 
  42 // ----------------------------------------------------------------------------- 
  44 class WXDLLEXPORT wxGenericTreeItem
; 
  46 WX_DEFINE_ARRAY(wxGenericTreeItem 
*, wxArrayTreeItems
); 
  48 // ----------------------------------------------------------------------------- 
  50 // ----------------------------------------------------------------------------- 
  53 class WXDLLEXPORT wxGenericTreeItem
 
  57   wxGenericTreeItem() { m_data 
= NULL
; } 
  58   wxGenericTreeItem( wxGenericTreeItem 
*parent
, 
  61                      int image
, int selImage
, 
  62                      wxTreeItemData 
*data 
); 
  67   wxArrayTreeItems
& GetChildren() { return m_children
; } 
  69   const wxString
& GetText() const { return m_text
; } 
  70   int GetImage() const { return m_image
; } 
  71   int GetSelectedImage() const { return m_selImage
; } 
  72   wxTreeItemData 
*GetData() const { return m_data
; } 
  74   void SetText( const wxString 
&text
, wxDC
& dc 
); 
  75   void SetImage(int image
) { m_image 
= image
; } 
  76   void SetSelectedImage(int image
) { m_selImage 
= image
; } 
  77   void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
  79   void SetHasPlus(bool has 
= TRUE
) { m_hasPlus 
= has
; } 
  81   void SetBold(bool bold
) { m_isBold 
= bold
; } 
  83   int GetX() const { return m_x
; } 
  84   int GetY() const { return m_y
; } 
  86   void SetHeight(int h
) { m_height 
= h
; } 
  88   void SetX(int x
) { m_x 
= x
; } 
  89   void SetY(int y
) { m_y 
= y
; } 
  91   wxGenericTreeItem 
*GetParent() const { return m_parent
; } 
  94     // deletes all children notifying the treectrl about it if !NULL pointer 
  96   void DeleteChildren(wxTreeCtrl 
*tree 
= NULL
); 
  97     // FIXME don't know what is it for 
 100   // get count of all children (and grand children if 'recursively') 
 101   size_t GetChildrenCount(bool recursively 
= TRUE
) const; 
 103   void Insert(wxGenericTreeItem 
*child
, size_t index
) 
 104     { m_children
.Insert(child
, index
); } 
 106   void SetCross( int x
, int y 
); 
 107   void GetSize( int &x
, int &y 
); 
 109   // return the item at given position (or NULL if no item), onButton is TRUE 
 110   // if the point belongs to the item's button, otherwise it lies on the 
 112   wxGenericTreeItem 
*HitTest( const wxPoint
& point
, bool &onButton 
); 
 114   void Expand() { m_isCollapsed 
= FALSE
; } 
 115   void Collapse() { m_isCollapsed 
= TRUE
; } 
 117   void SetHilight( bool set 
= TRUE 
) { m_hasHilight 
= set
; } 
 120   bool HasChildren() const { return !m_children
.IsEmpty(); } 
 121   bool HasHilight()  const { return m_hasHilight
; } 
 122   bool IsExpanded()  const { return !m_isCollapsed
; } 
 123   bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 124   bool IsBold()      const { return m_isBold
; } 
 132   wxTreeItemData     
*m_data
; 
 134   // use bitfields to save size 
 135   int                 m_isCollapsed 
:1; 
 136   int                 m_hasHilight  
:1; // same as focused 
 137   int                 m_hasPlus     
:1; // used for item which doesn't have 
 138                                         // children but still has a [+] button 
 139   int                 m_isBold      
:1; // render the label in bold font 
 142   long                m_height
, m_width
; 
 143   int                 m_xCross
, m_yCross
; 
 145   wxArrayTreeItems    m_children
; 
 146   wxGenericTreeItem  
*m_parent
; 
 149 // ============================================================================= 
 151 // ============================================================================= 
 153 // ----------------------------------------------------------------------------- 
 155 // ----------------------------------------------------------------------------- 
 157 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent
, wxNotifyEvent
) 
 159 wxTreeEvent::wxTreeEvent( wxEventType commandType
, int id 
) 
 160            : wxNotifyEvent( commandType
, id 
) 
 163   m_itemOld 
= (wxGenericTreeItem 
*)NULL
; 
 166 // ----------------------------------------------------------------------------- 
 168 // ----------------------------------------------------------------------------- 
 170 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 171                                      const wxString
& text
, 
 173                                      int image
, int selImage
, 
 174                                      wxTreeItemData 
*data
) 
 178   m_selImage 
= selImage
; 
 181   m_xCross 
= m_yCross 
= 0; 
 185   m_isCollapsed 
= TRUE
; 
 186   m_hasHilight 
= FALSE
; 
 192   dc
.GetTextExtent( m_text
, &m_width
, &m_height 
); 
 195 wxGenericTreeItem::~wxGenericTreeItem() 
 199   wxASSERT_MSG( m_children
.IsEmpty(), 
 200                 "please call DeleteChildren() before deleting the item" ); 
 203 void wxGenericTreeItem::DeleteChildren(wxTreeCtrl 
*tree
) 
 205   size_t count 
= m_children
.Count(); 
 206   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 208     wxGenericTreeItem 
*child 
= m_children
[n
]; 
 211       tree
->SendDeleteEvent(child
); 
 214     child
->DeleteChildren(tree
); 
 221 void wxGenericTreeItem::SetText( const wxString 
&text
, wxDC
& dc 
) 
 225   dc
.GetTextExtent( m_text
, &m_width
, &m_height 
); 
 228 void wxGenericTreeItem::Reset() 
 235   m_height 
= m_width 
= 0; 
 242   m_isCollapsed 
= TRUE
; 
 244   m_parent 
= (wxGenericTreeItem 
*)NULL
; 
 247 size_t wxGenericTreeItem::GetChildrenCount(bool recursively
) const 
 249   size_t count 
= m_children
.Count(); 
 253   size_t total 
= count
; 
 254   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 256     total 
+= m_children
[n
]->GetChildrenCount(); 
 262 void wxGenericTreeItem::SetCross( int x
, int y 
) 
 268 void wxGenericTreeItem::GetSize( int &x
, int &y 
) 
 270   if ( y 
< m_y 
) y 
= m_y
; 
 271   int width 
= m_x 
+  m_width
; 
 272   if (width 
> x
) x 
= width
; 
 276     size_t count 
= m_children
.Count(); 
 277     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 279       m_children
[n
]->GetSize( x
, y 
); 
 284 wxGenericTreeItem 
*wxGenericTreeItem::HitTest( const wxPoint
& point
, 
 287   if ((point
.y 
> m_y
) && (point
.y 
< m_y 
+ m_height
)) 
 290     //  Because that is the size of the plus sign, RR 
 291     if ((point
.x 
> m_xCross
-5) && (point
.x 
< m_xCross
+5) && 
 292         (point
.y 
> m_yCross
-5) && (point
.y 
< m_yCross
+5) && 
 293         (IsExpanded() || HasPlus())) 
 299     /* TODO: we should do a query here like 
 300          m_imageListNormal->GetSize( item->GetImage(), image_w, image_h );  */ 
 302     if (m_image 
!= -1) w 
+= 24; 
 304     if ((point
.x 
> m_x
) && (point
.x 
< m_x
+w
)) 
 314       size_t count 
= m_children
.Count(); 
 315       for ( size_t n 
= 0; n 
< count
; n
++ ) 
 317         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, onButton 
); 
 327 // ----------------------------------------------------------------------------- 
 328 // wxTreeCtrl implementation 
 329 // ----------------------------------------------------------------------------- 
 331 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxScrolledWindow
) 
 333 BEGIN_EVENT_TABLE(wxTreeCtrl
,wxScrolledWindow
) 
 334   EVT_PAINT          (wxTreeCtrl::OnPaint
) 
 335   EVT_MOUSE_EVENTS   (wxTreeCtrl::OnMouse
) 
 336   EVT_CHAR           (wxTreeCtrl::OnChar
) 
 337   EVT_SET_FOCUS      (wxTreeCtrl::OnSetFocus
) 
 338   EVT_KILL_FOCUS     (wxTreeCtrl::OnKillFocus
) 
 339   EVT_IDLE           (wxTreeCtrl::OnIdle
) 
 342 // ----------------------------------------------------------------------------- 
 343 // construction/destruction 
 344 // ----------------------------------------------------------------------------- 
 345 void wxTreeCtrl::Init() 
 348   m_anchor 
= (wxGenericTreeItem 
*) NULL
; 
 357   m_hilightBrush 
= new wxBrush
 
 359       wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), 
 364   m_imageListState 
= (wxImageList 
*) NULL
; 
 369 bool wxTreeCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 370                         const wxPoint
& pos
, const wxSize
& size
, 
 372             const wxValidator 
&validator
, 
 373             const wxString
& name 
) 
 377   wxScrolledWindow::Create( parent
, id
, pos
, size
, style
|wxHSCROLL
|wxVSCROLL
, name 
); 
 379   SetValidator( validator 
); 
 381   SetBackgroundColour( *wxWHITE 
); 
 382   m_dottedPen 
= wxPen( *wxBLACK
, 0, 0 ); 
 387 wxTreeCtrl::~wxTreeCtrl() 
 389   wxDELETE( m_hilightBrush 
); 
 394 // ----------------------------------------------------------------------------- 
 396 // ----------------------------------------------------------------------------- 
 398 size_t wxTreeCtrl::GetCount() const 
 400   return m_anchor 
== NULL 
? 0u : m_anchor
->GetChildrenCount(); 
 403 void wxTreeCtrl::SetIndent(unsigned int indent
) 
 409 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
) 
 411   wxCHECK_MSG( item
.IsOk(), 0u, "invalid tree item" ); 
 413   return item
.m_pItem
->GetChildrenCount(recursively
); 
 416 // ----------------------------------------------------------------------------- 
 417 // functions to work with tree items 
 418 // ----------------------------------------------------------------------------- 
 420 wxString 
wxTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 422   wxCHECK_MSG( item
.IsOk(), "", "invalid tree item" ); 
 424   return item
.m_pItem
->GetText(); 
 427 int wxTreeCtrl::GetItemImage(const wxTreeItemId
& item
) const 
 429   wxCHECK_MSG( item
.IsOk(), -1, "invalid tree item" ); 
 431   return item
.m_pItem
->GetImage(); 
 434 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const 
 436   wxCHECK_MSG( item
.IsOk(), -1, "invalid tree item" ); 
 438   return item
.m_pItem
->GetSelectedImage(); 
 441 wxTreeItemData 
*wxTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 443   wxCHECK_MSG( item
.IsOk(), NULL
, "invalid tree item" ); 
 445   return item
.m_pItem
->GetData(); 
 448 void wxTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 450   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 453   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 454   pItem
->SetText(text
, dc
); 
 458 void wxTreeCtrl::SetItemImage(const wxTreeItemId
& item
, int image
) 
 460   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 462   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 463   pItem
->SetImage(image
); 
 467 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
) 
 469   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 471   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 472   pItem
->SetSelectedImage(image
); 
 476 void wxTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 478   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 480   item
.m_pItem
->SetData(data
); 
 483 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
 485   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 487   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 488   pItem
->SetHasPlus(has
); 
 492 void wxTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
 494   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 496   // avoid redrawing the tree if no real change 
 497   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 498   if ( pItem
->IsBold() != bold 
) 
 500     pItem
->SetBold(bold
); 
 505 // ----------------------------------------------------------------------------- 
 506 // item status inquiries 
 507 // ----------------------------------------------------------------------------- 
 509 bool wxTreeCtrl::IsVisible(const wxTreeItemId
& WXUNUSED(item
)) const 
 511   wxFAIL_MSG("not implemented"); 
 516 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
 518   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 520   return !item
.m_pItem
->GetChildren().IsEmpty(); 
 523 bool wxTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
 525   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 527   return item
.m_pItem
->IsExpanded(); 
 530 bool wxTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
 532   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 534   return item
.m_pItem
->HasHilight(); 
 537 bool wxTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
 539   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 541   return item
.m_pItem
->IsBold(); 
 544 // ----------------------------------------------------------------------------- 
 546 // ----------------------------------------------------------------------------- 
 548 wxTreeItemId 
wxTreeCtrl::GetParent(const wxTreeItemId
& item
) const 
 550   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 552   return item
.m_pItem
->GetParent(); 
 555 wxTreeItemId 
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const 
 557   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 560   return GetNextChild(item
, cookie
); 
 563 wxTreeItemId 
wxTreeCtrl::GetNextChild(const wxTreeItemId
& item
, long& cookie
) const 
 565   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 567   wxArrayTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 568   if ( (size_t)cookie 
< children
.Count() ) 
 570     return children
.Item(cookie
++); 
 574     // there are no more of them 
 575     return wxTreeItemId(); 
 579 wxTreeItemId 
wxTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
 581   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 583   wxArrayTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 584   return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
 587 wxTreeItemId 
wxTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
 589   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 591   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 592   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 593   if ( parent 
== NULL 
) 
 595     // root item doesn't have any siblings 
 596     return wxTreeItemId(); 
 599   wxArrayTreeItems
& siblings 
= parent
->GetChildren(); 
 600   int index 
= siblings
.Index(i
); 
 601   wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 603   size_t n 
= (size_t)(index 
+ 1); 
 604   return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
 607 wxTreeItemId 
wxTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
 609   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 611   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 612   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 613   if ( parent 
== NULL 
) 
 615     // root item doesn't have any siblings 
 616     return wxTreeItemId(); 
 619   wxArrayTreeItems
& siblings 
= parent
->GetChildren(); 
 620   int index 
= siblings
.Index(i
); 
 621   wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 623   return index 
== 0 ? wxTreeItemId() 
 624                     : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
 627 wxTreeItemId 
wxTreeCtrl::GetFirstVisibleItem() const 
 629   wxFAIL_MSG("not implemented"); 
 631   return wxTreeItemId(); 
 634 wxTreeItemId 
wxTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
 636   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 638   wxFAIL_MSG("not implemented"); 
 640   return wxTreeItemId(); 
 643 wxTreeItemId 
wxTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
 645   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 647   wxFAIL_MSG("not implemented"); 
 649   return wxTreeItemId(); 
 652 // ----------------------------------------------------------------------------- 
 654 // ----------------------------------------------------------------------------- 
 656 wxTreeItemId 
wxTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
 658                                       const wxString
& text
, 
 659                                       int image
, int selImage
, 
 660                                       wxTreeItemData 
*data
) 
 662   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 665     // should we give a warning here? 
 666     return AddRoot(text
, image
, selImage
, data
); 
 670   wxGenericTreeItem 
*item 
= new wxGenericTreeItem(parent
, 
 677     data
->m_pItem 
= item
; 
 680   parent
->Insert( item
, previous 
); 
 687 wxTreeItemId 
wxTreeCtrl::AddRoot(const wxString
& text
, 
 688                                  int image
, int selImage
, 
 689                                  wxTreeItemData 
*data
) 
 691   wxCHECK_MSG( !m_anchor
, wxTreeItemId(), "tree can have only one root" ); 
 694   m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, dc
, 
 695                                    image
, selImage
, data
); 
 698     data
->m_pItem 
= m_anchor
; 
 701   AdjustMyScrollbars(); 
 707 wxTreeItemId 
wxTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
 708                                      const wxString
& text
, 
 709                                      int image
, int selImage
, 
 710                                      wxTreeItemData 
*data
) 
 712   return DoInsertItem(parent
, 0u, text
, image
, selImage
, data
); 
 715 wxTreeItemId 
wxTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
 716                                     const wxTreeItemId
& idPrevious
, 
 717                                     const wxString
& text
, 
 718                                     int image
, int selImage
, 
 719                                     wxTreeItemData 
*data
) 
 721   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 724     // should we give a warning here? 
 725     return AddRoot(text
, image
, selImage
, data
); 
 728   int index 
= parent
->GetChildren().Index(idPrevious
.m_pItem
); 
 729   wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
 730                 "previous item in wxTreeCtrl::InsertItem() is not a sibling" ); 
 731   return DoInsertItem(parentId
, (size_t)index
, text
, image
, selImage
, data
); 
 734 wxTreeItemId 
wxTreeCtrl::AppendItem(const wxTreeItemId
& parentId
, 
 735                                     const wxString
& text
, 
 736                                     int image
, int selImage
, 
 737                                     wxTreeItemData 
*data
) 
 739   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 742     // should we give a warning here? 
 743     return AddRoot(text
, image
, selImage
, data
); 
 746   return DoInsertItem(parent
, parent
->GetChildren().Count(), text
, 
 747                       image
, selImage
, data
); 
 750 void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
 752   wxTreeEvent 
event( wxEVT_COMMAND_TREE_DELETE_ITEM
, GetId() ); 
 754   event
.SetEventObject( this ); 
 755   ProcessEvent( event 
); 
 758 void wxTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
 760     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 761     item
->DeleteChildren(this); 
 766 void wxTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
 768   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 769   wxGenericTreeItem 
*parent 
= item
->GetParent(); 
 773     parent
->GetChildren().Remove(item
); 
 776   item
->DeleteChildren(this); 
 777   SendDeleteEvent(item
); 
 783 void wxTreeCtrl::DeleteAllItems() 
 787     m_anchor
->DeleteChildren(this); 
 796 void wxTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
 798   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 800   if ( !item
->HasPlus() ) 
 803   if ( item
->IsExpanded() ) 
 806   wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
 808   event
.SetEventObject( this ); 
 809   if ( ProcessEvent( event 
) && event
.m_code 
) 
 811     // cancelled by program 
 816   CalculatePositions(); 
 818   RefreshSubtree(item
); 
 820   event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
 821   ProcessEvent( event 
); 
 824 void wxTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
 826   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 828   if ( !item
->IsExpanded() ) 
 831   wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
 833   event
.SetEventObject( this ); 
 834   if ( ProcessEvent( event 
) && event
.m_code 
) 
 836     // cancelled by program 
 842   wxArrayTreeItems
& children 
= item
->GetChildren(); 
 843   size_t count 
= children
.Count(); 
 844   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 846     Collapse(children
[n
]); 
 849   CalculatePositions(); 
 851   RefreshSubtree(item
); 
 853   event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
 854   ProcessEvent( event 
); 
 857 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
 860   DeleteChildren(item
); 
 863 void wxTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
 865   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 867   if ( item
->IsExpanded() ) 
 873 void wxTreeCtrl::Unselect() 
 877     m_current
->SetHilight( FALSE 
); 
 878     RefreshLine( m_current 
); 
 882 void wxTreeCtrl::SelectItem(const wxTreeItemId
& itemId
) 
 884   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 886   if ( m_current 
!= item 
) 
 888     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
 890     event
.m_itemOld 
= m_current
; 
 891     event
.SetEventObject( this ); 
 892     if ( GetEventHandler()->ProcessEvent( event 
) && event
.WasVetoed() ) 
 897       m_current
->SetHilight( FALSE 
); 
 898       RefreshLine( m_current 
); 
 902     m_current
->SetHilight( TRUE 
); 
 903     RefreshLine( m_current 
); 
 905     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
 906     GetEventHandler()->ProcessEvent( event 
); 
 910 void wxTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
 912     wxGenericTreeItem 
*gitem 
= item
.m_pItem
; 
 914     // first expand all parent branches 
 915     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
 916     while ( parent 
&& !parent
->IsExpanded() ) 
 920         parent 
= parent
->GetParent(); 
 923     // now scroll to the item 
 924     int item_y 
= gitem
->GetY(); 
 928     ViewStart( &start_x
, &start_y 
); 
 933     GetClientSize( &client_w
, &client_h 
); 
 935     if (item_y 
< start_y
+3) 
 939         m_anchor
->GetSize( x
, y 
); 
 941         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
 942         SetScrollbars( 10, 10, x
/10, y
/10, x_pos
, (item_y
-client_h
/2)/10 ); 
 944     else if (item_y 
> start_y
+client_h
-16) 
 948        m_anchor
->GetSize( x
, y 
); 
 950        int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
 951        SetScrollbars( 10, 10, x
/10, y
/10, x_pos
, (item_y
-client_h
/2)/10 ); 
 955 void wxTreeCtrl::ScrollTo(const wxTreeItemId
& WXUNUSED(item
)) 
 957     wxFAIL_MSG("not implemented"); 
 960 wxTextCtrl 
*wxTreeCtrl::EditLabel( const wxTreeItemId
& WXUNUSED(item
), 
 961                                    wxClassInfo
* WXUNUSED(textCtrlClass
) ) 
 963     wxFAIL_MSG("not implemented"); 
 965     return (wxTextCtrl
*)NULL
; 
 968 wxTextCtrl 
*wxTreeCtrl::GetEditControl() const 
 970     wxFAIL_MSG("not implemented"); 
 972     return (wxTextCtrl
*)NULL
; 
 975 void wxTreeCtrl::EndEditLabel(const wxTreeItemId
& WXUNUSED(item
), bool WXUNUSED(discardChanges
)) 
 977     wxFAIL_MSG("not implemented"); 
 980 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
 981 static wxTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
 983 static int tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
 984                                   wxGenericTreeItem 
**item2
) 
 986     wxCHECK_MSG( s_treeBeingSorted
, 0, "bug in wxTreeCtrl::SortChildren()" ); 
 988     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
 991 int wxTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
 992                                const wxTreeItemId
& item2
) 
 994     return strcmp(GetItemText(item1
), GetItemText(item2
)); 
 997 void wxTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
 999     wxCHECK_RET( itemId
.IsOk(), "invalid tree item" ); 
1001     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1003     wxCHECK_RET( !s_treeBeingSorted
, 
1004                  "wxTreeCtrl::SortChildren is not reentrant" ); 
1006     wxArrayTreeItems
& children 
= item
->GetChildren(); 
1007     if ( children
.Count() > 1 ) 
1009         s_treeBeingSorted 
= this; 
1010         children
.Sort(tree_ctrl_compare_func
); 
1011         s_treeBeingSorted 
= NULL
; 
1015     //else: don't make the tree dirty as nothing changed 
1018 wxImageList 
*wxTreeCtrl::GetImageList() const 
1020     return m_imageListNormal
; 
1023 wxImageList 
*wxTreeCtrl::GetStateImageList() const 
1025     return m_imageListState
; 
1028 void wxTreeCtrl::SetImageList(wxImageList 
*imageList
) 
1030    m_imageListNormal 
= imageList
; 
1031    // calculate a m_lineHeight value from the image sizes 
1034    m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1038       n 
= m_imageListNormal
->GetImageCount(); 
1039    for(int i 
= 0; i 
< n 
; i
++) 
1041       m_imageListNormal
->GetSize(i
, width
, height
); 
1042       height 
+= height
/5;  //20% extra spacing 
1043       if(height 
> m_lineHeight
) m_lineHeight 
= height
; 
1047 void wxTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
1049     m_imageListState 
= imageList
; 
1052 // ----------------------------------------------------------------------------- 
1054 // ----------------------------------------------------------------------------- 
1056 void wxTreeCtrl::AdjustMyScrollbars() 
1062         m_anchor
->GetSize( x
, y 
); 
1063         y 
+= 2*m_lineHeight
; 
1064         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1065         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
1066         SetScrollbars( 10, 10, x
/10, y
/10, x_pos
, y_pos 
); 
1070         SetScrollbars( 0, 0, 0, 0 ); 
1074 void wxTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
1076     // render bold items in bold 
1082         fontOld 
= dc
.GetFont(); 
1085           // VZ: is there any better way to make a bold variant of old font? 
1086           fontNew 
= wxFont( fontOld
.GetPointSize(), 
1087                             fontOld
.GetFamily(), 
1090                             fontOld
.GetUnderlined()); 
1091           dc
.SetFont(fontNew
); 
1095             wxFAIL_MSG("wxDC::GetFont() failed!"); 
1101     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
1105     if ((item
->IsExpanded()) && (item
->GetSelectedImage() != -1)) 
1107         m_imageListNormal
->GetSize( item
->GetSelectedImage(), image_w
, image_h 
); 
1110     else if (item
->GetImage() != -1) 
1112         m_imageListNormal
->GetSize( item
->GetImage(), image_w
, image_h 
); 
1116     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
1117     if(m_lineHeight 
> total_h
) total_h 
= m_lineHeight
; 
1119     dc
.DrawRectangle( item
->GetX()-2, item
->GetY(), image_w
+text_w
+4, total_h 
); 
1121     if ((item
->IsExpanded()) && (item
->GetSelectedImage() != -1)) 
1123         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
1124         m_imageListNormal
->Draw( item
->GetSelectedImage(), dc
, 
1126                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
1127                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
1128         dc
.DestroyClippingRegion(); 
1130     else if (item
->GetImage() != -1) 
1132         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
1133         m_imageListNormal
->Draw( item
->GetImage(), dc
, 
1135                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
1136                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
1137         dc
.DestroyClippingRegion(); 
1140     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1141     dc
.DrawText( item
->GetText(), image_w 
+ item
->GetX(), item
->GetY() 
1142                  + ((total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0)); 
1144     // restore normal font for bold items 
1147         dc
.SetFont( fontOld
); 
1151 void wxTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
1153     int horizX 
= level
*m_indent
; 
1155     item
->SetX( horizX
+33 ); 
1156     item
->SetY( y
-m_lineHeight
/2 ); 
1157     item
->SetHeight( m_lineHeight 
); 
1159     item
->SetCross( horizX
+15, y 
); 
1163     int exposed_x 
= dc
.LogicalToDeviceX( 0 ); 
1164     int exposed_y 
= dc
.LogicalToDeviceY( item
->GetY()-2 ); 
1166     if (IsExposed( exposed_x
, exposed_y
, 10000, m_lineHeight
+4 ))  // 10000 = very much 
1168         int startX 
= horizX
; 
1169         int endX 
= horizX 
+ 10; 
1171         if (!item
->HasChildren()) endX 
+= 20; 
1173         dc
.DrawLine( startX
, y
, endX
, y 
); 
1175         if (item
->HasPlus()) 
1177             dc
.DrawLine( horizX
+20, y
, horizX
+30, y 
); 
1178             dc
.SetPen( *wxGREY_PEN 
); 
1179             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1180             dc
.DrawRectangle( horizX
+10, y
-4, 11, 9 ); 
1181             dc
.SetPen( *wxBLACK_PEN 
); 
1182             dc
.DrawLine( horizX
+13, y
, horizX
+18, y 
); 
1184             if (!item
->IsExpanded()) 
1186                 dc
.DrawLine( horizX
+15, y
-2, horizX
+15, y
+3 ); 
1190         if (item
->HasHilight()) 
1192             dc
.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
) ); 
1194             dc
.SetBrush( *m_hilightBrush 
); 
1197                 dc
.SetPen( *wxBLACK_PEN 
); 
1199                 dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1201             PaintItem(item
, dc
); 
1203             dc
.SetPen( *wxBLACK_PEN 
); 
1204             dc
.SetTextForeground( *wxBLACK 
); 
1205             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1209             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1210             dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1212             PaintItem(item
, dc
); 
1214             dc
.SetPen( *wxBLACK_PEN 
); 
1218     if (item
->IsExpanded()) 
1222         wxArrayTreeItems
& children 
= item
->GetChildren(); 
1223         size_t count 
= children
.Count(); 
1224         for ( size_t n 
= 0; n 
< count
; n
++ ) 
1228             PaintLevel( children
[n
], dc
, level
+1, y 
); 
1231         // it may happen that the item is expanded but has no items (when you 
1232         // delete all its children for example) - don't draw the vertical line 
1235             dc
.DrawLine( horizX
+15, oldY
+5, horizX
+15, semiOldY 
); 
1239 // ----------------------------------------------------------------------------- 
1240 // wxWindows callbacks 
1241 // ----------------------------------------------------------------------------- 
1243 void wxTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1251     dc
.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT 
) ); 
1253     dc
.SetPen( m_dottedPen 
); 
1254     if(GetImageList() == NULL
) 
1255        m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1257     int y 
= m_lineHeight 
/ 2 + 2; 
1258     PaintLevel( m_anchor
, dc
, 0, y 
); 
1261 void wxTreeCtrl::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1265     if (m_current
) RefreshLine( m_current 
); 
1268 void wxTreeCtrl::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1272     if (m_current
) RefreshLine( m_current 
); 
1275 void wxTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
1277     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
1278     te
.m_code 
= event
.KeyCode(); 
1279     te
.SetEventObject( this ); 
1280     GetEventHandler()->ProcessEvent( te 
); 
1288     switch (event
.KeyCode()) 
1292             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
1300             if (IsExpanded(m_current
)) 
1302                 Collapse(m_current
); 
1314                 wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
1315                 event
.m_item 
= m_current
; 
1317                 event
.SetEventObject( this ); 
1318                 GetEventHandler()->ProcessEvent( event 
); 
1322             // up goes to the previous sibling or to the last of its children if 
1326                 wxTreeItemId prev 
= GetPrevSibling( m_current 
); 
1329                     prev 
= GetParent( m_current 
); 
1331                     wxTreeItemId current 
= m_current
; 
1332                     if (current 
== GetFirstChild( prev
, cockie 
)) 
1334                         // otherwise we return to where we came from 
1336                         EnsureVisible( prev 
); 
1342                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
1344                         wxTreeItemId child 
= GetLastChild(prev
); 
1352                     EnsureVisible( prev 
); 
1357             // left arrow goes to the parent 
1360                 wxTreeItemId prev 
= GetParent( m_current 
); 
1363                     EnsureVisible( prev 
); 
1370             // this works the same as the down arrow except that we also expand the 
1371             // item if it wasn't expanded yet 
1377                 if (IsExpanded(m_current
) && HasChildren(m_current
)) 
1380                     wxTreeItemId child 
= GetFirstChild( m_current
, cookie 
); 
1381                     SelectItem( child 
); 
1382                     EnsureVisible( child 
); 
1386                     wxTreeItemId next 
= GetNextSibling( m_current 
); 
1389                         wxTreeItemId current 
= m_current
; 
1390                         while (current 
&& !next
) 
1392                             current 
= GetParent( current 
); 
1393                             if (current
) next 
= GetNextSibling( current 
); 
1399                         EnsureVisible( next 
); 
1405             // <End> selects the last visible tree item 
1408                 wxTreeItemId last 
= GetRootItem(); 
1410                 while ( last
.IsOk() && IsExpanded(last
) ) 
1412                     wxTreeItemId lastChild 
= GetLastChild(last
); 
1414                     // it may happen if the item was expanded but then all of 
1415                     // its children have been deleted - so IsExpanded() returned 
1416                     // TRUE, but GetLastChild() returned invalid item 
1425                     EnsureVisible( last 
); 
1431             // <Home> selects the root item 
1434                 wxTreeItemId prev 
= GetRootItem(); 
1437                     EnsureVisible( prev 
); 
1448 wxTreeItemId 
wxTreeCtrl::HitTest(const wxPoint
& point
, int& WXUNUSED(flags
)) 
1450     wxClientDC 
dc(this); 
1452     long x 
= dc
.DeviceToLogicalX( (long)point
.x 
); 
1453     long y 
= dc
.DeviceToLogicalY( (long)point
.y 
); 
1455     bool onButton 
= FALSE
; 
1456     return m_anchor
->HitTest( wxPoint(x
, y
), onButton 
); 
1459 void wxTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
1461     if (!event
.LeftIsDown()) m_dragCount 
= 0; 
1463     if ( !(event
.LeftDown() || event
.LeftDClick() || event
.Dragging()) ) return; 
1465     if ( !m_anchor 
) return; 
1467     wxClientDC 
dc(this); 
1469     long x 
= dc
.DeviceToLogicalX( (long)event
.GetX() ); 
1470     long y 
= dc
.DeviceToLogicalY( (long)event
.GetY() ); 
1472     bool onButton 
= FALSE
; 
1473     wxGenericTreeItem 
*item 
= m_anchor
->HitTest( wxPoint(x
,y
), onButton 
); 
1475     if (item 
== NULL
) return;  /* we hit the blank area */ 
1477     if (event
.Dragging()) 
1479         if (m_dragCount 
== 2)  /* small drag latency (3?) */ 
1483             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_BEGIN_DRAG
, GetId()); 
1484             nevent
.m_item 
= m_current
; 
1485             nevent
.SetEventObject(this); 
1486             GetEventHandler()->ProcessEvent(nevent
); 
1495     if (!IsSelected(item
)) 
1496         SelectItem(item
);  /* we dont support multiple selections, BTW */ 
1498     if (event
.LeftDClick()) 
1500         wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
1501         event
.m_item 
= item
; 
1503         event
.SetEventObject( this ); 
1504         GetEventHandler()->ProcessEvent( event 
); 
1513 void wxTreeCtrl::OnIdle( wxIdleEvent 
&WXUNUSED(event
) ) 
1515     /* after all changes have been done to the tree control, 
1516      * we actually redraw the tree when everything is over */ 
1523     CalculatePositions(); 
1525     AdjustMyScrollbars(); 
1528 // ----------------------------------------------------------------------------- 
1530 void wxTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
1532     int horizX 
= level
*m_indent
; 
1534     item
->SetX( horizX
+33 ); 
1535     item
->SetY( y
-m_lineHeight
/2 ); 
1536     item
->SetHeight( m_lineHeight 
); 
1538     if ( !item
->IsExpanded() ) 
1540         // we dont need to calculate collapsed branches 
1544     wxArrayTreeItems
& children 
= item
->GetChildren(); 
1545     size_t count 
= children
.Count(); 
1546     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1549         CalculateLevel( children
[n
], dc
, level
+1, y 
);  // recurse 
1553 void wxTreeCtrl::CalculatePositions() 
1555     if ( !m_anchor 
) return; 
1557     wxClientDC 
dc(this); 
1560     dc
.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT 
) ); 
1562     dc
.SetPen( m_dottedPen 
); 
1563     if(GetImageList() == NULL
) 
1564        m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1566     int y 
= m_lineHeight 
/ 2 + 2; 
1567     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
1570 void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
1572     wxClientDC 
dc(this); 
1577     GetClientSize( &cw
, &ch 
); 
1580     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
1582     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
1585     Refresh( TRUE
, &rect 
); 
1587     AdjustMyScrollbars(); 
1590 void wxTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
1592     wxClientDC 
dc(this); 
1596     rect
.x 
= dc
.LogicalToDeviceX( item
->GetX() - 2 ); 
1597     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() - 2 ); 
1599     rect
.height 
= dc
.GetCharHeight() + 6; 
1601     Refresh( TRUE
, &rect 
);