diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index d4a0a391bb..9b08f419a3 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -388,7 +388,9 @@ DEFAULTFLAGS DEFAULTICON defaultlib DEFAULTONLY +DEFAULTSIZE DEFAULTTONEAREST +Defaulttonearest DEFAULTTONULL DEFAULTTOPRIMARY DEFERERASE @@ -884,9 +886,11 @@ IUI IVO IUWP IWIC +jeli jfif jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi jjw +JOBOBJECT jobject jpe jpnime @@ -922,6 +926,7 @@ lastcodeanalysissucceeded LASTEXITCODE LAYOUTRTL lbl +Lbuttondown LCh lcid LCIDTo @@ -1047,6 +1052,7 @@ maxversiontested mber MBM MBR +Mbuttondown MDICHILD MDL mdtext @@ -1522,6 +1528,7 @@ RAWINPUTHEADER RAWMODE RAWPATH rbhid +Rbuttondown rclsid RCZOOMIT rdp @@ -1558,6 +1565,7 @@ remoteip Removelnk renamable RENAMEONCOLLISION +RENDERFULLCONTENT Reparent reparented reparenting @@ -1827,6 +1835,8 @@ SVGIO svgz SVSI SWFO +SWP +Swp swp SWPNOSIZE SWPNOZORDER @@ -1895,7 +1905,6 @@ TILEDWINDOW TILLSON timedate timediff -timeunion timeutil TITLEBARINFO Titlecase @@ -2185,6 +2194,7 @@ Wwanpp xap XAxis XButton +Xbuttondown xclip xcopy XDeployment diff --git a/.github/actions/spell-check/patterns.txt b/.github/actions/spell-check/patterns.txt index 8c59d38c47..34b2ad9fe9 100644 --- a/.github/actions/spell-check/patterns.txt +++ b/.github/actions/spell-check/patterns.txt @@ -286,3 +286,6 @@ St&yle # 2D Region struct names \bDisplayConfig2?D?Region\b + +# Microsoft Store URLs and product IDs +ms-windows-store://\S+ diff --git a/.pipelines/ESRPSigning_core.json b/.pipelines/ESRPSigning_core.json index b0c2766e84..dfb259fd8f 100644 --- a/.pipelines/ESRPSigning_core.json +++ b/.pipelines/ESRPSigning_core.json @@ -117,6 +117,7 @@ "WinUI3Apps\\PowerToys.FileLocksmithUI.dll", "WinUI3Apps\\PowerToys.FileLocksmithContextMenu.dll", "FileLocksmithContextMenuPackage.msix", + "FileLocksmithCLI.exe", "WinUI3Apps\\Peek.Common.dll", "WinUI3Apps\\Peek.FilePreviewer.dll", diff --git a/.pipelines/v2/templates/job-build-ui-tests.yml b/.pipelines/v2/templates/job-build-ui-tests.yml index 342750d51c..346248b80a 100644 --- a/.pipelines/v2/templates/job-build-ui-tests.yml +++ b/.pipelines/v2/templates/job-build-ui-tests.yml @@ -68,14 +68,13 @@ jobs: - template: .\steps-restore-nuget.yml - - task: NuGetCommand@2 + - task: MSBuild@1 displayName: Restore solution-level NuGet packages inputs: - command: restore - feedsToUse: config - configPath: nuget.config - restoreSolution: PowerToys.slnx - restoreDirectory: '$(Build.SourcesDirectory)\packages' + solution: PowerToys.slnx + msbuildArguments: '/t:restore /p:RestorePackagesConfig=true' + platform: $(BuildPlatform) + configuration: $(BuildConfiguration) # Build all UI test projects if no specific modules are specified - ${{ if eq(length(parameters.uiTestModules), 0) }}: diff --git a/COMMUNITY.md b/COMMUNITY.md index c18bacc8c9..dbbc413f68 100644 --- a/COMMUNITY.md +++ b/COMMUNITY.md @@ -6,9 +6,6 @@ Names are in alphabetical order based on first name. ## High impact community members -### [@Noraa-Junker](https://github.com/Noraa-Junker) - [Noraa Junker](https://noraajunker.ch) -Noraa has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes. Noraa was the primary person for helping build the File Explorer preview pane handler for developer files. - ### [@cgaarden](https://github.com/cgaarden) - [Christian Gaarden Gaardmark](https://www.onegreatworld.com) Christian contributed New+ utility @@ -42,6 +39,12 @@ Jay has helped triaging, discussing, creating a substantial number of issues and ### [@jefflord](https://github.com/Jjefflord) - Jeff Lord Jeff added in multiple new features into Keyboard manager, such as key chord support and launching apps. He also contributed multiple features/fixes to PowerToys. +### [@snickler](https://github.com/snickler) - [Jeremy Sinclair](http://sinclairinat0r.com) +Jeremy has helped drive large sums of the ARM64 support inside PowerToys + +### [@jiripolasek](https://github.com/jiripolasek) - [Jiří Polášek](https://github.com/jiripolasek) +Jiří has contributed a massive number of features and improvements to Command Palette, including drag & drop support, custom themes, Web Search enhancements, Remote Desktop extension fixes, and many UX improvements. + ### [@TheJoeFin](https://github.com/TheJoeFin) - [Joe Finney](https://joefinapps.com) Joe has helped triaging, discussing, issues as well as fixing bugs and building features for Text Extractor. @@ -57,6 +60,9 @@ Color Picker is from Martin. ### [@mikeclayton](https://github.com/mikeclayton) - [Michael Clayton](https://michael-clayton.com) Michael contributed the [initial version](https://github.com/microsoft/PowerToys/issues/23216) of the Mouse Jump tool and [a number of updates](https://github.com/microsoft/PowerToys/pulls?q=is%3Apr+author%3Amikeclayton) based on his FancyMouse utility. +### [@Noraa-Junker](https://github.com/Noraa-Junker) - [Noraa Junker](https://noraajunker.ch) +Noraa has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes. Noraa was the primary person for helping build the File Explorer preview pane handler for developer files. + ### [@pedrolamas](https://github.com/pedrolamas/) - Pedro Lamas Pedro helped create the thumbnail and File Explorer previewers for 3D files like STL and GCode. If you like 3D printing, these are very helpful. @@ -69,15 +75,12 @@ Rafael has helped do the [upgrade from CppWinRT 1.x to 2.0](https://github.com/m ### [@royvou](https://github.com/royvou) Roy has helped out contributing multiple features to PowerToys Run -### [@snickler](https://github.com/snickler) - [Jeremy Sinclair](http://sinclairinat0r.com) -Jeremy has helped drive large sums of the ARM64 support inside PowerToys +### [@ThiefZero](https://github.com/ThiefZero) +ThiefZero has helped out contributing a features to PowerToys Run such as the unit converter plugin ### [@TobiasSekan](https://github.com/TobiasSekan) - Tobias Sekan Tobias Sekan has helped out contributing features to PowerToys Run such as Settings plugin, Registry plugin -### [@ThiefZero](https://github.com/ThiefZero) -ThiefZero has helped out contributing a features to PowerToys Run such as the unit converter plugin - ## Open source projects As PowerToys creates new utilities, some will be based off existing technology. We'll continue to do our best to contribute back to these projects but their efforts were the base of some of our projects. We want to be sure their work is directly recognized. @@ -187,18 +190,10 @@ ZoomIt source code was originally implemented by [Sysinternals](https://sysinter - [@niels9001](https://github.com/niels9001/) - Niels Laute - Product Manager - [@dhowett](https://github.com/dhowett) - Dustin Howett - Dev Lead - [@yeelam-gordon](https://github.com/yeelam-gordon) - Gordon Lam - Dev Lead -- [@jamrobot](https://github.com/jamrobot) - Jerry Xu - Dev Lead - [@lei9444](https://github.com/lei9444) - Leilei Zhang - Dev - [@shuaiyuanxx](https://github.com/shuaiyuanxx) - Shawn Yuan - Dev - [@moooyo](https://github.com/moooyo) - Yu Leng - Dev - [@haoliuu](https://github.com/haoliuu) - Hao Liu - Dev -- [@chenmy77](https://github.com/chenmy77) - Mengyuan Chen - Dev -- [@chemwolf6922](https://github.com/chemwolf6922) - Feng Wang - Dev -- [@yaqingmi](https://github.com/yaqingmi) - Yaqing Mi - Dev -- [@zhaoqpcn](https://github.com/zhaoqpcn) - Qingpeng Zhao - Dev -- [@urnotdfs](https://github.com/urnotdfs) - Xiaofeng Wang - Dev -- [@zhaopy536](https://github.com/zhaopy536) - Peiyao Zhao - Dev -- [@wang563681252](https://github.com/wang563681252) - Zhaopeng Wang - Dev - [@vanzue](https://github.com/vanzue) - Kai Tao - Dev - [@zadjii-msft](https://github.com/zadjii-msft) - Mike Griese - Dev - [@khmyznikov](https://github.com/khmyznikov) - Gleb Khmyznikov - Dev @@ -229,3 +224,12 @@ ZoomIt source code was originally implemented by [Sysinternals](https://sysinter - [@SeraphimaZykova](https://github.com/SeraphimaZykova) - Seraphima Zykova - Dev - [@stefansjfw](https://github.com/stefansjfw) - Stefan Markovic - Dev - [@jaimecbernardo](https://github.com/jaimecbernardo) - Jaime Bernardo - Dev Lead +- [@haoliuu](https://github.com/haoliuu) - Hao Liu - Dev +- [@chenmy77](https://github.com/chenmy77) - Mengyuan Chen - Dev +- [@chemwolf6922](https://github.com/chemwolf6922) - Feng Wang - Dev +- [@yaqingmi](https://github.com/yaqingmi) - Yaqing Mi - Dev +- [@zhaoqpcn](https://github.com/zhaoqpcn) - Qingpeng Zhao - Dev +- [@urnotdfs](https://github.com/urnotdfs) - Xiaofeng Wang - Dev +- [@zhaopy536](https://github.com/zhaopy536) - Peiyao Zhao - Dev +- [@wang563681252](https://github.com/wang563681252) - Zhaopeng Wang - Dev +- [@jamrobot](https://github.com/jamrobot) - Jerry Xu - Dev Lead diff --git a/DATA_AND_PRIVACY.md b/DATA_AND_PRIVACY.md index 66a0daa1d8..07089e44c3 100644 --- a/DATA_AND_PRIVACY.md +++ b/DATA_AND_PRIVACY.md @@ -694,6 +694,30 @@ _If you want to find diagnostic data events in the source code, these two links +### Light Switch + + + + + + + + + + + + + + + + + + + + + +
Event NameDescription
Microsoft.PowerToys.LightSwitch_EnableLightSwitchTriggered when Light Switch is enabled or disabled.
Microsoft.PowerToys.LightSwitch_ShortcutInvokedOccurs when the shortcut for Light Switch is invoked.
Microsoft.PowerToys.LightSwitch_ScheduleModeToggledOccurs when a new schedule mode is selected for Light Switch.
Microsoft.PowerToys.LightSwitch_ThemeTargetChangedOccurs when the options for targeting the system or apps is updated.
+ ### Mouse Highlighter diff --git a/PowerToys.slnx b/PowerToys.slnx index 0b3480b34a..565a5c1e4a 100644 --- a/PowerToys.slnx +++ b/PowerToys.slnx @@ -420,6 +420,7 @@ + @@ -429,6 +430,9 @@ + + + @@ -1018,6 +1022,14 @@ + + + + + + + + diff --git a/doc/devdocs/guidance.md b/doc/devdocs/guidance.md index 6a5050d89d..c4500f5543 100644 --- a/doc/devdocs/guidance.md +++ b/doc/devdocs/guidance.md @@ -58,8 +58,8 @@ string validUIDisplayString = Resources.ValidUIDisplayString; ## More On Coding Guidance Please review these brief docs below relating to our coding standards, etc. -* [Coding Style](./style.md) -* [Code Organization](./readme.md) +* [Coding Style](development/style.md) +* [Code Organization](readme.md) [VS Resource Editor]: https://learn.microsoft.com/cpp/windows/resource-editors?view=vs-2019 diff --git a/doc/devdocs/modules/cropandlock.md b/doc/devdocs/modules/cropandlock.md index 91f020e3e6..db5e9402cf 100644 --- a/doc/devdocs/modules/cropandlock.md +++ b/doc/devdocs/modules/cropandlock.md @@ -20,6 +20,9 @@ Creates a window showing the selected area of the original window. Changes in th ### Reparent Mode Creates a window that replaces the original window, showing only the selected area. The application is controlled through the cropped window. +### Screenshot Mode +Creates a window showing a freezed snapshot of the original window. + ## Code Structure ### Project Layout @@ -30,6 +33,7 @@ The Crop and Lock module is part of the PowerToys solution. All the logic-relate - **OverlayWindow.cpp**: Thumbnail module type's window concrete implementation. - **ReparentCropAndLockWindow.cpp**: Defines the UI for the reparent mode. - **ChildWindow.cpp**: Reparent module type's window concrete implementation. +- **ScreenshotCropAndLockWindow.cpp**: Defines the UI for the screenshot mode. ## Known Issues diff --git a/doc/devdocs/readme.md b/doc/devdocs/readme.md index 38df894d1a..a6ac800be9 100644 --- a/doc/devdocs/readme.md +++ b/doc/devdocs/readme.md @@ -57,7 +57,7 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and an ## Rules - **Follow the pattern of what you already see in the code.** -- [Coding style](style.md). +- [Coding style](development/style.md). - Try to package new functionality/components into libraries that have nicely defined interfaces. - Package new functionality into classes or refactor existing functionality into a class as you extend the code. - When adding new classes/methods/changing existing code, add new unit tests or update the existing tests. diff --git a/doc/thirdPartyRunPlugins.md b/doc/thirdPartyRunPlugins.md index 9cfdc505ff..80e1c16cc1 100644 --- a/doc/thirdPartyRunPlugins.md +++ b/doc/thirdPartyRunPlugins.md @@ -50,6 +50,8 @@ Contact the developers of a plugin directly for assistance with a specific plugi | [Hotkeys](https://github.com/ruslanlap/PowerToysRun-Hotkeys) | [ruslanlap](https://github.com/ruslanlap) | Create, manage, and trigger custom keyboard shortcuts directly from PowerToys Run. | | [RandomGen](https://github.com/ruslanlap/PowerToysRun-RandomGen) | [ruslanlap](https://github.com/ruslanlap) | 🎲 Generate random data instantly with a single keystroke. Perfect for developers, testers, designers, and anyone who needs quick access to random data. Features include secure passwords, PINs, names, business data, dates, numbers, GUIDs, color codes, and more. Especially useful for designers who need random color codes and placeholder content. | | [Open With Cursor](https://github.com/VictorNoxx/PowerToys-Run-Cursor/) | [VictorNoxx](https://github.com/VictorNoxx) | Open Visual Studio, VS Code recents with Cursor AI | +| [Open With Antigravity](https://github.com/artickc/PowerToys-Run-Antygravity) | [artickc](https://github.com/artickc) | Open Visual Studio, VS Code recents with Antigravity AI | +| [Project Launcher Plugin](https://github.com/artickc/ProjectLauncherPowerToysPlugin) | [artickc](https://github.com/artickc) | Access your projects using Project Launcher and PowerToys Run | | [CheatSheets](https://github.com/ruslanlap/PowerToysRun-CheatSheets) | [ruslanlap](https://github.com/ruslanlap) | 📚 Find cheat sheets and command examples instantly from tldr pages, cheat.sh, and devhints.io. Features include favorites system, categories, offline mode, and smart caching. | | [QuickAI](https://github.com/ruslanlap/PowerToysRun-QuickAi) | [ruslanlap](https://github.com/ruslanlap) | AI-powered assistance with instant, smart responses from multiple providers (Groq, Together, Fireworks, OpenRouter, Cohere) | diff --git a/src/common/ManagedCommon/ModuleType.cs b/src/common/ManagedCommon/ModuleType.cs index aab99beec8..548276f725 100644 --- a/src/common/ManagedCommon/ModuleType.cs +++ b/src/common/ManagedCommon/ModuleType.cs @@ -37,5 +37,6 @@ namespace ManagedCommon PowerOCR, Workspaces, ZoomIt, + GeneralSettings, } } diff --git a/src/common/SettingsAPI/settings_objects.h b/src/common/SettingsAPI/settings_objects.h index 84b064d5af..8927ba5657 100644 --- a/src/common/SettingsAPI/settings_objects.h +++ b/src/common/SettingsAPI/settings_objects.h @@ -119,6 +119,16 @@ namespace PowerToysSettings class HotkeyObject { public: + HotkeyObject() : + m_json(json::JsonObject()) + { + m_json.SetNamedValue(L"win", json::value(false)); + m_json.SetNamedValue(L"ctrl", json::value(false)); + m_json.SetNamedValue(L"alt", json::value(false)); + m_json.SetNamedValue(L"shift", json::value(false)); + m_json.SetNamedValue(L"code", json::value(0)); + m_json.SetNamedValue(L"key", json::value(L"")); + } static HotkeyObject from_json(json::JsonObject json) { return HotkeyObject(std::move(json)); diff --git a/src/common/interop/Constants.cpp b/src/common/interop/Constants.cpp index 86e5b16262..67b4da51f2 100644 --- a/src/common/interop/Constants.cpp +++ b/src/common/interop/Constants.cpp @@ -223,6 +223,10 @@ namespace winrt::PowerToys::Interop::implementation { return CommonSharedConstants::CROP_AND_LOCK_REPARENT_EVENT; } + hstring Constants::CropAndLockScreenshotEvent() + { + return CommonSharedConstants::CROP_AND_LOCK_SCREENSHOT_EVENT; + } hstring Constants::ShowEnvironmentVariablesSharedEvent() { return CommonSharedConstants::SHOW_ENVIRONMENT_VARIABLES_EVENT; diff --git a/src/common/interop/Constants.h b/src/common/interop/Constants.h index 5ac57d6f11..faa2a97379 100644 --- a/src/common/interop/Constants.h +++ b/src/common/interop/Constants.h @@ -59,6 +59,7 @@ namespace winrt::PowerToys::Interop::implementation static hstring TerminateHostsSharedEvent(); static hstring CropAndLockThumbnailEvent(); static hstring CropAndLockReparentEvent(); + static hstring CropAndLockScreenshotEvent(); static hstring ShowEnvironmentVariablesSharedEvent(); static hstring ShowEnvironmentVariablesAdminSharedEvent(); static hstring WorkspacesLaunchEditorEvent(); diff --git a/src/common/interop/Constants.idl b/src/common/interop/Constants.idl index 38cc1fdbe2..042d790699 100644 --- a/src/common/interop/Constants.idl +++ b/src/common/interop/Constants.idl @@ -56,6 +56,7 @@ namespace PowerToys static String TerminateHostsSharedEvent(); static String CropAndLockThumbnailEvent(); static String CropAndLockReparentEvent(); + static String CropAndLockScreenshotEvent(); static String ShowEnvironmentVariablesSharedEvent(); static String ShowEnvironmentVariablesAdminSharedEvent(); static String WorkspacesLaunchEditorEvent(); diff --git a/src/common/interop/shared_constants.h b/src/common/interop/shared_constants.h index 2df428f116..a007d50928 100644 --- a/src/common/interop/shared_constants.h +++ b/src/common/interop/shared_constants.h @@ -132,6 +132,7 @@ namespace CommonSharedConstants // Path to the events used by CropAndLock const wchar_t CROP_AND_LOCK_REPARENT_EVENT[] = L"Local\\PowerToysCropAndLockReparentEvent-6060860a-76a1-44e8-8d0e-6355785e9c36"; const wchar_t CROP_AND_LOCK_THUMBNAIL_EVENT[] = L"Local\\PowerToysCropAndLockThumbnailEvent-1637be50-da72-46b2-9220-b32b206b2434"; + const wchar_t CROP_AND_LOCK_SCREENSHOT_EVENT[] = L"Local\\PowerToysCropAndLockScreenshotEvent-ff077ab2-8360-4bd1-864a-637389d35593"; const wchar_t CROP_AND_LOCK_EXIT_EVENT[] = L"Local\\PowerToysCropAndLockExitEvent-d995d409-7b70-482b-bad6-e7c8666f375a"; // Path to the events used by EnvironmentVariables diff --git a/src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj b/src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj index c3e9e4f3f1..dfe9f11b2e 100644 --- a/src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj +++ b/src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj @@ -112,6 +112,7 @@ + @@ -126,6 +127,7 @@ + diff --git a/src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj.filters b/src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj.filters index bea68db119..e906ed2a02 100644 --- a/src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj.filters +++ b/src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj.filters @@ -12,6 +12,7 @@ + @@ -28,6 +29,7 @@ + diff --git a/src/modules/CropAndLock/CropAndLock/ScreenshotCropAndLockWindow.cpp b/src/modules/CropAndLock/CropAndLock/ScreenshotCropAndLockWindow.cpp new file mode 100644 index 0000000000..11afbd0a26 --- /dev/null +++ b/src/modules/CropAndLock/CropAndLock/ScreenshotCropAndLockWindow.cpp @@ -0,0 +1,178 @@ +#include "pch.h" +#include "ScreenshotCropAndLockWindow.h" + +const std::wstring ScreenshotCropAndLockWindow::ClassName = L"CropAndLock.ScreenshotCropAndLockWindow"; +std::once_flag ScreenshotCropAndLockWindowClassRegistration; + +void ScreenshotCropAndLockWindow::RegisterWindowClass() +{ + auto instance = winrt::check_pointer(GetModuleHandleW(nullptr)); + WNDCLASSEXW wcex = {}; + wcex.cbSize = sizeof(wcex); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.hInstance = instance; + wcex.hIcon = LoadIconW(instance, IDI_APPLICATION); + wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); + wcex.hbrBackground = static_cast(GetStockObject(BLACK_BRUSH)); + wcex.lpszClassName = ClassName.c_str(); + wcex.hIconSm = LoadIconW(wcex.hInstance, IDI_APPLICATION); + winrt::check_bool(RegisterClassExW(&wcex)); +} + +ScreenshotCropAndLockWindow::ScreenshotCropAndLockWindow(std::wstring const& titleString, int width, int height) +{ + auto instance = winrt::check_pointer(GetModuleHandleW(nullptr)); + + std::call_once(ScreenshotCropAndLockWindowClassRegistration, []() { RegisterWindowClass(); }); + + auto exStyle = 0; + auto style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN; + + RECT rect = { 0, 0, width, height }; + winrt::check_bool(AdjustWindowRectEx(&rect, style, false, exStyle)); + auto adjustedWidth = rect.right - rect.left; + auto adjustedHeight = rect.bottom - rect.top; + + winrt::check_bool(CreateWindowExW(exStyle, ClassName.c_str(), titleString.c_str(), style, CW_USEDEFAULT, CW_USEDEFAULT, adjustedWidth, adjustedHeight, nullptr, nullptr, instance, this)); + WINRT_ASSERT(m_window); +} + +ScreenshotCropAndLockWindow::~ScreenshotCropAndLockWindow() +{ + DestroyWindow(m_window); +} + +LRESULT ScreenshotCropAndLockWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) +{ + switch (message) + { + case WM_DESTROY: + if (m_closedCallback != nullptr && !m_destroyed) + { + m_destroyed = true; + m_closedCallback(m_window); + } + break; + case WM_PAINT: + if (m_captured && m_bitmap) + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(m_window, &ps); + HDC memDC = CreateCompatibleDC(hdc); + SelectObject(memDC, m_bitmap.get()); + + RECT clientRect = {}; + GetClientRect(m_window, &clientRect); + int clientWidth = clientRect.right - clientRect.left; + int clientHeight = clientRect.bottom - clientRect.top; + + int srcWidth = m_destRect.right - m_destRect.left; + int srcHeight = m_destRect.bottom - m_destRect.top; + + float srcAspect = static_cast(srcWidth) / srcHeight; + float dstAspect = static_cast(clientWidth) / clientHeight; + + int drawWidth = clientWidth; + int drawHeight = static_cast(clientWidth / srcAspect); + if (dstAspect > srcAspect) + { + drawHeight = clientHeight; + drawWidth = static_cast(clientHeight * srcAspect); + } + + int offsetX = (clientWidth - drawWidth) / 2; + int offsetY = (clientHeight - drawHeight) / 2; + + SetStretchBltMode(hdc, HALFTONE); + StretchBlt(hdc, offsetX, offsetY, drawWidth, drawHeight, memDC, 0, 0, srcWidth, srcHeight, SRCCOPY); + DeleteDC(memDC); + EndPaint(m_window, &ps); + } + break; + default: + return base_type::MessageHandler(message, wparam, lparam); + } + return 0; +} + +void ScreenshotCropAndLockWindow::CropAndLock(HWND windowToCrop, RECT cropRect) +{ + if (m_captured) + { + return; + } + + // Get full window bounds + RECT windowRect{}; + winrt::check_hresult(DwmGetWindowAttribute( + windowToCrop, + DWMWA_EXTENDED_FRAME_BOUNDS, + &windowRect, + sizeof(windowRect))); + + RECT clientRect = ClientAreaInScreenSpace(windowToCrop); + auto offsetX = clientRect.left - windowRect.left; + auto offsetY = clientRect.top - windowRect.top; + + m_sourceRect = { + cropRect.left + offsetX, + cropRect.top + offsetY, + cropRect.right + offsetX, + cropRect.bottom + offsetY + }; + + int fullWidth = windowRect.right - windowRect.left; + int fullHeight = windowRect.bottom - windowRect.top; + + HDC fullDC = CreateCompatibleDC(nullptr); + HDC screenDC = GetDC(nullptr); + HBITMAP fullBitmap = CreateCompatibleBitmap(screenDC, fullWidth, fullHeight); + HGDIOBJ oldFullBitmap = SelectObject(fullDC, fullBitmap); + + // Capture full window + winrt::check_bool(PrintWindow(windowToCrop, fullDC, PW_RENDERFULLCONTENT)); + + + // Crop + int cropWidth = m_sourceRect.right - m_sourceRect.left; + int cropHeight = m_sourceRect.bottom - m_sourceRect.top; + + HDC cropDC = CreateCompatibleDC(nullptr); + HBITMAP cropBitmap = CreateCompatibleBitmap(screenDC, cropWidth, cropHeight); + HGDIOBJ oldCropBitmap = SelectObject(cropDC, cropBitmap); + ReleaseDC(nullptr, screenDC); + + BitBlt( + cropDC, + 0, + 0, + cropWidth, + cropHeight, + fullDC, + m_sourceRect.left, + m_sourceRect.top, + SRCCOPY); + + SelectObject(fullDC, oldFullBitmap); + DeleteObject(fullBitmap); + DeleteDC(fullDC); + + SelectObject(cropDC, oldCropBitmap); + DeleteDC(cropDC); + m_bitmap.reset(cropBitmap); + + // Resize our window + RECT dest{ 0, 0, cropWidth, cropHeight }; + LONG_PTR exStyle = GetWindowLongPtrW(m_window, GWL_EXSTYLE); + LONG_PTR style = GetWindowLongPtrW(m_window, GWL_STYLE); + + winrt::check_bool(AdjustWindowRectEx(&dest, static_cast(style), FALSE, static_cast(exStyle))); + + winrt::check_bool(SetWindowPos( + m_window, HWND_TOPMOST, 0, 0, dest.right - dest.left, dest.bottom - dest.top, SWP_NOMOVE | SWP_SHOWWINDOW)); + + m_destRect = { 0, 0, cropWidth, cropHeight }; + m_captured = true; + InvalidateRect(m_window, nullptr, FALSE); +} \ No newline at end of file diff --git a/src/modules/CropAndLock/CropAndLock/ScreenshotCropAndLockWindow.h b/src/modules/CropAndLock/CropAndLock/ScreenshotCropAndLockWindow.h new file mode 100644 index 0000000000..149e4c740a --- /dev/null +++ b/src/modules/CropAndLock/CropAndLock/ScreenshotCropAndLockWindow.h @@ -0,0 +1,27 @@ +#pragma once +#include +#include "CropAndLockWindow.h" + +struct ScreenshotCropAndLockWindow : robmikh::common::desktop::DesktopWindow, CropAndLockWindow +{ + static const std::wstring ClassName; + ScreenshotCropAndLockWindow(std::wstring const& titleString, int width, int height); + ~ScreenshotCropAndLockWindow() override; + LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam); + + HWND Handle() override { return m_window; } + void CropAndLock(HWND windowToCrop, RECT cropRect) override; + void OnClosed(std::function callback) override { m_closedCallback = callback; } + +private: + static void RegisterWindowClass(); + +private: + std::unique_ptr m_bitmap{ nullptr, &DeleteObject }; + RECT m_destRect = {}; + RECT m_sourceRect = {}; + + bool m_captured = false; + bool m_destroyed = false; + std::function m_closedCallback; +}; \ No newline at end of file diff --git a/src/modules/CropAndLock/CropAndLock/SettingsWindow.h b/src/modules/CropAndLock/CropAndLock/SettingsWindow.h index 88489601ee..f51e4636f0 100644 --- a/src/modules/CropAndLock/CropAndLock/SettingsWindow.h +++ b/src/modules/CropAndLock/CropAndLock/SettingsWindow.h @@ -4,4 +4,5 @@ enum class CropAndLockType { Reparent, Thumbnail, + Screenshot, }; diff --git a/src/modules/CropAndLock/CropAndLock/main.cpp b/src/modules/CropAndLock/CropAndLock/main.cpp index 5aeea262a4..8f3ac89569 100644 --- a/src/modules/CropAndLock/CropAndLock/main.cpp +++ b/src/modules/CropAndLock/CropAndLock/main.cpp @@ -2,6 +2,7 @@ #include "SettingsWindow.h" #include "OverlayWindow.h" #include "CropAndLockWindow.h" +#include "ScreenshotCropAndLockWindow.h" #include "ThumbnailCropAndLockWindow.h" #include "ReparentCropAndLockWindow.h" #include "ModuleConstants.h" @@ -133,6 +134,7 @@ int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PWSTR lpCmdLine, _I // Handles and thread for the events sent from runner HANDLE m_reparent_event_handle; HANDLE m_thumbnail_event_handle; + HANDLE m_screenshot_event_handle; HANDLE m_exit_event_handle; std::thread m_event_triggers_thread; @@ -181,6 +183,11 @@ int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PWSTR lpCmdLine, _I Logger::trace(L"Creating a thumbnail window"); Trace::CropAndLock::CreateThumbnailWindow(); break; + case CropAndLockType::Screenshot: + croppedWindow = std::make_shared(title, 800, 600); + Logger::trace(L"Creating a screenshot window"); + Trace::CropAndLock::CreateScreenshotWindow(); + break; default: return; } @@ -215,8 +222,9 @@ int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PWSTR lpCmdLine, _I // Start a thread to listen on the events. m_reparent_event_handle = CreateEventW(nullptr, false, false, CommonSharedConstants::CROP_AND_LOCK_REPARENT_EVENT); m_thumbnail_event_handle = CreateEventW(nullptr, false, false, CommonSharedConstants::CROP_AND_LOCK_THUMBNAIL_EVENT); + m_screenshot_event_handle = CreateEventW(nullptr, false, false, CommonSharedConstants::CROP_AND_LOCK_SCREENSHOT_EVENT); m_exit_event_handle = CreateEventW(nullptr, false, false, CommonSharedConstants::CROP_AND_LOCK_EXIT_EVENT); - if (!m_reparent_event_handle || !m_thumbnail_event_handle || !m_exit_event_handle) + if (!m_reparent_event_handle || !m_thumbnail_event_handle || !m_screenshot_event_handle || !m_exit_event_handle) { Logger::warn(L"Failed to create events. {}", get_last_error_or_default(GetLastError())); return 1; @@ -224,10 +232,10 @@ int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PWSTR lpCmdLine, _I m_event_triggers_thread = std::thread([&]() { MSG msg; - HANDLE event_handles[3] = { m_reparent_event_handle, m_thumbnail_event_handle, m_exit_event_handle }; + HANDLE event_handles[4] = { m_reparent_event_handle, m_thumbnail_event_handle, m_screenshot_event_handle, m_exit_event_handle }; while (m_running) { - DWORD dwEvt = MsgWaitForMultipleObjects(3, event_handles, false, INFINITE, QS_ALLINPUT); + DWORD dwEvt = MsgWaitForMultipleObjects(4, event_handles, false, INFINITE, QS_ALLINPUT); if (!m_running) { break; @@ -259,13 +267,25 @@ int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PWSTR lpCmdLine, _I break; } case WAIT_OBJECT_0 + 2: + { + // Screenshot Event + bool enqueueSucceeded = controller.DispatcherQueue().TryEnqueue([&]() { + ProcessCommand(CropAndLockType::Screenshot); + }); + if (!enqueueSucceeded) + { + Logger::error("Couldn't enqueue message to screenshot a window."); + } + break; + } + case WAIT_OBJECT_0 + 3: { // Exit Event Logger::trace(L"Received an exit event."); PostThreadMessage(mainThreadId, WM_QUIT, 0, 0); break; } - case WAIT_OBJECT_0 + 3: + case WAIT_OBJECT_0 + 4: if (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); @@ -295,6 +315,7 @@ int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ PWSTR lpCmdLine, _I SetEvent(m_reparent_event_handle); CloseHandle(m_reparent_event_handle); CloseHandle(m_thumbnail_event_handle); + CloseHandle(m_screenshot_event_handle); CloseHandle(m_exit_event_handle); m_event_triggers_thread.join(); diff --git a/src/modules/CropAndLock/CropAndLock/trace.cpp b/src/modules/CropAndLock/CropAndLock/trace.cpp index 42674ec624..3a08fb9683 100644 --- a/src/modules/CropAndLock/CropAndLock/trace.cpp +++ b/src/modules/CropAndLock/CropAndLock/trace.cpp @@ -41,6 +41,15 @@ void Trace::CropAndLock::ActivateThumbnail() noexcept TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); } +void Trace::CropAndLock::ActivateScreenshot() noexcept +{ + TraceLoggingWriteWrapper( + g_hProvider, + "CropAndLock_ActivateScreenshot", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); +} + void Trace::CropAndLock::CreateReparentWindow() noexcept { TraceLoggingWriteWrapper( @@ -59,8 +68,17 @@ void Trace::CropAndLock::CreateThumbnailWindow() noexcept TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); } +void Trace::CropAndLock::CreateScreenshotWindow() noexcept +{ + TraceLoggingWriteWrapper( + g_hProvider, + "CropAndLock_CreateScreenshotWindow", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); +} + // Event to send settings telemetry. -void Trace::CropAndLock::SettingsTelemetry(PowertoyModuleIface::Hotkey& reparentHotkey, PowertoyModuleIface::Hotkey& thumbnailHotkey) noexcept +void Trace::CropAndLock::SettingsTelemetry(PowertoyModuleIface::Hotkey& reparentHotkey, PowertoyModuleIface::Hotkey& thumbnailHotkey, PowertoyModuleIface::Hotkey& screenshotHotkey) noexcept { std::wstring hotKeyStrReparent = std::wstring(reparentHotkey.win ? L"Win + " : L"") + @@ -76,11 +94,19 @@ void Trace::CropAndLock::SettingsTelemetry(PowertoyModuleIface::Hotkey& reparent std::wstring(thumbnailHotkey.alt ? L"Alt + " : L"") + std::wstring(L"VK ") + std::to_wstring(thumbnailHotkey.key); + std::wstring hotKeyStrScreenshot = + std::wstring(screenshotHotkey.win ? L"Win + " : L"") + + std::wstring(screenshotHotkey.ctrl ? L"Ctrl + " : L"") + + std::wstring(screenshotHotkey.shift ? L"Shift + " : L"") + + std::wstring(screenshotHotkey.alt ? L"Alt + " : L"") + + std::wstring(L"VK ") + std::to_wstring(screenshotHotkey.key); + TraceLoggingWriteWrapper( g_hProvider, "CropAndLock_Settings", ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE), TraceLoggingWideString(hotKeyStrReparent.c_str(), "ReparentHotKey"), - TraceLoggingWideString(hotKeyStrThumbnail.c_str(), "ThumbnailHotkey")); + TraceLoggingWideString(hotKeyStrThumbnail.c_str(), "ThumbnailHotkey"), + TraceLoggingWideString(hotKeyStrScreenshot.c_str(), "ScreenshotHotkey")); } diff --git a/src/modules/CropAndLock/CropAndLock/trace.h b/src/modules/CropAndLock/CropAndLock/trace.h index 5a9aaa95ca..bd9a3431a2 100644 --- a/src/modules/CropAndLock/CropAndLock/trace.h +++ b/src/modules/CropAndLock/CropAndLock/trace.h @@ -12,8 +12,10 @@ public: static void Enable(bool enabled) noexcept; static void ActivateReparent() noexcept; static void ActivateThumbnail() noexcept; + static void ActivateScreenshot() noexcept; static void CreateReparentWindow() noexcept; static void CreateThumbnailWindow() noexcept; - static void SettingsTelemetry(PowertoyModuleIface::Hotkey&, PowertoyModuleIface::Hotkey&) noexcept; + static void CreateScreenshotWindow() noexcept; + static void SettingsTelemetry(PowertoyModuleIface::Hotkey&, PowertoyModuleIface::Hotkey&, PowertoyModuleIface::Hotkey&) noexcept; }; }; diff --git a/src/modules/CropAndLock/CropAndLockModuleInterface/dllmain.cpp b/src/modules/CropAndLock/CropAndLockModuleInterface/dllmain.cpp index 42c7c6da7e..9821b786f1 100644 --- a/src/modules/CropAndLock/CropAndLockModuleInterface/dllmain.cpp +++ b/src/modules/CropAndLock/CropAndLockModuleInterface/dllmain.cpp @@ -29,6 +29,7 @@ namespace const wchar_t JSON_KEY_CODE[] = L"code"; const wchar_t JSON_KEY_REPARENT_HOTKEY[] = L"reparent-hotkey"; const wchar_t JSON_KEY_THUMBNAIL_HOTKEY[] = L"thumbnail-hotkey"; + const wchar_t JSON_KEY_SCREENSHOT_HOTKEY[] = L"screenshot-hotkey"; const wchar_t JSON_KEY_VALUE[] = L"value"; } @@ -124,6 +125,10 @@ public: SetEvent(m_thumbnail_event_handle); Trace::CropAndLock::ActivateThumbnail(); } + if (hotkeyId == 2) { // Same order as set by get_hotkeys + SetEvent(m_screenshot_event_handle); + Trace::CropAndLock::ActivateScreenshot(); + } return true; } @@ -133,12 +138,13 @@ public: virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override { - if (hotkeys && buffer_size >= 2) + if (hotkeys && buffer_size >= 3) { hotkeys[0] = m_reparent_hotkey; hotkeys[1] = m_thumbnail_hotkey; + hotkeys[2] = m_screenshot_hotkey; } - return 2; + return 3; } // Enable the powertoy @@ -171,7 +177,7 @@ public: virtual void send_settings_telemetry() override { Logger::info("Send settings telemetry"); - Trace::CropAndLock::SettingsTelemetry(m_reparent_hotkey, m_thumbnail_hotkey); + Trace::CropAndLock::SettingsTelemetry(m_reparent_hotkey, m_thumbnail_hotkey, m_screenshot_hotkey); } CropAndLockModuleInterface() @@ -182,6 +188,7 @@ public: m_reparent_event_handle = CreateDefaultEvent(CommonSharedConstants::CROP_AND_LOCK_REPARENT_EVENT); m_thumbnail_event_handle = CreateDefaultEvent(CommonSharedConstants::CROP_AND_LOCK_THUMBNAIL_EVENT); + m_screenshot_event_handle = CreateDefaultEvent(CommonSharedConstants::CROP_AND_LOCK_SCREENSHOT_EVENT); m_exit_event_handle = CreateDefaultEvent(CommonSharedConstants::CROP_AND_LOCK_EXIT_EVENT); init_settings(); @@ -202,6 +209,7 @@ private: ResetEvent(m_reparent_event_handle); ResetEvent(m_thumbnail_event_handle); + ResetEvent(m_screenshot_event_handle); ResetEvent(m_exit_event_handle); SHELLEXECUTEINFOW sei{ sizeof(sei) }; @@ -234,6 +242,7 @@ private: ResetEvent(m_reparent_event_handle); ResetEvent(m_thumbnail_event_handle); + ResetEvent(m_screenshot_event_handle); // Log telemetry if (traceEvent) @@ -283,6 +292,21 @@ private: { Logger::error("Failed to initialize CropAndLock thumbnail shortcut from settings. Value will keep unchanged."); } + try + { + Hotkey _temp_screenshot; + auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_SCREENSHOT_HOTKEY).GetNamedObject(JSON_KEY_VALUE); + _temp_screenshot.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN); + _temp_screenshot.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT); + _temp_screenshot.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT); + _temp_screenshot.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL); + _temp_screenshot.key = static_cast(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE)); + m_screenshot_hotkey = _temp_screenshot; + } + catch (...) + { + Logger::error("Failed to initialize CropAndLock screenshot shortcut from settings. Value will keep unchanged."); + } } else { @@ -321,9 +345,11 @@ private: // TODO: actual default hotkey setting in line with other PowerToys. Hotkey m_reparent_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'R' }; Hotkey m_thumbnail_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'T' }; + Hotkey m_screenshot_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'S' }; HANDLE m_reparent_event_handle; HANDLE m_thumbnail_event_handle; + HANDLE m_screenshot_event_handle; HANDLE m_exit_event_handle; }; diff --git a/src/modules/EnvironmentVariables/EnvironmentVariablesUILib/EnvironmentVariablesMainPage.xaml b/src/modules/EnvironmentVariables/EnvironmentVariablesUILib/EnvironmentVariablesMainPage.xaml index f2628cf375..baa2447cd1 100644 --- a/src/modules/EnvironmentVariables/EnvironmentVariablesUILib/EnvironmentVariablesMainPage.xaml +++ b/src/modules/EnvironmentVariables/EnvironmentVariablesUILib/EnvironmentVariablesMainPage.xaml @@ -466,27 +466,39 @@ TextChanged="EditVariableDialogValueTxtBox_TextChanged" TextWrapping="Wrap" /> - - + + + + + + + + + + + + + diff --git a/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/AppsListPage.xaml.cs b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/AppsListPage.xaml.cs new file mode 100644 index 0000000000..1212855fe4 --- /dev/null +++ b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/AppsListPage.xaml.cs @@ -0,0 +1,64 @@ +// 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.QuickAccess.ViewModels; +using Microsoft.PowerToys.Settings.UI.Library; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media.Animation; +using Microsoft.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.QuickAccess.Flyout; + +public sealed partial class AppsListPage : Page +{ + private FlyoutNavigationContext? _context; + + public AppsListPage() + { + InitializeComponent(); + } + + public AllAppsViewModel ViewModel { get; private set; } = default!; + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + + if (e.Parameter is FlyoutNavigationContext context) + { + _context = context; + ViewModel = context.AllAppsViewModel; + DataContext = ViewModel; + ViewModel.RefreshSettings(); + } + } + + private void BackButton_Click(object sender, RoutedEventArgs e) + { + if (_context == null || Frame == null) + { + return; + } + + Frame.Navigate(typeof(LaunchPage), _context, new SlideNavigationTransitionInfo { Effect = SlideNavigationTransitionEffect.FromLeft }); + } + + private void SortAlphabetical_Click(object sender, RoutedEventArgs e) + { + if (ViewModel != null) + { + ViewModel.DashboardSortOrder = DashboardSortOrder.Alphabetical; + } + } + + private void SortByStatus_Click(object sender, RoutedEventArgs e) + { + if (ViewModel != null) + { + ViewModel.DashboardSortOrder = DashboardSortOrder.ByStatus; + } + } +} diff --git a/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/FlyoutNavigationContext.cs b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/FlyoutNavigationContext.cs new file mode 100644 index 0000000000..3aab3ca334 --- /dev/null +++ b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/FlyoutNavigationContext.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.PowerToys.QuickAccess.Services; +using Microsoft.PowerToys.QuickAccess.ViewModels; + +namespace Microsoft.PowerToys.QuickAccess.Flyout; + +internal sealed record FlyoutNavigationContext( + LauncherViewModel LauncherViewModel, + AllAppsViewModel AllAppsViewModel, + IQuickAccessCoordinator Coordinator); diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Flyout/LaunchPage.xaml b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/LaunchPage.xaml similarity index 64% rename from src/settings-ui/Settings.UI/SettingsXAML/Flyout/LaunchPage.xaml rename to src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/LaunchPage.xaml index 8dea006b08..f2f53b57d4 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Flyout/LaunchPage.xaml +++ b/src/settings-ui/QuickAccess.UI/QuickAccessXAML/Flyout/LaunchPage.xaml @@ -1,5 +1,5 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Settings.UI.Controls/ModuleList/ModuleList.xaml.cs b/src/settings-ui/Settings.UI.Controls/ModuleList/ModuleList.xaml.cs new file mode 100644 index 0000000000..f9d36a7e69 --- /dev/null +++ b/src/settings-ui/Settings.UI.Controls/ModuleList/ModuleList.xaml.cs @@ -0,0 +1,57 @@ +// 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; + +namespace Microsoft.PowerToys.Settings.UI.Controls +{ + public sealed partial class ModuleList : UserControl + { + public ModuleList() + { + this.InitializeComponent(); + } + + public Thickness DividerThickness + { + get => (Thickness)GetValue(DividerThicknessProperty); + set => SetValue(DividerThicknessProperty, value); + } + + public static readonly DependencyProperty DividerThicknessProperty = DependencyProperty.Register(nameof(DividerThickness), typeof(Thickness), typeof(ModuleList), new PropertyMetadata(new Thickness(0, 1, 0, 0))); + + public bool IsItemClickable + { + get => (bool)GetValue(IsItemClickableProperty); + set => SetValue(IsItemClickableProperty, value); + } + + public static readonly DependencyProperty IsItemClickableProperty = DependencyProperty.Register(nameof(IsItemClickable), typeof(bool), typeof(ModuleList), new PropertyMetadata(true)); + + public object ItemsSource + { + get => (object)GetValue(ItemsSourceProperty); + set => SetValue(ItemsSourceProperty, value); + } + + public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(ModuleList), new PropertyMetadata(null)); + + public ModuleListSortOption SortOption + { + get => (ModuleListSortOption)GetValue(SortOptionProperty); + set => SetValue(SortOptionProperty, value); + } + + public static readonly DependencyProperty SortOptionProperty = DependencyProperty.Register(nameof(SortOption), typeof(ModuleListSortOption), typeof(ModuleList), new PropertyMetadata(ModuleListSortOption.Alphabetical)); + + private void OnSettingsCardClick(object sender, RoutedEventArgs e) + { + if (sender is FrameworkElement element && element.Tag is ModuleListItem item) + { + item.ClickCommand?.Execute(item.Tag); + } + } + } +} diff --git a/src/settings-ui/Settings.UI.Controls/ModuleList/ModuleListItem.cs b/src/settings-ui/Settings.UI.Controls/ModuleList/ModuleListItem.cs new file mode 100644 index 0000000000..ef92e3e592 --- /dev/null +++ b/src/settings-ui/Settings.UI.Controls/ModuleList/ModuleListItem.cs @@ -0,0 +1,119 @@ +// 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.ComponentModel; +using System.Runtime.CompilerServices; +using System.Windows.Input; + +namespace Microsoft.PowerToys.Settings.UI.Controls +{ + public class ModuleListItem : INotifyPropertyChanged + { + private bool _isEnabled; + private string _label = string.Empty; + private string _icon = string.Empty; + private bool _isNew; + private bool _isLocked; + private object? _tag; + private ICommand? _clickCommand; + + public virtual string Label + { + get => _label; + set + { + if (_label != value) + { + _label = value; + OnPropertyChanged(); + } + } + } + + public virtual string Icon + { + get => _icon; + set + { + if (_icon != value) + { + _icon = value; + OnPropertyChanged(); + } + } + } + + public virtual bool IsNew + { + get => _isNew; + set + { + if (_isNew != value) + { + _isNew = value; + OnPropertyChanged(); + } + } + } + + public virtual bool IsLocked + { + get => _isLocked; + set + { + if (_isLocked != value) + { + _isLocked = value; + OnPropertyChanged(); + } + } + } + + public virtual bool IsEnabled + { + get => _isEnabled; + set + { + if (_isEnabled != value) + { + _isEnabled = value; + OnPropertyChanged(); + } + } + } + + public virtual object? Tag + { + get => _tag; + set + { + if (_tag != value) + { + _tag = value; + OnPropertyChanged(); + } + } + } + + public virtual ICommand? ClickCommand + { + get => _clickCommand; + set + { + if (_clickCommand != value) + { + _clickCommand = value; + OnPropertyChanged(); + } + } + } + + public event PropertyChangedEventHandler? PropertyChanged; + + protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/src/settings-ui/Settings.UI.Controls/ModuleList/ModuleListSortOption.cs b/src/settings-ui/Settings.UI.Controls/ModuleList/ModuleListSortOption.cs new file mode 100644 index 0000000000..233c891d6b --- /dev/null +++ b/src/settings-ui/Settings.UI.Controls/ModuleList/ModuleListSortOption.cs @@ -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 Microsoft.PowerToys.Settings.UI.Controls +{ + public enum ModuleListSortOption + { + Alphabetical, + ByStatus, + } +} diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Controls/Dashboard/Card.xaml b/src/settings-ui/Settings.UI.Controls/Primitives/Card.xaml similarity index 97% rename from src/settings-ui/Settings.UI/SettingsXAML/Controls/Dashboard/Card.xaml rename to src/settings-ui/Settings.UI.Controls/Primitives/Card.xaml index 9563bfceb3..508d94b7ca 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Controls/Dashboard/Card.xaml +++ b/src/settings-ui/Settings.UI.Controls/Primitives/Card.xaml @@ -21,11 +21,11 @@ BorderThickness="{x:Bind BorderThickness, Mode=OneWay}" CornerRadius="{x:Bind CornerRadius, Mode=OneWay}"> - + - + diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Controls/Dashboard/Card.xaml.cs b/src/settings-ui/Settings.UI.Controls/Primitives/Card.xaml.cs similarity index 94% rename from src/settings-ui/Settings.UI/SettingsXAML/Controls/Dashboard/Card.xaml.cs rename to src/settings-ui/Settings.UI.Controls/Primitives/Card.xaml.cs index 1959a70445..ebf04c4e89 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Controls/Dashboard/Card.xaml.cs +++ b/src/settings-ui/Settings.UI.Controls/Primitives/Card.xaml.cs @@ -11,9 +11,9 @@ namespace Microsoft.PowerToys.Settings.UI.Controls { public static readonly DependencyProperty TitleContentProperty = DependencyProperty.Register(nameof(TitleContent), typeof(object), typeof(Card), new PropertyMetadata(defaultValue: null, OnVisualPropertyChanged)); - public object TitleContent + public object? TitleContent { - get => (object)GetValue(TitleContentProperty); + get => (object?)GetValue(TitleContentProperty); set => SetValue(TitleContentProperty, value); } @@ -34,7 +34,7 @@ namespace Microsoft.PowerToys.Settings.UI.Controls set => SetValue(ContentProperty, value); } - public static readonly DependencyProperty DividerVisibilityProperty = DependencyProperty.Register(nameof(DividerVisibility), typeof(Visibility), typeof(Card), new PropertyMetadata(defaultValue: null)); + public static readonly DependencyProperty DividerVisibilityProperty = DependencyProperty.Register(nameof(DividerVisibility), typeof(Visibility), typeof(Card), new PropertyMetadata(defaultValue: Visibility.Visible)); public Visibility DividerVisibility { @@ -66,7 +66,6 @@ namespace Microsoft.PowerToys.Settings.UI.Controls else { VisualStateManager.GoToState(this, "TitleGridVisible", true); - DividerVisibility = Visibility.Visible; } } } diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Controls/FlyoutMenuButton.xaml.cs b/src/settings-ui/Settings.UI.Controls/Primitives/FlyoutMenuButton.cs similarity index 96% rename from src/settings-ui/Settings.UI/SettingsXAML/Controls/FlyoutMenuButton.xaml.cs rename to src/settings-ui/Settings.UI.Controls/Primitives/FlyoutMenuButton.cs index bb1767e01e..f313506f23 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Controls/FlyoutMenuButton.xaml.cs +++ b/src/settings-ui/Settings.UI.Controls/Primitives/FlyoutMenuButton.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation +// 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. diff --git a/src/settings-ui/Settings.UI.Controls/QuickAccess/IQuickAccessLauncher.cs b/src/settings-ui/Settings.UI.Controls/QuickAccess/IQuickAccessLauncher.cs new file mode 100644 index 0000000000..8c35889c94 --- /dev/null +++ b/src/settings-ui/Settings.UI.Controls/QuickAccess/IQuickAccessLauncher.cs @@ -0,0 +1,13 @@ +// 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 ManagedCommon; + +namespace Microsoft.PowerToys.Settings.UI.Controls +{ + public interface IQuickAccessLauncher + { + bool Launch(ModuleType moduleType); + } +} diff --git a/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessItem.cs b/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessItem.cs new file mode 100644 index 0000000000..b639d87802 --- /dev/null +++ b/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessItem.cs @@ -0,0 +1,69 @@ +// 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.Windows.Input; +using Microsoft.PowerToys.Settings.UI.Library.Helpers; +using Microsoft.UI.Xaml; + +namespace Microsoft.PowerToys.Settings.UI.Controls +{ + public sealed class QuickAccessItem : Observable + { + private string _title = string.Empty; + + public string Title + { + get => _title; + set => Set(ref _title, value); + } + + private string _description = string.Empty; + + public string Description + { + get => _description; + set => Set(ref _description, value); + } + + private string _icon = string.Empty; + + public string Icon + { + get => _icon; + set => Set(ref _icon, value); + } + + private ICommand? _command; + + public ICommand? Command + { + get => _command; + set => Set(ref _command, value); + } + + private object? _commandParameter; + + public object? CommandParameter + { + get => _commandParameter; + set => Set(ref _commandParameter, value); + } + + private bool _visible = true; + + public bool Visible + { + get => _visible; + set => Set(ref _visible, value); + } + + private object? _tag; + + public object? Tag + { + get => _tag; + set => Set(ref _tag, value); + } + } +} diff --git a/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessLauncher.cs b/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessLauncher.cs new file mode 100644 index 0000000000..4799ff624f --- /dev/null +++ b/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessLauncher.cs @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using ManagedCommon; +using Microsoft.PowerToys.Settings.UI.Library; +using PowerToys.Interop; + +namespace Microsoft.PowerToys.Settings.UI.Controls +{ + public class QuickAccessLauncher : IQuickAccessLauncher + { + private readonly bool _isElevated; + + public QuickAccessLauncher(bool isElevated) + { + _isElevated = isElevated; + } + + public virtual bool Launch(ModuleType moduleType) + { + switch (moduleType) + { + case ModuleType.ColorPicker: + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowColorPickerSharedEvent())) + { + eventHandle.Set(); + } + + return true; + case ModuleType.EnvironmentVariables: + { + bool launchAdmin = SettingsRepository.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.LaunchAdministrator; + string eventName = !_isElevated && launchAdmin + ? Constants.ShowEnvironmentVariablesAdminSharedEvent() + : Constants.ShowEnvironmentVariablesSharedEvent(); + + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName)) + { + eventHandle.Set(); + } + } + + return true; + case ModuleType.FancyZones: + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.FZEToggleEvent())) + { + eventHandle.Set(); + } + + return true; + case ModuleType.Hosts: + { + bool launchAdmin = SettingsRepository.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.LaunchAdministrator; + string eventName = !_isElevated && launchAdmin + ? Constants.ShowHostsAdminSharedEvent() + : Constants.ShowHostsSharedEvent(); + + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName)) + { + eventHandle.Set(); + } + } + + return true; + case ModuleType.PowerLauncher: + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.PowerLauncherSharedEvent())) + { + eventHandle.Set(); + } + + return true; + case ModuleType.PowerOCR: + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowPowerOCRSharedEvent())) + { + eventHandle.Set(); + } + + return true; + case ModuleType.RegistryPreview: + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.RegistryPreviewTriggerEvent())) + { + eventHandle.Set(); + } + + return true; + case ModuleType.MeasureTool: + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.MeasureToolTriggerEvent())) + { + eventHandle.Set(); + } + + return true; + case ModuleType.ShortcutGuide: + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShortcutGuideTriggerEvent())) + { + eventHandle.Set(); + } + + return true; + case ModuleType.CmdPal: + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.ShowCmdPalEvent())) + { + eventHandle.Set(); + } + + return true; + case ModuleType.Workspaces: + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.WorkspacesLaunchEditorEvent())) + { + eventHandle.Set(); + } + + return true; + default: + return false; + } + } + } +} diff --git a/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessList.xaml b/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessList.xaml new file mode 100644 index 0000000000..415ae22684 --- /dev/null +++ b/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessList.xaml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessList.xaml.cs b/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessList.xaml.cs new file mode 100644 index 0000000000..34c4bad013 --- /dev/null +++ b/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessList.xaml.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; + +namespace Microsoft.PowerToys.Settings.UI.Controls +{ + public sealed partial class QuickAccessList : UserControl + { + public QuickAccessList() + { + this.InitializeComponent(); + } + + public object ItemsSource + { + get => (object)GetValue(ItemsSourceProperty); + set => SetValue(ItemsSourceProperty, value); + } + + public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(QuickAccessList), new PropertyMetadata(null)); + } +} diff --git a/src/settings-ui/Settings.UI/ViewModels/Flyout/LauncherViewModel.cs b/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessViewModel.cs similarity index 52% rename from src/settings-ui/Settings.UI/ViewModels/Flyout/LauncherViewModel.cs rename to src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessViewModel.cs index 931600d4f0..06d2dd9d07 100644 --- a/src/settings-ui/Settings.UI/ViewModels/Flyout/LauncherViewModel.cs +++ b/src/settings-ui/Settings.UI.Controls/QuickAccess/QuickAccessViewModel.cs @@ -4,41 +4,61 @@ using System; using System.Collections.ObjectModel; - -using global::PowerToys.GPOWrapper; using ManagedCommon; -using Microsoft.PowerToys.Settings.UI.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Helpers; using Microsoft.PowerToys.Settings.UI.Library.Interfaces; +using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands; +using Microsoft.UI.Dispatching; using Microsoft.Windows.ApplicationModel.Resources; -namespace Microsoft.PowerToys.Settings.UI.ViewModels +namespace Microsoft.PowerToys.Settings.UI.Controls { - public partial class LauncherViewModel : Observable + public partial class QuickAccessViewModel : Observable { - public bool IsUpdateAvailable { get; set; } + private readonly ISettingsRepository _settingsRepository; + private readonly IQuickAccessLauncher _launcher; + private readonly Func _isModuleGpoDisabled; + private readonly ResourceLoader _resourceLoader; + private readonly DispatcherQueue _dispatcherQueue; + private GeneralSettings _generalSettings; - public ObservableCollection FlyoutMenuItems { get; set; } + public ObservableCollection Items { get; } = new(); - private GeneralSettings generalSettingsConfig; - private UpdatingSettings updatingSettingsConfig; - private ISettingsRepository _settingsRepository; - private ResourceLoader resourceLoader; - - private Func SendIPCMessage { get; } - - public LauncherViewModel(ISettingsRepository settingsRepository, Func ipcMSGCallBackFunc) + public QuickAccessViewModel( + ISettingsRepository settingsRepository, + IQuickAccessLauncher launcher, + Func isModuleGpoDisabled, + ResourceLoader resourceLoader) { _settingsRepository = settingsRepository; - generalSettingsConfig = settingsRepository.SettingsConfig; - generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChanged); + _launcher = launcher; + _isModuleGpoDisabled = isModuleGpoDisabled; + _resourceLoader = resourceLoader; + _dispatcherQueue = DispatcherQueue.GetForCurrentThread(); - // set the callback functions value to handle outgoing IPC message. - SendIPCMessage = ipcMSGCallBackFunc; - resourceLoader = ResourceLoaderInstance.ResourceLoader; - FlyoutMenuItems = new ObservableCollection(); + _generalSettings = _settingsRepository.SettingsConfig; + _generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChanged); + _settingsRepository.SettingsChanged += OnSettingsChanged; + InitializeItems(); + } + + private void OnSettingsChanged(GeneralSettings newSettings) + { + if (_dispatcherQueue != null) + { + _dispatcherQueue.TryEnqueue(() => + { + _generalSettings = newSettings; + _generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChanged); + RefreshItemsVisibility(); + }); + } + } + + private void InitializeItems() + { AddFlyoutMenuItem(ModuleType.ColorPicker); AddFlyoutMenuItem(ModuleType.CmdPal); AddFlyoutMenuItem(ModuleType.EnvironmentVariables); @@ -51,40 +71,50 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels AddFlyoutMenuItem(ModuleType.MeasureTool); AddFlyoutMenuItem(ModuleType.ShortcutGuide); AddFlyoutMenuItem(ModuleType.Workspaces); - - updatingSettingsConfig = UpdatingSettings.LoadSettings(); - if (updatingSettingsConfig == null) - { - updatingSettingsConfig = new UpdatingSettings(); - } - - if (updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToInstall || updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToDownload) - { - IsUpdateAvailable = true; - } - else - { - IsUpdateAvailable = false; - } } private void AddFlyoutMenuItem(ModuleType moduleType) { - if (ModuleHelper.GetModuleGpoConfiguration(moduleType) == GpoRuleConfigured.Disabled) + if (_isModuleGpoDisabled(moduleType)) { return; } - FlyoutMenuItems.Add(new FlyoutMenuItem() + Items.Add(new QuickAccessItem { - Label = resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)), + Title = _resourceLoader.GetString(Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetModuleLabelResourceName(moduleType)), Tag = moduleType, - Visible = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType), - ToolTip = GetModuleToolTip(moduleType), - Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType), + Visible = Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetIsModuleEnabled(_generalSettings, moduleType), + Description = GetModuleToolTip(moduleType), + Icon = Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetModuleTypeFluentIconName(moduleType), + Command = new RelayCommand(() => _launcher.Launch(moduleType)), }); } + private void ModuleEnabledChanged() + { + if (_dispatcherQueue != null) + { + _dispatcherQueue.TryEnqueue(() => + { + _generalSettings = _settingsRepository.SettingsConfig; + _generalSettings.AddEnabledModuleChangeNotification(ModuleEnabledChanged); + RefreshItemsVisibility(); + }); + } + } + + private void RefreshItemsVisibility() + { + foreach (var item in Items) + { + if (item.Tag is ModuleType moduleType) + { + item.Visible = Microsoft.PowerToys.Settings.UI.Library.Helpers.ModuleHelper.GetIsModuleEnabled(_generalSettings, moduleType); + } + } + } + private string GetModuleToolTip(ModuleType moduleType) { return moduleType switch @@ -101,16 +131,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels }; } - private void ModuleEnabledChanged() - { - generalSettingsConfig = _settingsRepository.SettingsConfig; - generalSettingsConfig.AddEnabledModuleChangeNotification(ModuleEnabledChanged); - foreach (FlyoutMenuItem item in FlyoutMenuItems) - { - item.Visible = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, item.Tag); - } - } - private string GetShortcutGuideToolTip() { var shortcutGuideSettings = SettingsRepository.GetInstance(SettingsUtils.Default).SettingsConfig; @@ -118,15 +138,5 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels ? "Win" : shortcutGuideSettings.Properties.OpenShortcutGuide.ToString(); } - - internal void StartBugReport() - { - SendIPCMessage("{\"bugreport\": 0 }"); - } - - internal void KillRunner() - { - SendIPCMessage("{\"killrunner\": 0 }"); - } } } diff --git a/src/settings-ui/Settings.UI.Controls/Settings.UI.Controls.csproj b/src/settings-ui/Settings.UI.Controls/Settings.UI.Controls.csproj new file mode 100644 index 0000000000..fac43d56a4 --- /dev/null +++ b/src/settings-ui/Settings.UI.Controls/Settings.UI.Controls.csproj @@ -0,0 +1,32 @@ + + + + + + Library + net9.0-windows10.0.26100.0 + Microsoft.PowerToys.Settings.UI.Controls + PowerToys.Settings.UI.Controls + true + true + true + PowerToys.Settings.UI.Controls.pri + enable + x64;ARM64 + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Settings.UI.Controls/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI.Controls/Strings/en-us/Resources.resw new file mode 100644 index 0000000000..6664b14936 --- /dev/null +++ b/src/settings-ui/Settings.UI.Controls/Strings/en-us/Resources.resw @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Sort utilities + + + Alphabetically + + + By status + + + Sort utilities + + + NEW + + + This setting is managed by your organization + + \ No newline at end of file diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Controls/FlyoutMenuButton.xaml b/src/settings-ui/Settings.UI.Controls/Themes/Generic.xaml similarity index 95% rename from src/settings-ui/Settings.UI/SettingsXAML/Controls/FlyoutMenuButton.xaml rename to src/settings-ui/Settings.UI.Controls/Themes/Generic.xaml index 50c0e4007c..466ad4475b 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Controls/FlyoutMenuButton.xaml +++ b/src/settings-ui/Settings.UI.Controls/Themes/Generic.xaml @@ -1,14 +1,9 @@ - - - -