shell32: Add a navigation pane to the ExplorerBrowser control.
This commit is contained in:
parent
209526088c
commit
91c5c0bab3
|
@ -37,6 +37,10 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(shell);
|
||||
|
||||
#define SPLITTER_WIDTH 2
|
||||
#define NP_MIN_WIDTH 60
|
||||
#define SV_MIN_WIDTH 150
|
||||
|
||||
typedef struct _event_client {
|
||||
struct list entry;
|
||||
IExplorerBrowserEvents *pebe;
|
||||
|
@ -60,6 +64,16 @@ typedef struct _ExplorerBrowserImpl {
|
|||
HWND hwnd_main;
|
||||
HWND hwnd_sv;
|
||||
|
||||
RECT splitter_rc;
|
||||
struct {
|
||||
INameSpaceTreeControl2 *pnstc2;
|
||||
HWND hwnd_splitter, hwnd_nstc;
|
||||
DWORD nstc_cookie;
|
||||
UINT width;
|
||||
BOOL show;
|
||||
RECT rc;
|
||||
} navpane;
|
||||
|
||||
EXPLORER_BROWSER_OPTIONS eb_options;
|
||||
FOLDERSETTINGS fs;
|
||||
|
||||
|
@ -80,6 +94,8 @@ typedef struct _ExplorerBrowserImpl {
|
|||
IExplorerPaneVisibility *pepv_site;
|
||||
} ExplorerBrowserImpl;
|
||||
|
||||
static void initialize_navpane(ExplorerBrowserImpl *This, HWND hwnd_parent, RECT *rc);
|
||||
|
||||
/**************************************************************************
|
||||
* Event functions.
|
||||
*/
|
||||
|
@ -255,14 +271,66 @@ static LPCITEMIDLIST travellog_go_forward(ExplorerBrowserImpl *This)
|
|||
static void update_layout(ExplorerBrowserImpl *This)
|
||||
{
|
||||
RECT rc;
|
||||
TRACE("%p\n", This);
|
||||
INT navpane_width_actual;
|
||||
INT shellview_width_actual;
|
||||
TRACE("%p (navpane: %d, EBO_SHOWFRAMES: %d)\n",
|
||||
This, This->navpane.show, This->eb_options & EBO_SHOWFRAMES);
|
||||
|
||||
GetClientRect(This->hwnd_main, &rc);
|
||||
CopyRect(&This->sv_rc, &rc);
|
||||
|
||||
if((This->eb_options & EBO_SHOWFRAMES) && This->navpane.show)
|
||||
navpane_width_actual = This->navpane.width;
|
||||
else
|
||||
navpane_width_actual = 0;
|
||||
|
||||
shellview_width_actual = rc.right - navpane_width_actual;
|
||||
if(shellview_width_actual < SV_MIN_WIDTH && navpane_width_actual)
|
||||
{
|
||||
INT missing_width = SV_MIN_WIDTH - shellview_width_actual;
|
||||
if(missing_width < (navpane_width_actual - NP_MIN_WIDTH))
|
||||
{
|
||||
/* Shrink the navpane */
|
||||
navpane_width_actual -= missing_width;
|
||||
shellview_width_actual += missing_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Hide the navpane */
|
||||
shellview_width_actual += navpane_width_actual;
|
||||
navpane_width_actual = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* Calculate rectangles for the panes. All rectangles contain
|
||||
* the position of the panes relative to hwnd_main.
|
||||
*/
|
||||
|
||||
if(navpane_width_actual)
|
||||
{
|
||||
This->navpane.rc.left = This->navpane.rc.top = 0;
|
||||
This->navpane.rc.right = navpane_width_actual;
|
||||
This->navpane.rc.bottom = rc.bottom;
|
||||
|
||||
if(!This->navpane.hwnd_splitter)
|
||||
initialize_navpane(This, This->hwnd_main, &This->navpane.rc);
|
||||
}
|
||||
else
|
||||
ZeroMemory(&This->navpane.rc, sizeof(RECT));
|
||||
|
||||
This->sv_rc.left = navpane_width_actual;
|
||||
This->sv_rc.top = 0;
|
||||
This->sv_rc.right = This->sv_rc.left + shellview_width_actual;
|
||||
This->sv_rc.bottom = rc.bottom;
|
||||
}
|
||||
|
||||
static void size_panes(ExplorerBrowserImpl *This)
|
||||
{
|
||||
MoveWindow(This->navpane.hwnd_splitter,
|
||||
This->navpane.rc.right - SPLITTER_WIDTH, This->navpane.rc.top,
|
||||
SPLITTER_WIDTH, This->navpane.rc.bottom - This->navpane.rc.top,
|
||||
TRUE);
|
||||
|
||||
MoveWindow(This->hwnd_sv,
|
||||
This->sv_rc.left, This->sv_rc.top,
|
||||
This->sv_rc.right - This->sv_rc.left, This->sv_rc.bottom - This->sv_rc.top,
|
||||
|
@ -387,6 +455,269 @@ static void get_interfaces_from_site(ExplorerBrowserImpl *This)
|
|||
IServiceProvider_Release(psp);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* General pane functionality.
|
||||
*/
|
||||
static void update_panestate(ExplorerBrowserImpl *This)
|
||||
{
|
||||
EXPLORERPANESTATE eps = EPS_DONTCARE;
|
||||
BOOL show_navpane;
|
||||
TRACE("%p\n", This);
|
||||
|
||||
if(!This->pepv_site) return;
|
||||
|
||||
IExplorerPaneVisibility_GetPaneState(This->pepv_site, (REFEXPLORERPANE) &EP_NavPane, &eps);
|
||||
if( !(eps & EPS_DEFAULT_OFF) )
|
||||
show_navpane = TRUE;
|
||||
else
|
||||
show_navpane = FALSE;
|
||||
|
||||
if(This->navpane.show ^ show_navpane)
|
||||
{
|
||||
update_layout(This);
|
||||
size_panes(This);
|
||||
}
|
||||
|
||||
This->navpane.show = show_navpane;
|
||||
}
|
||||
|
||||
static void splitter_draw(HWND hwnd, RECT *rc)
|
||||
{
|
||||
HDC hdc = GetDC(hwnd);
|
||||
InvertRect(hdc, rc);
|
||||
ReleaseDC(hwnd, hdc);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* The Navigation Pane.
|
||||
*/
|
||||
static LRESULT navpane_splitter_beginresize(ExplorerBrowserImpl *This, HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
TRACE("\n");
|
||||
|
||||
SetCapture(hwnd);
|
||||
|
||||
CopyRect(&This->splitter_rc, &This->navpane.rc);
|
||||
This->splitter_rc.left = This->splitter_rc.right - SPLITTER_WIDTH;
|
||||
|
||||
splitter_draw(GetParent(hwnd), &This->splitter_rc);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static LRESULT navpane_splitter_resizing(ExplorerBrowserImpl *This, HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
int new_width, dx;
|
||||
RECT rc;
|
||||
|
||||
if(GetCapture() != hwnd) return FALSE;
|
||||
|
||||
dx = (SHORT)LOWORD(lParam);
|
||||
TRACE("%d.\n", dx);
|
||||
|
||||
CopyRect(&rc, &This->navpane.rc);
|
||||
|
||||
new_width = This->navpane.width + dx;
|
||||
if(new_width > NP_MIN_WIDTH && This->sv_rc.right - new_width > SV_MIN_WIDTH)
|
||||
{
|
||||
rc.right = new_width;
|
||||
rc.left = rc.right - SPLITTER_WIDTH;
|
||||
splitter_draw(GetParent(hwnd), &This->splitter_rc);
|
||||
splitter_draw(GetParent(hwnd), &rc);
|
||||
CopyRect(&This->splitter_rc, &rc);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static LRESULT navpane_splitter_endresize(ExplorerBrowserImpl *This, HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
int new_width, dx;
|
||||
|
||||
if(GetCapture() != hwnd) return FALSE;
|
||||
|
||||
dx = (SHORT)LOWORD(lParam);
|
||||
TRACE("%d.\n", dx);
|
||||
|
||||
splitter_draw(GetParent(hwnd), &This->splitter_rc);
|
||||
|
||||
new_width = This->navpane.width + dx;
|
||||
if(new_width < NP_MIN_WIDTH)
|
||||
new_width = NP_MIN_WIDTH;
|
||||
else if(This->sv_rc.right - new_width < SV_MIN_WIDTH)
|
||||
new_width = This->sv_rc.right - SV_MIN_WIDTH;
|
||||
|
||||
This->navpane.width = new_width;
|
||||
|
||||
update_layout(This);
|
||||
size_panes(This);
|
||||
|
||||
ReleaseCapture();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static LRESULT navpane_on_wm_create(HWND hwnd, CREATESTRUCTW *crs)
|
||||
{
|
||||
ExplorerBrowserImpl *This = crs->lpCreateParams;
|
||||
INameSpaceTreeControl2 *pnstc2;
|
||||
DWORD style;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("%p\n", This);
|
||||
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This);
|
||||
This->navpane.hwnd_splitter = hwnd;
|
||||
|
||||
hr = CoCreateInstance(&CLSID_NamespaceTreeControl, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_INameSpaceTreeControl2, (void**)&pnstc2);
|
||||
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
style = NSTCS_HASEXPANDOS | NSTCS_ROOTHASEXPANDO | NSTCS_SHOWSELECTIONALWAYS;
|
||||
hr = INameSpaceTreeControl2_Initialize(pnstc2, GetParent(hwnd), NULL, style);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
INameSpaceTreeControlEvents *pnstce;
|
||||
IShellFolder *psfdesktop;
|
||||
IShellItem *psi;
|
||||
IOleWindow *pow;
|
||||
LPITEMIDLIST pidl;
|
||||
DWORD cookie, style2 = NSTCS2_DISPLAYPADDING;
|
||||
|
||||
hr = INameSpaceTreeControl2_SetControlStyle2(pnstc2, 0xFF, style2);
|
||||
if(FAILED(hr))
|
||||
ERR("SetControlStyle2 failed (0x%08x)\n", hr);
|
||||
|
||||
hr = INameSpaceTreeControl2_QueryInterface(pnstc2, &IID_IOleWindow, (void**)&pow);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
IOleWindow_GetWindow(pow, &This->navpane.hwnd_nstc);
|
||||
IOleWindow_Release(pow);
|
||||
}
|
||||
else
|
||||
ERR("QueryInterface(IOleWindow) failed (0x%08x)\n", hr);
|
||||
|
||||
pnstce = (INameSpaceTreeControlEvents *)&This->lpnstceVtbl;
|
||||
hr = INameSpaceTreeControl2_TreeAdvise(pnstc2, (IUnknown*)pnstce, &cookie);
|
||||
if(FAILED(hr))
|
||||
ERR("TreeAdvise failed. (0x%08x).\n", hr);
|
||||
|
||||
/*
|
||||
* Add the default roots
|
||||
*/
|
||||
|
||||
/* TODO: This should be FOLDERID_Links */
|
||||
hr = SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
hr = SHCreateShellItem(NULL, NULL, pidl, &psi);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
hr = INameSpaceTreeControl2_AppendRoot(pnstc2, psi, SHCONTF_NONFOLDERS, NSTCRS_VISIBLE, NULL);
|
||||
IShellItem_Release(psi);
|
||||
}
|
||||
ILFree(pidl);
|
||||
}
|
||||
|
||||
SHGetDesktopFolder(&psfdesktop);
|
||||
hr = SHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
|
||||
IShellFolder_Release(psfdesktop);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
hr = INameSpaceTreeControl2_AppendRoot(pnstc2, psi, SHCONTF_FOLDERS, NSTCRS_EXPANDED, NULL);
|
||||
IShellItem_Release(psi);
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
* We should advertise IID_INameSpaceTreeControl to the site of the
|
||||
* host through its IProfferService interface, if any.
|
||||
*/
|
||||
|
||||
This->navpane.pnstc2 = pnstc2;
|
||||
This->navpane.nstc_cookie = cookie;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
This->navpane.pnstc2 = NULL;
|
||||
ERR("Failed (0x%08x)\n", hr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static LRESULT navpane_on_wm_size_move(ExplorerBrowserImpl *This)
|
||||
{
|
||||
UINT height, width;
|
||||
TRACE("%p\n", This);
|
||||
|
||||
width = This->navpane.rc.right - This->navpane.rc.left - SPLITTER_WIDTH;
|
||||
height = This->navpane.rc.bottom - This->navpane.rc.top;
|
||||
|
||||
MoveWindow(This->navpane.hwnd_nstc,
|
||||
This->navpane.rc.left, This->navpane.rc.top,
|
||||
width, height,
|
||||
TRUE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static LRESULT navpane_on_wm_destroy(ExplorerBrowserImpl *This)
|
||||
{
|
||||
INameSpaceTreeControl_TreeUnadvise(This->navpane.pnstc2, This->navpane.nstc_cookie);
|
||||
INameSpaceTreeControl_Release(This->navpane.pnstc2);
|
||||
This->navpane.pnstc2 = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK navpane_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
|
||||
|
||||
switch(uMessage) {
|
||||
case WM_CREATE: return navpane_on_wm_create(hWnd, (CREATESTRUCTW*)lParam);
|
||||
case WM_MOVE: /* Fall through */
|
||||
case WM_SIZE: return navpane_on_wm_size_move(This);
|
||||
case WM_DESTROY: return navpane_on_wm_destroy(This);
|
||||
case WM_LBUTTONDOWN: return navpane_splitter_beginresize(This, hWnd, lParam);
|
||||
case WM_MOUSEMOVE: return navpane_splitter_resizing(This, hWnd, lParam);
|
||||
case WM_LBUTTONUP: return navpane_splitter_endresize(This, hWnd, lParam);
|
||||
default:
|
||||
return DefWindowProcW(hWnd, uMessage, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void initialize_navpane(ExplorerBrowserImpl *This, HWND hwnd_parent, RECT *rc)
|
||||
{
|
||||
WNDCLASSW wc;
|
||||
HWND splitter;
|
||||
static const WCHAR navpane_classname[] = {'e','b','_','n','a','v','p','a','n','e',0};
|
||||
|
||||
if( !GetClassInfoW(shell32_hInstance, navpane_classname, &wc) )
|
||||
{
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = navpane_wndproc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = shell32_hInstance;
|
||||
wc.hIcon = 0;
|
||||
wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_SIZEWE);
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_HIGHLIGHT + 1);
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = navpane_classname;
|
||||
|
||||
if (!RegisterClassW(&wc)) return;
|
||||
}
|
||||
|
||||
splitter = CreateWindowExW(0, navpane_classname, NULL,
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE,
|
||||
rc->right - SPLITTER_WIDTH, rc->top,
|
||||
SPLITTER_WIDTH, rc->bottom - rc->top,
|
||||
hwnd_parent, 0, shell32_hInstance, This);
|
||||
if(!splitter)
|
||||
ERR("Failed to create navpane : %d.\n", GetLastError());
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Main window related functions.
|
||||
|
@ -672,7 +1003,7 @@ static HRESULT WINAPI IExplorerBrowser_fnSetOptions(IExplorerBrowser *iface,
|
|||
{
|
||||
ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
|
||||
static const EXPLORER_BROWSER_OPTIONS unsupported_options =
|
||||
EBO_SHOWFRAMES | EBO_ALWAYSNAVIGATE | EBO_NOWRAPPERWINDOW | EBO_HTMLSHAREPOINTVIEW;
|
||||
EBO_ALWAYSNAVIGATE | EBO_NOWRAPPERWINDOW | EBO_HTMLSHAREPOINTVIEW;
|
||||
|
||||
TRACE("%p (0x%x)\n", This, dwFlag);
|
||||
|
||||
|
@ -798,6 +1129,7 @@ static HRESULT WINAPI IExplorerBrowser_fnBrowseToIDList(IExplorerBrowser *iface,
|
|||
}
|
||||
|
||||
get_interfaces_from_site(This);
|
||||
update_panestate(This);
|
||||
|
||||
/* Only browse if the new pidl differs from the old */
|
||||
if(!ILIsEqual(This->current_pidl, absolute_pidl))
|
||||
|
@ -830,6 +1162,18 @@ static HRESULT WINAPI IExplorerBrowser_fnBrowseToIDList(IExplorerBrowser *iface,
|
|||
ILFree(This->current_pidl);
|
||||
This->current_pidl = absolute_pidl;
|
||||
|
||||
/* Expand the NameSpaceTree to the current location. */
|
||||
if(This->navpane.show && This->navpane.pnstc2)
|
||||
{
|
||||
IShellItem *psi;
|
||||
hr = SHCreateItemFromIDList(This->current_pidl, &IID_IShellItem, (void**)&psi);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
INameSpaceTreeControl_EnsureItemVisible(This->navpane.pnstc2, psi);
|
||||
IShellItem_Release(psi);
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -1620,6 +1964,10 @@ HRESULT WINAPI ExplorerBrowser_Constructor(IUnknown *pUnkOuter, REFIID riid, voi
|
|||
eb->lpowsVtbl = &vt_IObjectWithSite;
|
||||
eb->lpnstceVtbl = &vt_INameSpaceTreeControlEvents;
|
||||
|
||||
/* Default settings */
|
||||
eb->navpane.width = 150;
|
||||
eb->navpane.show = TRUE;
|
||||
|
||||
list_init(&eb->event_clients);
|
||||
list_init(&eb->travellog);
|
||||
|
||||
|
|
|
@ -973,7 +973,7 @@ static void test_SetSite(void)
|
|||
todo_wine ok(cdbimpl->OnPreviewCreated, "Got %d\n", cdbimpl->OnPreviewCreated);
|
||||
|
||||
/* IExplorerPaneVisibility */
|
||||
todo_wine ok(epvimpl->np, "Got %d\n", epvimpl->np);
|
||||
ok(epvimpl->np, "Got %d\n", epvimpl->np);
|
||||
todo_wine ok(epvimpl->cp, "Got %d\n", epvimpl->cp);
|
||||
todo_wine ok(epvimpl->cp_o, "Got %d\n", epvimpl->cp_o);
|
||||
todo_wine ok(epvimpl->cp_v, "Got %d\n", epvimpl->cp_v);
|
||||
|
|
Loading…
Reference in New Issue