Listbox M12

Dimitrie O. Paun dpaun at rogers.com
Wed Oct 9 10:07:14 CDT 2002


ChangeLog
  Reimplement FindItem (cleaner, faster, more compliant with MSDN).

--- dlls/comctl32/listview.c.M11	Wed Oct  9 09:41:21 2002
+++ dlls/comctl32/listview.c	Wed Oct  9 11:04:48 2002
@@ -267,7 +267,6 @@
  * forward declarations
  */
 static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL);
-static INT LISTVIEW_SuperHitTestItem(LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL, BOOL);
 static BOOL LISTVIEW_GetItemMeasures(LISTVIEW_INFO *, INT, LPRECT, LPRECT, LPRECT, LPRECT);
 static void LISTVIEW_AlignLeft(LISTVIEW_INFO *);
 static void LISTVIEW_AlignTop(LISTVIEW_INFO *);
@@ -4361,45 +4360,6 @@
 
 /***
  * DESCRIPTION:
- * Retrieves the nearest item, given a position and a direction.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] POINT : start position
- * [I] UINT : direction
- *
- * RETURN:
- * Item index if successdful, -1 otherwise.
- */
-static INT LISTVIEW_GetNearestItem(LISTVIEW_INFO *infoPtr, POINT pt, UINT vkDirection)
-{
-    LVHITTESTINFO ht;
-    RECT rcView;
-
-    TRACE("point %ld,%ld, direction %s\n", pt.x, pt.y,
-          (vkDirection == VK_DOWN) ? "VK_DOWN" :
-          ((vkDirection == VK_UP) ? "VK_UP" :
-          ((vkDirection == VK_LEFT) ? "VK_LEFT" : "VK_RIGHT")));
-
-    if (!LISTVIEW_GetViewRect(infoPtr, &rcView)) return -1;
-    
-    if (!LISTVIEW_GetOrigin(infoPtr, &ht.pt)) return -1;
-    
-    ht.pt.x += pt.x;
-    ht.pt.y += pt.y;
-
-    if (vkDirection == VK_DOWN)       ht.pt.y += infoPtr->nItemHeight;
-    else if (vkDirection == VK_UP)    ht.pt.y -= infoPtr->nItemHeight;
-    else if (vkDirection == VK_LEFT)  ht.pt.x -= infoPtr->nItemWidth;
-    else if (vkDirection == VK_RIGHT) ht.pt.x += infoPtr->nItemWidth;
-
-    if (!PtInRect(&rcView, ht.pt)) return -1;
-    
-    return LISTVIEW_SuperHitTestItem(infoPtr, &ht, TRUE, TRUE);
-}
-
-/***
- * DESCRIPTION:
  * Searches for an item with specific characteristics.
  *
  * PARAMETER(S):
@@ -4414,101 +4374,109 @@
 static LRESULT LISTVIEW_FindItemW(LISTVIEW_INFO *infoPtr, INT nStart,
                                   LPLVFINDINFOW lpFindInfo)
 {
-  POINT ptItem;
-  WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
-  LVITEMW lvItem;
-  BOOL bWrap = FALSE;
-  INT nItem = nStart;
-  INT nLast = infoPtr->nItemCount;
+    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
+    WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
+    BOOL bWrap = FALSE, bNearest = FALSE;
+    INT nItem = nStart + 1, nLast = infoPtr->nItemCount, nNearestItem = -1;
+    ULONG xdist, ydist, dist, mindist = 0x7fffffff;
+    POINT Position, Destination;
+    LVITEMW lvItem;
 
-  if ((nItem >= -1) && (lpFindInfo != NULL))
-  {
+    if (!lpFindInfo || nItem < 0) return -1;
+    
     lvItem.mask = 0;
-    if (lpFindInfo->flags & LVFI_PARAM)
-    {
-      lvItem.mask |= LVIF_PARAM;
-    }
-
     if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL))
     {
-      lvItem.mask |= LVIF_TEXT;
-      lvItem.pszText = szDispText;
-      lvItem.cchTextMax = DISP_TEXT_SIZE;
+        lvItem.mask |= LVIF_TEXT;
+        lvItem.pszText = szDispText;
+        lvItem.cchTextMax = DISP_TEXT_SIZE;
     }
 
     if (lpFindInfo->flags & LVFI_WRAP)
-      bWrap = TRUE;
+        bWrap = TRUE;
 
-    if (lpFindInfo->flags & LVFI_NEARESTXY)
+    if ((lpFindInfo->flags & LVFI_NEARESTXY) && 
+	(uView == LVS_ICON || uView ==LVS_SMALLICON))
     {
-      ptItem.x = lpFindInfo->pt.x;
-      ptItem.y = lpFindInfo->pt.y;
+	POINT Origin;
+	
+	FIXME("LVFI_NEARESTXY is slow.\n");
+        if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return -1;
+	Destination.x = lpFindInfo->pt.x + Origin.x;
+	Destination.y = lpFindInfo->pt.y + Origin.y;
+	switch(lpFindInfo->vkDirection)
+	{
+	case VK_DOWN:  Destination.y += infoPtr->nItemHeight; break;
+	case VK_UP:    Destination.y -= infoPtr->nItemHeight; break;
+	case VK_RIGHT: Destination.x += infoPtr->nItemWidth; break;
+	case VK_LEFT:  Destination.x -= infoPtr->nItemWidth; break;
+	case VK_HOME:  Destination.x = Destination.y = 0; break;
+	case VK_END:   Destination.x = infoPtr->rcView.right; Destination.y = infoPtr->rcView.bottom; break;
+	case VK_NEXT:  Destination.y += infoPtr->rcList.bottom - infoPtr->rcList.top; break;
+	case VK_PRIOR: Destination.y -= infoPtr->rcList.bottom - infoPtr->rcList.top; break;
+	default: FIXME("Unknown vkDirection=%d\n", lpFindInfo->vkDirection);
+	}
+	bNearest = TRUE;
     }
 
-    while (1)
+    /* if LVFI_PARAM is specified, all other flags are ignored */
+    if (lpFindInfo->flags & LVFI_PARAM)
     {
-      while (nItem < nLast)
-      {
-        if (lpFindInfo->flags & LVFI_NEARESTXY)
-        {
-          nItem = LISTVIEW_GetNearestItem(infoPtr, ptItem,
-                                          lpFindInfo->vkDirection);
-          if (nItem != -1)
-          {
-            /* get position of the new item index */
-            if (!ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &ptItem))
-              return -1;
-          }
-          else
-            return -1;
-        }
-        else
-        {
-          nItem++;
-        }
+        lvItem.mask |= LVIF_PARAM;
+	bNearest = FALSE;
+	lvItem.mask &= ~LVIF_TEXT;
+    }
 
+again:
+    for (; nItem < nLast; nItem++)
+    {
         lvItem.iItem = nItem;
         lvItem.iSubItem = 0;
-        if (LISTVIEW_GetItemW(infoPtr, &lvItem))
-        {
-          if (lvItem.mask & LVIF_TEXT)
-          {
+        if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue;
+
+	if (lvItem.mask & LVIF_PARAM && lpFindInfo->lParam == lvItem.lParam)
+	    return nItem;
+	
+        if (lvItem.mask & LVIF_TEXT)
+	{
             if (lpFindInfo->flags & LVFI_PARTIAL)
             {
-              if (strstrW(lvItem.pszText, lpFindInfo->psz) == NULL)
-                continue;
+            	if (strstrW(lvItem.pszText, lpFindInfo->psz) == NULL) continue;
             }
             else
             {
-              if (lstrcmpW(lvItem.pszText, lpFindInfo->psz) != 0)
-                continue;
+            	if (lstrcmpW(lvItem.pszText, lpFindInfo->psz) != 0) continue;
             }
-          }
+	}
 
-          if (lvItem.mask & LVIF_PARAM)
-          {
-            if (lpFindInfo->lParam != lvItem.lParam)
-              continue;
-          }
+        if (!bNearest) return nItem;
+	
+	/* This is very inefficient. To do a good job here,
+	 * we need a sorted array of (x,y) item positions */
+	if (!LISTVIEW_GetItemListOrigin(infoPtr, nItem, &Position)) continue;
+
+	/* compute the distance^2 to the destination */
+	xdist = Destination.x - Position.x;
+	ydist = Destination.y - Position.y;
+	dist = xdist * xdist + ydist * ydist;
 
-          return nItem;
-        }
-      }
+	/* remember the distance, and item if it's closer */
+	if (dist < mindist)
+	{
+	    mindist = dist;
+	    nNearestItem = nItem;
+	}
+    }
 
-      if (bWrap)
-      {
-        nItem = -1;
-        nLast = nStart + 1;
+    if (bWrap)
+    {
+        nItem = 0;
+        nLast = min(nStart + 1, infoPtr->nItemCount);
         bWrap = FALSE;
-      }
-      else
-      {
-        return -1;
-      }
+	goto again;
     }
-  }
 
- return -1;
+    return nNearestItem;
 }
 
 /***
@@ -5568,124 +5536,6 @@
     return stringSize.cx;
 }
 
-
-/***
- * DESCRIPTION:
- * Determines item if a hit or closest if not
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [IO] lpht : hit test information
- * [I] subitem : fill out iSubItem.
- * [I] bNearItem : return the nearest item
- *
- * RETURN:
- *   SUCCESS : item index of hit
- *   FAILURE : -1
- */
-static INT LISTVIEW_SuperHitTestItem(LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht, BOOL subitem, BOOL bNearItem)
-{
-  LONG lStyle = infoPtr->dwStyle;
-  UINT uView = lStyle & LVS_TYPEMASK;
-  INT i,j,topindex,bottomindex,nearestItem;
-  RECT rcItem,rcSubItem;
-  DWORD xterm, yterm, dist, mindist;
-
-  TRACE("(lpht->pt=%s, subitem=%d\n", debugpoint(&lpht->pt), subitem);
-
-  nearestItem = -1;
-  mindist = -1;
-  
-  /* FIXME: get the visible range */
-  topindex = LISTVIEW_GetTopIndex(infoPtr);
-  if (uView == LVS_REPORT)
-  {
-    bottomindex = topindex + LISTVIEW_GetCountPerColumn(infoPtr) + 1;
-    bottomindex = min(bottomindex,infoPtr->nItemCount);
-  }
-  else
-  {
-    bottomindex = infoPtr->nItemCount;
-  }
-
-  /* FIXME iter */
-  for (i = topindex; i < bottomindex; i++)
-  {
-    rcItem.left = LVIR_BOUNDS;
-    if (LISTVIEW_GetItemRect(infoPtr, i, &rcItem))
-    {
-      if (PtInRect(&rcItem, lpht->pt))
-      {
-        rcSubItem = rcItem;
-        rcItem.left = LVIR_ICON;
-        if (LISTVIEW_GetItemRect(infoPtr, i, &rcItem))
-        {
-          if (PtInRect(&rcItem, lpht->pt))
-          {
-            lpht->flags = LVHT_ONITEMICON;
-            lpht->iItem = i;
-            goto set_subitem;
-          }
-        }
-
-        rcItem.left = LVIR_LABEL;
-        if (LISTVIEW_GetItemRect(infoPtr, i, &rcItem))
-        {
-          if (PtInRect(&rcItem, lpht->pt))
-          {
-            lpht->flags = LVHT_ONITEMLABEL;
-            lpht->iItem = i;
-            goto set_subitem;
-          }
-        }
-
-        lpht->flags = LVHT_ONITEMSTATEICON;
-        lpht->iItem = i;
-       set_subitem:
-        if (subitem)
-        {
-	  INT nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
-          lpht->iSubItem = 0;
-          rcSubItem.right = rcSubItem.left;
-          for (j = 0; j < nColumnCount; j++)
-          {
-            rcSubItem.left = rcSubItem.right;
-            rcSubItem.right += LISTVIEW_GetColumnWidth(infoPtr, j);
-            if (PtInRect(&rcSubItem, lpht->pt))
-            {
-              lpht->iSubItem = j;
-              break;
-            }
-          }
-        }
-	TRACE("hit on item %d\n", i);
-        return i;
-      }
-      else if (bNearItem)
-      {
-        /*
-         * Now compute distance from point to center of boundary
-         * box. Since we are only interested in the relative
-         * distance, we can skip the nasty square root operation
-         */
-        xterm = rcItem.left + (rcItem.right - rcItem.left)/2 - lpht->pt.x;
-        yterm = rcItem.top + (rcItem.bottom - rcItem.top)/2 - lpht->pt.y;
-        dist = xterm * xterm + yterm * yterm;
-	if (mindist < 0 || dist < mindist)
-	{
-	    mindist = dist;
-	    nearestItem = i;
-	}
-      }
-    }
-  }
-
-  lpht->flags = LVHT_NOWHERE;
-
-  return bNearItem ? nearestItem : -1;
-}
-
-
 /***
  * DESCRIPTION:
  * Determines which listview item is located at the specified position.




More information about the wine-patches mailing list