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/arrimpl.cpp" 
  38 #include "wx/dcclient.h" 
  39 #include "wx/msgdlg.h" 
  41 // ----------------------------------------------------------------------------- 
  43 // ----------------------------------------------------------------------------- 
  45 class WXDLLEXPORT wxGenericTreeItem
; 
  47 WX_DEFINE_ARRAY(wxGenericTreeItem 
*, wxArrayGenericTreeItems
); 
  48 WX_DEFINE_OBJARRAY(wxArrayTreeItemIds
); 
  50 // ----------------------------------------------------------------------------- 
  52 // ----------------------------------------------------------------------------- 
  55 class WXDLLEXPORT wxGenericTreeItem
 
  59   wxGenericTreeItem() { m_data 
= NULL
; } 
  60   wxGenericTreeItem( wxGenericTreeItem 
*parent
, 
  63                      int image
, int selImage
, 
  64                      wxTreeItemData 
*data 
); 
  69   wxArrayGenericTreeItems
& GetChildren() { return m_children
; } 
  71   const wxString
& GetText() const { return m_text
; } 
  72   int GetImage() const { return m_image
; } 
  73   int GetSelectedImage() const { return m_selImage
; } 
  74   wxTreeItemData 
*GetData() const { return m_data
; } 
  76   void SetText( const wxString 
&text 
); 
  77   void SetImage(int image
) { m_image 
= image
; } 
  78   void SetSelectedImage(int image
) { m_selImage 
= image
; } 
  79   void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
  81   void SetHasPlus(bool has 
= TRUE
) { m_hasPlus 
= has
; } 
  83   void SetBold(bool bold
) { m_isBold 
= bold
; } 
  85   int GetX() const { return m_x
; } 
  86   int GetY() const { return m_y
; } 
  88   void SetX(int x
) { m_x 
= x
; } 
  89   void SetY(int y
) { m_y 
= y
; } 
  91   int  GetHeight() const { return m_height
; } 
  92   int  GetWidth()  const { return m_width
; } 
  94   void SetHeight(int h
) { m_height 
= h
; } 
  95   void SetWidth(int w
) { m_width 
= w
; } 
  98   wxGenericTreeItem 
*GetParent() const { return m_parent
; } 
 101     // deletes all children notifying the treectrl about it if !NULL pointer 
 103   void DeleteChildren(wxTreeCtrl 
*tree 
= NULL
); 
 104     // FIXME don't know what is it for 
 107   // get count of all children (and grand children if 'recursively') 
 108   size_t GetChildrenCount(bool recursively 
= TRUE
) const; 
 110   void Insert(wxGenericTreeItem 
*child
, size_t index
) 
 111     { m_children
.Insert(child
, index
); } 
 113   void SetCross( int x
, int y 
); 
 114   void GetSize( int &x
, int &y
, const wxTreeCtrl
* ); 
 116   // return the item at given position (or NULL if no item), onButton is TRUE 
 117   // if the point belongs to the item's button, otherwise it lies on the 
 119   wxGenericTreeItem 
*HitTest( const wxPoint
& point
, const wxTreeCtrl 
*, int &flags
); 
 121   void Expand() { m_isCollapsed 
= FALSE
; } 
 122   void Collapse() { m_isCollapsed 
= TRUE
; } 
 124   void SetHilight( bool set 
= TRUE 
) { m_hasHilight 
= set
; } 
 127   bool HasChildren() const { return !m_children
.IsEmpty(); } 
 128   bool HasHilight()  const { return m_hasHilight
; } 
 129   bool IsExpanded()  const { return !m_isCollapsed
; } 
 130   bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 131   bool IsBold()      const { return m_isBold
; } 
 139   wxTreeItemData     
*m_data
; 
 141   // use bitfields to save size 
 142   int                 m_isCollapsed 
:1; 
 143   int                 m_hasHilight  
:1; // same as focused 
 144   int                 m_hasPlus     
:1; // used for item which doesn't have 
 145                                         // children but still has a [+] button 
 146   int                 m_isBold      
:1; // render the label in bold font 
 149   long                m_height
, m_width
; 
 150   int                 m_xCross
, m_yCross
; 
 152   wxArrayGenericTreeItems m_children
; 
 153   wxGenericTreeItem  
*m_parent
; 
 156 // ============================================================================= 
 158 // ============================================================================= 
 160 #define PIXELS_PER_UNIT 10 
 161 // ----------------------------------------------------------------------------- 
 163 // ----------------------------------------------------------------------------- 
 165 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent
, wxNotifyEvent
) 
 167 wxTreeEvent::wxTreeEvent( wxEventType commandType
, int id 
) 
 168            : wxNotifyEvent( commandType
, id 
) 
 171   m_itemOld 
= (wxGenericTreeItem 
*)NULL
; 
 174 // ----------------------------------------------------------------------------- 
 176 // ----------------------------------------------------------------------------- 
 178 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 179                                      const wxString
& text
, 
 181                                      int image
, int selImage
, 
 182                                      wxTreeItemData 
*data
) 
 186   m_selImage 
= selImage
; 
 189   m_xCross 
= m_yCross 
= 0; 
 193   m_isCollapsed 
= TRUE
; 
 194   m_hasHilight 
= FALSE
; 
 200   dc
.GetTextExtent( m_text
, &m_width
, &m_height 
); 
 201   // TODO : Add the width of the image 
 202   // PB   : We don't know which image is shown (image, selImage) 
 203   //        We don't even know imageList from the treectrl this item belongs to !!! 
 204   // At this point m_width doesn't mean much, this can be remove ! 
 207 wxGenericTreeItem::~wxGenericTreeItem() 
 211   wxASSERT_MSG( m_children
.IsEmpty(), 
 212                 _T("please call DeleteChildren() before deleting the item") ); 
 215 void wxGenericTreeItem::DeleteChildren(wxTreeCtrl 
*tree
) 
 217   size_t count 
= m_children
.Count(); 
 218   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 220     wxGenericTreeItem 
*child 
= m_children
[n
]; 
 223       tree
->SendDeleteEvent(child
); 
 226     child
->DeleteChildren(tree
); 
 233 void wxGenericTreeItem::SetText( const wxString 
&text 
) 
 238 void wxGenericTreeItem::Reset() 
 245   m_height 
= m_width 
= 0; 
 252   m_isCollapsed 
= TRUE
; 
 254   m_parent 
= (wxGenericTreeItem 
*)NULL
; 
 257 size_t wxGenericTreeItem::GetChildrenCount(bool recursively
) const 
 259   size_t count 
= m_children
.Count(); 
 263   size_t total 
= count
; 
 264   for ( size_t n 
= 0; n 
< count
; ++n 
) 
 266     total 
+= m_children
[n
]->GetChildrenCount(); 
 272 void wxGenericTreeItem::SetCross( int x
, int y 
) 
 278 void wxGenericTreeItem::GetSize( int &x
, int &y
, const wxTreeCtrl 
*theTree 
) 
 280   int bottomY
=m_y
+theTree
->GetLineHeight(this); 
 281   if ( y 
< bottomY 
) y 
= bottomY
; 
 282   int width 
= m_x 
+  m_width
; 
 283   if ( x 
< width 
) x 
= width
; 
 287     size_t count 
= m_children
.Count(); 
 288     for ( size_t n 
= 0; n 
< count
; ++n 
) 
 290       m_children
[n
]->GetSize( x
, y
, theTree 
); 
 295 wxGenericTreeItem 
*wxGenericTreeItem::HitTest( const wxPoint
& point
, 
 296                                                const wxTreeCtrl 
*theTree
, 
 299   if ((point
.y 
> m_y
) && (point
.y 
< m_y 
+ theTree
->GetLineHeight(this))) 
 301     if (point
.y
<m_y
+theTree
->GetLineHeight(this)/2) flags
|=wxTREE_HITTEST_ONITEMUPPERPART
; 
 302     else flags
|=wxTREE_HITTEST_ONITEMLOWERPART
; 
 305     //  Because that is the size of the plus sign, RR 
 306     if ((point
.x 
> m_xCross
-5) && (point
.x 
< m_xCross
+5) && 
 307         (point
.y 
> m_yCross
-5) && (point
.y 
< m_yCross
+5) && 
 308         (IsExpanded() || HasPlus())) 
 310       flags
|=wxTREE_HITTEST_ONITEMBUTTON
; 
 314     if ((point
.x 
>= m_x
) && (point
.x 
<= m_x
+m_width
)) 
 318       // assuming every image (normal and selected ) has the same size ! 
 319       theTree
->m_imageListNormal
->GetSize(m_image
, image_w
, image_h
); 
 320       if (point
.x
<=m_x
+image_w
+1) 
 321         flags
|=wxTREE_HITTEST_ONITEMICON
; 
 323         flags
|=wxTREE_HITTEST_ONITEMLABEL
; 
 328     if (point
.x 
< m_x
)         flags
|=wxTREE_HITTEST_ONITEMIDENT
; 
 329     if (point
.x 
> m_x
+m_width
) flags
|=wxTREE_HITTEST_ONITEMRIGHT
; 
 337       size_t count 
= m_children
.Count(); 
 338       for ( size_t n 
= 0; n 
< count
; n
++ ) 
 340         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, theTree
, flags 
); 
 347   flags
|=wxTREE_HITTEST_NOWHERE
; 
 351 // ----------------------------------------------------------------------------- 
 352 // wxTreeCtrl implementation 
 353 // ----------------------------------------------------------------------------- 
 355 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxScrolledWindow
) 
 357 BEGIN_EVENT_TABLE(wxTreeCtrl
,wxScrolledWindow
) 
 358   EVT_PAINT          (wxTreeCtrl::OnPaint
) 
 359   EVT_MOUSE_EVENTS   (wxTreeCtrl::OnMouse
) 
 360   EVT_CHAR           (wxTreeCtrl::OnChar
) 
 361   EVT_SET_FOCUS      (wxTreeCtrl::OnSetFocus
) 
 362   EVT_KILL_FOCUS     (wxTreeCtrl::OnKillFocus
) 
 363   EVT_IDLE           (wxTreeCtrl::OnIdle
) 
 366 // ----------------------------------------------------------------------------- 
 367 // construction/destruction 
 368 // ----------------------------------------------------------------------------- 
 370 void wxTreeCtrl::Init() 
 374   m_anchor 
= (wxGenericTreeItem 
*) NULL
; 
 384   m_hilightBrush 
= new wxBrush
 
 386       wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), 
 391   m_imageListState 
= (wxImageList 
*) NULL
; 
 396 bool wxTreeCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 397                         const wxPoint
& pos
, const wxSize
& size
, 
 399             const wxValidator 
&validator
, 
 400             const wxString
& name 
) 
 404   wxScrolledWindow::Create( parent
, id
, pos
, size
, style
|wxHSCROLL
|wxVSCROLL
, name 
); 
 406   SetValidator( validator 
); 
 408   SetBackgroundColour( *wxWHITE 
); 
 409   m_dottedPen 
= wxPen( *wxBLACK
, 0, 0 ); 
 414 wxTreeCtrl::~wxTreeCtrl() 
 416   wxDELETE( m_hilightBrush 
); 
 421 // ----------------------------------------------------------------------------- 
 423 // ----------------------------------------------------------------------------- 
 425 size_t wxTreeCtrl::GetCount() const 
 427   return m_anchor 
== NULL 
? 0u : m_anchor
->GetChildrenCount(); 
 430 void wxTreeCtrl::SetIndent(unsigned int indent
) 
 437 void wxTreeCtrl::SetSpacing(unsigned int spacing
) 
 444 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
) 
 446   wxCHECK_MSG( item
.IsOk(), 0u, _T("invalid tree item") ); 
 448   return item
.m_pItem
->GetChildrenCount(recursively
); 
 451 // ----------------------------------------------------------------------------- 
 452 // functions to work with tree items 
 453 // ----------------------------------------------------------------------------- 
 455 wxString 
wxTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 457   wxCHECK_MSG( item
.IsOk(), _T(""), _T("invalid tree item") ); 
 459   return item
.m_pItem
->GetText(); 
 462 int wxTreeCtrl::GetItemImage(const wxTreeItemId
& item
) const 
 464   wxCHECK_MSG( item
.IsOk(), -1, _T("invalid tree item") ); 
 466   return item
.m_pItem
->GetImage(); 
 469 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const 
 471   wxCHECK_MSG( item
.IsOk(), -1, _T("invalid tree item") ); 
 473   return item
.m_pItem
->GetSelectedImage(); 
 476 wxTreeItemData 
*wxTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 478   wxCHECK_MSG( item
.IsOk(), NULL
, _T("invalid tree item") ); 
 480   return item
.m_pItem
->GetData(); 
 483 void wxTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 485   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 488   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 489   pItem
->SetText(text
); 
 490   CalculateSize(pItem
, dc
); 
 494 void wxTreeCtrl::SetItemImage(const wxTreeItemId
& item
, int image
) 
 496   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 499   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 500   pItem
->SetImage(image
); 
 501   CalculateSize(pItem
, dc
); 
 505 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
) 
 507   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 510   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 511   pItem
->SetSelectedImage(image
); 
 512   CalculateSize(pItem
, dc
); 
 516 void wxTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 518   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 520   item
.m_pItem
->SetData(data
); 
 523 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
 525   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 527   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 528   pItem
->SetHasPlus(has
); 
 532 void wxTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
 534   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 536   // avoid redrawing the tree if no real change 
 537   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 538   if ( pItem
->IsBold() != bold 
) 
 540     pItem
->SetBold(bold
); 
 545 // ----------------------------------------------------------------------------- 
 546 // item status inquiries 
 547 // ----------------------------------------------------------------------------- 
 549 bool wxTreeCtrl::IsVisible(const wxTreeItemId
& WXUNUSED(item
)) const 
 551   wxFAIL_MSG(_T("not implemented")); 
 556 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
 558   wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid tree item") ); 
 560   return !item
.m_pItem
->GetChildren().IsEmpty(); 
 563 bool wxTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
 565   wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid tree item") ); 
 567   return item
.m_pItem
->IsExpanded(); 
 570 bool wxTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
 572   wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid tree item") ); 
 574   return item
.m_pItem
->HasHilight(); 
 577 bool wxTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
 579   wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid tree item") ); 
 581   return item
.m_pItem
->IsBold(); 
 584 // ----------------------------------------------------------------------------- 
 586 // ----------------------------------------------------------------------------- 
 588 wxTreeItemId 
wxTreeCtrl::GetParent(const wxTreeItemId
& item
) const 
 590   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 592   return item
.m_pItem
->GetParent(); 
 595 wxTreeItemId 
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const 
 597   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 600   return GetNextChild(item
, cookie
); 
 603 wxTreeItemId 
wxTreeCtrl::GetNextChild(const wxTreeItemId
& item
, long& cookie
) const 
 605   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 607   wxArrayGenericTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 608   if ( (size_t)cookie 
< children
.Count() ) 
 610     return children
.Item(cookie
++); 
 614     // there are no more of them 
 615     return wxTreeItemId(); 
 619 wxTreeItemId 
wxTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
 621   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 623   wxArrayGenericTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 624   return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
 627 wxTreeItemId 
wxTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
 629   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 631   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 632   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 633   if ( parent 
== NULL 
) 
 635     // root item doesn't have any siblings 
 636     return wxTreeItemId(); 
 639   wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
 640   int index 
= siblings
.Index(i
); 
 641   wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 643   size_t n 
= (size_t)(index 
+ 1); 
 644   return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
 647 wxTreeItemId 
wxTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
 649   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 651   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 652   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 653   if ( parent 
== NULL 
) 
 655     // root item doesn't have any siblings 
 656     return wxTreeItemId(); 
 659   wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
 660   int index 
= siblings
.Index(i
); 
 661   wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 663   return index 
== 0 ? wxTreeItemId() 
 664                     : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
 667 wxTreeItemId 
wxTreeCtrl::GetFirstVisibleItem() const 
 669   wxFAIL_MSG(_T("not implemented")); 
 671   return wxTreeItemId(); 
 674 wxTreeItemId 
wxTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
 676   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 678   wxFAIL_MSG(_T("not implemented")); 
 680   return wxTreeItemId(); 
 683 wxTreeItemId 
wxTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
 685   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 687   wxFAIL_MSG(_T("not implemented")); 
 689   return wxTreeItemId(); 
 692 // ----------------------------------------------------------------------------- 
 694 // ----------------------------------------------------------------------------- 
 696 wxTreeItemId 
wxTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
 698                                       const wxString
& text
, 
 699                                       int image
, int selImage
, 
 700                                       wxTreeItemData 
*data
) 
 702   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 705     // should we give a warning here? 
 706     return AddRoot(text
, image
, selImage
, data
); 
 710   wxGenericTreeItem 
*item 
= new wxGenericTreeItem(parent
, 
 717     data
->m_pItem 
= item
; 
 720   parent
->Insert( item
, previous 
); 
 727 wxTreeItemId 
wxTreeCtrl::AddRoot(const wxString
& text
, 
 728                                  int image
, int selImage
, 
 729                                  wxTreeItemData 
*data
) 
 731   wxCHECK_MSG( !m_anchor
, wxTreeItemId(), _T("tree can have only one root") ); 
 734   m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, dc
, 
 735                                    image
, selImage
, data
); 
 738     data
->m_pItem 
= m_anchor
; 
 742   AdjustMyScrollbars(); 
 747 wxTreeItemId 
wxTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
 748                                      const wxString
& text
, 
 749                                      int image
, int selImage
, 
 750                                      wxTreeItemData 
*data
) 
 752   return DoInsertItem(parent
, 0u, text
, image
, selImage
, data
); 
 755 wxTreeItemId 
wxTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
 756                                     const wxTreeItemId
& idPrevious
, 
 757                                     const wxString
& text
, 
 758                                     int image
, int selImage
, 
 759                                     wxTreeItemData 
*data
) 
 761   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 764     // should we give a warning here? 
 765     return AddRoot(text
, image
, selImage
, data
); 
 768   int index 
= parent
->GetChildren().Index(idPrevious
.m_pItem
); 
 769   wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
 770                 _T("previous item in wxTreeCtrl::InsertItem() is not a sibling") ); 
 771   return DoInsertItem(parentId
, (size_t)++index
, text
, image
, selImage
, data
); 
 774 wxTreeItemId 
wxTreeCtrl::AppendItem(const wxTreeItemId
& parentId
, 
 775                                     const wxString
& text
, 
 776                                     int image
, int selImage
, 
 777                                     wxTreeItemData 
*data
) 
 779   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 782     // should we give a warning here? 
 783     return AddRoot(text
, image
, selImage
, data
); 
 786   return DoInsertItem(parent
, parent
->GetChildren().Count(), text
, 
 787                       image
, selImage
, data
); 
 790 void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
 792   wxTreeEvent 
event( wxEVT_COMMAND_TREE_DELETE_ITEM
, GetId() ); 
 794   event
.SetEventObject( this ); 
 795   ProcessEvent( event 
); 
 798 void wxTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
 800     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 801     item
->DeleteChildren(this); 
 806 void wxTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
 808   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 809   wxGenericTreeItem 
*parent 
= item
->GetParent(); 
 813     parent
->GetChildren().Remove(item
); 
 816   item
->DeleteChildren(this); 
 817   SendDeleteEvent(item
); 
 823 void wxTreeCtrl::DeleteAllItems() 
 827     m_anchor
->DeleteChildren(this); 
 836 void wxTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
 838   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 840   if ( !item
->HasPlus() ) 
 843   if ( item
->IsExpanded() ) 
 846   wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
 848   event
.SetEventObject( this ); 
 849   if ( ProcessEvent( event 
) && event
.m_code 
) 
 851     // cancelled by program 
 856   CalculatePositions(); 
 858   RefreshSubtree(item
); 
 860   event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
 861   ProcessEvent( event 
); 
 864 void wxTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
 866   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 868   if ( !item
->IsExpanded() ) 
 871   wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
 873   event
.SetEventObject( this ); 
 874   if ( ProcessEvent( event 
) && event
.m_code 
) 
 876     // cancelled by program 
 882   wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
 883   size_t count 
= children
.Count(); 
 884   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 886     Collapse(children
[n
]); 
 889   CalculatePositions(); 
 891   RefreshSubtree(item
); 
 893   event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
 894   ProcessEvent( event 
); 
 897 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
 900   DeleteChildren(item
); 
 903 void wxTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
 905   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 907   if ( item
->IsExpanded() ) 
 913 void wxTreeCtrl::Unselect() 
 917     m_current
->SetHilight( FALSE 
); 
 918     RefreshLine( m_current 
); 
 922 void wxTreeCtrl::UnselectAllChildren(wxGenericTreeItem 
*item
) 
 924   item
->SetHilight(FALSE
); 
 927   if (item
->HasChildren()) 
 929       wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
 930       size_t count 
= children
.Count(); 
 931       for ( size_t n 
= 0; n 
< count
; ++n 
) 
 932         UnselectAllChildren(children
[n
]); 
 936 void wxTreeCtrl::UnselectAll() 
 938   UnselectAllChildren(GetRootItem().m_pItem
); 
 941 // Recursive function ! 
 942 // To stop we must have crt_item<last_item 
 944 // Tag all next children, when no more children, 
 945 // Move to parent (not to tag)  
 946 // Keep going... if we found last_item, we stop. 
 947 bool wxTreeCtrl::TagNextChildren(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
 949     wxGenericTreeItem 
*parent 
= crt_item
->GetParent(); 
 951     if ( parent 
== NULL 
) // This is root item 
 952       return TagAllChildrenUntilLast(crt_item
, last_item
, select
); 
 954     wxArrayGenericTreeItems
& children 
= parent
->GetChildren(); 
 955     int index 
= children
.Index(crt_item
); 
 956     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 958     size_t count 
= children
.Count(); 
 959     for (size_t n
=(size_t)(index
+1); n
<count
; ++n
) 
 960       if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return TRUE
; 
 962     return TagNextChildren(parent
, last_item
, select
); 
 965 bool wxTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
 967   crt_item
->SetHilight(select
); 
 968   RefreshLine(crt_item
); 
 970   if (crt_item
==last_item
) return TRUE
; 
 972   if (crt_item
->HasChildren()) 
 974       wxArrayGenericTreeItems
& children 
= crt_item
->GetChildren(); 
 975       size_t count 
= children
.Count(); 
 976       for ( size_t n 
= 0; n 
< count
; ++n 
) 
 977         if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return TRUE
; 
 983 void wxTreeCtrl::SelectItemRange(wxGenericTreeItem 
*item1
, wxGenericTreeItem 
*item2
) 
 985   // item2 is not necessary after item1 
 986   wxGenericTreeItem 
*first
=NULL
, *last
=NULL
; 
 988   // choice first' and 'last' between item1 and item2 
 989   if (item1
->GetY()<item2
->GetY())  
1000   bool select
=m_current
->HasHilight(); 
1002   if (TagAllChildrenUntilLast(first
,last
,select
)) return; 
1004   TagNextChildren(first
,last
,select
);   
1007 void wxTreeCtrl::SelectItem(const wxTreeItemId
& itemId
,  
1008                             bool unselect_others
,  
1009                             bool extended_select
) 
1011     bool is_single
=!(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1013     //wxCHECK_RET( ( (!unselect_others) && is_single), 
1014     //           _T("this is a single selection tree") ); 
1016     // to keep going anyhow !!! 
1019         unselect_others
=TRUE
; 
1020         extended_select
=FALSE
; 
1023     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1025     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
1026     event
.m_item 
= item
; 
1027     event
.m_itemOld 
= m_current
; 
1028     event
.SetEventObject( this ); 
1029     // TODO : Here we don't send any selection mode yet ! 
1031     if ( GetEventHandler()->ProcessEvent( event 
) && event
.WasVetoed() ) 
1035     if (unselect_others
) 
1037         if (is_single
) Unselect(); // to speed up thing 
1042     if (extended_select
)  
1044         if (m_current 
== NULL
) m_current
=m_key_current
=GetRootItem().m_pItem
; 
1045         // don't change the mark (m_current) 
1046         SelectItemRange(m_current
, item
); 
1050         bool select
=TRUE
; // the default 
1052         // Check if we need to toggle hilight (ctrl mode) 
1053         if (!unselect_others
) 
1054           select
=!item
->HasHilight(); 
1056         m_current 
= m_key_current 
= item
; 
1057         m_current
->SetHilight(select
); 
1058         RefreshLine( m_current 
); 
1061     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
1062     GetEventHandler()->ProcessEvent( event 
); 
1065 void wxTreeCtrl::FillArray(wxGenericTreeItem 
*item
, wxArrayTreeItemIds 
&array
) const 
1067   if (item
->HasHilight()) array
.Add(wxTreeItemId(item
)); 
1069   if (item
->HasChildren()) 
1071       wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1072       size_t count 
= children
.Count(); 
1073       for ( size_t n 
= 0; n 
< count
; ++n 
) 
1074         FillArray(children
[n
],array
); 
1078 size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds 
&array
) const 
1081   FillArray(GetRootItem().m_pItem
, array
); 
1083   return array
.Count(); 
1086 void wxTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
1088     if (!item
.IsOk()) return; 
1090     wxGenericTreeItem 
*gitem 
= item
.m_pItem
; 
1092     // first expand all parent branches 
1093     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
1094     while ( parent 
&& !parent
->IsExpanded() ) 
1098         parent 
= parent
->GetParent(); 
1101     if (parent
) CalculatePositions(); 
1106 void wxTreeCtrl::ScrollTo(const wxTreeItemId 
&item
) 
1108     if (!item
.IsOk()) return; 
1110     wxGenericTreeItem 
*gitem 
= item
.m_pItem
; 
1112     // now scroll to the item 
1113     int item_y 
= gitem
->GetY(); 
1117     ViewStart( &start_x
, &start_y 
); 
1118     start_y 
*= PIXELS_PER_UNIT
; 
1122     GetClientSize( &client_w
, &client_h 
); 
1124     if (item_y 
< start_y
+3) 
1129         m_anchor
->GetSize( x
, y
, this ); 
1130         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1131         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1132         // Item should appear at top 
1133         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, item_y
/PIXELS_PER_UNIT 
); 
1135     else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) 
1140        m_anchor
->GetSize( x
, y
, this ); 
1141        y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1142        item_y 
+= PIXELS_PER_UNIT
+2; 
1143        int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1144         // Item should appear at bottom 
1145        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 
); 
1149 wxTextCtrl 
*wxTreeCtrl::EditLabel( const wxTreeItemId
& WXUNUSED(item
), 
1150                                    wxClassInfo
* WXUNUSED(textCtrlClass
) ) 
1152     wxFAIL_MSG(_T("not implemented")); 
1154     return (wxTextCtrl
*)NULL
; 
1157 wxTextCtrl 
*wxTreeCtrl::GetEditControl() const 
1159     wxFAIL_MSG(_T("not implemented")); 
1161     return (wxTextCtrl
*)NULL
; 
1164 void wxTreeCtrl::EndEditLabel(const wxTreeItemId
& WXUNUSED(item
), bool WXUNUSED(discardChanges
)) 
1166     wxFAIL_MSG(_T("not implemented")); 
1169 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
1170 static wxTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
1172 static int tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
1173                                   wxGenericTreeItem 
**item2
) 
1175     wxCHECK_MSG( s_treeBeingSorted
, 0, _T("bug in wxTreeCtrl::SortChildren()") ); 
1177     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
1180 int wxTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
1181                                const wxTreeItemId
& item2
) 
1183     return wxStrcmp(GetItemText(item1
), GetItemText(item2
)); 
1186 void wxTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
1188     wxCHECK_RET( itemId
.IsOk(), _T("invalid tree item") ); 
1190     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1192     wxCHECK_RET( !s_treeBeingSorted
, 
1193                  _T("wxTreeCtrl::SortChildren is not reentrant") ); 
1195     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1196     if ( children
.Count() > 1 ) 
1198         s_treeBeingSorted 
= this; 
1199         children
.Sort(tree_ctrl_compare_func
); 
1200         s_treeBeingSorted 
= NULL
; 
1204     //else: don't make the tree dirty as nothing changed 
1207 wxImageList 
*wxTreeCtrl::GetImageList() const 
1209     return m_imageListNormal
; 
1212 wxImageList 
*wxTreeCtrl::GetStateImageList() const 
1214     return m_imageListState
; 
1217 void wxTreeCtrl::SetImageList(wxImageList 
*imageList
) 
1219    m_imageListNormal 
= imageList
; 
1221    // Calculate a m_lineHeight value from the image sizes. 
1222    // May be toggle off. Then wxTreeCtrl will spread when 
1223    // necessary (which might look ugly). 
1226    m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1230       n 
= m_imageListNormal
->GetImageCount(); 
1231    for(int i 
= 0; i 
< n 
; i
++) 
1233       m_imageListNormal
->GetSize(i
, width
, height
); 
1234       if(height 
> m_lineHeight
) m_lineHeight 
= height
; 
1237    if (m_lineHeight
<40) m_lineHeight
+=4; // at least 4 pixels (odd such that a line can be drawn in between) 
1238    else m_lineHeight
+=m_lineHeight
/10;   // otherwise 10% extra spacing 
1243 void wxTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
1245     m_imageListState 
= imageList
; 
1248 // ----------------------------------------------------------------------------- 
1250 // ----------------------------------------------------------------------------- 
1252 void wxTreeCtrl::AdjustMyScrollbars() 
1258         m_anchor
->GetSize( x
, y
, this ); 
1259         //y += GetLineHeight(m_anchor); 
1260         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1261         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1262         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
1263         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, y_pos 
); 
1267         SetScrollbars( 0, 0, 0, 0 ); 
1271 int wxTreeCtrl::GetLineHeight(wxGenericTreeItem 
*item
) const 
1273   if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HIGHT
) 
1274     return item
->GetHeight(); 
1276     return m_lineHeight
;   
1279 void wxTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
1281     // render bold items in bold 
1287         fontOld 
= dc
.GetFont(); 
1290           // VZ: is there any better way to make a bold variant of old font? 
1291           fontNew 
= wxFont( fontOld
.GetPointSize(), 
1292                             fontOld
.GetFamily(), 
1295                             fontOld
.GetUnderlined()); 
1296           dc
.SetFont(fontNew
); 
1300             wxFAIL_MSG(_T("wxDC::GetFont() failed!")); 
1306     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
1310     if ((item
->IsExpanded()) && (item
->GetSelectedImage() != -1)) 
1312         m_imageListNormal
->GetSize( item
->GetSelectedImage(), image_w
, image_h 
); 
1315     else if (item
->GetImage() != -1) 
1317         m_imageListNormal
->GetSize( item
->GetImage(), image_w
, image_h 
); 
1321     int total_h 
= GetLineHeight(item
); 
1323     dc
.DrawRectangle( item
->GetX()-2, item
->GetY(), item
->GetWidth()+2, total_h 
); 
1325     if ((item
->IsExpanded()) && (item
->GetSelectedImage() != -1)) 
1327         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
1328         m_imageListNormal
->Draw( item
->GetSelectedImage(), dc
, 
1330                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
1331                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
1332         dc
.DestroyClippingRegion(); 
1334     else if (item
->GetImage() != -1) 
1336         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
1337         m_imageListNormal
->Draw( item
->GetImage(), dc
, 
1339                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
1340                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
1341         dc
.DestroyClippingRegion(); 
1344     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1345     dc
.DrawText( item
->GetText(), image_w 
+ item
->GetX(), item
->GetY() 
1346                  + ((total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0)); 
1348     // restore normal font for bold items 
1351         dc
.SetFont( fontOld
); 
1355 // Now y stands for the top of the item, whereas it used to stand for middle ! 
1356 void wxTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
1358     int horizX 
= level
*m_indent
; 
1360     item
->SetX( horizX
+m_indent
+m_spacing 
); 
1364     y
+=GetLineHeight(item
)/2; 
1366     item
->SetCross( horizX
+m_indent
, y 
); 
1368     int exposed_x 
= dc
.LogicalToDeviceX( 0 ); 
1369     int exposed_y 
= dc
.LogicalToDeviceY( item
->GetY()-2 ); 
1371     if (IsExposed( exposed_x
, exposed_y
, 10000, GetLineHeight(item
)+4 ))  // 10000 = very much 
1373         int startX 
= horizX
; 
1374         int endX 
= horizX 
+ (m_indent
-5); 
1376 //        if (!item->HasChildren()) endX += (m_indent+5); 
1377         if (!item
->HasChildren()) endX 
+= 20; 
1379         dc
.DrawLine( startX
, y
, endX
, y 
); 
1381         if (item
->HasPlus()) 
1383             dc
.DrawLine( horizX
+(m_indent
+5), y
, horizX
+(m_indent
+15), y 
); 
1384             dc
.SetPen( *wxGREY_PEN 
); 
1385             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1386             dc
.DrawRectangle( horizX
+(m_indent
-5), y
-4, 11, 9 ); 
1387             dc
.SetPen( *wxBLACK_PEN 
); 
1388             dc
.DrawLine( horizX
+(m_indent
-2), y
, horizX
+(m_indent
+3), y 
); 
1390             if (!item
->IsExpanded()) 
1392                 dc
.DrawLine( horizX
+m_indent
, y
-2, horizX
+m_indent
, y
+3 ); 
1396         if (item
->HasHilight()) 
1398             dc
.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
) ); 
1400             dc
.SetBrush( *m_hilightBrush 
); 
1403                 dc
.SetPen( *wxBLACK_PEN 
); 
1405                 dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1407             PaintItem(item
, dc
); 
1409             dc
.SetPen( *wxBLACK_PEN 
); 
1410             dc
.SetTextForeground( *wxBLACK 
); 
1411             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1415             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1416             dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1418             PaintItem(item
, dc
); 
1420             dc
.SetPen( *wxBLACK_PEN 
); 
1424     y 
= oldY
+GetLineHeight(item
); 
1426     if (item
->IsExpanded()) 
1428         oldY
+=GetLineHeight(item
)/2; 
1429         int semiOldY
=y
; // (=y) for stupid compilator 
1431         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1432         size_t n
, count 
= children
.Count(); 
1433         for ( n 
= 0; n 
< count
; ++n 
) 
1436             PaintLevel( children
[n
], dc
, level
+1, y 
); 
1439         // it may happen that the item is expanded but has no items (when you 
1440         // delete all its children for example) - don't draw the vertical line 
1444             semiOldY
+=GetLineHeight(children
[--n
])/2; 
1445             dc
.DrawLine( horizX
+m_indent
, oldY
+5, horizX
+m_indent
, semiOldY 
); 
1450 void wxTreeCtrl::DrawBorder(wxTreeItemId 
&item
) 
1454     wxGenericTreeItem 
*i
=item
.m_pItem
; 
1458     dc
.SetLogicalFunction(wxINVERT
); 
1461     ViewStart(&x
,&h
);     // we only need x 
1462     GetClientSize(&w
,&h
); // we only need w 
1464     h
=GetLineHeight(i
)+1; 
1465     // 2 white column at border 
1466     dc
.DrawRectangle( PIXELS_PER_UNIT
*x
+2, i
->GetY()-1, w
-6, h
); 
1469 void wxTreeCtrl::DrawLine(wxTreeItemId 
&item
, bool below
) 
1473     wxGenericTreeItem 
*i
=item
.m_pItem
; 
1477     dc
.SetLogicalFunction(wxINVERT
); 
1482     if (below
) y
=i
->GetY()+GetLineHeight(i
)-1; 
1485     dc
.DrawLine( 0, y
, w
, y
); 
1488 // ----------------------------------------------------------------------------- 
1489 // wxWindows callbacks 
1490 // ----------------------------------------------------------------------------- 
1492 void wxTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1500     dc
.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT 
) ); 
1502     dc
.SetPen( m_dottedPen 
); 
1503     //if(GetImageList() == NULL) 
1504     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
1507     PaintLevel( m_anchor
, dc
, 0, y 
); 
1510 void wxTreeCtrl::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1514     if (m_current
) RefreshLine( m_current 
); 
1517 void wxTreeCtrl::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1521     if (m_current
) RefreshLine( m_current 
); 
1524 void wxTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
1526     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
1527     te
.m_code 
= event
.KeyCode(); 
1528     te
.SetEventObject( this ); 
1529     GetEventHandler()->ProcessEvent( te 
); 
1531     if ( (m_current 
== 0) || (m_key_current 
== 0) ) 
1537     bool is_multiple
=(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1538     bool extended_select
=(event
.ShiftDown() && is_multiple
); 
1539     bool unselect_others
=!(extended_select 
|| (event
.ControlDown() && is_multiple
)); 
1541     switch (event
.KeyCode()) 
1545             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
1553             if (IsExpanded(m_current
)) 
1555                 Collapse(m_current
); 
1567                 wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
1568                 event
.m_item 
= m_current
; 
1570                 event
.SetEventObject( this ); 
1571                 GetEventHandler()->ProcessEvent( event 
); 
1575             // up goes to the previous sibling or to the last of its children if 
1579                 wxTreeItemId prev 
= GetPrevSibling( m_key_current 
); 
1582                     prev 
= GetParent( m_key_current 
); 
1586                         wxTreeItemId current 
= m_key_current
; 
1587                         if (current 
== GetFirstChild( prev
, cockie 
)) 
1589                             // otherwise we return to where we came from 
1590                             SelectItem( prev
, unselect_others
, extended_select 
); 
1591                             m_key_current
=prev
.m_pItem
; 
1592                             EnsureVisible( prev 
); 
1599                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
1601                         wxTreeItemId child 
= GetLastChild(prev
); 
1608                     SelectItem( prev
, unselect_others
, extended_select 
); 
1609                     m_key_current
=prev
.m_pItem
; 
1610                     EnsureVisible( prev 
); 
1615             // left arrow goes to the parent 
1618                 wxTreeItemId prev 
= GetParent( m_current 
); 
1621                     EnsureVisible( prev 
); 
1622                     SelectItem( prev
, unselect_others
, extended_select 
); 
1628             // this works the same as the down arrow except that we also expand the 
1629             // item if it wasn't expanded yet 
1635                 if (IsExpanded(m_key_current
) && HasChildren(m_key_current
)) 
1638                     wxTreeItemId child 
= GetFirstChild( m_key_current
, cookie 
); 
1639                     SelectItem( child
, unselect_others
, extended_select 
); 
1640                     m_key_current
=child
.m_pItem
; 
1641                     EnsureVisible( child 
); 
1645                     wxTreeItemId next 
= GetNextSibling( m_key_current 
); 
1648                         wxTreeItemId current 
= m_key_current
; 
1649                         while (current 
&& !next
) 
1651                             current 
= GetParent( current 
); 
1652                             if (current
) next 
= GetNextSibling( current 
); 
1657                         SelectItem( next
, unselect_others
, extended_select 
); 
1658                         m_key_current
=next
.m_pItem
; 
1659                         EnsureVisible( next 
); 
1665             // <End> selects the last visible tree item 
1668                 wxTreeItemId last 
= GetRootItem(); 
1670                 while ( last
.IsOk() && IsExpanded(last
) ) 
1672                     wxTreeItemId lastChild 
= GetLastChild(last
); 
1674                     // it may happen if the item was expanded but then all of 
1675                     // its children have been deleted - so IsExpanded() returned 
1676                     // TRUE, but GetLastChild() returned invalid item 
1685                     EnsureVisible( last 
); 
1686                     SelectItem( last
, unselect_others
, extended_select 
); 
1691             // <Home> selects the root item 
1694                 wxTreeItemId prev 
= GetRootItem(); 
1697                     EnsureVisible( prev 
); 
1698                     SelectItem( prev
, unselect_others
, extended_select 
); 
1708 wxTreeItemId 
wxTreeCtrl::HitTest(const wxPoint
& point
, int& flags
) 
1710     wxClientDC 
dc(this); 
1712     long x 
= dc
.DeviceToLogicalX( (long)point
.x 
); 
1713     long y 
= dc
.DeviceToLogicalY( (long)point
.y 
); 
1718     if (point
.x
<0) flags
|=wxTREE_HITTEST_TOLEFT
; 
1719     if (point
.x
>w
) flags
|=wxTREE_HITTEST_TORIGHT
; 
1720     if (point
.y
<0) flags
|=wxTREE_HITTEST_ABOVE
; 
1721     if (point
.y
>h
) flags
|=wxTREE_HITTEST_BELOW
; 
1723     return m_anchor
->HitTest( wxPoint(x
, y
), this, flags
); 
1726 void wxTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
1728     if (!event
.LeftIsDown()) m_dragCount 
= 0; 
1730     if ( !(event
.LeftUp() || event
.LeftDClick() || event
.Dragging()) ) return; 
1732     if ( !m_anchor 
) return; 
1734     wxClientDC 
dc(this); 
1736     long x 
= dc
.DeviceToLogicalX( (long)event
.GetX() ); 
1737     long y 
= dc
.DeviceToLogicalY( (long)event
.GetY() ); 
1740     wxGenericTreeItem 
*item 
= m_anchor
->HitTest( wxPoint(x
,y
), this, flags
); 
1741     bool onButton 
= flags 
& wxTREE_HITTEST_ONITEMBUTTON
; 
1743     if (item 
== NULL
) return;  /* we hit the blank area */ 
1745     if (event
.Dragging()) 
1747         if (m_dragCount 
== 2)  /* small drag latency (3?) */ 
1751             wxTreeEvent 
nevent(wxEVT_COMMAND_TREE_BEGIN_DRAG
, GetId()); 
1752             nevent
.m_item 
= m_current
; 
1753             nevent
.SetEventObject(this); 
1754             GetEventHandler()->ProcessEvent(nevent
); 
1763     bool is_multiple
=(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1764     bool extended_select
=(event
.ShiftDown() && is_multiple
); 
1765     bool unselect_others
=!(extended_select 
|| (event
.ControlDown() && is_multiple
)); 
1770         if (is_multiple
) return; 
1773     SelectItem(item
, unselect_others
, extended_select
); 
1775     if (event
.LeftDClick()) 
1777         wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
1778         event
.m_item 
= item
; 
1780         event
.SetEventObject( this ); 
1781         GetEventHandler()->ProcessEvent( event 
); 
1785 void wxTreeCtrl::OnIdle( wxIdleEvent 
&WXUNUSED(event
) ) 
1787     /* after all changes have been done to the tree control, 
1788      * we actually redraw the tree when everything is over */ 
1795     CalculatePositions(); 
1797     AdjustMyScrollbars(); 
1800 void wxTreeCtrl::CalculateSize( wxGenericTreeItem 
*item
, wxDC 
&dc 
) 
1804     // TODO : check for boldness. Here with suppose that font normal and bold 
1805     //        have the same height ! 
1806     // TODO : bug here, text_w is sometime not the correct answer !!! 
1807     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
1812     if ((item
->IsExpanded()) && (item
->GetSelectedImage() != -1)) 
1814         m_imageListNormal
->GetSize( item
->GetSelectedImage(), image_w
, image_h 
); 
1817     else if (item
->GetImage() != -1) 
1819         m_imageListNormal
->GetSize( item
->GetImage(), image_w
, image_h 
); 
1823     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
1825     if (total_h
<40) total_h
+=4; // at least 4 pixels 
1826     else total_h
+=total_h
/10;   // otherwise 10% extra spacing 
1828     item
->SetHeight(total_h
); 
1829     if (total_h
>m_lineHeight
) m_lineHeight
=total_h
; 
1831     item
->SetWidth(image_w
+text_w
+2); 
1834 // ----------------------------------------------------------------------------- 
1835 // for developper : y is now the top of the level 
1836 // not the middle of it ! 
1837 void wxTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
1839     int horizX 
= level
*m_indent
; 
1841     CalculateSize( item
, dc 
); 
1844     item
->SetX( horizX
+m_indent
+m_spacing 
); 
1846     y
+=GetLineHeight(item
); 
1848     if ( !item
->IsExpanded() ) 
1850         // we dont need to calculate collapsed branches 
1854     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1855     size_t n
, count 
= children
.Count(); 
1856     for (n 
= 0; n 
< count
; ++n 
) 
1857       CalculateLevel( children
[n
], dc
, level
+1, y 
);  // recurse 
1860 void wxTreeCtrl::CalculatePositions() 
1862     if ( !m_anchor 
) return; 
1864     wxClientDC 
dc(this); 
1867     dc
.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT 
) ); 
1869     dc
.SetPen( m_dottedPen 
); 
1870     //if(GetImageList() == NULL) 
1871     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
1873     int y 
= 2; //GetLineHeight(m_anchor) / 2 + 2; 
1874     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
1877 void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
1879     wxClientDC 
dc(this); 
1884     GetClientSize( &cw
, &ch 
); 
1887     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
1889     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
1892     Refresh( TRUE
, &rect 
); 
1894     AdjustMyScrollbars(); 
1897 void wxTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
1899     wxClientDC 
dc(this); 
1903     rect
.x 
= dc
.LogicalToDeviceX( item
->GetX() - 2 ); 
1904     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY()); 
1906     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
1908     Refresh( TRUE
, &rect 
);