1 /////////////////////////////////////////////////////////////////////////////
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 #pragma implementation "treectrl.h"
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
30 #include "wx/window.h"
31 #include "wx/msw/private.h"
34 #include "wx/settings.h"
37 // Mingw32 is a bit mental even though this is done in winundef
46 #if defined(__WIN95__)
49 #include "wx/dynarray.h"
50 #include "wx/imaglist.h"
51 #include "wx/msw/treectrl.h"
54 #include "wx/msw/gnuwin32/extra.h"
57 #if (defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__)
61 // Bug in headers, sometimes
63 #define TVIS_FOCUSED 0x0001
66 // ----------------------------------------------------------------------------
68 // ----------------------------------------------------------------------------
70 // a convenient wrapper around TV_ITEM struct which adds a ctor
71 struct wxTreeViewItem
: public TV_ITEM
73 wxTreeViewItem(const wxTreeItemId
& item
,
74 UINT mask_
, UINT stateMask_
= 0)
77 stateMask
= stateMask_
;
78 hItem
= (HTREEITEM
) (WXHTREEITEM
) item
;
82 // ----------------------------------------------------------------------------
84 // ----------------------------------------------------------------------------
86 #if !USE_SHARED_LIBRARY
87 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxControl
)
90 // ----------------------------------------------------------------------------
92 // ----------------------------------------------------------------------------
94 // handy table for sending events
95 static const wxEventType g_events
[2][2] =
97 { wxEVT_COMMAND_TREE_ITEM_COLLAPSED
, wxEVT_COMMAND_TREE_ITEM_COLLAPSING
},
98 { wxEVT_COMMAND_TREE_ITEM_EXPANDED
, wxEVT_COMMAND_TREE_ITEM_EXPANDING
}
101 // ============================================================================
103 // ============================================================================
105 // ----------------------------------------------------------------------------
106 // construction and destruction
107 // ----------------------------------------------------------------------------
109 void wxTreeCtrl::Init()
111 m_imageListNormal
= NULL
;
112 m_imageListState
= NULL
;
116 bool wxTreeCtrl::Create(wxWindow
*parent
, wxWindowID id
,
117 const wxPoint
& pos
, const wxSize
& size
,
118 long style
, const wxValidator
& validator
,
119 const wxString
& name
)
123 wxSystemSettings settings
;
126 SetValidator(validator
);
128 m_windowStyle
= style
;
132 m_windowId
= (id
== -1) ? NewControlId() : id
;
134 DWORD wstyle
= WS_VISIBLE
| WS_CHILD
| WS_TABSTOP
| TVS_HASLINES
| TVS_SHOWSELALWAYS
;
138 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
) ;
140 // Even with extended styles, need to combine with WS_BORDER
141 // for them to look right.
142 if ( want3D
|| wxStyleHasBorder(m_windowStyle
) )
147 if ( m_windowStyle
& wxTR_HAS_BUTTONS
)
148 wstyle
|= TVS_HASBUTTONS
;
150 if ( m_windowStyle
& wxTR_EDIT_LABELS
)
151 wstyle
|= TVS_EDITLABELS
;
153 if ( m_windowStyle
& wxTR_LINES_AT_ROOT
)
154 wstyle
|= TVS_LINESATROOT
;
156 // Create the tree control.
157 m_hWnd
= (WXHWND
)::CreateWindowEx
163 pos
.x
, pos
.y
, size
.x
, size
.y
,
164 (HWND
)parent
->GetHWND(),
170 wxCHECK_MSG( m_hWnd
, FALSE
, _T("Failed to create tree ctrl") );
173 parent
->AddChild(this);
180 wxTreeCtrl::~wxTreeCtrl()
184 // delete user data to prevent memory leaks
188 // ----------------------------------------------------------------------------
190 // ----------------------------------------------------------------------------
192 // simple wrappers which add error checking in debug mode
194 bool wxTreeCtrl::DoGetItem(wxTreeViewItem
* tvItem
) const
196 if ( !TreeView_GetItem(GetHwnd(), tvItem
) )
198 wxLogLastError("TreeView_GetItem");
206 void wxTreeCtrl::DoSetItem(wxTreeViewItem
* tvItem
)
208 if ( TreeView_SetItem(GetHwnd(), tvItem
) == -1 )
210 wxLogLastError("TreeView_SetItem");
214 size_t wxTreeCtrl::GetCount() const
216 return (size_t)TreeView_GetCount(GetHwnd());
219 unsigned int wxTreeCtrl::GetIndent() const
221 return TreeView_GetIndent(GetHwnd());
224 void wxTreeCtrl::SetIndent(unsigned int indent
)
226 TreeView_SetIndent(GetHwnd(), indent
);
229 wxImageList
*wxTreeCtrl::GetImageList() const
231 return m_imageListNormal
;
234 wxImageList
*wxTreeCtrl::GetStateImageList() const
236 return m_imageListNormal
;
239 void wxTreeCtrl::SetAnyImageList(wxImageList
*imageList
, int which
)
242 TreeView_SetImageList(GetHwnd(),
243 imageList
? imageList
->GetHIMAGELIST() : 0,
247 void wxTreeCtrl::SetImageList(wxImageList
*imageList
)
249 SetAnyImageList(m_imageListNormal
= imageList
, TVSIL_NORMAL
);
252 void wxTreeCtrl::SetStateImageList(wxImageList
*imageList
)
254 SetAnyImageList(m_imageListState
= imageList
, TVSIL_STATE
);
257 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
)
263 wxArrayLong children
;
264 wxTreeItemId child
= GetFirstChild(item
, cookie
);
265 while ( child
.IsOk() )
270 result
+= GetChildrenCount(child
, TRUE
);
273 // add the child to the result in any case
276 child
= GetNextChild(item
, cookie
);
282 // ----------------------------------------------------------------------------
284 // ----------------------------------------------------------------------------
286 wxString
wxTreeCtrl::GetItemText(const wxTreeItemId
& item
) const
288 wxChar buf
[512]; // the size is arbitrary...
290 wxTreeViewItem
tvItem(item
, TVIF_TEXT
);
291 tvItem
.pszText
= buf
;
292 tvItem
.cchTextMax
= WXSIZEOF(buf
);
293 if ( !DoGetItem(&tvItem
) )
295 // don't return some garbage which was on stack, but an empty string
299 return wxString(buf
);
302 void wxTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
)
304 wxTreeViewItem
tvItem(item
, TVIF_TEXT
);
305 tvItem
.pszText
= (wxChar
*)text
.c_str(); // conversion is ok
309 int wxTreeCtrl::GetItemImage(const wxTreeItemId
& item
) const
311 wxTreeViewItem
tvItem(item
, TVIF_IMAGE
);
314 return tvItem
.iImage
;
317 void wxTreeCtrl::SetItemImage(const wxTreeItemId
& item
, int image
)
319 wxTreeViewItem
tvItem(item
, TVIF_IMAGE
);
320 tvItem
.iImage
= image
;
324 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const
326 wxTreeViewItem
tvItem(item
, TVIF_SELECTEDIMAGE
);
329 return tvItem
.iSelectedImage
;
332 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
)
334 wxTreeViewItem
tvItem(item
, TVIF_SELECTEDIMAGE
);
335 tvItem
.iSelectedImage
= image
;
339 wxTreeItemData
*wxTreeCtrl::GetItemData(const wxTreeItemId
& item
) const
341 wxTreeViewItem
tvItem(item
, TVIF_PARAM
);
342 if ( !DoGetItem(&tvItem
) )
347 return (wxTreeItemData
*)tvItem
.lParam
;
350 void wxTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData
*data
)
352 wxTreeViewItem
tvItem(item
, TVIF_PARAM
);
353 tvItem
.lParam
= (LPARAM
)data
;
357 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
)
359 wxTreeViewItem
tvItem(item
, TVIF_CHILDREN
);
360 tvItem
.cChildren
= (int)has
;
364 void wxTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
)
366 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_BOLD
);
367 tvItem
.state
= bold
? TVIS_BOLD
: 0;
371 void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId
& item
, bool highlight
)
373 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_DROPHILITED
);
374 tvItem
.state
= highlight
? TVIS_DROPHILITED
: 0;
378 // ----------------------------------------------------------------------------
380 // ----------------------------------------------------------------------------
382 bool wxTreeCtrl::IsVisible(const wxTreeItemId
& item
) const
384 // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect
386 return SendMessage(GetHwnd(), TVM_GETITEMRECT
, FALSE
, (LPARAM
)&rect
) != 0;
390 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const
392 wxTreeViewItem
tvItem(item
, TVIF_CHILDREN
);
395 return tvItem
.cChildren
!= 0;
398 bool wxTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const
400 // probably not a good idea to put it here
401 //wxASSERT( ItemHasChildren(item) );
403 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_EXPANDED
);
406 return (tvItem
.state
& TVIS_EXPANDED
) != 0;
409 bool wxTreeCtrl::IsSelected(const wxTreeItemId
& item
) const
411 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_SELECTED
);
414 return (tvItem
.state
& TVIS_SELECTED
) != 0;
417 bool wxTreeCtrl::IsBold(const wxTreeItemId
& item
) const
419 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_BOLD
);
422 return (tvItem
.state
& TVIS_BOLD
) != 0;
425 // ----------------------------------------------------------------------------
427 // ----------------------------------------------------------------------------
429 wxTreeItemId
wxTreeCtrl::GetRootItem() const
431 return wxTreeItemId((WXHTREEITEM
) TreeView_GetRoot(GetHwnd()));
434 wxTreeItemId
wxTreeCtrl::GetSelection() const
436 return wxTreeItemId((WXHTREEITEM
) TreeView_GetSelection(GetHwnd()));
439 wxTreeItemId
wxTreeCtrl::GetParent(const wxTreeItemId
& item
) const
441 return wxTreeItemId((WXHTREEITEM
) TreeView_GetParent(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
) item
));
444 wxTreeItemId
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
,
447 // remember the last child returned in 'cookie'
448 _cookie
= (long)TreeView_GetChild(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
)item
);
450 return wxTreeItemId((WXHTREEITEM
)_cookie
);
453 wxTreeItemId
wxTreeCtrl::GetNextChild(const wxTreeItemId
& WXUNUSED(item
),
456 wxTreeItemId l
= wxTreeItemId((WXHTREEITEM
)TreeView_GetNextSibling(GetHwnd(),
457 (HTREEITEM
)(WXHTREEITEM
)_cookie
));
463 wxTreeItemId
wxTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const
465 // can this be done more efficiently?
468 wxTreeItemId childLast
,
469 child
= GetFirstChild(item
, cookie
);
470 while ( child
.IsOk() )
473 child
= GetNextChild(item
, cookie
);
479 wxTreeItemId
wxTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const
481 return wxTreeItemId((WXHTREEITEM
) TreeView_GetNextSibling(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
) item
));
484 wxTreeItemId
wxTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const
486 return wxTreeItemId((WXHTREEITEM
) TreeView_GetPrevSibling(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
) item
));
489 wxTreeItemId
wxTreeCtrl::GetFirstVisibleItem() const
491 return wxTreeItemId((WXHTREEITEM
) TreeView_GetFirstVisible(GetHwnd()));
494 wxTreeItemId
wxTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const
496 wxASSERT_MSG( IsVisible(item
), _T("The item you call GetNextVisible() "
497 "for must be visible itself!"));
499 return wxTreeItemId((WXHTREEITEM
) TreeView_GetNextVisible(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
) item
));
502 wxTreeItemId
wxTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const
504 wxASSERT_MSG( IsVisible(item
), _T("The item you call GetPrevVisible() "
505 "for must be visible itself!"));
507 return wxTreeItemId((WXHTREEITEM
) TreeView_GetPrevVisible(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
) item
));
510 // ----------------------------------------------------------------------------
512 // ----------------------------------------------------------------------------
514 wxTreeItemId
wxTreeCtrl::DoInsertItem(const wxTreeItemId
& parent
,
515 wxTreeItemId hInsertAfter
,
516 const wxString
& text
,
517 int image
, int selectedImage
,
518 wxTreeItemData
*data
)
520 TV_INSERTSTRUCT tvIns
;
521 tvIns
.hParent
= (HTREEITEM
) (WXHTREEITEM
)parent
;
522 tvIns
.hInsertAfter
= (HTREEITEM
) (WXHTREEITEM
) hInsertAfter
;
524 // This is how we insert the item as the first child: supply a NULL hInsertAfter
525 if (tvIns
.hInsertAfter
== (HTREEITEM
) 0)
527 tvIns
.hInsertAfter
= TVI_FIRST
;
531 if ( !text
.IsEmpty() )
534 tvIns
.item
.pszText
= (wxChar
*)text
.c_str(); // cast is ok
540 tvIns
.item
.iImage
= image
;
542 if ( selectedImage
== -1 )
544 // take the same image for selected icon if not specified
545 selectedImage
= image
;
549 if ( selectedImage
!= -1 )
551 mask
|= TVIF_SELECTEDIMAGE
;
552 tvIns
.item
.iSelectedImage
= selectedImage
;
558 tvIns
.item
.lParam
= (LPARAM
)data
;
561 tvIns
.item
.mask
= mask
;
563 HTREEITEM id
= (HTREEITEM
) TreeView_InsertItem(GetHwnd(), &tvIns
);
566 wxLogLastError("TreeView_InsertItem");
571 // associate the application tree item with Win32 tree item handle
572 data
->SetId((WXHTREEITEM
)id
);
575 return wxTreeItemId((WXHTREEITEM
)id
);
578 // for compatibility only
579 wxTreeItemId
wxTreeCtrl::InsertItem(const wxTreeItemId
& parent
,
580 const wxString
& text
,
581 int image
, int selImage
,
584 return DoInsertItem(parent
, (WXHTREEITEM
)insertAfter
, text
,
585 image
, selImage
, NULL
);
588 wxTreeItemId
wxTreeCtrl::AddRoot(const wxString
& text
,
589 int image
, int selectedImage
,
590 wxTreeItemData
*data
)
592 return DoInsertItem(wxTreeItemId((WXHTREEITEM
) 0), (WXHTREEITEM
) 0,
593 text
, image
, selectedImage
, data
);
596 wxTreeItemId
wxTreeCtrl::PrependItem(const wxTreeItemId
& parent
,
597 const wxString
& text
,
598 int image
, int selectedImage
,
599 wxTreeItemData
*data
)
601 return DoInsertItem(parent
, (WXHTREEITEM
) TVI_FIRST
,
602 text
, image
, selectedImage
, data
);
605 wxTreeItemId
wxTreeCtrl::InsertItem(const wxTreeItemId
& parent
,
606 const wxTreeItemId
& idPrevious
,
607 const wxString
& text
,
608 int image
, int selectedImage
,
609 wxTreeItemData
*data
)
611 return DoInsertItem(parent
, idPrevious
, text
, image
, selectedImage
, data
);
614 wxTreeItemId
wxTreeCtrl::AppendItem(const wxTreeItemId
& parent
,
615 const wxString
& text
,
616 int image
, int selectedImage
,
617 wxTreeItemData
*data
)
619 return DoInsertItem(parent
, (WXHTREEITEM
) TVI_LAST
,
620 text
, image
, selectedImage
, data
);
623 void wxTreeCtrl::Delete(const wxTreeItemId
& item
)
625 if ( !TreeView_DeleteItem(GetHwnd(), (HTREEITEM
)(WXHTREEITEM
)item
) )
627 wxLogLastError("TreeView_DeleteItem");
631 // delete all children (but don't delete the item itself)
632 void wxTreeCtrl::DeleteChildren(const wxTreeItemId
& item
)
636 wxArrayLong children
;
637 wxTreeItemId child
= GetFirstChild(item
, cookie
);
638 while ( child
.IsOk() )
640 children
.Add((long)(WXHTREEITEM
)child
);
642 child
= GetNextChild(item
, cookie
);
645 size_t nCount
= children
.Count();
646 for ( size_t n
= 0; n
< nCount
; n
++ )
648 if ( !TreeView_DeleteItem(GetHwnd(), (HTREEITEM
)children
[n
]) )
650 wxLogLastError("TreeView_DeleteItem");
655 void wxTreeCtrl::DeleteAllItems()
657 if ( !TreeView_DeleteAllItems(GetHwnd()) )
659 wxLogLastError("TreeView_DeleteAllItems");
663 void wxTreeCtrl::DoExpand(const wxTreeItemId
& item
, int flag
)
665 wxASSERT_MSG( flag
== TVE_COLLAPSE
||
666 flag
== (TVE_COLLAPSE
| TVE_COLLAPSERESET
) ||
667 flag
== TVE_EXPAND
||
669 _T("Unknown flag in wxTreeCtrl::DoExpand") );
671 // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
672 // emulate them. This behaviour has changed slightly with comctl32.dll
673 // v 4.70 - now it does send them but only the first time. To maintain
674 // compatible behaviour and also in order to not have surprises with the
675 // future versions, don't rely on this and still do everything ourselves.
676 // To avoid that the messages be sent twice when the item is expanded for
677 // the first time we must clear TVIS_EXPANDEDONCE style manually.
679 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_EXPANDEDONCE
);
683 if ( TreeView_Expand(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
) item
, flag
) != 0 )
685 wxTreeEvent
event(wxEVT_NULL
, m_windowId
);
688 bool isExpanded
= IsExpanded(item
);
690 event
.SetEventObject(this);
692 // FIXME return value of {EXPAND|COLLAPS}ING event handler is discarded
693 event
.SetEventType(g_events
[isExpanded
][TRUE
]);
694 GetEventHandler()->ProcessEvent(event
);
696 event
.SetEventType(g_events
[isExpanded
][FALSE
]);
697 GetEventHandler()->ProcessEvent(event
);
699 //else: change didn't took place, so do nothing at all
702 void wxTreeCtrl::Expand(const wxTreeItemId
& item
)
704 DoExpand(item
, TVE_EXPAND
);
707 void wxTreeCtrl::Collapse(const wxTreeItemId
& item
)
709 DoExpand(item
, TVE_COLLAPSE
);
712 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
)
714 DoExpand(item
, TVE_COLLAPSE
| TVE_COLLAPSERESET
);
717 void wxTreeCtrl::Toggle(const wxTreeItemId
& item
)
719 DoExpand(item
, TVE_TOGGLE
);
722 void wxTreeCtrl::ExpandItem(const wxTreeItemId
& item
, int action
)
724 DoExpand(item
, action
);
727 void wxTreeCtrl::Unselect()
729 SelectItem(wxTreeItemId((WXHTREEITEM
) 0));
732 void wxTreeCtrl::SelectItem(const wxTreeItemId
& item
)
734 // inspite of the docs (MSDN Jan 99 edition), we don't seem to receive
735 // the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so
736 // send them ourselves
738 wxTreeEvent
event(wxEVT_NULL
, m_windowId
);
740 event
.SetEventObject(this);
742 event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGING
);
743 if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() )
745 if ( !TreeView_SelectItem(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
) item
) )
747 wxLogLastError("TreeView_SelectItem");
751 event
.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED
);
752 (void)GetEventHandler()->ProcessEvent(event
);
755 //else: program vetoed the change
758 void wxTreeCtrl::EnsureVisible(const wxTreeItemId
& item
)
761 TreeView_EnsureVisible(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
) item
);
764 void wxTreeCtrl::ScrollTo(const wxTreeItemId
& item
)
766 if ( !TreeView_SelectSetFirstVisible(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
) item
) )
768 wxLogLastError("TreeView_SelectSetFirstVisible");
772 wxTextCtrl
* wxTreeCtrl::GetEditControl() const
777 void wxTreeCtrl::DeleteTextCtrl()
781 m_textCtrl
->UnsubclassWin();
782 m_textCtrl
->SetHWND(0);
788 wxTextCtrl
* wxTreeCtrl::EditLabel(const wxTreeItemId
& item
,
789 wxClassInfo
* textControlClass
)
791 wxASSERT( textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
)) );
793 HWND hWnd
= (HWND
) TreeView_EditLabel(GetHwnd(), (HTREEITEM
) (WXHTREEITEM
) item
);
795 wxCHECK_MSG( hWnd
, NULL
, _T("Can't edit tree ctrl label") );
799 m_textCtrl
= (wxTextCtrl
*)textControlClass
->CreateObject();
800 m_textCtrl
->SetHWND((WXHWND
)hWnd
);
801 m_textCtrl
->SubclassWin((WXHWND
)hWnd
);
806 // End label editing, optionally cancelling the edit
807 void wxTreeCtrl::EndEditLabel(const wxTreeItemId
& item
, bool discardChanges
)
809 TreeView_EndEditLabelNow(GetHwnd(), discardChanges
);
814 wxTreeItemId
wxTreeCtrl::HitTest(const wxPoint
& point
, int& flags
)
816 TV_HITTESTINFO hitTestInfo
;
817 hitTestInfo
.pt
.x
= (int)point
.x
;
818 hitTestInfo
.pt
.y
= (int)point
.y
;
820 TreeView_HitTest(GetHwnd(), &hitTestInfo
);
825 #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \
826 flags |= wxTREE_HITTEST_##flag
828 TRANSLATE_FLAG(ABOVE
);
829 TRANSLATE_FLAG(BELOW
);
830 TRANSLATE_FLAG(NOWHERE
);
831 TRANSLATE_FLAG(ONITEMBUTTON
);
832 TRANSLATE_FLAG(ONITEMICON
);
833 TRANSLATE_FLAG(ONITEMINDENT
);
834 TRANSLATE_FLAG(ONITEMLABEL
);
835 TRANSLATE_FLAG(ONITEMRIGHT
);
836 TRANSLATE_FLAG(ONITEMSTATEICON
);
837 TRANSLATE_FLAG(TOLEFT
);
838 TRANSLATE_FLAG(TORIGHT
);
840 #undef TRANSLATE_FLAG
842 return wxTreeItemId((WXHTREEITEM
) hitTestInfo
.hItem
);
845 bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
,
850 if ( TreeView_GetItemRect(GetHwnd(), (HTREEITEM
)(WXHTREEITEM
)item
,
853 rect
= wxRect(wxPoint(rc
.left
, rc
.top
), wxPoint(rc
.right
, rc
.bottom
));
859 // couldn't retrieve rect: for example, item isn't visible
864 // ----------------------------------------------------------------------------
866 // ----------------------------------------------------------------------------
868 static int CALLBACK
TreeView_CompareCallback(wxTreeItemData
*pItem1
,
869 wxTreeItemData
*pItem2
,
872 wxCHECK_MSG( pItem1
&& pItem2
, 0,
873 _T("sorting tree without data doesn't make sense") );
875 return tree
->OnCompareItems(pItem1
->GetId(), pItem2
->GetId());
878 int wxTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
,
879 const wxTreeItemId
& item2
)
881 return wxStrcmp(GetItemText(item1
), GetItemText(item2
));
884 void wxTreeCtrl::SortChildren(const wxTreeItemId
& item
)
886 // rely on the fact that TreeView_SortChildren does the same thing as our
887 // default behaviour, i.e. sorts items alphabetically and so call it
888 // directly if we're not in derived class (much more efficient!)
889 if ( GetClassInfo() == CLASSINFO(wxTreeCtrl
) )
891 TreeView_SortChildren(GetHwnd(), (HTREEITEM
)(WXHTREEITEM
)item
, 0);
896 tvSort
.hParent
= (HTREEITEM
)(WXHTREEITEM
)item
;
897 tvSort
.lpfnCompare
= (PFNTVCOMPARE
)TreeView_CompareCallback
;
898 tvSort
.lParam
= (LPARAM
)this;
899 TreeView_SortChildrenCB(GetHwnd(), &tvSort
, 0 /* reserved */);
903 // ----------------------------------------------------------------------------
905 // ----------------------------------------------------------------------------
907 bool wxTreeCtrl::MSWCommand(WXUINT cmd
, WXWORD id
)
909 if ( cmd
== EN_UPDATE
)
911 wxCommandEvent
event(wxEVT_COMMAND_TEXT_UPDATED
, id
);
912 event
.SetEventObject( this );
913 ProcessCommand(event
);
915 else if ( cmd
== EN_KILLFOCUS
)
917 wxCommandEvent
event(wxEVT_KILL_FOCUS
, id
);
918 event
.SetEventObject( this );
919 ProcessCommand(event
);
931 // process WM_NOTIFY Windows message
932 bool wxTreeCtrl::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
)
934 wxTreeEvent
event(wxEVT_NULL
, m_windowId
);
935 wxEventType eventType
= wxEVT_NULL
;
936 NMHDR
*hdr
= (NMHDR
*)lParam
;
941 eventType
= wxEVT_COMMAND_TREE_BEGIN_DRAG
;
946 if ( eventType
== wxEVT_NULL
)
947 eventType
= wxEVT_COMMAND_TREE_BEGIN_RDRAG
;
948 //else: left drag, already set above
950 NM_TREEVIEW
*tv
= (NM_TREEVIEW
*)lParam
;
952 event
.m_item
= (WXHTREEITEM
) tv
->itemNew
.hItem
;
953 event
.m_pointDrag
= wxPoint(tv
->ptDrag
.x
, tv
->ptDrag
.y
);
957 case TVN_BEGINLABELEDIT
:
959 eventType
= wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
;
960 TV_DISPINFO
*info
= (TV_DISPINFO
*)lParam
;
962 event
.m_item
= (WXHTREEITEM
) info
->item
.hItem
;
968 eventType
= wxEVT_COMMAND_TREE_DELETE_ITEM
;
969 NM_TREEVIEW
*tv
= (NM_TREEVIEW
*)lParam
;
971 event
.m_item
= (WXHTREEITEM
) tv
->itemOld
.hItem
;
975 case TVN_ENDLABELEDIT
:
977 eventType
= wxEVT_COMMAND_TREE_END_LABEL_EDIT
;
978 TV_DISPINFO
*info
= (TV_DISPINFO
*)lParam
;
980 event
.m_item
= (WXHTREEITEM
) info
->item
.hItem
;
984 case TVN_GETDISPINFO
:
985 eventType
= wxEVT_COMMAND_TREE_GET_INFO
;
988 case TVN_SETDISPINFO
:
990 if ( eventType
== wxEVT_NULL
)
991 eventType
= wxEVT_COMMAND_TREE_SET_INFO
;
992 //else: get, already set above
994 TV_DISPINFO
*info
= (TV_DISPINFO
*)lParam
;
996 event
.m_item
= (WXHTREEITEM
) info
->item
.hItem
;
1000 case TVN_ITEMEXPANDING
:
1001 event
.m_code
= FALSE
;
1004 case TVN_ITEMEXPANDED
:
1006 NM_TREEVIEW
* tv
= (NM_TREEVIEW
*)lParam
;
1008 bool expand
= FALSE
;
1009 switch ( tv
->action
)
1020 wxLogDebug(_T("unexpected code %d in TVN_ITEMEXPAND "
1021 "message"), tv
->action
);
1024 bool ing
= (hdr
->code
== TVN_ITEMEXPANDING
);
1025 eventType
= g_events
[expand
][ing
];
1027 event
.m_item
= (WXHTREEITEM
) tv
->itemNew
.hItem
;
1033 eventType
= wxEVT_COMMAND_TREE_KEY_DOWN
;
1034 TV_KEYDOWN
*info
= (TV_KEYDOWN
*)lParam
;
1036 event
.m_code
= wxCharCodeMSWToWX(info
->wVKey
);
1038 // a separate event for this case
1039 if ( info
->wVKey
== VK_SPACE
|| info
->wVKey
== VK_RETURN
)
1041 wxTreeEvent
event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED
,
1043 event2
.SetEventObject(this);
1045 GetEventHandler()->ProcessEvent(event2
);
1050 case TVN_SELCHANGED
:
1051 eventType
= wxEVT_COMMAND_TREE_SEL_CHANGED
;
1054 case TVN_SELCHANGING
:
1056 if ( eventType
== wxEVT_NULL
)
1057 eventType
= wxEVT_COMMAND_TREE_SEL_CHANGING
;
1058 //else: already set above
1060 NM_TREEVIEW
* tv
= (NM_TREEVIEW
*)lParam
;
1062 event
.m_item
= (WXHTREEITEM
) tv
->itemNew
.hItem
;
1063 event
.m_itemOld
= (WXHTREEITEM
) tv
->itemOld
.hItem
;
1068 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1071 event
.SetEventObject(this);
1072 event
.SetEventType(eventType
);
1074 bool processed
= GetEventHandler()->ProcessEvent(event
);
1077 if ( hdr
->code
== TVN_DELETEITEM
)
1079 // NB: we might process this message using wxWindows event tables, but
1080 // due to overhead of wxWin event system we prefer to do it here
1081 // (otherwise deleting a tree with many items is just too slow)
1082 NM_TREEVIEW
* tv
= (NM_TREEVIEW
*)lParam
;
1083 wxTreeItemData
*data
= (wxTreeItemData
*)tv
->itemOld
.lParam
;
1084 delete data
; // may be NULL, ok
1085 processed
= TRUE
; // Make sure we don't get called twice
1088 *result
= !event
.IsAllowed();
1093 // ----------------------------------------------------------------------------
1095 // ----------------------------------------------------------------------------
1097 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent
, wxNotifyEvent
)
1099 wxTreeEvent::wxTreeEvent(wxEventType commandType
, int id
)
1100 : wxNotifyEvent(commandType
, id
)