177 lines
7.8 KiB
C#
177 lines
7.8 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace ProjectM.Client
|
|
{
|
|
/// <summary>
|
|
/// UI Toolkit factories for the in-game HUD — a thin extension of <see cref="MenuUi"/>'s Aether palette,
|
|
/// now skinned with the curated Synty sci-fi-soldier kit (<see cref="HudTheme"/>). Panels are 9-sliced Synty
|
|
/// boxes tinted into the Aether palette; bars are a skinned track + a percent-width fill; numerics use the
|
|
/// Orbitron display font and labels the Exo 2.0 body font. EVERYTHING is null-safe: if <see cref="HudTheme"/>
|
|
/// (or a given sprite/font) is missing, each factory falls back to the original flat-colour look, so the HUD
|
|
/// is shippable with or without the theme asset. Every element is <c>pickingMode = Ignore</c> by default so
|
|
/// the HUD never eats clicks meant for the game world (only the interactive build-palette slots opt back in).
|
|
/// </summary>
|
|
public static class HudUi
|
|
{
|
|
public static readonly Color Track = new(0f, 0f, 0f, 0.55f);
|
|
|
|
// ---- text (Orbitron display vs Exo body, theme-driven with a bold fallback) ----
|
|
|
|
/// <summary>A body label (Exo 2.0 when themed) — labels, captions, hints.</summary>
|
|
public static Label Text(string text, int size, Color color, TextAnchor align)
|
|
{
|
|
var l = MakeLabel(text, size, color, align);
|
|
var theme = HudTheme.Get();
|
|
if (theme != null) theme.ApplyBody(l.style);
|
|
return l;
|
|
}
|
|
|
|
/// <summary>A display label (Orbitron when themed) — numerics + phase words, the authoritative HUD voice.</summary>
|
|
public static Label Display(string text, int size, Color color, TextAnchor align)
|
|
{
|
|
var l = MakeLabel(text, size, color, align);
|
|
var theme = HudTheme.Get();
|
|
if (theme != null) theme.ApplyDisplay(l.style);
|
|
return l;
|
|
}
|
|
|
|
static Label MakeLabel(string text, int size, Color color, TextAnchor align)
|
|
{
|
|
var l = new Label(text);
|
|
l.style.fontSize = size;
|
|
l.style.color = color;
|
|
l.style.unityTextAlign = align;
|
|
l.style.unityFontStyleAndWeight = FontStyle.Bold;
|
|
l.pickingMode = PickingMode.Ignore;
|
|
return l;
|
|
}
|
|
|
|
// ---- bars ----
|
|
|
|
/// <summary>A dark rounded bar track with a percent-width fill child (returned via <paramref name="fill"/>).</summary>
|
|
public static VisualElement Bar(float width, float height, Color fillColor, out VisualElement fill)
|
|
{
|
|
var theme = HudTheme.Get();
|
|
var trackSpr = theme != null ? theme.BarTrack : null;
|
|
|
|
var track = new VisualElement();
|
|
track.style.width = width;
|
|
track.style.height = height;
|
|
track.style.paddingLeft = 2; track.style.paddingRight = 2;
|
|
track.style.paddingTop = 2; track.style.paddingBottom = 2;
|
|
track.style.flexDirection = FlexDirection.Row;
|
|
track.pickingMode = PickingMode.Ignore;
|
|
|
|
fill = new VisualElement();
|
|
fill.style.height = Length.Percent(100);
|
|
fill.style.width = Length.Percent(100);
|
|
fill.style.backgroundColor = fillColor;
|
|
fill.pickingMode = PickingMode.Ignore;
|
|
MenuUi.Round(fill, 3);
|
|
|
|
if (trackSpr != null)
|
|
{
|
|
// Bar_Angled ships an 80/0 border → UITK 9-slices it horizontally from the art; no style override.
|
|
track.style.backgroundImage = new StyleBackground(Background.FromSprite(trackSpr));
|
|
track.style.unityBackgroundImageTintColor = new Color(0.04f, 0.06f, 0.09f, 0.92f);
|
|
}
|
|
else
|
|
{
|
|
track.style.backgroundColor = Track;
|
|
MenuUi.Round(track, 4);
|
|
}
|
|
|
|
track.Add(fill);
|
|
return track;
|
|
}
|
|
|
|
/// <summary>Set a fill's width to a 0..1 fraction of its track.</summary>
|
|
public static void SetFill(VisualElement fill, float frac)
|
|
{
|
|
if (fill != null) fill.style.width = Length.Percent(Mathf.Clamp01(frac) * 100f);
|
|
}
|
|
|
|
// ---- panels / icons / glyphs ----
|
|
|
|
/// <summary>A grouping container (no background). Transparent, click-through.</summary>
|
|
public static VisualElement Group(Align items = Align.FlexStart)
|
|
{
|
|
var g = new VisualElement();
|
|
g.style.alignItems = items;
|
|
g.pickingMode = PickingMode.Ignore;
|
|
return g;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A 9-sliced Synty panel tinted into the Aether palette; falls back to a flat translucent rounded panel
|
|
/// when the theme/sprite is missing. <paramref name="tint"/> multiplies the (light-grey) skin, so a dark
|
|
/// tint reads as panel-dark while preserving the printed bevels.
|
|
/// </summary>
|
|
public static VisualElement Panel(Color tint)
|
|
{
|
|
var p = new VisualElement();
|
|
p.pickingMode = PickingMode.Ignore;
|
|
var theme = HudTheme.Get();
|
|
var box = theme != null ? theme.PanelBox : null;
|
|
if (box != null)
|
|
{
|
|
p.style.backgroundImage = new StyleBackground(Background.FromSprite(box));
|
|
p.style.unityBackgroundImageTintColor = tint;
|
|
// 9-slice uses the sprite's AUTHORED border (Box_Glass ships 25px); no style override → no
|
|
// "borders overridden by style slices" log, and the art's intended corners are preserved.
|
|
}
|
|
else
|
|
{
|
|
p.style.backgroundColor = tint;
|
|
MenuUi.Round(p, 8);
|
|
MenuUi.Border(p, new Color(1f, 1f, 1f, 0.08f), 1);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
/// <summary>A fixed-size icon element backed by a Synty sprite (tinted). Returns an empty element if null.</summary>
|
|
public static VisualElement Icon(Sprite sprite, float size, Color tint)
|
|
{
|
|
var e = new VisualElement();
|
|
e.style.width = size; e.style.height = size;
|
|
e.style.flexShrink = 0;
|
|
e.pickingMode = PickingMode.Ignore;
|
|
if (sprite != null)
|
|
{
|
|
e.style.backgroundImage = new StyleBackground(Background.FromSprite(sprite));
|
|
e.style.unityBackgroundImageTintColor = tint;
|
|
e.style.backgroundSize = new StyleBackgroundSize(new BackgroundSize(BackgroundSizeType.Contain));
|
|
}
|
|
return e;
|
|
}
|
|
|
|
/// <summary>True when the theme is loaded and a sprite is present (callers choose icon vs text fallback).</summary>
|
|
|
|
|
|
/// <summary>
|
|
/// An input-prompt chip: the Synty key/button glyph (left untinted to keep its printed face) when present,
|
|
/// else a bordered text keycap with <paramref name="fallbackText"/> (e.g. "R", "Esc").
|
|
/// </summary>
|
|
public static VisualElement Glyph(Sprite sprite, string fallbackText, float size)
|
|
{
|
|
if (sprite != null) return Icon(sprite, size, Color.white);
|
|
|
|
var cap = new VisualElement();
|
|
cap.style.minWidth = size; cap.style.height = size;
|
|
cap.style.paddingLeft = 7; cap.style.paddingRight = 7;
|
|
cap.style.alignItems = Align.Center; cap.style.justifyContent = Justify.Center;
|
|
cap.style.backgroundColor = new Color(0.14f, 0.17f, 0.22f, 0.95f);
|
|
cap.style.flexShrink = 0;
|
|
cap.pickingMode = PickingMode.Ignore;
|
|
MenuUi.Round(cap, 4);
|
|
MenuUi.Border(cap, new Color(1f, 1f, 1f, 0.25f), 1);
|
|
cap.Add(Text(fallbackText, Mathf.Max(10, (int)(size * 0.5f)), MenuUi.TextCol, TextAnchor.MiddleCenter));
|
|
return cap;
|
|
}
|
|
|
|
/// <summary>Apply a uniform 9-slice (horizontal / vertical source-texture px) to a skinned element.</summary>
|
|
|
|
}
|
|
}
|