ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_widget.h File Reference

Zero-heap composable widget layer (dwm-style) over ra8_box + ra8_ui. More...

#include <stdint.h>
#include "ra8_box.h"
#include "ra8_err.h"
#include "ra8_ui.h"
Include dependency graph for ra8_widget.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ra8_widget_event_t
 One input event delivered to ra8_widget_dispatch. More...
struct  ra8_widget_vtable_t
 Behaviour table shared by all widgets of one kind. More...
struct  ra8_widget
struct  ra8_widget_panel
struct  ra8_widget_paint
struct  ra8_widget_label
struct  ra8_widget_button

Typedefs

typedef struct ra8_widget ra8_widget_t
typedef struct ra8_widget_panel ra8_widget_panel_t
typedef struct ra8_widget_paint ra8_widget_paint_t
typedef struct ra8_widget_label ra8_widget_label_t
typedef struct ra8_widget_button ra8_widget_button_t

Enumerations

enum  ra8_widget_ev_kind_t : uint8_t {
  k_ra8_widget_ev_touch = 0U ,
  k_ra8_widget_ev_button = 1U
}
 Input event kind routed to widgets. More...
enum  ra8_widget_refresh_t : uint8_t {
  k_ra8_widget_refresh_none = 0U ,
  k_ra8_widget_refresh_fast = 1U ,
  k_ra8_widget_refresh_quality = 2U
}
 E-ink-style refresh hint carried by a dirty widget. More...
enum  ra8_widget_axis_t : uint8_t {
  k_ra8_widget_axis_col = 0U ,
  k_ra8_widget_axis_row = 1U
}
 Main axis a container stacks its children along. More...
enum  ra8_widget_align_t : uint8_t {
  k_ra8_widget_align_left = 0U ,
  k_ra8_widget_align_center = 1U ,
  k_ra8_widget_align_right = 2U
}
 Horizontal placement of a leaf widget's text within its rect. More...

Functions

ra8_err_t ra8_widget_layout_stack (ra8_widget_t *widgets, uint16_t count, const ra8_ui_rect_t *frame, ra8_widget_axis_t axis, int16_t gap, int16_t pad, ra8_box_t *box_scratch, uint16_t box_cap)
 Lay a stack of widgets out inside a frame (delegates to ra8_box).
ra8_err_t ra8_widget_dispatch (ra8_widget_t *widgets, uint16_t count, const ra8_widget_event_t *ev, bool *out_handled)
 Route an event to the widget that should handle it.
ra8_err_t ra8_widget_invalidate (ra8_widget_t *w, ra8_widget_refresh_t refresh)
 Mark a widget dirty with a refresh hint (folds upward in strength).
ra8_err_t ra8_widget_damage (const ra8_widget_t *widgets, uint16_t count, ra8_ui_rect_t *out_rect, ra8_widget_refresh_t *out_hint, uint16_t *out_count)
 Compute the minimal damage rectangle + refresh hint to flush.
ra8_err_t ra8_widget_render_dirty (ra8_widget_t *widgets, uint16_t count)
 Render every visible + dirty widget, clearing its damage.
const ra8_widget_vtable_tra8_widget_panel_vtable (void)
 Return the shared vtable that every container panel uses.
ra8_err_t ra8_widget_panel_init (ra8_widget_t *w, ra8_widget_panel_t *panel)
 Bind a widget instance to a container panel.
ra8_err_t ra8_widget_panel_compose (ra8_widget_t *panel_w, const ra8_ui_rect_t *frame, ra8_ui_rect_t *out_damage, ra8_widget_refresh_t *out_hint, uint16_t *out_dirty)
 Run one top-level compose cycle over a panel and report the flush.
const ra8_widget_vtable_tra8_widget_label_vtable (void)
 Return the shared vtable backing every text-label widget.
ra8_err_t ra8_widget_label_init (ra8_widget_t *w, ra8_widget_label_t *label)
 Bind a widget instance to a text label.
const ra8_widget_vtable_tra8_widget_button_vtable (void)
 Return the shared vtable backing every push-button widget.
ra8_err_t ra8_widget_button_init (ra8_widget_t *w, ra8_widget_button_t *button)
 Bind a widget instance to a push button.

Detailed Description

Zero-heap composable widget layer (dwm-style) over ra8_box + ra8_ui.

ra8_widget is the composable-UI layer issue #145 asks for: render everything as widgets the way a tiling WM (dwm) composes a screen from opt-in pieces. A status bar is a widget; a book view is a widget; an on-screen keyboard is a widget. A screen (or an app, issue #146) is just an array of widgets laid out by a container.

The split that keeps this testable on the host AND zero-heap on the RA8D2 (NASA Rule 3):

  • Layout is delegated to ra8_box (the bounded box-model engine): children stack in a row / column with fixed-or-flex main-axis sizing, padding and gap. Invisible widgets are skipped (dwm-style opt-in).
  • Hit routing is delegated to ra8_ui (ra8_ui_rect_contains): a touch is routed to the visible widget whose rect contains it.
  • Damage is a union of the dirty widgets' rects plus a refresh hint (fast/A2 for text, quality/GC16 for full redraws) – the minimal display_pal flush the compositor must issue.
  • Render is a per-widget vtable callback, so this library carries no ra8_gfx / framebuffer dependency: the layout/route/damage logic is pure and unit-tested on the host; the concrete pixel drawing lives in the widget's render callback (exercised on-target).

Everything is caller-owned plain data (static widget + box arrays, no globals, no allocation), so the same composition runs identically on the host test harness and on the board.

[Ring 5 / UI] {World: NS}

Since
0.1.0

Definition in file ra8_widget.h.

Typedef Documentation

◆ ra8_widget_button_t

typedef struct ra8_widget_button ra8_widget_button_t

◆ ra8_widget_label_t

typedef struct ra8_widget_label ra8_widget_label_t

◆ ra8_widget_paint_t

typedef struct ra8_widget_paint ra8_widget_paint_t

◆ ra8_widget_panel_t

typedef struct ra8_widget_panel ra8_widget_panel_t

◆ ra8_widget_t

typedef struct ra8_widget ra8_widget_t

Enumeration Type Documentation

◆ ra8_widget_align_t

enum ra8_widget_align_t : uint8_t

Horizontal placement of a leaf widget's text within its rect.

center and right need the string's pixel width, so they fall back to left when the paint backend supplies no ra8_widget_paint_t::text_size.

Enumerator
k_ra8_widget_align_left 

Hug the left inner inset.

k_ra8_widget_align_center 

Centre horizontally in the rect.

k_ra8_widget_align_right 

Hug the right inner inset.

Definition at line 540 of file ra8_widget.h.

◆ ra8_widget_axis_t

enum ra8_widget_axis_t : uint8_t

Main axis a container stacks its children along.

Enumerator
k_ra8_widget_axis_col 

Vertical stack (top -> bottom).

k_ra8_widget_axis_row 

Horizontal stack (left -> right).

Definition at line 175 of file ra8_widget.h.

◆ ra8_widget_ev_kind_t

enum ra8_widget_ev_kind_t : uint8_t

Input event kind routed to widgets.

Selects how ra8_widget_dispatch routes an event: a touch is delivered to the single widget whose rect contains (x, y), while a button is offered to each visible widget in order until one consumes it.

Enumerator
k_ra8_widget_ev_touch 

A touch / tap at (x, y).

k_ra8_widget_ev_button 

A physical button press (button_id).

Definition at line 68 of file ra8_widget.h.

◆ ra8_widget_refresh_t

enum ra8_widget_refresh_t : uint8_t

E-ink-style refresh hint carried by a dirty widget.

Mirrors ra8_display_pal's display_refresh_hint_t. A widget that changed only text/glyphs marks fast (A2 partial update, no flash); a widget that redrew its whole area marks quality (GC16, ghost-free). The compositor folds the dirty widgets' hints into the strongest one for the flush.

Note
Hint strength is ordered none < fast < quality; folding keeps the highest value present across the dirty widgets.
Enumerator
k_ra8_widget_refresh_none 

Clean – not dirty.

k_ra8_widget_refresh_fast 

Partial / A2 (text-only change).

k_ra8_widget_refresh_quality 

Full / GC16 (whole-area redraw).

Definition at line 98 of file ra8_widget.h.

Function Documentation

◆ ra8_widget_button_init()

ra8_err_t ra8_widget_button_init ( ra8_widget_t * w,
ra8_widget_button_t * button )
nodiscard

Bind a widget instance to a push button.

Wires w to render + route button: sets its vtable to ra8_widget_button_vtable, points its ctx at button, and makes it visible. The caller still sets w's fixed / flex (and usually its action_id) for its parent's layout and hit routing.

Parameters
[in,out]wWidget to turn into a button (non-NULL).
[in]buttonButton descriptor (non-NULL; outlives w's use).
Returns
ra8_err_t
Return values
k_ra8_okBound; w renders + routes button.
k_ra8_err_null_ptrw or button is NULL.
Precondition
w and button are non-NULL.
button outlives every render / dispatch of w.
Postcondition
On success w->vt == ra8_widget_button_vtable(), w->ctx == button, w->visible == true.
On failure w is left unchanged.
Note
Not thread-safe.
See also
ra8_widget_button_vtable
Since
0.1.0

Definition at line 145 of file ra8_widget_button.c.

References k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_widget_button_vtable(), and s_tag.

Referenced by wk_build_tree().

◆ ra8_widget_button_vtable()

const ra8_widget_vtable_t * ra8_widget_button_vtable ( void )

Return the shared vtable backing every push-button widget.

One immutable vtable serves all buttons: render paints the (optionally bordered) face and aligned label through the button's ra8_widget_paint_t; on_input latches a touch (flip pressed, bump presses, self-invalidate fast, call on_press) and consumes it, ignoring button events; measure is NULL. ra8_widget_button_init binds it.

Returns
Non-NULL pointer to the static button vtable.
Precondition
None.
None.
Postcondition
The returned pointer is non-NULL and references static storage.
No state is modified.
Note
Pure; thread-safe (returns a pointer to immutable static data).
See also
ra8_widget_button_init
Since
0.1.0

Definition at line 140 of file ra8_widget_button.c.

References s_button_vt.

Referenced by ra8_widget_button_init().

◆ ra8_widget_damage()

ra8_err_t ra8_widget_damage ( const ra8_widget_t * widgets,
uint16_t count,
ra8_ui_rect_t * out_rect,
ra8_widget_refresh_t * out_hint,
uint16_t * out_count )
nodiscard

Compute the minimal damage rectangle + refresh hint to flush.

Unions the rects of every visible AND dirty widget into one bounding rectangle and folds their refresh hints into the strongest one. This is the single display_pal flush the compositor issues: changing only the status bar yields just the status bar's rect with the fast hint; a full redraw yields the whole frame with the quality hint.

Parameters
[in]widgetsWidget array.
[in]countNumber of widgets.
[out]out_rectReceives the union rect (w == h == 0 if nothing dirty).
[out]out_hintReceives the folded refresh hint (none if clean).
[out]out_countReceives the number of dirty widgets.
Returns
ra8_err_t
Return values
k_ra8_okComputed (see out_count).
k_ra8_err_null_ptrAny output pointer, or widgets (count>0), NULL.
Precondition
All output pointers non-NULL.
Postcondition
*out_count == 0 iff nothing was dirty (then *out_rect is empty).
Note
Pure; not thread-safe vs concurrent mutation.
Since
0.1.0

Definition at line 299 of file ra8_widget.c.

References internal_rect_union(), k_ra8_err_null_ptr, k_ra8_ok, k_ra8_widget_refresh_none, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by ra8_widget_panel_compose(), wa_verify_or_halt(), and wd_check_damage().

◆ ra8_widget_dispatch()

ra8_err_t ra8_widget_dispatch ( ra8_widget_t * widgets,
uint16_t count,
const ra8_widget_event_t * ev,
bool * out_handled )
nodiscard

Route an event to the widget that should handle it.

For a touch event, finds the first visible widget whose rect contains (ev->x, ev->y) (earlier widgets win on overlap) and calls its on_input. For a button event, offers it to each visible widget in order until one consumes it. A widget with a NULL on_input never consumes.

Parameters
[in,out]widgetsWidget array.
[in]countNumber of widgets.
[in]evThe event to route.
[out]out_handledReceives true if some widget consumed the event.
Returns
ra8_err_t
Return values
k_ra8_okRouted (see out_handled).
k_ra8_err_null_ptrwidgets (with count>0), ev, or out_handled is NULL.
Precondition
ev and out_handled non-NULL.
Postcondition
On a hit *out_handled == true; otherwise false.
Note
Not thread-safe.
Since
0.1.0

Definition at line 252 of file ra8_widget.c.

References k_ra8_err_null_ptr, k_ra8_ok, k_ra8_widget_ev_touch, ra8_widget_event_t::kind, RA8_CHECK_NULL_PTR, ra8_ui_rect_contains(), s_tag, ra8_widget_event_t::x, and ra8_widget_event_t::y.

Referenced by internal_panel_on_input(), and wd_app_on_input().

◆ ra8_widget_invalidate()

ra8_err_t ra8_widget_invalidate ( ra8_widget_t * w,
ra8_widget_refresh_t refresh )
nodiscard

Mark a widget dirty with a refresh hint (folds upward in strength).

Parameters
[in,out]wWidget to invalidate.
[in]refreshk_ra8_widget_refresh_fast / _quality.
Returns
ra8_err_t
Return values
k_ra8_okMarked dirty.
k_ra8_err_null_ptrw is NULL.
k_ra8_err_invalid_argrefresh is k_ra8_widget_refresh_none.
Precondition
w non-NULL.
Postcondition
w->dirty == true; w->refresh is the stronger of old/new.
Note
Not thread-safe.
Since
0.1.0

Definition at line 286 of file ra8_widget.c.

References k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_widget_refresh_none, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by er_render_keyboard(), er_render_library(), er_render_reading(), internal_bg_on_input(), internal_button_on_input(), internal_kbd_on_input(), internal_nav_on_input(), internal_panel_render(), internal_rv_link(), internal_rv_on_input(), internal_tb_on_input(), wa_app_render(), wa_verify_or_halt(), wc_check_partial(), wc_invalidate_all(), wc_tick_live(), wd_app_render(), wd_check_damage(), wd_check_partial(), wd_invalidate_all(), wd_tick_live(), wk_invalidate_all(), and wk_on_button_press().

◆ ra8_widget_label_init()

ra8_err_t ra8_widget_label_init ( ra8_widget_t * w,
ra8_widget_label_t * label )
nodiscard

Bind a widget instance to a text label.

Wires w to render label: sets its vtable to ra8_widget_label_vtable, points its ctx at label, and makes it visible. The caller still sets w's fixed / flex for its parent's layout.

Parameters
[in,out]wWidget to turn into a label (non-NULL).
[in]labelLabel descriptor (non-NULL; outlives w's use).
Returns
ra8_err_t
Return values
k_ra8_okBound; w renders label.
k_ra8_err_null_ptrw or label is NULL.
Precondition
w and label are non-NULL.
label outlives every render of w.
Postcondition
On success w->vt == ra8_widget_label_vtable(), w->ctx == label, w->visible == true.
On failure w is left unchanged.
Note
Not thread-safe.
See also
ra8_widget_label_vtable
Since
0.1.0

Definition at line 90 of file ra8_widget_label.c.

References k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_widget_label_vtable(), and s_tag.

Referenced by wk_build_tree().

◆ ra8_widget_label_vtable()

const ra8_widget_vtable_t * ra8_widget_label_vtable ( void )

Return the shared vtable backing every text-label widget.

One immutable vtable serves all labels: render fills the background and draws the aligned text through the label's ra8_widget_paint_t; measure and on_input are NULL (a label sizes from its parent's fixed/flex and never consumes input). ra8_widget_label_init binds it, so callers rarely need it directly – it is exposed for tests and hand-built widgets.

Returns
Non-NULL pointer to the static label vtable.
Precondition
None.
None.
Postcondition
The returned pointer is non-NULL and references static storage.
No state is modified.
Note
Pure; thread-safe (returns a pointer to immutable static data).
See also
ra8_widget_label_init
Since
0.1.0

Definition at line 85 of file ra8_widget_label.c.

References s_label_vt.

Referenced by ra8_widget_label_init().

◆ ra8_widget_layout_stack()

ra8_err_t ra8_widget_layout_stack ( ra8_widget_t * widgets,
uint16_t count,
const ra8_ui_rect_t * frame,
ra8_widget_axis_t axis,
int16_t gap,
int16_t pad,
ra8_box_t * box_scratch,
uint16_t box_cap )
nodiscard

Lay a stack of widgets out inside a frame (delegates to ra8_box).

Builds a transient ra8_box tree – one container plus a leaf per visible widget (invisible widgets are skipped, dwm-style) carrying that widget's fixed / flex – runs ra8_box_layout, then copies each visible widget's computed rect back into widget->rect. Invisible widgets keep their old rect. No allocation: the caller supplies the ra8_box scratch.

Parameters
[in,out]widgetsWidget array.
[in]countNumber of widgets.
[in]frameOuter rectangle the stack fills.
[in]axisk_ra8_widget_axis_col / _row.
[in]gapGap between children (pixels).
[in]padInner padding of the frame (pixels).
[in]box_scratchCaller ra8_box_t scratch (>= count + 1 nodes).
[in]box_capCapacity of box_scratch.
Returns
ra8_err_t
Return values
k_ra8_okLaid out; every visible widget's rect set.
k_ra8_err_null_ptrwidgets, frame, or box_scratch NULL.
k_ra8_err_invalid_argbox_cap < (visible count + 1).
Precondition
widgets covers count; frame non-NULL.
box_scratch holds at least (visible_count + 1) nodes.
Postcondition
Every visible widget reachable has its rect assigned.
Note
Not thread-safe.
Since
0.1.0

Definition at line 215 of file ra8_widget.c.

References internal_build_stack_tree(), k_ra8_box_none, k_ra8_ok, ra8_box_layout(), RA8_CHECK_NULL_PTR, ra8_box_t::rect, and s_tag.

Referenced by er_render_keyboard(), er_render_library(), er_render_reading(), internal_panel_layout(), wa_app_render(), and wd_app_render().

◆ ra8_widget_panel_compose()

ra8_err_t ra8_widget_panel_compose ( ra8_widget_t * panel_w,
const ra8_ui_rect_t * frame,
ra8_ui_rect_t * out_damage,
ra8_widget_refresh_t * out_hint,
uint16_t * out_dirty )
nodiscard

Run one top-level compose cycle over a panel and report the flush.

The compositor pass the issue asks for, packaged as one call:

  1. Pin the panel to frame (panel_w->rect = *frame).
  2. Lay the panel's children out inside it (ra8_widget_layout_stack).
  3. Compute the minimal damage rectangle + folded refresh hint over the dirty children (ra8_widget_damage) – what the caller hands to display_flush.
  4. Composite by rendering only the dirty children (ra8_widget_render_dirty); a dirty child that is itself a panel repaints its whole subtree.

Marking the whole tree dirty before the call yields a full-frame quality flush; marking only one child (e.g. the status bar) yields just that child's rect with its hint – the damage-tracked partial update.

Parameters
[in,out]panel_wThe root panel widget (bound via panel_init).
[in]frameOuter rectangle the panel fills (the framebuffer).
[out]out_damageReceives the union rect to flush (empty if clean).
[out]out_hintReceives the folded refresh hint (none if clean).
[out]out_dirtyReceives the number of dirty children composited.
Returns
ra8_err_t
Return values
k_ra8_okComposed; see out_dirty / out_damage.
k_ra8_err_null_ptrAny pointer argument is NULL.
k_ra8_err_invalid_argpanel_w is not a panel, or its scratch is too small (forwarded from the layout step).
Precondition
All pointer arguments are non-NULL.
panel_w was bound by ra8_widget_panel_init.
Postcondition
On success every dirty child has been rendered and cleared.
*out_dirty == 0 iff nothing was dirty (then *out_damage is empty).
Note
Not thread-safe. Descends the tree; depth is statically bounded by the caller's widget tree (NASA Rule 1).
See also
ra8_widget_damage
ra8_widget_render_dirty
Since
0.1.0

Definition at line 203 of file ra8_widget_panel.c.

References internal_compose_check(), internal_panel_layout(), k_ra8_ok, k_ra8_widget_refresh_none, ra8_widget_damage(), and ra8_widget_render_dirty().

Referenced by wc_compose(), wd_compose(), and wk_compose().

◆ ra8_widget_panel_init()

ra8_err_t ra8_widget_panel_init ( ra8_widget_t * w,
ra8_widget_panel_t * panel )
nodiscard

Bind a widget instance to a container panel.

Wires w to act as a container: sets its vtable to ra8_widget_panel_vtable, points its ctx at panel, and makes it visible. The caller still sets w's fixed / flex for its parent's layout (a root panel is typically pinned by ra8_widget_panel_compose, which sets its rect directly).

Parameters
[in,out]wWidget to turn into a panel (non-NULL).
[in]panelPanel descriptor (non-NULL; children covers count).
Returns
ra8_err_t
Return values
k_ra8_okBound; w renders/routes panel's children.
k_ra8_err_null_ptrw or panel is NULL.
k_ra8_err_invalid_argpanel has count > 0 but a NULL child array or box_cap < count + 1.
Precondition
w and panel are non-NULL.
panel->box_scratch holds at least count + 1 nodes.
Postcondition
On success w->vt == ra8_widget_panel_vtable(), w->ctx == panel, w->visible == true.
On failure w is left unchanged.
Note
Not thread-safe.
See also
ra8_widget_panel_compose
Since
0.1.0

Definition at line 185 of file ra8_widget_panel.c.

References k_ra8_err_invalid_arg, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_widget_panel_vtable(), and s_tag.

Referenced by wc_build_tree(), wd_build_tree(), and wk_build_tree().

◆ ra8_widget_panel_vtable()

const ra8_widget_vtable_t * ra8_widget_panel_vtable ( void )

Return the shared vtable that every container panel uses.

One immutable vtable backs all panels: its render lays out the panel's children inside the panel widget's rect and composites them (a dirty panel repaints its whole subtree); its on_input routes the event to the children via ra8_widget_dispatch; measure is NULL (a panel sizes from its parent's fixed/flex like any widget). ra8_widget_panel_init binds this vtable, so callers rarely need it directly – it is exposed for tests and for building a widget by hand.

Returns
Non-NULL pointer to the static panel vtable.
Precondition
None.
None.
Postcondition
The returned pointer is non-NULL and references static storage.
No state is modified.
Note
Pure; thread-safe (returns a pointer to immutable static data).
Render/route descend the tree, so nesting depth is bounded by the caller's static tree – there is no data-dependent self-call (NASA Rule 1).
See also
ra8_widget_panel_init
Since
0.1.0

Definition at line 180 of file ra8_widget_panel.c.

References s_panel_vt.

Referenced by ra8_widget_panel_init().

◆ ra8_widget_render_dirty()

ra8_err_t ra8_widget_render_dirty ( ra8_widget_t * widgets,
uint16_t count )
nodiscard

Render every visible + dirty widget, clearing its damage.

Calls each visible, dirty widget's render (skipping NULL render callbacks) and then clears its dirty flag and resets refresh to none. The selection of which widgets render is pure (host-testable with a recording mock vtable); the pixel drawing inside render is the on-target part.

Parameters
[in,out]widgetsWidget array.
[in]countNumber of widgets.
Returns
ra8_err_t
Return values
k_ra8_okRendered + cleared.
k_ra8_err_null_ptrwidgets is NULL while count > 0.
Precondition
widgets covers count.
Postcondition
Every rendered widget has dirty == false, refresh == none.
Note
Not thread-safe.
Since
0.1.0

Definition at line 331 of file ra8_widget.c.

References k_ra8_err_null_ptr, k_ra8_ok, and k_ra8_widget_refresh_none.

Referenced by er_render_current(), er_render_keyboard(), er_render_library(), er_render_nag_region(), er_render_reading(), internal_panel_render(), ra8_widget_panel_compose(), wa_app_render(), and wd_app_render().