PreviewerControl.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. using System.Collections.ObjectModel;
  2. using Avalonia;
  3. using Avalonia.Controls;
  4. using Avalonia.Input;
  5. using Avalonia.Media;
  6. using Avalonia.Threading;
  7. namespace QuestPDF.Previewer
  8. {
  9. class PreviewerControl : Control
  10. {
  11. private InteractiveCanvas InteractiveCanvas { get; set; } = new();
  12. public static readonly StyledProperty<float> CurrentScrollProperty = AvaloniaProperty.Register<PreviewerControl, float>(nameof(CurrentScroll));
  13. public float CurrentScroll
  14. {
  15. get => GetValue(CurrentScrollProperty);
  16. set => SetValue(CurrentScrollProperty, value);
  17. }
  18. public static readonly StyledProperty<float> ScrollViewportSizeProperty = AvaloniaProperty.Register<PreviewerControl, float>(nameof(ScrollViewportSize));
  19. public float ScrollViewportSize
  20. {
  21. get => GetValue(ScrollViewportSizeProperty);
  22. set => SetValue(ScrollViewportSizeProperty, value);
  23. }
  24. public PreviewerControl()
  25. {
  26. var requestedRenderings = new HashSet<(int pageIndex, int zoomLevel)>();
  27. CommunicationService.Instance.OnDocumentUpdated += document =>
  28. {
  29. requestedRenderings.Clear();
  30. InteractiveCanvas.SetNewDocumentStructure(document);
  31. Dispatcher.UIThread.InvokeAsync(InvalidateVisual).GetTask();
  32. };
  33. Task.Run(async () =>
  34. {
  35. while (true)
  36. {
  37. var missingSnapshots = InteractiveCanvas.GetMissingSnapshots().Select(x => (x.PageIndex, x.ZoomLevel)).ToList();
  38. if (!missingSnapshots.Any())
  39. {
  40. await Task.Delay(10);
  41. continue;
  42. }
  43. foreach (var pageSnapshotIndex in missingSnapshots.Except(requestedRenderings).ToList())
  44. {
  45. requestedRenderings.Add(pageSnapshotIndex);
  46. CommunicationService.Instance.RequestNewPage(new PageSnapshotIndex
  47. {
  48. PageIndex = pageSnapshotIndex.Item1,
  49. ZoomLevel = pageSnapshotIndex.Item2
  50. });
  51. }
  52. }
  53. });
  54. CommunicationService.Instance.OnPageSnapshotsProvided += snapshot =>
  55. {
  56. InteractiveCanvas.AddSnapshots(snapshot);
  57. Dispatcher.UIThread.InvokeAsync(InvalidateVisual).GetTask();
  58. };
  59. CurrentScrollProperty.Changed.Subscribe(x =>
  60. {
  61. InteractiveCanvas.ScrollPercentY = x.NewValue.Value;
  62. Dispatcher.UIThread.InvokeAsync(InvalidateVisual).GetTask();
  63. });
  64. ClipToBounds = true;
  65. }
  66. protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
  67. {
  68. base.OnPointerWheelChanged(e);
  69. if ((e.KeyModifiers & KeyModifiers.Control) != 0)
  70. {
  71. var scaleFactor = 1 + e.Delta.Y / 10f;
  72. var point = new Point(Bounds.Center.X, Bounds.Top) - e.GetPosition(this);
  73. InteractiveCanvas.ZoomToPoint((float)point.X, -(float)point.Y, (float)scaleFactor);
  74. }
  75. if (e.KeyModifiers == KeyModifiers.None)
  76. {
  77. var translation = (float)e.Delta.Y * 25;
  78. InteractiveCanvas.TranslateWithCurrentScale(0, -translation);
  79. }
  80. InvalidateVisual();
  81. }
  82. private bool IsMousePressed { get; set; }
  83. private Vector MousePosition { get; set; }
  84. protected override void OnPointerMoved(PointerEventArgs e)
  85. {
  86. base.OnPointerMoved(e);
  87. if (IsMousePressed)
  88. {
  89. var currentPosition = e.GetPosition(this);
  90. var translation = currentPosition - MousePosition;
  91. InteractiveCanvas.TranslateWithCurrentScale((float)translation.X, -(float)translation.Y);
  92. InvalidateVisual();
  93. }
  94. MousePosition = e.GetPosition(this);
  95. }
  96. protected override void OnPointerPressed(PointerPressedEventArgs e)
  97. {
  98. base.OnPointerPressed(e);
  99. IsMousePressed = true;
  100. }
  101. protected override void OnPointerReleased(PointerReleasedEventArgs e)
  102. {
  103. base.OnPointerReleased(e);
  104. IsMousePressed = false;
  105. }
  106. public override void Render(DrawingContext context)
  107. {
  108. CurrentScroll = InteractiveCanvas.ScrollPercentY;
  109. ScrollViewportSize = InteractiveCanvas.ScrollViewportSizeY;
  110. InteractiveCanvas.RenderingScale = (float)VisualRoot.RenderScaling;
  111. InteractiveCanvas.Bounds = new Rect(0, 0, Bounds.Width, Bounds.Height);
  112. context.Custom(InteractiveCanvas);
  113. base.Render(context);
  114. }
  115. }
  116. }