From c9aa8dab8f0d86cf4fb06612f261c67327046789 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Wed, 5 Sep 2018 22:58:37 +0800 Subject: [PATCH] comctl32/button: Support imagelist rendering. 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 Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- 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 2fa18f4f47d..5fdfe7f936e 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 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; + } - /* Get text rect */ - SubtractRect(&boundingTextRect, &labelRect, &boundingImageRect); - BUTTON_PositionRect(style, &boundingTextRect, &textRect, &oneMargin); + /* 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,23 +1216,39 @@ static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, flags |= DSS_MONO; } - 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; - } - if (show_image(infoPtr)) - DrawStateW(hdc, hbr, lpOutputProc, lp, wp, imageRect->left, imageRect->top, - imageRect->right - imageRect->left, imageRect->bottom - imageRect->top, imageFlags); + { + 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_only(infoPtr)) return;