Skip to content
3 changes: 0 additions & 3 deletions Sources/OpenSwiftUI/EventHandling/Focus/FocusStore.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// FIXME
protocol ResponderNode {}

struct FocusStore {
var seed: VersionSeed
var focusedResponders: ContiguousArray<ResponderNode>
Expand Down
4 changes: 0 additions & 4 deletions Sources/OpenSwiftUICore/Event/Event.swift

This file was deleted.

217 changes: 217 additions & 0 deletions Sources/OpenSwiftUICore/Event/Event/Event.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
//
// Event.swift
// OpenSwiftUICore
//
// Status: Complete

package import Foundation

// MARK: - MouseEvent [6.5.4]

package struct MouseEvent: SpatialEventType, TappableEventType, ModifiersEventType, Equatable {
package struct Button: RawRepresentable, Equatable {
package let rawValue: Int

package init(rawValue: Int) {
self.rawValue = rawValue
}

package static let primary: MouseEvent.Button = .init(rawValue: 1 << 0)

package static let secondary: MouseEvent.Button = .init(rawValue: 1 << 1)

package static func other(_ index: Int) -> MouseEvent.Button {
.init(rawValue: index)
}
}

package var timestamp: Time
package var binding: EventBinding?
package var button: MouseEvent.Button
package var phase: EventPhase
package var location: CGPoint
package var globalLocation: CGPoint
package var modifiers: EventModifiers

package init(
timestamp: Time,
binding: EventBinding? = nil,
button: MouseEvent.Button,
phase: EventPhase,
location: CGPoint,
globalLocation: CGPoint,
modifiers: EventModifiers
) {
self.timestamp = timestamp
self.binding = binding
self.button = button
self.phase = phase
self.location = location
self.globalLocation = globalLocation
self.modifiers = modifiers
}

package var radius: CGFloat { .zero }

package var kind: SpatialEvent.Kind? { .mouse }
}

extension MouseEvent: HitTestableEventType {}

// MARK: - EventModifiers [6.5.4]

/// A set of key modifiers that you can add to a gesture.
@available(OpenSwiftUI_v1_0, *)
@frozen
public struct EventModifiers: OptionSet {
public let rawValue: Int

public init(rawValue: Int) {
self.rawValue = rawValue
}

/// The Caps Lock key.
public static let capsLock: EventModifiers = .init(rawValue: 1 << 0)

/// The Shift key.
public static let shift: EventModifiers = .init(rawValue: 1 << 1)

/// The Control key.
public static let control: EventModifiers = .init(rawValue: 1 << 2)

/// The Option key.
public static let option: EventModifiers = .init(rawValue: 1 << 3)

/// The Command key.
public static let command: EventModifiers = .init(rawValue: 1 << 4)

/// Any key on the numeric keypad.
public static let numericPad: EventModifiers = .init(rawValue: 1 << 5)

/// The Function key.
@available(*, deprecated, message: "Function modifier is reserved for system applications")
public static let function: EventModifiers = .init(rawValue: 1 << 6)

package static let _function: EventModifiers = .init(rawValue: 1 << 6)

/// All possible modifier keys.
public static let all: EventModifiers = [.capsLock, .shift, .control, .option, .command, .numericPad]

package static let _all: EventModifiers = [.capsLock, .shift, .control, .option, .command, .numericPad, ._function]
}

// MARK: - ModifiersEventType [6.5.4]

package protocol ModifiersEventType: EventType {
var modifiers: EventModifiers { get set }
}

// MARK: - EventPhase [6.5.4]

@_spi(ForOpenSwiftUIOnly)
@available(OpenSwiftUI_v6_0, *)
public enum EventPhase: Hashable {
case began
case active
case ended
case failed
}

@available(*, unavailable)
extension EventPhase: Sendable {}

extension EventPhase {
package var isTerminal: Bool {
switch self {
case .began, .active: false
case .ended, .failed: true
}
}
}

// MARK: - EventType [6.5.4]

@_spi(ForOpenSwiftUIOnly)
@available(OpenSwiftUI_v6_0, *)
public protocol EventType {
var phase: EventPhase { get }

var timestamp: Time { get }

var binding: EventBinding? { get set }

init?(_ event: any EventType)
}

extension EventType {
package init?(_ event: any EventType) {
guard let event = event as? Self else {
return nil
}
self = event
}

package var isFocusEvent: Bool {
HitTestableEvent(self) == nil
}
}

// MARK: - Event [6.5.4]

package struct Event: EventType {
package var phase: EventPhase
package var timestamp: Time
package var binding: EventBinding?

package init<T>(_ event: T) where T: EventType {
phase = event.phase
timestamp = event.timestamp
binding = event.binding
}

package init?(_ event: any EventType) {
phase = event.phase
timestamp = event.timestamp
binding = event.binding
}
}

// MARK: - EventID [6.5.4]

@_spi(ForOpenSwiftUIOnly)
@available(OpenSwiftUI_v6_0, *)
public struct EventID: Hashable {
package var type: any Any.Type

package var serial: Int

package init(type: any Any.Type, serial: Int) {
self.type = type
self.serial = serial
}

public static func == (lhs: EventID, rhs: EventID) -> Bool {
lhs.type == rhs.type && lhs.serial == rhs.serial
}

public func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(type))
hasher.combine(serial)
}
}

@available(*, unavailable)
extension EventID: Sendable {}

extension EventID {
package init<T, S>(_ obj: T, subtype: S.Type) where T: NSObject {
type = (T, S).self
serial = unsafeBitCast(obj, to: Int.self)
}
}

extension EventID: CustomStringConvertible {
public var description: String {
"\(type)#\(serial)"
}
}
25 changes: 25 additions & 0 deletions Sources/OpenSwiftUICore/Event/Event/EventBinding.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// EventBinding.swift
// OpenSwiftUICore
//
// Status: Complete

// MARK: - EventBinding [6.5.4]

@_spi(ForOpenSwiftUIOnly)
@available(OpenSwiftUI_v6_0, *)
public struct EventBinding: Equatable {
package var responder: ResponderNode

package init(responder: ResponderNode) {
self.responder = responder
}

public static func == (lhs: EventBinding, rhs: EventBinding) -> Bool {
lhs.responder === rhs.responder
}
}

@_spi(ForOpenSwiftUIOnly)
@available(*, unavailable)
extension EventBinding: Sendable {}
100 changes: 100 additions & 0 deletions Sources/OpenSwiftUICore/Event/Event/EventBindingBridge.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// EventBindingBridge.swift
// OpenSwiftUICore
//
// Status: WIP
// ID: E11AC34B5BFF53E1001A61D61F5B9E0F (SwiftUICore)

// MARK: - EventBindingBridge [6.5.4] [WIP]

@_spi(ForOpenSwiftUIOnly)
@available(OpenSwiftUI_v6_0, *)
open class EventBindingBridge {
package private(set) weak var eventBindingManager: EventBindingManager?

package var responderWasBoundHandler: ((ResponderNode) -> Void)?

private struct TrackedEventState {
var sourceID: ObjectIdentifier
var reset: Bool
}

private var trackedEvents: [EventID: TrackedEventState] = [:]

public init(eventBindingManager: EventBindingManager) {
self.eventBindingManager = eventBindingManager
}

public init() {}

open var eventSources: [any EventBindingSource] { [] }

@discardableResult
open func send(
_ events: [EventID: any EventType],
source: any EventBindingSource
) -> Set<EventID> {
preconditionFailure("TODO")
}

open func reset(
eventSource: any EventBindingSource,
resetForwardedEventDispatchers: Bool = false
) {
preconditionFailure("TODO")
}

private func resetEvent() {
preconditionFailure("TODO")
}

open func setInheritedPhase(_ phase: _GestureInputs.InheritedPhase) {
eventBindingManager?.setInheritedPhase(phase)
}

open func source(for sourceType: EventSourceType) -> (any EventBindingSource)? {
nil
}
}

@_spi(ForOpenSwiftUIOnly)
@available(*, unavailable)
extension EventBindingBridge: Sendable {}

// MARK: - EventBindingBridge + EventBindingManagerDelegate [6.5.4]

@_spi(ForOpenSwiftUIOnly)
extension EventBindingBridge: EventBindingManagerDelegate {
package func didBind(
to newBinding: EventBinding,
id: EventID
) {
if let responderWasBoundHandler {
// TODO: Update.enqueueAction(reason:_:)
Update.enqueueAction {
responderWasBoundHandler(newBinding.responder)
}
}
for eventSource in eventSources {
eventSource.didBind(to: newBinding, id: id, in: self)
}
}

package func didUpdate(
phase: GesturePhase<Void>,
in eventBindingManager: EventBindingManager
) {
for eventSource in eventSources {
eventSource.didUpdate(phase: phase, in: self)
}
}

package func didUpdate(
gestureCategory: GestureCategory,
in eventBindingManager: EventBindingManager
) {
for eventSource in eventSources {
eventSource.didUpdate(gestureCategory: gestureCategory, in: self)
}
}
}
Loading