Skip to content
Kanisuko edited this page Jun 1, 2026 · 3 revisions

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.gui IMGUI types (MenuWindow, MenuBuilder, MenuManager) were moved into ScavLib.gui.imgui and renamed to ImguiWindow, ImguiMenuBuilder, ImguiMenuManager. See the Changelog for migration notes.


uGUI (Recommend for Player-Facing)

Creating a Window

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.


UguiWindowBase Members

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.

Methods

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 to false for purely informational HUD overlays that should not eat input.


UguiBuilder Controls

All controls are added inside Build(). Each returns the underlying Unity component 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).

Method Returns Description
AddLabel(string text) TextMeshProUGUI A non-interactive text row.
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.
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. Parent further content under the returned RectTransform.
AddSeparator() void A horizontal divider row.
AddSpace(float pixels = -1f) void Vertical empty space. Negative uses the theme's default spacing.

Note on slider arguments: uGUI's AddSlider takes (label, min, max, initial) — min/max come before the initial value. This differs from IMGUI's Slider(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 (scroll, content) = b.AddScrollView(120f);
    // Build additional rows under `content` with another UguiBuilder if needed.
}

UguiTheme

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);

Common knobs

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-Left alignment disables left/right title padding (top/bottom still apply). Title padding and content padding are two independent sets of fields.

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.


UguiPixelBar

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;

IMGUI (Recommend for Debug)

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.

Creating a Window

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());
}

ImguiWindow Properties

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.

Methods

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.

ImguiMenuBuilder Controls

All methods must be called from within DrawContent().

Display

Method Description
Label(string text) Non-interactive text label.
Separator() Horizontal divider line.
Space(float pixels = 8f) Vertical empty space.

Interaction

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.

BepInEx Config Binding

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.

Layout

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();
}

Window ID Management

ImguiMenuManager assigns a unique IMGUI window ID (starting at 9000) to each registered window automatically. Do not assign window IDs manually.

Console Conflict Prevention

IMGUI hotkey detection is suspended while the developer console is open, so menu toggle keys will not fire accidentally during console input.

Clone this wiki locally