SHA256
Add Preset System
This commit is contained in:
7 files changed
+931
-151
No files matched your search
+419
-57
@@ -21,6 +21,13 @@ internal static class RenderConfigWindow
|
||||
{
|
||||
private static O5Window? _configWindow;
|
||||
|
||||
// Presets controls
|
||||
private static O5Dropdown<string>? _presetDropdown;
|
||||
private static O5InputField? _presetNameInput;
|
||||
private static O5Button? _savePresetButton;
|
||||
private static O5Button? _deletePresetButton;
|
||||
private static string? _lastLoadedPresetName;
|
||||
|
||||
// Controls cache for validation & sync
|
||||
private static O5Slider? _renderFpsSlider;
|
||||
private static O5Slider? _videoFPSSlider;
|
||||
@@ -89,6 +96,10 @@ internal static class RenderConfigWindow
|
||||
|
||||
BuildUI(_configWindow.Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReloadPresetDropdown(GlobalSettings.Current.LastPresetName);
|
||||
}
|
||||
|
||||
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
|
||||
var config = RenderManager.Instance.Configuration ??= new RenderConfig();
|
||||
@@ -133,7 +144,117 @@ internal static class RenderConfigWindow
|
||||
864, 960, 1536, 2048, 3072 // 4:3
|
||||
};
|
||||
|
||||
// TODO: Presets
|
||||
// Presets (Collapsible Card)
|
||||
var (_, presetContent) = O5Factory.Card(
|
||||
ctx, scrollContent,
|
||||
LocalizationManager.Get("ui.render_config.presets"),
|
||||
activeValue: true,
|
||||
onActiveChanged: null,
|
||||
onDeleteClick: null,
|
||||
showDeleteButton: false,
|
||||
showActiveToggle: false
|
||||
);
|
||||
|
||||
var presets = PresetManager.GetPresets();
|
||||
var presetNames = presets.Select(p => p.Name).ToList();
|
||||
var initialPresetName = GlobalSettings.Current.LastPresetName;
|
||||
if (string.IsNullOrEmpty(initialPresetName) || !presetNames.Contains(initialPresetName))
|
||||
{
|
||||
initialPresetName = presetNames.FirstOrDefault(n => n.StartsWith("QHD", StringComparison.OrdinalIgnoreCase))
|
||||
?? (presetNames.Count > 0 ? presetNames[0] : "");
|
||||
}
|
||||
_lastLoadedPresetName = initialPresetName;
|
||||
|
||||
if (config.RenderFPS <= 0)
|
||||
{
|
||||
var initialPreset = presets.FirstOrDefault(p => string.Equals(p.Name, initialPresetName, StringComparison.OrdinalIgnoreCase)) ?? presets.FirstOrDefault();
|
||||
if (initialPreset != null)
|
||||
{
|
||||
config.CopyFrom(initialPreset.Config);
|
||||
}
|
||||
}
|
||||
EnsureDefaultConfig(config);
|
||||
|
||||
_presetDropdown = CreateDropdownField(
|
||||
ctx, presetContent,
|
||||
LocalizationManager.Get("ui.render_config.preset_select"),
|
||||
initialPresetName, initialPresetName,
|
||||
presetNames, p => p,
|
||||
"dd_presets",
|
||||
selectedName =>
|
||||
{
|
||||
OnPresetSelected(selectedName, config);
|
||||
}
|
||||
);
|
||||
|
||||
var actionsRowObj = new GameObject("PresetActionsRow");
|
||||
actionsRowObj.transform.SetParent(presetContent, false);
|
||||
var actionsRowRect = actionsRowObj.AddComponent<RectTransform>();
|
||||
var actionsHLayout = actionsRowObj.AddComponent<HorizontalLayoutGroup>();
|
||||
actionsHLayout.spacing = 8f;
|
||||
actionsHLayout.childAlignment = TextAnchor.MiddleCenter;
|
||||
actionsHLayout.childControlWidth = true;
|
||||
actionsHLayout.childControlHeight = true;
|
||||
actionsHLayout.childForceExpandWidth = false;
|
||||
actionsHLayout.childForceExpandHeight = false;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
var actionsRowLE = actionsRowObj.AddComponent<LayoutElement>();
|
||||
actionsRowLE.preferredHeight = 40f;
|
||||
actionsRowLE.flexibleWidth = 1f;
|
||||
|
||||
_presetNameInput = O5Factory.Input(
|
||||
ctx: ctx,
|
||||
parent: actionsRowRect,
|
||||
defaultValue: "",
|
||||
value: initialPresetName,
|
||||
onChanged: null,
|
||||
placeholder: LocalizationManager.Get("ui.render_config.preset_name_placeholder"),
|
||||
icon: null,
|
||||
id: "input_preset_name"
|
||||
);
|
||||
var inputLE = _presetNameInput.Rect.GetComponent<LayoutElement>() ?? _presetNameInput.Rect.gameObject.AddComponent<LayoutElement>();
|
||||
inputLE.flexibleWidth = 1f;
|
||||
inputLE.preferredHeight = 40f;
|
||||
|
||||
_savePresetButton = O5Factory.Button(
|
||||
ctx: ctx,
|
||||
parent: actionsRowRect,
|
||||
onClick: () => OnSavePresetClicked(config),
|
||||
text: LocalizationManager.Get("ui.render_config.preset_save"),
|
||||
id: "btn_preset_save",
|
||||
height: 40f
|
||||
);
|
||||
var saveLE = _savePresetButton.Rect.GetComponent<LayoutElement>() ?? _savePresetButton.Rect.gameObject.AddComponent<LayoutElement>();
|
||||
saveLE.preferredWidth = 90f;
|
||||
saveLE.flexibleWidth = 0f;
|
||||
saveLE.preferredHeight = 40f;
|
||||
|
||||
var redTheme = ctx.Theme with
|
||||
{
|
||||
ObjectButton = ctx.Theme.SoftRed,
|
||||
ButtonHover = ctx.Theme.SoftRed * 0.8f
|
||||
};
|
||||
var redCtx = new O5Context(
|
||||
config: ctx.Config,
|
||||
theme: redTheme,
|
||||
fonts: ctx.Fonts,
|
||||
tween: ctx.Tween
|
||||
);
|
||||
_deletePresetButton = O5Factory.Button(
|
||||
ctx: redCtx,
|
||||
parent: actionsRowRect,
|
||||
onClick: () => OnDeletePresetClicked(config),
|
||||
text: LocalizationManager.Get("ui.render_config.preset_delete"),
|
||||
id: "btn_preset_delete",
|
||||
height: 40f
|
||||
);
|
||||
var deleteLE = _deletePresetButton.Rect.GetComponent<LayoutElement>() ?? _deletePresetButton.Rect.gameObject.AddComponent<LayoutElement>();
|
||||
deleteLE.preferredWidth = 90f;
|
||||
deleteLE.flexibleWidth = 0f;
|
||||
deleteLE.preferredHeight = 40f;
|
||||
|
||||
UpdateDeleteButtonState();
|
||||
|
||||
// 1-3. Top section: 좌/우 컨테이너 1개씩으로 3행을 쌓는다 (중앙선 1개)
|
||||
var (topLeft, topRight) = CreateTwoColumnPanel(scrollContent, spacing: 8f, columnSpacing: 10f);
|
||||
@@ -144,7 +265,7 @@ internal static class RenderConfigWindow
|
||||
format: "F3", clampMode: ClampMode.All,
|
||||
|
||||
sliderFilter: value => Snap(renderFpsSnap, value),
|
||||
inputFilter: null, onComplete: null, onChanged: val => { config.RenderFPS = val; },
|
||||
inputFilter: null, onComplete: null, onChanged: val => { config.RenderFPS = val; MarkConfigModified(); },
|
||||
text: LocalizationManager.Get("ui.render_config.render_fps"),
|
||||
id: "slider_render_fps", showFill: true
|
||||
);
|
||||
@@ -155,7 +276,7 @@ internal static class RenderConfigWindow
|
||||
format: "F3", clampMode: ClampMode.All,
|
||||
|
||||
sliderFilter: value => Snap(videoFpsSnap, value),
|
||||
inputFilter: null, onComplete: null, onChanged: val => { config.VideoFPS = val; },
|
||||
inputFilter: null, onComplete: null, onChanged: val => { config.VideoFPS = val; MarkConfigModified(); },
|
||||
text: LocalizationManager.Get("ui.render_config.video_fps"),
|
||||
id: "slider_video_fps", showFill: true
|
||||
);
|
||||
@@ -166,7 +287,7 @@ internal static class RenderConfigWindow
|
||||
format: "F0", clampMode: ClampMode.All,
|
||||
|
||||
sliderFilter: value => Snap(renderWidthSnap, value), inputFilter: value => Math.Max(value, 2),
|
||||
onComplete: null, onChanged: val => { config.RenderWidth = (int)Math.Round(val); },
|
||||
onComplete: null, onChanged: val => { config.RenderWidth = (int)Math.Round(val); MarkConfigModified(); },
|
||||
text: LocalizationManager.Get("ui.render_config.render_width"),
|
||||
id: "slider_render_width", showFill: true
|
||||
);
|
||||
@@ -177,7 +298,7 @@ internal static class RenderConfigWindow
|
||||
format: "F0", clampMode: ClampMode.All,
|
||||
|
||||
sliderFilter: value => Snap(renderHeightSnap, value), inputFilter: value => Math.Max(value, 2),
|
||||
onComplete: null, onChanged: val => { config.RenderHeight = (int)Math.Round(val); },
|
||||
onComplete: null, onChanged: val => { config.RenderHeight = (int)Math.Round(val); MarkConfigModified(); },
|
||||
text: LocalizationManager.Get("ui.render_config.render_height"),
|
||||
id: "slider_render_height", showFill: true
|
||||
);
|
||||
@@ -188,7 +309,7 @@ internal static class RenderConfigWindow
|
||||
format: "F3", clampMode: ClampMode.All,
|
||||
|
||||
sliderFilter: null, inputFilter: null,
|
||||
onComplete: null, onChanged: val => { config.DelayAfterEnd = val; },
|
||||
onComplete: null, onChanged: val => { config.DelayAfterEnd = val; MarkConfigModified(); },
|
||||
text: LocalizationManager.Get("ui.render_config.delay_after_end"),
|
||||
id: "slider_delay_after_end", showFill: true
|
||||
);
|
||||
@@ -198,7 +319,7 @@ internal static class RenderConfigWindow
|
||||
false, config.ShowJudgementText,
|
||||
LocalizationManager.Get("ui.render_config.show_judgement"),
|
||||
"toggle_show_judgement",
|
||||
val => config.ShowJudgementText = val,
|
||||
val => { config.ShowJudgementText = val; MarkConfigModified(); },
|
||||
generateLabel: false
|
||||
);
|
||||
|
||||
@@ -225,6 +346,7 @@ internal static class RenderConfigWindow
|
||||
{
|
||||
config.VideoConfig.Codec = c;
|
||||
UpdateVideoCodecUI(c, config);
|
||||
MarkConfigModified();
|
||||
});
|
||||
|
||||
_bitrateInput = CreateInputField(
|
||||
@@ -233,7 +355,7 @@ internal static class RenderConfigWindow
|
||||
"30000", config.VideoConfig.Bitrate.ToString(),
|
||||
"input_bitrate", out _bitrateLabel,
|
||||
TMPro.TMP_InputField.CharacterValidation.Integer,
|
||||
val => { if (int.TryParse(val, out var b) && b > 0) config.VideoConfig.Bitrate = b; }
|
||||
val => { if (int.TryParse(val, out var b) && b > 0) config.VideoConfig.Bitrate = b; MarkConfigModified(); }
|
||||
);
|
||||
|
||||
_qpInput = CreateInputField(
|
||||
@@ -242,7 +364,7 @@ internal static class RenderConfigWindow
|
||||
"18", config.VideoConfig.QP.ToString(),
|
||||
"input_qp", out _qpLabel,
|
||||
TMPro.TMP_InputField.CharacterValidation.Integer,
|
||||
val => { if (int.TryParse(val, out var qp) && qp >= 0) config.VideoConfig.QP = qp; }
|
||||
val => { if (int.TryParse(val, out var qp) && qp >= 0) config.VideoConfig.QP = qp; MarkConfigModified(); }
|
||||
);
|
||||
|
||||
var rateModes = (RateControlMode[])Enum.GetValues(typeof(RateControlMode));
|
||||
@@ -256,6 +378,7 @@ internal static class RenderConfigWindow
|
||||
{
|
||||
config.VideoConfig.RateControlMode = m;
|
||||
UpdateRateControlUI(m);
|
||||
MarkConfigModified();
|
||||
}
|
||||
);
|
||||
|
||||
@@ -265,7 +388,7 @@ internal static class RenderConfigWindow
|
||||
"50000", config.VideoConfig.MaxBitrate.ToString(),
|
||||
"input_max_bitrate", out _maxBitrateLabel,
|
||||
TMPro.TMP_InputField.CharacterValidation.Integer,
|
||||
val => { if (int.TryParse(val, out var mb) && mb > 0) config.VideoConfig.MaxBitrate = mb; }
|
||||
val => { if (int.TryParse(val, out var mb) && mb > 0) config.VideoConfig.MaxBitrate = mb; MarkConfigModified(); }
|
||||
);
|
||||
|
||||
_forceSoftwareToggle = CreateToggleField(
|
||||
@@ -273,7 +396,7 @@ internal static class RenderConfigWindow
|
||||
false, config.VideoConfig.ForceSoftwareEncoder,
|
||||
LocalizationManager.Get("ui.render_config.force_software"),
|
||||
"toggle_force_software",
|
||||
val => config.VideoConfig.ForceSoftwareEncoder = val,
|
||||
val => { config.VideoConfig.ForceSoftwareEncoder = val; MarkConfigModified(); },
|
||||
generateLabel: true
|
||||
);
|
||||
|
||||
@@ -283,7 +406,7 @@ internal static class RenderConfigWindow
|
||||
format: "F1", clampMode: ClampMode.All,
|
||||
|
||||
sliderFilter: null, inputFilter: null,
|
||||
onComplete: null, onChanged: val => { config.VideoConfig.KeyframeInterval = val; },
|
||||
onComplete: null, onChanged: val => { config.VideoConfig.KeyframeInterval = val; MarkConfigModified(); },
|
||||
text: LocalizationManager.Get("ui.render_config.keyframe_interval"),
|
||||
id: "slider_keyframe_interval", showFill: true
|
||||
);
|
||||
@@ -305,7 +428,7 @@ internal static class RenderConfigWindow
|
||||
true, config.AudioConfig.RenderAudio,
|
||||
LocalizationManager.Get("ui.render_config.render_audio"),
|
||||
"toggle_render_audio",
|
||||
val => config.AudioConfig.RenderAudio = val,
|
||||
val => { config.AudioConfig.RenderAudio = val; MarkConfigModified(); },
|
||||
generateLabel: false
|
||||
);
|
||||
|
||||
@@ -315,7 +438,7 @@ internal static class RenderConfigWindow
|
||||
format: "F0", clampMode: ClampMode.All,
|
||||
|
||||
sliderFilter: value => Snap(audioBitrateSnap, value),
|
||||
inputFilter: null, onComplete: null, onChanged: val => { config.AudioConfig.AudioBitrate = (int)Math.Round(val) * 1000; },
|
||||
inputFilter: null, onComplete: null, onChanged: val => { config.AudioConfig.AudioBitrate = (int)Math.Round(val) * 1000; MarkConfigModified(); },
|
||||
text: LocalizationManager.Get("ui.render_config.audio_bitrate"),
|
||||
id: "slider_audio_bitrate", showFill: true
|
||||
);
|
||||
@@ -327,7 +450,7 @@ internal static class RenderConfigWindow
|
||||
2, config.AudioConfig.AudioChannels,
|
||||
channels, c => c == 1 ? "1 (Mono)" : "2 (Stereo)",
|
||||
"dd_channels",
|
||||
c => config.AudioConfig.AudioChannels = c
|
||||
c => { config.AudioConfig.AudioChannels = c; MarkConfigModified(); }
|
||||
);
|
||||
|
||||
_sampleRateDropdown = CreateDropdownField(
|
||||
@@ -336,7 +459,7 @@ internal static class RenderConfigWindow
|
||||
48000, config.AudioConfig.AudioSampleRate,
|
||||
CodecUtil.AvailableSampleRate[CodecUtil.AudioCodecMatch[config.VideoConfig.Codec]], r => $"{r/1000.0} kHz",
|
||||
"dd_sample_rate",
|
||||
r => config.AudioConfig.AudioSampleRate = r
|
||||
r => { config.AudioConfig.AudioSampleRate = r; MarkConfigModified(); }
|
||||
);
|
||||
|
||||
// 6. Global Settings (Collapsible Card)
|
||||
@@ -425,7 +548,11 @@ internal static class RenderConfigWindow
|
||||
"mkv", config.AdvancedConfig.FileExtension,
|
||||
extensions, e => e,
|
||||
"dd_adv_file_extension",
|
||||
e => { if (!string.IsNullOrEmpty(e)) config.AdvancedConfig.FileExtension = e; }
|
||||
e =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e)) config.AdvancedConfig.FileExtension = e;
|
||||
MarkConfigModified();
|
||||
}
|
||||
);
|
||||
|
||||
_processAudioToggle = CreateToggleField(
|
||||
@@ -433,7 +560,11 @@ internal static class RenderConfigWindow
|
||||
true, config.AdvancedConfig.ProcessAudio,
|
||||
LocalizationManager.Get("ui.render_config.process_audio"),
|
||||
"toggle_process_audio",
|
||||
val => config.AdvancedConfig.ProcessAudio = val,
|
||||
val =>
|
||||
{
|
||||
config.AdvancedConfig.ProcessAudio = val;
|
||||
MarkConfigModified();
|
||||
},
|
||||
generateLabel: false
|
||||
);
|
||||
|
||||
@@ -447,6 +578,7 @@ internal static class RenderConfigWindow
|
||||
{
|
||||
if (int.TryParse(val, out var s)) config.AdvancedConfig.RandomSeed = s;
|
||||
else if (string.IsNullOrWhiteSpace(val)) config.AdvancedConfig.RandomSeed = null;
|
||||
MarkConfigModified();
|
||||
}
|
||||
);
|
||||
|
||||
@@ -455,7 +587,11 @@ internal static class RenderConfigWindow
|
||||
false, config.AdvancedConfig.NonTile,
|
||||
LocalizationManager.Get("ui.render_config.non_tile"),
|
||||
"toggle_non_tile",
|
||||
val => config.AdvancedConfig.NonTile = val,
|
||||
val =>
|
||||
{
|
||||
config.AdvancedConfig.NonTile = val;
|
||||
MarkConfigModified();
|
||||
},
|
||||
generateLabel: false
|
||||
);
|
||||
|
||||
@@ -482,6 +618,7 @@ internal static class RenderConfigWindow
|
||||
_firePlanetPicker?.SetBlocked(!val);
|
||||
config.AdvancedConfig.firePlanetColor = val ? _firePlanetPicker?.Value : null;
|
||||
if (!val) _firePlanetPicker?.SetExpanded(false);
|
||||
MarkConfigModified();
|
||||
},
|
||||
generateLabel: false
|
||||
);
|
||||
@@ -493,7 +630,10 @@ internal static class RenderConfigWindow
|
||||
val =>
|
||||
{
|
||||
if (_firePlanetToggle?.Value == true)
|
||||
{
|
||||
config.AdvancedConfig.firePlanetColor = val;
|
||||
MarkConfigModified();
|
||||
}
|
||||
}
|
||||
);
|
||||
if (!config.AdvancedConfig.firePlanetColor.HasValue)
|
||||
@@ -512,6 +652,7 @@ internal static class RenderConfigWindow
|
||||
_icePlanetPicker?.SetBlocked(!val);
|
||||
config.AdvancedConfig.icePlanetColor = val ? _icePlanetPicker?.Value : null;
|
||||
if (!val) _icePlanetPicker?.SetExpanded(false);
|
||||
MarkConfigModified();
|
||||
},
|
||||
generateLabel: false
|
||||
);
|
||||
@@ -523,7 +664,10 @@ internal static class RenderConfigWindow
|
||||
val =>
|
||||
{
|
||||
if (_icePlanetToggle?.Value == true)
|
||||
{
|
||||
config.AdvancedConfig.icePlanetColor = val;
|
||||
MarkConfigModified();
|
||||
}
|
||||
}
|
||||
);
|
||||
if (!config.AdvancedConfig.icePlanetColor.HasValue)
|
||||
@@ -542,6 +686,7 @@ internal static class RenderConfigWindow
|
||||
_windPlanetPicker?.SetBlocked(!val);
|
||||
config.AdvancedConfig.windPlanetColor = val ? _windPlanetPicker?.Value : null;
|
||||
if (!val) _windPlanetPicker?.SetExpanded(false);
|
||||
MarkConfigModified();
|
||||
},
|
||||
generateLabel: false
|
||||
);
|
||||
@@ -553,7 +698,10 @@ internal static class RenderConfigWindow
|
||||
val =>
|
||||
{
|
||||
if (_windPlanetToggle?.Value == true)
|
||||
{
|
||||
config.AdvancedConfig.windPlanetColor = val;
|
||||
MarkConfigModified();
|
||||
}
|
||||
}
|
||||
);
|
||||
if (!config.AdvancedConfig.windPlanetColor.HasValue)
|
||||
@@ -647,49 +795,19 @@ internal static class RenderConfigWindow
|
||||
|
||||
UpdateVideoCodecUI(config.VideoConfig.Codec, config);
|
||||
UpdateRateControlUI(config.VideoConfig.RateControlMode, noAnimate: true);
|
||||
|
||||
if (!string.IsNullOrEmpty(GlobalSettings.Current.LastPresetName))
|
||||
{
|
||||
_presetDropdown?.Set(GlobalSettings.Current.LastPresetName, false);
|
||||
_lastLoadedPresetName = GlobalSettings.Current.LastPresetName;
|
||||
UpdateDeleteButtonState();
|
||||
}
|
||||
}
|
||||
|
||||
private static void TryGoRender()
|
||||
{
|
||||
var config = RenderManager.Instance.Configuration;
|
||||
|
||||
// Sync Video Config
|
||||
if (_bitrateInput != null && int.TryParse(_bitrateInput.Value, out var bitrate) && bitrate > 0)
|
||||
{
|
||||
config.VideoConfig.Bitrate = bitrate;
|
||||
}
|
||||
if (_maxBitrateInput != null && int.TryParse(_maxBitrateInput.Value, out var maxBitrate) && maxBitrate > 0)
|
||||
{
|
||||
config.VideoConfig.MaxBitrate = maxBitrate;
|
||||
}
|
||||
if (_qpInput != null && int.TryParse(_qpInput.Value, out var qp) && qp >= 0)
|
||||
{
|
||||
config.VideoConfig.QP = qp;
|
||||
}
|
||||
|
||||
// Sync Advanced Config
|
||||
if (_randomSeedInput != null)
|
||||
{
|
||||
if (int.TryParse(_randomSeedInput.Value, out var seed))
|
||||
{
|
||||
config.AdvancedConfig.RandomSeed = seed;
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(_randomSeedInput.Value))
|
||||
{
|
||||
config.AdvancedConfig.RandomSeed = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Sync Planet Colors
|
||||
config.AdvancedConfig.firePlanetColor = (_firePlanetToggle?.Value == true && _firePlanetPicker != null)
|
||||
? _firePlanetPicker.Value
|
||||
: null;
|
||||
config.AdvancedConfig.icePlanetColor = (_icePlanetToggle?.Value == true && _icePlanetPicker != null)
|
||||
? _icePlanetPicker.Value
|
||||
: null;
|
||||
config.AdvancedConfig.windPlanetColor = (_windPlanetToggle?.Value == true && _windPlanetPicker != null)
|
||||
? _windPlanetPicker.Value
|
||||
: null;
|
||||
SyncUItoConfig(config);
|
||||
|
||||
// Sync Output Directory
|
||||
if (_outputDirInput != null)
|
||||
@@ -725,6 +843,250 @@ internal static class RenderConfigWindow
|
||||
new RenderSession().Start(config, RenderManager.Instance.levelPath);
|
||||
}
|
||||
|
||||
private static void SyncUItoConfig(RenderConfig target)
|
||||
{
|
||||
if (_renderFpsSlider != null) target.RenderFPS = _renderFpsSlider.Value;
|
||||
if (_videoFPSSlider != null) target.VideoFPS = _videoFPSSlider.Value;
|
||||
if (_renderWidthSlider != null) target.RenderWidth = (int)Math.Round(_renderWidthSlider.Value);
|
||||
if (_renderHeightSlider != null) target.RenderHeight = (int)Math.Round(_renderHeightSlider.Value);
|
||||
if (_delayAfterEndSlider != null) target.DelayAfterEnd = _delayAfterEndSlider.Value;
|
||||
if (_showJudgementToggle != null) target.ShowJudgementText = _showJudgementToggle.Value;
|
||||
|
||||
if (_codecDropdown != null) target.VideoConfig.Codec = _codecDropdown.Value;
|
||||
if (_rateControlDropdown != null) target.VideoConfig.RateControlMode = _rateControlDropdown.Value;
|
||||
|
||||
if (_bitrateInput != null && int.TryParse(_bitrateInput.Value, out var bitrate) && bitrate > 0)
|
||||
{
|
||||
target.VideoConfig.Bitrate = bitrate;
|
||||
}
|
||||
if (_maxBitrateInput != null && int.TryParse(_maxBitrateInput.Value, out var maxBitrate) && maxBitrate > 0)
|
||||
{
|
||||
target.VideoConfig.MaxBitrate = maxBitrate;
|
||||
}
|
||||
if (_qpInput != null && int.TryParse(_qpInput.Value, out var qp) && qp >= 0)
|
||||
{
|
||||
target.VideoConfig.QP = qp;
|
||||
}
|
||||
if (_keyframeIntervalSlider != null) target.VideoConfig.KeyframeInterval = _keyframeIntervalSlider.Value;
|
||||
if (_forceSoftwareToggle != null) target.VideoConfig.ForceSoftwareEncoder = _forceSoftwareToggle.Value;
|
||||
|
||||
if (_renderAudioToggle != null) target.AudioConfig.RenderAudio = _renderAudioToggle.Value;
|
||||
if (_sampleRateDropdown != null) target.AudioConfig.AudioSampleRate = _sampleRateDropdown.Value;
|
||||
if (_channelsDropdown != null) target.AudioConfig.AudioChannels = _channelsDropdown.Value;
|
||||
if (_audioBitrateSlider != null) target.AudioConfig.AudioBitrate = (int)Math.Round(_audioBitrateSlider.Value) * 1000;
|
||||
|
||||
if (_fileExtensionDropdown != null && !string.IsNullOrEmpty(_fileExtensionDropdown.Value))
|
||||
target.AdvancedConfig.FileExtension = _fileExtensionDropdown.Value;
|
||||
|
||||
if (_randomSeedInput != null)
|
||||
{
|
||||
if (int.TryParse(_randomSeedInput.Value, out var seed))
|
||||
{
|
||||
target.AdvancedConfig.RandomSeed = seed;
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(_randomSeedInput.Value))
|
||||
{
|
||||
target.AdvancedConfig.RandomSeed = null;
|
||||
}
|
||||
}
|
||||
if (_processAudioToggle != null) target.AdvancedConfig.ProcessAudio = _processAudioToggle.Value;
|
||||
if (_nonTileToggle != null) target.AdvancedConfig.NonTile = _nonTileToggle.Value;
|
||||
|
||||
// Planet Colors
|
||||
target.AdvancedConfig.firePlanetColor = (_firePlanetToggle?.Value == true && _firePlanetPicker != null)
|
||||
? _firePlanetPicker.Value
|
||||
: null;
|
||||
target.AdvancedConfig.icePlanetColor = (_icePlanetToggle?.Value == true && _icePlanetPicker != null)
|
||||
? _icePlanetPicker.Value
|
||||
: null;
|
||||
target.AdvancedConfig.windPlanetColor = (_windPlanetToggle?.Value == true && _windPlanetPicker != null)
|
||||
? _windPlanetPicker.Value
|
||||
: null;
|
||||
}
|
||||
|
||||
private static string CustomPresetLabel => LocalizationManager.Get("ui.render_config.preset_custom");
|
||||
|
||||
private static void MarkConfigModified()
|
||||
{
|
||||
if (_presetDropdown == null) return;
|
||||
var customLabel = CustomPresetLabel;
|
||||
if (_presetDropdown.Value == customLabel) return;
|
||||
|
||||
var currentValues = _presetDropdown.Values;
|
||||
if (!currentValues.Contains(customLabel))
|
||||
{
|
||||
var list = new List<string>(currentValues);
|
||||
list.Insert(0, customLabel);
|
||||
_presetDropdown.SetValues(list);
|
||||
}
|
||||
|
||||
_presetDropdown.Set(customLabel, false);
|
||||
UpdateDeleteButtonState();
|
||||
}
|
||||
|
||||
private static void OnPresetSelected(string? selectedName, RenderConfig config)
|
||||
{
|
||||
if (string.IsNullOrEmpty(selectedName) || selectedName == CustomPresetLabel) return;
|
||||
var preset = PresetManager.GetPresets().FirstOrDefault(p => string.Equals(p.Name, selectedName, StringComparison.OrdinalIgnoreCase));
|
||||
if (preset == null) return;
|
||||
|
||||
GlobalSettings.Current.LastPresetName = preset.Name;
|
||||
GlobalSettings.Save();
|
||||
_lastLoadedPresetName = preset.Name;
|
||||
|
||||
config.CopyFrom(preset.Config);
|
||||
ApplyConfigToUI(config);
|
||||
|
||||
_presetNameInput?.Set(preset.Name, false);
|
||||
|
||||
if (_presetDropdown != null && _presetDropdown.Values.Contains(CustomPresetLabel))
|
||||
{
|
||||
var cleaned = _presetDropdown.Values.Where(v => v != CustomPresetLabel).ToList();
|
||||
_presetDropdown.SetValues(cleaned);
|
||||
_presetDropdown.Set(preset.Name, false);
|
||||
}
|
||||
|
||||
UpdateDeleteButtonState();
|
||||
}
|
||||
|
||||
private static void OnSavePresetClicked(RenderConfig config)
|
||||
{
|
||||
SyncUItoConfig(config);
|
||||
|
||||
var name = _presetNameInput?.Value?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(name) || name == CustomPresetLabel)
|
||||
{
|
||||
CommonWarningDialogUI.ShowDialog(
|
||||
LocalizationManager.Get("ui.render_config.validation_title"),
|
||||
LocalizationManager.Get("ui.render_config.preset_name_empty"),
|
||||
new DialogButton(LocalizationManager.Get("ui.render_config.confirm"), () => { })
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isCurrentPreset = !string.IsNullOrEmpty(_lastLoadedPresetName) &&
|
||||
string.Equals(_lastLoadedPresetName, name, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var existing = PresetManager.GetPresets().FirstOrDefault(p => string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase));
|
||||
if (existing != null && !isCurrentPreset)
|
||||
{
|
||||
CommonWarningDialogUI.ShowDialog(
|
||||
LocalizationManager.Get("ui.render_config.preset_overwrite_title"),
|
||||
LocalizationManager.Get("ui.render_config.preset_overwrite_desc", name),
|
||||
new DialogButton(
|
||||
LocalizationManager.Get("ui.render_config.confirm"),
|
||||
() => DoSavePreset(name, config)
|
||||
),
|
||||
new DialogButton(
|
||||
LocalizationManager.Get("ui.render_config.cancel"),
|
||||
() => { }
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoSavePreset(name, config);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoSavePreset(string name, RenderConfig config)
|
||||
{
|
||||
PresetManager.SavePreset(name, config);
|
||||
GlobalSettings.Current.LastPresetName = name;
|
||||
GlobalSettings.Save();
|
||||
_lastLoadedPresetName = name;
|
||||
ReloadPresetDropdown(selectName: name);
|
||||
}
|
||||
|
||||
private static void OnDeletePresetClicked(RenderConfig config)
|
||||
{
|
||||
var targetPresetName = _presetDropdown?.Value;
|
||||
if (string.IsNullOrWhiteSpace(targetPresetName) || targetPresetName == CustomPresetLabel)
|
||||
{
|
||||
targetPresetName = _lastLoadedPresetName;
|
||||
if (string.IsNullOrWhiteSpace(targetPresetName) || targetPresetName == CustomPresetLabel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var ctx = RendererUIManager.Context;
|
||||
CommonWarningDialogUI.ShowDialog(
|
||||
LocalizationManager.Get("ui.render_config.preset_delete_title"),
|
||||
LocalizationManager.Get("ui.render_config.preset_delete_desc", targetPresetName),
|
||||
new DialogButton(
|
||||
LocalizationManager.Get("ui.render_config.confirm"),
|
||||
() => DoDeletePreset(targetPresetName, config),
|
||||
ctx.Theme.SoftRed
|
||||
),
|
||||
new DialogButton(
|
||||
LocalizationManager.Get("ui.render_config.cancel"),
|
||||
() => { }
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static void DoDeletePreset(string name, RenderConfig config)
|
||||
{
|
||||
PresetManager.DeletePreset(name);
|
||||
var presets = PresetManager.GetPresets();
|
||||
var fallbackName = presets.Count > 0 ? presets[0].Name : "";
|
||||
GlobalSettings.Current.LastPresetName = fallbackName;
|
||||
GlobalSettings.Save();
|
||||
_lastLoadedPresetName = fallbackName;
|
||||
|
||||
ReloadPresetDropdown(selectName: fallbackName);
|
||||
|
||||
var fallbackPreset = presets.FirstOrDefault(p => string.Equals(p.Name, fallbackName, StringComparison.OrdinalIgnoreCase));
|
||||
if (fallbackPreset != null)
|
||||
{
|
||||
config.CopyFrom(fallbackPreset.Config);
|
||||
ApplyConfigToUI(config);
|
||||
_presetNameInput?.Set(fallbackPreset.Name, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReloadPresetDropdown(string? selectName = null)
|
||||
{
|
||||
var presets = PresetManager.GetPresets();
|
||||
var names = presets.Select(p => p.Name).ToList();
|
||||
if (names.Count == 0)
|
||||
{
|
||||
_presetDropdown?.SetValues(new List<string> { CustomPresetLabel });
|
||||
_presetDropdown?.Set(CustomPresetLabel, false);
|
||||
_lastLoadedPresetName = null;
|
||||
UpdateDeleteButtonState();
|
||||
return;
|
||||
}
|
||||
|
||||
_presetDropdown?.SetValues(names);
|
||||
|
||||
var targetName = selectName;
|
||||
if (string.IsNullOrEmpty(targetName) || !names.Contains(targetName))
|
||||
{
|
||||
targetName = names[0];
|
||||
}
|
||||
|
||||
_presetDropdown?.Set(targetName, false);
|
||||
_lastLoadedPresetName = targetName;
|
||||
UpdateDeleteButtonState();
|
||||
}
|
||||
|
||||
private static void UpdateDeleteButtonState(string? presetName = null)
|
||||
{
|
||||
var targetName = presetName ?? _presetDropdown?.Value;
|
||||
if (targetName == CustomPresetLabel)
|
||||
{
|
||||
targetName = _lastLoadedPresetName;
|
||||
}
|
||||
|
||||
bool canDelete = !string.IsNullOrEmpty(targetName) &&
|
||||
targetName != CustomPresetLabel &&
|
||||
PresetManager.GetPresets().Any(p => string.Equals(p.Name, targetName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
_deletePresetButton?.SetBlocked(!canDelete);
|
||||
}
|
||||
|
||||
private static void ShowValidationError(string message)
|
||||
{
|
||||
Melon<RenderMod>.Logger.Error(message);
|
||||
|
||||
Reference in new issue
Block a user