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.
This commit is contained in:
Dimitrie O. Paun 2002-10-15 21:03:10 +00:00 committed by Alexandre Julliard
parent 50b4688c7e
commit 3baa344a43
1 changed files with 58 additions and 114 deletions

View File

@ -882,8 +882,8 @@ static inline BOOL iterator_empty(ITERATOR* i)
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 @@ static BOOL iterator_frameditems(ITERATOR* i, LISTVIEW_INFO* infoPtr, const RECT
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 @@ static BOOL iterator_visibleitems(ITERATOR* i, LISTVIEW_INFO *infoPtr, HDC hdc)
{
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 @@ static BOOL LISTVIEW_GetItemListOrigin(LISTVIEW_INFO *infoPtr, INT nItem, LPPOIN
{
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 @@ static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
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 @@ static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc)
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 @@ static LRESULT LISTVIEW_GetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn)
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 @@ static LRESULT LISTVIEW_GetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn)
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 @@ static LRESULT LISTVIEW_HitTest(LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht, BO
{
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 @@ static LRESULT LISTVIEW_HitTest(LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht, BO
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 @@ static LRESULT LISTVIEW_HitTest(LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht, BO
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;
}