summaryrefslogtreecommitdiff
path: root/src/widget
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2026-03-12 15:29:23 -0700
committer3gg <3gg@shellblade.net>2026-03-12 15:29:23 -0700
commit92978a10576d52a0f6c9983d3b6afae7c40eff40 (patch)
treebf73faed8aa1ecd71b9f61c37a549faf4cd30372 /src/widget
parent58c0f40df5947b3933bf7b6564b2ba5dc39fbd92 (diff)
Support scrolling by dragging scrollbars
Diffstat (limited to 'src/widget')
-rw-r--r--src/widget/scrollbar.c8
-rw-r--r--src/widget/table.c58
-rw-r--r--src/widget/widget.c21
-rw-r--r--src/widget/widget.h49
4 files changed, 98 insertions, 38 deletions
diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c
new file mode 100644
index 0000000..9cece5d
--- /dev/null
+++ b/src/widget/scrollbar.c
@@ -0,0 +1,8 @@
1#include "widget.h"
2
3int ScrollbarScroll(uiScrollbar* scrollbar, int y) {
4 assert(scrollbar);
5 scrollbar->handle_y =
6 Max(0, Min(scrollbar->height - scrollbar->handle_height, y));
7 return scrollbar->handle_y;
8}
diff --git a/src/widget/table.c b/src/widget/table.c
index 76a0413..e7d412e 100644
--- a/src/widget/table.c
+++ b/src/widget/table.c
@@ -1,20 +1,7 @@
1#include "widget.h" 1#include "widget.h"
2 2
3const uiCell* GetCell(const uiTable* table, int row, int col) { 3#define Min(a, b) ((a) < (b) ? (a) : (b))
4 assert(table); 4#define Max(a, b) ((a) > (b) ? (a) : (b))
5 return &table->cells[row][col];
6}
7
8uiCell* GetCellMut(uiTable* table, int row, int col) {
9 assert(table);
10 return (uiCell*)GetCell(table, row, col);
11}
12
13uiCell** GetLastRow(uiTable* table) {
14 assert(table);
15 assert(table->rows > 0);
16 return &table->cells[table->rows - 1];
17}
18 5
19uiTable* uiMakeTable(int rows, int cols, const char** header) { 6uiTable* uiMakeTable(int rows, int cols, const char** header) {
20 uiTable* table = UI_NEW(uiTable); 7 uiTable* table = UI_NEW(uiTable);
@@ -73,7 +60,7 @@ void uiTableAddRow(uiTable* table, const char** row) {
73 ASSERT(cells); 60 ASSERT(cells);
74 table->cells = cells; 61 table->cells = cells;
75 62
76 uiCell** pLastRow = GetLastRow(table); 63 uiCell** pLastRow = TableGetLastRow(table);
77 *pLastRow = calloc(table->cols, sizeof(uiCell)); 64 *pLastRow = calloc(table->cols, sizeof(uiCell));
78 ASSERT(*pLastRow); 65 ASSERT(*pLastRow);
79 uiCell* lastRow = *pLastRow; 66 uiCell* lastRow = *pLastRow;
@@ -86,10 +73,45 @@ void uiTableAddRow(uiTable* table, const char** row) {
86void uiTableSet(uiTable* table, int row, int col, const char* text) { 73void uiTableSet(uiTable* table, int row, int col, const char* text) {
87 assert(table); 74 assert(table);
88 assert(text); 75 assert(text);
89 GetCellMut(table, row, col)->text = string_new(text); 76 TableGetCellMut(table, row, col)->text = string_new(text);
90} 77}
91 78
92const char* uiTableGet(const uiTable* table, int row, int col) { 79const char* uiTableGet(const uiTable* table, int row, int col) {
93 assert(table); 80 assert(table);
94 return string_data(GetCell(table, row, col)->text); 81 return string_data(TableGetCell(table, row, col)->text);
82}
83
84void uiTableScroll(uiTable* table, int row) {
85 assert(table);
86 table->offset = Min(table->rows - table->num_visible_rows, Max(0, row));
87 SyncScrollbarToTable(table);
88}
89
90void SyncScrollbarToTable(uiTable* table) {
91 assert(table);
92 ScrollbarScroll(
93 &table->scrollbar, (int)((double)table->offset / (double)table->rows *
94 (double)table->height));
95}
96
97void SyncTableToScrollbar(uiTable* table) {
98 assert(table);
99 table->offset = (int)((double)table->scrollbar.handle_y /
100 (double)table->height * (double)table->rows);
101}
102
103const uiCell* TableGetCell(const uiTable* table, int row, int col) {
104 assert(table);
105 return &table->cells[row][col];
106}
107
108uiCell* TableGetCellMut(uiTable* table, int row, int col) {
109 assert(table);
110 return (uiCell*)TableGetCell(table, row, col);
111}
112
113uiCell** TableGetLastRow(uiTable* table) {
114 assert(table);
115 assert(table->rows > 0);
116 return &table->cells[table->rows - 1];
95} 117}
diff --git a/src/widget/widget.c b/src/widget/widget.c
index ef79ac4..ebcaf10 100644
--- a/src/widget/widget.c
+++ b/src/widget/widget.c
@@ -63,11 +63,28 @@ uiPtr uiMakeTablePtr(uiTable* table) {
63 return (uiPtr){.type = uiTypeTable, .table = table}; 63 return (uiPtr){.type = uiTypeTable, .table = table};
64} 64}
65 65
66static uiPtr uiMakeWidgetPtr(uiWidget* widget) { 66uiPtr uiMakeWidgetPtr(uiWidget* widget) {
67 assert(widget); 67 assert(widget);
68 return (uiPtr){.type = widget->type, .widget = widget}; 68 switch (widget->type) {
69 case uiTypeButton:
70 return uiMakeButtonPtr((uiButton*)widget);
71 case uiTypeFrame:
72 return uiMakeFramePtr((uiFrame*)widget);
73 case uiTypeLabel:
74 return uiMakeLabelPtr((uiLabel*)widget);
75 case uiTypeTable:
76 return uiMakeTablePtr((uiTable*)widget);
77 default:
78 ASSERT(false);
79 break;
80 }
81 return (uiPtr){0};
69} 82}
70 83
84uiPtr uiNullptr(void) { return (uiPtr){0}; }
85
86bool uiIsNullptr(uiPtr ptr) { return ptr.widget == 0; }
87
71uiButton* uiGetButtonPtr(uiPtr ptr) { 88uiButton* uiGetButtonPtr(uiPtr ptr) {
72 assert(ptr.type == uiTypeButton); 89 assert(ptr.type == uiTypeButton);
73 assert(ptr.button); 90 assert(ptr.button);
diff --git a/src/widget/widget.h b/src/widget/widget.h
index 63f3d94..db11164 100644
--- a/src/widget/widget.h
+++ b/src/widget/widget.h
@@ -16,39 +16,42 @@ typedef struct uiWidget {
16 Widget_list children; 16 Widget_list children;
17} uiWidget; 17} uiWidget;
18 18
19/// Button.
20typedef struct uiButton { 19typedef struct uiButton {
21 uiWidget widget; 20 uiWidget widget;
22 string text; 21 string text;
23} uiButton; 22} uiButton;
24 23
25/// Frame.
26typedef struct uiFrame { 24typedef struct uiFrame {
27 uiWidget widget; 25 uiWidget widget;
28} uiFrame; 26} uiFrame;
29 27
30/// Label.
31typedef struct uiLabel { 28typedef struct uiLabel {
32 uiWidget widget; 29 uiWidget widget;
33 string text; 30 string text;
34} uiLabel; 31} uiLabel;
35 32
36/// Table cell. 33typedef struct uiScrollbar {
34 int width;
35 int height; // Total height: handle plus scrollable area.
36 int handle_height; // Height of the scroll handle.
37 int handle_y; // Starting y-coordinate of the handle.
38} uiScrollbar;
39
37typedef struct uiCell { 40typedef struct uiCell {
38 string text; 41 string text;
39} uiCell; 42} uiCell;
40 43
41/// Table.
42typedef struct uiTable { 44typedef struct uiTable {
43 uiWidget widget; 45 uiWidget widget;
44 int rows; 46 int rows;
45 int cols; 47 int cols;
46 int height; // Height in pixels. 48 int height; // Height in pixels.
47 int* widths; // Width, in pixels, for each column. 49 int* widths; // Width, in pixels, for each column.
48 uiCell* header; // If non-null, row of 'cols' header cells. 50 uiCell* header; // If non-null, row of 'cols' header cells.
49 uiCell** cells; // Array of 'rows' rows, each of 'cols' cells. 51 uiCell** cells; // Array of 'rows' rows, each of 'cols' cells.
50 int offset; // Offset into the rows of the table. Units: rows. 52 int offset; // Offset into the rows of the table. Units: rows.
51 int num_visible_rows; // The number of rows that are visible at once. 53 int num_visible_rows; // The number of rows that are visible at once.
54 uiScrollbar scrollbar;
52 struct { 55 struct {
53 bool vertical_overflow : 1; // True if contents overflow vertically. 56 bool vertical_overflow : 1; // True if contents overflow vertically.
54 } flags; 57 } flags;
@@ -56,14 +59,24 @@ typedef struct uiTable {
56 59
57void DestroyWidget(uiWidget** ppWidget); 60void DestroyWidget(uiWidget** ppWidget);
58 61
59const uiCell* GetCell(const uiTable* table, int row, int col); 62/// Set the scrollbar handle's y-coordinate, which is clipped to the scrollbar's
60uiCell* GetCellMut(uiTable* table, int row, int col); 63/// rectangle.
61uiCell** GetLastRow(uiTable* table); 64///
65/// Return the handle's y-coordinate after clipping.
66int ScrollbarScroll(uiScrollbar*, int y);
62 67
63#define UI_NEW(TYPE) (TYPE*)uiAlloc(1, sizeof(TYPE)) 68const uiCell* TableGetCell(const uiTable*, int row, int col);
69uiCell* TableGetCellMut(uiTable*, int row, int col);
70uiCell** TableGetLastRow(uiTable*);
71void SyncScrollbarToTable(uiTable*);
72void SyncTableToScrollbar(uiTable*);
73
74static inline int Min(int a, int b) { return a < b ? a : b; }
75static inline int Max(int a, int b) { return a > b ? a : b; }
64 76
65static inline void* uiAlloc(size_t count, size_t size) { 77static inline void* uiAlloc(size_t count, size_t size) {
66 void* mem = calloc(count, size); 78 void* mem = calloc(count, size);
67 ASSERT(mem); 79 ASSERT(mem);
68 return mem; 80 return mem;
69} 81}
82#define UI_NEW(TYPE) (TYPE*)uiAlloc(1, sizeof(TYPE))