From 782219eb31fc0a59e65ed78a57f94e6dcf0cfcb5 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 29 Jun 2025 18:41:05 +0800 Subject: [PATCH 1/4] Update GestureViewModifier --- Package.resolved | 4 +- .../Gesture/GestureContainerFactory.swift | 26 + .../Gesture/GestureContainerFeature.swift | 11 + .../Event/Gesture/GestureGraph.swift | 34 +- .../Event/Gesture/GestureViewModifier.swift | 511 +++++++++++++++--- .../DefaultLayoutViewResponder.swift | 71 +++ .../Responder/HitTestBindingModifier.swift | 52 ++ .../Event/Responder/MultiViewResponder.swift | 70 +++ .../Event/Responder/ViewResponder.swift | 14 - 9 files changed, 714 insertions(+), 79 deletions(-) create mode 100644 Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFactory.swift create mode 100644 Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFeature.swift create mode 100644 Sources/OpenSwiftUICore/Event/Responder/DefaultLayoutViewResponder.swift create mode 100644 Sources/OpenSwiftUICore/Event/Responder/HitTestBindingModifier.swift create mode 100644 Sources/OpenSwiftUICore/Event/Responder/MultiViewResponder.swift diff --git a/Package.resolved b/Package.resolved index c35f679df..ccb3212db 100644 --- a/Package.resolved +++ b/Package.resolved @@ -7,7 +7,7 @@ "location" : "https://github.com/OpenSwiftUIProject/DarwinPrivateFrameworks.git", "state" : { "branch" : "main", - "revision" : "d115c29b7468940969b0c2f5cb0d612a28563a02" + "revision" : "af7ef1c0a0e2c2b87e287743997a22ab3678924c" } }, { @@ -25,7 +25,7 @@ "location" : "https://github.com/OpenSwiftUIProject/OpenGraph", "state" : { "branch" : "main", - "revision" : "cbe7eaf78ee9a3b29714131f7699d79b61bf4f81" + "revision" : "83bedb98f5e54f75f225c003da7eaa9f7871ccab" } }, { diff --git a/Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFactory.swift b/Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFactory.swift new file mode 100644 index 000000000..e54e71ee3 --- /dev/null +++ b/Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFactory.swift @@ -0,0 +1,26 @@ +// +// GestureContainerFactory.swift +// OpenSwiftUICore +// +// Status: Complete + +// MARK: - GestureContainerFactory [6.5.4] + +package protocol GestureContainerFactory { + static func makeGestureContainer(responder: any AnyGestureContainingResponder) -> AnyObject +} + +package struct GestureContainerFactoryInput: ViewInput { + package static let defaultValue: (any GestureContainerFactory.Type)? = nil + + package typealias Value = (any GestureContainerFactory.Type)? +} + +extension _ViewInputs { + package func makeGestureContainer(responder: any AnyGestureContainingResponder) -> AnyObject { + guard let factory = self[GestureContainerFactoryInput.self] else { + preconditionFailure("Gesture container factory must be configured") + } + return factory.makeGestureContainer(responder: responder) + } +} diff --git a/Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFeature.swift b/Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFeature.swift new file mode 100644 index 000000000..ba1c9b40b --- /dev/null +++ b/Sources/OpenSwiftUICore/Event/Gesture/GestureContainerFeature.swift @@ -0,0 +1,11 @@ +// +// GestureContainerFeature.swift +// OpenSwiftUICore +// +// Status: WIP + +struct GestureContainerFeature { + static var isEnabled: Bool { + false + } +} diff --git a/Sources/OpenSwiftUICore/Event/Gesture/GestureGraph.swift b/Sources/OpenSwiftUICore/Event/Gesture/GestureGraph.swift index 36965cdd3..98e1569aa 100644 --- a/Sources/OpenSwiftUICore/Event/Gesture/GestureGraph.swift +++ b/Sources/OpenSwiftUICore/Event/Gesture/GestureGraph.swift @@ -101,15 +101,45 @@ final package class GestureGraph: GraphHost, EventGraphHost, CustomStringConvert delegate?.enqueueAction(action) } + @inline(__always) + func access(_ body: @autoclosure () -> T) -> T { + Update.perform { + instantiateIfNeeded() + return body() + } + } + package func gestureCategory() -> GestureCategory? { guard let rootResponder, rootResponder.isValid else { return nil } + return access(gestureCategoryAttr) + } + + @inline(__always) + var gestureLabel: String? { + guard isInstantiated else { + return nil + } return Update.perform { - instantiateIfNeeded() - return gestureCategoryAttr + gestureLabelAttr ?? nil } } + + @inline(__always) + var isCancellable: Bool { + access(isCancellableAttr ?? false) + } + + @inline(__always) + var requiredTapCount: Int? { + access(requiredTapCountAttr ?? nil) + } + + @inline(__always) + var gestureDependency: GestureDependency { + access(gestureDependencyAttr ?? .none) + } } extension GestureGraph { diff --git a/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift b/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift index cdbcf4e34..1be692c0f 100644 --- a/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift +++ b/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift @@ -14,7 +14,7 @@ package protocol GestureViewModifier: MultiViewModifier, PrimitiveViewModifier { associatedtype Combiner: GestureCombiner = DefaultGestureCombiner - var gesture: Self.ContentGesture { get } + var gesture: ContentGesture { get } var name: String? { get } @@ -40,13 +40,13 @@ extension GestureResponderExclusionPolicy: Sendable {} // MARK: - GestureCombiner [6.5.4] package protocol GestureCombiner { - associatedtype Result: Gesture /*where Result.Value == ()*/ + associatedtype Result: Gesture where Result.Value == () static func combine( _ gesture1: AnyGesture, _ gesture2: AnyGesture - ) -> Self.Result - + ) -> Result + static var exclusionPolicy: GestureResponderExclusionPolicy { get } } @@ -90,40 +90,6 @@ extension GestureViewModifier { } } -// MARK: - GestureFilter [6.5.4] [Blocked by ViewResponder] - -private struct GestureFilter: StatefulRule where Modifier: GestureViewModifier { - typealias Value = [ViewResponder] - - @Attribute var children: [ViewResponder] - - @Attribute var modifier: Modifier - - var inputs: _ViewInputs - - var viewSubgraph: Subgraph - - lazy var responder: GestureResponder = { - viewSubgraph.apply { - GestureResponder( - modifier: $modifier, - inputs: inputs - ) - } - }() - - mutating func updateValue() { - let responder = responder - let (children, childrenChanged) = $children.changedValue() - if childrenChanged { - // responder.children = children - } - if !hasValue { - // value = [self.responder] - } - } -} - // MARK: - AddGestureModifier [6.5.4] package struct AddGestureModifier: GestureViewModifier where T: Gesture { @@ -146,10 +112,12 @@ package struct AddGestureModifier: GestureViewModifier where T: Gesture { package typealias ContentGesture = T } +// MARK: - DefaultGestureCombiner [6.5.4] + package struct DefaultGestureCombiner: GestureCombiner { package typealias Base = ExclusiveGesture, AnyGesture> - package typealias Result = _MapGesture + package typealias Result = _MapGesture package static var exclusionPolicy: GestureResponderExclusionPolicy { .default } @@ -157,68 +125,316 @@ package struct DefaultGestureCombiner: GestureCombiner { _ first: AnyGesture, _ second: AnyGesture ) -> DefaultGestureCombiner.Result { - preconditionFailure("TODO") + first.exclusively(before: second).map { _ in } } } +// MARK: - AnyGestureContainingResponder [6.5.4] + package protocol AnyGestureContainingResponder: ViewResponder { var viewSubgraph: Subgraph { get } + var eventSources: [any EventBindingSource] { get } + var gestureType: any Any.Type { get } + var isValid: Bool { get } - + func detachContainer() } +// MARK: - AnyGestureResponder [6.5.4] + package protocol AnyGestureResponder: AnyGestureContainingResponder { var inputs: _ViewInputs { get } + var childSubgraph: Subgraph? { get set } + var childViewSubgraph: Subgraph? { get set } + var exclusionPolicy: GestureResponderExclusionPolicy { get } + + var label: String? { get } + var gestureGraph: GestureGraph { get } - + + var relatedAttribute: AnyAttribute { get } + func makeSubviewsGesture(inputs: _GestureInputs) -> _GestureOutputs } extension AnyGestureResponder { - package var exclusionPolicy: GestureResponderExclusionPolicy { - get { preconditionFailure("TODO") } - } - + package var exclusionPolicy: GestureResponderExclusionPolicy { .default } + package func makeSubviewsGesture(inputs: _GestureInputs) -> _GestureOutputs { - preconditionFailure("TODO") + _GestureOutputs(phase: inputs.failedPhase) } package func makeWrappedGesture( inputs: _GestureInputs, makeChild: (_GestureInputs) -> _GestureOutputs - ) -> _GestureOutputs { preconditionFailure("TODO") } - - package var label: String? { - get { preconditionFailure("TODO") } + ) -> _GestureOutputs { + let inputs = inputs + var outputs: _GestureOutputs = inputs.makeDefaultOutputs() + guard viewSubgraph.isValid else { + return outputs + } + let currentSubgraph = Subgraph.current! + let needGestureGraph = inputs.options.contains(.gestureGraph) + childSubgraph = Subgraph(graph: (needGestureGraph ? currentSubgraph : viewSubgraph).graph) + viewSubgraph.addChild(childSubgraph!, tag: 1) + currentSubgraph.addChild(childSubgraph!) + if needGestureGraph { + childViewSubgraph = Subgraph(graph: viewSubgraph.graph) + childSubgraph!.addChild(childViewSubgraph!, tag: 1) + } + childSubgraph!.apply { + let subgraph = (childViewSubgraph ?? childSubgraph)! + var childInputs = inputs + var viewInputs = self.inputs + viewInputs.copyCaches() + childInputs.viewInputs = viewInputs + let childOutputs = makeChild(childInputs) + outputs.overrideDefaultValues(childOutputs) + } + return outputs } + package var label: String? { nil } + package var isCancellable: Bool { - get { preconditionFailure("TODO") } + gestureGraph.isCancellable } package var requiredTapCount: Int? { - get { preconditionFailure("TODO") } + gestureGraph.requiredTapCount } package func canPrevent( _ other: ViewResponder, otherExclusionPolicy: GestureResponderExclusionPolicy - ) -> Bool { preconditionFailure("TODO") } + ) -> Bool { + guard isPrioritized(over: other, otherExclusionPolicy: otherExclusionPolicy) else { + return false + } + guard let other = other as? any AnyGestureResponder else { + return true + } + return other.dependency == .none + } package func shouldRequireFailure(of other: any AnyGestureResponder) -> Bool { - preconditionFailure("TODO") + guard exclusionPolicy != .simultaneous, + other.exclusionPolicy != .simultaneous, + let requiredTapCount, + let otherRequiredTapCount = other.requiredTapCount, + otherRequiredTapCount != requiredTapCount + else { + return other.isPrioritized(over: self, otherExclusionPolicy: exclusionPolicy) && dependency != .none + } + return requiredTapCount < otherRequiredTapCount + } + + private func isPrioritized(over other: ViewResponder, otherExclusionPolicy: GestureResponderExclusionPolicy) -> Bool { + switch (exclusionPolicy, otherExclusionPolicy) { + case (.default, .default): + var resonder: ResponderNode = other + while true { + guard resonder !== self else { + return false + } + guard let nextResponder = resonder.nextResponder else { + return true + } + resonder = nextResponder + } + case (.highPriority, .highPriority): + var resonder: ResponderNode = other + while true { + guard resonder !== self else { + return true + } + guard let nextResponder = resonder.nextResponder else { + return false + } + resonder = nextResponder + } + case (.highPriority, .default): + return true + default: + return false + } + } + + private var dependency: GestureDependency { + gestureGraph.gestureDependency } } -private class GestureResponder/*: AnyGestureResponder where Modifier: GestureViewModifier*/ { +private class GestureResponder: DefaultLayoutViewResponder, AnyGestureResponder where Modifier: GestureViewModifier { + let modifier: Attribute + + var childSubgraph: Subgraph? + + var childViewSubgraph: Subgraph? + + lazy var gestureGraph: GestureGraph = { + GestureGraph(rootResponder: self) + }() + + lazy var bindingBridge: EventBindingBridge & GestureGraphDelegate = { + let bridge = inputs.makeEventBindingBridge(bindingManager: gestureGraph.eventBindingManager, responder: self) + gestureGraph.delegate = bridge + return bridge + }() + + var _gestureContainer: AnyObject? + init(modifier: Attribute, inputs: _ViewInputs) { - preconditionFailure("TODO") + self.modifier = modifier + super.init(inputs: inputs) + } + + var gestureType: any Any.Type { + Modifier.ContentGesture.self + } + + var relatedAttribute: AnyAttribute { + modifier.identifier + } + + var eventSources: [any EventBindingSource] { + bindingBridge.eventSources + } + + var exclusionPolicy: GestureResponderExclusionPolicy { + Modifier.Combiner.exclusionPolicy + } + + var label: String? { + guard viewSubgraph.isValid else { return nil } + return Graph.withoutUpdate { + viewSubgraph.apply { + modifier.name.value + } + } ?? gestureGraph.gestureLabel + } + + var isValid: Bool { + _gestureContainer != nil && viewSubgraph.isValid + } + + func detachContainer() { + _gestureContainer = nil + } + + func makeSubviewsGesture(inputs: _GestureInputs) -> _GestureOutputs { + makeGesture(inputs: inputs) + } + + override var gestureContainer: AnyObject? { + guard let gestureContainer = _gestureContainer else { + guard viewSubgraph.isValid else { + return nil + } + _gestureContainer = inputs.makeGestureContainer(responder: self) + return _gestureContainer! + } + return gestureContainer + } + + override func containsGlobalPoints( + _ points: [PlatformPoint], + cacheKey: UInt32?, + options: ViewResponder.ContainsPointsOptions + ) -> ViewResponder.ContainsPointsResult { + openSwiftUIUnimplementedFailure() + } + + override func bindEvent(_ event: any EventType) -> ResponderNode? { + guard GestureContainerFeature.isEnabled else { + return super.bindEvent(event) + } + guard let hitTestableEvent = HitTestableEvent(event) else { + return nil + } + return hitTest( + globalPoint: hitTestableEvent.hitTestLocation, + radius: hitTestableEvent.hitTestRadius + ) + } + + override func makeGesture(inputs: _GestureInputs) -> _GestureOutputs { + makeWrappedGesture(inputs: inputs) { childInputs in + var childViewInputs = childInputs.viewInputs + let closure: () -> _GestureOutputs = { [self] in + if inputs.options.contains(.skipCombiners) { + let childGesture = Attribute(GestureViewChild( + modifier: modifier, + isEnabled: childViewInputs.isEnabled, + viewPhase: childViewInputs.viewPhase + )) + return AnyGesture.makeDebuggableGesture(gesture: _GraphValue(childGesture), inputs: childInputs) + } else { + let childGesture = Attribute(CombiningGestureViewChild( + modifier: modifier, + isEnabled: childViewInputs.isEnabled, + viewPhase: childViewInputs.viewPhase, + node: self + )) + return Modifier.Combiner.Result.makeDebuggableGesture(gesture: _GraphValue(childGesture), inputs: childInputs) + } + } + guard inputs.options.contains(.includeDebugOutput) else { + return closure() + } + // TODO: GestureViewDebug + return closure() + } + } + + override func resetGesture() { + childSubgraph = nil + childViewSubgraph = nil + super.resetGesture() + } + + override func extendPrintTree(string: inout String) { + string.append("\(Modifier.ContentGesture.self)") + } +} + +// MARK: - GestureFilter [6.5.4] + +private struct GestureFilter: StatefulRule where Modifier: GestureViewModifier { + typealias Value = [ViewResponder] + + @Attribute var children: [ViewResponder] + + @Attribute var modifier: Modifier + + var inputs: _ViewInputs + + var viewSubgraph: Subgraph + + lazy var responder: GestureResponder = { + viewSubgraph.apply { + GestureResponder( + modifier: $modifier, + inputs: inputs + ) + } + }() + + mutating func updateValue() { + let responder = responder + let (children, childrenChanged) = $children.changedValue() + if childrenChanged { + responder.children = children + } + if !hasValue { + value = [self.responder] + } } } @@ -232,10 +448,6 @@ package protocol GestureAccessibilityProvider { ) } -private struct GestureAccessibilityProviderKey: GraphInput { - static let defaultValue: (any GestureAccessibilityProvider.Type) = EmptyGestureAccessibilityProvider.self -} - struct EmptyGestureAccessibilityProvider: GestureAccessibilityProvider { nonisolated static func makeGesture( mask: @autoclosure () -> Attribute, @@ -246,6 +458,10 @@ struct EmptyGestureAccessibilityProvider: GestureAccessibilityProvider { } extension _GraphInputs { + private struct GestureAccessibilityProviderKey: GraphInput { + static let defaultValue: (any GestureAccessibilityProvider.Type) = EmptyGestureAccessibilityProvider.self + } + package var gestureAccessibilityProvider: (any GestureAccessibilityProvider.Type) { get { self[GestureAccessibilityProviderKey.self] } set { self[GestureAccessibilityProviderKey.self] = newValue } @@ -259,6 +475,179 @@ extension _ViewInputs { } } +// MARK: - GestureViewChild [6.5.4] + +private struct GestureViewChild: Rule where Modifier: GestureViewModifier { + @Attribute var modifier: Modifier + @Attribute var isEnabled: Bool + @Attribute var viewPhase: _GraphInputs.Phase + + typealias Value = AnyGesture + + var value: Value { + let shouldReceiveEvents = modifier.gestureMask.contains(.gesture) && isEnabled + guard shouldReceiveEvents else { + return AnyGesture(EmptyGesture()) + } + return AnyGesture(modifier.gesture.map { _ in }) + } +} + +// MARK: - CombiningGestureViewChild [6.5.4] + +private struct CombiningGestureViewChild: Rule where Modifier: GestureViewModifier { + @Attribute var modifier: Modifier + @Attribute var isEnabled: Bool + @Attribute var viewPhase: _GraphInputs.Phase + + let node: any AnyGestureResponder + + typealias Value = Modifier.Combiner.Result + + @inline(__always) + private var shouldReceiveEvents: Bool { + modifier.gestureMask.contains(.gesture) && isEnabled + } + + @inline(__always) + private var shouldReceiveSubviewEvents: Bool { + modifier.gestureMask.contains(.subviews) + } + + @inline(__always) + private var subviewsGesture: AnyGesture { + if modifier.gestureMask.contains(.subviews) { + return AnyGesture(SubviewsGesture(node: node)) + } else { + return AnyGesture(EmptyGesture()) + } + } + + @inline(__always) + private var contentGesture: AnyGesture { + if shouldReceiveEvents { + AnyGesture(modifier.gesture + .modifier(ContentGesture()) + ) + } else { + AnyGesture(EmptyGesture()) + } + } + + var value: Value { + Modifier.Combiner.combine(subviewsGesture, contentGesture) + } +} + +// MARK: - GestureViewDebug [6.5.4] [WIP] + +private struct GestureViewDebug where Modifier: GestureViewModifier { +} + +// MARK: - SubviewsGesture [6.5.4] + +private struct SubviewsGesture: PrimitiveGesture, PrimitiveDebuggableGesture { + internal typealias Value = () + + internal typealias Body = Never + + internal let node: AnyGestureResponder + + fileprivate static func _makeGesture(gesture: _GraphValue, inputs: _GestureInputs) -> _GestureOutputs { + let outputs: _GestureOutputs = inputs.makeIndirectOutputs() + let currentSubgraph = Subgraph.current! + let subviewValue = Attribute(SubviewsPhase( + gesture: gesture.value, + resetSeed: inputs.resetSeed, + inputs: inputs, + outputs: outputs, + parentSubgraph: currentSubgraph, + oldNode: nil, + oldSeed: 0, + childSubgraph: nil, + childPhase: .init(), + childDebugData: .init() + )) + outputs.setIndirectDependency(subviewValue.identifier) + return outputs + } +} + +// MARK: - SimultaneousGestureCombiner [6.5.4] [WIP] + +struct SimultaneousGestureCombiner {} + +// MARK: - HighPriorityGestureCombiner [6.5.4] [WIP] + +struct HighPriorityGestureCombiner {} + +// MARK: - SubviewsPhase [6.5.4] [WIP] + +private struct SubviewsPhase: StatefulRule, ObservedAttribute { + struct Value { + var phase: GesturePhase + var debugData: GestureDebug.Data + } + + @Attribute var gesture: SubviewsGesture + @Attribute var resetSeed: UInt32 + let inputs: _GestureInputs + let outputs: _GestureOutputs + let parentSubgraph: Subgraph + var oldNode: AnyGestureResponder? + var oldSeed: UInt32 + var childSubgraph: Subgraph? + @OptionalAttribute var childPhase: GesturePhase? + @OptionalAttribute var childDebugData: GestureDebug.Data? + + mutating func updateValue() { + openSwiftUIUnimplementedFailure() + } + + func destroy() { + oldNode?.resetGesture() + } +} + +// MARK: - ContentGesture [6.5.4] + +private struct ContentGesture: GestureModifier { + typealias Value = Void + + typealias BodyValue = V + + nonisolated static func _makeGesture( + modifier: _GraphValue>, + inputs: _GestureInputs, + body: (_GestureInputs) -> _GestureOutputs + ) -> _GestureOutputs { + let outputs = body(inputs) + let phase = Attribute(ContentPhase( + phase: outputs.phase, + resetSeed: inputs.resetSeed, + lastResetSeed: 0 + )) + return outputs.withPhase(phase) + } +} + +// MARK: - ContentPhase [6.5.4] + +private struct ContentPhase: ResettableGestureRule { + @Attribute var phase: GesturePhase + @Attribute var resetSeed: UInt32 + var lastResetSeed: UInt32 + + typealias Value = GesturePhase + + mutating func updateValue() { + guard resetIfNeeded() else { + return + } + value = phase.withValue(()) + } +} + // MARK: - Optional: Gesture [WIP] extension Optional: Gesture where Wrapped: Gesture { diff --git a/Sources/OpenSwiftUICore/Event/Responder/DefaultLayoutViewResponder.swift b/Sources/OpenSwiftUICore/Event/Responder/DefaultLayoutViewResponder.swift new file mode 100644 index 000000000..ef28ad3da --- /dev/null +++ b/Sources/OpenSwiftUICore/Event/Responder/DefaultLayoutViewResponder.swift @@ -0,0 +1,71 @@ +// +// DefaultLayoutViewResponder.swift +// OpenSwiftUICore +// +// Status: WIP + +package import OpenGraphShims + +package struct DefaultLayoutResponderFilter: StatefulRule { +// @Attribute +// @_projectedValueProperty($children) +// package var children: [ViewResponder] { +// get { preconditionFailure("TODO") } +// nonmutating set { preconditionFailure("TODO") } +// nonmutating _modify { preconditionFailure("TODO") } +// } +// +// package var $children: Attribute<[ViewResponder]> { +// get { preconditionFailure("TODO") } +// set { preconditionFailure("TODO") } +// } +// +// package let responder: MultiViewResponder +// +// package init( +// children: Attribute<[ViewResponder]>, +// responder: MultiViewResponder +// ) { +// preconditionFailure("TODO") +// } +// + package typealias Value = [ViewResponder] + + package mutating func updateValue() { + preconditionFailure("TODO") + } +} + +@_spi(ForOpenSwiftUIOnly) +open class DefaultLayoutViewResponder: MultiViewResponder { + final package let inputs: _ViewInputs + + final package let viewSubgraph: Subgraph + + package init(inputs: _ViewInputs) { + preconditionFailure("TODO") + } +// +// package init(inputs: _ViewInputs, viewSubgraph: Subgraph) { +// preconditionFailure("TODO") +// } +// +// override open func makeGesture(inputs: _GestureInputs) -> _GestureOutputs { +// preconditionFailure("TODO") +// } +// +// override open func childrenDidChange() { +// preconditionFailure("TODO") +// } +// +// override open func resetGesture() { +// preconditionFailure("TODO") +// } +// +// @objc deinit { +// preconditionFailure("TODO") +// } +} + +@available(*, unavailable) +extension DefaultLayoutViewResponder: Sendable {} diff --git a/Sources/OpenSwiftUICore/Event/Responder/HitTestBindingModifier.swift b/Sources/OpenSwiftUICore/Event/Responder/HitTestBindingModifier.swift new file mode 100644 index 000000000..514cfea11 --- /dev/null +++ b/Sources/OpenSwiftUICore/Event/Responder/HitTestBindingModifier.swift @@ -0,0 +1,52 @@ +// +// HitTestBindingModifier.swift +// OpenSwiftUICore +// +// Status: WIP +// ID: D16C83991EAE21A87411739F6DC01498 (SwiftUICore) + +package import Foundation + +package typealias PlatformHitTestableEvent = HitTestableEvent + +package struct HitTestBindingModifier: ViewModifier, MultiViewModifier, PrimitiveViewModifier { + nonisolated package static func _makeView( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs + ) -> _ViewOutputs { + openSwiftUIUnimplementedWarning() + return body(_Graph(), inputs) + } + + package typealias Body = Never +} + +extension ViewResponder { + package static var hitTestKey: UInt32 { preconditionFailure("TODO") } + + package static let minOpacityForHitTest: Double = 0.0 + + package func hitTest( + globalPoint: PlatformPoint, + radius: CGFloat, + cacheKey: UInt32? = nil, + options: ContainsPointsOptions = .platformDefault + ) -> ViewResponder? { + openSwiftUIUnimplementedFailure() + } + + private func hitTest( + globalPoints: [PlatformPoint], + weights: [Double], + mask: BitVector64, + cacheKey: UInt32?, + options: ContainsPointsOptions + ) -> ViewResponder? { + openSwiftUIUnimplementedFailure() + } +} + +private func hitPoints(point: PlatformPoint, radius: CGFloat) -> ([PlatformPoint], [Double]) { + openSwiftUIUnimplementedFailure() +} diff --git a/Sources/OpenSwiftUICore/Event/Responder/MultiViewResponder.swift b/Sources/OpenSwiftUICore/Event/Responder/MultiViewResponder.swift new file mode 100644 index 000000000..af8e7f004 --- /dev/null +++ b/Sources/OpenSwiftUICore/Event/Responder/MultiViewResponder.swift @@ -0,0 +1,70 @@ +// +// MultiViewResponder.swift +// OpenSwiftUICore +// +// Status: WIP + +@_spi(ForOpenSwiftUIOnly) +open class MultiViewResponder: ViewResponder { + override public init() { + preconditionFailure("TODO") + } + + final public override var children: [ViewResponder] { + get { preconditionFailure("TODO") } + + set { preconditionFailure("TODO") } + } + + final package func updateChildren(_ data: (value: [ViewResponder], changed: Bool)) { + preconditionFailure("TODO") + } + + open func childrenDidChange() { + preconditionFailure("TODO") + } + + override open func bindEvent(_ event: any EventType) -> ResponderNode? { + preconditionFailure("TODO") + } + + override open func resetGesture() { + preconditionFailure("TODO") + } + +// override open func containsGlobalPoints( +// _ points: [PlatformPoint], +// cacheKey: UInt32?, +// options: ViewResponder.ContainsPointsOptions +// ) -> (mask: BitVector64, priority: Double) { +// preconditionFailure("TODO") +// } + + override open func addContentPath( + to path: inout Path, + kind: ContentShapeKinds, + in space: CoordinateSpace, + observer: (any ContentPathObserver)? + ) { + preconditionFailure("TODO") + } + + override open func addObserver(_ observer: any ContentPathObserver) { + preconditionFailure("TODO") + } + + @discardableResult + override final public func visit(applying visitor: (ResponderNode) -> ResponderVisitorResult) -> ResponderVisitorResult { + preconditionFailure("TODO") + } + +// override final public var childCount: Int { preconditionFailure("TODO") } +// +// override final public func child(at index: Int) -> ViewResponder { +// preconditionFailure("TODO") +// } + +} + +@available(*, unavailable) +extension MultiViewResponder: Sendable {} diff --git a/Sources/OpenSwiftUICore/Event/Responder/ViewResponder.swift b/Sources/OpenSwiftUICore/Event/Responder/ViewResponder.swift index 56457f115..a6497ff31 100644 --- a/Sources/OpenSwiftUICore/Event/Responder/ViewResponder.swift +++ b/Sources/OpenSwiftUICore/Event/Responder/ViewResponder.swift @@ -182,17 +182,3 @@ extension ViewResponder: Sendable {} @_spi(ForOpenSwiftUIOnly) @available(*, unavailable) extension ViewResponder.ContainsPointsOptions: Sendable {} - -// FIXME -package struct HitTestBindingModifier: ViewModifier, /*MultiViewModifier,*/ PrimitiveViewModifier { - nonisolated package static func _makeView( - modifier: _GraphValue, - inputs: _ViewInputs, - body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs - ) -> _ViewOutputs { - // preconditionFailure("TODO") - return body(_Graph(), inputs) - } - - package typealias Body = Never -} From 2ce2c8bfb3cc37e5aa7e7893ce77d3d9adcda475 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 29 Jun 2025 20:41:50 +0800 Subject: [PATCH 2/4] Update MultiViewResponder and DefaultLayoutViewResponder --- .../Event/Gesture/DefaultLayoutGesture.swift | 18 +++ .../Responder/ContentPathObservers.swift | 43 ++++++ .../DefaultLayoutViewResponder.swift | 139 ++++++++++++------ .../Event/Responder/MultiViewResponder.swift | 111 +++++++++----- 4 files changed, 232 insertions(+), 79 deletions(-) create mode 100644 Sources/OpenSwiftUICore/Event/Gesture/DefaultLayoutGesture.swift create mode 100644 Sources/OpenSwiftUICore/Event/Responder/ContentPathObservers.swift diff --git a/Sources/OpenSwiftUICore/Event/Gesture/DefaultLayoutGesture.swift b/Sources/OpenSwiftUICore/Event/Gesture/DefaultLayoutGesture.swift new file mode 100644 index 000000000..57871accc --- /dev/null +++ b/Sources/OpenSwiftUICore/Event/Gesture/DefaultLayoutGesture.swift @@ -0,0 +1,18 @@ +// +// DefaultLayoutGesture.swift +// OpenSwiftUICore +// +// Status: WIP + + +import Foundation + +struct DefaultLayoutGesture: PrimitiveGesture { + nonisolated static func _makeGesture(gesture: _GraphValue, inputs: _GestureInputs) -> _GestureOutputs { + openSwiftUIUnimplementedFailure() + } + + var responder: MultiViewResponder + + typealias Value = Void +} diff --git a/Sources/OpenSwiftUICore/Event/Responder/ContentPathObservers.swift b/Sources/OpenSwiftUICore/Event/Responder/ContentPathObservers.swift new file mode 100644 index 000000000..9ca614620 --- /dev/null +++ b/Sources/OpenSwiftUICore/Event/Responder/ContentPathObservers.swift @@ -0,0 +1,43 @@ +// +// ContentPathObservers.swift +// OpenSwiftUICore +// +// Status: Complete +// ID: A7CB304DFEF7D87240811B051B15E2CD (SwiftUICore?) + +struct ContentPathObservers { + private struct Observer { + weak var value: (any ContentPathObserver)? + } + + private var observers: [Observer] = [] + + @inline(__always) + mutating func addObserver(_ observer: any ContentPathObserver) { + guard !observers.contains(where: { $0.value === observer }) else { return } + observers.append(Observer(value: observer)) + } + + @inline(__always) + mutating func notifyDidChange(for parent: ViewResponder) { + let oldObservers = observers + observers = [] + for observer in oldObservers { + guard let value = observer.value else { continue } + value.respondersDidChange(for: parent) + } + } + + mutating func notifyPathChanged(for parent: ViewResponder, changes: ContentPathChanges, transform: (old: ViewTransform, new: ViewTransform)) { + let oldObservers = observers + observers = [] + var failedObservers: [Observer] = [] + for observer in oldObservers { + var result = true + guard let value = observer.value else { continue } + value.contentPathDidChange(for: parent, changes: changes, transform: transform, finished: &result) + guard !result else { continue } + failedObservers.append(observer) + } + } +} diff --git a/Sources/OpenSwiftUICore/Event/Responder/DefaultLayoutViewResponder.swift b/Sources/OpenSwiftUICore/Event/Responder/DefaultLayoutViewResponder.swift index ef28ad3da..33acd27ca 100644 --- a/Sources/OpenSwiftUICore/Event/Responder/DefaultLayoutViewResponder.swift +++ b/Sources/OpenSwiftUICore/Event/Responder/DefaultLayoutViewResponder.swift @@ -2,70 +2,117 @@ // DefaultLayoutViewResponder.swift // OpenSwiftUICore // -// Status: WIP +// Status: Complete package import OpenGraphShims +// MARK: - DefaultLayoutResponderFilter [6.5.4] + package struct DefaultLayoutResponderFilter: StatefulRule { -// @Attribute -// @_projectedValueProperty($children) -// package var children: [ViewResponder] { -// get { preconditionFailure("TODO") } -// nonmutating set { preconditionFailure("TODO") } -// nonmutating _modify { preconditionFailure("TODO") } -// } -// -// package var $children: Attribute<[ViewResponder]> { -// get { preconditionFailure("TODO") } -// set { preconditionFailure("TODO") } -// } -// -// package let responder: MultiViewResponder -// -// package init( -// children: Attribute<[ViewResponder]>, -// responder: MultiViewResponder -// ) { -// preconditionFailure("TODO") -// } -// + @Attribute + package var children: [ViewResponder] + + package let responder: MultiViewResponder + + package init( + children: Attribute<[ViewResponder]>, + responder: MultiViewResponder + ) { + self._children = children + self.responder = responder + } + package typealias Value = [ViewResponder] package mutating func updateValue() { - preconditionFailure("TODO") + let (children, childrenChanged) = $children.changedValue() + if childrenChanged { + responder.children = children + } + if !hasValue { + value = [responder] + } } } +// MARK: - DefaultLayoutViewResponder [6.5.4] + @_spi(ForOpenSwiftUIOnly) +@available(OpenSwiftUI_v6_0, *) open class DefaultLayoutViewResponder: MultiViewResponder { final package let inputs: _ViewInputs - final package let viewSubgraph: Subgraph + private var childSubgraph: Subgraph? + private var childViewSubgraph: Subgraph? + private var invalidateChildren: (() -> Void)? package init(inputs: _ViewInputs) { - preconditionFailure("TODO") + self.inputs = inputs + self.viewSubgraph = Subgraph.current! + super.init() + } + + package init(inputs: _ViewInputs, viewSubgraph: Subgraph) { + self.inputs = inputs + self.viewSubgraph = Subgraph.current! + super.init() + } + + // MARK: - DefaultLayoutViewResponder: ResponderNode + + override open func makeGesture(inputs: _GestureInputs) -> _GestureOutputs { + let outputs: _GestureOutputs = inputs.makeDefaultOutputs() + guard viewSubgraph.isValid else { + return outputs + } + let currentSubgraph = Subgraph.current! + let needGestureGraph = inputs.options.contains(.gestureGraph) + childSubgraph = Subgraph(graph: (needGestureGraph ? currentSubgraph : viewSubgraph).graph) + viewSubgraph.addChild(childSubgraph!, tag: 1) + currentSubgraph.addChild(childSubgraph!) + if needGestureGraph { + childViewSubgraph = Subgraph(graph: viewSubgraph.graph) + childSubgraph!.addChild(childViewSubgraph!, tag: 1) + } + childSubgraph!.apply { + let gesture = Attribute(value: DefaultLayoutGesture(responder: self)) + let weakGesture = WeakAttribute(gesture) + invalidateChildren = { + Update.enqueueAction { // TODO: enqueAction(reason: 0x5) + weakGesture.attribute?.invalidateValue() + } + } + let subgraph = (childViewSubgraph ?? childSubgraph)! + var childInputs = inputs + childInputs.viewInputs = self.inputs + childInputs.copyCaches() + childInputs.viewSubgraph = subgraph + let childOutputs = DefaultLayoutGesture.makeDebuggableGesture( + gesture: _GraphValue(gesture), + inputs: childInputs + ) + outputs.overrideDefaultValues(childOutputs) + } + return outputs + } + + override open func resetGesture() { + invalidateChildren = nil + childSubgraph = nil + childViewSubgraph = nil + super.resetGesture() + } + + // MARK: - DefaultLayoutViewResponder: MultiViewResponder + + open override func childrenDidChange() { + if let invalidateChildren { + invalidateChildren() + } + super.childrenDidChange() } -// -// package init(inputs: _ViewInputs, viewSubgraph: Subgraph) { -// preconditionFailure("TODO") -// } -// -// override open func makeGesture(inputs: _GestureInputs) -> _GestureOutputs { -// preconditionFailure("TODO") -// } -// -// override open func childrenDidChange() { -// preconditionFailure("TODO") -// } -// -// override open func resetGesture() { -// preconditionFailure("TODO") -// } -// -// @objc deinit { -// preconditionFailure("TODO") -// } } +@_spi(ForOpenSwiftUIOnly) @available(*, unavailable) extension DefaultLayoutViewResponder: Sendable {} diff --git a/Sources/OpenSwiftUICore/Event/Responder/MultiViewResponder.swift b/Sources/OpenSwiftUICore/Event/Responder/MultiViewResponder.swift index af8e7f004..3deccb25a 100644 --- a/Sources/OpenSwiftUICore/Event/Responder/MultiViewResponder.swift +++ b/Sources/OpenSwiftUICore/Event/Responder/MultiViewResponder.swift @@ -2,68 +2,113 @@ // MultiViewResponder.swift // OpenSwiftUICore // -// Status: WIP +// Status: Blocked by children.setter +// ID: 4A74C6B0E69BD6BC864CC77E33CF2D28 (SwiftUICore?) + +public import Foundation + +// MARK: - MultiViewResponder [6.5.4] [WIP] @_spi(ForOpenSwiftUIOnly) open class MultiViewResponder: ViewResponder { + private var _children: [ViewResponder] + private var cache: ContainsPointsCache + private var observers: ContentPathObservers + override public init() { - preconditionFailure("TODO") + _children = [] + cache = ContainsPointsCache() + observers = .init() + super.init() } - final public override var children: [ViewResponder] { - get { preconditionFailure("TODO") } + // MARK: - MultiViewResponder: ResponderNode - set { preconditionFailure("TODO") } + override open func bindEvent(_ event: any EventType) -> ResponderNode? { + for child in children { + guard let result = child.bindEvent(event) else { + continue + } + return result + } + return nil } - final package func updateChildren(_ data: (value: [ViewResponder], changed: Bool)) { - preconditionFailure("TODO") + @discardableResult + override final public func visit(applying visitor: (ResponderNode) -> ResponderVisitorResult) -> ResponderVisitorResult { + let result = visitor(self) + guard result == .next else { + return result + } + for child in children { + let childResult = child.visit(applying: visitor) + guard childResult != .cancel else { + return .cancel + } + } + return .next } - open func childrenDidChange() { - preconditionFailure("TODO") + override open func resetGesture() { + for child in children { + child.resetGesture() + } } - override open func bindEvent(_ event: any EventType) -> ResponderNode? { - preconditionFailure("TODO") - } + // MARK: - MultiViewResponder: ViewResponder - override open func resetGesture() { - preconditionFailure("TODO") + override open func containsGlobalPoints( + _ points: [PlatformPoint], + cacheKey: UInt32?, + options: ViewResponder.ContainsPointsOptions + ) -> ViewResponder.ContainsPointsResult { + cache.fetch(key: cacheKey) { + var mask: BitVector64 = [] + var priority: Double = 0 + for child in children { + let childResult = child.containsGlobalPoints( + points, + cacheKey: cacheKey, + options: options + ) + mask.formUnion(childResult.mask) + priority = max(priority, childResult.priority) + } + return ContainsPointsResult(mask: mask, priority: priority, children: children) + } } -// override open func containsGlobalPoints( -// _ points: [PlatformPoint], -// cacheKey: UInt32?, -// options: ViewResponder.ContainsPointsOptions -// ) -> (mask: BitVector64, priority: Double) { -// preconditionFailure("TODO") -// } - override open func addContentPath( to path: inout Path, kind: ContentShapeKinds, in space: CoordinateSpace, observer: (any ContentPathObserver)? ) { - preconditionFailure("TODO") + if let observer { + observers.addObserver(observer) + } + for child in children { + child.addContentPath( + to: &path, + kind: kind, + in: space, + observer: observer + ) + } } override open func addObserver(_ observer: any ContentPathObserver) { - preconditionFailure("TODO") + observers.addObserver(observer) } - @discardableResult - override final public func visit(applying visitor: (ResponderNode) -> ResponderVisitorResult) -> ResponderVisitorResult { - preconditionFailure("TODO") + override final public var children: [ViewResponder] { + get { _children } + set { openSwiftUIUnimplementedFailure() } } -// override final public var childCount: Int { preconditionFailure("TODO") } -// -// override final public func child(at index: Int) -> ViewResponder { -// preconditionFailure("TODO") -// } - + open func childrenDidChange() { + observers.notifyDidChange(for: self) + } } @available(*, unavailable) From 4cc8a46843379de9fdbd7313ea596a69d25e04c8 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 29 Jun 2025 20:45:44 +0800 Subject: [PATCH 3/4] Add API for LayoutGesture --- .../Event/Gesture/DefaultLayoutGesture.swift | 18 ----- .../Event/Gesture/GestureViewModifier.swift | 12 +-- .../Event/Gesture/LayoutGesture.swift | 73 +++++++++++++++++++ 3 files changed, 80 insertions(+), 23 deletions(-) delete mode 100644 Sources/OpenSwiftUICore/Event/Gesture/DefaultLayoutGesture.swift create mode 100644 Sources/OpenSwiftUICore/Event/Gesture/LayoutGesture.swift diff --git a/Sources/OpenSwiftUICore/Event/Gesture/DefaultLayoutGesture.swift b/Sources/OpenSwiftUICore/Event/Gesture/DefaultLayoutGesture.swift deleted file mode 100644 index 57871accc..000000000 --- a/Sources/OpenSwiftUICore/Event/Gesture/DefaultLayoutGesture.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// DefaultLayoutGesture.swift -// OpenSwiftUICore -// -// Status: WIP - - -import Foundation - -struct DefaultLayoutGesture: PrimitiveGesture { - nonisolated static func _makeGesture(gesture: _GraphValue, inputs: _GestureInputs) -> _GestureOutputs { - openSwiftUIUnimplementedFailure() - } - - var responder: MultiViewResponder - - typealias Value = Void -} diff --git a/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift b/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift index 1be692c0f..b1d96d4fb 100644 --- a/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift +++ b/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift @@ -175,7 +175,7 @@ extension AnyGestureResponder { makeChild: (_GestureInputs) -> _GestureOutputs ) -> _GestureOutputs { let inputs = inputs - var outputs: _GestureOutputs = inputs.makeDefaultOutputs() + let outputs: _GestureOutputs = inputs.makeDefaultOutputs() guard viewSubgraph.isValid else { return outputs } @@ -191,9 +191,9 @@ extension AnyGestureResponder { childSubgraph!.apply { let subgraph = (childViewSubgraph ?? childSubgraph)! var childInputs = inputs - var viewInputs = self.inputs - viewInputs.copyCaches() - childInputs.viewInputs = viewInputs + childInputs.viewInputs = self.inputs + childInputs.copyCaches() + childInputs.viewSubgraph = subgraph let childOutputs = makeChild(childInputs) outputs.overrideDefaultValues(childOutputs) } @@ -271,6 +271,8 @@ extension AnyGestureResponder { } } +// MARK: - GestureResponder [6.5.4] [WIP] + private class GestureResponder: DefaultLayoutViewResponder, AnyGestureResponder where Modifier: GestureViewModifier { let modifier: Attribute @@ -366,7 +368,7 @@ private class GestureResponder: DefaultLayoutViewResponder, AnyGesture override func makeGesture(inputs: _GestureInputs) -> _GestureOutputs { makeWrappedGesture(inputs: inputs) { childInputs in - var childViewInputs = childInputs.viewInputs + let childViewInputs = childInputs.viewInputs let closure: () -> _GestureOutputs = { [self] in if inputs.options.contains(.skipCombiners) { let childGesture = Attribute(GestureViewChild( diff --git a/Sources/OpenSwiftUICore/Event/Gesture/LayoutGesture.swift b/Sources/OpenSwiftUICore/Event/Gesture/LayoutGesture.swift new file mode 100644 index 000000000..c0b786265 --- /dev/null +++ b/Sources/OpenSwiftUICore/Event/Gesture/LayoutGesture.swift @@ -0,0 +1,73 @@ +// +// LayoutGesture.swift +// OpenSwiftUICore +// +// Status: WIP + +// MARK: - LayoutGesture [6.5.4] [WIP] + +package protocol LayoutGesture: PrimitiveDebuggableGesture, PrimitiveGesture where Value == () { + var responder: MultiViewResponder { get } + + func updateEventBindings( + _ events: inout [EventID : any EventType], + proxy: LayoutGestureChildProxy + ) +} + +extension LayoutGesture { + package static func _makeGesture( + gesture: _GraphValue, + inputs: _GestureInputs + ) -> _GestureOutputs { + openSwiftUIUnimplementedFailure() + } + + package func updateEventBindings( + _ events: inout [EventID : any EventType], + proxy: LayoutGestureChildProxy + ) {} +} + +// MARK: - DefaultLayoutGesture [6.5.4] [WIP] + +package struct DefaultLayoutGesture: LayoutGesture { + package var responder: MultiViewResponder + + package typealias Body = Never + package typealias Value = () +} + +// MARK: - LayoutGestureChildProxy [6.5.4] [WIP] + +package struct LayoutGestureChildProxy: RandomAccessCollection { + package struct Child { + package func binds(_ binding: EventBinding) -> Bool { + preconditionFailure("TODO") + } + + package func containsGlobalLocation(_ p: PlatformPoint) -> Bool { + preconditionFailure("TODO") + } + } + + package var startIndex: Int { + get { preconditionFailure("TODO") } + } + + package var endIndex: Int { + get { preconditionFailure("TODO") } + } + + package subscript(index: Int) -> LayoutGestureChildProxy.Child { + get { preconditionFailure("TODO") } + } + + package func bindChild( + index: Int, + event: any EventType, + id: EventID + ) -> (from: EventBinding?, to: EventBinding?)? { + preconditionFailure("TODO") + } +} From da370308f02fc34b7465b3b64902b6305760eda2 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 29 Jun 2025 21:53:28 +0800 Subject: [PATCH 4/4] Fix macOS + release build issue --- .../Event/Gesture/AnyGesture.swift | 3 +- .../Event/Gesture/GestureViewModifier.swift | 57 ++++++++++--------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/Sources/OpenSwiftUICore/Event/Gesture/AnyGesture.swift b/Sources/OpenSwiftUICore/Event/Gesture/AnyGesture.swift index 75f2d70eb..753d87384 100644 --- a/Sources/OpenSwiftUICore/Event/Gesture/AnyGesture.swift +++ b/Sources/OpenSwiftUICore/Event/Gesture/AnyGesture.swift @@ -27,11 +27,12 @@ public struct AnyGesture: PrimitiveGesture, Gesture { inputs: _GestureInputs ) -> _GestureOutputs { let outputs: _GestureOutputs = inputs.makeIndirectOutputs() + let currentSubgraph = Subgraph.current! let info = Attribute(AnyGestureInfo( gesture: gesture.value, inputs: inputs, outputs: outputs, - parentSubgraph: Subgraph.current! + parentSubgraph: currentSubgraph )) info.setFlags(.active, mask: .mask) outputs.setIndirectDependency(info.identifier) diff --git a/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift b/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift index b1d96d4fb..486bbf533 100644 --- a/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift +++ b/Sources/OpenSwiftUICore/Event/Gesture/GestureViewModifier.swift @@ -368,30 +368,31 @@ private class GestureResponder: DefaultLayoutViewResponder, AnyGesture override func makeGesture(inputs: _GestureInputs) -> _GestureOutputs { makeWrappedGesture(inputs: inputs) { childInputs in - let childViewInputs = childInputs.viewInputs - let closure: () -> _GestureOutputs = { [self] in - if inputs.options.contains(.skipCombiners) { - let childGesture = Attribute(GestureViewChild( - modifier: modifier, - isEnabled: childViewInputs.isEnabled, - viewPhase: childViewInputs.viewPhase - )) - return AnyGesture.makeDebuggableGesture(gesture: _GraphValue(childGesture), inputs: childInputs) - } else { - let childGesture = Attribute(CombiningGestureViewChild( - modifier: modifier, - isEnabled: childViewInputs.isEnabled, - viewPhase: childViewInputs.viewPhase, - node: self - )) - return Modifier.Combiner.Result.makeDebuggableGesture(gesture: _GraphValue(childGesture), inputs: childInputs) - } - } - guard inputs.options.contains(.includeDebugOutput) else { - return closure() - } - // TODO: GestureViewDebug - return closure() +// let childViewInputs = childInputs.viewInputs +// let closure: () -> _GestureOutputs = { [self] in +// if inputs.options.contains(.skipCombiners) { +// let childGesture = Attribute(GestureViewChild( +// modifier: modifier, +// isEnabled: childViewInputs.isEnabled, +// viewPhase: childViewInputs.viewPhase +// )) +// return AnyGesture.makeDebuggableGesture(gesture: _GraphValue(childGesture), inputs: childInputs) +// } else { +// let childGesture = Attribute(CombiningGestureViewChild( +// modifier: modifier, +// isEnabled: childViewInputs.isEnabled, +// viewPhase: childViewInputs.viewPhase, +// node: self +// )) +// return Modifier.Combiner.Result.makeDebuggableGesture(gesture: _GraphValue(childGesture), inputs: childInputs) +// } +// } +// guard inputs.options.contains(.includeDebugOutput) else { +// return closure() +// } +// // TODO: GestureViewDebug +// return closure() + preconditionFailure("TODO") } } @@ -549,13 +550,13 @@ private struct GestureViewDebug where Modifier: GestureViewModifier { // MARK: - SubviewsGesture [6.5.4] private struct SubviewsGesture: PrimitiveGesture, PrimitiveDebuggableGesture { - internal typealias Value = () + typealias Value = () - internal typealias Body = Never + typealias Body = Never - internal let node: AnyGestureResponder + let node: AnyGestureResponder - fileprivate static func _makeGesture(gesture: _GraphValue, inputs: _GestureInputs) -> _GestureOutputs { + static func _makeGesture(gesture: _GraphValue, inputs: _GestureInputs) -> _GestureOutputs { let outputs: _GestureOutputs = inputs.makeIndirectOutputs() let currentSubgraph = Subgraph.current! let subviewValue = Attribute(SubviewsPhase(