New Utility: New+ (#33136)
Co-authored-by: Jaime Bernardo <jaime@janeasystems.com> Co-authored-by: Stefan Markovic <stefan@janeasystems.com>
1
.github/actions/spell-check/allow/names.txt
vendored
@ -64,6 +64,7 @@ Essey
|
||||
ethanfangg
|
||||
ferraridavide
|
||||
frankychen
|
||||
gaardmark
|
||||
gabime
|
||||
Galaxi
|
||||
Garside
|
||||
|
24
.github/actions/spell-check/expect.txt
vendored
@ -80,6 +80,8 @@ asf
|
||||
AShortcut
|
||||
ASingle
|
||||
ASSOCCHANGED
|
||||
ASSOCF
|
||||
ASSOCSTR
|
||||
ASYNCWINDOWPLACEMENT
|
||||
ASYNCWINDOWPOS
|
||||
atl
|
||||
@ -318,6 +320,7 @@ Dedup
|
||||
DEFAULTBOOTSTRAPPERINSTALLFOLDER
|
||||
DEFAULTCOLOR
|
||||
DEFAULTFLAGS
|
||||
DEFAULTICON
|
||||
DEFAULTONLY
|
||||
DEFAULTTONEAREST
|
||||
DEFAULTTONULL
|
||||
@ -332,6 +335,7 @@ deletethis
|
||||
DENORMAL
|
||||
depersist
|
||||
deprioritized
|
||||
DESELECTOTHERS
|
||||
DESKTOPABSOLUTEEDITING
|
||||
DESKTOPABSOLUTEPARSING
|
||||
desktopshorcutinstalled
|
||||
@ -428,6 +432,7 @@ encodedlaunch
|
||||
encryptor
|
||||
endpointvolume
|
||||
ENDSESSION
|
||||
ENSUREVISIBLE
|
||||
ENTERSIZEMOVE
|
||||
ENU
|
||||
EOAC
|
||||
@ -509,6 +514,7 @@ FOLDERID
|
||||
folderpath
|
||||
FORCEMINIMIZE
|
||||
formatetc
|
||||
FORPARSING
|
||||
FRAMECHANGED
|
||||
frm
|
||||
Froml
|
||||
@ -563,6 +569,7 @@ Hashset
|
||||
hashtag
|
||||
HASHVAL
|
||||
HASSTRINGS
|
||||
HASSUBCOMMANDS
|
||||
hbitmap
|
||||
hbm
|
||||
hbmp
|
||||
@ -641,6 +648,7 @@ IBeam
|
||||
ICapture
|
||||
IClass
|
||||
ICONERROR
|
||||
ICONLOCATION
|
||||
IData
|
||||
IDD
|
||||
IDesktop
|
||||
@ -658,6 +666,7 @@ IFACEMETHOD
|
||||
IFACEMETHODIMP
|
||||
IFile
|
||||
IFilter
|
||||
IGNOREUNKNOWN
|
||||
IGraphics
|
||||
iid
|
||||
Iindex
|
||||
@ -719,6 +728,7 @@ ISettings
|
||||
IShell
|
||||
isocpp
|
||||
iss
|
||||
ISSEPARATOR
|
||||
ITask
|
||||
ith
|
||||
ITHUMBNAIL
|
||||
@ -994,6 +1004,8 @@ newdev
|
||||
NEWDIALOGSTYLE
|
||||
newitem
|
||||
newpath
|
||||
newplus
|
||||
NEWPLUSCONTEXTMENU
|
||||
newrow
|
||||
newsgroups
|
||||
NIF
|
||||
@ -1006,7 +1018,10 @@ NOAGGREGATION
|
||||
NOASYNC
|
||||
NOCLOSEPROCESS
|
||||
NOCOALESCE
|
||||
NOCOMM
|
||||
NOCONFIRMMKDIR
|
||||
NOCOPYBITS
|
||||
NOCOPYSECURITYATTRIBS
|
||||
nodeca
|
||||
nodoc
|
||||
NODRAWCAPTION
|
||||
@ -1014,6 +1029,7 @@ NODRAWICON
|
||||
NOINHERITLAYOUT
|
||||
NOINTERFACE
|
||||
NOLINKINFO
|
||||
NOMCX
|
||||
NOMINMAX
|
||||
NOMIRRORBITMAP
|
||||
NOMOVE
|
||||
@ -1414,6 +1430,8 @@ SHELLEXECUTEINFO
|
||||
SHELLEXECUTEINFOW
|
||||
shellscalingapi
|
||||
SHFILEINFO
|
||||
SHFILEOPSTRUCT
|
||||
SHGDN
|
||||
SHGDNF
|
||||
SHGFI
|
||||
shinfo
|
||||
@ -1421,6 +1439,7 @@ shldisp
|
||||
shlobj
|
||||
shlwapi
|
||||
shmem
|
||||
SHNAMEMAPPING
|
||||
shobjidl
|
||||
SHORTCUTATLEAST
|
||||
shortcutcontrol
|
||||
@ -1525,7 +1544,7 @@ stringtable
|
||||
stringval
|
||||
Strm
|
||||
Strmiids
|
||||
Strret
|
||||
strret
|
||||
strsafe
|
||||
strutil
|
||||
sttngs
|
||||
@ -1541,6 +1560,7 @@ svchost
|
||||
SVGIn
|
||||
SVGIO
|
||||
svgz
|
||||
SVSI
|
||||
SWC
|
||||
SWFO
|
||||
SWP
|
||||
@ -1745,6 +1765,7 @@ VSTHRD
|
||||
VSTT
|
||||
vswhere
|
||||
Vtbl
|
||||
WANTMAPPINGHANDLE
|
||||
WANTPALM
|
||||
wbem
|
||||
Wbemidl
|
||||
@ -1756,6 +1777,7 @@ WCE
|
||||
wcex
|
||||
WClass
|
||||
wcsicmp
|
||||
wcsncpy
|
||||
wcsnicmp
|
||||
WDA
|
||||
wdp
|
||||
|
@ -178,6 +178,9 @@
|
||||
"PowerToys.MouseWithoutBordersHelper.dll",
|
||||
"PowerToys.MouseWithoutBordersHelper.exe",
|
||||
|
||||
"WinUI3Apps\\PowerToys.NewPlus.ShellExtension.dll",
|
||||
"WinUI3Apps\\NewPlusPackage.msix",
|
||||
|
||||
"PowerAccent.Core.dll",
|
||||
"PowerToys.PowerAccent.dll",
|
||||
"PowerToys.PowerAccent.exe",
|
||||
|
@ -582,6 +582,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerToys.Settings.DSC.Sche
|
||||
{020A7474-3601-4160-A159-D7B70B77B15F} = {020A7474-3601-4160-A159-D7B70B77B15F}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewPlus.ShellExtension", "src\modules\NewPlus\NewShellExtensionContextMenu\NewShellExtensionContextMenu.vcxproj", "{8ACB33D9-C95B-47D4-8363-9731EE0930A0}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "New+", "New+", "{CA716AE6-FE5C-40AC-BB8F-2C87912687AC}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToys.Interop", "src\common\interop\PowerToys.Interop.vcxproj", "{F055103B-F80B-4D0C-BF48-057C55620033}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Workspaces", "Workspaces", "{A2221D7E-55E7-4BEA-90D1-4F162D670BBF}"
|
||||
@ -2621,6 +2625,16 @@ Global
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Release|x64.Build.0 = Release|x64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Release|x86.ActiveCfg = Release|x64
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A}.Release|x86.Build.0 = Release|x64
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0}.Debug|x64.Build.0 = Debug|x64
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0}.Release|x64.ActiveCfg = Release|x64
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0}.Release|x64.Build.0 = Release|x64
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0}.Release|x86.ActiveCfg = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@ -2920,6 +2934,8 @@ Global
|
||||
{3A9A791E-94A9-49F8-8401-C11CE288D5FB} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{C0974915-8A1D-4BF0-977B-9587D3807AB7} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{1D6893CB-BC0C-46A8-A76C-9728706CA51A} = {557C4636-D7E1-4838-A504-7D19B725EE95}
|
||||
{8ACB33D9-C95B-47D4-8363-9731EE0930A0} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC}
|
||||
{CA716AE6-FE5C-40AC-BB8F-2C87912687AC} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033} = {5A7818A8-109C-4E1C-850D-1A654E234B0E}
|
||||
{A2221D7E-55E7-4BEA-90D1-4F162D670BBF} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{BE126CBB-AE12-406A-9837-A05ACFCA57A7} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
|
||||
|
73
installer/PowerToysSetup/NewPlus.wxs
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
||||
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" >
|
||||
|
||||
<?include $(sys.CURRENTDIR)\Common.wxi?>
|
||||
|
||||
<?define NewPlusAssetsFiles=?>
|
||||
<?define NewPlusAssetsFilesPath=$(var.BinDir)WinUI3Apps\Assets\NewPlus\?>
|
||||
<?define NewPlusTemplateFilesPath=$(var.BinDir)WinUI3Apps\Assets\NewPlus\Templates\?>
|
||||
<?define NewPlusTemplateSubFilesPath=$(var.BinDir)WinUI3Apps\Assets\NewPlus\Templates\Example folder\?>
|
||||
|
||||
<Fragment>
|
||||
|
||||
<!-- Assets -->
|
||||
<DirectoryRef Id="WinUI3AppsAssetsFolder">
|
||||
<Directory Id="NewPlusAssetsInstallFolder" Name="NewPlus" />
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="NewPlusAssetsInstallFolder" FileSource="$(var.NewPlusAssetsFilesPath)">
|
||||
<!-- Generated by generateFileComponents.ps1 -->
|
||||
<!--NewPlusAssetsFiles_Component_Def-->
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="NewPlusComponentGroup">
|
||||
<Component Id="RemoveNewPlusFolder" Guid="4189C789-56EB-409D-912E-3F4F3F4F1FFA" Directory="NewPlusAssetsInstallFolder" >
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="RemoveNewPlusFolder" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderNewPlusAssetsFolder" Directory="NewPlusAssetsInstallFolder" On="uninstall"/>
|
||||
</Component>
|
||||
</ComponentGroup>
|
||||
|
||||
|
||||
<!-- Example templates -->
|
||||
<DirectoryRef Id="WinUI3AppsAssetsFolder">
|
||||
<Directory Id="NewPlusInstallFolder" Name="NewPlus">
|
||||
<Directory Id="NewPlusTemplatesInstallFolder" Name="Templates">
|
||||
<Directory Id="NewPlusTemplatesSubInstallFolder" Name="Example folder"/>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="NewPlusTemplatesInstallFolder" FileSource="$(var.NewPlusTemplateFilesPath)">
|
||||
<Component Id="NewPlusTemplateFiles_Component" Win64="yes" Guid="39264075-4B7F-40E3-A76F-21E68576D43E">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="NewPlusTemplateFiles_Component" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<File Id="NewPlusTemplateFiles_File_1.md" Source="$(var.NewPlusTemplateFilesPath)Any files or folders placed in the template folder are available via New+.txt" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="NewPlusTemplatesSubInstallFolder" FileSource="$(var.NewPlusTemplateSubFilesPath)">
|
||||
<Component Id="NewPlusTemplateSubFiles_Component" Win64="yes" Guid="7618E61C-CCB8-492F-B284-E1AE2954AF0B">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="NewPlusTemplateSubFiles_Component" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<File Id="NewPlusTemplateSubFiles_File_1.md" Source="$(var.NewPlusTemplateSubFilesPath)Example txt file.txt" />
|
||||
<File Id="NewPlusTemplateSubFiles_File_2.md" Source="$(var.NewPlusTemplateSubFilesPath)Another example txt file.txt" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="NewPlusTemplatesComponentGroup">
|
||||
<Component Id="RemoveNewPlusTemplateFolder" Guid="3E9B15CA-A50C-42DA-977F-5E9914562FE7" Directory="NewPlusInstallFolder" >
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
|
||||
<RegistryValue Type="string" Name="RemoveNewPlusTemplateFolder" Value="" KeyPath="yes"/>
|
||||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderNewPlusInstallFolder" Directory="NewPlusInstallFolder" On="uninstall"/>
|
||||
<RemoveFolder Id="RemoveFolderNewPlusTemplatesInstallFolder" Directory="NewPlusTemplatesInstallFolder" On="uninstall"/>
|
||||
<RemoveFolder Id="RemoveFolderNewPlusTemplatesSubInstallFolder" Directory="NewPlusTemplatesSubInstallFolder" On="uninstall"/>
|
||||
</Component>
|
||||
<ComponentRef Id="NewPlusTemplateFiles_Component" />
|
||||
<ComponentRef Id="NewPlusTemplateSubFiles_Component" />
|
||||
</ComponentGroup>
|
||||
|
||||
</Fragment>
|
||||
</Wix>
|
@ -1,9 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureNuGetPackageBuildImports"
|
||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureNuGetPackageBuildImports" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\src\Version.props" Condition="Exists('..\..\src\Version.props')" />
|
||||
<Import Project="..\wix.props" Condition="Exists('..\wix.props')" />
|
||||
|
||||
<PropertyGroup Condition="'$(Platform)' == 'x64'">
|
||||
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\x64\$(Configuration)\Assets\Monaco\monacoSRC</DefineConstants>
|
||||
<!-- THIS IS AN INNER LOOP OPTIMIZATION
|
||||
@ -18,7 +16,6 @@ call "..\..\..\publish.cmd" x64
|
||||
call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuildThisFileDirectory)\generateMonacoWxs.ps1 -monacoWxsFile "$(MSBuildThisFileDirectory)\MonacoSRC.wxs"
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Platform)' != 'x64'">
|
||||
<DefineConstants>Version=$(Version);MonacoSRCHarvestPath=$(ProjectDir)..\..\ARM64\$(Configuration)\Assets\Monaco\monacoSRC</DefineConstants>
|
||||
<PreBuildEvent>IF NOT DEFINED IsPipeline (
|
||||
@ -32,31 +29,32 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
|
||||
<PropertyGroup>
|
||||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||
<PostBuildEvent>
|
||||
call move /Y ..\..\..\AdvancedPaste.wxs.bk ..\..\..\AdvancedPaste.wxs
|
||||
call move /Y ..\..\..\Awake.wxs.bk ..\..\..\Awake.wxs
|
||||
call move /Y ..\..\..\BaseApplications.wxs.bk ..\..\..\BaseApplications.wxs
|
||||
call move /Y ..\..\..\ColorPicker.wxs.bk ..\..\..\ColorPicker.wxs
|
||||
call move /Y ..\..\..\Core.wxs.bk ..\..\..\Core.wxs
|
||||
call move /Y ..\..\..\EnvironmentVariables.wxs.bk ..\..\..\EnvironmentVariables.wxs
|
||||
call move /Y ..\..\..\FileExplorerPreview.wxs.bk ..\..\..\FileExplorerPreview.wxs
|
||||
call move /Y ..\..\..\FileLocksmith.wxs.bk ..\..\..\FileLocksmith.wxs
|
||||
call move /Y ..\..\..\Hosts.wxs.bk ..\..\..\Hosts.wxs
|
||||
call move /Y ..\..\..\ImageResizer.wxs.bk ..\..\..\ImageResizer.wxs
|
||||
call move /Y ..\..\..\KeyboardManager.wxs.bk ..\..\..\KeyboardManager.wxs
|
||||
call move /Y ..\..\..\MouseWithoutBorders.wxs.bk ..\..\..\MouseWithoutBorders.wxs
|
||||
call move /Y ..\..\..\Peek.wxs.bk ..\..\..\Peek.wxs
|
||||
call move /Y ..\..\..\PowerRename.wxs.bk ..\..\..\PowerRename.wxs
|
||||
call move /Y ..\..\..\Product.wxs.bk ..\..\..\Product.wxs
|
||||
call move /Y ..\..\..\RegistryPreview.wxs.bk ..\..\..\RegistryPreview.wxs
|
||||
call move /Y ..\..\..\Resources.wxs.bk ..\..\..\Resources.wxs
|
||||
call move /Y ..\..\..\Run.wxs.bk ..\..\..\Run.wxs
|
||||
call move /Y ..\..\..\Settings.wxs.bk ..\..\..\Settings.wxs
|
||||
call move /Y ..\..\..\ShortcutGuide.wxs.bk ..\..\..\ShortcutGuide.wxs
|
||||
call move /Y ..\..\..\Tools.wxs.bk ..\..\..\Tools.wxs
|
||||
call move /Y ..\..\..\VideoConference.wxs.bk ..\..\..\VideoConference.wxs
|
||||
call move /Y ..\..\..\WinAppSDK.wxs.bk ..\..\..\WinAppSDK.wxs
|
||||
call move /Y ..\..\..\WinUI3Applications.wxs.bk ..\..\..\WinUI3Applications.wxs
|
||||
</PostBuildEvent>
|
||||
call move /Y ..\..\..\AdvancedPaste.wxs.bk ..\..\..\AdvancedPaste.wxs
|
||||
call move /Y ..\..\..\Awake.wxs.bk ..\..\..\Awake.wxs
|
||||
call move /Y ..\..\..\BaseApplications.wxs.bk ..\..\..\BaseApplications.wxs
|
||||
call move /Y ..\..\..\ColorPicker.wxs.bk ..\..\..\ColorPicker.wxs
|
||||
call move /Y ..\..\..\Core.wxs.bk ..\..\..\Core.wxs
|
||||
call move /Y ..\..\..\EnvironmentVariables.wxs.bk ..\..\..\EnvironmentVariables.wxs
|
||||
call move /Y ..\..\..\FileExplorerPreview.wxs.bk ..\..\..\FileExplorerPreview.wxs
|
||||
call move /Y ..\..\..\FileLocksmith.wxs.bk ..\..\..\FileLocksmith.wxs
|
||||
call move /Y ..\..\..\Hosts.wxs.bk ..\..\..\Hosts.wxs
|
||||
call move /Y ..\..\..\ImageResizer.wxs.bk ..\..\..\ImageResizer.wxs
|
||||
call move /Y ..\..\..\KeyboardManager.wxs.bk ..\..\..\KeyboardManager.wxs
|
||||
call move /Y ..\..\..\MouseWithoutBorders.wxs.bk ..\..\..\MouseWithoutBorders.wxs
|
||||
call move /Y ..\..\..\NewPlus.wxs.bk ..\..\..\NewPlus.wxs
|
||||
call move /Y ..\..\..\Peek.wxs.bk ..\..\..\Peek.wxs
|
||||
call move /Y ..\..\..\PowerRename.wxs.bk ..\..\..\PowerRename.wxs
|
||||
call move /Y ..\..\..\Product.wxs.bk ..\..\..\Product.wxs
|
||||
call move /Y ..\..\..\RegistryPreview.wxs.bk ..\..\..\RegistryPreview.wxs
|
||||
call move /Y ..\..\..\Resources.wxs.bk ..\..\..\Resources.wxs
|
||||
call move /Y ..\..\..\Run.wxs.bk ..\..\..\Run.wxs
|
||||
call move /Y ..\..\..\Settings.wxs.bk ..\..\..\Settings.wxs
|
||||
call move /Y ..\..\..\ShortcutGuide.wxs.bk ..\..\..\ShortcutGuide.wxs
|
||||
call move /Y ..\..\..\Tools.wxs.bk ..\..\..\Tools.wxs
|
||||
call move /Y ..\..\..\VideoConference.wxs.bk ..\..\..\VideoConference.wxs
|
||||
call move /Y ..\..\..\WinAppSDK.wxs.bk ..\..\..\WinAppSDK.wxs
|
||||
call move /Y ..\..\..\WinUI3Applications.wxs.bk ..\..\..\WinUI3Applications.wxs
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Name>PowerToysInstaller</Name>
|
||||
@ -67,7 +65,6 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
|
||||
<PropertyGroup Label="UserMacros" Condition=" '$(PerUser)' != 'true' ">
|
||||
<DefineConstants>$(DefineConstants);PerUser=false</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- We do not support debug installer builds -->
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
@ -102,8 +99,8 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
|
||||
<Compile Include="CustomDialogs\PTInstallDirDlg.wxs" />
|
||||
<Compile Include="CustomDialogs\PTLicenseDlg.wxs" />
|
||||
<Compile Include="CustomDialogs\WixUI_PTInstallDir.wxs" />
|
||||
<Compile Include="NewPlus.wxs" />
|
||||
<Compile Include="Product.wxs" />
|
||||
|
||||
<Compile Include="AdvancedPaste.wxs" />
|
||||
<Compile Include="Awake.wxs" />
|
||||
<Compile Include="BaseApplications.wxs" />
|
||||
@ -124,9 +121,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
|
||||
<Compile Include="VideoConference.wxs" />
|
||||
<Compile Include="MouseWithoutBorders.wxs" />
|
||||
<Compile Include="WinUI3Applications.wxs" />
|
||||
|
||||
<Compile Include="MonacoSRC.wxs" />
|
||||
|
||||
<Compile Include="Core.wxs" />
|
||||
<Compile Include="Resources.wxs" />
|
||||
<Compile Include="WinAppSDK.wxs" />
|
||||
@ -184,9 +179,8 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
|
||||
<Target Name="AfterBuild">
|
||||
</Target> -->
|
||||
<Target Name="BeforeBuild">
|
||||
<HeatDirectory Directory="..\..\src\common\FilePreviewCommon\Assets\Monaco\monacoSRC" PreprocessorVariable="var.MonacoSRCHarvestPath" OutputFile="MonacoSRC.wxs" ComponentGroupName="MonacoSRCHeatGenerated" DirectoryRefId="MonacoPreviewHandlerMonacoSRCFolder" AutogenerateGuids="false" GenerateGuidsNow="true" ToolPath="$(WixToolPath)" RunAsSeparateProcess="true" SuppressFragments="false" SuppressRegistry="false" SuppressRootDirectory="true"/>
|
||||
<HeatDirectory Directory="..\..\src\common\FilePreviewCommon\Assets\Monaco\monacoSRC" PreprocessorVariable="var.MonacoSRCHarvestPath" OutputFile="MonacoSRC.wxs" ComponentGroupName="MonacoSRCHeatGenerated" DirectoryRefId="MonacoPreviewHandlerMonacoSRCFolder" AutogenerateGuids="false" GenerateGuidsNow="true" ToolPath="$(WixToolPath)" RunAsSeparateProcess="true" SuppressFragments="false" SuppressRegistry="false" SuppressRootDirectory="true" />
|
||||
</Target>
|
||||
|
||||
<!-- Prevents NU1503 -->
|
||||
<Target Name="_IsProjectRestoreSupported" Returns="@(_ValidProjectsForRestore)">
|
||||
<ItemGroup>
|
||||
|
@ -73,6 +73,8 @@
|
||||
<ComponentGroupRef Id="MouseWithoutBordersComponentGroup" />
|
||||
<ComponentGroupRef Id="EnvironmentVariablesComponentGroup" />
|
||||
<ComponentGroupRef Id="AdvancedPasteComponentGroup" />
|
||||
<ComponentGroupRef Id="NewPlusComponentGroup" />
|
||||
<ComponentGroupRef Id="NewPlusTemplatesComponentGroup" />
|
||||
<ComponentGroupRef Id="ResourcesComponentGroup" />
|
||||
<ComponentGroupRef Id="WindowsAppSDKComponentGroup" />
|
||||
<ComponentGroupRef Id="ToolComponentGroup" />
|
||||
|
@ -58,6 +58,10 @@ Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListNa
|
||||
Invoke-Expression -Command "$PSScriptRoot\generateFileList.ps1 -fileDepsJson """" -fileListName ImageResizerAssetsFiles -wxsFilePath $PSScriptRoot\ImageResizer.wxs -depsPath ""$PSScriptRoot..\..\..\$platform\Release\Assets\ImageResizer"""
|
||||
Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListName ""ImageResizerAssetsFiles"" -wxsFilePath $PSScriptRoot\ImageResizer.wxs -regroot $registryroot"
|
||||
|
||||
#New+
|
||||
Invoke-Expression -Command "$PSScriptRoot\generateFileList.ps1 -fileDepsJson """" -fileListName NewPlusAssetsFiles -wxsFilePath $PSScriptRoot\NewPlus.wxs -depsPath ""$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\NewPlus"""
|
||||
Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListName ""NewPlusAssetsFiles"" -wxsFilePath $PSScriptRoot\NewPlus.wxs -regroot $registryroot"
|
||||
|
||||
#Peek
|
||||
Invoke-Expression -Command "$PSScriptRoot\generateFileList.ps1 -fileDepsJson """" -fileListName PeekAssetsFiles -wxsFilePath $PSScriptRoot\Peek.wxs -depsPath ""$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\Peek\"""
|
||||
Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListName ""PeekAssetsFiles"" -wxsFilePath $PSScriptRoot\Peek.wxs -regroot $registryroot"
|
||||
|
@ -1148,7 +1148,7 @@ UINT __stdcall UnRegisterContextMenuPackagesCA(MSIHANDLE hInstall)
|
||||
try
|
||||
{
|
||||
// Packages to unregister
|
||||
const std::vector<std::wstring> packagesToRemoveDisplayName{ { L"PowerRenameContextMenu" }, { L"ImageResizerContextMenu" }, { L"FileLocksmithContextMenu" } };
|
||||
const std::vector<std::wstring> packagesToRemoveDisplayName{ { L"PowerRenameContextMenu" }, { L"ImageResizerContextMenu" }, { L"FileLocksmithContextMenu" }, { L"NewPlusContextMenu" } };
|
||||
|
||||
PackageManager packageManager;
|
||||
|
||||
|
@ -60,6 +60,7 @@
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\ImageResizer.wxs"" ""$(ProjectDir)..\PowerToysSetup\ImageResizer.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\KeyboardManager.wxs"" ""$(ProjectDir)..\PowerToysSetup\KeyboardManager.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\MouseWithoutBorders.wxs"" ""$(ProjectDir)..\PowerToysSetup\MouseWithoutBorders.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\NewPlus.wxs"" ""$(ProjectDir)..\PowerToysSetup\NewPlus.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\Peek.wxs"" ""$(ProjectDir)..\PowerToysSetup\Peek.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\PowerRename.wxs"" ""$(ProjectDir)..\PowerToysSetup\PowerRename.wxs.bk""""
|
||||
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\Product.wxs"" ""$(ProjectDir)..\PowerToysSetup\Product.wxs.bk""""
|
||||
|
@ -176,6 +176,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getAllowedAdvancedPasteOnlineAIModelsValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredNewPlusEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredNewPlusEnabledValue());
|
||||
}
|
||||
GpoRuleConfigured GPOWrapper::GetConfiguredWorkspacesEnabledValue()
|
||||
{
|
||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredWorkspacesEnabledValue());
|
||||
|
@ -50,6 +50,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
||||
static GpoRuleConfigured GetConfiguredQoiPreviewEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredQoiThumbnailsEnabledValue();
|
||||
static GpoRuleConfigured GetAllowedAdvancedPasteOnlineAIModelsValue();
|
||||
static GpoRuleConfigured GetConfiguredNewPlusEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredWorkspacesEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredMwbClipboardSharingEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredMwbFileTransferEnabledValue();
|
||||
|
@ -54,6 +54,7 @@ namespace PowerToys
|
||||
static GpoRuleConfigured GetConfiguredQoiPreviewEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredQoiThumbnailsEnabledValue();
|
||||
static GpoRuleConfigured GetAllowedAdvancedPasteOnlineAIModelsValue();
|
||||
static GpoRuleConfigured GetConfiguredNewPlusEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredWorkspacesEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredMwbClipboardSharingEnabledValue();
|
||||
static GpoRuleConfigured GetConfiguredMwbFileTransferEnabledValue();
|
||||
|
@ -22,6 +22,7 @@ namespace ManagedCommon
|
||||
MouseJump,
|
||||
MousePointerCrosshairs,
|
||||
MouseWithoutBorders,
|
||||
NewPlus,
|
||||
Peek,
|
||||
PowerRename,
|
||||
PowerLauncher,
|
||||
|
@ -3,13 +3,23 @@
|
||||
#include "dwmapi.h"
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
#pragma comment (lib,"Dwmapi.lib")
|
||||
#pragma comment(lib, "Dwmapi.lib")
|
||||
|
||||
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
|
||||
#define HKEY_WINDOWS_THEME L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"
|
||||
|
||||
// based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application
|
||||
AppTheme ThemeHelpers::GetAppTheme()
|
||||
Theme ThemeHelpers::GetAppTheme()
|
||||
{
|
||||
return ThemeRegistryHelper(L"AppsUseLightTheme");
|
||||
}
|
||||
|
||||
Theme ThemeHelpers::GetSystemTheme()
|
||||
{
|
||||
return ThemeRegistryHelper(L"SystemUsesLightTheme");
|
||||
}
|
||||
|
||||
Theme ThemeHelpers::ThemeRegistryHelper(LPCWSTR theme_key)
|
||||
{
|
||||
// The value is expected to be a REG_DWORD, which is a signed 32-bit little-endian
|
||||
auto buffer = std::vector<char>(4);
|
||||
@ -17,21 +27,22 @@ AppTheme ThemeHelpers::GetAppTheme()
|
||||
auto res = RegGetValueW(
|
||||
HKEY_CURRENT_USER,
|
||||
HKEY_WINDOWS_THEME,
|
||||
L"AppsUseLightTheme",
|
||||
RRF_RT_REG_DWORD, // expected value type
|
||||
theme_key,
|
||||
RRF_RT_REG_DWORD,
|
||||
nullptr,
|
||||
buffer.data(),
|
||||
&cbData);
|
||||
|
||||
if (res != ERROR_SUCCESS)
|
||||
{
|
||||
return AppTheme::Light;
|
||||
// Defaulting to Light
|
||||
return Theme::Light;
|
||||
}
|
||||
|
||||
// convert bytes written to our buffer to an int, assuming little-endian
|
||||
auto i = static_cast<int>(buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0]);
|
||||
|
||||
return AppTheme(i);
|
||||
return Theme(i);
|
||||
}
|
||||
|
||||
void ThemeHelpers::SetImmersiveDarkMode(HWND window, bool enabled)
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
|
||||
enum class AppTheme
|
||||
enum class Theme
|
||||
{
|
||||
Dark = 0,
|
||||
Light = 1
|
||||
@ -9,6 +9,10 @@ enum class AppTheme
|
||||
|
||||
struct ThemeHelpers
|
||||
{
|
||||
static AppTheme GetAppTheme();
|
||||
static void ThemeHelpers::SetImmersiveDarkMode(HWND window, bool enabled);
|
||||
static Theme GetAppTheme();
|
||||
static Theme GetSystemTheme();
|
||||
static void SetImmersiveDarkMode(HWND window, bool enabled);
|
||||
|
||||
protected:
|
||||
static Theme ThemeRegistryHelper(LPCWSTR theme_key);
|
||||
};
|
@ -22,7 +22,7 @@ public:
|
||||
dwThreadId = 0;
|
||||
}
|
||||
|
||||
AppTheme AppTheme;
|
||||
Theme AppTheme;
|
||||
void ThemeListener::AddChangedHandler(THEME_HANDLE handle);
|
||||
void ThemeListener::DelChangedHandler(THEME_HANDLE handle);
|
||||
void CheckTheme();
|
||||
|
@ -66,7 +66,7 @@ WindowsColors::Color WindowsColors::get_background_color()
|
||||
|
||||
bool WindowsColors::is_dark_mode()
|
||||
{
|
||||
return ThemeHelpers::GetAppTheme() == AppTheme::Dark;
|
||||
return ThemeHelpers::GetAppTheme() == Theme::Dark;
|
||||
}
|
||||
|
||||
bool WindowsColors::update()
|
||||
|
@ -69,6 +69,7 @@ struct LogSettings
|
||||
inline const static std::string environmentVariablesLoggerName = "environment-variables";
|
||||
inline const static std::wstring cmdNotFoundLogPath = L"Logs\\cmd-not-found-log.txt";
|
||||
inline const static std::string cmdNotFoundLoggerName = "cmd-not-found";
|
||||
inline const static std::string newLoggerName = "NewPlus";
|
||||
inline const static std::string workspacesLauncherLoggerName = "workspaces-launcher";
|
||||
inline const static std::wstring workspacesLauncherLogPath = L"workspaces-launcher-log.txt";
|
||||
inline const static std::string workspacesSnapshotToolLoggerName = "workspaces-snapshot-tool";
|
||||
|
@ -60,6 +60,7 @@ namespace powertoys_gpo {
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_ENVIRONMENT_VARIABLES = L"ConfigureEnabledUtilityEnvironmentVariables";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_QOI_PREVIEW = L"ConfigureEnabledUtilityFileExplorerQOIPreview";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_QOI_THUMBNAILS = L"ConfigureEnabledUtilityFileExplorerQOIThumbnails";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_NEWPLUS = L"ConfigureEnabledUtilityNewPlus";
|
||||
const std::wstring POLICY_CONFIGURE_ENABLED_WORKSPACES = L"ConfigureEnabledUtilityWorkspaces";
|
||||
|
||||
// The registry value names for PowerToys installer and update policies.
|
||||
@ -515,6 +516,11 @@ namespace powertoys_gpo {
|
||||
return getUtilityEnabledValue(POLICY_ALLOW_ADVANCED_PASTE_ONLINE_AI_MODELS);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredNewPlusEnabledValue()
|
||||
{
|
||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_NEWPLUS);
|
||||
}
|
||||
|
||||
inline gpo_rule_configured_t getConfiguredMwbClipboardSharingEnabledValue()
|
||||
{
|
||||
return getUtilityEnabledValue(POLICY_MWB_CLIPBOARD_SHARING_ENABLED);
|
||||
|
@ -35,6 +35,8 @@ properties:
|
||||
Enabled: false
|
||||
MouseWithoutBorders:
|
||||
Enabled: false
|
||||
NewPlus:
|
||||
Enabled: false
|
||||
Peek:
|
||||
Enabled: false
|
||||
PowerRename:
|
||||
|
@ -35,6 +35,8 @@ properties:
|
||||
Enabled: true
|
||||
MouseWithoutBorders:
|
||||
Enabled: true
|
||||
NewPlus:
|
||||
Enabled: true
|
||||
Peek:
|
||||
Enabled: true
|
||||
PowerRename:
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.12" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
|
||||
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.13" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
|
||||
<policyNamespaces>
|
||||
<target prefix="powertoys" namespace="Microsoft.Policies.PowerToys" />
|
||||
</policyNamespaces>
|
||||
<resources minRequiredRevision="1.12"/><!-- Last changed with PowerToys v0.84.0 -->
|
||||
<resources minRequiredRevision="1.13"/><!-- Last changed with PowerToys v0.85.0 -->
|
||||
<supportedOn>
|
||||
<definitions>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_64_0" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0)"/>
|
||||
@ -21,6 +21,7 @@
|
||||
<definition name="SUPPORTED_POWERTOYS_0_81_1" displayName="$(string.SUPPORTED_POWERTOYS_0_81_1)"/>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_83_0" displayName="$(string.SUPPORTED_POWERTOYS_0_83_0)"/>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_84_0" displayName="$(string.SUPPORTED_POWERTOYS_0_84_0)"/>
|
||||
<definition name="SUPPORTED_POWERTOYS_0_85_0" displayName="$(string.SUPPORTED_POWERTOYS_0_85_0)"/>
|
||||
</definitions>
|
||||
</supportedOn>
|
||||
<categories>
|
||||
@ -335,6 +336,16 @@
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityNewPlus" class="Both" displayName="$(string.ConfigureEnabledUtilityNewPlus)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityNewPlus">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_85_0" />
|
||||
<enabledValue>
|
||||
<decimal value="1" />
|
||||
</enabledValue>
|
||||
<disabledValue>
|
||||
<decimal value="0" />
|
||||
</disabledValue>
|
||||
</policy>
|
||||
<policy name="ConfigureEnabledUtilityPeek" class="Both" displayName="$(string.ConfigureEnabledUtilityPeek)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityPeek">
|
||||
<parentCategory ref="PowerToys" />
|
||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_70_0" />
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT License. -->
|
||||
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.12" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
|
||||
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="1.13" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
|
||||
<displayName>PowerToys</displayName>
|
||||
<description>PowerToys</description>
|
||||
<resources>
|
||||
@ -26,6 +26,7 @@
|
||||
<string id="SUPPORTED_POWERTOYS_0_81_1">PowerToys version 0.81.1 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_83_0">PowerToys version 0.83.0 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_84_0">PowerToys version 0.84.0 or later</string>
|
||||
<string id="SUPPORTED_POWERTOYS_0_85_0">PowerToys version 0.85.0 or later</string>
|
||||
|
||||
<string id="ConfigureAllUtilityGlobalEnabledStateDescription">This policy configures the enabled state for all PowerToys utilities.
|
||||
|
||||
@ -217,6 +218,7 @@ If you disable or don't configure this policy, no predefined rules are applied.
|
||||
<string id="ConfigureEnabledUtilityMouseJump">Mouse Jump: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityMousePointerCrosshairs">Mouse Pointer Crosshairs: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityMouseWithoutBorders">Mouse Without Borders: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityNewPlus">New+: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityPeek">Peek: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityPowerRename">Power Rename: Configure enabled state</string>
|
||||
<string id="ConfigureEnabledUtilityPowerLauncher">PowerToys Run: Configure enabled state</string>
|
||||
|
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
|
||||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
|
||||
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
|
||||
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" IgnorableNamespaces="uap uap2 uap3 rescap desktop desktop4 desktop5 uap10 com">
|
||||
<Identity Name="Microsoft.PowerToys.NewPlusContextMenu" ProcessorArchitecture="neutral" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="1.0.0.0" />
|
||||
<Properties>
|
||||
<DisplayName>PowerToys New+</DisplayName>
|
||||
<PublisherDisplayName>Microsoft</PublisherDisplayName>
|
||||
<Logo>Assets\NewPlus\StoreLogo.png</Logo>
|
||||
<uap10:AllowExternalContent>true</uap10:AllowExternalContent>
|
||||
</Properties>
|
||||
<Resources>
|
||||
<Resource Language="en-us" />
|
||||
</Resources>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18950.0" MaxVersionTested="10.0.19000.0" />
|
||||
</Dependencies>
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
<rescap:Capability Name="unvirtualizedResources"/>
|
||||
</Capabilities>
|
||||
<Applications>
|
||||
<Application Id="Microsoft.PowerToys.NewPlusContextMenu" Executable="NewPlus.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
|
||||
<uap:VisualElements AppListEntry="none" DisplayName="PowerToys New+" Description="New+ File Explorer Context Menu" BackgroundColor="transparent" Square150x150Logo="Assets\NewPlus\Square150x150Logo.png" Square44x44Logo="Assets\NewPlus\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\NewPlus\Wide310x150Logo.png" Square310x310Logo="Assets\NewPlus\LargeTile.png" Square71x71Logo="Assets\NewPlus\SmallTile.png"></uap:DefaultTile>
|
||||
<uap:SplashScreen Image="Assets\NewPlus\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<desktop4:Extension Category="windows.fileExplorerContextMenus">
|
||||
<desktop4:FileExplorerContextMenus>
|
||||
<desktop5:ItemType Type="Directory">
|
||||
<desktop5:Verb Id="NewPlusCommand" Clsid="69824FC6-4660-4A09-9E7C-48DA63C6CC0F" />
|
||||
</desktop5:ItemType>
|
||||
<desktop5:ItemType Type="Directory\Background">
|
||||
<desktop5:Verb Id="NewPlusCommand" Clsid="69824FC6-4660-4A09-9E7C-48DA63C6CC0F" />
|
||||
</desktop5:ItemType>
|
||||
</desktop4:FileExplorerContextMenus>
|
||||
</desktop4:Extension>
|
||||
<com:Extension Category="windows.comServer" uap10:RuntimeBehavior="packagedClassicApp">
|
||||
<com:ComServer>
|
||||
<com:SurrogateServer DisplayName="Context menu verb handler">
|
||||
<com:Class Id="69824FC6-4660-4A09-9E7C-48DA63C6CC0F" Path="PowerToys.NewPlus.ShellExtension.dll" ThreadingModel="STA"/>
|
||||
</com:SurrogateServer>
|
||||
</com:ComServer>
|
||||
</com:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
</Package>
|
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 264 KiB |
After Width: | Height: | Size: 264 KiB |
After Width: | Height: | Size: 264 KiB |
After Width: | Height: | Size: 264 KiB |
After Width: | Height: | Size: 433 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 433 B |
After Width: | Height: | Size: 328 B |
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,236 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
|
||||
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h new.base.rc new.rc" />
|
||||
</Target>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{8acb33d9-c95b-47d4-8363-9731ee0930a0}</ProjectGuid>
|
||||
<RootNamespace>NewPlusShellExtension</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>NewPlus.ShellExtension</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<TargetExt>.dll</TargetExt>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
|
||||
<TargetName>PowerToys.NewPlus.ShellExtension</TargetName>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\TemporaryBuild\obj\$(ProjectName)\</IntDir>
|
||||
<LinkIncremental />
|
||||
<IgnoreImportLibrary />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
|
||||
<TargetName>PowerToys.NewPlus.ShellExtension</TargetName>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\TemporaryBuild\obj\$(ProjectName)\</IntDir>
|
||||
<LinkIncremental />
|
||||
<IgnoreImportLibrary />
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;NEWPLUSCONTEXTMENU_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>runtimeobject.lib;$(CoreLibraryDependencies)</AdditionalDependencies>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>del $(OutDir)\NewPlusPackage.msix /q
|
||||
MakeAppx.exe pack /d . /p $(OutDir)NewPlusPackage.msix /nv</Command>
|
||||
</PreBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;NEWPLUSCONTEXTMENU_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>runtimeobject.lib;$(CoreLibraryDependencies)</AdditionalDependencies>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>del $(OutDir)\NewPlusPackage.msix /q
|
||||
MakeAppx.exe pack /d . /p $(OutDir)NewPlusPackage.msix /nv</Command>
|
||||
</PreBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="dll_main.h" />
|
||||
<ClInclude Include="shell_context_menu.h" />
|
||||
<ClInclude Include="shell_context_sub_menu.h" />
|
||||
<ClInclude Include="shell_context_sub_menu_item.h" />
|
||||
<ClInclude Include="constants.h" />
|
||||
<ClInclude Include="settings.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="new_utilities.h" />
|
||||
<ClInclude Include="resource.base.h" />
|
||||
<ClInclude Include="template_folder.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="Generated Files/resource.h" />
|
||||
<ClInclude Include="template_item.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="shell_context_menu.cpp" />
|
||||
<ClCompile Include="shell_context_sub_menu.cpp" />
|
||||
<ClCompile Include="shell_context_sub_menu_item.cpp" />
|
||||
<ClCompile Include="dll_main.cpp" />
|
||||
<ClCompile Include="powertoys_module.cpp" />
|
||||
<ClCompile Include="settings.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<ClCompile Include="template_folder.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="template_item.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="dll.def" />
|
||||
<None Include="packages.config" />
|
||||
<CopyFileToFolders Include="TemplateExamples\Any files or folders placed in the template folder are available via New+.txt">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
<FileType>Document</FileType>
|
||||
<DestinationFolders>$(OutDir)\Assets\NewPlus\Templates</DestinationFolders>
|
||||
</CopyFileToFolders>
|
||||
<CopyFileToFolders Include="TemplateExamples\Example folder\Example txt file.txt">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
<FileType>Document</FileType>
|
||||
<DestinationFolders>$(OutDir)\Assets\NewPlus\Templates\Example folder</DestinationFolders>
|
||||
</CopyFileToFolders>
|
||||
<CopyFileToFolders Include="TemplateExamples\Example folder\Another example txt file.txt">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
<FileType>Document</FileType>
|
||||
<DestinationFolders>$(OutDir)\Assets\NewPlus\Templates\Example folder</DestinationFolders>
|
||||
</CopyFileToFolders>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\Themes\Themes.vcxproj">
|
||||
<Project>{98537082-0fdb-40de-abd8-0dc5a4269bab}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\version\version.vcxproj">
|
||||
<Project>{cc6e41ac-8174-4e8a-8d22-85dd7f4851df}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files/new.rc" />
|
||||
<None Include="new.base.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Assets\NewPlus\LargeTile.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\New_dark.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\New_light.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Open_templates_dark.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Open_templates_light.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\SmallTile.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\SplashScreen.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Square150x150Logo.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Square44x44Logo.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\StoreLogo.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Wide310x150Logo.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources.resx">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="AppxManifest.xml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
@ -0,0 +1,203 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="shell_context_menu.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="shell_context_sub_menu.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="shell_context_sub_menu_item.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="template_folder.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="template_item.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dll_main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="powertoys_module.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="settings.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="template_folder.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="template_item.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="shell_context_sub_menu_item.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="shell_context_sub_menu.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="shell_context_menu.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="dll_main.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="constants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="settings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="new_utilities.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Generated Files/resource.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.base.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Assets\NewPlus\SmallTile.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\SplashScreen.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Square150x150Logo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Square44x44Logo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\StoreLogo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Wide310x150Logo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\SmallTile.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\SplashScreen.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Square150x150Logo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Square44x44Logo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\StoreLogo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Wide310x150Logo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="resources.resx">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="new.base.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
<None Include="dll.def">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="AppxManifest.xml">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\New.ico">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\SmallTile.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\SplashScreen.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Square150x150Logo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Square44x44Logo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\StoreLogo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Wide310x150Logo.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\LargeTile.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\New_dark.ico">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\New_light.ico">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Open_templates_dark.ico">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\Open_templates_light.ico">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{82bf7d46-1201-4fc2-99e0-6c1f48f97f1f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{0c915b9c-0e6a-4d16-8620-507a10fc29c9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Asset Files">
|
||||
<UniqueIdentifier>{0c64a1a0-1f9e-4663-8649-454da469d15c}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{4f319851-7d86-4180-b3a3-fd497a320c34}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{a998f674-d126-488b-8457-7673fe986f94}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Template Examples">
|
||||
<UniqueIdentifier>{b442cb0f-9f62-46e8-b269-fefa8ceacb21}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Template Examples\Example folder">
|
||||
<UniqueIdentifier>{e7904759-7b6c-4609-9c6d-e3eae3cb866c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Generated Files/new.rc">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="TemplateExamples\Example folder\Another example txt file.txt">
|
||||
<Filter>Template Examples\Example folder</Filter>
|
||||
</Text>
|
||||
<Text Include="TemplateExamples\Example folder\Example txt file.txt">
|
||||
<Filter>Template Examples\Example folder</Filter>
|
||||
</Text>
|
||||
<Text Include="TemplateExamples\Any files or folders placed in the template folder are available via New+.txt">
|
||||
<Filter>Template Examples</Filter>
|
||||
</Text>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1 @@
|
||||
Learn more about New+ by visiting https://aka.ms/PowerToysOverview_NewPlus
|
@ -0,0 +1 @@
|
||||
Another example txt file
|
@ -0,0 +1 @@
|
||||
Example txt file
|
34
src/modules/NewPlus/NewShellExtensionContextMenu/constants.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
namespace newplus::constants::non_localizable
|
||||
{
|
||||
constexpr WCHAR powertoy_key[] = L"NewPlus";
|
||||
|
||||
constexpr WCHAR powertoy_name[] = L"NewPlus";
|
||||
|
||||
constexpr WCHAR settings_json_data_file_path[] = L"\\settings.json";
|
||||
|
||||
constexpr WCHAR settings_json_key_hide_file_extension[] = L"HideFileExtension";
|
||||
|
||||
constexpr WCHAR settings_json_key_hide_starting_digits[] = L"HideStartingDigits";
|
||||
|
||||
constexpr WCHAR settings_json_key_template_location[] = L"TemplateLocation";
|
||||
|
||||
constexpr WCHAR context_menu_package_name[] = L"NewPlusContextMenu";
|
||||
|
||||
constexpr WCHAR msix_package_name[] = L"NewPlusPackage.msix";
|
||||
|
||||
constexpr WCHAR module_name[] = L"NewPlus.ShellExtension";
|
||||
|
||||
constexpr WCHAR new_icon_light_resource_relative_path[] = L"\\Assets\\NewPlus\\New_light.ico";
|
||||
|
||||
constexpr WCHAR new_icon_dark_resource_relative_path[] = L"\\Assets\\NewPlus\\New_dark.ico";
|
||||
|
||||
constexpr WCHAR open_templates_icon_light_resource_relative_path[] = L"\\Assets\\NewPlus\\Open_templates_light.ico";
|
||||
|
||||
constexpr WCHAR open_templates_icon_dark_resource_relative_path[] = L"\\Assets\\NewPlus\\Open_templates_dark.ico";
|
||||
|
||||
constexpr WCHAR desktop_ini_filename[] = L"desktop.ini";
|
||||
}
|
5
src/modules/NewPlus/NewShellExtensionContextMenu/dll.def
Normal file
@ -0,0 +1,5 @@
|
||||
LIBRARY
|
||||
EXPORTS
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllGetClassObject PRIVATE
|
||||
DllGetActivationFactory PRIVATE
|
@ -0,0 +1,41 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "shell_context_menu.h"
|
||||
#include "dll_main.h"
|
||||
#include "trace.h"
|
||||
|
||||
HMODULE module_instance_handle = 0;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE module_handle, DWORD ul_reason_for_call, LPVOID reserved)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
module_instance_handle = module_handle;
|
||||
Trace::RegisterProvider();
|
||||
newplus::utilities::init_logger();
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
STDAPI DllGetActivationFactory(_In_ HSTRING activatableClassId, _COM_Outptr_ IActivationFactory** factory)
|
||||
{
|
||||
return Module<ModuleType::InProc>::GetModule().GetActivationFactory(activatableClassId, factory);
|
||||
}
|
||||
|
||||
STDAPI DllCanUnloadNow()
|
||||
{
|
||||
return Module<InProc>::GetModule().GetObjectCount() == 0 ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv)
|
||||
{
|
||||
return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv);
|
||||
}
|
||||
|
||||
CoCreatableClass(shell_context_menu)
|
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
extern HMODULE module_instance_handle;
|
49
src/modules/NewPlus/NewShellExtensionContextMenu/new.base.rc
Normal file
@ -0,0 +1,49 @@
|
||||
#include <windows.h>
|
||||
#include "Generated Files/resource.h"
|
||||
#include "../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
PRODUCTVERSION PRODUCT_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", COMPANY_NAME
|
||||
VALUE "FileDescription", FILE_DESCRIPTION
|
||||
VALUE "FileVersion", FILE_VERSION_STRING
|
||||
VALUE "InternalName", INTERNAL_NAME
|
||||
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||
VALUE "ProductName", PRODUCT_NAME
|
||||
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_ICON1 ICON "Assets/NewPlus/New_light.ico"
|
177
src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h
Normal file
@ -0,0 +1,177 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/utils/package.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "settings.h"
|
||||
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
|
||||
namespace newplus::utilities
|
||||
{
|
||||
|
||||
inline std::wstring get_explorer_icon(std::filesystem::path path)
|
||||
{
|
||||
SHFILEINFO shell_file_info = { 0 };
|
||||
const std::wstring filepath = path.wstring();
|
||||
DWORD_PTR result = SHGetFileInfo(filepath.c_str(), 0, &shell_file_info, sizeof(shell_file_info), SHGFI_ICONLOCATION);
|
||||
std::wstring icon_path = shell_file_info.szDisplayName;
|
||||
if (icon_path != L"")
|
||||
{
|
||||
const int icon_index = shell_file_info.iIcon;
|
||||
std::wstring icon_resource = icon_path + std::wstring(L",") + std::to_wstring(icon_index);
|
||||
return icon_resource;
|
||||
}
|
||||
|
||||
WCHAR icon_resource_specifier[MAX_PATH] = { 0 };
|
||||
DWORD buffer_length = MAX_PATH;
|
||||
const std::wstring extension = path.extension().wstring();
|
||||
const HRESULT hr = AssocQueryString(ASSOCF_INIT_IGNOREUNKNOWN,
|
||||
ASSOCSTR_DEFAULTICON,
|
||||
extension.c_str(),
|
||||
NULL,
|
||||
icon_resource_specifier,
|
||||
&buffer_length);
|
||||
const std::wstring icon_resource = icon_resource_specifier;
|
||||
return icon_resource;
|
||||
}
|
||||
|
||||
inline bool is_hidden(const std::filesystem::path path)
|
||||
{
|
||||
const std::filesystem::path::string_type name = path.filename();
|
||||
if (name == constants::non_localizable::desktop_ini_filename)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool wstring_same_when_comparing_ignore_case(std::wstring stringA, std::wstring stringB)
|
||||
{
|
||||
transform(stringA.begin(), stringA.end(), stringA.begin(), towupper);
|
||||
transform(stringB.begin(), stringB.end(), stringB.begin(), towupper);
|
||||
|
||||
return (stringA == stringB);
|
||||
}
|
||||
|
||||
inline void process_pending_window_messages(HWND window_handle = NULL)
|
||||
{
|
||||
if (window_handle == NULL)
|
||||
{
|
||||
window_handle = GetActiveWindow();
|
||||
}
|
||||
|
||||
MSG current_message;
|
||||
while (PeekMessage(¤t_message, window_handle, NULL, NULL, PM_REMOVE))
|
||||
{
|
||||
DispatchMessage(¤t_message);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::wstring get_new_template_folder_location()
|
||||
{
|
||||
return NewSettingsInstance().GetTemplateLocation();
|
||||
}
|
||||
|
||||
inline bool get_newplus_setting_hide_extension()
|
||||
{
|
||||
return NewSettingsInstance().GetHideFileExtension();
|
||||
}
|
||||
|
||||
inline bool get_newplus_setting_hide_starting_digits()
|
||||
{
|
||||
return NewSettingsInstance().GetHideStartingDigits();
|
||||
}
|
||||
|
||||
inline void create_folder_if_not_exist(const std::filesystem::path path)
|
||||
{
|
||||
std::filesystem::create_directory(path);
|
||||
}
|
||||
|
||||
inline std::wstring get_new_icon_resource_filepath(const HMODULE module_instance_handle, const Theme theme)
|
||||
{
|
||||
auto iconResourcePath = get_module_folderpath(module_instance_handle);
|
||||
|
||||
if (theme == Theme::Dark)
|
||||
{
|
||||
iconResourcePath += constants::non_localizable::new_icon_dark_resource_relative_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Defaulting to the Light icon
|
||||
iconResourcePath += constants::non_localizable::new_icon_light_resource_relative_path;
|
||||
}
|
||||
|
||||
return iconResourcePath;
|
||||
}
|
||||
|
||||
inline std::wstring get_open_templates_icon_resource_filepath(const HMODULE module_instance_handle, const Theme theme)
|
||||
{
|
||||
auto iconResourcePath = get_module_folderpath(module_instance_handle);
|
||||
|
||||
if (theme == Theme::Dark)
|
||||
{
|
||||
iconResourcePath += constants::non_localizable::open_templates_icon_dark_resource_relative_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Defaulting to the Light icon
|
||||
iconResourcePath += constants::non_localizable::open_templates_icon_light_resource_relative_path;
|
||||
}
|
||||
|
||||
return iconResourcePath;
|
||||
}
|
||||
|
||||
inline void init_logger()
|
||||
{
|
||||
LoggerHelpers::init_logger(
|
||||
constants::non_localizable::powertoy_name,
|
||||
constants::non_localizable::module_name,
|
||||
LogSettings::newLoggerName);
|
||||
}
|
||||
|
||||
inline void register_msix_package()
|
||||
{
|
||||
if (package::IsWin11OrGreater())
|
||||
{
|
||||
static const auto new_dll_path = get_module_folderpath(module_instance_handle);
|
||||
auto new_package_uri = new_dll_path + L"\\" + constants::non_localizable::msix_package_name;
|
||||
|
||||
if (!package::IsPackageRegistered(constants::non_localizable::context_menu_package_name))
|
||||
{
|
||||
package::RegisterSparsePackage(new_dll_path, new_package_uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline std::wstring get_path_from_unknown_site(const ComPtr<IUnknown> site_of_folder)
|
||||
{
|
||||
ComPtr<IServiceProvider> service_provider;
|
||||
site_of_folder->QueryInterface(IID_PPV_ARGS(&service_provider));
|
||||
ComPtr<IFolderView> folder_view;
|
||||
service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&folder_view));
|
||||
ComPtr<IShellFolder> shell_folder;
|
||||
folder_view->GetFolder(IID_PPV_ARGS(&shell_folder));
|
||||
STRRET strings_returned;
|
||||
shell_folder->GetDisplayNameOf(0, SHGDN_FORPARSING, &strings_returned);
|
||||
LPWSTR path;
|
||||
StrRetToStr(&strings_returned, NULL, &path);
|
||||
return path;
|
||||
}
|
||||
|
||||
inline std::wstring get_path_from_folder_view(const ComPtr<IFolderView> folder_view)
|
||||
{
|
||||
ComPtr<IShellFolder> shell_folder;
|
||||
folder_view->GetFolder(IID_PPV_ARGS(&shell_folder));
|
||||
STRRET strings_returned;
|
||||
shell_folder->GetDisplayNameOf(0, SHGDN_FORPARSING, &strings_returned);
|
||||
LPWSTR path;
|
||||
StrRetToStr(&strings_returned, NULL, &path);
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
|
||||
</packages>
|
3
src/modules/NewPlus/NewShellExtensionContextMenu/pch.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
37
src/modules/NewPlus/NewShellExtensionContextMenu/pch.h
Normal file
@ -0,0 +1,37 @@
|
||||
// Precompiled header file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMCX
|
||||
#define NOHELP
|
||||
#define NOCOMM
|
||||
|
||||
// Windows and STL
|
||||
#include <Shobjidl.h>
|
||||
#include <shlwapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <Windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <vector>
|
||||
#include <system_error>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <atlbase.h>
|
||||
#include <wrl.h>
|
||||
#include <wrl/module.h>
|
||||
#include <unknwn.h>
|
||||
|
||||
// PowerToys project common
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/logger/logger_settings.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/Themes/theme_helpers.h>
|
||||
|
||||
// New project specific
|
||||
#include "dll_main.h"
|
||||
#include "template_folder.h"
|
||||
#include "settings.h"
|
||||
#include "new_utilities.h"
|
@ -0,0 +1,134 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include <winrt/Windows.Data.Json.h>
|
||||
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <common/utils/gpo.h>
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "settings.h"
|
||||
#include "trace.h"
|
||||
#include "new_utilities.h"
|
||||
#include "Generated Files/resource.h"
|
||||
|
||||
// Note: Settings are managed via Settings and UI Settings
|
||||
class NewModule : public PowertoyModuleIface
|
||||
{
|
||||
public:
|
||||
NewModule()
|
||||
{
|
||||
init_settings();
|
||||
}
|
||||
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
static const std::wstring localized_context_menu_item =
|
||||
GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_NEW, L"New+");
|
||||
|
||||
return localized_context_menu_item.c_str();
|
||||
}
|
||||
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
// This setting key must match EnabledModules.cs [JsonPropertyName("NewPlus")]
|
||||
return newplus::constants::non_localizable::powertoy_key;
|
||||
}
|
||||
|
||||
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
|
||||
{
|
||||
return powertoys_gpo::getConfiguredNewPlusEnabledValue();
|
||||
}
|
||||
|
||||
virtual bool get_config(_Out_ PWSTR buffer, _Out_ int* buffer_size) override
|
||||
{
|
||||
// Not implemented as Settings are propagating via json
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void set_config(PCWSTR config) override
|
||||
{
|
||||
// The following just checks to see if the Template Location was changed for metrics purposes
|
||||
// Note: We are not saving the settings here and instead relying on read/write of json in Settings App .cs code paths
|
||||
try
|
||||
{
|
||||
json::JsonObject config_as_json = json::JsonValue::Parse(winrt::to_hstring(config)).GetObjectW();
|
||||
|
||||
const auto latest_location_value = config_as_json.GetNamedString(newplus::constants::non_localizable::settings_json_key_template_location).data();
|
||||
const auto existing_location_value = NewSettingsInstance().GetTemplateLocation();
|
||||
|
||||
if (!newplus::utilities::wstring_same_when_comparing_ignore_case(latest_location_value, existing_location_value))
|
||||
{
|
||||
Trace::EventChangedTemplateLocation();
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
Logger::error("Configuration parsing failed: {}", std::string{ e.what() });
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool is_enabled_by_default() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void enable() override
|
||||
{
|
||||
Logger::info("New+ enabled via Settings UI");
|
||||
|
||||
newplus::utilities::register_msix_package();
|
||||
|
||||
powertoy_new_enabled = true;
|
||||
}
|
||||
|
||||
virtual void disable() override
|
||||
{
|
||||
Logger::info("New+ disabled via Settings UI");
|
||||
|
||||
powertoy_new_enabled = false;
|
||||
}
|
||||
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return powertoy_new_enabled;
|
||||
}
|
||||
|
||||
virtual void hide_file_extension(bool hide_file_extension)
|
||||
{
|
||||
Logger::info("New+ hide file extension {}", hide_file_extension);
|
||||
}
|
||||
|
||||
virtual void hide_starting_digits(bool hide_starting_digits)
|
||||
{
|
||||
Logger::info("New+ hide starting digits {}", hide_starting_digits);
|
||||
}
|
||||
|
||||
virtual void template_location(std::wstring path_location)
|
||||
{
|
||||
Logger::info("New+ template location");
|
||||
}
|
||||
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
bool powertoy_new_enabled = false;
|
||||
|
||||
void init_settings()
|
||||
{
|
||||
powertoy_new_enabled = NewSettingsInstance().GetEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new NewModule();
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by AlwaysOnTop.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys.New+"
|
||||
#define INTERNAL_NAME "PowerToys.New+"
|
||||
#define ORIGINAL_FILENAME "PowerToys.NewPlus.ShellExtension.dll"
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
132
src/modules/NewPlus/NewShellExtensionContextMenu/resources.resx
Normal file
@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="context_menu_item_new" xml:space="preserve">
|
||||
<value>New+</value>
|
||||
<comment>The main context menu item that users click on. This should be localized to match New in Windows. e.g. Danish it would become Ny+</comment>
|
||||
</data>
|
||||
<data name="context_menu_item_open_templates" xml:space="preserve">
|
||||
<value>Open templates</value>
|
||||
<comment>The menu item in the context menu that enables user to open the folder that contains their templates.</comment>
|
||||
</data>
|
||||
<data name="default_template_sub_folder_name_where_templates_are_stored" xml:space="preserve">
|
||||
<value>Templates</value>
|
||||
<comment>Default subfolder name where templates are stored.</comment>
|
||||
</data>
|
||||
</root>
|
225
src/modules/NewPlus/NewShellExtensionContextMenu/settings.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <common/utils/gpo.h>
|
||||
#include <common/utils/json.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
#include "settings.h"
|
||||
#include "constants.h"
|
||||
#include "Generated Files/resource.h"
|
||||
|
||||
// NewSettings are stored in PowerToys/New/settings.json
|
||||
// The New PowerToy enabled state is stored in the general PowerToys/settings.json
|
||||
|
||||
static bool LastModifiedTime(const std::wstring& file_Path, FILETIME* returned_file_timestamp)
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA attr{};
|
||||
if (GetFileAttributesExW(file_Path.c_str(), GetFileExInfoStandard, &attr))
|
||||
{
|
||||
*returned_file_timestamp = attr.ftLastWriteTime;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NewSettings::NewSettings()
|
||||
{
|
||||
// New+ overall enable state is stored in the general settings json file
|
||||
general_settings_json_file_path = PTSettingsHelper::get_powertoys_general_save_file_location();
|
||||
|
||||
// New+' actual settings are stored in new_settings_json_file_path
|
||||
std::wstring settings_save_path = PTSettingsHelper::get_module_save_folder_location(newplus::constants::non_localizable::powertoy_key);
|
||||
new_settings_json_file_path = settings_save_path + newplus::constants::non_localizable::settings_json_data_file_path;
|
||||
|
||||
RefreshEnabledState();
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
void NewSettings::Save()
|
||||
{
|
||||
json::JsonObject new_settings_json_data;
|
||||
|
||||
new_settings_json_data.SetNamedValue(newplus::constants::non_localizable::settings_json_key_hide_file_extension,
|
||||
json::value(new_settings.hide_file_extension));
|
||||
|
||||
new_settings_json_data.SetNamedValue(newplus::constants::non_localizable::settings_json_key_hide_starting_digits,
|
||||
json::value(new_settings.hide_starting_digits));
|
||||
|
||||
new_settings_json_data.SetNamedValue(newplus::constants::non_localizable::settings_json_key_template_location,
|
||||
json::value(new_settings.template_location));
|
||||
|
||||
json::to_file(new_settings_json_file_path, new_settings_json_data);
|
||||
|
||||
GetSystemTimeAsFileTime(&new_settings_last_loaded_timestamp);
|
||||
}
|
||||
|
||||
void NewSettings::Load()
|
||||
{
|
||||
if (!std::filesystem::exists(new_settings_json_file_path))
|
||||
{
|
||||
InitializeWithDefaultSettings();
|
||||
|
||||
Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseJson();
|
||||
}
|
||||
}
|
||||
|
||||
void NewSettings::InitializeWithDefaultSettings()
|
||||
{
|
||||
// Init the default New settings - in case the New/settings.json doesn't exist
|
||||
// Currently a similar defaulting logic is also in InitializeWithDefaultSettings in NewViewModel.cs
|
||||
SetHideFileExtension(true);
|
||||
|
||||
SetTemplateLocation(GetTemplateLocationDefaultPath());
|
||||
}
|
||||
|
||||
void NewSettings::RefreshEnabledState()
|
||||
{
|
||||
// Load json general settings from data file, if it was modified since we last checked
|
||||
FILETIME last_modified_timestamp{};
|
||||
if (!(LastModifiedTime(general_settings_json_file_path, &last_modified_timestamp) &&
|
||||
CompareFileTime(&last_modified_timestamp, &general_settings_last_loaded_timestamp) == 1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
general_settings_last_loaded_timestamp = last_modified_timestamp;
|
||||
|
||||
auto json = json::from_file(general_settings_json_file_path);
|
||||
if (!json)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the enabled settings for the New PowerToy via the general settings
|
||||
const json::JsonObject& json_general_settings = json.value();
|
||||
try
|
||||
{
|
||||
json::JsonObject powertoy_new_enabled_state;
|
||||
json::get(json_general_settings, L"enabled", powertoy_new_enabled_state, json::JsonObject{});
|
||||
json::get(powertoy_new_enabled_state, newplus::constants::non_localizable::powertoy_key, new_settings.enabled, false);
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
Logger::error(L"New+ unable to load enabled state from json");
|
||||
}
|
||||
}
|
||||
|
||||
void NewSettings::Reload()
|
||||
{
|
||||
// Load json New settings from data file, if it was modified since we last checked.
|
||||
FILETIME very_latest_modified_timestamp{};
|
||||
if (LastModifiedTime(new_settings_json_file_path, &very_latest_modified_timestamp) &&
|
||||
CompareFileTime(&very_latest_modified_timestamp, &new_settings_last_loaded_timestamp) == 1)
|
||||
{
|
||||
Load();
|
||||
}
|
||||
}
|
||||
|
||||
void NewSettings::ParseJson()
|
||||
{
|
||||
auto json = json::from_file(new_settings_json_file_path);
|
||||
if (json)
|
||||
{
|
||||
try
|
||||
{
|
||||
const json::JsonObject& new_settings_json = json.value();
|
||||
|
||||
if (json::has(new_settings_json, newplus::constants::non_localizable::settings_json_key_hide_file_extension, json::JsonValueType::Boolean))
|
||||
{
|
||||
new_settings.hide_file_extension = new_settings_json.GetNamedBoolean(
|
||||
newplus::constants::non_localizable::settings_json_key_hide_file_extension);
|
||||
}
|
||||
|
||||
if (json::has(new_settings_json, newplus::constants::non_localizable::settings_json_key_hide_starting_digits, json::JsonValueType::Boolean))
|
||||
{
|
||||
new_settings.hide_starting_digits = new_settings_json.GetNamedBoolean(
|
||||
newplus::constants::non_localizable::settings_json_key_hide_starting_digits);
|
||||
}
|
||||
|
||||
if (json::has(new_settings_json, newplus::constants::non_localizable::settings_json_key_template_location, json::JsonValueType::String))
|
||||
{
|
||||
new_settings.template_location = new_settings_json.GetNamedString(
|
||||
newplus::constants::non_localizable::settings_json_key_template_location);
|
||||
}
|
||||
}
|
||||
catch (const winrt::hresult_error&)
|
||||
{
|
||||
}
|
||||
}
|
||||
GetSystemTimeAsFileTime(&new_settings_last_loaded_timestamp);
|
||||
}
|
||||
|
||||
bool NewSettings::GetEnabled()
|
||||
{
|
||||
auto gpoSetting = powertoys_gpo::getConfiguredNewPlusEnabledValue();
|
||||
if (gpoSetting == powertoys_gpo::gpo_rule_configured_enabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (gpoSetting == powertoys_gpo::gpo_rule_configured_disabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Reload();
|
||||
|
||||
RefreshEnabledState();
|
||||
|
||||
return new_settings.enabled;
|
||||
}
|
||||
|
||||
bool NewSettings::GetHideFileExtension() const
|
||||
{
|
||||
return new_settings.hide_file_extension;
|
||||
}
|
||||
|
||||
void NewSettings::SetHideFileExtension(const bool hide_file_extension)
|
||||
{
|
||||
new_settings.hide_file_extension = hide_file_extension;
|
||||
}
|
||||
|
||||
bool NewSettings::GetHideStartingDigits() const
|
||||
{
|
||||
return new_settings.hide_starting_digits;
|
||||
}
|
||||
|
||||
void NewSettings::SetHideStartingDigits(const bool hide_starting_digits)
|
||||
{
|
||||
new_settings.hide_starting_digits = hide_starting_digits;
|
||||
}
|
||||
|
||||
std::wstring NewSettings::GetTemplateLocation() const
|
||||
{
|
||||
return new_settings.template_location;
|
||||
}
|
||||
|
||||
void NewSettings::SetTemplateLocation(const std::wstring template_location)
|
||||
{
|
||||
new_settings.template_location = template_location;
|
||||
}
|
||||
|
||||
std::wstring NewSettings::GetTemplateLocationDefaultPath()
|
||||
{
|
||||
static const std::wstring default_template_sub_folder_name =
|
||||
GET_RESOURCE_STRING_FALLBACK(
|
||||
IDS_DEFAULT_TEMPLATE_SUB_FOLDER_NAME_WHERE_TEMPLATES_ARE_STORED,
|
||||
L"Templates");
|
||||
|
||||
static const std::wstring full_path = PTSettingsHelper::get_module_save_folder_location(
|
||||
newplus::constants::non_localizable::powertoy_key) +
|
||||
L"\\" + default_template_sub_folder_name;
|
||||
|
||||
return full_path;
|
||||
}
|
||||
|
||||
NewSettings& NewSettingsInstance()
|
||||
{
|
||||
static NewSettings instance;
|
||||
|
||||
return instance;
|
||||
}
|
45
src/modules/NewPlus/NewShellExtensionContextMenu/settings.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
class NewSettings
|
||||
{
|
||||
public:
|
||||
NewSettings();
|
||||
|
||||
bool GetEnabled();
|
||||
bool GetHideFileExtension() const;
|
||||
void SetHideFileExtension(const bool hide_file_extension);
|
||||
bool GetHideStartingDigits() const;
|
||||
void SetHideStartingDigits(const bool hide_starting_digits);
|
||||
std::wstring GetTemplateLocation() const;
|
||||
void SetTemplateLocation(const std::wstring template_location);
|
||||
|
||||
void Save();
|
||||
void Load();
|
||||
|
||||
private:
|
||||
struct Settings
|
||||
{
|
||||
// These values are not used
|
||||
bool enabled{ false };
|
||||
bool hide_file_extension{ true };
|
||||
bool hide_starting_digits{ true };
|
||||
std::wstring template_location;
|
||||
};
|
||||
|
||||
void RefreshEnabledState();
|
||||
void InitializeWithDefaultSettings();
|
||||
std::wstring GetTemplateLocationDefaultPath();
|
||||
|
||||
void Reload();
|
||||
void ParseJson();
|
||||
|
||||
Settings new_settings;
|
||||
std::wstring general_settings_json_file_path;
|
||||
std::wstring new_settings_json_file_path;
|
||||
FILETIME general_settings_last_loaded_timestamp{};
|
||||
FILETIME new_settings_last_loaded_timestamp{};
|
||||
};
|
||||
|
||||
NewSettings& NewSettingsInstance();
|
@ -0,0 +1,87 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "shell_context_menu.h"
|
||||
#include "shell_context_sub_menu.h"
|
||||
#include "shell_context_sub_menu_item.h"
|
||||
#include "template_folder.h"
|
||||
#include "new_utilities.h"
|
||||
#include "settings.h"
|
||||
#include "trace.h"
|
||||
#include "Generated Files/resource.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace newplus;
|
||||
|
||||
#pragma region IExplorerCommand
|
||||
IFACEMETHODIMP shell_context_menu::GetTitle(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_title)
|
||||
{
|
||||
static const std::wstring localized_context_menu_item =
|
||||
GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_NEW, L"New+");
|
||||
|
||||
return SHStrDup(localized_context_menu_item.c_str(), returned_title);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_menu::GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_icon)
|
||||
{
|
||||
*returned_icon = nullptr;
|
||||
|
||||
static const auto icon_resource_filepath = utilities::get_new_icon_resource_filepath(module_instance_handle, ThemeHelpers::GetAppTheme());
|
||||
|
||||
return SHStrDup(icon_resource_filepath.c_str(), returned_icon);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_menu::GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_tool_tip)
|
||||
{
|
||||
*returned_tool_tip = nullptr;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_menu::GetCanonicalName(_Out_ GUID* returned_id)
|
||||
{
|
||||
*returned_id = __uuidof(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_menu::GetState(_In_opt_ IShellItemArray*, _In_ BOOL, _Out_ EXPCMDSTATE* returned_state)
|
||||
{
|
||||
if (!NewSettingsInstance().GetEnabled())
|
||||
{
|
||||
*returned_state = ECS_HIDDEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
*returned_state = ECS_ENABLED;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_menu::Invoke(_In_opt_ IShellItemArray*, _In_opt_ IBindCtx*) noexcept
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_menu::GetFlags(_Out_ EXPCMDFLAGS* returned_menu_item_flags)
|
||||
{
|
||||
*returned_menu_item_flags = ECF_HASSUBCOMMANDS;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_menu::EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands)
|
||||
{
|
||||
auto e = Make<shell_context_sub_menu>(site_of_folder);
|
||||
return e->QueryInterface(IID_PPV_ARGS(returned_enum_commands));
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region IObjectWithSite
|
||||
IFACEMETHODIMP shell_context_menu::SetSite(_In_ IUnknown* site) noexcept
|
||||
{
|
||||
this->site_of_folder = site;
|
||||
return S_OK;
|
||||
}
|
||||
IFACEMETHODIMP shell_context_menu::GetSite(_In_ REFIID riid, _COM_Outptr_ void** returned_site) noexcept
|
||||
{
|
||||
return this->site_of_folder.CopyTo(riid, returned_site);
|
||||
}
|
||||
#pragma endregion
|
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
#define NEW_SHELL_EXTENSION_EXPLORER_COMMAND_UUID_STR "69824FC6-4660-4A09-9E7C-48DA63C6CC0F"
|
||||
|
||||
// File Explorer context menu "New+"
|
||||
class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_UUID_STR)) shell_context_menu final :
|
||||
public RuntimeClass<
|
||||
RuntimeClassFlags<ClassicCom>,
|
||||
IExplorerCommand,
|
||||
IObjectWithSite>
|
||||
{
|
||||
public:
|
||||
#pragma region IExplorerCommand
|
||||
IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_title);
|
||||
IFACEMETHODIMP GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_icon);
|
||||
IFACEMETHODIMP GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_tool_tip);
|
||||
IFACEMETHODIMP GetCanonicalName(_Out_ GUID* returned_id);
|
||||
IFACEMETHODIMP GetState(_In_opt_ IShellItemArray*, _In_ BOOL, _Out_ EXPCMDSTATE* returned_state);
|
||||
IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray*, _In_opt_ IBindCtx*) noexcept;
|
||||
IFACEMETHODIMP GetFlags(_Out_ EXPCMDFLAGS* returned_menu_item_flags);
|
||||
IFACEMETHODIMP EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands);
|
||||
#pragma endregion
|
||||
|
||||
#pragma region IObjectWithSite
|
||||
IFACEMETHODIMP SetSite(_In_ IUnknown* site) noexcept;
|
||||
|
||||
IFACEMETHODIMP GetSite(_In_ REFIID riid, _COM_Outptr_ void** site) noexcept;
|
||||
#pragma endregion
|
||||
|
||||
protected:
|
||||
HINSTANCE instance_handle = 0;
|
||||
ComPtr<IUnknown> site_of_folder;
|
||||
};
|
@ -0,0 +1,80 @@
|
||||
#include "pch.h"
|
||||
#include "shell_context_sub_menu.h"
|
||||
#include "trace.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
// // Sub context menu command enumerator
|
||||
shell_context_sub_menu::shell_context_sub_menu(const ComPtr<IUnknown> site_of_folder)
|
||||
{
|
||||
this->site_of_folder = site_of_folder;
|
||||
|
||||
// Determine the New+ Template folder location
|
||||
const std::filesystem::path root = utilities::get_new_template_folder_location();
|
||||
|
||||
// Create the New+ Template folder location if it doesn't exist (very rare scenario)
|
||||
utilities::create_folder_if_not_exist(root);
|
||||
|
||||
// Scan the folder for any files and folders (the templates)
|
||||
templates = new template_folder(root);
|
||||
templates->rescan_template_folder();
|
||||
|
||||
// Add template items to context menu
|
||||
const auto number_of_templates = templates->list_of_templates.size();
|
||||
int index = 0;
|
||||
for (int i = 0; i < number_of_templates; i++)
|
||||
{
|
||||
explorer_menu_item_commands.push_back(Make<shell_context_sub_menu_item>(templates->get_template_item(i), site_of_folder));
|
||||
}
|
||||
|
||||
// Add separator to context menu
|
||||
explorer_menu_item_commands.push_back(Make<separator_context_menu_item>());
|
||||
|
||||
// Add "Open templates" item to context menu
|
||||
explorer_menu_item_commands.push_back(Make<template_folder_context_menu_item>(root));
|
||||
|
||||
current_command = explorer_menu_item_commands.cbegin();
|
||||
|
||||
// Log that context menu was shown and with how many items
|
||||
Trace::EventShowTemplateItems(number_of_templates);
|
||||
}
|
||||
|
||||
// IEnumExplorerCommand
|
||||
IFACEMETHODIMP shell_context_sub_menu::Next(ULONG celt, __out_ecount_part(celt, *pceltFetched) IExplorerCommand** apUICommand, __out_opt ULONG* pceltFetched)
|
||||
{
|
||||
ULONG fetched{ 0 };
|
||||
|
||||
if (pceltFetched)
|
||||
{
|
||||
*pceltFetched = 0ul;
|
||||
}
|
||||
|
||||
for (ULONG i = 0; (i < celt) && (current_command != explorer_menu_item_commands.cend()); i++)
|
||||
{
|
||||
current_command->CopyTo(&apUICommand[0]);
|
||||
current_command++;
|
||||
fetched++;
|
||||
}
|
||||
|
||||
if (pceltFetched)
|
||||
{
|
||||
*pceltFetched = fetched;
|
||||
}
|
||||
|
||||
return (fetched == celt) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_sub_menu::Skip(ULONG)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
IFACEMETHODIMP shell_context_sub_menu::Reset()
|
||||
{
|
||||
current_command = explorer_menu_item_commands.cbegin();
|
||||
return S_OK;
|
||||
}
|
||||
IFACEMETHODIMP shell_context_sub_menu::Clone(__deref_out IEnumExplorerCommand** ppenum)
|
||||
{
|
||||
*ppenum = nullptr;
|
||||
return E_NOTIMPL;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "template_folder.h"
|
||||
#include "new_utilities.h"
|
||||
#include "shell_context_sub_menu_item.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace newplus;
|
||||
|
||||
// // Sub context menu command enumerator
|
||||
class shell_context_sub_menu final : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IEnumExplorerCommand>
|
||||
{
|
||||
public:
|
||||
shell_context_sub_menu(const ComPtr<IUnknown> site_of_folder);
|
||||
|
||||
// IEnumExplorerCommand
|
||||
IFACEMETHODIMP Next(ULONG celt, __out_ecount_part(celt, *pceltFetched) IExplorerCommand** apUICommand, __out_opt ULONG* pceltFetched);
|
||||
IFACEMETHODIMP Skip(ULONG);
|
||||
IFACEMETHODIMP Reset();
|
||||
IFACEMETHODIMP Clone(__deref_out IEnumExplorerCommand** ppenum);
|
||||
|
||||
protected:
|
||||
std::vector<ComPtr<IExplorerCommand>> explorer_menu_item_commands;
|
||||
std::vector<ComPtr<IExplorerCommand>>::const_iterator current_command;
|
||||
template_folder* templates;
|
||||
ComPtr<IUnknown> site_of_folder;
|
||||
};
|
@ -0,0 +1,160 @@
|
||||
#include "pch.h"
|
||||
#include "shell_context_sub_menu_item.h"
|
||||
|
||||
#include "trace.h"
|
||||
#include "Generated Files/resource.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
// Sub context menu containing the actual list of templates
|
||||
shell_context_sub_menu_item::shell_context_sub_menu_item()
|
||||
{
|
||||
this->template_entry = nullptr;
|
||||
}
|
||||
|
||||
shell_context_sub_menu_item::shell_context_sub_menu_item(const template_item* template_entry, const ComPtr<IUnknown> site_of_folder)
|
||||
{
|
||||
this->template_entry = template_entry;
|
||||
this->site_of_folder = site_of_folder;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_sub_menu_item::GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* title)
|
||||
{
|
||||
return SHStrDup(this->template_entry->get_menu_title(
|
||||
!utilities::get_newplus_setting_hide_extension(),
|
||||
!utilities::get_newplus_setting_hide_starting_digits()
|
||||
).c_str(), title);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_sub_menu_item::GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* icon)
|
||||
{
|
||||
return SHStrDup(this->template_entry->get_explorer_icon().c_str(), icon);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_sub_menu_item::GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* infoTip)
|
||||
{
|
||||
*infoTip = nullptr;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
IFACEMETHODIMP shell_context_sub_menu_item::GetCanonicalName(_Out_ GUID* guidCommandName)
|
||||
{
|
||||
*guidCommandName = GUID_NULL;
|
||||
return S_OK;
|
||||
}
|
||||
IFACEMETHODIMP shell_context_sub_menu_item::GetState(_In_opt_ IShellItemArray* selection, _In_ BOOL, _Out_ EXPCMDSTATE* returned_state)
|
||||
{
|
||||
// Commented out for performance reasons
|
||||
|
||||
//DWORD object_count = 0;
|
||||
//selection->GetCount(&object_count);
|
||||
|
||||
//if (object_count == 1)
|
||||
//{
|
||||
// *returned_state = ECS_ENABLED;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// *returned_state = ECS_HIDDEN;
|
||||
//}
|
||||
|
||||
*returned_state = ECS_ENABLED;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_sub_menu_item::Invoke(_In_opt_ IShellItemArray*, _In_opt_ IBindCtx*) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
// Determine target path of where context menu was displayed
|
||||
const auto target_path_name = utilities::get_path_from_unknown_site(site_of_folder);
|
||||
|
||||
// Determine initial filename
|
||||
std::filesystem::path source_fullpath = template_entry->path;
|
||||
std::filesystem::path target_fullpath = std::wstring(target_path_name)
|
||||
+ L"\\"
|
||||
+ this->template_entry->get_target_filename(!utilities::get_newplus_setting_hide_starting_digits());
|
||||
|
||||
// Copy file and determine final filename
|
||||
std::filesystem::path target_final_fullpath = this->template_entry->copy_object_to(GetActiveWindow(), target_fullpath);
|
||||
|
||||
Trace::EventCopyTemplate(target_final_fullpath.extension().c_str());
|
||||
|
||||
// Refresh folder items
|
||||
SHChangeNotify(SHCNE_CREATE, SHCNF_PATH | SHCNF_FLUSH, target_final_fullpath.wstring().c_str(), NULL);
|
||||
|
||||
// Enter rename mode
|
||||
this->template_entry->enter_rename_mode(site_of_folder, target_final_fullpath);
|
||||
|
||||
Trace::EventCopyTemplateResult(S_OK);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
Trace::EventCopyTemplateResult(S_FALSE);
|
||||
Logger::error(ex.what());
|
||||
}
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_sub_menu_item::GetFlags(_Out_ EXPCMDFLAGS* returned_flags)
|
||||
{
|
||||
*returned_flags = ECF_DEFAULT;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP shell_context_sub_menu_item::EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** enumCommands)
|
||||
{
|
||||
*enumCommands = nullptr;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// Sub context menu - separator
|
||||
IFACEMETHODIMP separator_context_menu_item::GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* title)
|
||||
{
|
||||
title = nullptr;
|
||||
|
||||
// NOTE: Must by S_FALSE for the separator to show up
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP separator_context_menu_item::GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* icon)
|
||||
{
|
||||
*icon = nullptr;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP separator_context_menu_item::GetFlags(_Out_ EXPCMDFLAGS* returned_flags)
|
||||
{
|
||||
*returned_flags = ECF_ISSEPARATOR;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Sub context menu - "Open templates" New+ folder
|
||||
template_folder_context_menu_item::template_folder_context_menu_item(const std::filesystem::path shell_template_folder)
|
||||
{
|
||||
this->shell_template_folder = shell_template_folder;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP template_folder_context_menu_item::GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* name)
|
||||
{
|
||||
static const std::wstring localized_context_menu_item =
|
||||
GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_OPEN_TEMPLATES, L"Open templates");
|
||||
|
||||
return SHStrDup(localized_context_menu_item.c_str(), name);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP template_folder_context_menu_item::GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* icon)
|
||||
{
|
||||
return SHStrDup(utilities::get_open_templates_icon_resource_filepath(module_instance_handle, ThemeHelpers::GetAppTheme()).c_str(), icon);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP template_folder_context_menu_item::Invoke(_In_opt_ IShellItemArray* selection, _In_opt_ IBindCtx*) noexcept
|
||||
{
|
||||
Logger::info(L"Open templates folder");
|
||||
const std::wstring verb_hardcoded_do_not_change = L"open";
|
||||
ShellExecute(nullptr, verb_hardcoded_do_not_change.c_str(), shell_template_folder.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
||||
|
||||
return S_OK;
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#include "template_folder.h"
|
||||
#include "template_item.h"
|
||||
#include "new_utilities.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace newplus;
|
||||
|
||||
// The sub-context-menu that displays the list of templates
|
||||
class shell_context_sub_menu_item : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IExplorerCommand>
|
||||
{
|
||||
public:
|
||||
shell_context_sub_menu_item(const template_item* template_entry, const ComPtr<IUnknown> site_of_folder);
|
||||
|
||||
// IExplorerCommand
|
||||
IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* title);
|
||||
|
||||
IFACEMETHODIMP GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* icon);
|
||||
|
||||
IFACEMETHODIMP GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* infoTip);
|
||||
|
||||
IFACEMETHODIMP GetCanonicalName(_Out_ GUID* guidCommandName);
|
||||
|
||||
IFACEMETHODIMP GetState(_In_opt_ IShellItemArray* selection, _In_ BOOL okToBeSlow, _Out_ EXPCMDSTATE* returned_state);
|
||||
|
||||
IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray* selection, _In_opt_ IBindCtx*) noexcept;
|
||||
|
||||
IFACEMETHODIMP GetFlags(_Out_ EXPCMDFLAGS* returned_flags);
|
||||
|
||||
IFACEMETHODIMP EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** enumCommands);
|
||||
|
||||
protected:
|
||||
shell_context_sub_menu_item();
|
||||
const template_item* template_entry;
|
||||
ComPtr<IUnknown> site_of_folder;
|
||||
};
|
||||
|
||||
// Sub-context-menu separator between the list of templates menu-items and "Open templates" menu-item
|
||||
class separator_context_menu_item final : public shell_context_sub_menu_item
|
||||
{
|
||||
public:
|
||||
IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* title);
|
||||
|
||||
IFACEMETHODIMP GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* icon);
|
||||
|
||||
IFACEMETHODIMP GetFlags(_Out_ EXPCMDFLAGS* returned_flags);
|
||||
};
|
||||
|
||||
// Sub-context-menu - The "Open templates" menu-item
|
||||
class template_folder_context_menu_item final : public shell_context_sub_menu_item
|
||||
{
|
||||
public:
|
||||
template_folder_context_menu_item(const std::filesystem::path shell_template_folder);
|
||||
|
||||
IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* name);
|
||||
|
||||
IFACEMETHODIMP GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* icon);
|
||||
|
||||
IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray* selection, _In_opt_ IBindCtx*) noexcept;
|
||||
|
||||
std::filesystem::path shell_template_folder;
|
||||
};
|
@ -0,0 +1,52 @@
|
||||
#include "pch.h"
|
||||
#include <shellapi.h>
|
||||
#include "template_folder.h"
|
||||
|
||||
using namespace newplus;
|
||||
|
||||
template_folder::template_folder(){};
|
||||
|
||||
template_folder::template_folder(const std::filesystem::path newplus_template_folder)
|
||||
{
|
||||
this->template_folder_path = newplus_template_folder;
|
||||
}
|
||||
|
||||
void template_folder::init()
|
||||
{
|
||||
rescan_template_folder();
|
||||
}
|
||||
|
||||
void template_folder::rescan_template_folder()
|
||||
{
|
||||
list_of_templates.clear();
|
||||
|
||||
std::list<std::pair<std::wstring, template_item*>> dirs;
|
||||
std::list<std::pair<std::wstring, template_item*>> files;
|
||||
for (const auto& entry : std::filesystem::directory_iterator(template_folder_path))
|
||||
{
|
||||
if (entry.is_directory())
|
||||
{
|
||||
dirs.push_back({ entry.path().wstring(), new template_item(entry) });
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!utilities::is_hidden(entry.path()))
|
||||
{
|
||||
files.push_back({ entry.path().wstring(), new template_item(entry) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// List of templates are sorted, with template-directories/folders first then followed by template-files
|
||||
dirs.sort();
|
||||
files.sort();
|
||||
list_of_templates = dirs;
|
||||
list_of_templates.splice(list_of_templates.end(), files);
|
||||
}
|
||||
|
||||
template_item* template_folder::get_template_item(const int index) const
|
||||
{
|
||||
auto it = list_of_templates.begin();
|
||||
std::advance(it, index);
|
||||
return it->second;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include "template_item.h"
|
||||
|
||||
namespace newplus
|
||||
{
|
||||
class template_folder
|
||||
{
|
||||
public:
|
||||
template_folder(const std::filesystem::path newplus_template_folder);
|
||||
void rescan_template_folder();
|
||||
|
||||
std::filesystem::path template_folder_path;
|
||||
std::list<std::pair<std::wstring, template_item*>> list_of_templates;
|
||||
|
||||
template_item* get_template_item(const int index) const;
|
||||
|
||||
protected:
|
||||
template_folder();
|
||||
void init();
|
||||
};
|
||||
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
|
||||
|
||||
#include "pch.h"
|
||||
#include "template_item.h"
|
||||
#include <shellapi.h>
|
||||
#include "new_utilities.h"
|
||||
#include <cassert>
|
||||
#include <thread>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj_core.h>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace newplus;
|
||||
|
||||
template_item::template_item(const std::filesystem::path entry)
|
||||
{
|
||||
path = entry;
|
||||
}
|
||||
|
||||
std::wstring template_item::get_menu_title(const bool show_extension, const bool show_starting_digits) const
|
||||
{
|
||||
std::wstring title = path.filename();
|
||||
|
||||
if (!show_starting_digits)
|
||||
{
|
||||
// Hide starting digits, spaces, and .
|
||||
title = remove_starting_digits_from_filename(title);
|
||||
}
|
||||
|
||||
if (show_extension || !path.has_extension())
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
std::wstring ext = path.extension();
|
||||
title = title.substr(0, title.length() - ext.length());
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
std::wstring template_item::get_target_filename(const bool include_starting_digits) const
|
||||
{
|
||||
std::wstring filename = path.filename();
|
||||
|
||||
if (!include_starting_digits)
|
||||
{
|
||||
// Remove starting digits, spaces, and .
|
||||
filename = remove_starting_digits_from_filename(filename);
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
std::wstring template_item::remove_starting_digits_from_filename(std::wstring filename) const
|
||||
{
|
||||
filename.erase(0, min(filename.find_first_not_of(L"0123456789 ."), filename.size()));
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
std::wstring template_item::get_explorer_icon() const
|
||||
{
|
||||
return utilities::get_explorer_icon(path);
|
||||
}
|
||||
|
||||
std::filesystem::path template_item::copy_object_to(const HWND window_handle, const std::filesystem::path destination) const
|
||||
{
|
||||
// SHFILEOPSTRUCT wants the from and to paths to be terminated with two NULLs,
|
||||
wchar_t double_terminated_path_from[MAX_PATH + 1] = { 0 };
|
||||
wcsncpy_s(double_terminated_path_from, this->path.c_str(), this->path.string().length());
|
||||
double_terminated_path_from[this->path.string().length() + 1] = 0;
|
||||
|
||||
wchar_t double_terminated_path_to[MAX_PATH + 1] = { 0 };
|
||||
wcsncpy_s(double_terminated_path_to, destination.c_str(), destination.string().length());
|
||||
double_terminated_path_to[destination.string().length() + 1] = 0;
|
||||
|
||||
SHFILEOPSTRUCT file_operation_params = { 0 };
|
||||
file_operation_params.wFunc = FO_COPY;
|
||||
file_operation_params.hwnd = window_handle;
|
||||
file_operation_params.pFrom = double_terminated_path_from;
|
||||
file_operation_params.pTo = double_terminated_path_to;
|
||||
file_operation_params.fFlags = FOF_RENAMEONCOLLISION | FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS | FOF_WANTMAPPINGHANDLE;
|
||||
|
||||
const int result = SHFileOperation(&file_operation_params);
|
||||
|
||||
if (!file_operation_params.hNameMappings)
|
||||
{
|
||||
// No file name collision on copy
|
||||
return destination;
|
||||
}
|
||||
|
||||
struct file_operation_collision_mapping
|
||||
{
|
||||
int index;
|
||||
SHNAMEMAPPING* mapping;
|
||||
};
|
||||
|
||||
file_operation_collision_mapping* mapping = static_cast<file_operation_collision_mapping*>(file_operation_params.hNameMappings);
|
||||
SHNAMEMAPPING* map = &mapping->mapping[0];
|
||||
std::wstring final_path(map->pszNewPath);
|
||||
|
||||
SHFreeNameMappings(file_operation_params.hNameMappings);
|
||||
|
||||
return final_path;
|
||||
}
|
||||
|
||||
void template_item::enter_rename_mode(const ComPtr<IUnknown> site, const std::filesystem::path target_fullpath) const
|
||||
{
|
||||
std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, site, target_fullpath);
|
||||
thread_for_renaming_workaround.detach();
|
||||
}
|
||||
|
||||
void template_item::rename_on_other_thread_workaround(const ComPtr<IUnknown> site, const std::filesystem::path target_fullpath)
|
||||
{
|
||||
// Have been unable to have Windows Explorer Shell enter rename mode from the main thread
|
||||
// Sleep for a bit to only enter rename mode when icon has been drawn. Not strictly needed.
|
||||
const std::chrono::milliseconds approx_wait_for_icon_redraw_not_needed{ 350 };
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(approx_wait_for_icon_redraw_not_needed));
|
||||
|
||||
const std::wstring filename = target_fullpath.filename();
|
||||
|
||||
ComPtr<IServiceProvider> service_provider;
|
||||
site->QueryInterface(IID_PPV_ARGS(&service_provider));
|
||||
ComPtr<IFolderView> folder_view;
|
||||
service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&folder_view));
|
||||
|
||||
int count = 0;
|
||||
folder_view->ItemCount(SVGIO_ALLVIEW, &count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
std::wstring path_of_item(MAX_PATH, 0);
|
||||
LPITEMIDLIST pidl;
|
||||
|
||||
folder_view->Item(i, &pidl);
|
||||
SHGetPathFromIDList(pidl, &path_of_item[0]);
|
||||
CoTaskMemFree(pidl);
|
||||
|
||||
std::wstring current_filename = std::filesystem::path(path_of_item.c_str()).filename();
|
||||
|
||||
if (utilities::wstring_same_when_comparing_ignore_case(filename, current_filename))
|
||||
{
|
||||
folder_view->SelectItem(i, SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
namespace newplus
|
||||
{
|
||||
class template_item
|
||||
{
|
||||
public:
|
||||
template_item(const std::filesystem::path entry);
|
||||
|
||||
std::wstring get_menu_title(const bool show_extension, const bool show_starting_digits) const;
|
||||
|
||||
std::wstring get_target_filename(const bool include_starting_digits) const;
|
||||
|
||||
std::wstring get_explorer_icon() const;
|
||||
|
||||
std::filesystem::path copy_object_to(const HWND window_handle, const std::filesystem::path destination) const;
|
||||
|
||||
void enter_rename_mode(const ComPtr<IUnknown> site, const std::filesystem::path target_folder) const;
|
||||
|
||||
std::filesystem::path path;
|
||||
|
||||
private:
|
||||
static void rename_on_other_thread_workaround(const ComPtr<IUnknown> site, const std::filesystem::path target_fullpath);
|
||||
|
||||
std::wstring remove_starting_digits_from_filename(std::wstring filename) const;
|
||||
};
|
||||
}
|
70
src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "trace.h"
|
||||
#include <common/Telemetry/ProjectTelemetry.h>
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::EventToggleOnOff(_In_ const bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"NewPlus_EventToggleOnOff",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
|
||||
void Trace::EventChangedTemplateLocation() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"NewPlus_ChangedTemplateLocation",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
void Trace::EventShowTemplateItems(const size_t number_of_templates) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"NewPlus_EventShowTemplateItems",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingValue(number_of_templates, "Count"));
|
||||
}
|
||||
|
||||
void Trace::EventCopyTemplate(_In_ const std::wstring template_file_extension) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"NewPlus_EventCopyTemplate",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingWideString(template_file_extension.c_str(), "Ext"));
|
||||
}
|
||||
|
||||
void Trace::EventCopyTemplateResult(_In_ const HRESULT hr) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"NewPlus_EventCopyTemplateResult",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingHResult(hr),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
15
src/modules/NewPlus/NewShellExtensionContextMenu/trace.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider() noexcept;
|
||||
static void UnregisterProvider() noexcept;
|
||||
static void EventToggleOnOff(_In_ const bool new_enabled_state) noexcept;
|
||||
static void EventChangedTemplateLocation() noexcept;
|
||||
static void EventShowTemplateItems(_In_ const size_t number_of_templates) noexcept;
|
||||
static void EventCopyTemplate(_In_ const std::wstring template_file_extension) noexcept;
|
||||
static void EventCopyTemplateResult(_In_ const HRESULT hr) noexcept;
|
||||
};
|
@ -49,7 +49,7 @@ static ThemeListener theme_listener{};
|
||||
static void handleTheme()
|
||||
{
|
||||
auto theme = theme_listener.AppTheme;
|
||||
auto isDark = theme == AppTheme::Dark;
|
||||
auto isDark = theme == Theme::Dark;
|
||||
Logger::info(L"Theme is now {}", isDark ? L"Dark" : L"Light");
|
||||
if (hwndEditKeyboardNativeWindow != nullptr)
|
||||
{
|
||||
@ -137,7 +137,7 @@ inline void CreateEditKeyboardWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMan
|
||||
windowClass.lpfnWndProc = EditKeyboardWindowProc;
|
||||
windowClass.hInstance = hInst;
|
||||
windowClass.lpszClassName = szWindowClass;
|
||||
windowClass.hbrBackground = CreateSolidBrush((ThemeHelpers::GetAppTheme() == AppTheme::Dark) ? 0x00000000 : 0x00FFFFFF);
|
||||
windowClass.hbrBackground = CreateSolidBrush((ThemeHelpers::GetAppTheme() == Theme::Dark) ? 0x00000000 : 0x00FFFFFF);
|
||||
windowClass.hIcon = static_cast<HICON>(LoadImageW(
|
||||
windowClass.hInstance,
|
||||
MAKEINTRESOURCE(IDS_KEYBOARDMANAGER_ICON),
|
||||
|
@ -43,7 +43,7 @@ static ThemeListener theme_listener{};
|
||||
static void handleTheme()
|
||||
{
|
||||
auto theme = theme_listener.AppTheme;
|
||||
auto isDark = theme == AppTheme::Dark;
|
||||
auto isDark = theme == Theme::Dark;
|
||||
Logger::info(L"Theme is now {}", isDark ? L"Dark" : L"Light");
|
||||
if (hwndEditShortcutsNativeWindow != nullptr)
|
||||
{
|
||||
@ -90,7 +90,7 @@ inline void CreateEditShortcutsWindowImpl(HINSTANCE hInst, KBMEditor::KeyboardMa
|
||||
windowClass.lpfnWndProc = EditShortcutsWindowProc;
|
||||
windowClass.hInstance = hInst;
|
||||
windowClass.lpszClassName = szWindowClass;
|
||||
windowClass.hbrBackground = CreateSolidBrush((ThemeHelpers::GetAppTheme() == AppTheme::Dark) ? 0x00000000 : 0x00FFFFFF);
|
||||
windowClass.hbrBackground = CreateSolidBrush((ThemeHelpers::GetAppTheme() == Theme::Dark) ? 0x00000000 : 0x00FFFFFF);
|
||||
windowClass.hIcon = static_cast<HICON>(LoadImageW(
|
||||
windowClass.hInstance,
|
||||
MAKEINTRESOURCE(IDS_KEYBOARDMANAGER_ICON),
|
||||
|
@ -43,7 +43,7 @@ HWND CurrentWindow;
|
||||
void handleTheme()
|
||||
{
|
||||
auto theme = theme_listener.AppTheme;
|
||||
auto isDark = theme == AppTheme::Dark;
|
||||
auto isDark = theme == Theme::Dark;
|
||||
Logger::info(L"Theme is now {}", isDark ? L"Dark" : L"Light");
|
||||
ThemeHelpers::SetImmersiveDarkMode(CurrentWindow, isDark);
|
||||
}
|
||||
|
@ -154,6 +154,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
||||
L"WinUI3Apps/PowerToys.FileLocksmithExt.dll",
|
||||
L"WinUI3Apps/PowerToys.RegistryPreviewExt.dll",
|
||||
L"WinUI3Apps/PowerToys.MeasureToolModuleInterface.dll",
|
||||
L"WinUI3Apps/PowerToys.NewPlus.ShellExtension.dll",
|
||||
L"WinUI3Apps/PowerToys.HostsModuleInterface.dll",
|
||||
L"WinUI3Apps/PowerToys.Peek.dll",
|
||||
L"WinUI3Apps/PowerToys.EnvironmentVariablesModuleInterface.dll",
|
||||
|
@ -684,6 +684,8 @@ std::string ESettingsWindowNames_to_string(ESettingsWindowNames value)
|
||||
return "Dashboard";
|
||||
case ESettingsWindowNames::AdvancedPaste:
|
||||
return "AdvancedPaste";
|
||||
case ESettingsWindowNames::NewPlus:
|
||||
return "NewPlus";
|
||||
default:
|
||||
{
|
||||
Logger::error(L"Can't convert ESettingsWindowNames value={} to string", static_cast<int>(value));
|
||||
@ -779,6 +781,10 @@ ESettingsWindowNames ESettingsWindowNames_from_string(std::string value)
|
||||
{
|
||||
return ESettingsWindowNames::AdvancedPaste;
|
||||
}
|
||||
else if (value == "NewPlus")
|
||||
{
|
||||
return ESettingsWindowNames::NewPlus;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Can't convert string value={} to ESettingsWindowNames", winrt::to_hstring(value));
|
||||
|
@ -25,6 +25,7 @@ enum class ESettingsWindowNames
|
||||
CropAndLock,
|
||||
EnvironmentVariables,
|
||||
AdvancedPaste,
|
||||
NewPlus,
|
||||
};
|
||||
|
||||
std::string ESettingsWindowNames_to_string(ESettingsWindowNames value);
|
||||
|
@ -462,6 +462,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool newPlus;
|
||||
|
||||
[JsonPropertyName("NewPlus")] // This key must match newplus::constants::non_localizable
|
||||
public bool NewPlus
|
||||
{
|
||||
get => newPlus;
|
||||
set
|
||||
{
|
||||
if (newPlus != value)
|
||||
{
|
||||
LogTelemetryEvent(value);
|
||||
newPlus = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool workspaces = true;
|
||||
|
||||
[JsonPropertyName("Workspaces")]
|
||||
|
48
src/settings-ui/Settings.UI.Library/NewPlusSettings.cs
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using Settings.UI.Library.Resources;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class NewPlusSettings : ISettingsConfig
|
||||
{
|
||||
public const string ModuleName = "NewPlus";
|
||||
|
||||
public void InitializeWithDefaultSettings()
|
||||
{
|
||||
// This code path should never happen
|
||||
}
|
||||
|
||||
public string ToJsonString()
|
||||
{
|
||||
return JsonSerializer.Serialize(this);
|
||||
}
|
||||
|
||||
[JsonPropertyName("HideFileExtension")]
|
||||
public bool HideFileExtension { get; set; }
|
||||
|
||||
[JsonPropertyName("HideStartingDigits")]
|
||||
public bool HideStartingDigits { get; set; }
|
||||
|
||||
[JsonPropertyName("TemplateLocation")]
|
||||
public string TemplateLocation { get; set; }
|
||||
|
||||
public string GetModuleName()
|
||||
{
|
||||
return ModuleName;
|
||||
}
|
||||
|
||||
public bool UpgradeSettingsConfiguration()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -96,6 +96,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Utilities
|
||||
return Directory.GetParent(settingsPath).FullName;
|
||||
}
|
||||
|
||||
public static string GetPowerToysInstallationWinUI3AppsAssetsFolder()
|
||||
{
|
||||
// return .\PowerToys\WinUI3Apps\Assets
|
||||
return Path.Combine(GetPowerToysInstallationFolder(), "WinUI3Apps", "Assets");
|
||||
}
|
||||
|
||||
private static readonly global::PowerToys.Interop.LayoutMapManaged LayoutMap = new global::PowerToys.Interop.LayoutMapManaged();
|
||||
|
||||
public static string GetKeyName(uint key)
|
||||
@ -148,6 +154,30 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
public static void CopyDirectory(string source_directory, string destination_directory, bool copy_recursively)
|
||||
{
|
||||
var current_directory_info = new DirectoryInfo(source_directory);
|
||||
|
||||
DirectoryInfo[] source_subdirectories = current_directory_info.GetDirectories();
|
||||
|
||||
Directory.CreateDirectory(destination_directory);
|
||||
|
||||
foreach (FileInfo file in current_directory_info.GetFiles())
|
||||
{
|
||||
string destination_file_path = Path.Combine(destination_directory, file.Name);
|
||||
file.CopyTo(destination_file_path, true);
|
||||
}
|
||||
|
||||
if (copy_recursively)
|
||||
{
|
||||
foreach (DirectoryInfo subdirectory in source_subdirectories)
|
||||
{
|
||||
string newDestinationDir = Path.Combine(destination_directory, subdirectory.Name);
|
||||
CopyDirectory(subdirectory.FullName, newDestinationDir, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly uint VirtualKeyWindows = global::PowerToys.Interop.Constants.VK_WIN_BOTH;
|
||||
}
|
||||
}
|
||||
|
BIN
src/settings-ui/Settings.UI/Assets/Settings/Icons/NewPlus.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
src/settings-ui/Settings.UI/Assets/Settings/Modules/NewPlus.png
Normal file
After Width: | Height: | Size: 322 KiB |
After Width: | Height: | Size: 879 KiB |
@ -62,6 +62,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
case ModuleType.MouseJump: return generalSettingsConfig.Enabled.MouseJump;
|
||||
case ModuleType.MousePointerCrosshairs: return generalSettingsConfig.Enabled.MousePointerCrosshairs;
|
||||
case ModuleType.MouseWithoutBorders: return generalSettingsConfig.Enabled.MouseWithoutBorders;
|
||||
case ModuleType.NewPlus: return generalSettingsConfig.Enabled.NewPlus;
|
||||
case ModuleType.Peek: return generalSettingsConfig.Enabled.Peek;
|
||||
case ModuleType.PowerRename: return generalSettingsConfig.Enabled.PowerRename;
|
||||
case ModuleType.PowerLauncher: return generalSettingsConfig.Enabled.PowerLauncher;
|
||||
@ -95,6 +96,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
case ModuleType.MouseJump: generalSettingsConfig.Enabled.MouseJump = isEnabled; break;
|
||||
case ModuleType.MousePointerCrosshairs: generalSettingsConfig.Enabled.MousePointerCrosshairs = isEnabled; break;
|
||||
case ModuleType.MouseWithoutBorders: generalSettingsConfig.Enabled.MouseWithoutBorders = isEnabled; break;
|
||||
case ModuleType.NewPlus: generalSettingsConfig.Enabled.NewPlus = isEnabled; break;
|
||||
case ModuleType.Peek: generalSettingsConfig.Enabled.Peek = isEnabled; break;
|
||||
case ModuleType.PowerRename: generalSettingsConfig.Enabled.PowerRename = isEnabled; break;
|
||||
case ModuleType.PowerLauncher: generalSettingsConfig.Enabled.PowerLauncher = isEnabled; break;
|
||||
@ -127,6 +129,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
case ModuleType.MouseJump: return GPOWrapper.GetConfiguredMouseJumpEnabledValue();
|
||||
case ModuleType.MousePointerCrosshairs: return GPOWrapper.GetConfiguredMousePointerCrosshairsEnabledValue();
|
||||
case ModuleType.MouseWithoutBorders: return GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue();
|
||||
case ModuleType.NewPlus: return GPOWrapper.GetConfiguredNewPlusEnabledValue();
|
||||
case ModuleType.Peek: return GPOWrapper.GetConfiguredPeekEnabledValue();
|
||||
case ModuleType.PowerRename: return GPOWrapper.GetConfiguredPowerRenameEnabledValue();
|
||||
case ModuleType.PowerLauncher: return GPOWrapper.GetConfiguredPowerLauncherEnabledValue();
|
||||
@ -160,6 +163,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
ModuleType.MouseJump => typeof(MouseUtilsPage),
|
||||
ModuleType.MousePointerCrosshairs => typeof(MouseUtilsPage),
|
||||
ModuleType.MouseWithoutBorders => typeof(MouseWithoutBordersPage),
|
||||
ModuleType.NewPlus => typeof(NewPlusPage),
|
||||
ModuleType.Peek => typeof(PeekPage),
|
||||
ModuleType.PowerRename => typeof(PowerRenamePage),
|
||||
ModuleType.PowerLauncher => typeof(PowerLauncherPage),
|
||||
|
@ -26,6 +26,11 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
}
|
||||
|
||||
public static string GetFolderDialog(IntPtr hwndOwner)
|
||||
{
|
||||
return GetFolderDialogWithFlags(hwndOwner, 0);
|
||||
}
|
||||
|
||||
public static string GetFolderDialogWithFlags(IntPtr hwndOwner, uint ulFlags)
|
||||
{
|
||||
// windows MAX_PATH with long path enable can be approximated 32k char long
|
||||
// allocating more than double (unicode) to hold the path
|
||||
@ -37,7 +42,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
browseInfo.PidlRoot = IntPtr.Zero;
|
||||
browseInfo.PszDisplayName = null;
|
||||
browseInfo.LpszTitle = null;
|
||||
browseInfo.UlFlags = 0;
|
||||
browseInfo.UlFlags = ulFlags;
|
||||
browseInfo.Lpfn = null;
|
||||
browseInfo.LParam = IntPtr.Zero;
|
||||
browseInfo.IImage = 0;
|
||||
@ -61,5 +66,10 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public struct FolderDialogFlags
|
||||
{
|
||||
public const uint _BIF_NEWDIALOGSTYLE = 0x00000040;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,5 +33,6 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Enums
|
||||
Workspaces,
|
||||
WhatsNew,
|
||||
RegistryPreview,
|
||||
NewPlus,
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@
|
||||
<None Remove="Assets\Settings\Modules\APDialog.dark.png" />
|
||||
<None Remove="Assets\Settings\Modules\APDialog.light.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Remove="SettingsXAML\App.xaml" />
|
||||
</ItemGroup>
|
||||
|
@ -424,6 +424,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
case "Peek": return typeof(PeekPage);
|
||||
case "CropAndLock": return typeof(CropAndLockPage);
|
||||
case "EnvironmentVariables": return typeof(EnvironmentVariablesPage);
|
||||
case "NewPlus": return typeof(NewPlusPage);
|
||||
case "Workspaces": return typeof(WorkspacesPage);
|
||||
default:
|
||||
// Fallback to Dashboard
|
||||
|
@ -0,0 +1,31 @@
|
||||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.OOBE.Views.OobeNewPlus"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tk7controls="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<!-- TODO: Create New+ overview .gif and update ref here -->
|
||||
<controls:OOBEPageControl x:Uid="Oobe_NewPlus" HeroImage="ms-appx:///Assets/Settings/Modules/OOBE/NewPlus.png">
|
||||
<controls:OOBEPageControl.PageContent>
|
||||
<StackPanel Orientation="Vertical" Spacing="12">
|
||||
<TextBlock x:Uid="Oobe_HowToUse" Style="{ThemeResource OobeSubtitleStyle}" />
|
||||
<tk7controls:MarkdownTextBlock x:Uid="Oobe_NewPlus_HowToUse" Background="Transparent" />
|
||||
|
||||
<TextBlock x:Uid="Oobe_TipsAndTricks" Style="{ThemeResource OobeSubtitleStyle}" />
|
||||
<tk7controls:MarkdownTextBlock x:Uid="Oobe_NewPlus_TipsAndTricks" Background="Transparent" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Button x:Uid="OOBE_Settings" Click="SettingsLaunchButton_Click" />
|
||||
|
||||
<HyperlinkButton NavigateUri="https://aka.ms/PowerToysOverview_NewPlus" Style="{StaticResource TextButtonStyle}">
|
||||
<TextBlock x:Uid="NewPlus_Learn_More" TextWrapping="Wrap" />
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</controls:OOBEPageControl.PageContent>
|
||||
</controls:OOBEPageControl>
|
||||
</Page>
|
@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class OobeNewPlus : Page
|
||||
{
|
||||
public OobePowerToysModule ViewModel { get; set; }
|
||||
|
||||
public OobeNewPlus()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.NewPlus]);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
private void SettingsLaunchButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (OobeShellPage.OpenMainWindowCallback != null)
|
||||
{
|
||||
OobeShellPage.OpenMainWindowCallback(typeof(NewPlusPage));
|
||||
}
|
||||
|
||||
ViewModel.LogOpeningSettingsEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogClosingModuleEvent();
|
||||
}
|
||||
}
|
||||
}
|
@ -121,6 +121,10 @@
|
||||
x:Uid="Shell_MouseWithoutBorders"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseWithoutBorders.png}"
|
||||
Tag="MouseWithoutBorders" />
|
||||
<NavigationViewItem
|
||||
x:Uid="NewPlus_Product_Name"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/NewPlus.png}"
|
||||
Tag="NewPlus" />
|
||||
<NavigationViewItem
|
||||
x:Uid="Shell_Peek"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/Peek.png}"
|
||||
|
@ -207,6 +207,12 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
ModuleName = "RegistryPreview",
|
||||
IsNew = true,
|
||||
});
|
||||
|
||||
Modules.Insert((int)PowerToysModules.NewPlus, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = "NewPlus",
|
||||
IsNew = true,
|
||||
});
|
||||
}
|
||||
|
||||
public void OnClosing()
|
||||
@ -285,6 +291,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
case "Hosts": NavigationFrame.Navigate(typeof(OobeHosts)); break;
|
||||
case "RegistryPreview": NavigationFrame.Navigate(typeof(OobeRegistryPreview)); break;
|
||||
case "Peek": NavigationFrame.Navigate(typeof(OobePeek)); break;
|
||||
case "NewPlus": NavigationFrame.Navigate(typeof(OobeNewPlus)); break;
|
||||
case "Workspaces": NavigationFrame.Navigate(typeof(OobeWorkspaces)); break;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.NewPlusPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<controls:SettingsPageControl x:Uid="NewPlus" ModuleImageSource="ms-appx:///Assets/Settings/Modules/NewPlus.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel
|
||||
ChildrenTransitions="{StaticResource SettingsCardsAnimations}"
|
||||
Orientation="Vertical"
|
||||
Spacing="2">
|
||||
<tkcontrols:SettingsCard
|
||||
x:Uid="NewPlus_Enable_Toggle"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/NewPlus.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<InfoBar
|
||||
x:Uid="NewPlus_NoWindows10SupportWarning"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsWin10OrLower, Mode=OneWay}"
|
||||
IsTabStop="{x:Bind ViewModel.IsWin10OrLower, Mode=OneWay}"
|
||||
Severity="Warning" />
|
||||
|
||||
<InfoBar
|
||||
x:Uid="GPO_SettingIsManaged"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay}"
|
||||
IsTabStop="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay}"
|
||||
Severity="Informational" />
|
||||
|
||||
<controls:SettingsGroup x:Uid="NewPlus_Templates" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
x:Uid="NewPlus_Templates_Location"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Command="{x:Bind ViewModel.OpenCurrentNewTemplateFolder}"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsClickEnabled="True">
|
||||
<Button
|
||||
x:Uid="NewPlus_Templates_Location_Change"
|
||||
Command="{x:Bind ViewModel.PickAnotherNewTemplateFolder}"
|
||||
Style="{ThemeResource AccentButtonStyle}" />
|
||||
|
||||
<tkcontrols:SettingsCard.Description>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{x:Bind ViewModel.TemplateLocation, Mode=OneWay}" />
|
||||
<HyperlinkButton x:Uid="NewPlus_Templates_Location_Learn_More" NavigateUri="https://aka.ms/PowerToysOverview_NewPlus_TemplatesLocation" />
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsCard.Description>
|
||||
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<InfoBar
|
||||
x:Uid="NewPlus_TemplatesNotBackupAndRestoreWarning"
|
||||
IsClosable="True"
|
||||
IsOpen="True"
|
||||
IsTabStop="True"
|
||||
Severity="Informational" />
|
||||
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="NewPlus_Display_Options" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="NewPlus_Hide_File_Extension_Toggle" IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch x:Uid="HideFileExtensionToggle" IsOn="{x:Bind ViewModel.HideFileExtension, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="NewPlus_Hide_Starting_Digits_Toggle" IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch x:Uid="HideStartingDigitsToggle" IsOn="{x:Bind ViewModel.HideStartingDigits, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsCard.Description>
|
||||
<TextBlock x:Uid="NewPlus_Hide_Starting_Digits_Description" />
|
||||
</tkcontrols:SettingsCard.Description>
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
</StackPanel>
|
||||
</controls:SettingsPageControl.ModuleContent>
|
||||
|
||||
<controls:SettingsPageControl.PrimaryLinks>
|
||||
<controls:PageLink x:Uid="NewPlus_Learn_More" Link="https://aka.ms/PowerToysOverview_NewPlus" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
<controls:SettingsPageControl.SecondaryLinks>
|
||||
<controls:PageLink Link="https://www.linkedin.com/in/christian-gaardmark/" Text="Christian Gaardmark" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
|
||||
</Page>
|
@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class NewPlusPage : Page, IRefreshablePage
|
||||
{
|
||||
private NewPlusViewModel ViewModel { get; set; }
|
||||
|
||||
public NewPlusPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
var settings_utils = new SettingsUtils();
|
||||
ViewModel = new NewPlusViewModel(settings_utils, SettingsRepository<GeneralSettings>.GetInstance(settings_utils), ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
public void RefreshEnabledState()
|
||||
{
|
||||
ViewModel.RefreshEnabledState();
|
||||
}
|
||||
}
|
||||
}
|
@ -180,6 +180,11 @@
|
||||
helpers:NavHelper.NavigateTo="views:MouseWithoutBordersPage"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseWithoutBorders.png}" />
|
||||
|
||||
<NavigationViewItem
|
||||
x:Uid="NewPlus_Product_Name"
|
||||
helpers:NavHelper.NavigateTo="views:NewPlusPage"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/NewPlus.png}" />
|
||||
|
||||
<NavigationViewItem
|
||||
x:Uid="Shell_Peek"
|
||||
helpers:NavHelper.NavigateTo="views:PeekPage"
|
||||
|
@ -4276,6 +4276,88 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Automatically close the AdvancedPaste window after it loses focus</value>
|
||||
<comment>AdvancedPaste is a product name, do not loc</comment>
|
||||
</data>
|
||||
<data name="NewPlus.ModuleTitle" xml:space="preserve">
|
||||
<value>New+</value>
|
||||
<comment>New+ is the name of the utility. Localize product name in accordance with Windows New</comment>
|
||||
</data>
|
||||
<data name="NewPlus.ModuleDescription" xml:space="preserve">
|
||||
<value>Create files and folders from a personalized set of templates</value>
|
||||
</data>
|
||||
<data name="NewPlus_Product_Name.Content" xml:space="preserve">
|
||||
<value>New+</value>
|
||||
<comment>New+ is the name of the utility. Localize product name in accordance with Windows New</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Product_Description.Description" xml:space="preserve">
|
||||
<value>Create files and folders from a personalized set of templates</value>
|
||||
<comment>New+ product description</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Learn_More.Text" xml:space="preserve">
|
||||
<value>Learn more about New+</value>
|
||||
<comment>New+ learn more link. Localize product name in accordance with Windows New</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Enable_Toggle.Header" xml:space="preserve">
|
||||
<value>Enable New+</value>
|
||||
<comment>Localize product name in accordance with Windows New</comment>
|
||||
</data>
|
||||
<data name="NewPlus_NoWindows10SupportWarning.Title" xml:space="preserve">
|
||||
<value>New+ is not supported in Windows 10 and is not expected to work.</value>
|
||||
</data>
|
||||
<data name="NewPlus_TemplatesNotBackupAndRestoreWarning.Title" xml:space="preserve">
|
||||
<value>PowerToys "Backup and Restore" feature doesn't take templates into account at this moment. If you use that feature, templates will have to be copied manually.</value>
|
||||
</data>
|
||||
<data name="NewPlus_Templates.Header" xml:space="preserve">
|
||||
<value>Templates</value>
|
||||
<comment>Templates label</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Templates_Location.Header" xml:space="preserve">
|
||||
<value>Location</value>
|
||||
<comment>Templates Location label</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Templates_Location_Path.Text" xml:space="preserve">
|
||||
<value>...</value>
|
||||
<comment>Do not localize</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Templates_Location_Learn_More.Content" xml:space="preserve">
|
||||
<value>Learn more about template location</value>
|
||||
<comment>Read more about templates location</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Templates_Location_Change.Content" xml:space="preserve">
|
||||
<value>Change</value>
|
||||
<comment>Button where user can Change the location of New templates</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Display_Options.Header" xml:space="preserve">
|
||||
<value>Display options</value>
|
||||
<comment>Display options label</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Hide_File_Extension_Toggle.Header" xml:space="preserve">
|
||||
<value>Hide template filename extension</value>
|
||||
<comment>Template file name extension settings toggle</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Hide_Starting_Digits_Toggle.Header" xml:space="preserve">
|
||||
<value>Hide template filename starting digits, spaces, and dots</value>
|
||||
<comment>Template filename starting digits settings toggle</comment>
|
||||
</data>
|
||||
<data name="NewPlus_Hide_Starting_Digits_Description.Text" xml:space="preserve">
|
||||
<value>This option is useful when using digits, spaces and dots at the beginning of filenames to control the display order of templates</value>
|
||||
<comment>Template filename starting digits settings toggle</comment>
|
||||
</data>
|
||||
<data name="NewPlus.SecondaryLinksHeader" xml:space="preserve">
|
||||
<value>Attribution</value>
|
||||
<comment>giving credit</comment>
|
||||
</data>
|
||||
<data name="Oobe_NewPlus.Title" xml:space="preserve">
|
||||
<value>New+</value>
|
||||
<comment>New+ is the name of the utility. Localize product name in accordance with Windows New</comment>
|
||||
</data>
|
||||
<data name="Oobe_NewPlus.Description" xml:space="preserve">
|
||||
<value>Create files and folders from a personalized set of templates.</value>
|
||||
</data>
|
||||
<data name="Oobe_NewPlus_HowToUse.Text" xml:space="preserve">
|
||||
<value>In File Explorer, right-click the desktop or a folder and via the New+ from the context menu select your template. You can add new templates by opening the template folder via "Open templates" and add new files and folders there.</value>
|
||||
</data>
|
||||
<data name="Oobe_NewPlus_TipsAndTricks.Text" xml:space="preserve">
|
||||
<value>You can have multiple templates of the same file type, and you can even template folders!</value>
|
||||
</data>
|
||||
<data name="Workspaces.ModuleDescription" xml:space="preserve">
|
||||
<value>Workspaces is a quick and easy way to launch a set of applications to custom positions and configurations with one-click.</value>
|
||||
</data>
|
||||
|
@ -125,6 +125,13 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
private void EnabledChangedOnUI(DashboardListItem dashboardListItem)
|
||||
{
|
||||
Views.ShellPage.UpdateGeneralSettingsCallback(dashboardListItem.Tag, dashboardListItem.IsEnabled);
|
||||
|
||||
if (dashboardListItem.Tag == ModuleType.NewPlus && dashboardListItem.IsEnabled == true)
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settings = NewPlusViewModel.LoadSettings(settingsUtils);
|
||||
NewPlusViewModel.CopyTemplateExamples(settings.TemplateLocation);
|
||||
}
|
||||
}
|
||||
|
||||
public void ModuleEnabledChangedOnSettingsPage()
|
||||
@ -178,6 +185,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
ModuleType.MeasureTool => GetModuleItemsMeasureTool(),
|
||||
ModuleType.ShortcutGuide => GetModuleItemsShortcutGuide(),
|
||||
ModuleType.PowerOCR => GetModuleItemsPowerOCR(),
|
||||
ModuleType.NewPlus => GetModuleItemsNewPlus(),
|
||||
_ => new ObservableCollection<DashboardModuleItem>(), // never called, all values listed above
|
||||
};
|
||||
}
|
||||
@ -495,6 +503,15 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
return new ObservableCollection<DashboardModuleItem>(list);
|
||||
}
|
||||
|
||||
private ObservableCollection<DashboardModuleItem> GetModuleItemsNewPlus()
|
||||
{
|
||||
var list = new List<DashboardModuleItem>
|
||||
{
|
||||
new DashboardModuleTextItem() { Label = resourceLoader.GetString("NewPlus_Product_Description/Description") },
|
||||
};
|
||||
return new ObservableCollection<DashboardModuleItem>(list);
|
||||
}
|
||||
|
||||
internal void SWVersionButtonClicked()
|
||||
{
|
||||
NavigationService.Navigate(typeof(GeneralPage));
|
||||
|
256
src/settings-ui/Settings.UI/ViewModels/NewPlusViewModel.cs
Normal file
@ -0,0 +1,256 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Common.UI;
|
||||
using global::PowerToys.GPOWrapper;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
|
||||
using Windows.ApplicationModel.VoiceCommands;
|
||||
using Windows.System;
|
||||
using static Microsoft.PowerToys.Settings.UI.Helpers.ShellGetFolder;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
{
|
||||
public class NewPlusViewModel : Observable
|
||||
{
|
||||
private GeneralSettings GeneralSettingsConfig { get; set; }
|
||||
|
||||
private readonly ISettingsUtils _settingsUtils;
|
||||
|
||||
private NewPlusSettings Settings { get; set; }
|
||||
|
||||
private const string ModuleName = NewPlusSettings.ModuleName;
|
||||
|
||||
public NewPlusViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
||||
{
|
||||
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
|
||||
|
||||
// To obtain the general settings configurations of PowerToys Settings.
|
||||
ArgumentNullException.ThrowIfNull(settingsRepository);
|
||||
|
||||
GeneralSettingsConfig = settingsRepository.SettingsConfig;
|
||||
|
||||
Settings = LoadSettings(settingsUtils);
|
||||
|
||||
// Initialize properties
|
||||
_hideFileExtension = Settings.HideFileExtension;
|
||||
_hideStartingDigits = Settings.HideStartingDigits;
|
||||
_templateLocation = Settings.TemplateLocation;
|
||||
InitializeEnabledValue();
|
||||
|
||||
// set the callback functions value to handle outgoing IPC message.
|
||||
SendConfigMSG = ipcMSGCallBackFunc;
|
||||
}
|
||||
|
||||
private void InitializeEnabledValue()
|
||||
{
|
||||
_enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredNewPlusEnabledValue();
|
||||
if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
||||
{
|
||||
// Get the enabled state from GPO.
|
||||
_enabledStateIsGPOConfigured = true;
|
||||
_isNewPlusEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
_isNewPlusEnabled = GeneralSettingsConfig.Enabled.NewPlus;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isNewPlusEnabled;
|
||||
set
|
||||
{
|
||||
if (_isNewPlusEnabled != value)
|
||||
{
|
||||
_isNewPlusEnabled = value;
|
||||
|
||||
GeneralSettingsConfig.Enabled.NewPlus = value;
|
||||
OnPropertyChanged(nameof(IsEnabled));
|
||||
|
||||
OutGoingGeneralSettings outgoingMessage = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||
SendConfigMSG(outgoingMessage.ToString());
|
||||
|
||||
NotifySettingsChanged();
|
||||
|
||||
if (_isNewPlusEnabled == true)
|
||||
{
|
||||
CopyTemplateExamples(_templateLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsWin10OrLower
|
||||
{
|
||||
get => !OSVersionHelper.IsWindows11();
|
||||
}
|
||||
|
||||
public string TemplateLocation
|
||||
{
|
||||
get => _templateLocation;
|
||||
set
|
||||
{
|
||||
if (_templateLocation != value)
|
||||
{
|
||||
_templateLocation = value;
|
||||
Settings.TemplateLocation = value;
|
||||
OnPropertyChanged(nameof(TemplateLocation));
|
||||
|
||||
NotifySettingsChanged();
|
||||
|
||||
SaveSettingsToJson();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool HideFileExtension
|
||||
{
|
||||
get => _hideFileExtension;
|
||||
set
|
||||
{
|
||||
if (_hideFileExtension != value)
|
||||
{
|
||||
_hideFileExtension = value;
|
||||
Settings.HideFileExtension = value;
|
||||
OnPropertyChanged(nameof(HideFileExtension));
|
||||
|
||||
NotifySettingsChanged();
|
||||
|
||||
SaveSettingsToJson();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool HideStartingDigits
|
||||
{
|
||||
get => _hideStartingDigits;
|
||||
set
|
||||
{
|
||||
if (_hideStartingDigits != value)
|
||||
{
|
||||
_hideStartingDigits = value;
|
||||
Settings.HideStartingDigits = value;
|
||||
OnPropertyChanged(nameof(HideStartingDigits));
|
||||
|
||||
NotifySettingsChanged();
|
||||
|
||||
SaveSettingsToJson();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabledGpoConfigured
|
||||
{
|
||||
get => _enabledStateIsGPOConfigured;
|
||||
}
|
||||
|
||||
public ButtonClickCommand OpenCurrentNewTemplateFolder => new ButtonClickCommand(OpenNewTemplateFolder);
|
||||
|
||||
public ButtonClickCommand PickAnotherNewTemplateFolder => new ButtonClickCommand(PickNewTemplateFolder);
|
||||
|
||||
private void NotifySettingsChanged()
|
||||
{
|
||||
// Using InvariantCulture as this is an IPC message
|
||||
SendConfigMSG(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"{{ \"powertoys\": {{ \"{0}\": {1} }} }}",
|
||||
ModuleName,
|
||||
JsonSerializer.Serialize(Settings)));
|
||||
}
|
||||
|
||||
private Func<string, int> SendConfigMSG { get; }
|
||||
|
||||
public static NewPlusSettings LoadSettings(ISettingsUtils settingsUtils)
|
||||
{
|
||||
NewPlusSettings settings = null;
|
||||
|
||||
try
|
||||
{
|
||||
settings = settingsUtils.GetSettings<NewPlusSettings>(NewPlusSettings.ModuleName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Exception encountered while reading {NewPlusSettings.ModuleName} settings.", e);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
public static void CopyTemplateExamples(string templateLocation)
|
||||
{
|
||||
if (!Directory.Exists(templateLocation))
|
||||
{
|
||||
Directory.CreateDirectory(templateLocation);
|
||||
}
|
||||
|
||||
if (Directory.GetFiles(templateLocation).Length == 0 && Directory.GetDirectories(templateLocation).Length == 0)
|
||||
{
|
||||
// No files in templateLocation directory
|
||||
// Copy over examples files from <Program Files>\PowerToys\WinUI3Apps\Assets\NewPlus\Templates
|
||||
var example_templates = Path.Combine(Helper.GetPowerToysInstallationWinUI3AppsAssetsFolder(), "NewPlus", "Templates");
|
||||
Helper.CopyDirectory(example_templates, templateLocation, true);
|
||||
}
|
||||
}
|
||||
|
||||
private GpoRuleConfigured _enabledGpoRuleConfiguration;
|
||||
private bool _enabledStateIsGPOConfigured;
|
||||
private bool _isNewPlusEnabled;
|
||||
private string _templateLocation;
|
||||
private bool _hideFileExtension;
|
||||
private bool _hideStartingDigits;
|
||||
|
||||
public void RefreshEnabledState()
|
||||
{
|
||||
InitializeEnabledValue();
|
||||
OnPropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
|
||||
private void OpenNewTemplateFolder()
|
||||
{
|
||||
var process = new ProcessStartInfo()
|
||||
{
|
||||
FileName = _templateLocation,
|
||||
UseShellExecute = true,
|
||||
};
|
||||
Process.Start(process);
|
||||
}
|
||||
|
||||
private async void PickNewTemplateFolder()
|
||||
{
|
||||
var newPath = await PickFolderDialog();
|
||||
if (newPath.Length > 1)
|
||||
{
|
||||
TemplateLocation = newPath;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> PickFolderDialog()
|
||||
{
|
||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.GetSettingsWindow());
|
||||
string pathFolder = await Task.FromResult<string>(ShellGetFolder.GetFolderDialogWithFlags(hwnd, ShellGetFolder.FolderDialogFlags._BIF_NEWDIALOGSTYLE));
|
||||
return pathFolder;
|
||||
}
|
||||
|
||||
private void SaveSettingsToJson()
|
||||
{
|
||||
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
||||
}
|
||||
}
|
||||
}
|
@ -54,7 +54,8 @@ vector<wstring> filesToDelete = {
|
||||
L"PowerRename\\replace-mru.json",
|
||||
L"PowerRename\\search-mru.json",
|
||||
L"PowerToys Run\\Settings\\UserSelectedRecord.json",
|
||||
L"PowerToys Run\\Settings\\QueryHistory.json"
|
||||
L"PowerToys Run\\Settings\\QueryHistory.json",
|
||||
L"NewPlus\\Templates",
|
||||
};
|
||||
|
||||
vector<wstring> GetXpathArray(wstring xpath)
|
||||
|