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