UI wip
This commit is contained in:
parent
24294d45a9
commit
317ad22de0
22
app.c
22
app.c
@ -11,6 +11,7 @@
|
|||||||
#include "render_bundle.h"
|
#include "render_bundle.h"
|
||||||
#include "render_component.h"
|
#include "render_component.h"
|
||||||
#include "mapper_misc.h"
|
#include "mapper_misc.h"
|
||||||
|
#include "ui.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -27,6 +28,9 @@ App *app_NewApp() {
|
|||||||
app->camera = camera_NewSystem(app);
|
app->camera = camera_NewSystem(app);
|
||||||
app->particle = particle_NewSystem(app);
|
app->particle = particle_NewSystem(app);
|
||||||
app->time = gametime_NewSystem(app);
|
app->time = gametime_NewSystem(app);
|
||||||
|
app->ui = ui_NewSystem(app);
|
||||||
|
ui_RebuildUI(app->ui);
|
||||||
|
ui_PushState(app->ui, ui_Running);
|
||||||
|
|
||||||
app->switch_level = NULL;
|
app->switch_level = NULL;
|
||||||
app->timescale = 1.0;
|
app->timescale = 1.0;
|
||||||
@ -57,6 +61,7 @@ void app_DeleteApp(App *app) {
|
|||||||
camera_DeleteSystem(app->camera);
|
camera_DeleteSystem(app->camera);
|
||||||
particle_DeleteSystem(app->particle);
|
particle_DeleteSystem(app->particle);
|
||||||
gametime_DeleteSystem(app->time);
|
gametime_DeleteSystem(app->time);
|
||||||
|
ui_DeleteSystem(app->ui);
|
||||||
|
|
||||||
free(app);
|
free(app);
|
||||||
}
|
}
|
||||||
@ -72,15 +77,18 @@ void app_Advance(App *app, Duration deltaTime) {
|
|||||||
|
|
||||||
input_Advance(app->input);
|
input_Advance(app->input);
|
||||||
|
|
||||||
|
Duration delta_game = deltaTime;
|
||||||
if (1.0 - app->timescale > EPS)
|
if (1.0 - app->timescale > EPS)
|
||||||
deltaTime.microseconds = deltaTime.microseconds * app->timescale;
|
delta_game.microseconds = delta_game.microseconds * app->timescale;
|
||||||
|
|
||||||
if (!app->paused) {
|
if (!app->paused) {
|
||||||
gametime_Advance(app->time, deltaTime);
|
gametime_Advance(app->time, delta_game);
|
||||||
particle_Advance(app->particle, deltaTime);
|
particle_Advance(app->particle, delta_game);
|
||||||
player_Advance(app->player, deltaTime);
|
player_Advance(app->player, delta_game);
|
||||||
physics_Advance(app->physics, deltaTime);
|
physics_Advance(app->physics, delta_game);
|
||||||
entity_Advance(app->entity, deltaTime);
|
entity_Advance(app->entity, delta_game);
|
||||||
camera_Advance(app->camera, deltaTime);
|
camera_Advance(app->camera, delta_game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui_Advance(app->ui, deltaTime);
|
||||||
}
|
}
|
||||||
|
2
app.h
2
app.h
@ -7,6 +7,7 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
#include "particle.h"
|
#include "particle.h"
|
||||||
|
#include "ui.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "util/vector.h"
|
#include "util/vector.h"
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ typedef struct _App {
|
|||||||
System_Camera *camera;
|
System_Camera *camera;
|
||||||
System_Particle *particle;
|
System_Particle *particle;
|
||||||
System_GameTime *time;
|
System_GameTime *time;
|
||||||
|
System_UI *ui;
|
||||||
|
|
||||||
char *switch_level;
|
char *switch_level;
|
||||||
double timescale;
|
double timescale;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "easyx.h"
|
#include "easyx.h"
|
||||||
#include "render_bundle.h"
|
#include "render_bundle.h"
|
||||||
#include "render_component.h"
|
#include "render_component.h"
|
||||||
|
#include "ui.h"
|
||||||
#include "util/tree.h"
|
#include "util/tree.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "render_util.h"
|
#include "render_util.h"
|
||||||
@ -21,10 +22,7 @@ TimePoint since = time_Now();
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" void app_Render(App *app) {
|
||||||
|
|
||||||
|
|
||||||
void app_Render(App *app) {
|
|
||||||
render_SetModes(render_ModeDefault, time_Now());
|
render_SetModes(render_ModeDefault, time_Now());
|
||||||
setbkcolor(app->clear_color);
|
setbkcolor(app->clear_color);
|
||||||
cleardevice();
|
cleardevice();
|
||||||
@ -176,11 +174,13 @@ void app_Render(App *app) {
|
|||||||
|
|
||||||
// If paused, display a text
|
// If paused, display a text
|
||||||
if (app->paused)
|
if (app->paused)
|
||||||
render_DrawTextEx("Game Paused", box2(SCREEN_WIDTH / 2 - 10, 100, 20, 100), DT_CENTER | DT_NOCLIP);
|
render_DrawTextEx("Game Paused", box2(SCREEN_WIDTH / 2.0 - 10, 100, 20, 100), DT_CENTER | DT_NOCLIP);
|
||||||
if (1.0 - app->timescale > EPS) {
|
if (1.0 - app->timescale > EPS) {
|
||||||
char buf[128];
|
char buf[128];
|
||||||
snprintf(buf, sizeof(buf), "*** TIMESCALE %.2lf ***", app->timescale);
|
snprintf(buf, sizeof(buf), "*** TIMESCALE %.2lf ***", app->timescale);
|
||||||
render_DrawTextEx(buf, box2(SCREEN_WIDTH / 2 - 10, 50, 20, 100), DT_CENTER | DT_NOCLIP);
|
render_DrawTextEx(buf, box2(SCREEN_WIDTH / 2.0 - 10, 50, 20, 100), DT_CENTER | DT_NOCLIP);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Draw UI
|
||||||
|
ui_Render(app->ui);
|
||||||
}
|
}
|
||||||
|
15
input.c
15
input.c
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -75,11 +76,15 @@ void input_Advance(System_Input *sys) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sys->keys[input_Key_Escape] == JustPressed) {
|
if (sys->keys[input_Key_Escape] == JustPressed) {
|
||||||
if (!sys->super->paused)
|
if (ui_CurrentState(sys->super->ui) == ui_Running) {
|
||||||
fprintf(stderr, "[input_Advance] Pausing\n");
|
// Pause
|
||||||
else
|
ui_PushState(sys->super->ui, ui_Paused);
|
||||||
fprintf(stderr, "[input_Advance] Unpausing\n");
|
sys->super->paused = true;
|
||||||
sys->super->paused = !sys->super->paused;
|
} else if (ui_CurrentState(sys->super->ui) == ui_Paused) {
|
||||||
|
// Unpause
|
||||||
|
ui_PopState(sys->super->ui);
|
||||||
|
sys->super->paused = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
types.h
4
types.h
@ -11,8 +11,8 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define SCREEN_WIDTH 1600
|
#define SCREEN_WIDTH 1536
|
||||||
#define SCREEN_HEIGHT 900
|
#define SCREEN_HEIGHT 864
|
||||||
|
|
||||||
#define WARN(fmt, ...) fprintf(stderr, "[WARN][%s] " fmt "\n", __func__, ##__VA_ARGS__)
|
#define WARN(fmt, ...) fprintf(stderr, "[WARN][%s] " fmt "\n", __func__, ##__VA_ARGS__)
|
||||||
#define INFO(fmt, ...) fprintf(stderr, "[%s] " fmt "\n", __func__, ##__VA_ARGS__)
|
#define INFO(fmt, ...) fprintf(stderr, "[%s] " fmt "\n", __func__, ##__VA_ARGS__)
|
||||||
|
127
ui.c
Normal file
127
ui.c
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
|
||||||
|
#include "ui.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "app.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "util/vector.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
const char *ui_StateTitle[ui_StateCount] = {
|
||||||
|
"Running",
|
||||||
|
"Pause Menu",
|
||||||
|
"Jack's Escape (ver. 3.141592) - Title",
|
||||||
|
"Select Level",
|
||||||
|
"Options"};
|
||||||
|
|
||||||
|
|
||||||
|
static inline double dabs(double x) { return x > 0 ? x : -x; }
|
||||||
|
static inline double dmin(double x, double y) { return x < y ? x : y; }
|
||||||
|
static inline double dmax(double x, double y) { return x > y ? x : y; }
|
||||||
|
|
||||||
|
|
||||||
|
System_UI *ui_NewSystem(App *super) {
|
||||||
|
System_UI *sys = zero_malloc(sizeof(System_UI));
|
||||||
|
sys->super = super;
|
||||||
|
sys->state = vector_Create(sizeof(ui_State));
|
||||||
|
for (int i = 0; i < ui_StateCount; i++)
|
||||||
|
sys->parts[i] = vector_Create(sizeof(ui_Part));
|
||||||
|
return sys;
|
||||||
|
}
|
||||||
|
void ui_DeleteSystem(System_UI *sys) {
|
||||||
|
for (int i = 0; i < ui_StateCount; i++)
|
||||||
|
for (int j = 0; j < vector_Size(sys->parts[i]); j++) {
|
||||||
|
ui_Part *part = (ui_Part *)vector_At(sys->parts[i], j);
|
||||||
|
part->free(sys, part, part->user);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ui_StateCount; i++)
|
||||||
|
vector_Destroy(sys->parts[i]);
|
||||||
|
vector_Destroy(sys->state);
|
||||||
|
free(sys);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ui_PushPart(System_UI *sys, ui_State layer, ui_Part part) {
|
||||||
|
vector_Push(sys->parts[layer], &part);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline double fadeto(double from, double to, Duration deltaTime) {
|
||||||
|
if (dabs(from - to) < EPS)
|
||||||
|
return to;
|
||||||
|
else
|
||||||
|
return from + (to - from) * UI_BACKGROUND_FADE_MOVE_SPEED * duration_Seconds(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _ui_UpdateBgTarget(System_UI *sys) {
|
||||||
|
if (vector_Size(sys->state) == 0) {
|
||||||
|
WARN("state stack is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_State layer = *(ui_State *)vector_Back(sys->state);
|
||||||
|
if (vector_Size(sys->parts[layer]) == 0) {
|
||||||
|
// No UI target, set to (0,0), (0,0)
|
||||||
|
memset(&sys->bg_target, 0, sizeof(sys->bg_target));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 min = {.x = SCREEN_WIDTH, .y = SCREEN_HEIGHT}, max = {.x = 0, .y = 0};
|
||||||
|
for (int i = 0; i < vector_Size(sys->parts[layer]); i++) {
|
||||||
|
ui_Part *part = (ui_Part *)vector_At(sys->parts[layer], i);
|
||||||
|
min.x = dmin(min.x, part->box.lefttop.x);
|
||||||
|
min.y = dmin(min.y, part->box.lefttop.y);
|
||||||
|
max.x = dmax(max.x, part->box.lefttop.x + part->box.size.x);
|
||||||
|
max.y = dmax(max.y, part->box.lefttop.y + part->box.size.y);
|
||||||
|
}
|
||||||
|
sys->bg_target.lefttop = vec2(min.x - UI_PADDING, min.y - UI_PADDING);
|
||||||
|
sys->bg_target.size = vec2(max.x - min.x + 2 * UI_PADDING, max.y - min.y + 2 * UI_PADDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_Advance(System_UI *sys, Duration deltaTime) {
|
||||||
|
Vec2 lt = sys->bg.lefttop, rb = vec2_Add(sys->bg.lefttop, sys->bg.size);
|
||||||
|
Vec2 lt_target = sys->bg_target.lefttop, rb_target = vec2_Add(sys->bg_target.lefttop, sys->bg_target.size);
|
||||||
|
lt.x = fadeto(lt.x, lt_target.x, deltaTime);
|
||||||
|
lt.y = fadeto(lt.y, lt_target.y, deltaTime);
|
||||||
|
rb.x = fadeto(rb.x, rb_target.x, deltaTime);
|
||||||
|
rb.y = fadeto(rb.y, rb_target.y, deltaTime);
|
||||||
|
|
||||||
|
sys->bg.lefttop = lt;
|
||||||
|
sys->bg.size = vec2_Minus(rb, lt);
|
||||||
|
|
||||||
|
for (int i = 0; i < ui_StateCount; i++)
|
||||||
|
for (int j = 0; j < vector_Size(sys->parts[i]); j++) {
|
||||||
|
ui_Part *part = (ui_Part *)vector_At(sys->parts[i], j);
|
||||||
|
// Hover check
|
||||||
|
if (box2_Contains(part->box, input_MousePosition(sys->super->input))) {
|
||||||
|
part->hovered = true;
|
||||||
|
part->progress = dmin(part->progress + UI_BUTTON_HOVER_SPEED * duration_Seconds(deltaTime), 1.0);
|
||||||
|
} else {
|
||||||
|
part->hovered = false;
|
||||||
|
part->progress = dmax(part->progress - UI_BUTTON_HOVER_SPEED * duration_Seconds(deltaTime), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
part->update(sys, part, part->user, deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ui_PushState(System_UI *sys, ui_State push_state) {
|
||||||
|
vector_Push(sys->state, &push_state);
|
||||||
|
_ui_UpdateBgTarget(sys);
|
||||||
|
}
|
||||||
|
void ui_PopState(System_UI *sys) {
|
||||||
|
if (vector_Size(sys->state) == 0)
|
||||||
|
WARN("state stack empty");
|
||||||
|
else {
|
||||||
|
vector_Pop(sys->state, NULL);
|
||||||
|
_ui_UpdateBgTarget(sys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_State ui_CurrentState(System_UI *sys) {
|
||||||
|
if (vector_Size(sys->state) == 0)
|
||||||
|
WARN("state stack empty");
|
||||||
|
return *(ui_State *)vector_Back(sys->state);
|
||||||
|
}
|
72
ui.h
72
ui.h
@ -15,26 +15,86 @@ typedef enum {
|
|||||||
ui_Running,
|
ui_Running,
|
||||||
ui_Paused,
|
ui_Paused,
|
||||||
ui_TitleMenu,
|
ui_TitleMenu,
|
||||||
|
ui_SceneSelect,
|
||||||
|
ui_Options,
|
||||||
ui_StateCount // Keep at last
|
ui_StateCount // Keep at last
|
||||||
} ui_States;
|
} ui_State;
|
||||||
|
|
||||||
|
extern const char *ui_StateTitle[ui_StateCount];
|
||||||
|
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
typedef struct _ui_Button ui_Button;
|
|
||||||
typedef struct _System_UI System_UI;
|
typedef struct _System_UI System_UI;
|
||||||
|
|
||||||
// a Part of the UI.
|
// a Part of the UI.
|
||||||
typedef struct {
|
typedef struct _ui_Part {
|
||||||
void *user; // user data
|
Box2 box; // bounding box of the UI element
|
||||||
void (*draw)(System_UI *sys, void *user); // called when the UI is to be drawn
|
float progress; // hover process, from 0 to 1
|
||||||
|
bool hovered; // Whether the part is hovered
|
||||||
|
uintptr_t user; // user data
|
||||||
|
void (*draw)(System_UI *sys, struct _ui_Part *part, uintptr_t user); // called when the UI is to be drawn
|
||||||
|
void (*update)(System_UI *sys, struct _ui_Part *part, uintptr_t user, Duration deltatime); // called when the element is to be updated
|
||||||
|
void (*free)(System_UI *sys, struct _ui_Part *part, uintptr_t user); // called when the element is to be deleted
|
||||||
} ui_Part;
|
} ui_Part;
|
||||||
|
|
||||||
// UI system with its own state machine.
|
// UI system with its own state machine.
|
||||||
typedef struct _System_UI {
|
typedef struct _System_UI {
|
||||||
App *super;
|
App *super;
|
||||||
vector_Vector *parts[ui_StateCount];
|
vector_Vector *parts[ui_StateCount]; // A vector of ui_Parts
|
||||||
|
vector_Vector *state; // A stack of ui_States
|
||||||
|
|
||||||
|
Box2 bg, bg_target;
|
||||||
} System_UI;
|
} System_UI;
|
||||||
|
|
||||||
|
System_UI *ui_NewSystem(App *super);
|
||||||
|
void ui_DeleteSystem(System_UI *sys);
|
||||||
|
|
||||||
|
// Clears and refills every menu with its widgets
|
||||||
|
void ui_RebuildUI(System_UI *sys);
|
||||||
|
|
||||||
|
void ui_PushPart(System_UI *sys, ui_State layer, ui_Part part);
|
||||||
|
|
||||||
|
void ui_Advance(System_UI *sys, Duration deltaTime);
|
||||||
|
void ui_Render(System_UI *sys);
|
||||||
|
|
||||||
|
void ui_PushState(System_UI *sys, ui_State push_state);
|
||||||
|
void ui_PopState(System_UI *sys);
|
||||||
|
|
||||||
|
ui_State ui_CurrentState(System_UI *sys);
|
||||||
|
|
||||||
|
|
||||||
|
#define UI_PADDING (20)
|
||||||
|
#define UI_BACKGROUND (0)
|
||||||
|
|
||||||
|
#define UI_BACKGROUND_FADE_MOVE_SPEED (20.0)
|
||||||
|
#define UI_BUTTON_HOVER_SPEED (5.0)
|
||||||
|
|
||||||
|
#define UI_BUTTON_BACKGROUND (RGB(50, 50, 50))
|
||||||
|
#define UI_BUTTON_HOVERED (RGB(75, 75, 75))
|
||||||
|
#define UI_BUTTON_CLICKED (RGB(90, 90, 90))
|
||||||
|
|
||||||
|
typedef void (*ui_ActionCallback)(System_UI *sys, ui_Part *part, uintptr_t data);
|
||||||
|
|
||||||
|
// An Action to pop the UI state stack once
|
||||||
|
void ui_Action_PopState(System_UI *sys, ui_Part *part, uintptr_t data);
|
||||||
|
// An Action to push the state, casted directly from data
|
||||||
|
void ui_Action_PushState(System_UI *sys, ui_Part *part, uintptr_t data);
|
||||||
|
|
||||||
|
|
||||||
|
// Allocated & passed in as user data for ui part
|
||||||
|
typedef struct _ui_Button {
|
||||||
|
ui_ActionCallback callback;
|
||||||
|
uintptr_t callback_data;
|
||||||
|
|
||||||
|
uint32_t bg, bg_hover, clicked;
|
||||||
|
char *label; // Allocated & copied
|
||||||
|
bool left_aligned;
|
||||||
|
} ui_Button;
|
||||||
|
|
||||||
|
ui_Part ui_Button_New(Box2 box, const char *label, ui_ActionCallback callback, uintptr_t data);
|
||||||
|
ui_Part ui_Button_NewLeftAligned(Box2 box, const char *label, ui_ActionCallback callback, uintptr_t data);
|
||||||
|
// ui_Part ui_Button_NewColored(Box2 box, const char *label, uint32_t bg, uint32_t hover, uint32_t clicked, ui_ActionCallback callback, uintptr_t data);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
10
ui_action.c
Normal file
10
ui_action.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
|
|
||||||
|
void ui_Action_PopState(System_UI *sys, ui_Part *part, uintptr_t data) {
|
||||||
|
ui_PopState(sys);
|
||||||
|
}
|
||||||
|
void ui_Action_PushState(System_UI *sys, ui_Part *part, uintptr_t data) {
|
||||||
|
ui_PushState(sys, (ui_State)data);
|
||||||
|
}
|
29
ui_build.c
Normal file
29
ui_build.c
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
#include "ui.h"
|
||||||
|
#include "app.h"
|
||||||
|
#include "util/vector.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void _ui_Action_ResumeGame(System_UI *sys, ui_Part *part, uintptr_t data) {
|
||||||
|
ui_Action_PopState(sys, part, data);
|
||||||
|
sys->super->paused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define PUSH_UI(part) \
|
||||||
|
_p0 = (part); \
|
||||||
|
vector_Push(p, &_p0);
|
||||||
|
|
||||||
|
void ui_RebuildUI(System_UI *sys) {
|
||||||
|
vector_Vector *p;
|
||||||
|
ui_Part _p0;
|
||||||
|
|
||||||
|
|
||||||
|
// Paused
|
||||||
|
p = sys->parts[ui_Paused];
|
||||||
|
vector_Clear(p);
|
||||||
|
PUSH_UI(ui_Button_New(
|
||||||
|
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300), vec2(400, 50)),
|
||||||
|
"Resume Game",
|
||||||
|
&_ui_Action_ResumeGame, 0))
|
||||||
|
}
|
45
ui_button.c
Normal file
45
ui_button.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
#include "input.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "ui.h"
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef RGB
|
||||||
|
#define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void _ui_Button_Draw(System_UI *sys, ui_Part *part, uintptr_t user); // Defined in ui_render.cpp
|
||||||
|
void _ui_Button_Update(System_UI *sys, ui_Part *part, uintptr_t user, Duration deltatime) {
|
||||||
|
ui_Button *b = (ui_Button *)user;
|
||||||
|
if (part->hovered && sys->super->input->keys[input_Key_LeftMouse] == JustReleased)
|
||||||
|
b->callback(sys, part, b->callback_data);
|
||||||
|
}
|
||||||
|
void _ui_Button_Free(System_UI *sys, ui_Part *part, uintptr_t user) {
|
||||||
|
ui_Button *b = (ui_Button *)user;
|
||||||
|
free(b->label);
|
||||||
|
free(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ui_Part ui_Button_New(Box2 box, const char *label, ui_ActionCallback callback, uintptr_t data) {
|
||||||
|
ui_Button *b = zero_malloc(sizeof(ui_Button));
|
||||||
|
b->callback = callback;
|
||||||
|
b->callback_data = data;
|
||||||
|
b->bg = UI_BUTTON_BACKGROUND;
|
||||||
|
b->bg_hover = UI_BUTTON_HOVERED;
|
||||||
|
b->clicked = UI_BUTTON_CLICKED;
|
||||||
|
b->label = copy_malloc(label);
|
||||||
|
b->left_aligned = false;
|
||||||
|
|
||||||
|
ui_Part part = {
|
||||||
|
.box = box,
|
||||||
|
.progress = 0.0f,
|
||||||
|
.user = (uintptr_t)b,
|
||||||
|
.draw = &_ui_Button_Draw,
|
||||||
|
.update = &_ui_Button_Update,
|
||||||
|
.free = &_ui_Button_Free};
|
||||||
|
return part;
|
||||||
|
}
|
||||||
|
ui_Part ui_Button_NewLeftAligned(Box2 box, const char *label, ui_ActionCallback callback, uintptr_t data);
|
75
ui_render.cpp
Normal file
75
ui_render.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
#include "input.h"
|
||||||
|
#include "render_util.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "ui.h"
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
|
#include <easyx.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void ui_Render(System_UI *sys) {
|
||||||
|
// Background filled rectangle
|
||||||
|
if (sys->bg.size.x > EPS && sys->bg.size.y > EPS) {
|
||||||
|
setfillcolor(UI_BACKGROUND);
|
||||||
|
solidrectangle(
|
||||||
|
(int)round(sys->bg.lefttop.x),
|
||||||
|
(int)round(sys->bg.lefttop.y),
|
||||||
|
(int)round(sys->bg.lefttop.x + sys->bg.size.x),
|
||||||
|
(int)round(sys->bg.lefttop.y + sys->bg.size.y));
|
||||||
|
}
|
||||||
|
if (vector_Size(sys->state) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ui_State layer = *(ui_State *)vector_Back(sys->state);
|
||||||
|
// Title string
|
||||||
|
setbkcolor(UI_BACKGROUND);
|
||||||
|
render_DrawText(
|
||||||
|
(int)round(sys->bg.lefttop.x),
|
||||||
|
(int)round(sys->bg.lefttop.y) - TEXTHEIGHT,
|
||||||
|
ui_StateTitle[layer]);
|
||||||
|
|
||||||
|
// UI elements
|
||||||
|
// Skip them if the width of background is less than 90% of the target
|
||||||
|
if (sys->bg.size.x > sys->bg_target.size.x * 0.9)
|
||||||
|
for (int i = 0; i < vector_Size(sys->parts[layer]); i++) {
|
||||||
|
ui_Part *part = (ui_Part *)vector_At(sys->parts[layer], i);
|
||||||
|
part->draw(sys, part, part->user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void _ui_Button_Draw(System_UI *sys, ui_Part *part, void *user) {
|
||||||
|
ui_Button *b = (ui_Button *)user;
|
||||||
|
|
||||||
|
uint32_t color_final = 0;
|
||||||
|
|
||||||
|
if (part->hovered && input_IsPressed(sys->super->input->keys[input_Key_LeftMouse]))
|
||||||
|
// Hovered & pressed
|
||||||
|
color_final = b->clicked;
|
||||||
|
else {
|
||||||
|
// Fade the color
|
||||||
|
int r0 = b->bg & 0xff;
|
||||||
|
int g0 = (b->bg & 0xff00) >> 8;
|
||||||
|
int b0 = (b->bg & 0xff0000) >> 16;
|
||||||
|
|
||||||
|
int r1 = b->bg_hover & 0xff;
|
||||||
|
int g1 = (b->bg_hover & 0xff00) >> 8;
|
||||||
|
int b1 = (b->bg_hover & 0xff0000) >> 16;
|
||||||
|
|
||||||
|
color_final = RGB(
|
||||||
|
(int)((r1 - r0) * sqrt(part->progress) + r0),
|
||||||
|
(int)((g1 - g0) * sqrt(part->progress) + g0),
|
||||||
|
(int)((b1 - b0) * sqrt(part->progress) + b0));
|
||||||
|
}
|
||||||
|
|
||||||
|
setbkcolor(color_final);
|
||||||
|
setfillcolor(color_final);
|
||||||
|
settextcolor(RGB(255, 255, 255));
|
||||||
|
|
||||||
|
solidrectangle(
|
||||||
|
(int)round(part->box.lefttop.x),
|
||||||
|
(int)round(part->box.lefttop.y),
|
||||||
|
(int)round(part->box.lefttop.x + part->box.size.x),
|
||||||
|
(int)round(part->box.lefttop.y + part->box.size.y));
|
||||||
|
render_DrawTextEx(b->label, part->box, (b->left_aligned ? DT_LEFT : DT_CENTER) | DT_VCENTER | DT_SINGLELINE);
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
|
#include "assert.h"
|
||||||
|
|
||||||
|
|
||||||
vector_Vector *vector_Create(uintptr_t objectSize) {
|
vector_Vector *vector_Create(uintptr_t objectSize) {
|
||||||
@ -19,6 +20,7 @@ vector_Vector *vector_Create(uintptr_t objectSize) {
|
|||||||
|
|
||||||
// Resizes the underlying buffer to a new capacity
|
// Resizes the underlying buffer to a new capacity
|
||||||
static inline void __vector_Rebuffer(vector_Vector *vec, uintptr_t newcap) {
|
static inline void __vector_Rebuffer(vector_Vector *vec, uintptr_t newcap) {
|
||||||
|
ASSERT(newcap >= vec->size);
|
||||||
void *newbuf = malloc(newcap);
|
void *newbuf = malloc(newcap);
|
||||||
memcpy(newbuf, vec->data, vec->size);
|
memcpy(newbuf, vec->data, vec->size);
|
||||||
free(vec->data);
|
free(vec->data);
|
||||||
@ -50,7 +52,7 @@ bool vector_Pop(vector_Vector *vec, void *out_data) {
|
|||||||
|
|
||||||
void vector_Append(vector_Vector *vec, const void *data, uintptr_t n) {
|
void vector_Append(vector_Vector *vec, const void *data, uintptr_t n) {
|
||||||
uintptr_t oldsize = vec->size, addsize = vec->objectSize * n;
|
uintptr_t oldsize = vec->size, addsize = vec->objectSize * n;
|
||||||
vector_Resize(vec, oldsize + addsize);
|
vector_Resize(vec, vector_Size(vec) + n);
|
||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
memcpy(vec->data + oldsize, data, addsize);
|
memcpy(vec->data + oldsize, data, addsize);
|
||||||
@ -59,7 +61,7 @@ void vector_Append(vector_Vector *vec, const void *data, uintptr_t n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void vector_Resize(vector_Vector *vec, uintptr_t size) {
|
void vector_Resize(vector_Vector *vec, uintptr_t size) {
|
||||||
uintptr_t newsize = size;
|
uintptr_t newsize = size * vec->objectSize;
|
||||||
if (newsize > vec->cap) {
|
if (newsize > vec->cap) {
|
||||||
// grow the buffer exponentially
|
// grow the buffer exponentially
|
||||||
uint64_t newcap = vec->cap;
|
uint64_t newcap = vec->cap;
|
||||||
@ -101,3 +103,7 @@ void *vector_At(vector_Vector *vec, uintptr_t i) {
|
|||||||
void *vector_Data(vector_Vector *vec) {
|
void *vector_Data(vector_Vector *vec) {
|
||||||
return vec->data;
|
return vec->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *vector_Back(vector_Vector *vec) {
|
||||||
|
return vector_At(vec, vector_Size(vec) - 1);
|
||||||
|
}
|
||||||
|
@ -68,6 +68,11 @@ void *vector_At(vector_Vector *vec, uintptr_t i);
|
|||||||
// Data returns the data buffer.
|
// Data returns the data buffer.
|
||||||
void *vector_Data(vector_Vector *vec);
|
void *vector_Data(vector_Vector *vec);
|
||||||
|
|
||||||
|
// Back returns the last element in the vector.
|
||||||
|
//
|
||||||
|
// No boundary test is performed.
|
||||||
|
void *vector_Back(vector_Vector *vec);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user