commit eaf31cc5096be1db264a3066cf213fd18a1d6fb3
parent 071239df07ee045485a73c2b6e9c204893c2c2af
Author: hhvn <dev@hhvn.uk>
Date: Mon, 5 Sep 2022 13:57:52 +0100
Dropdowns
Diffstat:
4 files changed, 84 insertions(+), 13 deletions(-)
diff --git a/src/main.h b/src/main.h
@@ -53,6 +53,7 @@ extern Tabs view_tabs;
extern void (*view_handlers[UI_VIEW_LAST])(int);
extern void (*view_drawers[UI_VIEW_LAST])(void);
extern Screen screen;
+extern Focus focus;
extern View_sys view_sys;
void ui_init(void);
void ui_update_screen(void);
diff --git a/src/pane.c b/src/pane.c
@@ -58,8 +58,8 @@ pane_visible(float miny, float maxy) {
float
pane_max(float y) {
- if (pane && y > pane->max)
- pane->max = y;
+ if (pane && y - pane->geom->y > pane->max)
+ pane->max = y - pane->geom->y;
return y;
}
diff --git a/src/struct.h b/src/struct.h
@@ -89,6 +89,17 @@ typedef struct {
int w, h;
} Rect;
+/* pane.c */
+#define PANESCROLL {NULL, 1, 0, 0}
+#define PANENOSCROLL {NULL, 0, 0, 0}
+typedef struct {
+ Rect *geom;
+ int scroll;
+ int max;
+ int off;
+} Pane;
+
+/* ui.c again */
typedef struct {
Vector2 centre;
int r;
@@ -141,14 +152,18 @@ typedef struct {
typedef struct {
char str[INPUT_MAX];
void (*onenter)(char *, int);
- int arg;
+ int arg; /* differentiates buttons with common onenter() */
} Input;
#define DROPDOWN_MAX 64
typedef struct {
int n;
int sel; /* -1 for none */
+ char *placeholder;
char *val[DROPDOWN_MAX];
+ /* internal */
+ Rect rect;
+ Pane pane;
} Dropdown;
enum UiElements {
@@ -157,8 +172,14 @@ enum UiElements {
UI_BODY,
UI_BUTTON,
UI_INPUT,
+ UI_DROPDOWN,
};
+typedef struct {
+ enum UiElements type;
+ void *p;
+} Focus;
+
enum UiViews {
UI_VIEW_MAIN,
UI_VIEW_COLONIES,
@@ -177,6 +198,7 @@ typedef struct {
void *elem;
} Clickable;
+/* loading.c */
#define LOAD_STR_MAX 512
typedef struct {
char path[64];
@@ -184,13 +206,3 @@ typedef struct {
int *step;
char *data;
} Loader;
-
-/* pane.c */
-#define PANESCROLL {NULL, 1, 0, 0}
-#define PANENOSCROLL {NULL, 0, 0, 0}
-typedef struct {
- Rect *geom;
- int scroll;
- int max;
- int off;
-} Pane;
diff --git a/src/ui.c b/src/ui.c
@@ -29,6 +29,7 @@ void (*view_drawers[UI_VIEW_LAST])(void) = {
};
Screen screen = { 0 };
+Focus focus = { 0 };
Tabs view_tabs = {
/* Tactical is the terminology used in Aurora, so I decided to use it
@@ -214,6 +215,7 @@ void
ui_clickable_handle(Vector2 mouse, MouseButton button, Clickable *clickable) {
Tabs *tabs;
Checkbox *checkbox;
+ Dropdown *drop;
Rect *rect;
/* Circle *circle; */
int ftabw, fw, fn, tabw, x;
@@ -253,6 +255,19 @@ ui_clickable_handle(Vector2 mouse, MouseButton button, Clickable *clickable) {
checkbox = clickable->elem;
checkbox->val = !checkbox->val;
break;
+ case UI_DROPDOWN:
+ if (button != MOUSE_BUTTON_LEFT)
+ return;
+ drop = clickable->elem;
+ if (focus.p != drop) {
+ focus.p = drop;
+ } else {
+ i = (mouse.y - rect->y) / FONT_SIZE;
+ if (i != 0 && i <= drop->n)
+ drop->sel = i - 1;
+ focus.p = NULL;
+ }
+ break;
}
}
@@ -262,6 +277,7 @@ ui_clickable_update(void) {
MouseButton button;
int i;
int ret = 0;
+ int keepfocus = 0;
mouse = GetMousePosition();
/* I wish there was a: int GetMouseButton(void) */
@@ -273,10 +289,16 @@ ui_clickable_update(void) {
for (i = 0; i < CLICKABLE_MAX; i++) {
if (clickable[i].elem && ui_collides(clickable[i].geom, mouse)) {
ui_clickable_handle(mouse, button, &clickable[i]);
+ if (clickable[i].elem == focus.p)
+ keepfocus = 1;
ret = 1;
}
}
+ /* clicking outside the focused elememnt unfocuses */
+ if (button != -1 && !keepfocus)
+ focus.p = NULL;
+
/* Handle bodies seperately for efficiency:
* - body->pxloc can be used instead of a geometry passed to
* ui_clickable_register()
@@ -464,6 +486,42 @@ ui_draw_checkbox(int x, int y, 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;
+ int px = 2, py = 1;
+ Geom geom = {UI_RECT};
+
+ 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 + py};
+ d->pane.geom = &d->rect;
+ pane_begin(&d->pane);
+
+ if (d->sel != -1)
+ ui_print(x + px, y + py, col_fg, "%s", d->val[d->sel]);
+ else if (d->placeholder)
+ ui_print(x + px, y + py, 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 + px, y + py + (i+1) * h, col_fg, "%s", d->val[i]);
+ }
+ }
+
+ geom.rect = (Rect){x, y, w, ph};
+ ui_clickable_register(geom, UI_DROPDOWN, d);
+ pane_end();
+}
+
Vector2
ui_vectordiff(Vector2 a, Vector2 b) {
float x = a.x - b.x;