Listview Q4
Dimitrie O. Paun
dpaun at rogers.com
Mon Oct 14 22:02:45 CDT 2002
ChangeLog
No longer compute the ill-defined bounds in GetItemMetrics
Fix a bunch of bug in subitem metrics computation
Properly implement GetSubItemRect in terms of GetItemMetrics
Documenation updates, and code cleanups.
--- dlls/comctl32/listview.c.Q3 Mon Oct 14 20:41:04 2002
+++ dlls/comctl32/listview.c Mon Oct 14 22:57:41 2002
@@ -279,7 +279,6 @@
static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *, INT, LPPOINT);
static BOOL LISTVIEW_GetItemRect(LISTVIEW_INFO *, INT, LPRECT);
static INT LISTVIEW_CalculateMaxWidth(LISTVIEW_INFO *);
-static BOOL LISTVIEW_GetSubItemRect(LISTVIEW_INFO *, INT, LPRECT);
static INT LISTVIEW_GetLabelWidth(LISTVIEW_INFO *, INT);
static LRESULT LISTVIEW_GetColumnWidth(LISTVIEW_INFO *, INT);
static BOOL LISTVIEW_GetOrigin(LISTVIEW_INFO *, LPPOINT);
@@ -1035,6 +1034,17 @@
LISTVIEW_InvalidateRect(infoPtr, &rcBox); \
} while (0)
+#define LISTVIEW_InvalidateSubItem(infoPtr, nItem, nSubItem) do { \
+ POINT Origin, Position; \
+ RECT rcBox; \
+ if (LISTVIEW_GetOrigin(infoPtr, &Origin) && \
+ LISTVIEW_GetItemListOrigin(infoPtr, nItem, &Position) && \
+ Header_GetItemRect(infoPtr->hwndHeader, nSubItem, &rcBox)) { \
+ OffsetRect(&rcBox, Origin.x + Position.x, Origin.y + Position.y); \
+ LISTVIEW_InvalidateRect(infoPtr, &rcBox); \
+ }\
+} while (0)
+
#define LISTVIEW_InvalidateList(infoPtr)\
LISTVIEW_InvalidateRect(infoPtr, NULL)
@@ -1539,17 +1549,24 @@
* expensive. This gives an easy and effective optimization when
* searching (like point inclusion, or rectangle intersection):
* first test against the BOX, and if TRUE, test agains the desired
- * rectangle. These optimizations are coded in:
- * LISTVIEW_PtInRect, and LISTVIEW_IntersectRect
- * use them wherever is appropriate.
+ * rectangle.
+ * If the function does not have all the necessary information
+ * to computed the requested rectangles, will crash with a
+ * failed assertion. This is done so we catch all programming
+ * errors, given that the function is called only from our code.
+ *
+ * We have the following 'special' meanings for a few fields:
+ * * If LVIS_FOCUSED is set, we assume the item has the focus
+ * This is important in ICON mode, where it might get a larger
+ * then usual rectange
+ *
+ * Please note that subitem support works only in REPORT mode.
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
* [I] lpLVItem : item to compute the measures for
* [O] lprcBox : ptr to Box rectangle
* The internal LVIR_BOX rectangle
- * [O] lprcBounds : ptr to Bounds rectangle
- * Same as LVM_GETITEMRECT with LVIR_BOUNDS
* [0] lprcState : ptr to State icon rectangle
* The internal LVIR_STATE rectangle
* [O] lprcIcon : ptr to Icon rectangle
@@ -1562,8 +1579,8 @@
* FALSE otherwise
*/
static BOOL LISTVIEW_GetItemMetrics(LISTVIEW_INFO *infoPtr, LVITEMW *lpLVItem,
- LPRECT lprcBox, LPRECT lprcBounds,
- LPRECT lprcState, LPRECT lprcIcon, LPRECT lprcLabel)
+ LPRECT lprcBox, LPRECT lprcState,
+ LPRECT lprcIcon, LPRECT lprcLabel)
{
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
BOOL doState = FALSE, doIcon = FALSE, doLabel = FALSE, oversizedBox = FALSE;
@@ -1573,12 +1590,7 @@
/* Be smart and try to figure out the minimum we have to do */
if (lpLVItem->iSubItem) assert(uView == LVS_REPORT);
- if (lprcBounds)
- {
- if (uView == LVS_REPORT) doIcon = TRUE;
- else doLabel = TRUE;
- }
- if (uView == LVS_ICON && (lprcBox || lprcBounds || lprcLabel))
+ if (uView == LVS_ICON && (lprcBox || lprcLabel))
{
assert((lpLVItem->mask & LVIF_STATE) && (lpLVItem->stateMask & LVIS_FOCUSED));
if (lpLVItem->state & LVIS_FOCUSED) oversizedBox = doLabel = TRUE;
@@ -1680,6 +1692,14 @@
{
SIZE labelSize = { 0, 0 };
+ /* calculate how far to the right can the label strech */
+ Label.right = Box.right;
+ if (uView == LVS_REPORT)
+ {
+ if (lpLVItem->iSubItem == 0 && !Header_GetItemRect(infoPtr->hwndHeader, 0, &Label)) return FALSE;
+ Label.right -= REPORT_MARGINX;
+ }
+
if (lpLVItem->iSubItem || ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && uView == LVS_REPORT))
{
labelSize.cx = infoPtr->nItemWidth;
@@ -1741,7 +1761,7 @@
Label.left = Icon.right;
if (!IsRectEmpty(&Icon) || !IsRectEmpty(&State)) Label.left += IMAGE_PADDING;
Label.top = Box.top;
- Label.right = min(Label.left + labelSize.cx, Box.right - (uView == LVS_REPORT ? REPORT_MARGINX : 0));
+ Label.right = min(Label.left + labelSize.cx, Label.right);
Label.bottom = Label.top + infoPtr->nItemHeight;
}
@@ -1749,26 +1769,12 @@
TRACE(" - label=%s\n", debugrect(&Label));
}
- /***********************************************************/
- /* compute bounds box for the item (ala LVM_GETITEMRECT) */
- /***********************************************************/
- if (lprcBounds)
+ /* Fix the Box if necessary */
+ if (lprcBox)
{
- if (uView == LVS_REPORT)
- {
- lprcBounds->left = infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT ? Box.left : Icon.left;
- lprcBounds->top = Box.top;
- lprcBounds->right = min(lprcBounds->left + infoPtr->nItemWidth, Box.right) - REPORT_MARGINX;
- if (lprcBounds->right < lprcBounds->left) lprcBounds->right = lprcBounds->left;
- lprcBounds->bottom = lprcBounds->top + infoPtr->nItemHeight;
- }
- else
- UnionRect(lprcBounds, &Icon, &Label);
- TRACE(" - bounds=%s\n", debugrect(lprcBounds));
+ if (oversizedBox) UnionRect(lprcBox, &Box, &Label);
+ else *lprcBox = Box;
}
-
- if (oversizedBox) UnionRect(lprcBox, &Box, &Label);
- else if (lprcBox) *lprcBox = Box;
TRACE(" - box=%s\n", debugrect(&Box));
return TRUE;
@@ -1812,7 +1818,7 @@
lvItem.stateMask = LVIS_FOCUSED;
lvItem.state = (lvItem.mask & LVIF_TEXT ? LVIS_FOCUSED : 0);
}
- if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprcBox, 0, 0, 0, 0)) return FALSE;
+ if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprcBox, 0, 0, 0)) return FALSE;
OffsetRect(lprcBox, Position.x + Origin.x, Position.y + Origin.y);
@@ -3020,6 +3026,7 @@
*/
static BOOL set_sub_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
{
+ UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
HDPA hdpaSubItems;
LISTVIEW_SUBITEM *lpSubItem;
BOOL bModified = FALSE;
@@ -3073,17 +3080,8 @@
bModified = TRUE;
}
- if (bModified && !infoPtr->bIsDrawing)
- {
- RECT rect;
-
- rect.left = LVIR_BOUNDS;
- rect.top = lpLVItem->iSubItem;
- /* GetSubItemRect will fail in non-report mode, so there's
- * gonna be no invalidation then, yay! */
- if (LISTVIEW_GetSubItemRect(infoPtr, lpLVItem->iItem, &rect))
- LISTVIEW_InvalidateRect(infoPtr, &rect);
- }
+ if (bModified && !infoPtr->bIsDrawing && uView == LVS_REPORT)
+ LISTVIEW_InvalidateSubItem(infoPtr, lpLVItem->iItem, lpLVItem->iSubItem);
return TRUE;
}
@@ -3143,14 +3141,7 @@
if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT &&
!(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) &&
!(infoPtr->dwStyle & LVS_OWNERDRAWFIXED))
- {
- RECT rect;
-
- rect.left = LVIR_BOUNDS;
- rect.top = 0;
- if (LISTVIEW_GetSubItemRect(infoPtr, lpLVItem->iItem, &rect))
- LISTVIEW_InvalidateRect(infoPtr, &rect);
- }
+ LISTVIEW_InvalidateSubItem(infoPtr, lpLVItem->iItem, lpLVItem->iSubItem);
else
LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem);
}
@@ -3267,7 +3258,7 @@
HIMAGELIST himl;
LVITEMW lvItem;
- TRACE("(hdc=%x, nItem=%d)\n", hdc, nItem);
+ TRACE("(hdc=%x, nItem=%d, nSubItem=%d, pos=%s)\n", hdc, nItem, nSubItem, debugpoint(&pos));
/* get information needed for drawing the item */
lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
@@ -3285,11 +3276,13 @@
lprcFocus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0;
if (!lprcFocus) lvItem.state &= ~LVIS_FOCUSED;
- if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, NULL, &rcState, &rcIcon, &rcLabel)) return FALSE;
+ if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, &rcState, &rcIcon, &rcLabel)) return FALSE;
OffsetRect(&rcBox, pos.x, pos.y);
OffsetRect(&rcState, pos.x, pos.y);
OffsetRect(&rcIcon, pos.x, pos.y);
OffsetRect(&rcLabel, pos.x, pos.y);
+ TRACE(" rcBox=%s, rcState=%s, rcIcon=%s. rcLabel=%s\n",
+ debugrect(&rcBox), debugrect(&rcState), debugrect(&rcIcon), debugrect(&rcLabel));
customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBox, &lvItem);
if (cdmode & CDRF_NOTIFYITEMDRAW)
@@ -3342,10 +3335,11 @@
LISTVIEW_GetColumnT(infoPtr, nSubItem, &lvColumn, TRUE);
TRACE("lvColumn=%s\n", debuglvcolumn_t(&lvColumn, TRUE));
if (lvColumn.fmt & LVCFMT_RIGHT) align = DT_RIGHT;
- else if (lvColumn.fmt & LVCFMT_CENTER)align = DT_CENTER;
+ else if (lvColumn.fmt & LVCFMT_CENTER) align = DT_CENTER;
}
uFormat |= align;
}
+ if (!(uFormat & (DT_RIGHT | DT_CENTER))) rcLabel.left += 2;
DrawTextW(hdc, lvItem.pszText, -1, &rcLabel, uFormat);
postpaint:
@@ -5018,25 +5012,25 @@
lvItem.state = (oversizedBox ? LVIS_FOCUSED : 0);
}
+ if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && lprc->left == LVIR_SELECTBOUNDS)
+ lprc->left = LVIR_BOUNDS;
switch(lprc->left)
{
case LVIR_ICON:
- if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, NULL, lprc, NULL)) return FALSE;
+ if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL)) return FALSE;
break;
case LVIR_LABEL:
- if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, NULL, NULL, lprc)) return FALSE;
+ if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, NULL, lprc)) return FALSE;
break;
case LVIR_BOUNDS:
- if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, lprc, NULL, NULL, NULL)) return FALSE;
+ if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL)) return FALSE;
break;
case LVIR_SELECTBOUNDS:
- if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, lprc, NULL, NULL, &label_rect)) return FALSE;
- if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT &&
- !(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) )
- lprc->right = label_rect.right;
+ if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, &label_rect)) return FALSE;
+ UnionRect(lprc, lprc, &label_rect);
break;
default:
@@ -5060,11 +5054,9 @@
* [IO] lprc : rectangle to receive the output
* on input, lprc->top = nSubItem
* lprc->left = LVIR_ICON | LVIR_BOUNDS | LVIR_LABEL
- *
- * NOTE: this call is succeeds only for REPORT style listviews.
- * Because we can calculate things much faster in report mode,
- * we're gonna do the calculations inline here, instead of
- * calling functions that do heavy lifting.
+ *
+ * NOTE: for subItem = 0, we should return the bounds of the _entire_ item,
+ * not only those of the first column.
*
* RETURN:
* TRUE: success
@@ -5072,34 +5064,38 @@
*/
static BOOL LISTVIEW_GetSubItemRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc)
{
- POINT ptPosition;
- INT nSubItem, flags;
+ POINT Position, Origin;
+ LVITEMW lvItem;
if (!lprc || (infoPtr->dwStyle & LVS_TYPEMASK) != LVS_REPORT) return FALSE;
- nSubItem = lprc->top;
- flags = lprc->left;
-
- TRACE("(nItem=%d, nSubItem=%d)\n", nItem, nSubItem);
+ TRACE("(nItem=%d, nSubItem=%d)\n", nItem, lprc->top);
- if (!Header_GetItemRect(infoPtr->hwndHeader, nSubItem, lprc)) return FALSE;
- if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &ptPosition)) return FALSE;
- lprc->top = ptPosition.y;
- lprc->bottom = lprc->top + infoPtr->nItemHeight;
+ if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return FALSE;
+ if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &Position)) return FALSE;
- switch(flags)
+ lvItem.mask = lprc->top == 0 ? LVIF_INDENT : 0;
+ lvItem.iItem = nItem;
+ lvItem.iSubItem = lprc->top;
+
+ if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
+ switch(lprc->left)
{
case LVIR_ICON:
- FIXME("Unimplemented LVIR_ICON\n");
- return FALSE;
+ if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL)) return FALSE;
+ break;
+
case LVIR_LABEL:
case LVIR_BOUNDS:
- /* nothing to do here, we're done */
+ if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL)) return FALSE;
break;
+
default:
ERR("Unknown bounds=%d\n", lprc->left);
return FALSE;
- }
+ }
+
+ OffsetRect(lprc, Position.x + Origin.x, Position.y + Origin.y);
return TRUE;
}
@@ -5476,7 +5472,7 @@
{
WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
- RECT rcBounds, rcState, rcIcon, rcLabel, rcSearch;
+ RECT rcBox, rcBounds, rcState, rcIcon, rcLabel, rcSearch;
POINT Origin, Position, opt;
LVITEMW lvItem;
ITERATOR i;
@@ -5526,11 +5522,15 @@
lvItem.cchTextMax = DISP_TEXT_SIZE;
if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return -1;
- if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, 0, &rcBounds, &rcState, &rcIcon, &rcLabel)) return -1;
+ if (!LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, &rcState, &rcIcon, &rcLabel)) return -1;
if (!LISTVIEW_GetItemListOrigin(infoPtr, lpht->iItem, &Position)) return -1;
opt.x = lpht->pt.x - Position.x - Origin.x;
opt.y = lpht->pt.y - Position.y - Origin.y;
+ if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT))
+ rcBounds = rcBox;
+ else
+ UnionRect(&rcBounds, &rcIcon, &rcLabel);
if (!PtInRect(&rcBounds, opt)) return -1;
if (PtInRect(&rcIcon, opt))
More information about the wine-patches
mailing list