Skip to content

Themed GUIs, HUD elements and appearance pages

Lesson 9.8

Players choose how Celestial looks in Appearance: the Vanilla style (the game’s own widgets) or the Fancy style (the Celestial design), and a colour theme. With the UI kit (API 1.21) your screens, HUD parts and settings follow that choice by themselves.

A themed screen

Set themed in the screen descriptor and use the kit widgets:

static cl_screen g_settings;

static void on_show(cl_widget w, void* user) {
    (void)user;
    bool on = cl_widget_value(w) >= 0.5;   /* 1 or 0 */
    (void)on;
}
static void on_done(cl_widget w, void* user) {
    (void)w;
    cl_screen_close(*(cl_screen*)user);
}

static void settings_init(cl_screen s, void* user) {
    (void)user;
    int32_t x = cl_screen_width(s) / 2 - 150, y = 30;
    cl_widget_panel(s, x - 14, y - 14, 328, 210, NULL);
    cl_widget_heading(s, x, y, CL_STR("Compass Plus"), 1, NULL);
    cl_widget_toggle(s, x, y + 30, 300, 20, CL_STR("Show the compass bar"), true, on_show, NULL, NULL);
    cl_widget_slider(s, x, y + 56, 300, 20, CL_STR("Bar width"), 80, 240, 160, 10, NULL, NULL, NULL);
    cl_widget_dropdown(s, x, y + 86, 300, 20, CL_STR("Labels"), CL_STR("Letters\nDegrees"), 0, NULL, NULL, NULL);
    cl_widget_button(s, x + 210, y + 160, 90, 20, CL_STR("Done"), on_done, &g_settings, NULL);
}

static void open_settings(void) {
    cl_screen_desc d = CL_SCREEN_DESC_INIT;
    d.title = CL_STR("Compass Plus");
    d.pause = false;
    d.themed = true;
    d.init = settings_init;
    cl_screen_open(&d, &g_settings);
}

Switch Appearance > Style while the screen is open and it redraws in the other style. The other kit widgets are cl_widget_icon_button, cl_widget_tabs, cl_widget_list (fill it with cl_widget_list_add(w, title, detail, icon)), cl_widget_card and cl_widget_color_picker. The UI Kit has the table.

Drawing in the right style

In the render callback of a themed screen, and in HUD elements, cl_gui_panel, cl_gui_ui_text, cl_gui_icon and cl_gui_control draw in the player’s style:

static void settings_render(cl_screen s, cl_gui g, int32_t mx, int32_t my, float pt, void* user) {
    (void)s; (void)mx; (void)my; (void)pt; (void)user;
    cl_gui_panel(g, 10, 10, 120, 40);
    cl_gui_ui_text(g, CL_STR("Distance"), 18, 16, CL_UI_TEXT_SMALL, 0);   /* 0: the style's colour */
}

cl_ui_fancy() tells you the style, cl_ui_color(CL_STR("panel")) and cl_ui_length(CL_STR("radius.box")) give the theme’s values.

A HUD element

A box the player moves, scales and hides in the HUD editor. With cached, the game keeps your drawing and calls render again only after cl_hud_element_invalidate:

static cl_hud_element g_bar;
static int g_heading = 0;

static void draw_bar(cl_gui g, int32_t w, int32_t h, void* user) {
    (void)h; (void)user;
    char text[8];
    int n = snprintf(text, sizeof text, "%d", g_heading);
    cl_gui_ui_text(g, (cl_str){text, (size_t)n}, (float)w / 2 - 6, 2, CL_UI_TEXT_SMALL, 0);
}

static void setup_hud(void) {
    cl_hud_element_desc d = CL_HUD_ELEMENT_DESC_INIT;
    d.id = CL_STR("compass");
    d.label = CL_STR("Compass bar");
    d.icon = CL_STR("marker");
    d.width = 160;
    d.height = 14;
    d.anchor = CL_HUD_TOP;
    d.y = 6;
    d.panel = true;
    d.cached = true;
    d.render = draw_bar;
    cl_hud_element_register(&d, &g_bar);
}

When the heading changes (in your client tick handler), set g_heading and call cl_hud_element_invalidate(g_bar).

An Appearance page

static void setup_page(void) {
    cl_ui_page_desc d = CL_UI_PAGE_DESC_INIT;
    d.id = CL_STR("settings");
    d.label = CL_STR("Compass Plus");
    d.icon = CL_STR("marker");
    cl_ui_page page;
    if (cl_ui_page_register(&d, &page) != CL_OK) return;
    cl_ui_page_option(page, CL_STR("bar.show"), CL_STR("Show the compass bar"), CL_STR(""));
    cl_ui_page_choice(page, CL_STR("bar.labels"), CL_STR("Labels"), CL_STR(""), CL_STR("Letters\nDegrees"));
    cl_ui_page_hud_element(page, g_bar);
}

The options are those you defined with cl_config_define_* in your client config; the page edits and saves them. Call setup_hud and setup_page from your lifecycle.client_setup handler.

Try it

Add a colour picker for the compass marker to the settings screen, store it as "#RRGGBB" in the config option bar.marker, and show it on the Appearance page with cl_ui_page_color.

Show a solution
static cl_config g_cfg;   /* cl_config_open(CL_CONFIG_CLIENT, &g_cfg) and cl_config_define_str(g_cfg, CL_STR("bar.marker"), CL_STR("#FFAA00")) at setup */

static void on_colour(cl_widget w, void* user) {
    (void)user;
    char hex[8];
    snprintf(hex, sizeof hex, "#%06X", (unsigned)cl_widget_value(w) & 0xFFFFFFu);
    cl_config_set_str(g_cfg, CL_STR("bar.marker"), (cl_str){hex, 7});
    cl_config_save(g_cfg);
    cl_hud_element_invalidate(g_bar);
}

/* in settings_init */
cl_widget_color_picker(s, x, y + 116, 300, 20, CL_STR("Marker colour"), 0xFFAA00, on_colour, NULL, NULL);

/* in setup_page */
cl_ui_page_color(page, CL_STR("bar.marker"), CL_STR("Marker colour"), CL_STR("The centre marker"));

Recap: d.themed = true + cl_widget_* kit widgets, cl_gui_panel / cl_gui_ui_text for your own drawing, cl_hud_element_register for placeable HUD parts, cl_ui_page_register for an Appearance page.