ValueComparison is a reusable utility for showing changes between two values in UI (old -> new), with optional increase/decrease coloring.

It is designed to be domain-agnostic: inventory, RPG stats, settings diffs, save slot comparisons, and more.

Types

ValueDeltaType

Represents the direction of change:

  • NEUTRAL
  • INCREASE
  • DECREASE

ValueComparisonLine

Data model for one comparison row.

csharp
public struct ValueComparisonLine { public string Key; public string Name; public Sprite Icon; public string OldValue; public string NewValue; public ValueDeltaType DeltaType; public bool HideOldValue; }

Use GetDeltaType(float value, float comparisonValue) to compute the delta state for numeric comparisons.

ValueComparisonLineController

UI Toolkit controller that renders a single ValueComparisonLine.

Features:

  • optional name and icon
  • old/new value presentation
  • arrow between values
  • delta-based color formatting for new value
  • optional tooltip support through TooltipController

Basic Usage

The controller builds its own row elements in C# — all your UXML needs is a host element to parent it under. Assign this UXML to the PanelRenderer's Source Asset:

xml
<ui:UXML xmlns:ui="UnityEngine.UIElements"> <ui:VisualElement> <ui:VisualElement name="ComparisonHost" /> </ui:VisualElement> </ui:UXML>

The generated row uses Luna utility classes internally (flex-row, items-center, size-36, the icon-arrow-right arrow), so the panel's Panel Settings must point at the Luna theme — see Theme Stack.

csharp
using CupkekGames.Luna; using UnityEngine; using UnityEngine.UIElements; public class ValueComparisonExample : MonoBehaviour { [SerializeField] private PanelRenderer _panelRenderer; private ValueComparisonLineController _controller; private void Awake() { if (_panelRenderer == null) { _panelRenderer = GetComponent<PanelRenderer>(); } if (_panelRenderer != null) { _panelRenderer.RegisterUIReloadCallback(OnUIReload); } } // PanelRenderer delivers the visual tree asynchronously — // query elements in the reload callback, not in Awake/Start. private void OnUIReload(PanelRenderer renderer, VisualElement root, int version) { if (_controller != null) return; // sentinel: only init once VisualElement host = root.Q<VisualElement>("ComparisonHost"); float oldValue = 12f; float newValue = 17f; ValueDeltaType delta = ValueComparisonLine.GetDeltaType(newValue, oldValue); var line = new ValueComparisonLine( key: "Damage", name: "Damage", icon: null, oldValue: oldValue.ToString(), newValue: newValue.ToString(), deltaType: delta, hideOldValue: false ); _controller = new ValueComparisonLineController(host, withName: true, withIcon: false); _controller.SetData(line); } private void OnDestroy() { if (_panelRenderer != null) { _panelRenderer.UnregisterUIReloadCallback(OnUIReload); } } }

Migration Notes

If you previously used item-specific stat line utilities:

  • ItemStatChangeType -> ValueDeltaType
  • ItemStatLine -> ValueComparisonLine
  • ItemStatLineController -> ValueComparisonLineController

ItemStatDataController still lives in Inventory because it depends on ItemStatData, but now uses these generic value-comparison utilities internally.

See also

  • Tooltip — the TooltipController the optional per-line tooltips run through
  • Inventory view — equipment stat diffs, the pattern's flagship consumer
  • Theme Stack — the theme wiring the generated rows depend on

Settings

Theme

Light

Contrast

Material

Dark

Dim

Material Dark

System

Sidebar(Light & Contrast only)

Light
Dark

Font Family

DM Sans

Wix

Inclusive Sans

AR One Sans

Direction

LTR
RTL