commit ab45f999ca0b0c34caf10f1434b1066470cec2a8
parent 59885cfa5a0d3bf69005f57d7c2dc0b9b40ed974
Author: hhvn <dev@hhvn.uk>
Date: Tue, 15 Nov 2022 15:45:21 +0000
Improve bodies view
Diffstat:
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 {