Beautiful GUIs

This commit is contained in:
Edgaru089 2024-04-24 22:23:01 +08:00
parent 317ad22de0
commit 888a7a9962
9 changed files with 148 additions and 33 deletions

20
app.c
View File

@ -16,6 +16,11 @@
#include <stdio.h> #include <stdio.h>
#ifndef RGB
#define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16))
#endif
App *app_NewApp() { App *app_NewApp() {
render_LoadBundle("bundles.txt"); render_LoadBundle("bundles.txt");
@ -30,26 +35,15 @@ App *app_NewApp() {
app->time = gametime_NewSystem(app); app->time = gametime_NewSystem(app);
app->ui = ui_NewSystem(app); app->ui = ui_NewSystem(app);
ui_RebuildUI(app->ui); ui_RebuildUI(app->ui);
ui_PushState(app->ui, ui_Running); ui_PushState(app->ui, ui_TitleMenu);
app->switch_level = NULL; app->switch_level = NULL;
app->timescale = 1.0; app->timescale = 1.0;
app->clear_color = 0; app->clear_color = RGB(40, 40, 40);
app->wantQuit = false; app->wantQuit = false;
app->paused = false; app->paused = false;
Entity *player = entity_Create(app->entity, "player");
ADD_COMPONENT(player, player);
ADD_COMPONENT(player, position);
player->position->position = vec2(500, 500);
player->position->velocity = vec2(0, 0);
ADD_COMPONENT(player, hitbox);
player->hitbox->box.lefttop = vec2(-20, -80);
app_QueueLoadLevel(app, "intro.txt");
_app_SwitchLevel(app);
return app; return app;
} }

View File

@ -1,6 +1,7 @@
#include "app.h" #include "app.h"
#include "types.h" #include "types.h"
#include "ui.h"
#include "util/tree.h" #include "util/tree.h"
#include "util/vector.h" #include "util/vector.h"
@ -46,9 +47,18 @@ void app_DebugText(App *app, vector_Vector *vec_string) {
PUSH_STRING(buf); PUSH_STRING(buf);
snprintf( snprintf(
buf, sizeof(buf) - 1, buf, sizeof(buf) - 1,
"Particle count[0]: %d\n", tree_Count(app->particle->parts[0])); "Particle count[0]: %d\n\nUI Stack:\n", tree_Count(app->particle->parts[0]));
PUSH_STRING(buf); PUSH_STRING(buf);
for (int i = 0; i < vector_Size(app->ui->state); i++) {
ui_State *s = vector_At(app->ui->state, i);
snprintf(
buf, sizeof(buf) - 1,
" %s\n", ui_StateTitle[*s]);
PUSH_STRING(buf);
}
char zero = '\0'; char zero = '\0';
vector_Push(vec_string, &zero); vector_Push(vec_string, &zero);
} }

View File

@ -227,6 +227,8 @@ void _app_SwitchLevel(App *app) {
FILE *f = fopen(app->switch_level, "r"); FILE *f = fopen(app->switch_level, "r");
if (!f) { if (!f) {
WARN("failed to open file\"%s\"", app->switch_level); WARN("failed to open file\"%s\"", app->switch_level);
free(app->switch_level);
app->switch_level = NULL;
return; return;
} }

View File

@ -11,8 +11,8 @@ extern "C" {
#endif #endif
#define SCREEN_WIDTH 1536 #define SCREEN_WIDTH 1440
#define SCREEN_HEIGHT 864 #define SCREEN_HEIGHT 810
#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__)

26
ui.c
View File

@ -90,20 +90,20 @@ void ui_Advance(System_UI *sys, Duration deltaTime) {
sys->bg.lefttop = lt; sys->bg.lefttop = lt;
sys->bg.size = vec2_Minus(rb, lt); sys->bg.size = vec2_Minus(rb, lt);
for (int i = 0; i < ui_StateCount; i++) ui_State state = ui_CurrentState(sys);
for (int j = 0; j < vector_Size(sys->parts[i]); j++) { for (int i = 0; i < vector_Size(sys->parts[state]); i++) {
ui_Part *part = (ui_Part *)vector_At(sys->parts[i], j); ui_Part *part = (ui_Part *)vector_At(sys->parts[state], i);
// Hover check // Hover check
if (box2_Contains(part->box, input_MousePosition(sys->super->input))) { if (box2_Contains(part->box, input_MousePosition(sys->super->input))) {
part->hovered = true; part->hovered = true;
part->progress = dmin(part->progress + UI_BUTTON_HOVER_SPEED * duration_Seconds(deltaTime), 1.0); part->progress = dmin(part->progress + UI_BUTTON_HOVER_SPEED * duration_Seconds(deltaTime), 1.0);
} else { } else {
part->hovered = false; part->hovered = false;
part->progress = dmax(part->progress - UI_BUTTON_HOVER_SPEED * duration_Seconds(deltaTime), 0.0); part->progress = dmax(part->progress - UI_BUTTON_HOVER_SPEED * duration_Seconds(deltaTime), 0.0);
}
part->update(sys, part, part->user, deltaTime);
} }
part->update(sys, part, part->user, deltaTime);
}
} }

2
ui.h
View File

@ -63,7 +63,7 @@ void ui_PopState(System_UI *sys);
ui_State ui_CurrentState(System_UI *sys); ui_State ui_CurrentState(System_UI *sys);
#define UI_PADDING (20) #define UI_PADDING (16)
#define UI_BACKGROUND (0) #define UI_BACKGROUND (0)
#define UI_BACKGROUND_FADE_MOVE_SPEED (20.0) #define UI_BACKGROUND_FADE_MOVE_SPEED (20.0)

View File

@ -2,12 +2,46 @@
#include "ui.h" #include "ui.h"
#include "app.h" #include "app.h"
#include "util/vector.h" #include "util/vector.h"
#include <stdio.h>
#ifndef RGB
#define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16))
#endif
static void _ui_Action_ResumeGame(System_UI *sys, ui_Part *part, uintptr_t data) { static void _ui_Action_ResumeGame(System_UI *sys, ui_Part *part, uintptr_t data) {
ui_Action_PopState(sys, part, data); ui_Action_PopState(sys, part, data);
sys->super->paused = false; sys->super->paused = false;
} }
static void _ui_Action_ReturnToTitle(System_UI *sys, ui_Part *part, uintptr_t data) {
while (vector_Size(sys->state) > 0 && ui_CurrentState(sys) != ui_TitleMenu) {
INFO("popping \"%s\"", ui_StateTitle[ui_CurrentState(sys)]);
ui_Action_PopState(sys, part, data);
}
sys->super->paused = false;
if (vector_Size(sys->state) == 0)
WARN("new state stack is now empty, ohno");
sys->super->clear_color = RGB(40, 40, 40);
// Clear the app
// see app_file.c:233
entity_Clear(sys->super->entity);
particle_Clear(sys->super->particle);
sys->super->camera->target = NULL;
}
static void _ui_Action_SelectLevel(System_UI *sys, ui_Part *part, uintptr_t data) {
const char *level = (const char *)data;
app_QueueLoadLevel(sys->super, level);
ui_Action_PushState(sys, part, (uintptr_t)ui_Running);
sys->super->paused = false;
}
static void _ui_Action_StartFromBeginning(System_UI *sys, ui_Part *part, uintptr_t data) {
_ui_Action_SelectLevel(sys, part, (uintptr_t) "intro.txt");
}
static void _ui_Action_Quit(System_UI *sys, ui_Part *part, uintptr_t data) {
sys->super->wantQuit = true;
}
#define PUSH_UI(part) \ #define PUSH_UI(part) \
@ -18,12 +52,78 @@ void ui_RebuildUI(System_UI *sys) {
vector_Vector *p; vector_Vector *p;
ui_Part _p0; ui_Part _p0;
// Title Menu
p = sys->parts[ui_TitleMenu];
vector_Clear(p);
PUSH_UI(ui_Button_New(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 250), vec2(500, 50)),
"Start from Beginning",
&_ui_Action_StartFromBeginning, 0))
PUSH_UI(ui_Button_New(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 250 + (50 + UI_PADDING)), vec2(500, 50)),
"Select Level",
&ui_Action_PushState, ui_SceneSelect))
PUSH_UI(ui_Button_New(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0 - (500 - UI_PADDING) / 4.0 - UI_PADDING / 2.0, 250 + 2 * (50 + UI_PADDING)), vec2((500 - UI_PADDING) / 2.0, 40)),
"Options",
&ui_Action_PushState, (uintptr_t)ui_Options))
PUSH_UI(ui_Button_New(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0 + (500 - UI_PADDING) / 4.0 + UI_PADDING / 2.0, 250 + 2 * (50 + UI_PADDING)), vec2((500 - UI_PADDING) / 2.0, 40)),
"Quit",
&_ui_Action_Quit, 0))
// Select Level
p = sys->parts[ui_SceneSelect];
vector_Clear(p);
PUSH_UI(ui_Button_NewLeftAligned(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 280), vec2(400, 40)),
"Introduction",
&_ui_Action_SelectLevel, (uintptr_t) "intro.txt"));
PUSH_UI(ui_Button_NewLeftAligned(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 280 + (40 + UI_PADDING / 2.0)), vec2(400, 40)),
"Scene 1",
&_ui_Action_SelectLevel, (uintptr_t) "level1.txt"));
PUSH_UI(ui_Button_NewLeftAligned(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 280 + 2 * (40 + UI_PADDING / 2.0)), vec2(400, 40)),
"Scene 2",
&_ui_Action_SelectLevel, (uintptr_t) "level2.txt"));
PUSH_UI(ui_Button_NewLeftAligned(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 280 + 3 * (40 + UI_PADDING / 2.0)), vec2(400, 40)),
"Scene 3",
&_ui_Action_SelectLevel, (uintptr_t) "level3.txt"));
PUSH_UI(ui_Button_NewLeftAligned(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0 + 100, 280 + 3 * (40 + UI_PADDING / 2.0) + (40 + UI_PADDING)), vec2(200, 40)),
"Return",
&ui_Action_PopState, 0));
// Paused // Paused
p = sys->parts[ui_Paused]; p = sys->parts[ui_Paused];
vector_Clear(p); vector_Clear(p);
PUSH_UI(ui_Button_New( PUSH_UI(ui_Button_New(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300), vec2(400, 50)), box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300), vec2(400, 40)),
"Resume Game", "Resume Game",
&_ui_Action_ResumeGame, 0)) &_ui_Action_ResumeGame, 0))
PUSH_UI(ui_Button_New(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300 + (40 + UI_PADDING)), vec2(400, 40)),
"Reselect Level",
&ui_Action_PushState, (uintptr_t)ui_SceneSelect))
PUSH_UI(ui_Button_New(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300 + 2 * (40 + UI_PADDING)), vec2(400, 40)),
"Options",
&ui_Action_PushState, (uintptr_t)ui_Options))
PUSH_UI(ui_Button_New(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300 + 3 * (40 + UI_PADDING) + UI_PADDING), vec2(400, 40)),
"Return to Title",
&_ui_Action_ReturnToTitle, 0))
// Options
p = sys->parts[ui_Options];
vector_Clear(p);
PUSH_UI(ui_Button_New(
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300), vec2(600, 50)),
"Return",
&ui_Action_PopState, 0))
} }

View File

@ -42,4 +42,9 @@ ui_Part ui_Button_New(Box2 box, const char *label, ui_ActionCallback callback, u
.free = &_ui_Button_Free}; .free = &_ui_Button_Free};
return part; return part;
} }
ui_Part ui_Button_NewLeftAligned(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 part = ui_Button_New(box, label, callback, data);
((ui_Button *)part.user)->left_aligned = true;
return part;
}

View File

@ -66,10 +66,14 @@ extern "C" void _ui_Button_Draw(System_UI *sys, ui_Part *part, void *user) {
setfillcolor(color_final); setfillcolor(color_final);
settextcolor(RGB(255, 255, 255)); settextcolor(RGB(255, 255, 255));
Box2 padded_box = part->box;
padded_box.lefttop.x += UI_PADDING;
padded_box.size.x -= 2 * UI_PADDING;
solidrectangle( solidrectangle(
(int)round(part->box.lefttop.x), (int)round(part->box.lefttop.x),
(int)round(part->box.lefttop.y), (int)round(part->box.lefttop.y),
(int)round(part->box.lefttop.x + part->box.size.x), (int)round(part->box.lefttop.x + part->box.size.x),
(int)round(part->box.lefttop.y + part->box.size.y)); (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); render_DrawTextEx(b->label, padded_box, (b->left_aligned ? DT_LEFT : DT_CENTER) | DT_VCENTER | DT_SINGLELINE);
} }