Owen Rudge : comctl32: Implement highlighting (marquee) selection support in listview.

Alexandre Julliard julliard at winehq.org
Thu Oct 1 09:48:19 CDT 2009


Module: wine
Branch: master
Commit: 69b76a18fb19bd4a6c83f4f05eb942513af970fd
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=69b76a18fb19bd4a6c83f4f05eb942513af970fd

Author: Owen Rudge <orudge at codeweavers.com>
Date:   Wed Sep 30 16:41:23 2009 +0100

comctl32: Implement highlighting (marquee) selection support in listview.

---

 dlls/comctl32/listview.c |  135 ++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 120 insertions(+), 15 deletions(-)

diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index 1c0f58b..eb2dbfb 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -7,6 +7,7 @@
  * Copyright 2001 CodeWeavers Inc.
  * Copyright 2002 Dimitrie O. Paun
  * Copyright 2009 Nikolay Sivov
+ * Copyright 2009 Owen Rudge for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -98,7 +99,6 @@
  *   -- LVN_BEGINSCROLL, LVN_ENDSCROLL
  *   -- LVN_GETINFOTIP
  *   -- LVN_HOTTRACK
- *   -- LVN_MARQUEEBEGIN
  *   -- LVN_SETDISPINFO
  *   -- NM_HOVER
  *   -- LVN_BEGINRDRAG
@@ -248,6 +248,8 @@ typedef struct tagLISTVIEW_INFO
   BOOL bLButtonDown;
   BOOL bRButtonDown;
   BOOL bDragging;
+  BOOL bMarqueeSelect;       /* marquee selection/highlight underway */
+  RECT marqueeRect;
   POINT ptClickPos;         /* point where the user clicked */ 
   BOOL bNoItemMetrics;		/* flags if item metrics are not yet computed */
   INT nItemHeight;
@@ -3605,17 +3607,94 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
         WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
         WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
 
-        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;
 
         lvHitTestInfo.pt = tmp;
         LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
 
+        if (infoPtr->bMarqueeSelect)
+        {
+            LVITEMW item;
+            ITERATOR i;
+
+            if (x > infoPtr->ptClickPos.x)
+            {
+                rect.left = infoPtr->ptClickPos.x;
+                rect.right = x;
+            }
+            else
+            {
+                rect.left = x;
+                rect.right = infoPtr->ptClickPos.x;
+            }
+
+            if (y > infoPtr->ptClickPos.y)
+            {
+                rect.top = infoPtr->ptClickPos.y;
+                rect.bottom = y;
+            }
+            else
+            {
+                rect.top = y;
+                rect.bottom = infoPtr->ptClickPos.y;
+            }
+
+            /* Cancel out the old marquee rectangle and draw the new one */
+            LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeRect);
+
+            /* Invert the items in the old marquee rectangle */
+            iterator_frameditems(&i, infoPtr, &infoPtr->marqueeRect);
+
+            while (iterator_next(&i))
+            {
+                if (i.nItem > -1)
+                {
+                    if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED) == LVIS_SELECTED)
+                        item.state = 0;
+                    else
+                        item.state = LVIS_SELECTED;
+
+                    item.stateMask = LVIS_SELECTED;
+
+                    LISTVIEW_SetItemState(infoPtr, i.nItem, &item);
+                }
+            }
+
+            iterator_destroy(&i);
+
+            CopyRect(&infoPtr->marqueeRect, &rect);
+
+            /* Iterate over the items within our marquee rectangle */
+            iterator_frameditems(&i, infoPtr, &rect);
+
+            while (iterator_next(&i))
+            {
+                if (i.nItem > -1)
+                {
+                    /* If CTRL is pressed, invert. If not, always select the item. */
+                    if ((fwKeys & MK_CONTROL) && (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED)))
+                        item.state = 0;
+                    else
+                        item.state = LVIS_SELECTED;
+
+                    item.stateMask = LVIS_SELECTED;
+
+                    LISTVIEW_SetItemState(infoPtr, i.nItem, &item);
+                }
+            }
+
+            iterator_destroy(&i);
+
+            LISTVIEW_InvalidateRect(infoPtr, &rect);
+            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;
+
         /* reset item marker */
         if (infoPtr->nLButtonDownItem != lvHitTestInfo.iItem)
             infoPtr->nLButtonDownItem = -1;
@@ -3640,17 +3719,31 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN
 
             if (!infoPtr->bDragging)
             {
-                NMLISTVIEW nmlv;
-
                 lvHitTestInfo.pt = infoPtr->ptClickPos;
                 LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE);
 
-                ZeroMemory(&nmlv, sizeof(nmlv));
-                nmlv.iItem = lvHitTestInfo.iItem;
-                nmlv.ptAction = infoPtr->ptClickPos;
+                /* If the click is outside the range of an item, begin a
+                   highlight. If not, begin an item drag. */
+                if (lvHitTestInfo.iItem == -1)
+                {
+                    NMHDR hdr;
+
+                    /* If we're allowing multiple selections, send notification.
+                       If return value is non-zero, cancel. */
+                    if (!(infoPtr->dwStyle & LVS_SINGLESEL) && (notify_hdr(infoPtr, LVN_MARQUEEBEGIN, &hdr) == 0))
+                        infoPtr->bMarqueeSelect = TRUE;
+                }
+                else
+                {
+                    NMLISTVIEW nmlv;
 
-                notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv);
-                infoPtr->bDragging = TRUE;
+                    ZeroMemory(&nmlv, sizeof(nmlv));
+                    nmlv.iItem = lvHitTestInfo.iItem;
+                    nmlv.ptAction = infoPtr->ptClickPos;
+
+                    notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv);
+                    infoPtr->bDragging = TRUE;
+                }
             }
 
             return 0;
@@ -4643,6 +4736,10 @@ enddraw:
     if ((infoPtr->uView == LV_VIEW_DETAILS) && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES)
         LISTVIEW_RefreshReportGrid(infoPtr, hdc);
 
+    /* Draw marquee rectangle if appropriate */
+    if (infoPtr->bMarqueeSelect)
+        DrawFocusRect(hdc, &infoPtr->marqueeRect);
+
     if (cdmode & CDRF_NOTIFYPOSTPAINT)
 	notify_postpaint(infoPtr, &nmlvcd);
 
@@ -9312,6 +9409,7 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, IN
   infoPtr->bLButtonDown = TRUE;
   infoPtr->ptClickPos = pt;
   infoPtr->bDragging = FALSE;
+  infoPtr->bMarqueeSelect = FALSE;
 
   lvHitTestInfo.pt.x = x;
   lvHitTestInfo.pt.y = y;
@@ -9433,9 +9531,16 @@ static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT
         LISTVIEW_SetSelection(infoPtr, infoPtr->nLButtonDownItem);
     infoPtr->nLButtonDownItem = -1;
 
-    if (infoPtr->bDragging)
+    if (infoPtr->bDragging || infoPtr->bMarqueeSelect)
     {
+        /* Remove the marquee rectangle */
+        if (infoPtr->bMarqueeSelect)
+            LISTVIEW_InvalidateRect(infoPtr, &infoPtr->marqueeRect);
+
+        SetRect(&infoPtr->marqueeRect, 0, 0, 0, 0);
+
         infoPtr->bDragging = FALSE;
+        infoPtr->bMarqueeSelect = FALSE;
         return 0;
     }
 




More information about the wine-cvs mailing list