Browse Source

Improved viewport ui

flabbet 1 year ago
parent
commit
f7d6ba781f

+ 26 - 0
src/PixiEditor/Helpers/Converters/AllTrueConverter.cs

@@ -0,0 +1,26 @@
+using System.Globalization;
+
+namespace PixiEditor.Helpers.Converters;
+
+internal class AllTrueConverter : SingleInstanceMultiValueConverter<AllTrueConverter>
+{
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        if (value is IEnumerable<bool> bools)
+        {
+            return bools.All(x => x);
+        }
+
+        return false;
+    }
+
+    public override object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
+    {
+        if (values.All(x => x is bool b))
+        {
+            return values.Cast<bool>().All(x => x);
+        }
+
+        return false;
+    }
+}

+ 10 - 1
src/PixiEditor/Styles/PortingWipStyles.axaml

@@ -81,6 +81,9 @@
             </Setter.Value>
         </Setter>
     </Style>
+    <Style Selector="ToggleButton.Right">
+        <Setter Property="Content" Value="{DynamicResource icon-chevron-left}" />
+    </Style>
 
     <Style Selector="ToggleButton.ExpandCollapseToggleStyle:pressed">
         <Setter Property="Background" Value="Transparent" />
@@ -91,6 +94,11 @@
         <Setter Property="Background" Value="Transparent" />
     </Style>
 
+    <Style Selector="ToggleButton.Right:checked">
+        <Setter Property="Content" Value="{DynamicResource icon-chevron-right}" />
+        <Setter Property="Background" Value="Transparent" />
+    </Style>
+
     <Style Selector="Button.SocialMediaButton">
         <Setter Property="Width" Value="50" />
         <Setter Property="Margin" Value="5,8,5,0" />
@@ -141,7 +149,8 @@
                             </Transitions>
                         </Border.Transitions>
                         <Grid>
-                            <TextBlock Text="{DynamicResource icon-dot}" VerticalAlignment="Center" HorizontalAlignment="Center" Classes="pixi-icon"/>
+                            <TextBlock Text="{DynamicResource icon-dot}" VerticalAlignment="Center"
+                                       HorizontalAlignment="Center" Classes="pixi-icon" />
                             <ContentPresenter Padding="{TemplateBinding Padding}"
                                               HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                               VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"

+ 1 - 1
src/PixiEditor/Views/Decorators/Chip.axaml

@@ -9,6 +9,6 @@
     <Border VerticalAlignment="Center" Background="{DynamicResource GlyphBrush}" BorderThickness="1"
             BorderBrush="{Binding ElementName=chip, Path=OutlineColor}"
             Padding="5 2.5" CornerRadius="2.5">
-        <TextBlock Text="{Binding ElementName=chip, Path=Text}" Foreground="White"/>
+        <TextBlock Text="{Binding ElementName=chip, Path=Text}" Foreground="{DynamicResource ThemeForegroundBrush}"/>
     </Border>
 </UserControl>

+ 58 - 46
src/PixiEditor/Views/Main/Tools/Toolbar.axaml

@@ -4,58 +4,70 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:cmds="clr-namespace:PixiEditor.Models.Commands.XAML"
              xmlns:ui="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
+             xmlns:decorators="clr-namespace:PixiEditor.Views.Decorators"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              x:Class="PixiEditor.Views.Main.Tools.Toolbar">
-     <StackPanel
-                Background="{DynamicResource ThemeBackgroundBrush1}"
-                Orientation="Horizontal">
-                <Button
-                    Margin="12.5,0,0,0"
-                    Width="36" Height="36"
-                    Classes="pixi-icon"
-                    Command="{cmds:Command PixiEditor.Undo.Undo}"
-                    ui:Translator.TooltipKey="UNDO">
-                    <TextBlock Text="{DynamicResource icon-undo}" FontSize="20"/>
-                </Button>
-                <Button
-				Command="{cmds:Command PixiEditor.Undo.Redo}"
+    <Border CornerRadius="{DynamicResource ControlCornerRadius}"
+            BorderBrush="{DynamicResource ThemeBorderMidBrush}"
+            BorderThickness="{DynamicResource ThemeBorderThickness}"
+            Cursor="Arrow"
+            Padding="5"
+            Margin="10"
+            Height="40"
+            HorizontalAlignment="Left"
+            Background="{DynamicResource ThemeBackgroundBrush1}">
+        <StackPanel Orientation="Horizontal">
+            <Button
                 Width="36" Height="36"
-                Classes="pixi-icon" 
+                Classes="pixi-icon"
+                Command="{cmds:Command PixiEditor.Undo.Undo}"
+                ui:Translator.TooltipKey="UNDO">
+                <TextBlock Text="{DynamicResource icon-undo}" FontSize="20" />
+            </Button>
+            <Button
+                Command="{cmds:Command PixiEditor.Undo.Redo}"
+                Width="36" Height="36"
+                Classes="pixi-icon"
                 Margin="0, 0, 5, 0"
-				ui:Translator.TooltipKey="REDO">
-                    <TextBlock Text="{DynamicResource icon-redo}" FontSize="20"/>
-                </Button>
-                <ToggleButton
-				Width="30"
-				BorderThickness="0"
-				ui:Translator.TooltipKey="PEN_MODE"
-				Focusable="False"
+                ui:Translator.TooltipKey="REDO">
+                <TextBlock Text="{DynamicResource icon-redo}" FontSize="20" />
+            </Button>
+            <ToggleButton
+                Width="30"
+                BorderThickness="0"
+                ui:Translator.TooltipKey="PEN_MODE"
+                Focusable="False"
                 Classes="pixi-icon"
                 Content="{DynamicResource icon-edit}"
                 FontSize="20"
                 IsChecked="{Binding StylusSubViewModel.IsPenModeEnabled}">
-                </ToggleButton>
-                <Grid Margin="5,5,10,5" Background="{DynamicResource ThemeBackgroundBrush2}" Width="5"/>
-                <Label Classes="BaseLabel" FontSize="12"
-                   VerticalAlignment="Center" ui:Translator.Key="{Binding ToolsSubViewModel.ActiveTool.DisplayName.Key}"
-                   ui:Translator.TooltipLocalizedString="{Binding ToolsSubViewModel.ActiveTool.ActionDisplay}"
-                   />
-                <ItemsControl ItemsSource="{Binding ToolsSubViewModel.ActiveTool.Toolbar.Settings}">
-                    <ItemsControl.ItemsPanel>
-                        <ItemsPanelTemplate>
-                            <StackPanel Orientation="Horizontal" Margin="10, 0, 0, 0" />
-                        </ItemsPanelTemplate>
-                    </ItemsControl.ItemsPanel>
-                    <ItemsControl.ItemTemplate>
-                        <DataTemplate>
-                            <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="10,0,10,0">
-                                <Label
+            </ToggleButton>
+            <Grid Margin="5,5,10,5" Background="{DynamicResource ThemeBackgroundBrush2}" Width="5"
+                  IsVisible="{Binding ElementName=CollapseButton, Path=!IsChecked}" />
+            <Label CornerRadius="5" Background="{DynamicResource ThemeBackgroundBrush2}" Padding="5" FontSize="12"
+                   VerticalAlignment="Center" IsVisible="{Binding ElementName=CollapseButton, Path=!IsChecked}"
+                   ui:Translator.Key="{Binding ToolsSubViewModel.ActiveTool.DisplayName.Key}"
+                   ui:Translator.TooltipLocalizedString="{Binding ToolsSubViewModel.ActiveTool.ActionDisplay}" />
+            <ItemsControl IsVisible="{Binding ElementName=CollapseButton, Path=!IsChecked}"
+                          ItemsSource="{Binding ToolsSubViewModel.ActiveTool.Toolbar.Settings}">
+                <ItemsControl.ItemsPanel>
+                    <ItemsPanelTemplate>
+                        <StackPanel Orientation="Horizontal" Margin="0, 0, 0, 0" />
+                    </ItemsPanelTemplate>
+                </ItemsControl.ItemsPanel>
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="5,0,5,0">
+                            <Label
                                 IsVisible="{Binding HasLabel}" VerticalAlignment="Center"
-                                Foreground="White" ui:Translator.Key="{Binding Label.Key}" />
-                                <ContentControl VerticalAlignment="Center" Content="{Binding SettingControl}" />
-                            </StackPanel>
-                        </DataTemplate>
-                    </ItemsControl.ItemTemplate>
-                </ItemsControl>
-            </StackPanel>
-</UserControl>
+                                Foreground="{DynamicResource ThemeForegroundBrush}" ui:Translator.Key="{Binding Label.Key}" />
+                            <ContentControl VerticalAlignment="Center" Content="{Binding SettingControl}" />
+                        </StackPanel>
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
+            <Border Margin="5 -5 5 -5" Width="1" Background="{DynamicResource ThemeBackgroundBrush2}"/>
+            <ToggleButton Name="CollapseButton" Classes="ExpandCollapseToggleStyle Right" VerticalAlignment="Center" />
+        </StackPanel>
+    </Border>
+</UserControl>

+ 1 - 0
src/PixiEditor/Views/Main/Tools/ToolsPicker.axaml

@@ -9,6 +9,7 @@
     <Border CornerRadius="{DynamicResource ControlCornerRadius}"
             BorderBrush="{DynamicResource ThemeBorderMidBrush}"
             BorderThickness="{DynamicResource ThemeBorderThickness}"
+            Cursor="Arrow"
             Background="{DynamicResource ThemeBackgroundBrush1}">
         <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
         <ItemsControl ItemsSource="{Binding ElementName=picker, Path=Tools}" Padding="0 2">

+ 12 - 60
src/PixiEditor/Views/Main/ViewportControls/Viewport.axaml

@@ -100,9 +100,10 @@
                 </Border>
             </overlays:TogglableFlyout.Child>
         </overlays:TogglableFlyout>
-        
-        <tools:ToolsPicker ZIndex="2"
-                           Margin="10 10 0 0"
+        <tools:Toolbar ZIndex="100" VerticalAlignment="Top" DataContext="{Binding Source={viewModels:MainVM}, Path=.}" />
+
+        <tools:ToolsPicker ZIndex="100"
+                           Margin="10 55 0 0"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Top"
                            Tools="{Binding Source={viewModels:MainVM}, Path=ToolsSubViewModel.ToolSet}" />
@@ -125,61 +126,6 @@
             DefaultCursor="{Binding Source={viewModels:MainVM}, Path=ToolsSubViewModel.ToolCursor, Mode=OneWay}"
             CheckerImagePath="/Images/CheckerTile.png"
             ui:RenderOptionsBindable.BitmapInterpolationMode="{Binding Scale, Converter={converters:ScaleToBitmapScalingModeConverter}, RelativeSource={RelativeSource Self}}" />
-        <!--<zoombox:Zoombox
-            Tag="{Binding ElementName=vpUc}"
-            x:Name="zoombox"
-            UseTouchGestures="{Binding UseTouchGestures, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}, Mode=OneWay}"
-            Scale="{Binding ZoomboxScale, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}, Mode=OneWayToSource}"
-            Center="{Binding Center, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}, Mode=OneWayToSource}"
-            Angle="{Binding Angle, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}, Mode=OneWayToSource}"
-            RealDimensions="{Binding RealDimensions, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}, Mode=OneWayToSource}"
-            Dimensions="{Binding Dimensions, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}, Mode=OneWayToSource}"
-            ZoomMode="{Binding ZoomMode, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}, Mode=TwoWay}"
-            ZoomOutOnClick="{Binding ZoomOutOnClick, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}, Mode=TwoWay}"
-            FlipX="{Binding FlipX, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}, Mode=TwoWay}"
-            FlipY="{Binding FlipY, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}, Mode=TwoWay}">
-            <zoombox:Zoombox.AdditionalContent>
-                <Border
-                    d:Width="64"
-                    d:Height="64"
-                    HorizontalAlignment="Center"
-                    VerticalAlignment="Center"
-                    DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}}"
-                    RenderOptions.BitmapInterpolationMode="None">
-                    <Grid>
-
-                        <Rectangle Stroke="{DynamicResource ThemeBackgroundBrush1}" Opacity=".8" ZIndex="2"
-                                   IsVisible="{Binding Document.ReferenceLayerViewModel.IsVisibleBindable}">
-                            <Rectangle.StrokeThickness>
-                                <Binding Converter="{converters:ReciprocalConverter}">
-                                    <Binding.Path>Zoombox.Scale</Binding.Path>
-                                    <Binding.ConverterParameter>
-                                        <sys:Double>
-                                            3
-                                        </sys:Double>
-                                    </Binding.ConverterParameter>
-                                </Binding>
-                            </Rectangle.StrokeThickness>
-                            <Rectangle.Margin>
-                                <Binding Converter="{converters:ReciprocalConverter}">
-                                    <Binding.Path>Zoombox.Scale</Binding.Path>
-                                    <Binding.ConverterParameter>
-                                        <sys:Double>
-                                            -3
-                                        </sys:Double>
-                                    </Binding.ConverterParameter>
-                                </Binding>
-                            </Rectangle.Margin>
-                        </Rectangle>
-                    </Grid>
-                </Border>
-            </zoombox:Zoombox.AdditionalContent>
-        </zoombox:Zoombox>-->
-        <!--<overlays:ReferenceLayerOverlay SizeChanged="OnReferenceImageSizeChanged"
-                                        ReferenceLayer="{Binding Document.ReferenceLayerViewModel}"
-                                        ReferenceLayerScale="{Binding ReferenceLayerScale}"
-                                        FadeOut="{Binding Source={viewModels:ToolVM ColorPickerToolViewModel}, Path=!PickFromReferenceLayer, Mode=OneWay}"
-                                        RenderTransformOrigin="0, 0" RenderTransform="{Binding #scene.CanvasTransform}"/>-->
 
         <!--Brush shape overlay is rendered separately, so it doesn't trigger rerender each mouse movement to scene-->
         <!--I didn't measure it, but I thought that could impact performance-->
@@ -190,12 +136,18 @@
             Name="brushShapeOverlay"
             Focusable="False" ZIndex="6"
             IsHitTestVisible="False"
-            IsVisible="{Binding !Document.TransformViewModel.TransformActive}"
             ZoomScale="{Binding #scene.Scale}"
             Scene="{Binding #scene, Mode=OneTime}"
             BrushSize="{Binding ToolsSubViewModel.ActiveBasicToolbar.ToolSize, Source={viewModels:MainVM}}"
             BrushShape="{Binding ToolsSubViewModel.ActiveTool.BrushShape, Source={viewModels:MainVM}, FallbackValue={x:Static brushShapeOverlay:BrushShape.Hidden}}"
-            FlowDirection="LeftToRight" />
+            FlowDirection="LeftToRight">
+            <brushShapeOverlay:BrushShapeOverlay.IsVisible>
+                <MultiBinding Converter="{converters:AllTrueConverter}">
+                    <Binding Path="!Document.TransformViewModel.TransformActive"/>
+                    <Binding Path="IsOverCanvas"/> 
+                </MultiBinding>
+            </brushShapeOverlay:BrushShapeOverlay.IsVisible>
+        </brushShapeOverlay:BrushShapeOverlay>
         <Button
             ZIndex="99999"
             DockPanel.Dock="Bottom"

+ 20 - 5
src/PixiEditor/Views/Main/ViewportControls/Viewport.axaml.cs

@@ -85,8 +85,18 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
     public static readonly StyledProperty<ICommand> MiddleMouseClickedCommandProperty =
         AvaloniaProperty.Register<Viewport, ICommand>(nameof(MiddleMouseClickedCommand), null);
 
-    public static readonly StyledProperty<ViewportColorChannels> ChannelsProperty = AvaloniaProperty.Register<Viewport, ViewportColorChannels>(
-        nameof(Channels));
+    public static readonly StyledProperty<ViewportColorChannels> ChannelsProperty =
+        AvaloniaProperty.Register<Viewport, ViewportColorChannels>(
+            nameof(Channels));
+
+    public static readonly StyledProperty<bool> IsOverCanvasProperty = AvaloniaProperty.Register<Viewport, bool>(
+        "IsOverCanvas");
+
+    public bool IsOverCanvas
+    {
+        get => GetValue(IsOverCanvasProperty);
+        set => SetValue(IsOverCanvasProperty, value);
+    }
 
     public ICommand? MiddleMouseClickedCommand
     {
@@ -302,6 +312,9 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
         //TODO: It's weird that I had to do it this way, right click didn't raise Image_MouseUp otherwise.
         viewportGrid.AddHandler(PointerReleasedEvent, Image_MouseUp, RoutingStrategies.Tunnel);
         viewportGrid.AddHandler(PointerPressedEvent, Image_MouseDown, RoutingStrategies.Bubble);
+        
+        Scene.PointerExited += (sender, args) => IsOverCanvas = false;
+        Scene.PointerEntered += (sender, args) => IsOverCanvas = true;
     }
 
     public Scene Scene => scene;
@@ -338,6 +351,7 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
         {
             oldDoc.SizeChanged -= viewport.OnImageSizeChanged;
         }
+
         DocumentViewModel? newDoc = e.NewValue.Value;
         if (newDoc != null)
         {
@@ -368,12 +382,13 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
 
     private ViewportInfo GetLocation()
     {
-        return new(AngleRadians, Center, RealDimensions, Dimensions, CalculateResolution(), GuidValue, Delayed, ForceRefreshFinalImage);
+        return new(AngleRadians, Center, RealDimensions, Dimensions, CalculateResolution(), GuidValue, Delayed,
+            ForceRefreshFinalImage);
     }
 
     private void Image_MouseDown(object? sender, PointerPressedEventArgs e)
     {
-        if(Document is null)
+        if (Document is null)
             return;
 
         bool isMiddle = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
@@ -441,7 +456,7 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
         scene.ZoomIntoCenter(-1);
         scene.ZoomIntoCenter(1); // a bit hacky, but it resets brush overlay properly
     }
-    
+
     private void ResetViewportClicked(object sender, RoutedEventArgs e)
     {
         scene.AngleRadians = 0;

+ 2 - 4
src/PixiEditor/Views/MainView.axaml

@@ -25,16 +25,14 @@
             <main1:MainTitleBar DockPanel.Dock="Top" DataContext="{Binding MenuBarViewModel}"/>
             <Grid Focusable="True" Name="FocusableGrid">
                 <Grid.RowDefinitions>
-                    <RowDefinition Height="40" />
                     <RowDefinition Height="*" />
                     <RowDefinition Height="30"/>
                 </Grid.RowDefinitions>
 
-                <tools:Toolbar Grid.Row="0" DataContext="{Binding .}" />
-                <controls:DockableAreaRegion Grid.Row="1"
+                <controls:DockableAreaRegion Grid.Row="0"
                                              Root="{Binding LayoutSubViewModel.LayoutManager.ActiveLayout.Root}"
                                              Context="{Binding LayoutSubViewModel.LayoutManager.DockContext}"/>
-                <main1:ActionDisplayBar Grid.Row="2" DataContext="{Binding .}"/>
+                <main1:ActionDisplayBar Grid.Row="1" DataContext="{Binding .}"/>
             </Grid>
         </DockPanel>
         <commandSearch:CommandSearchControl

+ 3 - 2
src/PixiEditor/Views/Overlays/BrushShapeOverlay/BrushShapeOverlay.cs

@@ -8,6 +8,7 @@ using Avalonia.Media;
 using ChunkyImageLib.Operations;
 using PixiEditor.Views.Visuals;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.Extensions.UI.Overlays;
 using PixiEditor.Models.Controllers.InputDevice;
 using PixiEditor.Numerics;
 using PixiEditor.Views.Rendering;
@@ -78,14 +79,14 @@ internal class BrushShapeOverlay : Overlay
 
     private void SourceMouseMove(PointerEventArgs args)
     {
-        if (Scene is null || BrushShape == BrushShape.Hidden)
+        if (Scene is null || BrushShape == BrushShape.Hidden) 
             return;
 
         Point rawPoint = args.GetPosition(Scene);
         lastMousePos = Scene.ToZoomboxSpace(new VecD(rawPoint.X, rawPoint.Y));
         InvalidateVisual();
     }
-
+    
     public override void RenderOverlay(DrawingContext context, RectD canvasBounds) => Render(context);
 
     public override void Render(DrawingContext drawingContext)