Listview M13
Dimitrie O. Paun
dpaun at rogers.com
Wed Oct 9 12:57:57 CDT 2002
The 'we like speed too' patch. This is getting exciting :)
ChangeLog
Draw _only_ the items that are invalidated
Fix serious bug when deleting from a range
Pass in a range to the ranges_{add,del} functions
Tidy up the RefreshIcon function
Assorted cleanups.
--- dlls/comctl32/listview.c.M12 Wed Oct 9 11:05:12 2002
+++ dlls/comctl32/listview.c Wed Oct 9 13:53:06 2002
@@ -272,6 +272,7 @@
static void LISTVIEW_AlignTop(LISTVIEW_INFO *);
static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *, INT);
static INT LISTVIEW_GetItemHeight(LISTVIEW_INFO *);
+static BOOL LISTVIEW_GetItemListOrigin(LISTVIEW_INFO *, INT, LPPOINT);
static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *, INT, LPPOINT);
static BOOL LISTVIEW_GetItemRect(LISTVIEW_INFO *, INT, LPRECT);
static INT LISTVIEW_CalculateMaxWidth(LISTVIEW_INFO *);
@@ -718,7 +719,9 @@
/******** Item iterator functions **********************************/
-static BOOL iterator_create_frameditems(ITERATOR*, LISTVIEW_INFO*, const RECT*, HRGN);
+static BOOL ranges_add(HDPA ranges, RANGE range);
+static BOOL ranges_del(HDPA ranges, RANGE range);
+static void ranges_dump(HDPA ranges);
static inline BOOL iterator_next(ITERATOR* i)
{
@@ -757,51 +760,25 @@
if (i->ranges) DPA_Destroy(i->ranges);
}
-static inline BOOL iterator_create_empty(ITERATOR* i)
+static inline BOOL iterator_empty(ITERATOR* i)
{
ZeroMemory(i, sizeof(*i));
i->nItem = i->range.lower = i->range.upper = -1;
return TRUE;
}
-static inline BOOL iterator_create_visibleitems(ITERATOR* i, LISTVIEW_INFO *infoPtr)
-{
- return iterator_create_frameditems(i, infoPtr, &infoPtr->rcList, 0);
-}
-
-static BOOL iterator_create_clippeditems(ITERATOR* i, LISTVIEW_INFO *infoPtr, HDC hdc)
-{
- HRGN rgnClip;
- RECT rcClip;
- INT rgntype;
-
- rgntype = GetClipBox(hdc, &rcClip);
- if (rgntype == NULLREGION)
- return iterator_create_empty(i);
- if (rgntype == SIMPLEREGION)
- rgnClip = 0;
- else
- {
- FIXME("TODO: complex clipped region!\n");
- rgnClip = 0;
- }
- return iterator_create_frameditems(i, infoPtr, &rcClip, rgnClip);
-}
-
-static BOOL iterator_create_frameditems(ITERATOR* i, LISTVIEW_INFO* infoPtr, const RECT* lprc, HRGN rgn)
+static BOOL iterator_frameditems(ITERATOR* i, LISTVIEW_INFO* infoPtr, const RECT* lprc)
{
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
INT nPerCol, nPerRow;
- if (rgn) FIXME("Don't know how to handle regions yet.\n");
-
/* in case we fail, we want to return an empty iterator */
- if (!iterator_create_empty(i)) return FALSE;
+ if (!iterator_empty(i)) return FALSE;
if (uView == LVS_ICON || uView == LVS_SMALLICON)
{
i->range.lower = 0;
- i->range.upper = infoPtr->nItemCount;
+ i->range.upper = infoPtr->nItemCount - 1;
return TRUE;
}
@@ -813,9 +790,54 @@
else /* uView == LVS_LIST */
nPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left)/infoPtr->nItemWidth, 1);
- i->range.upper = min(i->range.lower + nPerCol * nPerRow, infoPtr->nItemCount);
+ i->range.upper = min(i->range.lower + nPerCol * nPerRow, infoPtr->nItemCount - 1);
return TRUE;
}
+
+static BOOL iterator_clippeditems(ITERATOR* i, LISTVIEW_INFO *infoPtr, HDC hdc)
+{
+ POINT Origin, Position;
+ RECT rcItem, rcClip;
+ INT nItem, 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;
+
+ /* 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))
+ {
+ DPA_Destroy(i->ranges);
+ i->ranges = 0;
+ return TRUE;
+ }
+
+ /* no delete the invisible items from the list */
+ for (nItem = i->range.lower; nItem <= i->range.upper; nItem++)
+ {
+ if (!LISTVIEW_GetItemListOrigin(infoPtr, 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 };
+ ranges_del(i->ranges, item_range);
+ }
+ }
+
+ return TRUE;
+}
+
+static inline BOOL iterator_visibleitems(ITERATOR* i, LISTVIEW_INFO *infoPtr)
+{
+ return iterator_frameditems(i, infoPtr, &infoPtr->rcList);
+}
+
/******** Misc helper functions ************************************/
static inline LRESULT CallWindowProcT(WNDPROC proc, HWND hwnd, UINT uMsg,
@@ -1263,7 +1285,7 @@
{
ITERATOR i;
- iterator_create_visibleitems(&i, infoPtr);
+ iterator_visibleitems(&i, infoPtr);
while(iterator_next(&i))
{
if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED))
@@ -1885,19 +1907,9 @@
}
#if 0
-static void ranges_dump(HDPA ranges)
-{
- INT i;
-
- ERR("Selections are:\n");
- for (i = 0; i < ranges->nItemCount; i++)
- {
- RANGE *selection = DPA_GetPtr(ranges, i);
- ERR(" [%d - %d]\n", selection->lower, selection->upper);
- }
-}
static void LISTVIEW_PrintSelectionRanges(LISTVIEW_INFO *infoPtr)
{
+ ERR("Selections are:\n");
ranges_dump(infoPtr->hdpaSelectionRanges);
}
#endif
@@ -1925,6 +1937,17 @@
return 0;
}
+static void ranges_dump(HDPA ranges)
+{
+ INT i;
+
+ for (i = 0; i < ranges->nItemCount; i++)
+ {
+ RANGE *selection = DPA_GetPtr(ranges, i);
+ ERR(" [%d - %d]\n", selection->lower, selection->upper);
+ }
+}
+
static inline BOOL ranges_contain(HDPA ranges, INT nItem)
{
RANGE srchrng = { nItem, nItem };
@@ -1954,16 +1977,17 @@
return TRUE;
}
-static BOOL ranges_add(HDPA ranges, INT lower, INT upper)
+static BOOL ranges_add(HDPA ranges, RANGE range)
{
RANGE srchrgn;
INT index;
- TRACE("range (%i - %i)\n", lower, upper);
+ TRACE("range=(%i - %i)\n", range.lower, range.upper);
+ if (TRACE_ON(listview)) ranges_dump(ranges);
/* try find overlapping regions first */
- srchrgn.lower = lower - 1;
- srchrgn.upper = upper + 1;
+ srchrgn.lower = range.lower - 1;
+ srchrgn.upper = range.upper + 1;
index = DPA_Search(ranges, &srchrgn, 0, ranges_cmp, 0, 0);
if (index == -1)
@@ -1973,8 +1997,7 @@
/* create the brand new range to insert */
newrgn = (RANGE *)COMCTL32_Alloc(sizeof(RANGE));
if(!newrgn) return FALSE;
- newrgn->lower = lower;
- newrgn->upper = upper;
+ *newrgn = range;
/* figure out where to insert it */
index = DPA_Search(ranges, newrgn, 0, ranges_cmp, 0, DPAS_INSERTAFTER);
@@ -1993,8 +2016,8 @@
TRACE("Merge with index %i (%d - %d)\n",
index, chkrgn->lower, chkrgn->upper);
- chkrgn->lower = min(lower, chkrgn->lower);
- chkrgn->upper = max(upper, chkrgn->upper);
+ chkrgn->lower = min(range.lower, chkrgn->lower);
+ chkrgn->upper = max(range.upper, chkrgn->upper);
TRACE("New range %i (%d - %d)\n",
index, chkrgn->lower, chkrgn->upper);
@@ -2030,17 +2053,15 @@
return TRUE;
}
-static BOOL ranges_del(HDPA ranges, INT lower, INT upper)
+static BOOL ranges_del(HDPA ranges, RANGE range)
{
RANGE remrgn, tmprgn, *chkrgn;
BOOL done = FALSE;
INT index;
- remrgn.lower = lower;
- remrgn.upper = upper;
-
- TRACE("range: (%d - %d)\n", remrgn.lower, remrgn.upper);
-
+ TRACE("range: (%d - %d)\n", range.lower, range.upper);
+
+ remrgn = range;
do
{
index = DPA_Search(ranges, &remrgn, 0, ranges_cmp, 0, 0);
@@ -2066,14 +2087,14 @@
DPA_DeletePtr(ranges, index);
}
/* case 3: overlap upper */
- else if ( (chkrgn->upper < remrgn.upper) &&
+ else if ( (chkrgn->upper <= remrgn.upper) &&
(chkrgn->lower < remrgn.lower) )
{
chkrgn->upper = remrgn.lower - 1;
}
/* case 4: overlap lower */
else if ( (chkrgn->upper > remrgn.upper) &&
- (chkrgn->lower > remrgn.lower) )
+ (chkrgn->lower >= remrgn.lower) )
{
chkrgn->lower = remrgn.upper + 1;
}
@@ -2100,10 +2121,11 @@
*/
static BOOL remove_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only)
{
+ RANGE range = { lower, upper };
LVITEMW lvItem;
INT i;
- if (!ranges_del(infoPtr->hdpaSelectionRanges, lower, upper)) return FALSE;
+ if (!ranges_del(infoPtr->hdpaSelectionRanges, range)) return FALSE;
if (adj_sel_only) return TRUE;
/* reset the selection on items */
@@ -2119,10 +2141,11 @@
*/
static BOOL add_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only)
{
+ RANGE range = { lower, upper };
LVITEMW lvItem;
INT i;
- if (!ranges_add(infoPtr->hdpaSelectionRanges, lower, upper)) return FALSE;
+ if (!ranges_add(infoPtr->hdpaSelectionRanges, range)) return FALSE;
if (adj_sel_only) return TRUE;
/* set the selection on items */
@@ -2394,7 +2417,7 @@
rcSelMark.left = LVIR_BOUNDS;
if (!LISTVIEW_GetItemRect(infoPtr, infoPtr->nSelectionMark, &rcSelMark)) return;
UnionRect(&rcSel, &rcItem, &rcSelMark);
- iterator_create_frameditems(&i, infoPtr, &rcSel, 0);
+ iterator_frameditems(&i, infoPtr, &rcSel);
while(iterator_next(&i))
{
LISTVIEW_GetItemPosition(infoPtr, i.nItem, &ptItem);
@@ -2503,7 +2526,7 @@
ITERATOR i;
RECT rcItem;
- iterator_create_visibleitems(&i, infoPtr);
+ iterator_visibleitems(&i, infoPtr);
while(iterator_next(&i))
{
rcItem.left = LVIR_SELECTBOUNDS;
@@ -3366,7 +3389,7 @@
if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return;
/* figure out what we need to draw */
- iterator_create_clippeditems(&i, infoPtr, hdc);
+ iterator_clippeditems(&i, infoPtr, hdc);
/* send cache hint notification */
if (infoPtr->dwStyle & LVS_OWNERDATA)
@@ -3474,7 +3497,7 @@
oldTa.fgColor = GetTextColor(hdc);
/* figure out what we need to draw */
- iterator_create_clippeditems(&i, infoPtr, hdc);
+ iterator_clippeditems(&i, infoPtr, hdc);
/* a last few bits before we start drawing */
bFullSelected = infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT;
@@ -3571,7 +3594,7 @@
if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return;
/* figure out what we need to draw */
- iterator_create_clippeditems(&i, infoPtr, hdc);
+ iterator_clippeditems(&i, infoPtr, hdc);
while(iterator_next(&i))
{
@@ -3611,20 +3634,20 @@
{
DWORD cditemmode = CDRF_DODEFAULT;
POINT Origin, Position;
- RECT rcItem, rcClip, rcTemp;
- BOOL bDrawFocusedItem = FALSE;
+ RECT rcItem;
ITERATOR i;
- GetClipBox(hdc, &rcClip); /* FIXME: get rid of this */
-
/* Get scroll info once before loop */
if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return;
/* figure out what we need to draw */
- iterator_create_clippeditems(&i, infoPtr, hdc);
+ iterator_clippeditems(&i, infoPtr, hdc);
while(iterator_next(&i))
{
+ if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_FOCUSED))
+ continue;
+
if (!LISTVIEW_GetItemListOrigin(infoPtr, i.nItem, &Position)) continue;
rcItem.left = Position.x;
rcItem.top = Position.y;
@@ -3632,15 +3655,6 @@
rcItem.right = rcItem.left + infoPtr->nItemWidth;
OffsetRect(&rcItem, Origin.x, Origin.y);
- if (!IntersectRect(&rcTemp, &rcItem, &rcClip)) continue;
-
- /* FIXME: move this before the rcItem computation, when we no longer need rcClip */
- if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_FOCUSED))
- {
- bDrawFocusedItem = TRUE;
- continue;
- }
-
if (cdmode & CDRF_NOTIFYITEMDRAW)
cditemmode = notify_customdrawitem (infoPtr, hdc, i.nItem, 0, CDDS_ITEMPREPAINT);
if (cditemmode & CDRF_SKIPDEFAULT) continue;
@@ -3652,20 +3666,19 @@
}
iterator_destroy(&i);
- /* use the 'while' trick so we can break out of the loop */
- while (bDrawFocusedItem)
- {
- if (!LISTVIEW_GetItemMeasures(infoPtr, infoPtr->nFocusedItem, &rcItem, 0, 0, 0)) break;
- if (cdmode & CDRF_NOTIFYITEMDRAW)
- cditemmode = notify_customdrawitem (infoPtr, hdc, infoPtr->nFocusedItem, 0, CDDS_ITEMPREPAINT);
- if (cditemmode & CDRF_SKIPDEFAULT) break;
-
- LISTVIEW_DrawLargeItem(infoPtr, hdc, infoPtr->nFocusedItem, rcItem);
+ /* draw the focused item last, in case it's oversized */
+ if (!LISTVIEW_GetItemMeasures(infoPtr, infoPtr->nFocusedItem, &rcItem, 0, 0, 0)) return;
+ if (!RectVisible(hdc, &rcItem)) return;
+
+ if (cdmode & CDRF_NOTIFYITEMDRAW)
+ cditemmode = notify_customdrawitem (infoPtr, hdc, infoPtr->nFocusedItem, 0, CDDS_ITEMPREPAINT);
+ if (cditemmode & CDRF_SKIPDEFAULT)
+ return;
+
+ LISTVIEW_DrawLargeItem(infoPtr, hdc, infoPtr->nFocusedItem, rcItem);
- if (cditemmode & CDRF_NOTIFYPOSTPAINT)
- notify_customdrawitem(infoPtr, hdc, i.nItem, 0, CDDS_ITEMPOSTPAINT);
- bDrawFocusedItem = FALSE;
- }
+ if (cditemmode & CDRF_NOTIFYPOSTPAINT)
+ notify_customdrawitem(infoPtr, hdc, i.nItem, 0, CDDS_ITEMPOSTPAINT);
}
/***
@@ -5597,7 +5610,7 @@
rcSearch.right = lpht->pt.x + 1;
rcSearch.bottom = lpht->pt.y + 1;
- iterator_create_frameditems(&i, infoPtr, &rcSearch, 0);
+ iterator_frameditems(&i, infoPtr, &rcSearch);
while(iterator_next(&i))
{
if (!LISTVIEW_GetItemMeasures(infoPtr, i.nItem, &rcBounds, 0, 0, 0)) continue;
More information about the wine-patches
mailing list