From fa3e750e2cfc5fe763c2891f5fa47fec2ded43b0 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Sun, 11 May 2014 00:49:27 +0400 Subject: [PATCH] comctl32/listview: Fix custom draw stage sequence. --- dlls/comctl32/listview.c | 319 ++++++++++++++++++++------------- dlls/comctl32/tests/listview.c | 83 +++++++-- 2 files changed, 268 insertions(+), 134 deletions(-) diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c index fa9895d447c..7670f1801f5 100644 --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -6,7 +6,7 @@ * Copyright 2000 Jason Mawdsley * Copyright 2001 CodeWeavers Inc. * Copyright 2002 Dimitrie O. Paun - * Copyright 2009-2013 Nikolay Sivov + * Copyright 2009-2014 Nikolay Sivov * Copyright 2009 Owen Rudge for CodeWeavers * Copyright 2012-2013 Daniel Jelinski * @@ -331,7 +331,6 @@ typedef struct tagLISTVIEW_INFO WCHAR szSearchParam[ MAX_PATH ]; /* painting */ - DWORD cditemmode; /* Keep the custom draw flags for an item/row */ BOOL bIsDrawing; /* Drawing in progress */ INT nMeasureItemHeight; /* WM_MEASUREITEM result */ BOOL bRedraw; /* WM_SETREDRAW switch */ @@ -1052,10 +1051,7 @@ static inline DWORD notify_customdraw (const LISTVIEW_INFO *infoPtr, DWORD dwDra static void prepaint_setup (const LISTVIEW_INFO *infoPtr, HDC hdc, NMLVCUSTOMDRAW *lpnmlvcd, BOOL SubItem) { - if (lpnmlvcd->clrTextBk == CLR_DEFAULT) - lpnmlvcd->clrTextBk = comctl32_color.clrWindow; - if (lpnmlvcd->clrText == CLR_DEFAULT) - lpnmlvcd->clrText = comctl32_color.clrWindowText; + COLORREF backcolor, textcolor; /* apparently, for selected items, we have to override the returned values */ if (!SubItem) @@ -1075,15 +1071,23 @@ static void prepaint_setup (const LISTVIEW_INFO *infoPtr, HDC hdc, NMLVCUSTOMDRA } } + backcolor = lpnmlvcd->clrTextBk; + textcolor = lpnmlvcd->clrText; + + if (backcolor == CLR_DEFAULT) + backcolor = comctl32_color.clrWindow; + if (textcolor == CLR_DEFAULT) + textcolor = comctl32_color.clrWindowText; + /* Set the text attributes */ - if (lpnmlvcd->clrTextBk != CLR_NONE) + if (backcolor != CLR_NONE) { SetBkMode(hdc, OPAQUE); - SetBkColor(hdc,lpnmlvcd->clrTextBk); + SetBkColor(hdc, backcolor); } else SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, lpnmlvcd->clrText); + SetTextColor(hdc, textcolor); } static inline DWORD notify_postpaint (const LISTVIEW_INFO *infoPtr, NMLVCUSTOMDRAW *lpnmlvcd) @@ -4543,87 +4547,28 @@ static inline BOOL LISTVIEW_FillBkgnd(const LISTVIEW_INFO *infoPtr, HDC hdc, con return FillRect(hdc, lprcBox, infoPtr->hBkBrush); } -/*** - * DESCRIPTION: - * Draws an item. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * [I] nItem : item index - * [I] nSubItem : subitem index - * [I] pos : item position in client coordinates - * [I] cdmode : custom draw mode - * - * RETURN: - * Success: TRUE - * Failure: FALSE - */ -static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nSubItem, POINT pos, DWORD cdmode) +/* Draw main item or subitem */ +static void LISTVIEW_DrawItemPart(LISTVIEW_INFO *infoPtr, LVITEMW *item, const NMLVCUSTOMDRAW *nmlvcd, const POINT *pos) { - UINT uFormat; - WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; - static WCHAR szCallback[] = { '(', 'c', 'a', 'l', 'l', 'b', 'a', 'c', 'k', ')', 0 }; - DWORD cdsubitemmode = CDRF_DODEFAULT; - LPRECT lprcFocus; - RECT rcSelect, rcBox, rcIcon, rcLabel, rcStateIcon; - NMLVCUSTOMDRAW nmlvcd; + RECT rcSelect, rcLabel, rcBox, rcStateIcon, rcIcon; HIMAGELIST himl; - LVITEMW lvItem; - - TRACE("(hdc=%p, nItem=%d, nSubItem=%d, pos=%s)\n", hdc, nItem, nSubItem, wine_dbgstr_point(&pos)); - - /* get information needed for drawing the item */ - lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; - if (nSubItem == 0) lvItem.mask |= LVIF_STATE; - if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT; - lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK | LVIS_CUT | LVIS_OVERLAYMASK; - lvItem.iItem = nItem; - lvItem.iSubItem = nSubItem; - lvItem.state = 0; - lvItem.lParam = 0; - lvItem.cchTextMax = DISP_TEXT_SIZE; - lvItem.pszText = szDispText; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; - if (nSubItem > 0 && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) - lvItem.state = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED); - if (lvItem.pszText == LPSTR_TEXTCALLBACKW) lvItem.pszText = szCallback; - TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE)); + UINT format; + RECT *focus; /* now check if we need to update the focus rectangle */ - lprcFocus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0; + focus = infoPtr->bFocus && (item->state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0; + if (!focus) item->state &= ~LVIS_FOCUSED; - if (!lprcFocus) lvItem.state &= ~LVIS_FOCUSED; - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, &rcSelect, &rcIcon, &rcStateIcon, &rcLabel); - OffsetRect(&rcBox, pos.x, pos.y); - OffsetRect(&rcSelect, pos.x, pos.y); - OffsetRect(&rcIcon, pos.x, pos.y); - OffsetRect(&rcStateIcon, pos.x, pos.y); - OffsetRect(&rcLabel, pos.x, pos.y); + LISTVIEW_GetItemMetrics(infoPtr, item, &rcBox, &rcSelect, &rcIcon, &rcStateIcon, &rcLabel); + OffsetRect(&rcBox, pos->x, pos->y); + OffsetRect(&rcSelect, pos->x, pos->y); + OffsetRect(&rcIcon, pos->x, pos->y); + OffsetRect(&rcStateIcon, pos->x, pos->y); + OffsetRect(&rcLabel, pos->x, pos->y); TRACE(" rcBox=%s, rcSelect=%s, rcIcon=%s. rcLabel=%s\n", wine_dbgstr_rect(&rcBox), wine_dbgstr_rect(&rcSelect), wine_dbgstr_rect(&rcIcon), wine_dbgstr_rect(&rcLabel)); - /* fill in the custom draw structure */ - customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBox, &lvItem); - - if (nSubItem > 0) cdmode = infoPtr->cditemmode; - if (cdmode & CDRF_SKIPDEFAULT) goto postpaint; - if (cdmode & CDRF_NOTIFYITEMDRAW) - cdsubitemmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd); - if (nSubItem == 0) infoPtr->cditemmode = cdsubitemmode; - if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint; - /* we have to send a CDDS_SUBITEM customdraw explicitly for subitem 0 */ - if (nSubItem == 0 && (cdsubitemmode & CDRF_NOTIFYITEMDRAW) != 0) - { - cdsubitemmode = notify_customdraw(infoPtr, CDDS_SUBITEM | CDDS_ITEMPREPAINT, &nmlvcd); - if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint; - } - if (nSubItem == 0 || (cdmode & CDRF_NOTIFYITEMDRAW)) - prepaint_setup(infoPtr, hdc, &nmlvcd, FALSE); - else if ((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) == FALSE) - prepaint_setup(infoPtr, hdc, &nmlvcd, TRUE); - /* FIXME: temporary hack */ rcSelect.left = rcLabel.left; @@ -4632,16 +4577,15 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS /* in detail mode, we want to paint background for label rect when * item is not selected or listview has full row select; otherwise paint * background for text only */ - if (infoPtr->uView == LV_VIEW_ICON || - (infoPtr->uView == LV_VIEW_DETAILS && - (!(lvItem.state & LVIS_SELECTED) || - (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) != 0))) + if ( infoPtr->uView == LV_VIEW_ICON || + (infoPtr->uView == LV_VIEW_DETAILS && (!(item->state & LVIS_SELECTED) || + (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)))) rcSelect = rcLabel; - if (nmlvcd.clrTextBk != CLR_NONE) - ExtTextOutW(hdc, rcSelect.left, rcSelect.top, ETO_OPAQUE, &rcSelect, NULL, 0, NULL); + if (nmlvcd->clrTextBk != CLR_NONE) + ExtTextOutW(nmlvcd->nmcd.hdc, rcSelect.left, rcSelect.top, ETO_OPAQUE, &rcSelect, NULL, 0, NULL); - if(nSubItem == 0 && infoPtr->nFocusedItem == nItem) + if (item->state & LVIS_FOCUSED) { if (infoPtr->uView == LV_VIEW_DETAILS && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) { @@ -4653,7 +4597,7 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS if ((leftmost = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX, 0, 0))) { - INT Originx = pos.x - LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left; + INT Originx = pos->x - LISTVIEW_GetColumnInfo(infoPtr, 0)->rcHeader.left; INT index = SendMessageW(infoPtr->hwndHeader, HDM_ORDERTOINDEX, DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, 0); @@ -4670,68 +4614,196 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS } /* state icons */ - if (infoPtr->himlState && STATEIMAGEINDEX(lvItem.state) && (nSubItem == 0)) + if (infoPtr->himlState && STATEIMAGEINDEX(item->state) && (item->iSubItem == 0)) { - UINT uStateImage = STATEIMAGEINDEX(lvItem.state); - if (uStateImage) + UINT stateimage = STATEIMAGEINDEX(item->state); + if (stateimage) { - TRACE("uStateImage=%d\n", uStateImage); - ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, - rcStateIcon.left, rcStateIcon.top, ILD_NORMAL); + TRACE("stateimage=%d\n", stateimage); + ImageList_Draw(infoPtr->himlState, stateimage-1, nmlvcd->nmcd.hdc, rcStateIcon.left, rcStateIcon.top, ILD_NORMAL); } } /* item icons */ himl = (infoPtr->uView == LV_VIEW_ICON ? infoPtr->himlNormal : infoPtr->himlSmall); - if (himl && lvItem.iImage >= 0 && !IsRectEmpty(&rcIcon)) + if (himl && item->iImage >= 0 && !IsRectEmpty(&rcIcon)) { UINT style; - TRACE("iImage=%d\n", lvItem.iImage); + TRACE("iImage=%d\n", item->iImage); - if (lvItem.state & (LVIS_SELECTED | LVIS_CUT) && infoPtr->bFocus) + if (item->state & (LVIS_SELECTED | LVIS_CUT) && infoPtr->bFocus) style = ILD_SELECTED; else style = ILD_NORMAL; - ImageList_DrawEx(himl, lvItem.iImage, hdc, rcIcon.left, rcIcon.top, + ImageList_DrawEx(himl, item->iImage, nmlvcd->nmcd.hdc, rcIcon.left, rcIcon.top, rcIcon.right - rcIcon.left, rcIcon.bottom - rcIcon.top, infoPtr->clrBk, - lvItem.state & LVIS_CUT ? RGB(255, 255, 255) : CLR_DEFAULT, - style | (lvItem.state & LVIS_OVERLAYMASK)); + item->state & LVIS_CUT ? RGB(255, 255, 255) : CLR_DEFAULT, + style | (item->state & LVIS_OVERLAYMASK)); } /* Don't bother painting item being edited */ - if (infoPtr->hwndEdit && nItem == infoPtr->nEditLabelItem && nSubItem == 0) goto postpaint; - + if (infoPtr->hwndEdit && item->iItem == infoPtr->nEditLabelItem && item->iSubItem == 0) return; + /* figure out the text drawing flags */ - uFormat = (infoPtr->uView == LV_VIEW_ICON ? (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS) : LV_SL_DT_FLAGS); + format = (infoPtr->uView == LV_VIEW_ICON ? (focus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS) : LV_SL_DT_FLAGS); if (infoPtr->uView == LV_VIEW_ICON) - uFormat = (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS); - else if (nSubItem) + format = (focus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS); + else if (item->iSubItem) { - switch (LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->fmt & LVCFMT_JUSTIFYMASK) + switch (LISTVIEW_GetColumnInfo(infoPtr, item->iSubItem)->fmt & LVCFMT_JUSTIFYMASK) { - case LVCFMT_RIGHT: uFormat |= DT_RIGHT; break; - case LVCFMT_CENTER: uFormat |= DT_CENTER; break; - default: uFormat |= DT_LEFT; + case LVCFMT_RIGHT: format |= DT_RIGHT; break; + case LVCFMT_CENTER: format |= DT_CENTER; break; + default: format |= DT_LEFT; } } - if (!(uFormat & (DT_RIGHT | DT_CENTER))) + if (!(format & (DT_RIGHT | DT_CENTER))) { - if (himl && lvItem.iImage >= 0 && !IsRectEmpty(&rcIcon)) rcLabel.left += IMAGE_PADDING; + if (himl && item->iImage >= 0 && !IsRectEmpty(&rcIcon)) rcLabel.left += IMAGE_PADDING; else rcLabel.left += LABEL_HOR_PADDING; } - else if (uFormat & DT_RIGHT) rcLabel.right -= LABEL_HOR_PADDING; + else if (format & DT_RIGHT) rcLabel.right -= LABEL_HOR_PADDING; /* for GRIDLINES reduce the bottom so the text formats correctly */ if (infoPtr->uView == LV_VIEW_DETAILS && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES) rcLabel.bottom--; - DrawTextW(hdc, lvItem.pszText, -1, &rcLabel, uFormat); + DrawTextW(nmlvcd->nmcd.hdc, item->pszText, -1, &rcLabel, format); +} + +/*** + * DESCRIPTION: + * Draws an item. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hdc : device context handle + * [I] nItem : item index + * [I] nSubItem : subitem index + * [I] pos : item position in client coordinates + * [I] cdmode : custom draw mode + * + * RETURN: + * Success: TRUE + * Failure: FALSE + */ +static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, ITERATOR *subitems, POINT pos, DWORD cdmode) +{ + WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; + static WCHAR callbackW[] = { '(', 'c', 'a', 'l', 'l', 'b', 'a', 'c', 'k', ')', 0 }; + DWORD cdsubitemmode = CDRF_DODEFAULT; + RECT *focus, rcBox; + NMLVCUSTOMDRAW nmlvcd; + LVITEMW lvItem; + + TRACE("(hdc=%p, nItem=%d, subitems=%p, pos=%s)\n", hdc, nItem, subitems, wine_dbgstr_point(&pos)); + + /* get information needed for drawing the item */ + lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT; + lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK | LVIS_CUT | LVIS_OVERLAYMASK; + lvItem.iItem = nItem; + lvItem.iSubItem = 0; + lvItem.state = 0; + lvItem.lParam = 0; + lvItem.cchTextMax = DISP_TEXT_SIZE; + lvItem.pszText = szDispText; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; + if (lvItem.pszText == LPSTR_TEXTCALLBACKW) lvItem.pszText = callbackW; + TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE)); + + /* now check if we need to update the focus rectangle */ + focus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0; + if (!focus) lvItem.state &= ~LVIS_FOCUSED; + + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, NULL, NULL, NULL, NULL); + OffsetRect(&rcBox, pos.x, pos.y); + + /* Full custom draw stage sequence looks like this: + + LV_VIEW_DETAILS: + + - CDDS_ITEMPREPAINT + - CDDS_ITEMPREPAINT|CDDS_SUBITEM | => sent n times, where n is number of subitems, + CDDS_ITEMPOSTPAINT|CDDS_SUBITEM | including item iself + - CDDS_ITEMPOSTPAINT + + other styles: + + - CDDS_ITEMPREPAINT + - CDDS_ITEMPOSTPAINT + */ + + /* fill in the custom draw structure */ + customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBox, &lvItem); + if (cdmode & CDRF_NOTIFYITEMDRAW) + cdsubitemmode = notify_customdraw(infoPtr, CDDS_ITEMPREPAINT, &nmlvcd); + if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint; + + if (subitems) + { + while (iterator_next(subitems)) + { + DWORD subitemstage = CDRF_DODEFAULT; + + /* We need to query for each subitem, item's data (subitem == 0) is already here at this point */ + if (subitems->nItem) + { + lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_INDENT; + lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK | LVIS_CUT | LVIS_OVERLAYMASK; + lvItem.iItem = nItem; + lvItem.iSubItem = subitems->nItem; + lvItem.state = 0; + lvItem.lParam = 0; + lvItem.cchTextMax = DISP_TEXT_SIZE; + lvItem.pszText = szDispText; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; + if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) + lvItem.state = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED); + if (lvItem.pszText == LPSTR_TEXTCALLBACKW) lvItem.pszText = callbackW; + TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE)); + + /* update custom draw data */ + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &nmlvcd.nmcd.rc, NULL, NULL, NULL, NULL); + OffsetRect(&nmlvcd.nmcd.rc, pos.x, pos.y); + nmlvcd.iSubItem = subitems->nItem; + } + + if (cdsubitemmode & CDRF_NOTIFYSUBITEMDRAW) + subitemstage = notify_customdraw(infoPtr, CDDS_SUBITEM | CDDS_ITEMPREPAINT, &nmlvcd); + else + { + nmlvcd.clrTextBk = infoPtr->clrTextBk; + nmlvcd.clrText = infoPtr->clrText; + } + + if (subitems->nItem == 0 || (cdmode & CDRF_NOTIFYITEMDRAW)) + prepaint_setup(infoPtr, hdc, &nmlvcd, FALSE); + else if (!(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) + prepaint_setup(infoPtr, hdc, &nmlvcd, TRUE); + + if (!(subitemstage & CDRF_SKIPDEFAULT)) + LISTVIEW_DrawItemPart(infoPtr, &lvItem, &nmlvcd, &pos); + + if (subitemstage & CDRF_NOTIFYPOSTPAINT) + subitemstage = notify_customdraw(infoPtr, CDDS_SUBITEM | CDDS_ITEMPOSTPAINT, &nmlvcd); + } + } + else + { + prepaint_setup(infoPtr, hdc, &nmlvcd, FALSE); + LISTVIEW_DrawItemPart(infoPtr, &lvItem, &nmlvcd, &pos); + } postpaint: if (cdsubitemmode & CDRF_NOTIFYPOSTPAINT) - notify_postpaint(infoPtr, &nmlvcd); + { + nmlvcd.iSubItem = 0; + notify_customdraw(infoPtr, CDDS_ITEMPOSTPAINT, &nmlvcd); + } + return TRUE; } @@ -4858,10 +4930,15 @@ static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, /* iterate through the invalidated rows */ while(iterator_next(i)) { + RANGES subitems; + ITERATOR k; + SelectObject(hdc, infoPtr->hFont); LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position); Position.y += Origin.y; + subitems = ranges_create(DPA_GetPtrCount(infoPtr->hdpaColumns)); + /* iterate through the invalidated columns */ while(iterator_next(&j)) { @@ -4876,8 +4953,12 @@ static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, if (!RectVisible(hdc, &rcItem)) continue; } - LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, j.nItem, Position, cdmode); + ranges_additem(subitems, j.nItem); } + + iterator_rangesitems(&k, subitems); + LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, &k, Position, cdmode); + iterator_destroy(&k); } iterator_destroy(&j); } @@ -5011,7 +5092,7 @@ static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, D Position.x += Origin.x; Position.y += Origin.y; - LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, 0, Position, cdmode); + LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, NULL, Position, cdmode); } } @@ -5087,8 +5168,6 @@ static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *prcEra hdcOrig, infoPtr->rcList.left, infoPtr->rcList.top, SRCCOPY); } - infoPtr->cditemmode = CDRF_DODEFAULT; - GetClientRect(infoPtr->hwndSelf, &rcClient); customdraw_fill(&nmlvcd, infoPtr, hdc, &rcClient, 0); cdmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd); @@ -5350,7 +5429,7 @@ static HIMAGELIST LISTVIEW_CreateDragImage(LISTVIEW_INFO *infoPtr, INT iItem, LP FillRect(hdc, &rcItem, infoPtr->hBkBrush); pos.x = pos.y = 0; - if (LISTVIEW_DrawItem(infoPtr, hdc, iItem, 0, pos, infoPtr->cditemmode)) + if (LISTVIEW_DrawItem(infoPtr, hdc, iItem, NULL, pos, CDRF_DODEFAULT)) { dragList = ImageList_Create(size.cx, size.cy, ILC_COLOR, 10, 10); SelectObject(hdc, hOldbmp); diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c index 9310f5691b6..0e3a5c9d407 100644 --- a/dlls/comctl32/tests/listview.c +++ b/dlls/comctl32/tests/listview.c @@ -3,7 +3,7 @@ * * Copyright 2006 Mike McCormack for CodeWeavers * Copyright 2007 George Gov - * Copyright 2009-2013 Nikolay Sivov + * Copyright 2009-2014 Nikolay Sivov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,12 +28,15 @@ #include "v6util.h" #include "msg.h" -#define PARENT_SEQ_INDEX 0 -#define PARENT_FULL_SEQ_INDEX 1 -#define LISTVIEW_SEQ_INDEX 2 -#define EDITBOX_SEQ_INDEX 3 -#define COMBINED_SEQ_INDEX 4 -#define NUM_MSG_SEQUENCES 5 +enum seq_index { + PARENT_SEQ_INDEX, + PARENT_FULL_SEQ_INDEX, + PARENT_CD_SEQ_INDEX, + LISTVIEW_SEQ_INDEX, + EDITBOX_SEQ_INDEX, + COMBINED_SEQ_INDEX, + NUM_MSG_SEQUENCES +}; #define LISTVIEW_ID 0 #define HEADER_ID 1 @@ -389,6 +392,26 @@ static const struct message parent_insert_focused_seq[] = { { 0 } }; +static const struct message parent_report_cd_seq[] = { + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT|CDDS_SUBITEM }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT|CDDS_SUBITEM }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT }, + { 0 } +}; + +static const struct message parent_list_cd_seq[] = { + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT }, + { 0 } +}; + static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static LONG defwndproc_counter = 0; @@ -1758,24 +1781,36 @@ static void test_redraw(void) DestroyWindow(hwnd); } -static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee); - if(msg == WM_NOTIFY) { - NMHDR *nmhdr = (PVOID)lp; + if(message == WM_NOTIFY) { + NMHDR *nmhdr = (NMHDR*)lParam; if(nmhdr->code == NM_CUSTOMDRAW) { NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr; + struct message msg; + + msg.message = message; + msg.flags = sent|wparam|lparam|custdraw; + msg.wParam = wParam; + msg.lParam = lParam; + msg.id = nmhdr->code; + msg.stage = nmlvcd->nmcd.dwDrawStage; + add_message(sequences, PARENT_CD_SEQ_INDEX, &msg); switch(nmlvcd->nmcd.dwDrawStage) { case CDDS_PREPAINT: SetBkColor(nmlvcd->nmcd.hdc, c0ffee); - return CDRF_NOTIFYITEMDRAW; + return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT; case CDDS_ITEMPREPAINT: nmlvcd->clrTextBk = CLR_DEFAULT; - return CDRF_NOTIFYSUBITEMDRAW; + nmlvcd->clrText = RGB(0, 255, 0); + return CDRF_NOTIFYSUBITEMDRAW|CDRF_NOTIFYPOSTPAINT; case CDDS_ITEMPREPAINT | CDDS_SUBITEM: clr = GetBkColor(nmlvcd->nmcd.hdc); + ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk); + ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText); if (nmlvcd->iSubItem) todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr); else @@ -1784,13 +1819,15 @@ static LRESULT WINAPI cd_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM: clr = GetBkColor(nmlvcd->nmcd.hdc); todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr); + ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk); + ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText); return CDRF_DODEFAULT; } return CDRF_DODEFAULT; } } - return DefWindowProcA(hwnd, msg, wp, lp); + return DefWindowProcA(hwnd, message, wParam, lParam); } static void test_customdraw(void) @@ -1810,9 +1847,27 @@ static void test_customdraw(void) InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); - SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc); + /* message tests */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE); DestroyWindow(hwnd); + + hwnd = create_listview_control(LVS_LIST); + + insert_column(hwnd, 0); + insert_column(hwnd, 1); + insert_item(hwnd, 0); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE); + + SetWindowLongPtrA(hwndparent, GWLP_WNDPROC, (LONG_PTR)oldwndproc); + DestroyWindow(hwnd); } static void test_icon_spacing(void)