always on top accent color borders (#15709)

This commit is contained in:
Davide Giacometti
2022-01-24 18:02:09 +01:00
committed by GitHub
parent 2ccf492707
commit 2182aabe35
9 changed files with 118 additions and 27 deletions

View File

@@ -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<HINSTANCE>(&__ImageBase))
{
s_instance = this;

View File

@@ -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 (...)
{

View File

@@ -7,6 +7,8 @@
#include <SettingsConstants.h>
#include <winrt/Windows.UI.ViewManagement.h>
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<std::wstring> excludedApps{};
@@ -42,6 +45,7 @@ private:
AlwaysOnTopSettings();
~AlwaysOnTopSettings() = default;
winrt::Windows::UI::ViewManagement::UISettings m_uiSettings;
Settings m_settings;
std::unique_ptr<FileWatcher> m_settingsFileWatcher;
std::unordered_set<SettingsObserver*> m_observers;

View File

@@ -8,5 +8,6 @@ enum class SettingId
FrameThickness,
FrameColor,
BlockInGameMode,
ExcludeApps
ExcludeApps,
FrameAccentColor
};

View File

@@ -5,6 +5,7 @@
#include <FrameDrawer.h>
#include <Settings.h>
#include "winrt/Windows.Foundation.h"
// Non-Localizable strings
namespace NonLocalizable
@@ -30,7 +31,7 @@ std::optional<RECT> 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;
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -1765,7 +1765,7 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
</data>
<data name="MouseUtils_FindMyMouse_SpotlightRadius.Header" xml:space="preserve">
<value>Spotlight radius (px)</value>
<comment>px = pixels</comment>
<comment>px = pixels</comment>
</data>
<data name="MouseUtils_FindMyMouse_SpotlightInitialZoom.Header" xml:space="preserve">
<value>Spotlight initial zoom</value>
@@ -1775,11 +1775,11 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
</data>
<data name="MouseUtils_FindMyMouse_AnimationDurationMs.Header" xml:space="preserve">
<value>Animation duration (ms)</value>
<comment>ms = milliseconds</comment>
<comment>ms = milliseconds</comment>
</data>
<data name="MouseUtils_FindMyMouse_AnimationDurationMs.Description" xml:space="preserve">
<value>Time before the spotlight appears (ms)</value>
<comment>ms = milliseconds</comment>
<comment>ms = milliseconds</comment>
</data>
<data name="MouseUtils_MouseHighlighter.Header" xml:space="preserve">
<value>Mouse Highlighter</value>
@@ -1811,23 +1811,23 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
</data>
<data name="MouseUtils_MouseHighlighter_HighlightRadius.Header" xml:space="preserve">
<value>Radius (px)</value>
<comment>px = pixels</comment>
<comment>px = pixels</comment>
</data>
<data name="MouseUtils_MouseHighlighter_FadeDelayMs.Header" xml:space="preserve">
<value>Fade delay (ms)</value>
<comment>ms = milliseconds</comment>
<comment>ms = milliseconds</comment>
</data>
<data name="MouseUtils_MouseHighlighter_FadeDelayMs.Description" xml:space="preserve">
<value>Time before a highlight appears (ms)</value>
<comment>ms = milliseconds</comment>
<comment>ms = milliseconds</comment>
</data>
<data name="MouseUtils_MouseHighlighter_FadeDurationMs.Header" xml:space="preserve">
<value>Fade duration (ms)</value>
<comment>ms = milliseconds</comment>
<comment>ms = milliseconds</comment>
</data>
<data name="MouseUtils_MouseHighlighter_FadeDurationMs.Description" xml:space="preserve">
<value>Duration of the disappear animation (ms)</value>
<comment>ms = milliseconds</comment>
<comment>ms = milliseconds</comment>
</data>
<data name="MouseUtils_MousePointerCrosshair.Header" xml:space="preserve">
<value>Mouse Pointer Crosshair</value>
@@ -1916,11 +1916,11 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
</data>
<data name="AlwaysOnTop.ModuleDescription" xml:space="preserve">
<value>Always On Top is a quick and easy way to pin windows on top.</value>
<comment>"Always On Top" is the name of the utility</comment>
<comment>"Always On Top" is the name of the utility</comment>
</data>
<data name="AlwaysOnTop.ModuleTitle" xml:space="preserve">
<value>Always On Top </value>
<comment>"Always On Top" is the name of the utility</comment>
<comment>"Always On Top" is the name of the utility</comment>
</data>
<data name="AlwaysOnTop_Activation_GroupSettings.Header" xml:space="preserve">
<value>Activation</value>
@@ -1949,43 +1949,43 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
<comment>px = pixels</comment>
</data>
<data name="AlwaysOnTop_Behavior_GroupSettings.Header" xml:space="preserve">
<value>Appearance &amp; behavior</value>
<value>Appearance &amp; behavior</value>
</data>
<data name="Shell_AlwaysOnTop.Content" xml:space="preserve">
<value>Always On Top</value>
<comment>"Always On Top" is the name of the utility</comment>
<comment>"Always On Top" is the name of the utility</comment>
</data>
<data name="AlwaysOnTop_GameMode.Content" xml:space="preserve">
<value>Do not activate when Game Mode is on</value>
<comment>Game Mode is a Windows feature</comment>
<comment>Game Mode is a Windows feature</comment>
</data>
<data name="AlwaysOnTop_SoundTitle.Header" xml:space="preserve">
<data name="AlwaysOnTop_SoundTitle.Header" xml:space="preserve">
<value>Sound</value>
</data>
<data name="AlwaysOnTop_Sound.Content" xml:space="preserve">
<value>Play a sound when pinning a window</value>
</data>
<data name="AlwaysOnTop_Behavior.Header" xml:space="preserve">
<data name="AlwaysOnTop_Behavior.Header" xml:space="preserve">
<value>Behavior</value>
</data>
<data name="LearnMore_AlwaysOnTop.Text" xml:space="preserve">
<data name="LearnMore_AlwaysOnTop.Text" xml:space="preserve">
<value>Learn more about Always On Top</value>
<comment>"Always On Top" is the name of the utility</comment>
<comment>"Always On Top" is the name of the utility</comment>
</data>
<data name="AlwaysOnTop_ActivationShortcut.Header" xml:space="preserve">
<data name="AlwaysOnTop_ActivationShortcut.Header" xml:space="preserve">
<value>Activation shortcut</value>
</data>
<data name="AlwaysOnTop_ActivationShortcut.Description" xml:space="preserve">
<data name="AlwaysOnTop_ActivationShortcut.Description" xml:space="preserve">
<value>Customize the shortcut to pin or unpin an app window</value>
<comment>"Always On Top" is the name of the utility</comment>
</data>
<data name="Oobe_AlwaysOnTop" xml:space="preserve">
<value>Always On Top</value>
<comment>"Always On Top" is the name of the utility</comment>
<comment>"Always On Top" is the name of the utility</comment>
</data>
<data name="Oobe_AlwaysOnTop_Description" xml:space="preserve">
<value>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.</value>
<comment>"Always On Top" is the name of the utility</comment>
<comment>"Always On Top" is the name of the utility</comment>
</data>
<data name="Oobe_AlwaysOnTop_HowToUse.Text" xml:space="preserve">
<value>to pin or unpin the selected window so it's always on top of all other windows.</value>
@@ -1993,4 +1993,13 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
<data name="Oobe_AlwaysOnTop_TipsAndTricks.Text" xml:space="preserve">
<value>You can tweak the visual outline of the pinned windows in PowerToys settings.</value>
</data>
<data name="AlwaysOnTop_FrameColor_Mode.Header" xml:space="preserve">
<value>Color mode</value>
</data>
<data name="AlwaysOnTop_Radio_Custom_Color.Content" xml:space="preserve">
<value>Custom color</value>
</data>
<data name="AlwaysOnTop_Radio_Windows_Default.Content" xml:space="preserve">
<value>Window default</value>
</data>
</root>

View File

@@ -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">
<Page.Resources>
<converters:BoolToObjectConverter x:Key="BoolToComboBoxIndexConverter" TrueValue="1" FalseValue="0"/>
<converters:BoolToVisibilityConverter x:Key="FalseToVisibleConverter" TrueValue="Collapsed" FalseValue="Visible"/>
</Page.Resources>
<controls:SettingsPageControl x:Uid="AlwaysOnTop" IsTabStop="False"
ModuleImageSource="ms-appx:///Assets/Modules/AlwaysOnTop.png">
<controls:SettingsPageControl.ModuleContent>
@@ -50,7 +57,17 @@
</controls:SettingExpander.Header>
<controls:SettingExpander.Content>
<StackPanel>
<controls:Setting x:Uid="AlwaysOnTop_FrameColor" Style="{StaticResource ExpanderContentSettingStyle}" IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.FrameEnabled}">
<controls:Setting x:Uid="AlwaysOnTop_FrameColor_Mode" Style="{StaticResource ExpanderContentSettingStyle}" IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.FrameEnabled}">
<controls:Setting.ActionContent>
<ComboBox SelectedIndex="{x:Bind Mode=TwoWay, Path=ViewModel.FrameAccentColor, Converter={StaticResource BoolToComboBoxIndexConverter}}" MinWidth="{StaticResource SettingActionControlMinWidth}">
<ComboBoxItem x:Uid="AlwaysOnTop_Radio_Custom_Color"/>
<ComboBoxItem x:Uid="AlwaysOnTop_Radio_Windows_Default"/>
</ComboBox>
</controls:Setting.ActionContent>
</controls:Setting>
<controls:Setting x:Uid="AlwaysOnTop_FrameColor" Style="{StaticResource ExpanderContentSettingStyle}" IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.FrameEnabled}" Visibility="{x:Bind Mode=OneWay, Path=ViewModel.FrameAccentColor, Converter={StaticResource FalseToVisibleConverter}}">
<controls:Setting.ActionContent>
<controls:ColorPickerButton SelectedColor="{x:Bind Path=ViewModel.FrameColor, Mode=TwoWay}" />
</controls:Setting.ActionContent>