While inside a window block we can safely process controls. Controls that allow
user interaction return a bitset of MU_RES_...
values. Some controls — such
as buttons — can only potentially return a single MU_RES_...
, thus their
return value can be treated as a boolean:
if (mu_button(ctx, "My Button")) {
printf("'My Button' was pressed\n");
}
The library generates unique IDs for controls internally to keep track of which
are focused, hovered, etc. These are typically generated from the name/label
passed to the function, or, in the case of sliders and checkboxes the value
pointer. An issue arises then if you have several buttons in a window or panel
that use the same label. The mu_push_id()
and mu_pop_id()
functions are
provided for such situations, allowing you to push additional data that will be
mixed into the unique ID:
for (int i = 0; i < 10; i++) {
mu_push_id(ctx, &i, sizeof(i));
if (mu_button(ctx, "x")) {
printf("Pressed button %d\n", i);
}
mu_pop_id(ctx);
}
When we’re finished processing the UI for this frame the mu_end()
function
should be called:
mu_end(ctx);
When we’re ready to draw the UI the mu_next_command()
can be used to iterate
the resultant commands. The function expects a mu_Command
pointer initialised
to NULL
. It is safe to iterate through the commands list any number of times:
mu_Command *cmd = NULL;
while (mu_next_command(ctx, &cmd)) {
if (cmd->type == MU_COMMAND_TEXT) {
render_text(cmd->text.font, cmd->text.text, cmd->text.pos.x, cmd->text.pos.y, cmd->text.color);
}
if (cmd->type == MU_COMMAND_RECT) {
render_rect(cmd->rect.rect, cmd->rect.color);
}
if (cmd->type == MU_COMMAND_ICON) {
render_icon(cmd->icon.id, cmd->icon.rect, cmd->icon.color);
}
if (cmd->type == MU_COMMAND_CLIP) {
set_clip_rect(cmd->clip.rect);
}
}
Layout System
The layout system is primarily based around rows — Each row
can contain a number of items or columns each column can itself
contain a number of rows and so forth. A row is initialised using the
mu_layout_row()
function, the user should specify the number of items
on the row, an array containing the width of each item, and the height
of the row:
mu_layout_row(ctx, 3, (int[]) { 90, 100, 100 }, 0);
When a row is filled the next row is started, for example, in the above
code 6 buttons immediately after would result in two rows. The function
can be called again to begin a new row.
As well as absolute values, width and height can be specified as 0
which will result in the Context’s style.size
value being used, or a
negative value which will size the item relative to the right/bottom edge,
thus if we wanted a row with a small button at the left, a textbox filling
most the row and a larger button at the right, we could do the following:
mu_layout_row(ctx, 3, (int[]) { 30, -90, -1 }, 0);
mu_button(ctx, "X");
mu_textbox(ctx, buf, sizeof(buf));
mu_button(ctx, "Submit");
If the items
parameter is 0
, the widths
parameter is ignored
and controls will continue to be added to the row at the width last
specified by mu_layout_width()
or style.size.x
if this function has
not been called:
mu_layout_row(ctx, 0, NULL, 0);
mu_layout_width(ctx, -90);
mu_textbox(ctx, buf, sizeof(buf));
mu_layout_width(ctx, -1);
mu_button(ctx, "Submit");
A column can be started at any point on a row using the
mu_layout_begin_column()
function. Once begun, rows will act inside
the body of the column — all negative size values will be relative to
the column’s body as opposed to the body of the container. All new rows
will be contained within this column until the mu_layout_end_column()
function is called.
Internally controls use the mu_layout_next()
function to retrieve the
next screen-positioned-Rect and advance the layout system, you should use
this function when making custom controls or if you want to advance the
layout system without placing a control.
The mu_layout_set_next()
function is provided to set the next layout
Rect explicitly. This will be returned by mu_layout_next()
when it is
next called. By using the relative
boolean you can choose to provide
a screen-space Rect or a Rect which will have the container’s position
and scroll offset applied to it. You can peek the next Rect from the
layout system by using the mu_layout_next()
function to retrieve it,
followed by mu_layout_set_next()
to return it:
mu_Rect rect = mu_layout_next(ctx);
mu_layout_set_next(ctx, rect, 0);