comctl32/taskdialog: Support dynamic layout.
Support dynamic layout since some controls might change their own layout after creation. Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
dd90ed02d9
commit
df2e5f3975
|
@ -66,21 +66,14 @@ struct taskdialog_button_desc
|
|||
{
|
||||
int id;
|
||||
const WCHAR *text;
|
||||
unsigned int width;
|
||||
unsigned int line;
|
||||
HINSTANCE hinst;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -89,23 +82,30 @@ struct taskdialog_info
|
|||
HWND hwnd;
|
||||
const TASKDIALOGCONFIG *taskconfig;
|
||||
DWORD last_timer_tick;
|
||||
HFONT font;
|
||||
HFONT main_instruction_font;
|
||||
/* Dialog metrics */
|
||||
struct
|
||||
{
|
||||
LONG x_baseunit;
|
||||
LONG y_baseunit;
|
||||
LONG h_spacing;
|
||||
LONG v_spacing;
|
||||
} m;
|
||||
};
|
||||
|
||||
static void pixels_to_dialogunits(const struct taskdialog_template_desc *desc, LONG *width, LONG *height)
|
||||
struct button_layout_info
|
||||
{
|
||||
if (width)
|
||||
*width = MulDiv(*width, 4, desc->x_baseunit);
|
||||
if (height)
|
||||
*height = MulDiv(*height, 8, desc->y_baseunit);
|
||||
}
|
||||
INT id;
|
||||
HWND hwnd;
|
||||
LONG width;
|
||||
LONG line;
|
||||
};
|
||||
|
||||
static void dialogunits_to_pixels(const struct taskdialog_template_desc *desc, LONG *width, LONG *height)
|
||||
static void taskdialog_du_to_px(struct taskdialog_info *dialog_info, 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->m.x_baseunit, 4);
|
||||
if (height) *height = MulDiv(*height, dialog_info->m.y_baseunit, 8);
|
||||
}
|
||||
|
||||
static void template_write_data(char **ptr, const void *src, unsigned int size)
|
||||
|
@ -132,49 +132,8 @@ static void taskdialog_set_main_instruction_font(struct taskdialog_info *dialog_
|
|||
SendMessageW(hwnd, WM_SETFONT, (WPARAM)dialog_info->main_instruction_font, TRUE);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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;
|
||||
|
||||
if (IS_INTRESOURCE(text))
|
||||
{
|
||||
if (!(length = LoadStringW(user_resource ? desc->taskconfig->hInstance : COMCTL32_hModule,
|
||||
(UINT_PTR)text, (WCHAR *)&textW, 0)))
|
||||
{
|
||||
WARN("Failed to load text\n");
|
||||
textW = &nulW;
|
||||
length = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
textW = text;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -203,10 +162,6 @@ static unsigned int taskdialog_add_control(struct taskdialog_template_desc *desc
|
|||
|
||||
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);
|
||||
|
@ -221,17 +176,11 @@ 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;
|
||||
size = taskdialog_add_control(desc, id, WC_STATICW, desc->taskconfig->hInstance, str, 0);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -248,14 +197,8 @@ static unsigned int taskdialog_add_content(struct taskdialog_template_desc *desc
|
|||
static void taskdialog_init_button(struct taskdialog_button_desc *button, struct taskdialog_template_desc *desc,
|
||||
int id, const WCHAR *text, BOOL custom_button)
|
||||
{
|
||||
SIZE sz;
|
||||
|
||||
taskdialog_get_text_extent(desc, text, custom_button, &sz);
|
||||
|
||||
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;
|
||||
|
||||
if (id == desc->taskconfig->nDefaultButton)
|
||||
|
@ -290,8 +233,7 @@ static void taskdialog_init_common_buttons(struct taskdialog_template_desc *desc
|
|||
|
||||
static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc)
|
||||
{
|
||||
unsigned int count = 0, buttons_size, i, line_count, size = 0;
|
||||
unsigned int location_x, *line_widths, alignment = ~0u;
|
||||
unsigned int count = 0, buttons_size, i, size = 0;
|
||||
const TASKDIALOGCONFIG *taskconfig = desc->taskconfig;
|
||||
struct taskdialog_button_desc *buttons;
|
||||
|
||||
|
@ -319,78 +261,13 @@ static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc
|
|||
if (!desc->default_button)
|
||||
desc->default_button = &buttons[0];
|
||||
|
||||
/* For easy handling just allocate as many lines as buttons, the worst case. */
|
||||
line_widths = Alloc(count * sizeof(*line_widths));
|
||||
|
||||
/* Separate buttons into lines */
|
||||
location_x = DIALOG_SPACING;
|
||||
for (i = 0, line_count = 0; i < count; i++)
|
||||
{
|
||||
if (location_x + buttons[i].width + DIALOG_SPACING > desc->dialog_width)
|
||||
{
|
||||
location_x = DIALOG_SPACING;
|
||||
line_count++;
|
||||
}
|
||||
|
||||
buttons[i].line = line_count;
|
||||
|
||||
location_x += buttons[i].width + DIALOG_SPACING;
|
||||
line_widths[line_count] += buttons[i].width + DIALOG_SPACING;
|
||||
}
|
||||
line_count++;
|
||||
|
||||
/* Try to balance lines so they are about the same size */
|
||||
for (i = 1; i < line_count - 1; i++)
|
||||
{
|
||||
int diff_now = abs(line_widths[i] - line_widths[i - 1]);
|
||||
unsigned int j, last_button = 0;
|
||||
int diff_changed;
|
||||
|
||||
for (j = 0; j < 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]);
|
||||
|
||||
if (diff_changed < diff_now)
|
||||
{
|
||||
buttons[last_button].line = i;
|
||||
line_widths[i] += buttons[last_button].width;
|
||||
line_widths[i - 1] -= buttons[last_button].width;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate left alignment so all lines are as far right as possible. */
|
||||
for (i = 0; i < line_count; i++)
|
||||
{
|
||||
int new_alignment = desc->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;
|
||||
/* create all buttons */
|
||||
for (i = 0; i < 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 */
|
||||
{
|
||||
location_x = alignment;
|
||||
desc->dialog_height += DIALOG_BUTTON_HEIGHT + DIALOG_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;
|
||||
size += taskdialog_add_control(desc, buttons[i].id, WC_BUTTONW, buttons[i].hinst, buttons[i].text, style);
|
||||
}
|
||||
|
||||
/* Add height for last row and spacing */
|
||||
desc->dialog_height += DIALOG_BUTTON_HEIGHT + DIALOG_SPACING;
|
||||
|
||||
Free(line_widths);
|
||||
Free(buttons);
|
||||
|
||||
return size;
|
||||
|
@ -408,25 +285,20 @@ static void taskdialog_clear_controls(struct list *controls)
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned int taskdialog_get_reference_rect(const struct taskdialog_template_desc *desc, RECT *ret)
|
||||
static unsigned int taskdialog_get_reference_rect(const TASKDIALOGCONFIG *taskconfig, RECT *ret)
|
||||
{
|
||||
HMONITOR monitor = MonitorFromWindow(desc->taskconfig->hwndParent ? desc->taskconfig->hwndParent : GetActiveWindow(),
|
||||
MONITOR_DEFAULTTOPRIMARY);
|
||||
HMONITOR monitor = MonitorFromWindow(taskconfig->hwndParent ? 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);
|
||||
if (taskconfig->dwFlags & TDF_POSITION_RELATIVE_TO_WINDOW && taskconfig->hwndParent)
|
||||
GetWindowRect(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;
|
||||
}
|
||||
|
||||
|
@ -447,17 +319,14 @@ static WCHAR *taskdialog_get_exe_name(WCHAR *name, DWORD length)
|
|||
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)
|
||||
|
@ -480,21 +349,6 @@ static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfi
|
|||
list_init(&desc.controls);
|
||||
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);
|
||||
|
@ -505,7 +359,6 @@ static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfi
|
|||
if (!template)
|
||||
{
|
||||
taskdialog_clear_controls(&desc.controls);
|
||||
DeleteObject(desc.font);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -514,10 +367,6 @@ static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfi
|
|||
if (!(taskconfig->dwFlags & TDF_NO_SET_FOREGROUND)) template->style |= DS_SETFOREGROUND;
|
||||
if (taskconfig->dwFlags & TDF_RTL_LAYOUT) template->dwExtendedStyle = WS_EX_LAYOUTRTL | WS_EX_RIGHT | WS_EX_RTLREADING;
|
||||
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 */
|
||||
|
@ -538,7 +387,6 @@ static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfi
|
|||
Free(control);
|
||||
}
|
||||
|
||||
DeleteObject(desc.font);
|
||||
return template;
|
||||
}
|
||||
|
||||
|
@ -556,13 +404,219 @@ static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, WORD
|
|||
EndDialog(dialog_info->hwnd, command_id);
|
||||
}
|
||||
|
||||
static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND hwnd, LONG max_width, SIZE *size)
|
||||
{
|
||||
DWORD style = DT_EXPANDTABS | DT_CALCRECT | DT_WORDBREAK;
|
||||
HFONT hfont, old_hfont;
|
||||
HDC hdc;
|
||||
RECT rect = {0};
|
||||
WCHAR text[1024];
|
||||
INT text_length;
|
||||
|
||||
if (dialog_info->taskconfig->dwFlags & TDF_RTL_LAYOUT)
|
||||
style |= DT_RIGHT | DT_RTLREADING;
|
||||
else
|
||||
style |= DT_LEFT;
|
||||
|
||||
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, style);
|
||||
size->cx = min(max_width, rect.right - rect.left);
|
||||
if (old_hfont) SelectObject(hdc, old_hfont);
|
||||
ReleaseDC(hwnd, hdc);
|
||||
}
|
||||
|
||||
static void taskdialog_label_layout(struct taskdialog_info *dialog_info, HWND hwnd, INT start_x, LONG dialog_width,
|
||||
LONG *dialog_height)
|
||||
{
|
||||
LONG x, y, max_width;
|
||||
SIZE size;
|
||||
|
||||
if (!hwnd) return;
|
||||
|
||||
x = start_x + dialog_info->m.h_spacing;
|
||||
y = *dialog_height + dialog_info->m.v_spacing;
|
||||
max_width = dialog_width - x - dialog_info->m.h_spacing;
|
||||
taskdialog_get_label_size(dialog_info, hwnd, max_width, &size);
|
||||
SetWindowPos(hwnd, 0, x, y, size.cx, size.cy, SWP_NOZORDER);
|
||||
*dialog_height = y + size.cy;
|
||||
}
|
||||
|
||||
static void taskdialog_layout(struct taskdialog_info *dialog_info)
|
||||
{
|
||||
const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
|
||||
DWORD flags = taskconfig->dwCommonButtons;
|
||||
static BOOL first_time = TRUE;
|
||||
HWND hwnd;
|
||||
RECT ref_rect;
|
||||
LONG screen_width, dialog_width, dialog_height = 0;
|
||||
LONG h_spacing, v_spacing;
|
||||
INT button_max_count, button_count = 0;
|
||||
struct button_layout_info *button_layout_infos;
|
||||
LONG button_min_width, button_height;
|
||||
LONG *line_widths, line_count, align;
|
||||
LONG x, y;
|
||||
SIZE size;
|
||||
INT i;
|
||||
|
||||
screen_width = taskdialog_get_reference_rect(dialog_info->taskconfig, &ref_rect);
|
||||
dialog_width = max(taskconfig->cxWidth, DIALOG_MIN_WIDTH);
|
||||
taskdialog_du_to_px(dialog_info, &dialog_width, 0);
|
||||
dialog_width = min(dialog_width, screen_width);
|
||||
|
||||
h_spacing = dialog_info->m.h_spacing;
|
||||
v_spacing = dialog_info->m.v_spacing;
|
||||
|
||||
/* Main instruction */
|
||||
hwnd = GetDlgItem(dialog_info->hwnd, ID_MAIN_INSTRUCTION);
|
||||
taskdialog_label_layout(dialog_info, hwnd, 0, dialog_width, &dialog_height);
|
||||
|
||||
/* Content */
|
||||
hwnd = GetDlgItem(dialog_info->hwnd, ID_CONTENT);
|
||||
taskdialog_label_layout(dialog_info, hwnd, 0, dialog_width, &dialog_height);
|
||||
|
||||
/* Common and custom buttons */
|
||||
/* Allocate enough memory for the custom and the default buttons. Maximum 6 default buttons possible. */
|
||||
button_max_count = 6;
|
||||
/* Custom buttons */
|
||||
if (taskconfig->cButtons && taskconfig->pButtons) button_max_count += taskconfig->cButtons;
|
||||
|
||||
button_layout_infos = Alloc(button_max_count * sizeof(*button_layout_infos));
|
||||
line_widths = Alloc(button_max_count * sizeof(*line_widths));
|
||||
|
||||
if (taskconfig->cButtons && taskconfig->pButtons)
|
||||
for (button_count = 0; button_count < taskconfig->cButtons; button_count++)
|
||||
button_layout_infos[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)) button_layout_infos[button_count++].id = IDOK;
|
||||
if (flags & TDCBF_YES_BUTTON) button_layout_infos[button_count++].id = IDYES;
|
||||
if (flags & TDCBF_NO_BUTTON) button_layout_infos[button_count++].id = IDNO;
|
||||
if (flags & TDCBF_RETRY_BUTTON) button_layout_infos[button_count++].id = IDRETRY;
|
||||
if (flags & TDCBF_CANCEL_BUTTON) button_layout_infos[button_count++].id = IDCANCEL;
|
||||
if (flags & TDCBF_CLOSE_BUTTON) button_layout_infos[button_count++].id = IDCLOSE;
|
||||
|
||||
button_min_width = DIALOG_BUTTON_WIDTH;
|
||||
button_height = DIALOG_BUTTON_HEIGHT;
|
||||
taskdialog_du_to_px(dialog_info, &button_min_width, &button_height);
|
||||
for (i = 0; i < button_count; i++)
|
||||
{
|
||||
button_layout_infos[i].hwnd = GetDlgItem(dialog_info->hwnd, button_layout_infos[i].id);
|
||||
taskdialog_get_label_size(dialog_info, button_layout_infos[i].hwnd, dialog_width - h_spacing * 2, &size);
|
||||
button_layout_infos[i].width = max(size.cx, button_min_width);
|
||||
}
|
||||
|
||||
/* Separate buttons into lines */
|
||||
x = h_spacing;
|
||||
for (i = 0, line_count = 0; i < button_count; i++)
|
||||
{
|
||||
if (x + button_layout_infos[i].width + h_spacing >= dialog_width)
|
||||
{
|
||||
x = h_spacing;
|
||||
line_count++;
|
||||
}
|
||||
|
||||
button_layout_infos[i].line = line_count;
|
||||
|
||||
x += button_layout_infos[i].width + h_spacing;
|
||||
line_widths[line_count] += button_layout_infos[i].width + h_spacing;
|
||||
}
|
||||
line_count++;
|
||||
|
||||
/* Try to balance lines so they are about the same size */
|
||||
for (i = 1; i < line_count - 1; i++)
|
||||
{
|
||||
int diff_now = abs(line_widths[i] - line_widths[i - 1]);
|
||||
unsigned int j, last_button = 0;
|
||||
int diff_changed;
|
||||
|
||||
for (j = 0; j < button_count; j++)
|
||||
if (button_layout_infos[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 * button_layout_infos[last_button].width + line_widths[i] - line_widths[i - 1]);
|
||||
|
||||
if (diff_changed < diff_now)
|
||||
{
|
||||
button_layout_infos[last_button].line = i;
|
||||
line_widths[i] += button_layout_infos[last_button].width;
|
||||
line_widths[i - 1] -= button_layout_infos[last_button].width;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate left alignment so all lines are as far right as possible. */
|
||||
align = dialog_width - h_spacing;
|
||||
for (i = 0; i < line_count; i++)
|
||||
{
|
||||
int new_alignment = dialog_width - line_widths[i];
|
||||
if (new_alignment < align) align = new_alignment;
|
||||
}
|
||||
|
||||
/* Now that we got them all positioned, move all buttons */
|
||||
x = align;
|
||||
size.cy = button_height;
|
||||
for (i = 0; i < button_count; i++)
|
||||
{
|
||||
/* New line */
|
||||
if (i > 0 && button_layout_infos[i].line != button_layout_infos[i - 1].line)
|
||||
{
|
||||
x = align;
|
||||
dialog_height += size.cy + v_spacing;
|
||||
}
|
||||
|
||||
y = dialog_height + v_spacing;
|
||||
size.cx = button_layout_infos[i].width;
|
||||
SetWindowPos(button_layout_infos[i].hwnd, 0, x, y, size.cx, size.cy, SWP_NOZORDER);
|
||||
x += button_layout_infos[i].width + h_spacing;
|
||||
}
|
||||
|
||||
/* Add height for last row button and spacing */
|
||||
dialog_height += size.cy + v_spacing;
|
||||
|
||||
Free(button_layout_infos);
|
||||
Free(line_widths);
|
||||
|
||||
/* Add height for spacing, title height and frame height */
|
||||
dialog_height += v_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;
|
||||
SetWindowPos(dialog_info->hwnd, 0, x, y, dialog_width, dialog_height, SWP_NOZORDER);
|
||||
first_time = FALSE;
|
||||
}
|
||||
else
|
||||
SetWindowPos(dialog_info->hwnd, 0, 0, 0, dialog_width, dialog_height, SWP_NOMOVE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd)
|
||||
{
|
||||
const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
|
||||
NONCLIENTMETRICSW ncm;
|
||||
HDC hdc;
|
||||
|
||||
ncm.cbSize = sizeof(ncm);
|
||||
SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
|
||||
|
||||
memset(dialog_info, 0, sizeof(*dialog_info));
|
||||
dialog_info->taskconfig = taskconfig;
|
||||
dialog_info->hwnd = hwnd;
|
||||
dialog_info->font = CreateFontIndirectW(&ncm.lfMessageFont);
|
||||
|
||||
hdc = GetDC(dialog_info->hwnd);
|
||||
SelectObject(hdc, dialog_info->font);
|
||||
dialog_info->m.x_baseunit = GdiGetCharDimensions(hdc, NULL, &dialog_info->m.y_baseunit);
|
||||
ReleaseDC(dialog_info->hwnd, hdc);
|
||||
|
||||
dialog_info->m.h_spacing = DIALOG_SPACING;
|
||||
dialog_info->m.v_spacing = DIALOG_SPACING;
|
||||
taskdialog_du_to_px(dialog_info, &dialog_info->m.h_spacing, &dialog_info->m.v_spacing);
|
||||
|
||||
if (taskconfig->dwFlags & TDF_CALLBACK_TIMER)
|
||||
{
|
||||
|
@ -571,11 +625,13 @@ static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd)
|
|||
}
|
||||
|
||||
taskdialog_set_main_instruction_font(dialog_info);
|
||||
taskdialog_layout(dialog_info);
|
||||
}
|
||||
|
||||
static void taskdialog_destroy(struct taskdialog_info *dialog_info)
|
||||
{
|
||||
if (dialog_info->taskconfig->dwFlags & TDF_CALLBACK_TIMER) KillTimer(dialog_info->hwnd, ID_TIMER);
|
||||
if (dialog_info->font) DeleteObject(dialog_info->font);
|
||||
if (dialog_info->main_instruction_font) DeleteObject(dialog_info->main_instruction_font);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue