Skip to content

Screens, widgets and 2d drawing

Status: Partly implemented. 2D drawing in HUD layers and screens (cl_gui_*), custom screens with vanilla widgets (button, checkbox, slider, text field, label) and their callbacks. Not yet: cl_gui_blit of texture files draws nothing (use GUI atlas sprites), cl_gui_item draws the item’s flat icon without the durability bar, text is drawn without formatting codes or styles, and a screen’s char_typed callback is not called. An immediate-mode widget layer, lists and more widgets are Planned.

Function tables: gui, screen. Client only. HUD layers: HUD layers. Document screens: GUI screens (RmlUi).

2D drawing (cl_gui)

A cl_gui draw context is passed to a HUD layer’s or a screen’s render callback and is valid only during that call. Coordinates are GUI pixels (after the GUI scale), origin top left, like vanilla GuiGraphics. Colours are 0xAARRGGBB; an alpha of 0 counts as opaque, so 0xRRGGBB works like vanilla text colours.

C Lua (g:...) Does
cl_gui_width(g), cl_gui_height(g), cl_gui_scale_factor(g) g:width(), g:height(), g:scale_factor() The scaled screen size and the GUI scale
cl_gui_fill(g, x0, y0, x1, y1, argb) g:fill(...) A rectangle
cl_gui_fill_gradient(g, x0, y0, x1, y1, top, bottom) g:fill_gradient(...) A vertical gradient
cl_gui_outline(g, x, y, w, h, argb) g:outline(...) A 1-pixel outline
cl_gui_text(g, s, x, y, argb, shadow) → end x g:text(s, x, y, argb, shadow) Text in the vanilla font
cl_gui_text_component(g, text, x, y, argb, shadow) g:text_component(t, ...) A text component (its plain text today)
cl_gui_text_centered(g, s, cx, y, argb, shadow) g:text_centered(...) Centred on cx
cl_gui_text_width(s), cl_gui_line_height() cl.gui.text_width(s), cl.gui.line_height() Measure text
cl_gui_sprite(g, sprite, x, y, w, h) g:sprite(...) A GUI atlas sprite: "minecraft:hud/heart/full", or "<modid>:<path>" from assets/<modid>/textures/gui/sprites/<path>.png
cl_gui_blit(g, texture, x, y, w, h, u0, v0, u1, v1, tint) g:blit(...) Any texture (draws nothing yet)
cl_gui_item(g, stack, x, y, decorations), cl_gui_item_by_name(g, id, x, y) g:item(stack, x, y, true), g:item_by_name("minecraft:apple", x, y) A 16x16 item icon (and its count)
cl_gui_push_pose, cl_gui_pop_pose, cl_gui_translate(g, x, y), cl_gui_scale(g, x, y) g:push_pose(), … Move or scale what follows
cl_gui_push_scissor(g, x0, y0, x1, y1), cl_gui_pop_scissor g:push_scissor(...), … Clip to a rectangle (nested clips intersect)
cl_gui_tooltip(g, s, x, y) g:tooltip("Line 1\nLine 2", mx, my) A vanilla tooltip box

A pose or scissor you forget to pop is reset after your callback, so the vanilla GUI is never affected.

Custom screens

typedef struct cl_screen_desc {
    uint32_t struct_size;
    cl_str   title;                       // a translation key or plain text
    bool     pause, background, close_on_esc;   // all true by default
    cl_screen_init_fn   init;             // (s, user): build the widgets; runs again after every resize
    cl_screen_render_fn render;           // (s, g, mouse_x, mouse_y, partial_tick, user)
    cl_screen_tick_fn   tick;             // (s, user): 20 times a second
    cl_screen_key_fn    key;              // (s, key, scancode, modifiers, user) -> true = used
    cl_screen_char_fn   char_typed;       // not called yet
    cl_screen_mouse_fn  mouse;            // (s, x, y, button, action, user) -> true = used
    cl_screen_scroll_fn scroll;           // (s, x, y, dx, dy, user) -> true = used
    cl_screen_close_fn  close;            // (s, user)
    void*    user;
} cl_screen_desc;
/* CL_SCREEN_DESC_INIT */

cl_result cl_screen_open(const cl_screen_desc* desc, cl_screen* out);   // replaces the current screen
cl_result cl_screen_close(cl_screen s);
bool      cl_screen_is_open(cl_screen s);
int32_t   cl_screen_width(cl_screen s);  int32_t cl_screen_height(cl_screen s);

Widgets

Widgets are owned by the screen and removed when init runs again and when it closes.

C Lua (on the screen s) Callback gets
cl_widget_button(s, x, y, w, h, label, on_press, user, &out) s:button(x, y, w, h, label, fn) the button
cl_widget_checkbox(s, x, y, label, checked, on_change, user, &out) s:checkbox(x, y, label, checked, fn) the checkbox (value() 1 or 0)
cl_widget_slider(s, x, y, w, h, label, min, max, value, step, on_change, user, &out) s:slider(...) the slider (value()); the label shows "label: value"; step 0 = smooth
cl_widget_text_field(s, x, y, w, h, hint, max_length, on_change, user, &out) s:text_field(...) the field (text())
cl_widget_label(s, x, y, label, argb, centered, &out) s:label(x, y, text, colour, centered)

Every widget: cl_widget_set_active, set_visible, set_label, set_tooltip, set_bounds, value / set_value, text / set_text, remove (Lua w:set_label(...), …). Labels are literal text.

Bindings

C C++ Lua
cl_screen_open(&d, &s) clight::screen::open({.title = "Hello", .init = [](clight::Screen s) { s.button(10, 10, 200, 20, "Done", [s] { s.close(); }); }}) → Expected<Screen> (lambdas freed when it closes) cl.screen.open{ title = "Hello", init = function(s) ... end }
cl_widget_button(...) s.button(x, y, w, h, label, fn) s:button(...)
drawing clight::Gui(g).text("Hi", 4, 4, 0xFFFFFF, true) g:text("Hi", 4, 4, 0xFFFFFF, true)

Example (Lua)

local volume = 50
local function open_settings()
  cl.screen.open{
    title = "Settings",
    pause = false,
    init = function(s)
      local cx = s:width() // 2
      s:slider(cx - 100, 60, 200, 20, "Volume", 0, 100, volume, 5, function(w) volume = w:value() end)
      s:button(cx - 100, s:height() - 40, 200, 20, "Done", function() s:close() end)
    end,
    render = function(s, g, mx, my)
      g:text_centered("My Mod", s:width() // 2, 20, 0xFFFFFF, true)
    end,
  }
end

Keep the screen’s state outside it (here volume): init runs again after every resize.

Themed screens (API 1.21)

Open a screen with themed = true and it follows the player’s Appearance style: the widgets above draw as the kit’s widgets (vanilla widgets in Vanilla, the design system in Fancy), and new widget kinds (toggles, dropdowns, tabs, lists, cards, a colour picker) are available. See The UI Kit.

Planned

Texture blits, items with durability bars, styled text and formatting codes, char_typed, list and cycle widgets, and an immediate-mode widget layer for tool windows.