commit 8d0163a8ba5dfc998b7a73ae8b8c938ef3d683fa
parent 587eaf48e684bb58e21a9593a7361c97a8454cdb
Author: hhvn <dev@hhvn.uk>
Date: Sun, 20 Nov 2022 21:51:28 +0000
Start menu
Diffstat:
17 files changed, 493 insertions(+), 26 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,4 +1,5 @@
*.o
+data/*.o
data/*.h
data/*.c
data/sol
diff --git a/data/icons/burger.png b/data/icons/burger.png
Binary files differ.
diff --git a/data/icons/burger.xcf b/data/icons/burger.xcf
Binary files differ.
diff --git a/data/splash.png b/data/splash.png
Binary files differ.
diff --git a/data/splash.png.source b/data/splash.png.source
@@ -0,0 +1 @@
+Source: NASA, public domain
diff --git a/src/data.c b/src/data.c
@@ -9,6 +9,8 @@
#include "../data/icons/design.h"
#include "../data/icons/sys.h"
#include "../data/icons/settings.h"
+#include "../data/icons/burger.h"
+#include "../data/splash.h"
#define IMAGE(name) \
static Image raw_image_##name; \
@@ -22,6 +24,8 @@ IMAGE(fleet);
IMAGE(design);
IMAGE(sys);
IMAGE(settings);
+IMAGE(burger);
+IMAGE(splash);
#define IMAGE_LOAD(name) \
raw_image_##name = LoadImageFromMemory(".png", \
@@ -42,6 +46,8 @@ data_load(void) {
IMAGE_LOAD(design);
IMAGE_LOAD(sys);
IMAGE_LOAD(settings);
+ IMAGE_LOAD(burger);
+ IMAGE_LOAD(splash);
}
#define IMAGE_UNLOAD(name) \
@@ -57,4 +63,6 @@ data_unload(void) {
IMAGE_UNLOAD(design);
IMAGE_UNLOAD(sys);
IMAGE_UNLOAD(settings);
+ IMAGE_UNLOAD(burger);
+ IMAGE_UNLOAD(splash);
}
diff --git a/src/main.c b/src/main.c
@@ -10,6 +10,8 @@
Save *save = NULL;
int sigint = 0;
int sigterm = 0;
+int quit = 0;
+int view_before_smenu = UI_VIEW_MAIN;
void
error(int code, char *fmt, ...) {
@@ -64,10 +66,6 @@ main(void) {
data_load();
- if (!save_exists(DEFSAVE))
- save_create(DEFSAVE);
- save_read(DEFSAVE);
-
/* The window is hidden so that only the loading bar is shown. Hiding
* and unhiding the window also has the added effect of making it
* behave like a normal window in window managers, rather than having
@@ -76,14 +74,17 @@ main(void) {
ui_update_screen();
while (ui_loop()) {
- if (IsKeyDown(KEY_LEFT_ALT) || IsKeyDown(KEY_RIGHT_ALT)) {
+ if (IsKeyPressed(KEY_ESCAPE))
+ view_tabs.sel = UI_VIEW_SMENU;
+
+ if (save && (IsKeyDown(KEY_LEFT_ALT) || IsKeyDown(KEY_RIGHT_ALT))) {
/* AAAAAAAAAAHHHHHHHHHHHH. WHY NOT JUST USE KEY_1, KEY_2..! */
- if (IsKeyPressed(KEY_ONE)) view_tabs.sel = 0;
- else if (IsKeyPressed(KEY_TWO)) view_tabs.sel = 1;
- else if (IsKeyPressed(KEY_THREE)) view_tabs.sel = 2;
- else if (IsKeyPressed(KEY_FOUR)) view_tabs.sel = 3;
- else if (IsKeyPressed(KEY_FIVE)) view_tabs.sel = 4;
- else if (IsKeyPressed(KEY_SIX)) view_tabs.sel = 5;
+ if (IsKeyPressed(KEY_ONE)) view_tabs.sel = 1;
+ else if (IsKeyPressed(KEY_TWO)) view_tabs.sel = 2;
+ else if (IsKeyPressed(KEY_THREE)) view_tabs.sel = 3;
+ else if (IsKeyPressed(KEY_FOUR)) view_tabs.sel = 4;
+ else if (IsKeyPressed(KEY_FIVE)) view_tabs.sel = 5;
+ else if (IsKeyPressed(KEY_SIX)) view_tabs.sel = 6;
}
view_handlers[view_tabs.sel](view_prev != view_tabs.sel);
@@ -91,7 +92,10 @@ main(void) {
BeginDrawing();
ClearBackground(col_bg);
view_drawers[view_tabs.sel]();
- ui_draw_views();
+ if (view_tabs.sel != UI_VIEW_SMENU) {
+ ui_draw_views();
+ view_before_smenu = view_tabs.sel;
+ }
EndDrawing();
view_prev = view_tabs.sel;
@@ -99,7 +103,6 @@ main(void) {
data_unload();
ui_deinit();
- save_write();
dbcleanup();
return 0;
}
diff --git a/src/main.h b/src/main.h
@@ -20,6 +20,8 @@
extern Save *save;
extern int sigint;
extern int sigterm;
+extern int quit;
+extern int view_before_smenu;
void error(int code, char *fmt, ...);
void warning(char *fmt, ...);
@@ -34,6 +36,7 @@ char * smprintf(char *fmt, ...); /* return allocated string */
char * nstrdup(char *str); /* NULL-safe */
char * strkm(float km);
char * strly(float km);
+char * strdate(time_t time);
int streq(char *s1, char *s2); /* NULL-safe, no `== 0` required */
int strprefix(char *str, char *prefix);
char * strsuffix(char *str, char *suffix);
@@ -111,6 +114,7 @@ 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);
void ui_draw_texture(Texture2D texture, int x, int y);
+void ui_draw_texture_part(Texture2D texture, int x, int y, int fx, int fy, int w, int h);
void ui_draw_circle(int x, int y, float r, Color col);
void ui_draw_line(int sx, int sy, int ex, int ey, float thick, Color col);
void ui_draw_line_v(Vector start, Vector end, float thick, Color col);
@@ -154,6 +158,12 @@ extern View_sys view_sys;
void ui_handle_view_sys(int nowsel);
void ui_draw_view_sys(void);
+/* views/smenu.c */
+extern View_smenu view_smenu;
+void ui_handle_view_smenu(int nowsel);
+void ui_draw_view_smenu(void);
+void checkbeforequit(void);
+
/* pane.c */
void pane_begin(Pane *f);
void pane_end(void);
@@ -198,7 +208,8 @@ extern Texture image_fleet;
extern Texture image_design;
extern Texture image_sys;
extern Texture image_settings;
-#define DATA_LOAD_STEPS (1 + 7)
+extern Texture image_burger;
+extern Texture image_splash;
void data_load(void);
void data_unload(void);
diff --git a/src/maths.h b/src/maths.h
@@ -6,6 +6,9 @@
#define GIGA (MEGA * 1000)
#define MEGA (KILO * 1000)
#define KILO 1000
+#define MILLI (1.0 / 1000.0)
+#define MICRO (MILLI / 1000.0)
+#define NANO (MICRO / 1000.0)
#define C_MS 299792458 /* c, in m/s */
diff --git a/src/save.c b/src/save.c
@@ -19,7 +19,7 @@ save_free(void) {
void
save_read(char *name) {
char dir[PATH_MAX];
- /* char *str; */
+ char *str;
if (save)
save_free();
@@ -36,10 +36,13 @@ save_read(char *name) {
save->db.races = smprintf("%s/Races", dir);
save->db.systems = smprintf("%s/Systems", dir);
save->db.fleets = smprintf("%s/Fleets", dir);
- /* if ((str = dbget(save->db.dir, "index", "homesystem"))) */
- /* save->homesys = sys_get(str); */
- save->homesys = NULL;
sys_tree_load();
+
+ if ((str = dbget(save->db.dir, "index", "homesystem")))
+ save->homesys = sys_get(str);
+
+ view_main.sys = NULL;
+ view_main.sys = sys_default();
return;
};
diff --git a/src/str.c b/src/str.c
@@ -6,6 +6,7 @@
#include <wchar.h>
#include <errno.h>
#include <math.h>
+#include <time.h>
#include "main.h"
#define TEXTBUF 2048
@@ -132,6 +133,18 @@ strly(float km) {
return sfprintf("%.2f ls", ls);
}
+char *
+strdate(time_t time) {
+ struct tm *tm;
+ char *ret = falloc(256);
+
+ tm = localtime(&time);
+
+ strftime(ret, 256, "%c", tm);
+
+ return ret;
+}
+
int
streq(char *s1, char *s2) {
if (s1 == s2)
diff --git a/src/struct.h b/src/struct.h
@@ -24,6 +24,7 @@ typedef void (*Treesetter)(char *dir, char *group, char *name, int depth, Tree *
typedef void (*Treefree)(Tree *t);
typedef int (*Treefilter)(Tree *t, void *data);
typedef void (*Treeprinter)(int x, int y, Treeview *tv, Tree *t);
+typedef void (*Treedclick)(Treeview *tv);
typedef int (*Treecompar)(Tree *a, Tree *b, void *data);
@@ -219,6 +220,7 @@ struct Treeview {
void *fdata; /* data to pass to filter() */
Treefilter filter; /* hide nodes when 0 is returned */
Treeprinter print; /* prints data related to the node */
+ Treedclick dclick; /* runs on double click of selected node */
/* internal */
Geom rect;
Pane pane;
@@ -240,6 +242,7 @@ typedef struct {
} Focus;
enum UiViews {
+ UI_VIEW_SMENU,
UI_VIEW_MAIN,
UI_VIEW_COLONIES,
UI_VIEW_BODIES,
diff --git a/src/system.c b/src/system.c
@@ -266,5 +266,5 @@ sys_default(void) {
else if (save->systems.d && save->systems.d->data)
return save->systems.d->data;
else
- exit(1);
+ error(1, "could not locate any systems\n");
}
diff --git a/src/ui.c b/src/ui.c
@@ -7,6 +7,7 @@
#include "main.h"
void (*view_handlers[UI_VIEW_LAST])(int) = {
+ [UI_VIEW_SMENU] = ui_handle_view_smenu,
[UI_VIEW_MAIN] = ui_handle_view_main,
[UI_VIEW_COLONIES] = ui_handle_view_colonies,
[UI_VIEW_BODIES] = ui_handle_view_bodies,
@@ -17,6 +18,7 @@ void (*view_handlers[UI_VIEW_LAST])(int) = {
};
void (*view_drawers[UI_VIEW_LAST])(void) = {
+ [UI_VIEW_SMENU] = ui_draw_view_smenu,
[UI_VIEW_MAIN] = ui_draw_view_main,
[UI_VIEW_COLONIES] = ui_draw_view_colonies,
[UI_VIEW_BODIES] = ui_draw_view_bodies,
@@ -33,13 +35,16 @@ Mouse mouse = { 0 };
Tabs view_tabs = {
/* Tactical is the terminology used in Aurora, so I decided to use it
* in the ui; in the code it's just called 'main' for my fingers' sake */
- UI_VIEW_LAST, 0, {{&image_tactical, "Tactical", 0},
+ UI_VIEW_LAST, 0, {
+ {&image_burger, NULL, VIEWS_HEIGHT},
+ {&image_tactical, "Tactical", 0},
{&image_colonies, "Colonies", 0},
{&image_bodies, "Bodies", 0},
{&image_fleet, "Fleets", 0},
{&image_design, "Design", 0},
{&image_sys, "Systems", 0},
- {&image_settings, "Settings", 0}}
+ {&image_settings, "Settings", 0},
+ }
};
int charpx; /* thank god for monospaced fonts */
@@ -48,8 +53,8 @@ void
ui_init(void) {
SetWindowState(FLAG_WINDOW_RESIZABLE|FLAG_WINDOW_HIDDEN);
SetTargetFPS(TARGET_FPS);
- SetExitKey(KEY_NULL);
InitWindow(500, 500, "");
+ SetExitKey(KEY_NULL);
}
void
@@ -70,6 +75,9 @@ ui_focus(enum GuiElements type, void *p) {
int
ui_loop(void) {
if (WindowShouldClose() || sigint || sigterm)
+ checkbeforequit();
+
+ if (((sigint || sigterm) && view_smenu.save.check) || quit)
return 0;
ffree();
@@ -142,6 +150,7 @@ ui_title(char *fmt, ...) {
int
ui_textsize(char *text) {
+ if (!text) return 0;
return charpx * strlen(text);
}
@@ -293,6 +302,13 @@ ui_draw_texture(Texture2D texture, int x, int y) {
}
void
+ui_draw_texture_part(Texture2D texture, int x, int y, int fx, int fy, int w, int h) {
+ if (!pane_visible(y, y + h))
+ return;
+ DrawTextureRec(texture, (Rectangle){fx, fy, w, h}, (Vector){x, y}, NO_TINT);
+}
+
+void
ui_draw_circle(int x, int y, float r, Color col) {
if (!pane_visible(y - r, y + r))
return;
diff --git a/src/views/main.c b/src/views/main.c
@@ -107,10 +107,6 @@ ui_handle_view_main(int nowsel) {
}
}
- if (!view_main.sys) {
- view_main.sys = sys_default();
- }
-
if (nowsel)
ui_title("Tactical: %s", view_main.sys->name);
diff --git a/src/views/smenu.c b/src/views/smenu.c
@@ -0,0 +1,359 @@
+#include <raylib.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/stat.h>
+#include "../main.h"
+
+#define CONTCUR "Back to current game"
+
+#define LOAD_W 300
+#define LOAD_H 350
+#define LOAD_NAMEW 100
+#define BUTTON_W 50
+
+static void savecheck(char *msg, void (*action)(void));
+static void savecheck_callback(int arg);
+static void buttonhandler(int arg);
+static void newhandler(void);
+static int newhandler_actual(Input *in);
+static void newhandler_back(int arg);
+static void quithandler(void);
+static void loadhandler(void);
+static void loadhandler_actual(void);
+static void loadhandler_click(Treeview *tv);
+static void loadhandler_button(int arg);
+static void loadprinter(int x, int y, Treeview *tv, Tree *t);
+static void loadadd(char *dir, time_t mod);
+static void loadinit(char *sdir);
+
+static View_smenu *v = &view_smenu;
+View_smenu view_smenu = {
+ .main = {
+ .x = PAD,
+ .y = PAD,
+ .w = 250,
+ .h = 0,
+ },
+ .b = {
+ [SMENU_NEW] = {1, "New Game", buttonhandler, SMENU_NEW },
+ [SMENU_CONT] = {0, view_smenu.cont.label, buttonhandler, SMENU_CONT },
+ [SMENU_SAVE] = {0, "Save Game", buttonhandler, SMENU_SAVE },
+ [SMENU_LOAD] = {0, "Load Game", buttonhandler, SMENU_LOAD },
+ [SMENU_QUIT] = {1, "Quit", buttonhandler, SMENU_QUIT },
+ },
+ .new = {
+ .disp = 0,
+ .name = {
+ .placeholder = "Save name",
+ .onenter = newhandler_actual,
+ },
+ .create = {1, "Create", NULL, 0, .submit = &view_smenu.new.name},
+ .back = {1, "Back", newhandler_back, 0},
+ },
+ .cont = {
+ .save = NULL,
+ .label = "Continue",
+ },
+ .save = {
+ .check = 0,
+ .msg = NULL,
+ .back = {1, "Back", NULL, -1},
+ .save = {1, "Save", NULL, 1},
+ .discard = {1, "Discard", NULL, 0},
+ },
+ .load = {
+ .init = 1,
+ .disp = 0,
+ .saves = {0},
+ .savelist = {
+ .t = &view_smenu.load.saves,
+ .sel = NULL,
+ .selmask = 0xff,
+ .colmask = 0x00,
+ .filter = NULL,
+ .print = loadprinter,
+ .dclick = loadhandler_click,
+ },
+ .load = {0, "Load", loadhandler_button, 0 },
+ }
+};
+
+static void
+savecheck(char *msg, void (*action)(void)) {
+ v->save.check = 1;
+ v->save.back.func =
+ v->save.save.func =
+ v->save.discard.func = savecheck_callback;
+ v->save.msg = msg;
+ v->save.func = action;
+}
+
+static void
+savecheck_callback(int arg) {
+ v->save.check = 0;
+ if (arg)
+ save_write();
+ if (arg != -1)
+ v->save.func();
+}
+
+
+static void
+buttonhandler(int arg) {
+ switch (arg) {
+ case SMENU_NEW:
+ if (save && save_changed())
+ savecheck("The current game hasn't been saved. Save it?", newhandler);
+ else
+ newhandler();
+ break;
+ case SMENU_SAVE:
+ save_write();
+ /* add to event log */
+ /* fallthrough */
+ case SMENU_CONT:
+ if (!save) {
+ save_read(v->cont.save->name);
+ strcpy(v->cont.label, CONTCUR);
+ }
+ view_tabs.sel = view_before_smenu;
+ break;
+ case SMENU_LOAD:
+ if (save && save_changed())
+ savecheck("The current game hasn't been saved. Save it?", loadhandler);
+ else
+ loadhandler();
+ break;
+ case SMENU_QUIT:
+ checkbeforequit();
+ break;
+ }
+}
+
+static void
+newhandler(void) {
+ v->new.disp = 1;
+}
+
+static int
+newhandler_actual(Input *in) {
+ save_create(v->new.name.str);
+ save_read(v->new.name.str);
+ loadadd(v->new.name.str, time(NULL));
+ view_tabs.sel = UI_VIEW_MAIN;
+ v->new.disp = 0;
+ return 1;
+}
+
+static void
+newhandler_back(int arg) {
+ gui_input_clear(&v->new.name);
+ v->new.disp = 0;
+}
+
+static void
+quithandler(void) {
+ quit = 1;
+}
+
+static void
+loadhandler(void) {
+ v->load.disp = 1;
+ /* strcpy(v->cont.label, CONTCUR); */
+ /* v->b[SMENU_CONT].enabled = 1; */
+}
+
+static void
+loadhandler_actual(void) {
+ struct Loadable *l;
+
+ l = v->load.savelist.sel->data;
+ save_read(l->name);
+ view_tabs.sel = UI_VIEW_MAIN;
+ v->load.disp = 0;
+ return;
+}
+
+static void
+loadhandler_click(Treeview *tv) {
+ loadhandler_actual();
+}
+
+static void
+loadhandler_button(int arg) {
+ loadhandler_actual();
+}
+
+static void
+loadprinter(int x, int y, Treeview *tv, Tree *t) {
+ struct Loadable *l;
+ Color c = (tv->sel == t) ? col_info : col_fg;
+
+ if (!t) {
+ ui_print(x + PAD, y, col_fg, "Name");
+ ui_print(x + PAD + LOAD_NAMEW, y, col_fg, "Last saved");
+ } else {
+ l = t->data;
+ ui_printw(x, y, LOAD_NAMEW, c, "%s", l->name);
+ ui_print( x + LOAD_NAMEW, y, c, "%s", strdate(l->mod));
+ }
+}
+
+static void
+loadadd(char *dir, time_t mod) {
+ struct Loadable *p;
+
+ p = malloc(sizeof(struct Loadable));
+ p->name = nstrdup(dir);
+ p->mod = mod;
+
+ tree_add_child(&v->load.saves, p->name, 1, p, NULL);
+}
+
+void
+checkbeforequit(void) {
+ if (save_changed()) {
+ view_tabs.sel = UI_VIEW_SMENU;
+ savecheck("There are unsaved changes. Save before quitting?", quithandler);
+ } else {
+ quithandler();
+ }
+}
+
+static void
+loadinit(char *sdir) {
+ struct dirent **dirent;
+ struct stat st;
+ char path[PATH_MAX];
+ int n, i;
+
+ n = scandir(sdir, &dirent, NULL, alphasort);
+ if (n < 0) return;
+
+ for (i = 0; i < n; i++) {
+ snprintf(path, sizeof(path), "%s/%s", sdir, dirent[i]->d_name);
+ stat(path, &st);
+ if (dirent[i]->d_name[0] != '.' && S_ISDIR(st.st_mode))
+ loadadd(dirent[i]->d_name, st.st_mtime);
+ free(dirent[i]);
+ }
+ free(dirent);
+}
+
+void
+ui_handle_view_smenu(int nowsel) {
+ Tree *t;
+ struct Loadable *cont, *l;
+
+ v->main.h = PAD + SMENU_LAST * (BUTTON_HEIGHT + PAD);
+ v->main.x = (screen.w - v->main.w) / 2;
+ v->main.y = (screen.h - v->main.h) / 2;
+
+ if (v->load.init) {
+ loadinit(SAVEDIR);
+ for (t = v->load.saves.d, cont = NULL; t; t = t->n) {
+ l = t->data;
+ if (!cont || l->mod > cont->mod)
+ cont = l;
+ }
+ if ((v->cont.save = cont) != NULL) {
+ snprintf(v->cont.label, sizeof(v->cont.label),
+ "Continue (%s)", v->cont.save->name);
+ v->b[SMENU_CONT].enabled = 1;
+ }
+ if (v->load.saves.d)
+ v->b[SMENU_LOAD].enabled = 1;
+ v->load.init = 0;
+ }
+
+ if (v->load.disp && v->load.savelist.sel)
+ v->load.load.enabled = 1;
+ else
+ v->load.load.enabled = 0;
+
+ v->b[SMENU_SAVE].enabled = save ? 1 : 0;
+}
+
+void
+ui_draw_view_smenu(void) {
+ Color bg = { col_bg.r, col_bg.g, col_bg.b, 0xcc };
+ int x, y, w, h;
+ int i;
+
+ ui_draw_texture_part(image_splash, 0, 0,
+ MAX((image_splash.width - screen.w) / 2, 0),
+ MAX((image_splash.height - screen.h) / 2, 0),
+ screen.w, screen.h);
+
+ if (v->new.disp) {
+ w = PAD * 2 + 300;
+ h = PAD * 3 + FONT_SIZE + BUTTON_HEIGHT;
+ x = (screen.w - w) / 2;
+ y = (screen.h - h) / 2;
+
+ ui_draw_rect(x, y, w, h, col_bg);
+ ui_draw_border_around(x, y, w, h, 1);
+
+ x += PAD;
+ y += PAD;
+ gui_input(x, y, 300, &v->new.name);
+
+ x += w - 50 - PAD * 2,
+ gui_button(x, y + PAD * 2, 50, &v->new.create);
+
+ x -= 50 + PAD;
+ gui_button(x, y + PAD * 2, 50, &v->new.back);
+ } else if (v->save.check) {
+ w = PAD * 2 + ui_textsize(v->save.msg);
+ h = PAD * 3 + FONT_SIZE + BUTTON_HEIGHT;
+ x = (screen.w - w) / 2;
+ y = (screen.h - h) / 2;
+
+ ui_draw_rect(x, y, w, h, col_bg);
+ ui_draw_border_around(x, y, w, h, 1);
+
+ x += PAD;
+ y += PAD;
+ ui_print(x, y, col_fg, "%s", v->save.msg);
+
+ x += w - PAD * 2 - 50;
+ y += PAD * 2;
+
+ gui_button(x, y, 50, &v->save.back);
+ gui_button(x -= 50 + PAD, y, 50, &v->save.discard);
+ gui_button(x -= 50 + PAD, y, 50, &v->save.save);
+ } else if (v->load.disp) {
+ w = PAD * 2 + LOAD_W;
+ h = PAD * 3 + LOAD_H + BUTTON_HEIGHT;
+ x = (screen.w - w) / 2;
+ y = (screen.h - h) / 2;
+
+ ui_draw_rect(x, y, w, h, col_bg);
+ ui_draw_border_around(x, y, w, h, 1);
+
+ x += PAD;
+ y += PAD;
+
+ gui_treeview(x, y, LOAD_W, LOAD_H, &v->load.savelist);
+ gui_button(x + w - BUTTON_W - PAD * 2,
+ y + h - PAD * 2 - BUTTON_HEIGHT,
+ BUTTON_W, &v->load.load);
+ } else {
+ ui_draw_rect(EXPLODE_RECT(v->main), bg);
+ ui_draw_border_around(EXPLODE_RECT(v->main), 1);
+
+ x = v->main.x + PAD;
+ y = v->main.y + PAD;
+ w = v->main.w - PAD * 2;
+
+ for (i = 0; i < SMENU_LAST; i++) {
+ ui_draw_rect(x, y, w, BUTTON_HEIGHT, col_bg);
+ gui_button(x, y, w, &v->b[i]);
+ y += BUTTON_HEIGHT + PAD;
+ }
+ }
+}
diff --git a/src/views/struct.h b/src/views/struct.h
@@ -1,3 +1,6 @@
+/* vim: set syntax=c : */
+
+/* main/tactical */
typedef struct {
struct {
Tabs tabs;
@@ -31,6 +34,7 @@ typedef struct {
System *sys;
} View_main;
+/* bodies */
typedef struct {
System *sys;
Body *selstar;
@@ -54,6 +58,7 @@ typedef struct {
} prevframe;
} View_bodies;
+/* sys */
typedef struct {
struct {
Geom geom;
@@ -65,3 +70,48 @@ typedef struct {
} ly;
System *sel;
} View_sys;
+
+/* smenu */
+enum {
+ SMENU_NEW,
+ SMENU_SAVE,
+ SMENU_CONT,
+ SMENU_LOAD,
+ SMENU_QUIT,
+ SMENU_LAST
+};
+
+struct Loadable {
+ char *name;
+ time_t mod;
+};
+
+typedef struct {
+ Geom main;
+ Button b[SMENU_LAST];
+ struct {
+ int disp;
+ Input name;
+ Button create;
+ Button back;
+ } new;
+ struct {
+ struct Loadable *save;
+ char label[128];
+ } cont;
+ struct {
+ int check;
+ char *msg;
+ Button back;
+ Button save;
+ Button discard;
+ void (*func)(void);
+ } save;
+ struct {
+ int init;
+ int disp;
+ Tree saves;
+ Treeview savelist;
+ Button load;
+ } load;
+} View_smenu;