Browse Source

Basic UI, config and stuff

flabbet 11 months ago
parent
commit
73e938a64c

+ 11 - 0
src/PixiEditor/Data/Configs/ToolSetsConfig.json

@@ -18,5 +18,16 @@
       "Brightness",
       "Brightness",
       "Zoom"
       "Zoom"
     ]
     ]
+  },
+  {
+    "Name": "VECTOR_TOOLSET",
+    "Tools": [
+      "MoveViewport",
+      "RotateViewport",
+      "Move",
+      "Line",
+      "Ellipse",
+      "Rectangle"
+    ]
   }
   }
 ]
 ]

+ 1 - 0
src/PixiEditor/Models/Handlers/IToolSetHandler.cs

@@ -2,5 +2,6 @@
 
 
 internal interface IToolSetHandler : IHandler
 internal interface IToolSetHandler : IHandler
 {
 {
+    public string Name { get; }
     public ICollection<IToolHandler> Tools { get; }
     public ICollection<IToolHandler> Tools { get; }
 }
 }

+ 2 - 2
src/PixiEditor/ViewModels/SubViewModels/ToolSetViewModel.cs

@@ -7,13 +7,13 @@ namespace PixiEditor.ViewModels.SubViewModels;
 
 
 internal class ToolSetViewModel : PixiObservableObject, IToolSetHandler
 internal class ToolSetViewModel : PixiObservableObject, IToolSetHandler
 {
 {
-    public LocalizedString ToolSetName { get; }
+    public string Name { get; }
     ICollection<IToolHandler> IToolSetHandler.Tools => Tools;
     ICollection<IToolHandler> IToolSetHandler.Tools => Tools;
     public ObservableCollection<IToolHandler> Tools { get; } = new();
     public ObservableCollection<IToolHandler> Tools { get; } = new();
     
     
     public ToolSetViewModel(string setName, List<IToolHandler> tools)
     public ToolSetViewModel(string setName, List<IToolHandler> tools)
     {
     {
-        ToolSetName = setName;
+        Name = setName;
         foreach (var tool in tools)
         foreach (var tool in tools)
         {
         {
             Tools.Add(tool);
             Tools.Add(tool);

+ 68 - 4
src/PixiEditor/ViewModels/SubViewModels/ToolsViewModel.cs

@@ -80,7 +80,11 @@ internal class ToolsViewModel : SubViewModel<ViewModelMain>, IToolsHandler
         }
         }
     }
     }
 
 
-    public IToolSetHandler ActiveToolSet { get; private set; }
+    public IToolSetHandler ActiveToolSet
+    {
+        get => _activeToolSet!;
+        private set => SetProperty(ref _activeToolSet, value);
+    }
 
 
     ICollection<IToolSetHandler> IToolsHandler.AllToolSets => AllToolSets;
     ICollection<IToolSetHandler> IToolsHandler.AllToolSets => AllToolSets;
     
     
@@ -95,6 +99,7 @@ internal class ToolsViewModel : SubViewModel<ViewModelMain>, IToolsHandler
     private ToolViewModel _preTransientTool;
     private ToolViewModel _preTransientTool;
     
     
     private List<IToolHandler> allTools = new();
     private List<IToolHandler> allTools = new();
+    private IToolSetHandler? _activeToolSet;
 
 
     public ToolsViewModel(ViewModelMain owner)
     public ToolsViewModel(ViewModelMain owner)
         : base(owner)
         : base(owner)
@@ -112,8 +117,14 @@ internal class ToolsViewModel : SubViewModel<ViewModelMain>, IToolsHandler
             throw new InvalidOperationException("No tool set configuration found.");
             throw new InvalidOperationException("No tool set configuration found.");
         }
         }
         
         
-        List<IToolHandler> tools = activeToolSetConfig.Tools.Select(toolName => allTools.FirstOrDefault(tool => tool.ToolName == toolName)).Where(x => x != null).ToList();
-        ActiveToolSet = new ToolSetViewModel(activeToolSetConfig.Name, tools); 
+        AllToolSets.Clear();
+        AddToolSets(toolSetConfig);
+        SetActiveToolSet(AllToolSets.First());
+    }
+
+    public void SetActiveToolSet(IToolSetHandler toolSetHandler)
+    {
+        ActiveToolSet = toolSetHandler;
     }
     }
 
 
     public void SetupToolsTooltipShortcuts(IServiceProvider services)
     public void SetupToolsTooltipShortcuts(IServiceProvider services)
@@ -146,6 +157,36 @@ internal class ToolsViewModel : SubViewModel<ViewModelMain>, IToolsHandler
             return;
             return;
         doc.EventInlet.OnApplyTransform();
         doc.EventInlet.OnApplyTransform();
     }
     }
+    
+    [Command.Internal("PixiEditor.Tools.SwitchToolSet", AnalyticsTrack = true, CanExecute = "PixiEditor.HasNextToolSet")]
+    [Command.Basic("PixiEditor.Tools.NextToolSet", true, "NEXT_TOOL_SET", "NEXT_TOOL_SET", Modifiers = KeyModifiers.Shift, 
+        Key = Key.E, AnalyticsTrack = true)]
+    [Command.Basic("PixiEditor.Tools.PreviousToolSet", false, "PREVIOUS_TOOL_SET", "PREVIOUS_TOOL_SET", Modifiers = KeyModifiers.Shift,
+        Key = Key.Q, AnalyticsTrack = true)]
+    public void SwitchToolSet(bool forward)
+    {
+        int currentIndex = AllToolSets.IndexOf(ActiveToolSet);
+        int nextIndex = currentIndex + (forward ? 1 : -1);
+        if (nextIndex >= AllToolSets.Count || nextIndex < 0)
+        {
+            nextIndex = 0;
+        }
+
+        SetActiveToolSet(AllToolSets.ElementAt(nextIndex));
+    }
+
+    [Evaluator.CanExecute("PixiEditor.HasNextToolSet")]
+    public bool HasNextToolSet(bool next)
+    {
+        int currentIndex = AllToolSets.IndexOf(ActiveToolSet);
+        int nextIndex = currentIndex + (next ? 1 : -1);
+        if (nextIndex < 0 || nextIndex >= AllToolSets.Count)
+        {
+            return false;
+        }
+
+        return AllToolSets.ElementAt(nextIndex) != ActiveToolSet;
+    } 
 
 
     [Command.Internal("PixiEditor.Tools.SelectTool", CanExecute = "PixiEditor.HasDocument")]
     [Command.Internal("PixiEditor.Tools.SelectTool", CanExecute = "PixiEditor.HasDocument")]
     public void SetActiveTool(ToolViewModel tool)
     public void SetActiveTool(ToolViewModel tool)
@@ -250,7 +291,9 @@ internal class ToolsViewModel : SubViewModel<ViewModelMain>, IToolsHandler
     {
     {
         if (!typeof(ToolViewModel).IsAssignableFrom(toolType))
         if (!typeof(ToolViewModel).IsAssignableFrom(toolType))
             throw new ArgumentException($"'{toolType}' does not inherit from {typeof(ToolViewModel)}");
             throw new ArgumentException($"'{toolType}' does not inherit from {typeof(ToolViewModel)}");
-        IToolHandler foundTool = ActiveToolSet!.Tools.First(x => x.GetType().IsAssignableFrom(toolType));
+        IToolHandler foundTool = ActiveToolSet!.Tools.FirstOrDefault(x => x.GetType().IsAssignableFrom(toolType));
+        if (foundTool == null) return;
+        
         SetActiveTool(foundTool, transient, sourceInfo);
         SetActiveTool(foundTool, transient, sourceInfo);
     }
     }
     
     
@@ -318,4 +361,25 @@ internal class ToolsViewModel : SubViewModel<ViewModelMain>, IToolsHandler
     {
     {
         ActiveTool?.ModifierKeyChanged(args.IsCtrlDown, args.IsShiftDown, args.IsAltDown);
         ActiveTool?.ModifierKeyChanged(args.IsCtrlDown, args.IsShiftDown, args.IsAltDown);
     }
     }
+    
+    private void AddToolSets(ToolSetsConfig toolSetConfig)
+    {
+        foreach (ToolSetConfig toolSet in toolSetConfig)
+        {
+            List<IToolHandler> tools = new List<IToolHandler>();
+            
+            foreach (string toolName in toolSet.Tools)
+            {
+                IToolHandler? tool = allTools.FirstOrDefault(tool => tool.ToolName == toolName);
+                if (tool is null)
+                {
+                    throw new InvalidOperationException($"Tool '{toolName}' not found.");
+                }
+                
+                tools.Add(tool);
+            }
+            
+            AllToolSets.Add(new ToolSetViewModel(toolSet.Name, tools));
+        }
+    }
 }
 }

+ 33 - 15
src/PixiEditor/Views/Main/Tools/ToolsPicker.axaml

@@ -4,6 +4,8 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:tools="clr-namespace:PixiEditor.ViewModels.Tools"
              xmlns:tools="clr-namespace:PixiEditor.ViewModels.Tools"
              xmlns:tools1="clr-namespace:PixiEditor.Views.Main.Tools"
              xmlns:tools1="clr-namespace:PixiEditor.Views.Main.Tools"
+             xmlns:ui="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
+             xmlns:system="clr-namespace:System;assembly=System.Runtime"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              x:Class="PixiEditor.Views.Main.Tools.ToolsPicker" Name="picker">
              x:Class="PixiEditor.Views.Main.Tools.ToolsPicker" Name="picker">
     <Border CornerRadius="{DynamicResource ControlCornerRadius}"
     <Border CornerRadius="{DynamicResource ControlCornerRadius}"
@@ -11,19 +13,35 @@
             BorderThickness="{DynamicResource ThemeBorderThickness}"
             BorderThickness="{DynamicResource ThemeBorderThickness}"
             Cursor="Arrow"
             Cursor="Arrow"
             Background="{DynamicResource ThemeBackgroundBrush1}">
             Background="{DynamicResource ThemeBackgroundBrush1}">
-        <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
-        <ItemsControl ItemsSource="{Binding ElementName=picker, Path=Tools}" Padding="0 2">
-            <ItemsControl.ItemTemplate>
-                <DataTemplate DataType="tools:ToolViewModel">
-                    <tools1:ToolPickerButton DataContext="{Binding}" IsSelected="{Binding IsActive}"/>
-                </DataTemplate>
-            </ItemsControl.ItemTemplate>
-            <ItemsControl.ItemsPanel>
-                <ItemsPanelTemplate>
-                    <StackPanel Orientation="Vertical"/>
-                </ItemsPanelTemplate>
-            </ItemsControl.ItemsPanel>
-        </ItemsControl>
-        </ScrollViewer>
+        <StackPanel>
+            <StackPanel Orientation="Horizontal">
+                <Button Classes="pixi-icon" Content="{DynamicResource icon-chevron-left}" 
+                        Command="{Binding SwitchToolSetCommand, ElementName=picker}">
+                    <Button.CommandParameter>
+                        <system:Boolean>False</system:Boolean>
+                    </Button.CommandParameter>
+                </Button>
+                <Button Classes="pixi-icon" Content="{DynamicResource icon-chevron-right}"
+                        Command="{Binding SwitchToolSetCommand, ElementName=picker}">
+                    <Button.CommandParameter>
+                        <system:Boolean>True</system:Boolean>
+                    </Button.CommandParameter>
+                </Button>
+            </StackPanel>
+            <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
+                <ItemsControl ItemsSource="{Binding ElementName=picker, Path=ToolSet.Tools}" Padding="0 2">
+                    <ItemsControl.ItemTemplate>
+                        <DataTemplate DataType="tools:ToolViewModel">
+                            <tools1:ToolPickerButton DataContext="{Binding}" IsSelected="{Binding IsActive}" />
+                        </DataTemplate>
+                    </ItemsControl.ItemTemplate>
+                    <ItemsControl.ItemsPanel>
+                        <ItemsPanelTemplate>
+                            <StackPanel Orientation="Vertical" />
+                        </ItemsPanelTemplate>
+                    </ItemsControl.ItemsPanel>
+                </ItemsControl>
+            </ScrollViewer>
+        </StackPanel>
     </Border>
     </Border>
-</UserControl>
+</UserControl>

+ 15 - 6
src/PixiEditor/Views/Main/Tools/ToolsPicker.axaml.cs

@@ -1,4 +1,4 @@
-using System.Collections.ObjectModel;
+using System.Windows.Input;
 using Avalonia;
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Handlers;
@@ -7,13 +7,22 @@ namespace PixiEditor.Views.Main.Tools;
 
 
 internal partial class ToolsPicker : UserControl
 internal partial class ToolsPicker : UserControl
 {
 {
-    public static readonly StyledProperty<ObservableCollection<IToolHandler>> ToolsProperty =
-        AvaloniaProperty.Register<ToolsPicker, ObservableCollection<IToolHandler>>(nameof(Tools));
+    public static readonly StyledProperty<IToolSetHandler> ToolSetProperty =
+        AvaloniaProperty.Register<ToolsPicker, IToolSetHandler>(
+            nameof(ToolSet));
+    public IToolSetHandler ToolSet
+    {
+        get => GetValue(ToolSetProperty);
+        set => SetValue(ToolSetProperty, value);
+    }
+
+    public static readonly StyledProperty<ICommand> SwitchToolSetCommandProperty = AvaloniaProperty.Register<ToolsPicker, ICommand>(
+        "SwitchToolSetCommand");
 
 
-    public ObservableCollection<IToolHandler> Tools
+    public ICommand SwitchToolSetCommand
     {
     {
-        get => GetValue(ToolsProperty);
-        set => SetValue(ToolsProperty, value);
+        get => GetValue(SwitchToolSetCommandProperty);
+        set => SetValue(SwitchToolSetCommandProperty, value);
     }
     }
 
 
     public ToolsPicker()
     public ToolsPicker()

+ 2 - 1
src/PixiEditor/Views/Main/ViewportControls/Viewport.axaml

@@ -117,7 +117,8 @@
                            Margin="10 55 0 0"
                            Margin="10 55 0 0"
                            HorizontalAlignment="Left"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Top"
                            VerticalAlignment="Top"
-                           Tools="{Binding Source={viewModels:MainVM}, Path=ToolsSubViewModel.ActiveToolSet.Tools}" />
+                           ToolSet="{Binding Source={viewModels:MainVM}, Path=ToolsSubViewModel.ActiveToolSet}" 
+                           SwitchToolSetCommand="{xaml:Command Name=PixiEditor.Tools.SwitchToolSet, UseProvided=True}"/>
         <rendering:Scene
         <rendering:Scene
             Focusable="False" Name="scene"
             Focusable="False" Name="scene"
             ZIndex="1"
             ZIndex="1"