The overall structure when using the library is as follows:
+initialise `mu_Context`
+
+main loop:
+ call `mu_input_...` functions
+ call `mu_begin()`
+ process ui
+ call `mu_end()`
+ iterate commands using `mu_command_next()`
+Before use a mu_Context should be initialised:
mu_Context *ctx = malloc(sizeof(mu_Context));
+mu_init(ctx);Following which the context's text_width and text_height callback functions
+should be set:
ctx->text_width = text_width;
+ctx->text_height = text_height;In your main loop you should first pass user input to microui using the
+mu_input_... functions. It is safe to call the input functions multiple times
+if the same input event occurs in a single frame.
After handling the input the mu_begin() function must be called before
+processing your UI:
mu_begin(ctx);Before any controls can be used we must begin a window using one of the
+mu_begin_window... or mu_begin_popup... functions. The mu_begin_... window
+functions return a truthy value if the window is open, if this is not the case
+we should not process the window any further. When we are finished processing
+the window's ui the mu_end_... window function should be called.
if (mu_begin_window(ctx, "My Window", mu_rect(10, 10, 300, 400))) {
+ /* process ui here... */
+ mu_end_window(ctx);
+}It is safe to nest mu_begin_window() calls, this can be useful for things like
+context menus; the windows will still render separate from one another like
+normal.
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);
+ }
+}See the demo directory for a usage example.
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:
/* initialise a row of 3 items: the first item with a width
+** of 90 and the remaining two with the width of 100 */
+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);If you want to position controls arbitrarily inside a container the
+relative argument of mu_layout_set_next() should be true:
/* place a (40, 40) sized button at (300, 300) inside the container: */
+mu_layout_set_next(ctx, mu_rect(300, 300, 40, 40), 1);
+mu_button(ctx, "X");A Rect set with relative true will also effect the content_size
+of the container, causing it to effect the scrollbars if it exceeds the
+width or height of the container's body.
The library provides styling support via the mu_Style struct and, if you
+want greater control over the look, the draw_frame() callback function.
The mu_Style struct contains spacing and sizing information, as well
+as a colors array which maps colorid to mu_Color. The library uses
+the style pointer field of the context to resolve colors and spacing,
+it is safe to change this pointer or modify any fields of the resultant
+struct at any point. See microui.h for the struct's
+implementation.
In addition to the style struct the context stores a draw_frame()
+callback function which is used whenever the frame of a control needs
+to be drawn, by default this function draws a rectangle using the color
+of the colorid argument, with a one-pixel border around it using the
+MU_COLOR_BORDER color.
The library exposes the functions used by built-in controls to allow the
+user to make custom controls. A control should take a mu_Context* value
+as its first argument and return a MU_RES_... value. Your control's
+implementation should use mu_layout_next() to get its destination
+Rect and advance the layout system. mu_get_id() should be used with
+some data unique to the control to generate an ID for that control and
+mu_update_control() should be used to update the context's hover
+and focus values based on the mouse input state.
The MU_OPT_HOLDFOCUS opt value can be passed to mu_update_control()
+if we want the control to retain focus when the mouse button is released
+— this behaviour is used by textboxes which we want to stay focused
+to allow for text input.
A control that acts as a button which displays an integer and, when +clicked increments that integer, could be implemented as such:
+int incrementer(mu_Context *ctx, int *value) {
+ mu_Id id = mu_get_id(ctx, &value, sizeof(value));
+ mu_Rect rect = mu_layout_next(ctx);
+ mu_update_control(ctx, id, rect, 0);
+
+ /* handle input */
+ int res = 0;
+ if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id) {
+ (*value)++;
+ res |= MU_RES_CHANGE;
+ }
+
+ /* draw */
+ char buf[32];
+ sprintf(buf, "%d", *value);
+ mu_draw_control_frame(ctx, id, rect, MU_COLOR_BUTTON, 0);
+ mu_draw_control_text(ctx, buf, rect, MU_COLOR_TEXT, MU_OPT_ALIGNCENTER);
+
+ return res;
+}