[13/13] comctl32/listview: Handle mouse selections more accurately

Nikolay Sivov bunglehead at gmail.com
Mon May 18 12:20:25 CDT 2009


http://bugs.winehq.org/show_bug.cgi?id=4372

This fix covers the following:
    - after multiple selection made clicking on selected item changes selection
      only after mouse button released
    - pressing L-button on selected item in multiselection and changing focused item
      with keys should select only new focused item. After that moving mouse further
      drag limits should select and focus the first one back.
    - pressing L-button outside items' rectangles with selection keys (Ctrl, Shift)
      pressed shouldn't clear multiselection.

Changelog:
    - Handle mouse selections more accurately

>From 177f5d689253073218b17df62fdd957c53eaff60 Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <bunglehead at gmail.com>
Date: Mon, 18 May 2009 20:50:43 +0400
Subject: Handle mouse selections more accurately

---
 dlls/comctl32/listview.c |   46 ++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index e94d389..ce78224 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -293,6 +293,7 @@ typedef struct tagLISTVIEW_INFO
   HWND hwndEdit;
   WNDPROC EditWndProc;
   INT nEditLabelItem;
+  INT nLButtonDownItem;		/* tracks item to reset multiselection on WM_LBUTTONUP */
   DWORD dwHoverTime;
   HWND hwndToolTip;
 
@@ -3388,6 +3389,7 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
     {
         POINT tmp;
         RECT rect;
+        LVHITTESTINFO lvHitTestInfo;
         WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
         WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
 
@@ -3399,11 +3401,33 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
         tmp.x = x;
         tmp.y = y;
 
+        lvHitTestInfo.pt = tmp;
+        LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
+
+        /* reset item marker */
+        if (infoPtr->nLButtonDownItem != lvHitTestInfo.iItem)
+            infoPtr->nLButtonDownItem = -1;
+
         if (!PtInRect(&rect, tmp))
         {
-            LVHITTESTINFO lvHitTestInfo;
             NMLISTVIEW nmlv;
 
+            /* this path covers the following:
+               1. WM_LBUTTONDOWN over selected item (sets focus on it)
+               2. change focus with keys
+               3. move mouse over item from step 1 selects it and moves focus on it */
+            if (infoPtr->nLButtonDownItem != -1 &&
+               !LISTVIEW_GetItemState(infoPtr, infoPtr->nLButtonDownItem, LVIS_SELECTED))
+            {
+                LVITEMW lvItem;
+
+                lvItem.state =  LVIS_FOCUSED | LVIS_SELECTED;
+                lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
+
+                LISTVIEW_SetItemState(infoPtr, infoPtr->nLButtonDownItem, &lvItem);
+                infoPtr->nLButtonDownItem = -1;
+            }
+
             lvHitTestInfo.pt = infoPtr->ptClickPos;
             LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
 
@@ -3420,8 +3444,6 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
             return 0;
         }
     }
-    else
-        infoPtr->bLButtonDown = FALSE;
 
     /* see if we are supposed to be tracking mouse hovering */
     if (LISTVIEW_isHotTracking(infoPtr)) {
@@ -8144,6 +8166,7 @@ static LRESULT LISTVIEW_NCCreate(HWND hwnd, const CREATESTRUCTW *lpcs)
   infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
   infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
   infoPtr->nEditLabelItem = -1;
+  infoPtr->nLButtonDownItem = -1;
   infoPtr->dwHoverTime = -1; /* default system hover time */
   infoPtr->nMeasureItemHeight = 0;
   infoPtr->xTrackLine = -1;  /* no track line */
@@ -8835,10 +8858,15 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN
       else
       {
 	if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
+	{
 	  infoPtr->nEditLabelItem = nItem;
+	  infoPtr->nLButtonDownItem = nItem;
 
-	/* set selection (clears other pre-existing selections) */
-        LISTVIEW_SetSelection(infoPtr, nItem);
+          LISTVIEW_SetItemFocus(infoPtr, nItem);
+	}
+	else
+	  /* set selection (clears other pre-existing selections) */
+	  LISTVIEW_SetSelection(infoPtr, nItem);
       }
     }
 
@@ -8848,7 +8876,8 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN
   else
   {
     /* remove all selections */
-    LISTVIEW_DeselectAll(infoPtr);
+    if (!(wKey & MK_CONTROL) && !(wKey & MK_SHIFT))
+        LISTVIEW_DeselectAll(infoPtr);
     ReleaseCapture();
   }
   
@@ -8885,6 +8914,11 @@ static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT
     /* set left button flag */
     infoPtr->bLButtonDown = FALSE;
 
+    /* set a single selection, reset others */
+    if(lvHitTestInfo.iItem == infoPtr->nLButtonDownItem && lvHitTestInfo.iItem != -1)
+        LISTVIEW_SetSelection(infoPtr, infoPtr->nLButtonDownItem);
+    infoPtr->nLButtonDownItem = -1;
+
     if (infoPtr->bDragging)
     {
         infoPtr->bDragging = FALSE;
-- 
1.5.6.5





More information about the wine-patches mailing list