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:
parent
a8d8b52d6f
commit
71be094420
|
@ -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,62 +2542,24 @@ 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)
|
||||||
|
@ -2532,24 +2567,6 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue