summaryrefslogtreecommitdiff
path: root/gui.c
diff options
context:
space:
mode:
Diffstat (limited to 'gui.c')
-rw-r--r--gui.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/gui.c b/gui.c
new file mode 100644
index 0000000..0fe1f69
--- /dev/null
+++ b/gui.c
@@ -0,0 +1,198 @@
+#include "gui.h"
+#include "memory.h"
+#include "plat.h"
+#include "render.h"
+#include "standard.h"
+
+void* gui_alloc(GUI* g, int size) {
+ GUI_El* e = arena_alloc(g->a, size);
+ if (g->prev)
+ g->prev->next = e;
+ if (!g->first)
+ g->first = e;
+ g->prev = e;
+ e->next = 0;
+ return e;
+}
+
+void gui_begin(GUI* g, const App* app, Arena* a) {
+ g->a = a;
+ g->app = app;
+ g->pad = 2;
+ g->first = 0;
+ g->cursor[0] = 10;
+ g->cursor[1] = 10;
+}
+
+void gui_get_layout(GUI* g, Rect* r) {
+ r->x = g->cursor[0];
+ r->y = g->cursor[1];
+ g->cursor[1] += r->h;
+}
+
+int gui_text_width(const char* text, int len) {
+ (void)text;
+ return len * 10;
+}
+
+int gui_text_height(void) {
+ return 10;
+}
+
+int mouse_over(const App* app, const Rect* r) {
+ return
+ app->mx > r->x &&
+ app->my > r->y &&
+ app->mx < r->x + r->w &&
+ app->my < r->y + r->h;
+}
+
+Rect gui_viewport(GUI* g) {
+ Rect r = { 0 };
+ r.w = g->app->w;
+ r.h = g->app->h;
+ return r;
+}
+
+Rect gui_cut_left(Rect* a, int v) {
+ Rect r = * a;
+ a->x += v;
+ a->w -= v;
+ r.w -= a->w;
+ return r;
+}
+
+Rect gui_cut_right(Rect* a, int v) {
+ Rect r = *a;
+ a->w -= v;
+ r.x += v;
+ r.w -= v;
+ return r;
+}
+
+Rect gui_cut_down(Rect* a, int v) {
+ Rect r = *a;
+ a->h -= v;
+ r.y += v;
+ r.h -= v;
+ return r;
+}
+
+Rect gui_cut_up(Rect* a, int v) {
+ Rect r = * a;
+ a->y += v;
+ a->h -= v;
+ r.h -= a->h;
+ return r;
+}
+
+int gui_btn(GUI* g, Rect r, const char* text) {
+ int len = string_len(text);
+ GUI_Btn* e = gui_alloc(g, sizeof *e);
+ e->el.type = gui_el_type_btn;
+ e->el.r = r;
+ e->text = arena_alloc_aligned(g->a, len + 1, 1);
+ string_copy(e->text, text);
+ e->hover = mouse_over(g->app, &e->el.r);
+ e->active = e->hover &&
+ g->app->mbtn_states[mbtn_left] & key_state_pressed;
+ return e->hover &&
+ g->app->mbtn_states[mbtn_left] & key_state_just_released;
+}
+
+void gui_scrollable(
+ GUI* g,
+ Rect r,
+ GUI_Scroll_State* state,
+ GUI_Scrollable_Draw_Fn fn
+) {
+ GUI_Scrollable* e = gui_alloc(g, sizeof *e);
+ e->el.type = gui_el_type_scrollable;
+ e->el.r = r;
+ e->ss = state;
+ e->draw = fn;
+}
+
+void rect_cfit(Rect* r) {
+ r->x++;
+ r->y++;
+ r->w -= 2;
+ r->h -= 2;
+}
+
+void draw_container(Renderer* r, const Rect* rect, int active) {
+ const Colour bg = make_colour(0xc3c3c3, 0xff);
+ Colour out1 = make_colour(0xffffff, 0xff);
+ Colour out2 = make_colour(0x000000, 0xff);
+ Rect t = *rect;
+ if (active) {
+ Colour t = out1;
+ out1 = out2;
+ out2 = t;
+ }
+ ren_rect(r, bg, rect);
+ t.h = 1;
+ ren_rect(r, out1, &t);
+ t.w = 1;
+ t.h = rect->h;
+ ren_rect(r, out1, &t);
+ t.h--;
+ t.x += rect->w - 1;
+ t.y++;
+ ren_rect(r, out2, &t);
+ t.y = rect->y + rect->h - 1;
+ t.x = rect->x + 1;
+ t.w = rect->w - 1;
+ t.h = 1;
+ ren_rect(r, out2, &t);
+}
+
+void draw_btn(GUI* g, Renderer* r, const GUI_Btn* btn) {
+ const Colour txt = make_colour(0x000000, 0xff);
+ int tp[2];
+ Rect rect = btn->el.r;
+ (void)g;
+ tp[0] =
+ rect.x + rect.w / 2 -
+ gui_text_width(btn->text, string_len(btn->text)) / 2;
+ tp[1] =
+ rect.y + rect.h / 2 -
+ gui_text_height() / 2;
+ if (btn->active) {
+ tp[0]++;
+ tp[1]++;
+ }
+ draw_container(r, &rect, btn->active);
+ rect_cfit(&rect);
+ ren_clip(r, &rect);
+ ren_text(r, txt, tp[0], tp[1], btn->text);
+ ren_clipr(r);
+}
+
+void draw_scrollable(
+ GUI* g,
+ Renderer* r,
+ const GUI_Scrollable* s
+) {
+ Rect rect = s->el.r;
+ draw_container(r, &s->el.r, 0);
+ rect_cfit(&rect);
+ ren_clip(r, &rect);
+ s->draw(g, r, &rect, s->ss);
+ ren_clipr(r);
+}
+
+void gui_end(GUI* g, Renderer* r) {
+ GUI_El* el = g->first;
+ while (el) {
+ switch (el->type) {
+ case gui_el_type_btn:
+ draw_btn(g, r, (GUI_Btn*)el);
+ break;
+ case gui_el_type_scrollable:
+ draw_scrollable(g, r, (GUI_Scrollable*)el);
+ break;
+ }
+ el = el->next;
+ }
+}