diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..a87344b --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,1743 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + microui/doc/usage.md at master · rxi/microui · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + +
+ +
+ +
+ +
+ + + + / + + microui + + + Public +
+ + +
+ +
+ + +
+
+ +
+
+ + + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + +

Latest commit

 

History

History
251 lines (218 loc) · 9.08 KB

File metadata and controls

251 lines (218 loc) · 9.08 KB

Usage

+ +

Overview

+

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()`
+
+

Getting Started

+

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.

+

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:

+
/* 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.

+

Style Customisation

+

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.

+

Custom Controls

+

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;
+}
+
+
+ + + + +
+ +
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + diff --git a/gui.c b/gui.c new file mode 100644 index 0000000..e69de29 diff --git a/gui.h b/gui.h new file mode 100644 index 0000000..e69de29 diff --git a/test_gui.c b/test_gui.c new file mode 100644 index 0000000..e69de29