=?UTF-8?Q?Gabriel=20Iv=C4=83ncescu=20?=: comctl32/button: Implement BCM_GETIDEALSIZE for command links.

Alexandre Julliard julliard at winehq.org
Mon Apr 22 16:30:39 CDT 2019


Module: wine
Branch: master
Commit: b15859d871c50fff812c117ebc5d6eaa2e06fb5b
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=b15859d871c50fff812c117ebc5d6eaa2e06fb5b

Author: Gabriel Ivăncescu <gabrielopcode at gmail.com>
Date:   Fri Apr 19 15:14:02 2019 +0300

comctl32/button: Implement BCM_GETIDEALSIZE for command links.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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
             {




More information about the wine-cvs mailing list