Browse Source

Reference layer color picker support and UI improvements

Equbuxu 2 years ago
parent
commit
04aa35b1ed

+ 10 - 5
src/ChunkyImageLibTest/RectITests.cs

@@ -30,7 +30,8 @@ public class RectITests
     public void FromTwoPoints_DiagonalsCombinations_ReturnsStandardizedRects()
     public void FromTwoPoints_DiagonalsCombinations_ReturnsStandardizedRects()
     {
     {
         RectI refR = new RectI(3, 4, 8 - 3, 9 - 4);
         RectI refR = new RectI(3, 4, 8 - 3, 9 - 4);
-        Span<RectI> rects = stackalloc RectI[] {
+        Span<RectI> rects = stackalloc RectI[] 
+        {
             RectI.FromTwoPoints(new VecI(3, 4), new VecI(8, 9)),
             RectI.FromTwoPoints(new VecI(3, 4), new VecI(8, 9)),
             RectI.FromTwoPoints(new VecI(8, 9), new VecI(3, 4)),
             RectI.FromTwoPoints(new VecI(8, 9), new VecI(3, 4)),
             RectI.FromTwoPoints(new VecI(8, 9), new VecI(3, 4)),
             RectI.FromTwoPoints(new VecI(8, 9), new VecI(3, 4)),
@@ -241,7 +242,8 @@ public class RectITests
     public void IntersectsWithInclusive_BasicRects_ReturnsTrue()
     public void IntersectsWithInclusive_BasicRects_ReturnsTrue()
     {
     {
         RectI rect = new RectI(960, 540, 1920, 1080);
         RectI rect = new RectI(960, 540, 1920, 1080);
-        Span<RectI> rects = stackalloc RectI[] {
+        Span<RectI> rects = stackalloc RectI[] 
+        {
             rect.Offset(1920, 1080),
             rect.Offset(1920, 1080),
             rect.Offset(-1920, 0).Inflate(-1).Offset(1, 0),
             rect.Offset(-1920, 0).Inflate(-1).Offset(1, 0),
             rect.Offset(0, 1080).Inflate(-1).Offset(0, -1),
             rect.Offset(0, 1080).Inflate(-1).Offset(0, -1),
@@ -256,7 +258,8 @@ public class RectITests
     public void IntersectsWithInclusive_BasicRects_ReturnsFalse()
     public void IntersectsWithInclusive_BasicRects_ReturnsFalse()
     {
     {
         RectI rect = new RectI(960, 540, 1920, 1080);
         RectI rect = new RectI(960, 540, 1920, 1080);
-        Span<RectI> rects = stackalloc RectI[] {
+        Span<RectI> rects = stackalloc RectI[] 
+        {
             rect.Offset(1921, 1080),
             rect.Offset(1921, 1080),
             rect.Offset(-1921, 0).Inflate(-1).Offset(1, 0),
             rect.Offset(-1921, 0).Inflate(-1).Offset(1, 0),
             rect.Offset(0, 1081).Inflate(-1).Offset(0, -1)
             rect.Offset(0, 1081).Inflate(-1).Offset(0, -1)
@@ -269,7 +272,8 @@ public class RectITests
     public void IntersectsWithExclusive_BasicRects_ReturnsTrue()
     public void IntersectsWithExclusive_BasicRects_ReturnsTrue()
     {
     {
         RectI rect = new RectI(960, 540, 1920, 1080);
         RectI rect = new RectI(960, 540, 1920, 1080);
-        Span<RectI> rects = stackalloc RectI[] {
+        Span<RectI> rects = stackalloc RectI[] 
+        {
             rect.Offset(1920 - 1, 1080 - 1),
             rect.Offset(1920 - 1, 1080 - 1),
             rect.Offset(-1920, 0).Inflate(-1).Offset(2, 0),
             rect.Offset(-1920, 0).Inflate(-1).Offset(2, 0),
             rect.Offset(0, 1080).Inflate(-1).Offset(0, -2),
             rect.Offset(0, 1080).Inflate(-1).Offset(0, -2),
@@ -284,7 +288,8 @@ public class RectITests
     public void IntersectsWithExclusive_BasicRects_ReturnsFalse()
     public void IntersectsWithExclusive_BasicRects_ReturnsFalse()
     {
     {
         RectI rect = new RectI(960, 540, 1920, 1080);
         RectI rect = new RectI(960, 540, 1920, 1080);
-        Span<RectI> rects = stackalloc RectI[] {
+        Span<RectI> rects = stackalloc RectI[] 
+        {
             rect.Offset(1920, 1080),
             rect.Offset(1920, 1080),
             rect.Offset(-1920, 0).Inflate(-1).Offset(1, 0),
             rect.Offset(-1920, 0).Inflate(-1).Offset(1, 0),
             rect.Offset(0, 1080).Inflate(-1).Offset(0, -1),
             rect.Offset(0, 1080).Inflate(-1).Offset(0, -1),

+ 1 - 0
src/Custom.ruleset

@@ -28,6 +28,7 @@
     <Rule Id="SA1112" Action="None" />
     <Rule Id="SA1112" Action="None" />
     <Rule Id="SA1117" Action="None" />
     <Rule Id="SA1117" Action="None" />
     <Rule Id="SA1119" Action="None" />
     <Rule Id="SA1119" Action="None" />
+    <Rule Id="SA1121" Action="None" />
     <Rule Id="SA1122" Action="None" />
     <Rule Id="SA1122" Action="None" />
     <Rule Id="SA1124" Action="None" />
     <Rule Id="SA1124" Action="None" />
     <Rule Id="SA1127" Action="None" />
     <Rule Id="SA1127" Action="None" />

+ 4 - 4
src/PixiEditor.ChangeableDocument.Gen/Helpers.cs

@@ -6,7 +6,7 @@ namespace PixiEditor.ChangeableDocument.Gen;
 
 
 internal static class Helpers
 internal static class Helpers
 {
 {
-    private static SymbolDisplayFormat TypeWithGenerics =
+    private static SymbolDisplayFormat typeWithGenerics =
         new SymbolDisplayFormat(genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints);
         new SymbolDisplayFormat(genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints);
     public static string CreateMakeChangeAction(MethodInfo changeConstructorInfo)
     public static string CreateMakeChangeAction(MethodInfo changeConstructorInfo)
     {
     {
@@ -77,8 +77,8 @@ bool PixiEditor.ChangeableDocument.Actions.IStartOrUpdateChangeAction.IsChangeTy
     public static string CreateEndChangeAction(MethodInfo changeConstructorInfo)
     public static string CreateEndChangeAction(MethodInfo changeConstructorInfo)
     {
     {
         string actionName = "End" + changeConstructorInfo.ContainingClass.Name.Split('_')[0] + "_Action";
         string actionName = "End" + changeConstructorInfo.ContainingClass.Name.Split('_')[0] + "_Action";
-        return $@"
-namespace PixiEditor.ChangeableDocument.Actions.Generated;
+        return 
+$@"namespace PixiEditor.ChangeableDocument.Actions.Generated;
 
 
 public record class {actionName} : PixiEditor.ChangeableDocument.Actions.IEndChangeAction
 public record class {actionName} : PixiEditor.ChangeableDocument.Actions.IEndChangeAction
 {{
 {{
@@ -95,7 +95,7 @@ public record class {actionName} : PixiEditor.ChangeableDocument.Actions.IEndCha
         List<TypeWithName> variables = method.Parameters.Select(static parameter =>
         List<TypeWithName> variables = method.Parameters.Select(static parameter =>
         {
         {
             return new TypeWithName(
             return new TypeWithName(
-                parameter.Type.ToDisplayString(TypeWithGenerics),
+                parameter.Type.ToDisplayString(typeWithGenerics),
                 parameter.Type.ContainingNamespace.ToDisplayString(),
                 parameter.Type.ContainingNamespace.ToDisplayString(),
                 parameter.Name,
                 parameter.Name,
                 parameter.NullableAnnotation is NullableAnnotation.Annotated
                 parameter.NullableAnnotation is NullableAnnotation.Annotated

+ 10 - 4
src/PixiEditor.ChangeableDocument.Gen/UpdateableChangeActionGenerator.cs

@@ -9,8 +9,8 @@ public class UpdateableChangeActionGenerator : IIncrementalGenerator
     private const string AttributesNamespace = "PixiEditor.ChangeableDocument.Actions.Attributes";
     private const string AttributesNamespace = "PixiEditor.ChangeableDocument.Actions.Attributes";
     private const string ConstructorAttribute = "GenerateUpdateableChangeActionsAttribute";
     private const string ConstructorAttribute = "GenerateUpdateableChangeActionsAttribute";
     private const string UpdateMethodAttribute = "UpdateChangeMethodAttribute";
     private const string UpdateMethodAttribute = "UpdateChangeMethodAttribute";
-    private static NamespacedType ConstructorAttributeType = new NamespacedType(ConstructorAttribute, AttributesNamespace);
-    private static NamespacedType UpdateMethodAttributeType = new NamespacedType(UpdateMethodAttribute, AttributesNamespace);
+    private static NamespacedType constructorAttributeType = new NamespacedType(ConstructorAttribute, AttributesNamespace);
+    private static NamespacedType updateMethodAttributeType = new NamespacedType(UpdateMethodAttribute, AttributesNamespace);
 
 
     private static Result<(IMethodSymbol, IMethodSymbol, ClassDeclarationSyntax)>? TransformSyntax
     private static Result<(IMethodSymbol, IMethodSymbol, ClassDeclarationSyntax)>? TransformSyntax
         (GeneratorSyntaxContext context, CancellationToken cancelToken)
         (GeneratorSyntaxContext context, CancellationToken cancelToken)
@@ -20,7 +20,7 @@ public class UpdateableChangeActionGenerator : IIncrementalGenerator
         // make sure we are actually working with a constructor
         // make sure we are actually working with a constructor
         if (context.Node is ConstructorDeclarationSyntax constructor)
         if (context.Node is ConstructorDeclarationSyntax constructor)
         {
         {
-            if (!Helpers.MethodHasAttribute(context, cancelToken, constructor, ConstructorAttributeType))
+            if (!Helpers.MethodHasAttribute(context, cancelToken, constructor, constructorAttributeType))
                 return null;
                 return null;
             containingClass = (ClassDeclarationSyntax)constructor.Parent!;
             containingClass = (ClassDeclarationSyntax)constructor.Parent!;
             constructorSyntax = constructor;
             constructorSyntax = constructor;
@@ -42,13 +42,15 @@ public class UpdateableChangeActionGenerator : IIncrementalGenerator
         var members = containingClass.Members.Where(node => node is MethodDeclarationSyntax).ToList();
         var members = containingClass.Members.Where(node => node is MethodDeclarationSyntax).ToList();
         const string errorMessage = $"Update method isn't marked with {UpdateMethodAttribute}";
         const string errorMessage = $"Update method isn't marked with {UpdateMethodAttribute}";
         if (!members.Any())
         if (!members.Any())
+        {
             return Result<(IMethodSymbol, IMethodSymbol, ClassDeclarationSyntax)>.Error
             return Result<(IMethodSymbol, IMethodSymbol, ClassDeclarationSyntax)>.Error
                 (errorMessage, containingClass.SyntaxTree, containingClass.Span);
                 (errorMessage, containingClass.SyntaxTree, containingClass.Span);
+        }
         foreach (var member in members)
         foreach (var member in members)
         {
         {
             cancelToken.ThrowIfCancellationRequested();
             cancelToken.ThrowIfCancellationRequested();
             var method = (MethodDeclarationSyntax)member;
             var method = (MethodDeclarationSyntax)member;
-            bool hasAttr = Helpers.MethodHasAttribute(context, cancelToken, method, UpdateMethodAttributeType);
+            bool hasAttr = Helpers.MethodHasAttribute(context, cancelToken, method, updateMethodAttributeType);
             if (hasAttr)
             if (hasAttr)
             {
             {
                 methodSyntax = method;
                 methodSyntax = method;
@@ -73,8 +75,10 @@ public class UpdateableChangeActionGenerator : IIncrementalGenerator
         (Result<(IMethodSymbol, IMethodSymbol, ClassDeclarationSyntax)>? prevResult, CancellationToken cancelToken)
         (Result<(IMethodSymbol, IMethodSymbol, ClassDeclarationSyntax)>? prevResult, CancellationToken cancelToken)
     {
     {
         if (prevResult!.Value.ErrorText is not null)
         if (prevResult!.Value.ErrorText is not null)
+        {
             return Result<(NamedSourceCode, NamedSourceCode)>.Error
             return Result<(NamedSourceCode, NamedSourceCode)>.Error
                 (prevResult.Value.ErrorText, prevResult.Value.SyntaxTree!, (TextSpan)prevResult.Value.Span!);
                 (prevResult.Value.ErrorText, prevResult.Value.SyntaxTree!, (TextSpan)prevResult.Value.Span!);
+        }
         var (constructor, update, containingClass) = prevResult.Value.Value;
         var (constructor, update, containingClass) = prevResult.Value.Value;
 
 
         var constructorInfo = Helpers.ExtractMethodInfo(constructor!);
         var constructorInfo = Helpers.ExtractMethodInfo(constructor!);
@@ -82,8 +86,10 @@ public class UpdateableChangeActionGenerator : IIncrementalGenerator
 
 
         var maybeStartUpdateAction = Helpers.CreateStartUpdateChangeAction(constructorInfo, updateInfo, containingClass);
         var maybeStartUpdateAction = Helpers.CreateStartUpdateChangeAction(constructorInfo, updateInfo, containingClass);
         if (maybeStartUpdateAction.ErrorText is not null)
         if (maybeStartUpdateAction.ErrorText is not null)
+        {
             return Result<(NamedSourceCode, NamedSourceCode)>.Error
             return Result<(NamedSourceCode, NamedSourceCode)>.Error
                 (maybeStartUpdateAction.ErrorText, maybeStartUpdateAction.SyntaxTree!, (TextSpan)maybeStartUpdateAction.Span!);
                 (maybeStartUpdateAction.ErrorText, maybeStartUpdateAction.SyntaxTree!, (TextSpan)maybeStartUpdateAction.Span!);
+        }
 
 
         var endAction = Helpers.CreateEndChangeAction(constructorInfo);
         var endAction = Helpers.CreateEndChangeAction(constructorInfo);
 
 

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/IChangeable.cs

@@ -3,4 +3,4 @@
 internal interface IChangeable
 internal interface IChangeable
 {
 {
 
 
-};
+}

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyDocument.cs

@@ -4,7 +4,8 @@ using PixiEditor.DrawingApi.Core.Numerics;
 namespace PixiEditor.ChangeableDocument.Changeables.Interfaces;
 namespace PixiEditor.ChangeableDocument.Changeables.Interfaces;
 
 
 public interface IReadOnlyDocument
 public interface IReadOnlyDocument
-{    /// <summary>
+{    
+    /// <summary>
     /// The root folder of the document
     /// The root folder of the document
     /// </summary>
     /// </summary>
     IReadOnlyFolder StructureRoot { get; }
     IReadOnlyFolder StructureRoot { get; }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changes/Change.cs

@@ -32,4 +32,4 @@ internal abstract class Change : IDisposable
     public abstract OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target);
     public abstract OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target);
 
 
     public virtual void Dispose() { }
     public virtual void Dispose() { }
-};
+}

+ 18 - 0
src/PixiEditor/Helpers/Converters/BoolToHiddenVisibilityConverter.cs

@@ -0,0 +1,18 @@
+using System.Globalization;
+using System.Windows;
+
+namespace PixiEditor.Helpers.Converters;
+
+internal class BoolToHiddenVisibilityConverter : SingleInstanceConverter<BoolToHiddenVisibilityConverter>
+{
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        bool boolean = (bool)value;
+        return boolean ? Visibility.Visible : Visibility.Hidden;
+    }
+
+    public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        throw new NotImplementedException();
+    }
+}

+ 14 - 0
src/PixiEditor/Helpers/Extensions/ColorHelpers.cs

@@ -10,4 +10,18 @@ internal static class ColorHelpers
 
 
     public static Color ToOpaqueMediaColor(this BackendColor color) => Color.FromRgb(color.R, color.G, color.B);
     public static Color ToOpaqueMediaColor(this BackendColor color) => Color.FromRgb(color.R, color.G, color.B);
     public static Color ToColor(this BackendColor color) => Color.FromArgb(color.A, color.R, color.G, color.B);
     public static Color ToColor(this BackendColor color) => Color.FromArgb(color.A, color.R, color.G, color.B);
+    
+    public static BackendColor BlendColors(BackendColor bottomColor, BackendColor topColor)
+    {
+        if (topColor.A is < 255 and > 0)
+        {
+            byte r = (byte)((topColor.R * topColor.A / 255) + (bottomColor.R * bottomColor.A * (255 - topColor.A) / (255 * 255)));
+            byte g = (byte)((topColor.G * topColor.A / 255) + (bottomColor.G * bottomColor.A * (255 - topColor.A) / (255 * 255)));
+            byte b = (byte)((topColor.B * topColor.A / 255) + (bottomColor.B * bottomColor.A * (255 - topColor.A) / (255 * 255)));
+            byte a = (byte)(topColor.A + (bottomColor.A * (255 - topColor.A) / 255));
+            return new BackendColor(r, g, b, a);
+        }
+
+        return topColor.A == 255 ? topColor : bottomColor;
+    }
 }
 }

+ 30 - 7
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ColorPickerToolExecutor.cs

@@ -1,22 +1,45 @@
-using PixiEditor.Models.Enums;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.Models.Enums;
+using PixiEditor.ViewModels.SubViewModels.Tools.Tools;
 
 
 namespace PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 namespace PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 
 
+#nullable enable
 internal class ColorPickerToolExecutor : UpdateableChangeExecutor
 internal class ColorPickerToolExecutor : UpdateableChangeExecutor
 {
 {
+    private bool includeReference;
+    private bool includeCanvas;
+    private DocumentScope scope;
+    private ColorsViewModel? colorsViewModel;
+
     public override ExecutionState Start()
     public override ExecutionState Start()
     {
     {
-        ColorsViewModel colorsViewModel = ViewModelMain.Current?.ColorsSubViewModel;
-        
-        if(document is null || controller is null)
-        {
+        colorsViewModel = ViewModelMain.Current?.ColorsSubViewModel;
+        ColorPickerToolViewModel? tool = ViewModelMain.Current?.ToolsSubViewModel.GetTool<ColorPickerToolViewModel>();
+
+        if (colorsViewModel is null || tool is null)
             return ExecutionState.Error;
             return ExecutionState.Error;
-        }
+
+        scope = tool.Mode;
+        includeReference = tool.PickFromReferenceLayer && document!.ReferenceLayerViewModel.ReferenceBitmap is not null;
+        includeCanvas = tool.PickFromCanvas;
         
         
-        colorsViewModel.PrimaryColor = document.PickColor(controller.LastPixelPosition, false);
+        colorsViewModel.PrimaryColor = document.PickColor(controller.LastPrecisePosition, scope, includeReference, includeCanvas);
         return ExecutionState.Success;
         return ExecutionState.Success;
     }
     }
 
 
+    public override void OnPrecisePositionChange(VecD pos)
+    {
+        if (!includeReference)
+            return;
+        colorsViewModel.PrimaryColor = document.PickColor(pos, scope, includeReference, includeCanvas);
+    }
+
+    public override void OnPixelPositionChange(VecI pos)
+    {
+        colorsViewModel.PrimaryColor = document.PickColor(pos, scope, includeReference, includeCanvas);
+    }
+
     public override void OnLeftMouseButtonUp()
     public override void OnLeftMouseButtonUp()
     {
     {
         onEnded?.Invoke(this);
         onEnded?.Invoke(this);

+ 40 - 4
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs

@@ -1,5 +1,5 @@
-using System.Collections.Immutable;
-using System.IO;
+using System.IO;
+using System.Windows;
 using System.Windows.Media;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Media.Imaging;
 using ChunkyImageLib;
 using ChunkyImageLib;
@@ -19,6 +19,7 @@ using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels.Public;
 using PixiEditor.Models.DocumentModels.Public;
+using PixiEditor.Models.Enums;
 using PixiEditor.Views.UserControls.SymmetryOverlay;
 using PixiEditor.Views.UserControls.SymmetryOverlay;
 using Color = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 using Color = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 using Colors = PixiEditor.DrawingApi.Core.ColorsImpl.Colors;
 using Colors = PixiEditor.DrawingApi.Core.ColorsImpl.Colors;
@@ -319,14 +320,49 @@ internal partial class DocumentViewModel : NotifyableObject
         return (output, bounds);
         return (output, bounds);
     }
     }
 
 
-    public Color PickColor(VecI pos, bool fromAllLayers)
+    public Color PickColor(VecD pos, DocumentScope scope, bool includeReference, bool includeCanvas)
+    {
+        if (scope == DocumentScope.SingleLayer && includeReference && includeCanvas)
+            includeReference = false;
+        
+        if (includeCanvas && includeReference)
+        {
+            Color canvasColor = PickColorFromCanvas((VecI)pos, scope);
+            Color? referenceColor = PickColorFromReferenceLayer(pos);
+            if (referenceColor is null)
+                return canvasColor;
+            return ColorHelpers.BlendColors((Color)referenceColor, canvasColor);
+        }
+        if (includeCanvas)
+            return PickColorFromCanvas((VecI)pos, scope);
+        if (includeReference)
+            return PickColorFromReferenceLayer(pos) ?? Colors.Transparent;
+        return Colors.Transparent;
+    }
+
+    public Color? PickColorFromReferenceLayer(VecD pos)
+    {
+        WriteableBitmap? bitmap = ReferenceLayerViewModel.ReferenceBitmap; 
+        if (bitmap is null)
+            return null;
+        
+        Matrix matrix = ReferenceLayerViewModel.ReferenceTransformMatrix;
+        matrix.Invert();
+        var transformed = matrix.Transform(new System.Windows.Point(pos.X, pos.Y));
+
+        if (transformed.X < 0 || transformed.Y < 0 || transformed.X >= bitmap.Width || transformed.Y >= bitmap.Height)
+            return null;
+        return bitmap.GetPixel((int)transformed.X, (int)transformed.Y).ToColor();
+    }
+
+    public Color PickColorFromCanvas(VecI pos, DocumentScope scope)
     {
     {
         // there is a tiny chance that the image might get disposed by another thread
         // there is a tiny chance that the image might get disposed by another thread
         try
         try
         {
         {
             // it might've been a better idea to implement this function asynchronously
             // it might've been a better idea to implement this function asynchronously
             // via a passthrough action to avoid all the try catches
             // via a passthrough action to avoid all the try catches
-            if (fromAllLayers)
+            if (scope == DocumentScope.AllLayers)
             {
             {
                 VecI chunkPos = OperationHelper.GetChunkPos(pos, ChunkyImage.FullChunkSize);
                 VecI chunkPos = OperationHelper.GetChunkPos(pos, ChunkyImage.FullChunkSize);
                 return ChunkRenderer.MergeWholeStructure(chunkPos, ChunkResolution.Full, Internals.Tracker.Document.StructureRoot)
                 return ChunkRenderer.MergeWholeStructure(chunkPos, ChunkResolution.Full, Internals.Tracker.Document.StructureRoot)

+ 7 - 6
src/PixiEditor/ViewModels/SubViewModels/Tools/ToolSettings/Settings/EnumSetting.cs

@@ -31,16 +31,17 @@ internal sealed class EnumSetting<TEnum> : Setting<TEnum, ComboBox>
     /// </summary>
     /// </summary>
     public override TEnum Value
     public override TEnum Value
     {
     {
-        get => (TEnum)(SettingControl.SelectedItem as ComboBoxItem).Tag;
+        get => Enum.GetValues<TEnum>()[SelectedIndex];
         set
         set
         {
         {
-            for (var i = 0; i < SettingControl.Items.Count; i++)
-            {
-                var item = SettingControl.Items[i] as ComboBoxItem;
+            var values = Enum.GetValues<TEnum>();
 
 
-                if (item.Tag.Equals(value))
+            for (var i = 0; i < values.Length; i++)
+            {
+                if (values[i].Equals(value))
                 {
                 {
                     SelectedIndex = i;
                     SelectedIndex = i;
+                    break;
                 }
                 }
             }
             }
 
 
@@ -62,7 +63,7 @@ internal sealed class EnumSetting<TEnum> : Setting<TEnum, ComboBox>
     public EnumSetting(string name, string label, TEnum defaultValue)
     public EnumSetting(string name, string label, TEnum defaultValue)
         : this(name, label)
         : this(name, label)
     {
     {
-        base.Value = defaultValue;
+        Value = defaultValue;
     }
     }
 
 
     private static ComboBox GenerateDropdown()
     private static ComboBox GenerateDropdown()

+ 0 - 0
src/PixiEditor/ViewModels/SubViewModels/Tools/Tool.cs → src/PixiEditor/ViewModels/SubViewModels/Tools/ToolViewModel.cs


+ 32 - 20
src/PixiEditor/ViewModels/SubViewModels/Tools/Tools/ColorPickerToolViewModel.cs

@@ -2,6 +2,8 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Commands.Attributes.Commands;
 using PixiEditor.Models.Commands.Attributes.Commands;
+using PixiEditor.Models.Enums;
+using PixiEditor.ViewModels.SubViewModels.Tools.ToolSettings.Toolbars;
 using PixiEditor.Views.UserControls.BrushShapeOverlay;
 using PixiEditor.Views.UserControls.BrushShapeOverlay;
 
 
 namespace PixiEditor.ViewModels.SubViewModels.Tools.Tools;
 namespace PixiEditor.ViewModels.SubViewModels.Tools.Tools;
@@ -11,17 +13,35 @@ internal class ColorPickerToolViewModel : ToolViewModel
 {
 {
     private readonly string defaultActionDisplay = "Click to pick colors. Hold Ctrl to hide the canvas. Hold Shift to hide the reference layer";
     private readonly string defaultActionDisplay = "Click to pick colors. Hold Ctrl to hide the canvas. Hold Shift to hide the reference layer";
 
 
-    public ColorPickerToolViewModel()
-    {
-        ActionDisplay = defaultActionDisplay;
-    }
-
     public override bool HideHighlight => true;
     public override bool HideHighlight => true;
 
 
     public override BrushShape BrushShape => BrushShape.Pixel;
     public override BrushShape BrushShape => BrushShape.Pixel;
 
 
     public override string Tooltip => $"Picks the primary color from the canvas. ({Shortcut})";
     public override string Tooltip => $"Picks the primary color from the canvas. ({Shortcut})";
 
 
+    private bool pickFromCanvas = true;
+    public bool PickFromCanvas
+    {
+        get => pickFromCanvas; 
+        private set => SetProperty(ref pickFromCanvas, value);
+    }
+    
+    private bool pickFromReferenceLayer = true;
+    public bool PickFromReferenceLayer
+    {
+        get => pickFromReferenceLayer; 
+        private set => SetProperty(ref pickFromReferenceLayer, value);
+    }
+
+    [Settings.Enum("Scope", DocumentScope.AllLayers)]
+    public DocumentScope Mode => GetValue<DocumentScope>();
+
+    public ColorPickerToolViewModel()
+    {
+        ActionDisplay = defaultActionDisplay;
+        Toolbar = ToolbarFactory.Create<ColorPickerToolViewModel, EmptyToolbar>();
+    }
+
     public override void OnLeftMouseButtonDown(VecD pos)
     public override void OnLeftMouseButtonDown(VecD pos)
     {
     {
         ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseColorPickerTool();
         ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseColorPickerTool();
@@ -29,32 +49,24 @@ internal class ColorPickerToolViewModel : ToolViewModel
 
 
     public override void UpdateActionDisplay(bool ctrlIsDown, bool shiftIsDown, bool altIsDown)
     public override void UpdateActionDisplay(bool ctrlIsDown, bool shiftIsDown, bool altIsDown)
     {
     {
-        /*
-        if (!IsActive)
-        {
-            _bitmapManager.HideReferenceLayer = false;
-            _bitmapManager.OnlyReferenceLayer = false;
-            return;
-        }
-
         if (ctrlIsDown)
         if (ctrlIsDown)
         {
         {
-            _bitmapManager.HideReferenceLayer = false;
-            _bitmapManager.OnlyReferenceLayer = true;
+            PickFromCanvas = false;
+            PickFromReferenceLayer = true;
             ActionDisplay = "Click to pick colors from the reference layer.";
             ActionDisplay = "Click to pick colors from the reference layer.";
         }
         }
         else if (shiftIsDown)
         else if (shiftIsDown)
         {
         {
-            _bitmapManager.HideReferenceLayer = true;
-            _bitmapManager.OnlyReferenceLayer = false;
+            PickFromCanvas = true;
+            PickFromReferenceLayer = false;
             ActionDisplay = "Click to pick colors from the canvas.";
             ActionDisplay = "Click to pick colors from the canvas.";
             return;
             return;
         }
         }
         else
         else
         {
         {
-            _bitmapManager.HideReferenceLayer = false;
-            _bitmapManager.OnlyReferenceLayer = false;
+            PickFromCanvas = true;
+            PickFromReferenceLayer = true;
             ActionDisplay = defaultActionDisplay;
             ActionDisplay = defaultActionDisplay;
-        }*/
+        }
     }
     }
 }
 }

+ 15 - 0
src/PixiEditor/ViewModels/ToolVM.cs

@@ -0,0 +1,15 @@
+using System.Windows.Markup;
+
+namespace PixiEditor.ViewModels;
+
+internal class ToolVM : MarkupExtension
+{
+    public string TypeName { get; set; }
+
+    public ToolVM(string typeName) => TypeName = typeName;
+
+    public override object ProvideValue(IServiceProvider serviceProvider)
+    {
+        return ViewModelMain.Current?.ToolsSubViewModel.ToolSet?.Where(tool => tool.GetType().Name == TypeName).FirstOrDefault();
+    }
+}

+ 92 - 95
src/PixiEditor/Views/UserControls/Layers/ReferenceLayer.xaml

@@ -16,48 +16,110 @@
         <i:Interaction.Behaviors>
         <i:Interaction.Behaviors>
             <behaviors:ClearFocusOnClickBehavior/>
             <behaviors:ClearFocusOnClickBehavior/>
         </i:Interaction.Behaviors>
         </i:Interaction.Behaviors>
-        <Grid>
-            <Grid Background="Transparent"/>
-            <Grid Grid.Row="0"  VerticalAlignment="Center">
-                <Grid.ColumnDefinitions>
-                    <ColumnDefinition Width="30"/>
-                    <ColumnDefinition Width="*"/>
-                </Grid.ColumnDefinitions>
-                <Grid Visibility="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, ElementName=uc, Converter={converters:NullToVisibilityConverter}}"  Grid.ColumnSpan="2" Grid.RowSpan="2" Panel.ZIndex="5">
-                    <Grid Cursor="Hand" Visibility="{Binding ElementName=visibilityCheckbox, Path=IsChecked, Converter={InverseBoolToVisibilityConverter}}"  Background="Transparent">
+        <DockPanel Background="Transparent">
+            <CheckBox Focusable="False" Panel.ZIndex="10" Name="visibilityCheckbox" Margin="0,0,5,0" Height="16" HorizontalAlignment="Right" DockPanel.Dock="Right">
+                <CheckBox.Triggers>
+                    <EventTrigger RoutedEvent="CheckBox.Checked">
+                        <BeginStoryboard>
+                            <Storyboard>
+                                <DoubleAnimation Storyboard.TargetName="mainDockPanel" Storyboard.TargetProperty="Height" From="40" To="0" Duration="0:0:0.15"/>
+                            </Storyboard>
+                        </BeginStoryboard>
+                    </EventTrigger>
+                    <EventTrigger RoutedEvent="CheckBox.Unchecked">
+                        <BeginStoryboard>
+                            <Storyboard>
+                                <DoubleAnimation Storyboard.TargetName="mainDockPanel" Storyboard.TargetProperty="Height" From="0" To="40" Duration="0:0:0.15"/>
+                            </Storyboard>
+                        </BeginStoryboard>
+                    </EventTrigger>
+
+                </CheckBox.Triggers>
+                <CheckBox.Template>
+                    <ControlTemplate TargetType="{x:Type CheckBox}">
+                        <StackPanel Orientation="Horizontal" Focusable="False">
+                            <Image Focusable="False" Width="14" Cursor="Hand" x:Name="checkboxImage" Source="/Images/ChevronDown.png">
+                                <Image.RenderTransform>
+                                    <RotateTransform Angle="0"/>
+                                </Image.RenderTransform>
+                            </Image>
+                            <ContentPresenter Focusable="False"/>
+                        </StackPanel>
+                        <ControlTemplate.Triggers>
+                            <Trigger Property="IsChecked" Value="True">
+                                <Setter TargetName="checkboxImage" Property="RenderTransform">
+                                    <Setter.Value>
+                                        <RotateTransform Angle="180" CenterX="7" CenterY="4"/>
+                                    </Setter.Value>
+                                </Setter>
+                            </Trigger>
+                        </ControlTemplate.Triggers>
+                    </ControlTemplate>
+                </CheckBox.Template>
+            </CheckBox>
+
+            <Grid Height="40" x:Name="mainDockPanel">
+                <Grid 
+                    Visibility="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, ElementName=uc, Converter={converters:NullToVisibilityConverter}}" 
+                    Panel.ZIndex="5">
+                    <Grid Cursor="Hand" Visibility="{Binding ElementName=visibilityCheckbox, Path=IsChecked, Converter={InverseBoolToVisibilityConverter}}" Background="Transparent">
+                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" DockPanel.Dock="Left">
+                            <Image Margin="5 0 5 0" Width="20" Source="/Images/Layer-add.png"
+                               Visibility="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, ElementName=uc, Converter={converters:NullToVisibilityConverter}}"/>
+
+                            <TextBlock IsEnabled="{Binding ElementName=uc, Path=IsEnabled}" 
+                                        Margin="0 0 5 0" Foreground="White" 
+                                        FontSize="15" VerticalAlignment="Center">Add Reference Layer</TextBlock>
+                        </StackPanel>
                         <i:Interaction.Triggers>
                         <i:Interaction.Triggers>
                             <i:EventTrigger EventName="MouseUp">
                             <i:EventTrigger EventName="MouseUp">
                                 <i:InvokeCommandAction Command="{cmds:Command PixiEditor.Layer.ImportReferenceLayer}"
                                 <i:InvokeCommandAction Command="{cmds:Command PixiEditor.Layer.ImportReferenceLayer}"
-                                    PassEventArgsToCommand="True"/>
+                                        PassEventArgsToCommand="True"/>
                             </i:EventTrigger>
                             </i:EventTrigger>
                         </i:Interaction.Triggers>
                         </i:Interaction.Triggers>
                     </Grid>
                     </Grid>
                 </Grid>
                 </Grid>
-                <Grid Grid.Column="0" Height="16" Name="layerVisibilityCheckboxGrid">
-                    <CheckBox 
-                        Visibility="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, 
-                                             ElementName=uc, 
-                                             Converter={converters:NotNullToVisibilityConverter}}"
-                        Style="{StaticResource ImageCheckBox}" VerticalAlignment="Center"
-                        IsThreeState="False" HorizontalAlignment="Center" 
-                        IsChecked="{Binding Path=Document.ReferenceLayerViewModel.IsVisibleBindable, Mode=TwoWay, ElementName=uc}"/>
-                </Grid>
-                <StackPanel Name="middleStackPanel" Height="40" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Left">
-                    <Button Cursor="Hand" Grid.Column="1"
+
+                <DockPanel Grid.Row="0" VerticalAlignment="Center" Height="40"
+                           Visibility="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, ElementName=uc, Converter={converters:NotNullToVisibilityConverter}}" >
+                    <Grid Height="16" Name="layerVisibilityCheckboxGrid" DockPanel.Dock="Left" Margin="10,0,5,0">
+                        <CheckBox 
+                            Style="{StaticResource ImageCheckBox}" VerticalAlignment="Center"
+                            IsThreeState="False" HorizontalAlignment="Center" 
+                            IsChecked="{Binding Path=Document.ReferenceLayerViewModel.IsVisibleBindable, Mode=TwoWay, ElementName=uc}"/>
+                    </Grid>
+                    <Border 
+                        HorizontalAlignment="Left" DockPanel.Dock="Left"
+                        Width="30" Height="30"
+                        BorderThickness="1" 
+                        BorderBrush="Black"
+                        Background="{StaticResource MainColor}"
+                        Margin="5, 0, 10, 0">
+                        <Image Source="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap,ElementName=uc}" Stretch="Uniform" Width="26" Height="26"
+                               RenderOptions.BitmapScalingMode="HighQuality" IsHitTestVisible="False"/>
+                    </Border>
+                    <Button Cursor="Hand" Grid.Column="1" DockPanel.Dock="Right"
+                                Command="{cmds:Command PixiEditor.Layer.DeleteReferenceLayer}"
+                                Style="{StaticResource ImageButtonStyle}" 
+                                RenderOptions.BitmapScalingMode="HighQuality"
+                                Margin="3,0,5,0"
+                                Width="20" Height="20" HorizontalAlignment="Right">
+                        <Button.Background>
+                            <ImageBrush ImageSource="/Images/Trash.png"/>
+                        </Button.Background>
+                    </Button>
+                    <Button Cursor="Hand" DockPanel.Dock="Right"
                             Command="{cmds:Command PixiEditor.Layer.ResetReferenceLayerPosition}"
                             Command="{cmds:Command PixiEditor.Layer.ResetReferenceLayerPosition}"
-                            Visibility="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, ElementName=uc, Converter={BoolToVisibilityConverter}}" 
                             Style="{StaticResource ImageButtonStyle}" 
                             Style="{StaticResource ImageButtonStyle}" 
                             ToolTip="Reset reference layer position"
                             ToolTip="Reset reference layer position"
                             RenderOptions.BitmapScalingMode="HighQuality"
                             RenderOptions.BitmapScalingMode="HighQuality"
-                            Margin="3"
                             Width="20" Height="20" HorizontalAlignment="Right">
                             Width="20" Height="20" HorizontalAlignment="Right">
                         <Button.Background>
                         <Button.Background>
                             <ImageBrush ImageSource="/Images/Layout.png"/>
                             <ImageBrush ImageSource="/Images/Layout.png"/>
                         </Button.Background>
                         </Button.Background>
                     </Button>
                     </Button>
-                    <Button Cursor="Hand" Grid.Column="1"
+                    <Button Cursor="Hand" DockPanel.Dock="Right"
                             Command="{cmds:Command PixiEditor.Layer.TransformReferenceLayer}"
                             Command="{cmds:Command PixiEditor.Layer.TransformReferenceLayer}"
-                            Visibility="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, ElementName=uc, Converter={BoolToVisibilityConverter}}" 
                             Style="{StaticResource ImageButtonStyle}" 
                             Style="{StaticResource ImageButtonStyle}" 
                             ToolTip="Transform reference layer"
                             ToolTip="Transform reference layer"
                             RenderOptions.BitmapScalingMode="HighQuality"
                             RenderOptions.BitmapScalingMode="HighQuality"
@@ -66,76 +128,11 @@
                             <ImageBrush ImageSource="/Images/Tools/MoveImage.png"/>
                             <ImageBrush ImageSource="/Images/Tools/MoveImage.png"/>
                         </Button.Background>
                         </Button.Background>
                     </Button>
                     </Button>
-                    <Border HorizontalAlignment="Left" 
-                            Visibility="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, ElementName=uc, Converter={converters:NotNullToVisibilityConverter}}" 
-                            Width="30" Height="30"
-                            BorderThickness="1" BorderBrush="Black"
-                            Background="{StaticResource MainColor}"
-                            Margin="5, 0, 10, 0">
-                        <Image Source="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap,ElementName=uc}" Stretch="Uniform" Width="26" Height="26"
-                           RenderOptions.BitmapScalingMode="HighQuality" IsHitTestVisible="False"/>
-                    </Border>
-                    <Image Margin="30 0 5 0" Width="20" Source="/Images/Layer-add.png"  
-                           Visibility="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, ElementName=uc, Converter={converters:NullToVisibilityConverter}}"/>
-
-                    <local1:PrependTextBlock IsEnabled="{Binding ElementName=uc, Path=IsEnabled}" 
-                                             Margin="0 0 5 0" Prepend="Add " Foreground="White" 
-                                             HidePrepend="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, ElementName=uc, Converter={converters:NotNullToBoolConverter}}"
-                                             FontSize="15" VerticalAlignment="Center" Text="Reference Layer" />
-                    <Button Cursor="Hand" Grid.Column="1" 
-                            Command="{cmds:Command PixiEditor.Layer.DeleteReferenceLayer}"
-                            Visibility="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, ElementName=uc, Converter={BoolToVisibilityConverter}}" 
-                            Style="{StaticResource ImageButtonStyle}" 
-                            RenderOptions.BitmapScalingMode="HighQuality"
-                            Width="20" Height="20" HorizontalAlignment="Right">
-                        <Button.Background>
-                            <ImageBrush ImageSource="/Images/Trash.png"/>
-                        </Button.Background>
-                    </Button>
-                </StackPanel>
-                <CheckBox Focusable="False" Panel.ZIndex="10" Name="visibilityCheckbox" Grid.Column="1" Margin="0,0,5,0" Height="16" HorizontalAlignment="Right">
-                    <CheckBox.Triggers>
-                        <EventTrigger RoutedEvent="CheckBox.Checked">
-                            <BeginStoryboard>
-                                <Storyboard>
-                                    <DoubleAnimation Storyboard.TargetName="middleStackPanel" Storyboard.TargetProperty="Height" From="40" To="0" Duration="0:0:0.15"/>
-                                    <DoubleAnimation Storyboard.TargetName="layerVisibilityCheckboxGrid" Storyboard.TargetProperty="Height" From="16" To="0" Duration="0:0:0.15"/>
-                                </Storyboard>
-                            </BeginStoryboard>
-                        </EventTrigger>
-                        <EventTrigger RoutedEvent="CheckBox.Unchecked">
-                            <BeginStoryboard>
-                                <Storyboard>
-                                    <DoubleAnimation Storyboard.TargetName="middleStackPanel" Storyboard.TargetProperty="Height" From="0" To="40" Duration="0:0:0.15"/>
-                                    <DoubleAnimation Storyboard.TargetName="layerVisibilityCheckboxGrid" Storyboard.TargetProperty="Height" From="0" To="16" Duration="0:0:0.15"/>
-                                </Storyboard>
-                            </BeginStoryboard>
-                        </EventTrigger>
-
-                    </CheckBox.Triggers>
-                    <CheckBox.Template>
-                        <ControlTemplate TargetType="{x:Type CheckBox}">
-                            <StackPanel Orientation="Horizontal" Focusable="False">
-                                <Image Focusable="False" Width="14" Cursor="Hand" x:Name="checkboxImage" Source="/Images/ChevronDown.png">
-                                    <Image.RenderTransform>
-                                        <RotateTransform Angle="0"/>
-                                    </Image.RenderTransform>
-                                </Image>
-                                <ContentPresenter Focusable="False"/>
-                            </StackPanel>
-                            <ControlTemplate.Triggers>
-                                <Trigger Property="IsChecked" Value="True">
-                                    <Setter TargetName="checkboxImage" Property="RenderTransform">
-                                        <Setter.Value>
-                                            <RotateTransform Angle="180" CenterX="7" CenterY="4"/>
-                                        </Setter.Value>
-                                    </Setter>
-                                </Trigger>
-                            </ControlTemplate.Triggers>
-                        </ControlTemplate>
-                    </CheckBox.Template>
-                </CheckBox>
+                    <TextBlock IsEnabled="{Binding ElementName=uc, Path=IsEnabled}" HorizontalAlignment="Center"
+                                Margin="0 0 5 0" Foreground="White" 
+                                FontSize="15" VerticalAlignment="Center">Reference Layer</TextBlock>
+                </DockPanel>
             </Grid>
             </Grid>
-        </Grid>
+        </DockPanel>
     </Border>
     </Border>
 </UserControl>
 </UserControl>

+ 2 - 1
src/PixiEditor/Views/UserControls/PreviewWindow.xaml.cs

@@ -5,6 +5,7 @@ using System.Windows.Media;
 using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 using BackendColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Document;
+using PixiEditor.Models.Enums;
 
 
 namespace PixiEditor.Views.UserControls;
 namespace PixiEditor.Views.UserControls;
 
 
@@ -136,7 +137,7 @@ internal partial class PreviewWindow : UserControl
 
 
         ColorCursorPosition = newPos;
         ColorCursorPosition = newPos;
 
 
-        BackendColor color = Document.PickColor(new(x, y), true);
+        BackendColor color = Document.PickColor(new(x, y), DocumentScope.AllLayers, false, true);
         ColorCursorColor = Color.FromArgb(color.A, color.R, color.G, color.B);
         ColorCursorColor = Color.FromArgb(color.A, color.R, color.G, color.B);
     }
     }
 }
 }

+ 3 - 2
src/PixiEditor/Views/UserControls/Viewport.xaml

@@ -147,12 +147,12 @@
                     </ImageBrush>
                     </ImageBrush>
                 </Border.Background>
                 </Border.Background>
                 <Grid>
                 <Grid>
-                    <Canvas>
+                    <Canvas Visibility="{Binding Source={vm:ToolVM ColorPickerToolViewModel}, Path=PickFromReferenceLayer, Converter={converters:BoolToVisibilityConverter}}">
                         <Image
                         <Image
                             Width="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap.Width}"
                             Width="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap.Width}"
                             Height="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap.Height}"
                             Height="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap.Height}"
                             Source="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, Mode=OneWay}"
                             Source="{Binding Document.ReferenceLayerViewModel.ReferenceBitmap, Mode=OneWay}"
-                            Visibility="{Binding Document.ReferenceLayerViewModel.IsVisibleBindable, Converter={converters:BoolToVisibilityConverter}}"
+                            Visibility="{Binding Document.ReferenceLayerViewModel.IsVisibleBindable, Converter={converters:BoolToHiddenVisibilityConverter}}"
                             SizeChanged="OnReferenceImageSizeChanged"
                             SizeChanged="OnReferenceImageSizeChanged"
                             RenderOptions.BitmapScalingMode="{Binding ReferenceLayerScale, Converter={converters:ScaleToBitmapScalingModeConverter}}">
                             RenderOptions.BitmapScalingMode="{Binding ReferenceLayerScale, Converter={converters:ScaleToBitmapScalingModeConverter}}">
                             <Image.RenderTransform>
                             <Image.RenderTransform>
@@ -168,6 +168,7 @@
                         Width="{Binding Document.Width}"
                         Width="{Binding Document.Width}"
                         Height="{Binding Document.Height}"
                         Height="{Binding Document.Height}"
                         Source="{Binding TargetBitmap}"
                         Source="{Binding TargetBitmap}"
+                        Visibility="{Binding Source={vm:ToolVM ColorPickerToolViewModel}, Path=PickFromCanvas, Converter={converters:BoolToHiddenVisibilityConverter}}"
                         RenderOptions.BitmapScalingMode="{Binding Zoombox.Scale, Converter={converters:ScaleToBitmapScalingModeConverter}}"/>
                         RenderOptions.BitmapScalingMode="{Binding Zoombox.Scale, Converter={converters:ScaleToBitmapScalingModeConverter}}"/>
                     <sym:SymmetryOverlay
                     <sym:SymmetryOverlay
                         IsHitTestVisible="{Binding ZoomMode, Converter={converters:ZoomModeToHitTestVisibleConverter}}"
                         IsHitTestVisible="{Binding ZoomMode, Converter={converters:ZoomModeToHitTestVisibleConverter}}"