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     if ((point
.x 
> m_xCross
-5) && (point
.x 
< m_xCross
+5) && 
 291         (point
.y 
> m_yCross
-5) && (point
.y 
< m_yCross
+5) && 
 292         (IsExpanded() || HasPlus())) 
 299     if (m_image 
!= -1) w 
+= 20; 
 301     if ((point
.x 
> m_x
) && (point
.x 
< m_x
+w
)) 
 311       size_t count 
= m_children
.Count(); 
 312       for ( size_t n 
= 0; n 
< count
; n
++ ) 
 314         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, onButton 
); 
 324 // ----------------------------------------------------------------------------- 
 325 // wxTreeCtrl implementation 
 326 // ----------------------------------------------------------------------------- 
 328 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxScrolledWindow
) 
 330 BEGIN_EVENT_TABLE(wxTreeCtrl
,wxScrolledWindow
) 
 331   EVT_PAINT          (wxTreeCtrl::OnPaint
) 
 332   EVT_MOUSE_EVENTS   (wxTreeCtrl::OnMouse
) 
 333   EVT_CHAR           (wxTreeCtrl::OnChar
) 
 334   EVT_SET_FOCUS      (wxTreeCtrl::OnSetFocus
) 
 335   EVT_KILL_FOCUS     (wxTreeCtrl::OnKillFocus
) 
 336   EVT_IDLE           (wxTreeCtrl::OnIdle
) 
 339 // ----------------------------------------------------------------------------- 
 340 // construction/destruction 
 341 // ----------------------------------------------------------------------------- 
 342 void wxTreeCtrl::Init() 
 345   m_anchor 
= (wxGenericTreeItem 
*) NULL
; 
 354   m_hilightBrush 
= new wxBrush
 
 356       wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), 
 361   m_imageListState 
= (wxImageList 
*) NULL
; 
 366 bool wxTreeCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 367                         const wxPoint
& pos
, const wxSize
& size
, 
 369             const wxValidator 
&validator
, 
 370             const wxString
& name 
) 
 374   wxScrolledWindow::Create( parent
, id
, pos
, size
, style
|wxHSCROLL
|wxVSCROLL
, name 
); 
 376   SetValidator( validator 
); 
 378   SetBackgroundColour( *wxWHITE 
); 
 379   m_dottedPen 
= wxPen( *wxBLACK
, 0, 0 ); 
 384 wxTreeCtrl::~wxTreeCtrl() 
 386   wxDELETE( m_hilightBrush 
); 
 391 // ----------------------------------------------------------------------------- 
 393 // ----------------------------------------------------------------------------- 
 395 size_t wxTreeCtrl::GetCount() const 
 397   return m_anchor 
== NULL 
? 0u : m_anchor
->GetChildrenCount(); 
 400 void wxTreeCtrl::SetIndent(unsigned int indent
) 
 406 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
) 
 408   wxCHECK_MSG( item
.IsOk(), 0u, "invalid tree item" ); 
 410   return item
.m_pItem
->GetChildrenCount(recursively
); 
 413 // ----------------------------------------------------------------------------- 
 414 // functions to work with tree items 
 415 // ----------------------------------------------------------------------------- 
 417 wxString 
wxTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 419   wxCHECK_MSG( item
.IsOk(), "", "invalid tree item" ); 
 421   return item
.m_pItem
->GetText(); 
 424 int wxTreeCtrl::GetItemImage(const wxTreeItemId
& item
) const 
 426   wxCHECK_MSG( item
.IsOk(), -1, "invalid tree item" ); 
 428   return item
.m_pItem
->GetImage(); 
 431 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const 
 433   wxCHECK_MSG( item
.IsOk(), -1, "invalid tree item" ); 
 435   return item
.m_pItem
->GetSelectedImage(); 
 438 wxTreeItemData 
*wxTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 440   wxCHECK_MSG( item
.IsOk(), NULL
, "invalid tree item" ); 
 442   return item
.m_pItem
->GetData(); 
 445 void wxTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 447   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 450   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 451   pItem
->SetText(text
, dc
); 
 455 void wxTreeCtrl::SetItemImage(const wxTreeItemId
& item
, int image
) 
 457   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 459   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 460   pItem
->SetImage(image
); 
 464 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
) 
 466   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 468   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 469   pItem
->SetSelectedImage(image
); 
 473 void wxTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 475   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 477   item
.m_pItem
->SetData(data
); 
 480 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
 482   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 484   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 485   pItem
->SetHasPlus(has
); 
 489 void wxTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
 491   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 493   // avoid redrawing the tree if no real change 
 494   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 495   if ( pItem
->IsBold() != bold 
) 
 497     pItem
->SetBold(bold
); 
 502 // ----------------------------------------------------------------------------- 
 503 // item status inquiries 
 504 // ----------------------------------------------------------------------------- 
 506 bool wxTreeCtrl::IsVisible(const wxTreeItemId
& WXUNUSED(item
)) const 
 508   wxFAIL_MSG("not implemented"); 
 513 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
 515   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 517   return !item
.m_pItem
->GetChildren().IsEmpty(); 
 520 bool wxTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
 522   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 524   return item
.m_pItem
->IsExpanded(); 
 527 bool wxTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
 529   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 531   return item
.m_pItem
->HasHilight(); 
 534 bool wxTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
 536   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 538   return item
.m_pItem
->IsBold(); 
 541 // ----------------------------------------------------------------------------- 
 543 // ----------------------------------------------------------------------------- 
 545 wxTreeItemId 
wxTreeCtrl::GetParent(const wxTreeItemId
& item
) const 
 547   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 549   return item
.m_pItem
->GetParent(); 
 552 wxTreeItemId 
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const 
 554   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 557   return GetNextChild(item
, cookie
); 
 560 wxTreeItemId 
wxTreeCtrl::GetNextChild(const wxTreeItemId
& item
, long& cookie
) const 
 562   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 564   wxArrayTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 565   if ( (size_t)cookie 
< children
.Count() ) 
 567     return children
.Item(cookie
++); 
 571     // there are no more of them 
 572     return wxTreeItemId(); 
 576 wxTreeItemId 
wxTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
 578   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 580   wxArrayTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 581   return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
 584 wxTreeItemId 
wxTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
 586   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 588   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 589   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 590   if ( parent 
== NULL 
) 
 592     // root item doesn't have any siblings 
 593     return wxTreeItemId(); 
 596   wxArrayTreeItems
& siblings 
= parent
->GetChildren(); 
 597   int index 
= siblings
.Index(i
); 
 598   wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 600   size_t n 
= (size_t)(index 
+ 1); 
 601   return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
 604 wxTreeItemId 
wxTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
 606   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 608   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 609   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 610   if ( parent 
== NULL 
) 
 612     // root item doesn't have any siblings 
 613     return wxTreeItemId(); 
 616   wxArrayTreeItems
& siblings 
= parent
->GetChildren(); 
 617   int index 
= siblings
.Index(i
); 
 618   wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 620   return index 
== 0 ? wxTreeItemId() 
 621                     : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
 624 wxTreeItemId 
wxTreeCtrl::GetFirstVisibleItem() const 
 626   wxFAIL_MSG("not implemented"); 
 628   return wxTreeItemId(); 
 631 wxTreeItemId 
wxTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
 633   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 635   wxFAIL_MSG("not implemented"); 
 637   return wxTreeItemId(); 
 640 wxTreeItemId 
wxTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
 642   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), "invalid tree item" ); 
 644   wxFAIL_MSG("not implemented"); 
 646   return wxTreeItemId(); 
 649 // ----------------------------------------------------------------------------- 
 651 // ----------------------------------------------------------------------------- 
 653 wxTreeItemId 
wxTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
 655                                       const wxString
& text
, 
 656                                       int image
, int selImage
, 
 657                                       wxTreeItemData 
*data
) 
 659   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 662     // should we give a warning here? 
 663     return AddRoot(text
, image
, selImage
, data
); 
 667   wxGenericTreeItem 
*item 
= new wxGenericTreeItem(parent
, 
 674     data
->m_pItem 
= item
; 
 677   parent
->Insert( item
, previous 
); 
 684 wxTreeItemId 
wxTreeCtrl::AddRoot(const wxString
& text
, 
 685                                  int image
, int selImage
, 
 686                                  wxTreeItemData 
*data
) 
 688   wxCHECK_MSG( !m_anchor
, wxTreeItemId(), "tree can have only one root" ); 
 691   m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, dc
, 
 692                                    image
, selImage
, data
); 
 695     data
->m_pItem 
= m_anchor
; 
 698   AdjustMyScrollbars(); 
 704 wxTreeItemId 
wxTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
 705                                      const wxString
& text
, 
 706                                      int image
, int selImage
, 
 707                                      wxTreeItemData 
*data
) 
 709   return DoInsertItem(parent
, 0u, text
, image
, selImage
, data
); 
 712 wxTreeItemId 
wxTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
 713                                     const wxTreeItemId
& idPrevious
, 
 714                                     const wxString
& text
, 
 715                                     int image
, int selImage
, 
 716                                     wxTreeItemData 
*data
) 
 718   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 721     // should we give a warning here? 
 722     return AddRoot(text
, image
, selImage
, data
); 
 725   int index 
= parent
->GetChildren().Index(idPrevious
.m_pItem
); 
 726   wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
 727                 "previous item in wxTreeCtrl::InsertItem() is not a sibling" ); 
 728   return DoInsertItem(parentId
, (size_t)index
, text
, image
, selImage
, data
); 
 731 wxTreeItemId 
wxTreeCtrl::AppendItem(const wxTreeItemId
& parentId
, 
 732                                     const wxString
& text
, 
 733                                     int image
, int selImage
, 
 734                                     wxTreeItemData 
*data
) 
 736   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 739     // should we give a warning here? 
 740     return AddRoot(text
, image
, selImage
, data
); 
 743   return DoInsertItem(parent
, parent
->GetChildren().Count(), text
, 
 744                       image
, selImage
, data
); 
 747 void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
 749   wxTreeEvent 
event( wxEVT_COMMAND_TREE_DELETE_ITEM
, GetId() ); 
 751   event
.SetEventObject( this ); 
 752   ProcessEvent( event 
); 
 755 void wxTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
 757     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 758     item
->DeleteChildren(this); 
 763 void wxTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
 765   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 766   wxGenericTreeItem 
*parent 
= item
->GetParent(); 
 770     parent
->GetChildren().Remove(item
); 
 773   item
->DeleteChildren(this); 
 774   SendDeleteEvent(item
); 
 780 void wxTreeCtrl::DeleteAllItems() 
 784     m_anchor
->DeleteChildren(this); 
 793 void wxTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
 795   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 797   if ( !item
->HasPlus() ) 
 800   if ( item
->IsExpanded() ) 
 803   wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
 805   event
.SetEventObject( this ); 
 806   if ( ProcessEvent( event 
) && event
.m_code 
) 
 808     // cancelled by program 
 813   CalculatePositions(); 
 815   RefreshSubtree(item
); 
 817   event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
 818   ProcessEvent( event 
); 
 821 void wxTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
 823   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 825   if ( !item
->IsExpanded() ) 
 828   wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
 830   event
.SetEventObject( this ); 
 831   if ( ProcessEvent( event 
) && event
.m_code 
) 
 833     // cancelled by program 
 839   wxArrayTreeItems
& children 
= item
->GetChildren(); 
 840   size_t count 
= children
.Count(); 
 841   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 843     Collapse(children
[n
]); 
 846   CalculatePositions(); 
 848   RefreshSubtree(item
); 
 850   event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
 851   ProcessEvent( event 
); 
 854 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
 857   DeleteChildren(item
); 
 860 void wxTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
 862   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 864   if ( item
->IsExpanded() ) 
 870 void wxTreeCtrl::Unselect() 
 874     m_current
->SetHilight( FALSE 
); 
 875     RefreshLine( m_current 
); 
 879 void wxTreeCtrl::SelectItem(const wxTreeItemId
& itemId
) 
 881   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 883   if ( m_current 
!= item 
) 
 885     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
 887     event
.m_itemOld 
= m_current
; 
 888     event
.SetEventObject( this ); 
 889     if ( GetEventHandler()->ProcessEvent( event 
) && event
.WasVetoed() ) 
 894       m_current
->SetHilight( FALSE 
); 
 895       RefreshLine( m_current 
); 
 899     m_current
->SetHilight( TRUE 
); 
 900     RefreshLine( m_current 
); 
 902     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
 903     GetEventHandler()->ProcessEvent( event 
); 
 907 void wxTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
 909     wxGenericTreeItem 
*gitem 
= item
.m_pItem
; 
 911     // first expand all parent branches 
 912     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
 913     while ( parent 
&& !parent
->IsExpanded() ) 
 917         parent 
= parent
->GetParent(); 
 920     // now scroll to the item 
 921     int item_y 
= gitem
->GetY(); 
 925     ViewStart( &start_x
, &start_y 
); 
 930     GetClientSize( &client_w
, &client_h 
); 
 932     if (item_y 
< start_y
+3) 
 936         m_anchor
->GetSize( x
, y 
); 
 938         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
 939         SetScrollbars( 10, 10, x
/10, y
/10, x_pos
, (item_y
-client_h
/2)/10 ); 
 941     else if (item_y 
> start_y
+client_h
-16) 
 945        m_anchor
->GetSize( x
, y 
); 
 947        int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
 948        SetScrollbars( 10, 10, x
/10, y
/10, x_pos
, (item_y
-client_h
/2)/10 ); 
 952 void wxTreeCtrl::ScrollTo(const wxTreeItemId
& WXUNUSED(item
)) 
 954     wxFAIL_MSG("not implemented"); 
 957 wxTextCtrl 
*wxTreeCtrl::EditLabel( const wxTreeItemId
& WXUNUSED(item
), 
 958                                    wxClassInfo
* WXUNUSED(textCtrlClass
) ) 
 960     wxFAIL_MSG("not implemented"); 
 962     return (wxTextCtrl
*)NULL
; 
 965 wxTextCtrl 
*wxTreeCtrl::GetEditControl() const 
 967     wxFAIL_MSG("not implemented"); 
 969     return (wxTextCtrl
*)NULL
; 
 972 void wxTreeCtrl::EndEditLabel(const wxTreeItemId
& WXUNUSED(item
), bool WXUNUSED(discardChanges
)) 
 974     wxFAIL_MSG("not implemented"); 
 977 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
 978 static wxTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
 980 static int tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
 981                                   wxGenericTreeItem 
**item2
) 
 983     wxCHECK_MSG( s_treeBeingSorted
, 0, "bug in wxTreeCtrl::SortChildren()" ); 
 985     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
 988 int wxTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
 989                                const wxTreeItemId
& item2
) 
 991     return strcmp(GetItemText(item1
), GetItemText(item2
)); 
 994 void wxTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
 996     wxCHECK_RET( itemId
.IsOk(), "invalid tree item" ); 
 998     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1000     wxCHECK_RET( !s_treeBeingSorted
, 
1001                  "wxTreeCtrl::SortChildren is not reentrant" ); 
1003     wxArrayTreeItems
& children 
= item
->GetChildren(); 
1004     if ( children
.Count() > 1 ) 
1006         s_treeBeingSorted 
= this; 
1007         children
.Sort(tree_ctrl_compare_func
); 
1008         s_treeBeingSorted 
= NULL
; 
1012     //else: don't make the tree dirty as nothing changed 
1015 wxImageList 
*wxTreeCtrl::GetImageList() const 
1017     return m_imageListNormal
; 
1020 wxImageList 
*wxTreeCtrl::GetStateImageList() const 
1022     return m_imageListState
; 
1025 void wxTreeCtrl::SetImageList(wxImageList 
*imageList
) 
1027    m_imageListNormal 
= imageList
; 
1028    // calculate a m_lineHeight value from the image sizes 
1031    m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1035       n 
= m_imageListNormal
->GetImageCount(); 
1036    for(int i 
= 0; i 
< n 
; i
++) 
1038       m_imageListNormal
->GetSize(i
, width
, height
); 
1039       if(height 
> m_lineHeight
) m_lineHeight 
= height
; 
1043 void wxTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
1045     m_imageListState 
= imageList
; 
1048 // ----------------------------------------------------------------------------- 
1050 // ----------------------------------------------------------------------------- 
1052 void wxTreeCtrl::AdjustMyScrollbars() 
1058         m_anchor
->GetSize( x
, y 
); 
1059         y 
+= 2*m_lineHeight
; 
1060         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1061         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
1062         SetScrollbars( 10, 10, x
/10, y
/10, x_pos
, y_pos 
); 
1066         SetScrollbars( 0, 0, 0, 0 ); 
1070 void wxTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
1072     // render bold items in bold 
1078         fontOld 
= dc
.GetFont(); 
1081           // VZ: is there any better way to make a bold variant of old font? 
1082           fontNew 
= wxFont( fontOld
.GetPointSize(), 
1083                             fontOld
.GetFamily(), 
1086                             fontOld
.GetUnderlined()); 
1087           dc
.SetFont(fontNew
); 
1091             wxFAIL_MSG("wxDC::GetFont() failed!"); 
1097     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
1101     if ((item
->IsExpanded()) && (item
->GetSelectedImage() != -1)) 
1103         m_imageListNormal
->GetSize( item
->GetSelectedImage(), image_w
, image_h 
); 
1106     else if (item
->GetImage() != -1) 
1108         m_imageListNormal
->GetSize( item
->GetImage(), image_w
, image_h 
); 
1112     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
1113     dc
.DrawRectangle( item
->GetX()-2, item
->GetY()-2, image_w
+text_w
+4, total_h
+4 ); 
1115     if ((item
->IsExpanded()) && (item
->GetSelectedImage() != -1)) 
1117         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
1118         m_imageListNormal
->Draw( item
->GetSelectedImage(), dc
, 
1120                                  item
->GetY()/* +((total_h > image_h)?((total_h-image_h)/2):0)*/, 
1121                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
1122         dc
.DestroyClippingRegion(); 
1124     else if (item
->GetImage() != -1) 
1126         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
1127         m_imageListNormal
->Draw( item
->GetImage(), dc
, 
1129                                  item
->GetY() /*+((total_h > image_h)?((total_h-image_h)/2):0)*/, 
1130                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
1131         dc
.DestroyClippingRegion(); 
1134     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1135     dc
.DrawText( item
->GetText(), image_w 
+ item
->GetX(), item
->GetY() 
1136                  + ((total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0)); 
1138     // restore normal font for bold items 
1141         dc
.SetFont( fontOld
); 
1145 void wxTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
1147     int horizX 
= level
*m_indent
; 
1149     item
->SetX( horizX
+33 ); 
1150     item
->SetY( y
-m_lineHeight
/3 ); 
1151     item
->SetHeight( m_lineHeight 
); 
1153     item
->SetCross( horizX
+15, y 
); 
1157     int exposed_x 
= dc
.LogicalToDeviceX( 0 ); 
1158     int exposed_y 
= dc
.LogicalToDeviceY( item
->GetY()-2 ); 
1160     if (IsExposed( exposed_x
, exposed_y
, 10000, m_lineHeight
+4 ))  // 10000 = very much 
1162         int startX 
= horizX
; 
1163         int endX 
= horizX 
+ 10; 
1165         if (!item
->HasChildren()) endX 
+= 20; 
1167         dc
.DrawLine( startX
, y
, endX
, y 
); 
1169         if (item
->HasPlus()) 
1171             dc
.DrawLine( horizX
+20, y
, horizX
+30, y 
); 
1172             dc
.SetPen( *wxGREY_PEN 
); 
1173             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1174             dc
.DrawRectangle( horizX
+10, y
-4, 11, 9 ); 
1175             dc
.SetPen( *wxBLACK_PEN 
); 
1176             dc
.DrawLine( horizX
+13, y
, horizX
+18, y 
); 
1178             if (!item
->IsExpanded()) 
1180                 dc
.DrawLine( horizX
+15, y
-2, horizX
+15, y
+3 ); 
1184         if (item
->HasHilight()) 
1186             dc
.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
) ); 
1188             dc
.SetBrush( *m_hilightBrush 
); 
1191                 dc
.SetPen( *wxBLACK_PEN 
); 
1193                 dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1195             PaintItem(item
, dc
); 
1197             dc
.SetPen( *wxBLACK_PEN 
); 
1198             dc
.SetTextForeground( *wxBLACK 
); 
1199             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1203             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1204             dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1206             PaintItem(item
, dc
); 
1208             dc
.SetPen( *wxBLACK_PEN 
); 
1212     if (item
->IsExpanded()) 
1216         wxArrayTreeItems
& children 
= item
->GetChildren(); 
1217         size_t count 
= children
.Count(); 
1218         for ( size_t n 
= 0; n 
< count
; n
++ ) 
1222             PaintLevel( children
[n
], dc
, level
+1, y 
); 
1225         // it may happen that the item is expanded but has no items (when you 
1226         // delete all its children for example) - don't draw the vertical line 
1229             dc
.DrawLine( horizX
+15, oldY
+5, horizX
+15, semiOldY 
); 
1233 // ----------------------------------------------------------------------------- 
1234 // wxWindows callbacks 
1235 // ----------------------------------------------------------------------------- 
1237 void wxTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1245     dc
.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT 
) ); 
1247     dc
.SetPen( m_dottedPen 
); 
1248     if(GetImageList() == NULL
) 
1249        m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1251     int y 
= m_lineHeight 
/ 2 + 2; 
1252     PaintLevel( m_anchor
, dc
, 0, y 
); 
1255 void wxTreeCtrl::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1259     if (m_current
) RefreshLine( m_current 
); 
1262 void wxTreeCtrl::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1266     if (m_current
) RefreshLine( m_current 
); 
1269 void wxTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
1271     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
1272     te
.m_code 
= event
.KeyCode(); 
1273     te
.SetEventObject( this ); 
1274     GetEventHandler()->ProcessEvent( te 
); 
1282     switch (event
.KeyCode()) 
1286             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
1294             if (IsExpanded(m_current
)) 
1296                 Collapse(m_current
); 
1308                 wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
1309                 event
.m_item 
= m_current
; 
1311                 event
.SetEventObject( this ); 
1312                 GetEventHandler()->ProcessEvent( event 
); 
1316             // up goes to the previous sibling or to the last of its children if 
1320                 wxTreeItemId prev 
= GetPrevSibling( m_current 
); 
1323                     prev 
= GetParent( m_current 
); 
1325                     wxTreeItemId current 
= m_current
; 
1326                     if (current 
== GetFirstChild( prev
, cockie 
)) 
1328                         // otherwise we return to where we came from 
1330                         EnsureVisible( prev 
); 
1336                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
1338                         wxTreeItemId child 
= GetLastChild(prev
); 
1346                     EnsureVisible( prev 
); 
1351             // left arrow goes to the parent 
1354                 wxTreeItemId prev 
= GetParent( m_current 
); 
1357                     EnsureVisible( prev 
); 
1364             // this works the same as the down arrow except that we also expand the 
1365             // item if it wasn't expanded yet 
1371                 if (IsExpanded(m_current
) && HasChildren(m_current
)) 
1374                     wxTreeItemId child 
= GetFirstChild( m_current
, cookie 
); 
1375                     SelectItem( child 
); 
1376                     EnsureVisible( child 
); 
1380                     wxTreeItemId next 
= GetNextSibling( m_current 
); 
1383                         wxTreeItemId current 
= m_current
; 
1384                         while (current 
&& !next
) 
1386                             current 
= GetParent( current 
); 
1387                             if (current
) next 
= GetNextSibling( current 
); 
1393                         EnsureVisible( next 
); 
1399             // <End> selects the last visible tree item 
1402                 wxTreeItemId last 
= GetRootItem(); 
1404                 while ( last
.IsOk() && IsExpanded(last
) ) 
1406                     wxTreeItemId lastChild 
= GetLastChild(last
); 
1408                     // it may happen if the item was expanded but then all of 
1409                     // its children have been deleted - so IsExpanded() returned 
1410                     // TRUE, but GetLastChild() returned invalid item 
1419                     EnsureVisible( last 
); 
1425             // <Home> selects the root item 
1428                 wxTreeItemId prev 
= GetRootItem(); 
1431                     EnsureVisible( prev 
); 
1442 wxTreeItemId 
wxTreeCtrl::HitTest(const wxPoint
& point
, int& WXUNUSED(flags
)) 
1444     bool onButton 
= FALSE
; 
1445     return m_anchor
->HitTest( point
, onButton 
); 
1448 void wxTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
1450     if (!event
.LeftIsDown()) m_dragCount 
= 0; 
1452     if ( !(event
.LeftDown() || event
.LeftDClick() || event
.Dragging()) ) return; 
1454     if ( !m_anchor 
) return; 
1456     wxClientDC 
dc(this); 
1458     long x 
= dc
.DeviceToLogicalX( (long)event
.GetX() ); 
1459     long y 
= dc
.DeviceToLogicalY( (long)event
.GetY() ); 
1461     bool onButton 
= FALSE
; 
1462     wxGenericTreeItem 
*item 
= m_anchor
->HitTest( wxPoint(x
,y
), onButton 
); 
1464     if (item 
== NULL
) return;  /* we hit the blank area */ 
1466     if (event
.Dragging()) 
1468         if (m_dragCount 
== 2)  /* small drag latency (3?) */ 
1472             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_BEGIN_DRAG
, GetId()); 
1473             nevent
.m_item 
= m_current
; 
1474             nevent
.SetEventObject(this); 
1475             GetEventHandler()->ProcessEvent(nevent
); 
1484     if (!IsSelected(item
)) 
1485         SelectItem(item
);  /* we dont support multiple selections, BTW */ 
1487     if (event
.LeftDClick()) 
1489         wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
1490         event
.m_item 
= item
; 
1492         event
.SetEventObject( this ); 
1493         GetEventHandler()->ProcessEvent( event 
); 
1502 void wxTreeCtrl::OnIdle( wxIdleEvent 
&WXUNUSED(event
) ) 
1504     /* after all changes have been done to the tree control, 
1505      * we actually redraw the tree when everything is over */ 
1512     CalculatePositions(); 
1514     AdjustMyScrollbars(); 
1517 // ----------------------------------------------------------------------------- 
1519 void wxTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
1521     int horizX 
= level
*m_indent
; 
1523     item
->SetX( horizX
+33 ); 
1524     item
->SetY( y
-m_lineHeight
/3-2 ); 
1525     item
->SetHeight( m_lineHeight 
); 
1527     if ( !item
->IsExpanded() ) 
1529         // we dont need to calculate collapsed branches 
1533     wxArrayTreeItems
& children 
= item
->GetChildren(); 
1534     size_t count 
= children
.Count(); 
1535     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1538         CalculateLevel( children
[n
], dc
, level
+1, y 
);  // recurse 
1542 void wxTreeCtrl::CalculatePositions() 
1544     if ( !m_anchor 
) return; 
1546     wxClientDC 
dc(this); 
1549     dc
.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT 
) ); 
1551     dc
.SetPen( m_dottedPen 
); 
1552     if(GetImageList() == NULL
) 
1553        m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1555     int y 
= m_lineHeight 
/ 2 + 2; 
1556     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
1559 void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
1561     wxClientDC 
dc(this); 
1566     GetClientSize( &cw
, &ch 
); 
1569     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
1571     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
1574     Refresh( TRUE
, &rect 
); 
1576     AdjustMyScrollbars(); 
1579 void wxTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
1581     wxClientDC 
dc(this); 
1585     rect
.x 
= dc
.LogicalToDeviceX( item
->GetX() - 2 ); 
1586     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() - 2 ); 
1588     rect
.height 
= dc
.GetCharHeight() + 6; 
1590     Refresh( TRUE
, &rect 
);