mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-24 04:00:02 +01:00
Merge branch 'main' into shawn/winappsdkPwshUpdate
This commit is contained in:
3
.github/actions/spell-check/expect.txt
vendored
3
.github/actions/spell-check/expect.txt
vendored
@@ -1483,6 +1483,7 @@ rgh
|
||||
rgn
|
||||
rgs
|
||||
rguid
|
||||
rhk
|
||||
RIDEV
|
||||
RIGHTSCROLLBAR
|
||||
riid
|
||||
@@ -1588,6 +1589,7 @@ SHGDNF
|
||||
SHGFI
|
||||
SHIL
|
||||
shinfo
|
||||
shk
|
||||
shlwapi
|
||||
shobjidl
|
||||
SHORTCUTATLEAST
|
||||
@@ -1798,6 +1800,7 @@ tlbimp
|
||||
tlc
|
||||
tmain
|
||||
TNP
|
||||
toolgood
|
||||
Toolhelp
|
||||
toolwindow
|
||||
TOPDOWNDIB
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
"PowerToys.FancyZonesEditorCommon.dll",
|
||||
"PowerToys.FancyZonesModuleInterface.dll",
|
||||
"PowerToys.FancyZones.exe",
|
||||
"FancyZonesCLI.exe",
|
||||
"FancyZonesCLI.dll",
|
||||
|
||||
"PowerToys.GcodePreviewHandler.dll",
|
||||
"PowerToys.GcodePreviewHandler.exe",
|
||||
@@ -351,6 +353,11 @@
|
||||
"Microsoft.SemanticKernel.Connectors.Ollama.dll",
|
||||
"OllamaSharp.dll",
|
||||
|
||||
"boost_regex-vc143-mt-gd-x32-1_87.dll",
|
||||
"boost_regex-vc143-mt-gd-x64-1_87.dll",
|
||||
"boost_regex-vc143-mt-x32-1_87.dll",
|
||||
"boost_regex-vc143-mt-x64-1_87.dll",
|
||||
|
||||
"UnitsNet.dll",
|
||||
"UtfUnknown.dll",
|
||||
"Wpf.Ui.dll"
|
||||
|
||||
@@ -52,7 +52,12 @@ $nullVersionExceptions = @(
|
||||
"System.Diagnostics.EventLog.Messages.dll",
|
||||
"Microsoft.Windows.Widgets.dll",
|
||||
"AdaptiveCards.ObjectModel.WinUI3.dll",
|
||||
"AdaptiveCards.Rendering.WinUI3.dll") -join '|';
|
||||
"AdaptiveCards.Rendering.WinUI3.dll",
|
||||
"boost_regex_vc143_mt_gd_x32_1_87.dll",
|
||||
"boost_regex_vc143_mt_gd_x64_1_87.dll",
|
||||
"boost_regex_vc143_mt_x32_1_87.dll",
|
||||
"boost_regex_vc143_mt_x64_1_87.dll"
|
||||
) -join '|';
|
||||
$totalFailure = 0;
|
||||
|
||||
Write-Host $DirPath;
|
||||
|
||||
@@ -73,10 +73,10 @@
|
||||
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
||||
<PackageVersion Include="Microsoft.Windows.ImplementationLibrary" Version="1.0.231216.1"/>
|
||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6901" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.250907003" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK.Foundation" Version="1.8.250906002" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK.AI" Version="1.8.37" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK.Runtime" Version="1.8.250907003" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK.Foundation" Version="1.8.251104000" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK.AI" Version="1.8.39" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK.Runtime" Version="1.8.251106002" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
|
||||
<PackageVersion Include="ModernWpfUI" Version="0.9.4" />
|
||||
@@ -115,6 +115,7 @@
|
||||
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="22.0.13" />
|
||||
<PackageVersion Include="System.Management" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageVersion Include="System.Numerics.Tensors" Version="9.0.11" />
|
||||
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
|
||||
<PackageVersion Include="System.Reactive" Version="6.0.1" />
|
||||
<PackageVersion Include="System.Runtime.Caching" Version="9.0.10" />
|
||||
@@ -122,6 +123,7 @@
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.10" />
|
||||
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageVersion Include="ToolGood.Words.Pinyin" Version="3.1.0.3" />
|
||||
<PackageVersion Include="UnicodeInformation" Version="2.6.0" />
|
||||
<PackageVersion Include="UnitsNet" Version="5.56.0" />
|
||||
<PackageVersion Include="UTF.Unknown" Version="2.6.0" />
|
||||
|
||||
32
NOTICE.md
32
NOTICE.md
@@ -75,6 +75,37 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
```
|
||||
|
||||
### ToolGood.Words.Pinyin
|
||||
|
||||
We use the ToolGood.Words.Pinyin NuGet package for converting Chinese characters to pinyin.
|
||||
|
||||
**Source**: [https://github.com/toolgood/ToolGood.Words.Pinyin](https://github.com/toolgood/ToolGood.Words.Pinyin)
|
||||
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 ToolGood
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
|
||||
## Utility: Command Palette Built-in Extensions
|
||||
|
||||
### Calculator
|
||||
@@ -1532,6 +1563,7 @@ SOFTWARE.
|
||||
- SkiaSharp.Views.WinUI
|
||||
- StreamJsonRpc
|
||||
- StyleCop.Analyzers
|
||||
- ToolGood.Words.Pinyin
|
||||
- UnicodeInformation
|
||||
- UnitsNet
|
||||
- UTF.Unknown
|
||||
|
||||
@@ -370,6 +370,10 @@
|
||||
<Platform Solution="*|x64" Project="x64" />
|
||||
</Project>
|
||||
<Project Path="src/modules/fancyzones/FancyZones/FancyZones.vcxproj" Id="ff1d7936-842a-4bbb-8bea-e9fe796de700" />
|
||||
<Project Path="src/modules/fancyzones/FancyZonesCLI/FancyZonesCLI.csproj">
|
||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||
<Platform Solution="*|x64" Project="x64" />
|
||||
</Project>
|
||||
<Project Path="src/modules/fancyzones/FancyZonesEditorCommon/FancyZonesEditorCommon.csproj">
|
||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||
<Platform Solution="*|x64" Project="x64" />
|
||||
|
||||
@@ -38,7 +38,7 @@ For C# modules, the settings are accessed through the `SettingsUtils` class in t
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
// Read settings
|
||||
var settings = SettingsUtils.GetSettings<ModuleSettings>("ModuleName");
|
||||
var settings = SettingsUtils.Default.GetSettings<ModuleSettings>("ModuleName");
|
||||
bool enabled = settings.Enabled;
|
||||
```
|
||||
|
||||
@@ -49,7 +49,7 @@ using Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
// Write settings
|
||||
settings.Enabled = true;
|
||||
SettingsUtils.SaveSettings(settings.ToJsonString(), "ModuleName");
|
||||
SettingsUtils.Default.SaveSettings(settings.ToJsonString(), "ModuleName");
|
||||
```
|
||||
|
||||
## Settings Handling in Modules
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Microsoft.PowerToys.UITest
|
||||
public class SettingsConfigHelper
|
||||
{
|
||||
private static readonly JsonSerializerOptions IndentedJsonOptions = new() { WriteIndented = true };
|
||||
private static readonly SettingsUtils SettingsUtils = new SettingsUtils();
|
||||
private static readonly SettingsUtils SettingsUtils = SettingsUtils.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Configures global PowerToys settings to enable only specified modules and disable all others.
|
||||
|
||||
@@ -16,9 +16,54 @@
|
||||
|
||||
namespace registry
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct on_exit
|
||||
{
|
||||
std::function<void()> f;
|
||||
|
||||
on_exit(std::function<void()> f) :
|
||||
f{ std::move(f) } {}
|
||||
~on_exit() { f(); }
|
||||
};
|
||||
|
||||
template<class... Ts>
|
||||
struct overloaded : Ts...
|
||||
{
|
||||
using Ts::operator()...;
|
||||
};
|
||||
|
||||
template<class... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
inline const wchar_t* getScopeName(HKEY scope)
|
||||
{
|
||||
if (scope == HKEY_LOCAL_MACHINE)
|
||||
{
|
||||
return L"HKLM";
|
||||
}
|
||||
else if (scope == HKEY_CURRENT_USER)
|
||||
{
|
||||
return L"HKCU";
|
||||
}
|
||||
else if (scope == HKEY_CLASSES_ROOT)
|
||||
{
|
||||
return L"HKCR";
|
||||
}
|
||||
else
|
||||
{
|
||||
return L"HK??";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace install_scope
|
||||
{
|
||||
const wchar_t INSTALL_SCOPE_REG_KEY[] = L"Software\\Classes\\powertoys\\";
|
||||
const wchar_t UNINSTALL_REG_KEY[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
|
||||
|
||||
// Bundle UpgradeCode from PowerToys.wxs (with braces as stored in registry)
|
||||
const wchar_t BUNDLE_UPGRADE_CODE[] = L"{6341382D-C0A9-4238-9188-BE9607E3FAB2}";
|
||||
|
||||
enum class InstallScope
|
||||
{
|
||||
@@ -26,8 +71,67 @@ namespace registry
|
||||
PerUser,
|
||||
};
|
||||
|
||||
// Helper function to find PowerToys bundle in Windows Uninstall registry by BundleUpgradeCode
|
||||
inline bool find_powertoys_bundle_in_uninstall_registry(HKEY rootKey)
|
||||
{
|
||||
HKEY uninstallKey{};
|
||||
if (RegOpenKeyExW(rootKey, UNINSTALL_REG_KEY, 0, KEY_READ, &uninstallKey) != ERROR_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
detail::on_exit closeUninstallKey{ [uninstallKey] { RegCloseKey(uninstallKey); } };
|
||||
|
||||
DWORD index = 0;
|
||||
wchar_t subKeyName[256];
|
||||
|
||||
// Enumerate all subkeys under Uninstall
|
||||
while (RegEnumKeyW(uninstallKey, index++, subKeyName, 256) == ERROR_SUCCESS)
|
||||
{
|
||||
HKEY productKey{};
|
||||
if (RegOpenKeyExW(uninstallKey, subKeyName, 0, KEY_READ, &productKey) != ERROR_SUCCESS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
detail::on_exit closeProductKey{ [productKey] { RegCloseKey(productKey); } };
|
||||
|
||||
// Check BundleUpgradeCode value (specific to WiX Bundle installations)
|
||||
wchar_t bundleUpgradeCode[256]{};
|
||||
DWORD bundleUpgradeCodeSize = sizeof(bundleUpgradeCode);
|
||||
|
||||
if (RegQueryValueExW(productKey, L"BundleUpgradeCode", nullptr, nullptr,
|
||||
reinterpret_cast<LPBYTE>(bundleUpgradeCode), &bundleUpgradeCodeSize) == ERROR_SUCCESS)
|
||||
{
|
||||
if (_wcsicmp(bundleUpgradeCode, BUNDLE_UPGRADE_CODE) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline const InstallScope get_current_install_scope()
|
||||
{
|
||||
// 1. Check HKCU Uninstall registry first (user-level bundle)
|
||||
// Note: MSI components are always in HKLM regardless of install scope,
|
||||
// but the Bundle entry will be in HKCU for per-user installations
|
||||
if (find_powertoys_bundle_in_uninstall_registry(HKEY_CURRENT_USER))
|
||||
{
|
||||
Logger::info(L"Found user-level PowerToys bundle via BundleUpgradeCode in HKCU");
|
||||
return InstallScope::PerUser;
|
||||
}
|
||||
|
||||
// 2. Check HKLM Uninstall registry (machine-level bundle)
|
||||
if (find_powertoys_bundle_in_uninstall_registry(HKEY_LOCAL_MACHINE))
|
||||
{
|
||||
Logger::info(L"Found machine-level PowerToys bundle via BundleUpgradeCode in HKLM");
|
||||
return InstallScope::PerMachine;
|
||||
}
|
||||
|
||||
// 3. Fallback to legacy custom registry key detection
|
||||
Logger::info(L"PowerToys bundle not found in Uninstall registry, falling back to legacy detection");
|
||||
|
||||
// Open HKLM key
|
||||
HKEY perMachineKey{};
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
@@ -45,6 +149,7 @@ namespace registry
|
||||
&perUserKey) != ERROR_SUCCESS)
|
||||
{
|
||||
// both keys are missing
|
||||
Logger::warn(L"No PowerToys installation detected, defaulting to PerMachine");
|
||||
return InstallScope::PerMachine;
|
||||
}
|
||||
else
|
||||
@@ -96,47 +201,6 @@ namespace registry
|
||||
template<class>
|
||||
inline constexpr bool always_false_v = false;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct on_exit
|
||||
{
|
||||
std::function<void()> f;
|
||||
|
||||
on_exit(std::function<void()> f) :
|
||||
f{ std::move(f) } {}
|
||||
~on_exit() { f(); }
|
||||
};
|
||||
|
||||
template<class... Ts>
|
||||
struct overloaded : Ts...
|
||||
{
|
||||
using Ts::operator()...;
|
||||
};
|
||||
|
||||
template<class... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
inline const wchar_t* getScopeName(HKEY scope)
|
||||
{
|
||||
if (scope == HKEY_LOCAL_MACHINE)
|
||||
{
|
||||
return L"HKLM";
|
||||
}
|
||||
else if (scope == HKEY_CURRENT_USER)
|
||||
{
|
||||
return L"HKCU";
|
||||
}
|
||||
else if (scope == HKEY_CLASSES_ROOT)
|
||||
{
|
||||
return L"HKCR";
|
||||
}
|
||||
else
|
||||
{
|
||||
return L"HK??";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ValueChange
|
||||
{
|
||||
using value_t = std::variant<DWORD, std::wstring>;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace PowerToys.DSC.UnitTests.SettingsResourceTests;
|
||||
public abstract class SettingsResourceModuleTest<TSettingsConfig> : BaseDscTest
|
||||
where TSettingsConfig : ISettingsConfig, new()
|
||||
{
|
||||
private readonly SettingsUtils _settingsUtils = new();
|
||||
private readonly SettingsUtils _settingsUtils = SettingsUtils.Default;
|
||||
private TSettingsConfig _originalSettings;
|
||||
|
||||
protected TSettingsConfig DefaultSettings => new();
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace PowerToys.DSC.Models.FunctionData;
|
||||
public sealed class SettingsFunctionData<TSettingsConfig> : BaseFunctionData, ISettingsFunctionData
|
||||
where TSettingsConfig : ISettingsConfig, new()
|
||||
{
|
||||
private static readonly SettingsUtils _settingsUtils = new();
|
||||
private static readonly SettingsUtils _settingsUtils = SettingsUtils.Default;
|
||||
private static readonly TSettingsConfig _settingsConfig = new();
|
||||
|
||||
private readonly SettingsResourceObject<TSettingsConfig> _input;
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Hosts.Settings
|
||||
|
||||
public UserSettings()
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
var defaultSettings = new HostsProperties();
|
||||
ShowStartupWarning = defaultSettings.ShowStartupWarning;
|
||||
LoopbackDuplicates = defaultSettings.LoopbackDuplicates;
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace MeasureToolUI
|
||||
{
|
||||
public sealed class Settings
|
||||
{
|
||||
private static readonly SettingsUtils ModuleSettings = new();
|
||||
private static readonly SettingsUtils ModuleSettings = SettingsUtils.Default;
|
||||
|
||||
public MeasureToolMeasureStyle DefaultMeasureStyle
|
||||
{
|
||||
|
||||
@@ -53,7 +53,7 @@ internal sealed class SettingsHelper
|
||||
lock (this.LockObject)
|
||||
{
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
|
||||
// set this to 1 to disable retries
|
||||
var remainingRetries = 5;
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
internal Settings()
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
|
||||
_watcher = SettingsHelper.GetFileWatcher("MouseWithoutBorders", "settings.json", () =>
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace PowerOCR.Settings
|
||||
[ImportingConstructor]
|
||||
public UserSettings(Helpers.IThrottledActionInvoker throttledActionInvoker)
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
ActivationShortcut = new SettingItem<string>(DefaultActivationShortcut);
|
||||
PreferredLanguage = new SettingItem<string>(string.Empty);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace WorkspacesEditor.Utils
|
||||
public class Settings
|
||||
{
|
||||
private const string WorkspacesModuleName = "Workspaces";
|
||||
private static readonly SettingsUtils _settingsUtils = new();
|
||||
private static readonly SettingsUtils _settingsUtils = SettingsUtils.Default;
|
||||
|
||||
public static WorkspacesSettings ReadSettings()
|
||||
{
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace WorkspacesEditor.ViewModels
|
||||
_orderByIndex = value;
|
||||
OnPropertyChanged(new PropertyChangedEventArgs(nameof(WorkspacesView)));
|
||||
settings.Properties.SortBy = (WorkspacesProperties.SortByProperty)value;
|
||||
settings.Save(new SettingsUtils());
|
||||
settings.Save(SettingsUtils.Default);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Awake.Core
|
||||
{
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
_stateQueue = [];
|
||||
ModuleSettings = new SettingsUtils();
|
||||
ModuleSettings = SettingsUtils.Default;
|
||||
}
|
||||
|
||||
internal static void StartMonitor()
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Awake
|
||||
|
||||
private static async Task<int> Main(string[] args)
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
|
||||
LockMutex = new Mutex(true, Core.Constants.AppName, out bool instantiated);
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// 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.
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Used to navigate left in a grid view when pressing the Left arrow key in the SearchBox.
|
||||
/// </summary>
|
||||
public record NavigateLeftCommand;
|
||||
@@ -0,0 +1,10 @@
|
||||
// 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.
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Used to navigate right in a grid view when pressing the Right arrow key in the SearchBox.
|
||||
/// </summary>
|
||||
public record NavigateRightCommand;
|
||||
@@ -12,6 +12,7 @@ using Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.Ext.Apps;
|
||||
using Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
using Microsoft.CmdPal.Ext.Apps.State;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Commands;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Properties;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
@@ -44,6 +45,9 @@ public partial class MainListPage : DynamicListPage,
|
||||
private List<Scored<IListItem>>? _filteredItems;
|
||||
private List<Scored<IListItem>>? _filteredApps;
|
||||
private List<Scored<IListItem>>? _fallbackItems;
|
||||
|
||||
// Keep as IEnumerable for deferred execution. Fallback item titles are updated
|
||||
// asynchronously, so scoring must happen lazily when GetItems is called.
|
||||
private IEnumerable<Scored<IListItem>>? _scoredFallbackItems;
|
||||
private bool _includeApps;
|
||||
private bool _filteredItemsIncludesApps;
|
||||
@@ -155,42 +159,18 @@ public partial class MainListPage : DynamicListPage,
|
||||
|
||||
public override IListItem[] GetItems()
|
||||
{
|
||||
if (string.IsNullOrEmpty(SearchText))
|
||||
lock (_tlcManager.TopLevelCommands)
|
||||
{
|
||||
lock (_tlcManager.TopLevelCommands)
|
||||
{
|
||||
return _tlcManager
|
||||
.TopLevelCommands
|
||||
.Where(tlc => !tlc.IsFallback && !string.IsNullOrEmpty(tlc.Title))
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (_tlcManager.TopLevelCommands)
|
||||
{
|
||||
var limitedApps = new List<Scored<IListItem>>();
|
||||
|
||||
// Fuzzy matching can produce a lot of results, so we want to limit the
|
||||
// number of apps we show at once if it's a large set.
|
||||
if (_filteredApps?.Count > 0)
|
||||
{
|
||||
limitedApps = _filteredApps.OrderByDescending(s => s.Score).Take(_appResultLimit).ToList();
|
||||
}
|
||||
|
||||
var items = Enumerable.Empty<Scored<IListItem>>()
|
||||
.Concat(_filteredItems is not null ? _filteredItems : [])
|
||||
.Concat(_scoredFallbackItems is not null ? _scoredFallbackItems : [])
|
||||
.Concat(limitedApps)
|
||||
.OrderByDescending(o => o.Score)
|
||||
|
||||
// Add fallback items post-sort so they are always at the end of the list
|
||||
// and eventually ordered based on user preference
|
||||
.Concat(_fallbackItems is not null ? _fallbackItems.Where(w => !string.IsNullOrEmpty(w.Item.Title)) : [])
|
||||
.Select(s => s.Item)
|
||||
.ToArray();
|
||||
return items;
|
||||
}
|
||||
// Either return the top-level commands (no search text), or the merged and
|
||||
// filtered results.
|
||||
return string.IsNullOrEmpty(SearchText)
|
||||
? _tlcManager.TopLevelCommands.Where(tlc => !tlc.IsFallback && !string.IsNullOrEmpty(tlc.Title)).ToArray()
|
||||
: MainListPageResultFactory.Create(
|
||||
_filteredItems,
|
||||
_scoredFallbackItems?.ToList(),
|
||||
_filteredApps,
|
||||
_fallbackItems,
|
||||
_appResultLimit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
// 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.
|
||||
|
||||
#pragma warning disable IDE0007 // Use implicit type
|
||||
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.ViewModels.Commands;
|
||||
|
||||
internal static class MainListPageResultFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a merged and ordered array of results from multiple scored input lists,
|
||||
/// applying an application result limit and filtering fallback items as needed.
|
||||
/// </summary>
|
||||
public static IListItem[] Create(
|
||||
IList<Scored<IListItem>>? filteredItems,
|
||||
IList<Scored<IListItem>>? scoredFallbackItems,
|
||||
IList<Scored<IListItem>>? filteredApps,
|
||||
IList<Scored<IListItem>>? fallbackItems,
|
||||
int appResultLimit)
|
||||
{
|
||||
if (appResultLimit < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(appResultLimit), "App result limit must be non-negative.");
|
||||
}
|
||||
|
||||
int len1 = filteredItems?.Count ?? 0;
|
||||
int len2 = scoredFallbackItems?.Count ?? 0;
|
||||
|
||||
// Apps are pre-sorted, so we just need to take the top N, limited by appResultLimit.
|
||||
int len3 = Math.Min(filteredApps?.Count ?? 0, appResultLimit);
|
||||
|
||||
// Allocate the exact size of the result array.
|
||||
int totalCount = len1 + len2 + len3 + GetNonEmptyFallbackItemsCount(fallbackItems);
|
||||
var result = new IListItem[totalCount];
|
||||
|
||||
// Three-way stable merge of already-sorted lists.
|
||||
int idx1 = 0, idx2 = 0, idx3 = 0;
|
||||
int writePos = 0;
|
||||
|
||||
// Merge while all three lists have items. To maintain a stable sort, the
|
||||
// priority is: list1 > list2 > list3 when scores are equal.
|
||||
while (idx1 < len1 && idx2 < len2 && idx3 < len3)
|
||||
{
|
||||
// Using null-forgiving operator as we have already checked against lengths.
|
||||
int score1 = filteredItems![idx1].Score;
|
||||
int score2 = scoredFallbackItems![idx2].Score;
|
||||
int score3 = filteredApps![idx3].Score;
|
||||
|
||||
if (score1 >= score2 && score1 >= score3)
|
||||
{
|
||||
result[writePos++] = filteredItems[idx1++].Item;
|
||||
}
|
||||
else if (score2 >= score3)
|
||||
{
|
||||
result[writePos++] = scoredFallbackItems[idx2++].Item;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[writePos++] = filteredApps[idx3++].Item;
|
||||
}
|
||||
}
|
||||
|
||||
// Two-way merges for remaining pairs.
|
||||
while (idx1 < len1 && idx2 < len2)
|
||||
{
|
||||
if (filteredItems![idx1].Score >= scoredFallbackItems![idx2].Score)
|
||||
{
|
||||
result[writePos++] = filteredItems[idx1++].Item;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[writePos++] = scoredFallbackItems[idx2++].Item;
|
||||
}
|
||||
}
|
||||
|
||||
while (idx1 < len1 && idx3 < len3)
|
||||
{
|
||||
if (filteredItems![idx1].Score >= filteredApps![idx3].Score)
|
||||
{
|
||||
result[writePos++] = filteredItems[idx1++].Item;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[writePos++] = filteredApps[idx3++].Item;
|
||||
}
|
||||
}
|
||||
|
||||
while (idx2 < len2 && idx3 < len3)
|
||||
{
|
||||
if (scoredFallbackItems![idx2].Score >= filteredApps![idx3].Score)
|
||||
{
|
||||
result[writePos++] = scoredFallbackItems[idx2++].Item;
|
||||
}
|
||||
else
|
||||
{
|
||||
result[writePos++] = filteredApps[idx3++].Item;
|
||||
}
|
||||
}
|
||||
|
||||
// Drain remaining items from a non-empty list.
|
||||
while (idx1 < len1)
|
||||
{
|
||||
result[writePos++] = filteredItems![idx1++].Item;
|
||||
}
|
||||
|
||||
while (idx2 < len2)
|
||||
{
|
||||
result[writePos++] = scoredFallbackItems![idx2++].Item;
|
||||
}
|
||||
|
||||
while (idx3 < len3)
|
||||
{
|
||||
result[writePos++] = filteredApps![idx3++].Item;
|
||||
}
|
||||
|
||||
// Append filtered fallback items. Fallback items are added post-sort so they are
|
||||
// always at the end of the list and eventually ordered based on user preference.
|
||||
if (fallbackItems is not null)
|
||||
{
|
||||
for (int i = 0; i < fallbackItems.Count; i++)
|
||||
{
|
||||
var item = fallbackItems[i].Item;
|
||||
if (!string.IsNullOrEmpty(item.Title))
|
||||
{
|
||||
result[writePos++] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int GetNonEmptyFallbackItemsCount(IList<Scored<IListItem>>? fallbackItems)
|
||||
{
|
||||
int fallbackItemsCount = 0;
|
||||
|
||||
if (fallbackItems is not null)
|
||||
{
|
||||
for (int i = 0; i < fallbackItems.Count; i++)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(fallbackItems[i].Item.Title))
|
||||
{
|
||||
fallbackItemsCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fallbackItemsCount;
|
||||
}
|
||||
}
|
||||
#pragma warning restore IDE0007 // Use implicit type
|
||||
@@ -208,21 +208,32 @@ public sealed partial class SearchBar : UserControl,
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == VirtualKey.Left)
|
||||
{
|
||||
// Check if we're in a grid view, and if so, send grid navigation command
|
||||
var isGridView = CurrentPageViewModel is ListViewModel { IsGridView: true };
|
||||
|
||||
// Special handling is required if we're in grid view.
|
||||
if (isGridView)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<NavigateLeftCommand>();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
else if (e.Key == VirtualKey.Right)
|
||||
{
|
||||
// Check if the "replace search text with suggestion" feature from 0.4-0.5 is enabled.
|
||||
// If it isn't, then only use the suggestion when the caret is at the end of the input.
|
||||
if (!IsTextToSuggestEnabled)
|
||||
{
|
||||
if (_textToSuggest != null &&
|
||||
if (!string.IsNullOrEmpty(_textToSuggest) &&
|
||||
FilterBox.SelectionStart == FilterBox.Text.Length)
|
||||
{
|
||||
FilterBox.Text = _textToSuggest;
|
||||
FilterBox.Select(_textToSuggest.Length, 0);
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Here, we're using the "replace search text with suggestion" feature.
|
||||
@@ -232,6 +243,20 @@ public sealed partial class SearchBar : UserControl,
|
||||
_lastText = null;
|
||||
DoFilterBoxUpdate();
|
||||
}
|
||||
|
||||
// Wouldn't want to perform text completion *and* move the selected item, so only perform this if text suggestion wasn't performed.
|
||||
if (!e.Handled)
|
||||
{
|
||||
// Check if we're in a grid view, and if so, send grid navigation command
|
||||
var isGridView = CurrentPageViewModel is ListViewModel { IsGridView: true };
|
||||
|
||||
// Special handling is required if we're in grid view.
|
||||
if (isGridView)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<NavigateRightCommand>();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.Key == VirtualKey.Down)
|
||||
{
|
||||
@@ -274,6 +299,8 @@ public sealed partial class SearchBar : UserControl,
|
||||
|
||||
e.Key == VirtualKey.Up ||
|
||||
e.Key == VirtualKey.Down ||
|
||||
e.Key == VirtualKey.Left ||
|
||||
e.Key == VirtualKey.Right ||
|
||||
|
||||
e.Key == VirtualKey.RightMenu ||
|
||||
e.Key == VirtualKey.LeftMenu ||
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace Microsoft.CmdPal.UI;
|
||||
public sealed partial class ListPage : Page,
|
||||
IRecipient<NavigateNextCommand>,
|
||||
IRecipient<NavigatePreviousCommand>,
|
||||
IRecipient<NavigateLeftCommand>,
|
||||
IRecipient<NavigateRightCommand>,
|
||||
IRecipient<NavigatePageDownCommand>,
|
||||
IRecipient<NavigatePageUpCommand>,
|
||||
IRecipient<ActivateSelectedListItemMessage>,
|
||||
@@ -85,6 +87,8 @@ public sealed partial class ListPage : Page,
|
||||
// RegisterAll isn't AOT compatible
|
||||
WeakReferenceMessenger.Default.Register<NavigateNextCommand>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigatePreviousCommand>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigateLeftCommand>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigateRightCommand>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigatePageDownCommand>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigatePageUpCommand>(this);
|
||||
WeakReferenceMessenger.Default.Register<ActivateSelectedListItemMessage>(this);
|
||||
@@ -99,6 +103,8 @@ public sealed partial class ListPage : Page,
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<NavigateNextCommand>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<NavigatePreviousCommand>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<NavigateLeftCommand>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<NavigateRightCommand>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<NavigatePageDownCommand>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<NavigatePageUpCommand>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<ActivateSelectedListItemMessage>(this);
|
||||
@@ -257,25 +263,71 @@ public sealed partial class ListPage : Page,
|
||||
// And then have these commands manipulate that state being bound to the UI instead
|
||||
// We may want to see how other non-list UIs need to behave to make this decision
|
||||
// At least it's decoupled from the SearchBox now :)
|
||||
if (ItemView.SelectedIndex < ItemView.Items.Count - 1)
|
||||
if (ViewModel?.IsGridView == true)
|
||||
{
|
||||
ItemView.SelectedIndex++;
|
||||
// For grid views, use spatial navigation (down)
|
||||
HandleGridArrowNavigation(VirtualKey.Down);
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemView.SelectedIndex = 0;
|
||||
// For list views, use simple linear navigation
|
||||
if (ItemView.SelectedIndex < ItemView.Items.Count - 1)
|
||||
{
|
||||
ItemView.SelectedIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemView.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(NavigatePreviousCommand message)
|
||||
{
|
||||
if (ItemView.SelectedIndex > 0)
|
||||
if (ViewModel?.IsGridView == true)
|
||||
{
|
||||
ItemView.SelectedIndex--;
|
||||
// For grid views, use spatial navigation (up)
|
||||
HandleGridArrowNavigation(VirtualKey.Up);
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemView.SelectedIndex = ItemView.Items.Count - 1;
|
||||
// For list views, use simple linear navigation
|
||||
if (ItemView.SelectedIndex > 0)
|
||||
{
|
||||
ItemView.SelectedIndex--;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemView.SelectedIndex = ItemView.Items.Count - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(NavigateLeftCommand message)
|
||||
{
|
||||
// For grid views, use spatial navigation. For list views, just move up.
|
||||
if (ViewModel?.IsGridView == true)
|
||||
{
|
||||
HandleGridArrowNavigation(VirtualKey.Left);
|
||||
}
|
||||
else
|
||||
{
|
||||
// In list view, left arrow doesn't navigate
|
||||
// This maintains consistency with the SearchBar behavior
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(NavigateRightCommand message)
|
||||
{
|
||||
// For grid views, use spatial navigation. For list views, just move down.
|
||||
if (ViewModel?.IsGridView == true)
|
||||
{
|
||||
HandleGridArrowNavigation(VirtualKey.Right);
|
||||
}
|
||||
else
|
||||
{
|
||||
// In list view, right arrow doesn't navigate
|
||||
// This maintains consistency with the SearchBar behavior
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,6 +566,130 @@ public sealed partial class ListPage : Page,
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find a logical neighbor in the requested direction using containers' positions.
|
||||
private void HandleGridArrowNavigation(VirtualKey key)
|
||||
{
|
||||
if (ItemView.Items.Count == 0)
|
||||
{
|
||||
// No items, goodbye.
|
||||
return;
|
||||
}
|
||||
|
||||
var currentIndex = ItemView.SelectedIndex;
|
||||
if (currentIndex < 0)
|
||||
{
|
||||
// -1 is a valid value (no item currently selected)
|
||||
currentIndex = 0;
|
||||
ItemView.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Try to compute using container positions; if not available, fall back to simple +/-1.
|
||||
var currentContainer = ItemView.ContainerFromIndex(currentIndex) as FrameworkElement;
|
||||
if (currentContainer is not null && currentContainer.ActualWidth != 0 && currentContainer.ActualHeight != 0)
|
||||
{
|
||||
// Use center of current container as reference
|
||||
var curPoint = currentContainer.TransformToVisual(ItemView).TransformPoint(new Point(0, 0));
|
||||
var curCenterX = curPoint.X + (currentContainer.ActualWidth / 2.0);
|
||||
var curCenterY = curPoint.Y + (currentContainer.ActualHeight / 2.0);
|
||||
|
||||
var bestScore = double.MaxValue;
|
||||
var bestIndex = currentIndex;
|
||||
|
||||
for (var i = 0; i < ItemView.Items.Count; i++)
|
||||
{
|
||||
if (i == currentIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ItemView.ContainerFromIndex(i) is FrameworkElement c && c.ActualWidth > 0 && c.ActualHeight > 0)
|
||||
{
|
||||
var p = c.TransformToVisual(ItemView).TransformPoint(new Point(0, 0));
|
||||
var centerX = p.X + (c.ActualWidth / 2.0);
|
||||
var centerY = p.Y + (c.ActualHeight / 2.0);
|
||||
|
||||
var dx = centerX - curCenterX;
|
||||
var dy = centerY - curCenterY;
|
||||
|
||||
var candidate = false;
|
||||
var score = double.MaxValue;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case VirtualKey.Left:
|
||||
if (dx < 0)
|
||||
{
|
||||
candidate = true;
|
||||
score = Math.Abs(dy) + (Math.Abs(dx) * 0.7);
|
||||
}
|
||||
|
||||
break;
|
||||
case VirtualKey.Right:
|
||||
if (dx > 0)
|
||||
{
|
||||
candidate = true;
|
||||
score = Math.Abs(dy) + (Math.Abs(dx) * 0.7);
|
||||
}
|
||||
|
||||
break;
|
||||
case VirtualKey.Up:
|
||||
if (dy < 0)
|
||||
{
|
||||
candidate = true;
|
||||
score = Math.Abs(dx) + (Math.Abs(dy) * 0.7);
|
||||
}
|
||||
|
||||
break;
|
||||
case VirtualKey.Down:
|
||||
if (dy > 0)
|
||||
{
|
||||
candidate = true;
|
||||
score = Math.Abs(dx) + (Math.Abs(dy) * 0.7);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (candidate && score < bestScore)
|
||||
{
|
||||
bestScore = score;
|
||||
bestIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestIndex != currentIndex)
|
||||
{
|
||||
ItemView.SelectedIndex = bestIndex;
|
||||
ItemView.ScrollIntoView(ItemView.SelectedItem);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore transform errors and fall back
|
||||
}
|
||||
|
||||
// fallback linear behavior
|
||||
var fallback = key switch
|
||||
{
|
||||
VirtualKey.Left => Math.Max(0, currentIndex - 1),
|
||||
VirtualKey.Right => Math.Min(ItemView.Items.Count - 1, currentIndex + 1),
|
||||
VirtualKey.Up => Math.Max(0, currentIndex - 1),
|
||||
VirtualKey.Down => Math.Min(ItemView.Items.Count - 1, currentIndex + 1),
|
||||
_ => currentIndex,
|
||||
};
|
||||
if (fallback != currentIndex)
|
||||
{
|
||||
ItemView.SelectedIndex = fallback;
|
||||
ItemView.ScrollIntoView(ItemView.SelectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void Items_OnContextRequested(UIElement sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
var (item, element) = e.OriginalSource switch
|
||||
@@ -564,9 +740,27 @@ public sealed partial class ListPage : Page,
|
||||
|
||||
private void Items_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
|
||||
{
|
||||
// Track keyboard as the last input source for activation logic.
|
||||
if (e.Key is VirtualKey.Enter or VirtualKey.Space)
|
||||
{
|
||||
_lastInputSource = InputSource.Keyboard;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle arrow navigation when we're showing a grid.
|
||||
if (ViewModel?.IsGridView == true)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case VirtualKey.Left:
|
||||
case VirtualKey.Right:
|
||||
case VirtualKey.Up:
|
||||
case VirtualKey.Down:
|
||||
_lastInputSource = InputSource.Keyboard;
|
||||
HandleGridArrowNavigation(e.Key);
|
||||
e.Handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Commands;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.ViewModels.UnitTests;
|
||||
|
||||
[TestClass]
|
||||
public partial class MainListPageResultFactoryTests
|
||||
{
|
||||
private sealed partial class MockListItem : IListItem
|
||||
{
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
public string Subtitle { get; set; } = string.Empty;
|
||||
|
||||
public ICommand Command => new NoOpCommand();
|
||||
|
||||
public IDetails? Details => null;
|
||||
|
||||
public IIconInfo? Icon => null;
|
||||
|
||||
public string Section => throw new NotImplementedException();
|
||||
|
||||
public ITag[] Tags => throw new NotImplementedException();
|
||||
|
||||
public string TextToSuggest => throw new NotImplementedException();
|
||||
|
||||
public IContextItem[] MoreCommands => throw new NotImplementedException();
|
||||
|
||||
#pragma warning disable CS0067 // The event is never used
|
||||
public event TypedEventHandler<object, IPropChangedEventArgs>? PropChanged;
|
||||
#pragma warning restore CS0067 // The event is never used
|
||||
|
||||
public override string ToString() => Title;
|
||||
}
|
||||
|
||||
private static Scored<IListItem> S(string title, int score)
|
||||
{
|
||||
return new Scored<IListItem>
|
||||
{
|
||||
Score = score,
|
||||
Item = new MockListItem { Title = title },
|
||||
};
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Merge_PrioritizesListsCorrectly()
|
||||
{
|
||||
var filtered = new List<Scored<IListItem>>
|
||||
{
|
||||
S("F1", 100),
|
||||
S("F2", 50),
|
||||
};
|
||||
|
||||
var scoredFallback = new List<Scored<IListItem>>
|
||||
{
|
||||
S("SF1", 100),
|
||||
S("SF2", 60),
|
||||
};
|
||||
|
||||
var apps = new List<Scored<IListItem>>
|
||||
{
|
||||
S("A1", 100),
|
||||
S("A2", 55),
|
||||
};
|
||||
|
||||
// Fallbacks are not scored.
|
||||
var fallbacks = new List<Scored<IListItem>>
|
||||
{
|
||||
S("FB1", 0),
|
||||
S("FB2", 0),
|
||||
};
|
||||
|
||||
var result = MainListPageResultFactory.Create(
|
||||
filtered,
|
||||
scoredFallback,
|
||||
apps,
|
||||
fallbacks,
|
||||
appResultLimit: 10);
|
||||
|
||||
// Expected order:
|
||||
// 100: F1, SF1, A1
|
||||
// 60: SF2
|
||||
// 55: A2
|
||||
// 50: F2
|
||||
// Then fallbacks in original order: FB1, FB2
|
||||
var titles = result.Select(r => r.Title).ToArray();
|
||||
#pragma warning disable CA1861 // Avoid constant arrays as arguments
|
||||
CollectionAssert.AreEqual(
|
||||
new[] { "F1", "SF1", "A1", "SF2", "A2", "F2", "FB1", "FB2" },
|
||||
titles);
|
||||
#pragma warning restore CA1861 // Avoid constant arrays as arguments
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Merge_AppliesAppLimit()
|
||||
{
|
||||
var apps = new List<Scored<IListItem>>
|
||||
{
|
||||
S("A1", 100),
|
||||
S("A2", 90),
|
||||
S("A3", 80),
|
||||
};
|
||||
|
||||
var result = MainListPageResultFactory.Create(
|
||||
null,
|
||||
null,
|
||||
apps,
|
||||
null,
|
||||
2);
|
||||
|
||||
Assert.AreEqual(2, result.Length);
|
||||
Assert.AreEqual("A1", result[0].Title);
|
||||
Assert.AreEqual("A2", result[1].Title);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Merge_FiltersEmptyFallbacks()
|
||||
{
|
||||
var fallbacks = new List<Scored<IListItem>>
|
||||
{
|
||||
S("FB1", 0),
|
||||
S(string.Empty, 0),
|
||||
S("FB3", 0),
|
||||
};
|
||||
|
||||
var result = MainListPageResultFactory.Create(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
fallbacks,
|
||||
appResultLimit: 10);
|
||||
|
||||
Assert.AreEqual(2, result.Length);
|
||||
Assert.AreEqual("FB1", result[0].Title);
|
||||
Assert.AreEqual("FB3", result[1].Title);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Merge_HandlesNullLists()
|
||||
{
|
||||
var result = MainListPageResultFactory.Create(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
appResultLimit: 10);
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(0, result.Length);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
// 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.Globalization;
|
||||
|
||||
using ToolGood.Words.Pinyin;
|
||||
|
||||
namespace Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
// Inspired by the fuzzy.rs from edit.exe
|
||||
@@ -9,6 +13,21 @@ public static class FuzzyStringMatcher
|
||||
{
|
||||
private const int NOMATCH = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to support Chinese PinYin.
|
||||
/// Automatically enabled when the system UI culture is Simplified Chinese.
|
||||
/// </summary>
|
||||
public static bool ChinesePinYinSupport { get; } = IsSimplifiedChinese();
|
||||
|
||||
private static bool IsSimplifiedChinese()
|
||||
{
|
||||
var culture = CultureInfo.CurrentUICulture;
|
||||
|
||||
// Detect Simplified Chinese: zh-CN, zh-Hans, zh-Hans-*
|
||||
return culture.Name.StartsWith("zh-CN", StringComparison.OrdinalIgnoreCase)
|
||||
|| culture.Name.StartsWith("zh-Hans", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static int ScoreFuzzy(string needle, string haystack, bool allowNonContiguousMatches = true)
|
||||
{
|
||||
var (s, _) = ScoreFuzzyWithPositions(needle, haystack, allowNonContiguousMatches);
|
||||
@@ -16,6 +35,28 @@ public static class FuzzyStringMatcher
|
||||
}
|
||||
|
||||
public static (int Score, List<int> Positions) ScoreFuzzyWithPositions(string needle, string haystack, bool allowNonContiguousMatches)
|
||||
=> ScoreAllFuzzyWithPositions(needle, haystack, allowNonContiguousMatches).MaxBy(i => i.Score);
|
||||
|
||||
public static IEnumerable<(int Score, List<int> Positions)> ScoreAllFuzzyWithPositions(string needle, string haystack, bool allowNonContiguousMatches)
|
||||
{
|
||||
List<string> needles = [needle];
|
||||
List<string> haystacks = [haystack];
|
||||
|
||||
if (ChinesePinYinSupport)
|
||||
{
|
||||
// Remove IME composition split characters.
|
||||
var input = needle.Replace("'", string.Empty);
|
||||
needles.Add(WordsHelper.GetPinyin(input));
|
||||
if (WordsHelper.HasChinese(haystack))
|
||||
{
|
||||
haystacks.Add(WordsHelper.GetPinyin(haystack));
|
||||
}
|
||||
}
|
||||
|
||||
return needles.SelectMany(i => haystacks.Select(j => ScoreFuzzyWithPositionsInternal(i, j, allowNonContiguousMatches)));
|
||||
}
|
||||
|
||||
private static (int Score, List<int> Positions) ScoreFuzzyWithPositionsInternal(string needle, string haystack, bool allowNonContiguousMatches)
|
||||
{
|
||||
if (string.IsNullOrEmpty(haystack) || string.IsNullOrEmpty(needle))
|
||||
{
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Drawing.Common" />
|
||||
<PackageReference Include="ToolGood.Words.Pinyin" />
|
||||
<!-- This line forces the WebView2 version used by Windows App SDK to be the one we expect from Directory.Packages.props . -->
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<PathToRoot>..\..\..\..\..\</PathToRoot>
|
||||
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.8.250907003</WasdkNuget>
|
||||
<CppWinRTNuget>$(PathToRoot)packages\Microsoft.Windows.CppWinRT.2.0.240111.5</CppWinRTNuget>
|
||||
<WindowsSdkBuildToolsNuget>$(PathToRoot)packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.4188</WindowsSdkBuildToolsNuget>
|
||||
<WindowsSdkBuildToolsNuget>$(PathToRoot)packages\Microsoft.Windows.SDK.BuildTools.10.0.26100.6901</WindowsSdkBuildToolsNuget>
|
||||
<WebView2Nuget>$(PathToRoot)packages\Microsoft.Web.WebView2.1.0.2903.40</WebView2Nuget>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props')" />
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
<package id="Microsoft.WindowsAppSDK.InteractiveExperiences" version="1.8.250906004" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.Widgets" version="1.8.250904007" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK.AI" version="1.8.37" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.26100.4188" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.26100.6901" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.SDK.BuildTools.MSIX" version="1.7.20250829.1" targetFramework="native" />
|
||||
</packages>
|
||||
</packages>
|
||||
|
||||
@@ -54,9 +54,15 @@ if ($IsAzurePipelineBuild) {
|
||||
} else {
|
||||
$nugetPath = (Join-Path $PSScriptRoot "NugetWrapper.cmd")
|
||||
}
|
||||
$solutionPath = (Join-Path $PSScriptRoot "..\..\..\..\..\PowerToys.slnx")
|
||||
|
||||
if (($BuildStep -ieq "all") -Or ($BuildStep -ieq "build")) {
|
||||
& $nugetPath restore (Join-Path $PSScriptRoot "..\..\..\..\..\PowerToys.slnx")
|
||||
$restoreArgs = @(
|
||||
$solutionPath
|
||||
"/t:Restore"
|
||||
"/p:RestorePackagesConfig=true"
|
||||
)
|
||||
& $msbuildPath $restoreArgs
|
||||
|
||||
Try {
|
||||
foreach ($config in $Configuration.Split(",")) {
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace ColorPicker.Settings
|
||||
[ImportingConstructor]
|
||||
public UserSettings(Helpers.IThrottledActionInvoker throttledActionInvoker)
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
ChangeCursor = new SettingItem<bool>(true);
|
||||
ActivationShortcut = new SettingItem<string>(DefaultActivationShortcut);
|
||||
CopiedColorRepresentation = new SettingItem<string>(ColorRepresentationType.HEX.ToString());
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// 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.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace FancyZonesCLI.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Editor and Settings commands.
|
||||
/// </summary>
|
||||
internal static class EditorCommands
|
||||
{
|
||||
public static (int ExitCode, string Output) OpenEditor()
|
||||
{
|
||||
var editorExe = "PowerToys.FancyZonesEditor.exe";
|
||||
|
||||
// Check if editor-parameters.json exists
|
||||
if (!FancyZonesData.EditorParametersExist())
|
||||
{
|
||||
return (1, "Error: editor-parameters.json not found.\nPlease launch FancyZones Editor using Win+` (Win+Backtick) hotkey first.");
|
||||
}
|
||||
|
||||
// Check if editor is already running
|
||||
var existingProcess = Process.GetProcessesByName("PowerToys.FancyZonesEditor").FirstOrDefault();
|
||||
if (existingProcess != null)
|
||||
{
|
||||
NativeMethods.SetForegroundWindow(existingProcess.MainWindowHandle);
|
||||
return (0, "FancyZones Editor is already running. Brought window to foreground.");
|
||||
}
|
||||
|
||||
// Only check same directory as CLI
|
||||
var editorPath = Path.Combine(AppContext.BaseDirectory, editorExe);
|
||||
|
||||
if (File.Exists(editorPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = editorPath,
|
||||
UseShellExecute = true,
|
||||
});
|
||||
return (0, "FancyZones Editor launched successfully.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (1, $"Failed to launch: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return (1, $"Error: Could not find {editorExe} in {AppContext.BaseDirectory}");
|
||||
}
|
||||
|
||||
public static (int ExitCode, string Output) OpenSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Find PowerToys.exe in common locations
|
||||
string powertoysExe = null;
|
||||
|
||||
// Check in the same directory as the CLI (typical for dev builds)
|
||||
var sameDirPath = Path.Combine(AppContext.BaseDirectory, "PowerToys.exe");
|
||||
if (File.Exists(sameDirPath))
|
||||
{
|
||||
powertoysExe = sameDirPath;
|
||||
}
|
||||
|
||||
if (powertoysExe == null)
|
||||
{
|
||||
return (1, "Error: PowerToys.exe not found. Please ensure PowerToys is installed.");
|
||||
}
|
||||
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = powertoysExe,
|
||||
Arguments = "--open-settings=FancyZones",
|
||||
UseShellExecute = false,
|
||||
});
|
||||
return (0, "FancyZones Settings opened successfully.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (1, $"Error: Failed to open FancyZones Settings. {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace FancyZonesCLI.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Hotkey-related commands.
|
||||
/// </summary>
|
||||
internal static class HotkeyCommands
|
||||
{
|
||||
public static (int ExitCode, string Output) GetHotkeys()
|
||||
{
|
||||
var hotkeys = FancyZonesData.ReadLayoutHotkeys();
|
||||
if (hotkeys?.Hotkeys == null || hotkeys.Hotkeys.Count == 0)
|
||||
{
|
||||
return (0, "No hotkeys configured.");
|
||||
}
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine("=== Layout Hotkeys ===\n");
|
||||
sb.AppendLine("Press Win + Ctrl + Alt + <number> to switch layouts:\n");
|
||||
|
||||
foreach (var hotkey in hotkeys.Hotkeys.OrderBy(h => h.Key))
|
||||
{
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" [{hotkey.Key}] => {hotkey.LayoutId}");
|
||||
}
|
||||
|
||||
return (0, sb.ToString().TrimEnd());
|
||||
}
|
||||
|
||||
public static (int ExitCode, string Output) SetHotkey(int key, string layoutUuid, Action<uint> notifyFancyZones, uint wmPrivLayoutHotkeysFileUpdate)
|
||||
{
|
||||
if (key < 0 || key > 9)
|
||||
{
|
||||
return (1, "Error: Key must be between 0 and 9");
|
||||
}
|
||||
|
||||
// Check if this is a custom layout UUID
|
||||
var customLayouts = FancyZonesData.ReadCustomLayouts();
|
||||
var matchedLayout = customLayouts?.Layouts?.FirstOrDefault(l => l.Uuid.Equals(layoutUuid, StringComparison.OrdinalIgnoreCase));
|
||||
bool isCustomLayout = matchedLayout != null;
|
||||
string layoutName = matchedLayout?.Name ?? layoutUuid;
|
||||
|
||||
var hotkeys = FancyZonesData.ReadLayoutHotkeys() ?? new LayoutHotkeys();
|
||||
|
||||
hotkeys.Hotkeys ??= new List<LayoutHotkey>();
|
||||
|
||||
// Remove existing hotkey for this key
|
||||
hotkeys.Hotkeys.RemoveAll(h => h.Key == key);
|
||||
|
||||
// Add new hotkey
|
||||
hotkeys.Hotkeys.Add(new LayoutHotkey { Key = key, LayoutId = layoutUuid });
|
||||
|
||||
// Save
|
||||
FancyZonesData.WriteLayoutHotkeys(hotkeys);
|
||||
|
||||
// Notify FancyZones
|
||||
notifyFancyZones(wmPrivLayoutHotkeysFileUpdate);
|
||||
|
||||
if (isCustomLayout)
|
||||
{
|
||||
return (0, $"✓ Hotkey {key} assigned to custom layout '{layoutName}'\n Press Win + Ctrl + Alt + {key} to switch to this layout");
|
||||
}
|
||||
else
|
||||
{
|
||||
return (0, $"⚠ Warning: Hotkey {key} assigned to '{layoutUuid}'\n Note: FancyZones hotkeys only work with CUSTOM layouts.\n Template layouts (focus, columns, rows, etc.) cannot be used with hotkeys.\n Create a custom layout in the FancyZones Editor to use this hotkey.");
|
||||
}
|
||||
}
|
||||
|
||||
public static (int ExitCode, string Output) RemoveHotkey(int key, Action<uint> notifyFancyZones, uint wmPrivLayoutHotkeysFileUpdate)
|
||||
{
|
||||
var hotkeys = FancyZonesData.ReadLayoutHotkeys();
|
||||
if (hotkeys?.Hotkeys == null)
|
||||
{
|
||||
return (0, $"No hotkey assigned to key {key}");
|
||||
}
|
||||
|
||||
var removed = hotkeys.Hotkeys.RemoveAll(h => h.Key == key);
|
||||
if (removed == 0)
|
||||
{
|
||||
return (0, $"No hotkey assigned to key {key}");
|
||||
}
|
||||
|
||||
// Save
|
||||
FancyZonesData.WriteLayoutHotkeys(hotkeys);
|
||||
|
||||
// Notify FancyZones
|
||||
notifyFancyZones(wmPrivLayoutHotkeysFileUpdate);
|
||||
|
||||
return (0, $"Hotkey {key} removed");
|
||||
}
|
||||
}
|
||||
276
src/modules/fancyzones/FancyZonesCLI/Commands/LayoutCommands.cs
Normal file
276
src/modules/fancyzones/FancyZonesCLI/Commands/LayoutCommands.cs
Normal file
@@ -0,0 +1,276 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace FancyZonesCLI.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Layout-related commands.
|
||||
/// </summary>
|
||||
internal static class LayoutCommands
|
||||
{
|
||||
public static (int ExitCode, string Output) GetLayouts()
|
||||
{
|
||||
var sb = new System.Text.StringBuilder();
|
||||
|
||||
// Print template layouts
|
||||
var templatesJson = FancyZonesData.ReadLayoutTemplates();
|
||||
if (templatesJson?.Templates != null)
|
||||
{
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $"=== Built-in Template Layouts ({templatesJson.Templates.Count} total) ===\n");
|
||||
|
||||
for (int i = 0; i < templatesJson.Templates.Count; i++)
|
||||
{
|
||||
var template = templatesJson.Templates[i];
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $"[T{i + 1}] {template.Type}");
|
||||
sb.Append(CultureInfo.InvariantCulture, $" Zones: {template.ZoneCount}");
|
||||
if (template.ShowSpacing && template.Spacing > 0)
|
||||
{
|
||||
sb.Append(CultureInfo.InvariantCulture, $", Spacing: {template.Spacing}px");
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine();
|
||||
|
||||
// Draw visual preview
|
||||
sb.Append(LayoutVisualizer.DrawTemplateLayout(template));
|
||||
|
||||
if (i < templatesJson.Templates.Count - 1)
|
||||
{
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine("\n");
|
||||
}
|
||||
|
||||
// Print custom layouts
|
||||
var customLayouts = FancyZonesData.ReadCustomLayouts();
|
||||
if (customLayouts?.Layouts != null)
|
||||
{
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $"=== Custom Layouts ({customLayouts.Layouts.Count} total) ===");
|
||||
|
||||
for (int i = 0; i < customLayouts.Layouts.Count; i++)
|
||||
{
|
||||
var layout = customLayouts.Layouts[i];
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $"[{i + 1}] {layout.Name}");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" UUID: {layout.Uuid}");
|
||||
sb.Append(CultureInfo.InvariantCulture, $" Type: {layout.Type}");
|
||||
|
||||
bool isCanvasLayout = false;
|
||||
if (layout.Info.ValueKind != JsonValueKind.Undefined && layout.Info.ValueKind != JsonValueKind.Null)
|
||||
{
|
||||
if (layout.Type == "grid" && layout.Info.TryGetProperty("rows", out var rows) && layout.Info.TryGetProperty("columns", out var cols))
|
||||
{
|
||||
sb.Append(CultureInfo.InvariantCulture, $" ({rows.GetInt32()}x{cols.GetInt32()} grid)");
|
||||
}
|
||||
else if (layout.Type == "canvas" && layout.Info.TryGetProperty("zones", out var zones))
|
||||
{
|
||||
sb.Append(CultureInfo.InvariantCulture, $" ({zones.GetArrayLength()} zones)");
|
||||
isCanvasLayout = true;
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine("\n");
|
||||
|
||||
// Draw visual preview
|
||||
sb.Append(LayoutVisualizer.DrawCustomLayout(layout));
|
||||
|
||||
// Add note for canvas layouts
|
||||
if (isCanvasLayout)
|
||||
{
|
||||
sb.AppendLine("\n Note: Canvas layout preview is approximate.");
|
||||
sb.AppendLine(" Open FancyZones Editor for precise zone boundaries.");
|
||||
}
|
||||
|
||||
if (i < customLayouts.Layouts.Count - 1)
|
||||
{
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine("\nUse 'FancyZonesCLI.exe set-layout <UUID>' to apply a layout.");
|
||||
}
|
||||
|
||||
return (0, sb.ToString().TrimEnd());
|
||||
}
|
||||
|
||||
public static (int ExitCode, string Output) GetActiveLayout()
|
||||
{
|
||||
if (!FancyZonesData.TryReadAppliedLayouts(out var appliedLayouts, out var error))
|
||||
{
|
||||
return (1, $"Error: {error}");
|
||||
}
|
||||
|
||||
if (appliedLayouts.Layouts == null || appliedLayouts.Layouts.Count == 0)
|
||||
{
|
||||
return (0, "No active layouts found.");
|
||||
}
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine("\n=== Active FancyZones Layout(s) ===\n");
|
||||
|
||||
for (int i = 0; i < appliedLayouts.Layouts.Count; i++)
|
||||
{
|
||||
var layout = appliedLayouts.Layouts[i];
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $"Monitor {i + 1}:");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Name: {layout.AppliedLayout.Type}");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" UUID: {layout.AppliedLayout.Uuid}");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Type: {layout.AppliedLayout.Type} ({layout.AppliedLayout.ZoneCount} zones)");
|
||||
|
||||
if (layout.AppliedLayout.ShowSpacing)
|
||||
{
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Spacing: {layout.AppliedLayout.Spacing}px");
|
||||
}
|
||||
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Sensitivity Radius: {layout.AppliedLayout.SensitivityRadius}px");
|
||||
|
||||
if (i < appliedLayouts.Layouts.Count - 1)
|
||||
{
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
return (0, sb.ToString().TrimEnd());
|
||||
}
|
||||
|
||||
public static (int ExitCode, string Output) SetLayout(string[] args, Action<uint> notifyFancyZones, uint wmPrivAppliedLayoutsFileUpdate)
|
||||
{
|
||||
Logger.LogInfo($"SetLayout called with args: [{string.Join(", ", args)}]");
|
||||
|
||||
if (args.Length == 0)
|
||||
{
|
||||
return (1, "Error: set-layout requires a UUID parameter");
|
||||
}
|
||||
|
||||
string uuid = args[0];
|
||||
int? targetMonitor = null;
|
||||
bool applyToAll = false;
|
||||
|
||||
// Parse options
|
||||
for (int i = 1; i < args.Length; i++)
|
||||
{
|
||||
if (args[i] == "--monitor" && i + 1 < args.Length)
|
||||
{
|
||||
if (int.TryParse(args[i + 1], out int monitorNum))
|
||||
{
|
||||
targetMonitor = monitorNum;
|
||||
i++; // Skip next arg
|
||||
}
|
||||
else
|
||||
{
|
||||
return (1, $"Error: Invalid monitor number: {args[i + 1]}");
|
||||
}
|
||||
}
|
||||
else if (args[i] == "--all")
|
||||
{
|
||||
applyToAll = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (targetMonitor.HasValue && applyToAll)
|
||||
{
|
||||
return (1, "Error: Cannot specify both --monitor and --all");
|
||||
}
|
||||
|
||||
// Try to find layout in custom layouts first (by UUID)
|
||||
var customLayouts = FancyZonesData.ReadCustomLayouts();
|
||||
var targetCustomLayout = customLayouts?.Layouts?.FirstOrDefault(l => l.Uuid.Equals(uuid, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// If not found in custom layouts, try template layouts (by type name)
|
||||
TemplateLayout targetTemplate = null;
|
||||
if (targetCustomLayout == null)
|
||||
{
|
||||
var templates = FancyZonesData.ReadLayoutTemplates();
|
||||
targetTemplate = templates?.Templates?.FirstOrDefault(t => t.Type.Equals(uuid, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
if (targetCustomLayout == null && targetTemplate == null)
|
||||
{
|
||||
return (1, $"Error: Layout '{uuid}' not found\nTip: For templates, use the type name (e.g., 'focus', 'columns', 'rows', 'grid', 'priority-grid')\n For custom layouts, use the UUID from 'get-layouts'");
|
||||
}
|
||||
|
||||
// Read current applied layouts
|
||||
if (!FancyZonesData.TryReadAppliedLayouts(out var appliedLayouts, out var error))
|
||||
{
|
||||
return (1, $"Error: {error}");
|
||||
}
|
||||
|
||||
if (appliedLayouts.Layouts == null || appliedLayouts.Layouts.Count == 0)
|
||||
{
|
||||
return (1, "Error: No monitors configured");
|
||||
}
|
||||
|
||||
// Determine which monitors to update
|
||||
List<int> monitorsToUpdate = new List<int>();
|
||||
if (applyToAll)
|
||||
{
|
||||
for (int i = 0; i < appliedLayouts.Layouts.Count; i++)
|
||||
{
|
||||
monitorsToUpdate.Add(i);
|
||||
}
|
||||
}
|
||||
else if (targetMonitor.HasValue)
|
||||
{
|
||||
int monitorIndex = targetMonitor.Value - 1; // Convert to 0-based
|
||||
if (monitorIndex < 0 || monitorIndex >= appliedLayouts.Layouts.Count)
|
||||
{
|
||||
return (1, $"Error: Monitor {targetMonitor.Value} not found. Available monitors: 1-{appliedLayouts.Layouts.Count}");
|
||||
}
|
||||
|
||||
monitorsToUpdate.Add(monitorIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default: first monitor
|
||||
monitorsToUpdate.Add(0);
|
||||
}
|
||||
|
||||
// Update selected monitors
|
||||
foreach (int monitorIndex in monitorsToUpdate)
|
||||
{
|
||||
if (targetCustomLayout != null)
|
||||
{
|
||||
appliedLayouts.Layouts[monitorIndex].AppliedLayout.Uuid = targetCustomLayout.Uuid;
|
||||
appliedLayouts.Layouts[monitorIndex].AppliedLayout.Type = targetCustomLayout.Type;
|
||||
}
|
||||
else if (targetTemplate != null)
|
||||
{
|
||||
// For templates, use all-zeros UUID and the template type
|
||||
appliedLayouts.Layouts[monitorIndex].AppliedLayout.Uuid = "{00000000-0000-0000-0000-000000000000}";
|
||||
appliedLayouts.Layouts[monitorIndex].AppliedLayout.Type = targetTemplate.Type;
|
||||
appliedLayouts.Layouts[monitorIndex].AppliedLayout.ZoneCount = targetTemplate.ZoneCount;
|
||||
appliedLayouts.Layouts[monitorIndex].AppliedLayout.ShowSpacing = targetTemplate.ShowSpacing;
|
||||
appliedLayouts.Layouts[monitorIndex].AppliedLayout.Spacing = targetTemplate.Spacing;
|
||||
}
|
||||
}
|
||||
|
||||
// Write back to file
|
||||
FancyZonesData.WriteAppliedLayouts(appliedLayouts);
|
||||
Logger.LogInfo($"Applied layouts file updated for {monitorsToUpdate.Count} monitor(s)");
|
||||
|
||||
// Notify FancyZones to reload
|
||||
notifyFancyZones(wmPrivAppliedLayoutsFileUpdate);
|
||||
Logger.LogInfo("FancyZones notified of layout change");
|
||||
|
||||
string layoutName = targetCustomLayout?.Name ?? targetTemplate?.Type ?? uuid;
|
||||
if (applyToAll)
|
||||
{
|
||||
return (0, $"Layout '{layoutName}' applied to all {monitorsToUpdate.Count} monitors");
|
||||
}
|
||||
else if (targetMonitor.HasValue)
|
||||
{
|
||||
return (0, $"Layout '{layoutName}' applied to monitor {targetMonitor.Value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
return (0, $"Layout '{layoutName}' applied to monitor 1");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// 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.Globalization;
|
||||
|
||||
namespace FancyZonesCLI.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Monitor-related commands.
|
||||
/// </summary>
|
||||
internal static class MonitorCommands
|
||||
{
|
||||
public static (int ExitCode, string Output) GetMonitors()
|
||||
{
|
||||
if (!FancyZonesData.TryReadAppliedLayouts(out var appliedLayouts, out var error))
|
||||
{
|
||||
return (1, $"Error: {error}");
|
||||
}
|
||||
|
||||
if (appliedLayouts.Layouts == null || appliedLayouts.Layouts.Count == 0)
|
||||
{
|
||||
return (0, "No monitors found.");
|
||||
}
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $"=== Monitors ({appliedLayouts.Layouts.Count} total) ===");
|
||||
sb.AppendLine();
|
||||
|
||||
for (int i = 0; i < appliedLayouts.Layouts.Count; i++)
|
||||
{
|
||||
var layout = appliedLayouts.Layouts[i];
|
||||
var monitorNum = i + 1;
|
||||
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $"Monitor {monitorNum}:");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Monitor: {layout.Device.Monitor}");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Monitor Instance: {layout.Device.MonitorInstance}");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Monitor Number: {layout.Device.MonitorNumber}");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Serial Number: {layout.Device.SerialNumber}");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Virtual Desktop: {layout.Device.VirtualDesktop}");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Sensitivity Radius: {layout.AppliedLayout.SensitivityRadius}px");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Active Layout: {layout.AppliedLayout.Type}");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" Zone Count: {layout.AppliedLayout.ZoneCount}");
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
return (0, sb.ToString().TrimEnd());
|
||||
}
|
||||
}
|
||||
32
src/modules/fancyzones/FancyZonesCLI/FancyZonesCLI.csproj
Normal file
32
src/modules/fancyzones/FancyZonesCLI/FancyZonesCLI.csproj
Normal file
@@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.SelfContained.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>PowerToys.FancyZonesCLI</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys FancyZones Command Line Interface</AssemblyDescription>
|
||||
<Description>PowerToys FancyZones CLI</Description>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Platforms>x64;ARM64</Platforms>
|
||||
<PublishAot>true</PublishAot>
|
||||
<DisableRuntimeMarshalling>true</DisableRuntimeMarshalling>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)</OutputPath>
|
||||
<AssemblyName>FancyZonesCLI</AssemblyName>
|
||||
<NoWarn>$(NoWarn);SA1500;SA1402;CA1852</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Force using WindowsDesktop runtime to ensure consistent dll versions with other projects -->
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.WindowsDesktop.App" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
142
src/modules/fancyzones/FancyZonesCLI/FancyZonesData.cs
Normal file
142
src/modules/fancyzones/FancyZonesCLI/FancyZonesData.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
// 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.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
|
||||
namespace FancyZonesCLI;
|
||||
|
||||
/// <summary>
|
||||
/// Provides methods to read and write FancyZones configuration data.
|
||||
/// </summary>
|
||||
internal static class FancyZonesData
|
||||
{
|
||||
/// <summary>
|
||||
/// Try to read applied layouts configuration.
|
||||
/// </summary>
|
||||
public static bool TryReadAppliedLayouts(out AppliedLayouts result, out string error)
|
||||
{
|
||||
return TryReadJsonFile(FancyZonesPaths.AppliedLayouts, FancyZonesJsonContext.Default.AppliedLayouts, out result, out error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read applied layouts or return null if not found.
|
||||
/// </summary>
|
||||
public static AppliedLayouts ReadAppliedLayouts()
|
||||
{
|
||||
return ReadJsonFileOrDefault(FancyZonesPaths.AppliedLayouts, FancyZonesJsonContext.Default.AppliedLayouts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write applied layouts configuration.
|
||||
/// </summary>
|
||||
public static void WriteAppliedLayouts(AppliedLayouts layouts)
|
||||
{
|
||||
WriteJsonFile(FancyZonesPaths.AppliedLayouts, layouts, FancyZonesJsonContext.Default.AppliedLayouts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read custom layouts or return null if not found.
|
||||
/// </summary>
|
||||
public static CustomLayouts ReadCustomLayouts()
|
||||
{
|
||||
return ReadJsonFileOrDefault(FancyZonesPaths.CustomLayouts, FancyZonesJsonContext.Default.CustomLayouts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read layout templates or return null if not found.
|
||||
/// </summary>
|
||||
public static LayoutTemplates ReadLayoutTemplates()
|
||||
{
|
||||
return ReadJsonFileOrDefault(FancyZonesPaths.LayoutTemplates, FancyZonesJsonContext.Default.LayoutTemplates);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read layout hotkeys or return null if not found.
|
||||
/// </summary>
|
||||
public static LayoutHotkeys ReadLayoutHotkeys()
|
||||
{
|
||||
return ReadJsonFileOrDefault(FancyZonesPaths.LayoutHotkeys, FancyZonesJsonContext.Default.LayoutHotkeys);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write layout hotkeys configuration.
|
||||
/// </summary>
|
||||
public static void WriteLayoutHotkeys(LayoutHotkeys hotkeys)
|
||||
{
|
||||
WriteJsonFile(FancyZonesPaths.LayoutHotkeys, hotkeys, FancyZonesJsonContext.Default.LayoutHotkeys);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if editor parameters file exists.
|
||||
/// </summary>
|
||||
public static bool EditorParametersExist()
|
||||
{
|
||||
return File.Exists(FancyZonesPaths.EditorParameters);
|
||||
}
|
||||
|
||||
private static bool TryReadJsonFile<T>(string filePath, JsonTypeInfo<T> jsonTypeInfo, out T result, out string error)
|
||||
where T : class
|
||||
{
|
||||
result = null;
|
||||
error = null;
|
||||
|
||||
Logger.LogDebug($"Reading file: {filePath}");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
error = $"File not found: {Path.GetFileName(filePath)}";
|
||||
Logger.LogWarning(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
result = JsonSerializer.Deserialize(json, jsonTypeInfo);
|
||||
if (result == null)
|
||||
{
|
||||
error = $"Failed to parse {Path.GetFileName(filePath)}";
|
||||
Logger.LogError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger.LogDebug($"Successfully read {Path.GetFileName(filePath)}");
|
||||
return true;
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
error = $"JSON parse error in {Path.GetFileName(filePath)}: {ex.Message}";
|
||||
Logger.LogError(error, ex);
|
||||
return false;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
error = $"Failed to read {Path.GetFileName(filePath)}: {ex.Message}";
|
||||
Logger.LogError(error, ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static T ReadJsonFileOrDefault<T>(string filePath, JsonTypeInfo<T> jsonTypeInfo, T defaultValue = null)
|
||||
where T : class
|
||||
{
|
||||
if (TryReadJsonFile(filePath, jsonTypeInfo, out var result, out _))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private static void WriteJsonFile<T>(string filePath, T data, JsonTypeInfo<T> jsonTypeInfo)
|
||||
{
|
||||
Logger.LogDebug($"Writing file: {filePath}");
|
||||
var json = JsonSerializer.Serialize(data, jsonTypeInfo);
|
||||
File.WriteAllText(filePath, json);
|
||||
Logger.LogInfo($"Successfully wrote {Path.GetFileName(filePath)}");
|
||||
}
|
||||
}
|
||||
30
src/modules/fancyzones/FancyZonesCLI/FancyZonesPaths.cs
Normal file
30
src/modules/fancyzones/FancyZonesCLI/FancyZonesPaths.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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.IO;
|
||||
|
||||
namespace FancyZonesCLI;
|
||||
|
||||
/// <summary>
|
||||
/// Provides paths to FancyZones configuration files.
|
||||
/// </summary>
|
||||
internal static class FancyZonesPaths
|
||||
{
|
||||
private static readonly string DataPath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"Microsoft",
|
||||
"PowerToys",
|
||||
"FancyZones");
|
||||
|
||||
public static string AppliedLayouts => Path.Combine(DataPath, "applied-layouts.json");
|
||||
|
||||
public static string CustomLayouts => Path.Combine(DataPath, "custom-layouts.json");
|
||||
|
||||
public static string LayoutTemplates => Path.Combine(DataPath, "layout-templates.json");
|
||||
|
||||
public static string LayoutHotkeys => Path.Combine(DataPath, "layout-hotkeys.json");
|
||||
|
||||
public static string EditorParameters => Path.Combine(DataPath, "editor-parameters.json");
|
||||
}
|
||||
550
src/modules/fancyzones/FancyZonesCLI/LayoutVisualizer.cs
Normal file
550
src/modules/fancyzones/FancyZonesCLI/LayoutVisualizer.cs
Normal file
@@ -0,0 +1,550 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace FancyZonesCLI;
|
||||
|
||||
public static class LayoutVisualizer
|
||||
{
|
||||
public static string DrawTemplateLayout(TemplateLayout template)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(" Visual Preview:");
|
||||
|
||||
switch (template.Type.ToLowerInvariant())
|
||||
{
|
||||
case "focus":
|
||||
sb.Append(RenderFocusLayout(template.ZoneCount > 0 ? template.ZoneCount : 3));
|
||||
break;
|
||||
case "columns":
|
||||
sb.Append(RenderGridLayout(1, template.ZoneCount > 0 ? template.ZoneCount : 3));
|
||||
break;
|
||||
case "rows":
|
||||
sb.Append(RenderGridLayout(template.ZoneCount > 0 ? template.ZoneCount : 3, 1));
|
||||
break;
|
||||
case "grid":
|
||||
// Grid layout: calculate rows and columns from zone count
|
||||
// Algorithm from GridLayoutModel.InitGrid() - tries to make it close to square
|
||||
// with cols >= rows preference
|
||||
int zoneCount = template.ZoneCount > 0 ? template.ZoneCount : 3;
|
||||
int rows = 1;
|
||||
while (zoneCount / rows >= rows)
|
||||
{
|
||||
rows++;
|
||||
}
|
||||
|
||||
rows--;
|
||||
int cols = zoneCount / rows;
|
||||
if (zoneCount % rows != 0)
|
||||
{
|
||||
cols++;
|
||||
}
|
||||
|
||||
sb.Append(RenderGridLayoutWithZoneCount(rows, cols, zoneCount));
|
||||
break;
|
||||
case "priority-grid":
|
||||
sb.Append(RenderPriorityGridLayout(template.ZoneCount > 0 ? template.ZoneCount : 3));
|
||||
break;
|
||||
case "blank":
|
||||
sb.AppendLine(" (No zones)");
|
||||
break;
|
||||
default:
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" ({template.Type} layout)");
|
||||
break;
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string DrawCustomLayout(CustomLayout layout)
|
||||
{
|
||||
if (layout.Info.ValueKind == JsonValueKind.Undefined || layout.Info.ValueKind == JsonValueKind.Null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(" Visual Preview:");
|
||||
|
||||
if (layout.Type == "grid" &&
|
||||
layout.Info.TryGetProperty("rows", out var rows) &&
|
||||
layout.Info.TryGetProperty("columns", out var cols))
|
||||
{
|
||||
int r = rows.GetInt32();
|
||||
int c = cols.GetInt32();
|
||||
|
||||
// Check if there's a cell-child-map (merged cells)
|
||||
if (layout.Info.TryGetProperty("cell-child-map", out var cellMap))
|
||||
{
|
||||
sb.Append(RenderGridLayoutWithMergedCells(r, c, cellMap));
|
||||
}
|
||||
else
|
||||
{
|
||||
int height = r >= 4 ? 12 : 8;
|
||||
sb.Append(RenderGridLayout(r, c, 30, height));
|
||||
}
|
||||
}
|
||||
else if (layout.Type == "canvas" &&
|
||||
layout.Info.TryGetProperty("zones", out var zones) &&
|
||||
layout.Info.TryGetProperty("ref-width", out var refWidth) &&
|
||||
layout.Info.TryGetProperty("ref-height", out var refHeight))
|
||||
{
|
||||
sb.Append(RenderCanvasLayout(zones, refWidth.GetInt32(), refHeight.GetInt32()));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string RenderFocusLayout(int zoneCount = 3)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
// Focus layout: overlapping zones with cascading offset
|
||||
if (zoneCount == 1)
|
||||
{
|
||||
sb.AppendLine(" +-------+");
|
||||
sb.AppendLine(" | |");
|
||||
sb.AppendLine(" | |");
|
||||
sb.AppendLine(" +-------+");
|
||||
}
|
||||
else if (zoneCount == 2)
|
||||
{
|
||||
sb.AppendLine(" +-------+");
|
||||
sb.AppendLine(" | |");
|
||||
sb.AppendLine(" | +-------+");
|
||||
sb.AppendLine(" +-| |");
|
||||
sb.AppendLine(" | |");
|
||||
sb.AppendLine(" +-------+");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine(" +-------+");
|
||||
sb.AppendLine(" | |");
|
||||
sb.AppendLine(" | +-------+");
|
||||
sb.AppendLine(" +-| |");
|
||||
sb.AppendLine(" | +-------+");
|
||||
sb.AppendLine(" +-| |");
|
||||
sb.AppendLine(" ...");
|
||||
sb.AppendLine(CultureInfo.InvariantCulture, $" (total: {zoneCount} zones)");
|
||||
sb.AppendLine(" ...");
|
||||
sb.AppendLine(" | +-------+");
|
||||
sb.AppendLine(" +-| |");
|
||||
sb.AppendLine(" | |");
|
||||
sb.AppendLine(" +-------+");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string RenderPriorityGridLayout(int zoneCount = 3)
|
||||
{
|
||||
// Priority Grid has predefined layouts for zone counts 1-11
|
||||
// Data format from GridLayoutModel._priorityData
|
||||
if (zoneCount >= 1 && zoneCount <= 11)
|
||||
{
|
||||
int[,] cellMap = GetPriorityGridCellMap(zoneCount);
|
||||
return RenderGridLayoutWithCellMap(cellMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
// > 11 zones: use grid layout
|
||||
int rows = 1;
|
||||
while (zoneCount / rows >= rows)
|
||||
{
|
||||
rows++;
|
||||
}
|
||||
|
||||
rows--;
|
||||
int cols = zoneCount / rows;
|
||||
if (zoneCount % rows != 0)
|
||||
{
|
||||
cols++;
|
||||
}
|
||||
|
||||
return RenderGridLayoutWithZoneCount(rows, cols, zoneCount);
|
||||
}
|
||||
}
|
||||
|
||||
private static int[,] GetPriorityGridCellMap(int zoneCount)
|
||||
{
|
||||
// Parsed from Editor's _priorityData byte arrays
|
||||
return zoneCount switch
|
||||
{
|
||||
1 => new int[,] { { 0 } },
|
||||
2 => new int[,] { { 0, 1 } },
|
||||
3 => new int[,] { { 0, 1, 2 } },
|
||||
4 => new int[,] { { 0, 1, 2 }, { 0, 1, 3 } },
|
||||
5 => new int[,] { { 0, 1, 2 }, { 3, 1, 4 } },
|
||||
6 => new int[,] { { 0, 1, 2 }, { 0, 1, 3 }, { 4, 1, 5 } },
|
||||
7 => new int[,] { { 0, 1, 2 }, { 3, 1, 4 }, { 5, 1, 6 } },
|
||||
8 => new int[,] { { 0, 1, 2, 3 }, { 4, 1, 2, 5 }, { 6, 1, 2, 7 } },
|
||||
9 => new int[,] { { 0, 1, 2, 3 }, { 4, 1, 2, 5 }, { 6, 1, 7, 8 } },
|
||||
10 => new int[,] { { 0, 1, 2, 3 }, { 4, 1, 5, 6 }, { 7, 1, 8, 9 } },
|
||||
11 => new int[,] { { 0, 1, 2, 3 }, { 4, 1, 5, 6 }, { 7, 8, 9, 10 } },
|
||||
_ => new int[,] { { 0 } },
|
||||
};
|
||||
}
|
||||
|
||||
private static string RenderGridLayoutWithCellMap(int[,] cellMap, int width = 30, int height = 8)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
int rows = cellMap.GetLength(0);
|
||||
int cols = cellMap.GetLength(1);
|
||||
|
||||
int cellWidth = width / cols;
|
||||
int cellHeight = height / rows;
|
||||
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
// Top border
|
||||
sb.Append(" +");
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
bool mergeTop = r > 0 && cellMap[r, c] == cellMap[r - 1, c];
|
||||
bool mergeLeft = c > 0 && cellMap[r, c] == cellMap[r, c - 1];
|
||||
|
||||
if (mergeTop)
|
||||
{
|
||||
sb.Append(mergeLeft ? new string(' ', cellWidth) : new string(' ', cellWidth - 1) + "+");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(mergeLeft ? new string('-', cellWidth) : new string('-', cellWidth - 1) + "+");
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
// Cell content
|
||||
for (int h = 0; h < cellHeight - 1; h++)
|
||||
{
|
||||
sb.Append(" ");
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
bool mergeLeft = c > 0 && cellMap[r, c] == cellMap[r, c - 1];
|
||||
sb.Append(mergeLeft ? ' ' : '|');
|
||||
sb.Append(' ', cellWidth - 1);
|
||||
}
|
||||
|
||||
sb.AppendLine("|");
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom border
|
||||
sb.Append(" +");
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
sb.Append('-', cellWidth - 1);
|
||||
sb.Append('+');
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string RenderGridLayoutWithMergedCells(int rows, int cols, JsonElement cellMap)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
const int displayWidth = 39;
|
||||
const int displayHeight = 12;
|
||||
|
||||
// Build zone map from cell-child-map
|
||||
int[,] zoneMap = new int[rows, cols];
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
var rowArray = cellMap[r];
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
zoneMap[r, c] = rowArray[c].GetInt32();
|
||||
}
|
||||
}
|
||||
|
||||
int cellHeight = displayHeight / rows;
|
||||
int cellWidth = displayWidth / cols;
|
||||
|
||||
// Draw top border
|
||||
sb.Append(" +");
|
||||
sb.Append('-', displayWidth);
|
||||
sb.AppendLine("+");
|
||||
|
||||
// Draw rows
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
for (int h = 0; h < cellHeight; h++)
|
||||
{
|
||||
sb.Append(" |");
|
||||
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
int currentZone = zoneMap[r, c];
|
||||
int leftZone = c > 0 ? zoneMap[r, c - 1] : -1;
|
||||
bool needLeftBorder = c > 0 && currentZone != leftZone;
|
||||
|
||||
bool zoneHasTopBorder = r > 0 && h == 0 && currentZone != zoneMap[r - 1, c];
|
||||
|
||||
if (needLeftBorder)
|
||||
{
|
||||
sb.Append('|');
|
||||
sb.Append(zoneHasTopBorder ? '-' : ' ', cellWidth - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(zoneHasTopBorder ? '-' : ' ', cellWidth);
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine("|");
|
||||
}
|
||||
}
|
||||
|
||||
// Draw bottom border
|
||||
sb.Append(" +");
|
||||
sb.Append('-', displayWidth);
|
||||
sb.AppendLine("+");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string RenderGridLayoutWithZoneCount(int rows, int cols, int zoneCount, int width = 30, int height = 8)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
// Build zone map like Editor's InitGrid
|
||||
int[,] zoneMap = new int[rows, cols];
|
||||
int index = 0;
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
zoneMap[r, c] = index++;
|
||||
if (index == zoneCount)
|
||||
{
|
||||
index--; // Remaining cells use the last zone index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cellWidth = width / cols;
|
||||
int cellHeight = height / rows;
|
||||
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
// Top border
|
||||
sb.Append(" +");
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
bool mergeLeft = c > 0 && zoneMap[r, c] == zoneMap[r, c - 1];
|
||||
sb.Append('-', mergeLeft ? cellWidth : cellWidth - 1);
|
||||
if (!mergeLeft)
|
||||
{
|
||||
sb.Append('+');
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
// Cell content
|
||||
for (int h = 0; h < cellHeight - 1; h++)
|
||||
{
|
||||
sb.Append(" ");
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
bool mergeLeft = c > 0 && zoneMap[r, c] == zoneMap[r, c - 1];
|
||||
sb.Append(mergeLeft ? ' ' : '|');
|
||||
sb.Append(' ', cellWidth - 1);
|
||||
}
|
||||
|
||||
sb.AppendLine("|");
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom border
|
||||
sb.Append(" +");
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
sb.Append('-', cellWidth - 1);
|
||||
sb.Append('+');
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string RenderGridLayout(int rows, int cols, int width = 30, int height = 8)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
int cellWidth = width / cols;
|
||||
int cellHeight = height / rows;
|
||||
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
// Top border
|
||||
sb.Append(" +");
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
sb.Append('-', cellWidth - 1);
|
||||
sb.Append('+');
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
// Cell content
|
||||
for (int h = 0; h < cellHeight - 1; h++)
|
||||
{
|
||||
sb.Append(" ");
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
sb.Append('|');
|
||||
sb.Append(' ', cellWidth - 1);
|
||||
}
|
||||
|
||||
sb.AppendLine("|");
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom border
|
||||
sb.Append(" +");
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
sb.Append('-', cellWidth - 1);
|
||||
sb.Append('+');
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string RenderCanvasLayout(JsonElement zones, int refWidth, int refHeight)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
const int displayWidth = 49;
|
||||
const int displayHeight = 15;
|
||||
|
||||
// Create a 2D array to track which zones occupy each position
|
||||
var zoneGrid = new List<int>[displayHeight, displayWidth];
|
||||
for (int i = 0; i < displayHeight; i++)
|
||||
{
|
||||
for (int j = 0; j < displayWidth; j++)
|
||||
{
|
||||
zoneGrid[i, j] = new List<int>();
|
||||
}
|
||||
}
|
||||
|
||||
// Map each zone to the grid
|
||||
int zoneId = 0;
|
||||
var zoneList = new List<(int X, int Y, int Width, int Height, int Id)>();
|
||||
|
||||
foreach (var zone in zones.EnumerateArray())
|
||||
{
|
||||
int x = zone.GetProperty("X").GetInt32();
|
||||
int y = zone.GetProperty("Y").GetInt32();
|
||||
int w = zone.GetProperty("width").GetInt32();
|
||||
int h = zone.GetProperty("height").GetInt32();
|
||||
|
||||
int dx = Math.Max(0, Math.Min(displayWidth - 1, x * displayWidth / refWidth));
|
||||
int dy = Math.Max(0, Math.Min(displayHeight - 1, y * displayHeight / refHeight));
|
||||
int dw = Math.Max(3, w * displayWidth / refWidth);
|
||||
int dh = Math.Max(2, h * displayHeight / refHeight);
|
||||
|
||||
if (dx + dw > displayWidth)
|
||||
{
|
||||
dw = displayWidth - dx;
|
||||
}
|
||||
|
||||
if (dy + dh > displayHeight)
|
||||
{
|
||||
dh = displayHeight - dy;
|
||||
}
|
||||
|
||||
zoneList.Add((dx, dy, dw, dh, zoneId));
|
||||
|
||||
for (int r = dy; r < dy + dh && r < displayHeight; r++)
|
||||
{
|
||||
for (int c = dx; c < dx + dw && c < displayWidth; c++)
|
||||
{
|
||||
zoneGrid[r, c].Add(zoneId);
|
||||
}
|
||||
}
|
||||
|
||||
zoneId++;
|
||||
}
|
||||
|
||||
// Draw top border
|
||||
sb.Append(" +");
|
||||
sb.Append('-', displayWidth);
|
||||
sb.AppendLine("+");
|
||||
|
||||
// Draw each row
|
||||
char[] shades = { '.', ':', '░', '▒', '▓', '█', '◆', '●', '■', '▪' };
|
||||
|
||||
for (int r = 0; r < displayHeight; r++)
|
||||
{
|
||||
sb.Append(" |");
|
||||
for (int c = 0; c < displayWidth; c++)
|
||||
{
|
||||
var zonesHere = zoneGrid[r, c];
|
||||
|
||||
if (zonesHere.Count == 0)
|
||||
{
|
||||
sb.Append(' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
int topZone = zonesHere[zonesHere.Count - 1];
|
||||
var rect = zoneList[topZone];
|
||||
|
||||
bool isTopEdge = r == rect.Y;
|
||||
bool isBottomEdge = r == rect.Y + rect.Height - 1;
|
||||
bool isLeftEdge = c == rect.X;
|
||||
bool isRightEdge = c == rect.X + rect.Width - 1;
|
||||
|
||||
if ((isTopEdge || isBottomEdge) && (isLeftEdge || isRightEdge))
|
||||
{
|
||||
sb.Append('+');
|
||||
}
|
||||
else if (isTopEdge || isBottomEdge)
|
||||
{
|
||||
sb.Append('-');
|
||||
}
|
||||
else if (isLeftEdge || isRightEdge)
|
||||
{
|
||||
sb.Append('|');
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(shades[topZone % shades.Length]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine("|");
|
||||
}
|
||||
|
||||
// Draw bottom border
|
||||
sb.Append(" +");
|
||||
sb.Append('-', displayWidth);
|
||||
sb.AppendLine("+");
|
||||
|
||||
// Draw legend
|
||||
sb.AppendLine();
|
||||
sb.Append(" Legend: ");
|
||||
for (int i = 0; i < Math.Min(zoneId, shades.Length); i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append(CultureInfo.InvariantCulture, $"Zone {i} = {shades[i]}");
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
126
src/modules/fancyzones/FancyZonesCLI/Logger.cs
Normal file
126
src/modules/fancyzones/FancyZonesCLI/Logger.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
// 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.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace FancyZonesCLI;
|
||||
|
||||
/// <summary>
|
||||
/// Simple logger for FancyZones CLI.
|
||||
/// Logs to %LOCALAPPDATA%\Microsoft\PowerToys\FancyZones\CLI\Logs
|
||||
/// </summary>
|
||||
internal static class Logger
|
||||
{
|
||||
private static readonly object LockObj = new();
|
||||
private static string _logFilePath = string.Empty;
|
||||
private static bool _isInitialized;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the current log file.
|
||||
/// </summary>
|
||||
public static string LogFilePath => _logFilePath;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the logger.
|
||||
/// </summary>
|
||||
public static void InitializeLogger()
|
||||
{
|
||||
if (_isInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var logDirectory = Path.Combine(localAppData, "Microsoft", "PowerToys", "FancyZones", "CLI", "Logs");
|
||||
|
||||
if (!Directory.Exists(logDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(logDirectory);
|
||||
}
|
||||
|
||||
var logFileName = $"FancyZonesCLI_{DateTime.Now:yyyy-MM-dd}.log";
|
||||
_logFilePath = Path.Combine(logDirectory, logFileName);
|
||||
_isInitialized = true;
|
||||
|
||||
LogInfo("FancyZones CLI started");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Silently fail if logging cannot be initialized
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs an error message.
|
||||
/// </summary>
|
||||
public static void LogError(string message, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
Log("ERROR", message, memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs an error message with exception details.
|
||||
/// </summary>
|
||||
public static void LogError(string message, Exception ex, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
var fullMessage = ex == null
|
||||
? message
|
||||
: $"{message} | Exception: {ex.GetType().Name}: {ex.Message}";
|
||||
Log("ERROR", fullMessage, memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs a warning message.
|
||||
/// </summary>
|
||||
public static void LogWarning(string message, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
Log("WARN", message, memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs an informational message.
|
||||
/// </summary>
|
||||
public static void LogInfo(string message, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
Log("INFO", message, memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs a debug message (only in DEBUG builds).
|
||||
/// </summary>
|
||||
[System.Diagnostics.Conditional("DEBUG")]
|
||||
public static void LogDebug(string message, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
|
||||
{
|
||||
Log("DEBUG", message, memberName, sourceFilePath, sourceLineNumber);
|
||||
}
|
||||
|
||||
private static void Log(string level, string message, string memberName, string sourceFilePath, int sourceLineNumber)
|
||||
{
|
||||
if (!_isInitialized || string.IsNullOrEmpty(_logFilePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var fileName = Path.GetFileName(sourceFilePath);
|
||||
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
|
||||
var logEntry = $"[{timestamp}] [{level}] [{fileName}:{sourceLineNumber}] [{memberName}] {message}{Environment.NewLine}";
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
File.AppendAllText(_logFilePath, logEntry);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Silently fail if logging fails
|
||||
}
|
||||
}
|
||||
}
|
||||
137
src/modules/fancyzones/FancyZonesCLI/Models.cs
Normal file
137
src/modules/fancyzones/FancyZonesCLI/Models.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace FancyZonesCLI;
|
||||
|
||||
// JSON Source Generator for AOT compatibility
|
||||
[JsonSerializable(typeof(LayoutTemplates))]
|
||||
[JsonSerializable(typeof(CustomLayouts))]
|
||||
[JsonSerializable(typeof(AppliedLayouts))]
|
||||
[JsonSerializable(typeof(LayoutHotkeys))]
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
internal partial class FancyZonesJsonContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
// Layout Templates
|
||||
public sealed class LayoutTemplates
|
||||
{
|
||||
[JsonPropertyName("layout-templates")]
|
||||
public List<TemplateLayout> Templates { get; set; }
|
||||
}
|
||||
|
||||
public sealed class TemplateLayout
|
||||
{
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("zone-count")]
|
||||
public int ZoneCount { get; set; }
|
||||
|
||||
[JsonPropertyName("show-spacing")]
|
||||
public bool ShowSpacing { get; set; }
|
||||
|
||||
[JsonPropertyName("spacing")]
|
||||
public int Spacing { get; set; }
|
||||
|
||||
[JsonPropertyName("sensitivity-radius")]
|
||||
public int SensitivityRadius { get; set; }
|
||||
}
|
||||
|
||||
// Custom Layouts
|
||||
public sealed class CustomLayouts
|
||||
{
|
||||
[JsonPropertyName("custom-layouts")]
|
||||
public List<CustomLayout> Layouts { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CustomLayout
|
||||
{
|
||||
[JsonPropertyName("uuid")]
|
||||
public string Uuid { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("info")]
|
||||
public JsonElement Info { get; set; }
|
||||
}
|
||||
|
||||
// Applied Layouts
|
||||
public sealed class AppliedLayouts
|
||||
{
|
||||
[JsonPropertyName("applied-layouts")]
|
||||
public List<AppliedLayoutWrapper> Layouts { get; set; }
|
||||
}
|
||||
|
||||
public sealed class AppliedLayoutWrapper
|
||||
{
|
||||
[JsonPropertyName("device")]
|
||||
public DeviceInfo Device { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("applied-layout")]
|
||||
public AppliedLayoutInfo AppliedLayout { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class DeviceInfo
|
||||
{
|
||||
[JsonPropertyName("monitor")]
|
||||
public string Monitor { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("monitor-instance")]
|
||||
public string MonitorInstance { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("monitor-number")]
|
||||
public int MonitorNumber { get; set; }
|
||||
|
||||
[JsonPropertyName("serial-number")]
|
||||
public string SerialNumber { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("virtual-desktop")]
|
||||
public string VirtualDesktop { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed class AppliedLayoutInfo
|
||||
{
|
||||
[JsonPropertyName("uuid")]
|
||||
public string Uuid { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("show-spacing")]
|
||||
public bool ShowSpacing { get; set; }
|
||||
|
||||
[JsonPropertyName("spacing")]
|
||||
public int Spacing { get; set; }
|
||||
|
||||
[JsonPropertyName("zone-count")]
|
||||
public int ZoneCount { get; set; }
|
||||
|
||||
[JsonPropertyName("sensitivity-radius")]
|
||||
public int SensitivityRadius { get; set; }
|
||||
}
|
||||
|
||||
// Layout Hotkeys
|
||||
public sealed class LayoutHotkeys
|
||||
{
|
||||
[JsonPropertyName("layout-hotkeys")]
|
||||
public List<LayoutHotkey> Hotkeys { get; set; }
|
||||
}
|
||||
|
||||
public sealed class LayoutHotkey
|
||||
{
|
||||
[JsonPropertyName("key")]
|
||||
public int Key { get; set; }
|
||||
|
||||
[JsonPropertyName("layout-id")]
|
||||
public string LayoutId { get; set; } = string.Empty;
|
||||
}
|
||||
56
src/modules/fancyzones/FancyZonesCLI/NativeMethods.cs
Normal file
56
src/modules/fancyzones/FancyZonesCLI/NativeMethods.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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 Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
|
||||
namespace FancyZonesCLI;
|
||||
|
||||
/// <summary>
|
||||
/// Native Windows API methods for FancyZones CLI.
|
||||
/// </summary>
|
||||
internal static class NativeMethods
|
||||
{
|
||||
// Registered Windows messages for notifying FancyZones
|
||||
private static uint wmPrivAppliedLayoutsFileUpdate;
|
||||
private static uint wmPrivLayoutHotkeysFileUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Windows message ID for applied layouts file update notification.
|
||||
/// </summary>
|
||||
public static uint WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE => wmPrivAppliedLayoutsFileUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Windows message ID for layout hotkeys file update notification.
|
||||
/// </summary>
|
||||
public static uint WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE => wmPrivLayoutHotkeysFileUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Windows messages used for FancyZones notifications.
|
||||
/// </summary>
|
||||
public static void InitializeWindowMessages()
|
||||
{
|
||||
wmPrivAppliedLayoutsFileUpdate = PInvoke.RegisterWindowMessage("{2ef2c8a7-e0d5-4f31-9ede-52aade2d284d}");
|
||||
wmPrivLayoutHotkeysFileUpdate = PInvoke.RegisterWindowMessage("{07229b7e-4f22-4357-b136-33c289be2295}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Broadcasts a notification message to FancyZones.
|
||||
/// </summary>
|
||||
/// <param name="message">The Windows message ID to broadcast.</param>
|
||||
public static void NotifyFancyZones(uint message)
|
||||
{
|
||||
PInvoke.PostMessage(HWND.HWND_BROADCAST, message, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Brings the specified window to the foreground.
|
||||
/// </summary>
|
||||
/// <param name="hWnd">A handle to the window.</param>
|
||||
/// <returns>True if the window was brought to the foreground.</returns>
|
||||
public static bool SetForegroundWindow(nint hWnd)
|
||||
{
|
||||
return PInvoke.SetForegroundWindow(new HWND(hWnd));
|
||||
}
|
||||
}
|
||||
5
src/modules/fancyzones/FancyZonesCLI/NativeMethods.json
Normal file
5
src/modules/fancyzones/FancyZonesCLI/NativeMethods.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://aka.ms/CsWin32.schema.json",
|
||||
"emitSingleFile": true,
|
||||
"allowMarshaling": false
|
||||
}
|
||||
4
src/modules/fancyzones/FancyZonesCLI/NativeMethods.txt
Normal file
4
src/modules/fancyzones/FancyZonesCLI/NativeMethods.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
PostMessage
|
||||
SetForegroundWindow
|
||||
RegisterWindowMessage
|
||||
HWND_BROADCAST
|
||||
115
src/modules/fancyzones/FancyZonesCLI/Program.cs
Normal file
115
src/modules/fancyzones/FancyZonesCLI/Program.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
// 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.Linq;
|
||||
using FancyZonesCLI.Commands;
|
||||
|
||||
namespace FancyZonesCLI;
|
||||
|
||||
internal sealed class Program
|
||||
{
|
||||
private static int Main(string[] args)
|
||||
{
|
||||
// Initialize logger
|
||||
Logger.InitializeLogger();
|
||||
Logger.LogInfo($"CLI invoked with args: [{string.Join(", ", args)}]");
|
||||
|
||||
// Initialize Windows messages
|
||||
NativeMethods.InitializeWindowMessages();
|
||||
|
||||
(int ExitCode, string Output) result;
|
||||
|
||||
if (args.Length == 0)
|
||||
{
|
||||
result = (1, GetUsageText());
|
||||
}
|
||||
else
|
||||
{
|
||||
var command = args[0].ToLowerInvariant();
|
||||
|
||||
result = command switch
|
||||
{
|
||||
"open-editor" or "editor" or "e" => EditorCommands.OpenEditor(),
|
||||
"get-monitors" or "monitors" or "m" => MonitorCommands.GetMonitors(),
|
||||
"get-layouts" or "layouts" or "ls" => LayoutCommands.GetLayouts(),
|
||||
"get-active-layout" or "active" or "get-active" or "a" => LayoutCommands.GetActiveLayout(),
|
||||
"set-layout" or "set" or "s" => args.Length >= 2
|
||||
? LayoutCommands.SetLayout(args.Skip(1).ToArray(), NativeMethods.NotifyFancyZones, NativeMethods.WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE)
|
||||
: (1, "Error: set-layout requires a UUID parameter"),
|
||||
"open-settings" or "settings" => EditorCommands.OpenSettings(),
|
||||
"get-hotkeys" or "hotkeys" or "hk" => HotkeyCommands.GetHotkeys(),
|
||||
"set-hotkey" or "shk" => args.Length >= 3
|
||||
? HotkeyCommands.SetHotkey(int.Parse(args[1], CultureInfo.InvariantCulture), args[2], NativeMethods.NotifyFancyZones, NativeMethods.WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE)
|
||||
: (1, "Error: set-hotkey requires <key> <uuid>"),
|
||||
"remove-hotkey" or "rhk" => args.Length >= 2
|
||||
? HotkeyCommands.RemoveHotkey(int.Parse(args[1], CultureInfo.InvariantCulture), NativeMethods.NotifyFancyZones, NativeMethods.WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE)
|
||||
: (1, "Error: remove-hotkey requires <key>"),
|
||||
"help" or "--help" or "-h" => (0, GetUsageText()),
|
||||
_ => (1, $"Error: Unknown command: {command}\n\n{GetUsageText()}"),
|
||||
};
|
||||
}
|
||||
|
||||
// Log result
|
||||
if (result.ExitCode == 0)
|
||||
{
|
||||
Logger.LogInfo($"Command completed successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogWarning($"Command failed with exit code {result.ExitCode}: {result.Output}");
|
||||
}
|
||||
|
||||
// Output result
|
||||
if (!string.IsNullOrEmpty(result.Output))
|
||||
{
|
||||
Console.WriteLine(result.Output);
|
||||
}
|
||||
|
||||
return result.ExitCode;
|
||||
}
|
||||
|
||||
private static string GetUsageText()
|
||||
{
|
||||
return """
|
||||
FancyZones CLI - Command line interface for FancyZones
|
||||
======================================================
|
||||
|
||||
Usage: FancyZonesCLI.exe <command> [options]
|
||||
|
||||
Commands:
|
||||
open-editor (editor, e) Launch FancyZones layout editor
|
||||
get-monitors (monitors, m) List all monitors and their properties
|
||||
get-layouts (layouts, ls) List all available layouts
|
||||
get-active-layout (get-active, active, a)
|
||||
Show currently active layout
|
||||
set-layout (set, s) <uuid> [options]
|
||||
Set layout by UUID
|
||||
--monitor <n> Apply to monitor N (1-based)
|
||||
--all Apply to all monitors
|
||||
open-settings (settings) Open FancyZones settings page
|
||||
get-hotkeys (hotkeys, hk) List all layout hotkeys
|
||||
set-hotkey (shk) <key> <uuid> Assign hotkey (0-9) to CUSTOM layout
|
||||
Note: Only custom layouts work with hotkeys
|
||||
remove-hotkey (rhk) <key> Remove hotkey assignment
|
||||
help Show this help message
|
||||
|
||||
|
||||
Examples:
|
||||
FancyZonesCLI.exe e # Open editor (short)
|
||||
FancyZonesCLI.exe m # List monitors (short)
|
||||
FancyZonesCLI.exe ls # List layouts (short)
|
||||
FancyZonesCLI.exe a # Get active layout (short)
|
||||
FancyZonesCLI.exe s focus --all # Set layout (short)
|
||||
FancyZonesCLI.exe open-editor # Open editor (long)
|
||||
FancyZonesCLI.exe get-monitors
|
||||
FancyZonesCLI.exe get-layouts
|
||||
FancyZonesCLI.exe set-layout {12345678-1234-1234-1234-123456789012}
|
||||
FancyZonesCLI.exe set-layout focus --monitor 2
|
||||
FancyZonesCLI.exe set-layout columns --all
|
||||
FancyZonesCLI.exe set-hotkey 3 {12345678-1234-1234-1234-123456789012}
|
||||
""";
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ namespace Microsoft.PowerToys.Run.Plugin.PowerToys
|
||||
|
||||
public UtilityProvider()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
var generalSettings = settingsUtils.GetSettings<GeneralSettings>();
|
||||
|
||||
_utilities = new List<Utility>();
|
||||
@@ -228,7 +228,7 @@ namespace Microsoft.PowerToys.Run.Plugin.PowerToys
|
||||
{
|
||||
retryCount++;
|
||||
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
var generalSettings = settingsUtils.GetSettings<GeneralSettings>();
|
||||
|
||||
foreach (var u in _utilities)
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace PowerLauncher
|
||||
|
||||
public SettingsReader(PowerToysRunSettings settings, ThemeManager themeManager)
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
_settings = settings;
|
||||
_themeManager = themeManager;
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Peek.FilePreviewer.Models
|
||||
|
||||
public PreviewSettings()
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
SourceCodeWrapText = false;
|
||||
SourceCodeTryFormat = false;
|
||||
SourceCodeFontSize = 14;
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Peek.UI
|
||||
|
||||
public UserSettings()
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
|
||||
LoadSettingsFromJson();
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public class SettingsService
|
||||
|
||||
public SettingsService(KeyboardListener keyboardListener)
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
_keyboardListener = keyboardListener;
|
||||
ReadSettings();
|
||||
_watcher = Helper.GetFileWatcher(PowerAccentModuleName, "settings.json", () => { ReadSettings(); });
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace PowerAccent.Core.Tools
|
||||
|
||||
public CharactersUsageInfo()
|
||||
{
|
||||
_filePath = new SettingsUtils().GetSettingsFilePath(PowerAccentSettings.ModuleName, "UsageInfo.json");
|
||||
_filePath = SettingsUtils.Default.GetSettingsFilePath(PowerAccentSettings.ModuleName, "UsageInfo.json");
|
||||
var data = GetUsageInfoData();
|
||||
_characterUsageCounters = data.CharacterUsageCounters;
|
||||
_characterUsageTimestamp = data.CharacterUsageTimestamp;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
|
||||
<ProjectPriFileName>PowerToys.PowerRename.pri</ProjectPriFileName>
|
||||
<RuntimeIdentifier>win10-x64;win10-arm64</RuntimeIdentifier>
|
||||
<WindowsAppSDKVerifyTransitiveDependencies>false</WindowsAppSDKVerifyTransitiveDependencies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" GeneratePathProperty="true" />
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco
|
||||
/// </summary>
|
||||
public class Settings
|
||||
{
|
||||
private static SettingsUtils moduleSettings = new SettingsUtils();
|
||||
private static SettingsUtils moduleSettings = SettingsUtils.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether word wrapping should be applied. Set by PT settings.
|
||||
|
||||
@@ -155,7 +155,7 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Stl
|
||||
{
|
||||
try
|
||||
{
|
||||
var moduleSettings = new SettingsUtils();
|
||||
var moduleSettings = SettingsUtils.Default;
|
||||
|
||||
var colorString = moduleSettings.GetSettings<PowerPreviewSettings>(PowerPreviewSettings.ModuleName).Properties.StlThumbnailColor.Value;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace SvgPreviewHandler
|
||||
{
|
||||
internal sealed class Settings
|
||||
{
|
||||
private static readonly SettingsUtils ModuleSettings = new SettingsUtils();
|
||||
private static readonly SettingsUtils ModuleSettings = SettingsUtils.Default;
|
||||
|
||||
public int ColorMode
|
||||
{
|
||||
|
||||
@@ -592,7 +592,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
/// </summary>
|
||||
public (bool Success, string Message, string Severity, bool LastBackupExists, string OptionalMessage) DryRunBackup()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
var appBasePath = Path.GetDirectoryName(settingsUtils.GetSettingsFilePath());
|
||||
string settingsBackupAndRestoreDir = GetSettingsBackupAndRestoreDir();
|
||||
var results = BackupSettings(appBasePath, settingsBackupAndRestoreDir, true);
|
||||
|
||||
@@ -22,7 +22,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
private readonly ISettingsPath _settingsPath;
|
||||
private readonly JsonSerializerOptions _serializerOptions;
|
||||
|
||||
public SettingsUtils()
|
||||
/// <summary>
|
||||
/// Gets the default instance of the <see cref="SettingsUtils"/> class for general use.
|
||||
/// Same as instantiating a new instance with the <see cref="SettingsUtils(IFileSystem?, JsonSerializerOptions?)"/> constructor with a new <see cref="FileSystem"/> object as the first argument and <c>null</c> as the second argument.
|
||||
/// </summary>
|
||||
/// <remarks>For using in tests, you should use one of the public constructors.</remarks>
|
||||
public static SettingsUtils Default { get; } = new SettingsUtils();
|
||||
|
||||
private SettingsUtils()
|
||||
: this(new FileSystem())
|
||||
{
|
||||
}
|
||||
@@ -234,7 +241,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public static (bool Success, string Message, string Severity, bool LastBackupExists, string OptionalMessage) BackupSettings()
|
||||
{
|
||||
var settingsBackupAndRestoreUtilsX = SettingsBackupAndRestoreUtils.Instance;
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = Default;
|
||||
var appBasePath = Path.GetDirectoryName(settingsUtils._settingsPath.GetSettingsPath(string.Empty, string.Empty));
|
||||
string settingsBackupAndRestoreDir = settingsBackupAndRestoreUtilsX.GetSettingsBackupAndRestoreDir();
|
||||
|
||||
@@ -247,7 +254,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public static (bool Success, string Message, string Severity) RestoreSettings()
|
||||
{
|
||||
var settingsBackupAndRestoreUtilsX = SettingsBackupAndRestoreUtils.Instance;
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = Default;
|
||||
var appBasePath = Path.GetDirectoryName(settingsUtils._settingsPath.GetSettingsPath(string.Empty, string.Empty));
|
||||
string settingsBackupAndRestoreDir = settingsBackupAndRestoreUtilsX.GetSettingsBackupAndRestoreDir();
|
||||
return settingsBackupAndRestoreUtilsX.RestoreSettings(appBasePath, settingsBackupAndRestoreDir);
|
||||
|
||||
@@ -48,7 +48,7 @@ public sealed class GetSettingCommandLineCommand
|
||||
var modulesSettings = new Dictionary<string, Dictionary<string, object>>();
|
||||
|
||||
var settingsAssembly = CommandLineUtils.GetSettingsAssembly();
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
|
||||
var enabledModules = SettingsRepository<GeneralSettings>.GetInstance(settingsUtils).SettingsConfig.Enabled;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace ViewModelTests
|
||||
using (var viewModel = new ColorPickerViewModel(
|
||||
ISettingsUtilsMocks.GetStubSettingsUtils<ColorPickerSettings>().Object,
|
||||
SettingsRepository<GeneralSettings>.GetInstance(ISettingsUtilsMocks.GetStubSettingsUtils<GeneralSettings>().Object),
|
||||
SettingsRepository<ColorPickerSettings>.GetInstance(new SettingsUtils()),
|
||||
SettingsRepository<ColorPickerSettings>.GetInstance(SettingsUtils.Default),
|
||||
ColorPickerIsEnabledByDefaultIPC))
|
||||
{
|
||||
Assert.IsTrue(viewModel.IsEnabled);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO.Abstractions;
|
||||
using System.Text.Json;
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
@@ -120,7 +121,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void IsEnabledShouldDisableModuleWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
Func<string, int> sendMockIPCConfigMSG = msg =>
|
||||
{
|
||||
@@ -140,7 +141,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void ShiftDragShouldSetValue2FalseWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -158,7 +159,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void OverrideSnapHotkeysShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -176,7 +177,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void MoveWindowsAcrossMonitorsShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -194,7 +195,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void MoveWindowsBasedOnPositionShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -217,7 +218,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void QuickLayoutSwitchShouldSetValue2FalseWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -235,7 +236,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void FlashZonesOnQuickSwitchShouldSetValue2FalseWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -253,7 +254,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void MakeDraggedWindowsTransparentShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -271,7 +272,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void MouseSwitchShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -289,7 +290,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void DisplayOrWorkAreaChangeMoveWindowsShouldSetValue2FalseWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -307,7 +308,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void ZoneSetChangeMoveWindowsShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -325,7 +326,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void AppLastZoneMoveWindowsShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -343,7 +344,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void OpenWindowOnActiveMonitorShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -361,7 +362,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void RestoreSizeShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -379,7 +380,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void UseCursorPosEditorStartupScreenShouldSetValue2FalseWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -397,7 +398,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void ShowOnAllMonitorsShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -415,7 +416,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void SpanZonesAcrossMonitorsShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -433,7 +434,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void OverlappingZonesAlgorithmIndexShouldSetValue2AnotherWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -451,7 +452,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void AllowChildWindowsToSnapShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -469,7 +470,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void DisableRoundCornersOnSnapShouldSetValue2TrueWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -487,7 +488,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void ZoneHighlightColorShouldSetColorValue2WhiteWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -505,7 +506,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void ZoneBorderColorShouldSetColorValue2WhiteWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -523,7 +524,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void ZoneInActiveColorShouldSetColorValue2WhiteWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -541,7 +542,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void ExcludedAppsShouldSetColorValue2WhiteWhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
@@ -559,7 +560,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void HighlightOpacityShouldSetOpacityValueTo60WhenSuccessful()
|
||||
{
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>();
|
||||
Mock<SettingsUtils> mockSettingsUtils = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// arrange
|
||||
FancyZonesViewModel viewModel = new FancyZonesViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<FancyZonesSettings>.GetInstance(mockFancyZonesSettingsUtils.Object), sendMockIPCConfigMSG, FancyZonesTestFolderName);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO.Abstractions;
|
||||
using System.Text.Json;
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
@@ -69,7 +70,7 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void IsEnabledShouldEnableModuleWhenSuccessful()
|
||||
{
|
||||
var settingsUtilsMock = new Mock<SettingsUtils>();
|
||||
var settingsUtilsMock = new Mock<SettingsUtils>(new FileSystem(), null);
|
||||
|
||||
// Assert
|
||||
// Initialize mock function of sending IPC message.
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||
|
||||
static HotkeyConflictIgnoreHelper()
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
_generalSettingsRepository = SettingsRepository<GeneralSettings>.GetInstance(_settingsUtils);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
var settingValue = cmdArgs[3];
|
||||
try
|
||||
{
|
||||
SetSettingCommandLineCommand.Execute(settingName, settingValue, new SettingsUtils());
|
||||
SetSettingCommandLineCommand.Execute(settingName, settingValue, SettingsUtils.Default);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -151,7 +151,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
{
|
||||
using (var settings = JsonDocument.Parse(File.ReadAllText(ipcFileName)))
|
||||
{
|
||||
SetAdditionalSettingsCommandLineCommand.Execute(moduleName, settings, new SettingsUtils());
|
||||
SetAdditionalSettingsCommandLineCommand.Execute(moduleName, settings, SettingsUtils.Default);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -357,7 +357,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static ISettingsUtils settingsUtils = new SettingsUtils();
|
||||
private static ISettingsUtils settingsUtils = SettingsUtils.Default;
|
||||
private static ThemeService themeService = new ThemeService(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils));
|
||||
|
||||
public static ThemeService ThemeService => themeService;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Microsoft.PowerToys.Settings.UI.SettingsXAML.Controls.Dashboard
|
||||
|
||||
public ShortcutConflictWindow()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new ShortcutConflictViewModel(
|
||||
settingsUtils,
|
||||
SettingsRepository<GeneralSettings>.GetInstance(settingsUtils),
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new AllAppsViewModel(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), Views.ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
|
||||
public LaunchPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new LauncherViewModel(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), Views.ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
|
||||
break;
|
||||
case ModuleType.EnvironmentVariables: // Launch Environment Variables
|
||||
{
|
||||
bool launchAdmin = SettingsRepository<EnvironmentVariablesSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator;
|
||||
bool launchAdmin = SettingsRepository<EnvironmentVariablesSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.LaunchAdministrator;
|
||||
string eventName = !App.IsElevated && launchAdmin
|
||||
? Constants.ShowEnvironmentVariablesAdminSharedEvent()
|
||||
: Constants.ShowEnvironmentVariablesSharedEvent();
|
||||
@@ -74,7 +74,7 @@ namespace Microsoft.PowerToys.Settings.UI.Flyout
|
||||
|
||||
case ModuleType.Hosts: // Launch Hosts
|
||||
{
|
||||
bool launchAdmin = SettingsRepository<HostsSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator;
|
||||
bool launchAdmin = SettingsRepository<HostsSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.LaunchAdministrator;
|
||||
string eventName = !App.IsElevated && launchAdmin
|
||||
? Constants.ShowHostsAdminSharedEvent()
|
||||
: Constants.ShowHostsSharedEvent();
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
// open main window
|
||||
ShellPage.SetUpdatingGeneralSettingsCallback((ModuleType moduleType, bool isEnabled) =>
|
||||
{
|
||||
SettingsRepository<GeneralSettings> repository = SettingsRepository<GeneralSettings>.GetInstance(new SettingsUtils());
|
||||
SettingsRepository<GeneralSettings> repository = SettingsRepository<GeneralSettings>.GetInstance(SettingsUtils.Default);
|
||||
GeneralSettings generalSettingsConfig = repository.SettingsConfig;
|
||||
bool needToUpdate = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType) != isEnabled;
|
||||
|
||||
|
||||
@@ -35,9 +35,9 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
AdvancedPasteUIHotkeyControl.Keys = SettingsRepository<AdvancedPasteSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.AdvancedPasteUIShortcut.GetKeysList();
|
||||
PasteAsPlainTextHotkeyControl.Keys = SettingsRepository<AdvancedPasteSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.PasteAsPlainTextShortcut.GetKeysList();
|
||||
PasteAsMarkdownHotkeyControl.Keys = SettingsRepository<AdvancedPasteSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.PasteAsMarkdownShortcut.GetKeysList();
|
||||
AdvancedPasteUIHotkeyControl.Keys = SettingsRepository<AdvancedPasteSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.AdvancedPasteUIShortcut.GetKeysList();
|
||||
PasteAsPlainTextHotkeyControl.Keys = SettingsRepository<AdvancedPasteSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.PasteAsPlainTextShortcut.GetKeysList();
|
||||
PasteAsMarkdownHotkeyControl.Keys = SettingsRepository<AdvancedPasteSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.PasteAsMarkdownShortcut.GetKeysList();
|
||||
|
||||
// TODO(stefan): Check how to remove additional space if item is set to Collapsed.
|
||||
if (PasteAsMarkdownHotkeyControl.Keys.Count > 0)
|
||||
@@ -45,7 +45,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
PasteAsMarkdownHotkeyControl.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
|
||||
}
|
||||
|
||||
PasteAsJsonHotkeyControl.Keys = SettingsRepository<AdvancedPasteSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.PasteAsJsonShortcut.GetKeysList();
|
||||
PasteAsJsonHotkeyControl.Keys = SettingsRepository<AdvancedPasteSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.PasteAsJsonShortcut.GetKeysList();
|
||||
if (PasteAsJsonHotkeyControl.Keys.Count > 0)
|
||||
{
|
||||
PasteAsJsonHotkeyControl.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
HotkeyControl.Keys = SettingsRepository<AlwaysOnTopSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.Hotkey.Value.GetKeysList();
|
||||
HotkeyControl.Keys = SettingsRepository<AlwaysOnTopSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.Hotkey.Value.GetKeysList();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
ColorPickerSettings settings = new SettingsUtils().GetSettingsOrDefault<ColorPickerSettings, ColorPickerSettingsVersion1>(ColorPickerSettings.ModuleName, settingsUpgrader: ColorPickerSettings.UpgradeSettings);
|
||||
ColorPickerSettings settings = SettingsUtils.Default.GetSettingsOrDefault<ColorPickerSettings, ColorPickerSettingsVersion1>(ColorPickerSettings.ModuleName, settingsUpgrader: ColorPickerSettings.UpgradeSettings);
|
||||
|
||||
HotkeyControl.Keys = settings.Properties.ActivationShortcut.GetKeysList();
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
ReparentHotkeyControl.Keys = SettingsRepository<CropAndLockSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ReparentHotkey.Value.GetKeysList();
|
||||
ThumbnailHotkeyControl.Keys = SettingsRepository<CropAndLockSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ThumbnailHotkey.Value.GetKeysList();
|
||||
ReparentHotkeyControl.Keys = SettingsRepository<CropAndLockSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.ReparentHotkey.Value.GetKeysList();
|
||||
ThumbnailHotkeyControl.Keys = SettingsRepository<CropAndLockSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.ThumbnailHotkey.Value.GetKeysList();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
|
||||
private void Launch_EnvironmentVariables_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
bool launchAdmin = SettingsRepository<EnvironmentVariablesSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator;
|
||||
bool launchAdmin = SettingsRepository<EnvironmentVariablesSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.LaunchAdministrator;
|
||||
string eventName = !App.IsElevated && launchAdmin
|
||||
? Constants.ShowEnvironmentVariablesAdminSharedEvent()
|
||||
: Constants.ShowEnvironmentVariablesSharedEvent();
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
HotkeyControl.Keys = SettingsRepository<FancyZonesSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.FancyzonesEditorHotkey.Value.GetKeysList();
|
||||
HotkeyControl.Keys = SettingsRepository<FancyZonesSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.FancyzonesEditorHotkey.Value.GetKeysList();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
|
||||
private void Launch_Hosts_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
bool launchAdmin = SettingsRepository<HostsSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.LaunchAdministrator;
|
||||
bool launchAdmin = SettingsRepository<HostsSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.LaunchAdministrator;
|
||||
string eventName = !App.IsElevated && launchAdmin
|
||||
? Constants.ShowHostsAdminSharedEvent()
|
||||
: Constants.ShowHostsSharedEvent();
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
HotkeyActivation.Keys = SettingsRepository<MeasureToolSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.GetKeysList();
|
||||
HotkeyActivation.Keys = SettingsRepository<MeasureToolSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.ActivationShortcut.GetKeysList();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
|
||||
@@ -21,10 +21,10 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.Overview]);
|
||||
DataContext = ViewModel;
|
||||
|
||||
FancyZonesHotkeyControl.Keys = SettingsRepository<FancyZonesSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.FancyzonesEditorHotkey.Value.GetKeysList();
|
||||
RunHotkeyControl.Keys = SettingsRepository<PowerLauncherSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.OpenPowerLauncher.GetKeysList();
|
||||
ColorPickerHotkeyControl.Keys = SettingsRepository<ColorPickerSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.GetKeysList();
|
||||
AlwaysOnTopHotkeyControl.Keys = SettingsRepository<AlwaysOnTopSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.Hotkey.Value.GetKeysList();
|
||||
FancyZonesHotkeyControl.Keys = SettingsRepository<FancyZonesSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.FancyzonesEditorHotkey.Value.GetKeysList();
|
||||
RunHotkeyControl.Keys = SettingsRepository<PowerLauncherSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.OpenPowerLauncher.GetKeysList();
|
||||
ColorPickerHotkeyControl.Keys = SettingsRepository<ColorPickerSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.ActivationShortcut.GetKeysList();
|
||||
AlwaysOnTopHotkeyControl.Keys = SettingsRepository<AlwaysOnTopSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.Hotkey.Value.GetKeysList();
|
||||
}
|
||||
|
||||
private void SettingsLaunchButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
HotkeyControl.Keys = SettingsRepository<PeekSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.GetKeysList();
|
||||
HotkeyControl.Keys = SettingsRepository<PeekSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.ActivationShortcut.GetKeysList();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
HotkeyControl.Keys = SettingsRepository<PowerOcrSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.GetKeysList();
|
||||
HotkeyControl.Keys = SettingsRepository<PowerOcrSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.ActivationShortcut.GetKeysList();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
|
||||
HotkeyControl.Keys = SettingsRepository<PowerLauncherSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.OpenPowerLauncher.GetKeysList();
|
||||
HotkeyControl.Keys = SettingsRepository<PowerLauncherSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.OpenPowerLauncher.GetKeysList();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
|
||||
public ObservableCollection<OobePowerToysModule> Modules { get; }
|
||||
|
||||
private static ISettingsUtils settingsUtils = new SettingsUtils();
|
||||
private static ISettingsUtils settingsUtils = SettingsUtils.Default;
|
||||
|
||||
/* NOTE: Experimentation for OOBE is currently turned off on server side. Keeping this code in a comment to allow future experiments.
|
||||
private bool ExperimentationToggleSwitchEnabled { get; set; } = true;
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
var settingsProperties = SettingsRepository<ShortcutGuideSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties;
|
||||
var settingsProperties = SettingsRepository<ShortcutGuideSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties;
|
||||
|
||||
if ((bool)settingsProperties.UseLegacyPressWinKeyBehavior.Value)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
HotkeyControl.Keys = SettingsRepository<WorkspacesSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.Hotkey.Value.GetKeysList();
|
||||
HotkeyControl.Keys = SettingsRepository<WorkspacesSettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.Hotkey.Value.GetKeysList();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
|
||||
public AdvancedPastePage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new AdvancedPasteViewModel(
|
||||
settingsUtils,
|
||||
SettingsRepository<GeneralSettings>.GetInstance(settingsUtils),
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
|
||||
public AlwaysOnTopPage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new AlwaysOnTopViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<AlwaysOnTopSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
_fileSystem = new FileSystem();
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_settingsUtils = SettingsUtils.Default;
|
||||
_sendConfigMsg = ShellPage.SendDefaultIPCMessage;
|
||||
|
||||
ViewModel = new AwakeViewModel();
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
|
||||
public CmdPalPage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new CmdPalViewModel(
|
||||
settingsUtils,
|
||||
SettingsRepository<GeneralSettings>.GetInstance(settingsUtils),
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
|
||||
public ColorPickerPage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new ColorPickerViewModel(
|
||||
settingsUtils,
|
||||
SettingsRepository<GeneralSettings>.GetInstance(settingsUtils),
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
|
||||
public CropAndLockPage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new CropAndLockViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<CropAndLockSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
public DashboardPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
|
||||
ViewModel = new DashboardViewModel(
|
||||
SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
public EnvironmentVariablesPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new EnvironmentVariablesViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<EnvironmentVariablesSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, App.IsElevated);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
public FancyZonesPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new FancyZonesViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<FancyZonesSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
Loaded += (s, e) => ViewModel.OnPageLoaded();
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
|
||||
public FileLocksmithPage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new FileLocksmithViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
|
||||
// Load string resources
|
||||
var loader = Helpers.ResourceLoaderInstance.ResourceLoader;
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
|
||||
Action stateUpdatingAction = () =>
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
public HostsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new HostsViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<HostsSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, App.IsElevated);
|
||||
BackupsCountInputSettingsCard.Header = ResourceLoaderInstance.ResourceLoader.GetString("Hosts_Backup_CountInput_Header");
|
||||
BackupsCountInputSettingsCard.Description = ResourceLoaderInstance.ResourceLoader.GetString("Hosts_Backup_CountInput_Description");
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
public ImageResizerPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
var resourceLoader = ResourceLoaderInstance.ResourceLoader;
|
||||
Func<string, string> loader = resourceLoader.GetString;
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
|
||||
public KeyboardManagerPage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new KeyboardManagerViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, FilterRemapKeysList);
|
||||
|
||||
watcher = Helper.GetFileWatcher(
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
|
||||
public LightSwitchPage()
|
||||
{
|
||||
this.settingsUtils = new SettingsUtils();
|
||||
this.settingsUtils = SettingsUtils.Default;
|
||||
this.sendConfigMsg = ShellPage.SendDefaultIPCMessage;
|
||||
|
||||
this.generalSettingsRepository = SettingsRepository<GeneralSettings>.GetInstance(this.settingsUtils);
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
|
||||
public MeasureToolPage()
|
||||
{
|
||||
var settingsUtils = new SettingsUtils();
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new MeasureToolViewModel(
|
||||
settingsUtils,
|
||||
SettingsRepository<GeneralSettings>.GetInstance(settingsUtils),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user