ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_widget.c
Go to the documentation of this file.
1
10
11#include "ra8_widget.h"
12
13#include "ra8_attributes.h"
14#include "ra8_check.h"
15
17static const char* s_tag = "ra8_widget";
18
36{
37 return (r->w <= 0) && (r->h <= 0);
38}
39
56static int32_t internal_min_i32(int32_t a, int32_t b)
57{
58 return (a < b) ? a : b;
59}
60
77static int32_t internal_max_i32(int32_t a, int32_t b)
78{
79 return (a > b) ? a : b;
80}
81
100{
101 if (internal_rect_empty(&acc)) {
102 return r;
103 }
104 if (internal_rect_empty(&r)) {
105 return acc;
106 }
107 const int32_t x0 = internal_min_i32(acc.x, r.x);
108 const int32_t y0 = internal_min_i32(acc.y, r.y);
109 const int32_t x1 = internal_max_i32(acc.x + acc.w, r.x + r.w);
110 const int32_t y1 = internal_max_i32(acc.y + acc.h, r.y + r.h);
111 const ra8_ui_rect_t out = {.x = x0, .y = y0, .w = x1 - x0, .h = y1 - y0};
112 return out;
113}
114
131static uint16_t internal_visible_count(const ra8_widget_t* widgets, uint16_t count)
132{
133 uint16_t vis = 0U;
134 for (uint16_t i = 0U; i < count; ++i) {
135 if (widgets[i].visible) {
136 ++vis;
137 }
138 }
139 return vis;
140}
141
171 uint16_t count,
173 int16_t gap,
174 int16_t pad,
175 ra8_box_t* scratch,
176 uint16_t cap,
177 ra8_box_tree_t* out_tree,
178 int16_t* out_root)
179{
180 const uint16_t vis = internal_visible_count(widgets, count);
181 if ((uint32_t)cap < ((uint32_t)vis + 1U)) {
183 }
184 const ra8_err_t ierr = ra8_box_tree_init(out_tree, scratch, cap);
185 if (ierr != k_ra8_ok) {
186 return ierr;
187 }
188 ra8_box_t container = {};
189 container.kind =
190 (axis == k_ra8_widget_axis_row) ? (uint8_t)k_ra8_box_stack_h : (uint8_t)k_ra8_box_stack_v;
191 container.pad = pad;
192 container.gap = gap;
193 container.flex = 1U;
194 container.tag = (int16_t)k_ra8_box_none;
195 *out_root = ra8_box_add(out_tree, (int16_t)k_ra8_box_none, &container);
196 if (*out_root == (int16_t)k_ra8_box_none) {
198 }
199 for (uint16_t i = 0U; i < count; ++i) {
200 if (!widgets[i].visible) {
201 continue;
202 }
203 ra8_box_t leaf = {};
204 leaf.kind = (uint8_t)k_ra8_box_leaf;
205 leaf.fixed = widgets[i].fixed;
206 leaf.flex = widgets[i].flex;
207 leaf.tag = (int16_t)widgets[i].action_id;
208 if (ra8_box_add(out_tree, *out_root, &leaf) == (int16_t)k_ra8_box_none) {
210 }
211 }
212 return k_ra8_ok;
213}
214
216 uint16_t count,
217 const ra8_ui_rect_t* frame,
219 int16_t gap,
220 int16_t pad,
221 ra8_box_t* box_scratch,
222 uint16_t box_cap)
223{
224 RA8_CHECK_NULL_PTR(widgets, s_tag, "widgets must not be nullptr");
225 RA8_CHECK_NULL_PTR(frame, s_tag, "frame must not be nullptr");
226 RA8_CHECK_NULL_PTR(box_scratch, s_tag, "box_scratch must not be nullptr");
227
228 ra8_box_tree_t tree = {};
229 int16_t root = (int16_t)k_ra8_box_none;
230 const ra8_err_t berr =
231 internal_build_stack_tree(widgets, count, axis, gap, pad, box_scratch, box_cap, &tree, &root);
232 if (berr != k_ra8_ok) {
233 return berr;
234 }
235 const ra8_err_t lerr = ra8_box_layout(&tree, root, frame);
236 if (lerr != k_ra8_ok) {
237 return lerr;
238 }
239
240 /* Box nodes 1..vis are the visible children in add order. */
241 uint16_t box_idx = 1U;
242 for (uint16_t i = 0U; i < count; ++i) {
243 if (!widgets[i].visible) {
244 continue;
245 }
246 widgets[i].rect = box_scratch[box_idx].rect;
247 ++box_idx;
248 }
249 return k_ra8_ok;
250}
251
253 uint16_t count,
254 const ra8_widget_event_t* ev,
255 bool* out_handled)
256{
257 RA8_CHECK_NULL_PTR(ev, s_tag, "ev must not be nullptr");
258 RA8_CHECK_NULL_PTR(out_handled, s_tag, "out_handled must not be nullptr");
259 if ((count > 0U) && (widgets == nullptr)) {
260 return k_ra8_err_null_ptr;
261 }
262 *out_handled = false;
263
264 for (uint16_t i = 0U; i < count; ++i) {
265 ra8_widget_t* w = &widgets[i];
266 if (!w->visible || (w->vt == nullptr) || (w->vt->on_input == nullptr)) {
267 continue;
268 }
269 if (ev->kind == k_ra8_widget_ev_touch) {
270 /* Touch: only the widget under the point is offered the event. */
271 if (!ra8_ui_rect_contains(&w->rect, ev->x, ev->y)) {
272 continue;
273 }
274 *out_handled = w->vt->on_input(w, ev);
275 return k_ra8_ok;
276 }
277 /* Button: offer to each visible widget until one consumes it. */
278 if (w->vt->on_input(w, ev)) {
279 *out_handled = true;
280 return k_ra8_ok;
281 }
282 }
283 return k_ra8_ok;
284}
285
287{
288 RA8_CHECK_NULL_PTR(w, s_tag, "w must not be nullptr");
289 if (refresh == k_ra8_widget_refresh_none) {
291 }
292 w->dirty = true;
293 if ((uint8_t)refresh > w->refresh) {
294 w->refresh = (uint8_t)refresh;
295 }
296 return k_ra8_ok;
297}
298
299[[nodiscard]] ra8_err_t ra8_widget_damage(const ra8_widget_t* widgets,
300 uint16_t count,
301 ra8_ui_rect_t* out_rect,
302 ra8_widget_refresh_t* out_hint,
303 uint16_t* out_count)
304{
305 RA8_CHECK_NULL_PTR(out_rect, s_tag, "out_rect must not be nullptr");
306 RA8_CHECK_NULL_PTR(out_hint, s_tag, "out_hint must not be nullptr");
307 RA8_CHECK_NULL_PTR(out_count, s_tag, "out_count must not be nullptr");
308 if ((count > 0U) && (widgets == nullptr)) {
309 return k_ra8_err_null_ptr;
310 }
311
312 ra8_ui_rect_t acc = {.x = 0, .y = 0, .w = 0, .h = 0};
313 uint8_t hint = (uint8_t)k_ra8_widget_refresh_none;
314 uint16_t dirty = 0U;
315 for (uint16_t i = 0U; i < count; ++i) {
316 if (!widgets[i].visible || !widgets[i].dirty) {
317 continue;
318 }
319 acc = internal_rect_union(acc, widgets[i].rect);
320 if (widgets[i].refresh > hint) {
321 hint = widgets[i].refresh;
322 }
323 ++dirty;
324 }
325 *out_rect = acc;
326 *out_hint = (ra8_widget_refresh_t)hint;
327 *out_count = dirty;
328 return k_ra8_ok;
329}
330
331[[nodiscard]] ra8_err_t ra8_widget_render_dirty(ra8_widget_t* widgets, uint16_t count)
332{
333 if ((count > 0U) && (widgets == nullptr)) {
334 return k_ra8_err_null_ptr;
335 }
336 for (uint16_t i = 0U; i < count; ++i) {
337 ra8_widget_t* w = &widgets[i];
338 if (!w->visible || !w->dirty) {
339 continue;
340 }
341 if ((w->vt != nullptr) && (w->vt->render != nullptr)) {
342 w->vt->render(w);
343 }
344 w->dirty = false;
345 w->refresh = (uint8_t)k_ra8_widget_refresh_none;
346 }
347 return k_ra8_ok;
348}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
ra8_err_t ra8_box_tree_init(ra8_box_tree_t *tree, ra8_box_t *storage, uint16_t cap)
Bind a tree builder to caller-owned node storage.
Definition ra8_box.c:284
ra8_err_t ra8_box_layout(ra8_box_tree_t *tree, int16_t root, const ra8_ui_rect_t *frame)
Lay out the tree, filling every node's rect.
Definition ra8_box.c:331
@ k_ra8_box_none
No child / no sibling link.
Definition ra8_box.h:57
int16_t ra8_box_add(ra8_box_tree_t *tree, int16_t parent, const ra8_box_t *node)
Append a node and link it as a child of parent.
Definition ra8_box.c:297
@ k_ra8_box_stack_v
Vertical stack: children stack top->bottom.
Definition ra8_box.h:66
@ k_ra8_box_leaf
Terminal box (no children laid out).
Definition ra8_box.h:69
@ k_ra8_box_stack_h
Horizontal stack: children left->right.
Definition ra8_box.h:67
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
bool ra8_ui_rect_contains(const ra8_ui_rect_t *r, int32_t px, int32_t py)
Test whether a point lies inside a rectangle.
Definition ra8_ui.c:34
static uint16_t internal_visible_count(const ra8_widget_t *widgets, uint16_t count)
Count the visible widgets in widgets[0..count).
Definition ra8_widget.c:131
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).
Definition ra8_widget.c:215
static int32_t internal_max_i32(int32_t a, int32_t b)
Larger of two signed values.
Definition ra8_widget.c:77
static bool internal_rect_empty(const ra8_ui_rect_t *r)
True if a rect covers no pixels (used as the union identity).
Definition ra8_widget.c:35
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.
Definition ra8_widget.c:299
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).
Definition ra8_widget.c:286
static ra8_err_t internal_build_stack_tree(const ra8_widget_t *widgets, uint16_t count, ra8_widget_axis_t axis, int16_t gap, int16_t pad, ra8_box_t *scratch, uint16_t cap, ra8_box_tree_t *out_tree, int16_t *out_root)
Build a ra8_box stack tree: one container + a leaf per visible widget.
Definition ra8_widget.c:170
static int32_t internal_min_i32(int32_t a, int32_t b)
Smaller of two signed values.
Definition ra8_widget.c:56
static ra8_ui_rect_t internal_rect_union(ra8_ui_rect_t acc, ra8_ui_rect_t r)
Bounding union of two rects (empty acts as the identity).
Definition ra8_widget.c:99
ra8_err_t ra8_widget_render_dirty(ra8_widget_t *widgets, uint16_t count)
Render every visible + dirty widget, clearing its damage.
Definition ra8_widget.c:331
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.
Definition ra8_widget.c:252
Zero-heap composable widget layer (dwm-style) over ra8_box + ra8_ui.
ra8_widget_axis_t
Main axis a container stacks its children along.
Definition ra8_widget.h:175
@ k_ra8_widget_axis_row
Horizontal stack (left -> right).
Definition ra8_widget.h:177
ra8_widget_refresh_t
E-ink-style refresh hint carried by a dirty widget.
Definition ra8_widget.h:98
@ k_ra8_widget_refresh_none
Clean – not dirty.
Definition ra8_widget.h:99
@ k_ra8_widget_ev_touch
A touch / tap at (x, y).
Definition ra8_widget.h:69
One node in a box tree (caller-owned).
Definition ra8_box.h:90
uint8_t kind
ra8_box_kind_t.
Definition ra8_box.h:91
uint16_t flex
Flex weight when not fixed.
Definition ra8_box.h:94
int16_t fixed
Fixed main-axis extent; 0 => use flex.
Definition ra8_box.h:93
int16_t tag
Caller tag (e.g.
Definition ra8_box.h:100
int16_t gap
Gap between children.
Definition ra8_box.h:96
int16_t pad
Inner padding (all four sides).
Definition ra8_box.h:95
ra8_ui_rect_t rect
OUTPUT: computed rectangle.
Definition ra8_box.h:103
Append-only builder over caller-owned node storage.
Definition ra8_box.h:115
Axis-aligned rectangle in framebuffer pixel coordinates.
Definition ra8_ui.h:72
int32_t w
Width (pixels, >= 0).
Definition ra8_ui.h:75
int32_t h
Height (pixels, >= 0).
Definition ra8_ui.h:76
int32_t x
Left edge (pixels).
Definition ra8_ui.h:73
int32_t y
Top edge (pixels).
Definition ra8_ui.h:74
One input event delivered to ra8_widget_dispatch.
Definition ra8_widget.h:77
int32_t x
Touch X (for k_ra8_widget_ev_touch).
Definition ra8_widget.h:81
ra8_widget_ev_kind_t kind
Touch or button.
Definition ra8_widget.h:78
int32_t y
Touch Y (for k_ra8_widget_ev_touch).
Definition ra8_widget.h:82
One widget instance (caller-owned, no allocation).