waterui 0.3.0

A modern UI framework for Rust
import CWaterUI
import QuartzCore

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

/// Component for Metadata<ClipShape>.
///
/// Clips the wrapped view to a shape defined by path commands.
@MainActor
final class WuiClipShape: PlatformView, WuiComponent {
    static var rawId: CWaterUI.WuiTypeId { waterui_metadata_clip_shape_id() }

    private let contentView: any WuiComponent
    private let shapeKind: WuiShapeKind
    private let pathCommands: [WuiPathCommand]
    private var maskLayer: CAShapeLayer?

    var stretchAxis: WuiStretchAxis {
        contentView.stretchAxis
    }

    required init(anyview: OpaquePointer, env: WuiEnvironment) {
        let metadata = waterui_force_as_metadata_clip_shape(anyview)
        contentView = WuiAnyView.resolve(anyview: metadata.content, env: env)
        shapeKind = metadata.value.kind
        pathCommands = WuiShapePath.commands(from: metadata.value.commands)

        super.init(frame: .zero)

        contentView.translatesAutoresizingMaskIntoConstraints = true
        addSubview(contentView)

        #if canImport(UIKit)
        clipsToBounds = true
        #elseif canImport(AppKit)
        wantsLayer = true
        layer?.masksToBounds = true
        #endif
    }

    @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
        updateMask()
    }
    #elseif canImport(AppKit)
    nonisolated override var isFlipped: Bool { true }

    override func layout() {
        super.layout()
        contentView.frame = bounds
        updateMask()
    }
    #endif

    private func updateMask() {
        guard !bounds.isEmpty else { return }

        if maskLayer == nil {
            let newMask = CAShapeLayer()
            maskLayer = newMask
            #if canImport(UIKit)
            layer.mask = newMask
            #elseif canImport(AppKit)
            layer?.mask = newMask
            #endif
        }

        maskLayer?.path = WuiShapePath.makePath(
            kind: shapeKind, commands: pathCommands, in: bounds)
    }
}