Mercurial > molko
view libmlk-adventure/adventure/dialog/save.c @ 316:1a6125ffebff
misc: fix many warnings and build on macOS
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 22 Sep 2021 12:57:55 +0200 |
parents | 3bfaaf5342a9 |
children |
line wrap: on
line source
/* * save.c -- select a save slot * * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <assert.h> #include <stdio.h> #include <string.h> #include <port/port.h> #include <core/event.h> #include <core/font.h> #include <core/maths.h> #include <core/painter.h> #include <core/sprite.h> #include <core/window.h> #include <ui/align.h> #include <ui/label.h> #include <ui/frame.h> #include <ui/theme.h> #include <adventure/adventure_p.h> #include <adventure/assets.h> #include "save.h" #define THEME(s) ((s)->theme ? (s)->theme : theme_default()) #define LINES_MAX (3) /* TODO: require a module for this*/ #define TEAM_MAX (4) struct geo { int x, y; unsigned int w, h; /* Per line height/padding. */ unsigned int lh; unsigned int lp; struct { int x, y; unsigned int w, h; /* Lines start positions. */ int lx, ly; struct { int x, y; unsigned int w, h; } faces[TEAM_MAX]; } saves[DIALOG_SAVE_MAX]; }; static struct geo geometry(const struct dialog_save *dlg) { struct geo geo = { .w = window.w - THEME(dlg)->padding * 40, .h = window.h - THEME(dlg)->padding * 10, }; align(ALIGN_CENTER, &geo.x, &geo.y, geo.w, geo.h, 0, 0, window.w, window.h); for (size_t i = 0; i < DIALOG_SAVE_MAX; ++i) { const unsigned int padding = THEME(dlg)->padding; geo.saves[i].w = (geo.w - padding * 2); geo.saves[i].h = (geo.h - (padding * (DIALOG_SAVE_MAX + 1))) / DIALOG_SAVE_MAX; geo.saves[i].x = (geo.x + padding); geo.saves[i].y = (geo.y + padding) + i * (padding + geo.saves[i].h); geo.saves[i].lx = (geo.saves[i].x + padding); /* Compute lines padding (we draw LINES_MAX lines). */ geo.lh = font_height(THEME(dlg)->fonts[THEME_FONT_INTERFACE]); geo.lp = (geo.saves[i].h - (geo.lh * LINES_MAX)) / (LINES_MAX + 1); /* Compute faces position. */ for (size_t f = 0; f < TEAM_MAX; ++f) { geo.saves[i].faces[f].h = geo.saves[i].h - padding * 2; geo.saves[i].faces[f].w = geo.saves[i].faces[f].h; geo.saves[i].faces[f].x = (geo.saves[i].x + padding) + (f * (padding + geo.saves[i].faces[f].w)); geo.saves[i].faces[f].y = (geo.saves[i].y + padding); geo.saves[i].lx += geo.saves[i].faces[f].w + padding; } geo.saves[i].ly = geo.saves[i].y + geo.lp; } return geo; } static void draw_frame(const struct geo *geo) { struct frame f = { .x = geo->x, .y = geo->y, .w = geo->w, .h = geo->h, }; frame_draw(&f); } static void draw_save_box(const struct geo *geo, size_t i) { /* TODO: change colors at some point. */ painter_set_color(0x884b2bff); painter_draw_rectangle(geo->saves[i].x, geo->saves[i].y, geo->saves[i].w, geo->saves[i].h); } static void draw_save_faces(const struct dialog_save *dlg, const struct geo *geo, size_t i) { (void)dlg; /* TODO: determine face. */ for (size_t f = 0; f < TEAM_MAX; ++f) { sprite_scale(&assets_sprites[ASSETS_SPRITE_FACES], 0, f, geo->saves[i].faces[f].x, geo->saves[i].faces[f].y, geo->saves[i].faces[f].w, geo->saves[i].faces[f].h ); } } static void draw_save_times(const struct dialog_save *dlg, const struct geo *geo, size_t i) { struct label label = {0}; char time[128], line[256]; label.theme = dlg->theme; label.x = geo->saves[i].lx; label.y = geo->saves[i].ly; label.flags = LABEL_FLAGS_SHADOW; label.text = line; /* TODO: Get map position. */ strlcpy(line, "World", sizeof (line)); label_draw(&label); /* Last time. */ strftime(time, sizeof (time), "%c", localtime(&dlg->saves[i].updated)); snprintf(line, sizeof (line), _("Last played: %s"), time); label.y += geo->lp + geo->lh; label_draw(&label); /* TODO: Time played. */ snprintf(line, sizeof (line), _("Time played: %s"), "100 hours"); label.y += geo->lp + geo->lh; label_draw(&label); } static void draw_save(const struct dialog_save *dlg, const struct geo *geo, size_t i) { draw_save_box(geo, i); /* Do not draw the content if save is invalid. */ if (!save_ok(&dlg->saves[i])) return; draw_save_faces(dlg, geo, i); draw_save_times(dlg, geo, i); } static void draw_saves(const struct dialog_save *dlg, const struct geo *geo) { for (size_t i = 0; i < DIALOG_SAVE_MAX; ++i) draw_save(dlg, geo, i); } static void draw_cursor(const struct dialog_save *dlg, const struct geo *geo) { const struct sprite *sprite = &assets_sprites[ASSETS_SPRITE_UI_CURSOR]; const int x = geo->saves[dlg->selected].x - sprite->cellw; const int y = geo->saves[dlg->selected].y; sprite_draw(sprite, 1, 2, x, y + (geo->saves[dlg->selected].h / 2) - (sprite->cellh / 2)); } static int handle_keydown(struct dialog_save *s, const struct event_key *key) { assert(key->type == EVENT_KEYDOWN); switch (key->key) { case KEY_UP: if (s->selected == 0) s->selected = DIALOG_SAVE_MAX - 1; else s->selected --; break; case KEY_DOWN: if (s->selected + 1 >= DIALOG_SAVE_MAX) s->selected = 0; else s->selected ++; break; case KEY_ENTER: return save_ok(&s->saves[s->selected]); default: break; } return 0; } static int handle_clickdown(struct dialog_save *s, const struct geo *geo, const struct event_click *clk) { assert(clk->type == EVENT_CLICKDOWN); for (size_t i = 0; i < DIALOG_SAVE_MAX; ++i) { if (maths_is_boxed(geo->saves[i].x, geo->saves[i].y, geo->saves[i].w, geo->saves[i].h, clk->x, clk->y)) { s->selected = i; break; } } return clk->clicks >= 2 && save_ok(&s->saves[s->selected]); } void dialog_save_init(struct dialog_save *s) { assert(s); for (size_t i = 0; i < DIALOG_SAVE_MAX; ++i) save_open(&s->saves[i], i, SAVE_MODE_READ); } int dialog_save_handle(struct dialog_save *dlg, const union event *ev) { assert(dlg); assert(ev); const struct geo geo = geometry(dlg); switch (ev->type) { case EVENT_KEYDOWN: return handle_keydown(dlg, &ev->key); case EVENT_CLICKDOWN: return handle_clickdown(dlg, &geo, &ev->click); default: break; } return 0; } void dialog_save_update(struct dialog_save *dlg, unsigned int ticks) { (void)ticks; (void)dlg; } void dialog_save_draw(const struct dialog_save *dlg) { assert(dlg); const struct geo geo = geometry(dlg); draw_frame(&geo); draw_saves(dlg, &geo); draw_cursor(dlg, &geo); } void dialog_save_finish(struct dialog_save *dlg) { assert(dlg); for (size_t i = 0; i < DIALOG_SAVE_MAX; ++i) save_finish(&dlg->saves[i]); }