#define IS_GAMETYPE(NAME) \
(MapInfo_LoadedGametype == MAPINFO_TYPE_##NAME)
-REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,false,"timelimit=20 pointlimit=30 leadlimit=0",_("Score as many frags as you can."));
+REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,false,"timelimit=20 pointlimit=30 leadlimit=0",_("Score as many frags as you can"));
#define g_dm IS_GAMETYPE(DEATHMATCH)
-REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,false,"timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left."));
+REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,false,"timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left"));
#define g_lms IS_GAMETYPE(LMS)
-REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,false,"timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line."));
+REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,false,"timelimit=20 qualifying_timelimit=5 laplimit=7 teamlaplimit=15 leadlimit=0",_("Race against other players to the finish line"));
#define g_race IS_GAMETYPE(RACE)
-REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,false,"timelimit=20 skill=-1",_("Race for fastest time."));
+REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,false,"timelimit=20 skill=-1",_("Race for fastest time"));
#define g_cts IS_GAMETYPE(CTS)
-REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,true,"timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team."));
+REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,true,"timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team"));
#define g_tdm IS_GAMETYPE(TEAM_DEATHMATCH)
-REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,true,"timelimit=20 caplimit=10 leadlimit=6",_("Find and bring the enemy flag to your base to capture it, defend your base from the other team."));
+REGISTER_GAMETYPE(_("Capture the Flag"),ctf,g_ctf,CTF,true,"timelimit=20 caplimit=10 leadlimit=6",_("Find and bring the enemy flag to your base to capture it, defend your base from the other team"));
#define g_ctf IS_GAMETYPE(CTF)
-REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,true,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill all enemy teammates to win the round."));
+REGISTER_GAMETYPE(_("Clan Arena"),ca,g_ca,CA,true,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill all enemy teammates to win the round"));
#define g_ca IS_GAMETYPE(CA)
-REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,true,"timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture and defend all the control points to win."));
+REGISTER_GAMETYPE(_("Domination"),dom,g_domination,DOMINATION,true,"timelimit=20 pointlimit=200 teams=2 leadlimit=0",_("Capture and defend all the control points to win"));
#define g_domination IS_GAMETYPE(DOMINATION)
-REGISTER_GAMETYPE(_("Key Hunt"),kh,g_keyhunt,KEYHUNT,true,"timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round."));
+REGISTER_GAMETYPE(_("Key Hunt"),kh,g_keyhunt,KEYHUNT,true,"timelimit=20 pointlimit=1000 teams=3 leadlimit=0",_("Gather all the keys to win the round"));
#define g_keyhunt IS_GAMETYPE(KEYHUNT)
-REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,true,"timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out."));
+REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,true,"timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out"));
#define g_assault IS_GAMETYPE(ASSAULT)
-REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,true,"pointlimit=1 timelimit=20",_("Capture control points to reach and destroy the enemy generator."));
+REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,true,"pointlimit=1 timelimit=20",_("Capture control points to reach and destroy the enemy generator"));
#define g_onslaught IS_GAMETYPE(ONSLAUGHT)
-REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,true,"timelimit=20 pointlimit=5 leadlimit=0",_("Shoot and kick the ball into the enemies goal, keep your goal clean."));
+REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,true,"timelimit=20 pointlimit=5 leadlimit=0",_("Shoot and kick the ball into the enemies goal, keep your goal clean"));
#define g_nexball IS_GAMETYPE(NEXBALL)
-REGISTER_GAMETYPE(_("Freeze Tag"),ft,g_freezetag,FREEZETAG,true,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to teammates to revive them, freeze the most enemies to win."));
+REGISTER_GAMETYPE(_("Freeze Tag"),ft,g_freezetag,FREEZETAG,true,"timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to teammates to revive them, freeze the most enemies to win"));
#define g_freezetag IS_GAMETYPE(FREEZETAG)
-REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,true,"timelimit=20 pointlimit=30",_("Hold the ball to get points for kills."));
+REGISTER_GAMETYPE(_("Keepaway"),ka,g_keepaway,KEEPAWAY,true,"timelimit=20 pointlimit=30",_("Hold the ball to get points for kills"));
#define g_keepaway IS_GAMETYPE(KEEPAWAY)
-REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,false,"pointlimit=50 teams=0",_("Survive against waves of monsters."));
+REGISTER_GAMETYPE(_("Invasion"),inv,g_invasion,INVASION,false,"pointlimit=50 teams=0",_("Survive against waves of monsters"));
#define g_invasion IS_GAMETYPE(INVASION)
const int MAPINFO_FEATURE_WEAPONS = 1; // not defined for instagib-only maps
ATTRIB(ListBox, focusable, float, 1)
ATTRIB(ListBox, focusedItem, int, -1)
ATTRIB(ListBox, focusedItemAlpha, float, 0.3)
+ METHOD(ListBox, setFocusedItem, void(entity, int));
ATTRIB(ListBox, mouseMoveOffset, float, -1) // let know where the cursor is when the list scrolls without moving the cursor
ATTRIB(ListBox, allowFocusSound, float, 1)
ATTRIB(ListBox, selectedItem, int, 0)
ATTRIB(ListBox, origin, vector, '0 0 0')
ATTRIB(ListBox, scrollPos, float, 0) // measured in window heights, fixed when needed
ATTRIB(ListBox, scrollPosTarget, float, 0)
+ METHOD(ListBox, isScrolling, bool(entity));
ATTRIB(ListBox, needScrollToItem, float, -1)
METHOD(ListBox, scrollToItem, void(entity, int));
ATTRIB(ListBox, previousValue, float, 0)
METHOD(ListBox, clickListBoxItem, void(entity, float, vector)); // item number, relative clickpos
METHOD(ListBox, doubleClickListBoxItem, void(entity, float, vector)); // item number, relative clickpos
METHOD(ListBox, setSelected, void(entity, float));
+ METHOD(ListBox, focusedItemChangeNotify, void(entity));
METHOD(ListBox, getLastFullyVisibleItemAtScrollPos, float(entity, float));
METHOD(ListBox, getFirstFullyVisibleItemAtScrollPos, float(entity, float));
#endif
#ifdef IMPLEMENTATION
+bool ListBox_isScrolling(entity me)
+{
+ return (me.scrollPos != me.scrollPosTarget);
+}
+
void ListBox_scrollToItem(entity me, int i)
{
// scroll doesn't work properly until itemHeight is set to the correct value
}
else if(key == K_MWHEELDOWN)
{
- me.scrollPosTarget = min(me.scrollPosTarget + 0.5, me.getTotalHeight(me) - 1);
+ me.scrollPosTarget = min(me.scrollPosTarget + 0.5, max(0, me.getTotalHeight(me) - 1));
}
else if(key == K_PGUP || key == K_KP_PGUP)
{
me.mouseMoveOffset = pos.y;
else
{
- me.focusedItem = -1;
+ me.setFocusedItem(me, -1);
me.mouseMoveOffset = -1;
}
return 1;
else if(me.pressed == 2)
{
me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
- me.focusedItem = me.selectedItem;
+ me.setFocusedItem(me, me.selectedItem);
me.mouseMoveOffset = -1;
}
return 1;
me.pressed = 2;
// an item has been clicked. Select it, ...
me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
- me.focusedItem = me.selectedItem;
+ me.setFocusedItem(me, me.selectedItem);
}
return 1;
}
+void ListBox_setFocusedItem(entity me, int item)
+{
+ float focusedItem_save = me.focusedItem;
+ me.focusedItem = (item < me.nItems) ? item : -1;
+ if(focusedItem_save != me.focusedItem)
+ {
+ me.focusedItemChangeNotify(me);
+ if(me.focusedItem >= 0)
+ me.focusedItemAlpha = SKINALPHA_LISTBOX_FOCUSED;
+ }
+}
float ListBox_mouseRelease(entity me, vector pos)
{
if(me.pressed == 1)
// item dragging mode
// select current one one last time...
me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
- me.focusedItem = me.selectedItem;
+ me.setFocusedItem(me, me.selectedItem);
// and give it a nice click event
if(me.nItems > 0)
{
// by a mouse click on an item of the list
// for example showing a dialog on right click
me.pressed = 0;
- me.focusedItem = -1;
+ me.setFocusedItem(me, -1);
me.mouseMoveOffset = -1;
}
void ListBox_updateControlTopBottom(entity me)
vector oldshift, oldscale;
// we can't do this in mouseMove as the list can scroll without moving the cursor
- float focusedItem_save = me.focusedItem;
if(me.mouseMoveOffset != -1)
- me.focusedItem = me.getItemAtPos(me, me.scrollPos + me.mouseMoveOffset);
- if(me.focusedItem >= 0)
- if(focusedItem_save != me.focusedItem)
- me.focusedItemAlpha = SKINALPHA_LISTBOX_FOCUSED;
+ me.setFocusedItem(me, me.getItemAtPos(me, me.scrollPos + me.mouseMoveOffset));
if(me.needScrollToItem >= 0)
{
SUPER(ListBox).draw(me);
}
+void ListBox_focusedItemChangeNotify(entity me)
+{
+}
+
void ListBox_clickListBoxItem(entity me, float i, vector where)
{
// template method
vector menuTooltipSize;
float menuTooltipAlpha;
string menuTooltipText;
-float menuTooltipState; // 0: static, 1: fading in, 2: fading out
+float menuTooltipState; // 0: static, 1: fading in, 2: fading out, 3: forced fading out
float m_testmousetooltipbox(vector pos)
{
if(pos.x >= menuTooltipOrigin.x && pos.x < menuTooltipOrigin.x + menuTooltipSize.x)
}
return menuTooltipItem.tooltip;
}
+string prev_tooltip;
void m_tooltip(vector pos)
{
float f, i, w;
menuTooltipAveragedMousePos = menuTooltipAveragedMousePos * (1 - f) + pos * f;
f = vlen(pos - menuTooltipAveragedMousePos);
if(f < 0.01)
+ {
it = m_findtooltipitem(main, pos);
+
+ if(it.instanceOfListBox && it.isScrolling(it))
+ it = world;
+
+ if(it && prev_tooltip != it.tooltip)
+ {
+ // fade out if tooltip of a certain item has changed
+ menuTooltipState = 3;
+ if(prev_tooltip)
+ strunzone(prev_tooltip);
+ prev_tooltip = strzone(it.tooltip);
+ }
+ else if(menuTooltipItem && !m_testmousetooltipbox(pos))
+ menuTooltipState = 3; // fade out if mouse touches it
+
+ }
else
it = NULL;
}
fontsize = '1 0 0' * (SKINFONTSIZE_TOOLTIP / conwidth) + '0 1 0' * (SKINFONTSIZE_TOOLTIP / conheight);
- // float menuTooltipState; // 0: static, 1: fading in, 2: fading out
+ // float menuTooltipState; // 0: static, 1: fading in, 2: fading out, 3: forced fading out
if(it != menuTooltipItem)
{
switch(menuTooltipState)
else if(menuTooltipState == 2) // re-fade in?
menuTooltipState = 1;
- if(menuTooltipItem)
- if(!m_testmousetooltipbox(pos))
- menuTooltipState = 2; // fade out if mouse touches it
-
switch(menuTooltipState)
{
- case 1:
+ case 1: // fade in
menuTooltipAlpha = bound(0, menuTooltipAlpha + 5 * frametime, 1);
if(menuTooltipAlpha == 1)
menuTooltipState = 0;
break;
- case 2:
+ case 2: // fade out
+ case 3: // forced fade out
menuTooltipAlpha = bound(0, menuTooltipAlpha - 2 * frametime, 1);
if(menuTooltipAlpha == 0)
{
if (returns) returns(it.title, string_null);
return it;
}
+ METHOD(SettingSource, getEntryTooltip, entity(entity this, int i, void(string theTooltip) returns))
+ {
+ Lazy l = Settings[i];
+ entity it = l.m_get();
+ if (returns) returns(it.tooltip);
+ return it;
+ }
METHOD(SettingSource, reload, int(entity this, string filter)) { return Settings_COUNT; }
ENDCLASS(SettingSource)
ATTRIB(XonoticRegisteredSettingsList, source, DataSource, NULL)
ATTRIB(XonoticRegisteredSettingsList, onChange, void(entity, entity), func_null)
ATTRIB(XonoticRegisteredSettingsList, onChangeEntity, entity, NULL)
+ METHOD(XonoticRegisteredSettingsList, focusedItemChangeNotify, void(entity));
+
string XonoticRegisteredSettingsList_cb_name;
- void XonoticRegisteredSettingsList_cb(string _name, string _icon)
+ string XonoticRegisteredSettingsList_cb_tooltip;
+ void XonoticRegisteredSettingsList_getNameIcon_cb(string _name, string _icon)
{
XonoticRegisteredSettingsList_cb_name = _name;
}
+ void XonoticRegisteredSettingsList_getTooltip_cb(string _tooltip)
+ {
+ XonoticRegisteredSettingsList_cb_tooltip = _tooltip;
+ }
+
METHOD(XonoticRegisteredSettingsList, drawListBoxItem, void(entity this, int i, vector absSize, bool isSelected, bool isFocused))
{
if (!this.source) return;
- if (!this.source.getEntry(this.source, i, XonoticRegisteredSettingsList_cb)) return;
+ if (!this.source.getEntry(this.source, i, XonoticRegisteredSettingsList_getNameIcon_cb)) return;
string name = XonoticRegisteredSettingsList_cb_name;
if (isSelected) {
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
string s = draw_TextShortenToWidth(strdecolorize(name), 1, 0, this.realFontSize);
draw_Text(this.realUpperMargin * eY + (0.5 * this.realFontSize.x) * eX, s, this.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
}
+
+ METHOD(XonoticRegisteredSettingsList, focusedItemChangeNotify, void(entity this))
+ {
+ if (this.focusedItem == -1 || !this.source)
+ {
+ clearTooltip(this);
+ return;
+ }
+ if (!this.source.getEntryTooltip(this, this.focusedItem, XonoticRegisteredSettingsList_getTooltip_cb))
+ {
+ clearTooltip(this);
+ return;
+ }
+ string theTooltip = XonoticRegisteredSettingsList_cb_tooltip;
+ if(theTooltip != "")
+ setZonedTooltip(this, theTooltip, string_null);
+ else
+ clearTooltip(this);
+ }
+
METHOD(XonoticRegisteredSettingsList, refilter, void(entity this))
{
if (!this.source) {
METHOD(XonoticGameModelSettingsTab, fill, void(entity));
METHOD(XonoticGameModelSettingsTab, showNotify, void(entity));
ATTRIB(XonoticGameModelSettingsTab, title, string, _("Models"))
+ ATTRIB(XonoticGameModelSettingsTab, tooltip, string, _("Customize how players and items are displayed in game"))
ATTRIB(XonoticGameModelSettingsTab, intendedWidth, float, 0.9)
ATTRIB(XonoticGameModelSettingsTab, rows, float, 13)
ATTRIB(XonoticGameModelSettingsTab, columns, float, 5)
METHOD(XonoticGametypeList, saveCvars, void(entity));
METHOD(XonoticGametypeList, keyDown, float(entity, float, float, float));
METHOD(XonoticGametypeList, clickListBoxItem, void(entity, float, vector));
+ METHOD(XonoticGametypeList, focusedItemChangeNotify, void(entity));
ATTRIB(XonoticGametypeList, realFontSize, vector, '0 0 0')
ATTRIB(XonoticGametypeList, realUpperMargin, float, 0)
{
m_play_click_sound(MENU_SOUND_SELECT);
}
+void XonoticGametypeList_focusedItemChangeNotify(entity me)
+{
+ if(me.focusedItem >= 0)
+ setZonedTooltip(me, MapInfo_Type_Description(GameType_GetID(me.focusedItem)), string_null);
+ else
+ clearTooltip(me);
+}
#endif