Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Color picker wpf #37149

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
4 changes: 1 addition & 3 deletions src/modules/colorPicker/ColorPickerUI/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
x:Class="ColorPickerUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
ThemeMode="System"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Dark" />
<ui:ControlsDictionary />
<ResourceDictionary Source="Resources/Styles.xaml" />
<ResourceDictionary Source="Resources/ViewModelViewMappings.xaml" />
</ResourceDictionary.MergedDictionaries>
Expand Down
22 changes: 3 additions & 19 deletions src/modules/colorPicker/ColorPickerUI/ColorEditorWindow.xaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<ui:FluentWindow
<Window
x:Class="ColorPicker.ColorEditorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Expand All @@ -7,16 +7,12 @@
xmlns:e="http://schemas.microsoft.com/xaml/behaviors"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:p="clr-namespace:ColorPicker.Properties"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Width="440"
Height="380"
ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
Title="{x:Static p:Resources.CP_Title}"
AutomationProperties.Name="{x:Static p:Resources.cp_editor}"
ExtendsContentIntoTitleBar="True"
ResizeMode="NoResize"
Topmost="True"
WindowCornerPreference="Default"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<e:Interaction.Behaviors>
Expand All @@ -27,21 +23,9 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ui:TitleBar
x:Name="TitleBar"
Title="{x:Static p:Resources.CP_Title}"
Grid.Row="0"
Height="32"
Padding="16,0,16,0"
ShowMaximize="False"
ShowMinimize="False">
<ui:TitleBar.Icon>
<ui:ImageIcon Source="pack://application:,,,/Assets/ColorPicker/icon.ico" />
</ui:TitleBar.Icon>
</ui:TitleBar>
<ContentPresenter
x:Name="contentPresenter"
Grid.Row="1"
Content="{Binding Content}" />
</Grid>
</ui:FluentWindow>
</Window>
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,22 @@
// See the LICENSE file in the project root for more information.

using System;

using System.Windows;
using ColorPicker.Helpers;
using ManagedCommon;
using Wpf.Ui.Controls;

namespace ColorPicker
{
/// <summary>
/// Interaction logic for ColorEditorWindow.xaml
/// </summary>
public partial class ColorEditorWindow : FluentWindow
public partial class ColorEditorWindow : Window
{
private readonly AppStateHandler _appStateHandler;

public ColorEditorWindow(AppStateHandler appStateHandler)
{
InitializeComponent();
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this);
WindowBackdropType = OSVersionHelper.IsWindows11() ? WindowBackdropType.Mica : WindowBackdropType = WindowBackdropType.None;

_appStateHandler = appStateHandler;
Closing += ColorEditorWindow_Closing;
Expand Down
1 change: 0 additions & 1 deletion src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
<PackageReference Include="System.IO.Abstractions" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" />
<PackageReference Include="System.Drawing.Common" />
<PackageReference Include="WPF-UI" />
</ItemGroup>
<ItemGroup>
<None Update="Properties\Settings.settings">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
xmlns:local="clr-namespace:ColorPicker"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:p="clr-namespace:ColorPicker.Properties"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d">
<UserControl.Resources>
<Style x:Key="ReadonlyTextBoxStyle" TargetType="{x:Type TextBox}">
Expand Down Expand Up @@ -66,7 +65,6 @@
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
IsTabStop="{TemplateBinding ScrollViewer.IsTabStop}"
Style="{StaticResource DefaultTextBoxScrollViewerStyle}"
TextElement.Foreground="{TemplateBinding Foreground}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" />
</Grid>
Expand Down Expand Up @@ -173,7 +171,9 @@
Style="{StaticResource SubtleButtonStyle}"
ToolTipService.ToolTip="{x:Static p:Resources.Copy_to_clipboard}">
<Button.Content>
<ui:SymbolIcon FontSize="20" Symbol="Copy20" />
<TextBlock
FontFamily="{StaticResource IconFontFamily}"
Text="&#xE8C8;" />
</Button.Content>
</Button>
</Grid>
Expand Down
101 changes: 51 additions & 50 deletions src/modules/colorPicker/ColorPickerUI/Controls/ColorPickerControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
xmlns:helpers="clr-namespace:ColorPicker.Helpers"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:p="clr-namespace:ColorPicker.Properties"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
AutomationProperties.Name="{x:Static p:Resources.Color_Palette}"
FocusManager.IsFocusScope="True"
KeyboardNavigation.TabNavigation="Once"
Expand Down Expand Up @@ -213,19 +212,27 @@
Style="{DynamicResource ColorShadeButtonStyle}"
ToolTipService.ToolTip="{x:Static p:Resources.Selected_color_tooltip}">

<ui:Flyout
<Popup
x:Name="DetailsFlyout"
Margin="24,0,0,0"
Closed="DetailsFlyout_Closed"
Opened="DetailsFlyout_Opened"
AllowsTransparency="True"
StaysOpen="False"
Placement="Top">
<Grid x:Name="detailsGrid" KeyboardNavigation.TabNavigation="Contained">
<Grid.ColumnDefinitions>
<Border
CornerRadius="16"
BorderBrush="{DynamicResource SurfaceStrokeColorFlyoutBrush}"
BorderThickness="1"
Background="{DynamicResource ApplicationBackgroundBrush}"
Padding="15">
<Grid x:Name="detailsGrid" KeyboardNavigation.TabNavigation="Contained">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="44" />
<ColumnDefinition Width="86" />
<ColumnDefinition Width="86" />
<ColumnDefinition Width="86" />
</Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
Expand Down Expand Up @@ -317,38 +324,30 @@
Text="RGB"
TextAlignment="Center" />

<ui:NumberBox
x:Name="RNumberBox"
Grid.Row="6"
Grid.Column="1"
AutomationProperties.Name="{x:Static p:Resources.Red_value}"
Maximum="255"
Minimum="0"
SpinButtonPlacementMode="Compact"
TextBoxBase.TextChanged="RGBNumberBox_TextChanged" />

<ui:NumberBox
x:Name="GNumberBox"
Grid.Row="6"
Grid.Column="2"
Margin="4,0,0,0"
AutomationProperties.Name="{x:Static p:Resources.Green_value}"
Maximum="255"
Minimum="0"
SpinButtonPlacementMode="Compact"
TextBoxBase.TextChanged="RGBNumberBox_TextChanged" />

<ui:NumberBox
x:Name="BNumberBox"
Grid.Row="6"
Grid.Column="3"
Margin="4,0,0,0"
AutomationProperties.Name="{x:Static p:Resources.Blue_value}"
Maximum="255"
Minimum="0"
SpinButtonPlacementMode="Compact"
TextBoxBase.TextChanged="RGBNumberBox_TextChanged" />

<TextBox
x:Name="RNumberBox"
Grid.Row="6"
Grid.Column="1"
AutomationProperties.Name="{x:Static p:Resources.Red_value}"
PreviewTextInput="TextBox_PreviewTextInput"
TextBoxBase.TextChanged="RGBNumberBox_TextChanged" />
<TextBox
x:Name="GNumberBox"
Grid.Row="6"
Grid.Column="2"
Margin="4,0,0,0"
AutomationProperties.Name="{x:Static p:Resources.Green_value}"
PreviewTextInput="TextBox_PreviewTextInput"
TextBoxBase.TextChanged="RGBNumberBox_TextChanged" />
<TextBox
x:Name="BNumberBox"
Grid.Row="6"
Grid.Column="3"
Margin="4,0,0,0"
AutomationProperties.Name="{x:Static p:Resources.Blue_value}"
PreviewTextInput="TextBox_PreviewTextInput"
TextBoxBase.TextChanged="RGBNumberBox_TextChanged" />

<TextBlock
Grid.Row="8"
Width="38"
Expand All @@ -369,19 +368,21 @@
MaxLength="7"
TextChanged="HexCode_TextChanged"
TextWrapping="Wrap" />

<ui:Button
x:Name="OKButton"
Grid.Row="9"
Grid.ColumnSpan="4"
Margin="0,32,0,0"
HorizontalAlignment="Stretch"
Appearance="Primary"
AutomationProperties.Name="{x:Static p:Resources.Select}"
Click="OKButton_Click"
Content="{x:Static p:Resources.Select}" />
</Grid>
</ui:Flyout>

<Button
x:Name="OKButton"
Grid.Row="9"
Grid.ColumnSpan="4"
Margin="0,32,0,0"
HorizontalAlignment="Stretch"
Style="{StaticResource CustomAccentButtonStyle}"
AutomationProperties.Name="{x:Static p:Resources.Select}"
Click="OKButton_Click"
Content="{x:Static p:Resources.Select}" />

</Grid>
</Border>
</Popup>
</Button>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

using ColorPicker.Helpers;
using ManagedCommon;
using Wpf.Ui.Controls;

using static System.Net.Mime.MediaTypeNames;

Expand Down Expand Up @@ -76,9 +75,9 @@ private static void SelectedColorPropertyChanged(DependencyObject d, DependencyP
control._ignoreRGBChanges = true;

control.HexCode.Text = ColorToHex(newColor);
control.RNumberBox.Value = newColor.R;
control.GNumberBox.Value = newColor.G;
control.BNumberBox.Value = newColor.B;
control.RNumberBox.Text = newColor.R.ToString(CultureInfo.InvariantCulture);
control.GNumberBox.Text = newColor.G.ToString(CultureInfo.InvariantCulture);
control.BNumberBox.Text = newColor.B.ToString(CultureInfo.InvariantCulture);
control.SetColorFromTextBoxes(System.Drawing.Color.FromArgb(newColor.R, newColor.G, newColor.B));

control._ignoreRGBChanges = false;
Expand Down Expand Up @@ -175,9 +174,9 @@ private void UpdateTextBoxesAndCurrentColor(Color currentColor)

if (!_ignoreRGBChanges)
{
RNumberBox.Value = currentColor.R;
GNumberBox.Value = currentColor.G;
BNumberBox.Value = currentColor.B;
RNumberBox.Text = currentColor.R.ToString(CultureInfo.InvariantCulture);
GNumberBox.Text = currentColor.G.ToString(CultureInfo.InvariantCulture);
BNumberBox.Text = currentColor.B.ToString(CultureInfo.InvariantCulture);
}

_currentColor = currentColor;
Expand Down Expand Up @@ -231,7 +230,7 @@ private void OKButton_Click(object sender, RoutedEventArgs e)
{
SelectedColorChangedCommand.Execute(_currentColor);
SessionEventHelper.Event.EditorColorAdjusted = true;
DetailsFlyout.Hide();
DetailsFlyout.IsOpen = false;
}

private void DetailsFlyout_Closed(object sender, object e)
Expand Down Expand Up @@ -357,15 +356,19 @@ private void HexCode_GotKeyboardFocus(object sender, KeyboardFocusChangedEventAr
(sender as System.Windows.Controls.TextBox).SelectAll();
}

private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
e.Handled = !System.Text.RegularExpressions.Regex.IsMatch(e.Text, "^[0-9]+$");
Copy link
Preview

Copilot AI Feb 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex should allow hexadecimal characters (0-9, a-f, A-F) for color codes. Update the regex to: "^[0-9a-fA-F]+$".

Suggested change
e.Handled = !System.Text.RegularExpressions.Regex.IsMatch(e.Text, "^[0-9]+$");
e.Handled = !System.Text.RegularExpressions.Regex.IsMatch(e.Text, "^[0-9a-fA-F]+$");

Copilot is powered by AI, so mistakes are possible. Review output carefully before use.

Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
}

private void RGBNumberBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (!_ignoreRGBChanges)
{
var numberBox = sender as NumberBox;

byte r = numberBox.Name == "RNumberBox" ? GetValueFromNumberBox(numberBox) : (byte)RNumberBox.Value;
byte g = numberBox.Name == "GNumberBox" ? GetValueFromNumberBox(numberBox) : (byte)GNumberBox.Value;
byte b = numberBox.Name == "BNumberBox" ? GetValueFromNumberBox(numberBox) : (byte)BNumberBox.Value;
var numberBox = sender as TextBox;
byte r = numberBox.Name == "RNumberBox" ? GetValueFromNumberBox(numberBox, _currentColor.R) : _currentColor.R;
byte g = numberBox.Name == "GNumberBox" ? GetValueFromNumberBox(numberBox, _currentColor.G) : _currentColor.G;
byte b = numberBox.Name == "BNumberBox" ? GetValueFromNumberBox(numberBox, _currentColor.B) : _currentColor.B;

_ignoreRGBChanges = true;
SetColorFromTextBoxes(System.Drawing.Color.FromArgb(r, g, b));
Expand All @@ -379,22 +382,24 @@ private void RGBNumberBox_TextChanged(object sender, TextChangedEventArgs e)
/// </summary>
/// <param name="numberBox">numberBox control which value we want to get</param>
/// <returns>Validated value as per numberbox conditions, if content is invalid it returns previous value</returns>
private static byte GetValueFromNumberBox(NumberBox numberBox)
private static byte GetValueFromNumberBox(TextBox numberBox, byte previousValue)
{
int minimum = 0;
int maximum = 255;
double? parsedValue = ParseDouble(numberBox.Text);

if (parsedValue != null)
{
var parsedValueByte = (byte)parsedValue;

if (parsedValueByte >= numberBox.Minimum && parsedValueByte <= numberBox.Maximum)
if (parsedValueByte >= minimum && parsedValueByte <= maximum)
{
return parsedValueByte;
}
}

// not valid input, return previous value
return (byte)numberBox.Value;
return previousValue;
}

public static double? ParseDouble(string text)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,6 @@ private void ShowColorPicker()
Application.Current.MainWindow.Opacity = 0;
Application.Current.MainWindow.Visibility = Visibility.Visible;
_colorPickerShown = true;

// HACK: WPF UI theme watcher removes the composition target background color, among other weird stuff.
// https://github.com/lepoco/wpfui/blob/303f0aefcd59a142bc681415dc4360a34a15f33d/src/Wpf.Ui/Controls/Window/WindowBackdrop.cs#L280
// So we set it back with https://github.com/lepoco/wpfui/blob/303f0aefcd59a142bc681415dc4360a34a15f33d/src/Wpf.Ui/Controls/Window/WindowBackdrop.cs#L191
// And also reapply the intended backdrop.
// This hack fixes: https://github.com/microsoft/PowerToys/issues/31725
Wpf.Ui.Controls.WindowBackdrop.RemoveBackground(Application.Current.MainWindow);
Wpf.Ui.Controls.WindowBackdrop.ApplyBackdrop(Application.Current.MainWindow, Wpf.Ui.Controls.WindowBackdropType.None);
}
}

Expand Down
2 changes: 0 additions & 2 deletions src/modules/colorPicker/ColorPickerUI/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Windows.Interop;

using ColorPicker.ViewModelContracts;
using Wpf.Ui.Controls;

namespace ColorPicker
{
Expand All @@ -20,7 +19,6 @@ public MainWindow()
{
Closing += MainWindow_Closing;
Bootstrapper.InitializeContainer(this);
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this, WindowBackdropType.None);
InitializeComponent();
DataContext = this;
Show(); // Call show just to make sure source is initialized at startup.
Expand Down
Loading