Ver Fonte

Merge pull request #433 from PixiEditor/ux-improvements

random ui stuff
Krzysztof Krysiński há 2 anos atrás
pai
commit
1aae34def8
21 ficheiros alterados com 95 adições e 58 exclusões
  1. 9 8
      src/PixiEditor.ChangeableDocument/Changes/Drawing/TransformSelectedArea_UpdateableChange.cs
  2. 1 2
      src/PixiEditor.ChangeableDocument/Changes/Selection/SelectionChangeHelper.cs
  3. 2 2
      src/PixiEditor.ChangeableDocument/Changes/Selection/TransformSelectionPath_UpdateableChange.cs
  4. 1 8
      src/PixiEditor/Helpers/Behaviours/TextBoxFocusBehavior.cs
  5. 26 0
      src/PixiEditor/Helpers/FocusHelper.cs
  6. 8 5
      src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs
  7. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PasteImageExecutor.cs
  8. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ShapeToolExecutor.cs
  9. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/TransformReferenceLayerExecutor.cs
  10. 4 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/TransformSelectedAreaExecutor.cs
  11. 10 1
      src/PixiEditor/ViewModels/SubViewModels/Document/DocumentTransformViewModel.cs
  12. 0 1
      src/PixiEditor/ViewModels/SubViewModels/Main/ToolsViewModel.cs
  13. 0 5
      src/PixiEditor/ViewModels/SubViewModels/Tools/ShapeTool.cs
  14. 4 2
      src/PixiEditor/ViewModels/SubViewModels/Tools/ToolViewModel.cs
  15. 0 5
      src/PixiEditor/ViewModels/SubViewModels/Tools/Tools/MoveToolViewModel.cs
  16. 5 3
      src/PixiEditor/ViewModels/SubViewModels/Tools/Tools/MoveViewportToolViewModel.cs
  17. 3 3
      src/PixiEditor/ViewModels/SubViewModels/Tools/Tools/RotateViewportToolViewModel.cs
  18. 4 4
      src/PixiEditor/Views/Dialogs/SettingGroups/ShortcutsBinder.xaml
  19. 3 0
      src/PixiEditor/Views/UserControls/KeyCombinationBox.xaml.cs
  20. 11 4
      src/PixiEditor/Views/UserControls/Overlays/SelectionOverlay.cs
  21. 1 1
      src/PixiEditor/Views/UserControls/Viewport.xaml

+ 9 - 8
src/PixiEditor.ChangeableDocument/Changes/Drawing/TransformSelectedArea_UpdateableChange.cs

@@ -15,9 +15,10 @@ internal class TransformSelectedArea_UpdateableChange : UpdateableChange
 
     private Dictionary<Guid, (Surface surface, VecI pos)>? images;
     private Matrix3X3 globalMatrix;
-    private RectI originalTightBounds;
     private Dictionary<Guid, CommittedChunkStorage>? savedChunks;
 
+    private RectD originalTightBounds;
+    private RectI roundedTightBounds;
     private VectorPath? originalPath;
 
     private bool hasEnqueudImages = false;
@@ -49,21 +50,21 @@ internal class TransformSelectedArea_UpdateableChange : UpdateableChange
         }
 
         originalPath = new VectorPath(target.Selection.SelectionPath) { FillType = PathFillType.EvenOdd };
-        RectI bounds = (RectI)originalPath.TightBounds;
+        
+        originalTightBounds = originalPath.TightBounds;
+        roundedTightBounds = (RectI)originalTightBounds.RoundOutwards();
+        //boundsRoundingOffset = bounds.TopLeft - roundedBounds.TopLeft;
 
         images = new();
         foreach (var guid in membersToTransform)
         {
             ChunkyImage image = DrawingChangeHelper.GetTargetImageOrThrow(target, guid, drawOnMask);
-            var extracted = ExtractArea(image, originalPath, bounds);
+            var extracted = ExtractArea(image, originalPath, roundedTightBounds);
             if (extracted.IsT0)
                 continue;
             images.Add(guid, (extracted.AsT1.image, extracted.AsT1.extractedRect.Pos));
         }
 
-        if (images.Count == 0)
-            return false;
-        originalTightBounds = bounds;
         globalMatrix = OperationHelper.CreateMatrixFromPoints(corners, originalTightBounds.Size);
         return true;
     }
@@ -108,8 +109,8 @@ internal class TransformSelectedArea_UpdateableChange : UpdateableChange
         memberImage.CancelChanges();
 
         if (!keepOriginal)
-            memberImage.EnqueueClearPath(originalPath!, originalTightBounds);
-        Matrix3X3 localMatrix = Matrix3X3.CreateTranslation(originalPos.X - originalTightBounds.Left, originalPos.Y - originalTightBounds.Top);
+            memberImage.EnqueueClearPath(originalPath!, roundedTightBounds);
+        Matrix3X3 localMatrix = Matrix3X3.CreateTranslation(originalPos.X - (float)originalTightBounds.Left, originalPos.Y - (float)originalTightBounds.Top);
         localMatrix = localMatrix.PostConcat(globalMatrix);
         memberImage.EnqueueDrawImage(localMatrix, image, RegularPaint, false);
         hasEnqueudImages = true;

+ 1 - 2
src/PixiEditor.ChangeableDocument/Changes/Selection/SelectionChangeHelper.cs

@@ -6,14 +6,13 @@ namespace PixiEditor.ChangeableDocument.Changes.Selection;
 internal class SelectionChangeHelper
 {
     public static Selection_ChangeInfo DoSelectionTransform(
-        Document target, VectorPath originalPath, RectI originalPathTightBounds, ShapeCorners to)
+        Document target, VectorPath originalPath, RectD originalPathTightBounds, ShapeCorners to)
     {
         VectorPath newPath = new(originalPath);
 
         var matrix = Matrix3X3.CreateTranslation((float)-originalPathTightBounds.X, (float)-originalPathTightBounds.Y).PostConcat(
             OperationHelper.CreateMatrixFromPoints(to, originalPathTightBounds.Size));
         newPath.Transform(matrix);
-
         var toDispose = target.Selection.SelectionPath;
         target.Selection.SelectionPath = newPath;
         toDispose.Dispose();

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changes/Selection/TransformSelectionPath_UpdateableChange.cs

@@ -5,7 +5,7 @@ namespace PixiEditor.ChangeableDocument.Changes.Selection;
 internal class TransformSelectionPath_UpdateableChange : UpdateableChange
 {
     private VectorPath? originalPath;
-    private RectI originalTightBounds;
+    private RectD originalTightBounds;
     private ShapeCorners newCorners;
 
     [GenerateUpdateableChangeActions]
@@ -25,7 +25,7 @@ internal class TransformSelectionPath_UpdateableChange : UpdateableChange
         if (target.Selection.SelectionPath.IsEmpty)
             return false;
         originalPath = new(target.Selection.SelectionPath);
-        originalTightBounds = (RectI)originalPath.TightBounds;
+        originalTightBounds = originalPath.TightBounds;
         return true;
     }
 

+ 1 - 8
src/PixiEditor/Helpers/Behaviours/TextBoxFocusBehavior.cs

@@ -87,14 +87,7 @@ internal class TextBoxFocusBehavior : Behavior<TextBox>
     {
         if (!FocusNext)
         {
-            FrameworkElement parent = (FrameworkElement)AssociatedObject.Parent;
-            while (parent is IInputElement elem && !elem.Focusable)
-            {
-                parent = (FrameworkElement)parent.Parent;
-            }
-
-            DependencyObject scope = FocusManager.GetFocusScope(AssociatedObject);
-            FocusManager.SetFocusedElement(scope, parent);
+            FocusHelper.MoveFocusToParent(AssociatedObject);
         }
         else
         {

+ 26 - 0
src/PixiEditor/Helpers/FocusHelper.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Media;
+
+namespace PixiEditor.Helpers;
+
+internal static class FocusHelper
+{
+    public static void MoveFocusToParent(FrameworkElement element)
+    {
+        FrameworkElement parent = (FrameworkElement)VisualTreeHelper.GetParent(element);
+
+        while (parent is IInputElement elem && !elem.Focusable)
+        {
+            parent = (FrameworkElement)VisualTreeHelper.GetParent(parent);
+        }
+
+        DependencyObject scope = FocusManager.GetFocusScope(element);
+        FocusManager.SetFocusedElement(scope, parent);
+    }
+}

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

@@ -379,13 +379,16 @@ internal class DocumentUpdater
             }
         }
 
-        if (doc.SelectedStructureMember is null)
+        if (doc.SelectedStructureMember is not null)
         {
-            doc.InternalSetSelectedMember(memberVM);
-            memberVM.Selection = StructureMemberSelectionType.Hard;
-            doc.RaisePropertyChanged(nameof(doc.SelectedStructureMember));
-            doc.RaisePropertyChanged(nameof(memberVM.Selection));
+            doc.SelectedStructureMember.Selection = StructureMemberSelectionType.None;
+            doc.SelectedStructureMember.RaisePropertyChanged(nameof(doc.SelectedStructureMember.Selection));
         }
+        doc.InternalSetSelectedMember(memberVM);
+        memberVM.Selection = StructureMemberSelectionType.Hard;
+        doc.RaisePropertyChanged(nameof(doc.SelectedStructureMember));
+        doc.RaisePropertyChanged(nameof(memberVM.Selection));
+
         doc.InternalRaiseLayersChanged(new LayersChangedEventArgs(info.GuidValue, LayerAction.Add));
     }
 

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PasteImageExecutor.cs

@@ -35,7 +35,7 @@ internal class PasteImageExecutor : UpdateableChangeExecutor
 
         ShapeCorners corners = new(new RectD(pos, image.Size));
         internals!.ActionAccumulator.AddActions(new PasteImage_Action(image, corners, memberGuid, false, drawOnMask));
-        document.TransformViewModel.ShowTransform(DocumentTransformMode.Scale_Rotate_Shear_Perspective, true, corners);
+        document.TransformViewModel.ShowTransform(DocumentTransformMode.Scale_Rotate_Shear_Perspective, true, corners, true);
 
         return ExecutionState.Success;
     }

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ShapeToolExecutor.cs

@@ -133,7 +133,7 @@ internal abstract class ShapeToolExecutor<T> : UpdateableChangeExecutor where T
             return;
         }
         transforming = true;
-        document!.TransformViewModel.ShowTransform(TransformMode, false, new ShapeCorners((RectD)lastRect));
+        document!.TransformViewModel.ShowTransform(TransformMode, false, new ShapeCorners((RectD)lastRect), true);
     }
 
     public override void ForceStop()

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/TransformReferenceLayerExecutor.cs

@@ -15,7 +15,7 @@ internal class TransformReferenceLayerExecutor : UpdateableChangeExecutor
             return ExecutionState.Error;
 
         ShapeCorners corners = document.ReferenceLayerViewModel.ReferenceShapeBindable;
-        document.TransformViewModel.ShowTransform(DocumentTransformMode.Scale_Rotate_Shear_NoPerspective, true, corners);
+        document.TransformViewModel.ShowTransform(DocumentTransformMode.Scale_Rotate_Shear_NoPerspective, true, corners, true);
         internals!.ActionAccumulator.AddActions(new TransformReferenceLayer_Action(corners));
         return ExecutionState.Success;
     }

+ 4 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/TransformSelectedAreaExecutor.cs

@@ -32,7 +32,7 @@ internal class TransformSelectedAreaExecutor : UpdateableChangeExecutor
             return ExecutionState.Error;
 
         ShapeCorners corners = new(document.SelectionPathBindable.TightBounds);
-        document.TransformViewModel.ShowTransform(DocumentTransformMode.Scale_Rotate_Shear_Perspective, true, corners);
+        document.TransformViewModel.ShowTransform(DocumentTransformMode.Scale_Rotate_Shear_Perspective, true, corners, Type == ExecutorType.Regular);
         membersToTransform = members.Select(static a => a.GuidValue).ToArray();
         internals!.ActionAccumulator.AddActions(
             new TransformSelectedArea_Action(membersToTransform, corners, tool.KeepOriginalImage, false));
@@ -47,6 +47,9 @@ internal class TransformSelectedAreaExecutor : UpdateableChangeExecutor
 
     public override void OnTransformApplied()
     {
+        if (Type == ExecutorType.ToolLinked)
+            return;
+
         internals!.ActionAccumulator.AddActions(new EndTransformSelectedArea_Action());
         internals!.ActionAccumulator.AddFinishedActions();
         document!.TransformViewModel.HideTransform();

+ 10 - 1
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentTransformViewModel.cs

@@ -48,6 +48,13 @@ internal class DocumentTransformViewModel : NotifyableObject
         set => SetProperty(ref transformActive, value);
     }
 
+    private bool showTransformControls;
+    public bool ShowTransformControls
+    {
+        get => showTransformControls;
+        set => SetProperty(ref showTransformControls, value);
+    }
+
     private bool coverWholeScreen;
     public bool CoverWholeScreen
     {
@@ -85,9 +92,10 @@ internal class DocumentTransformViewModel : NotifyableObject
     public void HideTransform()
     {
         TransformActive = false;
+        ShowTransformControls = false;
     }
 
-    public void ShowTransform(DocumentTransformMode mode, bool coverWholeScreen, ShapeCorners initPos)
+    public void ShowTransform(DocumentTransformMode mode, bool coverWholeScreen, ShapeCorners initPos, bool showApplyButton)
     {
         activeTransformMode = mode;
         CornerFreedom = TransformCornerFreedom.Scale;
@@ -96,6 +104,7 @@ internal class DocumentTransformViewModel : NotifyableObject
         RequestedCorners = initPos;
         CoverWholeScreen = coverWholeScreen;
         TransformActive = true;
+        ShowTransformControls = showApplyButton;
     }
 
     public void ModifierKeysInlet(bool isShiftDown, bool isCtrlDown, bool isAltDown)

+ 0 - 1
src/PixiEditor/ViewModels/SubViewModels/Main/ToolsViewModel.cs

@@ -131,7 +131,6 @@ internal class ToolsViewModel : SubViewModel<ViewModelMain>
 
         //update old tool
         LastActionTool?.UpdateActionDisplay(false, false, false);
-        LastActionTool?.OnDeselected();
         //update new tool
         ActiveTool.UpdateActionDisplay(ctrlIsDown, shiftIsDown, altIsDown);
         ActiveTool.OnSelected();

+ 0 - 5
src/PixiEditor/ViewModels/SubViewModels/Tools/ShapeTool.cs

@@ -12,9 +12,4 @@ internal abstract class ShapeTool : ToolViewModel
         Cursor = Cursors.Cross;
         Toolbar = new BasicShapeToolbar();
     }
-
-    public override void OnDeselected()
-    {
-        ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument?.Operations.TryStopToolLinkedExecutor();
-    }
 }

+ 4 - 2
src/PixiEditor/ViewModels/SubViewModels/Tools/ToolViewModel.cs

@@ -55,8 +55,10 @@ internal abstract class ToolViewModel : NotifyableObject
 
     public virtual void UpdateActionDisplay(bool ctrlIsDown, bool shiftIsDown, bool altIsDown) { }
     public virtual void OnLeftMouseButtonDown(VecD pos) { }
-    public virtual void OnSelected() { }
-    public virtual void OnDeselected() { }
+    public virtual void OnSelected() 
+    {
+        ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument?.Operations.TryStopToolLinkedExecutor();
+    }
 
     protected T GetValue<T>([CallerMemberName] string name = null)
     {

+ 0 - 5
src/PixiEditor/ViewModels/SubViewModels/Tools/Tools/MoveToolViewModel.cs

@@ -36,9 +36,4 @@ internal class MoveToolViewModel : ToolViewModel
     {
         ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument?.Operations.TransformSelectedArea(true);
     }
-
-    public override void OnDeselected()
-    {
-        ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument?.Operations.TryStopToolLinkedExecutor();
-    }
 }

+ 5 - 3
src/PixiEditor/ViewModels/SubViewModels/Tools/Tools/MoveViewportToolViewModel.cs

@@ -7,13 +7,15 @@ namespace PixiEditor.ViewModels.SubViewModels.Tools.Tools;
 [Command.Tool(Key = Key.H, Transient = Key.Space)]
 internal class MoveViewportToolViewModel : ToolViewModel
 {
+    public override BrushShape BrushShape => BrushShape.Hidden;
+    public override bool HideHighlight => true;
+    public override string Tooltip => $"Moves viewport. ({Shortcut})";
+
     public MoveViewportToolViewModel()
     {
         Cursor = Cursors.SizeAll;
         ActionDisplay = "Click and move to pan viewport.";
     }
 
-    public override BrushShape BrushShape => BrushShape.Hidden;
-    public override bool HideHighlight => true;
-    public override string Tooltip => $"Moves viewport. ({Shortcut})";
+    public override void OnSelected() { }
 }

+ 3 - 3
src/PixiEditor/ViewModels/SubViewModels/Tools/Tools/RotateViewportToolViewModel.cs

@@ -13,13 +13,13 @@ namespace PixiEditor.ViewModels.SubViewModels.Tools.Tools;
 internal class RotateViewportToolViewModel : ToolViewModel
 {
     public override BrushShape BrushShape => BrushShape.Hidden;
+    public override bool HideHighlight => true;
+    public override string Tooltip => $"Rotates viewport ({Shortcut})";
 
     public RotateViewportToolViewModel()
     {
         ActionDisplay = "Rotate viewport";
     }
 
-    public override bool HideHighlight => true;
-
-    public override string Tooltip => $"Rotates viewport ({Shortcut})";
+    public override void OnSelected() { }
 }

+ 4 - 4
src/PixiEditor/Views/Dialogs/SettingGroups/ShortcutsBinder.xaml

@@ -8,7 +8,7 @@
              xmlns:userControls="clr-namespace:PixiEditor.Views.UserControls"
              mc:Ignorable="d"
              d:DesignHeight="600" d:DesignWidth="400">
-    <ScrollViewer x:Name="commandScroll">
+    <ScrollViewer x:Name="commandScroll" FocusVisualStyle="{x:Null}">
                     <ScrollViewer.Template>
                         <ControlTemplate TargetType="{x:Type ScrollViewer}">
                             <Grid x:Name="Grid" Background="{TemplateBinding Background}">
@@ -31,17 +31,17 @@
                         <TextBlock Foreground="LightGray" HorizontalAlignment="Center" TextAlignment="Center"
                                    Visibility="{Binding VisibleGroups, ConverterParameter=0, Mode=OneWay, Converter={converters:EqualityBoolToVisibilityConverter}}"
                                    Text="Nothing found"/>
-                        <ItemsControl ItemsSource="{Binding Commands}" Foreground="White">
+                        <ItemsControl ItemsSource="{Binding Commands}" Foreground="White" Focusable="False">
                             <ItemsControl.ItemTemplate>
                                 <DataTemplate>
                                     <StackPanel Margin="0,0,0,20" Visibility="{Binding Visibility}">
                                         <TextBlock Text="{Binding DisplayName}" FontSize="22" FontWeight="SemiBold"/>
-                                        <ItemsControl ItemsSource="{Binding Commands}">
+                                        <ItemsControl ItemsSource="{Binding Commands}" Focusable="False">
                                             <ItemsControl.ItemTemplate>
                                                 <DataTemplate>
                                                     <Grid Margin="0,5,5,0" Visibility="{Binding Visibility}">
                                                         <TextBlock Text="{Binding Command.DisplayName}" ToolTip="{Binding Command.Description}"/>
-                                                        <userControls:ShortcutBox Width="120" Command="{Binding Command}" HorizontalAlignment="Right"/>
+                                                        <userControls:ShortcutBox Width="120" Command="{Binding Command}" HorizontalAlignment="Right" Focusable="False"/>
                                                     </Grid>
                                                 </DataTemplate>
                                             </ItemsControl.ItemTemplate>

+ 3 - 0
src/PixiEditor/Views/UserControls/KeyCombinationBox.xaml.cs

@@ -1,6 +1,8 @@
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
+using PixiEditor.Helpers;
+using PixiEditor.Helpers.Behaviours;
 using PixiEditor.Models.DataHolders;
 
 namespace PixiEditor.Views.UserControls;
@@ -90,6 +92,7 @@ internal partial class KeyCombinationBox : UserControl
 
         UpdateText();
         UpdateButton();
+        FocusHelper.MoveFocusToParent((FrameworkElement)sender);
     }
 
     private void Button_Click(object sender, RoutedEventArgs e)

+ 11 - 4
src/PixiEditor/Views/UserControls/Overlays/SelectionOverlay.cs

@@ -82,11 +82,18 @@ internal class SelectionOverlay : Control
         if (Path is null)
             return;
 
-        renderPath = new PathGeometry()
+        try
         {
-            FillRule = FillRule.EvenOdd,
-            Figures = (PathFigureCollection?)converter.ConvertFromString(Path.ToSvgPathData()),
-        };
+            renderPath = new PathGeometry()
+            {
+                FillRule = FillRule.EvenOdd,
+                Figures = (PathFigureCollection?)converter.ConvertFromString(Path.ToSvgPathData()),
+            };
+        }
+        catch (FormatException)
+        {
+            return;
+        }
         drawingContext.DrawGeometry(null, whitePen, renderPath);
         drawingContext.DrawGeometry(fillBrush, blackDashedPen, renderPath);
     }

+ 1 - 1
src/PixiEditor/Views/UserControls/Viewport.xaml

@@ -297,7 +297,7 @@
             <Button.Visibility>
                 <MultiBinding Converter="{converters:BoolOrToVisibilityConverter}">
                     <MultiBinding.Bindings>
-                        <Binding ElementName="vpUc" Path="Document.TransformViewModel.TransformActive"/>
+                        <Binding ElementName="vpUc" Path="Document.TransformViewModel.ShowTransformControls"/>
                         <Binding ElementName="vpUc" Path="Document.LineToolOverlayViewModel.IsEnabled"/>
                     </MultiBinding.Bindings>
                 </MultiBinding>