State-Mode GUI API

Welcome to the manual for the SMGUI, the state-mode graphical user interface toolkit.

The main concept of a state-mode UI is, that you already have your variables, so you reference those from a layout, which has no callbacks neither requires immediate-mode calls, it is just uses those already existing variables for rendering the GUI states.

Hint

This manual can be used off-line. From the right-click pop-up menu, choose "Save As".

Including

This library is self-contained in one single header file and can be used either in header-only mode or in implementation mode. The implementation mode is used by default, including this header in other headers that does not contain the actual implementation requires a UI_HEADERONLY define (there's no reason to include this header in any source files other than the one with your main loop, but just in case you want to).

The base library is entirely platform and backend agnostic. You can select which backend and font driver module to use just by including before ui.h.

1
2
3
#include "ui_glfw.h" #include "ui_psf2.h" #include "ui.h"

The reference implementation for backend uses GLFW3, SDL2/3 and X11; for fonts PC-Screen-Font (same that Linux Console uses), and Scalable Screen Font (much more efficient than TTF or OTF, and any font, be it bitmap, vector or pixel font, can be converted into SSFN).

By default, if no other modules included beforehand, then ui.h includes the GLFW3 backend and PSF2 fonts and also embeds a minimal ASCII-only font (2080 bytes compiled).

Return Codes

Unless stated otherwise, all functions return a negative error code.

Define Description
UI_OK Successful, no error
UI_ERR_BADINP Bad input argument
UI_ERR_BACKEND Error intializing the backend
UI_ERR_NOMEM Memory allocation error


Window

Initializing

1
int ui_init(ui_t *ctx, int txtc, char **txtv, int w, int h, ui_image_t *icon);

Initializes the UI context and opens a window. The very first string in the txtv[] string array must be the window's title, the rest is up to you.

Parameter Description
ctx Pointer to UI context
txtc Number of strings
txtv Strings array for localization
w Window width
h Window height
icon Window icon image (or NULL)

Returns 0 on success, an error code otherwise.

Releasing

1
int ui_free(ui_t *ctx);

Closes the window and frees internal buffers.

Parameter Description
ctx Pointer to UI context

Returns 0 on success, an error code otherwise.

Fullscreen

1
int ui_fullscreen(ui_t *ctx);

Toggle context between fullscreen and windowed mode (after initialization it's windowed).

Parameter Description
ctx Pointer to UI context

Returns 0 on success, an error code otherwise.

Backend Window

1
void *ui_getwindow(ui_t *ctx);

In case there's a need, you can query the underlying backend's window handle with this function.

Parameter Description
ctx Pointer to UI context

Returns an implementation specific handle.

General Structure

General structure of your program should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/* UI context, one per window */ ui_t ctx; /* provide a localization strings array */ enum { WINDOW_TITLE, HELLO_WORLD }; char *english[] = { "Window title", "Hello World!" }; /* open a window and initialize the context */ ui_init(&ctx, 2, english, 640, 480, NULL); /* your main game loop */ do { /* do your thing, draw what you want to draw */ glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* ... */ /* get events and add an UI layer with your desired form on top */ /* if this returns NULL, you should exit */ if(!(evt = ui_event(&ctx, form))) break; /* parse the events */ switch(evt->type) { case UI_EVT_KEY: /* key press */ break; case UI_EVT_MOUSE: /* mouse button event */ break; case UI_EVT_GAMEPAD: /* gamepad event */ break; /* ... */ } } while(1); /* close the window */ ui_free(&ctx);


Localization

SMGUI supports localization, and for that you must gather all the strings in an array. I also suggest to create an enum for the indeces.

char *dictionary[];

You must pass this array when you open the window. The very first string in the array must be the window's title, the rest is up to you.

Changing the Language

1
int ui_settxt(ui_t *ctx, char **txtv);

You can change the language any time you want. The new txtv[] array must have exactly the same number of elements as the one you have used for initialization.

Parameter Description
ctx Pointer to UI context
txtv Strings array

Returns 0 on success, an error code otherwise.



Fonts

SMGUI supports any kind of fonts, and ships two reference implementations.

Setting up a Custom Implementation

1
int ui_fonthook(ui_t *ctx, ui_font_bbox bbox, ui_font_draw draw);

For a custom font format you'll have to pass two hooks to the context.

Parameter Description
ctx Pointer to UI context
bbox Bounding box function
draw Font renderer function

Returns 0 on success, an error code otherwise.

The hooks are:

1
2
typedef int (*ui_font_bbox)(void *fnt, char *str, char *end, int *w, int *h, int *l, int *t);

Measures the string and returns its width in w, height in h in pixels. If there's a left bearing, l is set. Baseline is set from the top in t (both l and t can be NULL if not interested). The string is a zero terminated UTF-8 string in str, but if end is not NULL, then it must stop at end.

1
2
3
typedef int (*ui_font_draw)(void *fnt, char *str, char *end, uint8_t *dst, uint32_t color, int x, int y, int l, int t, int p, int cx0, int cy0, int cx1, int cy1);

Renders the string at x, y (with left bearing l and baseline from top t) into a pixel buffer dst which has p bytes in a line (pitch). It is very important that this function must not modify pixels outside of the cx0, cy0 to cx1, cy1 crop region. The implementation specific font is passed in fnt, the font's color in color, the zero terminated UTF-8 string itself in str, but if end is not NULL, then it must stop at end.

Loading a Font

Warning

This function does not initialize the font, it just stores the pointer and passes it to the hooks. Font initialization and releasing is platform specific and up to the user (PSF2 needs none).

1
int ui_font(ui_t *ctx, void *fnt);

Sets the current font to be used.

Parameter Description
ctx Pointer to UI context
fnt Font to be used

Returns 0 on success, an error code otherwise.



Look and Feel

Mouse Pointer

1
int ui_swcursor(ui_t *ctx, ui_image_t *cursor);

Disables hardware mouse cursor and replaces it with an image cursor from software.

Parameter Description
ctx Pointer to UI context
cursor A cursor image

Returns 0 on success, an error code otherwise.

1
int ui_hwcursor(ui_t *ctx);

Disables software cursor and enables hardware mouse cursor.

Parameter Description
ctx Pointer to UI context

Returns 0 on success, an error code otherwise.

Color Theme

SMGUI supports color themes, which are basically palettes. Each palette entry corresponds to a specific UI element's color. These are in order:

  • foreground color
  • popup and menu title color
  • popup and menu background color
  • toggle active foreground color
  • toggle active background color
  • menu highlight foreground color
  • menu highlight background color
  • disabled foreground color
  • disabled background color
  • scrollbar background color
  • input box foreground color
  • input box light border color
  • input box dark border color
  • input box background color
  • input box selected foreground color
  • input box selected border color
  • input box selected cursor color
  • button foreground color
  • button shadow color
  • button normal outter border color
  • button selected foreground color
  • button selected shadow color
  • button selected outter border color
  • button light inner border color
  • button dark inner border color
  • button light background color
  • button dark background color
  • progressbar light color
  • progressbar background color
  • progressbar dark color
1
int ui_theme(ui_t *ctx, uint32_t *theme);

Sets a custom theme. The theme[] array has as many elements as UI colors, see the list above.

Parameter Description
ctx Pointer to UI context
theme Pointer to a palette

Returns 0 on success, an error code otherwise.

Skin

SMGUI supports skins, which are images, each corresponding to a specific part of the UI. These are in order:

  • the mouse cursor (hotspot at the centre)
  • popup and menu top left corner
  • popup and menu top middle
  • popup and menu top right corner
  • popup and menu left
  • popup and menu background
  • popup and menu right
  • popup and menu bottom left corner
  • popup and menu bottom middle
  • popup and menu bottom right corner
  • popup and menu title background
  • popup and menu close button
  • popup and menu alternative top left corner
  • popup and menu alternative top middle
  • popup and menu alternative top right corner
  • popup and menu alternative left
  • popup and menu alternative background
  • popup and menu alternative right
  • popup and menu alternative bottom left corner
  • popup and menu alternative bottom middle
  • popup and menu alternative bottom right corner
  • popup and menu alternative title background
  • popup and menu alternative close button
  • menu alternative left side
  • menu alternative background
  • menu alternative right side
  • menu highlight background
  • input box background
  • progressbar button background
  • slider left side
  • slider background
  • slider right side
  • slider button
  • vertical scrollbar top
  • vertical scrollbar background
  • vertical scrollbar bottom
  • vertical scrollbar button top
  • vertical scrollbar button middle
  • vertical scrollbar button bottom
  • horizontal scrollbar top
  • horizontal scrollbar background
  • horizontal scrollbar bottom
  • horizontal scrollbar button top
  • horizontal scrollbar button middle
  • horizontal scrollbar button bottom
  • checkbox unchecked
  • checkbox checked
  • radiobutton unchecked
  • radiobutton checked
  • normal button left side
  • normal button background
  • normal button right side
  • pressed button left side
  • pressed button background
  • pressed button right side
  • selected button left side
  • selected button background
  • selected button right side
  • left arrow button
  • down arrow button
  • right arrow button
  • pressed left arrow button
  • pressed down arrow button
  • pressed right arrow button
  • selected left arrow button
  • selected down arrow button
  • selected right arrow button
1
int ui_skin(ui_t *ctx, ui_image_t *skin);

Sets a custom skin. The skin[] array has as many elements as UI elements, see the list above.

Parameter Description
ctx Pointer to UI context
skin Array of skin images

Returns 0 on success, an error code otherwise.

If you include stb_image.h before ui.h, then you can also use the following function to load skin from a single PNG file:

1
int ui_pngskin(ui_t *ctx, uint8_t *png, int size);

Sets a custom skin from a packed PNG file.

Parameter Description
ctx Pointer to UI context
png Pointer to a PNG image
size Size of the PNG image

Returns 0 on success, an error code otherwise.

The packed PNG must have a comment, with x, y, w, h ASCII decimal numbers in each line that describe areas on the image. To create such packed skin PNGs, you can use for example sprpack with the -cdt flags, like:

sprpack -cdt skin.png mouse.png popup_topleft.png popup_topmiddle.png ...

You must list all separate UI element PNGs and in the exact same order as listed above, otherwise the skin PNG won't work.



Event Handling

1
ui_event_t *ui_event(ui_t *ctx, ui_form_t *form);

This is the heart of SMGUI, this function queries the events and also adds an UI layer on top with the desired form layout to the window.

Parameter Description
ctx Pointer to UI context
form Form layout

Returns NULL if the main loop should exit, an event otherwise.

If you change one of the variables that the passed form references, then you must call ui_refresh() before calling ui_event() to force a redrawing.

The returned event should be parsed with a switch on evt->type, because most fields depend on the type.



No Event

Nothing happened.

Parameter Description
evt->type UI_EVT_NONE (0)


Mouse

This is generated whenever a mouse button is pressed or released.

Parameter Description
evt->type UI_EVT_MOUSE
evt->btn Current button's state
evt->x Current mouse X position
evt->y Current mouse Y position

The btn field is a bitfield with the following values:

Define Description
UI_BTN_L Left mouse button
UI_BTN_M Middle mouse button
UI_BTN_R Right mouse button
UI_BTN_U Wheel scrolled up
UI_BTN_D Wheel scrolled down
UI_BTN_A Wheel scrolled left
UI_BTN_B Wheel scrolled right
UI_BTN_RELEASE set if this is a release event

If you want to know the mouse's position without an event, then you can use

1
int ui_getmouse(ui_t *ctx, int *x, int *y);
Parameter Description
ctx Pointer to UI context
x Pointer to store X position
y Pointer to store Y position

Returns 0 on success, error code otherwise.



Gamepad

This is generated whenever the gamepad state changes.

Parameter Description
evt->type UI_EVT_GAMEPAD
evt->btn Current button's state
evt->x Left joystick X position
evt->y Left joystick Y position
evt->rx Right joystick X position
evt->ry Right joystick Y position
evt->key[0] Gamepad's index if there's more than one

Joystick coordinates are signed, and in the range -32768 .. +32768. The btn field is a bitfield with the following values:

Define Description
UI_BTN_A The 'A'/cross button state
UI_BTN_B The 'B'/circle button state
UI_BTN_X The 'X'/square button state
UI_BTN_Y The 'Y'/triangle button state
UI_BTN_L DPad left button state
UI_BTN_R DPad right button state
UI_BTN_U DPad up button state
UI_BTN_D DPad down button state
UI_BTN_BA Back button state
UI_BTN_ST Start button state
UI_BTN_GU Guide button state
UI_BTN_LT Left thumb button state
UI_BTN_RT Right thumb button state
UI_BTN_LS Left shoulder button state
UI_BTN_RS Right shoulder button state


Keyboard

This is generated whenever a key is pressed on the keyboard.

Parameter Description
evt->type UI_EVT_KEY
evt->btn Modifier key's state
evt->key Pressed key

The returned key is an UTF-8 character, or (in case of special keys) an invalid UTF-8 sequence with the key's name. To distinguish, check if key[1] is non-zero and the most significant bit in key[0] is set (valid UTF-8) or clear (a key name).

Hint

There's no mapping with magic defines, to figure out what code a certain key generates, just print evt->key.

The btn field is a bitfield with the following values:

Define Description
UI_BTN_SHIFT One of the Shift keys is pressed
UI_BTN_CONTROL One of the Control keys is pressed
UI_BTN_ALT One of the Alt keys is pressed (right key is often called AltGr)
UI_BTN_GUI One of the GUI keys is pressed

For the modifier keys (LShift, RShift, LCtrl, RCtrl, LAlt, RAlt, LGui and RGui) you'll also receive a key release event, with UI_BTN_RELEASE being set. Other keys only generate a key press event.



Dropped File

This is generated whenever a file is dropped on the window.

Parameter Description
evt->type UI_EVT_DROP
evt->x Current mouse X position
evt->y Current mouse Y position
evt->fn Path of the file


Window Resize

This is generated whenever the window is resized.

Parameter Description
evt->type UI_EVT_RESIZE
evt->x New window width
evt->y New window height


Clipboard

Paste

To query the clipboard (after you have received a keyboard event with Paste key), call

1
char *ui_getclipboard(ui_t *ctx);
Parameter Description
ctx Pointer to UI context

Returns NULL if the clipboard is empty, otherwise the content in a newly allocated buffer. It is the caller's duty to free this buffer after finished using it.

Copy

To set the clipboard (after you have received Cut or Copy key), call

1
char *ui_setclipboard(ui_t *ctx, char *str);
Parameter Description
ctx Pointer to UI context
str String to copy to clipboard

Returns 0 on success, error code otherwise.



Layout

The SMGUI is not an immediate-mode GUI, but neither uses callbacks. Instead it expects that you already have your variables, and you provide a form which references those variables.

The form is an array of ui_form_t elements, and the last element's type MUST be UI_END. Some of the fields are common, others are type specific. The common fields are as follows:

Parameter Description
form->ptr Pointer to data
form->type Form element type
form->align Form element alignment
form->flags Form element flags (like visibility)
form->x Form element desired position
form->y Form element desired position
form->w Form element desired width
form->h Form element desired height
form->m Form element margin

Field Flags

These control how a certain field is displayed.

  • UI_HIDDEN not shown, does not influence normal flow
  • UI_NOBULLET for toggles, checkboxes and radiobuttons only display the label
  • UI_NOBR forces the next field in the same line, no line break
  • UI_FORCEBR opposite, breaks flow and forces the next field into a new line
  • UI_ALTSKIN for fields which support multiple skins (eg. tab instead of menu)
  • UI_NOBORDER for containers, do not display the borders
  • UI_HSCROLL for containers, display horizontal scrollbar
  • UI_VSCROLL for containers, display vertical scrollbar
  • UI_SCROLL same as UI_HSCROLL + UI_VSCROLL
  • UI_DRAGGABLE for popups, allows the user to move them around
  • UI_RESIZABLE for popups, allows the user to resize them
  • UI_SELECTED make the input box selected
  • UI_DISABLED make the field inactive, different style and non-clickable

Positioning

SMGUI does not use the classic packed rows / columns / grid layout, instead it utilizes a HTML-like flexible flow. You can specify coordinates in form->x and form->y three different ways: relative, absolute and percentage.

  • Relative positioning is the default, but for convenience you can also use the UI_REL() macro. A field positioned like this affects the normal flow.
  • For absolute positioning, use the UI_ABS() macro. You can also change the gravity and use UI_ABS_RIGHT() or UI_ABS_BOTTOM() to specify the position relative to the parent container's width or height. Outside of normal flow.
  • For percentage, use the UI_PERCENT() macro. This calculates the position as a parcentage to the parent container's width or height. Outside of normal flow.
  • For percentage plus some pixels, use the UI_PERPLUS() macro.

If you leave form->w and form->h as 0, then the element's width and height will be automatically calculated. If UI_ABS() macro is used on them, then the parent container's width (or height) minus the value will be the width (or height).

You can also use form->align to specify alignment on the given x, y coordinates. This is an OR'd bitmask.

  • UI_LEFT places the element as form->x is on the left (default)
  • UI_RIGHT places the element as form->x is on the right
  • UI_CENTER places the element so that form->x will be in the middle
  • UI_TOP places the element as form->y will be at the top (default)
  • UI_BOTTOM places the element as form->y will be at the bottom
  • UI_MIDDLE places the element so that form->y will be in the middle

Examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ui_form_t form[] = { /* these will be placed one after another, left to right, * break to the next line if necessary, tightly packed */ { .type = UI_LABEL, .label = 1 }, { .type = UI_LABEL, .label = 1 }, /* this will also be placed after the other but with a spacing */ { .type = UI_LABEL, .x = UI_REL(10), .label = 1 }, /* this will be placed at absolute position */ { .type = UI_LABEL, .x = UI_ABS(100), .y = UI_ABS(100), .label = 1 }, /* this will be placed at the centre of the window */ { .type = UI_LABEL, .align = UI_CENTER | UI_MIDDLE, .x = UI_PERCENT(50), .y = UI_PERCENT(50), .label = 1 }, /* this will be screen width - 20 and screen height - 20 in size */ { .type = UI_POPUP, .x = UI_ABS(10), .y = UI_ABS(10), .w = UI_ABS(20), .h = UI_ABS(20), .ptr = &popupform }, /* it is important to close the list */ { .type = UI_END } };

Redrawing

Redrawing the form happens automatically in event handling when needed, and that's it. However if you change one of the referenced variables outside of the UI's scope, then you must call

1
int ui_refresh(ui_t *ctx);

Informs UI that it must redraw the UI layer.

Parameter Description
ctx Pointer to UI context

Returns 0 on success, error code otherwise.



Containers

If a container is preceeded by a toggle field, then that toggle controls the visibility of that container.

ui_popup.png

Draws a popup.

Parameter Description
form->type UI_POPUP
form->flags Might want UI_HIDDEN, UI_DRAGGABLE or UI_RESIZABLE
form->ptr Pointer to another ui_form_t buffer
form->m Margin in pixels
form->p Padding in pixels
form->label Title, index to the localized strings array (or 0)
ui_menu.png

Same as popup, but by default its state is UI_HIDDEN, and there can be only one menu visible at any time. Its checkbox and radiobutton children are highlighted when you hover the mouse over them.

Parameter Description
form->type UI_MENU
form->flags Might want UI_SCROLL
form->ptr Pointer to another ui_form_t buffer
form->m Margin in pixels
form->p Padding in pixels

Div

Does not draw anything, just provides a way to group further fields, hide / show and position them together.

Parameter Description
form->type UI_DIV
form->flags Might want UI_SCROLL
form->ptr Pointer to another ui_form_t buffer
form->m Margin in pixels
form->p Padding in pixels


Labels

Label

ui_label.png

Draws a text label. If form->label is 0, then form->ptr should point to a zero terminated UTF-8 string.

Parameter Description
form->type UI_LABEL
form->label Index to the localized strings array (or 0)
form->ptr Only if label is 0, pointer to a string

Decimal

ui_dec.png

Draws an integer as a decimal number label. The number in the define specifies how many bits used to store the variable.

Parameter Description
form->type UI_DEC8 / UI_DEC16 / UI_DEC32 / UI_DEC64
form->ptr Pointer to the value

Hexadecimal

ui_hex.png

Draws an integer as a hexadecimal number label. The number in the define specifies how many bits used to store the variable.

Parameter Description
form->type UI_HEX8 / UI_HEX16 / UI_HEX32 / UI_HEX64
form->ptr Pointer to the value

Progressbar

ui_pbar.png

Draws an integer (64 bit) as a progressbar.

Parameter Description
form->type UI_PBAR
form->ptr Pointer to the int64 value
form->max Total value

Floating Point

ui_dec_float.png

Draws a floating point number label.

Parameter Description
form->type UI_DEC_FLOAT
form->ptr Pointer to the value

Image

ui_image.png

This field draws an image icon.

Parameter Description
form->type UI_IMAGE
form->icon Pointer to an ui_image_t struct

The ui_image_t image structure looks like:

Field Description
w Width in pixels
h Height in pixels
p Pitch in bytes (bytes in a row, at least w * 4)
buf Pixel buffer with 32-bit RGBA packed pixels


Inputs

Text

ui_text.png

Draws a text input box. The buffer should store an editable UTF-8 string. Normally it accepts all keys as input except control characters, but you can further filter the keys: UI_FILTER_ID (a UNIX id), UI_FILTER_VAR (a variable name, same as UNIX id but first character can't be 0-9), UI_FILTER_EXPR (an expression, same as variable plus parenthesis and operators), and UI_FILTER_HEX (only allows hexadecimal 0-9A-F keys). The UI_FILTER_PASS filters not the input, but the output, displays asterisks. Copy'n'paste works too. If the ui_textosk.h module is included, then on input an on-screen keyboard is displayed from software, otherwise OS-native OSK is only shown if the platform supports it.

Parameter Description
form->type UI_TEXT
form->ptr Pointer to a buffer
form->max Size of the buffer
form->inc 0 for all, or a UI_FILTER_x key filter

Selectbox

ui_select.png

Draws a selectbox. When the users clicks on it, opens a selection popup.

Parameter Description
form->type UI_SELECT
form->ptr Pointer to an int value
form->optc Maximum value plus 1, number of options
form->optv Pointer to a string array, options
form->m Right margin

Optionlist

ui_option.png

Draws an option selector. Same as a selectbox, just with a number input box visual, no popup.

Parameter Description
form->type UI_OPTION
form->ptr Pointer to an int value
form->optc Maximum value plus 1, number of options
form->optv Pointer to a string array, options
form->m Left and right margin

Float

ui_float.png

Draws a floating point number input box.

Parameter Description
form->type UI_FLOAT
form->ptr Pointer to the value
form->fmin Minimum value
form->fmax Maximum value
form->finc Increment value
form->m Left and right margin

Integer

ui_int.png

Draws an integer input box. The number in the define specifies how many bits used to store the variable.

Parameter Description
form->type UI_INT8 / UI_INT16 / UI_INT32 / UI_INT64
form->ptr Pointer to the value
form->min Minimum value
form->max Maximum value
form->inc Increment value
form->m Left and right margin

Slider

ui_slider.png

Draws an integer slider box (32 bit only).

Parameter Description
form->type UI_SLIDER
form->ptr Pointer to the int value
form->min Minimum value
form->max Maximum value
form->inc Increment value

Vertical Scrollbar

ui_vscrbar.png

Draws an integer as a vertical scroll bar (32 bit only). The containers have their own scrollbars, so this is only if you want to use for whatever other reason.

Parameter Description
form->type UI_VSCRBAR
form->ptr Pointer to the int value
form->max Maximum value

Horizontal Scrollbar

ui_hscrbar.png

Draws an integer as a horizontal scroll bar (32 bit only).

Parameter Description
form->type UI_HSCRBAR
form->ptr Pointer to the int value
form->max Maximum value

Color

ui_color.png

Draws an integer as color (32 bit only). When the users clicks on it, opens a color picker.

Parameter Description
form->type UI_COLOR
form->ptr Pointer to the int value


Buttons

Toggle

ui_toggle.png

This is a special field, should be followed by a container field, and it controls that container's visibility. If by any chance the next field isn't a container, then form->value is an index to the form passed to ui_event(). If form->label is 0, then form->ptr should point to a zero terminated UTF-8 string, displayed as label. Normally before that there's a right or down triangle, but with UI_NOBULLET there's no triangle rather the label is displayed with a different color (see color theme, this is to provide menu toggles).

Parameter Description
form->type UI_TOGGLE
form->flags Might want UI_NOBULLET
form->label Index to the localized strings array (or 0)
form->ptr Only if label is 0, pointer to a string
form->value Only if next field isn't a container, ui_event() form's index

Checkbox

ui_check.png

Draws a checkbox with label. The pointed value tells if it's checked. When clicked, int value is XOR'd at that address.

Parameter Description
form->type UI_CHECK
form->flags Might want UI_NOBULLET
form->ptr Pointer to the int value
form->value Bitmask for this label
form->label Index to the localized strings array

Radiobutton

ui_radio.png

Draws a radiobutton with label. The pointed value tells if it's pressed. When clicked, int value is stored at that address.

Parameter Description
form->type UI_RADIO
form->flags Might want UI_NOBULLET
form->ptr Pointer to the int value
form->value Int value for this label
form->label Index to the localized strings array

Button

ui_button.png

Draws a button. The pointed value tells if it's pressed. When clicked, int value is stored at that address. Might have an icon, a localized string, or both. When using skins, buttons might have a shadow which misaligns the button title vertically. If that happens, set the top margin in m (which could be negative as well).

Parameter Description
form->type UI_BUTTON
form->flags Might want UI_NOBORDER
form->ptr Pointer to the int value
form->value Int value for this button
form->label Index to the localized strings array
form->icon Pointer to an ui_image_t struct
form->m Top margin if skinned


Lines

Polyline

ui_lines.png

Draws a series of anti-aliased lines. form->ptr must point to an array of int16_t (short int) values, multiple x and y pairs, and the last pair must be 0,0.

Parameter Description
form->type UI_LINES
form->ptr Pointer to the int16_t array
form->value 32 bit RGBA color

Horizontal Connect

ui_hconnect.png

Connects two points horizontally with a curve. form->ptr must point to an array of exactly 4 int16_t values, x0 and y0 starting point, x1 and y1 end point pair.

Parameter Description
form->type UI_HCONNECT
form->ptr Pointer to int16_t array with 4 elements
form->value 32 bit RGBA color

Vertical Connect

ui_vconnect.png

Connects two points vertically with a curve. form->ptr must point to an array of exactly 4 int16_t values, x0 and y0 starting point, x1 and y1 end point pair.

Parameter Description
form->type UI_VCONNECT
form->ptr Pointer to int16_t array with 4 elements
form->value 32 bit RGBA color

Bezier Curve

ui_curve.png

Draws an arbitrary Bezier curve. form->ptr must point to an array of exactly 8 int16_t values, x0 and y0 starting point, x1 and y1 end point, cx0 and cy0 first control point, cx1 and cy1 second control point's coordinate pair.

Parameter Description
form->type UI_CURVE
form->ptr Pointer to int16_t array with 8 elements
form->value 32 bit RGBA color


Custom

User specified custom widgets can be added as well, it only needs 3 hooks per kind.

Parameter Description
form->type UI_CUSTOM
form->flags You must respect UI_HIDDEN and UI_DISABLED
form->ptr Pointer to an arbitrary data buffer
form->data Pointer to an arbitrary data context
form->bbox Pointer to a bounding box callback
form->view Pointer to a renderer callback
form->ctrl Pointer to an event handler callback

Bounding

1
2
typedef int (*ui_bbox)(ui_t *ctx, int x, int y, int w, int h, ui_form_t *form, int *dw, int *dh);

This function receives the calculated area x, y, w, h where the widget should be located, the form element in form, and must return the destination width in dw and destination height in dh.

View

1
2
typedef int (*ui_view)(ui_t *ctx, int x, int y, int w, int h, ui_form_t *form);

This function receives the effective area x, y, w, h where the widget is located, the form element in form, and should render the widget there. It might use the low level functions like _ui_line(), _ui_cbez(), _ui_rect(), _ui_blit() etc., or might directly set pixels on the ctx->screen image. It is very important that it must not draw outside of the designated area.

Controller

1
2
typedef int (*ui_ctrl)(ui_t *ctx, int x, int y, int w, int h, ui_form_t *form, ui_event_t *evt);

This function receives the effective area x, y, w, h where the widget is located, the form element in form, and the current event in evt for event handling. This hook is only called if the form isn't UI_HIDDEN nor UI_DISABLED, and the mouse is over the widget.



Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <ui.h> int main(int argc, char **argv) { /* localized strings array */ enum { WINDOW_TITLE, POPUP_TITLE, BUTTON_TITLE, EASY_TITLE, HARD_TITLE, VOLUME_TITLE }; char *lang[] = { "Basic demo", "Show", "Button", "easy", "hard", "Volume:" }; /* variables to store game states */ int button = 0, difficulty = 0, volume = 25; /* form referencing those variables, you use a HTML flow like layout */ ui_t ctx; ui_form_t popup[] = { { .type = UI_BUTTON, .flags = UI_FORCEBR, .ptr = &button, .value = 1, .label = BUTTON_TITLE }, { .type = UI_RADIO, .flags = UI_NOBR, .ptr = &difficulty, .value = 0, .y = 5, .label = EASY_TITLE }, { .type = UI_RADIO, .flags = UI_FORCEBR, .ptr = &difficulty, .value = 1, .x = 20, .label = HARD_TITLE }, { .type = UI_LABEL, .flags = UI_NOBR, .y = 5, .label = VOLUME_TITLE }, { .type = UI_SLIDER, .ptr = &volume, .max = 100 }, { .type = UI_END } }; ui_form_t form[] = { { .type = UI_POPUP, .align = UI_CENTER | UI_MIDDLE, .ptr = &popup, .x = UI_PERCENT(50), .y = UI_PERCENT(50), .m = 10, .label = POPUP_TITLE }, { .type = UI_END } }; /* initialize the UI context */ ui_init(&ctx, sizeof(lang)/sizeof(lang[0]), lang, 640, 480, NULL); /* wait until user closes the window */ while(ui_event(&ctx, form)) { /* handle button, you can do this from another thread if you want */ if(button) { printf("button clicked\n"); button = 0; ui_refresh(&ctx); } } /* destroy window, free resources */ ui_free(&ctx); return 0; }

example.png



Fine Tuning

Base

You can tweak SMGUI by providing some define before you include ui.h.

UI_HEADERONLY

Set this if you only want to include the definitions without the implementation (usually not needed).

UI_NOAA

Disable anti-aliased lines (eliminates math.h and libm dependency).

UI_MAXEVENTS

Set the maximum number of pending events. If not defined otherwise, defaults to 16.

UI_MAXPOPUPS

Set the maximum number of visible popups. If not defined otherwise, defaults to 16.

UI_BACKEND_INITIALIZED

Set if you want to call glfwInit() / glfwTerminate(), SDL_Init() / SDL_Quit() etc. yourself. This is needed if you want SMGUI to handle multiple windows.

UI_BACKEND_NOFLUSH

Set if you don't want ui_event() to flush the window, and you call glfwSwapBuffers() / SDL_RenderPresent() / etc. yourself. This is needed if you want to draw over the UI layer.

GLFW3

Separately you can tweak the GLFW3 backend by providing some define before you include ui_glfw.h.

UI_GLFW_CUSTOMHOOKS

If you want to use your own GLFW3 hooks, then define this, and also call the backend's hooks from your hooks. For example:

1
2
3
4
5
6
7
8
9
10
11
/* set your hook as usual */ glfwSetMouseButtonCallback(ui_getwindow(ctx), my_glfw_mouse); /* your hook */ void my_glfw_mouse(GLFWwindow *window, int button, int action, int mods) { /* parse what you want */ /* ... */ /* at the end also call the ui_glfw's hook */ ui_glfw_mouse(window, button, action, mods); }


SMGUI License

Licensed under the terms of the permissive MIT license.

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.