Revamp gui component
`gui` was tighly coupled to game logic, and could not be extended for other purposes. Therefore, a generic GUI implementation, loosely inspired by well-known GUI frameworks such as GTK, is now provided, with the following properties: - Does not depend on dynamic or static memory allocation, only automatic (i.e., stack) memory allocation required. - Portable among existing implementations. - Simple to extend. - Tiny memory footprint. `gui` is now composed by GUI elements that can be chained to form a tree structure. This is useful e.g.: to calculate X/Y coordinates for a given GUI element given its parent(s). This commit also refactors the older implementation, moving game-specific logic into `player` and making use of the new component.
This commit is contained in:
parent
f17c76c400
commit
7c75118429
|
@ -34,7 +34,6 @@ add_subdirectory("res")
|
|||
|
||||
set(components
|
||||
building
|
||||
button
|
||||
camera
|
||||
container
|
||||
font
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
add_library(button "src/button.c")
|
||||
target_include_directories(button PUBLIC "inc")
|
||||
target_link_libraries(button PUBLIC gfx PRIVATE font)
|
|
@ -1,36 +0,0 @@
|
|||
#ifndef BUTTON_H
|
||||
#define BUTTON_H
|
||||
|
||||
#include <gfx.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
BUTTON_LEFT,
|
||||
BUTTON_MID,
|
||||
BUTTON_RIGHT,
|
||||
|
||||
MAX_BUTTON_SPRITES
|
||||
};
|
||||
|
||||
struct button
|
||||
{
|
||||
const char *text;
|
||||
short x, y, w;
|
||||
};
|
||||
|
||||
bool button_is_pressed(const struct button *b);
|
||||
int button_render(const struct button *b);
|
||||
|
||||
extern struct sprite button_sprites[MAX_BUTTON_SPRITES];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BUTTON_H */
|
|
@ -1,100 +0,0 @@
|
|||
#include <button.h>
|
||||
#include <font.h>
|
||||
#include <gfx.h>
|
||||
|
||||
struct sprite button_sprites[MAX_BUTTON_SPRITES];
|
||||
|
||||
bool button_is_pressed(const struct button *const b)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int render_left(const struct button *const b, short *const x)
|
||||
{
|
||||
sprite_get_or_ret(s, -1);
|
||||
|
||||
if (sprite_clone(&button_sprites[BUTTON_LEFT], s))
|
||||
return -1;
|
||||
|
||||
s->x = b->x;
|
||||
s->y = b->y;
|
||||
sprite_sort(s);
|
||||
*x = s->x + s->w;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_mid(const struct button *const b, short *const x)
|
||||
{
|
||||
const short mid_w = button_sprites[BUTTON_MID].w;
|
||||
const short lw = button_sprites[BUTTON_LEFT].w;
|
||||
const short rw = button_sprites[BUTTON_RIGHT].w;
|
||||
const short w = b->w - lw - rw;
|
||||
|
||||
if (w > 0)
|
||||
{
|
||||
const short rem_mid = w > 0 ? w % mid_w : 0;
|
||||
const short whole_mid = w / mid_w;
|
||||
const short n_mid = rem_mid ? whole_mid + 1 : whole_mid;
|
||||
|
||||
for (struct
|
||||
{
|
||||
size_t i;
|
||||
short x;
|
||||
} a = {.i = 0, .x = lw};
|
||||
a.i < n_mid;
|
||||
a.i++, a.x += mid_w)
|
||||
{
|
||||
sprite_get_or_ret(m, -1);
|
||||
|
||||
if (sprite_clone(&button_sprites[BUTTON_MID], m))
|
||||
return -1;
|
||||
|
||||
m->x = *x;
|
||||
m->y = b->y;
|
||||
|
||||
if (rem_mid && a.i + 1 == n_mid)
|
||||
m->w = rem_mid;
|
||||
else
|
||||
m->w = mid_w;
|
||||
|
||||
sprite_sort(m);
|
||||
*x += m->w;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_right(const struct button *const b, const short *const x)
|
||||
{
|
||||
sprite_get_or_ret(s, -1);
|
||||
|
||||
if (sprite_clone(&button_sprites[BUTTON_RIGHT], s))
|
||||
return -1;
|
||||
|
||||
s->x = *x;
|
||||
s->y = b->y;
|
||||
sprite_sort(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_text(const struct button *const b)
|
||||
{
|
||||
const short x = b->x + button_sprites[BUTTON_LEFT].w,
|
||||
y = b->y + (button_sprites[BUTTON_MID].h >> 2);
|
||||
|
||||
return font_printf(FONT, x, y, "%s", b->text) < 0;
|
||||
}
|
||||
|
||||
int button_render(const struct button *const b)
|
||||
{
|
||||
short x;
|
||||
|
||||
if (render_left(b, &x)
|
||||
|| render_mid(b, &x)
|
||||
|| render_right(b, &x)
|
||||
|| render_text(b))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -2,7 +2,6 @@ add_library(game "src/game.c" "src/res.c")
|
|||
target_include_directories(game PUBLIC "inc" PRIVATE "privinc")
|
||||
target_link_libraries(game PRIVATE
|
||||
building
|
||||
button
|
||||
container
|
||||
font
|
||||
gfx
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include <game_private.h>
|
||||
#include <building.h>
|
||||
#include <button.h>
|
||||
#include <container.h>
|
||||
#include <font.h>
|
||||
#include <gfx.h>
|
||||
#include <gui.h>
|
||||
#include <gui/bar.h>
|
||||
#include <gui/button.h>
|
||||
#include <gui/rounded_rect.h>
|
||||
#include <resource.h>
|
||||
#include <terrain.h>
|
||||
#include <unit.h>
|
||||
|
@ -89,7 +90,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_sprites[GUI_BAR_LEFT]
|
||||
.sprite = &gui_bar_sprites[GUI_BAR_LEFT]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -98,7 +99,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_sprites[GUI_BAR_MID]
|
||||
.sprite = &gui_bar_sprites[GUI_BAR_MID]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -107,7 +108,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_sprites[GUI_BAR_RIGHT]
|
||||
.sprite = &gui_bar_sprites[GUI_BAR_RIGHT]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -116,7 +117,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_sprites[GUI_SELECTION_UP_LEFT]
|
||||
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_UP_LEFT]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -125,7 +126,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_sprites[GUI_SELECTION_UP_RIGHT]
|
||||
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_UP_RIGHT]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -134,7 +135,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_sprites[GUI_SELECTION_DOWN_LEFT]
|
||||
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_DOWN_LEFT]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -143,7 +144,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_sprites[GUI_SELECTION_DOWN_RIGHT]
|
||||
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_DOWN_RIGHT]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -152,7 +153,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_sprites[GUI_SELECTION_MID]
|
||||
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_MID]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -161,7 +162,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &gui_sprites[GUI_SELECTION_MID_VERT]
|
||||
.sprite = &gui_rounded_rect_sprites[GUI_ROUNDED_RECT_MID_VERT]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -224,7 +225,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &button_sprites[BUTTON_LEFT]
|
||||
.sprite = &gui_button_sprites[GUI_BUTTON_LEFT]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -233,7 +234,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &button_sprites[BUTTON_MID]
|
||||
.sprite = &gui_button_sprites[GUI_BUTTON_MID]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -242,7 +243,7 @@ static const struct container c[] =
|
|||
.type = CONTAINER_TYPE_SPRITE,
|
||||
.data =
|
||||
{
|
||||
.sprite = &button_sprites[BUTTON_RIGHT]
|
||||
.sprite = &gui_button_sprites[GUI_BUTTON_RIGHT]
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
add_library(gui "src/gui.c")
|
||||
target_include_directories(gui PUBLIC "inc")
|
||||
target_link_libraries(gui PUBLIC gfx player PRIVATE font unit building)
|
||||
add_library(gui
|
||||
"src/bar.c"
|
||||
"src/button.c"
|
||||
"src/gui.c"
|
||||
"src/label.c"
|
||||
"src/progress_bar.c"
|
||||
"src/rounded_rect.c"
|
||||
)
|
||||
target_include_directories(gui PUBLIC "inc" PRIVATE "privinc")
|
||||
target_link_libraries(gui PUBLIC camera gfx peripheral font)
|
||||
|
|
|
@ -1,33 +1,30 @@
|
|||
#ifndef GUI_H
|
||||
#define GUI_H
|
||||
|
||||
#include <camera.h>
|
||||
#include <gfx.h>
|
||||
#include <human_player.h>
|
||||
#include <peripheral.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
enum
|
||||
struct gui_common
|
||||
{
|
||||
GUI_BAR_LEFT,
|
||||
GUI_BAR_MID,
|
||||
GUI_BAR_RIGHT,
|
||||
GUI_SELECTION_UP_LEFT,
|
||||
GUI_SELECTION_UP_RIGHT,
|
||||
GUI_SELECTION_MID_VERT,
|
||||
GUI_SELECTION_DOWN_LEFT,
|
||||
GUI_SELECTION_DOWN_RIGHT,
|
||||
GUI_SELECTION_MID,
|
||||
|
||||
MAX_GUI_SPRITES
|
||||
int (*update)(struct gui_common *, const union peripheral *,
|
||||
const struct camera *);
|
||||
int (*render)(const struct gui_common *);
|
||||
short x, y;
|
||||
bool centered;
|
||||
struct gui_common *parent, *child, *sibling;
|
||||
};
|
||||
|
||||
void gui_update(struct human_player *h);
|
||||
int gui_render(const struct human_player *h);
|
||||
|
||||
extern struct sprite gui_sprites[MAX_GUI_SPRITES];
|
||||
void gui_add_child(struct gui_common *parent, struct gui_common *child);
|
||||
void gui_add_sibling(struct gui_common *g, struct gui_common *sibling);
|
||||
int gui_update(struct gui_common *g, const union peripheral *p,
|
||||
const struct camera *c);
|
||||
int gui_render(const struct gui_common *g);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef GUI_BAR_H
|
||||
#define GUI_BAR_H
|
||||
|
||||
#include <gui.h>
|
||||
#include <gfx.h>
|
||||
#include <util.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct gui_bar
|
||||
{
|
||||
struct gui_common common;
|
||||
};
|
||||
|
||||
UTIL_STATIC_ASSERT(!offsetof(struct gui_bar, common),
|
||||
"unexpected offset for struct gui_bar");
|
||||
|
||||
void gui_bar_init(struct gui_bar *b);
|
||||
|
||||
enum
|
||||
{
|
||||
GUI_BAR_LEFT,
|
||||
GUI_BAR_MID,
|
||||
GUI_BAR_RIGHT,
|
||||
|
||||
MAX_GUI_BAR_SPRITES
|
||||
};
|
||||
|
||||
extern struct sprite gui_bar_sprites[MAX_GUI_BAR_SPRITES];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GUI_BAR_H */
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef GUI_BUTTON_H
|
||||
#define GUI_BUTTON_H
|
||||
|
||||
#include <gfx.h>
|
||||
#include <gui.h>
|
||||
#include <gui/label.h>
|
||||
#include <util.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct gui_button
|
||||
{
|
||||
struct gui_common common;
|
||||
struct gui_label label;
|
||||
short w;
|
||||
void *arg;
|
||||
void (*on_pressed)(void *);
|
||||
};
|
||||
|
||||
UTIL_STATIC_ASSERT(!offsetof(struct gui_button, common),
|
||||
"unexpected offset for struct gui_button");
|
||||
|
||||
void gui_button_init(struct gui_button *b);
|
||||
|
||||
enum
|
||||
{
|
||||
GUI_BUTTON_LEFT,
|
||||
GUI_BUTTON_MID,
|
||||
GUI_BUTTON_RIGHT,
|
||||
|
||||
MAX_GUI_BUTTON_SPRITES
|
||||
};
|
||||
|
||||
extern struct sprite gui_button_sprites[MAX_GUI_BUTTON_SPRITES];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GUI_BUTTON_H */
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef GUI_LABEL_H
|
||||
#define GUI_LABEL_H
|
||||
|
||||
#include <gui.h>
|
||||
#include <font.h>
|
||||
#include <util.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct gui_label
|
||||
{
|
||||
struct gui_common common;
|
||||
enum font font;
|
||||
const char *text;
|
||||
};
|
||||
|
||||
UTIL_STATIC_ASSERT(!offsetof(struct gui_label, common),
|
||||
"unexpected offset for struct gui_label");
|
||||
|
||||
void gui_label_init(struct gui_label *l);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GUI_LABEL_H */
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef GUI_PROGRESS_BAR_H
|
||||
#define GUI_PROGRESS_BAR_H
|
||||
|
||||
#include <gui.h>
|
||||
#include <util.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
enum {GUI_PROGRESS_BAR_MAX = 255};
|
||||
|
||||
struct gui_progress_bar
|
||||
{
|
||||
struct gui_common common;
|
||||
short w, h;
|
||||
bool stp;
|
||||
unsigned char progress;
|
||||
struct
|
||||
{
|
||||
unsigned char r, g, b;
|
||||
} fg, bg;
|
||||
};
|
||||
|
||||
UTIL_STATIC_ASSERT(!offsetof(struct gui_progress_bar, common),
|
||||
"unexpected offset for struct gui_progress_bar");
|
||||
|
||||
void gui_progress_bar_init(struct gui_progress_bar *pb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GUI_PROGRESS_BAR_H */
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef GUI_ROUNDED_RECT_H
|
||||
#define GUI_ROUNDED_RECT_H
|
||||
|
||||
#include <gui.h>
|
||||
#include <gfx.h>
|
||||
#include <util.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct gui_rounded_rect
|
||||
{
|
||||
struct gui_common common;
|
||||
unsigned short w, h;
|
||||
};
|
||||
|
||||
UTIL_STATIC_ASSERT(!offsetof(struct gui_rounded_rect, common),
|
||||
"unexpected offset for struct gui_rounded_rect");
|
||||
|
||||
void gui_rounded_rect_init(struct gui_rounded_rect *l);
|
||||
|
||||
enum
|
||||
{
|
||||
GUI_ROUNDED_RECT_UP_LEFT,
|
||||
GUI_ROUNDED_RECT_UP_RIGHT,
|
||||
GUI_ROUNDED_RECT_MID_VERT,
|
||||
GUI_ROUNDED_RECT_DOWN_LEFT,
|
||||
GUI_ROUNDED_RECT_DOWN_RIGHT,
|
||||
GUI_ROUNDED_RECT_MID,
|
||||
|
||||
MAX_GUI_ROUNDED_RECT_SPRITES
|
||||
};
|
||||
|
||||
extern struct sprite gui_rounded_rect_sprites[MAX_GUI_ROUNDED_RECT_SPRITES];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GUI_ROUNDED_RECT_H */
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef GUI_PRIVATE_H
|
||||
#define GUI_PRIVATE_H
|
||||
|
||||
#include <gui.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void gui_coords(const struct gui_common *g, short *x, short *y);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GUI_PRIVATE_H */
|
|
@ -0,0 +1,84 @@
|
|||
#include <gui/bar.h>
|
||||
#include <gui.h>
|
||||
#include <gfx.h>
|
||||
|
||||
struct sprite gui_bar_sprites[MAX_GUI_BAR_SPRITES];
|
||||
|
||||
static int render_topleft(void)
|
||||
{
|
||||
sprite_get_or_ret(s, -1);
|
||||
|
||||
if (sprite_clone(&gui_bar_sprites[GUI_BAR_LEFT], s))
|
||||
return -1;
|
||||
|
||||
sprite_sort(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_topright(void)
|
||||
{
|
||||
sprite_get_or_ret(s, -1);
|
||||
|
||||
if (sprite_clone(&gui_bar_sprites[GUI_BAR_RIGHT], s))
|
||||
return -1;
|
||||
|
||||
s->x = screen_w - s->w;
|
||||
sprite_sort(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_topmid(void)
|
||||
{
|
||||
const uint16_t mid_w = gui_bar_sprites[GUI_BAR_MID].w;
|
||||
const uint16_t lw = gui_bar_sprites[GUI_BAR_LEFT].w;
|
||||
const size_t w = screen_w - lw - lw;
|
||||
const size_t rem_mid = w % mid_w;
|
||||
const size_t whole_mid = w / mid_w;
|
||||
const size_t n_mid = rem_mid ? whole_mid + 1 : whole_mid;
|
||||
|
||||
for (struct
|
||||
{
|
||||
size_t i;
|
||||
short x;
|
||||
} a = {.i = 0, .x = lw};
|
||||
a.i < n_mid;
|
||||
a.i++, a.x += mid_w)
|
||||
{
|
||||
sprite_get_or_ret(m, -1);
|
||||
|
||||
if (sprite_clone(&gui_bar_sprites[GUI_BAR_MID], m))
|
||||
return -1;
|
||||
|
||||
m->x = a.x;
|
||||
|
||||
if (rem_mid && a.i + 1 == n_mid)
|
||||
m->w = rem_mid;
|
||||
else
|
||||
m->w = mid_w;
|
||||
|
||||
sprite_sort(m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render(const struct gui_common *const g)
|
||||
{
|
||||
if (render_topleft()
|
||||
|| render_topright()
|
||||
|| render_topmid())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gui_bar_init(struct gui_bar *const b)
|
||||
{
|
||||
*b = (const struct gui_bar)
|
||||
{
|
||||
.common =
|
||||
{
|
||||
.render = render
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
#include <gui.h>
|
||||
#include <gui/button.h>
|
||||
#include <gui_private.h>
|
||||
#include <camera.h>
|
||||
#include <gfx.h>
|
||||
#include <mouse.h>
|
||||
#include <pad.h>
|
||||
#include <peripheral.h>
|
||||
|
||||
struct sprite gui_button_sprites[MAX_GUI_BUTTON_SPRITES];
|
||||
|
||||
/* Alias for readability. */
|
||||
static const struct sprite *const refs = gui_button_sprites;
|
||||
|
||||
static int render_left(const struct gui_button *const b,
|
||||
short *const x, const short y)
|
||||
{
|
||||
sprite_get_or_ret(s, -1);
|
||||
|
||||
if (sprite_clone(&refs[GUI_BUTTON_LEFT], s))
|
||||
return -1;
|
||||
|
||||
s->x = *x;
|
||||
s->y = y;
|
||||
sprite_sort(s);
|
||||
*x = s->x + s->w;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_mid(const struct gui_button *const b,
|
||||
short *const x, const short y)
|
||||
{
|
||||
const short mid_w = refs[GUI_BUTTON_MID].w;
|
||||
const short lw = refs[GUI_BUTTON_LEFT].w;
|
||||
const short rw = refs[GUI_BUTTON_RIGHT].w;
|
||||
const short w = b->w - lw - rw;
|
||||
|
||||
if (w > 0)
|
||||
{
|
||||
const short rem_mid = w > 0 ? w % mid_w : 0;
|
||||
const short whole_mid = w / mid_w;
|
||||
const short n_mid = rem_mid ? whole_mid + 1 : whole_mid;
|
||||
|
||||
for (struct
|
||||
{
|
||||
size_t i;
|
||||
short x;
|
||||
} a = {.x = lw};
|
||||
a.i < n_mid;
|
||||
a.i++, a.x += mid_w)
|
||||
{
|
||||
sprite_get_or_ret(m, -1);
|
||||
|
||||
if (sprite_clone(&refs[GUI_BUTTON_MID], m))
|
||||
return -1;
|
||||
|
||||
m->x = *x;
|
||||
m->y = y;
|
||||
|
||||
if (rem_mid && a.i + 1 == n_mid)
|
||||
m->w = rem_mid;
|
||||
else
|
||||
m->w = mid_w;
|
||||
|
||||
sprite_sort(m);
|
||||
*x += m->w;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_right(const struct gui_button *const b,
|
||||
const short x, const short y)
|
||||
{
|
||||
sprite_get_or_ret(s, -1);
|
||||
|
||||
if (sprite_clone(&refs[GUI_BUTTON_RIGHT], s))
|
||||
return -1;
|
||||
|
||||
s->x = x;
|
||||
s->y = y;
|
||||
sprite_sort(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render(const struct gui_common *const g)
|
||||
{
|
||||
const struct gui_button *const b = (const struct gui_button *)g;
|
||||
short x, y;
|
||||
|
||||
gui_coords(&b->common, &x, &y);
|
||||
|
||||
if (render_left(b, &x, y)
|
||||
|| render_mid(b, &x, y)
|
||||
|| render_right(b, x, y))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool pressed(const struct gui_button *const b,
|
||||
const union peripheral *const p,
|
||||
const struct camera *const cam)
|
||||
{
|
||||
bool check = false;
|
||||
|
||||
switch (p->common.type)
|
||||
{
|
||||
case PERIPHERAL_TYPE_PAD:
|
||||
check = pad_pressed(&p->pad.pad, PAD_KEY_A);
|
||||
break;
|
||||
|
||||
case PERIPHERAL_TYPE_KEYBOARD_MOUSE:
|
||||
check = mouse_justreleased(&p->kbm.mouse, MOUSE_BUTTON_LEFT);
|
||||
break;
|
||||
|
||||
case PERIPHERAL_TYPE_TOUCH:
|
||||
check = mouse_justpressed(&p->kbm.mouse, MOUSE_BUTTON_LEFT);
|
||||
break;
|
||||
}
|
||||
|
||||
if (check)
|
||||
{
|
||||
short x, y;
|
||||
|
||||
gui_coords(&b->common, &x, &y);
|
||||
|
||||
const struct util_rect d =
|
||||
{
|
||||
.x = x,
|
||||
.y = y,
|
||||
.w = b->w,
|
||||
.h = refs[GUI_BUTTON_LEFT].h
|
||||
};
|
||||
|
||||
return cursor_collision(cam, &d);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int update(struct gui_common *const g,
|
||||
const union peripheral *const p, const struct camera *const c)
|
||||
{
|
||||
struct gui_button *const b = (struct gui_button *)g;
|
||||
|
||||
if (pressed(b, p, c) && b->on_pressed)
|
||||
b->on_pressed(b->arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gui_button_init(struct gui_button *const b)
|
||||
{
|
||||
*b = (const struct gui_button)
|
||||
{
|
||||
.common =
|
||||
{
|
||||
.update = update,
|
||||
.render = render
|
||||
}
|
||||
};
|
||||
|
||||
gui_label_init(&b->label);
|
||||
gui_add_child(&b->common, &b->label.common);
|
||||
}
|
|
@ -1,452 +1,67 @@
|
|||
#include <gui.h>
|
||||
#include <building.h>
|
||||
#include <font.h>
|
||||
#include <gfx.h>
|
||||
#include <human_player.h>
|
||||
#include <player.h>
|
||||
#include <unit.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct sprite gui_sprites[MAX_GUI_SPRITES];
|
||||
|
||||
static int render_topleft(void)
|
||||
void gui_coords(const struct gui_common *const g, short *const x,
|
||||
short *const y)
|
||||
{
|
||||
sprite_get_or_ret(s, -1);
|
||||
*x = g->x;
|
||||
*y = g->y;
|
||||
|
||||
if (sprite_clone(&gui_sprites[GUI_BAR_LEFT], s))
|
||||
return -1;
|
||||
|
||||
sprite_sort(s);
|
||||
return 0;
|
||||
for (const struct gui_common *p = g->parent; p; p = p->parent)
|
||||
{
|
||||
*x += p->x;
|
||||
*y += p->y;
|
||||
}
|
||||
}
|
||||
|
||||
static int render_topright(void)
|
||||
void gui_add_sibling(struct gui_common *const g,
|
||||
struct gui_common *const s)
|
||||
{
|
||||
sprite_get_or_ret(s, -1);
|
||||
|
||||
if (sprite_clone(&gui_sprites[GUI_BAR_RIGHT], s))
|
||||
return -1;
|
||||
|
||||
s->x = screen_w - s->w;
|
||||
sprite_sort(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_topmid(void)
|
||||
{
|
||||
const uint16_t mid_w = gui_sprites[GUI_BAR_MID].w;
|
||||
const uint16_t lw = gui_sprites[GUI_BAR_LEFT].w;
|
||||
const size_t w = screen_w - lw - lw;
|
||||
const size_t rem_mid = w % mid_w;
|
||||
const size_t whole_mid = w / mid_w;
|
||||
const size_t n_mid = rem_mid ? whole_mid + 1 : whole_mid;
|
||||
|
||||
for (struct
|
||||
for (struct gui_common *c = g; c; c = c->sibling)
|
||||
if (!c->sibling)
|
||||
{
|
||||
size_t i;
|
||||
short x;
|
||||
} a = {.i = 0, .x = lw};
|
||||
a.i < n_mid;
|
||||
a.i++, a.x += mid_w)
|
||||
{
|
||||
sprite_get_or_ret(m, -1);
|
||||
|
||||
if (sprite_clone(&gui_sprites[GUI_BAR_MID], m))
|
||||
return -1;
|
||||
|
||||
m->x = a.x;
|
||||
|
||||
if (rem_mid && a.i + 1 == n_mid)
|
||||
m->w = rem_mid;
|
||||
else
|
||||
m->w = mid_w;
|
||||
|
||||
sprite_sort(m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_top(void)
|
||||
{
|
||||
if (render_topleft()
|
||||
|| render_topright()
|
||||
|| render_topmid())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_seltop(struct sprite *const up)
|
||||
{
|
||||
enum {OFFSET = 48};
|
||||
|
||||
if (sprite_clone(&gui_sprites[GUI_SELECTION_UP_LEFT], up))
|
||||
return -1;
|
||||
|
||||
up->y = screen_h - up->h - OFFSET;
|
||||
up->x = 16;
|
||||
sprite_sort(up);
|
||||
|
||||
sprite_get_or_ret(right, -1);
|
||||
|
||||
if (sprite_clone(&gui_sprites[GUI_SELECTION_UP_RIGHT], right))
|
||||
return -1;
|
||||
|
||||
right->x = screen_w - right->w - up->x;
|
||||
right->y = up->y;
|
||||
sprite_sort(right);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_selvert(const struct sprite *const up, const short x)
|
||||
{
|
||||
const uint16_t vert_h = gui_sprites[GUI_SELECTION_MID_VERT].h;
|
||||
const size_t h = screen_h - up->y - up->h - up->h;
|
||||
const size_t rem_vert = h % vert_h;
|
||||
const size_t whole_vert = h / vert_h;
|
||||
const size_t n_vert = rem_vert ? whole_vert + 1 : whole_vert;
|
||||
|
||||
for (struct
|
||||
{
|
||||
size_t i;
|
||||
short y;
|
||||
} a = {.i = 0, .y = up->y + up->h};
|
||||
a.i < n_vert;
|
||||
a.i++, a.y += vert_h)
|
||||
{
|
||||
sprite_get_or_ret(v, -1);
|
||||
|
||||
if (sprite_clone(&gui_sprites[GUI_SELECTION_MID_VERT], v))
|
||||
return -1;
|
||||
|
||||
v->y = a.y;
|
||||
v->x = x;
|
||||
|
||||
if (rem_vert && a.i + 1 == n_vert)
|
||||
v->h = rem_vert;
|
||||
else
|
||||
v->h = vert_h;
|
||||
|
||||
sprite_sort(v);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_selvertleft(const struct sprite *const up)
|
||||
{
|
||||
return render_selvert(up, up->x);
|
||||
}
|
||||
|
||||
static int render_selvertright(const struct sprite *const up)
|
||||
{
|
||||
return render_selvert(up, screen_w - gui_sprites[GUI_SELECTION_MID_VERT].w - up->x);
|
||||
}
|
||||
|
||||
static int render_seldown(const struct sprite *const up)
|
||||
{
|
||||
{
|
||||
sprite_get_or_ret(left, -1);
|
||||
|
||||
if (sprite_clone(&gui_sprites[GUI_SELECTION_DOWN_LEFT], left))
|
||||
return -1;
|
||||
|
||||
left->x = up->x;
|
||||
left->y = screen_h - left->h;
|
||||
sprite_sort(left);
|
||||
}
|
||||
|
||||
{
|
||||
sprite_get_or_ret(right, -1);
|
||||
|
||||
if (sprite_clone(&gui_sprites[GUI_SELECTION_DOWN_RIGHT], right))
|
||||
return -1;
|
||||
|
||||
right->x = screen_w - right->w - up->x;
|
||||
right->y = screen_h - right->h;
|
||||
sprite_sort(right);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_selrect(const struct sprite *const up)
|
||||
{
|
||||
rect_get_or_ret(sel, -1);
|
||||
semitrans_rect_init(sel);
|
||||
|
||||
const struct sprite *const mid = &gui_sprites[GUI_SELECTION_MID],
|
||||
*const vert = &gui_sprites[GUI_SELECTION_MID_VERT];
|
||||
sel->x = up->x + vert->w;
|
||||
sel->y = up->y + mid->h;
|
||||
sel->w = screen_w - sel->x - vert->w - up->x;
|
||||
sel->h = screen_h - sel->y - mid->h;
|
||||
sel->r = 72;
|
||||
sel->g = 66;
|
||||
sel->b = 56;
|
||||
rect_sort(sel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_selmid(const struct sprite *const up, const short y)
|
||||
{
|
||||
const uint16_t mid_w = gui_sprites[GUI_SELECTION_MID].w;
|
||||
const size_t w = screen_w - up->x - up->x - up->w - up->w;
|
||||
const size_t rem_mid = w % mid_w;
|
||||
const size_t whole_mid = w / mid_w;
|
||||
const size_t n_mid = rem_mid ? whole_mid + 1 : whole_mid;
|
||||
|
||||
for (struct
|
||||
{
|
||||
size_t i;
|
||||
short x;
|
||||
} a = {.i = 0, .x = up->x + up->w};
|
||||
a.i < n_mid;
|
||||
a.i++, a.x += mid_w)
|
||||
{
|
||||
sprite_get_or_ret(m, -1);
|
||||
*m = gui_sprites[GUI_SELECTION_MID];
|
||||
m->x = a.x;
|
||||
m->y = y;
|
||||
|
||||
if (rem_mid && a.i + 1 == n_mid)
|
||||
m->w = rem_mid;
|
||||
else
|
||||
m->w = mid_w;
|
||||
|
||||
sprite_sort(m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_selmidtop(const struct sprite *const up)
|
||||
{
|
||||
return render_selmid(up, up->y);
|
||||
}
|
||||
|
||||
static int render_selmiddown(const struct sprite *const up)
|
||||
{
|
||||
return render_selmid(up, screen_h - gui_sprites[GUI_SELECTION_MID].h);
|
||||
}
|
||||
|
||||
static int render_topmenu(const struct human_player *const h)
|
||||
{
|
||||
const struct player *const pl = &h->pl;
|
||||
|
||||
if (render_top()
|
||||
|| (font_printf(FONT, 16, 6, "Wood=%u",
|
||||
h->gui_res[RESOURCE_TYPE_WOOD]) < 0)
|
||||
|| (font_printf(FONT, 108, 6, "Gold=%u",
|
||||
h->gui_res[RESOURCE_TYPE_GOLD]) < 0)
|
||||
|| (font_printf(FONT, 212, 6, "Pop.=%u/%zu",
|
||||
pl->pop, sizeof pl->units / sizeof *pl->units) < 0))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_hp(const struct instance *const i, const short x, const short y,
|
||||
const instance_hp max_hp)
|
||||
{
|
||||
enum {OFFSET = 4, WIDTH = 64, HEIGHT = 4};
|
||||
const short ry = y - OFFSET - HEIGHT;
|
||||
|
||||
if (ry < 0)
|
||||
return 0;
|
||||
|
||||
const short gw = (WIDTH * i->hp) / max_hp;
|
||||
|
||||
{
|
||||
rect_get_or_ret(gr, -1);
|
||||
semitrans_rect_init(gr);
|
||||
gr->x = x;
|
||||
gr->y = ry;
|
||||
gr->w = gw;
|
||||
gr->h = HEIGHT;
|
||||
gr->g = UCHAR_MAX >> 1;
|
||||
rect_sort(gr);
|
||||
}
|
||||
|
||||
{
|
||||
rect_get_or_ret(rr, -1);
|
||||
semitrans_rect_init(rr);
|
||||
rr->x = x + gw;
|
||||
rr->y = ry;
|
||||
rr->w = WIDTH - gw;
|
||||
rr->h = HEIGHT;
|
||||
rr->r = UCHAR_MAX >> 1;
|
||||
rect_sort(rr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_miners(const struct resource *const r)
|
||||
{
|
||||
const struct resource_gold *const g = &r->res.gold;
|
||||
|
||||
if (!g->n_miners)
|
||||
return 0;
|
||||
|
||||
for (size_t i = 0, n = 0; i < sizeof g->miners / sizeof *g->miners; i++)
|
||||
{
|
||||
if (g->miners[i])
|
||||
{
|
||||
enum {OFFSET = 112, SZ = 16, GAP = 4};
|
||||
|
||||
rect_get_or_ret(r, -1);
|
||||
semitrans_rect_init(r);
|
||||
r->x = OFFSET + n * (SZ + GAP);
|
||||
r->y = screen_h - 40;
|
||||
r->r = r->g = r->b = 127;
|
||||
r->w = r->h = SZ;
|
||||
rect_sort(r);
|
||||
|
||||
if (++n >= g->n_miners)
|
||||
break;
|
||||
c->sibling = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_carry(const enum font f, const short x, const short y,
|
||||
const struct unit *const u)
|
||||
void gui_add_child(struct gui_common *const p,
|
||||
struct gui_common *const c)
|
||||
{
|
||||
if (unit_can_harvest(u))
|
||||
{
|
||||
const struct unit_harvester *const uh = &u->us.harvester;
|
||||
if (p->child)
|
||||
gui_add_sibling(p->child, c);
|
||||
else
|
||||
p->child = c;
|
||||
|
||||
if (uh->carry)
|
||||
return font_printf(f, x, y, "%d", uh->carry) < 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
c->parent = p;
|
||||
}
|
||||
|
||||
static int render_selsingle(const struct sprite *const up,
|
||||
const struct human_player *const h)
|
||||
int gui_update(struct gui_common *const g, const union peripheral *const p,
|
||||
const struct camera *const c)
|
||||
{
|
||||
enum {X_OFF = 8, Y_OFF = 8, HP_Y = 32};
|
||||
const short x = up->x + X_OFF, y = up->y + Y_OFF;
|
||||
|
||||
for (size_t i = 0; i < sizeof h->sel / sizeof *h->sel; i++)
|
||||
{
|
||||
const struct sel_instance *const sel = &h->sel[i];
|
||||
|
||||
if (sel)
|
||||
{
|
||||
switch (sel->type)
|
||||
{
|
||||
case INSTANCE_TYPE_BUILDING:
|
||||
{
|
||||
const struct building *const b = sel->d.b;
|
||||
const struct instance *const in = &b->instance;
|
||||
const instance_hp hp = in->hp, max_hp = building_maxhp(b);
|
||||
|
||||
if ((font_printf(FONT, x, y, "%s", building_str(b)) < 0)
|
||||
|| (font_printf(FONT, x, y + HP_Y, "%u/%u", hp, max_hp) < 0)
|
||||
|| draw_hp(in, x, y + HP_Y - 4, max_hp))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case INSTANCE_TYPE_UNIT:
|
||||
{
|
||||
const struct unit *const u = sel->d.u;
|
||||
const struct instance *const in = &u->instance;
|
||||
const instance_hp hp = in->hp, max_hp = unit_maxhp(u);
|
||||
enum {CARRY_X = 96, CARRY_Y = 8};
|
||||
|
||||
if ((font_printf(FONT, x, y, "%s", unit_str(u)) < 0)
|
||||
|| (font_printf(FONT, x, y + HP_Y, "%u/%u", hp, max_hp) < 0)
|
||||
|| draw_carry(FONT, x + CARRY_X, y, u)
|
||||
|| draw_hp(in, x, y + HP_Y - 4, max_hp))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case INSTANCE_TYPE_RESOURCE:
|
||||
{
|
||||
const struct resource *const r = sel->d.r;
|
||||
const struct instance *const in = &r->instance;
|
||||
const instance_hp hp = in->hp, max_hp = resource_maxhp(r);
|
||||
|
||||
if ((font_printf(FONT, x, y, "%s", resource_str(r)) < 0)
|
||||
|| (font_printf(FONT, x, y + HP_Y, "%u/%u", hp, max_hp) < 0)
|
||||
|| draw_hp(in, x, y + HP_Y - 4, max_hp)
|
||||
|| (r->type == RESOURCE_TYPE_GOLD && draw_miners(r)))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unreachable. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int render_selinfo(const struct sprite *const up,
|
||||
const struct human_player *const h)
|
||||
{
|
||||
enum {X_OFF = 8, Y_OFF = 8};
|
||||
|
||||
if (h->n_sel == 1)
|
||||
return render_selsingle(up, h);
|
||||
else if (font_printf(FONT, up->x + X_OFF, up->y + Y_OFF,
|
||||
"%u units selected", h->n_sel) < 0)
|
||||
if (g->update && g->update(g, p, c))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_sel(const struct human_player *const h)
|
||||
{
|
||||
sprite_get_or_ret(up, -1);
|
||||
|
||||
if (render_seltop(up)
|
||||
|| render_selrect(up)
|
||||
|| render_selmidtop(up)
|
||||
|| render_selmiddown(up)
|
||||
|| render_selvertleft(up)
|
||||
|| render_selvertright(up)
|
||||
|| render_seldown(up)
|
||||
|| render_selinfo(up, h))
|
||||
if (g->child && gui_update(g->child, p, c))
|
||||
return -1;
|
||||
|
||||
for (struct gui_common *s = g->sibling; s; s = s->sibling)
|
||||
if (gui_update(s, p, c))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gui_update(struct human_player *const h)
|
||||
int gui_render(const struct gui_common *const g)
|
||||
{
|
||||
struct player *const pl = &h->pl;
|
||||
|
||||
for (size_t i = 0; i < sizeof pl->resources / sizeof *pl->resources; i++)
|
||||
{
|
||||
if (h->gui_res[i] > pl->resources[i])
|
||||
h->gui_res[i]--;
|
||||
else if (h->gui_res[i] < pl->resources[i])
|
||||
h->gui_res[i]++;
|
||||
}
|
||||
}
|
||||
|
||||
int gui_render(const struct human_player *const h)
|
||||
{
|
||||
if ((h->top_gui && render_topmenu(h))
|
||||
|| (h->n_sel && render_sel(h)))
|
||||
if (g->render && g->render(g))
|
||||
return -1;
|
||||
|
||||
if (g->child && gui_render(g->child))
|
||||
return -1;
|
||||
|
||||
for (struct gui_common *s = g->sibling; s; s = s->sibling)
|
||||
if (gui_render(s))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#include <gui/label.h>
|
||||
#include <gui.h>
|
||||
#include <gui_private.h>
|
||||
#include <font.h>
|
||||
|
||||
static int render(const struct gui_common *const g)
|
||||
{
|
||||
const struct gui_label *const l = (const struct gui_label *)g;
|
||||
short x, y;
|
||||
|
||||
gui_coords(g, &x, &y);
|
||||
|
||||
return l->text ? font_puts(l->font, x, y, l->text) : -1;
|
||||
}
|
||||
|
||||
void gui_label_init(struct gui_label *const l)
|
||||
{
|
||||
*l = (const struct gui_label)
|
||||
{
|
||||
.common =
|
||||
{
|
||||
.render = render
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
#include <gui/progress_bar.h>
|
||||
#include <gui.h>
|
||||
#include <gui_private.h>
|
||||
#include <gfx.h>
|
||||
|
||||
static short progress_width(const struct gui_progress_bar *const pb)
|
||||
{
|
||||
return pb->progress ? ((short)pb->progress * pb->w)
|
||||
/ (short)GUI_PROGRESS_BAR_MAX : 0;
|
||||
}
|
||||
|
||||
static void set_fg_params(const struct gui_progress_bar *const pb,
|
||||
struct rect *const r, const short x, const short y)
|
||||
{
|
||||
r->x = x;
|
||||
r->y = y;
|
||||
r->w = progress_width(pb);
|
||||
r->h = pb->h;
|
||||
r->r = pb->fg.r;
|
||||
r->g = pb->fg.g;
|
||||
r->b = pb->fg.b;
|
||||
}
|
||||
|
||||
static void set_bg_params(const struct gui_progress_bar *const pb,
|
||||
struct rect *const r, const short x, const short y)
|
||||
{
|
||||
const short w = progress_width(pb);
|
||||
|
||||
r->x = x + w;
|
||||
r->y = y;
|
||||
r->w = pb->w - w;
|
||||
r->h = pb->h;
|
||||
r->r = pb->bg.r;
|
||||
r->g = pb->bg.g;
|
||||
r->b = pb->bg.b;
|
||||
}
|
||||
|
||||
static int render_common(const struct gui_progress_bar *const pb,
|
||||
const short x, const short y, void (*init)(struct rect *))
|
||||
{
|
||||
{
|
||||
rect_get_or_ret(fg, -1);
|
||||
init(fg);
|
||||
set_fg_params(pb, fg, x, y);
|
||||
rect_sort(fg);
|
||||
}
|
||||
|
||||
{
|
||||
rect_get_or_ret(bg, -1);
|
||||
init(bg);
|
||||
set_bg_params(pb, bg, x, y);
|
||||
rect_sort(bg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_op(const struct gui_progress_bar *const pb,
|
||||
const short x, const short y)
|
||||
{
|
||||
return render_common(pb, x, y, rect_init);
|
||||
}
|
||||
|
||||
static int render_stp(const struct gui_progress_bar *const pb,
|
||||
const short x, const short y)
|
||||
{
|
||||
return render_common(pb, x, y, semitrans_rect_init);
|
||||
}
|
||||
|
||||
static int render(const struct gui_common *const g)
|
||||
{
|
||||
const struct gui_progress_bar *const pb =
|
||||
(const struct gui_progress_bar *)g;
|
||||
short x, y;
|
||||
|
||||
gui_coords(&pb->common, &x, &y);
|
||||
|
||||
if (pb->stp)
|
||||
return render_stp(pb, x, y);
|
||||
|
||||
return render_op(pb, x, y);
|
||||
}
|
||||
|
||||
void gui_progress_bar_init(struct gui_progress_bar *const pb)
|
||||
{
|
||||
*pb = (const struct gui_progress_bar)
|
||||
{
|
||||
.common =
|
||||
{
|
||||
.render = render
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
#include <gui/rounded_rect.h>
|
||||
#include <gui.h>
|
||||
#include <gui_private.h>
|
||||
#include <gfx.h>
|
||||
|
||||
struct sprite gui_rounded_rect_sprites[MAX_GUI_ROUNDED_RECT_SPRITES];
|
||||
|
||||
/* Alias for readability. */
|
||||
static const struct sprite *const refs = gui_rounded_rect_sprites;
|
||||
|
||||
static int render_top(const struct gui_rounded_rect *const r,
|
||||
const short x, const short y)
|
||||
{
|
||||
{
|
||||
sprite_get_or_ret(left, -1);
|
||||
|
||||
if (sprite_clone(&refs[GUI_ROUNDED_RECT_UP_LEFT], left))
|
||||
return -1;
|
||||
|
||||
left->x = x;
|
||||
left->y = y;
|
||||
sprite_sort(left);
|
||||
}
|
||||
|
||||
{
|
||||
sprite_get_or_ret(right, -1);
|
||||
|
||||
const struct sprite *const ref =
|
||||
&refs[GUI_ROUNDED_RECT_UP_RIGHT];
|
||||
|
||||
if (sprite_clone(ref, right))
|
||||
return -1;
|
||||
|
||||
right->x = x + r->w - ref->w;
|
||||
right->y = y;
|
||||
sprite_sort(right);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_vert(const struct gui_rounded_rect *const r,
|
||||
const short x, const short y)
|
||||
{
|
||||
const struct sprite *const vert = &refs[GUI_ROUNDED_RECT_MID_VERT];
|
||||
const short top_h = refs[GUI_ROUNDED_RECT_UP_LEFT].h,
|
||||
h = r->h - (top_h * 2),
|
||||
rem_vert = h % vert->h,
|
||||
whole_vert = h / vert->h,
|
||||
n_vert = rem_vert ? whole_vert + 1 : whole_vert;
|
||||
|
||||
for (struct
|
||||
{
|
||||
size_t i;
|
||||
short y;
|
||||
} a = {.y = y + top_h}; a.i < n_vert; a.i++, a.y += vert->h)
|
||||
{
|
||||
sprite_get_or_ret(v, -1);
|
||||
|
||||
if (sprite_clone(vert, v))
|
||||
return -1;
|
||||
|
||||
v->y = a.y;
|
||||
v->x = x;
|
||||
|
||||
if (rem_vert && a.i + 1 == n_vert)
|
||||
v->h = rem_vert;
|
||||
else
|
||||
v->h = vert->h;
|
||||
|
||||
sprite_sort(v);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_vertleft(const struct gui_rounded_rect *const r,
|
||||
const short x, const short y)
|
||||
{
|
||||
return render_vert(r, x, y);
|
||||
}
|
||||
|
||||
static int render_vertright(const struct gui_rounded_rect *const r,
|
||||
const short x, const short y)
|
||||
{
|
||||
const struct sprite *const ref = &refs[GUI_ROUNDED_RECT_MID_VERT];
|
||||
|
||||
return render_vert(r, x + r->w - ref->w, y);
|
||||
}
|
||||
|
||||
static int render_down(const struct gui_rounded_rect *const r,
|
||||
const short x, const short y)
|
||||
{
|
||||
{
|
||||
const struct sprite *const ref = &refs[GUI_ROUNDED_RECT_DOWN_LEFT];
|
||||
sprite_get_or_ret(left, -1);
|
||||
|
||||
if (sprite_clone(ref, left))
|
||||
return -1;
|
||||
|
||||
left->x = x;
|
||||
left->y = y + r->h - ref->h;
|
||||
sprite_sort(left);
|
||||
}
|
||||
|
||||
{
|
||||
const struct sprite *const ref = &refs[GUI_ROUNDED_RECT_DOWN_RIGHT];
|
||||
sprite_get_or_ret(right, -1);
|
||||
|
||||
if (sprite_clone(ref, right))
|
||||
return -1;
|
||||
|
||||
right->x = x + r->w - ref->w;
|
||||
right->y = y + r->h - ref->h;
|
||||
sprite_sort(right);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_rect(const struct gui_rounded_rect *const r,
|
||||
const short x, const short y)
|
||||
{
|
||||
rect_get_or_ret(sel, -1);
|
||||
semitrans_rect_init(sel);
|
||||
|
||||
const struct sprite *const mid = &refs[GUI_ROUNDED_RECT_MID],
|
||||
*const vert = &refs[GUI_ROUNDED_RECT_MID_VERT];
|
||||
|
||||
sel->x = x + vert->w;
|
||||
sel->y = y + mid->h;
|
||||
sel->w = r->w - (vert->w * 2);
|
||||
sel->h = r->h - (mid->h * 2);
|
||||
sel->r = 72;
|
||||
sel->g = 66;
|
||||
sel->b = 56;
|
||||
rect_sort(sel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_mid(const struct gui_rounded_rect *const r,
|
||||
const short x, const short y)
|
||||
{
|
||||
const short mid_w = refs[GUI_ROUNDED_RECT_MID].w,
|
||||
top_w = refs[GUI_ROUNDED_RECT_UP_LEFT].w,
|
||||
w = r->w - (top_w * 2),
|
||||
rem_mid = w % mid_w,
|
||||
whole_mid = w / mid_w,
|
||||
n_mid = rem_mid ? whole_mid + 1 : whole_mid;
|
||||
|
||||
for (struct
|
||||
{
|
||||
size_t i;
|
||||
short x;
|
||||
} a = {.x = x + top_w}; a.i < n_mid; a.i++, a.x += mid_w)
|
||||
{
|
||||
sprite_get_or_ret(m, -1);
|
||||
|
||||
if (sprite_clone(&refs[GUI_ROUNDED_RECT_MID], m))
|
||||
return -1;
|
||||
|
||||
m->x = a.x;
|
||||
m->y = y;
|
||||
|
||||
if (rem_mid && a.i + 1 == n_mid)
|
||||
m->w = rem_mid;
|
||||
else
|
||||
m->w = mid_w;
|
||||
|
||||
sprite_sort(m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_midtop(const struct gui_rounded_rect *const r,
|
||||
const short x, const short y)
|
||||
{
|
||||
return render_mid(r, x, y);
|
||||
}
|
||||
|
||||
static int render_middown(const struct gui_rounded_rect *const r,
|
||||
const short x, const short y)
|
||||
{
|
||||
return render_mid(r, x, y + r->h - refs[GUI_ROUNDED_RECT_MID].h);
|
||||
}
|
||||
|
||||
static int render(const struct gui_common *const g)
|
||||
{
|
||||
const struct gui_rounded_rect *const r = (const struct gui_rounded_rect *)g;
|
||||
|
||||
short x, y;
|
||||
|
||||
gui_coords(&r->common, &x, &y);
|
||||
|
||||
static int (*const steps[])(const struct gui_rounded_rect *const r,
|
||||
const short x, const short y) =
|
||||
{
|
||||
render_top,
|
||||
render_rect,
|
||||
render_midtop,
|
||||
render_middown,
|
||||
render_vertleft,
|
||||
render_vertright,
|
||||
render_down
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof steps / sizeof *steps; i++)
|
||||
if (steps[i](r, x, y))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gui_rounded_rect_init(struct gui_rounded_rect *const r)
|
||||
{
|
||||
*r = (const struct gui_rounded_rect)
|
||||
{
|
||||
.common =
|
||||
{
|
||||
.render = render
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
add_library(player "src/player.c" "src/human_player.c")
|
||||
target_include_directories(player PUBLIC "inc")
|
||||
add_library(player
|
||||
"src/player.c"
|
||||
"src/human_player.c"
|
||||
"src/human_player_gui.c"
|
||||
)
|
||||
target_include_directories(player PUBLIC "inc" PRIVATE "privinc")
|
||||
target_link_libraries(player
|
||||
PUBLIC
|
||||
building
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef HUMAN_PLAYER_PRIVATE_H
|
||||
#define HUMAN_PLAYER_PRIVATE_H
|
||||
|
||||
#include <human_player.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void human_player_gui_update(struct human_player *h);
|
||||
int human_player_gui_render(const struct human_player *h);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HUMAN_PLAYER_PRIVATE_H */
|
|
@ -1,4 +1,5 @@
|
|||
#include <human_player.h>
|
||||
#include <human_player_private.h>
|
||||
#include <player.h>
|
||||
#include <building.h>
|
||||
#include <camera.h>
|
||||
|
@ -595,7 +596,7 @@ void human_player_update(struct human_player *const h,
|
|||
|
||||
if (p->alive)
|
||||
{
|
||||
gui_update(h);
|
||||
human_player_gui_update(h);
|
||||
update_selected(h);
|
||||
update_target(h);
|
||||
peripheral_update(&h->periph);
|
||||
|
@ -687,7 +688,7 @@ int human_player_render(const struct human_player *const h,
|
|||
|| render_own_units(h)
|
||||
|| render_own_buildings(h)
|
||||
|| render_resources(h, o->res, o->n_res)
|
||||
|| gui_render(h))
|
||||
|| human_player_gui_render(h))
|
||||
return -1;
|
||||
|
||||
switch (h->periph.common.type)
|
||||
|
|
|
@ -0,0 +1,341 @@
|
|||
#include <building.h>
|
||||
#include <gfx.h>
|
||||
#include <human_player.h>
|
||||
#include <player.h>
|
||||
#include <unit.h>
|
||||
#include <gui.h>
|
||||
#include <gui/bar.h>
|
||||
#include <gui/label.h>
|
||||
#include <gui/progress_bar.h>
|
||||
#include <gui/rounded_rect.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum {X_OFF = 8, Y_OFF = 8, HP_Y = 32};
|
||||
|
||||
static int draw_hp(const struct instance *const i, const instance_hp max_hp,
|
||||
struct gui_common *const r)
|
||||
{
|
||||
enum {WIDTH = 64, HEIGHT = 4};
|
||||
struct gui_progress_bar pb;
|
||||
|
||||
gui_progress_bar_init(&pb);
|
||||
pb.common.x = X_OFF;
|
||||
pb.common.y = HP_Y - 8;
|
||||
pb.progress = ((unsigned)GUI_PROGRESS_BAR_MAX * i->hp) / max_hp;
|
||||
pb.fg.g = UCHAR_MAX >> 1;
|
||||
pb.bg.r = UCHAR_MAX >> 1;
|
||||
pb.w = WIDTH;
|
||||
pb.h = HEIGHT;
|
||||
pb.stp = true;
|
||||
gui_add_child(r, &pb.common);
|
||||
|
||||
return gui_render(r);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int draw_miners(const struct resource *const r)
|
||||
{
|
||||
const struct resource_gold *const g = &r->res.gold;
|
||||
|
||||
if (!g->n_miners)
|
||||
return 0;
|
||||
|
||||
for (size_t i = 0, n = 0; i < sizeof g->miners / sizeof *g->miners; i++)
|
||||
{
|
||||
if (g->miners[i])
|
||||
{
|
||||
enum {OFFSET = 112, SZ = 16, GAP = 4};
|
||||
|
||||
rect_get_or_ret(r, -1);
|
||||
semitrans_rect_init(r);
|
||||
r->x = OFFSET + n * (SZ + GAP);
|
||||
r->y = screen_h - 40;
|
||||
r->r = r->g = r->b = 127;
|
||||
r->w = r->h = SZ;
|
||||
rect_sort(r);
|
||||
|
||||
if (++n >= g->n_miners)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void human_player_gui_update(struct human_player *const h)
|
||||
{
|
||||
struct player *const pl = &h->pl;
|
||||
|
||||
for (size_t i = 0; i < sizeof pl->resources / sizeof *pl->resources; i++)
|
||||
{
|
||||
if (h->gui_res[i] > pl->resources[i])
|
||||
h->gui_res[i]--;
|
||||
else if (h->gui_res[i] < pl->resources[i])
|
||||
h->gui_res[i]++;
|
||||
}
|
||||
}
|
||||
|
||||
static int render_sel_single_building(const struct human_player *const h,
|
||||
const struct sel_instance *const sel, struct gui_common *const r)
|
||||
{
|
||||
const struct building *const b = sel->d.b;
|
||||
const struct instance *const in = &b->instance;
|
||||
const instance_hp hp = in->hp, max_hp = building_maxhp(b);
|
||||
struct gui_label bl;
|
||||
|
||||
gui_label_init(&bl);
|
||||
bl.common.x = X_OFF;
|
||||
bl.common.y = Y_OFF;
|
||||
bl.text = building_str(b);
|
||||
gui_add_child(r, &bl.common);
|
||||
|
||||
char hp_str[sizeof "65535/65535"];
|
||||
|
||||
const int rs = snprintf(hp_str, sizeof hp_str, "%u/%u", hp, max_hp);
|
||||
|
||||
if (rs < 0 || rs >= sizeof hp_str)
|
||||
return -1;
|
||||
|
||||
struct gui_label hpl;
|
||||
|
||||
gui_label_init(&hpl);
|
||||
hpl.common.x = X_OFF;
|
||||
hpl.common.y = HP_Y;
|
||||
hpl.text = hp_str;
|
||||
gui_add_child(r, &hpl.common);
|
||||
|
||||
return draw_hp(in, max_hp, r);
|
||||
}
|
||||
|
||||
static int render_sel_single_unit(const struct human_player *const h,
|
||||
const struct sel_instance *const sel, struct gui_common *const r)
|
||||
{
|
||||
const struct unit *const u = sel->d.u;
|
||||
const struct instance *const in = &u->instance;
|
||||
const instance_hp hp = in->hp, max_hp = unit_maxhp(u);
|
||||
enum {CARRY_X = 96, CARRY_Y = 8};
|
||||
|
||||
struct gui_label ul;
|
||||
|
||||
gui_label_init(&ul);
|
||||
ul.common.x = X_OFF;
|
||||
ul.common.y = Y_OFF;
|
||||
ul.text = unit_str(u);
|
||||
gui_add_child(r, &ul.common);
|
||||
|
||||
char hp_str[sizeof "65535/65535"];
|
||||
|
||||
const int rs = snprintf(hp_str, sizeof hp_str, "%u/%u", hp, max_hp);
|
||||
|
||||
if (rs < 0 || rs >= sizeof hp_str)
|
||||
return -1;
|
||||
|
||||
struct gui_label hpl;
|
||||
|
||||
gui_label_init(&hpl);
|
||||
hpl.common.x = X_OFF;
|
||||
hpl.common.y = HP_Y;
|
||||
hpl.text = hp_str;
|
||||
gui_add_child(r, &hpl.common);
|
||||
|
||||
if (unit_can_harvest(u))
|
||||
{
|
||||
const struct unit_harvester *const uh = &u->us.harvester;
|
||||
|
||||
if (uh->carry)
|
||||
{
|
||||
char c_str[sizeof "255"];
|
||||
const int rs = snprintf(c_str, sizeof c_str, "%hhu", uh->carry);
|
||||
struct gui_label cl;
|
||||
|
||||
gui_label_init(&cl);
|
||||
cl.common.x = CARRY_X;
|
||||
cl.common.y = CARRY_Y;
|
||||
cl.text = c_str;
|
||||
gui_add_child(r, &cl.common);
|
||||
|
||||
if (rs < 0 || rs >= sizeof c_str)
|
||||
return -1;
|
||||
|
||||
return gui_render(r);
|
||||
}
|
||||
}
|
||||
|
||||
return draw_hp(in, max_hp, r);
|
||||
}
|
||||
|
||||
static int render_sel_single_resource(const struct human_player *const h,
|
||||
const struct sel_instance *const sel, struct gui_common *const r)
|
||||
{
|
||||
const struct resource *const res = sel->d.r;
|
||||
const struct instance *const in = &res->instance;
|
||||
const instance_hp hp = in->hp, max_hp = resource_maxhp(res);
|
||||
struct gui_label rl;
|
||||
|
||||
gui_label_init(&rl);
|
||||
rl.common.x = X_OFF;
|
||||
rl.common.y = Y_OFF;
|
||||
rl.text = resource_str(res);
|
||||
gui_add_child(r, &rl.common);
|
||||
|
||||
char hp_str[sizeof "65535/65535"];
|
||||
const int rs = snprintf(hp_str, sizeof hp_str, "%u/%u", hp, max_hp);
|
||||
|
||||
if (rs < 0 || rs >= sizeof hp_str)
|
||||
return -1;
|
||||
|
||||
struct gui_label hpl;
|
||||
|
||||
gui_label_init(&hpl);
|
||||
hpl.common.x = X_OFF;
|
||||
hpl.common.y = HP_Y;
|
||||
hpl.text = hp_str;
|
||||
gui_add_child(r, &hpl.common);
|
||||
|
||||
return draw_hp(in, max_hp, r);
|
||||
}
|
||||
|
||||
static int render_sel_single(const struct human_player *const h,
|
||||
struct gui_common *const r)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof h->sel / sizeof *h->sel; i++)
|
||||
{
|
||||
const struct sel_instance *const sel = &h->sel[i];
|
||||
|
||||
if (sel)
|
||||
{
|
||||
switch (sel->type)
|
||||
{
|
||||
case INSTANCE_TYPE_BUILDING:
|
||||
return render_sel_single_building(h, sel, r);
|
||||
|
||||
case INSTANCE_TYPE_UNIT:
|
||||
return render_sel_single_unit(h, sel, r);
|
||||
|
||||
case INSTANCE_TYPE_RESOURCE:
|
||||
return render_sel_single_resource(h, sel, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unreachable. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int render_sel_multiple(const struct human_player *const h,
|
||||
struct gui_common *const r)
|
||||
{
|
||||
struct gui_label l;
|
||||
char str[sizeof "4294967295 units selected"];
|
||||
const int rs = snprintf(str, sizeof str, "%zu units selected", h->n_sel);
|
||||
|
||||
if (rs < 0 || rs >= sizeof str)
|
||||
return -1;
|
||||
|
||||
gui_label_init(&l);
|
||||
l.common.x = X_OFF;
|
||||
l.common.y = Y_OFF;
|
||||
l.text = str;
|
||||
gui_add_child(r, &l.common);
|
||||
|
||||
return gui_render(r);
|
||||
}
|
||||
|
||||
static int render_sel(const struct human_player *const h)
|
||||
{
|
||||
enum {OFFSET = 60};
|
||||
struct gui_rounded_rect r;
|
||||
|
||||
gui_rounded_rect_init(&r);
|
||||
r.common.x = 16;
|
||||
r.common.y = screen_h - OFFSET;
|
||||
r.w = screen_w - (r.common.x * 2);
|
||||
r.h = OFFSET;
|
||||
|
||||
if (h->n_sel == 1)
|
||||
return render_sel_single(h, &r.common);
|
||||
|
||||
return render_sel_multiple(h, &r.common);
|
||||
}
|
||||
|
||||
static int render_top(const struct human_player *const h)
|
||||
{
|
||||
const struct player *const pl = &h->pl;
|
||||
struct gui_bar b;
|
||||
|
||||
gui_bar_init(&b);
|
||||
char wood_str[sizeof "Wood=429496729"];
|
||||
|
||||
{
|
||||
const int rs = snprintf(wood_str, sizeof wood_str,
|
||||
"Wood=%" PRIu32, h->gui_res[RESOURCE_TYPE_WOOD]);
|
||||
|
||||
if (rs < 0 || rs >= sizeof wood_str)
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct gui_label wl;
|
||||
|
||||
gui_label_init(&wl);
|
||||
wl.common.x = 16;
|
||||
wl.common.y = 6;
|
||||
wl.text = wood_str;
|
||||
gui_add_child(&b.common, &wl.common);
|
||||
|
||||
char gold_str[sizeof "Gold=429496729"];
|
||||
|
||||
{
|
||||
const int rs = snprintf(gold_str, sizeof gold_str,
|
||||
"Gold=%" PRIu32, h->gui_res[RESOURCE_TYPE_GOLD]);
|
||||
|
||||
if (rs < 0 || rs >= sizeof wood_str)
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct gui_label gl;
|
||||
|
||||
gui_label_init(&gl);
|
||||
gl.common.x = 108;
|
||||
gl.common.y = 6;
|
||||
gl.text = gold_str;
|
||||
gui_add_child(&b.common, &gl.common);
|
||||
|
||||
char pop_str[sizeof "Pop.=255/255"];
|
||||
|
||||
{
|
||||
const int rs = snprintf(pop_str, sizeof pop_str,
|
||||
"Pop.=%hhu/%zu", pl->pop, sizeof pl->units / sizeof *pl->units);
|
||||
|
||||
if (rs < 0 || rs >= sizeof wood_str)
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct gui_label popl;
|
||||
|
||||
gui_label_init(&popl);
|
||||
popl.common.x = 212;
|
||||
popl.common.y = 6;
|
||||
popl.text = pop_str;
|
||||
gui_add_child(&b.common, &popl.common);
|
||||
|
||||
if (gui_render(&b.common))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int human_player_gui_render(const struct human_player *const h)
|
||||
{
|
||||
if (h->top_gui && render_top(h))
|
||||
return -1;
|
||||
|
||||
if (h->n_sel && render_sel(h))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue