mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-12 01:47:24 +10:00
We are storing color settings in BBGGRR format (for historical reasons). This may be confusing for people that are used to (more widely used) RRGGBB format. Thus we will present color settings in RRGGBB format when editing. We will still use BBGGRR format for those settings internally. To maintain backward compatibility with existing settings stored in registry/xml. Also setting descriptions now contain hint about expected color format. This way it should be more clear what values `Open-Shell` expects. Fixes #82, #1141.
3633 lines
102 KiB
C++
3633 lines
102 KiB
C++
// Classic Shell (c) 2009-2017, Ivo Beltchev
|
|
// Open-Shell (c) 2017-2018, The Open-Shell Team
|
|
// Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author
|
|
|
|
#include <stdafx.h>
|
|
#include "resource.h"
|
|
#include "Settings.h"
|
|
#include "SettingsUIHelper.h"
|
|
#include "ResourceHelper.h"
|
|
#include "ComHelper.h"
|
|
#include "FNVHash.h"
|
|
#include "StringUtils.h"
|
|
#include "Translations.h"
|
|
#include "DownloadHelper.h"
|
|
#include <uxtheme.h>
|
|
#include <map>
|
|
#include <algorithm>
|
|
|
|
const KNOWNFOLDERID FOLDERID_DesktopRoot={'DESK', 'TO', 'P', {'D', 'E', 'S', 'K', 'T', 'O', 'P', 0x00}};
|
|
|
|
static bool IsVariantTrue( const CComVariant &var )
|
|
{
|
|
return (var.vt==VT_I4 && var.intVal==1);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CTreeItem::SetCommand( CString command, const CStdCommand *pStdCommands, int style, int mask )
|
|
{
|
|
this->command=command;
|
|
pStdCommand=NULL;
|
|
for (int i=0;pStdCommands[i].name;i++)
|
|
{
|
|
if (!pStdCommands[i].IsStyle(style,mask)) continue;
|
|
if (_wcsicmp(pStdCommands[i].name,command)==0)
|
|
{
|
|
pStdCommand=&pStdCommands[i];
|
|
return;
|
|
}
|
|
else if (pStdCommands[i].IsCustom())
|
|
{
|
|
pStdCommand=&pStdCommands[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int CTreeItem::GetIconKey( void ) const
|
|
{
|
|
if (!icon.IsEmpty())
|
|
return CalcFNVHash(icon);
|
|
else if (pStdCommand && pStdCommand->knownFolder)
|
|
return CalcFNVHash(pStdCommand->knownFolder,sizeof(GUID));
|
|
else if (!link.IsEmpty())
|
|
return CalcFNVHash(link);
|
|
return 0;
|
|
}
|
|
|
|
HICON CTreeItem::LoadIcon( bool bSmall, std::vector<HMODULE> &modules ) const
|
|
{
|
|
if (!icon.IsEmpty())
|
|
{
|
|
if (_wcsicmp(icon,L"none")==0)
|
|
return bSmall?HICON_NONE:NULL;
|
|
return ::LoadIcon(GetSystemMetrics(bSmall?SM_CXSMICON:SM_CXICON),icon,modules);
|
|
}
|
|
else
|
|
{
|
|
CAbsolutePidl pidl;
|
|
if (pStdCommand && pStdCommand->knownFolder)
|
|
{
|
|
SHGetKnownFolderIDList(*pStdCommand->knownFolder,0,NULL,&pidl);
|
|
}
|
|
else if (!link.IsEmpty())
|
|
{
|
|
const wchar_t *c=wcschr(link,'|');
|
|
if (c)
|
|
{
|
|
for (c++;*c==' ';)
|
|
c++;
|
|
}
|
|
else
|
|
c=link;
|
|
wchar_t buf[_MAX_PATH];
|
|
Strcpy(buf,_countof(buf),c);
|
|
DoEnvironmentSubst(buf,_countof(buf));
|
|
|
|
wchar_t *second=wcschr(buf,';');
|
|
if (second)
|
|
{
|
|
wchar_t *end= second;
|
|
while (end>buf)
|
|
{
|
|
*end=0;
|
|
end--;
|
|
if (*end!=' ')
|
|
break;
|
|
}
|
|
}
|
|
|
|
ShParseDisplayName(buf,&pidl,0,NULL);
|
|
}
|
|
if (pidl)
|
|
{
|
|
HICON hIcon=::LoadIcon(GetSystemMetrics(bSmall?SM_CXSMICON:SM_CXICON),pidl);
|
|
return hIcon;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
unsigned int CTreeItem::GetIconDKey( unsigned int iconKey ) const
|
|
{
|
|
if (iconD.IsEmpty())
|
|
return ~iconKey;
|
|
return CalcFNVHash(iconD);
|
|
}
|
|
|
|
HICON CTreeItem::LoadIconD( HICON hIcon, std::vector<HMODULE> &modules ) const
|
|
{
|
|
if (!iconD.IsEmpty())
|
|
{
|
|
if (_wcsicmp(iconD,L"none")==0)
|
|
return NULL;
|
|
return ::LoadIcon(GetSystemMetrics(SM_CXICON),iconD,modules);
|
|
}
|
|
else if (hIcon)
|
|
return CreateDisabledIcon(hIcon,GetSystemMetrics(SM_CXICON));
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
CString CTreeItem::GetDisplayName( bool bTitle ) const
|
|
{
|
|
if (pStdCommand->IsCustom())
|
|
{
|
|
if (!label.IsEmpty())
|
|
{
|
|
if (label[0]!='$')
|
|
return label;
|
|
const wchar_t *pLabel=label;
|
|
return FindTranslation(pLabel+1,pLabel);
|
|
}
|
|
if (!bTitle && !link.IsEmpty())
|
|
{
|
|
const wchar_t *c=wcschr(link,'|');
|
|
if (c)
|
|
{
|
|
for (c++;*c==' ';)
|
|
c++;
|
|
}
|
|
else
|
|
c=link;
|
|
wchar_t buf[_MAX_PATH];
|
|
Strcpy(buf,_countof(buf),c);
|
|
DoEnvironmentSubst(buf,_countof(buf));
|
|
|
|
wchar_t *second=wcschr(buf,';');
|
|
if (second)
|
|
{
|
|
wchar_t *end= second;
|
|
while (end>buf)
|
|
{
|
|
*end=0;
|
|
end--;
|
|
if (*end!=' ')
|
|
break;
|
|
}
|
|
}
|
|
|
|
CAbsolutePidl pidl;
|
|
ShParseDisplayName(buf,&pidl,0,NULL);
|
|
if (pidl)
|
|
{
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(SHCreateItemFromIDList(pidl,IID_IShellItem,(void**)&pItem)))
|
|
{
|
|
CComString pName;
|
|
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_NORMALDISPLAY,&pName)))
|
|
{
|
|
CString name;
|
|
name.Format(L"%s (%s)",(const wchar_t*)LoadStringEx(pStdCommand->displayNameId),(const wchar_t*)pName);
|
|
return name;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!bTitle && !tip.IsEmpty())
|
|
{
|
|
const wchar_t *pTip=tip;
|
|
CString name;
|
|
if (pTip[0]=='$')
|
|
name.Format(L"%s (%s)",LoadStringEx(pStdCommand->displayNameId),FindTranslation(pTip+1,pTip));
|
|
else
|
|
name.Format(L"%s (%s)",LoadStringEx(pStdCommand->displayNameId),pTip);
|
|
return name;
|
|
}
|
|
}
|
|
return LoadStringEx(pStdCommand->displayNameId);
|
|
}
|
|
|
|
// Subclass the renaming editbox to handle Esc and Enter
|
|
static LRESULT CALLBACK SubclassEditboxProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_GETDLGCODE)
|
|
return DLGC_WANTALLKEYS;
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
class CSettingsTree: public CWindowImpl<CSettingsTree, CWindow>
|
|
{
|
|
public:
|
|
BEGIN_MSG_MAP( CSettingsTree )
|
|
MESSAGE_HANDLER( WM_DESTROY, OnDestroy )
|
|
MESSAGE_HANDLER( WM_MOUSEMOVE, OnMouseMove )
|
|
MESSAGE_HANDLER( WM_LBUTTONUP, OnLButtonUp )
|
|
MESSAGE_HANDLER( WM_RBUTTONDOWN, OnRButtonDown )
|
|
MESSAGE_HANDLER( WM_KEYUP, OnKeyUp )
|
|
MESSAGE_HANDLER( WM_GETDLGCODE, OnGetDlgCode )
|
|
MESSAGE_HANDLER( WM_CHAR, OnChar )
|
|
MESSAGE_HANDLER( WM_CAPTURECHANGED, OnCaptureChanged )
|
|
MESSAGE_HANDLER( WM_TIMER, OnTimer )
|
|
REFLECTED_NOTIFY_CODE_HANDLER( TVN_DELETEITEM, OnDeleteItem )
|
|
REFLECTED_NOTIFY_CODE_HANDLER( TVN_BEGINDRAG, OnBeginDrag )
|
|
REFLECTED_NOTIFY_CODE_HANDLER( TVN_BEGINLABELEDIT, OnBeginLabelEdit )
|
|
REFLECTED_NOTIFY_CODE_HANDLER( TVN_ENDLABELEDIT, OnEndLabelEdit )
|
|
REFLECTED_NOTIFY_CODE_HANDLER( TVN_KEYDOWN, OnKeyDown )
|
|
END_MSG_MAP()
|
|
|
|
CSettingsTree( int mask ) { m_ImageList=NULL; m_StyleMask=mask; }
|
|
void SubclassWindow( HWND hWnd, CCustomTreeDlg *pOwner );
|
|
int LoadIcon( const CTreeItem *pItem );
|
|
int UpdateItem( CTreeItem *pItem, HTREEITEM hItem );
|
|
void SetDisabled( bool bDisabled ) { m_bDisabled=bDisabled; }
|
|
bool IsDragging( void ) const { return m_DragMode!=DRAG_NONE; }
|
|
|
|
void DeleteItem( HTREEITEM hItem );
|
|
|
|
void BeginDrag( const CStdCommand *pCommand );
|
|
HTREEITEM CreateStdItem( const CStdCommand *pCommand, HTREEITEM hParent, HTREEITEM hAfter );
|
|
|
|
std::vector<HMODULE> m_Modules;
|
|
|
|
protected:
|
|
LRESULT OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnMouseMove( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnLButtonUp( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnRButtonDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnKeyUp( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnGetDlgCode( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnChar( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnCaptureChanged( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnDeleteItem( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnBeginDrag( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnBeginLabelEdit( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnEndLabelEdit( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnKeyDown( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
|
|
private:
|
|
CCustomTreeDlg *m_pOwner;
|
|
std::map<unsigned int,int> m_IconCache;
|
|
HIMAGELIST m_ImageList;
|
|
bool m_bDisabled;
|
|
|
|
enum TDragMode
|
|
{
|
|
DRAG_NONE,
|
|
DRAG_DELETE,
|
|
DRAG_ERROR,
|
|
DRAG_MOVE, // these must be the last two
|
|
DRAG_COPY,
|
|
};
|
|
|
|
enum TDropLocation
|
|
{
|
|
DROP_NOWHERE,
|
|
DROP_INSIDE,
|
|
DROP_BEFORE,
|
|
DROP_AFTER,
|
|
DROP_LAST,
|
|
};
|
|
|
|
enum {
|
|
TIMER_SCROLL=1,
|
|
TIMER_HOVER=2,
|
|
};
|
|
|
|
int m_StyleMask;
|
|
TDragMode m_DragMode;
|
|
HCURSOR m_CursorError, m_CursorMove, m_CursorCopy, m_CursorDel;
|
|
HTREEITEM m_DragItem;
|
|
HTREEITEM m_DropTarget;
|
|
HTREEITEM m_DropSubmenu;
|
|
TDropLocation m_DropLocation;
|
|
int m_Scroll;
|
|
HTREEITEM m_HoverItem;
|
|
const CStdCommand *m_pStdDragItem;
|
|
bool m_bDragLink; // the item being dragged is a link
|
|
|
|
bool FindItemByName( HTREEITEM hParent, const wchar_t *name, HTREEITEM hExclude );
|
|
CString CreateUniqueName( CString oldName );
|
|
HTREEITEM CreateDeepCopy( HTREEITEM hSource, HTREEITEM hParent, HTREEITEM hAfter, bool bRename );
|
|
};
|
|
|
|
void CSettingsTree::SubclassWindow( HWND hWnd, CCustomTreeDlg *pOwner )
|
|
{
|
|
m_pOwner=pOwner;
|
|
int size=GetSystemMetrics(SM_CXSMICON);
|
|
if (!m_ImageList)
|
|
m_ImageList=ImageList_Create(size,size,ILC_COLOR32|ILC_MASK|ILC_MIRROR,1,16);
|
|
CWindowImpl<CSettingsTree, CWindow>::SubclassWindow(hWnd);
|
|
TreeView_SetImageList(hWnd,m_ImageList,TVSIL_NORMAL);
|
|
|
|
BITMAPINFO bi={0};
|
|
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
|
|
bi.bmiHeader.biWidth=bi.bmiHeader.biHeight=size;
|
|
bi.bmiHeader.biPlanes=1;
|
|
bi.bmiHeader.biBitCount=32;
|
|
RECT rc={0,0,size,size};
|
|
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
HBITMAP bmp=CreateDIBSection(hdc,&bi,DIB_RGB_COLORS,NULL,NULL,0);
|
|
HGDIOBJ bmp0=SelectObject(hdc,bmp);
|
|
FillRect(hdc,&rc,(HBRUSH)(COLOR_WINDOW+1));
|
|
SelectObject(hdc,bmp0);
|
|
DeleteDC(hdc);
|
|
ImageList_AddMasked(m_ImageList,bmp,GetSysColor(COLOR_WINDOW));
|
|
DeleteObject(bmp);
|
|
|
|
SHFILEINFO info;
|
|
if (SHGetFileInfo(L"file",FILE_ATTRIBUTE_NORMAL,&info,sizeof(info),SHGFI_USEFILEATTRIBUTES|SHGFI_ICON|SHGFI_SMALLICON))
|
|
{
|
|
ImageList_AddIcon(m_ImageList,info.hIcon);
|
|
DestroyIcon(info.hIcon);
|
|
}
|
|
m_DragMode=DRAG_NONE;
|
|
HMODULE hOle32=LoadLibrary(L"ole32.dll");
|
|
if (hOle32)
|
|
{
|
|
m_CursorError=(HCURSOR)LoadImage(hOle32,MAKEINTRESOURCE(1),IMAGE_CURSOR,0,0,LR_DEFAULTSIZE);
|
|
m_CursorMove=(HCURSOR)LoadImage(hOle32,MAKEINTRESOURCE(2),IMAGE_CURSOR,0,0,LR_DEFAULTSIZE);
|
|
m_CursorCopy=(HCURSOR)LoadImage(hOle32,MAKEINTRESOURCE(3),IMAGE_CURSOR,0,0,LR_DEFAULTSIZE);
|
|
m_CursorDel=(HCURSOR)LoadImage(hOle32,MAKEINTRESOURCE(5),IMAGE_CURSOR,0,0,LR_DEFAULTSIZE);
|
|
FreeLibrary(hOle32);
|
|
}
|
|
}
|
|
|
|
int CSettingsTree::LoadIcon( const CTreeItem *pItem )
|
|
{
|
|
unsigned int key=pItem->GetIconKey();
|
|
std::map<unsigned int,int>::const_iterator it=m_IconCache.find(key);
|
|
if (it!=m_IconCache.end())
|
|
return it->second;
|
|
|
|
// extract icon
|
|
HICON hIcon=pItem->LoadIcon(true,m_Modules);
|
|
if (hIcon==HICON_NONE)
|
|
{
|
|
m_IconCache[key]=0;
|
|
return 0;
|
|
}
|
|
int index=1;
|
|
if (hIcon)
|
|
{
|
|
index=ImageList_AddIcon(m_ImageList,hIcon);
|
|
DestroyIcon(hIcon);
|
|
}
|
|
m_IconCache[key]=index;
|
|
return index;
|
|
}
|
|
|
|
int CSettingsTree::UpdateItem( CTreeItem *pItem, HTREEITEM hItem )
|
|
{
|
|
TVITEM item={TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT,hItem};
|
|
|
|
item.iImage=item.iSelectedImage=LoadIcon(pItem);
|
|
if (hItem)
|
|
{
|
|
CString dispName=pItem->GetDisplayName(false);
|
|
item.pszText=(LPWSTR)(LPCWSTR)dispName;
|
|
TreeView_SetItem(m_hWnd,&item);
|
|
}
|
|
return item.iImage;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
for (std::vector<HMODULE>::const_iterator it=m_Modules.begin();it!=m_Modules.end();++it)
|
|
FreeLibrary(*it);
|
|
m_Modules.clear();
|
|
if (m_CursorError) DestroyCursor(m_CursorError);
|
|
if (m_CursorMove) DestroyCursor(m_CursorMove);
|
|
if (m_CursorCopy) DestroyCursor(m_CursorCopy);
|
|
if (m_CursorDel) DestroyCursor(m_CursorDel);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnDeleteItem( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
// free data
|
|
NMTREEVIEW *pItem=(NMTREEVIEW*)pnmh;
|
|
delete (CTreeItem*)pItem->itemOld.lParam;
|
|
return 0;
|
|
}
|
|
|
|
void CSettingsTree::BeginDrag( const CStdCommand *pCommand )
|
|
{
|
|
if (m_bDisabled) return;
|
|
m_pStdDragItem=pCommand;
|
|
m_bDragLink=pCommand->knownFolder!=NULL;
|
|
m_DragItem=TreeView_GetSelection(m_hWnd);
|
|
SetFocus();
|
|
SetCapture();
|
|
m_DragMode=DRAG_COPY;
|
|
m_DropTarget=NULL;
|
|
m_DropLocation=DROP_NOWHERE;
|
|
m_Scroll=0;
|
|
m_HoverItem=NULL;
|
|
m_DropSubmenu=NULL;
|
|
SetCursor(m_CursorCopy);
|
|
TreeView_SelectItem(m_hWnd,NULL);
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnBeginDrag( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
if (m_bDisabled) return 0;
|
|
NMTREEVIEW *pDrag=(NMTREEVIEW*)pnmh;
|
|
CTreeItem *pItem=(CTreeItem*)pDrag->itemNew.lParam;
|
|
if (!pItem) return 0;
|
|
m_pStdDragItem=NULL;
|
|
m_DragItem=pDrag->itemNew.hItem;
|
|
m_bDragLink=(pItem->pStdCommand && pItem->pStdCommand->knownFolder) || !pItem->link.IsEmpty();
|
|
TreeView_SelectItem(m_hWnd,m_DragItem);
|
|
SetCapture();
|
|
m_DragMode=GetKeyState(VK_CONTROL)<0?DRAG_COPY:DRAG_MOVE;
|
|
m_DropTarget=NULL;
|
|
m_DropLocation=DROP_NOWHERE;
|
|
m_Scroll=0;
|
|
m_HoverItem=NULL;
|
|
m_DropSubmenu=NULL;
|
|
SetCursor(m_DragMode==DRAG_COPY?m_CursorCopy:m_CursorMove);
|
|
SetFocus();
|
|
TreeView_SelectItem(m_hWnd,NULL);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnMouseMove( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_DragMode==DRAG_NONE)
|
|
{
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
// find the drop location
|
|
m_DropTarget=NULL;
|
|
m_DropLocation=DROP_NOWHERE;
|
|
TVHITTESTINFO test={{(short)LOWORD(lParam),(short)HIWORD(lParam)}};
|
|
RECT rc;
|
|
GetClientRect(&rc);
|
|
int h=TreeView_GetItemHeight(m_hWnd);
|
|
int scroll=0;
|
|
if (test.pt.y<h)
|
|
scroll=-1;
|
|
if (test.pt.y>rc.bottom-h)
|
|
scroll=1;
|
|
if (m_Scroll!=scroll)
|
|
{
|
|
m_Scroll=scroll;
|
|
if (m_Scroll)
|
|
SetTimer(TIMER_SCROLL,100);
|
|
else
|
|
KillTimer(TIMER_SCROLL);
|
|
}
|
|
bool bDelete=!PtInRect(&rc,test.pt);
|
|
if (!bDelete)
|
|
{
|
|
HTREEITEM hLast=TreeView_GetLastVisible(m_hWnd);
|
|
if (hLast)
|
|
{
|
|
TreeView_GetItemRect(m_hWnd,hLast,&rc,FALSE);
|
|
if (TreeView_HitTest(m_hWnd,&test))
|
|
{
|
|
m_DropTarget=test.hItem;
|
|
}
|
|
else
|
|
{
|
|
if (test.pt.y>=rc.bottom)
|
|
{
|
|
// after the last visible item
|
|
m_DropTarget=hLast;
|
|
}
|
|
}
|
|
}
|
|
else if (m_pStdDragItem)
|
|
m_DropLocation=DROP_LAST;
|
|
|
|
if (m_DropTarget && !m_pStdDragItem)
|
|
{
|
|
// can't drop inside itself
|
|
for (HTREEITEM hItem=TreeView_GetParent(m_hWnd,m_DropTarget);hItem;hItem=TreeView_GetParent(m_hWnd,hItem))
|
|
{
|
|
if (hItem==m_DragItem)
|
|
{
|
|
m_DropTarget=NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (m_DropTarget)
|
|
{
|
|
TreeView_GetItemRect(m_hWnd,m_DropTarget,&rc,FALSE);
|
|
TVITEM item={TVIF_PARAM,m_DropTarget};
|
|
TreeView_GetItem(m_hWnd,&item);
|
|
int dy=test.pt.y-rc.top;
|
|
int h1=(rc.bottom-rc.top)/4;
|
|
int h2=(rc.bottom-rc.top)-h1;
|
|
if (!item.lParam || ((CTreeItem*)item.lParam)->pStdCommand->IsSeparator())
|
|
{
|
|
h1=(rc.bottom-rc.top)/2;
|
|
h2=(rc.bottom-rc.top)-h1;
|
|
}
|
|
if (dy<h1)
|
|
m_DropLocation=DROP_BEFORE;
|
|
else if (dy>=h2)
|
|
m_DropLocation=DROP_AFTER;
|
|
else
|
|
{
|
|
// can't drop in a separator or itself
|
|
if (!item.lParam || ((CTreeItem*)item.lParam)->pStdCommand->IsSeparator() || (m_DropTarget==m_DragItem && !m_pStdDragItem))
|
|
m_DropTarget=NULL;
|
|
else
|
|
m_DropLocation=DROP_INSIDE;
|
|
}
|
|
}
|
|
}
|
|
// display drop location
|
|
if (!m_DropTarget)
|
|
{
|
|
TreeView_SelectDropTarget(m_hWnd,NULL);
|
|
TreeView_SetInsertMark(m_hWnd,NULL,FALSE);
|
|
if (m_DropLocation==DROP_LAST)
|
|
{
|
|
m_DragMode=DRAG_COPY;
|
|
SetCursor(m_CursorCopy);
|
|
}
|
|
else
|
|
{
|
|
if (m_pStdDragItem)
|
|
bDelete=false;
|
|
m_DragMode=bDelete?DRAG_DELETE:DRAG_ERROR;
|
|
SetCursor(bDelete?m_CursorDel:m_CursorError);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_DragMode=(m_pStdDragItem || GetKeyState(VK_CONTROL)<0)?DRAG_COPY:DRAG_MOVE;
|
|
SetCursor(m_DragMode==DRAG_COPY?m_CursorCopy:m_CursorMove);
|
|
if (m_DropLocation==DROP_INSIDE)
|
|
{
|
|
TreeView_SelectDropTarget(m_hWnd,m_DropTarget);
|
|
TreeView_SetInsertMark(m_hWnd,NULL,FALSE);
|
|
}
|
|
else
|
|
{
|
|
TreeView_SelectDropTarget(m_hWnd,NULL);
|
|
TreeView_SetInsertMark(m_hWnd,m_DropTarget,m_DropLocation==DROP_AFTER);
|
|
}
|
|
}
|
|
|
|
if (m_DropLocation==DROP_INSIDE)
|
|
{
|
|
if (m_HoverItem!=m_DropTarget)
|
|
{
|
|
SetTimer(TIMER_HOVER,400);
|
|
m_HoverItem=m_DropTarget;
|
|
}
|
|
}
|
|
else if (m_HoverItem)
|
|
{
|
|
m_HoverItem=NULL;
|
|
KillTimer(TIMER_HOVER);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool CSettingsTree::FindItemByName( HTREEITEM hParent, const wchar_t *name, HTREEITEM hExclude )
|
|
{
|
|
for (HTREEITEM hItem=hParent?TreeView_GetChild(m_hWnd,hParent):TreeView_GetRoot(m_hWnd);hItem;hItem=TreeView_GetNextSibling(m_hWnd,hItem))
|
|
{
|
|
if (FindItemByName(hItem,name,hExclude))
|
|
return true;
|
|
if (hItem!=hExclude)
|
|
{
|
|
TVITEM item={TVIF_PARAM,hItem};
|
|
TreeView_GetItem(m_hWnd,&item);
|
|
if (item.lParam && _wcsicmp(((CTreeItem*)item.lParam)->name,name)==0)
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
CString CSettingsTree::CreateUniqueName( CString oldName )
|
|
{
|
|
if (!FindItemByName(NULL,oldName,NULL))
|
|
return oldName;
|
|
wchar_t name[256];
|
|
Strcpy(name,_countof(name)-3,oldName);
|
|
// find numeric part
|
|
int pos=Strlen(name);
|
|
while (pos>0 && name[pos-1]>='0' && name[pos-1]<='9')
|
|
pos--;
|
|
for (int i=2;;i++)
|
|
{
|
|
Sprintf(name+pos,_countof(name)-pos,L"%d",i);
|
|
if (!FindItemByName(NULL,name,NULL))
|
|
break;
|
|
}
|
|
return name;
|
|
}
|
|
|
|
HTREEITEM CSettingsTree::CreateDeepCopy( HTREEITEM hSource, HTREEITEM hParent, HTREEITEM hAfter, bool bRename )
|
|
{
|
|
TVINSERTSTRUCT insert={hParent,hAfter?hAfter:TVI_FIRST,{TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_STATE,hSource,0,TVIS_EXPANDED}};
|
|
TreeView_GetItem(m_hWnd,&insert.item);
|
|
CTreeItem *pSource=(CTreeItem*)insert.item.lParam;
|
|
if (!pSource) return NULL;
|
|
CTreeItem *pNewItem=new CTreeItem(*pSource);
|
|
if (bRename && !pNewItem->pStdCommand->IsSeparator())
|
|
{
|
|
pNewItem->name=CreateUniqueName(pNewItem->name);
|
|
}
|
|
insert.item.lParam=(LPARAM)pNewItem;
|
|
insert.item.mask|=TVIF_TEXT;
|
|
CString dispName=pNewItem->GetDisplayName(false);
|
|
insert.item.pszText=(LPWSTR)(LPCWSTR)dispName;
|
|
HTREEITEM hResult=TreeView_InsertItem(m_hWnd,&insert);
|
|
for (HTREEITEM hChild=TreeView_GetChild(m_hWnd,hSource);hChild;hChild=TreeView_GetNextSibling(m_hWnd,hChild))
|
|
CreateDeepCopy(hChild,hResult,TVI_LAST,bRename);
|
|
return hResult;
|
|
}
|
|
|
|
HTREEITEM CSettingsTree::CreateStdItem( const CStdCommand *pCommand, HTREEITEM hParent, HTREEITEM hAfter )
|
|
{
|
|
TVINSERTSTRUCT insert={hParent,hAfter?hAfter:TVI_FIRST,{TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT,NULL,TVIS_EXPANDED,TVIS_EXPANDED}};
|
|
CTreeItem *pNewItem=new CTreeItem;
|
|
pNewItem->label=pCommand->label;
|
|
pNewItem->tip=pCommand->tip;
|
|
pNewItem->icon=pCommand->icon;
|
|
pNewItem->iconD=pCommand->iconD;
|
|
pNewItem->pStdCommand=pCommand;
|
|
pNewItem->settings=pCommand->settings&~m_StyleMask;
|
|
|
|
if (pCommand->IsSeparator())
|
|
{
|
|
pNewItem->name=pCommand->name;
|
|
}
|
|
else
|
|
{
|
|
pNewItem->command=pCommand->name;
|
|
pNewItem->name=CreateUniqueName(pCommand->itemName);
|
|
insert.item.iImage=insert.item.iSelectedImage=UpdateItem(pNewItem,NULL);
|
|
}
|
|
|
|
insert.item.lParam=(LPARAM)pNewItem;
|
|
CString dispName=pNewItem->GetDisplayName(false);
|
|
insert.item.pszText=(LPWSTR)(LPCWSTR)dispName;
|
|
return TreeView_InsertItem(m_hWnd,&insert);
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnRButtonDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
// ignore right-click during dragging
|
|
if (m_DragMode==DRAG_NONE)
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnLButtonUp( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_DragMode!=DRAG_NONE)
|
|
{
|
|
TDragMode mode=m_DragMode;
|
|
HTREEITEM dragItem=m_DragItem;
|
|
if (m_DropSubmenu==m_DropTarget && mode>=DRAG_MOVE)
|
|
m_DropSubmenu=NULL;
|
|
m_DragItem=NULL;
|
|
ReleaseCapture();
|
|
// perform drop operation
|
|
if (mode==DRAG_DELETE)
|
|
{
|
|
TreeView_EnsureVisible(m_hWnd,dragItem);
|
|
if (!m_pStdDragItem)
|
|
{
|
|
TreeView_DeleteItem(m_hWnd,dragItem);
|
|
m_pOwner->SerializeData();
|
|
}
|
|
}
|
|
else if (mode>=DRAG_MOVE)
|
|
{
|
|
HTREEITEM hParent=m_DropTarget;
|
|
HTREEITEM hAfter=TVI_LAST;
|
|
if (m_DropLocation==DROP_AFTER)
|
|
{
|
|
hAfter=hParent;
|
|
hParent=TreeView_GetParent(m_hWnd,hParent);
|
|
}
|
|
else if (m_DropLocation==DROP_BEFORE)
|
|
{
|
|
hAfter=TreeView_GetPrevSibling(m_hWnd,hParent);
|
|
if (!hAfter) hAfter=TVI_FIRST;
|
|
hParent=TreeView_GetParent(m_hWnd,hParent);
|
|
}
|
|
if (hParent)
|
|
{
|
|
HTREEITEM hChild=TreeView_GetChild(m_hWnd,hParent);
|
|
if (hChild)
|
|
{
|
|
TVITEM item={TVIF_PARAM,hChild};
|
|
TreeView_GetItem(m_hWnd,&item);
|
|
if (!item.lParam)
|
|
{
|
|
TreeView_DeleteItem(m_hWnd,hChild);
|
|
hAfter=TVI_LAST;
|
|
}
|
|
}
|
|
}
|
|
|
|
HTREEITEM hNewItem;
|
|
if (m_pStdDragItem)
|
|
{
|
|
hNewItem=CreateStdItem(m_pStdDragItem,hParent,hAfter);
|
|
}
|
|
else
|
|
{
|
|
hNewItem=CreateDeepCopy(dragItem,hParent,hAfter,mode==DRAG_COPY);
|
|
if (mode==DRAG_MOVE)
|
|
TreeView_DeleteItem(m_hWnd,dragItem);
|
|
}
|
|
|
|
TreeView_SelectItem(m_hWnd,hNewItem);
|
|
TreeView_EnsureVisible(m_hWnd,hNewItem);
|
|
m_pOwner->SerializeData();
|
|
}
|
|
}
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnKeyUp( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_DragMode>=DRAG_MOVE)
|
|
{
|
|
m_DragMode=(m_pStdDragItem || GetKeyState(VK_CONTROL)<0)?DRAG_COPY:DRAG_MOVE;
|
|
SetCursor(m_DragMode==DRAG_COPY?m_CursorCopy:m_CursorMove);
|
|
}
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnGetDlgCode( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_DragMode!=DRAG_NONE || (lParam && ((MSG*)lParam)->message==WM_KEYDOWN && ((MSG*)lParam)->wParam==VK_RETURN))
|
|
return DLGC_WANTALLKEYS;
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnChar( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (wParam==VK_RETURN)
|
|
return 0;
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnCaptureChanged( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (m_DragMode!=DRAG_NONE)
|
|
{
|
|
m_DragMode=DRAG_NONE;
|
|
TreeView_SelectDropTarget(m_hWnd,NULL);
|
|
TreeView_SetInsertMark(m_hWnd,NULL,FALSE);
|
|
SetCursor(LoadCursor(NULL,IDC_ARROW));
|
|
if (m_DragItem) TreeView_SelectItem(m_hWnd,m_DragItem);
|
|
KillTimer(TIMER_SCROLL);
|
|
KillTimer(TIMER_HOVER);
|
|
if (m_DropSubmenu)
|
|
TreeView_DeleteItem(m_hWnd,m_DropSubmenu);
|
|
m_DropSubmenu=NULL;
|
|
m_HoverItem=NULL;
|
|
}
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (wParam==TIMER_SCROLL)
|
|
{
|
|
if (m_Scroll>0)
|
|
SendMessage(WM_VSCROLL,SB_LINEDOWN);
|
|
else
|
|
SendMessage(WM_VSCROLL,SB_LINEUP);
|
|
}
|
|
else if (wParam==TIMER_HOVER)
|
|
{
|
|
if (m_HoverItem)
|
|
{
|
|
TreeView_Expand(m_hWnd,m_HoverItem,TVE_EXPAND);
|
|
if (!TreeView_GetChild(m_hWnd,m_HoverItem))
|
|
{
|
|
if (m_DropSubmenu)
|
|
TreeView_DeleteItem(m_hWnd,m_DropSubmenu);
|
|
TVINSERTSTRUCT insert={m_HoverItem,TVI_FIRST,{TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT,NULL,TVIS_EXPANDED,TVIS_EXPANDED}};
|
|
CString text=LoadStringEx(IDS_EMPTY_MENU);
|
|
insert.item.pszText=(LPWSTR)(LPCWSTR)text;
|
|
m_DropSubmenu=TreeView_InsertItem(m_hWnd,&insert);
|
|
TreeView_SelectItem(m_hWnd,m_DropSubmenu);
|
|
TreeView_EnsureVisible(m_hWnd,m_DropSubmenu);
|
|
}
|
|
}
|
|
KillTimer(TIMER_HOVER);
|
|
}
|
|
else
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnBeginLabelEdit( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
if (m_bDisabled) return TRUE;
|
|
CWindow edit=TreeView_GetEditControl(m_hWnd);
|
|
SetWindowSubclass(edit,SubclassEditboxProc,'CLSH',0);
|
|
NMTVDISPINFO *pInfo=(NMTVDISPINFO*)pnmh;
|
|
if (!pInfo->item.lParam)
|
|
return TRUE;
|
|
CTreeItem *pItem=(CTreeItem*)pInfo->item.lParam;
|
|
if (!pItem->pStdCommand->IsCustom())
|
|
return TRUE;
|
|
edit.SetWindowText(pItem->label);
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnEndLabelEdit( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
NMTVDISPINFO *pInfo=(NMTVDISPINFO*)pnmh;
|
|
if (pInfo->item.pszText)
|
|
{
|
|
CTreeItem *pItem=(CTreeItem*)pInfo->item.lParam;
|
|
pItem->label=pInfo->item.pszText;
|
|
m_pOwner->SerializeData();
|
|
UpdateItem(pItem,pInfo->item.hItem);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT CSettingsTree::OnKeyDown( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
NMTVKEYDOWN *pKey=(NMTVKEYDOWN*)pnmh;
|
|
if (m_DragMode!=DRAG_NONE)
|
|
{
|
|
if (pKey->wVKey==VK_ESCAPE)
|
|
{
|
|
ReleaseCapture();
|
|
return TRUE;
|
|
}
|
|
if (m_DragMode>=DRAG_MOVE)
|
|
{
|
|
m_DragMode=(m_pStdDragItem || GetKeyState(VK_CONTROL)<0)?DRAG_COPY:DRAG_MOVE;
|
|
SetCursor(m_DragMode==DRAG_COPY?m_CursorCopy:m_CursorMove);
|
|
}
|
|
}
|
|
// F2 to rename
|
|
if (pKey->wVKey==VK_F2)
|
|
{
|
|
HTREEITEM hSelected=TreeView_GetSelection(m_hWnd);
|
|
if (hSelected)
|
|
TreeView_EditLabel(m_hWnd,hSelected);
|
|
}
|
|
// Del to delete
|
|
if (pKey->wVKey==VK_DELETE)
|
|
{
|
|
HTREEITEM hSelected=TreeView_GetSelection(m_hWnd);
|
|
if (hSelected)
|
|
DeleteItem(hSelected);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CSettingsTree::DeleteItem( HTREEITEM hItem )
|
|
{
|
|
if (!m_bDisabled)
|
|
{
|
|
TreeView_DeleteItem(m_hWnd,hItem);
|
|
m_pOwner->SerializeData();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CCommandsTree: public CWindowImpl<CCommandsTree, CWindow>
|
|
{
|
|
public:
|
|
BEGIN_MSG_MAP( CCommandsTree )
|
|
MESSAGE_HANDLER( WM_GETDLGCODE, OnGetDlgCode )
|
|
MESSAGE_HANDLER( WM_CHAR, OnChar )
|
|
END_MSG_MAP()
|
|
|
|
protected:
|
|
LRESULT OnGetDlgCode( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnChar( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
};
|
|
|
|
LRESULT CCommandsTree::OnGetDlgCode( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (lParam && ((MSG*)lParam)->message==WM_KEYDOWN && ((MSG*)lParam)->wParam==VK_RETURN)
|
|
return DLGC_WANTALLKEYS;
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CCommandsTree::OnChar( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (wParam==VK_RETURN)
|
|
return 0;
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
CEditCustomItemDlg::~CEditCustomItemDlg( void )
|
|
{
|
|
if (m_hIcon) DestroyIcon(m_hIcon);
|
|
if (m_hIconD) DestroyIcon(m_hIconD);
|
|
}
|
|
|
|
void CEditCustomItemDlg::InitDialog( CWindow commandCombo, const CStdCommand *pStdcommands, int style, int mask, CWindow linkCombo, const KNOWNFOLDERID *const *pCommonLinks )
|
|
{
|
|
InitResize(MOVE_HORIZONTAL|MOVE_GRIPPER);
|
|
CString str;
|
|
GetWindowText(str);
|
|
CString title;
|
|
title.Format(str,m_pItem->GetDisplayName(true));
|
|
SetWindowText(title);
|
|
|
|
for (int i=0;pStdcommands[i].name;i++)
|
|
if (pStdcommands[i].IsStyle(style,mask) && !pStdcommands[i].IsSeparator() && !pStdcommands[i].IsCustom())
|
|
commandCombo.SendMessage(CB_ADDSTRING,0,(LPARAM)pStdcommands[i].name);
|
|
|
|
commandCombo.SetWindowText(m_pItem->command);
|
|
int idx=(int)commandCombo.SendMessage(CB_FINDSTRINGEXACT,-1,(LPARAM)(const wchar_t*)m_pItem->command);
|
|
if (idx>=0)
|
|
commandCombo.SendMessage(CB_SETCURSEL,idx);
|
|
|
|
for (int i=0;pCommonLinks[i];i++)
|
|
{
|
|
if (*pCommonLinks[i]==FOLDERID_DesktopRoot)
|
|
{
|
|
linkCombo.SendMessage(CB_ADDSTRING,0,(LPARAM)L"Main Desktop | ::{Desktop}");
|
|
}
|
|
else
|
|
{
|
|
CAbsolutePidl path;
|
|
if (FAILED(SHGetKnownFolderIDList(*pCommonLinks[i],0,NULL,&path)) || !path) continue;
|
|
CComString pName;
|
|
if (SUCCEEDED(SHGetNameFromIDList(path,SIGDN_NORMALDISPLAY,&pName)))
|
|
{
|
|
CComString pPath;
|
|
if (SUCCEEDED(SHGetNameFromIDList(path,SIGDN_DESKTOPABSOLUTEPARSING,&pPath)))
|
|
{
|
|
wchar_t text[_MAX_PATH*2];
|
|
int len=Sprintf(text,_countof(text),L"%s | ",(const wchar_t*)pName);
|
|
if (!PathUnExpandEnvStrings(pPath,text+len,_countof(text)-len))
|
|
Strcpy(text+len,_countof(text)-len,pPath);
|
|
linkCombo.SendMessage(CB_ADDSTRING,0,(LPARAM)text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
linkCombo.SetWindowText(m_pItem->link);
|
|
idx=(int)linkCombo.SendMessage(CB_FINDSTRINGEXACT,-1,(LPARAM)(const wchar_t*)m_pItem->link);
|
|
if (idx>=0)
|
|
linkCombo.SendMessage(CB_SETCURSEL,idx);
|
|
|
|
m_hIcon=NULL;
|
|
m_IconKey=0;
|
|
m_hIconD=NULL;
|
|
m_IconDKey=0;
|
|
m_StoredItem=*m_pItem;
|
|
|
|
RECT rc;
|
|
CRegKey regSettings;
|
|
if (regSettings.Open(HKEY_CURRENT_USER,GetSettingsRegPath())==ERROR_SUCCESS)
|
|
{
|
|
ULONG size=sizeof(rc);
|
|
if (regSettings.QueryBinaryValue(L"CEditCustomItemDlg",&rc,&size)==ERROR_SUCCESS && size==sizeof(rc))
|
|
SetStoreRect(rc);
|
|
}
|
|
|
|
COMBOBOXINFO info={sizeof(info)};
|
|
commandCombo.SendMessage(CB_GETCOMBOBOXINFO,0,(LPARAM)&info);
|
|
SHAutoComplete(info.hwndItem,SHACF_FILESYSTEM);
|
|
linkCombo.SendMessage(CB_GETCOMBOBOXINFO,0,(LPARAM)&info);
|
|
SHAutoComplete(info.hwndItem,SHACF_FILESYSTEM);
|
|
}
|
|
|
|
LRESULT CEditCustomItemDlg::OnSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
CResizeableDlg<CEditCustomItemDlg>::OnSize();
|
|
return 0;
|
|
}
|
|
|
|
void CEditCustomItemDlg::StorePlacement( void )
|
|
{
|
|
RECT rc;
|
|
GetStoreRect(rc);
|
|
|
|
CRegKey regSettings;
|
|
if (regSettings.Open(HKEY_CURRENT_USER,GetSettingsRegPath())!=ERROR_SUCCESS)
|
|
regSettings.Create(HKEY_CURRENT_USER,GetSettingsRegPath());
|
|
regSettings.SetBinaryValue(L"CEditCustomItemDlg",&rc,sizeof(rc));
|
|
}
|
|
|
|
LRESULT CEditCustomItemDlg::OnOK( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
::EnableWindow(m_EnableParent,TRUE);
|
|
m_bResult=true;
|
|
StorePlacement();
|
|
DestroyWindow();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CEditCustomItemDlg::OnCancel( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
::EnableWindow(m_EnableParent,TRUE);
|
|
m_bResult=false;
|
|
StorePlacement();
|
|
DestroyWindow();
|
|
(*m_pItem)=m_StoredItem;
|
|
return 0;
|
|
}
|
|
|
|
void CEditCustomItemDlg::UpdateIcons( int iconID, int iconDID )
|
|
{
|
|
unsigned int key=m_pItem->GetIconKey();
|
|
|
|
if (key!=m_IconKey)
|
|
{
|
|
m_IconKey=key;
|
|
if (m_hIcon) DestroyIcon(m_hIcon);
|
|
m_hIcon=m_pItem->LoadIcon(false,m_Modules);
|
|
SendDlgItemMessage(iconID,STM_SETICON,(WPARAM)m_hIcon);
|
|
}
|
|
|
|
if (iconDID)
|
|
{
|
|
key=m_pItem->GetIconDKey(key);
|
|
if (key!=m_IconDKey)
|
|
{
|
|
m_IconDKey=key;
|
|
if (m_hIconD) DestroyIcon(m_hIconD);
|
|
m_hIconD=m_pItem->LoadIconD(m_hIcon,m_Modules);
|
|
SendDlgItemMessage(iconDID,STM_SETICON,(WPARAM)m_hIconD);
|
|
}
|
|
}
|
|
}
|
|
|
|
CString CEditCustomItemDlg::GetComboText( WORD wNotifyCode, WORD wID )
|
|
{
|
|
CString text;
|
|
if (wNotifyCode==CBN_SELENDOK)
|
|
{
|
|
int idx=(int)SendDlgItemMessage(wID,CB_GETCURSEL);
|
|
text.Empty();
|
|
if (idx>=0)
|
|
{
|
|
int len=(int)SendDlgItemMessage(wID,CB_GETLBTEXTLEN,idx);
|
|
SendDlgItemMessage(wID,CB_GETLBTEXT,idx,(LPARAM)text.GetBuffer(len+1));
|
|
text.ReleaseBuffer(len);
|
|
}
|
|
}
|
|
else
|
|
GetDlgItemText(wID,text);
|
|
text.TrimLeft();
|
|
text.TrimRight();
|
|
return text;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CBrowseLinkEvents: public IFileDialogEvents, public IFileDialogControlEvents
|
|
{
|
|
public:
|
|
CBrowseLinkEvents( void ) { m_pResult=NULL; }
|
|
|
|
// IUnknown
|
|
virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void **ppvObject );
|
|
virtual ULONG STDMETHODCALLTYPE AddRef( void ) { return 1; }
|
|
virtual ULONG STDMETHODCALLTYPE Release( void ) { return 1; }
|
|
|
|
// IFileDialogEvents
|
|
STDMETHOD(OnFileOk)( IFileDialog *pfd ) { return S_OK; }
|
|
STDMETHOD(OnFolderChanging)( IFileDialog *pfd, IShellItem *psiFolder ) { return S_OK; }
|
|
STDMETHOD(OnFolderChange)( IFileDialog *pfd ) { return S_OK; }
|
|
STDMETHOD(OnSelectionChange)( IFileDialog *pfd ) { return S_OK; }
|
|
STDMETHOD(OnShareViolation)( IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse ) { return S_OK; }
|
|
STDMETHOD(OnTypeChange)( IFileDialog *pfd ) { return S_OK; }
|
|
STDMETHOD(OnOverwrite)( IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse ) { return S_OK; }
|
|
|
|
// IFileDialogControlEvents
|
|
STDMETHOD(OnItemSelected)( IFileDialogCustomize *pfdc, DWORD dwIDCtl, DWORD dwIDItem ) { return S_OK; }
|
|
STDMETHOD(OnButtonClicked)( IFileDialogCustomize *pfdc, DWORD dwIDCtl );
|
|
STDMETHOD(OnCheckButtonToggled)( IFileDialogCustomize *pfdc, DWORD dwIDCtl, BOOL bChecked ) { return S_OK; }
|
|
STDMETHOD(OnControlActivating)( IFileDialogCustomize *pfdc, DWORD dwIDCtl ) { return S_OK; }
|
|
|
|
CComPtr<IShellItem> m_pResult;
|
|
};
|
|
|
|
HRESULT STDMETHODCALLTYPE CBrowseLinkEvents::QueryInterface( REFIID riid, void **ppvObject )
|
|
{
|
|
if (riid==IID_IUnknown)
|
|
{
|
|
*ppvObject=(IUnknown*)(IFileDialogEvents*)this;
|
|
return S_OK;
|
|
}
|
|
if (riid==IID_IFileDialogEvents)
|
|
{
|
|
*ppvObject=(IFileDialogEvents*)this;
|
|
return S_OK;
|
|
}
|
|
if (riid==IID_IFileDialogControlEvents)
|
|
{
|
|
*ppvObject=(IFileDialogControlEvents*)this;
|
|
return S_OK;
|
|
}
|
|
*ppvObject=NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CBrowseLinkEvents::OnButtonClicked( IFileDialogCustomize *pfdc, DWORD dwIDCtl )
|
|
{
|
|
CComQIPtr<IFileDialog> pfd=pfdc;
|
|
if (!pfd) return E_INVALIDARG;
|
|
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(pfd->GetCurrentSelection(&pItem)))
|
|
{
|
|
SFGAOF attr;
|
|
if (SUCCEEDED(pItem->GetAttributes(SFGAO_FOLDER|SFGAO_STREAM,&attr)) && (attr&(SFGAO_FOLDER|SFGAO_STREAM))!=SFGAO_FOLDER)
|
|
pItem=NULL;
|
|
}
|
|
if (!pItem)
|
|
{
|
|
pfd->GetFolder(&pItem);
|
|
}
|
|
m_pResult=std::move(pItem);
|
|
pfd->Close(S_FALSE);
|
|
return S_OK;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool BrowseCommandHelper( HWND parent, wchar_t *text )
|
|
{
|
|
if (text[0]=='"')
|
|
{
|
|
// remove quotes
|
|
int len=Strlen(text);
|
|
if (len>1 && text[len-1]=='"')
|
|
{
|
|
len-=2;
|
|
memmove(text,text+1,len*2);
|
|
text[len]=0;
|
|
}
|
|
}
|
|
OPENFILENAME ofn={sizeof(ofn)};
|
|
ofn.hwndOwner=parent;
|
|
wchar_t filters[256];
|
|
Strcpy(filters,_countof(filters),LoadStringEx(IDS_COMMAND_FILTERS));
|
|
for (wchar_t *c=filters;*c;c++)
|
|
if (*c=='|') *c=0;
|
|
ofn.lpstrFilter=filters;
|
|
ofn.nFilterIndex=1;
|
|
DoEnvironmentSubst(text,_MAX_PATH);
|
|
wchar_t dir[_MAX_PATH];
|
|
Strcpy(dir,_countof(dir),text);
|
|
PathRemoveFileSpec(dir);
|
|
ofn.lpstrInitialDir=dir;
|
|
text[0]=0;
|
|
ofn.lpstrFile=text;
|
|
ofn.nMaxFile=_MAX_PATH;
|
|
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR|OFN_NODEREFERENCELINKS;
|
|
if (GetOpenFileName(&ofn))
|
|
{
|
|
wchar_t buf[_MAX_PATH];
|
|
UnExpandEnvStrings(text,buf,_countof(buf));
|
|
// add quotes if needed
|
|
if (wcschr(buf,' '))
|
|
{
|
|
int len=Strlen(buf);
|
|
if (len<_MAX_PATH-3)
|
|
{
|
|
memcpy(text+1,buf,len*2);
|
|
text[0]='"';
|
|
text[len+1]='"';
|
|
text[len+2]=0;
|
|
}
|
|
}
|
|
else
|
|
Strcpy(text,_MAX_PATH,buf);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool BrowseLinkHelper( HWND parent, wchar_t *text, bool bFoldersOnly )
|
|
{
|
|
DoEnvironmentSubst(text,_MAX_PATH);
|
|
|
|
CComPtr<IFileOpenDialog> pDialog;
|
|
if (FAILED(pDialog.CoCreateInstance(CLSID_FileOpenDialog,NULL,CLSCTX_INPROC_SERVER)))
|
|
return false;
|
|
CComQIPtr<IFileDialogCustomize> pCustomize(pDialog);
|
|
if (!pCustomize)
|
|
return false;
|
|
|
|
pDialog->SetTitle(LoadStringEx(bFoldersOnly?IDS_PICK_LINK_FOLDER:IDS_PICK_LINK_TITLE));
|
|
if (!bFoldersOnly) // add separate buttons for selecting files/folders to the dialog
|
|
{
|
|
pDialog->SetOkButtonLabel(LoadStringEx(IDS_PICK_LINK_FILE));
|
|
wchar_t button[256];
|
|
Sprintf(button,_countof(button),L" %s ",LoadStringEx(IDS_PICK_LINK_FOLDER));
|
|
pCustomize->AddPushButton(101,button);
|
|
}
|
|
|
|
CBrowseLinkEvents events;
|
|
DWORD cookie;
|
|
pDialog->Advise(&events,&cookie);
|
|
if (bFoldersOnly) // set FOS_PICKFOLDERS option to use dialog in folder-only mode
|
|
pDialog->SetOptions(FOS_PICKFOLDERS|FOS_ALLNONSTORAGEITEMS|FOS_DONTADDTORECENT|FOS_DEFAULTNOMINIMODE);
|
|
else
|
|
pDialog->SetOptions(FOS_ALLNONSTORAGEITEMS|FOS_FILEMUSTEXIST|FOS_DONTADDTORECENT|FOS_DEFAULTNOMINIMODE|FOS_NODEREFERENCELINKS);
|
|
{
|
|
const wchar_t *c=wcschr(text,'|');
|
|
if (c)
|
|
{
|
|
for (c++;*c==' ';)
|
|
c++;
|
|
}
|
|
else
|
|
c=text;
|
|
CComPtr<IShellItem> pItem;
|
|
if (SUCCEEDED(SHCreateItemFromParsingName(c,NULL,IID_IShellItem,(void**)&pItem)))
|
|
pDialog->SetFolder(pItem);
|
|
}
|
|
|
|
HRESULT hr=pDialog->Show(parent);
|
|
CComPtr<IShellItem> pResult;
|
|
if (hr==S_OK)
|
|
pDialog->GetResult(&pResult);
|
|
else if (hr==S_FALSE)
|
|
pResult=events.m_pResult;
|
|
|
|
pDialog->Unadvise(cookie);
|
|
|
|
if (pResult)
|
|
{
|
|
CComString pName;
|
|
pResult->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING,&pName);
|
|
UnExpandEnvStrings(pName,text,_MAX_PATH);
|
|
}
|
|
|
|
return pResult!=NULL;
|
|
}
|
|
|
|
bool BrowseIconHelper( HWND parent, wchar_t *text )
|
|
{
|
|
int id=0;
|
|
if (*text)
|
|
{
|
|
wchar_t *c=wcsrchr(text,',');
|
|
if (c)
|
|
{
|
|
*c=0;
|
|
id=_wtol(c+1);
|
|
}
|
|
}
|
|
else
|
|
Strcpy(text,_MAX_PATH,L"shell32.dll");
|
|
if (BrowseForIcon(parent,text,id))
|
|
{
|
|
if (_wcsicmp(PathFindExtension(text),L".ico")==0)
|
|
return true;
|
|
if (id>0)
|
|
{
|
|
wchar_t buf[20];
|
|
Sprintf(buf,_countof(buf),L", %d",id);
|
|
Strcat(text,_MAX_PATH,buf);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CEditCustomItemDlg::Run( HWND parent, int dlgID )
|
|
{
|
|
parent=GetAncestor(parent,GA_ROOT);
|
|
DLGTEMPLATE *pTemplate=LoadDialogEx(dlgID);
|
|
Create(parent,pTemplate);
|
|
ShowWindow(SW_SHOWNORMAL);
|
|
::EnableWindow(parent,FALSE);
|
|
SetEnableParent(parent);
|
|
MSG msg;
|
|
while (m_hWnd && GetMessage(&msg,0,0,0))
|
|
{
|
|
if (IsDialogMessage(&msg)) continue;
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
return GetResult();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Subclass the tooltip to delay the tip when the mouse moves from one tree item to the next
|
|
static LRESULT CALLBACK SubclassInfoTipProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==TTM_UPDATE)
|
|
{
|
|
int time=(int)SendMessage(hWnd,TTM_GETDELAYTIME,TTDT_RESHOW,0);
|
|
SetTimer(hWnd,'CLSH',time,NULL);
|
|
return 0;
|
|
}
|
|
if (uMsg==WM_TIMER && wParam=='CLSH')
|
|
{
|
|
KillTimer(hWnd,wParam);
|
|
DefSubclassProc(hWnd,TTM_UPDATE,0,0);
|
|
return 0;
|
|
}
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
LRESULT CCustomTreeDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
m_pSetting=NULL;
|
|
|
|
InitResize();
|
|
EnableThemeDialogTexture(m_hWnd,ETDT_ENABLETAB);
|
|
m_Tree.SubclassWindow(GetDlgItem(IDC_TREEITEMS),this);
|
|
m_CommandsTree.SubclassWindow(GetDlgItem(IDC_TREECOMMANDS));
|
|
TreeView_SetImageList(m_CommandsTree,TreeView_GetImageList(m_Tree,TVSIL_NORMAL),TVSIL_NORMAL);
|
|
if (IsAppThemed())
|
|
{
|
|
m_Tree.SetWindowLong(GWL_STYLE,m_Tree.GetWindowLong(GWL_STYLE)|TVS_TRACKSELECT);
|
|
SetWindowTheme(m_Tree,L"Explorer",NULL);
|
|
m_CommandsTree.SetWindowLong(GWL_STYLE,m_CommandsTree.GetWindowLong(GWL_STYLE)|TVS_TRACKSELECT);
|
|
SetWindowTheme(m_CommandsTree,L"Explorer",NULL);
|
|
}
|
|
|
|
int height=TreeView_GetItemHeight(m_Tree);
|
|
int minHeight=GetSystemMetrics(SM_CXSMICON)+2;
|
|
if (height<minHeight)
|
|
{
|
|
TreeView_SetItemHeight(m_Tree,minHeight);
|
|
TreeView_SetItemHeight(m_CommandsTree,minHeight);
|
|
}
|
|
|
|
HWND tooltip=TreeView_GetToolTips(m_CommandsTree);
|
|
SendMessage(tooltip,TTM_SETDELAYTIME,TTDT_AUTOPOP,10000);
|
|
SendMessage(tooltip,TTM_SETDELAYTIME,TTDT_INITIAL,1000);
|
|
SendMessage(tooltip,TTM_SETDELAYTIME,TTDT_RESHOW,1000);
|
|
SetWindowSubclass(tooltip,SubclassInfoTipProc,'CLSH',0);
|
|
|
|
tooltip=TreeView_GetToolTips(m_Tree);
|
|
SendMessage(tooltip,TTM_SETDELAYTIME,TTDT_AUTOPOP,10000);
|
|
SendMessage(tooltip,TTM_SETDELAYTIME,TTDT_INITIAL,1000);
|
|
SendMessage(tooltip,TTM_SETDELAYTIME,TTDT_RESHOW,1000);
|
|
SetWindowSubclass(tooltip,SubclassInfoTipProc,'CLSH',0);
|
|
|
|
for (int i=0;m_pStdCommands[i].name;i++)
|
|
{
|
|
const CStdCommand &command=m_pStdCommands[i];
|
|
if (!command.IsStyle(m_Style,m_StyleMask)) continue;
|
|
CString displayName=LoadStringEx(command.displayNameId);
|
|
TVINSERTSTRUCT insert={NULL,TVI_LAST,{TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE,NULL,0,0,(LPWSTR)(LPCWSTR)displayName}};
|
|
insert.item.iImage=insert.item.iSelectedImage=1;
|
|
if (!command.icon)
|
|
insert.item.iImage=insert.item.iSelectedImage=0;
|
|
else
|
|
{
|
|
CTreeItem tItem;
|
|
tItem.icon=command.icon;
|
|
tItem.pStdCommand=&command;
|
|
insert.item.iImage=insert.item.iSelectedImage=m_Tree.LoadIcon(&tItem);
|
|
}
|
|
|
|
insert.item.lParam=(LPARAM)&command;
|
|
TreeView_InsertItem(m_CommandsTree,&insert);
|
|
}
|
|
|
|
CString str=LoadStringEx(m_bMenu?IDS_TREE_MENU:IDS_TREE_TOOLBAR);
|
|
SetDlgItemText(IDC_STATICLEFT,str);
|
|
str=LoadStringEx(m_bMenu?IDS_DRAG_DROP_SM_TIP:IDS_DRAG_DROP_EXP_TIP);
|
|
SetDlgItemText(IDC_STATICHINT,str);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT CCustomTreeDlg::OnSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
CResizeableDlg<CCustomTreeDlg>::OnSize();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CCustomTreeDlg::OnContextMenu( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
CWindow tree=(HWND)wParam;
|
|
if (tree.m_hWnd!=m_Tree.m_hWnd && tree.m_hWnd!=m_CommandsTree.m_hWnd)
|
|
return 0;
|
|
if (m_Tree.IsDragging())
|
|
{
|
|
ReleaseCapture();
|
|
return 0;
|
|
}
|
|
HTREEITEM hItem=NULL;
|
|
POINT pt;
|
|
if ((DWORD)lParam==0xFFFFFFFF)
|
|
{
|
|
// keyboard
|
|
hItem=TreeView_GetSelection(tree);
|
|
if (hItem)
|
|
{
|
|
RECT rc;
|
|
TreeView_GetItemRect(tree,hItem,&rc,TRUE);
|
|
pt.x=(rc.left+rc.right)/2;
|
|
pt.y=(rc.top+rc.bottom)/2;
|
|
}
|
|
else
|
|
pt.x=pt.y=0;
|
|
tree.ClientToScreen(&pt);
|
|
}
|
|
else
|
|
{
|
|
DWORD pos=GetMessagePos();
|
|
pt.x=(short)LOWORD(pos);
|
|
pt.y=(short)HIWORD(pos);
|
|
TVHITTESTINFO test={pt};
|
|
tree.ScreenToClient(&test.pt);
|
|
if (TreeView_HitTest(tree,&test) && (test.flags&(TVHT_ONITEMICON|TVHT_ONITEMLABEL)))
|
|
{
|
|
TreeView_SelectItem(tree,test.hItem);
|
|
hItem=test.hItem;
|
|
}
|
|
}
|
|
|
|
CTreeItem *pItem=NULL;
|
|
if (tree.m_hWnd==m_Tree.m_hWnd)
|
|
{
|
|
if (hItem)
|
|
{
|
|
TVITEM item={TVIF_PARAM,hItem};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
pItem=(CTreeItem*)item.lParam;
|
|
}
|
|
}
|
|
else if (!hItem)
|
|
return 0;
|
|
|
|
enum {
|
|
CMD_EDIT=1,
|
|
CMD_RENAME,
|
|
CMD_DELETE,
|
|
CMD_RESETALL,
|
|
CMD_ADD,
|
|
CMD_ADD_MENU,
|
|
};
|
|
|
|
HMENU menu=CreatePopupMenu();
|
|
wchar_t text[256];
|
|
if (tree.m_hWnd==m_Tree.m_hWnd)
|
|
{
|
|
if (pItem)
|
|
{
|
|
if (!pItem->pStdCommand->IsSeparator())
|
|
{
|
|
Sprintf(text,_countof(text),L"%s\tEnter",LoadStringEx(IDS_MENU_EDIT));
|
|
AppendMenu(menu,MF_STRING,CMD_EDIT,text);
|
|
SetMenuDefaultItem(menu,CMD_EDIT,FALSE);
|
|
Sprintf(text,_countof(text),L"%s\tF2",LoadStringEx(IDS_MENU_RENAME));
|
|
AppendMenu(menu,MF_STRING,CMD_RENAME,text);
|
|
if (m_pSetting->IsLocked())
|
|
{
|
|
EnableMenuItem(menu,CMD_EDIT,MF_BYCOMMAND|MF_GRAYED);
|
|
EnableMenuItem(menu,CMD_RENAME,MF_BYCOMMAND|MF_GRAYED);
|
|
}
|
|
else if (!pItem->pStdCommand->IsCustom())
|
|
EnableMenuItem(menu,CMD_RENAME,MF_BYCOMMAND|MF_GRAYED);
|
|
if (!TreeView_GetChild(m_Tree,hItem))
|
|
AppendMenu(menu,MF_STRING,CMD_ADD_MENU,LoadStringEx(IDS_INSERT_MENU));
|
|
if (m_pSetting->IsLocked())
|
|
EnableMenuItem(menu,CMD_ADD_MENU,MF_BYCOMMAND|MF_GRAYED);
|
|
}
|
|
Sprintf(text,_countof(text),L"%s\tDel",LoadStringEx(IDS_MENU_DELETE));
|
|
AppendMenu(menu,MF_STRING,CMD_DELETE,text);
|
|
if (m_pSetting->IsLocked())
|
|
EnableMenuItem(menu,CMD_DELETE,MF_BYCOMMAND|MF_GRAYED);
|
|
}
|
|
if (!m_pSetting->IsLocked())
|
|
AppendMenu(menu,MF_STRING,CMD_RESETALL,LoadStringEx(m_bMenu?IDS_RESET_MENU:IDS_RESET_TOOLBAR));
|
|
}
|
|
else
|
|
{
|
|
Sprintf(text,_countof(text),L"%s\tEnter",LoadStringEx(m_bMenu?IDS_ADD_MENU:IDS_ADD_TOOLBAR));
|
|
AppendMenu(menu,MF_STRING,CMD_ADD,text);
|
|
SetMenuDefaultItem(menu,CMD_ADD,FALSE);
|
|
if (m_pSetting->IsLocked())
|
|
EnableMenuItem(menu,CMD_ADD,MF_BYCOMMAND|MF_GRAYED);
|
|
}
|
|
|
|
int res=TrackPopupMenu(menu,TPM_RIGHTBUTTON|TPM_RETURNCMD,pt.x,pt.y,0,m_hWnd,NULL);
|
|
DestroyMenu(menu);
|
|
if (res==CMD_EDIT)
|
|
EditItemInternal(pItem,hItem);
|
|
if (res==CMD_DELETE)
|
|
m_Tree.DeleteItem(hItem);
|
|
if (res==CMD_RENAME)
|
|
TreeView_EditLabel(m_Tree,hItem);
|
|
if (res==CMD_RESETALL)
|
|
{
|
|
if (::MessageBox(m_hWnd,LoadStringEx(m_bMenu?IDS_RESET_MENU_WARN:IDS_RESET_TOOLBAR_WARN),LoadStringEx(m_bMenu?IDS_RESET_MENU:IDS_RESET_TOOLBAR),MB_YESNO|MB_ICONWARNING)==IDYES)
|
|
{
|
|
{
|
|
CSettingsLockWrite lock;
|
|
m_pSetting->value=m_pSetting->defValue;
|
|
m_pSetting->flags|=CSetting::FLAG_DEFAULT;
|
|
ItemsChanged();
|
|
SetSettingsDirty();
|
|
}
|
|
SetGroup(m_pSetting-1,true);
|
|
}
|
|
}
|
|
if (res==CMD_ADD)
|
|
{
|
|
AddItem(hItem);
|
|
}
|
|
if (res==CMD_ADD_MENU)
|
|
{
|
|
TVINSERTSTRUCT insert={hItem,TVI_FIRST,{TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT,NULL,TVIS_EXPANDED,TVIS_EXPANDED}};
|
|
CString text=LoadStringEx(IDS_EMPTY_MENU);
|
|
insert.item.pszText=(LPWSTR)(LPCWSTR)text;
|
|
HTREEITEM hNew=TreeView_InsertItem(m_Tree,&insert);
|
|
TreeView_SelectItem(m_Tree,hNew);
|
|
TreeView_EnsureVisible(m_Tree,hNew);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const CStdCommand *CCustomTreeDlg::FindStdCommand( const wchar_t *name )
|
|
{
|
|
for (int i=0;m_pStdCommands[i].name;i++)
|
|
if (m_pStdCommands[i].IsStyle(m_Style,m_StyleMask) && _wcsicmp(m_pStdCommands[i].name,name)==0)
|
|
return &m_pStdCommands[i];
|
|
return NULL;
|
|
}
|
|
|
|
LRESULT CCustomTreeDlg::OnGetInfoTip( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
NMTVGETINFOTIP *pTip=(NMTVGETINFOTIP*)pnmh;
|
|
const CStdCommand *pCommand=NULL;
|
|
if (idCtrl==IDC_TREECOMMANDS)
|
|
pCommand=(CStdCommand*)pTip->lParam;
|
|
else if (!m_pSetting->IsLockedReg())
|
|
{
|
|
CTreeItem *pItem=(CTreeItem*)pTip->lParam;
|
|
if (pItem)
|
|
pCommand=pItem->pStdCommand;
|
|
}
|
|
if (pCommand)
|
|
{
|
|
if (idCtrl==IDC_TREECOMMANDS)
|
|
Sprintf(pTip->pszText,pTip->cchTextMax,L"%s\n%s",LoadStringEx(pCommand->tipID),LoadStringEx(m_bMenu?IDS_COMMAND_SM_TIP:IDS_COMMAND_EXP_TIP));
|
|
else
|
|
Strcpy(pTip->pszText,pTip->cchTextMax,LoadStringEx(pCommand->tipID));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CCustomTreeDlg::OnBeginDrag( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
NMTREEVIEW *pDrag=(NMTREEVIEW*)pnmh;
|
|
m_Tree.BeginDrag((CStdCommand*)pDrag->itemNew.lParam);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CCustomTreeDlg::OnAddItem( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
if (pnmh->code==TVN_KEYDOWN)
|
|
{
|
|
NMTVKEYDOWN *pKey=(NMTVKEYDOWN*)pnmh;
|
|
if (pKey->wVKey!=VK_RETURN)
|
|
{
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
HTREEITEM hItem=TreeView_GetSelection(m_CommandsTree);
|
|
if (hItem)
|
|
AddItem(hItem);
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT CCustomTreeDlg::OnEditItem( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
if (pnmh->code==TVN_KEYDOWN)
|
|
{
|
|
NMTVKEYDOWN *pKey=(NMTVKEYDOWN*)pnmh;
|
|
if (pKey->wVKey!=VK_RETURN)
|
|
{
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
TVITEM item={TVIF_PARAM,TreeView_GetSelection(m_Tree)};
|
|
if (!item.hItem) return 0;
|
|
TreeView_GetItem(m_Tree,&item);
|
|
CTreeItem *pItem=(CTreeItem*)item.lParam;
|
|
if (pItem)
|
|
EditItemInternal(pItem,item.hItem);
|
|
return TRUE;
|
|
}
|
|
|
|
void CCustomTreeDlg::AddItem( HTREEITEM hCommand )
|
|
{
|
|
if (m_pSetting->IsLocked()) return;
|
|
TVITEM item={TVIF_PARAM,hCommand};
|
|
TreeView_GetItem(m_CommandsTree,&item);
|
|
const CStdCommand *pCommand=(CStdCommand*)item.lParam;
|
|
HTREEITEM hAfter=TreeView_GetSelection(m_Tree);
|
|
HTREEITEM hParent=NULL;
|
|
if (hAfter)
|
|
{
|
|
hParent=TreeView_GetParent(m_Tree,hAfter);
|
|
TVITEM item={TVIF_PARAM,hAfter};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
if (!item.lParam)
|
|
{
|
|
TreeView_DeleteItem(m_Tree,hAfter);
|
|
hAfter=TVI_LAST;
|
|
}
|
|
}
|
|
else
|
|
hAfter=TVI_LAST;
|
|
HTREEITEM hItem=m_Tree.CreateStdItem(pCommand,hParent,hAfter);
|
|
TreeView_SelectItem(m_Tree,hItem);
|
|
TreeView_EnsureVisible(m_Tree,hItem);
|
|
SerializeData();
|
|
}
|
|
|
|
HTREEITEM CCustomTreeDlg::GetRoot( void )
|
|
{
|
|
return TreeView_GetRoot(m_Tree);
|
|
}
|
|
|
|
HTREEITEM CCustomTreeDlg::GetChild( HTREEITEM hParent )
|
|
{
|
|
return TreeView_GetChild(m_Tree,hParent);
|
|
}
|
|
|
|
HTREEITEM CCustomTreeDlg::GetNext( HTREEITEM hItem )
|
|
{
|
|
return TreeView_GetNextSibling(m_Tree,hItem);
|
|
}
|
|
|
|
CTreeItem *CCustomTreeDlg::GetItem( HTREEITEM hItem )
|
|
{
|
|
TVITEM item={TVIF_PARAM,hItem};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
return (CTreeItem*)item.lParam;
|
|
}
|
|
|
|
void CCustomTreeDlg::EditItemInternal( CTreeItem *pItem, HTREEITEM hItem )
|
|
{
|
|
if (!m_pSetting->IsLocked() && !pItem->pStdCommand->IsSeparator() && EditItem(pItem,m_Tree,hItem,m_Tree.m_Modules))
|
|
{
|
|
SerializeData();
|
|
m_Tree.UpdateItem(pItem,hItem);
|
|
}
|
|
}
|
|
|
|
bool CCustomTreeDlg::EditItem( CTreeItem *pItem, HWND tree, HTREEITEM hItem, std::vector<HMODULE> &modules )
|
|
{
|
|
MessageBox(L"Edit Item",L"",MB_OK);
|
|
return false;
|
|
}
|
|
|
|
LRESULT CCustomTreeDlg::OnCustomDraw( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
NMTVCUSTOMDRAW *pDraw=(NMTVCUSTOMDRAW*)pnmh;
|
|
if (pDraw->nmcd.dwDrawStage==CDDS_PREPAINT)
|
|
{
|
|
return CDRF_NOTIFYITEMDRAW;
|
|
}
|
|
else if (pDraw->nmcd.dwDrawStage==CDDS_ITEMPREPAINT && !pDraw->nmcd.lItemlParam)
|
|
{
|
|
if (!IsAppThemed())
|
|
{
|
|
TVITEM item={TVIF_STATE,(HTREEITEM)pDraw->nmcd.dwItemSpec,0,TVIS_SELECTED};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
if (item.state&TVIS_SELECTED)
|
|
return CDRF_DODEFAULT;
|
|
}
|
|
pDraw->clrText=GetSysColor(COLOR_GRAYTEXT);
|
|
}
|
|
return CDRF_DODEFAULT;
|
|
}
|
|
|
|
int CCustomTreeDlg::ParseTreeItem( CTreeItem *pItem, CSettingsParser &parser )
|
|
{
|
|
const CStdCommand *pStdCommand=FindStdCommand(pItem->name);
|
|
if (pStdCommand && pStdCommand->IsSeparator())
|
|
{
|
|
pItem->pStdCommand=pStdCommand;
|
|
return 0;
|
|
}
|
|
wchar_t text[256];
|
|
Sprintf(text,_countof(text),L"%s.Command",pItem->name);
|
|
pItem->SetCommand(parser.FindSetting(text,L""),m_pStdCommands,m_Style,m_StyleMask);
|
|
Sprintf(text,_countof(text),L"%s.Link",pItem->name);
|
|
pItem->link=parser.FindSetting(text,L"");
|
|
Sprintf(text,_countof(text),L"%s.Label",pItem->name);
|
|
pItem->label=parser.FindSetting(text,L"");
|
|
Sprintf(text,_countof(text),L"%s.Tip",pItem->name);
|
|
pItem->tip=parser.FindSetting(text,L"");
|
|
Sprintf(text,_countof(text),L"%s.Icon",pItem->name);
|
|
pItem->icon=parser.FindSetting(text,L"");
|
|
ParseTreeItemExtra(pItem,parser);
|
|
return m_Tree.UpdateItem(pItem,NULL);
|
|
}
|
|
|
|
void CCustomTreeDlg::AppendString( std::vector<wchar_t> &stringBuilder, const wchar_t *text )
|
|
{
|
|
stringBuilder.insert(stringBuilder.end(),text,text+Strlen(text));
|
|
}
|
|
|
|
void CCustomTreeDlg::SerializeItem( HTREEITEM hItem, std::vector<wchar_t> &stringBuilder )
|
|
{
|
|
TVITEM item={TVIF_PARAM,hItem};
|
|
CTreeItem *pItem=NULL;
|
|
if (hItem)
|
|
{
|
|
TreeView_GetItem(m_Tree,&item);
|
|
pItem=(CTreeItem*)item.lParam;
|
|
}
|
|
wchar_t text[2048];
|
|
HTREEITEM hChild=hItem?TreeView_GetChild(m_Tree,hItem):TreeView_GetRoot(m_Tree);
|
|
if (hChild)
|
|
{
|
|
// save .Items
|
|
if (pItem)
|
|
Sprintf(text,_countof(text),L"%s.Items=",pItem->name);
|
|
else
|
|
Strcpy(text,_countof(text),L"Items=");
|
|
AppendString(stringBuilder,text);
|
|
|
|
bool bFirst=true;
|
|
for (;hChild;hChild=TreeView_GetNextSibling(m_Tree,hChild), bFirst=false)
|
|
{
|
|
item.hItem=hChild;
|
|
TreeView_GetItem(m_Tree,&item);
|
|
CTreeItem *pChild=(CTreeItem*)item.lParam;
|
|
if (pChild)
|
|
{
|
|
Sprintf(text,_countof(text),bFirst?L"%s":L",%s",pChild->name);
|
|
AppendString(stringBuilder,text);
|
|
}
|
|
}
|
|
AppendString(stringBuilder,L"\n");
|
|
}
|
|
|
|
if (pItem && !pItem->pStdCommand->IsSeparator())
|
|
{
|
|
// save other properties
|
|
if (!pItem->command.IsEmpty())
|
|
{
|
|
Sprintf(text,_countof(text),L"%s.Command=%s\n",pItem->name,pItem->command);
|
|
AppendString(stringBuilder,text);
|
|
}
|
|
if (!pItem->link.IsEmpty())
|
|
{
|
|
Sprintf(text,_countof(text),L"%s.Link=%s\n",pItem->name,pItem->link);
|
|
AppendString(stringBuilder,text);
|
|
}
|
|
if (!pItem->label.IsEmpty())
|
|
{
|
|
Sprintf(text,_countof(text),L"%s.Label=%s\n",pItem->name,pItem->label);
|
|
AppendString(stringBuilder,text);
|
|
}
|
|
if (!pItem->tip.IsEmpty())
|
|
{
|
|
Sprintf(text,_countof(text),L"%s.Tip=%s\n",pItem->name,pItem->tip);
|
|
AppendString(stringBuilder,text);
|
|
}
|
|
if (!pItem->icon.IsEmpty())
|
|
{
|
|
Sprintf(text,_countof(text),L"%s.Icon=%s\n",pItem->name,pItem->icon);
|
|
AppendString(stringBuilder,text);
|
|
}
|
|
SerializeItemExtra(pItem,stringBuilder);
|
|
}
|
|
hChild=hItem?TreeView_GetChild(m_Tree,hItem):TreeView_GetRoot(m_Tree);
|
|
for (;hChild;hChild=TreeView_GetNextSibling(m_Tree,hChild))
|
|
SerializeItem(hChild,stringBuilder);
|
|
}
|
|
|
|
void CCustomTreeDlg::SerializeData( void )
|
|
{
|
|
std::vector<wchar_t> stringBuilder;
|
|
SerializeItem(NULL,stringBuilder);
|
|
stringBuilder.push_back(0);
|
|
CSettingsLockWrite lock;
|
|
const wchar_t *strNew=&stringBuilder[0];
|
|
const wchar_t *strOld=m_pSetting->value.vt==VT_BSTR?m_pSetting->value.bstrVal:L"???";
|
|
if ((m_pSetting->flags&CSetting::FLAG_DEFAULT) || wcscmp(strNew,strOld)!=0)
|
|
SetSettingsDirty();
|
|
m_pSetting->value=CComVariant(strNew);
|
|
m_pSetting->flags&=~CSetting::FLAG_DEFAULT;
|
|
ItemsChanged();
|
|
}
|
|
|
|
void CCustomTreeDlg::CreateTreeItems( CSettingsParser &parser, HTREEITEM hParent, const CSettingsParser::TreeItem *pItems, int index )
|
|
{
|
|
for (;!pItems[index].name.IsEmpty();index++)
|
|
{
|
|
CTreeItem *pNewItem=new CTreeItem;
|
|
pNewItem->name=pItems[index].name;
|
|
TVINSERTSTRUCT insert={hParent,TVI_LAST,{TVIF_STATE|TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE,NULL,TVIS_EXPANDED,TVIS_EXPANDED}};
|
|
insert.item.iImage=insert.item.iSelectedImage=ParseTreeItem(pNewItem,parser);
|
|
insert.item.lParam=(LPARAM)pNewItem;
|
|
CString dispName=pNewItem->GetDisplayName(false);
|
|
insert.item.pszText=(LPWSTR)(LPCWSTR)dispName;
|
|
HTREEITEM hItem=TreeView_InsertItem(m_Tree,&insert);
|
|
|
|
if (pItems[index].children>=0)
|
|
CreateTreeItems(parser,hItem,pItems,pItems[index].children);
|
|
}
|
|
}
|
|
|
|
void CCustomTreeDlg::SetGroup( CSetting *pGroup, bool bReset )
|
|
{
|
|
if (!m_pSetting || bReset) // optimization - initialize the UI only the first time
|
|
{
|
|
TreeView_DeleteAllItems(m_Tree);
|
|
m_pSetting=pGroup+1;
|
|
Assert(!m_pSetting->pLinkTo);
|
|
m_Tree.SetDisabled(m_pSetting->IsLocked());
|
|
const wchar_t *pText=L"";
|
|
if (m_pSetting->value.vt==VT_BSTR)
|
|
pText=m_pSetting->value.bstrVal;
|
|
|
|
CSettingsParser parser;
|
|
parser.LoadText(pText,Strlen(pText));
|
|
parser.ParseText();
|
|
std::vector<CSettingsParser::TreeItem> items;
|
|
parser.ParseTree(L"Items",items);
|
|
if (!items.empty())
|
|
CreateTreeItems(parser,NULL,&items[0],0);
|
|
InitItems();
|
|
}
|
|
// use the tooltip from m_CommandsTree to show the "locked" tooltip for m_Tree. otherwise it will behave like an infotip and move from item to item
|
|
CWindow tooltip=(HWND)m_CommandsTree.SendMessage(TVM_GETTOOLTIPS);
|
|
TOOLINFO tool={sizeof(tool),TTF_SUBCLASS|TTF_IDISHWND,m_hWnd,(UINT_PTR)(HWND)m_Tree};
|
|
CString str=LoadStringEx(m_bMenu?IDS_MENU_LOCKED:IDS_TOOLBAR_LOCKED);
|
|
tool.lpszText=(LPWSTR)(LPCWSTR)str;
|
|
if (m_pSetting->IsLockedReg())
|
|
tooltip.SendMessage(TTM_ADDTOOL,0,(LPARAM)&tool);
|
|
else
|
|
tooltip.SendMessage(TTM_DELTOOL,0,(LPARAM)&tool);
|
|
|
|
TreeView_SetBkColor(m_Tree,m_pSetting->IsLocked()?GetSysColor(COLOR_BTNFACE):-1);
|
|
TreeView_SetBkColor(m_CommandsTree,m_pSetting->IsLocked()?GetSysColor(COLOR_BTNFACE):-1);
|
|
}
|
|
|
|
CCustomTreeDlg::CCustomTreeDlg( bool bMenu, const CStdCommand *pStdCommands, int style, int mask ):
|
|
m_Tree(*new CSettingsTree(mask)), m_CommandsTree(*new CCommandsTree)
|
|
{
|
|
m_bMenu=bMenu;
|
|
m_pStdCommands=pStdCommands;
|
|
m_Style=style;
|
|
m_StyleMask=mask;
|
|
}
|
|
|
|
CCustomTreeDlg::~CCustomTreeDlg( void )
|
|
{
|
|
delete &m_Tree;
|
|
delete &m_CommandsTree;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CBrowseForIconDlg: public CResizeableDlg<CBrowseForIconDlg>
|
|
{
|
|
public:
|
|
CBrowseForIconDlg( wchar_t *path, int &id ): m_pPath(path), m_ID(id) { m_bResult=false; }
|
|
void SetEnableParent( HWND parent ) { m_EnableParent=parent; }
|
|
bool GetResult( void ) { return m_bResult; }
|
|
|
|
BEGIN_MSG_MAP( CBrowseForIconDlg )
|
|
MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog )
|
|
MESSAGE_HANDLER( WM_SIZE, OnSize )
|
|
MESSAGE_HANDLER( WM_GETMINMAXINFO, OnGetMinMaxInfo )
|
|
COMMAND_ID_HANDLER( IDC_BUTTONBROWSE, OnBrowse )
|
|
COMMAND_ID_HANDLER( IDOK, OnOK )
|
|
COMMAND_ID_HANDLER( IDCANCEL, OnCancel )
|
|
COMMAND_HANDLER( IDC_EDITFILE, EN_KILLFOCUS, OnKillFocus )
|
|
NOTIFY_HANDLER( IDC_LISTICONS, LVN_ITEMACTIVATE, OnItemActivate )
|
|
END_MSG_MAP()
|
|
|
|
BEGIN_RESIZE_MAP
|
|
RESIZE_CONTROL(IDC_EDITFILE,MOVE_SIZE_X)
|
|
RESIZE_CONTROL(IDC_BUTTONBROWSE,MOVE_MOVE_X)
|
|
RESIZE_CONTROL(IDC_LISTICONS,MOVE_SIZE_X|MOVE_SIZE_Y)
|
|
RESIZE_CONTROL(IDOK,MOVE_MOVE_X|MOVE_MOVE_Y)
|
|
RESIZE_CONTROL(IDCANCEL,MOVE_MOVE_X|MOVE_MOVE_Y)
|
|
END_RESIZE_MAP
|
|
|
|
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 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 );
|
|
LRESULT OnKillFocus( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled );
|
|
LRESULT OnItemActivate( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
|
|
private:
|
|
HWND m_EnableParent;
|
|
bool m_bResult;
|
|
wchar_t *m_pPath;
|
|
int &m_ID;
|
|
CString m_LastName;
|
|
|
|
void UpdateIcons( int id );
|
|
void StorePlacement( void );
|
|
static BOOL CALLBACK EnumIconsProc( HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam );
|
|
};
|
|
|
|
LRESULT CBrowseForIconDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
SetDlgItemText(IDC_EDITFILE,m_pPath);
|
|
CWindow list=GetDlgItem(IDC_LISTICONS);
|
|
list.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_DOUBLEBUFFER,LVS_EX_DOUBLEBUFFER);
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
HFONT font0=(HFONT)SelectObject(hdc,list.GetFont());
|
|
TEXTMETRIC metrics;
|
|
GetTextMetrics(hdc,&metrics);
|
|
SelectObject(hdc,font0);
|
|
DeleteDC(hdc);
|
|
ListView_SetIconSpacing(list,GetSystemMetrics(SM_CXICON)+metrics.tmHeight+7,GetSystemMetrics(SM_CYICON)+metrics.tmHeight+7);
|
|
if (IsAppThemed())
|
|
SetWindowTheme(list,L"Explorer",NULL);
|
|
UpdateIcons(m_ID);
|
|
InitResize(MOVE_MODAL);
|
|
SHAutoComplete(GetDlgItem(IDC_EDITFILE),SHACF_FILESYSTEM);
|
|
|
|
RECT rc;
|
|
CRegKey regSettings;
|
|
if (regSettings.Open(HKEY_CURRENT_USER,GetSettingsRegPath())==ERROR_SUCCESS)
|
|
{
|
|
ULONG size=sizeof(rc);
|
|
if (regSettings.QueryBinaryValue(L"CBrowseForIconDlg",&rc,&size)==ERROR_SUCCESS && size==sizeof(rc))
|
|
SetStoreRect(rc);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT CBrowseForIconDlg::OnSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
CResizeableDlg<CBrowseForIconDlg>::OnSize();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CBrowseForIconDlg::OnBrowse( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
OPENFILENAME ofn={sizeof(ofn)};
|
|
ofn.hwndOwner=m_hWnd;
|
|
wchar_t filters[256];
|
|
Strcpy(filters,_countof(filters),LoadStringEx(IDS_ICON_FILTERS));
|
|
for (wchar_t *c=filters;*c;c++)
|
|
if (*c=='|') *c=0;
|
|
ofn.lpstrFilter=filters;
|
|
ofn.nFilterIndex=1;
|
|
wchar_t path[_MAX_PATH];
|
|
GetDlgItemText(IDC_EDITFILE,path,_countof(path));
|
|
DoEnvironmentSubst(path,_countof(path));
|
|
wchar_t dir[_MAX_PATH];
|
|
Strcpy(dir,_countof(dir),path);
|
|
PathRemoveFileSpec(dir);
|
|
ofn.lpstrInitialDir=dir;
|
|
path[0]=0;
|
|
ofn.lpstrFile=path;
|
|
ofn.nMaxFile=_countof(path);
|
|
CString title=LoadStringEx(IDS_ICON_TITLE);
|
|
ofn.lpstrTitle=title;
|
|
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
|
|
if (GetOpenFileName(&ofn))
|
|
{
|
|
wchar_t buf[_MAX_PATH];
|
|
UnExpandEnvStrings(path,buf,_countof(buf));
|
|
SetDlgItemText(IDC_EDITFILE,buf);
|
|
UpdateIcons(-1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CBrowseForIconDlg::StorePlacement( void )
|
|
{
|
|
RECT rc;
|
|
GetStoreRect(rc);
|
|
|
|
CRegKey regSettings;
|
|
if (regSettings.Open(HKEY_CURRENT_USER,GetSettingsRegPath())!=ERROR_SUCCESS)
|
|
regSettings.Create(HKEY_CURRENT_USER,GetSettingsRegPath());
|
|
regSettings.SetBinaryValue(L"CBrowseForIconDlg",&rc,sizeof(rc));
|
|
}
|
|
|
|
LRESULT CBrowseForIconDlg::OnOK( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
if (GetFocus()==GetDlgItem(IDC_EDITFILE))
|
|
{
|
|
SendMessage(WM_NEXTDLGCTL,(WPARAM)GetDlgItem(IDOK).m_hWnd,TRUE);
|
|
return 0;
|
|
}
|
|
CString text;
|
|
GetDlgItemText(IDC_EDITFILE,text);
|
|
text.TrimLeft();
|
|
text.TrimRight();
|
|
Strcpy(m_pPath,_MAX_PATH,text);
|
|
CWindow list=GetDlgItem(IDC_LISTICONS);
|
|
int sel=ListView_GetNextItem(list,-1,LVNI_SELECTED);
|
|
if (sel>=0)
|
|
{
|
|
LVITEM item={LVIF_PARAM,sel};
|
|
ListView_GetItem(list,&item);
|
|
m_ID=(int)item.lParam;
|
|
}
|
|
else
|
|
m_ID=0;
|
|
::EnableWindow(m_EnableParent,TRUE);
|
|
m_bResult=true;
|
|
StorePlacement();
|
|
DestroyWindow();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CBrowseForIconDlg::OnCancel( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
::EnableWindow(m_EnableParent,TRUE);
|
|
m_bResult=false;
|
|
StorePlacement();
|
|
DestroyWindow();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CBrowseForIconDlg::OnKillFocus( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
UpdateIcons(-1);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CBrowseForIconDlg::OnItemActivate( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
PostMessage(WM_COMMAND,IDOK,0);
|
|
return 0;
|
|
}
|
|
|
|
BOOL CALLBACK CBrowseForIconDlg::EnumIconsProc( HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam )
|
|
{
|
|
if (IS_INTRESOURCE(lpszName))
|
|
{
|
|
HWND list=(HWND)lParam;
|
|
HICON hIcon=(HICON)LoadImage(hModule,lpszName,IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_DEFAULTCOLOR);
|
|
if (hIcon)
|
|
{
|
|
HIMAGELIST images=ListView_GetImageList(list,LVSIL_NORMAL);
|
|
int idx=ImageList_AddIcon(images,hIcon);
|
|
DestroyIcon(hIcon);
|
|
LVITEM item={LVIF_IMAGE|LVIF_PARAM|LVIF_TEXT};
|
|
item.iItem=idx;
|
|
item.iImage=idx;
|
|
item.lParam=(WORD)(DWORD_PTR)lpszName;
|
|
wchar_t text[20];
|
|
Sprintf(text,_countof(text),L"%d",(int)item.lParam);
|
|
item.pszText=text;
|
|
ListView_InsertItem(list,&item);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void CBrowseForIconDlg::UpdateIcons( int id )
|
|
{
|
|
wchar_t path[1024];
|
|
GetDlgItemText(IDC_EDITFILE,path,_countof(path));
|
|
DoEnvironmentSubst(path,_countof(path));
|
|
if (m_LastName==path && id==-1) return;
|
|
m_LastName=path;
|
|
|
|
CWindow list=GetDlgItem(IDC_LISTICONS);
|
|
ListView_DeleteAllItems(list);
|
|
HIMAGELIST images=ImageList_Create(GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON),ILC_COLOR32|ILC_MASK,10,10);
|
|
ListView_SetImageList(list,images,LVSIL_NORMAL);
|
|
ImageList_RemoveAll(images);
|
|
|
|
if (_wcsicmp(PathFindExtension(path),L".ico")==0)
|
|
{
|
|
// load icon file
|
|
HICON hIcon=(HICON)LoadImage(NULL,path,IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_DEFAULTCOLOR|LR_LOADFROMFILE);
|
|
if (hIcon)
|
|
{
|
|
ImageList_AddIcon(images,hIcon);
|
|
DestroyIcon(hIcon);
|
|
LVITEM item={LVIF_IMAGE|LVIF_PARAM|LVIF_STATE,0,0,LVIS_SELECTED,LVIS_SELECTED};
|
|
item.iImage=0;
|
|
item.lParam=0;
|
|
ListView_InsertItem(list,&item);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// load module file
|
|
HINSTANCE hInstance=_AtlBaseModule.GetResourceInstance();
|
|
HMODULE hModule;
|
|
if (*path)
|
|
hModule=LoadLibraryEx(path,NULL,LOAD_LIBRARY_AS_DATAFILE|LOAD_LIBRARY_AS_IMAGE_RESOURCE);
|
|
else
|
|
hModule=hInstance;
|
|
if (hModule)
|
|
{
|
|
// enumerate icons, extract icons
|
|
list.SendMessage(WM_SETREDRAW,FALSE);
|
|
EnumResourceNames(hModule,RT_GROUP_ICON,EnumIconsProc,(LONG_PTR)list.m_hWnd);
|
|
list.SendMessage(WM_SETREDRAW,TRUE);
|
|
// free module
|
|
if (hModule!=hInstance) FreeLibrary(hModule);
|
|
}
|
|
if (ListView_GetItemCount(list)>0)
|
|
{
|
|
int idx=0;
|
|
if (id>0)
|
|
{
|
|
LVFINDINFO find={LVFI_PARAM,0,id};
|
|
idx=ListView_FindItem(list,-1,&find);
|
|
if (idx<0) idx=0;
|
|
}
|
|
ListView_SetItemState(list,idx,LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);
|
|
ListView_EnsureVisible(list,idx,FALSE);
|
|
list.InvalidateRect(NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool BrowseForIcon( HWND hWndParent, wchar_t *path, int &id )
|
|
{
|
|
CBrowseForIconDlg dlg(path,id);
|
|
|
|
hWndParent=GetAncestor(hWndParent,GA_ROOT);
|
|
DLGTEMPLATE *pTemplate=LoadDialogEx(IDD_BROWSEFORICON);
|
|
dlg.Create(hWndParent,pTemplate);
|
|
dlg.ShowWindow(SW_SHOWNORMAL);
|
|
EnableWindow(hWndParent,FALSE);
|
|
dlg.SetEnableParent(hWndParent);
|
|
MSG msg;
|
|
while (dlg.m_hWnd && GetMessage(&msg,0,0,0))
|
|
{
|
|
if (dlg.IsDialogMessage(&msg)) continue;
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
return dlg.GetResult();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool BrowseForBitmap( HWND hWndParent, wchar_t *path, bool bAllowJpeg )
|
|
{
|
|
OPENFILENAME ofn={sizeof(ofn)};
|
|
ofn.hwndOwner=hWndParent;
|
|
wchar_t filters[256];
|
|
Strcpy(filters,_countof(filters),LoadStringEx(bAllowJpeg?IDS_BMP_FILTERS2:IDS_BMP_FILTERS));
|
|
for (wchar_t *c=filters;*c;c++)
|
|
if (*c=='|') *c=0;
|
|
ofn.lpstrFilter=filters;
|
|
ofn.nFilterIndex=1;
|
|
wchar_t dir[_MAX_PATH];
|
|
Strcpy(dir,_countof(dir),path);
|
|
PathRemoveFileSpec(dir);
|
|
ofn.lpstrInitialDir=dir;
|
|
path[0]=0;
|
|
ofn.lpstrFile=path;
|
|
ofn.nMaxFile=_MAX_PATH;
|
|
CString title=LoadStringEx(IDS_BMP_TITLE);
|
|
ofn.lpstrTitle=title;
|
|
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
|
|
if (GetOpenFileName(&ofn))
|
|
{
|
|
wchar_t buf[_MAX_PATH];
|
|
UnExpandEnvStrings(path,buf,_countof(buf));
|
|
Strcpy(path,_MAX_PATH,buf);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool BrowseForSound( HWND hWndParent, wchar_t *path )
|
|
{
|
|
OPENFILENAME ofn={sizeof(ofn)};
|
|
ofn.hwndOwner=hWndParent;
|
|
wchar_t filters[256];
|
|
Strcpy(filters,_countof(filters),LoadStringEx(IDS_WAV_FILTERS));
|
|
for (wchar_t *c=filters;*c;c++)
|
|
if (*c=='|') *c=0;
|
|
ofn.lpstrFilter=filters;
|
|
ofn.nFilterIndex=1;
|
|
wchar_t dir[_MAX_PATH];
|
|
Strcpy(dir,_countof(dir),path);
|
|
PathRemoveFileSpec(dir);
|
|
ofn.lpstrInitialDir=dir;
|
|
path[0]=0;
|
|
ofn.lpstrFile=path;
|
|
ofn.nMaxFile=_MAX_PATH;
|
|
CString title=LoadStringEx(IDS_WAV_TITLE);
|
|
ofn.lpstrTitle=title;
|
|
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
|
|
if (GetOpenFileName(&ofn))
|
|
{
|
|
wchar_t buf[_MAX_PATH];
|
|
UnExpandEnvStrings(path,buf,_countof(buf));
|
|
Strcpy(path,_MAX_PATH,buf);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CTreeSettingsDlg: public CResizeableDlg<CTreeSettingsDlg>
|
|
{
|
|
public:
|
|
enum {
|
|
IDC_EDITBOX=101,
|
|
IDC_BROWSEBTN=102,
|
|
IDC_PLAYBTN=103,
|
|
WM_EDITKEY=WM_APP+11,
|
|
};
|
|
|
|
enum TEditMode
|
|
{
|
|
EDIT_NONE,
|
|
EDIT_INT,
|
|
EDIT_STRING,
|
|
EDIT_ICON,
|
|
EDIT_BITMAP,
|
|
EDIT_BITMAP_JPG,
|
|
EDIT_SOUND,
|
|
EDIT_HOTKEY,
|
|
EDIT_HOTKEY_ANY,
|
|
EDIT_COLOR,
|
|
EDIT_FONT,
|
|
EDIT_DIRECTORY,
|
|
};
|
|
|
|
BEGIN_MSG_MAP( CTreeSettingsDlg )
|
|
MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog )
|
|
MESSAGE_HANDLER( WM_DESTROY, OnDestroy )
|
|
MESSAGE_HANDLER( WM_SIZE, OnSize )
|
|
MESSAGE_HANDLER( WM_EDITKEY, OnEditKey )
|
|
MESSAGE_HANDLER( WM_CONTEXTMENU, OnContextMenu )
|
|
COMMAND_HANDLER( IDC_EDITBOX, EN_CHANGE, OnEditChange )
|
|
COMMAND_HANDLER( IDC_EDITBOX, EN_KILLFOCUS, OnKillFocus )
|
|
COMMAND_HANDLER( IDC_BROWSEBTN, BN_CLICKED, OnBrowse )
|
|
COMMAND_HANDLER( IDC_PLAYBTN, BN_CLICKED, OnPlay )
|
|
COMMAND_HANDLER( IDC_BROWSEBTN, BN_KILLFOCUS, OnKillFocus )
|
|
NOTIFY_HANDLER( IDC_SETTINGS, NM_CUSTOMDRAW, OnCustomDraw )
|
|
NOTIFY_HANDLER( IDC_SETTINGS, NM_CLICK, OnClick )
|
|
NOTIFY_HANDLER( IDC_SETTINGS, NM_DBLCLK, OnClick )
|
|
NOTIFY_HANDLER( IDC_SETTINGS, TVN_KEYDOWN, OnKeyDown )
|
|
NOTIFY_HANDLER( IDC_SETTINGS, TVN_GETINFOTIP, OnGetInfoTip )
|
|
NOTIFY_HANDLER( IDC_SETTINGS, TVN_SELCHANGED, OnSelChanged )
|
|
NOTIFY_HANDLER( IDC_SETTINGS, TVN_ITEMEXPANDING, OnExpanding )
|
|
END_MSG_MAP()
|
|
|
|
BEGIN_RESIZE_MAP
|
|
RESIZE_CONTROL(IDC_SETTINGS,MOVE_SIZE_X|MOVE_SIZE_Y)
|
|
RESIZE_CONTROL(IDC_STATICTIP,MOVE_SIZE_X|MOVE_MOVE_Y)
|
|
END_RESIZE_MAP
|
|
|
|
void SetGroup( CSetting *pGroup, const CString &filter, const CSetting *pSelect );
|
|
void Validate( void ) { ApplyEditBox(); }
|
|
|
|
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 OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnEditKey( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnContextMenu( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled );
|
|
LRESULT OnEditChange( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled );
|
|
LRESULT OnKillFocus( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled );
|
|
LRESULT OnBrowse( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled );
|
|
LRESULT OnPlay( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled );
|
|
LRESULT OnCustomDraw( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnKeyDown( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnClick( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnGetInfoTip( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnSelChanged( int idCtrl, LPNMHDR pnmh, BOOL& bHandled );
|
|
LRESULT OnExpanding( int idCtrl, LPNMHDR pnmh, BOOL& bHandled ) { return TRUE; } // prevent collapsing
|
|
|
|
private:
|
|
CWindow m_Tree;
|
|
const CSetting *m_pGroup;
|
|
CWindow m_EditBox;
|
|
CWindow m_BrowseButton;
|
|
CWindow m_PlayButton;
|
|
HICON m_PlayIcon;
|
|
TEditMode m_EditMode;
|
|
HTREEITEM m_EditItem;
|
|
CSetting *m_pEditSetting;
|
|
bool m_bBasic;
|
|
bool m_bIgnoreFocus;
|
|
bool m_bSearch;
|
|
|
|
void UpdateGroup( const CSetting *pModified );
|
|
void ToggleItem( HTREEITEM hItem, bool bDefault );
|
|
void PlayItem( HTREEITEM hItem );
|
|
void LocateSetting( const CSetting *pSetting );
|
|
void ItemSelected( HTREEITEM hItem, CSetting *pSetting, bool bEnabled );
|
|
void ApplyEditBox( void );
|
|
void UpdateEditPosition( void );
|
|
const CSetting *GetNextSetting( const CSetting *pSetting, const wchar_t *filter );
|
|
bool IsVisible( const CSetting *pSetting, const wchar_t *filter ) const;
|
|
HTREEITEM GetNextItem( HTREEITEM hItem, bool bChildren=true );
|
|
HTREEITEM FindSettingsItem( const wchar_t *name );
|
|
};
|
|
|
|
// Subclass the tree control to forward the command messages to the parent
|
|
static LRESULT CALLBACK SubclassTreeProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (uMsg==WM_COMMAND)
|
|
return SendMessage(GetParent(hWnd),uMsg,wParam,lParam);
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static int g_HotKey;
|
|
|
|
static bool GetKeyName( int key, wchar_t *text, int size, bool bCtrl, bool bAlt, bool bShift )
|
|
{
|
|
wchar_t name[100];
|
|
text[0]=0;
|
|
int len=0;
|
|
if (bCtrl || (key&(HOTKEYF_CONTROL<<8)))
|
|
{
|
|
GetKeyNameText(MapVirtualKey(VK_CONTROL,MAPVK_VK_TO_VSC)<<16,name,_countof(name));
|
|
len+=Sprintf(text+len,size-len,L"%s+",name);
|
|
}
|
|
if (bAlt || (key&(HOTKEYF_ALT<<8)))
|
|
{
|
|
GetKeyNameText(MapVirtualKey(VK_MENU,MAPVK_VK_TO_VSC)<<16,name,_countof(name));
|
|
len+=Sprintf(text+len,size-len,L"%s+",name);
|
|
}
|
|
if (bShift || (key&(HOTKEYF_SHIFT<<8)))
|
|
{
|
|
GetKeyNameText(MapVirtualKey(VK_SHIFT,MAPVK_VK_TO_VSC)<<16,name,_countof(name));
|
|
len+=Sprintf(text+len,size-len,L"%s+",name);
|
|
}
|
|
if (key)
|
|
{
|
|
int scan=MapVirtualKey(key&255,MAPVK_VK_TO_VSC);
|
|
if (scan==0)
|
|
{
|
|
text[0]=0;
|
|
return false;
|
|
}
|
|
if (!GetKeyNameText(scan<<16,name,_countof(name)))
|
|
{
|
|
text[0]=0;
|
|
return false;
|
|
}
|
|
Strcpy(text+len,size-len,name);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Subclass the edit control to forward some keyboard messages to the parent and to act as a hotkey control
|
|
static LRESULT CALLBACK SubclassEditProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
|
|
{
|
|
if (dwRefData)
|
|
{
|
|
static bool s_bCtrl, s_bAlt, s_bShift;
|
|
|
|
if (uMsg==WM_GETDLGCODE)
|
|
return DLGC_WANTALLKEYS;
|
|
|
|
if (uMsg==WM_CHAR || uMsg==WM_SYSCHAR)
|
|
return 0;
|
|
|
|
if (uMsg==WM_KEYDOWN || uMsg==WM_SYSKEYDOWN)
|
|
{
|
|
if ((wParam==VK_UP || wParam==VK_DOWN || wParam==VK_PRIOR || wParam==VK_NEXT) && GetKeyState(VK_CONTROL)>=0 && GetKeyState(VK_MENU)>=0 && GetKeyState(VK_SHIFT)>=0)
|
|
return SendMessage(GetParent(hWnd),uMsg,wParam,lParam);
|
|
if (wParam==VK_ESCAPE)
|
|
{ // Esc - clears the key
|
|
g_HotKey=0;
|
|
SetWindowText(hWnd,L"");
|
|
return 0;
|
|
}
|
|
wchar_t text[100];
|
|
if (wParam==VK_CONTROL) s_bCtrl=true, g_HotKey=0;
|
|
else if (wParam==VK_SHIFT) s_bShift=true, g_HotKey=0;
|
|
else if (wParam==VK_MENU) s_bAlt=true, g_HotKey=0;
|
|
else
|
|
{
|
|
g_HotKey=wParam&255;
|
|
if (s_bCtrl) g_HotKey|=(HOTKEYF_CONTROL<<8);
|
|
if (s_bAlt) g_HotKey|=(HOTKEYF_ALT<<8);
|
|
if (s_bShift) g_HotKey|=(HOTKEYF_SHIFT<<8);
|
|
if (dwRefData==1)
|
|
{
|
|
if (!s_bAlt && !(s_bCtrl && s_bShift))
|
|
g_HotKey=0;
|
|
}
|
|
}
|
|
GetKeyName(g_HotKey,text,_countof(text),s_bCtrl,s_bAlt,s_bShift);
|
|
SetWindowText(hWnd,text);
|
|
return 0;
|
|
}
|
|
if (uMsg==WM_KEYUP || uMsg==WM_SYSKEYUP)
|
|
{
|
|
wchar_t text[100];
|
|
if (wParam==VK_CONTROL) s_bCtrl=false;
|
|
if (wParam==VK_MENU) s_bAlt=false;
|
|
if (wParam==VK_SHIFT) s_bShift=false;
|
|
GetKeyName(g_HotKey,text,_countof(text),s_bCtrl,s_bAlt,s_bShift);
|
|
SetWindowText(hWnd,text);
|
|
return 0;
|
|
}
|
|
if (uMsg==WM_RBUTTONUP || uMsg==WM_CONTEXTMENU)
|
|
return 0;
|
|
}
|
|
if (uMsg==WM_CHAR && wParam==VK_SPACE && GetKeyState(VK_CONTROL)<0)
|
|
return SendMessage(GetParent(hWnd),WM_KEYDOWN,wParam,lParam);
|
|
if (uMsg==WM_CHAR && wParam==VK_RETURN)
|
|
return 0;
|
|
if (uMsg==WM_GETDLGCODE && wParam==VK_RETURN)
|
|
return DLGC_WANTALLKEYS;
|
|
if (uMsg==WM_KEYDOWN)
|
|
{
|
|
if (wParam==VK_UP || wParam==VK_DOWN || wParam==VK_PRIOR || wParam==VK_NEXT || (wParam=='P' && GetKeyState(VK_CONTROL)<0))
|
|
return SendMessage(GetParent(hWnd),uMsg,wParam,lParam);
|
|
if (wParam==VK_RETURN || wParam==VK_ESCAPE)
|
|
return SendMessage(GetParent(GetParent(hWnd)),CTreeSettingsDlg::WM_EDITKEY,wParam,0);
|
|
}
|
|
if (uMsg==WM_KILLFOCUS)
|
|
{
|
|
if (wParam && (HWND)wParam==GetDlgItem(GetParent(hWnd),CTreeSettingsDlg::IDC_BROWSEBTN))
|
|
return 0;
|
|
}
|
|
if (uMsg==WM_CHAR && wParam==16)
|
|
return 0; // prevent Ctrl+P from playing the default sound
|
|
return DefSubclassProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnInitDialog( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
InitResize();
|
|
EnableThemeDialogTexture(m_hWnd,ETDT_ENABLETAB);
|
|
|
|
m_Tree=GetDlgItem(IDC_SETTINGS);
|
|
m_Tree.SetWindowLong(GWL_STYLE,m_Tree.GetWindowLong(GWL_STYLE)|WS_CLIPCHILDREN);
|
|
if (IsAppThemed())
|
|
{
|
|
m_Tree.SetWindowLong(GWL_STYLE,m_Tree.GetWindowLong(GWL_STYLE)|TVS_TRACKSELECT);
|
|
SetWindowTheme(m_Tree,L"Explorer",NULL);
|
|
}
|
|
m_Tree.SendMessage(TVM_SETEXTENDEDSTYLE,TVS_EX_DOUBLEBUFFER,TVS_EX_DOUBLEBUFFER);
|
|
SetWindowSubclass(m_Tree,SubclassTreeProc,'CLSH',0);
|
|
HINSTANCE hInstance=_AtlBaseModule.GetResourceInstance();
|
|
|
|
HIMAGELIST images=GetSettingsImageList(m_Tree);
|
|
TreeView_SetImageList(m_Tree,images,TVSIL_NORMAL);
|
|
int height=TreeView_GetItemHeight(m_Tree);
|
|
if (height<18) TreeView_SetItemHeight(m_Tree,18);
|
|
|
|
HWND tooltip=TreeView_GetToolTips(m_Tree);
|
|
SendMessage(tooltip,TTM_SETDELAYTIME,TTDT_AUTOPOP,10000);
|
|
SendMessage(tooltip,TTM_SETDELAYTIME,TTDT_INITIAL,1000);
|
|
SendMessage(tooltip,TTM_SETDELAYTIME,TTDT_RESHOW,1000);
|
|
SetWindowSubclass(tooltip,SubclassInfoTipProc,'CLSH',0);
|
|
|
|
HFONT font=m_Tree.GetFont();
|
|
m_EditBox=CreateWindow(L"EDIT",NULL,WS_CHILD|WS_BORDER|ES_AUTOHSCROLL,0,0,0,0,m_Tree,(HMENU)IDC_EDITBOX,hInstance,NULL);
|
|
m_EditBox.SetFont(font);
|
|
SetWindowSubclass(m_EditBox,SubclassEditProc,'CLSH',0);
|
|
m_BrowseButton=CreateWindow(L"BUTTON",L"...",WS_CHILD|BS_PUSHBUTTON,0,0,0,0,m_Tree,(HMENU)IDC_BROWSEBTN,hInstance,NULL);
|
|
m_BrowseButton.SetFont(font);
|
|
m_PlayIcon=(HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_ICONPLAY),IMAGE_ICON,0,0,0);
|
|
m_PlayButton=CreateWindow(L"BUTTON",L">",WS_CHILD|BS_PUSHBUTTON|BS_ICON,0,0,0,0,m_Tree,(HMENU)IDC_PLAYBTN,hInstance,NULL);
|
|
m_PlayButton.SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)m_PlayIcon);
|
|
m_EditMode=EDIT_NONE;
|
|
m_EditItem=NULL;
|
|
m_pEditSetting=NULL;
|
|
m_bIgnoreFocus=false;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
DestroyIcon(m_PlayIcon);
|
|
bHandled=FALSE;
|
|
m_EditMode=EDIT_NONE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnSize( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
CResizeableDlg<CTreeSettingsDlg>::OnSize();
|
|
UpdateEditPosition();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnEditKey( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if (wParam==VK_RETURN && !(m_EditBox.GetWindowLong(GWL_STYLE)&ES_READONLY))
|
|
ItemSelected(m_EditItem,m_pEditSetting,true);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnEditChange( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
UpdateEditPosition();
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnKillFocus( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
if (!m_bIgnoreFocus && m_pEditSetting)
|
|
{
|
|
ApplyEditBox();
|
|
UpdateEditPosition();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnBrowse( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
if (m_EditMode==EDIT_ICON)
|
|
{
|
|
m_bIgnoreFocus=true;
|
|
CString str;
|
|
m_EditBox.GetWindowText(str);
|
|
str.TrimLeft(); str.TrimRight();
|
|
wchar_t text[_MAX_PATH*2];
|
|
Strcpy(text,_countof(text),str);
|
|
int id=0;
|
|
if (*text)
|
|
{
|
|
wchar_t *c=wcsrchr(text,',');
|
|
if (c)
|
|
{
|
|
*c=0;
|
|
id=_wtol(c+1);
|
|
}
|
|
}
|
|
else
|
|
Strcpy(text,_countof(text),L"shell32.dll");
|
|
if (BrowseForIcon(m_hWnd,text,id))
|
|
{
|
|
if (id>0)
|
|
{
|
|
wchar_t buf[20];
|
|
Sprintf(buf,_countof(buf),L", %d",id);
|
|
Strcat(text,_countof(text),buf);
|
|
}
|
|
m_EditBox.SetWindowText(text);
|
|
}
|
|
SendMessage(WM_NEXTDLGCTL,(LPARAM)m_EditBox.m_hWnd,TRUE);
|
|
m_bIgnoreFocus=false;
|
|
}
|
|
else if (m_EditMode==EDIT_BITMAP || m_EditMode==EDIT_BITMAP_JPG)
|
|
{
|
|
m_bIgnoreFocus=true;
|
|
CString str;
|
|
m_EditBox.GetWindowText(str);
|
|
str.TrimLeft(); str.TrimRight();
|
|
wchar_t text[1024];
|
|
if (_wcsicmp(PathFindExtension(str),L".bmp")==0 || _wcsicmp(PathFindExtension(str),L".png")==0 || (m_EditMode==EDIT_BITMAP_JPG && _wcsicmp(PathFindExtension(str),L".jpg")==0))
|
|
{
|
|
Strcpy(text,_countof(text),str);
|
|
DoEnvironmentSubst(text,_countof(text));
|
|
}
|
|
else
|
|
text[0]=0;
|
|
if (BrowseForBitmap(m_hWnd,text,m_EditMode==EDIT_BITMAP_JPG))
|
|
{
|
|
m_EditBox.SetWindowText(text);
|
|
}
|
|
SendMessage(WM_NEXTDLGCTL,(LPARAM)m_EditBox.m_hWnd,TRUE);
|
|
m_EditBox.SetFocus();
|
|
m_bIgnoreFocus=false;
|
|
}
|
|
else if (m_EditMode==EDIT_SOUND)
|
|
{
|
|
m_bIgnoreFocus=true;
|
|
CString str;
|
|
m_EditBox.GetWindowText(str);
|
|
str.TrimLeft(); str.TrimRight();
|
|
wchar_t text[1024];
|
|
if (_wcsicmp(PathFindExtension(str),L".wav")==0)
|
|
{
|
|
Strcpy(text,_countof(text),str);
|
|
DoEnvironmentSubst(text,_countof(text));
|
|
}
|
|
else
|
|
text[0]=0;
|
|
if (BrowseForSound(m_hWnd,text))
|
|
{
|
|
m_EditBox.SetWindowText(text);
|
|
}
|
|
SendMessage(WM_NEXTDLGCTL,(LPARAM)m_EditBox.m_hWnd,TRUE);
|
|
m_EditBox.SetFocus();
|
|
m_bIgnoreFocus=false;
|
|
}
|
|
else if (m_EditMode==EDIT_COLOR)
|
|
{
|
|
m_bIgnoreFocus=true;
|
|
CString str;
|
|
m_EditBox.GetWindowText(str);
|
|
str.TrimLeft(); str.TrimRight();
|
|
COLORREF val=RgbToBgr(ParseColor(str));
|
|
static COLORREF customColors[16];
|
|
CHOOSECOLOR choose={sizeof(choose),m_hWnd,NULL,val,customColors};
|
|
choose.Flags=CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT;
|
|
if (ChooseColor(&choose))
|
|
{
|
|
wchar_t text[100];
|
|
Sprintf(text,_countof(text),L"%06X",BgrToRgb(choose.rgbResult));
|
|
m_EditBox.SetWindowText(text);
|
|
ApplyEditBox();
|
|
UpdateGroup(m_pEditSetting);
|
|
m_Tree.Invalidate();
|
|
}
|
|
SendMessage(WM_NEXTDLGCTL,(LPARAM)m_EditBox.m_hWnd,TRUE);
|
|
m_EditBox.SetFocus();
|
|
m_bIgnoreFocus=false;
|
|
}
|
|
else if (m_EditMode==EDIT_FONT)
|
|
{
|
|
m_bIgnoreFocus=true;
|
|
CString text;
|
|
m_EditBox.GetWindowText(text);
|
|
|
|
HDC hdc=::GetDC(NULL);
|
|
int dpi=GetDeviceCaps(hdc,LOGPIXELSY);
|
|
::ReleaseDC(NULL,hdc);
|
|
|
|
LOGFONT font={0};
|
|
const wchar_t *str=text;
|
|
while (*str==' ')
|
|
str++;
|
|
str=GetToken(str,font.lfFaceName,_countof(font.lfFaceName),L",");
|
|
int len=Strlen(font.lfFaceName);
|
|
while (len>0 && font.lfFaceName[len-1]==' ')
|
|
font.lfFaceName[--len]=0;
|
|
while (*str==' ')
|
|
str++;
|
|
wchar_t token[256];
|
|
str=GetToken(str,token,_countof(token),L",");
|
|
len=Strlen(token);
|
|
while (len>0 && token[len-1]==' ')
|
|
token[--len]=0;
|
|
font.lfWeight=FW_NORMAL;
|
|
if (_wcsicmp(token,L"bold")==0)
|
|
font.lfWeight=FW_BOLD;
|
|
else if (_wcsicmp(token,L"italic")==0)
|
|
font.lfItalic=1;
|
|
else if (_wcsicmp(token,L"bold_italic")==0)
|
|
font.lfWeight=FW_BOLD, font.lfItalic=1;
|
|
str=GetToken(str,token,_countof(token),L", \t");
|
|
font.lfHeight=-(_wtol(token)*dpi+36)/72;
|
|
|
|
CHOOSEFONT choose={sizeof(choose),m_hWnd,NULL,&font};
|
|
choose.Flags=CF_NOSCRIPTSEL;
|
|
if (*font.lfFaceName)
|
|
choose.Flags|=CF_INITTOLOGFONTSTRUCT;
|
|
if (ChooseFont(&choose))
|
|
{
|
|
wchar_t text[256];
|
|
const wchar_t *type=font.lfItalic?L"italic":L"normal";
|
|
if (font.lfWeight>=FW_BOLD)
|
|
type=font.lfItalic?L"bold_italic":L"bold";
|
|
Sprintf(text,_countof(text),L"%s, %s, %d",font.lfFaceName,type,(-font.lfHeight*72+dpi/2)/dpi);
|
|
m_EditBox.SetWindowText(text);
|
|
}
|
|
SendMessage(WM_NEXTDLGCTL,(LPARAM)m_EditBox.m_hWnd,TRUE);
|
|
m_EditBox.SetFocus();
|
|
m_bIgnoreFocus=false;
|
|
}
|
|
else if (m_EditMode==EDIT_DIRECTORY)
|
|
{
|
|
m_bIgnoreFocus=true;
|
|
CString str;
|
|
m_EditBox.GetWindowText(str);
|
|
str.TrimLeft(); str.TrimRight();
|
|
wchar_t text[1024];
|
|
DWORD dwAttrs=GetFileAttributes(str); // ensure directory exists before passing it to dialog
|
|
if (dwAttrs!=INVALID_FILE_ATTRIBUTES && dwAttrs&FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
Strcpy(text,_countof(text),str);
|
|
DoEnvironmentSubst(text,_countof(text));
|
|
}
|
|
else
|
|
text[0]=0;
|
|
Strcpy(text,_countof(text),str);
|
|
DoEnvironmentSubst(text,_countof(text));
|
|
if (BrowseLinkHelper(m_hWnd,text,true))
|
|
m_EditBox.SetWindowText(text);
|
|
SendMessage(WM_NEXTDLGCTL,(LPARAM)m_EditBox.m_hWnd,TRUE);
|
|
m_EditBox.SetFocus();
|
|
m_bIgnoreFocus=false;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnPlay( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
|
|
{
|
|
PlayItem(TreeView_GetSelection(m_Tree));
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnCustomDraw( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
NMTVCUSTOMDRAW *pDraw=(NMTVCUSTOMDRAW*)pnmh;
|
|
if (pDraw->nmcd.dwDrawStage==CDDS_PREPAINT)
|
|
{
|
|
UpdateEditPosition();
|
|
return CDRF_NOTIFYITEMDRAW;
|
|
}
|
|
else if (pDraw->nmcd.dwDrawStage==CDDS_ITEMPREPAINT)
|
|
{
|
|
TVITEM item={TVIF_IMAGE|TVIF_STATE,(HTREEITEM)pDraw->nmcd.dwItemSpec,0,TVIS_SELECTED};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
if ((item.state&TVIS_CUT) && (!(item.state&TVIS_SELECTED) || IsAppThemed()))
|
|
pDraw->clrText=GetSysColor(COLOR_GRAYTEXT);
|
|
}
|
|
return CDRF_DODEFAULT;
|
|
}
|
|
|
|
void CTreeSettingsDlg::ToggleItem( HTREEITEM hItem, bool bDefault )
|
|
{
|
|
if (!hItem) return;
|
|
TVITEM item={TVIF_PARAM|TVIF_IMAGE|TVIF_STATE,hItem,0,TVIS_CUT};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
if (item.state&TVIS_CUT)
|
|
return;
|
|
CSetting *pSetting=(CSetting*)item.lParam;
|
|
if (pSetting->pLinkTo) pSetting=pSetting->pLinkTo;
|
|
if (bDefault)
|
|
{
|
|
if (pSetting->flags&CSetting::FLAG_DEFAULT)
|
|
return;
|
|
{
|
|
CSettingsLockWrite lock;
|
|
pSetting->flags|=CSetting::FLAG_DEFAULT;
|
|
pSetting->value=pSetting->defValue;
|
|
SetSettingsDirty();
|
|
}
|
|
if (m_pEditSetting && (m_pEditSetting==pSetting || m_pEditSetting->pLinkTo==pSetting))
|
|
{
|
|
m_pEditSetting=NULL;
|
|
ItemSelected(item.hItem,pSetting,true);
|
|
}
|
|
if (pSetting->flags&CSetting::FLAG_CALLBACK)
|
|
{
|
|
SettingChangedCallback(pSetting);
|
|
}
|
|
UpdateGroup(pSetting);
|
|
}
|
|
else if (pSetting->type==CSetting::TYPE_BOOL)
|
|
{
|
|
// toggle
|
|
bool state=IsVariantTrue(pSetting->value);
|
|
{
|
|
CSettingsLockWrite lock;
|
|
pSetting->value=CComVariant(state?0:1);
|
|
pSetting->flags&=~CSetting::FLAG_DEFAULT;
|
|
SetSettingsDirty();
|
|
}
|
|
if (pSetting->flags&CSetting::FLAG_CALLBACK)
|
|
{
|
|
SettingChangedCallback(pSetting);
|
|
}
|
|
UpdateGroup(pSetting);
|
|
}
|
|
else if (pSetting->type==CSetting::TYPE_RADIO)
|
|
{
|
|
// set parent's value
|
|
for (CSetting *pParent=pSetting-1;;pParent--)
|
|
{
|
|
if (pParent->type!=CSetting::TYPE_RADIO)
|
|
{
|
|
CSetting *pTarget=pParent->pLinkTo?pParent->pLinkTo:pParent;
|
|
Assert(pTarget->type==CSetting::TYPE_INT);
|
|
int val=(int)(pSetting-pParent-1);
|
|
if (pTarget->value.vt==VT_I4 && pTarget->value.intVal==val)
|
|
break;
|
|
{
|
|
CSettingsLockWrite lock;
|
|
pTarget->value=CComVariant(val);
|
|
pTarget->flags&=~CSetting::FLAG_DEFAULT;
|
|
SetSettingsDirty();
|
|
}
|
|
if (pParent->flags&CSetting::FLAG_CALLBACK)
|
|
{
|
|
SettingChangedCallback(pParent);
|
|
}
|
|
UpdateGroup(pParent);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CTreeSettingsDlg::PlayItem( HTREEITEM hItem )
|
|
{
|
|
if (!hItem) return;
|
|
TVITEM item={TVIF_PARAM,hItem};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
CSetting *pSetting=(CSetting*)item.lParam;
|
|
if (pSetting->type==CSetting::TYPE_SOUND && pSetting->GetValue().vt==VT_BSTR)
|
|
{
|
|
if (!*pSetting->GetValue().bstrVal)
|
|
return;
|
|
wchar_t path[_MAX_PATH];
|
|
Strcpy(path,_countof(path),pSetting->GetValue().bstrVal);
|
|
DoEnvironmentSubst(path,_countof(path));
|
|
if (_wcsicmp(PathFindExtension(path),L"wav")==0)
|
|
PlaySound(path,NULL,SND_FILENAME|SND_ASYNC|SND_NODEFAULT|SND_SYSTEM);
|
|
else
|
|
PlaySound(path,NULL,SND_APPLICATION|SND_ALIAS|SND_ASYNC|SND_NODEFAULT|SND_SYSTEM);
|
|
}
|
|
}
|
|
|
|
void CTreeSettingsDlg::LocateSetting( const CSetting *pSetting )
|
|
{
|
|
for (const CSetting *pGroup=pSetting;;pGroup--)
|
|
{
|
|
if (pGroup->type==CSetting::TYPE_GROUP)
|
|
{
|
|
SelectSettingsTab(pGroup->nameID,true,pSetting);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnClick( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
DWORD pos=GetMessagePos();
|
|
TVHITTESTINFO test={{(short)LOWORD(pos),(short)HIWORD(pos)}};
|
|
m_Tree.ScreenToClient(&test.pt);
|
|
if (TreeView_HitTest(m_Tree,&test) && (test.flags&(TVHT_ONITEMICON|TVHT_ONITEMLABEL)))
|
|
ToggleItem(test.hItem,GetKeyState(VK_CONTROL)<0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnContextMenu( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
if ((HWND)wParam!=m_Tree.m_hWnd)
|
|
return 0;
|
|
HTREEITEM hItem=NULL;
|
|
POINT pt;
|
|
if ((DWORD)lParam==0xFFFFFFFF)
|
|
{
|
|
// keyboard
|
|
hItem=TreeView_GetSelection(m_Tree);
|
|
if (hItem)
|
|
{
|
|
RECT rc;
|
|
TreeView_GetItemRect(m_Tree,hItem,&rc,TRUE);
|
|
pt.x=(rc.left+rc.right)/2;
|
|
pt.y=(rc.top+rc.bottom)/2;
|
|
}
|
|
else
|
|
pt.x=pt.y=0;
|
|
m_Tree.ClientToScreen(&pt);
|
|
}
|
|
else
|
|
{
|
|
DWORD pos=GetMessagePos();
|
|
pt.x=(short)LOWORD(pos);
|
|
pt.y=(short)HIWORD(pos);
|
|
TVHITTESTINFO test={pt};
|
|
m_Tree.ScreenToClient(&test.pt);
|
|
if (TreeView_HitTest(m_Tree,&test) && (test.flags&(TVHT_ONITEMICON|TVHT_ONITEMLABEL)))
|
|
{
|
|
TreeView_SelectItem(m_Tree,test.hItem);
|
|
hItem=test.hItem;
|
|
}
|
|
}
|
|
|
|
if (!hItem) return 0;
|
|
|
|
TVITEM item={TVIF_PARAM|TVIF_IMAGE|TVIF_STATE,hItem,0,TVIS_CUT};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
CSetting *pSetting=(CSetting*)item.lParam;
|
|
|
|
enum
|
|
{
|
|
CMD_TOGGLE=1,
|
|
CMD_DEFAULT,
|
|
CMD_PLAY,
|
|
CMD_LOCATE,
|
|
};
|
|
|
|
HMENU menu=CreatePopupMenu();
|
|
if (pSetting->type!=CSetting::TYPE_RADIO)
|
|
{
|
|
if (pSetting->type==CSetting::TYPE_BOOL)
|
|
{
|
|
AppendMenu(menu,MF_STRING,CMD_TOGGLE,LoadStringEx(IDS_TOGGLE_SETTING));
|
|
if (item.state&TVIS_CUT)
|
|
EnableMenuItem(menu,CMD_TOGGLE,MF_BYCOMMAND|MF_GRAYED);
|
|
}
|
|
if (!(pSetting->flags&CSetting::FLAG_NODEFAULT))
|
|
{
|
|
AppendMenu(menu,MF_STRING,CMD_DEFAULT,LoadStringEx(IDS_DEFAULT_SETTING));
|
|
if ((item.state&TVIS_CUT) || pSetting->IsDefault())
|
|
EnableMenuItem(menu,CMD_DEFAULT,MF_BYCOMMAND|MF_GRAYED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AppendMenu(menu,MF_STRING,1,LoadStringEx(IDS_SELECT_SETTING));
|
|
if (item.state&TVIS_CUT)
|
|
EnableMenuItem(menu,1,MF_BYCOMMAND|MF_GRAYED);
|
|
}
|
|
if (pSetting->type==CSetting::TYPE_SOUND)
|
|
{
|
|
AppendMenu(menu,MF_STRING,CMD_PLAY,LoadStringEx(IDS_PLAY_SETTING));
|
|
if (pSetting->GetValue().vt!=VT_BSTR || *pSetting->GetValue().bstrVal==0)
|
|
EnableMenuItem(menu,CMD_PLAY,MF_BYCOMMAND|MF_GRAYED);
|
|
}
|
|
if (m_bSearch)
|
|
AppendMenu(menu,MF_STRING,CMD_LOCATE,LoadStringEx(IDS_LOCATE_SETTING));
|
|
|
|
int res=TrackPopupMenu(menu,TPM_RIGHTBUTTON|TPM_RETURNCMD,pt.x,pt.y,0,m_hWnd,NULL);
|
|
DestroyMenu(menu);
|
|
if (res==CMD_TOGGLE)
|
|
ToggleItem(hItem,false);
|
|
if (res==CMD_DEFAULT)
|
|
ToggleItem(hItem,true);
|
|
if (res==CMD_PLAY)
|
|
PlayItem(hItem);
|
|
if (res==CMD_LOCATE)
|
|
LocateSetting(pSetting);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnKeyDown( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
NMTVKEYDOWN *pKey=(NMTVKEYDOWN*)pnmh;
|
|
if (pKey->wVKey==VK_SPACE && GetKeyState(VK_MENU)>=0)
|
|
{
|
|
ToggleItem(TreeView_GetSelection(m_Tree),(GetKeyState(VK_CONTROL)<0));
|
|
return 1;
|
|
}
|
|
if (pKey->wVKey=='P' && GetKeyState(VK_CONTROL)<0)
|
|
{
|
|
PlayItem(TreeView_GetSelection(m_Tree));
|
|
return 1;
|
|
}
|
|
bHandled=FALSE;
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnGetInfoTip( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
NMTVGETINFOTIP *pTip=(NMTVGETINFOTIP*)pnmh;
|
|
const CSetting *pSetting=(CSetting*)pTip->lParam;
|
|
if (pSetting->IsLocked())
|
|
Sprintf(pTip->pszText,pTip->cchTextMax,L"%s\n%s",LoadStringEx(pSetting->tipID),LoadStringEx(pSetting->IsLockedReg()?IDS_SETTING_LOCKED:IDS_SETTING_LOCKED_GP));
|
|
else
|
|
Strcpy(pTip->pszText,pTip->cchTextMax,LoadStringEx(pSetting->tipID));
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CTreeSettingsDlg::OnSelChanged( int idCtrl, LPNMHDR pnmh, BOOL& bHandled )
|
|
{
|
|
HTREEITEM hItem=TreeView_GetSelection(m_Tree);
|
|
if (hItem)
|
|
{
|
|
TVITEM item={TVIF_PARAM|TVIF_STATE,hItem,0,TVIS_CUT};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
CSetting *pSetting=(CSetting*)item.lParam;
|
|
ItemSelected(item.hItem,pSetting,(item.state&TVIS_CUT)==0);
|
|
}
|
|
else
|
|
ItemSelected(NULL,NULL,false);
|
|
return 0;
|
|
}
|
|
|
|
void CTreeSettingsDlg::ApplyEditBox( void )
|
|
{
|
|
if (m_pEditSetting)
|
|
{
|
|
{
|
|
CSettingsLockWrite lock;
|
|
|
|
CString str;
|
|
m_EditBox.GetWindowText(str);
|
|
str.TrimLeft(); str.TrimRight();
|
|
CSetting *pSetting=m_pEditSetting->pLinkTo?m_pEditSetting->pLinkTo:m_pEditSetting;
|
|
if (pSetting->type==CSetting::TYPE_INT)
|
|
{
|
|
int val=_wtol(str);
|
|
if (pSetting->value.vt!=VT_I4 || pSetting->value.intVal!=val)
|
|
{
|
|
pSetting->value=CComVariant(val);
|
|
pSetting->flags&=~CSetting::FLAG_DEFAULT;
|
|
}
|
|
}
|
|
else if (pSetting->type==CSetting::TYPE_COLOR)
|
|
{
|
|
int val=RgbToBgr(ParseColor(str));
|
|
if (pSetting->value.vt!=VT_I4 || pSetting->value.intVal!=val)
|
|
{
|
|
pSetting->value=CComVariant(val);
|
|
pSetting->flags&=~CSetting::FLAG_DEFAULT;
|
|
}
|
|
}
|
|
else if (pSetting->type==CSetting::TYPE_HOTKEY || pSetting->type==CSetting::TYPE_HOTKEY_ANY)
|
|
{
|
|
if (pSetting->value.vt!=VT_I4 || pSetting->value.intVal!=g_HotKey)
|
|
{
|
|
pSetting->value=CComVariant(g_HotKey);
|
|
pSetting->flags&=~CSetting::FLAG_DEFAULT;
|
|
}
|
|
}
|
|
else if (pSetting->type==CSetting::TYPE_DIRECTORY)
|
|
{
|
|
if (pSetting->value.vt!=VT_BSTR || str!=pSetting->value.bstrVal)
|
|
{
|
|
if (str.IsEmpty()) // empty directory strings cause unexpected behavior, so we reset to avoid this
|
|
pSetting->value=pSetting->defValue;
|
|
else // otherwise we are very lenient about what users can input as a path
|
|
pSetting->value=CComVariant(str);
|
|
if (pSetting->value==pSetting->defValue)
|
|
pSetting->flags|=CSetting::FLAG_DEFAULT;
|
|
else
|
|
pSetting->flags&=~CSetting::FLAG_DEFAULT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pSetting->value.vt!=VT_BSTR || str!=pSetting->value.bstrVal)
|
|
{
|
|
pSetting->value=CComVariant(str);
|
|
pSetting->flags&=~CSetting::FLAG_DEFAULT;
|
|
}
|
|
}
|
|
SetSettingsDirty();
|
|
}
|
|
if (m_pEditSetting->flags&CSetting::FLAG_CALLBACK)
|
|
{
|
|
SettingChangedCallback(m_pEditSetting);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CTreeSettingsDlg::ItemSelected( HTREEITEM hItem, CSetting *pSetting, bool bEnabled )
|
|
{
|
|
if (m_pEditSetting)
|
|
{
|
|
ApplyEditBox();
|
|
const CSetting *pOld=m_pEditSetting;
|
|
m_pEditSetting=NULL;
|
|
UpdateGroup(pOld);
|
|
}
|
|
m_EditItem=NULL;
|
|
TEditMode mode=EDIT_NONE;
|
|
wchar_t text[2048];
|
|
if (pSetting)
|
|
{
|
|
const CComVariant &valVar=pSetting->GetValue();
|
|
if (pSetting->type==CSetting::TYPE_INT && pSetting[1].type!=CSetting::TYPE_RADIO)
|
|
{
|
|
mode=EDIT_INT;
|
|
int val=0;
|
|
if (valVar.vt==VT_I4)
|
|
val=valVar.intVal;
|
|
Sprintf(text,_countof(text),L"%d",val);
|
|
}
|
|
else if (pSetting->type==CSetting::TYPE_STRING || pSetting->type==CSetting::TYPE_ICON || pSetting->type==CSetting::TYPE_BITMAP || pSetting->type==CSetting::TYPE_BITMAP_JPG || pSetting->type==CSetting::TYPE_SOUND || pSetting->type==CSetting::TYPE_FONT || pSetting->type==CSetting::TYPE_DIRECTORY)
|
|
{
|
|
if (valVar.vt==VT_BSTR)
|
|
Strcpy(text,_countof(text),valVar.bstrVal);
|
|
else
|
|
text[0]=0;
|
|
if (pSetting->type==CSetting::TYPE_STRING)
|
|
mode=EDIT_STRING;
|
|
else if (pSetting->type==CSetting::TYPE_ICON)
|
|
mode=EDIT_ICON;
|
|
else if (pSetting->type==CSetting::TYPE_BITMAP)
|
|
mode=EDIT_BITMAP;
|
|
else if (pSetting->type==CSetting::TYPE_BITMAP_JPG)
|
|
mode=EDIT_BITMAP_JPG;
|
|
else if (pSetting->type==CSetting::TYPE_SOUND)
|
|
mode=EDIT_SOUND;
|
|
else if (pSetting->type==CSetting::TYPE_FONT)
|
|
mode=EDIT_FONT;
|
|
else
|
|
mode=EDIT_DIRECTORY;
|
|
}
|
|
else if (pSetting->type==CSetting::TYPE_HOTKEY || pSetting->type==CSetting::TYPE_HOTKEY_ANY)
|
|
{
|
|
text[0]=0;
|
|
g_HotKey=0;
|
|
if (valVar.vt==VT_I4)
|
|
{
|
|
g_HotKey=valVar.intVal;
|
|
GetKeyName(valVar.intVal,text,_countof(text),false,false,false);
|
|
}
|
|
if (bEnabled)
|
|
mode=pSetting->type==CSetting::TYPE_HOTKEY_ANY?EDIT_HOTKEY_ANY:EDIT_HOTKEY;
|
|
}
|
|
else if (pSetting->type==CSetting::TYPE_COLOR)
|
|
{
|
|
mode=EDIT_COLOR;
|
|
int val=0;
|
|
if (valVar.vt==VT_I4)
|
|
val=BgrToRgb(valVar.intVal);
|
|
Sprintf(text,_countof(text),L"%06X",val);
|
|
}
|
|
}
|
|
|
|
RECT rc;
|
|
m_EditMode=mode;
|
|
if (mode!=EDIT_NONE)
|
|
{
|
|
CString str=LoadStringEx(pSetting->nameID);
|
|
TVITEM item={TVIF_TEXT,hItem,0,0,(LPWSTR)(LPCWSTR)str};
|
|
TreeView_SetItem(m_Tree,&item);
|
|
m_Tree.GetClientRect(&rc);
|
|
int w=rc.right;
|
|
TreeView_GetItemRect(m_Tree,hItem,&rc,TRUE);
|
|
rc.left=rc.right;
|
|
rc.right=w;
|
|
m_EditItem=hItem;
|
|
m_pEditSetting=pSetting;
|
|
}
|
|
|
|
if (mode==EDIT_ICON || mode==EDIT_BITMAP || mode==EDIT_BITMAP_JPG || mode==EDIT_SOUND || mode==EDIT_FONT || mode==EDIT_COLOR || mode==EDIT_DIRECTORY)
|
|
{
|
|
RECT rc2=rc;
|
|
int width=(rc2.bottom-rc2.top)*3/2;
|
|
rc2.left=rc2.right-width;
|
|
if (mode==EDIT_SOUND)
|
|
{
|
|
m_PlayButton.SetWindowPos(NULL,&rc2,SWP_NOZORDER|SWP_SHOWWINDOW);
|
|
rc2.left-=width;
|
|
rc2.right-=width;
|
|
}
|
|
else
|
|
m_PlayButton.ShowWindow(SW_HIDE);
|
|
m_BrowseButton.SetWindowPos(NULL,&rc2,SWP_NOZORDER|SWP_SHOWWINDOW);
|
|
m_BrowseButton.EnableWindow(bEnabled);
|
|
rc.right=rc2.left;
|
|
}
|
|
else
|
|
{
|
|
m_BrowseButton.ShowWindow(SW_HIDE);
|
|
m_PlayButton.ShowWindow(SW_HIDE);
|
|
}
|
|
|
|
if (mode!=EDIT_NONE)
|
|
{
|
|
m_EditBox.SetWindowText(text);
|
|
m_EditBox.SendMessage(EM_SETREADONLY,!bEnabled,0);
|
|
m_EditBox.SetWindowPos(NULL,&rc,SWP_NOZORDER|SWP_SHOWWINDOW);
|
|
SendMessage(WM_NEXTDLGCTL,(LPARAM)m_EditBox.m_hWnd,TRUE);
|
|
SetWindowSubclass(m_EditBox,SubclassEditProc,'CLSH',(mode==EDIT_HOTKEY)?1:((mode==EDIT_HOTKEY_ANY)?2:0));
|
|
}
|
|
else
|
|
m_EditBox.ShowWindow(SW_HIDE);
|
|
}
|
|
|
|
void CTreeSettingsDlg::UpdateEditPosition( void )
|
|
{
|
|
if (m_EditMode==EDIT_NONE) return;
|
|
|
|
RECT rc;
|
|
m_Tree.GetClientRect(&rc);
|
|
int w=rc.right;
|
|
TreeView_GetItemRect(m_Tree,m_EditItem,&rc,TRUE);
|
|
rc.left=rc.right;
|
|
rc.right=w;
|
|
w-=rc.left;
|
|
int width=(rc.bottom-rc.top)*3/2;
|
|
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
HFONT font0=(HFONT)SelectObject(hdc,m_EditBox.GetFont());
|
|
SIZE size;
|
|
CString str;
|
|
m_EditBox.GetWindowText(str);
|
|
GetTextExtentPoint(hdc,str,str.GetLength(),&size);
|
|
SelectObject(hdc,font0);
|
|
DeleteDC(hdc);
|
|
DWORD margins=(DWORD)m_EditBox.SendMessage(EM_GETMARGINS);
|
|
size.cx+=HIWORD(margins)+LOWORD(margins)+12;
|
|
// adjust size and position of edit boxes for settings that use browse/play buttons
|
|
if (m_EditMode==EDIT_ICON || m_EditMode==EDIT_BITMAP || m_EditMode==EDIT_BITMAP_JPG || m_EditMode==EDIT_FONT || m_EditMode==EDIT_COLOR || m_EditMode==EDIT_DIRECTORY)
|
|
size.cx+=width;
|
|
if (m_EditMode==EDIT_SOUND)
|
|
size.cx+=width*2;
|
|
if (size.cx<w)
|
|
rc.right=rc.left+size.cx;
|
|
|
|
if (m_EditMode==EDIT_ICON || m_EditMode==EDIT_BITMAP || m_EditMode==EDIT_BITMAP_JPG || m_EditMode==EDIT_SOUND || m_EditMode==EDIT_FONT || m_EditMode==EDIT_COLOR || m_EditMode==EDIT_DIRECTORY)
|
|
{
|
|
RECT rc2=rc;
|
|
rc2.left=rc2.right-width;
|
|
if (m_EditMode==EDIT_SOUND)
|
|
{
|
|
m_PlayButton.SetWindowPos(NULL,&rc2,SWP_NOZORDER|SWP_NOCOPYBITS);
|
|
rc2.left-=width;
|
|
rc2.right-=width;
|
|
}
|
|
m_BrowseButton.SetWindowPos(NULL,&rc2,SWP_NOZORDER|SWP_NOCOPYBITS);
|
|
rc.right=rc2.left;
|
|
}
|
|
|
|
m_EditBox.SetWindowPos(NULL,&rc,SWP_NOZORDER|SWP_NOCOPYBITS);
|
|
}
|
|
|
|
bool CTreeSettingsDlg::IsVisible( const CSetting *pSetting, const wchar_t *filter ) const
|
|
{
|
|
if (pSetting->flags&CSetting::FLAG_HIDDEN)
|
|
return false;
|
|
if (!pSetting->MatchFilter(filter))
|
|
return false;
|
|
int style, mask;
|
|
GetSettingsStyle(style,mask);
|
|
if ((pSetting->flags&mask) && !(pSetting->flags&style))
|
|
return false;
|
|
if (pSetting->type==CSetting::TYPE_RADIO)
|
|
{
|
|
while (pSetting->type==CSetting::TYPE_RADIO)
|
|
pSetting--;
|
|
return IsVisible(pSetting,filter);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const CSetting *CTreeSettingsDlg::GetNextSetting( const CSetting *pSetting, const wchar_t *filter )
|
|
{
|
|
pSetting++;
|
|
while (pSetting->type==CSetting::TYPE_RADIO)
|
|
{
|
|
if (!(pSetting->flags&CSetting::FLAG_HIDDEN))
|
|
return pSetting;
|
|
pSetting++;
|
|
}
|
|
|
|
if (*filter)
|
|
{
|
|
while (pSetting->name && (pSetting->type==CSetting::TYPE_GROUP || !IsVisible(pSetting,filter) || !pSetting->MatchFilter(filter)))
|
|
{
|
|
if (pSetting->type==CSetting::TYPE_GROUP && (pSetting->flags&CSetting::FLAG_HIDDEN))
|
|
{
|
|
// if this is a hidden group skip to the next
|
|
pSetting++;
|
|
while (pSetting->type!=CSetting::TYPE_GROUP)
|
|
pSetting++;
|
|
}
|
|
pSetting++;
|
|
}
|
|
}
|
|
else if (m_bBasic)
|
|
{
|
|
while (pSetting->name && (pSetting->type==CSetting::TYPE_GROUP || !IsVisible(pSetting,filter) || !(pSetting->flags&CSetting::FLAG_BASIC)))
|
|
pSetting++;
|
|
}
|
|
else
|
|
{
|
|
while (pSetting->name && pSetting->type!=CSetting::TYPE_GROUP && !IsVisible(pSetting,filter))
|
|
pSetting++;
|
|
}
|
|
|
|
if (pSetting->name && pSetting->type!=CSetting::TYPE_GROUP)
|
|
return pSetting;
|
|
return NULL;
|
|
}
|
|
|
|
HTREEITEM CTreeSettingsDlg::GetNextItem( HTREEITEM hItem, bool bChildren )
|
|
{
|
|
if (!hItem) return NULL;
|
|
if (bChildren)
|
|
{
|
|
HTREEITEM hNext=TreeView_GetChild(m_Tree,hItem);
|
|
if (hNext) return hNext;
|
|
}
|
|
{
|
|
HTREEITEM hNext=TreeView_GetNextSibling(m_Tree,hItem);
|
|
if (hNext) return hNext;
|
|
}
|
|
return GetNextItem(TreeView_GetParent(m_Tree,hItem),false);
|
|
}
|
|
|
|
HTREEITEM CTreeSettingsDlg::FindSettingsItem( const wchar_t *name )
|
|
{
|
|
HTREEITEM res=NULL;
|
|
for (HTREEITEM hItem=TreeView_GetRoot(m_Tree);hItem;hItem=GetNextItem(hItem))
|
|
{
|
|
TVITEM item={TVIF_PARAM,hItem};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
const CSetting *pSetting=(CSetting*)item.lParam;
|
|
if (pSetting && wcscmp(name,pSetting->name)==0)
|
|
res=hItem;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void CTreeSettingsDlg::SetGroup( CSetting *pGroup, const CString &filter, const CSetting *pSelect )
|
|
{
|
|
ItemSelected(NULL,NULL,false);
|
|
m_pGroup=pGroup;
|
|
// fill tree control
|
|
m_Tree.SendMessage(WM_SETREDRAW,FALSE);
|
|
TreeView_SelectItem(m_Tree,NULL);
|
|
TreeView_DeleteAllItems(m_Tree);
|
|
int level=0;
|
|
HTREEITEM hRadioParent=NULL;
|
|
m_bSearch=!filter.IsEmpty();
|
|
m_bBasic=(pGroup->nameID==IDS_BASIC_SETTINGS);
|
|
HTREEITEM hSelect=NULL;
|
|
for (const CSetting *pSetting=GetNextSetting(pGroup,filter);pSetting;pSetting=GetNextSetting(pSetting,filter))
|
|
{
|
|
wchar_t text[256];
|
|
text[0]=0;
|
|
if (pSetting->type==CSetting::TYPE_BOOL || pSetting->type==CSetting::TYPE_RADIO || (pSetting->type==CSetting::TYPE_INT && pSetting[1].type==CSetting::TYPE_RADIO))
|
|
{
|
|
// the text for BOOL, RADIO or RADIO's parent items doesn't change
|
|
Strcpy(text,_countof(text),LoadStringEx(pSetting->nameID));
|
|
}
|
|
if (pSetting->type!=CSetting::TYPE_RADIO)
|
|
hRadioParent=NULL;
|
|
HTREEITEM hParent=hRadioParent;
|
|
if (pSetting->nest)
|
|
{
|
|
Assert(pSetting->type!=CSetting::TYPE_RADIO);
|
|
hParent=FindSettingsItem(pSetting->nest);
|
|
}
|
|
TVINSERTSTRUCT insert={hParent,TVI_LAST,{TVIF_STATE|TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM,NULL,TVIS_EXPANDED,TVIS_EXPANDED,text,0,SETTING_STATE_SETTING,SETTING_STATE_SETTING}};
|
|
insert.item.lParam=(LPARAM)pSetting;
|
|
if (pSetting->IsLocked())
|
|
{
|
|
insert.item.state|=INDEXTOOVERLAYMASK(1);
|
|
insert.item.stateMask|=TVIS_OVERLAYMASK;
|
|
}
|
|
else if (pSetting->flags&CSetting::FLAG_WARNING)
|
|
{
|
|
insert.item.state|=INDEXTOOVERLAYMASK(2);
|
|
insert.item.stateMask|=TVIS_OVERLAYMASK;
|
|
}
|
|
HTREEITEM hItem=TreeView_InsertItem(m_Tree,&insert);
|
|
if (pSetting->type!=CSetting::TYPE_RADIO)
|
|
hRadioParent=hItem;
|
|
if (pSetting==pSelect)
|
|
hSelect=hItem;
|
|
}
|
|
UpdateGroup(NULL);
|
|
m_Tree.SendMessage(WM_SETREDRAW,TRUE);
|
|
if (hSelect)
|
|
{
|
|
TreeView_SelectItem(m_Tree,hSelect);
|
|
m_Tree.PostMessage(TVM_ENSUREVISIBLE,0,(LPARAM)hSelect); // post instead of send, because the tree may be resized afterwards
|
|
}
|
|
m_Tree.Invalidate();
|
|
}
|
|
|
|
void CTreeSettingsDlg::UpdateGroup( const CSetting *pModified )
|
|
{
|
|
for (HTREEITEM hItem=TreeView_GetRoot(m_Tree);hItem;hItem=GetNextItem(hItem))
|
|
{
|
|
wchar_t text[256];
|
|
TVITEM item={TVIF_PARAM|TVIF_STATE|TVIF_IMAGE,hItem,0,TVIS_BOLD|TVIS_CUT,text};
|
|
TreeView_GetItem(m_Tree,&item);
|
|
const CSetting *pSetting=(CSetting*)item.lParam;
|
|
if (pSetting->type==CSetting::TYPE_RADIO) continue;
|
|
|
|
// check if the item is enabled
|
|
bool bEnabled=pSetting->IsEnabled();
|
|
|
|
// check if the item is default
|
|
bool bDefault=pSetting->IsDefault();
|
|
const CComVariant &valVar=pSetting->GetValue();
|
|
|
|
// check if modified items should be bold
|
|
bool bBoldSettings=GetSettingBool(L"BoldSettings");
|
|
|
|
// calculate text
|
|
if (pSetting!=m_pEditSetting)
|
|
{
|
|
if (pSetting->type==CSetting::TYPE_HOTKEY || pSetting->type==CSetting::TYPE_HOTKEY_ANY)
|
|
{
|
|
wchar_t val[100];
|
|
val[0]=0;
|
|
if (valVar.vt==VT_I4)
|
|
GetKeyName(valVar.intVal,val,_countof(val),false,false,false);
|
|
CString str=LoadStringEx(pSetting->nameID);
|
|
Sprintf(text,_countof(text),L"%s: %s",str,val);
|
|
item.mask|=TVIF_TEXT;
|
|
}
|
|
else if (pSetting->type>=CSetting::TYPE_STRING)
|
|
{
|
|
CString str=LoadStringEx(pSetting->nameID);
|
|
const wchar_t *val=L"";
|
|
if (valVar.vt==VT_BSTR)
|
|
val=valVar.bstrVal;
|
|
Sprintf(text,_countof(text),L"%s: %s",str,val);
|
|
item.mask|=TVIF_TEXT;
|
|
}
|
|
else if (pSetting->type==CSetting::TYPE_INT && pSetting[1].type!=CSetting::TYPE_RADIO)
|
|
{
|
|
CString str=LoadStringEx(pSetting->nameID);
|
|
int val=0;
|
|
if (valVar.vt==VT_I4)
|
|
val=valVar.intVal;
|
|
Sprintf(text,_countof(text),L"%s: %d",str,val);
|
|
item.mask|=TVIF_TEXT;
|
|
}
|
|
else if (pSetting->type==CSetting::TYPE_COLOR)
|
|
{
|
|
CString str=LoadStringEx(pSetting->nameID);
|
|
int val=0;
|
|
if (valVar.vt==VT_I4)
|
|
val=BgrToRgb(valVar.intVal);
|
|
Sprintf(text,_countof(text),L"%s: %06X",str,val);
|
|
item.mask|=TVIF_TEXT;
|
|
}
|
|
}
|
|
|
|
// calculate state
|
|
int image=SETTING_STATE_SETTING;
|
|
if (pSetting->type==CSetting::TYPE_BOOL)
|
|
image=SETTING_STATE_CHECKBOX|(IsVariantTrue(valVar)?SETTING_STATE_CHECKED:0);
|
|
if (pSetting->type==CSetting::TYPE_COLOR)
|
|
{
|
|
image=SETTING_IMAGE_COLOR+(pSetting->flags>>24);
|
|
|
|
HIMAGELIST images=GetSettingsImageList(m_Tree);
|
|
int cx, cy;
|
|
ImageList_GetIconSize(images,&cx,&cy);
|
|
|
|
BITMAPINFO dib={sizeof(dib)};
|
|
dib.bmiHeader.biWidth=cx;
|
|
dib.bmiHeader.biHeight=cy;
|
|
dib.bmiHeader.biPlanes=1;
|
|
dib.bmiHeader.biBitCount=32;
|
|
dib.bmiHeader.biCompression=BI_RGB;
|
|
HDC hdc=CreateCompatibleDC(NULL);
|
|
HDC hdcMask=CreateCompatibleDC(NULL);
|
|
HBITMAP bmp=CreateDIBSection(hdc,&dib,DIB_RGB_COLORS,NULL,NULL,0);
|
|
HBITMAP bmpMask=CreateDIBSection(hdcMask,&dib,DIB_RGB_COLORS,NULL,NULL,0);
|
|
|
|
HGDIOBJ bmp0=SelectObject(hdc,bmp);
|
|
HGDIOBJ bmp1=SelectObject(hdcMask,bmpMask);
|
|
SetDCBrushColor(hdc,valVar.intVal&0xFFFFFF);
|
|
SetDCPenColor(hdc,0);
|
|
SelectObject(hdc,GetStockObject(DC_BRUSH));
|
|
SelectObject(hdc,GetStockObject(DC_PEN));
|
|
Rectangle(hdc,0,0,cx,cy);
|
|
RECT rc={0,0,cx,cy};
|
|
FillRect(hdcMask,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
|
|
SelectObject(hdc,bmp0);
|
|
SelectObject(hdcMask,bmp1);
|
|
ImageList_Replace(images,image,bmp,bmpMask);
|
|
DeleteObject(bmp);
|
|
DeleteObject(bmpMask);
|
|
DeleteDC(hdc);
|
|
DeleteDC(hdcMask);
|
|
}
|
|
int state=bDefault||!bBoldSettings?0:TVIS_BOLD; // check if item should be highlighted in bold
|
|
if (!bEnabled)
|
|
{
|
|
if (pSetting->type!=CSetting::TYPE_COLOR) image|=SETTING_STATE_DISABLED;
|
|
state|=TVIS_CUT;
|
|
}
|
|
if (item.iImage==image)
|
|
item.mask&=~TVIF_IMAGE;
|
|
else
|
|
item.iImage=item.iSelectedImage=image;
|
|
|
|
if ((item.state&(TVIS_BOLD|TVIS_CUT))==state)
|
|
item.mask&=~TVIF_STATE;
|
|
else
|
|
item.state=state;
|
|
if (item.mask!=0)
|
|
{
|
|
if (item.mask&TVIF_IMAGE)
|
|
item.mask|=TVIF_SELECTEDIMAGE;
|
|
TreeView_SetItem(m_Tree,&item);
|
|
RECT rc;
|
|
TreeView_GetItemRect(m_Tree,hItem,&rc,FALSE);
|
|
m_Tree.InvalidateRect(&rc);
|
|
}
|
|
|
|
// update radio buttons
|
|
if (pSetting->type==CSetting::TYPE_INT && pSetting[1].type==CSetting::TYPE_RADIO)
|
|
{
|
|
int val=0;
|
|
if (valVar.vt==VT_I4)
|
|
val=valVar.intVal;
|
|
for (HTREEITEM hRadio=TreeView_GetChild(m_Tree,hItem);hRadio;hRadio=TreeView_GetNextSibling(m_Tree,hRadio))
|
|
{
|
|
TVITEM radio={TVIF_IMAGE|TVIF_PARAM|TVIF_STATE,hRadio,0,TVIS_CUT};
|
|
TreeView_GetItem(m_Tree,&radio);
|
|
int v=(int)((CSetting*)radio.lParam-pSetting-1);
|
|
|
|
int image=SETTING_STATE_RADIO;
|
|
if (v==val) image|=SETTING_STATE_CHECKED;
|
|
int state=0;
|
|
if (!bEnabled)
|
|
{
|
|
if (pSetting->type!=CSetting::TYPE_COLOR) image|=SETTING_STATE_DISABLED;
|
|
state=TVIS_CUT;
|
|
}
|
|
|
|
if (radio.iImage!=image || radio.state!=state)
|
|
{
|
|
radio.iImage=radio.iSelectedImage=image;
|
|
radio.mask=TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_STATE;
|
|
radio.state=state;
|
|
TreeView_SetItem(m_Tree,&radio);
|
|
RECT rc;
|
|
TreeView_GetItemRect(m_Tree,hRadio,&rc,FALSE);
|
|
m_Tree.InvalidateRect(&rc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class CDefaultSettingsPanel: public ISettingsPanel
|
|
{
|
|
public:
|
|
virtual HWND Create( HWND parent );
|
|
virtual HWND Activate( CSetting *pGroup, const RECT &rect, bool bReset );
|
|
virtual bool Validate( HWND parent );
|
|
void SetFilter( const CString &filter ) { m_Filter=filter; }
|
|
void Select( const CSetting *pSelect ) { m_pSelect=pSelect; }
|
|
|
|
private:
|
|
static CTreeSettingsDlg s_Dialog;
|
|
CString m_Filter;
|
|
const CSetting *m_pSelect;
|
|
};
|
|
|
|
CTreeSettingsDlg CDefaultSettingsPanel::s_Dialog;
|
|
|
|
ISettingsPanel *GetDefaultSettings( const CString *filter, const CSetting *pSelect )
|
|
{
|
|
static CDefaultSettingsPanel panel;
|
|
if (filter)
|
|
panel.SetFilter(*filter);
|
|
if (pSelect)
|
|
panel.Select(pSelect);
|
|
return &panel;
|
|
}
|
|
|
|
HWND CDefaultSettingsPanel::Create( HWND parent )
|
|
{
|
|
if (!s_Dialog.m_hWnd)
|
|
s_Dialog.Create(parent,LoadDialogEx(IDD_SETTINGSTREE));
|
|
return s_Dialog.m_hWnd;
|
|
}
|
|
|
|
HWND CDefaultSettingsPanel::Activate( CSetting *pGroup, const RECT &rect, bool bReset )
|
|
{
|
|
s_Dialog.SetGroup(pGroup,m_Filter,m_pSelect);
|
|
m_pSelect=NULL;
|
|
s_Dialog.SetWindowPos(HWND_TOP,&rect,SWP_SHOWWINDOW);
|
|
return s_Dialog.m_hWnd;
|
|
}
|
|
|
|
bool CDefaultSettingsPanel::Validate( HWND parent )
|
|
{
|
|
s_Dialog.Validate();
|
|
return true;
|
|
}
|
|
|
|
DWORD RgbToBgr(DWORD val)
|
|
{
|
|
return ((val & 0xFF) << 16) | (val & 0xFF00) | ((val >> 16) & 0xFF);
|
|
}
|
|
|
|
DWORD BgrToRgb(DWORD val)
|
|
{
|
|
return RgbToBgr(val);
|
|
}
|
|
|
|
DWORD ParseColor(const wchar_t* str)
|
|
{
|
|
wchar_t* end;
|
|
return wcstoul(str, &end, 16) & 0xFFFFFF;
|
|
}
|