X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f3f717033dbff8eb6fd9ad047148909ddd296476..48f625bc2ce81132a2a8c2d7c524a03f1b7196e5:/src/msw/treectrl.cpp?ds=sidebyside diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index 438cb312c0..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" @@ -31,6 +27,10 @@ #if wxUSE_TREECTRL #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 @@ -45,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 // -------------------------------- @@ -347,7 +344,8 @@ public: { m_selections.Empty(); - DoTraverse(tree->GetRootItem()); + if (tree->GetCount() > 0) + DoTraverse(tree->GetRootItem()); } virtual bool OnVisit(const wxTreeItemId& item) @@ -2244,14 +2242,38 @@ WXLRESULT wxTreeCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara WXLRESULT rc = 0; bool isMultiple = HasFlag(wxTR_MULTIPLE); + // 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 @@ -2263,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 ) { @@ -2283,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(); @@ -2310,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); @@ -2321,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); @@ -2333,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(); @@ -2349,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 @@ -2359,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)); @@ -2387,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 @@ -2737,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; @@ -2756,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,