[2/4] comdlg32: Implement open dropdown menu.
Vincent Povirk
madewokherd at gmail.com
Tue Aug 25 15:39:12 CDT 2015
This implements the open dropdown button as a separate button, rather
than using BS_SPLITBUTTON, which is unimplemented in Wine. This adds
some complexity, but I don't think it changes things enough to get in
the way of other work on this component.
I have an implementation using BS_SPLITBUTTON that works on Windows,
and could theoretically be used once we have support for window class
redirection and BS_SPLITBUTTON. I will send that to wine-devel so you
can see how much complexity this approach adds, and what the correct
approach will look like.
-------------- next part --------------
From c36ad47aa72dc4f2565c0f489a3405eda19445c7 Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
Date: Wed, 19 Aug 2015 13:36:59 -0500
Subject: [PATCH 2/6] comdlg32: Implement open dropdown menu.
---
dlls/comdlg32/comdlg32.rc | 5 ++
dlls/comdlg32/itemdlg.c | 164 ++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 165 insertions(+), 4 deletions(-)
diff --git a/dlls/comdlg32/comdlg32.rc b/dlls/comdlg32/comdlg32.rc
index 6612dfd..f93b0b3 100644
--- a/dlls/comdlg32/comdlg32.rc
+++ b/dlls/comdlg32/comdlg32.rc
@@ -491,6 +491,11 @@ FONT 8, "MS Shell Dlg"
WS_CLIPSIBLINGS | CBS_HASSTRINGS | CBS_DROPDOWNLIST
DEFPUSHBUTTON "&Open", IDOK, 350, 240, 40, 14, WS_GROUP | WS_CLIPSIBLINGS
+
+ /* drop-down menu for open button */
+ CONTROL "6", psh1, "Button", WS_CHILD | WS_CLIPSIBLINGS | WS_GROUP | WS_TABSTOP |
+ BS_CHECKBOX | BS_PUSHLIKE, 342, 240, 8, 14
+
PUSHBUTTON "Cancel", IDCANCEL, 395, 240, 40, 14, WS_CLIPSIBLINGS
PUSHBUTTON "&Help", pshHelp, 350, 272, 40, 14, WS_CLIPSIBLINGS
}
diff --git a/dlls/comdlg32/itemdlg.c b/dlls/comdlg32/itemdlg.c
index 270c5d6..2fe9779 100644
--- a/dlls/comdlg32/itemdlg.c
+++ b/dlls/comdlg32/itemdlg.c
@@ -142,6 +142,9 @@ typedef struct FileDialogImpl {
HMENU hmenu_opendropdown;
customctrl cctrl_opendropdown;
+ HFONT hfont_opendropdown;
+ BOOL opendropdown_has_selection;
+ DWORD opendropdown_selection;
GUID client_guid;
} FileDialogImpl;
@@ -293,7 +296,7 @@ static HRESULT cctrl_event_OnButtonClicked(FileDialogImpl *This, DWORD ctl_id)
static HRESULT cctrl_event_OnItemSelected(FileDialogImpl *This, DWORD ctl_id, DWORD item_id)
{
events_client *cursor;
- TRACE("%p\n", This);
+ TRACE("%p %i %i\n", This, ctl_id, item_id);
LIST_FOR_EACH_ENTRY(cursor, &This->events_clients, events_client, entry)
{
@@ -703,6 +706,35 @@ static HRESULT on_default_action(FileDialogImpl *This)
return ret;
}
+static void show_opendropdown(FileDialogImpl *This)
+{
+ HWND open_hwnd;
+ RECT open_rc;
+ MSG msg;
+
+ open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
+
+ GetWindowRect(open_hwnd, &open_rc);
+
+ if (TrackPopupMenu(This->hmenu_opendropdown, 0, open_rc.left, open_rc.bottom, 0, This->dlg_hwnd, NULL) &&
+ PeekMessageW(&msg, This->dlg_hwnd, WM_MENUCOMMAND, WM_MENUCOMMAND, PM_REMOVE))
+ {
+ MENUITEMINFOW mii;
+
+ This->opendropdown_has_selection = TRUE;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_ID;
+ GetMenuItemInfoW((HMENU)msg.lParam, msg.wParam, TRUE, &mii);
+ This->opendropdown_selection = mii.wID;
+
+ if(SUCCEEDED(on_default_action(This)))
+ EndDialog(This->dlg_hwnd, S_OK);
+ else
+ This->opendropdown_has_selection = FALSE;
+ }
+}
+
/**************************************************************************
* Control item functions.
*/
@@ -734,6 +766,19 @@ static cctrl_item* get_item(customctrl* parent, DWORD itemid, CDCONTROLSTATEF vi
return NULL;
}
+static cctrl_item* get_first_item(customctrl* parent)
+{
+ cctrl_item* item;
+
+ LIST_FOR_EACH_ENTRY(item, &parent->sub_items, cctrl_item, entry)
+ {
+ if ((item->cdcstate & (CDCS_VISIBLE|CDCS_ENABLED)) == (CDCS_VISIBLE|CDCS_ENABLED))
+ return item;
+ }
+
+ return NULL;
+}
+
static HRESULT add_item(customctrl* parent, DWORD itemid, LPCWSTR label, cctrl_item** result)
{
cctrl_item* item;
@@ -1395,7 +1440,7 @@ static void update_layout(FileDialogImpl *This)
HDWP hdwp;
HWND hwnd;
RECT dialog_rc;
- RECT cancel_rc, open_rc;
+ RECT cancel_rc, dropdown_rc, open_rc;
RECT filetype_rc, filename_rc, filenamelabel_rc;
RECT toolbar_rc, ebrowser_rc, customctrls_rc;
static const UINT vspacing = 4, hspacing = 4;
@@ -1432,6 +1477,28 @@ static void update_layout(FileDialogImpl *This)
cancel_rc.bottom = cancel_rc.top + cancel_height;
}
+ /* Open/Save dropdown */
+ if(This->hmenu_opendropdown)
+ {
+ int dropdown_width, dropdown_height;
+ hwnd = GetDlgItem(This->dlg_hwnd, psh1);
+
+ GetWindowRect(hwnd, &dropdown_rc);
+ dropdown_width = dropdown_rc.right - dropdown_rc.left;
+ dropdown_height = dropdown_rc.bottom - dropdown_rc.top;
+
+ dropdown_rc.left = cancel_rc.left - dropdown_width - hspacing;
+ dropdown_rc.top = cancel_rc.top;
+ dropdown_rc.right = dropdown_rc.left + dropdown_width;
+ dropdown_rc.bottom = dropdown_rc.top + dropdown_height;
+ }
+ else
+ {
+ dropdown_rc.left = dropdown_rc.right = cancel_rc.left - hspacing;
+ dropdown_rc.top = cancel_rc.top;
+ dropdown_rc.bottom = cancel_rc.bottom;
+ }
+
/* Open/Save button */
hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
if(hwnd)
@@ -1441,8 +1508,8 @@ static void update_layout(FileDialogImpl *This)
open_width = open_rc.right - open_rc.left;
open_height = open_rc.bottom - open_rc.top;
- open_rc.left = cancel_rc.left - open_width - hspacing;
- open_rc.top = cancel_rc.top;
+ open_rc.left = dropdown_rc.left - open_width;
+ open_rc.top = dropdown_rc.top;
open_rc.right = open_rc.left + open_width;
open_rc.bottom = open_rc.top + open_height;
}
@@ -1553,6 +1620,10 @@ static void update_layout(FileDialogImpl *This)
DeferWindowPos(hdwp, hwnd, NULL, open_rc.left, open_rc.top, 0, 0,
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+ if(hdwp && This->hmenu_opendropdown && (hwnd = GetDlgItem(This->dlg_hwnd, psh1)))
+ DeferWindowPos(hdwp, hwnd, NULL, dropdown_rc.left, dropdown_rc.top, 0, 0,
+ SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+
if(hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDCANCEL)) )
DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0,
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
@@ -1737,6 +1808,44 @@ static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam)
(hitem = GetDlgItem(This->dlg_hwnd, IDC_FILENAME)) )
SendMessageW(hitem, WM_SETTEXT, 0, (LPARAM)This->set_filename);
+ if(This->hmenu_opendropdown)
+ {
+ RECT open_rc, dropdown_rc;
+ HWND open_hwnd, dropdown_hwnd;
+ LOGFONTW lfw, lfw_marlett;
+ HFONT dialog_font;
+ static const WCHAR marlett[] = {'M','a','r','l','e','t','t',0};
+
+ open_hwnd = GetDlgItem(This->dlg_hwnd, IDOK);
+ dropdown_hwnd = GetDlgItem(This->dlg_hwnd, psh1);
+
+ /* Show dropdown button, and remove its size from the open button */
+ ShowWindow(dropdown_hwnd, SW_SHOW);
+
+ GetWindowRect(open_hwnd, &open_rc);
+ GetWindowRect(dropdown_hwnd, &dropdown_rc);
+
+ SetWindowPos(open_hwnd, NULL, 0, 0,
+ (open_rc.right - open_rc.left) - (dropdown_rc.right - dropdown_rc.left),
+ open_rc.bottom - open_rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+
+ /* Change dropdown button font to Marlett */
+ dialog_font = (HFONT)SendMessageW(dropdown_hwnd, WM_GETFONT, 0, 0);
+
+ GetObjectW(dialog_font, sizeof(lfw), &lfw);
+
+ memset(&lfw_marlett, 0, sizeof(lfw_marlett));
+ lstrcpyW(lfw_marlett.lfFaceName, marlett);
+ lfw_marlett.lfHeight = lfw.lfHeight;
+ lfw_marlett.lfCharSet = SYMBOL_CHARSET;
+
+ This->hfont_opendropdown = CreateFontIndirectW(&lfw_marlett);
+
+ SendMessageW(dropdown_hwnd, WM_SETFONT, (LPARAM)This->hfont_opendropdown, 0);
+ }
+ else
+ ShowWindow(GetDlgItem(This->dlg_hwnd, psh1), SW_HIDE);
+
ctrl_container_reparent(This, This->dlg_hwnd);
init_explorerbrowser(This);
init_toolbar(This, hwnd);
@@ -1781,6 +1890,9 @@ static LRESULT on_wm_destroy(FileDialogImpl *This)
ctrl_container_reparent(This, NULL);
This->dlg_hwnd = NULL;
+ DeleteObject(This->hfont_opendropdown);
+ This->hfont_opendropdown = NULL;
+
return TRUE;
}
@@ -1803,6 +1915,19 @@ static LRESULT on_idcancel(FileDialogImpl *This)
return FALSE;
}
+static LRESULT on_command_opendropdown(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
+{
+ if(HIWORD(wparam) == BN_CLICKED)
+ {
+ HWND hwnd = (HWND)lparam;
+ SendMessageW(hwnd, BM_SETCHECK, BST_CHECKED, 0);
+ show_opendropdown(This);
+ SendMessageW(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
+ }
+
+ return FALSE;
+}
+
static LRESULT on_browse_back(FileDialogImpl *This)
{
TRACE("%p\n", This);
@@ -1872,6 +1997,7 @@ static LRESULT on_wm_command(FileDialogImpl *This, WPARAM wparam, LPARAM lparam)
{
case IDOK: return on_idok(This);
case IDCANCEL: return on_idcancel(This);
+ case psh1: return on_command_opendropdown(This, wparam, lparam);
case IDC_NAVBACK: return on_browse_back(This);
case IDC_NAVFORWARD: return on_browse_forward(This);
case IDC_FILETYPE: return on_command_filetype(This, wparam, lparam);
@@ -2021,6 +2147,7 @@ static ULONG WINAPI IFileDialog2_fnRelease(IFileDialog2 *iface)
LocalFree(This->custom_filenamelabel);
DestroyMenu(This->hmenu_opendropdown);
+ DeleteObject(This->hfont_opendropdown);
HeapFree(GetProcessHeap(), 0, This);
}
@@ -2033,6 +2160,8 @@ static HRESULT WINAPI IFileDialog2_fnShow(IFileDialog2 *iface, HWND hwndOwner)
FileDialogImpl *This = impl_from_IFileDialog2(iface);
TRACE("%p (%p)\n", iface, hwndOwner);
+ This->opendropdown_has_selection = FALSE;
+
return create_dialog(This, hwndOwner);
}
@@ -3369,6 +3498,7 @@ static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCusto
DWORD dwIDCtl)
{
FileDialogImpl *This = impl_from_IFileDialogCustomize(iface);
+ MENUINFO mi;
FIXME("semi-stub - %p (%d)\n", This, dwIDCtl);
if (This->hmenu_opendropdown || get_cctrl(This, dwIDCtl))
@@ -3379,6 +3509,11 @@ static HRESULT WINAPI IFileDialogCustomize_fnEnableOpenDropDown(IFileDialogCusto
if (!This->hmenu_opendropdown)
return E_OUTOFMEMORY;
+ mi.cbSize = sizeof(mi);
+ mi.fMask = MIM_STYLE;
+ mi.dwStyle = MNS_NOTIFYBYPOS;
+ SetMenuInfo(This->hmenu_opendropdown, &mi);
+
This->cctrl_opendropdown.hwnd = NULL;
This->cctrl_opendropdown.wrapper_hwnd = NULL;
This->cctrl_opendropdown.id = dwIDCtl;
@@ -3982,6 +4117,26 @@ static HRESULT WINAPI IFileDialogCustomize_fnGetSelectedControlItem(IFileDialogC
*pdwIDItem = SendMessageW(ctrl->hwnd, CB_GETITEMDATA, index, 0);
return S_OK;
}
+ case IDLG_CCTRL_OPENDROPDOWN:
+ if (This->opendropdown_has_selection)
+ {
+ *pdwIDItem = This->opendropdown_selection;
+ return S_OK;
+ }
+ else
+ {
+ /* Return first enabled item. */
+ cctrl_item* item = get_first_item(ctrl);
+
+ if (item)
+ {
+ *pdwIDItem = item->id;
+ return S_OK;
+ }
+
+ WARN("no enabled items in open dropdown\n");
+ return E_FAIL;
+ }
default:
FIXME("Unsupported control type %d\n", ctrl->type);
}
@@ -4167,6 +4322,7 @@ static HRESULT FileDialog_constructor(IUnknown *pUnkOuter, REFIID riid, void **p
fdimpl->client_guid = GUID_NULL;
fdimpl->hmenu_opendropdown = NULL;
+ fdimpl->hfont_opendropdown = NULL;
/* FIXME: The default folder setting should be restored for the
* application if it was previously set. */
--
2.1.4
More information about the wine-patches
mailing list