浏览代码

Added scrollbar interactions

MarcinZiabek 3 年之前
父节点
当前提交
ff95fe287a

+ 3 - 3
QuestPDF.Previewer.Examples/Program.cs

@@ -7,9 +7,9 @@ using QuestPDF.ReportSample;
 using QuestPDF.ReportSample.Layouts;
 using Colors = QuestPDF.Helpers.Colors;
 
-var model = DataSource.GetReport();
-var report = new StandardReport(model);
-report.ShowInPreviewer();
+// var model = DataSource.GetReport();
+// var report = new StandardReport(model);
+// report.ShowInPreviewer();
 
 Document
     .Create(container =>

+ 48 - 18
QuestPDF.Previewer/InteractiveCanvas.cs

@@ -1,4 +1,5 @@
-using Avalonia;
+using System.Diagnostics;
+using Avalonia;
 using Avalonia.Platform;
 using Avalonia.Rendering.SceneGraph;
 using Avalonia.Skia;
@@ -13,17 +14,45 @@ class InteractiveCanvas : ICustomDrawOperation
 
     private float Width => (float)Bounds.Width;
     private float Height => (float)Bounds.Height;
-    
+
     public float Scale { get; private set; } = 1;
-    public float TranslateX { get; private set; }
-    public float TranslateY { get; private set; }
+    public float TranslateX { get; set; }
+    public float TranslateY { get; set; }
 
     private const float MinScale = 0.1f;
     private const float MaxScale = 10f;
-    
+
     private const float PageSpacing = 25f;
     private const float SafeZone = 50f;
 
+    public float TotalHeight => Pages.Sum(x => x.Size.Height) + (Pages.Count - 1) * PageSpacing;
+    public float MaxWidth => Pages.Max(x => x.Size.Width);
+    public float MaxTranslateY => -(Height / 2 - SafeZone) / Scale;
+    public float MinTranslateY => (Height / 2 - SafeZone) / Scale - TotalHeight;
+
+    public float ScrollPercentY
+    {
+        get
+        {
+            return Math.Clamp(1 - (TranslateY - MinTranslateY) / (MaxTranslateY - MinTranslateY), 0, 1);
+        }
+        set
+        {
+            TranslateY = (1 - value) * (MaxTranslateY - MinTranslateY) + MinTranslateY;
+        }
+    }
+
+    public float ScrollViewportSizeY
+    {
+        get
+        {
+            if (TotalHeight * Scale < Height)
+                return 1;
+            
+            return Math.Clamp(Height / Scale / (MaxTranslateY - MinTranslateY), 0, 1);
+        }
+    }
+
     #region transformations
     
     private void LimitScale()
@@ -34,26 +63,27 @@ class InteractiveCanvas : ICustomDrawOperation
     
     private void LimitTranslate()
     {
-        var totalHeight = Pages.Sum(x => x.Size.Height) + (Pages.Count - 1) * PageSpacing;
-        var maxWidth = Pages.Max(x => x.Size.Width);
-
-        var maxTranslateY = - (Height / 2 - SafeZone) / Scale;
-        var minTranslateY = (Height / 2 - SafeZone) / Scale - totalHeight;
-        
-        TranslateY = Math.Min(TranslateY, maxTranslateY);
-        TranslateY = Math.Max(TranslateY, minTranslateY);
-        
-        if (maxWidth < Width / Scale)
+        if (TotalHeight * Scale > Height)
         {
-            TranslateX = 0;
+            TranslateY = Math.Min(TranslateY, MaxTranslateY);
+            TranslateY = Math.Max(TranslateY, MinTranslateY);
         }
         else
         {
-            var maxTranslateX = (Width / 2 - SafeZone) / Scale - maxWidth / 2;
-        
+            TranslateY = -TotalHeight / 2;
+        }
+
+        if (Width / Scale < MaxWidth)
+        {
+            var maxTranslateX = (Width / 2 - SafeZone) / Scale - MaxWidth / 2;
+
             TranslateX = Math.Min(TranslateX, -maxTranslateX);
             TranslateX = Math.Max(TranslateX, maxTranslateX);
         }
+        else
+        {
+            TranslateX = 0;
+        }
     }
 
     public void TranslateWithCurrentScale(float x, float y)

+ 32 - 3
QuestPDF.Previewer/PreviewerControl.cs

@@ -1,17 +1,19 @@
 using System.Collections.ObjectModel;
+using System.Diagnostics;
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Input;
 using Avalonia.Media;
+using ReactiveUI;
 
 namespace QuestPDF.Previewer
 {
     class PreviewerControl : Control
     {
-        public static readonly StyledProperty<ObservableCollection<PreviewPage>?> PagesProperty =
+        private InteractiveCanvas InteractiveCanvas { get; set; } = new ();
+        
+        public static readonly StyledProperty<ObservableCollection<PreviewPage>> PagesProperty =
             AvaloniaProperty.Register<PreviewerControl, ObservableCollection<PreviewPage>>(nameof(Pages));
-
-        private InteractiveCanvas InteractiveCanvas { get; set; } = new InteractiveCanvas();
         
         public ObservableCollection<PreviewPage>? Pages
         {
@@ -19,14 +21,38 @@ namespace QuestPDF.Previewer
             set => SetValue(PagesProperty, value);
         }
 
+        public static readonly StyledProperty<float> CurrentScrollProperty = AvaloniaProperty.Register<PreviewerControl, float>(nameof(CurrentScroll));
+        
+        public float CurrentScroll
+        {
+            get => GetValue(CurrentScrollProperty);
+            set => SetValue(CurrentScrollProperty, value);
+        }
+        
+        public static readonly StyledProperty<float> ScrollViewportSizeProperty = AvaloniaProperty.Register<PreviewerControl, float>(nameof(ScrollViewportSize));
+        
+        public float ScrollViewportSize
+        {
+            get => GetValue(ScrollViewportSizeProperty);
+            set => SetValue(ScrollViewportSizeProperty, value);
+        }
+        
         public PreviewerControl()
         {
+            ScrollViewportSize = 0.5f;
+            
             PagesProperty.Changed.Subscribe(p =>
             {
                 InteractiveCanvas.Pages = Pages;
                 InvalidateVisual();
             });
 
+            CurrentScrollProperty.Changed.Subscribe(p =>
+            {
+                InteractiveCanvas.ScrollPercentY = CurrentScroll;
+                InvalidateVisual();
+            });
+
             ClipToBounds = true;
         }
         
@@ -84,6 +110,9 @@ namespace QuestPDF.Previewer
 
         public override void Render(DrawingContext context)
         {
+            CurrentScroll = InteractiveCanvas.ScrollPercentY;
+            ScrollViewportSize = InteractiveCanvas.ScrollViewportSizeY;
+    
             InteractiveCanvas.Bounds = new Rect(0, 0, Bounds.Width, Bounds.Height);
 
             context.Custom(InteractiveCanvas);

+ 13 - 6
QuestPDF.Previewer/PreviewerWindow.axaml

@@ -19,7 +19,6 @@
 			<Grid.RowDefinitions>
 				<RowDefinition Height="32" />
 				<RowDefinition Height="*" />
-				<RowDefinition Height="Auto" />
 			</Grid.RowDefinitions>
 
 			<Grid.ColumnDefinitions>
@@ -29,15 +28,23 @@
 			
 			<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" 
 			           VerticalAlignment="Center" HorizontalAlignment="Center" 
-			           TextAlignment="Center" Text="QuestPDF Document Preview" FontSize="14" Foreground="#DFFF" FontWeight="Regular" />
+			           TextAlignment="Center" Text="QuestPDF Document Preview" FontSize="14" Foreground="#DFFF" FontWeight="Regular" IsHitTestVisible="False" />
 			
-			<previewer:PreviewerControl Grid.Row="1" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2"
+			<previewer:PreviewerControl Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
 			                            HorizontalAlignment="Stretch" 
 			                            VerticalAlignment="Stretch"
+			                            CurrentScroll="{Binding #Window.CurrentScroll, Mode=TwoWay}"
+			                            ScrollViewportSize="{Binding #Window.ScrollViewportSize, Mode=OneWayToSource}"
 			                            Pages="{Binding #Window.DocumentRenderer.Pages, Mode=OneWay}" />
-			
-			<ScrollBar Grid.Row="2" Grid.Column="0" Orientation="Horizontal" />
-			<ScrollBar Grid.Row="1" Grid.Column="1" Orientation="Vertical" />
+
+
+			<ScrollBar Grid.Row="1" Grid.Column="1" 
+			           Orientation="Vertical" 
+			           AllowAutoHide="False" 
+			           Minimum="0" Maximum="1" 
+			           IsVisible="{Binding #Window.VerticalScrollbarVisible}"
+			           Value="{Binding #Window.CurrentScroll, Mode=TwoWay}" 
+			           ViewportSize="{Binding #Window.ScrollViewportSize, Mode=OneWay}"></ScrollBar>
 		</Grid>
 	</Panel>
 </Window>

+ 41 - 3
QuestPDF.Previewer/PreviewerWindow.axaml.cs

@@ -1,8 +1,13 @@
-using Avalonia;
+using System.Diagnostics;
+using Avalonia;
 using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Interactivity;
 using Avalonia.Markup.Xaml;
 using Avalonia.Threading;
+using QuestPDF.Helpers;
 using QuestPDF.Infrastructure;
+using ReactiveUI;
 
 namespace QuestPDF.Previewer
 {
@@ -18,11 +23,44 @@ namespace QuestPDF.Previewer
             get => GetValue(DocumentProperty);
             set => SetValue(DocumentProperty, value);
         }
-
+        
+        
+        
+        public static readonly StyledProperty<float> CurrentScrollProperty = AvaloniaProperty.Register<PreviewerControl, float>(nameof(CurrentScroll));
+        
+        public float CurrentScroll
+        {
+            get => GetValue(CurrentScrollProperty);
+            set => SetValue(CurrentScrollProperty, value);
+        }
+        
+        public static readonly StyledProperty<float> ScrollViewportSizeProperty = AvaloniaProperty.Register<PreviewerControl, float>(nameof(ScrollViewportSize));
+        
+        public float ScrollViewportSize
+        {
+            get => GetValue(ScrollViewportSizeProperty);
+            set => SetValue(ScrollViewportSizeProperty, value);
+        }
+        
+        public static readonly StyledProperty<bool> VerticalScrollbarVisibleProperty = AvaloniaProperty.Register<PreviewerControl, bool>(nameof(VerticalScrollbarVisible));
+        
+        public bool VerticalScrollbarVisible
+        {
+            get => GetValue(VerticalScrollbarVisibleProperty);
+            set => SetValue(VerticalScrollbarVisibleProperty, value);
+        }
+        
+        
         public PreviewerWindow()
         {
             InitializeComponent();
-            //
+
+            ScrollViewportSizeProperty.Changed.Subscribe(_ =>
+            {
+                VerticalScrollbarVisible = ScrollViewportSize < 1;
+                Debug.WriteLine($"Scrollbar visible: {VerticalScrollbarVisible}");
+            });
+            
             // this.FindControl<Button>("GeneratePdf")
             //     .Click += (_, _) => _ = PreviewerUtils.SavePdfWithDialog(Document, this);
 

+ 0 - 1
QuestPDF.ReportSample/Layouts/PhotoTemplate.cs

@@ -49,7 +49,6 @@ namespace QuestPDF.ReportSample.Layouts
             {
                 grid.Columns(6);
 
-
                 grid.Item().LabelCell().Text("Date");
                 grid.Item(2).ValueCell().Text(Model.Date?.ToString("g") ?? string.Empty);
                 grid.Item().LabelCell().Text("Location");