LayoutOverflowVisualization.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. using System;
  2. using QuestPDF.Drawing;
  3. using QuestPDF.Drawing.Proxy;
  4. using QuestPDF.Helpers;
  5. using QuestPDF.Infrastructure;
  6. using QuestPDF.Skia;
  7. namespace QuestPDF.Elements;
  8. internal class LayoutOverflowVisualization : ContainerElement, IContentDirectionAware
  9. {
  10. private const float BorderThickness = 1.5f;
  11. private readonly Color LineColor = Colors.Red.Medium;
  12. private readonly Color AvailableAreaColor = Colors.Green.Medium;
  13. private const byte AreaOpacity = 64;
  14. public ContentDirection ContentDirection { get; set; }
  15. internal override SpacePlan Measure(Size availableSpace)
  16. {
  17. if (Size.Equal(availableSpace, Size.Zero))
  18. return SpacePlan.Wrap("There is no available space.");
  19. var childSize = base.Measure(availableSpace);
  20. if (childSize.Type == SpacePlanType.FullRender)
  21. return childSize;
  22. return SpacePlan.FullRender(availableSpace);
  23. }
  24. internal override void Draw(Size availableSpace)
  25. {
  26. // measure content area
  27. var childSize = base.Measure(availableSpace);
  28. if (childSize.Type is SpacePlanType.Empty or SpacePlanType.FullRender)
  29. {
  30. Child?.Draw(availableSpace);
  31. return;
  32. }
  33. if (Canvas is SkiaCanvasBase skiaCanvasBase)
  34. skiaCanvasBase.MarkCurrentPageAsHavingLayoutIssues();
  35. // check overflow area
  36. var contentArea = Child.TryMeasureWithOverflow(availableSpace);
  37. var contentSize = contentArea.Type is SpacePlanType.Wrap
  38. ? Size.Max
  39. : contentArea;
  40. // draw content
  41. var translate = ContentDirection == ContentDirection.RightToLeft
  42. ? new Position(availableSpace.Width - contentSize.Width, 0)
  43. : Position.Zero;
  44. Canvas.Translate(translate);
  45. Child?.Draw(contentSize);
  46. Canvas.Translate(translate.Reverse());
  47. // draw overflow area
  48. var overflowTranslate = ContentDirection == ContentDirection.RightToLeft ? new Position(availableSpace.Width, 0) : Position.Zero;
  49. var overflowScale = ContentDirection == ContentDirection.RightToLeft ? -1 : 1;
  50. Canvas.Translate(overflowTranslate);
  51. Canvas.Scale(overflowScale, 1);
  52. DrawOverflowArea(availableSpace, contentSize);
  53. Canvas.Scale(overflowScale, 1);
  54. Canvas.Translate(overflowTranslate.Reverse());
  55. }
  56. private void DrawOverflowArea(Size availableSpace, Size contentSize)
  57. {
  58. var availableSpaceColor = AvailableAreaColor.WithAlpha(AreaOpacity);
  59. Canvas.DrawFilledRectangle(Position.Zero, availableSpace, availableSpaceColor);
  60. Canvas.Save();
  61. Canvas.ClipOverflowArea(new SkRect(0, 0, availableSpace.Width, availableSpace.Height), new SkRect(0, 0, contentSize.Width, contentSize.Height));
  62. Canvas.DrawOverflowArea(new SkRect(0, 0, contentSize.Width, contentSize.Height));
  63. Canvas.Restore();
  64. Canvas.DrawStrokeRectangle(Position.Zero, contentSize, BorderThickness, LineColor);
  65. }
  66. }