Pārlūkot izejas kodu

Basic layer selection

Equbuxu 3 gadi atpakaļ
vecāks
revīzija
1f3580dffd

+ 27 - 0
src/PixiEditor/Helpers/Converters/StructureMemberSelectionTypeToColorConverter.cs

@@ -0,0 +1,27 @@
+using System.Globalization;
+using System.Windows.Data;
+using System.Windows.Media;
+using PixiEditor.Models.Enums;
+
+namespace PixiEditor.Helpers.Converters;
+internal class StructureMemberSelectionTypeToColorConverter : IValueConverter
+{
+    public SolidColorBrush NoneColor { get; set; }
+    public SolidColorBrush SoftColor { get; set; }
+    public SolidColorBrush HardColor { get; set; }
+    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        return value switch
+        {
+            StructureMemberSelectionType.Hard => HardColor,
+            StructureMemberSelectionType.Soft => SoftColor,
+            StructureMemberSelectionType.None => NoneColor,
+            _ => NoneColor,
+        };
+    }
+
+    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        throw new NotImplementedException();
+    }
+}

+ 1 - 1
src/PixiEditor/Models/DocumentModels/DocumentStructureHelper.cs

@@ -16,7 +16,7 @@ internal class DocumentStructureHelper
 
     public void CreateNewStructureMember(StructureMemberType type)
     {
-        var member = doc.FindFirstSelectedMember();
+        var member = doc.SelectedStructureMember;
         if (member is null)
         {
             var guid = Guid.NewGuid();

+ 13 - 8
src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs

@@ -8,6 +8,7 @@ using PixiEditor.ChangeableDocument.ChangeInfos.Root;
 using PixiEditor.ChangeableDocument.ChangeInfos.Structure;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.Models.DocumentPassthroughActions;
+using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using SkiaSharp;
 
@@ -104,8 +105,10 @@ internal class DocumentUpdater
     {
         foreach (var oldMember in doc.SoftSelectedStructureMembers)
         {
-            oldMember.IsSoftSelected = false;
-            oldMember.RaisePropertyChanged(nameof(oldMember.IsSoftSelected));
+            if (oldMember.Selection == StructureMemberSelectionType.Hard)
+                continue;
+            oldMember.Selection = StructureMemberSelectionType.None;
+            oldMember.RaisePropertyChanged(nameof(oldMember.Selection));
         }
         doc.InternalClearSoftSelectedMembers();
     }
@@ -113,8 +116,10 @@ internal class DocumentUpdater
     private void ProcessAddSoftSelectedMember(AddSoftSelectedMember_PassthroughAction info)
     {
         var member = helper.StructureHelper.FindOrThrow(info.GuidValue);
-        member.IsSoftSelected = true;
-        member.RaisePropertyChanged(nameof(member.IsSoftSelected));
+        if (member.Selection == StructureMemberSelectionType.Hard)
+            return;
+        member.Selection = StructureMemberSelectionType.Soft;
+        member.RaisePropertyChanged(nameof(member.Selection));
         doc.InternalAddSoftSelectedMember(member);
     }
 
@@ -122,12 +127,12 @@ internal class DocumentUpdater
     {
         if (doc.SelectedStructureMember is { } oldMember)
         {
-            oldMember.IsSelected = false;
-            oldMember.RaisePropertyChanged(nameof(oldMember.IsSelected));
+            oldMember.Selection = StructureMemberSelectionType.None;
+            oldMember.RaisePropertyChanged(nameof(oldMember.Selection));
         }
         var member = helper.StructureHelper.FindOrThrow(info.GuidValue);
-        member.IsSelected = true;
-        member.RaisePropertyChanged(nameof(member.IsSelected));
+        member.Selection = StructureMemberSelectionType.Hard;
+        member.RaisePropertyChanged(nameof(member.Selection));
         doc.InternalSetSelectedMember(member);
     }
 

+ 7 - 0
src/PixiEditor/Models/Enums/StructureMemberSelectionType.cs

@@ -0,0 +1,7 @@
+namespace PixiEditor.Models.Enums;
+internal enum StructureMemberSelectionType
+{
+    None,
+    Soft,
+    Hard
+}

+ 2 - 0
src/PixiEditor/Styles/ThemeColors.xaml

@@ -11,4 +11,6 @@
     <SolidColorBrush x:Key="SelectionColor" Color="#999" />
     <SolidColorBrush x:Key="UIElementBlue" Color="#FF0077C9"/>
     <SolidColorBrush x:Key="UIElementBorder" Color="#3F3F46" />
+    <SolidColorBrush x:Key="SelectedLayerColor" Color="#505056" />
+    <SolidColorBrush x:Key="SoftSelectedLayerColor" Color="#7D505056" />
 </ResourceDictionary>

+ 14 - 10
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs

@@ -55,8 +55,6 @@ internal class DocumentViewModel : NotifyableObject
 
     public VecI SizeBindable => size;
 
-    public StructureMemberViewModel? FindFirstSelectedMember() => Helpers.StructureHelper.FindFirstWhere(member => member.IsSelected);
-
     public int HorizontalSymmetryAxisYBindable => horizontalSymmetryAxisY;
     public int VerticalSymmetryAxisXBindable => verticalSymmetryAxisX;
 
@@ -109,8 +107,6 @@ internal class DocumentViewModel : NotifyableObject
     private int horizontalSymmetryAxisY;
 
     private SKPath selectionPath = new SKPath();
-    private Guid testLayerGuid = Guid.NewGuid();
-
 
     public DocumentViewModel(DocumentManagerViewModel owner, string name)
     {
@@ -157,6 +153,7 @@ internal class DocumentViewModel : NotifyableObject
         PreviewBitmap = new WriteableBitmap(previewSize.X, previewSize.Y, 96, 96, PixelFormats.Pbgra32, null);
         PreviewSurface = SKSurface.Create(new SKImageInfo(previewSize.X, previewSize.Y, SKColorType.Bgra8888), PreviewBitmap.BackBuffer, PreviewBitmap.BackBufferStride);
 
+        Guid testLayerGuid = Guid.NewGuid();
         Helpers.ActionAccumulator.AddFinishedActions(new CreateStructureMember_Action(StructureRoot.GuidValue, testLayerGuid, 0, StructureMemberType.Layer));
         SetSelectedMember(testLayerGuid);
     }
@@ -224,6 +221,11 @@ internal class DocumentViewModel : NotifyableObject
         Helpers.ActionAccumulator.AddActions(new RemoveViewport_PassthroughAction(viewportGuid));
     }
 
+    public void CreateStructureMember(StructureMemberType type)
+    {
+        Helpers.StructureHelper.CreateNewStructureMember(type);
+    }
+
     public void SetSelectedMember(Guid memberGuid)
     {
         Helpers.ActionAccumulator.AddActions(new SetSelectedMember_PassthroughAction(memberGuid));
@@ -249,12 +251,14 @@ internal class DocumentViewModel : NotifyableObject
 
     }
 
-    private bool drawing = false;
+    private StructureMemberViewModel? drawingTarget = null;
     public void OnCanvasLeftMouseButtonDown(VecD pos)
     {
-        drawing = true;
+        if (SelectedStructureMember is null)
+            return;
+        drawingTarget = SelectedStructureMember;
         Helpers.ActionAccumulator.AddActions(new LineBasedPen_Action(
-            testLayerGuid,
+            drawingTarget.GuidValue,
             SKColors.Black,
             (VecI)pos,
             (int)1,
@@ -264,10 +268,10 @@ internal class DocumentViewModel : NotifyableObject
 
     public void OnCanvasMouseMove(VecD newPos)
     {
-        if (!drawing)
+        if (drawingTarget is null)
             return;
         Helpers.ActionAccumulator.AddActions(new LineBasedPen_Action(
-            testLayerGuid,
+            drawingTarget.GuidValue,
             SKColors.Black,
             (VecI)newPos,
             (int)1,
@@ -277,7 +281,7 @@ internal class DocumentViewModel : NotifyableObject
 
     public void OnCanvasLeftMouseButtonUp()
     {
-        drawing = false;
+        drawingTarget = null;
         Helpers.ActionAccumulator.AddFinishedActions(new EndLineBasedPen_Action());
     }
 }

+ 2 - 2
src/PixiEditor/ViewModels/SubViewModels/Document/StructureMemberViewModel.cs

@@ -6,6 +6,7 @@ using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DocumentModels;
+using PixiEditor.Models.Enums;
 using SkiaSharp;
 
 namespace PixiEditor.ViewModels.SubViewModels.Document;
@@ -106,8 +107,7 @@ internal abstract class StructureMemberViewModel : INotifyPropertyChanged
         get => opacity;
     }
 
-    public bool IsSelected { get; set; }
-    public bool IsSoftSelected { get; set; }
+    public StructureMemberSelectionType Selection { get; set; }
     public bool ShouldDrawOnMask { get; set; }
 
     public const int PreviewSize = 48;

+ 13 - 15
src/PixiEditor/ViewModels/SubViewModels/Main/LayersViewModel.cs

@@ -1,15 +1,14 @@
 using System.Windows.Input;
+using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Commands.Attributes.Commands;
 using PixiEditor.Models.Commands.Attributes.Evaluators;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
-
+#nullable enable
 [Command.Group("PixiEditor.Layer", "Image")]
 internal class LayersViewModel : SubViewModel<ViewModelMain>
 {
-    public RelayCommand SetActiveLayerCommand { get; set; }
-
     public RelayCommand CreateGroupFromActiveLayersCommand { get; set; }
 
     public RelayCommand DeleteGroupCommand { get; set; }
@@ -35,7 +34,6 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     public LayersViewModel(ViewModelMain owner)
         : base(owner)
     {
-        SetActiveLayerCommand = new RelayCommand(SetActiveLayer);
         CreateGroupFromActiveLayersCommand = new RelayCommand(CreateGroupFromActiveLayers, CanCreateGroupFromSelected);
         DeleteLayersCommand = new RelayCommand(DeleteActiveLayers, CanDeleteActiveLayers);
         DuplicateLayerCommand = new RelayCommand(DuplicateLayer, CanDuplicateLayer);
@@ -120,15 +118,12 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     {
     }
 
-    [Command.Basic("PixiEditor.Layer.NewFolder", "New Folder", "Create new folder", CanExecute = "PixiEditor.HasDocument")]
+    [Command.Basic("PixiEditor.Layer.NewFolder", "New Folder", "Create new folder", CanExecute = "PixiEditor.Layer.CanCreateNewMember")]
     public void NewFolder(object parameter)
     {
-
-    }
-
-    public bool CanAddNewGroup(object property)
-    {
-        return CanCreateNewLayer(property) && false;
+        if (Owner.DocumentManagerSubViewModel.ActiveDocument is not { } doc)
+            return;
+        doc.CreateStructureMember(StructureMemberType.Folder);
     }
 
     public bool CanMergeSelected(object obj)
@@ -141,15 +136,18 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
         return false;
     }
 
-    [Command.Basic("PixiEditor.Layer.New", "New Layer", "Create new layer", CanExecute = "PixiEditor.HasDocument", Key = Key.N, Modifiers = ModifierKeys.Control | ModifierKeys.Shift, IconPath = "Layer-add.png")]
+    [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)
     {
-
+        if (Owner.DocumentManagerSubViewModel.ActiveDocument is not { } doc)
+            return;
+        doc.CreateStructureMember(StructureMemberType.Layer);
     }
 
-    public bool CanCreateNewLayer(object parameter)
+    [Evaluator.CanExecute("PixiEditor.Layer.CanCreateNewMember")]
+    public bool CanCreateNewMember(object parameter)
     {
-        return false;
+        return Owner.DocumentManagerSubViewModel.ActiveDocument is not null;
     }
 
     public void SetActiveLayer(object parameter)

+ 23 - 6
src/PixiEditor/Views/UserControls/Layers/FolderControl.xaml

@@ -10,11 +10,27 @@
              xmlns:userControls1="clr-namespace:PixiEditor.Views.UserControls"
              mc:Ignorable="d" 
              Focusable="True"
-             d:DesignHeight="60" d:DesignWidth="250" Name="folderControl" DragEnter="FolderControl_DragEnter" DragLeave="FolderControl_DragLeave" DragDrop.Drop="FolderControl_DragLeave">
+             d:DesignHeight="60" 
+             d:DesignWidth="250" 
+             x:Name="folderControl" 
+             DragEnter="FolderControl_DragEnter" 
+             DragLeave="FolderControl_DragLeave" 
+             DragDrop.Drop="FolderControl_DragLeave">
     <UserControl.Resources>
         <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
     </UserControl.Resources>
     <Border BorderThickness="0 0 0 0.5" BorderBrush="Gray" MinWidth="60" Focusable="True" Tag="{Binding ElementName=folderControl}" MouseDown="Border_MouseDown">
+        <Border.Background>
+            <Binding ElementName="folderControl" Path="Folder.Selection">
+                <Binding.Converter>
+                    <converters:StructureMemberSelectionTypeToColorConverter
+                        SoftColor="{StaticResource SoftSelectedLayerColor}"
+                        HardColor="{StaticResource SelectedLayerColor}"
+                        NoneColor="Transparent"
+                        />
+                </Binding.Converter>
+            </Binding>
+        </Border.Background>
         <i:Interaction.Behaviors>
             <behaviors:ClearFocusOnClickBehavior/>
         </i:Interaction.Behaviors>
@@ -33,7 +49,7 @@
                 </Grid.ColumnDefinitions>
                 <CheckBox Style="{StaticResource ImageCheckBox}" VerticalAlignment="Center"
                       IsThreeState="False" HorizontalAlignment="Center" Click="CheckBox_Checked"
-                      IsChecked="{Binding Path=IsVisibleUndoTriggerable, ElementName=folderControl}" Grid.Column="0" Height="16"/>
+                      IsChecked="{Binding Path=Folder.IsVisibleBindable, ElementName=folderControl}" Grid.Column="0" Height="16"/>
 
                 <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Left">
                     <Rectangle Width="{Binding Path=(helpers:TreeViewItemHelper.Indent).Value, Mode=OneWay, RelativeSource={RelativeSource AncestorType=ItemsPresenter}}" Fill="Transparent" StrokeThickness="0"/>
@@ -41,18 +57,19 @@
                     <StackPanel Grid.Row="1" Orientation="Horizontal" Grid.Column="0" HorizontalAlignment="Left">
                         <Border Width="30" Height="30" BorderThickness="1" BorderBrush="Black" Background="{StaticResource MainColor}"
                            Margin="5, 0, 10, 0">
-                            <Image Source="{Binding PreviewImage, ElementName=folderControl}" Stretch="Uniform" Width="20" Height="20">
+                            <Image Source="{Binding Folder.PreviewBitmap, ElementName=folderControl}" Stretch="Uniform" Width="20" Height="20">
                                 <RenderOptions.BitmapScalingMode>
                                     <MultiBinding Converter="{converters:WidthToBitmapScalingModeConverter}">
-                                        <Binding Path="PreviewImage.PixelWidth" ElementName="folderControl"/>
+                                        <Binding Path="Folder.PreviewBitmap.PixelWidth" ElementName="folderControl"/>
                                         <Binding RelativeSource="{RelativeSource Mode=Self}" Path="ActualWidth"/>
                                     </MultiBinding>
                                 </RenderOptions.BitmapScalingMode>
                             </Image>
                         </Border>
                         <userControls1:EditableTextBlock
-                    FontSize="16"
-                    VerticalAlignment="Center" />
+                            FontSize="15"
+                            VerticalAlignment="Center"
+                            Text="{Binding Folder.NameBindable, ElementName=folderControl, Mode=TwoWay}" />
                     </StackPanel>
                     <Image Source="/Images/Folder.png" Height="20" Margin="0,0,10,0" HorizontalAlignment="Right"/>
                 </StackPanel>

+ 1 - 0
src/PixiEditor/Views/UserControls/Layers/FolderControl.xaml.cs

@@ -143,6 +143,7 @@ internal partial class FolderControl : UserControl
 
     private void Border_MouseDown(object sender, MouseButtonEventArgs e)
     {
+        Folder?.Document.SetSelectedMember(Folder.GuidValue);
         /*
             var doc = LayersViewModel.Owner.BitmapManager.ActiveDocument;
             var layer = doc.Layers.First(x => x.GuidValue == GroupData.EndLayerGuid);

+ 16 - 5
src/PixiEditor/Views/UserControls/Layers/LayerControl.xaml

@@ -5,6 +5,7 @@
              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:conv="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:controls="clr-namespace:PixiEditor.Views.UserControls"
              xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
              xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours"
@@ -12,8 +13,18 @@
              mc:Ignorable="d" Focusable="True"
              d:DesignHeight="60" d:DesignWidth="250" Name="uc"
              MouseLeave="LayerItem_OnMouseLeave" MouseEnter="LayerItem_OnMouseEnter">
-    <Border BorderThickness="0 0 0 0.5" BorderBrush="Gray" MinWidth="60" Focusable="True"
-            Background="{Binding LayerColor, ElementName=uc}" MouseDown="Border_MouseDown">
+    <Border BorderThickness="0 0 0 0.5" BorderBrush="Gray" MinWidth="60" Focusable="True" MouseDown="Border_MouseDown">
+        <Border.Background>
+            <Binding ElementName="uc" Path="Layer.Selection">
+                <Binding.Converter>
+                    <conv:StructureMemberSelectionTypeToColorConverter
+                        SoftColor="{StaticResource SoftSelectedLayerColor}"
+                        HardColor="{StaticResource SelectedLayerColor}"
+                        NoneColor="Transparent"
+                        />
+                </Binding.Converter>
+            </Binding>
+        </Border.Background>
         <i:Interaction.Behaviors>
             <behaviors:ClearFocusOnClickBehavior/>
         </i:Interaction.Behaviors>
@@ -41,9 +52,9 @@
                     </Border>
 
                     <controls:EditableTextBlock
-                    IsEditing="{Binding IsRenaming, ElementName=uc, Mode=TwoWay}" FontSize="15"
-                    VerticalAlignment="Center"
-                    Text="{Binding Layer.NameBindable, ElementName=uc, Mode=TwoWay}" />
+                        FontSize="15"
+                        VerticalAlignment="Center"
+                        Text="{Binding Layer.NameBindable, ElementName=uc, Mode=TwoWay}" />
                 </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"/>
                 <Grid Margin="0, 0, 0, -2.5" VerticalAlignment="Bottom" Height="10" Grid.Row="2" Grid.Column="1" Background="{Binding ElementName=dropBelowGrid, Path=Background}"/>

+ 1 - 1
src/PixiEditor/Views/UserControls/Layers/LayersManager.xaml

@@ -21,7 +21,7 @@
         </Grid.RowDefinitions>
         <DockPanel Background="{StaticResource MainColor}" Grid.Row="0" HorizontalAlignment="Stretch">
             <StackPanel Orientation="Horizontal" DockPanel.Dock="Left">
-                <Button Command="{commands:Command PixiEditor.Layer.New}" 
+                <Button Command="{commands:Command PixiEditor.Layer.NewLayer}" 
                         Height="24" Width="24" Cursor="Hand" ToolTip="New Layer"
                         CommandParameter="{Binding Path=SelectedItem, ElementName=layersManager}"
                                                 HorizontalAlignment="Stretch" Margin="5"