Schema field editors (scalar, list, map, locale); entity editors show fields that other mods' schemas add to their kind
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3ddb61d61e
commit
033192dcc9
16 files changed
+773
-2
No files matched your search
@@ -0,0 +1,128 @@
|
||||
namespace Cthangover.Tools.Schemas
|
||||
{
|
||||
using Cthangover.Mods.Schemas;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
using Cthangover.Core.UI.Theming;
|
||||
using Cthangover.Mods.Interface.Theming;
|
||||
using Cthangover.Tools.Common;
|
||||
using Godot;
|
||||
|
||||
/// <summary>
|
||||
/// Edits a <c>map</c> field — an object whose keys are ids of <see cref="FieldSchema.Kind"/>
|
||||
/// and whose values are numbers or formulas (a character's own <c>Stats</c>, an archetype's
|
||||
/// growth): one row per key with a key picker, a value box and a remove button. A number
|
||||
/// is written as a number, anything else as a formula text.
|
||||
/// </summary>
|
||||
public class MapFieldEditor : ISchemaFieldEditor
|
||||
{
|
||||
private readonly FieldSchema field;
|
||||
private readonly Action changed;
|
||||
private readonly VBoxContainer lines;
|
||||
private readonly List<(OptionButton Key, List<string> Keys, LineEdit Value, Control Row)> rows = new();
|
||||
private bool suppress;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FieldSchema Field => field;
|
||||
|
||||
/// <summary>Adds the editor for <paramref name="field"/> to <paramref name="parent"/>.</summary>
|
||||
public MapFieldEditor(Container parent, FieldSchema field, Action changed)
|
||||
{
|
||||
this.field = field;
|
||||
this.changed = changed;
|
||||
var box = new VBoxContainer { Name = "Map_" + field.Key };
|
||||
lines = new VBoxContainer();
|
||||
lines.AddThemeConstantOverride("separation", UiTokens.Space1);
|
||||
box.AddChild(lines);
|
||||
var add = ToolUi.Button("tools/schema/map_add", AddEmpty, ButtonKind.Secondary);
|
||||
add.Name = "Add";
|
||||
add.SizeFlagsHorizontal = Control.SizeFlags.ShrinkBegin;
|
||||
box.AddChild(add);
|
||||
ToolUi.Field(parent, string.IsNullOrEmpty(field.Name) ? field.Key : field.Name, box, field.Description);
|
||||
}
|
||||
|
||||
/// <summary>Shows the object <paramref name="node"/>.</summary>
|
||||
public void Load(JsonNode node)
|
||||
{
|
||||
suppress = true;
|
||||
foreach (var row in rows)
|
||||
{
|
||||
lines.RemoveChild(row.Row);
|
||||
row.Row.QueueFree();
|
||||
}
|
||||
rows.Clear();
|
||||
if (node is JsonObject obj)
|
||||
{
|
||||
foreach (var pair in obj)
|
||||
AddRow(pair.Key, SchemaJson.ToText(pair.Value));
|
||||
}
|
||||
suppress = false;
|
||||
}
|
||||
|
||||
/// <summary>The edited object, or null when empty.</summary>
|
||||
public JsonNode Save()
|
||||
{
|
||||
var obj = new JsonObject();
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var key = row.Key.Selected >= 0 && row.Key.Selected < row.Keys.Count ? row.Keys[row.Key.Selected] : null;
|
||||
if (!string.IsNullOrEmpty(key) && row.Value.Text.Trim().Length > 0)
|
||||
obj[key] = SchemaJson.NumberOrText(row.Value.Text.Trim());
|
||||
}
|
||||
return obj.Count == 0 ? null : obj;
|
||||
}
|
||||
|
||||
private void AddEmpty()
|
||||
{
|
||||
AddRow(null, string.Empty);
|
||||
changed?.Invoke();
|
||||
}
|
||||
|
||||
private void AddRow(string key, string value)
|
||||
{
|
||||
var row = new HBoxContainer { Name = "Row" + rows.Count };
|
||||
row.AddThemeConstantOverride("separation", UiTokens.Space2);
|
||||
var keys = new List<string> { string.Empty };
|
||||
if (!string.IsNullOrEmpty(key) && !GameEntityIndex.Of(field.Kind).ContainsKey(key))
|
||||
keys.Add(key);
|
||||
keys.AddRange(GameEntityIndex.Of(field.Kind).Keys);
|
||||
var picker = new OptionButton { CustomMinimumSize = new Vector2(200, 0) };
|
||||
foreach (var k in keys)
|
||||
picker.AddItem(k.Length == 0 ? "—" : GameEntityIndex.Label(field.Kind, k));
|
||||
picker.Select(Math.Max(0, keys.FindIndex(k => string.Equals(k, key, StringComparison.OrdinalIgnoreCase))));
|
||||
picker.ItemSelected += OnPicked;
|
||||
row.AddChild(picker);
|
||||
var edit = ToolUi.Text(field.Default ?? string.Empty, OnTyped);
|
||||
edit.Text = value ?? string.Empty;
|
||||
edit.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
|
||||
edit.AddThemeFontOverride("font", ToolUi.Mono());
|
||||
row.AddChild(edit);
|
||||
var entry = (picker, keys, edit, (Control)row);
|
||||
row.AddChild(ToolUi.Button("tools/schema/list_remove", () => Remove(entry), ButtonKind.Secondary));
|
||||
rows.Add(entry);
|
||||
lines.AddChild(row);
|
||||
}
|
||||
|
||||
private void Remove((OptionButton Key, List<string> Keys, LineEdit Value, Control Row) entry)
|
||||
{
|
||||
rows.Remove(entry);
|
||||
lines.RemoveChild(entry.Row);
|
||||
entry.Row.QueueFree();
|
||||
changed?.Invoke();
|
||||
}
|
||||
|
||||
private void OnPicked(long index)
|
||||
{
|
||||
if (!suppress)
|
||||
changed?.Invoke();
|
||||
}
|
||||
|
||||
private void OnTyped(string text)
|
||||
{
|
||||
if (!suppress)
|
||||
changed?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user