mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-23 20:32:43 +00:00
Add mods menu and all-cvars menu to menusys.
combo widgets now have sliders on dropdown lists. text edit widgets accept mouse-clicks to move the cursor. Fixed a bug with audio device selection. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5671 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
50c4e75c65
commit
81b270db70
18 changed files with 1954 additions and 347 deletions
|
@ -1126,6 +1126,9 @@ ADD_CUSTOM_TARGET(menusys ALL
|
|||
quakec/menusys/menu/presets.qc
|
||||
quakec/menusys/menu/servers.qc
|
||||
quakec/menusys/menu/main.qc
|
||||
quakec/menusys/menu/mods.qc
|
||||
quakec/menusys/menu/cvars.qc
|
||||
quakec/menusys/menu/updates.qc
|
||||
quakec/menusys/menu/options_audio.qc
|
||||
quakec/menusys/menu/options_configs.qc
|
||||
quakec/menusys/menu/options_hud.qc
|
||||
|
|
52
ftechrootbuild.sh
Normal file
52
ftechrootbuild.sh
Normal file
|
@ -0,0 +1,52 @@
|
|||
#!/bin/sh
|
||||
#Script to set up a debian chroot suitable for compiling fte's public builds.
|
||||
#deterministic builds are attempted but also requires:
|
||||
# gcc/etc versions must match exactly (we use debian oldstable, which should reduce issues...)
|
||||
# sourcecode must be unmodified, particuarly if 'svnversion' reports modified even in an irrelevant file then embedded revision numbers will be wrong.
|
||||
# third party dependancies need to work and not get messed up (either me failing to re-run makelibs, random wget failures, or outdated revisions being removed from public access)
|
||||
# obtained sourcecode revision must match the binary you're trying to duplicate (pre-5601 will insist on updating to latest svn (which may not even have a public build), so expect problems trying to duplicate older builds when the scripts instead try to grab the most recent build).
|
||||
#for regular use you should probably set up schroot so you don't need to remember so many args
|
||||
#requires about 2.3gb for the chroot+win64 build.
|
||||
#android and emscripten targets require proper mounting of /proc and /dev and are NOT supported by this script. don't try enabling them
|
||||
|
||||
FTEBUILD=/tmp/ftebuild #change freely
|
||||
CHUID=1000 #should generally be your non-root user id, giving you the same access in or out of the chroot...
|
||||
CHUSER=spike #sadly this matters. youll just need to pretend to be me inside your chroot for now.
|
||||
DEBIANMIRROR=http://ftp.uk.debian.org/debian/
|
||||
DEBIANVERSION=stretch #oldstable now... should update to stable, but paranoid to update due to portability of glibc symbols.
|
||||
LANG= #no language packs installed, so would be spammy if the following rules inherit the host lang
|
||||
#FTEREVISON="-r 5601" #earlier than 5601 will fail (scripts will try to update to latest)
|
||||
#THREADS="-j 8" #override number of threads to compile with, if you have a decent cpu.
|
||||
|
||||
#package lists
|
||||
#general packages required to get the build system working (python+unzip+etc is for third-party dependancies)
|
||||
GENERALPACKAGES= subversion build-essential automake ca-certificates unzip p7zip-full zip libtool python pkg-config
|
||||
#package list needed to crosscompile for windows
|
||||
WINTARGETPACKAGES= mingw-w64
|
||||
#dev packages required to compile the linux build properly. Comment out for less downloads/diskusage
|
||||
LINUXTARGETPACKAGES= gcc-multilib g++-multilib mesa-common-dev libasound2-dev libxcursor-dev libgnutls28-dev
|
||||
|
||||
#NOTE: chroot does NOT wipe all environment settings. some get carried over. This is a problem if your distro has a default PATH that excludes the system programs on debian, so this is included to be sure.
|
||||
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
|
||||
|
||||
#Set up our chroot (you can skip this part entirely if you're preconfigured a VM)
|
||||
#make sure debootstrap is installed, without erroring out if you're not on debian-derivative (NOTE: such users will needs to manually install it first from somewhere!)
|
||||
(which apt-get>/dev/null) && apt-get install --no-install-recommends debootstrap
|
||||
#create the new debian chroot. it should receive the most recent versions of packages.
|
||||
debootstrap $DEBIANVERSION $FTEBUILD $DEBIANMIRROR
|
||||
echo "FTEBuild">$FTEBUILD/etc/debian_chroot #optional, so it shows if you decide to run a bash prompt inside the chroot.
|
||||
chroot $FTEBUILD adduser --uid $CHUID $CHUSER #create a user (with a homedir), so we dont depend upon root inside the guest, where possible
|
||||
|
||||
#Install the extra packages needed to build
|
||||
chroot $FTEBUILD apt-get install --no-install-recommends $GENERALPACKAGES $WINTARGETPACKAGES $LINUXTARGETPACKAGES
|
||||
#NOW we finally start with non-debian downloads by grabbing the FTE sourcecode
|
||||
chroot $FTEBUILD su $CHUSER -c "svn checkout https://svn.code.sf.net/p/fteqw/code/trunk ~/quake/fteqw-code $FTEREVISON" #grab all the source code.
|
||||
#FTE has some setup bollocks, which does some toolchain checks and such. You can choose which targets to build here.
|
||||
#NOTE: the following line will download third-party packages.
|
||||
chroot $FTEBUILD su $CHUSER -c "cd ~/quake/fteqw-code && ./build_setup.sh --noupdate"
|
||||
#And finally the main rebuild thing. drop the --noupdate part if you want to build the latest-available revision.
|
||||
chroot $FTEBUILD su $CHUSER -c "cd ~/quake/fteqw-code && ./build_wip.sh --noupdate $THREADS"
|
||||
|
||||
|
||||
#to remove your chroot afterwards:
|
||||
#rm --one-file-system -rf $FTEBUILD
|
File diff suppressed because it is too large
Load diff
|
@ -48,6 +48,9 @@ void(mitem_desktop desktop) M_Pop =
|
|||
cmd("m_load", M_Load, menu/loadsave.qc) \
|
||||
cmd("m_save", M_Save, ) \
|
||||
cmd("m_quit", M_Quit, menu/quit.qc) \
|
||||
cmd("m_mods", M_Menu_Mods, menu/mods.qc) \
|
||||
cmd("m_updates", M_Menu_Updates, menu/updates.qc) \
|
||||
cmd("m_cvars", M_Menu_Cvars, menu/cvars.qc) \
|
||||
cmd("m_newgame", M_NewGame, menu/newgame.qc) \
|
||||
cmd("m_servers", M_Servers, menu/servers.qc) \
|
||||
cmd("m_configs", M_Configs, menu/options_configs.qc) \
|
||||
|
@ -71,7 +74,12 @@ void(mitem_desktop desktop) M_Pop =
|
|||
|
||||
mitem_desktop desktop;
|
||||
void() m_shutdown = {};
|
||||
void(vector screensize) m_draw = {items_draw(desktop);};
|
||||
void(vector screensize) m_draw =
|
||||
{
|
||||
if (dp_workarounds)
|
||||
cltime = gettime(0);
|
||||
items_draw(desktop);
|
||||
};
|
||||
void(float scan, float chr) m_keydown = {items_keypress(desktop, scan, chr, TRUE);};
|
||||
void(float scan, float chr) m_keyup = {items_keypress(desktop, scan, chr, FALSE);};
|
||||
void(float mode) m_toggle
|
||||
|
@ -90,6 +98,23 @@ void(float mode) m_toggle
|
|||
|
||||
items_updategrabs(TRUE);
|
||||
};
|
||||
float(string cstr) m_consolecommand =
|
||||
{
|
||||
tokenize(cstr);
|
||||
string cmd = argv(0);
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
//switch on the known commands.
|
||||
#define cmd(n,f) case n: f(desktop); break;
|
||||
concommandslist
|
||||
#undef cmd
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
items_updategrabs(TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
var float autocvar_dp_workarounds_allow = TRUE;
|
||||
var float autocvar_dp_workarounds_force = FALSE;
|
||||
|
@ -97,10 +122,19 @@ void() m_init =
|
|||
{
|
||||
desktop = spawn(mitem_desktop);
|
||||
|
||||
if (checkbuiltin(registercommand))
|
||||
{
|
||||
#define cmd(n,f) registercommand(n);
|
||||
concommandslist
|
||||
#undef cmd
|
||||
}
|
||||
else
|
||||
{
|
||||
//register the console commands via the alias command.
|
||||
#define cmd(n,f) localcmd("alias " n " \"menu_cmd " n " $*\"\n");
|
||||
concommandslist
|
||||
#undef cmd
|
||||
}
|
||||
|
||||
//work around some dp differences/bugs.
|
||||
//this check identifies one significant bug in DP.
|
||||
|
|
265
quakec/menusys/menu/cvars.qc
Normal file
265
quakec/menusys/menu/cvars.qc
Normal file
|
@ -0,0 +1,265 @@
|
|||
#include "../menusys/mitem_grid.qc"
|
||||
|
||||
class mitem_cvargrid : mitem_grid
|
||||
{
|
||||
strbuf grid_buf_names; //left column (
|
||||
static void(strbuf newbuf) grid_setbuf =
|
||||
{
|
||||
if (grid_buf_names >= 0)
|
||||
buf_del(grid_buf_names);
|
||||
grid_buf_names = newbuf;
|
||||
grid_numchildren = buf_getsize(grid_buf_names);
|
||||
item_resized();
|
||||
grid_kactive = grid_numchildren?0:-1;
|
||||
grid_selectionchanged(-1,grid_kactive);
|
||||
};
|
||||
float cursorpos;
|
||||
string newval;
|
||||
static void() mitem_cvargrid =
|
||||
{
|
||||
grid_buf_names = -1;
|
||||
cursorpos = -1;
|
||||
};
|
||||
static void(float idx) startedit =
|
||||
{
|
||||
if (cursorpos < 0)
|
||||
{
|
||||
string v = bufstr_get(grid_buf_names, idx);
|
||||
float flags = cvar_type(v);
|
||||
if (!(flags&1) || (flags&32)) //(!exists || readonly). we don't bother to check for private - we can still set them (they'll just read as empty).
|
||||
return;
|
||||
newval = strzone(cvar_string(v));
|
||||
cursorpos = strlen(newval);
|
||||
}
|
||||
};
|
||||
static string() getdesc =
|
||||
{
|
||||
float idx = grid_kactive;
|
||||
if (idx < 0 || idx >= grid_numchildren)
|
||||
return __NULL__;
|
||||
string v = bufstr_get(grid_buf_names, idx);
|
||||
return cvar_description(v);
|
||||
};
|
||||
virtual void(vector pos, float idx) grid_draw;
|
||||
virtual float(vector pos, float scan, float char, float down, float idx) grid_keypress;
|
||||
virtual void(float olditem, float newitem) grid_selectionchanged;
|
||||
};
|
||||
void(vector pos, float idx) mitem_cvargrid::grid_draw =
|
||||
{
|
||||
string text = bufstr_get(grid_buf_names, idx);
|
||||
string value = cvar_string(text);
|
||||
string defvalue = cvar_defstring(text);
|
||||
float flags;
|
||||
|
||||
vector col = item_rgb;
|
||||
if (item_flags & IF_MFOCUSED && idx == grid_mactive)
|
||||
col_z = 0;
|
||||
if (item_flags & IF_KFOCUSED && idx == grid_kactive)
|
||||
col_x = 0;
|
||||
|
||||
flags = cvar_type(text);
|
||||
if (!(flags&1))
|
||||
value = "<INVALID>";
|
||||
// if (flags & 2) //archive
|
||||
// text = strcat("^hseta^h ", text);
|
||||
if (flags & 4) //private
|
||||
{
|
||||
if (!value) //should always be true...
|
||||
value = "???";
|
||||
if (checkextension("FTE_EXTENDEDTEXTCODES"))
|
||||
value = strcat("^&FE", value); //yellow, so you know its valid is meaningless.
|
||||
}
|
||||
//8 means engine, or something
|
||||
//16 just means it has a description. who even cares?
|
||||
if (flags & 32)
|
||||
{
|
||||
if (checkextension("FTE_EXTENDEDTEXTCODES"))
|
||||
value = strcat("^&F4", value); //make it red so you know its pointless trying to change it.
|
||||
}
|
||||
|
||||
if (idx == grid_kactive && cursorpos >= 0)
|
||||
{ //we're editing...
|
||||
value = newval;
|
||||
if (value == defvalue)
|
||||
col *= 0.5;
|
||||
if (((cltime*4)&1) && (item_flags & IF_KFOCUSED))
|
||||
value = strcat(substring(value, 0, cursorpos), chr2str(0xe00b), substring(value, cursorpos+1, -1)); //replace the char with a box... ugly, whatever
|
||||
}
|
||||
else if (value == defvalue)
|
||||
col *= 0.5;
|
||||
|
||||
vector valuepos = [pos_x+item_size_x/2, pos_y];
|
||||
pos_x = valuepos_x - stringwidth(text, TRUE, '1 1 0'*this.item_scale) - 8;
|
||||
valuepos_x += 1;
|
||||
ui.drawstring(pos, text, '1 1 0' * item_scale, col, item_alpha, 0);
|
||||
ui.drawstring(valuepos, value, '1 1 0' * item_scale, col, item_alpha, 0);
|
||||
};
|
||||
void(float olditem, float newitem) mitem_cvargrid::grid_selectionchanged =
|
||||
{
|
||||
if (olditem == newitem)
|
||||
return;
|
||||
if (olditem && cursorpos >= 0)
|
||||
{ //we were editing... change it now.
|
||||
string v = bufstr_get(grid_buf_names, olditem);
|
||||
cvar_set(v, newval);
|
||||
}
|
||||
cursorpos = -1; //stop editing now.
|
||||
newval = "";
|
||||
};
|
||||
float(vector pos, float scan, float char, float down, float idx) mitem_cvargrid::grid_keypress =
|
||||
{
|
||||
if (!down)
|
||||
return FALSE;
|
||||
else if (scan == K_ESCAPE)
|
||||
{
|
||||
if (cursorpos >= 0)
|
||||
cursorpos = -1; //cancel editing, forgetting the change.
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
else if (scan == K_ENTER)
|
||||
{
|
||||
if (cursorpos >= 0)
|
||||
grid_selectionchanged(idx, -1);
|
||||
else
|
||||
startedit(idx);
|
||||
}
|
||||
else if (scan == K_LEFTARROW && cursorpos>=0)
|
||||
cursorpos = max(cursorpos-1, 0);
|
||||
else if (scan == K_RIGHTARROW && cursorpos>=0)
|
||||
cursorpos+=1;
|
||||
else if (scan == K_MOUSE1)
|
||||
{
|
||||
startedit(idx);
|
||||
if (cursorpos>=0)
|
||||
{
|
||||
float valuepos = pos_x+(item_size_x/2)+1;
|
||||
cursorpos = strlen(newval);
|
||||
if (ui.mousepos[0] > valuepos-8)
|
||||
while (cursorpos>0 && ui.mousepos[0] < valuepos+stringwidth(substring(newval, 0, cursorpos), TRUE, '1 1 0'*item_scale))
|
||||
cursorpos--;
|
||||
}
|
||||
}
|
||||
else if (scan == K_DEL && cursorpos<0)
|
||||
{ //reset to default
|
||||
string v = bufstr_get(grid_buf_names, idx);
|
||||
cvar_set(v, cvar_defstring(v));
|
||||
}
|
||||
else if (scan == K_HOME && cursorpos>= 0)
|
||||
cursorpos = 0;
|
||||
else if (scan == K_END && cursorpos>= 0)
|
||||
cursorpos = strlen(newval);
|
||||
else if (scan == K_DEL && cursorpos>=0 && cursorpos<strlen(newval))
|
||||
newval = strzone(strcat(substring(newval, 0, cursorpos), substring(newval, cursorpos+1, -1)));
|
||||
else if ((scan == K_BACKSPACE || scan == K_DEL) && cursorpos>=0)
|
||||
{
|
||||
if (cursorpos>0)
|
||||
{
|
||||
newval = strzone(strcat(substring(newval, 0, cursorpos-1), substring(newval, cursorpos, -1)));
|
||||
cursorpos -= 1;
|
||||
}
|
||||
}
|
||||
else if (char >= ' ' && cursorpos>=0)
|
||||
{
|
||||
string ins = chr2str(char);
|
||||
newval = strzone(strcat(substring(newval, 0, cursorpos), ins, substring(newval, cursorpos, -1)));
|
||||
cursorpos += strlen(ins);
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class cvarsmenu : mitem_exmenu
|
||||
{
|
||||
string filter;
|
||||
float modifiedonly;
|
||||
|
||||
mitem_cvargrid grid;
|
||||
|
||||
static void(void) updatefilters =
|
||||
{
|
||||
strbuf b = buf_create();
|
||||
buf_cvarlist(b, filter, "_*");
|
||||
if (modifiedonly)
|
||||
{
|
||||
for (float i = buf_getsize(b); i --> 0; )
|
||||
{
|
||||
string v = bufstr_get(b, i);
|
||||
if (cvar_string(v) == cvar_defstring(v))
|
||||
bufstr_free(b, i);
|
||||
else if (cvar_type(v)&32)
|
||||
bufstr_free(b, i); //also remove read-only cvars. we can't reset them or anything so there's no point listing them here.
|
||||
}
|
||||
buf_sort(b, 0, 0); //sort the names, to clean up any gaps
|
||||
}
|
||||
|
||||
grid.grid_setbuf(b);
|
||||
};
|
||||
|
||||
virtual string(string key) get =
|
||||
{
|
||||
if (key == "*filter")
|
||||
return filter;
|
||||
if (key == "*modified")
|
||||
return ftos(modifiedonly);
|
||||
if (key == "*desc")
|
||||
return grid.getdesc();
|
||||
return super::get(key);
|
||||
};
|
||||
virtual void(string key, string newval) set =
|
||||
{
|
||||
if (key == "*filter")
|
||||
filter = newval;
|
||||
else if (key == "*modified")
|
||||
modifiedonly = stof(newval);
|
||||
else
|
||||
return super::set(key, newval);
|
||||
updatefilters();
|
||||
};
|
||||
virtual float(string key) isvalid =
|
||||
{
|
||||
if (key == "*filter")
|
||||
return TRUE;
|
||||
if (key == "*modified")
|
||||
return TRUE;
|
||||
return super::isvalid(key);
|
||||
};
|
||||
};
|
||||
|
||||
void(mitem_desktop desktop) M_Menu_Cvars =
|
||||
{
|
||||
mitem it;
|
||||
float h = (480+240)/2;
|
||||
|
||||
//create the menu, give it focus, and make sure its displayed over everything else.
|
||||
cvarsmenu m = spawn(cvarsmenu, item_text:_("Mods List"), item_flags:IF_SELECTABLE, item_command:"m_main", frame_stdheight:h);
|
||||
desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0');
|
||||
desktop.item_focuschange(m, IF_KFOCUSED);
|
||||
m.totop();
|
||||
|
||||
//draw title art above the options
|
||||
mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN);
|
||||
m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [banner.item_size_x*-0.5, h*-0.5], [banner.item_size_x*0.5, 24]);
|
||||
|
||||
it = menuitemeditt_spawn("Cvar Filter", "*filter", '280 8');
|
||||
m.add(it, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [-160, h*-0.5+32], [40, 8]);
|
||||
|
||||
it = menuitemcheck_spawn("Modified Only", "*modified", '280 8');
|
||||
m.add(it, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [40, h*-0.5+32], [200, 8]);
|
||||
|
||||
//spawn our grid for the actual options. this provides a scrollbar if we have too many items.
|
||||
m.grid = spawn(mitem_cvargrid, item_flags: IF_SELECTABLE, item_scale: 8);
|
||||
m.add(m.grid, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [-160, h*-0.5+48], [320, h*0.5-64]);
|
||||
|
||||
it = spawn(mitem_label, item_text: "*desc", item_flags: 0, item_scale: 8);
|
||||
m.add(it, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [-160, h*0.5-60], [320, h*0.5]);
|
||||
|
||||
m.updatefilters();
|
||||
|
||||
//and give us a suitable menu tint too, just because.
|
||||
addmenuback(m);
|
||||
};
|
|
@ -39,6 +39,12 @@ float(string cmd) assumefalsecheckcommand =
|
|||
return checkcommand(cmd);
|
||||
};
|
||||
|
||||
float(__variant cmd, float assumption) checkbuiltin2 =
|
||||
{
|
||||
if (!checkbuiltin(checkbuiltin)) //teehee
|
||||
return assumption;
|
||||
return checkbuiltin(cmd);
|
||||
};
|
||||
|
||||
|
||||
nonstatic void(mitem_desktop desktop) M_Main =
|
||||
|
@ -88,8 +94,10 @@ nonstatic void(mitem_desktop desktop) M_Main =
|
|||
if (assumefalsecheckcommand("cef")) {menuitemtext_cladd16(m, _("Browser"), "m_pop;cef google.com", y); y += 16;}
|
||||
if (assumefalsecheckcommand("xmpp")) {menuitemtext_cladd16(m, _("Social"), "m_pop;xmpp", y); y += 16;}
|
||||
if (assumefalsecheckcommand("irc")) {menuitemtext_cladd16(m, _("IRC"), "m_pop;irc /info", y); y += 16;}
|
||||
if (assumefalsecheckcommand("menu_download")) {menuitemtext_cladd16(m, _("Updates+Packages"), "m_pop;menu_download", y); y += 16;}
|
||||
/*if (checkbuiltin2(getpackagemanagerinfo,FALSE)) {menuitemtext_cladd16(m, _("Updates+Packages"), "m_pop;m_updates", y); y += 16;}
|
||||
else*/ if (assumefalsecheckcommand("menu_download")) {menuitemtext_cladd16(m, _("Updates+Packages"), "m_pop;menu_download", y); y += 16;}
|
||||
if (assumefalsecheckcommand("qi")) {menuitemtext_cladd16(m, _("Quake Injector"), "m_pop;qi", y); y += 16;}
|
||||
if (checkbuiltin2(getgamedirinfo,TRUE)) {menuitemtext_cladd16(m, _("Mods"), "m_pop;m_mods", y); y += 16;}
|
||||
{menuitemtext_cladd16(m, _("Options"), "m_pop;m_options", y); y += 16;}
|
||||
{menuitemtext_cladd16(m, _("Quit"), "m_pop;m_quit", y); y += 16;}
|
||||
|
||||
|
|
77
quakec/menusys/menu/mods.qc
Normal file
77
quakec/menusys/menu/mods.qc
Normal file
|
@ -0,0 +1,77 @@
|
|||
class mitem_pictext : mitem_text
|
||||
{
|
||||
string pic;
|
||||
virtual void(vector pos) item_draw =
|
||||
{
|
||||
if (pic)
|
||||
drawpic(pos, pic, [item_size_y,item_size_y], '1 1 1', 1, 0);
|
||||
pos_x += item_size_y;
|
||||
super::item_draw(pos);
|
||||
};
|
||||
};
|
||||
|
||||
void(mitem_desktop desktop) M_Menu_Mods =
|
||||
{
|
||||
float h = (480+240)/2;
|
||||
|
||||
//create the menu, give it focus, and make sure its displayed over everything else.
|
||||
mitem_exmenu m = spawn(mitem_exmenu, item_text:_("Mods List"), item_flags:IF_SELECTABLE, item_command:"m_main", frame_stdheight:h);
|
||||
desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0');
|
||||
desktop.item_focuschange(m, IF_KFOCUSED);
|
||||
m.totop();
|
||||
|
||||
//draw title art above the options
|
||||
mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN);
|
||||
m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [banner.item_size_x*-0.5, h*-0.5], [banner.item_size_x*0.5, 24]);
|
||||
|
||||
//spawn a container frame for the actual options. this provides a scrollbar if we have too many items.
|
||||
mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE);
|
||||
m.add(fr, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_OWN_MIN|RS_Y_MAX_PARENT_MID, [-140, h*-0.5+32], [280, h*0.5]);
|
||||
|
||||
float mod;
|
||||
for (mod = 0; ; mod++)
|
||||
{
|
||||
string gamedir = getgamedirinfo(mod, GGDI_GAMEDIR);
|
||||
if not(gamedir)
|
||||
break;
|
||||
string desc = getgamedirinfo(mod, GGDI_DESCRIPTION);
|
||||
if (desc=="")
|
||||
{ //clean up some stuff a little, if we know it.
|
||||
string lwr = strtolower(gamedir); //windows sucks.
|
||||
if (lwr == "hipnotic")
|
||||
desc = "Scourge of Armagon";
|
||||
else if (lwr == "rogue")
|
||||
desc = "Dissolution of Eternity";
|
||||
else if (lwr == "dopa")
|
||||
desc = "Dimension of the Past";
|
||||
else if (lwr == "ad")
|
||||
desc = "Arcane Dimensions";
|
||||
else if (lwr == "quoth")
|
||||
desc = "Quoth";
|
||||
else if (lwr == "rally")
|
||||
desc = "Quake Rally";
|
||||
else if (lwr == "fortress")
|
||||
desc = "Team Fortress";
|
||||
}
|
||||
if (desc=="")
|
||||
desc = sprintf("%s/", gamedir); //no description given, so make it clear that its an actual subdir name
|
||||
else
|
||||
desc = sprintf("%s ^h(%s)", desc, gamedir); //include the gamedir, faded somewhat.
|
||||
string cmd = getgamedirinfo(mod, GGDI_LOADCOMMAND);
|
||||
if not(cmd) //for dp users, if they somehow run this
|
||||
cmd = sprintf("gamedir %s", gamedir);
|
||||
|
||||
string icon = getgamedirinfo(mod, GGDI_ICON);
|
||||
|
||||
//add some extra stuff to reset the menu
|
||||
cmd = strcat("m_pop; ", cmd, "; togglemenu");
|
||||
|
||||
fr.add(spawn(mitem_pictext, pic:icon, item_text:desc, item_command:cmd, item_scale:16, item_flags:0), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, mod*16], [0, 16]);
|
||||
}
|
||||
|
||||
if (!mod)
|
||||
fr.add(spawn(mitem_text, item_text:"No mods detected", item_scale:16, item_flags:0), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, mod*16], [0, 16]);
|
||||
|
||||
//and give us a suitable menu tint too, just because.
|
||||
addmenuback(m);
|
||||
};
|
|
@ -38,6 +38,7 @@ nonstatic void(mitem_desktop desktop) M_Options =
|
|||
{fr.add(spawn(mitem_text, item_text:"Graphical Presets", item_command:"m_pop;m_preset", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;}
|
||||
fr.add(spawn(mitem_text, item_text:"Game Configs", item_command:"m_pop;m_configs", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
|
||||
fr.add(spawn(mitem_text, item_text:"Basic Setup", item_command:"m_pop;m_basicopts", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
|
||||
fr.add(spawn(mitem_text, item_text:"Keys", item_command:"m_pop;m_keys", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
|
||||
fr.add(spawn(mitem_text, item_text:"Audio", item_command:"m_pop;m_audio", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
|
||||
fr.add(spawn(mitem_text, item_text:"Video", item_command:"m_pop;m_video", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
|
||||
fr.add(spawn(mitem_text, item_text:"Effects", item_command:"m_pop;m_effects", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
|
||||
|
@ -45,11 +46,12 @@ nonstatic void(mitem_desktop desktop) M_Options =
|
|||
{fr.add(spawn(mitem_text, item_text:"Particles", item_command:"m_pop;m_particles", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;}
|
||||
if (assumefalsecheckcommand("ezhud_nquake"))
|
||||
{fr.add(spawn(mitem_text, item_text:"Hud", item_command:"m_pop;m_hud", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;}
|
||||
fr.add(spawn(mitem_text, item_text:"Keys", item_command:"m_pop;m_keys", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;
|
||||
if (assumefalsecheckcommand("cfg_save"))
|
||||
{fr.add(spawn(mitem_text, item_text:"Save Settings", item_command:"cfg_save", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;}
|
||||
if (checkbuiltin2(buf_cvarlist, TRUE))
|
||||
{fr.add(spawn(mitem_text, item_text:"Advanced Guru Settings", item_command:"m_pop;m_cvars", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;}
|
||||
if (assumefalsecheckcommand("cvarreset"))
|
||||
{fr.add(spawn(mitem_text, item_text:"Reset to Defaults", item_command:"m_reset", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;}
|
||||
if (assumefalsecheckcommand("cfg_save"))
|
||||
{fr.add(spawn(mitem_text, item_text:"Save Settings", item_command:"cfg_save", item_scale:16, item_flags:IF_CENTERALIGN), fl, [0, pos], [0, 16]); pos += 16;}
|
||||
|
||||
//random art for style
|
||||
#if 1//def CSQC
|
||||
|
|
|
@ -1,8 +1,30 @@
|
|||
static class audiomenu : mitem_exmenu
|
||||
{
|
||||
virtual string(string key) get =
|
||||
{
|
||||
if (key == "s_device" || key == "cl_voip_capturedevice")
|
||||
{ //the cvar supports multiple options, but we only support one. :(
|
||||
//so just return the first to avoid getting too confused.
|
||||
tokenize(super::get(key));
|
||||
return argv(0);
|
||||
}
|
||||
return super::get(key);
|
||||
};
|
||||
virtual void(string key, string val) set =
|
||||
{
|
||||
if (key == "s_device" || key == "cl_voip_capturedevice")
|
||||
{ //add some quotes.
|
||||
val = strcat("\"", val, "\"");
|
||||
}
|
||||
super::set(key, val);
|
||||
};
|
||||
};
|
||||
|
||||
nonstatic void(mitem_desktop desktop) M_Options_Audio =
|
||||
{
|
||||
local float pos;
|
||||
mitem_exmenu m;
|
||||
m = spawn(mitem_exmenu, item_text:_("Audio Options"), item_flags:IF_SELECTABLE, item_command:"m_options");
|
||||
m = spawn(audiomenu, item_text:_("Audio Options"), item_flags:IF_SELECTABLE, item_command:"m_options");
|
||||
desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0');
|
||||
desktop.item_focuschange(m, IF_KFOCUSED);
|
||||
m.totop();
|
||||
|
@ -29,12 +51,14 @@ nonstatic void(mitem_desktop desktop) M_Options_Audio =
|
|||
fr.add(menuitemslider_spawn(_("Music Volume"), "bgmvolume", '0 0.5 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
|
||||
fr.add(menuitemslider_spawn(_("Channels"), "s_numspeakers", '1 6 1', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
|
||||
fr.add(menuitemcombo_spawn(_("Audio Quality"), "s_khz", '280 8', _(
|
||||
"11025 \"11025hz (vanilla quake)\" "
|
||||
"22050 \"22050hz\" "
|
||||
"44100 \"44100hz (cd quality)\" "
|
||||
"48000 \"48000hz (dvd quality)\" "
|
||||
"96000 \"96000hz\" "
|
||||
"192000 \"192000hz\" "
|
||||
"8 \"8000hz (telephone quality)\" "
|
||||
"11.025 \"11025hz (vanilla quake)\" "
|
||||
"22.05 \"22050hz\" "
|
||||
"44.1 \"44100hz (cd quality)\" "
|
||||
"48 \"48000hz (dvd quality)\" "
|
||||
//higher values are probably pointless when source data doesn't go that high, so not going to list them.
|
||||
//"96 \"96000hz (blu-ray quality)\" "
|
||||
//"192 \"192000hz (professional quality)\" "
|
||||
)), fl, [0, pos], [0, 8]); pos += 8;
|
||||
fr.add(menuitemcheck_spawn(_("Doppler"), "s_doppler", '280 8'), fl, [0, pos], [0, 8]); pos += 8;
|
||||
fr.add(menuitemcheck_spawn(_("8bit audio"), "s_loadas8bit", '280 8'), fl, [0, pos], [0, 8]); pos += 8;
|
||||
|
|
|
@ -17,7 +17,7 @@ nonstatic void(mitem_desktop desktop) M_Options_Hud =
|
|||
|
||||
//spawn a container frame for the actual options. this provides a scrollbar if we have too many items.
|
||||
mitem_frame fr = spawn(mitem_frame, item_flags: IF_SELECTABLE, frame_hasscroll:TRUE);
|
||||
m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h], [0, h*2]);
|
||||
m.add(fr, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, -h+16], [0, h*2+32]);
|
||||
|
||||
float fs = search_begin("huds/*.cfg", TRUE, TRUE);
|
||||
float fc = search_getsize(fs);
|
||||
|
|
184
quakec/menusys/menu/updates.qc
Normal file
184
quakec/menusys/menu/updates.qc
Normal file
|
@ -0,0 +1,184 @@
|
|||
#include "../menusys/mitem_grid.qc"
|
||||
|
||||
enum
|
||||
{
|
||||
GPMI_NAME, //name of the package, for use with the pkg command.
|
||||
GPMI_CATEGORY, //category text
|
||||
GPMI_TITLE, //name of the package, for showing the user.
|
||||
GPMI_VERSION, //version info (may have multiple with the same name but different versions)
|
||||
GPMI_DESCRIPTION, //some blurb
|
||||
GPMI_LICENSE, //what license its distributed under
|
||||
GPMI_AUTHOR, //name of the person(s) who created it
|
||||
GPMI_WEBSITE, //where to contribute/find out more info/etc
|
||||
GPMI_INSTALLED, //current state
|
||||
GPMI_ACTION, //desired state
|
||||
GPMI_AVAILABLE, //whether it may be downloaded or not.
|
||||
GPMI_FILESIZE, //whether it may be downloaded or not.
|
||||
};
|
||||
|
||||
class mitem_updategrid : mitem_grid
|
||||
{
|
||||
virtual void(vector pos) item_draw =
|
||||
{ //make sure we see any updates as they're detected...
|
||||
if (getpackagemanagerinfo(grid_numchildren, GPMI_NAME))
|
||||
{
|
||||
grid_numchildren++;
|
||||
while(getpackagemanagerinfo(grid_numchildren, GPMI_NAME))
|
||||
grid_numchildren++;
|
||||
item_resized();
|
||||
}
|
||||
super::item_draw(pos);
|
||||
};
|
||||
virtual void(vector pos, float idx) grid_draw;
|
||||
virtual float(vector pos, float scan, float char, float down, float idx) grid_keypress;
|
||||
// virtual void(float olditem, float newitem) grid_selectionchanged;
|
||||
};
|
||||
void(vector pos, float idx) mitem_updategrid::grid_draw =
|
||||
{
|
||||
string text = getpackagemanagerinfo(idx, GPMI_TITLE);
|
||||
|
||||
vector col = item_rgb;
|
||||
if (item_flags & IF_MFOCUSED && idx == grid_mactive)
|
||||
col_z = 0;
|
||||
if (item_flags & IF_KFOCUSED && idx == grid_kactive)
|
||||
col_x = 0;
|
||||
|
||||
string status = getpackagemanagerinfo(idx, GPMI_INSTALLED);
|
||||
string action = getpackagemanagerinfo(idx, GPMI_ACTION);
|
||||
|
||||
if (action == "purge") //delete the thing
|
||||
action = "^&F4 ";
|
||||
else if (action=="reinstall") //purge then reinstall(the purge status was explicit at least.)
|
||||
action = "^&F2P";
|
||||
else if (action=="user") //install(explcitly by user)
|
||||
action = "^&F2 ";
|
||||
else if (action=="auto") //install(to satisfy dependancies)
|
||||
action = "^&FA ";
|
||||
else if (action=="disable")
|
||||
action = "^&FE ";
|
||||
else if (action=="retain")
|
||||
action = "^&FE ";
|
||||
else
|
||||
action = "^&F4 ";
|
||||
|
||||
if (status == "0%" || status == "pending")
|
||||
{
|
||||
ui.drawfill(pos, [item_size_x, item_scale], '0 0 0.5', 0.1, 0);
|
||||
action = status = " ";
|
||||
}
|
||||
else if (strstrofs(status, "%")>=0)
|
||||
{
|
||||
float frac = stof(status)/100;
|
||||
ui.drawfill(pos, [item_size_x*frac, item_scale], '0 0 0.5', 0.9, 0);
|
||||
action = status = " ";
|
||||
}
|
||||
else if (status == "corrupt")
|
||||
status = "^&FE?"; //yellow
|
||||
else if (status == "enabled")
|
||||
status = "^&F2 "; //green
|
||||
else if (status == "present")
|
||||
status = "^&FE "; //yellow
|
||||
else
|
||||
status = "^&F4 "; //red
|
||||
|
||||
ui.drawstring(pos, strcat(status, action, "^&F-", text), '1 1 0' * item_scale, col, item_alpha, 0);
|
||||
};
|
||||
/*void(float olditem, float newitem) mitem_updategrid::grid_selectionchanged =
|
||||
{
|
||||
};
|
||||
*/float(vector pos, float scan, float char, float down, float idx) mitem_updategrid::grid_keypress =
|
||||
{
|
||||
string text;
|
||||
if (!down)
|
||||
return FALSE;
|
||||
else if (scan == K_DEL||scan == K_BACKSPACE||scan == K_LEFTARROW)
|
||||
{
|
||||
text = getpackagemanagerinfo(idx, GPMI_NAME);
|
||||
if (!text)
|
||||
return FALSE;
|
||||
|
||||
string action = getpackagemanagerinfo(idx, GPMI_ACTION);
|
||||
if (action == "purge") //delete the thing
|
||||
action = "rem";
|
||||
else if (action=="reinstall") //purge then reinstall(the purge status was explicit at least.)
|
||||
action = "rem";
|
||||
else if (action=="user") //install(explcitly by user)
|
||||
action = "rem";
|
||||
else if (action=="auto") //install(to satisfy dependancies)
|
||||
action = "rem";
|
||||
else
|
||||
action = "del";
|
||||
|
||||
text = strcat("pkg quiet_", action, " \"", text, "\"\n");
|
||||
localcmd(text);
|
||||
}
|
||||
else if (scan == K_RIGHTARROW || scan==K_ENTER || scan == K_MOUSE1)
|
||||
{
|
||||
text = getpackagemanagerinfo(idx, GPMI_NAME);
|
||||
if (!text)
|
||||
return FALSE;
|
||||
text = strcat("pkg quiet_add \"", text, "\"\n");
|
||||
localcmd(text);
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class menu_updates : mitem_exmenu
|
||||
{
|
||||
string filter;
|
||||
|
||||
mitem_updategrid grid;
|
||||
|
||||
virtual string(string key) get =
|
||||
{
|
||||
if (key == "info")
|
||||
{
|
||||
string text, tmp;
|
||||
tmp = getpackagemanagerinfo(grid.grid_kactive, GPMI_VERSION); text = strcat(text, "^aVersion:^a ", tmp?:"Unspecified");
|
||||
tmp = getpackagemanagerinfo(grid.grid_kactive, GPMI_AUTHOR); text = strcat(text, "\n^aAuthor:^a ", tmp?:"Unknown");
|
||||
tmp = getpackagemanagerinfo(grid.grid_kactive, GPMI_LICENSE); text = strcat(text, "\n^aLicense:^a ", tmp?:"Unknown");
|
||||
tmp = getpackagemanagerinfo(grid.grid_kactive, GPMI_WEBSITE); text = strcat(text, "\n^aWebsite:^a ", tmp?:"Unknown");
|
||||
tmp = getpackagemanagerinfo(grid.grid_kactive, GPMI_DESCRIPTION); text = strcat(text, "\n^aDescription:^a ", tmp?:"No description specified");
|
||||
return text;
|
||||
}
|
||||
return super::get(key);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
void(mitem_desktop desktop) M_Menu_Updates =
|
||||
{
|
||||
mitem it;
|
||||
float h = (480+240)/2;
|
||||
|
||||
localcmd("pkg update\n");
|
||||
|
||||
//create the menu, give it focus, and make sure its displayed over everything else.
|
||||
menu_updates m = spawn(menu_updates, item_text:_("Updates List"), item_flags:IF_SELECTABLE, item_command:"m_main", frame_stdheight:h);
|
||||
desktop.add(m, RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MAX, '0 0', '0 0');
|
||||
desktop.item_focuschange(m, IF_KFOCUSED);
|
||||
m.totop();
|
||||
|
||||
//draw title art above the options
|
||||
mitem_pic banner = spawn(mitem_pic, item_text:"gfx/ttl_cstm.lmp", item_size_y:24, item_flags:IF_CENTERALIGN);
|
||||
m.add(banner, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_OWN_MIN, [banner.item_size_x*-0.5, h*-0.5], [banner.item_size_x*0.5, 24]);
|
||||
|
||||
//spawn our grid for the actual options. this provides a scrollbar if we have too many items.
|
||||
m.grid = spawn(mitem_updategrid, item_flags: IF_SELECTABLE, item_scale: 8);
|
||||
m.add(m.grid, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MID|RS_Y_MAX_PARENT_MID, [-160, h*-0.5+32], [40, h*0.5]);
|
||||
|
||||
it = spawn(mitem_label, item_text: "info", item_flags: 0, item_scale: 8);
|
||||
m.add(it, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MID, [40, h*-0.5+32], [0, h*0.5-16]);
|
||||
|
||||
it = spawn(mitem_button, item_text: "Apply", item_command: "pkg apply\n", item_flags: IF_SELECTABLE, item_scale: 8);
|
||||
m.add(it, RS_X_MIN_PARENT_MID|RS_Y_MIN_PARENT_MID | RS_X_MAX_PARENT_MAX|RS_Y_MAX_PARENT_MID, [40+1, h*0.5-16+1], [0-1, h*0.5-1]);
|
||||
|
||||
//and give us a suitable menu tint too, just because.
|
||||
addmenuback(m);
|
||||
};
|
|
@ -11,13 +11,13 @@ The possible values is a separate popup.
|
|||
class mitem_combo;
|
||||
class mitem_combo_popup;
|
||||
|
||||
class mitem_combo : mitem
|
||||
class mitem_combo : mitem_edit
|
||||
{
|
||||
virtual void(vector pos) item_draw;
|
||||
virtual float(vector pos, float scan, float char, float down) item_keypress;
|
||||
virtual void(mitem newfocus, float changedflag) item_focuschange;
|
||||
|
||||
mitem_combo_popup cfriend;
|
||||
mitem_combo_popup cpopup;
|
||||
string mstrlist;
|
||||
float firstrow;
|
||||
float visrows;
|
||||
|
@ -32,6 +32,10 @@ class mitem_combo : mitem
|
|||
item_flags &= ~IF_SELECTABLE;
|
||||
super::item_resized();
|
||||
};
|
||||
void() mitem_combo =
|
||||
{
|
||||
spos = -1;
|
||||
};
|
||||
};
|
||||
|
||||
class mitem_combo_popup : mitem
|
||||
|
@ -40,22 +44,28 @@ class mitem_combo_popup : mitem
|
|||
virtual float(vector pos, float scan, float char, float down) item_keypress;
|
||||
virtual void(mitem newfocus, float changedflag) item_focuschange;
|
||||
|
||||
mitem_combo pfriend;
|
||||
mitem_combo pcombo;
|
||||
mitem_vslider pslider;
|
||||
float slidercache;
|
||||
|
||||
virtual void() item_remove =
|
||||
{
|
||||
if (pfriend)
|
||||
pfriend.cfriend = 0;
|
||||
if (pslider)
|
||||
pslider.item_remove();
|
||||
if (pcombo)
|
||||
pcombo.cpopup = 0;
|
||||
super::item_remove();
|
||||
};
|
||||
};
|
||||
|
||||
void() mitem_combo::item_remove =
|
||||
{
|
||||
mitem_combo_popup p = cfriend;
|
||||
mitem_combo_popup p = cpopup;
|
||||
if (p)
|
||||
p.item_remove();
|
||||
strunzone(mstrlist);
|
||||
item_text = __NULL__;
|
||||
item_command = __NULL__;
|
||||
super::item_remove();
|
||||
};
|
||||
|
||||
|
@ -67,10 +77,16 @@ void(vector pos) mitem_combo::item_draw =
|
|||
if (!(item_flags & IF_SELECTABLE))
|
||||
rgb *= 0.2;
|
||||
|
||||
if (cfriend)
|
||||
cfriend.item_position = pos + [item_size_x / 2, item_size_y];
|
||||
if (cpopup)
|
||||
cpopup.item_position = pos + [item_size_x / 2, item_size_y];
|
||||
|
||||
if (spos >= 0)
|
||||
{
|
||||
super::item_draw(pos);
|
||||
return;
|
||||
}
|
||||
else
|
||||
mitem::item_draw(pos);
|
||||
|
||||
v = tokenize(mstrlist);
|
||||
|
||||
|
@ -105,17 +121,18 @@ void(vector pos) mitem_combo::item_draw =
|
|||
};
|
||||
void(mitem newfocus, float flag) mitem_combo::item_focuschange =
|
||||
{
|
||||
if (!cfriend || !(flag & IF_KFOCUSED))
|
||||
if (!cpopup || !(flag & IF_KFOCUSED))
|
||||
return; //don't care
|
||||
if (newfocus != (mitem)this && newfocus != (mitem)cfriend)
|
||||
if (newfocus != (mitem)this && newfocus != (mitem)cpopup)
|
||||
{
|
||||
cfriend.item_size = cfriend.maxs = '0 0';
|
||||
cfriend.item_flags &~= IF_SELECTABLE;
|
||||
cpopup.item_size = cpopup.maxs = '0 0';
|
||||
cpopup.item_flags &~= IF_SELECTABLE;
|
||||
}
|
||||
spos = -1;
|
||||
};
|
||||
void(mitem newfocus, float flag) mitem_combo_popup::item_focuschange =
|
||||
{
|
||||
pfriend.item_focuschange(newfocus, flag);
|
||||
pcombo.item_focuschange(newfocus, flag);
|
||||
};
|
||||
void(vector pos) mitem_combo_popup::item_draw =
|
||||
{
|
||||
|
@ -123,11 +140,15 @@ void(vector pos) mitem_combo_popup::item_draw =
|
|||
if (item_size_y < 1)
|
||||
return;
|
||||
|
||||
local mitem_combo f = pfriend;
|
||||
local mitem_combo f = pcombo;
|
||||
item_command = f.item_command;
|
||||
local string curval = f.get(f.item_command);
|
||||
local float i, m, c, v;
|
||||
|
||||
vector popupsize = item_size;
|
||||
|
||||
|
||||
|
||||
if (!((f.item_flags | item_flags) & IF_KFOCUSED))
|
||||
{
|
||||
item_size = maxs = '0 0';
|
||||
|
@ -135,13 +156,13 @@ void(vector pos) mitem_combo_popup::item_draw =
|
|||
return;
|
||||
}
|
||||
|
||||
ui.drawfill(pos, item_size, item_rgb, item_alpha, 0);
|
||||
ui.drawfill(pos, popupsize, item_rgb, item_alpha, 0);
|
||||
|
||||
/* //border
|
||||
ui.drawfill(pos, [item_size_x, 1], TD_BOT, item_alpha, 0);
|
||||
ui.drawfill(pos, [1, item_size_y - 1], TD_RGT, item_alpha, 0);
|
||||
ui.drawfill(pos + [item_size_x-1, 1], [1, item_size_y - 1], TD_LFT, item_alpha, 0);
|
||||
ui.drawfill(pos + [0, item_size_y-1], [item_size_x, 1], TD_TOP, item_alpha, 0);
|
||||
ui.drawfill(pos, [popupsize_x, 1], TD_BOT, item_alpha, 0);
|
||||
ui.drawfill(pos, [1, popupsize_y - 1], TD_RGT, item_alpha, 0);
|
||||
ui.drawfill(pos + [popupsize_x-1, 1], [1, popupsize_y - 1], TD_LFT, item_alpha, 0);
|
||||
ui.drawfill(pos + [0, popupsize_y-1], [popupsize_x, 1], TD_TOP, item_alpha, 0);
|
||||
*/ pos_x += 1;
|
||||
|
||||
v = tokenize(f.mstrlist);
|
||||
|
@ -149,13 +170,13 @@ void(vector pos) mitem_combo_popup::item_draw =
|
|||
if (argv(c) == curval)
|
||||
break;
|
||||
if (c >= v)
|
||||
c = 0;
|
||||
c = -1;
|
||||
|
||||
i = f.firstrow;
|
||||
i = i*2;
|
||||
if (!f.visrows)
|
||||
i = 0;
|
||||
else
|
||||
else if (c >= 0)
|
||||
{
|
||||
//bound the displayed position
|
||||
if (c < i)
|
||||
|
@ -163,17 +184,52 @@ void(vector pos) mitem_combo_popup::item_draw =
|
|||
if (i < c - (f.visrows-1)*2)
|
||||
i = c - (f.visrows-1)*2;
|
||||
}
|
||||
m = i + f.visrows*2;
|
||||
f.firstrow = floor(i*0.5);
|
||||
|
||||
//constrain the drawing so it doesn't overflow the combo
|
||||
ui.setcliparea(pos[0], pos[1], item_size[0], item_size[1]);
|
||||
if (v > f.visrows*2)
|
||||
{
|
||||
if (!pslider)
|
||||
{
|
||||
slidercache = -2;
|
||||
pslider = spawn(mitem_vslider);
|
||||
}
|
||||
}
|
||||
else if (pslider)
|
||||
{
|
||||
pslider.item_remove();
|
||||
pslider = __NULL__;
|
||||
}
|
||||
|
||||
if (pslider)
|
||||
{
|
||||
popupsize_x -= pslider.item_size_x;
|
||||
if (slidercache != c)
|
||||
{ //current index changed, force the slider to the active item.
|
||||
slidercache = c;
|
||||
pslider.val = f.firstrow;
|
||||
}
|
||||
pslider.maxv = v/2 - f.visrows;
|
||||
pslider.item_size_y = popupsize_y;
|
||||
pslider.item_draw(pos + [popupsize_x, 0]);
|
||||
}
|
||||
|
||||
//constrain the drawing so it doesn't overflow the popup
|
||||
ui.setcliparea(pos[0], pos[1], popupsize[0], popupsize[1]);
|
||||
|
||||
if (pslider)
|
||||
{
|
||||
f.firstrow = i = floor(pslider.val);
|
||||
m = ((i!=pslider.val) + i + f.visrows)*2;
|
||||
i *= 2;
|
||||
pos[1] -= (pslider.val-i/2) * item_scale;
|
||||
}
|
||||
else m = i + f.visrows*2;
|
||||
|
||||
for (; i < m && i < v ; i+=2)
|
||||
{
|
||||
col = f.item_rgb;
|
||||
if (item_flags & IF_MFOCUSED)
|
||||
if (mouseinbox(pos, [item_size_x, item_scale]))
|
||||
if (mouseinbox(pos, [popupsize_x, item_scale]))
|
||||
col_z = 0;
|
||||
if (c == i)
|
||||
col_x = 0;
|
||||
|
@ -187,7 +243,14 @@ void(vector pos) mitem_combo_popup::item_draw =
|
|||
};
|
||||
float(vector pos, float scan, float char, float down) mitem_combo_popup::item_keypress =
|
||||
{
|
||||
return pfriend.item_keypress(pos - [0, pfriend.item_size_y], scan, char, down);
|
||||
if (pslider && scan == K_MOUSE1)
|
||||
{
|
||||
vector sliderpos = pos + [item_size_x-pslider.item_size_x,0];
|
||||
if (mouseinbox(pos + [item_size_x-pslider.item_size_x,0], pslider.item_size))
|
||||
return pslider.item_keypress(sliderpos, scan, char, down);
|
||||
}
|
||||
|
||||
return pcombo.item_keypress(pos - [0, pcombo.item_size_y], scan, char, down);
|
||||
};
|
||||
float(vector pos, float scan, float char, float down) mitem_combo::item_keypress =
|
||||
{
|
||||
|
@ -210,21 +273,21 @@ float(vector pos, float scan, float char, float down) mitem_combo::item_keypress
|
|||
|
||||
if (scan == K_ESCAPE || scan == K_MOUSE2)
|
||||
{
|
||||
if (cfriend)
|
||||
if (cpopup)
|
||||
{
|
||||
cfriend.item_remove();
|
||||
cpopup.item_remove();
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
else if (scan == K_MWHEELUP || (scan == K_UPARROW && cfriend))
|
||||
else if (scan == K_MWHEELUP || (scan == K_UPARROW && cpopup))
|
||||
{
|
||||
i -= 2;
|
||||
if (i < 0)
|
||||
i = c - 2;
|
||||
curval = argv(i);
|
||||
}
|
||||
else if (scan == K_MWHEELDOWN || (scan == K_DOWNARROW && cfriend))
|
||||
else if (scan == K_MWHEELDOWN || (scan == K_DOWNARROW && cpopup))
|
||||
{
|
||||
i += 2;
|
||||
if (i >= c)
|
||||
|
@ -233,20 +296,20 @@ float(vector pos, float scan, float char, float down) mitem_combo::item_keypress
|
|||
}
|
||||
else if (scan == K_MOUSE1 || scan == K_ENTER)
|
||||
{
|
||||
if (scan == K_ENTER && cfriend)
|
||||
if (scan == K_ENTER && cpopup)
|
||||
{
|
||||
cfriend.item_remove();
|
||||
cpopup.item_remove();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
visrows = ((c>18)?18/2:c/2);
|
||||
if (!cfriend)
|
||||
if (!cpopup)
|
||||
{
|
||||
cfriend = spawn(mitem_combo_popup);
|
||||
cfriend.pfriend = this;
|
||||
cfriend.item_scale = 8;
|
||||
cfriend.item_rgb = MENUBACK_RGB;
|
||||
cfriend.item_alpha = MENUBACK_ALPHA;
|
||||
cpopup = spawn(mitem_combo_popup);
|
||||
cpopup.pcombo = this;
|
||||
cpopup.item_scale = 8;
|
||||
cpopup.item_rgb = MENUBACK_RGB;
|
||||
cpopup.item_alpha = MENUBACK_ALPHA;
|
||||
pos = item_position;
|
||||
mitem_frame fr = item_parent;
|
||||
while (fr.item_parent)
|
||||
|
@ -254,36 +317,44 @@ float(vector pos, float scan, float char, float down) mitem_combo::item_keypress
|
|||
pos += fr.item_position;
|
||||
fr = fr.item_parent;
|
||||
}
|
||||
fr.addr(cfriend, RS_X_MIN_PARENT_MIN | RS_X_MAX_OWN_MIN | RS_Y_MIN_PARENT_MIN | RS_Y_MAX_OWN_MIN, pos + [self.item_size_x / 2, self.item_size_y], [item_size_x*0.5, item_size_y*visrows]);
|
||||
fr.addr(cpopup, RS_X_MIN_PARENT_MIN | RS_X_MAX_OWN_MIN | RS_Y_MIN_PARENT_MIN | RS_Y_MAX_OWN_MIN, pos + [self.item_size_x / 2, self.item_size_y], [item_size_x*0.5, item_size_y*visrows]);
|
||||
}
|
||||
cfriend.item_size = cfriend.maxs = [item_size_x*0.5, item_size_y*visrows];
|
||||
cfriend.item_flags |= IF_SELECTABLE;
|
||||
cfriend.totop();
|
||||
cpopup.item_size = cpopup.maxs = [item_size_x*0.5, item_size_y*visrows];
|
||||
cpopup.item_flags |= IF_SELECTABLE;
|
||||
cpopup.totop();
|
||||
|
||||
if (scan == K_MOUSE1 && (cfriend.item_flags & IF_MFOCUSED))
|
||||
if (scan == K_MOUSE1 && (cpopup.item_flags & IF_MFOCUSED))
|
||||
{
|
||||
//if they clicked inside the popup, change the selected item.
|
||||
f = ui.mousepos[1] - (pos_y + item_size_y);
|
||||
f /= cfriend.item_scale;
|
||||
f /= cpopup.item_scale;
|
||||
f += firstrow;
|
||||
i = floor(f) * 2;
|
||||
if (i < c)
|
||||
{
|
||||
curval = argv(i);
|
||||
cfriend.item_flags &~= IF_SELECTABLE;
|
||||
cfriend.item_size = cfriend.maxs = '0 0';
|
||||
cpopup.item_flags &~= IF_SELECTABLE;
|
||||
cpopup.item_size = cpopup.maxs = '0 0';
|
||||
item_parent.item_focuschange(this, IF_MFOCUSED|IF_KFOCUSED);
|
||||
|
||||
cfriend.item_remove();
|
||||
cpopup.item_remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (scan == K_BACKSPACE || scan == K_DEL)
|
||||
curval = substring(curval, 0, -2);
|
||||
else if (char >= ' ')
|
||||
curval = strcat(curval, chr2str(char));
|
||||
else
|
||||
{
|
||||
if (spos < 0)
|
||||
{
|
||||
spos = strlen(curval);
|
||||
if (!super::item_keypress(pos, scan, char, down))
|
||||
{
|
||||
spos = -1;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else return super::item_keypress(pos, scan, char, down);
|
||||
}
|
||||
|
||||
set(item_command, curval);
|
||||
return TRUE;
|
||||
|
|
|
@ -321,10 +321,11 @@ void(mitem_desktop desktop) items_draw =
|
|||
items_updategrabs(FALSE);
|
||||
if (dp_workarounds && oldgrabstate)
|
||||
{
|
||||
if (drawgetimagesize(autocvar_cl_cursor) == '0 0')
|
||||
// //hopefully dp isn't broken and reports non-zero sizes for files that failed.
|
||||
// if (drawgetimagesize(autocvar_cl_cursor) == '0 0')
|
||||
// ui.drawpic(ui.mousepos - autocvar_cl_cursorbias*'1 1', autocvar_cl_cursor, autocvar_cl_cursorsize*'1 1', '1 1 1', 1, 0);
|
||||
// else
|
||||
ui.drawcharacter(ui.mousepos - [stringwidth("+", TRUE, '4 4')*0.5, 4], '+', '8 8', '1 1 1', 1, 0);
|
||||
else
|
||||
ui.drawpic(ui.mousepos - autocvar_cl_cursorbias*'1 1', autocvar_cl_cursor, autocvar_cl_cursorsize*'1 1', '1 1 1', 1, 0);
|
||||
}
|
||||
|
||||
#ifndef MENU
|
||||
|
|
|
@ -21,7 +21,9 @@ class mitem_edit : mitem
|
|||
|
||||
void() mitem_edit::item_remove =
|
||||
{
|
||||
if (item_text)
|
||||
strunzone(item_text);
|
||||
if (item_command)
|
||||
strunzone(item_command);
|
||||
super::item_remove();
|
||||
};
|
||||
|
@ -59,11 +61,20 @@ float(vector pos, float scan, float char, float down) mitem_edit::item_keypress
|
|||
spos = max(spos-1, 0);
|
||||
else if (scan == K_RIGHTARROW)
|
||||
spos+=1;
|
||||
/* else if (scan == K_MOUSE1)
|
||||
else if (scan == K_HOME)
|
||||
spos = 0;
|
||||
else if (scan == K_END)
|
||||
spos = strlen(curval);
|
||||
else if (scan == K_MOUSE1)
|
||||
{
|
||||
//FIXME: figure out the spos for the cursor
|
||||
return TRUE;
|
||||
}*/
|
||||
float valuepos = pos_x+(item_size_x/2)+1;
|
||||
if (ui.mousepos[0] > valuepos-8)
|
||||
{
|
||||
spos = strlen(curval);
|
||||
while (spos>0 && ui.mousepos[0] < valuepos+stringwidth(substring(curval, 0, spos), TRUE, '1 1 0'*item_scale))
|
||||
spos--;
|
||||
}
|
||||
}
|
||||
else if (scan == K_BACKSPACE || scan == K_DEL)
|
||||
{
|
||||
if (spos)
|
||||
|
@ -89,7 +100,7 @@ mitem_edit(string text, string command, vector sz) menuitemeditt_spawn =
|
|||
n.item_scale = sz_y;
|
||||
n.item_text = strzone(text);
|
||||
n.item_size = sz;
|
||||
n.spos = 100000; //will be clipped so meh
|
||||
n.spos = 10000000; //will be clipped so meh
|
||||
|
||||
n.item_command = strzone(command);
|
||||
n.item_flags |= IF_SELECTABLE;
|
||||
|
|
|
@ -33,6 +33,7 @@ class mitem_frame : mitem
|
|||
|
||||
mitem_vslider vslider; //displayed if any client item's max[y] > our item_size[y]
|
||||
vector item_framesize; //x=sides, y=top, z=bottom
|
||||
float frame_stdheight; //adjust RS_Y_MIN_PARENT_MID to pinch inwards when the frame is smaller than this. Child items crossing the mid-point must size gracefully (like subframes).
|
||||
float frame_hasscroll;
|
||||
|
||||
static mitem(string title) findchildtext;
|
||||
|
@ -49,6 +50,71 @@ class mitem_frame : mitem
|
|||
};
|
||||
};
|
||||
|
||||
void(mitem ch, vector parentsize) mitem_parentresized =
|
||||
{
|
||||
float f = ch.resizeflags;
|
||||
|
||||
if (f & RS_X_FRACTION)
|
||||
ch.item_position[0] = parentsize[0] * ch.mins[0];
|
||||
else if (f & RS_X_MIN_PARENT_MAX)
|
||||
ch.item_position[0] = parentsize[0] + ch.mins[0];
|
||||
else if (f & RS_X_MIN_PARENT_MID)
|
||||
ch.item_position[0] = parentsize[0]/2 + ch.mins[0];
|
||||
else //if (f & RS_X_MIN_PARENT_MIN)
|
||||
ch.item_position[0] = ch.mins[0];
|
||||
|
||||
if (f & RS_X_FRACTION)
|
||||
ch.item_position[0] = parentsize[0] * ch.maxs[0];
|
||||
else if (f & RS_X_MAX_PARENT_MIN)
|
||||
ch.item_size[0] = ch.maxs[0] - ch.item_position[0];
|
||||
else if (f & RS_X_MAX_PARENT_MID)
|
||||
ch.item_size[0] = ch.maxs[0]+parentsize[0]/2 - ch.item_position[0];
|
||||
else if (f & RS_X_MAX_PARENT_MAX)
|
||||
ch.item_size[0] = ch.maxs[0]+parentsize[0] - ch.item_position[0];
|
||||
else //if (f & RS_X_MAX_OWN_MIN)
|
||||
ch.item_size[0] = ch.maxs[0];
|
||||
|
||||
if (f & RS_Y_FRACTION)
|
||||
ch.item_position[1] = parentsize[1] * ch.mins[1];
|
||||
else if (f & RS_Y_MIN_PARENT_MAX)
|
||||
ch.item_position[1] = parentsize[1] + ch.mins[1];
|
||||
else if (f & RS_Y_MIN_PARENT_MID)
|
||||
{
|
||||
ch.item_position[1] = parentsize[1]/2 + ch.mins[1];
|
||||
if (ch.item_parent.frame_stdheight)
|
||||
if (parentsize[1] < ch.item_parent.frame_stdheight)
|
||||
{
|
||||
if (ch.item_position[1] < parentsize[1]*0.5)
|
||||
ch.item_position[1] += (ch.item_parent.frame_stdheight-parentsize[1])*0.5;
|
||||
else
|
||||
ch.item_position[1] -= (ch.item_parent.frame_stdheight-parentsize[1])*0.5;
|
||||
}
|
||||
}
|
||||
else //if (f & RS_Y_MIN_PARENT_MIN)
|
||||
ch.item_position[1] = ch.mins[1];
|
||||
|
||||
if (f & RS_Y_FRACTION)
|
||||
ch.item_position[1] = parentsize[1] * ch.maxs[1];
|
||||
else if (f & RS_Y_MAX_PARENT_MIN)
|
||||
ch.item_size[1] = ch.maxs[1] - ch.item_position[1];
|
||||
else if (f & RS_Y_MAX_PARENT_MID)
|
||||
{
|
||||
ch.item_size[1] = ch.maxs[1]+parentsize[1]/2 - ch.item_position[1];
|
||||
if (ch.item_parent.frame_stdheight)
|
||||
if (parentsize[1] < ch.item_parent.frame_stdheight)
|
||||
{
|
||||
if (ch.item_position[1]+ch.item_size[1] < parentsize[1]*0.5)
|
||||
ch.item_size[1] += (ch.item_parent.frame_stdheight-parentsize[1])*0.5;
|
||||
else
|
||||
ch.item_size[1] -= (ch.item_parent.frame_stdheight-parentsize[1])*0.5;
|
||||
}
|
||||
}
|
||||
else if (f & RS_Y_MAX_PARENT_MAX)
|
||||
ch.item_size[1] = ch.maxs[1]+parentsize[1] - ch.item_position[1];
|
||||
else //if (f & RS_Y_MAX_OWN_MIN)
|
||||
ch.item_size[1] = ch.maxs[1];
|
||||
};
|
||||
|
||||
void(mitem fromitem, string cmd) mitem_frame::item_execcommand =
|
||||
{
|
||||
if (item_parent)
|
||||
|
@ -90,7 +156,8 @@ void(mitem newitem, float originflags, vector originmin, vector originmax) mitem
|
|||
newitem.resizeflags = originflags;
|
||||
newitem.mins = originmin;
|
||||
newitem.maxs = originmax;
|
||||
mitem_parentresized(newitem, [item_size[0] - item_framesize[0]*2, item_size[1] - (item_framesize[1] + item_framesize[2])]);
|
||||
local vector parentsize = [item_size[0] - item_framesize[0]*2, item_size[1] - (item_framesize[1] + item_framesize[2])];
|
||||
mitem_parentresized(newitem, parentsize);
|
||||
newitem.item_resized();
|
||||
|
||||
item_flags |= IF_CLIENTMOVED; //make sure it happens.
|
||||
|
@ -312,7 +379,7 @@ void(vector pos) mitem_vslider::item_draw =
|
|||
float h = item_size[1];
|
||||
float isize = w;
|
||||
|
||||
vector v = drawgetimagesize("scrollbars/slider.tga");
|
||||
vector v = dp_workarounds?'0 0 0':drawgetimagesize("scrollbars/slider.tga");
|
||||
|
||||
if (v != '0 0 0')
|
||||
{
|
||||
|
@ -352,7 +419,7 @@ void(vector pos) mitem_vslider::item_draw =
|
|||
};
|
||||
void() mitem_vslider::mitem_vslider =
|
||||
{
|
||||
item_size[0] = 16;
|
||||
item_size[0] = 8;
|
||||
item_size[1] = 128;
|
||||
};
|
||||
|
||||
|
|
210
quakec/menusys/menusys/mitem_grid.qc
Normal file
210
quakec/menusys/menusys/mitem_grid.qc
Normal file
|
@ -0,0 +1,210 @@
|
|||
#ifndef MITEM_GRID_QC__
|
||||
#define MITEM_GRID_QC__
|
||||
|
||||
//simple key/value grid (with editing).
|
||||
class mitem_grid : mitem
|
||||
{
|
||||
//virtual void(mitem newfocus, float changedflag) item_focuschange;
|
||||
virtual float(vector pos, float scan, float char, float down) item_keypress;
|
||||
virtual void(vector pos) item_draw;
|
||||
virtual void() item_resized;
|
||||
|
||||
//first child is determined from the vslider.
|
||||
float grid_numchildren;
|
||||
float grid_mactive;
|
||||
float grid_kactive;
|
||||
|
||||
mitem_vslider vslider; //displayed if any client item's max[y] > our item_size[y]
|
||||
|
||||
virtual void(vector pos, float idx) grid_draw = 0;
|
||||
virtual float(vector pos, float scan, float char, float down, float idx) grid_keypress = {return FALSE;};
|
||||
virtual void(float olditem, float newitem) grid_selectionchanged = {}; //just key focus
|
||||
};
|
||||
|
||||
//does NOT wrap.
|
||||
//does NOT pass go.
|
||||
static mitem(mitem item, float upwards) menu_simplenextitem =
|
||||
{
|
||||
mitem_frame menu = item.item_parent;
|
||||
mitem prev;
|
||||
if (upwards)
|
||||
{
|
||||
if (item)
|
||||
{
|
||||
item = item.item_next;
|
||||
if (!item)
|
||||
return __NULL__;
|
||||
return item;
|
||||
}
|
||||
else
|
||||
return __NULL__;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(prev = menu.item_children; prev.item_next; prev = prev.item_next)
|
||||
{
|
||||
if (prev.item_next == item)
|
||||
return prev;
|
||||
}
|
||||
return __NULL__;
|
||||
}
|
||||
};
|
||||
|
||||
float(vector pos, float scan, float char, float down) mitem_grid::item_keypress =
|
||||
{
|
||||
float ch;
|
||||
float handled = FALSE;
|
||||
|
||||
if (scan >= K_MOUSE1 && scan <= K_MOUSE5 && scan != K_MWHEELUP && scan != K_MWHEELDOWN)
|
||||
{
|
||||
ch = grid_mactive;
|
||||
if (ch != grid_kactive)
|
||||
if (down && scan == K_MOUSE1) //keyboard focus follows on mouse click.
|
||||
{
|
||||
item_focuschange((ch>=0)?__NULL__:vslider, IF_KFOCUSED);
|
||||
grid_selectionchanged(grid_kactive, ch);
|
||||
grid_kactive = ch;
|
||||
handled = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = grid_kactive;
|
||||
if (ch<0 && down)
|
||||
{
|
||||
//if there's no key child active, then go and pick one so you can just start using keyboard access etc.
|
||||
if (grid_mactive)
|
||||
ch = grid_mactive;
|
||||
else
|
||||
ch = 0;
|
||||
item_focuschange((ch>=0)?__NULL__:vslider, IF_KFOCUSED);
|
||||
grid_selectionchanged(grid_kactive, ch);
|
||||
grid_kactive = ch;
|
||||
}
|
||||
}
|
||||
|
||||
if (vslider)
|
||||
pos[1] -= vslider.val;
|
||||
|
||||
if (ch<0&&vslider)
|
||||
{
|
||||
if (vslider.item_keypress)
|
||||
handled = vslider.item_keypress(pos + vslider.item_position, scan, char, down);
|
||||
}
|
||||
else if (!handled && ch >= 0 && ch < grid_numchildren)
|
||||
handled = grid_keypress(pos + vslider.item_position + [0,ch]*item_scale, scan, char, down, ch);
|
||||
if (!handled && down)
|
||||
{
|
||||
ch = grid_kactive;
|
||||
switch(scan)
|
||||
{
|
||||
case K_MWHEELUP:
|
||||
case K_MWHEELDOWN:
|
||||
if (vslider) //give mwheel to the slider if its visible.
|
||||
handled = vslider.item_keypress(pos + vslider.item_position, scan, char, down);
|
||||
break;
|
||||
case K_HOME:
|
||||
ch = 0;
|
||||
break;
|
||||
case K_END:
|
||||
ch = grid_numchildren-1;
|
||||
break;
|
||||
case K_PGUP:
|
||||
ch = max(0, grid_kactive-5);
|
||||
break;
|
||||
case K_PGDN:
|
||||
ch = min(grid_numchildren-1, grid_kactive+5);
|
||||
break;
|
||||
case K_UPARROW:
|
||||
ch = max(grid_kactive-1, 0);
|
||||
break;
|
||||
case K_DOWNARROW:
|
||||
ch = min(grid_kactive+1, grid_numchildren-1);
|
||||
break;
|
||||
}
|
||||
if (ch != grid_kactive)
|
||||
{
|
||||
grid_selectionchanged(grid_kactive, ch);
|
||||
grid_kactive = ch;
|
||||
handled = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
};
|
||||
void() mitem_grid::item_resized =
|
||||
{
|
||||
float clientheight = grid_numchildren * item_scale;
|
||||
if (clientheight > item_size[1])
|
||||
{
|
||||
if (!vslider)
|
||||
vslider = spawn(mitem_vslider, val:0, stride:8);
|
||||
vslider.maxv = clientheight - item_size[1];
|
||||
}
|
||||
else if (vslider)
|
||||
{
|
||||
vslider.item_remove();
|
||||
vslider = (mitem_vslider)__NULL__;
|
||||
}
|
||||
}
|
||||
|
||||
void(vector pos) mitem_grid::item_draw =
|
||||
{
|
||||
local vector omin = ui.drawrectmin, omax = ui.drawrectmax;
|
||||
local vector clientpos;
|
||||
local vector clientsize;
|
||||
|
||||
clientpos = pos;
|
||||
clientsize = this.item_size;
|
||||
if (vslider)
|
||||
{
|
||||
//scroll+shrink the client area to fit the slider on it.
|
||||
clientpos[1] -= vslider.val;
|
||||
clientsize[0] -= vslider.item_size[0];
|
||||
}
|
||||
|
||||
if (ui.mousepos != ui.oldmousepos)
|
||||
{
|
||||
local mitem newfocus = __NULL__;
|
||||
grid_mactive = floor((ui.mousepos[1]-clientpos_y)/item_scale);
|
||||
|
||||
if (vslider)
|
||||
if (mouseinbox(pos + [clientsize[0], 0], vslider.item_size))
|
||||
{
|
||||
newfocus = vslider;
|
||||
grid_mactive = -1;
|
||||
}
|
||||
this.item_focuschange(newfocus, IF_MFOCUSED);
|
||||
}
|
||||
|
||||
//clip the draw rect to our area, so children don't draw outside it. don't draw if its inverted.
|
||||
if (pos_x > ui.drawrectmin[0])
|
||||
ui.drawrectmin[0] = pos_x;
|
||||
if (pos_y > ui.drawrectmin[1])
|
||||
ui.drawrectmin[1] = pos_y;
|
||||
if (pos_x+clientsize_x < ui.drawrectmax[0])
|
||||
ui.drawrectmax[0] = pos_x+clientsize_x;
|
||||
if (pos_y+clientsize_y < ui.drawrectmax[1])
|
||||
ui.drawrectmax[1] = pos_y+clientsize[1];
|
||||
if (ui.drawrectmax[0] > ui.drawrectmin[0] && ui.drawrectmax[1] > ui.drawrectmin[1])
|
||||
{
|
||||
ui.setcliparea(ui.drawrectmin[0], ui.drawrectmin[1], ui.drawrectmax[0] - ui.drawrectmin[0], ui.drawrectmax[1] - ui.drawrectmin[1]);
|
||||
float c = max(0,floor((ui.drawrectmin[1]-clientpos_y)/item_scale)); //calculate how many we can skip
|
||||
for (clientpos_y += item_scale * c; c < grid_numchildren; c++, clientpos_y += item_scale)
|
||||
{
|
||||
if (clientpos_y >= ui.drawrectmax[1])
|
||||
break;
|
||||
grid_draw(clientpos, c);
|
||||
}
|
||||
ui.setcliparea(omin_x, omin_y, omax_x - omin_x, omax_y - omin_y);
|
||||
|
||||
if (vslider)
|
||||
{
|
||||
vslider.item_size[1] = clientsize[1];
|
||||
vslider.item_draw(pos + [clientsize[0], 0]);
|
||||
}
|
||||
}
|
||||
ui.drawrectmin = omin;
|
||||
ui.drawrectmax = omax;
|
||||
};
|
||||
#endif
|
|
@ -190,50 +190,7 @@ float(vector minp, vector sz) mouseinbox =
|
|||
};
|
||||
|
||||
|
||||
void(mitem ch, vector parentsize) mitem_parentresized =
|
||||
{
|
||||
float f = ch.resizeflags;
|
||||
|
||||
if (f & RS_X_FRACTION)
|
||||
ch.item_position[0] = parentsize[0] * ch.mins[0];
|
||||
else if (f & RS_X_MIN_PARENT_MAX)
|
||||
ch.item_position[0] = parentsize[0] + ch.mins[0];
|
||||
else if (f & RS_X_MIN_PARENT_MID)
|
||||
ch.item_position[0] = parentsize[0]/2 + ch.mins[0];
|
||||
else //if (f & RS_X_MIN_PARENT_MIN)
|
||||
ch.item_position[0] = ch.mins[0];
|
||||
|
||||
if (f & RS_X_FRACTION)
|
||||
ch.item_position[0] = parentsize[0] * ch.maxs[0];
|
||||
else if (f & RS_X_MAX_PARENT_MIN)
|
||||
ch.item_size[0] = ch.maxs[0] - ch.item_position[0];
|
||||
else if (f & RS_X_MAX_PARENT_MID)
|
||||
ch.item_size[0] = ch.maxs[0]+parentsize[0]/2 - ch.item_position[0];
|
||||
else if (f & RS_X_MAX_PARENT_MAX)
|
||||
ch.item_size[0] = ch.maxs[0]+parentsize[0] - ch.item_position[0];
|
||||
else //if (f & RS_X_MAX_OWN_MIN)
|
||||
ch.item_size[0] = ch.maxs[0];
|
||||
|
||||
if (f & RS_Y_FRACTION)
|
||||
ch.item_position[1] = parentsize[1] * ch.mins[1];
|
||||
else if (f & RS_Y_MIN_PARENT_MAX)
|
||||
ch.item_position[1] = parentsize[1] + ch.mins[1];
|
||||
else if (f & RS_Y_MIN_PARENT_MID)
|
||||
ch.item_position[1] = parentsize[1]/2 + ch.mins[1];
|
||||
else //if (f & RS_Y_MIN_PARENT_MIN)
|
||||
ch.item_position[1] = ch.mins[1];
|
||||
|
||||
if (f & RS_Y_FRACTION)
|
||||
ch.item_position[1] = parentsize[1] * ch.maxs[1];
|
||||
else if (f & RS_Y_MAX_PARENT_MIN)
|
||||
ch.item_size[1] = ch.maxs[1] - ch.item_position[1];
|
||||
else if (f & RS_Y_MAX_PARENT_MID)
|
||||
ch.item_size[1] = ch.maxs[1]+parentsize[1]/2 - ch.item_position[1];
|
||||
else if (f & RS_Y_MAX_PARENT_MAX)
|
||||
ch.item_size[1] = ch.maxs[1]+parentsize[1] - ch.item_position[1];
|
||||
else //if (f & RS_Y_MAX_OWN_MIN)
|
||||
ch.item_size[1] = ch.maxs[1];
|
||||
};
|
||||
void(mitem ch, vector parentsize) mitem_parentresized;
|
||||
|
||||
#include "mitem_frame.qc"
|
||||
void() mitem::item_resized =
|
||||
|
|
|
@ -133,6 +133,118 @@ mitem(string text, string command, float height) menuitemtext_spawn =
|
|||
};
|
||||
|
||||
|
||||
class mitem_label : mitem
|
||||
{ //class that queries its frame to find the text to show.
|
||||
mitem_vslider vslider;
|
||||
virtual void(vector pos) item_draw =
|
||||
{
|
||||
vector rgb = menuitem_textcolour(this);
|
||||
string text = get(item_text);
|
||||
float fl = 2; //top-align
|
||||
vector textpos = pos;
|
||||
vector clientsize = item_size;
|
||||
if (item_flags & IF_CENTERALIGN)
|
||||
fl |= 0; //default is to center align
|
||||
else if (item_flags & IF_RIGHTALIGN)
|
||||
fl |= 4; //right align.
|
||||
else
|
||||
fl |= 1; //left align.
|
||||
|
||||
if (vslider)
|
||||
{
|
||||
textpos[1] -= vslider.val;
|
||||
clientsize[1] += vslider.val;
|
||||
clientsize[0] -= vslider.item_size[0];
|
||||
}
|
||||
|
||||
local vector omin = ui.drawrectmin, omax = ui.drawrectmax;
|
||||
|
||||
//clip the draw rect to our area, so text doesn't appear outside it. don't draw if its inverted.
|
||||
if (pos_x > ui.drawrectmin[0])
|
||||
ui.drawrectmin[0] = pos_x;
|
||||
if (pos_y > ui.drawrectmin[1])
|
||||
ui.drawrectmin[1] = pos_y;
|
||||
if (pos_x+clientsize_x < ui.drawrectmax[0])
|
||||
ui.drawrectmax[0] = pos_x+clientsize_x;
|
||||
if (pos_y+clientsize_y < ui.drawrectmax[1])
|
||||
ui.drawrectmax[1] = pos_y+clientsize[1];
|
||||
if (ui.drawrectmax[0] > ui.drawrectmin[0] && ui.drawrectmax[1] > ui.drawrectmin[1])
|
||||
{
|
||||
ui.setcliparea(ui.drawrectmin[0], ui.drawrectmin[1], ui.drawrectmax[0] - ui.drawrectmin[0], ui.drawrectmax[1] - ui.drawrectmin[1]);
|
||||
clientsize[1] = drawtextfield(textpos, clientsize, fl, text) * item_scale;
|
||||
ui.setcliparea(omin_x, omin_y, omax_x - omin_x, omax_y - omin_y);
|
||||
|
||||
if (vslider)
|
||||
{
|
||||
vslider.item_size[1] = item_size[1];
|
||||
if (ui.mousepos != ui.oldmousepos)
|
||||
{
|
||||
if (mouseinbox(pos + [clientsize[0], 0], vslider.item_size))
|
||||
this.item_focuschange(vslider, IF_MFOCUSED);
|
||||
}
|
||||
vslider.item_draw(pos + [clientsize[0], 0]);
|
||||
}
|
||||
}
|
||||
ui.drawrectmin = omin;
|
||||
ui.drawrectmax = omax;
|
||||
|
||||
if (clientsize[1] > item_size[1])
|
||||
{ //enough text that we need a scrollbar.
|
||||
if (!vslider)
|
||||
vslider = spawn(mitem_vslider, val:0, stride:8);
|
||||
vslider.maxv = clientsize[1] - item_size[1];
|
||||
item_flags |= IF_SELECTABLE;
|
||||
}
|
||||
else if (vslider)
|
||||
{ //the text got shorter...
|
||||
vslider.item_remove();
|
||||
vslider = (mitem_vslider)__NULL__;
|
||||
if (item_command == "")
|
||||
item_flags &~= IF_SELECTABLE;
|
||||
}
|
||||
};
|
||||
virtual float(vector pos, float scan, float char, float down) item_keypress =
|
||||
{
|
||||
if (vslider)
|
||||
if (vslider.item_keypress(pos, scan, char, down))
|
||||
return TRUE;
|
||||
if (this.item_command)
|
||||
{
|
||||
if (!down)
|
||||
return FALSE;
|
||||
if (scan == K_ENTER || (scan == K_MOUSE1 && mouseinbox(pos, this.item_size)))
|
||||
{
|
||||
item_parent.item_execcommand(this, this.item_command);
|
||||
// localcmd(strcat(this.item_command, "\n"));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
};
|
||||
|
||||
//zone+unzone input strings as needed
|
||||
virtual void() item_remove =
|
||||
{
|
||||
if (item_command)
|
||||
strunzone(item_command);
|
||||
if (vslider)
|
||||
{
|
||||
vslider.item_remove();
|
||||
vslider = (mitem_vslider)__NULL__;
|
||||
}
|
||||
super::item_remove();
|
||||
};
|
||||
void() mitem_label =
|
||||
{
|
||||
if (item_command != "")
|
||||
{
|
||||
item_command = strzone(item_command);
|
||||
item_flags |= IF_SELECTABLE;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
basic text item.
|
||||
identical to text, but includes a 3dish border.
|
||||
|
|
Loading…
Reference in a new issue