Nikolay Sivov : comctl32/listview: Implement dragging with right button with a message loop.
Alexandre Julliard
julliard at winehq.org
Mon Jan 28 13:43:19 CST 2013
Module: wine
Branch: master
Commit: 500da7def68934d2e2d74e611bb6cce77d59d60e
URL: http://source.winehq.org/git/wine.git/?a=commit;h=500da7def68934d2e2d74e611bb6cce77d59d60e
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Mon Jan 28 07:56:01 2013 +0400
comctl32/listview: Implement dragging with right button with a message loop.
---
dlls/comctl32/listview.c | 186 ++++++++++++++++++++++++++--------------------
1 files changed, 105 insertions(+), 81 deletions(-)
diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index 49da83c..a87ab98 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -99,7 +99,6 @@
* -- LVN_GETINFOTIP
* -- LVN_HOTTRACK
* -- LVN_SETDISPINFO
- * -- LVN_BEGINRDRAG
*
* Messages:
* -- LVM_ENABLEGROUPVIEW
@@ -325,7 +324,6 @@ typedef struct tagLISTVIEW_INFO
/* mouse operation */
BOOL bLButtonDown;
- BOOL bRButtonDown;
BOOL bDragging;
POINT ptClickPos; /* point where the user clicked */
INT nLButtonDownItem; /* tracks item to reset multiselection on WM_LBUTTONUP */
@@ -3984,17 +3982,23 @@ static VOID CALLBACK LISTVIEW_ScrollTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent
*/
static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y)
{
+ LVHITTESTINFO ht;
+ RECT rect;
+ POINT pt;
+
if (!(fwKeys & MK_LBUTTON))
infoPtr->bLButtonDown = FALSE;
if (infoPtr->bLButtonDown)
{
- POINT tmp;
- RECT rect;
- LVHITTESTINFO lvHitTestInfo;
- WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
- WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
+ rect.left = rect.right = infoPtr->ptClickPos.x;
+ rect.top = rect.bottom = infoPtr->ptClickPos.y;
+ InflateRect(&rect, GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG));
+ }
+
+ if (infoPtr->bLButtonDown)
+ {
if (infoPtr->bMarqueeSelect)
{
POINT coords_orig;
@@ -4037,22 +4041,17 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
return 0;
}
- rect.left = infoPtr->ptClickPos.x - wDragWidth;
- rect.right = infoPtr->ptClickPos.x + wDragWidth;
- rect.top = infoPtr->ptClickPos.y - wDragHeight;
- rect.bottom = infoPtr->ptClickPos.y + wDragHeight;
-
- tmp.x = x;
- tmp.y = y;
+ pt.x = x;
+ pt.y = y;
- lvHitTestInfo.pt = tmp;
- LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
+ ht.pt = pt;
+ LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
/* reset item marker */
- if (infoPtr->nLButtonDownItem != lvHitTestInfo.iItem)
+ if (infoPtr->nLButtonDownItem != ht.iItem)
infoPtr->nLButtonDownItem = -1;
- if (!PtInRect(&rect, tmp))
+ if (!PtInRect(&rect, pt))
{
/* this path covers the following:
1. WM_LBUTTONDOWN over selected item (sets focus on it)
@@ -4072,12 +4071,12 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
if (!infoPtr->bDragging)
{
- lvHitTestInfo.pt = infoPtr->ptClickPos;
- LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
+ ht.pt = infoPtr->ptClickPos;
+ LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
/* If the click is outside the range of an item, begin a
highlight. If not, begin an item drag. */
- if (lvHitTestInfo.iItem == -1)
+ if (ht.iItem == -1)
{
NMHDR hdr;
@@ -4102,7 +4101,7 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
NMLISTVIEW nmlv;
ZeroMemory(&nmlv, sizeof(nmlv));
- nmlv.iItem = lvHitTestInfo.iItem;
+ nmlv.iItem = ht.iItem;
nmlv.ptAction = infoPtr->ptClickPos;
notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv);
@@ -10015,6 +10014,52 @@ static LRESULT LISTVIEW_LButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x,
return 0;
}
+static LRESULT LISTVIEW_TrackMouse(const LISTVIEW_INFO *infoPtr, POINT pt)
+{
+ MSG msg;
+ RECT r;
+
+ r.top = r.bottom = pt.y;
+ r.left = r.right = pt.x;
+
+ InflateRect(&r, GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG));
+
+ SetCapture(infoPtr->hwndSelf);
+
+ while (1)
+ {
+ if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD))
+ {
+ if (msg.message == WM_MOUSEMOVE)
+ {
+ pt.x = (short)LOWORD(msg.lParam);
+ pt.y = (short)HIWORD(msg.lParam);
+ if (PtInRect(&r, pt))
+ continue;
+ else
+ {
+ ReleaseCapture();
+ return 1;
+ }
+ }
+ else if (msg.message >= WM_LBUTTONDOWN &&
+ msg.message <= WM_RBUTTONDBLCLK)
+ {
+ break;
+ }
+
+ DispatchMessageW(&msg);
+ }
+
+ if (GetCapture() != infoPtr->hwndSelf)
+ return 0;
+ }
+
+ ReleaseCapture();
+ return 0;
+}
+
+
/***
* DESCRIPTION:
* Processes mouse down messages (left mouse button).
@@ -10619,94 +10664,76 @@ static LRESULT LISTVIEW_RButtonDblClk(const LISTVIEW_INFO *infoPtr, WORD wKey, I
/***
* DESCRIPTION:
- * Processes mouse down messages (right mouse button).
+ * Processes WM_RBUTTONDOWN message and corresponding drag operation.
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
* [I] wKey : key flag
- * [I] x,y : mouse coordinate
+ * [I] x, y : mouse coordinate
*
* RETURN:
* Zero
*/
static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
{
- LVHITTESTINFO lvHitTestInfo;
- INT nItem;
+ LVHITTESTINFO ht;
+ INT item;
- TRACE("(key=%hu,X=%u,Y=%u)\n", wKey, x, y);
+ TRACE("(key=%hu, x=%d, y=%d)\n", wKey, x, y);
/* send NM_RELEASEDCAPTURE notification */
if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0;
+ /* determine the index of the selected item */
+ ht.pt.x = x;
+ ht.pt.y = y;
+ item = LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
+
/* make sure the listview control window has the focus */
if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf);
- /* set right button down flag */
- infoPtr->bRButtonDown = TRUE;
-
- /* determine the index of the selected item */
- lvHitTestInfo.pt.x = x;
- lvHitTestInfo.pt.y = y;
- nItem = LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
-
- if ((nItem >= 0) && (nItem < infoPtr->nItemCount))
+ if ((item >= 0) && (item < infoPtr->nItemCount))
{
- LISTVIEW_SetItemFocus(infoPtr, nItem);
+ LISTVIEW_SetItemFocus(infoPtr, item);
if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) &&
- !LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
- LISTVIEW_SetSelection(infoPtr, nItem);
+ !LISTVIEW_GetItemState(infoPtr, item, LVIS_SELECTED))
+ LISTVIEW_SetSelection(infoPtr, item);
}
else
- {
LISTVIEW_DeselectAll(infoPtr);
- }
-
- return 0;
-}
-
-/***
- * DESCRIPTION:
- * Processes mouse up messages (right mouse button).
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] wKey : key flag
- * [I] x,y : mouse coordinate
- *
- * RETURN:
- * Zero
- */
-static LRESULT LISTVIEW_RButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
-{
- LVHITTESTINFO lvHitTestInfo;
- POINT pt;
- TRACE("(key=%hu,X=%u,Y=%u)\n", wKey, x, y);
+ if (LISTVIEW_TrackMouse(infoPtr, ht.pt))
+ {
+ if (ht.iItem != -1)
+ {
+ NMLISTVIEW nmlv;
- if (!infoPtr->bRButtonDown) return 0;
-
- /* set button flag */
- infoPtr->bRButtonDown = FALSE;
+ memset(&nmlv, 0, sizeof(nmlv));
+ nmlv.iItem = ht.iItem;
+ nmlv.ptAction = ht.pt;
- /* Send NM_RCLICK notification */
- lvHitTestInfo.pt.x = x;
- lvHitTestInfo.pt.y = y;
- LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE);
- if (!notify_click(infoPtr, NM_RCLICK, &lvHitTestInfo)) return 0;
+ notify_listview(infoPtr, LVN_BEGINRDRAG, &nmlv);
+ }
+ }
+ else
+ {
+ SetFocus(infoPtr->hwndSelf);
- /* Change to screen coordinate for WM_CONTEXTMENU */
- pt = lvHitTestInfo.pt;
- ClientToScreen(infoPtr->hwndSelf, &pt);
+ ht.pt.x = x;
+ ht.pt.y = y;
+ LISTVIEW_HitTest(infoPtr, &ht, TRUE, FALSE);
- /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
- SendMessageW(infoPtr->hwndSelf, WM_CONTEXTMENU,
- (WPARAM)infoPtr->hwndSelf, MAKELPARAM(pt.x, pt.y));
+ if (notify_click(infoPtr, NM_RCLICK, &ht))
+ {
+ /* Send a WM_CONTEXTMENU message in response to the WM_RBUTTONUP */
+ SendMessageW(infoPtr->hwndSelf, WM_CONTEXTMENU,
+ (WPARAM)infoPtr->hwndSelf, (LPARAM)GetMessagePos());
+ }
+ }
return 0;
}
-
/***
* DESCRIPTION:
* Sets the cursor.
@@ -11600,9 +11627,6 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_RBUTTONDOWN:
return LISTVIEW_RButtonDown(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
- case WM_RBUTTONUP:
- return LISTVIEW_RButtonUp(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
-
case WM_SETCURSOR:
return LISTVIEW_SetCursor(infoPtr, wParam, lParam);
More information about the wine-cvs
mailing list