InsettableShape.swift 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. /// A shape type that is able to inset itself to produce another shape.
  2. public protocol InsettableShape: Shape {
  3. /// The type of the inset shape.
  4. associatedtype InsetShape: InsettableShape
  5. /// Returns `self` inset by `amount`.
  6. nonisolated func inset(by amount: Double) -> InsetShape
  7. }
  8. /// The `InsetShape` implementation used by ``Rectangle``, ``Ellipse``, ``Circle``, and ``Capsule``.
  9. ///
  10. /// This implementation only works for convex shapes where insetting the shape is equivalent to
  11. /// making the shape smaller.
  12. struct InsettableShapeImpl<Base: Shape>: InsettableShape {
  13. var inset: Double
  14. var base: Base
  15. nonisolated func path(in bounds: Path.Rect) -> Path {
  16. base.path(
  17. in: .init(
  18. x: bounds.x + inset,
  19. y: bounds.y + inset,
  20. width: bounds.width - 2 * inset,
  21. height: bounds.height - 2 * inset
  22. )
  23. )
  24. }
  25. nonisolated func size(fitting proposal: ProposedViewSize) -> ViewSize {
  26. let innerProposal = ProposedViewSize(
  27. proposal.width.map { max(0, $0 - 2 * inset) },
  28. proposal.height.map { max(0, $0 - 2 * inset) }
  29. )
  30. let innerSize = base.size(fitting: innerProposal)
  31. return ViewSize(
  32. innerSize.width + 2 * inset,
  33. innerSize.height + 2 * inset
  34. )
  35. }
  36. func inset(by amount: Double) -> InsettableShapeImpl<Base> {
  37. .init(inset: inset + amount, base: base)
  38. }
  39. }