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

The shared widgets every screen draws with: panels, cards, buttons, pills. More...

#include "ui_widgets.h"
#include <math.h>
#include <stdio.h>
#include <string.h>

Macros

#define TAG_TEXT_X_HOME   28
 A home tag's text from its left edge, past the chevron: 28px.
#define TAG_TEXT_X_MARK   12
 The wordmark's text from the tag's left edge: 12px.
#define TAG_TEXT_PAD_R   12
 The tag's text to its right edge: 12px.

Functions

void ui_panel_header (gfx_canvas_t *c, gfx_rect_t r, const char *title, gfx_color_t accent)
void ui_panel (gfx_canvas_t *c, gfx_rect_t r, const char *title, gfx_color_t accent)
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_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.
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.
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_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_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_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 (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_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_clock (char *out, size_t n, uint32_t seconds)
void ui_fmt (char *out, size_t n, float value, int decimals)
void ui_chevron_left (gfx_canvas_t *c, int x, int cy, int size, gfx_color_t color)
static int tag_width (const char *title, bool chevron)
gfx_rect_t ui_home_tag_rect (const char *title)
 Where the home tag with title is drawn and hit.
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_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_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.
static void choice_face_ink (gfx_canvas_t *c, gfx_rect_t r, const char *text, gfx_color_t ink, gfx_color_t mark)
 A choice face's text and chevron, as tall a face takes them.
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)
void ui_hold_reset (ui_hold_t *h)
float ui_hold_credit (float dt_s)
void ui_hold_begin (ui_hold_t *h)
bool ui_hold_leave (ui_hold_t *h)
bool ui_hold_end (ui_hold_t *h)
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)
int ui_hold_flash_left (int ms_left, float dt_s)
 The flash's time left, ms_left, after dt_s seconds.
void ui_hold_flash_step (ui_hold_t *h, float dt_s)
 Time passed for the flash.
gfx_color_t ui_hold_flash (gfx_color_t settled, int ms_left)
 The fill while the flash runs.

Detailed Description

The shared widgets every screen draws with: panels, cards, buttons, pills.

One place for the chrome, so every screen draws the same button. The one piece of logic here is ui_is_light(): a button picks its label colour from the luma of its fill, so the text is legible on a dark panel and on a bright accent alike.

SPDX-License-Identifier: MIT

Function Documentation

◆ choice_face_ink()

void choice_face_ink ( gfx_canvas_t * c,
gfx_rect_t r,
const char * text,
gfx_color_t ink,
gfx_color_t mark )
static

A choice face's text and chevron, as tall a face takes them.

Parameters
cCanvas.
rThe face.
textIts text, or NULL for none.
inkThe text's colour.
markThe chevron's colour.

◆ 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.