Made the popup system a lot more generic

This commit is contained in:
Sebastian Bularca
2026-04-06 20:38:58 +02:00
parent fa7659d905
commit cfe202da44
21 changed files with 840 additions and 682 deletions

View File

@@ -1,86 +1,114 @@
using Jovian.PopupSystem.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Jovian.PopupSystem {
/// <summary>
/// Fluent API struct for building popup content. Operates directly on cached elements
/// inside a <see cref="PopupReference"/> — no intermediate allocations. Received in
/// the build callback passed to <see cref="IPopupSystem.Show"/>.
/// Fluent API struct for building popup content. Operates on the generic element cache
/// inside a <see cref="PopupView"/>. Received in the build callback passed to
/// <see cref="IPopupSystem.Show"/>. Use <see cref="Add"/> for fully custom elements,
/// or convenience methods for common types.
/// </summary>
public struct PopupContentBuilder {
readonly PopupReference view;
public readonly struct PopupContentBuilder {
readonly PopupView view;
/// <summary>
/// Creates a builder targeting the given popup reference.
/// Creates a builder targeting the given popup view.
/// </summary>
public PopupContentBuilder(PopupReference view) {
public PopupContentBuilder(PopupView view) {
this.view = view;
}
/// <summary>
/// Adds a header text element (bold, larger font).
/// Returns a cached or newly instantiated element by its registered type.
/// Use this for fully custom or game-specific element types.
/// </summary>
public PopupContentBuilder AddHeader(string text) {
var header = view.GetHeader();
header.text = text;
public GameObject Add(PopupElementType elementType) {
return view.GetElement(elementType);
}
/// <summary>
/// Adds a text element using the given element type and sets its TMP_Text content.
/// </summary>
public PopupContentBuilder AddText(string text, PopupElementType elementType) {
var go = view.GetElement(elementType);
if(go == null) {
return this;
}
var tmp = go.GetComponentInChildren<TMP_Text>();
if(tmp) {
tmp.text = text;
}
return this;
}
/// <summary>
/// Adds a body text element.
/// Adds a colored text element using the given element type.
/// Hex color can be with or without the # prefix.
/// </summary>
public PopupContentBuilder AddText(string text) {
var label = view.GetText();
label.text = text;
return this;
}
/// <summary>
/// Adds a colored body text element. Hex color can be with or without the # prefix.
/// </summary>
public PopupContentBuilder AddText(string text, string hexColor) {
var label = view.GetText();
public PopupContentBuilder AddText(string text, string hexColor, PopupElementType elementType) {
var go = view.GetElement(elementType);
if(!go) {
return this;
}
var tmp = go.GetComponentInChildren<TMP_Text>();
if(!tmp) {
return this;
}
var prefix = hexColor.Length > 0 && hexColor[0] == '#' ? "" : "#";
label.text = $"<color={prefix}{hexColor}>{text}</color>";
tmp.text = $"<color={prefix}{hexColor}>{text}</color>";
return this;
}
/// <summary>
/// Adds a stat row with a label and integer value.
/// Adds a name/value row using the given element type. The prefab must have
/// exactly two TMP_Text children (label first, value second).
/// </summary>
public PopupContentBuilder AddStat(string label, int value) {
var (labelText, valueText) = view.GetStat();
labelText.text = label;
valueText.text = value.ToString();
return this;
public PopupContentBuilder AddNameValue(string label, int value, PopupElementType elementType) {
return AddNameValueInternal(elementType, label, value.ToString());
}
/// <summary>
/// Adds a stat row with a label and string value.
/// Adds a name/value row using the given element type. The prefab must have
/// exactly two TMP_Text children (label first, value second).
/// </summary>
public PopupContentBuilder AddStat(string label, string value) {
var (labelText, valueText) = view.GetStat();
labelText.text = label;
valueText.text = value;
public PopupContentBuilder AddNameValue(string label, string value, PopupElementType elementType) {
return AddNameValueInternal(elementType, label, value);
}
private PopupContentBuilder AddNameValueInternal(PopupElementType elementType, string label, string value) {
var go = view.GetElement(elementType);
if(go != null) {
var children = go.GetComponentsInChildren<TMP_Text>(true);
if(children.Length >= 2) {
children[0].text = label;
children[1].text = value;
}
}
return this;
}
/// <summary>
/// Adds an image element with the given sprite and optional height.
/// </summary>
public PopupContentBuilder AddImage(Sprite sprite, float height = 64f) {
var image = view.GetImage();
image.sprite = sprite;
var rt = (RectTransform)image.transform;
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
public PopupContentBuilder AddImage(Sprite sprite, PopupElementType elementType, float height = 64f) {
var go = view.GetElement(elementType);
if(go != null) {
var image = go.GetComponentInChildren<Image>();
if(image != null) {
image.sprite = sprite;
var rt = (RectTransform)image.transform;
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
}
}
return this;
}
/// <summary>
/// Adds a horizontal separator line.
/// Adds a separator element using the given element type.
/// </summary>
public PopupContentBuilder AddSeparator() {
view.GetSeparator();
public PopupContentBuilder AddSeparator(PopupElementType elementType) {
view.GetElement(elementType);
return this;
}
}