comctl32/listview: Implement dragging with right button with a message loop.

This commit is contained in:
Nikolay Sivov 2013-01-28 07:56:01 +04:00 committed by Alexandre Julliard
parent 8954671cdc
commit 500da7def6
1 changed files with 109 additions and 85 deletions

View File

@ -99,7 +99,6 @@
* -- LVN_GETINFOTIP * -- LVN_GETINFOTIP
* -- LVN_HOTTRACK * -- LVN_HOTTRACK
* -- LVN_SETDISPINFO * -- LVN_SETDISPINFO
* -- LVN_BEGINRDRAG
* *
* Messages: * Messages:
* -- LVM_ENABLEGROUPVIEW * -- LVM_ENABLEGROUPVIEW
@ -325,7 +324,6 @@ typedef struct tagLISTVIEW_INFO
/* mouse operation */ /* mouse operation */
BOOL bLButtonDown; BOOL bLButtonDown;
BOOL bRButtonDown;
BOOL bDragging; BOOL bDragging;
POINT ptClickPos; /* point where the user clicked */ POINT ptClickPos; /* point where the user clicked */
INT nLButtonDownItem; /* tracks item to reset multiselection on WM_LBUTTONUP */ 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) static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y)
{ {
LVHITTESTINFO ht;
RECT rect;
POINT pt;
if (!(fwKeys & MK_LBUTTON)) if (!(fwKeys & MK_LBUTTON))
infoPtr->bLButtonDown = FALSE; infoPtr->bLButtonDown = FALSE;
if (infoPtr->bLButtonDown) if (infoPtr->bLButtonDown)
{ {
POINT tmp; rect.left = rect.right = infoPtr->ptClickPos.x;
RECT rect; rect.top = rect.bottom = infoPtr->ptClickPos.y;
LVHITTESTINFO lvHitTestInfo;
WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
InflateRect(&rect, GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG));
}
if (infoPtr->bLButtonDown)
{
if (infoPtr->bMarqueeSelect) if (infoPtr->bMarqueeSelect)
{ {
POINT coords_orig; POINT coords_orig;
@ -4037,22 +4041,17 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
return 0; return 0;
} }
rect.left = infoPtr->ptClickPos.x - wDragWidth; pt.x = x;
rect.right = infoPtr->ptClickPos.x + wDragWidth; pt.y = y;
rect.top = infoPtr->ptClickPos.y - wDragHeight;
rect.bottom = infoPtr->ptClickPos.y + wDragHeight;
tmp.x = x; ht.pt = pt;
tmp.y = y; LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
lvHitTestInfo.pt = tmp;
LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
/* reset item marker */ /* reset item marker */
if (infoPtr->nLButtonDownItem != lvHitTestInfo.iItem) if (infoPtr->nLButtonDownItem != ht.iItem)
infoPtr->nLButtonDownItem = -1; infoPtr->nLButtonDownItem = -1;
if (!PtInRect(&rect, tmp)) if (!PtInRect(&rect, pt))
{ {
/* this path covers the following: /* this path covers the following:
1. WM_LBUTTONDOWN over selected item (sets focus on it) 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) if (!infoPtr->bDragging)
{ {
lvHitTestInfo.pt = infoPtr->ptClickPos; ht.pt = infoPtr->ptClickPos;
LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE);
/* If the click is outside the range of an item, begin a /* If the click is outside the range of an item, begin a
highlight. If not, begin an item drag. */ highlight. If not, begin an item drag. */
if (lvHitTestInfo.iItem == -1) if (ht.iItem == -1)
{ {
NMHDR hdr; NMHDR hdr;
@ -4102,7 +4101,7 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
NMLISTVIEW nmlv; NMLISTVIEW nmlv;
ZeroMemory(&nmlv, sizeof(nmlv)); ZeroMemory(&nmlv, sizeof(nmlv));
nmlv.iItem = lvHitTestInfo.iItem; nmlv.iItem = ht.iItem;
nmlv.ptAction = infoPtr->ptClickPos; nmlv.ptAction = infoPtr->ptClickPos;
notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv); notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv);
@ -10015,6 +10014,52 @@ static LRESULT LISTVIEW_LButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x,
return 0; 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: * DESCRIPTION:
* Processes mouse down messages (left mouse button). * Processes mouse down messages (left mouse button).
@ -10619,94 +10664,76 @@ static LRESULT LISTVIEW_RButtonDblClk(const LISTVIEW_INFO *infoPtr, WORD wKey, I
/*** /***
* DESCRIPTION: * DESCRIPTION:
* Processes mouse down messages (right mouse button). * Processes WM_RBUTTONDOWN message and corresponding drag operation.
* *
* PARAMETER(S): * PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure * [I] infoPtr : valid pointer to the listview structure
* [I] wKey : key flag * [I] wKey : key flag
* [I] x,y : mouse coordinate * [I] x, y : mouse coordinate
* *
* RETURN: * RETURN:
* Zero * Zero
*/ */
static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y)
{ {
LVHITTESTINFO lvHitTestInfo; LVHITTESTINFO ht;
INT nItem; 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 */ /* send NM_RELEASEDCAPTURE notification */
if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0; 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 */ /* make sure the listview control window has the focus */
if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf); if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf);
/* set right button down flag */ if ((item >= 0) && (item < infoPtr->nItemCount))
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))
{ {
LISTVIEW_SetItemFocus(infoPtr, nItem); LISTVIEW_SetItemFocus(infoPtr, item);
if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) && if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) &&
!LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED)) !LISTVIEW_GetItemState(infoPtr, item, LVIS_SELECTED))
LISTVIEW_SetSelection(infoPtr, nItem); LISTVIEW_SetSelection(infoPtr, item);
}
else
LISTVIEW_DeselectAll(infoPtr);
if (LISTVIEW_TrackMouse(infoPtr, ht.pt))
{
if (ht.iItem != -1)
{
NMLISTVIEW nmlv;
memset(&nmlv, 0, sizeof(nmlv));
nmlv.iItem = ht.iItem;
nmlv.ptAction = ht.pt;
notify_listview(infoPtr, LVN_BEGINRDRAG, &nmlv);
}
} }
else else
{ {
LISTVIEW_DeselectAll(infoPtr); SetFocus(infoPtr->hwndSelf);
ht.pt.x = x;
ht.pt.y = y;
LISTVIEW_HitTest(infoPtr, &ht, TRUE, FALSE);
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; 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 (!infoPtr->bRButtonDown) return 0;
/* set button flag */
infoPtr->bRButtonDown = FALSE;
/* 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;
/* Change to screen coordinate for WM_CONTEXTMENU */
pt = lvHitTestInfo.pt;
ClientToScreen(infoPtr->hwndSelf, &pt);
/* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
SendMessageW(infoPtr->hwndSelf, WM_CONTEXTMENU,
(WPARAM)infoPtr->hwndSelf, MAKELPARAM(pt.x, pt.y));
return 0;
}
/*** /***
* DESCRIPTION: * DESCRIPTION:
* Sets the cursor. * Sets the cursor.
@ -11600,9 +11627,6 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
return LISTVIEW_RButtonDown(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); 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: case WM_SETCURSOR:
return LISTVIEW_SetCursor(infoPtr, wParam, lParam); return LISTVIEW_SetCursor(infoPtr, wParam, lParam);