Redo of !1857, as suggested, the plan is to split original MR in half, breadcrumbs in first (this) MR, and address edit in another.
The changes are mostly cleanup (formatting, renaming, unused variables, missing free).
Part two branch can be found [here](https://gitlab.winehq.org/vt/wine/-/commits/fd-navbar-part2).
Visually, it hasn't changed:
![](/uploads/37038708b7500cda4f0cffde8981e58c/changes.png)
Requires !2068, otherwise if application doesn't request comctl v6 (e.g. qapitrace), navigation bar will look like this:
![no-comctl-v6](/uploads/03e6a8b6dcf827114157e79640e49fea/no-comctl-v6.png)
Closes: - https://bugs.winehq.org/show_bug.cgi?id=29912 - https://bugs.winehq.org/show_bug.cgi?id=54812 - https://bugs.winehq.org/show_bug.cgi?id=50338 (partially? fully with address edit?)
From: Vladislav Timonin timoninvlad@yandex.ru
--- dlls/comdlg32/Makefile.in | 2 + dlls/comdlg32/comdlg32.rc | 10 + dlls/comdlg32/itemdlg.c | 76 ++--- dlls/comdlg32/navbar.bmp | Bin 0 -> 9354 bytes dlls/comdlg32/navbar.c | 172 ++++++++++ dlls/comdlg32/navbar.h | 47 +++ dlls/comdlg32/navbar.svg | 676 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 937 insertions(+), 46 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..bf6ac778507 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
@@ -148,6 +149,12 @@ STRINGTABLE IDS_FONT_SIZE_INPUT "Font size has to be a number." }
+STRINGTABLE +{ + IDS_BACK "Back" + IDS_FORWARD "Forward" +} + /* * WARNING: DO NOT CHANGE THE SIZE OF THE STANDARD DIALOG TEMPLATES. */ @@ -602,3 +609,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 f3b9a217e79..0a9a8e03983 100644 --- a/dlls/comdlg32/itemdlg.c +++ b/dlls/comdlg32/itemdlg.c @@ -33,13 +33,13 @@ #include "commdlg.h" #include "cdlg.h" #include "filedlgbrowser.h" +#include "navbar.h"
#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 +#define NAVBAR_HEIGHT 30
#include <initguid.h> /* This seems to be another version of IID_IFileDialogCustomize. If @@ -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,12 +1772,11 @@ static void update_layout(FileDialogImpl *This) filename_rc.bottom = filename_rc.top + filename_height; }
- hwnd = GetDlgItem(This->dlg_hwnd, IDC_NAV_TOOLBAR); - if(hwnd) - { - GetWindowRect(hwnd, &toolbar_rc); - MapWindowPoints(NULL, This->dlg_hwnd, (POINT*)&toolbar_rc, 2); - } + /* Navigation bar */ + navbar_rc.top = hspacing; + navbar_rc.bottom = navbar_rc.top + MulDiv(NAVBAR_HEIGHT, This->dpi_y, USER_DEFAULT_SCREEN_DPI); + navbar_rc.left = dialog_rc.left + hspacing; + navbar_rc.right = dialog_rc.right - hspacing;
/* The custom controls */ customctrls_rc.left = dialog_rc.left + hspacing; @@ -1781,7 +1787,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 +1796,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 +1833,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,37 +1904,10 @@ static HRESULT init_explorerbrowser(FileDialogImpl *This)
static void init_toolbar(FileDialogImpl *This, HWND hwnd) { - HWND htoolbar; - TBADDBITMAP tbab; - TBBUTTON button[2]; - int height; - - 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); - height = MulDiv(24, This->dpi_y, USER_DEFAULT_SCREEN_DPI); - SendMessageW(htoolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(height, height)); - SendMessageW(htoolbar, TB_AUTOSIZE, 0, 0); + CreateWindowExW(0, WC_NAVBARW, NULL, WS_CHILD | WS_VISIBLE, + 0, 0, + 0, MulDiv(NAVBAR_HEIGHT, This->dpi_y, USER_DEFAULT_SCREEN_DPI), + hwnd, (HMENU)IDC_NAVBAR, NULL, NULL); }
static void update_control_text(FileDialogImpl *This) @@ -2064,8 +2048,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);
@@ -2218,8 +2202,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"); } @@ -2237,6 +2219,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..43bde05d0c4 --- /dev/null +++ b/dlls/comdlg32/navbar.c @@ -0,0 +1,172 @@ +/* + * 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 tooltip; + + HWND back_btn_hwnd; + HWND fwd_btn_hwnd; +} NAVBAR_INFO; + +static void set_icon(HIMAGELIST icons, INT icon_id, HWND window) +{ + HICON icon; + + icon = ImageList_GetIcon(icons, icon_id, ILD_NORMAL); + SendMessageW(window, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)icon); + DestroyIcon(icon); +} + +static void set_title_and_add_tooltip(NAVBAR_INFO *info, HWND window, UINT string_id) +{ + WCHAR buffer[128] = {0}; + TOOLINFOW toolinfo = {0}; + + LoadStringW(COMDLG32_hInstance, string_id, buffer, ARRAY_SIZE(buffer)); + + SetWindowTextW(window, buffer); + + toolinfo.cbSize = sizeof(toolinfo); + toolinfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS; + toolinfo.hwnd = info->container_hwnd; + toolinfo.lpszText = buffer; + toolinfo.uId = (UINT_PTR)window; + + SendMessageW(info->tooltip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo); +} + +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); + + 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); + + info->tooltip = CreateWindowW(TOOLTIPS_CLASSW, NULL, WS_POPUP | TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + hwnd, 0, COMDLG32_hInstance, NULL); + + x = 0; + info->back_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, + 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); + set_icon(info->icons, ILI_BACK, info->back_btn_hwnd); + set_title_and_add_tooltip(info, info->back_btn_hwnd, IDS_BACK); + + x += cs->cy + 1; + info->fwd_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, + 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); + set_icon(info->icons, ILI_FORWARD, info->fwd_btn_hwnd); + set_title_and_add_tooltip(info, info->fwd_btn_hwnd, IDS_FORWARD); + + 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..617967b829f --- /dev/null +++ b/dlls/comdlg32/navbar.h @@ -0,0 +1,47 @@ +/* + * 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 + +/* strings */ +#define IDS_BACK 2000 +#define IDS_FORWARD 2001 + +/* bitmaps */ +#define IDB_NAVBAR 3000 +/* icons 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>
Hi Vladislav,
On 6/6/23 22:48, Vladislav Timonin wrote:
- x = 0;
- info->back_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL,
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);
- set_icon(info->icons, ILI_BACK, info->back_btn_hwnd);
- set_title_and_add_tooltip(info, info->back_btn_hwnd, IDS_BACK);
- x += cs->cy + 1;
If I understand it correctly, the 1 here is a gap between these arrow buttons, right? So the 1 might need to be calculated with DPI, or they will look closer when in HiDPI.
- info->fwd_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL,
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);
- set_icon(info->icons, ILI_FORWARD, info->fwd_btn_hwnd);
- set_title_and_add_tooltip(info, info->fwd_btn_hwnd, IDS_FORWARD);
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=54812 --- 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 0a9a8e03983..4b07a26b1eb 100644 --- a/dlls/comdlg32/itemdlg.c +++ b/dlls/comdlg32/itemdlg.c @@ -2146,6 +2146,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) @@ -2221,6 +2228,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 43bde05d0c4..f19a8e71911 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -23,10 +23,12 @@ #include "navbar.h" #include "commdlg.h" #include "cdlg.h" +#include "filedlgbrowser.h"
/* private control ids */ #define IDC_NAVBACK 201 #define IDC_NAVFORWARD 202 +#define IDC_NAVUP 203
typedef struct { HWND parent_hwnd; @@ -37,6 +39,7 @@ typedef struct {
HWND back_btn_hwnd; HWND fwd_btn_hwnd; + HWND up_btn_hwnd; } NAVBAR_INFO;
static void set_icon(HIMAGELIST icons, INT icon_id, HWND window) @@ -102,6 +105,15 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) set_icon(info->icons, ILI_FORWARD, info->fwd_btn_hwnd); set_title_and_add_tooltip(info, info->fwd_btn_hwnd, IDS_FORWARD);
+ x += cs->cy + 1; + info->up_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, + 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); + set_icon(info->icons, ILI_UP, info->up_btn_hwnd); + set_title_and_add_tooltip(info, info->up_btn_hwnd, IDS_UPFOLDER); + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)info);
return DefWindowProcW(hwnd, msg, wparam, lparam); @@ -127,6 +139,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 617967b829f..367dc2f1b37 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
/* strings */ #define IDS_BACK 2000
From: Vladislav Timonin timoninvlad@yandex.ru
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50338 --- dlls/comdlg32/itemdlg.c | 19 ++++ dlls/comdlg32/navbar.c | 243 ++++++++++++++++++++++++++++++++++++++++ dlls/comdlg32/navbar.h | 4 + 3 files changed, 266 insertions(+)
diff --git a/dlls/comdlg32/itemdlg.c b/dlls/comdlg32/itemdlg.c index 4b07a26b1eb..edf0b3f10aa 100644 --- a/dlls/comdlg32/itemdlg.c +++ b/dlls/comdlg32/itemdlg.c @@ -2153,6 +2153,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) @@ -2229,6 +2238,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; @@ -3348,6 +3358,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) @@ -3359,6 +3370,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) + ERR("Failed to update navbar.\n"); + else + SendMessageW(hwnd, NBM_SETPIDL, 0, (LPARAM)pidlFolder); + }
events_OnFolderChange(This);
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index f19a8e71911..e8a9106d82c 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -24,15 +24,24 @@ #include "commdlg.h" #include "cdlg.h" #include "filedlgbrowser.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 tooltip; @@ -40,8 +49,22 @@ typedef struct { HWND back_btn_hwnd; HWND fwd_btn_hwnd; HWND up_btn_hwnd; + + struct list crumbs; + INT crumbs_total_n; + INT crumbs_visible_n; } NAVBAR_INFO;
+struct crumb { + struct list entry; + ITEMIDLIST *pidl; + WCHAR *display_name; + HWND hwnd; + INT full_w; + INT current_w; + INT x; +}; + static void set_icon(HIMAGELIST icons, INT icon_id, HWND window) { HICON icon; @@ -69,16 +92,129 @@ static void set_title_and_add_tooltip(NAVBAR_INFO *info, HWND window, UINT strin SendMessageW(info->tooltip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo); }
+static void NAVBAR_CalcLayout(NAVBAR_INFO *info) +{ + RECT container_rc, up_button_rc; + struct crumb *crumb1; + 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 1 crumb */ + if (crumbs_visible_n < 1) + { + crumb1 = (struct crumb *)list_tail(&info->crumbs); + if (&crumb1->entry == &info->crumbs) + { + ERR("no crumbs to layout\n"); + return; + } + + crumb1->current_w = max_crumbs_w; + crumbs_visible_n = 1; + + prev_x = buttons_w + crumb1->current_w; + } + else + prev_x = buttons_w + w; + + 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; + + 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; + } + + 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);
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); @@ -121,6 +257,16 @@ 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) + { + ILFree(crumb1->pidl); + CoTaskMemFree(crumb1->display_name); + list_remove(&crumb1->entry); + HeapFree(GetProcessHeap(), 0, crumb1); + } + SetWindowLongPtrW(hwnd, 0, 0); ImageList_Destroy(info->icons);
@@ -129,6 +275,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); + 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)) @@ -142,11 +301,93 @@ 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); + StrRetToStrW(&strret, pidl, &crumb1->display_name); + + 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); + IShellFolder_Release(desktop); + + LIST_FOR_EACH_ENTRY_SAFE(crumb1, crumb2, &info->crumbs, struct crumb, entry) + { + DestroyWindow(crumb1->hwnd); + ILFree(crumb1->pidl); + CoTaskMemFree(crumb1->display_name); + 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); + 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); @@ -158,7 +399,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 367dc2f1b37..a077cf58095 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
/* strings */ #define IDS_BACK 2000
From: Vladislav Timonin timoninvlad@yandex.ru
Mitigates some of the flickering when changing address. --- dlls/comdlg32/navbar.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index e8a9106d82c..ab71b2ef173 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -365,11 +365,42 @@ static LRESULT NAVBAR_SetPIDL(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa ILFree(pidl); IShellFolder_Release(desktop);
- LIST_FOR_EACH_ENTRY_SAFE(crumb1, crumb2, &info->crumbs, struct crumb, entry) + /* 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); + CoTaskMemFree(crumb2->display_name); + crumb2->pidl = crumb1->pidl; + crumb2->display_name = crumb1->display_name; + 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); CoTaskMemFree(crumb1->display_name); + + 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); }
From: Vladislav Timonin timoninvlad@yandex.ru
--- dlls/comdlg32/navbar.c | 46 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-)
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index ab71b2ef173..5ad19137213 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -95,7 +95,7 @@ static void set_title_and_add_tooltip(NAVBAR_INFO *info, HWND window, UINT strin static void NAVBAR_CalcLayout(NAVBAR_INFO *info) { RECT container_rc, up_button_rc; - struct crumb *crumb1; + struct crumb *crumb1, *crumb2; INT padding, container_w, buttons_w, max_crumbs_w, w = 0, crumbs_visible_n = 0, prev_x; @@ -129,9 +129,11 @@ static void NAVBAR_CalcLayout(NAVBAR_INFO *info) crumbs_visible_n += 1; }
- /* always show at least 1 crumb */ - if (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) { @@ -139,10 +141,42 @@ static void NAVBAR_CalcLayout(NAVBAR_INFO *info) return; }
- crumb1->current_w = max_crumbs_w; - crumbs_visible_n = 1; + 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; + 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 previous crumb take leftover space */ + crumb2->current_w = max_crumbs_w - crumb1->full_w; + + crumbs_visible_n = 2; + prev_x = buttons_w + crumb1->current_w + crumb2->current_w; + } } else prev_x = buttons_w + w;
From: Vladislav Timonin timoninvlad@yandex.ru
--- dlls/comdlg32/navbar.c | 53 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index 5ad19137213..9c8677545fd 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -37,6 +37,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(commdlg); #define IDC_NAVUP 203 #define IDC_NAVCRUMB 204
+#define BACKGROUND_SUBCLASS_ID 1 + typedef struct { HWND parent_hwnd; HWND container_hwnd; @@ -50,6 +52,10 @@ typedef struct { 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; @@ -92,6 +98,28 @@ static void set_title_and_add_tooltip(NAVBAR_INFO *info, HWND window, UINT strin SendMessageW(info->tooltip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo); }
+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; + + GetClientRect(hwnd, &rc); + + /* draw a frame without left border */ + DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_TOP | BF_BOTTOM | BF_RIGHT | BF_FLAT); + + return 0; /* processed */ + } + } + + return DefSubclassProc(hwnd, msg, wparam, lparam); +} + static void NAVBAR_CalcLayout(NAVBAR_INFO *info) { RECT container_rc, up_button_rc; @@ -181,6 +209,9 @@ static void NAVBAR_CalcLayout(NAVBAR_INFO *info) 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) @@ -211,6 +242,7 @@ 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) { @@ -229,6 +261,16 @@ static HDWP NAVBAR_DoLayout(NAVBAR_INFO *info, HDWP hdwp) 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; }
@@ -284,6 +326,13 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) set_icon(info->icons, ILI_UP, info->up_btn_hwnd); set_title_and_add_tooltip(info, info->up_btn_hwnd, IDS_UPFOLDER);
+ 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, BACKGROUND_SUBCLASS_ID, (DWORD_PTR)info); + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)info);
return DefWindowProcW(hwnd, msg, wparam, lparam); @@ -315,7 +364,7 @@ static LRESULT NAVBAR_Size(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wparam
NAVBAR_CalcLayout(info);
- hdwp = BeginDeferWindowPos(info->crumbs_total_n); + hdwp = BeginDeferWindowPos(info->crumbs_total_n + 1); hdwp = NAVBAR_DoLayout(info, hdwp); EndDeferWindowPos(hdwp);
@@ -445,7 +494,7 @@ static LRESULT NAVBAR_SetPIDL(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa
NAVBAR_CalcLayout(info);
- hdwp = BeginDeferWindowPos(info->crumbs_total_n); + hdwp = BeginDeferWindowPos(info->crumbs_total_n + 1); hdwp = NAVBAR_DoLayout(info, hdwp); EndDeferWindowPos(hdwp);
From: Vladislav Timonin timoninvlad@yandex.ru
--- dlls/comdlg32/navbar.c | 176 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 3 deletions(-)
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index 9c8677545fd..e5e952f36a4 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -25,6 +25,7 @@ #include "cdlg.h" #include "filedlgbrowser.h" #include "shlwapi.h" +#include "commoncontrols.h"
#include "wine/debug.h" #include "wine/list.h" @@ -36,6 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(commdlg); #define IDC_NAVFORWARD 202 #define IDC_NAVUP 203 #define IDC_NAVCRUMB 204 +#define IDC_OVERFLOW 205
#define BACKGROUND_SUBCLASS_ID 1
@@ -59,6 +61,9 @@ typedef struct { struct list crumbs; INT crumbs_total_n; INT crumbs_visible_n; + + HWND overflow_hwnd; + HMENU overflow_menu; } NAVBAR_INFO;
struct crumb { @@ -98,6 +103,87 @@ static void set_title_and_add_tooltip(NAVBAR_INFO *info, HWND window, UINT strin SendMessageW(info->tooltip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo); }
+static void NAVBAR_OVERFLOW_Insert(NAVBAR_INFO *info, ITEMIDLIST* pidl, WCHAR *display_name) +{ + MENUITEMINFOW menu_item = {0}; + + TRACE("info %p pidl %p display_name %s\n", info, pidl, debugstr_w(display_name)); + + 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}; + + TRACE("info %p menu_item_count %i\n", info, menu_item_count); + + 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, i, 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) @@ -122,7 +208,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, @@ -138,10 +224,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; @@ -243,6 +329,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) { @@ -251,7 +340,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, @@ -261,6 +353,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 @@ -281,6 +385,7 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) HDC hdc; INT x; HGDIOBJ gui_font = GetStockObject(DEFAULT_GUI_FONT); + MENUINFO menu_info = {0};
info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NAVBAR_INFO)); list_init(&info->crumbs); @@ -333,6 +438,18 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) hwnd, 0, COMDLG32_hInstance, NULL); SetWindowSubclass(info->background_hwnd, NAVBAR_BACKGROUND_SubclassProc, BACKGROUND_SUBCLASS_ID, (DWORD_PTR)info);
+ info->overflow_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, + WS_CHILD | WS_VISIBLE | BS_ICON | BS_SPLITBUTTON, + x, 0, cs->cy + MulDiv(6, info->dpi_x, USER_DEFAULT_SCREEN_DPI), cs->cy, + hwnd, (HMENU)IDC_OVERFLOW, COMDLG32_hInstance, NULL); + SendMessageW(info->overflow_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); + + 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); @@ -352,6 +469,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);
@@ -396,12 +515,32 @@ 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}; + + TRACE("info %p pos %i menu %p\n", info, pos, menu); + + 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; @@ -416,6 +555,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); @@ -502,6 +650,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); @@ -515,6 +681,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
To be able to Backspace multiple times.
On Windows, Back/Forward/Up/Refresh buttons don't take focus when clicked on, but we do, workaround this by sending Go Up command on Backspace ourselves. --- dlls/comdlg32/itemdlg.c | 12 ++++++++++++ dlls/comdlg32/navbar.c | 16 ++++++++++++++++ 2 files changed, 28 insertions(+)
diff --git a/dlls/comdlg32/itemdlg.c b/dlls/comdlg32/itemdlg.c index edf0b3f10aa..ab3555424b8 100644 --- a/dlls/comdlg32/itemdlg.c +++ b/dlls/comdlg32/itemdlg.c @@ -3376,7 +3376,19 @@ static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBro if (!hwnd) ERR("Failed to update navbar.\n"); else + { + IShellView *shellview; + HWND shellview_hwnd; + SendMessageW(hwnd, NBM_SETPIDL, 0, (LPARAM)pidlFolder); + + /* keep focus on the explorer browser to be able to Backspace multiple times */ + hr = IExplorerBrowser_GetCurrentView(This->peb, &IID_IShellView, (void**)&shellview); + if (SUCCEEDED(hr)) + hr = IShellView_GetWindow(shellview, &shellview_hwnd); + if (SUCCEEDED(hr)) + SetFocus(shellview_hwnd); + } }
events_OnFolderChange(This); diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index e5e952f36a4..60e90e0782a 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -40,6 +40,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(commdlg); #define IDC_OVERFLOW 205
#define BACKGROUND_SUBCLASS_ID 1 +#define BACKSPACE_SUBCLASS_ID 2
typedef struct { HWND parent_hwnd; @@ -184,6 +185,17 @@ static LRESULT NAVBAR_OVERFLOW_DrawIcon(HWND hwnd, NAVBAR_INFO *info, UINT msg, return DefWindowProcW(hwnd, msg, wparam, lparam); }
+static LRESULT CALLBACK NAVBAR_BackspaceProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id_subclass, DWORD_PTR ref_data) +{ + NAVBAR_INFO *info = (NAVBAR_INFO *)ref_data; + + if (msg == WM_KEYDOWN && wparam == VK_BACK) + /* match navigation direction with ShellView_OnNotify */ + SendMessageW(info->container_hwnd, WM_COMMAND, IDC_NAVUP, (LPARAM)hwnd); + + 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) { switch (msg) @@ -412,6 +424,7 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) SendMessageW(info->back_btn_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); set_icon(info->icons, ILI_BACK, info->back_btn_hwnd); set_title_and_add_tooltip(info, info->back_btn_hwnd, IDS_BACK); + SetWindowSubclass(info->back_btn_hwnd, NAVBAR_BackspaceProc, BACKSPACE_SUBCLASS_ID, (DWORD_PTR)info);
x += cs->cy + 1; info->fwd_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, @@ -421,6 +434,7 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) SendMessageW(info->fwd_btn_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); set_icon(info->icons, ILI_FORWARD, info->fwd_btn_hwnd); set_title_and_add_tooltip(info, info->fwd_btn_hwnd, IDS_FORWARD); + SetWindowSubclass(info->fwd_btn_hwnd, NAVBAR_BackspaceProc, BACKSPACE_SUBCLASS_ID, (DWORD_PTR)info);
x += cs->cy + 1; info->up_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, @@ -430,6 +444,7 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) SendMessageW(info->up_btn_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); set_icon(info->icons, ILI_UP, info->up_btn_hwnd); set_title_and_add_tooltip(info, info->up_btn_hwnd, IDS_UPFOLDER); + SetWindowSubclass(info->up_btn_hwnd, NAVBAR_BackspaceProc, BACKSPACE_SUBCLASS_ID, (DWORD_PTR)info);
x += cs->cy + 1; info->background_hwnd = CreateWindowExW(0, WC_STATICW, NULL, @@ -584,6 +599,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_BackspaceProc, BACKSPACE_SUBCLASS_ID, (DWORD_PTR)info);
crumb1->full_w = full_size.cx + padding; crumb1->current_w = crumb1->full_w;
From: Vladislav Timonin timoninvlad@yandex.ru
--- dlls/comdlg32/navbar.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index 60e90e0782a..a2a53be984d 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -41,6 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(commdlg);
#define BACKGROUND_SUBCLASS_ID 1 #define BACKSPACE_SUBCLASS_ID 2 +#define BUTTON_SUBCLASS_ID 3
typedef struct { HWND parent_hwnd; @@ -196,6 +197,18 @@ static LRESULT CALLBACK NAVBAR_BackspaceProc(HWND hwnd, UINT msg, WPARAM wparam, return DefSubclassProc(hwnd, msg, wparam, lparam); }
+static LRESULT CALLBACK NAVBAR_ButtonProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT_PTR id_subclass, DWORD_PTR ref_data) +{ + switch (msg) + { + case WM_SETFOCUS: + /* don't paint the focus rect */ + return 0; /* processed */ + } + + 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) { switch (msg) @@ -425,6 +438,7 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) set_icon(info->icons, ILI_BACK, info->back_btn_hwnd); set_title_and_add_tooltip(info, info->back_btn_hwnd, IDS_BACK); SetWindowSubclass(info->back_btn_hwnd, NAVBAR_BackspaceProc, BACKSPACE_SUBCLASS_ID, (DWORD_PTR)info); + SetWindowSubclass(info->back_btn_hwnd, NAVBAR_ButtonProc, BUTTON_SUBCLASS_ID, (DWORD_PTR)info);
x += cs->cy + 1; info->fwd_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, @@ -435,6 +449,7 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) set_icon(info->icons, ILI_FORWARD, info->fwd_btn_hwnd); set_title_and_add_tooltip(info, info->fwd_btn_hwnd, IDS_FORWARD); SetWindowSubclass(info->fwd_btn_hwnd, NAVBAR_BackspaceProc, BACKSPACE_SUBCLASS_ID, (DWORD_PTR)info); + SetWindowSubclass(info->fwd_btn_hwnd, NAVBAR_ButtonProc, BUTTON_SUBCLASS_ID, (DWORD_PTR)info);
x += cs->cy + 1; info->up_btn_hwnd = CreateWindowExW(0, WC_BUTTONW, NULL, @@ -445,6 +460,7 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) set_icon(info->icons, ILI_UP, info->up_btn_hwnd); set_title_and_add_tooltip(info, info->up_btn_hwnd, IDS_UPFOLDER); SetWindowSubclass(info->up_btn_hwnd, NAVBAR_BackspaceProc, BACKSPACE_SUBCLASS_ID, (DWORD_PTR)info); + SetWindowSubclass(info->up_btn_hwnd, NAVBAR_ButtonProc, BUTTON_SUBCLASS_ID, (DWORD_PTR)info);
x += cs->cy + 1; info->background_hwnd = CreateWindowExW(0, WC_STATICW, NULL, @@ -458,6 +474,7 @@ static LRESULT NAVBAR_Create(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) x, 0, cs->cy + MulDiv(6, info->dpi_x, USER_DEFAULT_SCREEN_DPI), cs->cy, hwnd, (HMENU)IDC_OVERFLOW, COMDLG32_hInstance, NULL); SendMessageW(info->overflow_hwnd, WM_SETFONT, (WPARAM)gui_font, FALSE); + SetWindowSubclass(info->overflow_hwnd, NAVBAR_ButtonProc, BUTTON_SUBCLASS_ID, (DWORD_PTR)info);
info->overflow_menu = CreatePopupMenu(); menu_info.cbSize = sizeof(MENUINFO); @@ -600,6 +617,7 @@ static LRESULT NAVBAR_SetPIDL(HWND hwnd, NAVBAR_INFO *info, UINT msg, WPARAM wpa SendMessageW(crumb1->hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&full_size); SetWindowLongPtrW(crumb1->hwnd, GWLP_USERDATA, (LPARAM)crumb1->pidl); SetWindowSubclass(crumb1->hwnd, NAVBAR_BackspaceProc, BACKSPACE_SUBCLASS_ID, (DWORD_PTR)info); + SetWindowSubclass(crumb1->hwnd, NAVBAR_ButtonProc, BUTTON_SUBCLASS_ID, (DWORD_PTR)info);
crumb1->full_w = full_size.cx + padding; crumb1->current_w = crumb1->full_w;
From: Vladislav Timonin timoninvlad@yandex.ru
Focusing the button (by clicking on it, then releasing the click outside the button), and pressing left arrow would leave a sticky highlight. --- dlls/comdlg32/navbar.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/comdlg32/navbar.c b/dlls/comdlg32/navbar.c index a2a53be984d..4a4d05947d2 100644 --- a/dlls/comdlg32/navbar.c +++ b/dlls/comdlg32/navbar.c @@ -204,6 +204,9 @@ static LRESULT CALLBACK NAVBAR_ButtonProc(HWND hwnd, UINT msg, WPARAM wparam, LP case WM_SETFOCUS: /* don't paint the focus rect */ return 0; /* processed */ + case WM_GETDLGCODE: + /* prevent arrow navigation, leaves sticky highlight on buttons */ + return DLGC_WANTARROWS; }
return DefSubclassProc(hwnd, msg, wparam, lparam);