mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-06 04:17:04 +01:00
Compare commits
21 Commits
leilzh/gpo
...
leilzh/rel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e6c81f955 | ||
|
|
67a15d2b1b | ||
|
|
77265b9df6 | ||
|
|
693a131036 | ||
|
|
fc87f03fd5 | ||
|
|
9850a19aac | ||
|
|
9c3df634b4 | ||
|
|
13731e8af1 | ||
|
|
ef6f4b2c3d | ||
|
|
336cdaff9b | ||
|
|
447118ab70 | ||
|
|
7455d63bb5 | ||
|
|
bb6b36af3f | ||
|
|
3ebf0f741a | ||
|
|
e8e1431e15 | ||
|
|
2d35fd8530 | ||
|
|
13d950a40a | ||
|
|
3eb8f96f3e | ||
|
|
11218ea4d8 | ||
|
|
8258f2ab6f | ||
|
|
4ad951eb56 |
6
.github/actions/spell-check/expect.txt
vendored
6
.github/actions/spell-check/expect.txt
vendored
@@ -49,6 +49,7 @@ ALPHATYPE
|
||||
AModifier
|
||||
amr
|
||||
ANDSCANS
|
||||
animatedvisuals
|
||||
Animnate
|
||||
ANull
|
||||
AOC
|
||||
@@ -1314,6 +1315,7 @@ PRODUCTVERSION
|
||||
Progman
|
||||
programdata
|
||||
projectname
|
||||
projitems
|
||||
PROPERTYKEY
|
||||
Propset
|
||||
PROPVARIANT
|
||||
@@ -1393,6 +1395,7 @@ regkey
|
||||
regroot
|
||||
regsvr
|
||||
REINSTALLMODE
|
||||
releaseblog
|
||||
reloadable
|
||||
Relogger
|
||||
remappings
|
||||
@@ -1501,6 +1504,7 @@ SETRULES
|
||||
SETSCREENSAVEACTIVE
|
||||
SETSTICKYKEYS
|
||||
SETTEXT
|
||||
settingscard
|
||||
SETTINGCHANGE
|
||||
SETTINGSCHANGED
|
||||
settingsheader
|
||||
@@ -1758,11 +1762,13 @@ transcodetomp
|
||||
transicc
|
||||
TRAYMOUSEMESSAGE
|
||||
triaging
|
||||
Tru
|
||||
trl
|
||||
trx
|
||||
tsa
|
||||
tskill
|
||||
tstoi
|
||||
tweakable
|
||||
TWF
|
||||
tymed
|
||||
TYPEKEYBOARD
|
||||
|
||||
4
.github/actions/spell-check/patterns.txt
vendored
4
.github/actions/spell-check/patterns.txt
vendored
@@ -260,3 +260,7 @@ Process Process
|
||||
# ZoomIt menu items with accelerator keys
|
||||
E&xit
|
||||
St&yle
|
||||
|
||||
# This matches a relative clause where the relative pronoun "that" is omitted.
|
||||
# Example: "Gets or sets the window the TitleBar should configure."
|
||||
\bthe\s+\w+\s+the\b
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -355,5 +355,8 @@ src/common/Telemetry/*.etl
|
||||
# MSBuildCache
|
||||
/MSBuildCacheLogs/
|
||||
|
||||
# PowerToys Settings generated search index (legacy location) and obj outputs
|
||||
/src/settings-ui/Settings.UI/Assets/Settings/search.index.json
|
||||
|
||||
# PowerToysInstaller Build Temp Files
|
||||
installer/*/*.wxs.bk
|
||||
installer/*/*.wxs.bk
|
||||
@@ -28,6 +28,8 @@
|
||||
"PowerToys.GPOWrapperProjection.dll",
|
||||
"PowerToys.AllExperiments.dll",
|
||||
|
||||
"Common.Search.dll",
|
||||
|
||||
"PowerToys.AlwaysOnTop.exe",
|
||||
"PowerToys.AlwaysOnTopModuleInterface.dll",
|
||||
|
||||
@@ -280,6 +282,7 @@
|
||||
"Mono.Cecil.Pdb.dll",
|
||||
"Mono.Cecil.Rocks.dll",
|
||||
"Newtonsoft.Json.dll",
|
||||
"CommunityToolkit.WinUI.Controls.TitleBar.dll",
|
||||
|
||||
"NLog.dll",
|
||||
"HtmlAgilityPack.dll",
|
||||
|
||||
@@ -712,6 +712,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Preview.BgcodePreviewHandle
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Preview.BgcodeThumbnailProvider.UnitTests", "src\modules\previewpane\UnitTests-BgcodeThumbnailProvider\Preview.BgcodeThumbnailProvider.UnitTests.csproj", "{61CBF221-9452-4934-B685-146285E080D7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Search", "src\common\Common.Search\Common.Search.csproj", "{38F187B2-6638-5A40-072F-DBE5E54070A0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Settings.UI.XamlIndexBuilder", "src\settings-ui\Settings.UI.XamlIndexBuilder\Settings.UI.XamlIndexBuilder.csproj", "{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MouseUtils.UITests", "src\modules\MouseUtils\MouseUtils.UITests\MouseUtils.UITests.csproj", "{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workspaces.Editor.UITests", "src\modules\Workspaces\WorkspacesEditorUITest\Workspaces.Editor.UITests.csproj", "{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}"
|
||||
@@ -2707,6 +2711,30 @@ Global
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}.Release|x64.ActiveCfg = Release|x64
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9}.Release|x64.Build.0 = Release|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Debug|x64.Build.0 = Debug|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|x64.ActiveCfg = Release|x64
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0}.Release|x64.Build.0 = Release|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE}.Release|x64.Build.0 = Release|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.Build.0 = Debug|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.ActiveCfg = Release|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.Build.0 = Release|x64
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2900,6 +2928,7 @@ Global
|
||||
{D1D6BC88-09AE-4FB4-AD24-5DED46A791DD} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9} = {264B412F-DB8B-4CF8-A74B-96998B183045}
|
||||
{1AFB6476-670D-4E80-A464-657E01DFF482} = {557C4636-D7E1-4838-A504-7D19B725EE95}
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
@@ -3167,6 +3196,8 @@ Global
|
||||
{61CBF221-9452-4934-B685-146285E080D7} = {6B01F1CF-F4DB-48B5-BFE7-0BF576C1D704}
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A1} = {2C318EC3-BA86-4372-B1BC-DB0F33C208B2}
|
||||
{43E779F3-D83C-48B1-BA8D-1912DBD76FC9} = {68328142-5B31-4715-BCBB-7B6345EE0971}
|
||||
{38F187B2-6638-5A40-072F-DBE5E54070A0} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{DA0744BC-E822-680E-9CEB-D0FBA903A8EE} = {C3081D9A-1586-441A-B5F4-ED815B3719C1}
|
||||
{2CF78CF7-8FEB-4BE1-9591-55FA25B48FC6} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{14AFD976-B4D2-49D0-9E6C-AA93CC061B8A} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{9D3F3793-EFE3-4525-8782-238015DABA62} = {66E1534A-1587-42B2-912F-45C994D32904}
|
||||
|
||||
199
README.md
199
README.md
@@ -35,19 +35,19 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
Go to the [Microsoft PowerToys GitHub releases page][github-release-link] and click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user.
|
||||
|
||||
<!-- items that need to be updated release to release -->
|
||||
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.94%22
|
||||
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.93%22
|
||||
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysUserSetup-0.93.0-x64.exe
|
||||
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysUserSetup-0.93.0-arm64.exe
|
||||
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysSetup-0.93.0-x64.exe
|
||||
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysSetup-0.93.0-arm64.exe
|
||||
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.95%22
|
||||
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.94%22
|
||||
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysUserSetup-0.94.0-x64.exe
|
||||
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysUserSetup-0.94.0-arm64.exe
|
||||
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysSetup-0.94.0-x64.exe
|
||||
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysSetup-0.94.0-arm64.exe
|
||||
|
||||
| Description | Filename |
|
||||
|----------------|----------|
|
||||
| Per user - x64 | [PowerToysUserSetup-0.93.0-x64.exe][ptUserX64] |
|
||||
| Per user - ARM64 | [PowerToysUserSetup-0.93.0-arm64.exe][ptUserArm64] |
|
||||
| Machine wide - x64 | [PowerToysSetup-0.93.0-x64.exe][ptMachineX64] |
|
||||
| Machine wide - ARM64 | [PowerToysSetup-0.93.0-arm64.exe][ptMachineArm64] |
|
||||
| Per user - x64 | [PowerToysUserSetup-0.94.0-x64.exe][ptUserX64] |
|
||||
| Per user - ARM64 | [PowerToysUserSetup-0.94.0-arm64.exe][ptUserArm64] |
|
||||
| Machine wide - x64 | [PowerToysSetup-0.94.0-x64.exe][ptMachineX64] |
|
||||
| Machine wide - ARM64 | [PowerToysSetup-0.94.0-arm64.exe][ptMachineArm64] |
|
||||
|
||||
This is our preferred method.
|
||||
|
||||
@@ -93,118 +93,145 @@ For guidance on developing for PowerToys, please read the [developer docs](./doc
|
||||
|
||||
Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on.
|
||||
|
||||
### 0.93 - Aug 2025 Update
|
||||
### 0.94 - Sep 2025 Update
|
||||
|
||||
In this release, we focused on new features, stability, optimization improvements, and automation.
|
||||
|
||||
For an in-depth look at the latest changes, visit the [release blog](https://aka.ms/powertoys-releaseblog).
|
||||
|
||||
**✨Highlights**
|
||||
|
||||
- PowerToys settings debuts a modern, card-based dashboard with clearer descriptions and faster navigation for a streamlined user experience.
|
||||
- Command Palette had over 99 issues resolved, including bringing back Clipboard History, adding context menu shortcuts, pinning favorite apps, and supporting history in Run.
|
||||
- Command Palette reduced its startup memory usage by ~15%, load time by ~40%, built-in extensions loading time by ~70%, and installation size by ~55%—all due to using the full Ahead-of-Time (AOT) compilation mode in Windows App SDK.
|
||||
- Peek now supports instant previews and embedded thumbnails for Binary G-code (.bgcode) 3D printing files, making it easy to inspect models at a glance. Thanks [@pedrolamas](https://github.com/pedrolamas)!
|
||||
- Mouse Utilities introduces a new spotlight highlighting mode that dims the screen and draws attention to your cursor, perfect for presentations.
|
||||
- Test coverage improvements for multiple PowerToys modules including Command Palette, Advanced Paste, Peek, Text Extractor, and PowerRename — ensuring better reliability and quality, with over 600 new unit tests (mostly for Command Palette) and doubled UI automation coverage.
|
||||
- PowerToys Settings added a Settings search with fuzzy matching, suggestions, a results page, and UX polish to make finding options faster.
|
||||
- A comprehensive hotkey conflict detection system was introduced in Settings to surface and help resolve conflicting shortcuts. Note that the default hotkey settings (Win+Ctrl+Shift+T, Win+Ctrl+V, Win+Ctrl+T, Win+Shift+T) may overlap with existing Windows system shortcuts. This is expected. You can resolve the conflict by assigning different hotkeys.
|
||||
- Mouse Utilities added a “Gliding cursor” accessibility feature to Mouse Pointer Crosshairs for single‑button cursor movement and clicking. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
|
||||
- The installer was upgraded to WiX 5 after WiX 3 reached end-of-life; this move improved installer security, reliability, and community support.
|
||||
- Tons of bug fixes and improvements for Command Palette, including visual updates and new support for filters on ListPages (handy for extension developers).
|
||||
- Hosts Editor now has a “No leading spaces” option so active host entries can start at column 0 even if others are disabled. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
|
||||
- Context menu registration was moved from the installer to runtime to avoid loading disabled modules (runtime registrations).
|
||||
- Quick Accent now supports Maltese, and frequently used accents appear first (and are remembered across sessions). Thanks [@rovercoder](https://github.com/rovercoder)! [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
|
||||
### Always On Top
|
||||
|
||||
- Fixed the border hover cursor so it shows the arrow instead of the wait cursor. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
|
||||
### Command Palette
|
||||
|
||||
- Ensured screen readers are notified when the selected item in the list changes for better accessibility.
|
||||
- Fixed command title changes not being properly notified to screen readers. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Made icon controls excluded from keyboard navigation by default for better accessibility. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Improved UI design with better text sizing and alignment.
|
||||
- Fixed keyboard shortcuts to work better in text boxes and context menus.
|
||||
- Added right-click context menus with critical command styling and separators.
|
||||
- Improved various context menu issues, improving item selection, handling of long titles, search bar text scaling, initial item behavior, and primary button functionality.
|
||||
- Fixed context menu crashes with better type handling.
|
||||
- Fixed "Reload" command to work with both uppercase and lowercase letters.
|
||||
- Added mouse back button support for easier navigation. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed Alt+Left Arrow navigation not working when search box contains text. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Updated back button tooltip to show keyboard shortcut information. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed Command Palette window not appearing properly when activated. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed Command Palette window staying hidden from taskbar after File Explorer restarts. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed window focus not returning to previous app properly.
|
||||
- Fixed Command Palette window to always appear on top when shown and move to bottom when hidden. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed window hiding to properly work on UI thread. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed crashes and improved stability with better synchronization of Command list updates. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Improved extension disposal with better error handling to prevent crashes. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Improved stability by fixing a UI threading issue when loading more results, preventing possible crashes and ensuring the loading state resets if loading fails. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Enhanced icon loading stability with better exception handling. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added thread safety to recent commands to prevent crashes. Thanks [@MaoShengelia](https://github.com/MaoShengelia)!
|
||||
- Fixed acrylic (frosted glass) system backdrop display issues by ensuring proper UI thread handling. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Applied single-click activation only to pointer input; keyboard always activates immediately. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Let context menus open at the cursor by removing window-bound constraints. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Made error messages clearer with timestamps, HRESULTs, and full details for easier diagnosis. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Prevented crashes and improved robustness when updating providers without commands. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Ensured the Settings window reliably comes to the front when opened. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Replaced the Clipboard History icon with a colorful Fluent icon. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Hardened ContentIcon to avoid duplicate parenting and improve diagnostics. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Standardized null checks using C# pattern matching for safer behavior.
|
||||
- Improved accessibility by focusing the activation shortcut dialog and making text reachable. Thanks [@chatasweetie](https://github.com/chatasweetie)!
|
||||
- Moved the extension SDK to a stable Windows SDK and cleaned up message namespaces.
|
||||
- Added path shortcuts: ~ to home, and / or \\ to system root, plus UNC support. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Fixed a race in cancellation handling to avoid InvalidOperationException. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Aligned separator styling with WinUI 3 for consistent visuals. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added ARM64 PDBs to the Extensions SDK NuGet for better debugging.
|
||||
- Added single-select filters to DynamicListPage and updated Windows Services sample.
|
||||
- Updated main page placeholder text to better describe what can be searched. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Removed explicit WinAppSDK/WebView2 dependencies from toolkit and API. Thanks [@rluengen](https://github.com/rluengen)!
|
||||
- Added a local keyboard hook to handle the GoBack key reliably. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Propagated alias changes safely and resolved conflicts across view models.
|
||||
- Allowed providers to override Dispose with a virtual method.
|
||||
- Fixed memory leaks by cleaning up removed or cancelled list items.
|
||||
- Sorted DateTime extension results by relevance for better usability.
|
||||
- Reduced search text “jiggling” by avoiding redundant change notifications.
|
||||
- Centralized automation notifications in a UIHelper for better accessibility. Thanks [@chatasweetie](https://github.com/chatasweetie)!
|
||||
- Preserved Adaptive Card action types during trimming via DynamicDependency.
|
||||
- Added an acrylic backdrop and refined styling to the context menu. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Prevented disposed pages and Settings windows from handling stale messages. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Made the extension API easier to evolve without breaking clients.
|
||||
- Added “evil” sample pages to help reproduce tricky bugs.
|
||||
- Fixed WinGet trim-safety issues by replacing LINQ with manual iteration.
|
||||
- Cancelled stale list fetches to avoid older results overwriting newer ones in CmdPal.
|
||||
|
||||
### Command Palette extensions
|
||||
|
||||
- Added settings to each provider to control which fallback commands are enabled. Thanks [@jiripolasek](https://github.com/jiripolasek)! for fixing a regression in this feature.
|
||||
- Added sample code showing how Command Palette extensions can track when their pages are loaded or unloaded. [Check it out here](./src/modules/cmdpal/ext/SamplePagesExtension/OnLoadPage.cs).
|
||||
- Fixed *Calculator* to accept regular spaces in numbers that use space separators. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
- Added a new setting to *Calculator* to make "Copy" the primary button (replacing “Save”) and enable "Close on Enter", streamlining the workflow. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
- Improved *Apps* indexing error handling and removed obsolete code. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Prevented apps from showing in search when the *Apps* extension is disabled. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added ability to pin/unpin *Apps* using Ctrl+P shortcut.
|
||||
- Added keyboard shortcuts to the *Apps* context menu items for faster access.
|
||||
- Added all file context menu options to the *Apps* items context menu, making all file actions available there for better functionality.
|
||||
- Streamlined All *Apps* extension settings by removing redundant descriptions, making the UI clearer.
|
||||
- Added command history to the *Run* page for easier access to previous commands.
|
||||
- Fixed directory path handling in *Run* fallback for better file navigation.
|
||||
- Fixed URL fallback item hiding properly in *Web Search* extension when search query becomes invalid. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added proper empty state message for *Web Search* extension when no results found. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added fallback command to *Windows Settings* extension for better search results.
|
||||
- Re-enabled *Clipboard History* feature with proper window handling.
|
||||
- Improved *Add Bookmark* extension to automatically detect file, folder, or URL types without manual input.
|
||||
- Updated terminology from "Kill process" to "End task" in *Window Walker* for consistency with Windows.
|
||||
- Fixed minor grammar error in SamplePagesExtension code comments. Thanks [@purofle](https://github.com/purofle)!
|
||||
- Improved empty states and ranking logic for multiple extensions. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Added app icons to the All Apps "Run" context command when available.
|
||||
- Restored missing builtin icons by standardizing extension dependencies.
|
||||
- Unblocked local deployment by adding WinAppSDK to two sample extensions.
|
||||
|
||||
### Hosts File Editor
|
||||
|
||||
- Added a "No leading spaces" option so active hosts entries can start at column 0 even when others are disabled. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
|
||||
|
||||
### Image Resizer
|
||||
|
||||
- Fixed Image Resizer localization by installing satellite resources under the WinUI 3 apps culture path.
|
||||
|
||||
### Mouse Utilities
|
||||
|
||||
- Added a new spotlight highlighting mode that creates a large transparent circle around your cursor with a backdrop effect, providing an alternative to the traditional circle highlight. Perfect for presentations where you want to focus attention on a specific area while dimming the rest of the screen.
|
||||
- Introduced "Gliding cursor" to control the pointer and click with a single hotkey for better accessibility. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
|
||||
|
||||
### Mouse Without Borders
|
||||
|
||||
- Blocked Easy Mouse from switching machines during fullscreen apps, with an allow-list for exceptions. Thanks [@dot-tb](https://github.com/dot-tb)!
|
||||
|
||||
### Peek
|
||||
|
||||
- Added preview and thumbnail support for Binary G-code (.bgcode) files used in 3D printing. You can now see embedded thumbnails and preview these compressed 3D printing files directly in Peek and File Explorer. Thanks [@pedrolamas](https://github.com/pedrolamas)!
|
||||
- Added Visual Studio shared project file types to XML preview and fixed bgcode handler registration. Thanks [@rezanid](https://github.com/rezanid)!
|
||||
- Fixes bgcode preview handler registration and events for reliable previews. Thanks [@pedrolamas](https://github.com/pedrolamas)!
|
||||
|
||||
### PowerRename
|
||||
|
||||
- Changed the Explorer accelerator key to PowErRename to avoid clashing with the New menu. Thanks [@aaron-ni](https://github.com/aaron-ni)!
|
||||
|
||||
### Quick Accent
|
||||
|
||||
- Added Vietnamese language support to Quick Accent, mappings for Vietnamese vowels (a, e, i, o, u, y) and the letter d. Thanks [@octastylos-pseudodipteros](https://github.com/octastylos-pseudodipteros)!
|
||||
- Remembered character usage across sessions so frequently used accents appear first. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Added Maltese language support with specific characters and the Euro symbol. Thanks [@rovercoder](https://github.com/rovercoder)!
|
||||
- Reduced GPU usage issues by making the window Topmost only when the picker is visible. Thanks [@daverayment](https://github.com/daverayment)!
|
||||
|
||||
### Settings
|
||||
|
||||
- Completely redesigned the Settings dashboard with a modern card-based layout featuring organized sections for quick actions and shortcuts overview, replacing the old module list.
|
||||
- Rewrote setting descriptions to be more concise and follow Windows writing style guidelines, making them easier to understand.
|
||||
- Improved formatting and readability of release notes in the "What's New" section with better typography and spacing.
|
||||
- Added missing deep link support for various settings pages (Peek, Quick Accent, PowerToys Run, etc.) so you can jump directly to specific settings.
|
||||
- Resolved an issue where the settings page header would drift away from its position when resizing the settings window.
|
||||
- Resolved a settings crash related to incompatible property names in ZoomIt configuration.
|
||||
- Added telemetry to track usage of the new shortcut conflict detection workflow.
|
||||
- Moved the shutdown action from the title bar to a footer menu item with confirmation. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Implemented comprehensive hotkey conflict detection with a dedicated resolution dialog.
|
||||
- Added branded visuals for Office and Copilot keys in the KeyVisual control.
|
||||
- Introduced Settings search with fuzzy matching and navigation to specific controls.
|
||||
- Corrected Spanish localization so product names like Awake remain in English across Settings and OOBE.
|
||||
- Simplified the Advanced Paste description in Settings for quicker reading and consistent capitalization. Thanks [@OldUser101](https://github.com/OldUser101)!
|
||||
- Localized conflict messages in the conflict window and dialog.
|
||||
|
||||
### Installer
|
||||
|
||||
- Upgraded the installer to WiX 5 with silent "Files in Use" handling for smoother winget installs.
|
||||
- Switched Win10 context menu modules to runtime registration and added cleanup on uninstall to avoid stale entries.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Added detailed step-by-step instructions for first-time developers building the Command Palette module, including prerequisites and Visual Studio setup guidance. Thanks [@chatasweetie](https://github.com/chatasweetie)!
|
||||
- **Fixed Broken SDK Link**: Corrected a broken markdown link in the Command Palette SDK README that was pointing to an incorrect directory path. Thanks [@ChrisGuzak](https://github.com/ChrisGuzak)!
|
||||
- Added documentation for the "Open With Cursor" plugin that enables opening Visual Studio and VS Code recent files using Cursor AI. Thanks [@VictorNoxx](https://github.com/VictorNoxx)!
|
||||
- Added documentation for two new community plugins - Hotkeys plugin for creating custom keyboard shortcuts, and RandomGen plugin for generating random data like passwords, colors, and placeholder text. Thanks [@ruslanlap](https://github.com/ruslanlap)!
|
||||
- Adds docs for building the installer locally and testing winget installs.
|
||||
- Fixed a broken style guide link in developer documentation. Thanks [@denizmaral](https://github.com/denizmaral)!
|
||||
|
||||
### Development
|
||||
|
||||
- Updated .NET libraries to 9.0.8 for performance and security. Thanks [@snickler](https://github.com/snickler)!
|
||||
- Updated the spell check system to version 0.0.25 with better GitHub integration and SARIF reporting, plus fixed numerous spelling errors throughout the codebase including property names and documentation. Thanks [@jsoref](https://github.com/jsoref)!
|
||||
- Cleaned up spelling check configuration to eliminate false positives and excessive noise that was appearing in every pull request, making the development process smoother.
|
||||
- Replaced NuGet feed with Azure Artifacts for better package management.
|
||||
- Implemented configurable UI test pipeline that can use pre-built official releases instead of building everything from scratch, reducing test execution time from 2+ hours.
|
||||
- Replaced brittle pixel-by-pixel image comparison with perceptual hash (pHash) technology that's more robust to minor rendering differences - no more test failures due to anti-aliasing or compression artifacts.
|
||||
- Reduced CI/fuzzing/UI test timeouts from 4 hours to 90 minutes, dramatically improving developer feedback loops and preventing long waits when builds get stuck.
|
||||
- Standardized test project naming across the entire codebase and improved pipeline result identification by adding platform/install mode context to test run titles. Thanks [@khmyznikov](https://github.com/khmyznikov)!
|
||||
- Added comprehensive UI test suites for multiple PowerToys modules including Command Palette, Advanced Paste, Peek, Text Extractor, and PowerRename - ensuring better reliability and quality.
|
||||
- Enhanced UI test automation with command-line argument support, better session management, and improved element location methods using pattern matching to avoid failures from minor differences in exact matches.
|
||||
- Excluded test and coverage DLLs from BinSkim scans to cut false positives and speed up security analysis.
|
||||
- Simplified NOTICE maintenance by removing version numbers and filtering out Microsoft/System packages.
|
||||
- Improved NuGet dependency validation to prevent package downgrades and catch issues during restore.
|
||||
- Updated UTF.Unknown to a modern version to improve compatibility without breaking changes. Thanks [@304NotModified](https://github.com/304NotModified)!
|
||||
- Refreshed package catalog in CI before installing dependencies to prevent Linux workflow failures.
|
||||
- Refactored CmdPal tests with dependency injection and added coverage for queries and settings.
|
||||
- Added unit tests to verify Close on Enter swaps Copy/Save as expected. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
|
||||
- Added accessibility IDs to CmdPal UI for stable UI tests.
|
||||
- Rewrote system command tests with a new test base and cleaner patterns.
|
||||
- Added unit tests for WebSearch and Shell extensions with mockable settings.
|
||||
- Added unit tests and abstractions for Apps and Bookmarks extensions.
|
||||
- Cleans up AI‑generated tests; adds meaningful query tests across extensions.
|
||||
- Removed the obsolete debug dialog from Settings for a smoother developer loop.
|
||||
|
||||
### What is being planned over the next few releases
|
||||
|
||||
For [v0.94][github-next-release-work], we'll work on the items below:
|
||||
For [v0.95][github-next-release-work], we'll work on the items below:
|
||||
|
||||
- Continued Command Palette polish
|
||||
- Working on Shortcut Guide v2 (Thanks [@noraa-junker](https://github.com/noraa-junker)!)
|
||||
- Working on upgrading the installer to WiX 5
|
||||
- Working on shortcut conflict detection
|
||||
- Working on setting search
|
||||
- Upgrading Keyboard Manager's editor UI
|
||||
- UI tweaking utility with day/night theme switcher
|
||||
- DSC v3 support for top utilities
|
||||
- New UI automation tests
|
||||
- Stability, bug fixes
|
||||
|
||||
|
||||
BIN
doc/specs/search-result.png
Normal file
BIN
doc/specs/search-result.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 194 KiB |
233
doc/specs/settings-search.md
Normal file
233
doc/specs/settings-search.md
Normal file
@@ -0,0 +1,233 @@
|
||||
# PowerToys Settings – Search Index (Hard-sealed)
|
||||
|
||||
## 1. What to index
|
||||
|
||||
This section describes the current structure of the settings pages in PowerToys. All user-facing settings are contained in the content of <controls:SettingsPageControl>. The logical and visual structure of settings follows a nested layout as shown below:
|
||||
|
||||
```css
|
||||
SettingsPageControl
|
||||
└─ SettingsGroup
|
||||
└─ [SettingsExpander]
|
||||
└─ SettingsCard
|
||||
```
|
||||
* Each SettingsGroup defines a functional section within a settings page.
|
||||
|
||||
* An optional SettingsExpander may be used to further organize related settings inside a group.
|
||||
|
||||
* Each actual setting is represented by a SettingsCard, which contains one user-tweakable control or a group of closely related controls.
|
||||
|
||||
>Note: Not all SettingsCard are necessarily wrapped in a SettingsExpander; they can exist directly under a SettingsGroup.
|
||||
|
||||
> For indexing purposes, we are specifically targeting all SettingsCard elements. These are the smallest units of user interaction and correspond to individual configurable settings.
|
||||
|
||||
> There could be setting item in expander, so we also need to index expander items as well.
|
||||
|
||||
### Module
|
||||
Module is a primary type that needs to be indexed, for modules, we need to index the 'ModuleTitle' and the 'ModuleDescription'.
|
||||
So these two should be passed in by x:Uid and binding with a key.
|
||||
|
||||
|
||||
### SettingsCard/SettingsExpander
|
||||
|
||||
Each SettingsCard/SettingsExpander should have an x:Uid for localization and indexing. The associated display strings are defined in the .resw files:
|
||||
|
||||
{x:Uid}.Header – The visible label/title of the setting.
|
||||
{x:Uid}.Description – (optional) The tooltip or explanatory text.
|
||||
|
||||
The index should be built around these SettingsCard elements and their x:Uid-bound resources, as they represent the actual settings users will search for.
|
||||
|
||||
---
|
||||
|
||||
## 2. How to Navigate
|
||||
|
||||
### Entry
|
||||
```csharp
|
||||
enum EntryType
|
||||
{
|
||||
SettingsPage,
|
||||
SettingsCard,
|
||||
SettingsExpander,
|
||||
}
|
||||
|
||||
public class SearchableElementMetadata
|
||||
{
|
||||
public string PageName { get; set; } // Used to navigate to a specific page
|
||||
public EntryType Type { get; set; } // Used to know how should we navigate(As a page, a settingscard or an expander?)
|
||||
public string ParentElementName { get; set; }
|
||||
public string ElementName { get; set; }
|
||||
public string ElementUid { get; set; }
|
||||
public string Icon { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### Navigation
|
||||
The steps for navigate to an item:
|
||||
* Navigate among pages
|
||||
* [optional] Expand the expander if setting entry is inside an expander
|
||||
* [optional] Navigate within page
|
||||
|
||||
> Use page name for navigation:
|
||||
```csharp
|
||||
Type GetPageTypeFromPageName(string PageName)
|
||||
{
|
||||
var assembly = typeof(GeneralPage).Assembly;
|
||||
return assembly.GetType($"Microsoft.PowerToys.Settings.UI.Views.{PageName}");
|
||||
}
|
||||
|
||||
NavigationService.Navigate(PageType, ElementName,ParentElementName);
|
||||
```
|
||||
|
||||
> Use ElementName and ParentElementName for in page navigation:
|
||||
```csharp
|
||||
Page.OnNavigateTo(ElementName, ParentElementName){
|
||||
var element = this.FindName(name) as FrameworkElement;
|
||||
var parentElement = this.FindName(ParentElementName) as FrameworkElement;
|
||||
|
||||
if(parentElement) {
|
||||
expander = (Expander)parentElement;
|
||||
if(expander){
|
||||
expander.Expand();
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.uielement.startbringintoview?view=winrt-26100
|
||||
element.StartBringIntoView();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Runtime Search
|
||||
When user start typing for an entry, e.g. shortcut or 快捷键(cn version of shortcut),
|
||||
we need to go through all the entries to see if an entry matches the search text.
|
||||
|
||||
A naive approach will be try to match all the localized text one by one and see if they match.
|
||||
Total entry is within thousand(To fill in an exact number), performance is acceptable now.
|
||||
```csharp
|
||||
// Match
|
||||
query = UserInput();
|
||||
matched = {};
|
||||
|
||||
indexes = BuildIndex();
|
||||
|
||||
foreach(var entry in indexes) {
|
||||
if(entry.Match(query)) {
|
||||
matched.Add(entry);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And we don't intend to introduce complexity on the match algorithm discussion, so let's use powertoys FuzzMatch impl for now.
|
||||
```csharp
|
||||
MatchResult Match(this Entry entry, string query) {
|
||||
return FuzzMatch(entry.DisplayedText, query);
|
||||
}
|
||||
|
||||
struct MatchResult{
|
||||
int Score;
|
||||
bool Result;
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Search Result Page
|
||||

|
||||
After we got matched items, map these items to a search result page according to spec.
|
||||
```c#
|
||||
ObservableCollection<SettingEntry> ModuleResult;
|
||||
ObservableCollection<SettingsGroup> GroupedSettingsResults;
|
||||
|
||||
public class SettingsGroup : INotifyPropertyChanged
|
||||
{
|
||||
private string _groupName;
|
||||
private ObservableCollection<SettingEntry> _settings;
|
||||
public string GroupName
|
||||
{
|
||||
get => _groupName;
|
||||
set
|
||||
{
|
||||
_groupName = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
public ObservableCollection<SettingEntry> Settings
|
||||
{
|
||||
get => _settings;
|
||||
set
|
||||
{
|
||||
_settings = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. How to do Index
|
||||
### Runtime index or build time index?
|
||||
Now We need to build all the entries in our settings.
|
||||
|
||||
Most of the entry properties are static, and in runtime, the `SettingsCard` is compiled into native winUI3 controls <small>(I suppose, please correct here if it's wrong)</small>, it's hard to locate all the `SettingsCard`, and performance is terrible if we do search for all the pages' elements.
|
||||
|
||||
### Build time indexing
|
||||
We can rely on xaml file parsing to get all the SettingsCard Entries.
|
||||
And we don't want xaml file to be brought into production bundle.
|
||||
Use a project for parsing and bring that index file into production bundle is a solution.
|
||||
```csproj
|
||||
<Target Name="GenerateSearchIndex" BeforeTargets="BeforeBuild">
|
||||
<PropertyGroup>
|
||||
<BuilderExe>$(MSBuildProjectDirectory)\..\Settings.UI.XamlIndexBuilder\bin\$(Configuration)\net8.0\XamlIndexBuilder.exe</BuilderExe>
|
||||
<XamlDir>$(MSBuildProjectDirectory)\Views</XamlDir>
|
||||
<GeneratedJson>$(MSBuildProjectDirectory)\Services\searchable_elements.json</GeneratedJson>
|
||||
</PropertyGroup>
|
||||
<Exec Command=""$(BuilderExe)" "$(XamlDir)" "$(GeneratedJson)"" />
|
||||
</Target>
|
||||
```
|
||||
```csharp
|
||||
for(xamlFile in xamlFiles){
|
||||
var doc = Load(xamlFile);
|
||||
var elements = doc.Descendants();
|
||||
|
||||
foreach(var element in elements){
|
||||
if(element.Name == "SettingsCard") {
|
||||
var entry = new Entry{
|
||||
ElementName = element.Attribute["Name"],
|
||||
PageName = FileName,
|
||||
Type = "SettingsCard",
|
||||
ElementUid = element.Attribute["Uid"],
|
||||
DisplayedText = "",
|
||||
}
|
||||
|
||||
var parent = element.GetParent();
|
||||
if(parent.Name == "SettingsExpander"){
|
||||
entry.ParentElementName = parent.Attribute["Name"];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Runtime index loading:
|
||||
```
|
||||
var entries = LoadEntriesFromFile();
|
||||
foreach(var entry in entries){
|
||||
entry.DisplayedText = ResourceLoader.GetString(entry.Uid);
|
||||
}
|
||||
```
|
||||
So now we have all the entries and entry properties.
|
||||
|
||||
## Overall flow:
|
||||
|
||||

|
||||
|
||||
|
||||
## 6. Corner cases - that have not addressed yet
|
||||
|
||||
1. CmdPal page is not in scope of this effort, that needs additional effort&design to launch and search within cmdpal settings page.
|
||||
|
||||
2. Go back button
|
||||
|
||||
3. Dynamic constructed settings page
|
||||
- Shortcut guide, with visibility converter
|
||||
- advanced paste dynamically configured setting items
|
||||
- powertoys run's extensions
|
||||
BIN
doc/specs/workflow.png
Normal file
BIN
doc/specs/workflow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
8
src/common/Common.Search/Common.Search.csproj
Normal file
8
src/common/Common.Search/Common.Search.csproj
Normal file
@@ -0,0 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
10
src/common/Common.Search/FuzzSearch/MatchOption.cs
Normal file
10
src/common/Common.Search/FuzzSearch/MatchOption.cs
Normal file
@@ -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 Common.Search.FuzzSearch;
|
||||
|
||||
public class MatchOption
|
||||
{
|
||||
public bool IgnoreCase { get; set; } = true;
|
||||
}
|
||||
67
src/common/Common.Search/FuzzSearch/MatchResult.cs
Normal file
67
src/common/Common.Search/FuzzSearch/MatchResult.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
// 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 Common.Search.FuzzSearch;
|
||||
|
||||
public class MatchResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The raw calculated search score without any search precision filtering applied.
|
||||
/// </summary>
|
||||
private int _rawScore;
|
||||
|
||||
public MatchResult(bool success, SearchPrecisionScore searchPrecision)
|
||||
{
|
||||
Success = success;
|
||||
SearchPrecision = searchPrecision;
|
||||
}
|
||||
|
||||
public MatchResult(bool success, SearchPrecisionScore searchPrecision, List<int> matchData, int rawScore)
|
||||
{
|
||||
Success = success;
|
||||
SearchPrecision = searchPrecision;
|
||||
MatchData = matchData;
|
||||
RawScore = rawScore;
|
||||
}
|
||||
|
||||
public bool Success { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the final score of the match result with search precision filters applied.
|
||||
/// </summary>
|
||||
public int Score { get; private set; }
|
||||
|
||||
public int RawScore
|
||||
{
|
||||
get => _rawScore;
|
||||
|
||||
set
|
||||
{
|
||||
_rawScore = value;
|
||||
Score = ScoreAfterSearchPrecisionFilter(_rawScore);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets matched data to highlight.
|
||||
/// </summary>
|
||||
public List<int> MatchData { get; private set; } = new();
|
||||
|
||||
public SearchPrecisionScore SearchPrecision { get; set; }
|
||||
|
||||
public bool IsSearchPrecisionScoreMet()
|
||||
{
|
||||
return IsSearchPrecisionScoreMet(_rawScore);
|
||||
}
|
||||
|
||||
private bool IsSearchPrecisionScoreMet(int rawScore)
|
||||
{
|
||||
return rawScore >= (int)SearchPrecision;
|
||||
}
|
||||
|
||||
private int ScoreAfterSearchPrecisionFilter(int rawScore)
|
||||
{
|
||||
return IsSearchPrecisionScoreMet(rawScore) ? rawScore : 0;
|
||||
}
|
||||
}
|
||||
12
src/common/Common.Search/FuzzSearch/SearchPrecisionScore.cs
Normal file
12
src/common/Common.Search/FuzzSearch/SearchPrecisionScore.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// 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 Common.Search.FuzzSearch;
|
||||
|
||||
public enum SearchPrecisionScore
|
||||
{
|
||||
Regular = 50,
|
||||
Low = 20,
|
||||
None = 0,
|
||||
}
|
||||
272
src/common/Common.Search/FuzzSearch/StringMatcher.cs
Normal file
272
src/common/Common.Search/FuzzSearch/StringMatcher.cs
Normal file
@@ -0,0 +1,272 @@
|
||||
// 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 Common.Search.FuzzSearch;
|
||||
|
||||
public class StringMatcher
|
||||
{
|
||||
public StringMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
private static readonly char[] Separator = [' '];
|
||||
|
||||
/// <summary>
|
||||
/// Current method:
|
||||
/// Character matching + substring matching;
|
||||
/// 1. Query search string is split into substrings, separator is whitespace.
|
||||
/// 2. Check each query substring's characters against full compare string,
|
||||
/// 3. if a character in the substring is matched, loop back to verify the previous character.
|
||||
/// 4. If previous character also matches, and is the start of the substring, update list.
|
||||
/// 5. Once the previous character is verified, move on to the next character in the query substring.
|
||||
/// 6. Move onto the next substring's characters until all substrings are checked.
|
||||
/// 7. Consider success and move onto scoring if every char or substring without whitespaces matched
|
||||
/// </summary>
|
||||
public static MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption opt = null)
|
||||
{
|
||||
opt = opt ?? new MatchOption();
|
||||
|
||||
if (string.IsNullOrEmpty(stringToCompare))
|
||||
{
|
||||
return new MatchResult(false, SearchPrecisionScore.Regular);
|
||||
}
|
||||
|
||||
SearchPrecisionScore score = SearchPrecisionScore.Regular;
|
||||
|
||||
var bestResult = new MatchResult(false, score);
|
||||
|
||||
for (int startIndex = 0; startIndex < stringToCompare.Length; startIndex++)
|
||||
{
|
||||
MatchResult result = FuzzyMatch(query, stringToCompare, opt, startIndex);
|
||||
if (result.Success && (!bestResult.Success || result.Score > bestResult.Score))
|
||||
{
|
||||
bestResult = result;
|
||||
}
|
||||
}
|
||||
|
||||
return bestResult;
|
||||
}
|
||||
|
||||
private static MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption opt, int startIndex)
|
||||
{
|
||||
if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query))
|
||||
{
|
||||
return new MatchResult(false, SearchPrecisionScore.Regular);
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(opt);
|
||||
|
||||
query = query.Trim();
|
||||
|
||||
// Using InvariantCulture since this is internal
|
||||
var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToUpper(CultureInfo.InvariantCulture) : stringToCompare;
|
||||
var queryWithoutCase = opt.IgnoreCase ? query.ToUpper(CultureInfo.InvariantCulture) : query;
|
||||
|
||||
var querySubstrings = queryWithoutCase.Split(Separator, StringSplitOptions.RemoveEmptyEntries);
|
||||
int currentQuerySubstringIndex = 0;
|
||||
var currentQuerySubstring = querySubstrings[currentQuerySubstringIndex];
|
||||
var currentQuerySubstringCharacterIndex = 0;
|
||||
|
||||
var firstMatchIndex = -1;
|
||||
var firstMatchIndexInWord = -1;
|
||||
var lastMatchIndex = 0;
|
||||
bool allQuerySubstringsMatched = false;
|
||||
bool matchFoundInPreviousLoop = false;
|
||||
bool allSubstringsContainedInCompareString = true;
|
||||
|
||||
var indexList = new List<int>();
|
||||
List<int> spaceIndices = new List<int>();
|
||||
|
||||
for (var compareStringIndex = startIndex; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++)
|
||||
{
|
||||
// To maintain a list of indices which correspond to spaces in the string to compare
|
||||
// To populate the list only for the first query substring
|
||||
if (fullStringToCompareWithoutCase[compareStringIndex].Equals(' ') && currentQuerySubstringIndex == 0)
|
||||
{
|
||||
spaceIndices.Add(compareStringIndex);
|
||||
}
|
||||
|
||||
bool compareResult;
|
||||
if (opt.IgnoreCase)
|
||||
{
|
||||
var fullStringToCompare = fullStringToCompareWithoutCase[compareStringIndex].ToString();
|
||||
var querySubstring = currentQuerySubstring[currentQuerySubstringCharacterIndex].ToString();
|
||||
#pragma warning disable CA1309 // Use ordinal string comparison (We are looking for a fuzzy match here)
|
||||
compareResult = string.Compare(fullStringToCompare, querySubstring, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) != 0;
|
||||
#pragma warning restore CA1309 // Use ordinal string comparison
|
||||
}
|
||||
else
|
||||
{
|
||||
compareResult = fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex];
|
||||
}
|
||||
|
||||
if (compareResult)
|
||||
{
|
||||
matchFoundInPreviousLoop = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (firstMatchIndex < 0)
|
||||
{
|
||||
// first matched char will become the start of the compared string
|
||||
firstMatchIndex = compareStringIndex;
|
||||
}
|
||||
|
||||
if (currentQuerySubstringCharacterIndex == 0)
|
||||
{
|
||||
// first letter of current word
|
||||
matchFoundInPreviousLoop = true;
|
||||
firstMatchIndexInWord = compareStringIndex;
|
||||
}
|
||||
else if (!matchFoundInPreviousLoop)
|
||||
{
|
||||
// we want to verify that there is not a better match if this is not a full word
|
||||
// in order to do so we need to verify all previous chars are part of the pattern
|
||||
var startIndexToVerify = compareStringIndex - currentQuerySubstringCharacterIndex;
|
||||
|
||||
if (AllPreviousCharsMatched(startIndexToVerify, currentQuerySubstringCharacterIndex, fullStringToCompareWithoutCase, currentQuerySubstring))
|
||||
{
|
||||
matchFoundInPreviousLoop = true;
|
||||
|
||||
// if it's the beginning character of the first query substring that is matched then we need to update start index
|
||||
firstMatchIndex = currentQuerySubstringIndex == 0 ? startIndexToVerify : firstMatchIndex;
|
||||
|
||||
indexList = GetUpdatedIndexList(startIndexToVerify, currentQuerySubstringCharacterIndex, firstMatchIndexInWord, indexList);
|
||||
}
|
||||
}
|
||||
|
||||
lastMatchIndex = compareStringIndex + 1;
|
||||
indexList.Add(compareStringIndex);
|
||||
|
||||
currentQuerySubstringCharacterIndex++;
|
||||
|
||||
// if finished looping through every character in the current substring
|
||||
if (currentQuerySubstringCharacterIndex == currentQuerySubstring.Length)
|
||||
{
|
||||
// if any of the substrings was not matched then consider as all are not matched
|
||||
allSubstringsContainedInCompareString = matchFoundInPreviousLoop && allSubstringsContainedInCompareString;
|
||||
|
||||
currentQuerySubstringIndex++;
|
||||
|
||||
allQuerySubstringsMatched = AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length);
|
||||
if (allQuerySubstringsMatched)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise move to the next query substring
|
||||
currentQuerySubstring = querySubstrings[currentQuerySubstringIndex];
|
||||
currentQuerySubstringCharacterIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// proceed to calculate score if every char or substring without whitespaces matched
|
||||
if (allQuerySubstringsMatched)
|
||||
{
|
||||
var nearestSpaceIndex = CalculateClosestSpaceIndex(spaceIndices, firstMatchIndex);
|
||||
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString);
|
||||
|
||||
return new MatchResult(true, SearchPrecisionScore.Regular, indexList, score);
|
||||
}
|
||||
|
||||
return new MatchResult(false, SearchPrecisionScore.Regular);
|
||||
}
|
||||
|
||||
// To get the index of the closest space which precedes the first matching index
|
||||
private static int CalculateClosestSpaceIndex(List<int> spaceIndices, int firstMatchIndex)
|
||||
{
|
||||
if (spaceIndices.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return spaceIndices.OrderBy(item => firstMatchIndex - item).Where(item => firstMatchIndex > item).FirstOrDefault(-1);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQuerySubstringCharacterIndex, string fullStringToCompareWithoutCase, string currentQuerySubstring)
|
||||
{
|
||||
var allMatch = true;
|
||||
for (int indexToCheck = 0; indexToCheck < currentQuerySubstringCharacterIndex; indexToCheck++)
|
||||
{
|
||||
if (fullStringToCompareWithoutCase[startIndexToVerify + indexToCheck] !=
|
||||
currentQuerySubstring[indexToCheck])
|
||||
{
|
||||
allMatch = false;
|
||||
}
|
||||
}
|
||||
|
||||
return allMatch;
|
||||
}
|
||||
|
||||
private static List<int> GetUpdatedIndexList(int startIndexToVerify, int currentQuerySubstringCharacterIndex, int firstMatchIndexInWord, List<int> indexList)
|
||||
{
|
||||
var updatedList = new List<int>();
|
||||
|
||||
indexList.RemoveAll(x => x >= firstMatchIndexInWord);
|
||||
|
||||
updatedList.AddRange(indexList);
|
||||
|
||||
for (int indexToCheck = 0; indexToCheck < currentQuerySubstringCharacterIndex; indexToCheck++)
|
||||
{
|
||||
updatedList.Add(startIndexToVerify + indexToCheck);
|
||||
}
|
||||
|
||||
return updatedList;
|
||||
}
|
||||
|
||||
private static bool AllQuerySubstringsMatched(int currentQuerySubstringIndex, int querySubstringsLength)
|
||||
{
|
||||
return currentQuerySubstringIndex >= querySubstringsLength;
|
||||
}
|
||||
|
||||
private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, bool allSubstringsContainedInCompareString)
|
||||
{
|
||||
// A match found near the beginning of a string is scored more than a match found near the end
|
||||
// A match is scored more if the characters in the patterns are closer to each other,
|
||||
// while the score is lower if they are more spread out
|
||||
|
||||
// The length of the match is assigned a larger weight factor.
|
||||
const int matchLenWeightFactor = 2;
|
||||
|
||||
var score = 100 * (query.Length + 1) * matchLenWeightFactor / (1 + firstIndex + (matchLenWeightFactor * (matchLen + 1)));
|
||||
|
||||
// A match with less characters assigning more weights
|
||||
if (stringToCompare.Length - query.Length < 5)
|
||||
{
|
||||
score += 20;
|
||||
}
|
||||
else if (stringToCompare.Length - query.Length < 10)
|
||||
{
|
||||
score += 10;
|
||||
}
|
||||
|
||||
if (allSubstringsContainedInCompareString)
|
||||
{
|
||||
int count = query.Count(c => !char.IsWhiteSpace(c));
|
||||
int threshold = 4;
|
||||
if (count <= threshold)
|
||||
{
|
||||
score += count * 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
score += (threshold * 10) + ((count - threshold) * 5);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable CA1309 // Use ordinal string comparison (Using CurrentCultureIgnoreCase since this relates to queries input by user)
|
||||
if (string.Equals(query, stringToCompare, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
var bonusForExactMatch = 10;
|
||||
score += bonusForExactMatch;
|
||||
}
|
||||
#pragma warning restore CA1309 // Use ordinal string comparison
|
||||
|
||||
return score;
|
||||
}
|
||||
}
|
||||
24
src/common/Common.Search/GlobalSuppressions.cs
Normal file
24
src/common/Common.Search/GlobalSuppressions.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
// 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.
|
||||
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1309:Field names should not begin with underscore", Justification = "coding style", Scope = "member", Target = "~F:Common.Search.MatchResult._rawScore")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1309:Field names should not begin with underscore", Justification = "coding style", Scope = "member", Target = "~F:Common.Search.StringMatcher._defaultMatchOption")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1309:Field names should not begin with underscore", Justification = "coding style", Scope = "member", Target = "~F:Common.Search.StringMatcher._instance")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "coding style", Scope = "member", Target = "~M:Common.Search.MatchResult.#ctor(System.Boolean,Common.Search.SearchPrecisionScore)")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "coding style", Scope = "member", Target = "~M:Common.Search.MatchResult.#ctor(System.Boolean,Common.Search.SearchPrecisionScore,System.Collections.Generic.List{System.Int32},System.Int32)")]
|
||||
[assembly: SuppressMessage("Compiler", "CS8618:Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.", Justification = "Coding style", Scope = "member", Target = "~F:Common.Search.StringMatcher._instance")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "coding style", Scope = "member", Target = "~F:Common.Search.StringMatcher._instance")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "coding style", Scope = "member", Target = "~F:Common.Search.StringMatcher.Separator")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "coding style", Scope = "member", Target = "~M:Common.Search.StringMatcher.#ctor")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "coding style", Scope = "member", Target = "~M:Common.Search.StringMatcher.FuzzyMatch(System.String,System.String)~Common.Search.MatchResult")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "coding style", Scope = "member", Target = "~M:Common.Search.StringMatcher.FuzzyMatch(System.String,System.String,Common.Search.MatchOption)~Common.Search.MatchResult")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1407:Arithmetic expressions should declare precedence", Justification = "migrate from stable code", Scope = "member", Target = "~M:Common.Search.StringMatcher.CalculateSearchScore(System.String,System.String,System.Int32,System.Int32,System.Boolean)~System.Int32")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "migrate from stable code", Scope = "member", Target = "~M:Common.Search.StringMatcher.FuzzyMatch(System.String,System.String,Common.Search.MatchOption,System.Int32)~Common.Search.MatchResult")]
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:Static elements should appear before instance elements", Justification = "migrate from stable code", Scope = "member", Target = "~M:Common.Search.StringMatcher.CalculateClosestSpaceIndex(System.Collections.Generic.List{System.Int32},System.Int32)~System.Int32")]
|
||||
22
src/common/Common.Search/stylecop.json
Normal file
22
src/common/Common.Search/stylecop.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
|
||||
"settings": {
|
||||
"documentationRules": {
|
||||
"companyName": "Microsoft Corporation",
|
||||
"copyrightText": "Copyright (c) {companyName}\r\nThe {companyName} licenses this file to you under the MIT license.\r\nSee the LICENSE file in the project root for more information.",
|
||||
"xmlHeader": false,
|
||||
"headerDecoration": "",
|
||||
"fileNamingConvention": "metadata",
|
||||
"documentInterfaces": false,
|
||||
"documentExposedElements": false,
|
||||
"documentInternalElements": false
|
||||
},
|
||||
"layoutRules": {
|
||||
"newlineAtEndOfFile": "require"
|
||||
},
|
||||
"orderingRules": {
|
||||
"usingDirectivesPlacement": "outsideNamespace",
|
||||
"systemUsingDirectivesFirst": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,17 +32,8 @@ namespace ManagedCommon
|
||||
/// <param name="isLocalLow">If the process using Logger is a low-privilege process.</param>
|
||||
public static void InitializeLogger(string applicationLogPath, bool isLocalLow = false)
|
||||
{
|
||||
string basePath;
|
||||
if (isLocalLow)
|
||||
{
|
||||
basePath = Environment.GetEnvironmentVariable("userprofile") + "\\appdata\\LocalLow\\Microsoft\\PowerToys" + applicationLogPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
basePath = Constants.AppDataPath() + applicationLogPath;
|
||||
}
|
||||
|
||||
string versionedPath = Path.Combine(basePath, Version);
|
||||
string versionedPath = LogDirectoryPath(applicationLogPath, isLocalLow);
|
||||
string basePath = Path.GetDirectoryName(versionedPath);
|
||||
|
||||
if (!Directory.Exists(versionedPath))
|
||||
{
|
||||
@@ -59,6 +50,22 @@ namespace ManagedCommon
|
||||
Task.Run(() => DeleteOldVersionLogFolders(basePath, versionedPath));
|
||||
}
|
||||
|
||||
public static string LogDirectoryPath(string applicationLogPath, bool isLocalLow = false)
|
||||
{
|
||||
string basePath;
|
||||
if (isLocalLow)
|
||||
{
|
||||
basePath = Environment.GetEnvironmentVariable("userprofile") + "\\appdata\\LocalLow\\Microsoft\\PowerToys" + applicationLogPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
basePath = Constants.AppDataPath() + applicationLogPath;
|
||||
}
|
||||
|
||||
string versionedPath = Path.Combine(basePath, Version);
|
||||
return versionedPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes old version log folders, keeping only the current version's folder.
|
||||
/// </summary>
|
||||
|
||||
@@ -19,6 +19,26 @@
|
||||
|
||||
class FileLocksmithModule : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// Update registration based on enabled state
|
||||
void UpdateRegistration(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
FileLocksmithRuntimeRegistration::EnsureRegistered();
|
||||
Logger::info(L"File Locksmith context menu registered");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
FileLocksmithRuntimeRegistration::Unregister();
|
||||
Logger::info(L"File Locksmith context menu unregistered");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
FileLocksmithModule()
|
||||
{
|
||||
@@ -88,21 +108,16 @@ public:
|
||||
package::RegisterSparsePackage(path, packageUri);
|
||||
}
|
||||
}
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
FileLocksmithRuntimeRegistration::EnsureRegistered();
|
||||
#endif
|
||||
|
||||
m_enabled = true;
|
||||
UpdateRegistration(m_enabled);
|
||||
}
|
||||
|
||||
virtual void disable() override
|
||||
{
|
||||
Logger::info(L"File Locksmith disabled");
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
FileLocksmithRuntimeRegistration::Unregister();
|
||||
Logger::info(L"File Locksmith context menu unregistered (Win10)");
|
||||
#endif
|
||||
m_enabled = false;
|
||||
UpdateRegistration(m_enabled);
|
||||
}
|
||||
|
||||
virtual bool is_enabled() override
|
||||
@@ -135,6 +150,7 @@ private:
|
||||
{
|
||||
m_enabled = FileLocksmithSettingsInstance().GetEnabled();
|
||||
m_extended_only = FileLocksmithSettingsInstance().GetShowInExtendedContextMenu();
|
||||
UpdateRegistration(m_enabled);
|
||||
Trace::EnableFileLocksmith(m_enabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,26 @@
|
||||
// Note: Settings are managed via Settings and UI Settings
|
||||
class NewModule : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// Update registration based on enabled state
|
||||
void UpdateRegistration(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
NewPlusRuntimeRegistration::EnsureRegisteredWin10();
|
||||
Logger::info(L"New+ context menu registered");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
NewPlusRuntimeRegistration::Unregister();
|
||||
Logger::info(L"New+ context menu unregistered");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
NewModule()
|
||||
{
|
||||
@@ -98,14 +118,9 @@ public:
|
||||
{
|
||||
newplus::utilities::register_msix_package();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
NewPlusRuntimeRegistration::EnsureRegisteredWin10();
|
||||
#endif
|
||||
}
|
||||
|
||||
powertoy_new_enabled = true;
|
||||
UpdateRegistration(powertoy_new_enabled);
|
||||
}
|
||||
|
||||
virtual void disable() override
|
||||
@@ -150,19 +165,14 @@ private:
|
||||
{
|
||||
Trace::EventToggleOnOff(false);
|
||||
}
|
||||
if (!package::IsWin11OrGreater())
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
NewPlusRuntimeRegistration::Unregister();
|
||||
Logger::info(L"New+ context menu unregistered (Win10)");
|
||||
#endif
|
||||
}
|
||||
powertoy_new_enabled = false;
|
||||
UpdateRegistration(powertoy_new_enabled);
|
||||
}
|
||||
|
||||
void init_settings()
|
||||
{
|
||||
powertoy_new_enabled = NewSettingsInstance().GetEnabled();
|
||||
UpdateRegistration(powertoy_new_enabled);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Commands;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
@@ -19,6 +20,10 @@ internal sealed partial class FallbackLogItem : FallbackCommandItem
|
||||
Title = string.Empty;
|
||||
_logMessagesPage.Name = string.Empty;
|
||||
Subtitle = Properties.Resources.builtin_log_subtitle;
|
||||
|
||||
var logPath = Logger.LogDirectoryPath("\\CmdPal\\Logs\\");
|
||||
var openLogCommand = new OpenFileCommand(logPath) { Name = Resources.builtin_log_folder_command_name };
|
||||
MoreCommands = [new CommandContextItem(openLogCommand)];
|
||||
}
|
||||
|
||||
public override void UpdateQuery(string query)
|
||||
|
||||
@@ -27,7 +27,9 @@ public partial class MainListPage : DynamicListPage,
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
private readonly TopLevelCommandManager _tlcManager;
|
||||
private IEnumerable<IListItem>? _filteredItems;
|
||||
private IEnumerable<Scored<IListItem>>? _filteredItems;
|
||||
private IEnumerable<Scored<IListItem>>? _filteredApps;
|
||||
private IEnumerable<IListItem>? _allApps;
|
||||
private bool _includeApps;
|
||||
private bool _filteredItemsIncludesApps;
|
||||
|
||||
@@ -83,7 +85,7 @@ public partial class MainListPage : DynamicListPage,
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseItemsChanged(_tlcManager.TopLevelCommands.Count);
|
||||
RaiseItemsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +150,13 @@ public partial class MainListPage : DynamicListPage,
|
||||
{
|
||||
lock (_tlcManager.TopLevelCommands)
|
||||
{
|
||||
return _filteredItems?.ToArray() ?? [];
|
||||
var items = Enumerable.Empty<Scored<IListItem>>()
|
||||
.Concat(_filteredItems is not null ? _filteredItems : [])
|
||||
.Concat(_filteredApps is not null ? _filteredApps : [])
|
||||
.OrderByDescending(o => o.Score)
|
||||
.Select(s => s.Item)
|
||||
.ToArray();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,6 +175,8 @@ public partial class MainListPage : DynamicListPage,
|
||||
{
|
||||
_filteredItemsIncludesApps = _includeApps;
|
||||
_filteredItems = null;
|
||||
_filteredApps = null;
|
||||
_allApps = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,6 +194,8 @@ public partial class MainListPage : DynamicListPage,
|
||||
{
|
||||
_filteredItemsIncludesApps = _includeApps;
|
||||
_filteredItems = null;
|
||||
_filteredApps = null;
|
||||
_allApps = null;
|
||||
RaiseItemsChanged(commands.Count);
|
||||
return;
|
||||
}
|
||||
@@ -193,35 +205,49 @@ public partial class MainListPage : DynamicListPage,
|
||||
if (!newSearch.StartsWith(oldSearch, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
_filteredItems = null;
|
||||
_filteredApps = null;
|
||||
_allApps = null;
|
||||
}
|
||||
|
||||
// If the internal state has changed, reset _filteredItems to reset the list.
|
||||
if (_filteredItemsIncludesApps != _includeApps)
|
||||
{
|
||||
_filteredItems = null;
|
||||
_filteredApps = null;
|
||||
_allApps = null;
|
||||
}
|
||||
|
||||
var newFilteredItems = _filteredItems?.Select(s => s.Item);
|
||||
|
||||
// If we don't have any previous filter results to work with, start
|
||||
// with a list of all our commands & apps.
|
||||
if (_filteredItems is null)
|
||||
if (newFilteredItems is null && _filteredApps is null)
|
||||
{
|
||||
_filteredItems = commands;
|
||||
newFilteredItems = commands;
|
||||
_filteredItemsIncludesApps = _includeApps;
|
||||
|
||||
if (_includeApps)
|
||||
{
|
||||
IEnumerable<IListItem> apps = AllAppsCommandProvider.Page.GetItems();
|
||||
var appIds = apps.Select(app => app.Command.Id).ToArray();
|
||||
|
||||
// Remove any top level pinned apps and use the apps from AllAppsCommandProvider.Page.GetItems()
|
||||
// since they contain details.
|
||||
_filteredItems = _filteredItems.Where(item => item.Command is not AppCommand);
|
||||
_filteredItems = _filteredItems.Concat(apps);
|
||||
_allApps = AllAppsCommandProvider.Page.GetItems();
|
||||
}
|
||||
}
|
||||
|
||||
// Produce a list of everything that matches the current filter.
|
||||
_filteredItems = ListHelpers.FilterList<IListItem>(_filteredItems, SearchText, ScoreTopLevelItem);
|
||||
RaiseItemsChanged(_filteredItems.Count());
|
||||
_filteredItems = ListHelpers.FilterListWithScores<IListItem>(newFilteredItems ?? [], SearchText, ScoreTopLevelItem);
|
||||
|
||||
// Produce a list of filtered apps with the appropriate limit
|
||||
if (_allApps is not null)
|
||||
{
|
||||
_filteredApps = ListHelpers.FilterListWithScores<IListItem>(_allApps, SearchText, ScoreTopLevelItem);
|
||||
|
||||
var appResultLimit = AllAppsCommandProvider.TopLevelResultLimit;
|
||||
if (appResultLimit >= 0)
|
||||
{
|
||||
_filteredApps = _filteredApps.Take(appResultLimit);
|
||||
}
|
||||
}
|
||||
|
||||
RaiseItemsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,10 @@ public class ExtensionWrapper : IExtensionWrapper
|
||||
// We'll just return out nothing.
|
||||
return;
|
||||
}
|
||||
else if (hr.Value != 0)
|
||||
{
|
||||
Logger.LogError($"Failed to find {ExtensionDisplayName}: {hr.Value}");
|
||||
}
|
||||
|
||||
// Marshal.ThrowExceptionForHR(hr);
|
||||
_extensionObject = MarshalInterface<IExtension>.FromAbi((nint)extensionPtr);
|
||||
|
||||
@@ -285,6 +285,15 @@ namespace Microsoft.CmdPal.UI.ViewModels.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to View log folder.
|
||||
/// </summary>
|
||||
public static string builtin_log_folder_command_name {
|
||||
get {
|
||||
return ResourceManager.GetString("builtin_log_folder_command_name", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to View log.
|
||||
/// </summary>
|
||||
|
||||
@@ -135,6 +135,9 @@
|
||||
<data name="builtin_log_title" xml:space="preserve">
|
||||
<value>View log</value>
|
||||
</data>
|
||||
<data name="builtin_log_folder_command_name" xml:space="preserve">
|
||||
<value>View log folder</value>
|
||||
</data>
|
||||
<data name="builtin_reload_subtitle" xml:space="preserve">
|
||||
<value>Reload Command Palette extensions</value>
|
||||
</data>
|
||||
|
||||
@@ -438,7 +438,7 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<data name="NavigationPaneClosed" xml:space="preserve">
|
||||
<value>Navigation pane closed</value>
|
||||
</data>
|
||||
<data name="NavigationPageOpened" xml:space="preserve">
|
||||
<data name="NavigationPaneOpened" xml:space="preserve">
|
||||
<value>Navigation page opened</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -3,9 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
using Microsoft.CmdPal.Ext.Apps.Properties;
|
||||
using Microsoft.CmdPal.Ext.Apps.State;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
@@ -45,6 +43,28 @@ public partial class AllAppsCommandProvider : CommandProvider
|
||||
PinnedAppsManager.Instance.PinStateChanged += OnPinStateChanged;
|
||||
}
|
||||
|
||||
public static int TopLevelResultLimit
|
||||
{
|
||||
get
|
||||
{
|
||||
var limitSetting = AllAppsSettings.Instance.SearchResultLimit;
|
||||
|
||||
if (limitSetting is null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var quantity = -1;
|
||||
|
||||
if (int.TryParse(limitSetting, out var result))
|
||||
{
|
||||
quantity = result;
|
||||
}
|
||||
|
||||
return quantity;
|
||||
}
|
||||
}
|
||||
|
||||
public override ICommandItem[] TopLevelCommands() => [_listItem, .._page.GetPinnedApps()];
|
||||
|
||||
public ICommandItem? LookupApp(string displayName)
|
||||
|
||||
@@ -20,6 +20,16 @@ public class AllAppsSettings : JsonSettingsManager, ISettingsInterface
|
||||
|
||||
private static string Experimental(string propertyName) => $"{_namespace}.experimental.{propertyName}";
|
||||
|
||||
private static readonly List<ChoiceSetSetting.Choice> _searchResultLimitChoices =
|
||||
[
|
||||
new ChoiceSetSetting.Choice(Resources.limit_none, "-1"),
|
||||
new ChoiceSetSetting.Choice(Resources.limit_0, "0"),
|
||||
new ChoiceSetSetting.Choice(Resources.limit_1, "1"),
|
||||
new ChoiceSetSetting.Choice(Resources.limit_5, "5"),
|
||||
new ChoiceSetSetting.Choice(Resources.limit_10, "10"),
|
||||
new ChoiceSetSetting.Choice(Resources.limit_20, "20"),
|
||||
];
|
||||
|
||||
#pragma warning disable SA1401 // Fields should be private
|
||||
internal static AllAppsSettings Instance = new();
|
||||
#pragma warning restore SA1401 // Fields should be private
|
||||
@@ -42,6 +52,14 @@ public class AllAppsSettings : JsonSettingsManager, ISettingsInterface
|
||||
|
||||
public bool EnablePathEnvironmentVariableSource => _enablePathEnvironmentVariableSource.Value;
|
||||
|
||||
private readonly ChoiceSetSetting _searchResultLimitSource = new(
|
||||
Namespaced(nameof(SearchResultLimit)),
|
||||
Resources.limit_fallback_results_source,
|
||||
Resources.limit_fallback_results_source_description,
|
||||
_searchResultLimitChoices);
|
||||
|
||||
public string SearchResultLimit => _searchResultLimitSource.Value ?? string.Empty;
|
||||
|
||||
private readonly ToggleSetting _enableStartMenuSource = new(
|
||||
Namespaced(nameof(EnableStartMenuSource)),
|
||||
Resources.enable_start_menu_source,
|
||||
@@ -87,6 +105,7 @@ public class AllAppsSettings : JsonSettingsManager, ISettingsInterface
|
||||
Settings.Add(_enableDesktopSource);
|
||||
Settings.Add(_enableRegistrySource);
|
||||
Settings.Add(_enablePathEnvironmentVariableSource);
|
||||
Settings.Add(_searchResultLimitSource);
|
||||
|
||||
// Load settings from file upon initialization
|
||||
LoadSettings();
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Apps.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Commands;
|
||||
|
||||
internal sealed partial class CopyPathCommand : InvokableCommand
|
||||
{
|
||||
private readonly string _target;
|
||||
|
||||
public CopyPathCommand(string target)
|
||||
{
|
||||
Name = Resources.copy_path;
|
||||
Icon = Icons.CopyIcon;
|
||||
|
||||
_target = target;
|
||||
}
|
||||
|
||||
private static readonly CompositeFormat CopyFailedFormat = CompositeFormat.Parse(Resources.copy_failed);
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
try
|
||||
{
|
||||
ClipboardHelper.SetText(_target);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Copy failed: " + ex.Message);
|
||||
return CommandResult.ShowToast(
|
||||
new ToastArgs
|
||||
{
|
||||
Message = string.Format(CultureInfo.CurrentCulture, CopyFailedFormat, ex.Message),
|
||||
Result = CommandResult.KeepOpen(),
|
||||
});
|
||||
}
|
||||
|
||||
return CommandResult.ShowToast(Resources.copied_to_clipboard);
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ public class UWPApplication : IUWPApplication
|
||||
|
||||
commands.Add(
|
||||
new CommandContextItem(
|
||||
new Commands.CopyPathCommand(Location))
|
||||
new CopyTextCommand(Location) { Name = Resources.copy_path })
|
||||
{
|
||||
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.C),
|
||||
});
|
||||
|
||||
@@ -202,7 +202,7 @@ public class Win32Program : IProgram
|
||||
}
|
||||
|
||||
commands.Add(new CommandContextItem(
|
||||
new Commands.CopyPathCommand(FullPath))
|
||||
new CopyTextCommand(FullPath) { Name = Resources.copy_path })
|
||||
{
|
||||
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.C),
|
||||
});
|
||||
|
||||
@@ -78,24 +78,6 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copied to clipboard!.
|
||||
/// </summary>
|
||||
internal static string copied_to_clipboard {
|
||||
get {
|
||||
return ResourceManager.GetString("copied_to_clipboard", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy failed ({0}). Please try again..
|
||||
/// </summary>
|
||||
internal static string copy_failed {
|
||||
get {
|
||||
return ResourceManager.GetString("copy_failed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy path.
|
||||
/// </summary>
|
||||
@@ -177,6 +159,78 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 0.
|
||||
/// </summary>
|
||||
internal static string limit_0 {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_0", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 1.
|
||||
/// </summary>
|
||||
internal static string limit_1 {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_1", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 10.
|
||||
/// </summary>
|
||||
internal static string limit_10 {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_10", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 20.
|
||||
/// </summary>
|
||||
internal static string limit_20 {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_20", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 5.
|
||||
/// </summary>
|
||||
internal static string limit_5 {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_5", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Limit the number of applications returned from the top level.
|
||||
/// </summary>
|
||||
internal static string limit_fallback_results_source {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_fallback_results_source", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Limit fallback results to n apps.
|
||||
/// </summary>
|
||||
internal static string limit_fallback_results_source_description {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_fallback_results_source_description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to None.
|
||||
/// </summary>
|
||||
internal static string limit_none {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_none", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Open containing folder.
|
||||
/// </summary>
|
||||
|
||||
@@ -172,13 +172,6 @@
|
||||
<data name="run_as_different_user" xml:space="preserve">
|
||||
<value>Run as different user</value>
|
||||
</data>
|
||||
<data name="copy_failed" xml:space="preserve">
|
||||
<value>Copy failed ({0}). Please try again.</value>
|
||||
<comment>{0} is the error message</comment>
|
||||
</data>
|
||||
<data name="copied_to_clipboard" xml:space="preserve">
|
||||
<value>Copied to clipboard!</value>
|
||||
</data>
|
||||
<data name="enable_start_menu_source" xml:space="preserve">
|
||||
<value>Include apps found in the Start Menu</value>
|
||||
</data>
|
||||
@@ -205,4 +198,28 @@
|
||||
<data name="unpin_app" xml:space="preserve">
|
||||
<value>Unpin</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="limit_1" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="limit_5" xml:space="preserve">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="limit_10" xml:space="preserve">
|
||||
<value>10</value>
|
||||
</data>
|
||||
<data name="limit_20" xml:space="preserve">
|
||||
<value>20</value>
|
||||
</data>
|
||||
<data name="limit_fallback_results_source" xml:space="preserve">
|
||||
<value>Limit the number of applications returned from the top level</value>
|
||||
</data>
|
||||
<data name="limit_fallback_results_source_description" xml:space="preserve">
|
||||
<value>Limit fallback results to n apps</value>
|
||||
</data>
|
||||
<data name="limit_0" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="limit_none" xml:space="preserve">
|
||||
<value>Unlimited</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -79,16 +79,22 @@ public sealed partial class TimeDateCalculator
|
||||
}
|
||||
else
|
||||
{
|
||||
List<(int Score, AvailableResult Item)> itemScores = [];
|
||||
|
||||
// Generate filtered list of results
|
||||
foreach (var f in availableFormats)
|
||||
{
|
||||
var score = f.Score(query, f.Label, f.AlternativeSearchTag);
|
||||
|
||||
if (score > 0)
|
||||
{
|
||||
results.Add(f.ToListItem());
|
||||
itemScores.Add((score, f));
|
||||
}
|
||||
}
|
||||
|
||||
results = itemScores
|
||||
.OrderByDescending(s => s.Score)
|
||||
.Select(s => s.Item.ToListItem())
|
||||
.ToList();
|
||||
}
|
||||
|
||||
if (results.Count == 0)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
// 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.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Resources;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Classes;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Properties;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Networking.NetworkOperators;
|
||||
using Windows.UI;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowsSettings.Commands;
|
||||
|
||||
internal sealed partial class CopySettingCommand : InvokableCommand
|
||||
{
|
||||
private readonly WindowsSetting _entry;
|
||||
|
||||
internal CopySettingCommand(WindowsSetting entry)
|
||||
{
|
||||
Name = Resources.CopyCommand;
|
||||
Icon = Icons.CopyIcon;
|
||||
_entry = entry;
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
ClipboardHelper.SetText(_entry.Command);
|
||||
|
||||
return CommandResult.Dismiss();
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ internal static class ContextMenuHelper
|
||||
{
|
||||
var list = new List<CommandContextItem>(1)
|
||||
{
|
||||
new(new CopySettingCommand(entry)),
|
||||
new(new CopyTextCommand(entry.Command) { Name = Resources.CopyCommand }),
|
||||
};
|
||||
|
||||
return list;
|
||||
|
||||
@@ -43,13 +43,18 @@ public partial class ListHelpers
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FilterList<T>(IEnumerable<T> items, string query, Func<string, T, int> scoreFunction)
|
||||
{
|
||||
return FilterListWithScores<T>(items, query, scoreFunction)
|
||||
.Select(score => score.Item);
|
||||
}
|
||||
|
||||
public static IEnumerable<Scored<T>> FilterListWithScores<T>(IEnumerable<T> items, string query, Func<string, T, int> scoreFunction)
|
||||
{
|
||||
var scores = items
|
||||
.Select(li => new Scored<T>() { Item = li, Score = scoreFunction(query, li) })
|
||||
.Where(score => score.Score > 0)
|
||||
.OrderByDescending(score => score.Score);
|
||||
return scores
|
||||
.Select(score => score.Item);
|
||||
return scores;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -43,11 +43,32 @@ private:
|
||||
//contains the non localized key of the powertoy
|
||||
std::wstring app_key;
|
||||
|
||||
// Update registration based on enabled state
|
||||
void UpdateRegistration(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
ImageResizerRuntimeRegistration::EnsureRegistered();
|
||||
Logger::info(L"ImageResizer context menu registered");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
ImageResizerRuntimeRegistration::Unregister();
|
||||
Logger::info(L"ImageResizer context menu unregistered");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
ImageResizerModule()
|
||||
{
|
||||
m_enabled = CSettingsInstance().GetEnabled();
|
||||
UpdateRegistration(m_enabled);
|
||||
app_name = GET_RESOURCE_STRING(IDS_IMAGERESIZER);
|
||||
app_key = ImageResizerConstants::ModuleKey;
|
||||
LoggerHelpers::init_logger(app_key, L"ModuleInterface", LogSettings::imageResizerLoggerName);
|
||||
@@ -112,10 +133,7 @@ public:
|
||||
package::RegisterSparsePackage(path, packageUri);
|
||||
}
|
||||
}
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
ImageResizerRuntimeRegistration::EnsureRegistered();
|
||||
#endif
|
||||
|
||||
UpdateRegistration(m_enabled);
|
||||
Trace::EnableImageResizer(m_enabled);
|
||||
}
|
||||
|
||||
@@ -123,11 +141,8 @@ public:
|
||||
virtual void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
UpdateRegistration(m_enabled);
|
||||
Trace::EnableImageResizer(m_enabled);
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
ImageResizerRuntimeRegistration::Unregister();
|
||||
Logger::info(L"ImageResizer context menu unregistered (Win10)");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
|
||||
@@ -168,6 +168,25 @@ private:
|
||||
//contains the non localized key of the powertoy
|
||||
std::wstring app_key;
|
||||
|
||||
// Update registration based on enabled state
|
||||
void UpdateRegistration(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
PowerRenameRuntimeRegistration::EnsureRegistered();
|
||||
Logger::info(L"PowerRename context menu registered");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
PowerRenameRuntimeRegistration::Unregister();
|
||||
Logger::info(L"PowerRename context menu unregistered");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// Return the localized display name of the powertoy
|
||||
virtual PCWSTR get_name() override
|
||||
@@ -202,9 +221,7 @@ public:
|
||||
package::RegisterSparsePackage(path, packageUri);
|
||||
}
|
||||
}
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
PowerRenameRuntimeRegistration::EnsureRegistered();
|
||||
#endif
|
||||
UpdateRegistration(m_enabled);
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
@@ -212,10 +229,7 @@ public:
|
||||
{
|
||||
m_enabled = false;
|
||||
Logger::info(L"PowerRename disabled");
|
||||
#if defined(ENABLE_REGISTRATION) || defined(NDEBUG)
|
||||
PowerRenameRuntimeRegistration::Unregister();
|
||||
Logger::info(L"PowerRename context menu unregistered (Win10)");
|
||||
#endif
|
||||
UpdateRegistration(m_enabled);
|
||||
}
|
||||
|
||||
// Returns if the powertoy is enabled
|
||||
@@ -315,6 +329,7 @@ public:
|
||||
void init_settings()
|
||||
{
|
||||
m_enabled = CSettingsInstance().GetEnabled();
|
||||
UpdateRegistration(m_enabled);
|
||||
Trace::EnablePowerRename(m_enabled);
|
||||
}
|
||||
|
||||
|
||||
44
src/settings-ui/Settings.UI.Library/SettingEntry.cs
Normal file
44
src/settings-ui/Settings.UI.Library/SettingEntry.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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 Settings.UI.Library
|
||||
{
|
||||
public enum EntryType
|
||||
{
|
||||
SettingsPage,
|
||||
SettingsCard,
|
||||
SettingsExpander,
|
||||
}
|
||||
|
||||
public struct SettingEntry
|
||||
{
|
||||
public EntryType Type { get; set; }
|
||||
|
||||
public string Header { get; set; }
|
||||
|
||||
public string PageTypeName { get; set; }
|
||||
|
||||
public string ElementName { get; set; }
|
||||
|
||||
public string ElementUid { get; set; }
|
||||
|
||||
public string ParentElementName { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public string Icon { get; set; }
|
||||
|
||||
public SettingEntry(EntryType type, string header, string pageTypeName, string elementName, string elementUid, string parentElementName = null, string description = null, string icon = null)
|
||||
{
|
||||
Type = type;
|
||||
Header = header;
|
||||
PageTypeName = pageTypeName;
|
||||
ElementName = elementName;
|
||||
ElementUid = elementUid;
|
||||
ParentElementName = parentElementName;
|
||||
Description = description;
|
||||
Icon = icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// 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.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Microsoft.PowerToys.Tools.XamlIndexBuilder
|
||||
{
|
||||
public static class ModuleIconResolver
|
||||
{
|
||||
// Hardcoded page-level overrides for module -> icon path
|
||||
private static readonly System.Collections.Generic.Dictionary<string, string> FileNameOverrides = new System.Collections.Generic.Dictionary<string, string>(System.StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
// Example overrides; expand as needed
|
||||
{ "FancyZonesPage.xaml", "/Assets/Settings/Icons/FancyZones.png" },
|
||||
{ "FileLocksmithPage.xaml", "/Assets/Settings/Icons/FileLocksmith.png" },
|
||||
{ "CmdNotFoundPage.xaml", "/Assets/Settings/Icons/CommandNotFound.png" },
|
||||
{ "PowerLauncherPage.xaml", "/Assets/Settings/Icons/PowerToysRun.png" },
|
||||
};
|
||||
|
||||
// Contract:
|
||||
// - Input: absolute path to the module XAML file (e.g., FancyZonesPage.xaml)
|
||||
// - Output: app-relative icon path (e.g., "/Assets/Settings/Icons/FancyZones.png"), or null if not found
|
||||
// - Strategy: take the first SettingsCard under the page and read its HeaderIcon value
|
||||
public static string ResolveIconFromFirstSettingsCard(string xamlFilePath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(xamlFilePath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var doc = XDocument.Load(xamlFilePath);
|
||||
|
||||
// Prefer looking inside SettingsPageControl.ModuleContent to avoid picking cards in Resources/DataTemplates
|
||||
var pageControl = doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "SettingsPageControl");
|
||||
|
||||
if (pageControl != null)
|
||||
{
|
||||
// Locate the property element <SettingsPageControl.ModuleContent>
|
||||
var moduleContent = pageControl
|
||||
.Elements()
|
||||
.FirstOrDefault(e => e.Name.LocalName.EndsWith(".ModuleContent", System.StringComparison.OrdinalIgnoreCase))
|
||||
?? pageControl
|
||||
.Descendants()
|
||||
.FirstOrDefault(e => e.Name.LocalName.EndsWith(".ModuleContent", System.StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (moduleContent != null)
|
||||
{
|
||||
// Find the first SettingsCard under ModuleContent and try to read its HeaderIcon
|
||||
var firstCardUnderModule = moduleContent
|
||||
.Descendants()
|
||||
.FirstOrDefault(e => e.Name.LocalName == "SettingsCard");
|
||||
|
||||
if (firstCardUnderModule != null)
|
||||
{
|
||||
var icon = Program.ExtractIconValue(firstCardUnderModule);
|
||||
if (!string.IsNullOrWhiteSpace(icon))
|
||||
{
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to hardcoded overrides by file name
|
||||
var fileName = Path.GetFileName(xamlFilePath);
|
||||
if (!string.IsNullOrEmpty(fileName) && FileNameOverrides.TryGetValue(fileName, out var overrideIcon))
|
||||
{
|
||||
return overrideIcon;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Non-fatal: let caller decide fallback
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
436
src/settings-ui/Settings.UI.XamlIndexBuilder/Program.cs
Normal file
436
src/settings-ui/Settings.UI.XamlIndexBuilder/Program.cs
Normal file
@@ -0,0 +1,436 @@
|
||||
// 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.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Microsoft.PowerToys.Tools.XamlIndexBuilder
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
private static readonly HashSet<string> ExcludedXamlFiles = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"ShellPage.xaml",
|
||||
};
|
||||
|
||||
// Hardcoded panel-to-page mapping (temporary until generic panel host mapping is needed)
|
||||
// Key: panel file base name (without .xaml), Value: owning page base name
|
||||
private static readonly Dictionary<string, string> PanelPageMapping = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "MouseJumpPanel", "MouseUtilsPage" },
|
||||
};
|
||||
|
||||
private static JsonSerializerOptions serializeOption = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
};
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
Debug.WriteLine("Usage: XamlIndexBuilder <xaml-directory> <output-json-file>");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
string xamlRootDirectory = args[0];
|
||||
string outputFile = args[1];
|
||||
|
||||
if (!Directory.Exists(xamlRootDirectory))
|
||||
{
|
||||
Debug.WriteLine($"Error: Directory '{xamlRootDirectory}' does not exist.");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var searchableElements = new List<SettingEntry>();
|
||||
var processedFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
void ScanDirectory(string root)
|
||||
{
|
||||
if (!Directory.Exists(root))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[XamlIndexBuilder] Scanning root: {root}");
|
||||
var xamlFilesLocal = Directory.GetFiles(root, "*.xaml", SearchOption.AllDirectories);
|
||||
foreach (var xamlFile in xamlFilesLocal)
|
||||
{
|
||||
var fullPath = Path.GetFullPath(xamlFile);
|
||||
if (processedFiles.Contains(fullPath))
|
||||
{
|
||||
continue; // already handled (can happen if overlapping directories)
|
||||
}
|
||||
|
||||
var fileName = Path.GetFileName(xamlFile);
|
||||
if (ExcludedXamlFiles.Contains(fileName))
|
||||
{
|
||||
continue; // explicitly excluded
|
||||
}
|
||||
|
||||
Debug.WriteLine($"Processing: {fileName}");
|
||||
var elements = ExtractSearchableElements(xamlFile);
|
||||
|
||||
// Apply hardcoded panel mapping override
|
||||
var baseName = Path.GetFileNameWithoutExtension(xamlFile);
|
||||
if (PanelPageMapping.TryGetValue(baseName, out var hostPage))
|
||||
{
|
||||
for (int i = 0; i < elements.Count; i++)
|
||||
{
|
||||
var entry = elements[i];
|
||||
entry.PageTypeName = hostPage;
|
||||
elements[i] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
searchableElements.AddRange(elements);
|
||||
processedFiles.Add(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Scan well-known subdirectories under the provided root
|
||||
var subDirs = new[] { "Views", "Panels" };
|
||||
foreach (var sub in subDirs)
|
||||
{
|
||||
ScanDirectory(Path.Combine(xamlRootDirectory, sub));
|
||||
}
|
||||
|
||||
// Fallback: also scan root directly (in case some XAML lives at root level)
|
||||
ScanDirectory(xamlRootDirectory);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Explicit include section: add specific XAML files that we always want indexed
|
||||
// even if future logic excludes them or they live outside typical scan patterns.
|
||||
// Add future files to the ExplicitExtraXamlFiles array below.
|
||||
// -----------------------------------------------------------------------------
|
||||
string[] explicitExtraXamlFiles = new[]
|
||||
{
|
||||
"MouseJumpPanel.xaml", // Mouse Jump settings panel
|
||||
};
|
||||
|
||||
foreach (var extraFileName in explicitExtraXamlFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
var matches = Directory.GetFiles(xamlRootDirectory, extraFileName, SearchOption.AllDirectories);
|
||||
foreach (var match in matches)
|
||||
{
|
||||
var full = Path.GetFullPath(match);
|
||||
if (processedFiles.Contains(full))
|
||||
{
|
||||
continue; // already processed in general scan
|
||||
}
|
||||
|
||||
Debug.WriteLine($"Processing (explicit include): {extraFileName}");
|
||||
var elements = ExtractSearchableElements(full);
|
||||
var baseName = Path.GetFileNameWithoutExtension(full);
|
||||
if (PanelPageMapping.TryGetValue(baseName, out var hostPage))
|
||||
{
|
||||
for (int i = 0; i < elements.Count; i++)
|
||||
{
|
||||
var entry = elements[i];
|
||||
entry.PageTypeName = hostPage;
|
||||
elements[i] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
searchableElements.AddRange(elements);
|
||||
processedFiles.Add(full);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Explicit include failed for {extraFileName}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
searchableElements = searchableElements.OrderBy(e => e.PageTypeName).ThenBy(e => e.ElementName).ToList();
|
||||
|
||||
string json = JsonSerializer.Serialize(searchableElements, serializeOption);
|
||||
File.WriteAllText(outputFile, json);
|
||||
|
||||
Debug.WriteLine($"Successfully generated index with {searchableElements.Count} elements.");
|
||||
Debug.WriteLine($"Output written to: {outputFile}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Error: {ex.Message}");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SettingEntry> ExtractSearchableElements(string xamlFile)
|
||||
{
|
||||
var elements = new List<SettingEntry>();
|
||||
string pageName = Path.GetFileNameWithoutExtension(xamlFile);
|
||||
|
||||
try
|
||||
{
|
||||
// Load XAML as XML
|
||||
var doc = XDocument.Load(xamlFile);
|
||||
|
||||
// Define namespaces
|
||||
XNamespace x = "http://schemas.microsoft.com/winfx/2006/xaml";
|
||||
XNamespace controls = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
|
||||
XNamespace labs = "using:CommunityToolkit.Labs.WinUI";
|
||||
XNamespace winui = "using:CommunityToolkit.WinUI.UI.Controls";
|
||||
|
||||
// Extract SettingsPageControl elements
|
||||
var settingsPageElements = doc.Descendants()
|
||||
.Where(e => e.Name.LocalName == "SettingsPageControl")
|
||||
.Where(e => e.Attribute(x + "Uid") != null);
|
||||
|
||||
// Extract SettingsCard elements (support both Name and x:Name)
|
||||
var settingsElements = doc.Descendants()
|
||||
.Where(e => e.Name.LocalName == "SettingsCard")
|
||||
.Where(e => e.Attribute("Name") != null || e.Attribute(x + "Name") != null || e.Attribute(x + "Uid") != null);
|
||||
|
||||
// Extract SettingsExpander elements (support both Name and x:Name)
|
||||
var settingsExpanderElements = doc.Descendants()
|
||||
.Where(e => e.Name.LocalName == "SettingsExpander")
|
||||
.Where(e => e.Attribute("Name") != null || e.Attribute(x + "Name") != null || e.Attribute(x + "Uid") != null);
|
||||
|
||||
// Process SettingsPageControl elements
|
||||
foreach (var element in settingsPageElements)
|
||||
{
|
||||
var elementUid = GetElementUid(element, x);
|
||||
|
||||
// Prefer the first SettingsCard.HeaderIcon as the module icon
|
||||
var moduleImageSource = ModuleIconResolver.ResolveIconFromFirstSettingsCard(xamlFile);
|
||||
|
||||
if (!string.IsNullOrEmpty(elementUid))
|
||||
{
|
||||
elements.Add(new SettingEntry
|
||||
{
|
||||
PageTypeName = pageName,
|
||||
Type = EntryType.SettingsPage,
|
||||
ParentElementName = string.Empty,
|
||||
ElementName = string.Empty,
|
||||
ElementUid = elementUid,
|
||||
Icon = moduleImageSource,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Process SettingsCard elements
|
||||
foreach (var element in settingsElements)
|
||||
{
|
||||
var elementName = GetElementName(element, x);
|
||||
var elementUid = GetElementUid(element, x);
|
||||
var headerIcon = ExtractIconValue(element);
|
||||
|
||||
if (!string.IsNullOrEmpty(elementName) || !string.IsNullOrEmpty(elementUid))
|
||||
{
|
||||
var parentElementName = GetParentElementName(element, x);
|
||||
|
||||
elements.Add(new SettingEntry
|
||||
{
|
||||
PageTypeName = pageName,
|
||||
Type = EntryType.SettingsCard,
|
||||
ParentElementName = parentElementName,
|
||||
ElementName = elementName,
|
||||
ElementUid = elementUid,
|
||||
Icon = headerIcon,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Process SettingsExpander elements
|
||||
foreach (var element in settingsExpanderElements)
|
||||
{
|
||||
var elementName = GetElementName(element, x);
|
||||
var elementUid = GetElementUid(element, x);
|
||||
var headerIcon = ExtractIconValue(element);
|
||||
|
||||
if (!string.IsNullOrEmpty(elementName) || !string.IsNullOrEmpty(elementUid))
|
||||
{
|
||||
var parentElementName = GetParentElementName(element, x);
|
||||
|
||||
elements.Add(new SettingEntry
|
||||
{
|
||||
PageTypeName = pageName,
|
||||
Type = EntryType.SettingsExpander,
|
||||
ParentElementName = parentElementName,
|
||||
ElementName = elementName,
|
||||
ElementUid = elementUid,
|
||||
Icon = headerIcon,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Error processing {xamlFile}: {ex.Message}");
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
public static string GetElementName(XElement element, XNamespace x)
|
||||
{
|
||||
var name = element.Attribute("Name")?.Value;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = element.Attribute(x + "Name")?.Value;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public static string GetElementUid(XElement element, XNamespace x)
|
||||
{
|
||||
// Try x:Uid on the element itself
|
||||
var uid = element.Attribute(x + "Uid")?.Value;
|
||||
if (!string.IsNullOrWhiteSpace(uid))
|
||||
{
|
||||
return uid;
|
||||
}
|
||||
|
||||
// Fallback: check the first direct child element's x:Uid
|
||||
var firstChild = element.Elements().FirstOrDefault();
|
||||
if (firstChild != null)
|
||||
{
|
||||
var childUid = firstChild.Attribute(x + "Uid")?.Value;
|
||||
if (!string.IsNullOrWhiteSpace(childUid))
|
||||
{
|
||||
return childUid;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetParentElementName(XElement element, XNamespace x)
|
||||
{
|
||||
// Look for parent SettingsExpander
|
||||
var current = element.Parent;
|
||||
while (current != null)
|
||||
{
|
||||
// Check if we're inside a SettingsExpander.Items or just directly inside SettingsExpander
|
||||
if (current.Name.LocalName == "Items")
|
||||
{
|
||||
// Check if the parent of Items is SettingsExpander
|
||||
var expanderParent = current.Parent;
|
||||
if (expanderParent?.Name.LocalName == "SettingsExpander")
|
||||
{
|
||||
var expanderName = expanderParent.Attribute("Name")?.Value;
|
||||
if (string.IsNullOrEmpty(expanderName))
|
||||
{
|
||||
expanderName = expanderParent.Attribute(x + "Name")?.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(expanderName))
|
||||
{
|
||||
return expanderName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (current.Name.LocalName == "SettingsExpander")
|
||||
{
|
||||
// Direct child of SettingsExpander
|
||||
var expanderName = current.Attribute("Name")?.Value;
|
||||
if (string.IsNullOrEmpty(expanderName))
|
||||
{
|
||||
expanderName = current.Attribute(x + "Name")?.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(expanderName))
|
||||
{
|
||||
return expanderName;
|
||||
}
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public static string ExtractIconValue(XElement element)
|
||||
{
|
||||
var headerIconAttribute = element.Attribute("HeaderIcon")?.Value;
|
||||
|
||||
if (string.IsNullOrEmpty(headerIconAttribute))
|
||||
{
|
||||
// Try nested property element: <SettingsCard.HeaderIcon> ... </SettingsCard.HeaderIcon>
|
||||
var headerIconProperty = element.Elements()
|
||||
.FirstOrDefault(e => e.Name.LocalName.EndsWith(".HeaderIcon", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (headerIconProperty != null)
|
||||
{
|
||||
// Prefer explicit icon elements within the HeaderIcon property
|
||||
var pathIcon = headerIconProperty.Descendants().FirstOrDefault(d => d.Name.LocalName == "PathIcon");
|
||||
if (pathIcon != null)
|
||||
{
|
||||
var dataAttr = pathIcon.Attribute("Data")?.Value;
|
||||
if (!string.IsNullOrWhiteSpace(dataAttr))
|
||||
{
|
||||
return dataAttr.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
var fontIcon = headerIconProperty.Descendants().FirstOrDefault(d => d.Name.LocalName == "FontIcon");
|
||||
if (fontIcon != null)
|
||||
{
|
||||
var glyphAttr = fontIcon.Attribute("Glyph")?.Value;
|
||||
if (!string.IsNullOrWhiteSpace(glyphAttr))
|
||||
{
|
||||
return glyphAttr.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
var bitmapIcon = headerIconProperty.Descendants().FirstOrDefault(d => d.Name.LocalName == "BitmapIcon");
|
||||
if (bitmapIcon != null)
|
||||
{
|
||||
var sourceAttr = bitmapIcon.Attribute("Source")?.Value;
|
||||
if (!string.IsNullOrWhiteSpace(sourceAttr))
|
||||
{
|
||||
return sourceAttr.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Parse different icon markup extensions
|
||||
// Example: {ui:BitmapIcon Source=/Assets/Settings/Icons/AlwaysOnTop.png}
|
||||
if (headerIconAttribute.Contains("BitmapIcon") && headerIconAttribute.Contains("Source="))
|
||||
{
|
||||
var sourceStart = headerIconAttribute.IndexOf("Source=", StringComparison.OrdinalIgnoreCase) + "Source=".Length;
|
||||
var sourceEnd = headerIconAttribute.IndexOf('}', sourceStart);
|
||||
if (sourceEnd == -1)
|
||||
{
|
||||
sourceEnd = headerIconAttribute.Length;
|
||||
}
|
||||
|
||||
return headerIconAttribute.Substring(sourceStart, sourceEnd - sourceStart).Trim();
|
||||
}
|
||||
|
||||
// Example: {ui:FontIcon Glyph=}
|
||||
if (headerIconAttribute.Contains("FontIcon") && headerIconAttribute.Contains("Glyph="))
|
||||
{
|
||||
var glyphStart = headerIconAttribute.IndexOf("Glyph=", StringComparison.OrdinalIgnoreCase) + "Glyph=".Length;
|
||||
var glyphEnd = headerIconAttribute.IndexOf('}', glyphStart);
|
||||
if (glyphEnd == -1)
|
||||
{
|
||||
glyphEnd = headerIconAttribute.Length;
|
||||
}
|
||||
|
||||
return headerIconAttribute.Substring(glyphStart, glyphEnd - glyphStart).Trim();
|
||||
}
|
||||
|
||||
// If it doesn't match known patterns, return the original value
|
||||
return headerIconAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/settings-ui/Settings.UI.XamlIndexBuilder/SettingEntry.cs
Normal file
44
src/settings-ui/Settings.UI.XamlIndexBuilder/SettingEntry.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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.PowerToys.Tools.XamlIndexBuilder
|
||||
{
|
||||
public enum EntryType
|
||||
{
|
||||
SettingsPage,
|
||||
SettingsCard,
|
||||
SettingsExpander,
|
||||
}
|
||||
|
||||
public struct SettingEntry
|
||||
{
|
||||
public EntryType Type { get; set; }
|
||||
|
||||
public string Header { get; set; }
|
||||
|
||||
public string PageTypeName { get; set; }
|
||||
|
||||
public string ElementName { get; set; }
|
||||
|
||||
public string ElementUid { get; set; }
|
||||
|
||||
public string ParentElementName { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public string Icon { get; set; }
|
||||
|
||||
public SettingEntry(EntryType type, string header, string pageTypeName, string elementName, string elementUid, string parentElementName = null, string description = null, string icon = null)
|
||||
{
|
||||
Type = type;
|
||||
Header = header;
|
||||
PageTypeName = pageTypeName;
|
||||
ElementName = elementName;
|
||||
ElementUid = elementUid;
|
||||
ParentElementName = parentElementName;
|
||||
Description = description;
|
||||
Icon = icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Import common props to satisfy repo audit; override problematic bits below for this console tool. -->
|
||||
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Microsoft.PowerToys.Tools.XamlIndexBuilder</RootNamespace>
|
||||
<AssemblyName>XamlIndexBuilder</AssemblyName>
|
||||
<!-- Platform-agnostic: framework-dependent DLL executed via dotnet -->
|
||||
<SelfContained>false</SelfContained>
|
||||
<UseAppHost>false</UseAppHost>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<RuntimeIdentifier></RuntimeIdentifier>
|
||||
<!-- Keep tool output out of product scan paths to avoid deps.json audit conflicts -->
|
||||
<OutputPath>$(MSBuildProjectDirectory)\obj\XamlIndexBuilder\$(Configuration)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Remove CsWinRT package introduced by common props; not needed for this tool and causes Windows metadata errors -->
|
||||
<ItemGroup>
|
||||
<PackageReference Remove="Microsoft.Windows.CsWinRT" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" />
|
||||
<PackageReference Include="System.CommandLine" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Remove UI library reference to avoid pulling WindowsDesktop runtime (WindowsBase) -->
|
||||
|
||||
<PropertyGroup>
|
||||
<DotNetExe Condition="'$(DotNetExe)' == ''">dotnet</DotNetExe>
|
||||
<XamlRootDir Condition="'$(XamlRootDir)' == ''">$(MSBuildProjectDirectory)\..\Settings.UI\SettingsXAML</XamlRootDir>
|
||||
<XamlRootDir Condition="'$(XamlViewsDir)' != ''">$([System.IO.Path]::GetDirectoryName('$(XamlViewsDir)'))</XamlRootDir>
|
||||
<GeneratedJsonFile Condition="'$(GeneratedJsonFile)' == ''">$(MSBuildProjectDirectory)\..\Settings.UI\Assets\Settings\search.index.json</GeneratedJsonFile>
|
||||
</PropertyGroup>
|
||||
<Target Name="GenerateSearchIndexSelf" AfterTargets="Build">
|
||||
<RemoveDir Directories="$(MSBuildProjectDirectory)\obj\ARM64;$(MSBuildProjectDirectory)\obj\x64;$(MSBuildProjectDirectory)\bin" />
|
||||
<MakeDir Directories="$([System.IO.Path]::GetDirectoryName('$(GeneratedJsonFile)'))" />
|
||||
<Message Importance="high" Text="[XamlIndexBuilder] Generating search index. Root='$(XamlRootDir)'; Out='$(GeneratedJsonFile)'; Tool='$(TargetPath)'; DotNet='$(DotNetExe)'." />
|
||||
<Exec Command=""$(DotNetExe)" "$(TargetPath)" "$(XamlRootDir)" "$(GeneratedJsonFile)"" />
|
||||
</Target>
|
||||
</Project>
|
||||
133
src/settings-ui/Settings.UI/Converters/IconConverter.cs
Normal file
133
src/settings-ui/Settings.UI/Converters/IconConverter.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
// 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 Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Markup;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||
{
|
||||
public partial class IconConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is not string iconValue || string.IsNullOrEmpty(iconValue))
|
||||
{
|
||||
// Return a default icon based on the parameter
|
||||
var defaultGlyph = parameter?.ToString() ?? "\uE8B7"; // Default gear icon
|
||||
return new FontIcon { Glyph = defaultGlyph };
|
||||
}
|
||||
|
||||
// Check if it's a single Unicode character (most common case after JSON deserialization)
|
||||
if (iconValue.Length == 1)
|
||||
{
|
||||
return new FontIcon { Glyph = iconValue };
|
||||
}
|
||||
|
||||
// Handle HTML numeric character references, e.g. "" or ""
|
||||
if (iconValue.StartsWith("&#", StringComparison.Ordinal) && iconValue.EndsWith(';'))
|
||||
{
|
||||
var inner = iconValue.Substring(2, iconValue.Length - 3); // strip &# and ;
|
||||
try
|
||||
{
|
||||
string glyph;
|
||||
if (inner.StartsWith("x", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var hex = inner.Substring(1);
|
||||
if (int.TryParse(hex, System.Globalization.NumberStyles.HexNumber, null, out int codePointHex))
|
||||
{
|
||||
glyph = char.ConvertFromUtf32(codePointHex);
|
||||
return new FontIcon { Glyph = glyph };
|
||||
}
|
||||
}
|
||||
else if (int.TryParse(inner, out int codePointDec))
|
||||
{
|
||||
glyph = char.ConvertFromUtf32(codePointDec);
|
||||
return new FontIcon { Glyph = glyph };
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// fall through to other handlers
|
||||
}
|
||||
}
|
||||
|
||||
if (iconValue.StartsWith("\\u", StringComparison.OrdinalIgnoreCase) && iconValue.Length == 6)
|
||||
{
|
||||
var hexPart = iconValue.Substring(2); // Remove \u
|
||||
if (int.TryParse(hexPart, System.Globalization.NumberStyles.HexNumber, null, out int codePoint))
|
||||
{
|
||||
var unicodeChar = char.ConvertFromUtf32(codePoint);
|
||||
return new FontIcon { Glyph = unicodeChar };
|
||||
}
|
||||
}
|
||||
|
||||
// Check if it's an image path
|
||||
if (iconValue.Contains('/') || iconValue.Contains('\\') || iconValue.Contains(".png", StringComparison.OrdinalIgnoreCase) || iconValue.Contains(".jpg", StringComparison.OrdinalIgnoreCase) || iconValue.Contains(".ico", StringComparison.OrdinalIgnoreCase) || iconValue.Contains(".svg", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Handle different path formats
|
||||
var imagePath = iconValue;
|
||||
|
||||
// Convert ms-appx:/// paths to local paths
|
||||
if (imagePath.StartsWith("ms-appx:///", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
imagePath = imagePath.Substring("ms-appx:///".Length);
|
||||
}
|
||||
|
||||
// Ensure path starts with /
|
||||
if (!imagePath.StartsWith('/'))
|
||||
{
|
||||
imagePath = "/" + imagePath;
|
||||
}
|
||||
|
||||
var uri = new Uri($"ms-appx://{imagePath}");
|
||||
|
||||
if (imagePath.EndsWith(".svg", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Render SVG using ImageIcon + SvgImageSource
|
||||
return new ImageIcon
|
||||
{
|
||||
Source = new SvgImageSource(uri),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return new BitmapIcon
|
||||
{
|
||||
UriSource = uri,
|
||||
ShowAsMonochrome = false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Try to interpret as raw SVG path data (PathIcon.Data)
|
||||
// Many of our XAML PathIcon usages (e.g., AdvancedPastePage) provide a Data string like "M128 766q0-42 ...".
|
||||
// If parsing succeeds, render it as a PathIcon.
|
||||
try
|
||||
{
|
||||
var geometryObj = XamlBindingHelper.ConvertValue(typeof(Geometry), iconValue);
|
||||
if (geometryObj is Geometry geometry)
|
||||
{
|
||||
return new PathIcon { Data = geometry };
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore parse errors and fall back below.
|
||||
}
|
||||
|
||||
// If all else fails, return default icon
|
||||
var fallbackGlyph = parameter?.ToString() ?? "\uE8B7";
|
||||
return new FontIcon { Glyph = fallbackGlyph };
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// 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 Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters;
|
||||
|
||||
public sealed partial class SearchSuggestionTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
public DataTemplate DefaultSuggestionTemplate { get; set; }
|
||||
|
||||
public DataTemplate NoResultsSuggestionTemplate { get; set; }
|
||||
|
||||
public DataTemplate ShowAllSuggestionTemplate { get; set; }
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
||||
{
|
||||
if (item is SuggestionItem suggestionItem)
|
||||
{
|
||||
if (suggestionItem.IsNoResults)
|
||||
{
|
||||
return NoResultsSuggestionTemplate;
|
||||
}
|
||||
|
||||
if (suggestionItem.IsShowAll)
|
||||
{
|
||||
return ShowAllSuggestionTemplate ?? NoResultsSuggestionTemplate ?? DefaultSuggestionTemplate;
|
||||
}
|
||||
|
||||
return DefaultSuggestionTemplate;
|
||||
}
|
||||
|
||||
return DefaultSuggestionTemplate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// 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 System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||
{
|
||||
public sealed partial class UriToImageSourceConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
return value is Uri uri ? new BitmapImage(uri) : null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
=> throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
244
src/settings-ui/Settings.UI/Helpers/NavigablePage.cs
Normal file
244
src/settings-ui/Settings.UI/Helpers/NavigablePage.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
// 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.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.WinUI.Controls;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Hosting;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Windows.UI;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
|
||||
public abstract partial class NavigablePage : Page
|
||||
{
|
||||
private const int ExpandWaitDuration = 500;
|
||||
private const int AnimationDuration = 1850;
|
||||
|
||||
private NavigationParams _pendingNavigationParams;
|
||||
|
||||
public NavigablePage()
|
||||
{
|
||||
Loaded += OnPageLoaded;
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(Microsoft.UI.Xaml.Navigation.NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
// Handle both old string parameter and new NavigationParams
|
||||
if (e.Parameter is NavigationParams navParams)
|
||||
{
|
||||
_pendingNavigationParams = navParams;
|
||||
}
|
||||
else if (e.Parameter is string elementKey)
|
||||
{
|
||||
_pendingNavigationParams = new NavigationParams(elementKey);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnPageLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_pendingNavigationParams != null && !string.IsNullOrEmpty(_pendingNavigationParams.ElementName))
|
||||
{
|
||||
// First, expand parent if specified
|
||||
if (!string.IsNullOrEmpty(_pendingNavigationParams.ParentElementName))
|
||||
{
|
||||
var parentElement = FindElementByName(_pendingNavigationParams.ParentElementName);
|
||||
if (parentElement is SettingsExpander expander)
|
||||
{
|
||||
expander.IsExpanded = true;
|
||||
|
||||
// Give time for the expander to animate
|
||||
await Task.Delay(ExpandWaitDuration);
|
||||
}
|
||||
}
|
||||
|
||||
// Then find and navigate to the target element
|
||||
var target = FindElementByName(_pendingNavigationParams.ElementName);
|
||||
|
||||
target?.StartBringIntoView(new BringIntoViewOptions
|
||||
{
|
||||
VerticalOffset = -20,
|
||||
AnimationDesired = true,
|
||||
});
|
||||
|
||||
await OnTargetElementNavigatedAsync(target, _pendingNavigationParams.ElementName);
|
||||
|
||||
_pendingNavigationParams = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual async Task OnTargetElementNavigatedAsync(FrameworkElement target, string elementKey)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to set keyboard focus so that screen readers announce the element and keyboard users land directly on it.
|
||||
TrySetFocus(target);
|
||||
|
||||
// Get the visual and compositor
|
||||
var visual = ElementCompositionPreview.GetElementVisual(target);
|
||||
var compositor = visual.Compositor;
|
||||
|
||||
// Create a subtle glow effect using drop shadow
|
||||
var dropShadow = compositor.CreateDropShadow();
|
||||
dropShadow.Color = (Color)Application.Current.Resources["SystemAccentColorLight2"];
|
||||
dropShadow.BlurRadius = 16f;
|
||||
dropShadow.Opacity = 0f;
|
||||
dropShadow.Offset = new Vector3(0, 0, 0);
|
||||
|
||||
var spriteVisual = compositor.CreateSpriteVisual();
|
||||
spriteVisual.Size = new Vector2((float)target.ActualWidth + 8, (float)target.ActualHeight + 8);
|
||||
spriteVisual.Shadow = dropShadow;
|
||||
spriteVisual.Offset = new Vector3(-4, -4, 0);
|
||||
|
||||
// Insert the shadow visual behind the target element
|
||||
ElementCompositionPreview.SetElementChildVisual(target, spriteVisual);
|
||||
|
||||
// Create a simple fade in/out animation
|
||||
var fadeAnimation = compositor.CreateScalarKeyFrameAnimation();
|
||||
fadeAnimation.InsertKeyFrame(0f, 0f);
|
||||
fadeAnimation.InsertKeyFrame(0.5f, 0.3f);
|
||||
fadeAnimation.InsertKeyFrame(1f, 0f);
|
||||
fadeAnimation.Duration = TimeSpan.FromMilliseconds(AnimationDuration);
|
||||
|
||||
dropShadow.StartAnimation("Opacity", fadeAnimation);
|
||||
await Task.Delay(AnimationDuration);
|
||||
|
||||
// Clean up the shadow visual
|
||||
ElementCompositionPreview.SetElementChildVisual(target, null);
|
||||
}
|
||||
|
||||
private static void TrySetFocus(FrameworkElement target)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Prefer Control.Focus when available.
|
||||
if (target is Control ctrl)
|
||||
{
|
||||
// Ensure it can receive focus.
|
||||
if (!ctrl.IsTabStop)
|
||||
{
|
||||
ctrl.IsTabStop = true;
|
||||
}
|
||||
|
||||
ctrl.Focus(FocusState.Programmatic);
|
||||
}
|
||||
|
||||
// Target is not a Control. Find first focusable descendant Control.
|
||||
var focusCandidate = FindFirstFocusableDescendant(target);
|
||||
if (focusCandidate != null)
|
||||
{
|
||||
if (!focusCandidate.IsTabStop)
|
||||
{
|
||||
focusCandidate.IsTabStop = true;
|
||||
}
|
||||
|
||||
focusCandidate.Focus(FocusState.Programmatic);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: attempt to focus parent control if no descendant found.
|
||||
if (target.Parent is Control parent)
|
||||
{
|
||||
if (!parent.IsTabStop)
|
||||
{
|
||||
parent.IsTabStop = true;
|
||||
}
|
||||
|
||||
parent.Focus(FocusState.Programmatic);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Swallow focus exceptions; not critical. Could log if logging enabled.
|
||||
// Leave the default focus as it is.
|
||||
}
|
||||
}
|
||||
|
||||
private static Control FindFirstFocusableDescendant(FrameworkElement root)
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var queue = new System.Collections.Generic.Queue<DependencyObject>();
|
||||
queue.Enqueue(root);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var current = queue.Dequeue();
|
||||
if (current is Control c && c.IsEnabled && c.Visibility == Visibility.Visible)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
int count = VisualTreeHelper.GetChildrenCount(current);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
queue.Enqueue(VisualTreeHelper.GetChild(current, i));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected FrameworkElement FindElementByName(string name)
|
||||
{
|
||||
var element = this.FindName(name) as FrameworkElement;
|
||||
if (element != null)
|
||||
{
|
||||
return element;
|
||||
}
|
||||
|
||||
if (this.Content is DependencyObject root)
|
||||
{
|
||||
var found = FindInDescendants(root, name);
|
||||
if (found != null)
|
||||
{
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static FrameworkElement FindInDescendants(DependencyObject root, string name)
|
||||
{
|
||||
if (root == null || string.IsNullOrEmpty(name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var queue = new System.Collections.Generic.Queue<DependencyObject>();
|
||||
queue.Enqueue(root);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var current = queue.Dequeue();
|
||||
if (current is FrameworkElement fe)
|
||||
{
|
||||
var local = fe.FindName(name) as FrameworkElement;
|
||||
if (local != null)
|
||||
{
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
int count = VisualTreeHelper.GetChildrenCount(current);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(current, i);
|
||||
queue.Enqueue(child);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
18
src/settings-ui/Settings.UI/Helpers/NavigationParams.cs
Normal file
18
src/settings-ui/Settings.UI/Helpers/NavigationParams.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// 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.PowerToys.Settings.UI.Helpers;
|
||||
|
||||
public class NavigationParams
|
||||
{
|
||||
public string ElementName { get; set; }
|
||||
|
||||
public string ParentElementName { get; set; }
|
||||
|
||||
public NavigationParams(string elementName, string parentElementName = null)
|
||||
{
|
||||
ElementName = elementName;
|
||||
ParentElementName = parentElementName;
|
||||
}
|
||||
}
|
||||
@@ -1,161 +1,188 @@
|
||||
<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" />
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\Common.SelfContained.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>Microsoft.PowerToys.Settings.UI</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
|
||||
<WindowsPackageType>None</WindowsPackageType>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<ApplicationIcon>Assets\Settings\icon.ico</ApplicationIcon>
|
||||
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
|
||||
<!-- OutputPath looks like this because it has to be called both by settings and publish.cmd -->
|
||||
<OutputPath>..\..\..\$(Platform)\$(Configuration)\WinUI3Apps</OutputPath>
|
||||
<!-- 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.Settings.pri</ProjectPriFileName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\Settings\Modules\APDialog.dark.png" />
|
||||
<None Remove="Assets\Settings\Modules\APDialog.light.png" />
|
||||
<None Remove="SettingsXAML\Controls\Dashboard\CheckUpdateControl.xaml" />
|
||||
<None Remove="SettingsXAML\Controls\Dashboard\ShortcutConflictControl.xaml" />
|
||||
<None Remove="SettingsXAML\Controls\KeyVisual\KeyCharPresenter.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Remove="SettingsXAML\App.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="SettingsXAML\App.xaml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>Microsoft.PowerToys.Settings.UI</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
|
||||
<WindowsPackageType>None</WindowsPackageType>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<ApplicationIcon>Assets\Settings\icon.ico</ApplicationIcon>
|
||||
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
|
||||
<!-- OutputPath looks like this because it has to be called both by settings and publish.cmd -->
|
||||
<OutputPath>..\..\..\$(Platform)\$(Configuration)\WinUI3Apps</OutputPath>
|
||||
<!-- 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.Settings.pri</ProjectPriFileName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\Settings\Modules\APDialog.dark.png" />
|
||||
<None Remove="Assets\Settings\Modules\APDialog.light.png" />
|
||||
<None Remove="SettingsXAML\Controls\Dashboard\CheckUpdateControl.xaml" />
|
||||
<None Remove="SettingsXAML\Controls\Dashboard\ShortcutConflictControl.xaml" />
|
||||
<None Remove="SettingsXAML\Controls\KeyVisual\KeyCharPresenter.xaml" />
|
||||
<None Remove="SettingsXAML\Controls\TitleBar\TitleBar.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Remove="SettingsXAML\App.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="SettingsXAML\App.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->
|
||||
<PropertyGroup>
|
||||
<CsWinRTIncludes>PowerToys.GPOWrapper;PowerToys.ZoomItSettingsInterop</CsWinRTIncludes>
|
||||
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
</PropertyGroup>
|
||||
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->
|
||||
<PropertyGroup>
|
||||
<CsWinRTIncludes>PowerToys.GPOWrapper;PowerToys.ZoomItSettingsInterop</CsWinRTIncludes>
|
||||
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\Settings\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\Settings\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\Settings\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Assets\Settings\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Settings\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\Settings\StoreLogo.png" />
|
||||
<Content Include="Assets\Settings\Wide310x150Logo.scale-200.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\Settings\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\Settings\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\Settings\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Assets\Settings\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Settings\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\Settings\StoreLogo.png" />
|
||||
<Content Include="Assets\Settings\Wide310x150Logo.scale-200.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Images\MouseJump-Desktop.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Images\MouseJump-Desktop.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Animations" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Extensions" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Markdown" />
|
||||
<PackageReference Include="System.Net.Http" />
|
||||
<PackageReference Include="System.Private.Uri" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" />
|
||||
<PackageReference Include="WinUIEx" />
|
||||
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
|
||||
<PackageReference Include="MessagePack" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" />
|
||||
<PackageReference Include="StreamJsonRpc" />
|
||||
<!-- HACK: Microsoft.Extensions.Hosting is referenced, even if it is not used, to force dll versions to be the same as in other projects. Really only needed since the Experimentation APIs that are added in CI reference some net standard 2.0 assemblies. -->
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||
<!-- HACK: To make sure the version pulled in by Microsoft.Extensions.Hosting is current. -->
|
||||
<PackageReference Include="System.Text.Json" />
|
||||
<!-- This line forces the WebView2 version used by Windows App SDK to be the one we expect from Directory.Packages.props . -->
|
||||
<PackageReference Include="Microsoft.Web.WebView2" />
|
||||
<!-- HACK: CmdPal uses CommunityToolkit.Common directly. Align the version. -->
|
||||
<PackageReference Include="CommunityToolkit.Common" />
|
||||
<!-- HACK: MWB and Advanced Paste. Align the version. got flagged when https://github.com/microsoft/PowerToys/pull/38779 was done -->
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
<!-- Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
||||
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
||||
package has not yet been restored -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Animations" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Extensions" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Markdown" />
|
||||
<PackageReference Include="System.Net.Http" />
|
||||
<PackageReference Include="System.Private.Uri" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" />
|
||||
<PackageReference Include="WinUIEx" />
|
||||
<!-- Including MessagePack to force version, since it's used by StreamJsonRpc but contains vulnerabilities. After StreamJsonRpc updates the version of MessagePack, we can upgrade StreamJsonRpc instead. -->
|
||||
<PackageReference Include="MessagePack" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" />
|
||||
<PackageReference Include="StreamJsonRpc" />
|
||||
<!-- HACK: Microsoft.Extensions.Hosting is referenced, even if it is not used, to force dll versions to be the same as in other projects. Really only needed since the Experimentation APIs that are added in CI reference some net standard 2.0 assemblies. -->
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||
<!-- HACK: To make sure the version pulled in by Microsoft.Extensions.Hosting is current. -->
|
||||
<PackageReference Include="System.Text.Json" />
|
||||
<!-- This line forces the WebView2 version used by Windows App SDK to be the one we expect from Directory.Packages.props . -->
|
||||
<PackageReference Include="Microsoft.Web.WebView2" />
|
||||
<!-- HACK: CmdPal uses CommunityToolkit.Common directly. Align the version. -->
|
||||
<PackageReference Include="CommunityToolkit.Common" />
|
||||
<!-- HACK: MWB and Advanced Paste. Align the version. got flagged when https://github.com/microsoft/PowerToys/pull/38779 was done -->
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
<!-- Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
||||
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
||||
package has not yet been restored -->
|
||||
|
||||
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnablePreviewMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnablePreviewMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- HACK: Common.UI is referenced, even if it is not used, to force dll versions to be the same as in other projects that use it. It's still unclear why this is the case, but this is need for flattening the install directory. -->
|
||||
<ProjectReference Include="..\..\common\Common.UI\Common.UI.csproj" />
|
||||
<ProjectReference Include="..\..\common\AllExperiments\AllExperiments.csproj" />
|
||||
<ProjectReference Include="..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
|
||||
<ProjectReference Include="..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\modules\ZoomIt\ZoomItSettingsInterop\ZoomItSettingsInterop.vcxproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\..\modules\MouseUtils\MouseJump.Common\MouseJump.Common.csproj" />
|
||||
<ProjectReference Include="..\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- HACK: Common.UI is referenced, even if it is not used, to force dll versions to be the same as in other projects that use it. It's still unclear why this is the case, but this is need for flattening the install directory. -->
|
||||
<ProjectReference Include="..\..\common\Common.Search\Common.Search.csproj" />
|
||||
<ProjectReference Include="..\..\common\Common.UI\Common.UI.csproj" />
|
||||
<ProjectReference Include="..\..\common\AllExperiments\AllExperiments.csproj" />
|
||||
<ProjectReference Include="..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
|
||||
<ProjectReference Include="..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\modules\ZoomIt\ZoomItSettingsInterop\ZoomItSettingsInterop.vcxproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\..\modules\MouseUtils\MouseJump.Common\MouseJump.Common.csproj" />
|
||||
<ProjectReference Include="..\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- TODO: fix issues and reenable -->
|
||||
<!-- These are caused by streamjsonrpc dependency on Microsoft.VisualStudio.Threading.Analyzers -->
|
||||
<!-- We might want to add that to the project and fix the issues as well -->
|
||||
<NoWarn>VSTHRD002;VSTHRD110;VSTHRD100;VSTHRD200;VSTHRD101</NoWarn>
|
||||
</PropertyGroup>
|
||||
<!-- XamlIndexBuilder now outputs directly to Assets\Settings -->
|
||||
<PropertyGroup>
|
||||
<GeneratedJsonFile>$(MSBuildProjectDirectory)\Assets\Settings\search.index.json</GeneratedJsonFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Assets\Settings\icon.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<!-- No RID/Platform plumbing needed here. XamlIndexBuilder handles generation after its own Build. -->
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Assets\Settings\Scripts\CheckCmdNotFoundRequirements.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Settings\Scripts\InstallWinGetClientModule.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Settings\Scripts\InstallPowerShell7.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Settings\Scripts\EnableModule.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Settings\Scripts\DisableModule.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Page Update="SettingsXAML\Controls\KeyVisual\KeyCharPresenter.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="SettingsXAML\Controls\Dashboard\ShortcutConflictControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="SettingsXAML\Controls\Dashboard\CheckUpdateControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- TODO: fix issues and reenable -->
|
||||
<!-- These are caused by streamjsonrpc dependency on Microsoft.VisualStudio.Threading.Analyzers -->
|
||||
<!-- We might want to add that to the project and fix the issues as well -->
|
||||
<NoWarn>VSTHRD002;VSTHRD110;VSTHRD100;VSTHRD200;VSTHRD101</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="SettingsXAML\OOBE\Views\OobeWorkspaces.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="SettingsXAML\Panels\MouseJumpPanel.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="SettingsXAML\Views\WorkspacesPage.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<!-- Removed hard-coded resource exclusion. -->
|
||||
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<!-- Ensure the generated search index is present in the project; only if it exists to prevent CS1566 in clean CI -->
|
||||
<Content Include="$(GeneratedJsonFile)" Condition="Exists('$(GeneratedJsonFile)')">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<!-- Embed the generated search index; logical name must match PrebuiltIndexResourceName -->
|
||||
<EmbeddedResource Include="$(GeneratedJsonFile)" Condition="Exists('$(GeneratedJsonFile)')">
|
||||
<LogicalName>Microsoft.PowerToys.Settings.UI.Assets.search.index.json</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Assets\Settings\icon.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Assets\Settings\Scripts\CheckCmdNotFoundRequirements.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Settings\Scripts\InstallWinGetClientModule.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Settings\Scripts\InstallPowerShell7.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Settings\Scripts\EnableModule.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Settings\Scripts\DisableModule.ps1">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None> <Page Update="SettingsXAML\Controls\TitleBar\TitleBar.xaml">
|
||||
</Page>
|
||||
<Page Update="SettingsXAML\Controls\KeyVisual\KeyCharPresenter.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="SettingsXAML\Controls\Dashboard\ShortcutConflictControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="SettingsXAML\Controls\Dashboard\CheckUpdateControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="SettingsXAML\OOBE\Views\OobeWorkspaces.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="SettingsXAML\Panels\MouseJumpPanel.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="SettingsXAML\Views\WorkspacesPage.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="BuildXamlIndexBeforeSettings" BeforeTargets="CoreCompile">
|
||||
<Message Importance="high" Text="[Settings] Building XamlIndexBuilder prior to compile. Views='$(MSBuildProjectDirectory)\SettingsXAML\Views' Out='$(GeneratedJsonFile)'" />
|
||||
<MSBuild Projects="..\Settings.UI.XamlIndexBuilder\Settings.UI.XamlIndexBuilder.csproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=Any CPU;TargetFramework=net9.0;XamlViewsDir=$(MSBuildProjectDirectory)\SettingsXAML\Views;GeneratedJsonFile=$(GeneratedJsonFile)" />
|
||||
</Target>
|
||||
</Project>
|
||||
338
src/settings-ui/Settings.UI/Services/SearchIndexService.cs
Normal file
338
src/settings-ui/Settings.UI/Services/SearchIndexService.cs
Normal file
@@ -0,0 +1,338 @@
|
||||
// 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.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Common.Search.FuzzSearch;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Microsoft.Windows.ApplicationModel.Resources;
|
||||
using Settings.UI.Library;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Services
|
||||
{
|
||||
public static class SearchIndexService
|
||||
{
|
||||
private static readonly object _lockObject = new();
|
||||
private static readonly Dictionary<string, string> _pageNameCache = [];
|
||||
private static readonly Dictionary<string, (string HeaderNorm, string DescNorm)> _normalizedTextCache = new();
|
||||
private static readonly Dictionary<string, Type> _pageTypeCache = new();
|
||||
private static ImmutableArray<SettingEntry> _index = [];
|
||||
private static bool _isIndexBuilt;
|
||||
private static bool _isIndexBuilding;
|
||||
private const string PrebuiltIndexResourceName = "Microsoft.PowerToys.Settings.UI.Assets.search.index.json";
|
||||
private static JsonSerializerOptions _serializerOptions = new() { PropertyNameCaseInsensitive = true };
|
||||
|
||||
public static ImmutableArray<SettingEntry> Index
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
return _index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsIndexReady
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
return _isIndexBuilt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void BuildIndex()
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_isIndexBuilt || _isIndexBuilding)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isIndexBuilding = true;
|
||||
|
||||
// Clear caches on rebuild
|
||||
_normalizedTextCache.Clear();
|
||||
_pageTypeCache.Clear();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var builder = ImmutableArray.CreateBuilder<SettingEntry>();
|
||||
LoadIndexFromPrebuiltData(builder);
|
||||
|
||||
lock (_lockObject)
|
||||
{
|
||||
_index = builder.ToImmutable();
|
||||
_isIndexBuilt = true;
|
||||
_isIndexBuilding = false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[SearchIndexService] CRITICAL ERROR building search index: {ex.Message}\n{ex.StackTrace}");
|
||||
lock (_lockObject)
|
||||
{
|
||||
_isIndexBuilding = false;
|
||||
_isIndexBuilt = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadIndexFromPrebuiltData(ImmutableArray<SettingEntry>.Builder builder)
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var resourceLoader = ResourceLoaderInstance.ResourceLoader;
|
||||
SettingEntry[] metadataList;
|
||||
|
||||
Debug.WriteLine($"[SearchIndexService] Attempting to load prebuilt index from: {PrebuiltIndexResourceName}");
|
||||
|
||||
try
|
||||
{
|
||||
using Stream stream = assembly.GetManifestResourceStream(PrebuiltIndexResourceName);
|
||||
if (stream == null)
|
||||
{
|
||||
Debug.WriteLine($"[SearchIndexService] ERROR: Embedded resource '{PrebuiltIndexResourceName}' not found. Ensure it's correctly embedded and the name matches.");
|
||||
return;
|
||||
}
|
||||
|
||||
using StreamReader reader = new(stream);
|
||||
string json = reader.ReadToEnd();
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
Debug.WriteLine("[SearchIndexService] ERROR: Embedded resource was empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
metadataList = JsonSerializer.Deserialize<SettingEntry[]>(json, _serializerOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[SearchIndexService] ERROR: Failed to load or deserialize prebuilt index: {ex.Message}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (metadataList == null || metadataList.Length == 0)
|
||||
{
|
||||
Debug.WriteLine("[SearchIndexService] Prebuilt index is empty or deserialization failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (ref var metadata in metadataList.AsSpan())
|
||||
{
|
||||
if (metadata.Type == EntryType.SettingsPage)
|
||||
{
|
||||
(metadata.Header, metadata.Description) = GetLocalizedModuleTitleAndDescription(resourceLoader, metadata.ElementUid);
|
||||
}
|
||||
else
|
||||
{
|
||||
(metadata.Header, metadata.Description) = GetLocalizedSettingHeaderAndDescription(resourceLoader, metadata.ElementUid);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(metadata.Header))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.Add(metadata);
|
||||
|
||||
// Cache the page name mapping for SettingsPage entries
|
||||
if (metadata.Type == EntryType.SettingsPage && !string.IsNullOrEmpty(metadata.Header))
|
||||
{
|
||||
_pageNameCache[metadata.PageTypeName] = metadata.Header;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[SearchIndexService] Finished loading index. Total entries: {builder.Count}");
|
||||
}
|
||||
|
||||
private static (string Header, string Description) GetLocalizedSettingHeaderAndDescription(ResourceLoader resourceLoader, string elementUid)
|
||||
{
|
||||
string header = GetString(resourceLoader, $"{elementUid}/Header");
|
||||
string description = GetString(resourceLoader, $"{elementUid}/Description");
|
||||
|
||||
if (string.IsNullOrEmpty(header))
|
||||
{
|
||||
header = GetString(resourceLoader, $"{elementUid}/Content");
|
||||
}
|
||||
|
||||
return (header, description);
|
||||
}
|
||||
|
||||
private static (string Title, string Description) GetLocalizedModuleTitleAndDescription(ResourceLoader resourceLoader, string elementUid)
|
||||
{
|
||||
string title = GetString(resourceLoader, $"{elementUid}/ModuleTitle");
|
||||
string description = GetString(resourceLoader, $"{elementUid}/ModuleDescription");
|
||||
|
||||
return (title, description);
|
||||
}
|
||||
|
||||
private static string GetString(ResourceLoader rl, string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
string value = rl.GetString(key);
|
||||
return string.IsNullOrWhiteSpace(value) ? string.Empty : value;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SettingEntry> Search(string query)
|
||||
{
|
||||
return Search(query, CancellationToken.None);
|
||||
}
|
||||
|
||||
public static List<SettingEntry> Search(string query, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var currentIndex = Index;
|
||||
if (currentIndex.IsEmpty)
|
||||
{
|
||||
Debug.WriteLine("[SearchIndexService] Search called but index is empty.");
|
||||
return [];
|
||||
}
|
||||
|
||||
var normalizedQuery = NormalizeString(query);
|
||||
var bag = new ConcurrentBag<(SettingEntry Hit, double Score)>();
|
||||
var po = new ParallelOptions
|
||||
{
|
||||
CancellationToken = token,
|
||||
MaxDegreeOfParallelism = Math.Max(1, Environment.ProcessorCount - 1),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
Parallel.ForEach(currentIndex, po, entry =>
|
||||
{
|
||||
var (headerNorm, descNorm) = GetNormalizedTexts(entry);
|
||||
var captionScoreResult = StringMatcher.FuzzyMatch(normalizedQuery, headerNorm);
|
||||
double score = captionScoreResult.Score;
|
||||
|
||||
if (!string.IsNullOrEmpty(descNorm))
|
||||
{
|
||||
var descriptionScoreResult = StringMatcher.FuzzyMatch(normalizedQuery, descNorm);
|
||||
if (descriptionScoreResult.Success)
|
||||
{
|
||||
score = Math.Max(score, descriptionScoreResult.Score * 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
if (score > 0)
|
||||
{
|
||||
var pageType = GetPageTypeFromName(entry.PageTypeName);
|
||||
if (pageType != null)
|
||||
{
|
||||
bag.Add((entry, score));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
return bag
|
||||
.OrderByDescending(r => r.Score)
|
||||
.Select(r => r.Hit)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static Type GetPageTypeFromName(string pageTypeName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(pageTypeName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_pageTypeCache.TryGetValue(pageTypeName, out var cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
var assembly = typeof(GeneralPage).Assembly;
|
||||
var type = assembly.GetType($"Microsoft.PowerToys.Settings.UI.Views.{pageTypeName}");
|
||||
_pageTypeCache[pageTypeName] = type;
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
private static (string HeaderNorm, string DescNorm) GetNormalizedTexts(SettingEntry entry)
|
||||
{
|
||||
if (entry.ElementUid == null && entry.Header == null)
|
||||
{
|
||||
return (NormalizeString(entry.Header), NormalizeString(entry.Description));
|
||||
}
|
||||
|
||||
var key = entry.ElementUid ?? $"{entry.PageTypeName}|{entry.ElementName}";
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_normalizedTextCache.TryGetValue(key, out var cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
|
||||
var headerNorm = NormalizeString(entry.Header);
|
||||
var descNorm = NormalizeString(entry.Description);
|
||||
lock (_lockObject)
|
||||
{
|
||||
_normalizedTextCache[key] = (headerNorm, descNorm);
|
||||
}
|
||||
|
||||
return (headerNorm, descNorm);
|
||||
}
|
||||
|
||||
private static string NormalizeString(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var normalized = input.ToLowerInvariant().Normalize(NormalizationForm.FormKD);
|
||||
var stringBuilder = new StringBuilder();
|
||||
foreach (var c in normalized)
|
||||
{
|
||||
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
|
||||
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
|
||||
{
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
public static string GetLocalizedPageName(string pageTypeName)
|
||||
{
|
||||
return _pageNameCache.TryGetValue(pageTypeName, out string cachedName) ? cachedName : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<ResourceDictionary Source="/SettingsXAML/Controls/KeyVisual/KeyVisual.xaml" />
|
||||
<ResourceDictionary Source="/SettingsXAML/Controls/KeyVisual/KeyCharPresenter.xaml" />
|
||||
<ResourceDictionary Source="/SettingsXAML/Controls/TitleBar/TitleBar.xaml" />
|
||||
<ResourceDictionary Source="/SettingsXAML/Styles/TextBlock.xaml" />
|
||||
<ResourceDictionary Source="/SettingsXAML/Styles/Button.xaml" />
|
||||
<ResourceDictionary Source="/SettingsXAML/Styles/InfoBadge.xaml" />
|
||||
@@ -49,8 +50,12 @@
|
||||
TrueValue="Collapsed" />
|
||||
<tkconverters:StringFormatConverter x:Key="StringFormatConverter" />
|
||||
<tkconverters:BoolNegationConverter x:Key="BoolNegationConverter" />
|
||||
<tkconverters:EmptyObjectToObjectConverter
|
||||
x:Key="EmptyObjectToObjectConverter"
|
||||
EmptyValue="Collapsed"
|
||||
NotEmptyValue="Visible" />
|
||||
<converters:UpdateStateToBoolConverter x:Key="UpdateStateToBoolConverter" />
|
||||
|
||||
<tkconverters:StringVisibilityConverter x:Key="StringVisibilityConverter" />
|
||||
<x:Double x:Key="SettingsCardSpacing">2</x:Double>
|
||||
|
||||
<!-- Overrides -->
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tk7controls="using:CommunityToolkit.WinUI.UI.Controls"
|
||||
@@ -11,6 +12,7 @@
|
||||
<UserControl.Resources>
|
||||
<x:Double x:Key="PageMaxWidth">1000</x:Double>
|
||||
<x:Double x:Key="PageHeaderMaxWidth">1020</x:Double>
|
||||
<converters:UriToImageSourceConverter x:Key="UriToImageSourceConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid Padding="20,0,0,0" RowSpacing="24">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -38,10 +40,7 @@
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Top panel -->
|
||||
<Grid
|
||||
MaxWidth="{StaticResource PageMaxWidth}"
|
||||
ColumnSpacing="16"
|
||||
RowSpacing="16">
|
||||
<Grid MaxWidth="{StaticResource PageMaxWidth}" RowSpacing="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
@@ -52,14 +51,12 @@
|
||||
</Grid.RowDefinitions>
|
||||
<Border
|
||||
MaxWidth="160"
|
||||
Margin="0,0,16,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
CornerRadius="{StaticResource OverlayCornerRadius}">
|
||||
<Image AutomationProperties.AccessibilityView="Raw">
|
||||
<Image.Source>
|
||||
<BitmapImage UriSource="{x:Bind ModuleImageSource}" />
|
||||
</Image.Source>
|
||||
</Image>
|
||||
CornerRadius="{StaticResource OverlayCornerRadius}"
|
||||
Visibility="{x:Bind ModuleImageSource, Converter={StaticResource EmptyObjectToObjectConverter}}">
|
||||
<Image AutomationProperties.AccessibilityView="Raw" Source="{x:Bind ModuleImageSource, Converter={StaticResource UriToImageSourceConverter}, Mode=OneWay}" />
|
||||
</Border>
|
||||
|
||||
<StackPanel x:Name="DescriptionPanel" Grid.Column="1">
|
||||
@@ -73,7 +70,8 @@
|
||||
x:Name="PrimaryLinksControl"
|
||||
Margin="0,8,0,0"
|
||||
IsTabStop="False"
|
||||
ItemsSource="{x:Bind PrimaryLinks}">
|
||||
ItemsSource="{x:Bind PrimaryLinks}"
|
||||
Visibility="{x:Bind PrimaryLinks.Count, Converter={StaticResource DoubleToVisibilityConverter}}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="controls:PageLink">
|
||||
<HyperlinkButton NavigateUri="{x:Bind Link}" Style="{StaticResource TextButtonStyle}">
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// 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.ObjectModel;
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
@@ -30,9 +31,9 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||
set => SetValue(ModuleDescriptionProperty, value);
|
||||
}
|
||||
|
||||
public string ModuleImageSource
|
||||
public Uri ModuleImageSource
|
||||
{
|
||||
get => (string)GetValue(ModuleImageSourceProperty);
|
||||
get => (Uri)GetValue(ModuleImageSourceProperty);
|
||||
set => SetValue(ModuleImageSourceProperty, value);
|
||||
}
|
||||
|
||||
@@ -60,13 +61,13 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||
set { SetValue(ModuleContentProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ModuleTitleProperty = DependencyProperty.Register("ModuleTitle", typeof(string), typeof(SettingsPageControl), new PropertyMetadata(default(string)));
|
||||
public static readonly DependencyProperty ModuleDescriptionProperty = DependencyProperty.Register("ModuleDescription", typeof(string), typeof(SettingsPageControl), new PropertyMetadata(default(string)));
|
||||
public static readonly DependencyProperty ModuleImageSourceProperty = DependencyProperty.Register("ModuleImageSource", typeof(string), typeof(SettingsPageControl), new PropertyMetadata(default(string)));
|
||||
public static readonly DependencyProperty PrimaryLinksProperty = DependencyProperty.Register("PrimaryLinks", typeof(ObservableCollection<PageLink>), typeof(SettingsPageControl), new PropertyMetadata(new ObservableCollection<PageLink>()));
|
||||
public static readonly DependencyProperty SecondaryLinksHeaderProperty = DependencyProperty.Register("SecondaryLinksHeader", typeof(string), typeof(SettingsPageControl), new PropertyMetadata(default(string)));
|
||||
public static readonly DependencyProperty SecondaryLinksProperty = DependencyProperty.Register("SecondaryLinks", typeof(ObservableCollection<PageLink>), typeof(SettingsPageControl), new PropertyMetadata(new ObservableCollection<PageLink>()));
|
||||
public static readonly DependencyProperty ModuleContentProperty = DependencyProperty.Register("ModuleContent", typeof(object), typeof(SettingsPageControl), new PropertyMetadata(new Grid()));
|
||||
public static readonly DependencyProperty ModuleTitleProperty = DependencyProperty.Register(nameof(ModuleTitle), typeof(string), typeof(SettingsPageControl), new PropertyMetadata(defaultValue: null));
|
||||
public static readonly DependencyProperty ModuleDescriptionProperty = DependencyProperty.Register(nameof(ModuleDescription), typeof(string), typeof(SettingsPageControl), new PropertyMetadata(defaultValue: null));
|
||||
public static readonly DependencyProperty ModuleImageSourceProperty = DependencyProperty.Register(nameof(ModuleImageSource), typeof(Uri), typeof(SettingsPageControl), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty PrimaryLinksProperty = DependencyProperty.Register(nameof(PrimaryLinks), typeof(ObservableCollection<PageLink>), typeof(SettingsPageControl), new PropertyMetadata(new ObservableCollection<PageLink>()));
|
||||
public static readonly DependencyProperty SecondaryLinksHeaderProperty = DependencyProperty.Register(nameof(SecondaryLinksHeader), typeof(string), typeof(SettingsPageControl), new PropertyMetadata(default(string)));
|
||||
public static readonly DependencyProperty SecondaryLinksProperty = DependencyProperty.Register(nameof(SecondaryLinks), typeof(ObservableCollection<PageLink>), typeof(SettingsPageControl), new PropertyMetadata(new ObservableCollection<PageLink>()));
|
||||
public static readonly DependencyProperty ModuleContentProperty = DependencyProperty.Register(nameof(ModuleContent), typeof(object), typeof(SettingsPageControl), new PropertyMetadata(new Grid()));
|
||||
|
||||
private void UserControl_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
@@ -548,18 +548,14 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||
}
|
||||
}
|
||||
|
||||
if (conflictingModules.Count > 0)
|
||||
var moduleNames = conflictingModules.ToArray();
|
||||
if (string.Equals(moduleNames[0], "System", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var moduleNames = conflictingModules.ToArray();
|
||||
var conflictMessage = moduleNames.Length == 1
|
||||
? $"Conflict detected with {moduleNames[0]}"
|
||||
: $"Conflicts detected with: {string.Join(", ", moduleNames)}";
|
||||
|
||||
c.ConflictMessage = conflictMessage;
|
||||
c.ConflictMessage = ResourceLoaderInstance.ResourceLoader.GetString("SysHotkeyConflictTooltipText");
|
||||
}
|
||||
else
|
||||
{
|
||||
c.ConflictMessage = "Conflict detected with unknown module";
|
||||
c.ConflictMessage = ResourceLoaderInstance.ResourceLoader.GetString("InAppHotkeyConflictTooltipText");
|
||||
}
|
||||
|
||||
c.HasConflict = true;
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
IsTabStop="{Binding ElementName=ShortcutContentControl, Path=IsWarningAltGr, Mode=OneWay}"
|
||||
Severity="Warning" />
|
||||
<InfoBar
|
||||
Title="Hotkey Conflict"
|
||||
x:Uid="WarningShortcutConflict"
|
||||
IsClosable="False"
|
||||
IsOpen="{Binding ElementName=ShortcutContentControl, Path=HasConflict, Mode=OneWay}"
|
||||
IsTabStop="{Binding ElementName=ShortcutContentControl, Path=HasConflict, Mode=OneWay}"
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
// 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 Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Controls;
|
||||
|
||||
public partial class TitleBar : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="Icon"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(IconElement), typeof(TitleBar), new PropertyMetadata(null, IconChanged));
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="Title"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(TitleBar), new PropertyMetadata(default(string)));
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="Subtitle"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SubtitleProperty = DependencyProperty.Register(nameof(Subtitle), typeof(string), typeof(TitleBar), new PropertyMetadata(default(string)));
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="Content"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(object), typeof(TitleBar), new PropertyMetadata(null, ContentChanged));
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="Footer"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty FooterProperty = DependencyProperty.Register(nameof(Footer), typeof(object), typeof(TitleBar), new PropertyMetadata(null, FooterChanged));
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="IsBackButtonVisible"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsBackButtonVisibleProperty = DependencyProperty.Register(nameof(IsBackButtonVisible), typeof(bool), typeof(TitleBar), new PropertyMetadata(false, IsBackButtonVisibleChanged));
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="IsPaneButtonVisible"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsPaneButtonVisibleProperty = DependencyProperty.Register(nameof(IsPaneButtonVisible), typeof(bool), typeof(TitleBar), new PropertyMetadata(false, IsPaneButtonVisibleChanged));
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="DisplayMode"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DisplayModeProperty = DependencyProperty.Register(nameof(DisplayMode), typeof(DisplayMode), typeof(TitleBar), new PropertyMetadata(DisplayMode.Standard, DisplayModeChanged));
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="CompactStateBreakpoint
|
||||
/// "/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CompactStateBreakpointProperty = DependencyProperty.Register(nameof(CompactStateBreakpoint), typeof(int), typeof(TitleBar), new PropertyMetadata(850));
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="AutoConfigureCustomTitleBar"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty AutoConfigureCustomTitleBarProperty = DependencyProperty.Register(nameof(AutoConfigureCustomTitleBar), typeof(bool), typeof(TitleBar), new PropertyMetadata(true, AutoConfigureCustomTitleBarChanged));
|
||||
|
||||
/// <summary>
|
||||
/// The backing <see cref="DependencyProperty"/> for the <see cref="Window"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty WindowProperty = DependencyProperty.Register(nameof(Window), typeof(Window), typeof(TitleBar), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// The event that gets fired when the back button is clicked
|
||||
/// </summary>
|
||||
#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
public event EventHandler<RoutedEventArgs>? BackButtonClick;
|
||||
#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
|
||||
/// <summary>
|
||||
/// The event that gets fired when the pane toggle button is clicked
|
||||
/// </summary>
|
||||
#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
public event EventHandler<RoutedEventArgs>? PaneButtonClick;
|
||||
#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Icon
|
||||
/// </summary>
|
||||
public IconElement Icon
|
||||
{
|
||||
get => (IconElement)GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Title
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get => (string)GetValue(TitleProperty);
|
||||
set => SetValue(TitleProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Subtitle
|
||||
/// </summary>
|
||||
public string Subtitle
|
||||
{
|
||||
get => (string)GetValue(SubtitleProperty);
|
||||
set => SetValue(SubtitleProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content shown at the center of the TitleBar. When setting this, using DisplayMode=Tall is recommended.
|
||||
/// </summary>
|
||||
public object Content
|
||||
{
|
||||
get => (object)GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content shown at the right of the TitleBar, next to the caption buttons. When setting this, using DisplayMode=Tall is recommended.
|
||||
/// </summary>
|
||||
public object Footer
|
||||
{
|
||||
get => (object)GetValue(FooterProperty);
|
||||
set => SetValue(FooterProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets DisplayMode. Compact is default (32px), Tall is recommended when setting the Content or Footer.
|
||||
/// </summary>
|
||||
public DisplayMode DisplayMode
|
||||
{
|
||||
get => (DisplayMode)GetValue(DisplayModeProperty);
|
||||
set => SetValue(DisplayModeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether gets or sets the visibility of the back button.
|
||||
/// </summary>
|
||||
public bool IsBackButtonVisible
|
||||
{
|
||||
get => (bool)GetValue(IsBackButtonVisibleProperty);
|
||||
set => SetValue(IsBackButtonVisibleProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether gets or sets the visibility of the pane toggle button.
|
||||
/// </summary>
|
||||
public bool IsPaneButtonVisible
|
||||
{
|
||||
get => (bool)GetValue(IsPaneButtonVisibleProperty);
|
||||
set => SetValue(IsPaneButtonVisibleProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the breakpoint of when the compact state is triggered.
|
||||
/// </summary>
|
||||
public int CompactStateBreakpoint
|
||||
{
|
||||
get => (int)GetValue(CompactStateBreakpointProperty);
|
||||
set => SetValue(CompactStateBreakpointProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether gets or sets if the TitleBar should auto configure ExtendContentIntoTitleBar and CaptionButton background colors.
|
||||
/// </summary>
|
||||
public bool AutoConfigureCustomTitleBar
|
||||
{
|
||||
get => (bool)GetValue(AutoConfigureCustomTitleBarProperty);
|
||||
set => SetValue(AutoConfigureCustomTitleBarProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the window the TitleBar should configure.
|
||||
/// </summary>
|
||||
public Window Window
|
||||
{
|
||||
get => (Window)GetValue(WindowProperty);
|
||||
set => SetValue(WindowProperty, value);
|
||||
}
|
||||
|
||||
private static void IsBackButtonVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((TitleBar)d).Update();
|
||||
}
|
||||
|
||||
private static void IsPaneButtonVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((TitleBar)d).Update();
|
||||
}
|
||||
|
||||
private static void DisplayModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((TitleBar)d).Update();
|
||||
}
|
||||
|
||||
private static void ContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((TitleBar)d).Update();
|
||||
}
|
||||
|
||||
private static void FooterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((TitleBar)d).Update();
|
||||
}
|
||||
|
||||
private static void IconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((TitleBar)d).Update();
|
||||
}
|
||||
|
||||
private static void AutoConfigureCustomTitleBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (((TitleBar)d).AutoConfigureCustomTitleBar)
|
||||
{
|
||||
((TitleBar)d).Configure();
|
||||
}
|
||||
else
|
||||
{
|
||||
((TitleBar)d).Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum DisplayMode
|
||||
{
|
||||
Standard,
|
||||
Tall,
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
// 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.UI;
|
||||
using Microsoft.UI.Input;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Windows.Foundation;
|
||||
using Windows.Graphics;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Controls;
|
||||
|
||||
[TemplatePart(Name = nameof(PART_FooterPresenter), Type = typeof(ContentPresenter))]
|
||||
[TemplatePart(Name = nameof(PART_ContentPresenter), Type = typeof(ContentPresenter))]
|
||||
|
||||
public partial class TitleBar : Control
|
||||
{
|
||||
#pragma warning disable SA1306 // Field names should begin with lower-case letter
|
||||
#pragma warning disable SA1310 // Field names should not contain underscore
|
||||
#pragma warning disable SA1400 // Access modifier should be declared
|
||||
#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
ContentPresenter? PART_ContentPresenter;
|
||||
ContentPresenter? PART_FooterPresenter;
|
||||
#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
#pragma warning restore SA1400 // Access modifier should be declared
|
||||
#pragma warning restore SA1306 // Field names should begin with lower-case letter
|
||||
#pragma warning restore SA1310 // Field names should not contain underscore
|
||||
|
||||
private void SetWASDKTitleBar()
|
||||
{
|
||||
if (this.Window == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (AutoConfigureCustomTitleBar)
|
||||
{
|
||||
Window.AppWindow.TitleBar.ExtendsContentIntoTitleBar = true;
|
||||
|
||||
this.Window.SizeChanged -= Window_SizeChanged;
|
||||
this.Window.SizeChanged += Window_SizeChanged;
|
||||
this.Window.Activated -= Window_Activated;
|
||||
this.Window.Activated += Window_Activated;
|
||||
|
||||
if (Window.Content is FrameworkElement rootElement)
|
||||
{
|
||||
UpdateCaptionButtons(rootElement);
|
||||
rootElement.ActualThemeChanged += (s, e) =>
|
||||
{
|
||||
UpdateCaptionButtons(rootElement);
|
||||
};
|
||||
}
|
||||
|
||||
PART_ContentPresenter = GetTemplateChild(nameof(PART_ContentPresenter)) as ContentPresenter;
|
||||
PART_FooterPresenter = GetTemplateChild(nameof(PART_FooterPresenter)) as ContentPresenter;
|
||||
|
||||
// Get caption button occlusion information.
|
||||
int captionButtonOcclusionWidthRight = Window.AppWindow.TitleBar.RightInset;
|
||||
int captionButtonOcclusionWidthLeft = Window.AppWindow.TitleBar.LeftInset;
|
||||
PART_LeftPaddingColumn!.Width = new GridLength(captionButtonOcclusionWidthLeft);
|
||||
PART_RightPaddingColumn!.Width = new GridLength(captionButtonOcclusionWidthRight);
|
||||
|
||||
if (DisplayMode == DisplayMode.Tall)
|
||||
{
|
||||
// Choose a tall title bar to provide more room for interactive elements
|
||||
// like search box or person picture controls.
|
||||
Window.AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
|
||||
}
|
||||
else
|
||||
{
|
||||
Window.AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Standard;
|
||||
}
|
||||
|
||||
// Recalculate the drag region for the custom title bar
|
||||
// if you explicitly defined new draggable areas.
|
||||
SetDragRegionForCustomTitleBar();
|
||||
|
||||
_isAutoConfigCompleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs args)
|
||||
{
|
||||
UpdateVisualStateAndDragRegion(args.Size);
|
||||
}
|
||||
|
||||
private void UpdateCaptionButtons(FrameworkElement rootElement)
|
||||
{
|
||||
Window.AppWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent;
|
||||
Window.AppWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||
if (rootElement.ActualTheme == ElementTheme.Dark)
|
||||
{
|
||||
Window.AppWindow.TitleBar.ButtonForegroundColor = Colors.White;
|
||||
Window.AppWindow.TitleBar.ButtonInactiveForegroundColor = Colors.DarkGray;
|
||||
}
|
||||
else
|
||||
{
|
||||
Window.AppWindow.TitleBar.ButtonForegroundColor = Colors.Black;
|
||||
Window.AppWindow.TitleBar.ButtonInactiveForegroundColor = Colors.DarkGray;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetWASDKTitleBar()
|
||||
{
|
||||
if (this.Window == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Only reset if we were the ones who configured
|
||||
if (_isAutoConfigCompleted)
|
||||
{
|
||||
Window.AppWindow.TitleBar.ExtendsContentIntoTitleBar = false;
|
||||
this.Window.SizeChanged -= Window_SizeChanged;
|
||||
this.Window.Activated -= Window_Activated;
|
||||
SizeChanged -= this.TitleBar_SizeChanged;
|
||||
Window.AppWindow.TitleBar.ResetToDefault();
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_Activated(object sender, WindowActivatedEventArgs args)
|
||||
{
|
||||
if (args.WindowActivationState == WindowActivationState.Deactivated)
|
||||
{
|
||||
VisualStateManager.GoToState(this, WindowDeactivatedState, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
VisualStateManager.GoToState(this, WindowActivatedState, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDragRegionForCustomTitleBar()
|
||||
{
|
||||
if (AutoConfigureCustomTitleBar && Window is not null)
|
||||
{
|
||||
ClearDragRegions(NonClientRegionKind.Passthrough);
|
||||
#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
var items = new FrameworkElement?[] { PART_ContentPresenter, PART_FooterPresenter, PART_ButtonHolder };
|
||||
#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
var validItems = items.Where(x => x is not null).Select(x => x!).ToArray(); // Prune null items
|
||||
|
||||
SetDragRegion(NonClientRegionKind.Passthrough, validItems);
|
||||
}
|
||||
}
|
||||
|
||||
public double GetRasterizationScaleForElement(UIElement element)
|
||||
{
|
||||
if (element.XamlRoot != null)
|
||||
{
|
||||
return element.XamlRoot.RasterizationScale;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
public void SetDragRegion(NonClientRegionKind nonClientRegionKind, params FrameworkElement[] frameworkElements)
|
||||
{
|
||||
List<RectInt32> rects = new List<RectInt32>();
|
||||
var scale = GetRasterizationScaleForElement(this);
|
||||
|
||||
foreach (var frameworkElement in frameworkElements)
|
||||
{
|
||||
if (frameworkElement == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GeneralTransform transformElement = frameworkElement.TransformToVisual(null);
|
||||
Rect bounds = transformElement.TransformBounds(new Rect(0, 0, frameworkElement.ActualWidth, frameworkElement.ActualHeight));
|
||||
var transparentRect = new RectInt32(
|
||||
_X: (int)Math.Round(bounds.X * scale),
|
||||
_Y: (int)Math.Round(bounds.Y * scale),
|
||||
_Width: (int)Math.Round(bounds.Width * scale),
|
||||
_Height: (int)Math.Round(bounds.Height * scale));
|
||||
rects.Add(transparentRect);
|
||||
}
|
||||
|
||||
if (rects.Count > 0)
|
||||
{
|
||||
InputNonClientPointerSource.GetForWindowId(Window.AppWindow.Id).SetRegionRects(nonClientRegionKind, rects.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearDragRegions(NonClientRegionKind nonClientRegionKind)
|
||||
{
|
||||
InputNonClientPointerSource.GetForWindowId(Window.AppWindow.Id).ClearRegionRects(nonClientRegionKind);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Controls;
|
||||
|
||||
[TemplateVisualState(Name = BackButtonVisibleState, GroupName = BackButtonStates)]
|
||||
[TemplateVisualState(Name = BackButtonCollapsedState, GroupName = BackButtonStates)]
|
||||
[TemplateVisualState(Name = PaneButtonVisibleState, GroupName = PaneButtonStates)]
|
||||
[TemplateVisualState(Name = PaneButtonCollapsedState, GroupName = PaneButtonStates)]
|
||||
[TemplateVisualState(Name = WindowActivatedState, GroupName = ActivationStates)]
|
||||
[TemplateVisualState(Name = WindowDeactivatedState, GroupName = ActivationStates)]
|
||||
[TemplateVisualState(Name = StandardState, GroupName = DisplayModeStates)]
|
||||
[TemplateVisualState(Name = TallState, GroupName = DisplayModeStates)]
|
||||
[TemplateVisualState(Name = IconVisibleState, GroupName = IconStates)]
|
||||
[TemplateVisualState(Name = IconCollapsedState, GroupName = IconStates)]
|
||||
[TemplateVisualState(Name = ContentVisibleState, GroupName = ContentStates)]
|
||||
[TemplateVisualState(Name = ContentCollapsedState, GroupName = ContentStates)]
|
||||
[TemplateVisualState(Name = FooterVisibleState, GroupName = FooterStates)]
|
||||
[TemplateVisualState(Name = FooterCollapsedState, GroupName = FooterStates)]
|
||||
[TemplateVisualState(Name = WideState, GroupName = ReflowStates)]
|
||||
[TemplateVisualState(Name = NarrowState, GroupName = ReflowStates)]
|
||||
[TemplatePart(Name = PartBackButton, Type = typeof(Button))]
|
||||
[TemplatePart(Name = PartPaneButton, Type = typeof(Button))]
|
||||
[TemplatePart(Name = nameof(PART_LeftPaddingColumn), Type = typeof(ColumnDefinition))]
|
||||
[TemplatePart(Name = nameof(PART_RightPaddingColumn), Type = typeof(ColumnDefinition))]
|
||||
[TemplatePart(Name = nameof(PART_ButtonHolder), Type = typeof(StackPanel))]
|
||||
|
||||
public partial class TitleBar : Control
|
||||
{
|
||||
private const string PartBackButton = "PART_BackButton";
|
||||
private const string PartPaneButton = "PART_PaneButton";
|
||||
|
||||
private const string BackButtonVisibleState = "BackButtonVisible";
|
||||
private const string BackButtonCollapsedState = "BackButtonCollapsed";
|
||||
private const string BackButtonStates = "BackButtonStates";
|
||||
|
||||
private const string PaneButtonVisibleState = "PaneButtonVisible";
|
||||
private const string PaneButtonCollapsedState = "PaneButtonCollapsed";
|
||||
private const string PaneButtonStates = "PaneButtonStates";
|
||||
|
||||
private const string WindowActivatedState = "Activated";
|
||||
private const string WindowDeactivatedState = "Deactivated";
|
||||
private const string ActivationStates = "WindowActivationStates";
|
||||
|
||||
private const string IconVisibleState = "IconVisible";
|
||||
private const string IconCollapsedState = "IconCollapsed";
|
||||
private const string IconStates = "IconStates";
|
||||
|
||||
private const string StandardState = "Standard";
|
||||
private const string TallState = "Tall";
|
||||
private const string DisplayModeStates = "DisplayModeStates";
|
||||
|
||||
private const string ContentVisibleState = "ContentVisible";
|
||||
private const string ContentCollapsedState = "ContentCollapsed";
|
||||
private const string ContentStates = "ContentStates";
|
||||
|
||||
private const string FooterVisibleState = "FooterVisible";
|
||||
private const string FooterCollapsedState = "FooterCollapsed";
|
||||
private const string FooterStates = "FooterStates";
|
||||
|
||||
private const string WideState = "Wide";
|
||||
private const string NarrowState = "Narrow";
|
||||
private const string ReflowStates = "ReflowStates";
|
||||
|
||||
#pragma warning disable SA1306 // Field names should begin with lower-case letter
|
||||
#pragma warning disable SA1310 // Field names should not contain underscore
|
||||
#pragma warning disable SA1400 // Access modifier should be declared
|
||||
#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
ColumnDefinition? PART_RightPaddingColumn;
|
||||
ColumnDefinition? PART_LeftPaddingColumn;
|
||||
StackPanel? PART_ButtonHolder;
|
||||
#pragma warning restore CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
|
||||
#pragma warning restore SA1400 // Access modifier should be declared
|
||||
#pragma warning restore SA1306 // Field names should begin with lower-case letter
|
||||
#pragma warning restore SA1310 // Field names should not contain underscore
|
||||
|
||||
// We only want to reset TitleBar configuration in app, if we're the TitleBar instance that's managing that state.
|
||||
private bool _isAutoConfigCompleted;
|
||||
|
||||
public TitleBar()
|
||||
{
|
||||
this.DefaultStyleKey = typeof(TitleBar);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
PART_LeftPaddingColumn = GetTemplateChild(nameof(PART_LeftPaddingColumn)) as ColumnDefinition;
|
||||
PART_RightPaddingColumn = GetTemplateChild(nameof(PART_RightPaddingColumn)) as ColumnDefinition;
|
||||
ConfigureButtonHolder();
|
||||
Configure();
|
||||
if (GetTemplateChild(PartBackButton) is Button backButton)
|
||||
{
|
||||
backButton.Click -= BackButton_Click;
|
||||
backButton.Click += BackButton_Click;
|
||||
}
|
||||
|
||||
if (GetTemplateChild(PartPaneButton) is Button paneButton)
|
||||
{
|
||||
paneButton.Click -= PaneButton_Click;
|
||||
paneButton.Click += PaneButton_Click;
|
||||
}
|
||||
|
||||
SizeChanged -= this.TitleBar_SizeChanged;
|
||||
SizeChanged += this.TitleBar_SizeChanged;
|
||||
|
||||
Update();
|
||||
base.OnApplyTemplate();
|
||||
}
|
||||
|
||||
private void TitleBar_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
UpdateVisualStateAndDragRegion(e.NewSize);
|
||||
}
|
||||
|
||||
private void UpdateVisualStateAndDragRegion(Size size)
|
||||
{
|
||||
if (size.Width <= CompactStateBreakpoint)
|
||||
{
|
||||
if (Content != null || Footer != null)
|
||||
{
|
||||
VisualStateManager.GoToState(this, NarrowState, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VisualStateManager.GoToState(this, WideState, true);
|
||||
}
|
||||
|
||||
SetDragRegionForCustomTitleBar();
|
||||
}
|
||||
|
||||
private void BackButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
BackButtonClick?.Invoke(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
private void PaneButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PaneButtonClick?.Invoke(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
private void ConfigureButtonHolder()
|
||||
{
|
||||
if (PART_ButtonHolder != null)
|
||||
{
|
||||
PART_ButtonHolder.SizeChanged -= PART_ButtonHolder_SizeChanged;
|
||||
}
|
||||
|
||||
PART_ButtonHolder = GetTemplateChild(nameof(PART_ButtonHolder)) as StackPanel;
|
||||
|
||||
if (PART_ButtonHolder != null)
|
||||
{
|
||||
PART_ButtonHolder.SizeChanged += PART_ButtonHolder_SizeChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void PART_ButtonHolder_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
SetDragRegionForCustomTitleBar();
|
||||
}
|
||||
|
||||
private void Configure()
|
||||
{
|
||||
SetWASDKTitleBar();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ResetWASDKTitleBar();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Icon != null)
|
||||
{
|
||||
VisualStateManager.GoToState(this, IconVisibleState, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
VisualStateManager.GoToState(this, IconCollapsedState, true);
|
||||
}
|
||||
|
||||
VisualStateManager.GoToState(this, IsBackButtonVisible ? BackButtonVisibleState : BackButtonCollapsedState, true);
|
||||
VisualStateManager.GoToState(this, IsPaneButtonVisible ? PaneButtonVisibleState : PaneButtonCollapsedState, true);
|
||||
|
||||
if (DisplayMode == DisplayMode.Tall)
|
||||
{
|
||||
VisualStateManager.GoToState(this, TallState, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
VisualStateManager.GoToState(this, StandardState, true);
|
||||
}
|
||||
|
||||
if (Content != null)
|
||||
{
|
||||
VisualStateManager.GoToState(this, ContentVisibleState, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
VisualStateManager.GoToState(this, ContentCollapsedState, true);
|
||||
}
|
||||
|
||||
if (Footer != null)
|
||||
{
|
||||
VisualStateManager.GoToState(this, FooterVisibleState, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
VisualStateManager.GoToState(this, FooterCollapsedState, true);
|
||||
}
|
||||
|
||||
SetDragRegionForCustomTitleBar();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Controls">
|
||||
|
||||
<x:Double x:Key="TitleBarCompactHeight">32</x:Double>
|
||||
<x:Double x:Key="TitleBarTallHeight">48</x:Double>
|
||||
<x:Double x:Key="TitleBarContentMinWidth">360</x:Double>
|
||||
<Style BasedOn="{StaticResource DefaultTitleBarStyle}" TargetType="local:TitleBar" />
|
||||
|
||||
<Style x:Key="DefaultTitleBarStyle" TargetType="local:TitleBar">
|
||||
<Setter Property="MinHeight" Value="{ThemeResource TitleBarCompactHeight}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:TitleBar">
|
||||
<Grid
|
||||
x:Name="PART_RootGrid"
|
||||
Height="{TemplateBinding MinHeight}"
|
||||
Padding="4,0,0,0"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="PART_LeftPaddingColumn" Width="0" />
|
||||
<ColumnDefinition x:Name="PART_ButtonsHolderColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="PART_IconColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="PART_TitleColumn" Width="Auto" />
|
||||
<ColumnDefinition
|
||||
x:Name="PART_LeftDragColumn"
|
||||
Width="*"
|
||||
MinWidth="4" />
|
||||
<ColumnDefinition x:Name="PART_ContentColumn" Width="Auto" />
|
||||
<ColumnDefinition
|
||||
x:Name="PART_RightDragColumn"
|
||||
Width="*"
|
||||
MinWidth="4" />
|
||||
<ColumnDefinition x:Name="PART_FooterColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="PART_RightPaddingColumn" Width="0" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border
|
||||
x:Name="PART_IconHolder"
|
||||
Grid.Column="2"
|
||||
Margin="12,0,0,0"
|
||||
VerticalAlignment="Center">
|
||||
<Viewbox
|
||||
x:Name="PART_Icon"
|
||||
MaxWidth="16"
|
||||
MaxHeight="16">
|
||||
<ContentPresenter
|
||||
x:Name="PART_IconPresenter"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Content="{TemplateBinding Icon}"
|
||||
HighContrastAdjustment="None" />
|
||||
</Viewbox>
|
||||
</Border>
|
||||
|
||||
<StackPanel
|
||||
x:Name="PART_TitleHolder"
|
||||
Grid.Column="3"
|
||||
Margin="16,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal"
|
||||
Spacing="4">
|
||||
<TextBlock
|
||||
x:Name="PART_TitleText"
|
||||
MinWidth="48"
|
||||
Margin="0,0,0,1"
|
||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{TemplateBinding Title}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap" />
|
||||
<TextBlock
|
||||
x:Name="PART_SubtitleText"
|
||||
MinWidth="48"
|
||||
Margin="0,0,0,1"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{TemplateBinding Subtitle}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="NoWrap" />
|
||||
</StackPanel>
|
||||
<Grid
|
||||
x:Name="PART_DragRegion"
|
||||
Grid.Column="2"
|
||||
Grid.ColumnSpan="6"
|
||||
Background="Transparent" />
|
||||
<StackPanel
|
||||
x:Name="PART_ButtonHolder"
|
||||
Grid.Column="1"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="PART_BackButton"
|
||||
Style="{ThemeResource TitleBarBackButtonStyle}"
|
||||
ToolTipService.ToolTip="Back" />
|
||||
<Button
|
||||
x:Name="PART_PaneButton"
|
||||
Style="{StaticResource TitleBarPaneToggleButtonStyle}"
|
||||
ToolTipService.ToolTip="Toggle menu" />
|
||||
</StackPanel>
|
||||
|
||||
<ContentPresenter
|
||||
x:Name="PART_ContentPresenter"
|
||||
Grid.Column="5"
|
||||
MinWidth="{ThemeResource TitleBarContentMinWidth}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Content="{TemplateBinding Content}" />
|
||||
<ContentPresenter
|
||||
x:Name="PART_FooterPresenter"
|
||||
Grid.Column="7"
|
||||
Margin="4,0,8,0"
|
||||
HorizontalContentAlignment="Right"
|
||||
Content="{TemplateBinding Footer}" />
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="BackButtonStates">
|
||||
<VisualState x:Name="BackButtonVisible" />
|
||||
<VisualState x:Name="BackButtonCollapsed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="PART_BackButton.Visibility" Value="Collapsed" />
|
||||
<Setter Target="PART_BackButton.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="PaneButtonStates">
|
||||
<VisualState x:Name="PaneButtonVisible" />
|
||||
<VisualState x:Name="PaneButtonCollapsed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="PART_PaneButton.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="IconStates">
|
||||
<VisualState x:Name="IconVisible" />
|
||||
<VisualState x:Name="IconCollapsed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="PART_IconHolder.Visibility" Value="Collapsed" />
|
||||
<Setter Target="PART_TitleHolder.Margin" Value="4,0,0,0" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="ContentStates">
|
||||
<VisualState x:Name="ContentVisible" />
|
||||
<VisualState x:Name="ContentCollapsed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="PART_ContentPresenter.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="FooterStates">
|
||||
<VisualState x:Name="FooterVisible" />
|
||||
<VisualState x:Name="FooterCollapsed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="PART_FooterPresenter.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="ReflowStates">
|
||||
<VisualState x:Name="Wide" />
|
||||
<VisualState x:Name="Narrow">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="PART_TitleHolder.Visibility" Value="Collapsed" />
|
||||
<Setter Target="PART_LeftDragColumn.Width" Value="Auto" />
|
||||
<Setter Target="PART_RightDragColumn.Width" Value="Auto" />
|
||||
<Setter Target="PART_RightDragColumn.MinWidth" Value="16" />
|
||||
<Setter Target="PART_LeftDragColumn.MinWidth" Value="16" />
|
||||
<Setter Target="PART_ContentColumn.Width" Value="*" />
|
||||
<!-- Content can stretch now -->
|
||||
<Setter Target="PART_ContentPresenter.MinWidth" Value="0" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="WindowActivationStates">
|
||||
<VisualState x:Name="Activated" />
|
||||
<VisualState x:Name="Deactivated">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="PART_TitleText.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" />
|
||||
<Setter Target="PART_SubtitleText.Foreground" Value="{ThemeResource TextFillColorDisabledBrush}" />
|
||||
<Setter Target="PART_BackButton.IsEnabled" Value="False" />
|
||||
<Setter Target="PART_PaneButton.IsEnabled" Value="False" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="DisplayModeStates">
|
||||
<VisualState x:Name="Standard" />
|
||||
<VisualState x:Name="Tall">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="PART_RootGrid.MinHeight" Value="{ThemeResource TitleBarTallHeight}" />
|
||||
<Setter Target="PART_RootGrid.Padding" Value="4" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Copy of WinUI NavigationBackButtonNormalStyle - cannot use it as it picks up the generic.xaml version, not the WinUI version -->
|
||||
<Style x:Key="TitleBarBackButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{ThemeResource NavigationViewBackButtonBackground}" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource NavigationViewItemForegroundChecked}" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource SymbolThemeFontFamily}" />
|
||||
<Setter Property="FontSize" Value="16" />
|
||||
<Setter Property="MaxHeight" Value="40" />
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
|
||||
<Setter Property="Content" Value="" />
|
||||
<Setter Property="Padding" Value="12,4,12,4" />
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Grid
|
||||
x:Name="RootGrid"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<AnimatedIcon
|
||||
x:Name="Content"
|
||||
Width="16"
|
||||
Height="16"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
AnimatedIcon.State="Normal"
|
||||
AutomationProperties.AccessibilityView="Raw">
|
||||
<animatedvisuals:AnimatedBackVisualSource />
|
||||
<AnimatedIcon.FallbackIconSource>
|
||||
<FontIconSource
|
||||
FontFamily="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FontFamily}"
|
||||
FontSize="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FontSize}"
|
||||
Glyph="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"
|
||||
MirroredWhenRightToLeft="True" />
|
||||
</AnimatedIcon.FallbackIconSource>
|
||||
</AnimatedIcon>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource NavigationViewButtonBackgroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource NavigationViewButtonForegroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Content.(AnimatedIcon.State)" Value="PointerOver" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource NavigationViewButtonBackgroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource NavigationViewButtonForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Content.(AnimatedIcon.State)" Value="Pressed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource NavigationViewButtonForegroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Copy of WinUI PaneToggleButtonStyle - cannot use it as it picks up the generic.xaml version, not the WinUI version -->
|
||||
<Style x:Key="TitleBarPaneToggleButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{ThemeResource NavigationViewBackButtonBackground}" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource NavigationViewItemForegroundChecked}" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource SymbolThemeFontFamily}" />
|
||||
<Setter Property="FontSize" Value="16" />
|
||||
<Setter Property="MaxHeight" Value="40" />
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
|
||||
<Setter Property="Content" Value="" />
|
||||
<Setter Property="Padding" Value="12,4,12,4" />
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Grid
|
||||
x:Name="RootGrid"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<AnimatedIcon
|
||||
x:Name="Content"
|
||||
Width="16"
|
||||
Height="16"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
AnimatedIcon.State="Normal"
|
||||
AutomationProperties.AccessibilityView="Raw">
|
||||
<animatedvisuals:AnimatedGlobalNavigationButtonVisualSource />
|
||||
<AnimatedIcon.FallbackIconSource>
|
||||
<FontIconSource
|
||||
FontFamily="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FontFamily}"
|
||||
FontSize="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FontSize}"
|
||||
Glyph="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"
|
||||
MirroredWhenRightToLeft="True" />
|
||||
</AnimatedIcon.FallbackIconSource>
|
||||
</AnimatedIcon>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource NavigationViewButtonBackgroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource NavigationViewButtonForegroundPointerOver}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Content.(AnimatedIcon.State)" Value="PointerOver" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource NavigationViewButtonBackgroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource NavigationViewButtonForegroundPressed}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Content.(AnimatedIcon.State)" Value="Pressed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource NavigationViewButtonForegroundDisabled}" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -21,7 +21,6 @@
|
||||
<Setter Property="Height" Value="32" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource SymbolThemeFontFamily}" />
|
||||
</Style>
|
||||
<tkconverters:StringVisibilityConverter x:Key="StringVisibilityConverter" />
|
||||
</Page.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerLauncher.Telemetry;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
@@ -14,6 +13,7 @@ using Microsoft.UI;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.Data.Json;
|
||||
using WinRT.Interop;
|
||||
using WinUIEx;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI
|
||||
@@ -104,7 +104,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
{
|
||||
if (App.GetOobeWindow() == null)
|
||||
{
|
||||
App.SetOobeWindow(new OobeWindow(Microsoft.PowerToys.Settings.UI.OOBE.Enums.PowerToysModules.Overview));
|
||||
App.SetOobeWindow(new OobeWindow(OOBE.Enums.PowerToysModules.Overview));
|
||||
}
|
||||
|
||||
App.GetOobeWindow().Activate();
|
||||
@@ -115,7 +115,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
{
|
||||
if (App.GetOobeWindow() == null)
|
||||
{
|
||||
App.SetOobeWindow(new OobeWindow(Microsoft.PowerToys.Settings.UI.OOBE.Enums.PowerToysModules.WhatsNew));
|
||||
App.SetOobeWindow(new OobeWindow(OOBE.Enums.PowerToysModules.WhatsNew));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -160,6 +160,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
});
|
||||
|
||||
this.InitializeComponent();
|
||||
SetAppTitleBar();
|
||||
|
||||
// receive IPC Message
|
||||
App.IPCMessageReceivedCallback = (string msg) =>
|
||||
@@ -186,6 +187,13 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
PowerToysTelemetry.Log.WriteEvent(new SettingsBootEvent() { BootTimeMs = bootTime.ElapsedMilliseconds });
|
||||
}
|
||||
|
||||
private void SetAppTitleBar()
|
||||
{
|
||||
// We need to assign the window here so it can configure the custom title bar area correctly.
|
||||
shellPage.TitleBar.Window = this;
|
||||
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(this));
|
||||
}
|
||||
|
||||
public void NavigateToSection(System.Type type)
|
||||
{
|
||||
ShellPage.Navigate(type);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<controls:SettingsGroup x:Uid="MouseUtils_MouseJump">
|
||||
|
||||
<tkcontrols:SettingsCard
|
||||
x:Name="MouseUtilsEnableMouseJump"
|
||||
x:Uid="MouseUtils_Enable_MouseJump"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseJump.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsJumpEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -42,6 +43,7 @@
|
||||
</InfoBar>
|
||||
|
||||
<tkcontrols:SettingsCard
|
||||
x:Name="MouseUtilsMouseJumpActivationShortcut"
|
||||
x:Uid="MouseUtils_MouseJump_ActivationShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsMouseJumpEnabled, Mode=OneWay}">
|
||||
@@ -126,6 +128,7 @@
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
x:Name="MouseUtilsMouseJumpAppearance"
|
||||
x:Uid="MouseUtils_MouseJump_Appearance"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsMouseJumpEnabled, Mode=OneWay}"
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.AdvancedPastePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="using:Microsoft.PowerToys.Settings.UI.Library"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
@@ -11,7 +12,7 @@
|
||||
x:Name="RootPage"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
<Page.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
@@ -37,7 +38,7 @@
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
<Grid>
|
||||
<controls:SettingsPageControl x:Uid="AdvancedPaste" ModuleImageSource="ms-appx:///Assets/Settings/Modules/AdvancedPaste.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
@@ -46,6 +47,7 @@
|
||||
Orientation="Vertical"
|
||||
Spacing="2">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AdvancedPasteEnableToggleControlHeaderText"
|
||||
x:Uid="AdvancedPaste_EnableToggleControl_HeaderText"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/AdvancedPaste.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -61,7 +63,6 @@
|
||||
<FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
|
||||
<controls:SettingsGroup x:Uid="AdvancedPaste_EnableAISettingsGroup" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<InfoBar
|
||||
x:Uid="GPO_AdvancedPasteAi_SettingIsManaged"
|
||||
@@ -73,7 +74,10 @@
|
||||
<FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsCard x:Uid="AdvancedPaste_EnableAISettingsCard" IsEnabled="{x:Bind ViewModel.IsOnlineAIModelsDisallowedByGPO, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AdvancedPasteEnableAISettingsCard"
|
||||
x:Uid="AdvancedPaste_EnableAISettingsCard"
|
||||
IsEnabled="{x:Bind ViewModel.IsOnlineAIModelsDisallowedByGPO, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<tkcontrols:SettingsCard.HeaderIcon>
|
||||
<PathIcon Data="M128 766q0-42 24-77t65-48l178-57q32-11 61-30t52-42q50-50 71-114l58-179q13-40 48-65t78-26q42 0 77 24t50 65l58 177q21 66 72 117 49 50 117 72l176 58q43 14 69 48t26 80q0 41-25 76t-64 49l-178 58q-66 21-117 72-32 32-51 73t-33 84-26 83-30 73-45 51-71 20q-42 0-77-24t-49-65l-58-178q-8-25-19-47t-28-43q-34-43-77-68t-89-41-89-27-78-29-55-45-21-75zm1149 7q-76-29-145-53t-129-60-104-88-73-138l-57-176-67 176q-18 48-42 89t-60 78q-34 34-76 61t-89 43l-177 57q75 29 144 53t127 60 103 89 73 137l57 176 67-176q37-97 103-168t168-103l177-57zm-125 759q0-31 20-57t49-36l99-32q34-11 53-34t30-51 20-59 20-54 33-41 58-16q32 0 59 19t38 50q6 20 11 40t13 40 17 38 25 34q16 17 39 26t48 18 49 16 44 20 31 32 12 50q0 33-18 60t-51 38q-19 6-39 11t-41 13-39 17-34 25q-24 25-35 62t-24 73-35 61-68 25q-32 0-59-19t-38-50q-6-18-11-39t-13-41-17-40-24-33q-18-17-41-27t-47-17-49-15-43-20-30-33-12-54zm583 4q-43-13-74-30t-55-41-40-55-32-74q-12 41-29 72t-42 55-55 42-71 31q81 23 128 71t71 129q15-43 31-74t40-54 53-40 75-32z" />
|
||||
</tkcontrols:SettingsCard.HeaderIcon>
|
||||
@@ -96,15 +100,16 @@
|
||||
</tkcontrols:SettingsCard.Description>
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AdvancedPasteEnableAdvancedAI"
|
||||
x:Uid="AdvancedPaste_EnableAdvancedAI"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/SemanticKernel.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsOpenAIEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.IsAdvancedAIEnabled, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="AdvancedPaste_BehaviorSettingsGroup" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AdvancedPasteClipboardHistoryEnabledSettingsCard"
|
||||
x:Uid="AdvancedPaste_Clipboard_History_Enabled_SettingsCard"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.ClipboardHistoryDisabledByGPO, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -120,19 +125,22 @@
|
||||
<FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsCard x:Uid="AdvancedPaste_CloseAfterLosingFocus">
|
||||
<tkcontrols:SettingsCard Name="AdvancedPasteCloseAfterLosingFocus" x:Uid="AdvancedPaste_CloseAfterLosingFocus">
|
||||
<tkcontrols:SettingsCard.HeaderIcon>
|
||||
<PathIcon Data="M 4 16.284 C 1 22.284 29 59.284 71 101.284 L 143 174.284 L 101 220.284 C 54 271.284 5 367.284 14 390.284 C 23 416.284 40 406.284 56 367.284 C 64 347.284 76 320.284 82 307.284 C 97 278.284 160 215.284 175 215.284 C 181 215.284 199 228.284 214 243.284 C 239 270.284 240 273.284 224 286.284 C 202 304.284 180 357.284 180 392.284 C 180 430.284 213 481.284 252 505.284 C 297 532.284 349 531.284 394 500.284 C 414 486.284 434 475.284 438 475.284 C 442 475.284 484 514.284 532 562.284 C 602 631.284 622 647.284 632 637.284 C 642 627.284 581 561.284 335 315.284 C 164 144.284 22 5.284 18 5.284 C 14 5.284 8 10.284 4 16.284 Z M 337 367.284 C 372 401.284 400 435.284 400 442.284 C 400 457.284 349 485.284 321 485.284 C 269 485.284 220 437.284 220 385.284 C 220 357.284 248 305.284 262 305.284 C 269 305.284 303 333.284 337 367.284 Z M 248 132.284 C 228 137.284 225 151.284 241 161.284 C 247 164.284 284 168.284 324 169.284 C 393 171.284 442 188.284 491 227.284 C 522 252.284 578 335.284 585 364.284 C 592 399.284 607 412.284 622 397.284 C 629 390.284 627 370.284 615 333.284 C 590 260.284 506 176.284 427 147.284 C 373 127.284 293 120.284 248 132.284 Z" />
|
||||
</tkcontrols:SettingsCard.HeaderIcon>
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.CloseAfterLosingFocus, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="AdvancedPaste_ShowCustomPreviewSettingsCard" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AdvancedPasteShowCustomPreviewSettingsCard"
|
||||
x:Uid="AdvancedPaste_ShowCustomPreviewSettingsCard"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowCustomPreview, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="AdvancedPaste_Direct_Access_Hotkeys_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AdvancedPasteUIActions"
|
||||
x:Uid="AdvancedPasteUI_Actions"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsOpenAIEnabled, Mode=OneWay}">
|
||||
@@ -141,25 +149,27 @@
|
||||
Click="AddCustomActionButton_Click"
|
||||
Style="{ThemeResource AccentButtonStyle}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="AdvancedPasteUI_Shortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AdvancedPasteUIShortcut"
|
||||
x:Uid="AdvancedPasteUI_Shortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.AdvancedPasteUIShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="PasteAsPlainText_Shortcut">
|
||||
<tkcontrols:SettingsCard Name="PasteAsPlainTextShortcut" x:Uid="PasteAsPlainText_Shortcut">
|
||||
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.PasteAsPlainTextShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="PasteAsMarkdown_Shortcut">
|
||||
<tkcontrols:SettingsCard Name="PasteAsMarkdownShortcut" x:Uid="PasteAsMarkdown_Shortcut">
|
||||
<controls:ShortcutControl
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
AllowDisable="True"
|
||||
HotkeySettings="{x:Bind Path=ViewModel.PasteAsMarkdownShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="PasteAsJson_Shortcut">
|
||||
<tkcontrols:SettingsCard Name="PasteAsJsonShortcut" x:Uid="PasteAsJson_Shortcut">
|
||||
<controls:ShortcutControl
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
AllowDisable="True"
|
||||
HotkeySettings="{x:Bind Path=ViewModel.PasteAsJsonShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<ItemsControl
|
||||
x:Name="CustomActions"
|
||||
x:Uid="CustomActions"
|
||||
@@ -233,13 +243,15 @@
|
||||
IsTabStop="{x:Bind ViewModel.IsConflictingCopyShortcut, Mode=OneWay}"
|
||||
Severity="Warning" />
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="AdvancedPaste_Additional_Actions_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="ImageToText" DataContext="{x:Bind ViewModel.AdditionalActions.ImageToText, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ImageToText"
|
||||
x:Uid="ImageToText"
|
||||
DataContext="{x:Bind ViewModel.AdditionalActions.ImageToText, Mode=OneWay}">
|
||||
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="PasteAsFile"
|
||||
x:Uid="PasteAsFile"
|
||||
DataContext="{x:Bind ViewModel.AdditionalActions.PasteAsFile, Mode=OneWay}"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
@@ -254,18 +266,21 @@
|
||||
<!-- HACK: For some weird reason, a ShortcutControl does not work correctly if it's the first or last item in the expander, so we add an invisible card. -->
|
||||
<tkcontrols:SettingsCard Visibility="Collapsed" />
|
||||
<tkcontrols:SettingsCard
|
||||
Name="PasteAsTxtFile"
|
||||
x:Uid="PasteAsTxtFile"
|
||||
DataContext="{Binding PasteAsTxtFile, Mode=TwoWay}"
|
||||
IsEnabled="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=OneWay}">
|
||||
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard
|
||||
Name="PasteAsPngFile"
|
||||
x:Uid="PasteAsPngFile"
|
||||
DataContext="{Binding PasteAsPngFile, Mode=TwoWay}"
|
||||
IsEnabled="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=OneWay}">
|
||||
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard
|
||||
Name="PasteAsHtmlFile"
|
||||
x:Uid="PasteAsHtmlFile"
|
||||
DataContext="{Binding PasteAsHtmlFile, Mode=TwoWay}"
|
||||
IsEnabled="{x:Bind ViewModel.AdditionalActions.PasteAsFile.IsShown, Mode=OneWay}">
|
||||
@@ -275,8 +290,8 @@
|
||||
<tkcontrols:SettingsCard Visibility="Collapsed" />
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="Transcode"
|
||||
x:Uid="Transcode"
|
||||
DataContext="{x:Bind ViewModel.AdditionalActions.Transcode, Mode=OneWay}"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
@@ -291,12 +306,14 @@
|
||||
<!-- HACK: For some weird reason, a ShortcutControl does not work correctly if it's the first or last item in the expander, so we add an invisible card. -->
|
||||
<tkcontrols:SettingsCard Visibility="Collapsed" />
|
||||
<tkcontrols:SettingsCard
|
||||
Name="TranscodeToMp3"
|
||||
x:Uid="TranscodeToMp3"
|
||||
DataContext="{Binding TranscodeToMp3, Mode=TwoWay}"
|
||||
IsEnabled="{x:Bind ViewModel.AdditionalActions.Transcode.IsShown, Mode=OneWay}">
|
||||
<ContentControl ContentTemplate="{StaticResource AdditionalActionTemplate}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard
|
||||
Name="TranscodeToMp4"
|
||||
x:Uid="TranscodeToMp4"
|
||||
DataContext="{Binding TranscodeToMp4, Mode=TwoWay}"
|
||||
IsEnabled="{x:Bind ViewModel.AdditionalActions.Transcode.IsShown, Mode=OneWay}">
|
||||
@@ -306,7 +323,6 @@
|
||||
<tkcontrols:SettingsCard Visibility="Collapsed" />
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
<InfoBar
|
||||
x:Uid="AdvancedPaste_ShortcutWarning"
|
||||
IsClosable="False"
|
||||
@@ -320,7 +336,6 @@
|
||||
<controls:PageLink x:Uid="LearnMore_AdvancedPaste" Link="https://aka.ms/PowerToysOverview_AdvancedPaste" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
|
||||
<ContentDialog
|
||||
x:Name="EnableAIDialog"
|
||||
x:Uid="EnableAIDialog"
|
||||
@@ -349,7 +364,6 @@
|
||||
<Run x:Uid="PrivacyLink" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Vertical">
|
||||
<TextBlock x:Uid="AdvancedPaste_EnableAIDialog_ConfigureOpenAIKey" FontWeight="SemiBold" />
|
||||
<TextBlock Grid.Row="2" TextWrapping="Wrap">
|
||||
@@ -411,4 +425,4 @@
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
</Grid>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
@@ -15,7 +15,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class AdvancedPastePage : Page, IRefreshablePage
|
||||
public sealed partial class AdvancedPastePage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private AdvancedPasteViewModel ViewModel { get; set; }
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.AlwaysOnTopPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
@@ -17,6 +18,7 @@
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AlwaysOnTopEnableToggleControlHeaderText"
|
||||
x:Uid="AlwaysOnTop_EnableToggleControl_HeaderText"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/AlwaysOnTop.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -35,6 +37,7 @@
|
||||
<controls:SettingsGroup x:Uid="AlwaysOnTop_Activation_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="AlwaysOnTopActivationShortcut"
|
||||
x:Uid="AlwaysOnTop_ActivationShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
@@ -49,31 +52,42 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="AlwaysOnTop_Behavior_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="AlwaysOnTopFrameEnabled"
|
||||
x:Uid="AlwaysOnTop_FrameEnabled"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.FrameEnabled, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="AlwaysOnTop_FrameColor_Mode" IsEnabled="{x:Bind ViewModel.FrameEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AlwaysOnTopFrameColorMode"
|
||||
x:Uid="AlwaysOnTop_FrameColor_Mode"
|
||||
IsEnabled="{x:Bind ViewModel.FrameEnabled, Mode=OneWay}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind ViewModel.FrameAccentColor, Mode=TwoWay, Converter={StaticResource BoolToComboBoxIndexConverter}}">
|
||||
<ComboBoxItem x:Uid="AlwaysOnTop_Radio_Custom_Color" />
|
||||
<ComboBoxItem x:Uid="AlwaysOnTop_Radio_Windows_Default" />
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AlwaysOnTopFrameColor"
|
||||
x:Uid="AlwaysOnTop_FrameColor"
|
||||
IsEnabled="{x:Bind ViewModel.FrameEnabled, Mode=OneWay}"
|
||||
Visibility="{x:Bind ViewModel.FrameAccentColor, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
|
||||
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.FrameColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="AlwaysOnTop_FrameOpacity" IsEnabled="{x:Bind ViewModel.FrameEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AlwaysOnTopFrameOpacity"
|
||||
x:Uid="AlwaysOnTop_FrameOpacity"
|
||||
IsEnabled="{x:Bind ViewModel.FrameEnabled, Mode=OneWay}">
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{x:Bind ViewModel.FrameOpacity, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="AlwaysOnTop_FrameThickness" IsEnabled="{x:Bind ViewModel.FrameEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AlwaysOnTopFrameThickness"
|
||||
x:Uid="AlwaysOnTop_FrameThickness"
|
||||
IsEnabled="{x:Bind ViewModel.FrameEnabled, Mode=OneWay}">
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
LargeChange="5"
|
||||
@@ -95,6 +109,7 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="ExcludedApps" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="AlwaysOnTopExcludedApps"
|
||||
x:Uid="AlwaysOnTop_ExcludedApps"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
@@ -121,4 +136,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_AlwaysOnTop" Link="https://aka.ms/PowerToysOverview_AlwaysOnTop" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class AlwaysOnTopPage : Page, IRefreshablePage
|
||||
public sealed partial class AlwaysOnTopPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private AlwaysOnTopViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.AwakePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
@@ -13,9 +14,9 @@
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:AwakeModeToIntConverter x:Key="AwakeModeToIntConverter" />
|
||||
</Page.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
|
||||
<controls:SettingsPageControl
|
||||
x:Uid="Awake"
|
||||
@@ -24,6 +25,7 @@
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AwakeEnableSettingsCard"
|
||||
x:Uid="Awake_EnableSettingsCard"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/Awake.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -42,7 +44,10 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="Awake_BehaviorSettingsGroup" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="Awake_ModeSettingsCard" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AwakeModeSettingsCard"
|
||||
x:Uid="Awake_ModeSettingsCard"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.Mode, Mode=TwoWay, Converter={StaticResource AwakeModeToIntConverter}}">
|
||||
<ComboBoxItem x:Uid="Awake_NoKeepAwakeSelector" />
|
||||
<ComboBoxItem x:Uid="Awake_IndefiniteKeepAwakeSelector" />
|
||||
@@ -52,21 +57,23 @@
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="AwakeExpirationSettingsExpander"
|
||||
x:Uid="Awake_ExpirationSettingsExpander"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True"
|
||||
Visibility="{x:Bind ViewModel.IsExpirationConfigurationEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="Awake_ExpirationSettingsExpander_Date">
|
||||
<tkcontrols:SettingsCard Name="AwakeExpirationSettingsExpanderDate" x:Uid="Awake_ExpirationSettingsExpander_Date">
|
||||
<DatePicker Date="{x:Bind ViewModel.ExpirationDateTime, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="Awake_ExpirationSettingsExpander_Time">
|
||||
<tkcontrols:SettingsCard Name="AwakeExpirationSettingsExpanderTime" x:Uid="Awake_ExpirationSettingsExpander_Time">
|
||||
<TimePicker ClockIdentifier="24HourClock" Time="{x:Bind ViewModel.ExpirationTime, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
<tkcontrols:SettingsCard
|
||||
Name="AwakeIntervalSettingsCard"
|
||||
x:Uid="Awake_IntervalSettingsCard"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
Visibility="{x:Bind ViewModel.IsTimeConfigurationEnabled, Mode=OneWay}">
|
||||
@@ -112,4 +119,4 @@
|
||||
<controls:PageLink x:Uid="SecondaryLink_Awake" Link="https://awake.den.dev" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -17,7 +17,7 @@ using PowerToys.GPOWrapper;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class AwakePage : Page, IRefreshablePage
|
||||
public sealed partial class AwakePage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private readonly string _appName = "Awake";
|
||||
private readonly SettingsUtils _settingsUtils;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.CmdNotFoundPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
|
||||
@@ -35,6 +36,7 @@
|
||||
</InfoBar>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="CmdNotFoundEnable"
|
||||
x:Uid="CmdNotFound_Enable"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/CommandNotFound.png}"
|
||||
IsExpanded="True">
|
||||
@@ -84,7 +86,7 @@
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsExpander.ItemsHeader>
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="CmdNotFound_PowerShellDetection">
|
||||
<tkcontrols:SettingsCard Name="CmdNotFoundPowerShellDetection" x:Uid="CmdNotFound_PowerShellDetection">
|
||||
<tkcontrols:SwitchPresenter TargetType="x:Boolean" Value="{x:Bind ViewModel.IsPowerShell7Detected, Mode=OneWay}">
|
||||
<tkcontrols:Case Value="True">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
@@ -117,7 +119,7 @@
|
||||
</tkcontrols:SwitchPresenter>
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="CmdNotFound_WinGetClientDetection">
|
||||
<tkcontrols:SettingsCard Name="CmdNotFoundWinGetClientDetection" x:Uid="CmdNotFound_WinGetClientDetection">
|
||||
<tkcontrols:SwitchPresenter TargetType="x:Boolean" Value="{x:Bind ViewModel.IsWinGetClientModuleDetected, Mode=OneWay}">
|
||||
<tkcontrols:Case Value="True">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
@@ -168,4 +170,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_CmdNotFound" Link="https://aka.ms/PowerToysOverview_CmdNotFound" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class CmdNotFoundPage : Page
|
||||
public sealed partial class CmdNotFoundPage : NavigablePage
|
||||
{
|
||||
private CmdNotFoundViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.CmdPalPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
@@ -14,6 +15,7 @@
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="CmdPalEnableCmdPal"
|
||||
x:Uid="CmdPal_Enable_CmdPal"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/CmdPal.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -27,7 +29,10 @@
|
||||
Severity="Informational" />
|
||||
|
||||
<controls:SettingsGroup x:Uid="CmdPal_Activation_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="CmdPal_ActivationShortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="CmdPalActivationShortcut"
|
||||
x:Uid="CmdPal_ActivationShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
HotkeySettings="{x:Bind Path=ViewModel.Hotkey, Mode=OneWay}"
|
||||
@@ -47,4 +52,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_CmdPal" Link="https://aka.ms/PowerToysOverview_CmdPal" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -13,7 +13,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class CmdPalPage : Page, IRefreshablePage
|
||||
public sealed partial class CmdPalPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private CmdPalViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.ColorPickerPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="using:Microsoft.PowerToys.Settings.UI.Library"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
@@ -21,6 +22,7 @@
|
||||
ChildrenTransitions="{StaticResource SettingsCardsAnimations}"
|
||||
Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ColorPickerEnableColorPicker"
|
||||
x:Uid="ColorPicker_EnableColorPicker"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/ColorPicker.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -38,11 +40,17 @@
|
||||
</InfoBar>
|
||||
|
||||
<controls:SettingsGroup x:Uid="Shortcut" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="Activation_Shortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ActivationShortcut"
|
||||
x:Uid="Activation_Shortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.ActivationShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="ColorPicker_ActivationAction" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ColorPickerActivationAction"
|
||||
x:Uid="ColorPicker_ActivationAction"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.ActivationBehavior, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="ColorPicker_OpenEditor" />
|
||||
<ComboBoxItem x:Uid="ColorPicker_PickColor" />
|
||||
@@ -50,25 +58,35 @@
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="ColorPickerMouseActions"
|
||||
x:Uid="ColorPicker_MouseActions"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="ColorPicker_PrimaryClick" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ColorPickerPrimaryClick"
|
||||
x:Uid="ColorPicker_PrimaryClick"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind ViewModel.PrimaryClickBehavior, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="ColorPicker_PickColorThenEditor" />
|
||||
<ComboBoxItem x:Uid="ColorPicker_PickColorAndClose" />
|
||||
<ComboBoxItem x:Uid="ColorPicker_Close" />
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="ColorPicker_MiddleClick" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ColorPickerMiddleClick"
|
||||
x:Uid="ColorPicker_MiddleClick"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind ViewModel.MiddleClickBehavior, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="ColorPicker_PickColorThenEditor" />
|
||||
<ComboBoxItem x:Uid="ColorPicker_PickColorAndClose" />
|
||||
<ComboBoxItem x:Uid="ColorPicker_Close" />
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="ColorPicker_SecondaryClick" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ColorPickerSecondaryClick"
|
||||
x:Uid="ColorPicker_SecondaryClick"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind ViewModel.SecondaryClickBehavior, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="ColorPicker_PickColorThenEditor" />
|
||||
<ComboBoxItem x:Uid="ColorPicker_PickColorAndClose" />
|
||||
@@ -80,7 +98,10 @@
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="ColorFormats" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="ColorPicker_CopiedColorRepresentation" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ColorPickerCopiedColorRepresentation"
|
||||
x:Uid="ColorPicker_CopiedColorRepresentation"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox
|
||||
x:Name="ColorPicker_ComboBox"
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
@@ -92,7 +113,7 @@
|
||||
SelectedValuePath="Key" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="ColorPicker_ShowColorName">
|
||||
<tkcontrols:SettingsCard Name="ColorPickerShowColorName" x:Uid="ColorPicker_ShowColorName">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{Binding ShowColorName, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<!--
|
||||
@@ -211,4 +232,4 @@
|
||||
<controls:PageLink Link="https://medium.com/@Niels9001/a-fluent-color-meter-for-powertoys-20407ededf0c" Text="Niels Laute's UX concept" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
@@ -15,7 +15,7 @@ using Microsoft.Windows.ApplicationModel.Resources;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class ColorPickerPage : Page, IRefreshablePage
|
||||
public sealed partial class ColorPickerPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
public ColorPickerViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.CropAndLockPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
@@ -17,6 +18,7 @@
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="CropAndLockEnableToggleControlHeaderText"
|
||||
x:Uid="CropAndLock_EnableToggleControl_HeaderText"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/CropAndLock.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -34,13 +36,19 @@
|
||||
</InfoBar>
|
||||
<controls:SettingsGroup x:Uid="CropAndLock_Activation_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="CropAndLock_ThumbnailActivation_Shortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="CropAndLockThumbnailActivationShortcut"
|
||||
x:Uid="CropAndLock_ThumbnailActivation_Shortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
AllowDisable="True"
|
||||
HotkeySettings="{x:Bind Path=ViewModel.ThumbnailActivationShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="CropAndLock_ReparentActivation_Shortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="CropAndLockReparentActivationShortcut"
|
||||
x:Uid="CropAndLock_ReparentActivation_Shortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
AllowDisable="True"
|
||||
@@ -58,4 +66,4 @@
|
||||
<controls:PageLink Link="https://github.com/kevinguo305" Text="Kevin Guo" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class CropAndLockPage : Page, IRefreshablePage
|
||||
public sealed partial class CropAndLockPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private CropAndLockViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.DashboardPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
|
||||
@@ -13,7 +14,7 @@
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
DataContext="DashboardViewModel"
|
||||
mc:Ignorable="d">
|
||||
<Page.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:ModuleItemTemplateSelector
|
||||
x:Key="ModuleItemTemplateSelector"
|
||||
ActivationTemplate="{StaticResource ModuleItemActivationTemplate}"
|
||||
@@ -73,7 +74,7 @@
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</Page.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
<Grid Margin="16,0,0,0" RowSpacing="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -362,4 +363,4 @@
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
/// <summary>
|
||||
/// Dashboard Settings Page.
|
||||
/// </summary>
|
||||
public sealed partial class DashboardPage : Page, IRefreshablePage
|
||||
public sealed partial class DashboardPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets view model.
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.EnvironmentVariablesPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
@@ -13,6 +14,7 @@
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="EnvironmentVariablesEnableToggleControlHeaderText"
|
||||
x:Uid="EnvironmentVariables_EnableToggleControl_HeaderText"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/EnvironmentVariables.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -30,12 +32,14 @@
|
||||
</InfoBar>
|
||||
<controls:SettingsGroup x:Uid="EnvironmentVariables_Activation_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="EnvironmentVariablesLaunchButtonControl"
|
||||
x:Uid="EnvironmentVariables_LaunchButtonControl"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Command="{x:Bind ViewModel.LaunchEventHandler}"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsClickEnabled="True" />
|
||||
<tkcontrols:SettingsCard
|
||||
Name="EnvironmentVariablesToggleLaunchAdministrator"
|
||||
x:Uid="EnvironmentVariables_Toggle_LaunchAdministrator"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.LaunchAdministratorEnabled, Mode=OneWay}">
|
||||
@@ -49,4 +53,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_EnvironmentVariables" Link="https://aka.ms/PowerToysOverview_EnvironmentVariables" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class EnvironmentVariablesPage : Page, IRefreshablePage
|
||||
public sealed partial class EnvironmentVariablesPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private EnvironmentVariablesViewModel ViewModel { get; }
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.FancyZonesPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
@@ -14,6 +15,7 @@
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesEnableToggleControlHeaderText"
|
||||
x:Uid="FancyZones_EnableToggleControl_HeaderText"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/FancyZones.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -32,6 +34,7 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="FancyZones_Editor_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesLaunchEditorButtonControl"
|
||||
x:Uid="FancyZones_LaunchEditorButtonControl"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
AutomationProperties.AutomationId="LaunchLayoutEditorButton"
|
||||
@@ -39,11 +42,17 @@
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsClickEnabled="True" />
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="Activation_Shortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ActivationShortcut"
|
||||
x:Uid="Activation_Shortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.EditorHotkey, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="FancyZones_UseCursorPosEditorStartupScreen" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesUseCursorPosEditorStartupScreen"
|
||||
x:Uid="FancyZones_UseCursorPosEditorStartupScreen"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind ViewModel.UseCursorPosEditorStartupScreen, Mode=TwoWay, Converter={StaticResource BoolToComboBoxIndexConverter}}">
|
||||
<ComboBoxItem x:Uid="FancyZones_LaunchPositionScreen" />
|
||||
<ComboBoxItem x:Uid="FancyZones_LaunchPositionMouse" />
|
||||
@@ -56,24 +65,27 @@
|
||||
x:Name="ZonesSettingsGroup"
|
||||
x:Uid="FancyZones_Zones"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander x:Uid="FancyZones_ZoneBehavior_GroupSettings" IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="FancyZonesZoneBehaviorGroupSettings"
|
||||
x:Uid="FancyZones_ZoneBehavior_GroupSettings"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesShiftDragCheckBoxControlHeader" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_ShiftDragCheckBoxControl_Header" IsChecked="{x:Bind ViewModel.ShiftDrag, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesMouseDragCheckBoxControlHeader" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_MouseDragCheckBoxControl_Header" IsChecked="{x:Bind ViewModel.MouseSwitch, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesMouseMiddleClickSpanningMultipleZonesCheckBoxControlHeader" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_MouseMiddleClickSpanningMultipleZonesCheckBoxControl_Header" IsChecked="{x:Bind ViewModel.MouseMiddleClickSpanningMultipleZones, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesShowZonesOnAllMonitorsCheckBoxControl" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_ShowZonesOnAllMonitorsCheckBoxControl" IsChecked="{x:Bind ViewModel.ShowOnAllMonitors, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesSpanZonesAcrossMonitors" ContentAlignment="Left">
|
||||
<controls:CheckBoxWithDescriptionControl x:Uid="FancyZones_SpanZonesAcrossMonitors" IsChecked="{x:Bind ViewModel.SpanZonesAcrossMonitors, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="FancyZones_OverlappingZones">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesOverlappingZones" x:Uid="FancyZones_OverlappingZones">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.OverlappingZonesAlgorithmIndex, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="FancyZones_OverlappingZonesSmallest" />
|
||||
<ComboBoxItem x:Uid="FancyZones_OverlappingZonesLargest" />
|
||||
@@ -85,6 +97,7 @@
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="FancyZonesZoneAppearance"
|
||||
x:Uid="FancyZones_Zone_Appearance"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
@@ -93,7 +106,7 @@
|
||||
<ComboBoxItem x:Uid="FancyZones_Radio_Default_Theme" />
|
||||
</ComboBox>
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesPreviewCard" ContentAlignment="Left">
|
||||
<controls:FancyZonesPreviewControl
|
||||
Width="192"
|
||||
Height="108"
|
||||
@@ -105,10 +118,10 @@
|
||||
IsSystemTheme="{x:Bind ViewModel.SystemTheme, Mode=OneWay}"
|
||||
ShowZoneNumber="{x:Bind Path=ViewModel.ShowZoneNumber, Mode=OneWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesShowZoneNumberCheckBoxControl" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_ShowZoneNumberCheckBoxControl" IsChecked="{x:Bind ViewModel.ShowZoneNumber, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="FancyZones_HighlightOpacity">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesHighlightOpacity" x:Uid="FancyZones_HighlightOpacity">
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
Maximum="100"
|
||||
@@ -116,16 +129,28 @@
|
||||
Value="{x:Bind ViewModel.HighlightOpacity, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="FancyZones_ZoneHighlightColor" Visibility="{x:Bind ViewModel.SystemTheme, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesZoneHighlightColor"
|
||||
x:Uid="FancyZones_ZoneHighlightColor"
|
||||
Visibility="{x:Bind ViewModel.SystemTheme, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
|
||||
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.ZoneHighlightColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="FancyZones_InActiveColor" Visibility="{x:Bind ViewModel.SystemTheme, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesInActiveColor"
|
||||
x:Uid="FancyZones_InActiveColor"
|
||||
Visibility="{x:Bind ViewModel.SystemTheme, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
|
||||
<controls:ColorPickerButton x:Name="InActiveColorButton" SelectedColor="{x:Bind Path=ViewModel.ZoneInActiveColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="FancyZones_BorderColor" Visibility="{x:Bind ViewModel.SystemTheme, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesBorderColor"
|
||||
x:Uid="FancyZones_BorderColor"
|
||||
Visibility="{x:Bind ViewModel.SystemTheme, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
|
||||
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.ZoneBorderColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="FancyZones_NumberColor" Visibility="{x:Bind ViewModel.SystemTheme, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesNumberColor"
|
||||
x:Uid="FancyZones_NumberColor"
|
||||
Visibility="{x:Bind ViewModel.SystemTheme, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}">
|
||||
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.ZoneNumberColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
@@ -134,59 +159,76 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="FancyZones_Windows" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
|
||||
<tkcontrols:SettingsExpander x:Uid="FancyZones_WindowBehavior_GroupSettings" IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="FancyZonesWindowBehaviorGroupSettings"
|
||||
x:Uid="FancyZones_WindowBehavior_GroupSettings"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesDisplayOrWorkAreaChangeMoveWindowsCheckBoxControl" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_DisplayOrWorkAreaChangeMoveWindowsCheckBoxControl" IsChecked="{x:Bind ViewModel.DisplayOrWorkAreaChangeMoveWindows, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesZoneSetChangeMoveWindows" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_ZoneSetChangeMoveWindows" IsChecked="{x:Bind ViewModel.ZoneSetChangeMoveWindows, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesAppLastZoneMoveWindows" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_AppLastZoneMoveWindows" IsChecked="{x:Bind ViewModel.AppLastZoneMoveWindows, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesOpenWindowOnActiveMonitor" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_OpenWindowOnActiveMonitor" IsChecked="{x:Bind ViewModel.OpenWindowOnActiveMonitor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesRestoreSize" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_RestoreSize" IsChecked="{x:Bind ViewModel.RestoreSize, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesMakeDraggedWindowTransparentCheckBoxControl" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_MakeDraggedWindowTransparentCheckBoxControl" IsChecked="{x:Bind ViewModel.MakeDraggedWindowsTransparent, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesAllowChildWindowSnap" ContentAlignment="Left">
|
||||
<CheckBox x:Uid="FancyZones_AllowChildWindowSnap" IsChecked="{x:Bind ViewModel.AllowChildWindowSnap, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left" Visibility="{x:Bind ViewModel.Windows11, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesDisableRoundCornersOnWindowSnap"
|
||||
ContentAlignment="Left"
|
||||
Visibility="{x:Bind ViewModel.Windows11, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<CheckBox x:Uid="FancyZones_DisableRoundCornersOnWindowSnap" IsChecked="{x:Bind ViewModel.DisableRoundCornersOnWindowSnap, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="FancyZonesWindowSwitchingGroupSettings"
|
||||
x:Uid="FancyZones_WindowSwitching_GroupSettings"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.WindowSwitching, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<!-- HACK: For some weird reason, a Shortcut Control is not working correctly if it's the first item in the expander, so we add an invisible card as the first one. -->
|
||||
<tkcontrols:SettingsCard Visibility="Collapsed" />
|
||||
<tkcontrols:SettingsCard x:Uid="FancyZones_HotkeyNextTabControl" IsEnabled="{x:Bind ViewModel.WindowSwitchingCategoryEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard Name="FancyZonesWindowSwitchingPlaceholder" Visibility="Collapsed" />
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesHotkeyNextTabControl"
|
||||
x:Uid="FancyZones_HotkeyNextTabControl"
|
||||
IsEnabled="{x:Bind ViewModel.WindowSwitchingCategoryEnabled, Mode=OneWay}">
|
||||
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.NextTabHotkey, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="FancyZones_HotkeyPrevTabControl" IsEnabled="{x:Bind ViewModel.WindowSwitchingCategoryEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesHotkeyPrevTabControl"
|
||||
x:Uid="FancyZones_HotkeyPrevTabControl"
|
||||
IsEnabled="{x:Bind ViewModel.WindowSwitchingCategoryEnabled, Mode=OneWay}">
|
||||
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.PrevTabHotkey, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="FancyZonesOverrideSnapHotkeys"
|
||||
x:Uid="FancyZones_OverrideSnapHotkeys"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.OverrideSnapHotkeys, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="FancyZones_MoveWindow" IsEnabled="{x:Bind ViewModel.SnapHotkeysCategoryEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesMoveWindow"
|
||||
x:Uid="FancyZones_MoveWindow"
|
||||
IsEnabled="{x:Bind ViewModel.SnapHotkeysCategoryEnabled, Mode=OneWay}">
|
||||
<ComboBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
MinHeight="56"
|
||||
@@ -209,7 +251,10 @@
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind ViewModel.SnapHotkeysCategoryEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesMoveWindowsAcrossAllMonitorsCheckBoxControl"
|
||||
ContentAlignment="Left"
|
||||
IsEnabled="{x:Bind ViewModel.SnapHotkeysCategoryEnabled, Mode=OneWay}">
|
||||
<CheckBox x:Uid="FancyZones_MoveWindowsAcrossAllMonitorsCheckBoxControl" IsChecked="{x:Bind ViewModel.MoveWindowsAcrossMonitors, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
@@ -217,10 +262,16 @@
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="FancyZones_Layouts" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander x:Uid="FancyZones_QuickLayoutSwitch" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="FancyZonesQuickLayoutSwitch"
|
||||
x:Uid="FancyZones_QuickLayoutSwitch"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.QuickLayoutSwitch, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind ViewModel.QuickSwitchEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesFlashZonesOnQuickSwitch"
|
||||
ContentAlignment="Left"
|
||||
IsEnabled="{x:Bind ViewModel.QuickSwitchEnabled, Mode=OneWay}">
|
||||
<CheckBox x:Uid="FancyZones_FlashZonesOnQuickSwitch" IsChecked="{x:Bind ViewModel.FlashZonesOnQuickSwitch, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
@@ -230,11 +281,15 @@
|
||||
<controls:SettingsGroup x:Uid="ExcludedApps" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="FancyZonesExcludeApps"
|
||||
x:Uid="FancyZones_ExcludeApps"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard HorizontalContentAlignment="Stretch" ContentAlignment="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FancyZonesExcludeAppsTextBoxControl"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ContentAlignment="Vertical">
|
||||
<TextBox
|
||||
x:Uid="FancyZones_ExcludeApps_TextBoxControl"
|
||||
MinWidth="240"
|
||||
@@ -256,4 +311,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_FancyZones" Link="https://aka.ms/PowerToysOverview_FancyZones" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class FancyZonesPage : Page, IRefreshablePage
|
||||
public sealed partial class FancyZonesPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private FancyZonesViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.FileLocksmithPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
@@ -14,6 +15,7 @@
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="FileLocksmithEnableFileLocksmith"
|
||||
x:Uid="FileLocksmith_Enable_FileLocksmith"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/FileLocksmith.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -32,7 +34,7 @@
|
||||
</InfoBar>
|
||||
|
||||
<controls:SettingsGroup x:Uid="FileLocksmith_ShellIntegration" IsEnabled="{x:Bind ViewModel.IsFileLocksmithEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="FileLocksmith_Toggle_ContextMenu">
|
||||
<tkcontrols:SettingsCard Name="FileLocksmithToggleContextMenu" x:Uid="FileLocksmith_Toggle_ContextMenu">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind ViewModel.EnabledOnContextExtendedMenu, Mode=TwoWay, Converter={StaticResource BoolToComboBoxIndexConverter}}">
|
||||
<ComboBoxItem x:Uid="FileLocksmith_Toggle_StandardContextMenu" />
|
||||
<ComboBoxItem x:Uid="FileLocksmith_Toggle_ExtendedContextMenu" />
|
||||
@@ -51,4 +53,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_FileLocksmith" Link="https://aka.ms/PowerToysOverview_FileLocksmith" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class FileLocksmithPage : Page, IRefreshablePage
|
||||
public sealed partial class FileLocksmithPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private FileLocksmithViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.GeneralPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:UpdateStateToBoolConverter x:Key="UpdateStateToBoolConverter" />
|
||||
<converters:StringToInfoBarSeverityConverter x:Key="StringToInfoBarSeverityConverter" />
|
||||
</Page.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
|
||||
<controls:SettingsPageControl x:Uid="General" ModuleImageSource="ms-appx:///Assets/Settings/Modules/PT.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
@@ -209,6 +211,7 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="Admin_Mode">
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="AdminModeRunningAs"
|
||||
x:Uid="Admin_Mode_Running_As"
|
||||
Header="{x:Bind ViewModel.RunningAsText, Mode=OneWay}"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
@@ -232,7 +235,10 @@
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="Appearance_Behavior" IsEnabled="True">
|
||||
<tkcontrols:SettingsCard x:Uid="LanguageHeader" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="LanguageHeader"
|
||||
x:Uid="LanguageHeader"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox
|
||||
x:Name="Languages_ComboBox"
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
@@ -251,7 +257,10 @@
|
||||
</InfoBar.ActionButton>
|
||||
</InfoBar>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="ColorModeHeader" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ColorModeHeader"
|
||||
x:Uid="ColorModeHeader"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard.Description>
|
||||
<HyperlinkButton x:Uid="Windows_Color_Settings" Click="OpenColorsSettings_Click" />
|
||||
</tkcontrols:SettingsCard.Description>
|
||||
@@ -262,10 +271,12 @@
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="GeneralPage_RunAtStartUp" IsEnabled="{x:Bind ViewModel.IsRunAtStartupGPOManaged, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="GeneralPageRunAtStartUp"
|
||||
x:Uid="GeneralPage_RunAtStartUp"
|
||||
IsEnabled="{x:Bind ViewModel.IsRunAtStartupGPOManaged, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.Startup, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="ShowSystemTrayIcon">
|
||||
<ToggleSwitch
|
||||
x:Uid="ShowSystemTrayIcon_ToggleSwitch"
|
||||
@@ -287,13 +298,16 @@
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="General_SettingsBackupAndRestoreTitle" Visibility="Visible">
|
||||
<tkcontrols:SettingsExpander x:Uid="General_SettingsBackupAndRestore" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="GeneralSettingsBackupAndRestore"
|
||||
x:Uid="General_SettingsBackupAndRestore"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Button x:Uid="General_SettingsBackupAndRestore_ButtonBackup" Command="{Binding BackupConfigsEventHandler}" />
|
||||
<Button x:Uid="General_SettingsBackupAndRestore_ButtonRestore" Command="{Binding RestoreConfigsEventHandler}" />
|
||||
</StackPanel>
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="General_SettingsBackupAndRestoreLocationText">
|
||||
<tkcontrols:SettingsCard Name="GeneralSettingsBackupAndRestoreLocationText" x:Uid="General_SettingsBackupAndRestoreLocationText">
|
||||
<Grid ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
@@ -327,6 +341,7 @@
|
||||
</Grid>
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard
|
||||
Name="GeneralSettingsBackupAndRestoreStatusInfo"
|
||||
x:Uid="General_SettingsBackupAndRestoreStatusInfo"
|
||||
HorizontalContentAlignment="Left"
|
||||
ContentAlignment="Vertical">
|
||||
@@ -390,7 +405,10 @@
|
||||
IsTabStop="{x:Bind ViewModel.SettingsBackupRestoreMessageVisible, Mode=OneWay}"
|
||||
Severity="{x:Bind ViewModel.BackupRestoreMessageSeverity, Converter={StaticResource StringToInfoBarSeverityConverter}}" />
|
||||
<controls:SettingsGroup x:Uid="General_Experimentation" Visibility="Visible">
|
||||
<tkcontrols:SettingsCard x:Uid="GeneralPage_EnableExperimentation" IsEnabled="{x:Bind ViewModel.IsExperimentationGpoDisallowed, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="GeneralPageEnableExperimentation"
|
||||
x:Uid="GeneralPage_EnableExperimentation"
|
||||
IsEnabled="{x:Bind ViewModel.IsExperimentationGpoDisallowed, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<tkcontrols:SettingsCard.HeaderIcon>
|
||||
<PathIcon Data="M1859 1758q14 23 21 47t7 51q0 40-15 75t-41 61-61 41-75 15H354q-40 0-75-15t-61-41-41-61-15-75q0-27 6-51t21-47l569-992q10-14 10-34V128H640V0h768v128h-128v604q0 19 10 35l569 991zM896 732q0 53-27 99l-331 577h972l-331-577q-27-46-27-99V128H896v604zm799 1188q26 0 44-19t19-45q0-10-2-17t-8-16l-164-287H464l-165 287q-9 15-9 33 0 26 18 45t46 19h1341z" />
|
||||
</tkcontrols:SettingsCard.HeaderIcon>
|
||||
@@ -499,4 +517,4 @@
|
||||
<controls:PageLink x:Uid="OpenSource_Notice" Link="https://github.com/microsoft/PowerToys/blob/main/NOTICE.md" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
/// <summary>
|
||||
/// General Settings Page.
|
||||
/// </summary>
|
||||
public sealed partial class GeneralPage : Page, IRefreshablePage
|
||||
public sealed partial class GeneralPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private static DateTime OkToHideBackupAndRestoreMessageTime { get; set; }
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.HostsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
@@ -13,6 +14,7 @@
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="HostsEnableToggleControlHeaderText"
|
||||
x:Uid="Hosts_EnableToggleControl_HeaderText"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/Hosts.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -30,30 +32,41 @@
|
||||
</InfoBar>
|
||||
<controls:SettingsGroup x:Uid="Hosts_Activation_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="HostsLaunchButtonControl"
|
||||
x:Uid="Hosts_LaunchButtonControl"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Command="{x:Bind ViewModel.LaunchEventHandler}"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsClickEnabled="True" />
|
||||
<tkcontrols:SettingsCard
|
||||
Name="HostsToggleLaunchAdministrator"
|
||||
x:Uid="Hosts_Toggle_LaunchAdministrator"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.LaunchAdministratorEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.LaunchAdministrator, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="Hosts_Toggle_ShowStartupWarning" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="HostsToggleShowStartupWarning"
|
||||
x:Uid="Hosts_Toggle_ShowStartupWarning"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.ShowStartupWarning, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="Hosts_Behavior_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="Hosts_AdditionalLinesPosition" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="HostsAdditionalLinesPosition"
|
||||
x:Uid="Hosts_AdditionalLinesPosition"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.AdditionalLinesPosition, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="Hosts_AdditionalLinesPosition_Top" />
|
||||
<ComboBoxItem x:Uid="Hosts_AdditionalLinesPosition_Bottom" />
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="Hosts_Toggle_LoopbackDuplicates" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="HostsToggleLoopbackDuplicates"
|
||||
x:Uid="Hosts_Toggle_LoopbackDuplicates"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.LoopbackDuplicates, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="Hosts_NoLeadingSpaces" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
@@ -73,4 +86,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_Hosts" Link="https://aka.ms/PowerToysOverview_HostsFileEditor" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class HostsPage : Page, IRefreshablePage
|
||||
public sealed partial class HostsPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private HostsViewModel ViewModel { get; }
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.ImageResizerPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="using:Microsoft.PowerToys.Settings.UI.Library"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
@@ -13,7 +14,7 @@
|
||||
x:Name="RootPage"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
<Page.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:ImageResizerFitToStringConverter x:Key="ImageResizerFitToStringConverter" />
|
||||
<converters:ImageResizerFitToIntConverter x:Key="ImageResizerFitToIntConverter" />
|
||||
<converters:ImageResizerUnitToStringConverter x:Key="ImageResizerUnitToStringConverter" />
|
||||
@@ -26,11 +27,12 @@
|
||||
x:Key="BoolToComboBoxIndexConverter"
|
||||
FalseValue="1"
|
||||
TrueValue="0" />
|
||||
</Page.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
<controls:SettingsPageControl x:Uid="ImageResizer" ModuleImageSource="ms-appx:///Assets/Settings/Modules/ImageResizer.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ImageResizerEnableToggle"
|
||||
x:Uid="ImageResizer_EnableToggle"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/ImageResizer.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -49,7 +51,10 @@
|
||||
</InfoBar>
|
||||
|
||||
<controls:SettingsGroup x:Uid="ImageResizer_CustomSizes" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="ImageResizer_Presets" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="ImageResizerPresets"
|
||||
x:Uid="ImageResizer_Presets"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<Button
|
||||
x:Uid="ImageResizer_AddSizeButton"
|
||||
Click="AddSizeButton_Click"
|
||||
@@ -192,7 +197,7 @@
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="Encoding" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="ImageResizer_FallBackEncoderText">
|
||||
<tkcontrols:SettingsCard Name="ImageResizerFallBackEncoderText" x:Uid="ImageResizer_FallBackEncoderText">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind ViewModel.Encoder, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="ImageResizer_FallbackEncoder_PNG" />
|
||||
<ComboBoxItem x:Uid="ImageResizer_FallbackEncoder_BMP" />
|
||||
@@ -203,7 +208,7 @@
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="ImageResizer_Encoding">
|
||||
<tkcontrols:SettingsCard Name="ImageResizerEncoding" x:Uid="ImageResizer_Encoding">
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
Maximum="100"
|
||||
@@ -211,7 +216,7 @@
|
||||
Value="{x:Bind ViewModel.JPEGQualityLevel, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="ImageResizer_PNGInterlacing">
|
||||
<tkcontrols:SettingsCard Name="ImageResizerPNGInterlacing" x:Uid="ImageResizer_PNGInterlacing">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind ViewModel.PngInterlaceOption, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="Default" />
|
||||
<ComboBoxItem x:Uid="On" />
|
||||
@@ -219,7 +224,7 @@
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="ImageResizer_TIFFCompression">
|
||||
<tkcontrols:SettingsCard Name="ImageResizerTIFFCompression" x:Uid="ImageResizer_TIFFCompression">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind ViewModel.TiffCompressOption, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="ImageResizer_ENCODER_TIFF_Default" />
|
||||
<ComboBoxItem x:Uid="ImageResizer_ENCODER_TIFF_None" />
|
||||
@@ -233,7 +238,7 @@
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="File" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="ImageResizer_FilenameFormatHeader">
|
||||
<tkcontrols:SettingsCard Name="ImageResizerFilenameFormatHeader" x:Uid="ImageResizer_FilenameFormatHeader">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<TextBox
|
||||
x:Uid="ImageResizer_FilenameFormatPlaceholder"
|
||||
@@ -280,7 +285,7 @@
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="ImageResizer_FileModifiedDate">
|
||||
<tkcontrols:SettingsCard Name="ImageResizerFileModifiedDate" x:Uid="ImageResizer_FileModifiedDate">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind ViewModel.KeepDateModified, Mode=TwoWay, Converter={StaticResource ReverseBoolToComboBoxIndexConverter}}">
|
||||
<ComboBoxItem x:Uid="ImageResizer_UseOriginalDate" />
|
||||
<ComboBoxItem x:Uid="ImageResizer_UseResizeDate" />
|
||||
@@ -298,4 +303,4 @@
|
||||
<controls:PageLink Link="https://github.com/bricelam/ImageResizer/" Text="Brice Lambson's ImageResizer" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
@@ -14,7 +14,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class ImageResizerPage : Page, IRefreshablePage
|
||||
public sealed partial class ImageResizerPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
public ImageResizerViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.KeyboardManagerPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:Lib="using:Microsoft.PowerToys.Settings.UI.Library"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
|
||||
@@ -12,7 +13,7 @@
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<tkconverters:CollectionVisibilityConverter x:Key="CollectionVisibilityConverter" />
|
||||
<Style x:Name="KeysListViewContainerStyle" TargetType="ListViewItem">
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
@@ -50,12 +51,13 @@
|
||||
Height="56">
|
||||
|
||||
</DataTemplate>-->
|
||||
</Page.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
|
||||
<controls:SettingsPageControl x:Uid="KeyboardManager" ModuleImageSource="ms-appx:///Assets/Settings/Modules/KBM.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="KeyboardManagerEnableToggle"
|
||||
x:Uid="KeyboardManager_EnableToggle"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/KeyboardManager.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -79,6 +81,7 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="KeyboardManager_Keys" IsEnabled="{x:Bind ViewModel.Enabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="KeyboardManagerRemapKeyboardButton"
|
||||
x:Uid="KeyboardManager_RemapKeyboardButton"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Command="{Binding Path=RemapKeyboardCommand}"
|
||||
@@ -132,6 +135,7 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="KeyboardManager_Shortcuts" IsEnabled="{x:Bind ViewModel.Enabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="KeyboardManagerRemapShortcutsButton"
|
||||
x:Uid="KeyboardManager_RemapShortcutsButton"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Command="{Binding Path=EditShortcutCommand}"
|
||||
@@ -231,4 +235,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_KBM" Link="https://aka.ms/PowerToysOverview_KeyboardManager" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class KeyboardManagerPage : Page, IRefreshablePage
|
||||
public sealed partial class KeyboardManagerPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private const string PowerToyName = "Keyboard Manager";
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.MeasureToolPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
@@ -14,6 +15,7 @@
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MeasureToolEnableMeasureTool"
|
||||
x:Uid="MeasureTool_EnableMeasureTool"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/ScreenRuler.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -30,10 +32,13 @@
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
<controls:SettingsGroup x:Uid="MeasureTool_ActivationSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="MeasureTool_ActivationShortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MeasureToolActivationShortcut"
|
||||
x:Uid="MeasureTool_ActivationShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.ActivationShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MeasureTool_DefaultMeasureStyle">
|
||||
<tkcontrols:SettingsCard Name="MeasureToolDefaultMeasureStyle" x:Uid="MeasureTool_DefaultMeasureStyle">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.DefaultMeasureStyle, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="MeasureTool_DefaultMeasureStyle_None" />
|
||||
<ComboBoxItem x:Uid="MeasureTool_DefaultMeasureStyle_Bounds" />
|
||||
@@ -46,7 +51,10 @@
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="MeasureTool_Settings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="MeasureTool_ContinuousCapture" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MeasureToolContinuousCapture"
|
||||
x:Uid="MeasureTool_ContinuousCapture"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch x:Uid="MeasureTool_ContinuousCapture_ToggleSwitch" IsOn="{x:Bind ViewModel.ContinuousCapture, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<InfoBar
|
||||
@@ -56,11 +64,14 @@
|
||||
IsTabStop="{x:Bind ViewModel.ShowContinuousCaptureWarning, Mode=OneWay}"
|
||||
Severity="Warning" />
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MeasureTool_PerColorChannelEdgeDetection" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MeasureToolPerColorChannelEdgeDetection"
|
||||
x:Uid="MeasureTool_PerColorChannelEdgeDetection"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch x:Uid="MeasureTool_PerColorChannelEdgeDetection_ToggleSwitch" IsOn="{x:Bind ViewModel.PerColorChannelEdgeDetection, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MeasureTool_PixelTolerance">
|
||||
<tkcontrols:SettingsCard Name="MeasureToolPixelTolerance" x:Uid="MeasureTool_PixelTolerance">
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
Maximum="255"
|
||||
@@ -68,7 +79,10 @@
|
||||
Value="{x:Bind ViewModel.PixelTolerance, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MeasureTool_UnitsOfMeasure" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MeasureToolUnitsOfMeasure"
|
||||
x:Uid="MeasureTool_UnitsOfMeasure"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.UnitsOfMeasure, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Pixels" />
|
||||
<ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Inches" />
|
||||
@@ -77,11 +91,11 @@
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MeasureTool_DrawFeetOnCross">
|
||||
<tkcontrols:SettingsCard Name="MeasureToolDrawFeetOnCross" x:Uid="MeasureTool_DrawFeetOnCross">
|
||||
<ToggleSwitch x:Uid="MeasureTool_DrawFeetOnCross_ToggleSwitch" IsOn="{x:Bind ViewModel.DrawFeetOnCross, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MeasureTool_MeasureCrossColor">
|
||||
<tkcontrols:SettingsCard Name="MeasureToolMeasureCrossColor" x:Uid="MeasureTool_MeasureCrossColor">
|
||||
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.CrossColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
@@ -94,4 +108,4 @@
|
||||
<controls:PageLink x:Uid="Attribution_Rooler" Link="https://github.com/peteblois/rooler" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class MeasureToolPage : Page, IRefreshablePage
|
||||
public sealed partial class MeasureToolPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private MeasureToolViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.MouseUtilsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:panels="using:Microsoft.PowerToys.Settings.UI.Panels"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
@@ -12,14 +13,19 @@
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
<Page.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:IndexBitFieldToVisibilityConverter x:Key="IndexBitFieldToVisibilityConverter" />
|
||||
</Page.Resources>
|
||||
<tkconverters:BoolToVisibilityConverter
|
||||
x:Key="BoolToInvertedVisibilityConverter"
|
||||
FalseValue="Visible"
|
||||
TrueValue="Collapsed" />
|
||||
</local:NavigablePage.Resources>
|
||||
<controls:SettingsPageControl x:Uid="MouseUtils" ModuleImageSource="ms-appx:///Assets/Settings/Modules/MouseUtils.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<controls:SettingsGroup x:Uid="MouseUtils_FindMyMouse">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseUtilsEnableFindMyMouse"
|
||||
x:Uid="MouseUtils_Enable_FindMyMouse"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/FindMyMouse.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsFindMyMouseEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -36,6 +42,7 @@
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="MouseUtilsFindMyMouseActivationMethod"
|
||||
x:Uid="MouseUtils_FindMyMouse_ActivationMethod"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsFindMyMouseEnabled, Mode=OneWay}"
|
||||
@@ -51,7 +58,10 @@
|
||||
<!-- Visible for both Press Left Control twice and Press Right Control twice activation methods -->
|
||||
<CheckBox x:Uid="MouseUtils_Include_Win_Key" IsChecked="{x:Bind ViewModel.FindMyMouseIncludeWinKey, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_FindMyMouse_ShakingMinimumDistance" Visibility="{x:Bind ViewModel.FindMyMouseActivationMethod, Converter={StaticResource IndexBitFieldToVisibilityConverter}, Mode=OneWay, ConverterParameter=0x4}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseUtilsFindMyMouseShakingMinimumDistance"
|
||||
x:Uid="MouseUtils_FindMyMouse_ShakingMinimumDistance"
|
||||
Visibility="{x:Bind ViewModel.FindMyMouseActivationMethod, Converter={StaticResource IndexBitFieldToVisibilityConverter}, Mode=OneWay, ConverterParameter=0x4}">
|
||||
<!-- Visible for the Shake Mouse activation method -->
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
@@ -62,7 +72,10 @@
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{x:Bind ViewModel.FindMyMouseShakingMinimumDistance, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_FindMyMouse_ShakingIntervalMs" Visibility="{x:Bind ViewModel.FindMyMouseActivationMethod, Converter={StaticResource IndexBitFieldToVisibilityConverter}, Mode=OneWay, ConverterParameter=0x4}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseUtilsFindMyMouseShakingIntervalMs"
|
||||
x:Uid="MouseUtils_FindMyMouse_ShakingIntervalMs"
|
||||
Visibility="{x:Bind ViewModel.FindMyMouseActivationMethod, Converter={StaticResource IndexBitFieldToVisibilityConverter}, Mode=OneWay, ConverterParameter=0x4}">
|
||||
<!-- Visible for the Shake Mouse activation method -->
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
@@ -73,7 +86,10 @@
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{x:Bind ViewModel.FindMyMouseShakingIntervalMs, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_FindMyMouse_ShakingFactor" Visibility="{x:Bind ViewModel.FindMyMouseActivationMethod, Converter={StaticResource IndexBitFieldToVisibilityConverter}, Mode=OneWay, ConverterParameter=0x4}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseUtilsFindMyMouseShakingFactor"
|
||||
x:Uid="MouseUtils_FindMyMouse_ShakingFactor"
|
||||
Visibility="{x:Bind ViewModel.FindMyMouseActivationMethod, Converter={StaticResource IndexBitFieldToVisibilityConverter}, Mode=OneWay, ConverterParameter=0x4}">
|
||||
<!-- Visible for the Shake Mouse activation method -->
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
@@ -85,6 +101,7 @@
|
||||
Value="{x:Bind ViewModel.FindMyMouseShakingFactor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseUtilsFindMyMouseActivationShortcut"
|
||||
x:Uid="MouseUtils_FindMyMouse_ActivationShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
Visibility="{x:Bind ViewModel.FindMyMouseActivationMethod, Converter={StaticResource IndexBitFieldToVisibilityConverter}, Mode=OneWay, ConverterParameter=0x8}">
|
||||
@@ -98,25 +115,26 @@
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="FindMyMouseAppearanceBehavior"
|
||||
x:Uid="Appearance_Behavior"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsFindMyMouseEnabled, Mode=OneWay}"
|
||||
IsExpanded="False">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_FindMyMouse_OverlayOpacity">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsFindMyMouseOverlayOpacity" x:Uid="MouseUtils_FindMyMouse_OverlayOpacity">
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
Maximum="100"
|
||||
Minimum="1"
|
||||
Value="{x:Bind ViewModel.FindMyMouseOverlayOpacity, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_FindMyMouse_BackgroundColor">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsFindMyMouseBackgroundColor" x:Uid="MouseUtils_FindMyMouse_BackgroundColor">
|
||||
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.FindMyMouseBackgroundColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_FindMyMouse_SpotlightColor">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsFindMyMouseSpotlightColor" x:Uid="MouseUtils_FindMyMouse_SpotlightColor">
|
||||
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.FindMyMouseSpotlightColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_FindMyMouse_SpotlightRadius">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsFindMyMouseSpotlightRadius" x:Uid="MouseUtils_FindMyMouse_SpotlightRadius">
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
LargeChange="10"
|
||||
@@ -125,14 +143,14 @@
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{x:Bind ViewModel.FindMyMouseSpotlightRadius, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_FindMyMouse_SpotlightInitialZoom">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsFindMyMouseSpotlightInitialZoom" x:Uid="MouseUtils_FindMyMouse_SpotlightInitialZoom">
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
Maximum="40"
|
||||
Minimum="1"
|
||||
Value="{x:Bind ViewModel.FindMyMouseSpotlightInitialZoom, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_FindMyMouse_AnimationDurationMs">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsFindMyMouseAnimationDurationMs" x:Uid="MouseUtils_FindMyMouse_AnimationDurationMs">
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
IsEnabled="{x:Bind ViewModel.IsAnimationEnabledBySystem, Mode=OneWay}"
|
||||
@@ -155,6 +173,7 @@
|
||||
</InfoBar.ActionButton>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="MouseUtilsFindMyMouseExcludedApps"
|
||||
x:Uid="MouseUtils_FindMyMouse_ExcludedApps"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsFindMyMouseEnabled, Mode=OneWay}">
|
||||
@@ -178,6 +197,7 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="MouseUtils_MouseHighlighter">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseUtilsEnableMouseHighlighter"
|
||||
x:Uid="MouseUtils_Enable_MouseHighlighter"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseHighlighter.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsHighlighterEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -194,6 +214,7 @@
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="MouseUtilsMouseHighlighterActivationShortcut"
|
||||
x:Uid="MouseUtils_MouseHighlighter_ActivationShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsMouseHighlighterEnabled, Mode=OneWay}"
|
||||
@@ -206,6 +227,7 @@
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="MouseHighlighterAppearanceBehavior"
|
||||
x:Uid="Appearance_Behavior"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsMouseHighlighterEnabled, Mode=OneWay}">
|
||||
@@ -216,7 +238,7 @@
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_SecondaryButtonClickColor" IsEnabled="{x:Bind ViewModel.IsSpotlightModeEnabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterRightButtonClickColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_AlwaysColor">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsMouseHighlighterAlwaysColor" x:Uid="MouseUtils_MouseHighlighter_AlwaysColor">
|
||||
<controls:AlphaColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MouseHighlighterAlwaysColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="HighlightMode">
|
||||
@@ -237,7 +259,7 @@
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{x:Bind ViewModel.MouseHighlighterRadius, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_FadeDelayMs">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsMouseHighlighterFadeDelayMs" x:Uid="MouseUtils_MouseHighlighter_FadeDelayMs">
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
LargeChange="100"
|
||||
@@ -246,7 +268,7 @@
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{x:Bind ViewModel.MouseHighlighterFadeDelayMs, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MouseHighlighter_FadeDurationMs">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsMouseHighlighterFadeDurationMs" x:Uid="MouseUtils_MouseHighlighter_FadeDurationMs">
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
LargeChange="100"
|
||||
@@ -263,6 +285,7 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="MouseUtils_MousePointerCrosshairs">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseUtilsEnableMousePointerCrosshairs"
|
||||
x:Uid="MouseUtils_Enable_MousePointerCrosshairs"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseCrosshairs.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsMousePointerCrosshairsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -279,6 +302,7 @@
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="MouseUtilsMousePointerCrosshairsActivationShortcut"
|
||||
x:Uid="MouseUtils_MousePointerCrosshairs_ActivationShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsMousePointerCrosshairsEnabled, Mode=OneWay}"
|
||||
@@ -292,14 +316,15 @@
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="MousePointerCrosshairsAppearanceBehavior"
|
||||
x:Uid="Appearance_Behavior"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsMousePointerCrosshairsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsColor">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsMousePointerCrosshairsCrosshairsColor" x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsColor">
|
||||
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MousePointerCrosshairsColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsOpacity">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsMousePointerCrosshairsCrosshairsOpacity" x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsOpacity">
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
Maximum="100"
|
||||
@@ -307,7 +332,7 @@
|
||||
Value="{x:Bind ViewModel.MousePointerCrosshairsOpacity, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsRadius">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsMousePointerCrosshairsCrosshairsRadius" x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsRadius">
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
LargeChange="10"
|
||||
@@ -318,7 +343,7 @@
|
||||
Value="{x:Bind ViewModel.MousePointerCrosshairsRadius, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsThickness">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsMousePointerCrosshairsCrosshairsThickness" x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsThickness">
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
LargeChange="10"
|
||||
@@ -329,11 +354,11 @@
|
||||
Value="{x:Bind ViewModel.MousePointerCrosshairsThickness, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsBorderColor">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsMousePointerCrosshairsCrosshairsBorderColor" x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsBorderColor">
|
||||
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.MousePointerCrosshairsBorderColor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsBorderSize">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsMousePointerCrosshairsCrosshairsBorderSize" x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsBorderSize">
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
LargeChange="2"
|
||||
@@ -348,11 +373,14 @@
|
||||
<CheckBox x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsAutoHide" IsChecked="{x:Bind ViewModel.MousePointerCrosshairsAutoHide, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MousePointerCrosshairs_IsCrosshairsFixedLengthEnabled">
|
||||
<tkcontrols:SettingsCard Name="MouseUtilsMousePointerCrosshairsIsCrosshairsFixedLengthEnabled" x:Uid="MouseUtils_MousePointerCrosshairs_IsCrosshairsFixedLengthEnabled">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.MousePointerCrosshairsIsFixedLengthEnabled, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsFixedLength" IsEnabled="{x:Bind ViewModel.MousePointerCrosshairsIsFixedLengthEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseUtilsMousePointerCrosshairsCrosshairsFixedLength"
|
||||
x:Uid="MouseUtils_MousePointerCrosshairs_CrosshairsFixedLength"
|
||||
IsEnabled="{x:Bind ViewModel.MousePointerCrosshairsIsFixedLengthEnabled, Mode=OneWay}">
|
||||
<NumberBox
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
LargeChange="10"
|
||||
@@ -395,4 +423,4 @@
|
||||
<controls:PageLink Link="https://michael-clayton.com/projects/fancymouse" Text="Michael Clayton's Mouse Jump (FancyMouse)" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -12,7 +12,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class MouseUtilsPage : Page, IRefreshablePage
|
||||
public sealed partial class MouseUtilsPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private MouseUtilsViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
<Page
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.MouseWithoutBordersPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
<Page.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:BoolToVisibilityConverter x:Key="negativeBoolToVisibilityConverter" />
|
||||
<converters:BoolToObjectConverter
|
||||
x:Key="OneRowMatrixBoolToNumberOfRowsConverter"
|
||||
FalseValue="2"
|
||||
TrueValue="4" />
|
||||
</Page.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
<controls:SettingsPageControl x:Uid="MouseWithoutBorders" ModuleImageSource="ms-appx:///Assets/Settings/Modules/MouseWithoutBorders.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<controls:SettingsGroup x:Uid="MouseWithoutBorders_ActivationSettings">
|
||||
<controls:SettingsGroup x:Name="ActivationSettingsGroup" x:Uid="MouseWithoutBorders_ActivationSettings">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersToggleEnable"
|
||||
x:Uid="MouseWithoutBorders_Toggle_Enable"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseWithoutBorders.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -40,9 +43,12 @@
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
</controls:SettingsGroup>
|
||||
<controls:SettingsGroup x:Uid="MouseWithoutBorders_KeySettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<controls:SettingsGroup
|
||||
x:Name="KeySettingsGroup"
|
||||
x:Uid="MouseWithoutBorders_KeySettings"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander
|
||||
x:Name="MouseWithoutBorders_ConnectSettings"
|
||||
Name="MouseWithoutBordersSecurityKey"
|
||||
x:Uid="MouseWithoutBorders_SecurityKey"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="{x:Bind ViewModel.ConnectFieldsVisible, Mode=TwoWay}">
|
||||
@@ -78,7 +84,7 @@
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_ThisMachineNameLabel">
|
||||
<tkcontrols:SettingsCard Name="MouseWithoutBordersThisMachineNameLabel" x:Uid="MouseWithoutBorders_ThisMachineNameLabel">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
@@ -99,7 +105,10 @@
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
<controls:SettingsGroup x:Uid="MouseWithoutBorders_DeviceLayoutSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<controls:SettingsGroup
|
||||
x:Name="DeviceLayoutSettingsGroup"
|
||||
x:Uid="MouseWithoutBorders_DeviceLayoutSettings"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
||||
@@ -180,12 +189,18 @@
|
||||
|
||||
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_MatrixOneRow">
|
||||
<tkcontrols:SettingsCard Name="MouseWithoutBordersMatrixOneRow" x:Uid="MouseWithoutBorders_MatrixOneRow">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_MatrixOneRow_ToggleSwitch" IsOn="{x:Bind ViewModel.MatrixOneRow, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
<controls:SettingsGroup x:Uid="MouseWithoutBorders_ServiceSettings" IsEnabled="{x:Bind ViewModel.CanToggleUseService, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_UseService" IsEnabled="{x:Bind ViewModel.UseServiceSettingIsEnabled, Mode=OneWay}">
|
||||
<controls:SettingsGroup
|
||||
x:Name="ServiceSettingsGroup"
|
||||
x:Uid="MouseWithoutBorders_ServiceSettings"
|
||||
IsEnabled="{x:Bind ViewModel.CanToggleUseService, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersUseService"
|
||||
x:Uid="MouseWithoutBorders_UseService"
|
||||
IsEnabled="{x:Bind ViewModel.UseServiceSettingIsEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_UseService_ToggleSwitch" IsOn="{x:Bind ViewModel.UseService, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<InfoBar
|
||||
@@ -211,13 +226,17 @@
|
||||
IsTabStop="{x:Bind ViewModel.IsEnabled, Mode=OneWay}"
|
||||
Severity="Warning" />
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersUninstallService"
|
||||
x:Uid="MouseWithoutBorders_UninstallService"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Command="{x:Bind ViewModel.UninstallServiceEventHandler}"
|
||||
IsClickEnabled="{x:Bind ViewModel.CanUninstallService, Mode=OneWay}"
|
||||
IsEnabled="{x:Bind ViewModel.CanUninstallService, Mode=OneWay}" />
|
||||
</controls:SettingsGroup>
|
||||
<controls:SettingsGroup x:Uid="MouseWithoutBorders_Settings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<controls:SettingsGroup
|
||||
x:Name="BehaviorSettingsGroup"
|
||||
x:Uid="MouseWithoutBorders_Settings"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<InfoBar
|
||||
x:Uid="GPO_SomeSettingsAreManaged"
|
||||
IsClosable="False"
|
||||
@@ -228,46 +247,58 @@
|
||||
<FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_WrapMouse">
|
||||
<tkcontrols:SettingsCard Name="MouseWithoutBordersWrapMouse" x:Uid="MouseWithoutBorders_WrapMouse">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_WrapMouse_ToggleSwitch" IsOn="{x:Bind ViewModel.WrapMouse, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="MouseWithoutBordersShareClipboard"
|
||||
x:Uid="MouseWithoutBorders_ShareClipboard"
|
||||
IsEnabled="{x:Bind ViewModel.CardForShareClipboardSettingIsEnabled, Mode=OneWay}"
|
||||
IsExpanded="True">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_ShareClipboard_ToggleSwitch" IsOn="{x:Bind ViewModel.ShareClipboard, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_TransferFile" IsEnabled="{x:Bind ViewModel.CardForTransferFileSettingIsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersTransferFile"
|
||||
x:Uid="MouseWithoutBorders_TransferFile"
|
||||
IsEnabled="{x:Bind ViewModel.CardForTransferFileSettingIsEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_TransferFile_ToggleSwitch" IsOn="{x:Bind ViewModel.TransferFile, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_HideMouseAtScreenEdge">
|
||||
<tkcontrols:SettingsCard Name="MouseWithoutBordersHideMouseAtScreenEdge" x:Uid="MouseWithoutBorders_HideMouseAtScreenEdge">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_HideMouseAtScreenEdge_ToggleSwitch" IsOn="{x:Bind ViewModel.HideMouseAtScreenEdge, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_DrawMouseCursor">
|
||||
<tkcontrols:SettingsCard Name="MouseWithoutBordersDrawMouseCursor" x:Uid="MouseWithoutBorders_DrawMouseCursor">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_DrawMouseCursor_ToggleSwitch" IsOn="{x:Bind ViewModel.DrawMouseCursor, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_ValidateRemoteMachineIP" IsEnabled="{x:Bind ViewModel.CardForValidateRemoteIpSettingIsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersValidateRemoteMachineIP"
|
||||
x:Uid="MouseWithoutBorders_ValidateRemoteMachineIP"
|
||||
IsEnabled="{x:Bind ViewModel.CardForValidateRemoteIpSettingIsEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_ValidateRemoteMachineIP_ToggleSwitch" IsOn="{x:Bind ViewModel.ValidateRemoteMachineIP, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_SameSubnetOnly" IsEnabled="{x:Bind ViewModel.CardForSameSubnetOnlySettingIsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersSameSubnetOnly"
|
||||
x:Uid="MouseWithoutBorders_SameSubnetOnly"
|
||||
IsEnabled="{x:Bind ViewModel.CardForSameSubnetOnlySettingIsEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_SameSubnetOnly_ToggleSwitch" IsOn="{x:Bind ViewModel.SameSubnetOnly, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_BlockScreenSaverOnOtherMachines" IsEnabled="{x:Bind ViewModel.CardForBlockScreensaverSettingIsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersBlockScreenSaverOnOtherMachines"
|
||||
x:Uid="MouseWithoutBorders_BlockScreenSaverOnOtherMachines"
|
||||
IsEnabled="{x:Bind ViewModel.CardForBlockScreensaverSettingIsEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_BlockScreenSaverOnOtherMachines_ToggleSwitch" IsOn="{x:Bind ViewModel.BlockScreenSaverOnOtherMachines, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_MoveMouseRelatively">
|
||||
<tkcontrols:SettingsCard Name="MouseWithoutBordersMoveMouseRelatively" x:Uid="MouseWithoutBorders_MoveMouseRelatively">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_MoveMouseRelatively_ToggleSwitch" IsOn="{x:Bind ViewModel.MoveMouseRelatively, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_BlockMouseAtScreenCorners">
|
||||
<tkcontrols:SettingsCard Name="MouseWithoutBordersBlockMouseAtScreenCorners" x:Uid="MouseWithoutBorders_BlockMouseAtScreenCorners">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_BlockMouseAtScreenCorners_ToggleSwitch" IsOn="{x:Bind ViewModel.BlockMouseAtScreenCorners, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_ShowClipboardAndNetworkStatusMessages">
|
||||
<tkcontrols:SettingsCard Name="MouseWithoutBordersShowClipboardAndNetworkStatusMessages" x:Uid="MouseWithoutBorders_ShowClipboardAndNetworkStatusMessages">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_ShowClipboardAndNetworkStatusMessages_ToggleSwitch" IsOn="{x:Bind ViewModel.ShowClipboardAndNetworkStatusMessages, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="MouseWithoutBorders_EasyMouseSettings_Group" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_EasyMouseOption" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.EasyMouseOptionIndex, Mode=TwoWay}">
|
||||
@@ -278,12 +309,12 @@
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersDisableEasyMouseWhenForegroundWindowIsFullscreen"
|
||||
x:Uid="MouseWithoutBorders_DisableEasyMouseWhenForegroundWindowIsFullscreen"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.EasyMouseEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_DisableEasyMouseWhenForegroundWindowIsFullscreen_ToggleSwitch" IsOn="{x:Bind ViewModel.DisableEasyMouseWhenForegroundWindowIsFullscreen, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<InfoBar
|
||||
x:Uid="MouseWithoutBorders_CanOnlyStopEasyMouseIfMovingFromHostMachine"
|
||||
IsClosable="False"
|
||||
@@ -291,12 +322,14 @@
|
||||
Severity="Informational" />
|
||||
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="MouseWithoutBordersDisableEasyMouseWhenForegroundWindowIsFullscreen_Expander"
|
||||
x:Uid="MouseWithoutBorders_DisableEasyMouseWhenForegroundWindowIsFullscreen_Expander"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEasyMouseBlockingOnFullscreenEnabled, Mode=OneWay}"
|
||||
IsExpanded="False">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersDisableEasyMouseWhenForegroundWindowIsFullscreenExcludedApps"
|
||||
x:Uid="MouseWithoutBorders_DisableEasyMouseWhenForegroundWindowIsFullscreen_ExcludedApps"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ContentAlignment="Vertical">
|
||||
@@ -316,36 +349,54 @@
|
||||
</tkcontrols:SettingsExpander>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="MouseWithoutBorders_KeyboardShortcuts_Group" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_ToggleEasyMouseShortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:SettingsGroup
|
||||
Name="MouseWithoutBordersKeyboardShortcutsGroup"
|
||||
x:Uid="MouseWithoutBorders_KeyboardShortcuts_Group"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersToggleEasyMouseShortcut"
|
||||
x:Uid="MouseWithoutBorders_ToggleEasyMouseShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
AllowDisable="True"
|
||||
HotkeySettings="{x:Bind Path=ViewModel.ToggleEasyMouseShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_LockMachinesShortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersLockMachinesShortcut"
|
||||
x:Uid="MouseWithoutBorders_LockMachinesShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
AllowDisable="True"
|
||||
HotkeySettings="{x:Bind Path=ViewModel.LockMachinesShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_Switch2AllPcShortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersSwitch2AllPcShortcut"
|
||||
x:Uid="MouseWithoutBorders_Switch2AllPcShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
AllowDisable="True"
|
||||
HotkeySettings="{x:Bind Path=ViewModel.HotKeySwitch2AllPC, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_ReconnectShortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersReconnectShortcut"
|
||||
x:Uid="MouseWithoutBorders_ReconnectShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
AllowDisable="True"
|
||||
HotkeySettings="{x:Bind Path=ViewModel.ReconnectShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_SwitchBetweenMachineShortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersSwitchBetweenMachineShortcut"
|
||||
x:Uid="MouseWithoutBorders_SwitchBetweenMachineShortcut"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.SelectedSwitchBetweenMachineShortcutOptionsIndex, Mode=TwoWay}">
|
||||
<!-- These should be in the same order as the array items in MouseWithoutBordersViewModel.cs -->
|
||||
<ComboBoxItem x:Uid="MouseWithoutBorders_SwitchBetweenMachineShortcut_F1" />
|
||||
@@ -354,8 +405,14 @@
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
<controls:SettingsGroup x:Uid="MouseWithoutBorders_AdvancedSettings_Group" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander x:Uid="MouseWithoutBorders_IPAddressMapping" IsExpanded="True">
|
||||
<controls:SettingsGroup
|
||||
x:Name="AdvancedSettingsGroup"
|
||||
x:Uid="MouseWithoutBorders_AdvancedSettings_Group"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander
|
||||
Name="MouseWithoutBordersIPAddressMapping"
|
||||
x:Uid="MouseWithoutBorders_IPAddressMapping"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard
|
||||
HorizontalContentAlignment="Stretch"
|
||||
@@ -430,13 +487,20 @@
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
</controls:SettingsGroup>
|
||||
<controls:SettingsGroup x:Uid="MouseWithoutBorders_TroubleShooting" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<controls:SettingsGroup
|
||||
x:Name="TroubleshootingGroup"
|
||||
x:Uid="MouseWithoutBorders_TroubleShooting"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersAddFirewallRuleButtonControl"
|
||||
x:Uid="MouseWithoutBorders_AddFirewallRuleButtonControl"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Command="{x:Bind ViewModel.AddFirewallRuleEventHandler}"
|
||||
IsClickEnabled="True" />
|
||||
<tkcontrols:SettingsCard x:Uid="MouseWithoutBorders_ShowOriginalUI" IsEnabled="{x:Bind ViewModel.CardForOriginalUiSettingIsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="MouseWithoutBordersShowOriginalUI"
|
||||
x:Uid="MouseWithoutBorders_ShowOriginalUI"
|
||||
IsEnabled="{x:Bind ViewModel.CardForOriginalUiSettingIsEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="MouseWithoutBorders_ShowOriginalUI_ToggleSwitch" IsOn="{x:Bind ViewModel.ShowOriginalUI, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<InfoBar
|
||||
@@ -460,4 +524,4 @@
|
||||
<controls:PageLink Link="https://github.com/microsoft/PowerToys/blob/main/COMMUNITY.md#mouse-without-borders-original-contributors" Text="Truong Do (Đỗ Đức Trường) and other original contributors" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</Page>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -6,7 +6,6 @@ using System;
|
||||
using System.IO.Abstractions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
@@ -14,6 +13,7 @@ using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using WinRT;
|
||||
|
||||
@@ -21,7 +21,7 @@ using static Microsoft.PowerToys.Settings.UI.ViewModels.MouseWithoutBordersViewM
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class MouseWithoutBordersPage : Page, IRefreshablePage
|
||||
public sealed partial class MouseWithoutBordersPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private const string MouseWithoutBordersDragDropCheckString = "MWB Device Drag Drop";
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Page
|
||||
<helper:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.NewPlusPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:helper="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:local="clr-namespace:Microsoft.PowerToys.Settings.UI.ViewModels"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
@@ -18,6 +19,7 @@
|
||||
Orientation="Vertical"
|
||||
Spacing="2">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="NewPlusEnableToggle"
|
||||
x:Uid="NewPlus_Enable_Toggle"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/NewPlus.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
@@ -36,6 +38,7 @@
|
||||
|
||||
<controls:SettingsGroup x:Uid="NewPlus_Templates" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="NewPlusTemplatesLocation"
|
||||
x:Uid="NewPlus_Templates_Location"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Command="{x:Bind ViewModel.OpenCurrentNewTemplateFolder}"
|
||||
@@ -65,7 +68,10 @@
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="NewPlus_Display_Options" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="NewPlus_Hide_File_Extension_Toggle" IsEnabled="{x:Bind ViewModel.IsHideFileExtSettingsCardEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="NewPlusHideFileExtensionToggle"
|
||||
x:Uid="NewPlus_Hide_File_Extension_Toggle"
|
||||
IsEnabled="{x:Bind ViewModel.IsHideFileExtSettingsCardEnabled, Mode=OneWay}">
|
||||
<ToggleSwitch x:Uid="HideFileExtensionToggle" IsOn="{x:Bind ViewModel.HideFileExtension, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<InfoBar
|
||||
@@ -78,7 +84,7 @@
|
||||
<FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="" />
|
||||
</InfoBar.IconSource>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsCard x:Uid="NewPlus_Hide_Starting_Digits_Toggle">
|
||||
<tkcontrols:SettingsCard Name="NewPlusHideStartingDigitsToggle" x:Uid="NewPlus_Hide_Starting_Digits_Toggle">
|
||||
<ToggleSwitch x:Uid="HideStartingDigitsToggle" IsOn="{x:Bind ViewModel.HideStartingDigits, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsCard.Description>
|
||||
<TextBlock x:Uid="NewPlus_Hide_Starting_Digits_Description" />
|
||||
@@ -87,7 +93,10 @@
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="NewPlus_behavior" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="NewPlus_Behaviour_Replace_Variables_Toggle" IsEnabled="{x:Bind ViewModel.IsReplaceVariablesSettingsCardEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
Name="NewPlusBehaviourReplaceVariablesToggle"
|
||||
x:Uid="NewPlus_Behaviour_Replace_Variables_Toggle"
|
||||
IsEnabled="{x:Bind ViewModel.IsReplaceVariablesSettingsCardEnabled, Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<ToggleSwitch x:Uid="ReplaceVariablesToggle" IsOn="{x:Bind ViewModel.ReplaceVariables, Mode=TwoWay}" />
|
||||
<Button
|
||||
@@ -206,4 +215,4 @@
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
|
||||
</Page>
|
||||
</helper:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class NewPlusPage : Page, IRefreshablePage
|
||||
public sealed partial class NewPlusPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private NewPlusViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user