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)
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 | 124 +++++++ dlls/comdlg32/navbar.h | 23 ++ dlls/comdlg32/navbar.svg | 676 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 871 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..4b81565d15b --- /dev/null +++ b/dlls/comdlg32/navbar.c @@ -0,0 +1,124 @@ +#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, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) +{ + CREATESTRUCTW *cs = (CREATESTRUCTW*)lparam; + 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); + DestroyWindow(info->back_btn_hwnd); + DestroyWindow(info->fwd_btn_hwnd); + + 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, info, msg, wparam, lparam); + case WM_NCDESTROY: 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..b881fec24a4 --- /dev/null +++ b/dlls/comdlg32/navbar.h @@ -0,0 +1,23 @@ +#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 | 16 ++++++++++++++++ dlls/comdlg32/navbar.h | 1 + 3 files changed, 25 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 4b81565d15b..1b853ec5061 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -7,6 +7,7 @@ /* private control ids */ #define IDC_NAVBACK 201 #define IDC_NAVFORWARD 202 +#define IDC_NAVUP 203
typedef struct { HWND parent_hwnd; @@ -16,6 +17,7 @@ typedef struct {
HWND back_btn_hwnd; HWND fwd_btn_hwnd; + HWND up_btn_hwnd; } NAVBAR_INFO;
static LRESULT NAVBAR_Create(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) @@ -52,6 +54,16 @@ static LRESULT NAVBAR_Create(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpar 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); @@ -63,6 +75,7 @@ static LRESULT NAVBAR_Destroy(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa ImageList_Destroy(info->icons); DestroyWindow(info->back_btn_hwnd); DestroyWindow(info->fwd_btn_hwnd); + DestroyWindow(info->up_btn_hwnd);
HeapFree(GetProcessHeap(), 0, info);
@@ -79,6 +92,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 b881fec24a4..a2e6cb8c854 100644 --- a/dlls/comdlg32/navbar.h +++ b/dlls/comdlg32/navbar.h @@ -8,6 +8,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 | 368 ++++++++++++++++++++++++++++++++++++++++ dlls/comdlg32/navbar.h | 4 + 3 files changed, 391 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 1b853ec5061..1b249c5fc92 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -3,33 +3,259 @@ #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 the 1px frame */ + FrameRect(hdc, &rc, frame_brush); + + /* erase the left border, retaining the 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(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_head(&info->crumbs); + if (&crumb1->entry == &info->crumbs) + { + ERR("no crumbs to layout\n"); + return; + } + + crumb2 = (struct crumb *)list_head(&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(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(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, NAVBAR_INFO *info, UINT msg, WPARAM wparam, LPARAM lparam) { CREATESTRUCTW *cs = (CREATESTRUCTW*)lparam; + 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); @@ -64,6 +290,13 @@ static LRESULT NAVBAR_Create(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpar 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); @@ -71,17 +304,45 @@ static LRESULT NAVBAR_Create(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpar
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); + + DestroyWindow(crumb1->hwnd); + + list_remove(&crumb1->entry); + HeapFree(GetProcessHeap(), 0, crumb1); + } + SetWindowLongPtrW(hwnd, 0, 0); ImageList_Destroy(info->icons); DestroyWindow(info->back_btn_hwnd); DestroyWindow(info->fwd_btn_hwnd); DestroyWindow(info->up_btn_hwnd); + DestroyWindow(info->background_hwnd);
HeapFree(GetProcessHeap(), 0, info);
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)) @@ -95,8 +356,113 @@ 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; + struct list new_crumbs; + struct crumb *crumb1, *crumb2; + BOOL matching = TRUE; + HDWP hdwp; + + 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 + { + INT padding = MulDiv(10, info->dpi_x, USER_DEFAULT_SCREEN_DPI); + 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; + + list_add_tail(&new_crumbs, &crumb1->entry); + info->crumbs_total_n += 1; + } + while (ILRemoveLastID(pidl)); + ILFree(pidl); + + /* reuse existing crumbs */ + crumb1 = LIST_ENTRY((&info->crumbs)->prev, struct crumb, entry); + crumb2 = LIST_ENTRY((&new_crumbs)->prev, struct crumb, entry); + for (;;) + { + if (&crumb1->entry != &info->crumbs) + { + if (&crumb2->entry != &new_crumbs + && matching + && (matching = ILIsEqual(crumb2->pidl, crumb1->pidl))) + { + DestroyWindow(crumb2->hwnd); + ILFree(crumb2->pidl); + crumb2->pidl = crumb1->pidl; + crumb2->hwnd = crumb1->hwnd; + } + else + { + DestroyWindow(crumb1->hwnd); + ILFree(crumb1->pidl); + } + } + else + break; + + crumb1 = LIST_ENTRY(crumb1->entry.prev, struct crumb, entry); + crumb2 = LIST_ENTRY(crumb2->entry.prev, 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); }
@@ -111,7 +477,9 @@ static LRESULT CALLBACK NAVBAR_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LP { case WM_NCCREATE: return NAVBAR_Create(hwnd, info, msg, wparam, lparam); case WM_NCDESTROY: 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 a2e6cb8c854..5360f9fc129 100644 --- a/dlls/comdlg32/navbar.h +++ b/dlls/comdlg32/navbar.h @@ -5,10 +5,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 | 204 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 3 deletions(-)
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index 1b249c5fc92..daa4babb391 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -4,6 +4,7 @@ #include "commdlg.h" #include "cdlg.h" #include "shlwapi.h" +#include "commoncontrols.h"
#include "wine/debug.h" #include "wine/list.h" @@ -35,6 +36,9 @@ typedef struct { struct list crumbs; INT crumbs_total_n; INT crumbs_visible_n; + + HWND overflow_hwnd; + HMENU overflow_menu; } NAVBAR_INFO;
struct crumb { @@ -47,6 +51,80 @@ 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 = 0; i < menu_item_count; i++) + { + /* deleting an item shifts further indices, so don't use `i` */ + GetMenuItemInfoW(info->overflow_menu, 0, 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); + } + + 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 - (icon_width / 2), 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) @@ -83,7 +161,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, @@ -99,10 +177,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; @@ -208,6 +286,36 @@ static HDWP NAVBAR_DoLayout(NAVBAR_INFO *info, HDWP hdwp) struct crumb *crumb; INT can_fit_n = info->crumbs_visible_n; UINT background_flags = 0; + INT menu_item_count = GetMenuItemCount(info->overflow_menu); + MENUITEMINFOW first_crumb_menu_item = {0}; + BUTTON_SPLITINFO split_info = {0}; + + split_info.mask = BCSIF_STYLE; + + if (menu_item_count > 0) + { + /* remove the first crumb from overflow menu and hold onto it */ + first_crumb_menu_item.cbSize = sizeof(MENUITEMINFOW); + first_crumb_menu_item.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STRING | MIIM_BITMAP; /* match with NAVBAR_OVERFLOW_Insert */ + GetMenuItemInfoW(info->overflow_menu, menu_item_count - 1, TRUE, &first_crumb_menu_item); + + first_crumb_menu_item.cch += 1; + first_crumb_menu_item.dwTypeData = HeapAlloc(GetProcessHeap(), 0, first_crumb_menu_item.cch); + GetMenuItemInfoW(info->overflow_menu, menu_item_count - 1, TRUE, &first_crumb_menu_item); + + RemoveMenu(info->overflow_menu, menu_item_count - 1, MF_BYPOSITION); + + /* 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); + } + + NAVBAR_OVERFLOW_Clear(info);
LIST_FOR_EACH_ENTRY(crumb, &info->crumbs, struct crumb, entry) { @@ -216,7 +324,11 @@ static HDWP NAVBAR_DoLayout(NAVBAR_INFO *info, HDWP hdwp) if (can_fit_n > 0) flags |= SWP_SHOWWINDOW | SWP_NOCOPYBITS; else + { flags |= SWP_HIDEWINDOW; + if (menu_item_count > 0) + NAVBAR_OVERFLOW_Insert(info, ILClone(crumb->pidl), crumb->display_name); + }
hdwp = DeferWindowPos(hdwp, crumb->hwnd, HWND_TOP, crumb->x, 0, @@ -226,6 +338,10 @@ static HDWP NAVBAR_DoLayout(NAVBAR_INFO *info, HDWP hdwp) can_fit_n -= 1; }
+ /* move the first crumb back */ + if (menu_item_count > 0) + InsertMenuItemW(info->overflow_menu, -1, TRUE, &first_crumb_menu_item); + if (info->background_w > 0) background_flags |= SWP_SHOWWINDOW | SWP_NOCOPYBITS; else @@ -246,6 +362,8 @@ static LRESULT NAVBAR_Create(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpar 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); @@ -297,6 +415,21 @@ static LRESULT NAVBAR_Create(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpar 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_NOTIFYBYPOS; + SetMenuInfo(info->overflow_menu, &menu_info); + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)info);
return DefWindowProcW(hwnd, msg, wparam, lparam); @@ -324,6 +457,9 @@ static LRESULT NAVBAR_Destroy(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa DestroyWindow(info->fwd_btn_hwnd); DestroyWindow(info->up_btn_hwnd); DestroyWindow(info->background_hwnd); + DestroyWindow(info->overflow_hwnd); + NAVBAR_OVERFLOW_Clear(info); + DestroyMenu(info->overflow_menu);
HeapFree(GetProcessHeap(), 0, info);
@@ -368,12 +504,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; struct list new_crumbs; struct crumb *crumb1, *crumb2; BOOL matching = TRUE; @@ -386,6 +540,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); @@ -417,6 +580,19 @@ static LRESULT NAVBAR_SetPIDL(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa while (ILRemoveLastID(pidl)); ILFree(pidl);
+ NAVBAR_OVERFLOW_Clear(info); + + /* move the first crumb to overflow menu, if there are at least 2 crumbs */ + crumb1 = LIST_ENTRY(list_tail(&new_crumbs), struct crumb, entry); + if (crumb1 && crumb1->entry.prev != &new_crumbs) + { + NAVBAR_OVERFLOW_Insert(info, crumb1->pidl, crumb1->display_name); + DestroyWindow(crumb1->hwnd); + + list_remove(&crumb1->entry); + HeapFree(GetProcessHeap(), 0, crumb1); + } + /* reuse existing crumbs */ crumb1 = LIST_ENTRY((&info->crumbs)->prev, struct crumb, entry); crumb2 = LIST_ENTRY((&new_crumbs)->prev, struct crumb, entry); @@ -466,6 +642,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); @@ -479,6 +673,10 @@ static LRESULT CALLBACK NAVBAR_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LP case WM_NCDESTROY: 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 | 320 +++++++++++++++++++++++++++++++++++++- dlls/comdlg32/navbar.h | 5 + 3 files changed, 327 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 daa4babb391..3107e6324c0 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -39,6 +39,8 @@ typedef struct {
HWND overflow_hwnd; HMENU overflow_menu; + + HWND pathedit_hwnd; } NAVBAR_INFO;
struct crumb { @@ -51,6 +53,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_head(&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 the 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}; @@ -125,8 +387,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: @@ -154,6 +433,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); @@ -164,7 +446,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)) @@ -179,12 +461,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(crumb1, &info->crumbs, struct crumb, entry) { INT next_w = w + crumb1->full_w; @@ -269,6 +559,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; @@ -410,10 +705,11 @@ static LRESULT NAVBAR_Create(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpar
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, @@ -423,6 +719,7 @@ static LRESULT NAVBAR_Create(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpar 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); @@ -430,6 +727,14 @@ static LRESULT NAVBAR_Create(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpar menu_info.dwStyle = 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); @@ -460,6 +765,7 @@ static LRESULT NAVBAR_Destroy(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa DestroyWindow(info->overflow_hwnd); NAVBAR_OVERFLOW_Clear(info); DestroyMenu(info->overflow_menu); + DestroyWindow(info->pathedit_hwnd);
HeapFree(GetProcessHeap(), 0, info);
@@ -472,9 +778,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; } @@ -570,6 +879,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 5360f9fc129..1438fd2b322 100644 --- a/dlls/comdlg32/navbar.h +++ b/dlls/comdlg32/navbar.h @@ -14,6 +14,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 | 66 +++++++++++++++++++++++++++++++++++++---- dlls/comdlg32/navbar.h | 1 + 3 files changed, 79 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 3107e6324c0..228080fafd1 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -16,6 +16,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; @@ -28,6 +29,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; @@ -70,6 +72,7 @@ static void NAVBAR_PATHEDIT_Edit(NAVBAR_INFO *info) { struct crumb *crumb; HDWP hdwp; + HICON icon;
NAVBAR_PATHEDIT_SetCurrentPath(info);
@@ -82,6 +85,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 the 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); }
@@ -94,6 +102,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; @@ -104,11 +113,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 the 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 the 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); } @@ -276,6 +293,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; @@ -443,10 +475,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)) @@ -468,10 +500,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;
@@ -543,7 +580,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;
@@ -735,6 +772,16 @@ static LRESULT NAVBAR_Create(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpar 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); @@ -761,6 +808,7 @@ static LRESULT NAVBAR_Destroy(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa DestroyWindow(info->back_btn_hwnd); DestroyWindow(info->fwd_btn_hwnd); DestroyWindow(info->up_btn_hwnd); + DestroyWindow(info->refresh_goto_btn_hwnd); DestroyWindow(info->background_hwnd); DestroyWindow(info->overflow_hwnd); NAVBAR_OVERFLOW_Clear(info); @@ -808,6 +856,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 1438fd2b322..f4d0eb73c45 100644 --- a/dlls/comdlg32/navbar.h +++ b/dlls/comdlg32/navbar.h @@ -13,6 +13,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
Jinoh Kang (@iamahuman) commented about dlls/comdlg32/navbar.c:
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);
SetWindowSubclass(crumb1->hwnd, NAVBAR_RMBMENU_SubclassProc, 0, (DWORD_PTR)info);
crumb1->full_w = full_size.cx + padding;
crumb1->current_w = crumb1->full_w;
list_add_tail(&new_crumbs, &crumb1->entry);
You can use `list_add_head` to _prepend_ items to a list. You can avoid reversing the list this way. Sorry for failing to mention this earlier.
Esme Povirk (@madewokherd) commented about dlls/comdlg32/navbar.c:
+#define COBJMACROS
This should have a copyright/license notice.