diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c index 1e339ef19c4..46a6ff40635 100644 --- a/dlls/comctl32/button.c +++ b/dlls/comctl32/button.c @@ -96,6 +96,7 @@ typedef struct _BUTTON_INFO HFONT font; WCHAR *note; INT note_length; + DWORD image_type; /* IMAGE_BITMAP or IMAGE_ICON */ union { HICON icon; @@ -718,18 +719,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L break; case BM_SETIMAGE: - /* Check that image format matches button style */ - switch (style & (BS_BITMAP|BS_ICON)) - { - case BS_BITMAP: - if (wParam != IMAGE_BITMAP) return 0; - break; - case BS_ICON: - if (wParam != IMAGE_ICON) return 0; - break; - default: - return 0; - } + infoPtr->image_type = (DWORD)wParam; oldHbitmap = infoPtr->u.image; infoPtr->u.image = (HANDLE)lParam; InvalidateRect( hWnd, NULL, FALSE ); @@ -802,61 +792,50 @@ static UINT BUTTON_CalcLabelRect(const BUTTON_INFO *infoPtr, HDC hdc, RECT *rc) { LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE ); LONG ex_style = GetWindowLongW( infoPtr->hwnd, GWL_EXSTYLE ); - WCHAR *text; + WCHAR *text = get_button_text(infoPtr); ICONINFO iconInfo; - BITMAP bm; + BITMAP bm = { 0 }; UINT dtStyle = BUTTON_BStoDT( style, ex_style ); RECT r = *rc; INT n; /* Calculate label rectangle according to label type */ - switch (style & (BS_ICON|BS_BITMAP)) + /* FIXME: Doesn't support showing both image and text yet */ + if (infoPtr->u.image) { - case BS_TEXT: - { - HFONT hFont, hPrevFont = 0; + if (infoPtr->image_type == IMAGE_ICON) + { + GetIconInfo(infoPtr->u.icon, &iconInfo); + GetObjectW(iconInfo.hbmColor, sizeof(bm), &bm); + DeleteObject(iconInfo.hbmColor); + DeleteObject(iconInfo.hbmMask); + } + else if (infoPtr->image_type == IMAGE_BITMAP) + { + GetObjectW(infoPtr->u.bitmap, sizeof(bm), &bm); + } - if (!(text = get_button_text( infoPtr ))) goto empty_rect; - if (!text[0]) - { - heap_free( text ); - goto empty_rect; - } - - if ((hFont = infoPtr->font)) hPrevFont = SelectObject( hdc, hFont ); - DrawTextW(hdc, text, -1, &r, dtStyle | DT_CALCRECT); - if (hPrevFont) SelectObject( hdc, hPrevFont ); - heap_free( text ); - break; - } - - case BS_ICON: - if (!GetIconInfo(infoPtr->u.icon, &iconInfo)) - goto empty_rect; - - GetObjectW (iconInfo.hbmColor, sizeof(BITMAP), &bm); - - r.right = r.left + bm.bmWidth; - r.bottom = r.top + bm.bmHeight; - - DeleteObject(iconInfo.hbmColor); - DeleteObject(iconInfo.hbmMask); - break; - - case BS_BITMAP: - if (!GetObjectW( infoPtr->u.bitmap, sizeof(BITMAP), &bm)) - goto empty_rect; - - r.right = r.left + bm.bmWidth; - r.bottom = r.top + bm.bmHeight; - break; - - default: - empty_rect: - rc->right = r.left; - rc->bottom = r.top; - return (UINT)-1; + r.right = r.left + bm.bmWidth; + r.bottom = r.top + bm.bmHeight; } + else if (text && text[0]) + { + HFONT hFont, hPrevFont = 0; + + if ((hFont = infoPtr->font)) hPrevFont = SelectObject(hdc, hFont); + DrawTextW(hdc, text, -1, &r, dtStyle | DT_CALCRECT); + if (hPrevFont) SelectObject(hdc, hPrevFont); + } + + if ((infoPtr->u.image && bm.bmWidth == 0 && bm.bmHeight == 0) + || (text == NULL || text[0] == '\0')) + { + rc->right = r.left; + rc->bottom = r.top; + heap_free(text); + return (UINT)-1; + } + heap_free(text); /* Position label inside bounding rectangle according to * alignment flags. (calculated rect is always left-top aligned). @@ -934,28 +913,30 @@ static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, flags |= DSS_MONO; } - switch (style & (BS_ICON|BS_BITMAP)) + /* FIXME: Support drawing label with both image and text */ + if (infoPtr->u.image != 0) { - case BS_TEXT: - /* DST_COMPLEX -- is 0 */ - lpOutputProc = BUTTON_DrawTextCallback; - if (!(text = get_button_text( infoPtr ))) return; - lp = (LPARAM)text; - wp = dtFlags; - break; - - case BS_ICON: - flags |= DST_ICON; - lp = (LPARAM)infoPtr->u.icon; - break; - - case BS_BITMAP: - flags |= DST_BITMAP; - lp = (LPARAM)infoPtr->u.bitmap; - break; - - default: - return; + switch (infoPtr->image_type) + { + case IMAGE_ICON: + flags |= DST_ICON; + lp = (LPARAM)infoPtr->u.icon; + break; + case IMAGE_BITMAP: + flags |= DST_BITMAP; + lp = (LPARAM)infoPtr->u.bitmap; + break; + default: + return; + } + } + else + { + /* DST_COMPLEX -- is 0 */ + lpOutputProc = BUTTON_DrawTextCallback; + if (!(text = get_button_text(infoPtr))) return; + lp = (LPARAM)text; + wp = dtFlags; } DrawStateW(hdc, hbr, lpOutputProc, lp, wp, rc->left, rc->top, diff --git a/dlls/comctl32/tests/button.c b/dlls/comctl32/tests/button.c index 7bd73de7cbd..3e705f1ec74 100644 --- a/dlls/comctl32/tests/button.c +++ b/dlls/comctl32/tests/button.c @@ -962,6 +962,239 @@ static void test_note(void) } } +static void test_bm_get_set_image(void) +{ + HWND hwnd; + HDC hdc; + HBITMAP hbmp1x1; + HBITMAP hbmp2x2; + HBITMAP hmask2x2; + ICONINFO icon_info2x2; + HICON hicon2x2; + HBITMAP hbmp; + HICON hicon; + ICONINFO icon_info; + BITMAP bm; + static const DWORD default_style = BS_PUSHBUTTON | WS_TABSTOP | WS_POPUP | WS_VISIBLE; + + hdc = GetDC(0); + hbmp1x1 = CreateCompatibleBitmap(hdc, 1, 1); + hbmp2x2 = CreateCompatibleBitmap(hdc, 2, 2); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(hbmp1x1, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1, + bm.bmWidth, bm.bmHeight); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(hbmp2x2, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2, + bm.bmWidth, bm.bmHeight); + + hmask2x2 = CreateCompatibleBitmap(hdc, 2, 2); + ZeroMemory(&icon_info2x2, sizeof(icon_info2x2)); + icon_info2x2.fIcon = TRUE; + icon_info2x2.hbmMask = hmask2x2; + icon_info2x2.hbmColor = hbmp2x2; + hicon2x2 = CreateIconIndirect(&icon_info2x2); + ok(hicon2x2 !=NULL, "Expect CreateIconIndirect() success\n"); + + ZeroMemory(&icon_info, sizeof(icon_info)); + ok(GetIconInfo(hicon2x2, &icon_info), "Expect GetIconInfo() success\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2, + bm.bmWidth, bm.bmHeight); + DeleteObject(icon_info.hbmColor); + DeleteObject(icon_info.hbmMask); + + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, + 0, 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + /* Get image when image is not set */ + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0); + ok(hbmp == 0, "Expect hbmp == 0\n"); + /* Set image */ + hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp1x1); + ok(hbmp == 0, "Expect hbmp == 0\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0); + ok(hbmp != 0, "Expect hbmp != 0\n"); + /* Set null resets image */ + hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, 0); + ok(hbmp != 0, "Expect hbmp != 0\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0); + ok(hbmp == 0, "Expect hbmp == 0\n"); + DestroyWindow(hwnd); + + /* Set bitmap with BS_BITMAP */ + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, + 0, 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp1x1); + ok(hbmp == 0, "Expect hbmp == 0\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0); + ok(hbmp != 0, "Expect hbmp != 0\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1, + bm.bmWidth, bm.bmHeight); + DestroyWindow(hwnd); + + /* Set bitmap without BS_BITMAP */ + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp1x1); + ok(hbmp == 0, "Expect hbmp == 0\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0); + if (hbmp == 0) + { + /* on xp or 2003*/ + win_skip("Show both image and text is not supported. Skip following tests.\n"); + DestroyWindow(hwnd); + goto done; + } + ok(hbmp != 0, "Expect hbmp != 0\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1, + bm.bmWidth, bm.bmHeight); + DestroyWindow(hwnd); + + /* Set icon with BS_ICON */ + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, + 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + hicon = (HICON)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon2x2); + ok(hicon == 0, "Expect hicon == 0\n"); + hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_ICON, 0); + ok(hicon != 0, "Expect hicon != 0\n"); + ZeroMemory(&icon_info, sizeof(icon_info)); + ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2, + bm.bmWidth, bm.bmHeight); + DeleteObject(icon_info.hbmColor); + DeleteObject(icon_info.hbmMask); + DestroyWindow(hwnd); + + /* Set icon without BS_ICON */ + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + hicon = (HICON)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon2x2); + ok(hicon == 0, "Expect hicon == 0\n"); + hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_ICON, 0); + ok(hicon != 0, "Expect hicon != 0\n"); + ZeroMemory(&icon_info, sizeof(icon_info)); + ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2, + bm.bmWidth, bm.bmHeight); + DeleteObject(icon_info.hbmColor); + DeleteObject(icon_info.hbmMask); + DestroyWindow(hwnd); + + /* Set icon with BS_BITMAP */ + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, + 0, 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + hicon = (HICON)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon2x2); + ok(hicon == 0, "Expect hicon == 0\n"); + hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_ICON, 0); + ok(hicon != 0, "Expect hicon != 0\n"); + ZeroMemory(&icon_info, sizeof(icon_info)); + ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2, + bm.bmWidth, bm.bmHeight); + DeleteObject(icon_info.hbmColor); + DeleteObject(icon_info.hbmMask); + DestroyWindow(hwnd); + + /* Set bitmap with BS_ICON */ + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, + 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp1x1); + ok(hbmp == 0, "Expect hbmp == 0\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0); + ok(hbmp != 0, "Expect hbmp != 0\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1, + bm.bmWidth, bm.bmHeight); + DestroyWindow(hwnd); + + /* Set bitmap with BS_BITMAP and IMAGE_ICON*/ + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, + 0, 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hbmp1x1); + ok(hbmp == 0, "Expect hbmp == 0\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_ICON, 0); + ok(hbmp != 0, "Expect hbmp != 0\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1, + bm.bmWidth, bm.bmHeight); + DestroyWindow(hwnd); + + /* Set icon with BS_ICON and IMAGE_BITMAP */ + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, + 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + hicon = (HICON)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hicon2x2); + ok(hicon == 0, "Expect hicon == 0\n"); + hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0); + ok(hicon != 0, "Expect hicon != 0\n"); + ZeroMemory(&icon_info, sizeof(icon_info)); + ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(icon_info.hbmColor, sizeof(BITMAP), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2, + bm.bmWidth, bm.bmHeight); + DeleteObject(icon_info.hbmColor); + DeleteObject(icon_info.hbmMask); + DestroyWindow(hwnd); + + /* Set bitmap with BS_ICON and IMAGE_ICON */ + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hbmp1x1); + ok(hbmp == 0, "Expect hbmp == 0\n"); + hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_ICON, 0); + ok(hbmp != 0, "Expect hbmp != 0\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1, + bm.bmWidth, bm.bmHeight); + DestroyWindow(hwnd); + + /* Set icon with BS_BITMAP and IMAGE_BITMAP */ + hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0); + ok(hwnd != NULL, "Expect hwnd to be not NULL\n"); + hicon = (HICON)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hicon2x2); + ok(hicon == 0, "Expect hicon == 0\n"); + hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0); + ok(hicon != 0, "Expect hicon != 0\n"); + ZeroMemory(&icon_info, sizeof(icon_info)); + ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n"); + ZeroMemory(&bm, sizeof(bm)); + ok(GetObjectW(icon_info.hbmColor, sizeof(BITMAP), &bm), "Expect GetObjectW() success\n"); + ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2, + bm.bmWidth, bm.bmHeight); + DeleteObject(icon_info.hbmColor); + DeleteObject(icon_info.hbmMask); + DestroyWindow(hwnd); + +done: + DestroyIcon(hicon2x2); + DeleteObject(hmask2x2); + DeleteObject(hbmp2x2); + DeleteObject(hbmp1x1); + ReleaseDC(0, hdc); +} + static void register_parent_class(void) { WNDCLASSA cls; @@ -1054,6 +1287,7 @@ START_TEST(button) test_button_messages(); test_note(); test_button_data(); + test_bm_get_set_image(); unload_v6_module(ctx_cookie, hCtx); }