TreeView fix endless loop and colors with custom draw
Vitaliy Margolen
wine-patch at kievinfo.com
Thu Apr 14 15:24:37 CDT 2005
Here is what I found:
- Not all changes to items through SetItem should trigger redraw.
- If app using callbacks for text and images it has to refresh control
explicitly when that information changes.
- TreeView should keep color changes maid by app within draw notifies but only
for the current draw cycle and not permanently.
Vitaliy Margolen
changelog:
dlls/comctl32/treeview.c
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
-------------- next part --------------
Index: dlls/comctl32/treeview.c
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/treeview.c,v
retrieving revision 1.170
diff -u -p -r1.170 treeview.c
--- dlls/comctl32/treeview.c 14 Apr 2005 13:56:12 -0000 1.170
+++ dlls/comctl32/treeview.c 14 Apr 2005 20:08:40 -0000
@@ -616,10 +616,10 @@ TREEVIEW_SendCustomDrawNotify(TREEVIEW_I
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 +635,7 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVI
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 +645,7 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVI
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 +653,7 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVI
retval = TREEVIEW_SendRealNotify(infoPtr,
(WPARAM)nmcd->hdr.idFrom,
- (LPARAM)&nmcdhdr);
+ (LPARAM)nmcdhdr);
return (BOOL)retval;
}
@@ -2114,9 +2112,17 @@ TREEVIEW_SetItemT(TREEVIEW_INFO *infoPtr
/* 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 (((tvItem->mask & TVIF_CHILDREN ) && (originalItem.cChildren != wineItem->cChildren ) ) ||
+ ((tvItem->mask & TVIF_IMAGE ) && (originalItem.iImage != wineItem->iImage )&&
+ wineItem->iImage != I_IMAGECALLBACK ) ||
+ ((tvItem->mask & TVIF_SELECTEDIMAGE) && (originalItem.iSelectedImage != wineItem->iSelectedImage)&&
+ wineItem->iSelectedImage != I_IMAGECALLBACK ) ||
+ ((tvItem->mask & TVIF_TEXT ) && (originalItem.pszText != wineItem->pszText )&&
+ wineItem->pszText != LPSTR_TEXTCALLBACKW ) ||
+ ((tvItem->mask & TVIF_INTEGRAL ) && (originalItem.iIntegral != wineItem->iIntegral ) ) ||
+ ((tvItem->mask & TVIF_STATE ) && ((originalItem.state ^ wineItem->state) & tvItem->stateMask ))
+ )
{
if (tvItem->mask & TVIF_INTEGRAL)
{
@@ -2265,10 +2271,14 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *in
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 +2345,10 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *in
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 +2378,8 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *in
}
}
}
+ SelectObject(hdc, hbrOld);
+ DeleteObject(hbr);
}
static void
@@ -2380,12 +2387,50 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr
{
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 +2442,7 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr
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 +2457,10 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr
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 +2518,31 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr
{
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 +2586,13 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr
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);
}
More information about the wine-patches
mailing list