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 #include "wx/treectrl.h" 
  25 #include "wx/settings.h" 
  28 #include "wx/dynarray.h" 
  29 #include "wx/dcclient.h" 
  30 #include "wx/imaglist.h" 
  32 // ----------------------------------------------------------------------------- 
  34 // ----------------------------------------------------------------------------- 
  36 WX_DEFINE_ARRAY(wxGenericTreeItem 
*, wxArrayTreeItems
); 
  38 // ----------------------------------------------------------------------------- 
  40 // ----------------------------------------------------------------------------- 
  43 class WXDLLEXPORT wxGenericTreeItem
 
  47   wxGenericTreeItem() { m_data 
= NULL
; } 
  48   wxGenericTreeItem( wxGenericTreeItem 
*parent
, 
  51                      int image
, int selImage
, 
  52                      wxTreeItemData 
*data 
); 
  57   wxArrayTreeItems
& GetChildren() { return m_children
; } 
  59   const wxString
& GetText() const { return m_text
; } 
  60   int GetImage() const { return m_image
; } 
  61   int GetSelectedImage() const { return m_selImage
; } 
  62   wxTreeItemData 
*GetData() const { return m_data
; } 
  64   void SetText( const wxString 
&text
, wxDC
& dc 
); 
  65   void SetImage(int image
) { m_image 
= image
; } 
  66   void SetSelectedImage(int image
) { m_selImage 
= image
; } 
  67   void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
  69   void SetHasPlus(bool has 
= TRUE
) { m_hasPlus 
= has
; } 
  71   void SetBold(bool bold
) { m_isBold 
= bold
; } 
  73   int GetX() const { return m_x
; } 
  74   int GetY() const { return m_y
; } 
  76   void SetHeight(int h
) { m_height 
= h
; } 
  78   void SetX(int x
) { m_x 
= x
; } 
  79   void SetY(int y
) { m_y 
= y
; } 
  81   wxGenericTreeItem 
*GetParent() const { return m_parent
; } 
  86   // get count of all children (and grand children if 'recursively') 
  87   size_t GetChildrenCount(bool recursively 
= TRUE
) const; 
  89   void Insert(wxGenericTreeItem 
*child
, size_t index
) 
  90     { m_children
.Insert(child
, index
); } 
  92   void SetCross( int x
, int y 
); 
  93   void GetSize( int &x
, int &y 
); 
  95   // return the item at given position (or NULL if no item), onButton is TRUE 
  96   // if the point belongs to the item's button, otherwise it lies on the 
  98   wxGenericTreeItem 
*HitTest( const wxPoint
& point
, bool &onButton 
); 
 100   void Expand() { m_isCollapsed 
= FALSE
; } 
 101   void Collapse() { m_isCollapsed 
= TRUE
; } 
 103   void SetHilight( bool set 
= TRUE 
) { m_hasHilight 
= set
; } 
 106   bool HasChildren() const { return !m_children
.IsEmpty(); } 
 107   bool HasHilight()  const { return m_hasHilight
; } 
 108   bool IsExpanded()  const { return !m_isCollapsed
; } 
 109   bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 110   bool IsBold()      const { return m_isBold
; } 
 118   wxTreeItemData     
*m_data
; 
 120   // use bitfields to save size 
 121   int                 m_isCollapsed 
:1; 
 122   int                 m_hasHilight  
:1; // same as focused 
 123   int                 m_hasPlus     
:1; // used for item which doesn't have 
 124                                         // children but still has a [+] button 
 125   int                 m_isBold      
:1; // render the label in bold font 
 128   long                m_height
, m_width
; 
 129   int                 m_xCross
, m_yCross
; 
 131   wxArrayTreeItems    m_children
; 
 132   wxGenericTreeItem  
*m_parent
; 
 135 // ============================================================================= 
 137 // ============================================================================= 
 139 // ----------------------------------------------------------------------------- 
 141 // ----------------------------------------------------------------------------- 
 143 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent
, wxCommandEvent
) 
 145 wxTreeEvent::wxTreeEvent( wxEventType commandType
, int id 
) 
 146            : wxCommandEvent( commandType
, id 
) 
 149   m_itemOld 
= (wxGenericTreeItem 
*)NULL
; 
 152 // ----------------------------------------------------------------------------- 
 154 // ----------------------------------------------------------------------------- 
 156 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem 
*parent
, 
 157                                      const wxString
& text
, 
 159                                      int image
, int selImage
, 
 160                                      wxTreeItemData 
*data
) 
 164   m_selImage 
= selImage
; 
 167   m_xCross 
= m_yCross 
= 0; 
 171   m_isCollapsed 
= TRUE
; 
 172   m_hasHilight 
= FALSE
; 
 178   dc
.GetTextExtent( m_text
, &m_width
, &m_height 
); 
 181 wxGenericTreeItem::~wxGenericTreeItem() 
 185   size_t count 
= m_children
.Count(); 
 186   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 187     delete m_children
[n
]; 
 190 void wxGenericTreeItem::SetText( const wxString 
&text
, wxDC
& dc 
) 
 194   dc
.GetTextExtent( m_text
, &m_width
, &m_height 
); 
 197 void wxGenericTreeItem::Reset() 
 204   m_height 
= m_width 
= 0; 
 211   m_isCollapsed 
= TRUE
; 
 213   m_parent 
= (wxGenericTreeItem 
*)NULL
; 
 216 size_t wxGenericTreeItem::GetChildrenCount(bool recursively
) const 
 218   size_t count 
= m_children
.Count(); 
 222   size_t total 
= count
; 
 223   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 225     total 
+= m_children
[n
]->GetChildrenCount(); 
 231 void wxGenericTreeItem::SetCross( int x
, int y 
) 
 237 void wxGenericTreeItem::GetSize( int &x
, int &y 
) 
 239   if ( y 
< m_y 
) y 
= m_y
; 
 240   int width 
= m_x 
+  m_width
; 
 241   if (width 
> x
) x 
= width
; 
 245     size_t count 
= m_children
.Count(); 
 246     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 248       m_children
[n
]->GetSize( x
, y 
); 
 253 wxGenericTreeItem 
*wxGenericTreeItem::HitTest( const wxPoint
& point
, 
 256   if ((point
.y 
> m_y
) && (point
.y 
< m_y 
+ m_height
)) 
 259     if ((point
.x 
> m_xCross
-5) && (point
.x 
< m_xCross
+5) && 
 260         (point
.y 
> m_yCross
-5) && (point
.y 
< m_yCross
+5) && 
 261         (IsExpanded() || HasPlus())) 
 267     if ((point
.x 
> m_x
) && (point
.x 
< m_x
+m_width
)) 
 277       size_t count 
= m_children
.Count(); 
 278       for ( size_t n 
= 0; n 
< count
; n
++ ) 
 280         wxGenericTreeItem 
*res 
= m_children
[n
]->HitTest( point
, onButton 
); 
 290 // ----------------------------------------------------------------------------- 
 291 // wxTreeCtrl implementation 
 292 // ----------------------------------------------------------------------------- 
 294 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxScrolledWindow
) 
 296 BEGIN_EVENT_TABLE(wxTreeCtrl
,wxScrolledWindow
) 
 297   EVT_PAINT          (wxTreeCtrl::OnPaint
) 
 298   EVT_MOUSE_EVENTS   (wxTreeCtrl::OnMouse
) 
 299   EVT_CHAR           (wxTreeCtrl::OnChar
) 
 300   EVT_SET_FOCUS      (wxTreeCtrl::OnSetFocus
) 
 301   EVT_KILL_FOCUS     (wxTreeCtrl::OnKillFocus
) 
 302   EVT_IDLE           (wxTreeCtrl::OnIdle
) 
 305 // ----------------------------------------------------------------------------- 
 306 // construction/destruction 
 307 // ----------------------------------------------------------------------------- 
 308 void wxTreeCtrl::Init() 
 311   m_anchor 
= (wxGenericTreeItem 
*) NULL
; 
 320   m_hilightBrush 
= new wxBrush
 
 322       wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
), 
 327   m_imageListState 
= (wxImageList 
*) NULL
; 
 330 bool wxTreeCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 331                         const wxPoint
& pos
, const wxSize
& size
, 
 332                         long style
, const wxString
& name 
) 
 336   wxScrolledWindow::Create( parent
, id
, pos
, size
, style
|wxHSCROLL
|wxVSCROLL
, name 
); 
 338   SetBackgroundColour( *wxWHITE 
); 
 339   m_dottedPen 
= wxPen( *wxBLACK
, 0, 0 ); 
 344 wxTreeCtrl::~wxTreeCtrl() 
 346   wxDELETE( m_hilightBrush 
); 
 347   wxDELETE( m_anchor 
); 
 350 // ----------------------------------------------------------------------------- 
 352 // ----------------------------------------------------------------------------- 
 354 size_t wxTreeCtrl::GetCount() const 
 356   return m_anchor 
== NULL 
? 0u : m_anchor
->GetChildrenCount(); 
 359 void wxTreeCtrl::SetIndent(unsigned int indent
) 
 365 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
) 
 367   wxCHECK_MSG( item
.IsOk(), 0u, "invalid tree item" ); 
 369   return item
.m_pItem
->GetChildrenCount(recursively
); 
 372 // ----------------------------------------------------------------------------- 
 373 // functions to work with tree items 
 374 // ----------------------------------------------------------------------------- 
 376 wxString 
wxTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 378   wxCHECK_MSG( item
.IsOk(), "", "invalid tree item" ); 
 380   return item
.m_pItem
->GetText(); 
 383 int wxTreeCtrl::GetItemImage(const wxTreeItemId
& item
) const 
 385   wxCHECK_MSG( item
.IsOk(), -1, "invalid tree item" ); 
 387   return item
.m_pItem
->GetImage(); 
 390 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const 
 392   wxCHECK_MSG( item
.IsOk(), -1, "invalid tree item" ); 
 394   return item
.m_pItem
->GetSelectedImage(); 
 397 wxTreeItemData 
*wxTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
 399   wxCHECK_MSG( item
.IsOk(), NULL
, "invalid tree item" ); 
 401   return item
.m_pItem
->GetData(); 
 404 void wxTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 406   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 409   item
.m_pItem
->SetText(text
, dc
); 
 412 void wxTreeCtrl::SetItemImage(const wxTreeItemId
& item
, int image
) 
 414   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 416   item
.m_pItem
->SetImage(image
); 
 419 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
) 
 421   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 423   item
.m_pItem
->SetSelectedImage(image
); 
 426 void wxTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
 428   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 430   item
.m_pItem
->SetData(data
); 
 433 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
 435   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 437   item
.m_pItem
->SetHasPlus(has
); 
 440 void wxTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
 442   wxCHECK_RET( item
.IsOk(), "invalid tree item" ); 
 444   // avoid redrawing the tree if no real change 
 445   wxGenericTreeItem 
*pItem 
= item
.m_pItem
; 
 446   if ( pItem
->IsBold() != bold 
) 
 448     pItem
->SetBold(bold
); 
 453 // ----------------------------------------------------------------------------- 
 454 // item status inquiries 
 455 // ----------------------------------------------------------------------------- 
 457 bool wxTreeCtrl::IsVisible(const wxTreeItemId
& WXUNUSED(item
)) const 
 459   wxFAIL_MSG("not implemented"); 
 464 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
 466   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 468   return !item
.m_pItem
->GetChildren().IsEmpty(); 
 471 bool wxTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
 473   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 475   return item
.m_pItem
->IsExpanded(); 
 478 bool wxTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
 480   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 482   return item
.m_pItem
->HasHilight(); 
 485 bool wxTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
 487   wxCHECK_MSG( item
.IsOk(), FALSE
, "invalid tree item" ); 
 489   return item
.m_pItem
->IsBold(); 
 492 // ----------------------------------------------------------------------------- 
 494 // ----------------------------------------------------------------------------- 
 496 wxTreeItemId 
wxTreeCtrl::GetParent(const wxTreeItemId
& item
) const 
 498   wxCHECK_MSG( item
.IsOk(), NULL
, "invalid tree item" ); 
 500   return item
.m_pItem
->GetParent(); 
 503 wxTreeItemId 
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const 
 505   wxCHECK_MSG( item
.IsOk(), NULL
, "invalid tree item" ); 
 508   return GetNextChild(item
, cookie
); 
 511 wxTreeItemId 
wxTreeCtrl::GetNextChild(const wxTreeItemId
& item
, long& cookie
) const 
 513   wxCHECK_MSG( item
.IsOk(), NULL
, "invalid tree item" ); 
 515   wxArrayTreeItems
& children 
= item
.m_pItem
->GetChildren(); 
 516   if ( (size_t)cookie 
< children
.Count() ) 
 518     return item
.m_pItem
->GetChildren().Item(cookie
++); 
 522     // there are no more of them 
 527 wxTreeItemId 
wxTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
 529   wxCHECK_MSG( item
.IsOk(), NULL
, "invalid tree item" ); 
 531   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 532   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 533   if ( parent 
== NULL 
) 
 535     // root item doesn't have any siblings 
 539   wxArrayTreeItems
& siblings 
= parent
->GetChildren(); 
 540   int index 
= siblings
.Index(i
); 
 541   wxASSERT( index 
!= NOT_FOUND 
); // I'm not a child of my parent? 
 543   size_t n 
= (size_t)(index 
+ 1); 
 544   return n 
== siblings
.Count() ? (wxGenericTreeItem
*)NULL 
: siblings
[n
]; 
 547 wxTreeItemId 
wxTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
 549   wxCHECK_MSG( item
.IsOk(), NULL
, "invalid tree item" ); 
 551   wxGenericTreeItem 
*i 
= item
.m_pItem
; 
 552   wxGenericTreeItem 
*parent 
= i
->GetParent(); 
 553   if ( parent 
== NULL 
) 
 555     // root item doesn't have any siblings 
 559   wxArrayTreeItems
& siblings 
= parent
->GetChildren(); 
 560   int index 
= siblings
.Index(i
); 
 561   wxASSERT( index 
!= NOT_FOUND 
); // I'm not a child of my parent? 
 563   return index 
== 0 ? (wxGenericTreeItem
*)NULL 
: siblings
[(size_t)(index 
- 1)]; 
 566 wxTreeItemId 
wxTreeCtrl::GetFirstVisibleItem() const 
 568   wxFAIL_MSG("not implemented"); 
 573 wxTreeItemId 
wxTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
 575   wxCHECK_MSG( item
.IsOk(), NULL
, "invalid tree item" ); 
 577   wxFAIL_MSG("not implemented"); 
 582 wxTreeItemId 
wxTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
 584   wxCHECK_MSG( item
.IsOk(), NULL
, "invalid tree item" ); 
 586   wxFAIL_MSG("not implemented"); 
 591 // ----------------------------------------------------------------------------- 
 593 // ----------------------------------------------------------------------------- 
 595 wxTreeItemId 
wxTreeCtrl::DoInsertItem(const wxTreeItemId
& parentId
, 
 597                                       const wxString
& text
, 
 598                                       int image
, int selImage
, 
 599                                       wxTreeItemData 
*data
) 
 601   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 604     // should we give a warning here? 
 605     return AddRoot(text
, image
, selImage
, data
); 
 609   wxGenericTreeItem 
*item 
= new wxGenericTreeItem(parent
, 
 616     data
->m_pItem 
= item
; 
 619   parent
->Insert( item
, previous 
); 
 626 wxTreeItemId 
wxTreeCtrl::AddRoot(const wxString
& text
, 
 627                                  int image
, int selImage
, 
 628                                  wxTreeItemData 
*data
) 
 630   wxCHECK_MSG( !m_anchor
, NULL
, "tree can have only one root" ); 
 633   m_anchor 
= new wxGenericTreeItem((wxGenericTreeItem 
*)NULL
, text
, dc
, 
 634                                    image
, selImage
, data
); 
 637     data
->m_pItem 
= m_anchor
; 
 640   AdjustMyScrollbars(); 
 646 wxTreeItemId 
wxTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
 647                                      const wxString
& text
, 
 648                                      int image
, int selImage
, 
 649                                      wxTreeItemData 
*data
) 
 651   return DoInsertItem(parent
, 0u, text
, image
, selImage
, data
); 
 654 wxTreeItemId 
wxTreeCtrl::InsertItem(const wxTreeItemId
& parentId
, 
 655                                     const wxTreeItemId
& idPrevious
, 
 656                                     const wxString
& text
, 
 657                                     int image
, int selImage
, 
 658                                     wxTreeItemData 
*data
) 
 660   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 663     // should we give a warning here? 
 664     return AddRoot(text
, image
, selImage
, data
); 
 667   int index 
= parent
->GetChildren().Index(idPrevious
.m_pItem
); 
 668   wxASSERT_MSG( index 
!= NOT_FOUND
, 
 669                 "previous item in wxTreeCtrl::InsertItem() is not a sibling" ); 
 670   return DoInsertItem(parentId
, (size_t)index
, text
, image
, selImage
, data
); 
 673 wxTreeItemId 
wxTreeCtrl::AppendItem(const wxTreeItemId
& parentId
, 
 674                                     const wxString
& text
, 
 675                                     int image
, int selImage
, 
 676                                     wxTreeItemData 
*data
) 
 678   wxGenericTreeItem 
*parent 
= parentId
.m_pItem
; 
 681     // should we give a warning here? 
 682     return AddRoot(text
, image
, selImage
, data
); 
 685   return DoInsertItem(parent
, parent
->GetChildren().Count(), text
, 
 686                       image
, selImage
, data
); 
 689 void wxTreeCtrl::Delete(const wxTreeItemId
& itemId
) 
 691   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 692   wxGenericTreeItem 
*parent 
= item
->GetParent(); 
 696     parent
->GetChildren().Remove(item
); 
 704 void wxTreeCtrl::DeleteAllItems() 
 715 void wxTreeCtrl::Expand(const wxTreeItemId
& itemId
) 
 717   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 719   if ( item
->IsExpanded() ) 
 722   wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_EXPANDING
, GetId() ); 
 724   event
.SetEventObject( this ); 
 725   if ( ProcessEvent( event 
) && event
.m_code 
) 
 727     // cancelled by program 
 733   RefreshSubtree(item
); 
 735   event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
 736   ProcessEvent( event 
); 
 739 void wxTreeCtrl::Collapse(const wxTreeItemId
& itemId
) 
 741   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 743   if ( !item
->IsExpanded() ) 
 746   wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, GetId() ); 
 748   event
.SetEventObject( this ); 
 749   if ( ProcessEvent( event 
) && event
.m_code 
) 
 751     // cancelled by program 
 757   wxArrayTreeItems
& children 
= item
->GetChildren(); 
 758   size_t count 
= children
.Count(); 
 759   for ( size_t n 
= 0; n 
< count
; n
++ ) 
 761     Collapse(children
[n
]); 
 764   CalculatePositions(); 
 766   RefreshSubtree(item
); 
 768   event
.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
 769   ProcessEvent( event 
); 
 772 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
 778 void wxTreeCtrl::Toggle(const wxTreeItemId
& itemId
) 
 780   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 782   if ( item
->IsExpanded() ) 
 788 void wxTreeCtrl::Unselect() 
 792     m_current
->SetHilight( FALSE 
); 
 793     RefreshLine( m_current 
); 
 797 void wxTreeCtrl::SelectItem(const wxTreeItemId
& itemId
) 
 799   wxGenericTreeItem 
*item 
= itemId
.m_pItem
; 
 801   if ( m_current 
!= item 
) 
 803     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, GetId() ); 
 805     event
.m_itemOld 
= m_current
; 
 806     event
.SetEventObject( this ); 
 807     if ( GetEventHandler()->ProcessEvent( event 
) && event
.WasVetoed() ) 
 812       m_current
->SetHilight( FALSE 
); 
 813       RefreshLine( m_current 
); 
 817     m_current
->SetHilight( TRUE 
); 
 818     RefreshLine( m_current 
); 
 820     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
 821     GetEventHandler()->ProcessEvent( event 
); 
 825 void wxTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
 827   wxGenericTreeItem 
*gitem 
= item
.m_pItem
; 
 829   int item_y 
= gitem
->GetY(); 
 833   ViewStart( &start_x
, &start_y 
); 
 836   if (item_y 
< start_y
+3) 
 840     m_anchor
->GetSize( x
, y 
); 
 842     int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
 843     SetScrollbars( 10, 10, x
/10, y
/10, x_pos
, item_y
/10 ); 
 849   GetClientSize( &w
, &h 
); 
 851   if (item_y 
> start_y
+h
-26) 
 855     m_anchor
->GetSize( x
, y 
); 
 857     int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
 858     SetScrollbars( 10, 10, x
/10, y
/10, x_pos
, (item_y
-h
+30)/10 ); 
 863 void wxTreeCtrl::ScrollTo(const wxTreeItemId
& WXUNUSED(item
)) 
 865   wxFAIL_MSG("not implemented"); 
 868 wxTextCtrl 
*wxTreeCtrl::EditLabel( const wxTreeItemId
& WXUNUSED(item
), 
 869                                    wxClassInfo
* WXUNUSED(textCtrlClass
) ) 
 871   wxFAIL_MSG("not implemented"); 
 876 wxTextCtrl 
*wxTreeCtrl::GetEditControl() const 
 878   wxFAIL_MSG("not implemented"); 
 883 void wxTreeCtrl::EndEditLabel(const wxTreeItemId
& WXUNUSED(item
), bool WXUNUSED(discardChanges
)) 
 885   wxFAIL_MSG("not implemented"); 
 888 void wxTreeCtrl::SortChildren( const wxTreeItemId
& WXUNUSED(item
), 
 889                                wxTreeItemCmpFunc 
*WXUNUSED(cmpFunction
)) 
 891   wxFAIL_MSG("not implemented"); 
 894 wxImageList 
*wxTreeCtrl::GetImageList() const 
 896     return m_imageListNormal
; 
 899 wxImageList 
*wxTreeCtrl::GetStateImageList() const 
 901     return m_imageListState
; 
 904 void wxTreeCtrl::SetImageList(wxImageList 
*imageList
) 
 906     m_imageListNormal 
= imageList
; 
 909 void wxTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
 911     m_imageListState 
= imageList
; 
 914 // ----------------------------------------------------------------------------- 
 916 // ----------------------------------------------------------------------------- 
 917 void wxTreeCtrl::AdjustMyScrollbars() 
 923     m_anchor
->GetSize( x
, y 
); 
 925     int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
 926     int y_pos 
= GetScrollPos( wxVERTICAL 
); 
 927     SetScrollbars( 10, 10, x
/10, y
/10, x_pos
, y_pos 
); 
 931     SetScrollbars( 0, 0, 0, 0 ); 
 935 void wxTreeCtrl::PaintItem(wxGenericTreeItem 
*item
, wxDC
& dc
) 
 937   // render bold items in bold 
 938   wxFont 
*fontOld 
= (wxFont 
*)NULL
, 
 939          *fontNew 
= (wxFont 
*)NULL
; 
 940   if ( item
->IsBold() ) 
 942       fontOld 
= dc
.GetFont(); 
 945         // @@ is there any better way to make a bold variant of old font? 
 946         fontNew 
= new wxFont(fontOld
->GetPointSize(), 
 947                              fontOld
->GetFamily(), 
 950                              fontOld
->GetUnderlined()); 
 955         wxFAIL_MSG("wxDC::GetFont() failed!"); 
 961   dc
.GetTextExtent( item
->GetText(), &text_w
, &text_h 
); 
 965   if (item
->GetImage() != -1) 
 967     m_imageListNormal
->GetSize( item
->GetImage(), image_w
, image_h 
); 
 971   dc
.DrawRectangle( item
->GetX()-2, item
->GetY()-2, image_w
+text_w
+4, text_h
+4 ); 
 973   if (item
->GetImage() != -1) 
 975     dc
.SetClippingRegion( item
->GetX(), item
->GetY(), image_w
-2, text_h 
); 
 976     m_imageListNormal
->Draw( item
->GetImage(), dc
, 
 977                              item
->GetX(), item
->GetY()-1, 
 978                              wxIMAGELIST_DRAW_TRANSPARENT 
); 
 979     dc
.DestroyClippingRegion(); 
 982   dc
.DrawText( item
->GetText(), image_w 
+ item
->GetX(), item
->GetY() ); 
 984   // restore normal font for bold items 
 992 void wxTreeCtrl::PaintLevel( wxGenericTreeItem 
*item
, wxDC 
&dc
, int level
, int &y 
) 
 994   int horizX 
= level
*m_indent
; 
 996   item
->SetX( horizX
+33 ); 
 997   item
->SetY( y
-m_lineHeight
/3 ); 
 998   item
->SetHeight( m_lineHeight 
); 
1000   item
->SetCross( horizX
+15, y 
); 
1004   int exposed_x 
= dc
.LogicalToDeviceX( 0 ); 
1005   int exposed_y 
= dc
.LogicalToDeviceY( item
->GetY()-2 ); 
1007   if (IsExposed( exposed_x
, exposed_y
, 10000, m_lineHeight
+4 ))  // 10000 = very much 
1009     int startX 
= horizX
; 
1010     int endX 
= horizX 
+ 10; 
1012     if (!item
->HasChildren()) endX 
+= 20; 
1014     dc
.DrawLine( startX
, y
, endX
, y 
); 
1016     if (item
->HasPlus()) 
1018       dc
.DrawLine( horizX
+20, y
, horizX
+30, y 
); 
1019       dc
.SetPen( *wxGREY_PEN 
); 
1020       dc
.DrawRectangle( horizX
+10, y
-4, 11, 9 ); 
1021       dc
.SetPen( *wxBLACK_PEN 
); 
1022       dc
.DrawLine( horizX
+13, y
, horizX
+18, y 
); 
1024       if (!item
->IsExpanded()) 
1025         dc
.DrawLine( horizX
+15, y
-2, horizX
+15, y
+3 ); 
1028     if (item
->HasHilight()) 
1030       dc
.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
) ); 
1032       dc
.SetBrush( *m_hilightBrush 
); 
1035         dc
.SetPen( *wxBLACK_PEN 
); 
1037         dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1039       PaintItem(item
, dc
); 
1041       dc
.SetPen( *wxBLACK_PEN 
); 
1042       dc
.SetTextForeground( *wxBLACK 
); 
1043       dc
.SetBrush( *wxWHITE_BRUSH 
); 
1047       dc
.SetBrush( *wxWHITE_BRUSH 
); 
1048       dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1050       PaintItem(item
, dc
); 
1052       dc
.SetPen( *wxBLACK_PEN 
); 
1056   if ( !item
->IsExpanded() ) 
1061   wxArrayTreeItems
& children 
= item
->GetChildren(); 
1062   size_t count 
= children
.Count(); 
1063   for ( size_t n 
= 0; n 
< count
; n
++ ) 
1068     PaintLevel( children
[n
], dc
, level
+1, y 
); 
1071   dc
.DrawLine( horizX
+15, oldY
+5, horizX
+15, semiOldY 
); 
1074 // ----------------------------------------------------------------------------- 
1075 // wxWindows callbacks 
1076 // ----------------------------------------------------------------------------- 
1078 void wxTreeCtrl::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1086   dc
.SetFont( wxSystemSettings::GetSystemFont( wxSYS_SYSTEM_FONT 
) ); 
1088   dc
.SetPen( m_dottedPen 
); 
1089   m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1091   int y 
= m_lineHeight 
/ 2 + 2; 
1092   PaintLevel( m_anchor
, dc
, 0, y 
); 
1095 void wxTreeCtrl::OnSetFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1099     RefreshLine( m_current 
); 
1102 void wxTreeCtrl::OnKillFocus( wxFocusEvent 
&WXUNUSED(event
) ) 
1106     RefreshLine( m_current 
); 
1109 void wxTreeCtrl::OnChar( wxKeyEvent 
&event 
) 
1117   switch (event
.KeyCode()) 
1121       if (HasChildren(m_current
) && !IsExpanded(m_current
)) 
1129       if (IsExpanded(m_current
)) 
1131         Collapse(m_current
); 
1143         wxTreeEvent 
event( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
1144         event
.m_item 
= m_current
; 
1146         event
.SetEventObject( this ); 
1147         GetEventHandler()->ProcessEvent( event 
); 
1154         wxTreeItemId prev 
= GetPrevSibling( m_current 
); 
1158           EnsureVisible( prev 
); 
1162           prev 
= GetParent( m_current 
); 
1165             EnsureVisible( prev 
); 
1173       // this works the same as the down arrow except that we also expand the 
1174       // item if it wasn't expanded yet 
1180         if (IsExpanded(m_current
)) 
1183           wxTreeItemId child 
= GetFirstChild( m_current
, cookie 
); 
1184           SelectItem( child 
); 
1185           EnsureVisible( child 
); 
1189           wxTreeItemId next 
= GetNextSibling( m_current 
); 
1192             wxTreeItemId current 
= m_current
; 
1193             while (current 
&& !next
) 
1195               current 
= GetParent( current 
); 
1196               if (current
) next 
= GetNextSibling( current 
); 
1202             EnsureVisible( next 
); 
1213 void wxTreeCtrl::OnMouse( wxMouseEvent 
&event 
) 
1215   if ( !(event
.LeftDown() || event
.LeftDClick()) ) 
1221   wxClientDC 
dc(this); 
1223   long x 
= dc
.DeviceToLogicalX( (long)event
.GetX() ); 
1224   long y 
= dc
.DeviceToLogicalY( (long)event
.GetY() ); 
1226   bool onButton 
= FALSE
; 
1227   wxGenericTreeItem 
*item 
= m_anchor
->HitTest( wxPoint(x
,y
), onButton 
); 
1231   if (!IsSelected(item
)) SelectItem(item
); 
1233   if ( event
.LeftDClick() ) 
1235     wxTreeEvent 
event( wxEVT_COMMAND_TREE_KEY_DOWN
, GetId() ); 
1236     event
.m_item 
= item
; 
1238     event
.SetEventObject( this ); 
1239     GetEventHandler()->ProcessEvent( event 
); 
1248 void wxTreeCtrl::OnIdle( wxIdleEvent 
&WXUNUSED(event
) ) 
1250   if (!m_dirty
) return; 
1254   CalculatePositions(); 
1256   AdjustMyScrollbars(); 
1259 // ----------------------------------------------------------------------------- 
1260 // ----------------------------------------------------------------------------- 
1261 void wxTreeCtrl::CalculateLevel( wxGenericTreeItem 
*item
, 
1266   int horizX 
= level
*m_indent
; 
1268   item
->SetX( horizX
+33 ); 
1269   item
->SetY( y
-m_lineHeight
/3-2 ); 
1270   item
->SetHeight( m_lineHeight 
); 
1272   if ( item
->IsExpanded() ) 
1275   wxArrayTreeItems
& children 
= item
->GetChildren(); 
1276   size_t count 
= children
.Count(); 
1277   for ( size_t n 
= 0; n 
< count
; n
++ ) 
1280     CalculateLevel( children
[n
], dc
, level
+1, y 
); 
1284 void wxTreeCtrl::CalculatePositions() 
1289   wxClientDC 
dc(this); 
1292   dc
.SetFont( wxSystemSettings::GetSystemFont( wxSYS_SYSTEM_FONT 
) ); 
1294   dc
.SetPen( m_dottedPen 
); 
1295   m_lineHeight 
= (int)(dc
.GetCharHeight() + 4); 
1297   int y 
= m_lineHeight 
/ 2 + 2; 
1298   CalculateLevel( m_anchor
, dc
, 0, y 
); 
1301 void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem 
*item
) 
1303   wxClientDC 
dc(this); 
1308   GetClientSize( &cw
, &ch 
); 
1311   rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
1313   rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
1316   Refresh( TRUE
, &rect 
); 
1318   AdjustMyScrollbars(); 
1321 void wxTreeCtrl::RefreshLine( wxGenericTreeItem 
*item 
) 
1323   wxClientDC 
dc(this); 
1327   rect
.x 
= dc
.LogicalToDeviceX( item
->GetX() - 2 ); 
1328   rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() - 2 ); 
1330   rect
.height 
= dc
.GetCharHeight() + 6; 
1331   Refresh( TRUE
, &rect 
);