commit 717a21586094d954f42683e39f66be2abd820371
parent 4e8feafcc3f5bebf66457cdd064ca5f5fea8c1fa
Author: hhvn <dev@hhvn.uk>
Date: Sun, 13 Nov 2022 18:17:59 +0000
Treeview
Diffstat:
7 files changed, 228 insertions(+), 102 deletions(-)
diff --git a/src/gui.c b/src/gui.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include "main.h"
static Clickable clickable[CLICKABLE_MAX];
@@ -7,9 +8,11 @@ static void gui_click_tabs(Vector2 mouse,
MouseButton button, Geom *geom, void *elem);
static void gui_click_checkbox(Vector2 mouse,
MouseButton button, Geom *geom, void *elem);
+static void gui_click_input(Vector2 mouse,
+ MouseButton button, Geom *geom, void *elem);
static void gui_click_dropdown(Vector2 mouse,
MouseButton button, Geom *geom, void *elem);
-static void gui_click_input(Vector2 mouse,
+static void gui_click_treeview(Vector2 mouse,
MouseButton button, Geom *geom, void *elem);
static void gui_key_input(void *elem, int *fcount);
@@ -19,15 +22,19 @@ static void (*click_handlers[GUI_ELEMS])(Vector2 mouse,
Geom *geom, void *elem) = {
[GUI_TAB] = gui_click_tabs,
[GUI_CHECKBOX] = gui_click_checkbox,
- [GUI_DROPDOWN] = gui_click_dropdown,
+ [GUI_BUTTON] = NULL,
[GUI_INPUT] = gui_click_input,
+ [GUI_DROPDOWN] = gui_click_dropdown,
+ [GUI_TREEVIEW] = gui_click_treeview,
};
void (*gui_key_handlers[GUI_ELEMS])(void *elem, int *fcount) = {
[GUI_TAB] = NULL,
[GUI_CHECKBOX] = NULL,
- [GUI_DROPDOWN] = NULL,
+ [GUI_BUTTON] = NULL,
[GUI_INPUT] = gui_key_input,
+ [GUI_DROPDOWN] = NULL,
+ [GUI_TREEVIEW] = NULL,
};
static void
@@ -311,3 +318,86 @@ gui_key_input(void *elem, int *fcount) {
editins(in->wstr, &in->len, &in->cur, INPUT_MAX, c);
}
}
+
+/* This function is an intermediate filter that checks whether an item is
+ * collapsed before running the filter defined in the Treeview struct */
+static int
+gui_treeview_filter(Tree *t, void *data) {
+ Treeview *tv = data;
+
+ if (t->u && t->u->collapsed)
+ return 0;
+
+ if (tv->filter)
+ return tv->filter(t, tv->fdata);
+ else
+ return 1;
+}
+
+void
+gui_treeview(int x, int y, int w, int h, Treeview *tv) {
+ int depth;
+ Tree *p;
+ int cx, cy;
+ int i;
+
+ ui_draw_border_around(x, y, w, h, 1);
+
+ if (!tv->rect.w && !tv->rect.h) /* zero when unitialized */
+ tv->pane = (Pane)PANESCROLL;
+ tv->rect = RECT(x, y, w, h);
+ tv->pane.geom = &tv->rect;
+
+ pane_begin(&tv->pane);
+
+ if (tv->print) {
+ tv->print(x + PAD, y + FONT_SIZE, tv, NULL);
+ cy = y + FONT_SIZE + PAD / 2;
+ } else {
+ cy = y;
+ }
+
+ for (p = NULL; tree_iter_f(tv->t, TREEMAX, &p, &depth, gui_treeview_filter, tv) != -1; ) {
+ 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->print)
+ tv->print(cx, cy, tv, p);
+ else
+ ui_print(cx, cy, tv->sel == p ? col_info : col_fg, "%s", p->name);
+
+ for (i = 0, cx = x + PAD; i < depth; i++, cx += PAD)
+ ui_draw_rectangle(cx + 2, cy - 2, 1, FONT_SIZE + 1, col_altbg);
+ }
+
+ pane_end();
+ gui_click_register(tv->rect, GUI_TREEVIEW, tv);
+}
+
+static void
+gui_click_treeview(Vector2 mouse, MouseButton button, Geom *geom, void *elem) {
+ Treeview *tv = elem;
+ int depth;
+ Tree *p;
+ int i, pos;
+
+ if (button == -1)
+ return;
+
+ pos = (mouse.y - geom->y - FONT_SIZE - (tv->print ? FONT_SIZE + PAD / 2 : 0) + tv->pane.off) / FONT_SIZE;
+
+ 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)
+ p->collapsed = !p->collapsed;
+ else if (p->type & tv->selmask)
+ tv->sel = p;
+ }
+ }
+}
diff --git a/src/main.h b/src/main.h
@@ -43,10 +43,19 @@ 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);
+/* coords.c */
+Vector vectorize(Polar p);
+Vector vectorize_at(Vector at, Polar p);
+Polar polarize(Vector v);
+Polar polarize_at(Vector at, Vector vector);
+Polar polar_add(Polar abs, Polar rel);
+Polar polar_add_noconv(Polar abs, Polar rel);
+
/* 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);
+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);
/* ui.c */
@@ -118,6 +127,7 @@ void gui_tabs(int x, int y, int w, int h, Tabs *tabs);
int gui_checkbox(int x, int y, Checkbox *checkbox); /* returns width */
void gui_dropdown(int x, int y, int w, Dropdown *d);
void gui_input(int x, int y, int w, Input *in);
+void gui_treeview(int x, int y, int w, int h, Treeview *tv);
/* ui/main.c */
extern View_main view_main;
diff --git a/src/struct.h b/src/struct.h
@@ -1,35 +1,40 @@
#include <stddef.h>
#include <sys/types.h>
-/* tree.c */
+/* tree.c
+ * See tree.c for further documentation */
#define TREEMAX 64 /* max depth: not actually enforced anywhere, anything
deeper than this will get ignored in some places */
typedef struct Tree Tree;
struct Tree {
Tree *p; /* previous */
char *name;
- int collapsed; /* matters for Treeview */
- int type;
+ int collapsed; /* used by Treeview */
+ int type; /* NOT a bitmask */
void *data;
Tree *u; /* up */
Tree *d; /* down */
Tree *n; /* next */
};
+typedef struct Treeview Treeview;
+
typedef char * (*Treegetter)(char *dir, char *group, char *name, int depth, Tree *t);
typedef void (*Treesetter)(char *dir, char *group, char *name, int depth, Tree *t);
-
-/* system.c */
-enum {
- SYSTREE_SYS,
- SYSTREE_BODY,
-};
+typedef int (*Treefilter)(Tree *t, void *data);
+typedef void (*Treeprinter)(int x, int y, Treeview *tv, Tree *t);
typedef struct {
float r;
float theta;
} Polar;
+/* system.c */
+enum {
+ SYSTREE_SYS = 1,
+ SYSTREE_BODY = 2,
+};
+
/* body->type + body->parent->type == complex type
*
* Ex. for orbiting a star:
@@ -190,12 +195,27 @@ typedef struct {
Pane pane;
} Dropdown;
+/* typedef'd earlier */
+struct Treeview {
+ Tree *t;
+ Tree *sel;
+ int selmask; /* bitmask of selectable types */
+ int colmask; /* bitmask of collapsible types */
+ void *fdata; /* data to pass to filter() */
+ Treefilter filter; /* hide nodes when 0 is returned */
+ Treeprinter print; /* prints data related to the node */
+ /* internal */
+ Geom rect;
+ Pane pane;
+};
+
enum GuiElements {
GUI_TAB,
GUI_CHECKBOX,
GUI_BUTTON,
GUI_INPUT,
GUI_DROPDOWN,
+ GUI_TREEVIEW,
GUI_ELEMS,
};
diff --git a/src/system.c b/src/system.c
@@ -86,16 +86,6 @@ sys_init(char *name) {
return ret;
}
-static int
-filter_bodyinsystem(void *data, char *path) {
- char *system = data;
-
- if (!strstr(path, "/index") && strncmp(path, system, strlen(system)) != 0)
- return 1;
- else
- return 0;
-}
-
void
sys_tree_load(void) {
Tree *t, *bt;
@@ -155,7 +145,8 @@ sys_tree_load(void) {
s->furthest_body = bp[i];
}
- body_sort(bp, n);
+ /* TODO: actually sort the tree */
+ /* body_sort(bp, n); */
}
free(bp);
diff --git a/src/tree.c b/src/tree.c
@@ -1,6 +1,17 @@
#include <stdlib.h>
#include "main.h"
+/* In cepheid, the Tree is a data structure that hierarchically represents data
+ * of arbitrary types. It is in essence a quadrupally linked list.
+ *
+ * Each tree should enumerate the types (not necessarily a typedef) of data it
+ * stores. These enums must only have 1 bit set to 1.
+ *
+ * The Treeview gui element displays a tree graphically.
+ * selmask and colmask are set such that only nodes with a ->type that matches
+ * the mask will be: selectable or collapsible, respectively.
+ */
+
/* 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,
@@ -114,30 +125,49 @@ tree_delete_r(Tree **t, int freedata) {
e->n->p = e->p;
tree_delete_r_sub(e, freedata);
+ return 0;
+}
+
+static int
+tree_iter_f_yes(Tree *t, void *data) {
+ return 1;
}
+#define TREPORT(direction) printf("%d %s | Direction: %s\n", *depth, (*p)->name, direction)
+
int
-tree_iter(Tree *t, int maxdepth, Tree **p, int *depth) {
+tree_iter_f(Tree *t, int maxdepth, Tree **p, int *depth,
+ Treefilter filter, void *fdata) {
+ if (!filter)
+ filter = tree_iter_f_yes;
+
if (!*p) {
*p = t->d;
if (depth) *depth = 0;
return *p ? 0 : -1;
}
+skip:
if ((maxdepth < 0 || *depth <= maxdepth) && (*p)->d) {
*p = (*p)->d;
if (depth) (*depth)++;
+ if (!filter(*p, fdata))
+ goto skip;
return 0;
}
if ((*p)->n) {
*p = (*p)->n;
+ if (!filter(*p, fdata))
+ goto skip;
return 0;
}
for (; *p && *p != t; *p = (*p)->u) {
if ((*p)->n) {
*p = (*p)->n;
+ if (!filter(*p, fdata))
+ goto skip;
return 0;
}
if (depth) (*depth)--;
@@ -145,3 +175,8 @@ tree_iter(Tree *t, int maxdepth, Tree **p, int *depth) {
return -1;
}
+
+int
+tree_iter(Tree *t, int maxdepth, Tree **p, int *depth) {
+ return tree_iter_f(t, maxdepth, p, depth, NULL, NULL);
+}
diff --git a/src/views/bodies.c b/src/views/bodies.c
@@ -6,6 +6,9 @@
#define BUTTONS 50
#define W MIN(screen.w / 20, 50)
+static int tree_filter(Tree *t, void *data);
+static void tree_printer(int x, int y, Treeview *tv, Tree *t);
+
static View_bodies *v = &view_bodies;
View_bodies view_bodies = {
.sys = NULL,
@@ -19,34 +22,61 @@ View_bodies view_bodies = {
.comet = {1, 1, "Show comets"},
.nomineral = {1, 1, "Show bodies without mins"},
},
- .pane = {
- .stars = PANESCROLL,
- .bodies = PANESCROLL,
- },
+ .tree = {
+ .t = NULL,
+ .sel = NULL,
+ .selmask = SYSTREE_BODY,
+ .colmask = SYSTREE_SYS,
+ .filter = tree_filter,
+ .print = tree_printer,
+ }
};
static int
-display_body(Body *body) {
- if (body->type == BODY_STAR || !body->parent)
+tree_filter(Tree *t, void *data) {
+ Body *b;
+
+ if (t->type == SYSTREE_SYS)
+ return 1;
+
+ b = t->data;
+ if (b->type == BODY_STAR || !b->parent)
return 0;
- if (body->type == BODY_MOON && !v->show.moon.val)
+ if (b->type == BODY_MOON && !v->show.moon.val)
return 0;
- if ((body->type == BODY_PLANET || body->parent->type == BODY_PLANET) &&
- !v->show.planet.val)
+ if ((b->type == BODY_PLANET || b->parent->type == BODY_PLANET) && !v->show.planet.val)
return 0;
- if ((body->type == BODY_DWARF || body->parent->type == BODY_DWARF) &&
- !v->show.dwarf.val)
+ if ((b->type == BODY_DWARF || b->parent->type == BODY_DWARF) && !v->show.dwarf.val)
return 0;
- if ((body->type == BODY_ASTEROID || body->parent->type == BODY_ASTEROID) &&
- !v->show.asteroid.val)
+ if ((b->type == BODY_ASTEROID || b->parent->type == BODY_ASTEROID) && !v->show.asteroid.val)
return 0;
- if ((body->type == BODY_COMET || body->parent->type == BODY_COMET) &&
- !v->show.comet.val)
+ if ((b->type == BODY_COMET || b->parent->type == BODY_COMET) && !v->show.comet.val)
return 0;
/* TODO: exclude bodies with no mins */
return 1;
}
+static void
+tree_printer(int x, int y, Treeview *tv, Tree *t) {
+ int sel = tv->sel == t;
+ Color c = sel ? col_info : col_fg;
+ Body *b;
+ int cx = tv->rect.x;
+
+ if (!t) {
+ ui_print(x, y, col_fg, "Body");
+ ui_print(cx + 3*W, y, col_fg, "Parent");
+ ui_print(cx + 5*W, y, col_fg, "Type");
+ } else if (t->type != SYSTREE_BODY) {
+ 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));
+ }
+}
+
void
ui_handle_view_bodies(int nowsel) {
Vector2 m = GetMousePosition();
@@ -58,29 +88,17 @@ ui_handle_view_bodies(int nowsel) {
v->sys = sys_default();
if (!nowsel) {
- if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) &&
- ui_collides(v->bodies, m)) {
- pos = (m.y + v->pane.bodies.off - v->bodies.y - PAD)
- / FONT_SIZE;
- 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;
- }
- }
- }
-
- if (nowsel)
+ if (v->tree.sel)
+ v->sel = v->tree.sel->data;
+ else
+ v->sel = NULL;
+ } else {
ui_title("Bodies in %s", v->sys->name);
+ v->tree.t = &save->systems;
+ }
}
-static int
-draw_star(int x, int y, Body *star) {
- ui_print(x, y, col_fg, "%s", star->name);
- return y + FONT_SIZE;
-}
-
+#if 0
static int
draw_body(int x, int y, Body *body) {
Color col;
@@ -95,17 +113,15 @@ draw_body(int x, int y, Body *body) {
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;
- Tree *t;
Body *body;
- v->stars = RECT(PAD, VIEWS_HEIGHT + PAD * 2 + FONT_SIZE,
- screen.w - PAD * 2, FONT_SIZE * 6);
- v->disp = RECT(v->stars.x, v->stars.y + v->stars.h + PAD,
- v->stars.w, FONT_SIZE + PAD);
+ v->disp = RECT(PAD, VIEWS_HEIGHT + FONT_SIZE,
+ screen.w - PAD * 2, FONT_SIZE + PAD);
v->bodies = RECT(v->disp.x, v->disp.y + v->disp.h + PAD/2,
v->disp.w, screen.h - v->bodies.y - INFOBOX_H - BUTTONS);
v->loc = RECT(v->bodies.x, v->bodies.y + v->bodies.h + PAD,
@@ -118,22 +134,6 @@ ui_draw_view_bodies(void) {
if (!v->sel)
v->bodies.h += INFOBOX_H;
- ui_print(PAD, VIEWS_HEIGHT + PAD, col_fg, "[System selection dropdown]");
-
- ui_draw_border_around(EXPLODE_RECT(v->stars), 1);
- v->pane.stars.geom = &v->stars;
- pane_begin(&v->pane.stars);
- x = v->stars.x + PAD/2;
- y = v->stars.y + PAD/2;
- ui_print(x, y, col_fg, "Name");
- y += FONT_SIZE * 1.5;
- 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;
y = v->disp.y + PAD/2;
x += gui_checkbox(x, y, &v->show.planet) + PAD * 2;
@@ -144,21 +144,7 @@ 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);
- ui_draw_border_around(EXPLODE_RECT(v->bodies), 1);
- v->pane.bodies.geom = &v->bodies;
- pane_begin(&v->pane.bodies);
- x = v->bodies.x + PAD/2;
- y = v->bodies.y + PAD/2;
- ui_print(x, y, col_fg, "Name");
- ui_print(x + 3*W, y, col_fg, "Parent");
- ui_print(x + 5*W, y, col_fg, "Type");
- y += FONT_SIZE * 1.5;
- for (t = v->sys->t->d; t; t = t->n) {
- body = t->data;
- if (display_body(body))
- y = draw_body(x, y, body);
- }
- pane_end();
+ gui_treeview(EXPLODE_RECT(v->bodies), &v->tree);
if (v->sel) {
ui_draw_border_around(EXPLODE_RECT(v->loc), 1);
@@ -177,6 +163,4 @@ ui_draw_view_bodies(void) {
ui_draw_border_around(EXPLODE_RECT(v->mins), 1);
ui_draw_border_around(EXPLODE_RECT(v->hab), 1);
}
-
- DrawFPS(50, 50);
}
diff --git a/src/views/struct.h b/src/views/struct.h
@@ -43,13 +43,9 @@ typedef struct {
Checkbox comet;
Checkbox nomineral;
} show;
- struct {
- Pane stars;
- Pane bodies;
- } pane;
- Geom stars;
Geom disp;
Geom bodies;
+ Treeview tree;
Geom loc;
Geom mins;
Geom hab;