diff options
author | VAN BOSSUYT Nicolas <nvanbossuyt@underside.be> | 2022-03-08 09:24:33 +0100 |
---|---|---|
committer | VAN BOSSUYT Nicolas <nicolas.van.bossuyt@gmail.com> | 2022-03-16 21:20:55 +0100 |
commit | 67837b6ee1153f8e21794130363f0eb35463fdf2 (patch) | |
tree | ee0dabd87e20b92753bb57afba1da02c8e32ee6e | |
parent | c83ed277f3638c8f6f963f7a4dade52450da6b17 (diff) |
-rw-r--r-- | sources/apps/clock/main.c | 139 | ||||
-rw-r--r-- | sources/libs/brutal/base/macros.h | 7 | ||||
-rw-r--r-- | sources/libs/ui/event.h | 6 | ||||
-rw-r--r-- | sources/libs/ui/funcs.h | 23 | ||||
-rw-r--r-- | sources/libs/ui/hooks.h | 48 | ||||
-rw-r--r-- | sources/libs/ui/layout.h | 23 | ||||
-rw-r--r-- | sources/libs/ui/macros.h | 9 | ||||
-rw-r--r-- | sources/libs/ui/traits.h | 25 | ||||
-rw-r--r-- | sources/libs/ui/ui.h | 8 | ||||
-rw-r--r-- | sources/libs/ui/views.h | 37 |
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); + } + } +} |