From b2826a06b868fb9fcd8189c1f99ff1e71c7b58cb Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Mon, 21 Mar 2022 01:16:26 +0100 Subject: [PATCH] Code refactorization + cleanup --- QuestPDF.Previewer/DocumentRenderer.cs | 76 +++++-------------- QuestPDF.Previewer/ExceptionDocument.cs | 55 ++++++++++++++ QuestPDF.Previewer/InteractiveCanvas.cs | 43 ++++++----- QuestPDF.Previewer/PreviewerCanvas.cs | 31 ++++---- QuestPDF.Previewer/PreviewerControl.cs | 11 +-- QuestPDF.Previewer/SkCustomDrawOperation.cs | 39 ---------- .../Layouts/PhotoTemplate.cs | 4 +- 7 files changed, 119 insertions(+), 140 deletions(-) create mode 100644 QuestPDF.Previewer/ExceptionDocument.cs delete mode 100644 QuestPDF.Previewer/SkCustomDrawOperation.cs diff --git a/QuestPDF.Previewer/DocumentRenderer.cs b/QuestPDF.Previewer/DocumentRenderer.cs index f61b23b..36bb61b 100644 --- a/QuestPDF.Previewer/DocumentRenderer.cs +++ b/QuestPDF.Previewer/DocumentRenderer.cs @@ -2,10 +2,7 @@ using System.ComponentModel; using Avalonia.Threading; using QuestPDF.Drawing; -using QuestPDF.Fluent; -using QuestPDF.Helpers; using QuestPDF.Infrastructure; -using SkiaSharp; namespace QuestPDF.Previewer { @@ -17,8 +14,8 @@ namespace QuestPDF.Previewer public event PropertyChangedEventHandler? PropertyChanged; - private ObservableCollection _pages = new(); - public ObservableCollection Pages + private ObservableCollection _pages = new(); + public ObservableCollection Pages { get => _pages; set @@ -48,21 +45,23 @@ namespace QuestPDF.Previewer public void UpdateDocument(IDocument? document) { Document = document; - if (document != null) + + if (document == null) + return; + + try { - try - { - IsRendering = true; - RenderDocument(document); - } - catch (Exception ex) - { - RenderDocument(CreateExceptionDocument(ex)); - } - finally - { - IsRendering = false; - } + IsRendering = true; + RenderDocument(document); + } + catch (Exception exception) + { + var exceptionDocument = new ExceptionDocument(exception); + RenderDocument(exceptionDocument); + } + finally + { + IsRendering = false; } } @@ -82,44 +81,7 @@ namespace QuestPDF.Previewer Dispatcher.UIThread.Post(() => { Pages.Clear(); - Pages = new ObservableCollection(canvas.Pictures); - }); - } - - private static IDocument CreateExceptionDocument(Exception exception) - { - return Fluent.Document.Create(document => - { - document.Page(page => - { - page.Size(PageSizes.A4); - page.Margin(1, Unit.Inch); - page.PageColor(Colors.Red.Lighten4); - page.DefaultTextStyle(x => x.FontSize(16)); - - page.Header() - .BorderBottom(2) - .BorderColor(Colors.Red.Medium) - .PaddingBottom(5) - .Text("Ooops! Something went wrong...").FontSize(28).FontColor(Colors.Red.Medium).Bold(); - - page.Content().PaddingVertical(20).Column(column => - { - var currentException = exception; - - while (currentException != null) - { - column.Item().Text(exception.GetType().Name).FontSize(20).SemiBold(); - column.Item().Text(exception.Message).FontSize(14); - column.Item().PaddingTop(10).Text(exception.StackTrace).FontSize(10).Light(); - - currentException = currentException.InnerException; - - if (currentException != null) - column.Item().PaddingVertical(15).LineHorizontal(2).LineColor(Colors.Red.Medium); - } - }); - }); + Pages = new ObservableCollection(canvas.Pictures); }); } } diff --git a/QuestPDF.Previewer/ExceptionDocument.cs b/QuestPDF.Previewer/ExceptionDocument.cs new file mode 100644 index 0000000..fbe8e0f --- /dev/null +++ b/QuestPDF.Previewer/ExceptionDocument.cs @@ -0,0 +1,55 @@ +using QuestPDF.Drawing; +using QuestPDF.Fluent; +using QuestPDF.Helpers; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Previewer; + +public class ExceptionDocument : IDocument +{ + private Exception Exception { get; } + + public ExceptionDocument(Exception exception) + { + Exception = exception; + } + + public DocumentMetadata GetMetadata() + { + return DocumentMetadata.Default; + } + + public void Compose(IDocumentContainer document) + { + document.Page(page => + { + page.Size(PageSizes.A4); + page.Margin(1, Unit.Inch); + page.PageColor(Colors.Red.Lighten4); + page.DefaultTextStyle(x => x.FontSize(16)); + + page.Header() + .BorderBottom(2) + .BorderColor(Colors.Red.Medium) + .PaddingBottom(5) + .Text("Ooops! Something went wrong...").FontSize(28).FontColor(Colors.Red.Medium).Bold(); + + page.Content().PaddingVertical(20).Column(column => + { + var currentException = Exception; + + while (currentException != null) + { + column.Item().Text(currentException.GetType().Name).FontSize(20).SemiBold(); + column.Item().Text(currentException.Message).FontSize(14); + column.Item().PaddingTop(10).Text(currentException.StackTrace).FontSize(10).Light(); + + currentException = currentException.InnerException; + + if (currentException != null) + column.Item().PaddingVertical(15).LineHorizontal(2).LineColor(Colors.Red.Medium); + } + }); + }); + } +} \ No newline at end of file diff --git a/QuestPDF.Previewer/InteractiveCanvas.cs b/QuestPDF.Previewer/InteractiveCanvas.cs index e4a7a79..b826762 100644 --- a/QuestPDF.Previewer/InteractiveCanvas.cs +++ b/QuestPDF.Previewer/InteractiveCanvas.cs @@ -1,9 +1,7 @@ -using System.Diagnostics; -using Avalonia; +using Avalonia; using Avalonia.Platform; using Avalonia.Rendering.SceneGraph; using Avalonia.Skia; -using QuestPDF.Helpers; using SkiaSharp; namespace QuestPDF.Previewer; @@ -11,7 +9,7 @@ namespace QuestPDF.Previewer; class InteractiveCanvas : ICustomDrawOperation { public Rect Bounds { get; set; } - public ICollection Pages { get; set; } + public ICollection Pages { get; set; } private float Width => (float)Bounds.Width; private float Height => (float)Bounds.Height; @@ -26,6 +24,8 @@ class InteractiveCanvas : ICustomDrawOperation private const float PageSpacing = 50f; private const float SafeZone = 50f; + #region transformations + private void LimitScale() { Scale = Math.Max(Scale, MinScale); @@ -79,15 +79,15 @@ class InteractiveCanvas : ICustomDrawOperation LimitTranslate(); } + #endregion + + #region rendering + public void Render(IDrawingContextImpl context) { if (Pages.Count <= 0) return; - LimitScale(); - LimitTranslate(); - - var canvas = (context as ISkiaDrawingContextImpl)?.SkCanvas; if (canvas == null) @@ -95,7 +95,6 @@ class InteractiveCanvas : ICustomDrawOperation var originalMatrix = canvas.TotalMatrix; - canvas.Translate(Width / 2, Height / 2); canvas.Scale(Scale); @@ -104,7 +103,7 @@ class InteractiveCanvas : ICustomDrawOperation foreach (var page in Pages) { canvas.Translate(-page.Size.Width / 2f, 0); - DrawPageShadow(canvas, page.Size); + DrawBlankPage(canvas, page.Size); canvas.DrawPicture(page.Picture); canvas.Translate(page.Size.Width / 2f, page.Size.Height + PageSpacing); } @@ -119,19 +118,27 @@ class InteractiveCanvas : ICustomDrawOperation public bool Equals(ICustomDrawOperation? other) => false; public bool HitTest(Point p) => true; - #region page shadow - - private static readonly SKImageFilter PageShadow1 = SKImageFilter.CreateDropShadowOnly(0, 6, 6, 6, SKColors.Black.WithAlpha(64)); - private static readonly SKImageFilter PageShadow2 = SKImageFilter.CreateDropShadowOnly(0, 10, 14, 14, SKColors.Black.WithAlpha(32)); + #endregion - private static SKPaint PageShadowPaint = new SKPaint + #region blank page + + private static SKPaint BlankPagePaint = new SKPaint { - ImageFilter = SKImageFilter.CreateBlendMode(SKBlendMode.Overlay, PageShadow1, PageShadow2) + Color = SKColors.White }; - private void DrawPageShadow(SKCanvas canvas, QuestPDF.Infrastructure.Size size) + private static SKPaint BlankPageShadowPaint = new SKPaint { - canvas.DrawRect(0, 0, size.Width, size.Height, PageShadowPaint); + ImageFilter = SKImageFilter.CreateBlendMode( + SKBlendMode.Overlay, + SKImageFilter.CreateDropShadowOnly(0, 6, 6, 6, SKColors.Black.WithAlpha(64)), + SKImageFilter.CreateDropShadowOnly(0, 10, 14, 14, SKColors.Black.WithAlpha(32))) + }; + + private void DrawBlankPage(SKCanvas canvas, QuestPDF.Infrastructure.Size size) + { + canvas.DrawRect(0, 0, size.Width, size.Height, BlankPageShadowPaint); + canvas.DrawRect(0, 0, size.Width, size.Height, BlankPagePaint); } #endregion diff --git a/QuestPDF.Previewer/PreviewerCanvas.cs b/QuestPDF.Previewer/PreviewerCanvas.cs index c57364b..fa10cdd 100644 --- a/QuestPDF.Previewer/PreviewerCanvas.cs +++ b/QuestPDF.Previewer/PreviewerCanvas.cs @@ -4,16 +4,15 @@ using SkiaSharp; namespace QuestPDF.Previewer { - public record RenderedPageInfo(SKPicture Picture, Size Size); + public record PreviewPage(SKPicture Picture, Size Size); internal sealed class PreviewerCanvas : SkiaCanvasBase, IRenderingCanvas { - private SKPictureRecorder? _currentRecorder; + private SKPictureRecorder? PictureRecorder { get; set; } + private Size? CurrentPageSize { get; set; } + + public ICollection Pictures { get; } = new List(); - public ICollection Pictures { get; } = new List(); - - private Size? _currentSize; - public override void BeginDocument() { Pictures.Clear(); @@ -21,23 +20,21 @@ namespace QuestPDF.Previewer public override void BeginPage(Size size) { - _currentSize = size; - _currentRecorder = new SKPictureRecorder(); - Canvas = _currentRecorder.BeginRecording(new SKRect(0, 0, size.Width, size.Height)); - - using var paint = new SKPaint() { Color = SKColors.White }; - Canvas.DrawRect(0, 0, size.Width, size.Height, paint); + CurrentPageSize = size; + PictureRecorder = new SKPictureRecorder(); + + Canvas = PictureRecorder.BeginRecording(new SKRect(0, 0, size.Width, size.Height)); } public override void EndPage() { - var picture = _currentRecorder?.EndRecording(); + var picture = PictureRecorder?.EndRecording(); - if (picture != null && _currentSize.HasValue) - Pictures.Add(new RenderedPageInfo(picture, _currentSize.Value)); + if (picture != null && CurrentPageSize.HasValue) + Pictures.Add(new PreviewPage(picture, CurrentPageSize.Value)); - _currentRecorder?.Dispose(); - _currentRecorder = null; + PictureRecorder?.Dispose(); + PictureRecorder = null; } public override void EndDocument() { } diff --git a/QuestPDF.Previewer/PreviewerControl.cs b/QuestPDF.Previewer/PreviewerControl.cs index ee98950..1688a7b 100644 --- a/QuestPDF.Previewer/PreviewerControl.cs +++ b/QuestPDF.Previewer/PreviewerControl.cs @@ -1,24 +1,19 @@ using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Reactive.Linq; -using System.Runtime.InteropServices.ComTypes; using Avalonia; using Avalonia.Controls; -using Avalonia.Controls.Presenters; using Avalonia.Input; -using Avalonia.Interactivity; using Avalonia.Media; namespace QuestPDF.Previewer { internal class PreviewerControl : Control { - public static readonly StyledProperty?> PagesProperty = - AvaloniaProperty.Register>(nameof(Pages)); + public static readonly StyledProperty?> PagesProperty = + AvaloniaProperty.Register>(nameof(Pages)); private InteractiveCanvas InteractiveCanvas { get; set; } = new InteractiveCanvas(); - public ObservableCollection? Pages + public ObservableCollection? Pages { get => GetValue(PagesProperty); set => SetValue(PagesProperty, value); diff --git a/QuestPDF.Previewer/SkCustomDrawOperation.cs b/QuestPDF.Previewer/SkCustomDrawOperation.cs deleted file mode 100644 index 5cec3e5..0000000 --- a/QuestPDF.Previewer/SkCustomDrawOperation.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Avalonia; -using Avalonia.Platform; -using Avalonia.Rendering.SceneGraph; -using Avalonia.Skia; -using SkiaSharp; - -namespace QuestPDF.Previewer -{ - internal sealed class SkCustomDrawOperation : ICustomDrawOperation - { - private readonly Action _renderFunc; - public Rect Bounds { get; } - - public SkCustomDrawOperation(Rect bounds, Action renderFunc) - { - Bounds = bounds; - _renderFunc = renderFunc; - } - - public void Dispose() { } - public bool Equals(ICustomDrawOperation? other) - { - return false; - } - public bool HitTest(Point p) - { - return false; - } - - public void Render(IDrawingContextImpl context) - { - var canvas = (context as ISkiaDrawingContextImpl)?.SkCanvas; - if (canvas == null) - throw new InvalidOperationException($"Context needs to be ISkiaDrawingContextImpl but got {nameof(context)}"); - - _renderFunc(canvas); - } - } -} diff --git a/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs b/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs index f578e95..87d1ce2 100644 --- a/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs @@ -1,3 +1,4 @@ +using System; using QuestPDF.Fluent; using QuestPDF.Helpers; using QuestPDF.Infrastructure; @@ -47,7 +48,8 @@ namespace QuestPDF.ReportSample.Layouts container.Border(0.75f).BorderColor(Colors.Grey.Medium).Grid(grid => { grid.Columns(6); - + + grid.Item().LabelCell().Text("Date"); grid.Item(2).ValueCell().Text(Model.Date?.ToString("g") ?? string.Empty); grid.Item().LabelCell().Text("Location");