1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/treectrl.cpp 
   4 // Author:      Julian Smart 
   5 // Modified by: Vadim Zeitlin to be less MSW-specific on 10.10.98 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "treectrl.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  33 #include "wx/msw/private.h" 
  35 // Set this to 1 to be _absolutely_ sure that repainting will work for all 
  36 // comctl32.dll versions 
  37 #define wxUSE_COMCTL32_SAFELY 0 
  41 #include "wx/dynarray.h" 
  42 #include "wx/imaglist.h" 
  43 #include "wx/settings.h" 
  44 #include "wx/msw/treectrl.h" 
  45 #include "wx/msw/dragimag.h" 
  47 // include <commctrl.h> "properly" 
  48 #include "wx/msw/wrapcctl.h" 
  50 // macros to hide the cast ugliness 
  51 // -------------------------------- 
  53 // ptr is the real item id, i.e. wxTreeItemId::m_pItem 
  54 #define HITEM_PTR(ptr)     (HTREEITEM)(ptr) 
  56 // item here is a wxTreeItemId 
  57 #define HITEM(item)     HITEM_PTR((item).m_pItem) 
  59 // the native control doesn't support multiple selections under MSW and we 
  60 // have 2 ways to emulate them: either using TVS_CHECKBOXES style and let 
  61 // checkboxes be the selection status (checked == selected) or by really 
  62 // emulating everything, i.e. intercepting mouse and key events &c. The first 
  63 // approach is much easier but doesn't work with comctl32.dll < 4.71 and also 
  65 #define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0 
  67 // ---------------------------------------------------------------------------- 
  69 // ---------------------------------------------------------------------------- 
  71 // wrapper for TreeView_HitTest 
  72 static HTREEITEM 
GetItemFromPoint(HWND hwndTV
, int x
, int y
) 
  78     return (HTREEITEM
)TreeView_HitTest(hwndTV
, &tvht
); 
  81 #if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
  83 // wrappers for TreeView_GetItem/TreeView_SetItem 
  84 static bool IsItemSelected(HWND hwndTV
, HTREEITEM hItem
) 
  88     tvi
.mask 
= TVIF_STATE 
| TVIF_HANDLE
; 
  89     tvi
.stateMask 
= TVIS_SELECTED
; 
  92     if ( !TreeView_GetItem(hwndTV
, &tvi
) ) 
  94         wxLogLastError(wxT("TreeView_GetItem")); 
  97     return (tvi
.state 
& TVIS_SELECTED
) != 0; 
 100 static bool SelectItem(HWND hwndTV
, HTREEITEM hItem
, bool select 
= true) 
 103     tvi
.mask 
= TVIF_STATE 
| TVIF_HANDLE
; 
 104     tvi
.stateMask 
= TVIS_SELECTED
; 
 105     tvi
.state 
= select 
? TVIS_SELECTED 
: 0; 
 108     if ( TreeView_SetItem(hwndTV
, &tvi
) == -1 ) 
 110         wxLogLastError(wxT("TreeView_SetItem")); 
 117 static inline void UnselectItem(HWND hwndTV
, HTREEITEM htItem
) 
 119     SelectItem(hwndTV
, htItem
, false); 
 122 static inline void ToggleItemSelection(HWND hwndTV
, HTREEITEM htItem
) 
 124     SelectItem(hwndTV
, htItem
, !IsItemSelected(hwndTV
, htItem
)); 
 127 // helper function which selects all items in a range and, optionally, 
 128 // unselects all others 
 129 static void SelectRange(HWND hwndTV
, 
 132                         bool unselectOthers 
= true) 
 134     // find the first (or last) item and select it 
 136     HTREEITEM htItem 
= (HTREEITEM
)TreeView_GetRoot(hwndTV
); 
 137     while ( htItem 
&& cont 
) 
 139         if ( (htItem 
== htFirst
) || (htItem 
== htLast
) ) 
 141             if ( !IsItemSelected(hwndTV
, htItem
) ) 
 143                 SelectItem(hwndTV
, htItem
); 
 150             if ( unselectOthers 
&& IsItemSelected(hwndTV
, htItem
) ) 
 152                 UnselectItem(hwndTV
, htItem
); 
 156         htItem 
= (HTREEITEM
)TreeView_GetNextVisible(hwndTV
, htItem
); 
 159     // select the items in range 
 160     cont 
= htFirst 
!= htLast
; 
 161     while ( htItem 
&& cont 
) 
 163         if ( !IsItemSelected(hwndTV
, htItem
) ) 
 165             SelectItem(hwndTV
, htItem
); 
 168         cont 
= (htItem 
!= htFirst
) && (htItem 
!= htLast
); 
 170         htItem 
= (HTREEITEM
)TreeView_GetNextVisible(hwndTV
, htItem
); 
 174     if ( unselectOthers 
) 
 178             if ( IsItemSelected(hwndTV
, htItem
) ) 
 180                 UnselectItem(hwndTV
, htItem
); 
 183             htItem 
= (HTREEITEM
)TreeView_GetNextVisible(hwndTV
, htItem
); 
 187     // seems to be necessary - otherwise the just selected items don't always 
 188     // appear as selected 
 189     UpdateWindow(hwndTV
); 
 192 // helper function which tricks the standard control into changing the focused 
 193 // item without changing anything else (if someone knows why Microsoft doesn't 
 194 // allow to do it by just setting TVIS_FOCUSED flag, please tell me!) 
 195 static void SetFocus(HWND hwndTV
, HTREEITEM htItem
) 
 198     HTREEITEM htFocus 
= (HTREEITEM
)TreeView_GetSelection(hwndTV
); 
 203         if ( htItem 
!= htFocus 
) 
 205             // remember the selection state of the item 
 206             bool wasSelected 
= IsItemSelected(hwndTV
, htItem
); 
 208             if ( htFocus 
&& IsItemSelected(hwndTV
, htFocus
) ) 
 210                 // prevent the tree from unselecting the old focus which it 
 211                 // would do by default (TreeView_SelectItem unselects the 
 213                 TreeView_SelectItem(hwndTV
, 0); 
 214                 SelectItem(hwndTV
, htFocus
); 
 217             TreeView_SelectItem(hwndTV
, htItem
); 
 221                 // need to clear the selection which TreeView_SelectItem() gave 
 223                 UnselectItem(hwndTV
, htItem
); 
 225             //else: was selected, still selected - ok 
 227         //else: nothing to do, focus already there 
 233             bool wasFocusSelected 
= IsItemSelected(hwndTV
, htFocus
); 
 235             // just clear the focus 
 236             TreeView_SelectItem(hwndTV
, 0); 
 238             if ( wasFocusSelected 
) 
 240                 // restore the selection state 
 241                 SelectItem(hwndTV
, htFocus
); 
 244         //else: nothing to do, no focus already 
 248 #endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
 250 // ---------------------------------------------------------------------------- 
 252 // ---------------------------------------------------------------------------- 
 254 // a convenient wrapper around TV_ITEM struct which adds a ctor 
 256 #pragma warning( disable : 4097 ) // inheriting from typedef 
 259 struct wxTreeViewItem 
: public TV_ITEM
 
 261     wxTreeViewItem(const wxTreeItemId
& item
,    // the item handle 
 262                    UINT mask_
,                  // fields which are valid 
 263                    UINT stateMask_ 
= 0)         // for TVIF_STATE only 
 267         // hItem member is always valid 
 268         mask 
= mask_ 
| TVIF_HANDLE
; 
 269         stateMask 
= stateMask_
; 
 274 // wxVirutalNode is used in place of a single root when 'hidden' root is 
 276 class wxVirtualNode 
: public wxTreeViewItem
 
 279     wxVirtualNode(wxTreeItemData 
*data
) 
 280         : wxTreeViewItem(TVI_ROOT
, 0) 
 290     wxTreeItemData 
*GetData() const { return m_data
; } 
 291     void SetData(wxTreeItemData 
*data
) { delete m_data
; m_data 
= data
; } 
 294     wxTreeItemData 
*m_data
; 
 296     DECLARE_NO_COPY_CLASS(wxVirtualNode
) 
 300 #pragma warning( default : 4097 ) 
 303 // a macro to get the virtual root, returns NULL if none 
 304 #define GET_VIRTUAL_ROOT() ((wxVirtualNode *)m_pVirtualRoot) 
 306 // returns true if the item is the virtual root 
 307 #define IS_VIRTUAL_ROOT(item) (HITEM(item) == TVI_ROOT) 
 309 // a class which encapsulates the tree traversal logic: it vists all (unless 
 310 // OnVisit() returns false) items under the given one 
 311 class wxTreeTraversal
 
 314     wxTreeTraversal(const wxTreeCtrl 
*tree
) 
 319     // do traverse the tree: visit all items (recursively by default) under the 
 320     // given one; return true if all items were traversed or false if the 
 321     // traversal was aborted because OnVisit returned false 
 322     bool DoTraverse(const wxTreeItemId
& root
, bool recursively 
= true); 
 324     // override this function to do whatever is needed for each item, return 
 325     // false to stop traversing 
 326     virtual bool OnVisit(const wxTreeItemId
& item
) = 0; 
 329     const wxTreeCtrl 
*GetTree() const { return m_tree
; } 
 332     bool Traverse(const wxTreeItemId
& root
, bool recursively
); 
 334     const wxTreeCtrl 
*m_tree
; 
 336     DECLARE_NO_COPY_CLASS(wxTreeTraversal
) 
 339 // internal class for getting the selected items 
 340 class TraverseSelections 
: public wxTreeTraversal
 
 343     TraverseSelections(const wxTreeCtrl 
*tree
, 
 344                        wxArrayTreeItemIds
& selections
) 
 345         : wxTreeTraversal(tree
), m_selections(selections
) 
 347             m_selections
.Empty(); 
 349             DoTraverse(tree
->GetRootItem()); 
 352     virtual bool OnVisit(const wxTreeItemId
& item
) 
 354         // can't visit a virtual node. 
 355         if ( (GetTree()->GetRootItem() == item
) && (GetTree()->GetWindowStyle() & wxTR_HIDE_ROOT
)) 
 360 #if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
 361         if ( GetTree()->IsItemChecked(item
) ) 
 363         if ( ::IsItemSelected(GetHwndOf(GetTree()), HITEM(item
)) ) 
 366             m_selections
.Add(item
); 
 372     size_t GetCount() const { return m_selections
.GetCount(); } 
 375     wxArrayTreeItemIds
& m_selections
; 
 377     DECLARE_NO_COPY_CLASS(TraverseSelections
) 
 380 // internal class for counting tree items 
 381 class TraverseCounter 
: public wxTreeTraversal
 
 384     TraverseCounter(const wxTreeCtrl 
*tree
, 
 385                     const wxTreeItemId
& root
, 
 387         : wxTreeTraversal(tree
) 
 391             DoTraverse(root
, recursively
); 
 394     virtual bool OnVisit(const wxTreeItemId
& WXUNUSED(item
)) 
 401     size_t GetCount() const { return m_count
; } 
 406     DECLARE_NO_COPY_CLASS(TraverseCounter
) 
 409 // ---------------------------------------------------------------------------- 
 410 // This class is needed for support of different images: the Win32 common 
 411 // control natively supports only 2 images (the normal one and another for the 
 412 // selected state). We wish to provide support for 2 more of them for folder 
 413 // items (i.e. those which have children): for expanded state and for expanded 
 414 // selected state. For this we use this structure to store the additional items 
 417 // There is only one problem with this: when we retrieve the item's data, we 
 418 // don't know whether we get a pointer to wxTreeItemData or 
 419 // wxTreeItemIndirectData. So we always set the item id to an invalid value 
 420 // in this class and the code using the client data checks for it and retrieves 
 421 // the real client data in this case. 
 422 // ---------------------------------------------------------------------------- 
 424 class wxTreeItemIndirectData 
: public wxTreeItemData
 
 427     // ctor associates this data with the item and the real item data becomes 
 428     // available through our GetData() method 
 429     wxTreeItemIndirectData(wxTreeCtrl 
*tree
, const wxTreeItemId
& item
) 
 431         for ( size_t n 
= 0; n 
< WXSIZEOF(m_images
); n
++ ) 
 437         m_data 
= tree
->GetItemData(item
); 
 439         // and set ourselves as the new one 
 440         tree
->SetIndirectItemData(item
, this); 
 442         // we must have the invalid value for the item 
 446     // dtor deletes the associated data as well 
 447     virtual ~wxTreeItemIndirectData() { delete m_data
; } 
 450         // get the real data associated with the item 
 451     wxTreeItemData 
*GetData() const { return m_data
; } 
 453     void SetData(wxTreeItemData 
*data
) { m_data 
= data
; } 
 455         // do we have such image? 
 456     bool HasImage(wxTreeItemIcon which
) const { return m_images
[which
] != -1; } 
 458     int GetImage(wxTreeItemIcon which
) const { return m_images
[which
]; } 
 460     void SetImage(int image
, wxTreeItemIcon which
) { m_images
[which
] = image
; } 
 463     // all the images associated with the item 
 464     int m_images
[wxTreeItemIcon_Max
]; 
 466     // the real client data 
 467     wxTreeItemData 
*m_data
; 
 469     DECLARE_NO_COPY_CLASS(wxTreeItemIndirectData
) 
 472 // ---------------------------------------------------------------------------- 
 474 // ---------------------------------------------------------------------------- 
 476 #if wxUSE_EXTENDED_RTTI 
 477 WX_DEFINE_FLAGS( wxTreeCtrlStyle 
) 
 479 wxBEGIN_FLAGS( wxTreeCtrlStyle 
) 
 480     // new style border flags, we put them first to 
 481     // use them for streaming out 
 482     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
 483     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
 484     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
 485     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
 486     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
 487     wxFLAGS_MEMBER(wxBORDER_NONE
) 
 489     // old style border flags 
 490     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
 491     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
 492     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
 493     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
 494     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
 495     wxFLAGS_MEMBER(wxBORDER
) 
 497     // standard window styles 
 498     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
 499     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
 500     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
 501     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
 502     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
 503     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
 504     wxFLAGS_MEMBER(wxVSCROLL
) 
 505     wxFLAGS_MEMBER(wxHSCROLL
) 
 507     wxFLAGS_MEMBER(wxTR_EDIT_LABELS
) 
 508     wxFLAGS_MEMBER(wxTR_NO_BUTTONS
) 
 509     wxFLAGS_MEMBER(wxTR_HAS_BUTTONS
) 
 510     wxFLAGS_MEMBER(wxTR_TWIST_BUTTONS
) 
 511     wxFLAGS_MEMBER(wxTR_NO_LINES
) 
 512     wxFLAGS_MEMBER(wxTR_FULL_ROW_HIGHLIGHT
) 
 513     wxFLAGS_MEMBER(wxTR_LINES_AT_ROOT
) 
 514     wxFLAGS_MEMBER(wxTR_HIDE_ROOT
) 
 515     wxFLAGS_MEMBER(wxTR_ROW_LINES
) 
 516     wxFLAGS_MEMBER(wxTR_HAS_VARIABLE_ROW_HEIGHT
) 
 517     wxFLAGS_MEMBER(wxTR_SINGLE
) 
 518     wxFLAGS_MEMBER(wxTR_MULTIPLE
) 
 519     wxFLAGS_MEMBER(wxTR_EXTENDED
) 
 520     wxFLAGS_MEMBER(wxTR_DEFAULT_STYLE
) 
 522 wxEND_FLAGS( wxTreeCtrlStyle 
) 
 524 IMPLEMENT_DYNAMIC_CLASS_XTI(wxTreeCtrl
, wxControl
,"wx/treectrl.h") 
 526 wxBEGIN_PROPERTIES_TABLE(wxTreeCtrl
) 
 527     wxEVENT_PROPERTY( TextUpdated 
, wxEVT_COMMAND_TEXT_UPDATED 
, wxCommandEvent 
) 
 528     wxEVENT_RANGE_PROPERTY( TreeEvent 
, wxEVT_COMMAND_TREE_BEGIN_DRAG 
, wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK 
, wxTreeEvent 
) 
 529     wxPROPERTY_FLAGS( WindowStyle 
, wxTreeCtrlStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 530 wxEND_PROPERTIES_TABLE() 
 532 wxBEGIN_HANDLERS_TABLE(wxTreeCtrl
) 
 533 wxEND_HANDLERS_TABLE() 
 535 wxCONSTRUCTOR_5( wxTreeCtrl 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle 
) 
 537 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxControl
) 
 540 // ---------------------------------------------------------------------------- 
 542 // ---------------------------------------------------------------------------- 
 544 // indices in gs_expandEvents table below 
 559 // handy table for sending events - it has to be initialized during run-time 
 560 // now so can't be const any more 
 561 static /* const */ wxEventType gs_expandEvents
[IDX_WHAT_MAX
][IDX_HOW_MAX
]; 
 564    but logically it's a const table with the following entries: 
 567     { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING }, 
 568     { wxEVT_COMMAND_TREE_ITEM_EXPANDED,  wxEVT_COMMAND_TREE_ITEM_EXPANDING  } 
 572 // ============================================================================ 
 574 // ============================================================================ 
 576 // ---------------------------------------------------------------------------- 
 578 // ---------------------------------------------------------------------------- 
 580 bool wxTreeTraversal::DoTraverse(const wxTreeItemId
& root
, bool recursively
) 
 582     if ( !OnVisit(root
) ) 
 585     return Traverse(root
, recursively
); 
 588 bool wxTreeTraversal::Traverse(const wxTreeItemId
& root
, bool recursively
) 
 590     wxTreeItemIdValue cookie
; 
 591     wxTreeItemId child 
= m_tree
->GetFirstChild(root
, cookie
); 
 592     while ( child
.IsOk() ) 
 594         // depth first traversal 
 595         if ( recursively 
&& !Traverse(child
, true) ) 
 598         if ( !OnVisit(child
) ) 
 601         child 
= m_tree
->GetNextChild(root
, cookie
); 
 607 // ---------------------------------------------------------------------------- 
 608 // construction and destruction 
 609 // ---------------------------------------------------------------------------- 
 611 void wxTreeCtrl::Init() 
 613     m_imageListNormal 
= NULL
; 
 614     m_imageListState 
= NULL
; 
 615     m_ownsImageListNormal 
= m_ownsImageListState 
= false; 
 617     m_hasAnyAttr 
= false; 
 619     m_pVirtualRoot 
= NULL
; 
 621     // initialize the global array of events now as it can't be done statically 
 622     // with the wxEVT_XXX values being allocated during run-time only 
 623     gs_expandEvents
[IDX_COLLAPSE
][IDX_DONE
] = wxEVT_COMMAND_TREE_ITEM_COLLAPSED
; 
 624     gs_expandEvents
[IDX_COLLAPSE
][IDX_DOING
] = wxEVT_COMMAND_TREE_ITEM_COLLAPSING
; 
 625     gs_expandEvents
[IDX_EXPAND
][IDX_DONE
] = wxEVT_COMMAND_TREE_ITEM_EXPANDED
; 
 626     gs_expandEvents
[IDX_EXPAND
][IDX_DOING
] = wxEVT_COMMAND_TREE_ITEM_EXPANDING
; 
 629 bool wxTreeCtrl::Create(wxWindow 
*parent
, 
 634                         const wxValidator
& validator
, 
 635                         const wxString
& name
) 
 639     if ( (style 
& wxBORDER_MASK
) == wxBORDER_DEFAULT 
) 
 640         style 
|= wxBORDER_SUNKEN
; 
 642     if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) ) 
 646     DWORD wstyle 
= MSWGetStyle(m_windowStyle
, & exStyle
); 
 647     wstyle 
|= WS_TABSTOP 
| TVS_SHOWSELALWAYS
; 
 649     if ((m_windowStyle 
& wxTR_NO_LINES
) == 0) 
 650         wstyle 
|= TVS_HASLINES
; 
 651     if ( m_windowStyle 
& wxTR_HAS_BUTTONS 
) 
 652         wstyle 
|= TVS_HASBUTTONS
; 
 654     if ( m_windowStyle 
& wxTR_EDIT_LABELS 
) 
 655         wstyle 
|= TVS_EDITLABELS
; 
 657     if ( m_windowStyle 
& wxTR_LINES_AT_ROOT 
) 
 658         wstyle 
|= TVS_LINESATROOT
; 
 660     if ( m_windowStyle 
& wxTR_FULL_ROW_HIGHLIGHT 
) 
 662         if ( wxApp::GetComCtl32Version() >= 471 ) 
 663             wstyle 
|= TVS_FULLROWSELECT
; 
 666     // using TVS_CHECKBOXES for emulation of a multiselection tree control 
 667     // doesn't work without the new enough headers 
 668 #if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE && \ 
 669     !defined( __GNUWIN32_OLD__ ) && \ 
 670     !defined( __BORLANDC__ ) && \ 
 671     !defined( __WATCOMC__ ) && \ 
 672     (!defined(__VISUALC__) || (__VISUALC__ > 1010)) 
 674     // we emulate the multiple selection tree controls by using checkboxes: set 
 675     // up the image list we need for this if we do have multiple selections 
 676     if ( m_windowStyle 
& wxTR_MULTIPLE 
) 
 677         wstyle 
|= TVS_CHECKBOXES
; 
 678 #endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
 681     // Need so that TVN_GETINFOTIP messages will be sent 
 682     wstyle 
|= TVS_INFOTIP
; 
 685     // Create the tree control. 
 686     if ( !MSWCreateControl(WC_TREEVIEW
, wstyle
, pos
, size
) ) 
 689 #if wxUSE_COMCTL32_SAFELY 
 690     wxWindow::SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 691     wxWindow::SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); 
 693     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 694     SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); 
 696     // This works around a bug in the Windows tree control whereby for some versions 
 697     // of comctrl32, setting any colour actually draws the background in black. 
 698     // This will initialise the background to the system colour. 
 699     // THIS FIX NOW REVERTED since it caused problems on _other_ systems. 
 700     // Assume the user has an updated comctl32.dll. 
 701     ::SendMessage(GetHwnd(), TVM_SETBKCOLOR
, 0,-1); 
 702     wxWindow::SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 703     SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); 
 707     // VZ: this is some experimental code which may be used to get the 
 708     //     TVS_CHECKBOXES style functionality for comctl32.dll < 4.71. 
 709     //     AFAIK, the standard DLL does about the same thing anyhow. 
 711     if ( m_windowStyle 
& wxTR_MULTIPLE 
) 
 715         // create the DC compatible with the current screen 
 716         HDC hdcMem 
= CreateCompatibleDC(NULL
); 
 718         // create a mono bitmap of the standard size 
 719         int x 
= ::GetSystemMetrics(SM_CXMENUCHECK
); 
 720         int y 
= ::GetSystemMetrics(SM_CYMENUCHECK
); 
 721         wxImageList 
imagelistCheckboxes(x
, y
, false, 2); 
 722         HBITMAP hbmpCheck 
= CreateBitmap(x
, y
,   // bitmap size 
 723                                          1,      // # of color planes 
 724                                          1,      // # bits needed for one pixel 
 725                                          0);     // array containing colour data 
 726         SelectObject(hdcMem
, hbmpCheck
); 
 728         // then draw a check mark into it 
 729         RECT rect 
= { 0, 0, x
, y 
}; 
 730         if ( !::DrawFrameControl(hdcMem
, &rect
, 
 732                                  DFCS_BUTTONCHECK 
| DFCS_CHECKED
) ) 
 734             wxLogLastError(wxT("DrawFrameControl(check)")); 
 737         bmp
.SetHBITMAP((WXHBITMAP
)hbmpCheck
); 
 738         imagelistCheckboxes
.Add(bmp
); 
 740         if ( !::DrawFrameControl(hdcMem
, &rect
, 
 744             wxLogLastError(wxT("DrawFrameControl(uncheck)")); 
 747         bmp
.SetHBITMAP((WXHBITMAP
)hbmpCheck
); 
 748         imagelistCheckboxes
.Add(bmp
); 
 754         SetStateImageList(&imagelistCheckboxes
); 
 758     wxSetCCUnicodeFormat(GetHwnd()); 
 763 wxTreeCtrl::~wxTreeCtrl() 
 765     // delete any attributes 
 768         WX_CLEAR_HASH_MAP(wxMapTreeAttr
, m_attrs
); 
 770         // prevent TVN_DELETEITEM handler from deleting the attributes again! 
 771         m_hasAnyAttr 
= false; 
 776     // delete user data to prevent memory leaks 
 777     // also deletes hidden root node storage. 
 780     if (m_ownsImageListNormal
) delete m_imageListNormal
; 
 781     if (m_ownsImageListState
) delete m_imageListState
; 
 784 // ---------------------------------------------------------------------------- 
 786 // ---------------------------------------------------------------------------- 
 788 /* static */ wxVisualAttributes
 
 789 wxTreeCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
 791     wxVisualAttributes attrs 
= GetCompositeControlsDefaultAttributes(variant
); 
 793     // common controls have their own default font 
 794     attrs
.font 
= wxGetCCDefaultFont(); 
 800 // simple wrappers which add error checking in debug mode 
 802 bool wxTreeCtrl::DoGetItem(wxTreeViewItem
* tvItem
) const 
 804     wxCHECK_MSG( tvItem
->hItem 
!= TVI_ROOT
, false, 
 805                  _T("can't retrieve virtual root item") ); 
 807     if ( !TreeView_GetItem(GetHwnd(), tvItem
) ) 
 809         wxLogLastError(wxT("TreeView_GetItem")); 
 817 void wxTreeCtrl::DoSetItem(wxTreeViewItem
* tvItem
) 
 819     if ( TreeView_SetItem(GetHwnd(), tvItem
) == -1 ) 
 821         wxLogLastError(wxT("TreeView_SetItem")); 
 825 size_t wxTreeCtrl::GetCount() const 
 827     return (size_t)TreeView_GetCount(GetHwnd()); 
 830 unsigned int wxTreeCtrl::GetIndent() const 
 832     return TreeView_GetIndent(GetHwnd()); 
 835 void wxTreeCtrl::SetIndent(unsigned int indent
) 
 837     TreeView_SetIndent(GetHwnd(), indent
); 
 840 wxImageList 
*wxTreeCtrl::GetImageList() const 
 842     return m_imageListNormal
; 
 845 wxImageList 
*wxTreeCtrl::GetStateImageList() const 
 847     return m_imageListState
; 
 850 void wxTreeCtrl::SetAnyImageList(wxImageList 
*imageList
, int which
) 
 853     TreeView_SetImageList(GetHwnd(), 
 854                           imageList 
? imageList
->GetHIMAGELIST() : 0, 
 858 void wxTreeCtrl::SetImageList(wxImageList 
*imageList
) 
 860     if (m_ownsImageListNormal
) 
 861         delete m_imageListNormal
; 
 863     SetAnyImageList(m_imageListNormal 
= imageList
, TVSIL_NORMAL
); 
 864     m_ownsImageListNormal 
= false; 
 867 void wxTreeCtrl::SetStateImageList(wxImageList 
*imageList
) 
 869     if (m_ownsImageListState
) delete m_imageListState
; 
 870     SetAnyImageList(m_imageListState 
= imageList
, TVSIL_STATE
); 
 871     m_ownsImageListState 
= false; 
 874 void wxTreeCtrl::AssignImageList(wxImageList 
*imageList
) 
 876     SetImageList(imageList
); 
 877     m_ownsImageListNormal 
= true; 
 880 void wxTreeCtrl::AssignStateImageList(wxImageList 
*imageList
) 
 882     SetStateImageList(imageList
); 
 883     m_ownsImageListState 
= true; 
 886 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, 
 887                                     bool recursively
) const 
 889     wxCHECK_MSG( item
.IsOk(), 0u, wxT("invalid tree item") ); 
 891     TraverseCounter 
counter(this, item
, recursively
); 
 892     return counter
.GetCount() - 1; 
 895 // ---------------------------------------------------------------------------- 
 897 // ---------------------------------------------------------------------------- 
 899 bool wxTreeCtrl::SetBackgroundColour(const wxColour 
&colour
) 
 901 #if !wxUSE_COMCTL32_SAFELY 
 902     if ( !wxWindowBase::SetBackgroundColour(colour
) ) 
 905     ::SendMessage(GetHwnd(), TVM_SETBKCOLOR
, 0, colour
.GetPixel()); 
 911 bool wxTreeCtrl::SetForegroundColour(const wxColour 
&colour
) 
 913 #if !wxUSE_COMCTL32_SAFELY 
 914     if ( !wxWindowBase::SetForegroundColour(colour
) ) 
 917     ::SendMessage(GetHwnd(), TVM_SETTEXTCOLOR
, 0, colour
.GetPixel()); 
 923 // ---------------------------------------------------------------------------- 
 925 // ---------------------------------------------------------------------------- 
 927 wxString 
wxTreeCtrl::GetItemText(const wxTreeItemId
& item
) const 
 929     wxCHECK_MSG( item
.IsOk(), wxEmptyString
, wxT("invalid tree item") ); 
 931     wxChar buf
[512];  // the size is arbitrary... 
 933     wxTreeViewItem 
tvItem(item
, TVIF_TEXT
); 
 934     tvItem
.pszText 
= buf
; 
 935     tvItem
.cchTextMax 
= WXSIZEOF(buf
); 
 936     if ( !DoGetItem(&tvItem
) ) 
 938         // don't return some garbage which was on stack, but an empty string 
 942     return wxString(buf
); 
 945 void wxTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
) 
 947     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
 949     if ( IS_VIRTUAL_ROOT(item
) ) 
 952     wxTreeViewItem 
tvItem(item
, TVIF_TEXT
); 
 953     tvItem
.pszText 
= (wxChar 
*)text
.c_str();  // conversion is ok 
 956     // when setting the text of the item being edited, the text control should 
 957     // be updated to reflect the new text as well, otherwise calling 
 958     // SetItemText() in the OnBeginLabelEdit() handler doesn't have any effect 
 960     // don't use GetEditControl() here because m_textCtrl is not set yet 
 961     HWND hwndEdit 
= TreeView_GetEditControl(GetHwnd()); 
 964         if ( item 
== m_idEdited 
) 
 966             ::SetWindowText(hwndEdit
, text
); 
 971 int wxTreeCtrl::DoGetItemImageFromData(const wxTreeItemId
& item
, 
 972                                        wxTreeItemIcon which
) const 
 974     wxTreeViewItem 
tvItem(item
, TVIF_PARAM
); 
 975     if ( !DoGetItem(&tvItem
) ) 
 980     return ((wxTreeItemIndirectData 
*)tvItem
.lParam
)->GetImage(which
); 
 983 void wxTreeCtrl::DoSetItemImageFromData(const wxTreeItemId
& item
, 
 985                                         wxTreeItemIcon which
) const 
 987     wxTreeViewItem 
tvItem(item
, TVIF_PARAM
); 
 988     if ( !DoGetItem(&tvItem
) ) 
 993     wxTreeItemIndirectData 
*data 
= ((wxTreeItemIndirectData 
*)tvItem
.lParam
); 
 995     data
->SetImage(image
, which
); 
 997     // make sure that we have selected images as well 
 998     if ( which 
== wxTreeItemIcon_Normal 
&& 
 999          !data
->HasImage(wxTreeItemIcon_Selected
) ) 
1001         data
->SetImage(image
, wxTreeItemIcon_Selected
); 
1004     if ( which 
== wxTreeItemIcon_Expanded 
&& 
1005          !data
->HasImage(wxTreeItemIcon_SelectedExpanded
) ) 
1007         data
->SetImage(image
, wxTreeItemIcon_SelectedExpanded
); 
1011 void wxTreeCtrl::DoSetItemImages(const wxTreeItemId
& item
, 
1015     wxTreeViewItem 
tvItem(item
, TVIF_IMAGE 
| TVIF_SELECTEDIMAGE
); 
1016     tvItem
.iSelectedImage 
= imageSel
; 
1017     tvItem
.iImage 
= image
; 
1021 int wxTreeCtrl::GetItemImage(const wxTreeItemId
& item
, 
1022                              wxTreeItemIcon which
) const 
1024     wxCHECK_MSG( item
.IsOk(), -1, wxT("invalid tree item") ); 
1026     if ( (HITEM(item
) == TVI_ROOT
) && (m_windowStyle 
& wxTR_HIDE_ROOT
) ) 
1028         // TODO: Maybe a hidden root can still provide images? 
1032     if ( HasIndirectData(item
) ) 
1034         return DoGetItemImageFromData(item
, which
); 
1041             wxFAIL_MSG( wxT("unknown tree item image type") ); 
1043         case wxTreeItemIcon_Normal
: 
1047         case wxTreeItemIcon_Selected
: 
1048             mask 
= TVIF_SELECTEDIMAGE
; 
1051         case wxTreeItemIcon_Expanded
: 
1052         case wxTreeItemIcon_SelectedExpanded
: 
1056     wxTreeViewItem 
tvItem(item
, mask
); 
1059     return mask 
== TVIF_IMAGE 
? tvItem
.iImage 
: tvItem
.iSelectedImage
; 
1062 void wxTreeCtrl::SetItemImage(const wxTreeItemId
& item
, int image
, 
1063                               wxTreeItemIcon which
) 
1065     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1067     if ( IS_VIRTUAL_ROOT(item
) ) 
1069         // TODO: Maybe a hidden root can still store images? 
1079             wxFAIL_MSG( wxT("unknown tree item image type") ); 
1082         case wxTreeItemIcon_Normal
: 
1084                 const int imageNormalOld 
= GetItemImage(item
); 
1085                 const int imageSelOld 
= 
1086                     GetItemImage(item
, wxTreeItemIcon_Selected
); 
1088                 // always set the normal image 
1089                 imageNormal 
= image
; 
1091                 // if the selected and normal images were the same, they should 
1092                 // be the same after the update, otherwise leave the selected 
1094                 imageSel 
= imageNormalOld 
== imageSelOld 
? image 
: imageSelOld
; 
1098         case wxTreeItemIcon_Selected
: 
1099             imageNormal 
= GetItemImage(item
); 
1103         case wxTreeItemIcon_Expanded
: 
1104         case wxTreeItemIcon_SelectedExpanded
: 
1105             if ( !HasIndirectData(item
) ) 
1107                 // we need to get the old images first, because after we create 
1108                 // the wxTreeItemIndirectData GetItemXXXImage() will use it to 
1110                 imageNormal 
= GetItemImage(item
); 
1111                 imageSel 
= GetItemImage(item
, wxTreeItemIcon_Selected
); 
1113                 // if it doesn't have it yet, add it 
1114                 wxTreeItemIndirectData 
*data 
= new 
1115                     wxTreeItemIndirectData(this, item
); 
1117                 // copy the data to the new location 
1118                 data
->SetImage(imageNormal
, wxTreeItemIcon_Normal
); 
1119                 data
->SetImage(imageSel
, wxTreeItemIcon_Selected
); 
1122             DoSetItemImageFromData(item
, image
, which
); 
1124             // reset the normal/selected images because we won't use them any 
1125             // more - now they're stored inside the indirect data 
1127             imageSel 
= I_IMAGECALLBACK
; 
1131     // NB: at least in version 5.00.0518.9 of comctl32.dll we need to always 
1132     //     change both normal and selected image - otherwise the change simply 
1133     //     doesn't take place! 
1134     DoSetItemImages(item
, imageNormal
, imageSel
); 
1137 wxTreeItemData 
*wxTreeCtrl::GetItemData(const wxTreeItemId
& item
) const 
1139     wxCHECK_MSG( item
.IsOk(), NULL
, wxT("invalid tree item") ); 
1141     wxTreeViewItem 
tvItem(item
, TVIF_PARAM
); 
1143     // Hidden root may have data. 
1144     if ( IS_VIRTUAL_ROOT(item
) ) 
1146         return GET_VIRTUAL_ROOT()->GetData(); 
1150     if ( !DoGetItem(&tvItem
) ) 
1155     wxTreeItemData 
*data 
= (wxTreeItemData 
*)tvItem
.lParam
; 
1156     if ( IsDataIndirect(data
) ) 
1158         data 
= ((wxTreeItemIndirectData 
*)data
)->GetData(); 
1164 void wxTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData 
*data
) 
1166     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1168     if ( IS_VIRTUAL_ROOT(item
) ) 
1170         GET_VIRTUAL_ROOT()->SetData(data
); 
1173     // first, associate this piece of data with this item 
1179     wxTreeViewItem 
tvItem(item
, TVIF_PARAM
); 
1181     if ( HasIndirectData(item
) ) 
1183         if ( DoGetItem(&tvItem
) ) 
1185             ((wxTreeItemIndirectData 
*)tvItem
.lParam
)->SetData(data
); 
1189             wxFAIL_MSG( wxT("failed to change tree items data") ); 
1194         tvItem
.lParam 
= (LPARAM
)data
; 
1199 void wxTreeCtrl::SetIndirectItemData(const wxTreeItemId
& item
, 
1200                                      wxTreeItemIndirectData 
*data
) 
1202     // this should never happen because it's unnecessary and will probably lead 
1203     // to crash too because the code elsewhere supposes that the pointer the 
1204     // wxTreeItemIndirectData has is a real wxItemData and not 
1205     // wxTreeItemIndirectData as well 
1206     wxASSERT_MSG( !HasIndirectData(item
), wxT("setting indirect data twice?") ); 
1208     SetItemData(item
, data
); 
1211 bool wxTreeCtrl::HasIndirectData(const wxTreeItemId
& item
) const 
1213     // query the item itself 
1214     wxTreeViewItem 
tvItem(item
, TVIF_PARAM
); 
1215     if ( !DoGetItem(&tvItem
) ) 
1220     wxTreeItemData 
*data 
= (wxTreeItemData 
*)tvItem
.lParam
; 
1222     return data 
&& IsDataIndirect(data
); 
1225 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
) 
1227     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1229     if ( IS_VIRTUAL_ROOT(item
) ) 
1232     wxTreeViewItem 
tvItem(item
, TVIF_CHILDREN
); 
1233     tvItem
.cChildren 
= (int)has
; 
1237 void wxTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
) 
1239     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1241     if ( IS_VIRTUAL_ROOT(item
) ) 
1244     wxTreeViewItem 
tvItem(item
, TVIF_STATE
, TVIS_BOLD
); 
1245     tvItem
.state 
= bold 
? TVIS_BOLD 
: 0; 
1249 void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId
& item
, bool highlight
) 
1251     if ( IS_VIRTUAL_ROOT(item
) ) 
1254     wxTreeViewItem 
tvItem(item
, TVIF_STATE
, TVIS_DROPHILITED
); 
1255     tvItem
.state 
= highlight 
? TVIS_DROPHILITED 
: 0; 
1259 void wxTreeCtrl::RefreshItem(const wxTreeItemId
& item
) 
1261     if ( IS_VIRTUAL_ROOT(item
) ) 
1265     if ( GetBoundingRect(item
, rect
) ) 
1271 wxColour 
wxTreeCtrl::GetItemTextColour(const wxTreeItemId
& item
) const 
1273     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
1275     wxMapTreeAttr::const_iterator it 
= m_attrs
.find(item
.m_pItem
); 
1276     return it 
== m_attrs
.end() ? wxNullColour 
: it
->second
->GetTextColour(); 
1279 wxColour 
wxTreeCtrl::GetItemBackgroundColour(const wxTreeItemId
& item
) const 
1281     wxCHECK_MSG( item
.IsOk(), wxNullColour
, wxT("invalid tree item") ); 
1283     wxMapTreeAttr::const_iterator it 
= m_attrs
.find(item
.m_pItem
); 
1284     return it 
== m_attrs
.end() ? wxNullColour 
: it
->second
->GetBackgroundColour(); 
1287 wxFont 
wxTreeCtrl::GetItemFont(const wxTreeItemId
& item
) const 
1289     wxCHECK_MSG( item
.IsOk(), wxNullFont
, wxT("invalid tree item") ); 
1291     wxMapTreeAttr::const_iterator it 
= m_attrs
.find(item
.m_pItem
); 
1292     return it 
== m_attrs
.end() ? wxNullFont 
: it
->second
->GetFont(); 
1295 void wxTreeCtrl::SetItemTextColour(const wxTreeItemId
& item
, 
1296                                    const wxColour
& col
) 
1298     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1300     wxTreeItemAttr 
*attr
; 
1301     wxMapTreeAttr::iterator it 
= m_attrs
.find(item
.m_pItem
); 
1302     if ( it 
== m_attrs
.end() ) 
1304         m_hasAnyAttr 
= true; 
1306         m_attrs
[item
.m_pItem
] = 
1307         attr 
= new wxTreeItemAttr
; 
1314     attr
->SetTextColour(col
); 
1319 void wxTreeCtrl::SetItemBackgroundColour(const wxTreeItemId
& item
, 
1320                                          const wxColour
& col
) 
1322     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1324     wxTreeItemAttr 
*attr
; 
1325     wxMapTreeAttr::iterator it 
= m_attrs
.find(item
.m_pItem
); 
1326     if ( it 
== m_attrs
.end() ) 
1328         m_hasAnyAttr 
= true; 
1330         m_attrs
[item
.m_pItem
] = 
1331         attr 
= new wxTreeItemAttr
; 
1333     else // already in the hash 
1338     attr
->SetBackgroundColour(col
); 
1343 void wxTreeCtrl::SetItemFont(const wxTreeItemId
& item
, const wxFont
& font
) 
1345     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1347     wxTreeItemAttr 
*attr
; 
1348     wxMapTreeAttr::iterator it 
= m_attrs
.find(item
.m_pItem
); 
1349     if ( it 
== m_attrs
.end() ) 
1351         m_hasAnyAttr 
= true; 
1353         m_attrs
[item
.m_pItem
] = 
1354         attr 
= new wxTreeItemAttr
; 
1356     else // already in the hash 
1361     attr
->SetFont(font
); 
1366 // ---------------------------------------------------------------------------- 
1368 // ---------------------------------------------------------------------------- 
1370 bool wxTreeCtrl::IsVisible(const wxTreeItemId
& item
) const 
1372     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1374     if ( item 
== wxTreeItemId(TVI_ROOT
) ) 
1376         // virtual (hidden) root is never visible 
1380     // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect 
1383     // this ugliness comes directly from MSDN - it *is* the correct way to pass 
1384     // the HTREEITEM with TVM_GETITEMRECT 
1385     *(HTREEITEM 
*)&rect 
= HITEM(item
); 
1387     // true means to get rect for just the text, not the whole line 
1388     if ( !::SendMessage(GetHwnd(), TVM_GETITEMRECT
, true, (LPARAM
)&rect
) ) 
1390         // if TVM_GETITEMRECT returned false, then the item is definitely not 
1391         // visible (because its parent is not expanded) 
1395     // however if it returned true, the item might still be outside the 
1396     // currently visible part of the tree, test for it (notice that partly 
1397     // visible means visible here) 
1398     return rect
.bottom 
> 0 && rect
.top 
< GetClientSize().y
; 
1401 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const 
1403     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1405     wxTreeViewItem 
tvItem(item
, TVIF_CHILDREN
); 
1408     return tvItem
.cChildren 
!= 0; 
1411 bool wxTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const 
1413     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1415     wxTreeViewItem 
tvItem(item
, TVIF_STATE
, TVIS_EXPANDED
); 
1418     return (tvItem
.state 
& TVIS_EXPANDED
) != 0; 
1421 bool wxTreeCtrl::IsSelected(const wxTreeItemId
& item
) const 
1423     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1425     wxTreeViewItem 
tvItem(item
, TVIF_STATE
, TVIS_SELECTED
); 
1428     return (tvItem
.state 
& TVIS_SELECTED
) != 0; 
1431 bool wxTreeCtrl::IsBold(const wxTreeItemId
& item
) const 
1433     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1435     wxTreeViewItem 
tvItem(item
, TVIF_STATE
, TVIS_BOLD
); 
1438     return (tvItem
.state 
& TVIS_BOLD
) != 0; 
1441 // ---------------------------------------------------------------------------- 
1443 // ---------------------------------------------------------------------------- 
1445 wxTreeItemId 
wxTreeCtrl::GetRootItem() const 
1447     // Root may be real (visible) or virtual (hidden). 
1448     if ( GET_VIRTUAL_ROOT() ) 
1451     return wxTreeItemId(TreeView_GetRoot(GetHwnd())); 
1454 wxTreeItemId 
wxTreeCtrl::GetSelection() const 
1456     wxCHECK_MSG( !(m_windowStyle 
& wxTR_MULTIPLE
), wxTreeItemId(), 
1457                  wxT("this only works with single selection controls") ); 
1459     return wxTreeItemId(TreeView_GetSelection(GetHwnd())); 
1462 wxTreeItemId 
wxTreeCtrl::GetItemParent(const wxTreeItemId
& item
) const 
1464     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1468     if ( IS_VIRTUAL_ROOT(item
) ) 
1470         // no parent for the virtual root 
1475         hItem 
= TreeView_GetParent(GetHwnd(), HITEM(item
)); 
1476         if ( !hItem 
&& HasFlag(wxTR_HIDE_ROOT
) ) 
1478             // the top level items should have the virtual root as their parent 
1483     return wxTreeItemId(hItem
); 
1486 wxTreeItemId 
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, 
1487                                        wxTreeItemIdValue
& cookie
) const 
1489     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1491     // remember the last child returned in 'cookie' 
1492     cookie 
= TreeView_GetChild(GetHwnd(), HITEM(item
)); 
1494     return wxTreeItemId(cookie
); 
1497 wxTreeItemId 
wxTreeCtrl::GetNextChild(const wxTreeItemId
& WXUNUSED(item
), 
1498                                       wxTreeItemIdValue
& cookie
) const 
1500     wxTreeItemId 
fromCookie(cookie
); 
1502     HTREEITEM hitem 
= HITEM(fromCookie
); 
1504     hitem 
= TreeView_GetNextSibling(GetHwnd(), hitem
); 
1506     wxTreeItemId 
item(hitem
); 
1508     cookie 
= item
.m_pItem
; 
1513 #if WXWIN_COMPATIBILITY_2_4 
1515 wxTreeItemId 
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
, 
1518     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1520     cookie 
= (long)TreeView_GetChild(GetHwnd(), HITEM(item
)); 
1522     return wxTreeItemId((void *)cookie
); 
1525 wxTreeItemId 
wxTreeCtrl::GetNextChild(const wxTreeItemId
& WXUNUSED(item
), 
1528     wxTreeItemId 
fromCookie((void *)cookie
); 
1530     HTREEITEM hitem 
= HITEM(fromCookie
); 
1532     hitem 
= TreeView_GetNextSibling(GetHwnd(), hitem
); 
1534     wxTreeItemId 
item(hitem
); 
1536     cookie 
= (long)item
.m_pItem
; 
1541 #endif // WXWIN_COMPATIBILITY_2_4 
1543 wxTreeItemId 
wxTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const 
1545     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1547     // can this be done more efficiently? 
1548     wxTreeItemIdValue cookie
; 
1550     wxTreeItemId childLast
, 
1551     child 
= GetFirstChild(item
, cookie
); 
1552     while ( child
.IsOk() ) 
1555         child 
= GetNextChild(item
, cookie
); 
1561 wxTreeItemId 
wxTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const 
1563     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1564     return wxTreeItemId(TreeView_GetNextSibling(GetHwnd(), HITEM(item
))); 
1567 wxTreeItemId 
wxTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const 
1569     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1570     return wxTreeItemId(TreeView_GetPrevSibling(GetHwnd(), HITEM(item
))); 
1573 wxTreeItemId 
wxTreeCtrl::GetFirstVisibleItem() const 
1575     return wxTreeItemId(TreeView_GetFirstVisible(GetHwnd())); 
1578 wxTreeItemId 
wxTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const 
1580     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1581     wxASSERT_MSG( IsVisible(item
), wxT("The item you call GetNextVisible() for must be visible itself!")); 
1583     return wxTreeItemId(TreeView_GetNextVisible(GetHwnd(), HITEM(item
))); 
1586 wxTreeItemId 
wxTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const 
1588     wxCHECK_MSG( item
.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); 
1589     wxASSERT_MSG( IsVisible(item
), wxT("The item you call GetPrevVisible() for must be visible itself!")); 
1591     return wxTreeItemId(TreeView_GetPrevVisible(GetHwnd(), HITEM(item
))); 
1594 // ---------------------------------------------------------------------------- 
1595 // multiple selections emulation 
1596 // ---------------------------------------------------------------------------- 
1598 bool wxTreeCtrl::IsItemChecked(const wxTreeItemId
& item
) const 
1600     wxCHECK_MSG( item
.IsOk(), false, wxT("invalid tree item") ); 
1602     // receive the desired information. 
1603     wxTreeViewItem 
tvItem(item
, TVIF_STATE
, TVIS_STATEIMAGEMASK
); 
1606     // state image indices are 1 based 
1607     return ((tvItem
.state 
>> 12) - 1) == 1; 
1610 void wxTreeCtrl::SetItemCheck(const wxTreeItemId
& item
, bool check
) 
1612     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
1614     // receive the desired information. 
1615     wxTreeViewItem 
tvItem(item
, TVIF_STATE
, TVIS_STATEIMAGEMASK
); 
1619     // state images are one-based 
1620     tvItem
.state 
= (check 
? 2 : 1) << 12; 
1625 size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds
& selections
) const 
1627     TraverseSelections 
selector(this, selections
); 
1629     return selector
.GetCount(); 
1632 // ---------------------------------------------------------------------------- 
1634 // ---------------------------------------------------------------------------- 
1636 wxTreeItemId 
wxTreeCtrl::DoInsertItem(const wxTreeItemId
& parent
, 
1637                                       wxTreeItemId hInsertAfter
, 
1638                                       const wxString
& text
, 
1639                                       int image
, int selectedImage
, 
1640                                       wxTreeItemData 
*data
) 
1642     wxCHECK_MSG( parent
.IsOk() || !TreeView_GetRoot(GetHwnd()), 
1644                  _T("can't have more than one root in the tree") ); 
1646     TV_INSERTSTRUCT tvIns
; 
1647     tvIns
.hParent 
= HITEM(parent
); 
1648     tvIns
.hInsertAfter 
= HITEM(hInsertAfter
); 
1650     // this is how we insert the item as the first child: supply a NULL 
1652     if ( !tvIns
.hInsertAfter 
) 
1654         tvIns
.hInsertAfter 
= TVI_FIRST
; 
1658     if ( !text
.empty() ) 
1661         tvIns
.item
.pszText 
= (wxChar 
*)text
.c_str();  // cast is ok 
1665         tvIns
.item
.pszText 
= NULL
; 
1666         tvIns
.item
.cchTextMax 
= 0; 
1672         tvIns
.item
.iImage 
= image
; 
1674         if ( selectedImage 
== -1 ) 
1676             // take the same image for selected icon if not specified 
1677             selectedImage 
= image
; 
1681     if ( selectedImage 
!= -1 ) 
1683         mask 
|= TVIF_SELECTEDIMAGE
; 
1684         tvIns
.item
.iSelectedImage 
= selectedImage
; 
1690         tvIns
.item
.lParam 
= (LPARAM
)data
; 
1693     tvIns
.item
.mask 
= mask
; 
1695     HTREEITEM id 
= (HTREEITEM
) TreeView_InsertItem(GetHwnd(), &tvIns
); 
1698         wxLogLastError(wxT("TreeView_InsertItem")); 
1703         // associate the application tree item with Win32 tree item handle 
1707     return wxTreeItemId(id
); 
1710 // for compatibility only 
1711 #if WXWIN_COMPATIBILITY_2_4 
1713 wxTreeItemId 
wxTreeCtrl::InsertItem(const wxTreeItemId
& parent
, 
1714                                     const wxString
& text
, 
1715                                     int image
, int selImage
, 
1718     return DoInsertItem(parent
, wxTreeItemId((void *)insertAfter
), text
, 
1719                         image
, selImage
, NULL
); 
1722 wxImageList 
*wxTreeCtrl::GetImageList(int) const 
1724     return GetImageList(); 
1727 void wxTreeCtrl::SetImageList(wxImageList 
*imageList
, int) 
1729     SetImageList(imageList
); 
1732 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const 
1734     return GetItemImage(item
, wxTreeItemIcon_Selected
); 
1737 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
) 
1739     SetItemImage(item
, image
, wxTreeItemIcon_Selected
); 
1742 #endif // WXWIN_COMPATIBILITY_2_4 
1744 wxTreeItemId 
wxTreeCtrl::AddRoot(const wxString
& text
, 
1745                                  int image
, int selectedImage
, 
1746                                  wxTreeItemData 
*data
) 
1749     if ( m_windowStyle 
& wxTR_HIDE_ROOT 
) 
1751         // create a virtual root item, the parent for all the others 
1752         m_pVirtualRoot 
= new wxVirtualNode(data
); 
1757     return DoInsertItem(wxTreeItemId(), wxTreeItemId(), 
1758                         text
, image
, selectedImage
, data
); 
1761 wxTreeItemId 
wxTreeCtrl::PrependItem(const wxTreeItemId
& parent
, 
1762                                      const wxString
& text
, 
1763                                      int image
, int selectedImage
, 
1764                                      wxTreeItemData 
*data
) 
1766     return DoInsertItem(parent
, TVI_FIRST
, 
1767                         text
, image
, selectedImage
, data
); 
1770 wxTreeItemId 
wxTreeCtrl::InsertItem(const wxTreeItemId
& parent
, 
1771                                     const wxTreeItemId
& idPrevious
, 
1772                                     const wxString
& text
, 
1773                                     int image
, int selectedImage
, 
1774                                     wxTreeItemData 
*data
) 
1776     return DoInsertItem(parent
, idPrevious
, text
, image
, selectedImage
, data
); 
1779 wxTreeItemId 
wxTreeCtrl::InsertItem(const wxTreeItemId
& parent
, 
1781                                     const wxString
& text
, 
1782                                     int image
, int selectedImage
, 
1783                                     wxTreeItemData 
*data
) 
1785     // find the item from index 
1786     wxTreeItemIdValue cookie
; 
1787     wxTreeItemId idPrev
, idCur 
= GetFirstChild(parent
, cookie
); 
1788     while ( index 
!= 0 && idCur
.IsOk() ) 
1793         idCur 
= GetNextChild(parent
, cookie
); 
1796     // assert, not check: if the index is invalid, we will append the item 
1798     wxASSERT_MSG( index 
== 0, _T("bad index in wxTreeCtrl::InsertItem") ); 
1800     return DoInsertItem(parent
, idPrev
, text
, image
, selectedImage
, data
); 
1803 wxTreeItemId 
wxTreeCtrl::AppendItem(const wxTreeItemId
& parent
, 
1804                                     const wxString
& text
, 
1805                                     int image
, int selectedImage
, 
1806                                     wxTreeItemData 
*data
) 
1808     return DoInsertItem(parent
, TVI_LAST
, 
1809                         text
, image
, selectedImage
, data
); 
1812 void wxTreeCtrl::Delete(const wxTreeItemId
& item
) 
1814     if ( !TreeView_DeleteItem(GetHwnd(), HITEM(item
)) ) 
1816         wxLogLastError(wxT("TreeView_DeleteItem")); 
1820 // delete all children (but don't delete the item itself) 
1821 void wxTreeCtrl::DeleteChildren(const wxTreeItemId
& item
) 
1823     wxTreeItemIdValue cookie
; 
1825     wxArrayTreeItemIds children
; 
1826     wxTreeItemId child 
= GetFirstChild(item
, cookie
); 
1827     while ( child
.IsOk() ) 
1829         children
.Add(child
); 
1831         child 
= GetNextChild(item
, cookie
); 
1834     size_t nCount 
= children
.Count(); 
1835     for ( size_t n 
= 0; n 
< nCount
; n
++ ) 
1837         if ( !TreeView_DeleteItem(GetHwnd(), HITEM_PTR(children
[n
])) ) 
1839             wxLogLastError(wxT("TreeView_DeleteItem")); 
1844 void wxTreeCtrl::DeleteAllItems() 
1846     // delete the "virtual" root item. 
1847     if ( GET_VIRTUAL_ROOT() ) 
1849         delete GET_VIRTUAL_ROOT(); 
1850         m_pVirtualRoot 
= NULL
; 
1853     // and all the real items 
1855     if ( !TreeView_DeleteAllItems(GetHwnd()) ) 
1857         wxLogLastError(wxT("TreeView_DeleteAllItems")); 
1861 void wxTreeCtrl::DoExpand(const wxTreeItemId
& item
, int flag
) 
1863     wxASSERT_MSG( flag 
== TVE_COLLAPSE 
|| 
1864                   flag 
== (TVE_COLLAPSE 
| TVE_COLLAPSERESET
) || 
1865                   flag 
== TVE_EXPAND   
|| 
1867                   wxT("Unknown flag in wxTreeCtrl::DoExpand") ); 
1869     // A hidden root can be neither expanded nor collapsed. 
1870     wxCHECK_RET( !(m_windowStyle 
& wxTR_HIDE_ROOT
) || (HITEM(item
) != TVI_ROOT
), 
1871                  wxT("Can't expand/collapse hidden root node!") ) 
1873     // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must 
1874     // emulate them. This behaviour has changed slightly with comctl32.dll 
1875     // v 4.70 - now it does send them but only the first time. To maintain 
1876     // compatible behaviour and also in order to not have surprises with the 
1877     // future versions, don't rely on this and still do everything ourselves. 
1878     // To avoid that the messages be sent twice when the item is expanded for 
1879     // the first time we must clear TVIS_EXPANDEDONCE style manually. 
1881     wxTreeViewItem 
tvItem(item
, TVIF_STATE
, TVIS_EXPANDEDONCE
); 
1885     if ( TreeView_Expand(GetHwnd(), HITEM(item
), flag
) != 0 ) 
1887         wxTreeEvent 
event(wxEVT_NULL
, m_windowId
); 
1888         event
.m_item 
= item
; 
1889         event
.SetEventObject(this); 
1891         // note that the {EXPAND|COLLAPS}ING event is sent by TreeView_Expand() 
1893         event
.SetEventType(gs_expandEvents
[IsExpanded(item
) ? IDX_EXPAND
 
1897         (void)GetEventHandler()->ProcessEvent(event
); 
1899     //else: change didn't took place, so do nothing at all 
1902 void wxTreeCtrl::Expand(const wxTreeItemId
& item
) 
1904     DoExpand(item
, TVE_EXPAND
); 
1907 void wxTreeCtrl::Collapse(const wxTreeItemId
& item
) 
1909     DoExpand(item
, TVE_COLLAPSE
); 
1912 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
) 
1914     DoExpand(item
, TVE_COLLAPSE 
| TVE_COLLAPSERESET
); 
1917 void wxTreeCtrl::Toggle(const wxTreeItemId
& item
) 
1919     DoExpand(item
, TVE_TOGGLE
); 
1922 #if WXWIN_COMPATIBILITY_2_4 
1924 void wxTreeCtrl::ExpandItem(const wxTreeItemId
& item
, int action
) 
1926     DoExpand(item
, action
); 
1931 void wxTreeCtrl::Unselect() 
1933     wxASSERT_MSG( !(m_windowStyle 
& wxTR_MULTIPLE
), 
1934                   wxT("doesn't make sense, may be you want UnselectAll()?") ); 
1936     // just remove the selection 
1937     SelectItem(wxTreeItemId()); 
1940 void wxTreeCtrl::UnselectAll() 
1942     if ( m_windowStyle 
& wxTR_MULTIPLE 
) 
1944         wxArrayTreeItemIds selections
; 
1945         size_t count 
= GetSelections(selections
); 
1946         for ( size_t n 
= 0; n 
< count
; n
++ ) 
1948 #if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
1949             SetItemCheck(HITEM_PTR(selections
[n
]), false); 
1950 #else // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
1951             ::UnselectItem(GetHwnd(), HITEM_PTR(selections
[n
])); 
1952 #endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE/!wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
1955         m_htSelStart
.Unset(); 
1959         // just remove the selection 
1964 void wxTreeCtrl::SelectItem(const wxTreeItemId
& item
, bool select
) 
1966     if ( m_windowStyle 
& wxTR_MULTIPLE 
) 
1968 #if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
1969         // selecting the item means checking it 
1970         SetItemCheck(item
, select
); 
1971 #else // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
1972         ::SelectItem(GetHwnd(), HITEM(item
), select
); 
1973 #endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE/!wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
1977         wxASSERT_MSG( select
, 
1978                       _T("SelectItem(false) works only for multiselect") ); 
1980         // inspite of the docs (MSDN Jan 99 edition), we don't seem to receive 
1981         // the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so 
1982         // send them ourselves 
1984         wxTreeEvent 
event(wxEVT_NULL
, m_windowId
); 
1985         event
.m_item 
= item
; 
1986         event
.SetEventObject(this); 
1988         event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGING
); 
1989         if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() ) 
1991             if ( !TreeView_SelectItem(GetHwnd(), HITEM(item
)) ) 
1993                 wxLogLastError(wxT("TreeView_SelectItem")); 
1997                 event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
); 
1998                 (void)GetEventHandler()->ProcessEvent(event
); 
2001         //else: program vetoed the change 
2005 void wxTreeCtrl::UnselectItem(const wxTreeItemId
& item
) 
2007     SelectItem(item
, false); 
2010 void wxTreeCtrl::ToggleItemSelection(const wxTreeItemId
& item
) 
2012     SelectItem(item
, !IsSelected(item
)); 
2015 void wxTreeCtrl::EnsureVisible(const wxTreeItemId
& item
) 
2018     TreeView_EnsureVisible(GetHwnd(), HITEM(item
)); 
2021 void wxTreeCtrl::ScrollTo(const wxTreeItemId
& item
) 
2023     if ( !TreeView_SelectSetFirstVisible(GetHwnd(), HITEM(item
)) ) 
2025         wxLogLastError(wxT("TreeView_SelectSetFirstVisible")); 
2029 wxTextCtrl 
*wxTreeCtrl::GetEditControl() const 
2034 void wxTreeCtrl::DeleteTextCtrl() 
2038         // the HWND corresponding to this control is deleted by the tree 
2039         // control itself and we don't know when exactly this happens, so check 
2040         // if the window still exists before calling UnsubclassWin() 
2041         if ( !::IsWindow(GetHwndOf(m_textCtrl
)) ) 
2043             m_textCtrl
->SetHWND(0); 
2046         m_textCtrl
->UnsubclassWin(); 
2047         m_textCtrl
->SetHWND(0); 
2055 wxTextCtrl
* wxTreeCtrl::EditLabel(const wxTreeItemId
& item
, 
2056                                   wxClassInfo
* textControlClass
) 
2058     wxASSERT( textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
)) ); 
2063     m_textCtrl 
= (wxTextCtrl 
*)textControlClass
->CreateObject(); 
2064     HWND hWnd 
= (HWND
) TreeView_EditLabel(GetHwnd(), HITEM(item
)); 
2066     // this is not an error - the TVN_BEGINLABELEDIT handler might have 
2075     // textctrl is subclassed in MSWOnNotify 
2079 // End label editing, optionally cancelling the edit 
2080 void wxTreeCtrl::DoEndEditLabel(bool discardChanges
) 
2082     TreeView_EndEditLabelNow(GetHwnd(), discardChanges
); 
2087 wxTreeItemId 
wxTreeCtrl::HitTest(const wxPoint
& point
, int& flags
) 
2089     TV_HITTESTINFO hitTestInfo
; 
2090     hitTestInfo
.pt
.x 
= (int)point
.x
; 
2091     hitTestInfo
.pt
.y 
= (int)point
.y
; 
2093     TreeView_HitTest(GetHwnd(), &hitTestInfo
); 
2098     #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \ 
2099                                     flags |= wxTREE_HITTEST_##flag 
2101     TRANSLATE_FLAG(ABOVE
); 
2102     TRANSLATE_FLAG(BELOW
); 
2103     TRANSLATE_FLAG(NOWHERE
); 
2104     TRANSLATE_FLAG(ONITEMBUTTON
); 
2105     TRANSLATE_FLAG(ONITEMICON
); 
2106     TRANSLATE_FLAG(ONITEMINDENT
); 
2107     TRANSLATE_FLAG(ONITEMLABEL
); 
2108     TRANSLATE_FLAG(ONITEMRIGHT
); 
2109     TRANSLATE_FLAG(ONITEMSTATEICON
); 
2110     TRANSLATE_FLAG(TOLEFT
); 
2111     TRANSLATE_FLAG(TORIGHT
); 
2113     #undef TRANSLATE_FLAG 
2115     return wxTreeItemId(hitTestInfo
.hItem
); 
2118 bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
, 
2120                                  bool textOnly
) const 
2124     // Virtual root items have no bounding rectangle 
2125     if ( IS_VIRTUAL_ROOT(item
) ) 
2130     if ( TreeView_GetItemRect(GetHwnd(), HITEM(item
), 
2133         rect 
= wxRect(wxPoint(rc
.left
, rc
.top
), wxPoint(rc
.right
, rc
.bottom
)); 
2139         // couldn't retrieve rect: for example, item isn't visible 
2144 // ---------------------------------------------------------------------------- 
2146 // ---------------------------------------------------------------------------- 
2148 // this is just a tiny namespace which is friend to wxTreeCtrl and so can use 
2149 // functions such as IsDataIndirect() 
2150 class wxTreeSortHelper
 
2153     static int CALLBACK 
Compare(LPARAM data1
, LPARAM data2
, LPARAM tree
); 
2156     static wxTreeItemId 
GetIdFromData(wxTreeCtrl 
*tree
, LPARAM item
) 
2158         wxTreeItemData 
*data 
= (wxTreeItemData 
*)item
; 
2159         if ( tree
->IsDataIndirect(data
) ) 
2161             data 
= ((wxTreeItemIndirectData 
*)data
)->GetData(); 
2164         return data
->GetId(); 
2168 int CALLBACK 
wxTreeSortHelper::Compare(LPARAM pItem1
, 
2172     wxCHECK_MSG( pItem1 
&& pItem2
, 0, 
2173                  wxT("sorting tree without data doesn't make sense") ); 
2175     wxTreeCtrl 
*tree 
= (wxTreeCtrl 
*)htree
; 
2177     return tree
->OnCompareItems(GetIdFromData(tree
, pItem1
), 
2178                                 GetIdFromData(tree
, pItem2
)); 
2181 int wxTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
, 
2182                                const wxTreeItemId
& item2
) 
2184     return wxStrcmp(GetItemText(item1
), GetItemText(item2
)); 
2187 void wxTreeCtrl::SortChildren(const wxTreeItemId
& item
) 
2189     wxCHECK_RET( item
.IsOk(), wxT("invalid tree item") ); 
2191     // rely on the fact that TreeView_SortChildren does the same thing as our 
2192     // default behaviour, i.e. sorts items alphabetically and so call it 
2193     // directly if we're not in derived class (much more efficient!) 
2194     if ( GetClassInfo() == CLASSINFO(wxTreeCtrl
) ) 
2196         TreeView_SortChildren(GetHwnd(), HITEM(item
), 0); 
2201         tvSort
.hParent 
= HITEM(item
); 
2202         tvSort
.lpfnCompare 
= wxTreeSortHelper::Compare
; 
2203         tvSort
.lParam 
= (LPARAM
)this; 
2204         TreeView_SortChildrenCB(GetHwnd(), &tvSort
, 0 /* reserved */); 
2208 // ---------------------------------------------------------------------------- 
2210 // ---------------------------------------------------------------------------- 
2212 bool wxTreeCtrl::MSWCommand(WXUINT cmd
, WXWORD id
) 
2214     if ( cmd 
== EN_UPDATE 
) 
2216         wxCommandEvent 
event(wxEVT_COMMAND_TEXT_UPDATED
, id
); 
2217         event
.SetEventObject( this ); 
2218         ProcessCommand(event
); 
2220     else if ( cmd 
== EN_KILLFOCUS 
) 
2222         wxCommandEvent 
event(wxEVT_KILL_FOCUS
, id
); 
2223         event
.SetEventObject( this ); 
2224         ProcessCommand(event
); 
2232     // command processed 
2236 // we hook into WndProc to process WM_MOUSEMOVE/WM_BUTTONUP messages - as we 
2237 // only do it during dragging, minimize wxWin overhead (this is important for 
2238 // WM_MOUSEMOVE as they're a lot of them) by catching Windows messages directly 
2239 // instead of passing by wxWin events 
2240 WXLRESULT 
wxTreeCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
2242     bool processed 
= false; 
2244     bool isMultiple 
= HasFlag(wxTR_MULTIPLE
); 
2246     if ( nMsg 
== WM_CONTEXTMENU 
) 
2248         wxTreeEvent 
event( wxEVT_COMMAND_TREE_ITEM_MENU
, GetId() ); 
2250         // can't use GetSelection() here as it would assert in multiselect mode 
2251         event
.m_item 
= wxTreeItemId(TreeView_GetSelection(GetHwnd())); 
2252         event
.SetEventObject( this ); 
2254         if ( GetEventHandler()->ProcessEvent(event
) ) 
2256         //else: continue with generating wxEVT_CONTEXT_MENU in base class code 
2258     else if ( (nMsg 
>= WM_MOUSEFIRST
) && (nMsg 
<= WM_MOUSELAST
) ) 
2260         // we only process mouse messages here and these parameters have the 
2261         // same meaning for all of them 
2262         int x 
= GET_X_LPARAM(lParam
), 
2263             y 
= GET_Y_LPARAM(lParam
); 
2264         HTREEITEM htItem 
= GetItemFromPoint(GetHwnd(), x
, y
); 
2268             case WM_RBUTTONDOWN
: 
2269                 // if the item we are about to right click on is not already 
2270                 // selected or if we click outside of any item, remove the 
2271                 // entire previous selection 
2272                 if ( !htItem 
|| !::IsItemSelected(GetHwnd(), htItem
) ) 
2277                 // select item and set the focus to the 
2278                 // newly selected item 
2279                 ::SelectItem(GetHwnd(), htItem
); 
2280                 ::SetFocus(GetHwnd(), htItem
); 
2283 #if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
2284             case WM_LBUTTONDOWN
: 
2285                 if ( htItem 
&& isMultiple 
) 
2287                     if ( wParam 
& MK_CONTROL 
) 
2291                         // toggle selected state 
2292                         ::ToggleItemSelection(GetHwnd(), htItem
); 
2294                         ::SetFocus(GetHwnd(), htItem
); 
2296                         // reset on any click without Shift 
2297                         m_htSelStart
.Unset(); 
2301                     else if ( wParam 
& MK_SHIFT 
) 
2303                         // this selects all items between the starting one and 
2306                         if ( !m_htSelStart 
) 
2308                             // take the focused item 
2309                             m_htSelStart 
= TreeView_GetSelection(GetHwnd()); 
2312                         SelectRange(GetHwnd(), HITEM(m_htSelStart
), htItem
, 
2313                                     !(wParam 
& MK_CONTROL
)); 
2315                         ::SetFocus(GetHwnd(), htItem
); 
2319                     else // normal click 
2321                         // avoid doing anything if we click on the only 
2322                         // currently selected item 
2324                         wxArrayTreeItemIds selections
; 
2325                         size_t count 
= GetSelections(selections
); 
2328                              HITEM_PTR(selections
[0]) != htItem 
) 
2330                             // clear the previously selected items, if the 
2331                             // user clicked outside of the present selection. 
2332                             // otherwise, perform the deselection on mouse-up. 
2333                             // this allows multiple drag and drop to work. 
2335                             if (IsItemSelected(GetHwnd(), htItem
)) 
2337                                 ::SetFocus(GetHwnd(), htItem
); 
2343                                 // prevent the click from starting in-place editing 
2344                                 // which should only happen if we click on the 
2345                                 // already selected item (and nothing else is 
2348                                 TreeView_SelectItem(GetHwnd(), 0); 
2349                                 ::SelectItem(GetHwnd(), htItem
); 
2353                         // reset on any click without Shift 
2354                         m_htSelStart
.Unset(); 
2358 #endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
2363                     m_dragImage
->Move(wxPoint(x
, y
)); 
2366                         // highlight the item as target (hiding drag image is 
2367                         // necessary - otherwise the display will be corrupted) 
2368                         m_dragImage
->Hide(); 
2369                         TreeView_SelectDropTarget(GetHwnd(), htItem
); 
2370                         m_dragImage
->Show(); 
2377                 // facilitates multiple drag-and-drop 
2378                 if (htItem 
&& isMultiple
) 
2380                     wxArrayTreeItemIds selections
; 
2381                     size_t count 
= GetSelections(selections
); 
2384                         !(wParam 
& MK_CONTROL
) && 
2385                         !(wParam 
& MK_SHIFT
)) 
2388                         TreeView_SelectItem(GetHwnd(), htItem
); 
2397                     m_dragImage
->EndDrag(); 
2401                     // generate the drag end event 
2402                     wxTreeEvent 
event(wxEVT_COMMAND_TREE_END_DRAG
, m_windowId
); 
2404                     event
.m_item 
= htItem
; 
2405                     event
.m_pointDrag 
= wxPoint(x
, y
); 
2406                     event
.SetEventObject(this); 
2408                     (void)GetEventHandler()->ProcessEvent(event
); 
2410                     // if we don't do it, the tree seems to think that 2 items 
2411                     // are selected simultaneously which is quite weird 
2412                     TreeView_SelectDropTarget(GetHwnd(), 0); 
2417 #if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
2418     else if ( (nMsg 
== WM_SETFOCUS 
|| nMsg 
== WM_KILLFOCUS
) && isMultiple 
) 
2420         // the tree control greys out the selected item when it loses focus and 
2421         // paints it as selected again when it regains it, but it won't do it 
2422         // for the other items itself - help it 
2423         wxArrayTreeItemIds selections
; 
2424         size_t count 
= GetSelections(selections
); 
2426         for ( size_t n 
= 0; n 
< count
; n
++ ) 
2428             // TreeView_GetItemRect() will return false if item is not visible, 
2429             // which may happen perfectly well 
2430             if ( TreeView_GetItemRect(GetHwnd(), HITEM_PTR(selections
[n
]), 
2433                 ::InvalidateRect(GetHwnd(), &rect
, FALSE
); 
2437     else if ( nMsg 
== WM_KEYDOWN 
&& isMultiple 
) 
2439         bool bCtrl 
= wxIsCtrlDown(), 
2440              bShift 
= wxIsShiftDown(); 
2442         HTREEITEM htSel 
= (HTREEITEM
)TreeView_GetSelection(GetHwnd()); 
2448                     ::ToggleItemSelection(GetHwnd(), htSel
); 
2454                     ::SelectItem(GetHwnd(), htSel
); 
2462                 if ( !bCtrl 
&& !bShift 
) 
2464                     // no modifiers, just clear selection and then let the default 
2465                     // processing to take place 
2470                     (void)wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
2472                     HTREEITEM htNext 
= (HTREEITEM
) 
2473                         TreeView_GetNextItem
 
2477                             wParam 
== VK_UP 
? TVGN_PREVIOUSVISIBLE
 
2483                         // at the top/bottom 
2489                         if ( !m_htSelStart 
) 
2490                             m_htSelStart 
= htSel
; 
2492                         SelectRange(GetHwnd(), HITEM(m_htSelStart
), htNext
); 
2496                         // without changing selection 
2497                         ::SetFocus(GetHwnd(), htNext
); 
2508                 // TODO: handle Shift/Ctrl with these keys 
2509                 if ( !bCtrl 
&& !bShift 
) 
2513                     m_htSelStart
.Unset(); 
2517 #endif // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 
2518     else if ( nMsg 
== WM_COMMAND 
) 
2520         // if we receive a EN_KILLFOCUS command from the in-place edit control 
2521         // used for label editing, make sure to end editing 
2524         UnpackCommand(wParam
, lParam
, &id
, &hwnd
, &cmd
); 
2526         if ( cmd 
== EN_KILLFOCUS 
) 
2528             if ( m_textCtrl 
&& m_textCtrl
->GetHandle() == hwnd 
) 
2538         rc 
= wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
2544 wxTreeCtrl::MSWDefWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
2546     // default WM_RBUTTONDOWN handler enters modal loop inside DefWindowProc() 
2547     // waiting for WM_RBUTTONUP and then sends the resulting WM_CONTEXTMENU to 
2548     // the parent window, not us, which completely breaks everything so simply 
2549     // don't let it see this message at all 
2550     if ( nMsg 
== WM_RBUTTONDOWN 
) 
2553     // but because of the above we don't get NM_RCLICK which is normally 
2554     // generated by tree window proc when the modal loop mentioned above ends 
2555     // because the mouse is released -- synthesize it ourselves instead 
2556     if ( nMsg 
== WM_RBUTTONUP 
) 
2559         hdr
.hwndFrom 
= GetHwnd(); 
2560         hdr
.idFrom 
= GetId(); 
2561         hdr
.code 
= NM_RCLICK
; 
2564         MSWOnNotify(GetId(), (LPARAM
)&hdr
, &rc
); 
2566         // continue as usual 
2569     if ( nMsg 
== WM_CHAR 
) 
2571         // also don't let the control process Space and Return keys because it 
2572         // doesn't do anything useful with them anyhow but always beeps 
2573         // annoyingly when it receives them and there is no way to turn it off 
2574         // simply if you just process TREEITEM_ACTIVATED event to which Space 
2575         // and Enter presses are mapped in your code 
2576         if ( wParam 
== VK_SPACE 
|| wParam 
== VK_RETURN 
) 
2580     return wxControl::MSWDefWindowProc(nMsg
, wParam
, lParam
); 
2583 // process WM_NOTIFY Windows message 
2584 bool wxTreeCtrl::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM 
*result
) 
2586     wxTreeEvent 
event(wxEVT_NULL
, m_windowId
); 
2587     wxEventType eventType 
= wxEVT_NULL
; 
2588     NMHDR 
*hdr 
= (NMHDR 
*)lParam
; 
2590     switch ( hdr
->code 
) 
2593             eventType 
= wxEVT_COMMAND_TREE_BEGIN_DRAG
; 
2596         case TVN_BEGINRDRAG
: 
2598                 if ( eventType 
== wxEVT_NULL 
) 
2599                     eventType 
= wxEVT_COMMAND_TREE_BEGIN_RDRAG
; 
2600                 //else: left drag, already set above 
2602                 NM_TREEVIEW 
*tv 
= (NM_TREEVIEW 
*)lParam
; 
2604                 event
.m_item 
= tv
->itemNew
.hItem
; 
2605                 event
.m_pointDrag 
= wxPoint(tv
->ptDrag
.x
, tv
->ptDrag
.y
); 
2607                 // don't allow dragging by default: the user code must 
2608                 // explicitly say that it wants to allow it to avoid breaking 
2614         case TVN_BEGINLABELEDIT
: 
2616                 eventType 
= wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
; 
2617                 TV_DISPINFO 
*info 
= (TV_DISPINFO 
*)lParam
; 
2619                 // although the user event handler may still veto it, it is 
2620                 // important to set it now so that calls to SetItemText() from 
2621                 // the event handler would change the text controls contents 
2623                 event
.m_item 
= info
->item
.hItem
; 
2624                 event
.m_label 
= info
->item
.pszText
; 
2625                 event
.m_editCancelled 
= false; 
2629         case TVN_DELETEITEM
: 
2631                 eventType 
= wxEVT_COMMAND_TREE_DELETE_ITEM
; 
2632                 NM_TREEVIEW 
*tv 
= (NM_TREEVIEW 
*)lParam
; 
2634                 event
.m_item 
= tv
->itemOld
.hItem
; 
2638                     wxMapTreeAttr::iterator it 
= m_attrs
.find(tv
->itemOld
.hItem
); 
2639                     if ( it 
!= m_attrs
.end() ) 
2648         case TVN_ENDLABELEDIT
: 
2650                 eventType 
= wxEVT_COMMAND_TREE_END_LABEL_EDIT
; 
2651                 TV_DISPINFO 
*info 
= (TV_DISPINFO 
*)lParam
; 
2653                 event
.m_item 
= info
->item
.hItem
; 
2654                 event
.m_label 
= info
->item
.pszText
; 
2655                 event
.m_editCancelled 
= info
->item
.pszText 
== NULL
; 
2660         // These *must* not be removed or TVN_GETINFOTIP will 
2661         // not be processed each time the mouse is moved 
2662         // and the tooltip will only ever update once. 
2671         case TVN_GETINFOTIP
: 
2673                 eventType 
= wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP
; 
2674                 NMTVGETINFOTIP 
*info 
= (NMTVGETINFOTIP
*)lParam
; 
2676                 // Which item are we trying to get a tooltip for? 
2677                 event
.m_item 
= info
->hItem
; 
2683         case TVN_GETDISPINFO
: 
2684             eventType 
= wxEVT_COMMAND_TREE_GET_INFO
; 
2687         case TVN_SETDISPINFO
: 
2689                 if ( eventType 
== wxEVT_NULL 
) 
2690                     eventType 
= wxEVT_COMMAND_TREE_SET_INFO
; 
2691                 //else: get, already set above 
2693                 TV_DISPINFO 
*info 
= (TV_DISPINFO 
*)lParam
; 
2695                 event
.m_item 
= info
->item
.hItem
; 
2699         case TVN_ITEMEXPANDING
: 
2700         case TVN_ITEMEXPANDED
: 
2702                 NM_TREEVIEW
* tv 
= (NM_TREEVIEW
*)lParam
; 
2705                 switch ( tv
->action 
) 
2708                         wxLogDebug(wxT("unexpected code %d in TVN_ITEMEXPAND message"), tv
->action
); 
2716                         what 
= IDX_COLLAPSE
; 
2720                 int how 
= hdr
->code 
== TVN_ITEMEXPANDING 
? IDX_DOING
 
2723                 eventType 
= gs_expandEvents
[what
][how
]; 
2725                 event
.m_item 
= tv
->itemNew
.hItem
; 
2731                 eventType 
= wxEVT_COMMAND_TREE_KEY_DOWN
; 
2732                 TV_KEYDOWN 
*info 
= (TV_KEYDOWN 
*)lParam
; 
2734                 // fabricate the lParam and wParam parameters sufficiently 
2735                 // similar to the ones from a "real" WM_KEYDOWN so that 
2736                 // CreateKeyEvent() works correctly 
2738                      (::GetKeyState(VK_MENU
) < 0 ? KF_ALTDOWN 
: 0) << 16; 
2740                 WXWPARAM wParam 
= info
->wVKey
; 
2742                 int keyCode 
= wxCharCodeMSWToWX(info
->wVKey
); 
2745                     // wxCharCodeMSWToWX() returns 0 to indicate that this is a 
2750                 event
.m_evtKey 
= CreateKeyEvent(wxEVT_KEY_DOWN
, 
2755                 // a separate event for Space/Return 
2756                 if ( !wxIsCtrlDown() && !wxIsShiftDown() && 
2757                      ((info
->wVKey 
== VK_SPACE
) || (info
->wVKey 
== VK_RETURN
)) ) 
2759                     wxTreeEvent 
event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED
, 
2761                     event2
.SetEventObject(this); 
2762                     if ( !(GetWindowStyle() & wxTR_MULTIPLE
) ) 
2764                         event2
.m_item 
= GetSelection(); 
2766                     //else: don't know how to get it 
2768                     (void)GetEventHandler()->ProcessEvent(event2
); 
2773         // NB: MSLU is broken and sends TVN_SELCHANGEDA instead of 
2774         //     TVN_SELCHANGEDW in Unicode mode under Win98. Therefore 
2775         //     we have to handle both messages: 
2776         case TVN_SELCHANGEDA
: 
2777         case TVN_SELCHANGEDW
: 
2778             eventType 
= wxEVT_COMMAND_TREE_SEL_CHANGED
; 
2781         case TVN_SELCHANGINGA
: 
2782         case TVN_SELCHANGINGW
: 
2784                 if ( eventType 
== wxEVT_NULL 
) 
2785                     eventType 
= wxEVT_COMMAND_TREE_SEL_CHANGING
; 
2786                 //else: already set above 
2788                 if (hdr
->code 
== TVN_SELCHANGINGW 
|| 
2789                     hdr
->code 
== TVN_SELCHANGEDW
) 
2791                     NM_TREEVIEWW
* tv 
= (NM_TREEVIEWW 
*)lParam
; 
2792                     event
.m_item 
= tv
->itemNew
.hItem
; 
2793                     event
.m_itemOld 
= tv
->itemOld
.hItem
; 
2797                     NM_TREEVIEWA
* tv 
= (NM_TREEVIEWA 
*)lParam
; 
2798                     event
.m_item 
= tv
->itemNew
.hItem
; 
2799                     event
.m_itemOld 
= tv
->itemOld
.hItem
; 
2804             // instead of explicitly checking for _WIN32_IE, check if the 
2805             // required symbols are available in the headers 
2806 #if defined(CDDS_PREPAINT) && !wxUSE_COMCTL32_SAFELY 
2809                 LPNMTVCUSTOMDRAW lptvcd 
= (LPNMTVCUSTOMDRAW
)lParam
; 
2810                 NMCUSTOMDRAW
& nmcd 
= lptvcd
->nmcd
; 
2811                 switch ( nmcd
.dwDrawStage 
) 
2814                         // if we've got any items with non standard attributes, 
2815                         // notify us before painting each item 
2816                         *result 
= m_hasAnyAttr 
? CDRF_NOTIFYITEMDRAW
 
2820                     case CDDS_ITEMPREPAINT
: 
2822                             wxMapTreeAttr::iterator
 
2823                                 it 
= m_attrs
.find((void *)nmcd
.dwItemSpec
); 
2825                             if ( it 
== m_attrs
.end() ) 
2827                                 // nothing to do for this item 
2828                                 *result 
= CDRF_DODEFAULT
; 
2832                             wxTreeItemAttr 
* const attr 
= it
->second
; 
2834                             // selection colours should override ours, 
2835                             // otherwise it is too confusing ot the user 
2836                             if ( !(nmcd
.uItemState 
& CDIS_SELECTED
) ) 
2839                                 if ( attr
->HasBackgroundColour() ) 
2841                                     colBack 
= attr
->GetBackgroundColour(); 
2842                                     lptvcd
->clrTextBk 
= wxColourToRGB(colBack
); 
2846                             // but we still want to keep the special foreground 
2847                             // colour when we don't have focus (we can't keep 
2848                             // it when we do, it would usually be unreadable on 
2849                             // the almost inverted bg colour...) 
2850                             if ( !(nmcd
.uItemState 
& CDIS_SELECTED
) || 
2851                                     FindFocus() != this ) 
2854                                 if ( attr
->HasTextColour() ) 
2856                                     colText 
= attr
->GetTextColour(); 
2857                                     lptvcd
->clrText 
= wxColourToRGB(colText
); 
2861                             if ( attr
->HasFont() ) 
2863                                 HFONT hFont 
= GetHfontOf(attr
->GetFont()); 
2865                                 ::SelectObject(nmcd
.hdc
, hFont
); 
2867                                 *result 
= CDRF_NEWFONT
; 
2869                             else // no specific font 
2871                                 *result 
= CDRF_DODEFAULT
; 
2877                         *result 
= CDRF_DODEFAULT
; 
2881             // we always process it 
2883 #endif // have owner drawn support in headers 
2887                 DWORD pos 
= GetMessagePos(); 
2889                 point
.x 
= LOWORD(pos
); 
2890                 point
.y 
= HIWORD(pos
); 
2891                 ::MapWindowPoints(HWND_DESKTOP
, GetHwnd(), &point
, 1); 
2893                 wxTreeItemId item 
= HitTest(wxPoint(point
.x
, point
.y
), flags
); 
2894                 if (flags 
& wxTREE_HITTEST_ONITEMSTATEICON
) 
2896                     event
.m_item 
= item
; 
2897                     eventType 
= wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK
; 
2905                 TV_HITTESTINFO tvhti
; 
2906                 ::GetCursorPos(&tvhti
.pt
); 
2907                 ::ScreenToClient(GetHwnd(), &tvhti
.pt
); 
2908                 if ( TreeView_HitTest(GetHwnd(), &tvhti
) ) 
2910                     if ( tvhti
.flags 
& TVHT_ONITEM 
) 
2912                         event
.m_item 
= tvhti
.hItem
; 
2913                         eventType 
= (int)hdr
->code 
== NM_DBLCLK
 
2914                                     ? wxEVT_COMMAND_TREE_ITEM_ACTIVATED
 
2915                                     : wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
; 
2917                         event
.m_pointDrag
.x 
= tvhti
.pt
.x
; 
2918                         event
.m_pointDrag
.y 
= tvhti
.pt
.y
; 
2927             return wxControl::MSWOnNotify(idCtrl
, lParam
, result
); 
2930     event
.SetEventObject(this); 
2931     event
.SetEventType(eventType
); 
2933     bool processed 
= GetEventHandler()->ProcessEvent(event
); 
2936     switch ( hdr
->code 
) 
2939             // we translate NM_DBLCLK into ACTIVATED event, so don't interpret 
2940             // the return code of this event handler as the return value for 
2941             // NM_DBLCLK - otherwise, double clicking the item to toggle its 
2942             // expanded status would never work 
2947         case TVN_BEGINRDRAG
: 
2948             if ( event
.IsAllowed() ) 
2950                 // normally this is impossible because the m_dragImage is 
2951                 // deleted once the drag operation is over 
2952                 wxASSERT_MSG( !m_dragImage
, _T("starting to drag once again?") ); 
2954                 m_dragImage 
= new wxDragImage(*this, event
.m_item
); 
2955                 m_dragImage
->BeginDrag(wxPoint(0,0), this); 
2956                 m_dragImage
->Show(); 
2960         case TVN_DELETEITEM
: 
2962                 // NB: we might process this message using wxWidgets event 
2963                 //     tables, but due to overhead of wxWin event system we 
2964                 //     prefer to do it here ourself (otherwise deleting a tree 
2965                 //     with many items is just too slow) 
2966                 NM_TREEVIEW
* tv 
= (NM_TREEVIEW 
*)lParam
; 
2968                 wxTreeItemId item 
= event
.m_item
; 
2969                 if ( HasIndirectData(item
) ) 
2971                     wxTreeItemIndirectData 
*data 
= (wxTreeItemIndirectData 
*) 
2973                     delete data
; // can't be NULL here 
2977                     wxTreeItemData 
*data 
= (wxTreeItemData 
*)tv
->itemOld
.lParam
; 
2978                     delete data
; // may be NULL, ok 
2981                 processed 
= true; // Make sure we don't get called twice 
2985         case TVN_BEGINLABELEDIT
: 
2986             // return true to cancel label editing 
2987             *result 
= !event
.IsAllowed(); 
2989             // set ES_WANTRETURN ( like we do in BeginLabelEdit ) 
2990             if ( event
.IsAllowed() ) 
2992                 HWND hText 
= TreeView_GetEditControl(GetHwnd()); 
2995                     // MBN: if m_textCtrl already has an HWND, it is a stale 
2996                     // pointer from a previous edit (because the user 
2997                     // didn't modify the label before dismissing the control, 
2998                     // and TVN_ENDLABELEDIT was not sent), so delete it 
2999                     if(m_textCtrl 
&& m_textCtrl
->GetHWND() != 0) 
3002                         m_textCtrl 
= new wxTextCtrl(); 
3003                     m_textCtrl
->SetParent(this); 
3004                     m_textCtrl
->SetHWND((WXHWND
)hText
); 
3005                     m_textCtrl
->SubclassWin((WXHWND
)hText
); 
3007                     // set wxTE_PROCESS_ENTER style for the text control to 
3008                     // force it to process the Enter presses itself, otherwise 
3009                     // they could be stolen from it by the dialog 
3011                     m_textCtrl
->SetWindowStyle(m_textCtrl
->GetWindowStyle() 
3012                                                | wxTE_PROCESS_ENTER
); 
3015             else // we had set m_idEdited before 
3021         case TVN_ENDLABELEDIT
: 
3022             // return true to set the label to the new string: note that we 
3023             // also must pretend that we did process the message or it is going 
3024             // to be passed to DefWindowProc() which will happily return false 
3025             // cancelling the label change 
3026             *result 
= event
.IsAllowed(); 
3029             // ensure that we don't have the text ctrl which is going to be 
3035          case TVN_GETINFOTIP
: 
3037                 // If the user permitted a tooltip change, change it 
3038                 if (event
.IsAllowed()) 
3040                     SetToolTip(event
.m_label
); 
3046         case TVN_SELCHANGING
: 
3047         case TVN_ITEMEXPANDING
: 
3048             // return true to prevent the action from happening 
3049             *result 
= !event
.IsAllowed(); 
3052         case TVN_ITEMEXPANDED
: 
3053             // the item is not refreshed properly after expansion when it has 
3054             // an image depending on the expanded/collapsed state - bug in 
3055             // comctl32.dll or our code? 
3057                 NM_TREEVIEW
* tv 
= (NM_TREEVIEW 
*)lParam
; 
3058                 wxTreeItemId 
id(tv
->itemNew
.hItem
); 
3060                 int image 
= GetItemImage(id
, wxTreeItemIcon_Expanded
); 
3068         case TVN_GETDISPINFO
: 
3069             // NB: so far the user can't set the image himself anyhow, so do it 
3070             //     anyway - but this may change later 
3071             //if ( /* !processed && */ 1 ) 
3073                 wxTreeItemId item 
= event
.m_item
; 
3074                 TV_DISPINFO 
*info 
= (TV_DISPINFO 
*)lParam
; 
3075                 if ( info
->item
.mask 
& TVIF_IMAGE 
) 
3078                         DoGetItemImageFromData
 
3081                          IsExpanded(item
) ? wxTreeItemIcon_Expanded
 
3082                                           : wxTreeItemIcon_Normal
 
3085                 if ( info
->item
.mask 
& TVIF_SELECTEDIMAGE 
) 
3087                     info
->item
.iSelectedImage 
= 
3088                         DoGetItemImageFromData
 
3091                          IsExpanded(item
) ? wxTreeItemIcon_SelectedExpanded
 
3092                                           : wxTreeItemIcon_Selected
 
3099             // for the other messages the return value is ignored and there is 
3100             // nothing special to do 
3105 // ---------------------------------------------------------------------------- 
3107 // ---------------------------------------------------------------------------- 
3109 // why do they define INDEXTOSTATEIMAGEMASK but not the inverse? 
3110 #define STATEIMAGEMASKTOINDEX(state) (((state) & TVIS_STATEIMAGEMASK) >> 12) 
3112 void wxTreeCtrl::SetState(const wxTreeItemId
& node
, int state
) 
3115     tvi
.hItem 
= (HTREEITEM
)node
.m_pItem
; 
3116     tvi
.mask 
= TVIF_STATE
; 
3117     tvi
.stateMask 
= TVIS_STATEIMAGEMASK
; 
3119     // Select the specified state, or -1 == cycle to the next one. 
3122         TreeView_GetItem(GetHwnd(), &tvi
); 
3124         state 
= STATEIMAGEMASKTOINDEX(tvi
.state
) + 1; 
3125         if ( state 
== m_imageListState
->GetImageCount() ) 
3129     wxCHECK_RET( state 
< m_imageListState
->GetImageCount(), 
3130                  _T("wxTreeCtrl::SetState(): item index out of bounds") ); 
3132     tvi
.state 
= INDEXTOSTATEIMAGEMASK(state
); 
3134     TreeView_SetItem(GetHwnd(), &tvi
); 
3137 int wxTreeCtrl::GetState(const wxTreeItemId
& node
) 
3140     tvi
.hItem 
= (HTREEITEM
)node
.m_pItem
; 
3141     tvi
.mask 
= TVIF_STATE
; 
3142     tvi
.stateMask 
= TVIS_STATEIMAGEMASK
; 
3143     TreeView_GetItem(GetHwnd(), &tvi
); 
3145     return STATEIMAGEMASKTOINDEX(tvi
.state
); 
3148 #if WXWIN_COMPATIBILITY_2_2 
3150 wxTreeItemId 
wxTreeCtrl::GetParent(const wxTreeItemId
& item
) const 
3152     return GetItemParent( item 
); 
3155 #endif  // WXWIN_COMPATIBILITY_2_2 
3157 #endif // wxUSE_TREECTRL