mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
[ui] Implement dragable collapsible windows
And of course, closable.
This commit is contained in:
parent
300badc96a
commit
df40a50b91
3 changed files with 148 additions and 23 deletions
|
@ -68,6 +68,16 @@ typedef struct imui_style_s {
|
|||
imui_color_t text;
|
||||
} imui_style_t;
|
||||
|
||||
typedef struct imui_window_s {
|
||||
const char *name;
|
||||
int xpos;
|
||||
int ypos;
|
||||
int xlen;
|
||||
int ylen;
|
||||
bool is_open;
|
||||
bool is_collapsed;
|
||||
} imui_window_t;
|
||||
|
||||
imui_ctx_t *IMUI_NewContext (struct canvas_system_s canvas_sys,
|
||||
const char *font, float fontsize);
|
||||
void IMUI_DestroyContext (imui_ctx_t *ctx);
|
||||
|
@ -80,6 +90,8 @@ void IMUI_Draw (imui_ctx_t *ctx);
|
|||
|
||||
void IMUI_PushLayout (imui_ctx_t *ctx, bool vertical);
|
||||
void IMUI_PopLayout (imui_ctx_t *ctx);
|
||||
void IMUI_StartWindow (imui_ctx_t *ctx, imui_window_t *window);
|
||||
void IMUI_EndWindow (imui_ctx_t *ctx);
|
||||
|
||||
bool IMUI_Button (imui_ctx_t *ctx, const char *label);
|
||||
bool IMUI_Checkbox (imui_ctx_t *ctx, bool *flag, const char *label);
|
||||
|
@ -112,6 +124,10 @@ void IMUI_FlexibleSpace (imui_ctx_t *ctx);
|
|||
IMUI_DeferLoop (IMUI_PushLayout (IMUI_context, vertical), \
|
||||
IMUI_PopLayout (IMUI_context ))
|
||||
|
||||
#define UI_Window(window) \
|
||||
IMUI_DeferLoop (IMUI_StartWindow (IMUI_context, window), \
|
||||
IMUI_EndWindow (IMUI_context))
|
||||
|
||||
#define UI_Horizontal UI_Layout(false)
|
||||
#define UI_Vertical UI_Layout(true)
|
||||
|
||||
|
|
|
@ -156,34 +156,47 @@ Con_Debug_Draw (void)
|
|||
IMUI_BeginFrame (debug_imui);
|
||||
static int state;
|
||||
static bool flag = true;
|
||||
UI_Vertical {
|
||||
UI_Horizontal {
|
||||
if (UI_Button ("Close Debug")) {
|
||||
close_debug ();
|
||||
}
|
||||
if (flag) {
|
||||
UI_FlexibleSpace ();
|
||||
UI_Button ("abcdefghijklmnopqrstuvwxyza##1");
|
||||
}
|
||||
static imui_window_t window = {
|
||||
.name = "Test Window",
|
||||
.xpos = 50,
|
||||
.ypos = 50,
|
||||
.xlen = 400,
|
||||
.ylen = 250,
|
||||
.is_open = true,
|
||||
};
|
||||
UI_Window (&window) {
|
||||
if (!window.is_open || window.is_collapsed) {
|
||||
continue;
|
||||
}
|
||||
UI_Horizontal {
|
||||
UI_Checkbox (&flag, "hi there");
|
||||
if (flag) {
|
||||
UI_Vertical {
|
||||
UI_Horizontal {
|
||||
if (UI_Button ("Close Debug")) {
|
||||
close_debug ();
|
||||
}
|
||||
UI_FlexibleSpace ();
|
||||
if (flag) {
|
||||
UI_Button ("abcde##1");
|
||||
}
|
||||
}
|
||||
UI_Horizontal {
|
||||
UI_Checkbox (&flag, "hi there");
|
||||
UI_FlexibleSpace ();
|
||||
if (flag) {
|
||||
UI_Button ("abcdefg##2");
|
||||
}
|
||||
}
|
||||
UI_Horizontal {
|
||||
UI_Radio (&state, 0, "A");
|
||||
UI_Radio (&state, 1, "B");
|
||||
UI_Radio (&state, 2, "C");
|
||||
UI_FlexibleSpace ();
|
||||
}
|
||||
UI_Horizontal {
|
||||
UI_Button (va(0, "mem: %zd", Sys_CurrentRSS ()));
|
||||
UI_FlexibleSpace ();
|
||||
UI_Button ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst##2");
|
||||
}
|
||||
}
|
||||
UI_Horizontal {
|
||||
UI_Radio (&state, 0, "A");
|
||||
UI_Radio (&state, 1, "B");
|
||||
UI_Radio (&state, 2, "C");
|
||||
UI_FlexibleSpace ();
|
||||
}
|
||||
UI_Horizontal {
|
||||
UI_Button (va(0, "mem: %zd", Sys_CurrentRSS ()));
|
||||
UI_FlexibleSpace ();
|
||||
}
|
||||
UI_FlexibleSpace ();
|
||||
}
|
||||
|
||||
IMUI_Draw (debug_imui);
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "QF/mathlib.h"
|
||||
#include "QF/progs.h"
|
||||
#include "QF/quakeio.h"
|
||||
#include "QF/va.h"
|
||||
|
||||
#include "QF/input/event.h"
|
||||
|
||||
|
@ -90,6 +91,7 @@ struct imui_ctx_s {
|
|||
|
||||
uint32_t hot;
|
||||
uint32_t active;
|
||||
view_pos_t mouse_active;
|
||||
bool mouse_pressed;
|
||||
bool mouse_released;
|
||||
unsigned mouse_buttons;
|
||||
|
@ -632,6 +634,26 @@ check_button_state (imui_ctx_t *ctx, uint32_t entity)
|
|||
return result;
|
||||
}
|
||||
|
||||
static view_pos_t
|
||||
check_drag_delta (imui_ctx_t *ctx, uint32_t entity)
|
||||
{
|
||||
view_pos_t delta = {};
|
||||
if (ctx->active == entity) {
|
||||
delta.x = ctx->mouse_position.x - ctx->mouse_active.x;
|
||||
delta.y = ctx->mouse_position.y - ctx->mouse_active.y;
|
||||
ctx->mouse_active = ctx->mouse_position;
|
||||
if (ctx->mouse_released) {
|
||||
ctx->active = nullent;
|
||||
}
|
||||
} else if (ctx->hot == entity) {
|
||||
if (ctx->mouse_pressed) {
|
||||
ctx->mouse_active = ctx->mouse_position;
|
||||
ctx->active = entity;
|
||||
}
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
static view_t
|
||||
add_text (imui_ctx_t *ctx, view_t view, imui_state_t *state, int mode)
|
||||
{
|
||||
|
@ -703,6 +725,14 @@ set_control (imui_ctx_t *ctx, view_t view, bool active)
|
|||
};
|
||||
}
|
||||
|
||||
static void
|
||||
set_expand_x (imui_ctx_t *ctx, view_t view, int weight)
|
||||
{
|
||||
View_Control (view)->semantic_x = imui_size_expand;
|
||||
uint32_t c_percent_x = ctx->csys.imui_base + imui_percent_x;
|
||||
*(int *) Ent_AddComponent(view.id, c_percent_x, ctx->csys.reg) = weight;
|
||||
}
|
||||
|
||||
bool
|
||||
IMUI_Button (imui_ctx_t *ctx, const char *label)
|
||||
{
|
||||
|
@ -817,3 +847,69 @@ IMUI_FlexibleSpace (imui_ctx_t *ctx)
|
|||
|
||||
set_fill (ctx, view, ctx->style.background.normal);
|
||||
}
|
||||
|
||||
void
|
||||
IMUI_StartWindow (imui_ctx_t *ctx, imui_window_t *window)
|
||||
{
|
||||
if (!window->is_open) {
|
||||
return;
|
||||
}
|
||||
auto state = imui_get_state (ctx, window->name);
|
||||
uint32_t old_entity = state->entity;
|
||||
|
||||
DARRAY_APPEND (&ctx->parent_stack, ctx->current_parent);
|
||||
|
||||
auto window_view = View_New (ctx->vsys, ctx->current_parent);
|
||||
state->entity = window_view.id;
|
||||
int mode = update_hot_active (ctx, old_entity, state->entity);
|
||||
|
||||
ctx->current_parent = window_view;
|
||||
*View_Control (window_view) = (viewcont_t) {
|
||||
.gravity = grav_northwest,
|
||||
.visible = 1,
|
||||
.semantic_x = imui_size_none,
|
||||
.semantic_y = imui_size_none,
|
||||
.vertical = true,
|
||||
.active = 1,
|
||||
};
|
||||
View_SetPos (window_view, window->xpos, window->ypos);
|
||||
View_SetLen (window_view, window->xlen, window->ylen);
|
||||
|
||||
#define IMUI_context ctx
|
||||
UI_Horizontal {
|
||||
if (UI_Button (va (0, "%c##collapse_%s",
|
||||
window->is_collapsed ? '>' : 'v', window->name))) {
|
||||
window->is_collapsed = !window->is_collapsed;
|
||||
}
|
||||
|
||||
auto tb_state = imui_get_state (ctx, va (0, "%s##title_bar",
|
||||
window->name));
|
||||
uint32_t tb_old_entity = tb_state->entity;
|
||||
auto title_bar = View_New (ctx->vsys, ctx->current_parent);
|
||||
tb_state->entity = title_bar.id;
|
||||
int tb_mode = update_hot_active (ctx, tb_old_entity, tb_state->entity);
|
||||
auto delta = check_drag_delta (ctx, tb_state->entity);
|
||||
if (ctx->active == tb_state->entity) {
|
||||
window->xpos += delta.x;
|
||||
window->ypos += delta.y;
|
||||
}
|
||||
|
||||
set_control (ctx, title_bar, true);
|
||||
set_expand_x (ctx, title_bar, 100);
|
||||
set_fill (ctx, title_bar, ctx->style.foreground.color[tb_mode]);
|
||||
|
||||
auto title = add_text (ctx, title_bar, state, mode);
|
||||
View_Control (title)->gravity = grav_center;
|
||||
|
||||
if (UI_Button (va (0, "X##close_%s", window->name))) {
|
||||
window->is_open = false;
|
||||
}
|
||||
}
|
||||
#undef IMUI_context
|
||||
}
|
||||
|
||||
void
|
||||
IMUI_EndWindow (imui_ctx_t *ctx)
|
||||
{
|
||||
IMUI_PopLayout (ctx);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue