Added pixel reveal effect, increased max zoom level to 4, added rounded corners to main and zoom window (#6242)

This commit is contained in:
martinchrzan
2020-09-03 23:31:27 +02:00
committed by GitHub
parent 288d929477
commit 6e898ae52d
10 changed files with 312 additions and 14 deletions

View File

@@ -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.Windows;
using System.Windows.Interactivity;
using ColorPicker.Shaders;
namespace ColorPicker.Behaviors
{
public class GridEffectBehavior : Behavior<FrameworkElement>
{
private static double baseZoomImageSizeInPx = 50;
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-security#:~:text=Dependency%20properties%20should%20generally%20be%20considered%20to%20be,make%20security%20guarantees%20about%20a%20dependency%20property%20value.")]
public static DependencyProperty EffectProperty = DependencyProperty.Register("Effect", typeof(GridShaderEffect), typeof(GridEffectBehavior));
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-security#:~:text=Dependency%20properties%20should%20generally%20be%20considered%20to%20be,make%20security%20guarantees%20about%20a%20dependency%20property%20value.")]
public static DependencyProperty ZoomFactorProperty = DependencyProperty.Register("ZoomFactor", typeof(double), typeof(GridEffectBehavior));
public GridShaderEffect Effect
{
get { return (GridShaderEffect)GetValue(EffectProperty); }
set { SetValue(EffectProperty, value); }
}
public double ZoomFactor
{
get { return (double)GetValue(ZoomFactorProperty); }
set { SetValue(ZoomFactorProperty, value); }
}
protected override void OnAttached()
{
AssociatedObject.Loaded += AssociatedObject_Loaded;
}
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
AssociatedObject.MouseMove += AssociatedObject_MouseMove;
}
private void AssociatedObject_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
var position = e.GetPosition(AssociatedObject);
var relativeX = position.X / AssociatedObject.ActualWidth;
var relativeY = position.Y / AssociatedObject.Height;
Effect.MousePosition = new Point(relativeX, relativeY);
if (ZoomFactor >= 4)
{
Effect.Radius = 0.04;
Effect.SquareSize = ZoomFactor;
Effect.TextureSize = baseZoomImageSizeInPx * ZoomFactor;
}
else
{
// don't show grid, too small pixels
Effect.Radius = 0.0;
Effect.SquareSize = 0;
Effect.TextureSize = 0;
}
}
}
}

View File

@@ -81,7 +81,6 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
@@ -107,11 +106,14 @@
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Compile Include="Behaviors\GridEffectBehavior.cs" />
<Compile Include="Helpers\IThrottledActionInvoker.cs" />
<Compile Include="Helpers\ThrottledActionInvoker.cs" />
<Compile Include="Settings\IUserSettings.cs" />
<Compile Include="Settings\SettingItem`1.cs" />
<Compile Include="Settings\UserSettings.cs" />
<Compile Include="Shaders\Global.cs" />
<Compile Include="Shaders\GridShaderEffect.cs" />
<Compile Include="Telemetry\ColorPickerCancelledEvent.cs" />
<Compile Include="Telemetry\ColorPickerShowEvent.cs" />
<Compile Include="Telemetry\ColorPickerZoomOpenedEvent.cs" />
@@ -208,6 +210,7 @@
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Resource Include="Shaders\GridShader.cso" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
@@ -254,5 +257,8 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Content Include="Shaders\GridShader.fx" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -21,7 +21,7 @@ namespace ColorPicker.Helpers
private const int ZoomWindowChangeDelayInMS = 50;
private const int ZoomFactor = 2;
private const int BaseZoomImageSize = 50;
private const int MaxZoomLevel = 3;
private const int MaxZoomLevel = 4;
private const int MinZoomLevel = 0;
private readonly IZoomViewModel _zoomViewModel;

View File

@@ -0,0 +1,39 @@
// 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;
namespace ColorPicker.Shaders
{
internal static class Global
{
/// <summary>
/// Helper method for generating a "pack://" URI for a given relative file based on the
/// assembly that this class is in.
/// </summary>
public static Uri MakePackUri(string relativeFile)
{
string uriString = "pack://application:,,,/" + AssemblyShortName + ";component/Shaders/" + relativeFile;
return new Uri(uriString);
}
private static string AssemblyShortName
{
get
{
if (_assemblyShortName == null)
{
var assembly = typeof(Global).Assembly;
// Pull out the short name.
_assemblyShortName = assembly.ToString().Split(',')[0];
}
return _assemblyShortName;
}
}
private static string _assemblyShortName;
}
}

View File

@@ -0,0 +1,81 @@
float2 mousePosition : register(C1);
float radius : register(C2);
float squareSize : register(c3);
float textureSize : register(c4);
sampler2D inputSampler : register(S0);
float4 main(float2 uv : TEXCOORD) : COLOR
{
// do not draw grid where the mouse is
if (uv.x == mousePosition.y && uv.y == mousePosition.y)
{
return tex2D(inputSampler, uv);
}
float gridColor = 1.0f;
float mainRectangleColor = 1.0f;
float4 originalColor = tex2D(inputSampler, uv);
float4 colorAtMousePosition = tex2D(inputSampler, mousePosition);
if (originalColor.r > 0.8 && originalColor.g > 0.8 && originalColor.b > 0.8)
{
gridColor = 0.0f;
}
if (colorAtMousePosition.r > 0.8 && colorAtMousePosition.g > 0.8 && colorAtMousePosition.b > 0.8)
{
mainRectangleColor = 0.0f;
}
float4 color = tex2D(inputSampler, uv);
float distanceFromMouse = length(mousePosition - uv);
float distanceFactor;
int pixelPositionX = textureSize * uv.x;
int pixelPositionY = textureSize * uv.y;
int mousePositionX = mousePosition.x * textureSize;
int mousePositionY = mousePosition.y * textureSize;
int2 topLeftRectangle = int2(mousePositionX - (mousePositionX % squareSize) - 1, mousePositionY - (mousePositionY % squareSize) - 1);
// do not draw grid inside square even when grid (avoid drawing grid in that area later
if (((pixelPositionX >= topLeftRectangle.x + 1 && pixelPositionX <= topLeftRectangle.x + squareSize) && (pixelPositionY == topLeftRectangle.y + 1 || pixelPositionY == topLeftRectangle.y + squareSize)) ||
((pixelPositionY >= topLeftRectangle.y + 1 && pixelPositionY <= topLeftRectangle.y + squareSize) && (pixelPositionX == topLeftRectangle.x + 1 || pixelPositionX == topLeftRectangle.x + squareSize)))
{
return originalColor;
}
if (distanceFromMouse <= radius)
{
// draw grid
if (pixelPositionX % squareSize == 0 || pixelPositionY % squareSize == 0)
{
if (gridColor == 1.0f)
{
color.r = color.r + ((1.0 - color.r) * (1.0 - (distanceFromMouse / radius)));
color.g = color.g + ((1.0 - color.g) * (1.0 - (distanceFromMouse / radius)));
color.b = color.b + ((1.0 - color.b) * (1.0 - (distanceFromMouse / radius)));
}
else
{
color.r = color.r * (distanceFromMouse / radius);
color.g = color.g * (distanceFromMouse / radius);
color.b = color.b * (distanceFromMouse / radius);
}
}
}
if (((pixelPositionX >= topLeftRectangle.x && pixelPositionX <= topLeftRectangle.x + squareSize + 2) && (pixelPositionY == topLeftRectangle.y || pixelPositionY == topLeftRectangle.y + squareSize + 2)) ||
((pixelPositionY >= topLeftRectangle.y && pixelPositionY <= topLeftRectangle.y + squareSize + 2) && (pixelPositionX == topLeftRectangle.x || pixelPositionX == topLeftRectangle.x + squareSize + 2)))
{
originalColor.r = mainRectangleColor;
originalColor.g = mainRectangleColor;
originalColor.b = mainRectangleColor;
return originalColor;
}
return color;
}

View File

@@ -0,0 +1,101 @@
// 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;
using System.Windows.Media;
using System.Windows.Media.Effects;
namespace ColorPicker.Shaders
{
public class GridShaderEffect : ShaderEffect
{
private static readonly PixelShader Shader =
new PixelShader()
{
UriSource = Global.MakePackUri("GridShader.cso"),
};
public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(GridShaderEffect), 0);
public static readonly DependencyProperty MousePositionProperty = DependencyProperty.Register("MousePosition", typeof(Point), typeof(GridShaderEffect), new UIPropertyMetadata(new Point(0D, 0D), PixelShaderConstantCallback(1)));
public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double), typeof(GridShaderEffect), new UIPropertyMetadata((double)0D, PixelShaderConstantCallback(2)));
public static readonly DependencyProperty SquareSizeProperty = DependencyProperty.Register("SquareSize", typeof(double), typeof(GridShaderEffect), new UIPropertyMetadata((double)0D, PixelShaderConstantCallback(3)));
public static readonly DependencyProperty TextureSizeProperty = DependencyProperty.Register("TextureSize", typeof(double), typeof(GridShaderEffect), new UIPropertyMetadata((double)0D, PixelShaderConstantCallback(4)));
public GridShaderEffect()
{
PixelShader = Shader;
UpdateShaderValue(InputProperty);
UpdateShaderValue(MousePositionProperty);
UpdateShaderValue(RadiusProperty);
UpdateShaderValue(SquareSizeProperty);
UpdateShaderValue(TextureSizeProperty);
}
public Brush Input
{
get
{
return (Brush)GetValue(InputProperty);
}
set
{
SetValue(InputProperty, value);
}
}
public Point MousePosition
{
get
{
return (Point)GetValue(MousePositionProperty);
}
set
{
SetValue(MousePositionProperty, value);
}
}
public double Radius
{
get
{
return (double)GetValue(RadiusProperty);
}
set
{
SetValue(RadiusProperty, value);
}
}
public double SquareSize
{
get
{
return (double)GetValue(SquareSizeProperty);
}
set
{
SetValue(SquareSizeProperty, value);
}
}
public double TextureSize
{
get
{
return (double)GetValue(TextureSizeProperty);
}
set
{
SetValue(TextureSizeProperty, value);
}
}
}
}

View File

@@ -20,13 +20,12 @@
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.RowSpan="2" Grid.ColumnSpan="2" Grid.Column="1" Background="#202020" BorderThickness="1" BorderBrush="Black" />
<Border Background="{Binding ColorBrush}" BorderBrush="Black" Grid.Column="1" BorderThickness="1" Grid.RowSpan="2" x:Name="ColorBorder"/>
<Border BorderBrush="#505050" Grid.Column="2" Margin="0,1,1,1" Grid.RowSpan="2" BorderThickness="3,0,3,0" Background="#202020" CornerRadius="0" />
<Border Background="{Binding ColorBrush}" BorderBrush="Black" Grid.Column="1" BorderThickness="1" Grid.RowSpan="2" x:Name="ColorBorder" CornerRadius="2,0,0,2"/>
<Border Grid.RowSpan="2" Grid.ColumnSpan="2" Grid.Column="1" Background="Transparent" BorderThickness="1" BorderBrush="Black" CornerRadius="2"/>
<TextBlock Margin="7,5,5,5" Foreground="White" Grid.Row="0" Grid.Column="2" Text="{Binding HexColor}"/>
<TextBlock Margin="7,0,0,0" Foreground="White" Grid.Row="1" Grid.Column="2" Text="{Binding RgbColor}"/>
<Border BorderBrush="#505050" Grid.Column="2" Margin="0,1,1,1" Grid.RowSpan="2" BorderThickness="3,0,3,0" />
</Grid>
</Grid>
</UserControl>

View File

@@ -5,12 +5,20 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ColorPicker.Views"
mc:Ignorable="d"
xmlns:shaders="clr-namespace:ColorPicker.Shaders"
xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behaviors="clr-namespace:ColorPicker.Behaviors"
d:DesignHeight="450" d:DesignWidth="800" BorderBrush="Black" BorderThickness="2" Focusable="False">
<Image Source="{Binding ZoomArea}" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Fill" Width="{Binding Width, Mode=TwoWay}" Height="{Binding Height, Mode=TwoWay}">
<e:Interaction.Behaviors>
<behaviors:ResizeBehavior Width="{Binding DesiredWidth}" Height="{Binding DesiredHeight}"/>
</e:Interaction.Behaviors>
</Image>
d:DesignHeight="450" d:DesignWidth="800" Background="Transparent" Focusable="False">
<Border BorderBrush="#FF2B2B2B" ClipToBounds="True" BorderThickness="2" CornerRadius="2">
<Image Source="{Binding ZoomArea}" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Fill" Width="{Binding Width, Mode=TwoWay}" Height="{Binding Height, Mode=TwoWay}">
<e:Interaction.Behaviors>
<behaviors:ResizeBehavior Width="{Binding DesiredWidth}" Height="{Binding DesiredHeight}"/>
<behaviors:GridEffectBehavior Effect="{Binding ElementName=gridEffect}" ZoomFactor="{Binding ZoomFactor}"/>
</e:Interaction.Behaviors>
<Image.Effect>
<shaders:GridShaderEffect x:Name="gridEffect"/>
</Image.Effect>
</Image>
</Border>
</UserControl>

View File

@@ -7,7 +7,7 @@
xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behaviors="clr-namespace:ColorPicker.Behaviors"
mc:Ignorable="d"
Title="Zoom window" WindowStyle="None" SizeToContent="WidthAndHeight" Topmost="True" ShowInTaskbar="False" ResizeMode="NoResize" Focusable="False">
Title="Zoom window" WindowStyle="None" SizeToContent="WidthAndHeight" Topmost="True" AllowsTransparency="True" Background="Transparent" ShowInTaskbar="False" ResizeMode="NoResize" Focusable="False">
<e:Interaction.Behaviors>
<behaviors:CloseZoomWindowBehavior/>
<behaviors:MoveWindowBehavior Left="{Binding DesiredLeft, Mode=TwoWay}" Top="{Binding DesiredTop}"/>