cepheid

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

commit bca3d6ff114aada012dd6d4be435043af80121bd
parent c2108e03a95dd018b62128994f25652ebebfebe3
Author: hhvn <dev@hhvn.uk>
Date:   Wed, 31 Aug 2022 20:57:45 +0100

Bodies view

Diffstat:
M.gitignore | 1+
Msrc/main.c | 29++++++-----------------------
Msrc/main.h | 48+++++++++++++++++++++++++++++++-----------------
Msrc/pane.c | 2+-
Msrc/struct.h | 38++++++++++++++++++++++++++++++--------
Msrc/system.c | 2+-
Msrc/ui.c | 367+++++++------------------------------------------------------------------------
Asrc/ui/bodies.c | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ui/main.c | 293+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ui/struct.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/views.h | 42------------------------------------------
11 files changed, 583 insertions(+), 430 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -6,3 +6,4 @@ db/dbtool game testdb/ core.* +tags diff --git a/src/main.c b/src/main.c @@ -9,12 +9,9 @@ Save *save = NULL; int main(void) { - int draw; - int view_prev = -1; - time_t lastevent; + int view_prev; Loader *loader; - loader = loading_open(DATA_LOAD_STEPS + SAVE_READ_STEPS + 3, "Initializing UI"); ui_init(); @@ -24,8 +21,6 @@ main(void) { loading_close(loader); - lastevent = time(NULL); - /* 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 @@ -49,27 +44,15 @@ main(void) { else if (IsKeyPressed(KEY_SIX)) view_tabs.sel = 5; } - draw = view_handlers[view_tabs.sel](view_prev != view_tabs.sel); - - if (lastevent == time(NULL)) - draw = 1; - view_prev = view_tabs.sel; - if (view_prev != view_tabs.sel || - GetMouseWheelMove() || - IsWindowResized() || - ui_clickable_update() || - IsMouseButtonDown(MOUSE_BUTTON_LEFT) || - IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) - lastevent = time(NULL); + ui_clickable_update(); + view_handlers[view_tabs.sel](view_prev != view_tabs.sel); BeginDrawing(); - if (draw) { - ClearBackground(col_bg); - ui_clickable_clear(); - view_drawers[view_tabs.sel](); - } + ClearBackground(col_bg); + ui_clickable_clear(); + view_drawers[view_tabs.sel](); ui_draw_views(); EndDrawing(); } diff --git a/src/main.h b/src/main.h @@ -2,11 +2,14 @@ #include <stdarg.h> #include <raylib.h> #include "struct.h" +#include "ui/struct.h" #include "style.h" #include "maths.h" #include "../db/db.h" #define ELEMS(array) (sizeof(array)/sizeof(array[0])) +#define MAX(a, b) (a > b ? a : b) +#define MIN(a, b) (a < b ? a : b) /* main.c */ extern Save *save; @@ -28,6 +31,12 @@ int strlistpos(char *str, char **list, size_t len); float strnum(char *str); /* ui.c */ +#define VIEWS_MAX_WIDTH (UI_VIEW_LAST*100) +#define VIEWS_HEIGHT 25 +#define WINDOW_TAB_HEIGHT 20 +#define TARGET_FPS 60 +#define WINDOW_BORDER 2 +#define PAD 10 #define EXPLODE_RECT(r) r.x, r.y, r.w, r.h #define EXPLODE_CIRCLE(c) c.centre, c.r #define RLIFY_RECT(r) ((Rectangle){ EXPLODE_RECT(r) }) @@ -36,16 +45,17 @@ float strnum(char *str); #define GEOM_RECT(x, y, w, h) ((Geom){UI_RECT, .rect = {x, y, w, h}}) #define GEOM_CIRCLE(centre, r) ((Geom){UI_CIRCLE, .circle = {centre, r}) extern Tabs view_tabs; -extern int (*view_handlers[UI_VIEW_LAST])(int); +extern void (*view_handlers[UI_VIEW_LAST])(int); extern void (*view_drawers[UI_VIEW_LAST])(void); -extern Rect screen_rect; -extern View_main view_main; +extern Screen screen; extern View_sys view_sys; void ui_init(void); void ui_update_screen(void); void ui_deinit(void); void ui_print(int x, int y, Color col, char *format, ...); +void ui_title(char *fmt, ...); int ui_textsize(char *text); +int ui_checkbox_size(Checkbox *checkbox); int ui_collides(Geom geom, Vector2 point); int ui_onscreen(Vector2 point); int ui_onscreen_ring(Vector2 centre, float r); @@ -57,6 +67,7 @@ void ui_clickable_clear(void); void ui_draw_views(void); void ui_draw_rectangle(int x, int y, int w, int h, Color col); 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_circle(int x, int y, float r, Color col); @@ -64,28 +75,31 @@ void ui_draw_line(int sx, int sy, int ex, int ey, float thick, Color col); void ui_draw_line_v(Vector2 start, Vector2 end, float thick, Color col); void ui_draw_tabs(int x, int y, int w, int h, Tabs *tabs); void ui_draw_tabbed_window(int x, int y, int w, int h, Tabs *tabs); -void ui_draw_checkbox(int x, int y, Checkbox *checkbox); -Vector2 ui_kmtopx(Vector2 km); -Vector2 ui_pxtokm(Vector2 vector); +int ui_draw_checkbox(int x, int y, Checkbox *checkbox); /* returns width */ Vector2 ui_vectordiff(Vector2 a, Vector2 b); float ui_vectordist(Vector2 a, Vector2 b); -void ui_draw_orbit(Body *body); -void ui_draw_body(Body *body); -int ui_handle_view_main(int nowsel); -int ui_handle_view_colonies(int nowsel); -int ui_handle_view_bodies(int nowsel); -int ui_handle_view_fleets(int nowsel); -int ui_handle_view_design(int nowsel); -int ui_handle_view_sys(int nowsel); -int ui_handle_view_settings(int nowsel); -void ui_draw_view_main(void); +void ui_handle_view_colonies(int nowsel); +void ui_handle_view_fleets(int nowsel); +void ui_handle_view_design(int nowsel); +void ui_handle_view_sys(int nowsel); +void ui_handle_view_settings(int nowsel); void ui_draw_view_colonies(void); -void ui_draw_view_bodies(void); void ui_draw_view_fleets(void); void ui_draw_view_design(void); void ui_draw_view_sys(void); void ui_draw_view_settings(void); +/* ui/main.c */ +extern View_main view_main; +void ui_handle_view_main(int nowsel); +void ui_draw_view_main(void); + +/* ui/bodies.c */ +extern View_bodies view_bodies; +void ui_handle_view_bodies(int nowsel); +void ui_draw_view_bodies(void); + + /* pane.c */ void pane_begin(Pane *f); void pane_end(void); diff --git a/src/pane.c b/src/pane.c @@ -2,7 +2,7 @@ #include "main.h" #define SCROLLBAR_W 4 -#define SCROLL_MULT 10 +#define SCROLL_MULT 50 static Pane *pane = NULL; diff --git a/src/struct.h b/src/struct.h @@ -130,6 +130,34 @@ typedef struct { char *label; } Checkbox; +typedef struct { + char *name; + void (*func)(int); + int arg; +} Button; + +#define INPUT_MAX 512 +typedef struct { + char str[INPUT_MAX]; + void (*onenter)(char *, int); + int arg; +} Input; + +#define DROPDOWN_MAX 64 +typedef struct { + int n; + int sel; /* -1 for none */ + char *val[DROPDOWN_MAX]; +} Dropdown; + +enum UiElements { + UI_TAB, + UI_CHECKBOX, + UI_BODY, + UI_BUTTON, + UI_INPUT, +}; + enum UiViews { UI_VIEW_MAIN, UI_VIEW_COLONIES, @@ -141,11 +169,6 @@ enum UiViews { UI_VIEW_LAST }; -enum UiElements { - UI_TAB, - UI_CHECKBOX, -}; - #define CLICKABLE_MAX 64 typedef struct { Geom geom; @@ -162,12 +185,11 @@ typedef struct { } Loader; /* pane.c */ +#define PANESCROLL {NULL, 1, 0, 0} +#define PANENOSCROLL {NULL, 0, 0, 0} typedef struct { Rect *geom; int scroll; int max; int off; } Pane; - -/* unique structures */ -#include "views.h" diff --git a/src/system.c b/src/system.c @@ -38,7 +38,7 @@ bodytype_enumify(char *name) { char * bodytype_strify(Body *body) { return bodytype_names[body->type + - body->parent ? body->parent->type : 0]; + (body->parent ? body->parent->type : 0)]; } Vector2 diff --git a/src/ui.c b/src/ui.c @@ -5,25 +5,10 @@ #include <raylib.h> #include "main.h" -#define VIEWS_MAX_WIDTH (UI_VIEW_LAST*100) -#define VIEWS_HEIGHT 25 -#define WINDOW_TAB_HEIGHT 20 -#define TARGET_FPS 60 -#define WINDOW_BORDER 2 - static Clickable clickable[CLICKABLE_MAX]; -static float min_body_rad[] = { - [BODY_STAR] = 4, - [BODY_PLANET] = 3, - [BODY_COMET] = 2, - [BODY_DWARF] = 2, - [BODY_ASTEROID] = 1, - [BODY_MOON] = 1, -}; - /* Return 1 for redraw, 0 to keep prev */ -int (*view_handlers[UI_VIEW_LAST])(int) = { +void (*view_handlers[UI_VIEW_LAST])(int) = { [UI_VIEW_MAIN] = ui_handle_view_main, [UI_VIEW_COLONIES] = ui_handle_view_colonies, [UI_VIEW_BODIES] = ui_handle_view_bodies, @@ -57,54 +42,6 @@ Tabs view_tabs = { {&image_settings, "Settings", 0}} }; -View_main view_main = { - .infobox = { - .tabs = { - 2, 0, {{NULL, "Display", 0}, {NULL, "Minerals", 0}} - }, - .names = { - .dwarf = {1, 1, "Name: dwarf planets"}, - .dwarfn = {1, 0, "Name: numbered dwarf planets"}, /* TODO */ - .asteroid = {1, 0, "Name: asteroids"}, - .asteroidn = {1, 0, "Name: numbered asteroids"}, /* TODO */ - .comet = {1, 1, "Name: comets"}, - }, - .orbit = { - .dwarf = {1, 0, "Orbit: dwarf planets"}, - .asteroid = {1, 0, "Orbit: asteroids"}, - .comet = {1, 0, "Orbit: comets"}, - }, - .comettail = {1, 1, "Comet tails"}, /* TODO */ - .geom = { - .type = UI_RECT, - .rect = { - .x = 10, - .y = VIEWS_HEIGHT + 10, - .w = 200, - .h = 400, - }, - }, - .pane = { - .geom = NULL, - .scroll = 1, - .max = 0, - .off = 0, - }, - }, - .pan = 0, - .ruler = {.held = 0}, - .kmx = 0, - .kmy = 0, - .kmperpx = 500000, - .scale = { - .x = 10, - .y = 10, /* from bottom */ - .w = 50, - .h = 3, - }, - .sys = NULL, -}; - View_sys view_sys = { .info = { .geom = { @@ -151,6 +88,9 @@ ui_print(int x, int y, Color col, char *fmt, ...) { Vector2 pos; char *text; + if (!pane_visible(y, y + FONT_SIZE)) + return; + pos.x = x; pos.y = pane_y(y); va_start(ap, fmt); @@ -477,34 +417,26 @@ 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) { + ui_draw_border(x - px, y - px, w + px * 2, h + px * 2, px); +} + +int ui_draw_checkbox(int x, int y, Checkbox *box) { int w, h; + int rw; w = h = FONT_SIZE; ui_draw_border(x, y, w, h, 1); ui_draw_rectangle(x + 1, y + 1, w - 2, h - 2, box->enabled ? (box->val ? col_fg : col_bg) : col_border); ui_print(x + w + (w / 2), y + (h / 6), col_fg, "%s", box->label); + rw = w + (w / 2) + ui_textsize(box->label); if (box->enabled) ui_clickable_register(GEOM_RECT(x, y, - w + (w / 2) + ui_textsize(box->label), h), + rw, h), UI_CHECKBOX, box); -} - -Vector2 -ui_kmtopx(Vector2 km) { - return (Vector2) { - (GetScreenWidth() / 2) + (km.x - view_main.kmx) / view_main.kmperpx, - (GetScreenHeight() / 2) + (km.y - view_main.kmy) / view_main.kmperpx - }; -} - -Vector2 -ui_pxtokm(Vector2 vector) { - return (Vector2) { - ((vector.x - GetScreenWidth() / 2) * view_main.kmperpx) + view_main.kmx, - ((vector.y - GetScreenHeight() / 2) * view_main.kmperpx) + view_main.kmy - }; + return rw; } Vector2 @@ -531,301 +463,60 @@ ui_draw_tabbed_window(int x, int y, int w, int h, Tabs *tabs) { ui_draw_border(x, y, w, h, WINDOW_BORDER); } -int -ui_handle_view_main(int nowsel) { - Vector2 mouse = GetMousePosition(); - Vector2 delta = GetMouseDelta(); - float wheel = GetMouseWheelMove(); - float diff; - Body *furth; - - if (view_main.sys) - furth = view_main.sys->furthest_body; - -#define SCROLL_DIVISOR 10 - if (!ui_collides(view_main.infobox.geom, mouse)) { - if (wheel) { - diff = wheel * (view_main.kmperpx/SCROLL_DIVISOR); - if (diff > 0 || !furth || view_main.kmperpx * GetScreenHeight() < - 2 * (furth->type == BODY_COMET ? furth->maxdist : furth->dist)) { - view_main.kmperpx -= diff; - view_main.kmx += (mouse.x - GetScreenWidth() / 2) * diff; - view_main.kmy += (mouse.y - GetScreenHeight() / 2) * diff; - } - } - - if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) { - if (view_main.pan) { - view_main.kmx -= delta.x * view_main.kmperpx; - view_main.kmy -= delta.y * view_main.kmperpx; - } else if (!ui_collides(view_main.infobox.geom, mouse)) { - view_main.pan = 1; - } - } else { - view_main.pan = 0; - } - - if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT) && !view_main.ruler.held) { - view_main.ruler.held = 1; - view_main.ruler.origin = ui_pxtokm(mouse); - } else if (IsMouseButtonUp(MOUSE_BUTTON_RIGHT)) { - view_main.ruler.held = 0; - } - } - - if (!view_main.sys) { - view_main.sys = sys_default(); - } - - if (nowsel) - ui_title("Tactical: %s", view_main.sys->name); - - view_main.infobox.names.dwarfn.enabled = view_main.infobox.names.dwarf.val; - view_main.infobox.names.asteroidn.enabled = view_main.infobox.names.asteroid.val; - - /* so that the debug stuff prints */ - if (delta.x || delta.y) - return 1; - - return 0; -} - -int +void ui_handle_view_colonies(int nowsel) { if (nowsel) ui_title("Colonies"); - return 1; -} - -int -ui_handle_view_bodies(int nowsel) { - if (nowsel) - ui_title("Bodies"); - return 1; } -int +void ui_handle_view_fleets(int nowsel) { if (nowsel) ui_title("Fleets"); - return 1; } -int +void ui_handle_view_design(int nowsel) { if (nowsel) ui_title("Design"); - return 1; } -int +void ui_handle_view_sys(int nowsel) { if (nowsel) ui_title("Systems"); view_sys.info.geom.h = GetScreenHeight() - VIEWS_HEIGHT; if (!view_sys.sel) view_sys.sel = sys_default(); - return 1; } -int +void ui_handle_view_settings(int nowsel) { if (nowsel) ui_title("Settings"); - return 1; -} - -static int -ui_should_draw_body_checkbox(Body *body, int type, Checkbox *box) { - if ((body->type == type || (body->parent && - body->parent->type == type)) && - !box->val) - return 0; - return 1; -} - -void -ui_draw_orbit(Body *body) { - Vector2 parent; - float pxrad; - - if (!body->parent) - return; - if (!ui_should_draw_body_checkbox(body, BODY_DWARF, - &view_main.infobox.orbit.dwarf)) - return; - if (!ui_should_draw_body_checkbox(body, BODY_ASTEROID, - &view_main.infobox.orbit.asteroid)) - return; - if (!ui_should_draw_body_checkbox(body, BODY_COMET, - &view_main.infobox.orbit.comet)) - return; - - parent = ui_kmtopx(body->parent->vector); - pxrad = ui_vectordist(parent, body->pxloc); - - if (pxrad < min_body_rad[body->parent->type]) - return; - - if (body->type == BODY_COMET) - ui_draw_line_v(parent, body->pxloc, 1, col_orbit); - else - ui_draw_ring(parent.x, parent.y, pxrad, col_orbit); -} - -void -ui_draw_body(Body *body) { - float w; - - if (!ui_onscreen(body->pxloc)) - return; - - /* body */ - if (body->radius / view_main.kmperpx > min_body_rad[body->type]) - w = body->radius / view_main.kmperpx; - else - w = min_body_rad[body->type]; - ui_draw_circle(body->pxloc.x, body->pxloc.y, w, col_body[body->type]); - if (body->type == BODY_COMET && view_main.infobox.comettail.val && - 10 * view_main.kmperpx < body->curdist) - ui_draw_line_v(body->pxloc, sys_vectorize_around(body->pxloc, - (Polar){w * 11 / min_body_rad[BODY_COMET], - body->inward ? body->theta : body->theta + 180}), - w / min_body_rad[BODY_COMET], col_body[BODY_COMET]); - - /* name */ - if (body->type != BODY_STAR && - (body->type == BODY_COMET ? body->maxdist : body->dist) - / view_main.kmperpx < ui_textsize(body->name)) - return; - if (body->parent && body->type != BODY_STAR && - ui_vectordist(body->vector, body->parent->vector) < - min_body_rad[body->type] * view_main.kmperpx) - return; - if (isdigit(*body->name) || *body->name == '(') { - if (!ui_should_draw_body_checkbox(body, BODY_DWARF, - &view_main.infobox.names.dwarfn)) - return; - if (!ui_should_draw_body_checkbox(body, BODY_ASTEROID, - &view_main.infobox.names.asteroidn)) - return; - } - if (!ui_should_draw_body_checkbox(body, BODY_DWARF, - &view_main.infobox.names.dwarf)) - return; - if (!ui_should_draw_body_checkbox(body, BODY_ASTEROID, - &view_main.infobox.names.asteroid)) - return; - if (!ui_should_draw_body_checkbox(body, BODY_COMET, - &view_main.infobox.names.comet)) - return; - - ui_print(body->pxloc.x + w + 2, body->pxloc.y + w + 2, - col_fg, "%s", body->name); -} - -void -ui_draw_view_main(void) { - Vector2 mouse = GetMousePosition(); - Vector2 mousekm = ui_pxtokm(mouse); - Vector2 ruler; - Rect rect; - Body *body; - float dist; - size_t i; - float x, y; - - /* debug info */ - ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 10, col_fg, "W: %f | H: %f", (float)screen.w, (float)screen.h); - ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 20, col_fg, "Xoff: %f | Yoff: %f | km/px: %f", - view_main.kmx, view_main.kmy, view_main.kmperpx); - ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 30, col_fg, "X: %f | Y: %f", - mousekm.x, mousekm.y); - ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 40, 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]; - body->pxloc = ui_kmtopx(body->vector); - ui_draw_orbit(body); - } - for (i = 0; i < view_main.sys->bodies_len; i++) { - body = view_main.sys->bodies[i]; - ui_draw_body(body); - } - - /* ruler */ - if (view_main.ruler.held) { - ruler = ui_kmtopx(view_main.ruler.origin); - ui_draw_line_v(ruler, mouse, 1, col_info); - dist = ui_vectordist(view_main.ruler.origin, mousekm); - ui_print(mouse.x + 10, mouse.y - 10, col_info, "%s (%s)", strkmdist(dist), strlightdist(dist)); - } - - /* scale */ - ui_draw_rectangle(view_main.scale.x, - GetScreenHeight() - view_main.scale.y, - view_main.scale.w, 1, col_info); /* horizontal */ - ui_draw_rectangle(view_main.scale.x, - GetScreenHeight() - view_main.scale.y - view_main.scale.h, - 1, view_main.scale.h, col_info); /* left vertical */ - ui_draw_rectangle(view_main.scale.x + view_main.scale.w, - GetScreenHeight() - view_main.scale.y - view_main.scale.h, - 1, view_main.scale.h, col_info); /* right vertical */ - dist = view_main.scale.w * view_main.kmperpx; - ui_print(view_main.scale.x + view_main.scale.w + FONT_SIZE / 3, - GetScreenHeight() - view_main.scale.y - FONT_SIZE / 2, - col_info, "%s", strkmdist(dist)); - - /* infobox */ - ui_draw_tabbed_window(EXPLODE_RECT(view_main.infobox.geom.rect), - &view_main.infobox.tabs); - x = view_main.infobox.geom.rect.x + FONT_SIZE; - y = view_main.infobox.geom.rect.y + WINDOW_TAB_HEIGHT; - rect.x = x - FONT_SIZE; - rect.y = y; - rect.w = view_main.infobox.geom.rect.w - WINDOW_BORDER; - rect.h = view_main.infobox.geom.rect.h - WINDOW_TAB_HEIGHT - WINDOW_BORDER; - view_main.infobox.pane.geom = &rect; - - pane_begin(&view_main.infobox.pane); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.dwarf); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.dwarfn); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.asteroid); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.asteroidn); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.comet); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.dwarf); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.asteroid); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.comet); - ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.comettail); - pane_end(); } void ui_draw_view_colonies(void) { - ui_print(10, VIEWS_HEIGHT + 10, col_fg, "Stars/colonies here"); - ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 10, col_fg, "Tabs here"); + ui_print(PAD, VIEWS_HEIGHT + PAD, col_fg, "Stars/colonies here"); + ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + PAD, col_fg, "Tabs here"); ui_print(GetScreenWidth() / 2, GetScreenHeight() / 2, col_fg, "Management stuff here"); } -void -ui_draw_view_bodies(void) { - ui_print(10, VIEWS_HEIGHT + 10, col_fg, "Something like the mineral overview in Aurora"); -} void ui_draw_view_fleets(void) { - ui_print(10, VIEWS_HEIGHT + 10, col_fg, "Groups/fleets/subfleets/ships here"); - ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + 10, col_fg, "Tabs here"); + ui_print(PAD, VIEWS_HEIGHT + PAD, col_fg, "Groups/fleets/subfleets/ships here"); + ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + PAD, col_fg, "Tabs here"); ui_print(GetScreenWidth() / 2, GetScreenHeight() / 2, col_fg, "Management stuff here"); } void ui_draw_view_design(void) { - ui_print(10, VIEWS_HEIGHT + 10, col_fg, "Designations/classes here"); - ui_print(GetScreenWidth() / 4, VIEWS_HEIGHT + 10, col_fg, "Selectable components here"); - ui_print((GetScreenWidth() / 4) * 2, VIEWS_HEIGHT + 10, col_fg, "Selected components"); - ui_print((GetScreenWidth() / 4) * 3, VIEWS_HEIGHT + 10, col_fg, "Class info"); + ui_print(PAD, VIEWS_HEIGHT + PAD, col_fg, "Designations/classes here"); + ui_print(GetScreenWidth() / 4, VIEWS_HEIGHT + PAD, col_fg, "Selectable components here"); + ui_print((GetScreenWidth() / 4) * 2, VIEWS_HEIGHT + PAD, col_fg, "Selected components"); + ui_print((GetScreenWidth() / 4) * 3, VIEWS_HEIGHT + PAD, col_fg, "Class info"); } void @@ -841,8 +532,8 @@ ui_draw_view_sys(void) { ui_draw_line(x, y, x, y + view_sys.info.geom.h, 1, col_border); /* draw info */ - x = view_sys.info.geom.x + 10; - y += 10; + x = view_sys.info.geom.x + PAD; + y += PAD; if (view_sys.sel) { ui_print(x, y, col_fg, "%s", view_sys.sel->name); ui_draw_line(x, y + FONT_SIZE, x + view_sys.info.geom.w - 20, @@ -860,5 +551,5 @@ ui_draw_view_sys(void) { void ui_draw_view_settings(void) { - ui_print(10, VIEWS_HEIGHT + 10, col_fg, "Settings here"); + ui_print(PAD, VIEWS_HEIGHT + PAD, col_fg, "Settings here"); } diff --git a/src/ui/bodies.c b/src/ui/bodies.c @@ -0,0 +1,134 @@ +#include "../main.h" + +#define INFOBOXES 3 +#define INFOBOX_H (FONT_SIZE * 11 + PAD * 2) +#define INFOBOX_W ((screen.w - PAD * (1 + INFOBOXES)) / INFOBOXES) +#define BUTTONS 50 +#define W MIN(screen.w / 20, 50) + +View_bodies view_bodies = { + .sys = NULL, + .sel = NULL, + .show = { + .planet = {1, 1, "Show planets"}, + .moon = {1, 1, "Show moons"}, + .dwarf = {1, 1, "Show dwarf planets"}, + .asteroid = {1, 1, "Show asteroids"}, + .comet = {1, 1, "Show comets"}, + .nomineral = {1, 1, "Show bodies without minerals"}, + }, + .stars = PANESCROLL, + .bodies = PANESCROLL, +}; + +void +ui_handle_view_bodies(int nowsel) { + if (!view_bodies.sys) + view_bodies.sys = sys_default(); + if (nowsel) + ui_title("Bodies in %s", view_bodies.sys->name); +} + +static int +draw_star(int x, int y, Body *star) { + ui_print(x, y, col_fg, "%s", star->name); + return y + FONT_SIZE; +} + +static int +draw_body(int x, int y, Body *body) { + ui_print(x, y, col_fg, "%s", body->name); + ui_print(x + 3*W, y, col_fg, "%s", body->parent ? body->parent->name : "-"); + ui_print(x + 5*W, y, col_fg, "%s", bodytype_strify(body)); + return y + FONT_SIZE; +} + +static int +display_body(Body *body) { + if (body->type == BODY_STAR || !body->parent) + return 0; + if (body->type == BODY_MOON && !view_bodies.show.moon.val) + return 0; + if ((body->type == BODY_PLANET || body->parent->type == BODY_PLANET) && + !view_bodies.show.planet.val) + return 0; + if ((body->type == BODY_DWARF || body->parent->type == BODY_DWARF) && + !view_bodies.show.dwarf.val) + return 0; + if ((body->type == BODY_ASTEROID || body->parent->type == BODY_ASTEROID) && + !view_bodies.show.asteroid.val) + return 0; + if ((body->type == BODY_COMET || body->parent->type == BODY_COMET) && + !view_bodies.show.comet.val) + return 0; + /* TODO: exclude bodies with no minerals */ + return 1; +} + +void +ui_draw_view_bodies(void) { + Rect stars = { PAD, VIEWS_HEIGHT + PAD * 2 + FONT_SIZE, + screen.w - PAD * 2, FONT_SIZE * 6 }; + Rect checkboxes = { stars.x, stars.y + stars.h + PAD, + stars.w, FONT_SIZE + PAD}; + Rect bodies = { checkboxes.x, checkboxes.y + checkboxes.h + PAD/2, + checkboxes.w, screen.h - bodies.y - INFOBOX_H - BUTTONS }; + Rect location = { bodies.x, bodies.y + bodies.h + PAD, + INFOBOX_W, INFOBOX_H }; + Rect minerals = { location.x + location.w + PAD, location.y, + INFOBOX_W, INFOBOX_H }; + Rect habitat = { minerals.x + minerals.w + PAD, minerals.y, + INFOBOX_W, INFOBOX_H }; + int x, y; + int i; + Body *body; + + if (!view_bodies.sel) + bodies.h += INFOBOX_H; + + ui_print(PAD, VIEWS_HEIGHT + PAD, col_fg, "[System selection dropdown]"); + + ui_draw_border_around(EXPLODE_RECT(stars), 1); + view_bodies.stars.geom = &stars; + pane_begin(&view_bodies.stars); + x = stars.x + PAD/2; + y = stars.y + PAD/2; + ui_print(x, y, col_fg, "Name"); + y += FONT_SIZE * 1.5; + for (i = 0; i < view_bodies.sys->bodies_len; i++) + if (view_bodies.sys->bodies[i]->type == BODY_STAR) + y = draw_star(x, y, view_bodies.sys->bodies[i]); + pane_end(); + + x = checkboxes.x + PAD/2; + y = checkboxes.y + PAD/2; + x += ui_draw_checkbox(x, y, &view_bodies.show.planet) + PAD * 2; + x += ui_draw_checkbox(x, y, &view_bodies.show.moon) + PAD * 2; + x += ui_draw_checkbox(x, y, &view_bodies.show.dwarf) + PAD * 2; + x += ui_draw_checkbox(x, y, &view_bodies.show.asteroid) + PAD * 2; + x += ui_draw_checkbox(x, y, &view_bodies.show.comet) + PAD * 2; + x += ui_draw_checkbox(x, y, &view_bodies.show.nomineral); + ui_draw_border_around(checkboxes.x, checkboxes.y, x, checkboxes.h, 1); + + ui_draw_border_around(EXPLODE_RECT(bodies), 1); + view_bodies.bodies.geom = &bodies; + pane_begin(&view_bodies.bodies); + x = bodies.x + PAD/2; + y = 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 (i = 0; i < view_bodies.sys->bodies_len; i++) { + body = view_bodies.sys->bodies[i]; + if (display_body(body)) + y = draw_body(x, y, body); + } + pane_end(); + + if (view_bodies.sel) { + ui_draw_border_around(EXPLODE_RECT(location), 1); + ui_draw_border_around(EXPLODE_RECT(minerals), 1); + ui_draw_border_around(EXPLODE_RECT(habitat), 1); + } +} diff --git a/src/ui/main.c b/src/ui/main.c @@ -0,0 +1,293 @@ +#include <ctype.h> +#include "../main.h" + +static float min_body_rad[] = { + [BODY_STAR] = 4, + [BODY_PLANET] = 3, + [BODY_COMET] = 2, + [BODY_DWARF] = 2, + [BODY_ASTEROID] = 1, + [BODY_MOON] = 1, +}; + +View_main view_main = { + .infobox = { + .tabs = { + 2, 0, {{NULL, "Display", 0}, {NULL, "Minerals", 0}} + }, + .names = { + .dwarf = {1, 1, "Name: dwarf planets"}, + .dwarfn = {1, 0, "Name: numbered dwarf planets"}, /* TODO */ + .asteroid = {1, 0, "Name: asteroids"}, + .asteroidn = {1, 0, "Name: numbered asteroids"}, /* TODO */ + .comet = {1, 1, "Name: comets"}, + }, + .orbit = { + .dwarf = {1, 0, "Orbit: dwarf planets"}, + .asteroid = {1, 0, "Orbit: asteroids"}, + .comet = {1, 0, "Orbit: comets"}, + }, + .comettail = {1, 1, "Comet tails"}, /* TODO */ + .geom = { + .type = UI_RECT, + .rect = { + .x = PAD, + .y = VIEWS_HEIGHT + PAD, + .w = 200, + .h = 400, + }, + }, + .pane = PANESCROLL, + }, + .pan = 0, + .ruler = {.held = 0}, + .kmx = 0, + .kmy = 0, + .kmperpx = 500000, + .scale = { + .x = PAD, + .y = PAD, /* from bottom */ + .w = 50, + .h = 3, + }, + .sys = NULL, +}; + +Vector2 +kmtopx(Vector2 km) { + return (Vector2) { + (GetScreenWidth() / 2) + (km.x - view_main.kmx) / view_main.kmperpx, + (GetScreenHeight() / 2) + (km.y - view_main.kmy) / view_main.kmperpx + }; +} + +Vector2 +pxtokm(Vector2 vector) { + return (Vector2) { + ((vector.x - GetScreenWidth() / 2) * view_main.kmperpx) + view_main.kmx, + ((vector.y - GetScreenHeight() / 2) * view_main.kmperpx) + view_main.kmy + }; +} + +void +ui_handle_view_main(int nowsel) { + Vector2 mouse = GetMousePosition(); + Vector2 delta = GetMouseDelta(); + float wheel = GetMouseWheelMove(); + float diff; + Body *furth; + + if (view_main.sys) + furth = view_main.sys->furthest_body; + +#define SCROLL_DIVISOR 10 + if (!ui_collides(view_main.infobox.geom, mouse)) { + if (wheel) { + diff = wheel * (view_main.kmperpx/SCROLL_DIVISOR); + if (diff > 0 || !furth || view_main.kmperpx * GetScreenHeight() < + 2 * (furth->type == BODY_COMET ? furth->maxdist : furth->dist)) { + view_main.kmperpx -= diff; + view_main.kmx += (mouse.x - GetScreenWidth() / 2) * diff; + view_main.kmy += (mouse.y - GetScreenHeight() / 2) * diff; + } + } + + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) { + if (view_main.pan) { + view_main.kmx -= delta.x * view_main.kmperpx; + view_main.kmy -= delta.y * view_main.kmperpx; + } else if (!ui_collides(view_main.infobox.geom, mouse)) { + view_main.pan = 1; + } + } else { + view_main.pan = 0; + } + + if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT) && !view_main.ruler.held) { + view_main.ruler.held = 1; + view_main.ruler.origin = pxtokm(mouse); + } else if (IsMouseButtonUp(MOUSE_BUTTON_RIGHT)) { + view_main.ruler.held = 0; + } + } + + if (!view_main.sys) { + view_main.sys = sys_default(); + } + + if (nowsel) + ui_title("Tactical: %s", view_main.sys->name); + + view_main.infobox.names.dwarfn.enabled = view_main.infobox.names.dwarf.val; + view_main.infobox.names.asteroidn.enabled = view_main.infobox.names.asteroid.val; +} + +static int +should_draw_body_checkbox(Body *body, int type, Checkbox *box) { + if ((body->type == type || (body->parent && + body->parent->type == type)) && + !box->val) + return 0; + return 1; +} + +static void +draw_orbit(Body *body) { + Vector2 parent; + float pxrad; + + if (!body->parent) + return; + if (!should_draw_body_checkbox(body, BODY_DWARF, + &view_main.infobox.orbit.dwarf)) + return; + if (!should_draw_body_checkbox(body, BODY_ASTEROID, + &view_main.infobox.orbit.asteroid)) + return; + if (!should_draw_body_checkbox(body, BODY_COMET, + &view_main.infobox.orbit.comet)) + return; + + parent = kmtopx(body->parent->vector); + pxrad = ui_vectordist(parent, body->pxloc); + + if (pxrad < min_body_rad[body->parent->type]) + return; + + if (body->type == BODY_COMET) + ui_draw_line_v(parent, body->pxloc, 1, col_orbit); + else + ui_draw_ring(parent.x, parent.y, pxrad, col_orbit); +} + +static void +draw_body(Body *body) { + float w; + + if (!ui_onscreen(body->pxloc)) + return; + + /* body */ + if (body->radius / view_main.kmperpx > min_body_rad[body->type]) + w = body->radius / view_main.kmperpx; + else + w = min_body_rad[body->type]; + + if (body->parent && body->type != BODY_COMET && body->dist / view_main.kmperpx < w) + return; + + ui_draw_circle(body->pxloc.x, body->pxloc.y, w, col_body[body->type]); + if (body->type == BODY_COMET && view_main.infobox.comettail.val && + 10 * view_main.kmperpx < body->curdist) + ui_draw_line_v(body->pxloc, sys_vectorize_around(body->pxloc, + (Polar){w * 11 / min_body_rad[BODY_COMET], + body->inward ? body->theta : body->theta + 180}), + w / min_body_rad[BODY_COMET], col_body[BODY_COMET]); + + /* name */ + if (body->type != BODY_STAR && + (body->type == BODY_COMET ? body->maxdist : body->dist) + / view_main.kmperpx < ui_textsize(body->name)) + return; + if (body->parent && body->type != BODY_STAR && + ui_vectordist(body->vector, body->parent->vector) < + min_body_rad[body->type] * view_main.kmperpx) + return; + if (isdigit(*body->name) || *body->name == '(') { + if (!should_draw_body_checkbox(body, BODY_DWARF, + &view_main.infobox.names.dwarfn)) + return; + if (!should_draw_body_checkbox(body, BODY_ASTEROID, + &view_main.infobox.names.asteroidn)) + return; + } + if (!should_draw_body_checkbox(body, BODY_DWARF, + &view_main.infobox.names.dwarf)) + return; + if (!should_draw_body_checkbox(body, BODY_ASTEROID, + &view_main.infobox.names.asteroid)) + return; + if (!should_draw_body_checkbox(body, BODY_COMET, + &view_main.infobox.names.comet)) + return; + + ui_print(body->pxloc.x + w + 2, body->pxloc.y + w + 2, + col_fg, "%s", body->name); +} + +void +ui_draw_view_main(void) { + Vector2 mouse = GetMousePosition(); + Vector2 mousekm = pxtokm(mouse); + Vector2 ruler; + Rect rect; + Body *body; + float dist; + size_t i; + float x, y; + + /* debug info */ + ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + PAD, col_fg, "W: %f | H: %f", (float)screen.w, (float)screen.h); + ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + PAD * 2, col_fg, "Xoff: %f | Yoff: %f | km/px: %f", + view_main.kmx, view_main.kmy, view_main.kmperpx); + ui_print(GetScreenWidth() / 2, VIEWS_HEIGHT + PAD * 3, col_fg, "X: %f | Y: %f", + mousekm.x, mousekm.y); + 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]; + body->pxloc = kmtopx(body->vector); + draw_orbit(body); + } + for (i = 0; i < view_main.sys->bodies_len; i++) { + body = view_main.sys->bodies[i]; + draw_body(body); + } + + /* ruler */ + if (view_main.ruler.held) { + ruler = kmtopx(view_main.ruler.origin); + ui_draw_line_v(ruler, mouse, 1, col_info); + dist = ui_vectordist(view_main.ruler.origin, mousekm); + ui_print(mouse.x + PAD, mouse.y - PAD, col_info, "%s (%s)", strkmdist(dist), strlightdist(dist)); + } + + /* scale */ + ui_draw_rectangle(view_main.scale.x, + GetScreenHeight() - view_main.scale.y, + view_main.scale.w, 1, col_info); /* horizontal */ + ui_draw_rectangle(view_main.scale.x, + GetScreenHeight() - view_main.scale.y - view_main.scale.h, + 1, view_main.scale.h, col_info); /* left vertical */ + ui_draw_rectangle(view_main.scale.x + view_main.scale.w, + GetScreenHeight() - view_main.scale.y - view_main.scale.h, + 1, view_main.scale.h, col_info); /* right vertical */ + dist = view_main.scale.w * view_main.kmperpx; + ui_print(view_main.scale.x + view_main.scale.w + FONT_SIZE / 3, + GetScreenHeight() - view_main.scale.y - FONT_SIZE / 2, + col_info, "%s", strkmdist(dist)); + + /* infobox */ + ui_draw_tabbed_window(EXPLODE_RECT(view_main.infobox.geom.rect), + &view_main.infobox.tabs); + x = view_main.infobox.geom.rect.x + FONT_SIZE; + y = view_main.infobox.geom.rect.y + WINDOW_TAB_HEIGHT; + rect.x = x - FONT_SIZE; + rect.y = y; + rect.w = view_main.infobox.geom.rect.w - WINDOW_BORDER; + rect.h = view_main.infobox.geom.rect.h - WINDOW_TAB_HEIGHT - WINDOW_BORDER; + view_main.infobox.pane.geom = &rect; + + pane_begin(&view_main.infobox.pane); + ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.dwarf); + ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.dwarfn); + ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.asteroid); + ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.asteroidn); + ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.names.comet); + ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.dwarf); + ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.asteroid); + ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.orbit.comet); + ui_draw_checkbox(x, y += FONT_SIZE*1.5, &view_main.infobox.comettail); + pane_end(); +} diff --git a/src/ui/struct.h b/src/ui/struct.h @@ -0,0 +1,57 @@ +typedef struct { + struct { + Tabs tabs; + struct { + Checkbox dwarf; + Checkbox dwarfn; + Checkbox asteroid; + Checkbox asteroidn; + Checkbox comet; + } names; + struct { + Checkbox dwarf; + Checkbox asteroid; + Checkbox comet; + } orbit; + Checkbox comettail; + Geom geom; + Pane pane; + } infobox; + int pan; + struct { + int held; + Vector2 origin; + } ruler; + float kmx, kmy; + float kmperpx; + struct { + int x, y; /* real y = GetScreenHeight() - y */ + int w, h; + } scale; + System *sys; +} View_main; + +typedef struct { + System *sys; + Body *sel; + struct { + Checkbox planet; + Checkbox moon; + Checkbox dwarf; + Checkbox asteroid; + Checkbox comet; + Checkbox nomineral; + } show; + Pane stars; + Pane bodies; +} View_bodies; + +typedef struct { + struct { + Rect geom; + } info; + int pan; + Vector2 off; + float lytopx; + System *sel; +} View_sys; diff --git a/src/views.h b/src/views.h @@ -1,42 +0,0 @@ -typedef struct { - struct { - Tabs tabs; - struct { - Checkbox dwarf; - Checkbox dwarfn; - Checkbox asteroid; - Checkbox asteroidn; - Checkbox comet; - } names; - struct { - Checkbox dwarf; - Checkbox asteroid; - Checkbox comet; - } orbit; - Checkbox comettail; - Geom geom; - Pane pane; - } infobox; - int pan; - struct { - int held; - Vector2 origin; - } ruler; - float kmx, kmy; - float kmperpx; - struct { - int x, y; /* real y = GetScreenHeight() - y */ - int w, h; - } scale; - System *sys; -} View_main; - -typedef struct { - struct { - Rect geom; - } info; - int pan; - Vector2 off; - float lytopx; - System *sel; -} View_sys;