mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 14:20:59 +00:00
[ui] Implement event handling in imui
Button presses work nicely thanks to both Casey Muratori and Darian (for clearing up some of Casey's comments about `hot`).
This commit is contained in:
parent
e89b5a88fa
commit
ed5ef3a5fb
3 changed files with 152 additions and 8 deletions
|
@ -33,6 +33,7 @@
|
|||
|
||||
typedef struct imui_ctx_s imui_ctx_t;
|
||||
struct canvas_system_s;
|
||||
struct IE_event_s;
|
||||
|
||||
typedef enum IMUI_SizeKind {
|
||||
IMUI_SizeKind_Null,
|
||||
|
@ -64,6 +65,8 @@ void IMUI_DestroyContext (imui_ctx_t *ctx);
|
|||
|
||||
void IMUI_SetVisible (imui_ctx_t *ctx, bool visible);
|
||||
void IMUI_SetSize (imui_ctx_t *ctx, int xlen, int ylen);
|
||||
void IMUI_ProcessEvent (imui_ctx_t *ctx, const struct IE_event_s *ie_event);
|
||||
void IMUI_BeginFrame (imui_ctx_t *ctx);
|
||||
void IMUI_Draw (imui_ctx_t *ctx);
|
||||
|
||||
bool IMUI_Button (imui_ctx_t *ctx, const char *label);
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#endif
|
||||
|
||||
#include "QF/cvar.h"
|
||||
#include "QF/keys.h"
|
||||
#include "QF/sys.h"
|
||||
|
||||
#include "QF/input/event.h"
|
||||
|
||||
|
@ -17,7 +19,9 @@
|
|||
#include "cl_console.h"
|
||||
|
||||
static int debug_event_id;
|
||||
static int debug_saved_focus;
|
||||
static imui_ctx_t *debug_imui;
|
||||
static int64_t debug_enable_time;
|
||||
#define IMUI_context debug_imui
|
||||
|
||||
bool con_debug;
|
||||
|
@ -54,6 +58,10 @@ con_debug_f (void *data, const cvar_t *cvar)
|
|||
Con_Show_Mouse (con_debug);
|
||||
if (debug_imui) {
|
||||
IMUI_SetVisible (debug_imui, con_debug);
|
||||
debug_enable_time = Sys_LongTime ();
|
||||
if (!con_debug) {
|
||||
IE_Set_Focus (debug_saved_focus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,11 +78,36 @@ debug_app_window (const IE_event_t *ie_event)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
debug_mouse (const IE_event_t *ie_event)
|
||||
{
|
||||
IMUI_ProcessEvent (debug_imui, ie_event);
|
||||
}
|
||||
|
||||
static void
|
||||
close_debug (void)
|
||||
{
|
||||
con_debug = false;
|
||||
con_debug_f (0, &con_debug_cvar);
|
||||
}
|
||||
|
||||
static void
|
||||
debug_key (const IE_event_t *ie_event)
|
||||
{
|
||||
int shift = ie_event->key.shift & ~(ies_capslock | ies_numlock);
|
||||
if (ie_event->key.code == QFK_ESCAPE && shift == ies_control) {
|
||||
close_debug ();
|
||||
}
|
||||
IMUI_ProcessEvent (debug_imui, ie_event);
|
||||
}
|
||||
|
||||
static int
|
||||
debug_event_handler (const IE_event_t *ie_event, void *data)
|
||||
{
|
||||
static void (*handlers[ie_event_count]) (const IE_event_t *ie_event) = {
|
||||
[ie_app_window] = debug_app_window,
|
||||
[ie_mouse] = debug_mouse,
|
||||
[ie_key] = debug_key,
|
||||
};
|
||||
if ((unsigned) ie_event->type >= ie_event_count
|
||||
|| !handlers[ie_event->type]) {
|
||||
|
@ -110,7 +143,17 @@ Con_Debug_Shutdown (void)
|
|||
void
|
||||
Con_Debug_Draw (void)
|
||||
{
|
||||
UI_Button ("Hi there!");
|
||||
if (debug_enable_time && Sys_LongTime () - debug_enable_time > 1000) {
|
||||
debug_saved_focus = IE_Get_Focus ();
|
||||
IE_Set_Focus (debug_event_id);
|
||||
debug_enable_time = 0;
|
||||
}
|
||||
|
||||
IMUI_BeginFrame (debug_imui);
|
||||
|
||||
if (UI_Button ("Close Debug")) {
|
||||
close_debug ();
|
||||
}
|
||||
|
||||
IMUI_Draw (debug_imui);
|
||||
}
|
||||
|
|
112
libs/ui/imui.c
112
libs/ui/imui.c
|
@ -38,6 +38,8 @@
|
|||
#include "QF/progs.h"
|
||||
#include "QF/quakeio.h"
|
||||
|
||||
#include "QF/input/event.h"
|
||||
|
||||
#include "QF/ui/canvas.h"
|
||||
#include "QF/ui/font.h"
|
||||
#include "QF/ui/imui.h"
|
||||
|
@ -50,7 +52,6 @@ typedef struct imui_state_s {
|
|||
uint32_t label_len;
|
||||
int key_offset;
|
||||
uint32_t entity;
|
||||
bool pressed;
|
||||
} imui_state_t;
|
||||
|
||||
struct imui_ctx_s {
|
||||
|
@ -64,6 +65,21 @@ struct imui_ctx_s {
|
|||
PR_RESMAP (imui_state_t) state_map;
|
||||
imui_state_t *states;
|
||||
font_t *font;
|
||||
|
||||
int64_t frame_start;
|
||||
int64_t frame_draw;
|
||||
int64_t frame_end;
|
||||
uint32_t framecount;
|
||||
uint32_t new_hot;
|
||||
uint32_t hot;
|
||||
uint32_t active;
|
||||
bool mouse_pressed;
|
||||
bool mouse_released;
|
||||
unsigned mouse_buttons;
|
||||
view_pos_t mouse_position;
|
||||
unsigned shift;
|
||||
int key_code;
|
||||
int unicode;
|
||||
};
|
||||
|
||||
static imui_state_t *
|
||||
|
@ -138,6 +154,10 @@ IMUI_NewContext (canvas_system_t canvas_sys, const char *font, float fontsize)
|
|||
.tsys = { canvas_sys.reg, canvas_sys.view_base, canvas_sys.text_base },
|
||||
.root_view = Canvas_GetRootView (canvas_sys, canvas),
|
||||
.tab = Hash_NewTable (511, imui_state_getkey, 0, ctx, &ctx->hashctx),
|
||||
.new_hot = nullent,
|
||||
.hot = nullent,
|
||||
.active = nullent,
|
||||
.mouse_position = {-1, -1},
|
||||
};
|
||||
|
||||
auto fpath = Font_SystemFont (font);
|
||||
|
@ -182,10 +202,87 @@ IMUI_SetSize (imui_ctx_t *ctx, int xlen, int ylen)
|
|||
View_UpdateHierarchy (ctx->root_view);
|
||||
}
|
||||
|
||||
void
|
||||
IMUI_ProcessEvent (imui_ctx_t *ctx, const IE_event_t *ie_event)
|
||||
{
|
||||
if (ie_event->type == ie_mouse) {
|
||||
auto m = &ie_event->mouse;
|
||||
ctx->mouse_position = (view_pos_t) { m->x, m->y };
|
||||
|
||||
unsigned old = ctx->mouse_buttons & 1;
|
||||
unsigned new = m->buttons & 1;
|
||||
ctx->mouse_pressed = (old ^ new) & new;
|
||||
ctx->mouse_released = (old ^ new) & !new;
|
||||
ctx->mouse_buttons = m->buttons;
|
||||
} else {
|
||||
auto k = &ie_event->key;
|
||||
//printf ("imui: %d %d %x\n", k->code, k->unicode, k->shift);
|
||||
ctx->shift = k->shift;
|
||||
ctx->key_code = k->code;
|
||||
ctx->unicode = k->unicode;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IMUI_BeginFrame (imui_ctx_t *ctx)
|
||||
{
|
||||
ctx->frame_start = Sys_LongTime ();
|
||||
ctx->framecount++;
|
||||
ctx->hot = ctx->new_hot;
|
||||
ctx->new_hot = nullent;
|
||||
}
|
||||
|
||||
void
|
||||
IMUI_Draw (imui_ctx_t *ctx)
|
||||
{
|
||||
ctx->frame_draw = Sys_LongTime ();
|
||||
|
||||
View_UpdateHierarchy (ctx->root_view);
|
||||
ctx->frame_end = Sys_LongTime ();
|
||||
}
|
||||
|
||||
static bool
|
||||
check_button_state (imui_ctx_t *ctx, uint32_t entity)
|
||||
{
|
||||
bool result = false;
|
||||
if (ctx->active == entity) {
|
||||
if (ctx->mouse_released) {
|
||||
result = ctx->hot == entity;
|
||||
ctx->active = nullent;
|
||||
}
|
||||
} else if (ctx->hot == entity) {
|
||||
if (ctx->mouse_pressed) {
|
||||
ctx->active = entity;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
check_inside (imui_ctx_t *ctx, view_pos_t pos, view_pos_t len, uint32_t entity)
|
||||
{
|
||||
auto mp = ctx->mouse_position;
|
||||
if (mp.x >= pos.x && mp.y >= pos.y
|
||||
&& mp.x < pos.x + len.x && mp.y < pos.y + len.y) {
|
||||
if (ctx->active == entity || ctx->active == nullent) {
|
||||
ctx->new_hot = entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static view_t
|
||||
add_text (view_t view, imui_state_t *state, imui_ctx_t *ctx)
|
||||
{
|
||||
uint32_t c_glyphs = ctx->csys.base + canvas_glyphs;
|
||||
uint32_t c_passage_glyphs = ctx->csys.text_base + text_passage_glyphs;
|
||||
auto reg = ctx->csys.reg;
|
||||
|
||||
auto text = Text_StringView (ctx->tsys, view, ctx->font,
|
||||
state->label, state->label_len, 0, 0);
|
||||
View_SetVisible (text, 1);
|
||||
Ent_SetComponent (text.id, c_glyphs, reg,
|
||||
Ent_GetComponent (text.id, c_passage_glyphs, reg));
|
||||
return text;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -203,15 +300,16 @@ IMUI_Button (imui_ctx_t *ctx, const char *label)
|
|||
View_SetGravity (view, grav_northwest);
|
||||
View_SetResize (view, 0, 0);
|
||||
|
||||
auto text = Text_StringView (ctx->tsys, view, ctx->font,
|
||||
state->label, state->label_len, 0, 0);
|
||||
View_SetVisible (text, 1);
|
||||
Ent_SetComponent (text.id, ctx->csys.base + canvas_glyphs, ctx->csys.reg,
|
||||
Ent_GetComponent (text.id, ctx->csys.text_base + text_passage_glyphs, ctx->csys.reg));
|
||||
auto text = add_text (view, state, ctx);
|
||||
auto len = View_GetLen (text);
|
||||
View_SetLen (view, len.x, len.y);
|
||||
}
|
||||
return state->pressed;
|
||||
auto view = View_FromEntity (ctx->vsys, state->entity);
|
||||
auto len = View_GetLen (view);
|
||||
auto pos = View_GetAbs (view);
|
||||
bool result = check_button_state (ctx, state->entity);
|
||||
check_inside (ctx, pos, len, state->entity);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
Loading…
Reference in a new issue