r122 - in trunk: . common menu menu/item menu/nexuiz menu/oo
DONOTREPLY at icculus.org
DONOTREPLY at icculus.org
Sat Aug 30 02:46:38 EDT 2008
Author: vermeulen
Date: 2008-08-30 02:46:38 -0400 (Sat, 30 Aug 2008)
New Revision: 122
Added:
trunk/common/
trunk/common/campaign_common.qh
trunk/common/campaign_file.qc
trunk/common/campaign_setup.qc
trunk/common/gamecommand.qc
trunk/common/mapinfo.qc
trunk/common/mapinfo.qh
trunk/common/util.qc
trunk/common/util.qh
trunk/menu/
trunk/menu/classes.c
trunk/menu/config.qh
trunk/menu/draw.qc
trunk/menu/draw.qh
trunk/menu/gamecommand.qc
trunk/menu/gamecommand.qh
trunk/menu/item.c
trunk/menu/item/
trunk/menu/item/borderimage.c
trunk/menu/item/button.c
trunk/menu/item/checkbox.c
trunk/menu/item/container.c
trunk/menu/item/dialog.c
trunk/menu/item/gecko.c
trunk/menu/item/image.c
trunk/menu/item/inputbox.c
trunk/menu/item/inputcontainer.c
trunk/menu/item/label.c
trunk/menu/item/listbox.c
trunk/menu/item/modalcontroller.c
trunk/menu/item/nexposee.c
trunk/menu/item/radiobutton.c
trunk/menu/item/slider.c
trunk/menu/item/tab.c
trunk/menu/item/textslider.c
trunk/menu/mbuiltin.qh
trunk/menu/menu.qc
trunk/menu/menu.qh
trunk/menu/msys.qh
trunk/menu/nexuiz/
trunk/menu/nexuiz/button.c
trunk/menu/nexuiz/campaign.c
trunk/menu/nexuiz/charmap.c
trunk/menu/nexuiz/checkbox.c
trunk/menu/nexuiz/checkbox_slider_invalid.c
trunk/menu/nexuiz/colorbutton.c
trunk/menu/nexuiz/commandbutton.c
trunk/menu/nexuiz/credits.c
trunk/menu/nexuiz/crosshairbutton.c
trunk/menu/nexuiz/dialog.c
trunk/menu/nexuiz/dialog_classselect.c
trunk/menu/nexuiz/dialog_credits.c
trunk/menu/nexuiz/dialog_infoscreen.c
trunk/menu/nexuiz/dialog_multiplayer.c
trunk/menu/nexuiz/dialog_multiplayer_create.c
trunk/menu/nexuiz/dialog_multiplayer_create_mapinfo.c
trunk/menu/nexuiz/dialog_multiplayer_create_mutators.c
trunk/menu/nexuiz/dialog_multiplayer_join.c
trunk/menu/nexuiz/dialog_multiplayer_playersetup.c
trunk/menu/nexuiz/dialog_news.c
trunk/menu/nexuiz/dialog_quit.c
trunk/menu/nexuiz/dialog_settings.c
trunk/menu/nexuiz/dialog_settings_effects.c
trunk/menu/nexuiz/dialog_settings_input.c
trunk/menu/nexuiz/dialog_settings_input_userbind.c
trunk/menu/nexuiz/dialog_settings_misc.c
trunk/menu/nexuiz/dialog_settings_video.c
trunk/menu/nexuiz/dialog_singleplayer.c
trunk/menu/nexuiz/dialog_singleplayer_winner.c
trunk/menu/nexuiz/dialog_teamselect.c
trunk/menu/nexuiz/gametypebutton.c
trunk/menu/nexuiz/image.c
trunk/menu/nexuiz/inputbox.c
trunk/menu/nexuiz/keybinder.c
trunk/menu/nexuiz/listbox.c
trunk/menu/nexuiz/mainwindow.c
trunk/menu/nexuiz/maplist.c
trunk/menu/nexuiz/nexposee.c
trunk/menu/nexuiz/playermodel.c
trunk/menu/nexuiz/radiobutton.c
trunk/menu/nexuiz/rootdialog.c
trunk/menu/nexuiz/serverlist.c
trunk/menu/nexuiz/slider.c
trunk/menu/nexuiz/slider_decibels.c
trunk/menu/nexuiz/slider_resolution.c
trunk/menu/nexuiz/tab.c
trunk/menu/nexuiz/tabcontroller.c
trunk/menu/nexuiz/textlabel.c
trunk/menu/nexuiz/textslider.c
trunk/menu/nexuiz/util.qc
trunk/menu/nexuiz/util.qh
trunk/menu/oo/
trunk/menu/oo/base.h
trunk/menu/oo/classdefs.h
trunk/menu/oo/constructors.h
trunk/menu/oo/implementation.h
trunk/menu/progs.src
trunk/menu/skin-customizables.inc
trunk/menu/skin.qh
trunk/menu/todo
Log:
Forked from Nexuiz
Added: trunk/common/campaign_common.qh
===================================================================
--- trunk/common/campaign_common.qh (rev 0)
+++ trunk/common/campaign_common.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,28 @@
+#ifndef CAMPAIGN_MAX_ENTRIES
+#define CAMPAIGN_MAX_ENTRIES 64
+#endif
+
+// each i-th array element corresponds to the list entry campaign_offset+i
+float campaign_entries;
+float campaign_offset;
+string campaign_gametype[CAMPAIGN_MAX_ENTRIES];
+string campaign_mapname[CAMPAIGN_MAX_ENTRIES];
+float campaign_bots[CAMPAIGN_MAX_ENTRIES];
+float campaign_botskill[CAMPAIGN_MAX_ENTRIES];
+float campaign_fraglimit[CAMPAIGN_MAX_ENTRIES];
+string campaign_mutators[CAMPAIGN_MAX_ENTRIES];
+string campaign_shortdesc[CAMPAIGN_MAX_ENTRIES];
+string campaign_longdesc[CAMPAIGN_MAX_ENTRIES];
+
+// load the campaign file, but use the given offset and limit the number of
+// entries being read. Returns the number of entries successfully read (this
+// number is also stored in campaign_entries).
+// NOTE: there MUST be a corresponding CampaignFile_Unload() to unzone the
+// strings.
+string campaign_name; // set that to the campaign you want to load before calling CampaignFile_Load
+float CampaignFile_Load(float offset, float entries);
+void CampaignFile_Unload();
+
+// Sets up the campaign for the n-th array item (meaning: campaign_offset+nth
+// level) using localcmd()
+void CampaignSetup(float n);
Added: trunk/common/campaign_file.qc
===================================================================
--- trunk/common/campaign_file.qc (rev 0)
+++ trunk/common/campaign_file.qc 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,80 @@
+// CampaignFileLoad(offset, n)
+// - Loads campaign level data (up to n entries starting at offset)
+// into the globals
+// - Returns the number of entries successfully read
+float CampaignFile_Load(float offset, float n)
+{
+ float fh;
+ float lineno;
+ float entlen;
+ float i;
+ string l, a;
+ string fn;
+
+ if(n > CAMPAIGN_MAX_ENTRIES)
+ n = CAMPAIGN_MAX_ENTRIES;
+
+ campaign_offset = offset;
+ campaign_entries = 0;
+
+ fn = strcat("maps/campaign", campaign_name, ".txt");
+ fh = fopen(fn, FILE_READ);
+ if(fh >= 0)
+ {
+ for(lineno = 0; (l = fgets(fh)); )
+ {
+ if(strlen(l) == 0)
+ continue; // empty line
+ if(substring(l, 0, 2) == "//")
+ continue; // comment
+ if(substring(l, 0, 3) == "\"//")
+ continue; // comment
+ if(lineno >= offset)
+ {
+ entlen = tokenize(l);
+
+#define CAMPAIGN_GETARG0 if(i >= entlen)
+#define CAMPAIGN_GETARG1 CAMPAIGN_GETARG0 error("syntax error in campaign file: line has not enough fields");
+#define CAMPAIGN_GETARG2 CAMPAIGN_GETARG1 a = argv(i++);
+#define CAMPAIGN_GETARG3 CAMPAIGN_GETARG2 if(a == ",")
+#define CAMPAIGN_GETARG4 CAMPAIGN_GETARG3 a = "";
+#define CAMPAIGN_GETARG5 CAMPAIGN_GETARG4 else
+#define CAMPAIGN_GETARG CAMPAIGN_GETARG5 ++i
+// What you're seeing here is what people will do when your compiler supports
+// C-style macros but no line continuations.
+
+ i = 0;
+ CAMPAIGN_GETARG; campaign_gametype[campaign_entries] = strzone(a);
+ CAMPAIGN_GETARG; campaign_mapname[campaign_entries] = strzone(a);
+ CAMPAIGN_GETARG; campaign_bots[campaign_entries] = stof(a);
+ CAMPAIGN_GETARG; campaign_botskill[campaign_entries] = stof(a);
+ CAMPAIGN_GETARG; campaign_fraglimit[campaign_entries] = stof(a);
+ CAMPAIGN_GETARG; campaign_mutators[campaign_entries] = strzone(a);
+ CAMPAIGN_GETARG; campaign_shortdesc[campaign_entries] = strzone(a);
+ CAMPAIGN_GETARG; campaign_longdesc[campaign_entries] = strzone(a);
+ campaign_entries = campaign_entries + 1;
+
+ if(campaign_entries >= n)
+ break;
+ }
+ lineno = lineno + 1;
+ }
+ fclose(fh);
+ }
+
+ return campaign_entries;
+}
+
+void CampaignFile_Unload()
+{
+ float i;
+ for(i = 0; i < campaign_entries; ++i)
+ {
+ strunzone(campaign_gametype[i]);
+ strunzone(campaign_mapname[i]);
+ strunzone(campaign_mutators[i]);
+ strunzone(campaign_shortdesc[i]);
+ strunzone(campaign_longdesc[i]);
+ }
+ campaign_entries = 0;
+}
Added: trunk/common/campaign_setup.qc
===================================================================
--- trunk/common/campaign_setup.qc (rev 0)
+++ trunk/common/campaign_setup.qc 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,27 @@
+void CampaignSetup(float n)
+{
+#ifndef MAPINFO
+ localcmd("exec game_reset.cfg\n");
+#endif
+ localcmd("exec mutator_reset.cfg\n");
+ localcmd("set g_campaign 1\n");
+ localcmd("set _campaign_name \"");
+ localcmd(campaign_name);
+ localcmd("\"\n");
+ localcmd("set _campaign_index ");
+ localcmd(ftos(campaign_offset + n));
+ localcmd("\n");
+ localcmd(campaign_mutators[n]);
+ localcmd("\n");
+#ifdef MAPINFO
+ MapInfo_SwitchGameType(MapInfo_Type_FromString(campaign_gametype[n]));
+ //print(">>", cvar_string("g_tdm"), "<<\n");
+ MapInfo_LoadMap(campaign_mapname[n]);
+#else
+ localcmd("exec maps/"); // can't use strcat here in current fteqcc
+ localcmd(campaign_gametype[n]);
+ localcmd("_");
+ localcmd(campaign_mapname[n]);
+ localcmd(".mapcfg\n");
+#endif
+}
Added: trunk/common/gamecommand.qc
===================================================================
--- trunk/common/gamecommand.qc (rev 0)
+++ trunk/common/gamecommand.qc 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,386 @@
+#define MAX_RPN_STACK 8
+float rpn_error;
+float rpn_sp;
+string rpn_stack[MAX_RPN_STACK];
+string rpn_pop() {
+ if(rpn_sp > 0) {
+ --rpn_sp;
+ return rpn_stack[rpn_sp];
+ } else {
+ print("rpn: stack underflow\n");
+ rpn_error = TRUE;
+ return "";
+ }
+}
+void rpn_push(string s) {
+ if(rpn_sp < MAX_RPN_STACK) {
+ rpn_stack[rpn_sp] = s;
+ ++rpn_sp;
+ } else {
+ print("rpn: stack overflow\n");
+ rpn_error = TRUE;
+ }
+}
+string rpn_get() {
+ if(rpn_sp > 0) {
+ return rpn_stack[rpn_sp - 1];
+ } else {
+ print("rpn: empty stack\n");
+ rpn_error = TRUE;
+ return "";
+ }
+}
+void rpn_set(string s) {
+ if(rpn_sp > 0) {
+ rpn_stack[rpn_sp - 1] = s;
+ } else {
+ print("rpn: empty stack\n");
+ rpn_error = TRUE;
+ }
+}
+float rpn_getf() { return stof(rpn_get()); }
+float rpn_popf() { return stof(rpn_pop()); }
+void rpn_pushf(float f) { return rpn_push(ftos(f)); }
+void rpn_setf(float f) { return rpn_set(ftos(f)); }
+
+float GameCommand_Generic(string command)
+{
+ float argc;
+ float i, j, f, n;
+ string s, s2;
+ argc = tokenize(command);
+ if(argv(0) == "help")
+ {
+ print(" rpn EXPRESSION... - a RPN calculator.\n");
+ print(" Operator description (x: string, s: set, f: float):\n");
+ print(" x pop -----------------------------> : removes the top\n");
+ print(" x dup -----------------------------> x x : duplicates the top\n");
+ print(" x x exch --------------------------> x x : swap the top two\n");
+ print(" /cvarname load --------------------> x : loads a cvar\n");
+ print(" /cvarname x def -------------------> : writes to a cvar\n");
+ print(" f f add|sub|mul|div|mod|max|min ---> f : adds/... two numbers\n");
+ print(" f f eq|ne|gt|ge|lt|le -------------> f : compares two numbers\n");
+ print(" f neg|abs|sgn|rand ----------------> f : negates/... a number\n");
+ print(" f f f bound -----------------------> f : bounds the middle number\n");
+ print(" f1 f2 b when ----------------------> f : f1 if b, f2 otherwise\n");
+ print(" s s union|intersection|difference -> s : set operations\n");
+ print(" s shuffle -------------------------> s : randomly arrange elements\n");
+ print(" Set operations operate on 'such''strings' like g_maplist.\n");
+ print(" Unknown tokens insert their cvar value.\n");
+ print(" maplist add map\n");
+ print(" maplist remove map\n");
+ print(" maplist shuffle\n");
+ return TRUE;
+ }
+
+ if(argv(0) == "maplist")
+ {
+ if(argv(1) == "add" && argc == 3)
+ {
+#ifdef MAPINFO
+ f = fopen(strcat("maps/", argv(2), ".bsp"), FILE_READ);
+ if(f != -1)
+ fclose(f);
+ else {
+ print("maplist: ERROR: ", argv(2), " does not exist!\n");
+ return TRUE;
+ }
+ if(cvar_string("g_maplist") == "")
+ cvar_set("g_maplist", argv(2));
+ else
+ cvar_set("g_maplist", strcat(argv(2), " ", cvar_string("g_maplist")));
+#else
+ f = fopen(strcat("maps/", argv(2), ".mapcfg"), FILE_READ);
+ if(f != -1)
+ fclose(f);
+ else {
+ print("maplist: ERROR: ", argv(2), " does not exist!\n");
+ return TRUE;
+ }
+ cvar_set("g_maplist", strcat("'", argv(2), "'", cvar_string("g_maplist")));
+#endif
+ return TRUE;
+ }
+ else if(argv(1) == "remove" && argc == 3)
+ {
+ s = argv(2);
+#ifdef MAPINFO
+ n = tokenizebyseparator(cvar_string("g_maplist"), " ");
+#else
+ n = tokenize(cvar_string("g_maplist"));
+#endif
+ s2 = "";
+ for(i = 0; i < n; ++i)
+ if(argv(i) != s)
+ {
+#ifdef MAPINFO
+ s2 = strcat(s2, " ", argv(i));
+#else
+ s2 = strcat(s2, "'", argv(i), "'");
+#endif
+ }
+#ifdef MAPINFO
+ s2 = substring(s2, 1, strlen(s2) - 1);
+#endif
+ cvar_set("g_maplist", s2);
+ return TRUE;
+ }
+ else if(argv(1) == "shuffle" && argc == 2)
+ {
+ s = cvar_string("g_maplist");
+#ifdef MAPINFO
+ for(i = 1; i < (n = tokenizebyseparator(s, " ")); ++i)
+#else
+ for(i = 1; i < (n = tokenize(s)); ++i)
+#endif
+ {
+ // swap i-th item at a random position from 0 to i
+ // proof for even distribution:
+ // n = 1: obvious
+ // n -> n+1:
+ // item n+1 gets at any position with chance 1/(n+1)
+ // all others will get their 1/n chance reduced by factor n/(n+1)
+ // to be on place n+1, their chance will be 1/(n+1)
+ // 1/n * n/(n+1) = 1/(n+1)
+ // q.e.d.
+ f = ceil(random() * (i + 1)) - 1; // 0 to i
+ if(f == i)
+ continue; // no change
+
+ s2 = "";
+ for(j = 0; j < n; ++j)
+#ifdef MAPINFO
+ s2 = strcat(s2, " ", argv((j == i) ? f : (j == f) ? i : j));
+ s = substring(s2, 1, strlen(s2) - 1);
+#else
+ s2 = strcat(s2, "'", argv((j == i) ? f : (j == f) ? i : j), "'");
+ s = s2;
+#endif
+ }
+ cvar_set("g_maplist", s);
+ return TRUE;
+ }
+ }
+ else if(argv(0) == "rpn")
+ {
+ if(argc >= 2)
+ {
+ float rpnpos;
+ string rpncmd;
+ float f2, f3;
+ rpn_sp = 0;
+ rpn_error = FALSE;
+ for(rpnpos = 1; rpnpos < argc; ++rpnpos)
+ {
+ rpncmd = argv(rpnpos);
+ f = strlen(rpncmd);
+ if(rpncmd == "") {
+ } else if(stof(substring(rpncmd, 0, 1)) > 0) {
+ rpn_push(rpncmd);
+ } else if(substring(rpncmd, 0, 1) == "0") {
+ rpn_push(rpncmd);
+ } else if(f >= 2 && substring(rpncmd, 0, 1) == "+") {
+ rpn_push(rpncmd);
+ } else if(f >= 2 && substring(rpncmd, 0, 1) == "-") {
+ rpn_push(rpncmd);
+ } else if(f >= 2 && substring(rpncmd, 0, 1) == "/") {
+ rpn_push(substring(rpncmd, 1, strlen(rpncmd) - 1));
+ } else if(rpncmd == "def" || rpncmd == "=") {
+ s = rpn_pop();
+ s2 = rpn_pop();
+#ifdef MENUQC
+ registercvar(s2, "", 0);
+#else
+ registercvar(s2, "");
+#endif
+ if(!rpn_error) // don't change cvars if a stack error had happened!
+ cvar_set(s2, s);
+ } else if(rpncmd == "load") {
+ rpn_set(cvar_string(rpn_get()));
+ } else if(rpncmd == "exch") {
+ s = rpn_pop();
+ s2 = rpn_get();
+ rpn_set(s);
+ rpn_push(s2);
+ } else if(rpncmd == "dup") {
+ rpn_push(rpn_get());
+ } else if(rpncmd == "pop") {
+ rpn_pop();
+ } else if(rpncmd == "add" || rpncmd == "+") {
+ f = rpn_popf();
+ rpn_setf(rpn_getf() + f);
+ } else if(rpncmd == "sub" || rpncmd == "-") {
+ f = rpn_popf();
+ rpn_setf(rpn_getf() - f);
+ } else if(rpncmd == "mul" || rpncmd == "*") {
+ f = rpn_popf();
+ rpn_setf(rpn_getf() * f);
+ } else if(rpncmd == "div" || rpncmd == "/") {
+ f = rpn_popf();
+ rpn_setf(rpn_getf() / f);
+ } else if(rpncmd == "mod" || rpncmd == "%") {
+ f = rpn_popf();
+ f2 = rpn_getf();
+ rpn_setf(f2 - f * floor(f2 / f));
+ } else if(rpncmd == "abs") {
+ rpn_setf(fabs(rpn_getf()));
+ } else if(rpncmd == "sgn") {
+ f = rpn_getf();
+ if(f < 0)
+ rpn_set("-1");
+ else if(f > 0)
+ rpn_set("1");
+ else
+ rpn_set("0");
+ } else if(rpncmd == "neg" || rpncmd == "~") {
+ rpn_setf(-rpn_getf());
+ } else if(rpncmd == "max") {
+ f = rpn_popf();
+ f2 = rpn_getf();
+ rpn_setf(max(f2, f));
+ } else if(rpncmd == "min") {
+ f = rpn_popf();
+ f2 = rpn_getf();
+ rpn_setf(min(f2, f));
+ } else if(rpncmd == "bound") {
+ f = rpn_popf();
+ f2 = rpn_popf();
+ f3 = rpn_getf();
+ rpn_setf(bound(f3, f2, f));
+ } else if(rpncmd == "when") {
+ f = rpn_popf();
+ f2 = rpn_popf();
+ f3 = rpn_getf();
+ if(f)
+ rpn_setf(f3);
+ else
+ rpn_setf(f2);
+ } else if(rpncmd == ">" || rpncmd == "gt") {
+ f = rpn_popf();
+ rpn_setf(rpn_getf() > f);
+ } else if(rpncmd == "<" || rpncmd == "lt") {
+ f = rpn_popf();
+ rpn_setf(rpn_getf() < f);
+ } else if(rpncmd == "==" || rpncmd == "eq") {
+ f = rpn_popf();
+ rpn_setf(rpn_getf() == f);
+ } else if(rpncmd == ">=" || rpncmd == "ge") {
+ f = rpn_popf();
+ rpn_setf(rpn_getf() >= f);
+ } else if(rpncmd == "<=" || rpncmd == "le") {
+ f = rpn_popf();
+ rpn_setf(rpn_getf() <= f);
+ } else if(rpncmd == "!=" || rpncmd == "ne") {
+ f = rpn_popf();
+ rpn_setf(rpn_getf() != f);
+ } else if(rpncmd == "rand") {
+ rpn_setf(ceil(random() * rpn_getf()) - 1);
+ } else if(rpncmd == "union") {
+ // s s2 union
+ s2 = rpn_pop();
+ s = rpn_get();
+ f = tokenize(s);
+ f2 = tokenize(strcat(s, s2));
+ // tokens 0..(f-1) represent s
+ // tokens f..f2 represent s2
+ // UNION: add all tokens to s that are in s2 but not in s
+ s = "";
+ for(i = 0; i < f; ++i)
+ s = strcat(s, "'", argv(i), "'");
+ for(i = f; i < f2; ++i) {
+ for(j = 0; j < f; ++j)
+ if(argv(i) == argv(j))
+ goto skip_union;
+ s = strcat(s, "'", argv(i), "'");
+:skip_union
+ }
+ rpn_set(s);
+ tokenize(command);
+ } else if(rpncmd == "intersection") {
+ // s s2 intersection
+ s2 = rpn_pop();
+ s = rpn_get();
+ f = tokenize(s);
+ f2 = tokenize(strcat(s, s2));
+ // tokens 0..(f-1) represent s
+ // tokens f..f2 represent s2
+ // INTERSECTION: keep only the tokens from s that are also in s2
+ s = "";
+ for(i = 0; i < f; ++i) {
+ for(j = f; j < f2; ++j)
+ if(argv(i) == argv(j))
+ {
+ s = strcat(s, "'", argv(i), "'");
+ break;
+ }
+ }
+ rpn_set(s);
+ tokenize(command);
+ } else if(rpncmd == "difference") {
+ // s s2 difference
+ s2 = rpn_pop();
+ s = rpn_get();
+ f = tokenize(s);
+ f2 = tokenize(strcat(s, s2));
+ // tokens 0..(f-1) represent s
+ // tokens f..f2 represent s2
+ // DIFFERENCE: keep only the tokens from s that are not in s2
+ s = "";
+ for(i = 0; i < f; ++i) {
+ for(j = f; j < f2; ++j)
+ if(argv(i) == argv(j))
+ goto skip_difference;
+ s = strcat(s, "'", argv(i), "'");
+:skip_difference
+ }
+ rpn_set(s);
+ tokenize(command);
+ } else if(rpncmd == "shuffle") {
+ // s shuffle
+ s = rpn_get();
+ f = tokenize(s);
+
+ for(i = 0; i < f - 1; ++i) {
+ // move a random item from i..f-1 to position i
+ s = "";
+ f2 = ceil(random() * (f - i) + i) - 1;
+ for(j = 0; j < i; ++j)
+ s = strcat(s, "'", argv(j), "'");
+ s = strcat(s, "'", argv(f2), "'");
+ for(j = i; j < f; ++j)
+ if(j != f2)
+ s = strcat(s, "'", argv(j), "'");
+ f = tokenize(s);
+ }
+
+ rpn_set(s);
+ tokenize(command);
+ } else if(rpncmd == "fexists_assert") {
+ s = rpn_pop();
+ if(!rpn_error)
+ {
+ f = fopen(s, FILE_READ);
+ if(f != -1)
+ fclose(f);
+ else {
+ print("rpn: ERROR: ", s, " does not exist!\n");
+ rpn_error = TRUE;
+ }
+ }
+ } else {
+ rpn_push(cvar_string(rpncmd));
+ }
+ if(rpn_error)
+ break;
+ }
+ while(rpn_sp > 0)
+ {
+ s = rpn_pop();
+ print("rpn: still on stack: ", s, "\n");
+ }
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
Added: trunk/common/mapinfo.qc
===================================================================
--- trunk/common/mapinfo.qc (rev 0)
+++ trunk/common/mapinfo.qc 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,817 @@
+ // internal toy
+void cvar_settemp(string pKey, string pValue)
+{
+ //localcmd(strcat("\nsettemp ", t, " \"", s, "\"\n"));
+
+ // duplicate what this alias does:
+ // alias settemp "settemp_list \"1 $1 $settemp_var $settemp_list\"; set $settemp_var \"${$1}\"; settemp_var ${settemp_var}x; $1 \"$2\""
+
+ cvar_set("settemp_list", strcat("1 ", pKey, " ", cvar_string("settemp_var"), " ", cvar_string("settemp_list")));
+#ifdef MENUQC
+ registercvar(cvar_string("settemp_var"), "", 0);
+#else
+ registercvar(cvar_string("settemp_var"), "");
+#endif
+ cvar_set(cvar_string("settemp_var"), cvar_string(pKey));
+ cvar_set("settemp_var", strcat(cvar_string("settemp_var"), "x"));
+ cvar_set(pKey, pValue);
+}
+
+void cvar_settemp_restore()
+{
+ // undo what cvar_settemp did
+ float n, i;
+ n = tokenize(cvar_string("settemp_list"));
+ for(i = 0; i < n - 3; i += 3)
+ cvar_set(argv(i + 1), cvar_string(argv(i + 2)));
+ cvar_set("settemp_list", "0");
+}
+
+#ifdef HSOI
+// HUGE SET - stored in a string
+string HugeSetOfIntegers_empty()
+{
+ return "";
+}
+float HugeSetOfIntegers_get(string pArr, float i)
+{
+ return stof(substring(pArr, i * 4, 4));
+}
+float HugeSetOfIntegers_length(string pArr)
+{
+ return strlen(pArr) / 4;
+}
+string HugeSetOfIntegers_concat(string a1, string a2)
+{
+ return strcat(a1, a2);
+}
+string HugeSetOfIntegers_insert(string a1, float n, string a2)
+ // special concat function to build up large lists in less time by binary concatenation
+{
+ string s;
+ s = strcat(" ", ftos(n));
+ return strcat(a1, substring(s, strlen(s) - 4, 4), a2);
+}
+#endif
+
+// generic string stuff
+float startsWith(string haystack, string needle)
+{
+ return substring(haystack, 0, strlen(needle)) == needle;
+}
+float startsWithNocase(string haystack, string needle)
+{
+ return strcasecmp(substring(haystack, 0, strlen(needle)), needle) == 0;
+}
+string extractRestOfLine(string haystack, string needle)
+{
+ if(startsWith(haystack, needle))
+ return substring(haystack, strlen(needle), strlen(haystack) - strlen(needle));
+ return string_null;
+}
+string car(string s)
+{
+ float o;
+ o = strstrofs(s, " ", 0);
+ if(o < 0)
+ return s;
+ return substring(s, 0, o);
+}
+string cdr(string s)
+{
+ float o;
+ o = strstrofs(s, " ", 0);
+ if(o < 0)
+ return string_null;
+ return substring(s, o + 1, strlen(s) - (o + 1));
+}
+
+float _MapInfo_Cache_Active;
+float _MapInfo_Cache_DB_NameToIndex;
+float _MapInfo_Cache_Buf_IndexToMapData;
+
+void MapInfo_Cache_Destroy()
+{
+ if(!_MapInfo_Cache_Active)
+ return;
+
+ db_close(_MapInfo_Cache_DB_NameToIndex);
+ buf_del(_MapInfo_Cache_Buf_IndexToMapData);
+ _MapInfo_Cache_Active = 0;
+}
+
+void MapInfo_Cache_Create()
+{
+ MapInfo_Cache_Destroy();
+ _MapInfo_Cache_DB_NameToIndex = db_create();
+ _MapInfo_Cache_Buf_IndexToMapData = buf_create();
+ _MapInfo_Cache_Active = 1;
+}
+
+void MapInfo_Cache_Invalidate()
+{
+ if(!_MapInfo_Cache_Active)
+ return;
+
+ MapInfo_Cache_Create();
+}
+
+void MapInfo_Cache_Store()
+{
+ float i;
+ string s;
+ if(!_MapInfo_Cache_Active)
+ return;
+
+ s = db_get(_MapInfo_Cache_DB_NameToIndex, MapInfo_Map_bspname);
+ if(!s) // empty string is NOT valid here!
+ {
+ i = buf_getsize(_MapInfo_Cache_Buf_IndexToMapData);
+ db_put(_MapInfo_Cache_DB_NameToIndex, MapInfo_Map_bspname, ftos(i));
+ }
+ else
+ i = stof(s);
+
+ // now store all the stuff
+ bufstr_set(_MapInfo_Cache_Buf_IndexToMapData, i++, MapInfo_Map_bspname);
+ bufstr_set(_MapInfo_Cache_Buf_IndexToMapData, i++, MapInfo_Map_title);
+ bufstr_set(_MapInfo_Cache_Buf_IndexToMapData, i++, MapInfo_Map_description);
+ bufstr_set(_MapInfo_Cache_Buf_IndexToMapData, i++, MapInfo_Map_author);
+ bufstr_set(_MapInfo_Cache_Buf_IndexToMapData, i++, ftos(MapInfo_Map_supportedGametypes));
+ bufstr_set(_MapInfo_Cache_Buf_IndexToMapData, i++, ftos(MapInfo_Map_supportedFeatures));
+ bufstr_set(_MapInfo_Cache_Buf_IndexToMapData, i++, ftos(MapInfo_Map_diameter));
+ bufstr_set(_MapInfo_Cache_Buf_IndexToMapData, i++, ftos(MapInfo_Map_spawnpoints));
+}
+
+float MapInfo_Cache_Retrieve(string map)
+{
+ float i;
+ string s;
+ if(!_MapInfo_Cache_Active)
+ return 0;
+
+ s = db_get(_MapInfo_Cache_DB_NameToIndex, map);
+ if(!s)
+ return 0;
+ i = stof(s);
+
+ // now retrieve all the stuff
+ MapInfo_Map_bspname = bufstr_get(_MapInfo_Cache_Buf_IndexToMapData, i++);
+ MapInfo_Map_title = bufstr_get(_MapInfo_Cache_Buf_IndexToMapData, i++);
+ MapInfo_Map_description = bufstr_get(_MapInfo_Cache_Buf_IndexToMapData, i++);
+ MapInfo_Map_author = bufstr_get(_MapInfo_Cache_Buf_IndexToMapData, i++);
+ MapInfo_Map_supportedGametypes = stof(bufstr_get(_MapInfo_Cache_Buf_IndexToMapData, i++));
+ MapInfo_Map_supportedFeatures = stof(bufstr_get(_MapInfo_Cache_Buf_IndexToMapData, i++));
+ MapInfo_Map_diameter = stof(bufstr_get(_MapInfo_Cache_Buf_IndexToMapData, i++));
+ MapInfo_Map_spawnpoints = stof(bufstr_get(_MapInfo_Cache_Buf_IndexToMapData, i++));
+ return 1;
+}
+
+// GLOB HANDLING (for all BSP files)
+float _MapInfo_globopen;
+float _MapInfo_globcount;
+float _MapInfo_globhandle;
+string _MapInfo_GlobItem(float i)
+{
+ string s;
+ s = search_getfilename(_MapInfo_globhandle, i);
+ return substring(s, 5, strlen(s) - 9); // without maps/ and .bsp
+}
+
+void MapInfo_Enumerate()
+{
+ if(_MapInfo_globopen)
+ search_end(_MapInfo_globhandle);
+ MapInfo_Cache_Invalidate();
+ _MapInfo_globhandle = search_begin("maps/*.bsp", TRUE, TRUE);
+ _MapInfo_globcount = search_getsize(_MapInfo_globhandle);
+ _MapInfo_globopen = 1;
+}
+
+// filter the info by game type mask (updates MapInfo_count)
+//
+#ifdef HSOI
+string _MapInfo_filtered;
+float MapInfo_FilterList_Lookup(float i)
+{
+ return MapInfo_FilterList_Lookup(i);
+}
+
+string MapInfo_FilterGametype_Recursive(float pGametype, float pFeatures, float pBegin, float pEnd, float pAbortOnGenerate)
+{
+ float m, valid;
+ string l, r;
+
+ if(pBegin == pEnd)
+ return HugeSetOfIntegers_empty();
+
+ m = floor((pBegin + pEnd) / 2);
+
+ l = MapInfo_FilterGametype_Recursive(pGametype, pFeatures, pBegin, m, pAbortOnGenerate);
+ if not(l)
+ return string_null; // BAIL OUT
+ if(MapInfo_Get_ByName(_MapInfo_GlobItem(m), 1, 0) == 2) // if we generated one... BAIL OUT and let the caller continue in the next frame.
+ if(pAbortOnGenerate)
+ {
+ MapInfo_progress = m / _MapInfo_globcount;
+ return string_null; // BAIL OUT
+ }
+ valid = (((MapInfo_Map_supportedGametypes & pGametype) != 0) && ((MapInfo_Map_supportedFeatures & pFeatures) == pFeatures));
+ r = MapInfo_FilterGametype_Recursive(pGametype, pFeatures, m + 1, pEnd, pAbortOnGenerate);
+ if not(r)
+ return string_null; // BAIL OUT
+
+ if(valid)
+ return HugeSetOfIntegers_insert(l, m, r);
+ else
+ return HugeSetOfIntegers_concat(l, r);
+}
+
+float MapInfo_FilterGametype(float pGametype, float pFeatures, float pAbortOnGenerate)
+{
+ if(_MapInfo_filtered)
+ strunzone(_MapInfo_filtered);
+ _MapInfo_filtered = MapInfo_FilterGametype_Recursive(pGametype, pFeatures, 0, _MapInfo_globcount, pAbortOnGenerate);
+ if not(_MapInfo_filtered)
+ {
+ dprint("Autogenerated a .mapinfo, doing the rest later.\n");
+ return 0;
+ }
+ _MapInfo_filtered = strzone(_MapInfo_filtered);
+ MapInfo_count = HugeSetOfIntegers_length(_MapInfo_filtered);
+ MapInfo_ClearTemps();
+ return 1;
+}
+#else
+float _MapInfo_filtered;
+float _MapInfo_filtered_allocated;
+float MapInfo_FilterList_Lookup(float i)
+{
+ return stof(bufstr_get(_MapInfo_filtered, i));
+}
+
+float MapInfo_FilterGametype(float pGametype, float pFeatures, float pAbortOnGenerate)
+{
+ float i, j;
+ if not(_MapInfo_filtered_allocated)
+ {
+ _MapInfo_filtered_allocated = 1;
+ _MapInfo_filtered = buf_create();
+ }
+ MapInfo_count = 0;
+ for(i = 0, j = 0; i < _MapInfo_globcount; ++i)
+ {
+ if(MapInfo_Get_ByName(_MapInfo_GlobItem(i), 1, 0) == 2) // if we generated one... BAIL OUT and let the caller continue in the next frame.
+ if(pAbortOnGenerate)
+ {
+ dprint("Autogenerated a .mapinfo, doing the rest later.\n");
+ MapInfo_progress = i / _MapInfo_globcount;
+ return 0;
+ }
+ if(((MapInfo_Map_supportedGametypes & pGametype) != 0) && ((MapInfo_Map_supportedFeatures & pFeatures) == pFeatures))
+ bufstr_set(_MapInfo_filtered, j++, ftos(i));
+ }
+ MapInfo_count = j;
+ return 1;
+}
+#endif
+
+// load info about the i-th map into the MapInfo_Map_* globals
+string MapInfo_BSPName_ByID(float i)
+{
+ return _MapInfo_GlobItem(MapInfo_FilterList_Lookup(i));
+}
+
+string unquote(string s)
+{
+ float i, j, l;
+ l = strlen(s);
+ j = -1;
+ for(i = 0; i < l; ++i)
+ {
+ string ch;
+ ch = substring(s, i, 1);
+ if(ch != " ") if(ch != "\"")
+ {
+ for(j = strlen(s) - i - 1; j > 0; --j)
+ {
+ ch = substring(s, i+j, 1);
+ if(ch != " ") if(ch != "\"")
+ return substring(s, i, j+1);
+ }
+ return substring(s, i, 1);
+ }
+ }
+ return "";
+}
+
+float MapInfo_Get_ByID(float i)
+{
+ if(MapInfo_Get_ByName(MapInfo_BSPName_ByID(i), 0, 0))
+ return 1;
+ return 0;
+}
+
+float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp
+{
+ string fn;
+ float fh;
+ string s, k, v;
+ vector o;
+ float i;
+ float inWorldspawn;
+ float r;
+ float twoBaseModes;
+
+ vector mapMins, mapMaxs;
+
+ r = 1;
+ fn = strcat("maps/", pFilename, ".ent");
+ fh = fopen(fn, FILE_READ);
+ if(fh < 0)
+ {
+ r = 2;
+ fn = strcat("maps/", pFilename, ".bsp");
+ fh = fopen(fn, FILE_READ);
+ }
+ if(fh < 0)
+ return 0;
+ print("Analyzing ", fn, " to generate initial mapinfo; please edit that file later\n");
+
+ inWorldspawn = 2;
+ MapInfo_Map_supportedGametypes = 0;
+
+ for(;;)
+ {
+ if not((s = fgets(fh)))
+ break;
+ if(inWorldspawn == 1)
+ if(startsWith(s, "}"))
+ inWorldspawn = 0;
+ k = unquote(car(s));
+ v = unquote(cdr(s));
+ if(inWorldspawn)
+ {
+ if(k == "classname" && v == "worldspawn")
+ inWorldspawn = 1;
+ else if(k == "author")
+ MapInfo_Map_author = v;
+ else if(k == "_description")
+ MapInfo_Map_description = v;
+ else if(k == "message")
+ {
+ i = strstrofs(v, " by ", 0);
+ if(MapInfo_Map_author == "<AUTHOR>" && i >= 0)
+ {
+ MapInfo_Map_title = substring(v, 0, i);
+ MapInfo_Map_author = substring(v, i + 4, strlen(v) - (i + 4));
+ }
+ else
+ MapInfo_Map_title = v;
+ }
+ }
+ else
+ {
+ if(k == "origin")
+ {
+ o = stov(strcat("'", v, "'"));
+ mapMins_x = min(mapMins_x, o_x);
+ mapMins_y = min(mapMins_y, o_y);
+ mapMins_z = min(mapMins_z, o_z);
+ mapMaxs_x = max(mapMaxs_x, o_x);
+ mapMaxs_y = max(mapMaxs_y, o_y);
+ mapMaxs_z = max(mapMaxs_z, o_z);
+ }
+ else if(k == "classname")
+ {
+ if(v == "dom_controlpoint")
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DOMINATION;
+ else if(v == "item_flag_team2")
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF;
+ else if(v == "team_CTF_blueflag")
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF;
+ else if(v == "runematch_spawn_point")
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RUNEMATCH;
+ else if(v == "target_assault_roundend")
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ASSAULT;
+ else if(v == "onslaught_generator")
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ONSLAUGHT;
+ else if(v == "info_player_team1")
+ ++MapInfo_Map_spawnpoints;
+ else if(v == "info_player_team2")
+ ++MapInfo_Map_spawnpoints;
+ else if(v == "info_player_start")
+ ++MapInfo_Map_spawnpoints;
+ else if(v == "info_player_deathmatch")
+ ++MapInfo_Map_spawnpoints;
+ else if(v == "weapon_nex")
+ { }
+ else if(v == "weapon_railgun")
+ { }
+ else if(startsWith(v, "weapon_"))
+ MapInfo_Map_supportedFeatures |= MAPINFO_FEATURE_WEAPONS;
+ }
+ }
+ }
+ if(inWorldspawn)
+ {
+ print(fn, " ended still in worldspawn, BUG\n");
+ return 0;
+ }
+ MapInfo_Map_diameter = vlen(mapMaxs - mapMins);
+
+ twoBaseModes = MapInfo_Map_supportedGametypes & (MAPINFO_TYPE_CTF | MAPINFO_TYPE_ASSAULT);
+ if(twoBaseModes && (MapInfo_Map_supportedGametypes == twoBaseModes))
+ {
+ // we have a CTF-only or Assault-only map. Don't add other modes then,
+ // as the map is too symmetric for them.
+ }
+ else
+ {
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DEATHMATCH; // DM always works
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_LMS; // LMS always works
+
+ if(MapInfo_Map_spawnpoints >= 8 && MapInfo_Map_diameter > 4096)
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_TEAM_DEATHMATCH;
+ if( MapInfo_Map_diameter < 4096)
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ARENA;
+ if(MapInfo_Map_spawnpoints >= 12 && MapInfo_Map_diameter > 5120)
+ MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEYHUNT;
+ }
+
+ fclose(fh);
+
+ return r;
+}
+
+void _MapInfo_Map_Reset()
+{
+ MapInfo_Map_title = "<TITLE>";
+ MapInfo_Map_description = "<DESCRIPTION>";
+ MapInfo_Map_author = "<AUTHOR>";
+ MapInfo_Map_supportedGametypes = 0;
+ MapInfo_Map_supportedFeatures = 0;
+ MapInfo_Map_diameter = 0;
+ MapInfo_Map_spawnpoints = 0;
+}
+
+void _MapInfo_Map_ApplyGametype(string s, float pWantedType, float pThisType)
+{
+ MapInfo_Map_supportedGametypes |= pThisType;
+ if(!(pThisType & pWantedType))
+ return;
+
+ cvar_set("fraglimit", car(s));
+ s = cdr(s);
+
+ cvar_set("timelimit", car(s));
+ s = cdr(s);
+
+ if(pWantedType == MAPINFO_TYPE_TEAM_DEATHMATCH)
+ {
+ cvar_set("g_tdm_teams", car(s));
+ s = cdr(s);
+ }
+
+ if(pWantedType == MAPINFO_TYPE_KEYHUNT)
+ {
+ cvar_set("g_keyhunt_teams", car(s));
+ s = cdr(s);
+ }
+}
+
+float MapInfo_Type_FromString(string t)
+{
+ if (t == "dm") return MAPINFO_TYPE_DEATHMATCH;
+ else if(t == "tdm") return MAPINFO_TYPE_TEAM_DEATHMATCH;
+ else if(t == "dom") return MAPINFO_TYPE_DOMINATION;
+ else if(t == "ctf") return MAPINFO_TYPE_CTF;
+ else if(t == "rune") return MAPINFO_TYPE_RUNEMATCH;
+ else if(t == "lms") return MAPINFO_TYPE_LMS;
+ else if(t == "arena") return MAPINFO_TYPE_ARENA;
+ else if(t == "kh") return MAPINFO_TYPE_KEYHUNT;
+ else if(t == "as") return MAPINFO_TYPE_ASSAULT;
+ else if(t == "ons") return MAPINFO_TYPE_ONSLAUGHT;
+ else if(t == "all") return MAPINFO_TYPE_ALL;
+ else return 0;
+}
+
+// load info about a map by name into the MapInfo_Map_* globals
+float MapInfo_Get_ByName(string pFilename, float pAllowGenerate, float pGametypeToSet)
+{
+ string fn;
+ string s, t;
+ float fh, fh2;
+ float r, f;
+
+ if(pGametypeToSet == 0)
+ if(MapInfo_Cache_Retrieve(pFilename))
+ return 1;
+
+ r = 1;
+
+ MapInfo_Map_bspname = pFilename;
+
+ // default all generic fields so they have "good" values in case something fails
+ fn = strcat("maps/", pFilename, ".mapinfo");
+ fh = fopen(fn, FILE_READ);
+ if(fh < 0)
+ {
+ if(!pAllowGenerate)
+ return 0;
+ _MapInfo_Map_Reset();
+ r = _MapInfo_Generate(pFilename);
+ if(!r)
+ return 0;
+ fh = fopen(fn, FILE_WRITE);
+ fputs(fh, strcat("title ", MapInfo_Map_title, "\n"));
+ fputs(fh, strcat("description ", MapInfo_Map_description, "\n"));
+ fputs(fh, strcat("author ", MapInfo_Map_author, "\n"));
+ fputs(fh, strcat("_diameter ", ftos(MapInfo_Map_diameter), "\n"));
+ fputs(fh, strcat("_spawnpoints ", ftos(MapInfo_Map_spawnpoints), "\n"));
+ if(MapInfo_Map_supportedFeatures & MAPINFO_FEATURE_WEAPONS) fputs(fh, "has weapons\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH) fputs(fh, "type dm 30 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_TEAM_DEATHMATCH) fputs(fh, "type tdm 50 20 2\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DOMINATION) fputs(fh, "type dom 200 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_CTF) fputs(fh, "type ctf 300 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RUNEMATCH) fputs(fh, "type rune 200 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_LMS) fputs(fh, "type lms 9 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ARENA) fputs(fh, "type arena 10 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_KEYHUNT) fputs(fh, "type kh 1000 20 3\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ASSAULT) fputs(fh, "type as 20\n");
+ if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ONSLAUGHT) fputs(fh, "type ons 20\n");
+
+ fh2 = fopen(strcat("scripts/", pFilename, ".arena"), FILE_READ);
+ if(fh2 >= 0)
+ {
+ fclose(fh2);
+ fputs(fh, "settemp_for_type all sv_q3acompat_machineshotgunswap 1\n");
+ }
+
+ fclose(fh);
+ r = 2;
+ // return r;
+ fh = fopen(fn, FILE_READ);
+ if(fh < 0)
+ error("... but I just wrote it!");
+ }
+
+ _MapInfo_Map_Reset();
+ for(;;)
+ {
+ if not((s = fgets(fh)))
+ break;
+ t = car(s); s = cdr(s);
+ if (t == "title")
+ MapInfo_Map_title = s;
+ else if(t == "description")
+ MapInfo_Map_description = s;
+ else if(t == "author")
+ MapInfo_Map_author = s;
+ else if(t == "_diameter")
+ MapInfo_Map_diameter = stof(s);
+ else if(t == "_spawnpoints")
+ MapInfo_Map_spawnpoints = stof(s);
+ else if(t == "has")
+ {
+ t = car(s); s = cdr(s);
+ if (t == "weapons") MapInfo_Map_supportedFeatures |= MAPINFO_FEATURE_WEAPONS;
+ else
+ dprint("Map ", pFilename, " supports unknown feature ", t, ", ignored\n");
+ }
+ else if(t == "type")
+ {
+ t = car(s); s = cdr(s);
+ f = MapInfo_Type_FromString(t);
+ if(f)
+ _MapInfo_Map_ApplyGametype (s, pGametypeToSet, f);
+ else
+ dprint("Map ", pFilename, " supports unknown game type ", t, ", ignored\n");
+ }
+ else if(t == "settemp_for_type")
+ {
+ t = car(s); s = cdr(s);
+ if((f = MapInfo_Type_FromString(t)))
+ {
+ if(f & pGametypeToSet)
+ {
+ t = car(s); s = cdr(s);
+ if(strstrofs(t, "\"", 0) >= 0)
+ print("Map ", pFilename, " contains a potentially harmful setting, ignored\n");
+ else if(strstrofs(t, "\\", 0) >= 0)
+ print("Map ", pFilename, " contains a potentially harmful setting, ignored\n");
+ else if(strstrofs(t, ";", 0) >= 0)
+ print("Map ", pFilename, " contains a potentially harmful setting, ignored\n");
+ else if(strstrofs(s, "\"", 0) >= 0)
+ print("Map ", pFilename, " contains a potentially harmful setting, ignored\n");
+ else if(strstrofs(s, "\\", 0) >= 0)
+ print("Map ", pFilename, " contains a potentially harmful setting, ignored\n");
+ else if(strstrofs(s, ";", 0) >= 0)
+ print("Map ", pFilename, " contains a potentially harmful setting, ignored\n");
+ else
+ {
+ dprint("Applying temporary setting ", t, " := ", s, "\n");
+ cvar_settemp(t, s);
+ }
+ }
+ }
+ else
+ {
+ dprint("Map ", pFilename, " has a setting for unknown game type ", t, ", ignored\n");
+ }
+ }
+ else
+ dprint("Map ", pFilename, " provides unknown info item ", t, ", ignored\n");
+ }
+ fclose(fh);
+ if(pGametypeToSet)
+ if(!(MapInfo_Map_supportedGametypes & pGametypeToSet))
+ error("Can't select the requested game type. Bailing out.");
+ MapInfo_Cache_Store();
+ if(MapInfo_Map_supportedGametypes != 0)
+ return r;
+ dprint("Map ", pFilename, " supports no game types, ignored\n");
+ return 0;
+}
+
+float MapInfo_FindName(string s)
+{
+ // if there is exactly one map of prefix s, return it
+ // if not, return the null string
+ // note that DP sorts glob results... so I can use a binary search
+ float l, r, m, cmp;
+ l = 0;
+ r = MapInfo_count;
+ // invariants: r is behind s, l-1 is equal or before
+ while(l != r)
+ {
+ m = floor((l + r) / 2);
+ MapInfo_FindName_match = _MapInfo_GlobItem(MapInfo_FilterList_Lookup(m));
+ cmp = strcasecmp(MapInfo_FindName_match, s);
+ if(cmp == 0)
+ return m; // found and good
+ if(cmp < 0)
+ l = m + 1; // l-1 is before s
+ else
+ r = m; // behind s
+ }
+ MapInfo_FindName_match = _MapInfo_GlobItem(MapInfo_FilterList_Lookup(l));
+ MapInfo_FindName_firstResult = l;
+ // r == l, so: l is behind s, l-1 is before
+ // SO: if there is any, l is the one with the right prefix
+ // and l+1 may be one too
+ if(l == MapInfo_count)
+ {
+ MapInfo_FindName_match = string_null;
+ MapInfo_FindName_firstResult = -1;
+ return -1; // no MapInfo_FindName_match, behind last item
+ }
+ if(!startsWithNocase(MapInfo_FindName_match, s))
+ {
+ MapInfo_FindName_match = string_null;
+ MapInfo_FindName_firstResult = -1;
+ return -1; // wrong prefix
+ }
+ if(l == MapInfo_count - 1)
+ return l; // last one, nothing can follow => unique
+ if(startsWithNocase(_MapInfo_GlobItem(MapInfo_FilterList_Lookup(l + 1)), s))
+ {
+ MapInfo_FindName_match = string_null;
+ return -1; // ambigous MapInfo_FindName_match
+ }
+ return l;
+}
+
+string MapInfo_FixName(string s)
+{
+ MapInfo_FindName(s);
+ return MapInfo_FindName_match;
+}
+
+float MapInfo_CurrentFeatures()
+{
+ float req;
+ req = 0;
+ if(!(cvar("g_lms") || cvar("g_instagib") || cvar("g_minstagib") || cvar("g_nixnex") || cvar("g_rocketarena")))
+ req |= MAPINFO_FEATURE_WEAPONS;
+ return req;
+}
+
+float MapInfo_CurrentGametype()
+{
+ if(cvar("g_domination"))
+ return MAPINFO_TYPE_DOMINATION;
+ else if(cvar("g_ctf"))
+ return MAPINFO_TYPE_CTF;
+ else if(cvar("g_runematch"))
+ return MAPINFO_TYPE_RUNEMATCH;
+ else if(cvar("g_tdm"))
+ return MAPINFO_TYPE_TEAM_DEATHMATCH;
+ else if(cvar("g_assault"))
+ return MAPINFO_TYPE_ASSAULT;
+ else if(cvar("g_lms"))
+ return MAPINFO_TYPE_LMS;
+ else if(cvar("g_arena"))
+ return MAPINFO_TYPE_ARENA;
+ else if(cvar("g_keyhunt"))
+ return MAPINFO_TYPE_KEYHUNT;
+ else if(cvar("g_onslaught"))
+ return MAPINFO_TYPE_ONSLAUGHT;
+ else
+ return MAPINFO_TYPE_DEATHMATCH;
+}
+
+float _MapInfo_CheckMap(string s) // returns 0 if the map can't be played with the current settings, 1 otherwise
+{
+ if(!MapInfo_Get_ByName(s, 1, 0))
+ return 0;
+ if((MapInfo_Map_supportedGametypes & MapInfo_CurrentGametype()) == 0)
+ return 0;
+ if((MapInfo_Map_supportedFeatures & MapInfo_CurrentFeatures()) != MapInfo_CurrentFeatures())
+ return 0;
+ return 1;
+}
+
+float MapInfo_CheckMap(string s) // returns 0 if the map can't be played with the current settings, 1 otherwise
+{
+ float r;
+ r = _MapInfo_CheckMap(s);
+ MapInfo_ClearTemps();
+ return r;
+}
+
+void MapInfo_SwitchGameType(float t)
+{
+ cvar_set("gamecfg", "0");
+ cvar_set("g_dm", (t == MAPINFO_TYPE_DEATHMATCH) ? "1" : "0");
+ cvar_set("g_tdm", (t == MAPINFO_TYPE_TEAM_DEATHMATCH) ? "1" : "0");
+ cvar_set("g_domination", (t == MAPINFO_TYPE_DOMINATION) ? "1" : "0");
+ cvar_set("g_ctf", (t == MAPINFO_TYPE_CTF) ? "1" : "0");
+ cvar_set("g_runematch", (t == MAPINFO_TYPE_RUNEMATCH) ? "1" : "0");
+ cvar_set("g_lms", (t == MAPINFO_TYPE_LMS) ? "1" : "0");
+ cvar_set("g_arena", (t == MAPINFO_TYPE_ARENA) ? "1" : "0");
+ cvar_set("g_keyhunt", (t == MAPINFO_TYPE_KEYHUNT) ? "1" : "0");
+ cvar_set("g_assault", (t == MAPINFO_TYPE_ASSAULT) ? "1" : "0");
+ cvar_set("g_onslaught", (t == MAPINFO_TYPE_ONSLAUGHT) ? "1" : "0");
+}
+
+void MapInfo_LoadMap(string s)
+{
+ MapInfo_Map_supportedGametypes = 0;
+ if(!MapInfo_CheckMap(s))
+ {
+ print("EMERGENCY: can't play the selected map in the given game mode. Falling back to DM.\n");
+ MapInfo_SwitchGameType(MAPINFO_TYPE_DEATHMATCH);
+ }
+ localcmd(strcat("\nsettemp_restore\nchangelevel ", s, "\n"));
+}
+
+string MapInfo_ListAllowedMaps()
+{
+ string out;
+ float i;
+
+ // to make absolutely sure:
+ MapInfo_Enumerate();
+ MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), 0);
+
+ out = "";
+ for(i = 0; i < MapInfo_count; ++i)
+ out = strcat(out, " ", _MapInfo_GlobItem(MapInfo_FilterList_Lookup(i)));
+ return substring(out, 1, strlen(out) - 1);
+}
+
+void MapInfo_LoadMapSettings(string s) // to be called from worldspawn
+{
+ float t;
+ if(!_MapInfo_CheckMap(s)) // with underscore, it keeps temps
+ {
+ if(MapInfo_Map_supportedGametypes <= 0)
+ error("Mapinfo system is not functional at all. BAILED OUT.\n");
+
+ t = 1;
+ while(!(MapInfo_Map_supportedGametypes & 1))
+ {
+ t *= 2;
+ MapInfo_Map_supportedGametypes = floor(MapInfo_Map_supportedGametypes / 2);
+ }
+ // t is now a supported mode!
+ print("EMERGENCY: can't play the selected map in the given game mode. Falling back to a supported mode.\n");
+ MapInfo_SwitchGameType(t);
+ }
+ cvar_settemp_restore();
+ MapInfo_Get_ByName(s, 1, MapInfo_CurrentGametype());
+ MapInfo_ClearTemps();
+}
+
+void MapInfo_ClearTemps()
+{
+ MapInfo_Map_bspname = string_null;
+ MapInfo_Map_title = string_null;
+ MapInfo_Map_description = string_null;
+ MapInfo_Map_author = string_null;
+ MapInfo_Map_supportedGametypes = 0;
+ MapInfo_Map_supportedFeatures = 0;
+ MapInfo_Map_diameter = 0;
+ MapInfo_Map_spawnpoints = 0;
+}
Added: trunk/common/mapinfo.qh
===================================================================
--- trunk/common/mapinfo.qh (rev 0)
+++ trunk/common/mapinfo.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,68 @@
+float MAPINFO_TYPE_DEATHMATCH = 1;
+float MAPINFO_TYPE_TEAM_DEATHMATCH = 2;
+float MAPINFO_TYPE_DOMINATION = 4;
+float MAPINFO_TYPE_CTF = 8;
+float MAPINFO_TYPE_RUNEMATCH = 16;
+float MAPINFO_TYPE_LMS = 32;
+float MAPINFO_TYPE_ARENA = 64;
+float MAPINFO_TYPE_KEYHUNT = 128;
+float MAPINFO_TYPE_ASSAULT = 256;
+float MAPINFO_TYPE_ONSLAUGHT = 512;
+float MAPINFO_TYPE_ALL = 65535; // this has to include all above bits
+
+float MAPINFO_FEATURE_WEAPONS = 1; // not defined for minstagib-only maps
+
+float MapInfo_count;
+
+// info about a map that MapInfo loads
+string MapInfo_Map_bspname;
+string MapInfo_Map_title;
+string MapInfo_Map_description;
+string MapInfo_Map_author;
+float MapInfo_Map_supportedGametypes;
+float MapInfo_Map_supportedFeatures;
+float MapInfo_Map_diameter;
+float MapInfo_Map_spawnpoints;
+
+// load MapInfo_count; generate mapinfo for maps that miss them, and clear the
+// cache; you need to call MapInfo_FilterGametype afterwards!
+void MapInfo_Enumerate();
+
+// filter the info by game type mask (updates MapInfo_count)
+float MapInfo_progress;
+float MapInfo_FilterGametype(float gametype, float features, float pAbortOnGenerate); // 1 on success, 0 on temporary failure (call it again next frame then; use MapInfo_progress as progress indicator)
+float MapInfo_CurrentFeatures(); // retrieves currently required features from cvars
+float MapInfo_CurrentGametype(); // retrieves current gametype from cvars
+
+// load info about the i-th map into the MapInfo_Map_* globals
+float MapInfo_Get_ByID(float i); // 1 on success, 0 on failure
+string MapInfo_BSPName_ByID(float i);
+
+// load info about a map by name into the MapInfo_Map_* globals
+float MapInfo_Get_ByName(string s, float allowGenerate, float gametypeToSet); // 1 on success, 0 on failure, 2 if it autogenerated a mapinfo file
+
+// look for a map by a prefix, returns the actual map name on success, string_null on failure or ambigous match
+string MapInfo_FindName_match; // the name of the map that was found
+float MapInfo_FindName_firstResult; // -1 if none were found, index of first one if not unique but found (FindName then returns -1)
+float MapInfo_FindName(string s);
+string MapInfo_FixName(string s);
+
+// play a map
+float MapInfo_CheckMap(string s); // returns 0 if the map can't be played with the current settings
+void MapInfo_LoadMap(string s);
+
+// list all maps for the current game type
+string MapInfo_ListAllowedMaps();
+
+// gets a gametype from a string
+float MapInfo_Type_FromString(string t);
+void MapInfo_SwitchGameType(float t);
+
+// to be called from worldspawn to set up cvars
+void MapInfo_LoadMapSettings(string s);
+
+void MapInfo_Cache_Destroy(); // disable caching
+void MapInfo_Cache_Create(); // enable caching
+void MapInfo_Cache_Invalidate(); // delete cache if any, but keep enabled
+
+void MapInfo_ClearTemps(); // call this when done with mapinfo for this frame
Added: trunk/common/util.qc
===================================================================
--- trunk/common/util.qc (rev 0)
+++ trunk/common/util.qc 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,378 @@
+string wordwrap_buffer;
+
+void wordwrap_buffer_put(string s)
+{
+ wordwrap_buffer = strcat(wordwrap_buffer, s);
+}
+
+string wordwrap(string s, float l)
+{
+ string r;
+ wordwrap_buffer = "";
+ wordwrap_cb(s, l, wordwrap_buffer_put);
+ r = wordwrap_buffer;
+ wordwrap_buffer = "";
+ return r;
+}
+
+#ifndef MENUQC
+void wordwrap_buffer_sprint(string s)
+{
+ wordwrap_buffer = strcat(wordwrap_buffer, s);
+ if(s == "\n")
+ {
+ sprint(self, wordwrap_buffer);
+ wordwrap_buffer = "";
+ }
+}
+
+void wordwrap_sprint(string s, float l)
+{
+ wordwrap_buffer = "";
+ wordwrap_cb(s, l, wordwrap_buffer_sprint);
+ if(wordwrap_buffer != "")
+ sprint(self, strcat(wordwrap_buffer, "\n"));
+ wordwrap_buffer = "";
+ return;
+}
+#endif
+
+void wordwrap_cb(string s, float l, void(string) callback)
+{
+ local string c;
+ local float lleft, i, j, wlen;
+
+ s = strzone(s);
+ lleft = l;
+ for (i = 0;i < strlen(s);i++)
+ {
+ if (substring(s, i, 2) == "\\n")
+ {
+ callback("\n");
+ lleft = l;
+ i++;
+ }
+ else if (substring(s, i, 1) == "\n")
+ {
+ callback("\n");
+ lleft = l;
+ }
+ else if (substring(s, i, 1) == " ")
+ {
+ if (lleft > 0)
+ {
+ callback(" ");
+ lleft = lleft - 1;
+ }
+ }
+ else
+ {
+ for (j = i+1;j < strlen(s);j++)
+ // ^^ this skips over the first character of a word, which
+ // is ALWAYS part of the word
+ // this is safe since if i+1 == strlen(s), i will become
+ // strlen(s)-1 at the end of this block and the function
+ // will terminate. A space can't be the first character we
+ // read here, and neither can a \n be the start, since these
+ // two cases have been handled above.
+ {
+ c = substring(s, j, 1);
+ if (c == " ")
+ break;
+ if (c == "\\")
+ break;
+ if (c == "\n")
+ break;
+ // we need to keep this tempstring alive even if substring is
+ // called repeatedly, so call strcat even though we're not
+ // doing anything
+ callback("");
+ }
+ wlen = j - i;
+ if (lleft < wlen)
+ {
+ callback("\n");
+ lleft = l;
+ }
+ callback(substring(s, i, wlen));
+ lleft = lleft - wlen;
+ i = j - 1;
+ }
+ }
+ strunzone(s);
+}
+
+float dist_point_line(vector p, vector l0, vector ldir)
+{
+ ldir = normalize(ldir);
+
+ // remove the component in line direction
+ p = p - (p * ldir) * ldir;
+
+ // vlen of the remaining vector
+ return vlen(p);
+}
+
+void depthfirst(entity start, .entity up, .entity downleft, .entity right, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass)
+{
+ entity e;
+ e = start;
+ funcPre(pass, e);
+ while(e.downleft)
+ {
+ e = e.downleft;
+ funcPre(pass, e);
+ }
+ funcPost(pass, e);
+ while(e != start)
+ {
+ if(e.right)
+ {
+ e = e.right;
+ funcPre(pass, e);
+ while(e.downleft)
+ {
+ e = e.downleft;
+ funcPre(pass, e);
+ }
+ }
+ else
+ e = e.up;
+ funcPost(pass, e);
+ }
+}
+
+float median(float a, float b, float c)
+{
+ if(a < c)
+ return bound(a, b, c);
+ return bound(c, b, a);
+}
+
+// converts a number to a string with the indicated number of decimals
+// works for up to 10 decimals!
+string ftos_decimals(float number, float decimals)
+{
+ string result;
+ string tmp;
+ float len;
+
+ // if negative, cut off the sign first
+ if(number < 0)
+ return strcat("-", ftos_decimals(-number, decimals));
+ // it now is always positive!
+
+ // 3.516 -> 352
+ number = floor(number * pow(10, decimals) + 0.5);
+
+ // 352 -> "352"
+ result = ftos(number);
+ len = strlen(result);
+ // does it have a decimal point (should not happen)? If there is one, it is always at len-7)
+ // if ftos had fucked it up, which should never happen: "34278.000000"
+ if(len >= 7)
+ if(substring(result, len - 7, 1) == ".")
+ {
+ dprint("ftos(integer) has comma? Can't be. Affected result: ", result, "\n");
+ result = substring(result, 0, len - 7);
+ len -= 7;
+ }
+ // "34278"
+ if(decimals == 0)
+ return result; // don't insert a point for zero decimals
+ // is it too short? If yes, insert leading zeroes
+ if(len <= decimals)
+ {
+ result = strcat(substring("0000000000", 0, decimals - len + 1), result);
+ len = decimals + 1;
+ }
+ // and now... INSERT THE POINT!
+ tmp = substring(result, len - decimals, decimals);
+ result = strcat(substring(result, 0, len - decimals), ".", tmp);
+ return result;
+}
+
+float time;
+vector colormapPaletteColor(float c, float isPants)
+{
+ switch(c)
+ {
+ case 0: return '0.733 0.733 0.733';
+ case 1: return '0.451 0.341 0.122';
+ case 2: return '0.000 0.733 0.733';
+ case 3: return '0.000 1.000 0.000';
+ case 4: return '1.000 0.000 0.000';
+ case 5: return '0.000 0.502 1.000';
+ case 6: return '0.812 0.561 0.169';
+ case 7: return '0.718 0.529 0.420';
+ case 8: return '0.765 0.545 0.667';
+ case 9: return '1.000 0.000 1.000';
+ case 10: return '0.639 0.529 0.482';
+ case 11: return '0.310 0.388 0.341';
+ case 12: return '1.000 1.000 0.000';
+ case 13: return '0.000 0.000 1.000';
+ case 14: return '1.000 0.502 0.000';
+ case 15:
+ if(isPants)
+ return
+ '1 0 0' * (0.502 + 0.498 * sin(time / 2.7182818285 + 0.0000000000))
+ + '0 1 0' * (0.502 + 0.498 * sin(time / 2.7182818285 + 2.0943951024))
+ + '0 0 1' * (0.502 + 0.498 * sin(time / 2.7182818285 + 4.1887902048));
+ else
+ return
+ '1 0 0' * (0.502 + 0.498 * sin(time / 3.1415926536 + 5.2359877560))
+ + '0 1 0' * (0.502 + 0.498 * sin(time / 3.1415926536 + 3.1415926536))
+ + '0 0 1' * (0.502 + 0.498 * sin(time / 3.1415926536 + 1.0471975512));
+ default: return '0.000 0.000 0.000';
+ }
+}
+
+// unzone the string, and return it as tempstring. Safe to be called on string_null
+string fstrunzone(string s)
+{
+ string sc;
+ if not(s)
+ return s;
+ sc = strcat(s, "");
+ strunzone(s);
+ return sc;
+}
+
+// Databases (hash tables)
+#define DB_BUCKETS 8192
+void db_save(float db, string pFilename)
+{
+ float fh, i, n;
+ fh = fopen(pFilename, FILE_WRITE);
+ if(fh < 0)
+ error(strcat("Can't write DB to ", pFilename));
+ n = buf_getsize(db);
+ fputs(fh, strcat(ftos(DB_BUCKETS), "\n"));
+ for(i = 0; i < n; ++i)
+ fputs(fh, strcat(bufstr_get(db, i), "\n"));
+ fclose(fh);
+}
+
+float db_create()
+{
+ return buf_create();
+}
+
+float db_load(string pFilename)
+{
+ float db, fh, i, j, n;
+ string l;
+ db = buf_create();
+ if(db < 0)
+ return -1;
+ fh = fopen(pFilename, FILE_READ);
+ if(fh < 0)
+ return db;
+ if(stof(fgets(fh)) == DB_BUCKETS)
+ {
+ i = 0;
+ while((l = fgets(fh)))
+ {
+ if(l != "")
+ bufstr_set(db, i, l);
+ ++i;
+ }
+ }
+ else
+ {
+ // different count of buckets?
+ // need to reorganize the database then (SLOW)
+ while((l = fgets(fh)))
+ {
+ n = tokenizebyseparator(l, "\\");
+ for(j = 2; j < n; j += 2)
+ db_put(db, argv(j-1), argv(j));
+ }
+ }
+ fclose(fh);
+ return db;
+}
+
+void db_dump(float db, string pFilename)
+{
+ float fh, i, j, n, m;
+ fh = fopen(pFilename, FILE_WRITE);
+ if(fh < 0)
+ error(strcat("Can't dump DB to ", pFilename));
+ n = buf_getsize(db);
+ fputs(fh, "0\n");
+ for(i = 0; i < n; ++i)
+ {
+ m = tokenizebyseparator(bufstr_get(db, i), "\\");
+ for(j = 2; j < m; j += 2)
+ fputs(fh, strcat("\\", argv(j-1), "\\", argv(j), "\n"));
+ }
+ fclose(fh);
+}
+
+void db_close(float db)
+{
+ buf_del(db);
+}
+
+string db_get(float db, string pKey)
+{
+ float h;
+ h = mod(crc16(FALSE, pKey), DB_BUCKETS);
+ return infoget(bufstr_get(db, h), pKey);
+}
+
+void db_put(float db, string pKey, string pValue)
+{
+ float h;
+ h = mod(crc16(FALSE, pKey), DB_BUCKETS);
+ bufstr_set(db, h, infoadd(bufstr_get(db, h), pKey, pValue));
+}
+
+void db_test()
+{
+ float db, i;
+ print("LOAD...\n");
+ db = db_load("foo.db");
+ print("LOADED. FILL...\n");
+ for(i = 0; i < DB_BUCKETS; ++i)
+ db_put(db, ftos(random()), "X");
+ print("FILLED. SAVE...\n");
+ db_save(db, "foo.db");
+ print("SAVED. CLOSE...\n");
+ db_close(db);
+ print("CLOSED.\n");
+}
+
+// Multiline text file buffers
+float buf_load(string pFilename)
+{
+ float buf, fh, i;
+ string l;
+ buf = buf_create();
+ if(buf < 0)
+ return -1;
+ fh = fopen(pFilename, FILE_READ);
+ if(fh < 0)
+ return buf;
+ i = 0;
+ while((l = fgets(fh)))
+ {
+ bufstr_set(buf, i, l);
+ ++i;
+ }
+ fclose(fh);
+ return buf;
+}
+
+void buf_save(float buf, string pFilename)
+{
+ float fh, i, n;
+ fh = fopen(pFilename, FILE_WRITE);
+ if(fh < 0)
+ error(strcat("Can't write buf to ", pFilename));
+ n = buf_getsize(buf);
+ for(i = 0; i < n; ++i)
+ fputs(fh, strcat(bufstr_get(buf, i), "\n"));
+ fclose(fh);
+}
Added: trunk/common/util.qh
===================================================================
--- trunk/common/util.qh (rev 0)
+++ trunk/common/util.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,55 @@
+// note: this is in util.qh so it is included as early as possible.
+var void(string s, ...) dprint;
+void dprint_null() { }
+void dprint_load()
+{
+ if(cvar("developer") > 0)
+ dprint = print;
+ else
+ dprint = dprint_null;
+}
+
+// this returns a tempstring containing a copy of s with additional \n newlines added, it also replaces \n in the text with a real newline
+// NOTE: s IS allowed to be a tempstring
+string wordwrap(string s, float l);
+#ifndef MENUQC
+void wordwrap_sprint(string s, float l);
+#endif
+void wordwrap_cb(string s, float l, void(string) callback)
+
+float GameCommand_Generic(string cmd);
+// returns TRUE if handled, FALSE otherwise
+// uses tokenize on its argument!
+
+// iterative depth-first search, with fields that go "up", "down left" and "right" in a tree
+// for each element, funcPre is called first, then funcPre and funcPost for all its children, and funcPost last
+void depthfirst(entity start, .entity up, .entity downleft, .entity right, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass);
+
+float median(float a, float b, float c);
+
+// converts a number to a string with the indicated number of decimals
+// works for up to 10 decimals!
+string ftos_decimals(float number, float decimals);
+
+vector colormapPaletteColor(float c, float isPants);
+
+// unzone the string, and return it as tempstring. Safe to be called on string_null
+string fstrunzone(string s);
+
+// database (NOTE: keys are case sensitive)
+void db_save(float db, string filename);
+void db_dump(float db, string pFilename);
+float db_create();
+float db_load(string filename);
+void db_close(float db);
+string db_get(float db, string key);
+void db_put(float db, string key, string value);
+
+// stringbuffer loading/saving
+float buf_load(string filename);
+void buf_save(float buf, string filename);
+
+// modulo function
+#ifndef MENUQC
+float mod(float a, float b) { return a - (floor(a / b) * b); }
+#endif
Added: trunk/menu/classes.c
===================================================================
--- trunk/menu/classes.c (rev 0)
+++ trunk/menu/classes.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,67 @@
+#include "item.c"
+#include "item/container.c"
+#include "item/inputcontainer.c"
+#include "item/nexposee.c"
+#include "item/modalcontroller.c"
+#include "item/image.c"
+#include "item/label.c"
+#include "item/button.c"
+#include "item/checkbox.c"
+#include "item/radiobutton.c"
+#include "item/borderimage.c"
+#include "item/slider.c"
+#include "item/dialog.c"
+#include "item/tab.c"
+#include "item/textslider.c"
+#include "item/listbox.c"
+#include "item/inputbox.c"
+#include "item/gecko.c"
+#include "nexuiz/dialog.c"
+#include "nexuiz/tab.c"
+#include "nexuiz/mainwindow.c"
+#include "nexuiz/button.c"
+#include "nexuiz/commandbutton.c"
+#include "nexuiz/dialog_teamselect.c"
+#include "nexuiz/dialog_classselect.c"
+#include "nexuiz/dialog_infoscreen.c"
+#include "nexuiz/dialog_settings.c"
+#include "nexuiz/dialog_settings_video.c"
+#include "nexuiz/dialog_settings_effects.c"
+#include "nexuiz/dialog_settings_misc.c"
+#include "nexuiz/dialog_multiplayer.c"
+#include "nexuiz/dialog_multiplayer_playersetup.c"
+#include "nexuiz/tabcontroller.c"
+#include "nexuiz/textlabel.c"
+#include "nexuiz/slider.c"
+#include "nexuiz/slider_resolution.c"
+#include "nexuiz/checkbox.c"
+#include "nexuiz/radiobutton.c"
+#include "nexuiz/nexposee.c"
+#include "nexuiz/rootdialog.c"
+#include "nexuiz/textslider.c"
+#include "nexuiz/colorbutton.c"
+#include "nexuiz/dialog_multiplayer_join.c"
+#include "nexuiz/listbox.c"
+#include "nexuiz/serverlist.c"
+#include "nexuiz/inputbox.c"
+#include "nexuiz/dialog_quit.c"
+#include "nexuiz/dialog_multiplayer_create.c"
+#include "nexuiz/dialog_multiplayer_create_mutators.c"
+#include "nexuiz/dialog_multiplayer_create_mapinfo.c"
+#include "nexuiz/gametypebutton.c"
+#include "nexuiz/maplist.c"
+#include "nexuiz/image.c"
+#include "nexuiz/crosshairbutton.c"
+#include "nexuiz/playermodel.c"
+#include "nexuiz/dialog_news.c"
+#include "nexuiz/checkbox_slider_invalid.c"
+#include "nexuiz/charmap.c"
+#include "nexuiz/keybinder.c"
+#include "nexuiz/dialog_settings_input.c"
+#include "nexuiz/dialog_settings_input_userbind.c"
+#include "nexuiz/slider_decibels.c"
+#include "nexuiz/dialog_singleplayer.c"
+#include "nexuiz/campaign.c"
+#include "nexuiz/dialog_singleplayer_winner.c"
+#include "nexuiz/dialog_credits.c"
+#include "nexuiz/credits.c"
Added: trunk/menu/config.qh
===================================================================
--- trunk/menu/config.qh (rev 0)
+++ trunk/menu/config.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,4 @@
+// build config file
+#define MENUQC // so common/*.qc can check for menu QC or game QC
+// #define MAPINFO // maybe later, when it is the default in server QC
+
Added: trunk/menu/draw.qc
===================================================================
--- trunk/menu/draw.qc (rev 0)
+++ trunk/menu/draw.qc 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,318 @@
+string draw_mousepointer;
+vector draw_mousepointer_offset;
+vector draw_mousepointer_size;
+
+string draw_UseSkinFor(string pic)
+{
+ if(substring(pic, 0, 1) == "/")
+ return substring(pic, 1, strlen(pic)-1);
+ else
+ return strcat(draw_currentSkin, "/", pic);
+}
+
+void draw_setMousePointer(string pic, vector theSize, vector theOffset)
+{
+ draw_mousepointer = strzone(draw_UseSkinFor(pic));
+ draw_mousepointer_size = theSize;
+ draw_mousepointer_offset = eX * (theOffset_x * theSize_x) + eY * (theOffset_y * theSize_y);
+}
+
+void draw_drawMousePointer(vector where)
+{
+ drawpic(boxToGlobal(where, draw_shift, draw_scale) - draw_mousepointer_offset, draw_mousepointer, draw_mousepointer_size, '1 1 1', draw_alpha, 0);
+}
+
+void draw_reset()
+{
+ drawfont = FONT_USER+0;
+ draw_shift = '0 0 0';
+ draw_scale = '1 0 0' * cvar("vid_conwidth") + '0 1 0' * cvar("vid_conheight");
+ draw_alpha = 1;
+}
+
+vector globalToBox(vector v, vector theOrigin, vector theScale)
+{
+ v -= theOrigin;
+ v_x /= theScale_x;
+ v_y /= theScale_y;
+ return v;
+}
+
+vector globalToBoxSize(vector v, vector theScale)
+{
+ v_x /= theScale_x;
+ v_y /= theScale_y;
+ return v;
+}
+
+vector boxToGlobal(vector v, vector theOrigin, vector theScale)
+{
+ v_x *= theScale_x;
+ v_y *= theScale_y;
+ v += theOrigin;
+ return v;
+}
+
+vector boxToGlobalSize(vector v, vector theScale)
+{
+ v_x *= theScale_x;
+ v_y *= theScale_y;
+ return v;
+}
+
+void draw_PreloadPicture(string pic)
+{
+ pic = draw_UseSkinFor(pic);
+ precache_pic(pic);
+}
+
+void draw_Picture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
+{
+ pic = draw_UseSkinFor(pic);
+ drawpic(boxToGlobal(theOrigin, draw_shift, draw_scale), pic, boxToGlobalSize(theSize, draw_scale), theColor, theAlpha * draw_alpha, 0);
+}
+
+vector draw_PictureSize(string pic)
+{
+ pic = draw_UseSkinFor(pic);
+ return drawgetimagesize(pic);
+}
+
+void draw_Fill(vector theOrigin, vector theSize, vector theColor, float theAlpha)
+{
+ drawfill(boxToGlobal(theOrigin, draw_shift, draw_scale), boxToGlobalSize(theSize, draw_scale), theColor, theAlpha * draw_alpha, 0);
+}
+
+// a button picture is a texture containing three parts:
+// 1/4 width: left part
+// 1/2 width: middle part (stretched)
+// 1/4 width: right part
+// it is assumed to be 4x as wide as high for aspect ratio purposes, which
+// means, the parts are a square, two squares and a square.
+void draw_ButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
+{
+ vector square;
+ vector width, height;
+ vector bW;
+ pic = draw_UseSkinFor(pic);
+ theOrigin = boxToGlobal(theOrigin, draw_shift, draw_scale);
+ theSize = boxToGlobalSize(theSize, draw_scale);
+ theAlpha *= draw_alpha;
+ width = eX * theSize_x;
+ height = eY * theSize_y;
+ if(theSize_x <= theSize_y * 2)
+ {
+ // button not wide enough
+ // draw just left and right part then
+ square = eX * theSize_x * 0.5;
+ bW = eX * (0.25 * theSize_x / (theSize_y * 2));
+ drawsubpic(theOrigin, square + height, pic, '0 0 0', eY + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + square, square + height, pic, eX - bW, eY + bW, theColor, theAlpha, 0);
+ }
+ else
+ {
+ square = eX * theSize_y;
+ drawsubpic(theOrigin, height + square, pic, '0 0 0', '0.25 1 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + square, theSize - 2 * square, pic, '0.25 0 0', '0.5 1 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width - square, height + square, pic, '0.75 0 0', '0.25 1 0', theColor, theAlpha, 0);
+ }
+}
+
+// a vertical button picture is a texture containing three parts:
+// 1/4 height: left part
+// 1/2 height: middle part (stretched)
+// 1/4 height: right part
+// it is assumed to be 4x as high as wide for aspect ratio purposes, which
+// means, the parts are a square, two squares and a square.
+void draw_VertButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
+{
+ vector square;
+ vector width, height;
+ vector bH;
+ pic = draw_UseSkinFor(pic);
+ theOrigin = boxToGlobal(theOrigin, draw_shift, draw_scale);
+ theSize = boxToGlobalSize(theSize, draw_scale);
+ theAlpha *= draw_alpha;
+ width = eX * theSize_x;
+ height = eY * theSize_y;
+ if(theSize_y <= theSize_x * 2)
+ {
+ // button not high enough
+ // draw just upper and lower part then
+ square = eY * theSize_y * 0.5;
+ bH = eY * (0.25 * theSize_y / (theSize_x * 2));
+ drawsubpic(theOrigin, square + width, pic, '0 0 0', eX + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + square, square + width, pic, eY - bH, eX + bH, theColor, theAlpha, 0);
+ }
+ else
+ {
+ square = eY * theSize_x;
+ drawsubpic(theOrigin, width + square, pic, '0 0 0', '1 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + square, theSize - 2 * square, pic, '0 0.25 0', '1 0.5 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height - square, width + square, pic, '0 0.75 0', '1 0.25 0', theColor, theAlpha, 0);
+ }
+}
+
+// a border picture is a texture containing nine parts:
+// 1/4 width: left part
+// 1/2 width: middle part (stretched)
+// 1/4 width: right part
+// divided into
+// 1/4 height: top part
+// 1/2 height: middle part (stretched)
+// 1/4 height: bottom part
+void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha, vector theBorderSize)
+{
+ vector dX, dY;
+ vector width, height;
+ vector bW, bH;
+ pic = draw_UseSkinFor(pic);
+ theOrigin = boxToGlobal(theOrigin, draw_shift, draw_scale);
+ theSize = boxToGlobalSize(theSize, draw_scale);
+ theBorderSize = boxToGlobalSize(theBorderSize, draw_scale);
+ theAlpha *= draw_alpha;
+ width = eX * theSize_x;
+ height = eY * theSize_y;
+ if(theSize_x <= theBorderSize_x * 2)
+ {
+ // not wide enough... draw just left and right then
+ bW = eX * (0.25 * theSize_x / (theBorderSize_x * 2));
+ if(theSize_y <= theBorderSize_y * 2)
+ {
+ // not high enough... draw just corners
+ bH = eY * (0.25 * theSize_y / (theBorderSize_y * 2));
+ drawsubpic(theOrigin, width * 0.5 + height * 0.5, pic, '0 0 0', bW + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width * 0.5, width * 0.5 + height * 0.5, pic, eX - bW, bW + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height * 0.5, width * 0.5 + height * 0.5, pic, eY - bH, bW + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + theSize * 0.5, width * 0.5 + height * 0.5, pic, eX + eY - bW - bH, bW + bH, theColor, theAlpha, 0);
+ }
+ else
+ {
+ dY = theBorderSize_x * eY;
+ drawsubpic(theOrigin, width * 0.5 + dY, pic, '0 0 0', '0 0.25 0' + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width * 0.5, width * 0.5 + dY, pic, '0 0 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0', '0 0.5 0' + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width * 0.5 + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0' + eX - bW, '0 0.5 0' + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height - dY, width * 0.5 + dY, pic, '0 0.75 0', '0 0.25 0' + bW, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width * 0.5 + height - dY, width * 0.5 + dY, pic, '0 0.75 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
+ }
+ }
+ else
+ {
+ if(theSize_y <= theBorderSize_y * 2)
+ {
+ // not high enough... draw just top and bottom then
+ bH = eY * (0.25 * theSize_y / (theBorderSize_y * 2));
+ dX = theBorderSize_x * eX;
+ drawsubpic(theOrigin, dX + height * 0.5, pic, '0 0 0', '0.25 0 0' + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dX, width - 2 * dX + height * 0.5, pic, '0.25 0 0', '0.5 0 0' + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width - dX, dX + height * 0.5, pic, '0.75 0 0', '0.25 0 0' + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height * 0.5, dX + height * 0.5, pic, '0 0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dX + height * 0.5, width - 2 * dX + height * 0.5, pic, '0.25 0 0' + eY - bH, '0.5 0 0' + bH, theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width - dX + height * 0.5, dX + height * 0.5, pic, '0.75 0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
+ }
+ else
+ {
+ dX = theBorderSize_x * eX;
+ dY = theBorderSize_x * eY;
+ drawsubpic(theOrigin, dX + dY, pic, '0 0 0', '0.25 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dX, width - 2 * dX + dY, pic, '0.25 0 0', '0.5 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + width - dX, dX + dY, pic, '0.75 0 0', '0.25 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dY, dX + height - 2 * dY, pic, '0 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dY + dX, width - 2 * dX + height - 2 * dY, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + dY + width - dX, dX + height - 2 * dY, pic, '0.75 0.25 0', '0.25 0.5 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height - dY, dX + dY, pic, '0 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height - dY + dX, width - 2 * dX + dY, pic, '0.25 0.75 0', '0.5 0.25 0', theColor, theAlpha, 0);
+ drawsubpic(theOrigin + height - dY + width - dX, dX + dY, pic, '0.75 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
+ }
+ }
+}
+void draw_Text(vector theOrigin, string theText, vector theSize, vector theColor, float theAlpha, float ICanHasKallerz)
+{
+ if(theSize_x <= 0 || theSize_y <= 0)
+ error("Drawing zero size text?\n");
+ if(ICanHasKallerz)
+ drawcolorcodedstring(boxToGlobal(theOrigin, draw_shift, draw_scale), theText, boxToGlobalSize(theSize, draw_scale), theAlpha * draw_alpha, 0);
+ else
+ drawstring(boxToGlobal(theOrigin, draw_shift, draw_scale), theText, boxToGlobalSize(theSize, draw_scale), theColor, theAlpha * draw_alpha, 0);
+}
+void draw_CenterText(vector theOrigin, string theText, vector theSize, vector theColor, float theAlpha, float ICanHasKallerz)
+{
+ draw_Text(theOrigin - eX * theSize_x * 0.5 * draw_TextWidth(theText, ICanHasKallerz), theText, theSize, theColor, theAlpha, ICanHasKallerz);
+}
+
+float draw_TextWidth(string theText, float ICanHasKallerz)
+{
+ //return strlen(theText);
+ //print("draw_TextWidth \"", theText, "\"\n");
+ return stringwidth(theText, ICanHasKallerz);
+}
+
+float draw_clipSet;
+void draw_SetClip()
+{
+ if(draw_clipSet)
+ error("Already clipping, no stack implemented here, sorry");
+ drawsetcliparea(draw_shift_x, draw_shift_y, draw_scale_x, draw_scale_y);
+ draw_clipSet = 1;
+}
+
+void draw_SetClipRect(vector theOrigin, vector theScale)
+{
+ vector o, s;
+ if(draw_clipSet)
+ error("Already clipping, no stack implemented here, sorry");
+ o = boxToGlobal(theOrigin, draw_shift, draw_scale);
+ s = boxToGlobalSize(theScale, draw_scale);
+ drawsetcliparea(o_x, o_y, s_x, s_y);
+ draw_clipSet = 1;
+}
+
+void draw_ClearClip()
+{
+ if(!draw_clipSet)
+ error("Not clipping, can't clear it then");
+ drawresetcliparea();
+ draw_clipSet = 0;
+}
+
+string draw_TextShortenToWidth(string theText, float maxWidth, float ICanHasKallerz)
+{
+ if(draw_TextWidth(theText, ICanHasKallerz) <= maxWidth)
+ return theText;
+ else
+ return strcat(substring(theText, 0, draw_TextLengthUpToWidth(theText, maxWidth - draw_TextWidth("...", ICanHasKallerz), ICanHasKallerz)), "...");
+}
+
+float draw_TextLengthUpToWidth(string theText, float maxWidth, float ICanHasKallerz)
+{
+ // STOP.
+ // The following function is SLOW.
+ // For your safety and for the protection of those around you...
+ // DO NOT CALL THIS AT HOME.
+ // No really, don't.
+ if(draw_TextWidth(theText, ICanHasKallerz) <= maxWidth)
+ return strlen(theText); // yeah!
+
+ // binary search for right place to cut string
+ float left, right, middle; // this always works
+ left = 0;
+ right = strlen(theText); // this always fails
+ do
+ {
+ middle = floor((left + right) / 2);
+ if(draw_TextWidth(substring(theText, 0, middle), ICanHasKallerz) <= maxWidth)
+ left = middle;
+ else
+ right = middle;
+ }
+ while(left < right - 1);
+
+ // NOTE: when color codes are involved, this binary search is,
+ // mathematically, BROKEN. However, it is obviously guaranteed to
+ // terminate, as the range still halves each time - but nevertheless, it is
+ // guaranteed that it finds ONE valid cutoff place (where "left" is in
+ // range, and "right" is outside).
+
+ return left;
+}
Added: trunk/menu/draw.qh
===================================================================
--- trunk/menu/draw.qh (rev 0)
+++ trunk/menu/draw.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,33 @@
+vector draw_shift;
+vector draw_scale;
+float draw_alpha;
+
+void draw_reset();
+void draw_setMousePointer(string pic, vector theSize, vector theOffset);
+void draw_drawMousePointer(vector where);
+
+void draw_PreloadPicture(string pic);
+void draw_ButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha);
+void draw_VertButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha);
+void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha, vector theBorderSize);
+void draw_Picture(vector origin, string pic, vector size, vector color, float alpha);
+vector draw_PictureSize(string pic);
+void draw_Fill(vector theOrigin, vector theSize, vector theColor, float theAlpha);
+void draw_Text(vector origin, string text, vector size, vector color, float alpha, float allowColorCodes);
+void draw_CenterText(vector origin, string text, vector size, vector color, float alpha, float allowColorCodes);
+float draw_TextWidth(string text, float allowColorCodes);
+string draw_TextShortenToWidth(string text, float maxWidth, float allowColorCodes);
+float draw_TextLengthUpToWidth(string text, float maxWidth, float allowColorCodes);
+
+void draw_SetClip();
+void draw_SetClipRect(vector theOrigin, vector theScale);
+void draw_ClearClip();
+
+vector boxToGlobal(vector v, vector shift, vector scale);
+vector boxToGlobalSize(vector v, vector scale);
+vector globalToBox(vector v, vector shift, vector scale);
+vector globalToBoxSize(vector v, vector scale);
+
+float draw_NeedResizeNotify;
+
+string draw_currentSkin;
Added: trunk/menu/gamecommand.qc
===================================================================
--- trunk/menu/gamecommand.qc (rev 0)
+++ trunk/menu/gamecommand.qc 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,72 @@
+void GameCommand_Init()
+{
+ // make gg call menu QC theCommands
+ localcmd("alias qc_cmd \"menu_cmd $*\"\n");
+}
+
+string _dumptree_space;
+void _dumptree_open(entity pass, entity me)
+{
+ string s;
+ s = me.toString(me);
+ if(s == "")
+ s = me.classname;
+ else
+ s = strcat(me.classname, ": ", s);
+ print(_dumptree_space, etos(me), " (", s, ")");
+ if(me.firstChild)
+ {
+ print(" {\n");
+ _dumptree_space = strcat(_dumptree_space, " ");
+ }
+ else
+ print("\n");
+}
+void _dumptree_close(entity pass, entity me)
+{
+ if(me.firstChild)
+ {
+ _dumptree_space = substring(_dumptree_space, 0, strlen(_dumptree_space) - 2);
+ print(_dumptree_space, "}\n");
+ }
+}
+
+void GameCommand(string theCommand)
+{
+ float argc;
+ argc = tokenize(theCommand);
+
+ if(argv(0) == "help" || argc == 0)
+ {
+ print("Usage: menu_cmd theCommand..., where possible theCommands are:\n");
+ print(" sync - reloads all cvars on the current menu page\n");
+ print(" directmenu ITEM - select a menu item as main item\n");
+ GameCommand_Generic("help");
+ return;
+ }
+
+ if(GameCommand_Generic(theCommand))
+ return;
+
+ if(argv(0) == "sync")
+ {
+ loadAllCvars(main);
+ return;
+ }
+
+ if(argv(0) == "directmenu") if(argc == 2)
+ {
+ // switch to a menu item
+ m_goto(argv(1));
+ return;
+ }
+
+ if(argv(0) == "dumptree")
+ {
+ _dumptree_space = "";
+ depthfirst(main, parent, firstChild, nextSibling, _dumptree_open, _dumptree_close, NULL);
+ return;
+ }
+
+ print("Invalid theCommand. For a list of supported theCommands, try menu_cmd help.\n");
+}
Added: trunk/menu/gamecommand.qh
===================================================================
--- trunk/menu/gamecommand.qh (rev 0)
+++ trunk/menu/gamecommand.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,2 @@
+void GameCommand_Init();
+void GameCommand(string command);
Added: trunk/menu/item/borderimage.c
===================================================================
--- trunk/menu/item/borderimage.c (rev 0)
+++ trunk/menu/item/borderimage.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,87 @@
+#ifdef INTERFACE
+CLASS(BorderImage) EXTENDS(Label)
+ METHOD(BorderImage, configureBorderImage, void(entity, string, float, vector, string, float))
+ METHOD(BorderImage, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(BorderImage, draw, void(entity))
+ ATTRIB(BorderImage, src, string, string_null)
+ ATTRIB(BorderImage, borderHeight, float, 0)
+ ATTRIB(BorderImage, borderVec, vector, '0 0 0')
+ ATTRIB(BorderImage, color, vector, '1 1 1')
+ ATTRIB(BorderImage, closeButton, entity, NULL)
+ ATTRIB(BorderImage, realFontSize_Nexposeed, vector, '0 0 0')
+ ATTRIB(BorderImage, realOrigin_Nexposeed, vector, '0 0 0')
+ ATTRIB(BorderImage, isNexposeeTitleBar, float, 0)
+ ATTRIB(BorderImage, zoomedOutTitleBarPosition, float, 0)
+ ATTRIB(BorderImage, zoomedOutTitleBar, float, 0)
+ENDCLASS(BorderImage)
+#endif
+
+#ifdef IMPLEMENTATION
+void resizeNotifyBorderImage(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ me.isNexposeeTitleBar = 0;
+ if(me.zoomedOutTitleBar)
+ if(me.parent.parent.instanceOfNexposee)
+ if(me.parent.instanceOfDialog)
+ if(me == me.parent.frame)
+ me.isNexposeeTitleBar = 1;
+ if(me.isNexposeeTitleBar)
+ {
+ vector scrs;
+ scrs = eX * conwidth + eY * conheight;
+ resizeNotifyLabel(me, relOrigin, relSize, boxToGlobal(me.parent.Nexposee_smallOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_smallSize, scrs));
+ me.realOrigin_y = me.realFontSize_y * me.zoomedOutTitleBarPosition;
+ me.realOrigin_Nexposeed = me.realOrigin;
+ me.realFontSize_Nexposeed = me.realFontSize;
+ }
+ resizeNotifyLabel(me, relOrigin, relSize, absOrigin, absSize);
+ me.borderVec = me.borderHeight / absSize_y * (eY + eX * (absSize_y / absSize_x));
+ me.realOrigin_y = 0.5 * (me.borderVec_y - me.realFontSize_y);
+ if(me.closeButton)
+ {
+ // move the close button to the right place
+ me.closeButton.Container_origin = '1 0 0' * (1 - me.borderVec_x);
+ me.closeButton.Container_size = me.borderVec;
+ me.closeButton.color = me.color;
+ me.closeButton.colorC = me.color;
+ me.closeButton.colorF = me.color;
+ }
+}
+void configureBorderImageBorderImage(entity me, string theTitle, float sz, vector theColor, string path, float theBorderHeight)
+{
+ me.configureLabel(me, theTitle, sz, 0.5);
+ me.src = path;
+ me.color = theColor;
+ me.borderHeight = theBorderHeight;
+}
+void drawBorderImage(entity me)
+{
+ //print(vtos(me.borderVec), "\n");
+
+ if(me.src)
+ draw_BorderPicture('0 0 0', me.src, '1 1 0', me.color, 1, me.borderVec);
+ if(me.fontSize > 0)
+ {
+ vector ro, rf;
+ if(me.isNexposeeTitleBar)
+ {
+ // me.parent.Nexposee_animationFactor 0 (small) or 1 (full)
+ // default values are for 1
+ ro = me.realOrigin;
+ rf = me.realFontSize;
+ me.realOrigin = ro * me.parent.Nexposee_animationFactor + me.realOrigin_Nexposeed * (1 - me.parent.Nexposee_animationFactor);
+ me.realFontSize = rf * me.parent.Nexposee_animationFactor + me.realFontSize_Nexposeed * (1 - me.parent.Nexposee_animationFactor);
+ }
+
+ drawLabel(me);
+
+ if(me.isNexposeeTitleBar)
+ {
+ // me.Nexposee_animationState 0 (small) or 1 (full)
+ // default values are for 1
+ me.realOrigin = ro;
+ me.realFontSize = rf;
+ }
+ }
+};
+#endif
Added: trunk/menu/item/button.c
===================================================================
--- trunk/menu/item/button.c (rev 0)
+++ trunk/menu/item/button.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,162 @@
+#ifdef INTERFACE
+CLASS(Button) EXTENDS(Label)
+ METHOD(Button, configureButton, void(entity, string, float, string))
+ METHOD(Button, draw, void(entity))
+ METHOD(Button, showNotify, void(entity))
+ METHOD(Button, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(Button, keyDown, float(entity, float, float, float))
+ METHOD(Button, mousePress, float(entity, vector))
+ METHOD(Button, mouseDrag, float(entity, vector))
+ METHOD(Button, mouseRelease, float(entity, vector))
+ ATTRIB(Button, onClick, void(entity, entity), SUB_Null)
+ ATTRIB(Button, onClickEntity, entity, NULL)
+ ATTRIB(Button, src, string, string_null)
+ ATTRIB(Button, srcSuffix, string, string_null)
+ ATTRIB(Button, src2, string, string_null) // is centered, same aspect, and stretched to label size
+ ATTRIB(Button, src2scale, float, 1)
+ ATTRIB(Button, srcMulti, float, 1) // 0: button square left, text right; 1: button stretched, text over it
+ ATTRIB(Button, buttonLeftOfText, float, 0)
+ ATTRIB(Button, focusable, float, 1)
+ ATTRIB(Button, pressed, float, 0)
+ ATTRIB(Button, clickTime, float, 0)
+ ATTRIB(Button, disabled, float, 0)
+ ATTRIB(Button, disabledAlpha, float, 0.3)
+ ATTRIB(Button, forcePressed, float, 0)
+ ATTRIB(Button, color, vector, '1 1 1')
+ ATTRIB(Button, colorC, vector, '1 1 1')
+ ATTRIB(Button, colorF, vector, '1 1 1')
+ ATTRIB(Button, colorD, vector, '1 1 1')
+ ATTRIB(Button, color2, vector, '1 1 1')
+ ATTRIB(Button, alpha2, float, 1)
+
+ ATTRIB(Button, origin, vector, '0 0 0')
+ ATTRIB(Button, size, vector, '0 0 0')
+ENDCLASS(Button)
+#endif
+
+#ifdef IMPLEMENTATION
+void resizeNotifyButton(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ if(me.srcMulti)
+ me.keepspaceLeft = 0;
+ else
+ me.keepspaceLeft = min(0.8, absSize_y / absSize_x);
+ resizeNotifyLabel(me, relOrigin, relSize, absOrigin, absSize);
+ me.origin = absOrigin;
+ me.size = absSize;
+}
+void configureButtonButton(entity me, string txt, float sz, string gfx)
+{
+ configureLabelLabel(me, txt, sz, me.srcMulti ? 0.5 : 0);
+ me.src = gfx;
+}
+float keyDownButton(entity me, float key, float ascii, float shift)
+{
+ if(key == K_ENTER || key == K_SPACE)
+ {
+ me.clickTime = 0.1; // delayed for effect
+ return 1;
+ }
+ return 0;
+}
+float mouseDragButton(entity me, vector pos)
+{
+ me.pressed = 1;
+ if(pos_x < 0) me.pressed = 0;
+ if(pos_y < 0) me.pressed = 0;
+ if(pos_x >= 1) me.pressed = 0;
+ if(pos_y >= 1) me.pressed = 0;
+ return 1;
+}
+float mousePressButton(entity me, vector pos)
+{
+ me.mouseDrag(me, pos); // verify coordinates
+ return 1;
+}
+float mouseReleaseButton(entity me, vector pos)
+{
+ me.mouseDrag(me, pos); // verify coordinates
+ if(me.pressed)
+ {
+ if not(me.disabled)
+ me.onClick(me, me.onClickEntity);
+ me.pressed = 0;
+ }
+ return 1;
+}
+void showNotifyButton(entity me)
+{
+ me.focusable = !me.disabled;
+}
+void drawButton(entity me)
+{
+ vector bOrigin, bSize;
+ float save;
+
+ me.focusable = !me.disabled;
+
+ save = draw_alpha;
+ if(me.disabled)
+ draw_alpha *= me.disabledAlpha;
+
+ if(me.src)
+ {
+ if(me.srcMulti)
+ {
+ bOrigin = '0 0 0';
+ bSize = '1 1 0';
+ if(me.disabled)
+ draw_ButtonPicture(bOrigin, strcat(me.src, "_d", me.srcSuffix), bSize, me.colorD, 1);
+ else if(me.forcePressed || me.pressed || me.clickTime > 0)
+ draw_ButtonPicture(bOrigin, strcat(me.src, "_c", me.srcSuffix), bSize, me.colorC, 1);
+ else if(me.focused)
+ draw_ButtonPicture(bOrigin, strcat(me.src, "_f", me.srcSuffix), bSize, me.colorF, 1);
+ else
+ draw_ButtonPicture(bOrigin, strcat(me.src, "_n", me.srcSuffix), bSize, me.color, 1);
+ }
+ else
+ {
+ if(me.realFontSize_y == 0)
+ {
+ bOrigin = '0 0 0';
+ bSize = '1 1 0';
+ }
+ else
+ {
+ bOrigin = eY * (0.5 * (1 - me.realFontSize_y)) + eX * (0.5 * (me.keepspaceLeft - me.realFontSize_x));
+ bSize = me.realFontSize;
+ }
+ if(me.disabled)
+ draw_Picture(bOrigin, strcat(me.src, "_d", me.srcSuffix), bSize, me.colorD, 1);
+ else if(me.forcePressed || me.pressed || me.clickTime > 0)
+ draw_Picture(bOrigin, strcat(me.src, "_c", me.srcSuffix), bSize, me.colorC, 1);
+ else if(me.focused)
+ draw_Picture(bOrigin, strcat(me.src, "_f", me.srcSuffix), bSize, me.colorF, 1);
+ else
+ draw_Picture(bOrigin, strcat(me.src, "_n", me.srcSuffix), bSize, me.color, 1);
+ }
+ }
+ if(me.src2)
+ {
+ bOrigin = me.keepspaceLeft * eX;
+ bSize = eY + eX * (1 - me.keepspaceLeft);
+
+ bOrigin += bSize * (0.5 - 0.5 * me.src2scale);
+ bSize = bSize * me.src2scale;
+
+ draw_Picture(bOrigin, me.src2, bSize, me.color2, me.alpha2);
+ }
+
+ draw_alpha = save;
+
+ drawLabel(me);
+
+ if(me.clickTime > 0 && me.clickTime <= frametime)
+ {
+ // keyboard click timer expired? Fire the event then.
+ if not(me.disabled)
+ me.onClick(me, me.onClickEntity);
+ }
+ me.clickTime -= frametime;
+}
+#endif
Added: trunk/menu/item/checkbox.c
===================================================================
--- trunk/menu/item/checkbox.c (rev 0)
+++ trunk/menu/item/checkbox.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,48 @@
+#ifdef INTERFACE
+void CheckBox_Click(entity me, entity other);
+CLASS(CheckBox) EXTENDS(Button)
+ METHOD(CheckBox, configureCheckBox, void(entity, string, float, string))
+ METHOD(CheckBox, draw, void(entity))
+ METHOD(CheckBox, toString, string(entity))
+ METHOD(CheckBox, setChecked, void(entity, float))
+ ATTRIB(CheckBox, useDownAsChecked, float, 0)
+ ATTRIB(CheckBox, checked, float, 0)
+ ATTRIB(CheckBox, onClick, void(entity, entity), CheckBox_Click)
+ ATTRIB(CheckBox, srcMulti, float, 0)
+ ATTRIB(CheckBox, disabled, float, 0)
+ENDCLASS(CheckBox)
+#endif
+
+#ifdef IMPLEMENTATION
+void setCheckedCheckBox(entity me, float val)
+{
+ me.checked = val;
+}
+void CheckBox_Click(entity me, entity other)
+{
+ me.setChecked(me, !me.checked);
+}
+string toStringCheckBox(entity me)
+{
+ return strcat(toStringLabel(me), ", ", me.checked ? "checked" : "unchecked");
+}
+void configureCheckBoxCheckBox(entity me, string txt, float sz, string gfx)
+{
+ me.configureButton(me, txt, sz, gfx);
+ me.align = 0;
+}
+void drawCheckBox(entity me)
+{
+ float s;
+ s = me.pressed;
+ if(me.useDownAsChecked)
+ {
+ me.srcSuffix = string_null;
+ me.forcePressed = me.checked;
+ }
+ else
+ me.srcSuffix = (me.checked ? "1" : "0");
+ drawButton(me);
+ me.pressed = s;
+}
+#endif
Added: trunk/menu/item/container.c
===================================================================
--- trunk/menu/item/container.c (rev 0)
+++ trunk/menu/item/container.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,342 @@
+#ifdef INTERFACE
+CLASS(Container) EXTENDS(Item)
+ METHOD(Container, draw, void(entity))
+ METHOD(Container, keyUp, float(entity, float, float, float))
+ METHOD(Container, keyDown, float(entity, float, float, float))
+ METHOD(Container, mouseMove, float(entity, vector))
+ METHOD(Container, mousePress, float(entity, vector))
+ METHOD(Container, mouseDrag, float(entity, vector))
+ METHOD(Container, mouseRelease, float(entity, vector))
+ METHOD(Container, focusLeave, void(entity))
+ METHOD(Container, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(Container, resizeNotifyLie, void(entity, vector, vector, vector, vector, .vector, .vector))
+ METHOD(Container, addItem, void(entity, entity, vector, vector, float))
+ METHOD(Container, addItemCentered, void(entity, entity, vector, float))
+ METHOD(Container, moveItemAfter, void(entity, entity, entity))
+ METHOD(Container, removeItem, void(entity, entity))
+ METHOD(Container, setFocus, void(entity, entity))
+ METHOD(Container, setAlphaOf, void(entity, entity, float))
+ METHOD(Container, itemFromPoint, entity(entity, vector))
+ METHOD(Container, showNotify, void(entity))
+ METHOD(Container, hideNotify, void(entity))
+ ATTRIB(Container, focusable, float, 0)
+ ATTRIB(Container, firstChild, entity, NULL)
+ ATTRIB(Container, lastChild, entity, NULL)
+ ATTRIB(Container, focusedChild, entity, NULL)
+ ATTRIB(Container, shown, float, 0)
+ENDCLASS(Container)
+.entity nextSibling;
+.entity prevSibling;
+.float resized;
+.vector Container_origin;
+.vector Container_size;
+.float Container_alpha;
+#endif
+
+#ifdef IMPLEMENTATION
+void showNotifyContainer(entity me)
+{
+ entity e;
+ if(me.shown)
+ return;
+ me.shown = 1;
+ for(e = me.firstChild; e; e = e.nextSibling)
+ if(e.Container_alpha > 0)
+ e.showNotify(e);
+}
+
+void hideNotifyContainer(entity me)
+{
+ entity e;
+ if not(me.shown)
+ return;
+ me.shown = 0;
+ for(e = me.firstChild; e; e = e.nextSibling)
+ if(e.Container_alpha > 0)
+ e.hideNotify(e);
+}
+
+void setAlphaOfContainer(entity me, entity other, float theAlpha)
+{
+ if(theAlpha <= 0)
+ {
+ if(other.Container_alpha > 0)
+ other.hideNotify(other);
+ }
+ else // value > 0
+ {
+ if(other.Container_alpha <= 0)
+ other.showNotify(other);
+ }
+ other.Container_alpha = theAlpha;
+}
+
+void resizeNotifyLieContainer(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize, .vector originField, .vector sizeField)
+{
+ entity e;
+ vector o, s;
+ float d;
+ for(e = me.firstChild; e; e = e.nextSibling)
+ {
+ o = e.originField;
+ s = e.sizeField;
+ e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
+ }
+ do
+ {
+ d = 0;
+ for(e = me.firstChild; e; e = e.nextSibling)
+ if(e.resized)
+ {
+ e.resized = 0;
+ d = 1;
+ o = e.originField;
+ s = e.sizeField;
+ e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
+ }
+ }
+ while(d);
+ resizeNotifyItem(me, relOrigin, relSize, absOrigin, absSize);
+}
+
+void resizeNotifyContainer(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Container_origin, Container_size);
+}
+
+entity itemFromPointContainer(entity me, vector pos)
+{
+ entity e;
+ vector o, s;
+ for(e = me.lastChild; e; e = e.prevSibling)
+ {
+ o = e.Container_origin;
+ s = e.Container_size;
+ if(pos_x < o_x) continue;
+ if(pos_y < o_y) continue;
+ if(pos_x >= o_x + s_x) continue;
+ if(pos_y >= o_y + s_y) continue;
+ return e;
+ }
+ return NULL;
+}
+
+void drawContainer(entity me)
+{
+ vector oldshift;
+ vector oldscale;
+ float oldalpha;
+ entity e;
+
+ oldshift = draw_shift;
+ oldscale = draw_scale;
+ oldalpha = draw_alpha;
+ me.focusable = 0;
+ for(e = me.firstChild; e; e = e.nextSibling)
+ {
+ if(e.focusable)
+ me.focusable += 1;
+ if(e.Container_alpha < 0.003) // can't change color values anyway
+ continue;
+ draw_shift = boxToGlobal(e.Container_origin, oldshift, oldscale);
+ draw_scale = boxToGlobalSize(e.Container_size, oldscale);
+ draw_alpha *= e.Container_alpha;
+ e.draw(e);
+ draw_shift = oldshift;
+ draw_scale = oldscale;
+ draw_alpha = oldalpha;
+ }
+};
+
+void focusLeaveContainer(entity me)
+{
+ me.setFocus(me, NULL);
+}
+
+float keyUpContainer(entity me, float scan, float ascii, float shift)
+{
+ entity f;
+ f = me.focusedChild;
+ if(f)
+ return f.keyUp(f, scan, ascii, shift);
+ return 0;
+}
+
+float keyDownContainer(entity me, float scan, float ascii, float shift)
+{
+ entity f;
+ f = me.focusedChild;
+ if(f)
+ return f.keyDown(f, scan, ascii, shift);
+ return 0;
+}
+
+float mouseMoveContainer(entity me, vector pos)
+{
+ entity f;
+ f = me.focusedChild;
+ if(f)
+ return f.mouseMove(f, globalToBox(pos, f.Container_origin, f.Container_size));
+ return 0;
+}
+float mousePressContainer(entity me, vector pos)
+{
+ entity f;
+ f = me.focusedChild;
+ if(f)
+ return f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
+ return 0;
+}
+float mouseDragContainer(entity me, vector pos)
+{
+ entity f;
+ f = me.focusedChild;
+ if(f)
+ return f.mouseDrag(f, globalToBox(pos, f.Container_origin, f.Container_size));
+ return 0;
+}
+float mouseReleaseContainer(entity me, vector pos)
+{
+ entity f;
+ f = me.focusedChild;
+ if(f)
+ return f.mouseRelease(f, globalToBox(pos, f.Container_origin, f.Container_size));
+ return 0;
+}
+
+void addItemCenteredContainer(entity me, entity other, vector theSize, float theAlpha)
+{
+ me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha);
+}
+
+void addItemContainer(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
+{
+ if(other.parent)
+ error("Can't add already added item!");
+
+ if(other.focusable)
+ me.focusable += 1;
+
+ if(theSize_x > 1)
+ {
+ theOrigin_x -= 0.5 * (theSize_x - 1);
+ theSize_x = 1;
+ }
+ if(theSize_y > 1)
+ {
+ theOrigin_y -= 0.5 * (theSize_y - 1);
+ theSize_y = 1;
+ }
+ theOrigin_x = bound(0, theOrigin_x, 1 - theSize_x);
+ theOrigin_y = bound(0, theOrigin_y, 1 - theSize_y);
+
+ other.parent = me;
+ other.Container_origin = theOrigin;
+ other.Container_size = theSize;
+ me.setAlphaOf(me, other, theAlpha);
+
+ entity f, l;
+ f = me.firstChild;
+ l = me.lastChild;
+
+ if(l)
+ l.nextSibling = other;
+ else
+ me.firstChild = other;
+
+ other.prevSibling = l;
+ other.nextSibling = NULL;
+ me.lastChild = other;
+
+ draw_NeedResizeNotify = 1;
+}
+
+void removeItemContainer(entity me, entity other)
+{
+ if(other.parent != me)
+ error("Can't remove from wrong container!");
+
+ if(other.focusable)
+ me.focusable -= 1;
+
+ other.parent = NULL;
+
+ entity n, p, f, l;
+ f = me.firstChild;
+ l = me.lastChild;
+ n = other.nextSibling;
+ p = other.prevSibling;
+
+ if(p)
+ p.nextSibling = n;
+ else
+ me.firstChild = n;
+
+ if(n)
+ n.prevSibling = p;
+ else
+ me.lastChild = p;
+}
+
+void setFocusContainer(entity me, entity other)
+{
+ if(other)
+ if not(me.focused)
+ error("Trying to set focus in a non-focused control!");
+ if(me.focusedChild == other)
+ return;
+ //print(etos(me), ": focus changes from ", etos(me.focusedChild), " to ", etos(other), "\n");
+ if(me.focusedChild)
+ {
+ me.focusedChild.focused = 0;
+ me.focusedChild.focusLeave(me.focusedChild);
+ }
+ if(other)
+ {
+ other.focused = 1;
+ other.focusEnter(other);
+ }
+ me.focusedChild = other;
+}
+
+void moveItemAfterContainer(entity me, entity other, entity dest)
+{
+ // first: remove other from the chain
+ entity n, p, f, l;
+
+ if(other.parent != me)
+ error("Can't move in wrong container!");
+
+ f = me.firstChild;
+ l = me.lastChild;
+ n = other.nextSibling;
+ p = other.prevSibling;
+
+ if(p)
+ p.nextSibling = n;
+ else
+ me.firstChild = n;
+
+ if(n)
+ n.prevSibling = p;
+ else
+ me.lastChild = p;
+
+ // now other got removed. Insert it behind dest now.
+ other.prevSibling = dest;
+ if(dest)
+ other.nextSibling = dest.nextSibling;
+ else
+ other.nextSibling = me.firstChild;
+
+ if(dest)
+ dest.nextSibling = other;
+ else
+ me.firstChild = other;
+
+ if(other.nextSibling)
+ other.nextSibling.prevSibling = other;
+ else
+ me.lastChild = other;
+}
+#endif
Added: trunk/menu/item/dialog.c
===================================================================
--- trunk/menu/item/dialog.c (rev 0)
+++ trunk/menu/item/dialog.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,191 @@
+// Note: this class is called Dialog, but it can also handle a tab under the following conditions:
+// - isTabRoot is 0
+// - backgroundImage is the tab's background
+// - closable is 0
+// - rootDialog is 0
+// - title is ""
+// - marginTop is
+// - intendedHeight ends up to be the tab's actual height, or at least close
+// - titleFontSize is 0
+// - marginTop cancels out as much of titleHeight as needed (that is, it should be actualMarginTop - titleHeight)
+// To ensure the latter, you best create all tabs FIRST and insert the tabbed
+// control to your dialog THEN - with the right height
+//
+// a subclass may help with using this as a tab
+
+#ifdef INTERFACE
+CLASS(Dialog) EXTENDS(InputContainer)
+ METHOD(Dialog, configureDialog, void(entity)) // no runtime configuration, all parameters are given in the code!
+ METHOD(Dialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
+ METHOD(Dialog, keyDown, float(entity, float, float, float))
+ METHOD(Dialog, close, void(entity))
+ METHOD(Dialog, addItemSimple, void(entity, float, float, float, float, entity, vector))
+
+ METHOD(Dialog, TD, void(entity, float, float, entity))
+ METHOD(Dialog, TDNoMargin, void(entity, float, float, entity, vector))
+ METHOD(Dialog, TDempty, void(entity, float))
+ METHOD(Dialog, setFirstColumn, void(entity, float))
+ METHOD(Dialog, TR, void(entity))
+ METHOD(Dialog, gotoRC, void(entity, float, float))
+
+ ATTRIB(Dialog, isTabRoot, float, 1)
+ ATTRIB(Dialog, closeButton, entity, NULL)
+ ATTRIB(Dialog, intendedHeight, float, 0)
+ ATTRIB(Dialog, itemOrigin, vector, '0 0 0')
+ ATTRIB(Dialog, itemSize, vector, '0 0 0')
+ ATTRIB(Dialog, itemSpacing, vector, '0 0 0')
+ ATTRIB(Dialog, currentRow, float, 0)
+ ATTRIB(Dialog, currentColumn, float, 0)
+ ATTRIB(Dialog, firstColumn, float, 0)
+
+ // to be customized
+ ATTRIB(Dialog, closable, float, 1)
+ ATTRIB(Dialog, title, string, "Form1") // ;)
+ ATTRIB(Dialog, color, vector, '1 0.5 1')
+ ATTRIB(Dialog, intendedWidth, float, 0)
+ ATTRIB(Dialog, rows, float, 3)
+ ATTRIB(Dialog, columns, float, 2)
+
+ ATTRIB(Dialog, marginTop, float, 0) // pixels
+ ATTRIB(Dialog, marginBottom, float, 0) // pixels
+ ATTRIB(Dialog, marginLeft, float, 0) // pixels
+ ATTRIB(Dialog, marginRight, float, 0) // pixels
+ ATTRIB(Dialog, columnSpacing, float, 0) // pixels
+ ATTRIB(Dialog, rowSpacing, float, 0) // pixels
+ ATTRIB(Dialog, rowHeight, float, 0) // pixels
+ ATTRIB(Dialog, titleHeight, float, 0) // pixels
+ ATTRIB(Dialog, titleFontSize, float, 0) // pixels; if 0, title causes no margin
+ ATTRIB(Dialog, zoomedOutTitleBarPosition, float, 0)
+ ATTRIB(Dialog, zoomedOutTitleBar, float, 0)
+
+ ATTRIB(Dialog, backgroundImage, string, string_null)
+ ATTRIB(Dialog, closeButtonImage, string, string_null)
+
+ ATTRIB(Dialog, frame, entity, NULL)
+ENDCLASS(Dialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void Dialog_Close(entity button, entity me)
+{
+ me.close(me);
+}
+
+void fillDialog(entity me)
+{
+}
+
+void addItemSimpleDialog(entity me, float row, float col, float rowspan, float colspan, entity e, vector v)
+{
+ //print(vtos(me.itemSpacing), " ", vtos(me.itemSize), "\n");
+ vector o, s;
+ o = me.itemOrigin + eX * ( col * me.itemSpacing_x) + eY * ( row * me.itemSpacing_y);
+ s = me.itemSize + eX * ((colspan - 1) * me.itemSpacing_x) + eY * ((rowspan - 1) * me.itemSpacing_y);
+ o_x -= 0.5 * (me.itemSpacing_x - me.itemSize_x) * v_x;
+ s_x += (me.itemSpacing_x - me.itemSize_x) * v_x;
+ o_y -= 0.5 * (me.itemSpacing_y - me.itemSize_y) * v_y;
+ s_y += (me.itemSpacing_y - me.itemSize_y) * v_y;
+ me.addItem(me, e, o, s, 1);
+}
+
+void gotoRCDialog(entity me, float row, float col)
+{
+ me.currentRow = row;
+ me.currentColumn = col;
+}
+
+void TRDialog(entity me)
+{
+ me.currentRow += 1;
+ me.currentColumn = me.firstColumn;
+}
+
+void TDDialog(entity me, float rowspan, float colspan, entity e)
+{
+ me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, '0 0 0');
+ me.currentColumn += colspan;
+}
+
+void TDNoMarginDialog(entity me, float rowspan, float colspan, entity e, vector v)
+{
+ me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, v);
+ me.currentColumn += colspan;
+}
+
+void setFirstColumnDialog(entity me, float col)
+{
+ me.firstColumn = col;
+}
+
+void TDemptyDialog(entity me, float colspan)
+{
+ me.currentColumn += colspan;
+}
+
+void configureDialogDialog(entity me)
+{
+ entity closebutton;
+ float absWidth, absHeight;
+
+ me.frame = spawnBorderImage();
+ me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.titleHeight);
+ me.frame.zoomedOutTitleBarPosition = me.zoomedOutTitleBarPosition;
+ me.frame.zoomedOutTitleBar = me.zoomedOutTitleBar;
+ me.frame.alpha = me.alpha;
+ me.addItem(me, me.frame, '0 0 0', '1 1 0', 1);
+
+ if not(me.titleFontSize)
+ me.titleHeight = 0; // no title bar
+
+ absWidth = me.intendedWidth * conwidth;
+ absHeight = me.titleHeight + me.marginTop + me.rows * me.rowHeight + (me.rows - 1) * me.rowSpacing + me.marginBottom;
+ me.itemOrigin = eX * (me.marginLeft / absWidth)
+ + eY * ((me.titleHeight + me.marginTop) / absHeight);
+ me.itemSize = eX * ((1 - (me.marginLeft + me.marginRight + me.columnSpacing * (me.columns - 1)) / absWidth) / me.columns)
+ + eY * (me.rowHeight / absHeight);
+ me.itemSpacing = me.itemSize
+ + eX * (me.columnSpacing / absWidth)
+ + eY * (me.rowSpacing / absHeight);
+ me.intendedHeight = absHeight / conheight;
+ me.currentRow = -1;
+ me.currentColumn = -1;
+
+ me.fill(me);
+
+ if(me.closable)
+ {
+ closebutton = me.closeButton = spawnButton();
+ closebutton.configureButton(closebutton, "Close", 0, me.closeButtonImage);
+ closebutton.onClick = Dialog_Close; closebutton.onClickEntity = me;
+ closebutton.srcMulti = 0;
+ me.addItem(me, closebutton, '0 0 0', '1 1 0', 1); // put it as LAST
+ }
+
+ me.frame.closeButton = closebutton;
+}
+
+void closeDialog(entity me)
+{
+ if(me.parent.instanceOfNexposee)
+ {
+ ExposeeCloseButton_Click(me, me.parent);
+ }
+ else if(me.parent.instanceOfModalController)
+ {
+ DialogCloseButton_Click(me, me);
+ }
+}
+
+float keyDownDialog(entity me, float key, float ascii, float shift)
+{
+ if(me.closable)
+ {
+ if(key == K_ESCAPE)
+ {
+ me.close(me);
+ return 1;
+ }
+ }
+ return keyDownInputContainer(me, key, ascii, shift);
+}
+#endif
Added: trunk/menu/item/gecko.c
===================================================================
--- trunk/menu/item/gecko.c (rev 0)
+++ trunk/menu/item/gecko.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,97 @@
+// Andreas Kirsch Gecko item (to test it)
+#ifdef INTERFACE
+CLASS(Gecko) EXTENDS(Item)
+ METHOD( Gecko, configureBrowser, void( entity, string ) )
+ METHOD( Gecko, draw, void(entity))
+ METHOD( Gecko, keyDown, float(entity, float, float, float))
+ METHOD( Gecko, keyUp, float(entity, float, float, float))
+ METHOD( Gecko, mouseMove, float(entity, vector))
+ METHOD( Gecko, mouseDrag, float(entity, vector))
+ METHOD( Gecko, resizeNotify, void(entity, vector, vector, vector, vector))
+ ATTRIB( Gecko, texturePath, string, string_null )
+ ATTRIB( Gecko, textureExtent, vector, '0 0 0')
+ENDCLASS(Item)
+#endif
+
+#ifdef IMPLEMENTATION
+// define static members
+float _gecko_instanceNumber;
+
+void configureBrowserGecko( entity me, string URI ) {
+ me.focusable = 1;
+
+ //create a new gecko object if needed
+ if( !me.texturePath ) {
+ me.texturePath = strzone( strcat( "_dynamic/gecko/menu/", ftos( _gecko_instanceNumber ) ) );
+ _gecko_instanceNumber+=1;
+ // TODO: add error checks
+ gecko_create( me.texturePath );
+ }
+ gecko_navigate( me.texturePath, URI );
+}
+
+void drawGecko(entity me)
+{
+ vector drawSize;
+
+ if( me.texturePath ) {
+ /* The gecko browser is actually only drawn to a part of the
+ texture. Correct scaling so that part fills up the whole
+ item area. */
+ drawSize_x = 1.0 / me.textureExtent_x;
+ drawSize_y = 1.0 / me.textureExtent_y;
+ draw_Picture( '0 0 0', strcat( "/", me.texturePath ),
+ drawSize, '1 1 1', 1.0 );
+ } else {
+ local vector fontsize;
+ fontsize_x = fontsize_y = 1.0 / 30.0;
+ fontsize_z = 0.0;
+ draw_Text( '0 0 0', "Browser not initialized!", fontsize, '1 1 1', 1.0, 0 );
+ }
+}
+
+float keyDownGecko(entity me, float scan, float ascii, float shift)
+{
+ if( scan == K_ESCAPE ) {
+ return 0;
+ }
+ if (ascii >= 32)
+ return gecko_keyevent( me.texturePath, ascii, GECKO_BUTTON_DOWN );
+ else
+ return gecko_keyevent( me.texturePath, scan, GECKO_BUTTON_DOWN );
+}
+
+float keyUpGecko(entity me, float scan, float ascii, float shift)
+{
+ if (ascii >= 32)
+ return gecko_keyevent( me.texturePath, ascii, GECKO_BUTTON_UP );
+ else
+ return gecko_keyevent( me.texturePath, scan, GECKO_BUTTON_UP );
+}
+
+float mouseMoveGecko(entity me, vector pos)
+{
+ gecko_mousemove( me.texturePath, pos_x, pos_y );
+ return 1;
+}
+
+float mouseDragGecko(entity me, vector pos)
+{
+ gecko_mousemove( me.texturePath, pos_x, pos_y );
+ return 1;
+}
+
+void resizeNotifyGecko(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ me.origin = absOrigin;
+ me.size = absSize;
+ gecko_resize( me.texturePath, absSize_x, absSize_y );
+ me.textureExtent = gecko_get_texture_extent( me.texturePath );
+}
+
+string toStringGecko(entity me)
+{
+ return me.texturePath;
+}
+
+#endif
Added: trunk/menu/item/image.c
===================================================================
--- trunk/menu/item/image.c (rev 0)
+++ trunk/menu/item/image.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,50 @@
+#ifdef INTERFACE
+CLASS(Image) EXTENDS(Item)
+ METHOD(Image, configureImage, void(entity, string))
+ METHOD(Image, draw, void(entity))
+ METHOD(Image, toString, string(entity))
+ METHOD(Image, resizeNotify, void(entity, vector, vector, vector, vector))
+ ATTRIB(Image, src, string, string_null)
+ ATTRIB(Image, color, vector, '1 1 1')
+ ATTRIB(Image, forcedAspect, float, 0)
+ ATTRIB(Image, imgOrigin, vector, '0 0 0')
+ ATTRIB(Image, imgSize, vector, '0 0 0')
+ENDCLASS(Image)
+#endif
+
+#ifdef IMPLEMENTATION
+string toStringImage(entity me)
+{
+ return me.src;
+}
+void configureImageImage(entity me, string path)
+{
+ me.src = path;
+}
+void drawImage(entity me)
+{
+ draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
+}
+void resizeNotifyImage(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ if(me.forcedAspect == 0)
+ {
+ me.imgOrigin = '0 0 0';
+ me.imgSize = '1 1 0';
+ }
+ else
+ {
+ if(absSize_x > me.forcedAspect * absSize_y)
+ {
+ // x too large, so center x-wise
+ me.imgSize = eY + eX * (absSize_y * me.forcedAspect / absSize_x);
+ }
+ else
+ {
+ // y too large, so center y-wise
+ me.imgSize = eX + eY * (absSize_x / (me.forcedAspect * absSize_y));
+ }
+ me.imgOrigin = '0.5 0.5 0' - 0.5 * me.imgSize;
+ }
+}
+#endif
Added: trunk/menu/item/inputbox.c
===================================================================
--- trunk/menu/item/inputbox.c (rev 0)
+++ trunk/menu/item/inputbox.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,232 @@
+#ifdef INTERFACE
+CLASS(InputBox) EXTENDS(Label)
+ METHOD(InputBox, configureInputBox, void(entity, string, float, float, string))
+ METHOD(InputBox, draw, void(entity))
+ METHOD(InputBox, setText, void(entity, string))
+ METHOD(InputBox, enterText, void(entity, string))
+ METHOD(InputBox, keyDown, float(entity, float, float, float))
+ METHOD(InputBox, mouseRelease, float(entity, vector))
+ METHOD(InputBox, mousePress, float(entity, vector))
+ METHOD(InputBox, mouseDrag, float(entity, vector))
+ METHOD(InputBox, showNotify, void(entity))
+
+ ATTRIB(InputBox, src, string, string_null)
+
+ ATTRIB(InputBox, cursorPos, float, 0) // characters
+ ATTRIB(InputBox, scrollPos, float, 0) // widths
+
+ ATTRIB(InputBox, focusable, float, 1)
+ ATTRIB(InputBox, disabled, float, 0)
+ ATTRIB(InputBox, lastChangeTime, float, 0)
+ ATTRIB(InputBox, dragScrollTimer, float, 0)
+ ATTRIB(InputBox, dragScrollPos, vector, '0 0 0')
+ ATTRIB(InputBox, pressed, float, 0)
+ ATTRIB(InputBox, editColorCodes, float, 1)
+ ATTRIB(InputBox, forbiddenCharacters, string, "")
+ ATTRIB(InputBox, color, vector, '1 1 1')
+ ATTRIB(InputBox, colorF, vector, '1 1 1')
+ENDCLASS(InputBox)
+void InputBox_Clear_Click(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+void configureInputBoxInputBox(entity me, string theText, float theCursorPos, float theFontSize, string gfx)
+{
+ configureLabelLabel(me, theText, theFontSize, 0.0);
+ me.src = gfx;
+ me.cursorPos = theCursorPos;
+}
+
+void setTextInputBox(entity me, string txt)
+{
+ if(me.text)
+ strunzone(me.text);
+ setTextLabel(me, strzone(txt));
+}
+
+void InputBox_Clear_Click(entity btn, entity me)
+{
+ me.setText(me, "");
+}
+
+float mouseDragInputBox(entity me, vector pos)
+{
+ float p;
+ me.dragScrollPos = pos;
+ p = me.scrollPos + pos_x - me.keepspaceLeft;
+ me.cursorPos = draw_TextLengthUpToWidth(me.text, p / me.realFontSize_x, 0);
+ me.lastChangeTime = time;
+ return 1;
+}
+
+float mousePressInputBox(entity me, vector pos)
+{
+ me.dragScrollTimer = time;
+ me.pressed = 1;
+ return mouseDragInputBox(me, pos);
+}
+
+float mouseReleaseInputBox(entity me, vector pos)
+{
+ me.pressed = 0;
+ return mouseDragInputBox(me, pos);
+}
+
+void enterTextInputBox(entity me, string ch)
+{
+ float i;
+ for(i = 0; i < strlen(ch); ++i)
+ if(strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1)
+ return;
+ me.setText(me, strcat(substring(me.text, 0, me.cursorPos), ch, substring(me.text, me.cursorPos, strlen(me.text) - me.cursorPos)));
+ me.cursorPos += strlen(ch);
+}
+
+float keyDownInputBox(entity me, float key, float ascii, float shift)
+{
+ me.lastChangeTime = time;
+ me.dragScrollTimer = time;
+ if(ascii >= 32 && ascii != 127)
+ {
+ me.enterText(me, chr(ascii));
+ return 1;
+ }
+ switch(key)
+ {
+ case K_LEFTARROW:
+ me.cursorPos -= 1;
+ return 1;
+ case K_RIGHTARROW:
+ me.cursorPos += 1;
+ return 1;
+ case K_HOME:
+ me.cursorPos = 0;
+ return 1;
+ case K_END:
+ me.cursorPos = strlen(me.text);
+ return 1;
+ case K_BACKSPACE:
+ if(me.cursorPos > 0)
+ {
+ me.cursorPos -= 1;
+ me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
+ }
+ return 1;
+ case K_DEL:
+ if(shift & S_CTRL)
+ me.setText(me, "");
+ else
+ me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
+ return 1;
+ }
+ return 0;
+}
+
+void drawInputBox(entity me)
+{
+#define CURSOR "_"
+ float cursorPosInWidths, totalSizeInWidths;
+
+ if(me.pressed)
+ me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
+
+ me.focusable = !me.disabled;
+ if(me.disabled)
+ draw_alpha *= me.disabledAlpha;
+
+ if(me.src)
+ {
+ if(me.focused && !me.disabled)
+ draw_ButtonPicture('0 0 0', strcat(me.src, "_f"), '1 1 0', me.colorF, 1);
+ else
+ draw_ButtonPicture('0 0 0', strcat(me.src, "_n"), '1 1 0', me.color, 1);
+ }
+
+ me.cursorPos = bound(0, me.cursorPos, strlen(me.text));
+ cursorPosInWidths = draw_TextWidth(substring(me.text, 0, me.cursorPos), 0) * me.realFontSize_x;
+ totalSizeInWidths = draw_TextWidth(strcat(me.text, CURSOR), 0) * me.realFontSize_x;
+
+ if(me.dragScrollTimer < time)
+ {
+ float save;
+ save = me.scrollPos;
+ me.scrollPos = bound(cursorPosInWidths - (0.875 - me.keepspaceLeft - me.keepspaceRight), me.scrollPos, cursorPosInWidths - 0.125);
+ if(me.scrollPos != save)
+ me.dragScrollTimer = time + 0.2;
+ }
+ me.scrollPos = min(me.scrollPos, totalSizeInWidths - (1 - me.keepspaceRight - me.keepspaceLeft));
+ me.scrollPos = max(0, me.scrollPos);
+
+ draw_SetClipRect(eX * me.keepspaceLeft, eX * (1 - me.keepspaceLeft - me.keepspaceRight) + eY);
+ if(me.editColorCodes)
+ {
+ string ch, ch2;
+ float i;
+ vector theColor;
+ float theAlpha;
+ vector p;
+ float brightness;
+ brightness = cvar("r_textbrightness");
+ p = me.realOrigin - eX * me.scrollPos;
+ theColor = '1 1 1';
+ theAlpha = 1;
+ for(i = 0; i < strlen(me.text); ++i)
+ {
+ ch = substring(me.text, i, 1);
+ if(ch == "^")
+ {
+ float w;
+ ch2 = substring(me.text, i+1, 1);
+ w = draw_TextWidth(strcat(ch, ch2), 0) * me.realFontSize_x;
+ if(ch2 == "^")
+ {
+ draw_Fill(p, eX * w + eY * me.realFontSize_y, '0 0 1', 0.5);
+ draw_Text(p + eX * 0.25 * w, "^", me.realFontSize, theColor, theAlpha, 0);
+ }
+ else if(ch2 == "0" || stof(ch2)) // digit?
+ {
+ switch(stof(ch2))
+ {
+ case 0: theColor = '0 0 0'; theAlpha = 1; break;
+ case 1: theColor = '1 0 0'; theAlpha = 1; break;
+ case 2: theColor = '0 1 0'; theAlpha = 1; break;
+ case 3: theColor = '1 1 0'; theAlpha = 1; break;
+ case 4: theColor = '0 0 1'; theAlpha = 1; break;
+ case 5: theColor = '0 1 1'; theAlpha = 1; break;
+ case 6: theColor = '1 0 1'; theAlpha = 1; break;
+ case 7: theColor = '1 1 1'; theAlpha = 1; break;
+ case 8: theColor = '1 1 1'; theAlpha = 0.5; break;
+ case 9: theColor = '0.5 0.5 0.5'; theAlpha = 1; break;
+ }
+ theColor = theColor * (1 - brightness) + brightness * '1 1 1';
+ draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
+ draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
+ draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
+ }
+ else
+ {
+ draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 0 0', 0.5);
+ draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
+ draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
+ }
+ p += w * eX;
+ ++i;
+ continue;
+ }
+ draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0); p += eX * draw_TextWidth(ch, 0) * me.realFontSize_x;
+ }
+ }
+ else
+ draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
+ // skipping drawLabel(me);
+ if(!me.focused || (time - me.lastChangeTime) < floor(time - me.lastChangeTime) + 0.5)
+ draw_Text(me.realOrigin + eX * (cursorPosInWidths - me.scrollPos), CURSOR, me.realFontSize, '1 1 1', 1, 0);
+
+ draw_ClearClip();
+}
+
+void showNotifyInputBox(entity me)
+{
+ me.focusable = !me.disabled;
+}
+#endif
Added: trunk/menu/item/inputcontainer.c
===================================================================
--- trunk/menu/item/inputcontainer.c (rev 0)
+++ trunk/menu/item/inputcontainer.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,165 @@
+#ifdef INTERFACE
+CLASS(InputContainer) EXTENDS(Container)
+ METHOD(InputContainer, keyDown, float(entity, float, float, float))
+ METHOD(InputContainer, mouseMove, float(entity, vector))
+ METHOD(InputContainer, mousePress, float(entity, vector))
+ METHOD(InputContainer, mouseRelease, float(entity, vector))
+ METHOD(InputContainer, mouseDrag, float(entity, vector))
+ METHOD(InputContainer, focusLeave, void(entity))
+ METHOD(InputContainer, resizeNotify, void(entity, vector, vector, vector, vector))
+
+ METHOD(InputContainer, _changeFocusXY, float(entity, vector))
+ ATTRIB(InputContainer, mouseFocusedChild, entity, NULL)
+ ATTRIB(InputContainer, isTabRoot, float, 0)
+ENDCLASS(InputContainer)
+#endif
+
+#ifdef IMPLEMENTATION
+void resizeNotifyInputContainer(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ resizeNotifyContainer(me, relOrigin, relSize, absOrigin, absSize);
+ /*
+ if(me.parent.instanceOfInputContainer)
+ me.isTabRoot = 0;
+ else
+ me.isTabRoot = 1;
+ */
+}
+
+void focusLeaveInputContainer(entity me)
+{
+ focusLeaveContainer(me);
+ me.mouseFocusedChild = NULL;
+}
+
+float keyDownInputContainer(entity me, float scan, float ascii, float shift)
+{
+ entity f, ff;
+ if(keyDownContainer(me, scan, ascii, shift))
+ return 1;
+ if(scan == K_ESCAPE)
+ {
+ f = me.focusedChild;
+ if(f)
+ {
+ me.setFocus(me, NULL);
+ return 1;
+ }
+ return 0;
+ }
+ if(scan == K_TAB)
+ {
+ f = me.focusedChild;
+ if(shift & S_SHIFT)
+ {
+ if(f)
+ {
+ for(ff = f.prevSibling; ff; ff = ff.prevSibling)
+ {
+ if not(ff.focusable)
+ continue;
+ me.setFocus(me, ff);
+ return 1;
+ }
+ }
+ if(!f || me.isTabRoot)
+ {
+ for(ff = me.lastChild; ff; ff = ff.prevSibling)
+ {
+ if not(ff.focusable)
+ continue;
+ me.setFocus(me, ff);
+ return 1;
+ }
+ return 0; // AIIIIEEEEE!
+ }
+ }
+ else
+ {
+ if(f)
+ {
+ for(ff = f.nextSibling; ff; ff = ff.nextSibling)
+ {
+ if not(ff.focusable)
+ continue;
+ me.setFocus(me, ff);
+ return 1;
+ }
+ }
+ if(!f || me.isTabRoot)
+ {
+ for(ff = me.firstChild; ff; ff = ff.nextSibling)
+ {
+ if not(ff.focusable)
+ continue;
+ me.setFocus(me, ff);
+ return 1;
+ }
+ return 0; // AIIIIEEEEE!
+ }
+ }
+ }
+ return 0;
+}
+
+float _changeFocusXYInputContainer(entity me, vector pos)
+{
+ entity e, ne;
+ e = me.mouseFocusedChild;
+ ne = me.itemFromPoint(me, pos);
+ if(ne)
+ if not(ne.focusable)
+ ne = NULL;
+ me.mouseFocusedChild = ne;
+ if(ne)
+ if(ne != e)
+ {
+ me.setFocus(me, ne);
+ if(ne.instanceOfInputContainer)
+ {
+ ne.focusedChild = NULL;
+ ne._changeFocusXY(e, globalToBox(pos, ne.Container_origin, ne.Container_size));
+ }
+ }
+ return (ne != NULL);
+}
+
+float mouseDragInputContainer(entity me, vector pos)
+{
+ if(mouseDragContainer(me, pos))
+ return 1;
+ if(pos_x >= 0 && pos_y >= 0 && pos_x < 1 && pos_y < 1)
+ return 1;
+ return 0;
+}
+float mouseMoveInputContainer(entity me, vector pos)
+{
+ if(me._changeFocusXY(me, pos))
+ if(mouseMoveContainer(me, pos))
+ return 1;
+ if(pos_x >= 0 && pos_y >= 0 && pos_x < 1 && pos_y < 1)
+ return 1;
+ return 0;
+}
+float mousePressInputContainer(entity me, vector pos)
+{
+ me.mouseFocusedChild = NULL; // force focusing
+ if(me._changeFocusXY(me, pos))
+ if(mousePressContainer(me, pos))
+ return 1;
+ if(pos_x >= 0 && pos_y >= 0 && pos_x < 1 && pos_y < 1)
+ return 1;
+ return 0;
+}
+float mouseReleaseInputContainer(entity me, vector pos)
+{
+ float r;
+ r = mouseReleaseContainer(me, pos);
+ if(me.focused) // am I still eligible for this? (UGLY HACK, but a mouse event could have changed focus away)
+ if(me._changeFocusXY(me, pos))
+ return 1;
+ if(pos_x >= 0 && pos_y >= 0 && pos_x < 1 && pos_y < 1)
+ return 1;
+ return 0;
+}
+#endif
Added: trunk/menu/item/label.c
===================================================================
--- trunk/menu/item/label.c (rev 0)
+++ trunk/menu/item/label.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,71 @@
+#ifdef INTERFACE
+CLASS(Label) EXTENDS(Item)
+ METHOD(Label, configureLabel, void(entity, string, float, float))
+ METHOD(Label, draw, void(entity))
+ METHOD(Label, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(Label, setText, void(entity, string))
+ METHOD(Label, toString, string(entity))
+ ATTRIB(Label, text, string, string_null)
+ ATTRIB(Label, fontSize, float, 8)
+ ATTRIB(Label, align, float, 0.5)
+ ATTRIB(Label, allowCut, float, 0)
+ ATTRIB(Label, keepspaceLeft, float, 0) // for use by subclasses (radiobuttons for example)
+ ATTRIB(Label, keepspaceRight, float, 0)
+ ATTRIB(Label, realFontSize, vector, '0 0 0')
+ ATTRIB(Label, realOrigin, vector, '0 0 0')
+ ATTRIB(Label, alpha, float, 0.7)
+ ATTRIB(Label, colorL, vector, '1 1 1')
+ ATTRIB(Label, disabled, float, 0)
+ ATTRIB(Label, disabledAlpha, float, 0.3)
+ ATTRIB(Label, textEntity, entity, NULL)
+ENDCLASS(Label)
+#endif
+
+#ifdef IMPLEMENTATION
+string toStringLabel(entity me)
+{
+ return me.text;
+}
+void setTextLabel(entity me, string txt)
+{
+ me.text = txt;
+ me.realOrigin_x = me.align * (1 - me.keepspaceLeft - me.keepspaceRight - min(me.realFontSize_x * draw_TextWidth(me.text, 0), (1 - me.keepspaceLeft - me.keepspaceRight))) + me.keepspaceLeft;
+}
+void resizeNotifyLabel(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ // absSize_y is height of label
+ me.realFontSize_y = me.fontSize / absSize_y;
+ me.realFontSize_x = me.fontSize / absSize_x;
+ me.realOrigin_x = me.align * (1 - me.keepspaceLeft - me.keepspaceRight - min(me.realFontSize_x * draw_TextWidth(me.text, 0), (1 - me.keepspaceLeft - me.keepspaceRight))) + me.keepspaceLeft;
+ me.realOrigin_y = 0.5 * (1 - me.realFontSize_y);
+}
+void configureLabelLabel(entity me, string txt, float sz, float algn)
+{
+ me.fontSize = sz;
+ me.align = algn;
+ me.setText(me, txt);
+}
+void drawLabel(entity me)
+{
+ string t;
+ if(me.disabled)
+ draw_alpha *= me.disabledAlpha;
+
+ if(me.textEntity)
+ {
+ t = me.textEntity.toString(me.textEntity);
+ me.realOrigin_x = me.align * (1 - me.keepspaceLeft - me.keepspaceRight - min(me.realFontSize_x * draw_TextWidth(t, 0), (1 - me.keepspaceLeft - me.keepspaceRight))) + me.keepspaceLeft;
+ }
+ else
+ t = me.text;
+
+ if(me.fontSize)
+ if(t)
+ {
+ if(me.allowCut)
+ draw_Text(me.realOrigin, draw_TextShortenToWidth(t, (1 - me.keepspaceLeft - me.keepspaceRight) / me.realFontSize_x, 0), me.realFontSize, me.colorL, me.alpha, 0);
+ else
+ draw_Text(me.realOrigin, t, me.realFontSize, me.colorL, me.alpha, 0);
+ }
+}
+#endif
Added: trunk/menu/item/listbox.c
===================================================================
--- trunk/menu/item/listbox.c (rev 0)
+++ trunk/menu/item/listbox.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,285 @@
+#ifdef INTERFACE
+CLASS(ListBox) EXTENDS(Item)
+ METHOD(ListBox, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(ListBox, configureListBox, void(entity, float, float))
+ METHOD(ListBox, draw, void(entity))
+ METHOD(ListBox, keyDown, float(entity, float, float, float))
+ METHOD(ListBox, mousePress, float(entity, vector))
+ METHOD(ListBox, mouseDrag, float(entity, vector))
+ METHOD(ListBox, mouseRelease, float(entity, vector))
+ ATTRIB(ListBox, focusable, float, 1)
+ ATTRIB(ListBox, selectedItem, float, 0)
+ ATTRIB(ListBox, size, vector, '0 0 0')
+ ATTRIB(ListBox, scrollPos, float, 0) // measured in window heights, fixed when needed
+ ATTRIB(ListBox, previousValue, float, 0)
+ ATTRIB(ListBox, pressed, float, 0) // 0 = normal, 1 = scrollbar dragging, 2 = item dragging, 3 = released
+ ATTRIB(ListBox, pressOffset, float, 0)
+
+ METHOD(ListBox, updateControlTopBottom, void(entity))
+ ATTRIB(ListBox, controlTop, float, 0)
+ ATTRIB(ListBox, controlBottom, float, 0)
+ ATTRIB(ListBox, controlWidth, float, 0)
+ ATTRIB(ListBox, dragScrollTimer, float, 0)
+ ATTRIB(ListBox, dragScrollPos, vector, '0 0 0')
+
+ ATTRIB(ListBox, src, string, string_null) // scrollbar
+ ATTRIB(ListBox, color, vector, '1 1 1')
+ ATTRIB(ListBox, color2, vector, '1 1 1')
+ ATTRIB(ListBox, colorC, vector, '1 1 1')
+ ATTRIB(ListBox, colorF, vector, '1 1 1')
+ ATTRIB(ListBox, tolerance, vector, '0 0 0') // drag tolerance
+ ATTRIB(ListBox, scrollbarWidth, float, 0) // pixels
+ ATTRIB(ListBox, nItems, float, 42)
+ ATTRIB(ListBox, itemHeight, float, 0)
+ METHOD(ListBox, drawListBoxItem, void(entity, float, vector, float)) // item number, width/height, selected
+ METHOD(ListBox, clickListBoxItem, void(entity, float, vector)) // item number, relative clickpos
+ METHOD(ListBox, setSelected, void(entity, float))
+ENDCLASS(ListBox)
+#endif
+
+#ifdef IMPLEMENTATION
+void setSelectedListBox(entity me, float i)
+{
+ me.selectedItem = floor(0.5 + bound(0, i, me.nItems - 1));
+}
+void resizeNotifyListBox(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ me.size = absSize;
+ me.controlWidth = me.scrollbarWidth / absSize_x;
+}
+void configureListBoxListBox(entity me, float theScrollbarWidth, float theItemHeight)
+{
+ me.scrollbarWidth = theScrollbarWidth;
+ me.itemHeight = theItemHeight;
+}
+float keyDownListBox(entity me, float key, float ascii, float shift)
+{
+ me.dragScrollTimer = time;
+ if(key == K_MWHEELUP)
+ {
+ me.scrollPos = max(me.scrollPos - 0.5, 0);
+ me.setSelected(me, min(me.selectedItem, floor((me.scrollPos + 1) / me.itemHeight - 1)));
+ }
+ else if(key == K_MWHEELDOWN)
+ {
+ me.scrollPos = min(me.scrollPos + 0.5, me.nItems * me.itemHeight - 1);
+ me.setSelected(me, max(me.selectedItem, ceil(me.scrollPos / me.itemHeight)));
+ }
+ else if(key == K_PGUP)
+ me.setSelected(me, me.selectedItem - 1 / me.itemHeight);
+ else if(key == K_PGDN)
+ me.setSelected(me, me.selectedItem + 1 / me.itemHeight);
+ else if(key == K_UPARROW)
+ me.setSelected(me, me.selectedItem - 1);
+ else if(key == K_DOWNARROW)
+ me.setSelected(me, me.selectedItem + 1);
+ else if(key == K_HOME)
+ {
+ me.scrollPos = 0;
+ me.setSelected(me, 0);
+ }
+ else if(key == K_END)
+ {
+ me.scrollPos = max(0, me.nItems * me.itemHeight - 1);
+ me.setSelected(me, me.nItems - 1);
+ }
+ else
+ return 0;
+ return 1;
+}
+float mouseDragListBox(entity me, vector pos)
+{
+ float hit;
+ float i;
+ me.updateControlTopBottom(me);
+ me.dragScrollPos = pos;
+ if(me.pressed == 1)
+ {
+ hit = 1;
+ if(pos_x < 1 - me.controlWidth - me.tolerance_y * me.controlWidth) hit = 0;
+ if(pos_y < 0 - me.tolerance_x) hit = 0;
+ if(pos_x >= 1 + me.tolerance_y * me.controlWidth) hit = 0;
+ if(pos_y >= 1 + me.tolerance_x) hit = 0;
+ if(hit)
+ {
+ // calculate new pos to v
+ float delta;
+ delta = (pos_y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.nItems * me.itemHeight - 1);
+ me.scrollPos = me.previousValue + delta;
+ }
+ else
+ me.scrollPos = me.previousValue;
+ me.scrollPos = min(me.scrollPos, me.nItems * me.itemHeight - 1);
+ me.scrollPos = max(me.scrollPos, 0);
+ i = min(me.selectedItem, floor((me.scrollPos + 1) / me.itemHeight - 1));
+ i = max(i, ceil(me.scrollPos / me.itemHeight));
+ me.setSelected(me, i);
+ }
+ else if(me.pressed == 2)
+ {
+ me.setSelected(me, floor((me.scrollPos + pos_y) / me.itemHeight));
+ }
+ return 1;
+}
+float mousePressListBox(entity me, vector pos)
+{
+ if(pos_x < 0) return 0;
+ if(pos_y < 0) return 0;
+ if(pos_x >= 1) return 0;
+ if(pos_y >= 1) return 0;
+ me.dragScrollPos = pos;
+ me.updateControlTopBottom(me);
+ me.dragScrollTimer = time;
+ if(pos_x >= 1 - me.controlWidth)
+ {
+ // if hit, set me.pressed, otherwise scroll by one page
+ if(pos_y < me.controlTop)
+ {
+ // page up
+ me.scrollPos = max(me.scrollPos - 1, 0);
+ me.setSelected(me, min(me.selectedItem, floor((me.scrollPos + 1) / me.itemHeight - 1)));
+ }
+ else if(pos_y > me.controlBottom)
+ {
+ // page down
+ me.scrollPos = min(me.scrollPos + 1, me.nItems * me.itemHeight - 1);
+ me.setSelected(me, max(me.selectedItem, ceil(me.scrollPos / me.itemHeight)));
+ }
+ else
+ {
+ me.pressed = 1;
+ me.pressOffset = pos_y;
+ me.previousValue = me.scrollPos;
+ }
+ }
+ else
+ {
+ // continue doing that while dragging (even when dragging outside). When releasing, forward the click to the then selected item.
+ me.pressed = 2;
+ // an item has been clicked. Select it, ...
+ me.setSelected(me, floor((me.scrollPos + pos_y) / me.itemHeight));
+ }
+ return 1;
+}
+float mouseReleaseListBox(entity me, vector pos)
+{
+ vector absSize;
+ if(me.pressed == 1)
+ {
+ // slider dragging mode
+ // in that case, nothing happens on releasing
+ }
+ else if(me.pressed == 2)
+ {
+ me.pressed = 3; // do that here, so setSelected can know the mouse has been released
+ // item dragging mode
+ // select current one one last time...
+ me.setSelected(me, floor((me.scrollPos + pos_y) / me.itemHeight));
+ // and give it a nice click event
+ if(me.nItems > 0)
+ {
+ absSize = boxToGlobalSize(me.size, eX * (1 - me.controlWidth) + eY * me.itemHeight);
+ me.clickListBoxItem(me, me.selectedItem, globalToBox(pos, eY * (me.selectedItem * me.itemHeight - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.itemHeight));
+ }
+ }
+ me.pressed = 0;
+ return 1;
+}
+void updateControlTopBottomListBox(entity me)
+{
+ float f;
+ // scrollPos is in 0..1 and indicates where the "page" currently shown starts.
+ if(me.nItems * me.itemHeight <= 1)
+ {
+ // we don't need no stinkin' scrollbar, we don't need no view control...
+ me.controlTop = 0;
+ me.controlBottom = 1;
+ me.scrollPos = 0;
+ }
+ else
+ {
+ if(frametime) // only do this in draw frames
+ {
+ if(me.dragScrollTimer < time)
+ {
+ float save;
+ save = me.scrollPos;
+ // if selected item is below listbox, increase scrollpos so it is in
+ me.scrollPos = max(me.scrollPos, me.selectedItem * me.itemHeight - 1 + me.itemHeight);
+ // if selected item is above listbox, decrease scrollpos so it is in
+ me.scrollPos = min(me.scrollPos, me.selectedItem * me.itemHeight);
+ if(me.scrollPos != save)
+ me.dragScrollTimer = time + 0.2;
+ }
+ }
+ // if scroll pos is below end of list, fix it
+ me.scrollPos = min(me.scrollPos, me.nItems * me.itemHeight - 1);
+ // if scroll pos is above beginning of list, fix it
+ me.scrollPos = max(me.scrollPos, 0);
+ // now that we know where the list is scrolled to, find out where to draw the control
+ me.controlTop = max(0, me.scrollPos / (me.nItems * me.itemHeight));
+ me.controlBottom = min((me.scrollPos + 1) / (me.nItems * me.itemHeight), 1);
+
+ float fmin;
+ fmin = 1 * me.controlWidth / me.size_y * me.size_x;
+ f = me.controlBottom - me.controlTop;
+ if(f < fmin) // FIXME good default?
+ {
+ // f * X + 1 * (1-X) = fmin
+ // (f - 1) * X + 1 = fmin
+ // (f - 1) * X = fmin - 1
+ // X = (fmin - 1) / (f - 1)
+ f = (fmin - 1) / (f - 1);
+ me.controlTop = me.controlTop * f + 0 * (1 - f);
+ me.controlBottom = me.controlBottom * f + 1 * (1 - f);
+ }
+ }
+}
+void drawListBox(entity me)
+{
+ float i;
+ vector absSize;
+ vector oldshift, oldscale;
+ if(me.pressed == 2)
+ me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
+ me.updateControlTopBottom(me);
+ draw_VertButtonPicture(eX * (1 - me.controlWidth), strcat(me.src, "_s"), eX * me.controlWidth + eY, me.color2, 1);
+ if(me.nItems * me.itemHeight > 1)
+ {
+ vector o, s;
+ o = eX * (1 - me.controlWidth) + eY * me.controlTop;
+ s = eX * me.controlWidth + eY * (me.controlBottom - me.controlTop);
+ if(me.pressed == 1)
+ draw_VertButtonPicture(o, strcat(me.src, "_c"), s, me.colorC, 1);
+ else if(me.focused)
+ draw_VertButtonPicture(o, strcat(me.src, "_f"), s, me.colorF, 1);
+ else
+ draw_VertButtonPicture(o, strcat(me.src, "_n"), s, me.color, 1);
+ }
+ draw_SetClip();
+ oldshift = draw_shift;
+ oldscale = draw_scale;
+ absSize = boxToGlobalSize(me.size, eX * (1 - me.controlWidth) + eY * me.itemHeight);
+ for(i = floor(me.scrollPos / me.itemHeight); i < me.nItems; ++i)
+ {
+ float y;
+ y = i * me.itemHeight - me.scrollPos;
+ if(y >= 1)
+ break;
+ draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
+ draw_scale = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), oldscale);
+ me.drawListBoxItem(me, i, absSize, (me.selectedItem == i));
+ }
+ draw_ClearClip();
+}
+
+void clickListBoxItemListBox(entity me, float i, vector where)
+{
+ // itemclick, itemclick, does whatever itemclick does
+}
+
+void drawListBoxItemListBox(entity me, float i, vector absSize, float selected)
+{
+ draw_Text('0 0 0', strcat("Item ", ftos(i)), eX * (8 / absSize_x) + eY * (8 / absSize_y), (selected ? '0 1 0' : '1 1 1'), 1, 0);
+}
+#endif
Added: trunk/menu/item/modalcontroller.c
===================================================================
--- trunk/menu/item/modalcontroller.c (rev 0)
+++ trunk/menu/item/modalcontroller.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,282 @@
+#ifdef INTERFACE
+CLASS(ModalController) EXTENDS(Container)
+ METHOD(ModalController, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(ModalController, draw, void(entity))
+ METHOD(ModalController, addItem, void(entity, entity, vector, vector, float))
+ METHOD(ModalController, showChild, void(entity, entity, vector, vector, float))
+ METHOD(ModalController, hideChild, void(entity, entity, float))
+ METHOD(ModalController, hideAll, void(entity, float))
+ METHOD(ModalController, addItem, void(entity, entity, vector, vector, float))
+ METHOD(ModalController, addTab, void(entity, entity, entity))
+
+ METHOD(ModalController, initializeDialog, void(entity, entity))
+
+ METHOD(ModalController, switchState, void(entity, entity, float, float))
+ ATTRIB(ModalController, origin, vector, '0 0 0')
+ ATTRIB(ModalController, size, vector, '0 0 0')
+ ATTRIB(ModalController, previousButton, entity, NULL)
+ ATTRIB(ModalController, fadedAlpha, float, 0.3)
+ENDCLASS(ModalController)
+
+.vector origin;
+.vector size;
+void TabButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
+void DialogOpenButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
+void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize);
+void DialogCloseButton_Click(entity button, entity tab); // assumes a button has set the above fields to the tab to close
+#endif
+
+#ifdef IMPLEMENTATION
+
+// modal dialog controller
+// handles a stack of dialog elements
+// each element can have one of the following states:
+// 0: hidden (fading out)
+// 1: visible (zooming in)
+// 2: greyed out (inactive)
+// While an animation is running, no item has focus. When an animation is done,
+// the topmost item gets focus.
+// The items are assumed to be added in overlapping order, that is, the lowest
+// window must get added first.
+//
+// Possible uses:
+// - to control a modal dialog:
+// - show modal dialog: me.showChild(me, childItem, buttonAbsOrigin, buttonAbsSize, 0) // childItem also gets focus
+// - dismiss modal dialog: me.hideChild(me, childItem, 0) // childItem fades out and relinquishes focus
+// - show first screen in m_show: me.hideAll(me, 1); me.showChild(me, me.firstChild, '0 0 0', '0 0 0', 1);
+// - to show a temporary dialog instead of the menu (teamselect): me.hideAll(me, 1); me.showChild(me, teamSelectDialog, '0 0 0', '0 0 0', 1);
+// - as a tabbed dialog control:
+// - to initialize: me.hideAll(me, 1); me.showChild(me, me.firstChild, '0 0 0', '0 0 0', 1);
+// - to show a tab: me.hideChild(me, currentTab, 0); me.showChild(me, newTab, buttonAbsOrigin, buttonAbsSize, 0);
+
+.vector ModalController_initialSize;
+.vector ModalController_initialOrigin;
+.float ModalController_initialAlpha;
+.vector ModalController_buttonSize;
+.vector ModalController_buttonOrigin;
+.float ModalController_state;
+.float ModalController_factor;
+.entity ModalController_controllingButton;
+
+void initializeDialogModalController(entity me, entity root)
+{
+ me.hideAll(me, 1);
+ me.showChild(me, root, '0 0 0', '0 0 0', 1); // someone else animates for us
+}
+
+void TabButton_Click(entity button, entity tab)
+{
+ if(tab.ModalController_state == 1)
+ return;
+ tab.parent.hideAll(tab.parent, 0);
+ button.forcePressed = 1;
+ tab.ModalController_controllingButton = button;
+ tab.parent.showChild(tab.parent, tab, button.origin, button.size, 0);
+}
+
+void DialogOpenButton_Click(entity button, entity tab)
+{
+ DialogOpenButton_Click_withCoords(button, tab, button.origin, button.size);
+}
+
+void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize)
+{
+ if(tab.ModalController_state)
+ return;
+ if(button)
+ button.forcePressed = 1;
+ tab.ModalController_controllingButton = button;
+ tab.parent.showChild(tab.parent, tab, theOrigin, theSize, 0);
+}
+
+void DialogCloseButton_Click(entity button, entity tab)
+{
+ tab.parent.hideChild(tab.parent, tab, 0);
+}
+
+void resizeNotifyModalController(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ me.origin = absOrigin;
+ me.size = absSize;
+ me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, ModalController_initialOrigin, ModalController_initialSize);
+}
+
+void switchStateModalController(entity me, entity other, float state, float skipAnimation)
+{
+ float previousState;
+ previousState = other.ModalController_state;
+ if(state == previousState && !skipAnimation)
+ return;
+ other.ModalController_state = state;
+ switch(state)
+ {
+ case 0:
+ other.ModalController_factor = 1 - other.Container_alpha / other.ModalController_initialAlpha;
+ // fading out
+ break;
+ case 1:
+ other.ModalController_factor = other.Container_alpha / other.ModalController_initialAlpha;
+ if(previousState == 0 && !skipAnimation)
+ {
+ other.Container_origin = other.ModalController_buttonOrigin;
+ other.Container_size = other.ModalController_buttonSize;
+ }
+ // zooming in
+ break;
+ case 2:
+ other.ModalController_factor = bound(0, (1 - other.Container_alpha / other.ModalController_initialAlpha) / me.fadedAlpha, 1);
+ // fading out halfway
+ break;
+ }
+ if(skipAnimation)
+ other.ModalController_factor = 1;
+}
+
+void drawModalController(entity me)
+{
+ entity e;
+ entity front;
+ float animating;
+ float f; // animation factor
+ float df; // animation step size
+ float prevFactor, targetFactor;
+ vector targetOrigin, targetSize; float targetAlpha;
+ animating = 0;
+
+ for(e = me.firstChild; e; e = e.nextSibling)
+ if(e.ModalController_state)
+ {
+ if(front)
+ me.switchState(me, front, 2, 0);
+ front = e;
+ }
+ if(front)
+ me.switchState(me, front, 1, 0);
+
+ df = frametime * 3; // animation speed
+
+ for(e = me.firstChild; e; e = e.nextSibling)
+ {
+ f = (e.ModalController_factor = min(1, e.ModalController_factor + df));
+ if(e.ModalController_state)
+ if(f < 1)
+ animating = 1;
+
+ if(f < 1)
+ {
+ prevFactor = (1 - f) / (1 - f + df);
+ targetFactor = df / (1 - f + df);
+ }
+ else
+ {
+ prevFactor = 0;
+ targetFactor = 1;
+ }
+
+ if(e.ModalController_state == 2)
+ {
+ // fading out partially
+ targetOrigin = e.Container_origin; // stay as is
+ targetSize = e.Container_size; // stay as is
+ targetAlpha = me.fadedAlpha * e.ModalController_initialAlpha;
+ }
+ else if(e.ModalController_state == 1)
+ {
+ // zooming in
+ targetOrigin = e.ModalController_initialOrigin;
+ targetSize = e.ModalController_initialSize;
+ targetAlpha = e.ModalController_initialAlpha;
+ }
+ else
+ {
+ // fading out
+ if(f < 1)
+ animating = 1;
+ targetOrigin = e.Container_origin; // stay as is
+ targetSize = e.Container_size; // stay as is
+ targetAlpha = 0;
+ }
+
+ if(f == 1)
+ {
+ e.Container_origin = targetOrigin;
+ e.Container_size = targetSize;
+ me.setAlphaOf(me, e, targetAlpha);
+ }
+ else
+ {
+ e.Container_origin = e.Container_origin * prevFactor + targetOrigin * targetFactor;
+ e.Container_size = e.Container_size * prevFactor + targetSize * targetFactor;
+ me.setAlphaOf(me, e, e.Container_alpha * prevFactor + targetAlpha * targetFactor);
+ }
+ // assume: o == to * f_prev + X * (1 - f_prev)
+ // make: o' = to * f + X * (1 - f)
+ // -->
+ // X == (o - to * f_prev) / (1 - f_prev)
+ // o' = to * f + (o - to * f_prev) / (1 - f_prev) * (1 - f)
+ // --> (maxima)
+ // o' = (to * (f - f_prev) + o * (1 - f)) / (1 - f_prev)
+ }
+ if(animating || !me.focused)
+ me.setFocus(me, NULL);
+ else
+ me.setFocus(me, front);
+ drawContainer(me);
+};
+
+void addTabModalController(entity me, entity other, entity tabButton)
+{
+ me.addItem(me, other, '0 0 0', '1 1 1', 1);
+ tabButton.onClick = TabButton_Click;
+ tabButton.onClickEntity = other;
+ if(other == me.firstChild)
+ {
+ tabButton.forcePressed = 1;
+ other.ModalController_controllingButton = tabButton;
+ me.showChild(me, other, '0 0 0', '0 0 0', 1);
+ }
+}
+
+void addItemModalController(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
+{
+ addItemContainer(me, other, theOrigin, theSize, (other == me.firstChild) ? theAlpha : 0);
+ other.ModalController_initialSize = other.Container_size;
+ other.ModalController_initialOrigin = other.Container_origin;
+ other.ModalController_initialAlpha = theAlpha; // hope Container never modifies this
+}
+
+void showChildModalController(entity me, entity other, vector theOrigin, vector theSize, float skipAnimation)
+{
+ if(other.ModalController_state == 0 || skipAnimation)
+ {
+ me.setFocus(me, NULL);
+ if(!skipAnimation)
+ {
+ other.ModalController_buttonOrigin = globalToBox(theOrigin, me.origin, me.size);
+ other.ModalController_buttonSize = globalToBoxSize(theSize, me.size);
+ }
+ me.switchState(me, other, 1, skipAnimation);
+ } // zoom in from button (factor increases)
+}
+
+void hideAllModalController(entity me, float skipAnimation)
+{
+ entity e;
+ for(e = me.firstChild; e; e = e.nextSibling)
+ me.hideChild(me, e, skipAnimation);
+}
+
+void hideChildModalController(entity me, entity other, float skipAnimation)
+{
+ if(other.ModalController_state || skipAnimation)
+ {
+ me.setFocus(me, NULL);
+ me.switchState(me, other, 0, skipAnimation);
+ if(other.ModalController_controllingButton)
+ {
+ other.ModalController_controllingButton.forcePressed = 0;
+ other.ModalController_controllingButton = NULL;
+ }
+ } // just alpha fade out (factor increases and decreases alpha)
+}
+#endif
Added: trunk/menu/item/nexposee.c
===================================================================
--- trunk/menu/item/nexposee.c (rev 0)
+++ trunk/menu/item/nexposee.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,371 @@
+#ifdef INTERFACE
+CLASS(Nexposee) EXTENDS(Container)
+ METHOD(Nexposee, draw, void(entity))
+ METHOD(Nexposee, keyDown, float(entity, float, float, float))
+ METHOD(Nexposee, keyUp, float(entity, float, float, float))
+ METHOD(Nexposee, mousePress, float(entity, vector))
+ METHOD(Nexposee, mouseMove, float(entity, vector))
+ METHOD(Nexposee, mouseRelease, float(entity, vector))
+ METHOD(Nexposee, mouseDrag, float(entity, vector))
+ METHOD(Nexposee, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(Nexposee, focusEnter, void(entity))
+ METHOD(Nexposee, close, void(entity))
+
+ ATTRIB(Nexposee, animationState, float, -1)
+ ATTRIB(Nexposee, animationFactor, float, 0)
+ ATTRIB(Nexposee, selectedChild, entity, NULL)
+ ATTRIB(Nexposee, mouseFocusedChild, entity, NULL)
+ METHOD(Nexposee, addItem, void(entity, entity, vector, vector, float))
+ METHOD(Nexposee, calc, void(entity))
+ METHOD(Nexposee, setNexposee, void(entity, entity, vector, float, float))
+ ATTRIB(Nexposee, mousePosition, vector, '0 0 0')
+ METHOD(Nexposee, pullNexposee, void(entity, entity, vector))
+ENDCLASS(Nexposee)
+
+void ExposeeCloseButton_Click(entity button, entity other); // un-exposees the current state
+#endif
+
+// animation states:
+// 0 = thumbnails seen
+// 1 = zooming in
+// 2 = zoomed in
+// 3 = zooming out
+// animation factor: 0 = minimum theSize, 1 = maximum theSize
+
+#ifdef IMPLEMENTATION
+
+.vector Nexposee_initialSize;
+.vector Nexposee_initialOrigin;
+.float Nexposee_initialAlpha;
+
+.vector Nexposee_smallSize;
+.vector Nexposee_smallOrigin;
+.float Nexposee_smallAlpha;
+.float Nexposee_mediumAlpha;
+.vector Nexposee_scaleCenter;
+.vector Nexposee_align;
+.float Nexposee_animationFactor;
+
+void closeNexposee(entity me)
+{
+ // user must override this
+}
+
+void ExposeeCloseButton_Click(entity button, entity other)
+{
+ other.selectedChild = other.focusedChild;
+ other.setFocus(other, NULL);
+ other.animationState = 3;
+}
+
+void resizeNotifyNexposee(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ me.calc(me);
+ me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Nexposee_initialOrigin, Nexposee_initialSize);
+}
+
+void Nexposee_Calc_Scale(entity me, float scale)
+{
+ entity e;
+ for(e = me.firstChild; e; e = e.nextSibling)
+ {
+ e.Nexposee_smallOrigin = (e.Nexposee_initialOrigin - e.Nexposee_scaleCenter) * scale + e.Nexposee_scaleCenter;
+ e.Nexposee_smallSize = e.Nexposee_initialSize * scale;
+ if(e.Nexposee_align_x > 0)
+ e.Nexposee_smallOrigin_x = 1 - e.Nexposee_align_x * scale;
+ if(e.Nexposee_align_x < 0)
+ e.Nexposee_smallOrigin_x = -e.Nexposee_smallSize_x + e.Nexposee_align_x * scale;
+ if(e.Nexposee_align_y > 0)
+ e.Nexposee_smallOrigin_y = 1 - e.Nexposee_align_y * scale;
+ if(e.Nexposee_align_y < 0)
+ e.Nexposee_smallOrigin_y = -e.Nexposee_smallSize_y + e.Nexposee_align_y * scale;
+ }
+}
+
+void calcNexposee(entity me)
+{
+ /*
+ * patented by Apple
+ * can't put that here ;)
+ */
+ float scale;
+ entity e, e2;
+ vector emins, emaxs, e2mins, e2maxs;
+
+ for(scale = 0.7;; scale *= 0.99)
+ {
+ Nexposee_Calc_Scale(me, scale);
+
+ for(e = me.firstChild; e; e = e.nextSibling)
+ {
+ emins = e.Nexposee_smallOrigin;
+ emaxs = emins + e.Nexposee_smallSize;
+ for(e2 = e.nextSibling; e2; e2 = e2.nextSibling)
+ {
+ e2mins = e2.Nexposee_smallOrigin;
+ e2maxs = e2mins + e2.Nexposee_smallSize;
+
+ // two intervals [amins, amaxs] and [bmins, bmaxs] overlap if:
+ // amins < bmins < amaxs < bmaxs
+ // for which suffices
+ // bmins < amaxs
+ // amins < bmaxs
+ if((e2mins_x - emaxs_x) * (emins_x - e2maxs_x) > 0) // x overlap
+ if((e2mins_y - emaxs_y) * (emins_y - e2maxs_y) > 0) // y overlap
+ {
+ goto have_overlap;
+ }
+ }
+ }
+
+ break;
+:have_overlap
+ }
+
+ scale *= 0.95;
+
+ Nexposee_Calc_Scale(me, scale);
+}
+
+void setNexposeeNexposee(entity me, entity other, vector scalecenter, float a0, float a1)
+{
+ other.Nexposee_scaleCenter = scalecenter;
+ other.Nexposee_smallAlpha = a0;
+ me.setAlphaOf(me, other, a0);
+ other.Nexposee_mediumAlpha = a1;
+}
+
+void drawNexposee(entity me)
+{
+ float a;
+ float a0;
+ entity e;
+ float f;
+
+ if(me.animationState == -1)
+ {
+ me.animationState = 0;
+ }
+
+ //print(ftos(me.animationState), "\n");
+
+ f = min(1, frametime * 5);
+ switch(me.animationState)
+ {
+ case 0:
+ me.animationFactor = 0;
+ break;
+ case 1:
+ me.animationFactor += f;
+ if(me.animationFactor >= 1)
+ {
+ me.animationFactor = 1;
+ me.animationState = 2;
+ setFocusContainer(me, me.selectedChild);
+ }
+ break;
+ case 2:
+ me.animationFactor = 1;
+ break;
+ case 3:
+ me.animationFactor -= f;
+ me.mouseFocusedChild = me.itemFromPoint(me, me.mousePosition);
+ if(me.animationFactor <= 0)
+ {
+ me.animationFactor = 0;
+ me.animationState = 0;
+ me.selectedChild = me.mouseFocusedChild;
+ }
+ break;
+ }
+
+ f = min(1, frametime * 10);
+ for(e = me.firstChild; e; e = e.nextSibling)
+ {
+ if(e == me.selectedChild)
+ {
+ e.Container_origin = e.Nexposee_smallOrigin * (1 - me.animationFactor) + e.Nexposee_initialOrigin * me.animationFactor;
+ e.Container_size = e.Nexposee_smallSize * (1 - me.animationFactor) + e.Nexposee_initialSize * me.animationFactor;
+ e.Nexposee_animationFactor = me.animationFactor;
+ a0 = e.Nexposee_mediumAlpha;
+ if(me.animationState == 3)
+ if(e != me.mouseFocusedChild)
+ a0 = e.Nexposee_smallAlpha;
+ a = a0 * (1 - me.animationFactor) + me.animationFactor;
+ }
+ else
+ {
+ // minimum theSize counts
+ e.Container_origin = e.Nexposee_smallOrigin;
+ e.Container_size = e.Nexposee_smallSize;
+ e.Nexposee_animationFactor = 0;
+ a = e.Nexposee_smallAlpha * (1 - me.animationFactor);
+ }
+ me.setAlphaOf(me, e, e.Container_alpha * (1 - f) + a * f);
+ }
+
+ drawContainer(me);
+
+ /*
+ for(e = me.firstChild; e; e = e.nextSibling)
+ {
+ vector t, fs;
+ a0 = e.Container_alpha;
+ if(a0 < e.Nexposee_smallAlpha)
+ a = 0.3 * (a0 - 0) / (e.Nexposee_smallAlpha - 0);
+ else if(a0 < e.Nexposee_mediumAlpha)
+ a = 0.3 + 0.5 * (a0 - e.Nexposee_smallAlpha) / (e.Nexposee_mediumAlpha - e.Nexposee_smallAlpha);
+ else
+ a = 0.8 - 0.8 * (a0 - e.Nexposee_mediumAlpha) / (1 - e.Nexposee_mediumAlpha);
+ fs = (eX * (1 / draw_scale_x) + eY * (1 / draw_scale_y)) * 36;
+ t = draw_TextWidth(e.title, FALSE) * eX * fs_x + eY * fs_y;
+ draw_Text(e.Container_origin + (e.Container_size_x * eX - t) * 0.5 - 0.5 * eY * t_y, e.title, fs, e.color, a, FALSE);
+ }
+ */
+};
+
+float mousePressNexposee(entity me, vector pos)
+{
+ if(me.animationState == 0)
+ {
+ me.mouseFocusedChild = NULL;
+ mouseMoveNexposee(me, pos);
+ if(me.mouseFocusedChild)
+ {
+ me.animationState = 1;
+ setFocusContainer(me, NULL);
+ }
+ else
+ me.close(me);
+ return 1;
+ }
+ else if(me.animationState == 2)
+ {
+ if not(mousePressContainer(me, pos))
+ {
+ me.animationState = 3;
+ setFocusContainer(me, NULL);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+float mouseReleaseNexposee(entity me, vector pos)
+{
+ if(me.animationState == 2)
+ return mouseReleaseContainer(me, pos);
+ return 0;
+}
+
+float mouseDragNexposee(entity me, vector pos)
+{
+ if(me.animationState == 2)
+ return mouseDragContainer(me, pos);
+ return 0;
+}
+
+float mouseMoveNexposee(entity me, vector pos)
+{
+ entity e;
+ me.mousePosition = pos;
+ e = me.mouseFocusedChild;
+ me.mouseFocusedChild = me.itemFromPoint(me, pos);
+ if(me.animationState == 2)
+ return mouseMoveContainer(me, pos);
+ if(me.animationState == 0)
+ {
+ if(me.mouseFocusedChild)
+ if(me.mouseFocusedChild != e)
+ me.selectedChild = me.mouseFocusedChild;
+ return 1;
+ }
+ return 0;
+}
+
+float keyUpNexposee(entity me, float scan, float ascii, float shift)
+{
+ if(me.animationState == 2)
+ return keyUpContainer(me, scan, ascii, shift);
+ return 0;
+}
+
+float keyDownNexposee(entity me, float scan, float ascii, float shift)
+{
+ float nexposeeKey;
+ if(me.animationState == 2)
+ if(keyDownContainer(me, scan, ascii, shift))
+ return 1;
+ if(scan == K_TAB)
+ {
+ if(me.animationState == 0)
+ {
+ if(shift & S_SHIFT)
+ {
+ if(me.selectedChild)
+ me.selectedChild = me.selectedChild.prevSibling;
+ if not(me.selectedChild)
+ me.selectedChild = me.lastChild;
+ }
+ else
+ {
+ if(me.selectedChild)
+ me.selectedChild = me.selectedChild.nextSibling;
+ if not(me.selectedChild)
+ me.selectedChild = me.firstChild;
+ }
+ }
+ }
+ switch(me.animationState)
+ {
+ case 0:
+ case 3:
+ nexposeeKey = ((scan == K_SPACE) || (scan == K_ENTER));
+ break;
+ case 1:
+ case 2:
+ nexposeeKey = (scan == K_ESCAPE);
+ break;
+ }
+ if(nexposeeKey)
+ {
+ switch(me.animationState)
+ {
+ case 0:
+ case 3:
+ me.animationState = 1;
+ break;
+ case 1:
+ case 2:
+ me.animationState = 3;
+ break;
+ }
+ if(me.focusedChild)
+ me.selectedChild = me.focusedChild;
+ if not(me.selectedChild)
+ me.animationState = 0;
+ setFocusContainer(me, NULL);
+ return 1;
+ }
+ return 0;
+}
+
+void addItemNexposee(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
+{
+ addItemContainer(me, other, theOrigin, theSize, theAlpha);
+ other.Nexposee_initialSize = other.Container_size;
+ other.Nexposee_initialOrigin = other.Container_origin;
+ other.Nexposee_initialAlpha = other.Container_alpha;
+}
+
+void focusEnterNexposee(entity me)
+{
+ if(me.animationState == 2)
+ setFocusContainer(me, me.selectedChild);
+}
+
+void pullNexposeeNexposee(entity me, entity other, vector theAlign)
+{
+ other.Nexposee_align = theAlign;
+}
+#endif
Added: trunk/menu/item/radiobutton.c
===================================================================
--- trunk/menu/item/radiobutton.c (rev 0)
+++ trunk/menu/item/radiobutton.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,37 @@
+#ifdef INTERFACE
+void RadioButton_Click(entity me, entity other);
+CLASS(RadioButton) EXTENDS(CheckBox)
+ METHOD(RadioButton, configureRadioButton, void(entity, string, float, string, float, float))
+ ATTRIB(RadioButton, checked, float, 0)
+ ATTRIB(RadioButton, group, float, 0)
+ ATTRIB(RadioButton, allowDeselect, float, 0)
+ ATTRIB(RadioButton, onClick, void(entity, entity), RadioButton_Click)
+ENDCLASS(RadioButton)
+#endif
+
+#ifdef IMPLEMENTATION
+void configureRadioButtonRadioButton(entity me, string txt, float sz, string gfx, float theGroup, float doAllowDeselect)
+{
+ me.configureCheckBox(me, txt, sz, gfx);
+ me.align = 0;
+ me.group = theGroup;
+ me.allowDeselect = doAllowDeselect;
+}
+void RadioButton_Click(entity me, entity other)
+{
+ if(me.checked)
+ {
+ if(me.allowDeselect)
+ me.setChecked(me, 0);
+ }
+ else
+ {
+ entity e;
+ for(e = me.parent.firstChild; e; e = e.nextSibling)
+ if(e != me)
+ if(e.group == me.group)
+ e.setChecked(e, 0);
+ me.setChecked(me, 1);
+ }
+}
+#endif
Added: trunk/menu/item/slider.c
===================================================================
--- trunk/menu/item/slider.c (rev 0)
+++ trunk/menu/item/slider.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,225 @@
+// Note:
+// to use this, you FIRST call configureSliderVisuals, then configureSliderValues
+#ifdef INTERFACE
+CLASS(Slider) EXTENDS(Label)
+ METHOD(Slider, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(Slider, configureSliderVisuals, void(entity, float, float, float, string))
+ METHOD(Slider, configureSliderValues, void(entity, float, float, float, float, float, float))
+ METHOD(Slider, draw, void(entity))
+ METHOD(Slider, keyDown, float(entity, float, float, float))
+ METHOD(Slider, mousePress, float(entity, vector))
+ METHOD(Slider, mouseDrag, float(entity, vector))
+ METHOD(Slider, mouseRelease, float(entity, vector))
+ METHOD(Slider, valueToText, string(entity, float))
+ METHOD(Slider, toString, string(entity))
+ METHOD(Slider, setValue, void(entity, float))
+ METHOD(Slider, showNotify, void(entity))
+ ATTRIB(Slider, src, string, string_null)
+ ATTRIB(Slider, focusable, float, 1)
+ ATTRIB(Slider, value, float, 0)
+ ATTRIB(Slider, valueMin, float, 0)
+ ATTRIB(Slider, valueMax, float, 0)
+ ATTRIB(Slider, valueStep, float, 0)
+ ATTRIB(Slider, valueDigits, float, 0)
+ ATTRIB(Slider, valueKeyStep, float, 0)
+ ATTRIB(Slider, valuePageStep, float, 0)
+ ATTRIB(Slider, valueDisplayMultiplier, float, 1.0)
+ ATTRIB(Slider, textSpace, float, 0)
+ ATTRIB(Slider, controlWidth, float, 0)
+ ATTRIB(Slider, pressed, float, 0)
+ ATTRIB(Slider, pressOffset, float, 0)
+ ATTRIB(Slider, previousValue, float, 0)
+ ATTRIB(Slider, tolerance, vector, '0 0 0')
+ ATTRIB(Slider, disabled, float, 0)
+ ATTRIB(Slider, color, vector, '1 1 1')
+ ATTRIB(Slider, color2, vector, '1 1 1')
+ ATTRIB(Slider, colorD, vector, '1 1 1')
+ ATTRIB(Slider, colorC, vector, '1 1 1')
+ ATTRIB(Slider, colorF, vector, '1 1 1')
+ ATTRIB(Slider, disabledAlpha, float, 0.3)
+ENDCLASS(Slider)
+#endif
+
+#ifdef IMPLEMENTATION
+void setValueSlider(entity me, float val)
+{
+ me.value = val;
+}
+string toStringSlider(entity me)
+{
+ return strcat(ftos(me.value), " (", me.valueToText(me, me.value), ")");
+}
+void resizeNotifySlider(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ resizeNotifyLabel(me, relOrigin, relSize, absOrigin, absSize);
+ me.controlWidth = absSize_y / absSize_x;
+}
+string valueToTextSlider(entity me, float val)
+{
+ if(val < me.valueMin) return "";
+ if(val > me.valueMax) return "";
+ return ftos_decimals(val * me.valueDisplayMultiplier, me.valueDigits);
+}
+void configureSliderVisualsSlider(entity me, float sz, float theAlign, float theTextSpace, string gfx)
+{
+ configureLabelLabel(me, string_null, sz, theAlign);
+ me.textSpace = theTextSpace;
+ me.keepspaceLeft = (theTextSpace == 0) ? 0 : (1 - theTextSpace);
+ me.src = gfx;
+}
+void configureSliderValuesSlider(entity me, float theValueMin, float theValue, float theValueMax, float theValueStep, float theValueKeyStep, float theValuePageStep)
+{
+ me.value = theValue;
+ me.valueStep = theValueStep;
+ me.valueMin = theValueMin;
+ me.valueMax = theValueMax;
+ me.valueKeyStep = theValueKeyStep;
+ me.valuePageStep = theValuePageStep;
+ me.valueDigits = 3;
+ if(fabs(floor(me.valueStep * 100 + 0.5) - (me.valueStep * 100)) < 0.01) // about a whole number of 100ths
+ me.valueDigits = 2;
+ if(fabs(floor(me.valueStep * 10 + 0.5) - (me.valueStep * 10)) < 0.01) // about a whole number of 10ths
+ me.valueDigits = 1;
+ if(fabs(floor(me.valueStep * 1 + 0.5) - (me.valueStep * 1)) < 0.01) // about a whole number
+ me.valueDigits = 0;
+}
+float keyDownSlider(entity me, float key, float ascii, float shift)
+{
+ float inRange;
+ if(me.disabled)
+ return 0;
+ inRange = (me.value == median(me.valueMin, me.value, me.valueMax));
+ if(key == K_LEFTARROW)
+ {
+ if(inRange)
+ me.setValue(me, median(me.valueMin, me.value - me.valueKeyStep, me.valueMax));
+ else
+ me.setValue(me, me.valueMax);
+ return 1;
+ }
+ if(key == K_RIGHTARROW)
+ {
+ if(inRange)
+ me.setValue(me, median(me.valueMin, me.value + me.valueKeyStep, me.valueMax));
+ else
+ me.setValue(me, me.valueMin);
+ return 1;
+ }
+ if(key == K_PGUP)
+ {
+ if(inRange)
+ me.setValue(me, median(me.valueMin, me.value - me.valuePageStep, me.valueMax));
+ else
+ me.setValue(me, me.valueMax);
+ return 1;
+ }
+ if(key == K_PGDN)
+ {
+ if(inRange)
+ me.setValue(me, median(me.valueMin, me.value + me.valuePageStep, me.valueMax));
+ else
+ me.setValue(me, me.valueMin);
+ return 1;
+ }
+ if(key == K_HOME)
+ {
+ me.setValue(me, me.valueMin);
+ return 1;
+ }
+ if(key == K_END)
+ {
+ me.setValue(me, me.valueMax);
+ return 1;
+ }
+ // TODO more keys
+ return 0;
+}
+float mouseDragSlider(entity me, vector pos)
+{
+ float hit;
+ float v;
+ if(me.disabled)
+ return 0;
+ if(me.pressed)
+ {
+ hit = 1;
+ if(pos_x < 0 - me.tolerance_x) hit = 0;
+ if(pos_y < 0 - me.tolerance_y) hit = 0;
+ if(pos_x >= 1 - me.textSpace + me.tolerance_x) hit = 0;
+ if(pos_y >= 1 + me.tolerance_y) hit = 0;
+ if(hit)
+ {
+ v = median(0, (pos_x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
+ if(me.valueStep)
+ v = floor(0.5 + v / me.valueStep) * me.valueStep;
+ me.setValue(me, v);
+ }
+ else
+ me.setValue(me, me.previousValue);
+ }
+ return 1;
+}
+float mousePressSlider(entity me, vector pos)
+{
+ float controlCenter;
+ if(me.disabled)
+ return 0;
+ if(pos_x < 0) return 0;
+ if(pos_y < 0) return 0;
+ if(pos_x >= 1 - me.textSpace) return 0;
+ if(pos_y >= 1) return 0;
+ controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
+ if(fabs(pos_x - controlCenter) <= 0.5 * me.controlWidth)
+ {
+ me.pressed = 1;
+ me.pressOffset = pos_x - controlCenter;
+ me.previousValue = me.value;
+ //me.mouseDrag(me, pos);
+ }
+ else
+ {
+ if(pos_x < controlCenter)
+ me.keyDown(me, K_PGUP, 0, 0);
+ else
+ me.keyDown(me, K_PGDN, 0, 0);
+ }
+ return 1;
+}
+float mouseReleaseSlider(entity me, vector pos)
+{
+ me.pressed = 0;
+ if(me.disabled)
+ return 0;
+ return 1;
+}
+void showNotifySlider(entity me)
+{
+ me.focusable = !me.disabled;
+}
+void drawSlider(entity me)
+{
+ float controlLeft;
+ float save;
+ me.focusable = !me.disabled;
+ save = draw_alpha;
+ if(me.disabled)
+ draw_alpha *= me.disabledAlpha;
+ draw_ButtonPicture('0 0 0', strcat(me.src, "_s"), eX * (1 - me.textSpace) + eY, me.color2, 1);
+ if(me.value == median(me.valueMin, me.value, me.valueMax))
+ {
+ controlLeft = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth);
+ if(me.disabled)
+ draw_Picture(eX * controlLeft, strcat(me.src, "_d"), eX * me.controlWidth + eY, me.colorD, 1);
+ else if(me.pressed)
+ draw_Picture(eX * controlLeft, strcat(me.src, "_c"), eX * me.controlWidth + eY, me.colorC, 1);
+ else if(me.focused)
+ draw_Picture(eX * controlLeft, strcat(me.src, "_f"), eX * me.controlWidth + eY, me.colorF, 1);
+ else
+ draw_Picture(eX * controlLeft, strcat(me.src, "_n"), eX * me.controlWidth + eY, me.color, 1);
+ }
+ me.setText(me, me.valueToText(me, me.value));
+ draw_alpha = save;
+ drawLabel(me);
+ me.text = string_null; // TEMPSTRING!
+}
+#endif
Added: trunk/menu/item/tab.c
===================================================================
--- trunk/menu/item/tab.c (rev 0)
+++ trunk/menu/item/tab.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,28 @@
+#ifdef INTERFACE
+CLASS(Tab) EXTENDS(Dialog)
+ ATTRIB(Tab, isTabRoot, float, 0)
+ ATTRIB(Tab, closable, float, 0)
+ ATTRIB(Tab, rootDialog, float, 0)
+ ATTRIB(Tab, title, string, string_null)
+ ATTRIB(Tab, titleFontSize, float, 0) // pixels
+
+ // still to be customized
+ ATTRIB(Tab, intendedWidth, float, 0)
+ ATTRIB(Tab, rows, float, 3)
+ ATTRIB(Tab, columns, float, 2)
+
+ ATTRIB(Tab, marginTop, float, 0) // pixels
+ ATTRIB(Tab, marginBottom, float, 0) // pixels
+ ATTRIB(Tab, marginLeft, float, 0) // pixels
+ ATTRIB(Tab, marginRight, float, 0) // pixels
+ ATTRIB(Tab, columnSpacing, float, 0) // pixels
+ ATTRIB(Tab, rowSpacing, float, 0) // pixels
+ ATTRIB(Tab, rowHeight, float, 0) // pixels
+ ATTRIB(Tab, titleHeight, float, 0) // pixels
+
+ ATTRIB(Tab, backgroundImage, string, string_null)
+ENDCLASS(Tab)
+#endif
+
+#ifdef IMPLEMENTATION
+#endif
Added: trunk/menu/item/textslider.c
===================================================================
--- trunk/menu/item/textslider.c (rev 0)
+++ trunk/menu/item/textslider.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,60 @@
+// Note:
+// to use this, you FIRST call configureSliderVisuals, then multiple times addValue, then configureTextSlider
+#ifdef INTERFACE
+CLASS(TextSlider) EXTENDS(Slider)
+ METHOD(TextSlider, valueToText, string(entity, float))
+ METHOD(TextSlider, valueToIdentifier, string(entity, float))
+ METHOD(TextSlider, setValueFromIdentifier, void(entity, string))
+ METHOD(TextSlider, getIdentifier, string(entity))
+ METHOD(TextSlider, addValue, void(entity, string, string))
+ METHOD(TextSlider, configureTextSliderValues, void(entity, string))
+ ATTRIBARRAY(TextSlider, valueStrings, string, 16)
+ ATTRIBARRAY(TextSlider, valueIdentifiers, string, 16)
+ ATTRIB(TextSlider, nValues, float, 0)
+ENDCLASS(TextSlider)
+#endif
+
+#ifdef IMPLEMENTATION
+string valueToIdentifierTextSlider(entity me, float val)
+{
+ if(val >= me.nValues)
+ return "custom";
+ if(val < 0)
+ return "custom";
+ return me.(valueIdentifiers[val]);
+}
+string valueToTextTextSlider(entity me, float val)
+{
+ if(val >= me.nValues)
+ return "custom";
+ if(val < 0)
+ return "custom";
+ return me.(valueStrings[val]);
+}
+void setValueFromIdentifierTextSlider(entity me, string id)
+{
+ float i;
+ for(i = 0; i < me.nValues; ++i)
+ if(me.valueToIdentifier(me, i) == id)
+ {
+ me.value = i;
+ return;
+ }
+ me.value = -1;
+}
+string getIdentifierTextSlider(entity me)
+{
+ return me.valueToIdentifier(me, me.value);
+}
+void addValueTextSlider(entity me, string theString, string theIdentifier)
+{
+ me.(valueStrings[me.nValues]) = theString;
+ me.(valueIdentifiers[me.nValues]) = theIdentifier;
+ me.nValues += 1;
+}
+void configureTextSliderValuesTextSlider(entity me, string theDefault)
+{
+ me.configureSliderValues(me, 0, 0, me.nValues - 1, 1, 1, 1);
+ me.setValueFromIdentifier(me, theDefault);
+}
+#endif
Added: trunk/menu/item.c
===================================================================
--- trunk/menu/item.c (rev 0)
+++ trunk/menu/item.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,89 @@
+#ifdef INTERFACE
+CLASS(Item) EXTENDS(Object)
+ METHOD(Item, draw, void(entity))
+ METHOD(Item, keyDown, float(entity, float, float, float))
+ METHOD(Item, keyUp, float(entity, float, float, float))
+ METHOD(Item, mouseMove, float(entity, vector))
+ METHOD(Item, mousePress, float(entity, vector))
+ METHOD(Item, mouseDrag, float(entity, vector))
+ METHOD(Item, mouseRelease, float(entity, vector))
+ METHOD(Item, focusEnter, void(entity))
+ METHOD(Item, focusLeave, void(entity))
+ METHOD(Item, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(Item, relinquishFocus, void(entity))
+ METHOD(Item, showNotify, void(entity))
+ METHOD(Item, hideNotify, void(entity))
+ METHOD(Item, toString, string(entity))
+ ATTRIB(Item, focused, float, 0)
+ ATTRIB(Item, focusable, float, 0)
+ ATTRIB(Item, parent, entity, NULL)
+ENDCLASS(Item)
+#endif
+
+#ifdef IMPLEMENTATION
+void relinquishFocusItem(entity me)
+{
+ if(me.parent)
+ if(me.parent.instanceOfContainer)
+ me.parent.setFocus(me.parent, NULL);
+}
+
+void resizeNotifyItem(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+}
+
+void drawItem(entity me)
+{
+}
+
+void showNotifyItem(entity me)
+{
+}
+
+void hideNotifyItem(entity me)
+{
+}
+
+float keyDownItem(entity me, float scan, float ascii, float shift)
+{
+ return 0; // unhandled
+}
+
+float keyUpItem(entity me, float scan, float ascii, float shift)
+{
+ return 0; // unhandled
+}
+
+float mouseMoveItem(entity me, vector pos)
+{
+ return 0; // unhandled
+}
+
+float mousePressItem(entity me, vector pos)
+{
+ return 0; // unhandled
+}
+
+float mouseDragItem(entity me, vector pos)
+{
+ return 0; // unhandled
+}
+
+float mouseReleaseItem(entity me, vector pos)
+{
+ return 0; // unhandled
+}
+
+void focusEnterItem(entity me)
+{
+}
+
+void focusLeaveItem(entity me)
+{
+}
+
+string toStringItem(entity me)
+{
+ return string_null;
+}
+#endif
Added: trunk/menu/mbuiltin.qh
===================================================================
--- trunk/menu/mbuiltin.qh (rev 0)
+++ trunk/menu/mbuiltin.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,302 @@
+//////////////////////////////////////////////////
+// common cmd
+//////////////////////////////////////////////////
+// AK FIXME: Create perhaps a special builtin file for the common cmds
+
+//#define PROFILESTRZONE
+//#define FIXEDFOPEN
+
+void checkextension(string ext) = #1;
+
+// error cmds
+void error(string err,...) = #2;
+void objerror(string err,...) = #3;
+
+// print
+
+void print(string text,...) = #4;
+void bprint(string text,...) = #5;
+void sprint(float clientnum, string text,...) = #6;
+void centerprint(string text,...) = #7;
+
+// vector stuff
+
+vector normalize(vector v) = #8;
+float vlen(vector v) = #9;
+float vectoyaw(vector v) = #10;
+vector vectoangles(vector v) = #11;
+
+float random(void) = #12;
+
+void cmd(string command, ...) = #13;
+
+// cvar cmds
+
+float cvar(string name) = #14;
+const string cvar_string(string name) = #71;
+const string cvar_defstring(string name) = #89;
+void cvar_set(string name, string value) = #15;
+
+//void dprint(string text,...) = #16;
+
+// conversion functions
+
+string ftos(float f) = #17;
+float fabs(float f) = #18;
+string vtos(vector v) = #19;
+string etos(entity e) = #20;
+
+float stof(string val,...) = #21;
+
+entity spawn(void) = #22;
+void remove(entity e) = #23;
+
+entity findstring(entity start, .string _field, string match) = #24;
+entity findfloat(entity start, .float _field, float match) = #25;
+entity findentity(entity start, .entity _field, entity match) = #25;
+
+entity findchainstring(.string _field, string match) = #26;
+entity findchainfloat(.float _field, float match) = #27;
+entity findchainentity(.entity _field, entity match) = #27;
+
+entity findflags(entity start, .float field, float match) = #87;
+entity findchainflags(.float field, float match) = #88;
+
+string precache_file(string file) = #28;
+string precache_sound(string sample) = #29;
+
+void crash(void) = #72;
+void coredump(void) = #30;
+void stackdump(void) = #73;
+void traceon(void) = #31;
+void traceoff(void) = #32;
+
+void eprint(entity e) = #33;
+float rint(float f) = #34;
+float floor(float f) = #35;
+float ceil(float f) = #36;
+entity nextent(entity e) = #37;
+float sin(float f) = #38;
+float cos(float f) = #39;
+float sqrt(float f) = #40;
+vector randomvec(void) = #41;
+
+float registercvar(string name, string value, float flags) = #42; // returns 1 if success
+float min(float f,...) = #43;
+float max(float f,...) = #44;
+float bound(float min,float value, float max) = #45;
+float pow(float a, float b) = #46;
+void copyentity(entity src, entity dst) = #47;
+
+#ifdef FIXEDFOPEN
+float _fopen( string filename, float mode ) = #48;
+#else
+float fopen(string filename, float mode) = #48;
+#endif
+void fclose(float fhandle) = #49;
+string fgets(float fhandle) = #50;
+void fputs(float fhandle, string s) = #51;
+
+float strlen(string s) = #52;
+//string strcat(string s1,string s2,...) = #53;
+string strcat(string s1, ...) = #53;
+string substring(string s, float start, float length) = #54;
+
+vector stov(string s) = #55;
+
+#ifdef PROFILESTRZONE
+string _strzone(string s) = #56;
+void _strunzone(string s) = #57;
+
+string( string s ) strzone =
+{
+ return _strzone( s );
+};
+
+void( string s ) strunzone =
+{
+ return _strunzone( s );
+};
+#else
+string strzone(string s) = #56;
+void strunzone(string s) = #57;
+#endif
+
+float tokenize(string s) = #58;
+float(string s, string separator1, ...) tokenizebyseparator = #479;
+string argv(float n) = #59;
+
+float isserver(void) = #60;
+float clientcount(void) = #61;
+float clientstate(void) = #62;
+void clientcommand(float client, string s) = #63;
+void changelevel(string map) = #64;
+void localsound(string sample) = #65;
+vector getmousepos(void) = #66;
+float gettime(void) = #67;
+void loadfromdata(string data) = #68;
+void loadfromfile(string file) = #69;
+
+float mod(float val, float m) = #70;
+
+float search_begin(string pattern, float caseinsensitive, float quiet) = #74;
+void search_end(float handle) = #75;
+float search_getsize(float handle) = #76;
+string search_getfilename(float handle, float num) = #77;
+
+string chr(float ascii) = #78;
+
+float etof(entity ent) = #79;
+entity ftoe(float num) = #80;
+
+float validstring(string str) = #81;
+
+float altstr_count(string str) = #82;
+string altstr_prepare(string str) = #83;
+string altstr_get(string str, float num) = #84;
+string altstr_set(string str, float num, string set) = #85;
+string altstr_ins(string str, float num, string set) = #86;
+
+/////////////////////////////////////////////////
+// Write* Functions
+/////////////////////////////////////////////////
+void WriteByte(float data, float dest, float desto) = #401;
+void WriteChar(float data, float dest, float desto) = #402;
+void WriteShort(float data, float dest, float desto) = #403;
+void WriteLong(float data, float dest, float desto) = #404;
+void WriteAngle(float data, float dest, float desto) = #405;
+void WriteCoord(float data, float dest, float desto) = #406;
+void WriteString(string data, float dest, float desto)= #407;
+void WriteEntity(entity data, float dest, float desto) = #408;
+
+//////////////////////////////////////////////////
+// Draw funtions
+//////////////////////////////////////////////////
+
+float iscachedpic(string name) = #451;
+string precache_pic(string name) = #452;
+void freepic(string name) = #453;
+
+float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) = #454;
+
+float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) = #455;
+float drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag) = #467;
+float stringwidth(string text, float handleColors) = #468;
+
+float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) = #456;
+float drawsubpic(vector position, vector size, string pic, vector srcPosition, vector srcSize, vector rgb, float alpha, float flag) = #469;
+
+float drawfill(vector position, vector size, vector rgb, float alpha, float flag) = #457;
+
+void drawsetcliparea(float x, float y, float width, float height) = #458;
+
+void drawresetcliparea(void) = #459;
+
+vector drawgetimagesize(string pic) = #460;
+
+float cin_open(string file, string name) = #461;
+void cin_close(string name) = #462;
+void cin_setstate(string name, float type) = #463;
+float cin_getstate(string name) = #464;
+
+////////////////////////////////////////////////
+// Menu functions
+////////////////////////////////////////////////
+
+void setkeydest(float dest) = #601;
+float getkeydest(void) = #602;
+
+void setmousetarget(float trg) = #603;
+float getmousetarget(void) = #604;
+
+float isfunction(string function_name) = #607;
+void callfunction(...) = #605;
+void writetofile(float fhandle, entity ent) = #606;
+vector getresolution(float number) = #608;
+string keynumtostring(float keynum) = #609;
+string findkeysforcommand(string command) = #610;
+
+float gethostcachevalue(float type) = #611;
+string gethostcachestring(float type, float hostnr) = #612;
+
+void parseentitydata(entity ent, string data) = #613;
+
+float stringtokeynum(string key) = #614;
+
+void resethostcachemasks(void) = #615;
+void sethostcachemaskstring(float mask, float fld, string str, float op) = #616;
+void sethostcachemasknumber(float mask, float fld, float num, float op) = #617;
+void resorthostcache(void) = #618;
+void sethostcachesort(float fld, float descending) = #619;
+void refreshhostcache(void) = #620;
+float gethostcachenumber(float fld, float hostnr) = #621;
+float gethostcacheindexforkey(string key) = #622;
+void addwantedhostcachekey(string key) = #623;
+string getextresponse(void) = #624;
+
+// AK the builtin numbers may change - the code might be removed again
+float gecko_create( string name ) = #487;
+void gecko_destroy( string name ) = #488;
+void gecko_navigate( string name, string URI ) = #489;
+float gecko_keyevent( string name, float key, float eventtype ) = #490;
+void gecko_mousemove( string name, float x, float y ) = #491;
+void gecko_resize( string name, float w, float h ) = #492;
+vector gecko_get_texture_extent( string name ) = #493;
+
+//FTE_STRINGS
+//idea: many
+//darkplaces implementation: KrimZon
+//description:
+//various string manipulation functions
+float(string str, string sub, float startpos) strstrofs = #221;
+float(string str, float ofs) str2chr = #222;
+string(float c, ...) chr2str = #223;
+string(float ccase, float calpha, float cnum, string s, ...) strconv = #224;
+string(float chars, string s, ...) strpad = #225;
+string(string info, string key, string value, ...) infoadd = #226;
+string(string info, string key) infoget = #227;
+float(string s1, string s2, float len) strncmp = #228;
+float(string s1, string s2) strcasecmp = #229;
+float(string s1, string s2, float len) strncasecmp = #230;
+
+//DP_QC_STRINGBUFFERS
+//idea: ??
+//darkplaces implementation: LordHavoc
+//functions to manage string buffer objects - that is, arbitrary length string arrays that are handled by the engine
+float() buf_create = #440;
+void(float bufhandle) buf_del = #441;
+float(float bufhandle) buf_getsize = #442;
+void(float bufhandle_from, float bufhandle_to) buf_copy = #443;
+void(float bufhandle, float sortpower, float backward) buf_sort = #444;
+string(float bufhandle, string glue) buf_implode = #445;
+string(float bufhandle, float string_index) bufstr_get = #446;
+void(float bufhandle, float string_index, string str) bufstr_set = #447;
+float(float bufhandle, string str, float order) bufstr_add = #448;
+void(float bufhandle, float string_index) bufstr_free = #449;
+
+//DP_QC_CRC16
+//idea: div0
+//darkplaces implementation: div0
+//Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol.
+//When caseinsensitive is set, the CRC is calculated of the lower cased string.
+float(float caseinsensitive, string s, ...) crc16 = #494;
+
+#ifdef FIXEDFOPEN
+float fopen( string filename, float mode ) =
+{
+ local float handle;
+ if( mode == FILE_READ ) {
+ return _fopen( filename, mode );
+ }
+
+ // check for data/
+ filename = strzone( filename );
+ if( substring( filename, 0, 5 ) != "data/" ) {
+ print( "menu: fopen: all output must go into data/!\n" );
+ return -1;
+ }
+ handle = _fopen( substring( filename, 5, 10000 ), mode );
+ strunzone( filename );
+ return handle;
+};
+#endif
Added: trunk/menu/menu.qc
===================================================================
--- trunk/menu/menu.qc (rev 0)
+++ trunk/menu/menu.qc 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,398 @@
+///////////////////////////////////////////////
+// Menu Source File
+///////////////////////
+// This file belongs to dpmod/darkplaces
+// AK contains all menu functions (especially the required ones)
+///////////////////////////////////////////////
+
+float mouseButtonsPressed;
+vector menuMousePos;
+float menuShiftState;
+float menuPrevTime;
+float menuAlpha;
+float menuLogoAlpha;
+float prevMenuAlpha;
+float menuInitialized;
+float menuNotTheFirstFrame;
+
+void SUB_Null() { };
+
+void() m_init =
+{
+ dprint_load();
+}
+
+void UpdateConWidthHeight()
+{
+ float conwidth_s, conheight_s;
+ conwidth_s = conwidth;
+ conheight_s = conheight;
+ conwidth = cvar("vid_conwidth");
+ conheight = cvar("vid_conheight");
+ if(conwidth < 800)
+ {
+ conheight *= 800 / conwidth;
+ conwidth = 800;
+ }
+ if(conheight < 600)
+ {
+ conwidth *= 600 / conheight;
+ conheight = 600;
+ }
+ if(main)
+ {
+ if(conwidth_s != conwidth || conheight_s != conheight)
+ {
+ draw_reset();
+ main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
+ }
+ }
+}
+
+void() m_init_delayed =
+{
+ float fh, glob, n, i;
+ string s;
+
+ dprint_load();
+
+ menuInitialized = 0;
+ if(!preMenuInit())
+ return;
+ menuInitialized = 1;
+ GameCommand_Init();
+
+ fh = -1;
+ if(cvar_string("menu_skin") != "")
+ {
+ draw_currentSkin = strcat("gfx/menu/", cvar_string("menu_skin"));
+ fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);
+ }
+ if(fh < 0)
+ {
+ draw_currentSkin = "gfx/menu/default";
+ fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);
+ }
+ draw_currentSkin = strzone(draw_currentSkin);
+ while((s = fgets(fh)))
+ if(tokenize(s) == 2)
+ Skin_ApplySetting(argv(0), argv(1));
+ fclose(fh);
+
+ glob = search_begin(strcat(draw_currentSkin, "/*.tga"), TRUE, TRUE);
+ if(glob >= 0)
+ {
+ n = search_getsize(glob);
+ for(i = 0; i < n; ++i)
+ precache_pic(search_getfilename(glob, i));
+ search_end(glob);
+ }
+
+ draw_setMousePointer(SKINGFX_CURSOR, SKINSIZE_CURSOR, SKINOFFSET_CURSOR);
+
+ conwidth = conheight = -1;
+ draw_reset();
+ UpdateConWidthHeight();
+ main = spawnMainWindow(); main.configureMainWindow(main);
+ main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
+ main.focused = 1;
+ menuShiftState = 0;
+ menuMousePos = '0.5 0.5 0';
+
+ if(Menu_Active)
+ m_display(); // delayed menu display
+};
+
+void(float key, float ascii) m_keyup =
+{
+ if(!menuInitialized)
+ return;
+ if(!Menu_Active)
+ return;
+ draw_reset();
+ main.keyUp(main, key, ascii, menuShiftState);
+ if(key >= K_MOUSE1 && key <= K_MOUSE3)
+ {
+ --mouseButtonsPressed;
+ if(!mouseButtonsPressed)
+ main.mouseRelease(main, menuMousePos);
+ if(mouseButtonsPressed < 0)
+ {
+ mouseButtonsPressed = 0;
+ print("Warning: released an already released button\n");
+ }
+ }
+ if(key == K_ALT) menuShiftState -= (menuShiftState & S_ALT);
+ if(key == K_CTRL) menuShiftState -= (menuShiftState & S_CTRL);
+ if(key == K_SHIFT) menuShiftState -= (menuShiftState & S_SHIFT);
+};
+
+void(float key, float ascii) m_keydown =
+{
+ if(!menuInitialized)
+ return;
+ if(!Menu_Active)
+ return;
+ if(keyGrabber)
+ {
+ entity e;
+ e = keyGrabber;
+ keyGrabber = NULL;
+ e.keyGrabbed(e, key, ascii);
+ }
+ else
+ {
+ draw_reset();
+ if(!main.keyDown(main, key, ascii, menuShiftState))
+ if(key == K_ESCAPE)
+ if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED)) // don't back out to console only
+ m_hide(); // disable menu on unhandled ESC
+ if(key >= K_MOUSE1 && key <= K_MOUSE3)
+ if(!mouseButtonsPressed)
+ main.mousePress(main, menuMousePos);
+ }
+ if(key >= K_MOUSE1 && key <= K_MOUSE3)
+ {
+ ++mouseButtonsPressed;
+ if(mouseButtonsPressed > 10)
+ {
+ mouseButtonsPressed = 10;
+ print("Warning: pressed an already pressed button\n");
+ }
+ }
+ if(key == K_ALT) menuShiftState |= S_ALT;
+ if(key == K_CTRL) menuShiftState |= S_CTRL;
+ if(key == K_SHIFT) menuShiftState |= S_SHIFT;
+};
+
+void(string img, float a) drawBackground =
+{
+ vector sz;
+ vector isz;
+ sz = draw_PictureSize(img);
+ // keep aspect of image
+ if(sz_x * draw_scale_y >= sz_y * draw_scale_x)
+ {
+ // that is, sz_x/sz_y >= draw_scale_x/draw_scale_y
+ // match up the height
+ isz_y = 1;
+ isz_x = isz_y * (sz_x / sz_y) * (draw_scale_y / draw_scale_x);
+ }
+ else
+ {
+ // that is, sz_x/sz_y <= draw_scale_x/draw_scale_y
+ // match up the width
+ isz_x = 1;
+ isz_y = isz_x * (sz_y / sz_x) * (draw_scale_x / draw_scale_y);
+ }
+ draw_Picture('0.5 0.5 0' - 0.5 * isz, img, isz, '1 1 1', a);
+}
+
+void() m_draw =
+{
+ float t;
+ float realFrametime;
+
+ if(main)
+ UpdateConWidthHeight();
+
+ if(!menuInitialized)
+ {
+ // TODO draw an info image about this situation
+ m_init_delayed();
+ return;
+ }
+ if(!menuNotTheFirstFrame)
+ {
+ menuNotTheFirstFrame = 1;
+ if(Menu_Active)
+ if(!cvar("menu_video_played"))
+ {
+ localcmd("set menu_video_played 1; cd loop 1; play sound/announcer/male/welcome.ogg\n");
+ menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading
+ }
+ }
+
+ t = gettime();
+ realFrametime = frametime = min(0.2, t - menuPrevTime);
+ menuPrevTime = t;
+ time += frametime;
+
+ t = cvar("menu_slowmo");
+ if(t)
+ {
+ frametime *= t;
+ realFrametime *= t;
+ }
+
+ if(Menu_Active)
+ {
+ if(getmousetarget() == MT_MENU && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))
+ setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);
+ else
+ m_hide();
+ }
+
+ if(cvar("cl_capturevideo"))
+ frametime = cvar("menu_slowmo") / cvar("cl_capturevideo_fps"); // make capturevideo work smoothly
+
+ dprint_load();
+ gamestatus = 0;
+ if(isserver())
+ gamestatus = gamestatus | GAME_ISSERVER;
+ if(clientstate() == CS_CONNECTED)
+ gamestatus = gamestatus | GAME_CONNECTED;
+ if(cvar("developer"))
+ gamestatus = gamestatus | GAME_DEVELOPER;
+
+ prevMenuAlpha = menuAlpha;
+ if(Menu_Active)
+ {
+ if(menuAlpha == 0 && menuLogoAlpha < 2)
+ {
+ menuLogoAlpha = menuLogoAlpha + frametime * 2;
+ }
+ else
+ {
+ menuAlpha = min(1, menuAlpha + frametime * 5);
+ menuLogoAlpha = 2;
+ }
+ }
+ else
+ {
+ menuAlpha = max(0, menuAlpha - frametime * 5);
+ menuLogoAlpha = 2;
+ }
+
+ draw_reset();
+
+ if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
+ {
+ if(menuLogoAlpha > 0)
+ {
+ drawBackground(SKINGFX_BACKGROUND, bound(0, menuLogoAlpha, 1));
+ if(menuAlpha <= 0 && SKINALPHA_CURSOR_INTRO > 0)
+ {
+ draw_alpha = SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1);
+ draw_drawMousePointer(menuMousePos);
+ draw_alpha = 1;
+ }
+ }
+ }
+ else if(SKINALPHA_BACKGROUND_INGAME)
+ {
+ if(menuAlpha > 0)
+ drawBackground(SKINGFX_BACKGROUND_INGAME, menuAlpha * SKINALPHA_BACKGROUND_INGAME);
+ }
+
+ draw_reset();
+ preMenuDraw();
+ draw_reset();
+
+ if(menuAlpha <= 0)
+ {
+ if(prevMenuAlpha > 0)
+ main.initializeDialog(main, main.firstChild);
+ draw_reset();
+ postMenuDraw();
+ return;
+ }
+
+ draw_alpha *= menuAlpha;
+
+ if(frametime > 0)
+ {
+ vector dMouse;
+ dMouse = getmousepos() * (frametime / realFrametime); // for capturevideo
+ if(dMouse != '0 0 0')
+ {
+ dMouse = globalToBoxSize(dMouse, draw_scale);
+ menuMousePos += dMouse * 1; // TODO use a cvar here
+ menuMousePos_x = bound(0, menuMousePos_x, 1);
+ menuMousePos_y = bound(0, menuMousePos_y, 1);
+ if(mouseButtonsPressed)
+ main.mouseDrag(main, menuMousePos);
+ else
+ main.mouseMove(main, menuMousePos);
+ }
+ }
+ main.draw(main);
+ draw_alpha = max(draw_alpha, SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1));
+
+ draw_drawMousePointer(menuMousePos);
+
+ draw_reset();
+ postMenuDraw();
+
+ frametime = 0;
+};
+
+void() m_display =
+{
+ Menu_Active = true;
+ setkeydest(KEY_MENU);
+ setmousetarget(MT_MENU);
+
+ if(!menuInitialized)
+ return;
+
+ if(mouseButtonsPressed)
+ main.mouseRelease(main, menuMousePos);
+ mouseButtonsPressed = 0;
+
+ main.focusEnter(main);
+ main.showNotify(main);
+};
+
+void() m_hide =
+{
+ Menu_Active = false;
+ setkeydest(KEY_GAME);
+ setmousetarget(MT_CLIENT);
+
+ if(!menuInitialized)
+ return;
+
+ main.focusLeave(main);
+ main.hideNotify(main);
+};
+
+void() m_toggle =
+{
+ if(Menu_Active)
+ m_hide();
+ else
+ m_display();
+};
+
+void() m_shutdown =
+{
+ m_hide();
+};
+
+void(string itemname) m_goto =
+{
+ entity e;
+ if(!menuInitialized)
+ return;
+ if(itemname == "") // this can be called by GameCommand
+ {
+ if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED))
+ m_hide();
+ else
+ {
+ main.initializeDialog(main, main.firstChild);
+ m_display();
+ }
+ }
+ else
+ {
+ e = findstring(NULL, name, itemname);
+ if(e && e.parent == main)
+ {
+ m_hide();
+ main.initializeDialog(main, e);
+ m_display();
+ }
+ }
+}
Added: trunk/menu/menu.qh
===================================================================
--- trunk/menu/menu.qh (rev 0)
+++ trunk/menu/menu.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,45 @@
+#define localcmd cmd
+
+#define NULL (null_entity)
+
+#define MAPINFO
+
+// constants
+
+const string string_null;
+const vector eX = '1 0 0';
+const vector eY = '0 1 0';
+const vector eZ = '0 0 1';
+
+const float GAME_ISSERVER = 1;
+const float GAME_CONNECTED = 2;
+const float GAME_DEVELOPER = 4;
+
+// prototypes
+
+float Menu_Active;
+float gamestatus;
+
+const float S_SHIFT = 1;
+const float S_CTRL = 2;
+const float S_ALT = 4;
+
+float frametime;
+float time;
+
+entity main;
+void m_hide();
+void m_display();
+void m_goto(string name);
+.string name;
+
+entity keyGrabber;
+.void(entity me, float key, float ascii) keyGrabbed;
+
+float conwidth, conheight; // "virtual" conwidth/height values for other stuff to assume for scaling
+
+void SUB_Null();
+
+float preMenuInit(); // you have to define this for pre-menu initialization. Return 0 if initialization needs to be retried a frame later, 1 if it succeeded.
+void preMenuDraw(); // this is run before the menu is drawn. You may put some stuff there that has to be done every frame.
+void postMenuDraw(); // this is run just after the menu is drawn (or not). Useful to draw something over everything else.
Added: trunk/menu/msys.qh
===================================================================
--- trunk/menu/msys.qh (rev 0)
+++ trunk/menu/msys.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,303 @@
+#pragma flag off fastarrays // make dp behave with new fteqcc versions. remove when dp bug with fteqcc fastarrays is fixed
+
+//////////////////////////////////////////////////////////
+// sys globals
+
+entity self;
+
+/////////////////////////////////////////////////////////
+void end_sys_globals;
+/////////////////////////////////////////////////////////
+// sys fields
+
+/////////////////////////////////////////////////////////
+void end_sys_fields;
+/////////////////////////////////////////////////////////
+// sys functions
+
+void() m_init;
+void(float keynr, float ascii) m_keydown;
+void() m_draw;
+void() m_display; // old NG Menu
+void() m_toggle;
+void() m_hide; // old NG Menu
+void() m_shutdown;
+
+/////////////////////////////////////////////////////////
+// sys constants
+///////////////////////////
+// key constants
+
+//
+// these are the key numbers that should be passed to Key_Event
+//
+float K_TAB = 9;
+float K_ENTER = 13;
+float K_ESCAPE = 27;
+float K_SPACE = 32;
+
+// normal keys should be passed as lowercased ascii
+
+float K_BACKSPACE = 127;
+float K_UPARROW = 128;
+float K_DOWNARROW = 129;
+float K_LEFTARROW = 130;
+float K_RIGHTARROW = 131;
+
+float K_ALT = 132;
+float K_CTRL = 133;
+float K_SHIFT = 134;
+float K_F1 = 135;
+float K_F2 = 136;
+float K_F3 = 137;
+float K_F4 = 138;
+float K_F5 = 139;
+float K_F6 = 140;
+float K_F7 = 141;
+float K_F8 = 142;
+float K_F9 = 143;
+float K_F10 = 144;
+float K_F11 = 145;
+float K_F12 = 146;
+float K_INS = 147;
+float K_DEL = 148;
+float K_PGDN = 149;
+float K_PGUP = 150;
+float K_HOME = 151;
+float K_END = 152;
+
+float K_KP_HOME = 160;
+float K_KP_UPARROW = 161;
+float K_KP_PGUP = 162;
+float K_KP_LEFTARROW = 163;
+float K_KP_5 = 164;
+float K_KP_RIGHTARROW = 165;
+float K_KP_END = 166;
+float K_KP_DOWNARROW = 167;
+float K_KP_PGDN = 168;
+float K_KP_ENTER = 169;
+float K_KP_INS = 170;
+float K_KP_DEL = 171;
+float K_KP_SLASH = 172;
+float K_KP_MINUS = 173;
+float K_KP_PLUS = 174;
+
+float K_PAUSE = 255;
+
+//
+// joystick buttons
+//
+float K_JOY1 = 768;
+float K_JOY2 = 769;
+float K_JOY3 = 770;
+float K_JOY4 = 771;
+
+//
+// aux keys are for multi-buttoned joysticks to generate so they can use
+// the normal binding process
+//
+float K_AUX1 = 772;
+float K_AUX2 = 773;
+float K_AUX3 = 774;
+float K_AUX4 = 775;
+float K_AUX5 = 776;
+float K_AUX6 = 777;
+float K_AUX7 = 778;
+float K_AUX8 = 779;
+float K_AUX9 = 780;
+float K_AUX10 = 781;
+float K_AUX11 = 782;
+float K_AUX12 = 783;
+float K_AUX13 = 784;
+float K_AUX14 = 785;
+float K_AUX15 = 786;
+float K_AUX16 = 787;
+float K_AUX17 = 788;
+float K_AUX18 = 789;
+float K_AUX19 = 790;
+float K_AUX20 = 791;
+float K_AUX21 = 792;
+float K_AUX22 = 793;
+float K_AUX23 = 794;
+float K_AUX24 = 795;
+float K_AUX25 = 796;
+float K_AUX26 = 797;
+float K_AUX27 = 798;
+float K_AUX28 = 799;
+float K_AUX29 = 800;
+float K_AUX30 = 801;
+float K_AUX31 = 802;
+float K_AUX32 = 803;
+
+//
+// mouse buttons generate virtual keys
+//
+float K_MOUSE1 = 512;
+float K_MOUSE2 = 513;
+float K_MOUSE3 = 514;
+float K_MWHEELUP = 515;
+float K_MWHEELDOWN = 516;
+float K_MOUSE4 = 517;
+float K_MOUSE5 = 518;
+float K_MOUSE6 = 519;
+float K_MOUSE7 = 520;
+float K_MOUSE8 = 521;
+float K_MOUSE9 = 522;
+float K_MOUSE10 = 523;
+float K_MOUSE11 = 524;
+float K_MOUSE12 = 525;
+float K_MOUSE13 = 526;
+float K_MOUSE14 = 527;
+float K_MOUSE15 = 528;
+float K_MOUSE16 = 529;
+
+///////////////////////////
+// key dest constants
+
+float KEY_UNKNOWN = -1;
+float KEY_GAME = 0;
+float KEY_MENU = 2;
+float KEY_MENU_GRABBED = 3;
+
+///////////////////////////
+// file constants
+
+float FILE_READ = 0;
+float FILE_APPEND = 1;
+float FILE_WRITE = 2;
+
+///////////////////////////
+// logical constants (just for completeness)
+
+float TRUE = 1;
+float FALSE = 0;
+
+///////////////////////////
+// boolean constants
+
+float true = 1;
+float false = 0;
+
+///////////////////////////
+// msg constants
+
+float MSG_BROADCAST = 0; // unreliable to all
+float MSG_ONE = 1; // reliable to one (msg_entity)
+float MSG_ALL = 2; // reliable to all
+float MSG_INIT = 3; // write to the init string
+
+/////////////////////////////
+// mouse target constants
+
+float MT_MENU = 1;
+float MT_CLIENT = 2;
+
+/////////////////////////
+// client state constants
+
+float CS_DEDICATED = 0;
+float CS_DISCONNECTED = 1;
+float CS_CONNECTED = 2;
+
+///////////////////////////
+// blend flags
+
+float DRAWFLAG_NORMAL = 0;
+float DRAWFLAG_ADDITIVE = 1;
+float DRAWFLAG_MODULATE = 2;
+float DRAWFLAG_2XMODULATE = 3;
+
+
+///////////////////////////
+// cvar constants
+
+float CVAR_SAVE = 1;
+float CVAR_NOTIFY = 2;
+float CVAR_READONLY = 4;
+
+///////////////////////////
+// server list constants
+
+float SLIST_HOSTCACHEVIEWCOUNT = 0;
+float SLIST_HOSTCACHETOTALCOUNT = 1;
+float SLIST_MASTERQUERYCOUNT = 2;
+float SLIST_MASTERREPLYCOUNT = 3;
+float SLIST_SERVERQUERYCOUNT = 4;
+float SLIST_SERVERREPLYCOUNT = 5;
+float SLIST_SORTFIELD = 6;
+float SLIST_SORTDESCENDING = 7;
+
+float SLIST_LEGACY_LINE1 = 1024;
+float SLIST_LEGACY_LINE2 = 1025;
+
+float SLIST_TEST_CONTAINS = 0;
+float SLIST_TEST_NOTCONTAIN = 1;
+float SLIST_TEST_LESSEQUAL = 2;
+float SLIST_TEST_LESS = 3;
+float SLIST_TEST_EQUAL = 4;
+float SLIST_TEST_GREATER = 5;
+float SLIST_TEST_GREATEREQUAL = 6;
+float SLIST_TEST_NOTEQUAL = 7;
+
+float SLIST_MASK_AND = 0;
+float SLIST_MASK_OR = 512;
+
+float NET_CURRENTPROTOCOL = 3;
+
+////////////////////////////////
+// cinematic action constants
+
+float CINE_PLAY = 1;
+float CINE_LOOP = 2;
+float CINE_PAUSE = 3;
+float CINE_FIRSTFRAME = 4;
+float CINE_RESETONWAKEUP= 5;
+
+///////////////////////////
+// null entity (actually it is the same like the world entity)
+
+entity null_entity;
+
+///////////////////////////
+// error constants
+
+// file handling
+float ERR_CANNOTOPEN = -1; // fopen
+float ERR_NOTENOUGHFILEHANDLES = -2; // fopen
+float ERR_INVALIDMODE = -3; // fopen
+float ERR_BADFILENAME = -4; // fopen
+
+// drawing functions
+
+float ERR_NULLSTRING = -1;
+float ERR_BADDRAWFLAG = -2;
+float ERR_BADSCALE = -3;
+//float ERR_BADSIZE = ERR_BADSCALE;
+float ERR_NOTCACHED = -4;
+
+float GECKO_BUTTON_DOWN = 0;
+float GECKO_BUTTON_UP = 1;
+// either use down and up or just press but not all of them!
+float GECKO_BUTTON_PRESS = 2;
+// use this for mouse events if needed?
+float GECKO_BUTTON_DOUBLECLICK = 3;
+
+/* not supported at the moment
+///////////////////////////
+// os constants
+
+float OS_WINDOWS = 0;
+float OS_LINUX = 1;
+float OS_MAC = 2;
+*/
+
+float drawfont; // set this to one of the following for draw text routines to work with another font
+float FONT_DEFAULT = 0;
+float FONT_CONSOLE = 1;
+float FONT_SBAR = 2;
+float FONT_NOTIFY = 3;
+float FONT_CHAT = 4;
+float FONT_CENTERPRINT = 5;
+float FONT_INFOBAR = 6;
+float FONT_MENU = 7;
+float FONT_USER = 8; // add to this the index, like FONT_USER+3 = user3. At least 8 of them are supported.
Added: trunk/menu/nexuiz/button.c
===================================================================
--- trunk/menu/nexuiz/button.c (rev 0)
+++ trunk/menu/nexuiz/button.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,40 @@
+#ifdef INTERFACE
+CLASS(NexuizButton) EXTENDS(Button)
+ METHOD(NexuizButton, configureNexuizButton, void(entity, string, vector))
+ ATTRIB(NexuizButton, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizButton, image, string, SKINGFX_BUTTON)
+ ATTRIB(NexuizButton, grayImage, string, SKINGFX_BUTTON_GRAY)
+ ATTRIB(NexuizButton, color, vector, SKINCOLOR_BUTTON_N)
+ ATTRIB(NexuizButton, colorC, vector, SKINCOLOR_BUTTON_C)
+ ATTRIB(NexuizButton, colorF, vector, SKINCOLOR_BUTTON_F)
+ ATTRIB(NexuizButton, colorD, vector, SKINCOLOR_BUTTON_D)
+ ATTRIB(NexuizButton, alpha, float, SKINALPHA_TEXT)
+ ATTRIB(NexuizButton, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(NexuizButton)
+entity makeNexuizButton(string theText, vector theColor);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizButton(string theText, vector theColor)
+{
+ entity me;
+ me = spawnNexuizButton();
+ me.configureNexuizButton(me, theText, theColor);
+ return me;
+}
+
+void configureNexuizButtonNexuizButton(entity me, string theText, vector theColor)
+{
+ if(theColor == '0 0 0')
+ {
+ me.configureButton(me, theText, me.fontSize, me.image);
+ }
+ else
+ {
+ me.configureButton(me, theText, me.fontSize, me.grayImage);
+ me.color = theColor;
+ me.colorC = theColor;
+ me.colorF = theColor;
+ }
+}
+#endif
Added: trunk/menu/nexuiz/campaign.c
===================================================================
--- trunk/menu/nexuiz/campaign.c (rev 0)
+++ trunk/menu/nexuiz/campaign.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,261 @@
+#ifdef INTERFACE
+CLASS(NexuizCampaignList) EXTENDS(NexuizListBox)
+ METHOD(NexuizCampaignList, configureNexuizCampaignList, void(entity))
+ ATTRIB(NexuizCampaignList, rowsPerItem, float, 10)
+ METHOD(NexuizCampaignList, draw, void(entity))
+ METHOD(NexuizCampaignList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(NexuizCampaignList, clickListBoxItem, void(entity, float, vector))
+ METHOD(NexuizCampaignList, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(NexuizCampaignList, setSelected, void(entity, float))
+ METHOD(NexuizCampaignList, keyDown, float(entity, float, float, float))
+
+ ATTRIB(NexuizCampaignList, realFontSize, vector, '0 0 0')
+ ATTRIB(NexuizCampaignList, columnPreviewOrigin, float, 0)
+ ATTRIB(NexuizCampaignList, columnPreviewSize, float, 0)
+ ATTRIB(NexuizCampaignList, columnNameOrigin, float, 0)
+ ATTRIB(NexuizCampaignList, columnNameSize, float, 0)
+ ATTRIB(NexuizCampaignList, columnCheckMarkOrigin, float, 0)
+ ATTRIB(NexuizCampaignList, columnCheckMarkSize, float, 0)
+ ATTRIB(NexuizCampaignList, checkMarkOrigin, vector, '0 0 0')
+ ATTRIB(NexuizCampaignList, checkMarkSize, vector, '0 0 0')
+ ATTRIB(NexuizCampaignList, realUpperMargin1, float, 0)
+ ATTRIB(NexuizCampaignList, realUpperMargin2, float, 0)
+
+ ATTRIB(NexuizCampaignList, lastClickedMap, float, -1)
+ ATTRIB(NexuizCampaignList, lastClickedTime, float, 0)
+
+ ATTRIB(NexuizCampaignList, origin, vector, '0 0 0')
+ ATTRIB(NexuizCampaignList, itemAbsSize, vector, '0 0 0')
+ ATTRIB(NexuizCampaignList, emptyLineHeight, float, 0.5)
+
+ ATTRIB(NexuizCampaignList, campaignIndex, float, 0)
+ ATTRIB(NexuizCampaignList, cvarName, string, string_null)
+ METHOD(NexuizCampaignList, loadCvars, void(entity))
+ METHOD(NexuizCampaignList, saveCvars, void(entity))
+ENDCLASS(NexuizCampaignList)
+entity makeNexuizCampaignList();
+void CampaignList_LoadMap(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+string campaign_longdesc_wrapped[CAMPAIGN_MAX_ENTRIES];
+
+void rewrapCampaign(float w, float l0, float emptyheight)
+{
+ float i, j;
+ float n, take, cantake, l;
+ string r, s;
+ for(i = 0; i < campaign_entries; ++i)
+ {
+ l = l0;
+ if(campaign_longdesc_wrapped[i])
+ strunzone(campaign_longdesc_wrapped[i]);
+ n = tokenizebyseparator(campaign_longdesc[i], "\n");
+ r = "";
+ for(j = 0; j < n; ++j)
+ {
+ s = argv(j);
+ if(s == "")
+ {
+ l -= emptyheight;
+ r = strcat(r, "\n");
+ continue;
+ }
+ for(;;)
+ {
+ cantake = draw_TextLengthUpToWidth(s, w, 0);
+ if(cantake > 0 && cantake < strlen(s))
+ {
+ take = cantake - 1;
+ while(take > 0 && substring(s, take, 1) != " ")
+ --take;
+ if(take == 0)
+ {
+ if(--l < 0) goto toolong;
+ r = strcat(r, substring(s, 0, cantake), "\n");
+ s = substring(s, cantake, strlen(s) - cantake);
+ }
+ else
+ {
+ if(--l < 0) goto toolong;
+ r = strcat(r, substring(s, 0, take), "\n");
+ s = substring(s, take + 1, strlen(s) - take);
+ }
+ }
+ else
+ {
+ if(--l < 0) goto toolong;
+ r = strcat(r, s, "\n");
+ break;
+ }
+ }
+ }
+ goto nottoolong;
+:toolong
+ while(substring(r, strlen(r) - 1, 1) == "\n")
+ r = substring(r, 0, strlen(r) - 1);
+ r = strcat(r, "...\n");
+:nottoolong
+ campaign_longdesc_wrapped[i] = strzone(substring(r, 0, strlen(r) - 1));
+ }
+}
+
+entity makeNexuizCampaignList()
+{
+ entity me;
+ me = spawnNexuizCampaignList();
+ me.configureNexuizCampaignList(me);
+ return me;
+}
+void configureNexuizCampaignListNexuizCampaignList(entity me)
+{
+ me.configureNexuizListBox(me);
+ me.loadCvars(me);
+}
+
+void loadCvarsNexuizCampaignList(entity me)
+{
+ // read campaign cvars
+ if(campaign_name)
+ strunzone(campaign_name);
+ if(me.cvarName)
+ strunzone(me.cvarName);
+ campaign_name = strzone(cvar_string("g_campaign_name"));
+ me.cvarName = strzone(strcat("g_campaign", campaign_name, "_index"));
+ CampaignFile_Load(0, CAMPAIGN_MAX_ENTRIES);
+ me.campaignIndex = bound(0, cvar(me.cvarName), campaign_entries);
+ cvar_set(me.cvarName, ftos(me.campaignIndex));
+ if(me.columnNameSize)
+ rewrapCampaign(me.columnNameSize / me.realFontSize_x, me.rowsPerItem - 3, me.emptyLineHeight);
+ me.nItems = min(me.campaignIndex + 2, campaign_entries);
+ me.selectedItem = min(me.campaignIndex, me.nItems - 1);
+ me.scrollPos = me.nItems * me.itemHeight - 1;
+}
+
+void saveCvarsNexuizCampaignList(entity me)
+{
+ // write campaign cvars
+ cvar_set("g_campaign_name", campaign_name);
+ // cvar_set(me.cvarName, ftos(me.campaignIndex)); // NOTE: only server QC does that!
+}
+
+void drawNexuizCampaignList(entity me)
+{
+ if(cvar(me.cvarName) != me.campaignIndex || cvar_string("g_campaign_name") != campaign_name)
+ me.loadCvars(me);
+ drawListBox(me);
+}
+
+void resizeNotifyNexuizCampaignList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ me.origin = absOrigin;
+ me.itemAbsSize = '0 0 0';
+ resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
+
+ me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize_y * me.itemHeight));
+ me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize_x * (1 - me.controlWidth)));
+ me.realUpperMargin1 = 0.5 * me.realFontSize_y;
+ me.realUpperMargin2 = me.realUpperMargin1 + 2 * me.realFontSize_y;
+
+ me.checkMarkSize = (eX * (me.itemAbsSize_y / me.itemAbsSize_x) + eY) * 0.5;
+
+ me.columnPreviewOrigin = 0;
+ me.columnPreviewSize = me.itemAbsSize_y / me.itemAbsSize_x * 4 / 3;
+ me.columnCheckMarkSize = me.checkMarkSize_x;
+ me.columnNameSize = 1 - me.columnPreviewSize - me.columnCheckMarkSize - 4 * me.realFontSize_x;
+ me.columnNameOrigin = me.columnPreviewOrigin + me.columnPreviewSize + me.realFontSize_x;
+ me.columnCheckMarkOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x * 2;
+
+ me.checkMarkOrigin = eY + eX * (me.columnCheckMarkOrigin + me.columnCheckMarkSize) - me.checkMarkSize;
+
+ rewrapCampaign(me.columnNameSize / me.realFontSize_x, me.rowsPerItem - 3, me.emptyLineHeight);
+}
+void clickListBoxItemNexuizCampaignList(entity me, float i, vector where)
+{
+ if(i == me.lastClickedMap)
+ if(time < me.lastClickedTime + 0.3)
+ {
+ // DOUBLE CLICK!
+ // start game
+ CampaignList_LoadMap(me, me);
+ return;
+ }
+ me.lastClickedMap = i;
+ me.lastClickedTime = time;
+}
+void drawListBoxItemNexuizCampaignList(entity me, float i, vector absSize, float isSelected)
+{
+ string s;
+ float p;
+ vector theColor;
+ float theAlpha;
+ float j, n;
+ vector o;
+
+ if(i < me.campaignIndex)
+ {
+ theAlpha = SKINALPHA_CAMPAIGN_SELECTABLE;
+ theColor = SKINCOLOR_CAMPAIGN_SELECTABLE;
+ }
+ else if(i == me.campaignIndex)
+ {
+ theAlpha = SKINALPHA_CAMPAIGN_CURRENT;
+ theColor = SKINCOLOR_CAMPAIGN_CURRENT;
+ }
+ else
+ {
+ theAlpha = SKINALPHA_CAMPAIGN_FUTURE;
+ theColor = SKINCOLOR_CAMPAIGN_FUTURE;
+ }
+
+ if(isSelected)
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+ s = ftos(p);
+ draw_Picture(me.columnPreviewOrigin * eX, strcat("/maps/", campaign_mapname[i]), me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
+ if(i < me.campaignIndex)
+ draw_Picture(me.checkMarkOrigin, "checkmark", me.checkMarkSize, '1 1 1', 1);
+ if(i <= me.campaignIndex)
+ s = campaign_shortdesc[i]; // fteqcc sucks
+ else
+ s = "???";
+ s = draw_TextShortenToWidth(strcat("Level ", ftos(i + 1), ": ", s), me.columnNameSize / me.realFontSize_x, 0);
+ draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0) * me.realFontSize_x)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
+
+ if(i <= me.campaignIndex)
+ {
+ s = campaign_longdesc_wrapped[i];
+ n = tokenizebyseparator(s, "\n");
+ o = me.realUpperMargin2 * eY + me.columnNameOrigin * eX;
+ for(j = 0; j < n; ++j)
+ if(argv(j) != "")
+ {
+ draw_Text(o, argv(j), me.realFontSize, theColor, theAlpha * SKINALPHA_CAMPAIGN_DESCRIPTION, 0);
+ o_y += me.realFontSize_y;
+ }
+ else
+ o_y += me.realFontSize_y * me.emptyLineHeight;
+ }
+}
+void CampaignList_LoadMap(entity btn, entity me)
+{
+ if(me.selectedItem >= me.nItems || me.selectedItem < 0)
+ return;
+ CampaignSetup(me.selectedItem);
+}
+
+void setSelectedNexuizCampaignList(entity me, float i)
+{
+ // prevent too late items from being played
+ setSelectedListBox(me, min(i, me.campaignIndex));
+}
+
+float keyDownNexuizCampaignList(entity me, float scan, float ascii, float shift)
+{
+ if(scan == K_ENTER || scan == K_SPACE)
+ CampaignList_LoadMap(me, me);
+ else
+ return keyDownListBox(me, scan, ascii, shift);
+ return 1;
+}
+#endif
Added: trunk/menu/nexuiz/charmap.c
===================================================================
--- trunk/menu/nexuiz/charmap.c (rev 0)
+++ trunk/menu/nexuiz/charmap.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,130 @@
+#ifdef INTERFACE
+CLASS(NexuizCharmap) EXTENDS(Image)
+ METHOD(NexuizCharmap, configureNexuizCharmap, void(entity, entity))
+ METHOD(NexuizCharmap, mousePress, float(entity, vector))
+ METHOD(NexuizCharmap, mouseRelease, float(entity, vector))
+ METHOD(NexuizCharmap, mouseMove, float(entity, vector))
+ METHOD(NexuizCharmap, mouseDrag, float(entity, vector))
+ METHOD(NexuizCharmap, keyDown, float(entity, float, float, float))
+ METHOD(NexuizCharmap, draw, void(entity))
+ ATTRIB(NexuizCharmap, controlledTextbox, entity, NULL)
+ ATTRIB(NexuizCharmap, image, string, SKINGFX_CHARMAP)
+ ATTRIB(NexuizCharmap, image2, string, SKINGFX_CHARMAP_SELECTED)
+ ATTRIB(NexuizCharmap, focusable, float, 1)
+ ATTRIB(NexuizCharmap, previouslySelectedCharacterCell, float, -1)
+ ATTRIB(NexuizCharmap, selectedCharacterCell, float, 0)
+ ATTRIB(NexuizCharmap, mouseSelectedCharacterCell, float, -1)
+ENDCLASS(NexuizCharmap)
+entity makeNexuizCharmap(entity theTextbox);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizCharmap(entity theTextbox)
+{
+ entity me;
+ me = spawnNexuizCharmap();
+ me.configureNexuizCharmap(me, theTextbox);
+ return me;
+}
+
+string CharMap_CellToChar(float c)
+{
+ if(c == 13)
+ return chr(127);
+ else if(c < 32)
+ return chr(c);
+ else
+ return chr(c + 96);
+}
+
+void configureNexuizCharmapNexuizCharmap(entity me, entity theTextbox)
+{
+ me.controlledTextbox = theTextbox;
+ me.configureImage(me, me.image);
+}
+
+float mouseMoveNexuizCharmap(entity me, vector coords)
+{
+ float x, y, c;
+ x = floor(coords_x * 16);
+ y = floor(coords_y * 10);
+ if(x < 0 || y < 0 || x >= 16 || y >= 10)
+ {
+ me.mouseSelectedCharacterCell = -1;
+ return 0;
+ }
+ c = y * 16 + x;
+ if(c != me.mouseSelectedCharacterCell)
+ me.mouseSelectedCharacterCell = me.selectedCharacterCell = c;
+ return 1;
+}
+float mouseDragNexuizCharmap(entity me, vector coords)
+{
+ return me.mouseMove(me, coords);
+}
+float mousePressNexuizCharmap(entity me, vector coords)
+{
+ me.mouseMove(me, coords);
+ if(me.mouseSelectedCharacterCell >= 0)
+ {
+ me.pressed = 1;
+ me.previouslySelectedCharacterCell = me.selectedCharacterCell;
+ }
+ return 1;
+}
+float mouseReleaseNexuizCharmap(entity me, vector coords)
+{
+ if(!me.pressed)
+ return 0;
+ me.mouseMove(me, coords);
+ if(me.selectedCharacterCell == me.previouslySelectedCharacterCell)
+ me.controlledTextbox.enterText(me.controlledTextbox, CharMap_CellToChar(me.selectedCharacterCell));
+ me.pressed = 0;
+ return 1;
+}
+float keyDownNexuizCharmap(entity me, float key, float ascii, float shift)
+{
+ switch(key)
+ {
+ case K_LEFTARROW:
+ me.selectedCharacterCell = mod(me.selectedCharacterCell + 159, 160);
+ return 1;
+ case K_RIGHTARROW:
+ me.selectedCharacterCell = mod(me.selectedCharacterCell + 1, 160);
+ return 1;
+ case K_UPARROW:
+ me.selectedCharacterCell = mod(me.selectedCharacterCell + 144, 160);
+ return 1;
+ case K_DOWNARROW:
+ me.selectedCharacterCell = mod(me.selectedCharacterCell + 16, 160);
+ return 1;
+ case K_HOME:
+ me.selectedCharacterCell = 0;
+ return 1;
+ case K_END:
+ me.selectedCharacterCell = 159;
+ return 1;
+ case K_SPACE:
+ case K_ENTER:
+ case K_INS:
+ me.controlledTextbox.enterText(me.controlledTextbox, CharMap_CellToChar(me.selectedCharacterCell));
+ return 1;
+ default:
+ return me.controlledTextbox.keyDown(me.controlledTextbox, key, ascii, shift);
+ }
+}
+void drawNexuizCharmap(entity me)
+{
+ if(me.focused)
+ {
+ if(!me.pressed || (me.selectedCharacterCell == me.previouslySelectedCharacterCell))
+ {
+ vector c;
+ c = eX * (mod(me.selectedCharacterCell, 16) / 16.0);
+ c += eY * (floor(me.selectedCharacterCell / 16.0) / 10.0);
+ draw_Picture(c, me.image2, '0.0625 0.1 0', '1 1 1', 1);
+ }
+ }
+ drawImage(me);
+}
+#endif
Added: trunk/menu/nexuiz/checkbox.c
===================================================================
--- trunk/menu/nexuiz/checkbox.c (rev 0)
+++ trunk/menu/nexuiz/checkbox.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,87 @@
+#ifdef INTERFACE
+CLASS(NexuizCheckBox) EXTENDS(CheckBox)
+ METHOD(NexuizCheckBox, configureNexuizCheckBox, void(entity, float, string, string))
+ METHOD(NexuizCheckBox, setChecked, void(entity, float))
+ ATTRIB(NexuizCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizCheckBox, image, string, SKINGFX_CHECKBOX)
+ ATTRIB(NexuizCheckBox, inverted, float, 0)
+ // can be: 0 (off = 0, on = 1)
+ // 1 (off = 1, on = 0)
+ // 1+a (off = a, on = -a)
+ // -1-a (off = -a, on = a)
+
+ ATTRIB(NexuizCheckBox, color, vector, SKINCOLOR_CHECKBOX_N)
+ ATTRIB(NexuizCheckBox, colorC, vector, SKINCOLOR_CHECKBOX_C)
+ ATTRIB(NexuizCheckBox, colorF, vector, SKINCOLOR_CHECKBOX_F)
+ ATTRIB(NexuizCheckBox, colorD, vector, SKINCOLOR_CHECKBOX_D)
+
+ ATTRIB(NexuizCheckBox, cvarName, string, string_null)
+ METHOD(NexuizCheckBox, loadCvars, void(entity))
+ METHOD(NexuizCheckBox, saveCvars, void(entity))
+
+ ATTRIB(NexuizCheckBox, alpha, float, SKINALPHA_TEXT)
+ ATTRIB(NexuizCheckBox, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(NexuizCheckBox)
+entity makeNexuizCheckBox(float, string, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizCheckBox(float isInverted, string theCvar, string theText)
+{
+ entity me;
+ me = spawnNexuizCheckBox();
+ me.configureNexuizCheckBox(me, isInverted, theCvar, theText);
+ return me;
+}
+void configureNexuizCheckBoxNexuizCheckBox(entity me, float isInverted, string theCvar, string theText)
+{
+ me.inverted = isInverted;
+ me.checked = 0;
+ if(theCvar)
+ {
+ me.cvarName = theCvar;
+ me.loadCvars(me);
+ }
+ me.configureCheckBox(me, theText, me.fontSize, me.image);
+}
+void setCheckedNexuizCheckBox(entity me, float val)
+{
+ if(val != me.checked)
+ {
+ me.checked = val;
+ me.saveCvars(me);
+ }
+}
+void loadCvarsNexuizCheckBox(entity me)
+{
+ if(me.inverted == 0)
+ me.checked = cvar(me.cvarName);
+ else if(me.inverted == 1)
+ me.checked = !cvar(me.cvarName);
+ else if(me.inverted > 1)
+ me.checked = (cvar(me.cvarName) < 0);
+ else if(me.inverted < -1)
+ me.checked = (cvar(me.cvarName) > 0);
+}
+void saveCvarsNexuizCheckBox(entity me)
+{
+ if(me.inverted == 0)
+ cvar_set(me.cvarName, me.checked ? "1" : "0");
+ else if(me.inverted == 1)
+ cvar_set(me.cvarName, me.checked ? "0" : "1");
+ else if(me.inverted > 1)
+ {
+ if(me.checked)
+ cvar_set(me.cvarName, ftos(-(me.inverted - 1)));
+ else
+ cvar_set(me.cvarName, ftos(+(me.inverted - 1)));
+ }
+ else if(me.inverted < -1)
+ {
+ if(me.checked)
+ cvar_set(me.cvarName, ftos(-(me.inverted + 1)));
+ else
+ cvar_set(me.cvarName, ftos(+(me.inverted + 1)));
+ }
+}
+#endif
Added: trunk/menu/nexuiz/checkbox_slider_invalid.c
===================================================================
--- trunk/menu/nexuiz/checkbox_slider_invalid.c (rev 0)
+++ trunk/menu/nexuiz/checkbox_slider_invalid.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,63 @@
+#ifdef INTERFACE
+CLASS(NexuizSliderCheckBox) EXTENDS(CheckBox)
+ METHOD(NexuizSliderCheckBox, configureNexuizSliderCheckBox, void(entity, float, float, entity, string))
+ METHOD(NexuizSliderCheckBox, setChecked, void(entity, float))
+ METHOD(NexuizSliderCheckBox, draw, void(entity))
+ ATTRIB(NexuizSliderCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizSliderCheckBox, image, string, SKINGFX_CHECKBOX)
+
+ ATTRIB(NexuizSliderCheckBox, color, vector, SKINCOLOR_CHECKBOX_N)
+ ATTRIB(NexuizSliderCheckBox, colorC, vector, SKINCOLOR_CHECKBOX_C)
+ ATTRIB(NexuizSliderCheckBox, colorF, vector, SKINCOLOR_CHECKBOX_F)
+ ATTRIB(NexuizSliderCheckBox, colorD, vector, SKINCOLOR_CHECKBOX_D)
+
+ ATTRIB(NexuizSliderCheckBox, alpha, float, SKINALPHA_TEXT)
+ ATTRIB(NexuizSliderCheckBox, disabledAlpha, float, SKINALPHA_DISABLED)
+
+ ATTRIB(NexuizSliderCheckBox, controlledSlider, entity, NULL)
+ ATTRIB(NexuizSliderCheckBox, offValue, float, -1)
+ ATTRIB(NexuizSliderCheckBox, inverted, float, 0)
+ ATTRIB(NexuizSliderCheckBox, savedValue, float, -1)
+ENDCLASS(NexuizSliderCheckBox)
+entity makeNexuizSliderCheckBox(float, float, entity, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizSliderCheckBox(float theOffValue, float isInverted, entity theControlledSlider, string theText)
+{
+ entity me;
+ me = spawnNexuizSliderCheckBox();
+ me.configureNexuizSliderCheckBox(me, theOffValue, isInverted, theControlledSlider, theText);
+ return me;
+}
+void configureNexuizSliderCheckBoxNexuizSliderCheckBox(entity me, float theOffValue, float isInverted, entity theControlledSlider, string theText)
+{
+ me.offValue = theOffValue;
+ me.inverted = isInverted;
+ me.checked = (theControlledSlider.value == theOffValue);
+ if(theControlledSlider.value == median(theControlledSlider.valueMin, theControlledSlider.value, theControlledSlider.valueMax))
+ me.savedValue = theControlledSlider.value;
+ else
+ me.savedValue = theControlledSlider.valueMin;
+ me.controlledSlider = theControlledSlider;
+ me.configureCheckBox(me, theText, me.fontSize, me.image);
+}
+void drawNexuizSliderCheckBox(entity me)
+{
+ me.checked = ((me.controlledSlider.value == me.offValue) != me.inverted);
+ if(me.controlledSlider.value == median(me.controlledSlider.valueMin, me.controlledSlider.value, me.controlledSlider.valueMax))
+ me.savedValue = me.controlledSlider.value;
+ drawCheckBox(me);
+}
+void setCheckedNexuizSliderCheckBox(entity me, float val)
+{
+ if(me.checked == val)
+ return;
+ me.checked = val;
+ if(val == me.inverted)
+ me.controlledSlider.setValue(me.controlledSlider, median(me.controlledSlider.valueMin, me.savedValue, me.controlledSlider.valueMax));
+ else
+ me.controlledSlider.setValue(me.controlledSlider, me.offValue);
+}
+
+#endif
Added: trunk/menu/nexuiz/colorbutton.c
===================================================================
--- trunk/menu/nexuiz/colorbutton.c (rev 0)
+++ trunk/menu/nexuiz/colorbutton.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,70 @@
+#ifdef INTERFACE
+CLASS(NexuizColorButton) EXTENDS(RadioButton)
+ METHOD(NexuizColorButton, configureNexuizColorButton, void(entity, float, float, float))
+ METHOD(NexuizColorButton, setChecked, void(entity, float))
+ METHOD(NexuizColorButton, draw, void(entity))
+ ATTRIB(NexuizColorButton, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizColorButton, image, string, SKINGFX_COLORBUTTON)
+ ATTRIB(NexuizColorButton, image2, string, SKINGFX_COLORBUTTON_COLOR)
+
+ ATTRIB(NexuizColorButton, useDownAsChecked, float, 1)
+
+ ATTRIB(NexuizColorButton, cvarPart, float, 0)
+ ATTRIB(NexuizColorButton, cvarName, string, string_null)
+ ATTRIB(NexuizColorButton, cvarValueFloat, float, 0)
+ METHOD(NexuizColorButton, loadCvars, void(entity))
+ METHOD(NexuizColorButton, saveCvars, void(entity))
+ENDCLASS(NexuizColorButton)
+entity makeNexuizColorButton(float, float, float);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizColorButton(float theGroup, float theColor, float theValue)
+{
+ entity me;
+ me = spawnNexuizColorButton();
+ me.configureNexuizColorButton(me, theGroup, theColor, theValue);
+ return me;
+}
+void configureNexuizColorButtonNexuizColorButton(entity me, float theGroup, float theColor, float theValue)
+{
+ me.cvarName = "_cl_color";
+ me.cvarValueFloat = theValue;
+ me.cvarPart = theColor;
+ me.loadCvars(me);
+ me.configureRadioButton(me, string_null, me.fontSize, me.image, theGroup, 0);
+ me.srcMulti = 1;
+ me.src2 = me.image2;
+}
+void setCheckedNexuizColorButton(entity me, float val)
+{
+ if(val != me.checked)
+ {
+ me.checked = val;
+ me.saveCvars(me);
+ }
+}
+void loadCvarsNexuizColorButton(entity me)
+{
+ if(me.cvarPart == 1)
+ me.checked = (cvar(me.cvarName) & 240) == me.cvarValueFloat * 16;
+ else
+ me.checked = (cvar(me.cvarName) & 15) == me.cvarValueFloat;
+}
+void saveCvarsNexuizColorButton(entity me)
+{
+ if(me.checked)
+ {
+ if(me.cvarPart == 1)
+ cvar_set(me.cvarName, ftos(cvar(me.cvarName) & 15 + me.cvarValueFloat * 16));
+ else
+ cvar_set(me.cvarName, ftos(cvar(me.cvarName) & 240 + me.cvarValueFloat));
+ }
+ // TODO on an apply button, read _cl_color and execute the color command for it
+}
+void drawNexuizColorButton(entity me)
+{
+ me.color2 = colormapPaletteColor(me.cvarValueFloat, me.cvarPart);
+ drawCheckBox(me);
+}
+#endif
Added: trunk/menu/nexuiz/commandbutton.c
===================================================================
--- trunk/menu/nexuiz/commandbutton.c (rev 0)
+++ trunk/menu/nexuiz/commandbutton.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,44 @@
+#ifndef COMMANDBUTTON_CLOSE
+# define COMMANDBUTTON_CLOSE 1
+# define COMMANDBUTTON_APPLY 2
+//# define COMMANDBUTTON_REVERT 4
+#endif
+
+#ifdef INTERFACE
+CLASS(NexuizCommandButton) EXTENDS(NexuizButton)
+ METHOD(NexuizCommandButton, configureNexuizCommandButton, void(entity, string, vector, string, float))
+ ATTRIB(NexuizCommandButton, onClickCommand, string, string_null)
+ ATTRIB(NexuizCommandButton, flags, float, 0)
+ENDCLASS(NexuizCommandButton)
+entity makeNexuizCommandButton(string theText, vector theColor, string theCommand, float closesMenu);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizCommandButton(string theText, vector theColor, string theCommand, float theFlags)
+{
+ entity me;
+ me = spawnNexuizCommandButton();
+ me.configureNexuizCommandButton(me, theText, theColor, theCommand, theFlags);
+ return me;
+}
+
+void NexuizCommandButton_Click(entity me, entity other)
+{
+ //if(me.flags & COMMANDBUTTON_APPLY)
+ // saveAllCvars(me.parent);
+ cmd("\n", me.onClickCommand, "\n");
+ //if(me.flags & COMMANDBUTTON_REVERT)
+ // loadAllCvars(me.parent);
+ if(me.flags & COMMANDBUTTON_CLOSE)
+ m_goto(string_null);
+}
+
+void configureNexuizCommandButtonNexuizCommandButton(entity me, string theText, vector theColor, string theCommand, float theFlags)
+{
+ me.configureNexuizButton(me, theText, theColor);
+ me.onClickCommand = theCommand;
+ me.flags = theFlags;
+ me.onClick = NexuizCommandButton_Click;
+ me.onClickEntity = me;
+}
+#endif
Added: trunk/menu/nexuiz/credits.c
===================================================================
--- trunk/menu/nexuiz/credits.c (rev 0)
+++ trunk/menu/nexuiz/credits.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,106 @@
+#ifdef INTERFACE
+CLASS(NexuizCreditsList) EXTENDS(NexuizListBox)
+ METHOD(NexuizCreditsList, configureNexuizCreditsList, void(entity))
+ ATTRIB(NexuizCreditsList, rowsPerItem, float, 1)
+ METHOD(NexuizCreditsList, draw, void(entity))
+ METHOD(NexuizCreditsList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(NexuizCreditsList, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(NexuizCreditsList, keyDown, float(entity, float, float, float))
+
+ ATTRIB(NexuizCreditsList, realFontSize, vector, '0 0 0')
+ ATTRIB(NexuizCreditsList, realUpperMargin, float, 0)
+ ATTRIB(NexuizCreditsList, bufferIndex, float, 0)
+ ATTRIB(NexuizCreditsList, scrolling, float, 0)
+ENDCLASS(NexuizCreditsList)
+entity makeNexuizCreditsList();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizCreditsList()
+{
+ entity me;
+ me = spawnNexuizCreditsList();
+ me.configureNexuizCreditsList(me);
+ return me;
+}
+void configureNexuizCreditsListNexuizCreditsList(entity me)
+{
+ me.configureNexuizListBox(me);
+ // load the file
+ me.bufferIndex = buf_load("nexuiz-credits.txt");
+ me.nItems = buf_getsize(me.bufferIndex);
+}
+void drawNexuizCreditsList(entity me)
+{
+ float i;
+ if(me.scrolling)
+ {
+ me.scrollPos = bound(0, (time - me.scrolling) * me.itemHeight, me.nItems * me.itemHeight - 1);
+ i = min(me.selectedItem, floor((me.scrollPos + 1) / me.itemHeight - 1));
+ i = max(i, ceil(me.scrollPos / me.itemHeight));
+ me.setSelected(me, i);
+ }
+ drawListBox(me);
+}
+void resizeNotifyNexuizCreditsList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
+
+ me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
+ me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
+ me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+}
+void drawListBoxItemNexuizCreditsList(entity me, float i, vector absSize, float isSelected)
+{
+ // layout: Ping, Credits name, Map name, NP, TP, MP
+ string s;
+ float theAlpha;
+ vector theColor;
+
+ s = bufstr_get(me.bufferIndex, i);
+
+ if(substring(s, 0, 2) == "**")
+ {
+ s = substring(s, 2, strlen(s) - 2);
+ theColor = SKINCOLOR_CREDITS_TITLE;
+ theAlpha = SKINALPHA_CREDITS_TITLE;
+ }
+ else if(substring(s, 0, 1) == "*")
+ {
+ s = substring(s, 1, strlen(s) - 1);
+ theColor = SKINCOLOR_CREDITS_FUNCTION;
+ theAlpha = SKINALPHA_CREDITS_FUNCTION;
+ }
+ else
+ {
+ theColor = SKINCOLOR_CREDITS_PERSON;
+ theAlpha = SKINALPHA_CREDITS_PERSON;
+ }
+
+ draw_CenterText(me.realUpperMargin * eY + 0.5 * eX, s, me.realFontSize, theColor, theAlpha, 0);
+}
+
+float keyDownNexuizCreditsList(entity me, float scan, float ascii, float shift)
+{
+ float i;
+ me.dragScrollTimer = time;
+ me.scrolling = 0;
+
+ if(scan == K_PGUP)
+ me.scrollPos = max(me.scrollPos - 0.5, 0);
+ else if(scan == K_PGDN)
+ me.scrollPos = min(me.scrollPos + 0.5, me.nItems * me.itemHeight - 1);
+ else if(scan == K_UPARROW)
+ me.scrollPos = max(me.scrollPos - me.itemHeight, 0);
+ else if(scan == K_DOWNARROW)
+ me.scrollPos = min(me.scrollPos + me.itemHeight, me.nItems * me.itemHeight - 1);
+ else
+ return keyDownListBox(me, scan, ascii, shift);
+
+ i = min(me.selectedItem, floor((me.scrollPos + 1) / me.itemHeight - 1));
+ i = max(i, ceil(me.scrollPos / me.itemHeight));
+ me.setSelected(me, i);
+
+ return 1;
+}
+#endif
Added: trunk/menu/nexuiz/crosshairbutton.c
===================================================================
--- trunk/menu/nexuiz/crosshairbutton.c (rev 0)
+++ trunk/menu/nexuiz/crosshairbutton.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,66 @@
+#ifdef INTERFACE
+CLASS(NexuizCrosshairButton) EXTENDS(RadioButton)
+ METHOD(NexuizCrosshairButton, configureNexuizCrosshairButton, void(entity, float, float))
+ METHOD(NexuizCrosshairButton, setChecked, void(entity, float))
+ METHOD(NexuizCrosshairButton, draw, void(entity))
+ ATTRIB(NexuizCrosshairButton, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizCrosshairButton, image, string, SKINGFX_CROSSHAIRBUTTON)
+
+ ATTRIB(NexuizCrosshairButton, useDownAsChecked, float, 1)
+
+ ATTRIB(NexuizCrosshairButton, cvarName, string, string_null)
+ ATTRIB(NexuizCrosshairButton, cvarValueFloat, float, 0)
+ METHOD(NexuizCrosshairButton, loadCvars, void(entity))
+ METHOD(NexuizCrosshairButton, saveCvars, void(entity))
+ENDCLASS(NexuizCrosshairButton)
+entity makeNexuizCrosshairButton(float, float);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizCrosshairButton(float theGroup, float theCrosshair)
+{
+ entity me;
+ me = spawnNexuizCrosshairButton();
+ me.configureNexuizCrosshairButton(me, theGroup, theCrosshair);
+ return me;
+}
+void configureNexuizCrosshairButtonNexuizCrosshairButton(entity me, float theGroup, float theCrosshair)
+{
+ me.cvarName = "crosshair";
+ me.cvarValueFloat = theCrosshair;
+ me.loadCvars(me);
+ me.configureRadioButton(me, string_null, me.fontSize, me.image, theGroup, 0);
+ me.srcMulti = 1;
+ me.src2 = strzone(strcat("/gfx/crosshair", ftos(me.cvarValueFloat)));
+}
+void setCheckedNexuizCrosshairButton(entity me, float val)
+{
+ if(val != me.checked)
+ {
+ me.checked = val;
+ me.saveCvars(me);
+ }
+}
+void loadCvarsNexuizCrosshairButton(entity me)
+{
+ me.checked = (cvar(me.cvarName) == me.cvarValueFloat);
+}
+void saveCvarsNexuizCrosshairButton(entity me)
+{
+ if(me.checked)
+ cvar_set(me.cvarName, ftos(me.cvarValueFloat));
+ // TODO on an apply button, read _cl_color and execute the color command for it
+}
+void drawNexuizCrosshairButton(entity me)
+{
+ me.color2 = eX * cvar("crosshair_color_red") + eY * cvar("crosshair_color_green") + eZ * cvar("crosshair_color_blue");
+ me.alpha2 = cvar("crosshair_color_alpha");
+ me.src2scale = min((draw_PictureSize(me.src2) * eY * cvar("crosshair_size")) / me.size_y, (draw_PictureSize(me.src2) * eX * cvar("crosshair_size")) / me.size_x, 0.8);
+ if(!me.checked && !me.focused)
+ {
+ me.alpha2 *= me.disabledAlpha;
+ me.color2 = '1 1 1';
+ }
+ drawCheckBox(me);
+}
+#endif
Added: trunk/menu/nexuiz/dialog.c
===================================================================
--- trunk/menu/nexuiz/dialog.c (rev 0)
+++ trunk/menu/nexuiz/dialog.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,32 @@
+#ifdef INTERFACE
+CLASS(NexuizDialog) EXTENDS(Dialog)
+ // still to be customized by user
+ /*
+ ATTRIB(NexuizDialog, closable, float, 1)
+ ATTRIB(NexuizDialog, title, string, "Form1") // ;)
+ ATTRIB(NexuizDialog, color, vector, '1 0.5 1')
+ ATTRIB(NexuizDialog, intendedWidth, float, 0)
+ ATTRIB(NexuizDialog, rows, float, 3)
+ ATTRIB(NexuizDialog, columns, float, 2)
+ */
+ ATTRIB(NexuizDialog, marginTop, float, SKINMARGIN_TOP) // pixels
+ ATTRIB(NexuizDialog, marginBottom, float, SKINMARGIN_BOTTOM) // pixels
+ ATTRIB(NexuizDialog, marginLeft, float, SKINMARGIN_LEFT) // pixels
+ ATTRIB(NexuizDialog, marginRight, float, SKINMARGIN_RIGHT) // pixels
+ ATTRIB(NexuizDialog, columnSpacing, float, SKINMARGIN_COLUMNS) // pixels
+ ATTRIB(NexuizDialog, rowSpacing, float, SKINMARGIN_ROWS) // pixels
+ ATTRIB(NexuizDialog, rowHeight, float, SKINFONTSIZE_NORMAL * SKINHEIGHT_NORMAL) // pixels
+ ATTRIB(NexuizDialog, titleHeight, float, SKINFONTSIZE_TITLE * SKINHEIGHT_TITLE) // pixels
+ ATTRIB(NexuizDialog, titleFontSize, float, SKINFONTSIZE_TITLE) // pixels
+
+ ATTRIB(NexuizDialog, backgroundImage, string, SKINGFX_DIALOGBORDER)
+ ATTRIB(NexuizDialog, closeButtonImage, string, SKINGFX_CLOSEBUTTON)
+ ATTRIB(NexuizDialog, zoomedOutTitleBarPosition, float, SKINHEIGHT_ZOOMEDTITLE * 0.5 - 0.5)
+ ATTRIB(NexuizDialog, zoomedOutTitleBar, float, SKINHEIGHT_ZOOMEDTITLE != 0)
+
+ ATTRIB(NexuizDialog, alpha, float, SKINALPHA_TEXT)
+ENDCLASS(NexuizDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+#endif
Added: trunk/menu/nexuiz/dialog_classselect.c
===================================================================
--- trunk/menu/nexuiz/dialog_classselect.c (rev 0)
+++ trunk/menu/nexuiz/dialog_classselect.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,53 @@
+#ifdef INTERFACE
+CLASS(NexuizClassSelectDialog) EXTENDS(NexuizRootDialog)
+ METHOD(NexuizClassSelectDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
+ METHOD(NexuizClassSelectDialog, showNotify, void(entity))
+ ATTRIB(NexuizClassSelectDialog, title, string, "Class Selection") // ;)
+ ATTRIB(NexuizClassSelectDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+ ATTRIB(NexuizClassSelectDialog, intendedWidth, float, 0.4)
+ ATTRIB(NexuizClassSelectDialog, rows, float, 5)
+ ATTRIB(NexuizClassSelectDialog, columns, float, 4)
+ ATTRIB(NexuizClassSelectDialog, name, string, "ClassSelect")
+ ATTRIB(NexuizClassSelectDialog, text1, entity, NULL)
+ ATTRIB(NexuizClassSelectDialog, text2, entity, NULL)
+ ATTRIB(NexuizClassSelectDialog, class1, entity, NULL)
+ ATTRIB(NexuizClassSelectDialog, class2, entity, NULL)
+ ATTRIB(NexuizClassSelectDialog, class3, entity, NULL)
+ ATTRIB(NexuizClassSelectDialog, class4, entity, NULL)
+ENDCLASS(NexuizClassSelectDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeClassButton(string theName, vector theColor, string commandtheName)
+{
+ entity b;
+ b = makeNexuizCommandButton(theName, theColor, commandtheName, 1);
+ return b;
+}
+
+void showNotifyNexuizClassSelectDialog(entity me)
+{
+ float classes, nClasses;
+ classes = cvar("_classes_available");
+ nClasses = 0;
+ me.class1.disabled = !(classes & 1); nClasses += !!(classes & 1);
+ me.class2.disabled = !(classes & 2); nClasses += !!(classes & 2);
+ me.class3.disabled = !(classes & 4); nClasses += !!(classes & 4);
+ me.class4.disabled = !(classes & 8); nClasses += !!(classes & 8);
+}
+
+void fillNexuizClassSelectDialog(entity me)
+{
+ me.TR(me);
+ me.TD(me, 1, 1, me.text1 = makeNexuizTextLabel(0, "Offensive:"));
+ me.TD(me, 2, 1, me.class1 = makeTeamButton("Commando", '1 0.5 0.5', "cmd selectclass 1; cmd join;"));
+ me.TD(me, 2, 1, me.class2 = makeTeamButton("Enforcer", '0.5 0.5 1', "cmd selectclass 2; cmd join;"));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, me.text2 = makeNexuizTextLabel(0, "Defensive:"));
+ me.TD(me, 2, 1, me.class3 = makeTeamButton("Techie", '1 1 0.5', "cmd selectclass 3; cmd join;"));
+ me.TD(me, 2, 1, me.class4 = makeTeamButton("Heavy", '1 0.5 1', "cmd selectclass 4; cmd join;"));
+}
+#endif
+
+// click. The C-word so you can grep for it.
Added: trunk/menu/nexuiz/dialog_credits.c
===================================================================
--- trunk/menu/nexuiz/dialog_credits.c (rev 0)
+++ trunk/menu/nexuiz/dialog_credits.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,29 @@
+#ifdef INTERFACE
+CLASS(NexuizCreditsDialog) EXTENDS(NexuizDialog)
+ METHOD(NexuizCreditsDialog, fill, void(entity))
+ METHOD(NexuizCreditsDialog, focusEnter, void(entity))
+ ATTRIB(NexuizCreditsDialog, title, string, "Credits")
+ ATTRIB(NexuizCreditsDialog, color, vector, SKINCOLOR_DIALOG_CREDITS)
+ ATTRIB(NexuizCreditsDialog, intendedWidth, float, SKINWIDTH_CREDITS)
+ ATTRIB(NexuizCreditsDialog, rows, float, SKINROWS_CREDITS)
+ ATTRIB(NexuizCreditsDialog, columns, float, 2)
+ ATTRIB(NexuizCreditsDialog, creditsList, entity, NULL)
+ENDCLASS(NexuizCreditsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void fillNexuizCreditsDialog(entity me)
+{
+ entity e;
+ me.TR(me);
+ me.TD(me, me.rows - 1, me.columns, me.creditsList = makeNexuizCreditsList());
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, e = makeNexuizButton("OK", '0 0 0'));
+ e.onClick = Dialog_Close;
+ e.onClickEntity = me;
+}
+void focusEnterNexuizCreditsDialog(entity me)
+{
+ me.creditsList.scrolling = time + 1;
+}
+#endif
Added: trunk/menu/nexuiz/dialog_infoscreen.c
===================================================================
--- trunk/menu/nexuiz/dialog_infoscreen.c (rev 0)
+++ trunk/menu/nexuiz/dialog_infoscreen.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,34 @@
+#ifdef INTERFACE
+CLASS(NexuizInfoScreenDialog) EXTENDS(NexuizRootDialog)
+ METHOD(NexuizInfoScreenDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
+ METHOD(NexuizInfoScreenDialog, showNotify, void(entity))
+ ATTRIB(NexuizInfoScreenDialog, title, string, "MISSION OBJECTIVE:") // ;)
+ ATTRIB(NexuizInfoScreenDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+ ATTRIB(NexuizInfoScreenDialog, intendedWidth, float, 0.4)
+ ATTRIB(NexuizInfoScreenDialog, rows, float, 5)
+ ATTRIB(NexuizInfoScreenDialog, columns, float, 4)
+ ATTRIB(NexuizInfoScreenDialog, name, string, "InfoScreen")
+ ATTRIB(NexuizTeamSelectDialog, okay1, entity, NULL)
+ENDCLASS(NexuizInfoScreenDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+
+void showNotifyNexuizInfoScreenDialog(entity me)
+{
+
+}
+
+void fillNexuizInfoScreenDialog(entity me)
+{
+ me.TR(me);
+ me.TD(me, 1, 1, me.text1 = makeNexuizTextLabel(0, "Destroy the 5 power stations throughout the level"));
+ me.TR(me);
+ me.TR(me);
+ me.TR(me);
+ me.TDempty(me, (me.columns - 1) / 2);
+ me.TD(me, 2, 1, me.okay1 = makeNexuizCommandButton("Start", '1 1 1', "",1));
+}
+#endif
+
+// click. The C-word so you can grep for it.
Added: trunk/menu/nexuiz/dialog_multiplayer.c
===================================================================
--- trunk/menu/nexuiz/dialog_multiplayer.c (rev 0)
+++ trunk/menu/nexuiz/dialog_multiplayer.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,29 @@
+#ifdef INTERFACE
+CLASS(NexuizMultiplayerDialog) EXTENDS(NexuizDialog)
+ METHOD(NexuizMultiplayerDialog, fill, void(entity))
+ ATTRIB(NexuizMultiplayerDialog, title, string, "Multiplayer")
+ ATTRIB(NexuizMultiplayerDialog, color, vector, SKINCOLOR_DIALOG_MULTIPLAYER)
+ ATTRIB(NexuizMultiplayerDialog, intendedWidth, float, 0.96)
+ ATTRIB(NexuizMultiplayerDialog, rows, float, 24)
+ ATTRIB(NexuizMultiplayerDialog, columns, float, 6)
+ENDCLASS(NexuizMultiplayerDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void fillNexuizMultiplayerDialog(entity me)
+{
+ entity mc, e;
+ mc = makeNexuizTabController(me.rows - 2);
+ me.TR(me);
+ me.TD(me, 1, 1, e = mc.makeTabButton(mc, "Join", makeNexuizServerListTab()));
+ setDependentStringNotEqual(e, "_cl_name", "Player");
+ me.TD(me, 1, 1, e = mc.makeTabButton(mc, "Player Setup", makeNexuizPlayerSettingsTab()));
+ if(cvar_string("_cl_name") == "Player")
+ e.onClick(e, e.onClickEntity); // lol animation
+ me.TD(me, 1, 1, e = mc.makeTabButton(mc, "Create", makeNexuizServerCreateTab()));
+ setDependentStringNotEqual(e, "_cl_name", "Player");
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, me.rows - 2, me.columns, mc);
+}
+#endif
Added: trunk/menu/nexuiz/dialog_multiplayer_create.c
===================================================================
--- trunk/menu/nexuiz/dialog_multiplayer_create.c (rev 0)
+++ trunk/menu/nexuiz/dialog_multiplayer_create.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,192 @@
+#ifdef INTERFACE
+CLASS(NexuizServerCreateTab) EXTENDS(NexuizTab)
+ METHOD(NexuizServerCreateTab, fill, void(entity))
+ METHOD(NexuizServerCreateTab, gameTypeChangeNotify, void(entity))
+ ATTRIB(NexuizServerCreateTab, title, string, "Create")
+ ATTRIB(NexuizServerCreateTab, intendedWidth, float, 0.9)
+ ATTRIB(NexuizServerCreateTab, rows, float, 22)
+ ATTRIB(NexuizServerCreateTab, columns, float, 6.5)
+
+ ATTRIB(NexuizServerCreateTab, mapListBox, entity, NULL)
+ ATTRIB(NexuizServerCreateTab, sliderFraglimit, entity, NULL)
+ ATTRIB(NexuizServerCreateTab, sliderTimelimit, entity, NULL)
+ ATTRIB(NexuizServerCreateTab, checkboxFraglimit, entity, NULL)
+ENDCLASS(NexuizServerCreateTab)
+entity makeNexuizServerCreateTab();
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeNexuizServerCreateTab()
+{
+ entity me;
+ me = spawnNexuizServerCreateTab();
+ me.configureDialog(me);
+ return me;
+}
+
+void fillNexuizServerCreateTab(entity me)
+{
+ entity e, e0;
+ float n;
+
+ me.TR(me);
+ n = 8 + 2 * !!cvar("developer");
+ me.TD(me, 2, me.columns / n, e = makeNexuizGametypeButton(1, "g_dm", "DM"));
+ e0 = e;
+ me.TD(me, 2, me.columns / n, e = makeNexuizGametypeButton(1, "g_tdm", "TDM"));
+ if(e.checked) e0 = NULL;
+ me.TD(me, 2, me.columns / n, e = makeNexuizGametypeButton(1, "g_lms", "LMS"));
+ if(e.checked) e0 = NULL;
+ me.TD(me, 2, me.columns / n, e = makeNexuizGametypeButton(1, "g_arena", "Arena"));
+ if(e.checked) e0 = NULL;
+ me.TD(me, 2, me.columns / n, e = makeNexuizGametypeButton(1, "g_runematch", "Rune"));
+ if(e.checked) e0 = NULL;
+ me.TD(me, 2, me.columns / n, e = makeNexuizGametypeButton(1, "g_domination", "Dom"));
+ if(e.checked) e0 = NULL;
+ me.TD(me, 2, me.columns / n, e = makeNexuizGametypeButton(1, "g_keyhunt", "Key Hunt"));
+ if(e.checked) e0 = NULL;
+ me.TD(me, 2, me.columns / n, e = makeNexuizGametypeButton(1, "g_ctf", "CTF"));
+ if(e.checked) e0 = NULL;
+ if(cvar("developer"))
+ {
+ me.TD(me, 2, me.columns / n, e = makeNexuizGametypeButton(1, "g_assault", "Assault"));
+ if(e.checked) e0 = NULL;
+ me.TD(me, 2, me.columns / n, e = makeNexuizGametypeButton(1, "g_onslaught", "Onslaught"));
+ if(e.checked) e0 = NULL;
+ }
+ if(e0)
+ {
+ //print("NO CHECK\n");
+ e0.setChecked(e0, 1);
+ }
+ me.TR(me);
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizTextLabel(0, "Map list:"));
+ me.TR(me);
+ me.TD(me, me.rows - 7, 3, e = makeNexuizMapList());
+ me.mapListBox = e;
+ me.gotoRC(me, me.rows - 3, 0);
+ me.TDempty(me, 0.5);
+ me.TD(me, 1, 1, e = makeNexuizButton("All", '0 0 0'));
+ e.onClick = MapList_All;
+ e.onClickEntity = me.mapListBox;
+ me.TD(me, 1, 1, e = makeNexuizButton("None", '0 0 0'));
+ e.onClick = MapList_None;
+ e.onClickEntity = me.mapListBox;
+ me.TDempty(me, 0.5);
+
+ me.gotoRC(me, 3, 3.5); me.setFirstColumn(me, me.currentColumn);
+ me.TD(me, 1, 3, e = makeNexuizTextLabel(0, "Settings:"));
+ me.TR(me);
+ me.sliderTimelimit = makeNexuizSlider(1.0, 60.0, 0.5, "timelimit_override");
+ me.TD(me, 1, 1, e = makeNexuizSliderCheckBox(0, 1, me.sliderTimelimit, "Time limit:"));
+ me.TD(me, 1, 2, me.sliderTimelimit);
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 2.8, e = makeNexuizSliderCheckBox(-1, 0, me.sliderTimelimit, "Use map specified default"));
+ me.TR(me);
+ me.sliderFraglimit = makeNexuizSlider(1.0, 2000.0, 5, "fraglimit_override");
+ me.TD(me, 1, 1, e = makeNexuizSliderCheckBox(0, 1, me.sliderFraglimit, "Point limit:"));
+ me.checkboxFraglimit = e;
+ me.TD(me, 1, 2, me.sliderFraglimit);
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 2.8, e = makeNexuizSliderCheckBox(-1, 0, me.sliderFraglimit, "Use map specified default"));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "g_antilag", "AntiLag"));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Map voting:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("g_maplist_votable"));
+ e.addValue(e, "No voting", "0");
+ e.addValue(e, "2 choices", "2");
+ e.addValue(e, "3 choices", "3");
+ e.addValue(e, "4 choices", "4");
+ e.addValue(e, "5 choices", "5");
+ e.addValue(e, "6 choices", "6");
+ e.addValue(e, "7 choices", "7");
+ e.configureNexuizTextSliderValues(e);
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "sv_vote_simple_majority", "Simple majority wins vcall"));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Number of players:"));
+ me.TD(me, 1, 2, makeNexuizSlider(1, 32, 1, "menu_maxplayers"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Number of bots:"));
+ me.TD(me, 1, 2, makeNexuizSlider(0, 7, 1, "bot_number"));
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 0.8, e = makeNexuizTextLabel(0, "Bot skill:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("skill"));
+ e.addValue(e, "Botlike", "0");
+ e.addValue(e, "Beginner", "1");
+ e.addValue(e, "You will win", "2");
+ e.addValue(e, "You can win", "3");
+ e.addValue(e, "You might win", "4");
+ e.addValue(e, "Advanced", "5");
+ e.addValue(e, "Expert", "6");
+ e.addValue(e, "Pro", "7");
+ e.addValue(e, "Assassin", "8");
+ e.addValue(e, "Unhuman", "9");
+ e.addValue(e, "Godlike", "10");
+ e.configureNexuizTextSliderValues(e);
+ setDependent(e, "bot_number", 0, -1);
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 0.8, e = makeNexuizTextLabel(0, "Bot names:"));
+ me.TD(me, 1, 0.7, e = makeNexuizInputBox(1, "bot_prefix"));
+ setDependent(e, "bot_number", 0, -1);
+ me.TD(me, 1, 0.6, e = makeNexuizTextLabel(0.5, "Spellbinder"));
+ setDependent(e, "bot_number", 0, -1);
+ me.TD(me, 1, 0.7, e = makeNexuizInputBox(1, "bot_suffix"));
+ setDependent(e, "bot_number", 0, -1);
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizButton("Mutators...", '0 0 0'));
+ e.onClick = DialogOpenButton_Click;
+ e.onClickEntity = main.mutatorsDialog;
+ main.mutatorsDialog.refilterEntity = me.mapListBox;
+ me.TD(me, 1, 2, e0 = makeNexuizTextLabel(0, string_null));
+ e0.textEntity = main.mutatorsDialog;
+ e0.allowCut = 1;
+
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, e = makeNexuizButton("Start!", '0 0 0'));
+ e.onClick = MapList_LoadMap;
+ e.onClickEntity = me.mapListBox;
+ me.mapListBox.startButton = e;
+
+ me.gameTypeChangeNotify(me);
+}
+
+void GameType_ConfigureSliders(entity e, entity l, string pLabel, float pMin, float pMax, float pStep, string pCvar)
+{
+ e.configureNexuizSlider(e, pMin, pMax, pStep, pCvar);
+ l.setText(l, pLabel);
+}
+
+void gameTypeChangeNotifyNexuizServerCreateTab(entity me)
+{
+ // tell the map list to update
+ float gt;
+ entity e, l;
+ gt = MapInfo_CurrentGametype();
+ e = me.sliderFraglimit;
+ l = me.checkboxFraglimit;
+ switch(gt)
+ {
+ case MAPINFO_TYPE_CTF: GameType_ConfigureSliders(e, l, "Point limit:", 50, 500, 10, "g_ctf_capture_limit"); break;
+ case MAPINFO_TYPE_DOMINATION: GameType_ConfigureSliders(e, l, "Point limit:", 50, 500, 10, "g_domination_point_limit"); break;
+ case MAPINFO_TYPE_KEYHUNT: GameType_ConfigureSliders(e, l, "Point limit:", 200, 1500, 50, "g_keyhunt_point_limit"); break;
+ case MAPINFO_TYPE_RUNEMATCH: GameType_ConfigureSliders(e, l, "Point limit:", 50, 500, 10, "g_runematch_point_limit"); break;
+ case MAPINFO_TYPE_LMS: GameType_ConfigureSliders(e, l, "Lives:", 3, 50, 1, "g_lms_lives_override"); break;
+ default: GameType_ConfigureSliders(e, l, "Frag limit:", 5, 100, 5, "fraglimit_override"); break;
+ }
+ me.mapListBox.refilter(me.mapListBox);
+}
+
+#endif
Added: trunk/menu/nexuiz/dialog_multiplayer_create_mapinfo.c
===================================================================
--- trunk/menu/nexuiz/dialog_multiplayer_create_mapinfo.c (rev 0)
+++ trunk/menu/nexuiz/dialog_multiplayer_create_mapinfo.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,147 @@
+#ifdef INTERFACE
+CLASS(NexuizMapInfoDialog) EXTENDS(NexuizDialog)
+ METHOD(NexuizMapInfoDialog, fill, void(entity))
+ METHOD(NexuizMapInfoDialog, loadMapInfo, void(entity, float))
+ ATTRIB(NexuizMapInfoDialog, title, string, "Map Information")
+ ATTRIB(NexuizMapInfoDialog, color, vector, SKINCOLOR_DIALOG_MAPINFO)
+ ATTRIB(NexuizMapInfoDialog, intendedWidth, float, 0.85)
+ ATTRIB(NexuizMapInfoDialog, rows, float, 9)
+ ATTRIB(NexuizMapInfoDialog, columns, float, 10)
+
+ ATTRIB(NexuizMapInfoDialog, previewImage, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, titleLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, authorLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, descriptionLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, featuresLabel, entity, NULL)
+
+ ATTRIB(NexuizMapInfoDialog, typeDeathmatchLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, typeTDMLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, typeLMSLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, typeArenaLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, typeRuneLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, typeDominationLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, typeKeyHuntLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, typeCTFLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, typeAssaultLabel, entity, NULL)
+ ATTRIB(NexuizMapInfoDialog, typeOnslaughtLabel, entity, NULL)
+
+ ATTRIB(NexuizMapInfoDialog, currentMapIndex, float, 0)
+ ATTRIB(NexuizMapInfoDialog, currentMapBSPName, string, string_null)
+ ATTRIB(NexuizMapInfoDialog, currentMapTitle, string, string_null)
+ ATTRIB(NexuizMapInfoDialog, currentMapAuthor, string, string_null)
+ ATTRIB(NexuizMapInfoDialog, currentMapDescription, string, string_null)
+ ATTRIB(NexuizMapInfoDialog, currentMapPreviewImage, string, string_null)
+ ATTRIB(NexuizMapInfoDialog, currentMapFeaturesText, string, string_null)
+ENDCLASS(NexuizMapInfoDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void loadMapInfoNexuizMapInfoDialog(entity me, float i)
+{
+ me.currentMapIndex = i;
+ MapInfo_Get_ByID(i);
+
+ if(me.currentMapBSPName)
+ {
+ strunzone(me.currentMapBSPName);
+ strunzone(me.currentMapTitle);
+ strunzone(me.currentMapAuthor);
+ strunzone(me.currentMapDescription);
+ strunzone(me.currentMapPreviewImage);
+ strunzone(me.currentMapFeaturesText);
+ }
+ me.currentMapBSPName = strzone(MapInfo_Map_bspname);
+ me.currentMapTitle = strzone(MapInfo_Map_title);
+ me.currentMapAuthor = strzone(MapInfo_Map_author);
+ me.currentMapDescription = strzone(MapInfo_Map_description);
+ me.currentMapFeaturesText = strzone((MapInfo_Map_supportedFeatures & MAPINFO_FEATURE_WEAPONS) ? "Full item placement" : "MinstaGib only");
+ me.currentMapPreviewImage = strzone(strcat("/maps/", MapInfo_Map_bspname));
+
+ me.frame.setText(me.frame, me.currentMapBSPName);
+ me.titleLabel.setText(me.titleLabel, me.currentMapTitle);
+ me.authorLabel.setText(me.authorLabel, me.currentMapAuthor);
+ me.descriptionLabel.setText(me.descriptionLabel, me.currentMapDescription);
+ me.featuresLabel.setText(me.featuresLabel, me.currentMapFeaturesText);
+ me.previewImage.src = me.currentMapPreviewImage;
+
+ me.typeDeathmatchLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH);
+ me.typeTDMLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_TEAM_DEATHMATCH);
+ me.typeLMSLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_LMS);
+ me.typeArenaLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ARENA);
+ me.typeDominationLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DOMINATION);
+ me.typeRuneLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RUNEMATCH);
+ me.typeKeyHuntLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_KEYHUNT);
+ me.typeCTFLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_CTF);
+ if(me.typeAssaultLabel)
+ me.typeAssaultLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ASSAULT);
+ if(me.typeOnslaughtLabel)
+ me.typeOnslaughtLabel.disabled = !(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_ONSLAUGHT);
+
+ MapInfo_ClearTemps();
+}
+void fillNexuizMapInfoDialog(entity me)
+{
+ entity e;
+ float w;
+ me.TR(me);
+ me.TD(me, me.rows - 2, 3, e = makeNexuizImage(string_null, 4.0/3.0));
+ me.previewImage = e;
+ me.gotoRC(me, 0, 3.5); me.setFirstColumn(me, me.currentColumn);
+ w = me.columns - me.currentColumn;
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Title:"));
+ me.TD(me, 1, w-1, e = makeNexuizTextLabel(0, ""));
+ e.alpha = 1;
+ e.colorL = SKINCOLOR_MAPLIST_TITLE;
+ e.allowCut = 1;
+ me.titleLabel = e;
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Author:"));
+ me.TD(me, 1, w-1, e = makeNexuizTextLabel(0, ""));
+ e.alpha = 1;
+ e.colorL = SKINCOLOR_MAPLIST_AUTHOR;
+ e.allowCut = 1;
+ me.authorLabel = e;
+ me.TR(me);
+ me.TD(me, 1, w, e = makeNexuizTextLabel(0, ""));
+ e.allowCut = 1;
+ me.featuresLabel = e;
+ me.TR(me);
+ me.TD(me, 1, w, e = makeNexuizTextLabel(0, "Game types:"));
+ me.TR(me);
+ me.TD(me, 1, w/4, e = makeNexuizTextLabel(0, "Deathmatch"));
+ me.typeDeathmatchLabel = e;
+ me.TD(me, 1, w/4, e = makeNexuizTextLabel(0, "TDM"));
+ me.typeTDMLabel = e;
+ me.TD(me, 1, w/4, e = makeNexuizTextLabel(0, "LMS"));
+ me.typeLMSLabel = e;
+ me.TD(me, 1, w/4, e = makeNexuizTextLabel(0, "Arena"));
+ me.typeArenaLabel = e;
+ me.TR(me);
+ me.TD(me, 1, w/4, e = makeNexuizTextLabel(0, "Rune"));
+ me.typeRuneLabel = e;
+ me.TD(me, 1, w/4, e = makeNexuizTextLabel(0, "Domination"));
+ me.typeDominationLabel = e;
+ me.TD(me, 1, w/4, e = makeNexuizTextLabel(0, "Key Hunt"));
+ me.typeKeyHuntLabel = e;
+ me.TD(me, 1, w/4, e = makeNexuizTextLabel(0, "CTF"));
+ me.typeCTFLabel = e;
+ me.TR(me);
+ if(cvar("developer"))
+ {
+ me.TD(me, 1, w/4, e = makeNexuizTextLabel(0, "Assault"));
+ me.typeAssaultLabel = e;
+ me.TD(me, 1, w/4, e = makeNexuizTextLabel(0, "Onslaught"));
+ me.typeOnslaughtLabel = e;
+ }
+
+ me.gotoRC(me, me.rows - 2, 0);
+ me.TD(me, 1, me.columns, e = makeNexuizTextLabel(0.5, ""));
+ e.allowCut = 1;
+ me.descriptionLabel = e;
+
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, e = makeNexuizButton("OK", '0 0 0'));
+ e.onClick = Dialog_Close;
+ e.onClickEntity = me;
+}
+#endif
Added: trunk/menu/nexuiz/dialog_multiplayer_create_mutators.c
===================================================================
--- trunk/menu/nexuiz/dialog_multiplayer_create_mutators.c (rev 0)
+++ trunk/menu/nexuiz/dialog_multiplayer_create_mutators.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,107 @@
+#ifdef INTERFACE
+CLASS(NexuizMutatorsDialog) EXTENDS(NexuizDialog)
+ METHOD(NexuizMutatorsDialog, toString, string(entity))
+ METHOD(NexuizMutatorsDialog, fill, void(entity))
+ METHOD(NexuizMutatorsDialog, showNotify, void(entity))
+ METHOD(NexuizMutatorsDialog, close, void(entity))
+ ATTRIB(NexuizMutatorsDialog, title, string, "Mutators")
+ ATTRIB(NexuizMutatorsDialog, color, vector, SKINCOLOR_DIALOG_MUTATORS)
+ ATTRIB(NexuizMutatorsDialog, intendedWidth, float, 0.6)
+ ATTRIB(NexuizMutatorsDialog, rows, float, 9)
+ ATTRIB(NexuizMutatorsDialog, columns, float, 4)
+ ATTRIB(NexuizMutatorsDialog, refilterEntity, entity, NULL)
+ENDCLASS(NexuizMutatorsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void showNotifyNexuizMutatorsDialog(entity me)
+{
+ loadAllCvars(me);
+}
+string toStringNexuizMutatorsDialog(entity me)
+{
+ string s;
+ s = "";
+ if(cvar("g_instagib"))
+ s = strcat(s, ", InstaGib");
+ if(cvar("g_minstagib"))
+ s = strcat(s, ", MinstaGib");
+ if(cvar("g_nixnex"))
+ s = strcat(s, ", NixNex");
+ if(cvar("g_rocketarena"))
+ s = strcat(s, ", RL arena");
+ if(cvar("sv_gravity") < 800)
+ s = strcat(s, ", Low gravity");
+ if(cvar("g_cloaked"))
+ s = strcat(s, ", Cloaked");
+ if(cvar("g_footsteps"))
+ s = strcat(s, ", Steps");
+ if(cvar("g_grappling_hook"))
+ s = strcat(s, ", Hook");
+ if(cvar("g_laserguided_missile"))
+ s = strcat(s, ", LG missiles");
+ if(cvar("g_midair"))
+ s = strcat(s, ", Mid-air");
+ if(cvar("g_vampire"))
+ s = strcat(s, ", Vampire");
+ if(s == "")
+ return "None";
+ else
+ return substring(s, 2, strlen(s) - 2);
+}
+void fillNexuizMutatorsDialog(entity me)
+{
+ entity e, s;
+ me.TR(me);
+ me.TD(me, 1, 2, makeNexuizTextLabel(0, "Game mutators:"));
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizCheckBox(0, "g_cloaked", "Cloaked"));
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizCheckBox(0, "g_footsteps", "Foot steps"));
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizCheckBox(0, "g_grappling_hook", "Grappling hook"));
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizCheckBox(0, "g_laserguided_missile", "Laser guided missiles"));
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizCheckBox(0, "g_midair", "Mid-air"));
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizCheckBox(0, "g_vampire", "Vampire"));
+
+ me.gotoRC(me, 0, 2); me.setFirstColumn(me, me.currentColumn);
+ me.TD(me, 1, 2, makeNexuizTextLabel(0, "Arena mutators:"));
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizRadioButton(1, string_null, string_null, "Regular"));
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizRadioButton(1, "g_instagib", string_null, "InstaGib"));
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizRadioButton(1, "g_minstagib", string_null, "MinstaGib"));
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizRadioButton(1, "g_nixnex", string_null, "NixNex"));
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 1.8, e = makeNexuizCheckBox(1, "g_nixnex_with_laser", "with laser"));
+ setDependent(e, "g_nixnex", 1, 1);
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizRadioButton(1, "g_rocketarena", string_null, "Rocket launcher arena"));
+
+ me.gotoRC(me, me.rows - 2, 0);
+ s = makeNexuizSlider(80, 400, 8, "sv_gravity");
+ s.valueDigits = 0;
+ s.valueDisplayMultiplier = 0.125; // show gravity in percent
+ me.TD(me, 1, 1, e = makeNexuizSliderCheckBox(800, 1, s, "Low gravity"));
+ e.savedValue = 200; // good on silvercity
+ me.TD(me, 1, 3, s);
+
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, e = makeNexuizButton("OK", '0 0 0'));
+ e.onClick = Dialog_Close;
+ e.onClickEntity = me;
+}
+
+void closeNexuizMutatorsDialog(entity me)
+{
+ if(me.refilterEntity)
+ me.refilterEntity.refilter(me.refilterEntity);
+ closeDialog(me);
+}
+#endif
Added: trunk/menu/nexuiz/dialog_multiplayer_join.c
===================================================================
--- trunk/menu/nexuiz/dialog_multiplayer_join.c (rev 0)
+++ trunk/menu/nexuiz/dialog_multiplayer_join.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,60 @@
+#ifdef INTERFACE
+CLASS(NexuizServerListTab) EXTENDS(NexuizTab)
+ METHOD(NexuizServerListTab, fill, void(entity))
+ ATTRIB(NexuizServerListTab, title, string, "Join")
+ ATTRIB(NexuizServerListTab, intendedWidth, float, 0.9)
+ ATTRIB(NexuizServerListTab, rows, float, 22)
+ ATTRIB(NexuizServerListTab, columns, float, 6.5)
+ENDCLASS(NexuizServerListTab)
+entity makeNexuizServerListTab();
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeNexuizServerListTab()
+{
+ entity me;
+ me = spawnNexuizServerListTab();
+ me.configureDialog(me);
+ return me;
+}
+void fillNexuizServerListTab(entity me)
+{
+ entity e, slist, clearbtn;
+
+ slist = makeNexuizServerList();
+
+ me.TR(me);
+ me.TD(me, 1, 0.5, e = makeNexuizTextLabel(0, "Filter:"));
+ me.TD(me, 1, 0.5, clearbtn = makeNexuizButton("Clear", '0 0 0'));
+ clearbtn.onClick = InputBox_Clear_Click;
+ me.TD(me, 1, me.columns - 2.5, e = makeNexuizInputBox(0, string_null));
+ e.onChange = ServerList_Filter_Change;
+ e.onChangeEntity = slist;
+ clearbtn.onClickEntity = e;
+ slist.controlledTextbox = e;
+ me.TD(me, 1, 0.5, e = makeNexuizCheckBox(0, "menu_slist_showempty", "Empty"));
+ slist.filterShowEmpty = e.checked;
+ e.onClickEntity = slist;
+ e.onClick = ServerList_ShowEmpty_Click;
+ me.TD(me, 1, 0.5, e = makeNexuizCheckBox(0, "menu_slist_showfull", "Full"));
+ slist.filterShowFull = e.checked;
+ e.onClickEntity = slist;
+ e.onClick = ServerList_ShowFull_Click;
+ me.TD(me, 1, 0.5, e = makeNexuizCheckBox(0, "net_slist_pause", "Pause"));
+
+ me.TR(me);
+ me.TD(me, 1, 1, slist.sortButton1 = makeNexuizButton(string_null, '0 0 0'));
+ me.TD(me, 1, 1, slist.sortButton2 = makeNexuizButton(string_null, '0 0 0'));
+ me.TD(me, 1, 1, slist.sortButton3 = makeNexuizButton(string_null, '0 0 0'));
+ me.TD(me, 1, 1, slist.sortButton4 = makeNexuizButton(string_null, '0 0 0'));
+ me.TR(me);
+ me.TD(me, me.rows - 3, me.columns, slist);
+
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, e = makeNexuizButton("Join!", '0 0 0'));
+ e.onClick = ServerList_Connect_Click;
+ e.onClickEntity = slist;
+ slist.connectButton = e;
+}
+#endif
Added: trunk/menu/nexuiz/dialog_multiplayer_playersetup.c
===================================================================
--- trunk/menu/nexuiz/dialog_multiplayer_playersetup.c (rev 0)
+++ trunk/menu/nexuiz/dialog_multiplayer_playersetup.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,144 @@
+#ifdef INTERFACE
+CLASS(NexuizPlayerSettingsTab) EXTENDS(NexuizTab)
+ METHOD(NexuizPlayerSettingsTab, fill, void(entity))
+ METHOD(NexuizPlayerSettingsTab, draw, void(entity))
+ ATTRIB(NexuizPlayerSettingsTab, title, string, "Player Setup")
+ ATTRIB(NexuizPlayerSettingsTab, intendedWidth, float, 0.9)
+ ATTRIB(NexuizPlayerSettingsTab, rows, float, 22)
+ ATTRIB(NexuizPlayerSettingsTab, columns, float, 6.5)
+ ATTRIB(NexuizPlayerSettingsTab, playerNameLabel, entity, NULL)
+ ATTRIB(NexuizPlayerSettingsTab, playerNameLabelAlpha, float, 0)
+ENDCLASS(NexuizPlayerSettingsTab)
+entity makeNexuizPlayerSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizPlayerSettingsTab()
+{
+ entity me;
+ me = spawnNexuizPlayerSettingsTab();
+ me.configureDialog(me);
+ return me;
+}
+void drawNexuizPlayerSettingsTab(entity me)
+{
+ if(cvar_string("_cl_name") == "Player")
+ me.playerNameLabel.alpha = ((mod(time * 2, 2) < 1) ? 1 : 0);
+ else
+ me.playerNameLabel.alpha = me.playerNameLabelAlpha;
+ drawContainer(me);
+}
+void fillNexuizPlayerSettingsTab(entity me)
+{
+ entity e, pms, sl;
+ float i, n;
+
+ me.TR(me);
+ me.TD(me, 1, 1, me.playerNameLabel = makeNexuizTextLabel(0, "Player Name:"));
+ me.playerNameLabelAlpha = me.playerNameLabel.alpha;
+ me.TD(me, 1, 2, e = makeNexuizInputBox(1, "_cl_name"));
+ e.forbiddenCharacters = "\r\n\\\""; // don't care, isn't getting saved
+ me.TR(me);
+ me.TDempty(me, 1);
+ me.TD(me, 5, 2, e = makeNexuizCharmap(e));
+ me.TR(me);
+ me.TR(me);
+ me.TR(me);
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Shirt Color:"));
+ n = 16 - !cvar("developer");
+ for(i = 0; i < n; ++i)
+ me.TDNoMargin(me, 1, 2 / n, e = makeNexuizColorButton(1, 0, i), '1 0 0');
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Pants Color:"));
+ for(i = 0; i < n; ++i)
+ me.TDNoMargin(me, 1, 2 / n, e = makeNexuizColorButton(2, 1, i), '1 0 0');
+ me.TR(me);
+ pms = makeNexuizPlayerModelSelector();
+ me.TD(me, 1, 0.3, e = makeNexuizButton("<<", '0 0 0'));
+ e.onClick = PlayerModelSelector_Prev_Click;
+ e.onClickEntity = pms;
+ me.TD(me, me.rows - me.currentRow - 1, 2.4, pms);
+ me.TD(me, 1, 0.3, e = makeNexuizButton(">>", '0 0 0'));
+ e.onClick = PlayerModelSelector_Next_Click;
+ e.onClickEntity = pms;
+
+ me.gotoRC(me, 0, 3.5); me.setFirstColumn(me, me.currentColumn);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Field of View:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(60, 130, 1, "fov"));
+ me.TR(me);
+
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Zoom Factor:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(2, 16, 0.5, "cl_zoomfactor"));
+ me.TR(me);
+ sl = makeNexuizSlider(1, 8, 0.5, "cl_zoomspeed");
+ me.TD(me, 1, 2.8, e = makeNexuizSliderCheckBox(-1, 1, sl, "Zoom speed:"));
+ me.TD(me, 1, 2, sl);
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "cl_autoswitch", "Auto switch weapons on pickup"));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Crosshair:"));
+ n = 10;
+ for(i = 1; i <= n; ++i)
+ me.TDNoMargin(me, 1, 2 / n, e = makeNexuizCrosshairButton(3, i), '0 0 0');
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Crosshair Size:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0.40, 2, 0.05, "crosshair_size"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Crosshair Alpha:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0, 1, 0.01, "crosshair_color_alpha"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Crosshair Red:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0, 1, 0.01, "crosshair_color_red"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Crosshair Green:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0, 1, 0.01, "crosshair_color_green"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Crosshair Blue:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0, 1, 0.01, "crosshair_color_blue"));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "HUD size:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("viewsize"));
+ e.addValue(e, "None", "120");
+ e.addValue(e, "Reduced", "110");
+ e.addValue(e, "Full", "100");
+ e.configureNexuizTextSliderValues(e);
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 2.8, e = makeNexuizCheckBox(1, "sbar_hudselector", "Use alternate HUD layout"));
+ setDependent(e, "viewsize", 0, 110);
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Show names:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("cl_shownames"));
+ e.addValue(e, "Never", "0");
+ e.addValue(e, "Team games", "1");
+ e.addValue(e, "Always", "2");
+ e.configureNexuizTextSliderValues(e);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Show waypoints:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("cl_hidewaypoints"));
+ e.addValue(e, "Players", "1");
+ e.addValue(e, "All", "0");
+ e.configureNexuizTextSliderValues(e);
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Network speed:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("_cl_rate"));
+ e.addValue(e, "56k", "4000");
+ e.addValue(e, "ISDN", "7000");
+ e.addValue(e, "Slow ADSL", "15000");
+ e.addValue(e, "Fast ADSL", "20000");
+ e.addValue(e, "Broadband", "25000");
+ e.configureNexuizTextSliderValues(e);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Client UDP port:"));
+ me.TD(me, 1, 0.5, e = makeNexuizInputBox(0, "cl_port"));
+
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, makeNexuizCommandButton("Apply immediately", '0 0 0', "color -1 -1;name $_cl_name;sendcvar cl_zoomfactor;sendcvar cl_zoomspeed;sendcvar cl_autoswitch;rate $_cl_rate", COMMANDBUTTON_APPLY));
+}
+#endif
Added: trunk/menu/nexuiz/dialog_news.c
===================================================================
--- trunk/menu/nexuiz/dialog_news.c (rev 0)
+++ trunk/menu/nexuiz/dialog_news.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,20 @@
+#ifdef INTERFACE
+CLASS(NexuizNewsDialog) EXTENDS(NexuizDialog)
+ METHOD(NexuizNewsDialog, fill, void(entity))
+ ATTRIB(NexuizNewsDialog, title, string, "News")
+ ATTRIB(NexuizNewsDialog, color, vector, SKINCOLOR_DIALOG_SETTINGS)
+ ATTRIB(NexuizNewsDialog, intendedWidth, float, 0.96)
+ ATTRIB(NexuizNewsDialog, rows, float, 24)
+ ATTRIB(NexuizNewsDialog, columns, float, 1)
+ENDCLASS(NexuizNewsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void fillNexuizNewsDialog(entity me)
+{
+ entity e;
+ me.TR(me);
+ me.TD(me, 24, 1, e = spawnGecko());
+ e.configureBrowser( e, "http://alientrap.org/nexuiz/index.php?module=news" );
+}
+#endif
Added: trunk/menu/nexuiz/dialog_quit.c
===================================================================
--- trunk/menu/nexuiz/dialog_quit.c (rev 0)
+++ trunk/menu/nexuiz/dialog_quit.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,25 @@
+#ifdef INTERFACE
+CLASS(NexuizQuitDialog) EXTENDS(NexuizDialog)
+ METHOD(NexuizQuitDialog, fill, void(entity))
+ ATTRIB(NexuizQuitDialog, title, string, "Quit")
+ ATTRIB(NexuizQuitDialog, color, vector, SKINCOLOR_DIALOG_QUIT)
+ ATTRIB(NexuizQuitDialog, intendedWidth, float, 0.5)
+ ATTRIB(NexuizQuitDialog, rows, float, 3)
+ ATTRIB(NexuizQuitDialog, columns, float, 2)
+ENDCLASS(NexuizQuitDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void fillNexuizQuitDialog(entity me)
+{
+ entity e;
+ me.TR(me);
+ me.TD(me, 1, 2, makeNexuizTextLabel(0.5, "Are you sure you want to quit?"));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizCommandButton("Yes", '1 0 0', "quit", 0));
+ me.TD(me, 1, 1, e = makeNexuizButton("No", '0 1 0'));
+ e.onClick = Dialog_Close;
+ e.onClickEntity = me;
+}
+#endif
Added: trunk/menu/nexuiz/dialog_settings.c
===================================================================
--- trunk/menu/nexuiz/dialog_settings.c (rev 0)
+++ trunk/menu/nexuiz/dialog_settings.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,26 @@
+#ifdef INTERFACE
+CLASS(NexuizSettingsDialog) EXTENDS(NexuizDialog)
+ METHOD(NexuizSettingsDialog, fill, void(entity))
+ ATTRIB(NexuizSettingsDialog, title, string, "Settings")
+ ATTRIB(NexuizSettingsDialog, color, vector, SKINCOLOR_DIALOG_SETTINGS)
+ ATTRIB(NexuizSettingsDialog, intendedWidth, float, 0.96)
+ ATTRIB(NexuizSettingsDialog, rows, float, 17)
+ ATTRIB(NexuizSettingsDialog, columns, float, 6)
+ENDCLASS(NexuizSettingsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void fillNexuizSettingsDialog(entity me)
+{
+ entity mc;
+ mc = makeNexuizTabController(me.rows - 2);
+ me.TR(me);
+ me.TD(me, 1, 1, mc.makeTabButton(mc, "Input", makeNexuizInputSettingsTab()));
+ me.TD(me, 1, 1, mc.makeTabButton(mc, "Video", makeNexuizVideoSettingsTab()));
+ me.TD(me, 1, 1, mc.makeTabButton(mc, "Effects", makeNexuizEffectsSettingsTab()));
+ me.TD(me, 1, 1, mc.makeTabButton(mc, "Misc", makeNexuizMiscSettingsTab()));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, me.rows - 2, me.columns, mc);
+}
+#endif
Added: trunk/menu/nexuiz/dialog_settings_effects.c
===================================================================
--- trunk/menu/nexuiz/dialog_settings_effects.c (rev 0)
+++ trunk/menu/nexuiz/dialog_settings_effects.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,193 @@
+#ifdef INTERFACE
+CLASS(NexuizEffectsSettingsTab) EXTENDS(NexuizTab)
+ METHOD(NexuizEffectsSettingsTab, fill, void(entity))
+ ATTRIB(NexuizEffectsSettingsTab, title, string, "Effects")
+ ATTRIB(NexuizEffectsSettingsTab, intendedWidth, float, 0.9)
+ ATTRIB(NexuizEffectsSettingsTab, rows, float, 15)
+ ATTRIB(NexuizEffectsSettingsTab, columns, float, 6.5)
+ENDCLASS(NexuizEffectsSettingsTab)
+entity makeNexuizEffectsSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizEffectsSettingsTab()
+{
+ entity me;
+ me = spawnNexuizEffectsSettingsTab();
+ me.configureDialog(me);
+ return me;
+}
+/*
+ * cl_decals 1
+ * cl_nogibs 0
+ * cl_particles_quality 1
+ * cl_particles_snow 1
+ * r_bloom 1
+ * r_coronas 1
+ * r_glsl_deluxemapping 1
+ * r_glsl_offsetmapping 1
+ * r_glsl_offsetmapping_reliefmapping 0
+ * r_hdr 0
+ * r_shadow_usenormalmap 1
+ * r_shadow_gloss 1
+ * r_shadow_realtime_dlight 1
+ * r_shadow_realtime_dlight_shadows 1
+ * r_shadow_realtime_world 1
+ * r_shadow_realtime_world_shadows 1
+ * r_depthfirst 2
+ * r_showsurfaces 0
+ * r_water 1
+ * r_water_resolutionmultiplier 0.5
+ *
+ *
+ * [X] cl_decals
+ * [X] !cl_nogibs
+ * Particles: |--v--|
+ * [X] Bloom [X] HDR
+ * [X] Coronas
+ * [X] Deluxemapping [X] Gloss
+ * [X] Offsetmapping [X] Reliefmapping
+ * [X] dlights [X] normalmaps [X] shadows
+ * [X] rtworld [X] shadows
+ * [X] depth first world [X] depth first models (?????)
+ * [X] OMGLOLWTFBBQ (showsurfaces)
+ * [X] water |----------v----|
+ *
+ *
+ */
+void fillNexuizEffectsSettingsTab(entity me)
+{
+ entity e;
+ float n;
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Quality preset:"));
+ n = 6 + !!cvar("developer");
+ if(cvar("developer"))
+ me.TD(me, 1, 5.5 / n, e = makeNexuizCommandButton("OMG!", '1 0 1', "exec omg.cfg", 0));
+ me.TD(me, 1, 5.5 / n, e = makeNexuizCommandButton("Low", '0 0 0', "exec low.cfg", 0));
+ me.TD(me, 1, 5.5 / n, e = makeNexuizCommandButton("Medium", '0 0 0', "exec med.cfg", 0));
+ me.TD(me, 1, 5.5 / n, e = makeNexuizCommandButton("Normal", '0 0 0', "exec normal.cfg", 0));
+ me.TD(me, 1, 5.5 / n, e = makeNexuizCommandButton("High", '0 0 0', "exec high.cfg", 0));
+ me.TD(me, 1, 5.5 / n, e = makeNexuizCommandButton("Ultra", '0 0 0', "exec ultra.cfg", 0));
+ me.TD(me, 1, 5.5 / n, e = makeNexuizCommandButton("Ultimate", '0 0 0', "exec ultimate.cfg", 0));
+
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Texture quality:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("gl_picmip"));
+ if(cvar("developer"))
+ e.addValue(e, "Leet", "1337");
+ e.addValue(e, "Lowest", "4");
+ e.addValue(e, "Low", "3");
+ e.addValue(e, "Normal", "2");
+ e.addValue(e, "Good", "1");
+ e.addValue(e, "Best", "0");
+ e.configureNexuizTextSliderValues(e);
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 2.8, e = makeNexuizCheckBox(1, "r_picmipworld", "Reduce model texture quality only"));
+ setDependent(e, "gl_picmip", 0.5, -0.5);
+
+ me.TR(me);
+
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Particle quality:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0.1, 1.0, 0.05, "cl_particles_quality"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "cl_decals", "Decals"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Gibs:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("cl_nogibs"));
+ if(cvar("developer"))
+ e.addValue(e, "German", "1");
+ e.addValue(e, "Few", "0.75");
+ e.addValue(e, "Many", "0.5");
+ e.addValue(e, "Lots", "1");
+ e.configureNexuizTextSliderValues(e);
+
+ me.TR(me);
+
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "r_coronas", "Coronas"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizCheckBox(0, "r_bloom", "Bloom"));
+ setDependent(e, "r_hdr", 0, 0);
+ me.TD(me, 1, 2, e = makeNexuizCheckBox(0, "r_hdr", "High Dynamic Range (HDR)"));
+
+ me.TR(me);
+
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "showfps", "Show frames per second"));
+
+ me.gotoRC(me, 2, 3.5); me.setFirstColumn(me, me.currentColumn);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Anisotropy:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("gl_texture_anisotropy"));
+ e.addValue(e, "1x", "1");
+ e.addValue(e, "2x", "2");
+ e.addValue(e, "4x", "4");
+ e.addValue(e, "8x", "8");
+ e.addValue(e, "16x", "16");
+ e.configureNexuizTextSliderValues(e);
+ me.TR(me);
+ me.TD(me, 1, 1.5, e = makeNexuizCheckBox(0, "r_glsl_deluxemapping", "Deluxe mapping"));
+ setDependent(e, "r_glsl", 1, 1);
+ me.TD(me, 1, 1.5, e = makeNexuizCheckBox(0, "r_shadow_gloss", "Gloss"));
+ setDependentAND(e, "r_glsl", 1, 1, "r_glsl_deluxemapping", 1, 1);
+
+ me.TR(me);
+
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizCheckBox(0, "r_shadow_realtime_dlight", "Realtime dynamic lighting"));
+ me.TD(me, 1, 1, e = makeNexuizCheckBox(0, "r_shadow_realtime_dlight_shadows", "Shadows"));
+ setDependent(e, "r_shadow_realtime_dlight", 1, 1);
+
+ me.TR(me);
+ me.TD(me, 1, 2, e = makeNexuizCheckBox(0, "r_shadow_realtime_world", "Realtime world lighting"));
+ me.TD(me, 1, 1, e = makeNexuizCheckBox(0, "r_shadow_realtime_world_shadows", "Shadows"));
+ setDependent(e, "r_shadow_realtime_world", 1, 1);
+
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 2.8, e = makeNexuizCheckBox(0, "r_shadow_usenormalmap", "Use normal maps"));
+ setDependentOR(e, "r_shadow_realtime_dlight", 1, 1, "r_shadow_realtime_world", 1, 1);
+
+ me.TR(me);
+
+ me.TR(me);
+ me.TD(me, 1, 1.5, e = makeNexuizCheckBox(0, "r_glsl_offsetmapping", "Offset mapping"));
+ setDependent(e, "r_glsl", 1, 1);
+ me.TD(me, 1, 1.5, e = makeNexuizCheckBox(0, "r_glsl_offsetmapping_reliefmapping", "Relief mapping"));
+ setDependentAND(e, "r_glsl", 1, 1, "r_glsl_offsetmapping", 1, 1);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizCheckBox(0, "r_water", "Reflections"));
+ setDependent(e, "r_glsl", 1, 1);
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("r_water_resolutionmultiplier"));
+ e.addValue(e, "Blurred", "0.25");
+ e.addValue(e, "Good", "0.5");
+ e.addValue(e, "Sharp", "1");
+ e.addValue(e, "Insane", "2");
+ e.configureNexuizTextSliderValues(e);
+ setDependentAND(e, "r_glsl", 1, 1, "r_water", 1, 1);
+
+ me.TR(me);
+
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Damage view kick:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0, 0.5, 0.05, "v_kicktime"));
+
+ me.TR(me);
+
+ me.TR(me);
+ if(cvar("developer"))
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "r_showsurfaces", "Show surfaces"));
+
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, makeNexuizCommandButton("Apply immediately", '0 0 0', "sendcvar cl_nogibs; r_restart", COMMANDBUTTON_APPLY));
+}
+/*
+ * [X] depth first world [X] depth first models (?????)
+ * [X] OMGLOLWTFBBQ (showsurfaces)
+ *
+ *
+ */
+#endif
Added: trunk/menu/nexuiz/dialog_settings_input.c
===================================================================
--- trunk/menu/nexuiz/dialog_settings_input.c (rev 0)
+++ trunk/menu/nexuiz/dialog_settings_input.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,67 @@
+#ifdef INTERFACE
+CLASS(NexuizInputSettingsTab) EXTENDS(NexuizTab)
+ METHOD(NexuizInputSettingsTab, fill, void(entity))
+ ATTRIB(NexuizInputSettingsTab, title, string, "Input")
+ ATTRIB(NexuizInputSettingsTab, intendedWidth, float, 0.9)
+ ATTRIB(NexuizInputSettingsTab, rows, float, 15)
+ ATTRIB(NexuizInputSettingsTab, columns, float, 6.5)
+ENDCLASS(NexuizInputSettingsTab)
+entity makeNexuizInputSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizInputSettingsTab()
+{
+ entity me;
+ me = spawnNexuizInputSettingsTab();
+ me.configureDialog(me);
+ return me;
+}
+void fillNexuizInputSettingsTab(entity me)
+{
+ entity e;
+ entity kb;
+
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizTextLabel(0, "Key bindings:"));
+ me.TR(me);
+ me.TD(me, me.rows - 2, 3, kb = makeNexuizKeyBinder());
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizButton("Change key...", '0 0 0'));
+ e.onClick = KeyBinder_Bind_Change;
+ e.onClickEntity = kb;
+ kb.keyGrabButton = e;
+ me.TD(me, 1, 1, e = makeNexuizButton("Edit...", '0 0 0'));
+ e.onClick = KeyBinder_Bind_Edit;
+ e.onClickEntity = kb;
+ kb.userbindEditButton = e;
+ kb.userbindEditDialog = main.userbindEditDialog;
+ main.userbindEditDialog.keybindBox = kb;
+ me.TD(me, 1, 1, e = makeNexuizButton("Clear", '0 0 0'));
+ e.onClick = KeyBinder_Bind_Clear;
+ e.onClickEntity = kb;
+
+ me.gotoRC(me, 0, 3.5); me.setFirstColumn(me, me.currentColumn);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Sensitivity:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(1, 32, 0.2, "sensitivity"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "m_filter", "Mouse filter"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(1.022, "m_pitch", "Invert mouse"));
+ me.TR(me);
+ if(cvar_defstring("joy_enable") != "")
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "joy_enable", "Use joystick input"));
+ else if(cvar_defstring("joystick") != "")
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "joystick", "Use joystick input"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "cl_movement", "Client-side movement prediction"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "con_closeontoggleconsole", "\"enter console\" also closes"));
+ me.TR(me);
+ if(cvar_defstring("vid_dgamouse") != "")
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "vid_dgamouse", "Turn off OS mouse acceleration"));
+ else if(cvar_defstring("apple_mouse_noaccel") != "")
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "vid_dgamouse", "Turn off OS mouse acceleration"));
+}
+#endif
Added: trunk/menu/nexuiz/dialog_settings_input_userbind.c
===================================================================
--- trunk/menu/nexuiz/dialog_settings_input_userbind.c (rev 0)
+++ trunk/menu/nexuiz/dialog_settings_input_userbind.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,55 @@
+#ifdef INTERFACE
+CLASS(NexuizUserbindEditDialog) EXTENDS(NexuizDialog)
+ METHOD(NexuizUserbindEditDialog, loadUserBind, void(entity, string, string, string))
+ METHOD(NexuizUserbindEditDialog, fill, void(entity))
+ ATTRIB(NexuizUserbindEditDialog, title, string, "User defined key bind")
+ ATTRIB(NexuizUserbindEditDialog, color, vector, SKINCOLOR_DIALOG_USERBIND)
+ ATTRIB(NexuizUserbindEditDialog, intendedWidth, float, 0.7)
+ ATTRIB(NexuizUserbindEditDialog, rows, float, 4)
+ ATTRIB(NexuizUserbindEditDialog, columns, float, 3)
+ ATTRIB(NexuizUserbindEditDialog, keybindBox, entity, NULL)
+
+ ATTRIB(NexuizUserbindEditDialog, nameBox, entity, NULL)
+ ATTRIB(NexuizUserbindEditDialog, commandPressBox, entity, NULL)
+ ATTRIB(NexuizUserbindEditDialog, commandReleaseBox, entity, NULL)
+ENDCLASS(NexuizUserbindEditDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void NexuizUserbindEditDialog_Save(entity btn, entity me)
+{
+ me.keybindBox.editUserbind(me.keybindBox, me.nameBox.text, me.commandPressBox.text, me.commandReleaseBox.text);
+ Dialog_Close(btn, me);
+}
+
+void loadUserBindNexuizUserbindEditDialog(entity me, string theName, string theCommandPress, string theCommandRelease)
+{
+ me.nameBox.setText(me.nameBox, theName);
+ me.nameBox.keyDown(me.nameBox, K_END, 0, 0);
+ me.commandPressBox.setText(me.commandPressBox, theCommandPress);
+ me.nameBox.keyDown(me.commandPressBox, K_END, 0, 0);
+ me.commandReleaseBox.setText(me.commandReleaseBox, theCommandRelease);
+ me.nameBox.keyDown(me.commandReleaseBox, K_END, 0, 0);
+}
+
+void fillNexuizUserbindEditDialog(entity me)
+{
+ entity e;
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Name:"));
+ me.TD(me, 1, me.columns - 1, me.nameBox = makeNexuizInputBox(0, string_null));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Command when pressed:"));
+ me.TD(me, 1, me.columns - 1, me.commandPressBox = makeNexuizInputBox(0, string_null));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Command when released:"));
+ me.TD(me, 1, me.columns - 1, me.commandReleaseBox = makeNexuizInputBox(0, string_null));
+ me.TR(me);
+ me.TD(me, 1, me.columns / 2, e = makeNexuizButton("Save", '0 0 0'));
+ e.onClick = NexuizUserbindEditDialog_Save;
+ e.onClickEntity = me;
+ me.TD(me, 1, me.columns / 2, e = makeNexuizButton("Cancel", '0 0 0'));
+ e.onClick = Dialog_Close;
+ e.onClickEntity = me;
+}
+#endif
Added: trunk/menu/nexuiz/dialog_settings_misc.c
===================================================================
--- trunk/menu/nexuiz/dialog_settings_misc.c (rev 0)
+++ trunk/menu/nexuiz/dialog_settings_misc.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,88 @@
+#ifdef INTERFACE
+CLASS(NexuizMiscSettingsTab) EXTENDS(NexuizTab)
+ METHOD(NexuizMiscSettingsTab, fill, void(entity))
+ ATTRIB(NexuizMiscSettingsTab, title, string, "Misc")
+ ATTRIB(NexuizMiscSettingsTab, intendedWidth, float, 0.9)
+ ATTRIB(NexuizMiscSettingsTab, rows, float, 15)
+ ATTRIB(NexuizMiscSettingsTab, columns, float, 6.5)
+ENDCLASS(NexuizMiscSettingsTab)
+entity makeNexuizMiscSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizMiscSettingsTab()
+{
+ entity me;
+ me = spawnNexuizMiscSettingsTab();
+ me.configureDialog(me);
+ return me;
+}
+entity makeNexuizDemoListbox()
+{
+ entity me;
+ me = spawnListBox();
+ me.configureListBox(me, 16, 0.1);
+ return me;
+}
+void fillNexuizMiscSettingsTab(entity me)
+{
+ entity e, s;
+
+ me.TR(me);
+ s = makeNexuizDecibelsSlider(-20, 0, 0.5, "bgmvolume");
+ me.TD(me, 1, 1, e = makeNexuizSliderCheckBox(-1000000, 1, s, "Music:"));
+ me.TD(me, 1, 2, s);
+ me.TR(me);
+ s = makeNexuizDecibelsSlider(-20, 0, 0.5, "volume");
+ me.TD(me, 1, 1, e = makeNexuizSliderCheckBox(-1000000, 1, s, "Game:"));
+ me.TD(me, 1, 2, s);
+ me.TR(me);
+ s = makeNexuizDecibelsSlider(-20, 0, 0.5, "snd_staticvolume");
+ me.TD(me, 1, 1, e = makeNexuizSliderCheckBox(-1000000, 1, s, "Ambient:"));
+ me.TD(me, 1, 2, s);
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Frequency:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("snd_speed"));
+ e.addValue(e, "8 kHz", "8000");
+ e.addValue(e, "11.025 kHz", "11025");
+ e.addValue(e, "16 kHz", "16000");
+ e.addValue(e, "22.05 kHz", "22050");
+ e.addValue(e, "24 kHz", "24000");
+ e.addValue(e, "32 kHz", "32000");
+ e.addValue(e, "44.1 kHz", "44100");
+ e.addValue(e, "48 kHz", "48000");
+ e.configureNexuizTextSliderValues(e);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Channels:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(1, 8, 1, "snd_channels"));
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 2.8, e = makeNexuizCheckBox(0, "snd_swapstereo", "Swap Stereo"));
+
+ me.gotoRC(me, 0, 3.5); me.setFirstColumn(me, me.currentColumn);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "cl_autodemo", "Demo recording"));
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "showtime", "Show current time"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "showdate", "Show current date"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "showfps", "Show frames per second"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizTextLabel(0, "Speedmeter:"));
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 2.8/3, e = makeNexuizRadioButton(1, "showspeed", "0", "Off"));
+ me.TD(me, 1, 2.8/3, e = makeNexuizRadioButton(1, "showspeed", "1", "in/s"));
+ me.TD(me, 1, 2.8/3, e = makeNexuizRadioButton(1, "showspeed", "2", "m/s"));
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 2.8/3, e = makeNexuizRadioButton(1, "showspeed", "3", "km/h"));
+ me.TD(me, 1, 2.8/3, e = makeNexuizRadioButton(1, "showspeed", "4", "mph"));
+ me.TD(me, 1, 2.8/3, e = makeNexuizRadioButton(1, "showspeed", "5", "knots"));
+
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, makeNexuizCommandButton("Apply immediately", '0 0 0', "snd_restart", COMMANDBUTTON_APPLY));
+}
+#endif
Added: trunk/menu/nexuiz/dialog_settings_video.c
===================================================================
--- trunk/menu/nexuiz/dialog_settings_video.c (rev 0)
+++ trunk/menu/nexuiz/dialog_settings_video.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,94 @@
+#ifdef INTERFACE
+CLASS(NexuizVideoSettingsTab) EXTENDS(NexuizTab)
+ METHOD(NexuizVideoSettingsTab, fill, void(entity))
+ ATTRIB(NexuizVideoSettingsTab, title, string, "Video")
+ ATTRIB(NexuizVideoSettingsTab, intendedWidth, float, 0.9)
+ ATTRIB(NexuizVideoSettingsTab, rows, float, 15)
+ ATTRIB(NexuizVideoSettingsTab, columns, float, 6.5)
+ENDCLASS(NexuizVideoSettingsTab)
+entity makeNexuizVideoSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizVideoSettingsTab()
+{
+ entity me;
+ me = spawnNexuizVideoSettingsTab();
+ me.configureDialog(me);
+ return me;
+}
+void fillNexuizVideoSettingsTab(entity me)
+{
+ entity e;
+
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Resolution:"));
+ me.TD(me, 1, 2, e = makeNexuizResolutionSlider());
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Color depth:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(16, 32, 16, "vid_bitsperpixel"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizCheckBox(0, "vid_fullscreen", "Full screen"));
+ me.TD(me, 1, 2, e = makeNexuizCheckBox(0, "vid_vsync", "Vertical synchronization"));
+
+ me.TR(me);
+
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "r_glsl", "Use OpenGL 2.0 shaders (GLSL)"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "gl_vbo", "Use Vertex Buffer Objects (VBO)"));
+ me.TR(me);
+ me.TD(me, 1, 1.5, e = makeNexuizTextLabel(0, "Texture compression"));
+ me.TD(me, 1, 0.5, e = makeNexuizRadioButton(1, "gl_texturecompression", "0", "None"));
+ me.TD(me, 1, 0.5, e = makeNexuizRadioButton(1, "gl_texturecompression", "1", "Fast"));
+ me.TD(me, 1, 0.5, e = makeNexuizRadioButton(1, "gl_texturecompression", "2", "Good"));
+
+ me.TR(me);
+
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Depth first:"));
+ me.TD(me, 1, 2, e = makeNexuizTextSlider("r_depthfirst"));
+ e.addValue(e, "Disabled", "0");
+ e.addValue(e, "World", "1");
+ e.addValue(e, "All", "2");
+ e.configureNexuizTextSliderValues(e);
+
+ me.TR(me);
+ if(cvar_defstring("apple_multithreadedgl") != "") // FIXME can this check against string_null too?
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(1, "apple_multithreadedgl", "Disable multithreaded OpenGL"));
+
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "gl_finish", "Wait for GPU to finish each frame"));
+
+ me.TR(me);
+
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "showfps", "Show frames per second"));
+
+ me.gotoRC(me, 0, 3.5); me.setFirstColumn(me, me.currentColumn);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Brightness:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0.0, 0.5, 0.02, "v_brightness"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Contrast:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(1.0, 3.0, 0.05, "v_contrast"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Gamma:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0.5, 2.0, 0.05, "v_gamma"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Contrast boost:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(1.0, 5.0, 0.1, "v_contrastboost"));
+ me.TR(me);
+ me.TD(me, 1, 3, e = makeNexuizCheckBox(0, "v_glslgamma", "Use GLSL to handle color control"));
+ setDependent(e, "r_glsl", 1, 1);
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Ambient lighting:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0, 20.0, 1.0, "r_ambient"));
+ me.TR(me);
+ me.TD(me, 1, 1, e = makeNexuizTextLabel(0, "Scene brightness:"));
+ me.TD(me, 1, 2, e = makeNexuizSlider(0.5, 2.0, 0.05, "r_hdr_scenebrightness"));
+
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, makeNexuizCommandButton("Apply immediately", '0 0 0', "vid_restart", COMMANDBUTTON_APPLY));
+}
+#endif
Added: trunk/menu/nexuiz/dialog_singleplayer.c
===================================================================
--- trunk/menu/nexuiz/dialog_singleplayer.c (rev 0)
+++ trunk/menu/nexuiz/dialog_singleplayer.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,71 @@
+#ifdef INTERFACE
+CLASS(NexuizSingleplayerDialog) EXTENDS(NexuizDialog)
+ METHOD(NexuizSingleplayerDialog, fill, void(entity))
+ ATTRIB(NexuizSingleplayerDialog, title, string, "Singleplayer")
+ ATTRIB(NexuizSingleplayerDialog, color, vector, SKINCOLOR_DIALOG_SINGLEPLAYER)
+ ATTRIB(NexuizSingleplayerDialog, intendedWidth, float, 0.80)
+ ATTRIB(NexuizSingleplayerDialog, rows, float, 24)
+ ATTRIB(NexuizSingleplayerDialog, columns, float, 5)
+ ATTRIB(NexuizSingleplayerDialog, campaignBox, entity, NULL)
+ENDCLASS(NexuizSingleplayerDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+
+void InstantAction_LoadMap(entity btn, entity dummy)
+{
+ float glob, i, n, fh;
+ string s;
+ glob = search_begin("maps/*.instantaction", TRUE, TRUE);
+ if(glob < 0)
+ return;
+ i = ceil(random() * search_getsize(glob)) - 1;
+ fh = fopen(search_getfilename(glob, i), FILE_READ);
+ search_end(glob);
+ if(fh < 0)
+ return;
+ while((s = fgets(fh)))
+ {
+ if(substring(s, 0, 4) == "set ")
+ s = substring(s, 4, strlen(s) - 4);
+ n = tokenize(s);
+ if(argv(0) == "bot_number")
+ cvar_set("bot_number", argv(1));
+ else if(argv(0) == "skill")
+ cvar_set("skill", argv(1));
+ else if(argv(0) == "timelimit")
+ cvar_set("timelimit_override", argv(1));
+ else if(argv(0) == "fraglimit")
+ cvar_set("fraglimit_override", argv(1));
+ else if(argv(0) == "changelevel")
+ {
+ fclose(fh);
+ MapInfo_SwitchGameType(MAPINFO_TYPE_DEATHMATCH);
+ MapInfo_LoadMap(argv(1));
+ cvar_set("lastlevel", "1");
+ return;
+ }
+ }
+ fclose(fh);
+}
+
+void fillNexuizSingleplayerDialog(entity me)
+{
+ entity e;
+
+ me.TR(me);
+ me.TDempty(me, (me.columns - 2) / 2);
+ me.TD(me, 2, 2, e = makeNexuizButton("Instant action!", '0 0 0'));
+ e.onClick = InstantAction_LoadMap;
+ e.onClickEntity = NULL;
+ me.TR(me);
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, me.rows - 5, me.columns, me.campaignBox = makeNexuizCampaignList());
+
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, e = makeNexuizButton("Start!", '0 0 0'));
+ e.onClick = CampaignList_LoadMap;
+ e.onClickEntity = me.campaignBox;
+}
+#endif
Added: trunk/menu/nexuiz/dialog_singleplayer_winner.c
===================================================================
--- trunk/menu/nexuiz/dialog_singleplayer_winner.c (rev 0)
+++ trunk/menu/nexuiz/dialog_singleplayer_winner.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,25 @@
+#ifdef INTERFACE
+CLASS(NexuizWinnerDialog) EXTENDS(NexuizDialog)
+ METHOD(NexuizWinnerDialog, fill, void(entity))
+ ATTRIB(NexuizWinnerDialog, title, string, "Winner")
+ ATTRIB(NexuizWinnerDialog, color, vector, SKINCOLOR_DIALOG_MULTIPLAYER)
+ ATTRIB(NexuizWinnerDialog, intendedWidth, float, 0.64)
+ ATTRIB(NexuizWinnerDialog, rows, float, 12)
+ ATTRIB(NexuizWinnerDialog, columns, float, 3)
+ENDCLASS(NexuizWinnerDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void fillNexuizWinnerDialog(entity me)
+{
+ entity e;
+
+ me.TR(me);
+ me.TD(me, me.rows - 2, me.columns, e = makeNexuizImage("/gfx/winner", -1));
+
+ me.gotoRC(me, me.rows - 1, 0);
+ me.TD(me, 1, me.columns, e = makeNexuizButton("OK", '0 0 0'));
+ e.onClick = Dialog_Close;
+ e.onClickEntity = me;
+}
+#endif
Added: trunk/menu/nexuiz/dialog_teamselect.c
===================================================================
--- trunk/menu/nexuiz/dialog_teamselect.c (rev 0)
+++ trunk/menu/nexuiz/dialog_teamselect.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,50 @@
+#ifdef INTERFACE
+CLASS(NexuizTeamSelectDialog) EXTENDS(NexuizRootDialog)
+ METHOD(NexuizTeamSelectDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
+ METHOD(NexuizTeamSelectDialog, showNotify, void(entity))
+ ATTRIB(NexuizTeamSelectDialog, title, string, "Team Selection") // ;)
+ ATTRIB(NexuizTeamSelectDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+ ATTRIB(NexuizTeamSelectDialog, intendedWidth, float, 0.4)
+ ATTRIB(NexuizTeamSelectDialog, rows, float, 5)
+ ATTRIB(NexuizTeamSelectDialog, columns, float, 4)
+ ATTRIB(NexuizTeamSelectDialog, name, string, "TeamSelect")
+ ATTRIB(NexuizTeamSelectDialog, team1, entity, NULL)
+ ATTRIB(NexuizTeamSelectDialog, team2, entity, NULL)
+ ATTRIB(NexuizTeamSelectDialog, team3, entity, NULL)
+ ATTRIB(NexuizTeamSelectDialog, team4, entity, NULL)
+ENDCLASS(NexuizTeamSelectDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeTeamButton(string theName, vector theColor, string commandtheName)
+{
+ entity b;
+ b = makeNexuizCommandButton(theName, theColor, commandtheName, 1);
+ return b;
+}
+
+void showNotifyNexuizTeamSelectDialog(entity me)
+{
+ float teams, nTeams;
+ teams = cvar("_teams_available");
+ nTeams = 0;
+ me.team1.disabled = !(teams & 1); nTeams += !!(teams & 1);
+ me.team2.disabled = !(teams & 2); nTeams += !!(teams & 2);
+ me.team3.disabled = !(teams & 4); nTeams += !!(teams & 4);
+ me.team4.disabled = !(teams & 8); nTeams += !!(teams & 8);
+}
+
+void fillNexuizTeamSelectDialog(entity me)
+{
+ me.TR(me);
+ me.TR(me);
+ me.TR(me);
+ me.TD(me, 2, 1, me.team1 = makeTeamButton("red", '1 0.5 0.5', "cmd selectteam red; menu_showclassselect;"));
+ me.TD(me, 2, 1, me.team2 = makeTeamButton("blue", '0.5 0.5 1', "cmd selectteam blue; menu_showclassselect;"));
+ me.TD(me, 2, 1, me.team3 = makeTeamButton("yellow", '1 1 0.5', "cmd selectteam yellow; menu_showclassselect;"));
+ me.TD(me, 2, 1, me.team4 = makeTeamButton("pink", '1 0.5 1', "cmd selectteam pink; menu_showclassselect;"));
+ me.TR(me);
+}
+#endif
+
+// click. The C-word so you can grep for it.
Added: trunk/menu/nexuiz/gametypebutton.c
===================================================================
--- trunk/menu/nexuiz/gametypebutton.c (rev 0)
+++ trunk/menu/nexuiz/gametypebutton.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,66 @@
+#ifdef INTERFACE
+CLASS(NexuizGametypeButton) EXTENDS(RadioButton)
+ METHOD(NexuizGametypeButton, configureNexuizGametypeButton, void(entity, float, string, string))
+ METHOD(NexuizGametypeButton, setChecked, void(entity, float))
+ ATTRIB(NexuizGametypeButton, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizGametypeButton, image, string, SKINGFX_BUTTON)
+ ATTRIB(NexuizGametypeButton, color, vector, SKINCOLOR_BUTTON_N)
+ ATTRIB(NexuizGametypeButton, colorC, vector, SKINCOLOR_BUTTON_C)
+ ATTRIB(NexuizGametypeButton, colorF, vector, SKINCOLOR_BUTTON_F)
+ ATTRIB(NexuizGametypeButton, colorD, vector, SKINCOLOR_BUTTON_D)
+ ATTRIB(NexuizGametypeButton, srcMulti, float, 1)
+ ATTRIB(NexuizGametypeButton, useDownAsChecked, float, 1)
+
+ ATTRIB(NexuizGametypeButton, cvarName, string, string_null)
+ METHOD(NexuizGametypeButton, loadCvars, void(entity))
+ METHOD(NexuizGametypeButton, saveCvars, void(entity))
+
+ ATTRIB(NexuizGametypeButton, alpha, float, SKINALPHA_TEXT)
+ ATTRIB(NexuizGametypeButton, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(NexuizGametypeButton)
+entity makeNexuizGametypeButton(float, string, string);
+#endif
+
+#ifdef IMPLEMENTATION
+void GameTypeButton_Click(entity me, entity other);
+entity makeNexuizGametypeButton(float theGroup, string theCvar, string theText)
+{
+ entity me;
+ me = spawnNexuizGametypeButton();
+ me.configureNexuizGametypeButton(me, theGroup, theCvar, theText);
+ return me;
+}
+void configureNexuizGametypeButtonNexuizGametypeButton(entity me, float theGroup, string theCvar, string theText)
+{
+ if(theCvar)
+ {
+ me.cvarName = theCvar;
+ me.loadCvars(me);
+ }
+ me.configureRadioButton(me, theText, me.fontSize, me.image, theGroup, 0);
+ me.align = 0.5;
+ me.onClick = GameTypeButton_Click;
+ me.onClickEntity = NULL;
+}
+void setCheckedNexuizGametypeButton(entity me, float val)
+{
+ if(val != me.checked)
+ {
+ me.checked = val;
+ me.saveCvars(me);
+ }
+}
+void loadCvarsNexuizGametypeButton(entity me)
+{
+ me.checked = cvar(me.cvarName);
+}
+void saveCvarsNexuizGametypeButton(entity me)
+{
+ cvar_set(me.cvarName, ftos(me.checked));
+}
+void GameTypeButton_Click(entity me, entity other)
+{
+ RadioButton_Click(me, other);
+ me.parent.gameTypeChangeNotify(me.parent);
+}
+#endif
Added: trunk/menu/nexuiz/image.c
===================================================================
--- trunk/menu/nexuiz/image.c (rev 0)
+++ trunk/menu/nexuiz/image.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,28 @@
+#ifdef INTERFACE
+CLASS(NexuizImage) EXTENDS(Image)
+ METHOD(NexuizImage, configureNexuizImage, void(entity, string, float))
+ENDCLASS(NexuizImage)
+entity makeNexuizImage(string theImage, float theAspect);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizImage(string theImage, float theAspect)
+{
+ entity me;
+ me = spawnNexuizImage();
+ me.configureNexuizImage(me, theImage, theAspect);
+ return me;
+}
+void configureNexuizImageNexuizImage(entity me, string theImage, float theAspect)
+{
+ me.configureImage(me, theImage);
+ if(theAspect < 0) // use image aspect
+ {
+ vector sz;
+ sz = draw_PictureSize(theImage);
+ me.forcedAspect = sz_x / sz_y;
+ }
+ else
+ me.forcedAspect = theAspect;
+}
+#endif
Added: trunk/menu/nexuiz/inputbox.c
===================================================================
--- trunk/menu/nexuiz/inputbox.c (rev 0)
+++ trunk/menu/nexuiz/inputbox.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,66 @@
+#ifdef INTERFACE
+CLASS(NexuizInputBox) EXTENDS(InputBox)
+ METHOD(NexuizInputBox, configureNexuizInputBox, void(entity, float, string))
+ METHOD(NexuizInputBox, focusLeave, void(entity))
+ METHOD(NexuizInputBox, setText, void(entity, string))
+ ATTRIB(NexuizInputBox, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizInputBox, image, string, SKINGFX_INPUTBOX)
+ ATTRIB(NexuizInputBox, onChange, void(entity, entity), SUB_Null)
+ ATTRIB(NexuizInputBox, onChangeEntity, entity, NULL)
+ ATTRIB(NexuizInputBox, keepspaceLeft, float, SKINMARGIN_INPUTBOX)
+ ATTRIB(NexuizInputBox, keepspaceRight, float, SKINMARGIN_INPUTBOX)
+ ATTRIB(NexuizInputBox, color, vector, SKINCOLOR_INPUTBOX_N)
+ ATTRIB(NexuizInputBox, colorF, vector, SKINCOLOR_INPUTBOX_F)
+
+ ATTRIB(NexuizInputBox, alpha, float, SKINALPHA_TEXT)
+
+ ATTRIB(NexuizInputBox, cvarName, string, string_null)
+ METHOD(NexuizInputBox, loadCvars, void(entity))
+ METHOD(NexuizInputBox, saveCvars, void(entity))
+ENDCLASS(NexuizInputBox)
+entity makeNexuizInputBox(float, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizInputBox(float doEditColorCodes, string theCvar)
+{
+ entity me;
+ me = spawnNexuizInputBox();
+ me.configureNexuizInputBox(me, doEditColorCodes, theCvar);
+ return me;
+}
+void configureNexuizInputBoxNexuizInputBox(entity me, float doEditColorCodes, string theCvar)
+{
+ me.configureInputBox(me, "", 0, me.fontSize, me.image);
+ me.editColorCodes = doEditColorCodes;
+ if(theCvar)
+ {
+ me.cvarName = theCvar;
+ me.loadCvars(me);
+ }
+ me.cursorPos = strlen(me.text);
+}
+void focusLeaveNexuizInputBox(entity me)
+{
+ if(me.cvarName)
+ me.saveCvars(me);
+}
+void setTextNexuizInputBox(entity me, string new)
+{
+ if(me.text != new)
+ {
+ setTextInputBox(me, new);
+ me.onChange(me, me.onChangeEntity);
+ }
+ else
+ setTextInputBox(me, new);
+}
+void loadCvarsNexuizInputBox(entity me)
+{
+ setTextInputBox(me, cvar_string(me.cvarName));
+}
+void saveCvarsNexuizInputBox(entity me)
+{
+ cvar_set(me.cvarName, me.text);
+}
+#endif
Added: trunk/menu/nexuiz/keybinder.c
===================================================================
--- trunk/menu/nexuiz/keybinder.c (rev 0)
+++ trunk/menu/nexuiz/keybinder.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,319 @@
+#ifdef INTERFACE
+CLASS(NexuizKeyBinder) EXTENDS(NexuizListBox)
+ METHOD(NexuizKeyBinder, configureNexuizKeyBinder, void(entity))
+ ATTRIB(NexuizKeyBinder, rowsPerItem, float, 1)
+ METHOD(NexuizKeyBinder, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(NexuizKeyBinder, clickListBoxItem, void(entity, float, vector))
+ METHOD(NexuizKeyBinder, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(NexuizKeyBinder, setSelected, void(entity, float))
+ METHOD(NexuizKeyBinder, keyDown, float(entity, float, float, float))
+ METHOD(NexuizKeyBinder, keyGrabbed, void(entity, float, float))
+
+ ATTRIB(NexuizKeyBinder, realFontSize, vector, '0 0 0')
+ ATTRIB(NexuizKeyBinder, realUpperMargin, float, 0)
+ ATTRIB(NexuizKeyBinder, columnFunctionOrigin, float, 0)
+ ATTRIB(NexuizKeyBinder, columnFunctionSize, float, 0)
+ ATTRIB(NexuizKeyBinder, columnKeysOrigin, float, 0)
+ ATTRIB(NexuizKeyBinder, columnKeysSize, float, 0)
+
+ ATTRIB(NexuizKeyBinder, lastClickedKey, float, -1)
+ ATTRIB(NexuizKeyBinder, lastClickedTime, float, 0)
+ ATTRIB(NexuizKeyBinder, previouslySelected, float, -1)
+ ATTRIB(NexuizKeyBinder, inMouseHandler, float, 0)
+ ATTRIB(NexuizKeyBinder, userbindEditButton, entity, NULL)
+ ATTRIB(NexuizKeyBinder, keyGrabButton, entity, NULL)
+ ATTRIB(NexuizKeyBinder, userbindEditDialog, entity, NULL)
+ METHOD(NexuizKeyBinder, editUserbind, void(entity, string, string, string))
+ENDCLASS(NexuizKeyBinder)
+entity makeNexuizKeyBinder();
+void KeyBinder_Bind_Change(entity btn, entity me);
+void KeyBinder_Bind_Clear(entity btn, entity me);
+void KeyBinder_Bind_Edit(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+
+#define MAX_KEYS_PER_FUNCTION 2
+#define MAX_KEYBINDS 256
+string Nexuiz_KeyBinds_Functions[MAX_KEYBINDS];
+string Nexuiz_KeyBinds_Descriptions[MAX_KEYBINDS];
+var float Nexuiz_KeyBinds_Count = -1;
+
+void Nexuiz_KeyBinds_Read()
+{
+ float fh;
+ string s;
+
+ Nexuiz_KeyBinds_Count = 0;
+ fh = fopen("keybinds.txt", FILE_READ);
+ if(fh < 0)
+ return;
+ while((s = fgets(fh)))
+ {
+ if(tokenize(s) != 2)
+ continue;
+ Nexuiz_KeyBinds_Functions[Nexuiz_KeyBinds_Count] = strzone(argv(0));
+ Nexuiz_KeyBinds_Descriptions[Nexuiz_KeyBinds_Count] = strzone(argv(1));
+ ++Nexuiz_KeyBinds_Count;
+ if(Nexuiz_KeyBinds_Count >= MAX_KEYBINDS)
+ break;
+ }
+ fclose(fh);
+}
+
+entity makeNexuizKeyBinder()
+{
+ entity me;
+ me = spawnNexuizKeyBinder();
+ me.configureNexuizKeyBinder(me);
+ return me;
+}
+void configureNexuizKeyBinderNexuizKeyBinder(entity me)
+{
+ me.configureNexuizListBox(me);
+ if(Nexuiz_KeyBinds_Count < 0)
+ Nexuiz_KeyBinds_Read();
+ me.nItems = Nexuiz_KeyBinds_Count;
+ me.setSelected(me, 0);
+}
+void resizeNotifyNexuizKeyBinder(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
+
+ me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
+ me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
+ me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+
+ me.columnFunctionOrigin = 0;
+ me.columnKeysSize = me.realFontSize_x * 12;
+ me.columnFunctionSize = 1 - me.columnKeysSize - 2 * me.realFontSize_x;
+ me.columnKeysOrigin = me.columnFunctionOrigin + me.columnFunctionSize + me.realFontSize_x;
+
+ if(me.userbindEditButton)
+ me.userbindEditButton.disabled = (substring(Nexuiz_KeyBinds_Descriptions[me.selectedItem], 0, 1) != "$");
+}
+void KeyBinder_Bind_Change(entity btn, entity me)
+{
+ string func;
+
+ func = Nexuiz_KeyBinds_Functions[me.selectedItem];
+ if(func == "")
+ return;
+
+ me.keyGrabButton.forcePressed = 1;
+ keyGrabber = me;
+}
+void keyGrabbedNexuizKeyBinder(entity me, float key, float ascii)
+{
+ float n, j, k, nvalid;
+ string func;
+
+ me.keyGrabButton.forcePressed = 0;
+ if(key == K_ESCAPE)
+ return;
+
+ func = Nexuiz_KeyBinds_Functions[me.selectedItem];
+ if(func == "")
+ return;
+
+ n = tokenize(findkeysforcommand(func));
+ nvalid = 0;
+ for(j = 0; j < n; ++j)
+ {
+ k = stof(argv(j));
+ if(k != -1)
+ ++nvalid;
+ }
+ if(nvalid >= MAX_KEYS_PER_FUNCTION)
+ {
+ for(j = 0; j < n; ++j)
+ {
+ k = stof(argv(j));
+ if(k != -1)
+ localcmd("\nunbind \"", keynumtostring(k), "\"\n");
+ }
+ }
+ localcmd("\nbind \"", keynumtostring(key), "\" \"", func, "\"\n");
+}
+void editUserbindNexuizKeyBinder(entity me, string theName, string theCommandPress, string theCommandRelease)
+{
+ string func, descr;
+
+ if(!me.userbindEditDialog)
+ return;
+
+ func = Nexuiz_KeyBinds_Functions[me.selectedItem];
+ if(func == "")
+ return;
+
+ descr = Nexuiz_KeyBinds_Descriptions[me.selectedItem];
+ if(substring(descr, 0, 1) != "$")
+ return;
+ descr = substring(descr, 1, strlen(descr) - 1);
+
+ // Hooray! It IS a user bind!
+ cvar_set(strcat(descr, "_description"), theName);
+ cvar_set(strcat(descr, "_press"), theCommandPress);
+ cvar_set(strcat(descr, "_release"), theCommandRelease);
+}
+void KeyBinder_Bind_Edit(entity btn, entity me)
+{
+ string func, descr;
+
+ if(!me.userbindEditDialog)
+ return;
+
+ func = Nexuiz_KeyBinds_Functions[me.selectedItem];
+ if(func == "")
+ return;
+
+ descr = Nexuiz_KeyBinds_Descriptions[me.selectedItem];
+ if(substring(descr, 0, 1) != "$")
+ return;
+ descr = substring(descr, 1, strlen(descr) - 1);
+
+ // Hooray! It IS a user bind!
+ me.userbindEditDialog.loadUserBind(me.userbindEditDialog, cvar_string(strcat(descr, "_description")), cvar_string(strcat(descr, "_press")), cvar_string(strcat(descr, "_release")));
+
+ DialogOpenButton_Click(btn, me.userbindEditDialog);
+}
+void KeyBinder_Bind_Clear(entity btn, entity me)
+{
+ float n, j, k;
+ string func;
+
+ func = Nexuiz_KeyBinds_Functions[me.selectedItem];
+ if(func == "")
+ return;
+
+ n = tokenize(findkeysforcommand(func));
+ for(j = 0; j < n; ++j)
+ {
+ k = stof(argv(j));
+ if(k != -1)
+ localcmd("\nunbind \"", keynumtostring(k), "\"\n");
+ }
+
+}
+void clickListBoxItemNexuizKeyBinder(entity me, float i, vector where)
+{
+ if(i == me.lastClickedServer)
+ if(time < me.lastClickedTime + 0.3)
+ {
+ // DOUBLE CLICK!
+ KeyBinder_Bind_Change(NULL, me);
+ }
+ me.lastClickedServer = i;
+ me.lastClickedTime = time;
+}
+void setSelectedNexuizKeyBinder(entity me, float i)
+{
+ // handling of "unselectable" items
+ i = floor(0.5 + bound(0, i, me.nItems - 1));
+ if(me.pressed == 0 || me.pressed == 1) // keyboard or scrolling - skip unselectable items
+ {
+ if(i > me.previouslySelected)
+ {
+ while((i < me.nItems - 1) && (Nexuiz_KeyBinds_Functions[i] == ""))
+ ++i;
+ }
+ while((i > 0) && (Nexuiz_KeyBinds_Functions[i] == ""))
+ --i;
+ while((i < me.nItems - 1) && (Nexuiz_KeyBinds_Functions[i] == ""))
+ ++i;
+ }
+ if(me.pressed == 3) // released the mouse - fall back to last valid item
+ {
+ if(Nexuiz_KeyBinds_Functions[i] == "")
+ i = me.previouslySelected;
+ }
+ if(Nexuiz_KeyBinds_Functions[i] != "")
+ me.previouslySelected = i;
+ if(me.userbindEditButton)
+ me.userbindEditButton.disabled = (substring(Nexuiz_KeyBinds_Descriptions[i], 0, 1) != "$");
+ setSelectedListBox(me, i);
+}
+float keyDownNexuizKeyBinder(entity me, float key, float ascii, float shift)
+{
+ float r;
+ r = 1;
+ switch(key)
+ {
+ case K_ENTER:
+ case K_SPACE:
+ KeyBinder_Bind_Change(me, me);
+ break;
+ case K_DEL:
+ case K_BACKSPACE:
+ KeyBinder_Bind_Clear(me, me);
+ break;
+ default:
+ r = keyDownListBox(me, key, ascii, shift);
+ break;
+ }
+ return r;
+}
+void drawListBoxItemNexuizKeyBinder(entity me, float i, vector absSize, float isSelected)
+{
+ string s;
+ float j, k, n;
+ vector theColor;
+ float theAlpha;
+ string func, descr;
+ float extraMargin;
+
+ descr = Nexuiz_KeyBinds_Descriptions[i];
+ func = Nexuiz_KeyBinds_Functions[i];
+
+ if(func == "")
+ {
+ theAlpha = 1;
+ theColor = SKINCOLOR_KEYGRABBER_TITLES;
+ theAlpha = SKINALPHA_KEYGRABBER_TITLES;
+ extraMargin = 0;
+ }
+ else
+ {
+ if(isSelected)
+ {
+ if(keyGrabber == me)
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_WAITING, SKINALPHA_LISTBOX_WAITING);
+ else
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ }
+ theAlpha = SKINALPHA_KEYGRABBER_KEYS;
+ theColor = SKINCOLOR_KEYGRABBER_KEYS;
+ extraMargin = me.realFontSize_x * 0.5;
+ }
+
+ if(substring(descr, 0, 1) == "$")
+ {
+ s = substring(descr, 1, strlen(descr) - 1);
+ descr = cvar_string(strcat(s, "_description"));
+ if(descr == "")
+ descr = s;
+ if(cvar_string(strcat(s, "_press")) == "")
+ if(cvar_string(strcat(s, "_release")) == "")
+ theAlpha *= SKINALPHA_DISABLED;
+ }
+
+ draw_Text(me.realUpperMargin * eY + extraMargin * eX, descr, me.realFontSize, theColor, theAlpha, 0);
+ if(func != "")
+ {
+ n = tokenize(findkeysforcommand(func));
+ s = "";
+ for(j = 0; j < n; ++j)
+ {
+ k = stof(argv(j));
+ if(k != -1)
+ {
+ if(s != "")
+ s = strcat(s, ", ");
+ s = strcat(s, keynumtostring(k));
+ }
+ }
+ s = draw_TextShortenToWidth(s, me.columnKeysSize / me.realFontSize_x, 0);
+ draw_CenterText(me.realUpperMargin * eY + (me.columnKeysOrigin + 0.5 * me.columnKeysSize) * eX, s, me.realFontSize, theColor, theAlpha, 0);
+ }
+}
+#endif
Added: trunk/menu/nexuiz/listbox.c
===================================================================
--- trunk/menu/nexuiz/listbox.c (rev 0)
+++ trunk/menu/nexuiz/listbox.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,34 @@
+#ifdef INTERFACE
+CLASS(NexuizListBox) EXTENDS(ListBox)
+ METHOD(NexuizListBox, configureNexuizListBox, void(entity))
+ ATTRIB(NexuizListBox, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizListBox, scrollbarWidth, float, SKINWIDTH_SCROLLBAR)
+ ATTRIB(NexuizListBox, src, string, SKINGFX_SCROLLBAR)
+ ATTRIB(NexuizListBox, tolerance, vector, SKINTOLERANCE_SLIDER)
+ ATTRIB(NexuizListBox, rowsPerItem, float, 1)
+ METHOD(NexuizListBox, resizeNotify, void(entity, vector, vector, vector, vector))
+ ATTRIB(NexuizListBox, color, vector, SKINCOLOR_SCROLLBAR_N)
+ ATTRIB(NexuizListBox, colorF, vector, SKINCOLOR_SCROLLBAR_F)
+ ATTRIB(NexuizListBox, color2, vector, SKINCOLOR_SCROLLBAR_S)
+ENDCLASS(NexuizListBox)
+entity makeNexuizListBox();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizListBox()
+{
+ entity me;
+ me = spawnNexuizListBox();
+ me.configureNexuizListBox(me);
+ return me;
+}
+void configureNexuizListBoxNexuizListBox(entity me)
+{
+ me.configureListBox(me, me.scrollbarWidth, 1); // item height gets set up later
+}
+void resizeNotifyNexuizListBox(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ me.itemHeight = me.rowsPerItem * me.fontSize / absSize_y;
+ resizeNotifyListBox(me, relOrigin, relSize, absOrigin, absSize);
+}
+#endif
Added: trunk/menu/nexuiz/mainwindow.c
===================================================================
--- trunk/menu/nexuiz/mainwindow.c (rev 0)
+++ trunk/menu/nexuiz/mainwindow.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,97 @@
+#ifdef INTERFACE
+CLASS(MainWindow) EXTENDS(ModalController)
+ METHOD(MainWindow, configureMainWindow, void(entity))
+ ATTRIB(MainWindow, mutatorsDialog, entity, NULL)
+ ATTRIB(MainWindow, mapInfoDialog, entity, NULL)
+ ATTRIB(MainWindow, userbindEditDialog, entity, NULL)
+ ATTRIB(MainWindow, winnerDialog, entity, NULL)
+ ATTRIB(MainWindow, fadedAlpha, float, SKINALPHA_BEHIND)
+ENDCLASS(MainWindow)
+#endif
+
+#ifdef IMPLEMENTATION
+
+void DemoButton_Click(entity me, entity other)
+{
+ if(me.text == "Do not press this button again!")
+ DialogOpenButton_Click(me, other);
+ else
+ me.setText(me, "Do not press this button again!");
+}
+
+void configureMainWindowMainWindow(entity me)
+{
+ entity n, i;
+
+ i = spawnNexuizTeamSelectDialog();
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+ i = spawnNexuizClassSelectDialog();
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+ i = spawnNexuizInfoScreenDialog();
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+ me.mutatorsDialog = i = spawnNexuizMutatorsDialog();
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+ me.mapInfoDialog = i = spawnNexuizMapInfoDialog();
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+ me.userbindEditDialog = i = spawnNexuizUserbindEditDialog();
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+ me.winnerDialog = i = spawnNexuizWinnerDialog();
+ i.configureDialog(i);
+ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+ n = spawnNexuizNexposee();
+ /*
+ if(checkextension("DP_GECKO_SUPPORT"))
+ {
+ i = spawnNexuizNewsDialog();
+ i.configureDialog(i);
+ n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ n.setNexposee(n, i, '0.1 0.1 0', SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
+ }
+ */
+ i = spawnNexuizSingleplayerDialog();
+ i.configureDialog(i);
+ n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ n.setNexposee(n, i, SKINPOSITION_DIALOG_SINGLEPLAYER, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
+
+ i = spawnNexuizMultiplayerDialog();
+ i.configureDialog(i);
+ n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ n.setNexposee(n, i, SKINPOSITION_DIALOG_MULTIPLAYER, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
+
+ i = spawnNexuizSettingsDialog();
+ i.configureDialog(i);
+ n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ n.setNexposee(n, i, SKINPOSITION_DIALOG_SETTINGS, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
+
+ i = spawnNexuizCreditsDialog();
+ i.configureDialog(i);
+ n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ n.setNexposee(n, i, SKINPOSITION_DIALOG_CREDITS, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
+ n.pullNexposee(n, i, eY * (SKINHEIGHT_TITLE * SKINFONTSIZE_TITLE / conheight));
+
+ i = spawnNexuizQuitDialog();
+ i.configureDialog(i);
+ n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+ n.setNexposee(n, i, SKINPOSITION_DIALOG_QUIT, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y);
+ n.pullNexposee(n, i, eY * (SKINHEIGHT_TITLE * SKINFONTSIZE_TITLE / conheight));
+ me.addItem(me, n, '0 0 0', '1 1 0', SKINALPHAS_MAINMENU_z);
+ me.moveItemAfter(me, n, NULL);
+
+ me.initializeDialog(me, n);
+}
+#endif
+
+// click. The C-word so you can grep for it.
Added: trunk/menu/nexuiz/maplist.c
===================================================================
--- trunk/menu/nexuiz/maplist.c (rev 0)
+++ trunk/menu/nexuiz/maplist.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,319 @@
+#ifdef INTERFACE
+CLASS(NexuizMapList) EXTENDS(NexuizListBox)
+ METHOD(NexuizMapList, configureNexuizMapList, void(entity))
+ ATTRIB(NexuizMapList, rowsPerItem, float, 4)
+ METHOD(NexuizMapList, draw, void(entity))
+ METHOD(NexuizMapList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(NexuizMapList, clickListBoxItem, void(entity, float, vector))
+ METHOD(NexuizMapList, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(NexuizMapList, refilter, void(entity))
+ METHOD(NexuizMapList, keyDown, float(entity, float, float, float))
+
+ ATTRIB(NexuizMapList, realFontSize, vector, '0 0 0')
+ ATTRIB(NexuizMapList, columnPreviewOrigin, float, 0)
+ ATTRIB(NexuizMapList, columnPreviewSize, float, 0)
+ ATTRIB(NexuizMapList, columnNameOrigin, float, 0)
+ ATTRIB(NexuizMapList, columnNameSize, float, 0)
+ ATTRIB(NexuizMapList, checkMarkOrigin, vector, '0 0 0')
+ ATTRIB(NexuizMapList, checkMarkSize, vector, '0 0 0')
+ ATTRIB(NexuizMapList, realUpperMargin1, float, 0)
+ ATTRIB(NexuizMapList, realUpperMargin2, float, 0)
+
+ ATTRIB(NexuizMapList, lastClickedMap, float, -1)
+ ATTRIB(NexuizMapList, lastClickedTime, float, 0)
+
+ ATTRIB(NexuizMapList, lastGametype, float, 0)
+ ATTRIB(NexuizMapList, lastFeatures, float, 0)
+
+ ATTRIB(NexuizMapList, origin, vector, '0 0 0')
+ ATTRIB(NexuizMapList, itemAbsSize, vector, '0 0 0')
+
+ ATTRIB(NexuizMapList, g_maplistCache, string, string_null)
+ METHOD(NexuizMapList, g_maplistCacheToggle, void(entity, float))
+ METHOD(NexuizMapList, g_maplistCacheQuery, float(entity, float))
+
+ ATTRIB(NexuizMapList, startButton, entity, NULL)
+
+ ATTRIB(NexuizMapList, cvarName, string, "dummy")
+ METHOD(NexuizMapList, loadCvars, void(entity))
+
+ ATTRIB(NexuizMapList, typeToSearchString, string, string_null)
+ ATTRIB(NexuizMapList, typeToSearchTime, float, 0)
+ENDCLASS(NexuizMapList)
+entity makeNexuizMapList();
+void MapList_All(entity btn, entity me);
+void MapList_None(entity btn, entity me);
+void MapList_LoadMap(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizMapList()
+{
+ entity me;
+ me = spawnNexuizMapList();
+ me.configureNexuizMapList(me);
+ return me;
+}
+void configureNexuizMapListNexuizMapList(entity me)
+{
+ me.configureNexuizListBox(me);
+ me.refilter(me);
+}
+
+void loadCvarsNexuizMapList(entity me)
+{
+ me.refilter(me);
+}
+
+float g_maplistCacheQueryNexuizMapList(entity me, float i)
+{
+ return stof(substring(me.g_maplistCache, i, 1));
+}
+void g_maplistCacheToggleNexuizMapList(entity me, float i)
+{
+ string a, b, c, s, bspname;
+ float n;
+ s = me.g_maplistCache;
+ if not(s)
+ return;
+ b = substring(s, i, 1);
+ if(b == "0")
+ b = "1";
+ else if(b == "1")
+ b = "0";
+ else
+ return; // nothing happens
+ a = substring(s, 0, i);
+ c = substring(s, i+1, strlen(s) - (i+1));
+ strunzone(s);
+ me.g_maplistCache = strzone(strcat(a, b, c));
+ // TODO also update the actual cvar
+ if not((bspname = MapInfo_BSPName_ByID(i)))
+ return;
+ if(b == "1")
+ cvar_set("g_maplist", strcat(bspname, " ", cvar_string("g_maplist")));
+ else
+ {
+ s = "";
+ n = tokenize(cvar_string("g_maplist"));
+ for(i = 0; i < n; ++i)
+ if(argv(i) != bspname)
+ s = strcat(s, " ", argv(i));
+ cvar_set("g_maplist", substring(s, 1, strlen(s) - 1));
+ }
+}
+
+void drawNexuizMapList(entity me)
+{
+ if(me.startButton)
+ me.startButton.disabled = ((me.selectedItem < 0) || (me.selectedItem >= me.nItems));
+ drawListBox(me);
+}
+
+void resizeNotifyNexuizMapList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ me.origin = absOrigin;
+ me.itemAbsSize = '0 0 0';
+ resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
+
+ me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize_y * me.itemHeight));
+ me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize_x * (1 - me.controlWidth)));
+ me.realUpperMargin1 = 0.5 * (1 - 2.5 * me.realFontSize_y);
+ me.realUpperMargin2 = me.realUpperMargin1 + 1.5 * me.realFontSize_y;
+
+ me.columnPreviewOrigin = 0;
+ me.columnPreviewSize = me.itemAbsSize_y / me.itemAbsSize_x * 4 / 3;
+ me.columnNameOrigin = me.columnPreviewOrigin + me.columnPreviewSize + me.realFontSize_x;
+ me.columnNameSize = 1 - me.columnPreviewSize - 2 * me.realFontSize_x;
+
+ me.checkMarkSize = (eX * (me.itemAbsSize_y / me.itemAbsSize_x) + eY) * 0.5;
+ me.checkMarkOrigin = eY + eX * (me.columnPreviewOrigin + me.columnPreviewSize) - me.checkMarkSize;
+}
+void clickListBoxItemNexuizMapList(entity me, float i, vector where)
+{
+ if(where_x <= me.columnPreviewOrigin + me.columnPreviewSize)
+ {
+ if(where_x >= 0)
+ me.g_maplistCacheToggle(me, i);
+ }
+ if(where_x >= me.columnNameOrigin)
+ if(where_x <= 1)
+ {
+ if(i == me.lastClickedMap)
+ if(time < me.lastClickedTime + 0.3)
+ {
+ // DOUBLE CLICK!
+ // pop up map info screen
+ main.mapInfoDialog.loadMapInfo(main.mapInfoDialog, i);
+ DialogOpenButton_Click_withCoords(NULL, main.mapInfoDialog, me.origin + eX * (me.columnNameOrigin * me.size_x) + eY * ((me.itemHeight * i - me.scrollPos) * me.size_y), eY * me.itemAbsSize_y + eX * (me.itemAbsSize_x * me.columnNameSize));
+ return;
+ }
+ me.lastClickedMap = i;
+ me.lastClickedTime = time;
+ }
+}
+void drawListBoxItemNexuizMapList(entity me, float i, vector absSize, float isSelected)
+{
+ // layout: Ping, Map name, Map name, NP, TP, MP
+ string s;
+ float p;
+ float theAlpha;
+ float included;
+
+ if(!MapInfo_Get_ByID(i))
+ return;
+
+ included = me.g_maplistCacheQuery(me, i);
+ if(included)
+ theAlpha = SKINALPHA_MAPLIST_INCLUDEDFG;
+ else
+ theAlpha = SKINALPHA_MAPLIST_NOTINCLUDEDFG;
+
+ if(isSelected)
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+ else if(included)
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_MAPLIST_INCLUDEDBG, SKINALPHA_MAPLIST_INCLUDEDBG);
+
+ s = ftos(p);
+ draw_Picture(me.columnPreviewOrigin * eX, strcat("/maps/", MapInfo_Map_bspname), me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
+ if(included)
+ draw_Picture(me.checkMarkOrigin, "checkmark", me.checkMarkSize, '1 1 1', 1);
+ s = draw_TextShortenToWidth(strcat(MapInfo_Map_bspname, ": ", MapInfo_Map_title), me.columnNameSize / me.realFontSize_x, 0);
+ draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0) * me.realFontSize_x)) * eX, s, me.realFontSize, SKINCOLOR_MAPLIST_TITLE, theAlpha, 0);
+ s = draw_TextShortenToWidth(MapInfo_Map_author, me.columnNameSize / me.realFontSize_x, 0);
+ draw_Text(me.realUpperMargin2 * eY + (me.columnNameOrigin + 1.00 * (me.columnNameSize - draw_TextWidth(s, 0) * me.realFontSize_x)) * eX, s, me.realFontSize, SKINCOLOR_MAPLIST_AUTHOR, theAlpha, 0);
+
+ MapInfo_ClearTemps();
+}
+
+void refilterNexuizMapList(entity me)
+{
+ float i, j, n;
+ string s;
+ float gt, f;
+ gt = MapInfo_CurrentGametype();
+ f = MapInfo_CurrentFeatures();
+ MapInfo_FilterGametype(gt, f, 0);
+ me.nItems = MapInfo_count;
+ for(i = 0; i < MapInfo_count; ++i)
+ draw_PreloadPicture(strcat("/maps/", MapInfo_BSPName_ByID(i)));
+ if(me.g_maplistCache)
+ strunzone(me.g_maplistCache);
+ s = "0";
+ for(i = 1; i < MapInfo_count; i *= 2)
+ s = strcat(s, s);
+ n = tokenize(cvar_string("g_maplist"));
+ for(i = 0; i < n; ++i)
+ {
+ j = MapInfo_FindName(argv(i));
+ if(j >= 0)
+ s = strcat(
+ substring(s, 0, j),
+ "1",
+ substring(s, j+1, MapInfo_count - (j+1))
+ );
+ }
+ me.g_maplistCache = strzone(s);
+ if(gt != me.lastGametype || f != me.lastFeatures)
+ {
+ me.lastGametype = gt;
+ me.lastFeatures = f;
+ me.setSelected(me, 0);
+ }
+}
+void MapList_All(entity btn, entity me)
+{
+ float i;
+ string s;
+ MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0); // all
+ s = "";
+ for(i = 0; i < MapInfo_count; ++i)
+ s = strcat(s, " ", MapInfo_BSPName_ByID(i));
+ cvar_set("g_maplist", substring(s, 1, strlen(s) - 1));
+ me.refilter(me);
+}
+void MapList_None(entity btn, entity me)
+{
+ cvar_set("g_maplist", "");
+ me.refilter(me);
+}
+void MapList_LoadMap(entity btn, entity me)
+{
+ string m;
+ if(me.selectedItem >= me.nItems || me.selectedItem < 0)
+ return;
+ m = MapInfo_BSPName_ByID(me.selectedItem);
+ if not(m)
+ return;
+ if(MapInfo_CheckMap(m))
+ {
+ localcmd("\ndisconnect\nwait\nmaxplayers $menu_maxplayers\ng_maplist_shufflenow\n");
+ MapInfo_LoadMap(m);
+ }
+ else
+ {
+ print("Huh? Can't play this. Refiltering so this won't happen again.\n");
+ me.refilter(me);
+ }
+}
+
+float keyDownNexuizMapList(entity me, float scan, float ascii, float shift)
+{
+ string ch, save;
+ if(scan == K_ENTER)
+ {
+ // pop up map info screen
+ main.mapInfoDialog.loadMapInfo(main.mapInfoDialog, me.selectedItem);
+ DialogOpenButton_Click_withCoords(NULL, main.mapInfoDialog, me.origin + eX * (me.columnNameOrigin * me.size_x) + eY * ((me.itemHeight * me.selectedItem - me.scrollPos) * me.size_y), eY * me.itemAbsSize_y + eX * (me.itemAbsSize_x * me.columnNameSize));
+ }
+ else if(scan == K_SPACE)
+ {
+ me.g_maplistCacheToggle(me, me.selectedItem);
+ }
+ else if(ascii == 43) // +
+ {
+ if not(me.g_maplistCacheQuery(me, me.selectedItem))
+ me.g_maplistCacheToggle(me, me.selectedItem);
+ }
+ else if(ascii == 45) // -
+ {
+ if(me.g_maplistCacheQuery(me, me.selectedItem))
+ me.g_maplistCacheToggle(me, me.selectedItem);
+ }
+ else if(scan == K_BACKSPACE)
+ {
+ if(time < me.typeToSearchTime)
+ {
+ save = substring(me.typeToSearchString, 0, strlen(me.typeToSearchString) - 1);
+ if(me.typeToSearchString)
+ strunzone(me.typeToSearchString);
+ me.typeToSearchString = strzone(save);
+ me.typeToSearchTime = time + 0.5;
+ if(strlen(me.typeToSearchString))
+ {
+ MapInfo_FindName(me.typeToSearchString);
+ if(MapInfo_FindName_firstResult >= 0)
+ me.setSelected(me, MapInfo_FindName_firstResult);
+ }
+ }
+ }
+ else if(ascii >= 32 && ascii != 127)
+ {
+ ch = chr(ascii);
+ if(time > me.typeToSearchTime)
+ save = ch;
+ else
+ save = strcat(me.typeToSearchString, ch);
+ if(me.typeToSearchString)
+ strunzone(me.typeToSearchString);
+ me.typeToSearchString = strzone(save);
+ me.typeToSearchTime = time + 0.5;
+ MapInfo_FindName(me.typeToSearchString);
+ if(MapInfo_FindName_firstResult >= 0)
+ me.setSelected(me, MapInfo_FindName_firstResult);
+ }
+ else
+ return keyDownListBox(me, scan, ascii, shift);
+ return 1;
+}
+#endif
Added: trunk/menu/nexuiz/nexposee.c
===================================================================
--- trunk/menu/nexuiz/nexposee.c (rev 0)
+++ trunk/menu/nexuiz/nexposee.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,26 @@
+#ifdef INTERFACE
+CLASS(NexuizNexposee) EXTENDS(Nexposee)
+ METHOD(NexuizNexposee, configureNexuizNexposee, void(entity))
+ METHOD(NexuizNexposee, close, void(entity))
+ENDCLASS(NexuizNexposee)
+entity makeNexuizNexposee();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizNexposee()
+{
+ entity me;
+ me = spawnNexuizNexposee();
+ me.configureNexuizNexposee(me);
+ return me;
+}
+
+void configureNexuizNexposeeNexuizNexposee(entity me)
+{
+}
+
+void closeNexuizNexposee(entity me)
+{
+ m_goto(string_null); // hide
+}
+#endif
Added: trunk/menu/nexuiz/playermodel.c
===================================================================
--- trunk/menu/nexuiz/playermodel.c (rev 0)
+++ trunk/menu/nexuiz/playermodel.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,201 @@
+#ifdef INTERFACE
+CLASS(NexuizPlayerModelSelector) EXTENDS(NexuizImage)
+ METHOD(NexuizPlayerModelSelector, configureNexuizPlayerModelSelector, void(entity))
+ METHOD(NexuizPlayerModelSelector, loadCvars, void(entity))
+ METHOD(NexuizPlayerModelSelector, saveCvars, void(entity))
+ METHOD(NexuizPlayerModelSelector, draw, void(entity))
+ METHOD(NexuizPlayerModelSelector, resizeNotify, void(entity, vector, vector, vector, vector))
+ ATTRIB(NexuizPlayerModelSelector, currentModel, string, string_null)
+ ATTRIB(NexuizPlayerModelSelector, currentSkin, float, 0)
+ ATTRIB(NexuizPlayerModelSelector, currentModelName, string, string_null)
+ ATTRIB(NexuizPlayerModelSelector, currentModelTitle, string, string_null)
+ ATTRIB(NexuizPlayerModelSelector, currentModelTxtName, string, string_null)
+ ATTRIB(NexuizPlayerModelSelector, currentModelDescription, string, string_null)
+ ATTRIB(NexuizPlayerModelSelector, cvarName, string, "_cl_playermodel")
+ METHOD(NexuizPlayerModelSelector, go, void(entity, float))
+ ATTRIB(NexuizPlayerModelSelector, origin, vector, '0 0 0')
+ ATTRIB(NexuizPlayerModelSelector, size, vector, '0 0 0')
+ ATTRIB(NexuizPlayerModelSelector, realFontSize, vector, '0 0 0')
+ ATTRIB(NexuizPlayerModelSelector, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizPlayerModelSelector, titleFontSize, float, SKINFONTSIZE_TITLE)
+ENDCLASS(NexuizPlayerModelSelector)
+entity makeNexuizPlayerModelSelector();
+void PlayerModelSelector_Next_Click(entity btn, entity me);
+void PlayerModelSelector_Prev_Click(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizPlayerModelSelector()
+{
+ entity me;
+ me = spawnNexuizPlayerModelSelector();
+ me.configureNexuizPlayerModelSelector(me);
+ return me;
+}
+
+void configureNexuizPlayerModelSelectorNexuizPlayerModelSelector(entity me)
+{
+ me.configureNexuizImage(me, string_null, 263.0/360.0);
+ me.loadCvars(me);
+}
+
+void loadCvarsNexuizPlayerModelSelector(entity me)
+{
+ float glob, i, fh;
+ string fn;
+ string nm, t, l;
+
+ if(me.currentModel)
+ strunzone(me.currentModel);
+ if(me.currentModelTitle)
+ strunzone(me.currentModelTitle);
+ if(me.currentModelName)
+ strunzone(me.currentModelName);
+ if(me.currentModelTxtName)
+ strunzone(me.currentModelTxtName);
+ if(me.currentModelDescription)
+ strunzone(me.currentModelDescription);
+ me.currentSkin = cvar("_cl_playerskin");
+ me.currentModel = strzone(cvar_string("_cl_playermodel"));
+ me.currentModelName = string_null;
+ me.currentModelDescription = string_null;
+ me.currentModelTitle = string_null;
+ me.currentModelTxtName = string_null;
+
+ // lookup model name
+ glob = search_begin("models/player/*.txt", TRUE, TRUE);
+ if(glob < 0)
+ return;
+ for(i = 0; i < search_getsize(glob); ++i)
+ {
+ fn = search_getfilename(glob, i);
+ fh = fopen(fn, FILE_READ);
+ if(fh < 0)
+ continue;
+ t = fgets(fh);
+ nm = fgets(fh);
+ if(stof(fgets(fh)) == me.currentSkin)
+ if(fgets(fh) == me.currentModel)
+ {
+ me.currentModelName = strzone(strcat("/", nm));
+ me.currentModelTxtName = strzone(fn);
+ me.currentModelTitle = strzone(t);
+ me.currentModelDescription = "";
+ while((l = fgets(fh)))
+ {
+ if(me.currentModelDescription != "")
+ me.currentModelDescription = strcat(me.currentModelDescription, "\n");
+ me.currentModelDescription = strcat(me.currentModelDescription, l);
+ }
+ me.currentModelDescription = strzone(me.currentModelDescription);
+ fclose(fh);
+ break;
+ }
+ fclose(fh);
+ }
+ search_end(glob);
+}
+
+void goNexuizPlayerModelSelector(entity me, float d)
+{
+ float glob, i, fh;
+ string l;
+
+ glob = search_begin("models/player/*.txt", TRUE, TRUE);
+ if(glob < 0)
+ return;
+ for(i = 0; i < search_getsize(glob); ++i)
+ if(search_getfilename(glob, i) == me.currentModelTxtName)
+ break;
+ // now i is search_getsize(glob) if not found, and the right index if found.
+ if(i == search_getsize(glob))
+ {
+ if(d < 0)
+ i = search_getsize(glob) - 1;
+ else
+ i = 0;
+ }
+ else
+ {
+ i = mod(i + d + search_getsize(glob), search_getsize(glob));
+ }
+
+ if(me.currentModel)
+ strunzone(me.currentModel);
+ if(me.currentModelTitle)
+ strunzone(me.currentModelTitle);
+ if(me.currentModelName)
+ strunzone(me.currentModelName);
+ if(me.currentModelTxtName)
+ strunzone(me.currentModelTxtName);
+ if(me.currentModelDescription)
+ strunzone(me.currentModelDescription);
+
+ // select model #i!
+ me.currentModelTxtName = strzone(search_getfilename(glob, i));
+ fh = fopen(me.currentModelTxtName, FILE_READ);
+ search_end(glob);
+ if(fh < 0)
+ return;
+ me.currentModelTitle = strzone(fgets(fh));
+ me.currentModelName = strzone(strcat("/", fgets(fh)));
+ me.currentSkin = stof(fgets(fh));
+ me.currentModel = strzone(fgets(fh));
+ me.currentModelDescription = "";
+ while((l = fgets(fh)))
+ {
+ if(me.currentModelDescription != "")
+ me.currentModelDescription = strcat(me.currentModelDescription, "\n");
+ me.currentModelDescription = strcat(me.currentModelDescription, l);
+ }
+ me.currentModelDescription = strzone(me.currentModelDescription);
+ fclose(fh);
+}
+
+void PlayerModelSelector_Next_Click(entity btn, entity me)
+{
+ me.go(me, +1);
+ me.saveCvars(me);
+}
+
+void PlayerModelSelector_Prev_Click(entity btn, entity me)
+{
+ me.go(me, -1);
+ me.saveCvars(me);
+}
+
+void saveCvarsNexuizPlayerModelSelector(entity me)
+{
+ // TODO rather set the _cl ones and apply later?
+ localcmd(strcat("playermodel ", me.currentModel, "\nplayerskin ", ftos(me.currentSkin), "\n"));
+}
+
+void drawNexuizPlayerModelSelector(entity me)
+{
+ float i, n;
+ vector o;
+
+ me.src = me.currentModelName;
+ drawImage(me);
+ me.src = string_null;
+
+ // draw text on the image, handle \n in the description
+ draw_CenterText('0.5 0 0', me.currentModelTitle, me.realFontSize * (me.titleFontSize / me.fontSize), SKINCOLOR_MODELTITLE, SKINALPHA_MODELTITLE, FALSE);
+
+ o = '0.5 1 0' - eY * me.realFontSize_y * ((n = tokenizebyseparator(me.currentModelDescription, "\n")) + 0.5);
+ for(i = 0; i < n; ++i)
+ {
+ draw_CenterText(o, argv(i), me.realFontSize, '1 1 1', 1, FALSE);
+ o += eY * me.realFontSize_y;
+ }
+}
+
+void resizeNotifyNexuizPlayerModelSelector(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ resizeNotifyImage(me, relOrigin, relSize, absOrigin, absSize);
+ me.origin = absOrigin;
+ me.size = absSize;
+ me.realFontSize_y = me.fontSize / absSize_y;
+ me.realFontSize_x = me.fontSize / absSize_x;
+}
+#endif
Added: trunk/menu/nexuiz/radiobutton.c
===================================================================
--- trunk/menu/nexuiz/radiobutton.c (rev 0)
+++ trunk/menu/nexuiz/radiobutton.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,104 @@
+#ifdef INTERFACE
+CLASS(NexuizRadioButton) EXTENDS(RadioButton)
+ METHOD(NexuizRadioButton, configureNexuizRadioButton, void(entity, float, string, string, string))
+ METHOD(NexuizRadioButton, draw, void(entity))
+ METHOD(NexuizRadioButton, setChecked, void(entity, float))
+ ATTRIB(NexuizRadioButton, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizRadioButton, image, string, SKINGFX_RADIOBUTTON)
+ ATTRIB(NexuizRadioButton, color, vector, SKINCOLOR_RADIOBUTTON_N)
+ ATTRIB(NexuizRadioButton, colorC, vector, SKINCOLOR_RADIOBUTTON_C)
+ ATTRIB(NexuizRadioButton, colorF, vector, SKINCOLOR_RADIOBUTTON_F)
+ ATTRIB(NexuizRadioButton, colorD, vector, SKINCOLOR_RADIOBUTTON_D)
+
+ ATTRIB(NexuizRadioButton, cvarName, string, string_null)
+ ATTRIB(NexuizRadioButton, cvarValue, string, string_null)
+ METHOD(NexuizRadioButton, loadCvars, void(entity))
+ METHOD(NexuizRadioButton, saveCvars, void(entity))
+
+ ATTRIB(NexuizRadioButton, alpha, float, SKINALPHA_TEXT)
+ ATTRIB(NexuizRadioButton, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(NexuizRadioButton)
+entity makeNexuizRadioButton(float, string, string, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizRadioButton(float theGroup, string theCvar, string theValue, string theText)
+{
+ entity me;
+ me = spawnNexuizRadioButton();
+ me.configureNexuizRadioButton(me, theGroup, theCvar, theValue, theText);
+ return me;
+}
+void configureNexuizRadioButtonNexuizRadioButton(entity me, float theGroup, string theCvar, string theValue, string theText)
+{
+ if(theCvar)
+ {
+ me.cvarName = theCvar;
+ me.cvarValue = theValue;
+ me.loadCvars(me);
+ }
+ me.configureRadioButton(me, theText, me.fontSize, me.image, theGroup, 0);
+}
+void setCheckedNexuizRadioButton(entity me, float val)
+{
+ if(val != me.checked)
+ {
+ me.checked = val;
+ me.saveCvars(me);
+ }
+}
+void loadCvarsNexuizRadioButton(entity me)
+{
+ if(me.cvarValue)
+ me.checked = (cvar_string(me.cvarName) == me.cvarValue);
+ else
+ {
+ if(me.cvarName)
+ {
+ me.checked = !!cvar(me.cvarName);
+ }
+ else
+ {
+ // this is difficult
+ // this is the "generic" selection... but at this time, not
+ // everything is constructed yet.
+ // we need to set this later in draw()
+ me.checked = 0;
+ }
+ }
+}
+void drawNexuizRadioButton(entity me)
+{
+ if not(me.cvarValue)
+ if not(me.cvarName)
+ {
+ // this is the "other" option
+ // always select this if none other is
+ entity e;
+ float found;
+ found = 0;
+ for(e = me.parent.firstChild; e; e = e.nextSibling)
+ if(e.group == me.group)
+ if(e.checked)
+ found = 1;
+ if(!found)
+ me.setChecked(me, 1);
+ }
+ drawCheckBox(me);
+}
+void saveCvarsNexuizRadioButton(entity me)
+{
+ if(me.cvarValue)
+ {
+ if(me.checked)
+ cvar_set(me.cvarName, me.cvarValue);
+ }
+ else
+ {
+ if(me.cvarName)
+ {
+ cvar_set(me.cvarName, ftos(me.checked));
+ }
+ }
+}
+#endif
Added: trunk/menu/nexuiz/rootdialog.c
===================================================================
--- trunk/menu/nexuiz/rootdialog.c (rev 0)
+++ trunk/menu/nexuiz/rootdialog.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,21 @@
+#ifdef INTERFACE
+CLASS(NexuizRootDialog) EXTENDS(NexuizDialog)
+ // still to be customized by user
+ /*
+ ATTRIB(NexuizDialog, closable, float, 1)
+ ATTRIB(NexuizDialog, title, string, "Form1") // ;)
+ ATTRIB(NexuizDialog, color, vector, '1 0.5 1')
+ ATTRIB(NexuizDialog, intendedWidth, float, 0)
+ ATTRIB(NexuizDialog, rows, float, 3)
+ ATTRIB(NexuizDialog, columns, float, 2)
+ */
+ METHOD(NexuizRootDialog, close, void(entity))
+ENDCLASS(NexuizRootDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void closeNexuizRootDialog(entity me)
+{
+ m_goto(string_null);
+}
+#endif
Added: trunk/menu/nexuiz/serverlist.c
===================================================================
--- trunk/menu/nexuiz/serverlist.c (rev 0)
+++ trunk/menu/nexuiz/serverlist.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,377 @@
+#ifdef INTERFACE
+CLASS(NexuizServerList) EXTENDS(NexuizListBox)
+ METHOD(NexuizServerList, configureNexuizServerList, void(entity))
+ ATTRIB(NexuizServerList, rowsPerItem, float, 1)
+ METHOD(NexuizServerList, draw, void(entity))
+ METHOD(NexuizServerList, drawListBoxItem, void(entity, float, vector, float))
+ METHOD(NexuizServerList, clickListBoxItem, void(entity, float, vector))
+ METHOD(NexuizServerList, resizeNotify, void(entity, vector, vector, vector, vector))
+ METHOD(NexuizServerList, keyDown, float(entity, float, float, float))
+
+ ATTRIB(NexuizServerList, realFontSize, vector, '0 0 0')
+ ATTRIB(NexuizServerList, realUpperMargin, float, 0)
+ ATTRIB(NexuizServerList, columnPingOrigin, float, 0)
+ ATTRIB(NexuizServerList, columnPingSize, float, 0)
+ ATTRIB(NexuizServerList, columnNameOrigin, float, 0)
+ ATTRIB(NexuizServerList, columnNameSize, float, 0)
+ ATTRIB(NexuizServerList, columnMapOrigin, float, 0)
+ ATTRIB(NexuizServerList, columnMapSize, float, 0)
+ ATTRIB(NexuizServerList, columnPlayersOrigin, float, 0)
+ ATTRIB(NexuizServerList, columnPlayersSize, float, 0)
+
+ ATTRIB(NexuizServerList, selectedServer, string, string_null) // to restore selected server when needed
+ METHOD(NexuizServerList, setSelected, void(entity, float))
+ METHOD(NexuizServerList, setSortOrder, void(entity, float, float))
+ ATTRIB(NexuizServerList, filterShowEmpty, float, 1)
+ ATTRIB(NexuizServerList, filterShowFull, float, 1)
+ ATTRIB(NexuizServerList, filterString, string, string_null)
+ ATTRIB(NexuizServerList, controlledTextbox, entity, NULL)
+ ATTRIB(NexuizServerList, nextRefreshTime, float, 0)
+ METHOD(NexuizServerList, refreshServerList, void(entity, float)) // refresh mode: 0 = just reparametrize, 1 = send new requests, 2 = clear
+ ATTRIB(NexuizServerList, needsRefresh, float, 1)
+ METHOD(NexuizServerList, focusEnter, void(entity))
+ METHOD(NexuizServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))
+ ATTRIB(NexuizServerList, sortButton1, entity, NULL)
+ ATTRIB(NexuizServerList, sortButton2, entity, NULL)
+ ATTRIB(NexuizServerList, sortButton3, entity, NULL)
+ ATTRIB(NexuizServerList, sortButton4, entity, NULL)
+ ATTRIB(NexuizServerList, connectButton, entity, NULL)
+ ATTRIB(NexuizServerList, currentSortOrder, float, 0)
+ ATTRIB(NexuizServerList, currentSortField, float, -1)
+ ATTRIB(NexuizServerList, lastClickedServer, float, -1)
+ ATTRIB(NexuizServerList, lastClickedTime, float, 0)
+ENDCLASS(NexuizServerList)
+entity makeNexuizServerList();
+void ServerList_Connect_Click(entity btn, entity me);
+void ServerList_ShowEmpty_Click(entity box, entity me);
+void ServerList_ShowFull_Click(entity box, entity me);
+void ServerList_Filter_Change(entity box, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+float SLIST_FIELD_CNAME;
+float SLIST_FIELD_PING;
+float SLIST_FIELD_GAME;
+float SLIST_FIELD_MOD;
+float SLIST_FIELD_MAP;
+float SLIST_FIELD_NAME;
+float SLIST_FIELD_MAXPLAYERS;
+float SLIST_FIELD_NUMPLAYERS;
+float SLIST_FIELD_NUMHUMANS;
+float SLIST_FIELD_NUMBOTS;
+float SLIST_FIELD_PROTOCOL;
+float SLIST_FIELD_FREESLOTS;
+void ServerList_UpdateFieldIDs()
+{
+ SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
+ SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
+ SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
+ SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
+ SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
+ SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
+ SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
+ SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
+ SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
+ SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
+ SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
+ SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
+}
+
+entity makeNexuizServerList()
+{
+ entity me;
+ me = spawnNexuizServerList();
+ me.configureNexuizServerList(me);
+ return me;
+}
+void configureNexuizServerListNexuizServerList(entity me)
+{
+ me.configureNexuizListBox(me);
+
+ ServerList_UpdateFieldIDs();
+
+ me.nItems = 0;
+}
+void setSelectedNexuizServerList(entity me, float i)
+{
+ float save;
+ save = me.selectedItem;
+ setSelectedListBox(me, i);
+ /*
+ if(me.selectedItem == save)
+ return;
+ */
+ if(me.nItems == 0)
+ return;
+ if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
+ return; // sorry, it would be wrong
+ if(me.selectedServer)
+ strunzone(me.selectedServer);
+ me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
+}
+void refreshServerListNexuizServerList(entity me, float mode)
+{
+ // 0: just reparametrize
+ // 1: also ask for new servers
+ // 2: clear
+ //print("refresh of type ", ftos(mode), "\n");
+ /* if(mode == 2) // borken
+ {
+ // clear list
+ localcmd("net_slist\n");
+ me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
+ }
+ else */
+ {
+ float m;
+ m = SLIST_MASK_AND;
+ resethostcachemasks();
+ if(!me.filterShowFull)
+ sethostcachemasknumber(m++, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL);
+ if(!me.filterShowEmpty)
+ sethostcachemasknumber(m++, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
+ m = SLIST_MASK_OR;
+ if(me.filterString)
+ {
+ sethostcachemaskstring(m++, SLIST_FIELD_NAME, me.filterString, SLIST_TEST_CONTAINS);
+ sethostcachemaskstring(m++, SLIST_FIELD_MAP, me.filterString, SLIST_TEST_CONTAINS);
+ }
+ sethostcachesort(me.currentSortField, me.currentSortOrder < 0);
+ resorthostcache();
+ if(mode >= 1)
+ refreshhostcache();
+ }
+}
+void focusEnterNexuizServerList(entity me)
+{
+ if(time < me.nextRefreshTime)
+ {
+ //print("sorry, no refresh yet\n");
+ return;
+ }
+ me.nextRefreshTime = time + 10;
+ me.refreshServerList(me, 1);
+}
+void drawNexuizServerList(entity me)
+{
+ float i, found;
+
+ if(me.currentSortField == -1)
+ {
+ me.setSortOrder(me, SLIST_FIELD_PING, +1);
+ me.refreshServerList(me, 2);
+ }
+ else if(me.needsRefresh == 1)
+ {
+ me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
+ }
+ else if(me.needsRefresh == 2)
+ {
+ me.needsRefresh = 0;
+ me.refreshServerList(me, 0);
+ }
+
+ me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
+ me.connectButton.disabled = (me.nItems == 0);
+
+ found = 0;
+ if(me.selectedServer)
+ {
+ for(i = 0; i < me.nItems; ++i)
+ if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
+ {
+ if(i != me.selectedItem)
+ {
+ me.lastClickedServer = -1;
+ me.selectedItem = i;
+ }
+ found = 1;
+ break;
+ }
+ }
+ if(!found)
+ if(me.nItems > 0)
+ {
+ if(me.selectedItem >= me.nItems)
+ me.selectedItem = me.nItems - 1;
+ if(me.selectedServer)
+ strunzone(me.selectedServer);
+ me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
+ }
+
+ drawListBox(me);
+}
+void ServerList_PingSort_Click(entity btn, entity me)
+{
+ me.setSortOrder(me, SLIST_FIELD_PING, +1);
+}
+void ServerList_NameSort_Click(entity btn, entity me)
+{
+ me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
+}
+void ServerList_MapSort_Click(entity btn, entity me)
+{
+ me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
+}
+void ServerList_PlayerSort_Click(entity btn, entity me)
+{
+ me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
+}
+void ServerList_Filter_Change(entity box, entity me)
+{
+ if(me.filterString)
+ strunzone(me.filterString);
+ if(box.text != "")
+ me.filterString = strzone(box.text);
+ else
+ me.filterString = string_null;
+ me.refreshServerList(me, 0);
+}
+void ServerList_ShowEmpty_Click(entity box, entity me)
+{
+ box.checked = me.filterShowEmpty = !me.filterShowEmpty;
+ me.refreshServerList(me, 0);
+}
+void ServerList_ShowFull_Click(entity box, entity me)
+{
+ box.checked = me.filterShowFull = !me.filterShowFull;
+ me.refreshServerList(me, 0);
+}
+void setSortOrderNexuizServerList(entity me, float field, float direction)
+{
+ if(me.currentSortField == field)
+ direction = -me.currentSortOrder;
+ me.currentSortOrder = direction;
+ me.currentSortField = field;
+ me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
+ me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
+ me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
+ me.sortButton4.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
+ me.selectedItem = 0;
+ if(me.selectedServer)
+ strunzone(me.selectedServer);
+ me.selectedServer = string_null;
+ me.refreshServerList(me, 0);
+}
+void positionSortButtonNexuizServerList(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
+{
+ vector originInLBSpace, sizeInLBSpace;
+ originInLBSpace = eY * (-me.itemHeight);
+ sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
+
+ vector originInDialogSpace, sizeInDialogSpace;
+ originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
+ sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
+
+ btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
+ btn.Container_size_x = sizeInDialogSpace_x * theSize;
+ btn.setText(btn, theTitle);
+ btn.onClick = theFunc;
+ btn.onClickEntity = me;
+ btn.resized = 1;
+}
+void resizeNotifyNexuizServerList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+ resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
+
+ me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
+ me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
+ me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+
+ me.columnPingOrigin = 0;
+ me.columnPingSize = me.realFontSize_x * 4;
+ me.columnMapSize = me.realFontSize_x * 12;
+ me.columnPlayersSize = me.realFontSize_x * 6;
+ me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - 3 * me.realFontSize_x;
+ me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
+ me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
+ me.columnPlayersOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
+
+ me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);
+ me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);
+ me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);
+ me.positionSortButton(me, me.sortButton4, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);
+
+ float f;
+ f = me.currentSortField;
+ if(f >= 0)
+ {
+ me.currentSortField = -1;
+ me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
+ }
+}
+void ServerList_Connect_Click(entity btn, entity me)
+{
+ if(me.nItems > 0)
+ localcmd("connect ", me.selectedServer, "\n");
+}
+void clickListBoxItemNexuizServerList(entity me, float i, vector where)
+{
+ if(i == me.lastClickedServer)
+ if(time < me.lastClickedTime + 0.3)
+ {
+ // DOUBLE CLICK!
+ ServerList_Connect_Click(NULL, me);
+ }
+ me.lastClickedServer = i;
+ me.lastClickedTime = time;
+}
+void drawListBoxItemNexuizServerList(entity me, float i, vector absSize, float isSelected)
+{
+ // layout: Ping, Server name, Map name, NP, TP, MP
+ string s;
+ float p;
+ vector theColor;
+ float theAlpha;
+
+ if(isSelected)
+ draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+ if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))
+ theAlpha = SKINALPHA_SERVERLIST_FULL;
+ else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
+ theAlpha = SKINALPHA_SERVERLIST_EMPTY;
+ else
+ theAlpha = 1;
+
+ p = gethostcachenumber(SLIST_FIELD_PING, i);
+ if(p < 50)
+ theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / 50);
+ else if(p < 150)
+ theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - 50) / 100);
+ else if(p < 650)
+ {
+ theColor = SKINCOLOR_SERVERLIST_HIGHPING;
+ theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - 150) / 500);
+ }
+ else
+ {
+ theColor = eX;
+ theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
+ }
+
+ s = ftos(p);
+ draw_Text(me.realUpperMargin * eY + (me.columnPingSize - draw_TextWidth(s, 0) * me.realFontSize_x) * eX, s, me.realFontSize, theColor, theAlpha, 0);
+ s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize / me.realFontSize_x, 0);
+ draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
+ s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize / me.realFontSize_x, 0);
+ draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0) * me.realFontSize_x) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
+ s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
+ draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0) * me.realFontSize_x) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
+}
+
+float keyDownNexuizServerList(entity me, float scan, float ascii, float shift)
+{
+ if(scan == K_ENTER)
+ {
+ ServerList_Connect_Click(NULL, me);
+ return 1;
+ }
+ else if(keyDownListBox(me, scan, ascii, shift))
+ return 1;
+ else if(!me.controlledTextbox)
+ return 0;
+ else
+ return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);
+}
+#endif
Added: trunk/menu/nexuiz/slider.c
===================================================================
--- trunk/menu/nexuiz/slider.c (rev 0)
+++ trunk/menu/nexuiz/slider.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,66 @@
+#ifdef INTERFACE
+CLASS(NexuizSlider) EXTENDS(Slider)
+ METHOD(NexuizSlider, configureNexuizSlider, void(entity, float, float, float, string))
+ METHOD(NexuizSlider, setValue, void(entity, float))
+ ATTRIB(NexuizSlider, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT)
+ ATTRIB(NexuizSlider, image, string, SKINGFX_SLIDER)
+ ATTRIB(NexuizSlider, tolerance, vector, SKINTOLERANCE_SLIDER)
+ ATTRIB(NexuizSlider, align, float, 0.5)
+ ATTRIB(NexuizSlider, color, vector, SKINCOLOR_SLIDER_N)
+ ATTRIB(NexuizSlider, colorC, vector, SKINCOLOR_SLIDER_C)
+ ATTRIB(NexuizSlider, colorF, vector, SKINCOLOR_SLIDER_F)
+ ATTRIB(NexuizSlider, colorD, vector, SKINCOLOR_SLIDER_D)
+ ATTRIB(NexuizSlider, color2, vector, SKINCOLOR_SLIDER_S)
+
+ ATTRIB(NexuizSlider, cvarName, string, string_null)
+ METHOD(NexuizSlider, loadCvars, void(entity))
+ METHOD(NexuizSlider, saveCvars, void(entity))
+
+ ATTRIB(NexuizSlider, alpha, float, SKINALPHA_TEXT)
+ ATTRIB(NexuizSlider, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(NexuizSlider)
+entity makeNexuizSlider(float, float, float, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizSlider(float theValueMin, float theValueMax, float theValueStep, string theCvar)
+{
+ entity me;
+ me = spawnNexuizSlider();
+ me.configureNexuizSlider(me, theValueMin, theValueMax, theValueStep, theCvar);
+ return me;
+}
+void configureNexuizSliderNexuizSlider(entity me, float theValueMin, float theValueMax, float theValueStep, string theCvar)
+{
+ float v, vk, vp;
+ v = theValueMin;
+ vk = theValueStep;
+ vp = theValueStep * 10;
+ while(fabs(vp) < fabs(theValueMax - theValueMin) / 40)
+ vp *= 10;
+ me.configureSliderVisuals(me, me.fontSize, me.align, me.valueSpace, me.image);
+ me.configureSliderValues(me, theValueMin, v, theValueMax, theValueStep, vk, vp);
+ if(theCvar)
+ {
+ me.cvarName = theCvar;
+ me.loadCvars(me);
+ }
+}
+void setValueNexuizSlider(entity me, float val)
+{
+ if(val != me.value)
+ {
+ me.value = val;
+ me.saveCvars(me);
+ }
+}
+void loadCvarsNexuizSlider(entity me)
+{
+ me.value = cvar(me.cvarName);
+}
+void saveCvarsNexuizSlider(entity me)
+{
+ cvar_set(me.cvarName, ftos(me.value));
+}
+#endif
Added: trunk/menu/nexuiz/slider_decibels.c
===================================================================
--- trunk/menu/nexuiz/slider_decibels.c (rev 0)
+++ trunk/menu/nexuiz/slider_decibels.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,88 @@
+#ifdef INTERFACE
+CLASS(NexuizDecibelsSlider) EXTENDS(NexuizSlider)
+ METHOD(NexuizDecibelsSlider, loadCvars, void(entity))
+ METHOD(NexuizDecibelsSlider, saveCvars, void(entity))
+ METHOD(NexuizDecibelsSlider, valueToText, string(entity, float))
+ENDCLASS(NexuizDecibelsSlider)
+entity makeNexuizDecibelsSlider(float, float, float, string);
+#endif
+
+#ifdef IMPLEMENTATION
+
+float exp(float x)
+{
+ float i;
+ float t, s;
+
+ s = 1;
+ t = 1;
+ for(i = 1; i < 100; ++i)
+ {
+ t *= x;
+ t /= i;
+ s += t;
+ }
+
+ return s;
+}
+
+float ln(float x)
+{
+ float i;
+ float r, r0;
+
+ r = 1;
+ r0 = 0;
+ for(i = 1; fabs(r - r0) >= 0.05; ++i)
+ {
+ // Newton iteration on exp(r) = x:
+ // r <- r - (exp(r) - x) / (exp(r))
+ // r <- r - 1 + x / exp(r)
+ r0 = r;
+ r = r0 - 1 + x / exp(r0);
+ }
+ dprint("ln: ", ftos(i), " iterations\n");
+
+ return r;
+}
+
+#define LOG10 2.302585093
+
+entity makeNexuizDecibelsSlider(float theValueMin, float theValueMax, float theValueStep, string theCvar)
+{
+ entity me;
+ me = spawnNexuizDecibelsSlider();
+ me.configureNexuizSlider(me, theValueMin, theValueMax, theValueStep, theCvar);
+ return me;
+}
+void loadCvarsNexuizDecibelsSlider(entity me)
+{
+ float v;
+ v = cvar(me.cvarName);
+ if(v >= 0.98)
+ me.value = 0;
+ else if(v < 0.0005)
+ me.value = -1000000;
+ else
+ me.value = 0.1 * floor(0.5 + 10.0 * ln(cvar(me.cvarName)) * 10 / LOG10);
+}
+void saveCvarsNexuizDecibelsSlider(entity me)
+{
+ if(me.value >= -0.1)
+ cvar_set(me.cvarName, "1");
+ if(me.value < -33)
+ cvar_set(me.cvarName, "0");
+ else
+ cvar_set(me.cvarName, ftos(exp(me.value / 10 * LOG10)));
+}
+
+string valueToTextNexuizDecibelsSlider(entity me, float v)
+{
+ if(v < -33)
+ return "OFF";
+ else if(v >= -0.1)
+ return "MAX";
+ return strcat(valueToTextSlider(me, v), " dB");
+}
+
+#endif
Added: trunk/menu/nexuiz/slider_resolution.c
===================================================================
--- trunk/menu/nexuiz/slider_resolution.c (rev 0)
+++ trunk/menu/nexuiz/slider_resolution.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,57 @@
+#ifdef INTERFACE
+CLASS(NexuizResolutionSlider) EXTENDS(NexuizTextSlider)
+ METHOD(NexuizResolutionSlider, configureNexuizResolutionSlider, void(entity))
+ METHOD(NexuizResolutionSlider, addResolution, void(entity, float, float, float, float))
+ METHOD(NexuizResolutionSlider, loadCvars, void(entity))
+ METHOD(NexuizResolutionSlider, saveCvars, void(entity))
+ENDCLASS(NexuizResolutionSlider)
+entity makeNexuizResolutionSlider();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizResolutionSlider()
+{
+ entity me;
+ me = spawnNexuizResolutionSlider();
+ me.configureNexuizResolutionSlider(me);
+ return me;
+}
+void addResolutionNexuizResolutionSlider(entity me, float w, float h, float cw, float ch)
+{
+ me.addValue(me, strzone(strcat(ftos(w), "x", ftos(h))), strzone(strcat(ftos(w), " ", ftos(h), " ", ftos(cw), " ", ftos(ch))));
+ // FIXME (in case you ever want to dynamically instantiate this): THIS IS NEVER FREED
+}
+void configureNexuizResolutionSliderNexuizResolutionSlider(entity me)
+{
+ me.configureNexuizTextSlider(me, "vid_width");
+ me.addResolution(me, 640, 480, 640, 480);
+ me.addResolution(me, 800, 600, 800, 600);
+ me.addResolution(me, 1024, 768, 800, 600);
+ me.addResolution(me, 1152, 864, 800, 600);
+ me.addResolution(me, 1280, 800, 800, 600);
+ me.addResolution(me, 1280, 960, 800, 600);
+ me.addResolution(me, 1280, 1024, 800, 600);
+ me.addResolution(me, 1440, 900, 800, 600);
+ me.addResolution(me, 1600, 900, 800, 600);
+ me.addResolution(me, 1600, 1200, 800, 600);
+ me.addResolution(me, 1680, 1050, 800, 600);
+ me.addResolution(me, 1920, 1200, 800, 600);
+ me.addResolution(me, 2048, 1536, 800, 600);
+ me.configureNexuizTextSliderValues(me);
+}
+void loadCvarsNexuizResolutionSlider(entity me)
+{
+ me.setValueFromIdentifier(me, strcat(cvar_string("vid_width"), " ", cvar_string("vid_height"), " ", cvar_string("vid_conwidth"), " ", cvar_string("vid_conheight")));
+}
+void saveCvarsNexuizResolutionSlider(entity me)
+{
+ if(me.value >= 0 || me.value < me.nValues)
+ {
+ tokenize(me.getIdentifier(me));
+ cvar_set("vid_width", argv(0));
+ cvar_set("vid_height", argv(1));
+ cvar_set("vid_conwidth", argv(2));
+ cvar_set("vid_conheight", argv(3));
+ }
+}
+#endif
Added: trunk/menu/nexuiz/tab.c
===================================================================
--- trunk/menu/nexuiz/tab.c (rev 0)
+++ trunk/menu/nexuiz/tab.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,29 @@
+#ifdef INTERFACE
+CLASS(NexuizTab) EXTENDS(Tab)
+ // still to be customized by user
+ /*
+ ATTRIB(NexuizTab, intendedWidth, float, 0)
+ ATTRIB(NexuizTab, rows, float, 3)
+ ATTRIB(NexuizTab, columns, float, 2)
+ */
+ METHOD(NexuizTab, showNotify, void(entity))
+
+ ATTRIB(NexuizTab, marginTop, float, 0) // pixels
+ ATTRIB(NexuizTab, marginBottom, float, 0) // pixels
+ ATTRIB(NexuizTab, marginLeft, float, 0) // pixels
+ ATTRIB(NexuizTab, marginRight, float, 0) // pixels
+ ATTRIB(NexuizTab, columnSpacing, float, SKINMARGIN_COLUMNS) // pixels
+ ATTRIB(NexuizTab, rowSpacing, float, SKINMARGIN_ROWS) // pixels
+ ATTRIB(NexuizTab, rowHeight, float, SKINFONTSIZE_NORMAL * SKINHEIGHT_NORMAL) // pixels
+ ATTRIB(NexuizTab, titleHeight, float, SKINFONTSIZE_TITLE * SKINHEIGHT_TITLE) // pixels
+
+ ATTRIB(NexuizTab, backgroundImage, string, string_null)
+ENDCLASS(NexuizTab)
+#endif
+
+#ifdef IMPLEMENTATION
+void showNotifyNexuizTab(entity me)
+{
+ loadAllCvars(me);
+}
+#endif
Added: trunk/menu/nexuiz/tabcontroller.c
===================================================================
--- trunk/menu/nexuiz/tabcontroller.c (rev 0)
+++ trunk/menu/nexuiz/tabcontroller.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,34 @@
+#ifdef INTERFACE
+CLASS(NexuizTabController) EXTENDS(ModalController)
+ METHOD(NexuizTabController, configureNexuizTabController, void(entity, float))
+ METHOD(NexuizTabController, makeTabButton, entity(entity, string, entity))
+ ATTRIB(NexuizTabController, rows, float, 0)
+ ATTRIB(NexuizTabController, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizTabController, image, string, SKINGFX_BUTTON)
+ENDCLASS(NexuizTabController)
+entity makeNexuizTabController(float theRows);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizTabController(float theRows)
+{
+ entity me;
+ me = spawnNexuizTabController();
+ me.configureNexuizTabController(me, theRows);
+ return me;
+}
+void configureNexuizTabControllerNexuizTabController(entity me, float theRows)
+{
+ me.rows = theRows;
+}
+entity makeTabButtonNexuizTabController(entity me, string theTitle, entity tab)
+{
+ entity b;
+ if(me.rows != tab.rows)
+ error("Tab dialog height mismatch!");
+ b = makeNexuizButton(theTitle, '0 0 0');
+ me.addTab(me, tab, b);
+ // TODO make this real tab buttons (with color parameters, and different gfx)
+ return b;
+}
+#endif
Added: trunk/menu/nexuiz/textlabel.c
===================================================================
--- trunk/menu/nexuiz/textlabel.c (rev 0)
+++ trunk/menu/nexuiz/textlabel.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,28 @@
+#ifdef INTERFACE
+CLASS(NexuizTextLabel) EXTENDS(Label)
+ METHOD(NexuizTextLabel, configureNexuizTextLabel, void(entity, float, string))
+ METHOD(NexuizTextLabel, draw, void(entity))
+ ATTRIB(NexuizTextLabel, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizTextLabel, alpha, float, SKINALPHA_TEXT)
+ ATTRIB(NexuizTextLabel, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(NexuizTextLabel)
+entity makeNexuizTextLabel(float theAlign, string theText);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizTextLabel(float theAlign, string theText)
+{
+ entity me;
+ me = spawnNexuizTextLabel();
+ me.configureNexuizTextLabel(me, theAlign, theText);
+ return me;
+}
+void configureNexuizTextLabelNexuizTextLabel(entity me, float theAlign, string theText)
+{
+ me.configureLabel(me, theText, me.fontSize, theAlign);
+}
+void drawNexuizTextLabel(entity me)
+{
+ drawLabel(me);
+}
+#endif
Added: trunk/menu/nexuiz/textslider.c
===================================================================
--- trunk/menu/nexuiz/textslider.c (rev 0)
+++ trunk/menu/nexuiz/textslider.c 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,64 @@
+#ifdef INTERFACE
+CLASS(NexuizTextSlider) EXTENDS(TextSlider)
+ METHOD(NexuizTextSlider, configureNexuizTextSlider, void(entity, string))
+ METHOD(NexuizTextSlider, setValue, void(entity, float))
+ METHOD(NexuizTextSlider, configureNexuizTextSliderValues, void(entity))
+ ATTRIB(NexuizTextSlider, fontSize, float, SKINFONTSIZE_NORMAL)
+ ATTRIB(NexuizTextSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT)
+ ATTRIB(NexuizTextSlider, image, string, SKINGFX_SLIDER)
+ ATTRIB(NexuizSlider, tolerance, vector, SKINTOLERANCE_SLIDER)
+ ATTRIB(NexuizTextSlider, align, float, 0.5)
+ ATTRIB(NexuizSlider, color, vector, SKINCOLOR_SLIDER_N)
+ ATTRIB(NexuizSlider, colorC, vector, SKINCOLOR_SLIDER_C)
+ ATTRIB(NexuizSlider, colorF, vector, SKINCOLOR_SLIDER_F)
+ ATTRIB(NexuizSlider, colorD, vector, SKINCOLOR_SLIDER_D)
+ ATTRIB(NexuizSlider, color2, vector, SKINCOLOR_SLIDER_S)
+
+ ATTRIB(NexuizTextSlider, cvarName, string, string_null)
+ METHOD(NexuizTextSlider, loadCvars, void(entity))
+ METHOD(NexuizTextSlider, saveCvars, void(entity))
+
+ ATTRIB(NexuizTextSlider, alpha, float, SKINALPHA_TEXT)
+ ATTRIB(NexuizTextSlider, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(NexuizTextSlider)
+entity makeNexuizTextSlider(string); // note: you still need to call addValue and configureNexuizTextSliderValues!
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeNexuizTextSlider(string theCvar)
+{
+ entity me;
+ me = spawnNexuizTextSlider();
+ me.configureNexuizTextSlider(me, theCvar);
+ return me;
+}
+void configureNexuizTextSliderNexuizTextSlider(entity me, string theCvar)
+{
+ me.configureSliderVisuals(me, me.fontSize, me.align, me.valueSpace, me.image);
+ if(theCvar)
+ me.cvarName = theCvar;
+ // don't load it yet
+}
+void setValueNexuizTextSlider(entity me, float val)
+{
+ if(val != me.value)
+ {
+ me.value = val;
+ me.saveCvars(me);
+ }
+}
+void loadCvarsNexuizTextSlider(entity me)
+{
+ me.setValueFromIdentifier(me, cvar_string(me.cvarName));
+}
+void saveCvarsNexuizTextSlider(entity me)
+{
+ if(me.value >= 0 && me.value < me.nValues)
+ cvar_set(me.cvarName, me.getIdentifier(me));
+}
+void configureNexuizTextSliderValuesNexuizTextSlider(entity me)
+{
+ me.configureTextSliderValues(me, string_null);
+ me.loadCvars(me);
+}
+#endif
Added: trunk/menu/nexuiz/util.qc
===================================================================
--- trunk/menu/nexuiz/util.qc (rev 0)
+++ trunk/menu/nexuiz/util.qc 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,261 @@
+void forAllDescendants(entity root, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass)
+{
+ depthfirst(root, parent, firstChild, nextSibling, funcPre, funcPost, pass);
+}
+
+.string cvarName;
+void SUB_Null_ee(entity e1, entity e2)
+{
+}
+void saveCvarsOf(entity ignore, entity e)
+{
+ if(e.cvarName)
+ e.saveCvars(e);
+}
+void loadCvarsOf(entity ignore, entity e)
+{
+ if(e.cvarName)
+ e.loadCvars(e);
+}
+void saveAllCvars(entity root)
+{
+ forAllDescendants(root, saveCvarsOf, SUB_Null_ee, NULL);
+}
+void loadAllCvars(entity root)
+{
+ forAllDescendants(root, loadCvarsOf, SUB_Null_ee, NULL);
+}
+
+.void(entity) draw_setDependent;
+.string cvar_setDependent;
+.float cvarMin_setDependent;
+.float cvarMax_setDependent;
+.string cvar2_setDependent;
+.float cvar2Min_setDependent;
+.float cvar2Max_setDependent;
+.float op_setDependent;
+.string cvarString_setDependent;
+.string cvarValue_setDependent;
+void setDependent_Check(entity e)
+{
+ float f;
+ string s;
+ if(e.cvarString_setDependent)
+ {
+ s = cvar_string(e.cvarString_setDependent);
+ e.disabled = (cvar_string(e.cvarString_setDependent) == e.cvarValue_setDependent);
+ }
+ else
+ {
+ if(e.cvar_setDependent)
+ {
+ f = cvar(e.cvar_setDependent);
+ if(e.cvarMin_setDependent <= e.cvarMax_setDependent)
+ e.disabled = ((f < e.cvarMin_setDependent) || (f > e.cvarMax_setDependent));
+ else
+ e.disabled = ((f >= e.cvarMax_setDependent) && (f <= e.cvarMin_setDependent));
+ }
+ if(e.cvar2_setDependent)
+ {
+ f = cvar(e.cvar2_setDependent);
+ if(e.cvar2Min_setDependent <= e.cvar2Max_setDependent)
+ e.disabled = (e.disabled + ((f < e.cvar2Min_setDependent) || (f > e.cvar2Max_setDependent)) > e.op_setDependent);
+ else
+ e.disabled = (e.disabled + ((f >= e.cvar2Max_setDependent) && (f <= e.cvar2Min_setDependent)) > e.op_setDependent);
+ }
+ }
+}
+void setDependent_Draw(entity e)
+{
+ setDependent_Check(e);
+ e.draw_setDependent(e);
+}
+void setDependent(entity e, string theCvarName, float theCvarMin, float theCvarMax)
+{
+ e.draw_setDependent = e.draw;
+ e.cvar_setDependent = theCvarName;
+ e.cvarMin_setDependent = theCvarMin;
+ e.cvarMax_setDependent = theCvarMax;
+ e.cvar2_setDependent = string_null;
+ e.draw = setDependent_Draw;
+ setDependent_Check(e);
+}
+void setDependentStringNotEqual(entity e, string theCvarName, string theCvarValue)
+{
+ e.draw_setDependent = e.draw;
+ e.cvarString_setDependent = theCvarName;
+ e.cvarValue_setDependent = theCvarValue;
+ e.cvar_setDependent = string_null;
+ e.cvar2_setDependent = string_null;
+ e.draw = setDependent_Draw;
+ setDependent_Check(e);
+}
+void setDependentAND(entity e, string theCvarName, float theCvarMin, float theCvarMax, string theCvar2Name, float theCvar2Min, float theCvar2Max)
+{
+ e.draw_setDependent = e.draw;
+ e.cvar_setDependent = theCvarName;
+ e.cvarMin_setDependent = theCvarMin;
+ e.cvarMax_setDependent = theCvarMax;
+ e.cvar2_setDependent = theCvar2Name;
+ e.cvar2Min_setDependent = theCvar2Min;
+ e.cvar2Max_setDependent = theCvar2Max;
+ e.op_setDependent = 0;
+ e.draw = setDependent_Draw;
+ setDependent_Check(e);
+}
+void setDependentOR(entity e, string theCvarName, float theCvarMin, float theCvarMax, string theCvar2Name, float theCvar2Min, float theCvar2Max)
+{
+ e.draw_setDependent = e.draw;
+ e.cvar_setDependent = theCvarName;
+ e.cvarMin_setDependent = theCvarMin;
+ e.cvarMax_setDependent = theCvarMax;
+ e.cvar2_setDependent = theCvar2Name;
+ e.cvar2Min_setDependent = theCvar2Min;
+ e.cvar2Max_setDependent = theCvar2Max;
+ e.op_setDependent = 1;
+ e.draw = setDependent_Draw;
+ setDependent_Check(e);
+}
+
+// EXTRESPONSE SYSTEM ////////////////////////////////////////////////////////
+
+float _Nex_ExtResponseSystem_RequestsSent;
+float _Nex_ExtResponseSystem_VersionHandled;
+string _Nex_ExtResponseSystem_UpdateTo;
+float _Nex_ExtResponseSystem_RetryTime;
+float _Nex_ExtResponseSystem_RetryTime_LastDelay;
+
+void() Item_Nex_ExtResponseSystem_SendQuery =
+{
+ dprint("Sending extended response requests...\n");
+ localcmd(strcat("packet update.alientrap.org:27950 \"getExtResponse checkUpdates nexuiz ", cvar_string("g_nexuizversion"), "\"\n"));
+ _Nex_ExtResponseSystem_RequestsSent = TRUE;
+ _Nex_ExtResponseSystem_RetryTime_LastDelay = _Nex_ExtResponseSystem_RetryTime_LastDelay * 2 + 1;
+ _Nex_ExtResponseSystem_RetryTime = time + _Nex_ExtResponseSystem_RetryTime_LastDelay;
+}
+
+void(float argc) Item_Nex_ExtResponseSystem_Parse =
+{
+ dprint("Received extended response packet from ", argv(0), "\n");
+ if(!_Nex_ExtResponseSystem_RequestsSent)
+ {
+ dprint(" But I haven't sent a request yet! Ignoring.\n");
+ return;
+ }
+ if(argv(1) == "noUpdateAvailable")
+ {
+ if(_Nex_ExtResponseSystem_VersionHandled)
+ {
+ dprint(" duplicated update notice, ignored\n");
+ return;
+ }
+ _Nex_ExtResponseSystem_VersionHandled = 1;
+ }
+ else if(argv(1) == "updateAvailable")
+ {
+ if(_Nex_ExtResponseSystem_VersionHandled)
+ {
+ dprint(" duplicated update notice, ignored\n");
+ return;
+ }
+ _Nex_ExtResponseSystem_VersionHandled = 1;
+ _Nex_ExtResponseSystem_UpdateTo = strzone(argv(2)); // note: only one packet can be handled, so this can't be a leak
+ }
+ else
+ dprint(" UNKNOWN RESPONSE TYPE: ", argv(1), "\n");
+}
+
+void() Item_Nex_ExtResponseSystem_CheckForResponse =
+{
+ local string s;
+ local float argc;
+ while(strlen((s = getextresponse())))
+ {
+ argc = tokenize(s);
+ Item_Nex_ExtResponseSystem_Parse(argc);
+ }
+}
+
+// END OF EXTRESPONSE SYSTEM /////////////////////////////////////////////////
+
+float preMenuInit()
+{
+ vector sz;
+ vector boxA, boxB;
+
+ MapInfo_Cache_Create();
+ MapInfo_Enumerate();
+ if(!MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 1))
+ {
+ draw_reset();
+
+ sz = eX * 0.025 + eY * 0.025 * (draw_scale_x / draw_scale_y);
+ draw_CenterText('0.5 0.5 0' - 1.25 * sz_y * eY, "Autogenerating mapinfo for newly added maps...", sz, '1 1 1', 1, 0);
+
+ boxA = '0.05 0.5 0' + 0.25 * sz_y * eY;
+ boxB = '0.95 0.5 0' + 1.25 * sz_y * eY;
+ draw_Fill(boxA, boxB - boxA, '1 1 1', 1);
+
+ boxA += sz * 0.1;
+ boxB -= sz * 0.1;
+ draw_Fill(boxA, boxB - boxA, '0.1 0.1 0.1', 1);
+
+ boxB_x = boxA_x * (1 - MapInfo_progress) + boxB_x * MapInfo_progress;
+ draw_Fill(boxA, boxB - boxA, '0 0 1', 1);
+
+ return FALSE;
+ }
+ return TRUE;
+}
+
+string campaign_name_previous;
+float campaign_won_previous;
+void postMenuDraw()
+{
+}
+void preMenuDraw()
+{
+ vector fs, sz, line, mid;
+ Item_Nex_ExtResponseSystem_CheckForResponse();
+ if(!_Nex_ExtResponseSystem_VersionHandled)
+ if(time > _Nex_ExtResponseSystem_RetryTime)
+ Item_Nex_ExtResponseSystem_SendQuery();
+
+ if(_Nex_ExtResponseSystem_UpdateTo != "")
+ {
+ fs = ((1/draw_scale_x) * eX + (1/draw_scale_y) * eY) * 12;
+ line = eY * fs_y;
+ sz_x = draw_TextWidth(" http://www.nexuiz.com/ ", 0) * fs_x;
+ sz_y = 3 * fs_y;
+
+ draw_alpha = sin(time * 0.112 - 0.3) * 0.7;
+ mid = eX * (0.5 + 0.5 * (1 - sz_x) * cos(time * 0.071))
+ + eY * (0.5 + 0.5 * (1 - sz_y) * sin(time * 0.071));
+
+ draw_Fill(mid - 0.5 * sz, sz, '1 1 0', 1);
+ draw_CenterText(mid - 1 * line, strcat("Update to ", _Nex_ExtResponseSystem_UpdateTo, " now!"), fs, '1 0 0', 1, 0);
+ draw_CenterText(mid - 0 * line, "http://www.nexuiz.com/", fs, '0 0 1', 1, 0);
+ }
+ if not(campaign_name_previous)
+ campaign_name_previous = strzone(strcat(campaign_name, "x")); // force unequal
+ if(campaign_name == campaign_name_previous)
+ {
+ if(cvar(strcat("g_campaign", campaign_name, "_won")))
+ {
+ if(!campaign_won_previous)
+ {
+ m_display();
+ DialogOpenButton_Click_withCoords(NULL, main.winnerDialog, '0 0 0', eX * conwidth + eY * conheight);
+ }
+ campaign_won_previous = 1;
+ }
+ else
+ campaign_won_previous = 0;
+ }
+ else
+ {
+ strunzone(campaign_name_previous);
+ campaign_name_previous = strzone(campaign_name);
+ campaign_won_previous = cvar(strcat("g_campaign", campaign_name, "_won"));
+ }
+}
Added: trunk/menu/nexuiz/util.qh
===================================================================
--- trunk/menu/nexuiz/util.qh (rev 0)
+++ trunk/menu/nexuiz/util.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,8 @@
+void forAllDescendants(entity root, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass);
+void saveAllCvars(entity root);
+void loadAllCvars(entity root);
+
+void setDependent(entity e, string theCvarName, float theCvarMin, float theCvarMax);
+void setDependentAND(entity e, string theCvarName, float theCvarMin, float theCvarMax, string theCvar2Name, float theCvar2Min, float theCvar2Max);
+void setDependentOR(entity e, string theCvarName, float theCvarMin, float theCvarMax, string theCvar2Name, float theCvar2Min, float theCvar2Max);
+void setDependentStringNotEqual(entity e, string theCvarName, string theCvarValue);
Added: trunk/menu/oo/base.h
===================================================================
--- trunk/menu/oo/base.h (rev 0)
+++ trunk/menu/oo/base.h 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,8 @@
+.string classname;
+entity spawnObject()
+{
+ entity e;
+ e = spawn();
+ e.classname = "Object";
+ return e;
+}
Added: trunk/menu/oo/classdefs.h
===================================================================
--- trunk/menu/oo/classdefs.h (rev 0)
+++ trunk/menu/oo/classdefs.h 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,23 @@
+#ifndef INTERFACE
+#define INTERFACE
+#endif
+
+#ifdef IMPLEMENTATION
+#undef IMPLEMENTATION
+#endif
+
+#ifdef CLASS
+#undef CLASS
+#undef EXTENDS
+#undef METHOD
+#undef ATTRIB
+#undef ATTRIBARRAY
+#undef ENDCLASS
+#endif
+
+#define CLASS(cname) entity spawn##cname();
+#define EXTENDS(base)
+#define METHOD(cname,name,prototype) prototype name##cname; .prototype name;
+#define ATTRIB(cname,name,type,val) .type name;
+#define ATTRIBARRAY(cname,name,type,cnt) .type name[cnt];
+#define ENDCLASS(cname) .float instanceOf##cname;
Added: trunk/menu/oo/constructors.h
===================================================================
--- trunk/menu/oo/constructors.h (rev 0)
+++ trunk/menu/oo/constructors.h 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,23 @@
+#ifndef INTERFACE
+#define INTERFACE
+#endif
+
+#ifdef IMPLEMENTATION
+#undef IMPLEMENTATION
+#endif
+
+#ifdef CLASS
+#undef CLASS
+#undef EXTENDS
+#undef METHOD
+#undef ATTRIB
+#undef ATTRIBARRAY
+#undef ENDCLASS
+#endif
+
+#define CLASS(cname) entity spawn##cname() { entity me;
+#define EXTENDS(base) me = spawn##base ();
+#define METHOD(cname,name,prototype) me.name = name##cname;
+#define ATTRIB(cname,name,type,val) me.name = val;
+#define ATTRIBARRAY(cname,name,type,cnt) me.name = me.name;
+#define ENDCLASS(cname) me.instanceOf##cname = 1; me.classname = #cname; return me; }
Added: trunk/menu/oo/implementation.h
===================================================================
--- trunk/menu/oo/implementation.h (rev 0)
+++ trunk/menu/oo/implementation.h 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,16 @@
+#ifdef INTERFACE
+#undef INTERFACE
+#endif
+
+#ifndef IMPLEMENTATION
+#define IMPLEMENTATION
+#endif
+
+#ifdef CLASS
+#undef CLASS
+#undef EXTENDS
+#undef METHOD
+#undef ATTRIB
+#undef ATTRIBARRAY
+#undef ENDCLASS
+#endif
Added: trunk/menu/progs.src
===================================================================
--- trunk/menu/progs.src (rev 0)
+++ trunk/menu/progs.src 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,36 @@
+../../menu.dat
+
+config.qh
+msys.qh
+mbuiltin.qh
+
+oo/base.h
+
+../common/util.qh
+../common/mapinfo.qh
+../common/campaign_common.qh
+
+gamecommand.qh
+menu.qh
+draw.qh
+skin.qh
+nexuiz/util.qh
+
+oo/classdefs.h
+ classes.c
+
+oo/constructors.h
+ classes.c
+oo/implementation.h
+ classes.c
+
+../common/util.qc
+../common/gamecommand.qc
+gamecommand.qc
+menu.qc
+draw.qc
+nexuiz/util.qc
+
+../common/campaign_file.qc
+../common/campaign_setup.qc
+../common/mapinfo.qc
Added: trunk/menu/skin-customizables.inc
===================================================================
--- trunk/menu/skin-customizables.inc (rev 0)
+++ trunk/menu/skin-customizables.inc 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,192 @@
+#if 0
+"Perl code to convert this to a skinvalues.txt file.";
+while(<DATA>)
+{
+ chomp;
+ if(/^\s*(?:SKINFLOAT|SKINVECTOR)\(([A-Z_]+), ([-'0-9. ]+)\);$/)
+ {
+ printf "%-31s %s\n", $1, $2;
+ }
+ elsif(/^\s*SKINSTRING\(([A-Z_]+), "(.*)"\);$/)
+ {
+ printf "// uses \"$2\" images\n";
+ }
+ elsif(/^$/)
+ {
+ print "\n";
+ }
+ elsif(/^\s+\/\/ (.*)$/)
+ {
+ print "// $1\n";
+ }
+ elsif(/^SKINBEGIN$|^SKINEND$|^#endif$/)
+ {
+ }
+ else
+ {
+ print "!!! $_\n";
+ }
+}
+__DATA__
+#endif
+SKINBEGIN
+ // font sizes (used for everything)
+ SKINFLOAT(FONTSIZE_NORMAL, 12);
+ SKINFLOAT(HEIGHT_NORMAL, 1.5);
+ SKINFLOAT(FONTSIZE_TITLE, 16);
+ SKINFLOAT(HEIGHT_TITLE, 1.5);
+ SKINFLOAT(HEIGHT_ZOOMEDTITLE, -1);
+
+ // the individual dialog background colors
+ SKINVECTOR(COLOR_DIALOG_MULTIPLAYER, '0.7 0.7 1');
+ SKINVECTOR(COLOR_DIALOG_SETTINGS, '0.7 0.7 1');
+ SKINVECTOR(COLOR_DIALOG_TEAMSELECT, '1 1 1');
+ SKINVECTOR(COLOR_DIALOG_QUIT, '1 0 0');
+ SKINVECTOR(COLOR_DIALOG_MUTATORS, '0.7 0.7 1');
+ SKINVECTOR(COLOR_DIALOG_MAPINFO, '0.7 0.7 1');
+ SKINVECTOR(COLOR_DIALOG_USERBIND, '0.7 0.7 1');
+ SKINVECTOR(COLOR_DIALOG_SINGLEPLAYER, '1 1 0.7');
+ SKINVECTOR(COLOR_DIALOG_CREDITS, '0.7 0.7 1');
+
+ // nexposee positions of windows (they are the scale transformation
+ // centers, NOT the actual positions of the windows!)
+ SKINVECTOR(POSITION_DIALOG_MULTIPLAYER, '0.9 0.5 0');
+ SKINVECTOR(POSITION_DIALOG_SINGLEPLAYER, '0.1 0.1 0');
+ SKINVECTOR(POSITION_DIALOG_SETTINGS, '0.1 0.9 0');
+ SKINVECTOR(POSITION_DIALOG_CREDITS, '0.3 1.2 0');
+ SKINVECTOR(POSITION_DIALOG_QUIT, '0.9 1.2 0');
+
+ // mouse
+ SKINSTRING(GFX_CURSOR, "cursor");
+ SKINVECTOR(SIZE_CURSOR, '32 32 0');
+ SKINVECTOR(OFFSET_CURSOR, '0 0 0');
+ SKINFLOAT(ALPHA_CURSOR_INTRO, 0);
+
+ // general
+ SKINSTRING(GFX_BACKGROUND, "background");
+ SKINSTRING(GFX_BACKGROUND_INGAME, "background_ingame");
+ SKINFLOAT(ALPHA_BACKGROUND_INGAME, 0.7);
+ SKINFLOAT(ALPHA_DISABLED, 0.2);
+ SKINFLOAT(ALPHA_BEHIND, 0.5);
+ SKINFLOAT(ALPHA_TEXT, 0.7);
+
+ // item: button
+ SKINSTRING(GFX_BUTTON, "button");
+ SKINSTRING(GFX_BUTTON_GRAY, "buttongray");
+ SKINVECTOR(COLOR_BUTTON_N, '1 1 1');
+ SKINVECTOR(COLOR_BUTTON_C, '1 1 1');
+ SKINVECTOR(COLOR_BUTTON_F, '1 1 1');
+ SKINVECTOR(COLOR_BUTTON_D, '1 1 1');
+
+ // item: campaign
+ SKINFLOAT(ALPHA_CAMPAIGN_SELECTABLE, 0.8);
+ SKINVECTOR(COLOR_CAMPAIGN_SELECTABLE, '1 1 1');
+ SKINFLOAT(ALPHA_CAMPAIGN_CURRENT, 1);
+ SKINVECTOR(COLOR_CAMPAIGN_CURRENT, '1 1 0');
+ SKINFLOAT(ALPHA_CAMPAIGN_FUTURE, 0.2);
+ SKINVECTOR(COLOR_CAMPAIGN_FUTURE, '1 1 1');
+ SKINFLOAT(ALPHA_CAMPAIGN_DESCRIPTION, 0.7);
+
+ // item: checkbox
+ SKINSTRING(GFX_CHECKBOX, "checkbox");
+ SKINVECTOR(COLOR_CHECKBOX_N, '1 1 1');
+ SKINVECTOR(COLOR_CHECKBOX_C, '1 1 1');
+ SKINVECTOR(COLOR_CHECKBOX_F, '1 1 1');
+ SKINVECTOR(COLOR_CHECKBOX_D, '1 1 1');
+
+ // item: credits list
+ SKINVECTOR(COLOR_CREDITS_TITLE, '1 1 1');
+ SKINFLOAT(ALPHA_CREDITS_TITLE, 1);
+ SKINVECTOR(COLOR_CREDITS_FUNCTION, '1 1 1');
+ SKINFLOAT(ALPHA_CREDITS_FUNCTION, 0.7);
+ SKINVECTOR(COLOR_CREDITS_PERSON, '0.7 0.7 1');
+ SKINFLOAT(ALPHA_CREDITS_PERSON, 0.7);
+ SKINFLOAT(ROWS_CREDITS, 20);
+ SKINFLOAT(WIDTH_CREDITS, 0.5);
+
+ // item: crosshair button
+ SKINSTRING(GFX_CROSSHAIRBUTTON, "crosshairbutton");
+
+ // item: dialog
+ SKINSTRING(GFX_DIALOGBORDER, "border");
+ SKINSTRING(GFX_CLOSEBUTTON, "closebutton");
+ SKINFLOAT(MARGIN_TOP, 8);
+ SKINFLOAT(MARGIN_BOTTOM, 8);
+ SKINFLOAT(MARGIN_LEFT, 8);
+ SKINFLOAT(MARGIN_RIGHT, 8);
+ SKINFLOAT(MARGIN_COLUMNS, 4);
+ SKINFLOAT(MARGIN_ROWS, 4);
+
+ // item: input box
+ SKINSTRING(GFX_INPUTBOX, "inputbox");
+ SKINVECTOR(COLOR_INPUTBOX_N, '1 1 1');
+ SKINVECTOR(COLOR_INPUTBOX_F, '1 1 1');
+ SKINFLOAT(MARGIN_INPUTBOX, 0.02);
+
+ // item: key grabber
+ SKINVECTOR(COLOR_KEYGRABBER_TITLES, '1 1 1');
+ SKINFLOAT(ALPHA_KEYGRABBER_TITLES, 1);
+ SKINVECTOR(COLOR_KEYGRABBER_KEYS, '1 1 1');
+ SKINFLOAT(ALPHA_KEYGRABBER_KEYS, 0.7);
+
+ // item: list box
+ SKINVECTOR(COLOR_LISTBOX_SELECTED, '0 0 1');
+ SKINFLOAT(ALPHA_LISTBOX_SELECTED, 0.5);
+ SKINVECTOR(COLOR_LISTBOX_WAITING, '1 0 0');
+ SKINFLOAT(ALPHA_LISTBOX_WAITING, 0.5);
+
+ // item: map list
+ SKINVECTOR(COLOR_MAPLIST_TITLE, '1 1 1');
+ SKINVECTOR(COLOR_MAPLIST_AUTHOR, '0.4 0.4 0.7');
+ SKINVECTOR(COLOR_MAPLIST_INCLUDEDBG, '0 0 0');
+ SKINFLOAT(ALPHA_MAPLIST_INCLUDEDFG, 1);
+ SKINFLOAT(ALPHA_MAPLIST_INCLUDEDBG, 0.5);
+ SKINFLOAT(ALPHA_MAPLIST_NOTINCLUDEDFG, 0.4);
+
+ // item: nexposee
+ SKINVECTOR(ALPHAS_MAINMENU, '0.6 0.8 0.9');
+
+ // item: player color button
+ SKINSTRING(GFX_COLORBUTTON, "colorbutton");
+ SKINSTRING(GFX_COLORBUTTON_COLOR, "color");
+
+ // item: player model
+ SKINVECTOR(COLOR_MODELTITLE, '1 1 1');
+ SKINFLOAT(ALPHA_MODELTITLE, 1);
+
+ // item: player name editor
+ SKINSTRING(GFX_CHARMAP, "charmap");
+ SKINSTRING(GFX_CHARMAP_SELECTED, "charmapbutton");
+
+ // item: radio button
+ SKINSTRING(GFX_RADIOBUTTON, "radiobutton");
+ SKINVECTOR(COLOR_RADIOBUTTON_N, '1 1 1');
+ SKINVECTOR(COLOR_RADIOBUTTON_C, '1 1 1');
+ SKINVECTOR(COLOR_RADIOBUTTON_F, '1 1 1');
+ SKINVECTOR(COLOR_RADIOBUTTON_D, '1 1 1');
+
+ // item: scrollbar
+ SKINSTRING(GFX_SCROLLBAR, "scrollbar");
+ SKINVECTOR(COLOR_SCROLLBAR_N, '1 1 1');
+ SKINVECTOR(COLOR_SCROLLBAR_F, '1 1 1');
+ SKINVECTOR(COLOR_SCROLLBAR_S, '1 1 1');
+ SKINFLOAT(WIDTH_SCROLLBAR, 16);
+
+ // item: server list
+ SKINFLOAT(ALPHA_SERVERLIST_FULL, 0.2);
+ SKINFLOAT(ALPHA_SERVERLIST_EMPTY, 0.5);
+ SKINVECTOR(COLOR_SERVERLIST_LOWPING, '0 1 0');
+ SKINVECTOR(COLOR_SERVERLIST_MEDPING, '1 1 0');
+ SKINVECTOR(COLOR_SERVERLIST_HIGHPING, '1 0 0');
+ SKINFLOAT(ALPHA_SERVERLIST_HIGHPING, 0.2);
+
+ // item: slider
+ SKINSTRING(GFX_SLIDER, "slider");
+ SKINVECTOR(COLOR_SLIDER_N, '1 1 1');
+ SKINVECTOR(COLOR_SLIDER_C, '1 1 1');
+ SKINVECTOR(COLOR_SLIDER_F, '1 1 1');
+ SKINVECTOR(COLOR_SLIDER_D, '1 1 1');
+ SKINVECTOR(COLOR_SLIDER_S, '1 1 1');
+ SKINFLOAT(WIDTH_SLIDERTEXT, 0.333333333333);
+ SKINVECTOR(TOLERANCE_SLIDER, '0.2 2 0');
+SKINEND
Added: trunk/menu/skin.qh
===================================================================
--- trunk/menu/skin.qh (rev 0)
+++ trunk/menu/skin.qh 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1,23 @@
+#define SKINBEGIN
+#define SKINVECTOR(name,def) var vector SKIN##name = def
+#define SKINFLOAT(name,def) var float SKIN##name = def
+#define SKINSTRING(name,def) const string SKIN##name = def
+#define SKINEND
+#include "skin-customizables.inc"
+#undef SKINEND
+#undef SKINBEGIN
+#undef SKINSTRING
+#undef SKINFLOAT
+#undef SKINVECTOR
+
+#define SKINBEGIN void Skin_ApplySetting(string key, string value) { switch(key) {
+#define SKINVECTOR(name,def) case #name: SKIN##name = stov(value); break
+#define SKINFLOAT(name,def) case #name: SKIN##name = stof(value); break
+#define SKINSTRING(name,def) break
+#define SKINEND case "": break; case "//": break; default: print("Invalid key in skin file: ", key, "\n"); } }
+#include "skin-customizables.inc"
+#undef SKINEND
+#undef SKINSTRING
+#undef SKINFLOAT
+#undef SKINVECTOR
+#undef SKINBEGIN
Added: trunk/menu/todo
===================================================================
--- trunk/menu/todo (rev 0)
+++ trunk/menu/todo 2008-08-30 06:46:38 UTC (rev 122)
@@ -0,0 +1 @@
+TODO credits dialog
More information about the zymotic-commits
mailing list