[PATCH 5/7] comctl32/button: Support imagelist rendering.

Zhiyi Zhang zzhang at codeweavers.com
Wed Sep 5 09:58:37 CDT 2018


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=40445
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=40062
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45246
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/comctl32/button.c | 162 ++++++++++++++++++++++++++++++-----------
 1 file changed, 118 insertions(+), 44 deletions(-)

diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c
index 2fa18f4f47..5fdfe7f936 100644
--- a/dlls/comctl32/button.c
+++ b/dlls/comctl32/button.c
@@ -876,16 +876,18 @@ static RECT BUTTON_GetTextRect(const BUTTON_INFO *infoPtr, HDC hdc, const WCHAR
 static BOOL show_image_only(const BUTTON_INFO *infoPtr)
 {
     LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
-    return (style & (BS_ICON | BS_BITMAP)) && infoPtr->u.image;
+    return (style & (BS_ICON | BS_BITMAP)) && (infoPtr->u.image || infoPtr->imagelist.himl);
 }
 
 static BOOL show_image_and_text(const BUTTON_INFO *infoPtr)
 {
     LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
     UINT type = get_button_type(style);
-    return !(style & (BS_ICON | BS_BITMAP)) && infoPtr->u.image
-           && (type == BS_PUSHBUTTON || type == BS_DEFPUSHBUTTON || type == BS_USERBUTTON || type == BS_SPLITBUTTON
-               || type == BS_DEFSPLITBUTTON || type == BS_COMMANDLINK || type == BS_DEFCOMMANDLINK);
+    return !(style & (BS_ICON | BS_BITMAP))
+           && ((infoPtr->u.image
+                && (type == BS_PUSHBUTTON || type == BS_DEFPUSHBUTTON || type == BS_USERBUTTON || type == BS_SPLITBUTTON
+                    || type == BS_DEFSPLITBUTTON || type == BS_COMMANDLINK || type == BS_DEFCOMMANDLINK))
+               || (infoPtr->imagelist.himl && type != BS_GROUPBOX));
 }
 
 static BOOL show_image(const BUTTON_INFO *infoPtr)
@@ -978,13 +980,35 @@ static void BUTTON_PositionRect(LONG style, const RECT *outerRect, RECT *innerRe
     }
 }
 
+/* Convert imagelist align style to button align style */
+static UINT BUTTON_ILStoBS(UINT align)
+{
+    switch (align)
+    {
+    case BUTTON_IMAGELIST_ALIGN_TOP:
+        return BS_CENTER | BS_TOP;
+    case BUTTON_IMAGELIST_ALIGN_BOTTOM:
+        return BS_CENTER | BS_BOTTOM;
+    case BUTTON_IMAGELIST_ALIGN_CENTER:
+        return BS_CENTER | BS_VCENTER;
+    case BUTTON_IMAGELIST_ALIGN_RIGHT:
+        return BS_RIGHT | BS_VCENTER;
+    case BUTTON_IMAGELIST_ALIGN_LEFT:
+    default:
+        return BS_LEFT | BS_VCENTER;
+    }
+}
+
 static SIZE BUTTON_GetImageSize(const BUTTON_INFO *infoPtr)
 {
     ICONINFO iconInfo;
     BITMAP bm = {0};
     SIZE size = {0};
 
-    if (infoPtr->u.image)
+    /* ImageList has priority over image */
+    if (infoPtr->imagelist.himl)
+        ImageList_GetIconSize(infoPtr->imagelist.himl, &size.cx, &size.cy);
+    else if (infoPtr->u.image)
     {
         if (infoPtr->image_type == IMAGE_ICON)
         {
@@ -1024,10 +1048,12 @@ static UINT BUTTON_CalcLayoutRects(const BUTTON_INFO *infoPtr, HDC hdc, RECT *la
 {
    LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
    LONG ex_style = GetWindowLongW( infoPtr->hwnd, GWL_EXSTYLE );
+   LONG split_style = infoPtr->imagelist.himl ? BUTTON_ILStoBS(infoPtr->imagelist.uAlign) : style;
    WCHAR *text = get_button_text(infoPtr);
    SIZE imageSize = BUTTON_GetImageSize(infoPtr);
    UINT dtStyle = BUTTON_BStoDT(style, ex_style);
-   RECT labelRect, imageRect, textRect;
+   RECT labelRect, imageRect, imageRectWithMargin, textRect;
+   LONG imageMarginWidth, imageMarginHeight;
    RECT emptyMargin = {0}, oneMargin = {1, 1, 1, 1};
    LONG maxTextWidth;
 
@@ -1042,6 +1068,14 @@ static UINT BUTTON_CalcLayoutRects(const BUTTON_INFO *infoPtr, HDC hdc, RECT *la
    }
 
    SetRect(&imageRect, 0, 0, imageSize.cx, imageSize.cy);
+   imageRectWithMargin = imageRect;
+   if (infoPtr->imagelist.himl)
+   {
+       imageRectWithMargin.top -= infoPtr->imagelist.margin.top;
+       imageRectWithMargin.bottom += infoPtr->imagelist.margin.bottom;
+       imageRectWithMargin.left -= infoPtr->imagelist.margin.left;
+       imageRectWithMargin.right += infoPtr->imagelist.margin.right;
+   }
 
    /* Show image only */
    if (show_image_only(infoPtr))
@@ -1064,30 +1098,53 @@ static UINT BUTTON_CalcLayoutRects(const BUTTON_INFO *infoPtr, HDC hdc, RECT *la
            RECT boundingLabelRect, boundingImageRect, boundingTextRect;
 
            /* Get label rect */
-           /* Get a label bounding rect to position the label in the user specified label rect because text and
-            * image need to align together. */
-           boundingLabelRect = BUTTON_GetBoundingLabelRect(style, &textRect, &imageRect);
-           BUTTON_PositionRect(style, labelRc, &boundingLabelRect, &emptyMargin);
-           labelRect = boundingLabelRect;
-
-           /* Get image rect */
-           /* Split the label rect to two halves as two bounding rects for image and text */
-           boundingImageRect = labelRect;
-           if ((style & BS_CENTER) == BS_RIGHT)
-               boundingImageRect.left = boundingImageRect.right - imageSize.cx;
-           else if ((style & BS_CENTER) == BS_LEFT)
-               boundingImageRect.right = boundingImageRect.left + imageSize.cx;
-           else if ((style & BS_VCENTER) == BS_BOTTOM)
-               boundingImageRect.top = boundingImageRect.bottom - imageSize.cy;
-           else if ((style & BS_VCENTER) == BS_TOP)
-               boundingImageRect.bottom = boundingImageRect.top + imageSize.cy;
+           /* Image list may have different alignment than the button, use the whole rect for label in this case */
+           if (infoPtr->imagelist.himl)
+               labelRect = *labelRc;
            else
-               boundingImageRect.right = boundingImageRect.left + imageSize.cx;
-           BUTTON_PositionRect(style, &boundingImageRect, &imageRect, &emptyMargin);
-
-           /* Get text rect */
-           SubtractRect(&boundingTextRect, &labelRect, &boundingImageRect);
-           BUTTON_PositionRect(style, &boundingTextRect, &textRect, &oneMargin);
+           {
+               /* Get a label bounding rectangle to position the label in the user specified label rectangle because
+                * text and image need to align together. */
+               boundingLabelRect = BUTTON_GetBoundingLabelRect(split_style, &textRect, &imageRectWithMargin);
+               BUTTON_PositionRect(split_style, labelRc, &boundingLabelRect, &emptyMargin);
+               labelRect = boundingLabelRect;
+           }
+
+           /* When imagelist has center align, use the whole rect for imagelist and text */
+           if(infoPtr->imagelist.himl && infoPtr->imagelist.uAlign == BUTTON_IMAGELIST_ALIGN_CENTER)
+           {
+               boundingImageRect = labelRect;
+               boundingTextRect = labelRect;
+               BUTTON_PositionRect(split_style, &boundingImageRect, &imageRect,
+                                   infoPtr->imagelist.himl ? &infoPtr->imagelist.margin : &emptyMargin);
+               /* Text doesn't use imagelist align */
+               BUTTON_PositionRect(style, &boundingTextRect, &textRect, &oneMargin);
+           }
+           else
+           {
+               /* Get image rect */
+               /* Split the label rect to two halves as two bounding rectangles for image and text */
+               boundingImageRect = labelRect;
+               imageMarginWidth = imageRectWithMargin.right - imageRectWithMargin.left;
+               imageMarginHeight = imageRectWithMargin.bottom - imageRectWithMargin.top;
+               if ((split_style & BS_CENTER) == BS_RIGHT)
+                   boundingImageRect.left = boundingImageRect.right - imageMarginWidth;
+               else if ((split_style & BS_CENTER) == BS_LEFT)
+                   boundingImageRect.right = boundingImageRect.left + imageMarginWidth;
+               else if ((split_style & BS_VCENTER) == BS_BOTTOM)
+                   boundingImageRect.top = boundingImageRect.bottom - imageMarginHeight;
+               else if ((split_style & BS_VCENTER) == BS_TOP)
+                   boundingImageRect.bottom = boundingImageRect.top + imageMarginHeight;
+               else
+                   boundingImageRect.right = boundingImageRect.left + imageMarginWidth;
+               BUTTON_PositionRect(split_style, &boundingImageRect, &imageRect,
+                                   infoPtr->imagelist.himl ? &infoPtr->imagelist.margin : &emptyMargin);
+
+               /* Get text rect */
+               SubtractRect(&boundingTextRect, &labelRect, &boundingImageRect);
+               /* Text doesn't use imagelist align */
+               BUTTON_PositionRect(style, &boundingTextRect, &textRect, &oneMargin);
+           }
        }
        /* Show text only */
        else
@@ -1144,6 +1201,7 @@ static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags,
    UINT flags = IsWindowEnabled(infoPtr->hwnd) ? DSS_NORMAL : DSS_DISABLED;
    UINT imageFlags;
    LONG state = infoPtr->state;
+   LONG draw_state;
    LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
    WCHAR *text = NULL;
 
@@ -1158,24 +1216,40 @@ static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags,
       flags |= DSS_MONO;
    }
 
-   switch (infoPtr->image_type)
+   if (show_image(infoPtr))
    {
-   case IMAGE_ICON:
-       imageFlags = flags | DST_ICON;
-       lp = (LPARAM)infoPtr->u.icon;
-       break;
-   case IMAGE_BITMAP:
-       imageFlags = flags | DST_BITMAP;
-       lp = (LPARAM)infoPtr->u.bitmap;
-       break;
-   default:
-       return;
+       if (infoPtr->imagelist.himl)
+       {
+           if (ImageList_GetImageCount(infoPtr->imagelist.himl) == 1)
+               ImageList_Draw(infoPtr->imagelist.himl, 0, hdc, imageRect->left, imageRect->top, ILD_NORMAL);
+           else
+           {
+               draw_state = get_draw_state(infoPtr);
+               ImageList_Draw(infoPtr->imagelist.himl, draw_state - 1, hdc, imageRect->left, imageRect->top,
+                              ILD_NORMAL);
+           }
+       }
+       else
+       {
+           switch (infoPtr->image_type)
+           {
+           case IMAGE_ICON:
+               imageFlags = flags | DST_ICON;
+               lp = (LPARAM)infoPtr->u.icon;
+               break;
+           case IMAGE_BITMAP:
+               imageFlags = flags | DST_BITMAP;
+               lp = (LPARAM)infoPtr->u.bitmap;
+               break;
+           default:
+               return;
+           }
+
+           DrawStateW(hdc, hbr, lpOutputProc, lp, wp, imageRect->left, imageRect->top,
+                      imageRect->right - imageRect->left, imageRect->bottom - imageRect->top, imageFlags);
+       }
    }
 
-   if (show_image(infoPtr))
-       DrawStateW(hdc, hbr, lpOutputProc, lp, wp, imageRect->left, imageRect->top,
-                  imageRect->right - imageRect->left, imageRect->bottom - imageRect->top, imageFlags);
-
    if (show_image_only(infoPtr)) return;
 
    /* DST_COMPLEX -- is 0 */
-- 
2.18.0





More information about the wine-devel mailing list