[PATCH v2 3/6] comctl32/taskdialog: Add support for expando button.
Zhiyi Zhang
zzhang at codeweavers.com
Wed Jul 18 22:04:15 CDT 2018
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
dlls/comctl32/comctl32.h | 4 +
dlls/comctl32/comctl32.rc | 6 ++
dlls/comctl32/taskdialog.c | 163 ++++++++++++++++++++++++++++++++++++-
3 files changed, 170 insertions(+), 3 deletions(-)
diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h
index eef2072e18..67da0e1677 100644
--- a/dlls/comctl32/comctl32.h
+++ b/dlls/comctl32/comctl32.h
@@ -107,6 +107,10 @@ extern HBRUSH COMCTL32_hPattern55AABrush DECLSPEC_HIDDEN;
#define IDS_BUTTON_CANCEL 3004
#define IDS_BUTTON_CLOSE 3005
+/* Task dialog expando control default text */
+#define IDS_TD_EXPANDED 3020
+#define IDS_TD_COLLAPSED 3021
+
#define WM_SYSTIMER 0x0118
enum combobox_state_flags
diff --git a/dlls/comctl32/comctl32.rc b/dlls/comctl32/comctl32.rc
index cea815a347..3f8e148bfa 100644
--- a/dlls/comctl32/comctl32.rc
+++ b/dlls/comctl32/comctl32.rc
@@ -56,6 +56,12 @@ STRINGTABLE
IDS_BUTTON_CLOSE "&Close"
}
+STRINGTABLE
+{
+ IDS_TD_EXPANDED "Hide details"
+ IDS_TD_COLLAPSED "See details"
+}
+
IDD_PROPSHEET DIALOG 0, 0, 220, 140
STYLE DS_CONTEXTHELP | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
CAPTION "Properties for %s"
diff --git a/dlls/comctl32/taskdialog.c b/dlls/comctl32/taskdialog.c
index db278cac46..54ad58b340 100644
--- a/dlls/comctl32/taskdialog.c
+++ b/dlls/comctl32/taskdialog.c
@@ -42,6 +42,8 @@ static const UINT DIALOG_MIN_WIDTH = 240;
static const UINT DIALOG_SPACING = 5;
static const UINT DIALOG_BUTTON_WIDTH = 50;
static const UINT DIALOG_BUTTON_HEIGHT = 14;
+static const UINT DIALOG_EXPANDO_ICON_WIDTH = 10;
+static const UINT DIALOG_EXPANDO_ICON_HEIGHT = 10;
static const UINT DIALOG_TIMER_MS = 200;
static const UINT ID_TIMER = 1;
@@ -63,6 +65,7 @@ struct taskdialog_info
HWND *command_links;
INT command_link_count;
HWND expanded_info;
+ HWND expando_button;
HWND *buttons;
INT button_count;
HWND default_button;
@@ -76,6 +79,8 @@ struct taskdialog_info
} m;
INT selected_radio_id;
BOOL expanded;
+ WCHAR *expanded_text;
+ WCHAR *collapsed_text;
};
struct button_layout_info
@@ -85,6 +90,7 @@ struct button_layout_info
};
static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, HWND hwnd);
+static void taskdialog_layout(struct taskdialog_info *dialog_info);
static void taskdialog_du_to_px(struct taskdialog_info *dialog_info, LONG *width, LONG *height)
{
@@ -222,11 +228,25 @@ static HRESULT taskdialog_notify(struct taskdialog_info *dialog_info, UINT notif
: S_OK;
}
+static void taskdialog_toggle_expando_control(struct taskdialog_info *dialog_info)
+{
+ dialog_info->expanded = !dialog_info->expanded;
+ ShowWindow(dialog_info->expanded_info, dialog_info->expanded ? SW_SHOWDEFAULT : SW_HIDE);
+ taskdialog_layout(dialog_info);
+}
+
static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, HWND hwnd)
{
INT command_id = GetWindowLongW(hwnd, GWLP_ID);
HWND radio_button;
+ if (hwnd == dialog_info->expando_button)
+ {
+ taskdialog_toggle_expando_control(dialog_info);
+ taskdialog_notify(dialog_info, TDN_EXPANDO_BUTTON_CLICKED, dialog_info->expanded, 0);
+ return;
+ }
+
radio_button = taskdialog_find_button(dialog_info->radio_buttons, dialog_info->radio_button_count, command_id);
if (radio_button)
{
@@ -357,6 +377,49 @@ static void taskdialog_get_radio_button_size(struct taskdialog_info *dialog_info
ReleaseDC(hwnd, hdc);
}
+static void taskdialog_get_expando_size(struct taskdialog_info *dialog_info, HWND hwnd, SIZE *size)
+{
+ DWORD style = DT_EXPANDTABS | DT_CALCRECT | DT_WORDBREAK;
+ HFONT hfont, old_hfont;
+ HDC hdc;
+ RECT rect = {0};
+ LONG icon_width, icon_height, text_offset;
+ LONG max_width, max_text_height;
+
+ hdc = GetDC(hwnd);
+ hfont = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
+ old_hfont = SelectObject(hdc, hfont);
+
+ icon_width = DIALOG_EXPANDO_ICON_WIDTH;
+ icon_height = DIALOG_EXPANDO_ICON_HEIGHT;
+ taskdialog_du_to_px(dialog_info, &icon_width, &icon_height);
+
+ GetCharWidthW(hdc, '0', '0', &text_offset);
+ text_offset /= 2;
+
+ if (dialog_info->taskconfig->dwFlags & TDF_RTL_LAYOUT)
+ style |= DT_RIGHT | DT_RTLREADING;
+ else
+ style |= DT_LEFT;
+
+ max_width = DIALOG_MIN_WIDTH / 2;
+ taskdialog_du_to_px(dialog_info, &max_width, NULL);
+
+ rect.right = max_width - icon_width - text_offset;
+ max_text_height = DrawTextW(hdc, dialog_info->expanded_text, -1, &rect, style);
+ size->cy = max(max_text_height, icon_height);
+ size->cx = rect.right - rect.left;
+
+ rect.right = max_width - icon_width - text_offset;
+ max_text_height = DrawTextW(hdc, dialog_info->collapsed_text, -1, &rect, style);
+ size->cy = max(size->cy, max_text_height);
+ size->cx = max(size->cx, rect.right - rect.left);
+ size->cx = min(size->cx, max_width);
+
+ if (old_hfont) SelectObject(hdc, old_hfont);
+ ReleaseDC(hwnd, hdc);
+}
+
static ULONG_PTR taskdialog_get_standard_icon(LPCWSTR icon)
{
if (icon == TD_WARNING_ICON)
@@ -544,6 +607,35 @@ static void taskdialog_add_expanded_info(struct taskdialog_info *dialog_info)
ShowWindow(dialog_info->expanded_info, dialog_info->expanded ? SW_SHOWDEFAULT : SW_HIDE);
}
+static void taskdialog_add_expando_button(struct taskdialog_info *dialog_info)
+{
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ const WCHAR *textW;
+
+ if (!taskconfig->pszExpandedInformation) return;
+
+ if (!taskconfig->pszCollapsedControlText && !taskconfig->pszExpandedControlText)
+ {
+ dialog_info->expanded_text = taskdialog_gettext(dialog_info, FALSE, MAKEINTRESOURCEW(IDS_TD_EXPANDED));
+ dialog_info->collapsed_text = taskdialog_gettext(dialog_info, FALSE, MAKEINTRESOURCEW(IDS_TD_COLLAPSED));
+ }
+ else
+ {
+ textW = taskconfig->pszExpandedControlText ? taskconfig->pszExpandedControlText
+ : taskconfig->pszCollapsedControlText;
+ dialog_info->expanded_text = taskdialog_gettext(dialog_info, TRUE, textW);
+ textW = taskconfig->pszCollapsedControlText ? taskconfig->pszCollapsedControlText
+ : taskconfig->pszExpandedControlText;
+ dialog_info->collapsed_text = taskdialog_gettext(dialog_info, TRUE, textW);
+ }
+
+ textW = dialog_info->expanded ? dialog_info->expanded_text : dialog_info->collapsed_text;
+
+ dialog_info->expando_button = CreateWindowW(WC_BUTTONW, textW, WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_OWNERDRAW, 0,
+ 0, 0, 0, dialog_info->hwnd, 0, 0, 0);
+ SendMessageW(dialog_info->expando_button, WM_SETFONT, (WPARAM)dialog_info->font, 0);
+}
+
static void taskdialog_add_button(struct taskdialog_info *dialog_info, HWND *button, INT_PTR id, const WCHAR *text,
BOOL custom_button)
{
@@ -622,6 +714,7 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
LONG screen_width, dialog_width, dialog_height = 0;
LONG h_spacing, v_spacing;
LONG main_icon_right, main_icon_bottom;
+ LONG expando_right, expando_bottom;
struct button_layout_info *button_layout_infos;
LONG button_min_width, button_height;
LONG *line_widths, line_count, align;
@@ -700,6 +793,19 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
dialog_height = max(dialog_height, main_icon_bottom);
+ expando_right = 0;
+ expando_bottom = dialog_height;
+ /* Expando control */
+ if (dialog_info->expando_button)
+ {
+ x = h_spacing;
+ y = dialog_height + v_spacing;
+ taskdialog_get_expando_size(dialog_info, dialog_info->expando_button, &size);
+ SetWindowPos(dialog_info->expando_button, 0, x, y, size.cx, size.cy, SWP_NOZORDER);
+ expando_right = x + size.cx;
+ expando_bottom = y + size.cy;
+ }
+
/* Common and custom buttons */
button_layout_infos = Alloc(dialog_info->button_count * sizeof(*button_layout_infos));
line_widths = Alloc(dialog_info->button_count * sizeof(*line_widths));
@@ -709,12 +815,13 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
taskdialog_du_to_px(dialog_info, &button_min_width, &button_height);
for (i = 0; i < dialog_info->button_count; i++)
{
- taskdialog_get_label_size(dialog_info, dialog_info->buttons[i], dialog_width - h_spacing * 2, &size, FALSE);
+ taskdialog_get_label_size(dialog_info, dialog_info->buttons[i], dialog_width - expando_right - h_spacing * 2,
+ &size, FALSE);
button_layout_infos[i].width = max(size.cx, button_min_width);
}
/* Separate buttons into lines */
- x = h_spacing;
+ x = expando_right + h_spacing;
for (i = 0, line_count = 0; i < dialog_info->button_count; i++)
{
button_layout_infos[i].line = line_count;
@@ -723,7 +830,7 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
if ((i + 1 < dialog_info->button_count) && (x + button_layout_infos[i + 1].width + h_spacing >= dialog_width))
{
- x = h_spacing;
+ x = expando_right + h_spacing;
line_count++;
}
}
@@ -778,6 +885,7 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
/* Add height for last row button and spacing */
dialog_height += size.cy + v_spacing;
+ dialog_height = max(dialog_height, expando_bottom);
Free(button_layout_infos);
Free(line_widths);
@@ -802,6 +910,41 @@ static void taskdialog_layout(struct taskdialog_info *dialog_info)
SetWindowPos(dialog_info->hwnd, 0, 0, 0, dialog_width, dialog_height, SWP_NOMOVE | SWP_NOZORDER);
}
+static void taskdialog_draw_expando_control(struct taskdialog_info *dialog_info, LPDRAWITEMSTRUCT dis)
+{
+ HWND hwnd;
+ HDC hdc;
+ RECT rect = {0};
+ WCHAR *text;
+ LONG icon_width, icon_height, text_offset;
+ UINT style = DFCS_FLAT;
+ BOOL draw_focus;
+
+ hdc = dis->hDC;
+ hwnd = dis->hwndItem;
+
+ SendMessageW(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
+
+ icon_width = DIALOG_EXPANDO_ICON_WIDTH;
+ icon_height = DIALOG_EXPANDO_ICON_HEIGHT;
+ taskdialog_du_to_px(dialog_info, &icon_width, &icon_height);
+ rect.right = icon_width;
+ rect.bottom = icon_height;
+ style |= dialog_info->expanded ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
+ DrawFrameControl(hdc, &rect, DFC_SCROLL, style);
+
+ GetCharWidthW(hdc, '0', '0', &text_offset);
+ text_offset /= 2;
+
+ rect = dis->rcItem;
+ rect.left += icon_width + text_offset;
+ text = dialog_info->expanded ? dialog_info->expanded_text : dialog_info->collapsed_text;
+ DrawTextW(hdc, text, -1, &rect, DT_WORDBREAK | DT_END_ELLIPSIS | DT_EXPANDTABS);
+
+ draw_focus = (dis->itemState & ODS_FOCUS) && !(dis->itemState & ODS_NOFOCUSRECT);
+ if(draw_focus) DrawFocusRect(hdc, &rect);
+}
+
static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd)
{
const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
@@ -839,6 +982,7 @@ static void taskdialog_init(struct taskdialog_info *dialog_info, HWND hwnd)
taskdialog_add_progress_bar(dialog_info);
taskdialog_add_radio_buttons(dialog_info);
taskdialog_add_command_links(dialog_info);
+ taskdialog_add_expando_button(dialog_info);
taskdialog_add_buttons(dialog_info);
/* Set default button */
@@ -860,6 +1004,8 @@ static void taskdialog_destroy(struct taskdialog_info *dialog_info)
Free(dialog_info->buttons);
Free(dialog_info->radio_buttons);
Free(dialog_info->command_links);
+ Free(dialog_info->expanded_text);
+ Free(dialog_info->collapsed_text);
}
static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
@@ -959,6 +1105,17 @@ static INT_PTR CALLBACK taskdialog_proc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
}
return FALSE;
}
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam;
+ if (dis->hwndItem == dialog_info->expando_button)
+ {
+ taskdialog_draw_expando_control(dialog_info, dis);
+ SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, TRUE);
+ break;
+ }
+ return FALSE;
+ }
case WM_DESTROY:
taskdialog_notify(dialog_info, TDN_DESTROYED, 0, 0);
RemovePropW(hwnd, taskdialog_info_propnameW);
--
2.18.0
More information about the wine-devel
mailing list