Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/comctl32/tests/button.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/dlls/comctl32/tests/button.c b/dlls/comctl32/tests/button.c index f31f526..e0c4736 100644 --- a/dlls/comctl32/tests/button.c +++ b/dlls/comctl32/tests/button.c @@ -1908,7 +1908,7 @@ static void test_bcm_get_ideal_size(void) { BS_SPLITBUTTON, extra_width * 2 + GetSystemMetrics(SM_CXEDGE) }, { BS_DEFSPLITBUTTON, extra_width * 2 + GetSystemMetrics(SM_CXEDGE) } }; - LONG image_width, height, line_count, text_width; + LONG image_width = 48, height = 48, line_count, text_width; HFONT hfont, prev_font; DWORD style, type; BOOL ret; @@ -1964,6 +1964,14 @@ static void test_bcm_get_ideal_size(void) return; }
+ /* Tests for image placements */ + /* Prepare bitmap */ + hdc = GetDC(0); + hmask = CreateCompatibleBitmap(hdc, image_width, height); + hbmp = CreateCompatibleBitmap(hdc, image_width, height); + himl = pImageList_Create(image_width, height, ILC_COLOR, 1, 1); + pImageList_Add(himl, hbmp, 0); + #define set_split_info(hwnd) do { \ BUTTON_SPLITINFO _info; \ int _ret; \ @@ -1976,14 +1984,6 @@ static void test_bcm_get_ideal_size(void)
for (k = 0; k < ARRAY_SIZE(pushtype); k++) { - /* Tests for image placements */ - /* Prepare bitmap */ - image_width = 48; - height = 48; - hdc = GetDC(0); - hmask = CreateCompatibleBitmap(hdc, image_width, height); - hbmp = CreateCompatibleBitmap(hdc, image_width, height); - /* Only bitmap for push button, ideal size should be enough for image and text */ hwnd = CreateWindowA(WC_BUTTONA, button_text, pushtype[k].style | BS_BITMAP | default_style, 0, 0, client_width, client_height, NULL, NULL, 0, NULL); @@ -2028,8 +2028,6 @@ static void test_bcm_get_ideal_size(void) }
/* Image list alignments */ - himl = pImageList_Create(image_width, height, ILC_COLOR, 1, 1); - pImageList_Add(himl, hbmp, 0); biml.himl = himl; for (i = 0; i < ARRAY_SIZE(imagelist_aligns); i++) { @@ -2099,6 +2097,7 @@ static void test_bcm_get_ideal_size(void) image_width + text_width + pushtype[k].extra_width, size.cy, max(height, tm.tmHeight)); ok(size.cy < large_height, "Expect ideal cy %d < %d\n", size.cy, large_height); DestroyWindow(hwnd); + DestroyIcon(hicon); }
#undef set_split_info @@ -2215,7 +2214,6 @@ static void test_bcm_get_ideal_size(void) }
pImageList_Destroy(himl); - DestroyIcon(hicon); DeleteObject(hbmp); DeleteObject(hmask); ReleaseDC(0, hdc);
This fixes button state when it is released and the mouse is still hot-tracking it.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This is currently significant only for themed buttons, but is needed for themeless command links also.
dlls/comctl32/button.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c index 5338ef8..38e2f5d 100644 --- a/dlls/comctl32/button.c +++ b/dlls/comctl32/button.c @@ -599,7 +599,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L if (state & BST_DROPDOWNPUSHED) SendMessageW(hWnd, BCM_SETDROPDOWNSTATE, FALSE, 0); if (!(state & BUTTON_BTNPRESSED)) break; - infoPtr->state &= BUTTON_NSTATES; + infoPtr->state &= BUTTON_NSTATES | BST_HOT; if (!(state & BST_PUSHED)) { ReleaseCapture();
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
No-op patch, but is needed for command links. Also simplifies the code and removes local variables that were only used once.
dlls/comctl32/button.c | 85 +++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 47 deletions(-)
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c index 38e2f5d..baa58d8 100644 --- a/dlls/comctl32/button.c +++ b/dlls/comctl32/button.c @@ -1496,6 +1496,39 @@ static UINT BUTTON_CalcLayoutRects(const BUTTON_INFO *infoPtr, HDC hdc, RECT *la }
+/********************************************************************** + * BUTTON_DrawImage + * + * Draw the button's image into the specified rectangle. + */ +static void BUTTON_DrawImage(const BUTTON_INFO *infoPtr, HDC hdc, HBRUSH hbr, UINT flags, const RECT *rect) +{ + if (infoPtr->imagelist.himl) + { + int i = (ImageList_GetImageCount(infoPtr->imagelist.himl) == 1) ? 0 : get_draw_state(infoPtr) - 1; + + ImageList_Draw(infoPtr->imagelist.himl, i, hdc, rect->left, rect->top, ILD_NORMAL); + } + else + { + switch (infoPtr->image_type) + { + case IMAGE_ICON: + flags |= DST_ICON; + break; + case IMAGE_BITMAP: + flags |= DST_BITMAP; + break; + default: + return; + } + + DrawStateW(hdc, hbr, NULL, (LPARAM)infoPtr->u.image, 0, rect->left, rect->top, + rect->right - rect->left, rect->bottom - rect->top, flags); + } +} + + /********************************************************************** * BUTTON_DrawTextCallback * @@ -1523,71 +1556,29 @@ static BOOL CALLBACK BUTTON_DrawTextCallback(HDC hdc, LPARAM lp, WPARAM wp, int static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, const RECT *imageRect, const RECT *textRect) { - DRAWSTATEPROC lpOutputProc = NULL; - LPARAM lp; - WPARAM wp = 0; HBRUSH hbr = 0; 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; + WCHAR *text;
/* FIXME: To draw disabled label in Win31 look-and-feel, we probably * must use DSS_MONO flag and COLOR_GRAYTEXT brush (or maybe DSS_UNION). * I don't have Win31 on hand to verify that, so I leave it as is. */
- if ((style & BS_PUSHLIKE) && (state & BST_INDETERMINATE)) + if ((style & BS_PUSHLIKE) && (infoPtr->state & BST_INDETERMINATE)) { hbr = GetSysColorBrush(COLOR_GRAYTEXT); flags |= DSS_MONO; }
- if (show_image(infoPtr)) - { - 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)) BUTTON_DrawImage(infoPtr, hdc, hbr, flags, imageRect); if (show_image_only(infoPtr)) return;
/* 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, textRect->left, textRect->top, textRect->right - textRect->left, - textRect->bottom - textRect->top, flags); + DrawStateW(hdc, hbr, BUTTON_DrawTextCallback, (LPARAM)text, dtFlags, textRect->left, textRect->top, + textRect->right - textRect->left, textRect->bottom - textRect->top, flags); heap_free(text); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Command Links have hot-tracking even when they don't use a theme. The default glyph (green arrow) is used when the button has no image (bitmap/icon) or imagelist, and seems to be hardcoded (i.e. BM_GETIMAGE and BCM_GETIMAGELIST must return NULL to pass the tests).
I've added the glyph as a bitmap with 3 hardcoded states to avoid duplication, they are very close to the ones in Windows 7 in appearance. I don't know where Windows stores them but I placed them in comctl32's resources. They were created from scratch by just filling a custom-drawn arrow shape and adding a white outline + shadow to it. (I can supply the 1024x1024 original image before I downsampled it, if that's needed)
Note that the glyphs are 17x17, which seems weird, but it is the exact size required to fit the alignment on Windows. I've been setting an image with BM_SETIMAGE on Windows and comparing to see the button's text alignment, only a 17x17 image properly aligned the text. They are always 17x17, even if the app is DPI aware and the font is larger.
Lastly the "disabled" state of the glyph is white with 50% transparency (no shadow but a dark outline). When changing the background color on Windows, this is what's needed to match it.
Note that this bitmap glyph is only used when there's no theme. Themes use BP_COMMANDLINKGLYPH to draw the default glyph and it looks differently. And it also works with BCCL_NOGLYPH in the button's image list (invalid ImageList with size 0).
dlls/comctl32/button.c | 191 +++++++++++++++++++++++++++++++++- dlls/comctl32/comctl32.h | 3 + dlls/comctl32/comctl32.rc | 3 + dlls/comctl32/idb_cmdlink.bmp | Bin 0 -> 3522 bytes 4 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 dlls/comctl32/idb_cmdlink.bmp
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c index baa58d8..4f2fbce 100644 --- a/dlls/comctl32/button.c +++ b/dlls/comctl32/button.c @@ -105,6 +105,7 @@ static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ); static void UB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ); static void OB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ); static void SB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ); +static void CL_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ); static void BUTTON_CheckAutoRadioButton( HWND hwnd ); static void get_split_button_rects(const BUTTON_INFO*, const RECT*, RECT*, RECT*); static BOOL notify_split_button_dropdown(const BUTTON_INFO*, const POINT*, HWND); @@ -161,8 +162,8 @@ static const pfPaint btnPaintFunc[MAX_BTN_TYPE] = OB_Paint, /* BS_OWNERDRAW */ SB_Paint, /* BS_SPLITBUTTON */ SB_Paint, /* BS_DEFSPLITBUTTON */ - PB_Paint, /* BS_COMMANDLINK */ - PB_Paint /* BS_DEFCOMMANDLINK */ + CL_Paint, /* BS_COMMANDLINK */ + CL_Paint /* BS_DEFCOMMANDLINK */ };
typedef void (*pfThemedPaint)( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, int drawState, UINT dtflags, BOOL focused); @@ -219,6 +220,12 @@ static const pfGetIdealSize btnGetIdealSizeFunc[MAX_BTN_TYPE] = { PB_GetIdealSize /* BS_DEFCOMMANDLINK */ };
+/* Fixed margin for command links, regardless of DPI (based on tests done on Windows) */ +enum { command_link_margin = 6 }; + +/* The width and height for the default command link glyph (when there's no image) */ +enum { command_link_defglyph_size = 17 }; + static inline UINT get_button_type( LONG window_style ) { return (window_style & BS_TYPEMASK); @@ -2297,6 +2304,186 @@ static void draw_split_button_dropdown_glyph(const BUTTON_INFO *infoPtr, HDC hdc }
+/********************************************************************** + * Command Link Functions + */ +static void CL_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action ) +{ + LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + LONG state = infoPtr->state; + + RECT rc, content_rect; + NMCUSTOMDRAW nmcd; + HPEN pen, old_pen; + HBRUSH old_brush; + INT old_bk_mode; + LRESULT cdrf; + HWND parent; + HRGN hrgn; + + GetClientRect(infoPtr->hwnd, &rc); + + /* Command Links are not affected by the button's font, and are based + on the default message font. Furthermore, they are not affected by + any of the alignment styles (and always align with the top-left). */ + if (!(parent = GetParent(infoPtr->hwnd))) parent = infoPtr->hwnd; + SendMessageW(parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)infoPtr->hwnd); + + hrgn = set_control_clipping(hDC, &rc); + + pen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME)); + old_pen = SelectObject(hDC, pen); + old_brush = SelectObject(hDC, GetSysColorBrush(COLOR_BTNFACE)); + old_bk_mode = 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; + content_rect = rc; + + if (get_button_type(style) == BS_DEFCOMMANDLINK) + { + if (action != ODA_FOCUS) + Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom); + InflateRect(&rc, -1, -1); + } + + /* Skip the frame drawing if only focus has changed */ + if (action != ODA_FOCUS) + { + if (!(state & (BST_HOT | BST_PUSHED | BST_CHECKED | BST_INDETERMINATE))) + FillRect(hDC, &rc, GetSysColorBrush(COLOR_BTNFACE)); + else + { + UINT flags = DFCS_BUTTONPUSH; + + if (style & BS_FLAT) flags |= DFCS_MONO; + else if (state & BST_PUSHED) flags |= DFCS_PUSHED; + + if (state & (BST_CHECKED | BST_INDETERMINATE)) + flags |= DFCS_CHECKED; + DrawFrameControl(hDC, &rc, DFC_BUTTON, flags); + } + } + + if (cdrf & CDRF_NOTIFYPOSTERASE) + { + nmcd.dwDrawStage = CDDS_POSTERASE; + SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd); + } + + /* Send paint notifications */ + nmcd.dwDrawStage = CDDS_PREPAINT; + cdrf = SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd); + if (cdrf & CDRF_SKIPDEFAULT) goto cleanup; + + if (!(cdrf & CDRF_DOERASE) && action != ODA_FOCUS) + { + UINT flags = IsWindowEnabled(infoPtr->hwnd) ? DSS_NORMAL : DSS_DISABLED; + COLORREF old_color = SetTextColor(hDC, GetSysColor(flags == DSS_NORMAL ? + COLOR_BTNTEXT : COLOR_GRAYTEXT)); + HIMAGELIST defimg = NULL; + NONCLIENTMETRICSW ncm; + UINT txt_h = 0; + SIZE img_size; + + /* Command Links ignore the margins of the image list or its alignment */ + if (infoPtr->u.image || infoPtr->imagelist.himl) + img_size = BUTTON_GetImageSize(infoPtr); + else + { + img_size.cx = img_size.cy = command_link_defglyph_size; + defimg = ImageList_LoadImageW(COMCTL32_hModule, (LPCWSTR)MAKEINTRESOURCE(IDB_CMDLINK), + img_size.cx, 3, CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION); + } + + /* Shrink rect by the command link margin, except on bottom (just the frame) */ + InflateRect(&content_rect, -command_link_margin, -command_link_margin); + content_rect.bottom += command_link_margin - 2; + + ncm.cbSize = sizeof(ncm); + if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)) + { + LONG note_weight = ncm.lfMessageFont.lfWeight; + RECT r = content_rect; + WCHAR *text; + HFONT font; + + if (img_size.cx) r.left += img_size.cx + command_link_margin; + + /* Draw the text */ + ncm.lfMessageFont.lfWeight = FW_BOLD; + if ((font = CreateFontIndirectW(&ncm.lfMessageFont))) + { + if ((text = get_button_text(infoPtr))) + { + SelectObject(hDC, font); + txt_h = DrawTextW(hDC, text, -1, &r, + DT_TOP | DT_LEFT | DT_WORDBREAK | DT_END_ELLIPSIS); + heap_free(text); + } + DeleteObject(font); + } + + /* Draw the note */ + ncm.lfMessageFont.lfWeight = note_weight; + if (infoPtr->note && (font = CreateFontIndirectW(&ncm.lfMessageFont))) + { + r.top += txt_h + 2; + SelectObject(hDC, font); + DrawTextW(hDC, infoPtr->note, infoPtr->note_length, &r, + DT_TOP | DT_LEFT | DT_WORDBREAK | DT_NOPREFIX); + DeleteObject(font); + } + } + + /* Position the image at the vertical center of the drawn text (not note) */ + txt_h = min(txt_h, content_rect.bottom - content_rect.top); + if (img_size.cy < txt_h) content_rect.top += (txt_h - img_size.cy) / 2; + + content_rect.right = content_rect.left + img_size.cx; + content_rect.bottom = content_rect.top + img_size.cy; + + if (defimg) + { + int i = 0; + if (flags == DSS_DISABLED) i = 2; + else if (state & BST_HOT) i = 1; + + ImageList_Draw(defimg, i, hDC, content_rect.left, content_rect.top, ILD_NORMAL); + ImageList_Destroy(defimg); + } + else + BUTTON_DrawImage(infoPtr, hDC, NULL, flags, &content_rect); + + SetTextColor(hDC, old_color); + } + + if (cdrf & CDRF_NOTIFYPOSTPAINT) + { + nmcd.dwDrawStage = CDDS_POSTPAINT; + SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd); + } + if (cdrf & CDRF_SKIPPOSTPAINT) goto cleanup; + + if (action == ODA_FOCUS || (state & BST_FOCUS)) + { + InflateRect(&rc, -2, -2); + DrawFocusRect(hDC, &rc); + } + +cleanup: + SelectObject(hDC, old_pen); + SelectObject(hDC, old_brush); + SetBkMode(hDC, old_bk_mode); + SelectClipRgn(hDC, hrgn); + if (hrgn) DeleteObject(hrgn); + DeleteObject(pen); +} + + /********************************************************************** * Themed Paint Functions */ diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h index b68b914..f3e889c 100644 --- a/dlls/comctl32/comctl32.h +++ b/dlls/comctl32/comctl32.h @@ -80,6 +80,9 @@ extern HBRUSH COMCTL32_hPattern55AABrush DECLSPEC_HIDDEN;
#define IDT_CHECK 401
+/* Command Link arrow */ +#define IDB_CMDLINK 402 +
/* Cursors */ #define IDC_MOVEBUTTON 102 diff --git a/dlls/comctl32/comctl32.rc b/dlls/comctl32/comctl32.rc index 3f8e148..c9aa1ba 100644 --- a/dlls/comctl32/comctl32.rc +++ b/dlls/comctl32/comctl32.rc @@ -144,6 +144,9 @@ IDB_HIST_SMALL BITMAP idb_hist_small.bmp /* @makedep: idb_hist_large.bmp */ IDB_HIST_LARGE BITMAP idb_hist_large.bmp
+/* @makedep: idb_cmdlink.bmp */ +IDB_CMDLINK BITMAP idb_cmdlink.bmp + /* @makedep: idc_copy.cur */ IDC_COPY CURSOR idc_copy.cur
diff --git a/dlls/comctl32/idb_cmdlink.bmp b/dlls/comctl32/idb_cmdlink.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4b3f07b3aae4259a653d8de2efa12ec413dcb252 GIT binary patch literal 3522 zcmb`JX-rgC6vr<v#T9L-Ye|7-OwdS!3&wsZG`3b-H9|tQe5h^B5SWw+`_dUekl+$a zM{R?9v`TH7mRPjZ#3CA7M8Y-*4pS?XfDR56l>M>2)Bk<ro6HEzV9H5;@4ol$z5jR4 zJ9pc#?bci-**aW(z#8x}aA97!GWHef-Dg{nUW|X4f-0`&1y+Og;7zauxB?g8%qBy_ z**7LqKLd@t!P{Uf*bY7b{$MGXNIa9FflvJ}b15h&@G}~XXP-QI($Lk_WhyT(zXHWz zz~fm97J=ztJev#+t9EQ`?DD9nsDPN5n3>j>j&Jz5;r`7s7!0uk0|OmtW+nMOaHXp5 z+d^e!<!`9t@oWZuz#U8lwl+#5T~N~6URTl&OjyHKk0mB1t|~1pJqv%n%gM<}i-?Gr zXV<{~LH@oQUVDUugsf|BZq9EVGKoI-82K11)b;55@7%d_32lPFMz9jh2Yg<Pts$Dk zl}{P1?6goPIMjg5Xw&I*aiS=m04d;Dc6PQ_rBd;4j%7S=uK_-{13W!Fw_!~EgnlC_ z&0(~xg3+=nMr-cQr+@p*-Pf*NJCAleo_7IXV)z<?6=iIVw4N~XX~q8l{%z0@#?^qt zXhU9nD=I3o;ZG(=6$IgUYHF%#bW7>Y5`{t$c<$V}eT|Kcr6!Z9wxgrtpP`{40exv_ zO#pcpGl|VrzSP~_-E!v4nQZjr>p=i`o#RL&)Eq#HCML0^Wn2x&SPcK&4R}OGMlMz= zm99ZSL7@!|4PV2bbg;*4HlM=W*(tY|%c7zpWm{WYjW8he<}@A@zci|7&tK7$Qm3W^ z_ci2y%Y!_AXI6IWw~LP-KQ=%s0UCVnEYHu+|3cCj6nc-h9~8A_6=k$WQ<_;#2U|6? zzQKb$?=vgPN24`lf0C1vw-go@W@Bs|!kFe9C@wBe!5YNlkjbd4t2?DutKXCR@v^_a z-*DoAPJHKvFD<^zBo^f}vf~##+n}jd4`Y2OLU$g^ir(H{<H=T?xWVX4ORJd$JxT{? zo9#8YFB*;JeT<8X@OdBD3;4L=@OwE9DK~h|Dk&*B5gi@P=Z0h>BO^}_-`h`XE-UDj z@7aWiEsda-mX;a_1OhKf<KcetuTYRX#^bBEofBVgufd(sYPDOD-yfd&pYbdP9tXdF zK9;@6-D!*uek70#^Wrkv4G6;mrIjYp=hs6i;^t=*esdS8{|uuyau?FvQ_R9iMq3Lu z(BR-;Pgz;n1qdt$Zg{>TX^cSQ?<Cq?6H2Ok&@k+xC}S8Y{#Z!!t}`p!Do1NrypiJh z2xID-+S=M9)z#I9^?JRos;Vj-x!+?OPknv;Y2<|O<5oi~tKdu4@bGXg+V+DXFbIYL zZTvZqW*lJ>K4-lNIT&neYAVM6*aQ)NM4IYMV^c{W&H9zmtO7<WZj7yAbqF_@_lq#^ zmtj75hlhu|1qTOz4Bz=$#&eT~J^W-sLc*uEedK%8&&FO9h`AHf+1aTD1@KwW6eZL2 z1B|ADIfq=y)b&VgZ*MmqJ$m#L^j!d^In}rejXWkX=Mpsf#@CRwY)km8K%Vx)$1IQv zzj87&Gh=MqjCYSU*B$xHHFcRpmkdTO=@!Z!m5EqOnsak=Bhi<iF<)}3(Pt8;Ttxq8 zl(kP>L)Lz7ulyFa7rB}t*E=c^`%L8MFv^h~Kkguw%BZluQ0(dHG3DjuC896iR~?=$ z?KEyd;{r5VUQ9#wF)1nOEzFzq&^(WQZ6D&`<6**v@gIU*Ht=|W*w@$h@aom8aS-5V zWd2Y1nZ=<^hKBrsxVX60@$vB=;(Y1oEG9R%E8+eE?hDQfSr}J3?76$pfS=d+xN;f? M7n=+XuJa=HAE4=@9{>OV
literal 0 HcmV?d00001
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
On 4/19/19 3:14 PM, Gabriel Ivăncescu wrote:
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
Command Links have hot-tracking even when they don't use a theme. The default glyph (green arrow) is used when the button has no image (bitmap/icon) or imagelist, and seems to be hardcoded (i.e. BM_GETIMAGE and BCM_GETIMAGELIST must return NULL to pass the tests).
I've added the glyph as a bitmap with 3 hardcoded states to avoid duplication, they are very close to the ones in Windows 7 in appearance. I don't know where Windows stores them but I placed them in comctl32's resources. They were created from scratch by just filling a custom-drawn arrow shape and adding a white outline + shadow to it. (I can supply the 1024x1024 original image before I downsampled it, if that's needed)
Please create a bug report for command link support, if we don't have one yet, and attach your original image file there so it's not lost.
On 4/22/19 4:53 PM, Nikolay Sivov wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
On 4/19/19 3:14 PM, Gabriel Ivăncescu wrote:
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
Command Links have hot-tracking even when they don't use a theme. The default glyph (green arrow) is used when the button has no image (bitmap/icon) or imagelist, and seems to be hardcoded (i.e. BM_GETIMAGE and BCM_GETIMAGELIST must return NULL to pass the tests).
I've added the glyph as a bitmap with 3 hardcoded states to avoid duplication, they are very close to the ones in Windows 7 in appearance. I don't know where Windows stores them but I placed them in comctl32's resources. They were created from scratch by just filling a custom-drawn arrow shape and adding a white outline + shadow to it. (I can supply the 1024x1024 original image before I downsampled it, if that's needed)
Please create a bug report for command link support, if we don't have one yet, and attach your original image file there so it's not lost.
Thanks, I will do that. I only have the "normal" state as 1024x1024 (first image in the bitmap), would that be enough? If not I can re-create the other states as 1024x1024 (just have to change the filling gradient and the outline color, also remove the shadow on the disabled state, shouldn't be a problem).
On 4/22/19 6:51 PM, Gabriel Ivăncescu wrote:
On 4/22/19 4:53 PM, Nikolay Sivov wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
On 4/19/19 3:14 PM, Gabriel Ivăncescu wrote:
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
Command Links have hot-tracking even when they don't use a theme. The default glyph (green arrow) is used when the button has no image (bitmap/icon) or imagelist, and seems to be hardcoded (i.e. BM_GETIMAGE and BCM_GETIMAGELIST must return NULL to pass the tests).
I've added the glyph as a bitmap with 3 hardcoded states to avoid duplication, they are very close to the ones in Windows 7 in appearance. I don't know where Windows stores them but I placed them in comctl32's resources. They were created from scratch by just filling a custom-drawn arrow shape and adding a white outline + shadow to it. (I can supply the 1024x1024 original image before I downsampled it, if that's needed)
Please create a bug report for command link support, if we don't have one yet, and attach your original image file there so it's not lost.
Thanks, I will do that. I only have the "normal" state as 1024x1024 (first image in the bitmap), would that be enough? If not I can re-create the other states as 1024x1024 (just have to change the filling gradient and the outline color, also remove the shadow on the disabled state, shouldn't be a problem).
I submitted the bug here: https://bugs.winehq.org/show_bug.cgi?id=47063
Let me know if I have to recreate the other states, I'll do it tomorrow if so.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
To avoid differences between themes (and because I didn't have a theme that supported command links), this has been verified to be very close to Windows 7 by subclassing a button on a Windows test app and using this function to paint it, then comparing with Windows' own command link. Most of the margin and font calculations were, to my knowledge, pixel perfect even on different DPI settings, but for some reason the background was slightly different in color (which isn't a big deal, since the code is displaying the theme's BP_COMMANDLINK background, so maybe it's a Windows 7 bug here).
dlls/comctl32/button.c | 128 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-)
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c index 4f2fbce..37212fb 100644 --- a/dlls/comctl32/button.c +++ b/dlls/comctl32/button.c @@ -172,6 +172,7 @@ static void PB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, i static void CB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, int drawState, UINT dtflags, BOOL focused); static void GB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, int drawState, UINT dtflags, BOOL focused); static void SB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, int drawState, UINT dtflags, BOOL focused); +static void CL_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, int drawState, UINT dtflags, BOOL focused);
static const pfThemedPaint btnThemedPaintFunc[MAX_BTN_TYPE] = { @@ -189,8 +190,8 @@ static const pfThemedPaint btnThemedPaintFunc[MAX_BTN_TYPE] = NULL, /* BS_OWNERDRAW */ SB_ThemedPaint, /* BS_SPLITBUTTON */ SB_ThemedPaint, /* BS_DEFSPLITBUTTON */ - NULL, /* BS_COMMANDLINK */ - NULL, /* BS_DEFCOMMANDLINK */ + CL_ThemedPaint, /* BS_COMMANDLINK */ + CL_ThemedPaint /* BS_DEFCOMMANDLINK */ };
typedef BOOL (*pfGetIdealSize)(BUTTON_INFO *infoPtr, SIZE *size); @@ -2820,6 +2821,129 @@ cleanup: if (old_font) SelectObject(hDC, old_font); }
+static void CL_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, int state, UINT dtFlags, BOOL focused) +{ + HFONT old_font = infoPtr->font ? SelectObject(hDC, infoPtr->font) : NULL; + NMCUSTOMDRAW nmcd; + LRESULT cdrf; + HWND parent; + RECT rc; + + GetClientRect(infoPtr->hwnd, &rc); + init_custom_draw(&nmcd, infoPtr, hDC, &rc); + + parent = GetParent(infoPtr->hwnd); + if (!parent) parent = infoPtr->hwnd; + + /* Send erase notifications */ + cdrf = SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd); + if (cdrf & CDRF_SKIPDEFAULT) goto cleanup; + + if (IsThemeBackgroundPartiallyTransparent(theme, BP_COMMANDLINK, state)) + DrawThemeParentBackground(infoPtr->hwnd, hDC, NULL); + DrawThemeBackground(theme, hDC, BP_COMMANDLINK, state, &rc, NULL); + + if (cdrf & CDRF_NOTIFYPOSTERASE) + { + nmcd.dwDrawStage = CDDS_POSTERASE; + SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd); + } + + /* Send paint notifications */ + nmcd.dwDrawStage = CDDS_PREPAINT; + cdrf = SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd); + if (cdrf & CDRF_SKIPDEFAULT) goto cleanup; + + if (!(cdrf & CDRF_DOERASE)) + { + RECT r, img_rect; + UINT txt_h = 0; + SIZE img_size; + WCHAR *text; + + GetThemeBackgroundContentRect(theme, hDC, BP_COMMANDLINK, state, &rc, &r); + + /* The text alignment and styles are fixed and don't depend on button styles */ + dtFlags = DT_TOP | DT_LEFT | DT_WORDBREAK; + + /* Command Links ignore the margins of the image list or its alignment */ + if (infoPtr->u.image || infoPtr->imagelist.himl) + img_size = BUTTON_GetImageSize(infoPtr); + else + GetThemePartSize(theme, NULL, BP_COMMANDLINKGLYPH, state, NULL, TS_DRAW, &img_size); + + img_rect = r; + if (img_size.cx) r.left += img_size.cx + command_link_margin; + + /* Draw the text */ + if ((text = get_button_text(infoPtr))) + { + UINT len = lstrlenW(text); + RECT text_rect; + + GetThemeTextExtent(theme, hDC, BP_COMMANDLINK, state, text, len, + dtFlags | DT_END_ELLIPSIS, &r, &text_rect); + DrawThemeText(theme, hDC, BP_COMMANDLINK, state, text, len, + dtFlags | DT_END_ELLIPSIS, 0, &r); + + txt_h = text_rect.bottom - text_rect.top; + heap_free(text); + } + + /* Draw the note */ + if (infoPtr->note) + { + DTTOPTS opts; + + r.top += txt_h; + opts.dwSize = sizeof(opts); + opts.dwFlags = DTT_FONTPROP; + opts.iFontPropId = TMT_BODYFONT; + DrawThemeTextEx(theme, hDC, BP_COMMANDLINK, state, + infoPtr->note, infoPtr->note_length, + dtFlags | DT_NOPREFIX, &r, &opts); + } + + /* Position the image at the vertical center of the drawn text (not note) */ + txt_h = min(txt_h, img_rect.bottom - img_rect.top); + if (img_size.cy < txt_h) img_rect.top += (txt_h - img_size.cy) / 2; + + img_rect.right = img_rect.left + img_size.cx; + img_rect.bottom = img_rect.top + img_size.cy; + + if (infoPtr->u.image || infoPtr->imagelist.himl) + BUTTON_DrawImage(infoPtr, hDC, NULL, + (state == CMDLS_DISABLED) ? DSS_DISABLED : DSS_NORMAL, + &img_rect); + else + DrawThemeBackground(theme, hDC, BP_COMMANDLINKGLYPH, state, &img_rect, NULL); + } + + if (cdrf & CDRF_NOTIFYPOSTPAINT) + { + nmcd.dwDrawStage = CDDS_POSTPAINT; + SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd); + } + if (cdrf & CDRF_SKIPPOSTPAINT) goto cleanup; + + if (focused) + { + MARGINS margins; + + /* The focus rect has margins of a push button rather than command link... */ + GetThemeMargins(theme, hDC, BP_PUSHBUTTON, state, TMT_CONTENTMARGINS, NULL, &margins); + + rc.left += margins.cxLeftWidth; + rc.top += margins.cyTopHeight; + rc.right -= margins.cxRightWidth; + rc.bottom -= margins.cyBottomHeight; + DrawFocusRect(hDC, &rc); + } + +cleanup: + if (old_font) SelectObject(hDC, old_font); +} + void BUTTON_Register(void) { WNDCLASSW wndClass;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Command Links seem to have weird behavior with BCM_GETIDEALSIZE (as evidenced by tests on this and the next patch) and the ideal size *does* depend on the theme. This is exact as on Windows in what testing I did with reasonably-sized fonts (there may be extreme corner cases I didn't bother to check).
dlls/comctl32/button.c | 137 ++++++++++++++++++++++++++++++++++- dlls/comctl32/tests/button.c | 10 +-- 2 files changed, 139 insertions(+), 8 deletions(-)
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c index 37212fb..0a8bdf1 100644 --- a/dlls/comctl32/button.c +++ b/dlls/comctl32/button.c @@ -200,6 +200,7 @@ static BOOL PB_GetIdealSize(BUTTON_INFO *infoPtr, SIZE *size); static BOOL CB_GetIdealSize(BUTTON_INFO *infoPtr, SIZE *size); static BOOL GB_GetIdealSize(BUTTON_INFO *infoPtr, SIZE *size); static BOOL SB_GetIdealSize(BUTTON_INFO *infoPtr, SIZE *size); +static BOOL CL_GetIdealSize(BUTTON_INFO *infoPtr, SIZE *size);
static const pfGetIdealSize btnGetIdealSizeFunc[MAX_BTN_TYPE] = { PB_GetIdealSize, /* BS_PUSHBUTTON */ @@ -216,9 +217,8 @@ static const pfGetIdealSize btnGetIdealSizeFunc[MAX_BTN_TYPE] = { GB_GetIdealSize, /* BS_OWNERDRAW */ SB_GetIdealSize, /* BS_SPLITBUTTON */ SB_GetIdealSize, /* BS_DEFSPLITBUTTON */ - /* GetIdealSize() for following types are unimplemented, use BS_PUSHBUTTON's for now */ - PB_GetIdealSize, /* BS_COMMANDLINK */ - PB_GetIdealSize /* BS_DEFCOMMANDLINK */ + CL_GetIdealSize, /* BS_COMMANDLINK */ + CL_GetIdealSize /* BS_DEFCOMMANDLINK */ };
/* Fixed margin for command links, regardless of DPI (based on tests done on Windows) */ @@ -1363,6 +1363,137 @@ static BOOL SB_GetIdealSize(BUTTON_INFO *infoPtr, SIZE *size) return TRUE; }
+static BOOL CL_GetIdealSize(BUTTON_INFO *infoPtr, SIZE *size) +{ + HTHEME theme = GetWindowTheme(infoPtr->hwnd); + HDC hdc = GetDC(infoPtr->hwnd); + LONG w, text_w = 0, text_h = 0; + UINT flags = DT_TOP | DT_LEFT; + HFONT font, old_font = NULL; + RECT text_bound = { 0 }; + SIZE img_size; + RECT margin; + WCHAR *text; + + /* Get the image size */ + if (infoPtr->u.image || infoPtr->imagelist.himl) + img_size = BUTTON_GetImageSize(infoPtr); + else + { + if (theme) + GetThemePartSize(theme, NULL, BP_COMMANDLINKGLYPH, CMDLS_NORMAL, NULL, TS_DRAW, &img_size); + else + img_size.cx = img_size.cy = command_link_defglyph_size; + } + + /* Get the content margins */ + if (theme) + { + RECT r = { 0, 0, 0xffff, 0xffff }; + GetThemeBackgroundContentRect(theme, hdc, BP_COMMANDLINK, CMDLS_NORMAL, &r, &margin); + margin.left -= r.left; + margin.top -= r.top; + margin.right = r.right - margin.right; + margin.bottom = r.bottom - margin.bottom; + } + else + { + margin.left = margin.right = command_link_margin; + margin.top = margin.bottom = command_link_margin; + } + + /* Account for the border margins and the margin between image and text */ + w = margin.left + margin.right + (img_size.cx ? (img_size.cx + command_link_margin) : 0); + + /* If a rectangle with a specific width was requested, bound the text to it */ + if (size->cx > w) + { + text_bound.right = size->cx - w; + flags |= DT_WORDBREAK; + } + + if (theme) + { + if (infoPtr->font) old_font = SelectObject(hdc, infoPtr->font); + + /* Find the text's rect */ + if ((text = get_button_text(infoPtr))) + { + RECT r; + GetThemeTextExtent(theme, hdc, BP_COMMANDLINK, CMDLS_NORMAL, + text, -1, flags, &text_bound, &r); + heap_free(text); + text_w = r.right - r.left; + text_h = r.bottom - r.top; + } + + /* Find the note's rect */ + if (infoPtr->note) + { + DTTOPTS opts; + + opts.dwSize = sizeof(opts); + opts.dwFlags = DTT_FONTPROP | DTT_CALCRECT; + opts.iFontPropId = TMT_BODYFONT; + DrawThemeTextEx(theme, hdc, BP_COMMANDLINK, CMDLS_NORMAL, + infoPtr->note, infoPtr->note_length, + flags | DT_NOPREFIX | DT_CALCRECT, &text_bound, &opts); + text_w = max(text_w, text_bound.right - text_bound.left); + text_h += text_bound.bottom - text_bound.top; + } + } + else + { + NONCLIENTMETRICSW ncm; + + ncm.cbSize = sizeof(ncm); + if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)) + { + LONG note_weight = ncm.lfMessageFont.lfWeight; + + /* Find the text's rect */ + ncm.lfMessageFont.lfWeight = FW_BOLD; + if ((font = CreateFontIndirectW(&ncm.lfMessageFont))) + { + if ((text = get_button_text(infoPtr))) + { + RECT r = text_bound; + old_font = SelectObject(hdc, font); + DrawTextW(hdc, text, -1, &r, flags | DT_CALCRECT); + heap_free(text); + + text_w = r.right - r.left; + text_h = r.bottom - r.top; + } + DeleteObject(font); + } + + /* Find the note's rect */ + ncm.lfMessageFont.lfWeight = note_weight; + if (infoPtr->note && (font = CreateFontIndirectW(&ncm.lfMessageFont))) + { + HFONT tmp = SelectObject(hdc, font); + if (!old_font) old_font = tmp; + + DrawTextW(hdc, infoPtr->note, infoPtr->note_length, &text_bound, + flags | DT_NOPREFIX | DT_CALCRECT); + DeleteObject(font); + + text_w = max(text_w, text_bound.right - text_bound.left); + text_h += text_bound.bottom - text_bound.top + 2; + } + } + } + w += text_w; + + size->cx = min(size->cx, w); + size->cy = max(text_h, img_size.cy) + margin.top + margin.bottom; + + if (old_font) SelectObject(hdc, old_font); + ReleaseDC(infoPtr->hwnd, hdc); + return TRUE; +} + /********************************************************************** * BUTTON_CalcLayoutRects * diff --git a/dlls/comctl32/tests/button.c b/dlls/comctl32/tests/button.c index e0c4736..c31603f 100644 --- a/dlls/comctl32/tests/button.c +++ b/dlls/comctl32/tests/button.c @@ -2162,8 +2162,8 @@ static void test_bcm_get_ideal_size(void)
if (type == BS_COMMANDLINK || type == BS_DEFCOMMANDLINK) { - todo_wine ok((size.cx == 0 && size.cy > 0), "Style 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", - style, size.cx, 0, size.cy, 0); + ok((size.cx == 0 && size.cy > 0), "Style 0x%08x expect ideal cx %d == %d and ideal cy %d > %d\n", + style, size.cx, 0, size.cy, 0); } else { @@ -2199,9 +2199,9 @@ static void test_bcm_get_ideal_size(void) } else if (type == BS_COMMANDLINK || type == BS_DEFCOMMANDLINK) { - todo_wine ok((size.cx == 0 && size.cy > 0), - "Style 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style, size.cx, 0, - size.cy, 0); + ok((size.cx == 0 && size.cy > 0), + "Style 0x%08x expect ideal cx %d == %d and ideal cy %d > %d\n", style, size.cx, 0, + size.cy, 0); } else {
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/comctl32/tests/button.c | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+)
diff --git a/dlls/comctl32/tests/button.c b/dlls/comctl32/tests/button.c index c31603f..e7789dc 100644 --- a/dlls/comctl32/tests/button.c +++ b/dlls/comctl32/tests/button.c @@ -1890,6 +1890,12 @@ static void test_bcm_get_ideal_size(void) { static const char *button_text2 = "WWWW\nWWWW"; static const char *button_text = "WWWW"; + static const WCHAR button_note_short[] = { 'W',0 }; + static const WCHAR button_note_long[] = { 'W','W','W','W','W','W','W','W','W','W','W','W','W','W','W','W',0 }; + static const WCHAR button_note_wordy[] = { 'T','h','i','s',' ','i','s',' ','a',' ','l','o','n','g',' ','n','o','t','e',' ','f','o','r',' ','t','h','e',' ','b','u','t','t','o','n',',',' ', + 'w','i','t','h',' ','m','a','n','y',' ','w','o','r','d','s',',',' ','w','h','i','c','h',' ','s','h','o','u','l','d',' ','b','e',' ', + 'o','v','e','r','a','l','l',' ','l','o','n','g','e','r',' ','t','h','a','n',' ','t','h','e',' ','t','e','x','t',' ','(','g','i','v','e','n',' ', + 't','h','e',' ','s','m','a','l','l','e','r',' ','f','o','n','t',')',' ','a','n','d',' ','t','h','u','s',' ','w','r','a','p','.',0 }; static const DWORD imagelist_aligns[] = {BUTTON_IMAGELIST_ALIGN_LEFT, BUTTON_IMAGELIST_ALIGN_RIGHT, BUTTON_IMAGELIST_ALIGN_TOP, BUTTON_IMAGELIST_ALIGN_BOTTOM, BUTTON_IMAGELIST_ALIGN_CENTER}; @@ -2213,6 +2219,57 @@ static void test_bcm_get_ideal_size(void) } }
+ /* Command Link with note */ + hwnd = CreateWindowA(WC_BUTTONA, "a", style, 0, 0, client_width, client_height, NULL, NULL, 0, NULL); + ok(hwnd != NULL, "Expected hwnd not NULL\n"); + SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp); + ret = SendMessageA(hwnd, BCM_SETNOTE, 0, (LPARAM)button_note_short); + ok(ret == TRUE, "Expected BCM_SETNOTE to return true\n"); + size.cx = 13; + size.cy = 0; + ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size); + ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n"); + ok(size.cx == 13 && size.cy > 0, "Expected ideal cx %d == %d and ideal cy %d > %d\n", size.cx, 13, size.cy, 0); + height = size.cy; + size.cx = 32767; + size.cy = 7; + ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size); + ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n"); + ok(size.cx < 32767, "Expected ideal cx to have been adjusted\n"); + ok(size.cx > image_width && size.cy == height, "Expected ideal cx %d > %d and ideal cy %d == %d\n", size.cx, image_width, size.cy, height); + + /* Try longer note without word breaks, shouldn't extend height because no word splitting */ + ret = SendMessageA(hwnd, BCM_SETNOTE, 0, (LPARAM)button_note_long); + ok(ret == TRUE, "Expected BCM_SETNOTE to return true\n"); + k = size.cx; + size.cy = 0; + ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size); + ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n"); + ok(size.cx == k && size.cy == height, "Expected ideal cx %d == %d and ideal cy %d == %d\n", size.cx, k, size.cy, height); + + /* Now let it extend the width */ + size.cx = 32767; + size.cy = 0; + ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size); + ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n"); + ok(size.cx > k && size.cy == height, "Expected ideal cx %d > %d and ideal cy %d == %d\n", size.cx, k, size.cy, height); + + /* Use a very long note with words and the same width, should extend the height due to word wrap */ + ret = SendMessageA(hwnd, BCM_SETNOTE, 0, (LPARAM)button_note_wordy); + ok(ret == TRUE, "Expected BCM_SETNOTE to return true\n"); + k = size.cx; + ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size); + ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n"); + ok(size.cx <= k && size.cy > height, "Expected ideal cx %d <= %d and ideal cy %d > %d\n", size.cx, k, size.cy, height); + + /* Now try the wordy note with a width smaller than the image itself, which prevents wrapping */ + size.cx = 13; + ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size); + ok(ret == TRUE, "Expected BCM_GETIDEALSIZE message to return true\n"); + ok(size.cx == 13 && size.cy == height, "Expected ideal cx %d == %d and ideal cy %d == %d\n", size.cx, 13, size.cy, height); + DestroyWindow(hwnd); + + pImageList_Destroy(himl); DeleteObject(hbmp); DeleteObject(hmask);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com