fix: repaired scene prefs

This commit is contained in:
2026-03-21 09:32:33 +01:00
parent 941ec92dbf
commit 675183152a

View File

@@ -1,66 +1,18 @@
import SwiftUI import SwiftUI
private let generationDoubleFormat = FloatingPointFormatStyle<Double>.number.precision(.fractionLength(0...2))
private let generationIntegerFormat = IntegerFormatStyle<Int>.number.grouping(.never)
struct GenerationDefaultsEditor: View { struct GenerationDefaultsEditor: View {
@Binding var settings: GenerationSettings @Binding var settings: GenerationSettings
var body: some View { var body: some View {
Toggle("Enable thinking mode", isOn: $settings.thinkingEnabled) Toggle("Enable thinking mode", isOn: $settings.thinkingEnabled)
doubleRow("Temperature", value: $settings.temperature) DecimalSettingRow(title: "Temperature", value: $settings.temperature)
doubleRow("Top P", value: $settings.topP) DecimalSettingRow(title: "Top P", value: $settings.topP)
intRow("Top K", value: $settings.topK) IntegerSettingRow(title: "Top K", value: $settings.topK)
doubleRow("Min P", value: $settings.minP) DecimalSettingRow(title: "Min P", value: $settings.minP)
intRow("Max tokens", value: $settings.maxTokens) IntegerSettingRow(title: "Max tokens", value: $settings.maxTokens)
optionalDoubleRow("Repetition penalty", value: $settings.repetitionPenalty) OptionalDecimalSettingRow(title: "Repetition penalty", value: $settings.repetitionPenalty, fallbackValue: 1.0)
optionalDoubleRow("Presence penalty", value: $settings.presencePenalty) OptionalDecimalSettingRow(title: "Presence penalty", value: $settings.presencePenalty, fallbackValue: 0.0)
optionalDoubleRow("Frequency penalty", value: $settings.frequencyPenalty) OptionalDecimalSettingRow(title: "Frequency penalty", value: $settings.frequencyPenalty, fallbackValue: 0.0)
}
private func doubleRow(_ title: String, value: Binding<Double>) -> some View {
HStack {
Text(title)
Spacer()
TextField(title, value: value, format: generationDoubleFormat)
.multilineTextAlignment(.trailing)
.frame(width: 90)
}
}
private func intRow(_ title: String, value: Binding<Int>) -> some View {
HStack {
Text(title)
Spacer()
TextField(title, value: value, format: generationIntegerFormat)
.multilineTextAlignment(.trailing)
.frame(width: 90)
}
}
private func optionalDoubleRow(_ title: String, value: Binding<Double?>) -> some View {
HStack {
Text(title)
Spacer()
TextField(title, value: binding(for: value), format: generationDoubleFormat)
.multilineTextAlignment(.trailing)
.frame(width: 90)
Button(value.wrappedValue == nil ? "Set" : "Clear") {
if value.wrappedValue == nil {
value.wrappedValue = 1.0
} else {
value.wrappedValue = nil
}
}
.buttonStyle(.link)
}
}
private func binding(for value: Binding<Double?>) -> Binding<Double> {
Binding(
get: { value.wrappedValue ?? 1.0 },
set: { value.wrappedValue = $0 }
)
} }
} }
@@ -76,69 +28,228 @@ struct GenerationOverridesEditor: View {
Text("Disabled").tag(Optional(false)) Text("Disabled").tag(Optional(false))
} }
optionalDoubleRow("Temperature", value: $overrides.temperature, inheritedValue: inheritedSettings.temperature) OptionalDecimalSettingRow(title: "Temperature", value: $overrides.temperature, fallbackValue: inheritedSettings.temperature, inherited: true)
optionalDoubleRow("Top P", value: $overrides.topP, inheritedValue: inheritedSettings.topP) OptionalDecimalSettingRow(title: "Top P", value: $overrides.topP, fallbackValue: inheritedSettings.topP, inherited: true)
optionalIntRow("Top K", value: $overrides.topK, inheritedValue: inheritedSettings.topK) OptionalIntegerSettingRow(title: "Top K", value: $overrides.topK, fallbackValue: inheritedSettings.topK, inherited: true)
optionalDoubleRow("Min P", value: $overrides.minP, inheritedValue: inheritedSettings.minP) OptionalDecimalSettingRow(title: "Min P", value: $overrides.minP, fallbackValue: inheritedSettings.minP, inherited: true)
optionalIntRow("Max tokens", value: $overrides.maxTokens, inheritedValue: inheritedSettings.maxTokens) OptionalIntegerSettingRow(title: "Max tokens", value: $overrides.maxTokens, fallbackValue: inheritedSettings.maxTokens, inherited: true)
optionalDoubleRow("Repetition penalty", value: $overrides.repetitionPenalty, inheritedValue: inheritedSettings.repetitionPenalty ?? 0) OptionalDecimalSettingRow(title: "Repetition penalty", value: $overrides.repetitionPenalty, fallbackValue: inheritedSettings.repetitionPenalty ?? 0, inherited: true)
optionalDoubleRow("Presence penalty", value: $overrides.presencePenalty, inheritedValue: inheritedSettings.presencePenalty ?? 0) OptionalDecimalSettingRow(title: "Presence penalty", value: $overrides.presencePenalty, fallbackValue: inheritedSettings.presencePenalty ?? 0, inherited: true)
optionalDoubleRow("Frequency penalty", value: $overrides.frequencyPenalty, inheritedValue: inheritedSettings.frequencyPenalty ?? 0) OptionalDecimalSettingRow(title: "Frequency penalty", value: $overrides.frequencyPenalty, fallbackValue: inheritedSettings.frequencyPenalty ?? 0, inherited: true)
Text("Unset fields inherit from \(inheritedSource). The values shown are the effective starting values for this scene.") Text("Unset fields inherit from \(inheritedSource). The values shown are the effective starting values for this scene.")
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} }
}
private func optionalDoubleRow(_ title: String, value: Binding<Double?>, inheritedValue: Double) -> some View { private struct DecimalSettingRow: View {
let title: String
@Binding var value: Double
@State private var text: String
init(title: String, value: Binding<Double>) {
self.title = title
self._value = value
self._text = State(initialValue: NumericFieldFormatting.doubleString(value.wrappedValue))
}
var body: some View {
HStack { HStack {
Text(title) Text(title)
Spacer() Spacer()
TextField(title, value: Binding( TextField("", text: $text)
get: { value.wrappedValue ?? inheritedValue },
set: { value.wrappedValue = $0 }
), format: generationDoubleFormat)
.multilineTextAlignment(.trailing) .multilineTextAlignment(.trailing)
.frame(width: 90) .frame(width: 90)
if value.wrappedValue == nil { .onChange(of: text) {
if let parsed = NumericFieldFormatting.parseDouble(text) {
value = parsed
}
}
.onChange(of: value) {
let formatted = NumericFieldFormatting.doubleString(value)
if text != formatted {
text = formatted
}
}
}
}
}
private struct IntegerSettingRow: View {
let title: String
@Binding var value: Int
@State private var text: String
init(title: String, value: Binding<Int>) {
self.title = title
self._value = value
self._text = State(initialValue: NumericFieldFormatting.intString(value.wrappedValue))
}
var body: some View {
HStack {
Text(title)
Spacer()
TextField("", text: $text)
.multilineTextAlignment(.trailing)
.frame(width: 90)
.onChange(of: text) {
if let parsed = NumericFieldFormatting.parseInt(text) {
value = parsed
}
}
.onChange(of: value) {
let formatted = NumericFieldFormatting.intString(value)
if text != formatted {
text = formatted
}
}
}
}
}
private struct OptionalDecimalSettingRow: View {
let title: String
@Binding var value: Double?
let fallbackValue: Double
var inherited = false
@State private var text: String
init(title: String, value: Binding<Double?>, fallbackValue: Double, inherited: Bool = false) {
self.title = title
self._value = value
self.fallbackValue = fallbackValue
self.inherited = inherited
self._text = State(initialValue: NumericFieldFormatting.doubleString(value.wrappedValue ?? fallbackValue))
}
var body: some View {
HStack {
Text(title)
Spacer()
TextField("", text: $text)
.multilineTextAlignment(.trailing)
.frame(width: 90)
.onChange(of: text) {
if let parsed = NumericFieldFormatting.parseDouble(text) {
value = parsed
}
}
.onChange(of: value) {
syncText()
}
.onChange(of: fallbackValue) {
if value == nil {
syncText()
}
}
if inherited && value == nil {
Text("Inherited") Text("Inherited")
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} }
Button(value.wrappedValue == nil ? "Override" : "Clear") { Button(value == nil ? "Override" : "Clear") {
if value.wrappedValue == nil { if value == nil {
value.wrappedValue = inheritedValue value = fallbackValue
} else { } else {
value.wrappedValue = nil value = nil
} }
syncText()
} }
.buttonStyle(.link) .buttonStyle(.link)
} }
} }
private func optionalIntRow(_ title: String, value: Binding<Int?>, inheritedValue: Int) -> some View { private func syncText() {
let formatted = NumericFieldFormatting.doubleString(value ?? fallbackValue)
if text != formatted {
text = formatted
}
}
}
private struct OptionalIntegerSettingRow: View {
let title: String
@Binding var value: Int?
let fallbackValue: Int
var inherited = false
@State private var text: String
init(title: String, value: Binding<Int?>, fallbackValue: Int, inherited: Bool = false) {
self.title = title
self._value = value
self.fallbackValue = fallbackValue
self.inherited = inherited
self._text = State(initialValue: NumericFieldFormatting.intString(value.wrappedValue ?? fallbackValue))
}
var body: some View {
HStack { HStack {
Text(title) Text(title)
Spacer() Spacer()
TextField(title, value: Binding( TextField("", text: $text)
get: { value.wrappedValue ?? inheritedValue },
set: { value.wrappedValue = $0 }
), format: generationIntegerFormat)
.multilineTextAlignment(.trailing) .multilineTextAlignment(.trailing)
.frame(width: 90) .frame(width: 90)
if value.wrappedValue == nil { .onChange(of: text) {
if let parsed = NumericFieldFormatting.parseInt(text) {
value = parsed
}
}
.onChange(of: value) {
syncText()
}
.onChange(of: fallbackValue) {
if value == nil {
syncText()
}
}
if inherited && value == nil {
Text("Inherited") Text("Inherited")
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} }
Button(value.wrappedValue == nil ? "Override" : "Clear") { Button(value == nil ? "Override" : "Clear") {
if value.wrappedValue == nil { if value == nil {
value.wrappedValue = inheritedValue value = fallbackValue
} else { } else {
value.wrappedValue = nil value = nil
} }
syncText()
} }
.buttonStyle(.link) .buttonStyle(.link)
} }
} }
private func syncText() {
let formatted = NumericFieldFormatting.intString(value ?? fallbackValue)
if text != formatted {
text = formatted
}
}
}
private enum NumericFieldFormatting {
static func parseDouble(_ text: String) -> Double? {
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return nil }
return Double(trimmed.replacingOccurrences(of: ",", with: "."))
}
static func parseInt(_ text: String) -> Int? {
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return nil }
return Int(trimmed)
}
static func doubleString(_ value: Double) -> String {
if value.rounded() == value {
return String(Int(value))
}
return String(value)
}
static func intString(_ value: Int) -> String {
String(value)
}
} }