==> include/tui/rect.h <==1/* @ajax/tui-rect: ratatui's Rect: a region of cells with u16 coordinates where every edge
2 * computation saturates instead of wrapping. Header-only. */
3#ifndef TUI_RECT_H
4#define TUI_RECT_H
5
6#include <stdbool.h>
7#include <stdint.h>
8
9typedef struct {
10 uint16_t x, y, width, height;
11} tui_rect;
12
13static inline uint16_t tui_sat_add(uint16_t a, uint16_t b) { return (uint16_t)((uint32_t)a + b > 0xFFFF ? 0xFFFF : a + b); }
14static inline uint16_t tui_sat_sub(uint16_t a, uint16_t b) { return (uint16_t)(a > b ? a - b : 0); }
15static inline uint16_t tui_min16(uint16_t a, uint16_t b) { return a < b ? a : b; }
16static inline uint16_t tui_max16(uint16_t a, uint16_t b) { return a > b ? a : b; }
17
18/* Rect::new: width and height cut so the far edges fit in u16. */
19static inline tui_rect tui_rect_new(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
20 return (tui_rect){x, y, (uint16_t)(tui_sat_add(x, w) - x), (uint16_t)(tui_sat_add(y, h) - y)};
21}
22static inline uint16_t tui_rect_left(tui_rect r) { return r.x; }
23static inline uint16_t tui_rect_top(tui_rect r) { return r.y; }
24static inline uint16_t tui_rect_right(tui_rect r) { return tui_sat_add(r.x, r.width); }
25static inline uint16_t tui_rect_bottom(tui_rect r) { return tui_sat_add(r.y, r.height); }
26static inline uint32_t tui_rect_area(tui_rect r) { return (uint32_t)r.width * r.height; }
27static inline bool tui_rect_empty(tui_rect r) { return r.width == 0 || r.height == 0; }
28static inline bool tui_rect_contains(tui_rect r, uint16_t x, uint16_t y) {
29 return x >= r.x && x < tui_rect_right(r) && y >= r.y && y < tui_rect_bottom(r);
30}
31/* Rect::inner(Margin): ZERO when the margins don't fit. */
32static inline tui_rect tui_rect_inner(tui_rect r, uint16_t horizontal, uint16_t vertical) {
33 uint32_t dh = (uint32_t)horizontal * 2, dv = (uint32_t)vertical * 2;
34 if (dh > 0xFFFF) dh = 0xFFFF;
35 if (dv > 0xFFFF) dv = 0xFFFF;
36 if (r.width < dh || r.height < dv) return (tui_rect){0, 0, 0, 0};
37 return (tui_rect){tui_sat_add(r.x, horizontal), tui_sat_add(r.y, vertical), (uint16_t)(r.width - dh),
38 (uint16_t)(r.height - dv)};
39}
40static inline tui_rect tui_rect_intersection(tui_rect a, tui_rect b) {
41 uint16_t x1 = tui_max16(a.x, b.x), y1 = tui_max16(a.y, b.y);
42 uint16_t x2 = tui_min16(tui_rect_right(a), tui_rect_right(b)), y2 = tui_min16(tui_rect_bottom(a), tui_rect_bottom(b));
43 return (tui_rect){x1, y1, tui_sat_sub(x2, x1), tui_sat_sub(y2, y1)};
44}
45static inline tui_rect tui_rect_union(tui_rect a, tui_rect b) {
46 uint16_t x1 = tui_min16(a.x, b.x), y1 = tui_min16(a.y, b.y);
47 uint16_t x2 = tui_max16(tui_rect_right(a), tui_rect_right(b)), y2 = tui_max16(tui_rect_bottom(a), tui_rect_bottom(b));
48 return (tui_rect){x1, y1, tui_sat_sub(x2, x1), tui_sat_sub(y2, y1)};
49}
50/* Rect::indent_x: moves the left edge right by offset, keeping the right edge. */
51static inline tui_rect tui_rect_indent_x(tui_rect r, uint16_t offset) {
52 r.x = tui_sat_add(r.x, offset);
53 r.width = tui_sat_sub(r.width, offset);
54 return r;
55}
56/* Row i of r (Rect::rows), height 1. */
57static inline tui_rect tui_rect_row(tui_rect r, uint16_t i) { return (tui_rect){r.x, (uint16_t)(r.y + i), r.width, 1}; }
58static inline bool tui_rect_eq(tui_rect a, tui_rect b) {
59 return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height;
60}
61
62#endif