cepheid

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

commit ab45f999ca0b0c34caf10f1434b1066470cec2a8
parent 59885cfa5a0d3bf69005f57d7c2dc0b9b40ed974
Author: hhvn <dev@hhvn.uk>
Date:   Tue, 15 Nov 2022 15:45:21 +0000

Improve bodies view

Diffstat:
Msrc/body.c | 19-------------------
Msrc/gui.c | 15+++++++--------
Msrc/main.c | 4++++
Msrc/main.h | 10++++++++--
Msrc/pane.c | 15++++++++++-----
Msrc/str.c | 38++++++++++++++++++++++++++++++++++++++
Msrc/struct.h | 6++++--
Msrc/system.c | 31++++++++++++++++++++++++++++---
Msrc/tree.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ui.c | 36++++++++++++++++++++++++++++++++++--
Msrc/views/bodies.c | 29+++++++++--------------------
Msrc/views/struct.h | 3+++
12 files changed, 195 insertions(+), 61 deletions(-)

diff --git a/src/body.c b/src/body.c @@ -53,22 +53,3 @@ body_init(char *name) { return ret; } - -int -body_cmp(Body *b1, Body *b2) { - float v1, v2; - Body *p; - - for (p = b1, v1 = 0; p->parent; p = p->parent) - v1 += (p->type == BODY_COMET ? p->maxdist : p->dist); - for (p = b2, v2 = 0; p->parent; p = p->parent) - v2 += (p->type == BODY_COMET ? p->maxdist : p->dist); - return (v1 == v2 ? 0 : (v1 > v2 ? 1 : -1)); -} - -SORT_FUNC(body_cmp, Body *); - -void -body_sort(Body **bodies, size_t n) { - qsort(bodies, n, sizeof(Body *), body_cmp_sort); -} diff --git a/src/gui.c b/src/gui.c @@ -344,7 +344,7 @@ gui_treeview(int x, int y, int w, int h, Treeview *tv) { ui_draw_border_around(x, y, w, h, 1); if (!tv->rect.w && !tv->rect.h) /* zero when unitialized */ - tv->pane = (Pane)PANESCROLL; + tv->pane = PANESCROLL; tv->rect = RECT(x, y, w, h); tv->pane.geom = &tv->rect; @@ -361,11 +361,8 @@ gui_treeview(int x, int y, int w, int h, Treeview *tv) { cy += FONT_SIZE; cx = x + PAD * (depth + 2); - if (tv->colmask & p->type) { - ui_draw_rectangle(cx - PAD, cy + 2, 5, 5, col_altbg); - ui_draw_rectangle(cx - PAD, cy + 4, 5, 1, col_fg); - ui_draw_rectangle(cx - PAD + 2, cy + 2, 1, 5, col_fg); - } + if (tv->colmask & p->type) + ui_draw_expander(cx - PAD - 2, cy - 1, 9, !p->collapsed); if (tv->print) tv->print(cx, cy, tv, p); @@ -394,9 +391,11 @@ gui_click_treeview(Vector mouse, MouseButton button, Geom *geom, void *elem) { for (i = 0, p = 0; tree_iter_f(tv->t, TREEMAX, &p, &depth, gui_treeview_filter, tv) != -1 && i <= pos; i++) { if (i == pos) { - if (mouse.x < geom->x + PAD * (depth + 2) && p->type & tv->colmask) + if (p->type & tv->colmask && (!(p->type & tv->selmask) || + mouse.x < geom->x + PAD * (depth + 2))) p->collapsed = !p->collapsed; - else if (p->type & tv->selmask) + if (p->type & tv->selmask && (!(p->type & tv->colmask) || + mouse.x > geom->x + PAD * (depth + 2))) tv->sel = p; } } diff --git a/src/main.c b/src/main.c @@ -18,6 +18,10 @@ warning(char *fmt, ...) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); + +#ifdef DEBUG + raise(SIGABRT); +#endif } static void diff --git a/src/main.h b/src/main.h @@ -25,6 +25,7 @@ void warning(char *fmt, ...); /* str.c */ void * falloc(size_t size); void ffree(void); +char * fstrdup(char *str); char * vsfprintf(char *fmt, va_list args); char * sfprintf(char *fmt, ...); /* return string allocated for current frame */ char * vsmprintf(char *fmt, va_list args); @@ -39,6 +40,7 @@ int strlistpos(char *str, char **list, size_t len); float strnum(char *str); size_t strlistcmp(char **l1, size_t s1, char **l2, size_t s2); size_t strsplit(char *str, char *sep, char **list, size_t len); +char * strtrunc(char *str, int w); void edittrunc(wchar_t *str, int *len, int *cur); void editrm(wchar_t *str, int *len, int *cur); void editins(wchar_t *str, int *len, int *cur, int size, wchar_t c); @@ -56,6 +58,8 @@ int tree_delete(Tree **t, int freedata); int tree_delete_r(Tree **t, int freedata); int tree_iter_f(Tree *t, int maxdepth, Tree **p, int *depth, Treefilter filter, void *fdata); int tree_iter(Tree *t, int maxdepth, Tree **p, int *depth); +void tree_sort_sideways(Tree *t, Treecompar compar, void *cdata); +void tree_sort(Tree *t, Treecompar compar, void *cdata); /* ui.c */ #define VIEWS_MAX_WIDTH (UI_VIEW_LAST*100) @@ -78,6 +82,7 @@ extern void (*view_handlers[UI_VIEW_LAST])(int); extern void (*view_drawers[UI_VIEW_LAST])(void); extern Screen screen; extern Focus focus; +extern Vector mouse; extern View_sys view_sys; extern int charpx; void ui_init(void); @@ -86,6 +91,7 @@ void ui_update_focus(enum GuiElements type, void *p); int ui_loop(void); void ui_deinit(void); void ui_print(int x, int y, Color col, char *format, ...); +void ui_printw(int x, int y, int w, Color col, char *format, ...); void ui_title(char *fmt, ...); int ui_textsize(char *text); float ui_get_scroll(void); @@ -98,6 +104,7 @@ int ui_keyboard_check(int key, int *fcount); void ui_keyboard_handle(void); void ui_draw_views(void); void ui_draw_rectangle(int x, int y, int w, int h, Color col); +void ui_draw_expander(int x, int y, int w, int expanded); void ui_draw_border(int x, int y, int w, int h, int px); void ui_draw_border_around(int x, int y, int w, int h, int px); void ui_draw_ring(int x, int y, float r, Color col); @@ -145,6 +152,7 @@ int pane_visible(float miny, float maxy); /* calls pane_max automatically */ float pane_max(float y); /* returns original y */ float pane_y(float y); Vector pane_v(Vector v); +void pane_scroll(Pane *f, int incr); /* system.c */ System *sys_init(char *name); @@ -158,8 +166,6 @@ System *sys_default(void); int bodytype_enumify(char *name); char * bodytype_strify(Body *body); Body * body_init(char *name); -int body_cmp(Body *b1, Body *b2); -void body_sort(Body **bodies, size_t n); /* save.c */ #define SAVE_READ_STEPS 2 diff --git a/src/pane.c b/src/pane.c @@ -36,11 +36,7 @@ pane_end(void) { } if (m.x >= f->geom->x && m.x <= f->geom->x + f->geom->w && m.y >= f->geom->y && m.y <= f->geom->y + f->geom->h) - f->off -= ui_get_scroll() * SCROLL_MULT; - if (f->off > f->max - f->geom->h) - f->off = f->max - f->geom->h; - if (f->off < 0) - f->off = 0; + pane_scroll(f, ui_get_scroll() * SCROLL_MULT * -1); EndScissorMode(); } @@ -75,3 +71,12 @@ pane_v(Vector v) { return (Vector) {v.x, v.y}; return (Vector) {v.x, v.y - pane->off}; } + +void +pane_scroll(Pane *f, int incr) { + f->off += incr; + if (f->off > f->max - f->geom->h) + f->off = f->max - f->geom->h; + if (f->off < 0) + f->off = 0; +} diff --git a/src/str.c b/src/str.c @@ -8,6 +8,7 @@ #include <math.h> #include "main.h" +#define TEXTBUF 2048 #define FMEMMAX 1024 static void *fmem[FMEMMAX] = {NULL}; @@ -33,6 +34,15 @@ ffree(void) { } char * +fstrdup(char *str) { + char *ret; + + ret = falloc(strlen(str) + 1); + strcpy(ret, str); + return ret; +} + +char * vsfprintf(char *fmt, va_list ap) { if (fmemi + 1 == FMEMMAX) { errno = ENOMEM; @@ -207,6 +217,34 @@ strsplit(char *str, char *sep, char **list, size_t len) { return i; } +#define TRUNCSTR "…" +#define TRUNCLEN strlen(TRUNCSTR) + +char * +strtrunc(char *str, int w) { + char buf[TEXTBUF]; + int len, cw, i, s; + mbstate_t mb = {0}; + + for (s = i = 0, len = strlen(str); + str && *str; + i += cw, str += cw, s++, len -= cw) { + cw = mbrlen(str, len, &mb); + + if ((s == w - 1 && str[cw] != '\0') || TEXTBUF - i <= 8) { + memcpy(&buf[i], TRUNCSTR, TRUNCLEN); + i += TRUNCLEN; + goto end; + } + + memcpy(&buf[i], str, cw); + } + +end: + buf[i] = '\0'; + return fstrdup(buf); +} + void edittrunc(wchar_t *str, int *len, int *cur) { *len = *cur = 0; diff --git a/src/struct.h b/src/struct.h @@ -24,6 +24,8 @@ typedef void (*Treesetter)(char *dir, char *group, char *name, int depth, Tree * typedef int (*Treefilter)(Tree *t, void *data); typedef void (*Treeprinter)(int x, int y, Treeview *tv, Tree *t); +typedef int (*Treecompar)(Tree *a, Tree *b, void *data); + /* coords.c */ typedef Vector2 Vector; typedef struct { @@ -135,8 +137,8 @@ typedef struct { } Geom; /* pane.c */ -#define PANESCROLL {NULL, 1, 0, 0} -#define PANENOSCROLL {NULL, 0, 0, 0} +#define PANESCROLL (Pane){NULL, 1, 0, 0} +#define PANENOSCROLL (Pane){NULL, 0, 0, 0} typedef struct { Geom *geom; int scroll; diff --git a/src/system.c b/src/system.c @@ -2,6 +2,7 @@ #include <string.h> #include <stdlib.h> #include <raylib.h> +#include <assert.h> #include "main.h" static Polar @@ -45,6 +46,31 @@ sys_init(char *name) { return ret; } +static int +sys_tree_compar(Tree *a, Tree *b, void *data) { + System *sa, *sb; + Body *p; + float v1, v2; + + assert(a->type == b->type); + + switch (a->type) { + case SYSTREE_SYS: + sa = a->data; + sb = b->data; + return (abs(sa->lypos.x) + abs(sa->lypos.y)) - + (abs(sb->lypos.x) + abs(sb->lypos.y)); + case SYSTREE_BODY: + for (p = a->data, v1 = 0; p->parent; p = p->parent) + v1 += (p->type == BODY_COMET ? p->maxdist : p->dist); + for (p = b->data, v2 = 0; p->parent; p = p->parent) + v2 += (p->type == BODY_COMET ? p->maxdist : p->dist); + return (v1 == v2 ? 0 : (v1 > v2 ? 1 : -1)); + } + + return 0; +} + void sys_tree_load(void) { Tree *t, *bt; @@ -103,13 +129,12 @@ sys_tree_load(void) { (s->furthest_body->type == BODY_COMET ? s->furthest_body->maxdist : s->furthest_body->dist))) s->furthest_body = bp[i]; } - - /* TODO: actually sort the tree */ - /* body_sort(bp, n); */ } free(bp); free(bn); + + tree_sort(&save->systems, sys_tree_compar, NULL); } char * diff --git a/src/tree.c b/src/tree.c @@ -180,3 +180,53 @@ int tree_iter(Tree *t, int maxdepth, Tree **p, int *depth) { return tree_iter_f(t, maxdepth, p, depth, NULL, NULL); } + +void +tree_sort_sideways(Tree *t, Treecompar compar, void *cdata) { + Tree *cp, *np, *p; + + for (; t->p; t = t->p); + + cp = t->n; + while (cp) { + np = cp->n; + + p = cp->p; + + if (cp->p) cp->p->n = cp->n; + if (cp->n) cp->n->p = cp->p; + + for (; p; p = p->p) { + if (compar(p, cp, cdata) < 0) { + if (p->n) p->n->p = cp; + cp->n = p->n; + cp->p = p; + p->n = cp; + break; + } + if (!p->p) { + t->u->d = cp; + cp->p = NULL; + cp->n = p; + p->p = cp; + break; + } + } + + cp = np; + } +} + +static int +tree_sort_filter(Tree *t, void *data) { + return !t->n && t->u; +} + +void +tree_sort(Tree *t, Treecompar compar, void *cdata) { + Tree *p; + int depth; + + for (p = NULL; tree_iter_f(t, TREEMAX, &p, &depth, tree_sort_filter, NULL) != -1; ) + tree_sort_sideways(p, compar, cdata); +} diff --git a/src/ui.c b/src/ui.c @@ -28,6 +28,7 @@ void (*view_drawers[UI_VIEW_LAST])(void) = { Screen screen = { 0 }; Focus focus = { 0 }; +Vector mouse = { 0 }; Tabs view_tabs = { /* Tactical is the terminology used in Aurora, so I decided to use it @@ -94,6 +95,7 @@ ui_loop(void) { ui_update_screen(); ui_keyboard_handle(); gui_click_handle(); + mouse = GetMousePosition(); return 1; } @@ -105,14 +107,13 @@ ui_deinit(void) { void ui_print(int x, int y, Color col, char *fmt, ...) { va_list ap; - Vector pos; + Vector pos = {x, pane_y(y)}; char *text; if (!pane_visible(y, y + FONT_SIZE)) return; pos.x = x; - pos.y = pane_y(y); va_start(ap, fmt); text = vsmprintf(fmt, ap); va_end(ap); @@ -121,6 +122,24 @@ ui_print(int x, int y, Color col, char *fmt, ...) { } void +ui_printw(int x, int y, int w, Color col, char *fmt, ...) { + va_list ap; + Vector pos = {x, pane_y(y)}; + char *t1, *t2; + + if (!pane_visible(y, y + FONT_SIZE)) + return; + + pos.x = x; + va_start(ap, fmt); + t1 = vsmprintf(fmt, ap); + va_end(ap); + t2 = strtrunc(t1, w / charpx); + DrawTextEx(font, t2, pos, (float)FONT_SIZE, FONT_SIZE/10, col); + free(t1); +} + +void ui_title(char *fmt, ...) { char *title; va_list ap; @@ -233,6 +252,19 @@ ui_draw_rectangle(int x, int y, int w, int h, Color col) { DrawRectangle(x, pane_y(y), w, h, col); } +void +ui_draw_expander(int x, int y, int w, int expanded) { + int p = (w / 2) - 1; + if (!pane_visible(y, y + w)) + return; + + if (w-1 & 1) warning("drawing plus with even width\n"); + + DrawRectangle(x, y, w, w, col_altbg); + DrawRectangle(x + 1, y + p + 1, w - 2, 1, col_fg); + if (!expanded) + DrawRectangle(x + p + 1, y + 1, 1, w - 2, col_fg); +} #define SEGMAX 1500 diff --git a/src/views/bodies.c b/src/views/bodies.c @@ -62,6 +62,7 @@ tree_printer(int x, int y, Treeview *tv, Tree *t) { Color c = sel ? col_info : col_fg; Body *b; int cx = tv->rect.x; + int cw = tv->rect.w; if (!t) { ui_print(x, y, col_fg, "Body"); @@ -71,9 +72,9 @@ tree_printer(int x, int y, Treeview *tv, Tree *t) { ui_print(x, y, c, t->name); } else { b = t->data; - ui_print(x, y, c, "%s", b->name); - ui_print(cx + 3*W, y, c, "%s", b->parent ? b->parent->name : ""); - ui_print(cx + 5*W, y, c, "%s", bodytype_strify(b)); + ui_printw(x, y, cx + 3*W - x, c, "%s", b->name); + ui_printw(cx + 3*W, y, 2*W, c, "%s", b->parent ? b->parent->name : ""); + ui_printw(cx + 5*W, y, cw, c, "%s", bodytype_strify(b)); } } @@ -84,6 +85,8 @@ ui_handle_view_bodies(int nowsel) { Body *body; int pos, i; + v->prevframe.sel = v->sel; + if (!v->sys) v->sys = sys_default(); @@ -98,23 +101,6 @@ ui_handle_view_bodies(int nowsel) { } } -#if 0 -static int -draw_body(int x, int y, Body *body) { - Color col; - - if (body == v->sel) - col = col_info; - else - col = col_fg; - - ui_print(x, y, col, "%s", body->name); - ui_print(x + 3*W, y, col, "%s", body->parent ? body->parent->name : "-"); - ui_print(x + 5*W, y, col, "%s", bodytype_strify(body)); - return y + FONT_SIZE; -} -#endif - void ui_draw_view_bodies(void) { int x, y; @@ -144,6 +130,9 @@ ui_draw_view_bodies(void) { x += gui_checkbox(x, y, &v->show.nomineral); ui_draw_border_around(v->disp.x, v->disp.y, x, v->disp.h, 1); + if (v->sel && !v->prevframe.sel && mouse.y > v->bodies.y + v->bodies.h) + pane_scroll(&v->tree.pane, INFOBOX_H); + gui_treeview(EXPLODE_RECT(v->bodies), &v->tree); if (v->sel) { diff --git a/src/views/struct.h b/src/views/struct.h @@ -49,6 +49,9 @@ typedef struct { Geom loc; Geom mins; Geom hab; + struct { + Body *sel; + } prevframe; } View_bodies; typedef struct {