diff --git a/Sources/OpenSwiftUI/View/Modifier/ClipEffect.swift b/Sources/OpenSwiftUI/View/Modifier/ClipEffect.swift new file mode 100644 index 00000000..717eea9f --- /dev/null +++ b/Sources/OpenSwiftUI/View/Modifier/ClipEffect.swift @@ -0,0 +1,130 @@ +import Foundation + +// MARK: - ClipEffect + +@frozen +public struct _ClipEffect where ClipShape: Shape { + public var shape: ClipShape + public var style: FillStyle + + @inlinable + public init(shape: ClipShape, style: FillStyle = FillStyle()) { + self.shape = shape + self.style = style + } + + public var animatableData: ClipShape.AnimatableData { + get { shape.animatableData } + set { shape.animatableData = newValue } + } + + public typealias AnimatableData = ClipShape.AnimatableData + public typealias Body = Swift.Never +} + +// FIXME +extension _ClipEffect: PrimitiveViewModifier {} + +// MARK: - View Extension + +extension View { + + /// Sets a clipping shape for this view. + /// + /// Use `clipShape(_:style:)` to clip the view to the provided shape. By + /// applying a clipping shape to a view, you preserve the parts of the view + /// covered by the shape, while eliminating other parts of the view. The + /// clipping shape itself isn't visible. + /// + /// For example, this code applies a circular clipping shape to a `Text` + /// view: + /// + /// Text("Clipped text in a circle") + /// .frame(width: 175, height: 100) + /// .foregroundColor(Color.white) + /// .background(Color.black) + /// .clipShape(Circle()) + /// + /// The resulting view shows only the portion of the text that lies within + /// the bounds of the circle. + /// + /// ![A screenshot of text clipped to the shape of a + /// circle.](OpenSwiftUI-View-clipShape.png) + /// + /// - Parameters: + /// - shape: The clipping shape to use for this view. The `shape` fills + /// the view's frame, while maintaining its aspect ratio. + /// - style: The fill style to use when rasterizing `shape`. + /// + /// - Returns: A view that clips this view to `shape`, using `style` to + /// define the shape's rasterization. + @inlinable + public func clipShape(_ shape: S, style: FillStyle = FillStyle()) -> some View where S: Shape { + modifier(_ClipEffect(shape: shape, style: style)) + } + + + /// Clips this view to its bounding rectangular frame. + /// + /// Use the `clipped(antialiased:)` modifier to hide any content that + /// extends beyond the layout bounds of the shape. + /// + /// By default, a view's bounding frame is used only for layout, so any + /// content that extends beyond the edges of the frame is still visible. + /// + /// Text("This long text string is clipped") + /// .fixedSize() + /// .frame(width: 175, height: 100) + /// .clipped() + /// .border(Color.gray) + /// + /// ![Screenshot showing text clipped to its + /// frame.](OpenSwiftUI-View-clipped.png) + /// + /// - Parameter antialiased: A Boolean value that indicates whether the + /// rendering system applies smoothing to the edges of the clipping + /// rectangle. + /// + /// - Returns: A view that clips this view to its bounding frame. + @inlinable + public func clipped(antialiased: Bool = false) -> some View { + clipShape( + Rectangle(), + style: FillStyle(antialiased: antialiased) + ) + } + + + /// Clips this view to its bounding frame, with the specified corner radius. + /// + /// By default, a view's bounding frame only affects its layout, so any + /// content that extends beyond the edges of the frame remains visible. Use + /// `cornerRadius(_:antialiased:)` to hide any content that extends beyond + /// these edges while applying a corner radius. + /// + /// The following code applies a corner radius of 25 to a text view: + /// + /// Text("Rounded Corners") + /// .frame(width: 175, height: 75) + /// .foregroundColor(Color.white) + /// .background(Color.black) + /// .cornerRadius(25) + /// + /// ![A screenshot of a rectangle with rounded corners bounding a text + /// view.](OpenSwiftUI-View-cornerRadius.png) + /// + /// - Parameter antialiased: A Boolean value that indicates whether the + /// rendering system applies smoothing to the edges of the clipping + /// rectangle. + /// + /// - Returns: A view that clips this view to its bounding frame with the + /// specified corner radius. + @available(*, deprecated, message: "Use `clipShape` or `fill` instead.") + @inlinable + public func cornerRadius(_ radius: CGFloat, antialiased: Bool = true) -> some View { + clipShape( + RoundedRectangle(cornerRadius: radius), + style: FillStyle(antialiased: antialiased) + ) + } +} diff --git a/Sources/OpenSwiftUI/View/Shape/RoundedCornerStyle.swift b/Sources/OpenSwiftUI/View/Shape/RoundedCornerStyle.swift new file mode 100644 index 00000000..dcd4dbac --- /dev/null +++ b/Sources/OpenSwiftUI/View/Shape/RoundedCornerStyle.swift @@ -0,0 +1,18 @@ +// +// ShapeRole.swift +// OpenSwiftUI +// +// Audited for RELEASE_2021 +// Status: Complete + +/// Defines the shape of a rounded rectangle's corners. +public enum RoundedCornerStyle: Sendable { + /// Quarter-circle rounded rect corners. + case circular + + /// Continuous curvature rounded rect corners. + case continuous +} + +extension RoundedCornerStyle: Equatable {} +extension RoundedCornerStyle: Hashable {} diff --git a/Sources/OpenSwiftUI/View/Shape/RoundedRectangle.swift b/Sources/OpenSwiftUI/View/Shape/RoundedRectangle.swift new file mode 100644 index 00000000..85571185 --- /dev/null +++ b/Sources/OpenSwiftUI/View/Shape/RoundedRectangle.swift @@ -0,0 +1,30 @@ +import Foundation + +@frozen +public struct RoundedRectangle: Shape { + public var cornerSize: CGSize + public var style: RoundedCornerStyle + + @inlinable + public init(cornerSize: CGSize, style: RoundedCornerStyle = .circular) { + self.cornerSize = cornerSize + self.style = style + } + + @inlinable + public init(cornerRadius: CGFloat, style: RoundedCornerStyle = .circular) { + let cornerSize = CGSize(width: cornerRadius, height: cornerRadius) + self.init(cornerSize: cornerSize, style: style) + } + + public func path(in rect: CGRect) -> Path { + fatalError("TODO") + } + public var animatableData: CGSize.AnimatableData { + get { cornerSize.animatableData } + set { cornerSize.animatableData = newValue } + } + + public typealias Body = _ShapeView +} + diff --git a/Sources/OpenSwiftUI/View/Shape/StrokeStyle.swift b/Sources/OpenSwiftUI/View/Shape/StrokeStyle.swift index 0ddfebc3..c94484ea 100644 --- a/Sources/OpenSwiftUI/View/Shape/StrokeStyle.swift +++ b/Sources/OpenSwiftUI/View/Shape/StrokeStyle.swift @@ -5,6 +5,7 @@ // Audited for RELEASE_2021 // Status: Complete +import Foundation #if canImport(CoreGraphics) import CoreGraphics #else