X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ba8a196102fe2dfbf51599d77d261607d4d91bc7..f94a81c084696210418b8709e8ab649a18465fa6:/src/msw/treectrl.cpp?ds=sidebyside diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index 93bdeea6e7..fd12c8c190 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -17,10 +17,6 @@ // headers // ---------------------------------------------------------------------------- -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "treectrl.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -32,6 +28,11 @@ #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 @@ -44,9 +45,6 @@ #include "wx/msw/treectrl.h" #include "wx/msw/dragimag.h" -// include "properly" -#include "wx/msw/wrapcctl.h" - // macros to hide the cast ugliness // -------------------------------- @@ -346,7 +344,8 @@ public: { m_selections.Empty(); - DoTraverse(tree->GetRootItem()); + if (tree->GetCount() > 0) + DoTraverse(tree->GetRootItem()); } virtual bool OnVisit(const wxTreeItemId& item) @@ -677,7 +676,7 @@ bool wxTreeCtrl::Create(wxWindow *parent, wstyle |= TVS_CHECKBOXES; #endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE -#ifndef __WXWINCE__ +#if !defined(__WXWINCE__) && defined(TVS_INFOTIP) // Need so that TVN_GETINFOTIP messages will be sent wstyle |= TVS_INFOTIP; #endif @@ -2243,20 +2242,42 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara WXLRESULT rc = 0; bool isMultiple = HasFlag(wxTR_MULTIPLE); -#ifdef WM_CONTEXTMENU + // This message is sent after a right-click, or when the "menu" key is pressed if ( nMsg == WM_CONTEXTMENU ) { + int x = GET_X_LPARAM(lParam), + y = GET_Y_LPARAM(lParam); + // Convert the screen point to a client point + wxPoint MenuPoint = ScreenToClient(wxPoint(x, y)); + wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_MENU, GetId() ); // can't use GetSelection() here as it would assert in multiselect mode event.m_item = wxTreeItemId(TreeView_GetSelection(GetHwnd())); event.SetEventObject( this ); + // Get the bounding rectangle for the item, including the non-text areas + wxRect ItemRect; + 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)) + { + event.m_pointDrag = MenuPoint; + } + // Use the Explorer standard of putting the menu at the left edge of the text, + // in the vertical middle of the text. Should be the case for the "menu" key + else + { + // Use the bounding rectangle of only the text part + GetBoundingRect(event.m_item, ItemRect, true); + event.m_pointDrag = wxPoint(ItemRect.GetX(), ItemRect.GetY() + ItemRect.GetHeight() / 2); + } + if ( GetEventHandler()->ProcessEvent(event) ) processed = true; //else: continue with generating wxEVT_CONTEXT_MENU in base class code } -#endif // WM_CONTEXTMENU else if ( (nMsg >= WM_MOUSEFIRST) && (nMsg <= WM_MOUSELAST) ) { // we only process mouse messages here and these parameters have the @@ -2264,6 +2285,12 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara int x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam); HTREEITEM htItem = GetItemFromPoint(GetHwnd(), x, y); + + TV_HITTESTINFO tvht; + tvht.pt.x = x; + tvht.pt.y = y; + + TreeView_HitTest(GetHwnd(), &tvht); switch ( nMsg ) { @@ -2284,8 +2311,11 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara #if !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE case WM_LBUTTONDOWN: - if ( htItem && isMultiple ) + if ( htItem && isMultiple && (tvht.flags & TVHT_ONITEM) != 0 ) { + m_htClickedItem = (WXHTREEITEM) htItem; + m_ptClick = wxPoint(x, y); + if ( wParam & MK_CONTROL ) { SetFocus(); @@ -2311,8 +2341,11 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara m_htSelStart = TreeView_GetSelection(GetHwnd()); } - SelectRange(GetHwnd(), HITEM(m_htSelStart), htItem, + if ( m_htSelStart ) + SelectRange(GetHwnd(), HITEM(m_htSelStart), htItem, !(wParam & MK_CONTROL)); + else + ::SelectItem(GetHwnd(), htItem); ::SetFocus(GetHwnd(), htItem); @@ -2322,6 +2355,8 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara { // avoid doing anything if we click on the only // currently selected item + + SetFocus(); wxArrayTreeItemIds selections; size_t count = GetSelections(selections); @@ -2334,11 +2369,7 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara // otherwise, perform the deselection on mouse-up. // this allows multiple drag and drop to work. - if (IsItemSelected(GetHwnd(), htItem)) - { - ::SetFocus(GetHwnd(), htItem); - } - else + if (!IsItemSelected(GetHwnd(), htItem)) { UnselectAll(); @@ -2350,6 +2381,8 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara TreeView_SelectItem(GetHwnd(), 0); ::SelectItem(GetHwnd(), htItem); } + ::SetFocus(GetHwnd(), htItem); + processed = true; } // reset on any click without Shift @@ -2360,6 +2393,45 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara #endif // wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE case WM_MOUSEMOVE: +#ifndef __WXWINCE__ + if ( m_htClickedItem ) + { + int cx = abs(m_ptClick.x - x); + int cy = abs(m_ptClick.y - y); + + if ( cx > GetSystemMetrics( SM_CXDRAG ) || cy > GetSystemMetrics( SM_CYDRAG ) ) + { + HWND pWnd = ::GetParent( GetHwnd() ); + if ( pWnd ) + { + NM_TREEVIEW tv; + + tv.hdr.hwndFrom = GetHwnd(); + tv.hdr.idFrom = ::GetWindowLong( GetHwnd(), GWL_ID ); + tv.hdr.code = TVN_BEGINDRAG; + + tv.itemNew.hItem = HITEM(m_htClickedItem); + + TVITEM tviAux; + ZeroMemory(&tviAux, sizeof(tviAux)); + tviAux.hItem = HITEM(m_htClickedItem); + tviAux.mask = TVIF_STATE | TVIF_PARAM; + tviAux.stateMask = 0xffffffff; + TreeView_GetItem( GetHwnd(), &tviAux ); + + tv.itemNew.state = tviAux.state; + tv.itemNew.lParam = tviAux.lParam; + + tv.ptDrag.x = x; + tv.ptDrag.y = y; + + ::SendMessage( pWnd, WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv ); + } + m_htClickedItem.Unset(); + } + } +#endif // __WXWINCE__ + if ( m_dragImage ) { m_dragImage->Move(wxPoint(x, y)); @@ -2388,7 +2460,10 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara { UnselectAll(); TreeView_SelectItem(GetHwnd(), htItem); + ::SelectItem(GetHwnd(), htItem); + ::SetFocus(GetHwnd(), htItem); } + m_htClickedItem.Unset(); } // fall through @@ -2517,18 +2592,6 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara } } #endif // !wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE - else if ( nMsg == WM_CHAR ) - { - // 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 - // and Enter presses are mapped in your code - if ( wParam == VK_SPACE || wParam == VK_RETURN ) - { - processed = true; - } - } else if ( nMsg == WM_COMMAND ) { // if we receive a EN_KILLFOCUS command from the in-place edit control @@ -2564,6 +2627,33 @@ wxTreeCtrl::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) 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 + // 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 + // and Enter presses are mapped in your code + if ( wParam == VK_SPACE || wParam == VK_RETURN ) + return 0; + } + return wxControl::MSWDefWindowProc(nMsg, wParam, lParam); } @@ -2655,6 +2745,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; } +#ifdef TVN_GETINFOTIP case TVN_GETINFOTIP: { eventType = wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP; @@ -2665,6 +2756,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; } +#endif #endif case TVN_GETDISPINFO: @@ -2721,8 +2813,8 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) // fabricate the lParam and wParam parameters sufficiently // similar to the ones from a "real" WM_KEYDOWN so that // CreateKeyEvent() works correctly - WXLPARAM lParam = - (::GetKeyState(VK_MENU) < 0 ? KF_ALTDOWN : 0) << 16; + const bool isAltDown = ::GetKeyState(VK_MENU) < 0; + WXLPARAM lParam = (isAltDown ? KF_ALTDOWN : 0) << 16; WXWPARAM wParam = info->wVKey; @@ -2740,7 +2832,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) wParam); // a separate event for Space/Return - if ( !wxIsCtrlDown() && !wxIsShiftDown() && + if ( !wxIsCtrlDown() && !wxIsShiftDown() && !isAltDown && ((info->wVKey == VK_SPACE) || (info->wVKey == VK_RETURN)) ) { wxTreeEvent event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, @@ -3019,6 +3111,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; #ifndef __WXWINCE__ +#ifdef TVN_GETINFOTIP case TVN_GETINFOTIP: { // If the user permitted a tooltip change, change it @@ -3028,6 +3121,7 @@ bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) } } break; +#endif #endif case TVN_SELCHANGING: