Explorar o código

Layer selection wip

Equbuxu %!s(int64=3) %!d(string=hai) anos
pai
achega
2dad718980

+ 50 - 7
src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs

@@ -7,7 +7,7 @@ using PixiEditor.ChangeableDocument.ChangeInfos.Properties;
 using PixiEditor.ChangeableDocument.ChangeInfos.Root;
 using PixiEditor.ChangeableDocument.ChangeInfos.Structure;
 using PixiEditor.ChangeableDocument.Enums;
-using PixiEditor.Models.BitmapActions;
+using PixiEditor.Models.DocumentPassthroughActions;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using SkiaSharp;
 
@@ -88,7 +88,47 @@ internal class DocumentUpdater
             case CreateReferenceLayer_ChangeInfo info:
                 ProcessCreateReferenceLayer(info);
                 break;
+            case SetSelectedMember_PassthroughAction info:
+                ProcessSetSelectedMember(info);
+                break;
+            case AddSoftSelectedMember_PassthroughAction info:
+                ProcessAddSoftSelectedMember(info);
+                break;
+            case ClearSoftSelectedMembers_PassthroughAction info:
+                ProcessClearSoftSelectedMembers(info);
+                break;
+        }
+    }
+
+    private void ProcessClearSoftSelectedMembers(ClearSoftSelectedMembers_PassthroughAction info)
+    {
+        foreach (var oldMember in doc.SoftSelectedStructureMembers)
+        {
+            oldMember.IsSoftSelected = false;
+            oldMember.RaisePropertyChanged(nameof(oldMember.IsSoftSelected));
+        }
+        doc.InternalClearSoftSelectedMembers();
+    }
+
+    private void ProcessAddSoftSelectedMember(AddSoftSelectedMember_PassthroughAction info)
+    {
+        var member = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        member.IsSoftSelected = true;
+        member.RaisePropertyChanged(nameof(member.IsSoftSelected));
+        doc.InternalAddSoftSelectedMember(member);
+    }
+
+    private void ProcessSetSelectedMember(SetSelectedMember_PassthroughAction info)
+    {
+        if (doc.SelectedStructureMember is { } oldMember)
+        {
+            oldMember.IsSelected = false;
+            oldMember.RaisePropertyChanged(nameof(oldMember.IsSelected));
         }
+        var member = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        member.IsSelected = true;
+        member.RaisePropertyChanged(nameof(member.IsSelected));
+        doc.InternalSetSelectedMember(member);
     }
 
     private void ProcessCreateReferenceLayer(CreateReferenceLayer_ChangeInfo info)
@@ -115,17 +155,17 @@ internal class DocumentUpdater
     private void ProcessSymmetryPosition(SymmetryAxisPosition_ChangeInfo info)
     {
         if (info.Direction == SymmetryAxisDirection.Horizontal)
-            doc.SetHorizontalSymmetryAxisY(info.NewPosition);
+            doc.InternalSetHorizontalSymmetryAxisY(info.NewPosition);
         else if (info.Direction == SymmetryAxisDirection.Vertical)
-            doc.SetVerticalSymmetryAxisX(info.NewPosition);
+            doc.InternalSetVerticalSymmetryAxisX(info.NewPosition);
     }
 
     private void ProcessSymmetryState(SymmetryAxisState_ChangeInfo info)
     {
         if (info.Direction == SymmetryAxisDirection.Horizontal)
-            doc.SetHorizontalSymmetryAxisEnabled(info.State);
+            doc.InternalSetHorizontalSymmetryAxisEnabled(info.State);
         else if (info.Direction == SymmetryAxisDirection.Vertical)
-            doc.SetVerticalSymmetryAxisEnabled(info.State);
+            doc.InternalSetVerticalSymmetryAxisEnabled(info.State);
     }
 
     private void ProcessSelection(Selection_ChangeInfo info)
@@ -211,8 +251,8 @@ internal class DocumentUpdater
         doc.Bitmaps = newBitmaps;
 
         doc.InternalSetSize(info.Size);
-        doc.SetVerticalSymmetryAxisX(info.VerticalSymmetryAxisX);
-        doc.SetHorizontalSymmetryAxisY(info.HorizontalSymmetryAxisY);
+        doc.InternalSetVerticalSymmetryAxisX(info.VerticalSymmetryAxisX);
+        doc.InternalSetHorizontalSymmetryAxisY(info.HorizontalSymmetryAxisY);
 
         var previewSize = StructureMemberViewModel.CalculatePreviewSize(info.Size);
         doc.PreviewSurface.Dispose();
@@ -286,6 +326,9 @@ internal class DocumentUpdater
     {
         var (memberVM, folderVM) = helper.StructureHelper.FindChildAndParentOrThrow(info.GuidValue);
         folderVM.Children.Remove(memberVM);
+        if (doc.SelectedStructureMember == memberVM)
+            doc.InternalSetSelectedMember(null);
+        doc.InternalClearSoftSelectedMembers();
     }
 
     private void ProcessUpdateStructureMemberIsVisible(StructureMemberIsVisible_ChangeInfo info)

+ 5 - 0
src/PixiEditor/Models/DocumentPassthroughActions/AddSoftSelectedMember_PassthroughAction.cs

@@ -0,0 +1,5 @@
+using PixiEditor.ChangeableDocument.Actions;
+using PixiEditor.ChangeableDocument.ChangeInfos;
+
+namespace PixiEditor.Models.DocumentPassthroughActions;
+internal record class AddSoftSelectedMember_PassthroughAction(Guid GuidValue) : IChangeInfo, IAction;

+ 5 - 0
src/PixiEditor/Models/DocumentPassthroughActions/ClearSoftSelectedMembers_PassthroughAction.cs

@@ -0,0 +1,5 @@
+using PixiEditor.ChangeableDocument.Actions;
+using PixiEditor.ChangeableDocument.ChangeInfos;
+
+namespace PixiEditor.Models.DocumentPassthroughActions;
+internal record class ClearSoftSelectedMembers_PassthroughAction() : IChangeInfo, IAction;

+ 1 - 1
src/PixiEditor/Models/BitmapActions/RefreshViewport_PassthroughAction.cs → src/PixiEditor/Models/DocumentPassthroughActions/RefreshViewport_PassthroughAction.cs

@@ -2,6 +2,6 @@
 using PixiEditor.ChangeableDocument.ChangeInfos;
 using PixiEditor.Models.Position;
 
-namespace PixiEditor.Models.BitmapActions;
+namespace PixiEditor.Models.DocumentPassthroughActions;
 
 internal record class RefreshViewport_PassthroughAction(ViewportInfo Info) : IAction, IChangeInfo;

+ 1 - 1
src/PixiEditor/Models/BitmapActions/RemoveViewport_PassthroughAction.cs → src/PixiEditor/Models/DocumentPassthroughActions/RemoveViewport_PassthroughAction.cs

@@ -1,5 +1,5 @@
 using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.ChangeableDocument.ChangeInfos;
 
-namespace PixiEditor.Models.BitmapActions;
+namespace PixiEditor.Models.DocumentPassthroughActions;
 internal record class RemoveViewport_PassthroughAction(Guid GuidValue) : IAction, IChangeInfo;

+ 5 - 0
src/PixiEditor/Models/DocumentPassthroughActions/SetSelectedMember_PassthroughAction.cs

@@ -0,0 +1,5 @@
+using PixiEditor.ChangeableDocument.Actions;
+using PixiEditor.ChangeableDocument.ChangeInfos;
+
+namespace PixiEditor.Models.DocumentPassthroughActions;
+internal record class SetSelectedMember_PassthroughAction(Guid GuidValue) : IAction, IChangeInfo;

+ 52 - 23
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs

@@ -7,8 +7,8 @@ using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.Helpers;
-using PixiEditor.Models.BitmapActions;
 using PixiEditor.Models.DocumentModels;
+using PixiEditor.Models.DocumentPassthroughActions;
 using PixiEditor.Models.Position;
 using SkiaSharp;
 
@@ -35,7 +35,10 @@ internal class DocumentViewModel : NotifyableObject
     public int Width => size.X;
     public int Height => size.Y;
 
-    public StructureMemberViewModel? SelectedStructureMember => FindFirstSelectedMember();
+    public StructureMemberViewModel? SelectedStructureMember { get; private set; } = null;
+
+    private HashSet<StructureMemberViewModel> softSelectedStructureMembers = new();
+    public IReadOnlyCollection<StructureMemberViewModel> SoftSelectedStructureMembers => softSelectedStructureMembers;
 
     public Dictionary<ChunkResolution, WriteableBitmap> Bitmaps { get; set; } = new()
     {
@@ -155,42 +158,60 @@ internal class DocumentViewModel : NotifyableObject
         PreviewSurface = SKSurface.Create(new SKImageInfo(previewSize.X, previewSize.Y, SKColorType.Bgra8888), PreviewBitmap.BackBuffer, PreviewBitmap.BackBufferStride);
 
         Helpers.ActionAccumulator.AddFinishedActions(new CreateStructureMember_Action(StructureRoot.GuidValue, testLayerGuid, 0, StructureMemberType.Layer));
+        SetSelectedMember(testLayerGuid);
     }
 
-    public void InternalSetSize(VecI size)
-    {
-        this.size = size;
-        RaisePropertyChanged(nameof(SizeBindable));
-        RaisePropertyChanged(nameof(Width));
-        RaisePropertyChanged(nameof(Height));
-    }
-
-    #region Symmetry
-
-    public void SetVerticalSymmetryAxisEnabled(bool verticalSymmetryAxisEnabled)
+    #region Internal Methods
+    // these are intended to only be called from DocumentUpdater
+    public void InternalSetVerticalSymmetryAxisEnabled(bool verticalSymmetryAxisEnabled)
     {
         this.verticalSymmetryAxisEnabled = verticalSymmetryAxisEnabled;
         RaisePropertyChanged(nameof(VerticalSymmetryAxisEnabledBindable));
     }
 
-    public void SetHorizontalSymmetryAxisEnabled(bool horizontalSymmetryAxisEnabled)
+    public void InternalSetHorizontalSymmetryAxisEnabled(bool horizontalSymmetryAxisEnabled)
     {
         this.horizontalSymmetryAxisEnabled = horizontalSymmetryAxisEnabled;
         RaisePropertyChanged(nameof(HorizontalSymmetryAxisEnabledBindable));
     }
 
-    public void SetVerticalSymmetryAxisX(int verticalSymmetryAxisX)
+    public void InternalSetVerticalSymmetryAxisX(int verticalSymmetryAxisX)
     {
         this.verticalSymmetryAxisX = verticalSymmetryAxisX;
         RaisePropertyChanged(nameof(VerticalSymmetryAxisXBindable));
     }
 
-    public void SetHorizontalSymmetryAxisY(int horizontalSymmetryAxisY)
+    public void InternalSetHorizontalSymmetryAxisY(int horizontalSymmetryAxisY)
     {
         this.horizontalSymmetryAxisY = horizontalSymmetryAxisY;
         RaisePropertyChanged(nameof(HorizontalSymmetryAxisYBindable));
     }
 
+    public void InternalSetSize(VecI size)
+    {
+        this.size = size;
+        RaisePropertyChanged(nameof(SizeBindable));
+        RaisePropertyChanged(nameof(Width));
+        RaisePropertyChanged(nameof(Height));
+    }
+
+    public void InternalUpdateSelectionPath(SKPath selectionPath)
+    {
+        (var toDispose, this.selectionPath) = (this.selectionPath, selectionPath);
+        toDispose.Dispose();
+        RaisePropertyChanged(nameof(SelectionPathBindable));
+    }
+
+    public void InternalSetSelectedMember(StructureMemberViewModel? member)
+    {
+        SelectedStructureMember = member;
+        RaisePropertyChanged(nameof(SelectedStructureMember));
+    }
+
+    public void InternalClearSoftSelectedMembers() => softSelectedStructureMembers.Clear();
+
+    public void InternalAddSoftSelectedMember(StructureMemberViewModel member) => softSelectedStructureMembers.Add(member);
+
     #endregion
 
     public void AddOrUpdateViewport(ViewportInfo info)
@@ -203,6 +224,21 @@ internal class DocumentViewModel : NotifyableObject
         Helpers.ActionAccumulator.AddActions(new RemoveViewport_PassthroughAction(viewportGuid));
     }
 
+    public void SetSelectedMember(Guid memberGuid)
+    {
+        Helpers.ActionAccumulator.AddActions(new SetSelectedMember_PassthroughAction(memberGuid));
+    }
+
+    public void AddSoftSelectedMember(Guid memberGuid)
+    {
+        Helpers.ActionAccumulator.AddActions(new AddSoftSelectedMember_PassthroughAction(memberGuid));
+    }
+
+    public void ClearSoftSelectedMembers()
+    {
+        Helpers.ActionAccumulator.AddActions(new ClearSoftSelectedMembers_PassthroughAction());
+    }
+
     public void OnKeyDown(Key args)
     {
 
@@ -244,11 +280,4 @@ internal class DocumentViewModel : NotifyableObject
         drawing = false;
         Helpers.ActionAccumulator.AddFinishedActions(new EndLineBasedPen_Action());
     }
-
-    public void InternalUpdateSelectionPath(SKPath selectionPath)
-    {
-        (var toDispose, this.selectionPath) = (this.selectionPath, selectionPath);
-        toDispose.Dispose();
-        RaisePropertyChanged(nameof(SelectionPathBindable));
-    }
 }

+ 3 - 12
src/PixiEditor/ViewModels/SubViewModels/Document/StructureMemberViewModel.cs

@@ -13,7 +13,7 @@ namespace PixiEditor.ViewModels.SubViewModels.Document;
 internal abstract class StructureMemberViewModel : INotifyPropertyChanged
 {
     public event PropertyChangedEventHandler? PropertyChanged;
-    protected DocumentViewModel Document { get; }
+    public DocumentViewModel Document { get; }
     protected DocumentHelpers Helpers { get; }
 
 
@@ -106,19 +106,10 @@ internal abstract class StructureMemberViewModel : INotifyPropertyChanged
         get => opacity;
     }
 
-    private bool isSelected;
-    public bool IsSelected
-    {
-        get => isSelected;
-        set
-        {
-            isSelected = value;
-            Document.RaisePropertyChanged(nameof(Document.SelectedStructureMember));
-        }
-    }
+    public bool IsSelected { get; set; }
+    public bool IsSoftSelected { get; set; }
     public bool ShouldDrawOnMask { get; set; }
 
-
     public const int PreviewSize = 48;
     public WriteableBitmap PreviewBitmap { get; set; }
     public SKSurface PreviewSurface { get; set; }

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

@@ -7,8 +7,6 @@ namespace PixiEditor.Views.UserControls.Layers;
 
 internal partial class FolderControl : UserControl
 {
-    public static string FolderControlDataName = typeof(FolderControl).FullName;
-
     public static readonly DependencyProperty FolderProperty =
         DependencyProperty.Register(nameof(Folder), typeof(FolderViewModel), typeof(FolderControl), new(null));
 
@@ -18,6 +16,8 @@ internal partial class FolderControl : UserControl
         set => SetValue(FolderProperty, value);
     }
 
+    public static string FolderControlDataName = typeof(FolderControl).FullName;
+
     public FolderControl()
     {
         InitializeComponent();

+ 1 - 9
src/PixiEditor/Views/UserControls/Layers/LayerControl.xaml

@@ -13,22 +13,14 @@
              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}" >
+            Background="{Binding LayerColor, ElementName=uc}" MouseDown="Border_MouseDown">
         <i:Interaction.Behaviors>
             <behaviors:ClearFocusOnClickBehavior/>
         </i:Interaction.Behaviors>
-        <i:Interaction.Triggers>
-            <i:EventTrigger EventName="MouseDown">
-                <i:InvokeCommandAction Command="{Binding ElementName=uc, 
-                            Path=SetActiveLayerCommand}"
-                                       CommandParameter="{Binding Path=LayerIndex, ElementName=uc}"/>
-            </i:EventTrigger>
-        </i:Interaction.Triggers>
         <Grid>
             <Grid.RowDefinitions>
                 <RowDefinition Height="10"/>
                 <RowDefinition Height="25"/>
-
             </Grid.RowDefinitions>
             <Grid AllowDrop="True" DragEnter="Grid_DragEnter" Drop="Grid_Drop_Top" DragLeave="Grid_DragLeave" Grid.Row="0" Grid.ColumnSpan="3" Background="Transparent"/>
             <Grid Grid.Row="1" Grid.RowSpan="3" Margin="0,-10,0,0" VerticalAlignment="Center" AllowDrop="False">

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

@@ -25,15 +25,6 @@ internal partial class LayerControl : UserControl
         InitializeComponent();
     }
 
-    public static readonly DependencyProperty SetActiveLayerCommandProperty = DependencyProperty.Register(
-        nameof(SetActiveLayerCommand), typeof(RelayCommand), typeof(LayerControl), new PropertyMetadata(default(RelayCommand)));
-
-    public RelayCommand SetActiveLayerCommand
-    {
-        get { return (RelayCommand)GetValue(SetActiveLayerCommandProperty); }
-        set { SetValue(SetActiveLayerCommandProperty, value); }
-    }
-
     public static readonly DependencyProperty ControlButtonsVisibleProperty = DependencyProperty.Register(
         nameof(ControlButtonsVisible), typeof(Visibility), typeof(LayerControl), new PropertyMetadata(System.Windows.Visibility.Hidden));
 
@@ -153,4 +144,9 @@ internal partial class LayerControl : UserControl
     {
         HandleGridDrop(sender, e, false, true);
     }
+
+    private void Border_MouseDown(object sender, MouseButtonEventArgs e)
+    {
+        Layer?.Document.SetSelectedMember(Layer.GuidValue);
+    }
 }