cepheid

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

commit 717a21586094d954f42683e39f66be2abd820371
parent 4e8feafcc3f5bebf66457cdd064ca5f5fea8c1fa
Author: hhvn <dev@hhvn.uk>
Date:   Sun, 13 Nov 2022 18:17:59 +0000

Treeview

Diffstat:
Msrc/gui.c | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/main.h | 10++++++++++
Msrc/struct.h | 38+++++++++++++++++++++++++++++---------
Msrc/system.c | 13++-----------
Msrc/tree.c | 37++++++++++++++++++++++++++++++++++++-
Msrc/views/bodies.c | 130+++++++++++++++++++++++++++++++++++--------------------------------------------
Msrc/views/struct.h | 6+-----
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;