cepheid

An Aurora 4X clone
Log | Files | Refs | README

commit 3f0e6475dd2dd06e821de038bab8ce7d0edd409b
parent cb22e8c5355b5677d096ffc9e089e2b738a4ecb6
Author: hhvn <dev@hhvn.uk>
Date:   Sat, 17 Sep 2022 05:19:55 +0100

Move gui elements and handlers to separate file

Diffstat:
Msrc/main.h | 14+++++++++-----
Msrc/struct.h | 2+-
Msrc/ui.c | 231+++++--------------------------------------------------------------------------
Msrc/ui/bodies.c | 12++++++------
Msrc/ui/main.c | 22+++++++++-------------
Asrc/uielem.c | 230+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 269 insertions(+), 242 deletions(-)

diff --git a/src/main.h b/src/main.h @@ -63,6 +63,7 @@ extern View_sys view_sys; extern int charpx; void ui_init(void); void ui_update_screen(void); +void ui_update_focus(enum UiElements type, void *p); int ui_loop(void); void ui_deinit(void); void ui_print(int x, int y, Color col, char *format, ...); @@ -75,7 +76,6 @@ int ui_onscreen(Vector2 point); int ui_onscreen_ring(Vector2 centre, float r); int ui_onscreen_circle(Vector2 centre, float r); void ui_clickable_register(Geom geom, enum UiElements type, void *elem); -void ui_clickable_handle(Vector2 mouse, MouseButton button, Clickable *clickable); int ui_clickable_update(void); void ui_clickable_clear(void); void ui_keyboard_handle(void); @@ -88,11 +88,7 @@ void ui_draw_texture(Texture2D texture, int x, int y); void ui_draw_circle(int x, int y, float r, Color col); void ui_draw_line(int sx, int sy, int ex, int ey, float thick, Color col); void ui_draw_line_v(Vector2 start, Vector2 end, float thick, Color col); -void ui_draw_tabs(int x, int y, int w, int h, Tabs *tabs); void ui_draw_tabbed_window(int x, int y, int w, int h, Tabs *tabs); -int ui_draw_checkbox(int x, int y, Checkbox *checkbox); /* returns width */ -void ui_draw_dropdown(int x, int y, int w, Dropdown *d); -void ui_draw_input(int x, int y, int w, Input *in); Vector2 ui_vectordiff(Vector2 a, Vector2 b); float ui_vectordist(Vector2 a, Vector2 b); void ui_handle_view_colonies(int nowsel); @@ -106,6 +102,14 @@ void ui_draw_view_design(void); void ui_draw_view_sys(void); void ui_draw_view_settings(void); +/* uielem.c */ +extern void (*ui_elem_handlers[UI_ELEMS])(Vector2 mouse, + MouseButton button, Geom *geom, void *elem); +void ui_tabs(int x, int y, int w, int h, Tabs *tabs); +int ui_checkbox(int x, int y, Checkbox *checkbox); /* returns width */ +void ui_dropdown(int x, int y, int w, Dropdown *d); +void ui_input(int x, int y, int w, Input *in); + /* ui/main.c */ extern View_main view_main; void ui_handle_view_main(int nowsel); diff --git a/src/struct.h b/src/struct.h @@ -167,10 +167,10 @@ typedef struct { enum UiElements { UI_TAB, UI_CHECKBOX, - UI_BODY, UI_BUTTON, UI_INPUT, UI_DROPDOWN, + UI_ELEMS, }; typedef struct { diff --git a/src/ui.c b/src/ui.c @@ -204,96 +204,31 @@ ui_clickable_register(Geom geom, enum UiElements type, void *elem) { /* welp, we ran out */ } -void -ui_clickable_handle(Vector2 mouse, MouseButton button, Clickable *clickable) { - Tabs *tabs; - Checkbox *checkbox; - Dropdown *drop; - Input *input; - Geom *geom = &clickable->geom; - int ftabw, fw, fn, tabw, x; - int i; - - switch (clickable->type) { - case UI_TAB: - if (button != MOUSE_BUTTON_LEFT) - return; - tabs = clickable->elem; - for (fw = geom->w, fn = i = 0; i < tabs->n; i++) { - if (!tabs->tabs[i].w) - fn++; - else - fw -= tabs->tabs[i].w; - } - ftabw = fw / fn; - for (i = 0, x = geom->x; i < tabs->n; x += tabw, i++) { - if (i == tabs->n - 1) - tabw = geom->x + geom->w - x; - else if (!tabs->tabs[i].w) - tabw = ftabw; - else - tabw = tabs->tabs[i].w; - if (mouse.x >= x && mouse.x <= x + tabw) { - tabs->sel = i; - return; - } - } - break; - case UI_CHECKBOX: - if (button != MOUSE_BUTTON_LEFT) - return; - checkbox = clickable->elem; - checkbox->val = !checkbox->val; - break; - case UI_INPUT: - /* TODO: display hover over text */ - if (button != MOUSE_BUTTON_LEFT) - return; - input = clickable->elem; - if (focus.p != input) { - ui_update_focus(UI_INPUT, input); - } else { - i = (mouse.x - TPX - geom->x + charpx / 2) / charpx; - if (i < input->len) - input->cur = i; - else if (i > 0) - input->cur = input->len; - } - break; - case UI_DROPDOWN: - if (button != MOUSE_BUTTON_LEFT) - return; - drop = clickable->elem; - if (focus.p != drop) { - ui_update_focus(UI_DROPDOWN, drop); - } else { - i = (mouse.y - geom->y) / FONT_SIZE; - if (i != 0 && i <= drop->n) - drop->sel = i - 1; - ui_update_focus(0, NULL); - } - break; - } -} - int ui_clickable_update(void) { Vector2 mouse; MouseButton button; + Geom *geom; int i; int ret = 0; int keepfocus = 0; mouse = GetMousePosition(); /* I wish there was a: int GetMouseButton(void) */ - if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) button = MOUSE_BUTTON_LEFT; - else if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE)) button = MOUSE_BUTTON_MIDDLE; - else if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) button = MOUSE_BUTTON_RIGHT; - else button = -1; + if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) + button = MOUSE_BUTTON_LEFT; + else if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE)) + button = MOUSE_BUTTON_MIDDLE; + else if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) + button = MOUSE_BUTTON_RIGHT; + else + button = -1; for (i = 0; i < CLICKABLE_MAX; i++) { if (clickable[i].elem && ui_collides(clickable[i].geom, mouse)) { - ui_clickable_handle(mouse, button, &clickable[i]); + geom = &clickable[i].geom; + ui_elem_handlers[clickable[i].type](mouse, + button, geom, clickable[i].elem); if (clickable[i].elem == focus.p) keepfocus = 1; ret = 1; @@ -375,7 +310,7 @@ void ui_draw_views(void) { int sw = GetScreenWidth(); if (sw > VIEWS_MAX_WIDTH) sw = VIEWS_MAX_WIDTH; - ui_draw_tabs(0, 0, sw, VIEWS_HEIGHT, &view_tabs); + ui_tabs(0, 0, sw, VIEWS_HEIGHT, &view_tabs); } void @@ -450,67 +385,6 @@ ui_draw_line_v(Vector2 start, Vector2 end, float thick, Color col) { } void -ui_draw_tabs(int x, int y, int w, int h, Tabs *tabs) { - int fw, fn, ftabw; - int tabw; - int padx, pady; - int iw; - int cx, selx = -1; - int i; - - ui_draw_rectangle(x, y, w, h, col_bg); - - for (fw = w, fn = i = 0; i < tabs->n; i++) { - if (!tabs->tabs[i].w) - fn++; - else - fw -= tabs->tabs[i].w; - } - - ftabw = fw / fn; - pady = (h - FONT_SIZE) / 2; - - for (i = 0, cx = x; i < tabs->n; i++, cx += tabw) { - if (i == tabs->n - 1) - tabw = x + w - cx; - else if (!tabs->tabs[i].w) - tabw = ftabw; - else - tabw = tabs->tabs[i].w; - - if (tabs->tabs[i].icon) - iw = tabs->tabs[i].icon->width; - else - iw = 0; - - padx = (tabw - ui_textsize(tabs->tabs[i].name) - iw) / 2; - if (i == tabs->sel) - selx = cx; - else - ui_draw_rectangle(cx, y, tabw, h, col_unselbg); - ui_print(cx + padx + iw, y + pady, col_fg, "%s", tabs->tabs[i].name); - if (tabs->tabs[i].icon) - ui_draw_texture(*tabs->tabs[i].icon, cx + padx / 2, - y + (h - tabs->tabs[i].icon->width) / 2); - ui_draw_rectangle(cx + tabw - 1, y, 1, h, col_border); - } - - if (tabs->sel != tabs->n - 1) { - if (!tabs->tabs[i].w) - tabw = ftabw; - else - tabw = w / tabs->n; - } - - ui_draw_border(x, y, w, h, 1); - if (selx != -1) ui_draw_rectangle(selx - 1, y + h - 1, tabw + 1, 1, col_bg); /* undraw bottom border */ - if (tabs->sel == 0) ui_draw_rectangle(x, y + 1, 1, h - 1, col_bg); /* undraw left border */ - if (tabs->sel == tabs->n - 1) ui_draw_rectangle(x + w - 1, y + 1, 1, h - 1, col_bg); /* undraw right border */ - - ui_clickable_register(RECT(x, y, w, h), UI_TAB, tabs); -} - -void ui_draw_border(int x, int y, int w, int h, int px) { if (!pane_visible(y, y + h)) return; @@ -522,83 +396,6 @@ ui_draw_border_around(int x, int y, int w, int h, int px) { ui_draw_border(x - px, y - px, w + px * 2, h + px * 2, px); } -int -ui_draw_checkbox(int x, int y, Checkbox *box) { - int w, h; - int rw; - - w = h = FONT_SIZE; - ui_draw_border(x, y, w, h, 1); - ui_draw_rectangle(x + 1, y + 1, w - 2, h - 2, - box->enabled ? (box->val ? col_fg : col_bg) : col_border); - ui_print(x + w + (w / 2), y + (h / 6), col_fg, "%s", box->label); - rw = w + (w / 2) + ui_textsize(box->label); - if (box->enabled) - ui_clickable_register(RECT(x, y, rw, h), - UI_CHECKBOX, box); - return rw; -} - -void -ui_draw_dropdown(int x, int y, int w, Dropdown *d) { - int h = FONT_SIZE; - int fh, ph; - int focused; - int i; - - focused = focus.p == d; - fh = h + (focused ? h * d->n : 0); - ph = MIN(fh, (screen.h - x) * 0.75); - - ui_draw_border_around(x, y, w, ph, 1); - - d->rect = RECT(x, y, w, fh + TPY); - d->pane.geom = &d->rect; - pane_begin(&d->pane); - - if (d->sel != -1) - ui_print(x + TPX, y + TPY, col_fg, "%s", d->val[d->sel]); - else if (d->placeholder) - ui_print(x + TPX, y + TPY, col_info, "%s", d->placeholder); - - if (focused) { - ui_draw_rectangle(x, y + h, w, fh - h, col_unselbg); - for (i = 0; i < d->n; i++) { - ui_print(x + TPX, y + TPY + (i+1) * h, col_fg, "%s", d->val[i]); - } - } - - ui_clickable_register(d->rect, UI_DROPDOWN, d); - pane_end(); -} - -void -ui_draw_input(int x, int y, int w, Input *in) { - int h = FONT_SIZE; - int focused = focus.p == in; - int cw; - - /* Dirty hack: truncate str to length that fits */ - cw = w / charpx - 1; - if (in->len > cw) { - in->len = cw; - in->wstr[cw] = '\0'; - } - if (in->cur > in->len) - in->cur = in->len; - - ui_draw_border_around(x, y, w, h, 1); - ui_draw_rectangle(x, y, w, h, focused ? col_bg : col_unselbg); - if (in->len) - ui_print(x + TPX, y + TPY, col_fg, "%S", in->wstr); - else if (!focused && in->placeholder) - ui_print(x + TPX, y + TPY, col_info, "%s", in->placeholder); - if (focused) { - ui_draw_rectangle(x + TPX + charpx * in->cur, y + TPY, 1, FONT_SIZE, col_fg); - } - ui_clickable_register(RECT(x, y, w, h), UI_INPUT, in); -} - Vector2 ui_vectordiff(Vector2 a, Vector2 b) { float x = a.x - b.x; @@ -619,7 +416,7 @@ ui_vectordist(Vector2 a, Vector2 b) { void ui_draw_tabbed_window(int x, int y, int w, int h, Tabs *tabs) { ui_draw_rectangle(x, y, w, h, col_bg); - ui_draw_tabs(x, y, w, WINDOW_TAB_HEIGHT, tabs); + ui_tabs(x, y, w, WINDOW_TAB_HEIGHT, tabs); ui_draw_border(x, y, w, h, WINDOW_BORDER); } diff --git a/src/ui/bodies.c b/src/ui/bodies.c @@ -130,12 +130,12 @@ ui_draw_view_bodies(void) { x = v->disp.x + PAD/2; y = v->disp.y + PAD/2; - x += ui_draw_checkbox(x, y, &v->show.planet) + PAD * 2; - x += ui_draw_checkbox(x, y, &v->show.moon) + PAD * 2; - x += ui_draw_checkbox(x, y, &v->show.dwarf) + PAD * 2; - x += ui_draw_checkbox(x, y, &v->show.asteroid) + PAD * 2; - x += ui_draw_checkbox(x, y, &v->show.comet) + PAD * 2; - x += ui_draw_checkbox(x, y, &v->show.nomineral); + x += ui_checkbox(x, y, &v->show.planet) + PAD * 2; + x += ui_checkbox(x, y, &v->show.moon) + PAD * 2; + x += ui_checkbox(x, y, &v->show.dwarf) + PAD * 2; + x += ui_checkbox(x, y, &v->show.asteroid) + PAD * 2; + x += ui_checkbox(x, y, &v->show.comet) + PAD * 2; + x += ui_checkbox(x, y, &v->show.nomineral); ui_draw_border_around(v->disp.x, v->disp.y, x, v->disp.h, 1); ui_draw_border_around(EXPLODE_RECT(v->bodies), 1); diff --git a/src/ui/main.c b/src/ui/main.c @@ -51,8 +51,6 @@ View_main view_main = { .sys = NULL, }; -Input test = { 0 }; - Vector2 kmtopx(Vector2 km) { return (Vector2) { @@ -282,16 +280,14 @@ ui_draw_view_main(void) { view_main.infobox.pane.geom = &geom; pane_begin(&view_main.infobox.pane); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.dwarf); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.dwarfn); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.asteroid); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.asteroidn); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.comet); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.dwarf); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.asteroid); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.comet); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.comettail); + ui_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.dwarf); + ui_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.dwarfn); + ui_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.asteroid); + ui_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.asteroidn); + ui_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.comet); + ui_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.dwarf); + ui_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.asteroid); + ui_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.comet); + ui_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.comettail); pane_end(); - - ui_draw_input(500, 500, 150, &test); } diff --git a/src/uielem.c b/src/uielem.c @@ -0,0 +1,230 @@ +#include "main.h" + +static void ui_handle_tabs(Vector2 mouse, + MouseButton button, Geom *geom, void *elem); +static void ui_handle_checkbox(Vector2 mouse, + MouseButton button, Geom *geom, void *elem); +static void ui_handle_dropdown(Vector2 mouse, + MouseButton button, Geom *geom, void *elem); +static void ui_handle_input(Vector2 mouse, + MouseButton button, Geom *geom, void *elem); + +void (*ui_elem_handlers[UI_ELEMS])(Vector2 mouse, + MouseButton button, + Geom *geom, void *elem) = { + [UI_TAB] = ui_handle_tabs, + [UI_CHECKBOX] = ui_handle_checkbox, + [UI_DROPDOWN] = ui_handle_dropdown, + [UI_INPUT] = ui_handle_input, +}; + +void +ui_tabs(int x, int y, int w, int h, Tabs *tabs) { + int fw, fn, ftabw; + int tabw; + int padx, pady; + int iw; + int cx, selx = -1; + int i; + + ui_draw_rectangle(x, y, w, h, col_bg); + + for (fw = w, fn = i = 0; i < tabs->n; i++) { + if (!tabs->tabs[i].w) + fn++; + else + fw -= tabs->tabs[i].w; + } + + ftabw = fw / fn; + pady = (h - FONT_SIZE) / 2; + + for (i = 0, cx = x; i < tabs->n; i++, cx += tabw) { + if (i == tabs->n - 1) + tabw = x + w - cx; + else if (!tabs->tabs[i].w) + tabw = ftabw; + else + tabw = tabs->tabs[i].w; + + if (tabs->tabs[i].icon) + iw = tabs->tabs[i].icon->width; + else + iw = 0; + + padx = (tabw - ui_textsize(tabs->tabs[i].name) - iw) / 2; + if (i == tabs->sel) + selx = cx; + else + ui_draw_rectangle(cx, y, tabw, h, col_unselbg); + ui_print(cx + padx + iw, y + pady, col_fg, "%s", tabs->tabs[i].name); + if (tabs->tabs[i].icon) + ui_draw_texture(*tabs->tabs[i].icon, cx + padx / 2, + y + (h - tabs->tabs[i].icon->width) / 2); + ui_draw_rectangle(cx + tabw - 1, y, 1, h, col_border); + } + + if (tabs->sel != tabs->n - 1) { + if (!tabs->tabs[i].w) + tabw = ftabw; + else + tabw = w / tabs->n; + } + + ui_draw_border(x, y, w, h, 1); + if (selx != -1) ui_draw_rectangle(selx - 1, y + h - 1, tabw + 1, 1, col_bg); /* undraw bottom border */ + if (tabs->sel == 0) ui_draw_rectangle(x, y + 1, 1, h - 1, col_bg); /* undraw left border */ + if (tabs->sel == tabs->n - 1) ui_draw_rectangle(x + w - 1, y + 1, 1, h - 1, col_bg); /* undraw right border */ + + ui_clickable_register(RECT(x, y, w, h), UI_TAB, tabs); +} + +static void +ui_handle_tabs(Vector2 mouse, MouseButton button, Geom *geom, void *elem) { + int ftabw, fw, fn; + int tabw, x, i; + Tabs *tabs = elem; + + if (button != MOUSE_BUTTON_LEFT) + return; + for (fw = geom->w, fn = i = 0; i < tabs->n; i++) { + if (!tabs->tabs[i].w) + fn++; + else + fw -= tabs->tabs[i].w; + } + ftabw = fw / fn; + for (i = 0, x = geom->x; i < tabs->n; x += tabw, i++) { + if (i == tabs->n - 1) + tabw = geom->x + geom->w - x; + else if (!tabs->tabs[i].w) + tabw = ftabw; + else + tabw = tabs->tabs[i].w; + if (mouse.x >= x && mouse.x <= x + tabw) { + tabs->sel = i; + return; + } + } +} + +int +ui_checkbox(int x, int y, Checkbox *box) { + int w, h; + int rw; + + w = h = FONT_SIZE; + ui_draw_border(x, y, w, h, 1); + ui_draw_rectangle(x + 1, y + 1, w - 2, h - 2, + box->enabled ? (box->val ? col_fg : col_bg) : col_border); + ui_print(x + w + (w / 2), y + (h / 6), col_fg, "%s", box->label); + rw = w + (w / 2) + ui_textsize(box->label); + if (box->enabled) + ui_clickable_register(RECT(x, y, rw, h), + UI_CHECKBOX, box); + return rw; +} + +static void +ui_handle_checkbox(Vector2 mouse, MouseButton button, Geom *geom, void *elem) { + Checkbox *checkbox = elem; + + if (button != MOUSE_BUTTON_LEFT) + return; + checkbox->val = !checkbox->val; +} + +void +ui_dropdown(int x, int y, int w, Dropdown *d) { + int h = FONT_SIZE; + int fh, ph; + int focused; + int i; + + focused = focus.p == d; + fh = h + (focused ? h * d->n : 0); + ph = MIN(fh, (screen.h - x) * 0.75); + + ui_draw_border_around(x, y, w, ph, 1); + + d->rect = RECT(x, y, w, fh + TPY); + d->pane.geom = &d->rect; + pane_begin(&d->pane); + + if (d->sel != -1) + ui_print(x + TPX, y + TPY, col_fg, "%s", d->val[d->sel]); + else if (d->placeholder) + ui_print(x + TPX, y + TPY, col_info, "%s", d->placeholder); + + if (focused) { + ui_draw_rectangle(x, y + h, w, fh - h, col_unselbg); + for (i = 0; i < d->n; i++) { + ui_print(x + TPX, y + TPY + (i+1) * h, col_fg, "%s", d->val[i]); + } + } + + ui_clickable_register(d->rect, UI_DROPDOWN, d); + pane_end(); +} + +static void +ui_handle_dropdown(Vector2 mouse, MouseButton button, Geom *geom, void *elem) { + Dropdown *drop = elem; + int i; + + if (button != MOUSE_BUTTON_LEFT) + return; + if (focus.p != drop) { + ui_update_focus(UI_DROPDOWN, drop); + } else { + i = (mouse.y - geom->y) / FONT_SIZE; + if (i != 0 && i <= drop->n) + drop->sel = i - 1; + ui_update_focus(0, NULL); + } +} + +void +ui_input(int x, int y, int w, Input *in) { + int h = FONT_SIZE; + int focused = focus.p == in; + int cw; + + /* Dirty hack: truncate str to length that fits */ + cw = w / charpx - 1; + if (in->len > cw) { + in->len = cw; + in->wstr[cw] = '\0'; + } + if (in->cur > in->len) + in->cur = in->len; + + ui_draw_border_around(x, y, w, h, 1); + ui_draw_rectangle(x, y, w, h, focused ? col_bg : col_unselbg); + if (in->len) + ui_print(x + TPX, y + TPY, col_fg, "%S", in->wstr); + else if (!focused && in->placeholder) + ui_print(x + TPX, y + TPY, col_info, "%s", in->placeholder); + if (focused) { + ui_draw_rectangle(x + TPX + charpx * in->cur, y + TPY, 1, FONT_SIZE, col_fg); + } + ui_clickable_register(RECT(x, y, w, h), UI_INPUT, in); +} + +static void +ui_handle_input(Vector2 mouse, MouseButton button, Geom *geom, void *elem) { + Input *input = elem; + int i; + + if (button != MOUSE_BUTTON_LEFT) + return; + if (focus.p != input) { + ui_update_focus(UI_INPUT, input); + } else { + i = (mouse.x - TPX - geom->x + charpx / 2) / charpx; + if (i < input->len) + input->cur = i; + else if (i > 0) + input->cur = input->len; + } +}