Zum Inhalt

apple/PhysarumApp/Sources/Editor/MorphSheet.swift

#if !os(tvOS)
import SwiftUI
import PhysarumEngine

/// Morph between the current edit (A) and a chosen preset (B). The main player
/// previews the blend live as the slider moves.
struct MorphSheet: View {
    @Bindable var state: AppState
    @Binding var isPresented: Bool

    @State private var baseA: PresetParams?
    @State private var targetID: String = ""
    @State private var t: Double = 0

    private var targetPreset: Preset? { state.presets.first { $0.id == targetID } }

    var body: some View {
        VStack(alignment: .leading, spacing: Theme.Space.s3) {
            Text("MORPH").font(Theme.Fonts.eyebrow).tracking(2)
                .foregroundStyle(Theme.Colors.fgSecondary)

            Picker("Morph to", selection: $targetID) {
                ForEach(state.presets.filter { $0.id != state.selectedID }, id: \.id) { Text($0.name).tag($0.id) }
            }
            .onChange(of: targetID) { _, _ in applyMorph() }
            .accessibilityLabel("Morph to")
            .accessibilityHint("Pick the target preset")
            .accessibilityValue(targetPreset?.name ?? "")

            HStack {
                Text("A").font(Theme.Fonts.value).foregroundStyle(Theme.Colors.fgTertiary)
                Slider(value: $t, in: 0...1)
                    .tint(Theme.Colors.accent)
                    .onChange(of: t) { _, _ in applyMorph() }
                    .accessibilityLabel("Blend factor")
                    .accessibilityHint("0 = start, 1 = target")
                    .accessibilityValue("\(Int(t * 100)) percent")
                Text("B").font(Theme.Fonts.value).foregroundStyle(Theme.Colors.fgTertiary)
            }

            HStack {
                PhysButton(title: "Cancel", kind: .ghost) {
                    if let a = baseA { state.edited = a }
                    isPresented = false
                }
                .accessibilityLabel("Cancel")
                PhysButton(title: "Apply", kind: .ember) {
                    if let a = baseA { state.pushUndo(a) }     // undo returns to A
                    isPresented = false
                }
                .accessibilityLabel("Apply morph")
            }
        }
        .padding(Theme.Space.s4)
        .frame(minWidth: 320)
        .background(Theme.Colors.surface)
        .foregroundStyle(Theme.Colors.fgPrimary)
        .onAppear {
            baseA = state.edited
            if targetID.isEmpty {
                targetID = state.presets.first { $0.id != state.selectedID }?.id
                    ?? state.presets.first?.id ?? ""
            }
        }
    }

    private func applyMorph() {
        guard let a = baseA, let b = targetPreset else { return }
        state.edited = morphParams(a, b.params, t: t)
    }
}
#endif