void(float width, float height) m_draw;
void(float mode) m_toggle;
void() m_shutdown;
+void(string name, string oldValue, string newValue) m_cvar_changed;
// optional: float(float) m_gethostcachecategory;
/////////////////////////////////////////////////////////
// generated file; do not modify
+#include <menu/cvarcallbackitem.qc>
#include <menu/draw.qc>
#include <menu/item.qc>
#include <menu/matrix.qc>
// generated file; do not modify
+#include <menu/cvarcallbackitem.qh>
#include <menu/draw.qh>
#include <menu/item.qh>
#include <menu/matrix.qh>
--- /dev/null
+#include "cvarcallbackitem.qh"
+
+entity createCvarCallbackItem(string theCvarName, cvar_callback theCallback, entity theContext)
+{
+ entity item;
+ item = NEW(CvarCallbackItem);
+ item.cvarName = theCvarName;
+ item.callback = theCallback;
+ item.context = theContext;
+ return item;
+}
\ No newline at end of file
--- /dev/null
+#pragma once
+
+#define cvar_callback void(string, string, string, entity)
+
+CLASS(CvarCallbackItem, Object)
+ ATTRIB(CvarCallbackItem, cvarName, string);
+ ATTRIB(CvarCallbackItem, callback, cvar_callback); // old value, new value
+ ATTRIB(CvarCallbackItem, context, entity);
+ENDCLASS(CvarCallbackItem)
+
+entity createCvarCallbackItem(string theCvarName, cvar_callback theCallback, entity theContext);
\ No newline at end of file
bool m_testmousetooltipbox(vector pos)
{
return !(
- (pos.x >= menuTooltipOrigin.x && pos.x < menuTooltipOrigin.x + menuTooltipSize.x)
- && (pos.y >= menuTooltipOrigin.y && pos.y < menuTooltipOrigin.y + menuTooltipSize.y)
- );
+ (pos.x >= menuTooltipOrigin.x && pos.x < menuTooltipOrigin.x + menuTooltipSize.x)
+ && (pos.y >= menuTooltipOrigin.y && pos.y < menuTooltipOrigin.y + menuTooltipSize.y)
+ );
}
bool m_testtooltipbox(vector tooltippos)
{
{
menuNotTheFirstFrame = true;
if (Menu_Active && !cvar("menu_video_played"))
- {
- localcmd("cd loop $menu_cdtrack\n");
- // TODO: use this when we have a welcome sound
- //localcmd("cd loop $menu_cdtrack; play sound/announcer/default/welcome.wav\n");
- menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading FIXME
- }
+ {
+ localcmd("cd loop $menu_cdtrack\n");
+ // TODO: use this when we have a welcome sound
+ //localcmd("cd loop $menu_cdtrack; play sound/announcer/default/welcome.wav\n");
+ menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading FIXME
+ }
// ALWAYS set this cvar; if we start but menu is not active, this means we want no background music!
localcmd("set menu_video_played 1\n");
}
if (Menu_Active)
{
if (getmousetarget() == (menuMouseMode ? MT_CLIENT : MT_MENU)
- && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))
- setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);
+ && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))
+ setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);
else m_hide();
}
if (!cvar("menu_sounds")) return;
localsound(soundfile);
}
+
+void m_cvar_changed(string theCvarName, string oldValue, string newValue)
+{
+ if (!menuInitialized) return;
+
+ // some variables have name "\n"
+ // LOG_INFOF("========> QC: Cvar \"%s\" changed from \"%s\" to \"%s\"",
+ // strreplace("\n", "\\n", theCvarName),
+ // strreplace("\n", "\\n", oldValue),
+ // strreplace("\n", "\\n", newValue)
+ // );
+
+ // search for subscribed callbacks and call them
+ IL_EACH(cvarCallbackItems, it.cvarName == theCvarName,
+ {
+ // LOG_INFOF("=========> Callback triggered for %s", it.name);
+ entity theContext = it.context;
+ it.callback(theCvarName, oldValue, newValue, theContext);
+ });
+}
+
+void cvar_onChangeSubscribe(string theCvarName, cvar_callback theCallback, entity theContext)
+{
+ entity callbackItem;
+ callbackItem = createCvarCallbackItem(theCvarName, theCallback, theContext);
+ IL_PUSH(cvarCallbackItems, callbackItem);
+}
\ No newline at end of file
#include <common/constants.qh>
#include <common/util.qh>
+#include "cvarcallbackitem.qh"
+
const int GAME_ISSERVER = BIT(0);
const int GAME_CONNECTED = BIT(1);
const int GAME_DEVELOPER = BIT(2);
void m_play_focus_sound();
void m_play_click_sound(string soundfile);
+
+// callback list and method to subscribe
+IntrusiveList cvarCallbackItems;
+STATIC_INIT(cvarCallbackItems) { cvarCallbackItems = IL_NEW(); }
+void cvar_onChangeSubscribe(string, cvar_callback, entity);
\ No newline at end of file
me = NEW(XonoticProfileTab);
me.configureDialog(me);
+ string name = cvar_string("_cl_name");
+ string playermodel = cvar_string("_cl_playermodel");
+ string playerskin = cvar_string("_cl_playerskin");
+ string color = cvar_string("_cl_color");
+
// if color unset, set random color (init it)
- if (cvar_string("_cl_color") == cvar_defstring("_cl_color"))
+ if (color == cvar_defstring("_cl_color"))
{
// idk what meaning of 16, maybe just COLOR_BUTTONS_COUNT+1
float randomColor = 16 * floor(random() * COLOR_BUTTONS_COUNT) + floor(random() * COLOR_BUTTONS_COUNT);
- cvar_set("_cl_color", ftos(randomColor));
+ color = ftos(randomColor);
+ cvar_set("_cl_color", color);
}
+ // copy field values from game cvars
+ cvar_set(MENU_CVAR_COLOR, color);
+ cvar_set(MENU_CVAR_NAME, name);
+ cvar_set(MENU_CVAR_SKIN, playerskin);
+ cvar_set(MENU_CVAR_MODEL, playermodel);
+
+ // subscribe to cvar changes
+
+ // stable branch cvars
+ cvar_onChangeSubscribe("_cl_name", onCvarChanged, me);
+ cvar_onChangeSubscribe("_cl_color", onCvarChanged, me);
+ cvar_onChangeSubscribe("_cl_playermodel", onCvarChanged, me);
+
+ // master branch cvars
+ cvar_onChangeSubscribe("name", onCvarChanged, me);
+ cvar_onChangeSubscribe("topcolor", onCvarChanged, me);
+ cvar_onChangeSubscribe("bottomcolor", onCvarChanged, me);
+ cvar_onChangeSubscribe("playermodel", onCvarChanged, me);
+
return me;
}
+// if values changed from console, update it in menu
+void onCvarChanged(string cvarName, string oldValue, string newValue, entity me)
+{
+ // IMPORTANT: dont change same cvars that was observed to avoid infinite loop
+
+ // nothing to change
+ if (oldValue == newValue)
+ {
+ return;
+ }
+
+ // not update field values when tab in 'edit mode'
+ if (!me.applyButton.disabled)
+ {
+ return;
+ }
+
+ // LOG_INFOF("[onCvarChanged]: %s, %s, %s", cvarName, oldValue, newValue);
+
+ // name
+ if (cvarName == "_cl_name" || cvarName == "name")
+ {
+ cvar_set(MENU_CVAR_NAME, newValue);
+ me.nameInput.loadCvars(me.nameInput);
+ }
+
+ // model
+ else if (cvarName == "_cl_playermodel" || cvarName == "playermodel")
+ {
+ cvar_set(MENU_CVAR_MODEL, newValue);
+ me.playerModelSelector.loadCvars(me.playerModelSelector);
+ me.playerModelSelector.go(me.playerModelSelector, 0);
+ }
+
+ // skin (skin not tested, dont know what cvars it use)
+ // else if (cvarName == "_cl_playerskin" || cvarName == "playerskin")
+ // {
+ // }
+
+ // color
+ else if (cvarName == "_cl_color")
+ {
+ cvar_set(MENU_CVAR_COLOR, newValue);
+ me.updateColor(me);
+ }
+ else if (cvarName == "topcolor" || cvarName == "bottomcolor")
+ {
+ cvar_set(MENU_CVAR_COLOR, cvar_string("_cl_color"));
+ me.updateColor(me);
+ }
+}
+
void XonoticProfileTab_draw(entity me)
{
string name = cvar_string("_cl_name");
me.playerNameLabel.alpha = ((mod(time * 2, 2) < 1) ? 1 : 0);
else
me.playerNameLabel.alpha = me.playerNameLabelAlpha;
-
- // if values changed from console, update it in menu
- if (me.applyButton.disabled)
- {
- // name field
- string inputName = cvar_string(MENU_CVAR_NAME);
- if (name != inputName)
- {
- cvar_set(MENU_CVAR_NAME, name);
- me.nameInput.loadCvars(me.nameInput);
- }
-
- // color buttons
- string color = cvar_string("_cl_color");
- string inputColor = cvar_string(MENU_CVAR_COLOR);
- if (color != inputColor)
- {
- cvar_set(MENU_CVAR_COLOR, color);
- for (int i = 0; i < COLOR_BUTTONS_COUNT; i++)
- {
- me.colorButtonGroup1[i].loadCvars(me.colorButtonGroup1[i]);
- me.colorButtonGroup2[i].loadCvars(me.colorButtonGroup2[i]);
- }
- }
-
- // player model
- string skin = cvar_string("_cl_playerskin");
- string skinInput = cvar_string(MENU_CVAR_SKIN);
- string model = cvar_string("_cl_playermodel");
- string modelInput = cvar_string(MENU_CVAR_MODEL);
- if (skin != skinInput || model != modelInput)
- {
- cvar_set(MENU_CVAR_SKIN, skin);
- cvar_set(MENU_CVAR_MODEL, model);
- me.playerModelSelector.loadCvars(me.playerModelSelector);
- me.playerModelSelector.go(me.playerModelSelector, 0);
- }
- }
SUPER(XonoticProfileTab).draw(me);
}
entity e, label;
float i;
me.applyButton = makeXonoticCommandButton(_("Apply immediately"), '0 0 0',
- "_cl_color \"$"MENU_CVAR_COLOR"\""
+ "_cl_color \"$"MENU_CVAR_COLOR"\";"
"color -1 -1;" // apply colors contained in _cl_color
"name \"$"MENU_CVAR_NAME"\";"
"playermodel $"MENU_CVAR_MODEL";"
me.gotoRC(me, me.rows - 1, 0);
me.TD(me, 1, me.columns, me.applyButton);
}
+
+void XonoticProfileTab_updateColor(entity me)
+{
+ for (int i = 0; i < COLOR_BUTTONS_COUNT; i++)
+ {
+ me.colorButtonGroup1[i].loadCvars(me.colorButtonGroup1[i]);
+ me.colorButtonGroup2[i].loadCvars(me.colorButtonGroup2[i]);
+ }
+}
\ No newline at end of file
CLASS(XonoticProfileTab, XonoticTab)
METHOD(XonoticProfileTab, fill, void(entity));
METHOD(XonoticProfileTab, draw, void(entity));
+ METHOD(XonoticProfileTab, updateColor, void(entity));
ATTRIB(XonoticProfileTab, intendedWidth, float, 0.9);
ATTRIB(XonoticProfileTab, rows, float, 23);
ATTRIB(XonoticProfileTab, columns, float, 6.1); // added extra .2 for center space
ATTRIB(XonoticProfileTab, playerModelSelector, entity);
ENDCLASS(XonoticProfileTab)
entity makeXonoticProfileTab();
+
+cvar_callback onCvarChanged;
\ No newline at end of file