Listvew N5 (Try 2)
Dimitrie O. Paun
dpaun at rogers.com
Thu Oct 10 13:30:16 CDT 2002
This is the good one :)
ChangeLog
Move the custom draw notifications into the Draw.*Item functions.
--- dlls/comctl32/listview.c.N4 Thu Oct 10 13:20:49 2002
+++ dlls/comctl32/listview.c Thu Oct 10 14:26:01 2002
@@ -28,6 +28,7 @@
* -- Drawing optimizations.
* -- Hot item handling.
* -- Expand large item in ICON mode when the cursor is flying over the icon or text.
+ * -- Support CustonDraw options for _WIN32_IE >= 0x560 (see NMLVCUSTOMDRAW docs)
*
* Notifications:
* LISTVIEW_Notify : most notifications from children (editbox and header)
@@ -667,69 +668,27 @@
notify_hdr(infoPtr, LVN_ODCACHEHINT, &nmlv.hdr);
}
-static BOOL notify_customdraw (LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, HDC hdc, RECT rc)
+static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, LISTVIEW_INFO *infoPtr, HDC hdc, LPRECT rcBounds, LVITEMW *lpLVItem)
{
- NMLVCUSTOMDRAW nmlvcd;
-
- TRACE("(dwDrawStage=%lx, hdc=%x, rc=?)\n", dwDrawStage, hdc);
-
- nmlvcd.nmcd.dwDrawStage = dwDrawStage;
- nmlvcd.nmcd.hdc = hdc;
- nmlvcd.nmcd.rc = rc;
- nmlvcd.nmcd.dwItemSpec = 0;
- nmlvcd.nmcd.uItemState = 0;
- nmlvcd.nmcd.lItemlParam = 0;
- nmlvcd.clrText = infoPtr->clrText;
- nmlvcd.clrTextBk = infoPtr->clrBk;
-
- return (BOOL)notify_hdr(infoPtr, NM_CUSTOMDRAW, &nmlvcd.nmcd.hdr);
+ ZeroMemory(lpnmlvcd, sizeof(NMLVCUSTOMDRAW));
+ lpnmlvcd->nmcd.hdc = hdc;
+ lpnmlvcd->nmcd.rc = *rcBounds;
+ if (lpLVItem)
+ {
+ lpnmlvcd->nmcd.dwItemSpec = lpLVItem->iItem;
+ if (lpLVItem->state & LVIS_SELECTED) lpnmlvcd->nmcd.uItemState |= CDIS_SELECTED;
+ if (lpLVItem->state & LVIS_FOCUSED) lpnmlvcd->nmcd.uItemState |= CDIS_FOCUS;
+ if (lpLVItem->iItem == infoPtr->nHotItem) lpnmlvcd->nmcd.uItemState |= CDIS_HOT;
+ lpnmlvcd->nmcd.lItemlParam = lpLVItem->lParam;
+ }
+ lpnmlvcd->clrText = infoPtr->clrText;
+ lpnmlvcd->clrTextBk = infoPtr->clrBk;
}
-/* FIXME: we should inline this where it's called somehow
- * I think we need to pass in the structure
- */
-static BOOL notify_customdrawitem (LISTVIEW_INFO *infoPtr, HDC hdc, UINT iItem, UINT iSubItem, UINT uItemDrawState)
+static inline DWORD notify_customdraw (LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, NMLVCUSTOMDRAW *lpnmlvcd)
{
- NMLVCUSTOMDRAW nmlvcd;
- UINT uItemState;
- RECT itemRect;
- LVITEMW item;
- BOOL bReturn;
-
- item.iItem = iItem;
- item.iSubItem = 0;
- item.mask = LVIF_PARAM;
- if (!LISTVIEW_GetItemT(infoPtr, &item, TRUE)) return FALSE;
-
- uItemState = 0;
-
- if (LISTVIEW_GetItemState(infoPtr, iItem, LVIS_SELECTED)) uItemState |= CDIS_SELECTED;
- if (LISTVIEW_GetItemState(infoPtr, iItem, LVIS_FOCUSED)) uItemState |= CDIS_FOCUS;
- if (iItem == infoPtr->nHotItem) uItemState |= CDIS_HOT;
-
- itemRect.left = LVIR_BOUNDS;
- LISTVIEW_GetItemRect(infoPtr, iItem, &itemRect);
-
- nmlvcd.nmcd.dwDrawStage = CDDS_ITEM | uItemDrawState;
- nmlvcd.nmcd.hdc = hdc;
- nmlvcd.nmcd.rc = itemRect;
- nmlvcd.nmcd.dwItemSpec = iItem;
- nmlvcd.nmcd.uItemState = uItemState;
- nmlvcd.nmcd.lItemlParam = item.lParam;
- nmlvcd.clrText = infoPtr->clrText;
- nmlvcd.clrTextBk = infoPtr->clrBk;
- nmlvcd.iSubItem = iSubItem;
-
- TRACE("drawstage=%lx hdc=%x item=%lx, itemstate=%x, lItemlParam=%lx\n",
- nmlvcd.nmcd.dwDrawStage, nmlvcd.nmcd.hdc, nmlvcd.nmcd.dwItemSpec,
- nmlvcd.nmcd.uItemState, nmlvcd.nmcd.lItemlParam);
-
- bReturn = notify_hdr(infoPtr, NM_CUSTOMDRAW, &nmlvcd.nmcd.hdr);
-
- infoPtr->clrText = nmlvcd.clrText;
- infoPtr->clrBk = nmlvcd.clrTextBk;
-
- return bReturn;
+ lpnmlvcd->nmcd.dwDrawStage = dwDrawStage;
+ return notify_hdr(infoPtr, NM_CUSTOMDRAW, &lpnmlvcd->nmcd.hdr);
}
/******** Item iterator functions **********************************/
@@ -3071,15 +3030,18 @@
* [I] INT : item index
* [I] INT : subitem index
* [I] RECT * : clipping rectangle
+ * [I] cdmode : custom draw mode
*
* RETURN:
* Success: TRUE
* Failure: FALSE
*/
static BOOL LISTVIEW_DrawSubItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem,
- INT nSubItem, RECT rcItem, UINT align)
+ INT nSubItem, RECT rcItem, UINT align, DWORD cdmode)
{
- WCHAR szDispText[DISP_TEXT_SIZE];
+ WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
+ DWORD cditemmode = CDRF_DODEFAULT;
+ NMLVCUSTOMDRAW nmlvcd;
LVITEMW lvItem;
TRACE("(hdc=%x, nItem=%d, nSubItem=%d, rcItem=%s)\n",
@@ -3091,15 +3053,24 @@
lvItem.iSubItem = nSubItem;
lvItem.cchTextMax = DISP_TEXT_SIZE;
lvItem.pszText = szDispText;
- *lvItem.pszText = '\0';
if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
-
TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
+ customdraw_fill(&nmlvcd, infoPtr, hdc, &rcItem, &lvItem);
+ if (cdmode & CDRF_NOTIFYITEMDRAW)
+ cditemmode = notify_customdraw (infoPtr, CDDS_ITEMPREPAINT, &nmlvcd);
+ if (cditemmode & CDRF_SKIPDEFAULT) goto postpaint;
+
+ /* FIXME: set the text attr in here, they may change! */
+
if (lvItem.iImage) FIXME("Draw the image for the subitem\n");
DrawTextW(hdc, lvItem.pszText, -1, &rcItem, LV_SL_DT_FLAGS | align);
+postpaint:
+ if (cditemmode & CDRF_NOTIFYPOSTPAINT)
+ notify_customdraw(infoPtr, CDDS_ITEMPOSTPAINT, &nmlvcd);
+
return TRUE;
}
@@ -3113,16 +3084,19 @@
* [I] hdc : device context handle
* [I] nItem : item index
* [I] rcItem : item rectangle
+ * [I] cdmode : custom draw mode
*
* RETURN:
- * TRUE: if item is focused
- * FALSE: otherwise
+ * Success: TRUE
+ * Failure: FALSE
*/
-static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem)
+static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem, DWORD cdmode)
{
- WCHAR szDispText[DISP_TEXT_SIZE];
+ WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
+ DWORD cditemmode = CDRF_DODEFAULT;
INT nLabelWidth, imagePadding = 0;
RECT* lprcFocus, rcOrig = rcItem;
+ NMLVCUSTOMDRAW nmlvcd;
LVITEMW lvItem;
TEXTATTR ta;
@@ -3135,7 +3109,6 @@
lvItem.iSubItem = 0;
lvItem.cchTextMax = DISP_TEXT_SIZE;
lvItem.pszText = szDispText;
- *lvItem.pszText = '\0';
if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
@@ -3143,6 +3116,11 @@
lprcFocus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0;
if (lprcFocus) SetRectEmpty(lprcFocus);
+ customdraw_fill(&nmlvcd, infoPtr, hdc, &rcItem, &lvItem);
+ if (cdmode & CDRF_NOTIFYITEMDRAW)
+ cditemmode = notify_customdraw (infoPtr, CDDS_ITEMPREPAINT, &nmlvcd);
+ if (cditemmode & CDRF_SKIPDEFAULT) goto postpaint;
+
/* do indent */
rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
@@ -3175,8 +3153,7 @@
}
/* Don't bother painting item being edited */
- if (infoPtr->bEditing && lprcFocus)
- return FALSE;
+ if (infoPtr->bEditing && lprcFocus) goto postpaint;
select_text_attr(infoPtr, hdc, lvItem.state & LVIS_SELECTED, &ta);
@@ -3193,9 +3170,12 @@
ExtTextOutW(hdc, rcItem.left, rcItem.top, ETO_OPAQUE, &rcItem, 0, 0, 0);
DrawTextW(hdc, lvItem.pszText, -1, &rcItem, LV_SL_DT_FLAGS | DT_CENTER);
}
-
set_text_attr(hdc, &ta);
- return lprcFocus != NULL;
+
+postpaint:
+ if (cditemmode & CDRF_NOTIFYPOSTPAINT)
+ notify_customdraw(infoPtr, CDDS_ITEMPOSTPAINT, &nmlvcd);
+ return TRUE;
}
/***
@@ -3206,16 +3186,18 @@
* [I] infoPtr : valid pointer to the listview structure
* [I] hdc : device context handle
* [I] nItem : item index
+ * [I] cdmode : custom draw mode
*
* RETURN:
- * TRUE: if item is focused
- * FALSE: otherwise
+ * Success: TRUE
+ * Failure: FALSE
*/
-static void LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, DWORD cdmode)
+static BOOL LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, DWORD cdmode)
{
WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
DWORD cditemmode = CDRF_DODEFAULT;
- RECT rcIcon, rcLabel, *lprcFocus;
+ RECT rcBounds, rcIcon, rcLabel, *lprcFocus;
+ NMLVCUSTOMDRAW nmlvcd;
LVITEMW lvItem;
UINT uFormat;
TEXTATTR ta;
@@ -3229,18 +3211,23 @@
lvItem.iSubItem = 0;
lvItem.pszText = szDispText;
lvItem.cchTextMax = DISP_TEXT_SIZE;
- if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return;
+ if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
/* now check if we need to update the focus rectangle */
lprcFocus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0;
- if (!LISTVIEW_GetItemMeasures(infoPtr, nItem, NULL, NULL, &rcIcon, &rcLabel)) return;
+ if (!LISTVIEW_GetItemMeasures(infoPtr, nItem, NULL, &rcBounds, &rcIcon, &rcLabel)) return FALSE;
+ customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBounds, &lvItem);
if (cdmode & CDRF_NOTIFYITEMDRAW)
- cditemmode = notify_customdrawitem (infoPtr, hdc, nItem, 0, CDDS_ITEMPREPAINT);
+ cditemmode = notify_customdraw (infoPtr, CDDS_ITEMPREPAINT, &nmlvcd);
if (cditemmode & CDRF_SKIPDEFAULT) goto postpaint;
+ /* FIXME: pass the mnlvcd to select text attr */
+ infoPtr->clrText = nmlvcd.clrText;
+ infoPtr->clrBk = nmlvcd.clrTextBk;
+
/* Set the item to the boundary box for now */
TRACE("rcIcon=%s, rcLabel=%s\n", debugrect(&rcIcon), debugrect(&rcLabel));
@@ -3295,7 +3282,9 @@
postpaint:
if (cditemmode & CDRF_NOTIFYPOSTPAINT)
- notify_customdrawitem(infoPtr, hdc, nItem, 0, CDDS_ITEMPOSTPAINT);
+ notify_customdraw(infoPtr, CDDS_ITEMPOSTPAINT, &nmlvcd);
+
+ return TRUE;
}
/***
@@ -3381,7 +3370,6 @@
INT nColumnCount, nFirstCol, nLastCol;
RECT rcItem, rcClip, rcFullSelect;
BOOL bFullSelected, isFocused;
- DWORD cditemmode = CDRF_DODEFAULT;
TEXTATTR tmpTa, oldTa;
COLUMNCACHE *lpCols;
LVCOLUMNW lvColumn;
@@ -3449,15 +3437,17 @@
{
nDrawPosY = i.nItem * infoPtr->nItemHeight;
+ isFocused = FALSE;
/* compute the full select rectangle, if needed */
if (bFullSelected)
{
item.mask = LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
- item.stateMask = LVIS_SELECTED;
+ item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
item.iItem = i.nItem;
item.iSubItem = 0;
if (!LISTVIEW_GetItemW(infoPtr, &item)) continue;
-
+
+ isFocused = item.state & LVIS_FOCUSED;
rcFullSelect.left = lpCols[0].rc.left + REPORT_MARGINX +
infoPtr->iconSize.cx * item.iIndent +
(infoPtr->himlSmall ? infoPtr->iconSize.cx : 0);
@@ -3473,7 +3463,6 @@
ExtTextOutW(hdc, rcFullSelect.left, rcFullSelect.top, ETO_OPAQUE, &rcFullSelect, 0, 0, 0);
/* iterate through the invalidated columns */
- isFocused = FALSE;
for (j = nFirstCol; j <= nLastCol; j++)
{
rcItem = lpCols[j].rc;
@@ -3487,17 +3476,10 @@
if (rgntype == COMPLEXREGION && !RectVisible(hdc, &rcItem)) continue;
- if (cdmode & CDRF_NOTIFYITEMDRAW)
- cditemmode = notify_customdrawitem (infoPtr, hdc, i.nItem, j, CDDS_ITEMPREPAINT);
- if (cditemmode & CDRF_SKIPDEFAULT) continue;
-
if (j == 0)
- isFocused = LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, rcItem);
+ LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, rcItem, cdmode);
else
- LISTVIEW_DrawSubItem(infoPtr, hdc, i.nItem, j, rcItem, lpCols[j].align);
-
- if (cditemmode & CDRF_NOTIFYPOSTPAINT)
- notify_customdrawitem(infoPtr, hdc, i.nItem, 0, CDDS_ITEMPOSTPAINT);
+ LISTVIEW_DrawSubItem(infoPtr, hdc, i.nItem, j, rcItem, lpCols[j].align, cdmode);
}
/* Adjust focus if we have it, and we are in full select */
@@ -3524,7 +3506,6 @@
*/
static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
{
- DWORD cditemmode = CDRF_DODEFAULT;
POINT Origin, Position;
RECT rcItem;
ITERATOR i;
@@ -3537,10 +3518,6 @@
while(iterator_next(&i))
{
- if (cdmode & CDRF_NOTIFYITEMDRAW)
- cditemmode = notify_customdrawitem (infoPtr, hdc, i.nItem, 0, CDDS_ITEMPREPAINT);
- if (cditemmode & CDRF_SKIPDEFAULT) continue;
-
if (!LISTVIEW_GetItemListOrigin(infoPtr, i.nItem, &Position)) continue;
rcItem.left = Position.x;
rcItem.top = Position.y;
@@ -3548,11 +3525,7 @@
rcItem.right = rcItem.left + infoPtr->nItemWidth;
OffsetRect(&rcItem, Origin.x, Origin.y);
- LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, rcItem);
-
- if (cditemmode & CDRF_NOTIFYPOSTPAINT)
- notify_customdrawitem(infoPtr, hdc, i.nItem, 0, CDDS_ITEMPOSTPAINT);
-
+ LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, rcItem, cdmode);
}
iterator_destroy(&i);
}
@@ -3611,25 +3584,27 @@
static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc)
{
UINT uView = LISTVIEW_GetType(infoPtr);
+ NMLVCUSTOMDRAW nmlvcd;
HFONT hOldFont;
DWORD cdmode;
RECT rcClient;
LISTVIEW_DUMP(infoPtr);
+ infoPtr->bIsDrawing = TRUE;
+
GetClientRect(infoPtr->hwndSelf, &rcClient);
-
- cdmode = notify_customdraw(infoPtr, CDDS_PREPAINT, hdc, rcClient);
- if (cdmode == CDRF_SKIPDEFAULT) return;
+
+ /* select font */
+ hOldFont = SelectObject(hdc, infoPtr->hFont);
- infoPtr->bIsDrawing = TRUE;
+ customdraw_fill(&nmlvcd, infoPtr, hdc, &rcClient, NULL);
+ cdmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd);
+ if (cdmode & CDRF_SKIPDEFAULT) goto enddraw;
/* nothing to draw */
if(infoPtr->nItemCount == 0) goto enddraw;
- /* select font */
- hOldFont = SelectObject(hdc, infoPtr->hFont);
-
if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED)
LISTVIEW_RefreshOwnerDraw(infoPtr, hdc);
else if (uView == LVS_ICON)
@@ -3643,12 +3618,12 @@
if (infoPtr->bFocus && !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED))
DrawFocusRect(hdc, &infoPtr->rcFocus);
- /* unselect objects */
- SelectObject(hdc, hOldFont);
-
enddraw:
if (cdmode & CDRF_NOTIFYPOSTPAINT)
- notify_customdraw(infoPtr, CDDS_POSTPAINT, hdc, rcClient);
+ notify_customdraw(infoPtr, CDDS_POSTPAINT, &nmlvcd);
+
+ /* unselect objects */
+ SelectObject(hdc, hOldFont);
infoPtr->bIsDrawing = FALSE;
}
More information about the wine-patches
mailing list