mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-16 17:01:53 +00:00
[ui] Implement a basic menu system
Menus within menu contexts automatically create menu items for the sub-menu, and menus collapse when leaf menus are select.
This commit is contained in:
parent
a6fa10b24d
commit
21a9cbc61b
6 changed files with 111 additions and 18 deletions
|
@ -465,6 +465,7 @@ qfv_step_t *QFV_FindStep (const char *step, qfv_job_t *job) __attribute__((pure)
|
|||
|
||||
struct imui_ctx_s;
|
||||
void QFV_Render_UI (struct vulkan_ctx_s *ctx, struct imui_ctx_s *imui_ctx);
|
||||
void QFV_Render_Menu (struct vulkan_ctx_s *ctx, struct imui_ctx_s *imui_ctx);
|
||||
void QFV_Render_UI_Shutdown (struct vulkan_ctx_s *ctx);
|
||||
|
||||
#endif//__QFCC__
|
||||
|
|
|
@ -89,6 +89,8 @@ typedef struct imui_window_s {
|
|||
const char *reference;
|
||||
grav_t reference_gravity;
|
||||
grav_t anchor_gravity;
|
||||
struct imui_window_s *parent; // for submenus
|
||||
bool no_collapse;
|
||||
} imui_window_t;
|
||||
|
||||
imui_ctx_t *IMUI_NewContext (struct canvas_system_s canvas_sys,
|
||||
|
@ -127,6 +129,10 @@ int IMUI_StartPanel (imui_ctx_t *ctx, imui_window_t *panel);
|
|||
int IMUI_ExtendPanel (imui_ctx_t *ctx, const char *panel_name);
|
||||
void IMUI_EndPanel (imui_ctx_t *ctx);
|
||||
|
||||
int IMUI_StartMenu (imui_ctx_t *ctx, imui_window_t *menu, bool vertical);
|
||||
void IMUI_EndMenu (imui_ctx_t *ctx);
|
||||
bool IMUI_MenuItem (imui_ctx_t *ctx, const char *label, bool collapse);
|
||||
|
||||
int IMUI_StartWindow (imui_ctx_t *ctx, imui_window_t *window);
|
||||
void IMUI_EndWindow (imui_ctx_t *ctx);
|
||||
|
||||
|
@ -168,6 +174,17 @@ void IMUI_EndWindow (imui_ctx_t *ctx);
|
|||
IMUI_DeferLoop (IMUI_ExtendPanel (IMUI_context, panel_name), \
|
||||
IMUI_EndPanel (IMUI_context))
|
||||
|
||||
#define UI_Menu(menu) \
|
||||
IMUI_DeferLoop (IMUI_StartMenu (IMUI_context, menu, true), \
|
||||
IMUI_EndMenu (IMUI_context))
|
||||
|
||||
#define UI_MenuBar(menu) \
|
||||
IMUI_DeferLoop (IMUI_StartMenu (IMUI_context, menu, false), \
|
||||
IMUI_EndMenu (IMUI_context))
|
||||
|
||||
#define UI_MenuItem(label) \
|
||||
IMUI_MenuItem (IMUI_context, label, true)
|
||||
|
||||
#define UI_Window(window) \
|
||||
IMUI_DeferLoop (IMUI_StartWindow (IMUI_context, window), \
|
||||
IMUI_EndWindow (IMUI_context))
|
||||
|
|
|
@ -495,7 +495,6 @@ static imui_window_t system_info_window = {
|
|||
static imui_window_t renderer_menu = {
|
||||
.name = "Renderer##menu",
|
||||
.group_offset = 1,
|
||||
.reference = "Renderer##menu_item",
|
||||
.reference_gravity = grav_northwest,
|
||||
.anchor_gravity = grav_southwest,
|
||||
};
|
||||
|
@ -503,20 +502,22 @@ static imui_window_t renderer_menu = {
|
|||
static void
|
||||
menu_bar (void)
|
||||
{
|
||||
UI_Horizontal {
|
||||
IMUI_Layout_SetYSize (debug_imui, imui_size_fitchildren, 0);
|
||||
if (UI_Button ("System Info##menu_item")) {
|
||||
static imui_window_t menu = {
|
||||
.name = "Debug##menu",
|
||||
.group_offset = 0,
|
||||
.is_open = true,
|
||||
.no_collapse = true,
|
||||
};
|
||||
UI_MenuBar (&menu) {
|
||||
if (UI_MenuItem ("System Info##menu_item")) {
|
||||
system_info_window.is_open = true;
|
||||
}
|
||||
if (r_funcs->debug_ui && (hs (), UI_Button ("Renderer##menu_item"))) {
|
||||
renderer_menu.is_open = true;
|
||||
if (r_funcs->debug_ui) {
|
||||
hs ();
|
||||
// create the menu so the renderer can access it
|
||||
UI_Menu (&renderer_menu);
|
||||
}
|
||||
}
|
||||
|
||||
if (r_funcs->debug_ui) {
|
||||
// create the panel so the renderer can access it
|
||||
UI_Panel (&renderer_menu);
|
||||
}
|
||||
}
|
||||
|
||||
static bool close_debug_pressed = false;
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
#include "QF/ui/shaper.h"
|
||||
#include "QF/ui/text.h"
|
||||
|
||||
#define IMUI_context ctx
|
||||
|
||||
#define c_percent_x (ctx->csys.imui_base + imui_percent_x)
|
||||
#define c_percent_y (ctx->csys.imui_base + imui_percent_y)
|
||||
#define c_reference (ctx->csys.imui_base + imui_reference)
|
||||
|
@ -84,6 +86,7 @@ typedef struct imui_state_s {
|
|||
char *label;
|
||||
uint32_t label_len;
|
||||
int key_offset;
|
||||
imui_window_t *menu;
|
||||
int16_t draw_order; // for window canvases
|
||||
uint32_t frame_count;
|
||||
uint32_t entity;
|
||||
|
@ -114,6 +117,8 @@ struct imui_ctx_s {
|
|||
struct DARRAY_TYPE(view_t) parent_stack;
|
||||
struct DARRAY_TYPE(imui_state_t *) windows;
|
||||
int16_t draw_order;
|
||||
imui_window_t *current_menu;
|
||||
imui_state_t *current_state;
|
||||
|
||||
dstring_t *dstr;
|
||||
|
||||
|
@ -188,6 +193,7 @@ imui_get_state (imui_ctx_t *ctx, const char *label)
|
|||
auto state = imui_find_state (ctx, label);
|
||||
if (state) {
|
||||
state->frame_count = ctx->frame_count;
|
||||
ctx->current_state = state;
|
||||
return state;
|
||||
}
|
||||
state = imui_state_new (ctx);
|
||||
|
@ -196,6 +202,7 @@ imui_get_state (imui_ctx_t *ctx, const char *label)
|
|||
state->key_offset = key_offset;
|
||||
state->frame_count = ctx->frame_count;
|
||||
Hash_Add (ctx->tab, state);
|
||||
ctx->current_state = state;
|
||||
return state;
|
||||
}
|
||||
|
||||
|
@ -343,6 +350,7 @@ IMUI_BeginFrame (imui_ctx_t *ctx)
|
|||
DARRAY_RESIZE (&ctx->parent_stack, 0);
|
||||
DARRAY_RESIZE (&ctx->windows, 0);
|
||||
DARRAY_RESIZE (&ctx->style_stack, 0);
|
||||
ctx->current_menu = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -702,6 +710,8 @@ void
|
|||
IMUI_Draw (imui_ctx_t *ctx)
|
||||
{
|
||||
ctx->frame_draw = Sys_LongTime ();
|
||||
ctx->mouse_pressed = false;
|
||||
ctx->mouse_released = false;
|
||||
sort_windows (ctx);
|
||||
auto ref = View_GetRef (ctx->root_view);
|
||||
Hierarchy_SetTreeMode (ref->hierarchy, false);
|
||||
|
@ -1154,7 +1164,6 @@ IMUI_StartPanel (imui_ctx_t *ctx, imui_window_t *panel)
|
|||
View_SetLen (panel_view, panel->xlen, panel->ylen);
|
||||
|
||||
auto bg = ctx->style.background.normal;
|
||||
#define IMUI_context ctx
|
||||
UI_Vertical {
|
||||
ctx->style.background.normal = 0;//FIXME style
|
||||
IMUI_Spacer (ctx, imui_size_expand, 100, imui_size_pixels, 2);
|
||||
|
@ -1168,7 +1177,6 @@ IMUI_StartPanel (imui_ctx_t *ctx, imui_window_t *panel)
|
|||
}
|
||||
IMUI_Spacer (ctx, imui_size_expand, 100, imui_size_pixels, 2);
|
||||
}
|
||||
#undef IMUI_context
|
||||
ctx->style.background.normal = bg;
|
||||
ctx->current_parent = panel_view;
|
||||
state->content = panel_view.id;
|
||||
|
@ -1193,6 +1201,68 @@ IMUI_EndPanel (imui_ctx_t *ctx)
|
|||
IMUI_PopLayout (ctx);
|
||||
}
|
||||
|
||||
int
|
||||
IMUI_StartMenu (imui_ctx_t *ctx, imui_window_t *menu, bool vertical)
|
||||
{
|
||||
menu->parent = ctx->current_menu;
|
||||
ctx->current_menu = menu;
|
||||
|
||||
if (menu->parent) {
|
||||
if (!menu->reference) {
|
||||
menu->reference = nva ("%s##item:%s", menu->name,
|
||||
menu->parent->name);
|
||||
}
|
||||
if (menu->parent->is_open) {
|
||||
UI_ExtendPanel (menu->parent->name) {
|
||||
if (IMUI_MenuItem (ctx, menu->reference, false)) {
|
||||
menu->is_open = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!menu->is_open) {
|
||||
ctx->current_menu = menu->parent;
|
||||
return 1;
|
||||
}
|
||||
|
||||
IMUI_StartPanel (ctx, menu);
|
||||
|
||||
auto state = ctx->windows.a[ctx->windows.size - 1];
|
||||
state->menu = menu;
|
||||
|
||||
auto menu_view = ctx->current_parent;
|
||||
if (vertical) {
|
||||
IMUI_Layout_SetXSize (ctx, imui_size_fitchildren, 0);
|
||||
} else {
|
||||
UI_Horizontal {
|
||||
IMUI_Layout_SetYSize (ctx, imui_size_fitchildren, 0);
|
||||
menu_view = ctx->current_parent;
|
||||
}
|
||||
}
|
||||
ctx->current_parent = menu_view;
|
||||
state->content = menu_view.id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
IMUI_EndMenu (imui_ctx_t *ctx)
|
||||
{
|
||||
IMUI_PopLayout (ctx);
|
||||
}
|
||||
|
||||
bool
|
||||
IMUI_MenuItem (imui_ctx_t *ctx, const char *label, bool collapse)
|
||||
{
|
||||
auto res = IMUI_Button (ctx, label);
|
||||
//auto state = ctx->current_state;
|
||||
if (res && collapse) {
|
||||
for (auto m = ctx->current_menu; m && !m->no_collapse; m = m->parent) {
|
||||
m->is_open = false;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
IMUI_StartWindow (imui_ctx_t *ctx, imui_window_t *window)
|
||||
{
|
||||
|
@ -1202,7 +1272,6 @@ IMUI_StartWindow (imui_ctx_t *ctx, imui_window_t *window)
|
|||
IMUI_StartPanel (ctx, window);
|
||||
auto state = ctx->windows.a[ctx->windows.size - 1];
|
||||
|
||||
#define IMUI_context ctx
|
||||
UI_Horizontal {
|
||||
char cbutton = window->is_collapsed ? '>' : 'v';
|
||||
if (UI_Button (va (0, "%c##collapse_%s", cbutton, window->name))) {
|
||||
|
@ -1233,7 +1302,6 @@ IMUI_StartWindow (imui_ctx_t *ctx, imui_window_t *window)
|
|||
window->is_open = false;
|
||||
}
|
||||
}
|
||||
#undef IMUI_context
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -372,9 +372,10 @@ vulkan_debug_ui (struct imui_ctx_s *imui_ctx)
|
|||
{
|
||||
#define IMUI_context imui_ctx
|
||||
UI_ExtendPanel ("Renderer##menu") {
|
||||
QFV_Render_UI (vulkan_ctx, imui_ctx);
|
||||
QFV_Render_Menu (vulkan_ctx, imui_ctx);
|
||||
}
|
||||
#undef IMUI_context
|
||||
QFV_Render_UI (vulkan_ctx, imui_ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -97,12 +97,17 @@ job_window (vulkan_ctx_t *ctx, imui_ctx_t *imui_ctx)
|
|||
|
||||
void
|
||||
QFV_Render_UI (vulkan_ctx_t *ctx, imui_ctx_t *imui_ctx)
|
||||
{
|
||||
job_window (ctx, imui_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
QFV_Render_Menu (vulkan_ctx_t *ctx, imui_ctx_t *imui_ctx)
|
||||
{
|
||||
auto rctx = ctx->render_context;
|
||||
if (UI_Button (va (ctx->va_ctx, "Job##%p", rctx))) {
|
||||
if (UI_MenuItem (va (ctx->va_ctx, "Job##%p", rctx))) {
|
||||
rctx->job_window->is_open = true;
|
||||
}
|
||||
job_window (ctx, imui_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in a new issue