Explorar o código

Lock transparency, Layer/Folder context menu improvements, Opacity slider minor fix

Equbuxu %!s(int64=3) %!d(string=hai) anos
pai
achega
871fe7890d

+ 6 - 1
src/PixiEditor.ChangeableDocument/Changes/Properties/StructureMemberOpacity_UpdateableChange.cs

@@ -30,7 +30,12 @@ internal class StructureMemberOpacity_UpdateableChange : UpdateableChange
         return new Success();
     }
 
-    public override OneOf<None, IChangeInfo, List<IChangeInfo>> ApplyTemporarily(Document target) => Apply(target, false, out _);
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> ApplyTemporarily(Document target)
+    {
+        var member = target.FindMemberOrThrow(memberGuid);
+        member.Opacity = newOpacity;
+        return new StructureMemberOpacity_ChangeInfo(memberGuid, newOpacity);
+    }
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document document, bool firstApply, out bool ignoreInUndo)
     {

BIN=BIN
src/PixiEditor/Images/Lock-alpha.png


+ 95 - 0
src/PixiEditor/Images/Lock-alpha.svg

@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   width="24"
+   height="24"
+   viewBox="0 0 6.3499999 6.3500002"
+   version="1.1"
+   id="svg5"
+   inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
+   sodipodi:docname="рисунок.svg"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <sodipodi:namedview
+     id="namedview7"
+     pagecolor="#000000"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0"
+     inkscape:pagecheckerboard="false"
+     inkscape:document-units="px"
+     showgrid="true"
+     units="px"
+     width="24px"
+     inkscape:snap-bbox="true"
+     inkscape:zoom="22.627417"
+     inkscape:cx="10.076272"
+     inkscape:cy="12.153398"
+     inkscape:window-width="1920"
+     inkscape:window-height="1009"
+     inkscape:window-x="1272"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="layer1">
+    <inkscape:grid
+       type="xygrid"
+       id="grid1308"
+       spacingx="0.13229167"
+       spacingy="0.13229167"
+       empspacing="4"
+       visible="false"
+       enabled="true" />
+  </sodipodi:namedview>
+  <defs
+     id="defs2" />
+  <g
+     inkscape:label="Слой 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <rect
+       style="opacity:1;fill:none;stroke:#ffffff;stroke-width:0.529167;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
+       id="rect1310"
+       width="4.7625008"
+       height="3.5718749"
+       x="0.79375005"
+       y="2.2489583"
+       ry="0.52916658" />
+    <circle
+       style="display:none;opacity:1;fill:#ffffff;stroke:none;stroke-width:0.264583"
+       id="path3065"
+       cx="3.1750002"
+       cy="2.3812501"
+       r="2.1166668" />
+    <rect
+       style="display:none;opacity:1;fill:#ffffff;stroke:none;stroke-width:0.264583"
+       id="rect3169"
+       width="4.2333336"
+       height="0.92604166"
+       x="1.0583332"
+       y="2.3812501" />
+    <path
+       id="path3295"
+       style="display:none;opacity:1;fill:#333333;stroke:none;stroke-width:0.288637"
+       d="m 3.1750001,0.79375002 a 1.5875,1.5875 0 0 1 1.5875,1.58750008 V 2.9104167 H 1.5875 V 2.3812501 A 1.5875,1.5875 0 0 1 3.1750001,0.79375002 Z" />
+    <path
+       style="fill:none;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 1.4552084,2.5135417 V 1.3229168 c 0,-0.39687506 0.396875,-0.79375003 0.79375,-0.79375003 l 1.8520834,-4e-8 c 0.3968751,0 0.7937501,0.39687501 0.7937501,0.79375007 l -1e-7,1.1906249"
+       id="path1511"
+       sodipodi:nodetypes="cscccc" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.7625px;line-height:1.25;font-family:'Palatino Linotype';-inkscape-font-specification:'Palatino Linotype Bold';fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264583"
+       x="1.5875001"
+       y="5.1593752"
+       id="text26385"><tspan
+         sodipodi:role="line"
+         id="tspan26383"
+         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4.7625px;font-family:'Palatino Linotype';-inkscape-font-specification:'Palatino Linotype Bold';fill:#ffffff;stroke-width:0.264583"
+         x="1.5875001"
+         y="5.1593752">α</tspan></text>
+  </g>
+</svg>

+ 2 - 0
src/PixiEditor/PixiEditor.csproj

@@ -159,6 +159,7 @@
 		<None Remove="Images\Globe.png" />
 		<None Remove="Images\hard-drive.png" />
 		<None Remove="Images\Layer-add.png" />
+		<None Remove="Images\Lock-alpha.png" />
 		<None Remove="Images\MoveImage.png" />
 		<None Remove="Images\MoveViewportImage.png" />
 		<None Remove="Images\penMode.png" />
@@ -248,6 +249,7 @@
 		<Resource Include="Images\Globe.png" />
 		<Resource Include="Images\hard-drive.png" />
 		<Resource Include="Images\Layer-add.png" />
+		<Resource Include="Images\Lock-alpha.png" />
 		<Resource Include="Images\penMode.png" />
 		<Resource Include="Images\PixiBotLogo.png" />
 		<Resource Include="Images\PixiEditorLogo.png" />

+ 22 - 2
src/PixiEditor/Styles/ThemeStyle.xaml

@@ -312,9 +312,23 @@
         <Setter Property="Template">
             <Setter.Value>
                 <ControlTemplate TargetType="MenuItem">
-                    <Border x:Name="Bd" Background="Transparent" Margin="10 0 10 0">
+                    <Border x:Name="Bd" Background="Transparent" Margin="3,0">
                         <Grid>
-                            <ContentPresenter Margin="6,3,6,3" ContentSource="Header" RecognizesAccessKey="True" />
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition x:Name="Col0" MinWidth="17" Width="Auto"
+                                                  SharedSizeGroup="MenuItemIconColumnGroup" />
+                                <ColumnDefinition Width="Auto" SharedSizeGroup="MenuTextColumnGroup" />
+                            </Grid.ColumnDefinitions>
+
+                            <!-- Checkmark -->
+                            <Grid Grid.Column="0" Visibility="Hidden" Margin="4,0,6,0" x:Name="Check"
+                                  VerticalAlignment="Center">
+                                <Path x:Name="GlyphPanelpath" VerticalAlignment="Center"
+                                      Fill="{TemplateBinding Foreground}"
+                                      Data="M0,2 L0,4.8 L2.5,7.4 L7.1,2.8 L7.1,0 L2.5,4.6 z"
+                                      FlowDirection="LeftToRight" />
+                            </Grid>
+                            <ContentPresenter Grid.Column="1" Margin="3,3,5,3" ContentSource="Header" RecognizesAccessKey="True" />
                         </Grid>
                     </Border>
                     <ControlTemplate.Triggers>
@@ -324,6 +338,12 @@
                         <Trigger Property="IsEnabled" Value="False">
                             <Setter Property="Foreground" Value="Gray" />
                         </Trigger>
+                        <Trigger Property="IsChecked" Value="False">
+                            <Setter TargetName="Check" Property="Visibility" Value="Hidden"/>
+                        </Trigger>
+                        <Trigger Property="IsChecked" Value="True">
+                            <Setter TargetName="Check" Property="Visibility" Value="Visible"/>
+                        </Trigger>
                     </ControlTemplate.Triggers>
                 </ControlTemplate>
             </Setter.Value>

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

@@ -290,18 +290,20 @@ internal class DocumentViewModel : NotifyableObject
         Helpers.ActionAccumulator.AddFinishedActions(new ReplaceColor_Action(oldColor, newColor));
     }
 
-    public void CreateMask(Guid memberGuid)
+    public void CreateMask(StructureMemberViewModel member)
     {
         if (Helpers.ChangeController.IsChangeActive)
             return;
-        Helpers.ActionAccumulator.AddFinishedActions(new CreateStructureMemberMask_Action(memberGuid));
+        if (!member.MaskIsVisibleBindable)
+            Helpers.ActionAccumulator.AddActions(new StructureMemberMaskIsVisible_Action(true, member.GuidValue));
+        Helpers.ActionAccumulator.AddFinishedActions(new CreateStructureMemberMask_Action(member.GuidValue));
     }
 
-    public void DeleteMask(Guid memberGuid)
+    public void DeleteMask(StructureMemberViewModel member)
     {
         if (Helpers.ChangeController.IsChangeActive)
             return;
-        Helpers.ActionAccumulator.AddFinishedActions(new DeleteStructureMemberMask_Action(memberGuid));
+        Helpers.ActionAccumulator.AddFinishedActions(new DeleteStructureMemberMask_Action(member.GuidValue));
     }
 
     public void SetSelectedMember(Guid memberGuid) => Helpers.ActionAccumulator.AddActions(new SetSelectedMember_PassthroughAction(memberGuid));

+ 5 - 1
src/PixiEditor/ViewModels/SubViewModels/Document/StructureMemberViewModel.cs

@@ -56,7 +56,11 @@ internal abstract class StructureMemberViewModel : INotifyPropertyChanged
     public bool MaskIsVisibleBindable
     {
         get => maskIsVisible;
-        set => Helpers.ActionAccumulator.AddFinishedActions(new StructureMemberMaskIsVisible_Action(value, GuidValue));
+        set
+        {
+            if (!Document.UpdateableChangeActive)
+                Helpers.ActionAccumulator.AddFinishedActions(new StructureMemberMaskIsVisible_Action(value, GuidValue));
+        }
     }
 
     private BlendMode blendMode;

+ 39 - 70
src/PixiEditor/ViewModels/SubViewModels/Main/LayersViewModel.cs

@@ -9,24 +9,23 @@ namespace PixiEditor.ViewModels.SubViewModels.Main;
 [Command.Group("PixiEditor.Layer", "Image")]
 internal class LayersViewModel : SubViewModel<ViewModelMain>
 {
-
     public LayersViewModel(ViewModelMain owner)
         : base(owner)
     {
     }
 
-    public void CreateFolderFromActiveLayers(object parameter)
+    public void CreateFolderFromActiveLayers()
     {
 
     }
 
-    public bool CanCreateFolderFromSelected(object obj)
+    public bool CanCreateFolderFromSelected()
     {
         return false;
     }
 
     [Evaluator.CanExecute("PixiEditor.Layer.CanDeleteSelected")]
-    public bool CanDeleteSelected(object parameter)
+    public bool CanDeleteSelected()
     {
         var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
         if (member is null)
@@ -35,7 +34,7 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Basic("PixiEditor.Layer.DeleteSelected", "Delete active layer/folder", "Delete active layer or folder", CanExecute = "PixiEditor.Layer.CanDeleteSelected")]
-    public void DeleteSelected(object parameter)
+    public void DeleteSelected()
     {
         var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
         if (member is null)
@@ -44,7 +43,7 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     }
 
     [Evaluator.CanExecute("PixiEditor.Layer.HasSelectedMembers")]
-    public bool HasSelectedMembers(object parameter)
+    public bool HasSelectedMembers()
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null)
@@ -53,7 +52,7 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     }
 
     [Evaluator.CanExecute("PixiEditor.Layer.HasMultipleSelectedMembers")]
-    public bool HasMultipleSelectedMembers(object parameter)
+    public bool HasMultipleSelectedMembers()
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null)
@@ -66,18 +65,18 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
 
     private List<Guid> GetSelected()
     {
-        List<Guid> membersToDelete = new();
+        List<Guid> members = new();
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null)
-            return membersToDelete;
+            return members;
         if (doc.SelectedStructureMember is not null)
-            membersToDelete.Add(doc.SelectedStructureMember.GuidValue);
-        membersToDelete.AddRange(doc.SoftSelectedStructureMembers.Select(static member => member.GuidValue));
-        return membersToDelete;
+            members.Add(doc.SelectedStructureMember.GuidValue);
+        members.AddRange(doc.SoftSelectedStructureMembers.Select(static member => member.GuidValue));
+        return members;
     }
 
     [Command.Basic("PixiEditor.Layer.DeleteAllSelected", "Delete all selected layers/folders", "Delete all selected layers and/or folders", CanExecute = "PixiEditor.Layer.HasSelectedMembers")]
-    public void DeleteAllSelected(object parameter)
+    public void DeleteAllSelected()
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null)
@@ -88,7 +87,7 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Basic("PixiEditor.Layer.NewFolder", "New Folder", "Create new folder", CanExecute = "PixiEditor.Layer.CanCreateNewMember")]
-    public void NewFolder(object parameter)
+    public void NewFolder()
     {
         if (Owner.DocumentManagerSubViewModel.ActiveDocument is not { } doc)
             return;
@@ -96,7 +95,7 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Basic("PixiEditor.Layer.NewLayer", "New Layer", "Create new layer", CanExecute = "PixiEditor.Layer.CanCreateNewMember", Key = Key.N, Modifiers = ModifierKeys.Control | ModifierKeys.Shift, IconPath = "Layer-add.png")]
-    public void NewLayer(object parameter)
+    public void NewLayer()
     {
         if (Owner.DocumentManagerSubViewModel.ActiveDocument is not { } doc)
             return;
@@ -104,13 +103,22 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     }
 
     [Evaluator.CanExecute("PixiEditor.Layer.CanCreateNewMember")]
-    public bool CanCreateNewMember(object parameter)
+    public bool CanCreateNewMember()
     {
         return Owner.DocumentManagerSubViewModel.ActiveDocument is { } doc && !doc.UpdateableChangeActive;
     }
 
+    [Command.Internal("PixiEditor.Layer.ToggleLockTransparency", CanExecute = "PixiEditor.Layer.SelectedMemberIsLayer")]
+    public void ToggleLockTransparency()
+    {
+        var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
+        if (member is not LayerViewModel layerVm)
+            return;
+        layerVm.LockTransparencyBindable = !layerVm.LockTransparencyBindable;
+    }
+
     [Command.Internal("PixiEditor.Layer.OpacitySliderDragStarted")]
-    public void OpacitySliderDragStarted(object parameter)
+    public void OpacitySliderDragStarted()
     {
         Owner.DocumentManagerSubViewModel.ActiveDocument?.UseOpacitySlider();
         Owner.DocumentManagerSubViewModel.ActiveDocument?.OnOpacitySliderDragStarted();
@@ -125,13 +133,13 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Internal("PixiEditor.Layer.OpacitySliderDragEnded")]
-    public void OpacitySliderDragEnded(object parameter)
+    public void OpacitySliderDragEnded()
     {
         Owner.DocumentManagerSubViewModel.ActiveDocument?.OnOpacitySliderDragEnded();
     }
 
-    [Command.Basic("PixiEditor.Layer.DuplicateSelectedLayer", "Duplicate selected layer", "Duplicate selected layer", CanExecute = "PixiEditor.Layer.CanDuplicatedSelectedLayer")]
-    public void DuplicateLayer(object parameter)
+    [Command.Basic("PixiEditor.Layer.DuplicateSelectedLayer", "Duplicate selected layer", "Duplicate selected layer", CanExecute = "PixiEditor.Layer.SelectedMemberIsLayer")]
+    public void DuplicateLayer()
     {
         var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
         if (member is not LayerViewModel layerVM)
@@ -139,8 +147,8 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
         member.Document.DuplicateLayer(member.GuidValue);
     }
 
-    [Evaluator.CanExecute("PixiEditor.Layer.CanDuplicatedSelectedLayer")]
-    public bool CanDuplicateLayer(object property)
+    [Evaluator.CanExecute("PixiEditor.Layer.SelectedMemberIsLayer")]
+    public bool SelectedMemberIsLayer(object property)
     {
         var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
         return member is LayerViewModel;
@@ -195,63 +203,24 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     [Evaluator.CanExecute("PixiEditor.Layer.ActiveLayerHasNoMask")]
     public bool ActiveLayerHasNoMask() => !ActiveMemberHasMask();
 
-    private bool? DoesMaskVisibilityEqual(bool value)
-    {
-        var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
-        if (member is null || !member.HasMaskBindable)
-            return false;
-        return member.MaskIsVisibleBindable == value;
-    }
-
-    [Evaluator.CanExecute("PixiEditor.Layer.CanEnableMask")]
-    public bool CanEnableMask() => DoesMaskVisibilityEqual(false) ?? false;
-
-    [Evaluator.CanExecute("PixiEditor.Layer.CanDisableMask")]
-    public bool CanDisableMask() => DoesMaskVisibilityEqual(true) ?? false;
-
-    [Command.Basic("PixiEditor.Layer.EnableMask", "Enable mask", "Enable mask", CanExecute = "PixiEditor.Layer.CanEnableMask", Parameter = true)]
-    [Command.Basic("PixiEditor.Layer.DisableMask", "Disable mask", "Disable mask", CanExecute = "PixiEditor.Layer.CanDisableMask", Parameter = false)]
-    public void ToggleMaskVisibility(bool newVisibility)
-    {
-        var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
-        if (member is null || !member.HasMaskBindable || member.MaskIsVisibleBindable == newVisibility)
-            return;
-        member.MaskIsVisibleBindable = newVisibility;
-    }
-
     [Command.Basic("PixiEditor.Layer.CreateMask", "Create mask", "Create mask", CanExecute = "PixiEditor.Layer.ActiveLayerHasNoMask")]
-    public void CreateMask(object parameter)
+    public void CreateMask()
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         var member = doc?.SelectedStructureMember;
         if (member is null || member.HasMaskBindable)
             return;
-        doc!.CreateMask(member.GuidValue);
+        doc!.CreateMask(member);
     }
 
     [Command.Basic("PixiEditor.Layer.DeleteMask", "Delete mask", "Delete mask", CanExecute = "PixiEditor.Layer.ActiveLayerHasMask")]
-    public void DeleteMask(object parameter)
+    public void DeleteMask()
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         var member = doc?.SelectedStructureMember;
         if (member is null || !member.HasMaskBindable)
             return;
-        doc!.DeleteMask(member.GuidValue);
-    }
-
-    [Evaluator.CanExecute("PixiEditor.Layer.CanEnableClipToMemberBelow")]
-    public bool CanClipToMemberBelow() => !Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember?.ClipToMemberBelowEnabledBindable ?? false;
-    [Evaluator.CanExecute("PixiEditor.Layer.CanDisableClipToMemberBelow")]
-    public bool CanDisableClipToMemberBelow() => Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember?.ClipToMemberBelowEnabledBindable ?? false;
-
-    [Command.Basic("PixiEditor.Layer.EnableClipToMemberBelow", "Clip to layer below", "Clip to layer below", Parameter = true, CanExecute = "PixiEditor.Layer.CanEnableClipToMemberBelow")]
-    [Command.Basic("PixiEditor.Layer.DisableClipToMemberBelow", "Disable clip to layer below", "Disable clip to layer below", Parameter = false, CanExecute = "PixiEditor.Layer.CanDisableClipToMemberBelow")]
-    public void ToogleClipToMemberBelow(bool newValue)
-    {
-        var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
-        if (member is null || member.ClipToMemberBelowEnabledBindable == newValue)
-            return;
-        member.ClipToMemberBelowEnabledBindable = newValue;
+        doc!.DeleteMask(member);
     }
 
     [Evaluator.CanExecute("PixiEditor.Layer.HasMemberAbove")]
@@ -260,12 +229,12 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     public bool HasMemberBelow(object property) => HasSelectedMember(false);
 
     [Command.Basic("PixiEditor.Layer.MoveSelectedMemberUpwards", "Move selected layer upwards", "Move selected layer or folder upwards", CanExecute = "PixiEditor.Layer.HasMemberAbove")]
-    public void MoveSelectedMemberUpwards(object parameter) => MoveSelectedMember(true);
+    public void MoveSelectedMemberUpwards() => MoveSelectedMember(true);
     [Command.Basic("PixiEditor.Layer.MoveSelectedMemberDownwards", "Move selected layer downwards", "Move selected layer or folder downwards", CanExecute = "PixiEditor.Layer.HasMemberBelow")]
-    public void MoveSelectedMemberDownwards(object parameter) => MoveSelectedMember(false);
+    public void MoveSelectedMemberDownwards() => MoveSelectedMember(false);
 
     [Command.Basic("PixiEditor.Layer.MergeSelected", "Merge all selected layers", "Merge all selected layers", CanExecute = "PixiEditor.Layer.HasMultipleSelectedMembers")]
-    public void MergeSelected(object parameter)
+    public void MergeSelected()
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null)
@@ -294,8 +263,8 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Basic("PixiEditor.Layer.MergeWithAbove", "Merge selected layer with the one above it", "Merge selected layer with the one above it", CanExecute = "PixiEditor.Layer.HasMemberAbove")]
-    public void MergeWithAbove(object parameter) => MergeSelectedWith(true);
+    public void MergeWithAbove() => MergeSelectedWith(true);
 
     [Command.Basic("PixiEditor.Layer.MergeWithBelow", "Merge selected layer with the one below it", "Merge selected layer with the one below it", CanExecute = "PixiEditor.Layer.HasMemberBelow")]
-    public void MergeWithBelow(object parameter) => MergeSelectedWith(false);
+    public void MergeWithBelow() => MergeSelectedWith(false);
 }

+ 11 - 5
src/PixiEditor/Views/UserControls/Layers/FolderControl.xaml

@@ -5,6 +5,7 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              xmlns:i="http://schemas.microsoft.com/xaml/behaviors" 
+             xmlns:local="clr-namespace:PixiEditor.Views.UserControls.Layers" 
              xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours" xmlns:userControls="clr-namespace:PixiEditor.Views" 
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters" xmlns:helpers="clr-namespace:PixiEditor.Helpers.UI"
              xmlns:userControls1="clr-namespace:PixiEditor.Views.UserControls"
@@ -123,16 +124,21 @@
             <ContextMenu>
                 <MenuItem Header="Delete" Command="{cmds:Command PixiEditor.Layer.DeleteAllSelected}"/>
                 <MenuItem Header="Rename" Click="RenameMenuItem_Click"/>
+                <MenuItem 
+                    IsCheckable="True" 
+                    IsChecked="{Binding PlacementTarget.Tag.Folder.ClipToMemberBelowEnabledBindable, RelativeSource={RelativeSource AncestorType=ContextMenu}}" 
+                    Header="Clip to layer below"/>
+                <Separator/>
                 <MenuItem Header="Move upwards" Command="{cmds:Command PixiEditor.Layer.MoveSelectedMemberUpwards}"/>
                 <MenuItem Header="Move downwards" Command="{cmds:Command PixiEditor.Layer.MoveSelectedMemberDownwards}"/>
                 <Separator/>
-                <MenuItem Header="Clip to layer below" Command="{cmds:Command PixiEditor.Layer.EnableClipToMemberBelow}"/>
-                <MenuItem Header="Disable clip to layer below" Command="{cmds:Command PixiEditor.Layer.DisableClipToMemberBelow}"/>
-                <Separator/>
                 <MenuItem Header="Create mask" Command="{cmds:Command PixiEditor.Layer.CreateMask}"/>
                 <MenuItem Header="Delete mask" Command="{cmds:Command PixiEditor.Layer.DeleteMask}"/>
-                <MenuItem Header="Enable mask" Command="{cmds:Command PixiEditor.Layer.EnableMask}"/>
-                <MenuItem Header="Disable mask" Command="{cmds:Command PixiEditor.Layer.DisableMask}"/>
+                <MenuItem 
+                    IsCheckable="True" 
+                    IsChecked="{Binding PlacementTarget.Tag.Folder.MaskIsVisibleBindable, RelativeSource={RelativeSource AncestorType=ContextMenu}}" 
+                    IsEnabled="{Binding PlacementTarget.Tag.Folder.HasMaskBindable, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
+                    Header="Enable mask"/>
                 <Separator/>
                 <MenuItem Header="Merge selected" Command="{cmds:Command PixiEditor.Layer.MergeSelected}"/>
                 <MenuItem Header="Merge with above" Command="{cmds:Command PixiEditor.Layer.MergeWithAbove}"/>

+ 20 - 11
src/PixiEditor/Views/UserControls/Layers/LayerControl.xaml

@@ -4,7 +4,7 @@
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
-             xmlns:local="clr-namespace:PixiEditor.Views"
+             xmlns:local="clr-namespace:PixiEditor.Views.UserControls.Layers"
              xmlns:conv="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:controls="clr-namespace:PixiEditor.Views.UserControls"
              xmlns:i="http://schemas.microsoft.com/xaml/behaviors" 
@@ -20,7 +20,7 @@
         <conv:BoolToBrushConverter x:Key="LayerBorderConverter" FalseBrush="White" TrueBrush="Black"/>
         <conv:BoolToBrushConverter x:Key="MaskBorderConverter" FalseBrush="Black" TrueBrush="White"/>
     </UserControl.Resources>
-    <Border BorderThickness="0 0 0 0.5" BorderBrush="Gray" MinWidth="60" Focusable="True">
+    <Border BorderThickness="0 0 0 0.5" BorderBrush="Gray" MinWidth="60" Focusable="True" Tag="{Binding ElementName=uc}">
         <Border.Background>
             <Binding ElementName="uc" Path="Layer.Selection">
                 <Binding.Converter>
@@ -115,10 +115,10 @@
                             d:Text="New Layer"
                             Text="{Binding Layer.NameBindable, ElementName=uc, Mode=TwoWay}" />
                     </StackPanel>
-                    <WrapPanel Orientation="Vertical" Margin="0,3,3,3" >
-                        <Grid Background="Black" Visibility="{Binding Layer.LockTransparencyBindable, ElementName=uc, Converter={BoolToVisibilityConverter}}">
-                            <Path Fill="White" Data="M 0 0 L 12 0 L 12 3 L 0 3 L 0 6 L 12 6 L 12 9 L 0 9 L 0 12 L 12 12 L 12 0 L 9 0 L 9 12 L 6 12 L 6 0 L 3 0 L 3 12 L 0 12 L 0 12 Z"/>
-                        </Grid>
+                    <WrapPanel Orientation="Vertical" Margin="0,3,3,3">
+                        <Image 
+                            Source="/Images/Lock-alpha.png" Width="14" Height="14"
+                            Visibility="{Binding Layer.LockTransparencyBindable, ElementName=uc, Converter={BoolToVisibilityConverter}}"/>
                     </WrapPanel>
                 </StackPanel>
                 <Grid Margin="0, 0, 0, -2.5" DragEnter="Grid_DragEnter" VerticalAlignment="Bottom" Height="10" Drop="Grid_Drop_Below"  DragLeave="Grid_DragLeave" Grid.Row="2" Grid.Column="0" AllowDrop="True"  Background="Transparent" Name="dropBelowGrid"/>
@@ -132,16 +132,25 @@
                 <MenuItem Header="Duplicate" Command="{cmds:Command PixiEditor.Layer.DuplicateSelectedLayer}"/>
                 <MenuItem Header="Delete" Command="{cmds:Command PixiEditor.Layer.DeleteAllSelected}"/>
                 <MenuItem Header="Rename" Click="RenameMenuItem_Click"/>
+                <MenuItem 
+                    IsCheckable="True" 
+                    IsChecked="{Binding PlacementTarget.Tag.Layer.ClipToMemberBelowEnabledBindable, RelativeSource={RelativeSource AncestorType=ContextMenu}}" 
+                    Header="Clip to layer below"/>
+                <MenuItem 
+                    IsCheckable="True" 
+                    IsChecked="{Binding PlacementTarget.Tag.Layer.LockTransparencyBindable, RelativeSource={RelativeSource AncestorType=ContextMenu}}" 
+                    Header="Lock transparency"/>
+                <Separator/>
                 <MenuItem Header="Move upwards" Command="{cmds:Command PixiEditor.Layer.MoveSelectedMemberUpwards}"/>
                 <MenuItem Header="Move downwards" Command="{cmds:Command PixiEditor.Layer.MoveSelectedMemberDownwards}"/>
                 <Separator/>
-                <MenuItem Header="Clip to layer below" Command="{cmds:Command PixiEditor.Layer.EnableClipToMemberBelow}"/>
-                <MenuItem Header="Disable clip to layer below" Command="{cmds:Command PixiEditor.Layer.DisableClipToMemberBelow}"/>
-                <Separator/>
                 <MenuItem Header="Create mask" Command="{cmds:Command PixiEditor.Layer.CreateMask}"/>
                 <MenuItem Header="Delete mask" Command="{cmds:Command PixiEditor.Layer.DeleteMask}"/>
-                <MenuItem Header="Enable mask" Command="{cmds:Command PixiEditor.Layer.EnableMask}"/>
-                <MenuItem Header="Disable mask" Command="{cmds:Command PixiEditor.Layer.DisableMask}"/>
+                <MenuItem 
+                    IsCheckable="True" 
+                    IsChecked="{Binding PlacementTarget.Tag.Layer.MaskIsVisibleBindable, RelativeSource={RelativeSource AncestorType=ContextMenu}}" 
+                    IsEnabled="{Binding PlacementTarget.Tag.Layer.HasMaskBindable, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
+                    Header="Enable mask"/>
                 <Separator/>
                 <MenuItem Header="Merge selected" Command="{cmds:Command PixiEditor.Layer.MergeSelected}"/>
                 <MenuItem Header="Merge with above" Command="{cmds:Command PixiEditor.Layer.MergeWithAbove}"/>

+ 43 - 30
src/PixiEditor/Views/UserControls/Layers/LayersManager.xaml

@@ -23,35 +23,47 @@
             <RowDefinition Height="1*"/>
         </Grid.RowDefinitions>
         <StackPanel Grid.Row="0" HorizontalAlignment="Stretch" Background="{StaticResource MainColor}">
-            <DockPanel  HorizontalAlignment="Stretch">
-                <StackPanel Orientation="Horizontal" DockPanel.Dock="Left">
-                    <Button Command="{commands:Command PixiEditor.Layer.NewLayer}" 
-                        Height="24" Width="24" Cursor="Hand" ToolTip="New Layer"
-                        HorizontalAlignment="Stretch" Margin="5,5,0,5"
-                        Style="{StaticResource ToolButtonStyle}">
-                        <Button.Background>
-                            <ImageBrush ImageSource="/Images/Layer-add.png"/>
-                        </Button.Background>
-                    </Button>
-                    <Button Command="{commands:Command PixiEditor.Layer.NewFolder}" 
-                        Height="24" Width="24" ToolTip="New Folder" Cursor="Hand"
-                                                HorizontalAlignment="Stretch"  Margin="5,5,0,5"
-                                                Style="{StaticResource ToolButtonStyle}">
-                        <Button.Background>
-                            <ImageBrush ImageSource="/Images/Folder-add.png"/>
-                        </Button.Background>
-                    </Button>
-                    <Button Command="{commands:Command PixiEditor.Layer.DeleteSelected}" Height="24" Width="24" ToolTip="Delete selected" Cursor="Hand"
-                            HorizontalAlignment="Stretch" Margin="5,5,0,5"
-                            Style="{StaticResource ToolButtonStyle}">
-                        <Button.Background>
-                            <ImageBrush ImageSource="/Images/Trash.png"/>
-                        </Button.Background>
-                    </Button>
-                </StackPanel>
-                <StackPanel Orientation="Horizontal" DockPanel.Dock="Right" Margin="0,0,10,0" HorizontalAlignment="Right" Focusable="True">
-
-                </StackPanel>
+            <DockPanel HorizontalAlignment="Stretch">
+                <Button 
+                    Command="{commands:Command PixiEditor.Layer.NewLayer}" 
+                    DockPanel.Dock="Left"
+                    Height="24" Width="24" Cursor="Hand" ToolTip="New Layer"
+                    HorizontalAlignment="Stretch" Margin="5,5,0,5"
+                    Style="{StaticResource ToolButtonStyle}">
+                    <Button.Background>
+                        <ImageBrush ImageSource="/Images/Layer-add.png"/>
+                    </Button.Background>
+                </Button>
+                <Button 
+                    Command="{commands:Command PixiEditor.Layer.NewFolder}" 
+                    Height="24" Width="24" ToolTip="New Folder" Cursor="Hand"
+                    DockPanel.Dock="Left"
+                    HorizontalAlignment="Stretch"  Margin="5,5,0,5"
+                    Style="{StaticResource ToolButtonStyle}">
+                    <Button.Background>
+                        <ImageBrush ImageSource="/Images/Folder-add.png"/>
+                    </Button.Background>
+                </Button>
+                <Button 
+                    Command="{commands:Command PixiEditor.Layer.DeleteSelected}" Height="24" Width="24" ToolTip="Delete selected" Cursor="Hand"
+                    HorizontalAlignment="Stretch" Margin="5,5,0,5"
+                    DockPanel.Dock="Left"
+                    Style="{StaticResource ToolButtonStyle}">
+                    <Button.Background>
+                        <ImageBrush ImageSource="/Images/Trash.png"/>
+                    </Button.Background>
+                </Button>
+                <Button 
+                    Height="24" Width="24" ToolTip="Delete selected" Cursor="Hand"
+                    DockPanel.Dock="Right"
+                    HorizontalAlignment="Stretch" Margin="5"
+                    Style="{StaticResource ToolButtonStyle}"
+                    Command="{commands:Command PixiEditor.Layer.ToggleLockTransparency}">
+                    <Button.Background>
+                        <ImageBrush ImageSource="/Images/Lock-alpha.png"/>
+                    </Button.Background>
+                </Button>
+                <Grid/>
             </DockPanel>
             <DockPanel>
                 <userControls:BlendModeComboBox
@@ -86,7 +98,8 @@
                     Maximum="1"
                     SmallChange="0.01"
                     LargeChange="0.1"
-                    IsSnapToTickEnabled="False"
+                    IsSnapToTickEnabled="True"
+                    TickFrequency="0.01"
                     x:Name="opacitySlider"
                     VerticalAlignment="Center"
                     HorizontalAlignment="Stretch">