SHA256
Implement Dynamic Localization in RenderConfigWindow
This commit is contained in:
3 files changed
+415
-165
No files matched your search
@@ -23,7 +23,7 @@
|
|||||||
"ui.render_config.audio_encoding": "오디오 인코딩 설정",
|
"ui.render_config.audio_encoding": "오디오 인코딩 설정",
|
||||||
"ui.render_config.global_settings": "전역 설정",
|
"ui.render_config.global_settings": "전역 설정",
|
||||||
"ui.render_config.advanced_settings": "고급 설정",
|
"ui.render_config.advanced_settings": "고급 설정",
|
||||||
"ui.render_config.go_render": "렌더 시작",
|
"ui.render_config.go_render": "렌더링하러 가다",
|
||||||
"ui.render_config.codec": "코덱",
|
"ui.render_config.codec": "코덱",
|
||||||
"ui.render_config.rate_control": "비트레이트 제어 모드",
|
"ui.render_config.rate_control": "비트레이트 제어 모드",
|
||||||
"ui.render_config.bitrate": "비트레이트 (kbps)",
|
"ui.render_config.bitrate": "비트레이트 (kbps)",
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
using System;
|
||||||
|
using ADOFAIRenderer.Localization;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ADOFAIRenderer.UI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Component that binds a TextMeshProUGUI component to a localization key or dynamic string provider,
|
||||||
|
/// automatically updating the displayed text whenever the active language changes.
|
||||||
|
/// </summary>
|
||||||
|
internal class LocalizedText : MonoBehaviour
|
||||||
|
{
|
||||||
|
private TextMeshProUGUI? _textComponent;
|
||||||
|
private string? _key;
|
||||||
|
private Func<string>? _dynamicProvider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the localization key. Setting this will clear any dynamic provider.
|
||||||
|
/// </summary>
|
||||||
|
public string? Key
|
||||||
|
{
|
||||||
|
get => _key;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_key = value;
|
||||||
|
_dynamicProvider = null;
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a dynamic string provider function.
|
||||||
|
/// </summary>
|
||||||
|
public void SetDynamic(Func<string> provider)
|
||||||
|
{
|
||||||
|
_dynamicProvider = provider;
|
||||||
|
_key = null;
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
EnsureComponent();
|
||||||
|
LocalizationManager.OnLanguageChanged += HandleLanguageChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
LocalizationManager.OnLanguageChanged -= HandleLanguageChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleLanguageChanged(SystemLanguage language)
|
||||||
|
{
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureComponent()
|
||||||
|
{
|
||||||
|
if (_textComponent == null)
|
||||||
|
{
|
||||||
|
_textComponent = GetComponent<TextMeshProUGUI>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Refreshes the text using either the dynamic provider or the static localization key.
|
||||||
|
/// </summary>
|
||||||
|
public void Refresh()
|
||||||
|
{
|
||||||
|
EnsureComponent();
|
||||||
|
if (_textComponent == null) return;
|
||||||
|
|
||||||
|
if (_dynamicProvider != null)
|
||||||
|
{
|
||||||
|
_textComponent.text = _dynamicProvider();
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(_key))
|
||||||
|
{
|
||||||
|
_textComponent.text = LocalizationManager.Get(_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binds a TextMeshProUGUI component to a localization key.
|
||||||
|
/// </summary>
|
||||||
|
public static LocalizedText Bind(TextMeshProUGUI target, string key)
|
||||||
|
{
|
||||||
|
if (target == null) throw new ArgumentNullException(nameof(target));
|
||||||
|
var component = target.GetComponent<LocalizedText>() ?? target.gameObject.AddComponent<LocalizedText>();
|
||||||
|
component._textComponent = target;
|
||||||
|
component.Key = key;
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binds a TextMeshProUGUI component to a dynamic string provider function.
|
||||||
|
/// </summary>
|
||||||
|
public static LocalizedText Bind(TextMeshProUGUI target, Func<string> provider)
|
||||||
|
{
|
||||||
|
if (target == null) throw new ArgumentNullException(nameof(target));
|
||||||
|
var component = target.GetComponent<LocalizedText>() ?? target.gameObject.AddComponent<LocalizedText>();
|
||||||
|
component._textComponent = target;
|
||||||
|
component.SetDynamic(provider);
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
+302
-164
@@ -87,6 +87,10 @@ internal static class RenderConfigWindow
|
|||||||
Size = new Vector2(900, 600), Draggable = true, Resizable = true,
|
Size = new Vector2(900, 600), Draggable = true, Resizable = true,
|
||||||
ShowCloseButton = true
|
ShowCloseButton = true
|
||||||
});
|
});
|
||||||
|
if (_configWindow.TitleText != null)
|
||||||
|
{
|
||||||
|
LocalizedText.Bind(_configWindow.TitleText, "ui.render_config.window_title");
|
||||||
|
}
|
||||||
|
|
||||||
_configWindow.CloseRequested += win =>
|
_configWindow.CloseRequested += win =>
|
||||||
{
|
{
|
||||||
@@ -95,6 +99,7 @@ internal static class RenderConfigWindow
|
|||||||
};
|
};
|
||||||
|
|
||||||
BuildUI(_configWindow.Content);
|
BuildUI(_configWindow.Content);
|
||||||
|
LocalizationManager.OnLanguageChanged += OnLanguageChanged;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -145,14 +150,9 @@ internal static class RenderConfigWindow
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Presets (Collapsible Card)
|
// Presets (Collapsible Card)
|
||||||
var (_, presetContent) = O5Factory.Card(
|
var (_, presetContent) = CreateCard(
|
||||||
ctx, scrollContent,
|
ctx, scrollContent,
|
||||||
LocalizationManager.Get("ui.render_config.presets"),
|
"ui.render_config.presets"
|
||||||
activeValue: true,
|
|
||||||
onActiveChanged: null,
|
|
||||||
onDeleteClick: null,
|
|
||||||
showDeleteButton: false,
|
|
||||||
showActiveToggle: false
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var presets = PresetManager.GetPresets();
|
var presets = PresetManager.GetPresets();
|
||||||
@@ -177,7 +177,7 @@ internal static class RenderConfigWindow
|
|||||||
|
|
||||||
_presetDropdown = CreateDropdownField(
|
_presetDropdown = CreateDropdownField(
|
||||||
ctx, presetContent,
|
ctx, presetContent,
|
||||||
LocalizationManager.Get("ui.render_config.preset_select"),
|
"ui.render_config.preset_select",
|
||||||
initialPresetName, initialPresetName,
|
initialPresetName, initialPresetName,
|
||||||
presetNames, p => p,
|
presetNames, p => p,
|
||||||
"dd_presets",
|
"dd_presets",
|
||||||
@@ -213,18 +213,24 @@ internal static class RenderConfigWindow
|
|||||||
icon: null,
|
icon: null,
|
||||||
id: "input_preset_name"
|
id: "input_preset_name"
|
||||||
);
|
);
|
||||||
|
if (_presetNameInput.Placeholder != null)
|
||||||
|
{
|
||||||
|
LocalizedText.Bind(_presetNameInput.Placeholder, "ui.render_config.preset_name_placeholder");
|
||||||
|
}
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
var inputLE = _presetNameInput.Rect.GetComponent<LayoutElement>() ?? _presetNameInput.Rect.gameObject.AddComponent<LayoutElement>();
|
var inputLE = _presetNameInput.Rect.GetComponent<LayoutElement>() ?? _presetNameInput.Rect.gameObject.AddComponent<LayoutElement>();
|
||||||
inputLE.flexibleWidth = 1f;
|
inputLE.flexibleWidth = 1f;
|
||||||
inputLE.preferredHeight = 40f;
|
inputLE.preferredHeight = 40f;
|
||||||
|
|
||||||
_savePresetButton = O5Factory.Button(
|
_savePresetButton = CreateButton(
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
parent: actionsRowRect,
|
parent: actionsRowRect,
|
||||||
onClick: () => OnSavePresetClicked(config),
|
textKey: "ui.render_config.preset_save",
|
||||||
text: LocalizationManager.Get("ui.render_config.preset_save"),
|
|
||||||
id: "btn_preset_save",
|
id: "btn_preset_save",
|
||||||
|
onClick: () => OnSavePresetClicked(config),
|
||||||
height: 40f
|
height: 40f
|
||||||
);
|
);
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
var saveLE = _savePresetButton.Rect.GetComponent<LayoutElement>() ?? _savePresetButton.Rect.gameObject.AddComponent<LayoutElement>();
|
var saveLE = _savePresetButton.Rect.GetComponent<LayoutElement>() ?? _savePresetButton.Rect.gameObject.AddComponent<LayoutElement>();
|
||||||
saveLE.preferredWidth = 90f;
|
saveLE.preferredWidth = 90f;
|
||||||
saveLE.flexibleWidth = 0f;
|
saveLE.flexibleWidth = 0f;
|
||||||
@@ -241,12 +247,12 @@ internal static class RenderConfigWindow
|
|||||||
fonts: ctx.Fonts,
|
fonts: ctx.Fonts,
|
||||||
tween: ctx.Tween
|
tween: ctx.Tween
|
||||||
);
|
);
|
||||||
_deletePresetButton = O5Factory.Button(
|
_deletePresetButton = CreateButton(
|
||||||
ctx: redCtx,
|
ctx: redCtx,
|
||||||
parent: actionsRowRect,
|
parent: actionsRowRect,
|
||||||
onClick: () => OnDeletePresetClicked(config),
|
textKey: "ui.render_config.preset_delete",
|
||||||
text: LocalizationManager.Get("ui.render_config.preset_delete"),
|
|
||||||
id: "btn_preset_delete",
|
id: "btn_preset_delete",
|
||||||
|
onClick: () => OnDeletePresetClicked(config),
|
||||||
height: 40f
|
height: 40f
|
||||||
);
|
);
|
||||||
var deleteLE = _deletePresetButton.Rect.GetComponent<LayoutElement>() ?? _deletePresetButton.Rect.gameObject.AddComponent<LayoutElement>();
|
var deleteLE = _deletePresetButton.Rect.GetComponent<LayoutElement>() ?? _deletePresetButton.Rect.gameObject.AddComponent<LayoutElement>();
|
||||||
@@ -259,86 +265,72 @@ internal static class RenderConfigWindow
|
|||||||
// 1-3. Top section: 좌/우 컨테이너 1개씩으로 3행을 쌓는다 (중앙선 1개)
|
// 1-3. Top section: 좌/우 컨테이너 1개씩으로 3행을 쌓는다 (중앙선 1개)
|
||||||
var (topLeft, topRight) = CreateTwoColumnPanel(scrollContent, spacing: 8f, columnSpacing: 10f);
|
var (topLeft, topRight) = CreateTwoColumnPanel(scrollContent, spacing: 8f, columnSpacing: 10f);
|
||||||
|
|
||||||
_renderFpsSlider = O5Factory.Slider(
|
_renderFpsSlider = CreateSlider(
|
||||||
ctx: ctx, parent: CreateFieldSlot(topLeft),
|
ctx: ctx, parent: CreateFieldSlot(topLeft),
|
||||||
|
labelKey: "ui.render_config.render_fps", id: "slider_render_fps",
|
||||||
defaultValue: 60, min: 0.01, max: 3000, value: 60,
|
defaultValue: 60, min: 0.01, max: 3000, value: 60,
|
||||||
format: "F3", clampMode: ClampMode.All,
|
format: "F3", clampMode: ClampMode.All,
|
||||||
|
|
||||||
sliderFilter: value => Snap(renderFpsSnap, value),
|
sliderFilter: value => Snap(renderFpsSnap, value),
|
||||||
inputFilter: null, onComplete: null, onChanged: val => { config.RenderFPS = val; MarkConfigModified(); },
|
onChanged: val => { config.RenderFPS = val; MarkConfigModified(); }
|
||||||
text: LocalizationManager.Get("ui.render_config.render_fps"),
|
|
||||||
id: "slider_render_fps", showFill: true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
_videoFPSSlider = O5Factory.Slider(
|
_videoFPSSlider = CreateSlider(
|
||||||
ctx: ctx, parent: CreateFieldSlot(topRight),
|
ctx: ctx, parent: CreateFieldSlot(topRight),
|
||||||
|
labelKey: "ui.render_config.video_fps", id: "slider_video_fps",
|
||||||
defaultValue: 60, min: 0.01, max: 600, value: 60,
|
defaultValue: 60, min: 0.01, max: 600, value: 60,
|
||||||
format: "F3", clampMode: ClampMode.All,
|
format: "F3", clampMode: ClampMode.All,
|
||||||
|
|
||||||
sliderFilter: value => Snap(videoFpsSnap, value),
|
sliderFilter: value => Snap(videoFpsSnap, value),
|
||||||
inputFilter: null, onComplete: null, onChanged: val => { config.VideoFPS = val; MarkConfigModified(); },
|
onChanged: val => { config.VideoFPS = val; MarkConfigModified(); }
|
||||||
text: LocalizationManager.Get("ui.render_config.video_fps"),
|
|
||||||
id: "slider_video_fps", showFill: true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
_renderWidthSlider = O5Factory.Slider(
|
_renderWidthSlider = CreateSlider(
|
||||||
ctx: ctx, parent: CreateFieldSlot(topLeft),
|
ctx: ctx, parent: CreateFieldSlot(topLeft),
|
||||||
|
labelKey: "ui.render_config.render_width", id: "slider_render_width",
|
||||||
defaultValue: 2560, min: 0, max: 15360, value: 2560,
|
defaultValue: 2560, min: 0, max: 15360, value: 2560,
|
||||||
format: "F0", clampMode: ClampMode.All,
|
format: "F0", clampMode: ClampMode.All,
|
||||||
|
|
||||||
sliderFilter: value => Snap(renderWidthSnap, value), inputFilter: value => Math.Max(value, 2),
|
sliderFilter: value => Snap(renderWidthSnap, value), inputFilter: value => Math.Max(value, 2),
|
||||||
onComplete: null, onChanged: val => { config.RenderWidth = (int)Math.Round(val); MarkConfigModified(); },
|
onChanged: val => { config.RenderWidth = (int)Math.Round(val); MarkConfigModified(); }
|
||||||
text: LocalizationManager.Get("ui.render_config.render_width"),
|
|
||||||
id: "slider_render_width", showFill: true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
_renderHeightSlider = O5Factory.Slider(
|
_renderHeightSlider = CreateSlider(
|
||||||
ctx: ctx, parent: CreateFieldSlot(topRight),
|
ctx: ctx, parent: CreateFieldSlot(topRight),
|
||||||
|
labelKey: "ui.render_config.render_height", id: "slider_render_height",
|
||||||
defaultValue: 1440, min: 0, max: 8640, value: 1440,
|
defaultValue: 1440, min: 0, max: 8640, value: 1440,
|
||||||
format: "F0", clampMode: ClampMode.All,
|
format: "F0", clampMode: ClampMode.All,
|
||||||
|
|
||||||
sliderFilter: value => Snap(renderHeightSnap, value), inputFilter: value => Math.Max(value, 2),
|
sliderFilter: value => Snap(renderHeightSnap, value), inputFilter: value => Math.Max(value, 2),
|
||||||
onComplete: null, onChanged: val => { config.RenderHeight = (int)Math.Round(val); MarkConfigModified(); },
|
onChanged: val => { config.RenderHeight = (int)Math.Round(val); MarkConfigModified(); }
|
||||||
text: LocalizationManager.Get("ui.render_config.render_height"),
|
|
||||||
id: "slider_render_height", showFill: true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
_delayAfterEndSlider = O5Factory.Slider(
|
_delayAfterEndSlider = CreateSlider(
|
||||||
ctx: ctx, parent: CreateFieldSlot(topLeft),
|
ctx: ctx, parent: CreateFieldSlot(topLeft),
|
||||||
|
labelKey: "ui.render_config.delay_after_end", id: "slider_delay_after_end",
|
||||||
defaultValue: 15, min: 0, max: 9999.999, value: 15,
|
defaultValue: 15, min: 0, max: 9999.999, value: 15,
|
||||||
format: "F3", clampMode: ClampMode.All,
|
format: "F3", clampMode: ClampMode.All,
|
||||||
|
onChanged: val => { config.DelayAfterEnd = val; MarkConfigModified(); }
|
||||||
sliderFilter: null, inputFilter: null,
|
|
||||||
onComplete: null, onChanged: val => { config.DelayAfterEnd = val; MarkConfigModified(); },
|
|
||||||
text: LocalizationManager.Get("ui.render_config.delay_after_end"),
|
|
||||||
id: "slider_delay_after_end", showFill: true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
_showJudgementToggle = CreateToggleField(
|
_showJudgementToggle = CreateToggleField(
|
||||||
ctx, CreateFieldSlot(topRight), "",
|
ctx, CreateFieldSlot(topRight),
|
||||||
false, config.ShowJudgementText,
|
labelKey: "",
|
||||||
LocalizationManager.Get("ui.render_config.show_judgement"),
|
defaultValue: false,
|
||||||
"toggle_show_judgement",
|
value: config.ShowJudgementText,
|
||||||
val => { config.ShowJudgementText = val; MarkConfigModified(); },
|
toggleTextKey: "ui.render_config.show_judgement",
|
||||||
|
id: "toggle_show_judgement",
|
||||||
|
onChanged: val => { config.ShowJudgementText = val; MarkConfigModified(); },
|
||||||
generateLabel: false
|
generateLabel: false
|
||||||
);
|
);
|
||||||
|
|
||||||
// 4. Video Encoding Config (Collapsible Card)
|
// 4. Video Encoding Config (Collapsible Card)
|
||||||
var (_, videoContent) = O5Factory.Card(
|
var (_, videoContent) = CreateCard(
|
||||||
ctx, scrollContent,
|
ctx, scrollContent,
|
||||||
LocalizationManager.Get("ui.render_config.video_encoding"),
|
"ui.render_config.video_encoding"
|
||||||
activeValue: true,
|
|
||||||
onActiveChanged: null,
|
|
||||||
onDeleteClick: null,
|
|
||||||
showDeleteButton: false,
|
|
||||||
showActiveToggle: false
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var (videoLeft, videoRight) = CreateTwoColumnPanel(videoContent);
|
var (videoLeft, videoRight) = CreateTwoColumnPanel(videoContent);
|
||||||
var codecs = (Codec[])Enum.GetValues(typeof(Codec));
|
var codecs = (Codec[])Enum.GetValues(typeof(Codec));
|
||||||
_codecDropdown = CreateDropdownField(
|
_codecDropdown = CreateDropdownField(
|
||||||
ctx, CreateFieldSlot(videoLeft),
|
ctx, CreateFieldSlot(videoLeft),
|
||||||
LocalizationManager.Get("ui.render_config.codec"),
|
"ui.render_config.codec",
|
||||||
Codec.H264, config.VideoConfig.Codec,
|
Codec.H264, config.VideoConfig.Codec,
|
||||||
codecs, c => c.ToString(),
|
codecs, c => c.ToString(),
|
||||||
"dd_video_codec",
|
"dd_video_codec",
|
||||||
@@ -351,7 +343,7 @@ internal static class RenderConfigWindow
|
|||||||
|
|
||||||
_bitrateInput = CreateInputField(
|
_bitrateInput = CreateInputField(
|
||||||
ctx, CreateFieldSlot(videoLeft),
|
ctx, CreateFieldSlot(videoLeft),
|
||||||
LocalizationManager.Get("ui.render_config.bitrate"),
|
"ui.render_config.bitrate",
|
||||||
"30000", config.VideoConfig.Bitrate.ToString(),
|
"30000", config.VideoConfig.Bitrate.ToString(),
|
||||||
"input_bitrate", out _bitrateLabel,
|
"input_bitrate", out _bitrateLabel,
|
||||||
TMPro.TMP_InputField.CharacterValidation.Integer,
|
TMPro.TMP_InputField.CharacterValidation.Integer,
|
||||||
@@ -360,7 +352,7 @@ internal static class RenderConfigWindow
|
|||||||
|
|
||||||
_qpInput = CreateInputField(
|
_qpInput = CreateInputField(
|
||||||
ctx, CreateFieldSlot(videoLeft),
|
ctx, CreateFieldSlot(videoLeft),
|
||||||
LocalizationManager.Get("ui.render_config.qp"),
|
"ui.render_config.qp",
|
||||||
"18", config.VideoConfig.QP.ToString(),
|
"18", config.VideoConfig.QP.ToString(),
|
||||||
"input_qp", out _qpLabel,
|
"input_qp", out _qpLabel,
|
||||||
TMPro.TMP_InputField.CharacterValidation.Integer,
|
TMPro.TMP_InputField.CharacterValidation.Integer,
|
||||||
@@ -370,7 +362,7 @@ internal static class RenderConfigWindow
|
|||||||
var rateModes = (RateControlMode[])Enum.GetValues(typeof(RateControlMode));
|
var rateModes = (RateControlMode[])Enum.GetValues(typeof(RateControlMode));
|
||||||
_rateControlDropdown = CreateDropdownField(
|
_rateControlDropdown = CreateDropdownField(
|
||||||
ctx, CreateFieldSlot(videoRight),
|
ctx, CreateFieldSlot(videoRight),
|
||||||
LocalizationManager.Get("ui.render_config.rate_control"),
|
"ui.render_config.rate_control",
|
||||||
RateControlMode.CBR, config.VideoConfig.RateControlMode,
|
RateControlMode.CBR, config.VideoConfig.RateControlMode,
|
||||||
rateModes, m => m.ToString(),
|
rateModes, m => m.ToString(),
|
||||||
"dd_rate_control",
|
"dd_rate_control",
|
||||||
@@ -384,7 +376,7 @@ internal static class RenderConfigWindow
|
|||||||
|
|
||||||
_maxBitrateInput = CreateInputField(
|
_maxBitrateInput = CreateInputField(
|
||||||
ctx, CreateFieldSlot(videoRight),
|
ctx, CreateFieldSlot(videoRight),
|
||||||
LocalizationManager.Get("ui.render_config.max_bitrate"),
|
"ui.render_config.max_bitrate",
|
||||||
"50000", config.VideoConfig.MaxBitrate.ToString(),
|
"50000", config.VideoConfig.MaxBitrate.ToString(),
|
||||||
"input_max_bitrate", out _maxBitrateLabel,
|
"input_max_bitrate", out _maxBitrateLabel,
|
||||||
TMPro.TMP_InputField.CharacterValidation.Integer,
|
TMPro.TMP_InputField.CharacterValidation.Integer,
|
||||||
@@ -392,61 +384,55 @@ internal static class RenderConfigWindow
|
|||||||
);
|
);
|
||||||
|
|
||||||
_forceSoftwareToggle = CreateToggleField(
|
_forceSoftwareToggle = CreateToggleField(
|
||||||
ctx, CreateFieldSlot(videoRight), "",
|
ctx, CreateFieldSlot(videoRight),
|
||||||
false, config.VideoConfig.ForceSoftwareEncoder,
|
labelKey: "",
|
||||||
LocalizationManager.Get("ui.render_config.force_software"),
|
defaultValue: false,
|
||||||
"toggle_force_software",
|
value: config.VideoConfig.ForceSoftwareEncoder,
|
||||||
val => { config.VideoConfig.ForceSoftwareEncoder = val; MarkConfigModified(); },
|
toggleTextKey: "ui.render_config.force_software",
|
||||||
|
id: "toggle_force_software",
|
||||||
|
onChanged: val => { config.VideoConfig.ForceSoftwareEncoder = val; MarkConfigModified(); },
|
||||||
generateLabel: true
|
generateLabel: true
|
||||||
);
|
);
|
||||||
|
|
||||||
_keyframeIntervalSlider = O5Factory.Slider(
|
_keyframeIntervalSlider = CreateSlider(
|
||||||
ctx: ctx, parent: videoContent,
|
ctx: ctx, parent: videoContent,
|
||||||
|
labelKey: "ui.render_config.keyframe_interval", id: "slider_keyframe_interval",
|
||||||
defaultValue: 2, min: 0.1, max: 10, value: 2,
|
defaultValue: 2, min: 0.1, max: 10, value: 2,
|
||||||
format: "F1", clampMode: ClampMode.All,
|
format: "F1", clampMode: ClampMode.All,
|
||||||
|
onChanged: val => { config.VideoConfig.KeyframeInterval = val; MarkConfigModified(); }
|
||||||
sliderFilter: null, inputFilter: null,
|
|
||||||
onComplete: null, onChanged: val => { config.VideoConfig.KeyframeInterval = val; MarkConfigModified(); },
|
|
||||||
text: LocalizationManager.Get("ui.render_config.keyframe_interval"),
|
|
||||||
id: "slider_keyframe_interval", showFill: true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// 5. Audio Encoding Config (Collapsible Card)
|
// 5. Audio Encoding Config (Collapsible Card)
|
||||||
var (_, audioContent) = O5Factory.Card(
|
var (_, audioContent) = CreateCard(
|
||||||
ctx, scrollContent,
|
ctx, scrollContent,
|
||||||
LocalizationManager.Get("ui.render_config.audio_encoding"),
|
"ui.render_config.audio_encoding"
|
||||||
activeValue: true,
|
|
||||||
onActiveChanged: null,
|
|
||||||
onDeleteClick: null,
|
|
||||||
showDeleteButton: false,
|
|
||||||
showActiveToggle: false
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var (audioLeft, audioRight) = CreateTwoColumnPanel(audioContent);
|
var (audioLeft, audioRight) = CreateTwoColumnPanel(audioContent);
|
||||||
_renderAudioToggle = CreateToggleField(
|
_renderAudioToggle = CreateToggleField(
|
||||||
ctx, CreateFieldSlot(audioLeft), "",
|
ctx, CreateFieldSlot(audioLeft),
|
||||||
true, config.AudioConfig.RenderAudio,
|
labelKey: "",
|
||||||
LocalizationManager.Get("ui.render_config.render_audio"),
|
defaultValue: true,
|
||||||
"toggle_render_audio",
|
value: config.AudioConfig.RenderAudio,
|
||||||
val => { config.AudioConfig.RenderAudio = val; MarkConfigModified(); },
|
toggleTextKey: "ui.render_config.render_audio",
|
||||||
|
id: "toggle_render_audio",
|
||||||
|
onChanged: val => { config.AudioConfig.RenderAudio = val; MarkConfigModified(); },
|
||||||
generateLabel: false
|
generateLabel: false
|
||||||
);
|
);
|
||||||
|
|
||||||
_audioBitrateSlider = O5Factory.Slider(
|
_audioBitrateSlider = CreateSlider(
|
||||||
ctx: ctx, parent: CreateFieldSlot(audioRight),
|
ctx: ctx, parent: CreateFieldSlot(audioRight),
|
||||||
|
labelKey: "ui.render_config.audio_bitrate", id: "slider_audio_bitrate",
|
||||||
defaultValue: 256, min: 64, max: 384, value: 256,
|
defaultValue: 256, min: 64, max: 384, value: 256,
|
||||||
format: "F0", clampMode: ClampMode.All,
|
format: "F0", clampMode: ClampMode.All,
|
||||||
|
|
||||||
sliderFilter: value => Snap(audioBitrateSnap, value),
|
sliderFilter: value => Snap(audioBitrateSnap, value),
|
||||||
inputFilter: null, onComplete: null, onChanged: val => { config.AudioConfig.AudioBitrate = (int)Math.Round(val) * 1000; MarkConfigModified(); },
|
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
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var channels = new[] { 1, 2 };
|
var channels = new[] { 1, 2 };
|
||||||
_channelsDropdown = CreateDropdownField(
|
_channelsDropdown = CreateDropdownField(
|
||||||
ctx, CreateFieldSlot(audioLeft),
|
ctx, CreateFieldSlot(audioLeft),
|
||||||
LocalizationManager.Get("ui.render_config.channels"),
|
"ui.render_config.channels",
|
||||||
2, config.AudioConfig.AudioChannels,
|
2, config.AudioConfig.AudioChannels,
|
||||||
channels, c => c == 1 ? "1 (Mono)" : "2 (Stereo)",
|
channels, c => c == 1 ? "1 (Mono)" : "2 (Stereo)",
|
||||||
"dd_channels",
|
"dd_channels",
|
||||||
@@ -455,7 +441,7 @@ internal static class RenderConfigWindow
|
|||||||
|
|
||||||
_sampleRateDropdown = CreateDropdownField(
|
_sampleRateDropdown = CreateDropdownField(
|
||||||
ctx, CreateFieldSlot(audioRight),
|
ctx, CreateFieldSlot(audioRight),
|
||||||
LocalizationManager.Get("ui.render_config.sample_rate"),
|
"ui.render_config.sample_rate",
|
||||||
48000, config.AudioConfig.AudioSampleRate,
|
48000, config.AudioConfig.AudioSampleRate,
|
||||||
CodecUtil.AvailableSampleRate[CodecUtil.AudioCodecMatch[config.VideoConfig.Codec]], r => $"{r/1000.0} kHz",
|
CodecUtil.AvailableSampleRate[CodecUtil.AudioCodecMatch[config.VideoConfig.Codec]], r => $"{r/1000.0} kHz",
|
||||||
"dd_sample_rate",
|
"dd_sample_rate",
|
||||||
@@ -463,19 +449,14 @@ internal static class RenderConfigWindow
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 6. Global Settings (Collapsible Card)
|
// 6. Global Settings (Collapsible Card)
|
||||||
var (_, globalContent) = O5Factory.Card(
|
var (_, globalContent) = CreateCard(
|
||||||
ctx, scrollContent,
|
ctx, scrollContent,
|
||||||
LocalizationManager.Get("ui.render_config.global_settings"),
|
"ui.render_config.global_settings"
|
||||||
activeValue: true,
|
|
||||||
onActiveChanged: null,
|
|
||||||
onDeleteClick: null,
|
|
||||||
showDeleteButton: false,
|
|
||||||
showActiveToggle: false
|
|
||||||
);
|
);
|
||||||
|
|
||||||
_outputDirInput = CreateFullWidthInputField(
|
_outputDirInput = CreateFullWidthInputField(
|
||||||
ctx, globalContent,
|
ctx, globalContent,
|
||||||
LocalizationManager.Get("ui.render_config.output_dir"),
|
"ui.render_config.output_dir",
|
||||||
GlobalSettings.DefaultOutputDirectory,
|
GlobalSettings.DefaultOutputDirectory,
|
||||||
GlobalSettings.EffectiveOutputDirectory,
|
GlobalSettings.EffectiveOutputDirectory,
|
||||||
"input_output_dir",
|
"input_output_dir",
|
||||||
@@ -495,8 +476,10 @@ internal static class RenderConfigWindow
|
|||||||
);
|
);
|
||||||
|
|
||||||
var (globalLeft, globalRight) = CreateTwoColumnPanel(globalContent);
|
var (globalLeft, globalRight) = CreateTwoColumnPanel(globalContent);
|
||||||
O5Factory.Button(
|
CreateButton(
|
||||||
ctx, globalLeft,
|
ctx, globalLeft,
|
||||||
|
"ui.render_config.browse",
|
||||||
|
"btn_browse_output",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
var initial = string.IsNullOrWhiteSpace(_outputDirInput.Value)
|
var initial = string.IsNullOrWhiteSpace(_outputDirInput.Value)
|
||||||
@@ -512,39 +495,32 @@ internal static class RenderConfigWindow
|
|||||||
GlobalSettings.Save();
|
GlobalSettings.Save();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
LocalizationManager.Get("ui.render_config.browse"),
|
|
||||||
"btn_browse_output"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
O5Factory.Button(
|
CreateButton(
|
||||||
ctx, globalRight,
|
ctx, globalRight,
|
||||||
|
"ui.render_config.reset_default",
|
||||||
|
"btn_reset_output",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
_outputDirInput.Set(GlobalSettings.DefaultOutputDirectory);
|
_outputDirInput.Set(GlobalSettings.DefaultOutputDirectory);
|
||||||
GlobalSettings.Current.OutputDirectory = null;
|
GlobalSettings.Current.OutputDirectory = null;
|
||||||
GlobalSettings.Save();
|
GlobalSettings.Save();
|
||||||
},
|
}
|
||||||
LocalizationManager.Get("ui.render_config.reset_default"),
|
|
||||||
"btn_reset_output"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// 7. Advanced Settings (Collapsible Card)
|
// 7. Advanced Settings (Collapsible Card)
|
||||||
var (_, advContent) = O5Factory.Card(
|
var (_, advContent) = CreateCard(
|
||||||
ctx, scrollContent,
|
ctx, scrollContent,
|
||||||
LocalizationManager.Get("ui.render_config.advanced_settings"),
|
"ui.render_config.advanced_settings"
|
||||||
activeValue: true,
|
|
||||||
onActiveChanged: null,
|
|
||||||
onDeleteClick: null,
|
|
||||||
showDeleteButton: false,
|
|
||||||
showActiveToggle: false
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var (advLeft, advRight) = CreateTwoColumnPanel(advContent);
|
var (advLeft, advRight) = CreateTwoColumnPanel(advContent);
|
||||||
var extensions = new[] { "mkv", "mp4", "mov", "webm", "avi" };
|
var extensions = new[] { "mkv", "mp4", "mov", "webm", "avi" };
|
||||||
_fileExtensionDropdown = CreateDropdownField(
|
_fileExtensionDropdown = CreateDropdownField(
|
||||||
ctx, CreateFieldSlot(advLeft),
|
ctx, CreateFieldSlot(advLeft),
|
||||||
LocalizationManager.Get("ui.render_config.file_extension"),
|
"ui.render_config.file_extension",
|
||||||
"mkv", config.AdvancedConfig.FileExtension,
|
"mkv", config.AdvancedConfig.FileExtension,
|
||||||
extensions, e => e,
|
extensions, e => e,
|
||||||
"dd_adv_file_extension",
|
"dd_adv_file_extension",
|
||||||
@@ -556,11 +532,13 @@ internal static class RenderConfigWindow
|
|||||||
);
|
);
|
||||||
|
|
||||||
_processAudioToggle = CreateToggleField(
|
_processAudioToggle = CreateToggleField(
|
||||||
ctx, CreateFieldSlot(advLeft), "",
|
ctx, CreateFieldSlot(advLeft),
|
||||||
true, config.AdvancedConfig.ProcessAudio,
|
labelKey: "",
|
||||||
LocalizationManager.Get("ui.render_config.process_audio"),
|
defaultValue: true,
|
||||||
"toggle_process_audio",
|
value: config.AdvancedConfig.ProcessAudio,
|
||||||
val =>
|
toggleTextKey: "ui.render_config.process_audio",
|
||||||
|
id: "toggle_process_audio",
|
||||||
|
onChanged: val =>
|
||||||
{
|
{
|
||||||
config.AdvancedConfig.ProcessAudio = val;
|
config.AdvancedConfig.ProcessAudio = val;
|
||||||
MarkConfigModified();
|
MarkConfigModified();
|
||||||
@@ -570,7 +548,7 @@ internal static class RenderConfigWindow
|
|||||||
|
|
||||||
_randomSeedInput = CreateInputField(
|
_randomSeedInput = CreateInputField(
|
||||||
ctx, CreateFieldSlot(advRight),
|
ctx, CreateFieldSlot(advRight),
|
||||||
LocalizationManager.Get("ui.render_config.random_seed"),
|
"ui.render_config.random_seed",
|
||||||
"", config.AdvancedConfig.RandomSeed?.ToString() ?? "",
|
"", config.AdvancedConfig.RandomSeed?.ToString() ?? "",
|
||||||
"input_random_seed",
|
"input_random_seed",
|
||||||
TMPro.TMP_InputField.CharacterValidation.Integer,
|
TMPro.TMP_InputField.CharacterValidation.Integer,
|
||||||
@@ -583,11 +561,13 @@ internal static class RenderConfigWindow
|
|||||||
);
|
);
|
||||||
|
|
||||||
_nonTileToggle = CreateToggleField(
|
_nonTileToggle = CreateToggleField(
|
||||||
ctx, CreateFieldSlot(advRight), "",
|
ctx, CreateFieldSlot(advRight),
|
||||||
false, config.AdvancedConfig.NonTile,
|
labelKey: "",
|
||||||
LocalizationManager.Get("ui.render_config.non_tile"),
|
defaultValue: false,
|
||||||
"toggle_non_tile",
|
value: config.AdvancedConfig.NonTile,
|
||||||
val =>
|
toggleTextKey: "ui.render_config.non_tile",
|
||||||
|
id: "toggle_non_tile",
|
||||||
|
onChanged: val =>
|
||||||
{
|
{
|
||||||
config.AdvancedConfig.NonTile = val;
|
config.AdvancedConfig.NonTile = val;
|
||||||
MarkConfigModified();
|
MarkConfigModified();
|
||||||
@@ -596,9 +576,7 @@ internal static class RenderConfigWindow
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 7-1. Planet Color Settings (Optional)
|
// 7-1. Planet Color Settings (Optional)
|
||||||
var planetColorsLabel = O5Factory.ControlText(ctx, advContent, 13f, noPad: true);
|
var planetColorsLabel = CreateLabel(ctx, advContent, "ui.render_config.planet_colors");
|
||||||
planetColorsLabel.text = LocalizationManager.Get("ui.render_config.planet_colors");
|
|
||||||
planetColorsLabel.color = ctx.Theme.TextDim;
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
var planetLabelLE = planetColorsLabel.gameObject.AddComponent<LayoutElement>();
|
var planetLabelLE = planetColorsLabel.gameObject.AddComponent<LayoutElement>();
|
||||||
planetLabelLE.preferredHeight = 18f;
|
planetLabelLE.preferredHeight = 18f;
|
||||||
@@ -609,11 +587,13 @@ internal static class RenderConfigWindow
|
|||||||
|
|
||||||
var fireSlot = CreateFieldSlot(fireCol);
|
var fireSlot = CreateFieldSlot(fireCol);
|
||||||
_firePlanetToggle = CreateToggleField(
|
_firePlanetToggle = CreateToggleField(
|
||||||
ctx, fireSlot, "",
|
ctx, fireSlot,
|
||||||
false, config.AdvancedConfig.firePlanetColor.HasValue,
|
labelKey: "",
|
||||||
LocalizationManager.Get("ui.render_config.fire_planet"),
|
defaultValue: false,
|
||||||
"toggle_fire_planet",
|
value: config.AdvancedConfig.firePlanetColor.HasValue,
|
||||||
val =>
|
toggleTextKey: "ui.render_config.fire_planet",
|
||||||
|
id: "toggle_fire_planet",
|
||||||
|
onChanged: val =>
|
||||||
{
|
{
|
||||||
_firePlanetPicker?.SetBlocked(!val);
|
_firePlanetPicker?.SetBlocked(!val);
|
||||||
config.AdvancedConfig.firePlanetColor = val ? _firePlanetPicker?.Value : null;
|
config.AdvancedConfig.firePlanetColor = val ? _firePlanetPicker?.Value : null;
|
||||||
@@ -643,11 +623,13 @@ internal static class RenderConfigWindow
|
|||||||
|
|
||||||
var iceSlot = CreateFieldSlot(iceCol);
|
var iceSlot = CreateFieldSlot(iceCol);
|
||||||
_icePlanetToggle = CreateToggleField(
|
_icePlanetToggle = CreateToggleField(
|
||||||
ctx, iceSlot, "",
|
ctx, iceSlot,
|
||||||
false, config.AdvancedConfig.icePlanetColor.HasValue,
|
labelKey: "",
|
||||||
LocalizationManager.Get("ui.render_config.ice_planet"),
|
defaultValue: false,
|
||||||
"toggle_ice_planet",
|
value: config.AdvancedConfig.icePlanetColor.HasValue,
|
||||||
val =>
|
toggleTextKey: "ui.render_config.ice_planet",
|
||||||
|
id: "toggle_ice_planet",
|
||||||
|
onChanged: val =>
|
||||||
{
|
{
|
||||||
_icePlanetPicker?.SetBlocked(!val);
|
_icePlanetPicker?.SetBlocked(!val);
|
||||||
config.AdvancedConfig.icePlanetColor = val ? _icePlanetPicker?.Value : null;
|
config.AdvancedConfig.icePlanetColor = val ? _icePlanetPicker?.Value : null;
|
||||||
@@ -677,11 +659,13 @@ internal static class RenderConfigWindow
|
|||||||
|
|
||||||
var windSlot = CreateFieldSlot(windCol);
|
var windSlot = CreateFieldSlot(windCol);
|
||||||
_windPlanetToggle = CreateToggleField(
|
_windPlanetToggle = CreateToggleField(
|
||||||
ctx, windSlot, "",
|
ctx, windSlot,
|
||||||
false, config.AdvancedConfig.windPlanetColor.HasValue,
|
labelKey: "",
|
||||||
LocalizationManager.Get("ui.render_config.wind_planet"),
|
defaultValue: false,
|
||||||
"toggle_wind_planet",
|
value: config.AdvancedConfig.windPlanetColor.HasValue,
|
||||||
val =>
|
toggleTextKey: "ui.render_config.wind_planet",
|
||||||
|
id: "toggle_wind_planet",
|
||||||
|
onChanged: val =>
|
||||||
{
|
{
|
||||||
_windPlanetPicker?.SetBlocked(!val);
|
_windPlanetPicker?.SetBlocked(!val);
|
||||||
config.AdvancedConfig.windPlanetColor = val ? _windPlanetPicker?.Value : null;
|
config.AdvancedConfig.windPlanetColor = val ? _windPlanetPicker?.Value : null;
|
||||||
@@ -710,20 +694,17 @@ internal static class RenderConfigWindow
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 8. Go Render Button
|
// 8. Go Render Button
|
||||||
O5Factory.Button(
|
CreateButton(
|
||||||
ctx, scrollContent,
|
ctx, scrollContent,
|
||||||
TryGoRender,
|
"ui.render_config.go_render",
|
||||||
LocalizationManager.Get("ui.render_config.go_render"),
|
|
||||||
"btn_go_render",
|
"btn_go_render",
|
||||||
|
onClick: TryGoRender,
|
||||||
height: 48f
|
height: 48f
|
||||||
);
|
);
|
||||||
|
|
||||||
// 9. Version Label
|
// 9. Version Label
|
||||||
var versionLabel = O5Factory.ControlText(ctx, scrollContent, 12f, noPad: true);
|
var versionLabel = O5Factory.ControlText(ctx, scrollContent, 12f, noPad: true);
|
||||||
var versionText = $"ADOFAI Renderer v{Melon<RenderMod>.Instance.Info.Version}";
|
LocalizedText.Bind(versionLabel, GetVersionText);
|
||||||
if (DateTime.UtcNow >= RenderMod.ExpirationTime) versionText += " " + LocalizationManager.Get("ui.render_config.expired");
|
|
||||||
|
|
||||||
versionLabel.text = versionText;
|
|
||||||
versionLabel.alignment = TMPro.TextAlignmentOptions.Center;
|
versionLabel.alignment = TMPro.TextAlignmentOptions.Center;
|
||||||
versionLabel.color = ctx.Theme.TextDim;
|
versionLabel.color = ctx.Theme.TextDim;
|
||||||
|
|
||||||
@@ -953,7 +934,7 @@ internal static class RenderConfigWindow
|
|||||||
{
|
{
|
||||||
SyncUItoConfig(config);
|
SyncUItoConfig(config);
|
||||||
|
|
||||||
var name = _presetNameInput?.Value?.Trim();
|
var name = _presetNameInput?.Value.Trim();
|
||||||
if (string.IsNullOrWhiteSpace(name) || name == CustomPresetLabel)
|
if (string.IsNullOrWhiteSpace(name) || name == CustomPresetLabel)
|
||||||
{
|
{
|
||||||
CommonWarningDialogUI.ShowDialog(
|
CommonWarningDialogUI.ShowDialog(
|
||||||
@@ -1087,6 +1068,26 @@ internal static class RenderConfigWindow
|
|||||||
_deletePresetButton?.SetBlocked(!canDelete);
|
_deletePresetButton?.SetBlocked(!canDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void OnLanguageChanged(SystemLanguage language)
|
||||||
|
{
|
||||||
|
if (_configWindow == null) return;
|
||||||
|
|
||||||
|
if (_presetDropdown != null)
|
||||||
|
{
|
||||||
|
var cur = _presetDropdown.Value;
|
||||||
|
var isCustom = cur == "(Modified)" || cur == "(수정됨)" || cur == CustomPresetLabel;
|
||||||
|
ReloadPresetDropdown(isCustom ? CustomPresetLabel : cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetVersionText()
|
||||||
|
{
|
||||||
|
var versionText = $"ADOFAI Renderer v{Melon<RenderMod>.Instance.Info.Version}";
|
||||||
|
if (DateTime.UtcNow >= RenderMod.ExpirationTime)
|
||||||
|
versionText += " " + LocalizationManager.Get("ui.render_config.expired");
|
||||||
|
return versionText;
|
||||||
|
}
|
||||||
|
|
||||||
private static void ShowValidationError(string message)
|
private static void ShowValidationError(string message)
|
||||||
{
|
{
|
||||||
Melon<RenderMod>.Logger.Error(message);
|
Melon<RenderMod>.Logger.Error(message);
|
||||||
@@ -1189,23 +1190,139 @@ internal static class RenderConfigWindow
|
|||||||
return slotRect;
|
return slotRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once UnusedTupleComponentInReturnValue
|
||||||
|
private static (RectTransform card, RectTransform content) CreateCard(
|
||||||
|
O5Context ctx,
|
||||||
|
Transform parent,
|
||||||
|
string titleKey,
|
||||||
|
bool activeValue = true,
|
||||||
|
Action<bool>? onActiveChanged = null,
|
||||||
|
Action? onDeleteClick = null,
|
||||||
|
bool showDeleteButton = false,
|
||||||
|
bool showActiveToggle = false)
|
||||||
|
{
|
||||||
|
var (card, content) = O5Factory.Card(
|
||||||
|
ctx,
|
||||||
|
parent,
|
||||||
|
LocalizationManager.Get(titleKey),
|
||||||
|
activeValue,
|
||||||
|
onActiveChanged,
|
||||||
|
onDeleteClick,
|
||||||
|
showDeleteButton,
|
||||||
|
showActiveToggle
|
||||||
|
);
|
||||||
|
|
||||||
|
var titleTmp = card.Find("Header/TitleTrigger/TitleText")?.GetComponent<TMPro.TextMeshProUGUI>()
|
||||||
|
?? card.GetComponentsInChildren<TMPro.TextMeshProUGUI>(true).FirstOrDefault(t => t.gameObject.name == "TitleText");
|
||||||
|
if (titleTmp)
|
||||||
|
{
|
||||||
|
titleTmp.fontSize = 18f;
|
||||||
|
LocalizedText.Bind(titleTmp, titleKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (card, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TMPro.TextMeshProUGUI CreateLabel(
|
||||||
|
O5Context ctx,
|
||||||
|
Transform parent,
|
||||||
|
string textKey,
|
||||||
|
float fontSize = 13f,
|
||||||
|
bool noPad = true,
|
||||||
|
Color? color = null)
|
||||||
|
{
|
||||||
|
var label = O5Factory.ControlText(ctx, parent, fontSize, noPad: noPad);
|
||||||
|
label.text = LocalizationManager.Get(textKey);
|
||||||
|
label.color = color ?? ctx.Theme.TextDim;
|
||||||
|
LocalizedText.Bind(label, textKey);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static O5Slider CreateSlider(
|
||||||
|
O5Context ctx,
|
||||||
|
Transform parent,
|
||||||
|
string labelKey,
|
||||||
|
string id,
|
||||||
|
double defaultValue,
|
||||||
|
double min,
|
||||||
|
double max,
|
||||||
|
double value,
|
||||||
|
string format = "F0",
|
||||||
|
ClampMode clampMode = ClampMode.All,
|
||||||
|
Func<double, double>? sliderFilter = null,
|
||||||
|
Func<double, double>? inputFilter = null,
|
||||||
|
Action<double>? onChanged = null,
|
||||||
|
Action<double>? onComplete = null,
|
||||||
|
bool showFill = true)
|
||||||
|
{
|
||||||
|
var slider = O5Factory.Slider(
|
||||||
|
ctx: ctx,
|
||||||
|
parent: parent,
|
||||||
|
defaultValue: defaultValue,
|
||||||
|
min: min,
|
||||||
|
max: max,
|
||||||
|
value: value,
|
||||||
|
format: format,
|
||||||
|
clampMode: clampMode,
|
||||||
|
sliderFilter: sliderFilter,
|
||||||
|
inputFilter: inputFilter,
|
||||||
|
onComplete: onComplete,
|
||||||
|
onChanged: onChanged,
|
||||||
|
text: LocalizationManager.Get(labelKey),
|
||||||
|
id: id,
|
||||||
|
showFill: showFill
|
||||||
|
);
|
||||||
|
|
||||||
|
if (slider.Label != null)
|
||||||
|
{
|
||||||
|
LocalizedText.Bind(slider.Label, labelKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return slider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static O5Button CreateButton(
|
||||||
|
O5Context ctx,
|
||||||
|
Transform parent,
|
||||||
|
string textKey,
|
||||||
|
string id,
|
||||||
|
Action onClick,
|
||||||
|
float? height = null)
|
||||||
|
{
|
||||||
|
var button = O5Factory.Button(
|
||||||
|
ctx: ctx,
|
||||||
|
parent: parent,
|
||||||
|
onClick: onClick,
|
||||||
|
text: LocalizationManager.Get(textKey),
|
||||||
|
id: id,
|
||||||
|
height: height
|
||||||
|
);
|
||||||
|
|
||||||
|
if (button.Label != null)
|
||||||
|
{
|
||||||
|
LocalizedText.Bind(button.Label, textKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
private static O5InputField CreateInputField(
|
private static O5InputField CreateInputField(
|
||||||
O5Context ctx,
|
O5Context ctx,
|
||||||
Transform colParent,
|
Transform colParent,
|
||||||
string labelText,
|
string labelKey,
|
||||||
string? defaultValue,
|
string? defaultValue,
|
||||||
string value,
|
string value,
|
||||||
string id,
|
string id,
|
||||||
TMPro.TMP_InputField.CharacterValidation characterValidation = TMPro.TMP_InputField.CharacterValidation.None,
|
TMPro.TMP_InputField.CharacterValidation characterValidation = TMPro.TMP_InputField.CharacterValidation.None,
|
||||||
Action<string>? onChanged = null)
|
Action<string>? onChanged = null)
|
||||||
{
|
{
|
||||||
return CreateInputField(ctx, colParent, labelText, defaultValue, value, id, out _, characterValidation, onChanged);
|
return CreateInputField(ctx, colParent, labelKey, defaultValue, value, id, out _, characterValidation, onChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static O5InputField CreateInputField(
|
private static O5InputField CreateInputField(
|
||||||
O5Context ctx,
|
O5Context ctx,
|
||||||
Transform colParent,
|
Transform colParent,
|
||||||
string labelText,
|
string labelKey,
|
||||||
string? defaultValue,
|
string? defaultValue,
|
||||||
string value,
|
string value,
|
||||||
string id,
|
string id,
|
||||||
@@ -1214,8 +1331,9 @@ internal static class RenderConfigWindow
|
|||||||
Action<string>? onChanged = null)
|
Action<string>? onChanged = null)
|
||||||
{
|
{
|
||||||
label = O5Factory.ControlText(ctx, colParent, 13f, noPad: true);
|
label = O5Factory.ControlText(ctx, colParent, 13f, noPad: true);
|
||||||
label.text = labelText;
|
label.text = LocalizationManager.Get(labelKey);
|
||||||
label.color = ctx.Theme.TextDim;
|
label.color = ctx.Theme.TextDim;
|
||||||
|
LocalizedText.Bind(label, labelKey);
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
var labelLE = label.gameObject.AddComponent<LayoutElement>();
|
var labelLE = label.gameObject.AddComponent<LayoutElement>();
|
||||||
@@ -1228,11 +1346,16 @@ internal static class RenderConfigWindow
|
|||||||
defaultValue: defaultValue,
|
defaultValue: defaultValue,
|
||||||
value: value,
|
value: value,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
placeholder: labelText,
|
placeholder: LocalizationManager.Get(labelKey),
|
||||||
icon: null,
|
icon: null,
|
||||||
id: id
|
id: id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (inputField.Placeholder != null)
|
||||||
|
{
|
||||||
|
LocalizedText.Bind(inputField.Placeholder, labelKey);
|
||||||
|
}
|
||||||
|
|
||||||
inputField.InputField.characterValidation = characterValidation;
|
inputField.InputField.characterValidation = characterValidation;
|
||||||
return inputField;
|
return inputField;
|
||||||
}
|
}
|
||||||
@@ -1291,7 +1414,7 @@ internal static class RenderConfigWindow
|
|||||||
private static O5InputField CreateFullWidthInputField(
|
private static O5InputField CreateFullWidthInputField(
|
||||||
O5Context ctx,
|
O5Context ctx,
|
||||||
Transform parent,
|
Transform parent,
|
||||||
string labelText,
|
string labelKey,
|
||||||
string? defaultValue,
|
string? defaultValue,
|
||||||
string value,
|
string value,
|
||||||
string id,
|
string id,
|
||||||
@@ -1309,8 +1432,9 @@ internal static class RenderConfigWindow
|
|||||||
layout.childForceExpandHeight = false;
|
layout.childForceExpandHeight = false;
|
||||||
|
|
||||||
var label = O5Factory.ControlText(ctx, containerRect, 13f, noPad: true);
|
var label = O5Factory.ControlText(ctx, containerRect, 13f, noPad: true);
|
||||||
label.text = labelText;
|
label.text = LocalizationManager.Get(labelKey);
|
||||||
label.color = ctx.Theme.TextDim;
|
label.color = ctx.Theme.TextDim;
|
||||||
|
LocalizedText.Bind(label, labelKey);
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
var labelLE = label.gameObject.AddComponent<LayoutElement>();
|
var labelLE = label.gameObject.AddComponent<LayoutElement>();
|
||||||
@@ -1323,30 +1447,36 @@ internal static class RenderConfigWindow
|
|||||||
defaultValue: defaultValue,
|
defaultValue: defaultValue,
|
||||||
value: value,
|
value: value,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
placeholder: labelText,
|
placeholder: LocalizationManager.Get(labelKey),
|
||||||
icon: null,
|
icon: null,
|
||||||
id: id
|
id: id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (input.Placeholder != null)
|
||||||
|
{
|
||||||
|
LocalizedText.Bind(input.Placeholder, labelKey);
|
||||||
|
}
|
||||||
|
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static O5Toggle CreateToggleField(
|
private static O5Toggle CreateToggleField(
|
||||||
O5Context ctx,
|
O5Context ctx,
|
||||||
Transform colParent,
|
Transform colParent,
|
||||||
string labelText,
|
string labelKey,
|
||||||
bool? defaultValue,
|
bool? defaultValue,
|
||||||
bool value,
|
bool value,
|
||||||
string toggleText,
|
string toggleTextKey,
|
||||||
string id,
|
string id,
|
||||||
Action<bool>? onChanged = null,
|
Action<bool>? onChanged = null,
|
||||||
bool generateLabel = true)
|
bool generateLabel = true)
|
||||||
{
|
{
|
||||||
if (generateLabel)
|
if (generateLabel && !string.IsNullOrEmpty(labelKey))
|
||||||
{
|
{
|
||||||
var label = O5Factory.ControlText(ctx, colParent, 13f, noPad: true);
|
var label = O5Factory.ControlText(ctx, colParent, 13f, noPad: true);
|
||||||
label.text = labelText;
|
label.text = LocalizationManager.Get(labelKey);
|
||||||
label.color = ctx.Theme.TextDim;
|
label.color = ctx.Theme.TextDim;
|
||||||
|
LocalizedText.Bind(label, labelKey);
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
var labelLE = label.gameObject.AddComponent<LayoutElement>();
|
var labelLE = label.gameObject.AddComponent<LayoutElement>();
|
||||||
@@ -1354,21 +1484,28 @@ internal static class RenderConfigWindow
|
|||||||
labelLE.minHeight = 18f;
|
labelLE.minHeight = 18f;
|
||||||
}
|
}
|
||||||
|
|
||||||
return O5Factory.Toggle(
|
var toggle = O5Factory.Toggle(
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
parent: colParent,
|
parent: colParent,
|
||||||
defaultValue: defaultValue,
|
defaultValue: defaultValue,
|
||||||
value: value,
|
value: value,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
text: toggleText,
|
text: !string.IsNullOrEmpty(toggleTextKey) ? LocalizationManager.Get(toggleTextKey) : "",
|
||||||
id: id
|
id: id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (toggle.Label != null && !string.IsNullOrEmpty(toggleTextKey))
|
||||||
|
{
|
||||||
|
LocalizedText.Bind(toggle.Label, toggleTextKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static O5Dropdown<T> CreateDropdownField<T>(
|
private static O5Dropdown<T> CreateDropdownField<T>(
|
||||||
O5Context ctx,
|
O5Context ctx,
|
||||||
Transform colParent,
|
Transform colParent,
|
||||||
string labelText,
|
string labelKey,
|
||||||
T defaultValue,
|
T defaultValue,
|
||||||
T value,
|
T value,
|
||||||
IReadOnlyList<T> values,
|
IReadOnlyList<T> values,
|
||||||
@@ -1377,8 +1514,9 @@ internal static class RenderConfigWindow
|
|||||||
Action<T>? onChanged = null)
|
Action<T>? onChanged = null)
|
||||||
{
|
{
|
||||||
var label = O5Factory.ControlText(ctx, colParent, 13f, noPad: true);
|
var label = O5Factory.ControlText(ctx, colParent, 13f, noPad: true);
|
||||||
label.text = labelText;
|
label.text = LocalizationManager.Get(labelKey);
|
||||||
label.color = ctx.Theme.TextDim;
|
label.color = ctx.Theme.TextDim;
|
||||||
|
LocalizedText.Bind(label, labelKey);
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
var labelLE = label.gameObject.AddComponent<LayoutElement>();
|
var labelLE = label.gameObject.AddComponent<LayoutElement>();
|
||||||
|
|||||||
Reference in new issue
Block a user