Drawing

ui

Windows and widgets, built on Dear ImGui.

ui draws windows and widgets with Dear ImGui, the same toolkit as the plugins' own windows. It only works inside on_render. If you know ImGui, the names are the same in snake_case.

local enabled, range, mode = true, 600, 1

function on_render()
    ui.set_next_window_size(Vec2(320, 0), ui.Cond.FirstUseEver)
    local _, visible = ui.begin_window("My plugin")
    if visible then
        local changed
        changed, enabled = ui.checkbox("Enabled", enabled)
        changed, range = ui.slider_float("Range", range, 100, 1500, "%.0f")
        changed, mode = ui.combo("Mode", mode, { "Closest", "Weakest", "Strongest" })
        if ui.button("Reset") then range = 600 end
    end
    ui.end_window()
end

Rules

  • Widgets that hold a value take the current value and return changed, new_value. Store the new value; nothing is kept for you.
  • Every begin_* and push_* needs its end_* or pop_*. begin_window and begin_child need their end always; the ones that return whether they're open (tree_node, begin_menu, begin_table, begin_tab_item, popups) only when they returned true.
  • An end_* that doesn't match is a Lua error, and whatever is still open when on_render returns is closed for you, with a warning.
  • A label is also the widget's id, so two widgets with the same label in one window clash. Add ## and something unique after the visible text ("Delete##3"), or wrap them in push_id/pop_id.
  • Indices (combos, list boxes, table columns) start at 1.
  • Flags are numbers from the tables in ui flags; combine several with |.

Windows

Starts a window. With open, the window has a close button and open comes back false once it's clicked. visible is false while it's collapsed. Always call ui.end_window().
Ends the window.
A scrolling region inside a window. Always call ui.end_child().
Ends the child region.
Places the next window. cond is a ui.Cond value, such as ui.Cond.FirstUseEver to only do it the first time.
Sizes the next window. A 0 width or height fits the content.
Limits how small and large the next window can be.
The current window's position.
The current window's size.
Whether it has focus (ui.FocusedFlags).
Whether the mouse is over it (ui.HoveredFlags).
Whether it's showing for the first frame.
Whether it's collapsed.

Text

A line of text. Several values are joined with spaces.
Text that wraps at the window's edge.
Text with a bullet.
A bullet, for the next item on the line.
Text that works as a button: no frame, true when clicked.
A tooltip by the mouse. Usually after if ui.is_item_hovered() then.
Starts a tooltip with any content. End it with ui.end_tooltip().

Buttons and choices

True when clicked.
A square button with an arrow; dir is a ui.Dir value.
A row that highlights and can be clicked.
A checkbox.
One radio button of a group: it's on when current == this_value, and clicking sets current to this_value.
A dropdown of strings.
A list of strings to pick from.
A color picker, with alpha unless flags has ui.ColorEditFlags.NoAlpha.

Inputs, sliders and drags

format is a printf format such as "%.1f" or "%d ms".

A text box (256 characters by default).
A text box showing hint while empty.
A multi-line text box (4096 characters by default).
An integer box with +/- buttons.
Two number boxes. ui.input_vec3 takes a Vec3.
Two drag fields. ui.drag_vec3 takes a Vec3.
Two sliders. ui.slider_vec3 takes a Vec3.

Images, bars and plots

Draws an image: a game icon (item:icon(), skill.icon...) or one loaded with gfx.image_from_png.
A bar filled from 0 to 1, with optional text on it.

Layout

Puts the next item on the same line.
Ends the line.
A horizontal line.
A little vertical space.
Indents what follows. ui.unindent([width]) undoes it.
Lines text up with the buttons and boxes next to it.
Groups items so they act as one (for same_line or hover checks). End with ui.end_group().
Grays out and disables what follows. End with ui.end_disabled().
Makes the labels that follow unique, for lists of similar widgets. End with ui.pop_id().
Sets the width of the widgets that follow. End with ui.pop_item_width().
Sets the next widget's width.
The width the next widget would get.
Wraps text at x. End with ui.pop_text_wrap_pos().
Changes a color, such as ui.Col.Text. End with ui.pop_style_color([count]).
Changes spacing or padding, such as ui.StyleVar.ItemSpacing. End with ui.pop_style_var([count]).
"DEFAULT", "MENU" or "HEADER". End with ui.pop_font().
The current font's size in pixels.
The scale applied to all text.
Sets it, between 0.25 and 4.
How big a text is drawn.
The height of a line of text.
The same, with the space between lines.
The height of a button or box.
The same, with the space after it.
The space left in the window.
Where the next item goes, in the window.
Moves where the next item goes.
Where the next item goes, on screen.
Moves it, in screen coordinates.
How far the window is scrolled.
How far it can scroll.
Scrolls the window to the end, for logs.

Trees and headers

A header that opens and closes its section. Nothing to end.
A node that unfolds. When it returns true, call ui.tree_pop() after its content.
Ends an open tree node.
Opens or closes the next tree node or header.

Popups

A modal popup. Call ui.end_popup() when visible.
A right-click menu on the last item. Call ui.end_popup() when true.
Ends the popup.
Closes the popup you're in.
A menu bar in a window made with ui.WindowFlags.MenuBar. Call ui.end_menubar() when true.
The menu bar at the top of the screen. Call ui.end_main_menubar() when true.
A menu. Call ui.end_menu() when true.
An item in a menu, optionally with a check mark.

Tabs

A row of tabs. Call ui.end_tab_bar() when true.
A tab. Its content follows when selected; then call ui.end_tab_item(). With open, the tab has a close button.

Tables

if ui.begin_table("players", 2, ui.TableFlags.Borders | ui.TableFlags.RowBg) then
    ui.table_setup_column("Name")
    ui.table_setup_column("Health")
    ui.table_headers_row()
    for _, p in ipairs(agents.players()) do
        ui.table_next_row()
        ui.table_next_column(); ui.text(p:name() or "?")
        ui.table_next_column(); ui.text(string.format("%.0f%%", p:health().percent))
    end
    ui.end_table()
end
A table with 1 to 64 columns. Call ui.end_table() when true.
Names a column. Before the first row, once per column.
A row of column names.
Moves to the next cell.
Moves to a cell of the row, from 1.
The current column, from 1.
The current row.
The current column's width.
Colors a row or cell; target is a ui.TableBgTarget value.

Drag and drop

Payloads are strings, with a type name of up to 32 characters.

Makes the last item draggable. When true, set a payload and call ui.end_drag_drop_source().
What's being dragged.
Makes the last item a drop target. When true, call ui.end_drag_drop_target().
The payload, once dropped here.

Drawing in a window

ui.draw draws shapes into the current window, in screen coordinates. Start from ui.get_cursor_screen_pos().

Items, keys and the mouse

Keys here are ui.Key values; mouse buttons are 0 (left), 1 (right) and 2 (middle).

Whether the mouse is over the last item.
Whether the last item was clicked.
Whether the last item is being used (held, dragged, typed in).
Whether it has keyboard focus.
Whether the mouse is over any item.
Whether any item is in use.
Whether any item has focus.
Focuses the last item when its window appears.
Whether a key is held.
Whether a key was pressed this frame.
Whether a key was released this frame.
Whether a mouse button is held.
Whether it was clicked this frame.
Whether it was released this frame.
Whether it was double-clicked.
How many clicks in a row.
Whether the mouse is being dragged.
Whether any mouse button is held.
The mouse position on screen.
Whether drawing is possible now (inside on_render).