do safer way to manage gui

This commit is contained in:
NishiOwO 2025-04-21 17:08:24 +09:00
parent c1c5d47f92
commit db496582a6
No known key found for this signature in database
GPG Key ID: 27EF69B208EB9343
4 changed files with 164 additions and 74 deletions

View File

@ -111,4 +111,13 @@ GF_EXPORT void gf_gui_draw_box(gf_gui_t* gui, int mul, double x, double y, doubl
*/
GF_EXPORT void gf_gui_set_callback(gf_gui_t* gui, gf_gui_id_t id, gf_gui_callback_t callback);
/**
* @~english
* @brief Set parent component
* @param gui GUI
* @param id Component ID
* @param parent Parent component ID
*/
GF_EXPORT void gf_gui_set_parent(gf_gui_t* gui, gf_gui_id_t id, gf_gui_id_t parent);
#endif

View File

@ -41,19 +41,12 @@ typedef union gf_gui_union_t gf_gui_union_t;
typedef void (*gf_gui_callback_t)(gf_engine_t* engine, gf_draw_t* draw, gf_gui_id_t id, int type);
/**
* @~english
* @brief Max components GUI can handle
*/
#define GF_GUI_MAX_COMPONENTS 64
/**
* @~english
* @brief GUI component types
*/
enum GF_GUI_COMPONENT_TYPES {
GF_GUI_UNUSED = -1,
GF_GUI_BUTTON
GF_GUI_BUTTON = 0
};
/**
@ -83,6 +76,9 @@ typedef union gf_gui_union_t {
* @~english
* @brief Component
*
* @var gf_gui_component_t::key
* @brief Component ID
*
* @var gf_gui_component_t::type
* @brief Component type
* @see GF_GUI_COMPONENT_TYPES
@ -107,14 +103,19 @@ typedef union gf_gui_union_t {
*
* @var gf_gui_component_t::u
* @brief Component union
*
* @var gf_gui_component_t::parent
* @brief Parent GUI component
*/
GF_DECLARE_TYPE(gui_component, {
gf_gui_id_t key;
int type;
double x;
double y;
double width;
double height;
int pressed;
gf_gui_id_t parent;
gf_gui_callback_t callback;
gf_gui_union_t u;
});
@ -137,10 +138,10 @@ GF_DECLARE_TYPE(gui_component, {
* @brief Created components
*/
GF_DECLARE_TYPE(gui, {
gf_engine_t* engine;
gf_draw_t* draw;
gf_gui_id_t pressed;
gf_gui_component_t area[GF_GUI_MAX_COMPONENTS];
gf_engine_t* engine;
gf_draw_t* draw;
gf_gui_id_t pressed;
gf_gui_component_t* area;
});
#else
typedef void* gf_gui_callback_t;

View File

@ -78,8 +78,7 @@ gf_draw_t* gf_draw_create(gf_engine_t* engine, const char* title) {
void gf_draw_reshape(gf_draw_t* draw) { gf_draw_driver_reshape(draw); }
gf_gui_id_t button1 = -1;
gf_gui_id_t button2 = -1;
int made = 0;
void gf_button_callback(gf_engine_t* engine, gf_draw_t* draw, gf_gui_id_t id, int type) {
if(type == GF_GUI_PRESS_EVENT) {
@ -91,13 +90,23 @@ void gf_button_callback(gf_engine_t* engine, gf_draw_t* draw, gf_gui_id_t id, in
void gf_draw_frame(gf_draw_t* draw) {
gf_graphic_color_t color;
color.r = color.g = color.b = color.a = 255;
if(button1 == -1) {
button1 = gf_gui_create_button(draw->gui, 0, 0, 200, 50, "\"Test\" text");
gf_gui_set_callback(draw->gui, button1, gf_button_callback);
}
if(button2 == -1) {
button2 = gf_gui_create_button(draw->gui, 100, 25, 200, 50, "\"Test\" text");
gf_gui_set_callback(draw->gui, button2, gf_button_callback);
if(made == 0) {
int i;
made = 1;
for(i = 0; i < 5; i++) {
double p = 50;
double s = 300 - i * p;
gf_gui_id_t id;
if(i > 0) {
p = (s + p) / 2 - (s / 2);
}
id = gf_gui_create_button(draw->gui, p, p, s, s, "");
if(i > 0) {
gf_gui_set_parent(draw->gui, id, id - 1);
}
}
}
if(draw->draw_3d) {
gf_graphic_draw_texture_polygon(draw, test_texture, color, GF_GRAPHIC_3D, 4,

View File

@ -5,6 +5,7 @@
#include <gf_pre.h>
/* External library */
#include <stb_ds.h>
/* Interface */
#include <gf_gui.h>
@ -24,40 +25,44 @@ gf_graphic_color_t gf_gui_base_color;
gf_graphic_color_t gf_gui_font_color;
gf_gui_t* gf_gui_create(gf_engine_t* engine, gf_draw_t* draw) {
gf_gui_t* gui = malloc(sizeof(*gui));
gf_gui_id_t i;
gf_gui_t* gui = malloc(sizeof(*gui));
memset(gui, 0, sizeof(*gui));
gui->engine = engine;
gui->draw = draw;
gui->area = NULL;
gui->pressed = -1;
GF_SET_COLOR(gf_gui_base_color, 48, 96, 48, 255);
GF_SET_COLOR(gf_gui_font_color, 256 - 32, 256 - 32, 256 - 32, 255);
for(i = 0; i < GF_GUI_MAX_COMPONENTS; i++) gui->area[i].type = -1;
return gui;
}
void gf_gui_destroy(gf_gui_t* gui) {
gf_gui_id_t i;
for(i = 0; i < GF_GUI_MAX_COMPONENTS; i++) {
gf_gui_destroy_id(gui, i);
int i;
if(gui->area != NULL) {
for(i = 0; i < hmlen(gui->area); i++) {
gf_gui_destroy_id(gui, gui->area[i].key);
}
}
gf_log_function(gui->engine, "Destroyed GUI", "");
free(gui);
}
void gf_gui_destroy_id(gf_gui_t* gui, gf_gui_id_t id) {
gf_gui_component_t* c = &gui->area[id];
switch(c->type) {
case GF_GUI_BUTTON: {
if(c->u.button.text != NULL) free(c->u.button.text);
c->u.button.text = NULL;
int ind = hmgeti(gui->area, id);
gf_gui_component_t* c;
if(ind != -1) {
c = &gui->area[ind];
switch(c->type) {
case GF_GUI_BUTTON: {
if(c->u.button.text != NULL) free(c->u.button.text);
c->u.button.text = NULL;
}
}
hmdel(gui->area, id);
}
}
c->type = GF_GUI_UNUSED;
}
/* note... left top should be the lightest in the border */
@ -84,48 +89,101 @@ void gf_gui_draw_box(gf_gui_t* gui, int mul, double x, double y, double w, doubl
gf_graphic_fill_rect(gui->draw, x + gf_gui_border_width, y + gf_gui_border_width, w - gf_gui_border_width * 2, h - gf_gui_border_width * 2, col);
}
gf_gui_component_t* gf_gui_first_unused(gf_gui_t* gui, gf_gui_id_t* id) {
gf_gui_id_t i;
for(i = 0; i < GF_GUI_MAX_COMPONENTS; i++) {
if(gui->area[i].type == GF_GUI_UNUSED) {
*id = i;
return &gui->area[i];
}
void gf_gui_create_component(gf_gui_t* gui, gf_gui_component_t* c, double x, double y, double w, double h) {
if(gui->area == NULL) {
c->key = 0;
} else {
c->key = hmlen(gui->area);
}
return NULL;
c->x = x;
c->y = y;
c->width = w;
c->height = h;
c->parent = -1;
c->pressed = 0;
c->callback = NULL;
}
gf_gui_id_t gf_gui_create_button(gf_gui_t* gui, double x, double y, double w, double h, const char* text) {
gf_gui_id_t id;
gf_gui_component_t* c = gf_gui_first_unused(gui, &id);
gf_gui_component_t c;
c->type = GF_GUI_BUTTON;
c->x = x;
c->y = y;
c->width = w;
c->height = h;
gf_gui_create_component(gui, &c, x, y, w, h);
c->pressed = 0;
c->callback = NULL;
c.type = GF_GUI_BUTTON;
c.u.button.text = malloc(strlen(text) + 1);
strcpy(c.u.button.text, text);
c->u.button.text = malloc(strlen(text) + 1);
strcpy(c->u.button.text, text);
return id;
hmputs(gui->area, c);
return c.key;
}
void gf_gui_calc_xywh_noset(gf_gui_t* gui, gf_gui_component_t* c, double* x, double* y, double* w, double* h) {
double pw = gui->draw->width;
double ph = gui->draw->height;
double bx = 0;
double by = 0;
if(c->parent != -1) {
double x2 = 0;
double y2 = 0;
double w2 = 0;
double h2 = 0;
int ind = hmgeti(gui->area, c->parent);
if(ind != -1) {
gf_gui_calc_xywh_noset(gui, &gui->area[ind], &x2, &y2, &w2, &h2);
}
pw = w2;
ph = h2;
bx = x2;
by = y2;
}
*x += bx;
if(c->x < 0) {
*x += pw;
}
*x += c->x;
*y += by;
if(c->y < 0) {
*y += ph;
}
*y += c->y;
if((*w) < c->width) {
*w = c->width;
}
if((*h) < c->height) {
*h = c->height;
}
}
void gf_gui_calc_xywh(gf_gui_t* gui, gf_gui_component_t* c, double* x, double* y, double* w, double* h) {
*x = 0;
*y = 0;
*w = 0;
*h = 0;
gf_gui_calc_xywh_noset(gui, c, x, y, w, h);
}
void gf_gui_render(gf_gui_t* gui) {
gf_gui_id_t i;
int i;
gf_input_t* input = gui->draw->input;
for(i = GF_GUI_MAX_COMPONENTS - 1; i >= 0; i--) {
gf_gui_component_t* c = &gui->area[i];
double cx = c->x;
double cy = c->y;
double cw = c->width;
double ch = c->height;
double cx;
double cy;
double cw;
double ch;
for(i = hmlen(gui->area) - 1; i >= 0; i--) {
gf_gui_component_t* c = &gui->area[i];
gf_gui_calc_xywh(gui, c, &cx, &cy, &cw, &ch);
switch(c->type) {
case GF_GUI_BUTTON: {
if(input->mouse_x != -1 && input->mouse_y != -1 && gui->pressed == -1 && (input->mouse_flag & GF_INPUT_MOUSE_LEFT_MASK) && (cx <= input->mouse_x && input->mouse_x <= cx + cw) && (cy <= input->mouse_y && input->mouse_y <= cy + ch)) {
gui->pressed = i;
gui->pressed = c->key;
} else if(gui->pressed == -1) {
c->pressed = 0;
}
@ -133,33 +191,46 @@ void gf_gui_render(gf_gui_t* gui) {
}
}
}
for(i = 0; i < GF_GUI_MAX_COMPONENTS; i++) {
gf_gui_component_t* c = &gui->area[i];
double cx = c->x;
double cy = c->y;
double cw = c->width;
double ch = c->height;
for(i = 0; i < hmlen(gui->area); i++) {
gf_gui_component_t* c = &gui->area[i];
gf_gui_calc_xywh(gui, c, &cx, &cy, &cw, &ch);
switch(c->type) {
case GF_GUI_BUTTON: {
double x = cx + cw / 2 - gf_graphic_text_width(gui->draw, GF_GUI_FONT_SIZE, c->u.button.text) / 2;
double y = cy + ch / 2 - GF_GUI_FONT_SIZE / 2;
if(gui->pressed == i) {
if(gui->pressed == c->key) {
x += gf_gui_border_width / 1;
y += gf_gui_border_width / 1;
}
gf_gui_draw_box(gui, (gui->pressed == i) ? GF_GUI_INVERT : GF_GUI_NORMAL, cx, cy, cw, ch);
gf_gui_draw_box(gui, (gui->pressed == c->key) ? GF_GUI_INVERT : GF_GUI_NORMAL, cx, cy, cw, ch);
gf_graphic_text(gui->draw, x, y, GF_GUI_FONT_SIZE, c->u.button.text, gf_gui_font_color);
break;
}
}
}
if((gui->pressed != -1) && !(input->mouse_flag & GF_INPUT_MOUSE_LEFT_MASK)) {
int ind;
if(gui->area[gui->pressed].callback != NULL) {
gui->area[gui->pressed].callback(gui->engine, gui->draw, gui->pressed, GF_GUI_PRESS_EVENT);
}
gui->area[gui->pressed].pressed = 1;
gui->pressed = -1;
ind = hmgeti(gui->area, gui->pressed);
if(ind != -1) {
gui->area[ind].pressed = 1;
}
gui->pressed = -1;
}
}
void gf_gui_set_callback(gf_gui_t* gui, gf_gui_id_t id, gf_gui_callback_t callback) { gui->area[id].callback = callback; }
void gf_gui_set_callback(gf_gui_t* gui, gf_gui_id_t id, gf_gui_callback_t callback) {
int ind = hmgeti(gui->area, id);
if(ind != -1) {
gui->area[ind].callback = callback;
}
}
void gf_gui_set_parent(gf_gui_t* gui, gf_gui_id_t id, gf_gui_id_t parent) {
int ind = hmgeti(gui->area, id);
if(ind != -1) {
gui->area[ind].parent = parent;
}
}