X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/03e7d1397ecbc051c6ee3adbc7928ffd404b57f2..8bc333d76d46ce8b3a0077e211ff1485673ae725:/src/msw/treectrl.cpp?ds=inline diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index e9bfaa8961..92dc2fce7d 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -29,6 +29,8 @@ #include "wx/treectrl.h" #ifndef WX_PRECOMP + #include "wx/msw/wrapcctl.h" // include "properly" + #include "wx/msw/missing.h" #include "wx/dynarray.h" #include "wx/log.h" #include "wx/app.h" @@ -37,11 +39,6 @@ #include "wx/msw/private.h" -// include "properly" -#include "wx/msw/wrapcctl.h" - -#include "wx/msw/missing.h" - // Set this to 1 to be _absolutely_ sure that repainting will work for all // comctl32.dll versions #define wxUSE_COMCTL32_SAFELY 0 @@ -55,14 +52,6 @@ // get HTREEITEM from wxTreeItemId #define HITEM(item) ((HTREEITEM)(((item).m_pItem))) -// the native control doesn't support multiple selections under MSW and we -// have 2 ways to emulate them: either using TVS_CHECKBOXES style and let -// checkboxes be the selection status (checked == selected) or by really -// emulating everything, i.e. intercepting mouse and key events &c. The first -// approach is much easier but doesn't work with comctl32.dll < 4.71 and also -// looks quite ugly. -#define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0 - // ---------------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------------- @@ -77,8 +66,6 @@ static HTREEITEM GetItemFromPoint(HWND hwndTV, int x, int y) return (HTREEITEM)TreeView_HitTest(hwndTV, &tvht); } -#if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE - // wrappers for TreeView_GetItem/TreeView_SetItem static bool IsItemSelected(HWND hwndTV, HTREEITEM hItem) { @@ -244,8 +231,6 @@ static void SetFocus(HWND hwndTV, HTREEITEM htItem) } } -#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE - // ---------------------------------------------------------------------------- // private classes // ---------------------------------------------------------------------------- @@ -293,9 +278,9 @@ class wxTreeItemParam { public: wxTreeItemParam() - : m_item((void*)NULL), - m_data(NULL) { + m_data = NULL; + for ( size_t n = 0; n < WXSIZEOF(m_images); n++ ) { m_images[n] = -1; @@ -451,17 +436,15 @@ public: virtual bool OnVisit(const wxTreeItemId& item) { + const wxTreeCtrl * const tree = GetTree(); + // can't visit a virtual node. - if ( (GetTree()->GetRootItem() == item) && (GetTree()->GetWindowStyle() & wxTR_HIDE_ROOT)) + if ( (tree->GetRootItem() == item) && tree->HasFlag(wxTR_HIDE_ROOT) ) { return true; } -#if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE - if ( GetTree()->IsItemChecked(item) ) -#else - if ( ::IsItemSelected(GetHwndOf(GetTree()), HITEM(item)) ) -#endif + if ( ::IsItemSelected(GetHwndOf(tree), HITEM(item)) ) { m_selections.Add(item); } @@ -676,7 +659,7 @@ bool wxTreeCtrl::Create(wxWindow *parent, if ( !CreateControl(parent, id, pos, size, style, validator, name) ) return false; - DWORD exStyle = 0; + WXDWORD exStyle = 0; DWORD wstyle = MSWGetStyle(m_windowStyle, & exStyle); wstyle |= WS_TABSTOP | TVS_SHOWSELALWAYS; @@ -697,20 +680,6 @@ bool wxTreeCtrl::Create(wxWindow *parent, wstyle |= TVS_FULLROWSELECT; } - // using TVS_CHECKBOXES for emulation of a multiselection tree control - // doesn't work without the new enough headers -#if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE && \ - !defined( __GNUWIN32_OLD__ ) && \ - !defined( __BORLANDC__ ) && \ - !defined( __WATCOMC__ ) && \ - (!defined(__VISUALC__) || (__VISUALC__ > 1010)) - - // we emulate the multiple selection tree controls by using checkboxes: set - // up the image list we need for this if we do have multiple selections - if ( m_windowStyle & wxTR_MULTIPLE ) - wstyle |= TVS_CHECKBOXES; -#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE - #if !defined(__WXWINCE__) && defined(TVS_INFOTIP) // Need so that TVN_GETINFOTIP messages will be sent wstyle |= TVS_INFOTIP; @@ -933,6 +902,11 @@ bool wxTreeCtrl::SetForegroundColour(const wxColour &colour) // Item access // ---------------------------------------------------------------------------- +bool wxTreeCtrl::IsHiddenRoot(const wxTreeItemId& item) const +{ + return HITEM(item) == TVI_ROOT && HasFlag(wxTR_HIDE_ROOT); +} + wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), wxEmptyString, wxT("invalid tree item") ); @@ -982,7 +956,7 @@ int wxTreeCtrl::GetItemImage(const wxTreeItemId& item, { wxCHECK_MSG( item.IsOk(), -1, wxT("invalid tree item") ); - if ( (HITEM(item) == TVI_ROOT) && (m_windowStyle & wxTR_HIDE_ROOT) ) + if ( IsHiddenRoot(item) ) { // no images for hidden root item return -1; @@ -1002,7 +976,7 @@ void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image, wxT("invalid image index")); - if ( (HITEM(item) == TVI_ROOT) && (m_windowStyle & wxTR_HIDE_ROOT) ) + if ( IsHiddenRoot(item) ) { // no images for hidden root item return; @@ -1564,7 +1538,7 @@ wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text, wxTreeItemData *data) { - if ( m_windowStyle & wxTR_HIDE_ROOT ) + if ( HasFlag(wxTR_HIDE_ROOT) ) { // create a virtual root item, the parent for all the others wxTreeItemParam *param = new wxTreeItemParam; @@ -1669,7 +1643,7 @@ void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag) wxT("Unknown flag in wxTreeCtrl::DoExpand") ); // A hidden root can be neither expanded nor collapsed. - wxCHECK_RET( !(m_windowStyle & wxTR_HIDE_ROOT) || (HITEM(item) != TVI_ROOT), + wxCHECK_RET( !IsHiddenRoot(item), wxT("Can't expand/collapse hidden root node!") ); // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must @@ -1743,11 +1717,7 @@ void wxTreeCtrl::UnselectAll() size_t count = GetSelections(selections); for ( size_t n = 0; n < count; n++ ) { -#if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE - SetItemCheck(HITEM(selections[n]), false); -#else // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE ::UnselectItem(GetHwnd(), HITEM(selections[n])); -#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE/!wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE } m_htSelStart.Unset(); @@ -1763,12 +1733,7 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select) { if ( m_windowStyle & wxTR_MULTIPLE ) { -#if wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE - // selecting the item means checking it - SetItemCheck(item, select); -#else // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE ::SelectItem(GetHwnd(), HITEM(item), select); -#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE/!wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE } else { @@ -1798,6 +1763,8 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& item, bool select) void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item) { + wxCHECK_RET( !IsHiddenRoot(item), _T("can't show hidden root item") ); + // no error return TreeView_EnsureVisible(GetHwnd(), HITEM(item)); } @@ -2050,7 +2017,7 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara GetBoundingRect(event.m_item, ItemRect, false); // If the point is inside the bounding rectangle, use it as the click position. // This should be the case for WM_CONTEXTMENU as the result of a right-click - if (ItemRect.Inside(MenuPoint)) + if (ItemRect.Contains(MenuPoint)) { event.m_pointDrag = MenuPoint; } @@ -2083,22 +2050,6 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara switch ( nMsg ) { - case WM_RBUTTONDOWN: - // if the item we are about to right click on is not already - // selected or if we click outside of any item, remove the - // entire previous selection - if ( !htItem || !::IsItemSelected(GetHwnd(), htItem) ) - { - UnselectAll(); - } - - // select item and set the focus to the - // newly selected item - ::SelectItem(GetHwnd(), htItem); - ::SetFocus(GetHwnd(), htItem); - break; - -#if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE case WM_LBUTTONDOWN: if ( htItem && isMultiple && (tvht.flags & TVHT_ONITEM) != 0 ) { @@ -2179,7 +2130,6 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara } } break; -#endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE case WM_MOUSEMOVE: #ifndef __WXWINCE__ @@ -2275,7 +2225,6 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara break; } } -#if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE else if ( (nMsg == WM_SETFOCUS || nMsg == WM_KILLFOCUS) && isMultiple ) { // the tree control greys out the selected item when it loses focus and @@ -2375,7 +2324,6 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara } } } -#endif // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE else if ( nMsg == WM_COMMAND ) { // if we receive a EN_KILLFOCUS command from the in-place edit control @@ -2404,32 +2352,9 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara WXLRESULT wxTreeCtrl::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { - // default WM_RBUTTONDOWN handler enters modal loop inside DefWindowProc() - // waiting for WM_RBUTTONUP and then sends the resulting WM_CONTEXTMENU to - // the parent window, not us, which completely breaks everything so simply - // don't let it see this message at all - if ( nMsg == WM_RBUTTONDOWN ) - return 0; - - // but because of the above we don't get NM_RCLICK which is normally - // generated by tree window proc when the modal loop mentioned above ends - // because the mouse is released -- synthesize it ourselves instead - if ( nMsg == WM_RBUTTONUP ) - { - NMHDR hdr; - hdr.hwndFrom = GetHwnd(); - hdr.idFrom = GetId(); - hdr.code = NM_RCLICK; - - WXLPARAM rc; - MSWOnNotify(GetId(), (LPARAM)&hdr, &rc); - - // continue as usual - } - if ( nMsg == WM_CHAR ) { - // also don't let the control process Space and Return keys because it + // don't let the control process Space and Return keys because it // doesn't do anything useful with them anyhow but always beeps // annoyingly when it receives them and there is no way to turn it off // simply if you just process TREEITEM_ACTIVATED event to which Space @@ -2540,8 +2465,8 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; } -#endif -#endif +#endif // TVN_GETINFOTIP +#endif // !__WXWINCE__ case TVN_GETDISPINFO: eventType = wxEVT_COMMAND_TREE_GET_INFO; @@ -2812,6 +2737,17 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) *result = false; break; + case NM_RCLICK: + // prevent tree control from sending WM_CONTEXTMENU to our parent + // (which it does if NM_RCLICK is not handled) because we want to + // send it to the control itself + *result = + processed = true; + + ::SendMessage(GetHwnd(), WM_CONTEXTMENU, + (WPARAM)GetHwnd(), ::GetMessagePos()); + break; + case TVN_BEGINDRAG: case TVN_BEGINRDRAG: if ( event.IsAllowed() )