Don't redraw if no information has changed.

Fixed endless redraw loop if app using callback for images and/or
text.
Keep color changes made by app for the current draw cycle.
This commit is contained in:
Vitaliy Margolen 2005-04-18 10:20:51 +00:00 committed by Alexandre Julliard
parent a8d8b52d6f
commit 71be094420
1 changed files with 106 additions and 86 deletions

View File

@ -241,6 +241,39 @@ TREEVIEW_GetItemIndex(TREEVIEW_INFO *infoPtr, HTREEITEM handle)
return DPA_GetPtrIndex(infoPtr->items, handle); return DPA_GetPtrIndex(infoPtr->items, handle);
} }
/* Checks if item has changed and needs to be redrawn */
static inline BOOL item_changed (TREEVIEW_ITEM *tiOld, TREEVIEW_ITEM *tiNew, LPTVITEMEXW tvChange)
{
/* Number of children has changed */
if ((tvChange->mask & TVIF_CHILDREN) && (tiOld->cChildren != tiNew->cChildren))
return TRUE;
/* Image has changed and it's not a callback */
if ((tvChange->mask & TVIF_IMAGE) && (tiOld->iImage != tiNew->iImage) &&
tiNew->iImage != I_IMAGECALLBACK)
return TRUE;
/* Selected image has changed and it's not a callback */
if ((tvChange->mask & TVIF_SELECTEDIMAGE) && (tiOld->iSelectedImage != tiNew->iSelectedImage) &&
tiNew->iSelectedImage != I_IMAGECALLBACK)
return TRUE;
/* Text has changed and it's not a callback */
if ((tvChange->mask & TVIF_TEXT) && (tiOld->pszText != tiNew->pszText) &&
tiNew->pszText != LPSTR_TEXTCALLBACKW)
return TRUE;
/* Indent has changed */
if ((tvChange->mask & TVIF_INTEGRAL) && (tiOld->iIntegral != tiNew->iIntegral))
return TRUE;
/* Item state has changed */
if ((tvChange->mask & TVIF_STATE) && ((tiOld->state ^ tiNew->state) & tvChange->stateMask ))
return TRUE;
return FALSE;
}
/*************************************************************************** /***************************************************************************
* This method checks that handle is an item for this tree. * This method checks that handle is an item for this tree.
*/ */
@ -616,10 +649,10 @@ TREEVIEW_SendCustomDrawNotify(TREEVIEW_INFO *infoPtr, DWORD dwDrawStage,
static BOOL static BOOL
TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
TREEVIEW_ITEM *wineItem, UINT uItemDrawState) TREEVIEW_ITEM *wineItem, UINT uItemDrawState,
NMTVCUSTOMDRAW *nmcdhdr)
{ {
HWND hwnd = infoPtr->hwnd; HWND hwnd = infoPtr->hwnd;
NMTVCUSTOMDRAW nmcdhdr;
LPNMCUSTOMDRAW nmcd; LPNMCUSTOMDRAW nmcd;
DWORD dwDrawStage, dwItemSpec; DWORD dwDrawStage, dwItemSpec;
UINT uItemState; UINT uItemState;
@ -635,7 +668,7 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
if (wineItem == infoPtr->hotItem) if (wineItem == infoPtr->hotItem)
uItemState |= CDIS_HOT; uItemState |= CDIS_HOT;
nmcd = &nmcdhdr.nmcd; nmcd = &nmcdhdr->nmcd;
nmcd->hdr.hwndFrom = hwnd; nmcd->hdr.hwndFrom = hwnd;
nmcd->hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); nmcd->hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID);
nmcd->hdr.code = NM_CUSTOMDRAW; nmcd->hdr.code = NM_CUSTOMDRAW;
@ -645,9 +678,7 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
nmcd->dwItemSpec = dwItemSpec; nmcd->dwItemSpec = dwItemSpec;
nmcd->uItemState = uItemState; nmcd->uItemState = uItemState;
nmcd->lItemlParam = wineItem->lParam; nmcd->lItemlParam = wineItem->lParam;
nmcdhdr.clrText = infoPtr->clrText; nmcdhdr->iLevel = wineItem->iLevel;
nmcdhdr.clrTextBk = infoPtr->clrBk;
nmcdhdr.iLevel = wineItem->iLevel;
TRACE("drawstage:%lx hdc:%p item:%lx, itemstate:%x, lItemlParam:%lx\n", TRACE("drawstage:%lx hdc:%p item:%lx, itemstate:%x, lItemlParam:%lx\n",
nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec, nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
@ -655,7 +686,7 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
retval = TREEVIEW_SendRealNotify(infoPtr, retval = TREEVIEW_SendRealNotify(infoPtr,
(WPARAM)nmcd->hdr.idFrom, (WPARAM)nmcd->hdr.idFrom,
(LPARAM)&nmcdhdr); (LPARAM)nmcdhdr);
return (BOOL)retval; return (BOOL)retval;
} }
@ -2114,9 +2145,8 @@ TREEVIEW_SetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
/* The refresh updates everything, but we can't wait until then. */ /* The refresh updates everything, but we can't wait until then. */
TREEVIEW_ComputeItemInternalMetrics(infoPtr, wineItem); TREEVIEW_ComputeItemInternalMetrics(infoPtr, wineItem);
/* if any of the items values changed, redraw the item */ /* if any of the item's values changed and it's not a callback, redraw the item */
if(memcmp(&originalItem, wineItem, sizeof(TREEVIEW_ITEM)) || if (item_changed(&originalItem, wineItem, tvItem))
(tvItem->stateMask & TVIS_BOLD))
{ {
if (tvItem->mask & TVIF_INTEGRAL) if (tvItem->mask & TVIF_INTEGRAL)
{ {
@ -2265,10 +2295,14 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
BOOL lar = ((infoPtr->dwStyle BOOL lar = ((infoPtr->dwStyle
& (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS)) & (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS))
> TVS_LINESATROOT); > TVS_LINESATROOT);
HBRUSH hbr, hbrOld;
if (!lar && item->iLevel == 0) if (!lar && item->iLevel == 0)
return; return;
hbr = CreateSolidBrush(infoPtr->clrBk);
hbrOld = SelectObject(hdc, hbr);
centerx = (item->linesOffset + item->stateOffset) / 2; centerx = (item->linesOffset + item->stateOffset) / 2;
centery = (item->rect.top + item->rect.bottom) / 2; centery = (item->rect.top + item->rect.bottom) / 2;
@ -2335,15 +2369,10 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
HPEN hNewPen = CreatePen(PS_SOLID, 0, infoPtr->clrLine); HPEN hNewPen = CreatePen(PS_SOLID, 0, infoPtr->clrLine);
HPEN hOldPen = SelectObject(hdc, hNewPen); HPEN hOldPen = SelectObject(hdc, hNewPen);
HBRUSH hbr = CreateSolidBrush(infoPtr->clrBk);
HBRUSH hbrOld = SelectObject(hdc, hbr);
Rectangle(hdc, centerx - rectsize - 1, centery - rectsize - 1, Rectangle(hdc, centerx - rectsize - 1, centery - rectsize - 1,
centerx + rectsize + 2, centery + rectsize + 2); centerx + rectsize + 2, centery + rectsize + 2);
SelectObject(hdc, hbrOld);
DeleteObject(hbr);
SelectObject(hdc, hOldPen); SelectObject(hdc, hOldPen);
DeleteObject(hNewPen); DeleteObject(hNewPen);
@ -2373,6 +2402,8 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
} }
} }
} }
SelectObject(hdc, hbrOld);
DeleteObject(hbr);
} }
static void static void
@ -2380,12 +2411,50 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
{ {
INT cditem; INT cditem;
HFONT hOldFont; HFONT hOldFont;
COLORREF oldTextColor, oldTextBkColor;
int centery; int centery;
BOOL inFocus = (GetFocus() == infoPtr->hwnd);
hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, wineItem)); NMTVCUSTOMDRAW nmcdhdr;
TREEVIEW_UpdateDispInfo(infoPtr, wineItem, CALLBACK_MASK_ALL); TREEVIEW_UpdateDispInfo(infoPtr, wineItem, CALLBACK_MASK_ALL);
/* - If item is drop target or it is selected and window is in focus -
* use blue background (COLOR_HIGHLIGHT).
* - If item is selected, window is not in focus, but it has style
* TVS_SHOWSELALWAYS - use grey background (COLOR_BTNFACE)
* - Otherwise - use background color
*/
if ((wineItem->state & TVIS_DROPHILITED) || ((wineItem == infoPtr->focusedItem) && !(wineItem->state & TVIS_SELECTED)) ||
((wineItem->state & TVIS_SELECTED) && (!infoPtr->focusedItem) &&
(inFocus || (infoPtr->dwStyle & TVS_SHOWSELALWAYS))))
{
if ((wineItem->state & TVIS_DROPHILITED) || inFocus)
{
nmcdhdr.clrTextBk = GetSysColor(COLOR_HIGHLIGHT);
nmcdhdr.clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
}
else
{
nmcdhdr.clrTextBk = GetSysColor(COLOR_BTNFACE);
if (infoPtr->clrText == -1)
nmcdhdr.clrText = GetSysColor(COLOR_WINDOWTEXT);
else
nmcdhdr.clrText = infoPtr->clrText;
}
}
else
{
nmcdhdr.clrTextBk = infoPtr->clrBk;
if ((infoPtr->dwStyle & TVS_TRACKSELECT) && (wineItem == infoPtr->hotItem))
nmcdhdr.clrText = comctl32_color.clrHighlight;
else if (infoPtr->clrText == -1)
nmcdhdr.clrText = GetSysColor(COLOR_WINDOWTEXT);
else
nmcdhdr.clrText = infoPtr->clrText;
}
hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, wineItem));
/* The custom draw handler can query the text rectangle, /* The custom draw handler can query the text rectangle,
* so get ready. */ * so get ready. */
/* should already be known, set to 0 when changed */ /* should already be known, set to 0 when changed */
@ -2397,7 +2466,7 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW)
{ {
cditem = TREEVIEW_SendCustomDrawItemNotify cditem = TREEVIEW_SendCustomDrawItemNotify
(infoPtr, hdc, wineItem, CDDS_ITEMPREPAINT); (infoPtr, hdc, wineItem, CDDS_ITEMPREPAINT, &nmcdhdr);
TRACE("prepaint:cditem-app returns 0x%x\n", cditem); TRACE("prepaint:cditem-app returns 0x%x\n", cditem);
if (cditem & CDRF_SKIPDEFAULT) if (cditem & CDRF_SKIPDEFAULT)
@ -2412,6 +2481,10 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
TREEVIEW_DrawItemLines(infoPtr, hdc, wineItem); TREEVIEW_DrawItemLines(infoPtr, hdc, wineItem);
/* Set colors. Custom draw handler can change these so we do this after it. */
oldTextColor = SetTextColor(hdc, nmcdhdr.clrText);
oldTextBkColor = SetBkColor(hdc, nmcdhdr.clrTextBk);
centery = (wineItem->rect.top + wineItem->rect.bottom) / 2; centery = (wineItem->rect.top + wineItem->rect.bottom) / 2;
/* /*
@ -2469,87 +2542,31 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
{ {
if (wineItem->pszText) if (wineItem->pszText)
{ {
COLORREF oldTextColor = 0;
INT oldBkMode;
HBRUSH hbrBk = 0;
BOOL inFocus = (GetFocus() == infoPtr->hwnd);
RECT rcText; RECT rcText;
oldBkMode = SetBkMode(hdc, TRANSPARENT);
/* - If item is drop target or it is selected and window is in focus -
* use blue background (COLOR_HIGHLIGHT).
* - If item is selected, window is not in focus, but it has style
* TVS_SHOWSELALWAYS - use grey background (COLOR_BTNFACE)
* - Otherwise - don't fill background
*/
if ((wineItem->state & TVIS_DROPHILITED) || ((wineItem == infoPtr->focusedItem) && !(wineItem->state & TVIS_SELECTED)) ||
((wineItem->state & TVIS_SELECTED) && (!infoPtr->focusedItem) &&
(inFocus || (infoPtr->dwStyle & TVS_SHOWSELALWAYS))))
{
if ((wineItem->state & TVIS_DROPHILITED) || inFocus)
{
hbrBk = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
oldTextColor =
SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
}
else
{
hbrBk = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
if (infoPtr->clrText == -1)
oldTextColor =
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
else
oldTextColor = SetTextColor(hdc, infoPtr->clrText);
}
}
else
{
if ((infoPtr->dwStyle & TVS_TRACKSELECT) && (wineItem == infoPtr->hotItem))
oldTextColor = SetTextColor(hdc, comctl32_color.clrHighlight);
else if (infoPtr->clrText == -1)
oldTextColor =
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
else
oldTextColor = SetTextColor(hdc, infoPtr->clrText);
}
rcText.top = wineItem->rect.top; rcText.top = wineItem->rect.top;
rcText.bottom = wineItem->rect.bottom; rcText.bottom = wineItem->rect.bottom;
rcText.left = wineItem->textOffset; rcText.left = wineItem->textOffset;
rcText.right = rcText.left + wineItem->textWidth + 4; rcText.right = rcText.left + wineItem->textWidth + 4;
if (hbrBk) TRACE("drawing text %s at (%ld,%ld)-(%ld,%ld)\n",
{ debugstr_w(wineItem->pszText),
FillRect(hdc, &rcText, hbrBk); rcText.left, rcText.top, rcText.right, rcText.bottom);
DeleteObject(hbrBk);
}
/* Draw it */
ExtTextOutW(hdc, rcText.left + 2, rcText.top + 1,
ETO_CLIPPED | ETO_OPAQUE,
&rcText,
wineItem->pszText,
lstrlenW(wineItem->pszText),
NULL);
/* Draw the box around the selected item */ /* Draw the box around the selected item */
if ((wineItem == infoPtr->selectedItem) && inFocus) if ((wineItem == infoPtr->selectedItem) && inFocus)
{ {
DrawFocusRect(hdc,&rcText); DrawFocusRect(hdc,&rcText);
} }
InflateRect(&rcText, -2, -1); /* allow for the focus rect */
TRACE("drawing text %s at (%ld,%ld)-(%ld,%ld)\n",
debugstr_w(wineItem->pszText),
rcText.left, rcText.top, rcText.right, rcText.bottom);
/* Draw it */
DrawTextW(hdc,
wineItem->pszText,
lstrlenW(wineItem->pszText),
&rcText,
DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
/* Restore the hdc state */
SetTextColor(hdc, oldTextColor);
if (oldBkMode != TRANSPARENT)
SetBkMode(hdc, oldBkMode);
} }
} }
@ -2593,10 +2610,13 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
if (cditem & CDRF_NOTIFYPOSTPAINT) if (cditem & CDRF_NOTIFYPOSTPAINT)
{ {
cditem = TREEVIEW_SendCustomDrawItemNotify cditem = TREEVIEW_SendCustomDrawItemNotify
(infoPtr, hdc, wineItem, CDDS_ITEMPOSTPAINT); (infoPtr, hdc, wineItem, CDDS_ITEMPOSTPAINT, &nmcdhdr);
TRACE("postpaint:cditem-app returns 0x%x\n", cditem); TRACE("postpaint:cditem-app returns 0x%x\n", cditem);
} }
/* Restore the hdc state */
SetTextColor(hdc, oldTextColor);
SetBkColor(hdc, oldTextBkColor);
SelectObject(hdc, hOldFont); SelectObject(hdc, hOldFont);
} }