Skip to content

Windows and menus

Mods draw with the game's own Dear ImGui, so windows look and behave like the game's.

Windows

Draw windows in gui(dt). A window is everything between begin and end; call end() even when begin returns false (the window is collapsed):

fn init() {
    this.on = false;
    this.warp = 1.0;
}

fn gui(dt) {
    if begin("My mod") {
        text("Hello");
        if button("Click me") {
            print("clicked");
        }
        same_line();
        text("next to the button");
        separator();
        this.on = checkbox("Enabled", this.on);
        this.warp = slider("Warp", this.warp, 1.0, 100.0);
        if header("More") {
            text("only while the section is open");
        }
    }
    end();
}
Function Does
begin(title) / end() A window. The title is also its identity: two windows with one title are one window.
text(s) A line of text.
button(label) A button; true on the frame it is clicked.
checkbox(label, value) A checkbox; returns the new value.
slider(label, value, min, max) A slider for a number; returns the new value.
same_line() Puts the next widget on the same line.
separator() A horizontal line.
header(label) A collapsible section; true while open.

More widgets

Oxidizer 0.8 and later:

fn init() {
    this.name = "Jeb";
    this.notes = "";
    this.mass = 1.5;
}

fn gui(dt) {
    set_next_window_size(420.0, 320.0);              // the size the first time the window opens
    if begin("My mod") {
        text_colored([1.0, 0.6, 0.2], "orange");     // [r, g, b] or [r, g, b, a], 0 to 1
        this.name = input_text("Name", this.name);   // returns the text after this frame's typing
        this.mass = input_float("Mass", this.mass);
        if begin_tab_bar("tabs") {
            if begin_tab("Notes") {
                this.notes = input_multiline("##notes", this.notes, 300.0, 120.0);
                end_tab();
            }
            if begin_tab("About") {
                text("second tab");
                end_tab();
            }
            end_tab_bar();
        }
        begin_child("log", 80.0);                    // a scrolling box; 0 height fills the window
        text("...");
        end_child();
        if ctrl_shortcut("s") {                      // Ctrl+S, also while typing in a field
            print("saved");
        }
    }
    end();
}
Function Does
text_colored(color, s) Text in a color: [r, g, b] or [r, g, b, a], each 0 to 1.
input_text(label, text) A one-line text field; returns the text after this frame's edits.
input_multiline(label, text, width, height) A multi-line text box (Tab types a tab); returns the text. A negative width or height fills the window except that many pixels.
input_float(label, value) A number field; returns the new value.
begin_tab_bar(id) / end_tab_bar() Tabs; call end_tab_bar() only when begin_tab_bar returned true.
begin_tab(label) / end_tab() A tab; true while it is selected, then call end_tab().
begin_child(id, height) / end_child() A scrolling region with a border; call end_child() always.
set_next_window_size(width, height) The next window's size the first time it is shown.
ctrl_shortcut(key) True on the frame Ctrl and the letter were pressed, also while typing in a text field.

Store what the text and number functions return, as with checkbox: a field shows what you pass in, so input_text("Name", this.name) without storing the result would undo the player's typing every frame. Sizes are floats: write 300.0, not 300.

Widgets in one window need different labels. To show the same label twice, add ## and something unique: button("Go##1"), button("Go##2"). Only the part before ## is shown.

The Mods menu

menu() runs while the game's Mods menu is open. Add entries with menu_item:

fn menu() {
    if menu_item("My mod", this.visible) {   // shown with a check mark while this.visible is true
        this.visible = !this.visible;
    }
}

menu_item(label) is an entry without a check mark. For a submenu, if begin_menu("My mod") { ...entries...; end_menu(); } (call end_menu only when begin_menu returned true).

The common pattern is a window that the menu entry shows and hides, as above, plus if !this.visible { return; } at the start of gui.