Listview Q1
Dimitrie O. Paun
dpaun at rogers.com
Mon Oct 14 13:02:23 CDT 2002
ChangeLog
Fix iterators to properly deal with LVS_{,SMALL}ICON modes
Unify the Refresh{List,Icon} functions
Simplify HitTest to make full use of the iterators
Fix selection bounds in HitTest
Avoid empty default to silence warning in gcc 3.2.
--- dlls/comctl32/listview.c.Q0 Sat Oct 12 11:42:11 2002
+++ dlls/comctl32/listview.c Mon Oct 14 13:55:47 2002
@@ -882,8 +882,8 @@
static BOOL iterator_frameditems(ITERATOR* i, LISTVIEW_INFO* infoPtr, const RECT* lprc)
{
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
- INT lower, upper;
- RECT frame = *lprc;
+ RECT frame = *lprc, rcItem, rcTemp;
+ INT lower, upper, nItem;
POINT Origin;
/* in case we fail, we want to return an empty iterator */
@@ -895,9 +895,25 @@
if (uView == LVS_ICON || uView == LVS_SMALLICON)
{
- /* FIXME: we got to do better then this */
- i->range.lower = 0;
- i->range.upper = infoPtr->nItemCount - 1;
+ if (uView == LVS_ICON)
+ {
+ if (LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcItem) && IntersectRect(&rcTemp, &rcItem, lprc))
+ i->nSpecial = infoPtr->nFocusedItem;
+ }
+ if (!(i->ranges = DPA_Create(50))) return FALSE;
+ /* to do better here, we need to have PosX, and PosY sorted */
+ for (nItem = 0; nItem < infoPtr->nItemCount; nItem++)
+ {
+ rcItem.left = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
+ rcItem.top = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
+ rcItem.right = rcItem.left + infoPtr->nItemWidth;
+ rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
+ if (IntersectRect(&rcTemp, &rcItem, &frame))
+ {
+ RANGE item_range = { nItem, nItem };
+ ranges_add(i->ranges, item_range);
+ }
+ }
return TRUE;
}
else if (uView == LVS_REPORT)
@@ -933,37 +949,45 @@
{
POINT Origin, Position;
RECT rcItem, rcClip;
- INT nItem, rgntype;
+ INT rgntype;
rgntype = GetClipBox(hdc, &rcClip);
if (rgntype == NULLREGION) return iterator_empty(i);
if (!iterator_frameditems(i, infoPtr, &rcClip)) return FALSE;
if (rgntype == SIMPLEREGION) return TRUE;
+ /* first deal with the special item */
+ if (LISTVIEW_GetItemBox(infoPtr, i->nSpecial, &rcItem) && !RectVisible(hdc, &rcItem))
+ i->nSpecial = -1;
+
/* if we can't deal with the region, we'll just go with the simple range */
if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return TRUE;
- if (!(i->ranges = DPA_Create(10))) return TRUE;
- if (!ranges_add(i->ranges, i->range))
+ if (!i->ranges)
{
- DPA_Destroy(i->ranges);
- i->ranges = 0;
- return TRUE;
+ if (!(i->ranges = DPA_Create(50))) return TRUE;
+ if (!ranges_add(i->ranges, i->range))
+ {
+ DPA_Destroy(i->ranges);
+ i->ranges = 0;
+ return TRUE;
+ }
}
/* now delete the invisible items from the list */
- for (nItem = i->range.lower; nItem <= i->range.upper; nItem++)
+ while(iterator_next(i))
{
- if (!LISTVIEW_GetItemListOrigin(infoPtr, nItem, &Position)) continue;
+ if (!LISTVIEW_GetItemListOrigin(infoPtr, i->nItem, &Position)) continue;
rcItem.left = Position.x + Origin.x;
rcItem.top = Position.y + Origin.y;
rcItem.right = rcItem.left + infoPtr->nItemWidth;
rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
if (!RectVisible(hdc, &rcItem))
{
- RANGE item_range = { nItem, nItem };
+ RANGE item_range = { i->nItem, i->nItem };
ranges_del(i->ranges, item_range);
}
}
+ /* the iterator should restart on the next iterator_next */
return TRUE;
}
@@ -1461,6 +1485,8 @@
{
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
+ if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE;
+
if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
{
lpptPosition->x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
@@ -3538,54 +3564,6 @@
iterator_destroy(&i);
}
-/***
- * DESCRIPTION:
- * Draws listview items when in icon or small icon display mode.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] hdc : device context handle
- * [I] cdmode : custom draw mode
- *
- * RETURN:
- * None
- */
-static void LISTVIEW_RefreshIcon(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
-{
- POINT Origin, Position;
- RECT rcBox;
- ITERATOR i;
-
- /* Get scroll info once before loop */
- if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return;
-
- /* figure out what we need to draw */
- iterator_visibleitems(&i, infoPtr, hdc);
-
- while(iterator_prev(&i))
- {
- if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_FOCUSED))
- continue;
-
- if (!LISTVIEW_GetItemListOrigin(infoPtr, i.nItem, &Position)) continue;
- Position.x += Origin.x;
- Position.y += Origin.y;
- LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, Position, cdmode);
- }
- iterator_destroy(&i);
-
- /* draw the focused item last, in case it's oversized */
- if (LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcBox) &&
- RectVisible(hdc, &rcBox))
- {
- if (LISTVIEW_GetItemListOrigin(infoPtr, infoPtr->nFocusedItem, &Position))
- {
- Position.x += Origin.x;
- Position.y += Origin.y;
- LISTVIEW_DrawItem(infoPtr, hdc, infoPtr->nFocusedItem, Position, cdmode);
- }
- }
-}
/***
* DESCRIPTION:
@@ -3630,11 +3608,9 @@
LISTVIEW_RefreshOwnerDraw(infoPtr, hdc);
else
{
- if (uView == LVS_ICON)
- LISTVIEW_RefreshIcon(infoPtr, hdc, cdmode);
- else if (uView == LVS_REPORT)
+ if (uView == LVS_REPORT)
LISTVIEW_RefreshReport(infoPtr, hdc, cdmode);
- else /* LVS_LIST or LVS_SMALLICON */
+ else /* LVS_LIST, LVS_ICON or LVS_SMALLICON */
LISTVIEW_RefreshList(infoPtr, hdc, cdmode);
/* if we have a focus rect, draw it */
@@ -4576,6 +4552,7 @@
TRACE("nColumn=%d\n", nColumn);
+ /* we have a 'column' in LIST and REPORT mode only */
switch(infoPtr->dwStyle & LVS_TYPEMASK)
{
case LVS_LIST:
@@ -4586,8 +4563,6 @@
if (Header_GetItemW(infoPtr->hwndHeader, nColumn, &hdi))
nColumnWidth = hdi.cxy;
break;
- default:
- /* we don't have a 'column' in [SMALL]ICON mode */
}
TRACE("nColumnWidth=%d\n", nColumnWidth);
@@ -5524,9 +5499,10 @@
{
WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
- RECT rcBounds, rcState, rcIcon, rcLabel;
+ RECT rcBounds, rcState, rcIcon, rcLabel, rcSearch;
POINT Origin, Position, opt;
LVITEMW lvItem;
+ ITERATOR i;
TRACE("(pt=%s, subitem=%d, select=%d)\n", debugpoint(&lpht->pt), subitem, select);
@@ -5551,49 +5527,16 @@
if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return -1;
/* first deal with the large items */
- if (uView == LVS_ICON && PtInRect (&infoPtr->rcFocus, lpht->pt))
- {
- lpht->iItem = infoPtr->nFocusedItem;
- }
- else
- {
- if (uView == LVS_ICON || uView == LVS_SMALLICON)
- {
- RECT rcSearch;
- ITERATOR i;
-
- rcSearch.left = lpht->pt.x - infoPtr->nItemWidth;
- rcSearch.top = lpht->pt.y - infoPtr->nItemHeight;
- rcSearch.right = lpht->pt.x + 1;
- rcSearch.bottom = lpht->pt.y + 1;
-
- iterator_frameditems(&i, infoPtr, &rcSearch);
- while(iterator_next(&i))
- {
- if (!LISTVIEW_GetItemBox(infoPtr, i.nItem, &rcBounds)) continue;
- if (PtInRect(&rcBounds, lpht->pt)) break;
- }
- lpht->iItem = i.nItem;
- iterator_destroy(&i);
- }
- else
- {
- INT nPerCol = (uView == LVS_REPORT) ? infoPtr->nItemCount : LISTVIEW_GetCountPerColumn(infoPtr);
-
- Position.x = lpht->pt.x - Origin.x;
- Position.y = lpht->pt.y - Origin.y;
- TRACE("Position=%s, nPerCol=%d, nItemHeight=%d, nColHeight=%d\n",
- debugpoint(&Position), nPerCol, infoPtr->nItemHeight, nPerCol * infoPtr->nItemHeight);
-
- if (Position.y < nPerCol * infoPtr->nItemHeight)
- {
- lpht->iItem = (Position.x / infoPtr->nItemWidth) * nPerCol + (Position.y / infoPtr->nItemHeight);
- TRACE("iItem=%d\n", lpht->iItem);
- if (lpht->iItem < 0 || lpht->iItem >= infoPtr->nItemCount) lpht->iItem = -1;
- }
- }
- }
-
+ 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 */
+ lpht->iItem = i.nItem;
+ iterator_destroy(&i);
+
if (lpht->iItem == -1) return -1;
lvItem.mask = LVIF_STATE | LVIF_TEXT;
@@ -5641,8 +5584,9 @@
if (!select || lpht->iItem == -1) return lpht->iItem;
if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) return lpht->iItem;
-
- return lpht->flags & (LVHT_ONITEMICON | LVHT_ONITEMLABEL) ? lpht->iItem : -1;
+
+ if (uView == LVS_REPORT) UnionRect(&rcBounds, &rcIcon, &rcLabel);
+ return PtInRect(&rcBounds, opt) ? lpht->iItem : -1;
}
More information about the wine-patches
mailing list