From 2182aabe35a44aee792b42803b1e591551f67c89 Mon Sep 17 00:00:00 2001 From: Davide Giacometti Date: Mon, 24 Jan 2022 18:02:09 +0100 Subject: [PATCH] always on top accent color borders (#15709) --- .../alwaysontop/AlwaysOnTop/AlwaysOnTop.cpp | 2 +- .../alwaysontop/AlwaysOnTop/Settings.cpp | 19 +++++++ .../alwaysontop/AlwaysOnTop/Settings.h | 4 ++ .../AlwaysOnTop/SettingsConstants.h | 3 +- .../alwaysontop/AlwaysOnTop/WindowBorder.cpp | 25 +++++++-- .../AlwaysOnTopProperties.cs | 5 ++ .../ViewModels/AlwaysOnTopViewModel.cs | 17 +++++++ .../Settings.UI/Strings/en-us/Resources.resw | 51 +++++++++++-------- .../Settings.UI/Views/AlwaysOnTopPage.xaml | 19 ++++++- 9 files changed, 118 insertions(+), 27 deletions(-) diff --git a/src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.cpp b/src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.cpp index 841d9009e0..7a98aebe7b 100644 --- a/src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.cpp +++ b/src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.cpp @@ -38,7 +38,7 @@ bool isExcluded(HWND window) } AlwaysOnTop::AlwaysOnTop() : - SettingsObserver({SettingId::FrameEnabled, SettingId::Hotkey, SettingId::ExcludeApps}), + SettingsObserver({SettingId::FrameEnabled, SettingId::Hotkey, SettingId::ExcludeApps, SettingId::FrameAccentColor}), m_hinstance(reinterpret_cast(&__ImageBase)) { s_instance = this; diff --git a/src/modules/alwaysontop/AlwaysOnTop/Settings.cpp b/src/modules/alwaysontop/AlwaysOnTop/Settings.cpp index ea5cc8ee84..eb7a0e9abc 100644 --- a/src/modules/alwaysontop/AlwaysOnTop/Settings.cpp +++ b/src/modules/alwaysontop/AlwaysOnTop/Settings.cpp @@ -19,6 +19,7 @@ namespace NonLocalizable const static wchar_t* FrameColorID = L"frame-color"; const static wchar_t* BlockInGameModeID = L"do-not-activate-on-game-mode"; const static wchar_t* ExcludedAppsID = L"excluded-apps"; + const static wchar_t* FrameAccentColor = L"frame-accent-color"; } // TODO: move to common utils @@ -42,6 +43,14 @@ inline COLORREF HexToRGB(std::wstring_view hex, const COLORREF fallbackColor = R AlwaysOnTopSettings::AlwaysOnTopSettings() { + m_uiSettings.ColorValuesChanged([&](winrt::Windows::UI::ViewManagement::UISettings const& settings, + winrt::Windows::Foundation::IInspectable const& args) + { + if (m_settings.frameAccentColor) + { + NotifyObservers(SettingId::FrameAccentColor); + } + }); } AlwaysOnTopSettings& AlwaysOnTopSettings::instance() @@ -167,6 +176,16 @@ void AlwaysOnTopSettings::LoadSettings() NotifyObservers(SettingId::ExcludeApps); } } + + if (const auto jsonVal = values.get_bool_value(NonLocalizable::FrameAccentColor)) + { + auto val = *jsonVal; + if (m_settings.frameAccentColor != val) + { + m_settings.frameAccentColor = val; + NotifyObservers(SettingId::FrameAccentColor); + } + } } catch (...) { diff --git a/src/modules/alwaysontop/AlwaysOnTop/Settings.h b/src/modules/alwaysontop/AlwaysOnTop/Settings.h index d447b044cf..0853abc2cb 100644 --- a/src/modules/alwaysontop/AlwaysOnTop/Settings.h +++ b/src/modules/alwaysontop/AlwaysOnTop/Settings.h @@ -7,6 +7,8 @@ #include +#include + class SettingsObserver; // Needs to be kept in sync with src\settings-ui\Settings.UI.Library\AlwaysOnTopProperties.cs @@ -16,6 +18,7 @@ struct Settings bool enableFrame = true; bool enableSound = true; bool blockInGameMode = true; + bool frameAccentColor = true; float frameThickness = 15.0f; COLORREF frameColor = RGB(0, 173, 239); std::vector excludedApps{}; @@ -42,6 +45,7 @@ private: AlwaysOnTopSettings(); ~AlwaysOnTopSettings() = default; + winrt::Windows::UI::ViewManagement::UISettings m_uiSettings; Settings m_settings; std::unique_ptr m_settingsFileWatcher; std::unordered_set m_observers; diff --git a/src/modules/alwaysontop/AlwaysOnTop/SettingsConstants.h b/src/modules/alwaysontop/AlwaysOnTop/SettingsConstants.h index 4c7f466ca2..87bd5d6e91 100644 --- a/src/modules/alwaysontop/AlwaysOnTop/SettingsConstants.h +++ b/src/modules/alwaysontop/AlwaysOnTop/SettingsConstants.h @@ -8,5 +8,6 @@ enum class SettingId FrameThickness, FrameColor, BlockInGameMode, - ExcludeApps + ExcludeApps, + FrameAccentColor }; \ No newline at end of file diff --git a/src/modules/alwaysontop/AlwaysOnTop/WindowBorder.cpp b/src/modules/alwaysontop/AlwaysOnTop/WindowBorder.cpp index f0e8b6ee2c..b1cfbad2db 100644 --- a/src/modules/alwaysontop/AlwaysOnTop/WindowBorder.cpp +++ b/src/modules/alwaysontop/AlwaysOnTop/WindowBorder.cpp @@ -5,6 +5,7 @@ #include #include +#include "winrt/Windows.Foundation.h" // Non-Localizable strings namespace NonLocalizable @@ -30,7 +31,7 @@ std::optional GetFrameRect(HWND window) } WindowBorder::WindowBorder(HWND window) : - SettingsObserver({SettingId::FrameColor, SettingId::FrameThickness}), + SettingsObserver({SettingId::FrameColor, SettingId::FrameThickness, SettingId::FrameAccentColor }), m_window(nullptr), m_trackingWindow(window), m_frameDrawer(nullptr) @@ -38,7 +39,7 @@ WindowBorder::WindowBorder(HWND window) : } WindowBorder::WindowBorder(WindowBorder&& other) : - SettingsObserver({ SettingId::FrameColor, SettingId::FrameThickness }), + SettingsObserver({ SettingId::FrameColor, SettingId::FrameThickness, SettingId::FrameAccentColor }), m_window(other.m_window), m_trackingWindow(other.m_trackingWindow), m_frameDrawer(std::move(other.m_frameDrawer)) @@ -152,7 +153,20 @@ void WindowBorder::UpdateBorderProperties() const RECT windowRect = windowRectOpt.value(); RECT frameRect{ 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top }; - m_frameDrawer->SetBorderRect(frameRect, AlwaysOnTopSettings::settings().frameColor, AlwaysOnTopSettings::settings().frameThickness); + + COLORREF color; + if (AlwaysOnTopSettings::settings().frameAccentColor) + { + winrt::Windows::UI::ViewManagement::UISettings settings; + auto accentValue = settings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Accent); + color = RGB(accentValue.R, accentValue.G, accentValue.B); + } + else + { + color = AlwaysOnTopSettings::settings().frameColor; + } + + m_frameDrawer->SetBorderRect(frameRect, color, AlwaysOnTopSettings::settings().frameThickness); } void WindowBorder::Show() const @@ -216,6 +230,11 @@ void WindowBorder::SettingsUpdate(SettingId id) } break; + case SettingId::FrameAccentColor: + { + UpdateBorderProperties(); + } + break; default: break; } diff --git a/src/settings-ui/Settings.UI.Library/AlwaysOnTopProperties.cs b/src/settings-ui/Settings.UI.Library/AlwaysOnTopProperties.cs index 05304c4447..a4cf4c0b95 100644 --- a/src/settings-ui/Settings.UI.Library/AlwaysOnTopProperties.cs +++ b/src/settings-ui/Settings.UI.Library/AlwaysOnTopProperties.cs @@ -16,6 +16,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library public const string DefaultFrameColor = "#0099cc"; public const bool DefaultSoundEnabled = true; public const bool DefaultDoNotActivateOnGameMode = true; + public const bool DefaultFrameAccentColor = true; public AlwaysOnTopProperties() { @@ -26,6 +27,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library SoundEnabled = new BoolProperty(DefaultSoundEnabled); DoNotActivateOnGameMode = new BoolProperty(DefaultDoNotActivateOnGameMode); ExcludedApps = new StringProperty(); + FrameAccentColor = new BoolProperty(DefaultFrameAccentColor); } [JsonPropertyName("hotkey")] @@ -49,6 +51,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library [JsonPropertyName("excluded-apps")] public StringProperty ExcludedApps { get; set; } + [JsonPropertyName("frame-accent-color")] + public BoolProperty FrameAccentColor { get; set; } + public string ToJsonString() { return JsonSerializer.Serialize(this); diff --git a/src/settings-ui/Settings.UI.Library/ViewModels/AlwaysOnTopViewModel.cs b/src/settings-ui/Settings.UI.Library/ViewModels/AlwaysOnTopViewModel.cs index e2868a302a..59468962ea 100644 --- a/src/settings-ui/Settings.UI.Library/ViewModels/AlwaysOnTopViewModel.cs +++ b/src/settings-ui/Settings.UI.Library/ViewModels/AlwaysOnTopViewModel.cs @@ -52,6 +52,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels _soundEnabled = Settings.Properties.SoundEnabled.Value; _doNotActivateOnGameMode = Settings.Properties.DoNotActivateOnGameMode.Value; _excludedApps = Settings.Properties.ExcludedApps.Value; + _frameAccentColor = Settings.Properties.FrameAccentColor.Value; // set the callback functions value to hangle outgoing IPC message. SendConfigMSG = ipcMSGCallBackFunc; @@ -190,6 +191,21 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels } } + public bool FrameAccentColor + { + get => _frameAccentColor; + + set + { + if (value != _frameAccentColor) + { + _frameAccentColor = value; + Settings.Properties.FrameAccentColor.Value = value; + NotifyPropertyChanged(); + } + } + } + public void NotifyPropertyChanged([CallerMemberName] string propertyName = null) { OnPropertyChanged(propertyName); @@ -204,5 +220,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels private bool _soundEnabled; private bool _doNotActivateOnGameMode; private string _excludedApps; + private bool _frameAccentColor; } } diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw index 3c5ba8ac3c..8295ecc966 100644 --- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw @@ -1765,7 +1765,7 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex Spotlight radius (px) - px = pixels + px = pixels Spotlight initial zoom @@ -1775,11 +1775,11 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex Animation duration (ms) - ms = milliseconds + ms = milliseconds Time before the spotlight appears (ms) - ms = milliseconds + ms = milliseconds Mouse Highlighter @@ -1811,23 +1811,23 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex Radius (px) - px = pixels + px = pixels Fade delay (ms) - ms = milliseconds + ms = milliseconds Time before a highlight appears (ms) - ms = milliseconds + ms = milliseconds Fade duration (ms) - ms = milliseconds + ms = milliseconds Duration of the disappear animation (ms) - ms = milliseconds + ms = milliseconds Mouse Pointer Crosshair @@ -1916,11 +1916,11 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex Always On Top is a quick and easy way to pin windows on top. - "Always On Top" is the name of the utility + "Always On Top" is the name of the utility Always On Top - "Always On Top" is the name of the utility + "Always On Top" is the name of the utility Activation @@ -1949,43 +1949,43 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex px = pixels - Appearance & behavior + Appearance & behavior Always On Top - "Always On Top" is the name of the utility + "Always On Top" is the name of the utility Do not activate when Game Mode is on - Game Mode is a Windows feature + Game Mode is a Windows feature - + Sound Play a sound when pinning a window - + Behavior - + Learn more about Always On Top - "Always On Top" is the name of the utility + "Always On Top" is the name of the utility - + Activation shortcut - + Customize the shortcut to pin or unpin an app window "Always On Top" is the name of the utility Always On Top - "Always On Top" is the name of the utility + "Always On Top" is the name of the utility Always On Top improves your multitasking workflow by pinning an application window so it's always in front - even when focus changes to another window after that. - "Always On Top" is the name of the utility + "Always On Top" is the name of the utility to pin or unpin the selected window so it's always on top of all other windows. @@ -1993,4 +1993,13 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex You can tweak the visual outline of the pinned windows in PowerToys settings. + + Color mode + + + Custom color + + + Window default + \ No newline at end of file diff --git a/src/settings-ui/Settings.UI/Views/AlwaysOnTopPage.xaml b/src/settings-ui/Settings.UI/Views/AlwaysOnTopPage.xaml index 42608d3e13..0be99975b0 100644 --- a/src/settings-ui/Settings.UI/Views/AlwaysOnTopPage.xaml +++ b/src/settings-ui/Settings.UI/Views/AlwaysOnTopPage.xaml @@ -5,8 +5,15 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls" + xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters" mc:Ignorable="d" AutomationProperties.LandmarkType="Main"> + + + + + + @@ -50,7 +57,17 @@ - + + + + + + + + + + +