[PATCH v2 1/7] comctl32/button: Implement NM_CUSTOMDRAW for Push Buttons

Gabriel Ivăncescu gabrielopcode at gmail.com
Tue Mar 5 07:13:23 CST 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=10531
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/comctl32/button.c | 103 ++++++++++++++++++++++++++++++-----------
 1 file changed, 77 insertions(+), 26 deletions(-)

diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c
index 56a4730..f9b4368 100644
--- a/dlls/comctl32/button.c
+++ b/dlls/comctl32/button.c
@@ -237,6 +237,28 @@ static inline WCHAR *get_button_text( const BUTTON_INFO *infoPtr )
     return buffer;
 }
 
+static void init_custom_draw(NMCUSTOMDRAW *nmcd, const BUTTON_INFO *infoPtr, HDC hdc, const RECT *rc)
+{
+    nmcd->hdr.hwndFrom = infoPtr->hwnd;
+    nmcd->hdr.idFrom   = GetWindowLongPtrW(infoPtr->hwnd, GWLP_ID);
+    nmcd->hdr.code     = NM_CUSTOMDRAW;
+    nmcd->hdc          = hdc;
+    nmcd->rc           = *rc;
+    nmcd->dwDrawStage  = CDDS_PREERASE;
+    nmcd->dwItemSpec   = 0;
+    nmcd->lItemlParam  = 0;
+    nmcd->uItemState   = IsWindowEnabled(infoPtr->hwnd) ? 0 : CDIS_DISABLED;
+    if (infoPtr->state & BST_PUSHED)  nmcd->uItemState |= CDIS_SELECTED;
+    if (infoPtr->state & BST_FOCUS)   nmcd->uItemState |= CDIS_FOCUS;
+    if (infoPtr->state & BST_HOT)     nmcd->uItemState |= CDIS_HOT;
+    if (infoPtr->state & BST_INDETERMINATE)
+        nmcd->uItemState |= CDIS_INDETERMINATE;
+
+    /* Windows doesn't seem to send CDIS_CHECKED (it fails the tests) */
+    /* CDIS_SHOWKEYBOARDCUES is misleading, as the meaning is reversed */
+    /* FIXME: Handle it properly when we support keyboard cues? */
+}
+
 HRGN set_control_clipping( HDC hdc, const RECT *rect )
 {
     RECT rc = *rect;
@@ -1476,7 +1498,9 @@ static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
     HBRUSH   hOldBrush;
     INT      oldBkMode;
     COLORREF oldTxtColor;
+    LRESULT  cdrf;
     HFONT hFont;
+    NMCUSTOMDRAW nmcd;
     LONG state = infoPtr->state;
     LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
     BOOL pushedState = (state & BST_PUSHED);
@@ -1498,6 +1522,12 @@ static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
     hOldBrush = SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE));
     oldBkMode = SetBkMode(hDC, TRANSPARENT);
 
+    init_custom_draw(&nmcd, infoPtr, hDC, &rc);
+
+    /* Send erase notifications */
+    cdrf = SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
+    if (cdrf & CDRF_SKIPDEFAULT) goto cleanup;
+
     if (get_button_type(style) == BS_DEFPUSHBUTTON)
     {
         if (action != ODA_FOCUS)
@@ -1505,44 +1535,65 @@ static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
 	InflateRect( &rc, -1, -1 );
     }
 
-    /* completely skip the drawing if only focus has changed */
-    if (action == ODA_FOCUS) goto draw_focus;
+    /* Skip the frame drawing if only focus has changed */
+    if (action != ODA_FOCUS)
+    {
+        uState = DFCS_BUTTONPUSH;
 
-    uState = DFCS_BUTTONPUSH;
+        if (style & BS_FLAT)
+            uState |= DFCS_MONO;
+        else if (pushedState)
+        {
+            if (get_button_type(style) == BS_DEFPUSHBUTTON )
+                uState |= DFCS_FLAT;
+            else
+                uState |= DFCS_PUSHED;
+        }
 
-    if (style & BS_FLAT)
-        uState |= DFCS_MONO;
-    else if (pushedState)
-    {
-	if (get_button_type(style) == BS_DEFPUSHBUTTON )
-	    uState |= DFCS_FLAT;
-	else
-	    uState |= DFCS_PUSHED;
+        if (state & (BST_CHECKED | BST_INDETERMINATE))
+            uState |= DFCS_CHECKED;
+
+        DrawFrameControl( hDC, &rc, DFC_BUTTON, uState );
     }
 
-    if (state & (BST_CHECKED | BST_INDETERMINATE))
-        uState |= DFCS_CHECKED;
+    if (cdrf & CDRF_NOTIFYPOSTERASE)
+    {
+        nmcd.dwDrawStage = CDDS_POSTERASE;
+        SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
+    }
 
-    DrawFrameControl( hDC, &rc, DFC_BUTTON, uState );
+    /* Send paint notifications */
+    nmcd.dwDrawStage = CDDS_PREPAINT;
+    cdrf = SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
+    if (cdrf & CDRF_SKIPDEFAULT) goto cleanup;
 
-    /* draw button label */
-    labelRect = rc;
-    /* Shrink label rect at all sides by 2 so that the content won't touch the surrounding frame */
-    InflateRect(&labelRect, -2, -2);
-    dtFlags = BUTTON_CalcLayoutRects(infoPtr, hDC, &labelRect, &imageRect, &textRect);
+    if (!(cdrf & CDRF_DOERASE) && action != ODA_FOCUS)
+    {
+        /* draw button label */
+        labelRect = rc;
+        /* Shrink label rect at all sides by 2 so that the content won't touch the surrounding frame */
+        InflateRect(&labelRect, -2, -2);
+        dtFlags = BUTTON_CalcLayoutRects(infoPtr, hDC, &labelRect, &imageRect, &textRect);
 
-    if (dtFlags == (UINT)-1L)
-       goto cleanup;
+        if (dtFlags != (UINT)-1L)
+        {
+            if (pushedState) OffsetRect(&labelRect, 1, 1);
 
-    if (pushedState) OffsetRect(&labelRect, 1, 1);
+            oldTxtColor = SetTextColor( hDC, GetSysColor(COLOR_BTNTEXT) );
 
-    oldTxtColor = SetTextColor( hDC, GetSysColor(COLOR_BTNTEXT) );
+            BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &imageRect, &textRect);
 
-    BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &imageRect, &textRect);
+            SetTextColor( hDC, oldTxtColor );
+        }
+    }
 
-    SetTextColor( hDC, oldTxtColor );
+    if (cdrf & CDRF_NOTIFYPOSTPAINT)
+    {
+        nmcd.dwDrawStage = CDDS_POSTPAINT;
+        SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
+    }
+    if ((cdrf & CDRF_SKIPPOSTPAINT) || dtFlags == (UINT)-1L) goto cleanup;
 
-draw_focus:
     if (action == ODA_FOCUS || (state & BST_FOCUS))
     {
         InflateRect( &rc, -2, -2 );
-- 
2.20.1




More information about the wine-devel mailing list