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
Add .themed = true (the last field of clight::ScreenSpec) and use the kit widgets:
void open_settings() {
clight::screen::open({
.title = "Compass Plus",
.pause = false,
.init = [](clight::Screen s) {
int32_t x = s.width() / 2 - 150, y = 30;
s.widget_panel(x - 14, y - 14, 328, 210);
s.widget_heading(x, y, "Compass Plus", 1);
s.toggle(x, y + 30, 300, 20, "Show the compass bar", true, [](clight::Widget w) {
bool on = w.value() >= 0.5;
(void)on;
});
s.slider(x, y + 56, 300, 20, "Bar width", 80, 240, 160, 10, [] {});
s.dropdown(x, y + 86, 300, 20, "Labels", "Letters\nDegrees", 0, [](clight::Widget d) { (void)d.value(); });
s.button(x + 210, y + 160, 90, 20, "Done", [s] { s.close(); });
},
.themed = true,
});
}
Switch Appearance > Style while the screen is open and it redraws in the other style. With lambdas there are toggle, icon_button, dropdown, tabs, list, card and color_picker; widget_panel and widget_heading need no callback. A list is filled with w.list_add(title, detail, icon). The UI Kit has the table.
Drawing in the right style
In the .render callback of a themed screen, and in HUD elements, the clight::Gui methods panel, ui_text, icon and control draw in the player’s style:
.render = [](clight::Screen, clight::Gui g, int32_t, int32_t, float) {
g.panel(10, 10, 120, 40);
g.ui_text("Distance", 18, 16, CL_UI_TEXT_SMALL, 0); // 0: the style's colour
},
clight::ui::fancy() tells you the style, clight::ui::color("panel") and clight::ui::length("radius.box") give the theme’s values.
A HUD element
clight::HudElement g_bar;
int g_heading = 0;
void setup_hud() {
cl_hud_element_desc d = CL_HUD_ELEMENT_DESC_INIT;
d.id = clight::s("compass");
d.label = clight::s("Compass bar");
d.icon = clight::s("marker");
d.width = 160;
d.height = 14;
d.anchor = CL_HUD_TOP;
d.y = 6;
d.panel = true;
d.cached = true;
d.render = [](cl_gui g, int32_t w, int32_t, void*) {
const std::string text = std::to_string(g_heading);
clight::Gui(g).ui_text(text, static_cast<float>(w) / 2 - 6, 2, CL_UI_TEXT_SMALL, 0);
};
if (auto e = clight::hud::element_register(&d)) g_bar = *e;
}
cached = true keeps your drawing; after g_heading changes, call g_bar.invalidate() and the game draws it once more. The player places the bar in the HUD editor (“From mods”).
An Appearance page
void setup_page() {
cl_ui_page_desc d = CL_UI_PAGE_DESC_INIT;
d.id = clight::s("settings");
d.label = clight::s("Compass Plus");
d.icon = clight::s("marker");
auto page = clight::ui::page_register(&d);
if (!page) return;
page->option("bar.show", "Show the compass bar", "");
page->choice("bar.labels", "Labels", "", "Letters\nDegrees");
page->hud_element(g_bar);
}
The options are those you defined in your client config (define_bool, define_i32, …); the page edits and saves them.
Try it
Add a colour picker for the compass marker. Save the colour as "#RRGGBB" in the client config option bar.marker and show the option on the Appearance page.
Show a solution
// in .init
s.color_picker(x, y + 116, 300, 20, "Marker colour", 0xFFAA00, [](clight::Widget w) {
char hex[8];
std::snprintf(hex, sizeof hex, "#%06X", static_cast<unsigned>(w.value()) & 0xFFFFFFu);
if (auto c = clight::config::open(CL_CONFIG_CLIENT)) {
c->set_str("bar.marker", hex);
c->save();
}
g_bar.invalidate();
});
// in setup_page
page->color("bar.marker", "Marker colour", "The centre marker");
Recap: .themed = true + kit widgets, g.panel / g.ui_text for your own drawing, clight::hud::element_register for placeable HUD parts, clight::ui::page_register for an Appearance page.