Commit 71be0944 authored by Vitaliy Margolen's avatar Vitaliy Margolen Committed by Alexandre Julliard

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.
parent a8d8b52d
...@@ -241,6 +241,39 @@ TREEVIEW_GetItemIndex(TREEVIEW_INFO *infoPtr, HTREEITEM handle) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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)
{
FillRect(hdc, &rcText, hbrBk);
DeleteObject(hbrBk);
}
/* 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", TRACE("drawing text %s at (%ld,%ld)-(%ld,%ld)\n",
debugstr_w(wineItem->pszText), debugstr_w(wineItem->pszText),
rcText.left, rcText.top, rcText.right, rcText.bottom); rcText.left, rcText.top, rcText.right, rcText.bottom);
/* Draw it */ /* Draw it */
DrawTextW(hdc, ExtTextOutW(hdc, rcText.left + 2, rcText.top + 1,
ETO_CLIPPED | ETO_OPAQUE,
&rcText,
wineItem->pszText, wineItem->pszText,
lstrlenW(wineItem->pszText), lstrlenW(wineItem->pszText),
&rcText, NULL);
DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
/* Restore the hdc state */ /* Draw the box around the selected item */
SetTextColor(hdc, oldTextColor); if ((wineItem == infoPtr->selectedItem) && inFocus)
{
DrawFocusRect(hdc,&rcText);
}
if (oldBkMode != TRANSPARENT)
SetBkMode(hdc, oldBkMode);
} }
} }
...@@ -2593,10 +2610,13 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem) ...@@ -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);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment