mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-12 01:47:24 +10:00
389 lines
12 KiB
C++
389 lines
12 KiB
C++
// Classic Shell (c) 2009-2016, Ivo Beltchev
|
|
// Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author
|
|
|
|
#pragma once
|
|
|
|
#include "SettingsParser.h"
|
|
#include "resource.h"
|
|
#include "Assert.h"
|
|
#include <vector>
|
|
|
|
class CCommandsTree;
|
|
class CSettingsTree;
|
|
class ISettingsPanel;
|
|
struct CSetting;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CResizeableDlg - a dialog that rearranges its controls when it gets resized
|
|
template<class T> class CResizeableDlg: public CDialogImpl<T>
|
|
{
|
|
public:
|
|
CResizeableDlg( void )
|
|
{
|
|
m_ClientSize.cx=m_ClientSize.cy=0;
|
|
m_WindowSize.cx=m_WindowSize.cy=0;
|
|
m_Flags=0;
|
|
}
|
|
|
|
void Create( HWND hWndParent )
|
|
{
|
|
CDialogImpl<T>::Create(hWndParent);
|
|
}
|
|
|
|
void Create( HWND hWndParent, DLGTEMPLATE *pTemplate )
|
|
{
|
|
ATLASSUME(m_hWnd == NULL);
|
|
if (!m_thunk.Init(NULL,NULL))
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return;
|
|
}
|
|
|
|
_AtlWinModule.AddCreateWndData(&m_thunk.cd,(CDialogImplBaseT<CWindow>*)this);
|
|
HWND hWnd=::CreateDialogIndirect(_AtlBaseModule.GetResourceInstance(),pTemplate,hWndParent,T::StartDialogProc);
|
|
ATLASSUME(m_hWnd==hWnd);
|
|
}
|
|
|
|
protected:
|
|
enum
|
|
{
|
|
MOVE_LEFT=1,
|
|
MOVE_LEFT2=2,
|
|
MOVE_RIGHT=4,
|
|
MOVE_RIGHT2=8,
|
|
MOVE_TOP=16,
|
|
MOVE_TOP2=32,
|
|
MOVE_BOTTOM=64,
|
|
MOVE_BOTTOM2=128,
|
|
|
|
MOVE_MOVE_X=MOVE_LEFT|MOVE_RIGHT,
|
|
MOVE_MOVE_Y=MOVE_TOP|MOVE_BOTTOM,
|
|
MOVE_SIZE_X=MOVE_RIGHT,
|
|
MOVE_SIZE_Y=MOVE_BOTTOM,
|
|
MOVE_LEFT_HALF=MOVE_RIGHT2,
|
|
MOVE_RIGHT_HALF=MOVE_LEFT2|MOVE_RIGHT,
|
|
MOVE_CENTER=MOVE_LEFT2|MOVE_RIGHT2,
|
|
MOVE_TOP_HALF=MOVE_BOTTOM2,
|
|
MOVE_BOTTOM_HALF=MOVE_TOP2|MOVE_BOTTOM,
|
|
MOVE_VCENTER=MOVE_TOP2|MOVE_BOTTOM2,
|
|
|
|
MOVE_HORIZONTAL=1,
|
|
MOVE_VERTICAL=2,
|
|
MOVE_GRIPPER=4,
|
|
MOVE_REINITIALIZE=8, // InitResize is called for a second time to recapture the control sizes
|
|
|
|
MOVE_MODAL=MOVE_HORIZONTAL|MOVE_VERTICAL|MOVE_GRIPPER,
|
|
};
|
|
|
|
struct Control
|
|
{
|
|
int id;
|
|
unsigned int flags;
|
|
HWND hwnd;
|
|
RECT rect0;
|
|
};
|
|
|
|
void InitResize( int flags=MOVE_HORIZONTAL|MOVE_VERTICAL )
|
|
{
|
|
m_Flags=flags;
|
|
T *pThis=static_cast<T*>(this);
|
|
|
|
int count=0;
|
|
for (const Control *pControl=pThis->GetResizeControls();pControl->id;pControl++)
|
|
count++;
|
|
m_Controls.resize(count);
|
|
if (count>0)
|
|
memcpy(&m_Controls[0],pThis->GetResizeControls(),count*sizeof(Control));
|
|
|
|
RECT rc;
|
|
pThis->GetClientRect(&rc);
|
|
if (!(m_Flags&MOVE_REINITIALIZE))
|
|
{
|
|
m_Gripper.m_hWnd=NULL;
|
|
if (m_Flags&MOVE_GRIPPER)
|
|
m_Gripper.Create(L"SCROLLBAR",pThis->m_hWnd,rc,NULL,WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|SBS_SIZEBOX|SBS_SIZEGRIP|SBS_SIZEBOXBOTTOMRIGHTALIGN);
|
|
}
|
|
m_ClientSize.cx=rc.right;
|
|
m_ClientSize.cy=rc.bottom;
|
|
pThis->GetWindowRect(&rc);
|
|
m_WindowSize.cx=rc.right-rc.left;
|
|
m_WindowSize.cy=rc.bottom-rc.top;
|
|
for (std::vector<Control>::iterator it=m_Controls.begin();it!=m_Controls.end();++it)
|
|
{
|
|
it->hwnd=pThis->GetDlgItem(it->id);
|
|
Assert(it->hwnd);
|
|
if (!it->hwnd) continue;
|
|
::GetWindowRect(it->hwnd,&it->rect0);
|
|
::MapWindowPoints(NULL,m_hWnd,(POINT*)&it->rect0,2);
|
|
}
|
|
}
|
|
|
|
void OnSize( void )
|
|
{
|
|
T *pThis=static_cast<T*>(this);
|
|
RECT rc;
|
|
pThis->GetClientRect(&rc);
|
|
int dx=rc.right-m_ClientSize.cx;
|
|
int dy=rc.bottom-m_ClientSize.cy;
|
|
int dx2=dx/2;
|
|
int dy2=dy/2;
|
|
for (std::vector<Control>::iterator it=m_Controls.begin();it!=m_Controls.end();++it)
|
|
{
|
|
if (!it->hwnd) continue;
|
|
int x1=it->rect0.left;
|
|
int y1=it->rect0.top;
|
|
int x2=it->rect0.right;
|
|
int y2=it->rect0.bottom;
|
|
if (it->flags&MOVE_LEFT) x1+=dx;
|
|
else if (it->flags&MOVE_LEFT2) x1+=dx2;
|
|
if (it->flags&MOVE_TOP) y1+=dy;
|
|
else if (it->flags&MOVE_TOP2) y1+=dy2;
|
|
if (it->flags&MOVE_RIGHT) x2+=dx;
|
|
else if (it->flags&MOVE_RIGHT2) x2+=dx2;
|
|
if (it->flags&MOVE_BOTTOM) y2+=dy;
|
|
else if (it->flags&MOVE_BOTTOM2) y2+=dy2;
|
|
::SetWindowPos(it->hwnd,NULL,x1,y1,x2-x1,y2-y1,SWP_NOZORDER|SWP_NOCOPYBITS);
|
|
}
|
|
if (m_Gripper.m_hWnd)
|
|
{
|
|
RECT rc2;
|
|
m_Gripper.GetWindowRect(&rc2);
|
|
int w=rc2.right-rc2.left;
|
|
int h=rc2.bottom-rc2.top;
|
|
m_Gripper.SetWindowPos(HWND_BOTTOM,rc.right-w,rc.bottom-h,w,h,0);
|
|
}
|
|
}
|
|
|
|
LRESULT OnGetMinMaxInfo( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
MINMAXINFO *pInfo=(MINMAXINFO*)lParam;
|
|
pInfo->ptMinTrackSize.x=m_WindowSize.cx;
|
|
pInfo->ptMinTrackSize.y=m_WindowSize.cy;
|
|
if (!(m_Flags&MOVE_HORIZONTAL))
|
|
pInfo->ptMaxTrackSize.x=pInfo->ptMinTrackSize.x;
|
|
if (!(m_Flags&MOVE_VERTICAL))
|
|
pInfo->ptMaxTrackSize.y=pInfo->ptMinTrackSize.y;
|
|
return 0;
|
|
}
|
|
|
|
void GetStoreRect( RECT &rc )
|
|
{
|
|
GetWindowRect(&rc);
|
|
rc.right-=rc.left+m_WindowSize.cx;
|
|
rc.bottom-=rc.top+m_WindowSize.cy;
|
|
}
|
|
|
|
void GetPlacementRect( RECT &rc )
|
|
{
|
|
WINDOWPLACEMENT placement;
|
|
GetWindowPlacement(&placement);
|
|
rc=placement.rcNormalPosition;
|
|
rc.right-=rc.left+m_WindowSize.cx;
|
|
rc.bottom-=rc.top+m_WindowSize.cy;
|
|
}
|
|
|
|
void SetStoreRect( const RECT &rc )
|
|
{
|
|
SetWindowPos(NULL,rc.left,rc.top,m_WindowSize.cx+rc.right,m_WindowSize.cy+rc.bottom,SWP_NOZORDER|SWP_NOCOPYBITS);
|
|
SendMessage(DM_REPOSITION);
|
|
}
|
|
|
|
private:
|
|
SIZE m_ClientSize;
|
|
SIZE m_WindowSize;
|
|
int m_Flags;
|
|
CWindow m_Gripper;
|
|
std::vector<Control> m_Controls;
|
|
};
|
|
|
|
#define BEGIN_RESIZE_MAP const Control *GetResizeControls( void ) { static Control controls[]={
|
|
#define RESIZE_CONTROL(id,flags) {id,flags},
|
|
#define END_RESIZE_MAP {0,0}}; return controls; }
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct CStdCommand
|
|
{
|
|
const wchar_t *name; // NULL for the terminator item, empty for custom item
|
|
int displayNameId; // always valid
|
|
int tipID;
|
|
const wchar_t *itemName; // NULL for separators
|
|
const wchar_t *label;
|
|
const wchar_t *tip;
|
|
const wchar_t *icon; // NULL for separators, "none" - force no icon, "" for default icon
|
|
const KNOWNFOLDERID *knownFolder;
|
|
unsigned int settings;
|
|
const wchar_t *iconD;
|
|
|
|
bool IsSeparator( void ) const { return !itemName; }
|
|
bool IsCustom( void ) const { return !*name; }
|
|
bool IsStyle( int style, int mask ) const { return (settings&mask)==0 || (settings&style); }
|
|
};
|
|
|
|
struct CTreeItem
|
|
{
|
|
CString name;
|
|
CString command;
|
|
CString link;
|
|
CString label;
|
|
CString tip;
|
|
CString icon;
|
|
CString iconD;
|
|
unsigned int settings;
|
|
const CStdCommand *pStdCommand; // always valid
|
|
|
|
CTreeItem( void ) { settings=0; pStdCommand=NULL; }
|
|
void SetCommand( CString command, const CStdCommand *pStdCommands, int style, int mask );
|
|
unsigned int GetIconKey( void ) const;
|
|
HICON LoadIcon( bool bSmall, std::vector<HMODULE> &modules ) const;
|
|
unsigned int GetIconDKey( unsigned int iconKey ) const;
|
|
HICON LoadIconD( HICON hIcon, std::vector<HMODULE> &modules ) const; // always large
|
|
CString GetDisplayName( bool bTitle ) const;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
const HICON HICON_NONE=(HICON)-1;
|
|
|
|
class CCustomTreeDlg: public CResizeableDlg<CCustomTreeDlg>
|
|
{
|
|
public:
|
|
CCustomTreeDlg( bool bMenu, const CStdCommand *pStdCommands, int style, int mask );
|
|
~CCustomTreeDlg( void );
|
|
|
|
BEGIN_MSG_MAP( CCustomTreeDlg )
|
|
MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog )
|
|
MESSAGE_HANDLER( WM_SIZE, OnSize )
|
|
MESSAGE_HANDLER( WM_CONTEXTMENU, OnContextMenu )
|
|
|
|
NOTIFY_HANDLER( IDC_TREECOMMANDS, TVN_GETINFOTIP, OnGetInfoTip )
|
|
NOTIFY_HANDLER( IDC_TREECOMMANDS, TVN_BEGINDRAG, OnBeginDrag )
|
|
NOTIFY_HANDLER( IDC_TREECOMMANDS, NM_DBLCLK, OnAddItem )
|
|
NOTIFY_HANDLER( IDC_TREECOMMANDS, TVN_KEYDOWN, OnAddItem )
|
|
NOTIFY_HANDLER( IDC_TREEITEMS, TVN_GETINFOTIP, OnGetInfoTip )
|
|
NOTIFY_HANDLER( IDC_TREEITEMS, NM_DBLCLK, OnEditItem )
|
|
NOTIFY_HANDLER( IDC_TREEITEMS, TVN_KEYDOWN, OnEditItem )
|
|
NOTIFY_HANDLER( IDC_TREEITEMS, NM_CUSTOMDRAW, OnCustomDraw )
|
|
REFLECT_NOTIFICATIONS()
|
|
END_MSG_MAP()
|
|
|
|
BEGIN_RESIZE_MAP
|
|
RESIZE_CONTROL(IDC_TREEITEMS,MOVE_LEFT_HALF|MOVE_SIZE_Y)
|
|
RESIZE_CONTROL(IDC_STATICMIDDLE,MOVE_CENTER|MOVE_VCENTER)
|
|
RESIZE_CONTROL(IDC_STATICRIGHT,MOVE_CENTER)
|
|
RESIZE_CONTROL(IDC_TREECOMMANDS,MOVE_RIGHT_HALF|MOVE_SIZE_Y)
|
|
RESIZE_CONTROL(IDC_STATICHINT,MOVE_SIZE_X|MOVE_MOVE_Y)
|
|
END_RESIZE_MAP
|
|
|
|
void SetGroup( CSetting *pGroup, bool bReset );
|
|
void SerializeData( void );
|
|
|
|
protected:
|
|
// Handler prototypes:
|
|
// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
|
// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
|
|
// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
|
|
LRESULT OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnContextMenu( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnGetInfoTip( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnBeginDrag( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnAddItem( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnEditItem( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnCustomDraw( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
|
|
virtual void InitItems( void ) {}
|
|
virtual void ItemsChanged( void ) {}
|
|
virtual void ParseTreeItemExtra( CTreeItem *pItem, CSettingsParser &parser ) {}
|
|
virtual void SerializeItemExtra( CTreeItem *pItem, std::vector<wchar_t> &stringBuilder ) {}
|
|
virtual bool EditItem( CTreeItem *pItem, HWND tree, HTREEITEM hItem, std::vector<HMODULE> &modules );
|
|
void AddItem( HTREEITEM hCommand );
|
|
|
|
HTREEITEM GetRoot( void );
|
|
HTREEITEM GetChild( HTREEITEM hParent );
|
|
HTREEITEM GetNext( HTREEITEM hItem );
|
|
CTreeItem *GetItem( HTREEITEM hItem );
|
|
|
|
static void AppendString( std::vector<wchar_t> &stringBuilder, const wchar_t *text );
|
|
|
|
int m_Style, m_StyleMask;
|
|
|
|
private:
|
|
CSettingsTree &m_Tree;
|
|
CCommandsTree &m_CommandsTree;
|
|
const CStdCommand *m_pStdCommands;
|
|
CSetting *m_pSetting;
|
|
bool m_bMenu;
|
|
|
|
const CStdCommand *FindStdCommand( const wchar_t *name );
|
|
|
|
void EditItemInternal( CTreeItem *pItem, HTREEITEM hItem );
|
|
int ParseTreeItem( CTreeItem *pItem, CSettingsParser &parser );
|
|
void SerializeItem( HTREEITEM hItem, std::vector<wchar_t> &stringBuilder );
|
|
void CreateTreeItems( CSettingsParser &parser, HTREEITEM hParent, const CSettingsParser::TreeItem *pItems, int index );
|
|
};
|
|
|
|
class CEditCustomItemDlg: public CResizeableDlg<CEditCustomItemDlg>
|
|
{
|
|
public:
|
|
CEditCustomItemDlg( CTreeItem *pItem, std::vector<HMODULE> &modules ): m_Modules(modules) { m_pItem=pItem; }
|
|
virtual ~CEditCustomItemDlg( void );
|
|
void SetEnableParent( HWND parent ) { m_EnableParent=parent; }
|
|
bool GetResult( void ) { return m_bResult; }
|
|
|
|
BEGIN_MSG_MAP( CEditCustomItemDlg )
|
|
MESSAGE_HANDLER( WM_SIZE, OnSize )
|
|
MESSAGE_HANDLER( WM_GETMINMAXINFO, OnGetMinMaxInfo )
|
|
END_MSG_MAP()
|
|
|
|
virtual BEGIN_RESIZE_MAP
|
|
END_RESIZE_MAP
|
|
|
|
bool Run( HWND parent, int dlgID );
|
|
|
|
protected:
|
|
CTreeItem *m_pItem;
|
|
|
|
// Handler prototypes:
|
|
// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
|
// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
|
|
// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
|
|
LRESULT OnSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnBrowse( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled );
|
|
LRESULT OnOK( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled );
|
|
LRESULT OnCancel( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled );
|
|
|
|
void InitDialog( CWindow commandCombo, const CStdCommand *pStdcommands, int style, int mask, CWindow linkCombo, const KNOWNFOLDERID *const *pCommonLinks );
|
|
void UpdateIcons( int iconID, int iconDID );
|
|
CString GetComboText( WORD wNotifyCode, WORD wID );
|
|
|
|
private:
|
|
std::vector<HMODULE> &m_Modules;
|
|
HWND m_EnableParent;
|
|
bool m_bResult;
|
|
HICON m_hIcon;
|
|
unsigned int m_IconKey;
|
|
HICON m_hIconD;
|
|
unsigned int m_IconDKey;
|
|
CTreeItem m_StoredItem;
|
|
|
|
void StorePlacement( void );
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
ISettingsPanel *GetDefaultSettings( const CString *filter, const CSetting *pSelect );
|
|
HIMAGELIST GetSettingsImageList( HWND tree );
|
|
bool BrowseForIcon( HWND hWndParent, wchar_t *path, int &id );
|
|
bool BrowseForBitmap( HWND hWndParent, wchar_t *path, bool bAllowJpeg );
|
|
bool BrowseForSound( HWND hWndParent, wchar_t *path );
|
|
const wchar_t *GetSettingsRegPath( void );
|
|
|
|
// Special GUID for the real desktop
|
|
extern const GUID FOLDERID_DesktopRoot;
|
|
|
|
bool BrowseCommandHelper( HWND parent, wchar_t *text );
|
|
bool BrowseLinkHelper( HWND parent, wchar_t *text );
|
|
bool BrowseIconHelper( HWND parent, wchar_t *text );
|