mirror of
https://github.com/nzp-team/quakec.git
synced 2024-11-22 03:41:15 +00:00
Menu: Start of MenuQC integration
This commit is contained in:
parent
8cc9296371
commit
6d0ee6b766
9 changed files with 2395 additions and 8 deletions
7
progs/fte-menu.src
Normal file
7
progs/fte-menu.src
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
../../build/pc/menu.dat
|
||||||
|
|
||||||
|
../source/menu/defs/fte.qc
|
||||||
|
../source/menu/defs/custom.qc
|
||||||
|
../source/shared/sui_sys.qc
|
||||||
|
../source/menu/menu.qc
|
||||||
|
../source/menu/main.qc
|
|
@ -581,20 +581,16 @@ noref void(float width, float height, float menushown) CSQC_UpdateView =
|
||||||
//does what you think it does
|
//does what you think it does
|
||||||
renderscene();
|
renderscene();
|
||||||
|
|
||||||
if(in_menu)
|
if (!menushown)
|
||||||
{
|
|
||||||
//in menu.qc
|
|
||||||
Draw_Menu();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
HUD_Draw(g_width, g_height);
|
HUD_Draw(g_width, g_height);
|
||||||
}
|
}
|
||||||
if(serverkey("constate") != "active" && serverkey("disconnected"))
|
|
||||||
|
/*if(serverkey("constate") != "active" && serverkey("disconnected"))
|
||||||
{
|
{
|
||||||
drawfill('0 0 0', [width, height, 0], '0.2 0.4 0.7', 1, 0);
|
drawfill('0 0 0', [width, height, 0], '0.2 0.4 0.7', 1, 0);
|
||||||
drawstring([width/2 - 60, height/2, 0], "Loading...", [16,16,0],[1,1,1],1,0);
|
drawstring([width/2 - 60, height/2, 0], "Loading...", [16,16,0],[1,1,1],1,0);
|
||||||
}
|
}*/
|
||||||
};
|
};
|
||||||
|
|
||||||
noref float(string cmd) CSQC_ConsoleCommand =
|
noref float(string cmd) CSQC_ConsoleCommand =
|
||||||
|
|
0
source/menu/defs/custom.qc
Normal file
0
source/menu/defs/custom.qc
Normal file
1049
source/menu/defs/fte.qc
Normal file
1049
source/menu/defs/fte.qc
Normal file
File diff suppressed because it is too large
Load diff
116
source/menu/main.qc
Normal file
116
source/menu/main.qc
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
float menu_active;
|
||||||
|
float splash_time;
|
||||||
|
void() m_open;
|
||||||
|
|
||||||
|
void() m_init =
|
||||||
|
{
|
||||||
|
splash_time = time + 2.5;
|
||||||
|
registercommand("togglemenu2");
|
||||||
|
// drawfont = loadfont("", "Courier Prime Code", "12,16,24,32,48,64,72,128,256,512", -1, 0, 0);
|
||||||
|
setcursormode(TRUE,"gfx/xhair", [16, 16], cvar("vid_conautoscale"));
|
||||||
|
current_menu = MENU_MAIN;
|
||||||
|
m_open();
|
||||||
|
};
|
||||||
|
|
||||||
|
vector() randomofs = { return [random() - 0.5, random() - 0.5] * 2; };
|
||||||
|
|
||||||
|
void(vector screensize) m_draw =
|
||||||
|
{
|
||||||
|
// clearscene();
|
||||||
|
|
||||||
|
|
||||||
|
vector realsize = getproperty(VF_SCREENPSIZE);
|
||||||
|
float target_conauto = 2;
|
||||||
|
if (realsize_y < 600) target_conauto = 1;
|
||||||
|
else if (realsize_y < 1200) target_conauto = 2;
|
||||||
|
else target_conauto = 4;
|
||||||
|
|
||||||
|
if (target_conauto != cvar("vid_conautoscale")) localcmd(sprintf("vid_conautoscale %f\n", target_conauto));
|
||||||
|
|
||||||
|
|
||||||
|
sui_begin(screensize_x, screensize_y);
|
||||||
|
|
||||||
|
if (menu_active)
|
||||||
|
root_menu(screensize);
|
||||||
|
else {
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]);
|
||||||
|
sui_text([0, 64], MENU_TEXT_LARGE, "NOT ACTIVE.", [1, 1, 1], 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*if (time < splash_time)
|
||||||
|
{
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]);
|
||||||
|
float diff = splash_time - time;
|
||||||
|
float a;
|
||||||
|
if (diff > 2.5)
|
||||||
|
{
|
||||||
|
a = 1 - (diff - 2.5) * 2;
|
||||||
|
float xstretch = (diff - 2.5) * 4;
|
||||||
|
sui_fill([0, 0], screensize, '0 0 0', 1, 0);
|
||||||
|
sui_pic(randomofs() * 1, [screensize_y * (0.7 + xstretch), screensize_y * 0.7], "gfx/splash.tga", '1 1 1', a * 0.75, 1);
|
||||||
|
sui_pic(randomofs() * 1, [screensize_y * (0.7 + xstretch), screensize_y * 0.7], "gfx/splash.tga", '1 1 1', a * 0.75, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a = diff * 0.6;
|
||||||
|
sui_fill([0, 0], screensize, '0 0 0', a * 2, 0);
|
||||||
|
sui_pic(randomofs() * a, [screensize_y * 0.7, screensize_y * 0.7], "gfx/splash.tga", '1 1 1', a, 1);
|
||||||
|
sui_pic(randomofs() * a, [screensize_y * (0.7 + random() * 0.05), screensize_y * 0.7], "gfx/splash.tga", '1 1 1', a * 0.5, 1);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
sui_end();
|
||||||
|
};
|
||||||
|
|
||||||
|
void() m_close =
|
||||||
|
{
|
||||||
|
setkeydest(0);
|
||||||
|
menu_active = FALSE;
|
||||||
|
};
|
||||||
|
|
||||||
|
void() m_open =
|
||||||
|
{
|
||||||
|
setkeydest(2);
|
||||||
|
menu_active = TRUE;
|
||||||
|
};
|
||||||
|
|
||||||
|
float(float evtype, float scanx, float chary, float devid) Menu_InputEvent =
|
||||||
|
{
|
||||||
|
float used = sui_input_event(evtype, scanx, chary, devid);
|
||||||
|
|
||||||
|
if (evtype == IE_KEYDOWN && !used)
|
||||||
|
{
|
||||||
|
string cmd = getkeybind(scanx);
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case "togglemenu":
|
||||||
|
m_close();
|
||||||
|
return TRUE;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
};
|
||||||
|
|
||||||
|
float(string cmd) m_consolecommand =
|
||||||
|
{
|
||||||
|
tokenize(cmd);
|
||||||
|
switch (argv(0))
|
||||||
|
{
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
};
|
||||||
|
|
||||||
|
void(float wantmode) m_toggle =
|
||||||
|
{
|
||||||
|
if (menu_active) m_close();
|
||||||
|
else m_open();
|
||||||
|
};
|
||||||
|
|
||||||
|
void() m_shutdown =
|
||||||
|
{
|
||||||
|
};
|
267
source/menu/menu.qc
Normal file
267
source/menu/menu.qc
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
vector MENU_BG = '0.2 0.3 0.4';
|
||||||
|
vector MENU_BG_DARK = '0.1 0.15 0.2';
|
||||||
|
vector MENU_BORDER = '0.3 0.4 0.5';
|
||||||
|
vector MENU_BUTTON = '0.3 0.4 0.5';
|
||||||
|
vector MENU_BUTTON_BORDER = '0.35 0.45 0.55';
|
||||||
|
vector MENU_TEXT_1 = '1 1 1';
|
||||||
|
vector MENU_TEXT_2 = '0.7 0.75 0.75';
|
||||||
|
vector MENU_HIGHLIGHT = '1 1 1';
|
||||||
|
vector MENU_DARKEN = '1 1 1';
|
||||||
|
|
||||||
|
vector MENU_TEXT_SMALL = '8 8 0';
|
||||||
|
vector MENU_TEXT_MEDIUM = '16 16 0';
|
||||||
|
vector MENU_TEXT_LARGE = '24 24 0';
|
||||||
|
|
||||||
|
void() input_tester =
|
||||||
|
{
|
||||||
|
float char = 0;
|
||||||
|
float scan = 0;
|
||||||
|
string printme = "";
|
||||||
|
while (sui_get_input(char, scan))
|
||||||
|
{
|
||||||
|
printme = strcat(printme, chr2str(char));
|
||||||
|
}
|
||||||
|
if (printme != "") printf("INPUT: %s\n", printme);
|
||||||
|
};
|
||||||
|
|
||||||
|
void(string id, vector pos, vector size, float maxlen, __inout string text, __inout float cursor) text_input_control =
|
||||||
|
{
|
||||||
|
vector textsize = [size_y - 4, size_y - 4];
|
||||||
|
sui_push_frame(pos, size);
|
||||||
|
vector basecolor = sui_is_hovered(id) ? MENU_BG_DARK + MENU_HIGHLIGHT * 0.08 : MENU_BG_DARK;
|
||||||
|
sui_fill([0, 0], size, basecolor, 0.6, 0);
|
||||||
|
|
||||||
|
sui_text_input(id, [0, 0], size, text, cursor);
|
||||||
|
|
||||||
|
sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]);
|
||||||
|
float focused = sui_is_last_clicked(id);
|
||||||
|
// Under focus
|
||||||
|
focused ? sui_border_box([0, 0], size, 1, MENU_BORDER, 0.6, 0) : 0;
|
||||||
|
|
||||||
|
sui_push_frame([2, 0], [size_x - 4, size_y - 4]);
|
||||||
|
|
||||||
|
float cursorx;
|
||||||
|
if (stringwidth(text, 1, textsize) > size_x - 4)
|
||||||
|
{
|
||||||
|
sui_clip_to_frame();
|
||||||
|
cursorx = 0;
|
||||||
|
sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]);
|
||||||
|
sui_text([0, 0], textsize, text, MENU_TEXT_1, 1, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cursorx = stringwidth(substring(text, 0, cursor), 1, textsize);
|
||||||
|
sui_text([0, 0], textsize, text, MENU_TEXT_1, 1, 0);
|
||||||
|
}
|
||||||
|
if (focused)
|
||||||
|
{
|
||||||
|
sui_fill([cursorx, 0], [2, textsize_y], MENU_TEXT_1, fabs(sin(time * 4)), 0);
|
||||||
|
}
|
||||||
|
sui_reset_clip();
|
||||||
|
sui_pop_frame();
|
||||||
|
|
||||||
|
sui_pop_frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
float(string id, vector pos, vector size, string text) my_button =
|
||||||
|
{
|
||||||
|
sui_push_frame(pos, size);
|
||||||
|
vector basecolor = sui_is_hovered(id) ? MENU_BUTTON + MENU_HIGHLIGHT * 0.1 : MENU_BUTTON;
|
||||||
|
basecolor = sui_is_held(id) ? MENU_BUTTON - MENU_DARKEN * 0.1 : basecolor;
|
||||||
|
sui_fill([0, 0], size, basecolor, 0.6, 0);
|
||||||
|
sui_border_box([0, 0], size, 1, MENU_BUTTON_BORDER, 0.4, 0);
|
||||||
|
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]);
|
||||||
|
sui_text([0, 0], MENU_TEXT_SMALL, text, MENU_TEXT_1, 1, 0);
|
||||||
|
sui_action_element([0, 0], size, id, sui_noop);
|
||||||
|
sui_pop_frame();
|
||||||
|
|
||||||
|
return sui_is_clicked(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void(string id, vector pos, vector size, vector minmaxsteps, __inout float value) my_slider =
|
||||||
|
{
|
||||||
|
sui_push_frame(pos, size);
|
||||||
|
|
||||||
|
value = sui_slidercontrol(id, [0, 0], size, minmaxsteps, value, sui_slider_noop);
|
||||||
|
float maxval = minmaxsteps[1];
|
||||||
|
float sliderx = (value / maxval) * size_x;
|
||||||
|
sui_fill([0, size_y * 0.25], [size_x, size_y * 0.5], MENU_BG_DARK, 1.0, 0);
|
||||||
|
|
||||||
|
float is_active = sui_is_held(id) || (sui_is_hovered(id) && !sui_click_held());
|
||||||
|
vector slider_ctrl_color = is_active ? MENU_BUTTON + MENU_HIGHLIGHT * 0.1 : MENU_BUTTON;
|
||||||
|
sui_fill([sliderx - 2, 0], [4, size_y], slider_ctrl_color, 1.0, 0);
|
||||||
|
|
||||||
|
sui_pop_frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
void(vector pos, vector size, vector minmaxsteps, string cvar_s, string name, string format) cvar_slider =
|
||||||
|
{
|
||||||
|
float current = cvar(cvar_s);
|
||||||
|
float old = current;
|
||||||
|
sui_push_frame(pos, [size_x, size_y * 0.5 - 4]);
|
||||||
|
sui_text([0, 0], MENU_TEXT_SMALL, name, MENU_TEXT_1, 1, 0);
|
||||||
|
sui_set_align([SUI_ALIGN_END, SUI_ALIGN_START]);
|
||||||
|
sui_text([0, 0], MENU_TEXT_SMALL, sprintf(format, current), MENU_TEXT_1, 1, 0);
|
||||||
|
sui_pop_frame();
|
||||||
|
my_slider(strcat(cvar_s, "sldr"), [pos_x, pos_y + size_y * 0.5], [size_x, size_y * 0.5], minmaxsteps, current);
|
||||||
|
if (current != old) cvar_set(cvar_s, ftos(current));
|
||||||
|
};
|
||||||
|
|
||||||
|
struct name_command {
|
||||||
|
string name;
|
||||||
|
string command;
|
||||||
|
};
|
||||||
|
|
||||||
|
name_command bindlist[] =
|
||||||
|
{
|
||||||
|
{ "Forward", "+forward" },
|
||||||
|
{ "Back", "+back" },
|
||||||
|
{ "Left", "+moveleft" },
|
||||||
|
{ "Right", "+moveright" },
|
||||||
|
{ "Jump", "+jump" }
|
||||||
|
};
|
||||||
|
|
||||||
|
void(string id, vector pos, vector size, string name, string command) bind_button =
|
||||||
|
{
|
||||||
|
sui_push_frame(pos, size);
|
||||||
|
sui_set_align([SUI_ALIGN_START, SUI_ALIGN_CENTER]);
|
||||||
|
string key = sui_binder(id, [0, 0], size, name, command);
|
||||||
|
if (sui_is_hovered(id)) sui_fill([0, 0], size, MENU_HIGHLIGHT, 0.1, 0);
|
||||||
|
sui_text([6, 0], MENU_TEXT_SMALL, name, MENU_TEXT_1, 1, 0);
|
||||||
|
sui_set_align([SUI_ALIGN_END, SUI_ALIGN_CENTER]);
|
||||||
|
sui_text([-6, 0], MENU_TEXT_SMALL, key, MENU_TEXT_1, 1, 0);
|
||||||
|
|
||||||
|
sui_pop_frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void(string id, vector pos, vector size, __inout vector scrollofs) bind_list =
|
||||||
|
{
|
||||||
|
sui_fill(pos, size, MENU_BG_DARK, 0.75, 0);
|
||||||
|
sui_list_view_begin(strcat(id, "scrl"), pos, size, [size_x - 6, 24], bindlist.length, scrollofs, [0, 6]);
|
||||||
|
vector listitem_pos = '0 0 0';
|
||||||
|
for (float index = sui_list_item(listitem_pos); index > -1; index = sui_list_item(listitem_pos))
|
||||||
|
{
|
||||||
|
sui_push_frame(listitem_pos, [size_x - 6, 24]);
|
||||||
|
bind_button(strcat(id, ftos(index)), [0, 0], [size_x - 6, 24], bindlist[index].name, bindlist[index].command);
|
||||||
|
sui_pop_frame();
|
||||||
|
}
|
||||||
|
sui_list_view_end();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
float current_menu;
|
||||||
|
const float MENU_MAIN = 1;
|
||||||
|
const float MENU_SETTINGS = 2;
|
||||||
|
const float MENU_HELP = 3;
|
||||||
|
|
||||||
|
vector binds_scroll;
|
||||||
|
void() settings_menu =
|
||||||
|
{
|
||||||
|
vector pos = [0, 0];
|
||||||
|
vector size = [360, 280];
|
||||||
|
|
||||||
|
sui_push_frame(pos, size);
|
||||||
|
|
||||||
|
sui_fill([0, 0], size, MENU_BG, 0.75, 0);
|
||||||
|
sui_border_box([0, 0], size, 2, MENU_BORDER, 0.3, 0);
|
||||||
|
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]);
|
||||||
|
sui_text([0, 4], MENU_TEXT_MEDIUM, "Settings", MENU_TEXT_1, 1, 0);
|
||||||
|
|
||||||
|
|
||||||
|
sui_set_align([SUI_ALIGN_START, SUI_ALIGN_START]);
|
||||||
|
|
||||||
|
float xpos = 8;
|
||||||
|
float ypos = 32;
|
||||||
|
float width = size_x * 0.5 - 8 * 2;
|
||||||
|
sui_text([xpos, ypos], MENU_TEXT_SMALL, "Controls", MENU_TEXT_1, 1, 0);
|
||||||
|
ypos += 16;
|
||||||
|
bind_list("bindlist", [xpos, ypos], [width, 160], binds_scroll);
|
||||||
|
ypos += 160 + 8;
|
||||||
|
|
||||||
|
cvar_slider([xpos, ypos], [width, 32], [0.1, 10], "sensitivity", "Sensitivity", "%.2f");
|
||||||
|
ypos += 32;
|
||||||
|
|
||||||
|
ypos = 32;
|
||||||
|
xpos = 8 + width + 8 + 8;
|
||||||
|
|
||||||
|
cvar_slider([xpos, ypos], [width, 32], [0, 1], "volume", "Volume", "%.2f");
|
||||||
|
ypos += 32 + 4;
|
||||||
|
cvar_slider([xpos, ypos], [width, 32], [0, 1], "musicvolume", "Music Volume", "%.2f");
|
||||||
|
ypos += 32 + 4 + 8;
|
||||||
|
|
||||||
|
sui_text([xpos, ypos], MENU_TEXT_SMALL, "Video", MENU_TEXT_1, 1, 0);
|
||||||
|
ypos += 16;
|
||||||
|
my_button("fs_btn", [xpos, ypos], [width, 20], "Fullscreen") ? localcmd("vid_fullscreen 2; vid_restart\n") : 0;
|
||||||
|
ypos += 24;
|
||||||
|
my_button("wn_btn", [xpos, ypos], [width, 20], "Windowed") ? localcmd("vid_fullscreen 0; vid_width 1024; vid_height 768; vid_restart\n") : 0;
|
||||||
|
ypos += 24;
|
||||||
|
sui_text([xpos, ypos], MENU_TEXT_SMALL, "Window can be resized.", MENU_TEXT_1, 0.8, 0);
|
||||||
|
ypos += 16;
|
||||||
|
sui_set_align([SUI_ALIGN_END, SUI_ALIGN_END]);
|
||||||
|
my_button("stg_back", [-8, -8], [80, 20], "Back") ? current_menu = MENU_MAIN : 0;
|
||||||
|
|
||||||
|
sui_pop_frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
void() help_menu =
|
||||||
|
{
|
||||||
|
vector pos = [0, 0];
|
||||||
|
vector size = [360, 280];
|
||||||
|
|
||||||
|
sui_push_frame(pos, size);
|
||||||
|
|
||||||
|
sui_fill([0, 0], size, MENU_BG, 0.75, 0);
|
||||||
|
sui_border_box([0, 0], size, 2, MENU_BORDER, 0.3, 0);
|
||||||
|
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]);
|
||||||
|
sui_text([0, 4], MENU_TEXT_MEDIUM, "Help", MENU_TEXT_1, 1, 0);
|
||||||
|
|
||||||
|
float xpos = 0;
|
||||||
|
float ypos = 32;
|
||||||
|
sui_text([xpos, ypos], MENU_TEXT_SMALL, "Bunch of Help and About", MENU_TEXT_1, 1, 0);
|
||||||
|
|
||||||
|
sui_set_align([SUI_ALIGN_END, SUI_ALIGN_END]);
|
||||||
|
my_button("hlp_back", [-8, -8], [80, 20], "Back") ? current_menu = MENU_MAIN : 0;
|
||||||
|
|
||||||
|
sui_pop_frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
void() main_menu =
|
||||||
|
{
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]);
|
||||||
|
sui_text([0, 64], MENU_TEXT_LARGE, "Title Screen", [1, 1, 1], 1, 0);
|
||||||
|
|
||||||
|
vector pos = [0, -24];
|
||||||
|
vector size = [120, 140];
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_END]);
|
||||||
|
sui_push_frame(pos, size);
|
||||||
|
|
||||||
|
sui_fill([0, 0], size, MENU_BG, 0.3, 0);
|
||||||
|
sui_border_box([0, 0], size, 2, MENU_BORDER, 0.2, 0);
|
||||||
|
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_START]);
|
||||||
|
|
||||||
|
my_button("mm_start", [0, 8], [size_x - 16, 20], "Start Game") ? localcmd("map ndu\n") : 0;
|
||||||
|
my_button("mm_settings", [0, 8 + 24], [size_x - 16, 20], "Settings") ? current_menu = MENU_SETTINGS : 0;
|
||||||
|
my_button("mm_help", [0, 8 + 48], [size_x - 16, 20], "Help") ? current_menu = MENU_HELP : 0;
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_END]);
|
||||||
|
my_button("mm_quit", [0, -8], [size_x - 16, 20], "Quit") ? localcmd("quit\n") : 0;
|
||||||
|
sui_pop_frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
void(vector size) root_menu =
|
||||||
|
{
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]);
|
||||||
|
sui_fill([0, 0], size, '0 0 0', 0.5, 0);
|
||||||
|
switch (current_menu)
|
||||||
|
{
|
||||||
|
case MENU_MAIN: main_menu(); break;
|
||||||
|
case MENU_SETTINGS: settings_menu(); break;
|
||||||
|
case MENU_HELP: help_menu();
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
};
|
940
source/shared/sui_sys.qc
Normal file
940
source/shared/sui_sys.qc
Normal file
|
@ -0,0 +1,940 @@
|
||||||
|
// Shpuld's Simple UI lib - sui
|
||||||
|
// Created 11/2018
|
||||||
|
//
|
||||||
|
// sui is a simple QuakeC UI lib for drawing and handling game interfaces.
|
||||||
|
// The API is made simple and easy to build upon, but cuts have been made
|
||||||
|
// to keep complexity low.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MENU
|
||||||
|
const float IE_KEYDOWN = 0; /* Specifies that a key was pressed. Second argument is the scan code. Third argument is the unicode (printable) char value. Fourth argument denotes which keyboard(or mouse, if its a mouse 'scan' key) the event came from. Note that some systems may completely separate scan codes and unicode values, with a 0 value for the unspecified argument. */
|
||||||
|
const float IE_KEYUP = 1; /* Specifies that a key was released. Arguments are the same as IE_KEYDOWN. On some systems, this may be fired instantly after IE_KEYDOWN was fired. */
|
||||||
|
const float IE_MOUSEDELTA = 2; /* Specifies that a mouse was moved (touch screens and tablets typically give IE_MOUSEABS events instead, use _windowed_mouse 0 to test code to cope with either). Second argument is the X displacement, third argument is the Y displacement. Fourth argument is which mouse or touch event triggered the event. */
|
||||||
|
const float IE_MOUSEABS = 3; /* Specifies that a mouse cursor or touch event was moved to a specific location relative to the virtual screen space. Second argument is the new X position, third argument is the new Y position. Fourth argument is which mouse or touch event triggered the event. */
|
||||||
|
const float IE_ACCELEROMETER = 4;
|
||||||
|
const float IE_FOCUS = 5; /* Specifies that input focus was given. parama says mouse focus, paramb says keyboard focus. If either are -1, then it is unchanged. */
|
||||||
|
const float IE_JOYAXIS = 6; /* Specifies that what value a joystick/controller axis currently specifies. x=axis, y=value. Will be called multiple times, once for each axis of each active controller. */
|
||||||
|
|
||||||
|
#define printf(x, ...) print(sprintf(x, __VA_ARGS__))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
float _sui_draw_initialized;
|
||||||
|
|
||||||
|
|
||||||
|
// framing
|
||||||
|
|
||||||
|
// pseudo windowing, sets a new "frame" for whatever we're drawing, instead of
|
||||||
|
// always using screen [0, 0] as min and [screen_width, screen_height] as max.
|
||||||
|
// also allows for aligning content to frame start/end/center on both axis
|
||||||
|
|
||||||
|
struct _frame_t {
|
||||||
|
vector pos;
|
||||||
|
vector size;
|
||||||
|
vector align;
|
||||||
|
};
|
||||||
|
const float MAX_FRAMES = 64;
|
||||||
|
_frame_t _frames[MAX_FRAMES];
|
||||||
|
float _frame_index;
|
||||||
|
|
||||||
|
const float SUI_ALIGN_START = 0;
|
||||||
|
const float SUI_ALIGN_CENTER = 1;
|
||||||
|
const float SUI_ALIGN_END = 2;
|
||||||
|
|
||||||
|
void() sui_reset_align =
|
||||||
|
{
|
||||||
|
_frames[_frame_index].align = [SUI_ALIGN_START, SUI_ALIGN_START];
|
||||||
|
};
|
||||||
|
|
||||||
|
void(float align) sui_set_x_align =
|
||||||
|
{
|
||||||
|
_frames[_frame_index].align.x = align;
|
||||||
|
};
|
||||||
|
|
||||||
|
void(float align) sui_set_y_align =
|
||||||
|
{
|
||||||
|
_frames[_frame_index].align.y = align;
|
||||||
|
};
|
||||||
|
|
||||||
|
void(vector align) sui_set_align =
|
||||||
|
{
|
||||||
|
_frames[_frame_index].align = align;
|
||||||
|
};
|
||||||
|
|
||||||
|
void(__inout vector point) sui_transform_point =
|
||||||
|
{
|
||||||
|
int idx = _frame_index;
|
||||||
|
switch (_frames[idx].align.x)
|
||||||
|
{
|
||||||
|
case SUI_ALIGN_START: point_x += _frames[idx].pos.x; break;
|
||||||
|
case SUI_ALIGN_CENTER: point_x += _frames[idx].pos.x + _frames[idx].size.x * 0.5; break;
|
||||||
|
case SUI_ALIGN_END: point_x += _frames[idx].pos.x + _frames[idx].size.x; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
switch (_frames[idx].align.y)
|
||||||
|
{
|
||||||
|
case SUI_ALIGN_START: point_y += _frames[idx].pos.y; break;
|
||||||
|
case SUI_ALIGN_CENTER: point_y += _frames[idx].pos.y + _frames[idx].size.y * 0.5; break;
|
||||||
|
case SUI_ALIGN_END: point_y += _frames[idx].pos.y + _frames[idx].size.y; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void(__inout vector point, vector size) sui_transform_box =
|
||||||
|
{
|
||||||
|
int idx = _frame_index;
|
||||||
|
switch (_frames[idx].align.x)
|
||||||
|
{
|
||||||
|
case SUI_ALIGN_START:
|
||||||
|
point_x += _frames[idx].pos.x;
|
||||||
|
break;
|
||||||
|
case SUI_ALIGN_CENTER:
|
||||||
|
point_x += _frames[idx].pos.x + _frames[idx].size.x * 0.5 - size_x * 0.5;
|
||||||
|
break;
|
||||||
|
case SUI_ALIGN_END:
|
||||||
|
point_x += _frames[idx].pos.x + _frames[idx].size.x - size_x;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
switch (_frames[idx].align.y)
|
||||||
|
{
|
||||||
|
case SUI_ALIGN_START:
|
||||||
|
point_y += _frames[idx].pos.y;
|
||||||
|
break;
|
||||||
|
case SUI_ALIGN_CENTER:
|
||||||
|
point_y += _frames[idx].pos.y + _frames[idx].size.y * 0.5 - size_y * 0.5;
|
||||||
|
break;
|
||||||
|
case SUI_ALIGN_END:
|
||||||
|
point_y += _frames[idx].pos.y + _frames[idx].size.y - size_y;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
vector() sui_current_frame_pos =
|
||||||
|
{
|
||||||
|
return _frames[_frame_index].pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
vector() sui_current_frame_size =
|
||||||
|
{
|
||||||
|
return _frames[_frame_index].size;
|
||||||
|
};
|
||||||
|
|
||||||
|
float _sui_is_clipping;
|
||||||
|
vector _sui_clip_area_mins;
|
||||||
|
vector _sui_clip_area_maxs;
|
||||||
|
void() sui_clip_to_frame =
|
||||||
|
{
|
||||||
|
vector pos = _frames[_frame_index].pos;
|
||||||
|
vector size = _frames[_frame_index].size;
|
||||||
|
_sui_is_clipping = TRUE;
|
||||||
|
_sui_clip_area_mins = pos;
|
||||||
|
_sui_clip_area_maxs = pos + size;
|
||||||
|
drawsetcliparea(pos.x, pos.y, size.x, size.y);
|
||||||
|
};
|
||||||
|
|
||||||
|
void() sui_reset_clip =
|
||||||
|
{
|
||||||
|
_sui_is_clipping = FALSE;
|
||||||
|
drawresetcliparea();
|
||||||
|
};
|
||||||
|
|
||||||
|
float() sui_is_clipping =
|
||||||
|
{
|
||||||
|
return _sui_is_clipping;
|
||||||
|
};
|
||||||
|
|
||||||
|
void(vector pos, vector size) sui_push_frame =
|
||||||
|
{
|
||||||
|
sui_transform_box(pos, size);
|
||||||
|
|
||||||
|
_frame_index += 1;
|
||||||
|
if (_frame_index >= MAX_FRAMES)
|
||||||
|
{
|
||||||
|
printf("^3sui warning: amount of frames = %.0f exceeds MAX_FRAMES = %.0f, consider increasing MAX_FRAMES\n", _frame_index, MAX_FRAMES);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_frames[_frame_index].pos = pos;
|
||||||
|
_frames[_frame_index].size = size;
|
||||||
|
_frames[_frame_index].align = [SUI_ALIGN_START, SUI_ALIGN_START]; // TODO allow customizing this
|
||||||
|
};
|
||||||
|
|
||||||
|
void() sui_pop_frame =
|
||||||
|
{
|
||||||
|
if (_frame_index > 0) _frame_index -= 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
void() sui_reset_frame =
|
||||||
|
{
|
||||||
|
_frame_index = 0;
|
||||||
|
sui_reset_align();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// actions
|
||||||
|
|
||||||
|
// interaction for sui elements, relies a lot on reading globals to see which
|
||||||
|
// element id is under cursor or held or whatever, not the most elegant
|
||||||
|
// solution but in this highly imperative world of QuakeC we can live with it
|
||||||
|
|
||||||
|
float _holding_click;
|
||||||
|
vector _cursor_click;
|
||||||
|
vector _cursor_position;
|
||||||
|
vector _cursor_relative_click;
|
||||||
|
vector _cursor_relative_hover;
|
||||||
|
struct _action_element_t {
|
||||||
|
vector pos;
|
||||||
|
vector size;
|
||||||
|
string id;
|
||||||
|
void(float index, vector click_ratios) action;
|
||||||
|
};
|
||||||
|
const float MAX_ACTION_ELEMENTS = 256;
|
||||||
|
_action_element_t _action_elements[MAX_ACTION_ELEMENTS];
|
||||||
|
float _action_elements_index;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO better naming
|
||||||
|
float(vector point, vector min, vector max) is_2dpoint_in_bounds =
|
||||||
|
{
|
||||||
|
if (point_x <= min_x || point_y <= min_y) return FALSE;
|
||||||
|
if (point_x > max_x || point_y > max_y) return FALSE;
|
||||||
|
return TRUE;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO better naming
|
||||||
|
float(vector point, vector pos, vector size) is_2dpoint_in_bbox =
|
||||||
|
{
|
||||||
|
return is_2dpoint_in_bounds(point, pos, pos + size);
|
||||||
|
};
|
||||||
|
|
||||||
|
void() _action_element_count_sanity =
|
||||||
|
{
|
||||||
|
if (_action_elements_index > MAX_ACTION_ELEMENTS)
|
||||||
|
{
|
||||||
|
// let the user know if they're hitting the bounds
|
||||||
|
printf("^3sui warning: amount of action elements = %.0f exceeds MAX_ACTION_ELEMENTS = %.0f, consider increasing MAX_ACTION_ELEMENTS\n", _action_elements_index, MAX_ACTION_ELEMENTS);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const float MAX_MOUSE_ACTIONS = 16;
|
||||||
|
string _hover_actions[MAX_MOUSE_ACTIONS];
|
||||||
|
string _click_actions[MAX_MOUSE_ACTIONS];
|
||||||
|
string _hold_actions[MAX_MOUSE_ACTIONS];
|
||||||
|
string _release_actions[MAX_MOUSE_ACTIONS];
|
||||||
|
string _last_clicked_actions[MAX_MOUSE_ACTIONS];
|
||||||
|
|
||||||
|
float _hover_action_count;
|
||||||
|
float _click_action_count;
|
||||||
|
float _hold_action_count;
|
||||||
|
float _release_action_count;
|
||||||
|
float _last_clicked_action_count;
|
||||||
|
|
||||||
|
|
||||||
|
// Resets things you might want to persist normally
|
||||||
|
void() sui_reset_actions =
|
||||||
|
{
|
||||||
|
_hover_action_count = 0;
|
||||||
|
_click_action_count = 0;
|
||||||
|
_hold_action_count = 0;
|
||||||
|
_release_action_count = 0;
|
||||||
|
_last_clicked_action_count = 0;
|
||||||
|
_holding_click = FALSE;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Per frame reset?
|
||||||
|
void() sui_reset_click =
|
||||||
|
{
|
||||||
|
_hold_action_count = 0;
|
||||||
|
_click_action_count = 0;
|
||||||
|
_holding_click = FALSE;
|
||||||
|
};
|
||||||
|
|
||||||
|
float() sui_click_held = { return _holding_click; };
|
||||||
|
|
||||||
|
|
||||||
|
// click: on mouse1 button down AND button op, once
|
||||||
|
|
||||||
|
// Returns true if id was the topmost click (what usually is cared about the most)
|
||||||
|
float(string id) sui_is_clicked =
|
||||||
|
{
|
||||||
|
return _click_action_count > 0 && _click_actions[0] == id;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the index of the clicked id, -1 if wasn't hit at all. 0 is topmost
|
||||||
|
float(string id) sui_click_index =
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _click_action_count; i++)
|
||||||
|
{
|
||||||
|
if (_click_actions[i] == id) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// hover: mouse is on top of the action element id
|
||||||
|
|
||||||
|
float(string id) sui_is_hovered =
|
||||||
|
{
|
||||||
|
return _hover_action_count > 0 && _hover_actions[0] == id;
|
||||||
|
};
|
||||||
|
|
||||||
|
float(string id) sui_hover_index =
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _hover_action_count; i++)
|
||||||
|
{
|
||||||
|
if (_hover_actions[i] == id) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// hold: mouse button was clicked on top of this id and is held down, but not necessarily over this id anymore
|
||||||
|
|
||||||
|
float(string id) sui_is_held =
|
||||||
|
{
|
||||||
|
return _hold_action_count > 0 && _hold_actions[0] == id;
|
||||||
|
};
|
||||||
|
|
||||||
|
float(string id) sui_hold_index =
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _hold_action_count; i++)
|
||||||
|
{
|
||||||
|
if (_hold_actions[i] == id) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// last clicked: is this the last action element that was clicked, good for focusing on input boxes for example
|
||||||
|
|
||||||
|
float(string id) sui_is_last_clicked =
|
||||||
|
{
|
||||||
|
return _last_clicked_action_count > 0 && _last_clicked_actions[0] == id;
|
||||||
|
};
|
||||||
|
|
||||||
|
float(string id) sui_last_clicked_index =
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _last_clicked_action_count; i++)
|
||||||
|
{
|
||||||
|
if (_last_clicked_actions[i] == id) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// release: a thing was held, but now it was released, once
|
||||||
|
|
||||||
|
float(string id) sui_is_released =
|
||||||
|
{
|
||||||
|
return _release_action_count > 0 && _release_actions[0] == id;
|
||||||
|
};
|
||||||
|
|
||||||
|
float(string id) sui_release_index =
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _release_action_count; i++)
|
||||||
|
{
|
||||||
|
if (_release_actions[i] == id) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
float(float num) mouse_action_sanity =
|
||||||
|
{
|
||||||
|
if (num >= MAX_MOUSE_ACTIONS)
|
||||||
|
{
|
||||||
|
printf("^3sui warning: you have exceeded the amount of overlapping action elements with %.0f, MAX_MOUSE_ACTIONS = %.0f\n", num, MAX_MOUSE_ACTIONS);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
};
|
||||||
|
|
||||||
|
// mouse move, mostly just update hovers
|
||||||
|
|
||||||
|
void(vector pos) _sui_mouse_move =
|
||||||
|
{
|
||||||
|
_cursor_position = pos;
|
||||||
|
_action_element_count_sanity();
|
||||||
|
|
||||||
|
// Reset hover, it'll be back to what it used to be before draw gets called if mouse is still on same element
|
||||||
|
_hover_action_count = 0;
|
||||||
|
|
||||||
|
// Iterate front to back, so topmost element gets the click/hover
|
||||||
|
for (int i = min(MAX_ACTION_ELEMENTS, _action_elements_index) - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (is_2dpoint_in_bbox(_cursor_position, _action_elements[i].pos, _action_elements[i].size))
|
||||||
|
{
|
||||||
|
if (mouse_action_sanity(_hover_action_count)) break;
|
||||||
|
|
||||||
|
if (_hover_action_count == 0) _cursor_relative_hover = _cursor_position - _action_elements[i].pos;
|
||||||
|
_hover_actions[_hover_action_count] = _action_elements[i].id;
|
||||||
|
_hover_action_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// JERK ALERT: hard to pass input params for it without them just being the globals
|
||||||
|
// ... so it just straight up uses the globals... optimization
|
||||||
|
void() _sui_mouse1_down =
|
||||||
|
{
|
||||||
|
// Cheap but it should work...
|
||||||
|
_cursor_click = _cursor_position;
|
||||||
|
_cursor_relative_click = _cursor_relative_hover;
|
||||||
|
for (int i = 0; i < _hover_action_count; i++) _hold_actions[i] = _hover_actions[i];
|
||||||
|
_hold_action_count = _hover_action_count;
|
||||||
|
_holding_click = TRUE;
|
||||||
|
_last_clicked_action_count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void() _sui_mouse1_up =
|
||||||
|
{
|
||||||
|
// Can't be cheap here, we have to get the action fn of the element anyway so..
|
||||||
|
_action_element_count_sanity();
|
||||||
|
|
||||||
|
// Assume we won't hit anything
|
||||||
|
_click_action_count = 0;
|
||||||
|
_last_clicked_action_count = 0;
|
||||||
|
|
||||||
|
// Iterate front to back, so topmost element gets the click/hover
|
||||||
|
for (int i = min(MAX_ACTION_ELEMENTS, _action_elements_index) - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
// If the thing wasn't the same thing we started pressing down on, ignore
|
||||||
|
for (int j = 0; j < _hold_action_count; j++)
|
||||||
|
{
|
||||||
|
if (_hold_actions[j] == _action_elements[i].id) // yes this element was held
|
||||||
|
{
|
||||||
|
// Still in bounds?
|
||||||
|
if (is_2dpoint_in_bbox(_cursor_position, _action_elements[i].pos, _action_elements[i].size))
|
||||||
|
{
|
||||||
|
if (mouse_action_sanity(_click_action_count)) break;
|
||||||
|
|
||||||
|
// Register click
|
||||||
|
_click_actions[_click_action_count] = _action_elements[i].id;
|
||||||
|
_last_clicked_actions[_last_clicked_action_count] = _action_elements[i].id;
|
||||||
|
_click_action_count += 1;
|
||||||
|
_last_clicked_action_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case someone is keeping state on hold and wants to do stuff on release, even if cursor has moved
|
||||||
|
for (int i = 0; i < _hold_action_count; i++) _release_actions[i] = _hold_actions[i];
|
||||||
|
_release_action_count = _hold_action_count;
|
||||||
|
_hold_action_count = 0;
|
||||||
|
_holding_click = FALSE;
|
||||||
|
};
|
||||||
|
|
||||||
|
void(vector pos, vector size, string id, void(float index, vector click_ratios) action) sui_action_element =
|
||||||
|
{
|
||||||
|
if (!_sui_draw_initialized)
|
||||||
|
{
|
||||||
|
print("^1sui error: adding sui elements before sui_pre_draw!\n^1 Always do your sui menus between sui_pre_draw and sui_draw!\n");
|
||||||
|
}
|
||||||
|
if (_action_elements_index >= MAX_ACTION_ELEMENTS)
|
||||||
|
{
|
||||||
|
// Silently fail here, sui will let us know another way, increase the count
|
||||||
|
// so that the error in click/mousemove handlers prints correct numbers.
|
||||||
|
_action_elements_index += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sui_transform_box(pos, size);
|
||||||
|
|
||||||
|
if (_sui_is_clipping)
|
||||||
|
{
|
||||||
|
vector oldpos = pos;
|
||||||
|
pos_x = max(pos_x, _sui_clip_area_mins_x);
|
||||||
|
pos_y = max(pos_y, _sui_clip_area_mins_y);
|
||||||
|
|
||||||
|
size -= pos - oldpos;
|
||||||
|
|
||||||
|
size_x -= bound(0, (pos_x + size_x - _sui_clip_area_maxs_x), size_x);
|
||||||
|
size_y -= bound(0, (pos_y + size_y - _sui_clip_area_maxs_y), size_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
_action_elements[_action_elements_index].pos = pos;
|
||||||
|
_action_elements[_action_elements_index].size = size;
|
||||||
|
_action_elements[_action_elements_index].id = id;
|
||||||
|
_action_elements[_action_elements_index].action = action;
|
||||||
|
|
||||||
|
_action_elements_index += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Input related stuff
|
||||||
|
|
||||||
|
string _sui_binding_command;
|
||||||
|
string _sui_binding_command_name;
|
||||||
|
|
||||||
|
struct _input_t {
|
||||||
|
float char;
|
||||||
|
float scan;
|
||||||
|
};
|
||||||
|
const float MAX_INPUTS = 64;
|
||||||
|
|
||||||
|
_input_t _input_buffer[MAX_INPUTS];
|
||||||
|
float _input_index;
|
||||||
|
float _input_length;
|
||||||
|
|
||||||
|
|
||||||
|
// probably good to use it like while (sui_get_input(char, scan)) { ... };
|
||||||
|
float(__inout float char, __inout float scan) sui_get_input =
|
||||||
|
{
|
||||||
|
if (_input_index >= _input_length) return FALSE;
|
||||||
|
|
||||||
|
char = _input_buffer[_input_index].char;
|
||||||
|
scan = _input_buffer[_input_index].scan;
|
||||||
|
_input_index++;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
};
|
||||||
|
|
||||||
|
// if 2 controls want to read the same input for some reason..
|
||||||
|
void() sui_reread_input =
|
||||||
|
{
|
||||||
|
_input_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void() sui_clear_input =
|
||||||
|
{
|
||||||
|
_input_length = 0;
|
||||||
|
_input_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
float(float char, float scan) _sui_add_input =
|
||||||
|
{
|
||||||
|
// TODO check if input was listened, return FALSE if not
|
||||||
|
if (_input_length >= MAX_INPUTS)
|
||||||
|
{
|
||||||
|
printf("^3sui warning: exceeded amount of per frame inputs count MAX_INPUTS = %.0f\n"
|
||||||
|
"^3 - make sure sui_input_event isn't being called without sui_draw being called in update loop\n"
|
||||||
|
"^3 - consider increasing MAX_INPUTS\n", MAX_INPUTS);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
_input_buffer[_input_length].char = char;
|
||||||
|
_input_buffer[_input_length].scan = scan;
|
||||||
|
_input_length += 1;
|
||||||
|
return TRUE;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Listen to a certain keycode if it was pressed, this way sui know it was requested
|
||||||
|
float(float keycode) sui_listen_keycode_down =
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
};
|
||||||
|
|
||||||
|
// all text that was input between last and current frame
|
||||||
|
string() sui_listen_text_input =
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
void(float char, float scan, __inout string text, __inout float cursor) sui_handle_text_input =
|
||||||
|
{
|
||||||
|
float maxlen = 128;
|
||||||
|
|
||||||
|
string prev = text;
|
||||||
|
string pre_cursor, post_cursor;
|
||||||
|
float length = strlen(prev);
|
||||||
|
if (char > 31 && char < 128) //an actual input
|
||||||
|
{
|
||||||
|
if (length >= maxlen) return;
|
||||||
|
pre_cursor = substring(prev, 0, cursor);
|
||||||
|
post_cursor = substring(prev, cursor, length);
|
||||||
|
|
||||||
|
text = sprintf("%s%s%s", pre_cursor, chr2str(char), post_cursor);
|
||||||
|
cursor += 1;
|
||||||
|
}
|
||||||
|
else if (char == 8) // backspace
|
||||||
|
{
|
||||||
|
if (cursor <= 0) return;
|
||||||
|
pre_cursor = substring(prev, 0, cursor - 1);
|
||||||
|
post_cursor = substring(prev, cursor, length);
|
||||||
|
cursor -= 1;
|
||||||
|
cursor = max(0, cursor);
|
||||||
|
text = strcat(pre_cursor, post_cursor);
|
||||||
|
}
|
||||||
|
else if (scan == K_DEL)
|
||||||
|
{
|
||||||
|
if (cursor >= length) return;
|
||||||
|
pre_cursor = substring(prev, 0, cursor);
|
||||||
|
post_cursor = substring(prev, cursor + 1, length);
|
||||||
|
text = strcat(pre_cursor, post_cursor);
|
||||||
|
}
|
||||||
|
else if (char == 13 || char == 27) // enter or escape
|
||||||
|
{
|
||||||
|
// Commit and deselect...
|
||||||
|
// Let's try a hack..
|
||||||
|
_last_clicked_action_count = 0;
|
||||||
|
}
|
||||||
|
else if (scan == K_LEFTARROW)
|
||||||
|
{
|
||||||
|
cursor -= 1;
|
||||||
|
cursor = max(0, cursor);
|
||||||
|
}
|
||||||
|
else if (scan == K_RIGHTARROW)
|
||||||
|
{
|
||||||
|
cursor += 1;
|
||||||
|
cursor = min(strlen(prev), cursor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void(float maxlen, __inout string text, __inout float cursor) sui_cap_input_length =
|
||||||
|
{
|
||||||
|
if (strlen(text) > maxlen)
|
||||||
|
{
|
||||||
|
text = substring(text, 0, strlen(text));
|
||||||
|
cursor = strlen(text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void(string command) _sui_unbind =
|
||||||
|
{
|
||||||
|
tokenize(findkeysforcommand(command));
|
||||||
|
string keyname = keynumtostring(stof(argv(0)));
|
||||||
|
string altkeyname = keynumtostring(stof(argv(1)));
|
||||||
|
localcmd(sprintf("unbind %s\n", keyname));
|
||||||
|
localcmd(sprintf("unbind %s\n", altkeyname));
|
||||||
|
};
|
||||||
|
|
||||||
|
void(float scan, string command) _sui_do_keybind =
|
||||||
|
{
|
||||||
|
if (scan == K_ESCAPE)
|
||||||
|
{
|
||||||
|
_sui_binding_command = "";
|
||||||
|
_sui_binding_command_name = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (scan == K_BACKSPACE)
|
||||||
|
{
|
||||||
|
_sui_unbind(command);
|
||||||
|
_sui_binding_command = "";
|
||||||
|
_sui_binding_command_name = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string keyname = keynumtostring(scan);
|
||||||
|
_sui_unbind(command);
|
||||||
|
localcmd(sprintf("bind %s %s\n", keyname, command));
|
||||||
|
_sui_binding_command = "";
|
||||||
|
_sui_binding_command_name = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
void(string command, string command_name) sui_start_bind =
|
||||||
|
{
|
||||||
|
_sui_binding_command = command;
|
||||||
|
_sui_binding_command_name = command_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
// void(float evtype, float scanx, float chary, float devid) sui_input_event
|
||||||
|
// same args is CSQC_InputEvent.
|
||||||
|
// return value tells you if sui used the event or not, in case you want to
|
||||||
|
// not let engine handle it if it was used.
|
||||||
|
// Sets all the internal sui action stuff, call it in CSQC_InputEvent
|
||||||
|
float(float evtype, float scanx, float chary, float devid) sui_input_event =
|
||||||
|
{
|
||||||
|
switch (evtype)
|
||||||
|
{
|
||||||
|
case IE_MOUSEABS:
|
||||||
|
_sui_mouse_move([scanx, chary]);
|
||||||
|
return TRUE;
|
||||||
|
break;
|
||||||
|
case IE_MOUSEDELTA:
|
||||||
|
// Big question mark...
|
||||||
|
// maybe make our own delta based sui_cursor here..
|
||||||
|
// maybe just ignore delta and let user fake mouseabs with their own
|
||||||
|
// delta cursor by passing different params to this func...?
|
||||||
|
// for MVP let's just use mouseabs only
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
case IE_KEYDOWN:
|
||||||
|
if (_sui_binding_command != "")
|
||||||
|
{
|
||||||
|
// Nothing
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else if (scanx == K_MOUSE1)
|
||||||
|
{
|
||||||
|
_sui_mouse1_down();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((scanx == K_ESCAPE || scanx == K_BACKSPACE) && _sui_binding_command != "")
|
||||||
|
return TRUE;
|
||||||
|
else if (scanx == K_ESCAPE)
|
||||||
|
return FALSE;
|
||||||
|
return _sui_add_input(chary, scanx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IE_KEYUP:
|
||||||
|
if (_sui_binding_command != "")
|
||||||
|
{
|
||||||
|
_sui_do_keybind(scanx, _sui_binding_command);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else if (scanx == K_MOUSE1)
|
||||||
|
{
|
||||||
|
_sui_mouse1_up();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// void() sui_pre_draw
|
||||||
|
// Resets state for sui actions so that no trouble happens.
|
||||||
|
// Call it before your menu code per frame in your draw/updateview.
|
||||||
|
void(float width, float height) sui_begin =
|
||||||
|
{
|
||||||
|
_action_elements_index = 0;
|
||||||
|
_sui_draw_initialized = TRUE;
|
||||||
|
|
||||||
|
sui_reset_frame();
|
||||||
|
sui_push_frame([0, 0], [width, height]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void() sui_draw_bind_overlay;
|
||||||
|
|
||||||
|
// void() sui_end
|
||||||
|
// Call after your menu code per frame in your draw/updateview.
|
||||||
|
void() sui_end =
|
||||||
|
{
|
||||||
|
// Todo: move overlay drawing elsewhere:
|
||||||
|
sui_draw_bind_overlay();
|
||||||
|
// Dirty part:
|
||||||
|
_sui_draw_initialized = FALSE;
|
||||||
|
// reset "once" type actions
|
||||||
|
_click_action_count = 0;
|
||||||
|
_release_action_count = 0;
|
||||||
|
// empty input buffer
|
||||||
|
sui_clear_input();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Different draw components:
|
||||||
|
|
||||||
|
void(vector pos, vector size, vector color, float alpha, float flags) sui_fill =
|
||||||
|
{
|
||||||
|
sui_transform_box(pos, size);
|
||||||
|
|
||||||
|
drawfill(pos, size, color, alpha, flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
void(vector pos, vector size, string pic, vector color, float alpha, float flags) sui_pic =
|
||||||
|
{
|
||||||
|
sui_transform_box(pos, size);
|
||||||
|
|
||||||
|
drawpic(pos, pic, size, color, alpha, flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
void(vector pos, vector size, float width, vector color, float alpha, float flags) sui_border_box =
|
||||||
|
{
|
||||||
|
sui_transform_box(pos, size);
|
||||||
|
|
||||||
|
// Top line
|
||||||
|
drawfill(pos, [size_x, width], color, alpha, flags);
|
||||||
|
// Bottom line
|
||||||
|
drawfill([pos_x, pos_y + size_y - width], [size_x, width], color, alpha, flags);
|
||||||
|
// Left line
|
||||||
|
drawfill([pos_x, pos_y + width], [width, size_y - width * 2], color, alpha, flags);
|
||||||
|
// Right line
|
||||||
|
drawfill([pos_x + size_x - width, pos_y + width], [width, size_y - width * 2], color, alpha, flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void(vector pos, vector size, string text, vector color, float alpha, float flags) sui_text =
|
||||||
|
{
|
||||||
|
sui_transform_box(pos, [stringwidth(text, 1, size), size_y]);
|
||||||
|
|
||||||
|
drawstring(pos, text, size, color, alpha, flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
void(float index, vector click_ratios) sui_noop = {};
|
||||||
|
|
||||||
|
void(float value) sui_slider_noop = {};
|
||||||
|
|
||||||
|
float(string id, vector pos, vector size, vector minmaxsteps, float value, void(float value) action) sui_slidercontrol =
|
||||||
|
{
|
||||||
|
sui_action_element(pos, size, id, sui_noop);
|
||||||
|
float newvalue = value;
|
||||||
|
|
||||||
|
sui_transform_box(pos, size);
|
||||||
|
// user is clicking and holding the slider
|
||||||
|
if (sui_is_held(id))
|
||||||
|
{
|
||||||
|
float min = minmaxsteps[0];
|
||||||
|
float max = minmaxsteps[1];
|
||||||
|
float steps = minmaxsteps[2];
|
||||||
|
float click_ratio = (_cursor_position_x - pos_x) / size_x;
|
||||||
|
click_ratio = bound(0, click_ratio, 1);
|
||||||
|
if (steps > 0) click_ratio = rint(click_ratio * steps) / steps;
|
||||||
|
newvalue = min + click_ratio * (max - min);
|
||||||
|
if (newvalue != value) action(newvalue);
|
||||||
|
}
|
||||||
|
return newvalue;
|
||||||
|
};
|
||||||
|
|
||||||
|
void(string id, vector pos, vector size, __inout string text, __inout float cursor) sui_text_input =
|
||||||
|
{
|
||||||
|
sui_action_element(pos, size, id, sui_noop);
|
||||||
|
if (sui_is_clicked(id)) cursor = strlen(text);
|
||||||
|
if (sui_is_last_clicked(id))
|
||||||
|
{
|
||||||
|
float char = 0;
|
||||||
|
float scan = 0;
|
||||||
|
while(sui_get_input(char, scan)) sui_handle_text_input(char, scan, text, cursor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void(string id, vector size, vector contentsize, __inout vector offset, vector scrollbar_widths) sui_scrollbar =
|
||||||
|
{
|
||||||
|
vector maxoffset = contentsize - size;
|
||||||
|
maxoffset_x = max(0, maxoffset_x);
|
||||||
|
maxoffset_y = max(0, maxoffset_y);
|
||||||
|
sui_push_frame([0, 0], size);
|
||||||
|
float ofs;
|
||||||
|
float length;
|
||||||
|
vector barpos, barsize;
|
||||||
|
float scan = 0;
|
||||||
|
float char = 0;
|
||||||
|
string barname;
|
||||||
|
if (maxoffset_y > 0 && contentsize_y > 0)
|
||||||
|
{
|
||||||
|
sui_set_align([SUI_ALIGN_END, SUI_ALIGN_START]);
|
||||||
|
sui_push_frame([0, 0], [scrollbar_widths_y, size_y]);
|
||||||
|
ofs = (offset_y / contentsize_y) * size_y;
|
||||||
|
length = (size_y / contentsize_y) * size_y;
|
||||||
|
barpos = [0, ofs];
|
||||||
|
barsize = [scrollbar_widths_y, length];
|
||||||
|
barname = strcat(id, "vbar");
|
||||||
|
|
||||||
|
if (sui_is_held(barname))
|
||||||
|
{
|
||||||
|
vector anchor = barpos + _cursor_relative_click;
|
||||||
|
sui_transform_point(anchor);
|
||||||
|
float diff = _cursor_position_y - anchor_y;
|
||||||
|
offset_y += (diff * contentsize_y) / size_y; // * contentsize_y; // (size_y / contentsize_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
sui_fill(barpos, barsize, '0.1 0.1 0.1' * (1 - sui_is_hovered(barname)), 0.66, 0);
|
||||||
|
sui_action_element(barpos, barsize, barname, sui_noop);
|
||||||
|
sui_pop_frame();
|
||||||
|
}
|
||||||
|
sui_pop_frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
void(string id, vector pos, vector size, vector contentsize, __inout vector offset, vector scrollbar_widths) sui_scroll_view_begin =
|
||||||
|
{
|
||||||
|
// make space for scrollbars
|
||||||
|
sui_push_frame(pos, size - [scrollbar_widths_y, scrollbar_widths_x]);
|
||||||
|
sui_action_element([0, 0], size, id, sui_noop);
|
||||||
|
|
||||||
|
if (sui_hover_index(id) > -1)
|
||||||
|
{
|
||||||
|
float scrollamount = 0;
|
||||||
|
float char = 0;
|
||||||
|
float scan = 0;
|
||||||
|
sui_reread_input();
|
||||||
|
while (sui_get_input(char, scan))
|
||||||
|
{
|
||||||
|
if (scan == K_MWHEELUP) scrollamount -= 20;
|
||||||
|
if (scan == K_MWHEELDOWN) scrollamount += 20;
|
||||||
|
}
|
||||||
|
offset_y += scrollamount;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector maxoffset = contentsize - size;
|
||||||
|
maxoffset_x = max(0, maxoffset_x);
|
||||||
|
maxoffset_y = max(0, maxoffset_y);
|
||||||
|
offset_x = bound(0, offset_x, maxoffset_x);
|
||||||
|
offset_y = bound(0, offset_y, maxoffset_y);
|
||||||
|
|
||||||
|
sui_scrollbar(id, size, contentsize, offset, scrollbar_widths);
|
||||||
|
|
||||||
|
offset_x = bound(0, offset_x, maxoffset_x);
|
||||||
|
offset_y = bound(0, offset_y, maxoffset_y);
|
||||||
|
|
||||||
|
sui_clip_to_frame();
|
||||||
|
|
||||||
|
|
||||||
|
sui_push_frame(-1 * offset, contentsize);
|
||||||
|
};
|
||||||
|
|
||||||
|
void() sui_scroll_view_end =
|
||||||
|
{
|
||||||
|
sui_pop_frame();
|
||||||
|
sui_reset_clip();
|
||||||
|
sui_pop_frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
float _sui_list_item_height;
|
||||||
|
float _sui_list_first;
|
||||||
|
float _sui_list_last;
|
||||||
|
float _sui_list_pos;
|
||||||
|
int _sui_list_index;
|
||||||
|
void(string id, vector pos, vector size, vector itemsize, float numitems, __inout vector offset, vector scrollbar_widths) sui_list_view_begin =
|
||||||
|
{
|
||||||
|
vector contentsize = [itemsize_x, itemsize_y * numitems];
|
||||||
|
sui_scroll_view_begin(id, pos, size, contentsize, offset, scrollbar_widths);
|
||||||
|
|
||||||
|
_sui_list_item_height = itemsize_y;
|
||||||
|
float hidden_above = floor(offset_y / itemsize_y);
|
||||||
|
_sui_list_first = max(0, hidden_above); // Index of first elem
|
||||||
|
_sui_list_last = min(_sui_list_first + rint(size_y / itemsize_y) + 1, numitems);
|
||||||
|
_sui_list_pos = hidden_above * itemsize_y;
|
||||||
|
_sui_list_index = _sui_list_first;
|
||||||
|
};
|
||||||
|
|
||||||
|
float(__inout vector pos) sui_list_item =
|
||||||
|
{
|
||||||
|
if (_sui_list_index >= _sui_list_last) return -1;
|
||||||
|
pos = _sui_list_index * [0, _sui_list_item_height];
|
||||||
|
_sui_list_index += 1;
|
||||||
|
return _sui_list_index - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
void() sui_list_view_end =
|
||||||
|
{
|
||||||
|
sui_scroll_view_end();
|
||||||
|
};
|
||||||
|
|
||||||
|
string(string id, vector pos, vector size, string name, string command) sui_binder =
|
||||||
|
{
|
||||||
|
sui_action_element(pos, size, id, sui_noop);
|
||||||
|
if (sui_is_released(id))
|
||||||
|
{
|
||||||
|
sui_start_bind(command, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenize(findkeysforcommand(command));
|
||||||
|
string keyname = keynumtostring(stof(argv(0)));
|
||||||
|
if (keyname == "01") keyname = "unbound";
|
||||||
|
|
||||||
|
return keyname;
|
||||||
|
};
|
||||||
|
|
||||||
|
void() sui_draw_bind_overlay =
|
||||||
|
{
|
||||||
|
if (_sui_binding_command != "")
|
||||||
|
{
|
||||||
|
vector size = sui_current_frame_size();
|
||||||
|
sui_fill([0, 0], size, '0 0 0', 0.5, 0);
|
||||||
|
sui_set_align([SUI_ALIGN_CENTER, SUI_ALIGN_CENTER]);
|
||||||
|
float textsize = 16;
|
||||||
|
sui_text([0, -16], [textsize, textsize], "Press a key for", '1 1 1', 1, 0);
|
||||||
|
sui_text([0, 0], [textsize, textsize], sprintf("'%s'", _sui_binding_command_name), '1 1 1', 1, 0);
|
||||||
|
sui_text([0, 16], [textsize - 4, textsize - 4], "ESC to cancel, BACKSPACE to remove", '1 1 1', 1, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------- END OF SUI SYSTEM STUFF --------------------
|
|
@ -18,6 +18,12 @@ echo ""
|
||||||
./fteqcc-cli-lin -srcfile ../progs/fte-server.src
|
./fteqcc-cli-lin -srcfile ../progs/fte-server.src
|
||||||
echo ""
|
echo ""
|
||||||
echo "===================="
|
echo "===================="
|
||||||
|
echo "compiling FTE MENUQC"
|
||||||
|
echo "===================="
|
||||||
|
echo ""
|
||||||
|
./fteqcc-cli-lin -srcfile ../progs/fte-menu.src
|
||||||
|
echo ""
|
||||||
|
echo "===================="
|
||||||
echo " compiling PSP QC "
|
echo " compiling PSP QC "
|
||||||
echo "===================="
|
echo "===================="
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
@ -20,6 +20,12 @@ echo.
|
||||||
fteqcc-cli-win.exe -srcfile ../progs/fte-server.src
|
fteqcc-cli-win.exe -srcfile ../progs/fte-server.src
|
||||||
echo.
|
echo.
|
||||||
echo ====================
|
echo ====================
|
||||||
|
echo compiling FTE MENUQC
|
||||||
|
echo ====================
|
||||||
|
echo.
|
||||||
|
fteqcc-cli-win.exe -srcfile ../progs/fte-menu.src
|
||||||
|
echo.
|
||||||
|
echo ====================
|
||||||
echo compiling PSP QC
|
echo compiling PSP QC
|
||||||
echo ====================
|
echo ====================
|
||||||
echo.
|
echo.
|
||||||
|
|
Loading…
Reference in a new issue