summaryrefslogtreecommitdiff
path: root/src/widget
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2026-03-25 19:59:14 -0700
committer3gg <3gg@shellblade.net>2026-03-25 19:59:14 -0700
commit4152fbecb6ee8360575aa4c24e9cedf822f159dc (patch)
tree9e9b9db0216a37c5867d472a65289502c459691f /src/widget
parent7778755c20e779554cd654ecdf7404d37b723fcc (diff)
Implement vertical and horizontal layouts. Use widget position properly when rendering. Toolbar, buttons and edit bars WIPmain
Diffstat (limited to 'src/widget')
-rw-r--r--src/widget/button.c9
-rw-r--r--src/widget/frame.c9
-rw-r--r--src/widget/label.c13
-rw-r--r--src/widget/layout.c25
-rw-r--r--src/widget/table.c13
-rw-r--r--src/widget/widget.c109
-rw-r--r--src/widget/widget.h14
7 files changed, 172 insertions, 20 deletions
diff --git a/src/widget/button.c b/src/widget/button.c
index f2313fd..d8de266 100644
--- a/src/widget/button.c
+++ b/src/widget/button.c
@@ -2,18 +2,21 @@
2 2
3#include "widget.h" 3#include "widget.h"
4 4
5uiButton* uiMakeButton(const char* text) { 5uiButton* uiMakeButton(uiPtr parent, const char* text, const uiParams* params) {
6 assert(text); 6 assert(text);
7 assert(params);
7 8
8 uiButton* button = UI_NEW(uiButton); 9 uiButton* button = UI_NEW(uiButton);
9 10
10 *button = (uiButton){ 11 *button = (uiButton){
11 .widget = 12 .widget =
12 (uiWidget){ 13 (uiWidget){
13 .type = uiTypeButton, 14 .type = uiTypeButton,
14 .rect = {0}, 15 .rect = {0},
16 .stretch = params->stretch,
15 }, 17 },
16 .text = string_new(text), 18 .text = string_new(text),
17 }; 19 };
20 WidgetSetParent(uiMakeButtonPtr(button), parent);
18 return button; 21 return button;
19} 22}
diff --git a/src/widget/frame.c b/src/widget/frame.c
index e1078be..7640e42 100644
--- a/src/widget/frame.c
+++ b/src/widget/frame.c
@@ -3,8 +3,13 @@
3#include "widget.h" 3#include "widget.h"
4 4
5uiFrame* uiMakeFrame(void) { 5uiFrame* uiMakeFrame(void) {
6 uiFrame* frame = UI_NEW(uiFrame); 6 uiFrame* frame = UI_NEW(uiFrame);
7 frame->widget.type = uiTypeFrame; 7
8 *frame = (uiFrame){
9 .widget =
10 (uiWidget){.type = uiTypeFrame, .stretch = uiStretchX | uiStretchY}
11 };
12
8 return frame; 13 return frame;
9} 14}
10 15
diff --git a/src/widget/label.c b/src/widget/label.c
index 30ca0ec..5c0c00a 100644
--- a/src/widget/label.c
+++ b/src/widget/label.c
@@ -3,22 +3,21 @@
3#include "uiLibrary.h" 3#include "uiLibrary.h"
4#include "widget.h" 4#include "widget.h"
5 5
6uiLabel* uiMakeLabel(const char* text) { 6uiLabel* uiMakeLabel(uiPtr parent, const char* text) {
7 assert(text); 7 assert(text);
8 8
9 uiLabel* label = UI_NEW(uiLabel); 9 uiLabel* label = UI_NEW(uiLabel);
10 10
11 *label = (uiLabel){ 11 *label = (uiLabel){
12 .widget = 12 .widget =
13 (uiWidget){ 13 (uiWidget){.type = uiTypeLabel,
14 .type = uiTypeLabel,
15 .rect = 14 .rect =
16 (uiRect){ 15 (uiRect){.width = (int)strlen(text) *
17 .width = 16 g_ui.font->header.glyph_width,
18 (int)strlen(text) * g_ui.font->header.glyph_width, 17 .height = g_ui.font->header.glyph_height}},
19 .height = g_ui.font->header.glyph_height}},
20 .text = string_new(text), 18 .text = string_new(text),
21 }; 19 };
20 WidgetSetParent(uiMakeLabelPtr(label), parent);
22 return label; 21 return label;
23} 22}
24 23
diff --git a/src/widget/layout.c b/src/widget/layout.c
new file mode 100644
index 0000000..c529c56
--- /dev/null
+++ b/src/widget/layout.c
@@ -0,0 +1,25 @@
1#include "widget.h"
2
3static uiStretch StretchFromDirection(uiLayoutDirection direction) {
4 switch (direction) {
5 case uiHorizontal:
6 return uiStretchX;
7 case uiVertical:
8 return uiStretchY;
9 }
10 assert(false);
11 return uiStretchNone;
12}
13
14uiLayout* uiMakeLayout(uiPtr parent, uiLayoutDirection direction) {
15 uiLayout* layout = UI_NEW(uiLayout);
16
17 *layout = (uiLayout){
18 .widget = (uiWidget){.type = uiTypeLayout,
19 .stretch = StretchFromDirection(direction)},
20 .direction = direction,
21 };
22 WidgetSetParent(uiMakeLayoutPtr(layout), parent);
23
24 return layout;
25}
diff --git a/src/widget/table.c b/src/widget/table.c
index e7d412e..d9a6440 100644
--- a/src/widget/table.c
+++ b/src/widget/table.c
@@ -3,11 +3,12 @@
3#define Min(a, b) ((a) < (b) ? (a) : (b)) 3#define Min(a, b) ((a) < (b) ? (a) : (b))
4#define Max(a, b) ((a) > (b) ? (a) : (b)) 4#define Max(a, b) ((a) > (b) ? (a) : (b))
5 5
6uiTable* uiMakeTable(int rows, int cols, const char** header) { 6uiTable* uiMakeTable(uiPtr parent, int rows, int cols, const char** header) {
7 uiTable* table = UI_NEW(uiTable); 7 uiTable* table = UI_NEW(uiTable);
8 8
9 *table = (uiTable){ 9 *table = (uiTable){
10 .widget = (uiWidget){.type = uiTypeTable}, 10 .widget =
11 (uiWidget){.type = uiTypeTable, .stretch = (uiStretchX | uiStretchY)},
11 .rows = rows, 12 .rows = rows,
12 .cols = cols, 13 .cols = cols,
13 .widths = (cols > 0) ? calloc(cols, sizeof(int)) : 0, 14 .widths = (cols > 0) ? calloc(cols, sizeof(int)) : 0,
@@ -15,6 +16,7 @@ uiTable* uiMakeTable(int rows, int cols, const char** header) {
15 .cells = (rows * cols > 0) ? calloc(rows, sizeof(uiCell*)) : 0, 16 .cells = (rows * cols > 0) ? calloc(rows, sizeof(uiCell*)) : 0,
16 .flags = {0}, 17 .flags = {0},
17 }; 18 };
19 WidgetSetParent(uiMakeTablePtr(table), parent);
18 20
19 if (header) { 21 if (header) {
20 for (int col = 0; col < cols; ++col) { 22 for (int col = 0; col < cols; ++col) {
@@ -91,13 +93,14 @@ void SyncScrollbarToTable(uiTable* table) {
91 assert(table); 93 assert(table);
92 ScrollbarScroll( 94 ScrollbarScroll(
93 &table->scrollbar, (int)((double)table->offset / (double)table->rows * 95 &table->scrollbar, (int)((double)table->offset / (double)table->rows *
94 (double)table->height)); 96 (double)table->widget.rect.height));
95} 97}
96 98
97void SyncTableToScrollbar(uiTable* table) { 99void SyncTableToScrollbar(uiTable* table) {
98 assert(table); 100 assert(table);
99 table->offset = (int)((double)table->scrollbar.handle_y / 101 table->offset =
100 (double)table->height * (double)table->rows); 102 (int)((double)table->scrollbar.handle_y /
103 (double)table->widget.rect.height * (double)table->rows);
101} 104}
102 105
103const uiCell* TableGetCell(const uiTable* table, int row, int col) { 106const uiCell* TableGetCell(const uiTable* table, int row, int col) {
diff --git a/src/widget/widget.c b/src/widget/widget.c
index ebcaf10..2c525cc 100644
--- a/src/widget/widget.c
+++ b/src/widget/widget.c
@@ -2,6 +2,8 @@
2 2
3#include <cassert.h> 3#include <cassert.h>
4 4
5#include <stdio.h>
6
5// ----------------------------------------------------------------------------- 7// -----------------------------------------------------------------------------
6// Widget. 8// Widget.
7 9
@@ -30,14 +32,19 @@ void DestroyWidget(uiWidget** ppWidget) {
30 UI_DEL(ppWidget); 32 UI_DEL(ppWidget);
31} 33}
32 34
33void uiWidgetSetParent(uiPtr child_, uiPtr parent_) { 35void WidgetSetParent(uiPtr child_, uiPtr parent_) {
34 uiWidget* child = child_.widget; 36 uiWidget* child = child_.widget;
35 uiWidget* parent = parent_.widget; 37 uiWidget* parent = parent_.widget;
36 38
37 assert(child); 39 assert(child);
38 assert(parent); 40 assert(parent);
39 41
40 list_add(parent->children, child); 42 if (!uiIsNullptr(child->parent)) {
43 list_remove(child->parent.widget->children, child);
44 }
45
46 list_push(parent->children, child);
47 child->parent = parent_;
41} 48}
42 49
43// ----------------------------------------------------------------------------- 50// -----------------------------------------------------------------------------
@@ -58,6 +65,11 @@ uiPtr uiMakeLabelPtr(uiLabel* label) {
58 return (uiPtr){.type = uiTypeLabel, .label = label}; 65 return (uiPtr){.type = uiTypeLabel, .label = label};
59} 66}
60 67
68uiPtr uiMakeLayoutPtr(uiLayout* layout) {
69 assert(layout);
70 return (uiPtr){.type = uiTypeLayout, .layout = layout};
71}
72
61uiPtr uiMakeTablePtr(uiTable* table) { 73uiPtr uiMakeTablePtr(uiTable* table) {
62 assert(table); 74 assert(table);
63 return (uiPtr){.type = uiTypeTable, .table = table}; 75 return (uiPtr){.type = uiTypeTable, .table = table};
@@ -72,6 +84,8 @@ uiPtr uiMakeWidgetPtr(uiWidget* widget) {
72 return uiMakeFramePtr((uiFrame*)widget); 84 return uiMakeFramePtr((uiFrame*)widget);
73 case uiTypeLabel: 85 case uiTypeLabel:
74 return uiMakeLabelPtr((uiLabel*)widget); 86 return uiMakeLabelPtr((uiLabel*)widget);
87 case uiTypeLayout:
88 return uiMakeLayoutPtr((uiLayout*)widget);
75 case uiTypeTable: 89 case uiTypeTable:
76 return uiMakeTablePtr((uiTable*)widget); 90 return uiMakeTablePtr((uiTable*)widget);
77 default: 91 default:
@@ -103,8 +117,99 @@ uiLabel* uiGetLabelPtr(uiPtr ptr) {
103 return ptr.label; 117 return ptr.label;
104} 118}
105 119
120uiLayout* uiGetLayoutPtr(uiPtr ptr) {
121 assert(ptr.type == uiTypeLayout);
122 assert(ptr.layout);
123 return ptr.layout;
124}
125
126uiEdit* uiGetEditPtr(uiPtr ptr) {
127 assert(ptr.type == uiTypeEdit);
128 assert(ptr.edit);
129 return ptr.edit;
130}
131
106uiTable* uiGetTablePtr(uiPtr ptr) { 132uiTable* uiGetTablePtr(uiPtr ptr) {
107 assert(ptr.type == uiTypeTable); 133 assert(ptr.type == uiTypeTable);
108 assert(ptr.table); 134 assert(ptr.table);
109 return ptr.table; 135 return ptr.table;
110} 136}
137
138typedef struct PrintState {
139 mstring pad;
140 mstring rect;
141} PrintState;
142
143static void RectToString(uiRect rect, mstring* out) {
144 assert(out);
145 out->length = snprintf(
146 out->str, sizeof(out->str), "rect{(x:%d, y:%d), (w:%d, h:%d)", rect.x,
147 rect.y, rect.width, rect.height);
148}
149
150static void uiPrintRec(uiPtr ptr, PrintState* state) {
151 if (uiIsNullptr(ptr)) {
152 return;
153 }
154 RectToString(ptr.widget->rect, &state->rect);
155 switch (ptr.type) {
156 case uiTypeButton: {
157 const uiButton* button = uiGetButtonPtr(ptr);
158 printf(
159 "%sbutton{rect=%s, text=\"%s\"}\n", mstring_cstr(&state->pad),
160 mstring_cstr(&state->rect), string_cstr(&button->text));
161 break;
162 }
163 case uiTypeLabel: {
164 const uiLabel* label = uiGetLabelPtr(ptr);
165 printf(
166 "%sbutton{rect=%s, text=\"%s\"}\n", mstring_cstr(&state->pad),
167 mstring_cstr(&state->rect), string_cstr(&label->text));
168 break;
169 }
170 case uiTypeLayout: {
171 const uiLayout* layout = uiGetLayoutPtr(ptr);
172 const char* direction = "";
173 switch (layout->direction) {
174 case uiHorizontal:
175 direction = "horizontal";
176 break;
177 case uiVertical:
178 direction = "vertical";
179 break;
180 }
181 printf(
182 "%s%s_layout{rect=%s}\n", mstring_cstr(&state->pad), direction,
183 mstring_cstr(&state->rect));
184 break;
185 }
186 case uiTypeFrame: {
187 printf(
188 "%sframe{rect=%s}\n", mstring_cstr(&state->pad),
189 mstring_cstr(&state->rect));
190 break;
191 }
192 case uiTypeTable: {
193 const uiTable* table = uiGetTablePtr(ptr);
194 printf(
195 "%stable{rect=%s}\n", mstring_cstr(&state->pad),
196 mstring_cstr(&state->rect));
197 break;
198 }
199 default:
200 printf("%swidget\n", mstring_cstr(&state->pad));
201 break;
202 }
203 const mstring pad = state->pad;
204 state->pad = mstring_concat(state->pad, mstring_make(" "));
205 list_foreach(ptr.widget->children, child, {
206 uiPrintRec(uiMakeWidgetPtr(child), state);
207 });
208 state->pad = pad;
209}
210
211void uiPrint(uiPtr ptr) {
212 PrintState state =
213 (PrintState){.pad = mstring_make_empty(), .rect = mstring_make_empty()};
214 uiPrintRec(ptr, &state);
215}
diff --git a/src/widget/widget.h b/src/widget/widget.h
index db11164..7482d38 100644
--- a/src/widget/widget.h
+++ b/src/widget/widget.h
@@ -13,9 +13,16 @@ DEF_LIST(Widget, uiWidget*)
13typedef struct uiWidget { 13typedef struct uiWidget {
14 uiWidgetType type; 14 uiWidgetType type;
15 uiRect rect; 15 uiRect rect;
16 uiStretch stretch;
17 uiPtr parent;
16 Widget_list children; 18 Widget_list children;
17} uiWidget; 19} uiWidget;
18 20
21typedef struct uiLayout {
22 uiWidget widget;
23 uiLayoutDirection direction;
24} uiLayout;
25
19typedef struct uiButton { 26typedef struct uiButton {
20 uiWidget widget; 27 uiWidget widget;
21 string text; 28 string text;
@@ -30,6 +37,11 @@ typedef struct uiLabel {
30 string text; 37 string text;
31} uiLabel; 38} uiLabel;
32 39
40typedef struct uiEdit {
41 uiWidget widget;
42 string text;
43} uiEdit;
44
33typedef struct uiScrollbar { 45typedef struct uiScrollbar {
34 int width; 46 int width;
35 int height; // Total height: handle plus scrollable area. 47 int height; // Total height: handle plus scrollable area.
@@ -45,7 +57,6 @@ typedef struct uiTable {
45 uiWidget widget; 57 uiWidget widget;
46 int rows; 58 int rows;
47 int cols; 59 int cols;
48 int height; // Height in pixels.
49 int* widths; // Width, in pixels, for each column. 60 int* widths; // Width, in pixels, for each column.
50 uiCell* header; // If non-null, row of 'cols' header cells. 61 uiCell* header; // If non-null, row of 'cols' header cells.
51 uiCell** cells; // Array of 'rows' rows, each of 'cols' cells. 62 uiCell** cells; // Array of 'rows' rows, each of 'cols' cells.
@@ -57,6 +68,7 @@ typedef struct uiTable {
57 } flags; 68 } flags;
58} uiTable; 69} uiTable;
59 70
71void WidgetSetParent(uiPtr child, uiPtr parent);
60void DestroyWidget(uiWidget** ppWidget); 72void DestroyWidget(uiWidget** ppWidget);
61 73
62/// Set the scrollbar handle's y-coordinate, which is clipped to the scrollbar's 74/// Set the scrollbar handle's y-coordinate, which is clipped to the scrollbar's