commit 58377c23450c9213e10d599df096dce0dca1263e
parent ce2c86eaba85fe239a2a77581b716e3b5eb0fb21
Author: hhvn <dev@hhvn.uk>
Date: Tue, 4 Oct 2022 17:52:24 +0100
Tree structure
Diffstat:
9 files changed, 245 insertions(+), 52 deletions(-)
diff --git a/src/main.c b/src/main.c
@@ -7,6 +7,16 @@
Save *save = NULL;
+void
+warning(char *fmt, ...) {
+ va_list ap;
+
+ fprintf(stderr, "warning: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
int
main(void) {
int view_prev;
diff --git a/src/main.h b/src/main.h
@@ -18,6 +18,7 @@
/* main.c */
extern Save *save;
+void warning(char *fmt, ...);
/* str.c */
void * falloc(size_t size);
@@ -38,6 +39,11 @@ 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);
+/* tree.c */
+Tree * tree_add_child(Tree *t, char *name, int type, void *data, Tree **ptr);
+int tree_delete(Tree **t, int freedata);
+int tree_delete_r(Tree **t, int freedata);
+
/* ui.c */
#define VIEWS_MAX_WIDTH (UI_VIEW_LAST*100)
#define VIEWS_HEIGHT 25
diff --git a/src/save.c b/src/save.c
@@ -28,7 +28,6 @@ save_read(Loader *lscr, char *name) {
char dir[PATH_MAX];
char *str;
-
if (save)
save_free();
@@ -37,6 +36,8 @@ save_read(Loader *lscr, char *name) {
snprintf(dir, sizeof(dir), "%s/%s", SAVEDIR, name);
+ memset(&save->systems, 0, sizeof(save->systems));
+
loading_update(lscr, "Initializing DB");
dbdeclare(dir);
save->db.dir = nstrdup(dir);
diff --git a/src/struct.h b/src/struct.h
@@ -1,7 +1,25 @@
#include <stddef.h>
#include <sys/types.h>
+/* tree.c */
+typedef struct Tree Tree;
+struct Tree {
+ Tree *p; /* previous */
+ char *name;
+ int collapsed; /* matters for Treeview */
+ int type;
+ void *data;
+ Tree *u; /* up */
+ Tree *d; /* down */
+ Tree *n; /* next */
+};
+
/* system.c */
+enum {
+ SYSTREE_SYS,
+ SYSTREE_BODY,
+};
+
typedef struct {
float r;
float theta;
@@ -27,6 +45,7 @@ enum BodyType {
typedef struct Body Body;
struct Body {
+ Tree *t;
Body *parent;
Polar polar;
Vector2 vector;
@@ -55,8 +74,7 @@ struct Body {
typedef struct {
char *name;
- Body **bodies;
- size_t bodies_len;
+ Tree *t;
Body *furthest_body;
struct {
int stars;
@@ -77,8 +95,7 @@ typedef struct {
char *systems;
char *fleets;
} db;
- System *systems;
- size_t systems_len;
+ Tree systems;
System *homesys;
} Save;
@@ -137,7 +154,7 @@ typedef struct {
} Checkbox;
typedef struct {
- char *name;
+ char *label;
void (*func)(int);
int arg;
} Button;
diff --git a/src/system.c b/src/system.c
@@ -80,8 +80,7 @@ sys_init(char *name) {
System *ret = malloc(sizeof(System));
if (!ret) return NULL;
ret->name = nstrdup(name);
- ret->bodies = NULL;
- ret->bodies_len = 0;
+ ret->t = NULL;
ret->furthest_body = NULL;
memset(&ret->num, 0, sizeof(ret->num));
return ret;
@@ -102,6 +101,7 @@ filter_bodyinsystem(void *data, char *path) {
System *
sys_load(System *s, char *name) {
char *dir, *tmp;
+ Body **bodies;
char **bname;
char **bparent;
size_t blen, i;
@@ -113,24 +113,24 @@ sys_load(System *s, char *name) {
s->lypos.y = strnum(dbget(save->db.systems, name, "y"));
dir = smprintf("%s/", s->name);
- s->bodies_len = blen = dblistgroups_f(&bname, save->db.systems, &filter_bodyinsystem, dir);
+ blen = dblistgroups_f(&bname, save->db.systems, &filter_bodyinsystem, dir);
if (!bname) return NULL;
bparent = malloc(sizeof(char *) * blen);
- s->bodies = malloc(sizeof(Body *) * blen);
+ bodies = malloc(sizeof(Body *) * blen);
- if (!bparent || !s->bodies)
+ if (!bparent || !bodies)
return NULL;
/* first pass: init bodies and parents */
for (i = 0; i < blen; i++) {
- s->bodies[i] = malloc(sizeof(Body));
- s->bodies[i]->name = nstrdup(bname[i] + strlen(dir));
+ bodies[i] = malloc(sizeof(Body));
+ bodies[i]->name = nstrdup(bname[i] + strlen(dir));
bparent[i] = nstrdup(dbget(save->db.systems, bname[i], "parent"));
tmp = dbget(save->db.systems, bname[i], "type");
- s->bodies[i]->type = bodytype_enumify(tmp);
+ bodies[i]->type = bodytype_enumify(tmp);
- switch (s->bodies[i]->type) {
+ switch (bodies[i]->type) {
case BODY_STAR: s->num.stars++; break;
case BODY_PLANET: s->num.planets++; break;
case BODY_DWARF: s->num.dwarfs++; break;
@@ -139,48 +139,48 @@ sys_load(System *s, char *name) {
case BODY_MOON: s->num.moons++; break;
}
- s->bodies[i]->radius = strnum(dbget(save->db.systems, bname[i], "radius"));
- s->bodies[i]->mass = strnum(dbget(save->db.systems, bname[i], "mass"));
- s->bodies[i]->orbdays = strnum(dbget(save->db.systems, bname[i], "orbdays"));
- if (s->bodies[i]->type == BODY_COMET) {
+ bodies[i]->radius = strnum(dbget(save->db.systems, bname[i], "radius"));
+ bodies[i]->mass = strnum(dbget(save->db.systems, bname[i], "mass"));
+ bodies[i]->orbdays = strnum(dbget(save->db.systems, bname[i], "orbdays"));
+ if (bodies[i]->type == BODY_COMET) {
/* mindist is on opposite side of parent */
- s->bodies[i]->mindist = 0 - strnum(dbget(save->db.systems, bname[i], "mindist"));
- s->bodies[i]->maxdist = strnum(dbget(save->db.systems, bname[i], "maxdist"));
- s->bodies[i]->curdist = strnum(dbget(save->db.systems, bname[i], "curdist"));
- s->bodies[i]->theta = strnum(dbget(save->db.systems, bname[i], "theta"));
- s->bodies[i]->inward = strnum(dbget(save->db.systems, bname[i], "inward"));
+ bodies[i]->mindist = 0 - strnum(dbget(save->db.systems, bname[i], "mindist"));
+ bodies[i]->maxdist = strnum(dbget(save->db.systems, bname[i], "maxdist"));
+ bodies[i]->curdist = strnum(dbget(save->db.systems, bname[i], "curdist"));
+ bodies[i]->theta = strnum(dbget(save->db.systems, bname[i], "theta"));
+ bodies[i]->inward = strnum(dbget(save->db.systems, bname[i], "inward"));
} else {
- s->bodies[i]->dist = strnum(dbget(save->db.systems, bname[i], "dist"));
- s->bodies[i]->curtheta = strnum(dbget(save->db.systems, bname[i], "curtheta"));
+ bodies[i]->dist = strnum(dbget(save->db.systems, bname[i], "dist"));
+ bodies[i]->curtheta = strnum(dbget(save->db.systems, bname[i], "curtheta"));
}
/* so sys_get_polar() knows if it's usable */
- s->bodies[i]->polar = (Polar) { INFINITY, INFINITY };
+ bodies[i]->polar = (Polar) { INFINITY, INFINITY };
}
/* second pass: assign parents (needs bparent[] from first pass) */
for (i = 0; i < blen; i++) {
tmp = smprintf("%s%s", dir, bparent[i]);
if ((pos = strlistpos(tmp, bname, blen)) != -1)
- s->bodies[i]->parent = s->bodies[pos];
+ bodies[i]->parent = bodies[pos];
else
- s->bodies[i]->parent = NULL;
+ bodies[i]->parent = NULL;
free(tmp);
}
/* third pass: get coords (needs parent ptr from second pass) */
for (i = 0; i < blen; i++) {
- sys_get_polar(s->bodies[i]); /* Builds the cache for us: this is more
+ sys_get_polar(bodies[i]); /* Builds the cache for us: this is more
efficient as it can cache the parent too */
- s->bodies[i]->vector = sys_vectorize(s->bodies[i]->polar);
+ bodies[i]->vector = sys_vectorize(bodies[i]->polar);
/* This could deal with moons, but that's probably not useful.
* What about multiple stars in a system? That may need to be
* addressed in future */
- if (s->bodies[i]->parent && s->bodies[i]->parent->type == BODY_STAR && (!s->furthest_body ||
- (s->bodies[i]->type == BODY_COMET ? s->bodies[i]->maxdist : s->bodies[i]->dist) >
+ if (bodies[i]->parent && bodies[i]->parent->type == BODY_STAR && (!s->furthest_body ||
+ (bodies[i]->type == BODY_COMET ? bodies[i]->maxdist : bodies[i]->dist) >
(s->furthest_body->type == BODY_COMET ? s->furthest_body->maxdist : s->furthest_body->dist)))
- s->furthest_body = s->bodies[i];
+ s->furthest_body = bodies[i];
}
for (i = 0; i < blen; i++) {
@@ -190,7 +190,14 @@ sys_load(System *s, char *name) {
dblistfree(bname, blen);
free(dir);
- body_sort(s->bodies, s->bodies_len);
+ body_sort(bodies, blen);
+
+ tree_add_child(&save->systems, s->name, SYSTREE_SYS, s, &s->t);
+ for (i = 0; i < blen; i++)
+ tree_add_child(s->t, bodies[i]->name, SYSTREE_BODY, bodies[i], &bodies[i]->t);
+
+ /* The bodies are attached to the systree now, so don't need to be freed */
+ free(bodies);
return s;
}
diff --git a/src/tree.c b/src/tree.c
@@ -0,0 +1,146 @@
+#include <stdlib.h>
+#include "main.h"
+
+/* This interface is purposely limited to adding children, as opposed to
+ * appending data on the same level. This is done on purpose, so that ->u
+ * can always be set. It also means there is always a root Tree structure,
+ * which does not need to be created with malloc and friends. */
+Tree *
+tree_add_child(Tree *t, char *name, int type, void *data, Tree **ptr) {
+ Tree *p;
+ Tree *e;
+
+ if (!t) return NULL;
+
+ e = malloc(sizeof(Tree));
+ if (!e) return NULL;
+
+ e->p = e->n = e->d = NULL;
+ e->name = name;
+ e->type = type;
+ e->data = data;
+ e->u = t;
+
+ if (!t->d) {
+ t->d = e;
+ } else {
+ for (p = t->d; p->n; p = p->n);
+ p->n = e;
+ e->p = p;
+ }
+
+ if (ptr)
+ *ptr = e;
+
+ return e;
+}
+
+/* Deletes a node in the tree and replaces it with its children. */
+int
+tree_delete(Tree **t, int freedata) {
+ Tree *e;
+ Tree *p;
+ Tree *fc, *lc;
+
+ if (!*t)
+ return -1;
+
+ e = *t;
+
+ if (!e->u)
+ warning("trying to delete root of tree\n");
+
+ if (e->d) {
+ fc = e->d;
+ for (p = fc; p->n; p = p->n);
+ lc = p;
+ } else {
+ fc = lc = NULL;
+ }
+
+ if (e->p)
+ e->p->n = fc ? fc : e->n;
+ else
+ e->u->d = e->n;
+
+ if (e->n)
+ e->n->p = lc ? lc : e->p;
+
+ if (freedata)
+ free(e->data);
+ free(e);
+
+ return 0;
+}
+
+static Tree *
+tree_delete_r_sub(Tree *e, int freedata) {
+ Tree *c;
+ Tree *n;
+
+ c = e->d;
+ n = e->n;
+
+ if (freedata)
+ free(e->data);
+ free(e);
+
+ while (c)
+ c = tree_delete_r_sub(c, freedata);
+
+ return n;
+}
+
+/* Deletes a node and its children. */
+int
+tree_delete_r(Tree **t, int freedata) {
+ Tree *e;
+
+ if (!*t)
+ return -1;
+
+ e = *t;
+
+ if (!e->u)
+ warning("trying to delete root of tree\n");
+
+ if (e->p)
+ e->p->n = e->n;
+ else
+ e->u->d = e->n;
+
+ if (e->n)
+ e->n->p = e->p;
+
+ tree_delete_r_sub(e, freedata);
+}
+
+int
+tree_iter(Tree *t, int maxdepth, Tree **p, int *depth) {
+ if (!*p) {
+ *p = t->d;
+ if (depth) *depth = 0;
+ return *p ? 0 : -1;
+ }
+
+ if ((maxdepth < 0 || *depth <= maxdepth) && (*p)->d) {
+ *p = (*p)->d;
+ if (depth) (*depth)++;
+ return 0;
+ }
+
+ if ((*p)->n) {
+ *p = (*p)->n;
+ return 0;
+ }
+
+ for (; *p && *p != t; *p = (*p)->u) {
+ if ((*p)->n) {
+ *p = (*p)->n;
+ return 0;
+ }
+ if (depth) (*depth)--;
+ }
+
+ return -1;
+}
diff --git a/src/ui.c b/src/ui.c
@@ -503,7 +503,7 @@ ui_draw_view_sys(void) {
ui_print(x, y + 40, col_fg, "Comets: %d", view_sys.sel->num.comets);
ui_print(x, y + 50, col_fg, "Moons: %d", view_sys.sel->num.moons);
ui_draw_line(x, y + 62, x + 85, y + 62, 1, col_fg);
- ui_print(x, y + 65, col_fg, "Total: %d", view_sys.sel->bodies_len);
+ /* ui_print(x, y + 65, col_fg, "Total: %d", view_sys.sel->bodies_len); TODO: tree_count() */
}
}
diff --git a/src/ui/bodies.c b/src/ui/bodies.c
@@ -50,7 +50,9 @@ display_body(Body *body) {
void
ui_handle_view_bodies(int nowsel) {
Vector2 m = GetMousePosition();
- int pos, i, j;
+ Tree *t;
+ Body *body;
+ int pos, i;
if (!v->sys)
v->sys = sys_default();
@@ -60,10 +62,12 @@ ui_handle_view_bodies(int nowsel) {
ui_collides(v->bodies, m)) {
pos = (m.y + v->pane.bodies.off - v->bodies.y - PAD)
/ FONT_SIZE;
- for (i = j = 0; i < v->sys->bodies_len && j < pos; i++)
- if (display_body(v->sys->bodies[i]))
- if (++j == pos)
- v->sel = v->sys->bodies[i];
+ for (t = v->sys->t->d, i = 0; t && i < pos; t = t->n) {
+ body = t->data;
+ if (display_body(body))
+ if (++i == pos)
+ v->sel = body;
+ }
}
}
@@ -95,7 +99,7 @@ draw_body(int x, int y, Body *body) {
void
ui_draw_view_bodies(void) {
int x, y;
- int i;
+ Tree *t;
Body *body;
v->stars = RECT(PAD, VIEWS_HEIGHT + PAD * 2 + FONT_SIZE,
@@ -123,9 +127,11 @@ ui_draw_view_bodies(void) {
y = v->stars.y + PAD/2;
ui_print(x, y, col_fg, "Name");
y += FONT_SIZE * 1.5;
- for (i = 0; i < v->sys->bodies_len; i++)
- if (v->sys->bodies[i]->type == BODY_STAR)
- y = draw_star(x, y, v->sys->bodies[i]);
+ for (t = v->sys->t->d; t; t = t->n) {
+ body = t->data;
+ if (body->type == BODY_STAR)
+ y = draw_star(x, y, body);
+ }
pane_end();
x = v->disp.x + PAD/2;
@@ -147,8 +153,8 @@ ui_draw_view_bodies(void) {
ui_print(x + 3*W, y, col_fg, "Parent");
ui_print(x + 5*W, y, col_fg, "Type");
y += FONT_SIZE * 1.5;
- for (i = 0; i < v->sys->bodies_len; i++) {
- body = v->sys->bodies[i];
+ for (t = v->sys->t->d; t; t = t->n) {
+ body = t->data;
if (display_body(body))
y = draw_body(x, y, body);
}
diff --git a/src/ui/main.c b/src/ui/main.c
@@ -221,9 +221,9 @@ ui_draw_view_main(void) {
Vector2 mousekm = pxtokm(mouse);
Vector2 ruler;
Geom geom;
+ Tree *t;
Body *body;
float dist;
- size_t i;
float x, y;
/* debug info */
@@ -235,13 +235,13 @@ ui_draw_view_main(void) {
ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + PAD * 4, col_fg, "FPS: %d (target: %d)", GetFPS(), TARGET_FPS);
/* draw system bodies */
- for (i = 0; i < view_main.sys->bodies_len; i++) {
- body = view_main.sys->bodies[i];
+ for (t = view_main.sys->t->d; t; t = t->n) {
+ body = t->data;
body->pxloc = kmtopx(body->vector);
draw_orbit(body);
}
- for (i = 0; i < view_main.sys->bodies_len; i++) {
- body = view_main.sys->bodies[i];
+ for (t = view_main.sys->t->d; t; t = t->n) {
+ body = t->data;
draw_body(body);
}