1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        treelistctrl.cpp 
   3 // Purpose:     multi column tree control implementation 
   4 // Author:      Robert Roebling 
   5 // Maintainer:  Otto Wyss 
   8 // Copyright:   (c) 2004 Robert Roebling, Julian Smart, Alberto Griggio, 
   9 //              Vadim Zeitlin, Otto Wyss 
  11 ///////////////////////////////////////////////////////////////////////////// 
  13 // =========================================================================== 
  15 // =========================================================================== 
  17 // --------------------------------------------------------------------------- 
  19 // --------------------------------------------------------------------------- 
  21 // For compilers that support precompilation, includes "wx.h". 
  22 #include "wx/wxprec.h" 
  29 #include <wx/treebase.h> 
  31 #include <wx/textctrl.h> 
  32 #include <wx/imaglist.h> 
  33 #include <wx/settings.h> 
  34 #include <wx/dcclient.h> 
  35 #include <wx/dcscreen.h> 
  36 #include <wx/scrolwin.h> 
  37 #if wxCHECK_VERSION(2, 7, 0) 
  38 #include <wx/renderer.h> 
  42 #include "wx/mac/private.h" 
  45 #include "wx/treelistctrl.h" 
  48 // --------------------------------------------------------------------------- 
  50 // --------------------------------------------------------------------------- 
  54 #if !wxCHECK_VERSION(2, 5, 0) 
  55 WX_DEFINE_ARRAY(wxTreeListItem 
*, wxArrayTreeListItems
); 
  57 WX_DEFINE_ARRAY_PTR(wxTreeListItem 
*, wxArrayTreeListItems
); 
  60 #include <wx/dynarray.h> 
  61 WX_DECLARE_OBJARRAY(wxTreeListColumnInfo
, wxArrayTreeListColumnInfo
); 
  62 #include <wx/arrimpl.cpp> 
  63 WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo
); 
  66 // -------------------------------------------------------------------------- 
  68 // -------------------------------------------------------------------------- 
  70 static const int NO_IMAGE 
= -1; 
  72 static const int LINEHEIGHT 
= 10; 
  73 static const int LINEATROOT 
= 5; 
  74 static const int MARGIN 
= 2; 
  75 static const int MININDENT 
= 16; 
  76 static const int BTNWIDTH 
= 9; 
  77 static const int BTNHEIGHT 
= 9; 
  78 static const int EXTRA_WIDTH 
= 4; 
  79 static const int EXTRA_HEIGHT 
= 4; 
  80 static const int HEADER_OFFSET_X 
= 1; 
  81 static const int HEADER_OFFSET_Y 
= 1; 
  83 static const int DRAG_TIMER_TICKS 
= 250; // minimum drag wait time in ms 
  84 static const int FIND_TIMER_TICKS 
= 500; // minimum find wait time in ms 
  85 static const int RENAME_TIMER_TICKS 
= 250; // minimum rename wait time in ms 
  87 const wxChar
* wxTreeListCtrlNameStr 
= _T("treelistctrl"); 
  89 static wxTreeListColumnInfo wxInvalidTreeListColumnInfo
; 
  92 // --------------------------------------------------------------------------- 
  94 // --------------------------------------------------------------------------- 
  95 //----------------------------------------------------------------------------- 
  96 //  wxTreeListHeaderWindow (internal) 
  97 //----------------------------------------------------------------------------- 
  99 class  wxTreeListHeaderWindow 
: public wxWindow
 
 102     wxTreeListMainWindow 
*m_owner
; 
 103     const wxCursor 
*m_currentCursor
; 
 104     const wxCursor 
*m_resizeCursor
; 
 107     // column being resized 
 110     // divider line position in logical (unscrolled) coords 
 113     // minimal position beyond which the divider line can't be dragged in 
 117     wxArrayTreeListColumnInfo m_columns
; 
 119     // total width of the columns 
 120     int m_total_col_width
; 
 122 #if wxCHECK_VERSION_FULL(2, 7, 0, 1) 
 123     // which col header is currently highlighted with mouse-over 
 127     void RefreshColLabel(int col
); 
 131     wxTreeListHeaderWindow(); 
 133     wxTreeListHeaderWindow( wxWindow 
*win
, 
 135                             wxTreeListMainWindow 
*owner
, 
 136                             const wxPoint 
&pos 
= wxDefaultPosition
, 
 137                             const wxSize 
&size 
= wxDefaultSize
, 
 139                             const wxString 
&name 
= _T("wxtreelistctrlcolumntitles") ); 
 141     virtual ~wxTreeListHeaderWindow(); 
 143     void DoDrawRect( wxDC 
*dc
, int x
, int y
, int w
, int h 
); 
 145     void AdjustDC(wxDC
& dc
); 
 147     void OnPaint( wxPaintEvent 
&event 
); 
 148     void OnMouse( wxMouseEvent 
&event 
); 
 149     void OnSetFocus( wxFocusEvent 
&event 
); 
 151     // total width of all columns 
 152     int GetWidth() const { return m_total_col_width
; } 
 154     // column manipulation 
 155     int GetColumnCount() const { return m_columns
.GetCount(); } 
 157     void AddColumn (const wxTreeListColumnInfo
& colInfo
); 
 159     void InsertColumn (int before
, const wxTreeListColumnInfo
& colInfo
); 
 161     void RemoveColumn (int column
); 
 163     // column information manipulation 
 164     const wxTreeListColumnInfo
& GetColumn (int column
) const{ 
 165         wxCHECK_MSG ((column 
>= 0) && (column 
< GetColumnCount()), 
 166                      wxInvalidTreeListColumnInfo
, _T("Invalid column")); 
 167         return m_columns
[column
]; 
 169     wxTreeListColumnInfo
& GetColumn (int column
) { 
 170         wxCHECK_MSG ((column 
>= 0) && (column 
< GetColumnCount()), 
 171                      wxInvalidTreeListColumnInfo
, _T("Invalid column")); 
 172         return m_columns
[column
]; 
 174     void SetColumn (int column
, const wxTreeListColumnInfo
& info
); 
 176     wxString 
GetColumnText (int column
) const { 
 177         wxCHECK_MSG ((column 
>= 0) && (column 
< GetColumnCount()), 
 178                      wxEmptyString
, _T("Invalid column")); 
 179         return m_columns
[column
].GetText(); 
 181     void SetColumnText (int column
, const wxString
& text
) { 
 182         wxCHECK_RET ((column 
>= 0) && (column 
< GetColumnCount()), 
 183                      _T("Invalid column")); 
 184         m_columns
[column
].SetText (text
); 
 187     int GetColumnAlignment (int column
) const { 
 188         wxCHECK_MSG ((column 
>= 0) && (column 
< GetColumnCount()), 
 189                      wxALIGN_LEFT
, _T("Invalid column")); 
 190         return m_columns
[column
].GetAlignment(); 
 192     void SetColumnAlignment (int column
, int flag
) { 
 193         wxCHECK_RET ((column 
>= 0) && (column 
< GetColumnCount()), 
 194                      _T("Invalid column")); 
 195         m_columns
[column
].SetAlignment (flag
); 
 198     int GetColumnWidth (int column
) const { 
 199         wxCHECK_MSG ((column 
>= 0) && (column 
< GetColumnCount()), 
 200                      -1, _T("Invalid column")); 
 201         return m_columns
[column
].GetWidth(); 
 203     void SetColumnWidth (int column
, int width
); 
 205     bool IsColumnEditable (int column
) const { 
 206         wxCHECK_MSG ((column 
>= 0) && (column 
< GetColumnCount()), 
 207                      false, _T("Invalid column")); 
 208         return m_columns
[column
].IsEditable(); 
 211     bool IsColumnShown (int column
) const { 
 212         wxCHECK_MSG ((column 
>= 0) && (column 
< GetColumnCount()), 
 213                      true, _T("Invalid column")); 
 214         return m_columns
[column
].IsShown(); 
 221     // common part of all ctors 
 224     void SendListEvent(wxEventType type
, wxPoint pos
); 
 226     DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow
) 
 227     DECLARE_EVENT_TABLE() 
 231 // this is the "true" control 
 232 class  wxTreeListMainWindow
: public wxScrolledWindow
 
 237     wxTreeListMainWindow() { Init(); } 
 239     wxTreeListMainWindow (wxTreeListCtrl 
*parent
, wxWindowID id 
= -1, 
 240                const wxPoint
& pos 
= wxDefaultPosition
, 
 241                const wxSize
& size 
= wxDefaultSize
, 
 242                long style 
= wxTR_DEFAULT_STYLE
, 
 243                const wxValidator 
&validator 
= wxDefaultValidator
, 
 244                const wxString
& name 
= _T("wxtreelistmainwindow")) 
 247         Create (parent
, id
, pos
, size
, style
, validator
, name
); 
 250     virtual ~wxTreeListMainWindow(); 
 252     bool Create(wxTreeListCtrl 
*parent
, wxWindowID id 
= -1, 
 253                 const wxPoint
& pos 
= wxDefaultPosition
, 
 254                 const wxSize
& size 
= wxDefaultSize
, 
 255                 long style 
= wxTR_DEFAULT_STYLE
, 
 256                 const wxValidator 
&validator 
= wxDefaultValidator
, 
 257                 const wxString
& name 
= _T("wxtreelistctrl")); 
 262     // return true if this is a virtual list control 
 263     bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL
); } 
 265     // get the total number of items in the control 
 266     size_t GetCount() const; 
 268     // indent is the number of pixels the children are indented relative to 
 269     // the parents position. SetIndent() also redraws the control 
 271     unsigned int GetIndent() const { return m_indent
; } 
 272     void SetIndent(unsigned int indent
); 
 274     // see wxTreeListCtrl for the meaning 
 275     unsigned int GetLineSpacing() const { return m_linespacing
; } 
 276     void SetLineSpacing(unsigned int spacing
); 
 278     // image list: these functions allow to associate an image list with 
 279     // the control and retrieve it. Note that when assigned with 
 280     // SetImageList, the control does _not_ delete 
 281     // the associated image list when it's deleted in order to allow image 
 282     // lists to be shared between different controls. If you use 
 283     // AssignImageList, the control _does_ delete the image list. 
 285     // The normal image list is for the icons which correspond to the 
 286     // normal tree item state (whether it is selected or not). 
 287     // Additionally, the application might choose to show a state icon 
 288     // which corresponds to an app-defined item state (for example, 
 289     // checked/unchecked) which are taken from the state image list. 
 290     wxImageList 
*GetImageList() const { return m_imageListNormal
; } 
 291     wxImageList 
*GetStateImageList() const { return m_imageListState
; } 
 292     wxImageList 
*GetButtonsImageList() const { return m_imageListButtons
; } 
 294     void SetImageList(wxImageList 
*imageList
); 
 295     void SetStateImageList(wxImageList 
*imageList
); 
 296     void SetButtonsImageList(wxImageList 
*imageList
); 
 297     void AssignImageList(wxImageList 
*imageList
); 
 298     void AssignStateImageList(wxImageList 
*imageList
); 
 299     void AssignButtonsImageList(wxImageList 
*imageList
); 
 301     // Functions to work with tree ctrl items. 
 306     // retrieve item's label 
 307     wxString 
GetItemText (const wxTreeItemId
& item
) const 
 308     { return GetItemText (item
, GetMainColumn()); } 
 309     wxString 
GetItemText (const wxTreeItemId
& item
, int column
) const; 
 310     wxString 
GetItemText (wxTreeItemData
* item
, int column
) const; 
 312     // get one of the images associated with the item (normal by default) 
 313     int GetItemImage (const wxTreeItemId
& item
, 
 314                       wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) const 
 315     { return GetItemImage (item
, GetMainColumn(), which
); } 
 316     int GetItemImage (const wxTreeItemId
& item
, int column
, 
 317                       wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) const; 
 319     // get the data associated with the item 
 320     wxTreeItemData 
*GetItemData(const wxTreeItemId
& item
) const; 
 322     bool GetItemBold(const wxTreeItemId
& item
) const; 
 323     wxColour 
GetItemTextColour(const wxTreeItemId
& item
) const; 
 324     wxColour 
GetItemBackgroundColour(const wxTreeItemId
& item
) const; 
 325     wxFont 
GetItemFont(const wxTreeItemId
& item
) const; 
 331     void SetItemText (const wxTreeItemId
& item
, const wxString
& text
) 
 332     { SetItemText (item
, GetMainColumn(), text
); } 
 333     void SetItemText (const wxTreeItemId
& item
, int column
, const wxString
& text
); 
 335     // get one of the images associated with the item (normal by default) 
 336     void SetItemImage (const wxTreeItemId
& item
, int image
, 
 337                        wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) 
 338     { SetItemImage (item
, GetMainColumn(), image
, which
); } 
 339     void SetItemImage (const wxTreeItemId
& item
, int column
, int image
, 
 340                        wxTreeItemIcon which 
= wxTreeItemIcon_Normal
); 
 342     // associate some data with the item 
 343     void SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
); 
 345     // force appearance of [+] button near the item. This is useful to 
 346     // allow the user to expand the items which don't have any children now 
 347     // - but instead add them only when needed, thus minimizing memory 
 348     // usage and loading time. 
 349     void SetItemHasChildren(const wxTreeItemId
& item
, bool has 
= true); 
 351     // the item will be shown in bold 
 352     void SetItemBold(const wxTreeItemId
& item
, bool bold 
= true); 
 354     // set the item's text colour 
 355     void SetItemTextColour(const wxTreeItemId
& item
, const wxColour
& colour
); 
 357     // set the item's background colour 
 358     void SetItemBackgroundColour(const wxTreeItemId
& item
, const wxColour
& colour
); 
 360     // set the item's font (should be of the same height for all items) 
 361     void SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
); 
 363     // set the window font 
 364     virtual bool SetFont( const wxFont 
&font 
); 
 366     // set the styles.  No need to specify a GetWindowStyle here since 
 367     // the base wxWindow member function will do it for us 
 368     void SetWindowStyle(const long styles
); 
 370     // item status inquiries 
 371     // --------------------- 
 373     // is the item visible (it might be outside the view or not expanded)? 
 374     bool IsVisible(const wxTreeItemId
& item
, bool fullRow
) const; 
 375     // does the item has any children? 
 376     bool HasChildren(const wxTreeItemId
& item
) const; 
 377     // is the item expanded (only makes sense if HasChildren())? 
 378     bool IsExpanded(const wxTreeItemId
& item
) const; 
 379     // is this item currently selected (the same as has focus)? 
 380     bool IsSelected(const wxTreeItemId
& item
) const; 
 381     // is item text in bold font? 
 382     bool IsBold(const wxTreeItemId
& item
) const; 
 383         // does the layout include space for a button? 
 385     // number of children 
 386     // ------------------ 
 388     // if 'recursively' is false, only immediate children count, otherwise 
 389     // the returned number is the number of all items in this branch 
 390     size_t GetChildrenCount(const wxTreeItemId
& item
, bool recursively 
= true); 
 395     // wxTreeItemId.IsOk() will return false if there is no such item 
 397     // get the root tree item 
 398     wxTreeItemId 
GetRootItem() const { return m_rootItem
; } 
 400     // get the item currently selected, only if a single item is selected 
 401     wxTreeItemId 
GetSelection() const { return m_selectItem
; } 
 403     // get all the items currently selected, return count of items 
 404     size_t GetSelections(wxArrayTreeItemIds
&) const; 
 406     // get the parent of this item (may return NULL if root) 
 407     wxTreeItemId 
GetItemParent(const wxTreeItemId
& item
) const; 
 409     // for this enumeration function you must pass in a "cookie" parameter 
 410     // which is opaque for the application but is necessary for the library 
 411     // to make these functions reentrant (i.e. allow more than one 
 412     // enumeration on one and the same object simultaneously). Of course, 
 413     // the "cookie" passed to GetFirstChild() and GetNextChild() should be 
 416     // get child of this item 
 417 #if !wxCHECK_VERSION(2, 5, 0) 
 418     wxTreeItemId 
GetFirstChild(const wxTreeItemId
& item
, long& cookie
) const; 
 419     wxTreeItemId 
GetNextChild(const wxTreeItemId
& item
, long& cookie
) const; 
 420     wxTreeItemId 
GetPrevChild(const wxTreeItemId
& item
, long& cookie
) const; 
 421     wxTreeItemId 
GetLastChild(const wxTreeItemId
& item
, long& cookie
) const; 
 423     wxTreeItemId 
GetFirstChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const; 
 424     wxTreeItemId 
GetNextChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const; 
 425     wxTreeItemId 
GetPrevChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const; 
 426     wxTreeItemId 
GetLastChild(const wxTreeItemId
& item
, wxTreeItemIdValue
& cookie
) const; 
 429     // get sibling of this item 
 430     wxTreeItemId 
GetNextSibling(const wxTreeItemId
& item
) const; 
 431     wxTreeItemId 
GetPrevSibling(const wxTreeItemId
& item
) const; 
 433     // get item in the full tree (currently only for internal use) 
 434     wxTreeItemId 
GetNext(const wxTreeItemId
& item
, bool fulltree 
= true) const; 
 435     wxTreeItemId 
GetPrev(const wxTreeItemId
& item
, bool fulltree 
= true) const; 
 437     // get expanded item, see IsExpanded() 
 438     wxTreeItemId 
GetFirstExpandedItem() const; 
 439     wxTreeItemId 
GetNextExpanded(const wxTreeItemId
& item
) const; 
 440     wxTreeItemId 
GetPrevExpanded(const wxTreeItemId
& item
) const; 
 442     // get visible item, see IsVisible() 
 443     wxTreeItemId 
GetFirstVisibleItem(bool fullRow
) const; 
 444     wxTreeItemId 
GetNextVisible(const wxTreeItemId
& item
, bool fullRow
) const; 
 445     wxTreeItemId 
GetPrevVisible(const wxTreeItemId
& item
, bool fullRow
) const; 
 450     // add the root node to the tree 
 451     wxTreeItemId 
AddRoot (const wxString
& text
, 
 452                           int image 
= -1, int selectedImage 
= -1, 
 453                           wxTreeItemData 
*data 
= NULL
); 
 455     // insert a new item in as the first child of the parent 
 456     wxTreeItemId 
PrependItem(const wxTreeItemId
& parent
, 
 457                              const wxString
& text
, 
 458                              int image 
= -1, int selectedImage 
= -1, 
 459                              wxTreeItemData 
*data 
= NULL
); 
 461     // insert a new item after a given one 
 462     wxTreeItemId 
InsertItem(const wxTreeItemId
& parent
, 
 463                             const wxTreeItemId
& idPrevious
, 
 464                             const wxString
& text
, 
 465                             int image 
= -1, int selectedImage 
= -1, 
 466                             wxTreeItemData 
*data 
= NULL
); 
 468     // insert a new item before the one with the given index 
 469     wxTreeItemId 
InsertItem(const wxTreeItemId
& parent
, 
 471                             const wxString
& text
, 
 472                             int image 
= -1, int selectedImage 
= -1, 
 473                             wxTreeItemData 
*data 
= NULL
); 
 475     // insert a new item in as the last child of the parent 
 476     wxTreeItemId 
AppendItem(const wxTreeItemId
& parent
, 
 477                             const wxString
& text
, 
 478                             int image 
= -1, int selectedImage 
= -1, 
 479                             wxTreeItemData 
*data 
= NULL
); 
 481     // delete this item and associated data if any 
 482     void Delete(const wxTreeItemId
& item
); 
 483     // delete all children (but don't delete the item itself) 
 484     // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events 
 485     void DeleteChildren(const wxTreeItemId
& item
); 
 486     // delete the root and all its children from the tree 
 487     // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events 
 491     void Expand(const wxTreeItemId
& item
); 
 492     // expand this item and all subitems recursively 
 493     void ExpandAll(const wxTreeItemId
& item
); 
 494     // collapse the item without removing its children 
 495     void Collapse(const wxTreeItemId
& item
); 
 496     // collapse the item and remove all children 
 497     void CollapseAndReset(const wxTreeItemId
& item
); 
 498     // toggles the current state 
 499     void Toggle(const wxTreeItemId
& item
); 
 501     // remove the selection from currently selected item (if any) 
 505     void SelectItem(const wxTreeItemId
& item
, const wxTreeItemId
& prev 
= (wxTreeItemId
*)NULL
, 
 506                     bool unselect_others 
= true); 
 508     // make sure this item is visible (expanding the parent item and/or 
 509     // scrolling to this item if necessary) 
 510     void EnsureVisible(const wxTreeItemId
& item
); 
 511     // scroll to this item (but don't expand its parent) 
 512     void ScrollTo(const wxTreeItemId
& item
); 
 513     void AdjustMyScrollbars(); 
 515     // The first function is more portable (because easier to implement 
 516     // on other platforms), but the second one returns some extra info. 
 517     wxTreeItemId 
HitTest (const wxPoint
& point
) 
 518         { int flags
; int column
; return HitTest (point
, flags
, column
); } 
 519     wxTreeItemId 
HitTest (const wxPoint
& point
, int& flags
) 
 520         { int column
; return HitTest (point
, flags
, column
); } 
 521     wxTreeItemId 
HitTest (const wxPoint
& point
, int& flags
, int& column
); 
 524     // get the bounding rectangle of the item (or of its label only) 
 525     bool GetBoundingRect(const wxTreeItemId
& item
, 
 527                          bool textOnly 
= false) const; 
 529     // Start editing the item label: this (temporarily) replaces the item 
 530     // with a one line edit control. The item will be selected if it hadn't 
 532     void EditLabel (const wxTreeItemId
& item
, int column
); 
 535     // this function is called to compare 2 items and should return -1, 0 
 536     // or +1 if the first item is less than, equal to or greater than the 
 537     // second one. The base class version performs alphabetic comparaison 
 538     // of item labels (GetText) 
 539     virtual int OnCompareItems(const wxTreeItemId
& item1
, 
 540                                const wxTreeItemId
& item2
); 
 541     // sort the children of this item using OnCompareItems 
 543     // NB: this function is not reentrant and not MT-safe (FIXME)! 
 544     void SortChildren(const wxTreeItemId
& item
); 
 547     wxTreeItemId 
FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode 
= 0); 
 549     // implementation only from now on 
 551     // overridden base class virtuals 
 552     virtual bool SetBackgroundColour(const wxColour
& colour
); 
 553     virtual bool SetForegroundColour(const wxColour
& colour
); 
 556     void SetDragItem (const wxTreeItemId
& item 
= (wxTreeItemId
*)NULL
); 
 559     void OnPaint( wxPaintEvent 
&event 
); 
 560     void OnSetFocus( wxFocusEvent 
&event 
); 
 561     void OnKillFocus( wxFocusEvent 
&event 
); 
 562     void OnChar( wxKeyEvent 
&event 
); 
 563     void OnMouse( wxMouseEvent 
&event 
); 
 564     void OnIdle( wxIdleEvent 
&event 
); 
 565     void OnScroll(wxScrollWinEvent
& event
); 
 567     // implementation helpers 
 568     void SendDeleteEvent(wxTreeListItem 
*itemBeingDeleted
); 
 570     int GetColumnCount() const 
 571     { return m_owner
->GetHeaderWindow()->GetColumnCount(); } 
 573     void SetMainColumn (int column
) 
 574     { if ((column 
>= 0) && (column 
< GetColumnCount())) m_main_column 
= column
; } 
 576     int GetMainColumn() const { return m_main_column
; } 
 578     int GetBestColumnWidth (int column
, wxTreeItemId parent 
= wxTreeItemId()); 
 579     int GetItemWidth (int column
, wxTreeListItem 
*item
); 
 580     wxFont 
GetItemFont (wxTreeListItem 
*item
); 
 585     wxTreeListCtrl
* m_owner
; 
 589     friend class wxTreeListItem
; 
 590     friend class wxTreeListRenameTimer
; 
 591     friend class wxEditTextCtrl
; 
 596     wxTreeListItem       
*m_rootItem
; // root item 
 597     wxTreeListItem       
*m_curItem
; // current item, either selected or marked 
 598     wxTreeListItem       
*m_shiftItem
; // item, where the shift key was pressed 
 599     wxTreeListItem       
*m_editItem
; // item, which is currently edited 
 600     wxTreeListItem       
*m_selectItem
; // current selected item, not with wxTR_MULTIPLE 
 604     int                  m_btnWidth
, m_btnWidth2
; 
 605     int                  m_btnHeight
, m_btnHeight2
; 
 606     int                  m_imgWidth
, m_imgWidth2
; 
 607     int                  m_imgHeight
, m_imgHeight2
; 
 608     unsigned short       m_indent
; 
 610     unsigned short       m_linespacing
; 
 612     wxBrush             
*m_hilightBrush
, 
 613                         *m_hilightUnfocusedBrush
; 
 618     bool                 m_ownsImageListNormal
, 
 619                          m_ownsImageListState
, 
 620                          m_ownsImageListButtons
; 
 621     bool                 m_isDragging
; // true between BEGIN/END drag events 
 623     bool                 m_lastOnSame
;  // last click on the same item as prev 
 624     bool                 m_left_down_selection
; 
 626     wxImageList         
*m_imageListNormal
, 
 631     wxTimer             
*m_dragTimer
; 
 632     wxTreeListItem      
*m_dragItem
; 
 634     wxTimer             
*m_renameTimer
; 
 635     wxString             m_renameRes
; 
 638     wxTimer             
*m_findTimer
; 
 641     // the common part of all ctors 
 645     wxTreeItemId 
DoInsertItem(const wxTreeItemId
& parent
, 
 647                               const wxString
& text
, 
 648                               int image
, int selectedImage
, 
 649                               wxTreeItemData 
*data
); 
 650     bool HasButtons(void) const 
 651         { return (m_imageListButtons
) || HasFlag (wxTR_TWIST_BUTTONS
|wxTR_HAS_BUTTONS
); } 
 654     void CalculateLineHeight(); 
 655     int  GetLineHeight(wxTreeListItem 
*item
) const; 
 656     void PaintLevel( wxTreeListItem 
*item
, wxDC
& dc
, int level
, int &y
, 
 658     void PaintItem( wxTreeListItem 
*item
, wxDC
& dc
); 
 660     void CalculateLevel( wxTreeListItem 
*item
, wxDC 
&dc
, int level
, int &y
, 
 662     void CalculatePositions(); 
 663     void CalculateSize( wxTreeListItem 
*item
, wxDC 
&dc 
); 
 665     void RefreshSubtree (wxTreeListItem 
*item
); 
 666     void RefreshLine (wxTreeListItem 
*item
); 
 668     // redraw all selected items 
 669     void RefreshSelected(); 
 671     // RefreshSelected() recursive helper 
 672     void RefreshSelectedUnder (wxTreeListItem 
*item
); 
 674     void OnRenameTimer(); 
 675     void OnRenameAccept(); 
 677     void FillArray(wxTreeListItem
*, wxArrayTreeItemIds
&) const; 
 678     bool TagAllChildrenUntilLast (wxTreeListItem 
*crt_item
, wxTreeListItem 
*last_item
); 
 679     bool TagNextChildren (wxTreeListItem 
*crt_item
, wxTreeListItem 
*last_item
); 
 680     void UnselectAllChildren (wxTreeListItem 
*item 
); 
 683     DECLARE_EVENT_TABLE() 
 684     DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow
) 
 688 // timer used for enabling in-place edit 
 689 class  wxTreeListRenameTimer
: public wxTimer
 
 692     wxTreeListRenameTimer( wxTreeListMainWindow 
*owner 
); 
 697     wxTreeListMainWindow   
*m_owner
; 
 700 // control used for in-place edit 
 701 class  wxEditTextCtrl
: public wxTextCtrl
 
 704     wxEditTextCtrl (wxWindow 
*parent
, 
 708                     wxTreeListMainWindow 
*owner
, 
 709                     const wxString 
&value 
= wxEmptyString
, 
 710                     const wxPoint 
&pos 
= wxDefaultPosition
, 
 711                     const wxSize 
&size 
= wxDefaultSize
, 
 713                     const wxValidator
& validator 
= wxDefaultValidator
, 
 714                     const wxString 
&name 
= wxTextCtrlNameStr 
); 
 716     void OnChar( wxKeyEvent 
&event 
); 
 717     void OnKeyUp( wxKeyEvent 
&event 
); 
 718     void OnKillFocus( wxFocusEvent 
&event 
); 
 723     wxTreeListMainWindow  
*m_owner
; 
 724     wxString            m_startValue
; 
 727     DECLARE_EVENT_TABLE() 
 735     wxTreeListItem() { m_data 
= NULL
; } 
 736     wxTreeListItem( wxTreeListMainWindow 
*owner
, 
 737                     wxTreeListItem 
*parent
, 
 738                     const wxArrayString
& text
, 
 741                     wxTreeItemData 
*data 
); 
 746     wxArrayTreeListItems
& GetChildren() { return m_children
; } 
 748     const wxString 
GetText() const 
 752     const wxString 
GetText (int column
) const 
 754         if(m_text
.GetCount() > 0) 
 756             if( IsVirtual() )   return m_owner
->GetItemText( m_data
, column 
); 
 757             else                return m_text
[column
]; 
 759         return wxEmptyString
; 
 762     int GetImage (wxTreeItemIcon which 
= wxTreeItemIcon_Normal
) const 
 763         { return m_images
[which
]; } 
 764     int GetImage (int column
, wxTreeItemIcon which
=wxTreeItemIcon_Normal
) const 
 766         if(column 
== m_owner
->GetMainColumn()) return m_images
[which
]; 
 767         if(column 
< (int)m_col_images
.GetCount()) return m_col_images
[column
]; 
 771     wxTreeItemData 
*GetData() const { return m_data
; } 
 773     // returns the current image for the item (depending on its 
 774     // selected/expanded/whatever state) 
 775     int GetCurrentImage() const; 
 777     void SetText (const wxString 
&text 
); 
 778     void SetText (int column
, const wxString
& text
) 
 780         if (column 
< (int)m_text
.GetCount()) { 
 781             m_text
[column
] = text
; 
 782         }else if (column 
< m_owner
->GetColumnCount()) { 
 783             int howmany 
= m_owner
->GetColumnCount(); 
 784             for (int i 
= m_text
.GetCount(); i 
< howmany
; ++i
) m_text
.Add (wxEmptyString
); 
 785             m_text
[column
] = text
; 
 788     void SetImage (int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; } 
 789     void SetImage (int column
, int image
, wxTreeItemIcon which
) 
 791         if (column 
== m_owner
->GetMainColumn()) { 
 792             m_images
[which
] = image
; 
 793         }else if (column 
< (int)m_col_images
.GetCount()) { 
 794             m_col_images
[column
] = image
; 
 795         }else if (column 
< m_owner
->GetColumnCount()) { 
 796             int howmany 
= m_owner
->GetColumnCount(); 
 797             for (int i 
= m_col_images
.GetCount(); i 
< howmany
; ++i
) m_col_images
.Add (NO_IMAGE
); 
 798             m_col_images
[column
] = image
; 
 802     void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
 804     void SetHasPlus(bool has 
= true) { m_hasPlus 
= has
; } 
 806     void SetBold(bool bold
) { m_isBold 
= bold
; } 
 808     int GetX() const { return m_x
; } 
 809     int GetY() const { return m_y
; } 
 811     void SetX (int x
) { m_x 
= x
; } 
 812     void SetY (int y
) { m_y 
= y
; } 
 814     int  GetHeight() const { return m_height
; } 
 815     int  GetWidth()  const { return m_width
; } 
 817     void SetHeight (int height
) { m_height 
= height
; } 
 818     void SetWidth (int width
) { m_width 
= width
; } 
 820     int GetTextX() const { return m_text_x
; } 
 821     void SetTextX (int text_x
) { m_text_x 
= text_x
; } 
 823     wxTreeListItem 
*GetItemParent() const { return m_parent
; } 
 826     // deletes all children notifying the treectrl about it if !NULL 
 828     void DeleteChildren(wxTreeListMainWindow 
*tree 
= NULL
); 
 830     // get count of all children (and grand children if 'recursively') 
 831     size_t GetChildrenCount(bool recursively 
= true) const; 
 833     void Insert(wxTreeListItem 
*child
, size_t index
) 
 834     { m_children
.Insert(child
, index
); } 
 836     void GetSize( int &x
, int &y
, const wxTreeListMainWindow
* ); 
 838     // return the item at given position (or NULL if no item), onButton is 
 839     // true if the point belongs to the item's button, otherwise it lies 
 840     // on the button's label 
 841     wxTreeListItem 
*HitTest (const wxPoint
& point
, 
 842                              const wxTreeListMainWindow 
*, 
 843                              int &flags
, int& column
, int level
); 
 845     void Expand() { m_isCollapsed 
= false; } 
 846     void Collapse() { m_isCollapsed 
= true; } 
 848     void SetHilight( bool set 
= true ) { m_hasHilight 
= set
; } 
 851     bool HasChildren() const { return !m_children
.IsEmpty(); } 
 852     bool IsSelected()  const { return m_hasHilight 
!= 0; } 
 853     bool IsExpanded()  const { return !m_isCollapsed
; } 
 854     bool HasPlus()     const { return m_hasPlus 
|| HasChildren(); } 
 855     bool IsBold()      const { return m_isBold 
!= 0; } 
 856     bool IsVirtual()   const { return m_owner
->IsVirtual(); } 
 859     // get them - may be NULL 
 860     wxTreeItemAttr 
*GetAttributes() const { return m_attr
; } 
 861     // get them ensuring that the pointer is not NULL 
 862     wxTreeItemAttr
& Attr() 
 866             m_attr 
= new wxTreeItemAttr
; 
 872     void SetAttributes(wxTreeItemAttr 
*attr
) 
 874         if ( m_ownsAttr 
) delete m_attr
; 
 878     // set them and delete when done 
 879     void AssignAttributes(wxTreeItemAttr 
*attr
) 
 886     wxTreeListMainWindow  
*m_owner
;        // control the item belongs to 
 888     // since there can be very many of these, we save size by chosing 
 889     // the smallest representation for the elements and by ordering 
 890     // the members to avoid padding. 
 891     wxArrayString      m_text
;    // labels to be rendered for item 
 893     wxTreeItemData     
*m_data
;         // user-provided data 
 895     wxArrayTreeListItems m_children
; // list of children 
 896     wxTreeListItem  
*m_parent
;       // parent of this item 
 898     wxTreeItemAttr     
*m_attr
;         // attributes??? 
 900     // tree ctrl images for the normal, selected, expanded and 
 901     // expanded+selected states 
 902     short               m_images
[wxTreeItemIcon_Max
]; 
 903     wxArrayShort m_col_images
; // images for the various columns (!= main) 
 905     // main column item positions 
 906     wxCoord             m_x
;            // (virtual) offset from left (vertical line) 
 907     wxCoord             m_y
;            // (virtual) offset from top 
 908     wxCoord             m_text_x
;       // item offset from left 
 909     short               m_width
;        // width of this item 
 910     unsigned char       m_height
;       // height of this item 
 912     // use bitfields to save size 
 913     int                 m_isCollapsed 
:1; 
 914     int                 m_hasHilight  
:1; // same as focused 
 915     int                 m_hasPlus     
:1; // used for item which doesn't have 
 916                                           // children but has a [+] button 
 917     int                 m_isBold      
:1; // render the label in bold font 
 918     int                 m_ownsAttr    
:1; // delete attribute when done 
 921 // =========================================================================== 
 923 // =========================================================================== 
 925 // --------------------------------------------------------------------------- 
 926 // wxTreeListRenameTimer (internal) 
 927 // --------------------------------------------------------------------------- 
 929 wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow 
*owner 
) 
 934 void wxTreeListRenameTimer::Notify() 
 936     m_owner
->OnRenameTimer(); 
 939 //----------------------------------------------------------------------------- 
 940 // wxEditTextCtrl (internal) 
 941 //----------------------------------------------------------------------------- 
 943 BEGIN_EVENT_TABLE (wxEditTextCtrl
,wxTextCtrl
) 
 944     EVT_CHAR           (wxEditTextCtrl::OnChar
) 
 945     EVT_KEY_UP         (wxEditTextCtrl::OnKeyUp
) 
 946     EVT_KILL_FOCUS     (wxEditTextCtrl::OnKillFocus
) 
 949 wxEditTextCtrl::wxEditTextCtrl (wxWindow 
*parent
, 
 953                                 wxTreeListMainWindow 
*owner
, 
 954                                 const wxString 
&value
, 
 958                                 const wxValidator
& validator
, 
 959                                 const wxString 
&name
) 
 960     : wxTextCtrl (parent
, id
, value
, pos
, size
, style
|wxSIMPLE_BORDER
, validator
, name
) 
 966     (*m_res
) = wxEmptyString
; 
 967     m_startValue 
= value
; 
 971 void wxEditTextCtrl::OnChar( wxKeyEvent 
&event 
) 
 973     if (event
.GetKeyCode() == WXK_RETURN
) 
 976         (*m_res
) = GetValue(); 
 978         if ((*m_res
) != m_startValue
) 
 979             m_owner
->OnRenameAccept(); 
 981         if (!wxPendingDelete
.Member(this)) 
 982             wxPendingDelete
.Append(this); 
 985         m_owner
->SetFocus(); // This doesn't work. TODO. 
 989     if (event
.GetKeyCode() == WXK_ESCAPE
) 
 992         (*m_res
) = wxEmptyString
; 
 994         if (!wxPendingDelete
.Member(this)) 
 995             wxPendingDelete
.Append(this); 
 998         m_owner
->SetFocus(); // This doesn't work. TODO. 
1005 void wxEditTextCtrl::OnKeyUp( wxKeyEvent 
&event 
) 
1013     // auto-grow the textctrl: 
1014     wxSize parentSize 
= m_owner
->GetSize(); 
1015     wxPoint myPos 
= GetPosition(); 
1016     wxSize mySize 
= GetSize(); 
1018     GetTextExtent(GetValue() + _T("M"), &sx
, &sy
); 
1019     if (myPos
.x 
+ sx 
> parentSize
.x
) sx 
= parentSize
.x 
- myPos
.x
; 
1020     if (mySize
.x 
> sx
) sx 
= mySize
.x
; 
1026 void wxEditTextCtrl::OnKillFocus( wxFocusEvent 
&event 
) 
1034     if (!wxPendingDelete
.Member(this)) 
1035         wxPendingDelete
.Append(this); 
1038     (*m_res
) = GetValue(); 
1040     if ((*m_res
) != m_startValue
) 
1041         m_owner
->OnRenameAccept(); 
1044 //----------------------------------------------------------------------------- 
1045 //  wxTreeListHeaderWindow 
1046 //----------------------------------------------------------------------------- 
1048 IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow
,wxWindow
); 
1050 BEGIN_EVENT_TABLE(wxTreeListHeaderWindow
,wxWindow
) 
1051     EVT_PAINT         (wxTreeListHeaderWindow::OnPaint
) 
1052     EVT_MOUSE_EVENTS  (wxTreeListHeaderWindow::OnMouse
) 
1053     EVT_SET_FOCUS     (wxTreeListHeaderWindow::OnSetFocus
) 
1056 void wxTreeListHeaderWindow::Init() 
1058     m_currentCursor 
= (wxCursor 
*) NULL
; 
1059     m_isDragging 
= false; 
1061     m_total_col_width 
= 0; 
1065 wxTreeListHeaderWindow::wxTreeListHeaderWindow() 
1069     m_owner 
= (wxTreeListMainWindow 
*) NULL
; 
1070     m_resizeCursor 
= (wxCursor 
*) NULL
; 
1073 wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow 
*win
, 
1075                                                 wxTreeListMainWindow 
*owner
, 
1079                                                 const wxString 
&name 
) 
1080     : wxWindow( win
, id
, pos
, size
, style
, name 
) 
1085     m_resizeCursor 
= new wxCursor(wxCURSOR_SIZEWE
); 
1087 #if !wxCHECK_VERSION(2, 5, 0) 
1088     SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNFACE
)); 
1090     SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE
)); 
1094 wxTreeListHeaderWindow::~wxTreeListHeaderWindow() 
1096     delete m_resizeCursor
; 
1099 void wxTreeListHeaderWindow::DoDrawRect( wxDC 
*dc
, int x
, int y
, int w
, int h 
) 
1101 #if !wxCHECK_VERSION(2, 5, 0) 
1102     wxPen 
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW 
), 1, wxSOLID
); 
1104     wxPen 
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW 
), 1, wxSOLID
); 
1107     const int m_corner 
= 1; 
1109     dc
->SetBrush( *wxTRANSPARENT_BRUSH 
); 
1110 #if defined( __WXMAC__  ) 
1113     dc
->SetPen( *wxBLACK_PEN 
); 
1115     dc
->DrawLine( x
+w
-m_corner
+1, y
, x
+w
, y
+h 
);  // right (outer) 
1116     dc
->DrawRectangle( x
, y
+h
, w
+1, 1 );          // bottom (outer) 
1118 #if defined( __WXMAC__  ) 
1119     pen 
= wxPen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID 
); 
1122     dc
->DrawLine( x
+w
-m_corner
, y
, x
+w
-1, y
+h 
);  // right (inner) 
1123     dc
->DrawRectangle( x
+1, y
+h
-1, w
-2, 1 );      // bottom (inner) 
1125     dc
->SetPen( *wxWHITE_PEN 
); 
1126     dc
->DrawRectangle( x
, y
, w
-m_corner
+1, 1 );   // top (outer) 
1127     dc
->DrawRectangle( x
, y
, 1, h 
);              // left (outer) 
1128     dc
->DrawLine( x
, y
+h
-1, x
+1, y
+h
-1 ); 
1129     dc
->DrawLine( x
+w
-1, y
, x
+w
-1, y
+1 ); 
1132 // shift the DC origin to match the position of the main window horz 
1133 // scrollbar: this allows us to always use logical coords 
1134 void wxTreeListHeaderWindow::AdjustDC(wxDC
& dc
) 
1137     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1139     m_owner
->GetViewStart( &x
, NULL 
); 
1141     // account for the horz scrollbar offset 
1142     dc
.SetDeviceOrigin( -x 
* xpix
, 0 ); 
1145 void wxTreeListHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1148     wxClientDC 
dc( this ); 
1150     wxPaintDC 
dc( this ); 
1156     int x 
= HEADER_OFFSET_X
; 
1158     // width and height of the entire header window 
1160     GetClientSize( &w
, &h 
); 
1161     m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1162     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1164 #if wxCHECK_VERSION_FULL(2, 7, 0, 1) 
1165     int numColumns 
= GetColumnCount(); 
1166     for ( int i 
= 0; i 
< numColumns 
&& x 
< w
; i
++ ) 
1168         if (!IsColumnShown (i
)) continue; // do next column if not shown 
1170         wxHeaderButtonParams params
; 
1172         // TODO: columnInfo should have label colours... 
1173         params
.m_labelColour 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
1174         params
.m_labelFont 
= GetFont(); 
1176         wxTreeListColumnInfo
& column 
= GetColumn(i
); 
1177         int wCol 
= column
.GetWidth(); 
1179         wxRect 
rect(x
, 0, wCol
, h
); 
1182         if ( i 
== m_hotTrackCol
) 
1183             flags 
|= wxCONTROL_CURRENT
; 
1185         params
.m_labelText 
= column
.GetText(); 
1186         params
.m_labelAlignment 
= column
.GetAlignment(); 
1188         int image 
= column
.GetImage(); 
1189         wxImageList
* imageList 
= m_owner
->GetImageList(); 
1190         if ((image 
!= -1) && imageList
)  
1191             params
.m_labelBitmap 
= imageList
->GetBitmap(image
); 
1193         wxRendererNative::Get().DrawHeaderButton(this, dc
, rect
, flags
, 
1194                                                  wxHDR_SORT_ICON_NONE
, ¶ms
); 
1198         wxRect 
rect(x
, 0, w
-x
, h
); 
1199         wxRendererNative::Get().DrawHeaderButton(this, dc
, rect
); 
1202 #else  // not 2.7.0.1+ 
1204     dc
.SetFont( GetFont() ); 
1206     // do *not* use the listctrl colour for headers - one day we will have a 
1207     // function to set it separately 
1208     //dc.SetTextForeground( *wxBLACK ); 
1209 #if !wxCHECK_VERSION(2, 5, 0) 
1210     dc
.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT 
)); 
1212     dc
.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
)); 
1215     int numColumns 
= GetColumnCount(); 
1216     for ( int i 
= 0; i 
< numColumns 
&& x 
< w
; i
++ ) 
1218         if (!IsColumnShown (i
)) continue; // do next column if not shown 
1220         wxTreeListColumnInfo
& column 
= GetColumn(i
); 
1221         int wCol 
= column
.GetWidth(); 
1223         // the width of the rect to draw: make it smaller to fit entirely 
1224         // inside the column rect 
1227 #if !wxCHECK_VERSION(2, 7, 0) 
1228         dc
.SetPen( *wxWHITE_PEN 
); 
1229         DoDrawRect( &dc
, x
, HEADER_OFFSET_Y
, cw
, h
-2 ); 
1231         wxRect 
rect(x
, HEADER_OFFSET_Y
, cw
, h
-2); 
1232         wxRendererNative::GetDefault().DrawHeaderButton (this, dc
, rect
); 
1235         // if we have an image, draw it on the right of the label 
1236         int image 
= column
.GetImage(); //item.m_image; 
1237         int ix 
= -2, iy 
= 0; 
1238         wxImageList
* imageList 
= m_owner
->GetImageList(); 
1239         if ((image 
!= -1) && imageList
) { 
1240             imageList
->GetSize (image
, ix
, iy
); 
1243         // extra margins around the text label 
1246         int image_offset 
= cw 
- ix 
- 1; 
1248         switch(column
.GetAlignment()) { 
1250             text_x 
+= EXTRA_WIDTH
; 
1254             dc
.GetTextExtent (column
.GetText(), &text_width
, NULL
); 
1255             text_x 
+= cw 
- text_width 
- EXTRA_WIDTH 
- MARGIN
; 
1258         case wxALIGN_CENTER
: 
1259             dc
.GetTextExtent(column
.GetText(), &text_width
, NULL
); 
1260             text_x 
+= (cw 
- text_width
)/2 + ix 
+ 2; 
1261             image_offset 
= (cw 
- text_width 
- ix 
- 2)/2 - MARGIN
; 
1266         if ((image 
!= -1) && imageList
) { 
1267             imageList
->Draw (image
, dc
, x 
+ image_offset
/*cw - ix - 1*/, 
1268                              HEADER_OFFSET_Y 
+ (h 
- 4 - iy
)/2, 
1269                              wxIMAGELIST_DRAW_TRANSPARENT
); 
1272         // draw the text clipping it so that it doesn't overwrite the column boundary 
1273         wxDCClipper 
clipper(dc
, x
, HEADER_OFFSET_Y
, cw
, h 
- 4 ); 
1274         dc
.DrawText (column
.GetText(), text_x
, HEADER_OFFSET_Y 
+ EXTRA_HEIGHT 
); 
1280     int more_w 
= m_owner
->GetSize().x 
- x 
- HEADER_OFFSET_X
; 
1282 #if !wxCHECK_VERSION(2, 7, 0) 
1283         DoDrawRect (&dc
, x
, HEADER_OFFSET_Y
, more_w
, h
-2 ); 
1285         wxRect 
rect (x
, HEADER_OFFSET_Y
, more_w
, h
-2); 
1286         wxRendererNative::GetDefault().DrawHeaderButton (this, dc
, rect
); 
1292 void wxTreeListHeaderWindow::DrawCurrent() 
1294     int x1 
= m_currentX
; 
1296     ClientToScreen (&x1
, &y1
); 
1298     int x2 
= m_currentX
-1; 
1300     ++x2
; // but why ???? 
1303     m_owner
->GetClientSize( NULL
, &y2 
); 
1304     m_owner
->ClientToScreen( &x2
, &y2 
); 
1307     dc
.SetLogicalFunction (wxINVERT
); 
1308     dc
.SetPen (wxPen (*wxBLACK
, 2, wxSOLID
)); 
1309     dc
.SetBrush (*wxTRANSPARENT_BRUSH
); 
1312     dc
.DrawLine (x1
, y1
, x2
, y2
); 
1313     dc
.SetLogicalFunction (wxCOPY
); 
1314     dc
.SetPen (wxNullPen
); 
1315     dc
.SetBrush (wxNullBrush
); 
1318 #if wxCHECK_VERSION_FULL(2, 7, 0, 1) 
1319 int wxTreeListHeaderWindow::XToCol(int x
) 
1322     int numColumns 
= GetColumnCount(); 
1323     for ( int col 
= 0; col 
< numColumns
; col
++ ) 
1325         if (!IsColumnShown(col
)) continue;  
1326         wxTreeListColumnInfo
& column 
= GetColumn(col
); 
1328         if ( x 
< (colLeft 
+ column
.GetWidth()) ) 
1331         colLeft 
+= column
.GetWidth(); 
1337 void wxTreeListHeaderWindow::RefreshColLabel(int col
) 
1339     if ( col 
>= GetColumnCount() ) 
1346         if (!IsColumnShown(idx
)) continue;  
1347         wxTreeListColumnInfo
& column 
= GetColumn(idx
); 
1349         width 
= column
.GetWidth(); 
1350     } while (++idx 
<= col
); 
1352     m_owner
->CalcScrolledPosition(x
, 0, &x
, NULL
); 
1353     RefreshRect(wxRect(x
, 0, width
, GetSize().GetHeight()));    
1358 void wxTreeListHeaderWindow::OnMouse (wxMouseEvent 
&event
) { 
1360     // we want to work with logical coords 
1362     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1363     int y 
= event
.GetY(); 
1365 #if wxCHECK_VERSION_FULL(2, 7, 0, 1) 
1366     if ( event
.Moving() ) 
1368         int col 
= XToCol(x
); 
1369         if ( col 
!= m_hotTrackCol 
) 
1371             // Refresh the col header so it will be painted with hot tracking 
1372             // (if supported by the native renderer.) 
1373             RefreshColLabel(col
); 
1375             // Also refresh the old hot header 
1376             if ( m_hotTrackCol 
>= 0 ) 
1377                 RefreshColLabel(m_hotTrackCol
); 
1379             m_hotTrackCol 
= col
; 
1383     if ( event
.Leaving() && m_hotTrackCol 
>= 0 ) 
1385         // Leaving the window so clear any hot tracking indicator that may be present 
1386         RefreshColLabel(m_hotTrackCol
); 
1393         SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING
, event
.GetPosition()); 
1395         // we don't draw the line beyond our window, but we allow dragging it 
1398         GetClientSize( &w
, NULL 
); 
1399         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1402         // erase the line if it was drawn 
1403         if (m_currentX 
< w
) DrawCurrent(); 
1405         if (event
.ButtonUp()) { 
1406             m_isDragging 
= false; 
1407             if (HasCapture()) ReleaseMouse(); 
1409             SetColumnWidth (m_column
, m_currentX 
- m_minX
); 
1411             SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG
, event
.GetPosition()); 
1413             m_currentX 
= wxMax (m_minX 
+ 7, x
); 
1415             // draw in the new location 
1416             if (m_currentX 
< w
) DrawCurrent(); 
1419     }else{ // not dragging 
1422         bool hit_border 
= false; 
1424         // end of the current column 
1427         // find the column where this event occured 
1428         int countCol 
= GetColumnCount(); 
1429         for (int column 
= 0; column 
< countCol
; column
++) { 
1430             if (!IsColumnShown (column
)) continue; // do next if not shown 
1432             xpos 
+= GetColumnWidth (column
); 
1434             if ((abs (x
-xpos
) < 3) && (y 
< 22)) { 
1435                 // near the column border 
1441                 // inside the column 
1448         if (event
.LeftDown() || event
.RightUp()) { 
1449             if (hit_border 
&& event
.LeftDown()) { 
1450                 m_isDragging 
= true; 
1454                 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
, event
.GetPosition()); 
1455             }else{ // click on a column 
1456                 wxEventType evt 
= event
.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK
: 
1457                                                     wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
; 
1458                 SendListEvent (evt
, event
.GetPosition()); 
1460         }else if (event
.LeftDClick() && hit_border
) { 
1461             SetColumnWidth (m_column
, m_owner
->GetBestColumnWidth (m_column
)); 
1464         }else if (event
.Moving()) { 
1467                 setCursor 
= m_currentCursor 
== wxSTANDARD_CURSOR
; 
1468                 m_currentCursor 
= m_resizeCursor
; 
1470                 setCursor 
= m_currentCursor 
!= wxSTANDARD_CURSOR
; 
1471                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
1473             if (setCursor
) SetCursor (*m_currentCursor
); 
1479 void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent 
&WXUNUSED(event
)) { 
1480     m_owner
->SetFocus(); 
1483 void wxTreeListHeaderWindow::SendListEvent (wxEventType type
, wxPoint pos
) { 
1484     wxWindow 
*parent 
= GetParent(); 
1485     wxListEvent 
le (type
, parent
->GetId()); 
1486     le
.SetEventObject (parent
); 
1487     le
.m_pointDrag 
= pos
; 
1489     // the position should be relative to the parent window, not 
1490     // this one for compatibility with MSW and common sense: the 
1491     // user code doesn't know anything at all about this header 
1492     // window, so why should it get positions relative to it? 
1493     le
.m_pointDrag
.y 
-= GetSize().y
; 
1494     le
.m_col 
= m_column
; 
1495     parent
->GetEventHandler()->ProcessEvent (le
); 
1498 void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo
& colInfo
) { 
1499     m_columns
.Add (colInfo
); 
1500     m_total_col_width 
+= colInfo
.GetWidth(); 
1501     m_owner
->AdjustMyScrollbars(); 
1502     m_owner
->m_dirty 
= true; 
1505 void wxTreeListHeaderWindow::SetColumnWidth (int column
, int width
) { 
1506     wxCHECK_RET ((column 
>= 0) && (column 
< GetColumnCount()), _T("Invalid column")); 
1507     m_total_col_width 
-= m_columns
[column
].GetWidth(); 
1508     m_columns
[column
].SetWidth(width
); 
1509     m_total_col_width 
+= width
; 
1510     m_owner
->AdjustMyScrollbars(); 
1511     m_owner
->m_dirty 
= true; 
1514 void wxTreeListHeaderWindow::InsertColumn (int before
, const wxTreeListColumnInfo
& colInfo
) { 
1515     wxCHECK_RET ((before 
>= 0) && (before 
< GetColumnCount()), _T("Invalid column")); 
1516     m_columns
.Insert (colInfo
, before
); 
1517     m_total_col_width 
+= colInfo
.GetWidth(); 
1518     m_owner
->AdjustMyScrollbars(); 
1519     m_owner
->m_dirty 
= true; 
1522 void wxTreeListHeaderWindow::RemoveColumn (int column
) { 
1523     wxCHECK_RET ((column 
>= 0) && (column 
< GetColumnCount()), _T("Invalid column")); 
1524     m_total_col_width 
-= m_columns
[column
].GetWidth(); 
1525     m_columns
.RemoveAt (column
); 
1526     m_owner
->AdjustMyScrollbars(); 
1527     m_owner
->m_dirty 
= true; 
1530 void wxTreeListHeaderWindow::SetColumn (int column
, const wxTreeListColumnInfo
& info
) { 
1531     wxCHECK_RET ((column 
>= 0) && (column 
< GetColumnCount()), _T("Invalid column")); 
1532     int w 
= m_columns
[column
].GetWidth(); 
1533     m_columns
[column
] = info
; 
1534     if (w 
!= info
.GetWidth()) { 
1535         m_total_col_width 
+= info
.GetWidth() - w
; 
1536         m_owner
->AdjustMyScrollbars(); 
1538     m_owner
->m_dirty 
= true; 
1541 // --------------------------------------------------------------------------- 
1543 // --------------------------------------------------------------------------- 
1545 wxTreeListItem::wxTreeListItem (wxTreeListMainWindow 
*owner
, 
1546                                 wxTreeListItem 
*parent
, 
1547                                 const wxArrayString
& text
, 
1548                                 int image
, int selImage
, 
1549                                 wxTreeItemData 
*data
) 
1552     m_images
[wxTreeItemIcon_Normal
] = image
; 
1553     m_images
[wxTreeItemIcon_Selected
] = selImage
; 
1554     m_images
[wxTreeItemIcon_Expanded
] = NO_IMAGE
; 
1555     m_images
[wxTreeItemIcon_SelectedExpanded
] = NO_IMAGE
; 
1562     m_isCollapsed 
= true; 
1563     m_hasHilight 
= false; 
1570     m_attr 
= (wxTreeItemAttr 
*)NULL
; 
1573     // We don't know the height here yet. 
1578 wxTreeListItem::~wxTreeListItem() { 
1580     if (m_ownsAttr
) delete m_attr
; 
1582     wxASSERT_MSG( m_children
.IsEmpty(), _T("please call DeleteChildren() before destructor")); 
1585 void wxTreeListItem::DeleteChildren (wxTreeListMainWindow 
*tree
) { 
1586     size_t count 
= m_children
.Count(); 
1587     for (size_t n 
= 0; n 
< count
; n
++) { 
1588         wxTreeListItem 
*child 
= m_children
[n
]; 
1590             tree
->SendDeleteEvent (child
); 
1591             if (tree
->m_selectItem 
== child
) tree
->m_selectItem 
= (wxTreeListItem
*)NULL
; 
1593         child
->DeleteChildren (tree
); 
1599 void wxTreeListItem::SetText (const wxString 
&text
) { 
1600     if (m_text
.GetCount() > 0) { 
1607 size_t wxTreeListItem::GetChildrenCount (bool recursively
) const { 
1608     size_t count 
= m_children
.Count(); 
1609     if (!recursively
) return count
; 
1611     size_t total 
= count
; 
1612     for (size_t n 
= 0; n 
< count
; ++n
) { 
1613         total 
+= m_children
[n
]->GetChildrenCount(); 
1618 void wxTreeListItem::GetSize (int &x
, int &y
, const wxTreeListMainWindow 
*theButton
) { 
1619     int bottomY 
= m_y 
+ theButton
->GetLineHeight (this); 
1620     if (y 
< bottomY
) y 
= bottomY
; 
1621     int width 
= m_x 
+  m_width
; 
1622     if ( x 
< width 
) x 
= width
; 
1625         size_t count 
= m_children
.Count(); 
1626         for (size_t n 
= 0; n 
< count
; ++n 
) { 
1627             m_children
[n
]->GetSize (x
, y
, theButton
); 
1632 wxTreeListItem 
*wxTreeListItem::HitTest (const wxPoint
& point
, 
1633                                          const wxTreeListMainWindow 
*theCtrl
, 
1634                                          int &flags
, int& column
, int level
) { 
1636     // for a hidden root node, don't evaluate it, but do evaluate children 
1637     if (!theCtrl
->HasFlag(wxTR_HIDE_ROOT
) || (level 
> 0)) { 
1639         // reset any previous hit infos 
1642         wxTreeListHeaderWindow
* header_win 
= theCtrl
->m_owner
->GetHeaderWindow(); 
1644         // check for right of all columns (outside) 
1645         if (point
.x 
> header_win
->GetWidth()) return (wxTreeListItem
*) NULL
; 
1647         // evaluate if y-pos is okay 
1648         int h 
= theCtrl
->GetLineHeight (this); 
1649         if ((point
.y 
>= m_y
) && (point
.y 
<= m_y 
+ h
)) { 
1651             int maincol 
= theCtrl
->GetMainColumn(); 
1653             // check for above/below middle 
1654             int y_mid 
= m_y 
+ h
/2; 
1655             if (point
.y 
< y_mid
) { 
1656                 flags 
|= wxTREE_HITTEST_ONITEMUPPERPART
; 
1658                 flags 
|= wxTREE_HITTEST_ONITEMLOWERPART
; 
1661             // check for button hit 
1662             if (HasPlus() && theCtrl
->HasButtons()) { 
1663                 int bntX 
= m_x 
- theCtrl
->m_btnWidth2
; 
1664                 int bntY 
= y_mid 
- theCtrl
->m_btnHeight2
; 
1665                 if ((point
.x 
>= bntX
) && (point
.x 
<= (bntX 
+ theCtrl
->m_btnWidth
)) && 
1666                     (point
.y 
>= bntY
) && (point
.y 
<= (bntY 
+ theCtrl
->m_btnHeight
))) { 
1667                     flags 
|= wxTREE_HITTEST_ONITEMBUTTON
; 
1673             // check for image hit 
1674             if (theCtrl
->m_imgWidth 
> 0) { 
1675                 int imgX 
= m_text_x 
- theCtrl
->m_imgWidth 
- MARGIN
; 
1676                 int imgY 
= y_mid 
- theCtrl
->m_imgHeight2
; 
1677                 if ((point
.x 
>= imgX
) && (point
.x 
<= (imgX 
+ theCtrl
->m_imgWidth
)) && 
1678                     (point
.y 
>= imgY
) && (point
.y 
<= (imgY 
+ theCtrl
->m_imgHeight
))) { 
1679                     flags 
|= wxTREE_HITTEST_ONITEMICON
; 
1685             // check for label hit 
1686             if ((point
.x 
>= m_text_x
) && (point
.x 
<= (m_text_x 
+ m_width
))) { 
1687                 flags 
|= wxTREE_HITTEST_ONITEMLABEL
; 
1692             // check for indent hit after button and image hit 
1693             if (point
.x 
< m_x
) { 
1694                 flags 
|= wxTREE_HITTEST_ONITEMINDENT
; 
1695                 column 
= -1; // considered not belonging to main column 
1699             // check for right of label 
1701             for (int i 
= 0; i 
<= maincol
; ++i
) end 
+= header_win
->GetColumnWidth (i
); 
1702             if ((point
.x 
> (m_text_x 
+ m_width
)) && (point
.x 
<= end
)) { 
1703                 flags 
|= wxTREE_HITTEST_ONITEMRIGHT
; 
1704                 column 
= -1; // considered not belonging to main column 
1708             // else check for each column except main 
1710             for (int j 
= 0; j 
< theCtrl
->GetColumnCount(); ++j
) { 
1711                 if (!header_win
->IsColumnShown(j
)) continue; 
1712                 int w 
= header_win
->GetColumnWidth (j
); 
1713                 if ((j 
!= maincol
) && (point
.x 
>= x 
&& point
.x 
< x
+w
)) { 
1714                     flags 
|= wxTREE_HITTEST_ONITEMCOLUMN
; 
1721             // no special flag or column found 
1726         // if children not expanded, return no item 
1727         if (!IsExpanded()) return (wxTreeListItem
*) NULL
; 
1730     // in any case evaluate children 
1731     wxTreeListItem 
*child
; 
1732     size_t count 
= m_children
.Count(); 
1733     for (size_t n 
= 0; n 
< count
; n
++) { 
1734         child 
= m_children
[n
]->HitTest (point
, theCtrl
, flags
, column
, level
+1); 
1735         if (child
) return child
; 
1739     return (wxTreeListItem
*) NULL
; 
1742 int wxTreeListItem::GetCurrentImage() const { 
1743     int image 
= NO_IMAGE
; 
1746             image 
= GetImage (wxTreeItemIcon_SelectedExpanded
); 
1748             image 
= GetImage (wxTreeItemIcon_Expanded
); 
1750     }else{ // not expanded 
1752             image 
= GetImage (wxTreeItemIcon_Selected
); 
1754             image 
= GetImage (wxTreeItemIcon_Normal
); 
1758     // maybe it doesn't have the specific image, try the default one instead 
1759     if (image 
== NO_IMAGE
) image 
= GetImage(); 
1764 // --------------------------------------------------------------------------- 
1765 // wxTreeListMainWindow implementation 
1766 // --------------------------------------------------------------------------- 
1768 IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow
, wxScrolledWindow
) 
1770 BEGIN_EVENT_TABLE(wxTreeListMainWindow
, wxScrolledWindow
) 
1771     EVT_PAINT          (wxTreeListMainWindow::OnPaint
) 
1772     EVT_MOUSE_EVENTS   (wxTreeListMainWindow::OnMouse
) 
1773     EVT_CHAR           (wxTreeListMainWindow::OnChar
) 
1774     EVT_SET_FOCUS      (wxTreeListMainWindow::OnSetFocus
) 
1775     EVT_KILL_FOCUS     (wxTreeListMainWindow::OnKillFocus
) 
1776     EVT_IDLE           (wxTreeListMainWindow::OnIdle
) 
1777     EVT_SCROLLWIN      (wxTreeListMainWindow::OnScroll
) 
1781 // --------------------------------------------------------------------------- 
1782 // construction/destruction 
1783 // --------------------------------------------------------------------------- 
1785 void wxTreeListMainWindow::Init() { 
1787     m_rootItem 
= (wxTreeListItem
*)NULL
; 
1788     m_curItem 
= (wxTreeListItem
*)NULL
; 
1789     m_shiftItem 
= (wxTreeListItem
*)NULL
; 
1790     m_editItem 
= (wxTreeListItem
*)NULL
; 
1791     m_selectItem 
= (wxTreeListItem
*)NULL
; 
1793     m_curColumn 
= -1; // no current column 
1798     m_lineHeight 
= LINEHEIGHT
; 
1799     m_indent 
= MININDENT
; // min. indent 
1802 #if !wxCHECK_VERSION(2, 5, 0) 
1803     m_hilightBrush 
= new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
); 
1804     m_hilightUnfocusedBrush 
= new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW
), wxSOLID
); 
1806     m_hilightBrush 
= new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT
), wxSOLID
); 
1807     m_hilightUnfocusedBrush 
= new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW
), wxSOLID
); 
1810     m_imageListNormal 
= (wxImageList 
*) NULL
; 
1811     m_imageListButtons 
= (wxImageList 
*) NULL
; 
1812     m_imageListState 
= (wxImageList 
*) NULL
; 
1813     m_ownsImageListNormal 
= m_ownsImageListButtons 
= 
1814     m_ownsImageListState 
= false; 
1816     m_imgWidth 
= 0, m_imgWidth2 
= 0; 
1817     m_imgHeight 
= 0, m_imgHeight2 
= 0; 
1818     m_btnWidth 
= 0, m_btnWidth2 
= 0; 
1819     m_btnHeight 
= 0, m_btnHeight2 
= 0; 
1822     m_isDragging 
= false; 
1823     m_dragTimer 
= new wxTimer (this, -1); 
1824     m_dragItem 
= (wxTreeListItem
*)NULL
; 
1826     m_renameTimer 
= new wxTreeListRenameTimer (this); 
1827     m_lastOnSame 
= false; 
1828     m_left_down_selection 
= false; 
1830     m_findTimer 
= new wxTimer (this, -1); 
1832 #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__) 
1833     m_normalFont
.MacCreateThemeFont (kThemeViewsFont
); 
1835     m_normalFont 
= wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT
); 
1837     m_boldFont 
= wxFont( m_normalFont
.GetPointSize(), 
1838                          m_normalFont
.GetFamily(), 
1839                          m_normalFont
.GetStyle(), 
1841                          m_normalFont
.GetUnderlined(), 
1842                          m_normalFont
.GetFaceName(), 
1843                          m_normalFont
.GetEncoding()); 
1846 bool wxTreeListMainWindow::Create (wxTreeListCtrl 
*parent
, 
1851                                    const wxValidator 
&validator
, 
1852                                    const wxString
& name
) { 
1855     style 
&= ~wxTR_LINES_AT_ROOT
; 
1856     style 
|= wxTR_NO_LINES
; 
1859     wxGetOsVersion( &major
, &minor 
); 
1860     if (major 
< 10) style 
|= wxTR_ROW_LINES
; 
1863     wxScrolledWindow::Create (parent
, id
, pos
, size
, style
|wxHSCROLL
|wxVSCROLL
|wxWANTS_CHARS
, name
); 
1865 #if wxUSE_VALIDATORS 
1866     SetValidator(validator
); 
1869 #if !wxCHECK_VERSION(2, 5, 0) 
1870     SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX
)); 
1872     SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX
)); 
1880         bdc
.SelectObject(bmp
); 
1881         bdc
.SetPen(*wxGREY_PEN
); 
1882         bdc
.DrawRectangle(-1, -1, 10, 10); 
1883         for (i 
= 0; i 
< 8; i
++) { 
1884             for (j 
= 0; j 
< 8; j
++) { 
1885                 if (!((i 
+ j
) & 1)) { 
1886                     bdc
.DrawPoint(i
, j
); 
1891         m_dottedPen 
= wxPen(bmp
, 1); 
1894 //?    m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT );  // too slow under XFree86 
1895     m_dottedPen 
= wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK! 
1904 wxTreeListMainWindow::~wxTreeListMainWindow() { 
1905     delete m_hilightBrush
; 
1906     delete m_hilightUnfocusedBrush
; 
1909     delete m_renameTimer
; 
1911     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
1912     if (m_ownsImageListState
) delete m_imageListState
; 
1913     if (m_ownsImageListButtons
) delete m_imageListButtons
; 
1919 //----------------------------------------------------------------------------- 
1921 //----------------------------------------------------------------------------- 
1923 size_t wxTreeListMainWindow::GetCount() const { 
1924     return m_rootItem 
== NULL
? 0: m_rootItem
->GetChildrenCount(); 
1927 void wxTreeListMainWindow::SetIndent (unsigned int indent
) { 
1928     m_indent 
= wxMax ((unsigned)MININDENT
, indent
); 
1932 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing
) { 
1933     m_linespacing 
= spacing
; 
1935     CalculateLineHeight(); 
1938 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId
& item
, 
1940     wxCHECK_MSG (item
.IsOk(), 0u, _T("invalid tree item")); 
1941     return ((wxTreeListItem
*)item
.m_pItem
)->GetChildrenCount (recursively
); 
1944 void wxTreeListMainWindow::SetWindowStyle (const long styles
) { 
1945     // right now, just sets the styles.  Eventually, we may 
1946     // want to update the inherited styles, but right now 
1947     // none of the parents has updatable styles 
1948     m_windowStyle 
= styles
; 
1952 //----------------------------------------------------------------------------- 
1953 // functions to work with tree items 
1954 //----------------------------------------------------------------------------- 
1956 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId
& item
, int column
, 
1957                                         wxTreeItemIcon which
) const { 
1958     wxCHECK_MSG (item
.IsOk(), -1, _T("invalid tree item")); 
1959     return ((wxTreeListItem
*) item
.m_pItem
)->GetImage (column
, which
); 
1962 wxTreeItemData 
*wxTreeListMainWindow::GetItemData (const wxTreeItemId
& item
) const { 
1963     wxCHECK_MSG (item
.IsOk(), NULL
, _T("invalid tree item")); 
1964     return ((wxTreeListItem
*) item
.m_pItem
)->GetData(); 
1967 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId
& item
) const { 
1968     wxCHECK_MSG(item
.IsOk(), false, _T("invalid tree item")); 
1969     return ((wxTreeListItem 
*)item
.m_pItem
)->IsBold(); 
1972 wxColour 
wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId
& item
) const { 
1973     wxCHECK_MSG (item
.IsOk(), wxNullColour
, _T("invalid tree item")); 
1974     wxTreeListItem 
*pItem 
= (wxTreeListItem
*) item
.m_pItem
; 
1975     return pItem
->Attr().GetTextColour(); 
1978 wxColour 
wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId
& item
) const { 
1979     wxCHECK_MSG (item
.IsOk(), wxNullColour
, _T("invalid tree item")); 
1980     wxTreeListItem 
*pItem 
= (wxTreeListItem
*) item
.m_pItem
; 
1981     return pItem
->Attr().GetBackgroundColour(); 
1984 wxFont 
wxTreeListMainWindow::GetItemFont (const wxTreeItemId
& item
) const { 
1985     wxCHECK_MSG (item
.IsOk(), wxNullFont
, _T("invalid tree item")); 
1986     wxTreeListItem 
*pItem 
= (wxTreeListItem
*) item
.m_pItem
; 
1987     return pItem
->Attr().GetFont(); 
1990 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId
& item
, int column
, 
1991                                          int image
, wxTreeItemIcon which
) { 
1992     wxCHECK_RET (item
.IsOk(), _T("invalid tree item")); 
1993     wxTreeListItem 
*pItem 
= (wxTreeListItem
*) item
.m_pItem
; 
1994     pItem
->SetImage (column
, image
, which
); 
1995     wxClientDC 
dc (this); 
1996     CalculateSize (pItem
, dc
); 
1997     RefreshLine (pItem
); 
2000 void wxTreeListMainWindow::SetItemData (const wxTreeItemId
& item
, 
2001                                         wxTreeItemData 
*data
) { 
2002     wxCHECK_RET (item
.IsOk(), _T("invalid tree item")); 
2003     ((wxTreeListItem
*) item
.m_pItem
)->SetData(data
); 
2006 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId
& item
, 
2008     wxCHECK_RET (item
.IsOk(), _T("invalid tree item")); 
2009     wxTreeListItem 
*pItem 
= (wxTreeListItem
*) item
.m_pItem
; 
2010     pItem
->SetHasPlus (has
); 
2011     RefreshLine (pItem
); 
2014 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId
& item
, bool bold
) { 
2015     wxCHECK_RET (item
.IsOk(), _T("invalid tree item")); 
2016     wxTreeListItem 
*pItem 
= (wxTreeListItem
*) item
.m_pItem
; 
2017     if (pItem
->IsBold() != bold
) { // avoid redrawing if no real change 
2018         pItem
->SetBold (bold
); 
2019         RefreshLine (pItem
); 
2023 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId
& item
, 
2024                                               const wxColour
& colour
) { 
2025     wxCHECK_RET (item
.IsOk(), _T("invalid tree item")); 
2026     wxTreeListItem 
*pItem 
= (wxTreeListItem
*) item
.m_pItem
; 
2027     pItem
->Attr().SetTextColour (colour
); 
2028     RefreshLine (pItem
); 
2031 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId
& item
, 
2032                                                     const wxColour
& colour
) { 
2033     wxCHECK_RET (item
.IsOk(), _T("invalid tree item")); 
2034     wxTreeListItem 
*pItem 
= (wxTreeListItem
*) item
.m_pItem
; 
2035     pItem
->Attr().SetBackgroundColour (colour
); 
2036     RefreshLine (pItem
); 
2039 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId
& item
, 
2040                                         const wxFont
& font
) { 
2041     wxCHECK_RET (item
.IsOk(), _T("invalid tree item")); 
2042     wxTreeListItem 
*pItem 
= (wxTreeListItem
*) item
.m_pItem
; 
2043     pItem
->Attr().SetFont (font
); 
2044     RefreshLine (pItem
); 
2047 bool wxTreeListMainWindow::SetFont (const wxFont 
&font
) { 
2048     wxScrolledWindow::SetFont (font
); 
2049     m_normalFont 
= font
; 
2050     m_boldFont 
= wxFont (m_normalFont
.GetPointSize(), 
2051                          m_normalFont
.GetFamily(), 
2052                          m_normalFont
.GetStyle(), 
2054                          m_normalFont
.GetUnderlined(), 
2055                          m_normalFont
.GetFaceName()); 
2056     CalculateLineHeight(); 
2061 // ---------------------------------------------------------------------------- 
2062 // item status inquiries 
2063 // ---------------------------------------------------------------------------- 
2065 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId
& item
, bool fullRow
) const { 
2066     wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item")); 
2068     // An item is only visible if it's not a descendant of a collapsed item 
2069     wxTreeListItem 
*pItem 
= (wxTreeListItem
*) item
.m_pItem
; 
2070     wxTreeListItem
* parent 
= pItem
->GetItemParent(); 
2072         if (parent 
== m_rootItem 
&& HasFlag(wxTR_HIDE_ROOT
)) break; 
2073         if (!parent
->IsExpanded()) return false; 
2074         parent 
= parent
->GetItemParent(); 
2077     wxSize clientSize 
= GetClientSize(); 
2079     if ((!GetBoundingRect (item
, rect
)) || 
2080         ((!fullRow 
&& rect
.GetWidth() == 0) || rect
.GetHeight() == 0) || 
2081         (rect
.GetBottom() < 0 || rect
.GetTop() > clientSize
.y
) || 
2082         (!fullRow 
&& (rect
.GetRight() < 0 || rect
.GetLeft() > clientSize
.x
))) return false; 
2087 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId
& item
) const { 
2088     wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item")); 
2090     // consider that the item does have children if it has the "+" button: it 
2091     // might not have them (if it had never been expanded yet) but then it 
2092     // could have them as well and it's better to err on this side rather than 
2093     // disabling some operations which are restricted to the items with 
2094     // children for an item which does have them 
2095     return ((wxTreeListItem
*) item
.m_pItem
)->HasPlus(); 
2098 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId
& item
) const { 
2099     wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item")); 
2100     return ((wxTreeListItem
*) item
.m_pItem
)->IsExpanded(); 
2103 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId
& item
) const { 
2104     wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item")); 
2105     return ((wxTreeListItem
*) item
.m_pItem
)->IsSelected(); 
2108 bool wxTreeListMainWindow::IsBold (const wxTreeItemId
& item
) const { 
2109     wxCHECK_MSG (item
.IsOk(), false, _T("invalid tree item")); 
2110     return ((wxTreeListItem
*) item
.m_pItem
)->IsBold(); 
2113 // ---------------------------------------------------------------------------- 
2115 // ---------------------------------------------------------------------------- 
2117 wxTreeItemId 
wxTreeListMainWindow::GetItemParent (const wxTreeItemId
& item
) const { 
2118     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2119     return ((wxTreeListItem
*) item
.m_pItem
)->GetItemParent(); 
2122 #if !wxCHECK_VERSION(2, 5, 0) 
2123 wxTreeItemId 
wxTreeListMainWindow::GetFirstChild (const wxTreeItemId
& item
, 
2124                                                   long& cookie
) const { 
2126 wxTreeItemId 
wxTreeListMainWindow::GetFirstChild (const wxTreeItemId
& item
, 
2127                                                   wxTreeItemIdValue
& cookie
) const { 
2129     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2130     wxArrayTreeListItems
& children 
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren(); 
2132     return (!children
.IsEmpty())? wxTreeItemId(children
.Item(0)): wxTreeItemId(); 
2135 #if !wxCHECK_VERSION(2, 5, 0) 
2136 wxTreeItemId 
wxTreeListMainWindow::GetNextChild (const wxTreeItemId
& item
, 
2137                                                  long& cookie
) const { 
2139 wxTreeItemId 
wxTreeListMainWindow::GetNextChild (const wxTreeItemId
& item
, 
2140                                                  wxTreeItemIdValue
& cookie
) const { 
2142     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2143     wxArrayTreeListItems
& children 
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren(); 
2144     // it's ok to cast cookie to long, we never have indices which overflow "void*" 
2145     long *pIndex 
= ((long*)&cookie
); 
2146     return ((*pIndex
)+1 < (long)children
.Count())? wxTreeItemId(children
.Item(++(*pIndex
))): wxTreeItemId(); 
2149 #if !wxCHECK_VERSION(2, 5, 0) 
2150 wxTreeItemId 
wxTreeListMainWindow::GetPrevChild (const wxTreeItemId
& item
, 
2151                                                  long& cookie
) const { 
2153 wxTreeItemId 
wxTreeListMainWindow::GetPrevChild (const wxTreeItemId
& item
, 
2154                                                  wxTreeItemIdValue
& cookie
) const { 
2156     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2157     wxArrayTreeListItems
& children 
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren(); 
2158     // it's ok to cast cookie to long, we never have indices which overflow "void*" 
2159     long *pIndex 
= (long*)&cookie
; 
2160     return ((*pIndex
)-1 >= 0)? wxTreeItemId(children
.Item(--(*pIndex
))): wxTreeItemId(); 
2163 #if !wxCHECK_VERSION(2, 5, 0) 
2164 wxTreeItemId 
wxTreeListMainWindow::GetLastChild (const wxTreeItemId
& item
, 
2165                                                  long& cookie
) const { 
2167 wxTreeItemId 
wxTreeListMainWindow::GetLastChild (const wxTreeItemId
& item
, 
2168                                                  wxTreeItemIdValue
& cookie
) const { 
2170     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2171     wxArrayTreeListItems
& children 
= ((wxTreeListItem
*) item
.m_pItem
)->GetChildren(); 
2172     // it's ok to cast cookie to long, we never have indices which overflow "void*" 
2173     long *pIndex 
= ((long*)&cookie
); 
2174     (*pIndex
) = children
.Count(); 
2175     return (!children
.IsEmpty())? wxTreeItemId(children
.Last()): wxTreeItemId(); 
2178 wxTreeItemId 
wxTreeListMainWindow::GetNextSibling (const wxTreeItemId
& item
) const { 
2179     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2182     wxTreeListItem 
*i 
= (wxTreeListItem
*) item
.m_pItem
; 
2183     wxTreeListItem 
*parent 
= i
->GetItemParent(); 
2184     if (!parent
) return wxTreeItemId(); // root item doesn't have any siblings 
2187     wxArrayTreeListItems
& siblings 
= parent
->GetChildren(); 
2188     size_t index 
= siblings
.Index (i
); 
2189     wxASSERT (index 
!= (size_t)wxNOT_FOUND
); // I'm not a child of my parent? 
2190     return (index 
< siblings
.Count()-1)? wxTreeItemId(siblings
[index
+1]): wxTreeItemId(); 
2193 wxTreeItemId 
wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId
& item
) const { 
2194     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2197     wxTreeListItem 
*i 
= (wxTreeListItem
*) item
.m_pItem
; 
2198     wxTreeListItem 
*parent 
= i
->GetItemParent(); 
2199     if (!parent
) return wxTreeItemId(); // root item doesn't have any siblings 
2202     wxArrayTreeListItems
& siblings 
= parent
->GetChildren(); 
2203     size_t index 
= siblings
.Index(i
); 
2204     wxASSERT (index 
!= (size_t)wxNOT_FOUND
); // I'm not a child of my parent? 
2205     return (index 
>= 1)? wxTreeItemId(siblings
[index
-1]): wxTreeItemId(); 
2208 // Only for internal use right now, but should probably be public 
2209 wxTreeItemId 
wxTreeListMainWindow::GetNext (const wxTreeItemId
& item
, bool fulltree
) const { 
2210     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2212     // if there are any children, return first child 
2213     if (fulltree 
|| ((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) { 
2214         wxArrayTreeListItems
& children 
= ((wxTreeListItem
*)item
.m_pItem
)->GetChildren(); 
2215         if (children
.GetCount() > 0) return children
.Item (0); 
2218     // get sibling of this item or of the ancestors instead 
2220     wxTreeItemId parent 
= item
; 
2222         next 
= GetNextSibling (parent
); 
2223         parent 
= GetItemParent (parent
); 
2224     } while (!next
.IsOk() && parent
.IsOk()); 
2228 // Only for internal use right now, but should probably be public 
2229 wxTreeItemId 
wxTreeListMainWindow::GetPrev (const wxTreeItemId
& item
, bool fulltree
) const { 
2230     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2232     // if there are any children, return last child 
2233     if (fulltree 
|| ((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) { 
2234         wxArrayTreeListItems
& children 
= ((wxTreeListItem
*)item
.m_pItem
)->GetChildren(); 
2235         if (children
.GetCount() > 0) return children
.Item (children
.GetCount()-1); 
2238     // get sibling of this item or of the ancestors instead 
2240     wxTreeItemId parent 
= item
; 
2242         next 
= GetPrevSibling (parent
); 
2243         parent 
= GetItemParent (parent
); 
2244     } while (!next
.IsOk() && parent
.IsOk()); 
2248 wxTreeItemId 
wxTreeListMainWindow::GetFirstExpandedItem() const { 
2249     return GetNextExpanded (GetRootItem()); 
2252 wxTreeItemId 
wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId
& item
) const { 
2253     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2254     return GetNext (item
, false); 
2257 wxTreeItemId 
wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId
& item
) const { 
2258     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2259     return GetPrev (item
, false); 
2262 wxTreeItemId 
wxTreeListMainWindow::GetFirstVisibleItem (bool fullRow
) const { 
2263     return GetNextVisible (GetRootItem(), fullRow
); 
2266 wxTreeItemId 
wxTreeListMainWindow::GetNextVisible (const wxTreeItemId
& item
, bool fullRow
) const { 
2267     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2268     wxTreeItemId id 
= GetNext (item
, false); 
2270         if (IsVisible (id
, fullRow
)) return id
; 
2271         id 
= GetNext (id
, false); 
2273     return wxTreeItemId(); 
2276 wxTreeItemId 
wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId
& item
, bool fullRow
) const { 
2277     wxCHECK_MSG (item
.IsOk(), wxTreeItemId(), _T("invalid tree item")); 
2278     wxTreeItemId id 
= GetPrev (item
, true); 
2280         if (IsVisible (id
, fullRow
)) return id
; 
2281         id 
= GetPrev(id
, true); 
2283     return wxTreeItemId(); 
2286 // ---------------------------------------------------------------------------- 
2288 // ---------------------------------------------------------------------------- 
2290 wxTreeItemId 
wxTreeListMainWindow::DoInsertItem (const wxTreeItemId
& parentId
, 
2292                                                  const wxString
& text
, 
2293                                                  int image
, int selImage
, 
2294                                                  wxTreeItemData 
*data
) { 
2295     wxTreeListItem 
*parent 
= (wxTreeListItem
*)parentId
.m_pItem
; 
2296     wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") ); 
2297     m_dirty 
= true; // do this first so stuff below doesn't cause flicker 
2300     arr
.Alloc (GetColumnCount()); 
2301     for (int i 
= 0; i 
< (int)GetColumnCount(); ++i
) arr
.Add (wxEmptyString
); 
2302     arr
[m_main_column
] = text
; 
2303     wxTreeListItem 
*item 
= new wxTreeListItem (this, parent
, arr
, image
, selImage
, data
); 
2305 #if !wxCHECK_VERSION(2, 5, 0) 
2306         data
->SetId ((long)item
); 
2311     parent
->Insert (item
, previous
); 
2316 wxTreeItemId 
wxTreeListMainWindow::AddRoot (const wxString
& text
, 
2317                                             int image
, int selImage
, 
2318                                             wxTreeItemData 
*data
) { 
2319     wxCHECK_MSG(!m_rootItem
, wxTreeItemId(), _T("tree can have only one root")); 
2320     wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item")); 
2321     m_dirty 
= true; // do this first so stuff below doesn't cause flicker 
2324     arr
.Alloc (GetColumnCount()); 
2325     for (int i 
= 0; i 
< (int)GetColumnCount(); ++i
) arr
.Add (wxEmptyString
); 
2326     arr
[m_main_column
] = text
; 
2327     m_rootItem 
= new wxTreeListItem (this, (wxTreeListItem 
*)NULL
, arr
, image
, selImage
, data
); 
2329 #if !wxCHECK_VERSION(2, 5, 0) 
2330         data
->SetId((long)m_rootItem
); 
2332         data
->SetId(m_rootItem
); 
2335     if (HasFlag(wxTR_HIDE_ROOT
)) { 
2336         // if we will hide the root, make sure children are visible 
2337         m_rootItem
->SetHasPlus(); 
2338         m_rootItem
->Expand(); 
2339 #if !wxCHECK_VERSION(2, 5, 0) 
2342         wxTreeItemIdValue cookie 
= 0; 
2344         m_curItem 
= (wxTreeListItem
*)GetFirstChild (m_rootItem
, cookie
).m_pItem
; 
2349 wxTreeItemId 
wxTreeListMainWindow::PrependItem (const wxTreeItemId
& parent
, 
2350                                                 const wxString
& text
, 
2351                                                 int image
, int selImage
, 
2352                                                 wxTreeItemData 
*data
) { 
2353     return DoInsertItem (parent
, 0u, text
, image
, selImage
, data
); 
2356 wxTreeItemId 
wxTreeListMainWindow::InsertItem (const wxTreeItemId
& parentId
, 
2357                                                const wxTreeItemId
& idPrevious
, 
2358                                                const wxString
& text
, 
2359                                                int image
, int selImage
, 
2360                                                wxTreeItemData 
*data
) { 
2361     wxTreeListItem 
*parent 
= (wxTreeListItem
*)parentId
.m_pItem
; 
2362     wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") ); 
2364     int index 
= parent
->GetChildren().Index((wxTreeListItem
*) idPrevious
.m_pItem
); 
2365     wxASSERT_MSG( index 
!= wxNOT_FOUND
, 
2366                   _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") ); 
2368     return DoInsertItem (parentId
, ++index
, text
, image
, selImage
, data
); 
2371 wxTreeItemId 
wxTreeListMainWindow::InsertItem (const wxTreeItemId
& parentId
, 
2373                                                const wxString
& text
, 
2374                                                int image
, int selImage
, 
2375                                                wxTreeItemData 
*data
) { 
2376     wxTreeListItem 
*parent 
= (wxTreeListItem
*)parentId
.m_pItem
; 
2377     wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") ); 
2379     return DoInsertItem (parentId
, before
, text
, image
, selImage
, data
); 
2382 wxTreeItemId 
wxTreeListMainWindow::AppendItem (const wxTreeItemId
& parentId
, 
2383                                                const wxString
& text
, 
2384                                                int image
, int selImage
, 
2385                                                wxTreeItemData 
*data
) { 
2386     wxTreeListItem 
*parent 
= (wxTreeListItem
*) parentId
.m_pItem
; 
2387     wxCHECK_MSG (parent
, wxTreeItemId(), _T("item must have a parent, at least root!") ); 
2389     return DoInsertItem (parent
, parent
->GetChildren().Count(), text
, image
, selImage
, data
); 
2392 void wxTreeListMainWindow::SendDeleteEvent (wxTreeListItem 
*item
) { 
2393     // send event to user code 
2394     wxTreeEvent 
event (wxEVT_COMMAND_TREE_DELETE_ITEM
, m_owner
->GetId()); 
2395 #if !wxCHECK_VERSION(2, 5, 0) 
2396     event
.SetItem ((long)item
); 
2398     event
.SetItem (item
); 
2400     event
.SetEventObject (m_owner
); 
2401     m_owner
->ProcessEvent (event
); 
2404 void wxTreeListMainWindow::Delete (const wxTreeItemId
& itemId
) { 
2405     wxTreeListItem 
*item 
= (wxTreeListItem
*) itemId
.m_pItem
; 
2406     wxCHECK_RET (item 
!= m_rootItem
, _T("invalid item, root may not be deleted this way!")); 
2407     m_dirty 
= true; // do this first so stuff below doesn't cause flicker 
2409     // don't stay with invalid m_shiftItem or we will crash in the next call to OnChar() 
2410     bool changeKeyCurrent 
= false; 
2411     wxTreeListItem 
*itemKey 
= m_shiftItem
; 
2413         if (itemKey 
== item
) { // m_shiftItem is a descendant of the item being deleted 
2414             changeKeyCurrent 
= true; 
2417         itemKey 
= itemKey
->GetItemParent(); 
2420     wxTreeListItem 
*parent 
= item
->GetItemParent(); 
2422         parent
->GetChildren().Remove (item
);  // remove by value 
2424     if (changeKeyCurrent
)  m_shiftItem 
= parent
; 
2426     SendDeleteEvent (item
); 
2427     if (m_selectItem 
== item
) m_selectItem 
= (wxTreeListItem
*)NULL
; 
2428     item
->DeleteChildren (this); 
2432 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId
& itemId
) { 
2433     wxTreeListItem 
*item 
= (wxTreeListItem
*) itemId
.m_pItem
; 
2434     m_dirty 
= true; // do this first so stuff below doesn't cause flicker 
2436     item
->DeleteChildren (this); 
2439 void wxTreeListMainWindow::DeleteRoot() { 
2442         SendDeleteEvent (m_rootItem
); 
2443         m_curItem 
= (wxTreeListItem
*)NULL
; 
2444         m_selectItem
= (wxTreeListItem
*)NULL
; 
2445         m_rootItem
->DeleteChildren (this); 
2451 void wxTreeListMainWindow::Expand (const wxTreeItemId
& itemId
) { 
2452     wxTreeListItem 
*item 
= (wxTreeListItem
*) itemId
.m_pItem
; 
2453     wxCHECK_RET (item
, _T("invalid item in wxTreeListMainWindow::Expand") ); 
2455     if (!item
->HasPlus() || item
->IsExpanded()) return; 
2457     // send event to user code 
2458     wxTreeEvent 
event (wxEVT_COMMAND_TREE_ITEM_EXPANDING
, m_owner
->GetId()); 
2459 #if !wxCHECK_VERSION(2, 5, 0) 
2460     event
.SetItem ((long)item
); 
2462     event
.SetItem (item
); 
2464     event
.SetEventObject (m_owner
); 
2465     if (m_owner
->ProcessEvent (event
) && !event
.IsAllowed()) return; // expand canceled 
2470     // send event to user code 
2471     event
.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED
); 
2472     m_owner
->ProcessEvent (event
); 
2475 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId
& itemId
) { 
2477     if (!IsExpanded (itemId
)) return; 
2478 #if !wxCHECK_VERSION(2, 5, 0) 
2481     wxTreeItemIdValue cookie
; 
2483     wxTreeItemId child 
= GetFirstChild (itemId
, cookie
); 
2484     while (child
.IsOk()) { 
2486         child 
= GetNextChild (itemId
, cookie
); 
2490 void wxTreeListMainWindow::Collapse (const wxTreeItemId
& itemId
) { 
2491     wxTreeListItem 
*item 
= (wxTreeListItem
*) itemId
.m_pItem
; 
2492     wxCHECK_RET (item
, _T("invalid item in wxTreeListMainWindow::Collapse") ); 
2494     if (!item
->HasPlus() || !item
->IsExpanded()) return; 
2496     // send event to user code 
2497     wxTreeEvent 
event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING
, m_owner
->GetId() ); 
2498 #if !wxCHECK_VERSION(2, 5, 0) 
2499     event
.SetItem ((long)item
); 
2501     event
.SetItem (item
); 
2503     event
.SetEventObject (m_owner
); 
2504     if (m_owner
->ProcessEvent (event
) && !event
.IsAllowed()) return; // collapse canceled 
2509     // send event to user code 
2510     event
.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED
); 
2511     ProcessEvent (event
); 
2514 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId
& item
) { 
2516     DeleteChildren (item
); 
2519 void wxTreeListMainWindow::Toggle (const wxTreeItemId
& itemId
) { 
2520     if (IsExpanded (itemId
)) { 
2527 void wxTreeListMainWindow::Unselect() { 
2529         m_selectItem
->SetHilight (false); 
2530         RefreshLine (m_selectItem
); 
2531         m_selectItem 
= (wxTreeListItem
*)NULL
; 
2535 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem 
*item
) { 
2536     if (item
->IsSelected()) { 
2537         item
->SetHilight (false); 
2539         if (item 
== m_selectItem
) m_selectItem 
= (wxTreeListItem
*)NULL
; 
2541     if (item
->HasChildren()) { 
2542         wxArrayTreeListItems
& children 
= item
->GetChildren(); 
2543         size_t count 
= children
.Count(); 
2544         for (size_t n 
= 0; n 
< count
; ++n
) { 
2545             UnselectAllChildren (children
[n
]); 
2550 void wxTreeListMainWindow::UnselectAll() { 
2551     UnselectAllChildren ((wxTreeListItem
*)GetRootItem().m_pItem
); 
2554 // Recursive function ! 
2555 // To stop we must have crt_item<last_item 
2557 // Tag all next children, when no more children, 
2558 // Move to parent (not to tag) 
2559 // Keep going... if we found last_item, we stop. 
2560 bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem 
*crt_item
, 
2561                                             wxTreeListItem 
*last_item
) { 
2562     wxTreeListItem 
*parent 
= crt_item
->GetItemParent(); 
2564     if (!parent
) {// This is root item 
2565         return TagAllChildrenUntilLast (crt_item
, last_item
); 
2568     wxArrayTreeListItems
& children 
= parent
->GetChildren(); 
2569     int index 
= children
.Index(crt_item
); 
2570     wxASSERT (index 
!= wxNOT_FOUND
); // I'm not a child of my parent? 
2572     if ((parent
->HasChildren() && parent
->IsExpanded()) || 
2573         ((parent 
== (wxTreeListItem
*)GetRootItem().m_pItem
) && HasFlag(wxTR_HIDE_ROOT
))) { 
2574         size_t count 
= children
.Count(); 
2575         for (size_t n 
= (index
+1); n 
< count
; ++n
) { 
2576             if (TagAllChildrenUntilLast (children
[n
], last_item
)) return true; 
2580     return TagNextChildren (parent
, last_item
); 
2583 bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem 
*crt_item
, 
2584                                                     wxTreeListItem 
*last_item
) { 
2585     crt_item
->SetHilight (true); 
2586     RefreshLine(crt_item
); 
2588     if (crt_item
==last_item
) return true; 
2590     if (crt_item
->HasChildren() && crt_item
->IsExpanded()) { 
2591         wxArrayTreeListItems
& children 
= crt_item
->GetChildren(); 
2592         size_t count 
= children
.Count(); 
2593         for (size_t n 
= 0; n 
< count
; ++n
) { 
2594             if (TagAllChildrenUntilLast (children
[n
], last_item
)) return true; 
2601 void wxTreeListMainWindow::SelectItem (const wxTreeItemId
& itemId
, 
2602                                        const wxTreeItemId
& lastId
, 
2603                                        bool unselect_others
) { 
2604     wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item") ); 
2606     bool is_single 
= !HasFlag(wxTR_MULTIPLE
); 
2607     wxTreeListItem 
*item 
= (wxTreeListItem
*) itemId
.m_pItem
; 
2609     // single selection requires unselect others 
2610     if (is_single
) unselect_others 
= true; 
2612     // send event to the user code 
2613     wxTreeEvent 
event( wxEVT_COMMAND_TREE_SEL_CHANGING
, m_owner
->GetId() ); 
2614 #if !wxCHECK_VERSION(2, 5, 0) 
2615     event
.SetItem ((long)item
); 
2616     event
.SetOldItem ((long)m_curItem
); 
2618     event
.SetItem (item
); 
2619     event
.SetOldItem (m_curItem
); 
2621     event
.SetEventObject (m_owner
); 
2622     if (m_owner
->GetEventHandler()->ProcessEvent (event
) && !event
.IsAllowed()) return; 
2624     // unselect all if unselect other items 
2625     bool unselected 
= false; // see that UnselectAll is done only once 
2626     if (unselect_others
) { 
2628             Unselect(); // to speed up thing 
2635     // select item or item range 
2636     if (lastId
.IsOk() && (itemId 
!= lastId
)) { 
2638         if (!unselected
) UnselectAll(); 
2639         wxTreeListItem 
*last 
= (wxTreeListItem
*) lastId
.m_pItem
; 
2641         // ensure that the position of the item it calculated in any case 
2642         if (m_dirty
) CalculatePositions(); 
2644         // select item range according Y-position 
2645         if (last
->GetY() < item
->GetY()) { 
2646             if (!TagAllChildrenUntilLast (last
, item
)) { 
2647                 TagNextChildren (last
, item
); 
2650             if (!TagAllChildrenUntilLast (item
, last
)) { 
2651                 TagNextChildren (item
, last
); 
2657         // select item according its old selection 
2658         item
->SetHilight (!item
->IsSelected()); 
2660         if (unselect_others
) { 
2661             m_selectItem 
= (item
->IsSelected())? item
: (wxTreeListItem
*)NULL
; 
2666     // send event to user code 
2667     event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
2668     m_owner
->GetEventHandler()->ProcessEvent (event
); 
2671 void wxTreeListMainWindow::SelectAll() { 
2672     wxCHECK_RET (HasFlag(wxTR_MULTIPLE
), _T("invalid tree style, must have wxTR_MULTIPLE style to select all items")); 
2674     // send event to user code 
2675     wxTreeEvent 
event (wxEVT_COMMAND_TREE_SEL_CHANGING
, m_owner
->GetId()); 
2676     event
.SetItem (GetRootItem()); 
2677 #if !wxCHECK_VERSION(2, 5, 0) 
2678     event
.SetOldItem ((long)m_curItem
); 
2680     event
.SetOldItem (m_curItem
); 
2682     event
.SetEventObject (m_owner
); 
2683     if (m_owner
->GetEventHandler()->ProcessEvent (event
) && !event
.IsAllowed()) return; 
2685 #if !wxCHECK_VERSION(2, 5, 0) 
2688     wxTreeItemIdValue cookie 
= 0; 
2690     wxTreeItemId root 
= GetRootItem(); 
2691     wxTreeListItem 
*first 
= (wxTreeListItem 
*)GetFirstChild (root
, cookie
).m_pItem
; 
2692     wxTreeListItem 
*last 
= (wxTreeListItem 
*)GetLastChild (root
, cookie
).m_pItem
; 
2693     if (!first 
|| !last
) return; 
2694     if (!TagAllChildrenUntilLast (first
, last
)) { 
2695         TagNextChildren (first
, last
); 
2698     // send event to user code 
2699     event
.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED
); 
2700     m_owner
->GetEventHandler()->ProcessEvent (event
); 
2703 void wxTreeListMainWindow::FillArray (wxTreeListItem 
*item
, 
2704                                       wxArrayTreeItemIds 
&array
) const { 
2705     if (item
->IsSelected()) array
.Add (wxTreeItemId(item
)); 
2707     if (item
->HasChildren()) { 
2708         wxArrayTreeListItems
& children 
= item
->GetChildren(); 
2709         size_t count 
= children
.GetCount(); 
2710         for (size_t n 
= 0; n 
< count
; ++n
) FillArray (children
[n
], array
); 
2714 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds 
&array
) const { 
2716     wxTreeItemId idRoot 
= GetRootItem(); 
2717     if (idRoot
.IsOk()) FillArray ((wxTreeListItem
*) idRoot
.m_pItem
, array
); 
2718     return array
.Count(); 
2721 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId
& item
) { 
2722     if (!item
.IsOk()) return; // do nothing if no item 
2724     // first expand all parent branches 
2725     wxTreeListItem 
*gitem 
= (wxTreeListItem
*) item
.m_pItem
; 
2726     wxTreeListItem 
*parent 
= gitem
->GetItemParent(); 
2729         parent 
= parent
->GetItemParent(); 
2733     RefreshLine (gitem
); 
2736 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId 
&item
) { 
2737     if (!item
.IsOk()) return; // do nothing if no item 
2739     // ensure that the position of the item it calculated in any case 
2740     if (m_dirty
) CalculatePositions(); 
2742     wxTreeListItem 
*gitem 
= (wxTreeListItem
*) item
.m_pItem
; 
2744     // now scroll to the item 
2745     int item_y 
= gitem
->GetY(); 
2748     GetScrollPixelsPerUnit (&xUnit
, &yUnit
); 
2751     GetViewStart (&start_x
, &start_y
); 
2756     GetClientSize (&client_w
, &client_h
); 
2760     m_rootItem
->GetSize (x
, y
, this); 
2761     x 
= m_owner
->GetHeaderWindow()->GetWidth(); 
2762     y 
+= yUnit 
+ 2; // one more scrollbar unit + 2 pixels 
2763     int x_pos 
= GetScrollPos( wxHORIZONTAL 
); 
2765     if (item_y 
< start_y
+3) { 
2766         // going down, item should appear at top 
2767         SetScrollbars (xUnit
, yUnit
, xUnit 
? x
/xUnit 
: 0, yUnit 
? y
/yUnit 
: 0, x_pos
, yUnit 
? item_y
/yUnit 
: 0); 
2768     }else if (item_y
+GetLineHeight(gitem
) > start_y
+client_h
) { 
2769         // going up, item should appear at bottom 
2770         item_y 
+= yUnit 
+ 2; 
2771         SetScrollbars (xUnit
, yUnit
, xUnit 
? x
/xUnit 
: 0, yUnit 
? y
/yUnit 
: 0, x_pos
, yUnit 
? (item_y
+GetLineHeight(gitem
)-client_h
)/yUnit 
: 0 ); 
2775 // FIXME: tree sorting functions are not reentrant and not MT-safe! 
2776 static wxTreeListMainWindow 
*s_treeBeingSorted 
= NULL
; 
2778 static int LINKAGEMODE 
tree_ctrl_compare_func(wxTreeListItem 
**item1
, 
2779                                   wxTreeListItem 
**item2
) 
2781     wxCHECK_MSG (s_treeBeingSorted
, 0, _T("bug in wxTreeListMainWindow::SortChildren()") ); 
2783     return s_treeBeingSorted
->OnCompareItems(*item1
, *item2
); 
2786 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId
& item1
, 
2787                                const wxTreeItemId
& item2
) 
2789     return m_owner
->OnCompareItems (item1
, item2
); 
2792 void wxTreeListMainWindow::SortChildren (const wxTreeItemId
& itemId
) { 
2793     wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item")); 
2795     wxTreeListItem 
*item 
= (wxTreeListItem
*) itemId
.m_pItem
; 
2797     wxCHECK_RET (!s_treeBeingSorted
, 
2798                  _T("wxTreeListMainWindow::SortChildren is not reentrant") ); 
2800     wxArrayTreeListItems
& children 
= item
->GetChildren(); 
2801     if ( children
.Count() > 1 ) { 
2803         s_treeBeingSorted 
= this; 
2804         children
.Sort(tree_ctrl_compare_func
); 
2805         s_treeBeingSorted 
= NULL
; 
2809 wxTreeItemId 
wxTreeListMainWindow::FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
) { 
2811     // determine start item 
2812     wxTreeItemId next 
= item
; 
2814         if (mode 
& wxTL_MODE_NAV_LEVEL
) { 
2815             next 
= GetNextSibling (next
); 
2816         }else if (mode 
& wxTL_MODE_NAV_VISIBLE
) { // 
2817             next 
= GetNextVisible (next
, false); 
2818         }else if (mode 
& wxTL_MODE_NAV_EXPANDED
) { 
2819             next 
= GetNextExpanded (next
); 
2820         }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default 
2821             next 
= GetNext (next
, true); 
2825 #if !wxCHECK_VERSION(2, 5, 0) 
2828     wxTreeItemIdValue cookie 
= 0; 
2831         next 
= (wxTreeListItem
*)GetRootItem().m_pItem
; 
2832         if (HasFlag(wxTR_HIDE_ROOT
)) { 
2833             next 
= (wxTreeListItem
*)GetFirstChild (GetRootItem().m_pItem
, cookie
).m_pItem
; 
2836     if (!next
.IsOk()) return (wxTreeItemId
*)NULL
; 
2838     // start checking the next items 
2839     while (next
.IsOk() && (next 
!= item
)) { 
2840         if (mode 
& wxTL_MODE_FIND_PARTIAL
) { 
2841             itemText 
= GetItemText (next
).Mid (0, str
.Length()); 
2843             itemText 
= GetItemText (next
); 
2845         if (mode 
& wxTL_MODE_FIND_NOCASE
) { 
2846             if (itemText
.CmpNoCase (str
) == 0) return next
; 
2848             if (itemText
.Cmp (str
) == 0) return next
; 
2850         if (mode 
& wxTL_MODE_NAV_LEVEL
) { 
2851             next 
= GetNextSibling (next
); 
2852         }else if (mode 
& wxTL_MODE_NAV_VISIBLE
) { // 
2853             next 
= GetNextVisible (next
, false); 
2854         }else if (mode 
& wxTL_MODE_NAV_EXPANDED
) { 
2855             next 
= GetNextExpanded (next
); 
2856         }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default 
2857             next 
= GetNext (next
, true); 
2859         if (!next
.IsOk() && item
.IsOk()) { 
2860             next 
= (wxTreeListItem
*)GetRootItem().m_pItem
; 
2861             if (HasFlag(wxTR_HIDE_ROOT
)) { 
2862                 next 
= (wxTreeListItem
*)GetNextChild (GetRootItem().m_pItem
, cookie
).m_pItem
; 
2866     return (wxTreeItemId
*)NULL
; 
2869 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId
& item
) { 
2870     wxTreeListItem 
*prevItem 
= m_dragItem
; 
2871     m_dragItem 
= (wxTreeListItem
*) item
.m_pItem
; 
2872     if (prevItem
) RefreshLine (prevItem
); 
2873     if (m_dragItem
) RefreshLine (m_dragItem
); 
2876 void wxTreeListMainWindow::CalculateLineHeight() { 
2877     wxClientDC 
dc (this); 
2878     dc
.SetFont (m_normalFont
); 
2879     m_lineHeight 
= (int)(dc
.GetCharHeight() + m_linespacing
); 
2881     if (m_imageListNormal
) { 
2882         // Calculate a m_lineHeight value from the normal Image sizes. 
2883         // May be toggle off. Then wxTreeListMainWindow will spread when 
2884         // necessary (which might look ugly). 
2885         int n 
= m_imageListNormal
->GetImageCount(); 
2886         for (int i 
= 0; i 
< n 
; i
++) { 
2887             int width 
= 0, height 
= 0; 
2888             m_imageListNormal
->GetSize(i
, width
, height
); 
2889             if (height 
> m_lineHeight
) m_lineHeight 
= height 
+ m_linespacing
; 
2893     if (m_imageListButtons
) { 
2894         // Calculate a m_lineHeight value from the Button image sizes. 
2895         // May be toggle off. Then wxTreeListMainWindow will spread when 
2896         // necessary (which might look ugly). 
2897         int n 
= m_imageListButtons
->GetImageCount(); 
2898         for (int i 
= 0; i 
< n 
; i
++) { 
2899             int width 
= 0, height 
= 0; 
2900             m_imageListButtons
->GetSize(i
, width
, height
); 
2901             if (height 
> m_lineHeight
) m_lineHeight 
= height 
+ m_linespacing
; 
2905     if (m_lineHeight 
< 30) { // add 10% space if greater than 30 pixels 
2906         m_lineHeight 
+= 2; // minimal 2 pixel space 
2908         m_lineHeight 
+= m_lineHeight 
/ 10; // otherwise 10% space 
2912 void wxTreeListMainWindow::SetImageList (wxImageList 
*imageList
) { 
2913     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
2914     m_imageListNormal 
= imageList
; 
2915     m_ownsImageListNormal 
= false; 
2917     CalculateLineHeight(); 
2920 void wxTreeListMainWindow::SetStateImageList (wxImageList 
*imageList
) { 
2921     if (m_ownsImageListState
) delete m_imageListState
; 
2922     m_imageListState 
= imageList
; 
2923     m_ownsImageListState 
= false; 
2926 void wxTreeListMainWindow::SetButtonsImageList (wxImageList 
*imageList
) { 
2927     if (m_ownsImageListButtons
) delete m_imageListButtons
; 
2928     m_imageListButtons 
= imageList
; 
2929     m_ownsImageListButtons 
= false; 
2931     CalculateLineHeight(); 
2934 void wxTreeListMainWindow::AssignImageList (wxImageList 
*imageList
) { 
2935     SetImageList(imageList
); 
2936     m_ownsImageListNormal 
= true; 
2939 void wxTreeListMainWindow::AssignStateImageList (wxImageList 
*imageList
) { 
2940     SetStateImageList(imageList
); 
2941     m_ownsImageListState 
= true; 
2944 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList 
*imageList
) { 
2945     SetButtonsImageList(imageList
); 
2946     m_ownsImageListButtons 
= true; 
2949 // ---------------------------------------------------------------------------- 
2951 // ---------------------------------------------------------------------------- 
2953 void wxTreeListMainWindow::AdjustMyScrollbars() { 
2956         GetScrollPixelsPerUnit (&xUnit
, &yUnit
); 
2957         if (xUnit 
== 0) xUnit 
= GetCharWidth(); 
2958         if (yUnit 
== 0) yUnit 
= m_lineHeight
; 
2960         m_rootItem
->GetSize (x
, y
, this); 
2961         y 
+= yUnit 
+ 2; // one more scrollbar unit + 2 pixels 
2962         int x_pos 
= GetScrollPos (wxHORIZONTAL
); 
2963         int y_pos 
= GetScrollPos (wxVERTICAL
); 
2964         x 
= m_owner
->GetHeaderWindow()->GetWidth() + 2; 
2965         if (x 
< GetClientSize().GetWidth()) x_pos 
= 0; 
2966         SetScrollbars (xUnit
, yUnit
, x
/xUnit
, y
/yUnit
, x_pos
, y_pos
); 
2968         SetScrollbars (0, 0, 0, 0); 
2972 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem 
*item
) const { 
2973     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT
) { 
2974         return item
->GetHeight(); 
2976         return m_lineHeight
; 
2980 void wxTreeListMainWindow::PaintItem (wxTreeListItem 
*item
, wxDC
& dc
) { 
2982     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
2984     dc
.SetFont (GetItemFont (item
)); 
2987     if (attr 
&& attr
->HasTextColour()) { 
2988         colText 
= attr
->GetTextColour(); 
2990         colText 
= GetForegroundColour(); 
2992 #if !wxCHECK_VERSION(2, 5, 0) 
2993     wxColour colTextHilight 
= wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT
); 
2995     wxColour colTextHilight 
= wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT
); 
2998     int total_w 
= m_owner
->GetHeaderWindow()->GetWidth(); 
2999     int total_h 
= GetLineHeight(item
); 
3000     int off_h 
= HasFlag(wxTR_ROW_LINES
) ? 1 : 0; 
3001     int off_w 
= HasFlag(wxTR_COLUMN_LINES
) ? 1 : 0; 
3002     wxDCClipper 
clipper (dc
, 0, item
->GetY(), total_w
, total_h
); // only within line 
3004     int text_w 
= 0, text_h 
= 0; 
3005     dc
.GetTextExtent( item
->GetText(GetMainColumn()), &text_w
, &text_h 
); 
3007     // determine background and show it 
3009     if (attr 
&& attr
->HasBackgroundColour()) { 
3010         colBg 
= attr
->GetBackgroundColour(); 
3012         colBg 
= m_backgroundColour
; 
3014     dc
.SetBrush (wxBrush (colBg
, wxSOLID
)); 
3015     dc
.SetPen (*wxTRANSPARENT_PEN
); 
3016     if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT
)) { 
3017         if (item 
== m_dragItem
) { 
3018             dc
.SetBrush (*m_hilightBrush
); 
3019 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color 
3020             dc
.SetPen ((item 
== m_dragItem
)? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
); 
3021 #endif // !__WXMAC__ 
3022             dc
.SetTextForeground (colTextHilight
); 
3023         }else if (item
->IsSelected()) { 
3024 #if defined(__WXGTK2__) || defined(__WXMAC__) 
3025         int flags 
= wxCONTROL_SELECTED
; 
3028             flags 
|= wxCONTROL_FOCUSED
; 
3030             dc
.SetTextForeground( *wxWHITE 
); 
3033         wxRendererNative::GetDefault().DrawItemSelectionRect( m_owner
, dc
, wxRect( 0, item
->GetY() + off_h
, total_w
, total_h 
- off_h 
), flags
);  
3035             if (!m_isDragging 
&& m_hasFocus
) { 
3036                 dc
.SetBrush (*m_hilightBrush
); 
3037                 dc
.SetPen (*wxBLACK_PEN
); 
3039                 dc
.SetBrush (*m_hilightUnfocusedBrush
); 
3040                 dc
.SetPen (*wxTRANSPARENT_PEN
); 
3042             dc
.SetTextForeground (colTextHilight
); 
3043 #endif // defined(__WXGTK2__) || defined(__WXMAC__) 
3044         }else if (item 
== m_curItem
) { 
3045             dc
.SetPen (m_hasFocus
? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
); 
3047             dc
.SetTextForeground (colText
); 
3049 #if !defined(__WXGTK2__) && !defined(__WXMAC__) 
3050         dc
.DrawRectangle (0, item
->GetY() + off_h
, total_w
, total_h 
- off_h
); 
3053         dc
.SetTextForeground (colText
); 
3056     int text_extraH 
= (total_h 
> text_h
) ? (total_h 
- text_h
)/2 : 0; 
3057     int img_extraH 
= (total_h 
> m_imgHeight
)? (total_h
-m_imgHeight
)/2: 0; 
3059     for (int i 
= 0; i 
< GetColumnCount(); ++i 
) { 
3060         if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue; 
3062         int col_w 
= m_owner
->GetHeaderWindow()->GetColumnWidth(i
); 
3063         wxDCClipper 
clipper (dc
, x_colstart
, item
->GetY(), col_w
, total_h
); // only within column 
3066         int image 
= NO_IMAGE
; 
3068         if(i 
== GetMainColumn()) { 
3069             x 
= item
->GetX() + MARGIN
; 
3071                 x 
+= (m_btnWidth
-m_btnWidth2
) + LINEATROOT
; 
3075             if (m_imageListNormal
) image 
= item
->GetCurrentImage(); 
3077             x 
= x_colstart 
+ MARGIN
; 
3078             image 
= item
->GetImage(i
); 
3080         if (image 
!= NO_IMAGE
) image_w 
= m_imgWidth 
+ MARGIN
; 
3082         // honor text alignment 
3083         wxString text 
= item
->GetText(i
); 
3085         switch ( m_owner
->GetHeaderWindow()->GetColumn(i
).GetAlignment() ) { 
3087             // nothing to do, already left aligned 
3090             dc
.GetTextExtent (text
, &text_w
, NULL
); 
3091             w 
= col_w 
- (image_w 
+ text_w 
+ off_w 
+ MARGIN
); 
3094         case wxALIGN_CENTER
: 
3095             dc
.GetTextExtent(text
, &text_w
, NULL
); 
3096             w 
= (col_w 
- (image_w 
+ text_w 
+ off_w 
+ MARGIN
))/2; 
3100         int text_x 
= x 
+ image_w
; 
3101         if (i 
== GetMainColumn()) item
->SetTextX (text_x
); 
3103         if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT
)) { 
3104             if (i 
== GetMainColumn()) { 
3105                 if (item 
== m_dragItem
) { 
3106                     dc
.SetBrush (*m_hilightBrush
); 
3107 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color 
3108                     dc
.SetPen ((item 
== m_dragItem
)? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
); 
3109 #endif // !__WXMAC__ 
3110                     dc
.SetTextForeground (colTextHilight
); 
3111                 }else if (item
->IsSelected()) { 
3112 #if defined(__WXGTK2__) || defined(__WXMAC__) 
3113                     int flags 
= wxCONTROL_SELECTED
; 
3116                         flags 
|= wxCONTROL_FOCUSED
; 
3118                         dc
.SetTextForeground( *wxWHITE 
); 
3121                     wxRendererNative::GetDefault().DrawItemSelectionRect( m_owner
, dc
, wxRect( 0, item
->GetY() + off_h
, total_w
, total_h 
- off_h 
), flags
);  
3123                     if (!m_isDragging 
&& m_hasFocus
) { 
3124                         dc
.SetBrush (*m_hilightBrush
); 
3125                         dc
.SetPen (*wxBLACK_PEN
); 
3127                         dc
.SetBrush (*m_hilightUnfocusedBrush
); 
3128                         dc
.SetPen (*wxTRANSPARENT_PEN
); 
3130                     dc
.SetTextForeground (colTextHilight
); 
3131 #endif // defined(__WXGTK2__) || defined(__WXMAC__) 
3132                 }else if (item 
== m_curItem
) { 
3133                     dc
.SetPen (m_hasFocus
? *wxBLACK_PEN
: *wxTRANSPARENT_PEN
); 
3135                     dc
.SetTextForeground (colText
); 
3137 #if !defined(__WXGTK2__) && !defined(__WXMAC__) 
3138                 dc
.DrawRectangle (text_x
, item
->GetY() + off_h
, text_w
, total_h 
- off_h
); 
3141                 dc
.SetTextForeground (colText
); 
3145         if (HasFlag(wxTR_COLUMN_LINES
)) { // vertical lines between columns 
3146 #if !wxCHECK_VERSION(2, 5, 0) 
3147             wxPen 
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT 
), 1, wxSOLID
); 
3149             wxPen 
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT 
), 1, wxSOLID
); 
3151             dc
.SetPen ((GetBackgroundColour() == *wxWHITE
)? pen
: *wxWHITE_PEN
); 
3152             dc
.DrawLine (x_colstart
+col_w
-1, item
->GetY(), x_colstart
+col_w
-1, item
->GetY()+total_h
); 
3155         dc
.SetBackgroundMode (wxTRANSPARENT
); 
3157         if (image 
!= NO_IMAGE
) { 
3158             int y 
= item
->GetY() + img_extraH
; 
3159             m_imageListNormal
->Draw (image
, dc
, x
, y
, wxIMAGELIST_DRAW_TRANSPARENT 
); 
3161         int text_y 
= item
->GetY() + text_extraH
; 
3162         dc
.DrawText (text
, (wxCoord
)text_x
, (wxCoord
)text_y
); 
3164         x_colstart 
+= col_w
; 
3167     // restore normal font 
3168     dc
.SetFont( m_normalFont 
); 
3171 // Now y stands for the top of the item, whereas it used to stand for middle ! 
3172 void wxTreeListMainWindow::PaintLevel (wxTreeListItem 
*item
, wxDC 
&dc
, 
3173                                        int level
, int &y
, int x_maincol
) { 
3175     // Handle hide root (only level 0) 
3176     if (HasFlag(wxTR_HIDE_ROOT
) && (level 
== 0)) { 
3177         wxArrayTreeListItems
& children 
= item
->GetChildren(); 
3178         for (size_t n 
= 0; n 
< children
.Count(); n
++) { 
3179             PaintLevel (children
[n
], dc
, 1, y
, x_maincol
); 
3181         // end after expanding root 
3185     // calculate position of vertical lines 
3186     int x 
= x_maincol 
+ MARGIN
; // start of column 
3187     if (HasFlag(wxTR_LINES_AT_ROOT
)) x 
+= LINEATROOT
; // space for lines at root 
3189         x 
+= (m_btnWidth
-m_btnWidth2
); // half button space 
3191         x 
+= (m_indent
-m_indent
/2); 
3193     if (HasFlag(wxTR_HIDE_ROOT
)) { 
3194         x 
+= m_indent 
* (level
-1); // indent but not level 1 
3196         x 
+= m_indent 
* level
; // indent according to level 
3199     // set position of vertical line 
3203     int h 
= GetLineHeight (item
); 
3205     int y_mid 
= y_top 
+ (h
/2); 
3208     int exposed_x 
= dc
.LogicalToDeviceX(0); 
3209     int exposed_y 
= dc
.LogicalToDeviceY(y_top
); 
3211     if (IsExposed(exposed_x
, exposed_y
, 10000, h
)) { // 10000 = very much 
3213         if (HasFlag(wxTR_ROW_LINES
)) { // horizontal lines between rows 
3214             //dc.DestroyClippingRegion(); 
3215             int total_width 
= m_owner
->GetHeaderWindow()->GetWidth(); 
3216             // if the background colour is white, choose a 
3217             // contrasting color for the lines 
3218 #if !wxCHECK_VERSION(2, 5, 0) 
3219             wxPen 
pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT 
), 1, wxSOLID
); 
3221             wxPen 
pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT 
), 1, wxSOLID
); 
3223             dc
.SetPen ((GetBackgroundColour() == *wxWHITE
)? pen
: *wxWHITE_PEN
); 
3224             dc
.DrawLine (0, y_top
, total_width
, y_top
); 
3225             dc
.DrawLine (0, y_top
+h
, total_width
, y_top
+h
); 
3229         PaintItem (item
, dc
); 
3231         // restore DC objects 
3232         dc
.SetBrush(*wxWHITE_BRUSH
); 
3233         dc
.SetPen(m_dottedPen
); 
3235         // clip to the column width 
3236         int clip_width 
= m_owner
->GetHeaderWindow()-> 
3237                             GetColumn(m_main_column
).GetWidth(); 
3238         wxDCClipper 
clipper(dc
, x_maincol
, y_top
, clip_width
, 10000); 
3240         if (!HasFlag(wxTR_NO_LINES
)) { // connection lines 
3242             // draw the horizontal line here 
3243             dc
.SetPen(m_dottedPen
); 
3244             int x2 
= x 
- m_indent
; 
3245             if (x2 
< (x_maincol 
+ MARGIN
)) x2 
= x_maincol 
+ MARGIN
; 
3246             int x3 
= x 
+ (m_btnWidth
-m_btnWidth2
); 
3248                 if (item
->HasPlus()) { 
3249                     dc
.DrawLine (x2
, y_mid
, x 
- m_btnWidth2
, y_mid
); 
3250                     dc
.DrawLine (x3
, y_mid
, x3 
+ LINEATROOT
, y_mid
); 
3252                     dc
.DrawLine (x2
, y_mid
, x3 
+ LINEATROOT
, y_mid
); 
3255                 dc
.DrawLine (x2
, y_mid
, x 
- m_indent
/2, y_mid
); 
3259         if (item
->HasPlus() && HasButtons()) { // should the item show a button? 
3261             if (m_imageListButtons
) { 
3263                 // draw the image button here 
3264                 int image 
= wxTreeItemIcon_Normal
; 
3265                 if (item
->IsExpanded()) image 
= wxTreeItemIcon_Expanded
; 
3266                 if (item
->IsSelected()) image 
+= wxTreeItemIcon_Selected 
- wxTreeItemIcon_Normal
; 
3267                 int xx 
= x 
- m_btnWidth2 
+ MARGIN
; 
3268                 int yy 
= y_mid 
- m_btnHeight2
; 
3269                 dc
.SetClippingRegion(xx
, yy
, m_btnWidth
, m_btnHeight
); 
3270                 m_imageListButtons
->Draw (image
, dc
, xx
, yy
, wxIMAGELIST_DRAW_TRANSPARENT
); 
3271                 dc
.DestroyClippingRegion(); 
3273             }else if (HasFlag (wxTR_TWIST_BUTTONS
)) { 
3275                 // draw the twisty button here 
3276                 dc
.SetPen(*wxBLACK_PEN
); 
3277                 dc
.SetBrush(*m_hilightBrush
); 
3279                 if (item
->IsExpanded()) { 
3280                     button
[0].x 
= x 
- (m_btnWidth2
+1); 
3281                     button
[0].y 
= y_mid 
- (m_btnHeight
/3); 
3282                     button
[1].x 
= x 
+ (m_btnWidth2
+1); 
3283                     button
[1].y 
= button
[0].y
; 
3285                     button
[2].y 
= button
[0].y 
+ (m_btnHeight2
+1); 
3287                     button
[0].x 
= x 
- (m_btnWidth
/3); 
3288                     button
[0].y 
= y_mid 
- (m_btnHeight2
+1); 
3289                     button
[1].x 
= button
[0].x
; 
3290                     button
[1].y 
= y_mid 
+ (m_btnHeight2
+1); 
3291                     button
[2].x 
= button
[0].x 
+ (m_btnWidth2
+1); 
3292                     button
[2].y 
= y_mid
; 
3294                 dc
.DrawPolygon(3, button
); 
3296             }else{ // if (HasFlag(wxTR_HAS_BUTTONS)) 
3298                 // draw the plus sign here 
3299 #if !wxCHECK_VERSION(2, 7, 0) 
3300                 dc
.SetPen(*wxGREY_PEN
); 
3301                 dc
.SetBrush(*wxWHITE_BRUSH
); 
3302                 dc
.DrawRectangle (x
-m_btnWidth2
, y_mid
-m_btnHeight2
, m_btnWidth
, m_btnHeight
); 
3303                 dc
.SetPen(*wxBLACK_PEN
); 
3304                 dc
.DrawLine (x
-(m_btnWidth2
-2), y_mid
, x
+(m_btnWidth2
-1), y_mid
); 
3305                 if (!item
->IsExpanded()) { // change "-" to "+" 
3306                     dc
.DrawLine (x
, y_mid
-(m_btnHeight2
-2), x
, y_mid
+(m_btnHeight2
-1)); 
3309                 wxRect 
rect (x
-m_btnWidth2
, y_mid
-m_btnHeight2
, m_btnWidth
, m_btnHeight
); 
3310                 int flag 
= item
->IsExpanded()? wxCONTROL_EXPANDED
: 0; 
3311                 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc
, rect
, flag
); 
3320     // restore DC objects 
3321     dc
.SetBrush(*wxWHITE_BRUSH
); 
3322     dc
.SetPen(m_dottedPen
); 
3323     dc
.SetTextForeground(*wxBLACK
); 
3325     if (item
->IsExpanded()) 
3327         wxArrayTreeListItems
& children 
= item
->GetChildren(); 
3329         // clip to the column width 
3330         int clip_width 
= m_owner
->GetHeaderWindow()-> 
3331                             GetColumn(m_main_column
).GetWidth(); 
3333         // process lower levels 
3335         if (m_imgWidth 
> 0) { 
3336             oldY 
= y_mid 
+ m_imgHeight2
; 
3341         for (size_t n 
= 0; n 
< children
.Count(); ++n
) { 
3344             PaintLevel (children
[n
], dc
, level
+1, y
, x_maincol
); 
3346             // draw vertical line 
3347             wxDCClipper 
clipper(dc
, x_maincol
, y_top
, clip_width
, 10000); 
3348             if (!HasFlag (wxTR_NO_LINES
)) { 
3350                 dc
.DrawLine (x
, oldY
, x
, y2
); 
3358 // ---------------------------------------------------------------------------- 
3359 // wxWindows callbacks 
3360 // ---------------------------------------------------------------------------- 
3362 void wxTreeListMainWindow::OnPaint (wxPaintEvent 
&WXUNUSED(event
)) { 
3364     wxPaintDC 
dc (this); 
3367     if (!m_rootItem 
|| (GetColumnCount() <= 0)) return; 
3369     // calculate button size 
3370     if (m_imageListButtons
) { 
3371         m_imageListButtons
->GetSize (0, m_btnWidth
, m_btnHeight
); 
3372     }else if (HasButtons()) { 
3373         m_btnWidth 
= BTNWIDTH
; 
3374         m_btnHeight 
= BTNHEIGHT
; 
3376     m_btnWidth2 
= m_btnWidth
/2; 
3377     m_btnHeight2 
= m_btnHeight
/2; 
3379     // calculate image size 
3380     if (m_imageListNormal
) { 
3381         m_imageListNormal
->GetSize (0, m_imgWidth
, m_imgHeight
); 
3383     m_imgWidth2 
= m_imgWidth
/2; 
3384     m_imgHeight2 
= m_imgHeight
/2; 
3386     // calculate indent size 
3387     if (m_imageListButtons
) { 
3388         m_indent 
= wxMax (MININDENT
, m_btnWidth 
+ MARGIN
); 
3389     }else if (HasButtons()) { 
3390         m_indent 
= wxMax (MININDENT
, m_btnWidth 
+ LINEATROOT
); 
3393     // set default values 
3394     dc
.SetFont( m_normalFont 
); 
3395     dc
.SetPen( m_dottedPen 
); 
3397     // calculate column start and paint 
3400     for (i 
= 0; i 
< (int)GetMainColumn(); ++i
) { 
3401         if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue; 
3402         x_maincol 
+= m_owner
->GetHeaderWindow()->GetColumnWidth (i
); 
3405     PaintLevel (m_rootItem
, dc
, 0, y
, x_maincol
); 
3408 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent 
&event
) { 
3412     if (m_curItem
) RefreshLine (m_curItem
); 
3416 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent 
&event 
) 
3420     if (m_curItem
) RefreshLine (m_curItem
); 
3424 void wxTreeListMainWindow::OnChar (wxKeyEvent 
&event
) { 
3425     // send event to user code 
3426     wxTreeEvent 
nevent (wxEVT_COMMAND_TREE_KEY_DOWN
, m_owner
->GetId()); 
3427     nevent
.SetKeyEvent (event
); 
3428     nevent
.SetEventObject (m_owner
); 
3429     if (m_owner
->GetEventHandler()->ProcessEvent (nevent
)) return; // handled in user code 
3431     // determine first current if none 
3432     bool curItemSet 
= false; 
3434         m_curItem 
= (wxTreeListItem
*)GetRootItem().m_pItem
; 
3435         if (HasFlag(wxTR_HIDE_ROOT
)) { 
3436 #if !wxCHECK_VERSION(2, 5, 0) 
3439             wxTreeItemIdValue cookie 
= 0; 
3441             m_curItem 
= (wxTreeListItem
*)GetFirstChild (m_curItem
, cookie
).m_pItem
; 
3445     if (!m_curItem
) return; // do nothing if empty tree 
3447     // remember item at shift down 
3448     if (HasFlag(wxTR_MULTIPLE
) && event
.ShiftDown()) { 
3449         if (!m_shiftItem
) m_shiftItem 
= m_curItem
; 
3451         m_shiftItem 
= (wxTreeListItem
*)NULL
; 
3454     // process all cases 
3455     wxTreeItemId newItem 
= (wxTreeItemId
*)NULL
; 
3456     switch (event
.GetKeyCode()) { 
3458         // '+': Expand subtree 
3461             if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) Expand (m_curItem
); 
3464         // '-': collapse subtree 
3466         case WXK_SUBTRACT
: { 
3467             if (m_curItem
->HasPlus() && IsExpanded (m_curItem
)) Collapse (m_curItem
); 
3470         // '*': expand/collapse all subtrees // TODO: Mak it more useful 
3472         case WXK_MULTIPLY
: { 
3473             if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) { 
3474                 ExpandAll (m_curItem
); 
3475             }else if (m_curItem
->HasPlus()) { 
3476                 Collapse (m_curItem
); // TODO: CollapseAll 
3480         // ' ': toggle current item 
3482             SelectItem (m_curItem
, (wxTreeListItem
*)NULL
, false); 
3485         // <RETURN>: activate current item 
3487             wxTreeEvent 
aevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, m_owner
->GetId()); 
3488 #if !wxCHECK_VERSION(2, 5, 0) 
3489             aevent
.SetItem ((long)m_curItem
); 
3491             aevent
.SetItem (m_curItem
); 
3493             aevent
.SetEventObject (m_owner
); 
3494             m_owner
->GetEventHandler()->ProcessEvent (aevent
); 
3497         // <BKSP>: go to the parent without collapsing 
3499             newItem 
= GetItemParent (m_curItem
); 
3500             if ((newItem 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) { 
3501                 newItem 
= GetPrevSibling (m_curItem
); // get sibling instead of root 
3505         // <UP>: go to the previous sibling or to the last of its children, to the parent 
3507             newItem 
= GetPrevSibling (m_curItem
); 
3509 #if !wxCHECK_VERSION(2, 5, 0) 
3512                 wxTreeItemIdValue cookie 
= 0; 
3514                 while (IsExpanded (newItem
) && HasChildren (newItem
)) { 
3515                     newItem 
= GetLastChild (newItem
, cookie
); 
3518                 newItem 
= GetItemParent (m_curItem
); 
3519                 if ((newItem 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) { 
3520                     newItem 
= (wxTreeItemId
*)NULL
; // don't go to root if it is hidden 
3525         // <LEFT>: if expanded collapse subtree, else go to the parent 
3527             if (IsExpanded (m_curItem
)) { 
3528                 Collapse (m_curItem
); 
3530                 newItem 
= GetItemParent (m_curItem
); 
3531                 if ((newItem 
== GetRootItem()) && HasFlag(wxTR_HIDE_ROOT
)) { 
3532                     newItem 
= GetPrevSibling (m_curItem
); // go to sibling if it is hidden 
3537         // <RIGHT>: if possible expand subtree, else go go to the first child 
3539             if (m_curItem
->HasPlus() && !IsExpanded (m_curItem
)) { 
3542                 if (IsExpanded (m_curItem
) && HasChildren (m_curItem
)) { 
3543 #if !wxCHECK_VERSION(2, 5, 0) 
3546                     wxTreeItemIdValue cookie 
= 0; 
3548                     newItem 
= GetFirstChild (m_curItem
, cookie
); 
3553         // <DOWN>: if expanded go to the first child, else to the next sibling, ect 
3556                 newItem 
= m_curItem
; 
3558                 if (IsExpanded (m_curItem
) && HasChildren (m_curItem
)) { 
3559 #if !wxCHECK_VERSION(2, 5, 0) 
3562                     wxTreeItemIdValue cookie 
= 0; 
3564                     newItem 
= GetFirstChild( m_curItem
, cookie 
); 
3567                     wxTreeItemId parent 
= m_curItem
; 
3569                         newItem 
= GetNextSibling (parent
); 
3570                         parent 
= GetItemParent (parent
); 
3571                     } while (!newItem 
&& parent
); 
3576         // <END>: go to last item of the root 
3578 #if !wxCHECK_VERSION(2, 5, 0) 
3581             wxTreeItemIdValue cookie 
= 0; 
3583             newItem 
= GetLastChild (GetRootItem(), cookie
); 
3586         // <HOME>: go to root 
3588             newItem 
= GetRootItem(); 
3589             if (HasFlag(wxTR_HIDE_ROOT
)) { 
3590 #if !wxCHECK_VERSION(2, 5, 0) 
3593                 wxTreeItemIdValue cookie 
= 0; 
3595                 newItem 
= GetFirstChild (newItem
, cookie
); 
3599         // any char: go to the next matching string 
3601             if (event
.GetKeyCode() >= (int)' ') { 
3602                 if (!m_findTimer
->IsRunning()) m_findStr
.Clear(); 
3603                 m_findStr
.Append ((char)event
.GetKeyCode()); 
3604                 m_findTimer
->Start (FIND_TIMER_TICKS
, wxTIMER_ONE_SHOT
); 
3605                 wxTreeItemId prev 
= m_curItem
? (wxTreeItemId
*)m_curItem
: (wxTreeItemId
*)NULL
; 
3607                     newItem 
= FindItem (prev
, m_findStr
, wxTL_MODE_NAV_EXPANDED 
| 
3608                                                          wxTL_MODE_FIND_PARTIAL 
| 
3609                                                          wxTL_MODE_FIND_NOCASE
); 
3610                     if (newItem 
|| (m_findStr
.Length() <= 1)) break; 
3611                     m_findStr
.RemoveLast(); 
3618     // select and show the new item 
3620         if (!event
.ControlDown()) { 
3621             bool unselect_others 
= !((event
.ShiftDown() || event
.ControlDown()) && 
3622                                       HasFlag(wxTR_MULTIPLE
)); 
3623             SelectItem (newItem
, m_shiftItem
, unselect_others
); 
3625         EnsureVisible (newItem
); 
3626         wxTreeListItem 
*oldItem 
= m_curItem
; 
3627         m_curItem 
= (wxTreeListItem
*)newItem
.m_pItem
; // make the new item the current item 
3628         RefreshLine (oldItem
); 
3633 wxTreeItemId 
wxTreeListMainWindow::HitTest (const wxPoint
& point
, int& flags
, int& column
) { 
3639     if (point
.x
<0) flags 
|= wxTREE_HITTEST_TOLEFT
; 
3640     if (point
.x
>w
) flags 
|= wxTREE_HITTEST_TORIGHT
; 
3641     if (point
.y
<0) flags 
|= wxTREE_HITTEST_ABOVE
; 
3642     if (point
.y
>h
) flags 
|= wxTREE_HITTEST_BELOW
; 
3643     if (flags
) return wxTreeItemId(); 
3646         flags 
= wxTREE_HITTEST_NOWHERE
; 
3648         return wxTreeItemId(); 
3651     wxTreeListItem 
*hit 
= m_rootItem
->HitTest (CalcUnscrolledPosition(point
), 
3652                                                this, flags
, column
, 0); 
3654         flags 
= wxTREE_HITTEST_NOWHERE
; 
3656         return wxTreeItemId(); 
3661 // get the bounding rectangle of the item (or of its label only) 
3662 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId
& itemId
, wxRect
& rect
, 
3663                                             bool WXUNUSED(textOnly
)) const { 
3664     wxCHECK_MSG (itemId
.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") ); 
3666     wxTreeListItem 
*item 
= (wxTreeListItem
*) itemId
.m_pItem
; 
3669     GetScrollPixelsPerUnit (&xUnit
, &yUnit
); 
3671     GetViewStart(& startX
, & startY
); 
3673     rect
.x 
= item
->GetX() - startX 
* xUnit
; 
3674     rect
.y 
= item
->GetY() - startY 
* yUnit
; 
3675     rect
.width 
= item
->GetWidth(); 
3676     rect
.height 
= GetLineHeight (item
); 
3683 void wxTreeListMainWindow::EditLabel (const wxTreeItemId
& item
, int column
) { 
3684     if (!item
.IsOk()) return; 
3685     if (!((column 
>= 0) && (column 
< GetColumnCount()))) return; 
3687     m_editItem 
= (wxTreeListItem
*) item
.m_pItem
; 
3689     wxTreeEvent 
te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
, m_owner
->GetId() ); 
3690 #if !wxCHECK_VERSION(2, 5, 0) 
3691     te
.SetItem ((long)m_editItem
); 
3693     te
.SetItem (m_editItem
); 
3696     te
.SetEventObject (m_owner 
); 
3697     m_owner
->GetEventHandler()->ProcessEvent (te
); 
3699     if (!te
.IsAllowed()) return; 
3701     // ensure that the position of the item it calculated in any case 
3702     if (m_dirty
) CalculatePositions(); 
3704     wxTreeListHeaderWindow
* header_win 
= m_owner
->GetHeaderWindow(); 
3706     int y 
= m_editItem
->GetY() + 1; // wxTextCtrl needs 1 pixels above the text 
3708     int h 
= m_editItem
->GetHeight(); 
3710     if (column 
== GetMainColumn()) { 
3711         x 
+= m_editItem
->GetTextX() - 2; // wxTextCtrl needs 2 pixels before the text 
3712         w 
= wxMin (m_editItem
->GetWidth(), m_owner
->GetHeaderWindow()->GetWidth() - x
); 
3714         for (int i 
= 0; i 
< column
; ++i
) x 
+= header_win
->GetColumnWidth (i
); // start of column 
3715         switch (header_win
->GetColumnAlignment (column
)) { 
3716             case wxALIGN_LEFT
: {style 
= wxTE_LEFT
; break;} 
3717             case wxALIGN_RIGHT
: {style 
= wxTE_RIGHT
; break;} 
3718             case wxALIGN_CENTER
: {style 
= wxTE_CENTER
; break;} 
3720         w 
= header_win
->GetColumnWidth (column
); // width of column 
3723     wxClientDC 
dc (this); 
3725     x 
= dc
.LogicalToDeviceX (x
); 
3726     y 
= dc
.LogicalToDeviceY (y
); 
3728     wxEditTextCtrl 
*text 
= new wxEditTextCtrl (this, -1, &m_renameAccept
, &m_renameRes
, 
3729                                                this, m_editItem
->GetText (column
), 
3730                                                wxPoint (x
, y
), wxSize (w
, h
), style
); 
3734 void wxTreeListMainWindow::OnRenameTimer() { 
3735     EditLabel (m_curItem
, m_curColumn
); 
3738 void wxTreeListMainWindow::OnRenameAccept() { 
3740     // TODO if the validator fails this causes a crash 
3741     wxTreeEvent 
le( wxEVT_COMMAND_TREE_END_LABEL_EDIT
, m_owner
->GetId() ); 
3742 #if !wxCHECK_VERSION(2, 5, 0) 
3743     le
.SetItem((long)m_editItem
); 
3745     le
.SetItem(m_editItem
); 
3747     le
.SetEventObject( /*this*/m_owner 
); 
3748     le
.SetLabel( m_renameRes 
); 
3749     m_owner
->GetEventHandler()->ProcessEvent( le 
); 
3751     if (!le
.IsAllowed()) return; 
3753     SetItemText (m_editItem
, m_curColumn
, m_renameRes
); 
3756 void wxTreeListMainWindow::OnMouse (wxMouseEvent 
&event
) { 
3757     if (!m_rootItem
) return; 
3759     // we process left mouse up event (enables in-place edit), right down 
3760     // (pass to the user code), left dbl click (activate item) and 
3761     // dragging/moving events for items drag-and-drop 
3762     if (!(event
.LeftDown() || 
3764           event
.RightDown() || 
3766           event
.LeftDClick() || 
3768           (event
.GetWheelRotation() != 0 )/*? TODO || 
3769           event.Moving()?*/)) { 
3770         m_owner
->GetEventHandler()->ProcessEvent (event
); 
3774     // set focus if window clicked 
3775     if (event
.LeftDown() || event
.RightDown()) SetFocus(); 
3778     wxPoint p 
= wxPoint (event
.GetX(), event
.GetY()); 
3780     wxTreeListItem 
*item 
= m_rootItem
->HitTest (CalcUnscrolledPosition (p
), 
3781                                                 this, flags
, m_curColumn
, 0); 
3783     // we only process dragging here 
3784     if (event
.Dragging()){ 
3785         if (m_isDragging
) return; // nothing to do, already done 
3786         if (item 
== NULL
) return; // we need an item to dragging 
3788         // determine drag start 
3789         if (m_dragCount 
== 0) { 
3790             m_dragTimer
->Start (DRAG_TIMER_TICKS
, wxTIMER_ONE_SHOT
); 
3793         if (m_dragCount 
< 3) return; // minimum drag 3 pixel 
3794         if (m_dragTimer
->IsRunning()) return; 
3796         // we're going to drag 
3798         m_isDragging 
= true; 
3802         // send drag start event 
3803         wxEventType command 
= event
.LeftIsDown() 
3804                               ? wxEVT_COMMAND_TREE_BEGIN_DRAG
 
3805                               : wxEVT_COMMAND_TREE_BEGIN_RDRAG
; 
3806         wxTreeEvent 
nevent (command
, m_owner
->GetId()); 
3807         nevent
.SetEventObject (m_owner
); 
3808 #if !wxCHECK_VERSION(2, 5, 0) 
3809         nevent
.SetItem ((long)item
); // the item the drag is ended 
3811         nevent
.SetItem (item
); // the item the drag is ended 
3813         nevent
.SetPoint (p
); 
3814         nevent
.Veto(); // dragging must be explicit allowed! 
3815         m_owner
->GetEventHandler()->ProcessEvent (nevent
); 
3817     }else if (m_isDragging
) { // any other event but not event.Dragging() 
3821         m_isDragging 
= false; 
3822         if (HasCapture()) ReleaseMouse(); 
3825         // send drag end event event 
3826         wxTreeEvent 
nevent (wxEVT_COMMAND_TREE_END_DRAG
, m_owner
->GetId()); 
3827         nevent
.SetEventObject (m_owner
); 
3828 #if !wxCHECK_VERSION(2, 5, 0) 
3829         nevent
.SetItem ((long)item
); // the item the drag is started 
3831         nevent
.SetItem (item
); // the item the drag is started 
3833         nevent
.SetPoint (p
); 
3834         m_owner
->GetEventHandler()->ProcessEvent (nevent
); 
3836     }else if (m_dragCount 
> 0) { // just in case dragging is initiated 
3843     // we process only the messages which happen on tree items 
3845         m_owner
->GetEventHandler()->ProcessEvent (event
); 
3849     // remember item at shift down 
3850     if (event
.ShiftDown())  { 
3851         if (!m_shiftItem
) m_shiftItem 
= m_curItem
; 
3853         m_shiftItem 
= (wxTreeListItem
*)NULL
; 
3856     if (event
.RightUp()) { 
3859         wxTreeEvent 
nevent (wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
, m_owner
->GetId()); 
3860         nevent
.SetEventObject (m_owner
); 
3861 #if !wxCHECK_VERSION(2, 5, 0) 
3862         nevent
.SetItem ((long)item
); // the item clicked 
3864         nevent
.SetItem (item
); // the item clicked 
3866         nevent
.SetInt (m_curColumn
); // the colum clicked 
3867         nevent
.SetPoint (p
); 
3868         m_owner
->GetEventHandler()->ProcessEvent (nevent
); 
3870     }else if (event
.LeftUp()) { 
3873             if ((item 
== m_curItem
) && (m_curColumn 
!= -1) && 
3874                 (m_owner
->GetHeaderWindow()->IsColumnEditable (m_curColumn
)) && 
3875                 (flags 
& (wxTREE_HITTEST_ONITEMLABEL 
| wxTREE_HITTEST_ONITEMCOLUMN
))){ 
3876                 m_renameTimer
->Start (RENAME_TIMER_TICKS
, wxTIMER_ONE_SHOT
); 
3878             m_lastOnSame 
= false; 
3881         if (((flags 
& wxTREE_HITTEST_ONITEMBUTTON
) || 
3882              (flags 
& wxTREE_HITTEST_ONITEMICON
)) && 
3883             HasButtons() && item
->HasPlus()) { 
3885             // only toggle the item for a single click, double click on 
3886             // the button doesn't do anything (it toggles the item twice) 
3887             if (event
.LeftDown()) Toggle (item
); 
3889             // don't select the item if the button was clicked 
3893         // determine the selection if not done by left down 
3894         if (!m_left_down_selection
) { 
3895             bool unselect_others 
= !((event
.ShiftDown() || event
.ControlDown()) && 
3896                                      HasFlag(wxTR_MULTIPLE
)); 
3897             SelectItem (item
, m_shiftItem
, unselect_others
); 
3898             EnsureVisible (item
); 
3899             m_curItem 
= item
; // make the new item the current item 
3901             m_left_down_selection 
= false; 
3904     }else if (event
.LeftDown() || event
.RightDown() || event
.LeftDClick()) { 
3906         if (event
.LeftDown() || event
.RightDown()) { 
3908             m_lastOnSame 
= item 
== m_curItem
; 
3911         if (((flags 
& wxTREE_HITTEST_ONITEMBUTTON
) || 
3912              (flags 
& wxTREE_HITTEST_ONITEMICON
)) && 
3915             // only toggle the item for a single click, double click on 
3916             // the button doesn't do anything (it toggles the item twice) 
3917             if (event
.LeftDown()) Toggle (item
); 
3919             // don't select the item if the button was clicked 
3923         // determine the selection if the current item is not selected 
3924         if (!item
->IsSelected()) { 
3925             bool unselect_others 
= !((event
.ShiftDown() || event
.ControlDown()) && 
3926                                      HasFlag(wxTR_MULTIPLE
)); 
3927             SelectItem (item
, m_shiftItem
, unselect_others
); 
3928             EnsureVisible (item
); 
3929             m_curItem 
= item
; // make the new item the current item 
3930             m_left_down_selection 
= true; 
3933         // For some reason, Windows isn't recognizing a left double-click, 
3934         // so we need to simulate it here.  Allow 200 milliseconds for now. 
3935         if (event
.LeftDClick()) { 
3937             // double clicking should not start editing the item label 
3938             m_renameTimer
->Stop(); 
3939             m_lastOnSame 
= false; 
3941             // send activate event first 
3942             wxTreeEvent 
nevent (wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, m_owner
->GetId()); 
3943             nevent
.SetEventObject (m_owner
); 
3944 #if !wxCHECK_VERSION(2, 5, 0) 
3945             nevent
.SetItem ((long)item
); // the item clicked 
3947             nevent
.SetItem (item
); // the item clicked 
3949             nevent
.SetInt (m_curColumn
); // the colum clicked 
3950             nevent
.SetPoint (p
); 
3951             if (!m_owner
->GetEventHandler()->ProcessEvent (nevent
)) { 
3953                 // if the user code didn't process the activate event, 
3954                 // handle it ourselves by toggling the item when it is 
3956                 if (item
->HasPlus()) Toggle(item
); 
3960     }else{ // any other event skip just in case 
3967 void wxTreeListMainWindow::OnIdle (wxIdleEvent 
&WXUNUSED(event
)) { 
3968     /* after all changes have been done to the tree control, 
3969      * we actually redraw the tree when everything is over */ 
3971     if (!m_dirty
) return; 
3975     CalculatePositions(); 
3977     AdjustMyScrollbars(); 
3980 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent
& event
) { 
3982 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) 
3983     wxScrolledWindow::OnScroll(event
); 
3985     HandleOnScroll( event 
); 
3988     if(event
.GetOrientation() == wxHORIZONTAL
) { 
3989         m_owner
->GetHeaderWindow()->Refresh(); 
3990         m_owner
->GetHeaderWindow()->Update(); 
3994 void wxTreeListMainWindow::CalculateSize (wxTreeListItem 
*item
, wxDC 
&dc
) { 
3998     dc
.SetFont (GetItemFont (item
)); 
4000     dc
.GetTextExtent (item
->GetText (m_main_column
), &text_w
, &text_h
); 
4002     // restore normal font 
4003     dc
.SetFont (m_normalFont
); 
4005     int total_h 
= (m_imgHeight 
> text_h
) ? m_imgHeight 
: text_h
; 
4006     if (total_h 
< 30) { // add 10% space if greater than 30 pixels 
4007         total_h 
+= 2; // minimal 2 pixel space 
4009         total_h 
+= total_h 
/ 10; // otherwise 10% space 
4012     item
->SetHeight (total_h
); 
4013     if (total_h 
> m_lineHeight
) m_lineHeight 
= total_h
; 
4014     item
->SetWidth(m_imgWidth 
+ text_w
+2); 
4017 // ----------------------------------------------------------------------------- 
4018 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem 
*item
, wxDC 
&dc
, 
4019                                            int level
, int &y
, int x_colstart
) { 
4021     // calculate position of vertical lines 
4022     int x 
= x_colstart 
+ MARGIN
; // start of column 
4023     if (HasFlag(wxTR_LINES_AT_ROOT
)) x 
+= LINEATROOT
; // space for lines at root 
4025         x 
+= (m_btnWidth
-m_btnWidth2
); // half button space 
4027         x 
+= (m_indent
-m_indent
/2); 
4029     if (HasFlag(wxTR_HIDE_ROOT
)) { 
4030         x 
+= m_indent 
* (level
-1); // indent but not level 1 
4032         x 
+= m_indent 
* level
; // indent according to level 
4035     // a hidden root is not evaluated, but its children are always 
4036     if (HasFlag(wxTR_HIDE_ROOT
) && (level 
== 0)) goto Recurse
; 
4038     CalculateSize( item
, dc 
); 
4043     y 
+= GetLineHeight(item
); 
4045     // we don't need to calculate collapsed branches 
4046     if ( !item
->IsExpanded() ) return; 
4049     wxArrayTreeListItems
& children 
= item
->GetChildren(); 
4050     long n
, count 
= (long)children
.Count(); 
4052     for (n 
= 0; n 
< count
; ++n
) { 
4053         CalculateLevel( children
[n
], dc
, level
, y
, x_colstart 
);  // recurse 
4057 void wxTreeListMainWindow::CalculatePositions() { 
4058     if ( !m_rootItem 
) return; 
4060     wxClientDC 
dc(this); 
4063     dc
.SetFont( m_normalFont 
); 
4065     dc
.SetPen( m_dottedPen 
); 
4066     //if(GetImageList() == NULL) 
4067     // m_lineHeight = (int)(dc.GetCharHeight() + 4); 
4071     for (int i 
= 0; i 
< (int)GetMainColumn(); ++i
) { 
4072         if (!m_owner
->GetHeaderWindow()->IsColumnShown(i
)) continue; 
4073         x_colstart 
+= m_owner
->GetHeaderWindow()->GetColumnWidth(i
); 
4075     CalculateLevel( m_rootItem
, dc
, 0, y
, x_colstart 
); // start recursion 
4078 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem 
*item
) { 
4079     if (m_dirty
) return; 
4081     wxClientDC 
dc(this); 
4086     GetVirtualSize( &cw
, &ch 
); 
4089     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
4091     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() - 2 ); 
4094     Refresh (true, &rect 
); 
4095     AdjustMyScrollbars(); 
4098 void wxTreeListMainWindow::RefreshLine (wxTreeListItem 
*item
) { 
4099     if (m_dirty
) return; 
4101     wxClientDC 
dc(this); 
4106     GetVirtualSize( &cw
, &ch 
); 
4109     rect
.x 
= dc
.LogicalToDeviceX( 0 ); 
4110     rect
.y 
= dc
.LogicalToDeviceY( item
->GetY() ); 
4112     rect
.height 
= GetLineHeight(item
); //dc.GetCharHeight() + 6; 
4114     Refresh (true, &rect
); 
4117 void wxTreeListMainWindow::RefreshSelected() { 
4118     // TODO: this is awfully inefficient, we should keep the list of all 
4119     //       selected items internally, should be much faster 
4121         RefreshSelectedUnder (m_rootItem
); 
4125 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem 
*item
) { 
4126     if (item
->IsSelected()) { 
4130     const wxArrayTreeListItems
& children 
= item
->GetChildren(); 
4131     long count 
= children
.GetCount(); 
4132     for (long n 
= 0; n 
< count
; n
++ ) { 
4133         RefreshSelectedUnder (children
[n
]); 
4137 // ---------------------------------------------------------------------------- 
4138 // changing colours: we need to refresh the tree control 
4139 // ---------------------------------------------------------------------------- 
4141 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour
& colour
) { 
4142     if (!wxWindow::SetBackgroundColour(colour
)) return false; 
4148 bool wxTreeListMainWindow::SetForegroundColour (const wxColour
& colour
) { 
4149     if (!wxWindow::SetForegroundColour(colour
)) return false; 
4155 void wxTreeListMainWindow::SetItemText (const wxTreeItemId
& itemId
, int column
, 
4156                                         const wxString
& text
) { 
4157     wxCHECK_RET (itemId
.IsOk(), _T("invalid tree item")); 
4159     wxClientDC 
dc (this); 
4160     wxTreeListItem 
*item 
= (wxTreeListItem
*) itemId
.m_pItem
; 
4161     item
->SetText (column
, text
); 
4162     CalculateSize (item
, dc
); 
4166 wxString 
wxTreeListMainWindow::GetItemText (const wxTreeItemId
& itemId
, 
4168     wxCHECK_MSG (itemId
.IsOk(), _T(""), _T("invalid tree item") ); 
4170     if( IsVirtual() )   return m_owner
->OnGetItemText(((wxTreeListItem
*) itemId
.m_pItem
)->GetData(),column
); 
4171     else                return ((wxTreeListItem
*) itemId
.m_pItem
)->GetText (column
); 
4174 wxString 
wxTreeListMainWindow::GetItemText (wxTreeItemData
* item
, 
4176    wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") ); 
4177    return m_owner
->OnGetItemText(item
,column
); 
4180 void wxTreeListMainWindow::SetFocus() { 
4181     wxWindow::SetFocus(); 
4184 wxFont 
wxTreeListMainWindow::GetItemFont (wxTreeListItem 
*item
) { 
4185     wxTreeItemAttr 
*attr 
= item
->GetAttributes(); 
4187     if (attr 
&& attr
->HasFont()) { 
4188         return attr
->GetFont(); 
4189     }else if (item
->IsBold()) { 
4192         return m_normalFont
; 
4196 int wxTreeListMainWindow::GetItemWidth (int column
, wxTreeListItem 
*item
) { 
4197     if (!item
) return 0; 
4199     // determine item width 
4201     wxFont font 
= GetItemFont (item
); 
4202     GetTextExtent (item
->GetText (column
), &w
, &h
, NULL
, NULL
, font
.Ok()? &font
: NULL
); 
4206     int width 
= w 
+ 2*MARGIN
; 
4207     if (column 
== GetMainColumn()) { 
4209         if (HasFlag(wxTR_LINES_AT_ROOT
)) width 
+= LINEATROOT
; 
4210         if (HasButtons()) width 
+= m_btnWidth 
+ LINEATROOT
; 
4211         if (item
->GetCurrentImage() != NO_IMAGE
) width 
+= m_imgWidth
; 
4213         // count indent level 
4215         wxTreeListItem 
*parent 
= item
->GetItemParent(); 
4216         wxTreeListItem 
*root 
= (wxTreeListItem
*)GetRootItem().m_pItem
; 
4217         while (parent 
&& (!HasFlag(wxTR_HIDE_ROOT
) || (parent 
!= root
))) { 
4219             parent 
= parent
->GetItemParent(); 
4221         if (level
) width 
+= level 
* GetIndent(); 
4227 int wxTreeListMainWindow::GetBestColumnWidth (int column
, wxTreeItemId parent
) { 
4229     GetClientSize (&maxWidth
, &h
); 
4232     // get root if on item 
4233     if (!parent
.IsOk()) parent 
= GetRootItem(); 
4236     if (!HasFlag(wxTR_HIDE_ROOT
)) { 
4237         int w 
= GetItemWidth (column
, (wxTreeListItem
*)parent
.m_pItem
); 
4238         if (width 
< w
) width 
= w
; 
4239         if (width 
> maxWidth
) return maxWidth
; 
4242     wxTreeItemIdValue cookie 
= 0; 
4243     wxTreeItemId item 
= GetFirstChild (parent
, cookie
); 
4244     while (item
.IsOk()) { 
4245         int w 
= GetItemWidth (column
, (wxTreeListItem
*)item
.m_pItem
); 
4246         if (width 
< w
) width 
= w
; 
4247         if (width 
> maxWidth
) return maxWidth
; 
4249         // check the children of this item 
4250         if (((wxTreeListItem
*)item
.m_pItem
)->IsExpanded()) { 
4251             int w 
= GetBestColumnWidth (column
, item
); 
4252             if (width 
< w
) width 
= w
; 
4253             if (width 
> maxWidth
) return maxWidth
; 
4257         item 
= GetNextChild (parent
, cookie
); 
4264 //----------------------------------------------------------------------------- 
4266 //----------------------------------------------------------------------------- 
4268 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl
, wxControl
); 
4270 BEGIN_EVENT_TABLE(wxTreeListCtrl
, wxControl
) 
4271     EVT_SIZE(wxTreeListCtrl::OnSize
) 
4274 bool wxTreeListCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
4277                             long style
, const wxValidator 
&validator
, 
4278                             const wxString
& name
) 
4280     long main_style 
= style 
& ~(wxSIMPLE_BORDER
|wxSUNKEN_BORDER
|wxDOUBLE_BORDER
| 
4281                                 wxRAISED_BORDER
|wxSTATIC_BORDER
); 
4282     long ctrl_style 
= style 
& ~(wxVSCROLL
|wxHSCROLL
); 
4284     if (!wxControl::Create(parent
, id
, pos
, size
, ctrl_style
, validator
, name
)) { 
4287     m_main_win 
= new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size
, 
4288                                            main_style
, validator
); 
4289     m_header_win 
= new wxTreeListHeaderWindow (this, -1, m_main_win
, 
4290                                                wxPoint(0, 0), wxDefaultSize
, 
4292     CalculateAndSetHeaderHeight(); 
4296 void wxTreeListCtrl::CalculateAndSetHeaderHeight() 
4300 #if wxCHECK_VERSION_FULL(2, 7, 0, 1) 
4301         h 
= wxRendererNative::Get().GetHeaderButtonHeight(m_header_win
); 
4303         // we use 'g' to get the descent, too 
4305         m_header_win
->GetTextExtent(_T("Hg"), &w
, &h
, &d
); 
4306         h 
+= d 
+ 2 * HEADER_OFFSET_Y 
+ EXTRA_HEIGHT
; 
4308         // only update if changed 
4309         if (h 
!= m_headerHeight
) { 
4316 void wxTreeListCtrl::DoHeaderLayout() 
4319     GetClientSize(&w
, &h
); 
4321         m_header_win
->SetSize (0, 0, w
, m_headerHeight
); 
4322         m_header_win
->Refresh(); 
4325         m_main_win
->SetSize (0, m_headerHeight 
+ 1, w
, h 
- m_headerHeight 
- 1); 
4329 void wxTreeListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
4334 size_t wxTreeListCtrl::GetCount() const { return m_main_win
->GetCount(); } 
4336 unsigned int wxTreeListCtrl::GetIndent() const 
4337 { return m_main_win
->GetIndent(); } 
4339 void wxTreeListCtrl::SetIndent(unsigned int indent
) 
4340 { m_main_win
->SetIndent(indent
); } 
4342 unsigned int wxTreeListCtrl::GetLineSpacing() const 
4343 { return m_main_win
->GetLineSpacing(); } 
4345 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing
) 
4346 { m_main_win
->SetLineSpacing(spacing
); } 
4348 wxImageList
* wxTreeListCtrl::GetImageList() const 
4349 { return m_main_win
->GetImageList(); } 
4351 wxImageList
* wxTreeListCtrl::GetStateImageList() const 
4352 { return m_main_win
->GetStateImageList(); } 
4354 wxImageList
* wxTreeListCtrl::GetButtonsImageList() const 
4355 { return m_main_win
->GetButtonsImageList(); } 
4357 void wxTreeListCtrl::SetImageList(wxImageList
* imageList
) 
4358 { m_main_win
->SetImageList(imageList
); } 
4360 void wxTreeListCtrl::SetStateImageList(wxImageList
* imageList
) 
4361 { m_main_win
->SetStateImageList(imageList
); } 
4363 void wxTreeListCtrl::SetButtonsImageList(wxImageList
* imageList
) 
4364 { m_main_win
->SetButtonsImageList(imageList
); } 
4366 void wxTreeListCtrl::AssignImageList(wxImageList
* imageList
) 
4367 { m_main_win
->AssignImageList(imageList
); } 
4369 void wxTreeListCtrl::AssignStateImageList(wxImageList
* imageList
) 
4370 { m_main_win
->AssignStateImageList(imageList
); } 
4372 void wxTreeListCtrl::AssignButtonsImageList(wxImageList
* imageList
) 
4373 { m_main_win
->AssignButtonsImageList(imageList
); } 
4375 wxString 
wxTreeListCtrl::GetItemText(const wxTreeItemId
& item
, int column
) const 
4376 { return m_main_win
->GetItemText (item
, column
); } 
4378 int wxTreeListCtrl::GetItemImage(const wxTreeItemId
& item
, int column
, 
4379                                  wxTreeItemIcon which
) const 
4380 { return m_main_win
->GetItemImage(item
, column
, which
); } 
4382 wxTreeItemData
* wxTreeListCtrl::GetItemData(const wxTreeItemId
& item
) const 
4383 { return m_main_win
->GetItemData(item
); } 
4385 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId
& item
) const 
4386 { return m_main_win
->GetItemBold(item
); } 
4388 wxColour 
wxTreeListCtrl::GetItemTextColour(const wxTreeItemId
& item
) const 
4389 { return m_main_win
->GetItemTextColour(item
); } 
4391 wxColour 
wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId
& item
) 
4393 { return m_main_win
->GetItemBackgroundColour(item
); } 
4395 wxFont 
wxTreeListCtrl::GetItemFont(const wxTreeItemId
& item
) const 
4396 { return m_main_win
->GetItemFont(item
); } 
4399 void wxTreeListCtrl::SetItemText(const wxTreeItemId
& item
, int column
, 
4400                                  const wxString
& text
) 
4401 { m_main_win
->SetItemText (item
, column
, text
); } 
4403 void wxTreeListCtrl::SetItemImage(const wxTreeItemId
& item
, 
4406                                   wxTreeItemIcon which
) 
4407 { m_main_win
->SetItemImage(item
, column
, image
, which
); } 
4409 void wxTreeListCtrl::SetItemData(const wxTreeItemId
& item
, 
4410                                  wxTreeItemData
* data
) 
4411 { m_main_win
->SetItemData(item
, data
); } 
4413 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
4414 { m_main_win
->SetItemHasChildren(item
, has
); } 
4416 void wxTreeListCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
4417 { m_main_win
->SetItemBold(item
, bold
); } 
4419 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId
& item
, 
4420                                        const wxColour
& colour
) 
4421 { m_main_win
->SetItemTextColour(item
, colour
); } 
4423 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
, 
4424                                              const wxColour
& colour
) 
4425 { m_main_win
->SetItemBackgroundColour(item
, colour
); } 
4427 void wxTreeListCtrl::SetItemFont(const wxTreeItemId
& item
, 
4429 { m_main_win
->SetItemFont(item
, font
); } 
4431 bool wxTreeListCtrl::SetFont(const wxFont
& font
) 
4434         m_header_win
->SetFont(font
); 
4435         CalculateAndSetHeaderHeight(); 
4436         m_header_win
->Refresh(); 
4439         return m_main_win
->SetFont(font
); 
4445 void wxTreeListCtrl::SetWindowStyle(const long style
) 
4448         m_main_win
->SetWindowStyle(style
); 
4449     m_windowStyle 
= style
; 
4450     // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win 
4453 long wxTreeListCtrl::GetWindowStyle() const 
4455     long style 
= m_windowStyle
; 
4457         style 
|= m_main_win
->GetWindowStyle(); 
4461 bool wxTreeListCtrl::IsVisible(const wxTreeItemId
& item
, bool fullRow
) const 
4462 { return m_main_win
->IsVisible(item
, fullRow
); } 
4464 bool wxTreeListCtrl::HasChildren(const wxTreeItemId
& item
) const 
4465 { return m_main_win
->HasChildren(item
); } 
4467 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId
& item
) const 
4468 { return m_main_win
->IsExpanded(item
); } 
4470 bool wxTreeListCtrl::IsSelected(const wxTreeItemId
& item
) const 
4471 { return m_main_win
->IsSelected(item
); } 
4473 bool wxTreeListCtrl::IsBold(const wxTreeItemId
& item
) const 
4474 { return m_main_win
->IsBold(item
); } 
4476 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool rec
) 
4477 { return m_main_win
->GetChildrenCount(item
, rec
); } 
4479 wxTreeItemId 
wxTreeListCtrl::GetRootItem() const 
4480 { return m_main_win
->GetRootItem(); } 
4482 wxTreeItemId 
wxTreeListCtrl::GetSelection() const 
4483 { return m_main_win
->GetSelection(); } 
4485 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds
& arr
) const 
4486 { return m_main_win
->GetSelections(arr
); } 
4488 wxTreeItemId 
wxTreeListCtrl::GetItemParent(const wxTreeItemId
& item
) const 
4489 { return m_main_win
->GetItemParent(item
); } 
4491 #if !wxCHECK_VERSION(2, 5, 0) 
4492 wxTreeItemId 
wxTreeListCtrl::GetFirstChild (const wxTreeItemId
& item
, 
4495 wxTreeItemId 
wxTreeListCtrl::GetFirstChild (const wxTreeItemId
& item
, 
4496                                             wxTreeItemIdValue
& cookie
) const 
4498 { return m_main_win
->GetFirstChild(item
, cookie
); } 
4500 #if !wxCHECK_VERSION(2, 5, 0) 
4501 wxTreeItemId 
wxTreeListCtrl::GetNextChild (const wxTreeItemId
& item
, 
4504 wxTreeItemId 
wxTreeListCtrl::GetNextChild (const wxTreeItemId
& item
, 
4505                                            wxTreeItemIdValue
& cookie
) const 
4507 { return m_main_win
->GetNextChild(item
, cookie
); } 
4509 #if !wxCHECK_VERSION(2, 5, 0) 
4510 wxTreeItemId 
wxTreeListCtrl::GetPrevChild (const wxTreeItemId
& item
, 
4513 wxTreeItemId 
wxTreeListCtrl::GetPrevChild (const wxTreeItemId
& item
, 
4514                                            wxTreeItemIdValue
& cookie
) const 
4516 { return m_main_win
->GetPrevChild(item
, cookie
); } 
4518 #if !wxCHECK_VERSION(2, 5, 0) 
4519 wxTreeItemId 
wxTreeListCtrl::GetLastChild (const wxTreeItemId
& item
, 
4522 wxTreeItemId 
wxTreeListCtrl::GetLastChild (const wxTreeItemId
& item
, 
4523                                            wxTreeItemIdValue
& cookie
) const 
4525 { return m_main_win
->GetLastChild(item
, cookie
); } 
4528 wxTreeItemId 
wxTreeListCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
4529 { return m_main_win
->GetNextSibling(item
); } 
4531 wxTreeItemId 
wxTreeListCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
4532 { return m_main_win
->GetPrevSibling(item
); } 
4534 wxTreeItemId 
wxTreeListCtrl::GetNext(const wxTreeItemId
& item
) const 
4535 { return m_main_win
->GetNext(item
, true); } 
4537 wxTreeItemId 
wxTreeListCtrl::GetPrev(const wxTreeItemId
& item
) const 
4538 { return m_main_win
->GetPrev(item
, true); } 
4540 wxTreeItemId 
wxTreeListCtrl::GetFirstExpandedItem() const 
4541 { return m_main_win
->GetFirstExpandedItem(); } 
4543 wxTreeItemId 
wxTreeListCtrl::GetNextExpanded(const wxTreeItemId
& item
) const 
4544 { return m_main_win
->GetNextExpanded(item
); } 
4546 wxTreeItemId 
wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId
& item
) const 
4547 { return m_main_win
->GetPrevExpanded(item
); } 
4549 wxTreeItemId 
wxTreeListCtrl::GetFirstVisibleItem(bool fullRow
) const 
4550 { return m_main_win
->GetFirstVisibleItem(fullRow
); } 
4552 wxTreeItemId 
wxTreeListCtrl::GetNextVisible(const wxTreeItemId
& item
, bool fullRow
) const 
4553 { return m_main_win
->GetNextVisible(item
, fullRow
); } 
4555 wxTreeItemId 
wxTreeListCtrl::GetPrevVisible(const wxTreeItemId
& item
, bool fullRow
) const 
4556 { return m_main_win
->GetPrevVisible(item
, fullRow
); } 
4558 wxTreeItemId 
wxTreeListCtrl::AddRoot (const wxString
& text
, int image
, 
4559                                       int selectedImage
, wxTreeItemData
* data
) 
4560 { return m_main_win
->AddRoot (text
, image
, selectedImage
, data
); } 
4562 wxTreeItemId 
wxTreeListCtrl::PrependItem(const wxTreeItemId
& parent
, 
4563                                          const wxString
& text
, int image
, 
4565                                          wxTreeItemData
* data
) 
4566 { return m_main_win
->PrependItem(parent
, text
, image
, selectedImage
, data
); } 
4568 wxTreeItemId 
wxTreeListCtrl::InsertItem(const wxTreeItemId
& parent
, 
4569                                         const wxTreeItemId
& previous
, 
4570                                         const wxString
& text
, int image
, 
4572                                         wxTreeItemData
* data
) 
4574     return m_main_win
->InsertItem(parent
, previous
, text
, image
, 
4575                                   selectedImage
, data
); 
4578 wxTreeItemId 
wxTreeListCtrl::InsertItem(const wxTreeItemId
& parent
, 
4580                                         const wxString
& text
, int image
, 
4582                                         wxTreeItemData
* data
) 
4584     return m_main_win
->InsertItem(parent
, index
, text
, image
, 
4585                                   selectedImage
, data
); 
4588 wxTreeItemId 
wxTreeListCtrl::AppendItem(const wxTreeItemId
& parent
, 
4589                                         const wxString
& text
, int image
, 
4591                                         wxTreeItemData
* data
) 
4592 { return m_main_win
->AppendItem(parent
, text
, image
, selectedImage
, data
); } 
4594 void wxTreeListCtrl::Delete(const wxTreeItemId
& item
) 
4595 { m_main_win
->Delete(item
); } 
4597 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId
& item
) 
4598 { m_main_win
->DeleteChildren(item
); } 
4600 void wxTreeListCtrl::DeleteRoot() 
4601 { m_main_win
->DeleteRoot(); } 
4603 void wxTreeListCtrl::Expand(const wxTreeItemId
& item
) 
4604 { m_main_win
->Expand(item
); } 
4606 void wxTreeListCtrl::ExpandAll(const wxTreeItemId
& item
) 
4607 { m_main_win
->ExpandAll(item
); } 
4609 void wxTreeListCtrl::Collapse(const wxTreeItemId
& item
) 
4610 { m_main_win
->Collapse(item
); } 
4612 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
4613 { m_main_win
->CollapseAndReset(item
); } 
4615 void wxTreeListCtrl::Toggle(const wxTreeItemId
& item
) 
4616 { m_main_win
->Toggle(item
); } 
4618 void wxTreeListCtrl::Unselect() 
4619 { m_main_win
->Unselect(); } 
4621 void wxTreeListCtrl::UnselectAll() 
4622 { m_main_win
->UnselectAll(); } 
4624 void wxTreeListCtrl::SelectItem(const wxTreeItemId
& item
, const wxTreeItemId
& last
, 
4625                                 bool unselect_others
) 
4626 { m_main_win
->SelectItem (item
, last
, unselect_others
); } 
4628 void wxTreeListCtrl::SelectAll() 
4629 { m_main_win
->SelectAll(); } 
4631 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId
& item
) 
4632 { m_main_win
->EnsureVisible(item
); } 
4634 void wxTreeListCtrl::ScrollTo(const wxTreeItemId
& item
) 
4635 { m_main_win
->ScrollTo(item
); } 
4637 wxTreeItemId 
wxTreeListCtrl::HitTest(const wxPoint
& pos
, int& flags
, int& column
) 
4639     return m_main_win
->HitTest (pos
, flags
, column
); 
4642 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId
& item
, wxRect
& rect
, 
4643                                      bool textOnly
) const 
4644 { return m_main_win
->GetBoundingRect(item
, rect
, textOnly
); } 
4646 void wxTreeListCtrl::EditLabel (const wxTreeItemId
& item
, int column
) 
4647 { m_main_win
->EditLabel (item
, column
); } 
4649 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
4650                                    const wxTreeItemId
& item2
) 
4652     // do the comparison here, and not delegate to m_main_win, in order 
4653     // to let the user override it 
4654     //return m_main_win->OnCompareItems(item1, item2); 
4655     return wxStrcmp(GetItemText(item1
), GetItemText(item2
)); 
4658 void wxTreeListCtrl::SortChildren(const wxTreeItemId
& item
) 
4659 { m_main_win
->SortChildren(item
); } 
4661 wxTreeItemId 
wxTreeListCtrl::FindItem (const wxTreeItemId
& item
, const wxString
& str
, int mode
) 
4662 { return m_main_win
->FindItem (item
, str
, mode
); } 
4664 void wxTreeListCtrl::SetDragItem (const wxTreeItemId
& item
) 
4665 { m_main_win
->SetDragItem (item
); } 
4667 bool wxTreeListCtrl::SetBackgroundColour(const wxColour
& colour
) 
4669     if (!m_main_win
) return false; 
4670     return m_main_win
->SetBackgroundColour(colour
); 
4673 bool wxTreeListCtrl::SetForegroundColour(const wxColour
& colour
) 
4675     if (!m_main_win
) return false; 
4676     return m_main_win
->SetForegroundColour(colour
); 
4679 int wxTreeListCtrl::GetColumnCount() const 
4680 { return m_main_win
->GetColumnCount(); } 
4682 void wxTreeListCtrl::SetColumnWidth(int column
, int width
) 
4684     if (width 
== wxLIST_AUTOSIZE_USEHEADER
) 
4686         wxFont font 
= m_header_win
->GetFont(); 
4687         m_header_win
->GetTextExtent(m_header_win
->GetColumnText(column
), &width
, NULL
, NULL
, NULL
, font
.Ok()? &font
: NULL
); 
4688         //search wxTreeListHeaderWindow::OnPaint to understand this: 
4689         width 
+= 2*EXTRA_WIDTH 
+ MARGIN
; 
4691     else if (width 
== wxLIST_AUTOSIZE
) 
4693         width 
= m_main_win
->GetBestColumnWidth(column
); 
4696     m_header_win
->SetColumnWidth (column
, width
); 
4697     m_header_win
->Refresh(); 
4700 int wxTreeListCtrl::GetColumnWidth(int column
) const 
4701 { return m_header_win
->GetColumnWidth(column
); } 
4703 void wxTreeListCtrl::SetMainColumn(int column
) 
4704 { m_main_win
->SetMainColumn(column
); } 
4706 int wxTreeListCtrl::GetMainColumn() const 
4707 { return m_main_win
->GetMainColumn(); } 
4709 void wxTreeListCtrl::SetColumnText(int column
, const wxString
& text
) 
4711     m_header_win
->SetColumnText (column
, text
); 
4712     m_header_win
->Refresh(); 
4715 wxString 
wxTreeListCtrl::GetColumnText(int column
) const 
4716 { return m_header_win
->GetColumnText(column
); } 
4718 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo
& colInfo
) 
4720     m_header_win
->AddColumn (colInfo
); 
4724 void wxTreeListCtrl::InsertColumn(int before
, const wxTreeListColumnInfo
& colInfo
) 
4726     m_header_win
->InsertColumn (before
, colInfo
); 
4727     m_header_win
->Refresh(); 
4730 void wxTreeListCtrl::RemoveColumn(int column
) 
4732     m_header_win
->RemoveColumn (column
); 
4733     m_header_win
->Refresh(); 
4736 void wxTreeListCtrl::SetColumn(int column
, const wxTreeListColumnInfo
& colInfo
) 
4738     m_header_win
->SetColumn (column
, colInfo
); 
4739     m_header_win
->Refresh(); 
4742 const wxTreeListColumnInfo
& wxTreeListCtrl::GetColumn(int column
) const 
4743 { return m_header_win
->GetColumn(column
); } 
4745 wxTreeListColumnInfo
& wxTreeListCtrl::GetColumn(int column
) 
4746 { return m_header_win
->GetColumn(column
); } 
4748 void wxTreeListCtrl::SetColumnImage(int column
, int image
) 
4750     m_header_win
->SetColumn (column
, GetColumn(column
).SetImage(image
)); 
4751     m_header_win
->Refresh(); 
4754 int wxTreeListCtrl::GetColumnImage(int column
) const 
4756     return m_header_win
->GetColumn(column
).GetImage(); 
4759 void wxTreeListCtrl::SetColumnEditable(int column
, bool shown
) 
4761     m_header_win
->SetColumn (column
, GetColumn(column
).SetEditable(shown
)); 
4764 void wxTreeListCtrl::SetColumnShown(int column
, bool shown
) 
4766     wxASSERT_MSG (column 
!= GetMainColumn(), _T("The main column may not be hidden") ); 
4767     m_header_win
->SetColumn (column
, GetColumn(column
).SetShown(GetMainColumn()==column
? true: shown
)); 
4768     m_header_win
->Refresh(); 
4771 bool wxTreeListCtrl::IsColumnEditable(int column
) const 
4773     return m_header_win
->GetColumn(column
).IsEditable(); 
4776 bool wxTreeListCtrl::IsColumnShown(int column
) const 
4778     return m_header_win
->GetColumn(column
).IsShown(); 
4781 void wxTreeListCtrl::SetColumnAlignment (int column
, int flag
) 
4783     m_header_win
->SetColumn(column
, GetColumn(column
).SetAlignment(flag
)); 
4784     m_header_win
->Refresh(); 
4787 int wxTreeListCtrl::GetColumnAlignment(int column
) const 
4789     return m_header_win
->GetColumn(column
).GetAlignment(); 
4792 void wxTreeListCtrl::Refresh(bool erase
, const wxRect
* rect
) 
4794     m_main_win
->Refresh (erase
, rect
); 
4795     m_header_win
->Refresh (erase
, rect
); 
4798 void wxTreeListCtrl::SetFocus() 
4799 { m_main_win
->SetFocus(); } 
4801 wxSize 
wxTreeListCtrl::DoGetBestSize() const 
4803     // something is better than nothing... 
4804     return wxSize (200,200); // but it should be specified values! FIXME 
4807 wxString 
wxTreeListCtrl::OnGetItemText( wxTreeItemData
* WXUNUSED(item
), long WXUNUSED(column
)) const 
4809     return wxEmptyString
;