rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
ui_widgets.h File Reference

Stateless drawing helpers shared by every screen. More...

#include <stdbool.h>
#include "gfx.h"
#include "ui_icons.h"
#include "ui_theme.h"

Go to the source code of this file.

Data Structures

struct  ui_tile_look_t
 Where a tile places its parts and in which faces: one look per grid, the menu's and SETUP's. Offsets are in pixels from the tile's top edge. More...
struct  ui_hold_t

Macros

#define UI_KEYS_FOOT   (UI_ALERT_Y - UI_BAND_H - 4)
 Where the key grid of the keypad and of the keyboard ends at the latest, in body coordinates: 4px above the alert band, y 492.
#define UI_TILE_PAD   8
 A tile's name and line keep this far from its sides, px.
#define UI_PILL_INSET   24
#define UI_TAG_X   8
 The home tag's left edge: 8px.
#define UI_TAG_Y   8
 The home tag's top edge: 8px.
#define UI_TAG_H   44
 The home tag's height: 44px (6.6mm).
#define UI_CHOICE_ROW_H   56
 The row height from which a choice face or row draws in the 20 x 36 face: 56px (8.4mm), the plan's choice row.
#define UI_HOLD_S   2.0f
#define UI_HOLD_MAX_CREDIT_S   0.25f
#define UI_HOLD_FLASH_PHASE_MS   25
 The flash as the command goes, by time: phases of UI_HOLD_FLASH_PHASE_MS (25ms) each, white, black, settled, the cycle twice, UI_HOLD_FLASH_MS (150ms) in all: 9 frames at 60Hz.
#define UI_HOLD_FLASH_CYCLE   3
 The phases of one cycle: white, black, settled.
#define UI_HOLD_FLASH_TIMES   2
 The cycles of one flash.
#define UI_HOLD_FLASH_MS   (UI_HOLD_FLASH_PHASE_MS * UI_HOLD_FLASH_CYCLE * UI_HOLD_FLASH_TIMES)
 The whole flash: 150ms.

Functions

void ui_panel (gfx_canvas_t *c, gfx_rect_t r, const char *title, gfx_color_t accent)
void ui_panel_header (gfx_canvas_t *c, gfx_rect_t r, const char *title, gfx_color_t accent)
void ui_button (gfx_canvas_t *c, gfx_rect_t r, const char *label, gfx_color_t fill, bool pressed, bool enabled)
 Filled rounded button, its label in UI_FONT_LABEL.
gfx_color_t ui_button_off_fill (void)
 The fill of a button that takes no press: the theme's ground (UI_BG), so with its faint label it reads dimmer than an enabled button in the dark theme and in the light one, and differs from every fill an enabled button takes (UI_PANEL, UI_PANEL_HI, UI_PANEL_SUNK, UI_EDGE_HI, an accent).
void ui_button_font (gfx_canvas_t *c, gfx_rect_t r, const char *label, gfx_color_t fill, bool pressed, bool enabled, const gfx_font_t *f)
 ui_button() with its label in face f.
bool ui_is_light (gfx_color_t c)
bool ui_text_fits (const gfx_font_t *f, const char *s, int w, int h, int pad)
 Whether s in face f fits a box w x h px with pad px to spare at each side.
const gfx_font_t * ui_button_face (const char *label, int w, int h, int pad, const gfx_font_t *big, const gfx_font_t *small)
 The face for a button label: big when the label keeps pad px at each side of a w x h px key in it, else small.
void ui_card (gfx_canvas_t *c, gfx_rect_t r, gfx_color_t fill)
int ui_text_wrap (gfx_canvas_t *c, gfx_rect_t first, int pitch, const char *t, const gfx_font_t *f, gfx_color_t col)
void ui_tile (gfx_canvas_t *c, gfx_rect_t r, const ui_tile_look_t *look, ui_icon_fn icon, const char *name, const char *line, bool pressed)
 A tile of a grid that opens what it names: the menu's, and SETUP's.
void ui_pill (gfx_canvas_t *c, gfx_rect_t r, const char *label, gfx_color_t dot, gfx_color_t fill)
 A status pill in the label face, its label UI_PILL_INSET px in.
void ui_pill_font (gfx_canvas_t *c, gfx_rect_t r, const char *label, gfx_color_t dot, gfx_color_t fill, int inset, const gfx_font_t *f)
 ui_pill() with the label in face f, inset px from the left edge and centred in the pill's height.
void ui_pill_ink (gfx_canvas_t *c, gfx_rect_t r, const char *label, gfx_color_t dot, gfx_color_t fill, gfx_color_t ink, int inset, const gfx_font_t *f)
 ui_pill_font() with the label in colour ink, for a fill the theme's text colour does not read on.
void ui_bar (gfx_canvas_t *c, gfx_rect_t r, float frac, float peak_frac, gfx_color_t color)
void ui_value (gfx_canvas_t *c, gfx_rect_t box, const char *number, const char *unit, gfx_color_t color)
void ui_fmt (char *out, size_t n, float value, int decimals)
void ui_clock (char *out, size_t n, uint32_t seconds)
gfx_rect_t ui_home_tag_rect (const char *title)
 Where the home tag with title is drawn and hit.
void ui_home_tag (gfx_canvas_t *c, const char *title, bool pressed)
 Draw the home tag: a chevron and title in UI_FONT_TAG.
void ui_wordmark (gfx_canvas_t *c, const char *text, gfx_color_t fill)
 The home tag's shape without the chevron: an identity mark, not a control.
void ui_chevron_left (gfx_canvas_t *c, int x, int cy, int size, gfx_color_t color)
void ui_rule (gfx_canvas_t *c, int x, int y, int w, gfx_color_t color)
 A 1px horizontal rule.
const gfx_font_t * ui_choice_font (int h)
 The face a choice face or row h px tall draws its text in.
const gfx_font_t * ui_choice_text_font (int h, int w, const char *text)
 The face a choice face or row draws text in.
void ui_choice_face (gfx_canvas_t *c, gfx_rect_t r, const char *text, bool pressed, bool open)
void ui_choice_face_locked (gfx_canvas_t *c, gfx_rect_t r, const char *text)
void ui_choice_list (gfx_canvas_t *c, gfx_rect_t r)
 The open list's ground: a shadow 4px down and right, then the panel.
void ui_choice_row (gfx_canvas_t *c, gfx_rect_t r, const char *text, bool chosen, bool pressed)
gfx_color_t ui_hold_fill (gfx_color_t base, gfx_color_t target, float held_s)
gfx_color_t ui_hold_flash (gfx_color_t settled, int ms_left)
 The fill while the flash runs.
void ui_hold_reset (ui_hold_t *h)
void ui_hold_begin (ui_hold_t *h)
bool ui_hold_leave (ui_hold_t *h)
bool ui_hold_end (ui_hold_t *h)
float ui_hold_credit (float dt_s)
bool ui_hold_tick (ui_hold_t *h, float dt_s)
void ui_hold_reached (ui_hold_t *h)
bool ui_hold_left (ui_hold_t *h)
void ui_hold_flash_step (ui_hold_t *h, float dt_s)
 Time passed for the flash.
int ui_hold_flash_left (int ms_left, float dt_s)
 The flash's time left, ms_left, after dt_s seconds.

Detailed Description

Stateless drawing helpers shared by every screen.

Every call takes explicit geometry and draws immediately. There is no retained widget tree: on this hardware the cost is in touching framebuffer pixels, and a retained tree touches them more often.

SPDX-License-Identifier: MIT

Macro Definition Documentation

◆ UI_KEYS_FOOT

#define UI_KEYS_FOOT   (UI_ALERT_Y - UI_BAND_H - 4)

Where the key grid of the keypad and of the keyboard ends at the latest, in body coordinates: 4px above the alert band, y 492.

An overlay paints its whole area; its keys end here when the area reaches further, so an alert covers no key on any screen.

◆ UI_PILL_INSET

#define UI_PILL_INSET   24

Small status pill: a filled dot, then a label UI_PILL_INSET px from the pill's left edge, the dot centred half that from it.

Function Documentation

◆ ui_bar()

void ui_bar ( gfx_canvas_t * c,
gfx_rect_t r,
float frac,
float peak_frac,
gfx_color_t color )

Horizontal proportional bar, frac in 0..1, with an optional peak tick.

◆ ui_button()

void ui_button ( gfx_canvas_t * c,
gfx_rect_t r,
const char * label,
gfx_color_t fill,
bool pressed,
bool enabled )

Filled rounded button, its label in UI_FONT_LABEL.

Parameters
cCanvas.
rThe button.
labelIts label, centred, or NULL for none.
fillIts colour while enabled.
pressedLightens the fill.
enabledFalse draws it in ui_button_off_fill() with a dim edge and a faint label.

◆ ui_button_face()

const gfx_font_t * ui_button_face ( const char * label,
int w,
int h,
int pad,
const gfx_font_t * big,
const gfx_font_t * small )

The face for a button label: big when the label keeps pad px at each side of a w x h px key in it, else small.

Parameters
labelThe label; NULL is the empty text.
wThe key's width, in pixels.
hThe key's height, in pixels.
padThe room to keep left and right of the label, in pixels.
bigThe face used when it fits.
smallThe face used when big leaves less than pad px.
Returns
big or small.

◆ ui_button_font()

void ui_button_font ( gfx_canvas_t * c,
gfx_rect_t r,
const char * label,
gfx_color_t fill,
bool pressed,
bool enabled,
const gfx_font_t * f )

ui_button() with its label in face f.

Parameters
cCanvas.
rThe button.
labelIts label, centred, or NULL for none.
fillIts colour.
pressedLightens the fill.
enabledFalse dims it.
fThe label's face.

◆ ui_button_off_fill()

gfx_color_t ui_button_off_fill ( void )

The fill of a button that takes no press: the theme's ground (UI_BG), so with its faint label it reads dimmer than an enabled button in the dark theme and in the light one, and differs from every fill an enabled button takes (UI_PANEL, UI_PANEL_HI, UI_PANEL_SUNK, UI_EDGE_HI, an accent).

Returns
the colour

◆ ui_card()

void ui_card ( gfx_canvas_t * c,
gfx_rect_t r,
gfx_color_t fill )

A raised surface with a hairline edge: the base of every panel.

◆ ui_chevron_left()

void ui_chevron_left ( gfx_canvas_t * c,
int x,
int cy,
int size,
gfx_color_t color )

Left-pointing solid triangle, apex at (x, cy).

◆ ui_choice_face_locked()

void ui_choice_face_locked ( gfx_canvas_t * c,
gfx_rect_t r,
const char * text )

The face of a choice that takes no press now, as ui_tabs_render_locked() draws a segment row: sunk, its text and chevron dim, no accent.

◆ ui_choice_font()

const gfx_font_t * ui_choice_font ( int h)

The face a choice face or row h px tall draws its text in.

Parameters
hThe face's or the row's height, in pixels.
Returns
UI_FONT_TAG (20 x 36) from UI_CHOICE_ROW_H on, UI_FONT_HEAD (16 x 28) under it.

◆ ui_choice_list()

void ui_choice_list ( gfx_canvas_t * c,
gfx_rect_t r )

The open list's ground: a shadow 4px down and right, then the panel.

Parameters
cthe canvas
rthe list's box

◆ ui_choice_row()

void ui_choice_row ( gfx_canvas_t * c,
gfx_rect_t r,
const char * text,
bool chosen,
bool pressed )

One row of the open list: chosen is the choice in force, accented.

◆ ui_choice_text_font()

const gfx_font_t * ui_choice_text_font ( int h,
int w,
const char * text )

The face a choice face or row draws text in.

Parameters
hThe face's or the row's height, in pixels.
wThe width its text may take, in pixels.
textThe text; NULL is the empty text.
Returns
ui_choice_font(h) when text fits w in it, else UI_FONT_HEAD (16 x 28).

◆ ui_clock()

void ui_clock ( char * out,
size_t n,
uint32_t seconds )

Run clock as H:MM:SS, or MM:SS below an hour.

Shared so every screen prints the same number the same way.

◆ ui_fmt()

void ui_fmt ( char * out,
size_t n,
float value,
int decimals )

Format value with decimals decimal places (0 to 3); a non-finite value prints as "--".

◆ ui_hold_begin()

void ui_hold_begin ( ui_hold_t * h)

A press landed on the control: the hold starts from zero.

◆ ui_hold_credit()

float ui_hold_credit ( float dt_s)

What one frame is worth to a hold: dt_s, capped at UI_HOLD_MAX_CREDIT_S and floored at zero. Used by ui_hold_tick() and by any screen that keeps its own hold timer, so a late frame cannot complete a gesture that began inside it.

◆ ui_hold_end()

bool ui_hold_end ( ui_hold_t * h)

The press lifted. Returns whether it was the press that fired, which the release consumes: a release that fired is not also a press.

◆ ui_hold_fill()

gfx_color_t ui_hold_fill ( gfx_color_t base,
gfx_color_t target,
float held_s )

The fill for a button held held_s of UI_HOLD_S, fading base to target. held_s of 0 is base; the fade previews the colour the button is about to hold.

◆ ui_hold_flash()

gfx_color_t ui_hold_flash ( gfx_color_t settled,
int ms_left )

The fill while the flash runs.

150ms in all is short enough to read as a flash rather than an animation. The colour follows the time the flash has run, not the frames drawn: a frame later than a phase (25ms) skips that phase.

Parameters
settledWhat the fill returns to: the settled phase and the end.
ms_leftThe flash's time still to run, counting down from UI_HOLD_FLASH_MS; 0 or less is no flash.
Returns
White, black or settled.

◆ ui_hold_flash_left()

int ui_hold_flash_left ( int ms_left,
float dt_s )

The flash's time left, ms_left, after dt_s seconds.

One step goes no further than the start of the next phase, so every phase is drawn on at least one frame at any frame rate: at 10 frames a second the flash takes 6 frames, 600ms, instead of skipping phases.

Parameters
ms_leftThe time left, in ms.
dt_sThe time passed, in seconds; under 0 counts as 0.
Returns
The time left, 0 at the least.

◆ ui_hold_flash_step()

void ui_hold_flash_step ( ui_hold_t * h,
float dt_s )

Time passed for the flash.

The first step after ui_hold_reached() spends nothing, so the frame the flash starts on draws its first phase whatever the order of the reach and the step in a tick.

Parameters
hThe hold.
dt_sThe time, in seconds; the flash's time left falls by it as ui_hold_flash_left() spends it.

◆ ui_hold_leave()

bool ui_hold_leave ( ui_hold_t * h)

The press left the control, so the gesture is over: contact with the control is the gesture, not contact with the panel. Sliding back on does not resume it. Returns whether a hold was actually abandoned, which is what tells the screen to drop its own record of the press.

◆ ui_hold_left()

bool ui_hold_left ( ui_hold_t * h)

What the hold asked for has gone away – a stop, a failsafe, or the far end – possibly under a finger that is still down.

Both halves of the gesture end here. A press left standing would start a fresh hold the moment the state went away and ask for it again, from a contact the operator made to stop it. Returns whether such a press was ended, so the screen can drop its own record of it; clearing the press without fired would strand it, because the release consumes fired and a release of a press that is no longer held does nothing.

◆ ui_hold_reached()

void ui_hold_reached ( ui_hold_t * h)

What the hold asked for has arrived: flash, and stop filling.

fired is deliberately kept. It remembers that the press still under the finger is the one that fired, and the application calls this between the hold completing and the finger lifting; clearing it would make that release look like a fresh press.

◆ ui_hold_reset()

void ui_hold_reset ( ui_hold_t * h)

Nothing held, nothing fired, nothing flashing.

◆ ui_hold_tick()

bool ui_hold_tick ( ui_hold_t * h,
float dt_s )

Time passed. True on the one frame the hold completes, and never again until the press is lifted and made afresh.

◆ ui_home_tag()

void ui_home_tag ( gfx_canvas_t * c,
const char * title,
bool pressed )

Draw the home tag: a chevron and title in UI_FONT_TAG.

Parameters
cThe canvas, the panel's.
titleThe screen's name.
pressedA press is on it: the fill lightens.

◆ ui_home_tag_rect()

gfx_rect_t ui_home_tag_rect ( const char * title)

Where the home tag with title is drawn and hit.

Parameters
titleThe screen's name.
Returns
The tag, panel coordinates: UI_TAG_X, UI_TAG_Y, UI_TAG_H tall and as wide as its chevron and title.

◆ ui_is_light()

bool ui_is_light ( gfx_color_t c)

True when c is bright enough to need dark text on it.

◆ ui_panel()

void ui_panel ( gfx_canvas_t * c,
gfx_rect_t r,
const char * title,
gfx_color_t accent )

Panel with a chamfered top-left / bottom-right, 1px edge, optional title.

◆ ui_panel_header()

void ui_panel_header ( gfx_canvas_t * c,
gfx_rect_t r,
const char * title,
gfx_color_t accent )

The title strip a panel draws for itself; exposed for custom headers.

◆ ui_pill()

void ui_pill ( gfx_canvas_t * c,
gfx_rect_t r,
const char * label,
gfx_color_t dot,
gfx_color_t fill )

A status pill in the label face, its label UI_PILL_INSET px in.

Parameters
cThe canvas.
rThe pill.
labelIts label; NULL draws the dot alone.
dotThe dot's colour.
fillThe pill's fill.

◆ ui_pill_font()

void ui_pill_font ( gfx_canvas_t * c,
gfx_rect_t r,
const char * label,
gfx_color_t dot,
gfx_color_t fill,
int inset,
const gfx_font_t * f )

ui_pill() with the label in face f, inset px from the left edge and centred in the pill's height.

Parameters
cCanvas.
rThe pill.
labelIts label, or NULL for none.
dotThe dot's colour.
fillThe pill's colour.
insetThe label's start from the pill's left edge, in pixels; the dot is centred half that from it.
fThe label's face.

◆ ui_pill_ink()

void ui_pill_ink ( gfx_canvas_t * c,
gfx_rect_t r,
const char * label,
gfx_color_t dot,
gfx_color_t fill,
gfx_color_t ink,
int inset,
const gfx_font_t * f )

ui_pill_font() with the label in colour ink, for a fill the theme's text colour does not read on.

Parameters
cCanvas.
rThe pill.
labelIts label, or NULL for none.
dotThe dot's colour.
fillThe pill's colour.
inkThe label's colour.
insetThe label's start from the pill's left edge, in pixels.
fThe label's face.

◆ ui_rule()

void ui_rule ( gfx_canvas_t * c,
int x,
int y,
int w,
gfx_color_t color )

A 1px horizontal rule.

Parameters
cthe canvas
xits left end, px
yits row, px
wits length, px
colorits colour

◆ ui_text_fits()

bool ui_text_fits ( const gfx_font_t * f,
const char * s,
int w,
int h,
int pad )

Whether s in face f fits a box w x h px with pad px to spare at each side.

The overlays pick the largest face of the type scale a label fits: a key of the keypad or the keyboard over a narrow host card takes a smaller face rather than overflow.

Parameters
fThe face; NULL fits nothing.
sThe text; NULL is the empty text.
wThe box's width, in pixels.
hThe box's height, in pixels: at least the face's cell height.
padThe room to keep left and right of the text, in pixels.
Returns
True when the text's width plus 2 * pad is at most w and the face's height at most h.

◆ ui_text_wrap()

int ui_text_wrap ( gfx_canvas_t * c,
gfx_rect_t first,
int pitch,
const char * t,
const gfx_font_t * f,
gfx_color_t col )

t broken at spaces into lines as wide as first, each drawn left aligned in a box of first's size, pitch px under the one before. A word wider than a line is cut where the line ends. Draws when c is not NULL and returns the number of lines either way, 0 for an empty t, so a caller measures with the code that draws.

◆ ui_tile()

void ui_tile ( gfx_canvas_t * c,
gfx_rect_t r,
const ui_tile_look_t * look,
ui_icon_fn icon,
const char * name,
const char * line,
bool pressed )

A tile of a grid that opens what it names: the menu's, and SETUP's.

A rounded surface, icon in a square box placed by look, centred in x, the name under it in the text colour and the line under the name in the dim one, both centred and clipped to the tile less UI_TILE_PAD px on either side. A line wider than that breaks at the last space that fits onto a second row look->line_pitch px lower, where line_pitch is not 0 and that row ends inside the tile; a line with no such space or no such row is clipped.

Parameters
cCanvas.
rThe tile.
lookWhere its parts go and their faces.
iconIts icon, or NULL for none.
nameIts name, or NULL for none.
lineThe line under the name, or NULL for none.
pressedLightens the surface.

◆ ui_value()

void ui_value ( gfx_canvas_t * c,
gfx_rect_t box,
const char * number,
const char * unit,
gfx_color_t color )

Right-aligned numeric readout in the hero face, with a unit suffix.

◆ ui_wordmark()

void ui_wordmark ( gfx_canvas_t * c,
const char * text,
gfx_color_t fill )

The home tag's shape without the chevron: an identity mark, not a control.

Parameters
cThe canvas, the panel's.
textThe mark's text, in UI_FONT_TAG: near-black on a light fill, the theme's panel colour on a dark one.
fillThe mark's fill.