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);
}
/* 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.
*/
@ -616,10 +649,10 @@ TREEVIEW_SendCustomDrawNotify(TREEVIEW_INFO *infoPtr, DWORD dwDrawStage,
static BOOL
TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
TREEVIEW_ITEM *wineItem, UINT uItemDrawState)
TREEVIEW_ITEM *wineItem, UINT uItemDrawState,
NMTVCUSTOMDRAW *nmcdhdr)
{
HWND hwnd = infoPtr->hwnd;
NMTVCUSTOMDRAW nmcdhdr;
LPNMCUSTOMDRAW nmcd;
DWORD dwDrawStage, dwItemSpec;
UINT uItemState;
@ -635,7 +668,7 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
if (wineItem == infoPtr->hotItem)
uItemState |= CDIS_HOT;
nmcd = &nmcdhdr.nmcd;
nmcd = &nmcdhdr->nmcd;
nmcd->hdr.hwndFrom = hwnd;
nmcd->hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID);
nmcd->hdr.code = NM_CUSTOMDRAW;
@ -645,9 +678,7 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
nmcd->dwItemSpec = dwItemSpec;
nmcd->uItemState = uItemState;
nmcd->lItemlParam = wineItem->lParam;
nmcdhdr.clrText = infoPtr->clrText;
nmcdhdr.clrTextBk = infoPtr->clrBk;
nmcdhdr.iLevel = wineItem->iLevel;
nmcdhdr->iLevel = wineItem->iLevel;
TRACE("drawstage:%lx hdc:%p item:%lx, itemstate:%x, lItemlParam:%lx\n",
nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
@ -655,7 +686,7 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
retval = TREEVIEW_SendRealNotify(infoPtr,
(WPARAM)nmcd->hdr.idFrom,
(LPARAM)&nmcdhdr);
(LPARAM)nmcdhdr);
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. */
TREEVIEW_ComputeItemInternalMetrics(infoPtr, wineItem);
/* if any of the items values changed, redraw the item */
if(memcmp(&originalItem, wineItem, sizeof(TREEVIEW_ITEM)) ||
(tvItem->stateMask & TVIS_BOLD))
/* if any of the item's values changed and it's not a callback, redraw the item */
if (item_changed(&originalItem, wineItem, tvItem))
{
if (tvItem->mask & TVIF_INTEGRAL)
{
@ -2265,10 +2295,14 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
BOOL lar = ((infoPtr->dwStyle
& (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS))
> TVS_LINESATROOT);
HBRUSH hbr, hbrOld;
if (!lar && item->iLevel == 0)
return;
hbr = CreateSolidBrush(infoPtr->clrBk);
hbrOld = SelectObject(hdc, hbr);
centerx = (item->linesOffset + item->stateOffset) / 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 hOldPen = SelectObject(hdc, hNewPen);
HBRUSH hbr = CreateSolidBrush(infoPtr->clrBk);
HBRUSH hbrOld = SelectObject(hdc, hbr);
Rectangle(hdc, centerx - rectsize - 1, centery - rectsize - 1,
centerx + rectsize + 2, centery + rectsize + 2);
SelectObject(hdc, hbrOld);
DeleteObject(hbr);
SelectObject(hdc, hOldPen);
DeleteObject(hNewPen);
@ -2373,6 +2402,8 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
}
}
}
SelectObject(hdc, hbrOld);
DeleteObject(hbr);
}
static void
@ -2380,12 +2411,50 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
{
INT cditem;
HFONT hOldFont;
COLORREF oldTextColor, oldTextBkColor;
int centery;
hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, wineItem));
BOOL inFocus = (GetFocus() == infoPtr->hwnd);
NMTVCUSTOMDRAW nmcdhdr;
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,
* so get ready. */
/* 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)
{
cditem = TREEVIEW_SendCustomDrawItemNotify
(infoPtr, hdc, wineItem, CDDS_ITEMPREPAINT);
(infoPtr, hdc, wineItem, CDDS_ITEMPREPAINT, &nmcdhdr);
TRACE("prepaint:cditem-app returns 0x%x\n", cditem);
if (cditem & CDRF_SKIPDEFAULT)
@ -2412,6 +2481,10 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *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;
/*
@ -2469,87 +2542,31 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
{
if (wineItem->pszText)
{
COLORREF oldTextColor = 0;
INT oldBkMode;
HBRUSH hbrBk = 0;
BOOL inFocus = (GetFocus() == infoPtr->hwnd);
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.bottom = wineItem->rect.bottom;
rcText.left = wineItem->textOffset;
rcText.right = rcText.left + wineItem->textWidth + 4;
if (hbrBk)
{
FillRect(hdc, &rcText, hbrBk);
DeleteObject(hbrBk);
}
TRACE("drawing text %s at (%ld,%ld)-(%ld,%ld)\n",
debugstr_w(wineItem->pszText),
rcText.left, rcText.top, rcText.right, rcText.bottom);
/* 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 */
if ((wineItem == infoPtr->selectedItem) && inFocus)
{
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)
{
cditem = TREEVIEW_SendCustomDrawItemNotify
(infoPtr, hdc, wineItem, CDDS_ITEMPOSTPAINT);
(infoPtr, hdc, wineItem, CDDS_ITEMPOSTPAINT, &nmcdhdr);
TRACE("postpaint:cditem-app returns 0x%x\n", cditem);
}
/* Restore the hdc state */
SetTextColor(hdc, oldTextColor);
SetBkColor(hdc, oldTextBkColor);
SelectObject(hdc, hOldFont);
}