commit bca3d6ff114aada012dd6d4be435043af80121bd
parent c2108e03a95dd018b62128994f25652ebebfebe3
Author: hhvn <dev@hhvn.uk>
Date: Wed, 31 Aug 2022 20:57:45 +0100
Bodies view
Diffstat:
M | .gitignore | | | 1 | + |
M | src/main.c | | | 29 | ++++++----------------------- |
M | src/main.h | | | 48 | +++++++++++++++++++++++++++++++----------------- |
M | src/pane.c | | | 2 | +- |
M | src/struct.h | | | 38 | ++++++++++++++++++++++++++++++-------- |
M | src/system.c | | | 2 | +- |
M | src/ui.c | | | 367 | +++++++------------------------------------------------------------------------ |
A | src/ui/bodies.c | | | 134 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/ui/main.c | | | 293 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/ui/struct.h | | | 57 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | src/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 = ▭
-
- 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 = ▭
+
+ 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;