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/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 // ============================================================================= 
 161 // ----------------------------------------------------------------------------- 
 162 // wxTreeRenameTimer (internal) 
 163 // ----------------------------------------------------------------------------- 
 165 wxTreeRenameTimer::wxTreeRenameTimer( wxTreeCtrl 
*owner 
) 
 170 void wxTreeRenameTimer::Notify() 
 172     m_owner
->OnRenameTimer(); 
 175 //----------------------------------------------------------------------------- 
 176 // wxTreeTextCtrl (internal) 
 177 //----------------------------------------------------------------------------- 
 179 IMPLEMENT_DYNAMIC_CLASS(wxTreeTextCtrl
,wxTextCtrl
); 
 181 BEGIN_EVENT_TABLE(wxTreeTextCtrl
,wxTextCtrl
) 
 182     EVT_CHAR           (wxTreeTextCtrl::OnChar
) 
 183     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus
) 
 186 wxTreeTextCtrl::wxTreeTextCtrl( wxWindow 
*parent
, const wxWindowID id
, 
 187     bool *accept
, wxString 
*res
, wxTreeCtrl 
*owner
, 
 188     const wxString 
&value
, const wxPoint 
&pos
, const wxSize 
&size
, 
 189     int style
, const wxValidator
& validator
, const wxString 
&name 
) : 
 190   wxTextCtrl( parent
, id
, value
, pos
, size
, style
, validator
, name 
) 
 197     m_startValue 
= value
; 
 200 void wxTreeTextCtrl::OnChar( wxKeyEvent 
&event 
) 
 202     if (event
.m_keyCode 
== WXK_RETURN
) 
 205         (*m_res
) = GetValue(); 
 209     if (event
.m_keyCode 
== WXK_ESCAPE
) 
 219 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
 221     if (wxPendingDelete
.Member(this)) return; 
 223     wxPendingDelete
.Append(this); 
 225     if ((*m_accept
) && ((*m_res
) != m_startValue
)) 
 226         m_owner
->OnRenameAccept(); 
 229 #define PIXELS_PER_UNIT 10 
 230 // ----------------------------------------------------------------------------- 
 232 // ----------------------------------------------------------------------------- 
 234 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent
, wxNotifyEvent
) 
 236 wxTreeEvent::wxTreeEvent( wxEventType commandType
, int id 
) 
 237            : wxNotifyEvent( commandType
, id 
) 
 240   m_itemOld 
= (wxGenericTreeItem 
*)NULL
; 
 243 // ----------------------------------------------------------------------------- 
 245 // ----------------------------------------------------------------------------- 
 247 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 248                                      const wxString
& text
, 
 250                                      int image
, int selImage
, 
 251                                      wxTreeItemData 
*data
) 
 255   m_selImage 
= selImage
; 
 258   m_xCross 
= m_yCross 
= 0; 
 262   m_isCollapsed 
= TRUE
; 
 263   m_hasHilight 
= FALSE
; 
 269   dc
.GetTextExtent( m_text
, &m_width
, &m_height 
); 
 270   // TODO : Add the width of the image 
 271   // PB   : We don't know which image is shown (image, selImage) 
 272   //        We don't even know imageList from the treectrl this item belongs to !!! 
 273   // At this point m_width doesn't mean much, this can be remove ! 
 276 wxGenericTreeItem::~wxGenericTreeItem() 
 280   wxASSERT_MSG( m_children
.IsEmpty(), 
 281                 _T("please call DeleteChildren() before deleting the item") ); 
 284 void wxGenericTreeItem::DeleteChildren(wxTreeCtrl 
*tree
) 
 286   size_t count 
= m_children
.Count(); 
 287   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 289     wxGenericTreeItem 
*child 
= m_children
[n
]; 
 292       tree
->SendDeleteEvent(child
); 
 295     child
->DeleteChildren(tree
); 
 302 void wxGenericTreeItem::SetText( const wxString 
&text 
) 
 307 void wxGenericTreeItem::Reset() 
 314   m_height 
= m_width 
= 0; 
 321   m_isCollapsed 
= TRUE
; 
 323   m_parent 
= (wxGenericTreeItem 
*)NULL
; 
 326 size_t wxGenericTreeItem::GetChildrenCount(bool recursively
) const 
 328   size_t count 
= m_children
.Count(); 
 332   size_t total 
= count
; 
 333   for ( size_t n 
= 0; n 
< count
; ++n 
) 
 335     total 
+= m_children
[n
]->GetChildrenCount(); 
 341 void wxGenericTreeItem::SetCross( int x
, int y 
) 
 347 void wxGenericTreeItem::GetSize( int &x
, int &y
, const wxTreeCtrl 
*theTree 
) 
 349   int bottomY
=m_y
+theTree
->GetLineHeight(this); 
 350   if ( y 
< bottomY 
) y 
= bottomY
; 
 351   int width 
= m_x 
+  m_width
; 
 352   if ( x 
< width 
) x 
= width
; 
 356     size_t count 
= m_children
.Count(); 
 357     for ( size_t n 
= 0; n 
< count
; ++n 
) 
 359       m_children
[n
]->GetSize( x
, y
, theTree 
); 
 364 wxGenericTreeItem 
*wxGenericTreeItem::HitTest( const wxPoint
& point
, 
 365                                                const wxTreeCtrl 
*theTree
, 
 368   if ((point
.y 
> m_y
) && (point
.y 
< m_y 
+ theTree
->GetLineHeight(this))) 
 370     if (point
.y
<m_y
+theTree
->GetLineHeight(this)/2) flags
|=wxTREE_HITTEST_ONITEMUPPERPART
; 
 371     else flags
|=wxTREE_HITTEST_ONITEMLOWERPART
; 
 374     //  Because that is the size of the plus sign, RR 
 375     if ((point
.x 
> m_xCross
-5) && (point
.x 
< m_xCross
+5) && 
 376         (point
.y 
> m_yCross
-5) && (point
.y 
< m_yCross
+5) && 
 377         (IsExpanded() || HasPlus())) 
 379       flags
|=wxTREE_HITTEST_ONITEMBUTTON
; 
 383     if ((point
.x 
>= m_x
) && (point
.x 
<= m_x
+m_width
)) 
 388       // assuming every image (normal and selected ) has the same size ! 
 389       if ((m_image
!=-1) && theTree
->m_imageListNormal
) 
 390           theTree
->m_imageListNormal
->GetSize(m_image
, image_w
, image_h
); 
 392       if ((image_w 
!= -1) && (point
.x 
<= m_x 
+ image_w 
+ 1)) 
 393         flags
|=wxTREE_HITTEST_ONITEMICON
; 
 395         flags
|=wxTREE_HITTEST_ONITEMLABEL
; 
 400     if (point
.x 
< m_x
)         flags
|=wxTREE_HITTEST_ONITEMIDENT
; 
 401     if (point
.x 
> m_x
+m_width
) flags
|=wxTREE_HITTEST_ONITEMRIGHT
; 
 409       size_t count 
= m_children
.Count(); 
 410       for ( size_t n 
= 0; n 
< count
; n
++ ) 
 412         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, theTree
, flags 
); 
 419   flags
|=wxTREE_HITTEST_NOWHERE
; 
 423 // ----------------------------------------------------------------------------- 
 424 // wxTreeCtrl implementation 
 425 // ----------------------------------------------------------------------------- 
 427 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxScrolledWindow
) 
 429 BEGIN_EVENT_TABLE(wxTreeCtrl
,wxScrolledWindow
) 
 430   EVT_PAINT          (wxTreeCtrl::OnPaint
) 
 431   EVT_MOUSE_EVENTS   (wxTreeCtrl::OnMouse
) 
 432   EVT_CHAR           (wxTreeCtrl::OnChar
) 
 433   EVT_SET_FOCUS      (wxTreeCtrl::OnSetFocus
) 
 434   EVT_KILL_FOCUS     (wxTreeCtrl::OnKillFocus
) 
 435   EVT_IDLE           (wxTreeCtrl::OnIdle
) 
 438 // ----------------------------------------------------------------------------- 
 439 // construction/destruction 
 440 // ----------------------------------------------------------------------------- 
 442 void wxTreeCtrl::Init() 
 446   m_anchor 
= (wxGenericTreeItem 
*) NULL
; 
 456   m_hilightBrush 
= new wxBrush
 
 458       wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), 
 463   m_imageListState 
= (wxImageList 
*) NULL
; 
 467   m_renameTimer 
= new wxTreeRenameTimer( this ); 
 470 bool wxTreeCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 471                         const wxPoint
& pos
, const wxSize
& size
, 
 473             const wxValidator 
&validator
, 
 474             const wxString
& name 
) 
 478   wxScrolledWindow::Create( parent
, id
, pos
, size
, style
|wxHSCROLL
|wxVSCROLL
, name 
); 
 481   SetValidator( validator 
); 
 484   SetBackgroundColour( *wxWHITE 
); 
 485 //  m_dottedPen = wxPen( "grey", 0, wxDOT ); 
 486   m_dottedPen 
= wxPen( "grey", 0, 0 ); 
 491 wxTreeCtrl::~wxTreeCtrl() 
 493   wxDELETE( m_hilightBrush 
); 
 497   delete m_renameTimer
; 
 500 // ----------------------------------------------------------------------------- 
 502 // ----------------------------------------------------------------------------- 
 504 size_t wxTreeCtrl::GetCount() const 
 506   return m_anchor 
== NULL 
? 0u : m_anchor
->GetChildrenCount(); 
 509 void wxTreeCtrl::SetIndent(unsigned int indent
) 
 516 void wxTreeCtrl::SetSpacing(unsigned int spacing
) 
 523 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
) 
 525   wxCHECK_MSG( item
.IsOk(), 0u, _T("invalid tree item") ); 
 527   return item
.m_pItem
->GetChildrenCount(recursively
); 
 530 // ----------------------------------------------------------------------------- 
 531 // functions to work with tree items 
 532 // ----------------------------------------------------------------------------- 
 534 wxString 
wxTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 536   wxCHECK_MSG( item
.IsOk(), _T(""), _T("invalid tree item") ); 
 538   return item
.m_pItem
->GetText(); 
 541 int wxTreeCtrl::GetItemImage(const wxTreeItemId
& item
) const 
 543   wxCHECK_MSG( item
.IsOk(), -1, _T("invalid tree item") ); 
 545   return item
.m_pItem
->GetImage(); 
 548 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const 
 550   wxCHECK_MSG( item
.IsOk(), -1, _T("invalid tree item") ); 
 552   return item
.m_pItem
->GetSelectedImage(); 
 555 wxTreeItemData 
*wxTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 557   wxCHECK_MSG( item
.IsOk(), NULL
, _T("invalid tree item") ); 
 559   return item
.m_pItem
->GetData(); 
 562 void wxTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 564   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 567   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 568   pItem
->SetText(text
); 
 569   CalculateSize(pItem
, dc
); 
 573 void wxTreeCtrl::SetItemImage(const wxTreeItemId
& item
, int image
) 
 575   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 578   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 579   pItem
->SetImage(image
); 
 580   CalculateSize(pItem
, dc
); 
 584 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
) 
 586   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 589   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 590   pItem
->SetSelectedImage(image
); 
 591   CalculateSize(pItem
, dc
); 
 595 void wxTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 597   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 599   item
.m_pItem
->SetData(data
); 
 602 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
 604   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 606   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 607   pItem
->SetHasPlus(has
); 
 611 void wxTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
 613   wxCHECK_RET( item
.IsOk(), _T("invalid tree item") ); 
 615   // avoid redrawing the tree if no real change 
 616   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 617   if ( pItem
->IsBold() != bold 
) 
 619     pItem
->SetBold(bold
); 
 624 // ----------------------------------------------------------------------------- 
 625 // item status inquiries 
 626 // ----------------------------------------------------------------------------- 
 628 bool wxTreeCtrl::IsVisible(const wxTreeItemId
& WXUNUSED(item
)) const 
 630   wxFAIL_MSG(_T("not implemented")); 
 635 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
 637   wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid tree item") ); 
 639   return !item
.m_pItem
->GetChildren().IsEmpty(); 
 642 bool wxTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
 644   wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid tree item") ); 
 646   return item
.m_pItem
->IsExpanded(); 
 649 bool wxTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
 651   wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid tree item") ); 
 653   return item
.m_pItem
->HasHilight(); 
 656 bool wxTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
 658   wxCHECK_MSG( item
.IsOk(), FALSE
, _T("invalid tree item") ); 
 660   return item
.m_pItem
->IsBold(); 
 663 // ----------------------------------------------------------------------------- 
 665 // ----------------------------------------------------------------------------- 
 667 wxTreeItemId 
wxTreeCtrl::GetParent(const wxTreeItemId
& item
) const 
 669   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 671   return item
.m_pItem
->GetParent(); 
 674 wxTreeItemId 
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const 
 676   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 679   return GetNextChild(item
, cookie
); 
 682 wxTreeItemId 
wxTreeCtrl::GetNextChild(const wxTreeItemId
& item
, long& cookie
) const 
 684   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 686   wxArrayGenericTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 687   if ( (size_t)cookie 
< children
.Count() ) 
 689     return children
.Item(cookie
++); 
 693     // there are no more of them 
 694     return wxTreeItemId(); 
 698 wxTreeItemId 
wxTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
 700   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 702   wxArrayGenericTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 703   return (children
.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children
.Last())); 
 706 wxTreeItemId 
wxTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
 708   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 710   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 711   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 712   if ( parent 
== NULL 
) 
 714     // root item doesn't have any siblings 
 715     return wxTreeItemId(); 
 718   wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
 719   int index 
= siblings
.Index(i
); 
 720   wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 722   size_t n 
= (size_t)(index 
+ 1); 
 723   return n 
== siblings
.Count() ? wxTreeItemId() : wxTreeItemId(siblings
[n
]); 
 726 wxTreeItemId 
wxTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
 728   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 730   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 731   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 732   if ( parent 
== NULL 
) 
 734     // root item doesn't have any siblings 
 735     return wxTreeItemId(); 
 738   wxArrayGenericTreeItems
& siblings 
= parent
->GetChildren(); 
 739   int index 
= siblings
.Index(i
); 
 740   wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
 742   return index 
== 0 ? wxTreeItemId() 
 743                     : wxTreeItemId(siblings
[(size_t)(index 
- 1)]); 
 746 wxTreeItemId 
wxTreeCtrl::GetFirstVisibleItem() const 
 748   wxFAIL_MSG(_T("not implemented")); 
 750   return wxTreeItemId(); 
 753 wxTreeItemId 
wxTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
 755   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 757   wxFAIL_MSG(_T("not implemented")); 
 759   return wxTreeItemId(); 
 762 wxTreeItemId 
wxTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
 764   wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), _T("invalid tree item") ); 
 766   wxFAIL_MSG(_T("not implemented")); 
 768   return wxTreeItemId(); 
 771 // ----------------------------------------------------------------------------- 
 773 // ----------------------------------------------------------------------------- 
 775 wxTreeItemId 
wxTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
 777                                       const wxString
& text
, 
 778                                       int image
, int selImage
, 
 779                                       wxTreeItemData 
*data
) 
 781   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 784     // should we give a warning here? 
 785     return AddRoot(text
, image
, selImage
, data
); 
 789   wxGenericTreeItem 
*item 
= new wxGenericTreeItem(parent
, 
 796     data
->m_pItem 
= item
; 
 799   parent
->Insert( item
, previous 
); 
 806 wxTreeItemId 
wxTreeCtrl::AddRoot(const wxString
& text
, 
 807                                  int image
, int selImage
, 
 808                                  wxTreeItemData 
*data
) 
 810   wxCHECK_MSG( !m_anchor
, wxTreeItemId(), _T("tree can have only one root") ); 
 813   m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, dc
, 
 814                                    image
, selImage
, data
); 
 817     data
->m_pItem 
= m_anchor
; 
 821   AdjustMyScrollbars(); 
 826 wxTreeItemId 
wxTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
 827                                      const wxString
& text
, 
 828                                      int image
, int selImage
, 
 829                                      wxTreeItemData 
*data
) 
 831   return DoInsertItem(parent
, 0u, text
, image
, selImage
, data
); 
 834 wxTreeItemId 
wxTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
 835                                     const wxTreeItemId
& idPrevious
, 
 836                                     const wxString
& text
, 
 837                                     int image
, int selImage
, 
 838                                     wxTreeItemData 
*data
) 
 840   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 843     // should we give a warning here? 
 844     return AddRoot(text
, image
, selImage
, data
); 
 847   int index 
= parent
->GetChildren().Index(idPrevious
.m_pItem
); 
 848   wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
 849                 _T("previous item in wxTreeCtrl::InsertItem() is not a sibling") ); 
 850   return DoInsertItem(parentId
, (size_t)++index
, text
, image
, selImage
, data
); 
 853 wxTreeItemId 
wxTreeCtrl::AppendItem(const wxTreeItemId
& parentId
, 
 854                                     const wxString
& text
, 
 855                                     int image
, int selImage
, 
 856                                     wxTreeItemData 
*data
) 
 858   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 861     // should we give a warning here? 
 862     return AddRoot(text
, image
, selImage
, data
); 
 865   return DoInsertItem(parent
, parent
->GetChildren().Count(), text
, 
 866                       image
, selImage
, data
); 
 869 void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem 
*item
) 
 871   wxTreeEvent 
event( wxEVT_COMMAND_TREE_DELETE_ITEM
, GetId() ); 
 873   event
.SetEventObject( this ); 
 874   ProcessEvent( event 
); 
 877 void wxTreeCtrl::DeleteChildren(const wxTreeItemId
& itemId
) 
 879     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 880     item
->DeleteChildren(this); 
 885 void wxTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
 887   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 888   wxGenericTreeItem 
*parent 
= item
->GetParent(); 
 892     parent
->GetChildren().Remove(item
); 
 895   item
->DeleteChildren(this); 
 896   SendDeleteEvent(item
); 
 902 void wxTreeCtrl::DeleteAllItems() 
 906     m_anchor
->DeleteChildren(this); 
 915 void wxTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
 917   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 919   if ( !item
->HasPlus() ) 
 922   if ( item
->IsExpanded() ) 
 925   wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
 927   event
.SetEventObject( this ); 
 928   if ( ProcessEvent( event 
) && event
.m_code 
) 
 930     // cancelled by program 
 935   CalculatePositions(); 
 937   RefreshSubtree(item
); 
 939   event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
 940   ProcessEvent( event 
); 
 943 void wxTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
 945   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 947   if ( !item
->IsExpanded() ) 
 950   wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
 952   event
.SetEventObject( this ); 
 953   if ( ProcessEvent( event 
) && event
.m_code 
) 
 955     // cancelled by program 
 961   wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
 962   size_t count 
= children
.Count(); 
 963   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 965     Collapse(children
[n
]); 
 968   CalculatePositions(); 
 970   RefreshSubtree(item
); 
 972   event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
 973   ProcessEvent( event 
); 
 976 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
 979   DeleteChildren(item
); 
 982 void wxTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
 984   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 986   if ( item
->IsExpanded() ) 
 992 void wxTreeCtrl::Unselect() 
 996     m_current
->SetHilight( FALSE 
); 
 997     RefreshLine( m_current 
); 
1001 void wxTreeCtrl::UnselectAllChildren(wxGenericTreeItem 
*item
) 
1003   item
->SetHilight(FALSE
); 
1006   if (item
->HasChildren()) 
1008       wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1009       size_t count 
= children
.Count(); 
1010       for ( size_t n 
= 0; n 
< count
; ++n 
) 
1011         UnselectAllChildren(children
[n
]); 
1015 void wxTreeCtrl::UnselectAll() 
1017   UnselectAllChildren(GetRootItem().m_pItem
); 
1020 // Recursive function ! 
1021 // To stop we must have crt_item<last_item 
1023 // Tag all next children, when no more children, 
1024 // Move to parent (not to tag) 
1025 // Keep going... if we found last_item, we stop. 
1026 bool wxTreeCtrl::TagNextChildren(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1028     wxGenericTreeItem 
*parent 
= crt_item
->GetParent(); 
1030     if ( parent 
== NULL 
) // This is root item 
1031       return TagAllChildrenUntilLast(crt_item
, last_item
, select
); 
1033     wxArrayGenericTreeItems
& children 
= parent
->GetChildren(); 
1034     int index 
= children
.Index(crt_item
); 
1035     wxASSERT( index 
!= wxNOT_FOUND 
); // I'm not a child of my parent? 
1037     size_t count 
= children
.Count(); 
1038     for (size_t n
=(size_t)(index
+1); n
<count
; ++n
) 
1039       if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return TRUE
; 
1041     return TagNextChildren(parent
, last_item
, select
); 
1044 bool wxTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem 
*crt_item
, wxGenericTreeItem 
*last_item
, bool select
) 
1046   crt_item
->SetHilight(select
); 
1047   RefreshLine(crt_item
); 
1049   if (crt_item
==last_item
) return TRUE
; 
1051   if (crt_item
->HasChildren()) 
1053       wxArrayGenericTreeItems
& children 
= crt_item
->GetChildren(); 
1054       size_t count 
= children
.Count(); 
1055       for ( size_t n 
= 0; n 
< count
; ++n 
) 
1056         if (TagAllChildrenUntilLast(children
[n
], last_item
, select
)) return TRUE
; 
1062 void wxTreeCtrl::SelectItemRange(wxGenericTreeItem 
*item1
, wxGenericTreeItem 
*item2
) 
1064   // item2 is not necessary after item1 
1065   wxGenericTreeItem 
*first
=NULL
, *last
=NULL
; 
1067   // choice first' and 'last' between item1 and item2 
1068   if (item1
->GetY()<item2
->GetY()) 
1079   bool select
=m_current
->HasHilight(); 
1081   if (TagAllChildrenUntilLast(first
,last
,select
)) return; 
1083   TagNextChildren(first
,last
,select
); 
1086 void wxTreeCtrl::SelectItem(const wxTreeItemId
& itemId
, 
1087                             bool unselect_others
, 
1088                             bool extended_select
) 
1090     wxCHECK_RET( itemId
.IsOk(), _T("invalid tree item") ); 
1092     bool is_single
=!(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1093     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1095     //wxCHECK_RET( ( (!unselect_others) && is_single), 
1096     //           _T("this is a single selection tree") ); 
1098     // to keep going anyhow !!! 
1101         if (item
->HasHilight()) return; // nothing to do 
1102         unselect_others
=TRUE
; 
1103         extended_select
=FALSE
; 
1105     else // check if selection will really change 
1106       if (unselect_others 
&& item
->HasHilight()) 
1108         // selection change if there is more than one item currently selected 
1109         wxArrayTreeItemIds selected_items
; 
1110         if (GetSelections(selected_items
)==1) return; 
1113     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
1114     event
.m_item 
= item
; 
1115     event
.m_itemOld 
= m_current
; 
1116     event
.SetEventObject( this ); 
1117     // TODO : Here we don't send any selection mode yet ! 
1119     if ( GetEventHandler()->ProcessEvent( event 
) && !event
.IsAllowed() ) 
1123     if (unselect_others
) 
1125         if (is_single
) Unselect(); // to speed up thing 
1130     if (extended_select
) 
1132         if (m_current 
== NULL
) m_current
=m_key_current
=GetRootItem().m_pItem
; 
1133         // don't change the mark (m_current) 
1134         SelectItemRange(m_current
, item
); 
1138         bool select
=TRUE
; // the default 
1140         // Check if we need to toggle hilight (ctrl mode) 
1141         if (!unselect_others
) 
1142           select
=!item
->HasHilight(); 
1144         m_current 
= m_key_current 
= item
; 
1145         m_current
->SetHilight(select
); 
1146         RefreshLine( m_current 
); 
1149     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
1150     GetEventHandler()->ProcessEvent( event 
); 
1153 void wxTreeCtrl::FillArray(wxGenericTreeItem 
*item
, 
1154                            wxArrayTreeItemIds 
&array
) const 
1156     if ( item
->HasHilight() ) 
1157         array
.Add(wxTreeItemId(item
)); 
1159     if ( item
->HasChildren() ) 
1161         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1162         size_t count 
= children
.GetCount(); 
1163         for ( size_t n 
= 0; n 
< count
; ++n 
) 
1164             FillArray(children
[n
],array
); 
1168 size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds 
&array
) const 
1171   FillArray(GetRootItem().m_pItem
, array
); 
1173   return array
.Count(); 
1176 void wxTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
1178     if (!item
.IsOk()) return; 
1180     wxGenericTreeItem 
*gitem 
= item
.m_pItem
; 
1182     // first expand all parent branches 
1183     wxGenericTreeItem 
*parent 
= gitem
->GetParent(); 
1187         parent 
= parent
->GetParent(); 
1190     //if (parent) CalculatePositions(); 
1195 void wxTreeCtrl::ScrollTo(const wxTreeItemId 
&item
) 
1197     if (!item
.IsOk()) return; 
1199     // We have to call this here because the label in 
1200     // question might just have been added and no screen 
1201     // update taken place. 
1202     if (m_dirty
) wxYield(); 
1204     wxGenericTreeItem 
*gitem 
= item
.m_pItem
; 
1206     // now scroll to the item 
1207     int item_y 
= gitem
->GetY(); 
1211     ViewStart( &start_x
, &start_y 
); 
1212     start_y 
*= PIXELS_PER_UNIT
; 
1216     GetClientSize( &client_w
, &client_h 
); 
1218     if (item_y 
< start_y
+3) 
1223         m_anchor
->GetSize( x
, y
, this ); 
1224         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1225         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1226         // Item should appear at top 
1227         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, item_y
/PIXELS_PER_UNIT 
); 
1229     else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) 
1234        m_anchor
->GetSize( x
, y
, this ); 
1235        y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1236        item_y 
+= PIXELS_PER_UNIT
+2; 
1237        int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1238         // Item should appear at bottom 
1239        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 
); 
1243 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
1244 static wxTreeCtrl 
*s_treeBeingSorted 
= NULL
; 
1246 static int tree_ctrl_compare_func(wxGenericTreeItem 
**item1
, 
1247                                   wxGenericTreeItem 
**item2
) 
1249     wxCHECK_MSG( s_treeBeingSorted
, 0, _T("bug in wxTreeCtrl::SortChildren()") ); 
1251     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
1254 int wxTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
1255                                const wxTreeItemId
& item2
) 
1257     return wxStrcmp(GetItemText(item1
), GetItemText(item2
)); 
1260 void wxTreeCtrl::SortChildren(const wxTreeItemId
& itemId
) 
1262     wxCHECK_RET( itemId
.IsOk(), _T("invalid tree item") ); 
1264     wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
1266     wxCHECK_RET( !s_treeBeingSorted
, 
1267                  _T("wxTreeCtrl::SortChildren is not reentrant") ); 
1269     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1270     if ( children
.Count() > 1 ) 
1272         s_treeBeingSorted 
= this; 
1273         children
.Sort(tree_ctrl_compare_func
); 
1274         s_treeBeingSorted 
= NULL
; 
1278     //else: don't make the tree dirty as nothing changed 
1281 wxImageList 
*wxTreeCtrl::GetImageList() const 
1283     return m_imageListNormal
; 
1286 wxImageList 
*wxTreeCtrl::GetStateImageList() const 
1288     return m_imageListState
; 
1291 void wxTreeCtrl::SetImageList(wxImageList 
*imageList
) 
1293    m_imageListNormal 
= imageList
; 
1295    // Calculate a m_lineHeight value from the image sizes. 
1296    // May be toggle off. Then wxTreeCtrl will spread when 
1297    // necessary (which might look ugly). 
1299    wxClientDC 
dc(this); 
1300    m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1304       n 
= m_imageListNormal
->GetImageCount(); 
1305    for(int i 
= 0; i 
< n 
; i
++) 
1307       m_imageListNormal
->GetSize(i
, width
, height
); 
1308       if(height 
> m_lineHeight
) m_lineHeight 
= height
; 
1311    if (m_lineHeight
<40) m_lineHeight
+=4; // at least 4 pixels (odd such that a line can be drawn in between) 
1312    else m_lineHeight
+=m_lineHeight
/10;   // otherwise 10% extra spacing 
1317 void wxTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
1319     m_imageListState 
= imageList
; 
1322 // ----------------------------------------------------------------------------- 
1324 // ----------------------------------------------------------------------------- 
1326 void wxTreeCtrl::AdjustMyScrollbars() 
1332         m_anchor
->GetSize( x
, y
, this ); 
1333         //y += GetLineHeight(m_anchor); 
1334         y 
+= PIXELS_PER_UNIT
+2; // one more scrollbar unit + 2 pixels 
1335         int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
1336         int y_pos 
= GetScrollPos( wxVERTICAL 
); 
1337         SetScrollbars( PIXELS_PER_UNIT
, PIXELS_PER_UNIT
, x
/PIXELS_PER_UNIT
, y
/PIXELS_PER_UNIT
, x_pos
, y_pos 
); 
1341         SetScrollbars( 0, 0, 0, 0 ); 
1345 int wxTreeCtrl::GetLineHeight(wxGenericTreeItem 
*item
) const 
1347     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
1348         return item
->GetHeight(); 
1350         return m_lineHeight
; 
1353 void wxTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
1355     // render bold items in bold 
1361         fontOld 
= dc
.GetFont(); 
1364           // VZ: is there any better way to make a bold variant of old font? 
1365           fontNew 
= wxFont( fontOld
.GetPointSize(), 
1366                             fontOld
.GetFamily(), 
1369                             fontOld
.GetUnderlined()); 
1370           dc
.SetFont(fontNew
); 
1374             wxFAIL_MSG(_T("wxDC::GetFont() failed!")); 
1380     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
1384     if ((item
->IsExpanded()) && (item
->GetSelectedImage() != -1)) 
1386         m_imageListNormal
->GetSize( item
->GetSelectedImage(), image_w
, image_h 
); 
1389     else if (item
->GetImage() != -1) 
1391         m_imageListNormal
->GetSize( item
->GetImage(), image_w
, image_h 
); 
1395     int total_h 
= GetLineHeight(item
); 
1397     dc
.DrawRectangle( item
->GetX()-2, item
->GetY(), item
->GetWidth()+2, total_h 
); 
1399     if ((item
->IsExpanded()) && (item
->GetSelectedImage() != -1)) 
1401         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
1402         m_imageListNormal
->Draw( item
->GetSelectedImage(), dc
, 
1404                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
1405                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
1406         dc
.DestroyClippingRegion(); 
1408     else if (item
->GetImage() != -1) 
1410         dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, total_h 
); 
1411         m_imageListNormal
->Draw( item
->GetImage(), dc
, 
1413                                  item
->GetY() +((total_h 
> image_h
)?((total_h
-image_h
)/2):0), 
1414                                  wxIMAGELIST_DRAW_TRANSPARENT 
); 
1415         dc
.DestroyClippingRegion(); 
1418     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1419     dc
.DrawText( item
->GetText(), image_w 
+ item
->GetX(), item
->GetY() 
1420                  + ((total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0)); 
1422     // restore normal font for bold items 
1425         dc
.SetFont( fontOld
); 
1429 // Now y stands for the top of the item, whereas it used to stand for middle ! 
1430 void wxTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
1432     int horizX 
= level
*m_indent
; 
1434     item
->SetX( horizX
+m_indent
+m_spacing 
); 
1438     y
+=GetLineHeight(item
)/2; 
1440     item
->SetCross( horizX
+m_indent
, y 
); 
1442     int exposed_x 
= dc
.LogicalToDeviceX( 0 ); 
1443     int exposed_y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
1445     if (IsExposed( exposed_x
, exposed_y
, 10000, GetLineHeight(item
) ))  // 10000 = very much 
1447         int startX 
= horizX
; 
1448         int endX 
= horizX 
+ (m_indent
-5); 
1450 //        if (!item->HasChildren()) endX += (m_indent+5); 
1451         if (!item
->HasChildren()) endX 
+= 20; 
1453         dc
.DrawLine( startX
, y
, endX
, y 
); 
1455         if (item
->HasPlus()) 
1457             dc
.DrawLine( horizX
+(m_indent
+5), y
, horizX
+(m_indent
+15), y 
); 
1458             dc
.SetPen( *wxGREY_PEN 
); 
1459             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1460             dc
.DrawRectangle( horizX
+(m_indent
-5), y
-4, 11, 9 ); 
1462             dc
.SetPen( *wxBLACK_PEN 
); 
1463             dc
.DrawLine( horizX
+(m_indent
-2), y
, horizX
+(m_indent
+3), y 
); 
1464             if (!item
->IsExpanded()) 
1465                 dc
.DrawLine( horizX
+m_indent
, y
-2, horizX
+m_indent
, y
+3 ); 
1467             dc
.SetPen( m_dottedPen 
); 
1470         if (item
->HasHilight()) 
1472             dc
.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
) ); 
1474             dc
.SetBrush( *m_hilightBrush 
); 
1477                 dc
.SetPen( *wxBLACK_PEN 
); 
1479                 dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1481             PaintItem(item
, dc
); 
1483             dc
.SetPen( m_dottedPen 
); 
1484             dc
.SetTextForeground( *wxBLACK 
); 
1485             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1489             dc
.SetBrush( *wxWHITE_BRUSH 
); 
1490             dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1492             PaintItem(item
, dc
); 
1494             dc
.SetPen( m_dottedPen 
); 
1498     y 
= oldY
+GetLineHeight(item
); 
1500     if (item
->IsExpanded()) 
1502         oldY
+=GetLineHeight(item
)/2; 
1503         int semiOldY
=y
; // (=y) for stupid compilator 
1505         wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
1506         size_t n
, count 
= children
.Count(); 
1507         for ( n 
= 0; n 
< count
; ++n 
) 
1510             PaintLevel( children
[n
], dc
, level
+1, y 
); 
1513         // it may happen that the item is expanded but has no items (when you 
1514         // delete all its children for example) - don't draw the vertical line 
1518             semiOldY
+=GetLineHeight(children
[--n
])/2; 
1519             dc
.DrawLine( horizX
+m_indent
, oldY
+5, horizX
+m_indent
, semiOldY 
); 
1524 void wxTreeCtrl::DrawBorder(wxTreeItemId 
&item
) 
1528     wxGenericTreeItem 
*i
=item
.m_pItem
; 
1530     wxClientDC 
dc(this); 
1532     dc
.SetLogicalFunction(wxINVERT
); 
1535     ViewStart(&x
,&h
);     // we only need x 
1536     GetClientSize(&w
,&h
); // we only need w 
1538     h
=GetLineHeight(i
)+1; 
1539     // 2 white column at border 
1540     dc
.DrawRectangle( PIXELS_PER_UNIT
*x
+2, i
->GetY()-1, w
-6, h
); 
1543 void wxTreeCtrl::DrawLine(wxTreeItemId 
&item
, bool below
) 
1547     wxGenericTreeItem 
*i
=item
.m_pItem
; 
1549     wxClientDC 
dc(this); 
1551     dc
.SetLogicalFunction(wxINVERT
); 
1556     if (below
) y
=i
->GetY()+GetLineHeight(i
)-1; 
1559     dc
.DrawLine( 0, y
, w
, y
); 
1562 // ----------------------------------------------------------------------------- 
1563 // wxWindows callbacks 
1564 // ----------------------------------------------------------------------------- 
1566 void wxTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1574     dc
.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT 
) ); 
1576     dc
.SetPen( m_dottedPen 
); 
1577     //if(GetImageList() == NULL) 
1578     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
1581     PaintLevel( m_anchor
, dc
, 0, y 
); 
1584 void wxTreeCtrl::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1588     if (m_current
) RefreshLine( m_current 
); 
1591 void wxTreeCtrl::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1595     if (m_current
) RefreshLine( m_current 
); 
1598 void wxTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
1600     wxTreeEvent 
te( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
1601     te
.m_code 
= event
.KeyCode(); 
1602     te
.SetEventObject( this ); 
1603     GetEventHandler()->ProcessEvent( te 
); 
1605     if ( (m_current 
== 0) || (m_key_current 
== 0) ) 
1611     bool is_multiple
=(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1612     bool extended_select
=(event
.ShiftDown() && is_multiple
); 
1613     bool unselect_others
=!(extended_select 
|| (event
.ControlDown() && is_multiple
)); 
1615     switch (event
.KeyCode()) 
1619             if (m_current
->HasPlus() && !IsExpanded(m_current
)) 
1627             if (IsExpanded(m_current
)) 
1629                 Collapse(m_current
); 
1641                 wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
1642                 event
.m_item 
= m_current
; 
1644                 event
.SetEventObject( this ); 
1645                 GetEventHandler()->ProcessEvent( event 
); 
1649             // up goes to the previous sibling or to the last of its children if 
1653                 wxTreeItemId prev 
= GetPrevSibling( m_key_current 
); 
1656                     prev 
= GetParent( m_key_current 
); 
1660                         wxTreeItemId current 
= m_key_current
; 
1661                         if (current 
== GetFirstChild( prev
, cockie 
)) 
1663                             // otherwise we return to where we came from 
1664                             SelectItem( prev
, unselect_others
, extended_select 
); 
1665                             m_key_current
=prev
.m_pItem
; 
1666                             EnsureVisible( prev 
); 
1673                     while ( IsExpanded(prev
) && HasChildren(prev
) ) 
1675                         wxTreeItemId child 
= GetLastChild(prev
); 
1682                     SelectItem( prev
, unselect_others
, extended_select 
); 
1683                     m_key_current
=prev
.m_pItem
; 
1684                     EnsureVisible( prev 
); 
1689             // left arrow goes to the parent 
1692                 wxTreeItemId prev 
= GetParent( m_current 
); 
1695                     EnsureVisible( prev 
); 
1696                     SelectItem( prev
, unselect_others
, extended_select 
); 
1702             // this works the same as the down arrow except that we also expand the 
1703             // item if it wasn't expanded yet 
1709                 if (IsExpanded(m_key_current
) && HasChildren(m_key_current
)) 
1712                     wxTreeItemId child 
= GetFirstChild( m_key_current
, cookie 
); 
1713                     SelectItem( child
, unselect_others
, extended_select 
); 
1714                     m_key_current
=child
.m_pItem
; 
1715                     EnsureVisible( child 
); 
1719                     wxTreeItemId next 
= GetNextSibling( m_key_current 
); 
1723                         wxTreeItemId current 
= m_key_current
; 
1724                         while (current 
&& !next
) 
1726                             current 
= GetParent( current 
); 
1727                             if (current
) next 
= GetNextSibling( current 
); 
1733                         SelectItem( next
, unselect_others
, extended_select 
); 
1734                         m_key_current
=next
.m_pItem
; 
1735                         EnsureVisible( next 
); 
1741             // <End> selects the last visible tree item 
1744                 wxTreeItemId last 
= GetRootItem(); 
1746                 while ( last
.IsOk() && IsExpanded(last
) ) 
1748                     wxTreeItemId lastChild 
= GetLastChild(last
); 
1750                     // it may happen if the item was expanded but then all of 
1751                     // its children have been deleted - so IsExpanded() returned 
1752                     // TRUE, but GetLastChild() returned invalid item 
1761                     EnsureVisible( last 
); 
1762                     SelectItem( last
, unselect_others
, extended_select 
); 
1767             // <Home> selects the root item 
1770                 wxTreeItemId prev 
= GetRootItem(); 
1773                     EnsureVisible( prev 
); 
1774                     SelectItem( prev
, unselect_others
, extended_select 
); 
1784 wxTreeItemId 
wxTreeCtrl::HitTest(const wxPoint
& point
, int& flags
) 
1786     // We have to call this here because the label in 
1787     // question might just have been added and no screen 
1788     // update taken place. 
1789     if (m_dirty
) wxYield(); 
1791     wxClientDC 
dc(this); 
1793     long x 
= dc
.DeviceToLogicalX( (long)point
.x 
); 
1794     long y 
= dc
.DeviceToLogicalY( (long)point
.y 
); 
1799     if (point
.x
<0) flags
|=wxTREE_HITTEST_TOLEFT
; 
1800     if (point
.x
>w
) flags
|=wxTREE_HITTEST_TORIGHT
; 
1801     if (point
.y
<0) flags
|=wxTREE_HITTEST_ABOVE
; 
1802     if (point
.y
>h
) flags
|=wxTREE_HITTEST_BELOW
; 
1804     return m_anchor
->HitTest( wxPoint(x
, y
), this, flags
); 
1809 void wxTreeCtrl::Edit( const wxTreeItemId
& item 
) 
1811     if (!item
.IsOk()) return; 
1813     m_currentEdit 
= item
.m_pItem
; 
1815     wxTreeEvent 
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, GetId() ); 
1816     te
.m_item 
= m_currentEdit
; 
1817     te
.SetEventObject( this ); 
1818     GetEventHandler()->ProcessEvent( te 
); 
1820     if (!te
.IsAllowed()) return; 
1822     // We have to call this here because the label in 
1823     // question might just have been added and no screen 
1824     // update taken place. 
1825     if (m_dirty
) wxYield(); 
1827     wxString s 
= m_currentEdit
->GetText(); 
1828     int x 
= m_currentEdit
->GetX(); 
1829     int y 
= m_currentEdit
->GetY(); 
1830     int w 
= m_currentEdit
->GetWidth(); 
1831     int h 
= m_currentEdit
->GetHeight(); 
1835     if ((m_currentEdit
->IsExpanded()) && (m_currentEdit
->GetSelectedImage() != -1)) 
1837         m_imageListNormal
->GetSize( m_currentEdit
->GetSelectedImage(), image_w
, image_h 
); 
1840     else if (m_currentEdit
->GetImage() != -1) 
1842         m_imageListNormal
->GetSize( m_currentEdit
->GetImage(), image_w
, image_h 
); 
1846     w 
-= image_w 
+ 4; // I don't know why +4 is needed 
1848     wxClientDC 
dc(this); 
1850     x 
= dc
.LogicalToDeviceX( x 
); 
1851     y 
= dc
.LogicalToDeviceY( y 
); 
1853     wxTreeTextCtrl 
*text 
= new wxTreeTextCtrl( 
1854       this, -1, &m_renameAccept
, &m_renameRes
, this, s
, wxPoint(x
-4,y
-4), wxSize(w
+11,h
+8) ); 
1858 void wxTreeCtrl::OnRenameTimer() 
1863 void wxTreeCtrl::OnRenameAccept() 
1865     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, GetId() ); 
1866     le
.m_item 
= m_currentEdit
; 
1867     le
.SetEventObject( this ); 
1868     le
.m_label 
= m_renameRes
; 
1869     GetEventHandler()->ProcessEvent( le 
); 
1871     if (!le
.IsAllowed()) return; 
1873     SetItemText( m_currentEdit
, m_renameRes 
); 
1876 void wxTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
1878     if ( !(event
.LeftUp() || event
.LeftDClick() || event
.Dragging()) ) return; 
1880     if ( !m_anchor 
) return; 
1882     wxClientDC 
dc(this); 
1884     long x 
= dc
.DeviceToLogicalX( (long)event
.GetX() ); 
1885     long y 
= dc
.DeviceToLogicalY( (long)event
.GetY() ); 
1888     wxGenericTreeItem 
*item 
= m_anchor
->HitTest( wxPoint(x
,y
), this, flags
); 
1889     bool onButton 
= flags 
& wxTREE_HITTEST_ONITEMBUTTON
; 
1891     if (event
.Dragging()) 
1893         if (m_dragCount 
== 0) 
1894             m_dragStart 
= wxPoint(x
,y
); 
1898         if (m_dragCount 
!= 3) return; 
1900         int command 
= wxEVT_COMMAND_TREE_BEGIN_DRAG
; 
1901         if (event
.RightIsDown()) command 
= wxEVT_COMMAND_TREE_BEGIN_RDRAG
; 
1903         wxTreeEvent 
nevent( command
, GetId() ); 
1904         nevent
.m_item 
= m_current
; 
1905         nevent
.SetEventObject(this); 
1906         GetEventHandler()->ProcessEvent(nevent
); 
1914     if (item 
== NULL
) return;  /* we hit the blank area */ 
1916     if (event
.LeftUp() && (item 
== m_current
) && 
1917         (flags 
& wxTREE_HITTEST_ONITEMLABEL
) && 
1918         HasFlag(wxTR_EDIT_LABELS
) ) 
1920         m_renameTimer
->Start( 100, TRUE 
); 
1924     bool is_multiple
=(GetWindowStyleFlag() & wxTR_MULTIPLE
); 
1925     bool extended_select
=(event
.ShiftDown() && is_multiple
); 
1926     bool unselect_others
=!(extended_select 
|| (event
.ControlDown() && is_multiple
)); 
1935     SelectItem(item
, unselect_others
, extended_select
); 
1937     if (event
.LeftDClick()) 
1939         wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, GetId() ); 
1940         event
.m_item 
= item
; 
1942         event
.SetEventObject( this ); 
1943         GetEventHandler()->ProcessEvent( event 
); 
1947 void wxTreeCtrl::OnIdle( wxIdleEvent 
&WXUNUSED(event
) ) 
1949     /* after all changes have been done to the tree control, 
1950      * we actually redraw the tree when everything is over */ 
1957     CalculatePositions(); 
1959     AdjustMyScrollbars(); 
1962 void wxTreeCtrl::CalculateSize( wxGenericTreeItem 
*item
, wxDC 
&dc 
) 
1971         fontOld 
= dc
.GetFont(); 
1974           // VZ: is there any better way to make a bold variant of old font? 
1975           fontNew 
= wxFont( fontOld
.GetPointSize(), 
1976                             fontOld
.GetFamily(), 
1979                             fontOld
.GetUnderlined()); 
1980           dc
.SetFont(fontNew
); 
1984             wxFAIL_MSG(_T("wxDC::GetFont() failed!")); 
1988     dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
1991     // restore normal font for bold items 
1993         dc
.SetFont( fontOld
); 
1997     if ((item
->IsExpanded()) && (item
->GetSelectedImage() != -1)) 
1999         m_imageListNormal
->GetSize( item
->GetSelectedImage(), image_w
, image_h 
); 
2002     else if (item
->GetImage() != -1) 
2004         m_imageListNormal
->GetSize( item
->GetImage(), image_w
, image_h 
); 
2008     int total_h 
= (image_h 
> text_h
) ? image_h 
: text_h
; 
2010     if (total_h
<40) total_h
+=4; // at least 4 pixels 
2011     else total_h
+=total_h
/10;   // otherwise 10% extra spacing 
2013     item
->SetHeight(total_h
); 
2014     if (total_h
>m_lineHeight
) m_lineHeight
=total_h
; 
2016     item
->SetWidth(image_w
+text_w
+2); 
2019 // ----------------------------------------------------------------------------- 
2020 // for developper : y is now the top of the level 
2021 // not the middle of it ! 
2022 void wxTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
2024     int horizX 
= level
*m_indent
; 
2026     CalculateSize( item
, dc 
); 
2029     item
->SetX( horizX
+m_indent
+m_spacing 
); 
2031     y
+=GetLineHeight(item
); 
2033     if ( !item
->IsExpanded() ) 
2035         // we dont need to calculate collapsed branches 
2039     wxArrayGenericTreeItems
& children 
= item
->GetChildren(); 
2040     size_t n
, count 
= children
.Count(); 
2041     for (n 
= 0; n 
< count
; ++n 
) 
2042       CalculateLevel( children
[n
], dc
, level
+1, y 
);  // recurse 
2045 void wxTreeCtrl::CalculatePositions() 
2047     if ( !m_anchor 
) return; 
2049     wxClientDC 
dc(this); 
2052     dc
.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT 
) ); 
2054     dc
.SetPen( m_dottedPen 
); 
2055     //if(GetImageList() == NULL) 
2056     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
2059     CalculateLevel( m_anchor
, dc
, 0, y 
); // start recursion 
2062 void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
2064     wxClientDC 
dc(this); 
2069     GetClientSize( &cw
, &ch 
); 
2072     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
2074     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
2077     Refresh( TRUE
, &rect 
); 
2079     AdjustMyScrollbars(); 
2082 void wxTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
2084     wxClientDC 
dc(this); 
2089     GetClientSize( &cw
, &ch 
); 
2092     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
2093     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
2095     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
2097     Refresh( TRUE
, &rect 
);