[PATCH 2/7] comctl32/taskdialog: Use dynamic resizing.

Nikolay Sivov nsivov at codeweavers.com
Thu May 17 10:54:56 CDT 2018


On 05/16/2018 07:14 PM, Zhiyi Zhang wrote:

> Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
> ---
>   dlls/comctl32/taskdialog.c | 476 +++++++++++++++++++++----------------
>   1 file changed, 268 insertions(+), 208 deletions(-)
>
> diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
> index 1ab9e133da..4fdea1e889 100644
> --- a/dlls/comctl32/taskdialog.c
> +++ b/dlls/comctl32/taskdialog.c
> @@ -2,6 +2,7 @@
>    * Task dialog control
>    *
>    * Copyright 2017 Fabian Maurer
> + * Copyright 2018 Zhiyi Zhang
>    *
>    * This library is free software; you can redistribute it and/or
>    * modify it under the terms of the GNU Lesser General Public
> @@ -71,37 +72,23 @@ struct taskdialog_button_desc
>   struct taskdialog_template_desc
>   {
>       const TASKDIALOGCONFIG *taskconfig;
> -    unsigned int dialog_height;
> -    unsigned int dialog_width;
>       struct list controls;
>       WORD control_count;
> -    LONG x_baseunit;
> -    LONG y_baseunit;
> -    HFONT font;
> -    struct taskdialog_button_desc *default_button;
>   };
>   
>   struct taskdialog_info
>   {
>       HWND hwnd;
> -    PFTASKDIALOGCALLBACK callback;
> -    LONG_PTR callback_data;
> +    const TASKDIALOGCONFIG *taskconfig;
> +    LONG x_baseunit;
> +    LONG y_baseunit;
> +    HFONT hfont;
>   };
>   
> -static void pixels_to_dialogunits(const struct taskdialog_template_desc *desc, LONG *width, LONG *height)
> +static void dialogunits_to_pixels(const struct taskdialog_info *dialog_info, LONG *width, LONG *height)
>   {
> -    if (width)
> -        *width = MulDiv(*width, 4, desc->x_baseunit);
> -    if (height)
> -        *height = MulDiv(*height, 8, desc->y_baseunit);
> -}
> -
> -static void dialogunits_to_pixels(const struct taskdialog_template_desc *desc, LONG *width, LONG *height)
> -{
> -    if (width)
> -        *width = MulDiv(*width, desc->x_baseunit, 4);
> -    if (height)
> -        *height = MulDiv(*height, desc->y_baseunit, 8);
> +    if (width) *width = MulDiv(*width, dialog_info->x_baseunit, 4);
> +    if (height) *height = MulDiv(*height, dialog_info->y_baseunit, 8);
>   }
>   
>   static void template_write_data(char **ptr, const void *src, unsigned int size)
> @@ -110,66 +97,54 @@ static void template_write_data(char **ptr, const void *src, unsigned int size)
>       *ptr += size;
>   }
>   
> -/* used to calculate size for the controls */
> -static void taskdialog_get_text_extent(const struct taskdialog_template_desc *desc, const WCHAR *text,
> -        BOOL user_resource, SIZE *sz)
> +static HRESULT taskdialog_notify(struct taskdialog_info *dialog_info, UINT notification, WPARAM wparam, LPARAM lparam)
> +{
> +    const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
> +    return taskconfig->pfCallback
> +               ? taskconfig->pfCallback(dialog_info->hwnd, notification, wparam, lparam, taskconfig->lpCallbackData)
> +               : S_OK;
> +}
> +
> +const WCHAR *taskdialog_loadstring(const WCHAR *text, BOOL user_resource, HINSTANCE hinstance, LONG *length)
>   {
> -    RECT rect = { 0, 0, desc->dialog_width - DIALOG_SPACING * 2, 0}; /* padding left and right of the control */
> -    const WCHAR *textW = NULL;
>       static const WCHAR nulW;
> -    unsigned int length;
> -    HFONT oldfont;
> -    HDC hdc;
> +    const WCHAR *textW = NULL;
>   
>       if (IS_INTRESOURCE(text))
>       {
> -        if (!(length = LoadStringW(user_resource ? desc->taskconfig->hInstance : COMCTL32_hModule,
> -                (UINT_PTR)text, (WCHAR *)&textW, 0)))
> +        if (!(*length = LoadStringW(user_resource ? hinstance : COMCTL32_hModule, (UINT_PTR)text, (WCHAR *)&textW, 0)))
>           {
>               WARN("Failed to load text\n");
>               textW = &nulW;
> -            length = 0;
> +            *length = 0;
>           }
>       }
>       else
>       {
>           textW = text;
> -        length = strlenW(textW);
> +        *length = strlenW(textW);
>       }
>   
> -    hdc = GetDC(0);
> -    oldfont = SelectObject(hdc, desc->font);
> -
> -    dialogunits_to_pixels(desc, &rect.right, NULL);
> -    DrawTextW(hdc, textW, length, &rect, DT_LEFT | DT_EXPANDTABS | DT_CALCRECT | DT_WORDBREAK);
> -    pixels_to_dialogunits(desc, &rect.right, &rect.bottom);
> -
> -    SelectObject(hdc, oldfont);
> -    ReleaseDC(0, hdc);
> -
> -    sz->cx = rect.right - rect.left;
> -    sz->cy = rect.bottom - rect.top;
> +    return textW;
>   }
>   
>   static unsigned int taskdialog_add_control(struct taskdialog_template_desc *desc, WORD id, const WCHAR *class,
> -        HINSTANCE hInstance, const WCHAR *text, DWORD style, short x, short y, short cx, short cy)
> +                                           HINSTANCE hInstance, const WCHAR *text, DWORD style)
>   {
>       struct taskdialog_control *control = Alloc(sizeof(*control));
>       unsigned int size, class_size, text_size;
>       DLGITEMTEMPLATE *template;
>       static const WCHAR nulW;
>       const WCHAR *textW;
> +    LONG length;
>       char *ptr;
>   
>       class_size = (strlenW(class) + 1) * sizeof(WCHAR);
>   
> -    if (IS_INTRESOURCE(text))
> -        text_size = LoadStringW(hInstance, (UINT_PTR)text, (WCHAR *)&textW, 0) * sizeof(WCHAR);
> -    else
> -    {
> -        textW = text;
> -        text_size = strlenW(textW) * sizeof(WCHAR);
> -    }
> +    if (!text) text = &nulW;
> +
> +    textW = taskdialog_loadstring(text, TRUE, hInstance, &length);
> +    text_size = length * sizeof(WCHAR);
>   
>       size = sizeof(DLGITEMTEMPLATE);
>       size += class_size;
> @@ -180,11 +155,6 @@ static unsigned int taskdialog_add_control(struct taskdialog_template_desc *desc
>       control->template_size = size;
>   
>       template->style = WS_VISIBLE | style;
> -    template->dwExtendedStyle = 0;
> -    template->x = x;
> -    template->y = y;
> -    template->cx = cx;
> -    template->cy = cy;
>       template->id = id;
>       ptr = (char *)(template + 1);
>       template_write_data(&ptr, class, class_size);
> @@ -198,19 +168,8 @@ static unsigned int taskdialog_add_control(struct taskdialog_template_desc *desc
>   
>   static unsigned int taskdialog_add_static_label(struct taskdialog_template_desc *desc, WORD id, const WCHAR *str)
>   {
> -    unsigned int size;
> -    SIZE sz;
> -
> -    if (!str)
> -        return 0;
> -
> -    taskdialog_get_text_extent(desc, str, TRUE, &sz);
> -
> -    desc->dialog_height += DIALOG_SPACING;
> -    size = taskdialog_add_control(desc, id, WC_STATICW, desc->taskconfig->hInstance, str, 0, DIALOG_SPACING,
> -            desc->dialog_height, sz.cx, sz.cy);
> -    desc->dialog_height += sz.cy + DIALOG_SPACING;
> -    return size;
> +    if (!str) return 0;
> +    return taskdialog_add_control(desc, id, WC_STATICW, desc->taskconfig->hInstance, str, 0);
>   }
>   
>   static unsigned int taskdialog_add_main_instruction(struct taskdialog_template_desc *desc)
> @@ -223,97 +182,214 @@ static unsigned int taskdialog_add_content(struct taskdialog_template_desc *desc
>       return taskdialog_add_static_label(desc, ID_CONTENT, desc->taskconfig->pszContent);
>   }
>   
> -static void taskdialog_init_button(struct taskdialog_button_desc *button, struct taskdialog_template_desc *desc,
> -        int id, const WCHAR *text, BOOL custom_button)
> +static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc)
>   {
> -    SIZE sz;
> -
> -    taskdialog_get_text_extent(desc, text, custom_button, &sz);
> +    const TASKDIALOGCONFIG *taskconfig = desc->taskconfig;
> +    DWORD style, flags = taskconfig->dwCommonButtons;
> +    struct taskdialog_button_desc *buttons;
> +    unsigned int max_count, count = 0, i, size = 0;
> +    int default_id = 0;
>   
> -    button->id = id;
> -    button->text = text;
> -    button->width = max(DIALOG_BUTTON_WIDTH, sz.cx + DIALOG_SPACING * 2);
> -    button->line = 0;
> -    button->hinst = custom_button ? desc->taskconfig->hInstance : COMCTL32_hModule;
> +    /* Allocate enough memory for the custom and the default buttons. Maximum 6
> +   * default buttons possible. */
> +    max_count = 6;
>   
> -    if (id == desc->taskconfig->nDefaultButton)
> -        desc->default_button = button;
> -}
> +    if (taskconfig->cButtons && taskconfig->pButtons) max_count += taskconfig->cButtons;
>   
> -static void taskdialog_init_common_buttons(struct taskdialog_template_desc *desc, struct taskdialog_button_desc *buttons,
> -    unsigned int *button_count)
> -{
> -    DWORD flags = desc->taskconfig->dwCommonButtons;
> +    buttons = Alloc(max_count * sizeof(*buttons));
> +    if (!buttons) return 0;
>   
> -#define TASKDIALOG_INIT_COMMON_BUTTON(id) \
> -    do { \
> -        taskdialog_init_button(&buttons[(*button_count)++], desc, ID##id, MAKEINTRESOURCEW(IDS_BUTTON_##id), FALSE); \
> -    } while(0)
> +    if (taskconfig->cButtons && taskconfig->pButtons)
> +        for (count = 0; count < taskconfig->cButtons; count++)
> +        {
> +            buttons[count].id = taskconfig->pButtons[count].nButtonID;
> +            buttons[count].text = taskconfig->pButtons[count].pszButtonText;
> +            buttons[count].hinst = taskconfig->hInstance;
> +        }
>   
> -    if (flags & TDCBF_OK_BUTTON)
> -        TASKDIALOG_INIT_COMMON_BUTTON(OK);
> +    if (flags & TDCBF_OK_BUTTON
> +        || (count == 0 && !(flags & (TDCBF_YES_BUTTON | TDCBF_NO_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CANCEL_BUTTON | TDCBF_CLOSE_BUTTON))))
> +    {
> +        buttons[count].id = IDOK;
> +        buttons[count++].text = MAKEINTRESOURCEW(IDS_BUTTON_OK);
> +    }
>       if (flags & TDCBF_YES_BUTTON)
> -        TASKDIALOG_INIT_COMMON_BUTTON(YES);
> +    {
> +        buttons[count].id = IDYES;
> +        buttons[count++].text = MAKEINTRESOURCEW(IDS_BUTTON_YES);
> +    }
>       if (flags & TDCBF_NO_BUTTON)
> -        TASKDIALOG_INIT_COMMON_BUTTON(NO);
> +    {
> +        buttons[count].id = IDNO;
> +        buttons[count++].text = MAKEINTRESOURCEW(IDS_BUTTON_NO);
> +    }
>       if (flags & TDCBF_RETRY_BUTTON)
> -        TASKDIALOG_INIT_COMMON_BUTTON(RETRY);
> +    {
> +        buttons[count].id = IDRETRY;
> +        buttons[count++].text = MAKEINTRESOURCEW(IDS_BUTTON_RETRY);
> +    }
>       if (flags & TDCBF_CANCEL_BUTTON)
> -        TASKDIALOG_INIT_COMMON_BUTTON(CANCEL);
> +    {
> +        buttons[count].id = IDCANCEL;
> +        buttons[count++].text = MAKEINTRESOURCEW(IDS_BUTTON_CANCEL);
> +    }
>       if (flags & TDCBF_CLOSE_BUTTON)
> -        TASKDIALOG_INIT_COMMON_BUTTON(CLOSE);
> +    {
> +        buttons[count].id = IDCLOSE;
> +        buttons[count++].text = MAKEINTRESOURCEW(IDS_BUTTON_CLOSE);
> +    }
> +
> +    for (i = 0; i < count; i++)
> +        if (buttons[i].id == taskconfig->nDefaultButton) default_id = buttons[i].id;
> +
> +    if (!default_id) default_id = buttons[0].id;
> +
> +    for (i = 0; i < count; i++)
> +    {
> +        style = buttons[i].id == default_id ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON;
> +        size += taskdialog_add_control(desc, buttons[i].id, WC_BUTTONW,
> +                                       buttons[i].hinst ? buttons[i].hinst : COMCTL32_hModule, buttons[i].text, style);
> +    }
>   
> -#undef TASKDIALOG_INIT_COMMON_BUTTON
> +    Free(buttons);
> +    return size;
>   }
>   
> -static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc)
> +static unsigned int taskdialog_get_reference_rect(struct taskdialog_info *dialog_info, RECT *ret)
>   {
> -    unsigned int count = 0, buttons_size, i, line_count, size = 0;
> -    unsigned int location_x, *line_widths, alignment = ~0u;
> -    const TASKDIALOGCONFIG *taskconfig = desc->taskconfig;
> +    const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
> +    HMONITOR monitor = MonitorFromWindow(taskconfig->hwndParent ? taskconfig->hwndParent : GetActiveWindow(),
> +                                         MONITOR_DEFAULTTOPRIMARY);
> +    MONITORINFO info;
> +
> +    info.cbSize = sizeof(info);
> +    GetMonitorInfoW(monitor, &info);
> +
> +    if (taskconfig->dwFlags & TDF_POSITION_RELATIVE_TO_WINDOW && taskconfig->hwndParent)
> +        GetWindowRect(taskconfig->hwndParent, ret);
> +    else
> +        *ret = info.rcWork;
> +
> +    return info.rcWork.right - info.rcWork.left;
> +}
> +
> +static void taskdialog_get_label_size(HWND hwnd, LONG max_width, SIZE *size)
> +{
> +    HFONT hfont, old_hfont;
> +    HDC hdc;
> +    RECT rect = {0};
> +    WCHAR text[1024];
> +    INT text_length;
> +
> +    hfont = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
> +    text_length = GetWindowTextW(hwnd, text, ARRAY_SIZE(text));
> +    hdc = GetDC(hwnd);
> +    old_hfont = SelectObject(hdc, hfont);
> +    rect.right = max_width;
> +    size->cy = DrawTextW(hdc, text, text_length, &rect, DT_LEFT | DT_EXPANDTABS | DT_CALCRECT | DT_WORDBREAK);
> +    size->cx = min(max_width, rect.right - rect.left);
> +    if(old_hfont) SelectObject(hdc, old_hfont);
> +    ReleaseDC(hwnd, hdc);
> +}
> +
> +static void taskdialog_resize(struct taskdialog_info *dialog_info)
> +{
> +    const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
> +    static BOOL first_time = TRUE;
> +    RECT ref_rect, window_rect;
> +    LONG screen_width;
> +    LONG dialog_width, dialog_height = 0;
> +    LONG x, y;
> +    SIZE size;
> +    LONG horizontal_spacing, vertical_spacing;
> +    HWND hwnd;
> +    DWORD flags = taskconfig->dwCommonButtons;
> +    LONG buttons_max_size, button_min_width, button_count = 0, line_count;
> +    LONG *line_widths, alignment;
>       struct taskdialog_button_desc *buttons;
> +    INT i;
>   
> -    /* Allocate enough memory for the custom and the default buttons. Maximum 6 default buttons possible. */
> -    buttons_size = 6;
> -    if (taskconfig->cButtons && taskconfig->pButtons)
> -        buttons_size += taskconfig->cButtons;
> +    screen_width = taskdialog_get_reference_rect(dialog_info, &ref_rect);
>   
> -    if (!(buttons = Alloc(buttons_size * sizeof(*buttons))))
> -        return 0;
> +    dialog_width = max(taskconfig->cxWidth, DIALOG_MIN_WIDTH);
> +    dialogunits_to_pixels(dialog_info, &dialog_width, 0);
> +    dialog_width = min(dialog_width, screen_width);
>   
> -    /* Custom buttons */
> -    if (taskconfig->cButtons && taskconfig->pButtons)
> -        for (i = 0; i < taskconfig->cButtons; i++)
> -            taskdialog_init_button(&buttons[count++], desc, taskconfig->pButtons[i].nButtonID,
> -                    taskconfig->pButtons[i].pszButtonText, TRUE);
> +    horizontal_spacing = DIALOG_SPACING;
> +    vertical_spacing = DIALOG_SPACING;
>   
> -    /* Common buttons */
> -    taskdialog_init_common_buttons(desc, buttons, &count);
> +    dialogunits_to_pixels(dialog_info, &horizontal_spacing, &vertical_spacing);
>   
> -    /* There must be at least one button */
> -    if (count == 0)
> -        taskdialog_init_button(&buttons[count++], desc, IDOK, MAKEINTRESOURCEW(IDS_BUTTON_OK), FALSE);
> +    /* Main instruction */
> +    hwnd = GetDlgItem(dialog_info->hwnd, ID_MAIN_INSTRUCTION);
> +    if (hwnd)
> +    {
> +        x = horizontal_spacing;
> +        y = dialog_height + vertical_spacing;
> +        size.cx = dialog_width - x - horizontal_spacing;
> +        taskdialog_get_label_size(hwnd, size.cx, &size);
> +        MoveWindow(hwnd, x, y, size.cx, size.cy, TRUE);
> +        dialog_height = y + size.cy;
> +    }
> +
> +    /* Main content */
> +    hwnd = GetDlgItem(dialog_info->hwnd, ID_CONTENT);
> +    if (hwnd)
> +    {
> +        x = horizontal_spacing;
> +        y = dialog_height + vertical_spacing;
> +        size.cx = dialog_width - x - horizontal_spacing;
> +        taskdialog_get_label_size(hwnd, size.cx, &size);
> +        MoveWindow(hwnd, x, y, size.cx, size.cy, TRUE);
> +        dialog_height = y + size.cy;
> +    }
> +
> +    /* Common Buttons and Custom Buttons */
> +    /* Allocate enough memory for the custom and the default buttons. Maximum 6 default buttons possible. */
> +    buttons_max_size = 6;
> +    /* Custom buttons */
> +    if (taskconfig->cButtons && taskconfig->pButtons) buttons_max_size += taskconfig->cButtons;
>   
> -    if (!desc->default_button)
> -        desc->default_button = &buttons[0];
> +    /* For easy handling just allocate as many lines as buttons, the worst case. s*/
> +    buttons = Alloc(buttons_max_size * sizeof(*buttons));
> +    line_widths = Alloc(buttons_max_size * sizeof(*line_widths));
>   
> -    /* For easy handling just allocate as many lines as buttons, the worst case. */
> -    line_widths = Alloc(count * sizeof(*line_widths));
> +    if (taskconfig->cButtons && taskconfig->pButtons)
> +        for (button_count = 0; button_count < taskconfig->cButtons; button_count++)
> +            buttons[button_count].id = taskconfig->pButtons[button_count].nButtonID;
> +
> +    /* Ok button may be added if no button is specified in taskconfig */
> +    if (GetDlgItem(dialog_info->hwnd, IDOK)) buttons[button_count++].id = IDOK;
> +    if (flags & TDCBF_YES_BUTTON) buttons[button_count++].id = IDYES;
> +    if (flags & TDCBF_NO_BUTTON) buttons[button_count++].id = IDNO;
> +    if (flags & TDCBF_RETRY_BUTTON) buttons[button_count++].id = IDRETRY;
> +    if (flags & TDCBF_CANCEL_BUTTON) buttons[button_count++].id = IDCANCEL;
> +    if (flags & TDCBF_CLOSE_BUTTON) buttons[button_count++].id = IDCLOSE;
> +
> +    button_min_width = DIALOG_BUTTON_WIDTH;
> +    dialogunits_to_pixels(dialog_info, &button_min_width, 0);
> +    for (i = 0; i < button_count; i++)
> +    {
> +        hwnd = GetDlgItem(dialog_info->hwnd, buttons[i].id);
> +        taskdialog_get_label_size(hwnd, dialog_width - horizontal_spacing, &size);
> +        buttons[i].width = max(size.cx, button_min_width);
> +        buttons[i].line = 0;
> +    }

Regarding buttons, I don't see a point of counting them up, or measuring 
them every time. They will never change after dialog is created. 
Messages used to update texts do not touch support buttons as far as I 
can see.

>   
>       /* Separate buttons into lines */
> -    location_x = DIALOG_SPACING;
> -    for (i = 0, line_count = 0; i < count; i++)
> +    x = horizontal_spacing;
> +    for (i = 0, line_count = 0; i < button_count; i++)
>       {
> -        if (location_x + buttons[i].width + DIALOG_SPACING > desc->dialog_width)
> +        if (x + buttons[i].width + horizontal_spacing >= dialog_width)
>           {
> -            location_x = DIALOG_SPACING;
> +            x = horizontal_spacing;
>               line_count++;
>           }
>   
>           buttons[i].line = line_count;
>   
> -        location_x += buttons[i].width + DIALOG_SPACING;
> -        line_widths[line_count] += buttons[i].width + DIALOG_SPACING;
> +        x += buttons[i].width + horizontal_spacing;
> +        line_widths[line_count] += buttons[i].width + horizontal_spacing;
>       }
>       line_count++;
>   
> @@ -324,9 +400,8 @@ static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc
>           unsigned int j, last_button = 0;
>           int diff_changed;
>   
> -        for (j = 0; j < count; j++)
> -            if (buttons[j].line == i - 1)
> -                last_button = j;
> +        for (j = 0; j < button_count; j++)
> +            if (buttons[j].line == i - 1) last_button = j;
>   
>           /* Difference in length of both lines if we wrapped the last button from the last line into this one */
>           diff_changed = abs(2 * buttons[last_button].width + line_widths[i] - line_widths[i - 1]);
> @@ -340,38 +415,58 @@ static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc
>       }
>   
>       /* Calculate left alignment so all lines are as far right as possible. */
> +    alignment = dialog_width;
>       for (i = 0; i < line_count; i++)
>       {
> -        int new_alignment = desc->dialog_width - line_widths[i];
> -        if (new_alignment < alignment)
> -            alignment = new_alignment;
> +        int new_alignment = dialog_width - line_widths[i];
> +        if (new_alignment < alignment) alignment = new_alignment;
>       }
>   
> -    /* Now that we got them all positioned, create all buttons */
> -    location_x = alignment;
> -    for (i = 0; i < count; i++)
> +    /* Now that we got them all positioned, move all buttons */
> +    x = alignment;
> +    size.cy = DIALOG_BUTTON_HEIGHT;
> +    dialogunits_to_pixels(dialog_info, NULL, &size.cy);
> +    for (i = 0; i < button_count; i++)
>       {
> -        DWORD style = &buttons[i] == desc->default_button ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON;
> -
> -        if (i > 0 && buttons[i].line != buttons[i - 1].line) /* New line */
> +        /* New line */
> +        if (i > 0 && buttons[i].line != buttons[i - 1].line)
>           {
> -            location_x = alignment;
> -            desc->dialog_height += DIALOG_BUTTON_HEIGHT + DIALOG_SPACING;
> +            x = alignment;
> +            dialog_height += size.cy + vertical_spacing;
>           }
>   
> -        size += taskdialog_add_control(desc, buttons[i].id, WC_BUTTONW, buttons[i].hinst, buttons[i].text, style,
> -                location_x, desc->dialog_height, buttons[i].width, DIALOG_BUTTON_HEIGHT);
> -
> -        location_x += buttons[i].width + DIALOG_SPACING;
> +        y = dialog_height + vertical_spacing;
> +        size.cx = buttons[i].width;
> +        hwnd = GetDlgItem(dialog_info->hwnd, buttons[i].id);
> +        MoveWindow(hwnd, x, y, size.cx, size.cy, TRUE);
> +        x += buttons[i].width + horizontal_spacing;
>       }
>   
> -    /* Add height for last row and spacing */
> -    desc->dialog_height += DIALOG_BUTTON_HEIGHT + DIALOG_SPACING;
> +    /* Add height for last row button and spacing */
> +    dialog_height += size.cy + vertical_spacing;
>   
>       Free(line_widths);
>       Free(buttons);
>   
> -    return size;
> +    /* Add height for spacing, title height and frame height */
> +    dialog_height += vertical_spacing;
> +    dialog_height += GetSystemMetrics(SM_CYCAPTION);
> +    dialog_height += GetSystemMetrics(SM_CXDLGFRAME);
> +
> +    if (first_time)
> +    {
> +        x = (ref_rect.left + ref_rect.right + dialog_width) / 2;
> +        y = (ref_rect.top + ref_rect.bottom + dialog_height) / 2;
> +        first_time = FALSE;
> +    }
> +    else
> +    {
> +        GetWindowRect(dialog_info->hwnd, &window_rect);
> +        x = window_rect.left;
> +        y = window_rect.top;
> +    }
> +
> +    MoveWindow(dialog_info->hwnd, x, y, dialog_width, dialog_height, TRUE);
>   }
>   
>   static void taskdialog_clear_controls(struct list *controls)
> @@ -386,28 +481,6 @@ static void taskdialog_clear_controls(struct list *controls)
>       }
>   }
>   
> -static unsigned int taskdialog_get_reference_rect(const struct taskdialog_template_desc *desc, RECT *ret)
> -{
> -    HMONITOR monitor = MonitorFromWindow(desc->taskconfig->hwndParent ? desc->taskconfig->hwndParent : GetActiveWindow(),
> -            MONITOR_DEFAULTTOPRIMARY);
> -    MONITORINFO info;
> -
> -    info.cbSize = sizeof(info);
> -    GetMonitorInfoW(monitor, &info);
> -
> -    if (desc->taskconfig->dwFlags & TDF_POSITION_RELATIVE_TO_WINDOW && desc->taskconfig->hwndParent)
> -        GetWindowRect(desc->taskconfig->hwndParent, ret);
> -    else
> -        *ret = info.rcWork;
> -
> -    pixels_to_dialogunits(desc, &ret->left, &ret->top);
> -    pixels_to_dialogunits(desc, &ret->right, &ret->bottom);
> -
> -    pixels_to_dialogunits(desc, &info.rcWork.left, &info.rcWork.top);
> -    pixels_to_dialogunits(desc, &info.rcWork.right, &info.rcWork.bottom);
> -    return info.rcWork.right - info.rcWork.left;
> -}
> -
>   static WCHAR *taskdialog_get_exe_name(const TASKDIALOGCONFIG *taskconfig, WCHAR *name, DWORD length)
>   {
>       DWORD len = GetModuleFileNameW(NULL, name, length);
> @@ -425,17 +498,14 @@ static WCHAR *taskdialog_get_exe_name(const TASKDIALOGCONFIG *taskconfig, WCHAR
>   static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfig)
>   {
>       struct taskdialog_control *control, *control2;
> -    unsigned int size, title_size, screen_width;
> +    unsigned int size, title_size;
>       struct taskdialog_template_desc desc;
>       static const WORD fontsize = 0x7fff;
>       static const WCHAR emptyW[] = { 0 };
>       const WCHAR *titleW = NULL;
>       DLGTEMPLATE *template;
> -    NONCLIENTMETRICSW ncm;
>       WCHAR pathW[MAX_PATH];
> -    RECT ref_rect;
>       char *ptr;
> -    HDC hdc;
>   
>       /* Window title */
>       if (!taskconfig->pszWindowTitle)
> @@ -459,22 +529,6 @@ static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfi
>       desc.taskconfig = taskconfig;
>       desc.control_count = 0;
>   
> -    ncm.cbSize = sizeof(ncm);
> -    SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
> -    desc.font = CreateFontIndirectW(&ncm.lfMessageFont);
> -
> -    hdc = GetDC(0);
> -    SelectObject(hdc, desc.font);
> -    desc.x_baseunit = GdiGetCharDimensions(hdc, NULL, &desc.y_baseunit);
> -    ReleaseDC(0, hdc);
> -
> -    screen_width = taskdialog_get_reference_rect(&desc, &ref_rect);
> -
> -    desc.dialog_height = 0;
> -    desc.dialog_width = max(taskconfig->cxWidth, DIALOG_MIN_WIDTH);
> -    desc.dialog_width = min(desc.dialog_width, screen_width);
> -    desc.default_button = NULL;
> -
>       size += taskdialog_add_main_instruction(&desc);
>       size += taskdialog_add_content(&desc);
>       size += taskdialog_add_buttons(&desc);
> @@ -483,16 +537,11 @@ static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfi
>       if (!template)
>       {
>           taskdialog_clear_controls(&desc.controls);
> -        DeleteObject(desc.font);
>           return NULL;
>       }
>   
>       template->style = DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_VISIBLE | WS_SYSMENU;
>       template->cdit = desc.control_count;
> -    template->x = (ref_rect.left + ref_rect.right + desc.dialog_width) / 2;
> -    template->y = (ref_rect.top + ref_rect.bottom + desc.dialog_height) / 2;
> -    template->cx = desc.dialog_width;
> -    template->cy = desc.dialog_height;
>   
>       ptr = (char *)(template + 1);
>       ptr += 2; /* menu */
> @@ -513,22 +562,32 @@ static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfi
>           Free(control);
>       }
>   
> -    DeleteObject(desc.font);
>       return template;
>   }
>   
> -static HRESULT taskdialog_notify(struct taskdialog_info *dialog_info, UINT notification, WPARAM wparam, LPARAM lparam)
> -{
> -    return dialog_info->callback ? dialog_info->callback(dialog_info->hwnd, notification, wparam, lparam,
> -            dialog_info->callback_data) : S_OK;
> -}
> -
>   static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, WORD command_id)
>   {
>       if (taskdialog_notify(dialog_info, TDN_BUTTON_CLICKED, command_id, 0) == S_OK)
>           EndDialog(dialog_info->hwnd, command_id);
>   }
>   
> +static void taskdialog_init_dialog_info(struct taskdialog_info *dialog_info, HWND hwnd)
> +{
> +    NONCLIENTMETRICSW ncm;
> +    HDC hdc;
> +
> +    dialog_info->hwnd = hwnd;
> +
> +    ncm.cbSize = sizeof(ncm);
> +    SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
> +    dialog_info->hfont = CreateFontIndirectW(&ncm.lfMessageFont);
> +
> +    hdc = GetDC(0);
> +    SelectObject(hdc, dialog_info->hfont);
> +    dialog_info->x_baseunit = GdiGetCharDimensions(hdc, NULL, &dialog_info->y_baseunit);
> +    ReleaseDC(0, hdc);
> +}
> +
>   static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
>   {
>       static const WCHAR taskdialog_info_propnameW[] = {'T','a','s','k','D','i','a','l','o','g','I','n','f','o',0};
> @@ -546,8 +605,10 @@ static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
>               break;
>           case WM_INITDIALOG:
>               dialog_info = (struct taskdialog_info *)lParam;
> -            dialog_info->hwnd = hwnd;
> +            taskdialog_init_dialog_info(dialog_info, hwnd);
> +
>               SetPropW(hwnd, taskdialog_info_propnameW, dialog_info);
> +            taskdialog_resize(dialog_info);
>   
>               taskdialog_notify(dialog_info, TDN_DIALOG_CONSTRUCTED, 0, 0);
>               break;
> @@ -584,8 +645,7 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *taskconfig, int *butto
>       if (!taskconfig || taskconfig->cbSize != sizeof(TASKDIALOGCONFIG))
>           return E_INVALIDARG;
>   
> -    dialog_info.callback = taskconfig->pfCallback;
> -    dialog_info.callback_data = taskconfig->lpCallbackData;
> +    dialog_info.taskconfig = taskconfig;
>   
>       template = create_taskdialog_template(taskconfig);
>       ret = (short)DialogBoxIndirectParamW(taskconfig->hInstance, template, taskconfig->hwndParent,

Please split this patch, it's too large, and contains unrelated changes. 
For approach itself, my understanding is that resize() helper will be 
used for expanding/collapsing too, where only vertical positions ever 
change, so there's never a need to re-layout button lines for example.

The only case when buttons layout can change as far as I can tell is 
when you update content text, that triggers dialog width change. We can 
handle that specifically, using additional helper for example.



More information about the wine-devel mailing list