[1/2] comctl32/listview: Improve hittesting a bit

Nikolay Sivov bunglehead at gmail.com
Tue Jun 30 17:05:26 CDT 2009


Actually hittesting is broking (with this patch too).
In report mode passed coordinates are relative to header bottom line,
not to client rectangle, this is the main problem, but not the
only one I've spoted in some days of testing.
To be continued...

Changelog:
    - Improve hittesting a bit

>From b71513e4c750d9197b4ed07290f38627b67c7ea4 Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <bunglehead at gmail.com>
Date: Wed, 1 Jul 2009 00:40:03 +0400
Subject: Improve hittesting a bit

---
 dlls/comctl32/listview.c       |   72 +++++++++++++++++++++------------------
 dlls/comctl32/tests/listview.c |   18 +++++++++-
 2 files changed, 55 insertions(+), 35 deletions(-)

diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index 7099227..23268c9 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -6798,55 +6798,42 @@ static INT LISTVIEW_HitTest(const LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht,
     lpht->iItem = -1;
     if (subitem) lpht->iSubItem = 0;
 
-    if (infoPtr->rcList.left > lpht->pt.x)
-	lpht->flags |= LVHT_TOLEFT;
-    else if (infoPtr->rcList.right < lpht->pt.x)
-	lpht->flags |= LVHT_TORIGHT;
+    LISTVIEW_GetOrigin(infoPtr, &Origin);
+
+    /* set whole list relation flags */
+    if (subitem && infoPtr->uView == LV_VIEW_DETAILS)
+    {
+        /* LVM_SUBITEMHITTEST checks left bound of possible client area */
+        if (infoPtr->rcList.left > lpht->pt.x && Origin.x < lpht->pt.x)
+	    lpht->flags |= LVHT_TOLEFT;
+    }
+    else
+    {
+	if (infoPtr->rcList.left > lpht->pt.x)
+	    lpht->flags |= LVHT_TOLEFT;
+	else if (infoPtr->rcList.right < lpht->pt.x)
+	    lpht->flags |= LVHT_TORIGHT;
+    }
     
     if (infoPtr->rcList.top > lpht->pt.y)
 	lpht->flags |= LVHT_ABOVE;
     else if (infoPtr->rcList.bottom < lpht->pt.y)
 	lpht->flags |= LVHT_BELOW;
 
-    TRACE("lpht->flags=0x%x\n", lpht->flags);
-    if (lpht->flags) return -1;
-
-    lpht->flags |= LVHT_NOWHERE;
-
-    LISTVIEW_GetOrigin(infoPtr, &Origin);
-   
-    /* first deal with the large items */
-    rcSearch.left = lpht->pt.x;
-    rcSearch.top = lpht->pt.y;
-    rcSearch.right = rcSearch.left + 1;
-    rcSearch.bottom = rcSearch.top + 1;
-    
-    iterator_frameditems(&i, infoPtr, &rcSearch);
-    iterator_next(&i); /* go to first item in the sequence */
-    iItem = i.nItem;
-    iterator_destroy(&i);
-   
-    TRACE("lpht->iItem=%d\n", iItem); 
-    if (iItem == -1) return -1;
-
+    /* even if item is invalid try to find subitem */
     if (infoPtr->uView == LV_VIEW_DETAILS && subitem)
     {
-	RECT  bounds, *pRect;
+	RECT *pRect;
 	INT j;
 
-	/* for top/bottom only */
-	bounds.left = LVIR_BOUNDS;
-	LISTVIEW_GetItemRect(infoPtr, iItem, &bounds);
 	opt.x = lpht->pt.x - Origin.x;
-	opt.y = lpht->pt.y;
 
+	lpht->iSubItem = -1;
 	for (j = 0; j < DPA_GetPtrCount(infoPtr->hdpaColumns); j++)
 	{
 	    pRect = &LISTVIEW_GetColumnInfo(infoPtr, j)->rcHeader;
-	    bounds.left  = pRect->left;
-	    bounds.right = pRect->right;
 
-	    if (PtInRect(&bounds, opt))
+	    if ((opt.x >= pRect->left) && (opt.x < pRect->right))
 	    {
 		lpht->iSubItem = j;
 		break;
@@ -6855,6 +6842,25 @@ static INT LISTVIEW_HitTest(const LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht,
 	TRACE("lpht->iSubItem=%d\n", lpht->iSubItem);
     }
 
+    TRACE("lpht->flags=0x%x\n", lpht->flags);
+    if (lpht->flags) return -1;
+
+    lpht->flags |= LVHT_NOWHERE;
+   
+    /* first deal with the large items */
+    rcSearch.left = lpht->pt.x;
+    rcSearch.top = lpht->pt.y;
+    rcSearch.right = rcSearch.left + 1;
+    rcSearch.bottom = rcSearch.top + 1;
+    
+    iterator_frameditems(&i, infoPtr, &rcSearch);
+    iterator_next(&i); /* go to first item in the sequence */
+    iItem = i.nItem;
+    iterator_destroy(&i);
+
+    TRACE("lpht->iItem=%d\n", iItem); 
+    if (iItem == -1) return -1;
+
     lvItem.mask = LVIF_STATE | LVIF_TEXT;
     if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT;
     lvItem.stateMask = LVIS_STATEIMAGEMASK;
diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c
index 38155b1..d11d9de 100644
--- a/dlls/comctl32/tests/listview.c
+++ b/dlls/comctl32/tests/listview.c
@@ -2684,7 +2684,16 @@ static void test_hittest(void)
     x = pos.x + 150; /* outside column */
     y = pos.y + (bounds.bottom - bounds.top) / 2;
     test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, FALSE, FALSE, __LINE__);
-    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, TRUE, TRUE, TRUE, __LINE__);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
+    /* outside possible client rectangle (to right) */
+    x = pos.x + 500;
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, FALSE, FALSE, __LINE__);
+    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
+    /* subitem returned with -1 item too */
+    x = pos.x + 150;
+    y = -10;
+    test_lvm_subitemhittest(hwnd, x, y, -1, 1, LVHT_NOWHERE, FALSE, FALSE, TRUE, __LINE__);
     /* parent client area is 100x100 by default */
     MoveWindow(hwnd, 0, 0, 300, 100, FALSE);
     x = pos.x + 150; /* outside column */
@@ -2701,7 +2710,12 @@ static void test_hittest(void)
     x = pos.x + 150; /* outside column */
     y = pos.y + (bounds.bottom - bounds.top) / 2;
     test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, FALSE, FALSE, __LINE__);
-    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, TRUE, TRUE, TRUE, __LINE__);
+    test_lvm_subitemhittest(hwnd, x, y, 0, 1, LVHT_ONITEMLABEL, FALSE, FALSE, FALSE, __LINE__);
+    /* outside possible client rectangle (to right) */
+    x = pos.x + 500;
+    y = pos.y + (bounds.bottom - bounds.top) / 2;
+    test_lvm_hittest(hwnd, x, y, -1, LVHT_TORIGHT, FALSE, FALSE, __LINE__);
+    test_lvm_subitemhittest(hwnd, x, y, -1, -1, LVHT_NOWHERE, FALSE, FALSE, FALSE, __LINE__);
     /* try with icons, state icons index is 1 based so at least 2 bitmaps needed */
     himl = ImageList_Create(16, 16, 0, 4, 4);
     ok(himl != NULL, "failed to create imagelist\n");
-- 
1.5.6.5







More information about the wine-patches mailing list