-
Notifications
You must be signed in to change notification settings - Fork 0
GUI
Namespaces: ScavLib.gui.ugui (uGUI) | ScavLib.gui.imgui (IMGUI)
ScavLib ships two parallel GUI stacks:
-
uGUI (
ScavLib.gui.ugui) — the primary, player-facing UI. Built on Unity's UI / TextMeshPro, themeable, draggable, and able to block game-world clicks. Use this for menus your players actually interact with. -
IMGUI (
ScavLib.gui.imgui) — a lightweight debug / development immediate-mode window stack. Quick to throw together for testing, but not intended as the shipping UI for a polished mod.
Both work in the main menu and in-game. When in doubt, build player-facing features with uGUI and reserve IMGUI for debug panels.
Renamed in 0.6.0: The old
ScavLib.guiIMGUI types (MenuWindow,MenuBuilder,MenuManager) were moved intoScavLib.gui.imguiand renamed toImguiWindow,ImguiMenuBuilder,ImguiMenuManager. See the Changelog for migration notes.
Inherit UguiWindowBase and implement Build(UguiBuilder). Controls are added
once at build time, each wired to a callback — unlike IMGUI, you do not
redraw every frame.
using ScavLib.gui.ugui;
using ScavLib.util;
using UnityEngine;
public class MyModUguiMenu : UguiWindowBase
{
public override string Title => "My Mod";
public override KeyCode ToggleKey => KeyCode.F5;
protected override void Build(UguiBuilder b)
{
b.AddLabel("Player Controls");
b.AddSeparator();
b.AddButton("Heal All", () => PlayerUtil.HealAll());
b.AddToggle("God Mode", false, on =>
{
GameUtil.Log($"God mode: {on}");
});
b.AddSlider("Heal Amount", 0f, 100f, 50f, v =>
{
GameUtil.Log($"Heal amount set to {v:F0}");
});
}
}Register it in your plugin's Awake():
private void Awake()
{
UguiWindowBase.Register(new MyModUguiMenu());
}The window builds lazily the first time it is shown, then toggles with F5.
| Member | Type | Default | Description |
|---|---|---|---|
Title |
string |
— | Title bar text. An empty title hides the title bar. |
ToggleKey |
KeyCode |
KeyCode.None |
Hotkey to show/hide. None disables hotkey toggling. |
Width |
float |
Theme.Metrics.WindowDefaultSize.x (400) |
Window width. Override for a fixed width. |
Height |
float |
Theme.Metrics.WindowDefaultSize.y (300) |
Window height. Override for a fixed height. |
Theme |
UguiTheme |
UguiTheme.Default |
Visual theme. Override to reskin. |
ShowInMenu |
bool |
false |
If true, the window is also usable in the main menu (no PlayerCamera). |
DefaultDraggable |
bool |
true |
Initial draggable state. |
Draggable |
bool (read-only) |
— | Current draggable state. Change at runtime via SetDraggable. |
DefaultBlockGameInput |
bool |
true |
Initial click-blocking state. |
BlockGameInput |
bool |
— | Runtime flag. When true, a click on this window does not pass through to the game world. |
IsVisible |
bool (read-only) |
false |
Current visibility. |
Root |
RectTransform (read-only) |
— | The built window root. null until first shown. |
| Method | Description |
|---|---|
Build(UguiBuilder builder) |
Abstract. Implement to populate the window with controls. |
Show() |
Build (if needed) and show the window. |
Hide() |
Hide the window. |
Toggle() |
Toggle visibility. |
SetDraggable(bool) |
Enable/disable dragging at runtime. |
OnShow() / OnHide()
|
Optional overrides called when the window is shown/hidden. |
UguiWindowBase.Register(window) |
Static. Register a window so its hotkey is polled. Call in Awake(). |
Click-blocking: While a visible window has
BlockGameInput = true, clicking on it will not trigger world-space actions (item pickup, etc.). Clicks on empty space still pass through. Set it tofalsefor purely informational HUD overlays that should not eat input.
Close button: Windows show an X close button in the top-right of the title bar by default. It is suppressed automatically when the title bar is hidden. Its size and right-edge padding are theme metrics (see UguiTheme).
All controls are added inside Build(). Each returns the underlying Unity
component (or a ScavLib handle) so you can hold a reference and update it later
(e.g. an AddProgressBar handle whose Fill you set each frame from your own
code, or an AddDropdown handle you drive with SetIndex).
| Method | Returns | Description |
|---|---|---|
AddLabel(string text) |
TextMeshProUGUI |
A non-interactive text row. |
AddImage(Sprite sprite, float pixelSize = 3f, float? maxSize = null) |
Image |
Display a sprite, sized from its texture by pixelSize (pixel multiplier) capped at maxSize. Non-interactive by default. Returns null for a null sprite. |
AddImage(string spriteName, float pixelSize = 3f, float? maxSize = null) |
Image |
Same as above, but looks the sprite up by resource name (exact match first, then contains). |
AddSeparator() |
void |
A horizontal divider row. |
AddSpace(float pixels = -1f) |
void |
Vertical empty space. Negative uses the theme's default spacing. |
| Method | Returns | Description |
|---|---|---|
AddButton(string label, Action onClick) |
Button |
A button; onClick fires when clicked. |
AddToggle(string label, bool initial, Action<bool> onChange = null) |
Toggle |
A checkbox; onChange receives the new value. |
AddSlider(string label, float min, float max, float initial, Action<float> onChange = null) |
Slider |
A labelled slider. The label auto-updates with the current value. |
AddInputField(string initialText = "", string placeholder = "", Action<string> onValueChanged = null, Action<string> onEndEdit = null) |
TMP_InputField |
A single-line text field. onValueChanged fires each keystroke; onEndEdit fires on focus loss / Enter. |
AddNumberField(float initial = 0f, float step = 1f, float min = float.MinValue, float max = float.MaxValue, bool isInteger = false, Action<float> onChange = null) |
UguiNumberField |
A numeric stepper [ - ][ field ][ + ]. Clamps to min/max; isInteger rounds to whole numbers. |
AddDropdown(IList<string> options, int initialIndex = 0, Action<int> onChange = null) |
UguiDropdown |
A self-contained dropdown. Options expand on a global overlay and collapse on outside click. |
AddToggleGroup(IList<string> options, int initialIndex = 0, UguiToggleGroupStyle style = Checkbox, Action<int> onChange = null) |
UguiToggleGroup |
A mutually exclusive selector. Checkbox renders one labelled checkbox per row; Buttons renders a single row of equal-width buttons. |
| Method | Returns | Description |
|---|---|---|
AddProgressBar(float initial01 = 0f) |
UguiPixelBar |
A pixel-snapped fill bar (0~1). Set .Fill to update. |
AddScrollView(float height) |
(ScrollRect, RectTransform) |
A vertical scroll area with a scrollbar. Parent further content under the returned RectTransform. |
BeginHorizontal(float rowHeight = -1f) |
UguiHorizontalRow |
Begin a horizontal row to place controls side by side. See Layout Containers. |
BeginTabs() |
UguiTabView |
Begin a tabbed view. See Layout Containers. |
Note on slider arguments: uGUI's
AddSlidertakes(label, min, max, initial)— min/max come before the initial value. This differs from IMGUI'sSlider(label, value, min, max).
protected override void Build(UguiBuilder b)
{
var hpBar = b.AddProgressBar(1f);
b.AddButton("Take 10 Damage", () =>
{
float hp = PlayerUtil.GetBrainHealth();
hpBar.Fill = Mathf.Clamp01((hp - 10f) / 100f);
});
var name = b.AddInputField("", "Enter a name...", onEndEdit: v =>
GameUtil.Log($"Name set to {v}"));
var qty = b.AddNumberField(1f, step: 1f, min: 0f, max: 99f, isInteger: true,
onChange: v => GameUtil.Log($"Quantity: {v}"));
var mode = b.AddDropdown(new[] { "Easy", "Normal", "Hard" }, 1, i =>
GameUtil.Log($"Mode index {i}"));
var (scroll, content) = b.AddScrollView(120f);
// Build additional rows under `content` with another UguiBuilder if needed.
}A few controls return ScavLib handles rather than raw Unity components.
| Member | Description |
|---|---|
Value |
Read-only current value. |
Step(int direction) |
Apply one increment (+1) or decrement (-1) of the configured step. |
SetValue(float v, bool notify) |
Set the value programmatically (clamped/rounded). Pass notify: false to suppress onChange. |
| Member | Description |
|---|---|
Index |
Read-only selected index. |
SelectedText |
Read-only text of the current selection. |
SetIndex(int index, bool notify = true) |
Select an option programmatically. |
| Member | Description |
|---|---|
SelectedIndex |
Read-only selected index. |
SetSelected(int index, ...) |
Select an option programmatically. |
UguiToggleGroupStyle has two values: Checkbox (one labelled checkbox per
row) and Buttons (a single row of equal-width buttons).
BeginHorizontal() returns a UguiHorizontalRow that places controls left to
right within one row. It implements IDisposable, so a using block settles
the row (pushes its height back to the layout) automatically.
| Method | Description |
|---|---|
AddSmallButton(string label, Action onClick, float fixedWidth) |
A fixed-width small button. |
AddSmallButton(string label, Action onClick) |
A small button sized to fit its text. |
AddFlexibleSmallButton(string label, Action onClick) |
Registers a button that shares the row's remaining width equally with other flexible buttons (laid out when the row settles). |
End() / Dispose()
|
Settle the row. Called automatically at the end of a using block. |
protected override void Build(UguiBuilder b)
{
using (var row = b.BeginHorizontal())
{
row.AddSmallButton("Save", () => GameUtil.Log("save"));
row.AddSmallButton("Load", () => GameUtil.Log("load"));
row.AddFlexibleSmallButton("Reset", () => GameUtil.Log("reset"));
}
}BeginTabs() returns a UguiTabView. Add pages with
AddTab(name, buildPage), where buildPage receives a fresh UguiBuilder for
that page's content. It is also IDisposable; a using block defaults to the
first page and completes initial layout on exit.
| Method | Description |
|---|---|
AddTab(string name, Action<UguiBuilder> buildPage) |
Add a page: tab label + a callback that builds the page contents. |
Select(int index) |
Show the page at index, hide the rest, and re-layout. |
ActiveIndex |
Read-only current page index (-1 before the first selection). |
End() / Dispose()
|
Settle the view (selects the first page). Called automatically at the end of a using block. |
protected override void Build(UguiBuilder b)
{
using (var tabs = b.BeginTabs())
{
tabs.AddTab("General", page =>
{
page.AddLabel("General settings");
page.AddToggle("God Mode", false);
});
tabs.AddTab("Advanced", page =>
{
page.AddSlider("Spawn Rate", 0f, 10f, 1f);
});
}
}A shared overlay layer backs both tooltips and dropdowns. It renders on a single persistent canvas that stays above open windows and survives scene transitions, so tooltips and expanded dropdowns are never clipped by a window.
Attach a hover tooltip to any control with the chainable WithTooltip
extension. It works on the value returned by any Add... call (any
Component) as well as on a GameObject, and returns the same object so you
can keep chaining.
b.AddButton("Heal All", () => PlayerUtil.HealAll())
.WithTooltip("Heal All", "Restores every limb and clears status effects.");
b.AddToggle("God Mode", false)
.WithTooltip("God Mode"); // name only; description is optionalScavLib's tooltips are deliberately isolated from the game's native tooltip system. A control carrying a ScavLib tooltip will not also trigger a duplicate game-native tooltip.
UguiTheme is an immutable bundle of all visual/layout parameters. Use
UguiTheme.Default for the stock look (matches the game's native style), or
derive a variant with chainable With... methods. Each call returns a new
theme; the original (including Default) is never mutated.
public override UguiTheme Theme =>
UguiTheme.Default
.WithWindowSize(500f, 360f)
.WithRowSpacing(8f)
.WithTitleAlignment(UguiTheme.TitleAlign.Center);| Method | Description |
|---|---|
WithWindowSize(width, height) |
Default window size (used when Width/Height are not overridden). |
WithRowHeight(float) |
Height of each control row. |
WithRowSpacing(float) |
Gap between control rows. |
WithDefaultSpace(float) |
Default pixel size used by AddSpace(). |
WithHeaderHeight(float) |
Title bar height. |
WithContentPadding(float) / (l, r, t, b)
|
Inner padding between the window edge and the content area. |
WithPanelColor(Color) |
Fallback panel background color (header follows it). |
WithHeaderBg(Color) |
Header background color only (advanced). |
WithHiddenTitle(bool = true) |
Hide the entire title bar (highest priority). |
WithTitleAlignment(TitleAlign) |
Left / Center / Right title alignment. |
WithTitlePadding(float) / (l, r, t, b)
|
Title text padding (independent of content padding). |
Title knob priority (high → low):
HideTitle>TitleAlignment>TitlePadding. Hiding the title disables alignment and all title padding; non-Leftalignment disables left/right title padding (top/bottom still apply). Title padding and content padding are two independent sets of fields.
Beyond the knobs above, UguiTheme.Metrics carries the layout values that
drive the full control set — small-button sizing, tab header height,
input-field height and padding, stepper-button width, dropdown arrow width /
row height / max visible rows, tooltip width / padding / cursor offset,
toggle-group button height, default image max size, scrollbar width, and the
title-bar close-button size / right padding (with ShowCloseButton enabled by
default). These match sensible internal defaults that mirror the game's native
look.
Font choices, nine-slice sprite names, outline distances, and checkmark/slider
pixel metrics are locked to sensible internal defaults and are not exposed
through With... methods.
The handle returned by AddProgressBar. Set Fill (clamped 0~1) to update the
bar; when backed by a sprite it snaps to whole texture pixels for a crisp,
retro look.
var bar = builder.AddProgressBar(0.5f);
bar.Fill = 0.75f;A lightweight immediate-mode window stack for debug panels. Inherit
ImguiWindow, draw controls with ImguiMenuBuilder inside DrawContent(),
and register with ImguiMenuManager. Unlike uGUI, DrawContent() runs every
frame and interactive controls are polled by return value.
using ScavLib.gui.imgui;
using ScavLib.util;
using UnityEngine;
public class MyModDebugMenu : ImguiWindow
{
public override string Title => "My Mod (Debug)";
public override KeyCode ToggleKey => KeyCode.F6;
public override float Width => 280f;
// Height defaults to 0, which enables true auto-height.
protected override void DrawContent()
{
ImguiMenuBuilder.Label($"Hunger: {PlayerUtil.GetHunger():F1}");
ImguiMenuBuilder.Separator();
if (ImguiMenuBuilder.Button("Heal All"))
PlayerUtil.HealAll();
if (ImguiMenuBuilder.Button("Max Hunger"))
PlayerUtil.Feed(100f);
}
}Register in Awake():
private void Awake()
{
ImguiMenuManager.Register(new MyModDebugMenu());
}| Property | Type | Default | Description |
|---|---|---|---|
Title |
string |
— | Title bar text. |
ToggleKey |
KeyCode |
KeyCode.None |
Hotkey to show/hide. |
Width |
float |
300f |
Window width in pixels. |
Height |
float |
0f |
0 = auto-height (resizes to content). Set a value to fix it. |
InitialPosition |
Vector2 |
Screen center | Starting position on first render. |
Layer |
int |
0 |
Render order. Lower value renders on top. |
ShowInMenu |
bool |
false |
If true, also active in the main menu. |
IsVisible |
bool (read-only) |
false |
Current visibility. |
| Method | Description |
|---|---|
DrawContent() |
Abstract. Draw the window's controls here (called every frame). |
Show() / Hide() / Toggle()
|
Visibility control. |
OnShow() / OnHide()
|
Optional overrides on open/close. |
All methods must be called from within DrawContent().
| Method | Description |
|---|---|
Label(string text) |
Non-interactive text label. |
Separator() |
Horizontal divider line. |
Space(float pixels = 8f) |
Vertical empty space. |
| Method | Returns | Description |
|---|---|---|
Button(string label) |
bool |
true on the frame it is clicked. |
Toggle(string label, bool value) |
bool |
Checkbox. Returns the new value. |
Slider(string label, float value, float min, float max) |
float |
Slider with label. Returns the new value. |
| Method | Description |
|---|---|
SliderConfig(string label, ConfigEntry<float> entry, float min, float max) |
Slider bound directly to a float config entry. |
ToggleConfig(string label, ConfigEntry<bool> entry) |
Toggle bound directly to a bool config entry. |
| Method | Description |
|---|---|
BeginHorizontal() / EndHorizontal()
|
Horizontal layout group. |
BeginScroll(ref Vector2 scrollPos) / EndScroll()
|
Scrollable area. |
private Vector2 _scroll;
protected override void DrawContent()
{
ImguiMenuBuilder.BeginScroll(ref _scroll);
foreach (var id in ItemUtil.GetAllIds())
ImguiMenuBuilder.Label(id);
ImguiMenuBuilder.EndScroll();
}ImguiMenuManager assigns a unique IMGUI window ID (starting at 9000) to each
registered window automatically. Do not assign window IDs manually.
IMGUI hotkey detection is suspended while the developer console is open, so menu toggle keys will not fire accidentally during console input.