Ruben 1 рік тому
батько
коміт
5b358a6204

+ 2 - 1
nuget.config

@@ -1,8 +1,9 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <configuration>
   <packageSources>
     <!--To inherit the global NuGet package sources remove the <clear/> line below -->
     <clear />
     <add key="nuget" value="https://api.nuget.org/v3/index.json" />
+    <add key="Avalonia Nightly" value="https://nuget-feed-nightly.avaloniaui.net/v3/index.json" />
   </packageSources>
 </configuration>

+ 10 - 0
src/PicView.Avalonia.Win32/Program.cs

@@ -22,7 +22,17 @@ internal class Program
             .LogToTrace()
 #endif
             .UseReactiveUI()
+            .With(new SkiaOptions { MaxGpuResourceSizeBytes = 256_000_000 })
             .UseWin32()
+            .With(new Win32PlatformOptions
+            {
+                CompositionMode = new[]
+                    {
+                        Win32CompositionMode.WinUIComposition
+                    },
+                OverlayPopups = true,
+                WinUICompositionBackdropCornerRadius = 8
+            })
             .UseSkia();
     }
 }

+ 6 - 2
src/PicView.Avalonia.Win32/Views/WinMainWindow.axaml

@@ -15,6 +15,7 @@
     d:DesignWidth="800"
     x:DataType="viewModels:MainViewModel"
     CanResize="{Binding CanResize}"
+    CornerRadius="8"
     Icon="/icon.ico"
     SizeChanged="Control_OnSizeChanged"
     SizeToContent="{Binding SizeToContent}"
@@ -24,11 +25,14 @@
         <viewModels:MainViewModel />
     </Design.DataContext>
 
-    <Border BorderBrush="{StaticResource MainBorderColor}" BorderThickness="1">
+    <Border
+        BorderBrush="{StaticResource MainBorderColor}"
+        BorderThickness="1"
+        CornerRadius="8">
         <DockPanel LastChildFill="True">
             <views1:WinTitleBar x:Name="TitleBar" DockPanel.Dock="Top" />
             <uc:BottomBar x:Name="BottomBar" DockPanel.Dock="Bottom" />
-            <views:MainView Background="{StaticResource NoisyTexture}" />
+            <views:MainView x:Name="MainView" Background="{StaticResource NoisyTexture}" />
         </DockPanel>
     </Border>
 </Window>

+ 1 - 0
src/PicView.Avalonia.Win32/Views/WinMainWindow.axaml.cs

@@ -8,6 +8,7 @@ using PicView.Core.FileHandling;
 using ReactiveUI;
 using System.Reactive.Concurrency;
 using PicView.Avalonia.Helpers;
+using PicView.Core.Calculations;
 
 namespace PicView.Avalonia.Win32.Views;
 

+ 7 - 2
src/PicView.Avalonia.Win32/Views/WinTitleBar.axaml

@@ -20,11 +20,15 @@
     <Border
         Background="{StaticResource MainButtonBackgroundColor}"
         BorderBrush="{StaticResource MainBorderColor}"
-        BorderThickness="0,1,0,1"
+        BorderThickness="0,0,0,1"
+        CornerRadius="8,8,0,0"
         PointerPressed="MoveWindow">
         <DockPanel LastChildFill="True">
 
-            <Border BorderBrush="{StaticResource MainBorderColor}" BorderThickness="0,0,1,0">
+            <Border
+                BorderBrush="{StaticResource MainBorderColor}"
+                BorderThickness="0,0,1,0"
+                CornerRadius="8,0,0,0">
                 <Image
                     Width="20"
                     Height="25"
@@ -108,6 +112,7 @@
                 BorderThickness="0,0,1,0"
                 Classes="hover"
                 Command="{Binding ExitCommand}"
+                CornerRadius="0,8,0,0"
                 DockPanel.Dock="Right">
                 <Path
                     Width="10"

+ 2 - 3
src/PicView.Avalonia/DarkTheme/Controls/Window.axaml

@@ -3,10 +3,9 @@
         <Window />
     </Design.PreviewWith>
     <ControlTheme x:Key="{x:Type Window}" TargetType="Window">
-        <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
-        <Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" />
+        <Setter Property="Background" Value="Transparent" />
         <Setter Property="TransparencyBackgroundFallback" Value="{DynamicResource HighlightForegroundColor}" />
-        <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}" />
+        <Setter Property="Foreground" Value="{StaticResource MainTextColor}" />
         <Setter Property="FontSize" Value="{DynamicResource FontSizeNormal}" />
         <Setter Property="Template">
             <ControlTemplate>

+ 1 - 1
src/PicView.Avalonia/PicView.Avalonia.csproj

@@ -66,7 +66,7 @@
     <Compile Update="Views\UC\Buttons\StarOutlineButtons.axaml.cs">
       <DependentUpon>StarOutlineButtons.axaml</DependentUpon>
     </Compile>
-    <Compile Update="Views\UC\ImageViewer.axaml.cs">
+    <Compile Update="Views\ImageViewer.axaml.cs">
       <DependentUpon>ImageViewer.axaml</DependentUpon>
     </Compile>
     <Compile Update="Views\UC\Menus\ToolsMenu.axaml.cs">

+ 1 - 0
src/PicView.Avalonia/ViewModels/MainViewModel.cs

@@ -27,6 +27,7 @@ using System.Reactive;
 using System.Reactive.Disposables;
 using System.Runtime.InteropServices;
 using System.Windows.Input;
+using ImageViewer = PicView.Avalonia.Views.ImageViewer;
 
 namespace PicView.Avalonia.ViewModels
 {

+ 1 - 0
src/PicView.Avalonia/Views/UC/BottomBar.axaml → src/PicView.Avalonia/Views/BottomBar.axaml

@@ -20,6 +20,7 @@
         Background="{StaticResource SecondaryBackgroundColor}"
         BorderBrush="{StaticResource MainBorderColor}"
         BorderThickness="0,1,0,0"
+        CornerRadius="0,0,8,8"
         PointerPressed="MoveWindow">
         <Grid>
             <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">

+ 0 - 0
src/PicView.Avalonia/Views/UC/BottomBar.axaml.cs → src/PicView.Avalonia/Views/BottomBar.axaml.cs


+ 13 - 6
src/PicView.Avalonia/Views/UC/ImageViewer.axaml → src/PicView.Avalonia/Views/ImageViewer.axaml

@@ -1,5 +1,5 @@
 <UserControl
-    x:Class="PicView.Avalonia.Views.UC.ImageViewer"
+    x:Class="PicView.Avalonia.Views.ImageViewer"
     xmlns="https://github.com/avaloniaui"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -9,19 +9,26 @@
     d:DesignWidth="800"
     x:DataType="vm:MainViewModel"
     DragDrop.AllowDrop="True"
+    PointerPressed="InputElement_OnPointerPressed"
     mc:Ignorable="d">
     <Design.DataContext>
         <vm:MainViewModel />
     </Design.DataContext>
 
-    <ScrollViewer x:Name="ImageScrollViewer" VerticalScrollBarVisibility="{Binding ToggleScrollBarVisibility}">
-        <Border>
+    <ScrollViewer
+        x:Name="ImageScrollViewer"
+        Focusable="False"
+        ScrollChanged="ImageScrollViewer_OnScrollChanged"
+        VerticalScrollBarVisibility="{Binding ToggleScrollBarVisibility}">
+        <Border
+            x:Name="ImageZoomBorder"
+            MaxWidth="{Binding ImageWidth}"
+            MaxHeight="{Binding ImageHeight}">
             <Image
-                Width="{Binding ImageWidth}"
-                Height="{Binding ImageHeight}"
+                x:Name="MainImage"
                 RenderOptions.BitmapInterpolationMode="HighQuality"
                 Source="{Binding Image}"
-                Stretch="Fill">
+                Stretch="Uniform">
                 <Image.RenderTransform>
                     <TransformGroup>
                         <ScaleTransform ScaleX="{Binding ScaleX}">

+ 335 - 0
src/PicView.Avalonia/Views/ImageViewer.axaml.cs

@@ -0,0 +1,335 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Media;
+using Avalonia.Media.Transformation;
+using Avalonia.Platform.Storage;
+using Avalonia.Threading;
+using PicView.Avalonia.ViewModels;
+using PicView.Core.Config;
+using PicView.Core.ImageTransformations;
+using PicView.Core.Navigation;
+using System.Runtime.InteropServices;
+using Point = Avalonia.Point;
+
+namespace PicView.Avalonia.Views;
+
+public partial class ImageViewer : UserControl
+{
+    private static ScaleTransform? _scaleTransform;
+    private static TranslateTransform? _translateTransform;
+
+    private static Point _origin;
+    private static Point _start;
+
+    public ImageViewer()
+    {
+        InitializeComponent();
+        AddHandler(PointerWheelChangedEvent, PreviewOnPointerWheelChanged, RoutingStrategies.Tunnel);
+        AddHandler(KeyDownEvent, PreviewKeyDown, RoutingStrategies.Tunnel);
+        // TODO add visual feedback for drag and drop
+        //AddHandler(DragDrop.DragOverEvent, DragOver);
+        AddHandler(DragDrop.DropEvent, Drop);
+
+        Loaded += delegate
+        {
+            InitializeZoom();
+            if (DataContext is not MainViewModel vm)
+                return;
+            vm.ImageChanged += (s, e) =>
+            {
+                if (SettingsHelper.Settings.Zoom.ScrollEnabled)
+                {
+                    Dispatcher.UIThread.InvokeAsync(() =>
+                    {
+                        ImageScrollViewer.ScrollToHome();
+                    }, DispatcherPriority.Normal);
+                }
+                ResetZoom(false);
+            };
+        };
+    }
+
+    private void PreviewKeyDown(object? sender, KeyEventArgs e)
+    {
+    }
+
+    private async Task PreviewOnPointerWheelChanged(object? sender, PointerWheelEventArgs e)
+    {
+        e.Handled = true;
+        await Main_OnPointerWheelChanged(e);
+    }
+
+    private void Drop(object? sender, DragEventArgs e)
+    {
+        if (DataContext is not MainViewModel vm)
+            return;
+
+        var data = e.Data.GetFiles();
+        if (data == null)
+        {
+            // TODO Handle URL and folder drops
+            return;
+        }
+
+        var storageItems = data as IStorageItem[] ?? data.ToArray();
+        var firstFile = storageItems.FirstOrDefault();
+        var path = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? firstFile.Path.AbsolutePath : firstFile.Path.LocalPath;
+        _ = vm.LoadPicFromString(path).ConfigureAwait(false);
+        foreach (var file in storageItems.Skip(1))
+        {
+            // TODO Open each file in a new window if the setting to open in the same window is false
+        }
+    }
+
+    private async Task Main_OnPointerWheelChanged(PointerWheelEventArgs e)
+    {
+        if (DataContext is not MainViewModel mainViewModel)
+            return;
+
+        if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+        {
+            // TODO figure out how to do image navigation with gestures
+            return;
+        }
+        var ctrl = e.KeyModifiers == KeyModifiers.Control;
+        var reverse = e.Delta.Y < 0;
+
+        if (SettingsHelper.Settings.Zoom.CtrlZoom)
+        {
+            if (ctrl)
+            {
+                //ImageZoomBorder.Zoom(e);
+                //return;
+                SetPointerPosition();
+                if (reverse)
+                {
+                    ZoomOut(e);
+                }
+                else
+                {
+                    ZoomIn(e);
+                }
+            }
+            else
+            {
+                await ScrollOrNavigate();
+            }
+        }
+        else
+        {
+            if (ctrl)
+            {
+                await ScrollOrNavigate();
+            }
+            else
+            {
+                SetPointerPosition();
+                if (reverse)
+                {
+                    ZoomOut(e);
+                }
+                else
+                {
+                    ZoomIn(e);
+                }
+            }
+        }
+
+        return;
+
+        void SetPointerPosition()
+        {
+            e.Pointer.Capture(this);
+            _start = e.GetPosition(this);
+            var x = _translateTransform?.X ?? 0;
+            var y = _translateTransform?.Y ?? 0;
+            _origin = new Point(x, y);
+        }
+
+        async Task ScrollOrNavigate()
+        {
+            if (!SettingsHelper.Settings.Zoom.ScrollEnabled)
+            {
+                await LoadNextPic();
+            }
+            else
+            {
+                if (reverse)
+                {
+                    ImageScrollViewer.LineUp();
+                }
+                else
+                {
+                    ImageScrollViewer.LineDown();
+                }
+            }
+        }
+
+        async Task LoadNextPic()
+        {
+            var navigateTo = SettingsHelper.Settings.Zoom.HorizontalReverseScroll ? NavigateTo.Next : NavigateTo.Previous;
+            if (reverse)
+            {
+                navigateTo = SettingsHelper.Settings.Zoom.HorizontalReverseScroll ? NavigateTo.Previous : NavigateTo.Next;
+            }
+            await mainViewModel.LoadNextPic(navigateTo);
+        }
+    }
+
+    private void ImageScrollViewer_OnScrollChanged(object? sender, ScrollChangedEventArgs e)
+    {
+        e.Handled = true;
+    }
+
+    #region Zoom
+
+    private void InitializeZoom()
+    {
+        ImageZoomBorder.RenderTransform = new TransformGroup
+        {
+            Children =
+            [
+                new ScaleTransform(),
+                new TranslateTransform()
+            ]
+        };
+        _scaleTransform = (ScaleTransform)((TransformGroup)ImageZoomBorder.RenderTransform)
+            .Children.First(tr => tr is ScaleTransform);
+
+        _translateTransform = (TranslateTransform)((TransformGroup)ImageZoomBorder.RenderTransform)
+            .Children.First(tr => tr is TranslateTransform);
+    }
+
+    public void ZoomIn(PointerWheelEventArgs e)
+    {
+        ZoomTo(e, true);
+    }
+
+    public void ZoomOut(PointerWheelEventArgs e)
+    {
+        ZoomTo(e, false);
+    }
+
+    public void ZoomTo(double zoomValue)
+    {
+        var absoluteX = _start.X * _scaleTransform.ScaleX + _translateTransform.X;
+        var absoluteY = _start.Y * _scaleTransform.ScaleY + _translateTransform.Y;
+
+        var newTranslateValueX = Math.Abs(zoomValue - 1) > .1 ? absoluteX - _start.X * zoomValue : 0;
+        var newTranslateValueY = Math.Abs(zoomValue - 1) > .1 ? absoluteY - _start.Y * zoomValue : 0;
+        Dispatcher.UIThread.InvokeAsync(() =>
+        {
+            _scaleTransform.ScaleX = zoomValue;
+            _scaleTransform.ScaleY = zoomValue;
+            _translateTransform.X = newTranslateValueX;
+            _translateTransform.Y = newTranslateValueY;
+        }, DispatcherPriority.Normal);
+
+        //var duration = TimeSpan.FromSeconds(.25);
+
+        //var anim = new Animation
+        //{
+        //    Duration = duration,
+        //    Children =
+        //    {
+        //        new KeyFrame
+        //        {
+        //            Cue = Cue.Parse(zoomValue.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture),
+        //            Setters =
+        //            {
+        //                new Setter { Property = ScaleTransform.ScaleXProperty, Value = zoomValue },
+        //                new Setter { Property = ScaleTransform.ScaleYProperty, Value = zoomValue },
+        //                new Setter { Property = TranslateTransform.XProperty, Value = newTranslateValueX },
+        //                new Setter { Property = TranslateTransform.YProperty, Value = newTranslateValueY },
+        //            },
+        //        }
+        //    }
+        //};
+        //anim.RunAsync(ImageZoomBorder);
+        //while (anim.IsAnimating(ScaleTransform.ScaleXProperty))
+        //{
+        //}
+    }
+
+    public void ZoomTo(PointerWheelEventArgs e, bool isZoomIn)
+    {
+        var currentZoom = _scaleTransform.ScaleX;
+        var zoomSpeed = SettingsHelper.Settings.Zoom.ZoomSpeed;
+
+        switch (currentZoom)
+        {
+            // Increase speed based on the current zoom level
+            case > 14 when isZoomIn:
+                return;
+
+            case > 4:
+                zoomSpeed += 1.5;
+                break;
+
+            case > 3.2:
+                zoomSpeed += 1;
+                break;
+
+            case > 1.6:
+                zoomSpeed += 0.5;
+                break;
+        }
+
+        if (!isZoomIn)
+        {
+            zoomSpeed = -zoomSpeed;
+        }
+
+        currentZoom += zoomSpeed;
+        currentZoom = Math.Max(0.09, currentZoom);
+        ZoomTo(currentZoom);
+    }
+
+    public void ResetZoom(bool animate)
+    {
+        if (animate)
+        {
+            if (Dispatcher.UIThread.CheckAccess())
+            {
+                Set();
+            }
+            else
+            {
+                Dispatcher.UIThread.InvokeAsync(Set, DispatcherPriority.Normal);
+            }
+        }
+        else
+        {
+            if (Dispatcher.UIThread.CheckAccess())
+            {
+                Set();
+            }
+            else
+            {
+                Dispatcher.UIThread.InvokeAsync(Set, DispatcherPriority.Normal);
+            }
+        }
+
+        return;
+
+        void Set()
+        {
+            _scaleTransform.ScaleX = 1;
+            _scaleTransform.ScaleY = 1;
+            _translateTransform.X = 0;
+            _translateTransform.Y = 0;
+        }
+    }
+
+    #endregion Zoom
+
+    private void InputElement_OnPointerPressed(object? sender, PointerPressedEventArgs e)
+    {
+        if (e.ClickCount == 2)
+        {
+            ResetZoom(false);
+        }
+    }
+}

+ 0 - 0
src/PicView.Avalonia/Views/UC/StartUpMenu.axaml → src/PicView.Avalonia/Views/StartUpMenu.axaml


+ 0 - 0
src/PicView.Avalonia/Views/UC/StartUpMenu.axaml.cs → src/PicView.Avalonia/Views/StartUpMenu.axaml.cs


+ 0 - 95
src/PicView.Avalonia/Views/UC/ImageViewer.axaml.cs

@@ -1,95 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Input;
-using Avalonia.Platform.Storage;
-using Avalonia.Threading;
-using PicView.Avalonia.ViewModels;
-using PicView.Core.Config;
-using PicView.Core.Navigation;
-using System.Runtime.InteropServices;
-
-namespace PicView.Avalonia.Views.UC;
-
-public partial class ImageViewer : UserControl
-{
-    public ImageViewer()
-    {
-        InitializeComponent();
-        PointerWheelChanged += async (_, e) => await Main_OnPointerWheelChanged(e);
-        // TODO add visual feedback for drag and drop
-        //AddHandler(DragDrop.DragOverEvent, DragOver);
-        AddHandler(DragDrop.DropEvent, Drop);
-
-        Loaded += delegate
-        {
-            if (DataContext is not MainViewModel vm)
-                return;
-            vm.ImageChanged += (s, e) =>
-            {
-                if (SettingsHelper.Settings.Zoom.ScrollEnabled)
-                {
-                    Dispatcher.UIThread.InvokeAsync(() =>
-                    {
-                        ImageScrollViewer.ScrollToHome();
-                    }, DispatcherPriority.Normal);
-                }
-            };
-        };
-    }
-
-    private void Drop(object? sender, DragEventArgs e)
-    {
-        if (DataContext is not MainViewModel vm)
-            return;
-
-        var data = e.Data.GetFiles();
-        if (data == null)
-        {
-            // TODO Handle URL and folder drops
-            return;
-        }
-
-        var storageItems = data as IStorageItem[] ?? data.ToArray();
-        var firstFile = storageItems.FirstOrDefault();
-        var path = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? firstFile.Path.AbsolutePath : firstFile.Path.LocalPath;
-        _ = vm.LoadPicFromString(path).ConfigureAwait(false);
-        foreach (var file in storageItems.Skip(1))
-        {
-            // TODO Open each file in a new window if the setting to open in the same window is false
-        }
-    }
-
-    private async Task Main_OnPointerWheelChanged(PointerWheelEventArgs e)
-    {
-        if (DataContext is not MainViewModel mainViewModel)
-            return;
-
-        if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
-        {
-            // TODO figure out how to do image navigation with gestures
-            return;
-        }
-
-        if (e.Delta.Y < 0)
-        {
-            if (SettingsHelper.Settings.Zoom.HorizontalReverseScroll)
-            {
-                await mainViewModel.LoadNextPic(NavigateTo.Next);
-            }
-            else
-            {
-                await mainViewModel.LoadNextPic(NavigateTo.Previous);
-            }
-        }
-        else
-        {
-            if (SettingsHelper.Settings.Zoom.HorizontalReverseScroll)
-            {
-                await mainViewModel.LoadNextPic(NavigateTo.Previous);
-            }
-            else
-            {
-                await mainViewModel.LoadNextPic(NavigateTo.Next);
-            }
-        }
-    }
-}

+ 1 - 10
src/PicView.Avalonia/Views/UC/Menus/FileMenu.axaml

@@ -26,7 +26,7 @@
                     Height="47"
                     Background="{StaticResource SecondaryBackgroundColor}"
                     BorderBrush="{StaticResource MainBorderColor}"
-                    BorderThickness="1"
+                    BorderThickness="0,0,0,1"
                     CornerRadius="8,8,0,0" />
 
                 <Button
@@ -154,15 +154,6 @@
                         Stretch="Fill" />
                 </Button>
 
-                <Rectangle
-                    Canvas.Left="1"
-                    Canvas.Top="46"
-                    Width="275"
-                    Height="1"
-                    Stroke="{StaticResource MainBorderColor}"
-                    StrokeThickness="1"
-                    ZIndex="1" />
-
                 <Button
                     Canvas.Left="7"
                     Canvas.Top="53"

+ 6 - 12
src/PicView.Avalonia/Views/UC/Menus/ImageMenu.axaml

@@ -26,7 +26,7 @@
                     Height="47"
                     Background="{StaticResource SecondaryBackgroundColor}"
                     BorderBrush="{StaticResource MainBorderColor}"
-                    BorderThickness="1"
+                    BorderThickness="0,0,0,1"
                     CornerRadius="8,8,0,0" />
 
                 <Button
@@ -61,7 +61,8 @@
                     BorderBrush="{StaticResource MainBorderColor}"
                     BorderThickness="0,0,1,0"
                     Classes="hover"
-                    ToolTip.Tip="{Binding Crop}">
+                    Command="{Binding RotateRightCommand}"
+                    ToolTip.Tip="{Binding RotateRight}">
                     <Path
                         Width="15"
                         Height="15"
@@ -77,7 +78,9 @@
                     Background="Transparent"
                     BorderBrush="{StaticResource MainBorderColor}"
                     BorderThickness="0,0,1,0"
-                    Classes="hover">
+                    Classes="hover"
+                    Command="{Binding FlipCommand}"
+                    ToolTip.Tip="{Binding GetFlipped}">
                     <Path
                         Width="13"
                         Height="13"
@@ -170,15 +173,6 @@
                         Stretch="Fill" />
                 </Button>
 
-                <Rectangle
-                    Canvas.Left="1"
-                    Canvas.Top="46"
-                    Width="275"
-                    Height="1"
-                    Stroke="{StaticResource MainBorderColor}"
-                    StrokeThickness="1"
-                    ZIndex="1" />
-
                 <Button
                     Canvas.Left="7"
                     Canvas.Top="53"

+ 1 - 10
src/PicView.Avalonia/Views/UC/Menus/SettingsMenu.axaml

@@ -26,7 +26,7 @@
                     Height="47"
                     Background="{StaticResource SecondaryBackgroundColor}"
                     BorderBrush="{StaticResource MainBorderColor}"
-                    BorderThickness="1"
+                    BorderThickness="0,0,0,1"
                     CornerRadius="8,8,0,0" />
 
                 <Button
@@ -132,15 +132,6 @@
                         Stretch="Fill" />
                 </Button>
 
-                <Rectangle
-                    Canvas.Left="1"
-                    Canvas.Top="46"
-                    Width="275"
-                    Height="1"
-                    Stroke="{StaticResource MainBorderColor}"
-                    StrokeThickness="1"
-                    ZIndex="1" />
-
                 <ToggleButton
                     Canvas.Left="7"
                     Canvas.Top="53"

+ 1 - 10
src/PicView.Avalonia/Views/UC/Menus/ToolsMenu.axaml

@@ -26,7 +26,7 @@
                     Height="47"
                     Background="{StaticResource SecondaryBackgroundColor}"
                     BorderBrush="{StaticResource MainBorderColor}"
-                    BorderThickness="1"
+                    BorderThickness="0,0,0,1"
                     CornerRadius="8,8,0,0" />
 
                 <Button
@@ -142,15 +142,6 @@
                         Stretch="Fill" />
                 </Button>
 
-                <Rectangle
-                    Canvas.Left="1"
-                    Canvas.Top="46"
-                    Width="275"
-                    Height="1"
-                    Stroke="{StaticResource MainBorderColor}"
-                    StrokeThickness="1"
-                    ZIndex="1" />
-
                 <Button
                     Canvas.Left="7"
                     Canvas.Top="53"

+ 2 - 2
src/PicView.Core/Calculations/ImageSizeCalculationHelper.cs

@@ -47,8 +47,8 @@ public static class ImageSizeCalculationHelper
         var borderSpaceHeight = fullscreen ? 0 : uiTopSize + uiBottomSize + galleryHeight;
         var borderSpaceWidth = fullscreen ? 0 : padding;
 
-        var workAreaWidth = (monitorWidth * dpiScaling) - borderSpaceWidth;
-        var workAreaHeight = (monitorHeight * dpiScaling) - borderSpaceHeight;
+        var workAreaWidth = monitorWidth * dpiScaling - borderSpaceWidth;
+        var workAreaHeight = monitorHeight * dpiScaling - borderSpaceHeight;
 
         if (autoFit)
         {