summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVAN BOSSUYT Nicolas <nvanbossuyt@underside.be>2022-03-08 09:24:33 +0100
committerVAN BOSSUYT Nicolas <nicolas.van.bossuyt@gmail.com>2022-03-16 21:20:55 +0100
commit67837b6ee1153f8e21794130363f0eb35463fdf2 (patch)
treeee0dabd87e20b92753bb57afba1da02c8e32ee6e
parentc83ed277f3638c8f6f963f7a4dade52450da6b17 (diff)
-rw-r--r--sources/apps/clock/main.c139
-rw-r--r--sources/libs/brutal/base/macros.h7
-rw-r--r--sources/libs/ui/event.h6
-rw-r--r--sources/libs/ui/funcs.h23
-rw-r--r--sources/libs/ui/hooks.h48
-rw-r--r--sources/libs/ui/layout.h23
-rw-r--r--sources/libs/ui/macros.h9
-rw-r--r--sources/libs/ui/traits.h25
-rw-r--r--sources/libs/ui/ui.h8
-rw-r--r--sources/libs/ui/views.h37
10 files changed, 323 insertions, 2 deletions
diff --git a/sources/apps/clock/main.c b/sources/apps/clock/main.c
new file mode 100644
index 00000000..e4ae7bca
--- /dev/null
+++ b/sources/apps/clock/main.c
@@ -0,0 +1,139 @@
+#include <brutal/time.h>
+#include <ui/ui.h>
+
+typedef struct
+{
+ enum
+ {
+ P_TIME,
+ P_TIMER,
+ P_CHRONO
+ } page;
+
+ int timer;
+ bool timer_running;
+
+ int chrono;
+ bool chrono_running;
+
+ Vec(TimeStamp) laps;
+} Clock;
+
+void clock_deinit(void *p)
+{
+ Clock *c = p;
+ vec_deinit(&c->laps);
+}
+
+Clock *clock_state(Ui *ui)
+{
+ Clock *state = ui_use_state$(ui, (Clock){});
+
+ if (ui_use_effect(ui, clock_deinit))
+ {
+ vec_init(&state->laps, ui_use_alloc(ui));
+ }
+
+ if (ui_use_timer(ui, state->timer_running, 1000))
+ {
+ state->timer--;
+ state->timer_running = state->timer > 0;
+ ui_update(ui, UI_STATE);
+ }
+
+ if (ui_use_timer(ui, state->chrono_running, 100))
+ {
+ state->chrono++;
+ ui_update(ui, UI_STATE);
+ }
+
+ return state;
+}
+
+void clock_render(Ui *ui)
+{
+ Clock *state = clock_state(ui);
+
+ switch (state->page)
+ {
+
+ default:
+ case P_TIME:
+ {
+ ui_text(ui, "Time");
+ Time dt = time_now();
+ ui_text_fmt$(ui, "%02d:%02d:%02d", dt.hour, dt.minute, dt.second);
+ break;
+ }
+
+ case P_TIMER:
+ ui_text(ui, "Timer");
+ ui_text_fmt$(ui, "%02d:%02d:%02d", state->timer / 3600, (state->timer / 60) % 60, state->timer % 60);
+
+ if (ui_button(ui, "Start/Pause"))
+ {
+ state->timer_running = !state->timer_running;
+ ui_update(ui, UI_STATE);
+ }
+
+ if (ui_button(ui, "Reset"))
+ {
+ state->timer = 60 * 60 * 5;
+ state->timer_running = false;
+ ui_update(ui, UI_STATE);
+ }
+ break;
+
+ case P_CHRONO:
+ ui_text(ui, "Chrono");
+ ui_text_fmt$(ui, "%02d:%02d:%02d", state->chrono / 3600, (state->chrono / 60) % 60, state->chrono % 60);
+
+ vec_foreach_v(lap, &state->laps)
+ {
+ ui_text_fmt$(ui, "%02d:%02d:%02d", lap / 3600, (lap / 60) % 60, lap % 60);
+ }
+
+ if (ui_button(ui, "Start/Pause"))
+ {
+ state->chrono_running = !state->chrono_running;
+ ui_update(ui, UI_STATE);
+ }
+
+ if (ui_button(ui, "Reset"))
+ {
+ state->chrono = 0;
+ vec_clear(&state->laps);
+ ui_update(ui, UI_STATE);
+ }
+
+ if (ui_button(ui, "Lap"))
+ {
+ vec_push(&state->laps, state->chrono);
+ ui_update(ui, UI_STATE);
+ }
+ break;
+ }
+
+ ui_scope$(ui, ui_panel)
+ {
+ if (ui_button(ui, "Time"))
+ {
+ state->page = P_TIME;
+ ui_update(ui, UI_STATE);
+ }
+
+ if (ui_button(ui, "Timer"))
+ {
+ state->page = P_TIMER;
+ ui_update(ui, UI_STATE);
+ }
+
+ if (ui_button(ui, "Chrono"))
+ {
+ state->page = P_CHRONO;
+ ui_update(ui, UI_STATE);
+ }
+ }
+}
+
+ui_main$(clock_render)
diff --git a/sources/libs/brutal/base/macros.h b/sources/libs/brutal/base/macros.h
index ae4a7c7e..c5152ad1 100644
--- a/sources/libs/brutal/base/macros.h
+++ b/sources/libs/brutal/base/macros.h
@@ -1,8 +1,8 @@
#pragma once
-#define __concat_impl$(LHS, RHS) LHS##RHS
+#define __concat$(LHS, RHS) LHS##RHS
-#define concat$(LHS, RHS) __concat_impl$(LHS, RHS)
+#define concat$(LHS, RHS) __concat$(LHS, RHS)
// Align the nearest _lower_ aligned address
// ex: 8 with align = 8 -> 8
@@ -33,3 +33,6 @@
*(X) = *(Y); \
*(Y) = __swap_tmp; \
} while (0)
+
+#define var$(NAME) concat$(NAME, __LINE__)
+#define defer$(BEGIN, END) for (int var$(__i) = (BEGIN, 0); !var$(__i); (var$(__i) += 1, END))
diff --git a/sources/libs/ui/event.h b/sources/libs/ui/event.h
new file mode 100644
index 00000000..01a53adc
--- /dev/null
+++ b/sources/libs/ui/event.h
@@ -0,0 +1,6 @@
+#pragma once
+
+typedef struct
+{
+
+} Ev;
diff --git a/sources/libs/ui/funcs.h b/sources/libs/ui/funcs.h
new file mode 100644
index 00000000..08bae79f
--- /dev/null
+++ b/sources/libs/ui/funcs.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <ui/traits.h>
+
+static inline bool ui_begin(Ui *ui)
+{
+ return ui->begin(ui->context);
+}
+
+static inline void ui_end(Ui *ui)
+{
+ ui->end(ui->context);
+}
+
+static inline void *ui_use(Ui *ui, int what)
+{
+ return ui->use(ui->context, what);
+}
+
+static inline void ui_update(Ui *ui, int what)
+{
+ ui->update(ui->context, what);
+}
diff --git a/sources/libs/ui/hooks.h b/sources/libs/ui/hooks.h
new file mode 100644
index 00000000..89fe7114
--- /dev/null
+++ b/sources/libs/ui/hooks.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <brutal/gfx.h>
+#include <brutal/math.h>
+#include <ui/event.h>
+#include <ui/funcs.h>
+#include <ui/layout.h>
+
+enum
+{
+ UI_HOOK_EFFECT,
+ UI_HOOK_STATE,
+ UI_HOOK_LAYOUT,
+ UI_HOOK_VISUAL,
+ UI_HOOK_EVENT,
+ UI_HOOK_TIMER,
+
+ UI_HOOKS_COUNT
+};
+
+static bool ui_use_effect(Ui *ui, void (*)(void *))
+{
+ return ui_use(ui, UI_HOOK_EFFECT) != nullptr;
+}
+
+static void *ui_use_state(Ui *ui, void *, size_t)
+{
+}
+
+static MRectf ui_use_bound(Ui *ui)
+{
+}
+
+static Lay *ui_use_layout(Ui *ui)
+{
+}
+
+static Gfx *ui_use_visual(Ui *ui)
+{
+}
+
+static Ev *ui_use_event(Ui *ui)
+{
+}
+
+static bool ui_use_timer(Ui *ui, bool active, int delta)
+{
+}
diff --git a/sources/libs/ui/layout.h b/sources/libs/ui/layout.h
new file mode 100644
index 00000000..a154ac9a
--- /dev/null
+++ b/sources/libs/ui/layout.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <brutal/ds.h>
+#include <brutal/ui/layout.h>
+
+typedef struct
+{
+ int child;
+ int next;
+ MRectf bound;
+ UiLayout layout;
+} Lay;
+
+typedef struct
+{
+ Vec(Lay);
+} LayTree;
+
+typedef struct
+{
+ LayTree tree;
+ Vec(int) stack;
+} LayBuilder;
diff --git a/sources/libs/ui/macros.h b/sources/libs/ui/macros.h
new file mode 100644
index 00000000..99e2c8bd
--- /dev/null
+++ b/sources/libs/ui/macros.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <ui/funcs.h>
+
+#define ui_use_state$(UI, STATE) (typeof(STATE) *)ui_use_state(UI, &(STATE), sizeof(STATE))
+#define ui_scope$(UI, TYPE, ...) defer$(TYPE##_begin(UI __VA_OPT__(, ) __VA_ARGS__), ui_end(UI))
+#define ui_begin$(UI) ({if (!ui_begin(UI)) return false; true; })
+#define ui_main$(FUN) \
+ int main() { return 0; }
diff --git a/sources/libs/ui/traits.h b/sources/libs/ui/traits.h
new file mode 100644
index 00000000..8dff7843
--- /dev/null
+++ b/sources/libs/ui/traits.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <brutal/base.h>
+
+/* --- Context -------------------------------------------------------------- */
+
+#define UI_STATE (1 << 0)
+#define UI_LAYOUT (1 << 1)
+#define UI_VISUAL (1 << 2)
+
+typedef bool UiBegin(void *ctx);
+typedef void UiEnd(void *ctx);
+typedef void *UiUse(void *ctx, int what);
+
+typedef void *UiUpdate(void *ctx, int what);
+
+typedef struct
+{
+ void *context;
+
+ UiBegin *begin;
+ UiEnd *end;
+ UiUse *use;
+ UiUpdate *update;
+} Ui;
diff --git a/sources/libs/ui/ui.h b/sources/libs/ui/ui.h
new file mode 100644
index 00000000..f4d9e6c3
--- /dev/null
+++ b/sources/libs/ui/ui.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <ui/funcs.h>
+#include <ui/hooks.h>
+#include <ui/layout.h>
+#include <ui/macros.h>
+#include <ui/traits.h>
+#include <ui/views.h>
diff --git a/sources/libs/ui/views.h b/sources/libs/ui/views.h
new file mode 100644
index 00000000..5797d48c
--- /dev/null
+++ b/sources/libs/ui/views.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <ui/macros.h>
+
+static bool ui_button_begin(Ui *ui)
+{
+ ui_begin$(ui);
+
+ struct State
+ {
+ bool over;
+ };
+
+ struct State *state = ui_use_state$(ui, (struct State){});
+
+ Gfx *gfx;
+ if ((gfx = ui_use_visual(ui)))
+ {
+ gfx_paint(gfx, state->over ? GFX_LIGHTBLUE : GFX_BLUE);
+ gfx_fill_rect(gfx, ui_use_bound(ui));
+ }
+
+ Ev *ev;
+ if ((ev = ui_use_event(ui)))
+ {
+ if (ev->type == EV_ENTER)
+ {
+ state->over = true;
+ ui_update(ui, UI_VISUAL);
+ }
+ else if (ev->type == EV_LEAVE)
+ {
+ state->over = false;
+ ui_update(ui, UI_VISUAL);
+ }
+ }
+}