Implements navigation bar featuring: - back/forward buttons - go up button - address crumbs - hides crumbs when there's not enough space to display all of them - always shows at least 2 crumbs - truncating them if needed - first crumb is at least 56px - aligns label to the left if truncated - right clicking on the crumb, or free space, opens a menu with `Copy address as text` and `Edit address` options - reuses existing crumbs to avoid some flickering - overflow menu - first crumb is always moved here - removes the split, if there are no items in the menu - hidden crumbs are moved here - left or right click on the button starts address editing - address edit - accepts an existing path - expands environment variables, e.g. `%APPDATA%\Microsoft` -> `C:\users%USERNAME%\AppData\Roaming\Microsoft` - errors with a `MessageBox` on nonexistent paths - refresh button - changes into go to button when editing address - DPI scaling
Screenshots:
![navbar-crumbs-classic](/uploads/8c9a806b57f8e456fcbfd3cbc1ef3bb7/navbar-crumbs-classic.png)
![navbar-crumbs-light](/uploads/9c8a7acf9b55ae5ac182219edd45b65d/navbar-crumbs-light.png)
![navbar-edit-classic](/uploads/f68309bbc9200a8d8d4e3cd692179409/navbar-edit-classic.png)
![navbar-edit-light](/uploads/6798e79e6d2498a052b0ecbc2545c6e4/navbar-edit-light.png)
![navbar-120dpi-classic](/uploads/72abee382ab6171ff9c1b99a9065c845/navbar-120dpi-classic.png)
![navbar-120dpi-light](/uploads/538a030bc2028f8654d6c35d6f2825dd/navbar-120dpi-light.png)
Remaining issues: - crumbs not lighting up when hovered sometimes - can be observed in current file dialog, hovering over dropdown arrow of a file type fixes it for a moment - crumbs flickering on address change sometimes - mostly when there's not enough space to display all of them - `DeferWindowPos` doesn't seem to be atomic in Wine, presumably is in native Windows? - unexpected address conversion for some PIDLs - e.g. `Desktop` -> `C:\users%USERNAME%\Desktop`, which is an entirely different location - or `My Computer` into an empty string - known folders are not handled by address edit, e.g. `Desktop`, `My Computer` - icons are not DPI scaled - while writing this: ``` 0024:fixme:bitmap:NtGdiCreateBitmap planes = 0 0024:err:system:user_check_not_lock BUG: holding USER lock wine/dlls/win32u/sysparams.c:396: user_check_not_lock: Assertion `0' failed. wine: Assertion failed at address F7FF8549 (thread 0024), starting debugger... ``` - can't reproduce, happened when clicking on an item in overflow menu - race condition? cosmic ray?
Addresses following bugs: - https://bugs.winehq.org/show_bug.cgi?id=29912 - https://bugs.winehq.org/show_bug.cgi?id=50338 - https://bugs.winehq.org/show_bug.cgi?id=51855 (partially? no search box)
-- v5: comdlg32: Add refresh/go to button to IFileDialog navigation bar. comdlg32: Add address edit to IFileDialog navigation bar. comdlg32: Add breadcrumb overflow menu to IFileDialog navigation bar. comdlg32: Add address breadcrumbs to IFileDialog navigation bar. comdlg32: Add go up button to IFileDialog navigation bar. comdlg32: Add IFileDialog navigation bar.
From: Vladislav Timonin timoninvlad@yandex.ru
--- dlls/comdlg32/Makefile.in | 2 + dlls/comdlg32/comdlg32.rc | 4 + dlls/comdlg32/itemdlg.c | 84 ++--- dlls/comdlg32/navbar.bmp | Bin 0 -> 9354 bytes dlls/comdlg32/navbar.c | 143 ++++++++ dlls/comdlg32/navbar.h | 43 +++ dlls/comdlg32/navbar.svg | 676 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 910 insertions(+), 42 deletions(-) create mode 100644 dlls/comdlg32/navbar.bmp create mode 100644 dlls/comdlg32/navbar.c create mode 100644 dlls/comdlg32/navbar.h create mode 100644 dlls/comdlg32/navbar.svg
diff --git a/dlls/comdlg32/Makefile.in b/dlls/comdlg32/Makefile.in index 91a12f8a7e4..953796cec07 100644 --- a/dlls/comdlg32/Makefile.in +++ b/dlls/comdlg32/Makefile.in @@ -13,11 +13,13 @@ C_SRCS = \ finddlg.c \ fontdlg.c \ itemdlg.c \ + navbar.c \ printdlg.c
RC_SRCS = comdlg32.rc
SVG_SRCS = \ + navbar.svg \ pd32_collate.svg \ pd32_landscape.svg \ pd32_nocollate.svg \ diff --git a/dlls/comdlg32/comdlg32.rc b/dlls/comdlg32/comdlg32.rc index a5d09faa563..4710f1955b7 100644 --- a/dlls/comdlg32/comdlg32.rc +++ b/dlls/comdlg32/comdlg32.rc @@ -22,6 +22,7 @@ #include "cdlg.h" #include "colordlg.h" #include "filedlgbrowser.h" +#include "navbar.h"
#pragma makedep po
@@ -602,3 +603,6 @@ NETWORK ICON network.ico
/* @makedep: fontpics.bmp */ 38 BITMAP fontpics.bmp + +/* @makedep: navbar.bmp */ +IDB_NAVBAR BITMAP navbar.bmp diff --git a/dlls/comdlg32/itemdlg.c b/dlls/comdlg32/itemdlg.c index 95778c2f358..89b67f24e6f 100644 --- a/dlls/comdlg32/itemdlg.c +++ b/dlls/comdlg32/itemdlg.c @@ -37,11 +37,11 @@ #include "wine/debug.h" #include "wine/list.h"
-#define IDC_NAV_TOOLBAR 200 -#define IDC_NAVBACK 201 -#define IDC_NAVFORWARD 202 +#define IDC_NAVBAR 200
#include <initguid.h> +#include "navbar.h" + /* This seems to be another version of IID_IFileDialogCustomize. If * there is any difference I have yet to find it. */ DEFINE_GUID(IID_IFileDialogCustomizeAlt, 0x8016B7B3, 0x3D49, 0x4504, 0xA0,0xAA, 0x2A,0x37,0x49,0x4E,0x60,0x6F); @@ -1567,6 +1567,13 @@ static HRESULT init_custom_controls(FileDialogImpl *This) ERR("Failed to register RadioButtonList window class.\n"); }
+ if (!GetClassInfoW(COMDLG32_hInstance, WC_NAVBARW, &wc) || + wc.hInstance != COMDLG32_hInstance) + { + if (!NAVBAR_Register()) + ERR("Failed to register NavBar window class.\n"); + } + return S_OK; }
@@ -1638,7 +1645,7 @@ static void update_layout(FileDialogImpl *This) RECT dialog_rc; RECT cancel_rc, dropdown_rc, open_rc; RECT filetype_rc, filename_rc, filenamelabel_rc; - RECT toolbar_rc, ebrowser_rc, customctrls_rc; + RECT navbar_rc, ebrowser_rc, customctrls_rc; static const UINT vspacing = 4, hspacing = 4; static const UINT min_width = 320, min_height = 200; BOOL show_dropdown; @@ -1765,11 +1772,24 @@ static void update_layout(FileDialogImpl *This) filename_rc.bottom = filename_rc.top + filename_height; }
- hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR); - if(hwnd) + hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAVBAR); + if (hwnd) { - GetWindowRect(hwnd, &toolbar_rc); - MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2); + INT w, h; + + GetWindowRect(hwnd, &navbar_rc); + + navbar_rc.left = dialog_rc.left; + navbar_rc.right = dialog_rc.right; + + MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&navbar_rc, 2); + + w = navbar_rc.right - navbar_rc.left; + h = navbar_rc.bottom - navbar_rc.top; + navbar_rc.top = hspacing; + navbar_rc.bottom = navbar_rc.top + h; + navbar_rc.left = hspacing; + navbar_rc.right = w - hspacing; }
/* The custom controls */ @@ -1781,7 +1801,7 @@ static void update_layout(FileDialogImpl *This)
/* The ExplorerBrowser control. */ ebrowser_rc.left = dialog_rc.left + hspacing; - ebrowser_rc.top = toolbar_rc.bottom + vspacing; + ebrowser_rc.top = navbar_rc.bottom + vspacing; ebrowser_rc.right = dialog_rc.right - hspacing; ebrowser_rc.bottom = customctrls_rc.top - vspacing;
@@ -1790,7 +1810,7 @@ static void update_layout(FileDialogImpl *This) */
/* FIXME: The Save Dialog uses a slightly different layout. */ - hdwp = BeginDeferWindowPos(7); + hdwp = BeginDeferWindowPos(8);
if(hdwp && This->peb) IExplorerBrowser_SetRect(This->peb, &hdwp, ebrowser_rc); @@ -1827,6 +1847,11 @@ static void update_layout(FileDialogImpl *This) DeferWindowPos(hdwp, hwnd, NULL, cancel_rc.left, cancel_rc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+ if (hdwp && (hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAVBAR))) + DeferWindowPos(hdwp, hwnd, NULL, navbar_rc.left, navbar_rc.top, + navbar_rc.right - navbar_rc.left, navbar_rc.bottom - navbar_rc.top, + SWP_NOZORDER | SWP_NOACTIVATE); + if(hdwp) EndDeferWindowPos(hdwp); else @@ -1893,35 +1918,10 @@ static HRESULT init_explorerbrowser(FileDialogImpl *This)
static void init_toolbar(FileDialogImpl *This, HWND hwnd) { - HWND htoolbar; - TBADDBITMAP tbab; - TBBUTTON button[2]; - - htoolbar = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE, - 0, 0, 0, 0, - hwnd, (HMENU)IDC_NAV_TOOLBAR, NULL, NULL); - - tbab.hInst = HINST_COMMCTRL; - tbab.nID = IDB_HIST_LARGE_COLOR; - SendMessageW(htoolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab); - - button[0].iBitmap = HIST_BACK; - button[0].idCommand = IDC_NAVBACK; - button[0].fsState = TBSTATE_ENABLED; - button[0].fsStyle = BTNS_BUTTON; - button[0].dwData = 0; - button[0].iString = 0; - - button[1].iBitmap = HIST_FORWARD; - button[1].idCommand = IDC_NAVFORWARD; - button[1].fsState = TBSTATE_ENABLED; - button[1].fsStyle = BTNS_BUTTON; - button[1].dwData = 0; - button[1].iString = 0; - - SendMessageW(htoolbar, TB_ADDBUTTONSW, 2, (LPARAM)button); - SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(24,24)); - SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0); + CreateWindowExW(0, WC_NAVBARW, NULL, WS_CHILD | WS_VISIBLE, + 0, 0, + 0, MulDiv(30, This->dpi_y, USER_DEFAULT_SCREEN_DPI), + hwnd, (HMENU)IDC_NAVBAR, NULL, NULL); }
static void update_control_text(FileDialogImpl *This) @@ -2062,8 +2062,8 @@ static LRESULT on_wm_initdialog(HWND hwnd, LPARAM lParam) }
ctrl_container_reparent(This, This->dlg_hwnd); - init_explorerbrowser(This); init_toolbar(This, hwnd); + init_explorerbrowser(This); update_control_text(This); update_layout(This);
@@ -2216,8 +2216,6 @@ 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); default: TRACE("Unknown command.\n"); } @@ -2235,6 +2233,8 @@ static INT_PTR CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, case WM_SIZE: return on_wm_size(This); case WM_GETMINMAXINFO: return on_wm_getminmaxinfo(This, lparam); case WM_DESTROY: return on_wm_destroy(This); + case NBN_NAVBACK: return on_browse_back(This); + case NBN_NAVFORWARD: return on_browse_forward(This); }
return FALSE; diff --git a/dlls/comdlg32/navbar.bmp b/dlls/comdlg32/navbar.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b021235312d85a933d391af5eedb4ea8e06686da GIT binary patch literal 9354 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 Zp7V?HYZbi5{_(Y@-(G)X;Qx|=e*#-Ru^IpX
literal 0 HcmV?d00001
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c new file mode 100644 index 00000000000..bb247657797 --- /dev/null +++ b/dlls/comdlg32/navbar.c @@ -0,0 +1,143 @@ +/* + * Navigation bar control + * + * Copyright 2022 Vladislav Timonin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "navbar.h" +#include "commdlg.h" +#include "cdlg.h" + +/* private control ids */ +#define IDC_NAVBACK 201 +#define IDC_NAVFORWARD 202 + +typedef struct { + HWND parent_hwnd; + HWND container_hwnd; + + HIMAGELIST icons; + + HWND back_btn_hwnd; + HWND fwd_btn_hwnd; +} NAVBAR_INFO; + +static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + CREATESTRUCTW *cs = (CREATESTRUCTW*)lparam; + NAVBAR_INFO *info; + INT x; + HGDIOBJ gui_font = GetStockObject(DEFAULT_GUI_FONT); + HICON icon; + + info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NAVBAR_INFO)); + info->parent_hwnd = GetParent(hwnd); + info->container_hwnd = hwnd; + + info->icons = ImageList_LoadImageW(COMDLG32_hInstance, MAKEINTRESOURCEW(IDB_NAVBAR), 24, 0, + CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION); + + x = 0; + info->back_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, L"Back", + WS_CHILD | WS_VISIBLE | BS_ICON | BS_BITMAP, + x, 0, cs->cy, cs->cy, + hwnd, (HMENU)IDC_NAVBACK, COMDLG32_hInstance, NULL); + SendMessageW(info->back_btn_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); + icon = ImageList_GetIcon(info->icons, ILI_BACK, ILD_NORMAL); + SendMessageW(info->back_btn_hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)icon); + DestroyIcon(icon); + + x += cs->cy + 1; + info->fwd_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, L"Forward", + WS_CHILD | WS_VISIBLE | BS_ICON | BS_BITMAP, + x, 0, cs->cy, cs->cy, + hwnd, (HMENU)IDC_NAVFORWARD, COMDLG32_hInstance, NULL); + SendMessageW(info->fwd_btn_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); + icon = ImageList_GetIcon(info->icons, ILI_FORWARD, ILD_NORMAL); + SendMessageW(info->fwd_btn_hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)icon); + DestroyIcon(icon); + + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)info); + + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + +static LRESULT NAVBAR_Destroy(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + SetWindowLongPtrW(hwnd, 0, 0); + ImageList_Destroy(info->icons); + + HeapFree(GetProcessHeap(), 0, info); + + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + +static LRESULT NAVBAR_Command(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (LOWORD(wparam)) + { + case IDC_NAVBACK: + SendMessageW(info->parent_hwnd, NBN_NAVBACK, 0, 0); + break; + case IDC_NAVFORWARD: + SendMessageW(info->parent_hwnd, NBN_NAVFORWARD, 0, 0); + break; + } + + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + +static LRESULT CALLBACK NAVBAR_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + NAVBAR_INFO *info = (NAVBAR_INFO *)GetWindowLongPtrW(hwnd, 0); + + if (!info && (msg != WM_NCCREATE)) + goto exit; + + switch (msg) + { + case WM_NCCREATE: return NAVBAR_Create(hwnd, msg, wparam, lparam); + case WM_DESTROY: return NAVBAR_Destroy(hwnd, info, msg, wparam, lparam); + case WM_COMMAND: return NAVBAR_Command(hwnd, info, msg, wparam, lparam); + } + +exit: + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + +ATOM NAVBAR_Register(void) +{ + WNDCLASSW wndClass; + + ZeroMemory(&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_HREDRAW; + wndClass.lpfnWndProc = NAVBAR_WindowProc; + wndClass.cbWndExtra = sizeof(NAVBAR_INFO *); + wndClass.hInstance = COMDLG32_hInstance; + wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNSHADOW); + wndClass.lpszClassName = WC_NAVBARW; + + return RegisterClassW(&wndClass); +} + +BOOL NAVBAR_Unregister(void) +{ + return UnregisterClassW(WC_NAVBARW, COMDLG32_hInstance); +} diff --git a/dlls/comdlg32/navbar.h b/dlls/comdlg32/navbar.h new file mode 100644 index 00000000000..2699ca460ba --- /dev/null +++ b/dlls/comdlg32/navbar.h @@ -0,0 +1,43 @@ +/* + * Navigation bar control + * + * Copyright 2022 Vladislav Timonin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _WINE_NAVBAR +#define _WINE_NAVBAR + +#include "windows.h" + +#define WC_NAVBARW L"NavBar" + +/* navbar notifications */ +#define NBN_NAVBACK WM_USER + 102 +#define NBN_NAVFORWARD WM_USER + 103 + +/* bitmap ids */ +#define IDB_NAVBAR 3000 +/* icon indicies in IDB_NAVBAR */ +#define ILI_BACK 0 +#define ILI_FORWARD 1 +#define ILI_UP 2 +#define ILI_REFRESH 3 + +ATOM NAVBAR_Register(void); +BOOL NAVBAR_Unregister(void); + +#endif /* _WINE_NAVBAR */ diff --git a/dlls/comdlg32/navbar.svg b/dlls/comdlg32/navbar.svg new file mode 100644 index 00000000000..d4a9c943738 --- /dev/null +++ b/dlls/comdlg32/navbar.svg @@ -0,0 +1,676 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + id="bitmap:120-32" + height="24" + width="96" + version="1.1" + sodipodi:docname="navbar.svg" + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg%22%3E + <defs + id="defs2916"> + <radialGradient + id="radialGradient1361" + gradientUnits="userSpaceOnUse" + cy="36.421" + cx="24.837" + gradientTransform="matrix(1,0,0,0.536723,0,16.87306)" + r="15.645"> + <stop + id="stop8664" + stop-color="#000" + offset="0" /> + <stop + id="stop8666" + stop-color="#000" + stop-opacity="0" + offset="1" /> + </radialGradient> + <radialGradient + id="radialGradient3241" + gradientUnits="userSpaceOnUse" + cx="15.987" + cy="1.535" + r="17.171" + gradientTransform="matrix(-0.99935,0,0,0.783428,33.4962,1.6234577)"> + <stop + id="stop8652-1" + stop-color="#FFF" + offset="0" /> + <stop + id="stop8654-1" + stop-color="#FFF" + stop-opacity="0" + offset="1" /> + </radialGradient> + <radialGradient + id="radialGradient3244" + gradientUnits="userSpaceOnUse" + cx="17.481" + cy="16.118" + r="16.956" + gradientTransform="matrix(-0.411558,0.00716573,-0.00521275,-0.299389,21.69622,19.724318)"> + <stop + id="stop2593-6" + stop-color="#73d216" + offset="0" /> + <stop + id="stop2595-2" + stop-color="#4e9a06" + offset="1" /> + </radialGradient> + <radialGradient + id="radialGradient3263" + gradientUnits="userSpaceOnUse" + cx="15.987" + cy="1.535" + r="17.171" + gradientTransform="matrix(0.99731932,0,0,0.783428,14.565151,1.62346)"> + <stop + id="stop8652" + stop-color="#FFF" + offset="0" /> + <stop + id="stop8654" + stop-color="#FFF" + stop-opacity="0" + offset="1" /> + </radialGradient> + <radialGradient + id="radialGradient3266" + gradientUnits="userSpaceOnUse" + cx="27.547" + cy="15.843" + r="16.956" + gradientTransform="matrix(0.41071672,0.0074091,0.00521275,-0.288964,26.347891,19.75179)"> + <stop + id="stop2593" + stop-color="#73d216" + offset="0" /> + <stop + id="stop2595" + stop-color="#4e9a06" + offset="1" /> + </radialGradient> + <linearGradient + id="linearGradient3278" + y2="4" + gradientUnits="userSpaceOnUse" + y1="15" + gradientTransform="translate(96,-1)" + x2="4" + x1="4"> + <stop + id="stop10718" + stop-color="#d3d7cf" + offset="0" /> + <stop + id="stop10720" + stop-color="#babdb6" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3281" + y2="5" + gradientUnits="userSpaceOnUse" + y1="2" + gradientTransform="translate(96,0)" + x2="4" + x1="4"> + <stop + id="stop10746" + stop-color="#729fcf" + offset="0" /> + <stop + id="stop10748" + stop-color="#3465a4" + offset="1" /> + </linearGradient> + <radialGradient + id="radialGradient1361-2" + gradientUnits="userSpaceOnUse" + cy="36.421001" + cx="24.837" + gradientTransform="matrix(1,0,0,0.536723,0,16.87306)" + r="15.645"> + <stop + id="stop8664-9" + stop-color="#000" + offset="0" /> + <stop + id="stop8666-3" + stop-color="#000" + stop-opacity="0" + offset="1" /> + </radialGradient> + <radialGradient + id="radialGradient5915" + gradientUnits="userSpaceOnUse" + cy="20.839001" + cx="13.175" + gradientTransform="matrix(0,-0.41162,-0.513112,0,215.50763,22.608323)" + r="16.955999"> + <stop + id="stop2593-1" + stop-color="#73d216" + offset="0" /> + <stop + id="stop2595-9" + stop-color="#4e9a06" + offset="1" /> + </radialGradient> + <radialGradient + id="radialGradient5912" + gradientUnits="userSpaceOnUse" + cy="1.535" + cx="15.987" + gradientTransform="matrix(0,-0.99935,0.783428,0,193.62392,34.495966)" + r="17.171"> + <stop + id="stop8652-4" + stop-color="#FFF" + offset="0" /> + <stop + id="stop8654-7" + stop-color="#FFF" + stop-opacity="0" + offset="1" /> + </radialGradient> + <radialGradient + id="radialGradient1992" + gradientUnits="userSpaceOnUse" + cy="36.421001" + cx="24.837" + gradientTransform="matrix(1,0,0,0.536723,0,16.87306)" + r="15.645"> + <stop + id="stop8664-6" + stop-color="#000" + offset="0" /> + <stop + id="stop8666-1" + stop-color="#000" + stop-opacity="0" + offset="1" /> + </radialGradient> + <linearGradient + id="linearGradient3681" + y2="19.115" + gradientUnits="userSpaceOnUse" + x2="15.419" + gradientTransform="matrix(0.666667,0,0,0.646309,96.83003,1019.302)" + y1="10.612" + x1="13.479"> + <stop + id="stop2833" + stop-color="#3465a4" + offset="0" /> + <stop + id="stop2855" + stop-color="#5b86be" + offset="0.33333" /> + <stop + id="stop2835" + stop-color="#83a8d8" + stop-opacity="0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3683" + y2="26.194" + gradientUnits="userSpaceOnUse" + x2="37.064999" + gradientTransform="matrix(-0.666667,0,0,-0.646309,128.20505,1049.113)" + y1="29.73" + x1="37.127998"> + <stop + id="stop2849" + stop-color="#3465a4" + offset="0" /> + <stop + id="stop2851" + stop-color="#3465a4" + stop-opacity="0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3685" + y2="20.608999" + xlink:href="#linearGradient2380" + gradientUnits="userSpaceOnUse" + x2="15.985" + y1="36.061001" + x1="62.514" /> + <linearGradient + id="linearGradient2380"> + <stop + id="stop2382-9" + stop-color="#b9cfe7" + offset="0" /> + <stop + id="stop2384" + stop-color="#729fcf" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3687" + y2="50.939999" + xlink:href="#linearGradient2871" + gradientUnits="userSpaceOnUse" + x2="45.380001" + y1="45.264" + x1="46.834999" /> + <linearGradient + id="linearGradient2871"> + <stop + id="stop2873" + stop-color="#3465a4" + offset="0" /> + <stop + id="stop2875" + stop-color="#3465a4" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3691" + y2="24.841999" + gradientUnits="userSpaceOnUse" + x2="37.124001" + gradientTransform="matrix(0.666667,0,0,0.647455,96.519755,1019.8536)" + y1="30.749001" + x1="32.647999"> + <stop + id="stop2692" + stop-color="#c4d7eb" + offset="0" /> + <stop + id="stop2694" + stop-color="#c4d7eb" + stop-opacity="0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3693" + y2="24.841999" + gradientUnits="userSpaceOnUse" + x2="37.124001" + gradientTransform="matrix(0.666667,0,0,0.647455,96.519755,1019.8536)" + y1="31.455999" + x1="36.714001"> + <stop + id="stop2684" + stop-color="#3977c3" + offset="0" /> + <stop + id="stop2686" + stop-color="#89aedc" + stop-opacity="0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3695" + y2="26.649" + xlink:href="#linearGradient2402" + gradientUnits="userSpaceOnUse" + x2="53.589001" + y1="23.667999" + x1="18.936001" /> + <linearGradient + id="linearGradient2402"> + <stop + id="stop2404" + stop-color="#729fcf" + offset="0" /> + <stop + id="stop2406" + stop-color="#528ac5" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3703" + y2="26.048" + xlink:href="#linearGradient2797" + gradientUnits="userSpaceOnUse" + x2="52.854" + y1="26.048" + x1="5.9649" /> + <linearGradient + id="linearGradient2797"> + <stop + id="stop2799" + stop-color="#FFF" + offset="0" /> + <stop + id="stop2801" + stop-color="#FFF" + stop-opacity="0" + offset="1" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2380" + id="linearGradient3228" + gradientUnits="userSpaceOnUse" + x1="62.514" + y1="36.061001" + x2="15.985" + y2="20.608999" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2871" + id="linearGradient3230" + gradientUnits="userSpaceOnUse" + x1="46.834999" + y1="45.264" + x2="45.380001" + y2="50.939999" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2402" + id="linearGradient3232" + gradientUnits="userSpaceOnUse" + x1="18.936001" + y1="23.667999" + x2="53.589001" + y2="26.649" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2871" + id="linearGradient3234" + gradientUnits="userSpaceOnUse" + x1="46.834999" + y1="45.264" + x2="45.380001" + y2="50.939999" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2797" + id="linearGradient3236" + gradientUnits="userSpaceOnUse" + x1="5.9649" + y1="26.048" + x2="52.854" + y2="26.048" /> + </defs> + <g + id="g3268" + sodipodi:insensitive="true"> + <path + id="path8660" + opacity="0.321569" + style="color:#000000" + d="m 40.482,36.421 a 15.645,8.3969 0 1 1 -31.289,0 15.645,8.3969 0 1 1 31.289,0 z" + fill-rule="evenodd" + transform="matrix(0.703097,0,0,0.655005,18.537026,-6.3560112)" + fill="url(#radialGradient1361)" /> + <path + id="path8643" + stroke-linejoin="round" + style="color:#000000;stroke-dasharray:none" + d="m 28.501,16.5 v -9 h 5.9878 v -4 l 10.011,8.5554 -10.011,8.445 v -4 H 28.501 Z" + fill-rule="evenodd" + stroke-dashoffset="0" + stroke="#3a7304" + stroke-linecap="round" + stroke-miterlimit="10" + stroke-width="1" + fill="url(#radialGradient3266)" /> + <path + id="path8645" + opacity="0.508021" + style="color:#000000" + d="M 34.988,4.5 V 8 H 29 l 0.03167,4.5 c 5.9878,-3 8.9817,2 14.471,-0.5 l -8.515,-7.5 z" + fill-rule="evenodd" + fill="url(#radialGradient3263)" /> + <path + id="path8658" + opacity="0.481283" + stroke-linejoin="miter" + style="color:#000000;stroke-dasharray:none" + d="m 29.499,15.5 v -7 h 5.9878 v -3 l 7.4848,6.5 -7.4848,6.5 v -3 z" + stroke-dashoffset="0" + stroke="#ffffff" + stroke-linecap="butt" + stroke-miterlimit="10" + stroke-width="1" + fill="none" /> + </g> + <g + id="g3246" + sodipodi:insensitive="true"> + <path + id="path8660-4" + opacity="0.321569" + style="color:#000000" + d="m 40.482,36.421 a 15.645,8.3969 0 1 1 -31.289,0 15.645,8.3969 0 1 1 31.289,0 z" + fill-rule="evenodd" + transform="matrix(0.703097,0,0,0.655005,-5.4629086,-6.3560133)" + fill="url(#radialGradient1361)" /> + <path + id="path8643-2" + stroke-linejoin="round" + style="color:#000000;stroke-dasharray:none" + d="m 19.532,16.5 v -9 h -6 v -4 L 3.5,12.0554 13.532,20.5 v -4 z" + fill-rule="evenodd" + stroke-dashoffset="0" + stroke="#3a7304" + stroke-linecap="round" + stroke-miterlimit="10" + stroke-width="1" + fill="url(#radialGradient3244)" /> + <path + id="path8645-4" + opacity="0.508021" + style="color:#000000" + d="M 13.032,4.5 V 8 h 6 l -0.03173,4.5 c -6,-3 -9,2 -14.5,-0.5 l 8.5317,-7.5 z" + fill-rule="evenodd" + fill="url(#radialGradient3241)" /> + <path + id="path8658-0" + opacity="0.481283" + stroke-linejoin="miter" + style="color:#000000;stroke-dasharray:none" + d="m 18.532,15.5 v -7 h -6 v -3 l -7.5,6.5 7.5,6.5 v -3 z" + stroke-dashoffset="0" + stroke="#ffffff" + stroke-linecap="butt" + stroke-miterlimit="10" + stroke-width="1" + fill="none" /> + </g> + <g + id="g5917" + transform="translate(-143.99954,-2.7328773e-5)" + sodipodi:insensitive="true"> + <path + id="path8660-8" + opacity="0.204545" + style="color:#000000;fill:url(#radialGradient1361-2)" + d="m 40.482,36.421 a 15.645,8.3969 0 1 1 -31.289,0 15.645,8.3969 0 1 1 31.289,0 z" + fill-rule="evenodd" + transform="matrix(0.703097,0,0,0.357277,186.53732,7.0193119)" + fill="url(#radialGradient1361)" /> + <path + id="path8643-4" + stroke-linejoin="round" + style="color:#000000;fill:url(#radialGradient5915);stroke-dasharray:none" + d="m 208.5,20.532 h -9 v -6 h -4 l 8.56,-10.032 8.4446,10.032 h -4 v 6 z" + fill-rule="evenodd" + stroke-dashoffset="0" + stroke="#3a7304" + stroke-linecap="round" + stroke-miterlimit="10" + stroke-width="1" + fill="url(#radialGradient5915)" /> + <path + id="path8645-5" + opacity="0.508021" + style="color:#000000;fill:url(#radialGradient5912)" + d="m 196.5,14.032 h 3.5 v 6 h 1 c 0.5,-10 9,-7.5 3,-14.5 z" + fill-rule="evenodd" + fill="url(#radialGradient5912)" /> + <path + id="path8658-03" + opacity="0.481283" + stroke-linejoin="miter" + style="color:#000000;stroke-dasharray:none" + d="m 207.5,19.532 h -7 v -6 h -3 l 6.5,-7.5 6.5,7.5 h -3 z" + stroke-dashoffset="0" + stroke="#ffffff" + stroke-linecap="butt" + stroke-miterlimit="10" + stroke-width="1" + fill="none" /> + </g> + <g + id="g3876" + style="display:inline" + transform="matrix(0.75039848,0,0,0.75039848,0.02870684,-765.02849)"> + <path + id="path8660-0" + opacity="0.383333" + style="color:#000000;fill:url(#radialGradient1992)" + d="m 40.482,36.421 a 15.645,8.3969 0 1 1 -31.289,0 15.645,8.3969 0 1 1 31.289,0 z" + fill-rule="evenodd" + transform="matrix(-0.993158,0,0,-0.667502,137.20489,1070.0684)" + fill="url(#radialGradient1992)" /> + <g + id="g3667" + transform="translate(-0.41059,1.42455)"> + <path + id="path2865" + stroke-linejoin="miter" + style="color:#000000;fill:url(#linearGradient3681);stroke:url(#linearGradient3683);stroke-dasharray:none" + d="m 109.96,1026.2 c 0,0 -5.9583,-0.4039 -4.125,6.3823 h -5.125 c 0,0 0.33334,-7.6749 9.25,-6.3823 z" + fill-rule="nonzero" + stroke-dashoffset="0" + display="block" + stroke="url(#linearGradient3683)" + stroke-linecap="butt" + stroke-miterlimit="4" + stroke-width="1" + fill="url(#linearGradient3681)" /> + <g + id="g1878" + transform="matrix(-0.386034,-0.316192,-0.326152,0.374245,134.46368,1028.1234)" + stroke="#3465a4" + stroke-width="1.52344" + fill="url(#linearGradient3685)" + style="fill:url(#linearGradient3685)"> + <path + id="path1880" + stroke-linejoin="miter" + style="color:#000000;fill:url(#linearGradient3228);stroke:url(#linearGradient3230);stroke-dasharray:none" + d="M 44.307,50.23 C 62.821,35.819 49.665,13.412 22.462,12.498 l -0.348,-9.3465 -14.49,17.346 15.09,12.722 c 0,0 -0.25192,-9.8812 -0.25192,-9.8812 18.83,0.99898 32.982,14.072 21.844,26.892 z" + fill-rule="nonzero" + stroke-dashoffset="0" + display="block" + stroke="url(#linearGradient3687)" + stroke-linecap="butt" + stroke-miterlimit="4" + stroke-width="2.00968" + fill="url(#linearGradient3685)" /> + </g> + <path + id="path2839" + stroke-linejoin="miter" + style="color:#000000;fill:url(#linearGradient3691);stroke:url(#linearGradient3693);stroke-dasharray:none" + d="m 115.44,1041.5 c 0,0 5.9583,0.4046 4.125,-6.3936 h 5.1839 c 0,0.9728 -0.39226,7.6885 -9.3089,6.3936 z" + fill-rule="nonzero" + stroke-dashoffset="0" + display="block" + stroke="url(#linearGradient3693)" + stroke-linecap="butt" + stroke-miterlimit="4" + stroke-width="1" + fill="url(#linearGradient3691)" /> + <g + id="g2779" + stroke-linejoin="miter" + style="color:#000000;fill:url(#linearGradient3695);stroke:url(#linearGradient3687);stroke-dasharray:none" + fill-rule="nonzero" + display="block" + stroke-dashoffset="0" + transform="matrix(0.386034,0.316753,0.326152,-0.374909,91.23907,1039.6243)" + stroke="url(#linearGradient3687)" + stroke-linecap="butt" + stroke-miterlimit="4" + stroke-width="2.0079" + fill="url(#linearGradient3695)"> + <path + id="path2781" + stroke-linejoin="miter" + style="color:#000000;fill:url(#linearGradient3232);stroke:url(#linearGradient3234);stroke-dasharray:none" + d="M 44.307,50.23 C 62.821,35.819 49.665,13.412 22.462,12.498 L 22.399,3.069 7.794,20.424 22.462,33.006 v -9.6684 c 18.83,0.99898 32.982,14.072 21.844,26.892 z" + fill-rule="nonzero" + stroke-dashoffset="0" + display="block" + stroke="url(#linearGradient3687)" + stroke-linecap="butt" + stroke-miterlimit="4" + stroke-width="2.0079" + fill="url(#linearGradient3695)" /> + </g> + <path + id="path2791" + opacity="0.272222" + style="color:#000000" + d="m 101.42,1044.2 -0.005,-9.2715 8.1406,-0.04 -2.8009,3.2437 2.7032,1.7397 c -2,1.4568 -2.9393,1.3182 -3.606,2.9773 l -1.9248,-1.4913 -2.5069,2.8418 z" + fill-rule="nonzero" + fill="#ffffff" /> + <g + id="g2793" + opacity="0.5" + transform="matrix(0.328713,0.262901,0.277723,-0.311169,94.451191,1039.6682)" + stroke="#ffffff" + stroke-width="1.59006" + fill="none"> + <path + id="path2795" + stroke-linejoin="miter" + style="color:#000000;stroke:url(#linearGradient3236);stroke-dasharray:none" + d="M 51.77,46.731 C 60.89,31.511 46.465,11.426 18.287,12.242 l -0.061,-7.0152 -11.692,14.07 11.502,9.847 c 0,0 0.05562,-9.0069 0.05562,-9.0069 23.572,0.79434 37.206,12.015 33.678,26.594 z" + stroke-dashoffset="0" + display="block" + stroke="url(#linearGradient3703)" + stroke-linecap="butt" + stroke-miterlimit="4" + stroke-width="2.38842" + fill="none" /> + </g> + <g + id="g2805" + opacity="0.5" + transform="matrix(-0.339024,-0.277687,-0.286434,0.328671,131.88578,1028.1196)" + stroke="#ffffff" + stroke-width="1.52344" + fill="none"> + <path + id="path2807" + stroke-linejoin="miter" + style="color:#000000;stroke:url(#linearGradient3703);stroke-dasharray:none" + d="M 51.39,46.506 C 60.51,31.286 46.287,13.118 18.865,12.756 l -0.203,-6.8084 -11.22,13.22 11.585,9.795 c 0,0 -0.31396,-8.424 -0.31396,-8.424 22.406,0.47504 35.698,11.698 32.677,25.967 z" + stroke-dashoffset="0" + display="block" + stroke="url(#linearGradient3703)" + stroke-linecap="butt" + stroke-miterlimit="4" + stroke-width="2.28835" + fill="none" /> + </g> + <path + id="path2811" + opacity="0.272222" + style="color:#000000" + d="m 101.06,1030.1 c 1.8331,-6.967 11.056,-4.1901 13.552,-3.1271 2.7835,0.1366 3.6269,-1.4573 5.8438,-1.564 -9.3665,-6.3273 -18.708,-4.0447 -19.396,4.6911 z" + fill-rule="nonzero" + fill="#ffffff" /> + </g> + </g> +</svg>
From: Vladislav Timonin timoninvlad@yandex.ru
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=29912
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51855 --- dlls/comdlg32/itemdlg.c | 8 ++++++++ dlls/comdlg32/navbar.c | 15 +++++++++++++++ dlls/comdlg32/navbar.h | 1 + 3 files changed, 24 insertions(+)
diff --git a/dlls/comdlg32/itemdlg.c b/dlls/comdlg32/itemdlg.c index 89b67f24e6f..703f525b7ca 100644 --- a/dlls/comdlg32/itemdlg.c +++ b/dlls/comdlg32/itemdlg.c @@ -2160,6 +2160,13 @@ static LRESULT on_browse_forward(FileDialogImpl *This) return FALSE; }
+static LRESULT on_browse_up(FileDialogImpl *This) +{ + TRACE("%p\n", This); + IExplorerBrowser_BrowseToIDList(This->peb, NULL, SBSP_PARENT); + return FALSE; +} + static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam) { if(HIWORD(wparam) == CBN_SELCHANGE) @@ -2235,6 +2242,7 @@ static INT_PTR CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, case WM_DESTROY: return on_wm_destroy(This); case NBN_NAVBACK: return on_browse_back(This); case NBN_NAVFORWARD: return on_browse_forward(This); + case NBN_NAVUP: return on_browse_up(This); }
return FALSE; diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index bb247657797..abf63e7bcde 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -27,6 +27,7 @@ /* private control ids */ #define IDC_NAVBACK 201 #define IDC_NAVFORWARD 202 +#define IDC_NAVUP 203
typedef struct { HWND parent_hwnd; @@ -36,6 +37,7 @@ typedef struct {
HWND back_btn_hwnd; HWND fwd_btn_hwnd; + HWND up_btn_hwnd; } NAVBAR_INFO;
static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) @@ -73,6 +75,16 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) SendMessageW(info->fwd_btn_hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)icon); DestroyIcon(icon);
+ x += cs->cy + 1; + info->up_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, L"Up", + WS_CHILD | WS_VISIBLE | BS_ICON | BS_BITMAP, + x, 0, cs->cy, cs->cy, + hwnd, (HMENU)IDC_NAVUP, COMDLG32_hInstance, NULL); + SendMessageW(info->up_btn_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); + icon = ImageList_GetIcon(info->icons, ILI_UP, ILD_NORMAL); + SendMessageW(info->up_btn_hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)icon); + DestroyIcon(icon); + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)info);
return DefWindowProcW(hwnd, msg, wparam, lparam); @@ -98,6 +110,9 @@ static LRESULT NAVBAR_Command(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa case IDC_NAVFORWARD: SendMessageW(info->parent_hwnd, NBN_NAVFORWARD, 0, 0); break; + case IDC_NAVUP: + SendMessageW(info->parent_hwnd, NBN_NAVUP, 0, 0); + break; }
return DefWindowProcW(hwnd, msg, wparam, lparam); diff --git a/dlls/comdlg32/navbar.h b/dlls/comdlg32/navbar.h index 2699ca460ba..111439ccbad 100644 --- a/dlls/comdlg32/navbar.h +++ b/dlls/comdlg32/navbar.h @@ -28,6 +28,7 @@ /* navbar notifications */ #define NBN_NAVBACK WM_USER + 102 #define NBN_NAVFORWARD WM_USER + 103 +#define NBN_NAVUP WM_USER + 104
/* bitmap ids */ #define IDB_NAVBAR 3000
From: Vladislav Timonin timoninvlad@yandex.ru
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50338
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51855 --- dlls/comdlg32/itemdlg.c | 19 +++ dlls/comdlg32/navbar.c | 369 ++++++++++++++++++++++++++++++++++++++++ dlls/comdlg32/navbar.h | 4 + 3 files changed, 392 insertions(+)
diff --git a/dlls/comdlg32/itemdlg.c b/dlls/comdlg32/itemdlg.c index 703f525b7ca..453c83dcf1a 100644 --- a/dlls/comdlg32/itemdlg.c +++ b/dlls/comdlg32/itemdlg.c @@ -2167,6 +2167,15 @@ static LRESULT on_browse_up(FileDialogImpl *This) return FALSE; }
+static LRESULT on_browse_pidl(FileDialogImpl *This, LPARAM lparam) +{ + ITEMIDLIST* pidl = (ITEMIDLIST*)lparam; + + TRACE("%p - pidl %p\n", This, pidl); + IExplorerBrowser_BrowseToIDList(This->peb, pidl, SBSP_ABSOLUTE); + return FALSE; +} + static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam) { if(HIWORD(wparam) == CBN_SELCHANGE) @@ -2243,6 +2252,7 @@ static INT_PTR CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, case NBN_NAVBACK: return on_browse_back(This); case NBN_NAVFORWARD: return on_browse_forward(This); case NBN_NAVUP: return on_browse_up(This); + case NBN_NAVPIDL: return on_browse_pidl(This, lparam); }
return FALSE; @@ -3362,6 +3372,7 @@ static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBro { FileDialogImpl *This = impl_from_IExplorerBrowserEvents(iface); HRESULT hr; + HWND hwnd; TRACE("%p (%p)\n", This, pidlFolder);
if(This->psi_folder) @@ -3373,6 +3384,14 @@ static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBro ERR("Failed to get the current folder.\n"); This->psi_folder = NULL; } + else + { + hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAVBAR); + if (hwnd) + SendMessageW(hwnd, NBM_SETPIDL, 0, (LPARAM)pidlFolder); + else + ERR("Failed to update navbar.\n"); + }
events_OnFolderChange(This);
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index abf63e7bcde..c295a14d236 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -23,34 +23,260 @@ #include "navbar.h" #include "commdlg.h" #include "cdlg.h" +#include "shlwapi.h" + +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
/* private control ids */ #define IDC_NAVBACK 201 #define IDC_NAVFORWARD 202 #define IDC_NAVUP 203 +#define IDC_NAVCRUMB 204
typedef struct { HWND parent_hwnd; HWND container_hwnd; + INT container_h; + INT dpi_x;
HIMAGELIST icons;
HWND back_btn_hwnd; HWND fwd_btn_hwnd; HWND up_btn_hwnd; + + HWND background_hwnd; + INT background_x; + INT background_w; + + struct list crumbs; + INT crumbs_total_n; + INT crumbs_visible_n; } NAVBAR_INFO;
+struct crumb { + struct list entry; + ITEMIDLIST *pidl; + WCHAR display_name[MAX_PATH]; + HWND hwnd; + INT full_w; + INT current_w; + INT x; +}; + +static LRESULT CALLBACK NAVBAR_BACKGROUND_SubclassProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id_subclass, DWORD_PTR ref_data) +{ + switch (msg) + { + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + RECT rc; + HBRUSH old_brush; + HBRUSH bg_brush = GetSysColorBrush(COLOR_BTNFACE); + HBRUSH frame_brush = GetSysColorBrush(COLOR_3DSHADOW); + + GetClientRect(hwnd, &rc); + + /* clear background to avoid border trailing when resizing */ + FillRect(hdc, &rc, bg_brush); + + /* draw 1px frame */ + FrameRect(hdc, &rc, frame_brush); + + /* erase left border, retaining top and bottom pixels */ + old_brush = SelectObject(hdc, bg_brush); + PatBlt(hdc, rc.left, rc.top + 1, 1, rc.bottom - rc.top - 2, PATCOPY); + + SelectObject(hdc, old_brush); + + return FALSE; /* processed */ + } + } + + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + +static void NAVBAR_CalcLayout(NAVBAR_INFO *info) +{ + RECT container_rc, up_button_rc; + struct crumb *crumb1, *crumb2; + INT padding, container_w, + buttons_w, max_crumbs_w, + w = 0, crumbs_visible_n = 0, prev_x; + + if (!GetWindowRect(info->container_hwnd, &container_rc)) + return; + padding = container_rc.left; + + if (!GetClientRect(info->container_hwnd, &container_rc)) + return; + container_w = container_rc.right - container_rc.left; + if (!container_w) + return; + + if (!GetWindowRect(info->up_btn_hwnd, &up_button_rc)) + return; + + buttons_w = up_button_rc.right + 1 - padding; + max_crumbs_w = container_w - buttons_w; + if (max_crumbs_w < 0) + return; + + LIST_FOR_EACH_ENTRY_REV(crumb1, &info->crumbs, struct crumb, entry) + { + INT next_w = w + crumb1->full_w; + crumb1->current_w = crumb1->full_w; + if (next_w > max_crumbs_w) + break; + + w = next_w; + crumbs_visible_n += 1; + } + + /* always show at least 2 crumbs */ + if (crumbs_visible_n < 2) + { + w = 0; + + crumb1 = (struct crumb *)list_tail(&info->crumbs); + if (&crumb1->entry == &info->crumbs) + { + ERR("no crumbs to layout\n"); + return; + } + + crumb2 = (struct crumb *)list_tail(&crumb1->entry); + if (&crumb2->entry == &info->crumbs) /* only 1 crumb in the list */ + { + if (crumbs_visible_n == 0) /* that doesn't fit on screen */ + { + crumb1->current_w = max_crumbs_w; + crumbs_visible_n = 1; + } + + prev_x = buttons_w + crumb1->current_w; + } + else + { + /* at least 2 crumbs in the list, 1 or 0 crumbs on screen */ + /* last crumb should take as much space as possible */ + INT min_crumb_w = MulDiv(56, info->dpi_x, USER_DEFAULT_SCREEN_DPI); + INT crumb2_size = crumb2->full_w; + + if (crumb2_size > min_crumb_w) + crumb2_size = min_crumb_w; + + /* calculate how much extra space is required to fit both crumbs */ + w = (crumb1->full_w + crumb2_size) - max_crumbs_w; + if (w > 0) + { + /* not enough space for last crumb, truncate it */ + crumb1->current_w = max(0, crumb1->full_w - w); + crumb2->current_w = crumb2_size; + } + else + { + /* enough space for last crumb, let the second crumb take leftover space */ + crumb2_size = max_crumbs_w - crumb1->full_w; + if (crumb2_size < crumb2->full_w) + crumb2->current_w = crumb2_size; + } + + crumbs_visible_n = 2; + prev_x = buttons_w + crumb1->current_w + crumb2->current_w; + } + } + else + prev_x = buttons_w + w; + + info->background_x = prev_x; + info->background_w = container_rc.right - prev_x; + + info->crumbs_visible_n = crumbs_visible_n; + + LIST_FOR_EACH_ENTRY_REV(crumb1, &info->crumbs, struct crumb, entry) + { + if (crumbs_visible_n > 0) + { + LONG_PTR style = WS_CHILD | WS_VISIBLE; + + /* if label doesn't fully fit, align it to the left */ + if (crumb1->current_w < crumb1->full_w) + style |= BS_LEFT; + else + style |= BS_CENTER; + + SetWindowLongPtrW(crumb1->hwnd, GWL_STYLE, style); + + crumb1->x = prev_x - crumb1->current_w; + prev_x = crumb1->x; + } + else + break; + + crumbs_visible_n -= 1; + } +} + +static HDWP NAVBAR_DoLayout(NAVBAR_INFO *info, HDWP hdwp) +{ + struct crumb *crumb; + INT can_fit_n = info->crumbs_visible_n; + UINT background_flags = 0; + + LIST_FOR_EACH_ENTRY_REV(crumb, &info->crumbs, struct crumb, entry) + { + UINT flags = 0; + + if (can_fit_n > 0) + flags |= SWP_SHOWWINDOW | SWP_NOCOPYBITS; + else + flags |= SWP_HIDEWINDOW; + + hdwp = DeferWindowPos(hdwp, crumb->hwnd, HWND_TOP, + crumb->x, 0, + crumb->current_w, info->container_h, + flags); + + can_fit_n -= 1; + } + + if (info->background_w > 0) + background_flags |= SWP_SHOWWINDOW | SWP_NOCOPYBITS; + else + background_flags |= SWP_HIDEWINDOW; + + hdwp = DeferWindowPos(hdwp, info->background_hwnd, HWND_TOP, + info->background_x, 0, + info->background_w, info->container_h, + background_flags); + + return hdwp; +} + static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { CREATESTRUCTW *cs = (CREATESTRUCTW*)lparam; NAVBAR_INFO *info; + HDC hdc; INT x; HGDIOBJ gui_font = GetStockObject(DEFAULT_GUI_FONT); HICON icon;
info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NAVBAR_INFO)); + list_init(&info->crumbs); info->parent_hwnd = GetParent(hwnd); info->container_hwnd = hwnd; + info->container_h = cs->cy; + + hdc = GetDC(0); + info->dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); + ReleaseDC(0, hdc);
info->icons = ImageList_LoadImageW(COMDLG32_hInstance, MAKEINTRESOURCEW(IDB_NAVBAR), 24, 0, CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION); @@ -85,6 +311,13 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) SendMessageW(info->up_btn_hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)icon); DestroyIcon(icon);
+ x += cs->cy + 1; + info->background_hwnd = CreateWindowExW(0, WC_STATICW, NULL, + WS_CHILD | WS_VISIBLE, + x, 0, 0, cs->cy, + hwnd, 0, COMDLG32_hInstance, NULL); + SetWindowSubclass(info->background_hwnd, NAVBAR_BACKGROUND_SubclassProc, 0, (DWORD_PTR)info); + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)info);
return DefWindowProcW(hwnd, msg, wparam, lparam); @@ -92,6 +325,18 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
static LRESULT NAVBAR_Destroy(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) { + struct crumb *crumb1, *crumb2; + + LIST_FOR_EACH_ENTRY_SAFE(crumb1, crumb2, &info->crumbs, struct crumb, entry) + { + ITEMIDLIST *pidl = NULL; + pidl = (ITEMIDLIST*)GetWindowLongPtrW(crumb1->hwnd, GWLP_USERDATA); + ILFree(pidl); + + list_remove(&crumb1->entry); + HeapFree(GetProcessHeap(), 0, crumb1); + } + SetWindowLongPtrW(hwnd, 0, 0); ImageList_Destroy(info->icons);
@@ -100,6 +345,19 @@ static LRESULT NAVBAR_Destroy(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa return DefWindowProcW(hwnd, msg, wparam, lparam); }
+static LRESULT NAVBAR_Size(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + HDWP hdwp; + + NAVBAR_CalcLayout(info); + + hdwp = BeginDeferWindowPos(info->crumbs_total_n + 1); + hdwp = NAVBAR_DoLayout(info, hdwp); + EndDeferWindowPos(hdwp); + + return TRUE; +} + static LRESULT NAVBAR_Command(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) { switch (LOWORD(wparam)) @@ -113,11 +371,120 @@ static LRESULT NAVBAR_Command(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa case IDC_NAVUP: SendMessageW(info->parent_hwnd, NBN_NAVUP, 0, 0); break; + case IDC_NAVCRUMB: + { + HWND crumb = (HWND)lparam; + ITEMIDLIST *pidl = (ITEMIDLIST*)GetWindowLongPtrW(crumb, GWLP_USERDATA); + SendMessageW(info->parent_hwnd, NBN_NAVPIDL, 0, (LPARAM)pidl); + break; + } }
return DefWindowProcW(hwnd, msg, wparam, lparam); }
+static LRESULT NAVBAR_SetPIDL(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + ITEMIDLIST *pidl = (ITEMIDLIST *)lparam; + IShellFolder *desktop; + HGDIOBJ gui_font = GetStockObject(DEFAULT_GUI_FONT); + HRESULT hr; + INT padding = MulDiv(10, info->dpi_x, USER_DEFAULT_SCREEN_DPI); + struct list new_crumbs; + struct crumb *crumb1, *crumb2; + HDWP hdwp; + + TRACE("info %p pidl %p\n", info, pidl); + + hr = SHGetDesktopFolder(&desktop); + if (FAILED(hr)) + { + ERR("failed to get desktop folder\n"); + goto exit; + } + + list_init(&new_crumbs); + info->crumbs_total_n = 0; + pidl = ILClone(pidl); + do + { + STRRET strret; + SIZE full_size; + + crumb1 = HeapAlloc(GetProcessHeap(), 0, sizeof(*crumb1)); + + crumb1->pidl = ILClone(pidl); + IShellFolder_GetDisplayNameOf(desktop, pidl, SHGDN_FORADDRESSBAR, &strret); + StrRetToBufW(&strret, pidl, crumb1->display_name, MAX_PATH); + + crumb1->hwnd = CreateWindowExW(0, WC_BUTTONW, crumb1->display_name, WS_CHILD, + 0, 0, 0, 0, + info->container_hwnd, (HMENU)IDC_NAVCRUMB, COMDLG32_hInstance, NULL); + SendMessageW(crumb1->hwnd, WM_SETFONT, (LPARAM)gui_font, FALSE); + SendMessageW(crumb1->hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&full_size); + SetWindowLongPtrW(crumb1->hwnd, GWLP_USERDATA, (LPARAM)crumb1->pidl); + + crumb1->full_w = full_size.cx + padding; + crumb1->current_w = crumb1->full_w; + + /* PIDL is iterated from right-to-left, prepend the crumb to store them in left-to-right order */ + list_add_head(&new_crumbs, &crumb1->entry); + info->crumbs_total_n += 1; + } + while (ILRemoveLastID(pidl)); + ILFree(pidl); + + /* reuse existing crumbs */ + crumb1 = LIST_ENTRY((&info->crumbs)->next, struct crumb, entry); + crumb2 = LIST_ENTRY((&new_crumbs)->next, struct crumb, entry); + for (;;) + { + if (&crumb1->entry == &info->crumbs || + &crumb2->entry == &new_crumbs || + !ILIsEqual(crumb2->pidl, crumb1->pidl)) + break; + + DestroyWindow(crumb2->hwnd); + ILFree(crumb2->pidl); + crumb2->pidl = crumb1->pidl; + crumb2->hwnd = crumb1->hwnd; + + crumb1 = LIST_ENTRY(crumb1->entry.next, struct crumb, entry); + crumb2 = LIST_ENTRY(crumb2->entry.next, struct crumb, entry); + } + + /* cleanup unused existing crumbs */ + for (;;) + { + if (&crumb1->entry == &info->crumbs) + break; + + DestroyWindow(crumb1->hwnd); + ILFree(crumb1->pidl); + + crumb1 = LIST_ENTRY(crumb1->entry.next, struct crumb, entry); + } + + LIST_FOR_EACH_ENTRY_SAFE(crumb1, crumb2, &info->crumbs, struct crumb, entry) + { + list_remove(&crumb1->entry); + HeapFree(GetProcessHeap(), 0, crumb1); + } + + new_crumbs.next->prev = &info->crumbs; + new_crumbs.prev->next = &info->crumbs; + info->crumbs = new_crumbs; + + NAVBAR_CalcLayout(info); + + hdwp = BeginDeferWindowPos(info->crumbs_total_n + 1); + hdwp = NAVBAR_DoLayout(info, hdwp); + EndDeferWindowPos(hdwp); + +exit: + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + static LRESULT CALLBACK NAVBAR_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { NAVBAR_INFO *info = (NAVBAR_INFO *)GetWindowLongPtrW(hwnd, 0); @@ -129,7 +496,9 @@ static LRESULT CALLBACK NAVBAR_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LP { case WM_NCCREATE: return NAVBAR_Create(hwnd, msg, wparam, lparam); case WM_DESTROY: return NAVBAR_Destroy(hwnd, info, msg, wparam, lparam); + case WM_SIZE: return NAVBAR_Size(hwnd, info, msg, wparam, lparam); case WM_COMMAND: return NAVBAR_Command(hwnd, info, msg, wparam, lparam); + case NBM_SETPIDL: return NAVBAR_SetPIDL(hwnd, info, msg, wparam, lparam); }
exit: diff --git a/dlls/comdlg32/navbar.h b/dlls/comdlg32/navbar.h index 111439ccbad..5b5cb3eac95 100644 --- a/dlls/comdlg32/navbar.h +++ b/dlls/comdlg32/navbar.h @@ -25,10 +25,14 @@
#define WC_NAVBARW L"NavBar"
+/* navbar messages */ +#define NBM_SETPIDL WM_USER + 101 + /* navbar notifications */ #define NBN_NAVBACK WM_USER + 102 #define NBN_NAVFORWARD WM_USER + 103 #define NBN_NAVUP WM_USER + 104 +#define NBN_NAVPIDL WM_USER + 105
/* bitmap ids */ #define IDB_NAVBAR 3000
From: Vladislav Timonin timoninvlad@yandex.ru
--- dlls/comdlg32/navbar.c | 173 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index c295a14d236..cd58e3464e5 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -24,6 +24,7 @@ #include "commdlg.h" #include "cdlg.h" #include "shlwapi.h" +#include "commoncontrols.h"
#include "wine/debug.h" #include "wine/list.h" @@ -55,6 +56,9 @@ typedef struct { struct list crumbs; INT crumbs_total_n; INT crumbs_visible_n; + + HWND overflow_hwnd; + HMENU overflow_menu; } NAVBAR_INFO;
struct crumb { @@ -67,6 +71,83 @@ struct crumb { INT x; };
+static void NAVBAR_OVERFLOW_Insert(NAVBAR_INFO *info, ITEMIDLIST* pidl, WCHAR *display_name) +{ + MENUITEMINFOW menu_item = {0}; + + menu_item.cbSize = sizeof(MENUITEMINFOW); + menu_item.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STRING | MIIM_BITMAP; + menu_item.fType = MFT_STRING; + menu_item.dwItemData = (ULONG_PTR)pidl; + menu_item.dwTypeData = display_name; /* copied by InsertMenuItemW */ + menu_item.cch = lstrlenW(display_name); + menu_item.hbmpItem = HBMMENU_CALLBACK; /* see NAVBAR_OVERFLOW_DrawIcon */ + + InsertMenuItemW(info->overflow_menu, -1, TRUE, &menu_item); +} + +static void NAVBAR_OVERFLOW_Clear(NAVBAR_INFO *info) +{ + INT i, menu_item_count = GetMenuItemCount(info->overflow_menu); + MENUITEMINFOW menu_item = {0}; + + menu_item.cbSize = sizeof(MENUITEMINFOW); + menu_item.fMask = MIIM_DATA; + + for (i = menu_item_count - 1; i >= 0; i--) + { + GetMenuItemInfoW(info->overflow_menu, i, TRUE, &menu_item); + ILFree((ITEMIDLIST *)menu_item.dwItemData); + DeleteMenu(info->overflow_menu, 0, MF_BYPOSITION); + } +} + +static LRESULT NAVBAR_OVERFLOW_MeasureIcon(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lparam; + ITEMIDLIST *pidl = (ITEMIDLIST *)mis->itemData; + SHFILEINFOW file_info = {0}; + IImageList *icon_list; + + icon_list = (IImageList *)SHGetFileInfoW((const WCHAR *)pidl, 0, &file_info, sizeof(file_info), + SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_SHELLICONSIZE | SHGFI_SYSICONINDEX); + if (icon_list) + { + IImageList_GetIconSize(icon_list, (int *)&mis->itemWidth, (int *)&mis->itemHeight); + IImageList_Release(icon_list); + DestroyIcon(file_info.hIcon); + + /* add some padding to the right side so that the text isn't so close to the icon */ + /* 4px is the default left side padding for MNS_NOCHECK */ + mis->itemWidth += 4; + } + + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + +static LRESULT NAVBAR_OVERFLOW_DrawIcon(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam; + ITEMIDLIST *pidl = (ITEMIDLIST *)dis->itemData; + SHFILEINFOW file_info = {0}; + IImageList *icon_list; + + icon_list = (IImageList *)SHGetFileInfoW((const WCHAR *)pidl, 0, &file_info, sizeof(file_info), + SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_SHELLICONSIZE | SHGFI_SYSICONINDEX); + if (icon_list) + { + int icon_width, icon_height; + + IImageList_GetIconSize(icon_list, &icon_width, &icon_height); + DrawIconEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, + file_info.hIcon, icon_width, icon_height, 0, NULL, DI_NORMAL); + IImageList_Release(icon_list); + DestroyIcon(file_info.hIcon); + } + + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + static LRESULT CALLBACK NAVBAR_BACKGROUND_SubclassProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id_subclass, DWORD_PTR ref_data) { switch (msg) @@ -103,7 +184,7 @@ static LRESULT CALLBACK NAVBAR_BACKGROUND_SubclassProc(HWND hwnd, UINT msg, WPAR
static void NAVBAR_CalcLayout(NAVBAR_INFO *info) { - RECT container_rc, up_button_rc; + RECT container_rc, overflow_rc; struct crumb *crumb1, *crumb2; INT padding, container_w, buttons_w, max_crumbs_w, @@ -119,10 +200,10 @@ static void NAVBAR_CalcLayout(NAVBAR_INFO *info) if (!container_w) return;
- if (!GetWindowRect(info->up_btn_hwnd, &up_button_rc)) + if (!GetWindowRect(info->overflow_hwnd, &overflow_rc)) return;
- buttons_w = up_button_rc.right + 1 - padding; + buttons_w = overflow_rc.right - padding; max_crumbs_w = container_w - buttons_w; if (max_crumbs_w < 0) return; @@ -228,6 +309,9 @@ static HDWP NAVBAR_DoLayout(NAVBAR_INFO *info, HDWP hdwp) struct crumb *crumb; INT can_fit_n = info->crumbs_visible_n; UINT background_flags = 0; + BUTTON_SPLITINFO split_info = {0}; + + NAVBAR_OVERFLOW_Clear(info);
LIST_FOR_EACH_ENTRY_REV(crumb, &info->crumbs, struct crumb, entry) { @@ -236,7 +320,10 @@ static HDWP NAVBAR_DoLayout(NAVBAR_INFO *info, HDWP hdwp) if (can_fit_n > 0) flags |= SWP_SHOWWINDOW | SWP_NOCOPYBITS; else + { flags |= SWP_HIDEWINDOW; + NAVBAR_OVERFLOW_Insert(info, ILClone(crumb->pidl), crumb->display_name); + }
hdwp = DeferWindowPos(hdwp, crumb->hwnd, HWND_TOP, crumb->x, 0, @@ -246,6 +333,18 @@ static HDWP NAVBAR_DoLayout(NAVBAR_INFO *info, HDWP hdwp) can_fit_n -= 1; }
+ split_info.mask = BCSIF_STYLE; + + if (GetMenuItemCount(info->overflow_menu) > 0) + /* reset split style to re-enable split and dropdown arrow if they were disabled */ + SendMessageW(info->overflow_hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&split_info); + else + { + /* remove the split and dropdown arrow when there are no items in the overflow */ + split_info.uSplitStyle = BCSS_NOSPLIT | BCSS_IMAGE; + SendMessageW(info->overflow_hwnd, BCM_SETSPLITINFO, 0, (LPARAM)&split_info); + } + if (info->background_w > 0) background_flags |= SWP_SHOWWINDOW | SWP_NOCOPYBITS; else @@ -267,6 +366,8 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) INT x; HGDIOBJ gui_font = GetStockObject(DEFAULT_GUI_FONT); HICON icon; + SIZE button_size; + MENUINFO menu_info = {0};
info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NAVBAR_INFO)); list_init(&info->crumbs); @@ -318,6 +419,21 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) hwnd, 0, COMDLG32_hInstance, NULL); SetWindowSubclass(info->background_hwnd, NAVBAR_BACKGROUND_SubclassProc, 0, (DWORD_PTR)info);
+ info->overflow_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, + WS_CHILD | WS_VISIBLE | BS_SPLITBUTTON, + x, 0, 0, 0, + hwnd, 0, COMDLG32_hInstance, NULL); + SendMessageW(info->overflow_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); + SendMessageW(info->overflow_hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&button_size); + SetWindowPos(info->overflow_hwnd, NULL, 0, 0, + button_size.cx + MulDiv(8, info->dpi_x, USER_DEFAULT_SCREEN_DPI), cs->cy, SWP_NOMOVE); + + info->overflow_menu = CreatePopupMenu(); + menu_info.cbSize = sizeof(MENUINFO); + menu_info.fMask = MIM_STYLE; + menu_info.dwStyle = MNS_NOCHECK | MNS_NOTIFYBYPOS; + SetMenuInfo(info->overflow_menu, &menu_info); + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)info);
return DefWindowProcW(hwnd, msg, wparam, lparam); @@ -339,6 +455,8 @@ static LRESULT NAVBAR_Destroy(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa
SetWindowLongPtrW(hwnd, 0, 0); ImageList_Destroy(info->icons); + NAVBAR_OVERFLOW_Clear(info); + DestroyMenu(info->overflow_menu);
HeapFree(GetProcessHeap(), 0, info);
@@ -383,12 +501,30 @@ static LRESULT NAVBAR_Command(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa return DefWindowProcW(hwnd, msg, wparam, lparam); }
+static LRESULT NAVBAR_MenuCommand(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + UINT pos = wparam; + HMENU menu = (HMENU)lparam; + MENUITEMINFOW menu_item = {0}; + + menu_item.cbSize = sizeof(MENUITEMINFOW); + menu_item.fMask = MIIM_DATA; + + if (GetMenuItemInfoW(menu, pos, TRUE, &menu_item)) + SendMessageW(info->parent_hwnd, NBN_NAVPIDL, 0, (LPARAM)menu_item.dwItemData); + else + ERR("failed to get menu item info\n"); + + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + static LRESULT NAVBAR_SetPIDL(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) { ITEMIDLIST *pidl = (ITEMIDLIST *)lparam; IShellFolder *desktop; HGDIOBJ gui_font = GetStockObject(DEFAULT_GUI_FONT); HRESULT hr; + SHFILEINFOW file_info; INT padding = MulDiv(10, info->dpi_x, USER_DEFAULT_SCREEN_DPI); struct list new_crumbs; struct crumb *crumb1, *crumb2; @@ -403,6 +539,15 @@ static LRESULT NAVBAR_SetPIDL(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa goto exit; }
+ if (SHGetFileInfoW((const WCHAR *)pidl, 0, &file_info, sizeof(file_info), + SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_SHELLICONSIZE)) + { + SendMessageW(info->overflow_hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)file_info.hIcon); + DestroyIcon(file_info.hIcon); + } + else + WARN("failed to get file info for pidl %p\n", pidl); + list_init(&new_crumbs); info->crumbs_total_n = 0; pidl = ILClone(pidl); @@ -485,6 +630,24 @@ exit: return DefWindowProcW(hwnd, msg, wparam, lparam); }
+static LRESULT NAVBAR_Notify(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + NMHDR *nmhdr = (NMHDR *)lparam; + + if (nmhdr && nmhdr->hwndFrom == info->overflow_hwnd && nmhdr->code == BCN_DROPDOWN) + { + NMBCDROPDOWN* dropdown = (NMBCDROPDOWN *)lparam; + POINT pt = { .x = dropdown->rcButton.left, + .y = dropdown->rcButton.bottom, }; + + ClientToScreen(info->overflow_hwnd, &pt); + TrackPopupMenu(info->overflow_menu, TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, hwnd, NULL); + return TRUE; + } + + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + static LRESULT CALLBACK NAVBAR_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { NAVBAR_INFO *info = (NAVBAR_INFO *)GetWindowLongPtrW(hwnd, 0); @@ -498,6 +661,10 @@ static LRESULT CALLBACK NAVBAR_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LP case WM_DESTROY: return NAVBAR_Destroy(hwnd, info, msg, wparam, lparam); case WM_SIZE: return NAVBAR_Size(hwnd, info, msg, wparam, lparam); case WM_COMMAND: return NAVBAR_Command(hwnd, info, msg, wparam, lparam); + case WM_MENUCOMMAND: return NAVBAR_MenuCommand(hwnd, info, msg, wparam, lparam); + case WM_NOTIFY: return NAVBAR_Notify(hwnd, info, msg, wparam, lparam); + case WM_MEASUREITEM: return NAVBAR_OVERFLOW_MeasureIcon(hwnd, info, msg, wparam, lparam); + case WM_DRAWITEM: return NAVBAR_OVERFLOW_DrawIcon(hwnd, info, msg, wparam, lparam); case NBM_SETPIDL: return NAVBAR_SetPIDL(hwnd, info, msg, wparam, lparam); }
From: Vladislav Timonin timoninvlad@yandex.ru
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50338
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51855 --- dlls/comdlg32/comdlg32.rc | 7 + dlls/comdlg32/navbar.c | 319 +++++++++++++++++++++++++++++++++++++- dlls/comdlg32/navbar.h | 5 + 3 files changed, 326 insertions(+), 5 deletions(-)
diff --git a/dlls/comdlg32/comdlg32.rc b/dlls/comdlg32/comdlg32.rc index 4710f1955b7..a1c71ece16b 100644 --- a/dlls/comdlg32/comdlg32.rc +++ b/dlls/comdlg32/comdlg32.rc @@ -149,6 +149,13 @@ STRINGTABLE IDS_FONT_SIZE_INPUT "Font size has to be a number." }
+STRINGTABLE +{ + IDS_COPY_ADDRESS_AS_TEXT "Copy address as text" + IDS_EDIT_ADDRESS "Edit address" + IDS_WINE_CANT_FIND_ADDRESS "Wine can't find '%s'." +} + /* * WARNING: DO NOT CHANGE THE SIZE OF THE STANDARD DIALOG TEMPLATES. */ diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index cd58e3464e5..fff4f33fcce 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -59,6 +59,8 @@ typedef struct {
HWND overflow_hwnd; HMENU overflow_menu; + + HWND pathedit_hwnd; } NAVBAR_INFO;
struct crumb { @@ -71,6 +73,266 @@ struct crumb { INT x; };
+static HDWP NAVBAR_DoLayout(NAVBAR_INFO *info, HDWP hdwp); + +static void NAVBAR_PATHEDIT_SetCurrentPath(NAVBAR_INFO *info) +{ + struct crumb *crumb; + WCHAR cur_path[MAX_PATH]; + + crumb = LIST_ENTRY(list_tail(&info->crumbs), struct crumb, entry); + SHGetPathFromIDListW(crumb->pidl, cur_path); + SetWindowTextW(info->pathedit_hwnd, cur_path); + SendMessageW(info->pathedit_hwnd, EM_SETSEL, 0, -1); /* select all */ +} + +static void NAVBAR_PATHEDIT_Edit(NAVBAR_INFO *info) +{ + struct crumb *crumb; + HDWP hdwp; + + NAVBAR_PATHEDIT_SetCurrentPath(info); + + /* show path edit, hide overflow and crumbs */ + hdwp = BeginDeferWindowPos(2 + info->crumbs_total_n + 1); + hdwp = DeferWindowPos(hdwp, info->pathedit_hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + hdwp = DeferWindowPos(hdwp, info->overflow_hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); + LIST_FOR_EACH_ENTRY(crumb, &info->crumbs, struct crumb, entry) + hdwp = DeferWindowPos(hdwp, crumb->hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); + hdwp = DeferWindowPos(hdwp, info->background_hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); + EndDeferWindowPos(hdwp); + + SetFocus(info->pathedit_hwnd); +} + +static void NAVBAR_PATHEDIT_Copy(NAVBAR_INFO *info) +{ + NAVBAR_PATHEDIT_SetCurrentPath(info); + SendMessageW(info->pathedit_hwnd, WM_COPY, 0, 0); +} + +static void NAVBAR_PATHEDIT_Dismiss(NAVBAR_INFO *info) +{ + HDWP hdwp; + + if (!IsWindowVisible(info->pathedit_hwnd)) + return; + + /* hide path edit, show overflow and crumbs */ + hdwp = BeginDeferWindowPos(2 + info->crumbs_total_n + 1); + hdwp = DeferWindowPos(hdwp, info->pathedit_hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); + hdwp = DeferWindowPos(hdwp, info->overflow_hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + hdwp = NAVBAR_DoLayout(info, hdwp); + EndDeferWindowPos(hdwp); +} + +static LRESULT NAVBAR_PATHEDIT_KillFocus(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + NAVBAR_PATHEDIT_Dismiss(info); + + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + +static void NAVBAR_PATHEDIT_GoTo(NAVBAR_INFO *info) +{ + INT len = 0, size; + WCHAR *text = NULL, *expanded = NULL; + DWORD expanded_cch; + ITEMIDLIST *pidl = NULL; + HRESULT hr; + + len = GetWindowTextLengthW(info->pathedit_hwnd); + if (!len) + goto exit; + + size = (len + 1) * sizeof(WCHAR); + text = HeapAlloc(GetProcessHeap(), 0, size); + if (!text) + goto exit; + + if (!GetWindowTextW(info->pathedit_hwnd, text, size)) + goto cleanup; + + /* expand variables */ + expanded_cch = ExpandEnvironmentStringsW(text, NULL, 0); + if (!expanded_cch) + goto cleanup; + + expanded = HeapAlloc(GetProcessHeap(), 0, expanded_cch * sizeof(WCHAR)); + if (!expanded) + goto cleanup; + + expanded_cch = ExpandEnvironmentStringsW(text, expanded, expanded_cch); + if (!expanded_cch) + goto cleanup; + + /* check if we have a valid path */ + if (GetFileAttributesW(expanded) == INVALID_FILE_ATTRIBUTES) + { + WCHAR spec[MAX_PATH + 128] = {0}, + caption[MAX_PATH + 128] = {0}; + LoadStringW(COMDLG32_hInstance, IDS_WINE_CANT_FIND_ADDRESS, spec, ARRAY_SIZE(spec)); + wsprintfW(caption, spec, text); + MessageBoxW(info->pathedit_hwnd, caption, NULL, MB_ICONERROR | MB_OK); + goto cleanup; + } + + hr = SHILCreateFromPath(expanded, &pidl, 0); + if (FAILED(hr)) + goto cleanup; + + SendMessageW(info->parent_hwnd, NBN_NAVPIDL, 0, (LPARAM)pidl); + ILFree(pidl); +cleanup: + if (text) + HeapFree(GetProcessHeap(), 0, text); + if (expanded) + HeapFree(GetProcessHeap(), 0, expanded); +exit: + NAVBAR_PATHEDIT_Dismiss(info); +} + +static LRESULT NAVBAR_PATHEDIT_GetDlgCode(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch (wparam) + { + case VK_ESCAPE: + NAVBAR_PATHEDIT_Dismiss(info); + SetFocus(info->parent_hwnd); + return DLGC_WANTMESSAGE; /* prevent dialog from closing */ + case VK_RETURN: + NAVBAR_PATHEDIT_GoTo(info); + break; + } + + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + +static INT NAVBAR_PATHEDIT_NCOffset(HWND hwnd) +{ + RECT hwnd_rc; + HDC hdc; + HGDIOBJ old_font, gui_font = GetStockObject(DEFAULT_GUI_FONT); + TEXTMETRICW tm; + INT cy_edge = GetSystemMetrics(SM_CYEDGE), + cy_border = GetSystemMetrics(SM_CYBORDER); + + GetWindowRect(hwnd, &hwnd_rc); + + /* get font height */ + hdc = GetDC(0); + old_font = SelectObject(hdc, gui_font); + GetTextMetricsW(hdc, &tm); + SelectObject(hdc, old_font); + ReleaseDC(0, hdc); + + /* offset to vertically center the text */ + return (hwnd_rc.bottom - hwnd_rc.top - tm.tmHeight - (cy_edge * 2) - (cy_border * 2)) / 2; +} + +static LRESULT NAVBAR_PATHEDIT_NCCalcSize(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + NCCALCSIZE_PARAMS *ncp = (NCCALCSIZE_PARAMS *)lparam; + + if (!wparam) + goto exit; + + /* vertically center the text */ + ncp->rgrc[0].top += NAVBAR_PATHEDIT_NCOffset(hwnd); + +exit: + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + +static LRESULT NAVBAR_PATHEDIT_NCPaint(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + RECT hwnd_rc; + HDC hdc = GetWindowDC(hwnd); + + GetClientRect(hwnd, &hwnd_rc); + hwnd_rc.right += GetSystemMetrics(SM_CXEDGE); + hwnd_rc.top += GetSystemMetrics(SM_CYEDGE); + hwnd_rc.bottom = hwnd_rc.top + NAVBAR_PATHEDIT_NCOffset(hwnd); + + /* depending on theme, e.g. classic theme, */ + /* NC background color might differ from window background, */ + /* paint over the area that we shifted in WM_NCCALCSIZE */ + FillRect(hdc, &hwnd_rc, GetSysColorBrush(COLOR_WINDOW)); + ReleaseDC(hwnd, hdc); + + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + +static LRESULT NAVBAR_PATHEDIT_NCHitTest(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + POINT screen_pt = { .x = LOWORD(lparam), + .y = HIWORD(lparam) }; + POINT client_pt = screen_pt; + + ScreenToClient(hwnd, &client_pt); + if (client_pt.y < 0) + { + /* what we shifted in WM_NCCALCSIZE is now not interactable, fix that */ + screen_pt.y += NAVBAR_PATHEDIT_NCOffset(hwnd); + lparam = MAKELPARAM(screen_pt.x, screen_pt.y); + } + + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + +static LRESULT CALLBACK NAVBAR_PATHEDIT_SubclassProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id_subclass, DWORD_PTR ref_data) +{ + NAVBAR_INFO *info = (NAVBAR_INFO *)ref_data; + + switch (msg) + { + case WM_GETDLGCODE: return NAVBAR_PATHEDIT_GetDlgCode(hwnd, info, msg, wparam, lparam); + case WM_KILLFOCUS: return NAVBAR_PATHEDIT_KillFocus(hwnd, info, msg, wparam, lparam); + case WM_NCCALCSIZE: return NAVBAR_PATHEDIT_NCCalcSize(hwnd, msg, wparam, lparam); + case WM_NCPAINT: return NAVBAR_PATHEDIT_NCPaint(hwnd, msg, wparam, lparam); + case WM_NCHITTEST: return NAVBAR_PATHEDIT_NCHitTest(hwnd, msg, wparam, lparam); + } + + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + +static LRESULT CALLBACK NAVBAR_RMBMENU_SubclassProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id_subclass, DWORD_PTR ref_data) +{ + NAVBAR_INFO *info = (NAVBAR_INFO *)ref_data; + + switch (msg) + { + case WM_RBUTTONUP: + { + POINT pt = { .x = LOWORD(lparam), + .y = HIWORD(lparam) }; + HMENU menu = CreatePopupMenu(); + WCHAR buffer[128] = {0}; + static const INT IDC_RMBMENUCOPY = 200; + static const INT IDC_RMBMENUEDIT = 201; + + LoadStringW(COMDLG32_hInstance, IDS_COPY_ADDRESS_AS_TEXT, buffer, ARRAY_SIZE(buffer)); + AppendMenuW(menu, MF_STRING, IDC_RMBMENUCOPY, buffer); + + LoadStringW(COMDLG32_hInstance, IDS_EDIT_ADDRESS, buffer, ARRAY_SIZE(buffer)); + AppendMenuW(menu, MF_STRING, IDC_RMBMENUEDIT, buffer); + + ClientToScreen(hwnd, &pt); + switch (TrackPopupMenu(menu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL)) + { + case IDC_RMBMENUCOPY: + NAVBAR_PATHEDIT_Copy(info); + break; + case IDC_RMBMENUEDIT: + NAVBAR_PATHEDIT_Edit(info); + break; + } + } + } + + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + static void NAVBAR_OVERFLOW_Insert(NAVBAR_INFO *info, ITEMIDLIST* pidl, WCHAR *display_name) { MENUITEMINFOW menu_item = {0}; @@ -148,8 +410,25 @@ static LRESULT NAVBAR_OVERFLOW_DrawIcon(HWND hwnd, NAVBAR_INFO *info, UINT msg, return DefWindowProcW(hwnd, msg, wparam, lparam); }
+static LRESULT CALLBACK NAVBAR_OVERFLOW_SubclassProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id_subclass, DWORD_PTR ref_data) +{ + NAVBAR_INFO *info = (NAVBAR_INFO *)ref_data; + + switch (msg) + { + case WM_LBUTTONUP: + case WM_RBUTTONUP: + NAVBAR_PATHEDIT_Edit(info); + break; + } + + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + static LRESULT CALLBACK NAVBAR_BACKGROUND_SubclassProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id_subclass, DWORD_PTR ref_data) { + NAVBAR_INFO *info = (NAVBAR_INFO *)ref_data; + switch (msg) { case WM_PAINT: @@ -177,6 +456,9 @@ static LRESULT CALLBACK NAVBAR_BACKGROUND_SubclassProc(HWND hwnd, UINT msg, WPAR
return FALSE; /* processed */ } + case WM_LBUTTONUP: + NAVBAR_PATHEDIT_Edit(info); + break; }
return DefSubclassProc(hwnd, msg, wparam, lparam); @@ -187,7 +469,7 @@ static void NAVBAR_CalcLayout(NAVBAR_INFO *info) RECT container_rc, overflow_rc; struct crumb *crumb1, *crumb2; INT padding, container_w, - buttons_w, max_crumbs_w, + buttons_w, overflow_w, max_crumbs_w, w = 0, crumbs_visible_n = 0, prev_x;
if (!GetWindowRect(info->container_hwnd, &container_rc)) @@ -202,12 +484,20 @@ static void NAVBAR_CalcLayout(NAVBAR_INFO *info)
if (!GetWindowRect(info->overflow_hwnd, &overflow_rc)) return; + overflow_w = overflow_rc.right - overflow_rc.left;
buttons_w = overflow_rc.right - padding; max_crumbs_w = container_w - buttons_w; if (max_crumbs_w < 0) return;
+ SetWindowPos(info->pathedit_hwnd, NULL, 0, 0, overflow_w + max_crumbs_w, info->container_h, SWP_NOMOVE); + + /* reserve some space on the right side for click-to-edit area */ + max_crumbs_w -= MulDiv(64, info->dpi_x, USER_DEFAULT_SCREEN_DPI); + if (max_crumbs_w < 0) + return; + LIST_FOR_EACH_ENTRY_REV(crumb1, &info->crumbs, struct crumb, entry) { INT next_w = w + crumb1->full_w; @@ -292,6 +582,11 @@ static void NAVBAR_CalcLayout(NAVBAR_INFO *info) else style |= BS_CENTER;
+ /* when resizing path edit, crumbs can briefly show through, apply WS_CLIPSIBLINGS to avoid that. */ + /* when crumb reappears during resizing, it can fail to repaint itself if WS_CLIPSIBLINGS was applied. */ + if (IsWindowVisible(info->pathedit_hwnd)) + style |= WS_CLIPSIBLINGS; + SetWindowLongPtrW(crumb1->hwnd, GWL_STYLE, style);
crumb1->x = prev_x - crumb1->current_w; @@ -414,10 +709,11 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
x += cs->cy + 1; info->background_hwnd = CreateWindowExW(0, WC_STATICW, NULL, - WS_CHILD | WS_VISIBLE, + WS_CHILD | WS_VISIBLE | SS_NOTIFY, x, 0, 0, cs->cy, hwnd, 0, COMDLG32_hInstance, NULL); SetWindowSubclass(info->background_hwnd, NAVBAR_BACKGROUND_SubclassProc, 0, (DWORD_PTR)info); + SetWindowSubclass(info->background_hwnd, NAVBAR_RMBMENU_SubclassProc, 1, (DWORD_PTR)info);
info->overflow_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, WS_CHILD | WS_VISIBLE | BS_SPLITBUTTON, @@ -427,6 +723,7 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) SendMessageW(info->overflow_hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&button_size); SetWindowPos(info->overflow_hwnd, NULL, 0, 0, button_size.cx + MulDiv(8, info->dpi_x, USER_DEFAULT_SCREEN_DPI), cs->cy, SWP_NOMOVE); + SetWindowSubclass(info->overflow_hwnd, NAVBAR_OVERFLOW_SubclassProc, 0, (DWORD_PTR)info);
info->overflow_menu = CreatePopupMenu(); menu_info.cbSize = sizeof(MENUINFO); @@ -434,6 +731,14 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) menu_info.dwStyle = MNS_NOCHECK | MNS_NOTIFYBYPOS; SetMenuInfo(info->overflow_menu, &menu_info);
+ info->pathedit_hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, + WC_EDITW, NULL, + WS_CHILD | ES_AUTOHSCROLL, + x, 0, 0, cs->cy, + hwnd, 0, COMDLG32_hInstance, NULL); + SendMessageW(info->pathedit_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); + SetWindowSubclass(info->pathedit_hwnd, NAVBAR_PATHEDIT_SubclassProc, 0, (DWORD_PTR)info); + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)info);
return DefWindowProcW(hwnd, msg, wparam, lparam); @@ -469,9 +774,12 @@ static LRESULT NAVBAR_Size(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam
NAVBAR_CalcLayout(info);
- hdwp = BeginDeferWindowPos(info->crumbs_total_n + 1); - hdwp = NAVBAR_DoLayout(info, hdwp); - EndDeferWindowPos(hdwp); + if (!IsWindowVisible(info->pathedit_hwnd)) + { + hdwp = BeginDeferWindowPos(info->crumbs_total_n + 1); + hdwp = NAVBAR_DoLayout(info, hdwp); + EndDeferWindowPos(hdwp); + }
return TRUE; } @@ -568,6 +876,7 @@ static LRESULT NAVBAR_SetPIDL(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa SendMessageW(crumb1->hwnd, WM_SETFONT, (LPARAM)gui_font, FALSE); SendMessageW(crumb1->hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&full_size); SetWindowLongPtrW(crumb1->hwnd, GWLP_USERDATA, (LPARAM)crumb1->pidl); + SetWindowSubclass(crumb1->hwnd, NAVBAR_RMBMENU_SubclassProc, 0, (DWORD_PTR)info);
crumb1->full_w = full_size.cx + padding; crumb1->current_w = crumb1->full_w; diff --git a/dlls/comdlg32/navbar.h b/dlls/comdlg32/navbar.h index 5b5cb3eac95..08f953c7ab9 100644 --- a/dlls/comdlg32/navbar.h +++ b/dlls/comdlg32/navbar.h @@ -34,6 +34,11 @@ #define NBN_NAVUP WM_USER + 104 #define NBN_NAVPIDL WM_USER + 105
+/* strings */ +#define IDS_COPY_ADDRESS_AS_TEXT 2001 +#define IDS_EDIT_ADDRESS 2002 +#define IDS_WINE_CANT_FIND_ADDRESS 2004 + /* bitmap ids */ #define IDB_NAVBAR 3000 /* icon indicies in IDB_NAVBAR */
From: Vladislav Timonin timoninvlad@yandex.ru
--- dlls/comdlg32/itemdlg.c | 18 ++++++++++++ dlls/comdlg32/navbar.c | 65 +++++++++++++++++++++++++++++++++++++---- dlls/comdlg32/navbar.h | 1 + 3 files changed, 78 insertions(+), 6 deletions(-)
diff --git a/dlls/comdlg32/itemdlg.c b/dlls/comdlg32/itemdlg.c index 453c83dcf1a..4c7d4fa0fdf 100644 --- a/dlls/comdlg32/itemdlg.c +++ b/dlls/comdlg32/itemdlg.c @@ -2176,6 +2176,23 @@ static LRESULT on_browse_pidl(FileDialogImpl *This, LPARAM lparam) return FALSE; }
+static LRESULT on_browse_refresh(FileDialogImpl *This) +{ + IShellView *psv; + HRESULT hr; + + TRACE("%p\n", This); + + hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&psv); + if (SUCCEEDED(hr)) + { + IShellView_Refresh(psv); + IShellView_Release(psv); + } + + return FALSE; +} + static LRESULT on_command_filetype(FileDialogImpl *This, WPARAM wparam, LPARAM lparam) { if(HIWORD(wparam) == CBN_SELCHANGE) @@ -2253,6 +2270,7 @@ static INT_PTR CALLBACK itemdlg_dlgproc(HWND hwnd, UINT umessage, WPARAM wparam, case NBN_NAVFORWARD: return on_browse_forward(This); case NBN_NAVUP: return on_browse_up(This); case NBN_NAVPIDL: return on_browse_pidl(This, lparam); + case NBN_NAVREFRESH: return on_browse_refresh(This); }
return FALSE; diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index fff4f33fcce..4f553128d5c 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -36,6 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(commdlg); #define IDC_NAVFORWARD 202 #define IDC_NAVUP 203 #define IDC_NAVCRUMB 204 +#define IDC_NAVREFRESHGOTO 205
typedef struct { HWND parent_hwnd; @@ -48,6 +49,7 @@ typedef struct { HWND back_btn_hwnd; HWND fwd_btn_hwnd; HWND up_btn_hwnd; + HWND refresh_goto_btn_hwnd;
HWND background_hwnd; INT background_x; @@ -90,6 +92,7 @@ static void NAVBAR_PATHEDIT_Edit(NAVBAR_INFO *info) { struct crumb *crumb; HDWP hdwp; + HICON icon;
NAVBAR_PATHEDIT_SetCurrentPath(info);
@@ -102,6 +105,11 @@ static void NAVBAR_PATHEDIT_Edit(NAVBAR_INFO *info) hdwp = DeferWindowPos(hdwp, info->background_hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); EndDeferWindowPos(hdwp);
+ /* change Refresh button to Go to button */ + icon = ImageList_GetIcon(info->icons, ILI_FORWARD, ILD_NORMAL); + SendMessageW(info->refresh_goto_btn_hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)icon); + DestroyIcon(icon); + SetFocus(info->pathedit_hwnd); }
@@ -114,6 +122,7 @@ static void NAVBAR_PATHEDIT_Copy(NAVBAR_INFO *info) static void NAVBAR_PATHEDIT_Dismiss(NAVBAR_INFO *info) { HDWP hdwp; + HICON icon;
if (!IsWindowVisible(info->pathedit_hwnd)) return; @@ -124,11 +133,19 @@ static void NAVBAR_PATHEDIT_Dismiss(NAVBAR_INFO *info) hdwp = DeferWindowPos(hdwp, info->overflow_hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); hdwp = NAVBAR_DoLayout(info, hdwp); EndDeferWindowPos(hdwp); + + /* change Go to button back to Refresh button */ + icon = ImageList_GetIcon(info->icons, ILI_REFRESH, ILD_NORMAL); + SendMessageW(info->refresh_goto_btn_hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)icon); + DestroyIcon(icon); }
static LRESULT NAVBAR_PATHEDIT_KillFocus(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) { - NAVBAR_PATHEDIT_Dismiss(info); + /* if user clicked on Go to button, don't dismiss the path edit, */ + /* let either Go to focus handler or NAVBAR_Command dismiss it */ + if (GetFocus() != info->refresh_goto_btn_hwnd) + NAVBAR_PATHEDIT_Dismiss(info);
return DefSubclassProc(hwnd, msg, wparam, lparam); } @@ -296,6 +313,21 @@ static LRESULT CALLBACK NAVBAR_PATHEDIT_SubclassProc(HWND hwnd, UINT msg, WPARAM return DefSubclassProc(hwnd, msg, wparam, lparam); }
+static LRESULT CALLBACK NAVBAR_REFRESHGOTO_SubclassProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id_subclass, DWORD_PTR ref_data) +{ + NAVBAR_INFO *info = (NAVBAR_INFO *)ref_data; + + switch (msg) + { + case WM_KILLFOCUS: + if (GetFocus() != info->pathedit_hwnd) + NAVBAR_PATHEDIT_Dismiss(info); + break; + } + + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + static LRESULT CALLBACK NAVBAR_RMBMENU_SubclassProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id_subclass, DWORD_PTR ref_data) { NAVBAR_INFO *info = (NAVBAR_INFO *)ref_data; @@ -466,10 +498,10 @@ static LRESULT CALLBACK NAVBAR_BACKGROUND_SubclassProc(HWND hwnd, UINT msg, WPAR
static void NAVBAR_CalcLayout(NAVBAR_INFO *info) { - RECT container_rc, overflow_rc; + RECT container_rc, overflow_rc, refresh_goto_btn_rc; struct crumb *crumb1, *crumb2; INT padding, container_w, - buttons_w, overflow_w, max_crumbs_w, + buttons_w, overflow_w, max_crumbs_w, refresh_goto_btn_w, w = 0, crumbs_visible_n = 0, prev_x;
if (!GetWindowRect(info->container_hwnd, &container_rc)) @@ -491,10 +523,15 @@ static void NAVBAR_CalcLayout(NAVBAR_INFO *info) if (max_crumbs_w < 0) return;
- SetWindowPos(info->pathedit_hwnd, NULL, 0, 0, overflow_w + max_crumbs_w, info->container_h, SWP_NOMOVE); + if (!GetClientRect(info->refresh_goto_btn_hwnd, &refresh_goto_btn_rc)) + return; + refresh_goto_btn_w = refresh_goto_btn_rc.right - refresh_goto_btn_rc.left; + + SetWindowPos(info->pathedit_hwnd, NULL, 0, 0, overflow_w + max_crumbs_w - refresh_goto_btn_w, info->container_h, SWP_NOMOVE); + SetWindowPos(info->refresh_goto_btn_hwnd, NULL, container_w - refresh_goto_btn_w, 0, 0, 0, SWP_NOSIZE);
/* reserve some space on the right side for click-to-edit area */ - max_crumbs_w -= MulDiv(64, info->dpi_x, USER_DEFAULT_SCREEN_DPI); + max_crumbs_w -= MulDiv(64 + refresh_goto_btn_w, info->dpi_x, USER_DEFAULT_SCREEN_DPI); if (max_crumbs_w < 0) return;
@@ -566,7 +603,7 @@ static void NAVBAR_CalcLayout(NAVBAR_INFO *info) prev_x = buttons_w + w;
info->background_x = prev_x; - info->background_w = container_rc.right - prev_x; + info->background_w = container_rc.right - refresh_goto_btn_w - prev_x;
info->crumbs_visible_n = crumbs_visible_n;
@@ -739,6 +776,16 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) SendMessageW(info->pathedit_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); SetWindowSubclass(info->pathedit_hwnd, NAVBAR_PATHEDIT_SubclassProc, 0, (DWORD_PTR)info);
+ info->refresh_goto_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, + WS_CHILD | WS_VISIBLE | BS_ICON | BS_BITMAP, + 0, 0, cs->cy, cs->cy, + hwnd, (HMENU)IDC_NAVREFRESHGOTO, COMDLG32_hInstance, NULL); + SendMessageW(info->refresh_goto_btn_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); + icon = ImageList_GetIcon(info->icons, ILI_REFRESH, ILD_NORMAL); + SendMessageW(info->refresh_goto_btn_hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)icon); + DestroyIcon(icon); + SetWindowSubclass(info->refresh_goto_btn_hwnd, NAVBAR_REFRESHGOTO_SubclassProc, 0, (DWORD_PTR)info); + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)info);
return DefWindowProcW(hwnd, msg, wparam, lparam); @@ -804,6 +851,12 @@ static LRESULT NAVBAR_Command(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa SendMessageW(info->parent_hwnd, NBN_NAVPIDL, 0, (LPARAM)pidl); break; } + case IDC_NAVREFRESHGOTO: + if (IsWindowVisible(info->pathedit_hwnd)) + NAVBAR_PATHEDIT_GoTo(info); + else + SendMessageW(info->parent_hwnd, NBN_NAVREFRESH, 0, 0); + break; }
return DefWindowProcW(hwnd, msg, wparam, lparam); diff --git a/dlls/comdlg32/navbar.h b/dlls/comdlg32/navbar.h index 08f953c7ab9..d7d15576534 100644 --- a/dlls/comdlg32/navbar.h +++ b/dlls/comdlg32/navbar.h @@ -33,6 +33,7 @@ #define NBN_NAVFORWARD WM_USER + 103 #define NBN_NAVUP WM_USER + 104 #define NBN_NAVPIDL WM_USER + 105 +#define NBN_NAVREFRESH WM_USER + 106
/* strings */ #define IDS_COPY_ADDRESS_AS_TEXT 2001
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=128062
Your paranoid android.
=== debian11 (32 bit report) ===
comdlg32: Unhandled exception: page fault on execute access to 0x00030000 in 32-bit code (0x00030000).
=== debian11b (64 bit WoW report) ===
comdlg32: itemdlg: Timeout
v4: - rebase on top of master to re-run CI
v5: - move `info` to local variables from `NAVBAR_Create` arguments - change `NAVBAR_OVERFLOW_Clear` to delete from the end - remove special handling of first crumb in overflow menu - remove `DestroyWindow` in `WM_DESTROY` - add padding for overflow menu icons in `WM_MEASUREITEM` instead of drawing outside of `rcItem` rectangle in `WM_DRAWITEM` - add `MNS_NOCHECK` style to overflow menu to remove remove extra padding
On Wed Dec 28 22:51:30 2022 +0000, Vladislav Timonin wrote:
If you mean extending it to be painted under crumbs, it originally was, static control with `SS_GRAYFRAME` taking up full width. But that had issues with frame being painted over crumbs on initial dialog show. And right border trailing on resize that I was ignoring thinking it was caused by [54137](https://bugs.winehq.org/show_bug.cgi?id=54137).
That's not what I mean. I expect that whatever you draw outside the bounds of the hwnd will get clipped, so if you draw the left border outside the hwnd's client rectangle, you shouldn't see the left border.
On Thu Dec 29 01:22:32 2022 +0000, Esme Povirk wrote:
That's not what I mean. I expect that whatever you draw outside the bounds of the hwnd will get clipped, so if you draw the left border outside the hwnd's client rectangle, you shouldn't see the left border.
Oh, sorry, I'm thick. Yup, that works.
On Thu Dec 29 13:28:16 2022 +0000, Vladislav Timonin wrote:
Oh, sorry, I'm thick. Yup, that works.
Instead of relying on clipping, you can just use [DrawEdge].
[DrawEdge]: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-drawe...