diff --git a/Sources/OpenSwiftUICore/Event/Responder/LeafViewResponder.swift b/Sources/OpenSwiftUICore/Event/Responder/LeafViewResponder.swift index 834349936..0b9d785eb 100644 --- a/Sources/OpenSwiftUICore/Event/Responder/LeafViewResponder.swift +++ b/Sources/OpenSwiftUICore/Event/Responder/LeafViewResponder.swift @@ -13,13 +13,13 @@ import OpenSwiftUI_SPI // MARK: - ContentResponder package protocol ContentResponder { - func contains(points: UnsafeBufferPointer, size: CGSize) -> BitVector64 + func contains(points: UnsafeBufferPointer, size: CGSize) -> BitVector64 func contentPath(size: CGSize) -> Path func contentPath(size: CGSize, kind: ContentShapeKinds) -> Path } extension ContentResponder { - package func contains(points: UnsafeBufferPointer, size: CGSize) -> BitVector64 { + package func contains(points: UnsafeBufferPointer, size: CGSize) -> BitVector64 { points.mapBool { size.contains(point: $0) } } diff --git a/Sources/OpenSwiftUICore/Graphic/Color/ColorView.swift b/Sources/OpenSwiftUICore/Graphic/Color/ColorView.swift index 08cfe9d3c..8097ec508 100644 --- a/Sources/OpenSwiftUICore/Graphic/Color/ColorView.swift +++ b/Sources/OpenSwiftUICore/Graphic/Color/ColorView.swift @@ -2,37 +2,44 @@ // ColorView.swift // OpenSwiftUICore // -// Audited for 6.0.87 -// Status: Empty +// Audited for 6.5.4 +// Status: Complete package import Foundation package struct ColorView: RendererLeafView, Animatable { package var color: Color.Resolved - + package init(_ color: Color.Resolved) { self.color = color } - nonisolated package static func _makeView(view: _GraphValue, inputs: _ViewInputs) -> _ViewOutputs { + nonisolated package static func _makeView( + view: _GraphValue, + inputs: _ViewInputs + ) -> _ViewOutputs { let animatable = makeAnimatable(value: view, inputs: inputs.base) return makeLeafView(view: .init(animatable), inputs: inputs) } - + package var descriptionAttributes: [(name: String, value: String)] { - _openSwiftUIUnimplementedFailure() + guard color != .clear else { return [] } + return [(name: "color", value: "\((color.red, color.green, color.blue, color.opacity))")] } - - package func contains(points: UnsafeBufferPointer, size: CGSize) -> BitVector64 { - _openSwiftUIUnimplementedFailure() + + package func contains(points: UnsafeBufferPointer, size: CGSize) -> BitVector64 { + guard color.opacity > 0 else { return BitVector64() } + return points.mapBool { + min($0.x, $0.y) >= 0 && $0.x < size.width && $0.y < size.height + } } - + package func content() -> DisplayList.Content.Value { .color(color) } - + package var animatableData: Color.Resolved.AnimatableData { - get { color.animatableData } + get { color.animatableData } set { color.animatableData = newValue } } } diff --git a/Sources/OpenSwiftUICore/Render/RendererLeafView.swift b/Sources/OpenSwiftUICore/Render/RendererLeafView.swift index bdd404e32..0a21e0453 100644 --- a/Sources/OpenSwiftUICore/Render/RendererLeafView.swift +++ b/Sources/OpenSwiftUICore/Render/RendererLeafView.swift @@ -20,14 +20,14 @@ extension RendererLeafView { package static var requiresMainThread: Bool { false } - + package func contains( - points: UnsafeBufferPointer, + points: UnsafeBufferPointer, size: CGSize ) -> BitVector64 { points.mapBool { size.contains(point: $0) } } - + package static func makeLeafView( view: _GraphValue, inputs: _ViewInputs diff --git a/Sources/OpenSwiftUICore/Shape/Path.swift b/Sources/OpenSwiftUICore/Shape/Path.swift index bd5df377b..6d15b3324 100644 --- a/Sources/OpenSwiftUICore/Shape/Path.swift +++ b/Sources/OpenSwiftUICore/Shape/Path.swift @@ -533,7 +533,21 @@ public struct Path: Equatable, LosslessStringConvertible, @unchecked Sendable { _openSwiftUIUnimplementedFailure() } - package func contains(points: [CGPoint], eoFill: Bool = false, origin: CGPoint = .zero) -> BitVector64 { + package func contains( + points: [PlatformPoint], + eoFill: Bool = false, + origin: CGPoint = .zero + ) -> BitVector64 { + points.withUnsafeBufferPointer { + contains(points: $0, eoFill: eoFill, origin: origin) + } + } + + package func contains( + points: UnsafeBufferPointer, + eoFill: Bool = false, + origin: CGPoint = .zero + ) -> BitVector64 { _openSwiftUIUnimplementedFailure() } diff --git a/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyledLeafView.swift b/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyledLeafView.swift index 90d20ab90..8a4235d8e 100644 --- a/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyledLeafView.swift +++ b/Sources/OpenSwiftUICore/Shape/ShapeStyle/ShapeStyledLeafView.swift @@ -3,11 +3,14 @@ // OpenSwiftUICore // // Audited for 6.5.4 -// Status: WIP +// Status: Complete // ID: E1641985C375D8826E6966D4F238A1B8 (SwiftUICore) package import Foundation package import OpenAttributeGraphShims +package import OpenCoreGraphicsShims + +// MARK: - ShapeStyledLeafView package protocol ShapeStyledLeafView: ContentResponder { static var animatesSize: Bool { get } @@ -33,19 +36,50 @@ extension ShapeStyledLeafView { package static var hasBackground: Bool { false } package func backgroundShape(in size: CGSize) -> FramedShape { - (shape: .path(Path(), FillStyle()), frame: .zero) + (shape: .empty, frame: .zero) } package func isClear(styles: ShapeStyle.Pack) -> Bool { styles.isClear(name: .foreground) && styles.isClear(name: .background) } - package func contains(points: UnsafeBufferPointer, size: CGSize) -> BitVector64 { - _openSwiftUIUnimplementedFailure() + package func contains(points: UnsafeBufferPointer, size: CGSize) -> BitVector64 { + let framedShape: FramedShape + if Self.hasBackground { + let background = backgroundShape(in: size) + if case .empty = background.shape { + framedShape = shape(in: size) + } else { + framedShape = background + } + } else { + framedShape = shape(in: size) + } + switch framedShape.shape { + case let .path(path, style): + guard points.contains(where: { framedShape.frame.contains($0) }) else { + return BitVector64() + } + return path.contains( + points: points, + eoFill: style.isEOFilled, + origin: framedShape.frame.origin + ) + default: + return points.mapBool { framedShape.frame.contains($0) } + } } package func contentPath(size: CGSize) -> Path { - _openSwiftUIUnimplementedFailure() + let framedShape = shape(in: size) + switch framedShape.shape { + case let .path(path, _): + let origin = framedShape.frame.origin + guard origin != .zero else { return path } + return path.applying(CGAffineTransform(translationX: origin.x, y: origin.y)) + default: + return Path(framedShape.frame) + } } package static func makeLeafView( @@ -57,30 +91,36 @@ extension ShapeStyledLeafView { ) -> _ViewOutputs { var outputs = _ViewOutputs() if inputs.preferences.requiresDisplayList { - let identity = DisplayList.Identity() inputs.pushIdentity(identity) - let displayList = Attribute( - ShapeStyledDisplayList( - group: interpolatorGroup, - identity: identity, - view: view.value, - styles: styles, - size: inputs.size.cgSize, - animatedSize: inputs.animatedSize(), - position: inputs.animatedPosition(), - containerPosition: inputs.containerPosition, - transform: inputs.transform, - environment: inputs.environment, - safeAreaInsets: inputs.safeAreaInsets, - options: inputs.displayListOptions, - data: data, - contentSeed: .init() - ) + let displayList = ShapeStyledDisplayList( + group: interpolatorGroup, + identity: identity, + view: view.value, + styles: styles, + size: inputs.size.cgSize, + animatedSize: inputs.animatedSize(), + position: inputs.animatedPosition(), + containerPosition: inputs.containerPosition, + transform: inputs.transform, + environment: inputs.environment, + safeAreaInsets: inputs.safeAreaInsets, + options: inputs.displayListOptions, + data: data, + contentSeed: .init() ) - outputs.displayList = displayList + outputs.displayList = Attribute(displayList) + } + let filter = ShapeStyledResponderFilter( + view: view.value, + styles: styles, + size: inputs.animatedSize(), + position: inputs.animatedPosition(), + transform: inputs.transform + ) + if inputs.preferences.requiresViewResponders { + outputs.preferences.viewResponders = Attribute(filter) } - // TODO: Responder return outputs } } @@ -110,17 +150,66 @@ extension ShapeStyledLeafView where ShapeUpdateData == () { } } +// MARK: - ShapeStyledResponderData + package struct ShapeStyledResponderData: ContentResponder where V: ShapeStyledLeafView { - package func contains(points: UnsafeBufferPointer, size: CGSize) -> BitVector64 { - _openSwiftUIUnimplementedFailure() + var view: V + var styles: ShapeStyle.Pack + + package func contains(points: UnsafeBufferPointer, size: CGSize) -> BitVector64 { + guard !view.isClear(styles: styles) else { return BitVector64() } + return view.contains(points: points, size: size) } package func contentPath(size: CGSize) -> Path { - _openSwiftUIUnimplementedFailure() + guard !view.isClear(styles: styles) else { return Path() } + return view.contentPath(size: size) } } -// TODO: ShapeStyledResponderFilter +// MARK: - ShapeStyledResponderFilter + +private struct ShapeStyledResponderFilter: StatefulRule where V: ShapeStyledLeafView { + @Attribute var view: V + @Attribute var styles: ShapeStyle.Pack + @Attribute var size: ViewSize + @Attribute var position: ViewOrigin + @Attribute var transform: ViewTransform + let responder: LeafViewResponder> + + init( + view: Attribute, + styles: Attribute, + size: Attribute, + position: Attribute, + transform: Attribute + ) { + self._view = view + self._styles = styles + self._size = size + self._position = position + self._transform = transform + self.responder = LeafViewResponder() + } + + typealias Value = ViewRespondersKey.Value + + mutating func updateValue() { + let (view, viewChanged) = $view.changedValue() + let (styles, stylesChanged) = $styles.changedValue() + let data = ShapeStyledResponderData(view: view, styles: styles) + responder.helper.update( + data: (data, viewChanged || stylesChanged), + size: $size.changedValue(), + position: $position.changedValue(), + transform: $transform.changedValue(), + parent: responder + ) + if !hasValue { + value = [responder] + } + } +} // MARK: - ShapeStyledDisplayList