mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 09:46:54 +02:00
always on top accent color borders (#15709)
This commit is contained in:
committed by
GitHub
parent
2ccf492707
commit
2182aabe35
@@ -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;
|
||||
|
||||
@@ -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 (...)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -8,5 +8,6 @@ enum class SettingId
|
||||
FrameThickness,
|
||||
FrameColor,
|
||||
BlockInGameMode,
|
||||
ExcludeApps
|
||||
ExcludeApps,
|
||||
FrameAccentColor
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 & behavior</value>
|
||||
<value>Appearance & 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>
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user