Inspector: keep field editing usable, clarify editable fields
CI / build-test (push) Successful in 1m7s
CI / build-test (push) Successful in 1m7s
Split the inspector's revision into a list revision and a detail revision. The periodic refresh now only bumps the list revision, and only when the entity count actually changes, so the field-editor TextBox in the details pane is no longer recreated (losing focus) twice a second while you type. Stats and the performance tab update as plain text every frame without rebuilding widgets. Editable fields now render with a background, border and padding so they read as inputs; read-only values and enum hints are muted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
09dbdfad79
commit
44019a706e
@@ -12,7 +12,7 @@ namespace MrGameEng.Inspector;
|
||||
/// Entities/Performance tabs and arms world-pick; the Entities tab shows archetypes → entities →
|
||||
/// the selected entity's components and editable fields; the Performance tab shows renderer
|
||||
/// timings. A thin border tracks the selected entity in the world each frame. Rebuilds lazily on
|
||||
/// <see cref="EcsInspector.Revision"/> changes.
|
||||
/// <see cref="EcsInspector.ListRevision"/>/<see cref="EcsInspector.DetailRevision"/> changes.
|
||||
/// </summary>
|
||||
internal sealed class EcsInspectorUi
|
||||
{
|
||||
@@ -33,7 +33,8 @@ internal sealed class EcsInspectorUi
|
||||
private readonly Panel _highlight;
|
||||
private readonly VerticalStackPanel _panel;
|
||||
|
||||
private int _lastRevision = -1;
|
||||
private int _lastListRevision = -1;
|
||||
private int _lastDetailRevision = -1;
|
||||
|
||||
public EcsInspectorUi(EcsInspector inspector, Renderer2D renderer)
|
||||
{
|
||||
@@ -91,10 +92,24 @@ internal sealed class EcsInspectorUi
|
||||
return;
|
||||
}
|
||||
|
||||
if (_inspector.Revision != _lastRevision)
|
||||
// Stats and perf are cheap text updates — refresh every frame so they stay live.
|
||||
var perf = _inspector.Performance();
|
||||
UpdateStats(perf);
|
||||
if (_inspector.ActiveTab == InspectorTab.Performance)
|
||||
{
|
||||
_lastRevision = _inspector.Revision;
|
||||
Rebuild();
|
||||
UpdatePerf(perf);
|
||||
}
|
||||
|
||||
if (_inspector.ListRevision != _lastListRevision)
|
||||
{
|
||||
_lastListRevision = _inspector.ListRevision;
|
||||
RebuildLists();
|
||||
}
|
||||
|
||||
if (_inspector.DetailRevision != _lastDetailRevision)
|
||||
{
|
||||
_lastDetailRevision = _inspector.DetailRevision;
|
||||
RebuildDetails();
|
||||
}
|
||||
|
||||
UpdateHighlight();
|
||||
@@ -116,39 +131,41 @@ internal sealed class EcsInspectorUi
|
||||
return section;
|
||||
}
|
||||
|
||||
private void Rebuild()
|
||||
private void RebuildLists()
|
||||
{
|
||||
var entitiesTab = _inspector.ActiveTab == InspectorTab.Entities;
|
||||
_entitiesSection.Visible = entitiesTab;
|
||||
_perf.Visible = !entitiesTab;
|
||||
_pickLabel.Text = _inspector.PickArmed ? "Pick*" : "Pick";
|
||||
|
||||
var perf = _inspector.Performance();
|
||||
_stats.Text =
|
||||
$"entities {perf.Entities} | archetypes {perf.Archetypes} | {perf.Fps} FPS"
|
||||
+ (_inspector.PickArmed ? " | click an entity…" : "");
|
||||
|
||||
if (entitiesTab)
|
||||
{
|
||||
RebuildArchetypes();
|
||||
RebuildEntities();
|
||||
RebuildDetails();
|
||||
}
|
||||
else
|
||||
{
|
||||
_perf.Text =
|
||||
$"FPS {perf.Fps}\n"
|
||||
+ $"submit {perf.SubmitMs:0.00} ms\n"
|
||||
+ $"sort {perf.SortMs:0.00} ms\n"
|
||||
+ $"build {perf.BuildMs:0.00} ms\n"
|
||||
+ $"upload {perf.UploadMs:0.00} ms\n"
|
||||
+ $"draw {perf.DrawMs:0.00} ms\n"
|
||||
+ $"draw calls {perf.DrawCalls}\n"
|
||||
+ $"sprites {perf.SubmittedSprites} drawn, {perf.CulledSprites} culled\n"
|
||||
+ $"entities {perf.Entities}";
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStats(in PerfSnapshot perf)
|
||||
{
|
||||
_stats.Text =
|
||||
$"entities {perf.Entities} | archetypes {perf.Archetypes} | {perf.Fps} FPS"
|
||||
+ (_inspector.PickArmed ? " | click an entity…" : "");
|
||||
}
|
||||
|
||||
private void UpdatePerf(in PerfSnapshot perf)
|
||||
{
|
||||
_perf.Text =
|
||||
$"FPS {perf.Fps}\n"
|
||||
+ $"submit {perf.SubmitMs:0.00} ms\n"
|
||||
+ $"sort {perf.SortMs:0.00} ms\n"
|
||||
+ $"build {perf.BuildMs:0.00} ms\n"
|
||||
+ $"upload {perf.UploadMs:0.00} ms\n"
|
||||
+ $"draw {perf.DrawMs:0.00} ms\n"
|
||||
+ $"draw calls {perf.DrawCalls}\n"
|
||||
+ $"sprites {perf.SubmittedSprites} drawn, {perf.CulledSprites} culled\n"
|
||||
+ $"entities {perf.Entities}";
|
||||
}
|
||||
|
||||
private void RebuildArchetypes()
|
||||
{
|
||||
_archetypeList.Widgets.Clear();
|
||||
@@ -209,16 +226,31 @@ internal sealed class EcsInspectorUi
|
||||
|
||||
private Widget BuildFieldRow(Type componentType, FieldRow field)
|
||||
{
|
||||
var row = new HorizontalStackPanel { Spacing = 6 };
|
||||
row.Widgets.Add(new Label { Text = field.Name, Width = 150 });
|
||||
var row = new HorizontalStackPanel { Spacing = 8 };
|
||||
row.Widgets.Add(
|
||||
new Label
|
||||
{
|
||||
Text = field.Name,
|
||||
Width = 140,
|
||||
TextColor = new Color(170, 178, 190),
|
||||
}
|
||||
);
|
||||
|
||||
if (!field.Editable)
|
||||
{
|
||||
row.Widgets.Add(new Label { Text = field.Value });
|
||||
row.Widgets.Add(new Label { Text = field.Value, TextColor = new Color(150, 156, 168) });
|
||||
return row;
|
||||
}
|
||||
|
||||
var editor = new TextBox { Text = field.Value, Width = 220 };
|
||||
var editor = new TextBox
|
||||
{
|
||||
Text = field.Value,
|
||||
Width = 150,
|
||||
Padding = new Thickness(4, 2),
|
||||
Background = new SolidBrush(new Color(28, 33, 42)),
|
||||
Border = new SolidBrush(new Color(70, 82, 100)),
|
||||
BorderThickness = new Thickness(1),
|
||||
};
|
||||
var entityId = _inspector.SelectedEntityId;
|
||||
editor.KeyDown += (_, args) =>
|
||||
{
|
||||
@@ -230,7 +262,13 @@ internal sealed class EcsInspectorUi
|
||||
row.Widgets.Add(editor);
|
||||
if (field.Kind == FieldKind.Enum && field.EnumOptions is { Length: > 0 })
|
||||
{
|
||||
row.Widgets.Add(new Label { Text = "(" + string.Join("/", field.EnumOptions) + ")" });
|
||||
row.Widgets.Add(
|
||||
new Label
|
||||
{
|
||||
Text = string.Join(" / ", field.EnumOptions),
|
||||
TextColor = new Color(120, 128, 140),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return row;
|
||||
|
||||
Reference in New Issue
Block a user