feat(ui): AcDream.UI.Abstractions layer — IPanel / IPanelRenderer / VitalsVM
Adds the backend-agnostic UI contract layer called for by the 2026-04-24
staged UI strategy (docs/plans/2026-04-24-ui-framework.md). This is the
stable layer both the Phase D.2a Hexa.NET.ImGui backend and the later
D.2b custom retail-look backend implement.
New module `src/AcDream.UI.Abstractions/`:
* IPanel — a drawable panel (id/title/visible/Render)
* IPanelHost — owns the panel list, drives per-frame dispatch
* IPanelRenderer — drawing primitives (Begin/End/Text/SameLine/
Separator/ProgressBar). Kept small + retail-friendly
on purpose — if a widget can't be expressed with
dat-sourced sprites+fonts later, don't add it here.
* ICommandBus — user-intent publisher; NullCommandBus is D.2a default
* PanelContext — per-frame record struct (DeltaSeconds + Commands)
* Panels/Vitals/
VitalsVM — reads CombatState.GetHealthPercent for the local
player. Stamina/Mana return null in D.2a; they await
a LocalPlayerState cache of PlayerDescription (0x0013)
which is filed as a follow-up issue.
VitalsPanel — first real panel. HP bar always drawn; Stam/Mana
appear automatically when the VM returns non-null.
Invariant documented in IPanel's XML doc: no `using Hexa.NET.ImGui` in
panel files, ever. If a widget needs something IPanelRenderer can't
express, the interface grows; panels never reach through.
References AcDream.Core for CombatState. Zero runtime/UI dependencies
— this project compiles headless, perfect for unit testing the
ViewModels.
No visible change yet. Next commits: (2) tests, (3) ImGui backend,
(4) GameWindow hookup + visible panel behind ACDREAM_DEVTOOLS=1.
This commit is contained in:
parent
b9455259f0
commit
8c64ad2eeb
10 changed files with 333 additions and 0 deletions
69
src/AcDream.UI.Abstractions/Panels/Vitals/VitalsPanel.cs
Normal file
69
src/AcDream.UI.Abstractions/Panels/Vitals/VitalsPanel.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
namespace AcDream.UI.Abstractions.Panels.Vitals;
|
||||
|
||||
/// <summary>
|
||||
/// First real UI panel — shows the local player's vitals as progress bars.
|
||||
/// Backend-agnostic; renders exclusively through <see cref="IPanelRenderer"/>
|
||||
/// so the same file works under Hexa.NET.ImGui (D.2a) and the future custom
|
||||
/// retail-look toolkit (D.2b).
|
||||
///
|
||||
/// <para>
|
||||
/// D.2a shows only HP (percent). <see cref="VitalsVM.StaminaPercent"/> /
|
||||
/// <see cref="VitalsVM.ManaPercent"/> return null until a
|
||||
/// <c>LocalPlayerState</c> is wired (follow-up issue). When they start
|
||||
/// returning non-null, this panel picks them up automatically.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class VitalsPanel : IPanel
|
||||
{
|
||||
private const float BarWidth = 200f;
|
||||
|
||||
private readonly VitalsVM _vm;
|
||||
|
||||
public VitalsPanel(VitalsVM vm)
|
||||
{
|
||||
_vm = vm ?? throw new ArgumentNullException(nameof(vm));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Id => "acdream.vitals";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Title => "Vitals";
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsVisible { get; set; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Render(PanelContext ctx, IPanelRenderer renderer)
|
||||
{
|
||||
if (!renderer.Begin(Title))
|
||||
{
|
||||
renderer.End();
|
||||
return;
|
||||
}
|
||||
|
||||
// HP — always available from CombatState.
|
||||
float hp = _vm.HealthPercent;
|
||||
renderer.Text("HP");
|
||||
renderer.SameLine();
|
||||
renderer.ProgressBar(hp, BarWidth, overlay: $"{hp * 100f:F0}%");
|
||||
|
||||
// Stamina — show only when the VM has a real value.
|
||||
if (_vm.StaminaPercent is float stam)
|
||||
{
|
||||
renderer.Text("Stam");
|
||||
renderer.SameLine();
|
||||
renderer.ProgressBar(stam, BarWidth, overlay: $"{stam * 100f:F0}%");
|
||||
}
|
||||
|
||||
// Mana — show only when the VM has a real value.
|
||||
if (_vm.ManaPercent is float mana)
|
||||
{
|
||||
renderer.Text("Mana");
|
||||
renderer.SameLine();
|
||||
renderer.ProgressBar(mana, BarWidth, overlay: $"{mana * 100f:F0}%");
|
||||
}
|
||||
|
||||
renderer.End();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue