waterui 0.3.0

A modern UI framework for Rust
import CWaterUI
import Metal
import QuartzCore

#if canImport(UIKit)
  import UIKit
#elseif canImport(AppKit)
  import AppKit
#endif

@MainActor
enum WuiDynamicRangeMode {
  case standard
  case high
}

private func dynamicRangeAssociationKey() -> UnsafeRawPointer {
  let selector = NSSelectorFromString("dev.waterui.dynamicRangeMode")
  return unsafeBitCast(selector, to: UnsafeRawPointer.self)
}

@MainActor
func applyDynamicRange(_ mode: WuiDynamicRangeMode, to layer: CALayer?) {
  guard let layer else { return }

  // Keep explicit nested overrides stable: if a sublayer already carries its own mode,
  // preserve that local mode and propagate from there.
  let localMode =
    (objc_getAssociatedObject(layer, dynamicRangeAssociationKey()) as? WuiDynamicRangeMode)
    ?? mode
  objc_setAssociatedObject(
    layer, dynamicRangeAssociationKey(), localMode, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

  #if canImport(UIKit)
    layer.preferredDynamicRange = (localMode == .high) ? .high : .standard
  #elseif canImport(AppKit)
    layer.preferredDynamicRange = (localMode == .high) ? .high : .standard
  #endif

  if let sublayers = layer.sublayers {
    for sublayer in sublayers {
      applyDynamicRange(localMode, to: sublayer)
    }
  }
}

@MainActor
func applyDynamicRange(_ mode: WuiDynamicRangeMode, to view: PlatformView) {
  objc_setAssociatedObject(
    view, dynamicRangeAssociationKey(), mode, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  #if canImport(AppKit)
    view.wantsLayer = true
    guard let layer = view.layer else {
      fatalError("AppKit failed to create the requested backing layer")
    }
  #elseif canImport(UIKit)
    let layer = view.layer
  #endif
  objc_setAssociatedObject(
    layer, dynamicRangeAssociationKey(), mode, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  #if canImport(UIKit)
    layer.preferredDynamicRange = (mode == .high) ? .high : .standard
  #elseif canImport(AppKit)
    layer.preferredDynamicRange = (mode == .high) ? .high : .standard
  #endif
  for sublayer in layer.sublayers ?? [] {
    applyDynamicRange(mode, to: sublayer)
  }
}

@MainActor
private func resolveDynamicRangeOverride(startingAt view: PlatformView?) -> WuiDynamicRangeMode? {
  var current = view
  while let node = current {
    if let tagged = objc_getAssociatedObject(node, dynamicRangeAssociationKey())
      as? WuiDynamicRangeMode
    {
      return tagged
    }
    current = node.superview
  }
  return nil
}

@MainActor
private func resolveDisplayDynamicRange(for view: PlatformView) -> WuiDynamicRangeMode? {
  #if canImport(UIKit)
    guard let screen = view.window?.windowScene?.screen else { return nil }
    return resolveDynamicRange(for: screen)
  #elseif canImport(AppKit)
    guard let screen = view.window?.screen else { return nil }
    return resolveDynamicRange(for: screen)
  #endif
}

#if canImport(UIKit)
  @MainActor
  func resolveDynamicRange(for screen: UIScreen) -> WuiDynamicRangeMode {
    screen.potentialEDRHeadroom > 1 ? .high : .standard
  }
#elseif canImport(AppKit)
  @MainActor
  func resolveDynamicRange(for screen: NSScreen) -> WuiDynamicRangeMode {
    screen.maximumPotentialExtendedDynamicRangeColorComponentValue > 1 ? .high : .standard
  }
#endif

@MainActor
private func resolveDynamicRange(
  for view: PlatformView,
  overrideStartingAt overrideOrigin: PlatformView?
) -> WuiDynamicRangeMode? {
  resolveDynamicRangeOverride(startingAt: overrideOrigin)
    ?? resolveDisplayDynamicRange(for: view)
}

@MainActor
func resolveDynamicRange(for view: PlatformView) -> WuiDynamicRangeMode? {
  resolveDynamicRange(for: view, overrideStartingAt: view)
}

@MainActor
func requireInheritedDynamicRange(for view: PlatformView) -> WuiDynamicRangeMode {
  guard let mode = resolveDynamicRange(for: view, overrideStartingAt: view.superview) else {
    fatalError("Dynamic range resolution requires a view attached to a display")
  }
  return mode
}

@MainActor
func applyResolvedDynamicRange(to layer: CALayer?, for view: PlatformView) {
  guard let mode = resolveDynamicRange(for: view) else { return }
  applyDynamicRange(mode, to: layer)
}

@MainActor
func configureMetalLayerDynamicRange(
  _ layer: CAMetalLayer,
  presentationMode: WuiDynamicRangeMode,
  rendererMode: WuiDynamicRangeMode
) {
  precondition(
    presentationMode == .standard || rendererMode == .high,
    "An HDR presentation requires an HDR-capable renderer target"
  )
  objc_setAssociatedObject(
    layer,
    dynamicRangeAssociationKey(),
    presentationMode,
    .OBJC_ASSOCIATION_RETAIN_NONATOMIC
  )
  layer.preferredDynamicRange = presentationMode == .high ? .high : .standard
  switch rendererMode {
  case .high:
    layer.pixelFormat = .rgba16Float
    layer.colorspace = CGColorSpace(name: CGColorSpace.extendedLinearSRGB)
  case .standard:
    layer.pixelFormat = .bgra8Unorm_srgb
    layer.colorspace = CGColorSpace(name: CGColorSpace.sRGB)
  }
  layer.wantsExtendedDynamicRangeContent = presentationMode == .high
}

/// Component for Metadata<StandardDynamicRange>.
@MainActor
final class WuiStandardDynamicRange: PlatformView, WuiComponent {
  static var rawId: CWaterUI.WuiTypeId { waterui_metadata_standard_dynamic_range_id() }

  private let contentView: any WuiComponent

  var stretchAxis: WuiStretchAxis {
    contentView.stretchAxis
  }

  required init(anyview: OpaquePointer, env: WuiEnvironment) {
    let metadata = waterui_force_as_metadata_standard_dynamic_range(anyview)

    // Resolve the content
    self.contentView = WuiAnyView.resolve(anyview: metadata.content, env: env)

    super.init(frame: .zero)

    contentView.translatesAutoresizingMaskIntoConstraints = true
    addSubview(contentView)

    applyDynamicRange(.standard, to: self)
  }

  @available(*, unavailable)
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  func layoutPriority() -> Int32 {
    contentView.layoutPriority()
  }

  func sizeThatFits(_ proposal: WuiProposalSize) -> CGSize {
    contentView.sizeThatFits(proposal)
  }

  #if canImport(UIKit)
    override func layoutSubviews() {
      super.layoutSubviews()
      contentView.frame = bounds
      applyDynamicRange(.standard, to: self)
    }
  #elseif canImport(AppKit)
    nonisolated override var isFlipped: Bool { true }

    override func layout() {
      super.layout()
      contentView.frame = bounds
      applyDynamicRange(.standard, to: self)
    }
  #endif
}

/// Component for Metadata<HighDynamicRange>.
@MainActor
final class WuiHighDynamicRange: PlatformView, WuiComponent {
  static var rawId: CWaterUI.WuiTypeId { waterui_metadata_high_dynamic_range_id() }

  private let contentView: any WuiComponent

  var stretchAxis: WuiStretchAxis {
    contentView.stretchAxis
  }

  required init(anyview: OpaquePointer, env: WuiEnvironment) {
    let metadata = waterui_force_as_metadata_high_dynamic_range(anyview)

    // Resolve the content
    self.contentView = WuiAnyView.resolve(anyview: metadata.content, env: env)

    super.init(frame: .zero)

    contentView.translatesAutoresizingMaskIntoConstraints = true
    addSubview(contentView)

    applyDynamicRange(.high, to: self)
  }

  @available(*, unavailable)
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  func layoutPriority() -> Int32 {
    contentView.layoutPriority()
  }

  func sizeThatFits(_ proposal: WuiProposalSize) -> CGSize {
    contentView.sizeThatFits(proposal)
  }

  #if canImport(UIKit)
    override func layoutSubviews() {
      super.layoutSubviews()
      contentView.frame = bounds
      applyDynamicRange(.high, to: self)
    }
  #elseif canImport(AppKit)
    nonisolated override var isFlipped: Bool { true }

    override func layout() {
      super.layout()
      contentView.frame = bounds
      applyDynamicRange(.high, to: self)
    }
  #endif
}