]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Rename menu files to be consistent
authorTimePath <andrew.hardaker1995@gmail.com>
Sun, 25 Jan 2015 04:02:50 +0000 (15:02 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Sun, 25 Jan 2015 04:02:50 +0000 (15:02 +1100)
*.h -> *.qh
*.c -> *.qc

271 files changed:
qcsrc/menu/anim/animation.c [deleted file]
qcsrc/menu/anim/animation.qc [new file with mode: 0644]
qcsrc/menu/anim/animhost.c [deleted file]
qcsrc/menu/anim/animhost.qc [new file with mode: 0644]
qcsrc/menu/anim/easing.c [deleted file]
qcsrc/menu/anim/easing.qc [new file with mode: 0644]
qcsrc/menu/anim/keyframe.c [deleted file]
qcsrc/menu/anim/keyframe.qc [new file with mode: 0644]
qcsrc/menu/classes.c [deleted file]
qcsrc/menu/classes.qc [new file with mode: 0644]
qcsrc/menu/item.c [deleted file]
qcsrc/menu/item.qc [new file with mode: 0644]
qcsrc/menu/item/borderimage.c [deleted file]
qcsrc/menu/item/borderimage.qc [new file with mode: 0644]
qcsrc/menu/item/button.c [deleted file]
qcsrc/menu/item/button.qc [new file with mode: 0644]
qcsrc/menu/item/checkbox.c [deleted file]
qcsrc/menu/item/checkbox.qc [new file with mode: 0644]
qcsrc/menu/item/container.c [deleted file]
qcsrc/menu/item/container.qc [new file with mode: 0644]
qcsrc/menu/item/dialog.c [deleted file]
qcsrc/menu/item/dialog.qc [new file with mode: 0644]
qcsrc/menu/item/image.c [deleted file]
qcsrc/menu/item/image.qc [new file with mode: 0644]
qcsrc/menu/item/inputbox.c [deleted file]
qcsrc/menu/item/inputbox.qc [new file with mode: 0644]
qcsrc/menu/item/inputcontainer.c [deleted file]
qcsrc/menu/item/inputcontainer.qc [new file with mode: 0644]
qcsrc/menu/item/label.c [deleted file]
qcsrc/menu/item/label.qc [new file with mode: 0644]
qcsrc/menu/item/listbox.c [deleted file]
qcsrc/menu/item/listbox.qc [new file with mode: 0644]
qcsrc/menu/item/modalcontroller.c [deleted file]
qcsrc/menu/item/modalcontroller.qc [new file with mode: 0644]
qcsrc/menu/item/nexposee.c [deleted file]
qcsrc/menu/item/nexposee.qc [new file with mode: 0644]
qcsrc/menu/item/radiobutton.c [deleted file]
qcsrc/menu/item/radiobutton.qc [new file with mode: 0644]
qcsrc/menu/item/slider.c [deleted file]
qcsrc/menu/item/slider.qc [new file with mode: 0644]
qcsrc/menu/item/tab.c [deleted file]
qcsrc/menu/item/tab.qc [new file with mode: 0644]
qcsrc/menu/item/textslider.c [deleted file]
qcsrc/menu/item/textslider.qc [new file with mode: 0644]
qcsrc/menu/oo/base.h [deleted file]
qcsrc/menu/oo/base.qh [new file with mode: 0644]
qcsrc/menu/oo/implementation.h [deleted file]
qcsrc/menu/oo/implementation.qh [new file with mode: 0644]
qcsrc/menu/oo/interface.h [deleted file]
qcsrc/menu/oo/interface.qh [new file with mode: 0644]
qcsrc/menu/progs.src
qcsrc/menu/xonotic/bigbutton.c [deleted file]
qcsrc/menu/xonotic/bigbutton.qc [new file with mode: 0644]
qcsrc/menu/xonotic/bigcommandbutton.c [deleted file]
qcsrc/menu/xonotic/bigcommandbutton.qc [new file with mode: 0644]
qcsrc/menu/xonotic/button.c [deleted file]
qcsrc/menu/xonotic/button.qc [new file with mode: 0644]
qcsrc/menu/xonotic/campaign.c [deleted file]
qcsrc/menu/xonotic/campaign.qc [new file with mode: 0644]
qcsrc/menu/xonotic/charmap.c [deleted file]
qcsrc/menu/xonotic/charmap.qc [new file with mode: 0644]
qcsrc/menu/xonotic/checkbox.c [deleted file]
qcsrc/menu/xonotic/checkbox.qc [new file with mode: 0644]
qcsrc/menu/xonotic/checkbox_slider_invalid.c [deleted file]
qcsrc/menu/xonotic/checkbox_slider_invalid.qc [new file with mode: 0644]
qcsrc/menu/xonotic/checkbox_string.c [deleted file]
qcsrc/menu/xonotic/checkbox_string.qc [new file with mode: 0644]
qcsrc/menu/xonotic/colorbutton.c [deleted file]
qcsrc/menu/xonotic/colorbutton.qc [new file with mode: 0644]
qcsrc/menu/xonotic/colorpicker.c [deleted file]
qcsrc/menu/xonotic/colorpicker.qc [new file with mode: 0644]
qcsrc/menu/xonotic/colorpicker_string.c [deleted file]
qcsrc/menu/xonotic/colorpicker_string.qc [new file with mode: 0644]
qcsrc/menu/xonotic/commandbutton.c [deleted file]
qcsrc/menu/xonotic/commandbutton.qc [new file with mode: 0644]
qcsrc/menu/xonotic/credits.c [deleted file]
qcsrc/menu/xonotic/credits.qc [new file with mode: 0644]
qcsrc/menu/xonotic/crosshairbutton.c [deleted file]
qcsrc/menu/xonotic/crosshairbutton.qc [new file with mode: 0644]
qcsrc/menu/xonotic/cvarlist.c [deleted file]
qcsrc/menu/xonotic/cvarlist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/demolist.c [deleted file]
qcsrc/menu/xonotic/demolist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog.c [deleted file]
qcsrc/menu/xonotic/dialog.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_credits.c [deleted file]
qcsrc/menu/xonotic/dialog_credits.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_firstrun.c [deleted file]
qcsrc/menu/xonotic/dialog_firstrun.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_ammo.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_buffs.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_buffs.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_centerprint.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_chat.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_chat.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_infomessages.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_modicons.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_modicons.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_notification.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_notification.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_physics.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_physics.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_powerups.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_racetimer.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_racetimer.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_radar.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_radar.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_score.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_score.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_timer.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_timer.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_vote.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_vote.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudpanel_weapons.c [deleted file]
qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_hudsetup_exit.c [deleted file]
qcsrc/menu/xonotic/dialog_hudsetup_exit.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_monstertools.c [deleted file]
qcsrc/menu/xonotic/dialog_monstertools.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_create.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_create.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_join.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_join.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_media.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_demo.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_multiplayer_profile.c [deleted file]
qcsrc/menu/xonotic/dialog_multiplayer_profile.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_quit.c [deleted file]
qcsrc/menu/xonotic/dialog_quit.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_sandboxtools.c [deleted file]
qcsrc/menu/xonotic/dialog_sandboxtools.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings.c [deleted file]
qcsrc/menu/xonotic/dialog_settings.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_audio.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_audio.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_effects.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_effects.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_game.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_crosshair.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_hud.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_game_hud.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_messages.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_game_messages.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_model.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_game_model.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_view.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_game_view.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_weapons.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_game_weapons.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_input.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_input.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_input_userbind.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_input_userbind.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_misc.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_misc.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_misc_cvars.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_misc_reset.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_misc_reset.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_user.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_user.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_user_languagewarning.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_video.c [deleted file]
qcsrc/menu/xonotic/dialog_settings_video.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_singleplayer.c [deleted file]
qcsrc/menu/xonotic/dialog_singleplayer.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_singleplayer_winner.c [deleted file]
qcsrc/menu/xonotic/dialog_singleplayer_winner.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_teamselect.c [deleted file]
qcsrc/menu/xonotic/dialog_teamselect.qc [new file with mode: 0644]
qcsrc/menu/xonotic/gametypebutton.c [deleted file]
qcsrc/menu/xonotic/gametypebutton.qc [new file with mode: 0644]
qcsrc/menu/xonotic/gametypelist.c [deleted file]
qcsrc/menu/xonotic/gametypelist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/image.c [deleted file]
qcsrc/menu/xonotic/image.qc [new file with mode: 0644]
qcsrc/menu/xonotic/inputbox.c [deleted file]
qcsrc/menu/xonotic/inputbox.qc [new file with mode: 0644]
qcsrc/menu/xonotic/keybinder.c [deleted file]
qcsrc/menu/xonotic/keybinder.qc [new file with mode: 0644]
qcsrc/menu/xonotic/languagelist.c [deleted file]
qcsrc/menu/xonotic/languagelist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/listbox.c [deleted file]
qcsrc/menu/xonotic/listbox.qc [new file with mode: 0644]
qcsrc/menu/xonotic/mainwindow.c [deleted file]
qcsrc/menu/xonotic/mainwindow.qc [new file with mode: 0644]
qcsrc/menu/xonotic/maplist.c [deleted file]
qcsrc/menu/xonotic/maplist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/nexposee.c [deleted file]
qcsrc/menu/xonotic/nexposee.qc [new file with mode: 0644]
qcsrc/menu/xonotic/playerlist.c [deleted file]
qcsrc/menu/xonotic/playerlist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/playermodel.c [deleted file]
qcsrc/menu/xonotic/playermodel.qc [new file with mode: 0644]
qcsrc/menu/xonotic/playlist.c [deleted file]
qcsrc/menu/xonotic/playlist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/radiobutton.c [deleted file]
qcsrc/menu/xonotic/radiobutton.qc [new file with mode: 0644]
qcsrc/menu/xonotic/rootdialog.c [deleted file]
qcsrc/menu/xonotic/rootdialog.qc [new file with mode: 0644]
qcsrc/menu/xonotic/screenshotimage.c [deleted file]
qcsrc/menu/xonotic/screenshotimage.qc [new file with mode: 0644]
qcsrc/menu/xonotic/screenshotlist.c [deleted file]
qcsrc/menu/xonotic/screenshotlist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/serverlist.c [deleted file]
qcsrc/menu/xonotic/serverlist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/skinlist.c [deleted file]
qcsrc/menu/xonotic/skinlist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/slider.c [deleted file]
qcsrc/menu/xonotic/slider.qc [new file with mode: 0644]
qcsrc/menu/xonotic/slider_decibels.c [deleted file]
qcsrc/menu/xonotic/slider_decibels.qc [new file with mode: 0644]
qcsrc/menu/xonotic/slider_particles.c [deleted file]
qcsrc/menu/xonotic/slider_particles.qc [new file with mode: 0644]
qcsrc/menu/xonotic/slider_picmip.c [deleted file]
qcsrc/menu/xonotic/slider_picmip.qc [new file with mode: 0644]
qcsrc/menu/xonotic/slider_resolution.c [deleted file]
qcsrc/menu/xonotic/slider_resolution.qc [new file with mode: 0644]
qcsrc/menu/xonotic/slider_sbfadetime.c [deleted file]
qcsrc/menu/xonotic/slider_sbfadetime.qc [new file with mode: 0644]
qcsrc/menu/xonotic/soundlist.c [deleted file]
qcsrc/menu/xonotic/soundlist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/statslist.c [deleted file]
qcsrc/menu/xonotic/statslist.qc [new file with mode: 0644]
qcsrc/menu/xonotic/tab.c [deleted file]
qcsrc/menu/xonotic/tab.qc [new file with mode: 0644]
qcsrc/menu/xonotic/tabcontroller.c [deleted file]
qcsrc/menu/xonotic/tabcontroller.qc [new file with mode: 0644]
qcsrc/menu/xonotic/textlabel.c [deleted file]
qcsrc/menu/xonotic/textlabel.qc [new file with mode: 0644]
qcsrc/menu/xonotic/textslider.c [deleted file]
qcsrc/menu/xonotic/textslider.qc [new file with mode: 0644]
qcsrc/menu/xonotic/weaponarenacheckbox.c [deleted file]
qcsrc/menu/xonotic/weaponarenacheckbox.qc [new file with mode: 0644]
qcsrc/menu/xonotic/weaponslist.c [deleted file]
qcsrc/menu/xonotic/weaponslist.qc [new file with mode: 0644]

diff --git a/qcsrc/menu/anim/animation.c b/qcsrc/menu/anim/animation.c
deleted file mode 100644 (file)
index 99ccc78..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-#ifdef INTERFACE
-CLASS(Animation) EXTENDS(Object)
-       METHOD(Animation, configureAnimation, void(entity, entity, void(entity, float), float, float, float, float))
-       METHOD(Animation, setTimeStartEnd, void(entity, float, float))
-       METHOD(Animation, setTimeStartDuration, void(entity, float, float))
-       METHOD(Animation, setValueStartEnd, void(entity, float, float))
-       METHOD(Animation, setValueStartDelta, void(entity, float, float))
-       METHOD(Animation, setObjectSetter, void(entity, entity, void(entity, float)))
-       METHOD(Animation, tick, void(entity, float))
-       METHOD(Animation, calcValue, float(entity, float, float, float, float))
-       METHOD(Animation, isStopped, float(entity))
-       METHOD(Animation, stopAnim, void(entity))
-       METHOD(Animation, resumeAnim, void(entity))
-       METHOD(Animation, isFinished, float(entity))
-       METHOD(Animation, finishAnim, void(entity))
-       ATTRIB(Animation, object, entity, NULL)
-       ATTRIB(Animation, setter, void(entity, float), setterDummy)
-       ATTRIB(Animation, value, float, 0)
-       ATTRIB(Animation, startTime, float, 0)
-       ATTRIB(Animation, duration, float, 0)
-       ATTRIB(Animation, startValue, float, 0)
-       ATTRIB(Animation, delta, float, 0)
-       ATTRIB(Animation, stopped, float, FALSE)
-       ATTRIB(Animation, finished, float, FALSE)
-ENDCLASS(Animation)
-void setterDummy(entity, float);
-#endif
-
-#ifdef IMPLEMENTATION
-void Animation_configureAnimation(entity me, entity obj, void(entity, float) objSetter, float animStartTime, float animDuration, float animStartValue, float animEndValue)
-{
-       me.setObjectSetter(me, obj, objSetter);
-       me.setTimeStartDuration(me, animStartTime, animDuration);
-       me.setValueStartEnd(me, animStartValue, animEndValue);
-}
-
-void Animation_setTimeStartEnd(entity me, float s, float e)
-{
-       me.startTime = s;
-       me.duration = e - s;
-}
-
-void Animation_setTimeStartDuration(entity me, float s, float d)
-{
-       me.startTime = s;
-       me.duration = d;
-}
-
-void Animation_setValueStartEnd(entity me, float s, float e)
-{
-       me.startValue = s;
-       me.delta = e - s;
-}
-
-void Animation_setValueStartDelta(entity me, float s, float d)
-{
-       me.startValue = s;
-       me.delta = d;
-}
-
-void Animation_setObjectSetter(entity me, entity o, void(entity, float) s)
-{
-       me.object = o;
-       me.setter = s;
-}
-
-void Animation_tick(entity me, float tickTime)
-{
-       if (me.isStopped(me) || me.isFinished(me) || (tickTime < me.startTime))
-               return;
-
-       if (tickTime >= (me.startTime + me.duration))
-               me.finishAnim(me);
-       else
-               me.value = me.calcValue(me, (tickTime - me.startTime), me.duration, me.startValue, me.delta);
-
-       me.setter(me.object, me.value);
-}
-
-float Animation_calcValue(entity me, float tickTime, float animDuration, float animStartValue, float animDelta)
-{
-       return animStartValue;
-}
-
-float Animation_isStopped(entity me)
-{
-       return me.stopped;
-}
-
-void Animation_stopAnim(entity me)
-{
-       me.stopped = TRUE;
-}
-
-void Animation_resumeAnim(entity me)
-{
-       me.stopped = FALSE;
-}
-
-float Animation_isFinished(entity me)
-{
-       return me.finished;
-}
-
-void Animation_finishAnim(entity me)
-{
-       me.value = me.delta + me.startValue;
-       me.finished = TRUE;
-       me.setter(me.object, me.value);
-}
-
-void setterDummy(entity obj, float objValue)
-{
-}
-
-#endif
diff --git a/qcsrc/menu/anim/animation.qc b/qcsrc/menu/anim/animation.qc
new file mode 100644 (file)
index 0000000..99ccc78
--- /dev/null
@@ -0,0 +1,116 @@
+#ifdef INTERFACE
+CLASS(Animation) EXTENDS(Object)
+       METHOD(Animation, configureAnimation, void(entity, entity, void(entity, float), float, float, float, float))
+       METHOD(Animation, setTimeStartEnd, void(entity, float, float))
+       METHOD(Animation, setTimeStartDuration, void(entity, float, float))
+       METHOD(Animation, setValueStartEnd, void(entity, float, float))
+       METHOD(Animation, setValueStartDelta, void(entity, float, float))
+       METHOD(Animation, setObjectSetter, void(entity, entity, void(entity, float)))
+       METHOD(Animation, tick, void(entity, float))
+       METHOD(Animation, calcValue, float(entity, float, float, float, float))
+       METHOD(Animation, isStopped, float(entity))
+       METHOD(Animation, stopAnim, void(entity))
+       METHOD(Animation, resumeAnim, void(entity))
+       METHOD(Animation, isFinished, float(entity))
+       METHOD(Animation, finishAnim, void(entity))
+       ATTRIB(Animation, object, entity, NULL)
+       ATTRIB(Animation, setter, void(entity, float), setterDummy)
+       ATTRIB(Animation, value, float, 0)
+       ATTRIB(Animation, startTime, float, 0)
+       ATTRIB(Animation, duration, float, 0)
+       ATTRIB(Animation, startValue, float, 0)
+       ATTRIB(Animation, delta, float, 0)
+       ATTRIB(Animation, stopped, float, FALSE)
+       ATTRIB(Animation, finished, float, FALSE)
+ENDCLASS(Animation)
+void setterDummy(entity, float);
+#endif
+
+#ifdef IMPLEMENTATION
+void Animation_configureAnimation(entity me, entity obj, void(entity, float) objSetter, float animStartTime, float animDuration, float animStartValue, float animEndValue)
+{
+       me.setObjectSetter(me, obj, objSetter);
+       me.setTimeStartDuration(me, animStartTime, animDuration);
+       me.setValueStartEnd(me, animStartValue, animEndValue);
+}
+
+void Animation_setTimeStartEnd(entity me, float s, float e)
+{
+       me.startTime = s;
+       me.duration = e - s;
+}
+
+void Animation_setTimeStartDuration(entity me, float s, float d)
+{
+       me.startTime = s;
+       me.duration = d;
+}
+
+void Animation_setValueStartEnd(entity me, float s, float e)
+{
+       me.startValue = s;
+       me.delta = e - s;
+}
+
+void Animation_setValueStartDelta(entity me, float s, float d)
+{
+       me.startValue = s;
+       me.delta = d;
+}
+
+void Animation_setObjectSetter(entity me, entity o, void(entity, float) s)
+{
+       me.object = o;
+       me.setter = s;
+}
+
+void Animation_tick(entity me, float tickTime)
+{
+       if (me.isStopped(me) || me.isFinished(me) || (tickTime < me.startTime))
+               return;
+
+       if (tickTime >= (me.startTime + me.duration))
+               me.finishAnim(me);
+       else
+               me.value = me.calcValue(me, (tickTime - me.startTime), me.duration, me.startValue, me.delta);
+
+       me.setter(me.object, me.value);
+}
+
+float Animation_calcValue(entity me, float tickTime, float animDuration, float animStartValue, float animDelta)
+{
+       return animStartValue;
+}
+
+float Animation_isStopped(entity me)
+{
+       return me.stopped;
+}
+
+void Animation_stopAnim(entity me)
+{
+       me.stopped = TRUE;
+}
+
+void Animation_resumeAnim(entity me)
+{
+       me.stopped = FALSE;
+}
+
+float Animation_isFinished(entity me)
+{
+       return me.finished;
+}
+
+void Animation_finishAnim(entity me)
+{
+       me.value = me.delta + me.startValue;
+       me.finished = TRUE;
+       me.setter(me.object, me.value);
+}
+
+void setterDummy(entity obj, float objValue)
+{
+}
+
+#endif
diff --git a/qcsrc/menu/anim/animhost.c b/qcsrc/menu/anim/animhost.c
deleted file mode 100644 (file)
index ae84e09..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifdef INTERFACE
-CLASS(AnimHost) EXTENDS(Object)
-       METHOD(AnimHost, addAnim, void(entity, entity))
-       METHOD(AnimHost, removeAnim, void(entity, entity))
-       METHOD(AnimHost, removeAllAnim, void(entity))
-       METHOD(AnimHost, removeObjAnim, void(entity, entity))
-       METHOD(AnimHost, stopAllAnim, void(entity))
-       METHOD(AnimHost, stopObjAnim, void(entity, entity))
-       METHOD(AnimHost, resumeAllAnim, void(entity))
-       METHOD(AnimHost, resumeObjAnim, void(entity, entity))
-       METHOD(AnimHost, finishAllAnim, void(entity))
-       METHOD(AnimHost, finishObjAnim, void(entity, entity))
-       METHOD(AnimHost, tickAll, void(entity))
-       ATTRIB(AnimHost, firstChild, entity, NULL)
-       ATTRIB(AnimHost, lastChild, entity, NULL)
-ENDCLASS(AnimHost)
-.entity nextSibling;
-.entity prevSibling;
-#endif
-
-#ifdef IMPLEMENTATION
-void AnimHost_addAnim(entity me, entity other)
-{
-       if(other.parent)
-               error("Can't add already added anim!");
-
-       if(other.isFinished(other))
-               error("Can't add finished anim!");
-
-       other.parent = me;
-
-       entity l;
-       l = me.lastChild;
-
-       if(l)
-               l.nextSibling = other;
-       else
-               me.firstChild = other;
-
-       other.prevSibling = l;
-       other.nextSibling = NULL;
-       me.lastChild = other;
-}
-
-void AnimHost_removeAnim(entity me, entity other)
-{
-       if(other.parent != me)
-               error("Can't remove from wrong AnimHost!");
-
-       other.parent = NULL;
-
-       entity n, p;
-       n = other.nextSibling;
-       p = other.prevSibling;
-
-       if(p)
-               p.nextSibling = n;
-       else
-               me.firstChild = n;
-
-       if(n)
-               n.prevSibling = p;
-       else
-               me.lastChild = p;
-       remove(other);
-}
-
-void AnimHost_removeAllAnim(entity me)
-{
-       entity e, tmp;
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               tmp = e;
-               e = tmp.prevSibling;
-               me.removeAnim(me, tmp);
-       }
-}
-
-void AnimHost_removeObjAnim(entity me, entity obj)
-{
-       entity e, tmp;
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               if (e.object == obj)
-               {
-                       tmp = e;
-                       e = tmp.prevSibling;
-                       me.removeAnim(me, tmp);
-               }
-       }
-}
-
-void AnimHost_stopAllAnim(entity me)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               e.stopAnim(e);
-       }
-}
-
-void AnimHost_stopObjAnim(entity me, entity obj)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               if (e.object == obj)
-               {
-                       e.stopAnim(e);
-               }
-       }
-}
-
-void AnimHost_resumeAllAnim(entity me)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               e.resumeAnim(e);
-       }
-}
-
-void AnimHost_resumeObjAnim(entity me, entity obj)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               if (e.object == obj)
-               {
-                       e.resumeAnim(e);
-               }
-       }
-}
-
-void AnimHost_finishAllAnim(entity me)
-{
-       entity e, tmp;
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               tmp = e;
-               e = tmp.prevSibling;
-               tmp.finishAnim(tmp);
-       }
-}
-
-void AnimHost_finishObjAnim(entity me, entity obj)
-{
-       entity e, tmp;
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               if (e.object == obj)
-               {
-                       tmp = e;
-                       e = tmp.prevSibling;
-                       tmp.finishAnim(tmp);
-               }
-       }
-}
-
-void AnimHost_tickAll(entity me)
-{
-       entity e, tmp;
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               e.tick(e, time);
-               if (e.isFinished(e))
-               {
-                       tmp = e;
-                       e = tmp.prevSibling;
-                       me.removeAnim(me, tmp);
-               }
-       }
-}
-#endif
diff --git a/qcsrc/menu/anim/animhost.qc b/qcsrc/menu/anim/animhost.qc
new file mode 100644 (file)
index 0000000..ae84e09
--- /dev/null
@@ -0,0 +1,174 @@
+#ifdef INTERFACE
+CLASS(AnimHost) EXTENDS(Object)
+       METHOD(AnimHost, addAnim, void(entity, entity))
+       METHOD(AnimHost, removeAnim, void(entity, entity))
+       METHOD(AnimHost, removeAllAnim, void(entity))
+       METHOD(AnimHost, removeObjAnim, void(entity, entity))
+       METHOD(AnimHost, stopAllAnim, void(entity))
+       METHOD(AnimHost, stopObjAnim, void(entity, entity))
+       METHOD(AnimHost, resumeAllAnim, void(entity))
+       METHOD(AnimHost, resumeObjAnim, void(entity, entity))
+       METHOD(AnimHost, finishAllAnim, void(entity))
+       METHOD(AnimHost, finishObjAnim, void(entity, entity))
+       METHOD(AnimHost, tickAll, void(entity))
+       ATTRIB(AnimHost, firstChild, entity, NULL)
+       ATTRIB(AnimHost, lastChild, entity, NULL)
+ENDCLASS(AnimHost)
+.entity nextSibling;
+.entity prevSibling;
+#endif
+
+#ifdef IMPLEMENTATION
+void AnimHost_addAnim(entity me, entity other)
+{
+       if(other.parent)
+               error("Can't add already added anim!");
+
+       if(other.isFinished(other))
+               error("Can't add finished anim!");
+
+       other.parent = me;
+
+       entity l;
+       l = me.lastChild;
+
+       if(l)
+               l.nextSibling = other;
+       else
+               me.firstChild = other;
+
+       other.prevSibling = l;
+       other.nextSibling = NULL;
+       me.lastChild = other;
+}
+
+void AnimHost_removeAnim(entity me, entity other)
+{
+       if(other.parent != me)
+               error("Can't remove from wrong AnimHost!");
+
+       other.parent = NULL;
+
+       entity n, p;
+       n = other.nextSibling;
+       p = other.prevSibling;
+
+       if(p)
+               p.nextSibling = n;
+       else
+               me.firstChild = n;
+
+       if(n)
+               n.prevSibling = p;
+       else
+               me.lastChild = p;
+       remove(other);
+}
+
+void AnimHost_removeAllAnim(entity me)
+{
+       entity e, tmp;
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               tmp = e;
+               e = tmp.prevSibling;
+               me.removeAnim(me, tmp);
+       }
+}
+
+void AnimHost_removeObjAnim(entity me, entity obj)
+{
+       entity e, tmp;
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               if (e.object == obj)
+               {
+                       tmp = e;
+                       e = tmp.prevSibling;
+                       me.removeAnim(me, tmp);
+               }
+       }
+}
+
+void AnimHost_stopAllAnim(entity me)
+{
+       entity e;
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               e.stopAnim(e);
+       }
+}
+
+void AnimHost_stopObjAnim(entity me, entity obj)
+{
+       entity e;
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               if (e.object == obj)
+               {
+                       e.stopAnim(e);
+               }
+       }
+}
+
+void AnimHost_resumeAllAnim(entity me)
+{
+       entity e;
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               e.resumeAnim(e);
+       }
+}
+
+void AnimHost_resumeObjAnim(entity me, entity obj)
+{
+       entity e;
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               if (e.object == obj)
+               {
+                       e.resumeAnim(e);
+               }
+       }
+}
+
+void AnimHost_finishAllAnim(entity me)
+{
+       entity e, tmp;
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               tmp = e;
+               e = tmp.prevSibling;
+               tmp.finishAnim(tmp);
+       }
+}
+
+void AnimHost_finishObjAnim(entity me, entity obj)
+{
+       entity e, tmp;
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               if (e.object == obj)
+               {
+                       tmp = e;
+                       e = tmp.prevSibling;
+                       tmp.finishAnim(tmp);
+               }
+       }
+}
+
+void AnimHost_tickAll(entity me)
+{
+       entity e, tmp;
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               e.tick(e, time);
+               if (e.isFinished(e))
+               {
+                       tmp = e;
+                       e = tmp.prevSibling;
+                       me.removeAnim(me, tmp);
+               }
+       }
+}
+#endif
diff --git a/qcsrc/menu/anim/easing.c b/qcsrc/menu/anim/easing.c
deleted file mode 100644 (file)
index 94ea9cf..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifdef INTERFACE
-CLASS(Easing) EXTENDS(Animation)
-       METHOD(Easing, calcValue, float(entity, float, float, float, float))
-       METHOD(Easing, setMath, void(entity, float(float, float, float, float)))
-       ATTRIB(Easing, math, float(float, float, float, float), easingLinear)
-ENDCLASS(Easing)
-entity makeHostedEasing(entity, void(entity, float), float(float, float, float, float), float, float, float);
-entity makeEasing(entity, void(entity, float), float(float, float, float, float), float, float, float, float);
-float easingLinear(float, float, float, float);
-float easingQuadIn(float, float, float, float);
-float easingQuadOut(float, float, float, float);
-float easingQuadInOut(float, float, float, float);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeHostedEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animDuration, float animStartValue, float animEnd)
-{
-       entity me;
-       me = makeEasing(obj, objSetter, func, time, animDuration, animStartValue, animEnd);
-       anim.addAnim(anim, me);
-       return me;
-}
-
-entity makeEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animStartTime, float animDuration, float animStartValue, float animEnd)
-{
-       entity me;
-       me = spawnEasing();
-       me.configureAnimation(me, obj, objSetter, animStartTime, animDuration, animStartValue, animEnd);
-       me.setMath(me, func);
-       return me;
-}
-
-float Easing_calcValue(entity me, float tickTime, float animDuration, float animStart, float animDelta)
-{
-       return me.math(tickTime, animDuration, animStart, animDelta);
-}
-
-void Easing_setMath(entity me, float(float, float, float, float) func)
-{
-       me.math = func;
-}
-
-float easingLinear(float tickTime, float animDuration, float animStart, float animDelta)
-{
-       return (animDelta * (tickTime / animDuration)) + animStart;
-}
-
-float easingQuadIn(float tickTime, float animDuration, float animStart, float animDelta)
-{
-       float frac = tickTime / animDuration;
-       return (animDelta * frac * frac) + animStart;
-}
-
-float easingQuadOut(float tickTime, float animDuration, float animStart, float animDelta)
-{
-       float frac = tickTime / animDuration;
-       return (-animDelta * frac * (frac - 2)) + animStart;
-}
-
-float easingQuadInOut(float tickTime, float animDuration, float animStart, float animDelta)
-{
-       if (tickTime < (animDuration / 2))
-       {
-               return easingQuadIn(tickTime, (animDuration / 2), animStart, (animDelta / 2));
-       }
-       else
-       {
-               return easingQuadOut((tickTime - (animDuration / 2)), (animDuration / 2), (animStart + (animDelta / 2)), (animDelta / 2));
-       }
-}
-
-#endif
diff --git a/qcsrc/menu/anim/easing.qc b/qcsrc/menu/anim/easing.qc
new file mode 100644 (file)
index 0000000..94ea9cf
--- /dev/null
@@ -0,0 +1,72 @@
+#ifdef INTERFACE
+CLASS(Easing) EXTENDS(Animation)
+       METHOD(Easing, calcValue, float(entity, float, float, float, float))
+       METHOD(Easing, setMath, void(entity, float(float, float, float, float)))
+       ATTRIB(Easing, math, float(float, float, float, float), easingLinear)
+ENDCLASS(Easing)
+entity makeHostedEasing(entity, void(entity, float), float(float, float, float, float), float, float, float);
+entity makeEasing(entity, void(entity, float), float(float, float, float, float), float, float, float, float);
+float easingLinear(float, float, float, float);
+float easingQuadIn(float, float, float, float);
+float easingQuadOut(float, float, float, float);
+float easingQuadInOut(float, float, float, float);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeHostedEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animDuration, float animStartValue, float animEnd)
+{
+       entity me;
+       me = makeEasing(obj, objSetter, func, time, animDuration, animStartValue, animEnd);
+       anim.addAnim(anim, me);
+       return me;
+}
+
+entity makeEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animStartTime, float animDuration, float animStartValue, float animEnd)
+{
+       entity me;
+       me = spawnEasing();
+       me.configureAnimation(me, obj, objSetter, animStartTime, animDuration, animStartValue, animEnd);
+       me.setMath(me, func);
+       return me;
+}
+
+float Easing_calcValue(entity me, float tickTime, float animDuration, float animStart, float animDelta)
+{
+       return me.math(tickTime, animDuration, animStart, animDelta);
+}
+
+void Easing_setMath(entity me, float(float, float, float, float) func)
+{
+       me.math = func;
+}
+
+float easingLinear(float tickTime, float animDuration, float animStart, float animDelta)
+{
+       return (animDelta * (tickTime / animDuration)) + animStart;
+}
+
+float easingQuadIn(float tickTime, float animDuration, float animStart, float animDelta)
+{
+       float frac = tickTime / animDuration;
+       return (animDelta * frac * frac) + animStart;
+}
+
+float easingQuadOut(float tickTime, float animDuration, float animStart, float animDelta)
+{
+       float frac = tickTime / animDuration;
+       return (-animDelta * frac * (frac - 2)) + animStart;
+}
+
+float easingQuadInOut(float tickTime, float animDuration, float animStart, float animDelta)
+{
+       if (tickTime < (animDuration / 2))
+       {
+               return easingQuadIn(tickTime, (animDuration / 2), animStart, (animDelta / 2));
+       }
+       else
+       {
+               return easingQuadOut((tickTime - (animDuration / 2)), (animDuration / 2), (animStart + (animDelta / 2)), (animDelta / 2));
+       }
+}
+
+#endif
diff --git a/qcsrc/menu/anim/keyframe.c b/qcsrc/menu/anim/keyframe.c
deleted file mode 100644 (file)
index 3bcda94..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifdef INTERFACE
-CLASS(Keyframe) EXTENDS(Animation)
-       METHOD(Keyframe, addEasing, entity(entity, float, float, float(float, float, float, float)))
-       METHOD(Keyframe, addAnim, void(entity, entity))
-       METHOD(Keyframe, calcValue, float(entity, float, float, float, float))
-       ATTRIB(Keyframe, currentChild, entity, NULL)
-       ATTRIB(Keyframe, firstChild, entity, NULL)
-       ATTRIB(Keyframe, lastChild, entity, NULL)
-ENDCLASS(Keyframe)
-entity makeHostedKeyframe(entity, void(entity, float), float, float, float);
-entity makeKeyframe(entity, void(entity, float), float, float, float);
-float getNewChildStart(entity);
-float getNewChildDuration(entity, float);
-float getNewChildValue(entity);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeHostedKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
-{
-       entity me;
-       me = makeKeyframe(obj, objSetter, animDuration, animStart, animEnd);
-       anim.addAnim(anim, me);
-       return me;
-}
-
-entity makeKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
-{
-       entity me;
-       me = spawnKeyframe();
-       me.configureAnimation(me, obj, objSetter, time, animDuration, animStart, animEnd);
-       return me;
-}
-
-entity Keyframe_addEasing(entity me, float animDurationTime, float animEnd, float(float, float, float, float) func)
-{
-       entity other;
-       other = makeEasing(me.object, me.setter, func, getNewChildStart(me), getNewChildDuration(me, animDurationTime), getNewChildValue(me), animEnd);
-       me.addAnim(me, other);
-       return other;
-}
-
-float getNewChildStart(entity me)
-{
-       if (me.lastChild)
-               return (me.lastChild.startTime + me.lastChild.duration);
-       else
-               return 0;
-}
-
-float getNewChildDuration(entity me, float durationTime)
-{
-       float dura, maxDura;
-       maxDura = me.duration;
-       if (me.lastChild) maxDura = maxDura - (me.lastChild.startTime + me.lastChild.duration);
-       dura = durationTime;
-       if (0 >= dura || dura > maxDura) dura = maxDura;
-       return dura;
-}
-
-float getNewChildValue(entity me)
-{
-       if (me.lastChild)
-               return (me.lastChild.startValue + me.lastChild.delta);
-       else
-               return me.startValue;
-}
-
-void Keyframe_addAnim(entity me, entity other)
-{
-       if(other.parent)
-               error("Can't add already added anim!");
-
-       if(other.isFinished(other))
-               error("Can't add finished anim!");
-
-       other.parent = me;
-
-       entity l;
-       l = me.lastChild;
-
-       if(l)
-               l.nextSibling = other;
-       else
-       {
-               me.currentChild = other;
-               me.firstChild = other;
-       }
-
-       other.prevSibling = l;
-       other.nextSibling = NULL;
-       me.lastChild = other;
-}
-
-float Keyframe_calcValue(entity me, float tickTime, float animDuration, float animStartValue, float animDelta)
-{
-       if (me.currentChild)
-               if (me.currentChild.isFinished(me.currentChild))
-                       me.currentChild = me.currentChild.nextSibling;
-
-       if (me.currentChild)
-       {
-               me.currentChild.tick(me.currentChild, tickTime);
-               return me.currentChild.value;
-       }
-
-       return animStartValue + animDelta;
-}
-#endif
diff --git a/qcsrc/menu/anim/keyframe.qc b/qcsrc/menu/anim/keyframe.qc
new file mode 100644 (file)
index 0000000..3bcda94
--- /dev/null
@@ -0,0 +1,108 @@
+#ifdef INTERFACE
+CLASS(Keyframe) EXTENDS(Animation)
+       METHOD(Keyframe, addEasing, entity(entity, float, float, float(float, float, float, float)))
+       METHOD(Keyframe, addAnim, void(entity, entity))
+       METHOD(Keyframe, calcValue, float(entity, float, float, float, float))
+       ATTRIB(Keyframe, currentChild, entity, NULL)
+       ATTRIB(Keyframe, firstChild, entity, NULL)
+       ATTRIB(Keyframe, lastChild, entity, NULL)
+ENDCLASS(Keyframe)
+entity makeHostedKeyframe(entity, void(entity, float), float, float, float);
+entity makeKeyframe(entity, void(entity, float), float, float, float);
+float getNewChildStart(entity);
+float getNewChildDuration(entity, float);
+float getNewChildValue(entity);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeHostedKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
+{
+       entity me;
+       me = makeKeyframe(obj, objSetter, animDuration, animStart, animEnd);
+       anim.addAnim(anim, me);
+       return me;
+}
+
+entity makeKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
+{
+       entity me;
+       me = spawnKeyframe();
+       me.configureAnimation(me, obj, objSetter, time, animDuration, animStart, animEnd);
+       return me;
+}
+
+entity Keyframe_addEasing(entity me, float animDurationTime, float animEnd, float(float, float, float, float) func)
+{
+       entity other;
+       other = makeEasing(me.object, me.setter, func, getNewChildStart(me), getNewChildDuration(me, animDurationTime), getNewChildValue(me), animEnd);
+       me.addAnim(me, other);
+       return other;
+}
+
+float getNewChildStart(entity me)
+{
+       if (me.lastChild)
+               return (me.lastChild.startTime + me.lastChild.duration);
+       else
+               return 0;
+}
+
+float getNewChildDuration(entity me, float durationTime)
+{
+       float dura, maxDura;
+       maxDura = me.duration;
+       if (me.lastChild) maxDura = maxDura - (me.lastChild.startTime + me.lastChild.duration);
+       dura = durationTime;
+       if (0 >= dura || dura > maxDura) dura = maxDura;
+       return dura;
+}
+
+float getNewChildValue(entity me)
+{
+       if (me.lastChild)
+               return (me.lastChild.startValue + me.lastChild.delta);
+       else
+               return me.startValue;
+}
+
+void Keyframe_addAnim(entity me, entity other)
+{
+       if(other.parent)
+               error("Can't add already added anim!");
+
+       if(other.isFinished(other))
+               error("Can't add finished anim!");
+
+       other.parent = me;
+
+       entity l;
+       l = me.lastChild;
+
+       if(l)
+               l.nextSibling = other;
+       else
+       {
+               me.currentChild = other;
+               me.firstChild = other;
+       }
+
+       other.prevSibling = l;
+       other.nextSibling = NULL;
+       me.lastChild = other;
+}
+
+float Keyframe_calcValue(entity me, float tickTime, float animDuration, float animStartValue, float animDelta)
+{
+       if (me.currentChild)
+               if (me.currentChild.isFinished(me.currentChild))
+                       me.currentChild = me.currentChild.nextSibling;
+
+       if (me.currentChild)
+       {
+               me.currentChild.tick(me.currentChild, tickTime);
+               return me.currentChild.value;
+       }
+
+       return animStartValue + animDelta;
+}
+#endif
diff --git a/qcsrc/menu/classes.c b/qcsrc/menu/classes.c
deleted file mode 100644 (file)
index 9f01ee3..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-#include "anim/animhost.c"
-#include "anim/animation.c"
-#include "anim/easing.c"
-#include "anim/keyframe.c"
-#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 "xonotic/dialog.c"
-#include "xonotic/tab.c"
-#include "xonotic/mainwindow.c"
-#include "xonotic/button.c"
-#include "xonotic/bigbutton.c"
-#include "xonotic/commandbutton.c"
-#include "xonotic/bigcommandbutton.c"
-#include "xonotic/textlabel.c"
-#include "xonotic/dialog_firstrun.c"
-#include "xonotic/dialog_teamselect.c"
-#include "xonotic/dialog_sandboxtools.c"
-#include "xonotic/dialog_monstertools.c"
-#include "xonotic/dialog_settings.c"
-#include "xonotic/dialog_settings_video.c"
-#include "xonotic/dialog_settings_effects.c"
-#include "xonotic/dialog_settings_audio.c"
-#include "xonotic/dialog_settings_game.c"
-#include "xonotic/dialog_settings_user.c"
-#include "xonotic/dialog_settings_user_languagewarning.c"
-#include "xonotic/dialog_settings_misc.c"
-#include "xonotic/dialog_multiplayer.c"
-#include "xonotic/dialog_multiplayer_profile.c"
-#include "xonotic/tabcontroller.c"
-#include "xonotic/slider.c"
-#include "xonotic/slider_resolution.c"
-#include "xonotic/checkbox.c"
-#include "xonotic/checkbox_string.c"
-#include "xonotic/weaponarenacheckbox.c"
-#include "xonotic/radiobutton.c"
-#include "xonotic/nexposee.c"
-#include "xonotic/rootdialog.c"
-#include "xonotic/textslider.c"
-#include "xonotic/colorbutton.c"
-#include "xonotic/dialog_multiplayer_join.c"
-#include "xonotic/dialog_multiplayer_join_serverinfo.c"
-#include "xonotic/playerlist.c"
-#include "xonotic/listbox.c"
-#include "xonotic/serverlist.c"
-#include "xonotic/inputbox.c"
-#include "xonotic/dialog_quit.c"
-#include "xonotic/dialog_multiplayer_create.c"
-#include "xonotic/dialog_multiplayer_create_mutators.c"
-#include "xonotic/dialog_multiplayer_create_mapinfo.c"
-#include "xonotic/gametypelist.c"
-#include "xonotic/maplist.c"
-#include "xonotic/skinlist.c"
-#include "xonotic/languagelist.c"
-#include "xonotic/image.c"
-#include "xonotic/crosshairbutton.c"
-#include "xonotic/playermodel.c"
-#include "xonotic/checkbox_slider_invalid.c"
-#include "xonotic/charmap.c"
-#include "xonotic/keybinder.c"
-#include "xonotic/dialog_settings_input.c"
-#include "xonotic/dialog_settings_input_userbind.c"
-#include "xonotic/slider_decibels.c"
-#include "xonotic/dialog_singleplayer.c"
-#include "xonotic/campaign.c"
-#include "xonotic/dialog_singleplayer_winner.c"
-#include "xonotic/dialog_credits.c"
-#include "xonotic/credits.c"
-#include "xonotic/dialog_settings_game_crosshair.c"
-#include "xonotic/dialog_settings_game_hud.c"
-#include "xonotic/dialog_settings_game_hudconfirm.c"
-#include "xonotic/dialog_settings_game_model.c"
-#include "xonotic/dialog_settings_game_messages.c"
-#include "xonotic/dialog_settings_game_view.c"
-#include "xonotic/dialog_settings_game_weapons.c"
-#include "xonotic/weaponslist.c"
-#include "xonotic/dialog_multiplayer_media.c"
-#include "xonotic/dialog_multiplayer_media_demo.c"
-#include "xonotic/dialog_multiplayer_media_demo_startconfirm.c"
-#include "xonotic/dialog_multiplayer_media_demo_timeconfirm.c"
-#include "xonotic/demolist.c"
-#include "xonotic/screenshotimage.c"
-#include "xonotic/dialog_multiplayer_media_screenshot.c"
-#include "xonotic/dialog_multiplayer_media_screenshot_viewer.c"
-#include "xonotic/screenshotlist.c"
-#include "xonotic/statslist.c"
-#include "xonotic/dialog_multiplayer_media_musicplayer.c"
-#include "xonotic/soundlist.c"
-#include "xonotic/playlist.c"
-#include "xonotic/colorpicker.c"
-#include "xonotic/colorpicker_string.c"
-#include "xonotic/cvarlist.c"
-#include "xonotic/dialog_settings_misc_cvars.c"
-#include "xonotic/dialog_hudsetup_exit.c"
-#include "xonotic/dialog_hudpanel_notification.c"
-#include "xonotic/dialog_hudpanel_ammo.c"
-#include "xonotic/dialog_hudpanel_healtharmor.c"
-#include "xonotic/dialog_hudpanel_powerups.c"
-#include "xonotic/dialog_hudpanel_racetimer.c"
-#include "xonotic/dialog_hudpanel_pressedkeys.c"
-#include "xonotic/dialog_hudpanel_radar.c"
-#include "xonotic/dialog_hudpanel_score.c"
-#include "xonotic/dialog_hudpanel_timer.c"
-#include "xonotic/dialog_hudpanel_vote.c"
-#include "xonotic/dialog_hudpanel_modicons.c"
-#include "xonotic/dialog_hudpanel_chat.c"
-#include "xonotic/dialog_hudpanel_engineinfo.c"
-#include "xonotic/dialog_hudpanel_infomessages.c"
-#include "xonotic/dialog_hudpanel_weapons.c"
-#include "xonotic/dialog_hudpanel_physics.c"
-#include "xonotic/dialog_hudpanel_centerprint.c"
-#include "xonotic/dialog_hudpanel_buffs.c"
-#include "xonotic/slider_picmip.c"
-#include "xonotic/slider_particles.c"
-#include "xonotic/slider_sbfadetime.c"
-#include "xonotic/dialog_settings_misc_reset.c"
diff --git a/qcsrc/menu/classes.qc b/qcsrc/menu/classes.qc
new file mode 100644 (file)
index 0000000..9b4bb4d
--- /dev/null
@@ -0,0 +1,130 @@
+#include "anim/animhost.qc"
+#include "anim/animation.qc"
+#include "anim/easing.qc"
+#include "anim/keyframe.qc"
+#include "item.qc"
+#include "item/container.qc"
+#include "item/inputcontainer.qc"
+#include "item/nexposee.qc"
+#include "item/modalcontroller.qc"
+#include "item/image.qc"
+#include "item/label.qc"
+#include "item/button.qc"
+#include "item/checkbox.qc"
+#include "item/radiobutton.qc"
+#include "item/borderimage.qc"
+#include "item/slider.qc"
+#include "item/dialog.qc"
+#include "item/tab.qc"
+#include "item/textslider.qc"
+#include "item/listbox.qc"
+#include "item/inputbox.qc"
+#include "xonotic/dialog.qc"
+#include "xonotic/tab.qc"
+#include "xonotic/mainwindow.qc"
+#include "xonotic/button.qc"
+#include "xonotic/bigbutton.qc"
+#include "xonotic/commandbutton.qc"
+#include "xonotic/bigcommandbutton.qc"
+#include "xonotic/textlabel.qc"
+#include "xonotic/dialog_firstrun.qc"
+#include "xonotic/dialog_teamselect.qc"
+#include "xonotic/dialog_sandboxtools.qc"
+#include "xonotic/dialog_monstertools.qc"
+#include "xonotic/dialog_settings.qc"
+#include "xonotic/dialog_settings_video.qc"
+#include "xonotic/dialog_settings_effects.qc"
+#include "xonotic/dialog_settings_audio.qc"
+#include "xonotic/dialog_settings_game.qc"
+#include "xonotic/dialog_settings_user.qc"
+#include "xonotic/dialog_settings_user_languagewarning.qc"
+#include "xonotic/dialog_settings_misc.qc"
+#include "xonotic/dialog_multiplayer.qc"
+#include "xonotic/dialog_multiplayer_profile.qc"
+#include "xonotic/tabcontroller.qc"
+#include "xonotic/slider.qc"
+#include "xonotic/slider_resolution.qc"
+#include "xonotic/checkbox.qc"
+#include "xonotic/checkbox_string.qc"
+#include "xonotic/weaponarenacheckbox.qc"
+#include "xonotic/radiobutton.qc"
+#include "xonotic/nexposee.qc"
+#include "xonotic/rootdialog.qc"
+#include "xonotic/textslider.qc"
+#include "xonotic/colorbutton.qc"
+#include "xonotic/dialog_multiplayer_join.qc"
+#include "xonotic/dialog_multiplayer_join_serverinfo.qc"
+#include "xonotic/playerlist.qc"
+#include "xonotic/listbox.qc"
+#include "xonotic/serverlist.qc"
+#include "xonotic/inputbox.qc"
+#include "xonotic/dialog_quit.qc"
+#include "xonotic/dialog_multiplayer_create.qc"
+#include "xonotic/dialog_multiplayer_create_mutators.qc"
+#include "xonotic/dialog_multiplayer_create_mapinfo.qc"
+#include "xonotic/gametypelist.qc"
+#include "xonotic/maplist.qc"
+#include "xonotic/skinlist.qc"
+#include "xonotic/languagelist.qc"
+#include "xonotic/image.qc"
+#include "xonotic/crosshairbutton.qc"
+#include "xonotic/playermodel.qc"
+#include "xonotic/checkbox_slider_invalid.qc"
+#include "xonotic/charmap.qc"
+#include "xonotic/keybinder.qc"
+#include "xonotic/dialog_settings_input.qc"
+#include "xonotic/dialog_settings_input_userbind.qc"
+#include "xonotic/slider_decibels.qc"
+#include "xonotic/dialog_singleplayer.qc"
+#include "xonotic/campaign.qc"
+#include "xonotic/dialog_singleplayer_winner.qc"
+#include "xonotic/dialog_credits.qc"
+#include "xonotic/credits.qc"
+#include "xonotic/dialog_settings_game_crosshair.qc"
+#include "xonotic/dialog_settings_game_hud.qc"
+#include "xonotic/dialog_settings_game_hudconfirm.qc"
+#include "xonotic/dialog_settings_game_model.qc"
+#include "xonotic/dialog_settings_game_messages.qc"
+#include "xonotic/dialog_settings_game_view.qc"
+#include "xonotic/dialog_settings_game_weapons.qc"
+#include "xonotic/weaponslist.qc"
+#include "xonotic/dialog_multiplayer_media.qc"
+#include "xonotic/dialog_multiplayer_media_demo.qc"
+#include "xonotic/dialog_multiplayer_media_demo_startconfirm.qc"
+#include "xonotic/dialog_multiplayer_media_demo_timeconfirm.qc"
+#include "xonotic/demolist.qc"
+#include "xonotic/screenshotimage.qc"
+#include "xonotic/dialog_multiplayer_media_screenshot.qc"
+#include "xonotic/dialog_multiplayer_media_screenshot_viewer.qc"
+#include "xonotic/screenshotlist.qc"
+#include "xonotic/statslist.qc"
+#include "xonotic/dialog_multiplayer_media_musicplayer.qc"
+#include "xonotic/soundlist.qc"
+#include "xonotic/playlist.qc"
+#include "xonotic/colorpicker.qc"
+#include "xonotic/colorpicker_string.qc"
+#include "xonotic/cvarlist.qc"
+#include "xonotic/dialog_settings_misc_cvars.qc"
+#include "xonotic/dialog_hudsetup_exit.qc"
+#include "xonotic/dialog_hudpanel_notification.qc"
+#include "xonotic/dialog_hudpanel_ammo.qc"
+#include "xonotic/dialog_hudpanel_healtharmor.qc"
+#include "xonotic/dialog_hudpanel_powerups.qc"
+#include "xonotic/dialog_hudpanel_racetimer.qc"
+#include "xonotic/dialog_hudpanel_pressedkeys.qc"
+#include "xonotic/dialog_hudpanel_radar.qc"
+#include "xonotic/dialog_hudpanel_score.qc"
+#include "xonotic/dialog_hudpanel_timer.qc"
+#include "xonotic/dialog_hudpanel_vote.qc"
+#include "xonotic/dialog_hudpanel_modicons.qc"
+#include "xonotic/dialog_hudpanel_chat.qc"
+#include "xonotic/dialog_hudpanel_engineinfo.qc"
+#include "xonotic/dialog_hudpanel_infomessages.qc"
+#include "xonotic/dialog_hudpanel_weapons.qc"
+#include "xonotic/dialog_hudpanel_physics.qc"
+#include "xonotic/dialog_hudpanel_centerprint.qc"
+#include "xonotic/dialog_hudpanel_buffs.qc"
+#include "xonotic/slider_picmip.qc"
+#include "xonotic/slider_particles.qc"
+#include "xonotic/slider_sbfadetime.qc"
+#include "xonotic/dialog_settings_misc_reset.qc"
diff --git a/qcsrc/menu/item.c b/qcsrc/menu/item.c
deleted file mode 100644 (file)
index d055b1a..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-#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))
-       METHOD(Item, destroy, void(entity))
-       ATTRIB(Item, focused, float, 0)
-       ATTRIB(Item, focusable, float, 0)
-       ATTRIB(Item, parent, entity, NULL)
-       ATTRIB(Item, preferredFocusPriority, float, 0)
-       ATTRIB(Item, origin, vector, '0 0 0')
-       ATTRIB(Item, size, vector, '0 0 0')
-       ATTRIB(Item, tooltip, string, string_null)
-ENDCLASS(Item)
-#endif
-
-#ifdef IMPLEMENTATION
-void Item_destroy(entity me)
-{
-       // free memory associated with me
-}
-
-void Item_relinquishFocus(entity me)
-{
-       if(me.parent)
-               if(me.parent.instanceOfContainer)
-                       me.parent.setFocus(me.parent, NULL);
-}
-
-void Item_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.origin = absOrigin;
-       me.size = absSize;
-}
-
-float autocvar_menu_showboxes;
-void Item_draw(entity me)
-{
-       if(autocvar_menu_showboxes)
-       {
-               vector rgb = '1 0 1';
-               float a = fabs(autocvar_menu_showboxes);
-
-               // don't draw containers and border images
-               if(me.instanceOfContainer || me.instanceOfBorderImage)
-               {
-                       rgb = '0 0 0';
-                       a = 0;
-               }
-
-#if 0
-               // hack to detect multi drawing
-               float r = random() * 3;
-               if(r >= 2)
-                       rgb = '1 0 0';
-               else if(r >= 1)
-                       rgb = '0 1 0';
-               else
-                       rgb = '0 0 1';
-#endif
-               if(autocvar_menu_showboxes < 0)
-               {
-                       draw_Fill('0 0 0', '0.5 0.5 0', rgb, a);
-                       draw_Fill('0.5 0.5 0', '0.5 0.5 0', rgb, a);
-               }
-               if(autocvar_menu_showboxes > 0)
-               {
-                       draw_Fill('0 0 0', '1 1 0', rgb, a);
-               }
-       }
-}
-
-void Item_showNotify(entity me)
-{
-}
-
-void Item_hideNotify(entity me)
-{
-}
-
-float Item_keyDown(entity me, float scan, float ascii, float shift)
-{
-       return 0; // unhandled
-}
-
-float Item_keyUp(entity me, float scan, float ascii, float shift)
-{
-       return 0; // unhandled
-}
-
-float Item_mouseMove(entity me, vector pos)
-{
-       return 0; // unhandled
-}
-
-float Item_mousePress(entity me, vector pos)
-{
-       return 0; // unhandled
-}
-
-float Item_mouseDrag(entity me, vector pos)
-{
-       return 0; // unhandled
-}
-
-float Item_mouseRelease(entity me, vector pos)
-{
-       return 0; // unhandled
-}
-
-void Item_focusEnter(entity me)
-{
-}
-
-void Item_focusLeave(entity me)
-{
-}
-
-string Item_toString(entity me)
-{
-       return string_null;
-}
-#endif
diff --git a/qcsrc/menu/item.qc b/qcsrc/menu/item.qc
new file mode 100644 (file)
index 0000000..d055b1a
--- /dev/null
@@ -0,0 +1,134 @@
+#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))
+       METHOD(Item, destroy, void(entity))
+       ATTRIB(Item, focused, float, 0)
+       ATTRIB(Item, focusable, float, 0)
+       ATTRIB(Item, parent, entity, NULL)
+       ATTRIB(Item, preferredFocusPriority, float, 0)
+       ATTRIB(Item, origin, vector, '0 0 0')
+       ATTRIB(Item, size, vector, '0 0 0')
+       ATTRIB(Item, tooltip, string, string_null)
+ENDCLASS(Item)
+#endif
+
+#ifdef IMPLEMENTATION
+void Item_destroy(entity me)
+{
+       // free memory associated with me
+}
+
+void Item_relinquishFocus(entity me)
+{
+       if(me.parent)
+               if(me.parent.instanceOfContainer)
+                       me.parent.setFocus(me.parent, NULL);
+}
+
+void Item_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.origin = absOrigin;
+       me.size = absSize;
+}
+
+float autocvar_menu_showboxes;
+void Item_draw(entity me)
+{
+       if(autocvar_menu_showboxes)
+       {
+               vector rgb = '1 0 1';
+               float a = fabs(autocvar_menu_showboxes);
+
+               // don't draw containers and border images
+               if(me.instanceOfContainer || me.instanceOfBorderImage)
+               {
+                       rgb = '0 0 0';
+                       a = 0;
+               }
+
+#if 0
+               // hack to detect multi drawing
+               float r = random() * 3;
+               if(r >= 2)
+                       rgb = '1 0 0';
+               else if(r >= 1)
+                       rgb = '0 1 0';
+               else
+                       rgb = '0 0 1';
+#endif
+               if(autocvar_menu_showboxes < 0)
+               {
+                       draw_Fill('0 0 0', '0.5 0.5 0', rgb, a);
+                       draw_Fill('0.5 0.5 0', '0.5 0.5 0', rgb, a);
+               }
+               if(autocvar_menu_showboxes > 0)
+               {
+                       draw_Fill('0 0 0', '1 1 0', rgb, a);
+               }
+       }
+}
+
+void Item_showNotify(entity me)
+{
+}
+
+void Item_hideNotify(entity me)
+{
+}
+
+float Item_keyDown(entity me, float scan, float ascii, float shift)
+{
+       return 0; // unhandled
+}
+
+float Item_keyUp(entity me, float scan, float ascii, float shift)
+{
+       return 0; // unhandled
+}
+
+float Item_mouseMove(entity me, vector pos)
+{
+       return 0; // unhandled
+}
+
+float Item_mousePress(entity me, vector pos)
+{
+       return 0; // unhandled
+}
+
+float Item_mouseDrag(entity me, vector pos)
+{
+       return 0; // unhandled
+}
+
+float Item_mouseRelease(entity me, vector pos)
+{
+       return 0; // unhandled
+}
+
+void Item_focusEnter(entity me)
+{
+}
+
+void Item_focusLeave(entity me)
+{
+}
+
+string Item_toString(entity me)
+{
+       return string_null;
+}
+#endif
diff --git a/qcsrc/menu/item/borderimage.c b/qcsrc/menu/item/borderimage.c
deleted file mode 100644 (file)
index 3a345a4..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-#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, recalcPositionWithText, void(entity, string))
-       ATTRIB(BorderImage, isBold, float, 1)
-       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)
-       ATTRIB(BorderImage, overrideRealOrigin, vector, '0 1 0')
-       ATTRIB(BorderImage, saveRelOrigin, vector, '0 0 0')
-       ATTRIB(BorderImage, saveRelSize, vector, '0 0 0')
-ENDCLASS(BorderImage)
-#endif
-
-#ifdef IMPLEMENTATION
-void BorderImage_recalcPositionWithText(entity me, string t)
-{
-       if(me.isNexposeeTitleBar)
-       {
-               vector scrs;
-               scrs = eX * conwidth + eY * conheight;
-               me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_smallOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_smallSize, scrs));
-               SUPER(BorderImage).recalcPositionWithText(me, t);
-               me.realOrigin_y = me.realFontSize_y * me.zoomedOutTitleBarPosition;
-               me.realOrigin_Nexposeed = me.realOrigin;
-               me.realFontSize_Nexposeed = me.realFontSize;
-               me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_initialOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_initialSize, scrs));
-       }
-       SUPER(BorderImage).recalcPositionWithText(me, t);
-}
-void BorderImage_resizeNotify(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;
-       me.saveRelOrigin = relOrigin;
-       me.saveRelSize = relSize;
-       SUPER(BorderImage).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       me.borderVec_x = me.borderHeight / absSize_x;
-       me.borderVec_y = me.borderHeight / absSize_y;
-       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 BorderImage_configureBorderImage(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 BorderImage_draw(entity me)
-{
-       if(me.src)
-               draw_BorderPicture('0 0 0', me.src, '1 1 0', me.color, 1, me.borderVec);
-
-       if(me.fontSize > 0)
-       {
-               if(me.recalcPos)
-                       me.recalcPositionWithText(me, me.text);
-
-               if(me.isNexposeeTitleBar)
-               {
-                       vector ro, rf, df;
-
-                       // me.parent.Nexposee_animationFactor 0 (small) or 1 (full)
-                       // default values are for 1
-                       ro = me.realOrigin;
-                       rf = me.realFontSize;
-                       df = draw_fontscale;
-                       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);
-                       draw_fontscale = globalToBoxSize(boxToGlobalSize(df, me.realFontSize), rf);
-
-                       SUPER(BorderImage).draw(me);
-
-                       // me.Nexposee_animationState 0 (small) or 1 (full)
-                       // default values are for 1
-                       me.realOrigin = ro;
-                       me.realFontSize = rf;
-                       draw_fontscale = df;
-               }
-               else
-                       SUPER(BorderImage).draw(me);
-       }
-       else
-       {
-               SUPER(BorderImage).draw(me);
-       }
-}
-#endif
diff --git a/qcsrc/menu/item/borderimage.qc b/qcsrc/menu/item/borderimage.qc
new file mode 100644 (file)
index 0000000..3a345a4
--- /dev/null
@@ -0,0 +1,110 @@
+#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, recalcPositionWithText, void(entity, string))
+       ATTRIB(BorderImage, isBold, float, 1)
+       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)
+       ATTRIB(BorderImage, overrideRealOrigin, vector, '0 1 0')
+       ATTRIB(BorderImage, saveRelOrigin, vector, '0 0 0')
+       ATTRIB(BorderImage, saveRelSize, vector, '0 0 0')
+ENDCLASS(BorderImage)
+#endif
+
+#ifdef IMPLEMENTATION
+void BorderImage_recalcPositionWithText(entity me, string t)
+{
+       if(me.isNexposeeTitleBar)
+       {
+               vector scrs;
+               scrs = eX * conwidth + eY * conheight;
+               me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_smallOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_smallSize, scrs));
+               SUPER(BorderImage).recalcPositionWithText(me, t);
+               me.realOrigin_y = me.realFontSize_y * me.zoomedOutTitleBarPosition;
+               me.realOrigin_Nexposeed = me.realOrigin;
+               me.realFontSize_Nexposeed = me.realFontSize;
+               me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_initialOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_initialSize, scrs));
+       }
+       SUPER(BorderImage).recalcPositionWithText(me, t);
+}
+void BorderImage_resizeNotify(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;
+       me.saveRelOrigin = relOrigin;
+       me.saveRelSize = relSize;
+       SUPER(BorderImage).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+       me.borderVec_x = me.borderHeight / absSize_x;
+       me.borderVec_y = me.borderHeight / absSize_y;
+       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 BorderImage_configureBorderImage(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 BorderImage_draw(entity me)
+{
+       if(me.src)
+               draw_BorderPicture('0 0 0', me.src, '1 1 0', me.color, 1, me.borderVec);
+
+       if(me.fontSize > 0)
+       {
+               if(me.recalcPos)
+                       me.recalcPositionWithText(me, me.text);
+
+               if(me.isNexposeeTitleBar)
+               {
+                       vector ro, rf, df;
+
+                       // me.parent.Nexposee_animationFactor 0 (small) or 1 (full)
+                       // default values are for 1
+                       ro = me.realOrigin;
+                       rf = me.realFontSize;
+                       df = draw_fontscale;
+                       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);
+                       draw_fontscale = globalToBoxSize(boxToGlobalSize(df, me.realFontSize), rf);
+
+                       SUPER(BorderImage).draw(me);
+
+                       // me.Nexposee_animationState 0 (small) or 1 (full)
+                       // default values are for 1
+                       me.realOrigin = ro;
+                       me.realFontSize = rf;
+                       draw_fontscale = df;
+               }
+               else
+                       SUPER(BorderImage).draw(me);
+       }
+       else
+       {
+               SUPER(BorderImage).draw(me);
+       }
+}
+#endif
diff --git a/qcsrc/menu/item/button.c b/qcsrc/menu/item/button.c
deleted file mode 100644 (file)
index 8bbdfa7..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-#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))
-       METHOD(Button, focusEnter, void(entity))
-       ATTRIB(Button, onClick, void(entity, entity), func_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 Button_resizeNotify(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);
-       SUPER(Button).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-}
-void Button_configureButton(entity me, string txt, float sz, string gfx)
-{
-       SUPER(Button).configureLabel(me, txt, sz, me.srcMulti ? 0.5 : 0);
-       me.src = gfx;
-}
-float Button_keyDown(entity me, float key, float ascii, float shift)
-{
-       if(key == K_ENTER || key == K_SPACE || key == K_KP_ENTER)
-       {
-               me.clickTime = 0.1; // delayed for effect
-               return 1;
-       }
-       return 0;
-}
-float Button_mouseDrag(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 Button_mousePress(entity me, vector pos)
-{
-       me.mouseDrag(me, pos); // verify coordinates
-       return 1;
-}
-float Button_mouseRelease(entity me, vector pos)
-{
-       me.mouseDrag(me, pos); // verify coordinates
-       if(me.pressed)
-       {
-               if (!me.disabled)
-               {
-                       if(cvar("menu_sounds"))
-                               localsound("sound/misc/menu2.wav");
-                       if(me.onClick)
-                               me.onClick(me, me.onClickEntity);
-               }
-               me.pressed = 0;
-       }
-       return 1;
-}
-void Button_showNotify(entity me)
-{
-       me.focusable = !me.disabled;
-}
-void Button_focusEnter(entity me)
-{
-       if(cvar("menu_sounds") > 1)
-               localsound("sound/misc/menu1.wav");
-       SUPER(Button).focusEnter(me);
-}
-void Button_draw(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;
-
-       if(me.clickTime > 0 && me.clickTime <= frametime)
-       {
-               // keyboard click timer expired? Fire the event then.
-               if (!me.disabled)
-                       if(me.onClick)
-                               me.onClick(me, me.onClickEntity);
-       }
-       me.clickTime -= frametime;
-
-       SUPER(Button).draw(me);
-}
-#endif
diff --git a/qcsrc/menu/item/button.qc b/qcsrc/menu/item/button.qc
new file mode 100644 (file)
index 0000000..8bbdfa7
--- /dev/null
@@ -0,0 +1,173 @@
+#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))
+       METHOD(Button, focusEnter, void(entity))
+       ATTRIB(Button, onClick, void(entity, entity), func_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 Button_resizeNotify(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);
+       SUPER(Button).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+}
+void Button_configureButton(entity me, string txt, float sz, string gfx)
+{
+       SUPER(Button).configureLabel(me, txt, sz, me.srcMulti ? 0.5 : 0);
+       me.src = gfx;
+}
+float Button_keyDown(entity me, float key, float ascii, float shift)
+{
+       if(key == K_ENTER || key == K_SPACE || key == K_KP_ENTER)
+       {
+               me.clickTime = 0.1; // delayed for effect
+               return 1;
+       }
+       return 0;
+}
+float Button_mouseDrag(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 Button_mousePress(entity me, vector pos)
+{
+       me.mouseDrag(me, pos); // verify coordinates
+       return 1;
+}
+float Button_mouseRelease(entity me, vector pos)
+{
+       me.mouseDrag(me, pos); // verify coordinates
+       if(me.pressed)
+       {
+               if (!me.disabled)
+               {
+                       if(cvar("menu_sounds"))
+                               localsound("sound/misc/menu2.wav");
+                       if(me.onClick)
+                               me.onClick(me, me.onClickEntity);
+               }
+               me.pressed = 0;
+       }
+       return 1;
+}
+void Button_showNotify(entity me)
+{
+       me.focusable = !me.disabled;
+}
+void Button_focusEnter(entity me)
+{
+       if(cvar("menu_sounds") > 1)
+               localsound("sound/misc/menu1.wav");
+       SUPER(Button).focusEnter(me);
+}
+void Button_draw(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;
+
+       if(me.clickTime > 0 && me.clickTime <= frametime)
+       {
+               // keyboard click timer expired? Fire the event then.
+               if (!me.disabled)
+                       if(me.onClick)
+                               me.onClick(me, me.onClickEntity);
+       }
+       me.clickTime -= frametime;
+
+       SUPER(Button).draw(me);
+}
+#endif
diff --git a/qcsrc/menu/item/checkbox.c b/qcsrc/menu/item/checkbox.c
deleted file mode 100644 (file)
index 94f67ba..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#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 CheckBox_setChecked(entity me, float val)
-{
-       me.checked = val;
-}
-void CheckBox_Click(entity me, entity other)
-{
-       me.setChecked(me, !me.checked);
-}
-string CheckBox_toString(entity me)
-{
-       return strcat(SUPER(CheckBox).toString(me), ", ", me.checked ? "checked" : "unchecked");
-}
-void CheckBox_configureCheckBox(entity me, string txt, float sz, string gfx)
-{
-       me.configureButton(me, txt, sz, gfx);
-       me.align = 0;
-}
-void CheckBox_draw(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");
-       me.pressed = s;
-       SUPER(CheckBox).draw(me);
-}
-#endif
diff --git a/qcsrc/menu/item/checkbox.qc b/qcsrc/menu/item/checkbox.qc
new file mode 100644 (file)
index 0000000..94f67ba
--- /dev/null
@@ -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 CheckBox_setChecked(entity me, float val)
+{
+       me.checked = val;
+}
+void CheckBox_Click(entity me, entity other)
+{
+       me.setChecked(me, !me.checked);
+}
+string CheckBox_toString(entity me)
+{
+       return strcat(SUPER(CheckBox).toString(me), ", ", me.checked ? "checked" : "unchecked");
+}
+void CheckBox_configureCheckBox(entity me, string txt, float sz, string gfx)
+{
+       me.configureButton(me, txt, sz, gfx);
+       me.align = 0;
+}
+void CheckBox_draw(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");
+       me.pressed = s;
+       SUPER(CheckBox).draw(me);
+}
+#endif
diff --git a/qcsrc/menu/item/container.c b/qcsrc/menu/item/container.c
deleted file mode 100644 (file)
index 8bc925f..0000000
+++ /dev/null
@@ -1,453 +0,0 @@
-#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, .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, saveFocus, void(entity))
-       METHOD(Container, setAlphaOf, void(entity, entity, float))
-       METHOD(Container, itemFromPoint, entity(entity, vector))
-       METHOD(Container, showNotify, void(entity))
-       METHOD(Container, hideNotify, void(entity))
-       METHOD(Container, preferredFocusedGrandChild, entity(entity))
-       ATTRIB(Container, focusable, float, 0)
-       ATTRIB(Container, firstChild, entity, NULL)
-       ATTRIB(Container, lastChild, entity, NULL)
-       ATTRIB(Container, focusedChild, entity, NULL)
-       ATTRIB(Container, savedFocus, entity, NULL)
-       ATTRIB(Container, shown, float, 0)
-
-       METHOD(Container, enterSubitem, void(entity, entity))
-       METHOD(Container, enterLieSubitem, void(entity, vector, vector, vector, float))
-       METHOD(Container, leaveSubitem, void(entity))
-ENDCLASS(Container)
-.entity nextSibling;
-.entity prevSibling;
-.float resized;
-.vector Container_origin;
-.vector Container_size;
-.vector Container_fontscale;
-.float Container_alpha;
-.vector Container_save_shift;
-.vector Container_save_scale;
-.vector Container_save_fontscale;
-.float Container_save_alpha;
-#endif
-
-#ifdef IMPLEMENTATION
-void Container_enterSubitem(entity me, entity sub)
-{
-       me.enterLieSubitem(me, sub.Container_origin, sub.Container_size, sub.Container_fontscale, sub.Container_alpha);
-}
-
-void Container_enterLieSubitem(entity me, vector o, vector s, vector f, float a)
-{
-       me.Container_save_shift = draw_shift;
-       me.Container_save_scale = draw_scale;
-       me.Container_save_alpha = draw_alpha;
-       me.Container_save_fontscale = draw_fontscale;
-
-       draw_shift = boxToGlobal(o, draw_shift, draw_scale);
-       draw_scale = boxToGlobalSize(s, draw_scale);
-       if(f != '0 0 0')
-               draw_fontscale = boxToGlobalSize(f, draw_fontscale);
-       draw_alpha *= a;
-}
-
-void Container_leaveSubitem(entity me)
-{
-       draw_shift = me.Container_save_shift;
-       draw_scale = me.Container_save_scale;
-       draw_alpha = me.Container_save_alpha;
-       draw_fontscale = me.Container_save_fontscale;
-}
-
-void Container_showNotify(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 Container_hideNotify(entity me)
-{
-       entity e;
-       if (!me.shown)
-               return;
-       me.shown = 0;
-       for(e = me.firstChild; e; e = e.nextSibling)
-               if(e.Container_alpha > 0)
-                       e.hideNotify(e);
-}
-
-void Container_setAlphaOf(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 Container_resizeNotifyLie(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize, .vector originField, .vector sizeField, .vector fontScaleField)
-{
-       entity e;
-       vector o, s;
-       float d;
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               o = e.originField;
-               s = e.sizeField;
-               me.enterLieSubitem(me, o, s, e.fontScaleField, e.Container_alpha);
-               e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
-               me.leaveSubitem(me);
-       }
-       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;
-                               me.enterLieSubitem(me, o, s, e.fontScaleField, e.Container_alpha);
-                               e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
-                               me.leaveSubitem(me);
-                       }
-       }
-       while(d);
-       SUPER(Container).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-}
-
-void Container_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Container_origin, Container_size, Container_fontscale);
-}
-
-entity Container_itemFromPoint(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 Container_draw(entity me)
-{
-       entity e;
-
-       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;
-               me.enterSubitem(me, e);
-               e.draw(e);
-               me.leaveSubitem(me);
-       }
-
-       SUPER(Container).draw(me);
-}
-
-void Container_focusLeave(entity me)
-{
-       me.setFocus(me, NULL);
-}
-
-float Container_keyUp(entity me, float scan, float ascii, float shift)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
-       {
-               me.enterSubitem(me, f);
-               r = f.keyUp(f, scan, ascii, shift);
-               me.leaveSubitem(me);
-               return r;
-       }
-       return 0;
-}
-
-float Container_keyDown(entity me, float scan, float ascii, float shift)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
-       {
-               me.enterSubitem(me, f);
-               r = f.keyDown(f, scan, ascii, shift);
-               me.leaveSubitem(me);
-               return r;
-       }
-       return 0;
-}
-
-float Container_mouseMove(entity me, vector pos)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
-       {
-               me.enterSubitem(me, f);
-               r = f.mouseMove(f, globalToBox(pos, f.Container_origin, f.Container_size));
-               me.leaveSubitem(me);
-               return r;
-       }
-       return 0;
-}
-float Container_mousePress(entity me, vector pos)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
-       {
-               me.enterSubitem(me, f);
-               r = f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
-               me.leaveSubitem(me);
-               return r;
-       }
-       return 0;
-}
-float Container_mouseDrag(entity me, vector pos)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
-       {
-               me.enterSubitem(me, f);
-               r = f.mouseDrag(f, globalToBox(pos, f.Container_origin, f.Container_size));
-               me.leaveSubitem(me);
-               return r;
-       }
-       return 0;
-}
-float Container_mouseRelease(entity me, vector pos)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
-       {
-               me.enterSubitem(me, f);
-               r = f.mouseRelease(f, globalToBox(pos, f.Container_origin, f.Container_size));
-               me.leaveSubitem(me);
-               return r;
-       }
-       return 0;
-}
-
-void Container_addItemCentered(entity me, entity other, vector theSize, float theAlpha)
-{
-       me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha);
-}
-
-void Container_addItem(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 l;
-       l = me.lastChild;
-
-       if(l)
-               l.nextSibling = other;
-       else
-               me.firstChild = other;
-
-       other.prevSibling = l;
-       other.nextSibling = NULL;
-       me.lastChild = other;
-}
-
-void Container_removeItem(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;
-       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 Container_setFocus(entity me, entity other)
-{
-       if(me.focusedChild == other)
-               return;
-
-       if(me.focusedChild)
-       {
-               me.focusedChild.focused = 0;
-               me.focusedChild.focusLeave(me.focusedChild);
-               me.focusedChild = NULL;
-       }
-
-       if(other)
-       {
-               if(!me.focused)
-                       error("Trying to set focus in a non-focused control!");
-
-               if(me.savedFocus)
-               {
-                       me.focusedChild = me.savedFocus;
-                       me.savedFocus = NULL;
-                       me.focusedChild.focused = 1;
-                       me.focusedChild.focusEnter(me.focusedChild);
-
-                       if(me.focusedChild.instanceOfContainer)
-                               me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
-               }
-               else
-               {
-                       me.focusedChild = other;
-                       me.focusedChild.focused = 1;
-                       me.focusedChild.focusEnter(me.focusedChild);
-               }
-       }
-}
-
-void Container_saveFocus(entity me)
-{
-       me.savedFocus = me.focusedChild;
-
-       if(me.focusedChild.instanceOfContainer)
-               me.focusedChild.saveFocus(me.focusedChild);
-}
-
-void Container_moveItemAfter(entity me, entity other, entity dest)
-{
-       // first: remove other from the chain
-       entity n, p;
-
-       if(other.parent != me)
-               error("Can't move in wrong container!");
-
-       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;
-}
-
-entity Container_preferredFocusedGrandChild(entity me)
-{
-       entity e, e2;
-       entity best;
-
-       best = NULL;
-
-       for(e = me.firstChild; e; e = e.nextSibling)
-       {
-               if(e.instanceOfContainer)
-               {
-                       e2 = e.preferredFocusedGrandChild(e);
-                       if(e2)
-                               if(!best || best.preferredFocusPriority < e2.preferredFocusPriority)
-                                       best = e2;
-               }
-               if(e)
-                       if(!best || best.preferredFocusPriority < e.preferredFocusPriority)
-                               best = e;
-       }
-
-       return best;
-}
-#endif
diff --git a/qcsrc/menu/item/container.qc b/qcsrc/menu/item/container.qc
new file mode 100644 (file)
index 0000000..8bc925f
--- /dev/null
@@ -0,0 +1,453 @@
+#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, .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, saveFocus, void(entity))
+       METHOD(Container, setAlphaOf, void(entity, entity, float))
+       METHOD(Container, itemFromPoint, entity(entity, vector))
+       METHOD(Container, showNotify, void(entity))
+       METHOD(Container, hideNotify, void(entity))
+       METHOD(Container, preferredFocusedGrandChild, entity(entity))
+       ATTRIB(Container, focusable, float, 0)
+       ATTRIB(Container, firstChild, entity, NULL)
+       ATTRIB(Container, lastChild, entity, NULL)
+       ATTRIB(Container, focusedChild, entity, NULL)
+       ATTRIB(Container, savedFocus, entity, NULL)
+       ATTRIB(Container, shown, float, 0)
+
+       METHOD(Container, enterSubitem, void(entity, entity))
+       METHOD(Container, enterLieSubitem, void(entity, vector, vector, vector, float))
+       METHOD(Container, leaveSubitem, void(entity))
+ENDCLASS(Container)
+.entity nextSibling;
+.entity prevSibling;
+.float resized;
+.vector Container_origin;
+.vector Container_size;
+.vector Container_fontscale;
+.float Container_alpha;
+.vector Container_save_shift;
+.vector Container_save_scale;
+.vector Container_save_fontscale;
+.float Container_save_alpha;
+#endif
+
+#ifdef IMPLEMENTATION
+void Container_enterSubitem(entity me, entity sub)
+{
+       me.enterLieSubitem(me, sub.Container_origin, sub.Container_size, sub.Container_fontscale, sub.Container_alpha);
+}
+
+void Container_enterLieSubitem(entity me, vector o, vector s, vector f, float a)
+{
+       me.Container_save_shift = draw_shift;
+       me.Container_save_scale = draw_scale;
+       me.Container_save_alpha = draw_alpha;
+       me.Container_save_fontscale = draw_fontscale;
+
+       draw_shift = boxToGlobal(o, draw_shift, draw_scale);
+       draw_scale = boxToGlobalSize(s, draw_scale);
+       if(f != '0 0 0')
+               draw_fontscale = boxToGlobalSize(f, draw_fontscale);
+       draw_alpha *= a;
+}
+
+void Container_leaveSubitem(entity me)
+{
+       draw_shift = me.Container_save_shift;
+       draw_scale = me.Container_save_scale;
+       draw_alpha = me.Container_save_alpha;
+       draw_fontscale = me.Container_save_fontscale;
+}
+
+void Container_showNotify(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 Container_hideNotify(entity me)
+{
+       entity e;
+       if (!me.shown)
+               return;
+       me.shown = 0;
+       for(e = me.firstChild; e; e = e.nextSibling)
+               if(e.Container_alpha > 0)
+                       e.hideNotify(e);
+}
+
+void Container_setAlphaOf(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 Container_resizeNotifyLie(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize, .vector originField, .vector sizeField, .vector fontScaleField)
+{
+       entity e;
+       vector o, s;
+       float d;
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               o = e.originField;
+               s = e.sizeField;
+               me.enterLieSubitem(me, o, s, e.fontScaleField, e.Container_alpha);
+               e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
+               me.leaveSubitem(me);
+       }
+       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;
+                               me.enterLieSubitem(me, o, s, e.fontScaleField, e.Container_alpha);
+                               e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
+                               me.leaveSubitem(me);
+                       }
+       }
+       while(d);
+       SUPER(Container).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+}
+
+void Container_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Container_origin, Container_size, Container_fontscale);
+}
+
+entity Container_itemFromPoint(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 Container_draw(entity me)
+{
+       entity e;
+
+       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;
+               me.enterSubitem(me, e);
+               e.draw(e);
+               me.leaveSubitem(me);
+       }
+
+       SUPER(Container).draw(me);
+}
+
+void Container_focusLeave(entity me)
+{
+       me.setFocus(me, NULL);
+}
+
+float Container_keyUp(entity me, float scan, float ascii, float shift)
+{
+       entity f;
+       float r;
+       f = me.focusedChild;
+       if(f)
+       {
+               me.enterSubitem(me, f);
+               r = f.keyUp(f, scan, ascii, shift);
+               me.leaveSubitem(me);
+               return r;
+       }
+       return 0;
+}
+
+float Container_keyDown(entity me, float scan, float ascii, float shift)
+{
+       entity f;
+       float r;
+       f = me.focusedChild;
+       if(f)
+       {
+               me.enterSubitem(me, f);
+               r = f.keyDown(f, scan, ascii, shift);
+               me.leaveSubitem(me);
+               return r;
+       }
+       return 0;
+}
+
+float Container_mouseMove(entity me, vector pos)
+{
+       entity f;
+       float r;
+       f = me.focusedChild;
+       if(f)
+       {
+               me.enterSubitem(me, f);
+               r = f.mouseMove(f, globalToBox(pos, f.Container_origin, f.Container_size));
+               me.leaveSubitem(me);
+               return r;
+       }
+       return 0;
+}
+float Container_mousePress(entity me, vector pos)
+{
+       entity f;
+       float r;
+       f = me.focusedChild;
+       if(f)
+       {
+               me.enterSubitem(me, f);
+               r = f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
+               me.leaveSubitem(me);
+               return r;
+       }
+       return 0;
+}
+float Container_mouseDrag(entity me, vector pos)
+{
+       entity f;
+       float r;
+       f = me.focusedChild;
+       if(f)
+       {
+               me.enterSubitem(me, f);
+               r = f.mouseDrag(f, globalToBox(pos, f.Container_origin, f.Container_size));
+               me.leaveSubitem(me);
+               return r;
+       }
+       return 0;
+}
+float Container_mouseRelease(entity me, vector pos)
+{
+       entity f;
+       float r;
+       f = me.focusedChild;
+       if(f)
+       {
+               me.enterSubitem(me, f);
+               r = f.mouseRelease(f, globalToBox(pos, f.Container_origin, f.Container_size));
+               me.leaveSubitem(me);
+               return r;
+       }
+       return 0;
+}
+
+void Container_addItemCentered(entity me, entity other, vector theSize, float theAlpha)
+{
+       me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha);
+}
+
+void Container_addItem(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 l;
+       l = me.lastChild;
+
+       if(l)
+               l.nextSibling = other;
+       else
+               me.firstChild = other;
+
+       other.prevSibling = l;
+       other.nextSibling = NULL;
+       me.lastChild = other;
+}
+
+void Container_removeItem(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;
+       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 Container_setFocus(entity me, entity other)
+{
+       if(me.focusedChild == other)
+               return;
+
+       if(me.focusedChild)
+       {
+               me.focusedChild.focused = 0;
+               me.focusedChild.focusLeave(me.focusedChild);
+               me.focusedChild = NULL;
+       }
+
+       if(other)
+       {
+               if(!me.focused)
+                       error("Trying to set focus in a non-focused control!");
+
+               if(me.savedFocus)
+               {
+                       me.focusedChild = me.savedFocus;
+                       me.savedFocus = NULL;
+                       me.focusedChild.focused = 1;
+                       me.focusedChild.focusEnter(me.focusedChild);
+
+                       if(me.focusedChild.instanceOfContainer)
+                               me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
+               }
+               else
+               {
+                       me.focusedChild = other;
+                       me.focusedChild.focused = 1;
+                       me.focusedChild.focusEnter(me.focusedChild);
+               }
+       }
+}
+
+void Container_saveFocus(entity me)
+{
+       me.savedFocus = me.focusedChild;
+
+       if(me.focusedChild.instanceOfContainer)
+               me.focusedChild.saveFocus(me.focusedChild);
+}
+
+void Container_moveItemAfter(entity me, entity other, entity dest)
+{
+       // first: remove other from the chain
+       entity n, p;
+
+       if(other.parent != me)
+               error("Can't move in wrong container!");
+
+       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;
+}
+
+entity Container_preferredFocusedGrandChild(entity me)
+{
+       entity e, e2;
+       entity best;
+
+       best = NULL;
+
+       for(e = me.firstChild; e; e = e.nextSibling)
+       {
+               if(e.instanceOfContainer)
+               {
+                       e2 = e.preferredFocusedGrandChild(e);
+                       if(e2)
+                               if(!best || best.preferredFocusPriority < e2.preferredFocusPriority)
+                                       best = e2;
+               }
+               if(e)
+                       if(!best || best.preferredFocusPriority < e.preferredFocusPriority)
+                               best = e;
+       }
+
+       return best;
+}
+#endif
diff --git a/qcsrc/menu/item/dialog.c b/qcsrc/menu/item/dialog.c
deleted file mode 100644 (file)
index 3835787..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-// 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, requiresConnection, float, 0) // set to TRUE if the dialog requires a connection to be opened
-
-       ATTRIB(Dialog, backgroundImage, string, string_null)
-       ATTRIB(Dialog, borderLines, float, 1)
-       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 Dialog_fill(entity me)
-{
-}
-
-void Dialog_addItemSimple(entity me, float row, float col, float rowspan, float colspan, entity e, vector v)
-{
-       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 Dialog_gotoRC(entity me, float row, float col)
-{
-       me.currentRow = row;
-       me.currentColumn = col;
-}
-
-void Dialog_TR(entity me)
-{
-       me.currentRow += 1;
-       me.currentColumn = me.firstColumn;
-}
-
-void Dialog_TD(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 Dialog_TDNoMargin(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 Dialog_setFirstColumn(entity me, float col)
-{
-       me.firstColumn = col;
-}
-
-void Dialog_TDempty(entity me, float colspan)
-{
-       me.currentColumn += colspan;
-}
-
-void Dialog_configureDialog(entity me)
-{
-       float absWidth, absHeight;
-
-       me.frame = spawnBorderImage();
-       me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.borderLines * 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 (!me.titleFontSize)
-               me.titleHeight = 0; // no title bar
-
-       absWidth = me.intendedWidth * conwidth;
-       absHeight = me.borderLines * me.titleHeight + me.marginTop + me.rows * me.rowHeight + (me.rows - 1) * me.rowSpacing + me.marginBottom;
-       me.itemOrigin  = eX * (me.marginLeft / absWidth)
-                      + eY * ((me.borderLines * 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 && me.borderLines > 0)
-       {
-               entity closebutton;
-               closebutton = me.closeButton = me.frame.closeButton = spawnButton();
-               closebutton.configureButton(closebutton, "", 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
-       }
-}
-
-void Dialog_close(entity me)
-{
-       if(me.parent.instanceOfNexposee)
-       {
-               ExposeeCloseButton_Click(me, me.parent);
-       }
-       else if(me.parent.instanceOfModalController)
-       {
-               DialogCloseButton_Click(me, me);
-       }
-}
-
-float Dialog_keyDown(entity me, float key, float ascii, float shift)
-{
-       if(me.closable)
-       {
-               if(key == K_ESCAPE)
-               {
-                       me.close(me);
-                       return 1;
-               }
-       }
-       return SUPER(Dialog).keyDown(me, key, ascii, shift);
-}
-#endif
diff --git a/qcsrc/menu/item/dialog.qc b/qcsrc/menu/item/dialog.qc
new file mode 100644 (file)
index 0000000..3835787
--- /dev/null
@@ -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, requiresConnection, float, 0) // set to TRUE if the dialog requires a connection to be opened
+
+       ATTRIB(Dialog, backgroundImage, string, string_null)
+       ATTRIB(Dialog, borderLines, float, 1)
+       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 Dialog_fill(entity me)
+{
+}
+
+void Dialog_addItemSimple(entity me, float row, float col, float rowspan, float colspan, entity e, vector v)
+{
+       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 Dialog_gotoRC(entity me, float row, float col)
+{
+       me.currentRow = row;
+       me.currentColumn = col;
+}
+
+void Dialog_TR(entity me)
+{
+       me.currentRow += 1;
+       me.currentColumn = me.firstColumn;
+}
+
+void Dialog_TD(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 Dialog_TDNoMargin(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 Dialog_setFirstColumn(entity me, float col)
+{
+       me.firstColumn = col;
+}
+
+void Dialog_TDempty(entity me, float colspan)
+{
+       me.currentColumn += colspan;
+}
+
+void Dialog_configureDialog(entity me)
+{
+       float absWidth, absHeight;
+
+       me.frame = spawnBorderImage();
+       me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.borderLines * 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 (!me.titleFontSize)
+               me.titleHeight = 0; // no title bar
+
+       absWidth = me.intendedWidth * conwidth;
+       absHeight = me.borderLines * me.titleHeight + me.marginTop + me.rows * me.rowHeight + (me.rows - 1) * me.rowSpacing + me.marginBottom;
+       me.itemOrigin  = eX * (me.marginLeft / absWidth)
+                      + eY * ((me.borderLines * 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 && me.borderLines > 0)
+       {
+               entity closebutton;
+               closebutton = me.closeButton = me.frame.closeButton = spawnButton();
+               closebutton.configureButton(closebutton, "", 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
+       }
+}
+
+void Dialog_close(entity me)
+{
+       if(me.parent.instanceOfNexposee)
+       {
+               ExposeeCloseButton_Click(me, me.parent);
+       }
+       else if(me.parent.instanceOfModalController)
+       {
+               DialogCloseButton_Click(me, me);
+       }
+}
+
+float Dialog_keyDown(entity me, float key, float ascii, float shift)
+{
+       if(me.closable)
+       {
+               if(key == K_ESCAPE)
+               {
+                       me.close(me);
+                       return 1;
+               }
+       }
+       return SUPER(Dialog).keyDown(me, key, ascii, shift);
+}
+#endif
diff --git a/qcsrc/menu/item/image.c b/qcsrc/menu/item/image.c
deleted file mode 100644 (file)
index 8d1a6de..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-#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))
-       METHOD(Image, updateAspect, void(entity))
-       METHOD(Image, initZoom, void(entity))
-       METHOD(Image, setZoom, void(entity, float, float))
-       METHOD(Image, drag_setStartPos, float(entity, vector))
-       METHOD(Image, drag, float(entity, vector))
-       ATTRIB(Image, src, string, string_null)
-       ATTRIB(Image, color, vector, '1 1 1')
-       ATTRIB(Image, forcedAspect, float, 0) // special values: -1 keep image aspect ratio, -2 keep image size but bound to the containing box, -3 always keep image size
-       ATTRIB(Image, zoomBox, float, 0) // used by forcedAspect -2 when the image is larger than the containing box
-       ATTRIB(Image, zoomFactor, float, 1)
-       ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
-       ATTRIB(Image, zoomSnapToTheBox, float, 1) // snap the zoomed in image to the box borders when zooming/dragging it
-       ATTRIB(Image, zoomTime, float, 0)
-       ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
-       ATTRIB(Image, zoomMax, float, 0)
-       ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
-       ATTRIB(Image, start_coords, vector, '0 0 0')
-       ATTRIB(Image, imgOrigin, vector, '0 0 0')
-       ATTRIB(Image, imgSize, vector, '0 0 0')
-ENDCLASS(Image)
-#endif
-
-#ifdef IMPLEMENTATION
-string Image_toString(entity me)
-{
-       return me.src;
-}
-void Image_configureImage(entity me, string path)
-{
-       me.src = path;
-}
-void Image_initZoom(entity me)
-{
-       me.zoomOffset = '0.5 0.5 0';
-       me.zoomFactor = 1;
-       if (me.forcedAspect == -2)
-               me.zoomBox = -1; // calculate zoomBox at the first updateAspect call
-       if (me.zoomLimitedByTheBox)
-               me.zoomMax = -1; // calculate zoomMax at the first updateAspect call
-}
-
-void Image_draw(entity me)
-{
-       if(me.imgSize_x > 1 || me.imgSize_y > 1)
-               draw_SetClip();
-       draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
-       if(me.imgSize_x > 1 || me.imgSize_y > 1)
-               draw_ClearClip();
-       SUPER(Image).draw(me);
-}
-void Image_updateAspect(entity me)
-{
-       float asp = 0;
-       if(me.size_x <= 0 || me.size_y <= 0)
-               return;
-       if(me.forcedAspect == 0)
-       {
-               me.imgOrigin = '0 0 0';
-               me.imgSize = '1 1 0';
-       }
-       else
-       {
-               vector sz = '0 0 0';
-               if(me.forcedAspect < 0)
-               {
-                       if (me.src != "")
-                               sz = draw_PictureSize(me.src);
-                       if(sz_x <= 0 || sz_y <= 0)
-                       {
-                               // image is broken or doesn't exist, set the size for the placeholder image
-                               sz_x = me.size_x;
-                               sz_y = me.size_y;
-                       }
-                       asp = sz_x / sz_y;
-               }
-               else
-                       asp = me.forcedAspect;
-
-               if(me.forcedAspect <= -2)
-               {
-                       me.imgSize_x = sz_x / me.size_x;
-                       me.imgSize_y = sz_y / me.size_y;
-                       if(me.zoomBox < 0 && (me.imgSize_x > 1 || me.imgSize_y > 1))
-                       {
-                               // image larger than the containing box, zoom it out to fit into the box
-                               if(me.size_x > asp * me.size_y)
-                                       me.zoomBox = (me.size_y * asp / me.size_x) / me.imgSize_x;
-                               else
-                                       me.zoomBox = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
-                               me.zoomFactor = me.zoomBox;
-                       }
-               }
-               else
-               {
-                       if(me.size_x > asp * me.size_y)
-                       {
-                               // x too large, so center x-wise
-                               me.imgSize = eY + eX * (me.size_y * asp / me.size_x);
-                       }
-                       else
-                       {
-                               // y too large, so center y-wise
-                               me.imgSize = eX + eY * (me.size_x / (asp * me.size_y));
-                       }
-               }
-       }
-
-       if (me.zoomMax < 0)
-       {
-               if(me.zoomBox > 0)
-                       me.zoomMax = me.zoomBox;
-               else
-               {
-                       if(me.size_x > asp * me.size_y)
-                               me.zoomMax = (me.size_y * asp / me.size_x) / me.imgSize_x;
-                       else
-                               me.zoomMax = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
-               }
-       }
-
-       if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
-               me.zoomFactor = me.zoomMax;
-       if (me.zoomFactor)
-               me.imgSize = me.imgSize * me.zoomFactor;
-
-       if(me.imgSize_x > 1 || me.imgSize_y > 1)
-       {
-               if(me.zoomSnapToTheBox)
-               {
-                       if(me.imgSize_x > 1)
-                               me.zoomOffset_x = bound(0.5/me.imgSize_x, me.zoomOffset_x, 1 - 0.5/me.imgSize_x);
-                       else
-                               me.zoomOffset_x = bound(1 - 0.5/me.imgSize_x, me.zoomOffset_x, 0.5/me.imgSize_x);
-
-                       if(me.imgSize_y > 1)
-                               me.zoomOffset_y = bound(0.5/me.imgSize_y, me.zoomOffset_y, 1 - 0.5/me.imgSize_y);
-                       else
-                               me.zoomOffset_y = bound(1 - 0.5/me.imgSize_y, me.zoomOffset_y, 0.5/me.imgSize_y);
-               }
-               else
-               {
-                       me.zoomOffset_x = bound(0, me.zoomOffset_x, 1);
-                       me.zoomOffset_y = bound(0, me.zoomOffset_y, 1);
-               }
-       }
-       else
-               me.zoomOffset = '0.5 0.5 0';
-
-       me.imgOrigin_x = 0.5 - me.zoomOffset_x * me.imgSize_x;
-       me.imgOrigin_y = 0.5 - me.zoomOffset_y * me.imgSize_y;
-}
-float Image_drag_setStartPos(entity me, vector coords)
-{
-       //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
-       {
-               me.start_zoomOffset = me.zoomOffset;
-               me.start_coords = coords;
-       }
-       return 1;
-}
-float Image_drag(entity me, vector coords)
-{
-       if(me.imgSize_x > 1 || me.imgSize_y > 1)
-       {
-               me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - coords_x) / me.imgSize_x;
-               me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - coords_y) / me.imgSize_y;
-               me.updateAspect(me);
-       }
-       return 1;
-}
-void Image_setZoom(entity me, float z, float atMousePosition)
-{
-       float prev_zoomFactor;
-       prev_zoomFactor = me.zoomFactor;
-       if (z < 0) // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
-       {
-               me.zoomFactor *= -z;
-               float realSize_in_the_middle, boxSize_in_the_middle;
-               realSize_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
-               boxSize_in_the_middle = (me.zoomBox > 0 && (prev_zoomFactor - me.zoomBox) * (me.zoomFactor - me.zoomBox) < 0);
-               if (realSize_in_the_middle && boxSize_in_the_middle)
-               {
-                       // snap to real dimensions or to box
-                       if (prev_zoomFactor < me.zoomFactor)
-                               me.zoomFactor = min(1, me.zoomBox);
-                       else
-                               me.zoomFactor = max(1, me.zoomBox);
-               }
-               else if (realSize_in_the_middle)
-                       me.zoomFactor = 1; // snap to real dimensions
-               else if (boxSize_in_the_middle)
-                       me.zoomFactor = me.zoomBox; // snap to box
-       }
-       else if (z == 0) // reset (no zoom)
-       {
-               if (me.zoomBox > 0)
-                       me.zoomFactor = me.zoomBox;
-               else
-                       me.zoomFactor = 1;
-       }
-       else // directly set
-               me.zoomFactor = z;
-       me.zoomFactor = bound(1/16, me.zoomFactor, 16);
-       if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
-               me.zoomFactor = me.zoomMax;
-       if (prev_zoomFactor != me.zoomFactor)
-       {
-               me.zoomTime = time;
-               if (atMousePosition)
-               {
-                       me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - 0.5) / me.imgSize_x;
-                       me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - 0.5) / me.imgSize_y;
-                       // updateAspect will reset zoomOffset to '0.5 0.5 0' if
-                       // with this zoomFactor the image will not be zoomed in
-                       // (updateAspect will check the new values of imgSize).
-               }
-       }
-       me.updateAspect(me);
-}
-void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       me.updateAspect(me);
-}
-#endif
diff --git a/qcsrc/menu/item/image.qc b/qcsrc/menu/item/image.qc
new file mode 100644 (file)
index 0000000..8d1a6de
--- /dev/null
@@ -0,0 +1,231 @@
+#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))
+       METHOD(Image, updateAspect, void(entity))
+       METHOD(Image, initZoom, void(entity))
+       METHOD(Image, setZoom, void(entity, float, float))
+       METHOD(Image, drag_setStartPos, float(entity, vector))
+       METHOD(Image, drag, float(entity, vector))
+       ATTRIB(Image, src, string, string_null)
+       ATTRIB(Image, color, vector, '1 1 1')
+       ATTRIB(Image, forcedAspect, float, 0) // special values: -1 keep image aspect ratio, -2 keep image size but bound to the containing box, -3 always keep image size
+       ATTRIB(Image, zoomBox, float, 0) // used by forcedAspect -2 when the image is larger than the containing box
+       ATTRIB(Image, zoomFactor, float, 1)
+       ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
+       ATTRIB(Image, zoomSnapToTheBox, float, 1) // snap the zoomed in image to the box borders when zooming/dragging it
+       ATTRIB(Image, zoomTime, float, 0)
+       ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
+       ATTRIB(Image, zoomMax, float, 0)
+       ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
+       ATTRIB(Image, start_coords, vector, '0 0 0')
+       ATTRIB(Image, imgOrigin, vector, '0 0 0')
+       ATTRIB(Image, imgSize, vector, '0 0 0')
+ENDCLASS(Image)
+#endif
+
+#ifdef IMPLEMENTATION
+string Image_toString(entity me)
+{
+       return me.src;
+}
+void Image_configureImage(entity me, string path)
+{
+       me.src = path;
+}
+void Image_initZoom(entity me)
+{
+       me.zoomOffset = '0.5 0.5 0';
+       me.zoomFactor = 1;
+       if (me.forcedAspect == -2)
+               me.zoomBox = -1; // calculate zoomBox at the first updateAspect call
+       if (me.zoomLimitedByTheBox)
+               me.zoomMax = -1; // calculate zoomMax at the first updateAspect call
+}
+
+void Image_draw(entity me)
+{
+       if(me.imgSize_x > 1 || me.imgSize_y > 1)
+               draw_SetClip();
+       draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
+       if(me.imgSize_x > 1 || me.imgSize_y > 1)
+               draw_ClearClip();
+       SUPER(Image).draw(me);
+}
+void Image_updateAspect(entity me)
+{
+       float asp = 0;
+       if(me.size_x <= 0 || me.size_y <= 0)
+               return;
+       if(me.forcedAspect == 0)
+       {
+               me.imgOrigin = '0 0 0';
+               me.imgSize = '1 1 0';
+       }
+       else
+       {
+               vector sz = '0 0 0';
+               if(me.forcedAspect < 0)
+               {
+                       if (me.src != "")
+                               sz = draw_PictureSize(me.src);
+                       if(sz_x <= 0 || sz_y <= 0)
+                       {
+                               // image is broken or doesn't exist, set the size for the placeholder image
+                               sz_x = me.size_x;
+                               sz_y = me.size_y;
+                       }
+                       asp = sz_x / sz_y;
+               }
+               else
+                       asp = me.forcedAspect;
+
+               if(me.forcedAspect <= -2)
+               {
+                       me.imgSize_x = sz_x / me.size_x;
+                       me.imgSize_y = sz_y / me.size_y;
+                       if(me.zoomBox < 0 && (me.imgSize_x > 1 || me.imgSize_y > 1))
+                       {
+                               // image larger than the containing box, zoom it out to fit into the box
+                               if(me.size_x > asp * me.size_y)
+                                       me.zoomBox = (me.size_y * asp / me.size_x) / me.imgSize_x;
+                               else
+                                       me.zoomBox = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
+                               me.zoomFactor = me.zoomBox;
+                       }
+               }
+               else
+               {
+                       if(me.size_x > asp * me.size_y)
+                       {
+                               // x too large, so center x-wise
+                               me.imgSize = eY + eX * (me.size_y * asp / me.size_x);
+                       }
+                       else
+                       {
+                               // y too large, so center y-wise
+                               me.imgSize = eX + eY * (me.size_x / (asp * me.size_y));
+                       }
+               }
+       }
+
+       if (me.zoomMax < 0)
+       {
+               if(me.zoomBox > 0)
+                       me.zoomMax = me.zoomBox;
+               else
+               {
+                       if(me.size_x > asp * me.size_y)
+                               me.zoomMax = (me.size_y * asp / me.size_x) / me.imgSize_x;
+                       else
+                               me.zoomMax = (me.size_x / (asp * me.size_y)) / me.imgSize_y;
+               }
+       }
+
+       if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
+               me.zoomFactor = me.zoomMax;
+       if (me.zoomFactor)
+               me.imgSize = me.imgSize * me.zoomFactor;
+
+       if(me.imgSize_x > 1 || me.imgSize_y > 1)
+       {
+               if(me.zoomSnapToTheBox)
+               {
+                       if(me.imgSize_x > 1)
+                               me.zoomOffset_x = bound(0.5/me.imgSize_x, me.zoomOffset_x, 1 - 0.5/me.imgSize_x);
+                       else
+                               me.zoomOffset_x = bound(1 - 0.5/me.imgSize_x, me.zoomOffset_x, 0.5/me.imgSize_x);
+
+                       if(me.imgSize_y > 1)
+                               me.zoomOffset_y = bound(0.5/me.imgSize_y, me.zoomOffset_y, 1 - 0.5/me.imgSize_y);
+                       else
+                               me.zoomOffset_y = bound(1 - 0.5/me.imgSize_y, me.zoomOffset_y, 0.5/me.imgSize_y);
+               }
+               else
+               {
+                       me.zoomOffset_x = bound(0, me.zoomOffset_x, 1);
+                       me.zoomOffset_y = bound(0, me.zoomOffset_y, 1);
+               }
+       }
+       else
+               me.zoomOffset = '0.5 0.5 0';
+
+       me.imgOrigin_x = 0.5 - me.zoomOffset_x * me.imgSize_x;
+       me.imgOrigin_y = 0.5 - me.zoomOffset_y * me.imgSize_y;
+}
+float Image_drag_setStartPos(entity me, vector coords)
+{
+       //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
+       {
+               me.start_zoomOffset = me.zoomOffset;
+               me.start_coords = coords;
+       }
+       return 1;
+}
+float Image_drag(entity me, vector coords)
+{
+       if(me.imgSize_x > 1 || me.imgSize_y > 1)
+       {
+               me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - coords_x) / me.imgSize_x;
+               me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - coords_y) / me.imgSize_y;
+               me.updateAspect(me);
+       }
+       return 1;
+}
+void Image_setZoom(entity me, float z, float atMousePosition)
+{
+       float prev_zoomFactor;
+       prev_zoomFactor = me.zoomFactor;
+       if (z < 0) // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
+       {
+               me.zoomFactor *= -z;
+               float realSize_in_the_middle, boxSize_in_the_middle;
+               realSize_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
+               boxSize_in_the_middle = (me.zoomBox > 0 && (prev_zoomFactor - me.zoomBox) * (me.zoomFactor - me.zoomBox) < 0);
+               if (realSize_in_the_middle && boxSize_in_the_middle)
+               {
+                       // snap to real dimensions or to box
+                       if (prev_zoomFactor < me.zoomFactor)
+                               me.zoomFactor = min(1, me.zoomBox);
+                       else
+                               me.zoomFactor = max(1, me.zoomBox);
+               }
+               else if (realSize_in_the_middle)
+                       me.zoomFactor = 1; // snap to real dimensions
+               else if (boxSize_in_the_middle)
+                       me.zoomFactor = me.zoomBox; // snap to box
+       }
+       else if (z == 0) // reset (no zoom)
+       {
+               if (me.zoomBox > 0)
+                       me.zoomFactor = me.zoomBox;
+               else
+                       me.zoomFactor = 1;
+       }
+       else // directly set
+               me.zoomFactor = z;
+       me.zoomFactor = bound(1/16, me.zoomFactor, 16);
+       if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
+               me.zoomFactor = me.zoomMax;
+       if (prev_zoomFactor != me.zoomFactor)
+       {
+               me.zoomTime = time;
+               if (atMousePosition)
+               {
+                       me.zoomOffset_x = me.start_zoomOffset_x + (me.start_coords_x - 0.5) / me.imgSize_x;
+                       me.zoomOffset_y = me.start_zoomOffset_y + (me.start_coords_y - 0.5) / me.imgSize_y;
+                       // updateAspect will reset zoomOffset to '0.5 0.5 0' if
+                       // with this zoomFactor the image will not be zoomed in
+                       // (updateAspect will check the new values of imgSize).
+               }
+       }
+       me.updateAspect(me);
+}
+void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+       me.updateAspect(me);
+}
+#endif
diff --git a/qcsrc/menu/item/inputbox.c b/qcsrc/menu/item/inputbox.c
deleted file mode 100644 (file)
index 7708a0d..0000000
+++ /dev/null
@@ -1,391 +0,0 @@
-#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, mouseMove, float(entity, vector))
-       METHOD(InputBox, mouseRelease, float(entity, vector))
-       METHOD(InputBox, mousePress, float(entity, vector))
-       METHOD(InputBox, mouseDrag, float(entity, vector))
-       METHOD(InputBox, showNotify, void(entity))
-       METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector))
-
-       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')
-       ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
-
-       ATTRIB(InputBox, enableClearButton, float, 1)
-       ATTRIB(InputBox, clearButton, entity, NULL)
-       ATTRIB(InputBox, cb_width, float, 0)
-       ATTRIB(InputBox, cb_pressed, float, 0)
-       ATTRIB(InputBox, cb_focused, float, 0)
-       ATTRIB(InputBox, cb_color, vector, '1 1 1')
-       ATTRIB(InputBox, cb_colorF, vector, '1 1 1')
-       ATTRIB(InputBox, cb_colorC, vector, '1 1 1')
-ENDCLASS(InputBox)
-void InputBox_Clear_Click(entity btn, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-void InputBox_configureInputBox(entity me, string theText, float theCursorPos, float theFontSize, string gfx)
-{
-       SUPER(InputBox).configureLabel(me, theText, theFontSize, 0.0);
-       me.src = gfx;
-       me.cursorPos = theCursorPos;
-}
-void InputBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(InputBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       if (me.enableClearButton)
-       {
-               me.cb_width = absSize_y / absSize_x;
-               me.cb_offset = bound(-1, me.cb_offset, 0) * me.cb_width; // bound to range -1, 0
-               me.keepspaceRight = me.keepspaceRight - me.cb_offset + me.cb_width;
-       }
-}
-
-void InputBox_setText(entity me, string txt)
-{
-       if(me.text)
-               strunzone(me.text);
-       SUPER(InputBox).setText(me, strzone(txt));
-}
-
-void InputBox_Clear_Click(entity btn, entity me)
-{
-       me.setText(me, "");
-}
-
-float over_ClearButton(entity me, vector pos)
-{
-       if (pos_x >= 1 + me.cb_offset - me.cb_width)
-       if (pos_x < 1 + me.cb_offset)
-       if (pos_y >= 0)
-       if (pos_y < 1)
-               return 1;
-       return 0;
-}
-
-float InputBox_mouseMove(entity me, vector pos)
-{
-       if (me.enableClearButton)
-       {
-               if (over_ClearButton(me, pos))
-               {
-                       me.cb_focused = 1;
-                       return 1;
-               }
-               me.cb_focused = 0;
-       }
-       return 1;
-}
-
-float InputBox_mouseDrag(entity me, vector pos)
-{
-       float p;
-       if(me.pressed)
-       {
-               me.dragScrollPos = pos;
-               p = me.scrollPos + pos_x - me.keepspaceLeft;
-               me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
-               me.lastChangeTime = time;
-       }
-       else if (me.enableClearButton)
-       {
-               if (over_ClearButton(me, pos))
-               {
-                       me.cb_pressed = 1;
-                       return 1;
-               }
-       }
-       me.cb_pressed = 0;
-       return 1;
-}
-
-float InputBox_mousePress(entity me, vector pos)
-{
-       if (me.enableClearButton)
-       if (over_ClearButton(me, pos))
-       {
-               me.cb_pressed = 1;
-               return 1;
-       }
-       me.dragScrollTimer = time;
-       me.pressed = 1;
-       return InputBox_mouseDrag(me, pos);
-}
-
-float InputBox_mouseRelease(entity me, vector pos)
-{
-       if(me.cb_pressed)
-       if (over_ClearButton(me, pos))
-       {
-               me.cb_pressed = 0;
-               InputBox_Clear_Click(world, me);
-               return 1;
-       }
-       float r = InputBox_mouseDrag(me, pos);
-       //reset cb_pressed after mouseDrag, mouseDrag could set cb_pressed in this case:
-       //mouse press out of the clear button, drag and then mouse release over the clear button
-       me.cb_pressed = 0;
-       me.pressed = 0;
-       return r;
-}
-
-void InputBox_enterText(entity me, string ch)
-{
-       float i;
-       for(i = 0; i < strlen(ch); ++i)
-               if(strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1)
-                       return;
-       if(me.maxLength > 0)
-       {
-               if(strlen(ch) + strlen(me.text) > me.maxLength)
-                       return;
-       }
-       else if(me.maxLength < 0)
-       {
-               if(u8_strsize(ch) + u8_strsize(me.text) > -me.maxLength)
-                       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 InputBox_keyDown(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_KP_LEFTARROW:
-               case K_LEFTARROW:
-                       me.cursorPos -= 1;
-                       return 1;
-               case K_KP_RIGHTARROW:
-               case K_RIGHTARROW:
-                       me.cursorPos += 1;
-                       return 1;
-               case K_KP_HOME:
-               case K_HOME:
-                       me.cursorPos = 0;
-                       return 1;
-               case K_KP_END:
-               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_KP_DEL:
-               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 InputBox_draw(entity me)
-{
-       string CURSOR = "_";
-       float cursorPosInWidths, totalSizeInWidths;
-
-       if(me.pressed)
-               me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
-
-       if(me.recalcPos)
-               me.recalcPositionWithText(me, me.text);
-
-       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);
-       totalSizeInWidths = draw_TextWidth(strcat(me.text, CURSOR), 0, me.realFontSize);
-
-       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, n;
-               vector theColor;
-               float theAlpha;    //float theVariableAlpha;
-               vector p;
-               vector theTempColor;
-               float component;
-
-               p = me.realOrigin - eX * me.scrollPos;
-               theColor = '1 1 1';
-               theAlpha = 1;    //theVariableAlpha = 1; // changes when ^ax found
-
-               n = strlen(me.text);
-               for(i = 0; i < n; ++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);
-                               if(ch2 == "^")
-                               {
-                                       draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 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;
-                                       }
-                                       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);
-                               }
-                               else if(ch2 == "x") // ^x found
-                               {
-                                       theColor = '1 1 1';
-
-                                       component = HEXDIGIT_TO_DEC(substring(me.text, i+2, 1));
-                                       if (component >= 0) // ^xr found
-                                       {
-                                               theTempColor_x = component/15;
-
-                                               component = HEXDIGIT_TO_DEC(substring(me.text, i+3, 1));
-                                               if (component >= 0) // ^xrg found
-                                               {
-                                                       theTempColor_y = component/15;
-
-                                                       component = HEXDIGIT_TO_DEC(substring(me.text, i+4, 1));
-                                                       if (component >= 0) // ^xrgb found
-                                                       {
-                                                               theTempColor_z = component/15;
-                                                               theColor = theTempColor;
-                                                               w = draw_TextWidth(substring(me.text, i, 5), 0, me.realFontSize);
-
-                                                               draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
-                                                               draw_Text(p, substring(me.text, i, 5), me.realFontSize, theColor, 1, 0);    // theVariableAlpha instead of 1 using alpha tags ^ax
-                                                               i += 3;
-                                                       }
-                                                       else
-                                                       {
-                                                               // blue missing
-                                                               w = draw_TextWidth(substring(me.text, i, 4), 0, me.realFontSize);
-                                                               draw_Fill(p, eX * w + eY * me.realFontSize_y, eZ, 0.5);
-                                                               draw_Text(p, substring(me.text, i, 4), me.realFontSize, '1 1 1', theAlpha, 0);
-                                                               i += 2;
-                                                       }
-                                               }
-                                               else
-                                               {
-                                                       // green missing
-                                                       w = draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize);
-                                                       draw_Fill(p, eX * w + eY * me.realFontSize_y, eY, 0.5);
-                                                       draw_Text(p, substring(me.text, i, 3), me.realFontSize, '1 1 1', theAlpha, 0);
-                                                       i += 1;
-                                               }
-                                       }
-                                       else
-                                       {
-                                               // red missing
-                                               //w = draw_TextWidth(substring(me.text, i, 2), 0) * me.realFontSize_x;
-                                               draw_Fill(p, eX * w + eY * me.realFontSize_y, eX, 0.5);
-                                               draw_Text(p, substring(me.text, i, 2), me.realFontSize, '1 1 1', theAlpha, 0);
-                                       }
-                               }
-                               else
-                               {
-                                       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);
-                               }
-                               p += w * eX;
-                               ++i;
-                               continue;
-                       }
-                       draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0); // TODO theVariableAlpha
-                       p += eX * draw_TextWidth(ch, 0, me.realFontSize);
-               }
-       }
-       else
-               draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
-
-       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();
-
-       if (me.enableClearButton)
-       if (me.text != "")
-       {
-               if(me.focused && me.cb_pressed)
-                       draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_c"), eX * me.cb_width + eY, me.cb_colorC, 1);
-               else if(me.focused && me.cb_focused)
-                       draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_f"), eX * me.cb_width + eY, me.cb_colorF, 1);
-               else
-                       draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_n"), eX * me.cb_width + eY, me.cb_color, 1);
-       }
-
-       // skipping SUPER(InputBox).draw(me);
-       Item_draw(me);
-}
-
-void InputBox_showNotify(entity me)
-{
-       me.focusable = !me.disabled;
-}
-#endif
diff --git a/qcsrc/menu/item/inputbox.qc b/qcsrc/menu/item/inputbox.qc
new file mode 100644 (file)
index 0000000..7708a0d
--- /dev/null
@@ -0,0 +1,391 @@
+#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, mouseMove, float(entity, vector))
+       METHOD(InputBox, mouseRelease, float(entity, vector))
+       METHOD(InputBox, mousePress, float(entity, vector))
+       METHOD(InputBox, mouseDrag, float(entity, vector))
+       METHOD(InputBox, showNotify, void(entity))
+       METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector))
+
+       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')
+       ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
+
+       ATTRIB(InputBox, enableClearButton, float, 1)
+       ATTRIB(InputBox, clearButton, entity, NULL)
+       ATTRIB(InputBox, cb_width, float, 0)
+       ATTRIB(InputBox, cb_pressed, float, 0)
+       ATTRIB(InputBox, cb_focused, float, 0)
+       ATTRIB(InputBox, cb_color, vector, '1 1 1')
+       ATTRIB(InputBox, cb_colorF, vector, '1 1 1')
+       ATTRIB(InputBox, cb_colorC, vector, '1 1 1')
+ENDCLASS(InputBox)
+void InputBox_Clear_Click(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+void InputBox_configureInputBox(entity me, string theText, float theCursorPos, float theFontSize, string gfx)
+{
+       SUPER(InputBox).configureLabel(me, theText, theFontSize, 0.0);
+       me.src = gfx;
+       me.cursorPos = theCursorPos;
+}
+void InputBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(InputBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+       if (me.enableClearButton)
+       {
+               me.cb_width = absSize_y / absSize_x;
+               me.cb_offset = bound(-1, me.cb_offset, 0) * me.cb_width; // bound to range -1, 0
+               me.keepspaceRight = me.keepspaceRight - me.cb_offset + me.cb_width;
+       }
+}
+
+void InputBox_setText(entity me, string txt)
+{
+       if(me.text)
+               strunzone(me.text);
+       SUPER(InputBox).setText(me, strzone(txt));
+}
+
+void InputBox_Clear_Click(entity btn, entity me)
+{
+       me.setText(me, "");
+}
+
+float over_ClearButton(entity me, vector pos)
+{
+       if (pos_x >= 1 + me.cb_offset - me.cb_width)
+       if (pos_x < 1 + me.cb_offset)
+       if (pos_y >= 0)
+       if (pos_y < 1)
+               return 1;
+       return 0;
+}
+
+float InputBox_mouseMove(entity me, vector pos)
+{
+       if (me.enableClearButton)
+       {
+               if (over_ClearButton(me, pos))
+               {
+                       me.cb_focused = 1;
+                       return 1;
+               }
+               me.cb_focused = 0;
+       }
+       return 1;
+}
+
+float InputBox_mouseDrag(entity me, vector pos)
+{
+       float p;
+       if(me.pressed)
+       {
+               me.dragScrollPos = pos;
+               p = me.scrollPos + pos_x - me.keepspaceLeft;
+               me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
+               me.lastChangeTime = time;
+       }
+       else if (me.enableClearButton)
+       {
+               if (over_ClearButton(me, pos))
+               {
+                       me.cb_pressed = 1;
+                       return 1;
+               }
+       }
+       me.cb_pressed = 0;
+       return 1;
+}
+
+float InputBox_mousePress(entity me, vector pos)
+{
+       if (me.enableClearButton)
+       if (over_ClearButton(me, pos))
+       {
+               me.cb_pressed = 1;
+               return 1;
+       }
+       me.dragScrollTimer = time;
+       me.pressed = 1;
+       return InputBox_mouseDrag(me, pos);
+}
+
+float InputBox_mouseRelease(entity me, vector pos)
+{
+       if(me.cb_pressed)
+       if (over_ClearButton(me, pos))
+       {
+               me.cb_pressed = 0;
+               InputBox_Clear_Click(world, me);
+               return 1;
+       }
+       float r = InputBox_mouseDrag(me, pos);
+       //reset cb_pressed after mouseDrag, mouseDrag could set cb_pressed in this case:
+       //mouse press out of the clear button, drag and then mouse release over the clear button
+       me.cb_pressed = 0;
+       me.pressed = 0;
+       return r;
+}
+
+void InputBox_enterText(entity me, string ch)
+{
+       float i;
+       for(i = 0; i < strlen(ch); ++i)
+               if(strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1)
+                       return;
+       if(me.maxLength > 0)
+       {
+               if(strlen(ch) + strlen(me.text) > me.maxLength)
+                       return;
+       }
+       else if(me.maxLength < 0)
+       {
+               if(u8_strsize(ch) + u8_strsize(me.text) > -me.maxLength)
+                       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 InputBox_keyDown(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_KP_LEFTARROW:
+               case K_LEFTARROW:
+                       me.cursorPos -= 1;
+                       return 1;
+               case K_KP_RIGHTARROW:
+               case K_RIGHTARROW:
+                       me.cursorPos += 1;
+                       return 1;
+               case K_KP_HOME:
+               case K_HOME:
+                       me.cursorPos = 0;
+                       return 1;
+               case K_KP_END:
+               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_KP_DEL:
+               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 InputBox_draw(entity me)
+{
+       string CURSOR = "_";
+       float cursorPosInWidths, totalSizeInWidths;
+
+       if(me.pressed)
+               me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
+
+       if(me.recalcPos)
+               me.recalcPositionWithText(me, me.text);
+
+       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);
+       totalSizeInWidths = draw_TextWidth(strcat(me.text, CURSOR), 0, me.realFontSize);
+
+       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, n;
+               vector theColor;
+               float theAlpha;    //float theVariableAlpha;
+               vector p;
+               vector theTempColor;
+               float component;
+
+               p = me.realOrigin - eX * me.scrollPos;
+               theColor = '1 1 1';
+               theAlpha = 1;    //theVariableAlpha = 1; // changes when ^ax found
+
+               n = strlen(me.text);
+               for(i = 0; i < n; ++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);
+                               if(ch2 == "^")
+                               {
+                                       draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 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;
+                                       }
+                                       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);
+                               }
+                               else if(ch2 == "x") // ^x found
+                               {
+                                       theColor = '1 1 1';
+
+                                       component = HEXDIGIT_TO_DEC(substring(me.text, i+2, 1));
+                                       if (component >= 0) // ^xr found
+                                       {
+                                               theTempColor_x = component/15;
+
+                                               component = HEXDIGIT_TO_DEC(substring(me.text, i+3, 1));
+                                               if (component >= 0) // ^xrg found
+                                               {
+                                                       theTempColor_y = component/15;
+
+                                                       component = HEXDIGIT_TO_DEC(substring(me.text, i+4, 1));
+                                                       if (component >= 0) // ^xrgb found
+                                                       {
+                                                               theTempColor_z = component/15;
+                                                               theColor = theTempColor;
+                                                               w = draw_TextWidth(substring(me.text, i, 5), 0, me.realFontSize);
+
+                                                               draw_Fill(p, eX * w + eY * me.realFontSize_y, '1 1 1', 0.5);
+                                                               draw_Text(p, substring(me.text, i, 5), me.realFontSize, theColor, 1, 0);    // theVariableAlpha instead of 1 using alpha tags ^ax
+                                                               i += 3;
+                                                       }
+                                                       else
+                                                       {
+                                                               // blue missing
+                                                               w = draw_TextWidth(substring(me.text, i, 4), 0, me.realFontSize);
+                                                               draw_Fill(p, eX * w + eY * me.realFontSize_y, eZ, 0.5);
+                                                               draw_Text(p, substring(me.text, i, 4), me.realFontSize, '1 1 1', theAlpha, 0);
+                                                               i += 2;
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       // green missing
+                                                       w = draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize);
+                                                       draw_Fill(p, eX * w + eY * me.realFontSize_y, eY, 0.5);
+                                                       draw_Text(p, substring(me.text, i, 3), me.realFontSize, '1 1 1', theAlpha, 0);
+                                                       i += 1;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               // red missing
+                                               //w = draw_TextWidth(substring(me.text, i, 2), 0) * me.realFontSize_x;
+                                               draw_Fill(p, eX * w + eY * me.realFontSize_y, eX, 0.5);
+                                               draw_Text(p, substring(me.text, i, 2), me.realFontSize, '1 1 1', theAlpha, 0);
+                                       }
+                               }
+                               else
+                               {
+                                       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);
+                               }
+                               p += w * eX;
+                               ++i;
+                               continue;
+                       }
+                       draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0); // TODO theVariableAlpha
+                       p += eX * draw_TextWidth(ch, 0, me.realFontSize);
+               }
+       }
+       else
+               draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
+
+       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();
+
+       if (me.enableClearButton)
+       if (me.text != "")
+       {
+               if(me.focused && me.cb_pressed)
+                       draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_c"), eX * me.cb_width + eY, me.cb_colorC, 1);
+               else if(me.focused && me.cb_focused)
+                       draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_f"), eX * me.cb_width + eY, me.cb_colorF, 1);
+               else
+                       draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_n"), eX * me.cb_width + eY, me.cb_color, 1);
+       }
+
+       // skipping SUPER(InputBox).draw(me);
+       Item_draw(me);
+}
+
+void InputBox_showNotify(entity me)
+{
+       me.focusable = !me.disabled;
+}
+#endif
diff --git a/qcsrc/menu/item/inputcontainer.c b/qcsrc/menu/item/inputcontainer.c
deleted file mode 100644 (file)
index 0f80c2b..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-#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 InputContainer_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(InputContainer).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       /*
-       if(me.parent.instanceOfInputContainer)
-               me.isTabRoot = 0;
-       else
-               me.isTabRoot = 1;
-       */
-}
-
-void InputContainer_focusLeave(entity me)
-{
-       SUPER(InputContainer).focusLeave(me);
-       me.mouseFocusedChild = NULL;
-}
-
-float InputContainer_keyDown(entity me, float scan, float ascii, float shift)
-{
-       entity f, ff;
-       if(SUPER(InputContainer).keyDown(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 (!ff.focusable)
-                                               continue;
-                                       me.setFocus(me, ff);
-                                       return 1;
-                               }
-                       }
-                       if(!f || me.isTabRoot)
-                       {
-                               for(ff = me.lastChild; ff; ff = ff.prevSibling)
-                               {
-                                       if (!ff.focusable)
-                                               continue;
-                                       me.setFocus(me, ff);
-                                       return 1;
-                               }
-                               return 0; // AIIIIEEEEE!
-                       }
-               }
-               else
-               {
-                       if(f)
-                       {
-                               for(ff = f.nextSibling; ff; ff = ff.nextSibling)
-                               {
-                                       if (!ff.focusable)
-                                               continue;
-                                       me.setFocus(me, ff);
-                                       return 1;
-                               }
-                       }
-                       if(!f || me.isTabRoot)
-                       {
-                               for(ff = me.firstChild; ff; ff = ff.nextSibling)
-                               {
-                                       if (!ff.focusable)
-                                               continue;
-                                       me.setFocus(me, ff);
-                                       return 1;
-                               }
-                               return 0; // AIIIIEEEEE!
-                       }
-               }
-       }
-       return 0;
-}
-
-float InputContainer__changeFocusXY(entity me, vector pos)
-{
-       entity e, ne;
-       e = me.mouseFocusedChild;
-       ne = me.itemFromPoint(me, pos);
-       if(ne)
-               if (!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 InputContainer_mouseDrag(entity me, vector pos)
-{
-       if(SUPER(InputContainer).mouseDrag(me, pos))
-               return 1;
-       if(pos_x >= 0 && pos_y >= 0 && pos_x < 1 && pos_y < 1)
-               return 1;
-       return 0;
-}
-float InputContainer_mouseMove(entity me, vector pos)
-{
-       if(me.mouseFocusedChild != me.focusedChild) // if the keyboard moved the focus away
-               me.mouseFocusedChild = NULL; // force focusing
-       if(me._changeFocusXY(me, pos))
-               if(SUPER(InputContainer).mouseMove(me, pos))
-                       return 1;
-       if(pos_x >= 0 && pos_y >= 0 && pos_x < 1 && pos_y < 1)
-               return 1;
-       return 0;
-}
-float InputContainer_mousePress(entity me, vector pos)
-{
-       me.mouseFocusedChild = NULL; // force focusing
-       if(me._changeFocusXY(me, pos))
-               if(SUPER(InputContainer).mousePress(me, pos))
-                       return 1;
-       if(pos_x >= 0 && pos_y >= 0 && pos_x < 1 && pos_y < 1)
-               return 1;
-       return 0;
-}
-float InputContainer_mouseRelease(entity me, vector pos)
-{
-       SUPER(InputContainer).mouseRelease(me, pos); // return value?
-       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
diff --git a/qcsrc/menu/item/inputcontainer.qc b/qcsrc/menu/item/inputcontainer.qc
new file mode 100644 (file)
index 0000000..0f80c2b
--- /dev/null
@@ -0,0 +1,166 @@
+#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 InputContainer_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(InputContainer).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+       /*
+       if(me.parent.instanceOfInputContainer)
+               me.isTabRoot = 0;
+       else
+               me.isTabRoot = 1;
+       */
+}
+
+void InputContainer_focusLeave(entity me)
+{
+       SUPER(InputContainer).focusLeave(me);
+       me.mouseFocusedChild = NULL;
+}
+
+float InputContainer_keyDown(entity me, float scan, float ascii, float shift)
+{
+       entity f, ff;
+       if(SUPER(InputContainer).keyDown(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 (!ff.focusable)
+                                               continue;
+                                       me.setFocus(me, ff);
+                                       return 1;
+                               }
+                       }
+                       if(!f || me.isTabRoot)
+                       {
+                               for(ff = me.lastChild; ff; ff = ff.prevSibling)
+                               {
+                                       if (!ff.focusable)
+                                               continue;
+                                       me.setFocus(me, ff);
+                                       return 1;
+                               }
+                               return 0; // AIIIIEEEEE!
+                       }
+               }
+               else
+               {
+                       if(f)
+                       {
+                               for(ff = f.nextSibling; ff; ff = ff.nextSibling)
+                               {
+                                       if (!ff.focusable)
+                                               continue;
+                                       me.setFocus(me, ff);
+                                       return 1;
+                               }
+                       }
+                       if(!f || me.isTabRoot)
+                       {
+                               for(ff = me.firstChild; ff; ff = ff.nextSibling)
+                               {
+                                       if (!ff.focusable)
+                                               continue;
+                                       me.setFocus(me, ff);
+                                       return 1;
+                               }
+                               return 0; // AIIIIEEEEE!
+                       }
+               }
+       }
+       return 0;
+}
+
+float InputContainer__changeFocusXY(entity me, vector pos)
+{
+       entity e, ne;
+       e = me.mouseFocusedChild;
+       ne = me.itemFromPoint(me, pos);
+       if(ne)
+               if (!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 InputContainer_mouseDrag(entity me, vector pos)
+{
+       if(SUPER(InputContainer).mouseDrag(me, pos))
+               return 1;
+       if(pos_x >= 0 && pos_y >= 0 && pos_x < 1 && pos_y < 1)
+               return 1;
+       return 0;
+}
+float InputContainer_mouseMove(entity me, vector pos)
+{
+       if(me.mouseFocusedChild != me.focusedChild) // if the keyboard moved the focus away
+               me.mouseFocusedChild = NULL; // force focusing
+       if(me._changeFocusXY(me, pos))
+               if(SUPER(InputContainer).mouseMove(me, pos))
+                       return 1;
+       if(pos_x >= 0 && pos_y >= 0 && pos_x < 1 && pos_y < 1)
+               return 1;
+       return 0;
+}
+float InputContainer_mousePress(entity me, vector pos)
+{
+       me.mouseFocusedChild = NULL; // force focusing
+       if(me._changeFocusXY(me, pos))
+               if(SUPER(InputContainer).mousePress(me, pos))
+                       return 1;
+       if(pos_x >= 0 && pos_y >= 0 && pos_x < 1 && pos_y < 1)
+               return 1;
+       return 0;
+}
+float InputContainer_mouseRelease(entity me, vector pos)
+{
+       SUPER(InputContainer).mouseRelease(me, pos); // return value?
+       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
diff --git a/qcsrc/menu/item/label.c b/qcsrc/menu/item/label.c
deleted file mode 100644 (file)
index 592c3a7..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-#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))
-       METHOD(Label, recalcPositionWithText, void(entity, string))
-       ATTRIB(Label, isBold, float, 0)
-       ATTRIB(Label, text, string, string_null)
-       ATTRIB(Label, currentText, string, string_null)
-       ATTRIB(Label, fontSize, float, 8)
-       ATTRIB(Label, align, float, 0.5)
-       ATTRIB(Label, allowCut, float, 0)
-       ATTRIB(Label, allowColors, float, 0)
-       ATTRIB(Label, keepspaceLeft, float, 0) // for use by subclasses (radiobuttons for example)
-       ATTRIB(Label, keepspaceRight, float, 0)
-       ATTRIB(Label, marginLeft, float, 0) // alternate way to specify keepspace* (in characters from the font)
-       ATTRIB(Label, marginRight, 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, SKINCOLOR_TEXT)
-       ATTRIB(Label, disabled, float, 0)
-       ATTRIB(Label, disabledAlpha, float, 0.3)
-       ATTRIB(Label, textEntity, entity, NULL)
-       ATTRIB(Label, allowWrap, float, 0)
-       ATTRIB(Label, recalcPos, float, 0)
-       ATTRIB(Label, condenseFactor, float, 1)
-       ATTRIB(Label, overrideRealOrigin, vector, '0 0 0')
-       ATTRIB(Label, overrideCondenseFactor, float, 0)
-ENDCLASS(Label)
-#endif
-
-#ifdef IMPLEMENTATION
-string Label_toString(entity me)
-{
-       return me.text;
-}
-void Label_setText(entity me, string txt)
-{
-       me.text = txt;
-       if(txt != me.currentText)
-       {
-               if(me.currentText)
-                       strunzone(me.currentText);
-               me.currentText = strzone(txt);
-               me.recalcPos = 1;
-       }
-}
-void Label_recalcPositionWithText(entity me, string t)
-{
-       float spaceAvail;
-       spaceAvail = 1 - me.keepspaceLeft - me.keepspaceRight;
-
-       if(me.isBold)
-               draw_beginBoldFont();
-
-       float spaceUsed;
-       spaceUsed = draw_TextWidth(t, me.allowColors, me.realFontSize);
-
-       if(spaceUsed <= spaceAvail)
-       {
-               if(!me.overrideRealOrigin_x)
-                       me.realOrigin_x = me.align * (spaceAvail - spaceUsed) + me.keepspaceLeft;
-               if(!me.overrideCondenseFactor)
-                       me.condenseFactor = 1;
-       }
-       else if(me.allowCut || me.allowWrap)
-       {
-               if(!me.overrideRealOrigin_x)
-                       me.realOrigin_x = me.keepspaceLeft;
-               if(!me.overrideCondenseFactor)
-                       me.condenseFactor = 1;
-       }
-       else
-       {
-               if(!me.overrideRealOrigin_x)
-                       me.realOrigin_x = me.keepspaceLeft;
-               if(!me.overrideCondenseFactor)
-                       me.condenseFactor = spaceAvail / spaceUsed;
-               dprintf("NOTE: label text %s too wide for label, condensed by factor %f\n", t, me.condenseFactor);
-       }
-
-       if(!me.overrideRealOrigin_y)
-       {
-               float lines;
-               vector dfs;
-               vector fs;
-
-               // set up variables to draw in condensed size, but use hinting for original size
-               fs = me.realFontSize;
-               fs_x *= me.condenseFactor;
-
-               dfs = draw_fontscale;
-               draw_fontscale_x *= me.condenseFactor;
-
-               if(me.allowCut) // FIXME allowCut incompatible with align != 0
-                       lines = 1;
-               else if(me.allowWrap) // FIXME allowWrap incompatible with align != 0
-               {
-                       getWrappedLine_remaining = me.text;
-                       lines = 0;
-                       while(getWrappedLine_remaining)
-                       {
-                               if (me.allowColors)
-                                       getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
-                               else
-                                       getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
-                               ++lines;
-                       }
-               }
-               else
-                       lines = 1;
-
-               draw_fontscale = dfs;
-
-               me.realOrigin_y = 0.5 * (1 - lines * me.realFontSize_y);
-       }
-
-       if(me.isBold)
-               draw_endBoldFont();
-
-       me.recalcPos = 0;
-}
-void Label_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(Label).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-
-       // absSize_y is height of label
-       me.realFontSize_y = me.fontSize / absSize_y;
-       me.realFontSize_x = me.fontSize / absSize_x;
-       if(me.marginLeft)
-               me.keepspaceLeft = me.marginLeft * me.realFontSize_x;
-       if(me.marginRight)
-               me.keepspaceRight = me.marginRight * me.realFontSize_x;
-
-       me.recalcPos = 1;
-}
-void Label_configureLabel(entity me, string txt, float sz, float algn)
-{
-       me.fontSize = sz;
-       me.align = algn;
-       me.setText(me, txt);
-}
-void Label_draw(entity me)
-{
-       string t;
-       vector o;
-       if(me.disabled)
-               draw_alpha *= me.disabledAlpha;
-
-       if(me.textEntity)
-       {
-               t = me.textEntity.toString(me.textEntity);
-               if(t != me.currentText)
-               {
-                       if(me.currentText)
-                               strunzone(me.currentText);
-                       me.currentText = strzone(t);
-                       me.recalcPos = 1;
-               }
-       }
-       else
-               t = me.text;
-
-       if(me.recalcPos)
-               me.recalcPositionWithText(me, t);
-
-       if(me.fontSize)
-               if(t)
-               {
-                       vector dfs;
-                       vector fs;
-
-                       if(me.isBold)
-                               draw_beginBoldFont();
-
-                       // set up variables to draw in condensed size, but use hinting for original size
-                       fs = me.realFontSize;
-                       fs_x *= me.condenseFactor;
-
-                       dfs = draw_fontscale;
-                       draw_fontscale_x *= me.condenseFactor;
-
-                       if(me.allowCut) // FIXME allowCut incompatible with align != 0
-                               draw_Text(me.realOrigin, draw_TextShortenToWidth(t, (1 - me.keepspaceLeft - me.keepspaceRight), me.allowColors, fs), fs, me.colorL, me.alpha, me.allowColors);
-                       else if(me.allowWrap) // FIXME allowWrap incompatible with align != 0
-                       {
-                               getWrappedLine_remaining = t;
-                               o = me.realOrigin;
-                               while(getWrappedLine_remaining)
-                               {
-                                       if (me.allowColors)
-                                               t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
-                                       else
-                                               t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
-                                       draw_Text(o, t, fs, me.colorL, me.alpha, me.allowColors);
-                                       o_y += me.realFontSize_y;
-                               }
-                       }
-                       else
-                               draw_Text(me.realOrigin, t, fs, me.colorL, me.alpha, me.allowColors);
-
-                       draw_fontscale = dfs;
-
-                       if(me.isBold)
-                               draw_endBoldFont();
-               }
-
-       SUPER(Label).draw(me);
-}
-#endif
diff --git a/qcsrc/menu/item/label.qc b/qcsrc/menu/item/label.qc
new file mode 100644 (file)
index 0000000..592c3a7
--- /dev/null
@@ -0,0 +1,213 @@
+#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))
+       METHOD(Label, recalcPositionWithText, void(entity, string))
+       ATTRIB(Label, isBold, float, 0)
+       ATTRIB(Label, text, string, string_null)
+       ATTRIB(Label, currentText, string, string_null)
+       ATTRIB(Label, fontSize, float, 8)
+       ATTRIB(Label, align, float, 0.5)
+       ATTRIB(Label, allowCut, float, 0)
+       ATTRIB(Label, allowColors, float, 0)
+       ATTRIB(Label, keepspaceLeft, float, 0) // for use by subclasses (radiobuttons for example)
+       ATTRIB(Label, keepspaceRight, float, 0)
+       ATTRIB(Label, marginLeft, float, 0) // alternate way to specify keepspace* (in characters from the font)
+       ATTRIB(Label, marginRight, 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, SKINCOLOR_TEXT)
+       ATTRIB(Label, disabled, float, 0)
+       ATTRIB(Label, disabledAlpha, float, 0.3)
+       ATTRIB(Label, textEntity, entity, NULL)
+       ATTRIB(Label, allowWrap, float, 0)
+       ATTRIB(Label, recalcPos, float, 0)
+       ATTRIB(Label, condenseFactor, float, 1)
+       ATTRIB(Label, overrideRealOrigin, vector, '0 0 0')
+       ATTRIB(Label, overrideCondenseFactor, float, 0)
+ENDCLASS(Label)
+#endif
+
+#ifdef IMPLEMENTATION
+string Label_toString(entity me)
+{
+       return me.text;
+}
+void Label_setText(entity me, string txt)
+{
+       me.text = txt;
+       if(txt != me.currentText)
+       {
+               if(me.currentText)
+                       strunzone(me.currentText);
+               me.currentText = strzone(txt);
+               me.recalcPos = 1;
+       }
+}
+void Label_recalcPositionWithText(entity me, string t)
+{
+       float spaceAvail;
+       spaceAvail = 1 - me.keepspaceLeft - me.keepspaceRight;
+
+       if(me.isBold)
+               draw_beginBoldFont();
+
+       float spaceUsed;
+       spaceUsed = draw_TextWidth(t, me.allowColors, me.realFontSize);
+
+       if(spaceUsed <= spaceAvail)
+       {
+               if(!me.overrideRealOrigin_x)
+                       me.realOrigin_x = me.align * (spaceAvail - spaceUsed) + me.keepspaceLeft;
+               if(!me.overrideCondenseFactor)
+                       me.condenseFactor = 1;
+       }
+       else if(me.allowCut || me.allowWrap)
+       {
+               if(!me.overrideRealOrigin_x)
+                       me.realOrigin_x = me.keepspaceLeft;
+               if(!me.overrideCondenseFactor)
+                       me.condenseFactor = 1;
+       }
+       else
+       {
+               if(!me.overrideRealOrigin_x)
+                       me.realOrigin_x = me.keepspaceLeft;
+               if(!me.overrideCondenseFactor)
+                       me.condenseFactor = spaceAvail / spaceUsed;
+               dprintf("NOTE: label text %s too wide for label, condensed by factor %f\n", t, me.condenseFactor);
+       }
+
+       if(!me.overrideRealOrigin_y)
+       {
+               float lines;
+               vector dfs;
+               vector fs;
+
+               // set up variables to draw in condensed size, but use hinting for original size
+               fs = me.realFontSize;
+               fs_x *= me.condenseFactor;
+
+               dfs = draw_fontscale;
+               draw_fontscale_x *= me.condenseFactor;
+
+               if(me.allowCut) // FIXME allowCut incompatible with align != 0
+                       lines = 1;
+               else if(me.allowWrap) // FIXME allowWrap incompatible with align != 0
+               {
+                       getWrappedLine_remaining = me.text;
+                       lines = 0;
+                       while(getWrappedLine_remaining)
+                       {
+                               if (me.allowColors)
+                                       getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
+                               else
+                                       getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
+                               ++lines;
+                       }
+               }
+               else
+                       lines = 1;
+
+               draw_fontscale = dfs;
+
+               me.realOrigin_y = 0.5 * (1 - lines * me.realFontSize_y);
+       }
+
+       if(me.isBold)
+               draw_endBoldFont();
+
+       me.recalcPos = 0;
+}
+void Label_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(Label).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+
+       // absSize_y is height of label
+       me.realFontSize_y = me.fontSize / absSize_y;
+       me.realFontSize_x = me.fontSize / absSize_x;
+       if(me.marginLeft)
+               me.keepspaceLeft = me.marginLeft * me.realFontSize_x;
+       if(me.marginRight)
+               me.keepspaceRight = me.marginRight * me.realFontSize_x;
+
+       me.recalcPos = 1;
+}
+void Label_configureLabel(entity me, string txt, float sz, float algn)
+{
+       me.fontSize = sz;
+       me.align = algn;
+       me.setText(me, txt);
+}
+void Label_draw(entity me)
+{
+       string t;
+       vector o;
+       if(me.disabled)
+               draw_alpha *= me.disabledAlpha;
+
+       if(me.textEntity)
+       {
+               t = me.textEntity.toString(me.textEntity);
+               if(t != me.currentText)
+               {
+                       if(me.currentText)
+                               strunzone(me.currentText);
+                       me.currentText = strzone(t);
+                       me.recalcPos = 1;
+               }
+       }
+       else
+               t = me.text;
+
+       if(me.recalcPos)
+               me.recalcPositionWithText(me, t);
+
+       if(me.fontSize)
+               if(t)
+               {
+                       vector dfs;
+                       vector fs;
+
+                       if(me.isBold)
+                               draw_beginBoldFont();
+
+                       // set up variables to draw in condensed size, but use hinting for original size
+                       fs = me.realFontSize;
+                       fs_x *= me.condenseFactor;
+
+                       dfs = draw_fontscale;
+                       draw_fontscale_x *= me.condenseFactor;
+
+                       if(me.allowCut) // FIXME allowCut incompatible with align != 0
+                               draw_Text(me.realOrigin, draw_TextShortenToWidth(t, (1 - me.keepspaceLeft - me.keepspaceRight), me.allowColors, fs), fs, me.colorL, me.alpha, me.allowColors);
+                       else if(me.allowWrap) // FIXME allowWrap incompatible with align != 0
+                       {
+                               getWrappedLine_remaining = t;
+                               o = me.realOrigin;
+                               while(getWrappedLine_remaining)
+                               {
+                                       if (me.allowColors)
+                                               t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
+                                       else
+                                               t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
+                                       draw_Text(o, t, fs, me.colorL, me.alpha, me.allowColors);
+                                       o_y += me.realFontSize_y;
+                               }
+                       }
+                       else
+                               draw_Text(me.realOrigin, t, fs, me.colorL, me.alpha, me.allowColors);
+
+                       draw_fontscale = dfs;
+
+                       if(me.isBold)
+                               draw_endBoldFont();
+               }
+
+       SUPER(Label).draw(me);
+}
+#endif
diff --git a/qcsrc/menu/item/listbox.c b/qcsrc/menu/item/listbox.c
deleted file mode 100644 (file)
index 275b997..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-#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))
-       METHOD(ListBox, focusLeave, void(entity))
-       ATTRIB(ListBox, focusable, float, 1)
-       ATTRIB(ListBox, selectedItem, float, 0)
-       ATTRIB(ListBox, size, vector, '0 0 0')
-       ATTRIB(ListBox, origin, 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)
-       ATTRIB(ListBox, colorBG, vector, '0 0 0')
-       ATTRIB(ListBox, alphaBG, float, 0)
-
-       ATTRIB(ListBox, lastClickedItem, float, -1)
-       ATTRIB(ListBox, lastClickedTime, 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, doubleClickListBoxItem, void(entity, float, vector)) // item number, relative clickpos
-       METHOD(ListBox, setSelected, void(entity, float))
-
-       METHOD(ListBox, getLastFullyVisibleItemAtScrollPos, float(entity, float))
-       METHOD(ListBox, getFirstFullyVisibleItemAtScrollPos, float(entity, float))
-
-       // NOTE: override these four methods if you want variable sized list items
-       METHOD(ListBox, getTotalHeight, float(entity))
-       METHOD(ListBox, getItemAtPos, float(entity, float))
-       METHOD(ListBox, getItemStart, float(entity, float))
-       METHOD(ListBox, getItemHeight, float(entity, float))
-       // NOTE: if getItemAt* are overridden, it may make sense to cache the
-       // start and height of the last item returned by getItemAtPos and fast
-       // track returning their properties for getItemStart and getItemHeight.
-       // The "hot" code path calls getItemAtPos first, then will query
-       // getItemStart and getItemHeight on it soon.
-       // When overriding, the following consistency rules must hold:
-       // getTotalHeight() == SUM(getItemHeight(i), i, 0, me.nItems-1)
-       // getItemStart(i+1) == getItemStart(i) + getItemHeight(i)
-       //   for 0 <= i < me.nItems-1
-       // getItemStart(0) == 0
-       // getItemStart(getItemAtPos(p)) <= p
-       //   if p >= 0
-       // getItemAtPos(p) == 0
-       //   if p < 0
-       // getItemStart(getItemAtPos(p)) + getItemHeight(getItemAtPos(p)) > p
-       //   if p < getTotalHeigt()
-       // getItemAtPos(p) == me.nItems - 1
-       //   if p >= getTotalHeight()
-ENDCLASS(ListBox)
-#endif
-
-#ifdef IMPLEMENTATION
-void ListBox_setSelected(entity me, float i)
-{
-       me.selectedItem = bound(0, i, me.nItems - 1);
-}
-void ListBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(ListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       me.controlWidth = me.scrollbarWidth / absSize_x;
-}
-void ListBox_configureListBox(entity me, float theScrollbarWidth, float theItemHeight)
-{
-       me.scrollbarWidth = theScrollbarWidth;
-       me.itemHeight = theItemHeight;
-}
-
-float ListBox_getTotalHeight(entity me)
-{
-       return me.nItems * me.itemHeight;
-}
-float ListBox_getItemAtPos(entity me, float pos)
-{
-       return floor(pos / me.itemHeight);
-}
-float ListBox_getItemStart(entity me, float i)
-{
-       return me.itemHeight * i;
-}
-float ListBox_getItemHeight(entity me, float i)
-{
-       return me.itemHeight;
-}
-
-float ListBox_getLastFullyVisibleItemAtScrollPos(entity me, float pos)
-{
-       return me.getItemAtPos(me, pos + 1.001) - 1;
-}
-float ListBox_getFirstFullyVisibleItemAtScrollPos(entity me, float pos)
-{
-       return me.getItemAtPos(me, pos - 0.001) + 1;
-}
-float ListBox_keyDown(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, me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos)));
-       }
-       else if(key == K_MWHEELDOWN)
-       {
-               me.scrollPos = min(me.scrollPos + 0.5, me.getTotalHeight(me) - 1);
-               me.setSelected(me, max(me.selectedItem, me.getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos)));
-       }
-       else if(key == K_PGUP || key == K_KP_PGUP)
-       {
-               float i = me.selectedItem;
-               float a = me.getItemHeight(me, i);
-               for(;;)
-               {
-                       --i;
-                       if (i < 0)
-                               break;
-                       a += me.getItemHeight(me, i);
-                       if (a >= 1)
-                               break;
-               }
-               me.setSelected(me, i + 1);
-       }
-       else if(key == K_PGDN || key == K_KP_PGDN)
-       {
-               float i = me.selectedItem;
-               float a = me.getItemHeight(me, i);
-               for(;;)
-               {
-                       ++i;
-                       if (i >= me.nItems)
-                               break;
-                       a += me.getItemHeight(me, i);
-                       if (a >= 1)
-                               break;
-               }
-               me.setSelected(me, i - 1);
-       }
-       else if(key == K_UPARROW || key == K_KP_UPARROW)
-               me.setSelected(me, me.selectedItem - 1);
-       else if(key == K_DOWNARROW || key == K_KP_DOWNARROW)
-               me.setSelected(me, me.selectedItem + 1);
-       else if(key == K_HOME || key == K_KP_HOME)
-       {
-               me.scrollPos = 0;
-               me.setSelected(me, 0);
-       }
-       else if(key == K_END || key == K_KP_END)
-       {
-               me.scrollPos = max(0, me.getTotalHeight(me) - 1);
-               me.setSelected(me, me.nItems - 1);
-       }
-       else
-               return 0;
-       return 1;
-}
-float ListBox_mouseDrag(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 d;
-                       d = (pos_y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.getTotalHeight(me) - 1);
-                       me.scrollPos = me.previousValue + d;
-               }
-               else
-                       me.scrollPos = me.previousValue;
-               me.scrollPos = min(me.scrollPos, me.getTotalHeight(me) - 1);
-               me.scrollPos = max(me.scrollPos, 0);
-               i = min(me.selectedItem, me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos));
-               i = max(i, ListBox_getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos));
-               me.setSelected(me, i);
-       }
-       else if(me.pressed == 2)
-       {
-               me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos_y));
-       }
-       return 1;
-}
-float ListBox_mousePress(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, ListBox_getLastFullyVisibleItemAtScrollPos(me, me.scrollPos)));
-               }
-               else if(pos_y > me.controlBottom)
-               {
-                       // page down
-                       me.scrollPos = min(me.scrollPos + 1, me.getTotalHeight(me) - 1);
-                       me.setSelected(me, max(me.selectedItem, ListBox_getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos)));
-               }
-               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, me.getItemAtPos(me, me.scrollPos + pos_y));
-       }
-       return 1;
-}
-float ListBox_mouseRelease(entity me, vector pos)
-{
-       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, me.getItemAtPos(me, me.scrollPos + pos_y));
-               // and give it a nice click event
-               if(me.nItems > 0)
-               {
-                       vector where = globalToBox(pos, eY * (me.getItemStart(me, me.selectedItem) - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, me.selectedItem));
-
-                       if((me.selectedItem == me.lastClickedItem) && (time < me.lastClickedTime + 0.3))
-                               me.doubleClickListBoxItem(me, me.selectedItem, where);
-                       else
-                               me.clickListBoxItem(me, me.selectedItem, where);
-
-                       me.lastClickedItem = me.selectedItem;
-                       me.lastClickedTime = time;
-               }
-       }
-       me.pressed = 0;
-       return 1;
-}
-void ListBox_focusLeave(entity me)
-{
-       // Reset the var pressed in case listbox loses focus
-       // by a mouse click on an item of the list
-       // for example showing a dialog on right click
-       me.pressed = 0;
-}
-void ListBox_updateControlTopBottom(entity me)
-{
-       float f;
-       // scrollPos is in 0..1 and indicates where the "page" currently shown starts.
-       if(me.getTotalHeight(me) <= 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.getItemStart(me, me.selectedItem) + me.getItemHeight(me, me.selectedItem) - 1);
-                               // if selected item is above listbox, decrease scrollpos so it is in
-                               me.scrollPos = min(me.scrollPos, me.getItemStart(me, me.selectedItem));
-                               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.getTotalHeight(me) - 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.getTotalHeight(me));
-               me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
-
-               float minfactor;
-               minfactor = 2 * me.controlWidth / me.size_y * me.size_x;
-               f = me.controlBottom - me.controlTop;
-               if(f < minfactor) // FIXME good default?
-               {
-                       // f * X + 1 * (1-X) = minfactor
-                       // (f - 1) * X + 1 = minfactor
-                       // (f - 1) * X = minfactor - 1
-                       // X = (minfactor - 1) / (f - 1)
-                       f = (minfactor - 1) / (f - 1);
-                       me.controlTop = me.controlTop * f + 0 * (1 - f);
-                       me.controlBottom = me.controlBottom * f + 1 * (1 - f);
-               }
-       }
-}
-void ListBox_draw(entity me)
-{
-       float i;
-       vector absSize, fillSize = '0 0 0';
-       vector oldshift, oldscale;
-       if(me.pressed == 2)
-               me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
-       me.updateControlTopBottom(me);
-       fillSize_x = (1 - me.controlWidth);
-       if(me.alphaBG)
-               draw_Fill('0 0 0', '0 1 0' + fillSize, me.colorBG, me.alphaBG);
-       if(me.controlWidth)
-       {
-               draw_VertButtonPicture(eX * (1 - me.controlWidth), strcat(me.src, "_s"), eX * me.controlWidth + eY, me.color2, 1);
-               if(me.getTotalHeight(me) > 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;
-       float y;
-       i = me.getItemAtPos(me, me.scrollPos);
-       y = me.getItemStart(me, i) - me.scrollPos;
-       for(; i < me.nItems && y < 1; ++i)
-       {
-               draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
-               vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
-               absSize = boxToGlobalSize(relSize, me.size);
-               draw_scale = boxToGlobalSize(relSize, oldscale);
-               me.drawListBoxItem(me, i, absSize, (me.selectedItem == i));
-               y += relSize_y;
-       }
-       draw_ClearClip();
-
-       draw_shift = oldshift;
-       draw_scale = oldscale;
-       SUPER(ListBox).draw(me);
-}
-
-void ListBox_clickListBoxItem(entity me, float i, vector where)
-{
-       // template method
-}
-
-void ListBox_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       // template method
-}
-
-void ListBox_drawListBoxItem(entity me, float i, vector absSize, float selected)
-{
-       draw_Text('0 0 0', sprintf(_("Item %d"), i), eX * (8 / absSize_x) + eY * (8 / absSize_y), (selected ? '0 1 0' : '1 1 1'), 1, 0);
-}
-#endif
diff --git a/qcsrc/menu/item/listbox.qc b/qcsrc/menu/item/listbox.qc
new file mode 100644 (file)
index 0000000..275b997
--- /dev/null
@@ -0,0 +1,402 @@
+#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))
+       METHOD(ListBox, focusLeave, void(entity))
+       ATTRIB(ListBox, focusable, float, 1)
+       ATTRIB(ListBox, selectedItem, float, 0)
+       ATTRIB(ListBox, size, vector, '0 0 0')
+       ATTRIB(ListBox, origin, 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)
+       ATTRIB(ListBox, colorBG, vector, '0 0 0')
+       ATTRIB(ListBox, alphaBG, float, 0)
+
+       ATTRIB(ListBox, lastClickedItem, float, -1)
+       ATTRIB(ListBox, lastClickedTime, 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, doubleClickListBoxItem, void(entity, float, vector)) // item number, relative clickpos
+       METHOD(ListBox, setSelected, void(entity, float))
+
+       METHOD(ListBox, getLastFullyVisibleItemAtScrollPos, float(entity, float))
+       METHOD(ListBox, getFirstFullyVisibleItemAtScrollPos, float(entity, float))
+
+       // NOTE: override these four methods if you want variable sized list items
+       METHOD(ListBox, getTotalHeight, float(entity))
+       METHOD(ListBox, getItemAtPos, float(entity, float))
+       METHOD(ListBox, getItemStart, float(entity, float))
+       METHOD(ListBox, getItemHeight, float(entity, float))
+       // NOTE: if getItemAt* are overridden, it may make sense to cache the
+       // start and height of the last item returned by getItemAtPos and fast
+       // track returning their properties for getItemStart and getItemHeight.
+       // The "hot" code path calls getItemAtPos first, then will query
+       // getItemStart and getItemHeight on it soon.
+       // When overriding, the following consistency rules must hold:
+       // getTotalHeight() == SUM(getItemHeight(i), i, 0, me.nItems-1)
+       // getItemStart(i+1) == getItemStart(i) + getItemHeight(i)
+       //   for 0 <= i < me.nItems-1
+       // getItemStart(0) == 0
+       // getItemStart(getItemAtPos(p)) <= p
+       //   if p >= 0
+       // getItemAtPos(p) == 0
+       //   if p < 0
+       // getItemStart(getItemAtPos(p)) + getItemHeight(getItemAtPos(p)) > p
+       //   if p < getTotalHeigt()
+       // getItemAtPos(p) == me.nItems - 1
+       //   if p >= getTotalHeight()
+ENDCLASS(ListBox)
+#endif
+
+#ifdef IMPLEMENTATION
+void ListBox_setSelected(entity me, float i)
+{
+       me.selectedItem = bound(0, i, me.nItems - 1);
+}
+void ListBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(ListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+       me.controlWidth = me.scrollbarWidth / absSize_x;
+}
+void ListBox_configureListBox(entity me, float theScrollbarWidth, float theItemHeight)
+{
+       me.scrollbarWidth = theScrollbarWidth;
+       me.itemHeight = theItemHeight;
+}
+
+float ListBox_getTotalHeight(entity me)
+{
+       return me.nItems * me.itemHeight;
+}
+float ListBox_getItemAtPos(entity me, float pos)
+{
+       return floor(pos / me.itemHeight);
+}
+float ListBox_getItemStart(entity me, float i)
+{
+       return me.itemHeight * i;
+}
+float ListBox_getItemHeight(entity me, float i)
+{
+       return me.itemHeight;
+}
+
+float ListBox_getLastFullyVisibleItemAtScrollPos(entity me, float pos)
+{
+       return me.getItemAtPos(me, pos + 1.001) - 1;
+}
+float ListBox_getFirstFullyVisibleItemAtScrollPos(entity me, float pos)
+{
+       return me.getItemAtPos(me, pos - 0.001) + 1;
+}
+float ListBox_keyDown(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, me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos)));
+       }
+       else if(key == K_MWHEELDOWN)
+       {
+               me.scrollPos = min(me.scrollPos + 0.5, me.getTotalHeight(me) - 1);
+               me.setSelected(me, max(me.selectedItem, me.getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos)));
+       }
+       else if(key == K_PGUP || key == K_KP_PGUP)
+       {
+               float i = me.selectedItem;
+               float a = me.getItemHeight(me, i);
+               for(;;)
+               {
+                       --i;
+                       if (i < 0)
+                               break;
+                       a += me.getItemHeight(me, i);
+                       if (a >= 1)
+                               break;
+               }
+               me.setSelected(me, i + 1);
+       }
+       else if(key == K_PGDN || key == K_KP_PGDN)
+       {
+               float i = me.selectedItem;
+               float a = me.getItemHeight(me, i);
+               for(;;)
+               {
+                       ++i;
+                       if (i >= me.nItems)
+                               break;
+                       a += me.getItemHeight(me, i);
+                       if (a >= 1)
+                               break;
+               }
+               me.setSelected(me, i - 1);
+       }
+       else if(key == K_UPARROW || key == K_KP_UPARROW)
+               me.setSelected(me, me.selectedItem - 1);
+       else if(key == K_DOWNARROW || key == K_KP_DOWNARROW)
+               me.setSelected(me, me.selectedItem + 1);
+       else if(key == K_HOME || key == K_KP_HOME)
+       {
+               me.scrollPos = 0;
+               me.setSelected(me, 0);
+       }
+       else if(key == K_END || key == K_KP_END)
+       {
+               me.scrollPos = max(0, me.getTotalHeight(me) - 1);
+               me.setSelected(me, me.nItems - 1);
+       }
+       else
+               return 0;
+       return 1;
+}
+float ListBox_mouseDrag(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 d;
+                       d = (pos_y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.getTotalHeight(me) - 1);
+                       me.scrollPos = me.previousValue + d;
+               }
+               else
+                       me.scrollPos = me.previousValue;
+               me.scrollPos = min(me.scrollPos, me.getTotalHeight(me) - 1);
+               me.scrollPos = max(me.scrollPos, 0);
+               i = min(me.selectedItem, me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos));
+               i = max(i, ListBox_getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos));
+               me.setSelected(me, i);
+       }
+       else if(me.pressed == 2)
+       {
+               me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos_y));
+       }
+       return 1;
+}
+float ListBox_mousePress(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, ListBox_getLastFullyVisibleItemAtScrollPos(me, me.scrollPos)));
+               }
+               else if(pos_y > me.controlBottom)
+               {
+                       // page down
+                       me.scrollPos = min(me.scrollPos + 1, me.getTotalHeight(me) - 1);
+                       me.setSelected(me, max(me.selectedItem, ListBox_getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos)));
+               }
+               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, me.getItemAtPos(me, me.scrollPos + pos_y));
+       }
+       return 1;
+}
+float ListBox_mouseRelease(entity me, vector pos)
+{
+       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, me.getItemAtPos(me, me.scrollPos + pos_y));
+               // and give it a nice click event
+               if(me.nItems > 0)
+               {
+                       vector where = globalToBox(pos, eY * (me.getItemStart(me, me.selectedItem) - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, me.selectedItem));
+
+                       if((me.selectedItem == me.lastClickedItem) && (time < me.lastClickedTime + 0.3))
+                               me.doubleClickListBoxItem(me, me.selectedItem, where);
+                       else
+                               me.clickListBoxItem(me, me.selectedItem, where);
+
+                       me.lastClickedItem = me.selectedItem;
+                       me.lastClickedTime = time;
+               }
+       }
+       me.pressed = 0;
+       return 1;
+}
+void ListBox_focusLeave(entity me)
+{
+       // Reset the var pressed in case listbox loses focus
+       // by a mouse click on an item of the list
+       // for example showing a dialog on right click
+       me.pressed = 0;
+}
+void ListBox_updateControlTopBottom(entity me)
+{
+       float f;
+       // scrollPos is in 0..1 and indicates where the "page" currently shown starts.
+       if(me.getTotalHeight(me) <= 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.getItemStart(me, me.selectedItem) + me.getItemHeight(me, me.selectedItem) - 1);
+                               // if selected item is above listbox, decrease scrollpos so it is in
+                               me.scrollPos = min(me.scrollPos, me.getItemStart(me, me.selectedItem));
+                               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.getTotalHeight(me) - 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.getTotalHeight(me));
+               me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
+
+               float minfactor;
+               minfactor = 2 * me.controlWidth / me.size_y * me.size_x;
+               f = me.controlBottom - me.controlTop;
+               if(f < minfactor) // FIXME good default?
+               {
+                       // f * X + 1 * (1-X) = minfactor
+                       // (f - 1) * X + 1 = minfactor
+                       // (f - 1) * X = minfactor - 1
+                       // X = (minfactor - 1) / (f - 1)
+                       f = (minfactor - 1) / (f - 1);
+                       me.controlTop = me.controlTop * f + 0 * (1 - f);
+                       me.controlBottom = me.controlBottom * f + 1 * (1 - f);
+               }
+       }
+}
+void ListBox_draw(entity me)
+{
+       float i;
+       vector absSize, fillSize = '0 0 0';
+       vector oldshift, oldscale;
+       if(me.pressed == 2)
+               me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
+       me.updateControlTopBottom(me);
+       fillSize_x = (1 - me.controlWidth);
+       if(me.alphaBG)
+               draw_Fill('0 0 0', '0 1 0' + fillSize, me.colorBG, me.alphaBG);
+       if(me.controlWidth)
+       {
+               draw_VertButtonPicture(eX * (1 - me.controlWidth), strcat(me.src, "_s"), eX * me.controlWidth + eY, me.color2, 1);
+               if(me.getTotalHeight(me) > 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;
+       float y;
+       i = me.getItemAtPos(me, me.scrollPos);
+       y = me.getItemStart(me, i) - me.scrollPos;
+       for(; i < me.nItems && y < 1; ++i)
+       {
+               draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
+               vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
+               absSize = boxToGlobalSize(relSize, me.size);
+               draw_scale = boxToGlobalSize(relSize, oldscale);
+               me.drawListBoxItem(me, i, absSize, (me.selectedItem == i));
+               y += relSize_y;
+       }
+       draw_ClearClip();
+
+       draw_shift = oldshift;
+       draw_scale = oldscale;
+       SUPER(ListBox).draw(me);
+}
+
+void ListBox_clickListBoxItem(entity me, float i, vector where)
+{
+       // template method
+}
+
+void ListBox_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       // template method
+}
+
+void ListBox_drawListBoxItem(entity me, float i, vector absSize, float selected)
+{
+       draw_Text('0 0 0', sprintf(_("Item %d"), i), eX * (8 / absSize_x) + eY * (8 / absSize_y), (selected ? '0 1 0' : '1 1 1'), 1, 0);
+}
+#endif
diff --git a/qcsrc/menu/item/modalcontroller.c b/qcsrc/menu/item/modalcontroller.c
deleted file mode 100644 (file)
index 8a025cb..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-#ifdef INTERFACE
-CLASS(ModalController) EXTENDS(Container)
-       METHOD(ModalController, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(ModalController, draw, void(entity))
-       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)
-
-.entity tabSelectingButton;
-.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;
-.vector ModalController_initialFontScale;
-.float ModalController_initialAlpha;
-.vector ModalController_buttonSize;
-.vector ModalController_buttonOrigin;
-.float ModalController_state;
-.float ModalController_factor;
-.entity ModalController_controllingButton;
-
-void ModalController_initializeDialog(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;
-       if(tab.parent.focusedChild)
-               tab.parent.focusedChild.saveFocus(tab.parent.focusedChild);
-       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 ModalController_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, ModalController_initialOrigin, ModalController_initialSize, ModalController_initialFontScale);
-}
-
-void ModalController_switchState(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 ModalController_draw(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;
-       vector fs;
-       animating = 0;
-
-       front = world;
-       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)
-
-               fs = globalToBoxSize(e.Container_size, e.ModalController_initialSize);
-               e.Container_fontscale_x = fs_x * e.ModalController_initialFontScale_x;
-               e.Container_fontscale_y = fs_y * e.ModalController_initialFontScale_y;
-       }
-       if(animating || !me.focused)
-               me.setFocus(me, NULL);
-       else
-               me.setFocus(me, front);
-       SUPER(ModalController).draw(me);
-}
-
-void ModalController_addTab(entity me, entity other, entity tabButton)
-{
-       me.addItem(me, other, '0 0 0', '1 1 1', 1);
-       tabButton.onClick = TabButton_Click;
-       tabButton.onClickEntity = other;
-       other.tabSelectingButton = tabButton;
-       if(other == me.firstChild)
-       {
-               tabButton.forcePressed = 1;
-               other.ModalController_controllingButton = tabButton;
-               me.showChild(me, other, '0 0 0', '0 0 0', 1);
-       }
-}
-
-void ModalController_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
-{
-       SUPER(ModalController).addItem(me, other, theOrigin, theSize, (other == me.firstChild) ? theAlpha : 0);
-       other.ModalController_initialFontScale = other.Container_fontscale;
-       other.ModalController_initialSize = other.Container_size;
-       other.ModalController_initialOrigin = other.Container_origin;
-       other.ModalController_initialAlpha = theAlpha; // hope Container never modifies this
-       if(other.ModalController_initialFontScale == '0 0 0')
-               other.ModalController_initialFontScale = '1 1 0';
-}
-
-void ModalController_showChild(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 ModalController_hideAll(entity me, float skipAnimation)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
-               me.hideChild(me, e, skipAnimation);
-}
-
-void ModalController_hideChild(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
diff --git a/qcsrc/menu/item/modalcontroller.qc b/qcsrc/menu/item/modalcontroller.qc
new file mode 100644 (file)
index 0000000..8a025cb
--- /dev/null
@@ -0,0 +1,293 @@
+#ifdef INTERFACE
+CLASS(ModalController) EXTENDS(Container)
+       METHOD(ModalController, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(ModalController, draw, void(entity))
+       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)
+
+.entity tabSelectingButton;
+.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;
+.vector ModalController_initialFontScale;
+.float ModalController_initialAlpha;
+.vector ModalController_buttonSize;
+.vector ModalController_buttonOrigin;
+.float ModalController_state;
+.float ModalController_factor;
+.entity ModalController_controllingButton;
+
+void ModalController_initializeDialog(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;
+       if(tab.parent.focusedChild)
+               tab.parent.focusedChild.saveFocus(tab.parent.focusedChild);
+       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 ModalController_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, ModalController_initialOrigin, ModalController_initialSize, ModalController_initialFontScale);
+}
+
+void ModalController_switchState(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 ModalController_draw(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;
+       vector fs;
+       animating = 0;
+
+       front = world;
+       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)
+
+               fs = globalToBoxSize(e.Container_size, e.ModalController_initialSize);
+               e.Container_fontscale_x = fs_x * e.ModalController_initialFontScale_x;
+               e.Container_fontscale_y = fs_y * e.ModalController_initialFontScale_y;
+       }
+       if(animating || !me.focused)
+               me.setFocus(me, NULL);
+       else
+               me.setFocus(me, front);
+       SUPER(ModalController).draw(me);
+}
+
+void ModalController_addTab(entity me, entity other, entity tabButton)
+{
+       me.addItem(me, other, '0 0 0', '1 1 1', 1);
+       tabButton.onClick = TabButton_Click;
+       tabButton.onClickEntity = other;
+       other.tabSelectingButton = tabButton;
+       if(other == me.firstChild)
+       {
+               tabButton.forcePressed = 1;
+               other.ModalController_controllingButton = tabButton;
+               me.showChild(me, other, '0 0 0', '0 0 0', 1);
+       }
+}
+
+void ModalController_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
+{
+       SUPER(ModalController).addItem(me, other, theOrigin, theSize, (other == me.firstChild) ? theAlpha : 0);
+       other.ModalController_initialFontScale = other.Container_fontscale;
+       other.ModalController_initialSize = other.Container_size;
+       other.ModalController_initialOrigin = other.Container_origin;
+       other.ModalController_initialAlpha = theAlpha; // hope Container never modifies this
+       if(other.ModalController_initialFontScale == '0 0 0')
+               other.ModalController_initialFontScale = '1 1 0';
+}
+
+void ModalController_showChild(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 ModalController_hideAll(entity me, float skipAnimation)
+{
+       entity e;
+       for(e = me.firstChild; e; e = e.nextSibling)
+               me.hideChild(me, e, skipAnimation);
+}
+
+void ModalController_hideChild(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
diff --git a/qcsrc/menu/item/nexposee.c b/qcsrc/menu/item/nexposee.c
deleted file mode 100644 (file)
index ca7ab8f..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-#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_initialFontScale;
-.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 Nexposee_close(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 Nexposee_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.calc(me);
-       me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Nexposee_initialOrigin, Nexposee_initialSize, Nexposee_initialFontScale);
-}
-
-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 Nexposee_calc(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 Nexposee_setNexposee(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 Nexposee_draw(entity me)
-{
-       float a;
-       float a0;
-       entity e;
-       float f;
-       vector fs;
-
-       if(me.animationState == -1)
-       {
-               me.animationState = 0;
-       }
-
-       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;
-                               SUPER(Nexposee).setFocus(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);
-
-               fs = globalToBoxSize(e.Container_size, e.Nexposee_initialSize);
-               e.Container_fontscale_x = fs_x * e.Nexposee_initialFontScale_x;
-               e.Container_fontscale_y = fs_y * e.Nexposee_initialFontScale_y;
-       }
-
-       SUPER(Nexposee).draw(me);
-}
-
-float Nexposee_mousePress(entity me, vector pos)
-{
-       if(me.animationState == 0)
-       {
-               me.mouseFocusedChild = NULL;
-               Nexposee_mouseMove(me, pos);
-               if(me.mouseFocusedChild)
-               {
-                       me.animationState = 1;
-                       SUPER(Nexposee).setFocus(me, NULL);
-               }
-               else
-                       me.close(me);
-               return 1;
-       }
-       else if(me.animationState == 2)
-       {
-               if (!(SUPER(Nexposee).mousePress(me, pos)))
-               {
-                       me.animationState = 3;
-                       SUPER(Nexposee).setFocus(me, NULL);
-               }
-               return 1;
-       }
-       return 0;
-}
-
-float Nexposee_mouseRelease(entity me, vector pos)
-{
-       if(me.animationState == 2)
-               return SUPER(Nexposee).mouseRelease(me, pos);
-       return 0;
-}
-
-float Nexposee_mouseDrag(entity me, vector pos)
-{
-       if(me.animationState == 2)
-               return SUPER(Nexposee).mouseDrag(me, pos);
-       return 0;
-}
-
-float Nexposee_mouseMove(entity me, vector pos)
-{
-       entity e;
-       me.mousePosition = pos;
-       e = me.mouseFocusedChild;
-       me.mouseFocusedChild = me.itemFromPoint(me, pos);
-       if(me.animationState == 2)
-               return SUPER(Nexposee).mouseMove(me, pos);
-       if(me.animationState == 0)
-       {
-               if(me.mouseFocusedChild)
-                       if(me.mouseFocusedChild != e || me.mouseFocusedChild != me.selectedChild)
-                               me.selectedChild = me.mouseFocusedChild;
-               return 1;
-       }
-       return 0;
-}
-
-float Nexposee_keyUp(entity me, float scan, float ascii, float shift)
-{
-       if(me.animationState == 2)
-               return SUPER(Nexposee).keyUp(me, scan, ascii, shift);
-       return 0;
-}
-
-float Nexposee_keyDown(entity me, float scan, float ascii, float shift)
-{
-       float nexposeeKey = 0;
-       if(me.animationState == 2)
-               if(SUPER(Nexposee).keyDown(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 (!me.selectedChild)
-                                       me.selectedChild = me.lastChild;
-                       }
-                       else
-                       {
-                               if(me.selectedChild)
-                                       me.selectedChild = me.selectedChild.nextSibling;
-                               if (!me.selectedChild)
-                                       me.selectedChild = me.firstChild;
-                       }
-               }
-       }
-       switch(me.animationState)
-       {
-               default:
-               case 0:
-               case 3:
-                       nexposeeKey = ((scan == K_SPACE) || (scan == K_ENTER) || (scan == K_KP_ENTER));
-                       break;
-               case 1:
-               case 2:
-                       nexposeeKey = (scan == K_ESCAPE);
-                       break;
-       }
-       if(nexposeeKey)
-       {
-               switch(me.animationState)
-               {
-                       default:
-                       case 0:
-                       case 3:
-                               me.animationState = 1;
-                               break;
-                       case 1:
-                       case 2:
-                               me.animationState = 3;
-                               break;
-               }
-               if(me.focusedChild)
-                       me.selectedChild = me.focusedChild;
-               if (!me.selectedChild)
-                       me.animationState = 0;
-               SUPER(Nexposee).setFocus(me, NULL);
-               return 1;
-       }
-       return 0;
-}
-
-void Nexposee_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
-{
-       SUPER(Nexposee).addItem(me, other, theOrigin, theSize, theAlpha);
-       other.Nexposee_initialFontScale = other.Container_fontscale;
-       other.Nexposee_initialSize = other.Container_size;
-       other.Nexposee_initialOrigin = other.Container_origin;
-       other.Nexposee_initialAlpha = other.Container_alpha;
-       if(other.Nexposee_initialFontScale == '0 0 0')
-               other.Nexposee_initialFontScale = '1 1 0';
-}
-
-void Nexposee_focusEnter(entity me)
-{
-       if(me.animationState == 2)
-               SUPER(Nexposee).setFocus(me, me.selectedChild);
-}
-
-void Nexposee_pullNexposee(entity me, entity other, vector theAlign)
-{
-       other.Nexposee_align = theAlign;
-}
-#endif
diff --git a/qcsrc/menu/item/nexposee.qc b/qcsrc/menu/item/nexposee.qc
new file mode 100644 (file)
index 0000000..ca7ab8f
--- /dev/null
@@ -0,0 +1,363 @@
+#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_initialFontScale;
+.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 Nexposee_close(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 Nexposee_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.calc(me);
+       me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Nexposee_initialOrigin, Nexposee_initialSize, Nexposee_initialFontScale);
+}
+
+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 Nexposee_calc(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 Nexposee_setNexposee(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 Nexposee_draw(entity me)
+{
+       float a;
+       float a0;
+       entity e;
+       float f;
+       vector fs;
+
+       if(me.animationState == -1)
+       {
+               me.animationState = 0;
+       }
+
+       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;
+                               SUPER(Nexposee).setFocus(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);
+
+               fs = globalToBoxSize(e.Container_size, e.Nexposee_initialSize);
+               e.Container_fontscale_x = fs_x * e.Nexposee_initialFontScale_x;
+               e.Container_fontscale_y = fs_y * e.Nexposee_initialFontScale_y;
+       }
+
+       SUPER(Nexposee).draw(me);
+}
+
+float Nexposee_mousePress(entity me, vector pos)
+{
+       if(me.animationState == 0)
+       {
+               me.mouseFocusedChild = NULL;
+               Nexposee_mouseMove(me, pos);
+               if(me.mouseFocusedChild)
+               {
+                       me.animationState = 1;
+                       SUPER(Nexposee).setFocus(me, NULL);
+               }
+               else
+                       me.close(me);
+               return 1;
+       }
+       else if(me.animationState == 2)
+       {
+               if (!(SUPER(Nexposee).mousePress(me, pos)))
+               {
+                       me.animationState = 3;
+                       SUPER(Nexposee).setFocus(me, NULL);
+               }
+               return 1;
+       }
+       return 0;
+}
+
+float Nexposee_mouseRelease(entity me, vector pos)
+{
+       if(me.animationState == 2)
+               return SUPER(Nexposee).mouseRelease(me, pos);
+       return 0;
+}
+
+float Nexposee_mouseDrag(entity me, vector pos)
+{
+       if(me.animationState == 2)
+               return SUPER(Nexposee).mouseDrag(me, pos);
+       return 0;
+}
+
+float Nexposee_mouseMove(entity me, vector pos)
+{
+       entity e;
+       me.mousePosition = pos;
+       e = me.mouseFocusedChild;
+       me.mouseFocusedChild = me.itemFromPoint(me, pos);
+       if(me.animationState == 2)
+               return SUPER(Nexposee).mouseMove(me, pos);
+       if(me.animationState == 0)
+       {
+               if(me.mouseFocusedChild)
+                       if(me.mouseFocusedChild != e || me.mouseFocusedChild != me.selectedChild)
+                               me.selectedChild = me.mouseFocusedChild;
+               return 1;
+       }
+       return 0;
+}
+
+float Nexposee_keyUp(entity me, float scan, float ascii, float shift)
+{
+       if(me.animationState == 2)
+               return SUPER(Nexposee).keyUp(me, scan, ascii, shift);
+       return 0;
+}
+
+float Nexposee_keyDown(entity me, float scan, float ascii, float shift)
+{
+       float nexposeeKey = 0;
+       if(me.animationState == 2)
+               if(SUPER(Nexposee).keyDown(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 (!me.selectedChild)
+                                       me.selectedChild = me.lastChild;
+                       }
+                       else
+                       {
+                               if(me.selectedChild)
+                                       me.selectedChild = me.selectedChild.nextSibling;
+                               if (!me.selectedChild)
+                                       me.selectedChild = me.firstChild;
+                       }
+               }
+       }
+       switch(me.animationState)
+       {
+               default:
+               case 0:
+               case 3:
+                       nexposeeKey = ((scan == K_SPACE) || (scan == K_ENTER) || (scan == K_KP_ENTER));
+                       break;
+               case 1:
+               case 2:
+                       nexposeeKey = (scan == K_ESCAPE);
+                       break;
+       }
+       if(nexposeeKey)
+       {
+               switch(me.animationState)
+               {
+                       default:
+                       case 0:
+                       case 3:
+                               me.animationState = 1;
+                               break;
+                       case 1:
+                       case 2:
+                               me.animationState = 3;
+                               break;
+               }
+               if(me.focusedChild)
+                       me.selectedChild = me.focusedChild;
+               if (!me.selectedChild)
+                       me.animationState = 0;
+               SUPER(Nexposee).setFocus(me, NULL);
+               return 1;
+       }
+       return 0;
+}
+
+void Nexposee_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
+{
+       SUPER(Nexposee).addItem(me, other, theOrigin, theSize, theAlpha);
+       other.Nexposee_initialFontScale = other.Container_fontscale;
+       other.Nexposee_initialSize = other.Container_size;
+       other.Nexposee_initialOrigin = other.Container_origin;
+       other.Nexposee_initialAlpha = other.Container_alpha;
+       if(other.Nexposee_initialFontScale == '0 0 0')
+               other.Nexposee_initialFontScale = '1 1 0';
+}
+
+void Nexposee_focusEnter(entity me)
+{
+       if(me.animationState == 2)
+               SUPER(Nexposee).setFocus(me, me.selectedChild);
+}
+
+void Nexposee_pullNexposee(entity me, entity other, vector theAlign)
+{
+       other.Nexposee_align = theAlign;
+}
+#endif
diff --git a/qcsrc/menu/item/radiobutton.c b/qcsrc/menu/item/radiobutton.c
deleted file mode 100644 (file)
index 80fd532..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#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 RadioButton_configureRadioButton(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
diff --git a/qcsrc/menu/item/radiobutton.qc b/qcsrc/menu/item/radiobutton.qc
new file mode 100644 (file)
index 0000000..80fd532
--- /dev/null
@@ -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 RadioButton_configureRadioButton(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
diff --git a/qcsrc/menu/item/slider.c b/qcsrc/menu/item/slider.c
deleted file mode 100644 (file)
index c92db27..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-// 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, focusEnter, void(entity))
-       METHOD(Slider, valueToText, string(entity, float))
-       METHOD(Slider, toString, string(entity))
-       METHOD(Slider, setValue, void(entity, float))
-       METHOD(Slider, setSliderValue, 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, animated, float, 1)
-       ATTRIB(Slider, sliderValue, 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 Slider_setValue(entity me, float val)
-{
-       if (me.animated) {
-               anim.removeObjAnim(anim, me);
-               makeHostedEasing(me, Slider_setSliderValue, easingQuadInOut, 1, me.sliderValue, val);
-       } else {
-               me.setSliderValue(me, val);
-       }
-       me.value = val;
-}
-void Slider_setSliderValue(entity me, float val)
-{
-       me.sliderValue = val;
-}
-string Slider_toString(entity me)
-{
-       return sprintf("%d (%s)", me.value, me.valueToText(me, me.value));
-}
-void Slider_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(Slider).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       me.controlWidth = absSize_y / absSize_x;
-}
-string Slider_valueToText(entity me, float val)
-{
-       if(almost_in_bounds(me.valueMin, val, me.valueMax))
-               return ftos_decimals(val * me.valueDisplayMultiplier, me.valueDigits);
-       return "";
-}
-void Slider_configureSliderVisuals(entity me, float sz, float theAlign, float theTextSpace, string gfx)
-{
-       SUPER(Slider).configureLabel(me, string_null, sz, theAlign);
-       me.textSpace = theTextSpace;
-       me.keepspaceLeft = (theTextSpace == 0) ? 0 : (1 - theTextSpace);
-       me.src = gfx;
-}
-void Slider_configureSliderValues(entity me, float theValueMin, float theValue, float theValueMax, float theValueStep, float theValueKeyStep, float theValuePageStep)
-{
-       me.value = theValue;
-       me.sliderValue = 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 Slider_keyDown(entity me, float key, float ascii, float shift)
-{
-       float inRange;
-       if(me.disabled)
-               return 0;
-       inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
-       if(key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELDOWN)
-       {
-               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 || key == K_KP_RIGHTARROW || key == K_MWHEELUP)
-       {
-               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_PGDN || key == K_KP_PGDN)
-       {
-               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_PGUP || key == K_KP_PGUP)
-       {
-               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 || key == K_KP_HOME)
-       {
-               me.setValue(me, me.valueMin);
-               return 1;
-       }
-       if(key == K_END || key == K_KP_END)
-       {
-               me.setValue(me, me.valueMax);
-               return 1;
-       }
-       // TODO more keys
-       return 0;
-}
-float Slider_mouseDrag(entity me, vector pos)
-{
-       float hit;
-       float v, animed;
-       if(me.disabled)
-               return 0;
-
-       anim.removeObjAnim(anim, me);
-       animed = me.animated;
-       me.animated = false;
-
-       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);
-       }
-
-       me.animated = animed;
-
-       return 1;
-}
-float Slider_mousePress(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
-       {
-               float clickValue, pageValue, inRange;
-               clickValue = median(0, (pos_x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
-               inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
-               if(pos_x < controlCenter)
-               {
-                       pageValue = me.value - me.valuePageStep;
-                       if(me.valueStep)
-                               clickValue = floor(clickValue / me.valueStep) * me.valueStep;
-                       pageValue = max(pageValue, clickValue);
-                       if(inRange)
-                               me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
-                       else
-                               me.setValue(me, me.valueMax);
-               }
-               else
-               {
-                       pageValue = me.value + me.valuePageStep;
-                       if(me.valueStep)
-                               clickValue = ceil(clickValue / me.valueStep) * me.valueStep;
-                       pageValue = min(pageValue, clickValue);
-                       if(inRange)
-                               me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
-                       else
-                               me.setValue(me, me.valueMax);
-               }
-               if(pageValue == clickValue)
-               {
-                       controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
-                       me.pressed = 1;
-                       me.pressOffset = pos_x - controlCenter;
-                       me.previousValue = me.value;
-                       //me.mouseDrag(me, pos);
-               }
-       }
-       return 1;
-}
-float Slider_mouseRelease(entity me, vector pos)
-{
-       me.pressed = 0;
-       if(me.disabled)
-               return 0;
-       if(cvar("menu_sounds"))
-               localsound("sound/misc/menu2.wav");
-       return 1;
-}
-void Slider_showNotify(entity me)
-{
-       me.focusable = !me.disabled;
-}
-void Slider_focusEnter(entity me)
-{
-       if(cvar("menu_sounds") > 1)
-               localsound("sound/misc/menu1.wav");
-       SUPER(Slider).focusEnter(me);
-}
-void Slider_draw(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(almost_in_bounds(me.valueMin, me.sliderValue, me.valueMax))
-       {
-               controlLeft = (me.sliderValue - 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;
-       SUPER(Slider).draw(me);
-       me.text = string_null; // TEMPSTRING!
-}
-#endif
diff --git a/qcsrc/menu/item/slider.qc b/qcsrc/menu/item/slider.qc
new file mode 100644 (file)
index 0000000..c92db27
--- /dev/null
@@ -0,0 +1,285 @@
+// 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, focusEnter, void(entity))
+       METHOD(Slider, valueToText, string(entity, float))
+       METHOD(Slider, toString, string(entity))
+       METHOD(Slider, setValue, void(entity, float))
+       METHOD(Slider, setSliderValue, 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, animated, float, 1)
+       ATTRIB(Slider, sliderValue, 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 Slider_setValue(entity me, float val)
+{
+       if (me.animated) {
+               anim.removeObjAnim(anim, me);
+               makeHostedEasing(me, Slider_setSliderValue, easingQuadInOut, 1, me.sliderValue, val);
+       } else {
+               me.setSliderValue(me, val);
+       }
+       me.value = val;
+}
+void Slider_setSliderValue(entity me, float val)
+{
+       me.sliderValue = val;
+}
+string Slider_toString(entity me)
+{
+       return sprintf("%d (%s)", me.value, me.valueToText(me, me.value));
+}
+void Slider_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(Slider).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+       me.controlWidth = absSize_y / absSize_x;
+}
+string Slider_valueToText(entity me, float val)
+{
+       if(almost_in_bounds(me.valueMin, val, me.valueMax))
+               return ftos_decimals(val * me.valueDisplayMultiplier, me.valueDigits);
+       return "";
+}
+void Slider_configureSliderVisuals(entity me, float sz, float theAlign, float theTextSpace, string gfx)
+{
+       SUPER(Slider).configureLabel(me, string_null, sz, theAlign);
+       me.textSpace = theTextSpace;
+       me.keepspaceLeft = (theTextSpace == 0) ? 0 : (1 - theTextSpace);
+       me.src = gfx;
+}
+void Slider_configureSliderValues(entity me, float theValueMin, float theValue, float theValueMax, float theValueStep, float theValueKeyStep, float theValuePageStep)
+{
+       me.value = theValue;
+       me.sliderValue = 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 Slider_keyDown(entity me, float key, float ascii, float shift)
+{
+       float inRange;
+       if(me.disabled)
+               return 0;
+       inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
+       if(key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELDOWN)
+       {
+               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 || key == K_KP_RIGHTARROW || key == K_MWHEELUP)
+       {
+               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_PGDN || key == K_KP_PGDN)
+       {
+               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_PGUP || key == K_KP_PGUP)
+       {
+               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 || key == K_KP_HOME)
+       {
+               me.setValue(me, me.valueMin);
+               return 1;
+       }
+       if(key == K_END || key == K_KP_END)
+       {
+               me.setValue(me, me.valueMax);
+               return 1;
+       }
+       // TODO more keys
+       return 0;
+}
+float Slider_mouseDrag(entity me, vector pos)
+{
+       float hit;
+       float v, animed;
+       if(me.disabled)
+               return 0;
+
+       anim.removeObjAnim(anim, me);
+       animed = me.animated;
+       me.animated = false;
+
+       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);
+       }
+
+       me.animated = animed;
+
+       return 1;
+}
+float Slider_mousePress(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
+       {
+               float clickValue, pageValue, inRange;
+               clickValue = median(0, (pos_x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
+               inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
+               if(pos_x < controlCenter)
+               {
+                       pageValue = me.value - me.valuePageStep;
+                       if(me.valueStep)
+                               clickValue = floor(clickValue / me.valueStep) * me.valueStep;
+                       pageValue = max(pageValue, clickValue);
+                       if(inRange)
+                               me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
+                       else
+                               me.setValue(me, me.valueMax);
+               }
+               else
+               {
+                       pageValue = me.value + me.valuePageStep;
+                       if(me.valueStep)
+                               clickValue = ceil(clickValue / me.valueStep) * me.valueStep;
+                       pageValue = min(pageValue, clickValue);
+                       if(inRange)
+                               me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
+                       else
+                               me.setValue(me, me.valueMax);
+               }
+               if(pageValue == clickValue)
+               {
+                       controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
+                       me.pressed = 1;
+                       me.pressOffset = pos_x - controlCenter;
+                       me.previousValue = me.value;
+                       //me.mouseDrag(me, pos);
+               }
+       }
+       return 1;
+}
+float Slider_mouseRelease(entity me, vector pos)
+{
+       me.pressed = 0;
+       if(me.disabled)
+               return 0;
+       if(cvar("menu_sounds"))
+               localsound("sound/misc/menu2.wav");
+       return 1;
+}
+void Slider_showNotify(entity me)
+{
+       me.focusable = !me.disabled;
+}
+void Slider_focusEnter(entity me)
+{
+       if(cvar("menu_sounds") > 1)
+               localsound("sound/misc/menu1.wav");
+       SUPER(Slider).focusEnter(me);
+}
+void Slider_draw(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(almost_in_bounds(me.valueMin, me.sliderValue, me.valueMax))
+       {
+               controlLeft = (me.sliderValue - 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;
+       SUPER(Slider).draw(me);
+       me.text = string_null; // TEMPSTRING!
+}
+#endif
diff --git a/qcsrc/menu/item/tab.c b/qcsrc/menu/item/tab.c
deleted file mode 100644 (file)
index 8cd72ba..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#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
diff --git a/qcsrc/menu/item/tab.qc b/qcsrc/menu/item/tab.qc
new file mode 100644 (file)
index 0000000..8cd72ba
--- /dev/null
@@ -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
diff --git a/qcsrc/menu/item/textslider.c b/qcsrc/menu/item/textslider.c
deleted file mode 100644 (file)
index 59d8c10..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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, clearValues, void(entity))
-       METHOD(TextSlider, addValue, void(entity, string, string))
-       METHOD(TextSlider, insertValue, void(entity, float, string, string))
-       METHOD(TextSlider, configureTextSliderValues, void(entity, string))
-       ATTRIBARRAY(TextSlider, valueStrings, string, 256)
-       ATTRIBARRAY(TextSlider, valueIdentifiers, string, 256)
-       ATTRIB(TextSlider, nValues, float, 0)
-ENDCLASS(TextSlider)
-#endif
-
-#ifdef IMPLEMENTATION
-string TextSlider_valueToIdentifier(entity me, float val)
-{
-       if(val >= me.nValues)
-               return "custom";
-       if(val < 0)
-               return "custom";
-       return me.(valueIdentifiers[val]);
-}
-string TextSlider_valueToText(entity me, float val)
-{
-       if(val >= me.nValues)
-               return _("Custom");
-       if(val < 0)
-               return _("Custom");
-       return me.(valueStrings[val]);
-}
-void TextSlider_setValueFromIdentifier(entity me, string id)
-{
-       float i;
-       for(i = 0; i < me.nValues; ++i)
-               if(me.valueToIdentifier(me, i) == id)
-               {
-                       SUPER(TextSlider).setValue( me, i );
-                       return;
-               }
-       SUPER(TextSlider).setValue( me, -1 );
-}
-string TextSlider_getIdentifier(entity me)
-{
-       return me.valueToIdentifier(me, me.value);
-}
-void TextSlider_clearValues(entity me)
-{
-       me.nValues = 0;
-}
-void TextSlider_addValue(entity me, string theString, string theIdentifier)
-{
-       me.(valueStrings[me.nValues]) = theString;
-       me.(valueIdentifiers[me.nValues]) = theIdentifier;
-       me.nValues += 1;
-}
-void TextSlider_insertValue(entity me, float pos, string theString, string theIdentifier)
-{
-       float i;
-       for (i = me.nValues; i > pos; --i)
-       {
-               me.(valueStrings[i]) = me.(valueStrings[i-1]);
-               me.(valueIdentifiers[i]) = me.(valueIdentifiers[i-1]);
-       }
-       me.(valueStrings[pos]) = theString;
-       me.(valueIdentifiers[pos]) = theIdentifier;
-       me.nValues += 1;
-}
-void TextSlider_configureTextSliderValues(entity me, string theDefault)
-{
-       me.configureSliderValues(me, 0, 0, me.nValues - 1, 1, 1, 1);
-       me.setValueFromIdentifier(me, theDefault);
-}
-#endif
diff --git a/qcsrc/menu/item/textslider.qc b/qcsrc/menu/item/textslider.qc
new file mode 100644 (file)
index 0000000..59d8c10
--- /dev/null
@@ -0,0 +1,78 @@
+// 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, clearValues, void(entity))
+       METHOD(TextSlider, addValue, void(entity, string, string))
+       METHOD(TextSlider, insertValue, void(entity, float, string, string))
+       METHOD(TextSlider, configureTextSliderValues, void(entity, string))
+       ATTRIBARRAY(TextSlider, valueStrings, string, 256)
+       ATTRIBARRAY(TextSlider, valueIdentifiers, string, 256)
+       ATTRIB(TextSlider, nValues, float, 0)
+ENDCLASS(TextSlider)
+#endif
+
+#ifdef IMPLEMENTATION
+string TextSlider_valueToIdentifier(entity me, float val)
+{
+       if(val >= me.nValues)
+               return "custom";
+       if(val < 0)
+               return "custom";
+       return me.(valueIdentifiers[val]);
+}
+string TextSlider_valueToText(entity me, float val)
+{
+       if(val >= me.nValues)
+               return _("Custom");
+       if(val < 0)
+               return _("Custom");
+       return me.(valueStrings[val]);
+}
+void TextSlider_setValueFromIdentifier(entity me, string id)
+{
+       float i;
+       for(i = 0; i < me.nValues; ++i)
+               if(me.valueToIdentifier(me, i) == id)
+               {
+                       SUPER(TextSlider).setValue( me, i );
+                       return;
+               }
+       SUPER(TextSlider).setValue( me, -1 );
+}
+string TextSlider_getIdentifier(entity me)
+{
+       return me.valueToIdentifier(me, me.value);
+}
+void TextSlider_clearValues(entity me)
+{
+       me.nValues = 0;
+}
+void TextSlider_addValue(entity me, string theString, string theIdentifier)
+{
+       me.(valueStrings[me.nValues]) = theString;
+       me.(valueIdentifiers[me.nValues]) = theIdentifier;
+       me.nValues += 1;
+}
+void TextSlider_insertValue(entity me, float pos, string theString, string theIdentifier)
+{
+       float i;
+       for (i = me.nValues; i > pos; --i)
+       {
+               me.(valueStrings[i]) = me.(valueStrings[i-1]);
+               me.(valueIdentifiers[i]) = me.(valueIdentifiers[i-1]);
+       }
+       me.(valueStrings[pos]) = theString;
+       me.(valueIdentifiers[pos]) = theIdentifier;
+       me.nValues += 1;
+}
+void TextSlider_configureTextSliderValues(entity me, string theDefault)
+{
+       me.configureSliderValues(me, 0, 0, me.nValues - 1, 1, 1, 1);
+       me.setValueFromIdentifier(me, theDefault);
+}
+#endif
diff --git a/qcsrc/menu/oo/base.h b/qcsrc/menu/oo/base.h
deleted file mode 100644 (file)
index ed4eba5..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-.string classname;
-entity Object_vtbl;
-.string vtblname;
-.entity vtblbase;
-// THIS LINE INTENTIONALLY LEFT BLANK
-entity spawnVtbl(entity e, entity b)
-{
-       entity v;
-       v = spawn();
-       copyentity(e, v);
-       v.vtblname = v.classname;
-       v.classname = "vtbl";
-       if(b)
-               v.vtblbase = b;
-       else
-               v.vtblbase = v;
-       return v;
-}
-entity spawnObject()
-{
-       entity e;
-       e = spawn();
-       e.classname = "Object";
-       if(!Object_vtbl)
-               Object_vtbl = spawnVtbl(e, null_entity);
-       return e;
-}
diff --git a/qcsrc/menu/oo/base.qh b/qcsrc/menu/oo/base.qh
new file mode 100644 (file)
index 0000000..ed4eba5
--- /dev/null
@@ -0,0 +1,27 @@
+.string classname;
+entity Object_vtbl;
+.string vtblname;
+.entity vtblbase;
+// THIS LINE INTENTIONALLY LEFT BLANK
+entity spawnVtbl(entity e, entity b)
+{
+       entity v;
+       v = spawn();
+       copyentity(e, v);
+       v.vtblname = v.classname;
+       v.classname = "vtbl";
+       if(b)
+               v.vtblbase = b;
+       else
+               v.vtblbase = v;
+       return v;
+}
+entity spawnObject()
+{
+       entity e;
+       e = spawn();
+       e.classname = "Object";
+       if(!Object_vtbl)
+               Object_vtbl = spawnVtbl(e, null_entity);
+       return e;
+}
diff --git a/qcsrc/menu/oo/implementation.h b/qcsrc/menu/oo/implementation.h
deleted file mode 100644 (file)
index 28b7f08..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef INTERFACE
-#define INTERFACE
-#endif
-
-#ifndef IMPLEMENTATION
-#define IMPLEMENTATION
-#endif
-
-#ifdef CLASS
-#undef CLASS
-#undef EXTENDS
-#undef METHOD
-#undef ATTRIB
-#undef ATTRIBARRAY
-#undef ENDCLASS
-#undef SUPER
-#endif
-
-// for the constructor
-#define CLASS(cname)                       entity spawn##cname() { entity me;
-#define EXTENDS(base)                      me = spawn##base (); entity basevtbl; basevtbl = base##_vtbl;
-#define METHOD(cname,name,prototype)       me.name = cname##_##name;
-#define ATTRIB(cname,name,type,val)        me.name = val;
-#define ATTRIBARRAY(cname,name,type,cnt)
-#define ENDCLASS(cname)                    me.instanceOf##cname = 1; me.classname = #cname; if(!cname##_vtbl) cname##_vtbl = spawnVtbl(me, basevtbl); return me; }
-
-// for the implementation
-#define SUPER(cname) (cname##_vtbl.vtblbase)
diff --git a/qcsrc/menu/oo/implementation.qh b/qcsrc/menu/oo/implementation.qh
new file mode 100644 (file)
index 0000000..28b7f08
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef INTERFACE
+#define INTERFACE
+#endif
+
+#ifndef IMPLEMENTATION
+#define IMPLEMENTATION
+#endif
+
+#ifdef CLASS
+#undef CLASS
+#undef EXTENDS
+#undef METHOD
+#undef ATTRIB
+#undef ATTRIBARRAY
+#undef ENDCLASS
+#undef SUPER
+#endif
+
+// for the constructor
+#define CLASS(cname)                       entity spawn##cname() { entity me;
+#define EXTENDS(base)                      me = spawn##base (); entity basevtbl; basevtbl = base##_vtbl;
+#define METHOD(cname,name,prototype)       me.name = cname##_##name;
+#define ATTRIB(cname,name,type,val)        me.name = val;
+#define ATTRIBARRAY(cname,name,type,cnt)
+#define ENDCLASS(cname)                    me.instanceOf##cname = 1; me.classname = #cname; if(!cname##_vtbl) cname##_vtbl = spawnVtbl(me, basevtbl); return me; }
+
+// for the implementation
+#define SUPER(cname) (cname##_vtbl.vtblbase)
diff --git a/qcsrc/menu/oo/interface.h b/qcsrc/menu/oo/interface.h
deleted file mode 100644 (file)
index 1e12206..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef INTERFACE
-#define INTERFACE
-#endif
-
-#ifdef IMPLEMENTATION
-#undef IMPLEMENTATION
-#endif
-
-#ifdef CLASS
-#undef CLASS
-#undef EXTENDS
-#undef METHOD
-#undef ATTRIB
-#undef ATTRIBARRAY
-#undef ENDCLASS
-#undef SUPER
-#endif
-
-#define CLASS(cname)                       entity spawn##cname(); entity cname##_vtbl;
-#define EXTENDS(base)
-#define METHOD(cname,name,prototype)       prototype cname##_##name; .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;
-#define SUPER(cname)
diff --git a/qcsrc/menu/oo/interface.qh b/qcsrc/menu/oo/interface.qh
new file mode 100644 (file)
index 0000000..1e12206
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef INTERFACE
+#define INTERFACE
+#endif
+
+#ifdef IMPLEMENTATION
+#undef IMPLEMENTATION
+#endif
+
+#ifdef CLASS
+#undef CLASS
+#undef EXTENDS
+#undef METHOD
+#undef ATTRIB
+#undef ATTRIBARRAY
+#undef ENDCLASS
+#undef SUPER
+#endif
+
+#define CLASS(cname)                       entity spawn##cname(); entity cname##_vtbl;
+#define EXTENDS(base)
+#define METHOD(cname,name,prototype)       prototype cname##_##name; .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;
+#define SUPER(cname)
index 79b0f9023cd28dedfbde120252393dd53ffb172b..3b1e46944449ec10a4a1f39ed6cd778a1d0ae201 100644 (file)
@@ -12,7 +12,7 @@ config.qh
 ../common/util.qh
 ../common/test.qh
 
-oo/base.h
+oo/base.qh
 
 ../common/playerstats.qh
 ../common/teams.qh
@@ -34,10 +34,10 @@ draw.qh
 skin.qh
 xonotic/util.qh
 
-oo/interface.h
-       classes.c
-oo/implementation.h
-       classes.c
+oo/interface.qh
+       classes.qc
+oo/implementation.qh
+       classes.qc
 
 ../common/util.qc
 ../common/test.qc
diff --git a/qcsrc/menu/xonotic/bigbutton.c b/qcsrc/menu/xonotic/bigbutton.c
deleted file mode 100644 (file)
index a63189b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticBigButton) EXTENDS(XonoticButton)
-       METHOD(XonoticBigButton, configureXonoticBigButton, void(entity, string, vector))
-       ATTRIB(XonoticBigButton, image, string, SKINGFX_BUTTON_BIG)
-       ATTRIB(XonoticBigButton, grayImage, string, SKINGFX_BUTTON_BIG_GRAY)
-ENDCLASS(XonoticBigButton)
-entity makeXonoticButton(string theText, vector theColor);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticBigButton(string theText, vector theColor)
-{
-       entity me;
-       me = spawnXonoticBigButton();
-       me.configureXonoticBigButton(me, theText, theColor);
-       return me;
-}
-
-void XonoticBigButton_configureXonoticBigButton(entity me, string theText, vector theColor)
-{
-       me.configureXonoticButton(me, theText, theColor);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/bigbutton.qc b/qcsrc/menu/xonotic/bigbutton.qc
new file mode 100644 (file)
index 0000000..a63189b
--- /dev/null
@@ -0,0 +1,23 @@
+#ifdef INTERFACE
+CLASS(XonoticBigButton) EXTENDS(XonoticButton)
+       METHOD(XonoticBigButton, configureXonoticBigButton, void(entity, string, vector))
+       ATTRIB(XonoticBigButton, image, string, SKINGFX_BUTTON_BIG)
+       ATTRIB(XonoticBigButton, grayImage, string, SKINGFX_BUTTON_BIG_GRAY)
+ENDCLASS(XonoticBigButton)
+entity makeXonoticButton(string theText, vector theColor);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticBigButton(string theText, vector theColor)
+{
+       entity me;
+       me = spawnXonoticBigButton();
+       me.configureXonoticBigButton(me, theText, theColor);
+       return me;
+}
+
+void XonoticBigButton_configureXonoticBigButton(entity me, string theText, vector theColor)
+{
+       me.configureXonoticButton(me, theText, theColor);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/bigcommandbutton.c b/qcsrc/menu/xonotic/bigcommandbutton.c
deleted file mode 100644 (file)
index c96dd57..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticBigCommandButton) EXTENDS(XonoticCommandButton)
-       METHOD(XonoticBigCommandButton, configureXonoticBigCommandButton, void(entity, string, vector, string, float))
-       ATTRIB(XonoticBigCommandButton, image, string, SKINGFX_BUTTON_BIG)
-       ATTRIB(XonoticBigCommandButton, grayImage, string, SKINGFX_BUTTON_BIG_GRAY)
-ENDCLASS(XonoticBigCommandButton)
-entity makeXonoticBigCommandButton(string theText, vector theColor, string theCommand, float closesMenu);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticBigCommandButton(string theText, vector theColor, string theCommand, float theFlags)
-{
-       entity me;
-       me = spawnXonoticBigCommandButton();
-       me.configureXonoticBigCommandButton(me, theText, theColor, theCommand, theFlags);
-       return me;
-}
-
-void XonoticBigCommandButton_configureXonoticBigCommandButton(entity me, string theText, vector theColor, string theCommand, float theFlags)
-{
-       me.configureXonoticCommandButton(me, theText, theColor, theCommand, theFlags);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/bigcommandbutton.qc b/qcsrc/menu/xonotic/bigcommandbutton.qc
new file mode 100644 (file)
index 0000000..c96dd57
--- /dev/null
@@ -0,0 +1,23 @@
+#ifdef INTERFACE
+CLASS(XonoticBigCommandButton) EXTENDS(XonoticCommandButton)
+       METHOD(XonoticBigCommandButton, configureXonoticBigCommandButton, void(entity, string, vector, string, float))
+       ATTRIB(XonoticBigCommandButton, image, string, SKINGFX_BUTTON_BIG)
+       ATTRIB(XonoticBigCommandButton, grayImage, string, SKINGFX_BUTTON_BIG_GRAY)
+ENDCLASS(XonoticBigCommandButton)
+entity makeXonoticBigCommandButton(string theText, vector theColor, string theCommand, float closesMenu);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticBigCommandButton(string theText, vector theColor, string theCommand, float theFlags)
+{
+       entity me;
+       me = spawnXonoticBigCommandButton();
+       me.configureXonoticBigCommandButton(me, theText, theColor, theCommand, theFlags);
+       return me;
+}
+
+void XonoticBigCommandButton_configureXonoticBigCommandButton(entity me, string theText, vector theColor, string theCommand, float theFlags)
+{
+       me.configureXonoticCommandButton(me, theText, theColor, theCommand, theFlags);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/button.c b/qcsrc/menu/xonotic/button.c
deleted file mode 100644 (file)
index cbc7c47..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticButton) EXTENDS(Button)
-       METHOD(XonoticButton, configureXonoticButton, void(entity, string, vector))
-       ATTRIB(XonoticButton, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticButton, image, string, SKINGFX_BUTTON)
-       ATTRIB(XonoticButton, grayImage, string, SKINGFX_BUTTON_GRAY)
-       ATTRIB(XonoticButton, color, vector, SKINCOLOR_BUTTON_N)
-       ATTRIB(XonoticButton, colorC, vector, SKINCOLOR_BUTTON_C)
-       ATTRIB(XonoticButton, colorF, vector, SKINCOLOR_BUTTON_F)
-       ATTRIB(XonoticButton, colorD, vector, SKINCOLOR_BUTTON_D)
-       ATTRIB(XonoticButton, alpha, float, SKINALPHA_TEXT)
-       ATTRIB(XonoticButton, disabledAlpha, float, SKINALPHA_DISABLED)
-       ATTRIB(XonoticButton, marginLeft, float, SKINMARGIN_BUTTON) // chars
-       ATTRIB(XonoticButton, marginRight, float, SKINMARGIN_BUTTON) // chars
-ENDCLASS(XonoticButton)
-entity makeXonoticButton(string theText, vector theColor);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticButton(string theText, vector theColor)
-{
-       entity me;
-       me = spawnXonoticButton();
-       me.configureXonoticButton(me, theText, theColor);
-       return me;
-}
-
-void XonoticButton_configureXonoticButton(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;
-       }
-       me.tooltip = getZonedTooltipForIdentifier(strcat(currentDialog.classname, "/", me.text));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/button.qc b/qcsrc/menu/xonotic/button.qc
new file mode 100644 (file)
index 0000000..cbc7c47
--- /dev/null
@@ -0,0 +1,43 @@
+#ifdef INTERFACE
+CLASS(XonoticButton) EXTENDS(Button)
+       METHOD(XonoticButton, configureXonoticButton, void(entity, string, vector))
+       ATTRIB(XonoticButton, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticButton, image, string, SKINGFX_BUTTON)
+       ATTRIB(XonoticButton, grayImage, string, SKINGFX_BUTTON_GRAY)
+       ATTRIB(XonoticButton, color, vector, SKINCOLOR_BUTTON_N)
+       ATTRIB(XonoticButton, colorC, vector, SKINCOLOR_BUTTON_C)
+       ATTRIB(XonoticButton, colorF, vector, SKINCOLOR_BUTTON_F)
+       ATTRIB(XonoticButton, colorD, vector, SKINCOLOR_BUTTON_D)
+       ATTRIB(XonoticButton, alpha, float, SKINALPHA_TEXT)
+       ATTRIB(XonoticButton, disabledAlpha, float, SKINALPHA_DISABLED)
+       ATTRIB(XonoticButton, marginLeft, float, SKINMARGIN_BUTTON) // chars
+       ATTRIB(XonoticButton, marginRight, float, SKINMARGIN_BUTTON) // chars
+ENDCLASS(XonoticButton)
+entity makeXonoticButton(string theText, vector theColor);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticButton(string theText, vector theColor)
+{
+       entity me;
+       me = spawnXonoticButton();
+       me.configureXonoticButton(me, theText, theColor);
+       return me;
+}
+
+void XonoticButton_configureXonoticButton(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;
+       }
+       me.tooltip = getZonedTooltipForIdentifier(strcat(currentDialog.classname, "/", me.text));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/campaign.c b/qcsrc/menu/xonotic/campaign.c
deleted file mode 100644 (file)
index 126b728..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCampaignList) EXTENDS(XonoticListBox)
-       METHOD(XonoticCampaignList, configureXonoticCampaignList, void(entity))
-       ATTRIB(XonoticCampaignList, rowsPerItem, float, 10)
-       METHOD(XonoticCampaignList, draw, void(entity))
-       METHOD(XonoticCampaignList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticCampaignList, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticCampaignList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticCampaignList, setSelected, void(entity, float))
-       METHOD(XonoticCampaignList, keyDown, float(entity, float, float, float))
-       METHOD(XonoticCampaignList, campaignGo, void(entity, float))
-       METHOD(XonoticCampaignList, destroy, void(entity))
-
-       ATTRIB(XonoticCampaignList, campaignGlob, float, 0)
-       ATTRIB(XonoticCampaignList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticCampaignList, columnPreviewOrigin, float, 0)
-       ATTRIB(XonoticCampaignList, columnPreviewSize, float, 0)
-       ATTRIB(XonoticCampaignList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticCampaignList, columnNameSize, float, 0)
-       ATTRIB(XonoticCampaignList, columnCheckMarkOrigin, float, 0)
-       ATTRIB(XonoticCampaignList, columnCheckMarkSize, float, 0)
-       ATTRIB(XonoticCampaignList, checkMarkOrigin, vector, '0 0 0')
-       ATTRIB(XonoticCampaignList, checkMarkSize, vector, '0 0 0')
-       ATTRIB(XonoticCampaignList, realUpperMargin1, float, 0)
-       ATTRIB(XonoticCampaignList, realUpperMargin2, float, 0)
-
-       ATTRIB(XonoticCampaignList, origin, vector, '0 0 0')
-       ATTRIB(XonoticCampaignList, itemAbsSize, vector, '0 0 0')
-       ATTRIB(XonoticCampaignList, emptyLineHeight, float, 0.5)
-
-       ATTRIB(XonoticCampaignList, campaignIndex, float, 0)
-       ATTRIB(XonoticCampaignList, cvarName, string, string_null)
-       METHOD(XonoticCampaignList, loadCvars, void(entity))
-       METHOD(XonoticCampaignList, saveCvars, void(entity))
-
-       ATTRIB(XonoticCampaignList, buttonNext, entity, NULL)
-       ATTRIB(XonoticCampaignList, buttonPrev, entity, NULL)
-       ATTRIB(XonoticCampaignList, labelTitle, entity, NULL)
-ENDCLASS(XonoticCampaignList)
-entity makeXonoticCampaignList();
-void CampaignList_LoadMap(entity btn, entity me);
-void MultiCampaign_Next(entity btn, entity me);
-void MultiCampaign_Prev(entity btn, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-string campaign_longdesc_wrapped[CAMPAIGN_MAX_ENTRIES];
-
-void rewrapCampaign(float w, float l0, float emptyheight, vector theFontSize)
-{
-       float i, j;
-       float n, 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;
-                       }
-
-                       getWrappedLine_remaining = s;
-                       while(getWrappedLine_remaining)
-                       {
-                               s = getWrappedLine(w, theFontSize, draw_TextWidth_WithoutColors);
-                               if(--l < 0) goto toolong;
-                               r = strcat(r, s, "\n");
-                       }
-               }
-               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 makeXonoticCampaignList()
-{
-       entity me;
-       me = spawnXonoticCampaignList();
-       me.configureXonoticCampaignList(me);
-       return me;
-}
-void XonoticCampaignList_configureXonoticCampaignList(entity me)
-{
-       me.configureXonoticListBox(me);
-       me.campaignGlob = search_begin("maps/campaign*.txt", TRUE, TRUE);
-       me.loadCvars(me);
-       me.campaignGo(me, 0); // takes care of enabling/disabling buttons too
-}
-
-void XonoticCampaignList_destroy(entity me)
-{
-       if(me.campaignGlob >= 0)
-               search_end(me.campaignGlob);
-}
-
-void XonoticCampaignList_loadCvars(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"));
-       registercvar(me.cvarName, "", 0); // saved by server QC anyway
-       CampaignFile_Unload();
-       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.rowsPerItem - 3, me.emptyLineHeight, me.realFontSize);
-       me.nItems = min(me.campaignIndex + 2, campaign_entries);
-       me.selectedItem = min(me.campaignIndex, me.nItems - 1);
-       me.scrollPos = me.nItems * me.itemHeight - 1;
-       if(me.labelTitle)
-               me.labelTitle.setText(me.labelTitle, campaign_title);
-}
-
-void XonoticCampaignList_saveCvars(entity me)
-{
-       // write campaign cvars
-       // no reason to do this!
-       // cvar_set("g_campaign_name", campaign_name);
-       // cvar_set(me.cvarName, ftos(me.campaignIndex)); // NOTE: only server QC does that!
-}
-
-void XonoticCampaignList_campaignGo(entity me, float step)
-{
-       float canNext, canPrev;
-       string s;
-       float i, j, n;
-
-       canNext = canPrev = 0;
-
-       if(me.campaignGlob >= 0)
-       {
-               n = search_getsize(me.campaignGlob);
-               if(n > 0)
-               {
-                       j = -1;
-                       s = strcat("maps/campaign", campaign_name, ".txt");
-                       for(i = 0; i < n; ++i)
-                       {
-                               if(search_getfilename(me.campaignGlob, i) == s)
-                                       j = i;
-                       }
-                       if(j < 0)
-                       {
-                               s = strcat("maps/campaign", cvar_defstring("g_campaign_name"), ".txt");
-                               for(i = 0; i < n; ++i)
-                               {
-                                       if(search_getfilename(me.campaignGlob, i) == s)
-                                               j = i;
-                               }
-                       }
-                       if(j < 0)
-                       {
-                               if(step >= 0)
-                                       j = 0;
-                               else
-                                       j = n - 1;
-                       }
-                       else
-                               j = mod(j + step, n);
-                       s = search_getfilename(me.campaignGlob, j);
-                       s = substring(s, 13, strlen(s) - 17);
-                       cvar_set("g_campaign_name", s);
-                       me.loadCvars(me);
-                       canNext = (j != n - 1);
-                       canPrev = (j != 0);
-               }
-       }
-
-       if(me.buttonNext)
-               me.buttonNext.disabled = !canNext;
-       if(me.buttonPrev)
-               me.buttonPrev.disabled = !canPrev;
-}
-
-void MultiCampaign_Next(entity btn, entity me)
-{
-       me.campaignGo(me, +1);
-}
-void MultiCampaign_Prev(entity btn, entity me)
-{
-       me.campaignGo(me, -1);
-}
-
-void XonoticCampaignList_draw(entity me)
-{
-       if(cvar(me.cvarName) != me.campaignIndex || cvar_string("g_campaign_name") != campaign_name)
-               me.loadCvars(me);
-       SUPER(XonoticCampaignList).draw(me);
-}
-
-void XonoticCampaignList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemAbsSize = '0 0 0';
-       SUPER(XonoticCampaignList).resizeNotify(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.rowsPerItem - 3, me.emptyLineHeight, me.realFontSize);
-}
-void XonoticCampaignList_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       CampaignList_LoadMap(me, me);
-}
-void XonoticCampaignList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string s;
-       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);
-
-       if(draw_PictureSize(strcat("/maps/", campaign_mapname[i])) == '0 0 0')
-               draw_Picture(me.columnPreviewOrigin * eX, "nopreview_map", me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
-       else
-               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(sprintf(_("Level %d: %s"), i+1, s), me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * 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 XonoticCampaignList_setSelected(entity me, float i)
-{
-       // prevent too late items from being played
-       SUPER(XonoticCampaignList).setSelected(me, min(i, me.campaignIndex));
-}
-
-float XonoticCampaignList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if(scan == K_ENTER || scan == K_SPACE || scan == K_KP_ENTER)
-               CampaignList_LoadMap(me, me);
-       else
-               return SUPER(XonoticCampaignList).keyDown(me, scan, ascii, shift);
-       return 1;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/campaign.qc b/qcsrc/menu/xonotic/campaign.qc
new file mode 100644 (file)
index 0000000..126b728
--- /dev/null
@@ -0,0 +1,314 @@
+#ifdef INTERFACE
+CLASS(XonoticCampaignList) EXTENDS(XonoticListBox)
+       METHOD(XonoticCampaignList, configureXonoticCampaignList, void(entity))
+       ATTRIB(XonoticCampaignList, rowsPerItem, float, 10)
+       METHOD(XonoticCampaignList, draw, void(entity))
+       METHOD(XonoticCampaignList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticCampaignList, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticCampaignList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticCampaignList, setSelected, void(entity, float))
+       METHOD(XonoticCampaignList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticCampaignList, campaignGo, void(entity, float))
+       METHOD(XonoticCampaignList, destroy, void(entity))
+
+       ATTRIB(XonoticCampaignList, campaignGlob, float, 0)
+       ATTRIB(XonoticCampaignList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticCampaignList, columnPreviewOrigin, float, 0)
+       ATTRIB(XonoticCampaignList, columnPreviewSize, float, 0)
+       ATTRIB(XonoticCampaignList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticCampaignList, columnNameSize, float, 0)
+       ATTRIB(XonoticCampaignList, columnCheckMarkOrigin, float, 0)
+       ATTRIB(XonoticCampaignList, columnCheckMarkSize, float, 0)
+       ATTRIB(XonoticCampaignList, checkMarkOrigin, vector, '0 0 0')
+       ATTRIB(XonoticCampaignList, checkMarkSize, vector, '0 0 0')
+       ATTRIB(XonoticCampaignList, realUpperMargin1, float, 0)
+       ATTRIB(XonoticCampaignList, realUpperMargin2, float, 0)
+
+       ATTRIB(XonoticCampaignList, origin, vector, '0 0 0')
+       ATTRIB(XonoticCampaignList, itemAbsSize, vector, '0 0 0')
+       ATTRIB(XonoticCampaignList, emptyLineHeight, float, 0.5)
+
+       ATTRIB(XonoticCampaignList, campaignIndex, float, 0)
+       ATTRIB(XonoticCampaignList, cvarName, string, string_null)
+       METHOD(XonoticCampaignList, loadCvars, void(entity))
+       METHOD(XonoticCampaignList, saveCvars, void(entity))
+
+       ATTRIB(XonoticCampaignList, buttonNext, entity, NULL)
+       ATTRIB(XonoticCampaignList, buttonPrev, entity, NULL)
+       ATTRIB(XonoticCampaignList, labelTitle, entity, NULL)
+ENDCLASS(XonoticCampaignList)
+entity makeXonoticCampaignList();
+void CampaignList_LoadMap(entity btn, entity me);
+void MultiCampaign_Next(entity btn, entity me);
+void MultiCampaign_Prev(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+string campaign_longdesc_wrapped[CAMPAIGN_MAX_ENTRIES];
+
+void rewrapCampaign(float w, float l0, float emptyheight, vector theFontSize)
+{
+       float i, j;
+       float n, 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;
+                       }
+
+                       getWrappedLine_remaining = s;
+                       while(getWrappedLine_remaining)
+                       {
+                               s = getWrappedLine(w, theFontSize, draw_TextWidth_WithoutColors);
+                               if(--l < 0) goto toolong;
+                               r = strcat(r, s, "\n");
+                       }
+               }
+               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 makeXonoticCampaignList()
+{
+       entity me;
+       me = spawnXonoticCampaignList();
+       me.configureXonoticCampaignList(me);
+       return me;
+}
+void XonoticCampaignList_configureXonoticCampaignList(entity me)
+{
+       me.configureXonoticListBox(me);
+       me.campaignGlob = search_begin("maps/campaign*.txt", TRUE, TRUE);
+       me.loadCvars(me);
+       me.campaignGo(me, 0); // takes care of enabling/disabling buttons too
+}
+
+void XonoticCampaignList_destroy(entity me)
+{
+       if(me.campaignGlob >= 0)
+               search_end(me.campaignGlob);
+}
+
+void XonoticCampaignList_loadCvars(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"));
+       registercvar(me.cvarName, "", 0); // saved by server QC anyway
+       CampaignFile_Unload();
+       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.rowsPerItem - 3, me.emptyLineHeight, me.realFontSize);
+       me.nItems = min(me.campaignIndex + 2, campaign_entries);
+       me.selectedItem = min(me.campaignIndex, me.nItems - 1);
+       me.scrollPos = me.nItems * me.itemHeight - 1;
+       if(me.labelTitle)
+               me.labelTitle.setText(me.labelTitle, campaign_title);
+}
+
+void XonoticCampaignList_saveCvars(entity me)
+{
+       // write campaign cvars
+       // no reason to do this!
+       // cvar_set("g_campaign_name", campaign_name);
+       // cvar_set(me.cvarName, ftos(me.campaignIndex)); // NOTE: only server QC does that!
+}
+
+void XonoticCampaignList_campaignGo(entity me, float step)
+{
+       float canNext, canPrev;
+       string s;
+       float i, j, n;
+
+       canNext = canPrev = 0;
+
+       if(me.campaignGlob >= 0)
+       {
+               n = search_getsize(me.campaignGlob);
+               if(n > 0)
+               {
+                       j = -1;
+                       s = strcat("maps/campaign", campaign_name, ".txt");
+                       for(i = 0; i < n; ++i)
+                       {
+                               if(search_getfilename(me.campaignGlob, i) == s)
+                                       j = i;
+                       }
+                       if(j < 0)
+                       {
+                               s = strcat("maps/campaign", cvar_defstring("g_campaign_name"), ".txt");
+                               for(i = 0; i < n; ++i)
+                               {
+                                       if(search_getfilename(me.campaignGlob, i) == s)
+                                               j = i;
+                               }
+                       }
+                       if(j < 0)
+                       {
+                               if(step >= 0)
+                                       j = 0;
+                               else
+                                       j = n - 1;
+                       }
+                       else
+                               j = mod(j + step, n);
+                       s = search_getfilename(me.campaignGlob, j);
+                       s = substring(s, 13, strlen(s) - 17);
+                       cvar_set("g_campaign_name", s);
+                       me.loadCvars(me);
+                       canNext = (j != n - 1);
+                       canPrev = (j != 0);
+               }
+       }
+
+       if(me.buttonNext)
+               me.buttonNext.disabled = !canNext;
+       if(me.buttonPrev)
+               me.buttonPrev.disabled = !canPrev;
+}
+
+void MultiCampaign_Next(entity btn, entity me)
+{
+       me.campaignGo(me, +1);
+}
+void MultiCampaign_Prev(entity btn, entity me)
+{
+       me.campaignGo(me, -1);
+}
+
+void XonoticCampaignList_draw(entity me)
+{
+       if(cvar(me.cvarName) != me.campaignIndex || cvar_string("g_campaign_name") != campaign_name)
+               me.loadCvars(me);
+       SUPER(XonoticCampaignList).draw(me);
+}
+
+void XonoticCampaignList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticCampaignList).resizeNotify(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.rowsPerItem - 3, me.emptyLineHeight, me.realFontSize);
+}
+void XonoticCampaignList_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       CampaignList_LoadMap(me, me);
+}
+void XonoticCampaignList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s;
+       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);
+
+       if(draw_PictureSize(strcat("/maps/", campaign_mapname[i])) == '0 0 0')
+               draw_Picture(me.columnPreviewOrigin * eX, "nopreview_map", me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
+       else
+               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(sprintf(_("Level %d: %s"), i+1, s), me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * 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 XonoticCampaignList_setSelected(entity me, float i)
+{
+       // prevent too late items from being played
+       SUPER(XonoticCampaignList).setSelected(me, min(i, me.campaignIndex));
+}
+
+float XonoticCampaignList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_SPACE || scan == K_KP_ENTER)
+               CampaignList_LoadMap(me, me);
+       else
+               return SUPER(XonoticCampaignList).keyDown(me, scan, ascii, shift);
+       return 1;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/charmap.c b/qcsrc/menu/xonotic/charmap.c
deleted file mode 100644 (file)
index 5439c39..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCharmap) EXTENDS(Item)
-       METHOD(XonoticCharmap, configureXonoticCharmap, void(entity, entity))
-       METHOD(XonoticCharmap, mousePress, float(entity, vector))
-       METHOD(XonoticCharmap, mouseRelease, float(entity, vector))
-       METHOD(XonoticCharmap, mouseMove, float(entity, vector))
-       METHOD(XonoticCharmap, mouseDrag, float(entity, vector))
-       METHOD(XonoticCharmap, keyDown, float(entity, float, float, float))
-       METHOD(XonoticCharmap, focusLeave, void(entity))
-       METHOD(XonoticCharmap, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticCharmap, draw, void(entity))
-       ATTRIB(XonoticCharmap, focusable, float, 1)
-
-       METHOD(XonoticCharmap, moveFocus, void(entity, vector, vector))
-       METHOD(XonoticCharmap, enterChar, void(entity))
-       ATTRIB(XonoticCharmap, inputBox, entity, NULL)
-       ATTRIB(XonoticCharmap, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticCharmap, realCellSize, vector, '0 0 0')
-       ATTRIB(XonoticCharmap, focusedCell, vector, '-1 -1 0')
-       ATTRIB(XonoticCharmap, previouslyFocusedCell, vector, '-1 -1 0')
-ENDCLASS(XonoticCharmap)
-entity makeXonoticCharmap(entity controlledInputBox);
-#endif
-
-#ifdef IMPLEMENTATION
-
-const float CHARMAP_COLS = 14;
-const float CHARMAP_ROWS = 10;
-
-string CHARMAP =
-       "★◆■▮▰▬◣◤◥◢◀▲▶▼"
-       "🌍🌎🌏🚀🌌👽🔫⌖❇❈←↑→↓"
-       "☠☣☢⚛⚡⚙🔥❌⚠⛔❰❱❲❳"
-       "😃😊😁😄😆😎😈😇😉😛😝😘❤ "
-       "😐😒😕😮😲😞😟😠😣😭😵😴  "
-       "\xEE\x83\xA1\xEE\x83\xA2\xEE\x83\xA3\xEE\x83\xA4\xEE\x83\xA5\xEE\x83\xA6\xEE\x83\xA7"
-       "\xEE\x83\xA8\xEE\x83\xA9\xEE\x83\xAA\xEE\x83\xAB\xEE\x83\xAC\xEE\x83\xAD\xEE\x83\xAE"
-       "\xEE\x83\xAF\xEE\x83\xB0\xEE\x83\xB1\xEE\x83\xB2\xEE\x83\xB3\xEE\x83\xB4\xEE\x83\xB5"
-       "\xEE\x83\xB6\xEE\x83\xB7\xEE\x83\xB8\xEE\x83\xB9\xEE\x83\xBA\xEE\x80\x90\xEE\x80\x91"
-       "\xEE\x82\xB0\xEE\x82\xB1\xEE\x82\xB2\xEE\x82\xB3\xEE\x82\xB4\xEE\x82\xB5\xEE\x82\xB6"
-       "\xEE\x82\xB7\xEE\x82\xB8\xEE\x82\xB9\xEE\x82\xA1\xEE\x82\xBF\xEE\x82\xA6\xEE\x82\xA5"
-       "\xEE\x83\x81\xEE\x83\x82\xEE\x83\x83\xEE\x83\x84\xEE\x83\x85\xEE\x83\x86\xEE\x83\x87"
-       "\xEE\x83\x88\xEE\x83\x89\xEE\x83\x8A\xEE\x83\x8B\xEE\x83\x8C\xEE\x83\x8D\xEE\x83\x8E"
-       "\xEE\x83\x8F\xEE\x83\x90\xEE\x83\x91\xEE\x83\x92\xEE\x83\x93\xEE\x83\x94\xEE\x83\x95"
-       "\xEE\x83\x96\xEE\x83\x97\xEE\x83\x98\xEE\x83\x99\xEE\x83\x9A\xEE\x81\x9B\xEE\x81\x9D";
-
-string charmap_cellToChar(vector cell)
-{
-       string character = substring(CHARMAP, cell_y * CHARMAP_COLS + cell_x, 1);
-
-       if (character != " ")
-               return character;
-       else
-               return "";
-}
-
-entity makeXonoticCharmap(entity controlledInputBox)
-{
-       entity me;
-       me = spawnXonoticCharmap();
-       me.configureXonoticCharmap(me, controlledInputBox);
-       return me;
-}
-
-void XonoticCharmap_configureXonoticCharmap(entity me, entity controlledInputBox)
-{
-       me.inputBox = controlledInputBox;
-       me.realCellSize = eX / CHARMAP_COLS + eY / CHARMAP_ROWS;
-}
-
-void XonoticCharmap_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(XonoticCharmap).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-
-       float maxFontWidth = SKINFONTSIZE_NORMAL / absSize_x;
-       float maxFontHeight = SKINFONTSIZE_NORMAL / absSize_y;
-
-       if((me.realCellSize_x * absSize_x) > (me.realCellSize_y * absSize_y))
-       {
-               me.realFontSize_x = me.realCellSize_y * absSize_y / absSize_x;
-               me.realFontSize_y = me.realCellSize_y;
-       }
-       else
-       {
-               me.realFontSize_x = me.realCellSize_x;
-               me.realFontSize_y = me.realCellSize_x * absSize_x / absSize_y;
-       }
-
-       if(me.realFontSize_x > maxFontWidth || me.realFontSize_y > maxFontHeight)
-               me.realFontSize = eX * maxFontWidth + eY * maxFontHeight;
-}
-
-float XonoticCharmap_mouseMove(entity me, vector coords)
-{
-       me.focusedCell_x = floor(coords_x * CHARMAP_COLS);
-       me.focusedCell_y = floor(coords_y * CHARMAP_ROWS);
-
-       if(me.focusedCell_x < 0 || me.focusedCell_y < 0 ||
-          me.focusedCell_x >= CHARMAP_COLS || me.focusedCell_y >= CHARMAP_ROWS)
-       {
-               me.focusedCell = '-1 -1 0';
-               return 0;
-       }
-
-       return 1;
-}
-
-float XonoticCharmap_mouseDrag(entity me, vector coords)
-{
-       return me.mouseMove(me, coords);
-}
-
-float XonoticCharmap_mousePress(entity me, vector coords)
-{
-       me.mouseMove(me, coords);
-
-       if(me.focusedCell_x >= 0)
-       {
-               me.pressed = 1;
-               me.previouslyFocusedCell = me.focusedCell;
-       }
-
-       return 1;
-}
-
-float XonoticCharmap_mouseRelease(entity me, vector coords)
-{
-       if(!me.pressed)
-               return 0;
-
-       me.mouseMove(me, coords);
-
-       if(me.focusedCell == me.previouslyFocusedCell)
-               me.enterChar(me);
-
-       me.pressed = 0;
-       return 1;
-}
-
-float XonoticCharmap_keyDown(entity me, float key, float ascii, float shift)
-{
-       switch(key)
-       {
-               case K_LEFTARROW:
-               case K_KP_LEFTARROW:
-                       me.moveFocus(me, me.focusedCell, '-1 0 0');
-                       return 1;
-               case K_RIGHTARROW:
-               case K_KP_RIGHTARROW:
-                       me.moveFocus(me, me.focusedCell, '1 0 0');
-                       return 1;
-               case K_UPARROW:
-               case K_KP_UPARROW:
-                       me.moveFocus(me, me.focusedCell, '0 -1 0');
-                       return 1;
-               case K_DOWNARROW:
-               case K_KP_DOWNARROW:
-                       me.moveFocus(me, me.focusedCell, '0 1 0');
-                       return 1;
-               case K_HOME:
-               case K_KP_HOME:
-                       me.focusedCell = '0 0 0';
-                       return 1;
-               case K_END:
-               case K_KP_END:
-                       me.focusedCell_x = CHARMAP_COLS - 1;
-                       me.focusedCell_y = CHARMAP_ROWS - 1;
-                       return 1;
-               case K_ENTER:
-               case K_KP_ENTER:
-               case K_INS:
-               case K_KP_INS:
-                       me.enterChar(me);
-                       return 1;
-               default:
-                       return me.inputBox.keyDown(me.inputBox, key, ascii, shift);
-       }
-}
-
-void XonoticCharmap_moveFocus(entity me, vector initialCell, vector step)
-{
-       me.focusedCell_x = mod(me.focusedCell_x + step_x + CHARMAP_COLS, CHARMAP_COLS);
-       me.focusedCell_y = mod(me.focusedCell_y + step_y + CHARMAP_ROWS, CHARMAP_ROWS);
-
-       if(me.focusedCell != initialCell) // Recursion break
-               if(charmap_cellToChar(me.focusedCell) == "")
-                       me.moveFocus(me, initialCell, step);
-}
-
-void XonoticCharmap_enterChar(entity me)
-{
-       string character = charmap_cellToChar(me.focusedCell);
-       if(character != "")
-               me.inputBox.enterText(me.inputBox, character);
-}
-
-void XonoticCharmap_focusLeave(entity me)
-{
-       me.inputBox.saveCvars(me.inputBox);
-}
-
-void XonoticCharmap_draw(entity me)
-{
-       string character;
-       vector cell, cellPos, charPos;
-       cell = '0 0 0';
-       cellPos = '0 0 0';
-       charPos = '0 0 0';
-
-       float CHAR_OFFSET_X = me.realCellSize_x / 2;
-       float CHAR_OFFSET_Y = (me.realCellSize_y - me.realFontSize_y) / 2;
-
-       for(cell_y = 0; cell_y < CHARMAP_ROWS; ++cell_y)
-       {
-               charPos_y = cell_y / CHARMAP_ROWS + CHAR_OFFSET_Y;
-               for(cell_x = 0; cell_x < CHARMAP_COLS; ++cell_x)
-               {
-                       character = charmap_cellToChar(cell);
-
-                       if(character == "")
-                               continue;
-
-                       // Draw focused cell
-                       if(cell == me.focusedCell && me.focused)
-                       {
-                               if(!me.pressed || me.focusedCell == me.previouslyFocusedCell)
-                               {
-                                       cellPos_x = mod(me.focusedCell_x, CHARMAP_COLS) / CHARMAP_COLS;
-                                       cellPos_y = mod(me.focusedCell_y, CHARMAP_ROWS) / CHARMAP_ROWS;
-                                       draw_Fill(cellPos, me.realCellSize, SKINCOLOR_CHARMAP_FOCUS, SKINALPHA_CHARMAP_FOCUS);
-                               }
-                       }
-
-                       // Draw character
-                       charPos_x = cell_x / CHARMAP_COLS + CHAR_OFFSET_X;
-                       draw_CenterText(charPos, character, me.realFontSize, SKINCOLOR_CHARMAP_CHAR, SKINALPHA_CHARMAP_CHAR, 0);
-               }
-       }
-}
-#endif
diff --git a/qcsrc/menu/xonotic/charmap.qc b/qcsrc/menu/xonotic/charmap.qc
new file mode 100644 (file)
index 0000000..5439c39
--- /dev/null
@@ -0,0 +1,240 @@
+#ifdef INTERFACE
+CLASS(XonoticCharmap) EXTENDS(Item)
+       METHOD(XonoticCharmap, configureXonoticCharmap, void(entity, entity))
+       METHOD(XonoticCharmap, mousePress, float(entity, vector))
+       METHOD(XonoticCharmap, mouseRelease, float(entity, vector))
+       METHOD(XonoticCharmap, mouseMove, float(entity, vector))
+       METHOD(XonoticCharmap, mouseDrag, float(entity, vector))
+       METHOD(XonoticCharmap, keyDown, float(entity, float, float, float))
+       METHOD(XonoticCharmap, focusLeave, void(entity))
+       METHOD(XonoticCharmap, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticCharmap, draw, void(entity))
+       ATTRIB(XonoticCharmap, focusable, float, 1)
+
+       METHOD(XonoticCharmap, moveFocus, void(entity, vector, vector))
+       METHOD(XonoticCharmap, enterChar, void(entity))
+       ATTRIB(XonoticCharmap, inputBox, entity, NULL)
+       ATTRIB(XonoticCharmap, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticCharmap, realCellSize, vector, '0 0 0')
+       ATTRIB(XonoticCharmap, focusedCell, vector, '-1 -1 0')
+       ATTRIB(XonoticCharmap, previouslyFocusedCell, vector, '-1 -1 0')
+ENDCLASS(XonoticCharmap)
+entity makeXonoticCharmap(entity controlledInputBox);
+#endif
+
+#ifdef IMPLEMENTATION
+
+const float CHARMAP_COLS = 14;
+const float CHARMAP_ROWS = 10;
+
+string CHARMAP =
+       "★◆■▮▰▬◣◤◥◢◀▲▶▼"
+       "🌍🌎🌏🚀🌌👽🔫⌖❇❈←↑→↓"
+       "☠☣☢⚛⚡⚙🔥❌⚠⛔❰❱❲❳"
+       "😃😊😁😄😆😎😈😇😉😛😝😘❤ "
+       "😐😒😕😮😲😞😟😠😣😭😵😴  "
+       "\xEE\x83\xA1\xEE\x83\xA2\xEE\x83\xA3\xEE\x83\xA4\xEE\x83\xA5\xEE\x83\xA6\xEE\x83\xA7"
+       "\xEE\x83\xA8\xEE\x83\xA9\xEE\x83\xAA\xEE\x83\xAB\xEE\x83\xAC\xEE\x83\xAD\xEE\x83\xAE"
+       "\xEE\x83\xAF\xEE\x83\xB0\xEE\x83\xB1\xEE\x83\xB2\xEE\x83\xB3\xEE\x83\xB4\xEE\x83\xB5"
+       "\xEE\x83\xB6\xEE\x83\xB7\xEE\x83\xB8\xEE\x83\xB9\xEE\x83\xBA\xEE\x80\x90\xEE\x80\x91"
+       "\xEE\x82\xB0\xEE\x82\xB1\xEE\x82\xB2\xEE\x82\xB3\xEE\x82\xB4\xEE\x82\xB5\xEE\x82\xB6"
+       "\xEE\x82\xB7\xEE\x82\xB8\xEE\x82\xB9\xEE\x82\xA1\xEE\x82\xBF\xEE\x82\xA6\xEE\x82\xA5"
+       "\xEE\x83\x81\xEE\x83\x82\xEE\x83\x83\xEE\x83\x84\xEE\x83\x85\xEE\x83\x86\xEE\x83\x87"
+       "\xEE\x83\x88\xEE\x83\x89\xEE\x83\x8A\xEE\x83\x8B\xEE\x83\x8C\xEE\x83\x8D\xEE\x83\x8E"
+       "\xEE\x83\x8F\xEE\x83\x90\xEE\x83\x91\xEE\x83\x92\xEE\x83\x93\xEE\x83\x94\xEE\x83\x95"
+       "\xEE\x83\x96\xEE\x83\x97\xEE\x83\x98\xEE\x83\x99\xEE\x83\x9A\xEE\x81\x9B\xEE\x81\x9D";
+
+string charmap_cellToChar(vector cell)
+{
+       string character = substring(CHARMAP, cell_y * CHARMAP_COLS + cell_x, 1);
+
+       if (character != " ")
+               return character;
+       else
+               return "";
+}
+
+entity makeXonoticCharmap(entity controlledInputBox)
+{
+       entity me;
+       me = spawnXonoticCharmap();
+       me.configureXonoticCharmap(me, controlledInputBox);
+       return me;
+}
+
+void XonoticCharmap_configureXonoticCharmap(entity me, entity controlledInputBox)
+{
+       me.inputBox = controlledInputBox;
+       me.realCellSize = eX / CHARMAP_COLS + eY / CHARMAP_ROWS;
+}
+
+void XonoticCharmap_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(XonoticCharmap).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+
+       float maxFontWidth = SKINFONTSIZE_NORMAL / absSize_x;
+       float maxFontHeight = SKINFONTSIZE_NORMAL / absSize_y;
+
+       if((me.realCellSize_x * absSize_x) > (me.realCellSize_y * absSize_y))
+       {
+               me.realFontSize_x = me.realCellSize_y * absSize_y / absSize_x;
+               me.realFontSize_y = me.realCellSize_y;
+       }
+       else
+       {
+               me.realFontSize_x = me.realCellSize_x;
+               me.realFontSize_y = me.realCellSize_x * absSize_x / absSize_y;
+       }
+
+       if(me.realFontSize_x > maxFontWidth || me.realFontSize_y > maxFontHeight)
+               me.realFontSize = eX * maxFontWidth + eY * maxFontHeight;
+}
+
+float XonoticCharmap_mouseMove(entity me, vector coords)
+{
+       me.focusedCell_x = floor(coords_x * CHARMAP_COLS);
+       me.focusedCell_y = floor(coords_y * CHARMAP_ROWS);
+
+       if(me.focusedCell_x < 0 || me.focusedCell_y < 0 ||
+          me.focusedCell_x >= CHARMAP_COLS || me.focusedCell_y >= CHARMAP_ROWS)
+       {
+               me.focusedCell = '-1 -1 0';
+               return 0;
+       }
+
+       return 1;
+}
+
+float XonoticCharmap_mouseDrag(entity me, vector coords)
+{
+       return me.mouseMove(me, coords);
+}
+
+float XonoticCharmap_mousePress(entity me, vector coords)
+{
+       me.mouseMove(me, coords);
+
+       if(me.focusedCell_x >= 0)
+       {
+               me.pressed = 1;
+               me.previouslyFocusedCell = me.focusedCell;
+       }
+
+       return 1;
+}
+
+float XonoticCharmap_mouseRelease(entity me, vector coords)
+{
+       if(!me.pressed)
+               return 0;
+
+       me.mouseMove(me, coords);
+
+       if(me.focusedCell == me.previouslyFocusedCell)
+               me.enterChar(me);
+
+       me.pressed = 0;
+       return 1;
+}
+
+float XonoticCharmap_keyDown(entity me, float key, float ascii, float shift)
+{
+       switch(key)
+       {
+               case K_LEFTARROW:
+               case K_KP_LEFTARROW:
+                       me.moveFocus(me, me.focusedCell, '-1 0 0');
+                       return 1;
+               case K_RIGHTARROW:
+               case K_KP_RIGHTARROW:
+                       me.moveFocus(me, me.focusedCell, '1 0 0');
+                       return 1;
+               case K_UPARROW:
+               case K_KP_UPARROW:
+                       me.moveFocus(me, me.focusedCell, '0 -1 0');
+                       return 1;
+               case K_DOWNARROW:
+               case K_KP_DOWNARROW:
+                       me.moveFocus(me, me.focusedCell, '0 1 0');
+                       return 1;
+               case K_HOME:
+               case K_KP_HOME:
+                       me.focusedCell = '0 0 0';
+                       return 1;
+               case K_END:
+               case K_KP_END:
+                       me.focusedCell_x = CHARMAP_COLS - 1;
+                       me.focusedCell_y = CHARMAP_ROWS - 1;
+                       return 1;
+               case K_ENTER:
+               case K_KP_ENTER:
+               case K_INS:
+               case K_KP_INS:
+                       me.enterChar(me);
+                       return 1;
+               default:
+                       return me.inputBox.keyDown(me.inputBox, key, ascii, shift);
+       }
+}
+
+void XonoticCharmap_moveFocus(entity me, vector initialCell, vector step)
+{
+       me.focusedCell_x = mod(me.focusedCell_x + step_x + CHARMAP_COLS, CHARMAP_COLS);
+       me.focusedCell_y = mod(me.focusedCell_y + step_y + CHARMAP_ROWS, CHARMAP_ROWS);
+
+       if(me.focusedCell != initialCell) // Recursion break
+               if(charmap_cellToChar(me.focusedCell) == "")
+                       me.moveFocus(me, initialCell, step);
+}
+
+void XonoticCharmap_enterChar(entity me)
+{
+       string character = charmap_cellToChar(me.focusedCell);
+       if(character != "")
+               me.inputBox.enterText(me.inputBox, character);
+}
+
+void XonoticCharmap_focusLeave(entity me)
+{
+       me.inputBox.saveCvars(me.inputBox);
+}
+
+void XonoticCharmap_draw(entity me)
+{
+       string character;
+       vector cell, cellPos, charPos;
+       cell = '0 0 0';
+       cellPos = '0 0 0';
+       charPos = '0 0 0';
+
+       float CHAR_OFFSET_X = me.realCellSize_x / 2;
+       float CHAR_OFFSET_Y = (me.realCellSize_y - me.realFontSize_y) / 2;
+
+       for(cell_y = 0; cell_y < CHARMAP_ROWS; ++cell_y)
+       {
+               charPos_y = cell_y / CHARMAP_ROWS + CHAR_OFFSET_Y;
+               for(cell_x = 0; cell_x < CHARMAP_COLS; ++cell_x)
+               {
+                       character = charmap_cellToChar(cell);
+
+                       if(character == "")
+                               continue;
+
+                       // Draw focused cell
+                       if(cell == me.focusedCell && me.focused)
+                       {
+                               if(!me.pressed || me.focusedCell == me.previouslyFocusedCell)
+                               {
+                                       cellPos_x = mod(me.focusedCell_x, CHARMAP_COLS) / CHARMAP_COLS;
+                                       cellPos_y = mod(me.focusedCell_y, CHARMAP_ROWS) / CHARMAP_ROWS;
+                                       draw_Fill(cellPos, me.realCellSize, SKINCOLOR_CHARMAP_FOCUS, SKINALPHA_CHARMAP_FOCUS);
+                               }
+                       }
+
+                       // Draw character
+                       charPos_x = cell_x / CHARMAP_COLS + CHAR_OFFSET_X;
+                       draw_CenterText(charPos, character, me.realFontSize, SKINCOLOR_CHARMAP_CHAR, SKINALPHA_CHARMAP_CHAR, 0);
+               }
+       }
+}
+#endif
diff --git a/qcsrc/menu/xonotic/checkbox.c b/qcsrc/menu/xonotic/checkbox.c
deleted file mode 100644 (file)
index 631a430..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCheckBox) EXTENDS(CheckBox)
-       METHOD(XonoticCheckBox, configureXonoticCheckBox, void(entity, float, float, string, string))
-       METHOD(XonoticCheckBox, setChecked, void(entity, float))
-       ATTRIB(XonoticCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticCheckBox, image, string, SKINGFX_CHECKBOX)
-       ATTRIB(XonoticCheckBox, yesValue, float, 1)
-       ATTRIB(XonoticCheckBox, noValue, float, 0)
-
-       ATTRIB(XonoticCheckBox, color, vector, SKINCOLOR_CHECKBOX_N)
-       ATTRIB(XonoticCheckBox, colorC, vector, SKINCOLOR_CHECKBOX_C)
-       ATTRIB(XonoticCheckBox, colorF, vector, SKINCOLOR_CHECKBOX_F)
-       ATTRIB(XonoticCheckBox, colorD, vector, SKINCOLOR_CHECKBOX_D)
-
-       ATTRIB(XonoticCheckBox, cvarName, string, string_null)
-       METHOD(XonoticCheckBox, loadCvars, void(entity))
-       METHOD(XonoticCheckBox, saveCvars, void(entity))
-       ATTRIB(XonoticCheckBox, sendCvars, float, 0)
-
-       ATTRIB(XonoticCheckBox, alpha, float, SKINALPHA_TEXT)
-       ATTRIB(XonoticCheckBox, disabledAlpha, float, SKINALPHA_DISABLED)
-ENDCLASS(XonoticCheckBox)
-entity makeXonoticCheckBox(float, string, string);
-entity makeXonoticCheckBoxEx(float, float, string, string);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticCheckBox(float isInverted, string theCvar, string theText)
-{
-       float y, n;
-       if(isInverted > 1)
-       {
-               n = isInverted - 1;
-               y = -n;
-       }
-       else if(isInverted < -1)
-       {
-               n = isInverted + 1;
-               y = -n;
-       }
-       else if(isInverted == 1)
-       {
-               n = 1;
-               y = 0;
-       }
-       else
-       {
-               n = 0;
-               y = 1;
-       }
-       return makeXonoticCheckBoxEx(y, n, theCvar, theText);
-}
-entity makeXonoticCheckBoxEx(float theYesValue, float theNoValue, string theCvar, string theText)
-{
-       entity me;
-       me = spawnXonoticCheckBox();
-       me.configureXonoticCheckBox(me, theYesValue, theNoValue, theCvar, theText);
-       return me;
-}
-void XonoticCheckBox_configureXonoticCheckBox(entity me, float theYesValue, float theNoValue, string theCvar, string theText)
-{
-       me.yesValue = theYesValue;
-       me.noValue = theNoValue;
-       me.checked = 0;
-       if(theCvar)
-       {
-               me.cvarName = theCvar;
-               me.tooltip = getZonedTooltipForIdentifier(theCvar);
-               me.loadCvars(me);
-       }
-       me.configureCheckBox(me, theText, me.fontSize, me.image);
-}
-void XonoticCheckBox_setChecked(entity me, float val)
-{
-       if(val != me.checked)
-       {
-               me.checked = val;
-               me.saveCvars(me);
-       }
-}
-void XonoticCheckBox_loadCvars(entity me)
-{
-       float m, d;
-
-       if (!me.cvarName)
-               return;
-
-       m = (me.yesValue + me.noValue) * 0.5;
-       d = (cvar(me.cvarName) - m) / (me.yesValue - m);
-       me.checked = (d > 0);
-}
-void XonoticCheckBox_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       if(me.checked)
-               cvar_set(me.cvarName, ftos(me.yesValue));
-       else
-               cvar_set(me.cvarName, ftos(me.noValue));
-
-       CheckSendCvars(me, me.cvarName);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/checkbox.qc b/qcsrc/menu/xonotic/checkbox.qc
new file mode 100644 (file)
index 0000000..631a430
--- /dev/null
@@ -0,0 +1,104 @@
+#ifdef INTERFACE
+CLASS(XonoticCheckBox) EXTENDS(CheckBox)
+       METHOD(XonoticCheckBox, configureXonoticCheckBox, void(entity, float, float, string, string))
+       METHOD(XonoticCheckBox, setChecked, void(entity, float))
+       ATTRIB(XonoticCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticCheckBox, image, string, SKINGFX_CHECKBOX)
+       ATTRIB(XonoticCheckBox, yesValue, float, 1)
+       ATTRIB(XonoticCheckBox, noValue, float, 0)
+
+       ATTRIB(XonoticCheckBox, color, vector, SKINCOLOR_CHECKBOX_N)
+       ATTRIB(XonoticCheckBox, colorC, vector, SKINCOLOR_CHECKBOX_C)
+       ATTRIB(XonoticCheckBox, colorF, vector, SKINCOLOR_CHECKBOX_F)
+       ATTRIB(XonoticCheckBox, colorD, vector, SKINCOLOR_CHECKBOX_D)
+
+       ATTRIB(XonoticCheckBox, cvarName, string, string_null)
+       METHOD(XonoticCheckBox, loadCvars, void(entity))
+       METHOD(XonoticCheckBox, saveCvars, void(entity))
+       ATTRIB(XonoticCheckBox, sendCvars, float, 0)
+
+       ATTRIB(XonoticCheckBox, alpha, float, SKINALPHA_TEXT)
+       ATTRIB(XonoticCheckBox, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(XonoticCheckBox)
+entity makeXonoticCheckBox(float, string, string);
+entity makeXonoticCheckBoxEx(float, float, string, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticCheckBox(float isInverted, string theCvar, string theText)
+{
+       float y, n;
+       if(isInverted > 1)
+       {
+               n = isInverted - 1;
+               y = -n;
+       }
+       else if(isInverted < -1)
+       {
+               n = isInverted + 1;
+               y = -n;
+       }
+       else if(isInverted == 1)
+       {
+               n = 1;
+               y = 0;
+       }
+       else
+       {
+               n = 0;
+               y = 1;
+       }
+       return makeXonoticCheckBoxEx(y, n, theCvar, theText);
+}
+entity makeXonoticCheckBoxEx(float theYesValue, float theNoValue, string theCvar, string theText)
+{
+       entity me;
+       me = spawnXonoticCheckBox();
+       me.configureXonoticCheckBox(me, theYesValue, theNoValue, theCvar, theText);
+       return me;
+}
+void XonoticCheckBox_configureXonoticCheckBox(entity me, float theYesValue, float theNoValue, string theCvar, string theText)
+{
+       me.yesValue = theYesValue;
+       me.noValue = theNoValue;
+       me.checked = 0;
+       if(theCvar)
+       {
+               me.cvarName = theCvar;
+               me.tooltip = getZonedTooltipForIdentifier(theCvar);
+               me.loadCvars(me);
+       }
+       me.configureCheckBox(me, theText, me.fontSize, me.image);
+}
+void XonoticCheckBox_setChecked(entity me, float val)
+{
+       if(val != me.checked)
+       {
+               me.checked = val;
+               me.saveCvars(me);
+       }
+}
+void XonoticCheckBox_loadCvars(entity me)
+{
+       float m, d;
+
+       if (!me.cvarName)
+               return;
+
+       m = (me.yesValue + me.noValue) * 0.5;
+       d = (cvar(me.cvarName) - m) / (me.yesValue - m);
+       me.checked = (d > 0);
+}
+void XonoticCheckBox_saveCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       if(me.checked)
+               cvar_set(me.cvarName, ftos(me.yesValue));
+       else
+               cvar_set(me.cvarName, ftos(me.noValue));
+
+       CheckSendCvars(me, me.cvarName);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/checkbox_slider_invalid.c b/qcsrc/menu/xonotic/checkbox_slider_invalid.c
deleted file mode 100644 (file)
index e304318..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticSliderCheckBox) EXTENDS(CheckBox)
-       METHOD(XonoticSliderCheckBox, configureXonoticSliderCheckBox, void(entity, float, float, entity, string))
-       METHOD(XonoticSliderCheckBox, setChecked, void(entity, float))
-       METHOD(XonoticSliderCheckBox, draw, void(entity))
-       ATTRIB(XonoticSliderCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticSliderCheckBox, image, string, SKINGFX_CHECKBOX)
-
-       ATTRIB(XonoticSliderCheckBox, color, vector, SKINCOLOR_CHECKBOX_N)
-       ATTRIB(XonoticSliderCheckBox, colorC, vector, SKINCOLOR_CHECKBOX_C)
-       ATTRIB(XonoticSliderCheckBox, colorF, vector, SKINCOLOR_CHECKBOX_F)
-       ATTRIB(XonoticSliderCheckBox, colorD, vector, SKINCOLOR_CHECKBOX_D)
-
-       ATTRIB(XonoticSliderCheckBox, alpha, float, SKINALPHA_TEXT)
-       ATTRIB(XonoticSliderCheckBox, disabledAlpha, float, SKINALPHA_DISABLED)
-
-       ATTRIB(XonoticSliderCheckBox, controlledSlider, entity, NULL)
-       ATTRIB(XonoticSliderCheckBox, offValue, float, -1)
-       ATTRIB(XonoticSliderCheckBox, inverted, float, 0)
-       ATTRIB(XonoticSliderCheckBox, savedValue, float, -1)
-ENDCLASS(XonoticSliderCheckBox)
-entity makeXonoticSliderCheckBox(float, float, entity, string);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticSliderCheckBox(float theOffValue, float isInverted, entity theControlledSlider, string theText)
-{
-       entity me;
-       me = spawnXonoticSliderCheckBox();
-       me.configureXonoticSliderCheckBox(me, theOffValue, isInverted, theControlledSlider, theText);
-       return me;
-}
-void XonoticSliderCheckBox_configureXonoticSliderCheckBox(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);
-       me.tooltip = theControlledSlider.tooltip;
-       me.cvarName = theControlledSlider.cvarName; // in case we want to display the cvar in the tooltip
-}
-void XonoticSliderCheckBox_draw(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;
-       SUPER(XonoticSliderCheckBox).draw(me);
-}
-void XonoticSliderCheckBox_setChecked(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
diff --git a/qcsrc/menu/xonotic/checkbox_slider_invalid.qc b/qcsrc/menu/xonotic/checkbox_slider_invalid.qc
new file mode 100644 (file)
index 0000000..e304318
--- /dev/null
@@ -0,0 +1,65 @@
+#ifdef INTERFACE
+CLASS(XonoticSliderCheckBox) EXTENDS(CheckBox)
+       METHOD(XonoticSliderCheckBox, configureXonoticSliderCheckBox, void(entity, float, float, entity, string))
+       METHOD(XonoticSliderCheckBox, setChecked, void(entity, float))
+       METHOD(XonoticSliderCheckBox, draw, void(entity))
+       ATTRIB(XonoticSliderCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticSliderCheckBox, image, string, SKINGFX_CHECKBOX)
+
+       ATTRIB(XonoticSliderCheckBox, color, vector, SKINCOLOR_CHECKBOX_N)
+       ATTRIB(XonoticSliderCheckBox, colorC, vector, SKINCOLOR_CHECKBOX_C)
+       ATTRIB(XonoticSliderCheckBox, colorF, vector, SKINCOLOR_CHECKBOX_F)
+       ATTRIB(XonoticSliderCheckBox, colorD, vector, SKINCOLOR_CHECKBOX_D)
+
+       ATTRIB(XonoticSliderCheckBox, alpha, float, SKINALPHA_TEXT)
+       ATTRIB(XonoticSliderCheckBox, disabledAlpha, float, SKINALPHA_DISABLED)
+
+       ATTRIB(XonoticSliderCheckBox, controlledSlider, entity, NULL)
+       ATTRIB(XonoticSliderCheckBox, offValue, float, -1)
+       ATTRIB(XonoticSliderCheckBox, inverted, float, 0)
+       ATTRIB(XonoticSliderCheckBox, savedValue, float, -1)
+ENDCLASS(XonoticSliderCheckBox)
+entity makeXonoticSliderCheckBox(float, float, entity, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticSliderCheckBox(float theOffValue, float isInverted, entity theControlledSlider, string theText)
+{
+       entity me;
+       me = spawnXonoticSliderCheckBox();
+       me.configureXonoticSliderCheckBox(me, theOffValue, isInverted, theControlledSlider, theText);
+       return me;
+}
+void XonoticSliderCheckBox_configureXonoticSliderCheckBox(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);
+       me.tooltip = theControlledSlider.tooltip;
+       me.cvarName = theControlledSlider.cvarName; // in case we want to display the cvar in the tooltip
+}
+void XonoticSliderCheckBox_draw(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;
+       SUPER(XonoticSliderCheckBox).draw(me);
+}
+void XonoticSliderCheckBox_setChecked(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
diff --git a/qcsrc/menu/xonotic/checkbox_string.c b/qcsrc/menu/xonotic/checkbox_string.c
deleted file mode 100644 (file)
index aeda757..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCheckBoxString) EXTENDS(CheckBox)
-       METHOD(XonoticCheckBoxString, configureXonoticCheckBoxString, void(entity, string, string, string, string))
-       METHOD(XonoticCheckBoxString, setChecked, void(entity, float))
-       ATTRIB(XonoticCheckBoxString, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticCheckBoxString, image, string, SKINGFX_CHECKBOX)
-       ATTRIB(XonoticCheckBoxString, yesString, string, string_null)
-       ATTRIB(XonoticCheckBoxString, noString, string, string_null)
-
-       ATTRIB(XonoticCheckBoxString, color, vector, SKINCOLOR_CHECKBOX_N)
-       ATTRIB(XonoticCheckBoxString, colorC, vector, SKINCOLOR_CHECKBOX_C)
-       ATTRIB(XonoticCheckBoxString, colorF, vector, SKINCOLOR_CHECKBOX_F)
-       ATTRIB(XonoticCheckBoxString, colorD, vector, SKINCOLOR_CHECKBOX_D)
-
-       ATTRIB(XonoticCheckBoxString, cvarName, string, string_null)
-       METHOD(XonoticCheckBoxString, loadCvars, void(entity))
-       METHOD(XonoticCheckBoxString, saveCvars, void(entity))
-       ATTRIB(XonoticCheckBoxString, sendCvars, float, 0)
-
-       ATTRIB(XonoticCheckBoxString, alpha, float, SKINALPHA_TEXT)
-       ATTRIB(XonoticCheckBoxString, disabledAlpha, float, SKINALPHA_DISABLED)
-ENDCLASS(XonoticCheckBoxString)
-entity makeXonoticCheckBoxString(string, string, string, string);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticCheckBoxString(string theYesValue, string theNoValue, string theCvar, string theText)
-{
-       entity me;
-       me = spawnXonoticCheckBoxString();
-       me.configureXonoticCheckBoxString(me, theYesValue, theNoValue, theCvar, theText);
-       return me;
-}
-void XonoticCheckBoxString_configureXonoticCheckBoxString(entity me, string theYesValue, string theNoValue, string theCvar, string theText)
-{
-       me.yesString = theYesValue;
-       me.noString = theNoValue;
-       me.checked = 0;
-       if(theCvar)
-       {
-               me.cvarName = theCvar;
-               me.tooltip = getZonedTooltipForIdentifier(theCvar);
-               me.loadCvars(me);
-       }
-       me.configureCheckBox(me, theText, me.fontSize, me.image);
-}
-void XonoticCheckBoxString_setChecked(entity me, float foo)
-{
-       me.checked = !me.checked;
-       me.saveCvars(me);
-}
-void XonoticCheckBoxString_loadCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       if(cvar_string(me.cvarName) == me.yesString)
-               me.checked = 1;
-}
-void XonoticCheckBoxString_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       if(me.checked)
-               cvar_set(me.cvarName, me.yesString);
-       else
-               cvar_set(me.cvarName, me.noString);
-
-       CheckSendCvars(me, me.cvarName);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/checkbox_string.qc b/qcsrc/menu/xonotic/checkbox_string.qc
new file mode 100644 (file)
index 0000000..aeda757
--- /dev/null
@@ -0,0 +1,72 @@
+#ifdef INTERFACE
+CLASS(XonoticCheckBoxString) EXTENDS(CheckBox)
+       METHOD(XonoticCheckBoxString, configureXonoticCheckBoxString, void(entity, string, string, string, string))
+       METHOD(XonoticCheckBoxString, setChecked, void(entity, float))
+       ATTRIB(XonoticCheckBoxString, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticCheckBoxString, image, string, SKINGFX_CHECKBOX)
+       ATTRIB(XonoticCheckBoxString, yesString, string, string_null)
+       ATTRIB(XonoticCheckBoxString, noString, string, string_null)
+
+       ATTRIB(XonoticCheckBoxString, color, vector, SKINCOLOR_CHECKBOX_N)
+       ATTRIB(XonoticCheckBoxString, colorC, vector, SKINCOLOR_CHECKBOX_C)
+       ATTRIB(XonoticCheckBoxString, colorF, vector, SKINCOLOR_CHECKBOX_F)
+       ATTRIB(XonoticCheckBoxString, colorD, vector, SKINCOLOR_CHECKBOX_D)
+
+       ATTRIB(XonoticCheckBoxString, cvarName, string, string_null)
+       METHOD(XonoticCheckBoxString, loadCvars, void(entity))
+       METHOD(XonoticCheckBoxString, saveCvars, void(entity))
+       ATTRIB(XonoticCheckBoxString, sendCvars, float, 0)
+
+       ATTRIB(XonoticCheckBoxString, alpha, float, SKINALPHA_TEXT)
+       ATTRIB(XonoticCheckBoxString, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(XonoticCheckBoxString)
+entity makeXonoticCheckBoxString(string, string, string, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticCheckBoxString(string theYesValue, string theNoValue, string theCvar, string theText)
+{
+       entity me;
+       me = spawnXonoticCheckBoxString();
+       me.configureXonoticCheckBoxString(me, theYesValue, theNoValue, theCvar, theText);
+       return me;
+}
+void XonoticCheckBoxString_configureXonoticCheckBoxString(entity me, string theYesValue, string theNoValue, string theCvar, string theText)
+{
+       me.yesString = theYesValue;
+       me.noString = theNoValue;
+       me.checked = 0;
+       if(theCvar)
+       {
+               me.cvarName = theCvar;
+               me.tooltip = getZonedTooltipForIdentifier(theCvar);
+               me.loadCvars(me);
+       }
+       me.configureCheckBox(me, theText, me.fontSize, me.image);
+}
+void XonoticCheckBoxString_setChecked(entity me, float foo)
+{
+       me.checked = !me.checked;
+       me.saveCvars(me);
+}
+void XonoticCheckBoxString_loadCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       if(cvar_string(me.cvarName) == me.yesString)
+               me.checked = 1;
+}
+void XonoticCheckBoxString_saveCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       if(me.checked)
+               cvar_set(me.cvarName, me.yesString);
+       else
+               cvar_set(me.cvarName, me.noString);
+
+       CheckSendCvars(me, me.cvarName);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/colorbutton.c b/qcsrc/menu/xonotic/colorbutton.c
deleted file mode 100644 (file)
index bcbdfee..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticColorButton) EXTENDS(RadioButton)
-       METHOD(XonoticColorButton, configureXonoticColorButton, void(entity, float, float, float))
-       METHOD(XonoticColorButton, setChecked, void(entity, float))
-       METHOD(XonoticColorButton, draw, void(entity))
-       ATTRIB(XonoticColorButton, fontSize, float, 0)
-       ATTRIB(XonoticColorButton, image, string, SKINGFX_COLORBUTTON)
-
-       ATTRIB(XonoticColorButton, useDownAsChecked, float, 1)
-
-       ATTRIB(XonoticColorButton, cvarPart, float, 0)
-       ATTRIB(XonoticColorButton, cvarName, string, string_null)
-       ATTRIB(XonoticColorButton, cvarValueFloat, float, 0)
-       METHOD(XonoticColorButton, loadCvars, void(entity))
-       METHOD(XonoticColorButton, saveCvars, void(entity))
-ENDCLASS(XonoticColorButton)
-entity makeXonoticColorButton(float, float, float);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticColorButton(float theGroup, float theColor, float theValue)
-{
-       entity me;
-       me = spawnXonoticColorButton();
-       me.configureXonoticColorButton(me, theGroup, theColor, theValue);
-       return me;
-}
-void XonoticColorButton_configureXonoticColorButton(entity me, float theGroup, float theColor, float theValue)
-{
-       switch(theValue)
-       {
-               // rearrange 1..14 for rainbow order
-               case  1: theValue = 10; break;
-               case  2: theValue =  4; break;
-               case  3: theValue =  1; break;
-               case  4: theValue = 14; break;
-               case  5: theValue = 12; break;
-               case  6: theValue =  7; break;
-               case  7: theValue =  3; break;
-               case  8: theValue =  2; break;
-               case  9: theValue =  6; break;
-               case 10: theValue =  5; break;
-               case 11: theValue = 13; break;
-               case 12: theValue = 11; break;
-               case 13: theValue =  8; break;
-               case 14: theValue =  9; break;
-               default:
-                       // no change
-                       break;
-       }
-       me.cvarName = "_cl_color";
-       me.cvarValueFloat = theValue;
-       me.cvarPart = theColor;
-       me.loadCvars(me);
-       me.configureRadioButton(me, string_null, me.fontSize, me.image, theGroup, 0);
-}
-void XonoticColorButton_setChecked(entity me, float val)
-{
-       if(val != me.checked)
-       {
-               me.checked = val;
-               me.saveCvars(me);
-       }
-}
-void XonoticColorButton_loadCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       if(cvar_string(me.cvarName) == cvar_defstring(me.cvarName))
-               cvar_set(me.cvarName, ftos(16 * floor(random() * 15) + floor(random() * 15)));
-
-       if(me.cvarPart == 1)
-               me.checked = (cvar(me.cvarName) & 240) == me.cvarValueFloat * 16;
-       else
-               me.checked = (cvar(me.cvarName) & 15) == me.cvarValueFloat;
-}
-void XonoticColorButton_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       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 XonoticColorButton_draw(entity me)
-{
-       me.color  = colormapPaletteColor(me.cvarValueFloat, me.cvarPart);
-       me.colorC = me.color;
-       me.colorF = me.color;
-       me.colorD = me.color;
-       SUPER(XonoticColorButton).draw(me);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/colorbutton.qc b/qcsrc/menu/xonotic/colorbutton.qc
new file mode 100644 (file)
index 0000000..bcbdfee
--- /dev/null
@@ -0,0 +1,100 @@
+#ifdef INTERFACE
+CLASS(XonoticColorButton) EXTENDS(RadioButton)
+       METHOD(XonoticColorButton, configureXonoticColorButton, void(entity, float, float, float))
+       METHOD(XonoticColorButton, setChecked, void(entity, float))
+       METHOD(XonoticColorButton, draw, void(entity))
+       ATTRIB(XonoticColorButton, fontSize, float, 0)
+       ATTRIB(XonoticColorButton, image, string, SKINGFX_COLORBUTTON)
+
+       ATTRIB(XonoticColorButton, useDownAsChecked, float, 1)
+
+       ATTRIB(XonoticColorButton, cvarPart, float, 0)
+       ATTRIB(XonoticColorButton, cvarName, string, string_null)
+       ATTRIB(XonoticColorButton, cvarValueFloat, float, 0)
+       METHOD(XonoticColorButton, loadCvars, void(entity))
+       METHOD(XonoticColorButton, saveCvars, void(entity))
+ENDCLASS(XonoticColorButton)
+entity makeXonoticColorButton(float, float, float);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticColorButton(float theGroup, float theColor, float theValue)
+{
+       entity me;
+       me = spawnXonoticColorButton();
+       me.configureXonoticColorButton(me, theGroup, theColor, theValue);
+       return me;
+}
+void XonoticColorButton_configureXonoticColorButton(entity me, float theGroup, float theColor, float theValue)
+{
+       switch(theValue)
+       {
+               // rearrange 1..14 for rainbow order
+               case  1: theValue = 10; break;
+               case  2: theValue =  4; break;
+               case  3: theValue =  1; break;
+               case  4: theValue = 14; break;
+               case  5: theValue = 12; break;
+               case  6: theValue =  7; break;
+               case  7: theValue =  3; break;
+               case  8: theValue =  2; break;
+               case  9: theValue =  6; break;
+               case 10: theValue =  5; break;
+               case 11: theValue = 13; break;
+               case 12: theValue = 11; break;
+               case 13: theValue =  8; break;
+               case 14: theValue =  9; break;
+               default:
+                       // no change
+                       break;
+       }
+       me.cvarName = "_cl_color";
+       me.cvarValueFloat = theValue;
+       me.cvarPart = theColor;
+       me.loadCvars(me);
+       me.configureRadioButton(me, string_null, me.fontSize, me.image, theGroup, 0);
+}
+void XonoticColorButton_setChecked(entity me, float val)
+{
+       if(val != me.checked)
+       {
+               me.checked = val;
+               me.saveCvars(me);
+       }
+}
+void XonoticColorButton_loadCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       if(cvar_string(me.cvarName) == cvar_defstring(me.cvarName))
+               cvar_set(me.cvarName, ftos(16 * floor(random() * 15) + floor(random() * 15)));
+
+       if(me.cvarPart == 1)
+               me.checked = (cvar(me.cvarName) & 240) == me.cvarValueFloat * 16;
+       else
+               me.checked = (cvar(me.cvarName) & 15) == me.cvarValueFloat;
+}
+void XonoticColorButton_saveCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       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 XonoticColorButton_draw(entity me)
+{
+       me.color  = colormapPaletteColor(me.cvarValueFloat, me.cvarPart);
+       me.colorC = me.color;
+       me.colorF = me.color;
+       me.colorD = me.color;
+       SUPER(XonoticColorButton).draw(me);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/colorpicker.c b/qcsrc/menu/xonotic/colorpicker.c
deleted file mode 100644 (file)
index e072737..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticColorpicker) EXTENDS(Image)
-       METHOD(XonoticColorpicker, configureXonoticColorpicker, void(entity, entity))
-       METHOD(XonoticColorpicker, mousePress, float(entity, vector))
-       METHOD(XonoticColorpicker, mouseRelease, float(entity, vector))
-       METHOD(XonoticColorpicker, mouseDrag, float(entity, vector))
-       ATTRIB(XonoticColorpicker, controlledTextbox, entity, NULL)
-       ATTRIB(XonoticColorpicker, image, string, SKINGFX_COLORPICKER)
-       ATTRIB(XonoticColorpicker, imagemargin, vector, SKINMARGIN_COLORPICKER)
-       ATTRIB(XonoticColorpicker, focusable, float, 1)
-       METHOD(XonoticColorpicker, focusLeave, void(entity))
-       METHOD(XonoticColorpicker, keyDown, float(entity, float, float, float))
-       METHOD(XonoticColorpicker, draw, void(entity))
-ENDCLASS(XonoticColorpicker)
-entity makeXonoticColorpicker(entity theTextbox);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticColorpicker(entity theTextbox)
-{
-       entity me;
-       me = spawnXonoticColorpicker();
-       me.configureXonoticColorpicker(me, theTextbox);
-       return me;
-}
-
-void XonoticColorpicker_configureXonoticColorpicker(entity me, entity theTextbox)
-{
-       me.controlledTextbox = theTextbox;
-       me.configureImage(me, me.image);
-}
-
-float XonoticColorpicker_mousePress(entity me, vector coords)
-{
-       me.mouseDrag(me, coords);
-       return 1;
-}
-
-// must match hslimage.c
-vector hslimage_color(vector v, vector margin)
-{
-    v_x = (v_x - margin_x) / (1 - 2 * margin_x);
-    v_y = (v_y - margin_y) / (1 - 2 * margin_y);
-    if(v_x < 0) v_x = 0;
-    if(v_y < 0) v_y = 0;
-    if(v_x > 1) v_x = 1;
-    if(v_y > 1) v_y = 1;
-    if(v_y > 0.875) // grey bar
-        return hsl_to_rgb(eZ * v_x);
-    else
-        return hsl_to_rgb(v_x * 6 * eX + eY + v_y / 0.875 * eZ);
-}
-
-vector color_hslimage(vector v, vector margin)
-{
-       vector pos = '0 0 0';
-       v = rgb_to_hsl(v);
-       if (v_y)
-       {
-               pos_x = v_x / 6;
-               pos_y = v_z * 0.875;
-       }
-       else // grey scale
-       {
-               pos_x = v_z;
-               pos_y = 0.875 + 0.07;
-       }
-       pos_x = margin_x + pos_x * (1 - 2 * margin_x);
-       pos_y = margin_y + pos_y * (1 - 2 * margin_y);
-       return pos;
-}
-
-float XonoticColorpicker_mouseDrag(entity me, vector coords)
-{
-       float i, carets;
-       for(;;)
-       {
-               i = me.controlledTextbox.cursorPos;
-               if(i >= 2)
-               {
-                       if(substring(me.controlledTextbox.text, i-2, 1) == "^")
-                       {
-                               carets = 1;
-                               while (i - 2 - carets >= 0 && substring(me.controlledTextbox.text, i - 2 - carets, 1) == "^")
-                                       ++carets;
-                               if (carets & 1)
-                                       if(strstrofs("0123456789", substring(me.controlledTextbox.text, i-1, 1), 0) >= 0)
-                                       {
-                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
-                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
-                                               continue;
-                                       }
-                       }
-               }
-
-               if(i >= 5)
-               {
-                       if(substring(me.controlledTextbox.text, i-5, 2) == "^x")
-                       {
-                               carets = 1;
-                               while (i - 5 - carets >= 0 && substring(me.controlledTextbox.text, i - 5 - carets, 1) == "^")
-                                       ++carets;
-                               if (carets & 1)
-                                       if(strstrofs("0123456789abcdefABCDEF", substring(me.controlledTextbox.text, i-3, 1), 0) >= 0)
-                                               if(strstrofs("0123456789abcdefABCDEF", substring(me.controlledTextbox.text, i-2, 1), 0) >= 0)
-                                                       if(strstrofs("0123456789abcdefABCDEF", substring(me.controlledTextbox.text, i-1, 1), 0) >= 0)
-                                                       {
-                                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
-                                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
-                                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
-                                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
-                                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
-                                                               continue;
-                                                       }
-                       }
-               }
-               break;
-       }
-
-       if(substring(me.controlledTextbox.text, i-1, 1) == "^")
-       {
-               carets = 1;
-               while (i - 1 - carets >= 0 && substring(me.controlledTextbox.text, i - 1 - carets, 1) == "^")
-                       ++carets;
-               if (carets & 1)
-                       me.controlledTextbox.enterText(me.controlledTextbox, "^"); // escape previous caret
-       }
-
-       vector margin;
-       margin = me.imagemargin;
-       if(coords_x >= margin_x)
-       if(coords_y >= margin_y)
-       if(coords_x <= 1 - margin_x)
-       if(coords_y <= 1 - margin_y)
-               me.controlledTextbox.enterText(me.controlledTextbox, rgb_to_hexcolor(hslimage_color(coords, margin)));
-
-       return 1;
-}
-
-float XonoticColorpicker_mouseRelease(entity me, vector coords)
-{
-       me.mouseDrag(me, coords);
-       return 1;
-}
-
-void XonoticColorpicker_focusLeave(entity me)
-{
-       me.controlledTextbox.saveCvars(me.controlledTextbox);
-}
-float XonoticColorpicker_keyDown(entity me, float key, float ascii, float shift)
-{
-       return me.controlledTextbox.keyDown(me.controlledTextbox, key, ascii, shift);
-}
-void XonoticColorpicker_draw(entity me)
-{
-       SUPER(XonoticColorpicker).draw(me);
-
-       float B, C, aC;
-       C = cvar("r_textcontrast");
-       B = cvar("r_textbrightness");
-
-       // for this to work, C/(1-B) must be in 0..1
-       // B must be < 1
-       // C must be < 1-B
-
-       B = bound(0, B, 1);
-       C = bound(0, C, 1-B);
-
-       aC = 1 - C / (1 - B);
-
-       draw_Picture(me.imgOrigin, strcat(me.src, "_m"), me.imgSize, '0 0 0', aC);
-       draw_Picture(me.imgOrigin, strcat(me.src, "_m"), me.imgSize, me.color, B);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/colorpicker.qc b/qcsrc/menu/xonotic/colorpicker.qc
new file mode 100644 (file)
index 0000000..e072737
--- /dev/null
@@ -0,0 +1,174 @@
+#ifdef INTERFACE
+CLASS(XonoticColorpicker) EXTENDS(Image)
+       METHOD(XonoticColorpicker, configureXonoticColorpicker, void(entity, entity))
+       METHOD(XonoticColorpicker, mousePress, float(entity, vector))
+       METHOD(XonoticColorpicker, mouseRelease, float(entity, vector))
+       METHOD(XonoticColorpicker, mouseDrag, float(entity, vector))
+       ATTRIB(XonoticColorpicker, controlledTextbox, entity, NULL)
+       ATTRIB(XonoticColorpicker, image, string, SKINGFX_COLORPICKER)
+       ATTRIB(XonoticColorpicker, imagemargin, vector, SKINMARGIN_COLORPICKER)
+       ATTRIB(XonoticColorpicker, focusable, float, 1)
+       METHOD(XonoticColorpicker, focusLeave, void(entity))
+       METHOD(XonoticColorpicker, keyDown, float(entity, float, float, float))
+       METHOD(XonoticColorpicker, draw, void(entity))
+ENDCLASS(XonoticColorpicker)
+entity makeXonoticColorpicker(entity theTextbox);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticColorpicker(entity theTextbox)
+{
+       entity me;
+       me = spawnXonoticColorpicker();
+       me.configureXonoticColorpicker(me, theTextbox);
+       return me;
+}
+
+void XonoticColorpicker_configureXonoticColorpicker(entity me, entity theTextbox)
+{
+       me.controlledTextbox = theTextbox;
+       me.configureImage(me, me.image);
+}
+
+float XonoticColorpicker_mousePress(entity me, vector coords)
+{
+       me.mouseDrag(me, coords);
+       return 1;
+}
+
+// must match hslimage.c
+vector hslimage_color(vector v, vector margin)
+{
+    v_x = (v_x - margin_x) / (1 - 2 * margin_x);
+    v_y = (v_y - margin_y) / (1 - 2 * margin_y);
+    if(v_x < 0) v_x = 0;
+    if(v_y < 0) v_y = 0;
+    if(v_x > 1) v_x = 1;
+    if(v_y > 1) v_y = 1;
+    if(v_y > 0.875) // grey bar
+        return hsl_to_rgb(eZ * v_x);
+    else
+        return hsl_to_rgb(v_x * 6 * eX + eY + v_y / 0.875 * eZ);
+}
+
+vector color_hslimage(vector v, vector margin)
+{
+       vector pos = '0 0 0';
+       v = rgb_to_hsl(v);
+       if (v_y)
+       {
+               pos_x = v_x / 6;
+               pos_y = v_z * 0.875;
+       }
+       else // grey scale
+       {
+               pos_x = v_z;
+               pos_y = 0.875 + 0.07;
+       }
+       pos_x = margin_x + pos_x * (1 - 2 * margin_x);
+       pos_y = margin_y + pos_y * (1 - 2 * margin_y);
+       return pos;
+}
+
+float XonoticColorpicker_mouseDrag(entity me, vector coords)
+{
+       float i, carets;
+       for(;;)
+       {
+               i = me.controlledTextbox.cursorPos;
+               if(i >= 2)
+               {
+                       if(substring(me.controlledTextbox.text, i-2, 1) == "^")
+                       {
+                               carets = 1;
+                               while (i - 2 - carets >= 0 && substring(me.controlledTextbox.text, i - 2 - carets, 1) == "^")
+                                       ++carets;
+                               if (carets & 1)
+                                       if(strstrofs("0123456789", substring(me.controlledTextbox.text, i-1, 1), 0) >= 0)
+                                       {
+                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
+                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
+                                               continue;
+                                       }
+                       }
+               }
+
+               if(i >= 5)
+               {
+                       if(substring(me.controlledTextbox.text, i-5, 2) == "^x")
+                       {
+                               carets = 1;
+                               while (i - 5 - carets >= 0 && substring(me.controlledTextbox.text, i - 5 - carets, 1) == "^")
+                                       ++carets;
+                               if (carets & 1)
+                                       if(strstrofs("0123456789abcdefABCDEF", substring(me.controlledTextbox.text, i-3, 1), 0) >= 0)
+                                               if(strstrofs("0123456789abcdefABCDEF", substring(me.controlledTextbox.text, i-2, 1), 0) >= 0)
+                                                       if(strstrofs("0123456789abcdefABCDEF", substring(me.controlledTextbox.text, i-1, 1), 0) >= 0)
+                                                       {
+                                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
+                                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
+                                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
+                                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
+                                                               me.controlledTextbox.keyDown(me.controlledTextbox, K_BACKSPACE, 8, 0);
+                                                               continue;
+                                                       }
+                       }
+               }
+               break;
+       }
+
+       if(substring(me.controlledTextbox.text, i-1, 1) == "^")
+       {
+               carets = 1;
+               while (i - 1 - carets >= 0 && substring(me.controlledTextbox.text, i - 1 - carets, 1) == "^")
+                       ++carets;
+               if (carets & 1)
+                       me.controlledTextbox.enterText(me.controlledTextbox, "^"); // escape previous caret
+       }
+
+       vector margin;
+       margin = me.imagemargin;
+       if(coords_x >= margin_x)
+       if(coords_y >= margin_y)
+       if(coords_x <= 1 - margin_x)
+       if(coords_y <= 1 - margin_y)
+               me.controlledTextbox.enterText(me.controlledTextbox, rgb_to_hexcolor(hslimage_color(coords, margin)));
+
+       return 1;
+}
+
+float XonoticColorpicker_mouseRelease(entity me, vector coords)
+{
+       me.mouseDrag(me, coords);
+       return 1;
+}
+
+void XonoticColorpicker_focusLeave(entity me)
+{
+       me.controlledTextbox.saveCvars(me.controlledTextbox);
+}
+float XonoticColorpicker_keyDown(entity me, float key, float ascii, float shift)
+{
+       return me.controlledTextbox.keyDown(me.controlledTextbox, key, ascii, shift);
+}
+void XonoticColorpicker_draw(entity me)
+{
+       SUPER(XonoticColorpicker).draw(me);
+
+       float B, C, aC;
+       C = cvar("r_textcontrast");
+       B = cvar("r_textbrightness");
+
+       // for this to work, C/(1-B) must be in 0..1
+       // B must be < 1
+       // C must be < 1-B
+
+       B = bound(0, B, 1);
+       C = bound(0, C, 1-B);
+
+       aC = 1 - C / (1 - B);
+
+       draw_Picture(me.imgOrigin, strcat(me.src, "_m"), me.imgSize, '0 0 0', aC);
+       draw_Picture(me.imgOrigin, strcat(me.src, "_m"), me.imgSize, me.color, B);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/colorpicker_string.c b/qcsrc/menu/xonotic/colorpicker_string.c
deleted file mode 100644 (file)
index 5d53135..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticColorpickerString) EXTENDS(Image)
-       METHOD(XonoticColorpickerString, configureXonoticColorpickerString, void(entity, string, string))
-       METHOD(XonoticColorpickerString, mousePress, float(entity, vector))
-       METHOD(XonoticColorpickerString, mouseRelease, float(entity, vector))
-       METHOD(XonoticColorpickerString, mouseDrag, float(entity, vector))
-       ATTRIB(XonoticColorpickerString, cvarName, string, string_null)
-       METHOD(XonoticColorPickerString, loadCvars, void(entity))
-       METHOD(XonoticColorPickerString, saveCvars, void(entity))
-       ATTRIB(XonoticColorpickerString, prevcoords, vector, '0 0 0')
-       ATTRIB(XonoticColorpickerString, image, string, SKINGFX_COLORPICKER)
-       ATTRIB(XonoticColorpickerString, imagemargin, vector, SKINMARGIN_COLORPICKER)
-       ATTRIB(XonoticColorpickerString, focusable, float, 1)
-       METHOD(XonoticColorpickerString, draw, void(entity))
-       ATTRIB(XonoticColorpickerString, disabledAlpha, float, 0.3)
-ENDCLASS(XonoticColorpickerString)
-entity makeXonoticColorpickerString(string theCvar, string theDefaultCvar);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticColorpickerString(string theCvar, string theDefaultCvar)
-{
-       entity me;
-       me = spawnXonoticColorpickerString();
-       me.configureXonoticColorpickerString(me, theCvar, theDefaultCvar);
-       return me;
-}
-
-void XonoticColorpickerString_configureXonoticColorpickerString(entity me, string theCvar, string theDefaultCvar)
-{
-       me.cvarName = theCvar;
-       me.configureImage(me, me.image);
-       if(theCvar)
-       {
-               me.cvarName = theCvar;
-               me.tooltip = getZonedTooltipForIdentifier(theCvar);
-               me.loadCvars(me);
-       }
-}
-
-void XonoticColorPickerString_loadCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       if(substring(me.cvarName, -1, 1) == "_")
-       {
-               me.prevcoords = color_hslimage(
-                       eX * cvar(strcat(me.cvarName, "red")) +
-                       eY * cvar(strcat(me.cvarName, "green")) +
-                       eZ * cvar(strcat(me.cvarName, "blue")),
-                       me.imagemargin);
-       }
-       else
-               me.prevcoords = color_hslimage(stov(cvar_string(me.cvarName)), me.imagemargin);
-}
-
-void XonoticColorPickerString_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       if(substring(me.cvarName, -1, 1) == "_")
-       {
-               vector v = hslimage_color(me.prevcoords, me.imagemargin);
-               cvar_set(strcat(me.cvarName, "red"), ftos(v_x));
-               cvar_set(strcat(me.cvarName, "green"), ftos(v_y));
-               cvar_set(strcat(me.cvarName, "blue"), ftos(v_z));
-       }
-       else
-               cvar_set(me.cvarName, sprintf("%v", hslimage_color(me.prevcoords, me.imagemargin)));
-}
-
-float XonoticColorpickerString_mousePress(entity me, vector coords)
-{
-       me.mouseDrag(me, coords);
-       return 1;
-}
-
-float XonoticColorpickerString_mouseDrag(entity me, vector coords)
-{
-       if(me.disabled)
-               return 0;
-       vector margin;
-       margin = me.imagemargin;
-       if(coords_x >= margin_x)
-       if(coords_y >= margin_y)
-       if(coords_x <= 1 - margin_x)
-       if(coords_y <= 1 - margin_y)
-       {
-               me.prevcoords = coords;
-               me.saveCvars(me);
-       }
-
-       return 1;
-}
-
-float XonoticColorpickerString_mouseRelease(entity me, vector coords)
-{
-       me.mouseDrag(me, coords);
-       return 1;
-}
-
-void XonoticColorpickerString_draw(entity me)
-{
-       float save;
-       save = draw_alpha;
-       if(me.disabled)
-               draw_alpha *= me.disabledAlpha;
-
-       SUPER(XonoticColorpickerString).draw(me);
-
-       vector sz;
-       sz = draw_PictureSize(strcat(me.src, "_selected"));
-       sz = globalToBoxSize(sz, draw_scale);
-
-       if(!me.disabled)
-               draw_Picture(me.imgOrigin + me.prevcoords - 0.5 * sz, strcat(me.src, "_selected"), sz, '1 1 1', 1);
-
-       draw_alpha = save;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/colorpicker_string.qc b/qcsrc/menu/xonotic/colorpicker_string.qc
new file mode 100644 (file)
index 0000000..5d53135
--- /dev/null
@@ -0,0 +1,122 @@
+#ifdef INTERFACE
+CLASS(XonoticColorpickerString) EXTENDS(Image)
+       METHOD(XonoticColorpickerString, configureXonoticColorpickerString, void(entity, string, string))
+       METHOD(XonoticColorpickerString, mousePress, float(entity, vector))
+       METHOD(XonoticColorpickerString, mouseRelease, float(entity, vector))
+       METHOD(XonoticColorpickerString, mouseDrag, float(entity, vector))
+       ATTRIB(XonoticColorpickerString, cvarName, string, string_null)
+       METHOD(XonoticColorPickerString, loadCvars, void(entity))
+       METHOD(XonoticColorPickerString, saveCvars, void(entity))
+       ATTRIB(XonoticColorpickerString, prevcoords, vector, '0 0 0')
+       ATTRIB(XonoticColorpickerString, image, string, SKINGFX_COLORPICKER)
+       ATTRIB(XonoticColorpickerString, imagemargin, vector, SKINMARGIN_COLORPICKER)
+       ATTRIB(XonoticColorpickerString, focusable, float, 1)
+       METHOD(XonoticColorpickerString, draw, void(entity))
+       ATTRIB(XonoticColorpickerString, disabledAlpha, float, 0.3)
+ENDCLASS(XonoticColorpickerString)
+entity makeXonoticColorpickerString(string theCvar, string theDefaultCvar);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticColorpickerString(string theCvar, string theDefaultCvar)
+{
+       entity me;
+       me = spawnXonoticColorpickerString();
+       me.configureXonoticColorpickerString(me, theCvar, theDefaultCvar);
+       return me;
+}
+
+void XonoticColorpickerString_configureXonoticColorpickerString(entity me, string theCvar, string theDefaultCvar)
+{
+       me.cvarName = theCvar;
+       me.configureImage(me, me.image);
+       if(theCvar)
+       {
+               me.cvarName = theCvar;
+               me.tooltip = getZonedTooltipForIdentifier(theCvar);
+               me.loadCvars(me);
+       }
+}
+
+void XonoticColorPickerString_loadCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       if(substring(me.cvarName, -1, 1) == "_")
+       {
+               me.prevcoords = color_hslimage(
+                       eX * cvar(strcat(me.cvarName, "red")) +
+                       eY * cvar(strcat(me.cvarName, "green")) +
+                       eZ * cvar(strcat(me.cvarName, "blue")),
+                       me.imagemargin);
+       }
+       else
+               me.prevcoords = color_hslimage(stov(cvar_string(me.cvarName)), me.imagemargin);
+}
+
+void XonoticColorPickerString_saveCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       if(substring(me.cvarName, -1, 1) == "_")
+       {
+               vector v = hslimage_color(me.prevcoords, me.imagemargin);
+               cvar_set(strcat(me.cvarName, "red"), ftos(v_x));
+               cvar_set(strcat(me.cvarName, "green"), ftos(v_y));
+               cvar_set(strcat(me.cvarName, "blue"), ftos(v_z));
+       }
+       else
+               cvar_set(me.cvarName, sprintf("%v", hslimage_color(me.prevcoords, me.imagemargin)));
+}
+
+float XonoticColorpickerString_mousePress(entity me, vector coords)
+{
+       me.mouseDrag(me, coords);
+       return 1;
+}
+
+float XonoticColorpickerString_mouseDrag(entity me, vector coords)
+{
+       if(me.disabled)
+               return 0;
+       vector margin;
+       margin = me.imagemargin;
+       if(coords_x >= margin_x)
+       if(coords_y >= margin_y)
+       if(coords_x <= 1 - margin_x)
+       if(coords_y <= 1 - margin_y)
+       {
+               me.prevcoords = coords;
+               me.saveCvars(me);
+       }
+
+       return 1;
+}
+
+float XonoticColorpickerString_mouseRelease(entity me, vector coords)
+{
+       me.mouseDrag(me, coords);
+       return 1;
+}
+
+void XonoticColorpickerString_draw(entity me)
+{
+       float save;
+       save = draw_alpha;
+       if(me.disabled)
+               draw_alpha *= me.disabledAlpha;
+
+       SUPER(XonoticColorpickerString).draw(me);
+
+       vector sz;
+       sz = draw_PictureSize(strcat(me.src, "_selected"));
+       sz = globalToBoxSize(sz, draw_scale);
+
+       if(!me.disabled)
+               draw_Picture(me.imgOrigin + me.prevcoords - 0.5 * sz, strcat(me.src, "_selected"), sz, '1 1 1', 1);
+
+       draw_alpha = save;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/commandbutton.c b/qcsrc/menu/xonotic/commandbutton.c
deleted file mode 100644 (file)
index 8ee4e7d..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef COMMANDBUTTON_CLOSE
-# define COMMANDBUTTON_CLOSE 1
-# define COMMANDBUTTON_APPLY 2
-//# define COMMANDBUTTON_REVERT 4
-#endif
-
-#ifdef INTERFACE
-CLASS(XonoticCommandButton) EXTENDS(XonoticButton)
-       METHOD(XonoticCommandButton, configureXonoticCommandButton, void(entity, string, vector, string, float))
-       ATTRIB(XonoticCommandButton, onClickCommand, string, string_null)
-       ATTRIB(XonoticCommandButton, flags, float, 0)
-ENDCLASS(XonoticCommandButton)
-entity makeXonoticCommandButton(string theText, vector theColor, string theCommand, float closesMenu);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticCommandButton(string theText, vector theColor, string theCommand, float theFlags)
-{
-       entity me;
-       me = spawnXonoticCommandButton();
-       me.configureXonoticCommandButton(me, theText, theColor, theCommand, theFlags);
-       return me;
-}
-
-void XonoticCommandButton_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 XonoticCommandButton_configureXonoticCommandButton(entity me, string theText, vector theColor, string theCommand, float theFlags)
-{
-       me.configureXonoticButton(me, theText, theColor);
-       me.onClickCommand = theCommand;
-       me.flags = theFlags;
-       me.onClick = XonoticCommandButton_Click;
-       me.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/commandbutton.qc b/qcsrc/menu/xonotic/commandbutton.qc
new file mode 100644 (file)
index 0000000..8ee4e7d
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef COMMANDBUTTON_CLOSE
+# define COMMANDBUTTON_CLOSE 1
+# define COMMANDBUTTON_APPLY 2
+//# define COMMANDBUTTON_REVERT 4
+#endif
+
+#ifdef INTERFACE
+CLASS(XonoticCommandButton) EXTENDS(XonoticButton)
+       METHOD(XonoticCommandButton, configureXonoticCommandButton, void(entity, string, vector, string, float))
+       ATTRIB(XonoticCommandButton, onClickCommand, string, string_null)
+       ATTRIB(XonoticCommandButton, flags, float, 0)
+ENDCLASS(XonoticCommandButton)
+entity makeXonoticCommandButton(string theText, vector theColor, string theCommand, float closesMenu);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticCommandButton(string theText, vector theColor, string theCommand, float theFlags)
+{
+       entity me;
+       me = spawnXonoticCommandButton();
+       me.configureXonoticCommandButton(me, theText, theColor, theCommand, theFlags);
+       return me;
+}
+
+void XonoticCommandButton_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 XonoticCommandButton_configureXonoticCommandButton(entity me, string theText, vector theColor, string theCommand, float theFlags)
+{
+       me.configureXonoticButton(me, theText, theColor);
+       me.onClickCommand = theCommand;
+       me.flags = theFlags;
+       me.onClick = XonoticCommandButton_Click;
+       me.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/credits.c b/qcsrc/menu/xonotic/credits.c
deleted file mode 100644 (file)
index 0d998d7..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCreditsList) EXTENDS(XonoticListBox)
-       METHOD(XonoticCreditsList, configureXonoticCreditsList, void(entity))
-       ATTRIB(XonoticCreditsList, rowsPerItem, float, 1)
-       METHOD(XonoticCreditsList, draw, void(entity))
-       METHOD(XonoticCreditsList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticCreditsList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticCreditsList, keyDown, float(entity, float, float, float))
-       METHOD(XonoticCreditsList, destroy, void(entity))
-
-       ATTRIB(XonoticCreditsList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticCreditsList, realUpperMargin, float, 0)
-       ATTRIB(XonoticCreditsList, bufferIndex, float, 0)
-       ATTRIB(XonoticCreditsList, scrolling, float, 0)
-
-       ATTRIB(XonoticListBox, alphaBG, float, 0)
-ENDCLASS(XonoticCreditsList)
-entity makeXonoticCreditsList();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticCreditsList()
-{
-       entity me;
-       me = spawnXonoticCreditsList();
-       me.configureXonoticCreditsList(me);
-       return me;
-}
-void XonoticCreditsList_configureXonoticCreditsList(entity me)
-{
-       me.configureXonoticListBox(me);
-       // load the file
-       me.bufferIndex = buf_load(language_filename("xonotic-credits.txt"));
-       me.nItems = buf_getsize(me.bufferIndex);
-}
-void XonoticCreditsList_destroy(entity me)
-{
-       buf_del(me.bufferIndex);
-}
-void XonoticCreditsList_draw(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);
-       }
-       SUPER(XonoticCreditsList).draw(me);
-}
-void XonoticCreditsList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(XonoticCreditsList).resizeNotify(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 XonoticCreditsList_drawListBoxItem(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 XonoticCreditsList_keyDown(entity me, float key, float ascii, float shift)
-{
-       float i;
-       me.dragScrollTimer = time;
-       me.scrolling = 0;
-       if(key == K_PGUP || key == K_KP_PGUP)
-               me.scrollPos = max(me.scrollPos - 0.5, 0);
-       else if(key == K_PGDN || key == K_KP_PGDN)
-               me.scrollPos = min(me.scrollPos + 0.5, me.nItems * me.itemHeight - 1);
-       else if(key == K_UPARROW || key == K_KP_UPARROW)
-               me.scrollPos = max(me.scrollPos - me.itemHeight, 0);
-       else if(key == K_DOWNARROW || key == K_KP_DOWNARROW)
-               me.scrollPos = min(me.scrollPos + me.itemHeight, me.nItems * me.itemHeight - 1);
-       else
-               return SUPER(XonoticCreditsList).keyDown(me, key, 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
diff --git a/qcsrc/menu/xonotic/credits.qc b/qcsrc/menu/xonotic/credits.qc
new file mode 100644 (file)
index 0000000..0d998d7
--- /dev/null
@@ -0,0 +1,112 @@
+#ifdef INTERFACE
+CLASS(XonoticCreditsList) EXTENDS(XonoticListBox)
+       METHOD(XonoticCreditsList, configureXonoticCreditsList, void(entity))
+       ATTRIB(XonoticCreditsList, rowsPerItem, float, 1)
+       METHOD(XonoticCreditsList, draw, void(entity))
+       METHOD(XonoticCreditsList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticCreditsList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticCreditsList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticCreditsList, destroy, void(entity))
+
+       ATTRIB(XonoticCreditsList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticCreditsList, realUpperMargin, float, 0)
+       ATTRIB(XonoticCreditsList, bufferIndex, float, 0)
+       ATTRIB(XonoticCreditsList, scrolling, float, 0)
+
+       ATTRIB(XonoticListBox, alphaBG, float, 0)
+ENDCLASS(XonoticCreditsList)
+entity makeXonoticCreditsList();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticCreditsList()
+{
+       entity me;
+       me = spawnXonoticCreditsList();
+       me.configureXonoticCreditsList(me);
+       return me;
+}
+void XonoticCreditsList_configureXonoticCreditsList(entity me)
+{
+       me.configureXonoticListBox(me);
+       // load the file
+       me.bufferIndex = buf_load(language_filename("xonotic-credits.txt"));
+       me.nItems = buf_getsize(me.bufferIndex);
+}
+void XonoticCreditsList_destroy(entity me)
+{
+       buf_del(me.bufferIndex);
+}
+void XonoticCreditsList_draw(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);
+       }
+       SUPER(XonoticCreditsList).draw(me);
+}
+void XonoticCreditsList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(XonoticCreditsList).resizeNotify(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 XonoticCreditsList_drawListBoxItem(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 XonoticCreditsList_keyDown(entity me, float key, float ascii, float shift)
+{
+       float i;
+       me.dragScrollTimer = time;
+       me.scrolling = 0;
+       if(key == K_PGUP || key == K_KP_PGUP)
+               me.scrollPos = max(me.scrollPos - 0.5, 0);
+       else if(key == K_PGDN || key == K_KP_PGDN)
+               me.scrollPos = min(me.scrollPos + 0.5, me.nItems * me.itemHeight - 1);
+       else if(key == K_UPARROW || key == K_KP_UPARROW)
+               me.scrollPos = max(me.scrollPos - me.itemHeight, 0);
+       else if(key == K_DOWNARROW || key == K_KP_DOWNARROW)
+               me.scrollPos = min(me.scrollPos + me.itemHeight, me.nItems * me.itemHeight - 1);
+       else
+               return SUPER(XonoticCreditsList).keyDown(me, key, 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
diff --git a/qcsrc/menu/xonotic/crosshairbutton.c b/qcsrc/menu/xonotic/crosshairbutton.c
deleted file mode 100644 (file)
index 7fe3a60..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCrosshairButton) EXTENDS(RadioButton)
-       METHOD(XonoticCrosshairButton, configureXonoticCrosshairButton, void(entity, float, float))
-       METHOD(XonoticCrosshairButton, setChecked, void(entity, float))
-       METHOD(XonoticCrosshairButton, draw, void(entity))
-       ATTRIB(XonoticCrosshairButton, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticCrosshairButton, image, string, SKINGFX_CROSSHAIRBUTTON)
-
-       ATTRIB(XonoticCrosshairButton, useDownAsChecked, float, 1)
-       ATTRIB(XonoticCrosshairButton, src3, string, string_null)
-       ATTRIB(XonoticCrosshairButton, src4, string, string_null)
-
-       ATTRIB(XonoticCrosshairButton, cvarName, string, string_null)
-       ATTRIB(XonoticCrosshairButton, cvarValueFloat, float, 0)
-       METHOD(XonoticCrosshairButton, loadCvars, void(entity))
-       METHOD(XonoticCrosshairButton, saveCvars, void(entity))
-ENDCLASS(XonoticCrosshairButton)
-entity makeXonoticCrosshairButton(float, float);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticCrosshairButton(float theGroup, float theCrosshair)
-{
-       entity me;
-       me = spawnXonoticCrosshairButton();
-       me.configureXonoticCrosshairButton(me, theGroup, theCrosshair);
-       return me;
-}
-void XonoticCrosshairButton_configureXonoticCrosshairButton(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;
-       if(me.cvarValueFloat == -1)
-               me.src3 = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
-       else
-               me.src3 = strzone(strcat("/gfx/crosshair", ftos(me.cvarValueFloat)));
-       me.src4 = "/gfx/crosshairdot";
-}
-void XonoticCrosshairButton_setChecked(entity me, float val)
-{
-       if(me.cvarValueFloat != -1) // preview shouldn't work as a button
-       if(val != me.checked)
-       {
-               me.checked = val;
-               me.saveCvars(me);
-       }
-}
-void XonoticCrosshairButton_loadCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       me.checked = (cvar(me.cvarName) == me.cvarValueFloat);
-}
-void XonoticCrosshairButton_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       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 XonoticCrosshairButton_draw(entity me)
-{
-       vector sz, rgb;
-       float a;
-
-
-       if(me.cvarValueFloat == -1)
-       {
-               rgb = stov(cvar_string("crosshair_color"));
-               a = cvar("crosshair_alpha");
-       }
-       else if(me.checked || me.focused)
-       {
-               a = 1;
-               rgb = '1 1 1';
-       }
-       else
-       {
-               a = me.disabledAlpha;
-               rgb = '1 1 1';
-       }
-
-       if(me.cvarValueFloat == -1) // update the preview if this is the preview button
-       {
-               if(me.src3)
-                       strunzone(me.src3);
-               me.src3 = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
-               me.focused = 1;
-               me.checked = 0;
-       }
-
-       SUPER(XonoticCrosshairButton).draw(me);
-
-       sz = draw_PictureSize(me.src3);
-       sz = globalToBoxSize(sz, me.size);
-       if(me.cvarValueFloat == -1)
-       {
-               sz = sz * cvar("crosshair_size"); // (6 * '1 1 0' + ...) * 0.08 here to make visible size changes happen also at bigger sizes
-               /*
-               if(sz_x > 0.95)
-                       sz = sz * (0.95 / sz_x);
-               if(sz_y > 0.95)
-                       sz = sz * (0.95 / sz_y);
-               */
-       }
-       else // show the crosshair picker at full size
-       {
-               sz = sz * (0.95 / sz_x);
-               if(sz_y > 0.95)
-                       sz = sz * (0.95 / sz_y);
-       }
-
-       draw_Picture('0.5 0.5 0' - 0.5 * sz, me.src3, sz, rgb, a);
-       if(cvar("crosshair_dot"))
-       {
-               if(cvar("crosshair_dot_color_custom") && (cvar_string("crosshair_dot_color") != "0"))
-                       rgb = stov(cvar_string("crosshair_dot_color"));
-
-               draw_Picture('0.5 0.5 0' - 0.5 * sz * cvar("crosshair_dot_size"), me.src4, sz * cvar("crosshair_dot_size"), rgb, a * cvar("crosshair_dot_alpha"));
-       }
-}
-#endif
diff --git a/qcsrc/menu/xonotic/crosshairbutton.qc b/qcsrc/menu/xonotic/crosshairbutton.qc
new file mode 100644 (file)
index 0000000..7fe3a60
--- /dev/null
@@ -0,0 +1,128 @@
+#ifdef INTERFACE
+CLASS(XonoticCrosshairButton) EXTENDS(RadioButton)
+       METHOD(XonoticCrosshairButton, configureXonoticCrosshairButton, void(entity, float, float))
+       METHOD(XonoticCrosshairButton, setChecked, void(entity, float))
+       METHOD(XonoticCrosshairButton, draw, void(entity))
+       ATTRIB(XonoticCrosshairButton, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticCrosshairButton, image, string, SKINGFX_CROSSHAIRBUTTON)
+
+       ATTRIB(XonoticCrosshairButton, useDownAsChecked, float, 1)
+       ATTRIB(XonoticCrosshairButton, src3, string, string_null)
+       ATTRIB(XonoticCrosshairButton, src4, string, string_null)
+
+       ATTRIB(XonoticCrosshairButton, cvarName, string, string_null)
+       ATTRIB(XonoticCrosshairButton, cvarValueFloat, float, 0)
+       METHOD(XonoticCrosshairButton, loadCvars, void(entity))
+       METHOD(XonoticCrosshairButton, saveCvars, void(entity))
+ENDCLASS(XonoticCrosshairButton)
+entity makeXonoticCrosshairButton(float, float);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticCrosshairButton(float theGroup, float theCrosshair)
+{
+       entity me;
+       me = spawnXonoticCrosshairButton();
+       me.configureXonoticCrosshairButton(me, theGroup, theCrosshair);
+       return me;
+}
+void XonoticCrosshairButton_configureXonoticCrosshairButton(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;
+       if(me.cvarValueFloat == -1)
+               me.src3 = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
+       else
+               me.src3 = strzone(strcat("/gfx/crosshair", ftos(me.cvarValueFloat)));
+       me.src4 = "/gfx/crosshairdot";
+}
+void XonoticCrosshairButton_setChecked(entity me, float val)
+{
+       if(me.cvarValueFloat != -1) // preview shouldn't work as a button
+       if(val != me.checked)
+       {
+               me.checked = val;
+               me.saveCvars(me);
+       }
+}
+void XonoticCrosshairButton_loadCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       me.checked = (cvar(me.cvarName) == me.cvarValueFloat);
+}
+void XonoticCrosshairButton_saveCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       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 XonoticCrosshairButton_draw(entity me)
+{
+       vector sz, rgb;
+       float a;
+
+
+       if(me.cvarValueFloat == -1)
+       {
+               rgb = stov(cvar_string("crosshair_color"));
+               a = cvar("crosshair_alpha");
+       }
+       else if(me.checked || me.focused)
+       {
+               a = 1;
+               rgb = '1 1 1';
+       }
+       else
+       {
+               a = me.disabledAlpha;
+               rgb = '1 1 1';
+       }
+
+       if(me.cvarValueFloat == -1) // update the preview if this is the preview button
+       {
+               if(me.src3)
+                       strunzone(me.src3);
+               me.src3 = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
+               me.focused = 1;
+               me.checked = 0;
+       }
+
+       SUPER(XonoticCrosshairButton).draw(me);
+
+       sz = draw_PictureSize(me.src3);
+       sz = globalToBoxSize(sz, me.size);
+       if(me.cvarValueFloat == -1)
+       {
+               sz = sz * cvar("crosshair_size"); // (6 * '1 1 0' + ...) * 0.08 here to make visible size changes happen also at bigger sizes
+               /*
+               if(sz_x > 0.95)
+                       sz = sz * (0.95 / sz_x);
+               if(sz_y > 0.95)
+                       sz = sz * (0.95 / sz_y);
+               */
+       }
+       else // show the crosshair picker at full size
+       {
+               sz = sz * (0.95 / sz_x);
+               if(sz_y > 0.95)
+                       sz = sz * (0.95 / sz_y);
+       }
+
+       draw_Picture('0.5 0.5 0' - 0.5 * sz, me.src3, sz, rgb, a);
+       if(cvar("crosshair_dot"))
+       {
+               if(cvar("crosshair_dot_color_custom") && (cvar_string("crosshair_dot_color") != "0"))
+                       rgb = stov(cvar_string("crosshair_dot_color"));
+
+               draw_Picture('0.5 0.5 0' - 0.5 * sz * cvar("crosshair_dot_size"), me.src4, sz * cvar("crosshair_dot_size"), rgb, a * cvar("crosshair_dot_alpha"));
+       }
+}
+#endif
diff --git a/qcsrc/menu/xonotic/cvarlist.c b/qcsrc/menu/xonotic/cvarlist.c
deleted file mode 100644 (file)
index 913a03e..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCvarList) EXTENDS(XonoticListBox)
-       METHOD(XonoticCvarList, configureXonoticCvarList, void(entity))
-       ATTRIB(XonoticCvarList, rowsPerItem, float, 1)
-       METHOD(XonoticCvarList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticCvarList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticCvarList, keyDown, float(entity, float, float, float))
-
-       METHOD(XonoticCvarList, destroy, void(entity))
-
-       ATTRIB(XonoticCvarList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticCvarList, realUpperMargin, float, 0)
-       ATTRIB(XonoticCvarList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticCvarList, columnNameSize, float, 0)
-       ATTRIB(XonoticCvarList, columnValueOrigin, float, 0)
-       ATTRIB(XonoticCvarList, columnValueSize, float, 0)
-
-       METHOD(XonoticCvarList, mouseRelease, float(entity, vector))
-       METHOD(XonoticCvarList, setSelected, void(entity, float))
-       METHOD(XonoticCvarList, updateCvarType, float(entity))
-
-       ATTRIB(XonoticCvarList, controlledTextbox, entity, NULL)
-       ATTRIB(XonoticCvarList, cvarNameBox, entity, NULL)
-       ATTRIB(XonoticCvarList, cvarDescriptionBox, entity, NULL)
-       ATTRIB(XonoticCvarList, cvarTypeBox, entity, NULL)
-       ATTRIB(XonoticCvarList, cvarValueBox, entity, NULL)
-       ATTRIB(XonoticCvarList, cvarDefaultBox, entity, NULL)
-       ATTRIB(XonoticCvarList, cvarNeedsForcing, float, 0)
-
-       ATTRIB(XonoticCvarList, handle, float, -1)
-       ATTRIB(XonoticCvarList, cvarName, string, string_null)
-       ATTRIB(XonoticCvarList, cvarDescription, string, string_null)
-       ATTRIB(XonoticCvarList, cvarType, string, string_null)
-       ATTRIB(XonoticCvarList, cvarDefault, string, string_null)
-ENDCLASS(XonoticCvarList)
-entity makeXonoticCvarList();
-void CvarList_Filter_Change(entity box, entity me);
-void CvarList_Value_Change(entity box, entity me);
-void CvarList_Revert_Click(entity btn, entity me);
-void CvarList_End_Editing(entity box, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticCvarList()
-{
-       entity me;
-       me = spawnXonoticCvarList();
-       me.configureXonoticCvarList(me);
-       return me;
-}
-void XonoticCvarList_configureXonoticCvarList(entity me)
-{
-       me.configureXonoticListBox(me);
-
-       me.handle = buf_create();
-       buf_cvarlist(me.handle, "", "_");
-       me.nItems = buf_getsize(me.handle);
-}
-void XonoticCvarList_destroy(entity me)
-{
-       buf_del(me.handle);
-}
-string autocvar_menu_forced_saved_cvars;
-string autocvar_menu_reverted_nonsaved_cvars;
-float XonoticCvarList_updateCvarType(entity me)
-{
-       float t;
-       t = cvar_type(me.cvarName);
-       me.cvarType = "";
-       float needsForcing;
-       if(strstrofs(strcat(" ", autocvar_menu_forced_saved_cvars, " "), strcat(" ", me.cvarName, " "), 0) >= 0)
-       {
-               me.cvarType = strcat(me.cvarType, ", ", _("forced to be saved to config.cfg"));
-               needsForcing = 0;
-       }
-       else if(strstrofs(strcat(" ", autocvar_menu_reverted_nonsaved_cvars, " "), strcat(" ", me.cvarName, " "), 0) >= 0)
-       {
-               // Currently claims to be saved, but won't be on next startup.
-               me.cvarType = strcat(me.cvarType, ", ", _("will not be saved"));
-               needsForcing = 1;
-       }
-       else if(t & CVAR_TYPEFLAG_SAVED)
-       {
-               me.cvarType = strcat(me.cvarType, ", ", _("will be saved to config.cfg"));
-               needsForcing = 0;
-       }
-       else
-       {
-               me.cvarType = strcat(me.cvarType, ", ", _("will not be saved"));
-               needsForcing = 1;
-       }
-       if(t & CVAR_TYPEFLAG_PRIVATE)
-               me.cvarType = strcat(me.cvarType, ", ", _("private"));
-       if(t & CVAR_TYPEFLAG_ENGINE)
-               me.cvarType = strcat(me.cvarType, ", ", _("engine setting"));
-       if(t & CVAR_TYPEFLAG_READONLY)
-               me.cvarType = strcat(me.cvarType, ", ", _("read only"));
-       me.cvarType = strzone(substring(me.cvarType, 2, strlen(me.cvarType) - 2));
-       me.cvarTypeBox.setText(me.cvarTypeBox, me.cvarType);
-       return needsForcing;
-}
-void XonoticCvarList_setSelected(entity me, float i)
-{
-       string s;
-
-       SUPER(XonoticCvarList).setSelected(me, i);
-       if(me.nItems == 0)
-               return;
-
-       if(me.cvarName)
-               strunzone(me.cvarName);
-       if(me.cvarDescription)
-               strunzone(me.cvarDescription);
-       if(me.cvarType)
-               strunzone(me.cvarType);
-       if(me.cvarDefault)
-               strunzone(me.cvarDefault);
-       me.cvarName = strzone(bufstr_get(me.handle, me.selectedItem));
-       me.cvarDescription = strzone(cvar_description(me.cvarName));
-       me.cvarDefault = strzone(cvar_defstring(me.cvarName));
-       me.cvarNameBox.setText(me.cvarNameBox, me.cvarName);
-       me.cvarDescriptionBox.setText(me.cvarDescriptionBox, me.cvarDescription);
-       float needsForcing = me.updateCvarType(me);
-       me.cvarDefaultBox.setText(me.cvarDefaultBox, me.cvarDefault);
-
-       // this one can handle tempstrings
-       s = cvar_string(me.cvarName);
-       me.cvarNeedsForcing = 0;
-       me.cvarValueBox.setText(me.cvarValueBox, s);
-       me.cvarNeedsForcing = needsForcing;
-       me.cvarValueBox.cursorPos = strlen(s);
-}
-void CvarList_Filter_Change(entity box, entity me)
-{
-       buf_cvarlist(me.handle, box.text, "_");
-       me.nItems = buf_getsize(me.handle);
-
-       me.setSelected(me, 0);
-}
-void XonoticCvarList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(XonoticCvarList).resizeNotify(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.columnNameOrigin = 0;
-       me.columnValueSize = me.realFontSize_x * 20;
-       me.columnNameSize = 1 - me.columnValueSize - me.realFontSize_x;
-       me.columnValueOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
-
-       me.setSelected(me, me.selectedItem);
-}
-void XonoticCvarList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string k, v, d;
-       float t;
-
-       vector theColor;
-       float theAlpha;
-
-       string s;
-
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-
-       k = bufstr_get(me.handle, i);
-
-       v = cvar_string(k);
-       d = cvar_defstring(k);
-       t = cvar_type(k);
-       if(strstrofs(strcat(" ", autocvar_menu_forced_saved_cvars, " "), strcat(" ", k, " "), 0) >= 0)
-               theAlpha = SKINALPHA_CVARLIST_SAVED;
-       else if(strstrofs(strcat(" ", autocvar_menu_reverted_nonsaved_cvars, " "), strcat(" ", k, " "), 0) >= 0)
-               theAlpha = SKINALPHA_CVARLIST_TEMPORARY;
-       else if(t & CVAR_TYPEFLAG_SAVED)
-               theAlpha = SKINALPHA_CVARLIST_SAVED;
-       else
-               theAlpha = SKINALPHA_CVARLIST_TEMPORARY;
-       if(v == d)
-               theColor = SKINCOLOR_CVARLIST_UNCHANGED;
-       else
-               theColor = SKINCOLOR_CVARLIST_CHANGED;
-
-       s = draw_TextShortenToWidth(k, me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
-       s = draw_TextShortenToWidth(v, me.columnValueSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + me.columnValueOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
-}
-
-float XonoticCvarList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if (scan == K_MOUSE3 || ((shift & S_CTRL) && scan == K_SPACE))
-       {
-               CvarList_Revert_Click(world, me);
-               return 1;
-       }
-       else if(scan == K_ENTER)
-       {
-               me.cvarValueBox.parent.setFocus(me.cvarValueBox.parent, me.cvarValueBox);
-               return 1;
-       }
-       else if(SUPER(XonoticCvarList).keyDown(me, scan, ascii, shift))
-               return 1;
-       else if(!me.controlledTextbox)
-               return 0;
-       else
-               return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);
-}
-
-float XonoticCvarList_mouseRelease(entity me, vector pos)
-{
-       if(me.pressed == 2)
-               me.cvarValueBox.parent.setFocus(me.cvarValueBox.parent, me.cvarValueBox);
-       return SUPER(XonoticCvarList).mouseRelease(me, pos);
-}
-
-void CvarList_Value_Change(entity box, entity me)
-{
-       cvar_set(me.cvarNameBox.text, box.text);
-       if(me.cvarNeedsForcing)
-       {
-               localcmd(sprintf("\nseta %1$s \"$%1$s\"\n", me.cvarName));
-               cvar_set("menu_reverted_nonsaved_cvars", substring(strreplace(strcat(" ", me.cvarName, " "), " ", strcat(" ", autocvar_menu_reverted_nonsaved_cvars, " ")), 1, -2));
-               if (autocvar_menu_forced_saved_cvars == "")
-                       cvar_set("menu_forced_saved_cvars", me.cvarName);
-               else
-                       cvar_set("menu_forced_saved_cvars", strcat(autocvar_menu_forced_saved_cvars, " ", me.cvarName));
-               me.cvarNeedsForcing = 0;
-               me.updateCvarType(me);
-       }
-}
-
-void CvarList_Revert_Click(entity btn, entity me)
-{
-       me.cvarValueBox.setText(me.cvarValueBox, me.cvarDefault);
-       me.cvarValueBox.cursorPos = strlen(me.cvarDefault);
-       if(strstrofs(strcat(" ", autocvar_menu_forced_saved_cvars, " "), strcat(" ", me.cvarName, " "), 0) >= 0)
-       {
-               cvar_set("menu_forced_saved_cvars", substring(strreplace(strcat(" ", me.cvarName, " "), " ", strcat(" ", autocvar_menu_forced_saved_cvars, " ")), 1, -2));
-               if (autocvar_menu_reverted_nonsaved_cvars == "")
-                       cvar_set("menu_reverted_nonsaved_cvars", me.cvarName);
-               else
-                       cvar_set("menu_reverted_nonsaved_cvars", strcat(autocvar_menu_reverted_nonsaved_cvars, " ", me.cvarName));
-       }
-       me.cvarNeedsForcing = me.updateCvarType(me);
-}
-
-void CvarList_End_Editing(entity box, entity me)
-{
-       box.parent.setFocus(box.parent, me);
-}
-
-#endif
diff --git a/qcsrc/menu/xonotic/cvarlist.qc b/qcsrc/menu/xonotic/cvarlist.qc
new file mode 100644 (file)
index 0000000..913a03e
--- /dev/null
@@ -0,0 +1,255 @@
+#ifdef INTERFACE
+CLASS(XonoticCvarList) EXTENDS(XonoticListBox)
+       METHOD(XonoticCvarList, configureXonoticCvarList, void(entity))
+       ATTRIB(XonoticCvarList, rowsPerItem, float, 1)
+       METHOD(XonoticCvarList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticCvarList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticCvarList, keyDown, float(entity, float, float, float))
+
+       METHOD(XonoticCvarList, destroy, void(entity))
+
+       ATTRIB(XonoticCvarList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticCvarList, realUpperMargin, float, 0)
+       ATTRIB(XonoticCvarList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticCvarList, columnNameSize, float, 0)
+       ATTRIB(XonoticCvarList, columnValueOrigin, float, 0)
+       ATTRIB(XonoticCvarList, columnValueSize, float, 0)
+
+       METHOD(XonoticCvarList, mouseRelease, float(entity, vector))
+       METHOD(XonoticCvarList, setSelected, void(entity, float))
+       METHOD(XonoticCvarList, updateCvarType, float(entity))
+
+       ATTRIB(XonoticCvarList, controlledTextbox, entity, NULL)
+       ATTRIB(XonoticCvarList, cvarNameBox, entity, NULL)
+       ATTRIB(XonoticCvarList, cvarDescriptionBox, entity, NULL)
+       ATTRIB(XonoticCvarList, cvarTypeBox, entity, NULL)
+       ATTRIB(XonoticCvarList, cvarValueBox, entity, NULL)
+       ATTRIB(XonoticCvarList, cvarDefaultBox, entity, NULL)
+       ATTRIB(XonoticCvarList, cvarNeedsForcing, float, 0)
+
+       ATTRIB(XonoticCvarList, handle, float, -1)
+       ATTRIB(XonoticCvarList, cvarName, string, string_null)
+       ATTRIB(XonoticCvarList, cvarDescription, string, string_null)
+       ATTRIB(XonoticCvarList, cvarType, string, string_null)
+       ATTRIB(XonoticCvarList, cvarDefault, string, string_null)
+ENDCLASS(XonoticCvarList)
+entity makeXonoticCvarList();
+void CvarList_Filter_Change(entity box, entity me);
+void CvarList_Value_Change(entity box, entity me);
+void CvarList_Revert_Click(entity btn, entity me);
+void CvarList_End_Editing(entity box, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticCvarList()
+{
+       entity me;
+       me = spawnXonoticCvarList();
+       me.configureXonoticCvarList(me);
+       return me;
+}
+void XonoticCvarList_configureXonoticCvarList(entity me)
+{
+       me.configureXonoticListBox(me);
+
+       me.handle = buf_create();
+       buf_cvarlist(me.handle, "", "_");
+       me.nItems = buf_getsize(me.handle);
+}
+void XonoticCvarList_destroy(entity me)
+{
+       buf_del(me.handle);
+}
+string autocvar_menu_forced_saved_cvars;
+string autocvar_menu_reverted_nonsaved_cvars;
+float XonoticCvarList_updateCvarType(entity me)
+{
+       float t;
+       t = cvar_type(me.cvarName);
+       me.cvarType = "";
+       float needsForcing;
+       if(strstrofs(strcat(" ", autocvar_menu_forced_saved_cvars, " "), strcat(" ", me.cvarName, " "), 0) >= 0)
+       {
+               me.cvarType = strcat(me.cvarType, ", ", _("forced to be saved to config.cfg"));
+               needsForcing = 0;
+       }
+       else if(strstrofs(strcat(" ", autocvar_menu_reverted_nonsaved_cvars, " "), strcat(" ", me.cvarName, " "), 0) >= 0)
+       {
+               // Currently claims to be saved, but won't be on next startup.
+               me.cvarType = strcat(me.cvarType, ", ", _("will not be saved"));
+               needsForcing = 1;
+       }
+       else if(t & CVAR_TYPEFLAG_SAVED)
+       {
+               me.cvarType = strcat(me.cvarType, ", ", _("will be saved to config.cfg"));
+               needsForcing = 0;
+       }
+       else
+       {
+               me.cvarType = strcat(me.cvarType, ", ", _("will not be saved"));
+               needsForcing = 1;
+       }
+       if(t & CVAR_TYPEFLAG_PRIVATE)
+               me.cvarType = strcat(me.cvarType, ", ", _("private"));
+       if(t & CVAR_TYPEFLAG_ENGINE)
+               me.cvarType = strcat(me.cvarType, ", ", _("engine setting"));
+       if(t & CVAR_TYPEFLAG_READONLY)
+               me.cvarType = strcat(me.cvarType, ", ", _("read only"));
+       me.cvarType = strzone(substring(me.cvarType, 2, strlen(me.cvarType) - 2));
+       me.cvarTypeBox.setText(me.cvarTypeBox, me.cvarType);
+       return needsForcing;
+}
+void XonoticCvarList_setSelected(entity me, float i)
+{
+       string s;
+
+       SUPER(XonoticCvarList).setSelected(me, i);
+       if(me.nItems == 0)
+               return;
+
+       if(me.cvarName)
+               strunzone(me.cvarName);
+       if(me.cvarDescription)
+               strunzone(me.cvarDescription);
+       if(me.cvarType)
+               strunzone(me.cvarType);
+       if(me.cvarDefault)
+               strunzone(me.cvarDefault);
+       me.cvarName = strzone(bufstr_get(me.handle, me.selectedItem));
+       me.cvarDescription = strzone(cvar_description(me.cvarName));
+       me.cvarDefault = strzone(cvar_defstring(me.cvarName));
+       me.cvarNameBox.setText(me.cvarNameBox, me.cvarName);
+       me.cvarDescriptionBox.setText(me.cvarDescriptionBox, me.cvarDescription);
+       float needsForcing = me.updateCvarType(me);
+       me.cvarDefaultBox.setText(me.cvarDefaultBox, me.cvarDefault);
+
+       // this one can handle tempstrings
+       s = cvar_string(me.cvarName);
+       me.cvarNeedsForcing = 0;
+       me.cvarValueBox.setText(me.cvarValueBox, s);
+       me.cvarNeedsForcing = needsForcing;
+       me.cvarValueBox.cursorPos = strlen(s);
+}
+void CvarList_Filter_Change(entity box, entity me)
+{
+       buf_cvarlist(me.handle, box.text, "_");
+       me.nItems = buf_getsize(me.handle);
+
+       me.setSelected(me, 0);
+}
+void XonoticCvarList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(XonoticCvarList).resizeNotify(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.columnNameOrigin = 0;
+       me.columnValueSize = me.realFontSize_x * 20;
+       me.columnNameSize = 1 - me.columnValueSize - me.realFontSize_x;
+       me.columnValueOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
+
+       me.setSelected(me, me.selectedItem);
+}
+void XonoticCvarList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string k, v, d;
+       float t;
+
+       vector theColor;
+       float theAlpha;
+
+       string s;
+
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       k = bufstr_get(me.handle, i);
+
+       v = cvar_string(k);
+       d = cvar_defstring(k);
+       t = cvar_type(k);
+       if(strstrofs(strcat(" ", autocvar_menu_forced_saved_cvars, " "), strcat(" ", k, " "), 0) >= 0)
+               theAlpha = SKINALPHA_CVARLIST_SAVED;
+       else if(strstrofs(strcat(" ", autocvar_menu_reverted_nonsaved_cvars, " "), strcat(" ", k, " "), 0) >= 0)
+               theAlpha = SKINALPHA_CVARLIST_TEMPORARY;
+       else if(t & CVAR_TYPEFLAG_SAVED)
+               theAlpha = SKINALPHA_CVARLIST_SAVED;
+       else
+               theAlpha = SKINALPHA_CVARLIST_TEMPORARY;
+       if(v == d)
+               theColor = SKINCOLOR_CVARLIST_UNCHANGED;
+       else
+               theColor = SKINCOLOR_CVARLIST_CHANGED;
+
+       s = draw_TextShortenToWidth(k, me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
+       s = draw_TextShortenToWidth(v, me.columnValueSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + me.columnValueOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
+}
+
+float XonoticCvarList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if (scan == K_MOUSE3 || ((shift & S_CTRL) && scan == K_SPACE))
+       {
+               CvarList_Revert_Click(world, me);
+               return 1;
+       }
+       else if(scan == K_ENTER)
+       {
+               me.cvarValueBox.parent.setFocus(me.cvarValueBox.parent, me.cvarValueBox);
+               return 1;
+       }
+       else if(SUPER(XonoticCvarList).keyDown(me, scan, ascii, shift))
+               return 1;
+       else if(!me.controlledTextbox)
+               return 0;
+       else
+               return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);
+}
+
+float XonoticCvarList_mouseRelease(entity me, vector pos)
+{
+       if(me.pressed == 2)
+               me.cvarValueBox.parent.setFocus(me.cvarValueBox.parent, me.cvarValueBox);
+       return SUPER(XonoticCvarList).mouseRelease(me, pos);
+}
+
+void CvarList_Value_Change(entity box, entity me)
+{
+       cvar_set(me.cvarNameBox.text, box.text);
+       if(me.cvarNeedsForcing)
+       {
+               localcmd(sprintf("\nseta %1$s \"$%1$s\"\n", me.cvarName));
+               cvar_set("menu_reverted_nonsaved_cvars", substring(strreplace(strcat(" ", me.cvarName, " "), " ", strcat(" ", autocvar_menu_reverted_nonsaved_cvars, " ")), 1, -2));
+               if (autocvar_menu_forced_saved_cvars == "")
+                       cvar_set("menu_forced_saved_cvars", me.cvarName);
+               else
+                       cvar_set("menu_forced_saved_cvars", strcat(autocvar_menu_forced_saved_cvars, " ", me.cvarName));
+               me.cvarNeedsForcing = 0;
+               me.updateCvarType(me);
+       }
+}
+
+void CvarList_Revert_Click(entity btn, entity me)
+{
+       me.cvarValueBox.setText(me.cvarValueBox, me.cvarDefault);
+       me.cvarValueBox.cursorPos = strlen(me.cvarDefault);
+       if(strstrofs(strcat(" ", autocvar_menu_forced_saved_cvars, " "), strcat(" ", me.cvarName, " "), 0) >= 0)
+       {
+               cvar_set("menu_forced_saved_cvars", substring(strreplace(strcat(" ", me.cvarName, " "), " ", strcat(" ", autocvar_menu_forced_saved_cvars, " ")), 1, -2));
+               if (autocvar_menu_reverted_nonsaved_cvars == "")
+                       cvar_set("menu_reverted_nonsaved_cvars", me.cvarName);
+               else
+                       cvar_set("menu_reverted_nonsaved_cvars", strcat(autocvar_menu_reverted_nonsaved_cvars, " ", me.cvarName));
+       }
+       me.cvarNeedsForcing = me.updateCvarType(me);
+}
+
+void CvarList_End_Editing(entity box, entity me)
+{
+       box.parent.setFocus(box.parent, me);
+}
+
+#endif
diff --git a/qcsrc/menu/xonotic/demolist.c b/qcsrc/menu/xonotic/demolist.c
deleted file mode 100644 (file)
index 9f59096..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticDemoList) EXTENDS(XonoticListBox)
-       METHOD(XonoticDemoList, configureXonoticDemoList, void(entity))
-       ATTRIB(XonoticDemoList, rowsPerItem, float, 1)
-       METHOD(XonoticDemoList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticDemoList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticDemoList, getDemos, void(entity))
-       METHOD(XonoticDemoList, startDemo, void(entity))
-       METHOD(XonoticDemoList, timeDemo, void(entity))
-       METHOD(XonoticDemoList, demoName, string(entity, float))
-       METHOD(XonoticDemoList, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticDemoList, keyDown, float(entity, float, float, float))
-       METHOD(XonoticDemoList, destroy, void(entity))
-       METHOD(XonoticDemoList, showNotify, void(entity))
-
-       ATTRIB(XonoticDemoList, listDemo, float, -1)
-       ATTRIB(XonoticDemoList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticDemoList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticDemoList, columnNameSize, float, 0)
-       ATTRIB(XonoticDemoList, realUpperMargin, float, 0)
-       ATTRIB(XonoticDemoList, origin, vector, '0 0 0')
-       ATTRIB(XonoticDemoList, itemAbsSize, vector, '0 0 0')
-
-       ATTRIB(XonoticDemoList, filterString, string, string_null)
-ENDCLASS(XonoticDemoList)
-
-entity demolist; // for reference elsewhere
-entity makeXonoticDemoList();
-void DemoList_Refresh_Click(entity btn, entity me);
-void DemoList_Filter_Change(entity box, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-
-entity makeXonoticDemoList()
-{
-       entity me;
-       me = spawnXonoticDemoList();
-       me.configureXonoticDemoList(me);
-       return me;
-}
-
-void XonoticDemoList_configureXonoticDemoList(entity me)
-{
-       me.configureXonoticListBox(me);
-       me.getDemos(me);
-}
-
-string XonoticDemoList_demoName(entity me, float i)
-{
-       string s;
-       s = bufstr_get(me.listDemo, i);
-
-       if(substring(s, 0, 1) == "/")
-               s = substring(s, 1, strlen(s) - 1);  // remove the first forward slash
-
-       return s;
-}
-
-// if subdir is TRUE look in subdirectories too (1 level)
-void getDemos_for_ext(entity me, string ext, float subdir)
-{
-       string s;
-       if (subdir)
-               s="demos/*/";
-       else
-               s="demos/";
-       if(me.filterString)
-               s=strcat(s, me.filterString, ext);
-       else
-               s=strcat(s, "*", ext);
-
-       float list, i, n;
-       list = search_begin(s, FALSE, TRUE);
-       if(list >= 0)
-       {
-               n = search_getsize(list);
-               for(i = 0; i < n; ++i)
-               {
-                       s = search_getfilename(list, i); // get initial full file name
-                       s = substring(s, 6, (strlen(s) - 6 - 4)); // remove "demos/" prefix and ".dem" suffix
-                       s = strdecolorize(s); // remove any pre-existing colors
-                       if(subdir)
-                       {
-                               s = strreplace("/", "^7/", s); // clear colors at the forward slash
-                               s = strcat("/", rgb_to_hexcolor(SKINCOLOR_DEMOLIST_SUBDIR), s); // add a forward slash for sorting, then color
-                               bufstr_add(me.listDemo, s, TRUE);
-                       }
-                       else { bufstr_add(me.listDemo, s, TRUE); }
-               }
-               search_end(list);
-       }
-
-       if (subdir)
-               getDemos_for_ext(me, ext, FALSE);
-}
-
-void XonoticDemoList_getDemos(entity me)
-{
-       if (me.listDemo >= 0)
-               buf_del(me.listDemo);
-       me.listDemo = buf_create();
-       if (me.listDemo < 0)
-       {
-               me.nItems = 0;
-               return;
-       }
-       getDemos_for_ext(me, ".dem", TRUE);
-       me.nItems = buf_getsize(me.listDemo);
-       if(me.nItems > 0)
-               buf_sort(me.listDemo, 128, FALSE);
-}
-
-void XonoticDemoList_destroy(entity me)
-{
-       if(me.nItems > 0)
-               buf_del(me.listDemo);
-}
-
-void XonoticDemoList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemAbsSize = '0 0 0';
-       SUPER(XonoticDemoList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
-
-       me.columnNameOrigin = me.realFontSize_x;
-       me.columnNameSize = 1 - 2 * me.realFontSize_x;
-}
-
-void XonoticDemoList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string s;
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-
-       s = me.demoName(me,i);
-       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 1);
-}
-
-void XonoticDemoList_showNotify(entity me)
-{
-       me.getDemos(me);
-}
-
-void DemoList_Refresh_Click(entity btn, entity me)
-{
-       me.getDemos(me);
-       me.setSelected(me, 0); //always select the first element after a list update
-}
-
-void DemoList_Filter_Change(entity box, entity me)
-{
-       if(me.filterString)
-               strunzone(me.filterString);
-
-       if(box.text != "")
-       {
-               if (strstrofs(box.text, "*", 0) >= 0 || strstrofs(box.text, "?", 0) >= 0)
-                       me.filterString = strzone(box.text);
-               else
-                       me.filterString = strzone(strcat("*", box.text, "*"));
-       }
-       else
-               me.filterString = string_null;
-
-       me.getDemos(me);
-}
-
-void XonoticDemoList_startDemo(entity me)
-{
-       string s;
-       s = me.demoName(me, me.selectedItem);
-       s = strdecolorize(s);
-
-       localcmd("playdemo \"demos/", s, ".dem\" \nwait \ntogglemenu\n");
-}
-
-void XonoticDemoList_timeDemo(entity me)
-{
-       string s;
-       s = me.demoName(me, me.selectedItem);
-       s = strdecolorize(s);
-
-       localcmd("timedemo \"demos/", s, ".dem\" \nwait \ntogglemenu\n");
-}
-
-void DemoConfirm_ListClick_Check_Gamestatus(entity me)
-{
-       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, lets watch the demo
-       {
-               me.startDemo(me);
-       }
-       else // already in a match, player has to confirm
-       {
-               DialogOpenButton_Click_withCoords(
-                       me,
-                       main.demostartconfirmDialog,
-                       boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size),
-                       boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size)
-               );
-       }
-}
-
-void XonoticDemoList_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       DemoConfirm_ListClick_Check_Gamestatus(me);
-}
-
-float XonoticDemoList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if(scan == K_ENTER || scan == K_KP_ENTER)
-       {
-               DemoConfirm_ListClick_Check_Gamestatus(me);
-               return 1;
-       }
-       else
-       {
-               return SUPER(XonoticDemoList).keyDown(me, scan, ascii, shift);
-       }
-}
-#endif
-
diff --git a/qcsrc/menu/xonotic/demolist.qc b/qcsrc/menu/xonotic/demolist.qc
new file mode 100644 (file)
index 0000000..9f59096
--- /dev/null
@@ -0,0 +1,226 @@
+#ifdef INTERFACE
+CLASS(XonoticDemoList) EXTENDS(XonoticListBox)
+       METHOD(XonoticDemoList, configureXonoticDemoList, void(entity))
+       ATTRIB(XonoticDemoList, rowsPerItem, float, 1)
+       METHOD(XonoticDemoList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticDemoList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticDemoList, getDemos, void(entity))
+       METHOD(XonoticDemoList, startDemo, void(entity))
+       METHOD(XonoticDemoList, timeDemo, void(entity))
+       METHOD(XonoticDemoList, demoName, string(entity, float))
+       METHOD(XonoticDemoList, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticDemoList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticDemoList, destroy, void(entity))
+       METHOD(XonoticDemoList, showNotify, void(entity))
+
+       ATTRIB(XonoticDemoList, listDemo, float, -1)
+       ATTRIB(XonoticDemoList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticDemoList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticDemoList, columnNameSize, float, 0)
+       ATTRIB(XonoticDemoList, realUpperMargin, float, 0)
+       ATTRIB(XonoticDemoList, origin, vector, '0 0 0')
+       ATTRIB(XonoticDemoList, itemAbsSize, vector, '0 0 0')
+
+       ATTRIB(XonoticDemoList, filterString, string, string_null)
+ENDCLASS(XonoticDemoList)
+
+entity demolist; // for reference elsewhere
+entity makeXonoticDemoList();
+void DemoList_Refresh_Click(entity btn, entity me);
+void DemoList_Filter_Change(entity box, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeXonoticDemoList()
+{
+       entity me;
+       me = spawnXonoticDemoList();
+       me.configureXonoticDemoList(me);
+       return me;
+}
+
+void XonoticDemoList_configureXonoticDemoList(entity me)
+{
+       me.configureXonoticListBox(me);
+       me.getDemos(me);
+}
+
+string XonoticDemoList_demoName(entity me, float i)
+{
+       string s;
+       s = bufstr_get(me.listDemo, i);
+
+       if(substring(s, 0, 1) == "/")
+               s = substring(s, 1, strlen(s) - 1);  // remove the first forward slash
+
+       return s;
+}
+
+// if subdir is TRUE look in subdirectories too (1 level)
+void getDemos_for_ext(entity me, string ext, float subdir)
+{
+       string s;
+       if (subdir)
+               s="demos/*/";
+       else
+               s="demos/";
+       if(me.filterString)
+               s=strcat(s, me.filterString, ext);
+       else
+               s=strcat(s, "*", ext);
+
+       float list, i, n;
+       list = search_begin(s, FALSE, TRUE);
+       if(list >= 0)
+       {
+               n = search_getsize(list);
+               for(i = 0; i < n; ++i)
+               {
+                       s = search_getfilename(list, i); // get initial full file name
+                       s = substring(s, 6, (strlen(s) - 6 - 4)); // remove "demos/" prefix and ".dem" suffix
+                       s = strdecolorize(s); // remove any pre-existing colors
+                       if(subdir)
+                       {
+                               s = strreplace("/", "^7/", s); // clear colors at the forward slash
+                               s = strcat("/", rgb_to_hexcolor(SKINCOLOR_DEMOLIST_SUBDIR), s); // add a forward slash for sorting, then color
+                               bufstr_add(me.listDemo, s, TRUE);
+                       }
+                       else { bufstr_add(me.listDemo, s, TRUE); }
+               }
+               search_end(list);
+       }
+
+       if (subdir)
+               getDemos_for_ext(me, ext, FALSE);
+}
+
+void XonoticDemoList_getDemos(entity me)
+{
+       if (me.listDemo >= 0)
+               buf_del(me.listDemo);
+       me.listDemo = buf_create();
+       if (me.listDemo < 0)
+       {
+               me.nItems = 0;
+               return;
+       }
+       getDemos_for_ext(me, ".dem", TRUE);
+       me.nItems = buf_getsize(me.listDemo);
+       if(me.nItems > 0)
+               buf_sort(me.listDemo, 128, FALSE);
+}
+
+void XonoticDemoList_destroy(entity me)
+{
+       if(me.nItems > 0)
+               buf_del(me.listDemo);
+}
+
+void XonoticDemoList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticDemoList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+
+       me.columnNameOrigin = me.realFontSize_x;
+       me.columnNameSize = 1 - 2 * me.realFontSize_x;
+}
+
+void XonoticDemoList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s;
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       s = me.demoName(me,i);
+       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_TEXT, SKINALPHA_TEXT, 1);
+}
+
+void XonoticDemoList_showNotify(entity me)
+{
+       me.getDemos(me);
+}
+
+void DemoList_Refresh_Click(entity btn, entity me)
+{
+       me.getDemos(me);
+       me.setSelected(me, 0); //always select the first element after a list update
+}
+
+void DemoList_Filter_Change(entity box, entity me)
+{
+       if(me.filterString)
+               strunzone(me.filterString);
+
+       if(box.text != "")
+       {
+               if (strstrofs(box.text, "*", 0) >= 0 || strstrofs(box.text, "?", 0) >= 0)
+                       me.filterString = strzone(box.text);
+               else
+                       me.filterString = strzone(strcat("*", box.text, "*"));
+       }
+       else
+               me.filterString = string_null;
+
+       me.getDemos(me);
+}
+
+void XonoticDemoList_startDemo(entity me)
+{
+       string s;
+       s = me.demoName(me, me.selectedItem);
+       s = strdecolorize(s);
+
+       localcmd("playdemo \"demos/", s, ".dem\" \nwait \ntogglemenu\n");
+}
+
+void XonoticDemoList_timeDemo(entity me)
+{
+       string s;
+       s = me.demoName(me, me.selectedItem);
+       s = strdecolorize(s);
+
+       localcmd("timedemo \"demos/", s, ".dem\" \nwait \ntogglemenu\n");
+}
+
+void DemoConfirm_ListClick_Check_Gamestatus(entity me)
+{
+       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, lets watch the demo
+       {
+               me.startDemo(me);
+       }
+       else // already in a match, player has to confirm
+       {
+               DialogOpenButton_Click_withCoords(
+                       me,
+                       main.demostartconfirmDialog,
+                       boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size),
+                       boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size)
+               );
+       }
+}
+
+void XonoticDemoList_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       DemoConfirm_ListClick_Check_Gamestatus(me);
+}
+
+float XonoticDemoList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_KP_ENTER)
+       {
+               DemoConfirm_ListClick_Check_Gamestatus(me);
+               return 1;
+       }
+       else
+       {
+               return SUPER(XonoticDemoList).keyDown(me, scan, ascii, shift);
+       }
+}
+#endif
+
diff --git a/qcsrc/menu/xonotic/dialog.c b/qcsrc/menu/xonotic/dialog.c
deleted file mode 100644 (file)
index 6ca9025..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticDialog) EXTENDS(Dialog)
-       // still to be customized by user
-       /*
-       ATTRIB(XonoticDialog, closable, float, 1)
-       ATTRIB(XonoticDialog, title, string, _("Form1")) // ;)
-       ATTRIB(XonoticDialog, color, vector, '1 0.5 1')
-       ATTRIB(XonoticDialog, intendedWidth, float, 0)
-       ATTRIB(XonoticDialog, rows, float, 3)
-       ATTRIB(XonoticDialog, columns, float, 2)
-       */
-       ATTRIB(XonoticDialog, marginTop, float, SKINMARGIN_TOP) // pixels
-       ATTRIB(XonoticDialog, marginBottom, float, SKINMARGIN_BOTTOM) // pixels
-       ATTRIB(XonoticDialog, marginLeft, float, SKINMARGIN_LEFT) // pixels
-       ATTRIB(XonoticDialog, marginRight, float, SKINMARGIN_RIGHT) // pixels
-       ATTRIB(XonoticDialog, columnSpacing, float, SKINMARGIN_COLUMNS) // pixels
-       ATTRIB(XonoticDialog, rowSpacing, float, SKINMARGIN_ROWS) // pixels
-       ATTRIB(XonoticDialog, rowHeight, float, SKINFONTSIZE_NORMAL * SKINHEIGHT_NORMAL) // pixels
-       ATTRIB(XonoticDialog, titleHeight, float, SKINFONTSIZE_TITLE * SKINHEIGHT_TITLE) // pixels
-       ATTRIB(XonoticDialog, titleFontSize, float, SKINFONTSIZE_TITLE) // pixels
-
-       ATTRIB(XonoticDialog, backgroundImage, string, SKINGFX_DIALOGBORDER)
-       ATTRIB(XonoticDialog, borderLines, float, SKINHEIGHT_DIALOGBORDER)
-       ATTRIB(XonoticDialog, closeButtonImage, string, SKINGFX_CLOSEBUTTON)
-       ATTRIB(XonoticDialog, zoomedOutTitleBarPosition, float, SKINHEIGHT_ZOOMEDTITLE * 0.5 - 0.5)
-       ATTRIB(XonoticDialog, zoomedOutTitleBar, float, SKINHEIGHT_ZOOMEDTITLE != 0)
-
-       ATTRIB(XonoticDialog, alpha, float, SKINALPHA_TEXT)
-
-       METHOD(XonoticDialog, configureDialog, void(entity))
-ENDCLASS(XonoticDialog)
-#ifndef IMPLEMENTATION
-entity currentDialog;
-#endif
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticDialog_configureDialog(entity me)
-{
-       currentDialog = me;
-       SUPER(XonoticDialog).configureDialog(me);
-       me.tooltip = getZonedTooltipForIdentifier(me.classname);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog.qc b/qcsrc/menu/xonotic/dialog.qc
new file mode 100644 (file)
index 0000000..6ca9025
--- /dev/null
@@ -0,0 +1,44 @@
+#ifdef INTERFACE
+CLASS(XonoticDialog) EXTENDS(Dialog)
+       // still to be customized by user
+       /*
+       ATTRIB(XonoticDialog, closable, float, 1)
+       ATTRIB(XonoticDialog, title, string, _("Form1")) // ;)
+       ATTRIB(XonoticDialog, color, vector, '1 0.5 1')
+       ATTRIB(XonoticDialog, intendedWidth, float, 0)
+       ATTRIB(XonoticDialog, rows, float, 3)
+       ATTRIB(XonoticDialog, columns, float, 2)
+       */
+       ATTRIB(XonoticDialog, marginTop, float, SKINMARGIN_TOP) // pixels
+       ATTRIB(XonoticDialog, marginBottom, float, SKINMARGIN_BOTTOM) // pixels
+       ATTRIB(XonoticDialog, marginLeft, float, SKINMARGIN_LEFT) // pixels
+       ATTRIB(XonoticDialog, marginRight, float, SKINMARGIN_RIGHT) // pixels
+       ATTRIB(XonoticDialog, columnSpacing, float, SKINMARGIN_COLUMNS) // pixels
+       ATTRIB(XonoticDialog, rowSpacing, float, SKINMARGIN_ROWS) // pixels
+       ATTRIB(XonoticDialog, rowHeight, float, SKINFONTSIZE_NORMAL * SKINHEIGHT_NORMAL) // pixels
+       ATTRIB(XonoticDialog, titleHeight, float, SKINFONTSIZE_TITLE * SKINHEIGHT_TITLE) // pixels
+       ATTRIB(XonoticDialog, titleFontSize, float, SKINFONTSIZE_TITLE) // pixels
+
+       ATTRIB(XonoticDialog, backgroundImage, string, SKINGFX_DIALOGBORDER)
+       ATTRIB(XonoticDialog, borderLines, float, SKINHEIGHT_DIALOGBORDER)
+       ATTRIB(XonoticDialog, closeButtonImage, string, SKINGFX_CLOSEBUTTON)
+       ATTRIB(XonoticDialog, zoomedOutTitleBarPosition, float, SKINHEIGHT_ZOOMEDTITLE * 0.5 - 0.5)
+       ATTRIB(XonoticDialog, zoomedOutTitleBar, float, SKINHEIGHT_ZOOMEDTITLE != 0)
+
+       ATTRIB(XonoticDialog, alpha, float, SKINALPHA_TEXT)
+
+       METHOD(XonoticDialog, configureDialog, void(entity))
+ENDCLASS(XonoticDialog)
+#ifndef IMPLEMENTATION
+entity currentDialog;
+#endif
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticDialog_configureDialog(entity me)
+{
+       currentDialog = me;
+       SUPER(XonoticDialog).configureDialog(me);
+       me.tooltip = getZonedTooltipForIdentifier(me.classname);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_credits.c b/qcsrc/menu/xonotic/dialog_credits.c
deleted file mode 100644 (file)
index e90ae4b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCreditsDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticCreditsDialog, fill, void(entity))
-       METHOD(XonoticCreditsDialog, focusEnter, void(entity))
-       ATTRIB(XonoticCreditsDialog, title, string, _("Credits"))
-       ATTRIB(XonoticCreditsDialog, color, vector, SKINCOLOR_DIALOG_CREDITS)
-       ATTRIB(XonoticCreditsDialog, intendedWidth, float, SKINWIDTH_CREDITS)
-       ATTRIB(XonoticCreditsDialog, rows, float, SKINROWS_CREDITS)
-       ATTRIB(XonoticCreditsDialog, columns, float, 2)
-       ATTRIB(XonoticCreditsDialog, creditsList, entity, NULL)
-ENDCLASS(XonoticCreditsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticCreditsDialog_fill(entity me)
-{
-       entity e;
-       me.TR(me);
-               me.TD(me, me.rows - 1, me.columns, me.creditsList = makeXonoticCreditsList());
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-void XonoticCreditsDialog_focusEnter(entity me)
-{
-       me.creditsList.scrolling = time + 1;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_credits.qc b/qcsrc/menu/xonotic/dialog_credits.qc
new file mode 100644 (file)
index 0000000..e90ae4b
--- /dev/null
@@ -0,0 +1,29 @@
+#ifdef INTERFACE
+CLASS(XonoticCreditsDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticCreditsDialog, fill, void(entity))
+       METHOD(XonoticCreditsDialog, focusEnter, void(entity))
+       ATTRIB(XonoticCreditsDialog, title, string, _("Credits"))
+       ATTRIB(XonoticCreditsDialog, color, vector, SKINCOLOR_DIALOG_CREDITS)
+       ATTRIB(XonoticCreditsDialog, intendedWidth, float, SKINWIDTH_CREDITS)
+       ATTRIB(XonoticCreditsDialog, rows, float, SKINROWS_CREDITS)
+       ATTRIB(XonoticCreditsDialog, columns, float, 2)
+       ATTRIB(XonoticCreditsDialog, creditsList, entity, NULL)
+ENDCLASS(XonoticCreditsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticCreditsDialog_fill(entity me)
+{
+       entity e;
+       me.TR(me);
+               me.TD(me, me.rows - 1, me.columns, me.creditsList = makeXonoticCreditsList());
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+void XonoticCreditsDialog_focusEnter(entity me)
+{
+       me.creditsList.scrolling = time + 1;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_firstrun.c b/qcsrc/menu/xonotic/dialog_firstrun.c
deleted file mode 100644 (file)
index 9098870..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticFirstRunDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticFirstRunDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
-       ATTRIB(XonoticFirstRunDialog, title, string, _("Welcome"))
-       ATTRIB(XonoticFirstRunDialog, color, vector, SKINCOLOR_DIALOG_FIRSTRUN)
-       ATTRIB(XonoticFirstRunDialog, intendedWidth, float, 0.7)
-       ATTRIB(XonoticFirstRunDialog, rows, float, 16)
-       ATTRIB(XonoticFirstRunDialog, columns, float, 6)
-       ATTRIB(XonoticFirstRunDialog, name, string, "FirstRun")
-       ATTRIB(XonoticFirstRunDialog, playerNameLabel, entity, NULL)
-       ATTRIB(XonoticFirstRunDialog, playerNameLabelAlpha, float, 0)
-
-       ATTRIB(XonoticFirstRunDialog, closable, float, 0)
-ENDCLASS(XonoticFirstRunDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-float CheckFirstRunButton(entity me)
-{
-       if(cvar_string("_cl_name") != cvar_defstring("_cl_name"))
-               return 1;
-
-       if(cvar_string("_menu_prvm_language") != prvm_language)
-               return 1; // OK will then reopen the dialog in another language
-
-       if(cvar_string("cl_allow_uid2name") != "-1")
-               return 1;
-
-       return 0;
-}
-
-void firstRun_setLanguage(entity me)
-{
-       if(prvm_language != cvar_string("_menu_prvm_language"))
-               localcmd("\nprvm_language \"$_menu_prvm_language\"; saveconfig; menu_restart\n");
-}
-
-void XonoticFirstRunDialog_fill(entity me)
-{
-       entity e;
-       entity label, box;
-
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 1);
-               me.TD(me, 2, 4, e = makeXonoticTextLabel(0, _("Welcome to Xonotic, please select your language preference and enter your player name to get started.  You can change these options later through the menu system.")));
-               e.allowWrap = 1;
-       me.TR(me);
-
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 0.5, me.playerNameLabel = makeXonoticTextLabel(0, _("Name:")));
-                       me.playerNameLabelAlpha = me.playerNameLabel.alpha;
-               me.TD(me, 1, 3.25, label = makeXonoticTextLabel(0, string_null));
-                       label.allowCut = 1;
-                       label.allowColors = 1;
-                       label.alpha = 1;
-       me.TR(me);
-               me.TD(me, 1, 3.75, box = makeXonoticInputBox(1, "_cl_name"));
-                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
-                       box.maxLength = -127; // negative means encoded length in bytes
-                       box.saveImmediately = 1;
-                       label.textEntity = box;
-       me.TR(me);
-               me.TD(me, 5, 1.25, e = makeXonoticColorpicker(box));
-               me.TD(me, 5, 2.5, e = makeXonoticCharmap(box));
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-
-       me.gotoRC(me, 3, 4); me.setFirstColumn(me, me.currentColumn);
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0, _("Text language:")));
-       me.TR(me);
-               me.TD(me, 6, 2, e = makeXonoticLanguageList());
-                       e.name = "languageselector_firstrun";
-                       e.setLanguage = firstRun_setLanguage;
-       me.TR(me);
-       me.TR(me);
-
-       me.gotoRC(me, me.rows - 4, 0);
-       me.TD(me, 1, me.columns, e = makeXonoticTextLabel(0.5, _("Allow player statistics to use your nickname at stats.xonotic.org?")));
-
-       me.gotoRC(me, me.rows - 3, 0);
-       me.TDempty(me, 1.5);
-       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "1", ZCTX(_("ALWU2N^Yes"))));
-       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "0", ZCTX(_("ALWU2N^No"))));
-       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "-1", ZCTX(_("ALWU2N^Undecided"))));
-
-       // because of the language selector, this is a menu_restart!
-       me.gotoRC(me, me.rows - 1, 0);
-       me.TD(me, 1, me.columns, e = makeXonoticCommandButton(_("Save settings"), '0 0 0', "prvm_language \"$_menu_prvm_language\"; saveconfig; menu_restart", COMMANDBUTTON_APPLY));
-               setDependentWeird(e, CheckFirstRunButton);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_firstrun.qc b/qcsrc/menu/xonotic/dialog_firstrun.qc
new file mode 100644 (file)
index 0000000..9098870
--- /dev/null
@@ -0,0 +1,96 @@
+#ifdef INTERFACE
+CLASS(XonoticFirstRunDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticFirstRunDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
+       ATTRIB(XonoticFirstRunDialog, title, string, _("Welcome"))
+       ATTRIB(XonoticFirstRunDialog, color, vector, SKINCOLOR_DIALOG_FIRSTRUN)
+       ATTRIB(XonoticFirstRunDialog, intendedWidth, float, 0.7)
+       ATTRIB(XonoticFirstRunDialog, rows, float, 16)
+       ATTRIB(XonoticFirstRunDialog, columns, float, 6)
+       ATTRIB(XonoticFirstRunDialog, name, string, "FirstRun")
+       ATTRIB(XonoticFirstRunDialog, playerNameLabel, entity, NULL)
+       ATTRIB(XonoticFirstRunDialog, playerNameLabelAlpha, float, 0)
+
+       ATTRIB(XonoticFirstRunDialog, closable, float, 0)
+ENDCLASS(XonoticFirstRunDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+float CheckFirstRunButton(entity me)
+{
+       if(cvar_string("_cl_name") != cvar_defstring("_cl_name"))
+               return 1;
+
+       if(cvar_string("_menu_prvm_language") != prvm_language)
+               return 1; // OK will then reopen the dialog in another language
+
+       if(cvar_string("cl_allow_uid2name") != "-1")
+               return 1;
+
+       return 0;
+}
+
+void firstRun_setLanguage(entity me)
+{
+       if(prvm_language != cvar_string("_menu_prvm_language"))
+               localcmd("\nprvm_language \"$_menu_prvm_language\"; saveconfig; menu_restart\n");
+}
+
+void XonoticFirstRunDialog_fill(entity me)
+{
+       entity e;
+       entity label, box;
+
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 1);
+               me.TD(me, 2, 4, e = makeXonoticTextLabel(0, _("Welcome to Xonotic, please select your language preference and enter your player name to get started.  You can change these options later through the menu system.")));
+               e.allowWrap = 1;
+       me.TR(me);
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 0.5, me.playerNameLabel = makeXonoticTextLabel(0, _("Name:")));
+                       me.playerNameLabelAlpha = me.playerNameLabel.alpha;
+               me.TD(me, 1, 3.25, label = makeXonoticTextLabel(0, string_null));
+                       label.allowCut = 1;
+                       label.allowColors = 1;
+                       label.alpha = 1;
+       me.TR(me);
+               me.TD(me, 1, 3.75, box = makeXonoticInputBox(1, "_cl_name"));
+                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
+                       box.maxLength = -127; // negative means encoded length in bytes
+                       box.saveImmediately = 1;
+                       label.textEntity = box;
+       me.TR(me);
+               me.TD(me, 5, 1.25, e = makeXonoticColorpicker(box));
+               me.TD(me, 5, 2.5, e = makeXonoticCharmap(box));
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+
+       me.gotoRC(me, 3, 4); me.setFirstColumn(me, me.currentColumn);
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0, _("Text language:")));
+       me.TR(me);
+               me.TD(me, 6, 2, e = makeXonoticLanguageList());
+                       e.name = "languageselector_firstrun";
+                       e.setLanguage = firstRun_setLanguage;
+       me.TR(me);
+       me.TR(me);
+
+       me.gotoRC(me, me.rows - 4, 0);
+       me.TD(me, 1, me.columns, e = makeXonoticTextLabel(0.5, _("Allow player statistics to use your nickname at stats.xonotic.org?")));
+
+       me.gotoRC(me, me.rows - 3, 0);
+       me.TDempty(me, 1.5);
+       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "1", ZCTX(_("ALWU2N^Yes"))));
+       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "0", ZCTX(_("ALWU2N^No"))));
+       me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "cl_allow_uid2name", "-1", ZCTX(_("ALWU2N^Undecided"))));
+
+       // because of the language selector, this is a menu_restart!
+       me.gotoRC(me, me.rows - 1, 0);
+       me.TD(me, 1, me.columns, e = makeXonoticCommandButton(_("Save settings"), '0 0 0', "prvm_language \"$_menu_prvm_language\"; saveconfig; menu_restart", COMMANDBUTTON_APPLY));
+               setDependentWeird(e, CheckFirstRunButton);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_ammo.c b/qcsrc/menu/xonotic/dialog_hudpanel_ammo.c
deleted file mode 100644 (file)
index 15095b2..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDAmmoDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDAmmoDialog, fill, void(entity))
-       ATTRIB(XonoticHUDAmmoDialog, title, string, _("Ammo Panel"))
-       ATTRIB(XonoticHUDAmmoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDAmmoDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDAmmoDialog, rows, float, 15)
-       ATTRIB(XonoticHUDAmmoDialog, columns, float, 4)
-       ATTRIB(XonoticHUDAmmoDialog, name, string, "HUDammo")
-       ATTRIB(XonoticHUDAmmoDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDAmmoDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDAmmoDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "ammo";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Ammunition display:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_ammo_onlycurrent", _("Show only current ammo type")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Noncurrent alpha:")));
-               me.TD(me, 1, 2.6, e = makeXonoticSlider(0, 1, 0.1, "hud_panel_ammo_noncurrent_alpha"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Noncurrent scale:")));
-               me.TD(me, 1, 2.6, e = makeXonoticSlider(0, 1, 0.1, "hud_panel_ammo_noncurrent_scale"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Align icon:")));
-                       me.TD(me, 1, 2.6/2, e = makeXonoticRadioButton(2, "hud_panel_ammo_iconalign", "0", _("Left")));
-                       me.TD(me, 1, 2.6/2, e = makeXonoticRadioButton(2, "hud_panel_ammo_iconalign", "1", _("Right")));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc b/qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc
new file mode 100644 (file)
index 0000000..15095b2
--- /dev/null
@@ -0,0 +1,41 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDAmmoDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDAmmoDialog, fill, void(entity))
+       ATTRIB(XonoticHUDAmmoDialog, title, string, _("Ammo Panel"))
+       ATTRIB(XonoticHUDAmmoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDAmmoDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDAmmoDialog, rows, float, 15)
+       ATTRIB(XonoticHUDAmmoDialog, columns, float, 4)
+       ATTRIB(XonoticHUDAmmoDialog, name, string, "HUDammo")
+       ATTRIB(XonoticHUDAmmoDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDAmmoDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDAmmoDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "ammo";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Ammunition display:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_ammo_onlycurrent", _("Show only current ammo type")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Noncurrent alpha:")));
+               me.TD(me, 1, 2.6, e = makeXonoticSlider(0, 1, 0.1, "hud_panel_ammo_noncurrent_alpha"));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Noncurrent scale:")));
+               me.TD(me, 1, 2.6, e = makeXonoticSlider(0, 1, 0.1, "hud_panel_ammo_noncurrent_scale"));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Align icon:")));
+                       me.TD(me, 1, 2.6/2, e = makeXonoticRadioButton(2, "hud_panel_ammo_iconalign", "0", _("Left")));
+                       me.TD(me, 1, 2.6/2, e = makeXonoticRadioButton(2, "hud_panel_ammo_iconalign", "1", _("Right")));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_buffs.c b/qcsrc/menu/xonotic/dialog_hudpanel_buffs.c
deleted file mode 100644 (file)
index ac1033c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDBuffsDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDBuffsDialog, fill, void(entity))
-       ATTRIB(XonoticHUDBuffsDialog, title, string, _("Buffs Panel"))
-       ATTRIB(XonoticHUDBuffsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDBuffsDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDBuffsDialog, rows, float, 15)
-       ATTRIB(XonoticHUDBuffsDialog, columns, float, 4)
-       ATTRIB(XonoticHUDBuffsDialog, name, string, "HUDbuffs")
-       ATTRIB(XonoticHUDBuffsDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDBuffsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDBuffsDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "buffs";
-
-       DIALOG_HUDPANEL_COMMON();
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_buffs.qc b/qcsrc/menu/xonotic/dialog_hudpanel_buffs.qc
new file mode 100644 (file)
index 0000000..ac1033c
--- /dev/null
@@ -0,0 +1,22 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDBuffsDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDBuffsDialog, fill, void(entity))
+       ATTRIB(XonoticHUDBuffsDialog, title, string, _("Buffs Panel"))
+       ATTRIB(XonoticHUDBuffsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDBuffsDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDBuffsDialog, rows, float, 15)
+       ATTRIB(XonoticHUDBuffsDialog, columns, float, 4)
+       ATTRIB(XonoticHUDBuffsDialog, name, string, "HUDbuffs")
+       ATTRIB(XonoticHUDBuffsDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDBuffsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDBuffsDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "buffs";
+
+       DIALOG_HUDPANEL_COMMON();
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_centerprint.c b/qcsrc/menu/xonotic/dialog_hudpanel_centerprint.c
deleted file mode 100644 (file)
index dce687a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDCenterprintDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDCenterprintDialog, fill, void(entity))
-       ATTRIB(XonoticHUDCenterprintDialog, title, string, _("Centerprint Panel"))
-       ATTRIB(XonoticHUDCenterprintDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDCenterprintDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDCenterprintDialog, rows, float, 15)
-       ATTRIB(XonoticHUDCenterprintDialog, columns, float, 4)
-       ATTRIB(XonoticHUDCenterprintDialog, name, string, "HUDcenterprint")
-       ATTRIB(XonoticHUDCenterprintDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDCenterprintDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDCenterprintDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "centerprint";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Message duration:")));
-               me.TD(me, 1, 2.6, e = makeXonoticSlider(1, 10, 1, "hud_panel_centerprint_time"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Fade time:")));
-               me.TD(me, 1, 2.6, e = makeXonoticSlider(0, 1, 0.05, "hud_panel_centerprint_fade_out"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_centerprint_flip", _("Flip messages order")));
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Text alignment:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-                       me.TD(me, 1, 3.8/3, e = makeXonoticRadioButton(3, "hud_panel_centerprint_align", "0", _("Left")));
-                       me.TD(me, 1, 3.8/3, e = makeXonoticRadioButton(3, "hud_panel_centerprint_align", "0.5", _("Center")));
-                       me.TD(me, 1, 3.8/3, e = makeXonoticRadioButton(3, "hud_panel_centerprint_align", "1", _("Right")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Font scale:")));
-               me.TD(me, 1, 2.6, e = makeXonoticSlider(0.5, 2, 0.1, "hud_panel_centerprint_fontscale"));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc b/qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc
new file mode 100644 (file)
index 0000000..dce687a
--- /dev/null
@@ -0,0 +1,45 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDCenterprintDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDCenterprintDialog, fill, void(entity))
+       ATTRIB(XonoticHUDCenterprintDialog, title, string, _("Centerprint Panel"))
+       ATTRIB(XonoticHUDCenterprintDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDCenterprintDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDCenterprintDialog, rows, float, 15)
+       ATTRIB(XonoticHUDCenterprintDialog, columns, float, 4)
+       ATTRIB(XonoticHUDCenterprintDialog, name, string, "HUDcenterprint")
+       ATTRIB(XonoticHUDCenterprintDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDCenterprintDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDCenterprintDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "centerprint";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Message duration:")));
+               me.TD(me, 1, 2.6, e = makeXonoticSlider(1, 10, 1, "hud_panel_centerprint_time"));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Fade time:")));
+               me.TD(me, 1, 2.6, e = makeXonoticSlider(0, 1, 0.05, "hud_panel_centerprint_fade_out"));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_centerprint_flip", _("Flip messages order")));
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Text alignment:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+                       me.TD(me, 1, 3.8/3, e = makeXonoticRadioButton(3, "hud_panel_centerprint_align", "0", _("Left")));
+                       me.TD(me, 1, 3.8/3, e = makeXonoticRadioButton(3, "hud_panel_centerprint_align", "0.5", _("Center")));
+                       me.TD(me, 1, 3.8/3, e = makeXonoticRadioButton(3, "hud_panel_centerprint_align", "1", _("Right")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Font scale:")));
+               me.TD(me, 1, 2.6, e = makeXonoticSlider(0.5, 2, 0.1, "hud_panel_centerprint_fontscale"));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_chat.c b/qcsrc/menu/xonotic/dialog_hudpanel_chat.c
deleted file mode 100644 (file)
index eb6ced2..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDChatDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDChatDialog, fill, void(entity))
-       ATTRIB(XonoticHUDChatDialog, title, string, _("Chat Panel"))
-       ATTRIB(XonoticHUDChatDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDChatDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDChatDialog, rows, float, 15)
-       ATTRIB(XonoticHUDChatDialog, columns, float, 4)
-       ATTRIB(XonoticHUDChatDialog, name, string, "HUDchat")
-       ATTRIB(XonoticHUDChatDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDChatDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDChatDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "chat";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0, _("Chat entries:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Chat size:")));
-               me.TD(me, 1, 2.6, e = makeXonoticSlider(6, 20, 1, "con_chatsize"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Chat lifetime:")));
-               me.TD(me, 1, 2.6, e = makeXonoticSlider(5, 60, 5, "con_chattime"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "con_chatsound", _("Chat beep sound")));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_chat.qc b/qcsrc/menu/xonotic/dialog_hudpanel_chat.qc
new file mode 100644 (file)
index 0000000..eb6ced2
--- /dev/null
@@ -0,0 +1,36 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDChatDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDChatDialog, fill, void(entity))
+       ATTRIB(XonoticHUDChatDialog, title, string, _("Chat Panel"))
+       ATTRIB(XonoticHUDChatDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDChatDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDChatDialog, rows, float, 15)
+       ATTRIB(XonoticHUDChatDialog, columns, float, 4)
+       ATTRIB(XonoticHUDChatDialog, name, string, "HUDchat")
+       ATTRIB(XonoticHUDChatDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDChatDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDChatDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "chat";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0, _("Chat entries:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Chat size:")));
+               me.TD(me, 1, 2.6, e = makeXonoticSlider(6, 20, 1, "con_chatsize"));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Chat lifetime:")));
+               me.TD(me, 1, 2.6, e = makeXonoticSlider(5, 60, 5, "con_chattime"));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "con_chatsound", _("Chat beep sound")));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.c b/qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.c
deleted file mode 100644 (file)
index bbc3f8c..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDEngineInfoDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDEngineInfoDialog, fill, void(entity))
-       ATTRIB(XonoticHUDEngineInfoDialog, title, string, _("Engine Info Panel"))
-       ATTRIB(XonoticHUDEngineInfoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDEngineInfoDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDEngineInfoDialog, rows, float, 15)
-       ATTRIB(XonoticHUDEngineInfoDialog, columns, float, 4)
-       ATTRIB(XonoticHUDEngineInfoDialog, name, string, "HUDengineinfo")
-       ATTRIB(XonoticHUDEngineInfoDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDEngineInfoDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDEngineInfoDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "engineinfo";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Engine info:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_engineinfo_framecounter_exponentialmovingaverage", _("Use an averaging algorithm for fps")));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc b/qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc
new file mode 100644 (file)
index 0000000..bbc3f8c
--- /dev/null
@@ -0,0 +1,28 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDEngineInfoDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDEngineInfoDialog, fill, void(entity))
+       ATTRIB(XonoticHUDEngineInfoDialog, title, string, _("Engine Info Panel"))
+       ATTRIB(XonoticHUDEngineInfoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDEngineInfoDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDEngineInfoDialog, rows, float, 15)
+       ATTRIB(XonoticHUDEngineInfoDialog, columns, float, 4)
+       ATTRIB(XonoticHUDEngineInfoDialog, name, string, "HUDengineinfo")
+       ATTRIB(XonoticHUDEngineInfoDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDEngineInfoDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDEngineInfoDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "engineinfo";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Engine info:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_engineinfo_framecounter_exponentialmovingaverage", _("Use an averaging algorithm for fps")));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.c b/qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.c
deleted file mode 100644 (file)
index 976139c..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDHealthArmorDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDHealthArmorDialog, fill, void(entity))
-       ATTRIB(XonoticHUDHealthArmorDialog, title, string, _("Health/Armor Panel"))
-       ATTRIB(XonoticHUDHealthArmorDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDHealthArmorDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDHealthArmorDialog, rows, float, 15)
-       ATTRIB(XonoticHUDHealthArmorDialog, columns, float, 4)
-       ATTRIB(XonoticHUDHealthArmorDialog, name, string, "HUDhealtharmor")
-       ATTRIB(XonoticHUDHealthArmorDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDHealthArmorDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDHealthArmorDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "healtharmor";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_healtharmor_progressbar", _("Enable status bar")));
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Status bar alignment:")));
-                       setDependent(e, "hud_panel_healtharmor_progressbar", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_healtharmor_baralign", "0", _("Left")));
-                       setDependent(e, "hud_panel_healtharmor_progressbar", 1, 1);
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_healtharmor_baralign", "1", _("Right")));
-                       setDependent(e, "hud_panel_healtharmor_progressbar", 1, 1);
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_healtharmor_baralign", "2", _("Inward")));
-                       setDependent(e, "hud_panel_healtharmor_progressbar", 1, 1);
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_healtharmor_baralign", "3", _("Outward")));
-                       setDependent(e, "hud_panel_healtharmor_progressbar", 1, 1);
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Icon alignment:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_healtharmor_iconalign", "0", _("Left")));
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_healtharmor_iconalign", "1", _("Right")));
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_healtharmor_iconalign", "2", _("Inward")));
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_healtharmor_iconalign", "3", _("Outward")));
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_healtharmor_flip", _("Flip health and armor positions")));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc b/qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc
new file mode 100644 (file)
index 0000000..976139c
--- /dev/null
@@ -0,0 +1,48 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDHealthArmorDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDHealthArmorDialog, fill, void(entity))
+       ATTRIB(XonoticHUDHealthArmorDialog, title, string, _("Health/Armor Panel"))
+       ATTRIB(XonoticHUDHealthArmorDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDHealthArmorDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDHealthArmorDialog, rows, float, 15)
+       ATTRIB(XonoticHUDHealthArmorDialog, columns, float, 4)
+       ATTRIB(XonoticHUDHealthArmorDialog, name, string, "HUDhealtharmor")
+       ATTRIB(XonoticHUDHealthArmorDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDHealthArmorDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDHealthArmorDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "healtharmor";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_healtharmor_progressbar", _("Enable status bar")));
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Status bar alignment:")));
+                       setDependent(e, "hud_panel_healtharmor_progressbar", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_healtharmor_baralign", "0", _("Left")));
+                       setDependent(e, "hud_panel_healtharmor_progressbar", 1, 1);
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_healtharmor_baralign", "1", _("Right")));
+                       setDependent(e, "hud_panel_healtharmor_progressbar", 1, 1);
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_healtharmor_baralign", "2", _("Inward")));
+                       setDependent(e, "hud_panel_healtharmor_progressbar", 1, 1);
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_healtharmor_baralign", "3", _("Outward")));
+                       setDependent(e, "hud_panel_healtharmor_progressbar", 1, 1);
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Icon alignment:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_healtharmor_iconalign", "0", _("Left")));
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_healtharmor_iconalign", "1", _("Right")));
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_healtharmor_iconalign", "2", _("Inward")));
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_healtharmor_iconalign", "3", _("Outward")));
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_healtharmor_flip", _("Flip health and armor positions")));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_infomessages.c b/qcsrc/menu/xonotic/dialog_hudpanel_infomessages.c
deleted file mode 100644 (file)
index 5bd8846..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDInfoMessagesDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDInfoMessagesDialog, fill, void(entity))
-       ATTRIB(XonoticHUDInfoMessagesDialog, title, string, _("Info Messages Panel"))
-       ATTRIB(XonoticHUDInfoMessagesDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDInfoMessagesDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDInfoMessagesDialog, rows, float, 15)
-       ATTRIB(XonoticHUDInfoMessagesDialog, columns, float, 4)
-       ATTRIB(XonoticHUDInfoMessagesDialog, name, string, "HUDinfomessages")
-       ATTRIB(XonoticHUDInfoMessagesDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDInfoMessagesDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDInfoMessagesDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "infomessages";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Info messages:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_infomessages_flip", _("Flip align")));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc b/qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc
new file mode 100644 (file)
index 0000000..5bd8846
--- /dev/null
@@ -0,0 +1,28 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDInfoMessagesDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDInfoMessagesDialog, fill, void(entity))
+       ATTRIB(XonoticHUDInfoMessagesDialog, title, string, _("Info Messages Panel"))
+       ATTRIB(XonoticHUDInfoMessagesDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDInfoMessagesDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDInfoMessagesDialog, rows, float, 15)
+       ATTRIB(XonoticHUDInfoMessagesDialog, columns, float, 4)
+       ATTRIB(XonoticHUDInfoMessagesDialog, name, string, "HUDinfomessages")
+       ATTRIB(XonoticHUDInfoMessagesDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDInfoMessagesDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDInfoMessagesDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "infomessages";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Info messages:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_infomessages_flip", _("Flip align")));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_modicons.c b/qcsrc/menu/xonotic/dialog_hudpanel_modicons.c
deleted file mode 100644 (file)
index 4c9e64c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDModIconsDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDModIconsDialog, fill, void(entity))
-       ATTRIB(XonoticHUDModIconsDialog, title, string, _("Mod Icons Panel"))
-       ATTRIB(XonoticHUDModIconsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDModIconsDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDModIconsDialog, rows, float, 15)
-       ATTRIB(XonoticHUDModIconsDialog, columns, float, 4)
-       ATTRIB(XonoticHUDModIconsDialog, name, string, "HUDmodicons")
-       ATTRIB(XonoticHUDModIconsDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDModIconsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDModIconsDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "modicons";
-
-       DIALOG_HUDPANEL_COMMON();
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_modicons.qc b/qcsrc/menu/xonotic/dialog_hudpanel_modicons.qc
new file mode 100644 (file)
index 0000000..4c9e64c
--- /dev/null
@@ -0,0 +1,22 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDModIconsDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDModIconsDialog, fill, void(entity))
+       ATTRIB(XonoticHUDModIconsDialog, title, string, _("Mod Icons Panel"))
+       ATTRIB(XonoticHUDModIconsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDModIconsDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDModIconsDialog, rows, float, 15)
+       ATTRIB(XonoticHUDModIconsDialog, columns, float, 4)
+       ATTRIB(XonoticHUDModIconsDialog, name, string, "HUDmodicons")
+       ATTRIB(XonoticHUDModIconsDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDModIconsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDModIconsDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "modicons";
+
+       DIALOG_HUDPANEL_COMMON();
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_notification.c b/qcsrc/menu/xonotic/dialog_hudpanel_notification.c
deleted file mode 100644 (file)
index 1239bd3..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDNotificationDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDNotificationDialog, fill, void(entity))
-       ATTRIB(XonoticHUDNotificationDialog, title, string, _("Notification Panel"))
-       ATTRIB(XonoticHUDNotificationDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDNotificationDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDNotificationDialog, rows, float, 15)
-       ATTRIB(XonoticHUDNotificationDialog, columns, float, 4)
-       ATTRIB(XonoticHUDNotificationDialog, name, string, "HUDnotify")
-       ATTRIB(XonoticHUDNotificationDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDNotificationDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDNotificationDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "notify";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Notifications:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_notify_print", _("Also print notifications to the console")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_notify_flip", _("Flip notify order")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Entry lifetime:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticSlider(3, 15, 1, "hud_panel_notify_time"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Entry fadetime:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticSlider(0.5, 5, 0.5, "hud_panel_notify_fadetime"));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_notification.qc b/qcsrc/menu/xonotic/dialog_hudpanel_notification.qc
new file mode 100644 (file)
index 0000000..1239bd3
--- /dev/null
@@ -0,0 +1,39 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDNotificationDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDNotificationDialog, fill, void(entity))
+       ATTRIB(XonoticHUDNotificationDialog, title, string, _("Notification Panel"))
+       ATTRIB(XonoticHUDNotificationDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDNotificationDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDNotificationDialog, rows, float, 15)
+       ATTRIB(XonoticHUDNotificationDialog, columns, float, 4)
+       ATTRIB(XonoticHUDNotificationDialog, name, string, "HUDnotify")
+       ATTRIB(XonoticHUDNotificationDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDNotificationDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDNotificationDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "notify";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Notifications:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_notify_print", _("Also print notifications to the console")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_notify_flip", _("Flip notify order")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Entry lifetime:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticSlider(3, 15, 1, "hud_panel_notify_time"));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Entry fadetime:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticSlider(0.5, 5, 0.5, "hud_panel_notify_fadetime"));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_physics.c b/qcsrc/menu/xonotic/dialog_hudpanel_physics.c
deleted file mode 100644 (file)
index 0144d66..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDPhysicsDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDPhysicsDialog, fill, void(entity))
-       ATTRIB(XonoticHUDPhysicsDialog, title, string, _("Physics Panel"))
-       ATTRIB(XonoticHUDPhysicsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDPhysicsDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDPhysicsDialog, rows, float, 15)
-       ATTRIB(XonoticHUDPhysicsDialog, columns, float, 4)
-       ATTRIB(XonoticHUDPhysicsDialog, name, string, "HUDphysics")
-       ATTRIB(XonoticHUDPhysicsDialog, sliderTopspeedTime, entity, NULL)
-       ATTRIB(XonoticHUDPhysicsDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDPhysicsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDPhysicsDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "physics";
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_physics"));
-                       e.addValue(e, _("Panel disabled"), "0");
-                       e.addValue(e, _("Panel enabled"), "1");
-                       e.addValue(e, _("Panel enabled even observing"), "2");
-                       e.addValue(e, _("Panel enabled only in Race/CTS"), "3");
-                       e.configureXonoticTextSliderValues(e);
-
-       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
-
-       me.TR(me);
-               me.TD(me, 1, 1.4, e = makeXonoticCheckBox(0, "hud_panel_physics_progressbar", _("Status bar")));
-               me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_physics_baralign"));
-                       e.addValue(e, _("Left align")   , "0");
-                       e.addValue(e, _("Right align")  , "1");
-                       e.addValue(e, _("Inward align") , "2");
-                       e.addValue(e, _("Outward align"), "3");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "hud_panel_physics_progressbar", 1, 3);
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_physics_flip", _("Flip speed/acceleration positions")));
-
-//speed
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Speed:")));
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_panel_physics_speed_vertical", _("Include vertical speed")));
-       // me.TR(me);
-               // me.TDempty(me, 0.2);
-               // me.TD(me, 1, 1.8, e = makeXonoticTextLabel(0, _("Full status bar at:")));
-                       // setDependent(e, "hud_panel_physics_progressbar", 1, 1);
-               // me.TD(me, 1, 1, e = makeXonoticInputBox(1, "hud_panel_physics_speed_max"));
-                       // setDependent(e, "hud_panel_physics_progressbar", 1, 1);
-               // me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("qu/s")));
-                       // setDependent(e, "hud_panel_physics_progressbar", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Speed unit:")));
-               me.TD(me, 1, 2.6/3*2, e = makeXonoticTextSlider("hud_panel_physics_speed_unit"));
-                       e.addValue(e, _("qu/s") , "1");
-                       e.addValue(e, _("m/s")  , "2");
-                       e.addValue(e, _("km/h") , "3");
-                       e.addValue(e, _("mph")  , "4");
-                       e.addValue(e, _("knots"), "5");
-                       e.configureXonoticTextSliderValues(e);
-               me.TD(me, 1, 2.6/3, e = makeXonoticCheckBox(0, "hud_panel_physics_speed_unit_show", _("Show")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8/2, e = makeXonoticCheckBox(0, "hud_panel_physics_topspeed", _("Top speed")));
-               me.TD(me, 1, 3.8/2, e = makeXonoticSlider(1, 10, 1, "hud_panel_physics_topspeed_time"));
-                       setDependent(e, "hud_panel_physics_topspeed", 1, 1);
-
-//acceleration
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Acceleration:")));
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_panel_physics_acceleration_vertical", _("Include vertical acceleration")));
-       // me.TR(me);
-               // me.TDempty(me, 0.2);
-               // me.TD(me, 1, 1.8, e = makeXonoticTextLabel(0, _("Full status bar at:")));
-                       // setDependent(e, "hud_panel_physics_progressbar", 1, 1);
-               // me.TD(me, 1, 0.6, e = makeXonoticInputBox(1, "hud_panel_physics_acceleration_max"));
-                       // setDependent(e, "hud_panel_physics_progressbar", 1, 1);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_physics.qc b/qcsrc/menu/xonotic/dialog_hudpanel_physics.qc
new file mode 100644 (file)
index 0000000..0144d66
--- /dev/null
@@ -0,0 +1,83 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDPhysicsDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDPhysicsDialog, fill, void(entity))
+       ATTRIB(XonoticHUDPhysicsDialog, title, string, _("Physics Panel"))
+       ATTRIB(XonoticHUDPhysicsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDPhysicsDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDPhysicsDialog, rows, float, 15)
+       ATTRIB(XonoticHUDPhysicsDialog, columns, float, 4)
+       ATTRIB(XonoticHUDPhysicsDialog, name, string, "HUDphysics")
+       ATTRIB(XonoticHUDPhysicsDialog, sliderTopspeedTime, entity, NULL)
+       ATTRIB(XonoticHUDPhysicsDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDPhysicsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDPhysicsDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "physics";
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_physics"));
+                       e.addValue(e, _("Panel disabled"), "0");
+                       e.addValue(e, _("Panel enabled"), "1");
+                       e.addValue(e, _("Panel enabled even observing"), "2");
+                       e.addValue(e, _("Panel enabled only in Race/CTS"), "3");
+                       e.configureXonoticTextSliderValues(e);
+
+       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
+
+       me.TR(me);
+               me.TD(me, 1, 1.4, e = makeXonoticCheckBox(0, "hud_panel_physics_progressbar", _("Status bar")));
+               me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_physics_baralign"));
+                       e.addValue(e, _("Left align")   , "0");
+                       e.addValue(e, _("Right align")  , "1");
+                       e.addValue(e, _("Inward align") , "2");
+                       e.addValue(e, _("Outward align"), "3");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "hud_panel_physics_progressbar", 1, 3);
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_physics_flip", _("Flip speed/acceleration positions")));
+
+//speed
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Speed:")));
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_panel_physics_speed_vertical", _("Include vertical speed")));
+       // me.TR(me);
+               // me.TDempty(me, 0.2);
+               // me.TD(me, 1, 1.8, e = makeXonoticTextLabel(0, _("Full status bar at:")));
+                       // setDependent(e, "hud_panel_physics_progressbar", 1, 1);
+               // me.TD(me, 1, 1, e = makeXonoticInputBox(1, "hud_panel_physics_speed_max"));
+                       // setDependent(e, "hud_panel_physics_progressbar", 1, 1);
+               // me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("qu/s")));
+                       // setDependent(e, "hud_panel_physics_progressbar", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Speed unit:")));
+               me.TD(me, 1, 2.6/3*2, e = makeXonoticTextSlider("hud_panel_physics_speed_unit"));
+                       e.addValue(e, _("qu/s") , "1");
+                       e.addValue(e, _("m/s")  , "2");
+                       e.addValue(e, _("km/h") , "3");
+                       e.addValue(e, _("mph")  , "4");
+                       e.addValue(e, _("knots"), "5");
+                       e.configureXonoticTextSliderValues(e);
+               me.TD(me, 1, 2.6/3, e = makeXonoticCheckBox(0, "hud_panel_physics_speed_unit_show", _("Show")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8/2, e = makeXonoticCheckBox(0, "hud_panel_physics_topspeed", _("Top speed")));
+               me.TD(me, 1, 3.8/2, e = makeXonoticSlider(1, 10, 1, "hud_panel_physics_topspeed_time"));
+                       setDependent(e, "hud_panel_physics_topspeed", 1, 1);
+
+//acceleration
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Acceleration:")));
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_panel_physics_acceleration_vertical", _("Include vertical acceleration")));
+       // me.TR(me);
+               // me.TDempty(me, 0.2);
+               // me.TD(me, 1, 1.8, e = makeXonoticTextLabel(0, _("Full status bar at:")));
+                       // setDependent(e, "hud_panel_physics_progressbar", 1, 1);
+               // me.TD(me, 1, 0.6, e = makeXonoticInputBox(1, "hud_panel_physics_acceleration_max"));
+                       // setDependent(e, "hud_panel_physics_progressbar", 1, 1);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_powerups.c b/qcsrc/menu/xonotic/dialog_hudpanel_powerups.c
deleted file mode 100644 (file)
index 17bfe04..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDPowerupsDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDPowerupsDialog, fill, void(entity))
-       ATTRIB(XonoticHUDPowerupsDialog, title, string, _("Powerups Panel"))
-       ATTRIB(XonoticHUDPowerupsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDPowerupsDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDPowerupsDialog, rows, float, 15)
-       ATTRIB(XonoticHUDPowerupsDialog, columns, float, 4)
-       ATTRIB(XonoticHUDPowerupsDialog, name, string, "HUDpowerups")
-       ATTRIB(XonoticHUDPowerupsDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDPowerupsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDPowerupsDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "powerups";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_powerups_progressbar", _("Enable status bar")));
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Status bar alignment:")));
-                       setDependent(e, "hud_panel_powerups_progressbar", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_powerups_baralign", "0", _("Left")));
-                       setDependent(e, "hud_panel_powerups_progressbar", 1, 1);
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_powerups_baralign", "1", _("Right")));
-                       setDependent(e, "hud_panel_powerups_progressbar", 1, 1);
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_powerups_baralign", "2", _("Inward")));
-                       setDependent(e, "hud_panel_powerups_progressbar", 1, 1);
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_powerups_baralign", "3", _("Outward")));
-                       setDependent(e, "hud_panel_powerups_progressbar", 1, 1);
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Icon alignment:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_powerups_iconalign", "0", _("Left")));
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_powerups_iconalign", "1", _("Right")));
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_powerups_iconalign", "2", _("Inward")));
-                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_powerups_iconalign", "3", _("Outward")));
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_powerups_flip", _("Flip strength and shield positions")));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc b/qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc
new file mode 100644 (file)
index 0000000..17bfe04
--- /dev/null
@@ -0,0 +1,48 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDPowerupsDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDPowerupsDialog, fill, void(entity))
+       ATTRIB(XonoticHUDPowerupsDialog, title, string, _("Powerups Panel"))
+       ATTRIB(XonoticHUDPowerupsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDPowerupsDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDPowerupsDialog, rows, float, 15)
+       ATTRIB(XonoticHUDPowerupsDialog, columns, float, 4)
+       ATTRIB(XonoticHUDPowerupsDialog, name, string, "HUDpowerups")
+       ATTRIB(XonoticHUDPowerupsDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDPowerupsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDPowerupsDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "powerups";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_powerups_progressbar", _("Enable status bar")));
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Status bar alignment:")));
+                       setDependent(e, "hud_panel_powerups_progressbar", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_powerups_baralign", "0", _("Left")));
+                       setDependent(e, "hud_panel_powerups_progressbar", 1, 1);
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_powerups_baralign", "1", _("Right")));
+                       setDependent(e, "hud_panel_powerups_progressbar", 1, 1);
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_powerups_baralign", "2", _("Inward")));
+                       setDependent(e, "hud_panel_powerups_progressbar", 1, 1);
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(2, "hud_panel_powerups_baralign", "3", _("Outward")));
+                       setDependent(e, "hud_panel_powerups_progressbar", 1, 1);
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Icon alignment:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_powerups_iconalign", "0", _("Left")));
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_powerups_iconalign", "1", _("Right")));
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_powerups_iconalign", "2", _("Inward")));
+                       me.TD(me, 1, 0.95, e = makeXonoticRadioButton(3, "hud_panel_powerups_iconalign", "3", _("Outward")));
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_powerups_flip", _("Flip strength and shield positions")));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.c b/qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.c
deleted file mode 100644 (file)
index 2e301cc..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDPressedKeysDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDPressedKeysDialog, fill, void(entity))
-       ATTRIB(XonoticHUDPressedKeysDialog, title, string, _("Pressed Keys Panel"))
-       ATTRIB(XonoticHUDPressedKeysDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDPressedKeysDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDPressedKeysDialog, rows, float, 15)
-       ATTRIB(XonoticHUDPressedKeysDialog, columns, float, 4)
-       ATTRIB(XonoticHUDPressedKeysDialog, name, string, "HUDpressedkeys")
-       ATTRIB(XonoticHUDPressedKeysDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDPressedKeysDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDPressedKeysDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "pressedkeys";
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_pressedkeys"));
-                       e.addValue(e, _("Panel disabled"), "0");
-                       e.addValue(e, _("Panel enabled when spectating"), "1");
-                       e.addValue(e, _("Panel always enabled"), "2");
-                       e.configureXonoticTextSliderValues(e);
-
-       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
-
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Forced aspect:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticSlider(0.2, 4, 0.1, "hud_panel_pressedkeys_aspect"));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc b/qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc
new file mode 100644 (file)
index 0000000..2e301cc
--- /dev/null
@@ -0,0 +1,34 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDPressedKeysDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDPressedKeysDialog, fill, void(entity))
+       ATTRIB(XonoticHUDPressedKeysDialog, title, string, _("Pressed Keys Panel"))
+       ATTRIB(XonoticHUDPressedKeysDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDPressedKeysDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDPressedKeysDialog, rows, float, 15)
+       ATTRIB(XonoticHUDPressedKeysDialog, columns, float, 4)
+       ATTRIB(XonoticHUDPressedKeysDialog, name, string, "HUDpressedkeys")
+       ATTRIB(XonoticHUDPressedKeysDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDPressedKeysDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDPressedKeysDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "pressedkeys";
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_pressedkeys"));
+                       e.addValue(e, _("Panel disabled"), "0");
+                       e.addValue(e, _("Panel enabled when spectating"), "1");
+                       e.addValue(e, _("Panel always enabled"), "2");
+                       e.configureXonoticTextSliderValues(e);
+
+       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
+
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Forced aspect:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticSlider(0.2, 4, 0.1, "hud_panel_pressedkeys_aspect"));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_racetimer.c b/qcsrc/menu/xonotic/dialog_hudpanel_racetimer.c
deleted file mode 100644 (file)
index 6b2badf..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDRaceTimerDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDRaceTimerDialog, fill, void(entity))
-       ATTRIB(XonoticHUDRaceTimerDialog, title, string, _("Race Timer Panel"))
-       ATTRIB(XonoticHUDRaceTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDRaceTimerDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDRaceTimerDialog, rows, float, 15)
-       ATTRIB(XonoticHUDRaceTimerDialog, columns, float, 4)
-       ATTRIB(XonoticHUDRaceTimerDialog, name, string, "HUDracetimer")
-       ATTRIB(XonoticHUDRaceTimerDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDRaceTimerDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDRaceTimerDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "racetimer";
-
-       DIALOG_HUDPANEL_COMMON();
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_racetimer.qc b/qcsrc/menu/xonotic/dialog_hudpanel_racetimer.qc
new file mode 100644 (file)
index 0000000..6b2badf
--- /dev/null
@@ -0,0 +1,22 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDRaceTimerDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDRaceTimerDialog, fill, void(entity))
+       ATTRIB(XonoticHUDRaceTimerDialog, title, string, _("Race Timer Panel"))
+       ATTRIB(XonoticHUDRaceTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDRaceTimerDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDRaceTimerDialog, rows, float, 15)
+       ATTRIB(XonoticHUDRaceTimerDialog, columns, float, 4)
+       ATTRIB(XonoticHUDRaceTimerDialog, name, string, "HUDracetimer")
+       ATTRIB(XonoticHUDRaceTimerDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDRaceTimerDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDRaceTimerDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "racetimer";
+
+       DIALOG_HUDPANEL_COMMON();
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_radar.c b/qcsrc/menu/xonotic/dialog_hudpanel_radar.c
deleted file mode 100644 (file)
index 6ad57fa..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDRadarDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDRadarDialog, fill, void(entity))
-       ATTRIB(XonoticHUDRadarDialog, title, string, _("Radar Panel"))
-       ATTRIB(XonoticHUDRadarDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDRadarDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDRadarDialog, rows, float, 15)
-       ATTRIB(XonoticHUDRadarDialog, columns, float, 4)
-       ATTRIB(XonoticHUDRadarDialog, name, string, "HUDradar")
-       ATTRIB(XonoticHUDRadarDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDRadarDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDRadarDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "radar";
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_radar"));
-                       e.addValue(e, _("Panel disabled"), "0");
-                       e.addValue(e, _("Panel enabled in teamgames"), "1");
-                       e.addValue(e, _("Panel always enabled"), "2");
-                       e.configureXonoticTextSliderValues(e);
-
-       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Radar:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Alpha:")));
-               me.TD(me, 1, 2.6, e = makeXonoticSlider(0.1, 1, 0.1, "hud_panel_radar_foreground_alpha"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Rotation:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_radar_rotation"));
-                               e.addValue(e, _("Forward"), "0");
-                               e.addValue(e, _("West"), "1");
-                               e.addValue(e, _("South"), "2");
-                               e.addValue(e, _("East"), "3");
-                               e.addValue(e, _("North"), "4");
-                               e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Scale:")));
-               me.TD(me, 1, 2.6, e = makeXonoticSlider(1024, 8192, 512, "hud_panel_radar_scale"));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Zoom mode:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_radar_zoommode"));
-                               e.addValue(e, _("Zoomed in"), "0");
-                               e.addValue(e, _("Zoomed out"), "1");
-                               e.addValue(e, _("Always zoomed"), "2");
-                               e.addValue(e, _("Never zoomed"), "3");
-                               e.configureXonoticTextSliderValues(e);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_radar.qc b/qcsrc/menu/xonotic/dialog_hudpanel_radar.qc
new file mode 100644 (file)
index 0000000..6ad57fa
--- /dev/null
@@ -0,0 +1,59 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDRadarDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDRadarDialog, fill, void(entity))
+       ATTRIB(XonoticHUDRadarDialog, title, string, _("Radar Panel"))
+       ATTRIB(XonoticHUDRadarDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDRadarDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDRadarDialog, rows, float, 15)
+       ATTRIB(XonoticHUDRadarDialog, columns, float, 4)
+       ATTRIB(XonoticHUDRadarDialog, name, string, "HUDradar")
+       ATTRIB(XonoticHUDRadarDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDRadarDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDRadarDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "radar";
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_radar"));
+                       e.addValue(e, _("Panel disabled"), "0");
+                       e.addValue(e, _("Panel enabled in teamgames"), "1");
+                       e.addValue(e, _("Panel always enabled"), "2");
+                       e.configureXonoticTextSliderValues(e);
+
+       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Radar:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Alpha:")));
+               me.TD(me, 1, 2.6, e = makeXonoticSlider(0.1, 1, 0.1, "hud_panel_radar_foreground_alpha"));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Rotation:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_radar_rotation"));
+                               e.addValue(e, _("Forward"), "0");
+                               e.addValue(e, _("West"), "1");
+                               e.addValue(e, _("South"), "2");
+                               e.addValue(e, _("East"), "3");
+                               e.addValue(e, _("North"), "4");
+                               e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Scale:")));
+               me.TD(me, 1, 2.6, e = makeXonoticSlider(1024, 8192, 512, "hud_panel_radar_scale"));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Zoom mode:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_radar_zoommode"));
+                               e.addValue(e, _("Zoomed in"), "0");
+                               e.addValue(e, _("Zoomed out"), "1");
+                               e.addValue(e, _("Always zoomed"), "2");
+                               e.addValue(e, _("Never zoomed"), "3");
+                               e.configureXonoticTextSliderValues(e);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_score.c b/qcsrc/menu/xonotic/dialog_hudpanel_score.c
deleted file mode 100644 (file)
index 676830f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDScoreDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDScoreDialog, fill, void(entity))
-       ATTRIB(XonoticHUDScoreDialog, title, string, _("Score Panel"))
-       ATTRIB(XonoticHUDScoreDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDScoreDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDScoreDialog, rows, float, 15)
-       ATTRIB(XonoticHUDScoreDialog, columns, float, 4)
-       ATTRIB(XonoticHUDScoreDialog, name, string, "HUDscore")
-       ATTRIB(XonoticHUDScoreDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDScoreDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDScoreDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "score";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Score:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Rankings:")));
-               me.TD(me, 1, 2.6/3, e = makeXonoticRadioButton(1, "hud_panel_score_rankings", "0", _("Off")));
-               me.TD(me, 1, 2.6/3, e = makeXonoticRadioButton(1, "hud_panel_score_rankings", "1", _("And me")));
-               me.TD(me, 1, 2.6/3, e = makeXonoticRadioButton(1, "hud_panel_score_rankings", "2", _("Pure")));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_score.qc b/qcsrc/menu/xonotic/dialog_hudpanel_score.qc
new file mode 100644 (file)
index 0000000..676830f
--- /dev/null
@@ -0,0 +1,31 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDScoreDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDScoreDialog, fill, void(entity))
+       ATTRIB(XonoticHUDScoreDialog, title, string, _("Score Panel"))
+       ATTRIB(XonoticHUDScoreDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDScoreDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDScoreDialog, rows, float, 15)
+       ATTRIB(XonoticHUDScoreDialog, columns, float, 4)
+       ATTRIB(XonoticHUDScoreDialog, name, string, "HUDscore")
+       ATTRIB(XonoticHUDScoreDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDScoreDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDScoreDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "score";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Score:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Rankings:")));
+               me.TD(me, 1, 2.6/3, e = makeXonoticRadioButton(1, "hud_panel_score_rankings", "0", _("Off")));
+               me.TD(me, 1, 2.6/3, e = makeXonoticRadioButton(1, "hud_panel_score_rankings", "1", _("And me")));
+               me.TD(me, 1, 2.6/3, e = makeXonoticRadioButton(1, "hud_panel_score_rankings", "2", _("Pure")));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_timer.c b/qcsrc/menu/xonotic/dialog_hudpanel_timer.c
deleted file mode 100644 (file)
index 2624a7e..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDTimerDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDTimerDialog, fill, void(entity))
-       ATTRIB(XonoticHUDTimerDialog, title, string, _("Timer Panel"))
-       ATTRIB(XonoticHUDTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDTimerDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDTimerDialog, rows, float, 15)
-       ATTRIB(XonoticHUDTimerDialog, columns, float, 4)
-       ATTRIB(XonoticHUDTimerDialog, name, string, "HUDtimer")
-       ATTRIB(XonoticHUDTimerDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDTimerDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDTimerDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "timer";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Timer:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_timer_increment", _("Show elapsed time")));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_timer.qc b/qcsrc/menu/xonotic/dialog_hudpanel_timer.qc
new file mode 100644 (file)
index 0000000..2624a7e
--- /dev/null
@@ -0,0 +1,28 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDTimerDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDTimerDialog, fill, void(entity))
+       ATTRIB(XonoticHUDTimerDialog, title, string, _("Timer Panel"))
+       ATTRIB(XonoticHUDTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDTimerDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDTimerDialog, rows, float, 15)
+       ATTRIB(XonoticHUDTimerDialog, columns, float, 4)
+       ATTRIB(XonoticHUDTimerDialog, name, string, "HUDtimer")
+       ATTRIB(XonoticHUDTimerDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDTimerDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDTimerDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "timer";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Timer:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_timer_increment", _("Show elapsed time")));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_vote.c b/qcsrc/menu/xonotic/dialog_hudpanel_vote.c
deleted file mode 100644 (file)
index 4e4931e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDVoteDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDVoteDialog, fill, void(entity))
-       ATTRIB(XonoticHUDVoteDialog, title, string, _("Vote Panel"))
-       ATTRIB(XonoticHUDVoteDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDVoteDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDVoteDialog, rows, float, 15)
-       ATTRIB(XonoticHUDVoteDialog, columns, float, 4)
-       ATTRIB(XonoticHUDVoteDialog, name, string, "HUDvote")
-       ATTRIB(XonoticHUDVoteDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDVoteDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDVoteDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "vote";
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Alpha after voting:")));
-               me.TD(me, 1, 2.6, e = makeXonoticSlider(0.1, 1, 0.1, "hud_panel_vote_alreadyvoted_alpha"));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_vote.qc b/qcsrc/menu/xonotic/dialog_hudpanel_vote.qc
new file mode 100644 (file)
index 0000000..4e4931e
--- /dev/null
@@ -0,0 +1,26 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDVoteDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDVoteDialog, fill, void(entity))
+       ATTRIB(XonoticHUDVoteDialog, title, string, _("Vote Panel"))
+       ATTRIB(XonoticHUDVoteDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDVoteDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDVoteDialog, rows, float, 15)
+       ATTRIB(XonoticHUDVoteDialog, columns, float, 4)
+       ATTRIB(XonoticHUDVoteDialog, name, string, "HUDvote")
+       ATTRIB(XonoticHUDVoteDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDVoteDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDVoteDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "vote";
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Alpha after voting:")));
+               me.TD(me, 1, 2.6, e = makeXonoticSlider(0.1, 1, 0.1, "hud_panel_vote_alreadyvoted_alpha"));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_weapons.c b/qcsrc/menu/xonotic/dialog_hudpanel_weapons.c
deleted file mode 100644 (file)
index 64c9cf4..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDWeaponsDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDWeaponsDialog, fill, void(entity))
-       ATTRIB(XonoticHUDWeaponsDialog, title, string, _("Weapons Panel"))
-       ATTRIB(XonoticHUDWeaponsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDWeaponsDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDWeaponsDialog, rows, float, 19)
-       ATTRIB(XonoticHUDWeaponsDialog, columns, float, 4)
-       ATTRIB(XonoticHUDWeaponsDialog, name, string, "HUDweapons")
-       ATTRIB(XonoticHUDWeaponsDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDWeaponsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDWeaponsDialog_fill(entity me)
-{
-       entity e;
-       string panelname = "weapons";
-       float i;
-
-       DIALOG_HUDPANEL_COMMON();
-
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Fade out after:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider(strzone(strcat("hud_panel_", panelname, "_timeout"))));
-                               e.addValue(e, _("Never"), "0");
-                               for(i = 1; i <= 10; ++i)
-                                       e.addValue(e, strzone(sprintf(_("%ds"), i)), strzone(ftos(i)));
-                               e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Fade effect:")));
-               setDependentStringNotEqual(e, strzone(strcat("hud_panel_", panelname, "_timeout")), "0");
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider(strzone(strcat("hud_panel_", panelname, "_timeout_effect"))));
-                               e.addValue(e, ZCTX(_("EF^None")),  "0");
-                               e.addValue(e, _("Alpha"), "1");
-                               e.addValue(e, _("Slide"), "2");
-                               e.addValue(e, ZCTX(_("EF^Both")),  "3");
-                               e.configureXonoticTextSliderValues(e);
-                       setDependentStringNotEqual(e, strzone(strcat("hud_panel_", panelname, "_timeout")), "0");
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Weapon icons:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_weapons_onlyowned", _("Show only owned weapons")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Show weapon ID as:")));
-                       me.TD(me, 1, 0.8, e = makeXonoticRadioButton(2, "hud_panel_weapons_label", "0", ZCTX(_("SHOWAS^None"))));
-                       me.TD(me, 1, 0.8, e = makeXonoticRadioButton(2, "hud_panel_weapons_label", "1", _("Number")));
-                       me.TD(me, 1, 0.8, e = makeXonoticRadioButton(2, "hud_panel_weapons_label", "2", _("Bind")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Weapon ID scale:")));
-                       me.TD(me, 1, 2.4, e = makeXonoticSlider(0.1, 1, 0.05, "hud_panel_weapons_label_scale"));
-                       setDependent(e, "hud_panel_weapons_label", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8/2, e = makeXonoticCheckBox(0, "hud_panel_weapons_accuracy", _("Show Accuracy")));
-               me.TD(me, 1, 3.8/2, e = makeXonoticCheckBox(0, "hud_panel_weapons_ammo", _("Show Ammo")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Ammo bar alpha:")));
-                       me.TD(me, 1, 2.4, e = makeXonoticSlider(0.1, 1, 0.1, "hud_panel_weapons_ammo_alpha"));
-                       setDependent(e, "hud_panel_weapons_ammo", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Ammo bar color:")));
-               me.TD(me, 2, 2.4, e = makeXonoticColorpickerString("hud_panel_weapons_ammo_color", "hud_panel_weapons_ammo_color"));
-                       setDependent(e, "hud_panel_weapons_ammo", 1, 1);
-               me.TR(me);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc b/qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc
new file mode 100644 (file)
index 0000000..64c9cf4
--- /dev/null
@@ -0,0 +1,74 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDWeaponsDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDWeaponsDialog, fill, void(entity))
+       ATTRIB(XonoticHUDWeaponsDialog, title, string, _("Weapons Panel"))
+       ATTRIB(XonoticHUDWeaponsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDWeaponsDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDWeaponsDialog, rows, float, 19)
+       ATTRIB(XonoticHUDWeaponsDialog, columns, float, 4)
+       ATTRIB(XonoticHUDWeaponsDialog, name, string, "HUDweapons")
+       ATTRIB(XonoticHUDWeaponsDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDWeaponsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDWeaponsDialog_fill(entity me)
+{
+       entity e;
+       string panelname = "weapons";
+       float i;
+
+       DIALOG_HUDPANEL_COMMON();
+
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Fade out after:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider(strzone(strcat("hud_panel_", panelname, "_timeout"))));
+                               e.addValue(e, _("Never"), "0");
+                               for(i = 1; i <= 10; ++i)
+                                       e.addValue(e, strzone(sprintf(_("%ds"), i)), strzone(ftos(i)));
+                               e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Fade effect:")));
+               setDependentStringNotEqual(e, strzone(strcat("hud_panel_", panelname, "_timeout")), "0");
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider(strzone(strcat("hud_panel_", panelname, "_timeout_effect"))));
+                               e.addValue(e, ZCTX(_("EF^None")),  "0");
+                               e.addValue(e, _("Alpha"), "1");
+                               e.addValue(e, _("Slide"), "2");
+                               e.addValue(e, ZCTX(_("EF^Both")),  "3");
+                               e.configureXonoticTextSliderValues(e);
+                       setDependentStringNotEqual(e, strzone(strcat("hud_panel_", panelname, "_timeout")), "0");
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Weapon icons:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_weapons_onlyowned", _("Show only owned weapons")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Show weapon ID as:")));
+                       me.TD(me, 1, 0.8, e = makeXonoticRadioButton(2, "hud_panel_weapons_label", "0", ZCTX(_("SHOWAS^None"))));
+                       me.TD(me, 1, 0.8, e = makeXonoticRadioButton(2, "hud_panel_weapons_label", "1", _("Number")));
+                       me.TD(me, 1, 0.8, e = makeXonoticRadioButton(2, "hud_panel_weapons_label", "2", _("Bind")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Weapon ID scale:")));
+                       me.TD(me, 1, 2.4, e = makeXonoticSlider(0.1, 1, 0.05, "hud_panel_weapons_label_scale"));
+                       setDependent(e, "hud_panel_weapons_label", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8/2, e = makeXonoticCheckBox(0, "hud_panel_weapons_accuracy", _("Show Accuracy")));
+               me.TD(me, 1, 3.8/2, e = makeXonoticCheckBox(0, "hud_panel_weapons_ammo", _("Show Ammo")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Ammo bar alpha:")));
+                       me.TD(me, 1, 2.4, e = makeXonoticSlider(0.1, 1, 0.1, "hud_panel_weapons_ammo_alpha"));
+                       setDependent(e, "hud_panel_weapons_ammo", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Ammo bar color:")));
+               me.TD(me, 2, 2.4, e = makeXonoticColorpickerString("hud_panel_weapons_ammo_color", "hud_panel_weapons_ammo_color"));
+                       setDependent(e, "hud_panel_weapons_ammo", 1, 1);
+               me.TR(me);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudsetup_exit.c b/qcsrc/menu/xonotic/dialog_hudsetup_exit.c
deleted file mode 100644 (file)
index 09e6c53..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDExitDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticHUDExitDialog, fill, void(entity))
-       ATTRIB(XonoticHUDExitDialog, title, string, _("Panel HUD Setup"))
-       ATTRIB(XonoticHUDExitDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticHUDExitDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticHUDExitDialog, rows, float, 18)
-       ATTRIB(XonoticHUDExitDialog, columns, float, 4)
-       ATTRIB(XonoticHUDExitDialog, name, string, "HUDExit")
-       ATTRIB(XonoticHUDExitDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticHUDExitDialog)
-
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticHUDExitDialog_fill(entity me)
-{
-       entity e;
-       float i;
-
-       me.TR(me);
-               me.TD(me, 1, 4, makeXonoticTextLabel(0, _("Panel background defaults:")));
-       me.TR(me);
-               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Background:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_bg"));
-                               e.addValue(e, _("Disable"), "0");
-                               e.addValue(e, "border_default", "border_default"); // this is a file name!
-                               e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Color:")));
-               me.TD(me, 2, 2.6, e = makeXonoticColorpickerString("hud_panel_bg_color", "hud_panel_bg_color"));
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Border size:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_bg_border"));
-                               e.addValue(e, _("Disable"), "0");
-                               for(i = 1; i <= 10; ++i)
-                                       e.addValue(e, strzone(ftos_decimals(i * 2, 0)), strzone(ftos(i * 2)));
-                               e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Alpha:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_bg_alpha"));
-                               for(i = 1; i <= 10; ++i)
-                                       e.addValue(e, strzone(ftos_decimals(i/10, 1)), strzone(ftos(i/10)));
-                               e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Team color:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_bg_color_team"));
-                               e.addValue(e, _("Disable"), "0");
-                               for(i = 1; i <= 10; ++i)
-                                       e.addValue(e, strzone(ftos_decimals(i/10, 1)), strzone(ftos(i/10)));
-                               e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.4);
-               me.TD(me, 1, 3.6, e = makeXonoticCheckBox(0, "hud_configure_teamcolorforced", _("Test team color in configure mode")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Padding:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_bg_padding"));
-                               for(i = 0; i <= 10; ++i)
-                                       e.addValue(e, strzone(ftos_decimals(i - 5, 0)), strzone(ftos(i - 5)));
-                               e.configureXonoticTextSliderValues(e);
-
-       me.TR(me);
-               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("HUD Dock:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_dock"));
-                               e.addValue(e, ZCTX(_("DOCK^Disabled")), "0");
-                               e.addValue(e, ZCTX(_("DOCK^Small")), "dock_small");
-                               e.addValue(e, ZCTX(_("DOCK^Medium")), "dock_medium");
-                               e.addValue(e, ZCTX(_("DOCK^Large")), "dock_large");
-                               e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Color:")));
-               me.TD(me, 2, 2.6, e = makeXonoticColorpickerString("hud_dock_color", "hud_dock_color"));
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Alpha:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_dock_alpha"));
-                               for(i = 1; i <= 10; ++i)
-                                       e.addValue(e, strzone(ftos_decimals(i/10, 1)), strzone(ftos(i/10)));
-                               e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Team color:")));
-                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_dock_color_team"));
-                               e.addValue(e, _("Disable"), "0");
-                               for(i = 1; i <= 10; ++i)
-                                       e.addValue(e, strzone(ftos_decimals(i/10, 1)), strzone(ftos(i/10)));
-                               e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 4, makeXonoticTextLabel(0, _("Grid settings:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_configure_grid", _("Snap panels to grid")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Grid size:")));
-               me.TD(me, 1, 0.2, e = makeXonoticTextLabel(0, _("X:")));
-                       me.TD(me, 1, 1.1, e = makeXonoticTextSlider("hud_configure_grid_xsize"));
-                               for(i = 1; i <= 14; ++i)
-                                       e.addValue(e, strzone(ftos_decimals(i/200, 3)), strzone(ftos(i/200)));
-                               e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "hud_configure_grid", 1, 1);
-               me.TD(me, 1, 0.2, e = makeXonoticTextLabel(0, _("Y:")));
-                       me.TD(me, 1, 1.1, e = makeXonoticTextSlider("hud_configure_grid_ysize"));
-                               for(i = 1; i <= 14; ++i)
-                                       e.addValue(e, strzone(ftos_decimals(i/200, 3)), strzone(ftos(i/200)));
-                               e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "hud_configure_grid", 1, 1);
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticCommandButton(_("Exit setup"), '0 0 0', "_hud_configure 0", 1));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_hudsetup_exit.qc b/qcsrc/menu/xonotic/dialog_hudsetup_exit.qc
new file mode 100644 (file)
index 0000000..09e6c53
--- /dev/null
@@ -0,0 +1,120 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDExitDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticHUDExitDialog, fill, void(entity))
+       ATTRIB(XonoticHUDExitDialog, title, string, _("Panel HUD Setup"))
+       ATTRIB(XonoticHUDExitDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticHUDExitDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticHUDExitDialog, rows, float, 18)
+       ATTRIB(XonoticHUDExitDialog, columns, float, 4)
+       ATTRIB(XonoticHUDExitDialog, name, string, "HUDExit")
+       ATTRIB(XonoticHUDExitDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticHUDExitDialog)
+
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticHUDExitDialog_fill(entity me)
+{
+       entity e;
+       float i;
+
+       me.TR(me);
+               me.TD(me, 1, 4, makeXonoticTextLabel(0, _("Panel background defaults:")));
+       me.TR(me);
+               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Background:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_bg"));
+                               e.addValue(e, _("Disable"), "0");
+                               e.addValue(e, "border_default", "border_default"); // this is a file name!
+                               e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Color:")));
+               me.TD(me, 2, 2.6, e = makeXonoticColorpickerString("hud_panel_bg_color", "hud_panel_bg_color"));
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Border size:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_bg_border"));
+                               e.addValue(e, _("Disable"), "0");
+                               for(i = 1; i <= 10; ++i)
+                                       e.addValue(e, strzone(ftos_decimals(i * 2, 0)), strzone(ftos(i * 2)));
+                               e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Alpha:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_bg_alpha"));
+                               for(i = 1; i <= 10; ++i)
+                                       e.addValue(e, strzone(ftos_decimals(i/10, 1)), strzone(ftos(i/10)));
+                               e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Team color:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_bg_color_team"));
+                               e.addValue(e, _("Disable"), "0");
+                               for(i = 1; i <= 10; ++i)
+                                       e.addValue(e, strzone(ftos_decimals(i/10, 1)), strzone(ftos(i/10)));
+                               e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TDempty(me, 0.4);
+               me.TD(me, 1, 3.6, e = makeXonoticCheckBox(0, "hud_configure_teamcolorforced", _("Test team color in configure mode")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Padding:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_bg_padding"));
+                               for(i = 0; i <= 10; ++i)
+                                       e.addValue(e, strzone(ftos_decimals(i - 5, 0)), strzone(ftos(i - 5)));
+                               e.configureXonoticTextSliderValues(e);
+
+       me.TR(me);
+               me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("HUD Dock:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_dock"));
+                               e.addValue(e, ZCTX(_("DOCK^Disabled")), "0");
+                               e.addValue(e, ZCTX(_("DOCK^Small")), "dock_small");
+                               e.addValue(e, ZCTX(_("DOCK^Medium")), "dock_medium");
+                               e.addValue(e, ZCTX(_("DOCK^Large")), "dock_large");
+                               e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Color:")));
+               me.TD(me, 2, 2.6, e = makeXonoticColorpickerString("hud_dock_color", "hud_dock_color"));
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Alpha:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_dock_alpha"));
+                               for(i = 1; i <= 10; ++i)
+                                       e.addValue(e, strzone(ftos_decimals(i/10, 1)), strzone(ftos(i/10)));
+                               e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Team color:")));
+                       me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_dock_color_team"));
+                               e.addValue(e, _("Disable"), "0");
+                               for(i = 1; i <= 10; ++i)
+                                       e.addValue(e, strzone(ftos_decimals(i/10, 1)), strzone(ftos(i/10)));
+                               e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 4, makeXonoticTextLabel(0, _("Grid settings:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_configure_grid", _("Snap panels to grid")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Grid size:")));
+               me.TD(me, 1, 0.2, e = makeXonoticTextLabel(0, _("X:")));
+                       me.TD(me, 1, 1.1, e = makeXonoticTextSlider("hud_configure_grid_xsize"));
+                               for(i = 1; i <= 14; ++i)
+                                       e.addValue(e, strzone(ftos_decimals(i/200, 3)), strzone(ftos(i/200)));
+                               e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "hud_configure_grid", 1, 1);
+               me.TD(me, 1, 0.2, e = makeXonoticTextLabel(0, _("Y:")));
+                       me.TD(me, 1, 1.1, e = makeXonoticTextSlider("hud_configure_grid_ysize"));
+                               for(i = 1; i <= 14; ++i)
+                                       e.addValue(e, strzone(ftos_decimals(i/200, 3)), strzone(ftos(i/200)));
+                               e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "hud_configure_grid", 1, 1);
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticCommandButton(_("Exit setup"), '0 0 0', "_hud_configure 0", 1));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_monstertools.c b/qcsrc/menu/xonotic/dialog_monstertools.c
deleted file mode 100644 (file)
index 8b67094..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticMonsterToolsDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticMonsterToolsDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
-       ATTRIB(XonoticMonsterToolsDialog, title, string, _("Monster Tools"))
-       ATTRIB(XonoticMonsterToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS)
-       ATTRIB(XonoticMonsterToolsDialog, intendedWidth, float, 0.8)
-       ATTRIB(XonoticMonsterToolsDialog, rows, float, 16)
-       ATTRIB(XonoticMonsterToolsDialog, columns, float, 4)
-       ATTRIB(XonoticMonsterToolsDialog, name, string, "MonsterTools")
-ENDCLASS(XonoticMonsterToolsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticMonsterToolsDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 0.25, e = makeXonoticTextLabel(0, _("Monster:")));
-       me.TR(me);
-               me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "zombie", _("Zombie")));
-               me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "spider", _("Spider")));
-               me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "shambler", _("Shambler")));
-               me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "mage", _("Mage")));
-               me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "wyvern", _("Wyvern")));
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Spawn"), '0 0 0', "cmd mobspawn $menu_monsters_edit_spawn $menu_monsters_edit_movetarget", 0));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Remove"), '0 0 0', "cmd mobkill", 0));
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Move target:"), '0 0 0', "editmob movetarget $menu_monsters_edit_movetarget", 0));
-               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_monsters_edit_movetarget", "1", _("Follow")));
-               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_monsters_edit_movetarget", "2", _("Wander")));
-               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_monsters_edit_movetarget", "3", _("Spawnpoint")));
-               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_monsters_edit_movetarget", "4", _("No moving")));
-       me.TR(me);
-       me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("Colors:")));
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set skin:"), '0 0 0', "editmob skin $menu_monsters_edit_skin", 0));
-               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 99, 1, "menu_monsters_edit_skin"));
-       me.TR(me);
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
-
-/* Click. The c-word is here so you can grep for it :-) */
diff --git a/qcsrc/menu/xonotic/dialog_monstertools.qc b/qcsrc/menu/xonotic/dialog_monstertools.qc
new file mode 100644 (file)
index 0000000..8b67094
--- /dev/null
@@ -0,0 +1,50 @@
+#ifdef INTERFACE
+CLASS(XonoticMonsterToolsDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticMonsterToolsDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
+       ATTRIB(XonoticMonsterToolsDialog, title, string, _("Monster Tools"))
+       ATTRIB(XonoticMonsterToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS)
+       ATTRIB(XonoticMonsterToolsDialog, intendedWidth, float, 0.8)
+       ATTRIB(XonoticMonsterToolsDialog, rows, float, 16)
+       ATTRIB(XonoticMonsterToolsDialog, columns, float, 4)
+       ATTRIB(XonoticMonsterToolsDialog, name, string, "MonsterTools")
+ENDCLASS(XonoticMonsterToolsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticMonsterToolsDialog_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 0.25, e = makeXonoticTextLabel(0, _("Monster:")));
+       me.TR(me);
+               me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "zombie", _("Zombie")));
+               me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "spider", _("Spider")));
+               me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "shambler", _("Shambler")));
+               me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "mage", _("Mage")));
+               me.TD(me, 1, 0.4, e = makeXonoticRadioButton(2, "menu_monsters_edit_spawn", "wyvern", _("Wyvern")));
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Spawn"), '0 0 0', "cmd mobspawn $menu_monsters_edit_spawn $menu_monsters_edit_movetarget", 0));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Remove"), '0 0 0', "cmd mobkill", 0));
+       me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Move target:"), '0 0 0', "editmob movetarget $menu_monsters_edit_movetarget", 0));
+               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_monsters_edit_movetarget", "1", _("Follow")));
+               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_monsters_edit_movetarget", "2", _("Wander")));
+               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_monsters_edit_movetarget", "3", _("Spawnpoint")));
+               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_monsters_edit_movetarget", "4", _("No moving")));
+       me.TR(me);
+       me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("Colors:")));
+       me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set skin:"), '0 0 0', "editmob skin $menu_monsters_edit_skin", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 99, 1, "menu_monsters_edit_skin"));
+       me.TR(me);
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
+
+/* Click. The c-word is here so you can grep for it :-) */
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer.c b/qcsrc/menu/xonotic/dialog_multiplayer.c
deleted file mode 100644 (file)
index 7d234c7..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticMultiplayerDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticMultiplayerDialog, fill, void(entity))
-       ATTRIB(XonoticMultiplayerDialog, title, string, _("Multiplayer"))
-       ATTRIB(XonoticMultiplayerDialog, color, vector, SKINCOLOR_DIALOG_MULTIPLAYER)
-       ATTRIB(XonoticMultiplayerDialog, intendedWidth, float, 0.96)
-       ATTRIB(XonoticMultiplayerDialog, rows, float, 24)
-       ATTRIB(XonoticMultiplayerDialog, columns, float, 4)
-ENDCLASS(XonoticMultiplayerDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticMultiplayerDialog_fill(entity me)
-{
-       entity mc, e;
-       mc = makeXonoticTabController(me.rows - 1);
-       me.TR(me);
-               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Servers"), makeXonoticServerListTab()));
-               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Create"), makeXonoticServerCreateTab()));
-               //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Demos"), makeXonoticDemoBrowserTab()));
-               //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Screenshots"), makeXonoticScreenshotBrowserTab()));
-               //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Players"), makeXonoticDemoBrowserTab()));
-               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Media"), makeXonoticMediaTab()));
-               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Profile"), makeXonoticProfileTab()));
-
-       me.TR(me);
-               me.TD(me, me.rows - 1, me.columns, mc);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer.qc b/qcsrc/menu/xonotic/dialog_multiplayer.qc
new file mode 100644 (file)
index 0000000..7d234c7
--- /dev/null
@@ -0,0 +1,29 @@
+#ifdef INTERFACE
+CLASS(XonoticMultiplayerDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticMultiplayerDialog, fill, void(entity))
+       ATTRIB(XonoticMultiplayerDialog, title, string, _("Multiplayer"))
+       ATTRIB(XonoticMultiplayerDialog, color, vector, SKINCOLOR_DIALOG_MULTIPLAYER)
+       ATTRIB(XonoticMultiplayerDialog, intendedWidth, float, 0.96)
+       ATTRIB(XonoticMultiplayerDialog, rows, float, 24)
+       ATTRIB(XonoticMultiplayerDialog, columns, float, 4)
+ENDCLASS(XonoticMultiplayerDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticMultiplayerDialog_fill(entity me)
+{
+       entity mc, e;
+       mc = makeXonoticTabController(me.rows - 1);
+       me.TR(me);
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Servers"), makeXonoticServerListTab()));
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Create"), makeXonoticServerCreateTab()));
+               //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Demos"), makeXonoticDemoBrowserTab()));
+               //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Screenshots"), makeXonoticScreenshotBrowserTab()));
+               //me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Players"), makeXonoticDemoBrowserTab()));
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Media"), makeXonoticMediaTab()));
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Profile"), makeXonoticProfileTab()));
+
+       me.TR(me);
+               me.TD(me, me.rows - 1, me.columns, mc);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create.c b/qcsrc/menu/xonotic/dialog_multiplayer_create.c
deleted file mode 100644 (file)
index bbffb52..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticServerCreateTab) EXTENDS(XonoticTab)
-       METHOD(XonoticServerCreateTab, fill, void(entity))
-       METHOD(XonoticServerCreateTab, gameTypeChangeNotify, void(entity))
-       METHOD(XonoticServerCreateTab, gameTypeSelectNotify, void(entity))
-       ATTRIB(XonoticServerCreateTab, title, string, _("Create"))
-       ATTRIB(XonoticServerCreateTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticServerCreateTab, rows, float, 23)
-       ATTRIB(XonoticServerCreateTab, columns, float, 6.2) // added extra .2 for center space
-
-       ATTRIB(XonoticServerCreateTab, mapListBox, entity, NULL)
-       ATTRIB(XonoticServerCreateTab, sliderFraglimit, entity, NULL)
-       ATTRIB(XonoticServerCreateTab, sliderTeams, entity, NULL)
-       ATTRIB(XonoticServerCreateTab, sliderTimelimit, entity, NULL)
-       ATTRIB(XonoticServerCreateTab, labelFraglimit, entity, NULL)
-       ATTRIB(XonoticServerCreateTab, labelTeams, entity, NULL)
-ENDCLASS(XonoticServerCreateTab)
-entity makeXonoticServerCreateTab();
-#endif
-
-#ifdef IMPLEMENTATION
-
-void GameType_ConfigureSliders(entity e, entity l, string pLabel, float pMin, float pMax, float pStep, string pCvar)
-{
-       if(pCvar == "")
-       {
-               e.configureXonoticTextSlider(e, string_null);
-               l.setText(l, pLabel);
-               e.disabled = l.disabled = TRUE;
-       }
-       else
-       {
-               e.configureXonoticTextSlider(e, pCvar);
-               
-               // clear old values
-               float i;
-               for(i = 0; i <= e.nValues; ++i);
-               {
-                       if(e.(valueStrings[i])) { strunzone(e.(valueStrings[i])); }
-                       if(e.(valueIdentifiers[i])) { strunzone(e.(valueIdentifiers[i])); }
-               }
-               e.clearValues(e);
-
-               // set new values
-               e.addValue(e, strzone(_("Default")), strzone("-1"));
-               for(i = pMin; i <= pMax; i += pStep) { e.addValue(e, strzone(ftos(i)), strzone(ftos(i))); }
-               e.addValue(e, strzone(_("Unlimited")), strzone("0"));
-               e.configureXonoticTextSliderValues(e);
-
-               // set text field
-               l.setText(l, pLabel);
-               e.disabled = l.disabled = FALSE;
-       }
-}
-
-entity makeXonoticServerCreateTab()
-{
-       entity me;
-       me = spawnXonoticServerCreateTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void XonoticServerCreateTab_fill(entity me)
-{
-       entity e, e0;
-
-       me.gotoRC(me, 0.5, 0);
-               me.TD(me, 1, 3, makeXonoticHeaderLabel(_("Gametype")));
-       me.TR(me);
-               me.TD(me, 10.5, 3, e = makeXonoticGametypeList());
-
-       me.gotoRC(me, 12.5, 0);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Time limit:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("timelimit_override"));
-                       e.addValue(e, ZCTX(_("TIMLIM^Default")), "-1");
-                       e.addValue(e, ZCTX(_("TIMLIM^1 minute")), "1");
-                       e.addValue(e, ZCTX(_("TIMLIM^2 minutes")), "2");
-                       e.addValue(e, ZCTX(_("TIMLIM^3 minutes")), "3");
-                       e.addValue(e, ZCTX(_("TIMLIM^4 minutes")), "4");
-                       e.addValue(e, ZCTX(_("TIMLIM^5 minutes")), "5");
-                       e.addValue(e, ZCTX(_("TIMLIM^6 minutes")), "6");
-                       e.addValue(e, ZCTX(_("TIMLIM^7 minutes")), "7");
-                       e.addValue(e, ZCTX(_("TIMLIM^8 minutes")), "8");
-                       e.addValue(e, ZCTX(_("TIMLIM^9 minutes")), "9");
-                       e.addValue(e, ZCTX(_("TIMLIM^10 minutes")), "10");
-                       e.addValue(e, ZCTX(_("TIMLIM^15 minutes")), "15");
-                       e.addValue(e, ZCTX(_("TIMLIM^20 minutes")), "20");
-                       e.addValue(e, ZCTX(_("TIMLIM^25 minutes")), "25");
-                       e.addValue(e, ZCTX(_("TIMLIM^30 minutes")), "30");
-                       e.addValue(e, ZCTX(_("TIMLIM^40 minutes")), "40");
-                       e.addValue(e, ZCTX(_("TIMLIM^50 minutes")), "50");
-                       e.addValue(e, ZCTX(_("TIMLIM^60 minutes")), "60");
-                       e.addValue(e, ZCTX(_("TIMLIM^Infinite")), "0");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, me.labelFraglimit = makeXonoticTextLabel(0, _("Frag limit:")));
-               me.TD(me, 1, 2, me.sliderFraglimit = makeXonoticTextSlider("fraglimit_override"));
-                       GameType_ConfigureSliders(me.sliderFraglimit, me.labelFraglimit, _("Frag limit:"), 5, 100, 5, "fraglimit_override");
-
-       me.gotoRC(me, 15, 0);
-               me.TD(me, 1, 1, me.labelTeams = makeXonoticTextLabel(0, _("Teams:")));
-               me.TD(me, 1, 2, e = me.sliderTeams = makeXonoticTextSlider(string_null));
-                       e.addValue(e, _("Default"), "0");
-                       e.addValue(e, _("2 teams"), "2");
-                       e.addValue(e, _("3 teams"), "3");
-                       e.addValue(e, _("4 teams"), "4");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Player slots:")));
-               me.TD(me, 1, 2, makeXonoticSlider(1, 32, 1, "menu_maxplayers"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Number of bots:")));
-               me.TD(me, 1, 2, makeXonoticSlider(0, 9, 1, "bot_number"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Bot skill:")));
-                       setDependent(e, "bot_number", 0, -1);
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("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.configureXonoticTextSliderValues(e);
-                       setDependent(e, "bot_number", 0, -1);
-
-       me.gotoRC(me, me.rows - 3.5, 0);
-               me.TD(me, 1, 3, e0 = makeXonoticTextLabel(0.5, string_null));
-                       e0.textEntity = main.mutatorsDialog;
-                       e0.allowCut = 1;
-                       //e0.allowWrap = 1;
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("Mutators"), '0 0 0'));
-                       e.onClick = DialogOpenButton_Click;
-                       e.onClickEntity = main.mutatorsDialog;
-                       main.mutatorsDialog.refilterEntity = me.mapListBox;
-
-       me.gotoRC(me, 0.5, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.mapListBox = makeXonoticMapList();
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Maplist")));
-                       makeCallback(e, me.mapListBox, me.mapListBox.refilterCallback);
-       me.TR(me);
-               me.TD(me, me.rows - 4, 3, me.mapListBox);
-       me.gotoRC(me, me.rows - 2.5, 3.2);
-               me.TDempty(me, 0.375);
-               me.TD(me, 1, 1.125, e = makeXonoticButton(_("Select all"), '0 0 0'));
-                       e.onClick = MapList_All;
-                       e.onClickEntity = me.mapListBox;
-               me.TD(me, 1, 1.125, e = makeXonoticButton(_("Select none"), '0 0 0'));
-                       e.onClick = MapList_None;
-                       e.onClickEntity = me.mapListBox;
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("Start Multiplayer!"), '0 0 0'));
-                       e.onClick = MapList_LoadMap;
-                       e.onClickEntity = me.mapListBox;
-                       me.mapListBox.startButton = e;
-
-       me.gameTypeChangeNotify(me);
-}
-
-void XonoticServerCreateTab_gameTypeChangeNotify(entity me)
-{
-       // tell the map list to update
-       float gt;
-       entity e, l;
-       gt = MapInfo_CurrentGametype();
-       e = me.sliderFraglimit;
-       l = me.labelFraglimit;
-
-       switch(gt)
-       {
-               case MAPINFO_TYPE_CTF:        GameType_ConfigureSliders(e, l, _("Capture limit:"),   1,   20, 1, "capturelimit_override");     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_LMS:        GameType_ConfigureSliders(e, l, _("Lives:"),           3,   50,  1, "g_lms_lives_override");     break;
-               case MAPINFO_TYPE_RACE:       GameType_ConfigureSliders(e, l, _("Laps:"),            1,   25,  1, "g_race_laps_limit");        break;
-               case MAPINFO_TYPE_NEXBALL:    GameType_ConfigureSliders(e, l, _("Goals:"),           1,   50,  1, "g_nexball_goallimit");      break;
-               case MAPINFO_TYPE_ASSAULT:    GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
-               case MAPINFO_TYPE_ONSLAUGHT:  GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
-               case MAPINFO_TYPE_CTS:        GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
-               case MAPINFO_TYPE_INVASION:   GameType_ConfigureSliders(e, l, _("Point limit:"),     5,    0,  5, "");                         break;
-               default:                      GameType_ConfigureSliders(e, l, _("Frag limit:"),      5,  100,  5, "fraglimit_override");       break;
-       }
-
-       string x = string_null;
-       e = me.sliderTeams;
-       switch(gt)
-       {
-               case MAPINFO_TYPE_CA:               x = "g_ca_teams_override";          break;
-               case MAPINFO_TYPE_DOMINATION:       x = "g_domination_teams_override";  break;
-               case MAPINFO_TYPE_FREEZETAG:        x = "g_freezetag_teams_override";   break;
-               case MAPINFO_TYPE_KEYHUNT:          x = "g_keyhunt_teams_override";     break;
-               case MAPINFO_TYPE_TEAM_DEATHMATCH:  x = "g_tdm_teams_override";         break;
-       }
-       e.configureXonoticTextSlider(e, x);
-       e.configureXonoticTextSliderValues(e);
-       if(!x)
-               e.value = 0;
-       me.sliderTeams.disabled = me.labelTeams.disabled = !x;
-
-       me.mapListBox.refilter(me.mapListBox);
-}
-
-void XonoticServerCreateTab_gameTypeSelectNotify(entity me)
-{
-       me.setFocus(me, me.mapListBox);
-}
-
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create.qc b/qcsrc/menu/xonotic/dialog_multiplayer_create.qc
new file mode 100644 (file)
index 0000000..bbffb52
--- /dev/null
@@ -0,0 +1,217 @@
+#ifdef INTERFACE
+CLASS(XonoticServerCreateTab) EXTENDS(XonoticTab)
+       METHOD(XonoticServerCreateTab, fill, void(entity))
+       METHOD(XonoticServerCreateTab, gameTypeChangeNotify, void(entity))
+       METHOD(XonoticServerCreateTab, gameTypeSelectNotify, void(entity))
+       ATTRIB(XonoticServerCreateTab, title, string, _("Create"))
+       ATTRIB(XonoticServerCreateTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticServerCreateTab, rows, float, 23)
+       ATTRIB(XonoticServerCreateTab, columns, float, 6.2) // added extra .2 for center space
+
+       ATTRIB(XonoticServerCreateTab, mapListBox, entity, NULL)
+       ATTRIB(XonoticServerCreateTab, sliderFraglimit, entity, NULL)
+       ATTRIB(XonoticServerCreateTab, sliderTeams, entity, NULL)
+       ATTRIB(XonoticServerCreateTab, sliderTimelimit, entity, NULL)
+       ATTRIB(XonoticServerCreateTab, labelFraglimit, entity, NULL)
+       ATTRIB(XonoticServerCreateTab, labelTeams, entity, NULL)
+ENDCLASS(XonoticServerCreateTab)
+entity makeXonoticServerCreateTab();
+#endif
+
+#ifdef IMPLEMENTATION
+
+void GameType_ConfigureSliders(entity e, entity l, string pLabel, float pMin, float pMax, float pStep, string pCvar)
+{
+       if(pCvar == "")
+       {
+               e.configureXonoticTextSlider(e, string_null);
+               l.setText(l, pLabel);
+               e.disabled = l.disabled = TRUE;
+       }
+       else
+       {
+               e.configureXonoticTextSlider(e, pCvar);
+               
+               // clear old values
+               float i;
+               for(i = 0; i <= e.nValues; ++i);
+               {
+                       if(e.(valueStrings[i])) { strunzone(e.(valueStrings[i])); }
+                       if(e.(valueIdentifiers[i])) { strunzone(e.(valueIdentifiers[i])); }
+               }
+               e.clearValues(e);
+
+               // set new values
+               e.addValue(e, strzone(_("Default")), strzone("-1"));
+               for(i = pMin; i <= pMax; i += pStep) { e.addValue(e, strzone(ftos(i)), strzone(ftos(i))); }
+               e.addValue(e, strzone(_("Unlimited")), strzone("0"));
+               e.configureXonoticTextSliderValues(e);
+
+               // set text field
+               l.setText(l, pLabel);
+               e.disabled = l.disabled = FALSE;
+       }
+}
+
+entity makeXonoticServerCreateTab()
+{
+       entity me;
+       me = spawnXonoticServerCreateTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticServerCreateTab_fill(entity me)
+{
+       entity e, e0;
+
+       me.gotoRC(me, 0.5, 0);
+               me.TD(me, 1, 3, makeXonoticHeaderLabel(_("Gametype")));
+       me.TR(me);
+               me.TD(me, 10.5, 3, e = makeXonoticGametypeList());
+
+       me.gotoRC(me, 12.5, 0);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Time limit:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("timelimit_override"));
+                       e.addValue(e, ZCTX(_("TIMLIM^Default")), "-1");
+                       e.addValue(e, ZCTX(_("TIMLIM^1 minute")), "1");
+                       e.addValue(e, ZCTX(_("TIMLIM^2 minutes")), "2");
+                       e.addValue(e, ZCTX(_("TIMLIM^3 minutes")), "3");
+                       e.addValue(e, ZCTX(_("TIMLIM^4 minutes")), "4");
+                       e.addValue(e, ZCTX(_("TIMLIM^5 minutes")), "5");
+                       e.addValue(e, ZCTX(_("TIMLIM^6 minutes")), "6");
+                       e.addValue(e, ZCTX(_("TIMLIM^7 minutes")), "7");
+                       e.addValue(e, ZCTX(_("TIMLIM^8 minutes")), "8");
+                       e.addValue(e, ZCTX(_("TIMLIM^9 minutes")), "9");
+                       e.addValue(e, ZCTX(_("TIMLIM^10 minutes")), "10");
+                       e.addValue(e, ZCTX(_("TIMLIM^15 minutes")), "15");
+                       e.addValue(e, ZCTX(_("TIMLIM^20 minutes")), "20");
+                       e.addValue(e, ZCTX(_("TIMLIM^25 minutes")), "25");
+                       e.addValue(e, ZCTX(_("TIMLIM^30 minutes")), "30");
+                       e.addValue(e, ZCTX(_("TIMLIM^40 minutes")), "40");
+                       e.addValue(e, ZCTX(_("TIMLIM^50 minutes")), "50");
+                       e.addValue(e, ZCTX(_("TIMLIM^60 minutes")), "60");
+                       e.addValue(e, ZCTX(_("TIMLIM^Infinite")), "0");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, me.labelFraglimit = makeXonoticTextLabel(0, _("Frag limit:")));
+               me.TD(me, 1, 2, me.sliderFraglimit = makeXonoticTextSlider("fraglimit_override"));
+                       GameType_ConfigureSliders(me.sliderFraglimit, me.labelFraglimit, _("Frag limit:"), 5, 100, 5, "fraglimit_override");
+
+       me.gotoRC(me, 15, 0);
+               me.TD(me, 1, 1, me.labelTeams = makeXonoticTextLabel(0, _("Teams:")));
+               me.TD(me, 1, 2, e = me.sliderTeams = makeXonoticTextSlider(string_null));
+                       e.addValue(e, _("Default"), "0");
+                       e.addValue(e, _("2 teams"), "2");
+                       e.addValue(e, _("3 teams"), "3");
+                       e.addValue(e, _("4 teams"), "4");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Player slots:")));
+               me.TD(me, 1, 2, makeXonoticSlider(1, 32, 1, "menu_maxplayers"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Number of bots:")));
+               me.TD(me, 1, 2, makeXonoticSlider(0, 9, 1, "bot_number"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Bot skill:")));
+                       setDependent(e, "bot_number", 0, -1);
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("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.configureXonoticTextSliderValues(e);
+                       setDependent(e, "bot_number", 0, -1);
+
+       me.gotoRC(me, me.rows - 3.5, 0);
+               me.TD(me, 1, 3, e0 = makeXonoticTextLabel(0.5, string_null));
+                       e0.textEntity = main.mutatorsDialog;
+                       e0.allowCut = 1;
+                       //e0.allowWrap = 1;
+       me.TR(me);
+               me.TDempty(me, 0.5);
+               me.TD(me, 1, 2, e = makeXonoticButton(_("Mutators"), '0 0 0'));
+                       e.onClick = DialogOpenButton_Click;
+                       e.onClickEntity = main.mutatorsDialog;
+                       main.mutatorsDialog.refilterEntity = me.mapListBox;
+
+       me.gotoRC(me, 0.5, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.mapListBox = makeXonoticMapList();
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Maplist")));
+                       makeCallback(e, me.mapListBox, me.mapListBox.refilterCallback);
+       me.TR(me);
+               me.TD(me, me.rows - 4, 3, me.mapListBox);
+       me.gotoRC(me, me.rows - 2.5, 3.2);
+               me.TDempty(me, 0.375);
+               me.TD(me, 1, 1.125, e = makeXonoticButton(_("Select all"), '0 0 0'));
+                       e.onClick = MapList_All;
+                       e.onClickEntity = me.mapListBox;
+               me.TD(me, 1, 1.125, e = makeXonoticButton(_("Select none"), '0 0 0'));
+                       e.onClick = MapList_None;
+                       e.onClickEntity = me.mapListBox;
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("Start Multiplayer!"), '0 0 0'));
+                       e.onClick = MapList_LoadMap;
+                       e.onClickEntity = me.mapListBox;
+                       me.mapListBox.startButton = e;
+
+       me.gameTypeChangeNotify(me);
+}
+
+void XonoticServerCreateTab_gameTypeChangeNotify(entity me)
+{
+       // tell the map list to update
+       float gt;
+       entity e, l;
+       gt = MapInfo_CurrentGametype();
+       e = me.sliderFraglimit;
+       l = me.labelFraglimit;
+
+       switch(gt)
+       {
+               case MAPINFO_TYPE_CTF:        GameType_ConfigureSliders(e, l, _("Capture limit:"),   1,   20, 1, "capturelimit_override");     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_LMS:        GameType_ConfigureSliders(e, l, _("Lives:"),           3,   50,  1, "g_lms_lives_override");     break;
+               case MAPINFO_TYPE_RACE:       GameType_ConfigureSliders(e, l, _("Laps:"),            1,   25,  1, "g_race_laps_limit");        break;
+               case MAPINFO_TYPE_NEXBALL:    GameType_ConfigureSliders(e, l, _("Goals:"),           1,   50,  1, "g_nexball_goallimit");      break;
+               case MAPINFO_TYPE_ASSAULT:    GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
+               case MAPINFO_TYPE_ONSLAUGHT:  GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
+               case MAPINFO_TYPE_CTS:        GameType_ConfigureSliders(e, l, _("Point limit:"),    50,  500, 10, "");                         break;
+               case MAPINFO_TYPE_INVASION:   GameType_ConfigureSliders(e, l, _("Point limit:"),     5,    0,  5, "");                         break;
+               default:                      GameType_ConfigureSliders(e, l, _("Frag limit:"),      5,  100,  5, "fraglimit_override");       break;
+       }
+
+       string x = string_null;
+       e = me.sliderTeams;
+       switch(gt)
+       {
+               case MAPINFO_TYPE_CA:               x = "g_ca_teams_override";          break;
+               case MAPINFO_TYPE_DOMINATION:       x = "g_domination_teams_override";  break;
+               case MAPINFO_TYPE_FREEZETAG:        x = "g_freezetag_teams_override";   break;
+               case MAPINFO_TYPE_KEYHUNT:          x = "g_keyhunt_teams_override";     break;
+               case MAPINFO_TYPE_TEAM_DEATHMATCH:  x = "g_tdm_teams_override";         break;
+       }
+       e.configureXonoticTextSlider(e, x);
+       e.configureXonoticTextSliderValues(e);
+       if(!x)
+               e.value = 0;
+       me.sliderTeams.disabled = me.labelTeams.disabled = !x;
+
+       me.mapListBox.refilter(me.mapListBox);
+}
+
+void XonoticServerCreateTab_gameTypeSelectNotify(entity me)
+{
+       me.setFocus(me, me.mapListBox);
+}
+
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c b/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.c
deleted file mode 100644 (file)
index 9baf361..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticMapInfoDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticMapInfoDialog, fill, void(entity))
-       METHOD(XonoticMapInfoDialog, loadMapInfo, void(entity, float, entity))
-       ATTRIB(XonoticMapInfoDialog, title, string, _("Map Information"))
-       ATTRIB(XonoticMapInfoDialog, color, vector, SKINCOLOR_DIALOG_MAPINFO)
-       ATTRIB(XonoticMapInfoDialog, intendedWidth, float, 1.0)
-       ATTRIB(XonoticMapInfoDialog, rows, float, 11)
-       ATTRIB(XonoticMapInfoDialog, columns, float, 10)
-
-       ATTRIB(XonoticMapInfoDialog, previewImage, entity, NULL)
-       ATTRIB(XonoticMapInfoDialog, titleLabel, entity, NULL)
-       ATTRIB(XonoticMapInfoDialog, authorLabel, entity, NULL)
-       ATTRIB(XonoticMapInfoDialog, descriptionLabel, entity, NULL)
-       ATTRIB(XonoticMapInfoDialog, featuresLabel, entity, NULL)
-
-       ATTRIBARRAY(XonoticMapInfoDialog, typeLabels, entity, 24)
-
-       ATTRIB(XonoticMapInfoDialog, currentMapIndex, float, 0)
-       ATTRIB(XonoticMapInfoDialog, currentMapBSPName, string, string_null)
-       ATTRIB(XonoticMapInfoDialog, currentMapTitle, string, string_null)
-       ATTRIB(XonoticMapInfoDialog, currentMapAuthor, string, string_null)
-       ATTRIB(XonoticMapInfoDialog, currentMapDescription, string, string_null)
-       ATTRIB(XonoticMapInfoDialog, currentMapPreviewImage, string, string_null)
-ENDCLASS(XonoticMapInfoDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticMapInfoDialog_loadMapInfo(entity me, float i, entity mlb)
-{
-       me.currentMapIndex = i;
-       me.startButton.onClickEntity = mlb;
-       MapInfo_Get_ByID(i);
-
-       if(me.currentMapBSPName)
-       {
-               strunzone(me.currentMapBSPName);
-               strunzone(me.currentMapTitle);
-               strunzone(me.currentMapAuthor);
-               strunzone(me.currentMapDescription);
-               strunzone(me.currentMapPreviewImage);
-       }
-       me.currentMapBSPName = strzone(MapInfo_Map_bspname);
-       me.currentMapTitle = strzone(strdecolorize(MapInfo_Map_title));
-       me.currentMapAuthor = strzone(strdecolorize(MapInfo_Map_author));
-       me.currentMapDescription = strzone(MapInfo_Map_description);
-       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);
-       if(draw_PictureSize(me.currentMapPreviewImage) == '0 0 0')
-               me.previewImage.src = "nopreview_map";
-       else
-               me.previewImage.src = me.currentMapPreviewImage;
-
-       for(i = 0; i < GameType_GetCount(); ++i)
-       {
-               entity e;
-               e = me.(typeLabels[i]);
-               e.disabled = !(MapInfo_Map_supportedGametypes & GameType_GetID(i));
-       }
-
-       MapInfo_ClearTemps();
-}
-void XonoticMapInfoDialog_fill(entity me)
-{
-       entity e;
-       float w, wgt, i, n;
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, me.rows - 2, 3, e = makeXonoticImage(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 = makeXonoticTextLabel(0, _("Title:")));
-               me.TD(me, 1, w-1, e = makeXonoticTextLabel(0, ""));
-                       e.colorL = SKINCOLOR_MAPLIST_TITLE;
-                       e.allowCut = 1;
-                       me.titleLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Author:")));
-               me.TD(me, 1, w-1, e = makeXonoticTextLabel(0, ""));
-                       e.colorL = SKINCOLOR_MAPLIST_AUTHOR;
-                       e.allowCut = 1;
-                       me.authorLabel = e;
-       me.TR(me);
-               me.TD(me, 1, w, e = makeXonoticTextLabel(0, _("Game types:")));
-
-       n = ceil(GameType_GetCount() / (me.rows - 6));
-       wgt = (w - 0.2) / n;
-       for(i = 0; i < GameType_GetCount(); ++i)
-       {
-               if(mod(i, n) == 0)
-               {
-                       me.TR(me);
-                       me.TDempty(me, 0.2);
-               }
-               me.TD(me, 1, wgt, e = makeXonoticTextLabel(0, MapInfo_Type_ToText(GameType_GetID(i))));
-                       me.(typeLabels[i]) = e;
-       }
-
-       me.gotoRC(me, me.rows - 2, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticTextLabel(0.5, ""));
-                       e.allowCut = 1;
-                       me.descriptionLabel = e;
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TDempty(me, 0.5);
-
-               me.TD(me, 1, me.columns - 5.5, e = makeXonoticButton(_("Close"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-               me.TD(me, 1, me.columns - 5.5, me.startButton = e = makeXonoticButton(ZCTX(_("MAP^Play")), '0 0 0'));
-                       me.startButton.onClick = MapList_LoadMap;
-                       me.startButton.onClickEntity = NULL; // filled later
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc b/qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc
new file mode 100644 (file)
index 0000000..9baf361
--- /dev/null
@@ -0,0 +1,119 @@
+#ifdef INTERFACE
+CLASS(XonoticMapInfoDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticMapInfoDialog, fill, void(entity))
+       METHOD(XonoticMapInfoDialog, loadMapInfo, void(entity, float, entity))
+       ATTRIB(XonoticMapInfoDialog, title, string, _("Map Information"))
+       ATTRIB(XonoticMapInfoDialog, color, vector, SKINCOLOR_DIALOG_MAPINFO)
+       ATTRIB(XonoticMapInfoDialog, intendedWidth, float, 1.0)
+       ATTRIB(XonoticMapInfoDialog, rows, float, 11)
+       ATTRIB(XonoticMapInfoDialog, columns, float, 10)
+
+       ATTRIB(XonoticMapInfoDialog, previewImage, entity, NULL)
+       ATTRIB(XonoticMapInfoDialog, titleLabel, entity, NULL)
+       ATTRIB(XonoticMapInfoDialog, authorLabel, entity, NULL)
+       ATTRIB(XonoticMapInfoDialog, descriptionLabel, entity, NULL)
+       ATTRIB(XonoticMapInfoDialog, featuresLabel, entity, NULL)
+
+       ATTRIBARRAY(XonoticMapInfoDialog, typeLabels, entity, 24)
+
+       ATTRIB(XonoticMapInfoDialog, currentMapIndex, float, 0)
+       ATTRIB(XonoticMapInfoDialog, currentMapBSPName, string, string_null)
+       ATTRIB(XonoticMapInfoDialog, currentMapTitle, string, string_null)
+       ATTRIB(XonoticMapInfoDialog, currentMapAuthor, string, string_null)
+       ATTRIB(XonoticMapInfoDialog, currentMapDescription, string, string_null)
+       ATTRIB(XonoticMapInfoDialog, currentMapPreviewImage, string, string_null)
+ENDCLASS(XonoticMapInfoDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticMapInfoDialog_loadMapInfo(entity me, float i, entity mlb)
+{
+       me.currentMapIndex = i;
+       me.startButton.onClickEntity = mlb;
+       MapInfo_Get_ByID(i);
+
+       if(me.currentMapBSPName)
+       {
+               strunzone(me.currentMapBSPName);
+               strunzone(me.currentMapTitle);
+               strunzone(me.currentMapAuthor);
+               strunzone(me.currentMapDescription);
+               strunzone(me.currentMapPreviewImage);
+       }
+       me.currentMapBSPName = strzone(MapInfo_Map_bspname);
+       me.currentMapTitle = strzone(strdecolorize(MapInfo_Map_title));
+       me.currentMapAuthor = strzone(strdecolorize(MapInfo_Map_author));
+       me.currentMapDescription = strzone(MapInfo_Map_description);
+       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);
+       if(draw_PictureSize(me.currentMapPreviewImage) == '0 0 0')
+               me.previewImage.src = "nopreview_map";
+       else
+               me.previewImage.src = me.currentMapPreviewImage;
+
+       for(i = 0; i < GameType_GetCount(); ++i)
+       {
+               entity e;
+               e = me.(typeLabels[i]);
+               e.disabled = !(MapInfo_Map_supportedGametypes & GameType_GetID(i));
+       }
+
+       MapInfo_ClearTemps();
+}
+void XonoticMapInfoDialog_fill(entity me)
+{
+       entity e;
+       float w, wgt, i, n;
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, me.rows - 2, 3, e = makeXonoticImage(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 = makeXonoticTextLabel(0, _("Title:")));
+               me.TD(me, 1, w-1, e = makeXonoticTextLabel(0, ""));
+                       e.colorL = SKINCOLOR_MAPLIST_TITLE;
+                       e.allowCut = 1;
+                       me.titleLabel = e;
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Author:")));
+               me.TD(me, 1, w-1, e = makeXonoticTextLabel(0, ""));
+                       e.colorL = SKINCOLOR_MAPLIST_AUTHOR;
+                       e.allowCut = 1;
+                       me.authorLabel = e;
+       me.TR(me);
+               me.TD(me, 1, w, e = makeXonoticTextLabel(0, _("Game types:")));
+
+       n = ceil(GameType_GetCount() / (me.rows - 6));
+       wgt = (w - 0.2) / n;
+       for(i = 0; i < GameType_GetCount(); ++i)
+       {
+               if(mod(i, n) == 0)
+               {
+                       me.TR(me);
+                       me.TDempty(me, 0.2);
+               }
+               me.TD(me, 1, wgt, e = makeXonoticTextLabel(0, MapInfo_Type_ToText(GameType_GetID(i))));
+                       me.(typeLabels[i]) = e;
+       }
+
+       me.gotoRC(me, me.rows - 2, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticTextLabel(0.5, ""));
+                       e.allowCut = 1;
+                       me.descriptionLabel = e;
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TDempty(me, 0.5);
+
+               me.TD(me, 1, me.columns - 5.5, e = makeXonoticButton(_("Close"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+               me.TD(me, 1, me.columns - 5.5, me.startButton = e = makeXonoticButton(ZCTX(_("MAP^Play")), '0 0 0'));
+                       me.startButton.onClick = MapList_LoadMap;
+                       me.startButton.onClickEntity = NULL; // filled later
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c b/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.c
deleted file mode 100644 (file)
index a4e052f..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticMutatorsDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticMutatorsDialog, toString, string(entity))
-       METHOD(XonoticMutatorsDialog, fill, void(entity))
-       METHOD(XonoticMutatorsDialog, showNotify, void(entity))
-       METHOD(XonoticMutatorsDialog, close, void(entity))
-       ATTRIB(XonoticMutatorsDialog, title, string, _("Mutators"))
-       ATTRIB(XonoticMutatorsDialog, color, vector, SKINCOLOR_DIALOG_MUTATORS)
-       ATTRIB(XonoticMutatorsDialog, intendedWidth, float, 0.9)
-       ATTRIB(XonoticMutatorsDialog, rows, float, 20)
-       ATTRIB(XonoticMutatorsDialog, columns, float, 6)
-       ATTRIB(XonoticMutatorsDialog, refilterEntity, entity, NULL)
-ENDCLASS(XonoticMutatorsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticMutatorsDialog_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-
-string weaponarenastring;
-string weaponarenastring_cvar;
-string WeaponArenaString()
-{
-       string s;
-       float n, i, j;
-       entity e;
-       s = cvar_string("g_weaponarena");
-       if(s == "0")
-               return "";
-       if(s == "all" || s == "1")
-               return _("All Weapons Arena");
-       if(s == "most")
-               return _("Most Weapons Arena");
-       if(s == weaponarenastring_cvar)
-               return weaponarenastring;
-       if(weaponarenastring)
-               strunzone(weaponarenastring);
-       if(weaponarenastring_cvar)
-               strunzone(weaponarenastring_cvar);
-
-       weaponarenastring_cvar = strzone(s);
-
-       n = tokenize_console(s);
-       s = "";
-       for(i = 0; i < n; ++i)
-       {
-               for(j = WEP_FIRST; j <= WEP_LAST; ++j)
-               {
-                       e = get_weaponinfo(j);
-                       if(argv(i) == e.netname)
-                               s = strcat(s, " & ", e.message);
-               }
-       }
-       s = sprintf(_("%s Arena"), substring(s, 3, strlen(s) - 3));
-
-       weaponarenastring = strzone(s);
-
-       return weaponarenastring;
-}
-
-string XonoticMutatorsDialog_toString(entity me)
-{
-       string s;
-       s = "";
-       if(cvar("g_dodging"))
-               s = strcat(s, ", ", _("Dodging"));
-       if(cvar("g_instagib"))
-               s = strcat(s, ", ", _("InstaGib"));
-       if(cvar("g_new_toys"))
-               s = strcat(s, ", ", _("New Toys"));
-       if(cvar("g_nix"))
-               s = strcat(s, ", ", _("NIX"));
-       if(cvar("g_rocket_flying"))
-               s = strcat(s, ", ", _("Rocket Flying"));
-       if(cvar("g_invincible_projectiles"))
-               s = strcat(s, ", ", _("Invincible Projectiles"));
-       if(cvar_string("g_weaponarena") != "0")
-               s = strcat(s, ", ", WeaponArenaString());
-       if(cvar("g_balance_blaster_weaponstart") == 0)
-               s = strcat(s, ", ", _("No start weapons"));
-       if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
-               s = strcat(s, ", ", _("Low gravity"));
-       if(cvar("g_cloaked"))
-               s = strcat(s, ", ", _("Cloaked"));
-       if(cvar("g_grappling_hook"))
-               s = strcat(s, ", ", _("Hook"));
-       if(cvar("g_midair"))
-               s = strcat(s, ", ", _("Midair"));
-       if(cvar("g_vampire"))
-               s = strcat(s, ", ", _("Vampire"));
-       if(cvar("g_pinata"))
-               s = strcat(s, ", ", _("Piñata"));
-       if(cvar("g_weapon_stay"))
-               s = strcat(s, ", ", _("Weapons stay"));
-       if(cvar("g_bloodloss") > 0)
-               s = strcat(s, ", ", _("Blood loss"));
-       if(cvar("g_jetpack"))
-               s = strcat(s, ", ", _("Jet pack"));
-       if(cvar("g_buffs"))
-               s = strcat(s, ", ", _("Buffs"));
-       if(cvar("g_overkill"))
-               s = strcat(s, ", ", _("Overkill"));
-       if(cvar("g_powerups") == 0)
-               s = strcat(s, ", ", _("No powerups"));
-       if(cvar("g_powerups") > 0)
-               s = strcat(s, ", ", _("Powerups"));
-       if(cvar("g_touchexplode") > 0)
-               s = strcat(s, ", ", _("Touch explode"));
-       if(s == "")
-               return ZCTX(_("MUT^None"));
-       else
-               return substring(s, 2, strlen(s) - 2);
-}
-
-float checkCompatibility_pinata(entity me)
-{
-       if(cvar("g_instagib"))
-               return 0;
-       if(cvar("g_nix"))
-               return 0;
-       if(cvar_string("g_weaponarena") != "0")
-               return 0;
-       return 1;
-}
-float checkCompatibility_weaponstay(entity me)
-{
-       return checkCompatibility_pinata(me);
-}
-float checkCompatibility_newtoys(entity me)
-{
-       if(cvar("g_instagib"))
-               return 0;
-       if(cvar_string("g_weaponarena") == "most")
-               return 1;
-       if(cvar_string("g_weaponarena") == "all" || cvar_string("g_weaponarena") == "1")
-               return 1;
-       if(cvar_string("g_weaponarena") != "0")
-               return 0;
-       return 1;
-}
-float checkCompatibility_weaponarena_weapon(entity me)
-{
-       if(cvar("g_instagib"))
-               return 0;
-       if(cvar_string("g_weaponarena") == "most")
-               return 0;
-       if(cvar_string("g_weaponarena") == "all" || cvar_string("g_weaponarena") == "1")
-               return 0;
-       if(cvar_string("g_weaponarena") == "0")
-               return 0;
-       if(cvar_string("g_balance_blaster_weaponstart") == "0")
-               return 0;
-       return 1;
-}
-
-void XonoticMutatorsDialog_fill(entity me)
-{
-       entity e, s, w;
-       float i, j;
-       me.TR(me);
-               me.TD(me, 1, 2, makeXonoticTextLabel(0, _("Gameplay mutators:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_dodging", _("Dodging")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_touchexplode", _("Touch explode")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_cloaked", _("Cloaked")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_buffs", _("Buffs")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_midair", _("Midair")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_vampire", _("Vampire")));
-                       setDependent(e, "g_instagib", 0, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticSlider(10, 50, 1, "g_bloodloss");
-               me.TD(me, 1, 1.8, e = makeXonoticSliderCheckBox(0, 1, s, _("Blood loss")));
-                       setDependent(e, "g_instagib", 0, 0);
-       me.TR(me);
-               me.TDempty(me, 0.4);
-               me.TD(me, 1, 1.6, s);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticSlider(80, 400, 8, "sv_gravity");
-                       s.valueDigits = 0;
-                       s.valueDisplayMultiplier = 0.125; // show gravity in percent
-               me.TD(me, 1, 1.8, e = makeXonoticSliderCheckBox(800, 1, s, _("Low gravity")));
-                       e.savedValue = 200; // good on silvercity
-       me.TR(me);
-               me.TDempty(me, 0.4);
-               me.TD(me, 1, 1.6, s);
-       me.TR(me);
-               me.TD(me, 1, 2, makeXonoticTextLabel(0, _("Weapon & item mutators:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_grappling_hook", _("Grappling hook")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_jetpack", _("Jet pack")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_invincible_projectiles", _("Invincible Projectiles")));
-                       setDependent(e, "g_instagib", 0, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_new_toys", _("New Toys")));
-                       setDependentWeird(e, checkCompatibility_newtoys);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_rocket_flying", _("Rocket Flying")));
-                       setDependent(e, "g_instagib", 0, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_pinata", _("Piñata")));
-                       setDependentWeird(e, checkCompatibility_pinata);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_weapon_stay", _("Weapons stay")));
-                       setDependentWeird(e, checkCompatibility_weaponstay);
-       me.TR(me);
-
-       me.gotoRC(me, 0, 2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 2, e = makeXonoticRadioButton(1, string_null, string_null, _("Regular (no arena)")));
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "g_weaponarena", "menu_weaponarena", _("Weapon arenas:")));
-                       e.getCvarValueFromCvar = TRUE;
-                       e.cvarOffValue = "0";
-       for(i = WEP_FIRST, j = 0; i <= WEP_LAST; ++i)
-       {
-               w = get_weaponinfo(i);
-               if(w.spawnflags & WEP_FLAG_HIDDEN)
-                       continue;
-               if((j & 1) == 0)
-                       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.message)));
-                       setDependentWeird(e, checkCompatibility_weaponarena_weapon);
-               ++j;
-       }
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_weaponarena", "most", _("Most weapons")));
-                       e.cvarOffValue = "0";
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_weaponarena", "all", _("All weapons")));
-                       e.cvarOffValue = "0";
-       me.TR(me);
-               me.TD(me, 1, 4, makeXonoticTextLabel(0, _("Special arenas:")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_instagib", "1", _("InstaGib")));
-                       e.cvarOffValue = "0";
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_nix", "1", _("NIX")));
-                       e.cvarOffValue = "0";
-       me.TR(me);
-               me.TDempty(me, 0.4);
-               me.TD(me, 1, 1.6, e = makeXonoticCheckBox(0, "g_nix_with_blaster", _("with blaster")));
-                       setDependent(e, "g_nix", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_balance_blaster_weaponstart", "0", _("No start weapons")));
-                       e.cvarOffValue = "-1";
-                       makeMulti(e, "g_balance_shotgun_weaponstart g_balance_machinegun_weaponstart g_balance_devastator_weaponstart g_balance_minelayer_weaponstart g_balance_electro_weaponstart g_balance_crylink_weaponstart g_balance_hagar_weaponstart g_balance_porto_weaponstart g_balance_vaporizer_weaponstart g_balance_hook_weaponstart g_balance_rifle_weaponstart g_balance_fireball_weaponstart g_balance_seeker_weaponstart g_balance_tuba_weaponstart g_balance_arc_weaponstart g_balance_vortex_weaponstart g_balance_mortar_weaponstart");
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-
-void XonoticMutatorsDialog_close(entity me)
-{
-       if(me.refilterEntity)
-               me.refilterEntity.refilter(me.refilterEntity);
-       SUPER(XonoticMutatorsDialog).close(me);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc b/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc
new file mode 100644 (file)
index 0000000..a4e052f
--- /dev/null
@@ -0,0 +1,289 @@
+#ifdef INTERFACE
+CLASS(XonoticMutatorsDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticMutatorsDialog, toString, string(entity))
+       METHOD(XonoticMutatorsDialog, fill, void(entity))
+       METHOD(XonoticMutatorsDialog, showNotify, void(entity))
+       METHOD(XonoticMutatorsDialog, close, void(entity))
+       ATTRIB(XonoticMutatorsDialog, title, string, _("Mutators"))
+       ATTRIB(XonoticMutatorsDialog, color, vector, SKINCOLOR_DIALOG_MUTATORS)
+       ATTRIB(XonoticMutatorsDialog, intendedWidth, float, 0.9)
+       ATTRIB(XonoticMutatorsDialog, rows, float, 20)
+       ATTRIB(XonoticMutatorsDialog, columns, float, 6)
+       ATTRIB(XonoticMutatorsDialog, refilterEntity, entity, NULL)
+ENDCLASS(XonoticMutatorsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticMutatorsDialog_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+
+string weaponarenastring;
+string weaponarenastring_cvar;
+string WeaponArenaString()
+{
+       string s;
+       float n, i, j;
+       entity e;
+       s = cvar_string("g_weaponarena");
+       if(s == "0")
+               return "";
+       if(s == "all" || s == "1")
+               return _("All Weapons Arena");
+       if(s == "most")
+               return _("Most Weapons Arena");
+       if(s == weaponarenastring_cvar)
+               return weaponarenastring;
+       if(weaponarenastring)
+               strunzone(weaponarenastring);
+       if(weaponarenastring_cvar)
+               strunzone(weaponarenastring_cvar);
+
+       weaponarenastring_cvar = strzone(s);
+
+       n = tokenize_console(s);
+       s = "";
+       for(i = 0; i < n; ++i)
+       {
+               for(j = WEP_FIRST; j <= WEP_LAST; ++j)
+               {
+                       e = get_weaponinfo(j);
+                       if(argv(i) == e.netname)
+                               s = strcat(s, " & ", e.message);
+               }
+       }
+       s = sprintf(_("%s Arena"), substring(s, 3, strlen(s) - 3));
+
+       weaponarenastring = strzone(s);
+
+       return weaponarenastring;
+}
+
+string XonoticMutatorsDialog_toString(entity me)
+{
+       string s;
+       s = "";
+       if(cvar("g_dodging"))
+               s = strcat(s, ", ", _("Dodging"));
+       if(cvar("g_instagib"))
+               s = strcat(s, ", ", _("InstaGib"));
+       if(cvar("g_new_toys"))
+               s = strcat(s, ", ", _("New Toys"));
+       if(cvar("g_nix"))
+               s = strcat(s, ", ", _("NIX"));
+       if(cvar("g_rocket_flying"))
+               s = strcat(s, ", ", _("Rocket Flying"));
+       if(cvar("g_invincible_projectiles"))
+               s = strcat(s, ", ", _("Invincible Projectiles"));
+       if(cvar_string("g_weaponarena") != "0")
+               s = strcat(s, ", ", WeaponArenaString());
+       if(cvar("g_balance_blaster_weaponstart") == 0)
+               s = strcat(s, ", ", _("No start weapons"));
+       if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
+               s = strcat(s, ", ", _("Low gravity"));
+       if(cvar("g_cloaked"))
+               s = strcat(s, ", ", _("Cloaked"));
+       if(cvar("g_grappling_hook"))
+               s = strcat(s, ", ", _("Hook"));
+       if(cvar("g_midair"))
+               s = strcat(s, ", ", _("Midair"));
+       if(cvar("g_vampire"))
+               s = strcat(s, ", ", _("Vampire"));
+       if(cvar("g_pinata"))
+               s = strcat(s, ", ", _("Piñata"));
+       if(cvar("g_weapon_stay"))
+               s = strcat(s, ", ", _("Weapons stay"));
+       if(cvar("g_bloodloss") > 0)
+               s = strcat(s, ", ", _("Blood loss"));
+       if(cvar("g_jetpack"))
+               s = strcat(s, ", ", _("Jet pack"));
+       if(cvar("g_buffs"))
+               s = strcat(s, ", ", _("Buffs"));
+       if(cvar("g_overkill"))
+               s = strcat(s, ", ", _("Overkill"));
+       if(cvar("g_powerups") == 0)
+               s = strcat(s, ", ", _("No powerups"));
+       if(cvar("g_powerups") > 0)
+               s = strcat(s, ", ", _("Powerups"));
+       if(cvar("g_touchexplode") > 0)
+               s = strcat(s, ", ", _("Touch explode"));
+       if(s == "")
+               return ZCTX(_("MUT^None"));
+       else
+               return substring(s, 2, strlen(s) - 2);
+}
+
+float checkCompatibility_pinata(entity me)
+{
+       if(cvar("g_instagib"))
+               return 0;
+       if(cvar("g_nix"))
+               return 0;
+       if(cvar_string("g_weaponarena") != "0")
+               return 0;
+       return 1;
+}
+float checkCompatibility_weaponstay(entity me)
+{
+       return checkCompatibility_pinata(me);
+}
+float checkCompatibility_newtoys(entity me)
+{
+       if(cvar("g_instagib"))
+               return 0;
+       if(cvar_string("g_weaponarena") == "most")
+               return 1;
+       if(cvar_string("g_weaponarena") == "all" || cvar_string("g_weaponarena") == "1")
+               return 1;
+       if(cvar_string("g_weaponarena") != "0")
+               return 0;
+       return 1;
+}
+float checkCompatibility_weaponarena_weapon(entity me)
+{
+       if(cvar("g_instagib"))
+               return 0;
+       if(cvar_string("g_weaponarena") == "most")
+               return 0;
+       if(cvar_string("g_weaponarena") == "all" || cvar_string("g_weaponarena") == "1")
+               return 0;
+       if(cvar_string("g_weaponarena") == "0")
+               return 0;
+       if(cvar_string("g_balance_blaster_weaponstart") == "0")
+               return 0;
+       return 1;
+}
+
+void XonoticMutatorsDialog_fill(entity me)
+{
+       entity e, s, w;
+       float i, j;
+       me.TR(me);
+               me.TD(me, 1, 2, makeXonoticTextLabel(0, _("Gameplay mutators:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_dodging", _("Dodging")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_touchexplode", _("Touch explode")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_cloaked", _("Cloaked")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_buffs", _("Buffs")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_midair", _("Midair")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_vampire", _("Vampire")));
+                       setDependent(e, "g_instagib", 0, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticSlider(10, 50, 1, "g_bloodloss");
+               me.TD(me, 1, 1.8, e = makeXonoticSliderCheckBox(0, 1, s, _("Blood loss")));
+                       setDependent(e, "g_instagib", 0, 0);
+       me.TR(me);
+               me.TDempty(me, 0.4);
+               me.TD(me, 1, 1.6, s);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticSlider(80, 400, 8, "sv_gravity");
+                       s.valueDigits = 0;
+                       s.valueDisplayMultiplier = 0.125; // show gravity in percent
+               me.TD(me, 1, 1.8, e = makeXonoticSliderCheckBox(800, 1, s, _("Low gravity")));
+                       e.savedValue = 200; // good on silvercity
+       me.TR(me);
+               me.TDempty(me, 0.4);
+               me.TD(me, 1, 1.6, s);
+       me.TR(me);
+               me.TD(me, 1, 2, makeXonoticTextLabel(0, _("Weapon & item mutators:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_grappling_hook", _("Grappling hook")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_jetpack", _("Jet pack")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_invincible_projectiles", _("Invincible Projectiles")));
+                       setDependent(e, "g_instagib", 0, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_new_toys", _("New Toys")));
+                       setDependentWeird(e, checkCompatibility_newtoys);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_rocket_flying", _("Rocket Flying")));
+                       setDependent(e, "g_instagib", 0, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_pinata", _("Piñata")));
+                       setDependentWeird(e, checkCompatibility_pinata);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_weapon_stay", _("Weapons stay")));
+                       setDependentWeird(e, checkCompatibility_weaponstay);
+       me.TR(me);
+
+       me.gotoRC(me, 0, 2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 2, e = makeXonoticRadioButton(1, string_null, string_null, _("Regular (no arena)")));
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "g_weaponarena", "menu_weaponarena", _("Weapon arenas:")));
+                       e.getCvarValueFromCvar = TRUE;
+                       e.cvarOffValue = "0";
+       for(i = WEP_FIRST, j = 0; i <= WEP_LAST; ++i)
+       {
+               w = get_weaponinfo(i);
+               if(w.spawnflags & WEP_FLAG_HIDDEN)
+                       continue;
+               if((j & 1) == 0)
+                       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.message)));
+                       setDependentWeird(e, checkCompatibility_weaponarena_weapon);
+               ++j;
+       }
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_weaponarena", "most", _("Most weapons")));
+                       e.cvarOffValue = "0";
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_weaponarena", "all", _("All weapons")));
+                       e.cvarOffValue = "0";
+       me.TR(me);
+               me.TD(me, 1, 4, makeXonoticTextLabel(0, _("Special arenas:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_instagib", "1", _("InstaGib")));
+                       e.cvarOffValue = "0";
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_nix", "1", _("NIX")));
+                       e.cvarOffValue = "0";
+       me.TR(me);
+               me.TDempty(me, 0.4);
+               me.TD(me, 1, 1.6, e = makeXonoticCheckBox(0, "g_nix_with_blaster", _("with blaster")));
+                       setDependent(e, "g_nix", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticRadioButton(1, "g_balance_blaster_weaponstart", "0", _("No start weapons")));
+                       e.cvarOffValue = "-1";
+                       makeMulti(e, "g_balance_shotgun_weaponstart g_balance_machinegun_weaponstart g_balance_devastator_weaponstart g_balance_minelayer_weaponstart g_balance_electro_weaponstart g_balance_crylink_weaponstart g_balance_hagar_weaponstart g_balance_porto_weaponstart g_balance_vaporizer_weaponstart g_balance_hook_weaponstart g_balance_rifle_weaponstart g_balance_fireball_weaponstart g_balance_seeker_weaponstart g_balance_tuba_weaponstart g_balance_arc_weaponstart g_balance_vortex_weaponstart g_balance_mortar_weaponstart");
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+
+void XonoticMutatorsDialog_close(entity me)
+{
+       if(me.refilterEntity)
+               me.refilterEntity.refilter(me.refilterEntity);
+       SUPER(XonoticMutatorsDialog).close(me);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join.c b/qcsrc/menu/xonotic/dialog_multiplayer_join.c
deleted file mode 100644 (file)
index 4636ebb..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticServerListTab) EXTENDS(XonoticTab)
-       METHOD(XonoticServerListTab, fill, void(entity))
-       ATTRIB(XonoticServerListTab, title, string, _("Join"))
-       ATTRIB(XonoticServerListTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticServerListTab, rows, float, 23)
-       ATTRIB(XonoticServerListTab, columns, float, 6.5)
-ENDCLASS(XonoticServerListTab)
-entity makeXonoticServerListTab();
-#endif
-
-#ifdef IMPLEMENTATION
-
-entity makeXonoticServerListTab()
-{
-       entity me;
-       me = spawnXonoticServerListTab();
-       me.configureDialog(me);
-       return me;
-}
-void XonoticServerListTab_fill(entity me)
-{
-       entity e, slist;
-
-       slist  = makeXonoticServerList();
-
-       me.gotoRC(me, 0.5, 0);
-               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
-               me.TD(me, 1, 2.8, e = makeXonoticInputBox(0, string_null));
-                       e.onChange = ServerList_Filter_Change;
-                       e.onChangeEntity = slist;
-                       slist.controlledTextbox = e;
-
-       me.gotoRC(me, 0.5, 3.6);
-               me.TD(me, 1, 0.9, e = makeXonoticCheckBox(0, "menu_slist_categories", ZCTX(_("SRVS^Categories"))));
-                       e.onClickEntity = slist;
-                       e.onClick = ServerList_Categories_Click;
-               me.TD(me, 1, 0.6, e = makeXonoticCheckBox(0, "menu_slist_showempty", ZCTX(_("SRVS^Empty"))));
-                       slist.filterShowEmpty = e.checked;
-                       e.onClickEntity = slist;
-                       e.onClick = ServerList_ShowEmpty_Click;
-               me.TD(me, 1, 0.6, e = makeXonoticCheckBox(0, "menu_slist_showfull", ZCTX(_("SRVS^Full"))));
-                       slist.filterShowFull = e.checked;
-                       e.onClickEntity = slist;
-                       e.onClick = ServerList_ShowFull_Click;
-               me.TD(me, 1, 0.6, e = makeXonoticCheckBox(0, "net_slist_pause", _("Pause")));
-
-       me.gotoRC(me, 2, 0);
-               me.TD(me, 1, 1, slist.sortButton1 = makeXonoticButton(string_null, '0 0 0'));
-               me.TD(me, 1, 1, slist.sortButton2 = makeXonoticButton(string_null, '0 0 0'));
-               me.TD(me, 1, 1, slist.sortButton3 = makeXonoticButton(string_null, '0 0 0'));
-               me.TD(me, 1, 1, slist.sortButton4 = makeXonoticButton(string_null, '0 0 0'));
-               me.TD(me, 1, 1, slist.sortButton5 = makeXonoticButton(string_null, '0 0 0'));
-       me.TR(me);
-               me.TD(me, me.rows - 5, me.columns, slist);
-
-       me.gotoRC(me, me.rows - 2, 0);
-               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(0, _("Address:")));
-               me.TD(me, 1, 2.9, e = makeXonoticInputBox(0, string_null));
-                       e.onEnter = ServerList_Connect_Click;
-                       e.onEnterEntity = slist;
-                       e.onChange = ServerList_Update_favoriteButton;
-                       e.onChangeEntity = slist;
-                       slist.ipAddressBox = e;
-               me.TD(me, 1, 1.5, e = makeXonoticButton("", '0 0 0'));
-                       e.onClick = ServerList_Favorite_Click;
-                       e.onClickEntity = slist;
-                       slist.favoriteButton = e;
-               me.TD(me, 1, 1.5, e = makeXonoticButton(_("Info..."), '0 0 0'));
-                       e.onClick = ServerList_Info_Click;
-                       e.onClickEntity = slist;
-                       slist.infoButton = e;
-       me.TR(me);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("Join!"), '0 0 0'));
-                       e.onClick = ServerList_Connect_Click;
-                       e.onClickEntity = slist;
-                       slist.connectButton = e;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join.qc b/qcsrc/menu/xonotic/dialog_multiplayer_join.qc
new file mode 100644 (file)
index 0000000..4636ebb
--- /dev/null
@@ -0,0 +1,79 @@
+#ifdef INTERFACE
+CLASS(XonoticServerListTab) EXTENDS(XonoticTab)
+       METHOD(XonoticServerListTab, fill, void(entity))
+       ATTRIB(XonoticServerListTab, title, string, _("Join"))
+       ATTRIB(XonoticServerListTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticServerListTab, rows, float, 23)
+       ATTRIB(XonoticServerListTab, columns, float, 6.5)
+ENDCLASS(XonoticServerListTab)
+entity makeXonoticServerListTab();
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeXonoticServerListTab()
+{
+       entity me;
+       me = spawnXonoticServerListTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticServerListTab_fill(entity me)
+{
+       entity e, slist;
+
+       slist  = makeXonoticServerList();
+
+       me.gotoRC(me, 0.5, 0);
+               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
+               me.TD(me, 1, 2.8, e = makeXonoticInputBox(0, string_null));
+                       e.onChange = ServerList_Filter_Change;
+                       e.onChangeEntity = slist;
+                       slist.controlledTextbox = e;
+
+       me.gotoRC(me, 0.5, 3.6);
+               me.TD(me, 1, 0.9, e = makeXonoticCheckBox(0, "menu_slist_categories", ZCTX(_("SRVS^Categories"))));
+                       e.onClickEntity = slist;
+                       e.onClick = ServerList_Categories_Click;
+               me.TD(me, 1, 0.6, e = makeXonoticCheckBox(0, "menu_slist_showempty", ZCTX(_("SRVS^Empty"))));
+                       slist.filterShowEmpty = e.checked;
+                       e.onClickEntity = slist;
+                       e.onClick = ServerList_ShowEmpty_Click;
+               me.TD(me, 1, 0.6, e = makeXonoticCheckBox(0, "menu_slist_showfull", ZCTX(_("SRVS^Full"))));
+                       slist.filterShowFull = e.checked;
+                       e.onClickEntity = slist;
+                       e.onClick = ServerList_ShowFull_Click;
+               me.TD(me, 1, 0.6, e = makeXonoticCheckBox(0, "net_slist_pause", _("Pause")));
+
+       me.gotoRC(me, 2, 0);
+               me.TD(me, 1, 1, slist.sortButton1 = makeXonoticButton(string_null, '0 0 0'));
+               me.TD(me, 1, 1, slist.sortButton2 = makeXonoticButton(string_null, '0 0 0'));
+               me.TD(me, 1, 1, slist.sortButton3 = makeXonoticButton(string_null, '0 0 0'));
+               me.TD(me, 1, 1, slist.sortButton4 = makeXonoticButton(string_null, '0 0 0'));
+               me.TD(me, 1, 1, slist.sortButton5 = makeXonoticButton(string_null, '0 0 0'));
+       me.TR(me);
+               me.TD(me, me.rows - 5, me.columns, slist);
+
+       me.gotoRC(me, me.rows - 2, 0);
+               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(0, _("Address:")));
+               me.TD(me, 1, 2.9, e = makeXonoticInputBox(0, string_null));
+                       e.onEnter = ServerList_Connect_Click;
+                       e.onEnterEntity = slist;
+                       e.onChange = ServerList_Update_favoriteButton;
+                       e.onChangeEntity = slist;
+                       slist.ipAddressBox = e;
+               me.TD(me, 1, 1.5, e = makeXonoticButton("", '0 0 0'));
+                       e.onClick = ServerList_Favorite_Click;
+                       e.onClickEntity = slist;
+                       slist.favoriteButton = e;
+               me.TD(me, 1, 1.5, e = makeXonoticButton(_("Info..."), '0 0 0'));
+                       e.onClick = ServerList_Info_Click;
+                       e.onClickEntity = slist;
+                       slist.infoButton = e;
+       me.TR(me);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("Join!"), '0 0 0'));
+                       e.onClick = ServerList_Connect_Click;
+                       e.onClickEntity = slist;
+                       slist.connectButton = e;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.c b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.c
deleted file mode 100644 (file)
index fa5e306..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticServerInfoDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticServerInfoDialog, fill, void(entity))
-       METHOD(XonoticServerInfoDialog, loadServerInfo, void(entity, float))
-       ATTRIB(XonoticServerInfoDialog, title, string, _("Server Information"))
-       ATTRIB(XonoticServerInfoDialog, color, vector, SKINCOLOR_DIALOG_SERVERINFO)
-       ATTRIB(XonoticServerInfoDialog, intendedWidth, float, 0.8)
-       ATTRIB(XonoticServerInfoDialog, rows, float, 18)
-       ATTRIB(XonoticServerInfoDialog, columns, float, 6.2)
-
-       ATTRIB(XonoticServerInfoDialog, currentServerName, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerCName, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerType, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerMap, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerPlayers, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerNumPlayers, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerNumBots, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerNumFreeSlots, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerMod, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerVersion, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerKey, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerID, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerEncrypt, string, string_null)
-       ATTRIB(XonoticServerInfoDialog, currentServerPure, string, string_null)
-
-       ATTRIB(XonoticServerInfoDialog, nameLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, cnameLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, typeLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, mapLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, rawPlayerList, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, numPlayersLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, numBotsLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, numFreeSlotsLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, modLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, versionLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, keyLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, idLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, encryptLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, canConnectLabel, entity, NULL)
-       ATTRIB(XonoticServerInfoDialog, pureLabel, entity, NULL)
-ENDCLASS(XonoticServerInfoDialog)
-
-void Join_Click(entity btn, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticServerInfoDialog_loadServerInfo(entity me, float i)
-{
-       float m, pure, freeslots, j, numh, maxp, numb, sflags;
-       string s, typestr, versionstr, k, v, modname;
-
-       // ====================================
-       //  First clear and unzone the strings
-       // ====================================
-       if(me.currentServerName)
-               strunzone(me.currentServerName);
-       me.currentServerName = string_null;
-
-       if(me.currentServerCName)
-               strunzone(me.currentServerCName);
-       me.currentServerCName = string_null;
-
-       if(me.currentServerType)
-               strunzone(me.currentServerType);
-       me.currentServerType = string_null;
-
-       if(me.currentServerMap)
-               strunzone(me.currentServerMap);
-       me.currentServerMap = string_null;
-
-       if(me.currentServerPlayers)
-               strunzone(me.currentServerPlayers);
-       me.currentServerPlayers = string_null;
-
-       if(me.currentServerNumPlayers)
-               strunzone(me.currentServerNumPlayers);
-       me.currentServerNumPlayers = string_null;
-
-       if(me.currentServerNumBots)
-               strunzone(me.currentServerNumBots);
-       me.currentServerNumBots = string_null;
-
-       if(me.currentServerNumFreeSlots)
-               strunzone(me.currentServerNumFreeSlots);
-       me.currentServerNumFreeSlots = string_null;
-
-       if(me.currentServerMod)
-               strunzone(me.currentServerMod);
-       me.currentServerMod = string_null;
-
-       if(me.currentServerVersion)
-               strunzone(me.currentServerVersion);
-       me.currentServerVersion = string_null;
-
-       // not zoned!
-       //if(me.currentServerEncrypt)
-       //      strunzone(me.currentServerEncrypt);
-       //me.currentServerEncrypt = string_null;
-       if(me.currentServerPure)
-               strunzone(me.currentServerPure);
-       me.currentServerPure = string_null;
-
-       if(me.currentServerKey)
-               strunzone(me.currentServerKey);
-       me.currentServerKey = string_null;
-
-       if(me.currentServerID)
-               strunzone(me.currentServerID);
-       me.currentServerID = string_null;
-
-       // ==========================
-       //  Now, fill in the strings
-       // ==========================
-       me.currentServerName = strzone(gethostcachestring(SLIST_FIELD_NAME, i));
-       me.nameLabel.setText(me.nameLabel, me.currentServerName);
-
-       me.currentServerCName = strzone(gethostcachestring(SLIST_FIELD_CNAME, i));
-       me.cnameLabel.setText(me.cnameLabel, me.currentServerCName);
-
-       pure = -1;
-       typestr = _("N/A");
-       versionstr = _("N/A");
-
-       s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
-       m = tokenizebyseparator(s, ":");
-       if(m >= 2)
-       {
-               typestr = argv(0);
-               versionstr = argv(1);
-       }
-       freeslots = -1;
-       sflags = -1;
-       modname = "";
-       for(j = 2; j < m; ++j)
-       {
-               if(argv(j) == "")
-                       break;
-               k = substring(argv(j), 0, 1);
-               v = substring(argv(j), 1, -1);
-               if(k == "P")
-                       pure = stof(v);
-               else if(k == "S")
-                       freeslots = stof(v);
-               else if(k == "F")
-                       sflags = stof(v);
-               else if(k == "M")
-                       modname = v;
-       }
-
-#ifdef COMPAT_NO_MOD_IS_XONOTIC
-       if(modname == "")
-               modname = "Xonotic";
-#endif
-
-       s = gethostcachestring(SLIST_FIELD_MOD, i);
-       if(s != "data")
-               modname = sprintf("%s (%s)", modname, s);
-
-       j = MapInfo_Type_FromString(typestr); // try and get the real name of the game type
-       if(j) { typestr = MapInfo_Type_ToText(j); } // only set it if we actually found it
-
-       me.currentServerType = strzone(typestr);
-       me.typeLabel.setText(me.typeLabel, me.currentServerType);
-
-       me.currentServerMap = strzone(gethostcachestring(SLIST_FIELD_MAP, i));
-       me.mapLabel.setText(me.mapLabel, me.currentServerMap);
-
-       me.currentServerPlayers = strzone(gethostcachestring(SLIST_FIELD_PLAYERS, i));
-       me.rawPlayerList.setPlayerList(me.rawPlayerList, me.currentServerPlayers);
-
-       numh = gethostcachenumber(SLIST_FIELD_NUMHUMANS, i);
-       maxp = gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i);
-       numb = gethostcachenumber(SLIST_FIELD_NUMBOTS, i);
-       me.currentServerNumPlayers = strzone(sprintf("%d/%d", numh, maxp));
-       me.numPlayersLabel.setText(me.numPlayersLabel, me.currentServerNumPlayers);
-
-       s = ftos(numb);
-       me.currentServerNumBots = strzone(s);
-       me.numBotsLabel.setText(me.numBotsLabel, me.currentServerNumBots);
-
-       if(freeslots < 0) { freeslots = maxp - numh - numb; }
-       s = ftos(freeslots);
-       me.currentServerNumFreeSlots = strzone(s);
-       me.numFreeSlotsLabel.setText(me.numFreeSlotsLabel, me.currentServerNumFreeSlots);
-
-       me.currentServerMod = ((modname == "Xonotic") ? _("Default") : modname);
-       me.currentServerMod = strzone(me.currentServerMod);
-       me.modLabel.setText(me.modLabel, me.currentServerMod);
-
-       me.currentServerVersion = strzone(versionstr);
-       me.versionLabel.setText(me.versionLabel, me.currentServerVersion);
-
-       me.currentServerPure = ((pure < 0) ? _("N/A") : (pure == 0) ? _("Official") : sprintf(_("%d modified"), pure));
-       me.currentServerPure = strzone(me.currentServerPure);
-       me.pureLabel.setText(me.pureLabel, me.currentServerPure);
-
-       s = crypto_getencryptlevel(me.currentServerCName);
-       if(s == "")
-       {
-               if(cvar("crypto_aeslevel") >= 3)
-                       me.currentServerEncrypt = _("N/A (auth library missing, can't connect)");
-               else
-                       me.currentServerEncrypt = _("N/A (auth library missing)");
-       }
-       else switch(stof(substring(s, 0, 1)))
-       {
-               case 0:
-                       if(cvar("crypto_aeslevel") >= 3)
-                               me.currentServerEncrypt = _("Not supported (can't connect)");
-                       else
-                               me.currentServerEncrypt = _("Not supported (won't encrypt)");
-                       break;
-               case 1:
-                       if(cvar("crypto_aeslevel") >= 2)
-                               me.currentServerEncrypt = _("Supported (will encrypt)");
-                       else
-                               me.currentServerEncrypt = _("Supported (won't encrypt)");
-                       break;
-               case 2:
-                       if(cvar("crypto_aeslevel") >= 1)
-                               me.currentServerEncrypt = _("Requested (will encrypt)");
-                       else
-                               me.currentServerEncrypt = _("Requested (won't encrypt)");
-                       break;
-               case 3:
-                       if(cvar("crypto_aeslevel") <= 0)
-                               me.currentServerEncrypt = _("Required (can't connect)");
-                       else
-                               me.currentServerEncrypt = _("Required (will encrypt)");
-                       break;
-       }
-       me.encryptLabel.setText(me.encryptLabel, me.currentServerEncrypt);
-
-       s = crypto_getidfp(me.currentServerCName);
-       if (!s) { s = _("N/A"); }
-       me.currentServerID = strzone(s);
-       me.idLabel.setText(me.idLabel, me.currentServerID);
-
-       s = crypto_getkeyfp(me.currentServerCName);
-       if (!s) { s = _("N/A"); }
-       me.currentServerKey = strzone(s);
-       me.keyLabel.setText(me.keyLabel, me.currentServerKey);
-}
-
-void XonoticServerInfoDialog_fill(entity me)
-{
-       entity e;
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Hostname:")));
-               me.TD(me, 1, 4.6, e = makeXonoticTextLabel(0.5, ""));
-               e.colorL = SKINCOLOR_SERVERINFO_NAME;
-               e.allowCut = 1;
-               me.nameLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Address:")));
-               me.TD(me, 1, 4.6, e = makeXonoticTextLabel(0.5, ""));
-               e.colorL = SKINCOLOR_SERVERINFO_IP;
-               e.allowCut = 1;
-               me.cnameLabel = e;
-
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Gametype:")));
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
-               e.allowCut = 1;
-               me.typeLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Map:")));
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
-               e.allowCut = 1;
-               me.mapLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Mod:")));
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
-               e.allowCut = 1;
-               me.modLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Version:")));
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
-               e.allowCut = 1;
-               me.versionLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Settings:")));
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
-               e.allowCut = 1;
-               me.pureLabel = e;
-
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Players:")));
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
-               e.allowCut = 1;
-               me.numPlayersLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Bots:")));
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
-               e.allowCut = 1;
-               me.numBotsLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Free slots:")));
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
-               e.allowCut = 1;
-               me.numFreeSlotsLabel = e;
-
-       me.gotoRC(me, me.rows - 5, 0);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Encryption:")));
-               me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, ""));
-                       e.allowCut = 1;
-                       me.encryptLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("ID:")));
-               me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, ""));
-                       e.allowCut = 1;
-                       me.keyLabel = e;
-       me.TR(me);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Key:")));
-               me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, ""));
-                       e.allowCut = 1;
-                       me.idLabel = e;
-
-       me.gotoRC(me, 2, 2.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Players:")));
-       me.TR(me);
-               me.TD(me, me.rows - 8, 4, e = makeXonoticPlayerList());
-                       me.rawPlayerList = e;
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns/2, e = makeXonoticButton(_("Close"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-               //me.TD(me, 1, me.columns/3, e = makeXonoticButton("", '0 0 0')); // TODO: Add bookmark button here
-               //      e.onClick = ServerList_Favorite_Click;
-               //      e.onClickEntity = slist;
-               //      slist.favoriteButton = e;
-               me.TD(me, 1, me.columns/2, e = makeXonoticButton(_("Join!"), '0 0 0'));
-                       e.onClick = Join_Click;
-                       e.onClickEntity = me;
-}
-
-void Join_Click(entity btn, entity me)
-{
-       localcmd("connect ", me.currentServerCName, "\n");
-}
-
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc b/qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc
new file mode 100644 (file)
index 0000000..fa5e306
--- /dev/null
@@ -0,0 +1,345 @@
+#ifdef INTERFACE
+CLASS(XonoticServerInfoDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticServerInfoDialog, fill, void(entity))
+       METHOD(XonoticServerInfoDialog, loadServerInfo, void(entity, float))
+       ATTRIB(XonoticServerInfoDialog, title, string, _("Server Information"))
+       ATTRIB(XonoticServerInfoDialog, color, vector, SKINCOLOR_DIALOG_SERVERINFO)
+       ATTRIB(XonoticServerInfoDialog, intendedWidth, float, 0.8)
+       ATTRIB(XonoticServerInfoDialog, rows, float, 18)
+       ATTRIB(XonoticServerInfoDialog, columns, float, 6.2)
+
+       ATTRIB(XonoticServerInfoDialog, currentServerName, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerCName, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerType, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerMap, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerPlayers, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerNumPlayers, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerNumBots, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerNumFreeSlots, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerMod, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerVersion, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerKey, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerID, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerEncrypt, string, string_null)
+       ATTRIB(XonoticServerInfoDialog, currentServerPure, string, string_null)
+
+       ATTRIB(XonoticServerInfoDialog, nameLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, cnameLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, typeLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, mapLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, rawPlayerList, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, numPlayersLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, numBotsLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, numFreeSlotsLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, modLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, versionLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, keyLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, idLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, encryptLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, canConnectLabel, entity, NULL)
+       ATTRIB(XonoticServerInfoDialog, pureLabel, entity, NULL)
+ENDCLASS(XonoticServerInfoDialog)
+
+void Join_Click(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticServerInfoDialog_loadServerInfo(entity me, float i)
+{
+       float m, pure, freeslots, j, numh, maxp, numb, sflags;
+       string s, typestr, versionstr, k, v, modname;
+
+       // ====================================
+       //  First clear and unzone the strings
+       // ====================================
+       if(me.currentServerName)
+               strunzone(me.currentServerName);
+       me.currentServerName = string_null;
+
+       if(me.currentServerCName)
+               strunzone(me.currentServerCName);
+       me.currentServerCName = string_null;
+
+       if(me.currentServerType)
+               strunzone(me.currentServerType);
+       me.currentServerType = string_null;
+
+       if(me.currentServerMap)
+               strunzone(me.currentServerMap);
+       me.currentServerMap = string_null;
+
+       if(me.currentServerPlayers)
+               strunzone(me.currentServerPlayers);
+       me.currentServerPlayers = string_null;
+
+       if(me.currentServerNumPlayers)
+               strunzone(me.currentServerNumPlayers);
+       me.currentServerNumPlayers = string_null;
+
+       if(me.currentServerNumBots)
+               strunzone(me.currentServerNumBots);
+       me.currentServerNumBots = string_null;
+
+       if(me.currentServerNumFreeSlots)
+               strunzone(me.currentServerNumFreeSlots);
+       me.currentServerNumFreeSlots = string_null;
+
+       if(me.currentServerMod)
+               strunzone(me.currentServerMod);
+       me.currentServerMod = string_null;
+
+       if(me.currentServerVersion)
+               strunzone(me.currentServerVersion);
+       me.currentServerVersion = string_null;
+
+       // not zoned!
+       //if(me.currentServerEncrypt)
+       //      strunzone(me.currentServerEncrypt);
+       //me.currentServerEncrypt = string_null;
+       if(me.currentServerPure)
+               strunzone(me.currentServerPure);
+       me.currentServerPure = string_null;
+
+       if(me.currentServerKey)
+               strunzone(me.currentServerKey);
+       me.currentServerKey = string_null;
+
+       if(me.currentServerID)
+               strunzone(me.currentServerID);
+       me.currentServerID = string_null;
+
+       // ==========================
+       //  Now, fill in the strings
+       // ==========================
+       me.currentServerName = strzone(gethostcachestring(SLIST_FIELD_NAME, i));
+       me.nameLabel.setText(me.nameLabel, me.currentServerName);
+
+       me.currentServerCName = strzone(gethostcachestring(SLIST_FIELD_CNAME, i));
+       me.cnameLabel.setText(me.cnameLabel, me.currentServerCName);
+
+       pure = -1;
+       typestr = _("N/A");
+       versionstr = _("N/A");
+
+       s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
+       m = tokenizebyseparator(s, ":");
+       if(m >= 2)
+       {
+               typestr = argv(0);
+               versionstr = argv(1);
+       }
+       freeslots = -1;
+       sflags = -1;
+       modname = "";
+       for(j = 2; j < m; ++j)
+       {
+               if(argv(j) == "")
+                       break;
+               k = substring(argv(j), 0, 1);
+               v = substring(argv(j), 1, -1);
+               if(k == "P")
+                       pure = stof(v);
+               else if(k == "S")
+                       freeslots = stof(v);
+               else if(k == "F")
+                       sflags = stof(v);
+               else if(k == "M")
+                       modname = v;
+       }
+
+#ifdef COMPAT_NO_MOD_IS_XONOTIC
+       if(modname == "")
+               modname = "Xonotic";
+#endif
+
+       s = gethostcachestring(SLIST_FIELD_MOD, i);
+       if(s != "data")
+               modname = sprintf("%s (%s)", modname, s);
+
+       j = MapInfo_Type_FromString(typestr); // try and get the real name of the game type
+       if(j) { typestr = MapInfo_Type_ToText(j); } // only set it if we actually found it
+
+       me.currentServerType = strzone(typestr);
+       me.typeLabel.setText(me.typeLabel, me.currentServerType);
+
+       me.currentServerMap = strzone(gethostcachestring(SLIST_FIELD_MAP, i));
+       me.mapLabel.setText(me.mapLabel, me.currentServerMap);
+
+       me.currentServerPlayers = strzone(gethostcachestring(SLIST_FIELD_PLAYERS, i));
+       me.rawPlayerList.setPlayerList(me.rawPlayerList, me.currentServerPlayers);
+
+       numh = gethostcachenumber(SLIST_FIELD_NUMHUMANS, i);
+       maxp = gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i);
+       numb = gethostcachenumber(SLIST_FIELD_NUMBOTS, i);
+       me.currentServerNumPlayers = strzone(sprintf("%d/%d", numh, maxp));
+       me.numPlayersLabel.setText(me.numPlayersLabel, me.currentServerNumPlayers);
+
+       s = ftos(numb);
+       me.currentServerNumBots = strzone(s);
+       me.numBotsLabel.setText(me.numBotsLabel, me.currentServerNumBots);
+
+       if(freeslots < 0) { freeslots = maxp - numh - numb; }
+       s = ftos(freeslots);
+       me.currentServerNumFreeSlots = strzone(s);
+       me.numFreeSlotsLabel.setText(me.numFreeSlotsLabel, me.currentServerNumFreeSlots);
+
+       me.currentServerMod = ((modname == "Xonotic") ? _("Default") : modname);
+       me.currentServerMod = strzone(me.currentServerMod);
+       me.modLabel.setText(me.modLabel, me.currentServerMod);
+
+       me.currentServerVersion = strzone(versionstr);
+       me.versionLabel.setText(me.versionLabel, me.currentServerVersion);
+
+       me.currentServerPure = ((pure < 0) ? _("N/A") : (pure == 0) ? _("Official") : sprintf(_("%d modified"), pure));
+       me.currentServerPure = strzone(me.currentServerPure);
+       me.pureLabel.setText(me.pureLabel, me.currentServerPure);
+
+       s = crypto_getencryptlevel(me.currentServerCName);
+       if(s == "")
+       {
+               if(cvar("crypto_aeslevel") >= 3)
+                       me.currentServerEncrypt = _("N/A (auth library missing, can't connect)");
+               else
+                       me.currentServerEncrypt = _("N/A (auth library missing)");
+       }
+       else switch(stof(substring(s, 0, 1)))
+       {
+               case 0:
+                       if(cvar("crypto_aeslevel") >= 3)
+                               me.currentServerEncrypt = _("Not supported (can't connect)");
+                       else
+                               me.currentServerEncrypt = _("Not supported (won't encrypt)");
+                       break;
+               case 1:
+                       if(cvar("crypto_aeslevel") >= 2)
+                               me.currentServerEncrypt = _("Supported (will encrypt)");
+                       else
+                               me.currentServerEncrypt = _("Supported (won't encrypt)");
+                       break;
+               case 2:
+                       if(cvar("crypto_aeslevel") >= 1)
+                               me.currentServerEncrypt = _("Requested (will encrypt)");
+                       else
+                               me.currentServerEncrypt = _("Requested (won't encrypt)");
+                       break;
+               case 3:
+                       if(cvar("crypto_aeslevel") <= 0)
+                               me.currentServerEncrypt = _("Required (can't connect)");
+                       else
+                               me.currentServerEncrypt = _("Required (will encrypt)");
+                       break;
+       }
+       me.encryptLabel.setText(me.encryptLabel, me.currentServerEncrypt);
+
+       s = crypto_getidfp(me.currentServerCName);
+       if (!s) { s = _("N/A"); }
+       me.currentServerID = strzone(s);
+       me.idLabel.setText(me.idLabel, me.currentServerID);
+
+       s = crypto_getkeyfp(me.currentServerCName);
+       if (!s) { s = _("N/A"); }
+       me.currentServerKey = strzone(s);
+       me.keyLabel.setText(me.keyLabel, me.currentServerKey);
+}
+
+void XonoticServerInfoDialog_fill(entity me)
+{
+       entity e;
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Hostname:")));
+               me.TD(me, 1, 4.6, e = makeXonoticTextLabel(0.5, ""));
+               e.colorL = SKINCOLOR_SERVERINFO_NAME;
+               e.allowCut = 1;
+               me.nameLabel = e;
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Address:")));
+               me.TD(me, 1, 4.6, e = makeXonoticTextLabel(0.5, ""));
+               e.colorL = SKINCOLOR_SERVERINFO_IP;
+               e.allowCut = 1;
+               me.cnameLabel = e;
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Gametype:")));
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
+               e.allowCut = 1;
+               me.typeLabel = e;
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Map:")));
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
+               e.allowCut = 1;
+               me.mapLabel = e;
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Mod:")));
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
+               e.allowCut = 1;
+               me.modLabel = e;
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Version:")));
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
+               e.allowCut = 1;
+               me.versionLabel = e;
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Settings:")));
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
+               e.allowCut = 1;
+               me.pureLabel = e;
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Players:")));
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
+               e.allowCut = 1;
+               me.numPlayersLabel = e;
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Bots:")));
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
+               e.allowCut = 1;
+               me.numBotsLabel = e;
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Free slots:")));
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, ""));
+               e.allowCut = 1;
+               me.numFreeSlotsLabel = e;
+
+       me.gotoRC(me, me.rows - 5, 0);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Encryption:")));
+               me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, ""));
+                       e.allowCut = 1;
+                       me.encryptLabel = e;
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("ID:")));
+               me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, ""));
+                       e.allowCut = 1;
+                       me.keyLabel = e;
+       me.TR(me);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Key:")));
+               me.TD(me, 1, 5.4, e = makeXonoticTextLabel(0, ""));
+                       e.allowCut = 1;
+                       me.idLabel = e;
+
+       me.gotoRC(me, 2, 2.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Players:")));
+       me.TR(me);
+               me.TD(me, me.rows - 8, 4, e = makeXonoticPlayerList());
+                       me.rawPlayerList = e;
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns/2, e = makeXonoticButton(_("Close"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+               //me.TD(me, 1, me.columns/3, e = makeXonoticButton("", '0 0 0')); // TODO: Add bookmark button here
+               //      e.onClick = ServerList_Favorite_Click;
+               //      e.onClickEntity = slist;
+               //      slist.favoriteButton = e;
+               me.TD(me, 1, me.columns/2, e = makeXonoticButton(_("Join!"), '0 0 0'));
+                       e.onClick = Join_Click;
+                       e.onClickEntity = me;
+}
+
+void Join_Click(entity btn, entity me)
+{
+       localcmd("connect ", me.currentServerCName, "\n");
+}
+
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media.c b/qcsrc/menu/xonotic/dialog_multiplayer_media.c
deleted file mode 100644 (file)
index a0b49b1..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticMediaTab) EXTENDS(XonoticTab)
-       METHOD(XonoticMediaTab, fill, void(entity))
-       ATTRIB(XonoticMediaTab, title, string, _("Media"))
-       ATTRIB(XonoticMediaTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticMediaTab, rows, float, 23)
-       ATTRIB(XonoticMediaTab, columns, float, 3)
-       ATTRIB(XonoticMediaTab, name, string, "Media")  
-ENDCLASS(XonoticMediaTab)
-entity makeXonoticMediaTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticMediaTab()
-{
-       entity me;
-       me = spawnXonoticMediaTab();
-       me.configureDialog(me);
-       return me;
-}
-void XonoticMediaTab_fill(entity me)
-{
-       entity mc, e;
-       mc = makeXonoticTabController(me.rows - 2);
-
-       me.gotoRC(me, 0.5, 0);
-               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Demos"), makeXonoticDemoBrowserTab()));
-               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Screenshots"), makeXonoticScreenshotBrowserTab()));
-               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Music Player"), makeXonoticMusicPlayerTab()));
-
-       me.gotoRC(me, 3, 0);
-               me.TD(me, me.rows - 2, me.columns, mc);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media.qc b/qcsrc/menu/xonotic/dialog_multiplayer_media.qc
new file mode 100644 (file)
index 0000000..a0b49b1
--- /dev/null
@@ -0,0 +1,34 @@
+#ifdef INTERFACE
+CLASS(XonoticMediaTab) EXTENDS(XonoticTab)
+       METHOD(XonoticMediaTab, fill, void(entity))
+       ATTRIB(XonoticMediaTab, title, string, _("Media"))
+       ATTRIB(XonoticMediaTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticMediaTab, rows, float, 23)
+       ATTRIB(XonoticMediaTab, columns, float, 3)
+       ATTRIB(XonoticMediaTab, name, string, "Media")  
+ENDCLASS(XonoticMediaTab)
+entity makeXonoticMediaTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticMediaTab()
+{
+       entity me;
+       me = spawnXonoticMediaTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticMediaTab_fill(entity me)
+{
+       entity mc, e;
+       mc = makeXonoticTabController(me.rows - 2);
+
+       me.gotoRC(me, 0.5, 0);
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Demos"), makeXonoticDemoBrowserTab()));
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Screenshots"), makeXonoticScreenshotBrowserTab()));
+               me.TD(me, 1, 1, e = mc.makeTabButton(mc, _("Music Player"), makeXonoticMusicPlayerTab()));
+
+       me.gotoRC(me, 3, 0);
+               me.TD(me, me.rows - 2, me.columns, mc);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_demo.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo.c
deleted file mode 100644 (file)
index 0923551..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticDemoBrowserTab) EXTENDS(XonoticTab)
-       METHOD(XonoticDemoBrowserTab, fill, void(entity))
-       ATTRIB(XonoticDemoBrowserTab, title, string, _("Demo"))
-       ATTRIB(XonoticDemoBrowserTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticDemoBrowserTab, rows, float, 21)
-       ATTRIB(XonoticDemoBrowserTab, columns, float, 6.5)
-       ATTRIB(XonoticDemoBrowserTab, name, string, "DemoBrowser")
-       ATTRIB(XonoticDemoBrowserTab, democlicktype, float, 0)
-ENDCLASS(XonoticDemoBrowserTab)
-entity makeXonoticDemoBrowserTab();
-const float DMO_PLAY = 1;
-const float DMO_TIME = 2;
-#endif
-
-#ifdef IMPLEMENTATION
-void DemoConfirm_Check_Gamestatus(entity btn, entity me)
-{
-       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, lets watch the demo
-       {
-               if(btn.democlicktype == DMO_PLAY)
-                       { demolist.startDemo(demolist); }
-               else if(btn.democlicktype == DMO_TIME)
-                       { demolist.timeDemo(demolist); }
-       }
-       else // already in a match, player has to confirm
-       {
-               if(btn.democlicktype == DMO_PLAY)
-                       { DialogOpenButton_Click(btn, main.demostartconfirmDialog); }
-               else if(btn.democlicktype == DMO_TIME)
-                       { DialogOpenButton_Click(btn, main.demotimeconfirmDialog); }
-       }
-}
-
-entity makeXonoticDemoBrowserTab()
-{
-       entity me;
-       me = spawnXonoticDemoBrowserTab();
-       me.configureDialog(me);
-       return me;
-}
-void XonoticDemoBrowserTab_fill(entity me)
-{
-       entity e;
-       demolist = makeXonoticDemoList();
-
-       me.TR(me);
-               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
-               me.TD(me, 1, 2.9, e = makeXonoticInputBox(0, string_null));
-                       e.onChange = DemoList_Filter_Change;
-                       e.onChangeEntity = demolist;
-                       demolist.controlledTextbox = e;
-
-       me.gotoRC(me, 0, 3.7);
-               me.TD(me, 1, 1.5, e = makeXonoticCheckBox(0, "cl_autodemo", _("Auto record demos")));
-               me.TD(me, 1, 1, e = makeXonoticButton(_("Refresh"), '0 0 0'));
-                       e.onClick = DemoList_Refresh_Click;
-                       e.onClickEntity = demolist;
-
-       me.gotoRC(me, 1.5, 0);
-               me.TD(me, me.rows - 2.5, me.columns, demolist);
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(_("Timedemo"), '0 0 0'));
-                       e.democlicktype = DMO_TIME;
-                       e.onClick = DemoConfirm_Check_Gamestatus;
-                       e.onClickEntity = me; // demolist is global anyway
-               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(ZCTX(_("DEMO^Play")), '0 0 0'));
-                       e.democlicktype = DMO_PLAY;
-                       e.onClick = DemoConfirm_Check_Gamestatus;
-                       e.onClickEntity = me; // demolist is global anyway
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc
new file mode 100644 (file)
index 0000000..0923551
--- /dev/null
@@ -0,0 +1,73 @@
+#ifdef INTERFACE
+CLASS(XonoticDemoBrowserTab) EXTENDS(XonoticTab)
+       METHOD(XonoticDemoBrowserTab, fill, void(entity))
+       ATTRIB(XonoticDemoBrowserTab, title, string, _("Demo"))
+       ATTRIB(XonoticDemoBrowserTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticDemoBrowserTab, rows, float, 21)
+       ATTRIB(XonoticDemoBrowserTab, columns, float, 6.5)
+       ATTRIB(XonoticDemoBrowserTab, name, string, "DemoBrowser")
+       ATTRIB(XonoticDemoBrowserTab, democlicktype, float, 0)
+ENDCLASS(XonoticDemoBrowserTab)
+entity makeXonoticDemoBrowserTab();
+const float DMO_PLAY = 1;
+const float DMO_TIME = 2;
+#endif
+
+#ifdef IMPLEMENTATION
+void DemoConfirm_Check_Gamestatus(entity btn, entity me)
+{
+       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, lets watch the demo
+       {
+               if(btn.democlicktype == DMO_PLAY)
+                       { demolist.startDemo(demolist); }
+               else if(btn.democlicktype == DMO_TIME)
+                       { demolist.timeDemo(demolist); }
+       }
+       else // already in a match, player has to confirm
+       {
+               if(btn.democlicktype == DMO_PLAY)
+                       { DialogOpenButton_Click(btn, main.demostartconfirmDialog); }
+               else if(btn.democlicktype == DMO_TIME)
+                       { DialogOpenButton_Click(btn, main.demotimeconfirmDialog); }
+       }
+}
+
+entity makeXonoticDemoBrowserTab()
+{
+       entity me;
+       me = spawnXonoticDemoBrowserTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticDemoBrowserTab_fill(entity me)
+{
+       entity e;
+       demolist = makeXonoticDemoList();
+
+       me.TR(me);
+               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
+               me.TD(me, 1, 2.9, e = makeXonoticInputBox(0, string_null));
+                       e.onChange = DemoList_Filter_Change;
+                       e.onChangeEntity = demolist;
+                       demolist.controlledTextbox = e;
+
+       me.gotoRC(me, 0, 3.7);
+               me.TD(me, 1, 1.5, e = makeXonoticCheckBox(0, "cl_autodemo", _("Auto record demos")));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Refresh"), '0 0 0'));
+                       e.onClick = DemoList_Refresh_Click;
+                       e.onClickEntity = demolist;
+
+       me.gotoRC(me, 1.5, 0);
+               me.TD(me, me.rows - 2.5, me.columns, demolist);
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(_("Timedemo"), '0 0 0'));
+                       e.democlicktype = DMO_TIME;
+                       e.onClick = DemoConfirm_Check_Gamestatus;
+                       e.onClickEntity = me; // demolist is global anyway
+               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(ZCTX(_("DEMO^Play")), '0 0 0'));
+                       e.democlicktype = DMO_PLAY;
+                       e.onClick = DemoConfirm_Check_Gamestatus;
+                       e.onClickEntity = me; // demolist is global anyway
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.c
deleted file mode 100644 (file)
index a5a97c5..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticDemoStartConfirmDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticDemoStartConfirmDialog, fill, void(entity))
-       ATTRIB(XonoticDemoStartConfirmDialog, title, string, _("Disconnect"))
-       ATTRIB(XonoticDemoStartConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
-       ATTRIB(XonoticDemoStartConfirmDialog, intendedWidth, float, 0.5)
-       ATTRIB(XonoticDemoStartConfirmDialog, rows, float, 4)
-       ATTRIB(XonoticDemoStartConfirmDialog, columns, float, 2)
-ENDCLASS(XonoticDemoStartConfirmDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void Handle_StartDemo_Click(entity unused, entity me) { demolist.startDemo(demolist); }
-void XonoticDemoStartConfirmDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Playing a demo will disconnect you from the current match.")));
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you really wish to disconnect now?")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^Yes")), '1 0 0'));
-                       e.onClick = Handle_StartDemo_Click;
-                       e.onClickEntity = demolist;
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^No")), '0 1 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc
new file mode 100644 (file)
index 0000000..a5a97c5
--- /dev/null
@@ -0,0 +1,31 @@
+#ifdef INTERFACE
+CLASS(XonoticDemoStartConfirmDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticDemoStartConfirmDialog, fill, void(entity))
+       ATTRIB(XonoticDemoStartConfirmDialog, title, string, _("Disconnect"))
+       ATTRIB(XonoticDemoStartConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
+       ATTRIB(XonoticDemoStartConfirmDialog, intendedWidth, float, 0.5)
+       ATTRIB(XonoticDemoStartConfirmDialog, rows, float, 4)
+       ATTRIB(XonoticDemoStartConfirmDialog, columns, float, 2)
+ENDCLASS(XonoticDemoStartConfirmDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void Handle_StartDemo_Click(entity unused, entity me) { demolist.startDemo(demolist); }
+void XonoticDemoStartConfirmDialog_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Playing a demo will disconnect you from the current match.")));
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you really wish to disconnect now?")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^Yes")), '1 0 0'));
+                       e.onClick = Handle_StartDemo_Click;
+                       e.onClickEntity = demolist;
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^No")), '0 1 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.c
deleted file mode 100644 (file)
index 5510710..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticDemoTimeConfirmDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticDemoTimeConfirmDialog, fill, void(entity))
-       ATTRIB(XonoticDemoTimeConfirmDialog, title, string, _("Disconnect"))
-       ATTRIB(XonoticDemoTimeConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
-       ATTRIB(XonoticDemoTimeConfirmDialog, intendedWidth, float, 0.5)
-       ATTRIB(XonoticDemoTimeConfirmDialog, rows, float, 4)
-       ATTRIB(XonoticDemoTimeConfirmDialog, columns, float, 2)
-ENDCLASS(XonoticDemoTimeConfirmDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void Handle_TimeDemo_Click(entity unused, entity unused) { demolist.timeDemo(demolist); }
-void XonoticDemoTimeConfirmDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Timing a demo will disconnect you from the current match.")));
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you really wish to disconnect now?")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^Yes")), '1 0 0'));
-                       e.onClick = Handle_TimeDemo_Click;
-                       e.onClickEntity = demolist;
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^No")), '0 1 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc b/qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc
new file mode 100644 (file)
index 0000000..5510710
--- /dev/null
@@ -0,0 +1,31 @@
+#ifdef INTERFACE
+CLASS(XonoticDemoTimeConfirmDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticDemoTimeConfirmDialog, fill, void(entity))
+       ATTRIB(XonoticDemoTimeConfirmDialog, title, string, _("Disconnect"))
+       ATTRIB(XonoticDemoTimeConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
+       ATTRIB(XonoticDemoTimeConfirmDialog, intendedWidth, float, 0.5)
+       ATTRIB(XonoticDemoTimeConfirmDialog, rows, float, 4)
+       ATTRIB(XonoticDemoTimeConfirmDialog, columns, float, 2)
+ENDCLASS(XonoticDemoTimeConfirmDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void Handle_TimeDemo_Click(entity unused, entity unused) { demolist.timeDemo(demolist); }
+void XonoticDemoTimeConfirmDialog_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Timing a demo will disconnect you from the current match.")));
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you really wish to disconnect now?")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^Yes")), '1 0 0'));
+                       e.onClick = Handle_TimeDemo_Click;
+                       e.onClickEntity = demolist;
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("DMCNFRM^No")), '0 1 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.c
deleted file mode 100644 (file)
index 0b7e423..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticMusicPlayerTab) EXTENDS(XonoticTab)
-       METHOD(XonoticMusicPlayerTab, fill, void(entity))
-       ATTRIB(XonoticMusicPlayerTab, title, string, _("Music"))
-       ATTRIB(XonoticMusicPlayerTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticMusicPlayerTab, rows, float, 21)
-       ATTRIB(XonoticMusicPlayerTab, columns, float, 6.5)
-       ATTRIB(XonoticMusicPlayerTab, name, string, "MusicPlayer")
-ENDCLASS(XonoticMusicPlayerTab)
-entity makeXonoticMusicPlayerTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticMusicPlayerTab()
-{
-       entity me;
-       me = spawnXonoticMusicPlayerTab();
-       me.configureDialog(me);
-       return me;
-}
-void XonoticMusicPlayerTab_fill(entity me)
-{
-       entity e;
-       entity soundList, playList;
-       float columns_nospacing = (me.columns - 0.2);
-
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticTextLabel(0, _("Filter:")));
-               me.TD(me, 1, 2.5, e = makeXonoticInputBox(0, string_null));
-                       soundList = makeXonoticSoundList();
-                       e.onChange = SoundList_Filter_Change;
-                       e.onChangeEntity = soundList;
-                       soundList.controlledTextbox = e;
-                       playList = makeXonoticPlayList();
-                       soundList.playlist = playList;
-
-       me.TR(me);
-               me.TD(me, me.rows - 4, columns_nospacing / 2, soundList);
-
-       me.gotoRC(me, me.rows - 3, 0);
-               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticButton(ZCTX(_("MUSICPL^Add")), '0 0 0'));
-                       e.onClick = SoundList_Add;
-                       e.onClickEntity = soundList;
-               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticButton(ZCTX(_("MUSICPL^Add all")), '0 0 0'));
-                       e.onClick = SoundList_Add_All;
-                       e.onClickEntity = soundList;
-       me.TR(me);
-               me.TD(me, 1, columns_nospacing / 2, e = makeXonoticButton(_("Set as menu track"), '0 0 0'));
-                       e.onClick = SoundList_Menu_Track_Change;
-                       e.onClickEntity = soundList;
-       me.TR(me);
-               me.TD(me, 1, columns_nospacing / 2, e = makeXonoticButton(_("Reset default menu track"), '0 0 0'));
-                       e.onClick = SoundList_Menu_Track_Reset;
-                       e.onClickEntity = soundList;
-       me.TR(me);
-       me.TR(me);
-       me.gotoRC(me, 0, columns_nospacing / 2 + 0.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticTextLabel(0, _("Playlist:")));
-               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticCheckBox(0, "music_playlist_random0", _("Random order")));
-       me.TR(me);
-               me.TD(me, me.rows - 3, columns_nospacing / 2, playList);
-
-       me.gotoRC(me, me.rows - 2, columns_nospacing / 2 + 0.2);
-               me.TD(me, 1, columns_nospacing / 10, e = makeXonoticButton(ZCTX(_("MUSICPL^Stop")), '0 0 0'));
-                       e.onClick = StopSound_Click;
-                       e.onClickEntity = playList;
-               me.TD(me, 1, columns_nospacing / 10, e = makeXonoticButton(ZCTX(_("MUSICPL^Play")), '0 0 0'));
-                       e.onClick = StartSound_Click;
-                       e.onClickEntity = playList;
-               me.TD(me, 1, columns_nospacing / 10, e = makeXonoticButton(ZCTX(_("MUSICPL^Pause")), '0 0 0'));
-                       e.onClick = PauseSound_Click;
-                       e.onClickEntity = playList;
-               me.TD(me, 1, columns_nospacing / 10, e = makeXonoticButton(ZCTX(_("MUSICPL^Prev")), '0 0 0'));
-                       e.onClick = PrevSound_Click;
-                       e.onClickEntity = playList;
-               me.TD(me, 1, columns_nospacing / 10, e = makeXonoticButton(ZCTX(_("MUSICPL^Next")), '0 0 0'));
-                       e.onClick = NextSound_Click;
-                       e.onClickEntity = playList;
-       me.TR(me);
-               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticButton(ZCTX(_("MUSICPL^Remove")), '0 0 0'));
-                       e.onClick = PlayList_Remove;
-                       e.onClickEntity = playList;
-               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticButton(ZCTX(_("MUSICPL^Remove all")), '0 0 0'));
-                       e.onClick = PlayList_Remove_All;
-                       e.onClickEntity = playList;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc b/qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc
new file mode 100644 (file)
index 0000000..0b7e423
--- /dev/null
@@ -0,0 +1,87 @@
+#ifdef INTERFACE
+CLASS(XonoticMusicPlayerTab) EXTENDS(XonoticTab)
+       METHOD(XonoticMusicPlayerTab, fill, void(entity))
+       ATTRIB(XonoticMusicPlayerTab, title, string, _("Music"))
+       ATTRIB(XonoticMusicPlayerTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticMusicPlayerTab, rows, float, 21)
+       ATTRIB(XonoticMusicPlayerTab, columns, float, 6.5)
+       ATTRIB(XonoticMusicPlayerTab, name, string, "MusicPlayer")
+ENDCLASS(XonoticMusicPlayerTab)
+entity makeXonoticMusicPlayerTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticMusicPlayerTab()
+{
+       entity me;
+       me = spawnXonoticMusicPlayerTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticMusicPlayerTab_fill(entity me)
+{
+       entity e;
+       entity soundList, playList;
+       float columns_nospacing = (me.columns - 0.2);
+
+       me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticTextLabel(0, _("Filter:")));
+               me.TD(me, 1, 2.5, e = makeXonoticInputBox(0, string_null));
+                       soundList = makeXonoticSoundList();
+                       e.onChange = SoundList_Filter_Change;
+                       e.onChangeEntity = soundList;
+                       soundList.controlledTextbox = e;
+                       playList = makeXonoticPlayList();
+                       soundList.playlist = playList;
+
+       me.TR(me);
+               me.TD(me, me.rows - 4, columns_nospacing / 2, soundList);
+
+       me.gotoRC(me, me.rows - 3, 0);
+               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticButton(ZCTX(_("MUSICPL^Add")), '0 0 0'));
+                       e.onClick = SoundList_Add;
+                       e.onClickEntity = soundList;
+               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticButton(ZCTX(_("MUSICPL^Add all")), '0 0 0'));
+                       e.onClick = SoundList_Add_All;
+                       e.onClickEntity = soundList;
+       me.TR(me);
+               me.TD(me, 1, columns_nospacing / 2, e = makeXonoticButton(_("Set as menu track"), '0 0 0'));
+                       e.onClick = SoundList_Menu_Track_Change;
+                       e.onClickEntity = soundList;
+       me.TR(me);
+               me.TD(me, 1, columns_nospacing / 2, e = makeXonoticButton(_("Reset default menu track"), '0 0 0'));
+                       e.onClick = SoundList_Menu_Track_Reset;
+                       e.onClickEntity = soundList;
+       me.TR(me);
+       me.TR(me);
+       me.gotoRC(me, 0, columns_nospacing / 2 + 0.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticTextLabel(0, _("Playlist:")));
+               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticCheckBox(0, "music_playlist_random0", _("Random order")));
+       me.TR(me);
+               me.TD(me, me.rows - 3, columns_nospacing / 2, playList);
+
+       me.gotoRC(me, me.rows - 2, columns_nospacing / 2 + 0.2);
+               me.TD(me, 1, columns_nospacing / 10, e = makeXonoticButton(ZCTX(_("MUSICPL^Stop")), '0 0 0'));
+                       e.onClick = StopSound_Click;
+                       e.onClickEntity = playList;
+               me.TD(me, 1, columns_nospacing / 10, e = makeXonoticButton(ZCTX(_("MUSICPL^Play")), '0 0 0'));
+                       e.onClick = StartSound_Click;
+                       e.onClickEntity = playList;
+               me.TD(me, 1, columns_nospacing / 10, e = makeXonoticButton(ZCTX(_("MUSICPL^Pause")), '0 0 0'));
+                       e.onClick = PauseSound_Click;
+                       e.onClickEntity = playList;
+               me.TD(me, 1, columns_nospacing / 10, e = makeXonoticButton(ZCTX(_("MUSICPL^Prev")), '0 0 0'));
+                       e.onClick = PrevSound_Click;
+                       e.onClickEntity = playList;
+               me.TD(me, 1, columns_nospacing / 10, e = makeXonoticButton(ZCTX(_("MUSICPL^Next")), '0 0 0'));
+                       e.onClick = NextSound_Click;
+                       e.onClickEntity = playList;
+       me.TR(me);
+               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticButton(ZCTX(_("MUSICPL^Remove")), '0 0 0'));
+                       e.onClick = PlayList_Remove;
+                       e.onClickEntity = playList;
+               me.TD(me, 1, columns_nospacing / 4, e = makeXonoticButton(ZCTX(_("MUSICPL^Remove all")), '0 0 0'));
+                       e.onClick = PlayList_Remove_All;
+                       e.onClickEntity = playList;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.c
deleted file mode 100644 (file)
index 6132719..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticScreenshotBrowserTab) EXTENDS(XonoticTab)
-       METHOD(XonoticScreenshotBrowserTab, fill, void(entity))
-       ATTRIB(XonoticScreenshotBrowserTab, title, string, "Screenshot")
-       ATTRIB(XonoticScreenshotBrowserTab, intendedWidth, float, 1)
-       ATTRIB(XonoticScreenshotBrowserTab, rows, float, 21)
-       ATTRIB(XonoticScreenshotBrowserTab, columns, float, 6.5)
-       ATTRIB(XonoticScreenshotBrowserTab, name, string, "ScreenshotBrowser")
-       
-       METHOD(XonoticScreenshotBrowserTab, loadPreviewScreenshot, void(entity, string))
-       ATTRIB(XonoticScreenshotBrowserTab, screenshotImage, entity, NULL)
-       ATTRIB(XonoticScreenshotBrowserTab, currentScrPath, string, string_null)
-ENDCLASS(XonoticScreenshotBrowserTab)
-entity makeXonoticScreenshotBrowserTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticScreenshotBrowserTab()
-{
-       entity me;
-       me = spawnXonoticScreenshotBrowserTab();
-       me.configureDialog(me);
-       return me;
-}
-void XonoticScreenshotBrowserTab_loadPreviewScreenshot(entity me, string scrImage)
-{
-       if (me.currentScrPath == scrImage)
-               return;
-       if (me.currentScrPath)
-               strunzone(me.currentScrPath);
-       me.currentScrPath = strzone(scrImage);
-       me.screenshotImage.load(me.screenshotImage, me.currentScrPath);
-}
-void XonoticScreenshotBrowserTab_fill(entity me)
-{
-       entity e, slist;
-       slist = makeXonoticScreenshotList();
-       float slist_height = me.rows - 2;
-
-
-       me.TR(me);
-               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
-               me.TD(me, 1, 2.4, e = makeXonoticInputBox(0, string_null));
-                       e.onChange = ScreenshotList_Filter_Would_Change;
-                       e.onChangeEntity = slist;
-                       slist.screenshotViewerDialog = main.screenshotViewerDialog;
-                       main.screenshotViewerDialog.scrList = slist;
-
-       me.gotoRC(me, 0, 3.1);
-               me.TD(me, 1, 1.9, e = makeXonoticCheckBoxEx(2, 1, "cl_autoscreenshot", _("Auto screenshot scoreboard")));
-               me.TD(me, 1, 1, e = makeXonoticButton(_("Refresh"), '0 0 0'));
-                       e.onClick = ScreenshotList_Refresh_Click;
-                       e.onClickEntity = slist;
-                       
-       /*me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticTextLabel(0, "Filter:"));
-               me.TD(me, 1, me.columns - 1.5, e = makeXonoticInputBox(0, string_null));
-                       e.onChange = ScreenshotList_Filter_Would_Change;
-                       e.onChangeEntity = slist;
-                       slist.screenshotViewerDialog = main.screenshotViewerDialog;
-                       main.screenshotViewerDialog.scrList = slist;
-               me.TD(me, 1, 1, e = makeXonoticButton(_("Refresh"), '0 0 0'));
-                       e.onClick = ScreenshotList_Refresh_Click;
-                       e.onClickEntity = slist;*/
-                       
-       me.gotoRC(me, 1.5, 0);
-               me.TD(me, me.rows - 2.5, me.columns, slist);
-
-       me.gotoRC(me, slist_height + 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("Open in the viewer"), '0 0 0'));
-                       e.onClick = StartScreenshot_Click;
-                       e.onClickEntity = slist;
-/*
-       me.TR(me);
-               me.TD(me, me.rows - me.currentRow, me.columns, e = makeXonoticScreenshotImage());
-                       e.showTitle = 0;
-                       me.screenshotImage = e;
-                       slist.screenshotPreview = e;
-                       slist.screenshotBrowserDialog = me;
-*/
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc b/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc
new file mode 100644 (file)
index 0000000..6132719
--- /dev/null
@@ -0,0 +1,82 @@
+#ifdef INTERFACE
+CLASS(XonoticScreenshotBrowserTab) EXTENDS(XonoticTab)
+       METHOD(XonoticScreenshotBrowserTab, fill, void(entity))
+       ATTRIB(XonoticScreenshotBrowserTab, title, string, "Screenshot")
+       ATTRIB(XonoticScreenshotBrowserTab, intendedWidth, float, 1)
+       ATTRIB(XonoticScreenshotBrowserTab, rows, float, 21)
+       ATTRIB(XonoticScreenshotBrowserTab, columns, float, 6.5)
+       ATTRIB(XonoticScreenshotBrowserTab, name, string, "ScreenshotBrowser")
+       
+       METHOD(XonoticScreenshotBrowserTab, loadPreviewScreenshot, void(entity, string))
+       ATTRIB(XonoticScreenshotBrowserTab, screenshotImage, entity, NULL)
+       ATTRIB(XonoticScreenshotBrowserTab, currentScrPath, string, string_null)
+ENDCLASS(XonoticScreenshotBrowserTab)
+entity makeXonoticScreenshotBrowserTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticScreenshotBrowserTab()
+{
+       entity me;
+       me = spawnXonoticScreenshotBrowserTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticScreenshotBrowserTab_loadPreviewScreenshot(entity me, string scrImage)
+{
+       if (me.currentScrPath == scrImage)
+               return;
+       if (me.currentScrPath)
+               strunzone(me.currentScrPath);
+       me.currentScrPath = strzone(scrImage);
+       me.screenshotImage.load(me.screenshotImage, me.currentScrPath);
+}
+void XonoticScreenshotBrowserTab_fill(entity me)
+{
+       entity e, slist;
+       slist = makeXonoticScreenshotList();
+       float slist_height = me.rows - 2;
+
+
+       me.TR(me);
+               me.TD(me, 1, 0.6, e = makeXonoticTextLabel(1, _("Filter:")));
+               me.TD(me, 1, 2.4, e = makeXonoticInputBox(0, string_null));
+                       e.onChange = ScreenshotList_Filter_Would_Change;
+                       e.onChangeEntity = slist;
+                       slist.screenshotViewerDialog = main.screenshotViewerDialog;
+                       main.screenshotViewerDialog.scrList = slist;
+
+       me.gotoRC(me, 0, 3.1);
+               me.TD(me, 1, 1.9, e = makeXonoticCheckBoxEx(2, 1, "cl_autoscreenshot", _("Auto screenshot scoreboard")));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Refresh"), '0 0 0'));
+                       e.onClick = ScreenshotList_Refresh_Click;
+                       e.onClickEntity = slist;
+                       
+       /*me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticTextLabel(0, "Filter:"));
+               me.TD(me, 1, me.columns - 1.5, e = makeXonoticInputBox(0, string_null));
+                       e.onChange = ScreenshotList_Filter_Would_Change;
+                       e.onChangeEntity = slist;
+                       slist.screenshotViewerDialog = main.screenshotViewerDialog;
+                       main.screenshotViewerDialog.scrList = slist;
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Refresh"), '0 0 0'));
+                       e.onClick = ScreenshotList_Refresh_Click;
+                       e.onClickEntity = slist;*/
+                       
+       me.gotoRC(me, 1.5, 0);
+               me.TD(me, me.rows - 2.5, me.columns, slist);
+
+       me.gotoRC(me, slist_height + 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("Open in the viewer"), '0 0 0'));
+                       e.onClick = StartScreenshot_Click;
+                       e.onClickEntity = slist;
+/*
+       me.TR(me);
+               me.TD(me, me.rows - me.currentRow, me.columns, e = makeXonoticScreenshotImage());
+                       e.showTitle = 0;
+                       me.screenshotImage = e;
+                       slist.screenshotPreview = e;
+                       slist.screenshotBrowserDialog = me;
+*/
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.c b/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.c
deleted file mode 100644 (file)
index 146f496..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticScreenshotViewerDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticScreenshotViewerDialog, fill, void(entity))
-       METHOD(XonoticScreenshotViewerDialog, keyDown, float(entity, float, float, float))
-       METHOD(XonoticScreenshotViewerDialog, loadScreenshot, void(entity, string))
-       METHOD(XonoticScreenshotViewerDialog, close, void(entity))
-       ATTRIB(XonoticScreenshotViewerDialog, title, string, "Screenshot Viewer")
-       ATTRIB(XonoticScreenshotViewerDialog, name, string, "ScreenshotViewer")
-       ATTRIB(XonoticScreenshotViewerDialog, intendedWidth, float, 1)
-       ATTRIB(XonoticScreenshotViewerDialog, rows, float, 25)
-       ATTRIB(XonoticScreenshotViewerDialog, columns, float, 4)
-       ATTRIB(XonoticScreenshotViewerDialog, color, vector, SKINCOLOR_DIALOG_SCREENSHOTVIEWER)
-       ATTRIB(XonoticScreenshotViewerDialog, scrList, entity, NULL)
-       ATTRIB(XonoticScreenshotViewerDialog, screenshotImage, entity, NULL)
-       ATTRIB(XonoticScreenshotViewerDialog, slideShowButton, entity, NULL)
-       ATTRIB(XonoticScreenshotViewerDialog, currentScrPath, string, string_null)
-ENDCLASS(XonoticScreenshotViewerDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-float music_playlist_index_backup;
-void XonoticScreenshotViewerDialog_loadScreenshot(entity me, string scrImage)
-{
-       // disable music as it can lag depending on image loading time
-       if(!cvar("menu_screenshotviewer_enablemusic"))
-       if(cvar("music_playlist_index") != 999) // if the playlist isn't paused
-       {
-               // pause music
-               if(cvar("music_playlist_index") != -1)
-               {
-                       music_playlist_index_backup = cvar("music_playlist_index");
-                       cvar_set("music_playlist_sampleposition0", "0");
-                       cvar_set("music_playlist_index", "999");
-               }
-               else
-                       localcmd("\ncd pause\n");
-       }
-
-       if (me.currentScrPath == scrImage)
-               return;
-       if (me.currentScrPath)
-               strunzone(me.currentScrPath);
-       me.currentScrPath = strzone(scrImage);
-       me.screenshotImage.load(me.screenshotImage, me.currentScrPath);
-       me.frame.setText(me.frame, me.screenshotImage.screenshotTitle);
-}
-void prevScreenshot_Click(entity btn, entity me)
-{
-       me.scrList.goScreenshot(me.scrList, -1);
-}
-void nextScreenshot_Click(entity btn, entity me)
-{
-       me.scrList.goScreenshot(me.scrList, +1);
-}
-void increaseZoom_Click(entity btn, entity me)
-{
-       me.screenshotImage.setZoom(me.screenshotImage, -2, FALSE);
-}
-void decreaseZoom_Click(entity btn, entity me)
-{
-       me.screenshotImage.setZoom(me.screenshotImage, -1/2, FALSE);
-}
-void resetZoom_Click(entity btn, entity me)
-{
-       me.screenshotImage.setZoom(me.screenshotImage, 0, FALSE);
-}
-void toggleSlideShow_Click(entity btn, entity me)
-{
-       if (me.slideShowButton.forcePressed)
-       {
-               me.scrList.stopSlideShow(me.scrList);
-               me.slideShowButton.forcePressed = 0;
-       }
-       else
-       {
-               me.scrList.startSlideShow(me.scrList);
-               me.slideShowButton.forcePressed = 1;
-       }
-}
-float XonoticScreenshotViewerDialog_keyDown(entity me, float key, float ascii, float shift)
-{
-       switch(key)
-       {
-               case K_KP_LEFTARROW:
-               case K_LEFTARROW:
-                       me.scrList.goScreenshot(me.scrList, -1);
-                       return 1;
-               case K_KP_RIGHTARROW:
-               case K_RIGHTARROW:
-                       me.scrList.goScreenshot(me.scrList, +1);
-                       return 1;
-               case K_KP_ENTER:
-               case K_ENTER:
-               case K_SPACE:
-                       // we cannot use SPACE/ENTER directly, as in a dialog they are needed
-                       // to press buttons while browsing with only the keyboard
-                       if (shift & S_CTRL)
-                       {
-                               toggleSlideShow_Click(world, me);
-                               return 1;
-                       }
-                       return SUPER(XonoticScreenshotViewerDialog).keyDown(me, key, ascii, shift);
-               default:
-                       if (key == K_MWHEELUP || ascii == '+')
-                       {
-                               me.screenshotImage.setZoom(me.screenshotImage, -2, (key == K_MWHEELUP));
-                               return 1;
-                       }
-                       else if (key == K_MWHEELDOWN || ascii == '-')
-                       {
-                               me.screenshotImage.setZoom(me.screenshotImage, -1/2, (key == K_MWHEELDOWN));
-                               return 1;
-                       }
-                       if (me.scrList.keyDown(me.scrList, key, ascii, shift))
-                       {
-                               // keyDown has already changed the selected item
-                               me.scrList.goScreenshot(me.scrList, 0);
-                               return 1;
-                       }
-                       return SUPER(XonoticScreenshotViewerDialog).keyDown(me, key, ascii, shift);
-       }
-}
-void XonoticScreenshotViewerDialog_close(entity me)
-{
-       // resume music
-       if(!cvar("menu_screenshotviewer_enablemusic"))
-       if(cvar("music_playlist_index") == 999)
-       {
-               cvar_set("music_playlist_index", ftos(music_playlist_index_backup));
-       }
-       else
-               localcmd("\ncd resume\n");
-
-       me.scrList.stopSlideShow(me.scrList);
-       me.slideShowButton.forcePressed = 0;
-       SUPER(XonoticScreenshotViewerDialog).close(me);
-}
-void XonoticScreenshotViewerDialog_fill(entity me)
-{
-       entity e;
-       me.TR(me);
-               me.TD(me, me.rows - 1, me.columns, e = makeXonoticScreenshotImage());
-                       e.showTitle = 0; // dialog title is enough
-                       me.screenshotImage = e;
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TDempty(me, 1/20 * me.columns);
-               me.TD(me, 1, 1/20 * me.columns, e = makeXonoticButton("-", '0 0 0'));
-                       e.onClick = decreaseZoom_Click;
-                       e.onClickEntity = me;
-               me.TD(me, 1, 1/20 * me.columns, e = makeXonoticButton("+", '0 0 0'));
-                       e.onClick = increaseZoom_Click;
-                       e.onClickEntity = me;
-               me.TD(me, 1, 2/20 * me.columns, e = makeXonoticButton(_("Reset"), '0 0 0'));
-                       e.onClick = resetZoom_Click;
-                       e.onClickEntity = me;
-
-               me.TDempty(me, 2/20 * me.columns);
-               me.TD(me, 1, 3/20 * me.columns, e = makeXonoticButton(_("Previous"), '0 0 0'));
-                       e.onClick = prevScreenshot_Click;
-                       e.onClickEntity = me;
-               me.TD(me, 1, 3/20 * me.columns, e = makeXonoticButton(_("Next"), '0 0 0'));
-                       e.onClick = nextScreenshot_Click;
-                       e.onClickEntity = me;
-
-               me.TDempty(me, 2/20 * me.columns);
-               me.TD(me, 1, 4/20 * me.columns, e = makeXonoticButton(_("Slide show"), '0 0 0'));
-                       e.onClick = toggleSlideShow_Click;
-                       e.onClickEntity = me;
-                       me.slideShowButton = e;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc b/qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc
new file mode 100644 (file)
index 0000000..146f496
--- /dev/null
@@ -0,0 +1,171 @@
+#ifdef INTERFACE
+CLASS(XonoticScreenshotViewerDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticScreenshotViewerDialog, fill, void(entity))
+       METHOD(XonoticScreenshotViewerDialog, keyDown, float(entity, float, float, float))
+       METHOD(XonoticScreenshotViewerDialog, loadScreenshot, void(entity, string))
+       METHOD(XonoticScreenshotViewerDialog, close, void(entity))
+       ATTRIB(XonoticScreenshotViewerDialog, title, string, "Screenshot Viewer")
+       ATTRIB(XonoticScreenshotViewerDialog, name, string, "ScreenshotViewer")
+       ATTRIB(XonoticScreenshotViewerDialog, intendedWidth, float, 1)
+       ATTRIB(XonoticScreenshotViewerDialog, rows, float, 25)
+       ATTRIB(XonoticScreenshotViewerDialog, columns, float, 4)
+       ATTRIB(XonoticScreenshotViewerDialog, color, vector, SKINCOLOR_DIALOG_SCREENSHOTVIEWER)
+       ATTRIB(XonoticScreenshotViewerDialog, scrList, entity, NULL)
+       ATTRIB(XonoticScreenshotViewerDialog, screenshotImage, entity, NULL)
+       ATTRIB(XonoticScreenshotViewerDialog, slideShowButton, entity, NULL)
+       ATTRIB(XonoticScreenshotViewerDialog, currentScrPath, string, string_null)
+ENDCLASS(XonoticScreenshotViewerDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+float music_playlist_index_backup;
+void XonoticScreenshotViewerDialog_loadScreenshot(entity me, string scrImage)
+{
+       // disable music as it can lag depending on image loading time
+       if(!cvar("menu_screenshotviewer_enablemusic"))
+       if(cvar("music_playlist_index") != 999) // if the playlist isn't paused
+       {
+               // pause music
+               if(cvar("music_playlist_index") != -1)
+               {
+                       music_playlist_index_backup = cvar("music_playlist_index");
+                       cvar_set("music_playlist_sampleposition0", "0");
+                       cvar_set("music_playlist_index", "999");
+               }
+               else
+                       localcmd("\ncd pause\n");
+       }
+
+       if (me.currentScrPath == scrImage)
+               return;
+       if (me.currentScrPath)
+               strunzone(me.currentScrPath);
+       me.currentScrPath = strzone(scrImage);
+       me.screenshotImage.load(me.screenshotImage, me.currentScrPath);
+       me.frame.setText(me.frame, me.screenshotImage.screenshotTitle);
+}
+void prevScreenshot_Click(entity btn, entity me)
+{
+       me.scrList.goScreenshot(me.scrList, -1);
+}
+void nextScreenshot_Click(entity btn, entity me)
+{
+       me.scrList.goScreenshot(me.scrList, +1);
+}
+void increaseZoom_Click(entity btn, entity me)
+{
+       me.screenshotImage.setZoom(me.screenshotImage, -2, FALSE);
+}
+void decreaseZoom_Click(entity btn, entity me)
+{
+       me.screenshotImage.setZoom(me.screenshotImage, -1/2, FALSE);
+}
+void resetZoom_Click(entity btn, entity me)
+{
+       me.screenshotImage.setZoom(me.screenshotImage, 0, FALSE);
+}
+void toggleSlideShow_Click(entity btn, entity me)
+{
+       if (me.slideShowButton.forcePressed)
+       {
+               me.scrList.stopSlideShow(me.scrList);
+               me.slideShowButton.forcePressed = 0;
+       }
+       else
+       {
+               me.scrList.startSlideShow(me.scrList);
+               me.slideShowButton.forcePressed = 1;
+       }
+}
+float XonoticScreenshotViewerDialog_keyDown(entity me, float key, float ascii, float shift)
+{
+       switch(key)
+       {
+               case K_KP_LEFTARROW:
+               case K_LEFTARROW:
+                       me.scrList.goScreenshot(me.scrList, -1);
+                       return 1;
+               case K_KP_RIGHTARROW:
+               case K_RIGHTARROW:
+                       me.scrList.goScreenshot(me.scrList, +1);
+                       return 1;
+               case K_KP_ENTER:
+               case K_ENTER:
+               case K_SPACE:
+                       // we cannot use SPACE/ENTER directly, as in a dialog they are needed
+                       // to press buttons while browsing with only the keyboard
+                       if (shift & S_CTRL)
+                       {
+                               toggleSlideShow_Click(world, me);
+                               return 1;
+                       }
+                       return SUPER(XonoticScreenshotViewerDialog).keyDown(me, key, ascii, shift);
+               default:
+                       if (key == K_MWHEELUP || ascii == '+')
+                       {
+                               me.screenshotImage.setZoom(me.screenshotImage, -2, (key == K_MWHEELUP));
+                               return 1;
+                       }
+                       else if (key == K_MWHEELDOWN || ascii == '-')
+                       {
+                               me.screenshotImage.setZoom(me.screenshotImage, -1/2, (key == K_MWHEELDOWN));
+                               return 1;
+                       }
+                       if (me.scrList.keyDown(me.scrList, key, ascii, shift))
+                       {
+                               // keyDown has already changed the selected item
+                               me.scrList.goScreenshot(me.scrList, 0);
+                               return 1;
+                       }
+                       return SUPER(XonoticScreenshotViewerDialog).keyDown(me, key, ascii, shift);
+       }
+}
+void XonoticScreenshotViewerDialog_close(entity me)
+{
+       // resume music
+       if(!cvar("menu_screenshotviewer_enablemusic"))
+       if(cvar("music_playlist_index") == 999)
+       {
+               cvar_set("music_playlist_index", ftos(music_playlist_index_backup));
+       }
+       else
+               localcmd("\ncd resume\n");
+
+       me.scrList.stopSlideShow(me.scrList);
+       me.slideShowButton.forcePressed = 0;
+       SUPER(XonoticScreenshotViewerDialog).close(me);
+}
+void XonoticScreenshotViewerDialog_fill(entity me)
+{
+       entity e;
+       me.TR(me);
+               me.TD(me, me.rows - 1, me.columns, e = makeXonoticScreenshotImage());
+                       e.showTitle = 0; // dialog title is enough
+                       me.screenshotImage = e;
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TDempty(me, 1/20 * me.columns);
+               me.TD(me, 1, 1/20 * me.columns, e = makeXonoticButton("-", '0 0 0'));
+                       e.onClick = decreaseZoom_Click;
+                       e.onClickEntity = me;
+               me.TD(me, 1, 1/20 * me.columns, e = makeXonoticButton("+", '0 0 0'));
+                       e.onClick = increaseZoom_Click;
+                       e.onClickEntity = me;
+               me.TD(me, 1, 2/20 * me.columns, e = makeXonoticButton(_("Reset"), '0 0 0'));
+                       e.onClick = resetZoom_Click;
+                       e.onClickEntity = me;
+
+               me.TDempty(me, 2/20 * me.columns);
+               me.TD(me, 1, 3/20 * me.columns, e = makeXonoticButton(_("Previous"), '0 0 0'));
+                       e.onClick = prevScreenshot_Click;
+                       e.onClickEntity = me;
+               me.TD(me, 1, 3/20 * me.columns, e = makeXonoticButton(_("Next"), '0 0 0'));
+                       e.onClick = nextScreenshot_Click;
+                       e.onClickEntity = me;
+
+               me.TDempty(me, 2/20 * me.columns);
+               me.TD(me, 1, 4/20 * me.columns, e = makeXonoticButton(_("Slide show"), '0 0 0'));
+                       e.onClick = toggleSlideShow_Click;
+                       e.onClickEntity = me;
+                       me.slideShowButton = e;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_profile.c b/qcsrc/menu/xonotic/dialog_multiplayer_profile.c
deleted file mode 100644 (file)
index a316be7..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticProfileTab) EXTENDS(XonoticTab)
-       METHOD(XonoticProfileTab, fill, void(entity))
-       METHOD(XonoticProfileTab, draw, void(entity))
-       ATTRIB(XonoticProfileTab, title, string, _("Profile"))
-       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, playerNameLabel, entity, NULL)
-       ATTRIB(XonoticProfileTab, playerNameLabelAlpha, float, SKINALPHA_HEADER)
-ENDCLASS(XonoticProfileTab)
-entity makeXonoticProfileTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticProfileTab()
-{
-       entity me;
-       me = spawnXonoticProfileTab();
-       me.configureDialog(me);
-       return me;
-}
-void XonoticProfileTab_draw(entity me)
-{
-       if(cvar_string("_cl_name") == "Player")
-               me.playerNameLabel.alpha = ((mod(time * 2, 2) < 1) ? 1 : 0);
-       else
-               me.playerNameLabel.alpha = me.playerNameLabelAlpha;
-       SUPER(XonoticProfileTab).draw(me);
-}
-void XonoticProfileTab_fill(entity me)
-{
-       entity e, pms, label, box;
-       float i;
-
-       // ==============
-       //  NAME SECTION
-       // ==============
-       me.gotoRC(me, 0.5, 0);
-               me.TD(me, 1, 3, me.playerNameLabel = makeXonoticHeaderLabel(_("Name")));
-
-       me.gotoRC(me, 1.5, 0);
-               me.TD(me, 1, 3, label = makeXonoticTextLabel(0.5, string_null));
-                       label.allowCut = 1;
-                       label.allowColors = 1;
-                       label.alpha = 1;
-                       label.isBold = TRUE;
-                       label.fontSize = SKINFONTSIZE_TITLE;
-
-       me.gotoRC(me, 2.5, 0);
-               me.TD(me, 1, 3.0, box = makeXonoticInputBox(1, "_cl_name"));
-                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
-                       box.maxLength = -127; // negative means encoded length in bytes
-                       box.saveImmediately = 1;
-                       box.enableClearButton = 0;
-                       label.textEntity = box;
-       me.TR(me);
-               me.TD(me, 5, 1, e = makeXonoticColorpicker(box));
-               me.TD(me, 5, 2, e = makeXonoticCharmap(box));
-
-       // ===============
-       //  MODEL SECTION
-       // ===============
-       //me.gotoRC(me, 0.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP RIGHT
-       //me.gotoRC(me, 9, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM RIGHT
-       me.gotoRC(me, 9, 0); me.setFirstColumn(me, me.currentColumn); // BOTTOM LEFT
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Model")));
-
-       me.TR(me);
-               //me.TDempty(me, 0); // MODEL LEFT, COLOR RIGHT
-               me.TDempty(me, 1); // MODEL RIGHT, COLOR LEFT
-               pms = makeXonoticPlayerModelSelector();
-               me.TD(me, 1, 0.3, e = makeXonoticButton("<<", '0 0 0'));
-                       e.onClick = PlayerModelSelector_Prev_Click;
-                       e.onClickEntity = pms;
-               me.TD(me, 11.5, 1.4, pms);
-               me.TD(me, 1, 0.3, e = makeXonoticButton(">>", '0 0 0'));
-                       e.onClick = PlayerModelSelector_Next_Click;
-                       e.onClickEntity = pms;
-
-       //me.setFirstColumn(me, me.currentColumn + 2); // MODEL LEFT, COLOR RIGHT
-       me.gotoRC(me, me.currentRow, 0); me.setFirstColumn(me, me.currentColumn); // MODEL RIGHT, COLOR LEFT
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticHeaderLabel(_("Glowing color")));
-               for(i = 0; i < 15; ++i)
-               {
-                       if(mod(i, 5) == 0)
-                               me.TR(me);
-                       me.TDNoMargin(me, 1, 0.2, e = makeXonoticColorButton(1, 0, i), '0 1 0');
-               }
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticHeaderLabel(_("Detail color")));
-               for(i = 0; i < 15; ++i)
-               {
-                       if(mod(i, 5) == 0)
-                               me.TR(me);
-                       me.TDNoMargin(me, 1, 0.2, e = makeXonoticColorButton(2, 1, i), '0 1 0');
-               }
-
-       // ====================
-       //  STATISTICS SECTION
-       // ====================
-       me.gotoRC(me, 0.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP RIGHT
-       //me.gotoRC(me, 9, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM RIGHT
-       //me.gotoRC(me, 9, 0); me.setFirstColumn(me, me.currentColumn); // BOTTOM LEFT
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Statistics")));
-
-       me.TR(me);
-               me.TDempty(me, 0.25);
-               me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_allow_uidtracking", _("Allow player statistics to track your client")));
-       me.TR(me);
-               me.TDempty(me, 0.25);
-               me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_allow_uid2name", _("Allow player statistics to use your nickname")));
-               setDependent(e, "cl_allow_uidtracking", 1, 1);
-       me.gotoRC(me, 4, 3.1); // TOP RIGHT
-       //me.gotoRC(me, 12.5, 3.1); // BOTTOM RIGHT 
-       //me.gotoRC(me, 12.5, 0); // BOTTOM LEFT
-               me.TDempty(me, 0.25);
-               me.TD(me, 9, 2.5, statslist = makeXonoticStatsList());
-               //setDependent(statslist, "cl_allow_uidtracking", 1, 1);
-
-       // =================
-       //  COUNTRY SECTION
-       // =================
-       me.gotoRC(me, 16, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, TOP POS
-       //me.gotoRC(me, 13.5, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, TOP POS
-       //me.gotoRC(me, 0.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP SECTION, TOP POS
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Country")));
-
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 4.5, 2, e = makeXonoticLanguageList()); // todo: cl_country: create proper country list
-
-
-       // ================
-       //  GENDER SECTION
-       // ================
-       me.gotoRC(me, 13.5, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, TOP POS
-       //me.gotoRC(me, 19.5, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, BOTTOM POS
-       //me.gotoRC(me, 6.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP SECTION, BOTTOM POS
-       #if 0
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gender:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_gender"));
-                       e.addValue(e, ZCTX(_("GENDER^Undisclosed")), "0");
-                       e.addValue(e, ZCTX(_("GENDER^Female")), "1");
-                       e.addValue(e, ZCTX(_("GENDER^Male")), "2");
-                       e.configureXonoticTextSliderValues(e);
-       #else
-                       me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Gender")));
-               me.TR(me);
-                       #define GENDERWIDTH_OFFSET 0.25
-                       #define GENDERWIDTH_LENGTH 2.5
-                       #define GENDERWIDTH_ITEM (GENDERWIDTH_LENGTH / 3)
-                       me.TDempty(me, GENDERWIDTH_OFFSET);
-                       me.TD(me, 1, GENDERWIDTH_ITEM, e = makeXonoticRadioButton(3, "cl_gender", "2", _("Female")));
-                       me.TD(me, 1, GENDERWIDTH_ITEM, e = makeXonoticRadioButton(3, "cl_gender", "1", _("Male")));
-                       me.TD(me, 1, GENDERWIDTH_ITEM, e = makeXonoticRadioButton(3, "cl_gender", "0", _("Undisclosed")));
-       #endif
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "color -1 -1;name \"$_cl_name\";sendcvar cl_weaponpriority;sendcvar cl_autoswitch;sendcvar cl_forceplayermodels;sendcvar cl_forceplayermodelsfromxonotic;playermodel $_cl_playermodel;playerskin $_cl_playerskin", COMMANDBUTTON_APPLY));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_profile.qc b/qcsrc/menu/xonotic/dialog_multiplayer_profile.qc
new file mode 100644 (file)
index 0000000..a316be7
--- /dev/null
@@ -0,0 +1,164 @@
+#ifdef INTERFACE
+CLASS(XonoticProfileTab) EXTENDS(XonoticTab)
+       METHOD(XonoticProfileTab, fill, void(entity))
+       METHOD(XonoticProfileTab, draw, void(entity))
+       ATTRIB(XonoticProfileTab, title, string, _("Profile"))
+       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, playerNameLabel, entity, NULL)
+       ATTRIB(XonoticProfileTab, playerNameLabelAlpha, float, SKINALPHA_HEADER)
+ENDCLASS(XonoticProfileTab)
+entity makeXonoticProfileTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticProfileTab()
+{
+       entity me;
+       me = spawnXonoticProfileTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticProfileTab_draw(entity me)
+{
+       if(cvar_string("_cl_name") == "Player")
+               me.playerNameLabel.alpha = ((mod(time * 2, 2) < 1) ? 1 : 0);
+       else
+               me.playerNameLabel.alpha = me.playerNameLabelAlpha;
+       SUPER(XonoticProfileTab).draw(me);
+}
+void XonoticProfileTab_fill(entity me)
+{
+       entity e, pms, label, box;
+       float i;
+
+       // ==============
+       //  NAME SECTION
+       // ==============
+       me.gotoRC(me, 0.5, 0);
+               me.TD(me, 1, 3, me.playerNameLabel = makeXonoticHeaderLabel(_("Name")));
+
+       me.gotoRC(me, 1.5, 0);
+               me.TD(me, 1, 3, label = makeXonoticTextLabel(0.5, string_null));
+                       label.allowCut = 1;
+                       label.allowColors = 1;
+                       label.alpha = 1;
+                       label.isBold = TRUE;
+                       label.fontSize = SKINFONTSIZE_TITLE;
+
+       me.gotoRC(me, 2.5, 0);
+               me.TD(me, 1, 3.0, box = makeXonoticInputBox(1, "_cl_name"));
+                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
+                       box.maxLength = -127; // negative means encoded length in bytes
+                       box.saveImmediately = 1;
+                       box.enableClearButton = 0;
+                       label.textEntity = box;
+       me.TR(me);
+               me.TD(me, 5, 1, e = makeXonoticColorpicker(box));
+               me.TD(me, 5, 2, e = makeXonoticCharmap(box));
+
+       // ===============
+       //  MODEL SECTION
+       // ===============
+       //me.gotoRC(me, 0.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP RIGHT
+       //me.gotoRC(me, 9, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM RIGHT
+       me.gotoRC(me, 9, 0); me.setFirstColumn(me, me.currentColumn); // BOTTOM LEFT
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Model")));
+
+       me.TR(me);
+               //me.TDempty(me, 0); // MODEL LEFT, COLOR RIGHT
+               me.TDempty(me, 1); // MODEL RIGHT, COLOR LEFT
+               pms = makeXonoticPlayerModelSelector();
+               me.TD(me, 1, 0.3, e = makeXonoticButton("<<", '0 0 0'));
+                       e.onClick = PlayerModelSelector_Prev_Click;
+                       e.onClickEntity = pms;
+               me.TD(me, 11.5, 1.4, pms);
+               me.TD(me, 1, 0.3, e = makeXonoticButton(">>", '0 0 0'));
+                       e.onClick = PlayerModelSelector_Next_Click;
+                       e.onClickEntity = pms;
+
+       //me.setFirstColumn(me, me.currentColumn + 2); // MODEL LEFT, COLOR RIGHT
+       me.gotoRC(me, me.currentRow, 0); me.setFirstColumn(me, me.currentColumn); // MODEL RIGHT, COLOR LEFT
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticHeaderLabel(_("Glowing color")));
+               for(i = 0; i < 15; ++i)
+               {
+                       if(mod(i, 5) == 0)
+                               me.TR(me);
+                       me.TDNoMargin(me, 1, 0.2, e = makeXonoticColorButton(1, 0, i), '0 1 0');
+               }
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticHeaderLabel(_("Detail color")));
+               for(i = 0; i < 15; ++i)
+               {
+                       if(mod(i, 5) == 0)
+                               me.TR(me);
+                       me.TDNoMargin(me, 1, 0.2, e = makeXonoticColorButton(2, 1, i), '0 1 0');
+               }
+
+       // ====================
+       //  STATISTICS SECTION
+       // ====================
+       me.gotoRC(me, 0.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP RIGHT
+       //me.gotoRC(me, 9, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM RIGHT
+       //me.gotoRC(me, 9, 0); me.setFirstColumn(me, me.currentColumn); // BOTTOM LEFT
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Statistics")));
+
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_allow_uidtracking", _("Allow player statistics to track your client")));
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_allow_uid2name", _("Allow player statistics to use your nickname")));
+               setDependent(e, "cl_allow_uidtracking", 1, 1);
+       me.gotoRC(me, 4, 3.1); // TOP RIGHT
+       //me.gotoRC(me, 12.5, 3.1); // BOTTOM RIGHT 
+       //me.gotoRC(me, 12.5, 0); // BOTTOM LEFT
+               me.TDempty(me, 0.25);
+               me.TD(me, 9, 2.5, statslist = makeXonoticStatsList());
+               //setDependent(statslist, "cl_allow_uidtracking", 1, 1);
+
+       // =================
+       //  COUNTRY SECTION
+       // =================
+       me.gotoRC(me, 16, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, TOP POS
+       //me.gotoRC(me, 13.5, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, TOP POS
+       //me.gotoRC(me, 0.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP SECTION, TOP POS
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Country")));
+
+       me.TR(me);
+               me.TDempty(me, 0.5);
+               me.TD(me, 4.5, 2, e = makeXonoticLanguageList()); // todo: cl_country: create proper country list
+
+
+       // ================
+       //  GENDER SECTION
+       // ================
+       me.gotoRC(me, 13.5, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, TOP POS
+       //me.gotoRC(me, 19.5, 3.1); me.setFirstColumn(me, me.currentColumn); // BOTTOM SECTION, BOTTOM POS
+       //me.gotoRC(me, 6.5, 3.1); me.setFirstColumn(me, me.currentColumn); // TOP SECTION, BOTTOM POS
+       #if 0
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gender:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_gender"));
+                       e.addValue(e, ZCTX(_("GENDER^Undisclosed")), "0");
+                       e.addValue(e, ZCTX(_("GENDER^Female")), "1");
+                       e.addValue(e, ZCTX(_("GENDER^Male")), "2");
+                       e.configureXonoticTextSliderValues(e);
+       #else
+                       me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Gender")));
+               me.TR(me);
+                       #define GENDERWIDTH_OFFSET 0.25
+                       #define GENDERWIDTH_LENGTH 2.5
+                       #define GENDERWIDTH_ITEM (GENDERWIDTH_LENGTH / 3)
+                       me.TDempty(me, GENDERWIDTH_OFFSET);
+                       me.TD(me, 1, GENDERWIDTH_ITEM, e = makeXonoticRadioButton(3, "cl_gender", "2", _("Female")));
+                       me.TD(me, 1, GENDERWIDTH_ITEM, e = makeXonoticRadioButton(3, "cl_gender", "1", _("Male")));
+                       me.TD(me, 1, GENDERWIDTH_ITEM, e = makeXonoticRadioButton(3, "cl_gender", "0", _("Undisclosed")));
+       #endif
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "color -1 -1;name \"$_cl_name\";sendcvar cl_weaponpriority;sendcvar cl_autoswitch;sendcvar cl_forceplayermodels;sendcvar cl_forceplayermodelsfromxonotic;playermodel $_cl_playermodel;playerskin $_cl_playerskin", COMMANDBUTTON_APPLY));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_quit.c b/qcsrc/menu/xonotic/dialog_quit.c
deleted file mode 100644 (file)
index 71de59d..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticQuitDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticQuitDialog, fill, void(entity))
-       ATTRIB(XonoticQuitDialog, title, string, _("Quit"))
-       ATTRIB(XonoticQuitDialog, color, vector, SKINCOLOR_DIALOG_QUIT)
-       ATTRIB(XonoticQuitDialog, intendedWidth, float, 0.5)
-       ATTRIB(XonoticQuitDialog, rows, float, 3)
-       ATTRIB(XonoticQuitDialog, columns, float, 2)
-       ATTRIB(XonoticQuitDialog, name, string, "Quit")
-ENDCLASS(XonoticQuitDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticQuitDialog_fill(entity me)
-{
-       entity e;
-       me.TR(me);
-               me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("Are you sure you want to quit?")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCommandButton(_("Yes"), '1 0 0', "echo ]quit\nquit", 0));
-               me.TD(me, 1, 1, e = makeXonoticButton(_("No"), '0 1 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_quit.qc b/qcsrc/menu/xonotic/dialog_quit.qc
new file mode 100644 (file)
index 0000000..71de59d
--- /dev/null
@@ -0,0 +1,26 @@
+#ifdef INTERFACE
+CLASS(XonoticQuitDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticQuitDialog, fill, void(entity))
+       ATTRIB(XonoticQuitDialog, title, string, _("Quit"))
+       ATTRIB(XonoticQuitDialog, color, vector, SKINCOLOR_DIALOG_QUIT)
+       ATTRIB(XonoticQuitDialog, intendedWidth, float, 0.5)
+       ATTRIB(XonoticQuitDialog, rows, float, 3)
+       ATTRIB(XonoticQuitDialog, columns, float, 2)
+       ATTRIB(XonoticQuitDialog, name, string, "Quit")
+ENDCLASS(XonoticQuitDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticQuitDialog_fill(entity me)
+{
+       entity e;
+       me.TR(me);
+               me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("Are you sure you want to quit?")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCommandButton(_("Yes"), '1 0 0', "echo ]quit\nquit", 0));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("No"), '0 1 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_sandboxtools.c b/qcsrc/menu/xonotic/dialog_sandboxtools.c
deleted file mode 100644 (file)
index 033336d..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticSandboxToolsDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticSandboxToolsDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
-       ATTRIB(XonoticSandboxToolsDialog, title, string, _("Sandbox Tools")) // ;)
-       ATTRIB(XonoticSandboxToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS)
-       ATTRIB(XonoticSandboxToolsDialog, intendedWidth, float, 0.8)
-       ATTRIB(XonoticSandboxToolsDialog, rows, float, 16)
-       ATTRIB(XonoticSandboxToolsDialog, columns, float, 4)
-       ATTRIB(XonoticSandboxToolsDialog, name, string, "SandboxTools")
-       ATTRIB(XonoticSandboxToolsDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticSandboxToolsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticSandboxToolsDialog_fill(entity me)
-{
-       entity e, box;
-
-       me.TR(me);
-               me.TD(me, 1, 0.25, e = makeXonoticTextLabel(0, _("Model:")));
-               me.TD(me, 1, 1.5, box = makeXonoticInputBox(1, "menu_sandbox_spawn_model"));
-                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
-                       box.maxLength = -127; // negative means encoded length in bytes
-                       box.saveImmediately = 1;
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Spawn"), '0 0 0', "sandbox object_spawn \"$menu_sandbox_spawn_model\"", 0));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Remove *"), '0 0 0', "sandbox object_remove", 0));
-       me.TDempty(me, 0.1);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Copy *"), '0 0 0', "sandbox object_duplicate copy cl_sandbox_clipboard", 0));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Paste"), '0 0 0', "sandbox object_duplicate paste \"$cl_sandbox_clipboard\"", 0));
-       me.TR(me);
-               me.TD(me, 1, 0.25, e = makeXonoticTextLabel(0, _("Bone:")));
-               me.TD(me, 1, 1.5, box = makeXonoticInputBox(1, "menu_sandbox_attach_bone"));
-                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
-                       box.maxLength = -127; // negative means encoded length in bytes
-                       box.saveImmediately = 1;
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set * as child"), '0 0 0', "sandbox object_attach get", 0));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Attach to *"), '0 0 0', "sandbox object_attach set \"$menu_sandbox_attach_bone\"", 0));
-       me.TDempty(me, 0.1);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Detach from *"), '0 0 0', "sandbox object_attach remove", 0));
-       me.TR(me);
-       me.TR(me);
-       me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("Visual object properties for *:")));
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set skin:"), '0 0 0', "sandbox object_edit skin $menu_sandbox_edit_skin", 0));
-               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 99, 1, "menu_sandbox_edit_skin"));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set alpha:"), '0 0 0', "sandbox object_edit alpha $menu_sandbox_edit_alpha", 0));
-               me.TD(me, 1, 1.5, e = makeXonoticSlider(0.1, 1, 0.05, "menu_sandbox_edit_alpha"));
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set color main:"), '0 0 0', "sandbox object_edit color_main \"$menu_sandbox_edit_color_main\"", 0));
-               me.TD(me, 2, 1.5, e = makeXonoticColorpickerString("menu_sandbox_edit_color_main", "menu_sandbox_edit_color_main"));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set color glow:"), '0 0 0', "sandbox object_edit color_glow \"$menu_sandbox_edit_color_glow\"", 0));
-               me.TD(me, 2, 1.5, e = makeXonoticColorpickerString("menu_sandbox_edit_color_glow", "menu_sandbox_edit_color_glow"));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set frame:"), '0 0 0', "sandbox object_edit frame $menu_sandbox_edit_frame", 0));
-               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 99, 1, "menu_sandbox_edit_frame"));
-       me.TR(me);
-       me.TR(me);
-       me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("Physical object properties for *:")));
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set material:"), '0 0 0', "sandbox object_edit material \"$menu_sandbox_edit_material\"", 0));
-               me.TD(me, 1, 1.5, box = makeXonoticInputBox(1, "menu_sandbox_edit_material"));
-                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
-                       box.maxLength = -127; // negative means encoded length in bytes
-                       box.saveImmediately = 1;
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set solidity:"), '0 0 0', "sandbox object_edit solidity $menu_sandbox_edit_solidity", 0));
-               me.TD(me, 1, 0.75, e = makeXonoticRadioButton(1, "menu_sandbox_edit_solidity", "0", _("Non-solid")));
-               me.TD(me, 1, 0.75, e = makeXonoticRadioButton(1, "menu_sandbox_edit_solidity", "1", _("Solid")));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set physics:"), '0 0 0', "sandbox object_edit physics $menu_sandbox_edit_physics", 0));
-               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_sandbox_edit_physics", "0", _("Static")));
-               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_sandbox_edit_physics", "1", _("Movable")));
-               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_sandbox_edit_physics", "2", _("Physical")));
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set scale:"), '0 0 0', "sandbox object_edit scale $menu_sandbox_edit_scale", 0));
-               me.TD(me, 1, 1.5, e = makeXonoticSlider(0.25, 2, 0.05, "menu_sandbox_edit_scale"));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set force:"), '0 0 0', "sandbox object_edit force $menu_sandbox_edit_force", 0));
-               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 10, 0.5, "menu_sandbox_edit_force"));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Claim *"), '0 0 0', "sandbox object_claim", 0));
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("* object info"), '1 1 0.5', "sandbox object_info object; toggleconsole", 0));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("* mesh info"), '1 1 0.5', "sandbox object_info mesh; toggleconsole", 0));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("* attachment info"), '1 1 0.5', "sandbox object_info attachments; toggleconsole", 0));
-               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Show help"), '1 0.5 0.5', "sandbox help; toggleconsole", 0));
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("* is the object you are facing")));
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
-
-/* Click. The c-word is here so you can grep for it :-) */
diff --git a/qcsrc/menu/xonotic/dialog_sandboxtools.qc b/qcsrc/menu/xonotic/dialog_sandboxtools.qc
new file mode 100644 (file)
index 0000000..033336d
--- /dev/null
@@ -0,0 +1,96 @@
+#ifdef INTERFACE
+CLASS(XonoticSandboxToolsDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticSandboxToolsDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
+       ATTRIB(XonoticSandboxToolsDialog, title, string, _("Sandbox Tools")) // ;)
+       ATTRIB(XonoticSandboxToolsDialog, color, vector, SKINCOLOR_DIALOG_SANDBOXTOOLS)
+       ATTRIB(XonoticSandboxToolsDialog, intendedWidth, float, 0.8)
+       ATTRIB(XonoticSandboxToolsDialog, rows, float, 16)
+       ATTRIB(XonoticSandboxToolsDialog, columns, float, 4)
+       ATTRIB(XonoticSandboxToolsDialog, name, string, "SandboxTools")
+       ATTRIB(XonoticSandboxToolsDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticSandboxToolsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticSandboxToolsDialog_fill(entity me)
+{
+       entity e, box;
+
+       me.TR(me);
+               me.TD(me, 1, 0.25, e = makeXonoticTextLabel(0, _("Model:")));
+               me.TD(me, 1, 1.5, box = makeXonoticInputBox(1, "menu_sandbox_spawn_model"));
+                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
+                       box.maxLength = -127; // negative means encoded length in bytes
+                       box.saveImmediately = 1;
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Spawn"), '0 0 0', "sandbox object_spawn \"$menu_sandbox_spawn_model\"", 0));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Remove *"), '0 0 0', "sandbox object_remove", 0));
+       me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Copy *"), '0 0 0', "sandbox object_duplicate copy cl_sandbox_clipboard", 0));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Paste"), '0 0 0', "sandbox object_duplicate paste \"$cl_sandbox_clipboard\"", 0));
+       me.TR(me);
+               me.TD(me, 1, 0.25, e = makeXonoticTextLabel(0, _("Bone:")));
+               me.TD(me, 1, 1.5, box = makeXonoticInputBox(1, "menu_sandbox_attach_bone"));
+                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
+                       box.maxLength = -127; // negative means encoded length in bytes
+                       box.saveImmediately = 1;
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set * as child"), '0 0 0', "sandbox object_attach get", 0));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Attach to *"), '0 0 0', "sandbox object_attach set \"$menu_sandbox_attach_bone\"", 0));
+       me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Detach from *"), '0 0 0', "sandbox object_attach remove", 0));
+       me.TR(me);
+       me.TR(me);
+       me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("Visual object properties for *:")));
+       me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set skin:"), '0 0 0', "sandbox object_edit skin $menu_sandbox_edit_skin", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 99, 1, "menu_sandbox_edit_skin"));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set alpha:"), '0 0 0', "sandbox object_edit alpha $menu_sandbox_edit_alpha", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0.1, 1, 0.05, "menu_sandbox_edit_alpha"));
+       me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set color main:"), '0 0 0', "sandbox object_edit color_main \"$menu_sandbox_edit_color_main\"", 0));
+               me.TD(me, 2, 1.5, e = makeXonoticColorpickerString("menu_sandbox_edit_color_main", "menu_sandbox_edit_color_main"));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set color glow:"), '0 0 0', "sandbox object_edit color_glow \"$menu_sandbox_edit_color_glow\"", 0));
+               me.TD(me, 2, 1.5, e = makeXonoticColorpickerString("menu_sandbox_edit_color_glow", "menu_sandbox_edit_color_glow"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set frame:"), '0 0 0', "sandbox object_edit frame $menu_sandbox_edit_frame", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 99, 1, "menu_sandbox_edit_frame"));
+       me.TR(me);
+       me.TR(me);
+       me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("Physical object properties for *:")));
+       me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set material:"), '0 0 0', "sandbox object_edit material \"$menu_sandbox_edit_material\"", 0));
+               me.TD(me, 1, 1.5, box = makeXonoticInputBox(1, "menu_sandbox_edit_material"));
+                       box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
+                       box.maxLength = -127; // negative means encoded length in bytes
+                       box.saveImmediately = 1;
+       me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set solidity:"), '0 0 0', "sandbox object_edit solidity $menu_sandbox_edit_solidity", 0));
+               me.TD(me, 1, 0.75, e = makeXonoticRadioButton(1, "menu_sandbox_edit_solidity", "0", _("Non-solid")));
+               me.TD(me, 1, 0.75, e = makeXonoticRadioButton(1, "menu_sandbox_edit_solidity", "1", _("Solid")));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set physics:"), '0 0 0', "sandbox object_edit physics $menu_sandbox_edit_physics", 0));
+               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_sandbox_edit_physics", "0", _("Static")));
+               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_sandbox_edit_physics", "1", _("Movable")));
+               me.TD(me, 1, 0.5, e = makeXonoticRadioButton(2, "menu_sandbox_edit_physics", "2", _("Physical")));
+       me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set scale:"), '0 0 0', "sandbox object_edit scale $menu_sandbox_edit_scale", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0.25, 2, 0.05, "menu_sandbox_edit_scale"));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Set force:"), '0 0 0', "sandbox object_edit force $menu_sandbox_edit_force", 0));
+               me.TD(me, 1, 1.5, e = makeXonoticSlider(0, 10, 0.5, "menu_sandbox_edit_force"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Claim *"), '0 0 0', "sandbox object_claim", 0));
+               me.TDempty(me, 0.5);
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("* object info"), '1 1 0.5', "sandbox object_info object; toggleconsole", 0));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("* mesh info"), '1 1 0.5', "sandbox object_info mesh; toggleconsole", 0));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("* attachment info"), '1 1 0.5', "sandbox object_info attachments; toggleconsole", 0));
+               me.TD(me, 1, 0.5, e = makeXonoticCommandButton(_("Show help"), '1 0.5 0.5', "sandbox help; toggleconsole", 0));
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("* is the object you are facing")));
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
+
+/* Click. The c-word is here so you can grep for it :-) */
diff --git a/qcsrc/menu/xonotic/dialog_settings.c b/qcsrc/menu/xonotic/dialog_settings.c
deleted file mode 100644 (file)
index a992e80..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticSettingsDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticSettingsDialog, fill, void(entity))
-       ATTRIB(XonoticSettingsDialog, title, string, _("Settings"))
-       ATTRIB(XonoticSettingsDialog, color, vector, SKINCOLOR_DIALOG_SETTINGS)
-       ATTRIB(XonoticSettingsDialog, intendedWidth, float, 0.96)
-       ATTRIB(XonoticSettingsDialog, rows, float, 18)
-       ATTRIB(XonoticSettingsDialog, columns, float, 6)
-ENDCLASS(XonoticSettingsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticSettingsDialog_fill(entity me)
-{
-       entity mc;
-       mc = makeXonoticTabController(me.rows - 2.5);
-       me.TR(me);
-               me.TD(me, 1, 2, mc.makeTabButton(mc, _("Video"),   makeXonoticVideoSettingsTab()));
-               me.TD(me, 1, 2, mc.makeTabButton(mc, _("Effects"), makeXonoticEffectsSettingsTab()));
-               me.TD(me, 1, 2, mc.makeTabButton(mc, _("Audio"),   makeXonoticAudioSettingsTab()));
-       me.TR(me);
-               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("Game"),   makeXonoticGameSettingsTab()));
-               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("Input"),   makeXonoticInputSettingsTab()));
-               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("User"),    makeXonoticUserSettingsTab()));
-               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("Misc"),    makeXonoticMiscSettingsTab()));
-       me.gotoRC(me, 2.5, 0);
-               me.TD(me, me.rows - 2.5, me.columns, mc);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings.qc b/qcsrc/menu/xonotic/dialog_settings.qc
new file mode 100644 (file)
index 0000000..a992e80
--- /dev/null
@@ -0,0 +1,29 @@
+#ifdef INTERFACE
+CLASS(XonoticSettingsDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticSettingsDialog, fill, void(entity))
+       ATTRIB(XonoticSettingsDialog, title, string, _("Settings"))
+       ATTRIB(XonoticSettingsDialog, color, vector, SKINCOLOR_DIALOG_SETTINGS)
+       ATTRIB(XonoticSettingsDialog, intendedWidth, float, 0.96)
+       ATTRIB(XonoticSettingsDialog, rows, float, 18)
+       ATTRIB(XonoticSettingsDialog, columns, float, 6)
+ENDCLASS(XonoticSettingsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticSettingsDialog_fill(entity me)
+{
+       entity mc;
+       mc = makeXonoticTabController(me.rows - 2.5);
+       me.TR(me);
+               me.TD(me, 1, 2, mc.makeTabButton(mc, _("Video"),   makeXonoticVideoSettingsTab()));
+               me.TD(me, 1, 2, mc.makeTabButton(mc, _("Effects"), makeXonoticEffectsSettingsTab()));
+               me.TD(me, 1, 2, mc.makeTabButton(mc, _("Audio"),   makeXonoticAudioSettingsTab()));
+       me.TR(me);
+               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("Game"),   makeXonoticGameSettingsTab()));
+               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("Input"),   makeXonoticInputSettingsTab()));
+               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("User"),    makeXonoticUserSettingsTab()));
+               me.TD(me, 1, 1.5, mc.makeTabButton(mc, _("Misc"),    makeXonoticMiscSettingsTab()));
+       me.gotoRC(me, 2.5, 0);
+               me.TD(me, me.rows - 2.5, me.columns, mc);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_audio.c b/qcsrc/menu/xonotic/dialog_settings_audio.c
deleted file mode 100644 (file)
index 39bee32..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticAudioSettingsTab) EXTENDS(XonoticTab)
-       METHOD(XonoticAudioSettingsTab, fill, void(entity))
-       ATTRIB(XonoticAudioSettingsTab, title, string, _("Audio"))
-       ATTRIB(XonoticAudioSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticAudioSettingsTab, rows, float, 15.5)
-       ATTRIB(XonoticAudioSettingsTab, columns, float, 6.2) // added extra .2 for center space
-ENDCLASS(XonoticAudioSettingsTab)
-entity makeXonoticAudioSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticAudioSettingsTab()
-{
-       entity me;
-       me = spawnXonoticAudioSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void XonoticAudioSettingsTab_fill(entity me)
-{
-       entity e, s;
-
-       me.TR(me);
-               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "mastervolume");
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Master:")));
-               me.TD(me, 1, 2, s);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "bgmvolume");
-               makeMulti(s, "snd_channel8volume");
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Music:")));
-               me.TD(me, 1, 2, s);
-               setDependentStringNotEqual(e, "mastervolume", "0");
-               setDependentStringNotEqual(s, "mastervolume", "0");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_staticvolume");
-               makeMulti(s, "snd_channel9volume");
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, ZCTX(_("VOL^Ambient:"))));
-               me.TD(me, 1, 2, s);
-               setDependentStringNotEqual(e, "mastervolume", "0");
-               setDependentStringNotEqual(s, "mastervolume", "0");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel0volume");
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Info:")));
-               me.TD(me, 1, 2, s);
-               setDependentStringNotEqual(e, "mastervolume", "0");
-               setDependentStringNotEqual(s, "mastervolume", "0");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel3volume");
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Items:")));
-               me.TD(me, 1, 2, s);
-               setDependentStringNotEqual(e, "mastervolume", "0");
-               setDependentStringNotEqual(s, "mastervolume", "0");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel6volume");
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Pain:")));
-               me.TD(me, 1, 2, s);
-               setDependentStringNotEqual(e, "mastervolume", "0");
-               setDependentStringNotEqual(s, "mastervolume", "0");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel7volume");
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Player:")));
-               me.TD(me, 1, 2, s);
-               setDependentStringNotEqual(e, "mastervolume", "0");
-               setDependentStringNotEqual(s, "mastervolume", "0");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel4volume");
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Shots:")));
-               me.TD(me, 1, 2, s);
-               setDependentStringNotEqual(e, "mastervolume", "0");
-               setDependentStringNotEqual(s, "mastervolume", "0");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel2volume");
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Voice:")));
-               me.TD(me, 1, 2, s);
-               setDependentStringNotEqual(e, "mastervolume", "0");
-               setDependentStringNotEqual(s, "mastervolume", "0");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel1volume");
-               makeMulti(s, "snd_channel5volume"); // @!#%'n Tuba
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Weapons:")));
-               me.TD(me, 1, 2, s);
-               setDependentStringNotEqual(e, "mastervolume", "0");
-               setDependentStringNotEqual(s, "mastervolume", "0");
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, makeXonoticCheckBox(0, "menu_snd_attenuation_method", _("New style sound attenuation")));
-       me.TR(me);
-               me.TD(me, 1, 3, makeXonoticCheckBox(0, "snd_mutewhenidle", _("Mute sounds when not active")));
-
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 1, makeXonoticTextLabel(0, _("Frequency:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("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.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, makeXonoticTextLabel(0, _("Channels:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("snd_channels"));
-                       e.addValue(e, _("Mono"), "1");
-                       e.addValue(e, _("Stereo"), "2");
-                       e.addValue(e, _("2.1"), "3");
-                       e.addValue(e, _("4"), "4");
-                       e.addValue(e, _("5"), "5");
-                       e.addValue(e, _("5.1"), "6");
-                       e.addValue(e, _("6.1"), "7");
-                       e.addValue(e, _("7.1"), "8");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "snd_swapstereo", _("Swap stereo output channels")));
-               setDependent(e, "snd_channels", 1.5, 0.5);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "snd_spatialization_control", _("Headphone friendly mode")));
-               setDependent(e, "snd_channels", 1.5, 0.5);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, makeXonoticCheckBox(0, "cl_hitsound", _("Hit indication sound")));
-               e.sendCvars = TRUE;
-       me.TR(me);
-               me.TD(me, 1, 3, makeXonoticCheckBox(0, "con_chatsound", _("Chat message sound")));
-       me.TR(me);
-               me.TD(me, 1, 3, makeXonoticCheckBoxEx(2, 0, "menu_sounds", _("Menu sounds")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, makeXonoticTextLabel(0, _("Time announcer:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_announcer_maptime"));
-                       e.addValue(e, ZCTX(_("WRN^Disabled")), "0");
-                       e.addValue(e, _("1 minute"), "1");
-                       e.addValue(e, _("5 minutes"), "2");
-                       e.addValue(e, ZCTX(_("WRN^Both")), "3");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, makeXonoticTextLabel(0, _("Automatic taunts:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_autotaunt"));
-                       e.addValue(e, _("Never"), "0");
-                       e.addValue(e, _("Sometimes"), "0.35");
-                       e.addValue(e, _("Often"), "0.65");
-                       e.addValue(e, _("Always"), "1");
-                       e.configureXonoticTextSliderValues(e);
-                       e.sendCvars = TRUE;
-       me.TR(me);
-       me.TR(me);
-               if(cvar("developer"))
-                       me.TD(me, 1, 3, makeXonoticCheckBox(0, "showsound", _("Debug info about sounds")));
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "snd_restart; snd_attenuation_method_${menu_snd_attenuation_method}", COMMANDBUTTON_APPLY));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_audio.qc b/qcsrc/menu/xonotic/dialog_settings_audio.qc
new file mode 100644 (file)
index 0000000..39bee32
--- /dev/null
@@ -0,0 +1,166 @@
+#ifdef INTERFACE
+CLASS(XonoticAudioSettingsTab) EXTENDS(XonoticTab)
+       METHOD(XonoticAudioSettingsTab, fill, void(entity))
+       ATTRIB(XonoticAudioSettingsTab, title, string, _("Audio"))
+       ATTRIB(XonoticAudioSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticAudioSettingsTab, rows, float, 15.5)
+       ATTRIB(XonoticAudioSettingsTab, columns, float, 6.2) // added extra .2 for center space
+ENDCLASS(XonoticAudioSettingsTab)
+entity makeXonoticAudioSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticAudioSettingsTab()
+{
+       entity me;
+       me = spawnXonoticAudioSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticAudioSettingsTab_fill(entity me)
+{
+       entity e, s;
+
+       me.TR(me);
+               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "mastervolume");
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Master:")));
+               me.TD(me, 1, 2, s);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "bgmvolume");
+               makeMulti(s, "snd_channel8volume");
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Music:")));
+               me.TD(me, 1, 2, s);
+               setDependentStringNotEqual(e, "mastervolume", "0");
+               setDependentStringNotEqual(s, "mastervolume", "0");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_staticvolume");
+               makeMulti(s, "snd_channel9volume");
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, ZCTX(_("VOL^Ambient:"))));
+               me.TD(me, 1, 2, s);
+               setDependentStringNotEqual(e, "mastervolume", "0");
+               setDependentStringNotEqual(s, "mastervolume", "0");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel0volume");
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Info:")));
+               me.TD(me, 1, 2, s);
+               setDependentStringNotEqual(e, "mastervolume", "0");
+               setDependentStringNotEqual(s, "mastervolume", "0");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel3volume");
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Items:")));
+               me.TD(me, 1, 2, s);
+               setDependentStringNotEqual(e, "mastervolume", "0");
+               setDependentStringNotEqual(s, "mastervolume", "0");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel6volume");
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Pain:")));
+               me.TD(me, 1, 2, s);
+               setDependentStringNotEqual(e, "mastervolume", "0");
+               setDependentStringNotEqual(s, "mastervolume", "0");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel7volume");
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Player:")));
+               me.TD(me, 1, 2, s);
+               setDependentStringNotEqual(e, "mastervolume", "0");
+               setDependentStringNotEqual(s, "mastervolume", "0");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel4volume");
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Shots:")));
+               me.TD(me, 1, 2, s);
+               setDependentStringNotEqual(e, "mastervolume", "0");
+               setDependentStringNotEqual(s, "mastervolume", "0");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel2volume");
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Voice:")));
+               me.TD(me, 1, 2, s);
+               setDependentStringNotEqual(e, "mastervolume", "0");
+               setDependentStringNotEqual(s, "mastervolume", "0");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               s = makeXonoticDecibelsSlider(-40, 0, 0.4, "snd_channel1volume");
+               makeMulti(s, "snd_channel5volume"); // @!#%'n Tuba
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Weapons:")));
+               me.TD(me, 1, 2, s);
+               setDependentStringNotEqual(e, "mastervolume", "0");
+               setDependentStringNotEqual(s, "mastervolume", "0");
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, makeXonoticCheckBox(0, "menu_snd_attenuation_method", _("New style sound attenuation")));
+       me.TR(me);
+               me.TD(me, 1, 3, makeXonoticCheckBox(0, "snd_mutewhenidle", _("Mute sounds when not active")));
+
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1, makeXonoticTextLabel(0, _("Frequency:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("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.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, makeXonoticTextLabel(0, _("Channels:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("snd_channels"));
+                       e.addValue(e, _("Mono"), "1");
+                       e.addValue(e, _("Stereo"), "2");
+                       e.addValue(e, _("2.1"), "3");
+                       e.addValue(e, _("4"), "4");
+                       e.addValue(e, _("5"), "5");
+                       e.addValue(e, _("5.1"), "6");
+                       e.addValue(e, _("6.1"), "7");
+                       e.addValue(e, _("7.1"), "8");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "snd_swapstereo", _("Swap stereo output channels")));
+               setDependent(e, "snd_channels", 1.5, 0.5);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "snd_spatialization_control", _("Headphone friendly mode")));
+               setDependent(e, "snd_channels", 1.5, 0.5);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, makeXonoticCheckBox(0, "cl_hitsound", _("Hit indication sound")));
+               e.sendCvars = TRUE;
+       me.TR(me);
+               me.TD(me, 1, 3, makeXonoticCheckBox(0, "con_chatsound", _("Chat message sound")));
+       me.TR(me);
+               me.TD(me, 1, 3, makeXonoticCheckBoxEx(2, 0, "menu_sounds", _("Menu sounds")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, makeXonoticTextLabel(0, _("Time announcer:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_announcer_maptime"));
+                       e.addValue(e, ZCTX(_("WRN^Disabled")), "0");
+                       e.addValue(e, _("1 minute"), "1");
+                       e.addValue(e, _("5 minutes"), "2");
+                       e.addValue(e, ZCTX(_("WRN^Both")), "3");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, makeXonoticTextLabel(0, _("Automatic taunts:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_autotaunt"));
+                       e.addValue(e, _("Never"), "0");
+                       e.addValue(e, _("Sometimes"), "0.35");
+                       e.addValue(e, _("Often"), "0.65");
+                       e.addValue(e, _("Always"), "1");
+                       e.configureXonoticTextSliderValues(e);
+                       e.sendCvars = TRUE;
+       me.TR(me);
+       me.TR(me);
+               if(cvar("developer"))
+                       me.TD(me, 1, 3, makeXonoticCheckBox(0, "showsound", _("Debug info about sounds")));
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "snd_restart; snd_attenuation_method_${menu_snd_attenuation_method}", COMMANDBUTTON_APPLY));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_effects.c b/qcsrc/menu/xonotic/dialog_settings_effects.c
deleted file mode 100644 (file)
index 59b4860..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticEffectsSettingsTab) EXTENDS(XonoticTab)
-       METHOD(XonoticEffectsSettingsTab, fill, void(entity))
-       ATTRIB(XonoticEffectsSettingsTab, title, string, _("Effects"))
-       ATTRIB(XonoticEffectsSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticEffectsSettingsTab, rows, float, 15.5)
-       ATTRIB(XonoticEffectsSettingsTab, columns, float, 6.2) // added extra .2 for center space
-ENDCLASS(XonoticEffectsSettingsTab)
-entity makeXonoticEffectsSettingsTab();
-float updateCompression();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticEffectsSettingsTab()
-{
-       entity me;
-       me = spawnXonoticEffectsSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-float someShadowCvarIsEnabled(entity box)
-{
-       if(cvar("r_shadow_realtime_dlight"))
-               if(cvar("r_shadow_realtime_dlight_shadows"))
-                       return TRUE;
-       if(cvar("r_shadow_realtime_world"))
-               if(cvar("r_shadow_realtime_world_shadows"))
-                       return TRUE;
-       return FALSE;
-}
-
-void XonoticEffectsSettingsTab_fill(entity me)
-{
-       entity e, s;
-       float n;
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Quality preset:")));
-               n = 5 + 2 * !!cvar("developer");
-               if(cvar("developer"))
-                       me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^OMG!")), '1 0 1', "exec effects-omg.cfg", 0));
-               me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Low")), '0 0 0', "exec effects-low.cfg", 0));
-               me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Medium")), '0 0 0', "exec effects-med.cfg", 0));
-               me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Normal")), '0 0 0', "exec effects-normal.cfg", 0));
-               me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^High")), '0 0 0', "exec effects-high.cfg", 0));
-               me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Ultra")), '0 0 0', "exec effects-ultra.cfg", 0));
-               if(cvar("developer"))
-                       me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Ultimate")), '0.5 0 0', "exec effects-ultimate.cfg", 0));
-
-       me.gotoRC(me, 1.25, 0);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Geometry detail:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("r_subdivisions_tolerance"));
-                       e.addValue(e, ZCTX(_("DET^Lowest")), "16");
-                       e.addValue(e, ZCTX(_("DET^Low")), "8");
-                       e.addValue(e, ZCTX(_("DET^Normal")), "4");
-                       e.addValue(e, ZCTX(_("DET^Good")), "3");
-                       e.addValue(e, ZCTX(_("DET^Best")), "2");
-                       e.addValue(e, ZCTX(_("DET^Insane")), "1");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Player detail:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_playerdetailreduction"));
-                       e.addValue(e, ZCTX(_("PDET^Low")), "4");
-                       e.addValue(e, ZCTX(_("PDET^Medium")), "3");
-                       e.addValue(e, ZCTX(_("PDET^Normal")), "2");
-                       e.addValue(e, ZCTX(_("PDET^Good")), "1");
-                       e.addValue(e, ZCTX(_("PDET^Best")), "0");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Texture resolution:")));
-                       setDependent(e, "r_showsurfaces", 0, 0);
-               me.TD(me, 1, 2, e = makeXonoticPicmipSlider());
-                       if(cvar("developer"))
-                               e.addValue(e, ZCTX(_("RES^Leet")), "1337");
-                       e.addValue(e, ZCTX(_("RES^Lowest")), "3");
-                       e.addValue(e, ZCTX(_("RES^Very low")), "2");
-                       e.addValue(e, ZCTX(_("RES^Low")), "1");
-                       e.addValue(e, ZCTX(_("RES^Normal")), "0");
-                       e.addValue(e, ZCTX(_("RES^Good")), "-1");
-                       e.addValue(e, ZCTX(_("RES^Best")), "-2");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "r_showsurfaces", 0, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               {
-                       // detect texture compression method
-                       float f;
-                       f = updateCompression();
-                       switch(f)
-                       {
-                               case 0:
-                                       me.TD(me, 1, 2.8, e = makeXonoticCheckBox(1, "r_texture_dds_load", _("Avoid lossy texture compression")));
-                                               e.disabled = 1; // just show the checkbox anyway, but with no ability to control it
-                                       break;
-                               case 1:
-                                       me.TD(me, 1, 2.8, e = makeXonoticCheckBox(1, "r_texture_dds_load", _("Avoid lossy texture compression")));
-                                               setDependent(e, "r_showsurfaces", 0, 0);
-                                       break;
-                               case 2:
-                                       me.TD(me, 1, 2.8, e = makeXonoticCheckBox(1, "r_texture_dds_load", _("Avoid lossy texture compression")));
-                                               setDependent(e, "r_showsurfaces", 0, 0);
-                                               makeMulti(e, "gl_texturecompression");
-                                       break;
-                       }
-               }
-       me.TR(me);
-               if(cvar("developer"))
-               {
-                       me.TDempty(me, 0.2);
-                       me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(3, 0, "r_showsurfaces", _("Show surfaces")));
-               }
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(1, "mod_q3bsp_nolightmaps", _("Use lightmaps")));
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_glsl_deluxemapping", _("Deluxe mapping")));
-                       setDependentAND(e, "vid_gl20", 1, 1, "mod_q3bsp_nolightmaps", 0, 0);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_shadow_gloss", _("Gloss")));
-                       setDependentAND3(e, "vid_gl20", 1, 1, "mod_q3bsp_nolightmaps", 0, 0, "r_glsl_deluxemapping", 1, 1);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_glsl_offsetmapping", _("Offset mapping")));
-                       setDependent(e, "vid_gl20", 1, 1);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_glsl_offsetmapping_reliefmapping", _("Relief mapping")));
-                       setDependentAND(e, "vid_gl20", 1, 1, "r_glsl_offsetmapping", 1, 1);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_water", _("Reflections:")));
-                       setDependent(e, "vid_gl20", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("r_water_resolutionmultiplier"));
-                       e.addValue(e, _("Blurred"), "0.25");
-                       e.addValue(e, ZCTX(_("REFL^Good")), "0.5");
-                       e.addValue(e, _("Sharp"), "1");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependentAND(e, "vid_gl20", 1, 1, "r_water", 1, 1);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_decals", _("Decals")));
-               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_decals_models", _("Decals on models")));
-                       setDependent(e, "cl_decals", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
-                       setDependent(e, "cl_decals", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(200, 500, 20, "r_drawdecals_drawdistance"));
-                       setDependent(e, "cl_decals", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Time:")));
-                       setDependent(e, "cl_decals", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(1, 20, 1, "cl_decals_fadetime"));
-                       setDependent(e, "cl_decals", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Damage effects:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_damageeffect"));
-                       e.addValue(e, _("Disabled"), "0");
-                       e.addValue(e, _("Skeletal"), "1");
-                       e.addValue(e, _("All"), "2");
-                       e.configureXonoticTextSliderValues(e);
-
-       me.gotoRC(me, 1.25, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "r_coronas", "0", _("No dynamic lighting")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "gl_flashblend", string_null, _("Fake corona lighting")));
-               makeMulti(e, "r_coronas");
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "r_shadow_realtime_dlight", string_null, _("Realtime dynamic lighting")));
-               makeMulti(e, "r_coronas");
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_shadow_realtime_dlight_shadows", _("Shadows")));
-                       setDependent(e, "r_shadow_realtime_dlight", 1, 1);
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "r_shadow_realtime_world", _("Realtime world lighting")));
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(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, 1.8, e = makeXonoticCheckBox(0, "r_shadow_usenormalmap", _("Use normal maps")));
-                       setDependentOR(e, "r_shadow_realtime_dlight", 1, 1, "r_shadow_realtime_world", 1, 1);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_shadow_shadowmapping", _("Soft shadows")));
-                       setDependentWeird(e, someShadowCvarIsEnabled);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "r_coronas_occlusionquery", _("Fade corona according to visibility")));
-                       setDependent(e, "r_coronas", 1, 1);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_bloom", _("Bloom")));
-               me.TD(me, 1, 2, e = makeXonoticCheckBoxEx(0.5, 0, "hud_postprocessing_maxbluralpha", _("Extra postprocessing effects")));
-                       makeMulti(e, "hud_powerup");
-                       setDependent(e, "vid_gl20", 1, 1);
-       me.TR(me);
-               s = makeXonoticSlider(0.1, 1, 0.1, "r_motionblur");
-               me.TD(me, 1, 1, e = makeXonoticSliderCheckBox(0, 1, s, _("Motion blur:")));
-               if(s.value != e.savedValue)
-                       e.savedValue = 0.4; // default
-               me.TD(me, 1, 2, s);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_particles", _("Particles")));
-               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_spawn_point_particles", _("Spawnpoint effects")));
-                       makeMulti(e, "cl_spawn_event_particles");
-                       setDependent(e, "cl_particles", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Quality:")));
-                       setDependent(e, "cl_particles", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticParticlesSlider());
-                       setDependent(e, "cl_particles", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
-                       setDependent(e, "cl_particles", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(200, 500, 20, "r_drawparticles_drawdistance"));
-                       setDependent(e, "cl_particles", 1, 1);
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "vid_restart", COMMANDBUTTON_APPLY));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_effects.qc b/qcsrc/menu/xonotic/dialog_settings_effects.qc
new file mode 100644 (file)
index 0000000..59b4860
--- /dev/null
@@ -0,0 +1,215 @@
+#ifdef INTERFACE
+CLASS(XonoticEffectsSettingsTab) EXTENDS(XonoticTab)
+       METHOD(XonoticEffectsSettingsTab, fill, void(entity))
+       ATTRIB(XonoticEffectsSettingsTab, title, string, _("Effects"))
+       ATTRIB(XonoticEffectsSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticEffectsSettingsTab, rows, float, 15.5)
+       ATTRIB(XonoticEffectsSettingsTab, columns, float, 6.2) // added extra .2 for center space
+ENDCLASS(XonoticEffectsSettingsTab)
+entity makeXonoticEffectsSettingsTab();
+float updateCompression();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticEffectsSettingsTab()
+{
+       entity me;
+       me = spawnXonoticEffectsSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+float someShadowCvarIsEnabled(entity box)
+{
+       if(cvar("r_shadow_realtime_dlight"))
+               if(cvar("r_shadow_realtime_dlight_shadows"))
+                       return TRUE;
+       if(cvar("r_shadow_realtime_world"))
+               if(cvar("r_shadow_realtime_world_shadows"))
+                       return TRUE;
+       return FALSE;
+}
+
+void XonoticEffectsSettingsTab_fill(entity me)
+{
+       entity e, s;
+       float n;
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Quality preset:")));
+               n = 5 + 2 * !!cvar("developer");
+               if(cvar("developer"))
+                       me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^OMG!")), '1 0 1', "exec effects-omg.cfg", 0));
+               me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Low")), '0 0 0', "exec effects-low.cfg", 0));
+               me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Medium")), '0 0 0', "exec effects-med.cfg", 0));
+               me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Normal")), '0 0 0', "exec effects-normal.cfg", 0));
+               me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^High")), '0 0 0', "exec effects-high.cfg", 0));
+               me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Ultra")), '0 0 0', "exec effects-ultra.cfg", 0));
+               if(cvar("developer"))
+                       me.TD(me, 1, 5 / n, e = makeXonoticCommandButton(ZCTX(_("PRE^Ultimate")), '0.5 0 0', "exec effects-ultimate.cfg", 0));
+
+       me.gotoRC(me, 1.25, 0);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Geometry detail:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("r_subdivisions_tolerance"));
+                       e.addValue(e, ZCTX(_("DET^Lowest")), "16");
+                       e.addValue(e, ZCTX(_("DET^Low")), "8");
+                       e.addValue(e, ZCTX(_("DET^Normal")), "4");
+                       e.addValue(e, ZCTX(_("DET^Good")), "3");
+                       e.addValue(e, ZCTX(_("DET^Best")), "2");
+                       e.addValue(e, ZCTX(_("DET^Insane")), "1");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Player detail:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_playerdetailreduction"));
+                       e.addValue(e, ZCTX(_("PDET^Low")), "4");
+                       e.addValue(e, ZCTX(_("PDET^Medium")), "3");
+                       e.addValue(e, ZCTX(_("PDET^Normal")), "2");
+                       e.addValue(e, ZCTX(_("PDET^Good")), "1");
+                       e.addValue(e, ZCTX(_("PDET^Best")), "0");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Texture resolution:")));
+                       setDependent(e, "r_showsurfaces", 0, 0);
+               me.TD(me, 1, 2, e = makeXonoticPicmipSlider());
+                       if(cvar("developer"))
+                               e.addValue(e, ZCTX(_("RES^Leet")), "1337");
+                       e.addValue(e, ZCTX(_("RES^Lowest")), "3");
+                       e.addValue(e, ZCTX(_("RES^Very low")), "2");
+                       e.addValue(e, ZCTX(_("RES^Low")), "1");
+                       e.addValue(e, ZCTX(_("RES^Normal")), "0");
+                       e.addValue(e, ZCTX(_("RES^Good")), "-1");
+                       e.addValue(e, ZCTX(_("RES^Best")), "-2");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "r_showsurfaces", 0, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               {
+                       // detect texture compression method
+                       float f;
+                       f = updateCompression();
+                       switch(f)
+                       {
+                               case 0:
+                                       me.TD(me, 1, 2.8, e = makeXonoticCheckBox(1, "r_texture_dds_load", _("Avoid lossy texture compression")));
+                                               e.disabled = 1; // just show the checkbox anyway, but with no ability to control it
+                                       break;
+                               case 1:
+                                       me.TD(me, 1, 2.8, e = makeXonoticCheckBox(1, "r_texture_dds_load", _("Avoid lossy texture compression")));
+                                               setDependent(e, "r_showsurfaces", 0, 0);
+                                       break;
+                               case 2:
+                                       me.TD(me, 1, 2.8, e = makeXonoticCheckBox(1, "r_texture_dds_load", _("Avoid lossy texture compression")));
+                                               setDependent(e, "r_showsurfaces", 0, 0);
+                                               makeMulti(e, "gl_texturecompression");
+                                       break;
+                       }
+               }
+       me.TR(me);
+               if(cvar("developer"))
+               {
+                       me.TDempty(me, 0.2);
+                       me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(3, 0, "r_showsurfaces", _("Show surfaces")));
+               }
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(1, "mod_q3bsp_nolightmaps", _("Use lightmaps")));
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_glsl_deluxemapping", _("Deluxe mapping")));
+                       setDependentAND(e, "vid_gl20", 1, 1, "mod_q3bsp_nolightmaps", 0, 0);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_shadow_gloss", _("Gloss")));
+                       setDependentAND3(e, "vid_gl20", 1, 1, "mod_q3bsp_nolightmaps", 0, 0, "r_glsl_deluxemapping", 1, 1);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_glsl_offsetmapping", _("Offset mapping")));
+                       setDependent(e, "vid_gl20", 1, 1);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_glsl_offsetmapping_reliefmapping", _("Relief mapping")));
+                       setDependentAND(e, "vid_gl20", 1, 1, "r_glsl_offsetmapping", 1, 1);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_water", _("Reflections:")));
+                       setDependent(e, "vid_gl20", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("r_water_resolutionmultiplier"));
+                       e.addValue(e, _("Blurred"), "0.25");
+                       e.addValue(e, ZCTX(_("REFL^Good")), "0.5");
+                       e.addValue(e, _("Sharp"), "1");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependentAND(e, "vid_gl20", 1, 1, "r_water", 1, 1);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_decals", _("Decals")));
+               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_decals_models", _("Decals on models")));
+                       setDependent(e, "cl_decals", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
+                       setDependent(e, "cl_decals", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(200, 500, 20, "r_drawdecals_drawdistance"));
+                       setDependent(e, "cl_decals", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Time:")));
+                       setDependent(e, "cl_decals", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(1, 20, 1, "cl_decals_fadetime"));
+                       setDependent(e, "cl_decals", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Damage effects:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_damageeffect"));
+                       e.addValue(e, _("Disabled"), "0");
+                       e.addValue(e, _("Skeletal"), "1");
+                       e.addValue(e, _("All"), "2");
+                       e.configureXonoticTextSliderValues(e);
+
+       me.gotoRC(me, 1.25, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "r_coronas", "0", _("No dynamic lighting")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "gl_flashblend", string_null, _("Fake corona lighting")));
+               makeMulti(e, "r_coronas");
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "r_shadow_realtime_dlight", string_null, _("Realtime dynamic lighting")));
+               makeMulti(e, "r_coronas");
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_shadow_realtime_dlight_shadows", _("Shadows")));
+                       setDependent(e, "r_shadow_realtime_dlight", 1, 1);
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "r_shadow_realtime_world", _("Realtime world lighting")));
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(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, 1.8, e = makeXonoticCheckBox(0, "r_shadow_usenormalmap", _("Use normal maps")));
+                       setDependentOR(e, "r_shadow_realtime_dlight", 1, 1, "r_shadow_realtime_world", 1, 1);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_shadow_shadowmapping", _("Soft shadows")));
+                       setDependentWeird(e, someShadowCvarIsEnabled);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "r_coronas_occlusionquery", _("Fade corona according to visibility")));
+                       setDependent(e, "r_coronas", 1, 1);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_bloom", _("Bloom")));
+               me.TD(me, 1, 2, e = makeXonoticCheckBoxEx(0.5, 0, "hud_postprocessing_maxbluralpha", _("Extra postprocessing effects")));
+                       makeMulti(e, "hud_powerup");
+                       setDependent(e, "vid_gl20", 1, 1);
+       me.TR(me);
+               s = makeXonoticSlider(0.1, 1, 0.1, "r_motionblur");
+               me.TD(me, 1, 1, e = makeXonoticSliderCheckBox(0, 1, s, _("Motion blur:")));
+               if(s.value != e.savedValue)
+                       e.savedValue = 0.4; // default
+               me.TD(me, 1, 2, s);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_particles", _("Particles")));
+               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_spawn_point_particles", _("Spawnpoint effects")));
+                       makeMulti(e, "cl_spawn_event_particles");
+                       setDependent(e, "cl_particles", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Quality:")));
+                       setDependent(e, "cl_particles", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticParticlesSlider());
+                       setDependent(e, "cl_particles", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
+                       setDependent(e, "cl_particles", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(200, 500, 20, "r_drawparticles_drawdistance"));
+                       setDependent(e, "cl_particles", 1, 1);
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "vid_restart", COMMANDBUTTON_APPLY));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game.c b/qcsrc/menu/xonotic/dialog_settings_game.c
deleted file mode 100644 (file)
index 2f48c2a..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticGameSettingsTab) EXTENDS(XonoticTab)
-       METHOD(XonoticGameSettingsTab, fill, void(entity))
-       ATTRIB(XonoticGameSettingsTab, title, string, _("Game"))
-       ATTRIB(XonoticGameSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticGameSettingsTab, rows, float, 15.5)
-       ATTRIB(XonoticGameSettingsTab, columns, float, 6.5)
-ENDCLASS(XonoticGameSettingsTab)
-entity makeXonoticGameSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticGameSettingsTab()
-{
-       entity me;
-       me = spawnXonoticGameSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void XonoticGameSettingsTab_fill(entity me)
-{
-       entity mc;
-       mc = makeXonoticTabController(me.rows - 2.5);
-       
-       me.TR(me);
-               me.TDempty(me, 0.25);
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("View"),           makeXonoticGameViewSettingsTab()));
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Crosshair"),      makeXonoticGameCrosshairSettingsTab()));
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("HUD"),            makeXonoticGameHUDSettingsTab()));
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Messages"),       makeXonoticGameMessageSettingsTab()));
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Weapons"),        makeXonoticGameWeaponsSettingsTab()));
-               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Models"),         makeXonoticGameModelSettingsTab()));
-
-       me.gotoRC(me, 1.5, 0);
-               me.TD(me, me.rows - 1.5, me.columns, mc);
-               
-       /*
-
-         makeXonoticGameViewSettingsTab()));
-         makeXonoticGameGeneralSettingsTab()));
-       makeXonoticGameCrosshairSettingsTab()));
-       
-              makeXonoticGameWeaponSettingsTab()));
-       l"),   makeXonoticGamePlayermodelSettingsTab()));
-              makeXonoticGameHUDSettingsTab()));
-       on"),  makeXonoticGameNotificationSettingsTab()));
-
-
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_gentle", _("Disable gore effects and harsh language"))); // also set sv_gentle
-       */
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game.qc b/qcsrc/menu/xonotic/dialog_settings_game.qc
new file mode 100644 (file)
index 0000000..2f48c2a
--- /dev/null
@@ -0,0 +1,54 @@
+#ifdef INTERFACE
+CLASS(XonoticGameSettingsTab) EXTENDS(XonoticTab)
+       METHOD(XonoticGameSettingsTab, fill, void(entity))
+       ATTRIB(XonoticGameSettingsTab, title, string, _("Game"))
+       ATTRIB(XonoticGameSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameSettingsTab, rows, float, 15.5)
+       ATTRIB(XonoticGameSettingsTab, columns, float, 6.5)
+ENDCLASS(XonoticGameSettingsTab)
+entity makeXonoticGameSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticGameSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameSettingsTab_fill(entity me)
+{
+       entity mc;
+       mc = makeXonoticTabController(me.rows - 2.5);
+       
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("View"),           makeXonoticGameViewSettingsTab()));
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Crosshair"),      makeXonoticGameCrosshairSettingsTab()));
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("HUD"),            makeXonoticGameHUDSettingsTab()));
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Messages"),       makeXonoticGameMessageSettingsTab()));
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Weapons"),        makeXonoticGameWeaponsSettingsTab()));
+               me.TD(me, 1, 1, mc.makeTabButton(mc, _("Models"),         makeXonoticGameModelSettingsTab()));
+
+       me.gotoRC(me, 1.5, 0);
+               me.TD(me, me.rows - 1.5, me.columns, mc);
+               
+       /*
+
+         makeXonoticGameViewSettingsTab()));
+         makeXonoticGameGeneralSettingsTab()));
+       makeXonoticGameCrosshairSettingsTab()));
+       
+              makeXonoticGameWeaponSettingsTab()));
+       l"),   makeXonoticGamePlayermodelSettingsTab()));
+              makeXonoticGameHUDSettingsTab()));
+       on"),  makeXonoticGameNotificationSettingsTab()));
+
+
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_gentle", _("Disable gore effects and harsh language"))); // also set sv_gentle
+       */
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_crosshair.c b/qcsrc/menu/xonotic/dialog_settings_game_crosshair.c
deleted file mode 100644 (file)
index 3e164c1..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticGameCrosshairSettingsTab) EXTENDS(XonoticTab)
-       //METHOD(XonoticGameCrosshairSettingsTab, toString, string(entity))
-       METHOD(XonoticGameCrosshairSettingsTab, fill, void(entity))
-       METHOD(XonoticGameCrosshairSettingsTab, showNotify, void(entity))
-       ATTRIB(XonoticGameCrosshairSettingsTab, title, string, _("Crosshair"))
-       ATTRIB(XonoticGameCrosshairSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticGameCrosshairSettingsTab, rows, float, 13)
-       ATTRIB(XonoticGameCrosshairSettingsTab, columns, float, 6.2)
-ENDCLASS(XonoticGameCrosshairSettingsTab)
-entity makeXonoticGameCrosshairSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticGameCrosshairSettingsTab_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-entity makeXonoticGameCrosshairSettingsTab()
-{
-       entity me;
-       me = spawnXonoticGameCrosshairSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void XonoticGameCrosshairSettingsTab_fill(entity me)
-{
-       entity e;
-       float i;
-
-       // crosshair_enabled: 0 = no crosshair options, 1 = no crosshair selection, but everything else enabled, 2 = all crosshair options enabled
-       // FIXME: In the future, perhaps make one global crosshair_type cvar which has 0 for disabled, 1 for custom, 2 for per weapon, etc?
-       me.TR(me); //me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_enabled", "0", _("No crosshair")));
-       //me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_per_weapon", string_null, _("Per weapon")));
-               makeMulti(e, "crosshair_enabled");
-       //me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_enabled", "2", _("Custom")));
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               for(i = 1; i <= 14; ++i) {
-                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
-                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
-               }
-               // show a larger preview of the selected crosshair
-               me.TDempty(me, 0.1);
-               me.TDNoMargin(me, 3, 0.8, e = makeXonoticCrosshairButton(7, -1), '1 1 0'); // crosshair -1 makes this a preview
-                       setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               for(i = 15; i <= 28; ++i) {
-                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
-                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
-               }
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair size:")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 1.9, e = makeXonoticSlider(0.1, 1.0, 0.01, "crosshair_size"));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair alpha:")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 1.9, e = makeXonoticSlider(0, 1, 0.1, "crosshair_alpha"));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair color:")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(5, "crosshair_color_special", "1", _("Per weapon")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(5, "crosshair_color_special", "2", _("By health")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticRadioButton(5, "crosshair_color_special", "0", _("Custom")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-               me.TD(me, 2, 2, e = makeXonoticColorpickerString("crosshair_color", "crosshair_color"));
-                       setDependentAND(e, "crosshair_color_special", 0, 0, "crosshair_enabled", 1, 2);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 2.9, e = makeXonoticCheckBox(0, "crosshair_ring", _("Use rings to indicate weapon status")));
-                       makeMulti(e, "crosshair_ring_reload");
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       //me.TR(me);
-       //      me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Ring size:")));
-       //              setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
-       //      me.TD(me, 1, 2, e = makeXonoticSlider(2, 4, 0.1, "crosshair_ring_size"));
-       //              setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.3);
-               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Ring alpha:")));
-                       setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 1.8, e = makeXonoticSlider(0.1, 1, 0.1, "crosshair_ring_alpha"));
-                       setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
-       
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_dot", _("Enable center crosshair dot")));
-               setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Dot size:")));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.2, 2, 0.1, "crosshair_dot_size"));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Dot alpha:")));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.1, "crosshair_dot_alpha"));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Dot color:")));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-               me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "crosshair_dot_color_custom", "0", _("Use normal crosshair color")));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticRadioButton(1, "crosshair_dot_color_custom", "1", _("Custom")));
-                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
-               me.TD(me, 2, 2, e = makeXonoticColorpickerString("crosshair_dot_color", "crosshair_dot_color"));
-                       setDependentAND3(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2, "crosshair_dot_color_custom", 1, 1);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_effect_scalefade", _("Smooth effects of crosshairs")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_hittest_blur", _("Blur crosshair if the shot is obstructed")));
-                       setDependentAND(e, "crosshair_hittest", 1, 100, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(1.25, 0, "crosshair_hittest_scale", _("Enlarge crosshair if targeting an enemy")));
-                       setDependentAND(e, "crosshair_hittest", 1, 100, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(0.5, 0, "crosshair_hitindication", _("Animate crosshair when hitting an enemy")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(0.25, 0, "crosshair_pickup", _("Animate crosshair when picking up an item")));
-                       setDependent(e, "crosshair_enabled", 1, 2);
-       /*me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Hit testing:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("crosshair_hittest"));
-                       e.addValue(e, ZCTX(_("HTTST^Disabled")), "0");
-                       e.addValue(e, ZCTX(_("HTTST^TrueAim")), "1");
-                       e.addValue(e, ZCTX(_("HTTST^Enemies")), "1.25");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "crosshair_enabled", 1, 2);*/
-                       
-       /*me.TR(me);
-                       
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;*/
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc b/qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc
new file mode 100644 (file)
index 0000000..3e164c1
--- /dev/null
@@ -0,0 +1,163 @@
+#ifdef INTERFACE
+CLASS(XonoticGameCrosshairSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameCrosshairSettingsTab, toString, string(entity))
+       METHOD(XonoticGameCrosshairSettingsTab, fill, void(entity))
+       METHOD(XonoticGameCrosshairSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameCrosshairSettingsTab, title, string, _("Crosshair"))
+       ATTRIB(XonoticGameCrosshairSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameCrosshairSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameCrosshairSettingsTab, columns, float, 6.2)
+ENDCLASS(XonoticGameCrosshairSettingsTab)
+entity makeXonoticGameCrosshairSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticGameCrosshairSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameCrosshairSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameCrosshairSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameCrosshairSettingsTab_fill(entity me)
+{
+       entity e;
+       float i;
+
+       // crosshair_enabled: 0 = no crosshair options, 1 = no crosshair selection, but everything else enabled, 2 = all crosshair options enabled
+       // FIXME: In the future, perhaps make one global crosshair_type cvar which has 0 for disabled, 1 for custom, 2 for per weapon, etc?
+       me.TR(me); //me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_enabled", "0", _("No crosshair")));
+       //me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_per_weapon", string_null, _("Per weapon")));
+               makeMulti(e, "crosshair_enabled");
+       //me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_enabled", "2", _("Custom")));
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               for(i = 1; i <= 14; ++i) {
+                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
+                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
+               }
+               // show a larger preview of the selected crosshair
+               me.TDempty(me, 0.1);
+               me.TDNoMargin(me, 3, 0.8, e = makeXonoticCrosshairButton(7, -1), '1 1 0'); // crosshair -1 makes this a preview
+                       setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               for(i = 15; i <= 28; ++i) {
+                       me.TDNoMargin(me, 1, 2 / 14, e = makeXonoticCrosshairButton(4, i), '1 1 0');
+                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
+               }
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair size:")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 1.9, e = makeXonoticSlider(0.1, 1.0, 0.01, "crosshair_size"));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair alpha:")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 1.9, e = makeXonoticSlider(0, 1, 0.1, "crosshair_alpha"));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair color:")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(5, "crosshair_color_special", "1", _("Per weapon")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(5, "crosshair_color_special", "2", _("By health")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticRadioButton(5, "crosshair_color_special", "0", _("Custom")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+               me.TD(me, 2, 2, e = makeXonoticColorpickerString("crosshair_color", "crosshair_color"));
+                       setDependentAND(e, "crosshair_color_special", 0, 0, "crosshair_enabled", 1, 2);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 2.9, e = makeXonoticCheckBox(0, "crosshair_ring", _("Use rings to indicate weapon status")));
+                       makeMulti(e, "crosshair_ring_reload");
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       //me.TR(me);
+       //      me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Ring size:")));
+       //              setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
+       //      me.TD(me, 1, 2, e = makeXonoticSlider(2, 4, 0.1, "crosshair_ring_size"));
+       //              setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.3);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Ring alpha:")));
+                       setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 1.8, e = makeXonoticSlider(0.1, 1, 0.1, "crosshair_ring_alpha"));
+                       setDependentAND(e, "crosshair_ring", 1, 1, "crosshair_enabled", 1, 2);
+       
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_dot", _("Enable center crosshair dot")));
+               setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Dot size:")));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.2, 2, 0.1, "crosshair_dot_size"));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Dot alpha:")));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.1, "crosshair_dot_alpha"));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Dot color:")));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+               me.TD(me, 1, 2, e = makeXonoticRadioButton(1, "crosshair_dot_color_custom", "0", _("Use normal crosshair color")));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticRadioButton(1, "crosshair_dot_color_custom", "1", _("Custom")));
+                       setDependentAND(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2);
+               me.TD(me, 2, 2, e = makeXonoticColorpickerString("crosshair_dot_color", "crosshair_dot_color"));
+                       setDependentAND3(e, "crosshair_dot", 1, 1, "crosshair_enabled", 1, 2, "crosshair_dot_color_custom", 1, 1);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_effect_scalefade", _("Smooth effects of crosshairs")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "crosshair_hittest_blur", _("Blur crosshair if the shot is obstructed")));
+                       setDependentAND(e, "crosshair_hittest", 1, 100, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(1.25, 0, "crosshair_hittest_scale", _("Enlarge crosshair if targeting an enemy")));
+                       setDependentAND(e, "crosshair_hittest", 1, 100, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(0.5, 0, "crosshair_hitindication", _("Animate crosshair when hitting an enemy")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(0.25, 0, "crosshair_pickup", _("Animate crosshair when picking up an item")));
+                       setDependent(e, "crosshair_enabled", 1, 2);
+       /*me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Hit testing:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("crosshair_hittest"));
+                       e.addValue(e, ZCTX(_("HTTST^Disabled")), "0");
+                       e.addValue(e, ZCTX(_("HTTST^TrueAim")), "1");
+                       e.addValue(e, ZCTX(_("HTTST^Enemies")), "1.25");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "crosshair_enabled", 1, 2);*/
+                       
+       /*me.TR(me);
+                       
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;*/
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_hud.c b/qcsrc/menu/xonotic/dialog_settings_game_hud.c
deleted file mode 100644 (file)
index fc7e3a1..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticGameHUDSettingsTab) EXTENDS(XonoticTab)
-       //METHOD(XonoticGameHUDSettingsTab, toString, string(entity))
-       METHOD(XonoticGameHUDSettingsTab, fill, void(entity))
-       METHOD(XonoticGameHUDSettingsTab, showNotify, void(entity))
-       ATTRIB(XonoticGameHUDSettingsTab, title, string, _("HUD"))
-       ATTRIB(XonoticGameHUDSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticGameHUDSettingsTab, rows, float, 13)
-       ATTRIB(XonoticGameHUDSettingsTab, columns, float, 6.2)
-ENDCLASS(XonoticGameHUDSettingsTab)
-entity makeXonoticGameHUDSettingsTab();
-void HUDSetup_Start(entity me, entity btn);
-#endif
-
-#ifdef IMPLEMENTATION
-void HUDSetup_Check_Gamestatus(entity me, entity btn)
-{
-       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, ask the player if they want to start one anyway
-       {
-               DialogOpenButton_Click(me, main.hudconfirmDialog);
-       }
-       else // already in a match, lets just cut to the point and open up the hud editor directly
-       {
-               HUDSetup_Start(me, btn);
-       }
-}
-void XonoticGameHUDSettingsTab_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-entity makeXonoticGameHUDSettingsTab()
-{
-       entity me;
-       me = spawnXonoticGameHUDSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void XonoticGameHUDSettingsTab_fill(entity me)
-{
-       entity e;
-
-       // todo:
-       // threshold: hud_damage_pain_threshold_lower_health
-       // scoreboard_alpha*
-
-       //me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Scoreboard")));
-       //me.TR(me);
-       //      me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Alpha:")));
-       //      me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "scoreboard_alpha_bg"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Fading speed:")));
-               me.TD(me, 1, 2, e = makeXonoticScoreboardFadeTimeSlider());
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Side padding:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.05, 0.3, 0.01, "scoreboard_offset_left"));
-                       makeMulti(e, "scoreboard_offset_right");
-
-       me.TR(me);
-       //me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "scoreboard_respawntime_decimals", _("Show decimals in respawn countdown")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "scoreboard_accuracy", _("Show accuracy underneath scoreboard")));
-
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Waypoints")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_hidewaypoints", _("Display waypoint markers for objectives on the map")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Alpha:")));
-                       setDependent(e, "cl_hidewaypoints", 0, 0);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.05, "g_waypointsprite_alpha"));
-                       setDependent(e, "cl_hidewaypoints", 0, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Fontsize:")));
-                       setDependent(e, "cl_hidewaypoints", 0, 0);
-               me.TD(me, 1, 2, e = makeXonoticSlider(5, 16, 1, "g_waypointsprite_fontsize"));
-                       setDependent(e, "cl_hidewaypoints", 0, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Edge offset:")));
-                       setDependent(e, "cl_hidewaypoints", 0, 0);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 0.3, 0.01, "g_waypointsprite_edgeoffset_bottom"));
-                       makeMulti(e, "g_waypointsprite_edgeoffset_top g_waypointsprite_edgeoffset_left g_waypointsprite_edgeoffset_right");
-                       setDependent(e, "cl_hidewaypoints", 0, 0);
-
-       me.TR(me);
-       //me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.25, 1, "g_waypointsprite_crosshairfadealpha", _("Fade when near the crosshair")));
-                       setDependent(e, "cl_hidewaypoints", 0, 0);
-
-       #if 0
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Damage")));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Overlay:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "hud_damage"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Factor:")));
-                       setDependent(e, "hud_damage", 0.001, 100);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.025, 0.1, 0.025, "hud_damage_factor"));
-                       setDependent(e, "hud_damage", 0.001, 100);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Fade rate:")));
-                       setDependent(e, "hud_damage", 0.001, 100);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.25, 1, 0.05, "hud_damage_fade_rate"));
-                       setDependent(e, "hud_damage", 0.001, 100);
-       me.TR(me);
-       #endif
-
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Player Names")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_shownames", _("Show names above players")));
-
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Alpha:")));
-                       setDependent(e, "hud_shownames", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.05, "hud_shownames_alpha"));
-                       setDependent(e, "hud_shownames", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Fontsize:")));
-                       setDependent(e, "hud_shownames", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(5, 16, 1, "hud_shownames_fontsize"));
-                       setDependent(e, "hud_shownames", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Max distance:")));
-                       setDependent(e, "hud_shownames", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(2000, 10000, 500, "hud_shownames_maxdistance"));
-                       setDependent(e, "hud_shownames", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Decolorize:")));
-                       setDependent(e, "hud_shownames", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("hud_shownames_decolorize"));
-                       e.addValue(e, ZCTX(_("Never")), "0");
-                       e.addValue(e, ZCTX(_("Teamplay")), "1");
-                       e.addValue(e, ZCTX(_("Always")), "2");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "hud_shownames", 1, 1);
-
-       me.TR(me);
-       //me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(25, 0, "hud_shownames_crosshairdistance", _("Only when near crosshair")));
-                       setDependent(e, "hud_shownames", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "hud_shownames_status", _("Display health and armor")));
-                       setDependent(e, "hud_shownames", 1, 1);
-
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Damage overlay:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "hud_damage"));
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("Enter HUD editor"), '0 0 0'));
-                       e.onClick = HUDSetup_Check_Gamestatus;
-                       e.onClickEntity = me;
-               // TODO: show hud config name with text here
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_hud.qc b/qcsrc/menu/xonotic/dialog_settings_game_hud.qc
new file mode 100644 (file)
index 0000000..fc7e3a1
--- /dev/null
@@ -0,0 +1,173 @@
+#ifdef INTERFACE
+CLASS(XonoticGameHUDSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameHUDSettingsTab, toString, string(entity))
+       METHOD(XonoticGameHUDSettingsTab, fill, void(entity))
+       METHOD(XonoticGameHUDSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameHUDSettingsTab, title, string, _("HUD"))
+       ATTRIB(XonoticGameHUDSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameHUDSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameHUDSettingsTab, columns, float, 6.2)
+ENDCLASS(XonoticGameHUDSettingsTab)
+entity makeXonoticGameHUDSettingsTab();
+void HUDSetup_Start(entity me, entity btn);
+#endif
+
+#ifdef IMPLEMENTATION
+void HUDSetup_Check_Gamestatus(entity me, entity btn)
+{
+       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER))) // we're not in a match, ask the player if they want to start one anyway
+       {
+               DialogOpenButton_Click(me, main.hudconfirmDialog);
+       }
+       else // already in a match, lets just cut to the point and open up the hud editor directly
+       {
+               HUDSetup_Start(me, btn);
+       }
+}
+void XonoticGameHUDSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameHUDSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameHUDSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameHUDSettingsTab_fill(entity me)
+{
+       entity e;
+
+       // todo:
+       // threshold: hud_damage_pain_threshold_lower_health
+       // scoreboard_alpha*
+
+       //me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Scoreboard")));
+       //me.TR(me);
+       //      me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Alpha:")));
+       //      me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "scoreboard_alpha_bg"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Fading speed:")));
+               me.TD(me, 1, 2, e = makeXonoticScoreboardFadeTimeSlider());
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Side padding:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.05, 0.3, 0.01, "scoreboard_offset_left"));
+                       makeMulti(e, "scoreboard_offset_right");
+
+       me.TR(me);
+       //me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "scoreboard_respawntime_decimals", _("Show decimals in respawn countdown")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "scoreboard_accuracy", _("Show accuracy underneath scoreboard")));
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Waypoints")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_hidewaypoints", _("Display waypoint markers for objectives on the map")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Alpha:")));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.05, "g_waypointsprite_alpha"));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Fontsize:")));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+               me.TD(me, 1, 2, e = makeXonoticSlider(5, 16, 1, "g_waypointsprite_fontsize"));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Edge offset:")));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 0.3, 0.01, "g_waypointsprite_edgeoffset_bottom"));
+                       makeMulti(e, "g_waypointsprite_edgeoffset_top g_waypointsprite_edgeoffset_left g_waypointsprite_edgeoffset_right");
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+
+       me.TR(me);
+       //me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.25, 1, "g_waypointsprite_crosshairfadealpha", _("Fade when near the crosshair")));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
+
+       #if 0
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Damage")));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Overlay:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "hud_damage"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Factor:")));
+                       setDependent(e, "hud_damage", 0.001, 100);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.025, 0.1, 0.025, "hud_damage_factor"));
+                       setDependent(e, "hud_damage", 0.001, 100);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Fade rate:")));
+                       setDependent(e, "hud_damage", 0.001, 100);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.25, 1, 0.05, "hud_damage_fade_rate"));
+                       setDependent(e, "hud_damage", 0.001, 100);
+       me.TR(me);
+       #endif
+
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Player Names")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "hud_shownames", _("Show names above players")));
+
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Alpha:")));
+                       setDependent(e, "hud_shownames", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.1, 1, 0.05, "hud_shownames_alpha"));
+                       setDependent(e, "hud_shownames", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Fontsize:")));
+                       setDependent(e, "hud_shownames", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(5, 16, 1, "hud_shownames_fontsize"));
+                       setDependent(e, "hud_shownames", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Max distance:")));
+                       setDependent(e, "hud_shownames", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(2000, 10000, 500, "hud_shownames_maxdistance"));
+                       setDependent(e, "hud_shownames", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Decolorize:")));
+                       setDependent(e, "hud_shownames", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("hud_shownames_decolorize"));
+                       e.addValue(e, ZCTX(_("Never")), "0");
+                       e.addValue(e, ZCTX(_("Teamplay")), "1");
+                       e.addValue(e, ZCTX(_("Always")), "2");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "hud_shownames", 1, 1);
+
+       me.TR(me);
+       //me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(25, 0, "hud_shownames_crosshairdistance", _("Only when near crosshair")));
+                       setDependent(e, "hud_shownames", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "hud_shownames_status", _("Display health and armor")));
+                       setDependent(e, "hud_shownames", 1, 1);
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Damage overlay:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.05, "hud_damage"));
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 0.5);
+               me.TD(me, 1, 2, e = makeXonoticButton(_("Enter HUD editor"), '0 0 0'));
+                       e.onClick = HUDSetup_Check_Gamestatus;
+                       e.onClickEntity = me;
+               // TODO: show hud config name with text here
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.c b/qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.c
deleted file mode 100644 (file)
index 7749a14..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticHUDConfirmDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticHUDConfirmDialog, fill, void(entity))
-       ATTRIB(XonoticHUDConfirmDialog, title, string, _("Enter HUD editor"))
-       ATTRIB(XonoticHUDConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
-       ATTRIB(XonoticHUDConfirmDialog, intendedWidth, float, 0.5)
-       ATTRIB(XonoticHUDConfirmDialog, rows, float, 4)
-       ATTRIB(XonoticHUDConfirmDialog, columns, float, 2)
-ENDCLASS(XonoticHUDConfirmDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void HUDSetup_Start(entity me, entity btn)
-{
-       if (!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
-               localcmd("map hudsetup/hudsetup", "\n");
-       else
-               localcmd("togglemenu 0\n");
-
-       localcmd("_hud_configure 1", "\n");
-}
-
-void XonoticHUDConfirmDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("In order for the HUD editor to show, you must first be in game.")));
-       me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you wish to start a local game to set up the HUD?")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("HDCNFRM^Yes")), '1 0 0'));
-                       e.onClick = HUDSetup_Start;
-                       e.onClickEntity = me;
-               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("HDCNFRM^No")), '0 1 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc b/qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc
new file mode 100644 (file)
index 0000000..7749a14
--- /dev/null
@@ -0,0 +1,40 @@
+#ifdef INTERFACE
+CLASS(XonoticHUDConfirmDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticHUDConfirmDialog, fill, void(entity))
+       ATTRIB(XonoticHUDConfirmDialog, title, string, _("Enter HUD editor"))
+       ATTRIB(XonoticHUDConfirmDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
+       ATTRIB(XonoticHUDConfirmDialog, intendedWidth, float, 0.5)
+       ATTRIB(XonoticHUDConfirmDialog, rows, float, 4)
+       ATTRIB(XonoticHUDConfirmDialog, columns, float, 2)
+ENDCLASS(XonoticHUDConfirmDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void HUDSetup_Start(entity me, entity btn)
+{
+       if (!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
+               localcmd("map hudsetup/hudsetup", "\n");
+       else
+               localcmd("togglemenu 0\n");
+
+       localcmd("_hud_configure 1", "\n");
+}
+
+void XonoticHUDConfirmDialog_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("In order for the HUD editor to show, you must first be in game.")));
+       me.TR(me);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Do you wish to start a local game to set up the HUD?")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("HDCNFRM^Yes")), '1 0 0'));
+                       e.onClick = HUDSetup_Start;
+                       e.onClickEntity = me;
+               me.TD(me, 1, 1, e = makeXonoticButton(ZCTX(_("HDCNFRM^No")), '0 1 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_messages.c b/qcsrc/menu/xonotic/dialog_settings_game_messages.c
deleted file mode 100644 (file)
index 6f605cc..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticGameMessageSettingsTab) EXTENDS(XonoticTab)
-       //METHOD(XonoticGameWeaponsSettingsTab, toString, string(entity))
-       METHOD(XonoticGameMessageSettingsTab, fill, void(entity))
-       METHOD(XonoticGameMessageSettingsTab, showNotify, void(entity))
-       ATTRIB(XonoticGameMessageSettingsTab, title, string, _("Messages"))
-       ATTRIB(XonoticGameMessageSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticGameMessageSettingsTab, rows, float, 13)
-       ATTRIB(XonoticGameMessageSettingsTab, columns, float, 6)
-       ATTRIB(XonoticGameMessageSettingsTab, weaponsList, entity, NULL)
-ENDCLASS(XonoticGameMessageSettingsTab)
-entity makeXonoticGameMessageSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticGameMessageSettingsTab_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-entity makeXonoticGameMessageSettingsTab()
-{
-       entity me;
-       me = spawnXonoticGameMessageSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void XonoticGameMessageSettingsTab_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Frag Information")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_show_sprees", _("Display information about killing sprees")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "notification_show_sprees_info_specialonly", _("Only display sprees if they are achievements")));
-                       makeMulti(e, "notification_show_sprees_center_specialonly");
-                       setDependent(e, "notification_show_sprees", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "notification_show_sprees_center", _("Show spree information in centerprints")));
-                       setDependent(e, "notification_show_sprees", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(3, 0, "notification_show_sprees_info", _("Show spree information in death messages")));
-                       setDependent(e, "notification_show_sprees", 1, 1);
-       #if 0
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Sprees in info messages:")));
-                       setDependent(e, "notification_show_sprees", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("notification_show_sprees_info"));
-                       e.addValue(e, ZCTX(_("Disabled")), "0");
-                       e.addValue(e, ZCTX(_("Target")), "1");
-                       e.addValue(e, ZCTX(_("Attacker")), "2");
-                       e.addValue(e, ZCTX(_("Both")), "3");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "notification_show_sprees", 1, 1);
-       #endif
-       me.TR(me);
-               me.TDempty(me, 0.4);
-               me.TD(me, 1, 2.6, e = makeXonoticCheckBox(0, "notification_show_sprees_info_newline", _("Print on a seperate line")));
-                       setDependent(e, "notification_show_sprees", 1, 1);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_CHOICE_FRAG", _("Add extra frag information to centerprint when available")));
-                       makeMulti(e, "notification_CHOICE_FRAGGED notification_CHOICE_TYPEFRAG notification_CHOICE_TYPEFRAGGED");
-                       e.sendCvars = TRUE;
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_show_location", _("Add frag location to death messages when available")));
-
-       me.gotoRC(me, 9, 0); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Gamemode Settings")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_CHOICE_CTF_CAPTURE_TIME_RED", _("Display capture times in Capture The Flag")));
-                       makeMulti(e, "notification_CHOICE_CTF_CAPTURE_TIME_BLUE notification_CHOICE_CTF_CAPTURE_BROKEN_RED notification_CHOICE_CTF_CAPTURE_BROKEN_BLUE notification_CHOICE_CTF_CAPTURE_UNBROKEN_RED notification_CHOICE_CTF_CAPTURE_UNBROKEN_BLUE ");
-                       e.sendCvars = TRUE;
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_CHOICE_CTF_PICKUP_ENEMY", _("Display name of flag stealer in Capture The Flag")));
-                       makeMulti(e, "notification_CHOICE_CTF_PICKUP_TEAM");
-                       e.sendCvars = TRUE;
-
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Other")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(4, 1, "con_notify", _("Display console messages in the top left corner")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_allow_chatboxprint", _("Display all info messages in the chatbox")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_INFO_QUIT_DISCONNECT", _("Display player statuses in the chatbox")));
-                       makeMulti(e, "notification_INFO_QUIT_KICK_IDLING notification_INFO_JOIN_CONNECT_TEAM_BLUE notification_INFO_JOIN_CONNECT_TEAM_PINK notification_INFO_JOIN_CONNECT_TEAM_RED notification_INFO_JOIN_CONNECT_TEAM_YELLOW");
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_CENTER_POWERUP_INVISIBILITY", _("Powerup notifications")));
-                       makeMulti(e, "notification_CENTER_POWERUP_SHIELD notification_CENTER_POWERUP_SPEED notification_CENTER_POWERUP_STRENGTH notification_CENTER_POWERDOWN_INVISIBILITY notification_CENTER_POWERDOWN_SHIELD notification_CENTER_POWERDOWN_SPEED notification_CENTER_POWERDOWN_STRENGTH notification_CENTER_SUPERWEAPON_BROKEN notification_CENTER_SUPERWEAPON_LOST notification_CENTER_SUPERWEAPON_PICKUP notification_INFO_POWERUP_INVISIBILITY notification_INFO_POWERUP_SHIELD notification_INFO_POWERUP_SPEED notification_INFO_POWERUP_STRENGTH");
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_CENTER_ITEM_WEAPON_DONTHAVE", _("Weapon centerprint notifications")));
-                       makeMulti(e, "notification_CENTER_ITEM_WEAPON_DROP notification_CENTER_ITEM_WEAPON_GOT notification_CENTER_ITEM_WEAPON_NOAMMO notification_CENTER_ITEM_WEAPON_PRIMORSEC notification_CENTER_ITEM_WEAPON_UNAVAILABLE"); 
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_INFO_ITEM_WEAPON_DONTHAVE", _("Weapon info message notifications")));
-                       makeMulti(e, "notification_INFO_ITEM_WEAPON_DROP notification_INFO_ITEM_WEAPON_GOT notification_INFO_ITEM_WEAPON_NOAMMO notification_INFO_ITEM_WEAPON_PRIMORSEC notification_INFO_ITEM_WEAPON_UNAVAILABLE"); 
-
-       me.gotoRC(me, 9, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Announcers")));
-       #if 0
-       // there's just not enough room for this, and it's not important enough to justify...
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 0, "notification_ANNCE_NUM_RESPAWN_1", _("Respawn countdown sounds")));
-                       makeMulti(e, "notification_ANNCE_NUM_RESPAWN_2 notification_ANNCE_NUM_RESPAWN_3 notification_ANNCE_NUM_RESPAWN_4 notification_ANNCE_NUM_RESPAWN_5 notification_ANNCE_NUM_RESPAWN_6 notification_ANNCE_NUM_RESPAWN_7 notification_ANNCE_NUM_RESPAWN_8 notification_ANNCE_NUM_RESPAWN_9 notification_ANNCE_NUM_RESPAWN_10");
-       #endif
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(1, 0, "notification_ANNCE_KILLSTREAK_03", _("Killstreak sounds")));
-                       makeMulti(e, "notification_ANNCE_KILLSTREAK_05 notification_ANNCE_KILLSTREAK_10 notification_ANNCE_KILLSTREAK_15 notification_ANNCE_KILLSTREAK_20 notification_ANNCE_KILLSTREAK_25 notification_ANNCE_KILLSTREAK_30");
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(1, 0, "notification_ANNCE_ACHIEVEMENT_AIRSHOT", _("Achievement sounds")));
-                       makeMulti(e, "notification_ANNCE_ACHIEVEMENT_AMAZING notification_ANNCE_ACHIEVEMENT_AWESOME notification_ANNCE_ACHIEVEMENT_BOTLIKE notification_ANNCE_ACHIEVEMENT_ELECTROBITCH notification_ANNCE_ACHIEVEMENT_IMPRESSIVE notification_ANNCE_ACHIEVEMENT_YODA");
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_messages.qc b/qcsrc/menu/xonotic/dialog_settings_game_messages.qc
new file mode 100644 (file)
index 0000000..6f605cc
--- /dev/null
@@ -0,0 +1,119 @@
+#ifdef INTERFACE
+CLASS(XonoticGameMessageSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameWeaponsSettingsTab, toString, string(entity))
+       METHOD(XonoticGameMessageSettingsTab, fill, void(entity))
+       METHOD(XonoticGameMessageSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameMessageSettingsTab, title, string, _("Messages"))
+       ATTRIB(XonoticGameMessageSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameMessageSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameMessageSettingsTab, columns, float, 6)
+       ATTRIB(XonoticGameMessageSettingsTab, weaponsList, entity, NULL)
+ENDCLASS(XonoticGameMessageSettingsTab)
+entity makeXonoticGameMessageSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticGameMessageSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameMessageSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameMessageSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameMessageSettingsTab_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Frag Information")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_show_sprees", _("Display information about killing sprees")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "notification_show_sprees_info_specialonly", _("Only display sprees if they are achievements")));
+                       makeMulti(e, "notification_show_sprees_center_specialonly");
+                       setDependent(e, "notification_show_sprees", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "notification_show_sprees_center", _("Show spree information in centerprints")));
+                       setDependent(e, "notification_show_sprees", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(3, 0, "notification_show_sprees_info", _("Show spree information in death messages")));
+                       setDependent(e, "notification_show_sprees", 1, 1);
+       #if 0
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Sprees in info messages:")));
+                       setDependent(e, "notification_show_sprees", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("notification_show_sprees_info"));
+                       e.addValue(e, ZCTX(_("Disabled")), "0");
+                       e.addValue(e, ZCTX(_("Target")), "1");
+                       e.addValue(e, ZCTX(_("Attacker")), "2");
+                       e.addValue(e, ZCTX(_("Both")), "3");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "notification_show_sprees", 1, 1);
+       #endif
+       me.TR(me);
+               me.TDempty(me, 0.4);
+               me.TD(me, 1, 2.6, e = makeXonoticCheckBox(0, "notification_show_sprees_info_newline", _("Print on a seperate line")));
+                       setDependent(e, "notification_show_sprees", 1, 1);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_CHOICE_FRAG", _("Add extra frag information to centerprint when available")));
+                       makeMulti(e, "notification_CHOICE_FRAGGED notification_CHOICE_TYPEFRAG notification_CHOICE_TYPEFRAGGED");
+                       e.sendCvars = TRUE;
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_show_location", _("Add frag location to death messages when available")));
+
+       me.gotoRC(me, 9, 0); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Gamemode Settings")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_CHOICE_CTF_CAPTURE_TIME_RED", _("Display capture times in Capture The Flag")));
+                       makeMulti(e, "notification_CHOICE_CTF_CAPTURE_TIME_BLUE notification_CHOICE_CTF_CAPTURE_BROKEN_RED notification_CHOICE_CTF_CAPTURE_BROKEN_BLUE notification_CHOICE_CTF_CAPTURE_UNBROKEN_RED notification_CHOICE_CTF_CAPTURE_UNBROKEN_BLUE ");
+                       e.sendCvars = TRUE;
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_CHOICE_CTF_PICKUP_ENEMY", _("Display name of flag stealer in Capture The Flag")));
+                       makeMulti(e, "notification_CHOICE_CTF_PICKUP_TEAM");
+                       e.sendCvars = TRUE;
+
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Other")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(4, 1, "con_notify", _("Display console messages in the top left corner")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_allow_chatboxprint", _("Display all info messages in the chatbox")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "notification_INFO_QUIT_DISCONNECT", _("Display player statuses in the chatbox")));
+                       makeMulti(e, "notification_INFO_QUIT_KICK_IDLING notification_INFO_JOIN_CONNECT_TEAM_BLUE notification_INFO_JOIN_CONNECT_TEAM_PINK notification_INFO_JOIN_CONNECT_TEAM_RED notification_INFO_JOIN_CONNECT_TEAM_YELLOW");
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_CENTER_POWERUP_INVISIBILITY", _("Powerup notifications")));
+                       makeMulti(e, "notification_CENTER_POWERUP_SHIELD notification_CENTER_POWERUP_SPEED notification_CENTER_POWERUP_STRENGTH notification_CENTER_POWERDOWN_INVISIBILITY notification_CENTER_POWERDOWN_SHIELD notification_CENTER_POWERDOWN_SPEED notification_CENTER_POWERDOWN_STRENGTH notification_CENTER_SUPERWEAPON_BROKEN notification_CENTER_SUPERWEAPON_LOST notification_CENTER_SUPERWEAPON_PICKUP notification_INFO_POWERUP_INVISIBILITY notification_INFO_POWERUP_SHIELD notification_INFO_POWERUP_SPEED notification_INFO_POWERUP_STRENGTH");
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_CENTER_ITEM_WEAPON_DONTHAVE", _("Weapon centerprint notifications")));
+                       makeMulti(e, "notification_CENTER_ITEM_WEAPON_DROP notification_CENTER_ITEM_WEAPON_GOT notification_CENTER_ITEM_WEAPON_NOAMMO notification_CENTER_ITEM_WEAPON_PRIMORSEC notification_CENTER_ITEM_WEAPON_UNAVAILABLE"); 
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "notification_INFO_ITEM_WEAPON_DONTHAVE", _("Weapon info message notifications")));
+                       makeMulti(e, "notification_INFO_ITEM_WEAPON_DROP notification_INFO_ITEM_WEAPON_GOT notification_INFO_ITEM_WEAPON_NOAMMO notification_INFO_ITEM_WEAPON_PRIMORSEC notification_INFO_ITEM_WEAPON_UNAVAILABLE"); 
+
+       me.gotoRC(me, 9, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Announcers")));
+       #if 0
+       // there's just not enough room for this, and it's not important enough to justify...
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 0, "notification_ANNCE_NUM_RESPAWN_1", _("Respawn countdown sounds")));
+                       makeMulti(e, "notification_ANNCE_NUM_RESPAWN_2 notification_ANNCE_NUM_RESPAWN_3 notification_ANNCE_NUM_RESPAWN_4 notification_ANNCE_NUM_RESPAWN_5 notification_ANNCE_NUM_RESPAWN_6 notification_ANNCE_NUM_RESPAWN_7 notification_ANNCE_NUM_RESPAWN_8 notification_ANNCE_NUM_RESPAWN_9 notification_ANNCE_NUM_RESPAWN_10");
+       #endif
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(1, 0, "notification_ANNCE_KILLSTREAK_03", _("Killstreak sounds")));
+                       makeMulti(e, "notification_ANNCE_KILLSTREAK_05 notification_ANNCE_KILLSTREAK_10 notification_ANNCE_KILLSTREAK_15 notification_ANNCE_KILLSTREAK_20 notification_ANNCE_KILLSTREAK_25 notification_ANNCE_KILLSTREAK_30");
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(1, 0, "notification_ANNCE_ACHIEVEMENT_AIRSHOT", _("Achievement sounds")));
+                       makeMulti(e, "notification_ANNCE_ACHIEVEMENT_AMAZING notification_ANNCE_ACHIEVEMENT_AWESOME notification_ANNCE_ACHIEVEMENT_BOTLIKE notification_ANNCE_ACHIEVEMENT_ELECTROBITCH notification_ANNCE_ACHIEVEMENT_IMPRESSIVE notification_ANNCE_ACHIEVEMENT_YODA");
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_model.c b/qcsrc/menu/xonotic/dialog_settings_game_model.c
deleted file mode 100644 (file)
index c2aedc1..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticGameModelSettingsTab) EXTENDS(XonoticTab)
-       //METHOD(XonoticGameModelSettingsTab, toString, string(entity))
-       METHOD(XonoticGameModelSettingsTab, fill, void(entity))
-       METHOD(XonoticGameModelSettingsTab, showNotify, void(entity))
-       ATTRIB(XonoticGameModelSettingsTab, title, string, _("Model"))
-       ATTRIB(XonoticGameModelSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticGameModelSettingsTab, rows, float, 13)
-       ATTRIB(XonoticGameModelSettingsTab, columns, float, 5)
-ENDCLASS(XonoticGameModelSettingsTab)
-entity makeXonoticGameModelSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticGameModelSettingsTab_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-entity makeXonoticGameModelSettingsTab()
-{
-       entity me;
-       me = spawnXonoticGameModelSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void XonoticGameModelSettingsTab_fill(entity me)
-{
-       entity e;
-       //float i;
-       
-       // Note that this is pretty terrible currently due to the lack of options for this tab...
-       // There is really not many other decent places for these options, additionally
-       // later I would like quite a few more options in this tab.
-
-       me.gotoRC(me, 0, 1); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Items")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_simple_items", _("Use simple 2D images instead of item models")));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Unavailable alpha:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.1, "cl_ghost_items"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Unavailable color:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_ghost_items_color"));
-                       e.addValue(e, ZCTX(_("GHOITEMS^Black")), "-1 -1 -1");
-                       e.addValue(e, ZCTX(_("GHOITEMS^Dark")), "0.1 0.1 0.1");
-                       e.addValue(e, ZCTX(_("GHOITEMS^Tinted")), "0.6 0.6 0.6");
-                       e.addValue(e, ZCTX(_("GHOITEMS^Normal")), "1 1 1");
-                       e.addValue(e, ZCTX(_("GHOITEMS^Blue")), "-1 -1 3");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "cl_ghost_items", 0.001, 1);
-
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Players")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_forceplayermodels", _("Force player models to mine")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_forceplayercolors", _("Force player colors to mine")));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Body fading:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 2, 0.2, "cl_deathglow"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gibs:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_nogibs"));
-                       e.addValue(e, ZCTX(_("GIBS^None")), "1");
-                       e.addValue(e, ZCTX(_("GIBS^Few")), "0.75");
-                       e.addValue(e, ZCTX(_("GIBS^Many")), "0.5");
-                       e.addValue(e, ZCTX(_("GIBS^Lots")), "0");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "cl_gentle", 0, 0);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_model.qc b/qcsrc/menu/xonotic/dialog_settings_game_model.qc
new file mode 100644 (file)
index 0000000..c2aedc1
--- /dev/null
@@ -0,0 +1,74 @@
+#ifdef INTERFACE
+CLASS(XonoticGameModelSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameModelSettingsTab, toString, string(entity))
+       METHOD(XonoticGameModelSettingsTab, fill, void(entity))
+       METHOD(XonoticGameModelSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameModelSettingsTab, title, string, _("Model"))
+       ATTRIB(XonoticGameModelSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameModelSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameModelSettingsTab, columns, float, 5)
+ENDCLASS(XonoticGameModelSettingsTab)
+entity makeXonoticGameModelSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticGameModelSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameModelSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameModelSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameModelSettingsTab_fill(entity me)
+{
+       entity e;
+       //float i;
+       
+       // Note that this is pretty terrible currently due to the lack of options for this tab...
+       // There is really not many other decent places for these options, additionally
+       // later I would like quite a few more options in this tab.
+
+       me.gotoRC(me, 0, 1); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Items")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_simple_items", _("Use simple 2D images instead of item models")));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Unavailable alpha:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.1, "cl_ghost_items"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Unavailable color:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_ghost_items_color"));
+                       e.addValue(e, ZCTX(_("GHOITEMS^Black")), "-1 -1 -1");
+                       e.addValue(e, ZCTX(_("GHOITEMS^Dark")), "0.1 0.1 0.1");
+                       e.addValue(e, ZCTX(_("GHOITEMS^Tinted")), "0.6 0.6 0.6");
+                       e.addValue(e, ZCTX(_("GHOITEMS^Normal")), "1 1 1");
+                       e.addValue(e, ZCTX(_("GHOITEMS^Blue")), "-1 -1 3");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "cl_ghost_items", 0.001, 1);
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Players")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_forceplayermodels", _("Force player models to mine")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_forceplayercolors", _("Force player colors to mine")));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Body fading:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 2, 0.2, "cl_deathglow"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gibs:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_nogibs"));
+                       e.addValue(e, ZCTX(_("GIBS^None")), "1");
+                       e.addValue(e, ZCTX(_("GIBS^Few")), "0.75");
+                       e.addValue(e, ZCTX(_("GIBS^Many")), "0.5");
+                       e.addValue(e, ZCTX(_("GIBS^Lots")), "0");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "cl_gentle", 0, 0);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_view.c b/qcsrc/menu/xonotic/dialog_settings_game_view.c
deleted file mode 100644 (file)
index 3fd4512..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticGameViewSettingsTab) EXTENDS(XonoticTab)
-       //METHOD(XonoticGameCrosshairSettingsTab, toString, string(entity))
-       METHOD(XonoticGameViewSettingsTab, fill, void(entity))
-       METHOD(XonoticGameViewSettingsTab, showNotify, void(entity))
-       ATTRIB(XonoticGameViewSettingsTab, title, string, _("View"))
-       ATTRIB(XonoticGameViewSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticGameViewSettingsTab, rows, float, 13)
-       ATTRIB(XonoticGameViewSettingsTab, columns, float, 6.2)
-ENDCLASS(XonoticGameViewSettingsTab)
-entity makeXonoticGameViewSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticGameViewSettingsTab_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-entity makeXonoticGameViewSettingsTab()
-{
-       entity me;
-       me = spawnXonoticGameViewSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void XonoticGameViewSettingsTab_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "chase_active", "0", _("1st person perspective")));
-               makeMulti(e, "crosshair_hittest_showimpact");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_eventchase_death", _("Slide to third person upon death")));
-               setDependent(e, "chase_active", -1, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.05, 0, "cl_bobfall", _("Smooth the view when landing from a jump")));
-               setDependent(e, "chase_active", -1, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.05, 0, "cl_smoothviewheight", _("Smooth the view while crouching")));
-               setDependent(e, "chase_active", -1, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(1, 0, "v_idlescale", _("View waving while idle")));
-               setDependent(e, "chase_active", -1, 0);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.01, 0, "cl_bob", _("View bobbing while walking around")));
-               makeMulti(e, "cl_bob2");
-               setDependent(e, "chase_active", -1, 0);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "chase_active", "1", _("3rd person perspective")));
-               makeMulti(e, "crosshair_hittest_showimpact");
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Back distance")));
-               setDependent(e, "chase_active", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(10, 100, 1, "chase_back"));
-               setDependent(e, "chase_active", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Up distance")));
-               setDependent(e, "chase_active", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(10, 50, 1, "chase_up"));
-               setDependent(e, "chase_active", 1, 1);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_clippedspectating", _("Allow passing through walls while spectating")));
-       
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Field of view:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(60, 130, 5, "fov"));
-       me.TR(me);
-       me.TR(me);
-               //me.TDempty(me, 0.2);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Zoom factor:"))));
-               me.TD(me, 1, 2, e = makeXonoticSlider(2, 16, 0.5, "cl_zoomfactor"));
-       me.TR(me);
-               //me.TDempty(me, 0.2);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Zoom speed:"))));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_zoomspeed"));
-                       e.addValue(e, "1", "1"); // Samual: for() loop doesn't work here, even though it would make sense.
-                       e.addValue(e, "2", "2");
-                       e.addValue(e, "3", "3");
-                       e.addValue(e, "4", "4");
-                       e.addValue(e, "5", "5");
-                       e.addValue(e, "6", "6");
-                       e.addValue(e, "7", "7");
-                       e.addValue(e, "8", "8");
-                       e.addValue(e, ZCTX(_("ZOOM^Instant")), "-1");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               //me.TDempty(me, 0.2);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Zoom sensitivity:"))));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.1, "cl_zoomsensitivity"));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_velocityzoom_enabled", _("Velocity zoom")));
-               me.TD(me, 1, 2, e = makeXonoticCheckBoxEx(3, 1, "cl_velocityzoom_type", _("Forward movement only")));
-                       setDependent(e, "cl_velocityzoom_enabled", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, ZCTX(_("VZOOM^Factor"))));
-                       setDependentAND(e, "cl_velocityzoom_enabled", 1, 1, "cl_velocityzoom_type", 1, 3);
-               me.TD(me, 1, 2, e = makeXonoticSlider(-1, 1, 0.1, "cl_velocityzoom_factor"));
-                       setDependentAND(e, "cl_velocityzoom_enabled", 1, 1, "cl_velocityzoom_type", 1, 3);
-       me.TR(me);
-       me.TR(me);
-               //me.TDempty(me, 0.2);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_reticle", _("Display reticle 2D overlay while zooming")));
-       me.TR(me);
-               //me.TDempty(me, 0.2);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_zoom_on_death", _("Release zoom when you die or respawn")));
-                       makeMulti(e, "cl_unpress_zoom_on_spawn");
-       me.TR(me);
-               //me.TDempty(me, 0.2);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_zoom_on_weapon_switch", _("Release zoom when you switch weapons")));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_view.qc b/qcsrc/menu/xonotic/dialog_settings_game_view.qc
new file mode 100644 (file)
index 0000000..3fd4512
--- /dev/null
@@ -0,0 +1,124 @@
+#ifdef INTERFACE
+CLASS(XonoticGameViewSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameCrosshairSettingsTab, toString, string(entity))
+       METHOD(XonoticGameViewSettingsTab, fill, void(entity))
+       METHOD(XonoticGameViewSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameViewSettingsTab, title, string, _("View"))
+       ATTRIB(XonoticGameViewSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameViewSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameViewSettingsTab, columns, float, 6.2)
+ENDCLASS(XonoticGameViewSettingsTab)
+entity makeXonoticGameViewSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticGameViewSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameViewSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameViewSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameViewSettingsTab_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "chase_active", "0", _("1st person perspective")));
+               makeMulti(e, "crosshair_hittest_showimpact");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_eventchase_death", _("Slide to third person upon death")));
+               setDependent(e, "chase_active", -1, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.05, 0, "cl_bobfall", _("Smooth the view when landing from a jump")));
+               setDependent(e, "chase_active", -1, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.05, 0, "cl_smoothviewheight", _("Smooth the view while crouching")));
+               setDependent(e, "chase_active", -1, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(1, 0, "v_idlescale", _("View waving while idle")));
+               setDependent(e, "chase_active", -1, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.01, 0, "cl_bob", _("View bobbing while walking around")));
+               makeMulti(e, "cl_bob2");
+               setDependent(e, "chase_active", -1, 0);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticRadioButton(1, "chase_active", "1", _("3rd person perspective")));
+               makeMulti(e, "crosshair_hittest_showimpact");
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Back distance")));
+               setDependent(e, "chase_active", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(10, 100, 1, "chase_back"));
+               setDependent(e, "chase_active", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Up distance")));
+               setDependent(e, "chase_active", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(10, 50, 1, "chase_up"));
+               setDependent(e, "chase_active", 1, 1);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_clippedspectating", _("Allow passing through walls while spectating")));
+       
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Field of view:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(60, 130, 5, "fov"));
+       me.TR(me);
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Zoom factor:"))));
+               me.TD(me, 1, 2, e = makeXonoticSlider(2, 16, 0.5, "cl_zoomfactor"));
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Zoom speed:"))));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_zoomspeed"));
+                       e.addValue(e, "1", "1"); // Samual: for() loop doesn't work here, even though it would make sense.
+                       e.addValue(e, "2", "2");
+                       e.addValue(e, "3", "3");
+                       e.addValue(e, "4", "4");
+                       e.addValue(e, "5", "5");
+                       e.addValue(e, "6", "6");
+                       e.addValue(e, "7", "7");
+                       e.addValue(e, "8", "8");
+                       e.addValue(e, ZCTX(_("ZOOM^Instant")), "-1");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Zoom sensitivity:"))));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 1, 0.1, "cl_zoomsensitivity"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_velocityzoom_enabled", _("Velocity zoom")));
+               me.TD(me, 1, 2, e = makeXonoticCheckBoxEx(3, 1, "cl_velocityzoom_type", _("Forward movement only")));
+                       setDependent(e, "cl_velocityzoom_enabled", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, ZCTX(_("VZOOM^Factor"))));
+                       setDependentAND(e, "cl_velocityzoom_enabled", 1, 1, "cl_velocityzoom_type", 1, 3);
+               me.TD(me, 1, 2, e = makeXonoticSlider(-1, 1, 0.1, "cl_velocityzoom_factor"));
+                       setDependentAND(e, "cl_velocityzoom_enabled", 1, 1, "cl_velocityzoom_type", 1, 3);
+       me.TR(me);
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_reticle", _("Display reticle 2D overlay while zooming")));
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_zoom_on_death", _("Release zoom when you die or respawn")));
+                       makeMulti(e, "cl_unpress_zoom_on_spawn");
+       me.TR(me);
+               //me.TDempty(me, 0.2);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_zoom_on_weapon_switch", _("Release zoom when you switch weapons")));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_weapons.c b/qcsrc/menu/xonotic/dialog_settings_game_weapons.c
deleted file mode 100644 (file)
index bc7cc7d..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticGameWeaponsSettingsTab) EXTENDS(XonoticTab)
-       //METHOD(XonoticGameWeaponsSettingsTab, toString, string(entity))
-       METHOD(XonoticGameWeaponsSettingsTab, fill, void(entity))
-       METHOD(XonoticGameWeaponsSettingsTab, showNotify, void(entity))
-       ATTRIB(XonoticGameWeaponsSettingsTab, title, string, _("Weapons"))
-       ATTRIB(XonoticGameWeaponsSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticGameWeaponsSettingsTab, rows, float, 13)
-       ATTRIB(XonoticGameWeaponsSettingsTab, columns, float, 6)
-       ATTRIB(XonoticGameWeaponsSettingsTab, weaponsList, entity, NULL)
-ENDCLASS(XonoticGameWeaponsSettingsTab)
-entity makeXonoticGameWeaponsSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticGameWeaponsSettingsTab_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-entity makeXonoticGameWeaponsSettingsTab()
-{
-       entity me;
-       me = spawnXonoticGameWeaponsSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void XonoticGameWeaponsSettingsTab_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TDempty(me, 0.25);
-               me.TD(me, 1, 2.5, e = makeXonoticHeaderLabel(_("Weapon Priority List")));
-       me.TR(me);
-               me.TDempty(me, 0.25);
-               me.TD(me, 10, 2.5, e = me.weaponsList = makeXonoticWeaponsList());
-       me.gotoRC(me, 11, 0.25);
-               me.TD(me, 1, 1.25, e = makeXonoticButton(_("Up"), '0 0 0'));
-                       e.onClick = WeaponsList_MoveUp_Click;
-                       e.onClickEntity = me.weaponsList;
-               me.TD(me, 1, 1.25, e = makeXonoticButton(_("Down"), '0 0 0'));
-                       e.onClick = WeaponsList_MoveDown_Click;
-                       e.onClickEntity = me.weaponsList;
-
-       me.gotoRC(me, 0, 3); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_weaponpriority_useforcycling", _("Use priority list for weapon cycling")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_weaponimpulsemode", _("Cycle through only usable weapon selections")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_autoswitch", _("Auto switch weapons on pickup")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_attack_on_weapon_switch", _("Release attack buttons when you switch weapons")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "r_drawviewmodel", _("Draw 1st person weapon model")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "cl_gunalign", "4", _("Left align")));
-                       setDependent(e, "r_drawviewmodel", 1, 1);
-               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "cl_gunalign", "1", _("Center")));
-                       setDependent(e, "r_drawviewmodel", 1, 1);
-               me.TD(me, 1, 1.0, e = makeXonoticRadioButton(1, "cl_gunalign", "3", _("Right align")));
-                       setDependent(e, "r_drawviewmodel", 1, 1);
-       me.TR(me);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_followmodel", _("Gun model swaying")));
-               makeMulti(e, "cl_leanmodel");
-               setDependent(e, "r_drawviewmodel", 1, 1);
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_bobmodel", _("Gun model bobbing")));
-               setDependent(e, "r_drawviewmodel", 1, 1);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_game_weapons.qc b/qcsrc/menu/xonotic/dialog_settings_game_weapons.qc
new file mode 100644 (file)
index 0000000..bc7cc7d
--- /dev/null
@@ -0,0 +1,77 @@
+#ifdef INTERFACE
+CLASS(XonoticGameWeaponsSettingsTab) EXTENDS(XonoticTab)
+       //METHOD(XonoticGameWeaponsSettingsTab, toString, string(entity))
+       METHOD(XonoticGameWeaponsSettingsTab, fill, void(entity))
+       METHOD(XonoticGameWeaponsSettingsTab, showNotify, void(entity))
+       ATTRIB(XonoticGameWeaponsSettingsTab, title, string, _("Weapons"))
+       ATTRIB(XonoticGameWeaponsSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticGameWeaponsSettingsTab, rows, float, 13)
+       ATTRIB(XonoticGameWeaponsSettingsTab, columns, float, 6)
+       ATTRIB(XonoticGameWeaponsSettingsTab, weaponsList, entity, NULL)
+ENDCLASS(XonoticGameWeaponsSettingsTab)
+entity makeXonoticGameWeaponsSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticGameWeaponsSettingsTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+entity makeXonoticGameWeaponsSettingsTab()
+{
+       entity me;
+       me = spawnXonoticGameWeaponsSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticGameWeaponsSettingsTab_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 1, 2.5, e = makeXonoticHeaderLabel(_("Weapon Priority List")));
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 10, 2.5, e = me.weaponsList = makeXonoticWeaponsList());
+       me.gotoRC(me, 11, 0.25);
+               me.TD(me, 1, 1.25, e = makeXonoticButton(_("Up"), '0 0 0'));
+                       e.onClick = WeaponsList_MoveUp_Click;
+                       e.onClickEntity = me.weaponsList;
+               me.TD(me, 1, 1.25, e = makeXonoticButton(_("Down"), '0 0 0'));
+                       e.onClick = WeaponsList_MoveDown_Click;
+                       e.onClickEntity = me.weaponsList;
+
+       me.gotoRC(me, 0, 3); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_weaponpriority_useforcycling", _("Use priority list for weapon cycling")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_weaponimpulsemode", _("Cycle through only usable weapon selections")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_autoswitch", _("Auto switch weapons on pickup")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_attack_on_weapon_switch", _("Release attack buttons when you switch weapons")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "r_drawviewmodel", _("Draw 1st person weapon model")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "cl_gunalign", "4", _("Left align")));
+                       setDependent(e, "r_drawviewmodel", 1, 1);
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "cl_gunalign", "1", _("Center")));
+                       setDependent(e, "r_drawviewmodel", 1, 1);
+               me.TD(me, 1, 1.0, e = makeXonoticRadioButton(1, "cl_gunalign", "3", _("Right align")));
+                       setDependent(e, "r_drawviewmodel", 1, 1);
+       me.TR(me);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_followmodel", _("Gun model swaying")));
+               makeMulti(e, "cl_leanmodel");
+               setDependent(e, "r_drawviewmodel", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_bobmodel", _("Gun model bobbing")));
+               setDependent(e, "r_drawviewmodel", 1, 1);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_input.c b/qcsrc/menu/xonotic/dialog_settings_input.c
deleted file mode 100644 (file)
index 57b6cef..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticInputSettingsTab) EXTENDS(XonoticTab)
-       METHOD(XonoticInputSettingsTab, fill, void(entity))
-       ATTRIB(XonoticInputSettingsTab, title, string, _("Input"))
-       ATTRIB(XonoticInputSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticInputSettingsTab, rows, float, 15.5)
-       ATTRIB(XonoticInputSettingsTab, columns, float, 6.2) // added extra .2 for center space
-ENDCLASS(XonoticInputSettingsTab)
-entity makeXonoticInputSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticInputSettingsTab()
-{
-       entity me;
-       me = spawnXonoticInputSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void CheckBox_Click_Redisplay(entity me, entity checkbox)
-{
-       CheckBox_Click(me, checkbox);
-       cmd("\ndefer 0.2 \"togglemenu 1\"\n");
-       //m_display();
-}
-void XonoticInputSettingsTab_fill(entity me)
-{
-       entity e;
-       entity kb = makeXonoticKeyBinder();
-
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Key Bindings")));
-       me.TR(me);
-               me.TD(me, me.rows - 3, 3, kb);
-       me.gotoRC(me, me.rows - 2, 0);
-               me.TD(me, 1, 1, e = makeXonoticButton(_("Change key..."), '0 0 0'));
-                       e.onClick = KeyBinder_Bind_Change;
-                       e.onClickEntity = kb;
-                       kb.keyGrabButton = e;
-               me.TD(me, 1, 1, e = makeXonoticButton(_("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 = makeXonoticButton(_("Clear"), '0 0 0'));
-                       e.onClick = KeyBinder_Bind_Clear;
-                       e.onClickEntity = kb;
-                       kb.clearButton = e;
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticButton(_("Reset all"), '0 0 0'));
-                       e.onClick = KeyBinder_Bind_Reset_All;
-                       e.onClickEntity = kb;
-
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Mouse")));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Sensitivity:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(1, 32, 0.2, "sensitivity"));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "m_filter", _("Smooth aiming")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(1.022, "m_pitch", _("Invert aiming")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "menu_mouse_absolute", _("Use system mouse positioning")));
-                       makeMulti(e, "hud_cursormode");
-                       e.onClick = CheckBox_Click_Redisplay;
-                       e.onClickEntity = e;
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "m_accelerate", _("Enable built in mouse acceleration")));
-       me.TR(me);
-               if(cvar_type("vid_dgamouse") & CVAR_TYPEFLAG_ENGINE)
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "vid_dgamouse", _("Disable system mouse acceleration")));
-               else if(cvar_type("apple_mouse_noaccel") & CVAR_TYPEFLAG_ENGINE)
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "apple_mouse_noaccel", _("Disable system mouse acceleration")));
-               else
-               {
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, string_null, _("Disable system mouse acceleration")));
-                       e.disabled = 1; // the option is never available in this case, just there for show
-               }
-
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Other")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "con_closeontoggleconsole", _("Pressing \"enter console\" key also closes it")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_movement_track_canjump", _("Automatically repeat jumping if holding jump")));
-                       e.sendCvars = TRUE;
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Jetpack on jump:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_jetpack_jump"));
-                       e.addValue(e, _("Disabled"), "0");
-                       e.addValue(e, _("Air only"), "1");
-                       e.addValue(e, _("All"), "2");
-                       e.configureXonoticTextSliderValues(e);
-                       e.sendCvars = TRUE;
-       me.TR(me);
-               if(cvar_type("joy_enable") & CVAR_TYPEFLAG_ENGINE)
-               {
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "joy_enable", _("Use joystick input")));
-                       setDependent(e, "joy_detected", 1, 10000000);
-               }
-               else if(cvar_type("joystick") & CVAR_TYPEFLAG_ENGINE)
-               {
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "joystick", _("Use joystick input")));
-                       setDependent(e, "joy_detected", 1, 10000000);
-               }
-               else
-               {
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, string_null, _("Use joystick input")));
-                       e.disabled = 1; // the option is never available in this case, just there for show
-               }
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_input.qc b/qcsrc/menu/xonotic/dialog_settings_input.qc
new file mode 100644 (file)
index 0000000..57b6cef
--- /dev/null
@@ -0,0 +1,116 @@
+#ifdef INTERFACE
+CLASS(XonoticInputSettingsTab) EXTENDS(XonoticTab)
+       METHOD(XonoticInputSettingsTab, fill, void(entity))
+       ATTRIB(XonoticInputSettingsTab, title, string, _("Input"))
+       ATTRIB(XonoticInputSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticInputSettingsTab, rows, float, 15.5)
+       ATTRIB(XonoticInputSettingsTab, columns, float, 6.2) // added extra .2 for center space
+ENDCLASS(XonoticInputSettingsTab)
+entity makeXonoticInputSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticInputSettingsTab()
+{
+       entity me;
+       me = spawnXonoticInputSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void CheckBox_Click_Redisplay(entity me, entity checkbox)
+{
+       CheckBox_Click(me, checkbox);
+       cmd("\ndefer 0.2 \"togglemenu 1\"\n");
+       //m_display();
+}
+void XonoticInputSettingsTab_fill(entity me)
+{
+       entity e;
+       entity kb = makeXonoticKeyBinder();
+
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Key Bindings")));
+       me.TR(me);
+               me.TD(me, me.rows - 3, 3, kb);
+       me.gotoRC(me, me.rows - 2, 0);
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Change key..."), '0 0 0'));
+                       e.onClick = KeyBinder_Bind_Change;
+                       e.onClickEntity = kb;
+                       kb.keyGrabButton = e;
+               me.TD(me, 1, 1, e = makeXonoticButton(_("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 = makeXonoticButton(_("Clear"), '0 0 0'));
+                       e.onClick = KeyBinder_Bind_Clear;
+                       e.onClickEntity = kb;
+                       kb.clearButton = e;
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticButton(_("Reset all"), '0 0 0'));
+                       e.onClick = KeyBinder_Bind_Reset_All;
+                       e.onClickEntity = kb;
+
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Mouse")));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Sensitivity:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(1, 32, 0.2, "sensitivity"));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "m_filter", _("Smooth aiming")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(1.022, "m_pitch", _("Invert aiming")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "menu_mouse_absolute", _("Use system mouse positioning")));
+                       makeMulti(e, "hud_cursormode");
+                       e.onClick = CheckBox_Click_Redisplay;
+                       e.onClickEntity = e;
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "m_accelerate", _("Enable built in mouse acceleration")));
+       me.TR(me);
+               if(cvar_type("vid_dgamouse") & CVAR_TYPEFLAG_ENGINE)
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "vid_dgamouse", _("Disable system mouse acceleration")));
+               else if(cvar_type("apple_mouse_noaccel") & CVAR_TYPEFLAG_ENGINE)
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "apple_mouse_noaccel", _("Disable system mouse acceleration")));
+               else
+               {
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, string_null, _("Disable system mouse acceleration")));
+                       e.disabled = 1; // the option is never available in this case, just there for show
+               }
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Other")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "con_closeontoggleconsole", _("Pressing \"enter console\" key also closes it")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_movement_track_canjump", _("Automatically repeat jumping if holding jump")));
+                       e.sendCvars = TRUE;
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Jetpack on jump:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_jetpack_jump"));
+                       e.addValue(e, _("Disabled"), "0");
+                       e.addValue(e, _("Air only"), "1");
+                       e.addValue(e, _("All"), "2");
+                       e.configureXonoticTextSliderValues(e);
+                       e.sendCvars = TRUE;
+       me.TR(me);
+               if(cvar_type("joy_enable") & CVAR_TYPEFLAG_ENGINE)
+               {
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "joy_enable", _("Use joystick input")));
+                       setDependent(e, "joy_detected", 1, 10000000);
+               }
+               else if(cvar_type("joystick") & CVAR_TYPEFLAG_ENGINE)
+               {
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "joystick", _("Use joystick input")));
+                       setDependent(e, "joy_detected", 1, 10000000);
+               }
+               else
+               {
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, string_null, _("Use joystick input")));
+                       e.disabled = 1; // the option is never available in this case, just there for show
+               }
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_input_userbind.c b/qcsrc/menu/xonotic/dialog_settings_input_userbind.c
deleted file mode 100644 (file)
index aaf182f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticUserbindEditDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticUserbindEditDialog, loadUserBind, void(entity, string, string, string))
-       METHOD(XonoticUserbindEditDialog, fill, void(entity))
-       ATTRIB(XonoticUserbindEditDialog, title, string, _("User defined key bind"))
-       ATTRIB(XonoticUserbindEditDialog, color, vector, SKINCOLOR_DIALOG_USERBIND)
-       ATTRIB(XonoticUserbindEditDialog, intendedWidth, float, 0.7)
-       ATTRIB(XonoticUserbindEditDialog, rows, float, 4)
-       ATTRIB(XonoticUserbindEditDialog, columns, float, 3)
-       ATTRIB(XonoticUserbindEditDialog, keybindBox, entity, NULL)
-
-       ATTRIB(XonoticUserbindEditDialog, nameBox, entity, NULL)
-       ATTRIB(XonoticUserbindEditDialog, commandPressBox, entity, NULL)
-       ATTRIB(XonoticUserbindEditDialog, commandReleaseBox, entity, NULL)
-ENDCLASS(XonoticUserbindEditDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticUserbindEditDialog_Save(entity btn, entity me)
-{
-       me.keybindBox.editUserbind(me.keybindBox, me.nameBox.text, me.commandPressBox.text, me.commandReleaseBox.text);
-       Dialog_Close(btn, me);
-}
-
-void XonoticUserbindEditDialog_loadUserBind(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 XonoticUserbindEditDialog_fill(entity me)
-{
-       entity e;
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Name:")));
-               me.TD(me, 1, me.columns - 1, me.nameBox = makeXonoticInputBox(0, string_null));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Command when pressed:")));
-               me.TD(me, 1, me.columns - 1, me.commandPressBox = makeXonoticInputBox(0, string_null));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Command when released:")));
-               me.TD(me, 1, me.columns - 1, me.commandReleaseBox = makeXonoticInputBox(0, string_null));
-       me.TR(me);
-               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(_("Save"), '0 0 0'));
-                       e.onClick = XonoticUserbindEditDialog_Save;
-                       e.onClickEntity = me;
-               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(_("Cancel"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_input_userbind.qc b/qcsrc/menu/xonotic/dialog_settings_input_userbind.qc
new file mode 100644 (file)
index 0000000..aaf182f
--- /dev/null
@@ -0,0 +1,55 @@
+#ifdef INTERFACE
+CLASS(XonoticUserbindEditDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticUserbindEditDialog, loadUserBind, void(entity, string, string, string))
+       METHOD(XonoticUserbindEditDialog, fill, void(entity))
+       ATTRIB(XonoticUserbindEditDialog, title, string, _("User defined key bind"))
+       ATTRIB(XonoticUserbindEditDialog, color, vector, SKINCOLOR_DIALOG_USERBIND)
+       ATTRIB(XonoticUserbindEditDialog, intendedWidth, float, 0.7)
+       ATTRIB(XonoticUserbindEditDialog, rows, float, 4)
+       ATTRIB(XonoticUserbindEditDialog, columns, float, 3)
+       ATTRIB(XonoticUserbindEditDialog, keybindBox, entity, NULL)
+
+       ATTRIB(XonoticUserbindEditDialog, nameBox, entity, NULL)
+       ATTRIB(XonoticUserbindEditDialog, commandPressBox, entity, NULL)
+       ATTRIB(XonoticUserbindEditDialog, commandReleaseBox, entity, NULL)
+ENDCLASS(XonoticUserbindEditDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticUserbindEditDialog_Save(entity btn, entity me)
+{
+       me.keybindBox.editUserbind(me.keybindBox, me.nameBox.text, me.commandPressBox.text, me.commandReleaseBox.text);
+       Dialog_Close(btn, me);
+}
+
+void XonoticUserbindEditDialog_loadUserBind(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 XonoticUserbindEditDialog_fill(entity me)
+{
+       entity e;
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Name:")));
+               me.TD(me, 1, me.columns - 1, me.nameBox = makeXonoticInputBox(0, string_null));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Command when pressed:")));
+               me.TD(me, 1, me.columns - 1, me.commandPressBox = makeXonoticInputBox(0, string_null));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Command when released:")));
+               me.TD(me, 1, me.columns - 1, me.commandReleaseBox = makeXonoticInputBox(0, string_null));
+       me.TR(me);
+               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(_("Save"), '0 0 0'));
+                       e.onClick = XonoticUserbindEditDialog_Save;
+                       e.onClickEntity = me;
+               me.TD(me, 1, me.columns / 2, e = makeXonoticButton(_("Cancel"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_misc.c b/qcsrc/menu/xonotic/dialog_settings_misc.c
deleted file mode 100644 (file)
index 2ea9c1e..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticMiscSettingsTab) EXTENDS(XonoticTab)
-       METHOD(XonoticMiscSettingsTab, fill, void(entity))
-       ATTRIB(XonoticMiscSettingsTab, title, string, _("Misc"))
-       ATTRIB(XonoticMiscSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticMiscSettingsTab, rows, float, 15.5)
-       ATTRIB(XonoticMiscSettingsTab, columns, float, 6.2)
-ENDCLASS(XonoticMiscSettingsTab)
-entity makeXonoticMiscSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticMiscSettingsTab()
-{
-       entity me;
-       me = spawnXonoticMiscSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-void XonoticMiscSettingsTab_fill(entity me)
-{
-       entity e;
-       //entity sk;
-
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Network")));
-       me.TR(me);
-               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Client UDP port:")));
-               me.TD(me, 1, 1.5, e = makeXonoticInputBox(0, "cl_port"));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Bandwidth:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("_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"), "66666");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Input packets/s:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(20, 100, 5, "cl_netfps"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Server queries/s:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(20, 100, 10, "net_slist_queriespersecond"));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Downloads:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(1, 5, 1, "cl_curl_maxdownloads"));
-       me.TR(me);
-               me.TDempty(me, 0.1);
-               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Speed (kB/s):")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(10, 2000, 50, "cl_curl_maxspeed"));
-       me.TR(me);
-               if(cvar("developer"))
-               {
-                       me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Local latency:")));
-                       me.TD(me, 1, 2, e = makeXonoticSlider(0, 1000, 25, "cl_netlocalping"));
-               }
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "shownetgraph", _("Show netgraph")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_movement", _("Client-side movement prediction")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_movement_errorcompensation", _("Movement error compensation")));
-               setDependent(e, "cl_movement", 1, 1);
-       me.TR(me);
-               if(cvar_type("crypto_aeslevel") & CVAR_TYPEFLAG_ENGINE)
-                       me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "crypto_aeslevel", _("Use encryption (AES) when available"))); // TODO: move up
-
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Framerate")));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Maximum:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_maxfps"));
-                       e.addValue(e, ZCTX(_("MAXFPS^5 fps")), "5");
-                       e.addValue(e, ZCTX(_("MAXFPS^10 fps")), "10");
-                       e.addValue(e, ZCTX(_("MAXFPS^20 fps")), "20");
-                       e.addValue(e, ZCTX(_("MAXFPS^30 fps")), "30");
-                       e.addValue(e, ZCTX(_("MAXFPS^40 fps")), "40");
-                       e.addValue(e, ZCTX(_("MAXFPS^50 fps")), "50");
-                       e.addValue(e, ZCTX(_("MAXFPS^60 fps")), "60");
-                       e.addValue(e, ZCTX(_("MAXFPS^70 fps")), "70");
-                       e.addValue(e, ZCTX(_("MAXFPS^100 fps")), "100");
-                       e.addValue(e, ZCTX(_("MAXFPS^125 fps")), "125");
-                       e.addValue(e, ZCTX(_("MAXFPS^200 fps")), "200");
-                       e.addValue(e, ZCTX(_("MAXFPS^Unlimited")), "0");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Target:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_minfps"));
-                       e.addValue(e, ZCTX(_("TRGT^Disabled")), "0");
-                       e.addValue(e, ZCTX(_("TRGT^30 fps")), "30");
-                       e.addValue(e, ZCTX(_("TRGT^40 fps")), "40");
-                       e.addValue(e, ZCTX(_("TRGT^50 fps")), "50");
-                       e.addValue(e, ZCTX(_("TRGT^60 fps")), "60");
-                       e.addValue(e, ZCTX(_("TRGT^100 fps")), "100");
-                       e.addValue(e, ZCTX(_("TRGT^125 fps")), "125");
-                       e.addValue(e, ZCTX(_("TRGT^200 fps")), "200");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Idle limit:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_maxidlefps"));
-                       e.addValue(e, ZCTX(_("IDLFPS^10 fps")), "10");
-                       e.addValue(e, ZCTX(_("IDLFPS^20 fps")), "20");
-                       e.addValue(e, ZCTX(_("IDLFPS^30 fps")), "30");
-                       e.addValue(e, ZCTX(_("IDLFPS^60 fps")), "60");
-                       e.addValue(e, ZCTX(_("IDLFPS^Unlimited")), "0");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_maxfps_alwayssleep", _("Save processing time for other apps")));
-               setDependent(e, "cl_maxfps", 1, 1000);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "showfps", _("Show frames per second")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Other")));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Menu tooltips:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("menu_tooltips"));
-                       e.addValue(e, ZCTX(_("TLTIP^Disabled")), "0");
-                       e.addValue(e, ZCTX(_("TLTIP^Standard")), "1");
-                       e.addValue(e, ZCTX(_("TLTIP^Advanced")), "2");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "showtime", _("Show current date and time")));
-                       makeMulti(e, "showdate");
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "developer", _("Enable developer mode")));
-
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("Advanced settings..."), '0 0 0'));
-                       e.onClick = DialogOpenButton_Click;
-                       e.onClickEntity = main.cvarsDialog;
-       me.TR(me);
-               me.TDempty(me, 0.5);
-               me.TD(me, 1, 2, e = makeXonoticButton(_("Factory reset"), '0 0 0'));
-                       e.onClick = DialogOpenButton_Click;
-                       e.onClickEntity = main.resetDialog;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_misc.qc b/qcsrc/menu/xonotic/dialog_settings_misc.qc
new file mode 100644 (file)
index 0000000..2ea9c1e
--- /dev/null
@@ -0,0 +1,143 @@
+#ifdef INTERFACE
+CLASS(XonoticMiscSettingsTab) EXTENDS(XonoticTab)
+       METHOD(XonoticMiscSettingsTab, fill, void(entity))
+       ATTRIB(XonoticMiscSettingsTab, title, string, _("Misc"))
+       ATTRIB(XonoticMiscSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticMiscSettingsTab, rows, float, 15.5)
+       ATTRIB(XonoticMiscSettingsTab, columns, float, 6.2)
+ENDCLASS(XonoticMiscSettingsTab)
+entity makeXonoticMiscSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticMiscSettingsTab()
+{
+       entity me;
+       me = spawnXonoticMiscSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticMiscSettingsTab_fill(entity me)
+{
+       entity e;
+       //entity sk;
+
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Network")));
+       me.TR(me);
+               me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Client UDP port:")));
+               me.TD(me, 1, 1.5, e = makeXonoticInputBox(0, "cl_port"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Bandwidth:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("_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"), "66666");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Input packets/s:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(20, 100, 5, "cl_netfps"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Server queries/s:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(20, 100, 10, "net_slist_queriespersecond"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Downloads:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(1, 5, 1, "cl_curl_maxdownloads"));
+       me.TR(me);
+               me.TDempty(me, 0.1);
+               me.TD(me, 1, 0.9, e = makeXonoticTextLabel(0, _("Speed (kB/s):")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(10, 2000, 50, "cl_curl_maxspeed"));
+       me.TR(me);
+               if(cvar("developer"))
+               {
+                       me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Local latency:")));
+                       me.TD(me, 1, 2, e = makeXonoticSlider(0, 1000, 25, "cl_netlocalping"));
+               }
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "shownetgraph", _("Show netgraph")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_movement", _("Client-side movement prediction")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_movement_errorcompensation", _("Movement error compensation")));
+               setDependent(e, "cl_movement", 1, 1);
+       me.TR(me);
+               if(cvar_type("crypto_aeslevel") & CVAR_TYPEFLAG_ENGINE)
+                       me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 1, "crypto_aeslevel", _("Use encryption (AES) when available"))); // TODO: move up
+
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Framerate")));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Maximum:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_maxfps"));
+                       e.addValue(e, ZCTX(_("MAXFPS^5 fps")), "5");
+                       e.addValue(e, ZCTX(_("MAXFPS^10 fps")), "10");
+                       e.addValue(e, ZCTX(_("MAXFPS^20 fps")), "20");
+                       e.addValue(e, ZCTX(_("MAXFPS^30 fps")), "30");
+                       e.addValue(e, ZCTX(_("MAXFPS^40 fps")), "40");
+                       e.addValue(e, ZCTX(_("MAXFPS^50 fps")), "50");
+                       e.addValue(e, ZCTX(_("MAXFPS^60 fps")), "60");
+                       e.addValue(e, ZCTX(_("MAXFPS^70 fps")), "70");
+                       e.addValue(e, ZCTX(_("MAXFPS^100 fps")), "100");
+                       e.addValue(e, ZCTX(_("MAXFPS^125 fps")), "125");
+                       e.addValue(e, ZCTX(_("MAXFPS^200 fps")), "200");
+                       e.addValue(e, ZCTX(_("MAXFPS^Unlimited")), "0");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Target:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_minfps"));
+                       e.addValue(e, ZCTX(_("TRGT^Disabled")), "0");
+                       e.addValue(e, ZCTX(_("TRGT^30 fps")), "30");
+                       e.addValue(e, ZCTX(_("TRGT^40 fps")), "40");
+                       e.addValue(e, ZCTX(_("TRGT^50 fps")), "50");
+                       e.addValue(e, ZCTX(_("TRGT^60 fps")), "60");
+                       e.addValue(e, ZCTX(_("TRGT^100 fps")), "100");
+                       e.addValue(e, ZCTX(_("TRGT^125 fps")), "125");
+                       e.addValue(e, ZCTX(_("TRGT^200 fps")), "200");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Idle limit:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_maxidlefps"));
+                       e.addValue(e, ZCTX(_("IDLFPS^10 fps")), "10");
+                       e.addValue(e, ZCTX(_("IDLFPS^20 fps")), "20");
+                       e.addValue(e, ZCTX(_("IDLFPS^30 fps")), "30");
+                       e.addValue(e, ZCTX(_("IDLFPS^60 fps")), "60");
+                       e.addValue(e, ZCTX(_("IDLFPS^Unlimited")), "0");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_maxfps_alwayssleep", _("Save processing time for other apps")));
+               setDependent(e, "cl_maxfps", 1, 1000);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "showfps", _("Show frames per second")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticHeaderLabel(_("Other")));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Menu tooltips:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("menu_tooltips"));
+                       e.addValue(e, ZCTX(_("TLTIP^Disabled")), "0");
+                       e.addValue(e, ZCTX(_("TLTIP^Standard")), "1");
+                       e.addValue(e, ZCTX(_("TLTIP^Advanced")), "2");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "showtime", _("Show current date and time")));
+                       makeMulti(e, "showdate");
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "developer", _("Enable developer mode")));
+
+       me.TR(me);
+               me.TDempty(me, 0.5);
+               me.TD(me, 1, 2, e = makeXonoticButton(_("Advanced settings..."), '0 0 0'));
+                       e.onClick = DialogOpenButton_Click;
+                       e.onClickEntity = main.cvarsDialog;
+       me.TR(me);
+               me.TDempty(me, 0.5);
+               me.TD(me, 1, 2, e = makeXonoticButton(_("Factory reset"), '0 0 0'));
+                       e.onClick = DialogOpenButton_Click;
+                       e.onClickEntity = main.resetDialog;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_misc_cvars.c b/qcsrc/menu/xonotic/dialog_settings_misc_cvars.c
deleted file mode 100644 (file)
index c2ea2a5..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCvarsDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticCvarsDialog, fill, void(entity))
-       METHOD(XonoticCvarsDialog, showNotify, void(entity))
-       ATTRIB(XonoticCvarsDialog, title, string, _("Advanced settings"))
-       ATTRIB(XonoticCvarsDialog, color, vector, SKINCOLOR_DIALOG_CVARS)
-       ATTRIB(XonoticCvarsDialog, intendedWidth, float, 0.8)
-       ATTRIB(XonoticCvarsDialog, rows, float, 24)
-       ATTRIB(XonoticCvarsDialog, columns, float, 6)
-ENDCLASS(XonoticCvarsDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticCvarsDialog_showNotify(entity me)
-{
-       loadAllCvars(me);
-}
-void XonoticCvarsDialog_fill(entity me) // in this dialog, use SKINCOLOR_CVARLIST_CONTROLS to color ALL controls
-{
-
-       entity e, cvarlist;
-
-       cvarlist = makeXonoticCvarList();
-
-       cvarlist.color =
-               cvarlist.colorF =
-               cvarlist.color2 =
-               cvarlist.colorC =
-               SKINCOLOR_CVARLIST_CONTROLS;
-
-       // todo:
-       // add button which does cvar_resettodefaults_saveonly
-
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Cvar filter:")));
-               me.TD(me, 1, me.columns - 1, e = makeXonoticInputBox(0, string_null));
-                       e.color = SKINCOLOR_CVARLIST_CONTROLS;
-                       e.colorF = SKINCOLOR_CVARLIST_CONTROLS;
-                       e.cb_color = SKINCOLOR_CVARLIST_CONTROLS;
-                       e.cb_colorC = SKINCOLOR_CVARLIST_CONTROLS;
-                       e.cb_colorF = SKINCOLOR_CVARLIST_CONTROLS;
-                       e.onChange = CvarList_Filter_Change;
-                       e.onChangeEntity = cvarlist;
-                       cvarlist.controlledTextbox = e; // this COULD also be the Value box, but this leads to accidentally editing stuff
-       me.TR(me);
-               me.TD(me, me.rows - me.currentRow - 9, me.columns, cvarlist);
-       me.gotoRC(me, me.rows - 8, 0);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Setting:")));
-               me.TD(me, 1, me.columns - 1, e = makeXonoticTextLabel(0, string_null));
-                       cvarlist.cvarNameBox = e;
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Type:")));
-               me.TD(me, 1, me.columns - 1, e = makeXonoticTextLabel(0, string_null));
-                       cvarlist.cvarTypeBox = e;
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Value:")));
-               me.TD(me, 1, me.columns - 2, e = makeXonoticInputBox(0, string_null));
-                       cvarlist.cvarValueBox = e;
-                       e.color = SKINCOLOR_CVARLIST_CONTROLS;
-                       e.colorF = SKINCOLOR_CVARLIST_CONTROLS;
-                       e.cb_color = SKINCOLOR_CVARLIST_CONTROLS;
-                       e.cb_colorC = SKINCOLOR_CVARLIST_CONTROLS;
-                       e.cb_colorF = SKINCOLOR_CVARLIST_CONTROLS;
-                       e.onChange = CvarList_Value_Change;
-                       e.onChangeEntity = cvarlist;
-                       e.onEnter = CvarList_End_Editing;
-                       e.onEnterEntity = cvarlist;
-               me.TD(me, 1, 1, e = makeXonoticButton(string_null, SKINCOLOR_CVARLIST_CONTROLS));
-                       cvarlist.cvarDefaultBox = e;
-                       e.onClick = CvarList_Revert_Click;
-                       e.onClickEntity = cvarlist;
-                       e.allowCut = 1;
-                       e.marginLeft = e.marginRight = 0.5;
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Description:")));
-               me.TD(me, 1, me.columns - 1, e = makeXonoticTextLabel(0, string_null));
-                       cvarlist.cvarDescriptionBox = e;
-                       e.allowWrap = 1;
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), SKINCOLOR_CVARLIST_CONTROLS));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc b/qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc
new file mode 100644 (file)
index 0000000..c2ea2a5
--- /dev/null
@@ -0,0 +1,86 @@
+#ifdef INTERFACE
+CLASS(XonoticCvarsDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticCvarsDialog, fill, void(entity))
+       METHOD(XonoticCvarsDialog, showNotify, void(entity))
+       ATTRIB(XonoticCvarsDialog, title, string, _("Advanced settings"))
+       ATTRIB(XonoticCvarsDialog, color, vector, SKINCOLOR_DIALOG_CVARS)
+       ATTRIB(XonoticCvarsDialog, intendedWidth, float, 0.8)
+       ATTRIB(XonoticCvarsDialog, rows, float, 24)
+       ATTRIB(XonoticCvarsDialog, columns, float, 6)
+ENDCLASS(XonoticCvarsDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticCvarsDialog_showNotify(entity me)
+{
+       loadAllCvars(me);
+}
+void XonoticCvarsDialog_fill(entity me) // in this dialog, use SKINCOLOR_CVARLIST_CONTROLS to color ALL controls
+{
+
+       entity e, cvarlist;
+
+       cvarlist = makeXonoticCvarList();
+
+       cvarlist.color =
+               cvarlist.colorF =
+               cvarlist.color2 =
+               cvarlist.colorC =
+               SKINCOLOR_CVARLIST_CONTROLS;
+
+       // todo:
+       // add button which does cvar_resettodefaults_saveonly
+
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Cvar filter:")));
+               me.TD(me, 1, me.columns - 1, e = makeXonoticInputBox(0, string_null));
+                       e.color = SKINCOLOR_CVARLIST_CONTROLS;
+                       e.colorF = SKINCOLOR_CVARLIST_CONTROLS;
+                       e.cb_color = SKINCOLOR_CVARLIST_CONTROLS;
+                       e.cb_colorC = SKINCOLOR_CVARLIST_CONTROLS;
+                       e.cb_colorF = SKINCOLOR_CVARLIST_CONTROLS;
+                       e.onChange = CvarList_Filter_Change;
+                       e.onChangeEntity = cvarlist;
+                       cvarlist.controlledTextbox = e; // this COULD also be the Value box, but this leads to accidentally editing stuff
+       me.TR(me);
+               me.TD(me, me.rows - me.currentRow - 9, me.columns, cvarlist);
+       me.gotoRC(me, me.rows - 8, 0);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Setting:")));
+               me.TD(me, 1, me.columns - 1, e = makeXonoticTextLabel(0, string_null));
+                       cvarlist.cvarNameBox = e;
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Type:")));
+               me.TD(me, 1, me.columns - 1, e = makeXonoticTextLabel(0, string_null));
+                       cvarlist.cvarTypeBox = e;
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Value:")));
+               me.TD(me, 1, me.columns - 2, e = makeXonoticInputBox(0, string_null));
+                       cvarlist.cvarValueBox = e;
+                       e.color = SKINCOLOR_CVARLIST_CONTROLS;
+                       e.colorF = SKINCOLOR_CVARLIST_CONTROLS;
+                       e.cb_color = SKINCOLOR_CVARLIST_CONTROLS;
+                       e.cb_colorC = SKINCOLOR_CVARLIST_CONTROLS;
+                       e.cb_colorF = SKINCOLOR_CVARLIST_CONTROLS;
+                       e.onChange = CvarList_Value_Change;
+                       e.onChangeEntity = cvarlist;
+                       e.onEnter = CvarList_End_Editing;
+                       e.onEnterEntity = cvarlist;
+               me.TD(me, 1, 1, e = makeXonoticButton(string_null, SKINCOLOR_CVARLIST_CONTROLS));
+                       cvarlist.cvarDefaultBox = e;
+                       e.onClick = CvarList_Revert_Click;
+                       e.onClickEntity = cvarlist;
+                       e.allowCut = 1;
+                       e.marginLeft = e.marginRight = 0.5;
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Description:")));
+               me.TD(me, 1, me.columns - 1, e = makeXonoticTextLabel(0, string_null));
+                       cvarlist.cvarDescriptionBox = e;
+                       e.allowWrap = 1;
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), SKINCOLOR_CVARLIST_CONTROLS));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_misc_reset.c b/qcsrc/menu/xonotic/dialog_settings_misc_reset.c
deleted file mode 100644 (file)
index 8f6da0a..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticResetDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticResetDialog, fill, void(entity))
-       ATTRIB(XonoticResetDialog, title, string, _("Factory reset"))
-       ATTRIB(XonoticResetDialog, color, vector, SKINCOLOR_DIALOG_QUIT)
-       ATTRIB(XonoticResetDialog, intendedWidth, float, 0.5)
-       ATTRIB(XonoticResetDialog, rows, float, 4)
-       ATTRIB(XonoticResetDialog, columns, float, 2)
-       ATTRIB(XonoticResetDialog, name, string, "Factory reset")
-ENDCLASS(XonoticResetDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticResetDialog_fill(entity me)
-{
-       entity e;
-       me.TR(me);
-               me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("Are you sure you want to reset all settings?")));
-       me.TR(me);
-               me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("This will create a backup config in your data directory")));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCommandButton(_("Yes"), '1 0 0', "saveconfig backup.cfg\n;\n exec defaultXonotic.cfg\n", 0));
-               me.TD(me, 1, 1, e = makeXonoticButton(_("No"), '0 1 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_misc_reset.qc b/qcsrc/menu/xonotic/dialog_settings_misc_reset.qc
new file mode 100644 (file)
index 0000000..8f6da0a
--- /dev/null
@@ -0,0 +1,28 @@
+#ifdef INTERFACE
+CLASS(XonoticResetDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticResetDialog, fill, void(entity))
+       ATTRIB(XonoticResetDialog, title, string, _("Factory reset"))
+       ATTRIB(XonoticResetDialog, color, vector, SKINCOLOR_DIALOG_QUIT)
+       ATTRIB(XonoticResetDialog, intendedWidth, float, 0.5)
+       ATTRIB(XonoticResetDialog, rows, float, 4)
+       ATTRIB(XonoticResetDialog, columns, float, 2)
+       ATTRIB(XonoticResetDialog, name, string, "Factory reset")
+ENDCLASS(XonoticResetDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticResetDialog_fill(entity me)
+{
+       entity e;
+       me.TR(me);
+               me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("Are you sure you want to reset all settings?")));
+       me.TR(me);
+               me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("This will create a backup config in your data directory")));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCommandButton(_("Yes"), '1 0 0', "saveconfig backup.cfg\n;\n exec defaultXonotic.cfg\n", 0));
+               me.TD(me, 1, 1, e = makeXonoticButton(_("No"), '0 1 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_user.c b/qcsrc/menu/xonotic/dialog_settings_user.c
deleted file mode 100644 (file)
index 180efcc..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticUserSettingsTab) EXTENDS(XonoticTab)
-       METHOD(XonoticUserSettingsTab, fill, void(entity))
-       ATTRIB(XonoticUserSettingsTab, title, string, _("User"))
-       ATTRIB(XonoticUserSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticUserSettingsTab, rows, float, 15.5)
-       ATTRIB(XonoticUserSettingsTab, columns, float, 6)
-ENDCLASS(XonoticUserSettingsTab)
-entity makeXonoticUserSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticUserSettingsTab()
-{
-       entity me;
-       me = spawnXonoticUserSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-
-void XonoticUserSettingsTab_fill(entity me)
-{
-       entity e;
-       entity sk;
-
-       me.TR(me);
-               me.TDempty(me, 0.25);
-               me.TD(me, 1, 2.5, e = makeXonoticHeaderLabel(_("Menu Skins")));
-       me.TR(me);
-               me.TDempty(me, 0.25);
-               me.TD(me, me.rows - 2.5, 2.5, sk = makeXonoticSkinList());
-       me.gotoRC(me, me.rows - 1.5, 0.25);
-               me.TD(me, 1, 2.5, e = makeXonoticButton(_("Set skin"), '0 0 0'));
-                       e.onClick = SetSkin_Click;
-                       e.onClickEntity = sk;
-
-       /* AFTER 0.6 RELEASE TODO: Add a listbox which has fonts too, this way user can select the font they want.
-       me.gotoRC(me, 0, 2.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Text language:")));
-       me.TR(me);
-               me.TD(me, 6, 1, sk = makeXonoticLanguageList());
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticButton(_("Set language"), '0 0 0'));
-                       e.onClick = SetLanguage_Click;
-                       e.onClickEntity = sk;
-
-       me.gotoRC(me, 0, 3.3); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("Font:")));
-       me.TR(me);
-               me.TD(me, 2, 1.5, sk = makeXonoticLanguageList());
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1.5, e = makeXonoticButton(_("Set font"), '0 0 0'));
-                       e.onClick = SetLanguage_Click;
-                       e.onClickEntity = sk;*/
-
-       me.gotoRC(me, 0, 3.75); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 1.5, e = makeXonoticHeaderLabel(_("Text Language")));
-       me.TR(me);
-               me.TD(me, 8, 1.5, sk = makeXonoticLanguageList());
-
-       me.gotoRC(me, 9, 3.75); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 1.5, e = makeXonoticButton(_("Set language"), '0 0 0'));
-                       e.onClick = SetLanguage_Click;
-                       e.onClickEntity = sk;
-
-       me.gotoRC(me, 11.5, 3.25); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_gentle", _("Disable gore effects and harsh language")));
-
-       //me.TR(me);
-       //      me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Menu tooltips:")));
-       //      me.TD(me, 1, 2, e = makeXonoticTextSlider("menu_tooltips"));
-       //              e.addValue(e, ZCTX(_("TLTIP^Disabled")), "0");
-       //              e.addValue(e, ZCTX(_("TLTIP^Standard")), "1");
-       //              e.addValue(e, ZCTX(_("TLTIP^Advanced")), "2");
-       //              e.configureXonoticTextSliderValues(e);
-       //me.TR(me);
-       //      me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_allow_uidtracking", _("Allow player statistics to track your client"))); // TODO: move to profile tab
-       //me.TR(me);
-       //      me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_allow_uid2name", _("Allow player statistics to use your nickname")));
-       //      setDependent(e, "cl_allow_uidtracking", 1, 1);
-
-       //me.gotoRC(me, me.rows - 1, 2.6);
-       //      me.TD(me, 1, 2, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "sendcvar cl_gentle; sendcvar cl_allow_uidtracking; sendcvar cl_allow_uid2name;", COMMANDBUTTON_APPLY));
-
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_user.qc b/qcsrc/menu/xonotic/dialog_settings_user.qc
new file mode 100644 (file)
index 0000000..180efcc
--- /dev/null
@@ -0,0 +1,96 @@
+#ifdef INTERFACE
+CLASS(XonoticUserSettingsTab) EXTENDS(XonoticTab)
+       METHOD(XonoticUserSettingsTab, fill, void(entity))
+       ATTRIB(XonoticUserSettingsTab, title, string, _("User"))
+       ATTRIB(XonoticUserSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticUserSettingsTab, rows, float, 15.5)
+       ATTRIB(XonoticUserSettingsTab, columns, float, 6)
+ENDCLASS(XonoticUserSettingsTab)
+entity makeXonoticUserSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticUserSettingsTab()
+{
+       entity me;
+       me = spawnXonoticUserSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+
+void XonoticUserSettingsTab_fill(entity me)
+{
+       entity e;
+       entity sk;
+
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, 1, 2.5, e = makeXonoticHeaderLabel(_("Menu Skins")));
+       me.TR(me);
+               me.TDempty(me, 0.25);
+               me.TD(me, me.rows - 2.5, 2.5, sk = makeXonoticSkinList());
+       me.gotoRC(me, me.rows - 1.5, 0.25);
+               me.TD(me, 1, 2.5, e = makeXonoticButton(_("Set skin"), '0 0 0'));
+                       e.onClick = SetSkin_Click;
+                       e.onClickEntity = sk;
+
+       /* AFTER 0.6 RELEASE TODO: Add a listbox which has fonts too, this way user can select the font they want.
+       me.gotoRC(me, 0, 2.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Text language:")));
+       me.TR(me);
+               me.TD(me, 6, 1, sk = makeXonoticLanguageList());
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticButton(_("Set language"), '0 0 0'));
+                       e.onClick = SetLanguage_Click;
+                       e.onClickEntity = sk;
+
+       me.gotoRC(me, 0, 3.3); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1.5, e = makeXonoticTextLabel(0, _("Font:")));
+       me.TR(me);
+               me.TD(me, 2, 1.5, sk = makeXonoticLanguageList());
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1.5, e = makeXonoticButton(_("Set font"), '0 0 0'));
+                       e.onClick = SetLanguage_Click;
+                       e.onClickEntity = sk;*/
+
+       me.gotoRC(me, 0, 3.75); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1.5, e = makeXonoticHeaderLabel(_("Text Language")));
+       me.TR(me);
+               me.TD(me, 8, 1.5, sk = makeXonoticLanguageList());
+
+       me.gotoRC(me, 9, 3.75); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1.5, e = makeXonoticButton(_("Set language"), '0 0 0'));
+                       e.onClick = SetLanguage_Click;
+                       e.onClickEntity = sk;
+
+       me.gotoRC(me, 11.5, 3.25); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_gentle", _("Disable gore effects and harsh language")));
+
+       //me.TR(me);
+       //      me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Menu tooltips:")));
+       //      me.TD(me, 1, 2, e = makeXonoticTextSlider("menu_tooltips"));
+       //              e.addValue(e, ZCTX(_("TLTIP^Disabled")), "0");
+       //              e.addValue(e, ZCTX(_("TLTIP^Standard")), "1");
+       //              e.addValue(e, ZCTX(_("TLTIP^Advanced")), "2");
+       //              e.configureXonoticTextSliderValues(e);
+       //me.TR(me);
+       //      me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_allow_uidtracking", _("Allow player statistics to track your client"))); // TODO: move to profile tab
+       //me.TR(me);
+       //      me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_allow_uid2name", _("Allow player statistics to use your nickname")));
+       //      setDependent(e, "cl_allow_uidtracking", 1, 1);
+
+       //me.gotoRC(me, me.rows - 1, 2.6);
+       //      me.TD(me, 1, 2, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "sendcvar cl_gentle; sendcvar cl_allow_uidtracking; sendcvar cl_allow_uid2name;", COMMANDBUTTON_APPLY));
+
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_user_languagewarning.c b/qcsrc/menu/xonotic/dialog_settings_user_languagewarning.c
deleted file mode 100644 (file)
index c830b55..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticLanguageWarningDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticLanguageWarningDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
-       ATTRIB(XonoticLanguageWarningDialog, title, string, _("Warning"))
-       ATTRIB(XonoticLanguageWarningDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
-       ATTRIB(XonoticLanguageWarningDialog, intendedWidth, float, 0.6)
-       ATTRIB(XonoticLanguageWarningDialog, rows, float, 5)
-       ATTRIB(XonoticLanguageWarningDialog, columns, float, 4)
-ENDCLASS(XonoticLanguageWarningDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticLanguageWarningDialog_fill(entity me)
-{
-       entity e;
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("While connected language changes will be applied only to the menu,")));
-       me.TR(me);
-               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("full language changes will take effect starting from the next game")));
-       me.TR(me);
-       me.TR(me);
-               // reconnect command doesn't work properly, otherwise it would replace disconnect
-               me.TD(me, 1, 2, e = makeXonoticCommandButton(_("Disconnect now"), '0 0 0', "disconnect", 0));
-               me.TD(me, 1, 2, e = makeXonoticCommandButton(_("Switch language"), '0 0 0', "prvm_language \"$_menu_prvm_language\"; menu_restart; menu_cmd languageselect", 0));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc b/qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc
new file mode 100644 (file)
index 0000000..c830b55
--- /dev/null
@@ -0,0 +1,26 @@
+#ifdef INTERFACE
+CLASS(XonoticLanguageWarningDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticLanguageWarningDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
+       ATTRIB(XonoticLanguageWarningDialog, title, string, _("Warning"))
+       ATTRIB(XonoticLanguageWarningDialog, color, vector, SKINCOLOR_DIALOG_HUDCONFIRM)
+       ATTRIB(XonoticLanguageWarningDialog, intendedWidth, float, 0.6)
+       ATTRIB(XonoticLanguageWarningDialog, rows, float, 5)
+       ATTRIB(XonoticLanguageWarningDialog, columns, float, 4)
+ENDCLASS(XonoticLanguageWarningDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticLanguageWarningDialog_fill(entity me)
+{
+       entity e;
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("While connected language changes will be applied only to the menu,")));
+       me.TR(me);
+               me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("full language changes will take effect starting from the next game")));
+       me.TR(me);
+       me.TR(me);
+               // reconnect command doesn't work properly, otherwise it would replace disconnect
+               me.TD(me, 1, 2, e = makeXonoticCommandButton(_("Disconnect now"), '0 0 0', "disconnect", 0));
+               me.TD(me, 1, 2, e = makeXonoticCommandButton(_("Switch language"), '0 0 0', "prvm_language \"$_menu_prvm_language\"; menu_restart; menu_cmd languageselect", 0));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_video.c b/qcsrc/menu/xonotic/dialog_settings_video.c
deleted file mode 100644 (file)
index 36929cb..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticVideoSettingsTab) EXTENDS(XonoticTab)
-       METHOD(XonoticVideoSettingsTab, fill, void(entity))
-       ATTRIB(XonoticVideoSettingsTab, title, string, _("Video"))
-       ATTRIB(XonoticVideoSettingsTab, intendedWidth, float, 0.9)
-       ATTRIB(XonoticVideoSettingsTab, rows, float, 15.5)
-       ATTRIB(XonoticVideoSettingsTab, columns, float, 6.2) // added extra .2 for center space
-       ATTRIB(XonoticVideoSettingsTab, name, string, "videosettings")
-ENDCLASS(XonoticVideoSettingsTab)
-entity makeXonoticVideoSettingsTab();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticVideoSettingsTab()
-{
-       entity me;
-       me = spawnXonoticVideoSettingsTab();
-       me.configureDialog(me);
-       return me;
-}
-void XonoticVideoSettingsTab_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Resolution:")));
-               me.TD(me, 1, 2, e = makeXonoticResolutionSlider());
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Font/UI size:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("menu_vid_scale"));
-                       e.addValue(e, ZCTX(_("SZ^Unreadable")), "-1");
-                       e.addValue(e, ZCTX(_("SZ^Tiny")), "-0.75");
-                       e.addValue(e, ZCTX(_("SZ^Little")), "-0.5");
-                       e.addValue(e, ZCTX(_("SZ^Small")), "-0.25");
-                       e.addValue(e, ZCTX(_("SZ^Medium")), "0");
-                       e.addValue(e, ZCTX(_("SZ^Large")), "0.25");
-                       e.addValue(e, ZCTX(_("SZ^Huge")), "0.5");
-                       e.addValue(e, ZCTX(_("SZ^Gigantic")), "0.75");
-                       e.addValue(e, ZCTX(_("SZ^Colossal")), "1");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Color depth:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("vid_bitsperpixel"));
-                       e.addValue(e, _("16bit"), "16");
-                       e.addValue(e, _("32bit"), "32");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "vid_fullscreen", _("Full screen")));
-               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "vid_vsync", _("Vertical Synchronization")));
-
-       me.TR(me);
-               if(cvar("developer"))
-                       { me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "v_flipped", _("Flip view horizontally"))); }
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Anisotropy:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("gl_texture_anisotropy"));
-                       e.addValue(e, ZCTX(_("ANISO^Disabled")), "1");
-                       e.addValue(e, _("2x"), "2");
-                       e.addValue(e, _("4x"), "4");
-                       e.addValue(e, _("8x"), "8");
-                       e.addValue(e, _("16x"), "16");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Antialiasing:")));
-                       setDependent(e, "r_viewfbo", 0, 0);
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("vid_samples"));
-                       e.addValue(e, ZCTX(_("AA^Disabled")), "1");
-                       e.addValue(e, _("2x"), "2");
-                       e.addValue(e, _("4x"), "4");
-                       e.configureXonoticTextSliderValues(e);
-                       setDependent(e, "r_viewfbo", 0, 0);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 0, "r_viewfbo", _("High-quality frame buffer")));
-                       setDependent(e, "vid_samples", 1, 1);
-
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Depth first:")));
-               me.TD(me, 1, 2, e = makeXonoticTextSlider("r_depthfirst"));
-                       e.addValue(e, ZCTX(_("DF^Disabled")), "0");
-                       e.addValue(e, ZCTX(_("DF^World")), "1");
-                       e.addValue(e, ZCTX(_("DF^All")), "2");
-                       e.configureXonoticTextSliderValues(e);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Vertex Buffer Objects (VBOs)")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "gl_vbo", "0", ZCTX(_("VBO^Off"))));
-               me.TD(me, 1, 1.9, e = makeXonoticRadioButton(1, "gl_vbo", "3", _("Vertices, some Tris (compatible)")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "gl_vbo", "2", _("Vertices")));
-               me.TD(me, 1, 1.9, e = makeXonoticRadioButton(1, "gl_vbo", "1", _("Vertices and Triangles")));
-
-       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Brightness:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.0, 0.5, 0.02, "v_brightness"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Contrast:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(1.0, 3.0, 0.05, "v_contrast"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gamma:")));
-                       setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.5, 2.0, 0.05, "v_gamma"));
-                       setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Contrast boost:")));
-                       setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(1.0, 5.0, 0.1, "v_contrastboost"));
-                       setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Saturation:")));
-                       setDependent(e, "vid_gl20", 1, 1);
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.5, 2.0, 0.05, "r_glsl_saturation"));
-                       setDependent(e, "vid_gl20", 1, 1);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("LIT^Ambient:"))));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0, 20.0, 0.25, "r_ambient"));
-       me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Intensity:")));
-               me.TD(me, 1, 2, e = makeXonoticSlider(0.5, 2.0, 0.05, "r_hdr_scenebrightness"));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "gl_finish", _("Wait for GPU to finish each frame")));
-       me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "vid_gl20", _("Use OpenGL 2.0 shaders (GLSL)")));
-       me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "v_glslgamma", _("Use GLSL to handle color control")));
-                       setDependent(e, "vid_gl20", 1, 1);
-       if(cvar("developer"))
-       {
-               me.TR(me);
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "v_psycho", _("Psycho coloring (easter egg)")));
-                               setDependent(e, "vid_gl20", 1, 1);
-               me.TR(me);
-                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "r_trippy", _("Trippy vertices (easter egg)")));
-                               setDependent(e, "vid_gl20", 1, 1);
-       }
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "vid_width $_menu_vid_width; vid_height $_menu_vid_height; vid_pixelheight $_menu_vid_pixelheight; vid_desktopfullscreen $_menu_vid_desktopfullscreen; menu_cmd update_conwidths_before_vid_restart; vid_restart; menu_cmd sync", COMMANDBUTTON_APPLY));
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_settings_video.qc b/qcsrc/menu/xonotic/dialog_settings_video.qc
new file mode 100644 (file)
index 0000000..36929cb
--- /dev/null
@@ -0,0 +1,145 @@
+#ifdef INTERFACE
+CLASS(XonoticVideoSettingsTab) EXTENDS(XonoticTab)
+       METHOD(XonoticVideoSettingsTab, fill, void(entity))
+       ATTRIB(XonoticVideoSettingsTab, title, string, _("Video"))
+       ATTRIB(XonoticVideoSettingsTab, intendedWidth, float, 0.9)
+       ATTRIB(XonoticVideoSettingsTab, rows, float, 15.5)
+       ATTRIB(XonoticVideoSettingsTab, columns, float, 6.2) // added extra .2 for center space
+       ATTRIB(XonoticVideoSettingsTab, name, string, "videosettings")
+ENDCLASS(XonoticVideoSettingsTab)
+entity makeXonoticVideoSettingsTab();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticVideoSettingsTab()
+{
+       entity me;
+       me = spawnXonoticVideoSettingsTab();
+       me.configureDialog(me);
+       return me;
+}
+void XonoticVideoSettingsTab_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Resolution:")));
+               me.TD(me, 1, 2, e = makeXonoticResolutionSlider());
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Font/UI size:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("menu_vid_scale"));
+                       e.addValue(e, ZCTX(_("SZ^Unreadable")), "-1");
+                       e.addValue(e, ZCTX(_("SZ^Tiny")), "-0.75");
+                       e.addValue(e, ZCTX(_("SZ^Little")), "-0.5");
+                       e.addValue(e, ZCTX(_("SZ^Small")), "-0.25");
+                       e.addValue(e, ZCTX(_("SZ^Medium")), "0");
+                       e.addValue(e, ZCTX(_("SZ^Large")), "0.25");
+                       e.addValue(e, ZCTX(_("SZ^Huge")), "0.5");
+                       e.addValue(e, ZCTX(_("SZ^Gigantic")), "0.75");
+                       e.addValue(e, ZCTX(_("SZ^Colossal")), "1");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Color depth:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("vid_bitsperpixel"));
+                       e.addValue(e, _("16bit"), "16");
+                       e.addValue(e, _("32bit"), "32");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "vid_fullscreen", _("Full screen")));
+               me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "vid_vsync", _("Vertical Synchronization")));
+
+       me.TR(me);
+               if(cvar("developer"))
+                       { me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "v_flipped", _("Flip view horizontally"))); }
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Anisotropy:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("gl_texture_anisotropy"));
+                       e.addValue(e, ZCTX(_("ANISO^Disabled")), "1");
+                       e.addValue(e, _("2x"), "2");
+                       e.addValue(e, _("4x"), "4");
+                       e.addValue(e, _("8x"), "8");
+                       e.addValue(e, _("16x"), "16");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Antialiasing:")));
+                       setDependent(e, "r_viewfbo", 0, 0);
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("vid_samples"));
+                       e.addValue(e, ZCTX(_("AA^Disabled")), "1");
+                       e.addValue(e, _("2x"), "2");
+                       e.addValue(e, _("4x"), "4");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "r_viewfbo", 0, 0);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBoxEx(2, 0, "r_viewfbo", _("High-quality frame buffer")));
+                       setDependent(e, "vid_samples", 1, 1);
+
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Depth first:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("r_depthfirst"));
+                       e.addValue(e, ZCTX(_("DF^Disabled")), "0");
+                       e.addValue(e, ZCTX(_("DF^World")), "1");
+                       e.addValue(e, ZCTX(_("DF^All")), "2");
+                       e.configureXonoticTextSliderValues(e);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticTextLabel(0, _("Vertex Buffer Objects (VBOs)")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "gl_vbo", "0", ZCTX(_("VBO^Off"))));
+               me.TD(me, 1, 1.9, e = makeXonoticRadioButton(1, "gl_vbo", "3", _("Vertices, some Tris (compatible)")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "gl_vbo", "2", _("Vertices")));
+               me.TD(me, 1, 1.9, e = makeXonoticRadioButton(1, "gl_vbo", "1", _("Vertices and Triangles")));
+
+       me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Brightness:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.0, 0.5, 0.02, "v_brightness"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Contrast:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(1.0, 3.0, 0.05, "v_contrast"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gamma:")));
+                       setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.5, 2.0, 0.05, "v_gamma"));
+                       setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Contrast boost:")));
+                       setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(1.0, 5.0, 0.1, "v_contrastboost"));
+                       setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Saturation:")));
+                       setDependent(e, "vid_gl20", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.5, 2.0, 0.05, "r_glsl_saturation"));
+                       setDependent(e, "vid_gl20", 1, 1);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("LIT^Ambient:"))));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0, 20.0, 0.25, "r_ambient"));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Intensity:")));
+               me.TD(me, 1, 2, e = makeXonoticSlider(0.5, 2.0, 0.05, "r_hdr_scenebrightness"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "gl_finish", _("Wait for GPU to finish each frame")));
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "vid_gl20", _("Use OpenGL 2.0 shaders (GLSL)")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "v_glslgamma", _("Use GLSL to handle color control")));
+                       setDependent(e, "vid_gl20", 1, 1);
+       if(cvar("developer"))
+       {
+               me.TR(me);
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "v_psycho", _("Psycho coloring (easter egg)")));
+                               setDependent(e, "vid_gl20", 1, 1);
+               me.TR(me);
+                       me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "r_trippy", _("Trippy vertices (easter egg)")));
+                               setDependent(e, "vid_gl20", 1, 1);
+       }
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "vid_width $_menu_vid_width; vid_height $_menu_vid_height; vid_pixelheight $_menu_vid_pixelheight; vid_desktopfullscreen $_menu_vid_desktopfullscreen; menu_cmd update_conwidths_before_vid_restart; vid_restart; menu_cmd sync", COMMANDBUTTON_APPLY));
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_singleplayer.c b/qcsrc/menu/xonotic/dialog_singleplayer.c
deleted file mode 100644 (file)
index 6e13f65..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticSingleplayerDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticSingleplayerDialog, fill, void(entity))
-       ATTRIB(XonoticSingleplayerDialog, title, string, _("Singleplayer"))
-       ATTRIB(XonoticSingleplayerDialog, color, vector, SKINCOLOR_DIALOG_SINGLEPLAYER)
-       ATTRIB(XonoticSingleplayerDialog, intendedWidth, float, 0.80)
-       ATTRIB(XonoticSingleplayerDialog, rows, float, 24)
-       ATTRIB(XonoticSingleplayerDialog, columns, float, 5)
-       ATTRIB(XonoticSingleplayerDialog, campaignBox, entity, NULL)
-ENDCLASS(XonoticSingleplayerDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-
-void InstantAction_LoadMap(entity btn, entity dummy)
-{
-       float pmin = 2, pmax = 16, pstep = 1;
-
-       cvar_set("timelimit_override", "10");
-       cvar_set("g_lms_lives_override", "9");
-
-       if(random() < 0.4) // 40% are DM
-       {
-               MapInfo_SwitchGameType(MAPINFO_TYPE_DEATHMATCH);
-               pmin = 2;
-               pmax = 8;
-               pstep = 1;
-       }
-       else if(random() < 0.5) // half of the remaining 60%, i.e. 30%, are CTF
-       {
-               MapInfo_SwitchGameType(MAPINFO_TYPE_CTF);
-               pmin = 4;
-               pmax = 12;
-               pstep = 2;
-       }
-       else if(random() < 0.5) // half of the remaining 30%, i.e. 15%, are TDM
-       {
-               MapInfo_SwitchGameType(MAPINFO_TYPE_TEAM_DEATHMATCH);
-               pmin = 4;
-               pmax = 8;
-               pstep = 2;
-       }
-       else if(random() < 0.666) // 2/3 of the remaining 15%, i.e. 10%, are KH
-       {
-               MapInfo_SwitchGameType(MAPINFO_TYPE_KEYHUNT);
-               pmin = 6;
-               pmax = 6;
-               pstep = 6; // works both for 2 and 3 teams
-               // TODO find team count of map, set pstep=2 or 3, and use 2v2(v2) games at least
-       }
-       else // somehow distribute the remaining 5%
-       {
-               float r;
-               r = floor(random() * 4);
-               switch(r)
-               {
-                       default:
-                       case 0:
-                               MapInfo_SwitchGameType(MAPINFO_TYPE_LMS);
-                               pmin = 2;
-                               pmax = 6;
-                               pstep = 1;
-                               cvar_set("timelimit_override", "-1");
-                               break;
-                       case 1:
-                               MapInfo_SwitchGameType(MAPINFO_TYPE_DOMINATION);
-                               pmin = 2;
-                               pmax = 8;
-                               pstep = 2;
-                               break;
-                       case 2:
-                               MapInfo_SwitchGameType(MAPINFO_TYPE_ONSLAUGHT);
-                               pmin = 6;
-                               pmax = 16;
-                               pstep = 2;
-                               break;
-                       case 3:
-                               MapInfo_SwitchGameType(MAPINFO_TYPE_ASSAULT);
-                               pmin = 4;
-                               pmax = 16;
-                               pstep = 2;
-                               break;
-                       // CA, Freezetag: bot AI does not work, add them once it does
-               }
-       }
-
-       // find random map
-       MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
-       string s;
-       do
-       {
-               float m;
-               m = floor(random() * MapInfo_count);
-               s = MapInfo_BSPName_ByID(m);
-       }
-       while(!fexists(sprintf("maps/%s.waypoints", s)));
-       MapInfo_LoadMap(s, 1);
-
-       // configure bots
-       float p;
-       pmin = pstep * ceil(pmin / pstep);
-       pmax = pstep * floor(pmax / pstep);
-       p = pmin + pstep * floor(random() * ((pmax - pmin) / pstep + 1));
-       cvar_set("bot_number", ftos(p - 1));
-
-       // make sure we go back to menu
-       cvar_set("lastlevel", "1");
-}
-
-void XonoticSingleplayerDialog_fill(entity me)
-{
-       entity e, btnPrev, btnNext, lblTitle;
-
-       me.TR(me);
-               me.TDempty(me, (me.columns - 3) / 2);
-               me.TD(me, 2, 3, e = makeXonoticBigButton(_("Instant action! (random map with bots)"), '0 0 0'));
-                       e.onClick = InstantAction_LoadMap;
-                       e.onClickEntity = NULL;
-       me.TR(me);
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 1, btnPrev = makeXonoticButton("<<", '0 0 0'));
-               me.TD(me, 1, me.columns - 2, lblTitle = makeXonoticTextLabel(0.5, _("???")));
-               me.TD(me, 1, 1, btnNext = makeXonoticButton(">>", '0 0 0'));
-       me.TR(me);
-               me.TD(me, me.rows - 6, me.columns, me.campaignBox = makeXonoticCampaignList());
-                       btnPrev.onClick = MultiCampaign_Prev;
-                       btnPrev.onClickEntity = me.campaignBox;
-                       btnNext.onClick = MultiCampaign_Next;
-                       btnNext.onClickEntity = me.campaignBox;
-                       me.campaignBox.buttonNext = btnNext;
-                       me.campaignBox.buttonPrev = btnPrev;
-                       me.campaignBox.labelTitle = lblTitle;
-                       me.campaignBox.campaignGo(me.campaignBox, 0);
-
-       me.gotoRC(me, me.rows - 2, 0);
-               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Campaign Difficulty:")));
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "-2", ZCTX(_("CSKL^Easy"))));
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "-1", ZCTX(_("CSKL^Medium"))));
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "0", ZCTX(_("CSKL^Hard"))));
-               me.TR(me);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("Start Singleplayer!"), '0 0 0'));
-                       e.onClick = CampaignList_LoadMap;
-                       e.onClickEntity = me.campaignBox;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_singleplayer.qc b/qcsrc/menu/xonotic/dialog_singleplayer.qc
new file mode 100644 (file)
index 0000000..6e13f65
--- /dev/null
@@ -0,0 +1,146 @@
+#ifdef INTERFACE
+CLASS(XonoticSingleplayerDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticSingleplayerDialog, fill, void(entity))
+       ATTRIB(XonoticSingleplayerDialog, title, string, _("Singleplayer"))
+       ATTRIB(XonoticSingleplayerDialog, color, vector, SKINCOLOR_DIALOG_SINGLEPLAYER)
+       ATTRIB(XonoticSingleplayerDialog, intendedWidth, float, 0.80)
+       ATTRIB(XonoticSingleplayerDialog, rows, float, 24)
+       ATTRIB(XonoticSingleplayerDialog, columns, float, 5)
+       ATTRIB(XonoticSingleplayerDialog, campaignBox, entity, NULL)
+ENDCLASS(XonoticSingleplayerDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+
+void InstantAction_LoadMap(entity btn, entity dummy)
+{
+       float pmin = 2, pmax = 16, pstep = 1;
+
+       cvar_set("timelimit_override", "10");
+       cvar_set("g_lms_lives_override", "9");
+
+       if(random() < 0.4) // 40% are DM
+       {
+               MapInfo_SwitchGameType(MAPINFO_TYPE_DEATHMATCH);
+               pmin = 2;
+               pmax = 8;
+               pstep = 1;
+       }
+       else if(random() < 0.5) // half of the remaining 60%, i.e. 30%, are CTF
+       {
+               MapInfo_SwitchGameType(MAPINFO_TYPE_CTF);
+               pmin = 4;
+               pmax = 12;
+               pstep = 2;
+       }
+       else if(random() < 0.5) // half of the remaining 30%, i.e. 15%, are TDM
+       {
+               MapInfo_SwitchGameType(MAPINFO_TYPE_TEAM_DEATHMATCH);
+               pmin = 4;
+               pmax = 8;
+               pstep = 2;
+       }
+       else if(random() < 0.666) // 2/3 of the remaining 15%, i.e. 10%, are KH
+       {
+               MapInfo_SwitchGameType(MAPINFO_TYPE_KEYHUNT);
+               pmin = 6;
+               pmax = 6;
+               pstep = 6; // works both for 2 and 3 teams
+               // TODO find team count of map, set pstep=2 or 3, and use 2v2(v2) games at least
+       }
+       else // somehow distribute the remaining 5%
+       {
+               float r;
+               r = floor(random() * 4);
+               switch(r)
+               {
+                       default:
+                       case 0:
+                               MapInfo_SwitchGameType(MAPINFO_TYPE_LMS);
+                               pmin = 2;
+                               pmax = 6;
+                               pstep = 1;
+                               cvar_set("timelimit_override", "-1");
+                               break;
+                       case 1:
+                               MapInfo_SwitchGameType(MAPINFO_TYPE_DOMINATION);
+                               pmin = 2;
+                               pmax = 8;
+                               pstep = 2;
+                               break;
+                       case 2:
+                               MapInfo_SwitchGameType(MAPINFO_TYPE_ONSLAUGHT);
+                               pmin = 6;
+                               pmax = 16;
+                               pstep = 2;
+                               break;
+                       case 3:
+                               MapInfo_SwitchGameType(MAPINFO_TYPE_ASSAULT);
+                               pmin = 4;
+                               pmax = 16;
+                               pstep = 2;
+                               break;
+                       // CA, Freezetag: bot AI does not work, add them once it does
+               }
+       }
+
+       // find random map
+       MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
+       string s;
+       do
+       {
+               float m;
+               m = floor(random() * MapInfo_count);
+               s = MapInfo_BSPName_ByID(m);
+       }
+       while(!fexists(sprintf("maps/%s.waypoints", s)));
+       MapInfo_LoadMap(s, 1);
+
+       // configure bots
+       float p;
+       pmin = pstep * ceil(pmin / pstep);
+       pmax = pstep * floor(pmax / pstep);
+       p = pmin + pstep * floor(random() * ((pmax - pmin) / pstep + 1));
+       cvar_set("bot_number", ftos(p - 1));
+
+       // make sure we go back to menu
+       cvar_set("lastlevel", "1");
+}
+
+void XonoticSingleplayerDialog_fill(entity me)
+{
+       entity e, btnPrev, btnNext, lblTitle;
+
+       me.TR(me);
+               me.TDempty(me, (me.columns - 3) / 2);
+               me.TD(me, 2, 3, e = makeXonoticBigButton(_("Instant action! (random map with bots)"), '0 0 0'));
+                       e.onClick = InstantAction_LoadMap;
+                       e.onClickEntity = NULL;
+       me.TR(me);
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 1, btnPrev = makeXonoticButton("<<", '0 0 0'));
+               me.TD(me, 1, me.columns - 2, lblTitle = makeXonoticTextLabel(0.5, _("???")));
+               me.TD(me, 1, 1, btnNext = makeXonoticButton(">>", '0 0 0'));
+       me.TR(me);
+               me.TD(me, me.rows - 6, me.columns, me.campaignBox = makeXonoticCampaignList());
+                       btnPrev.onClick = MultiCampaign_Prev;
+                       btnPrev.onClickEntity = me.campaignBox;
+                       btnNext.onClick = MultiCampaign_Next;
+                       btnNext.onClickEntity = me.campaignBox;
+                       me.campaignBox.buttonNext = btnNext;
+                       me.campaignBox.buttonPrev = btnPrev;
+                       me.campaignBox.labelTitle = lblTitle;
+                       me.campaignBox.campaignGo(me.campaignBox, 0);
+
+       me.gotoRC(me, me.rows - 2, 0);
+               me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Campaign Difficulty:")));
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "-2", ZCTX(_("CSKL^Easy"))));
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "-1", ZCTX(_("CSKL^Medium"))));
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "0", ZCTX(_("CSKL^Hard"))));
+               me.TR(me);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("Start Singleplayer!"), '0 0 0'));
+                       e.onClick = CampaignList_LoadMap;
+                       e.onClickEntity = me.campaignBox;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_singleplayer_winner.c b/qcsrc/menu/xonotic/dialog_singleplayer_winner.c
deleted file mode 100644 (file)
index 8e584b8..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticWinnerDialog) EXTENDS(XonoticDialog)
-       METHOD(XonoticWinnerDialog, fill, void(entity))
-       ATTRIB(XonoticWinnerDialog, title, string, _("Winner"))
-       ATTRIB(XonoticWinnerDialog, color, vector, SKINCOLOR_DIALOG_SINGLEPLAYER)
-       ATTRIB(XonoticWinnerDialog, intendedWidth, float, 0.32)
-       ATTRIB(XonoticWinnerDialog, rows, float, 12)
-       ATTRIB(XonoticWinnerDialog, columns, float, 3)
-ENDCLASS(XonoticWinnerDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticWinnerDialog_fill(entity me)
-{
-       entity e;
-
-       me.TR(me);
-               me.TD(me, me.rows - 2, me.columns, e = makeXonoticImage("/gfx/winner", -1));
-
-       me.gotoRC(me, me.rows - 1, 0);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
-                       e.onClick = Dialog_Close;
-                       e.onClickEntity = me;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/dialog_singleplayer_winner.qc b/qcsrc/menu/xonotic/dialog_singleplayer_winner.qc
new file mode 100644 (file)
index 0000000..8e584b8
--- /dev/null
@@ -0,0 +1,25 @@
+#ifdef INTERFACE
+CLASS(XonoticWinnerDialog) EXTENDS(XonoticDialog)
+       METHOD(XonoticWinnerDialog, fill, void(entity))
+       ATTRIB(XonoticWinnerDialog, title, string, _("Winner"))
+       ATTRIB(XonoticWinnerDialog, color, vector, SKINCOLOR_DIALOG_SINGLEPLAYER)
+       ATTRIB(XonoticWinnerDialog, intendedWidth, float, 0.32)
+       ATTRIB(XonoticWinnerDialog, rows, float, 12)
+       ATTRIB(XonoticWinnerDialog, columns, float, 3)
+ENDCLASS(XonoticWinnerDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticWinnerDialog_fill(entity me)
+{
+       entity e;
+
+       me.TR(me);
+               me.TD(me, me.rows - 2, me.columns, e = makeXonoticImage("/gfx/winner", -1));
+
+       me.gotoRC(me, me.rows - 1, 0);
+               me.TD(me, 1, me.columns, e = makeXonoticButton(_("OK"), '0 0 0'));
+                       e.onClick = Dialog_Close;
+                       e.onClickEntity = me;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/dialog_teamselect.c b/qcsrc/menu/xonotic/dialog_teamselect.c
deleted file mode 100644 (file)
index 10efc3c..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticTeamSelectDialog) EXTENDS(XonoticRootDialog)
-       METHOD(XonoticTeamSelectDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
-       METHOD(XonoticTeamSelectDialog, showNotify, void(entity))
-       ATTRIB(XonoticTeamSelectDialog, title, string, _("Team Selection")) // ;)
-       ATTRIB(XonoticTeamSelectDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
-       ATTRIB(XonoticTeamSelectDialog, intendedWidth, float, 0.4)
-       ATTRIB(XonoticTeamSelectDialog, rows, float, 5)
-       ATTRIB(XonoticTeamSelectDialog, columns, float, 4)
-       ATTRIB(XonoticTeamSelectDialog, name, string, "TeamSelect")
-       ATTRIB(XonoticTeamSelectDialog, team1, entity, NULL)
-       ATTRIB(XonoticTeamSelectDialog, team2, entity, NULL)
-       ATTRIB(XonoticTeamSelectDialog, team3, entity, NULL)
-       ATTRIB(XonoticTeamSelectDialog, team4, entity, NULL)
-       ATTRIB(XonoticTeamSelectDialog, requiresConnection, float, TRUE)
-ENDCLASS(XonoticTeamSelectDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeTeamButton(string theName, vector theColor, string commandtheName)
-{
-       entity b;
-       b = makeXonoticBigCommandButton(theName, theColor, commandtheName, 1);
-       return b;
-}
-
-void XonoticTeamSelectDialog_showNotify(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 XonoticTeamSelectDialog_fill(entity me)
-{
-       entity e;
-       me.TR(me);
-               me.TD(me, 2, 4, e = makeTeamButton(_("join 'best' team (auto-select)"), '0 0 0', "cmd selectteam auto; cmd join"));
-                       e.preferredFocusPriority = 1;
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 2, 1, me.team1 = makeTeamButton(_("red"), '1 0.5 0.5', "cmd selectteam red; cmd join"));
-               me.TD(me, 2, 1, me.team2 = makeTeamButton(_("blue"), '0.5 0.5 1', "cmd selectteam blue; cmd join"));
-               me.TD(me, 2, 1, me.team3 = makeTeamButton(_("yellow"), '1 1 0.5', "cmd selectteam yellow; cmd join"));
-               me.TD(me, 2, 1, me.team4 = makeTeamButton(_("pink"), '1 0.5 1', "cmd selectteam pink; cmd join"));
-       me.TR(me);
-       me.TR(me);
-               me.TD(me, 1, 4, makeXonoticCommandButton(_("spectate"), '0 0 0', "cmd spectate", 1));
-}
-#endif
-
-/* Click. The c-word is here so you can grep for it :-) */
diff --git a/qcsrc/menu/xonotic/dialog_teamselect.qc b/qcsrc/menu/xonotic/dialog_teamselect.qc
new file mode 100644 (file)
index 0000000..10efc3c
--- /dev/null
@@ -0,0 +1,56 @@
+#ifdef INTERFACE
+CLASS(XonoticTeamSelectDialog) EXTENDS(XonoticRootDialog)
+       METHOD(XonoticTeamSelectDialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
+       METHOD(XonoticTeamSelectDialog, showNotify, void(entity))
+       ATTRIB(XonoticTeamSelectDialog, title, string, _("Team Selection")) // ;)
+       ATTRIB(XonoticTeamSelectDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT)
+       ATTRIB(XonoticTeamSelectDialog, intendedWidth, float, 0.4)
+       ATTRIB(XonoticTeamSelectDialog, rows, float, 5)
+       ATTRIB(XonoticTeamSelectDialog, columns, float, 4)
+       ATTRIB(XonoticTeamSelectDialog, name, string, "TeamSelect")
+       ATTRIB(XonoticTeamSelectDialog, team1, entity, NULL)
+       ATTRIB(XonoticTeamSelectDialog, team2, entity, NULL)
+       ATTRIB(XonoticTeamSelectDialog, team3, entity, NULL)
+       ATTRIB(XonoticTeamSelectDialog, team4, entity, NULL)
+       ATTRIB(XonoticTeamSelectDialog, requiresConnection, float, TRUE)
+ENDCLASS(XonoticTeamSelectDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeTeamButton(string theName, vector theColor, string commandtheName)
+{
+       entity b;
+       b = makeXonoticBigCommandButton(theName, theColor, commandtheName, 1);
+       return b;
+}
+
+void XonoticTeamSelectDialog_showNotify(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 XonoticTeamSelectDialog_fill(entity me)
+{
+       entity e;
+       me.TR(me);
+               me.TD(me, 2, 4, e = makeTeamButton(_("join 'best' team (auto-select)"), '0 0 0', "cmd selectteam auto; cmd join"));
+                       e.preferredFocusPriority = 1;
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 2, 1, me.team1 = makeTeamButton(_("red"), '1 0.5 0.5', "cmd selectteam red; cmd join"));
+               me.TD(me, 2, 1, me.team2 = makeTeamButton(_("blue"), '0.5 0.5 1', "cmd selectteam blue; cmd join"));
+               me.TD(me, 2, 1, me.team3 = makeTeamButton(_("yellow"), '1 1 0.5', "cmd selectteam yellow; cmd join"));
+               me.TD(me, 2, 1, me.team4 = makeTeamButton(_("pink"), '1 0.5 1', "cmd selectteam pink; cmd join"));
+       me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 4, makeXonoticCommandButton(_("spectate"), '0 0 0', "cmd spectate", 1));
+}
+#endif
+
+/* Click. The c-word is here so you can grep for it :-) */
diff --git a/qcsrc/menu/xonotic/gametypebutton.c b/qcsrc/menu/xonotic/gametypebutton.c
deleted file mode 100644 (file)
index cc10f3d..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticGametypeButton) EXTENDS(RadioButton)
-       METHOD(XonoticGametypeButton, configureXonoticGametypeButton, void(entity, float, string, string))
-       METHOD(XonoticGametypeButton, setChecked, void(entity, float))
-       ATTRIB(XonoticGametypeButton, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticGametypeButton, image, string, SKINGFX_BUTTON_BIG)
-       ATTRIB(XonoticGametypeButton, color, vector, SKINCOLOR_BUTTON_N)
-       ATTRIB(XonoticGametypeButton, colorC, vector, SKINCOLOR_BUTTON_C)
-       ATTRIB(XonoticGametypeButton, colorF, vector, SKINCOLOR_BUTTON_F)
-       ATTRIB(XonoticGametypeButton, colorD, vector, SKINCOLOR_BUTTON_D)
-       ATTRIB(XonoticGametypeButton, srcMulti, float, 1)
-       ATTRIB(XonoticGametypeButton, useDownAsChecked, float, 1)
-
-       ATTRIB(XonoticGametypeButton, cvarName, string, string_null)
-       METHOD(XonoticGametypeButton, loadCvars, void(entity))
-       METHOD(XonoticGametypeButton, saveCvars, void(entity))
-
-       ATTRIB(XonoticGametypeButton, alpha, float, SKINALPHA_TEXT)
-       ATTRIB(XonoticGametypeButton, disabledAlpha, float, SKINALPHA_DISABLED)
-ENDCLASS(XonoticGametypeButton)
-entity makeXonoticGametypeButton(float, string, string);
-#endif
-
-#ifdef IMPLEMENTATION
-void GameTypeButton_Click(entity me, entity other);
-entity makeXonoticGametypeButton(float theGroup, string theCvar, string theText)
-{
-       entity me;
-       me = spawnXonoticGametypeButton();
-       me.configureXonoticGametypeButton(me, theGroup, theCvar, theText);
-       return me;
-}
-void XonoticGametypeButton_configureXonoticGametypeButton(entity me, float theGroup, string theCvar, string theText)
-{
-       if(theCvar)
-       {
-               me.cvarName = theCvar;
-               me.tooltip = getZonedTooltipForIdentifier(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 XonoticGametypeButton_setChecked(entity me, float val)
-{
-       if(val != me.checked)
-       {
-               me.checked = val;
-               me.saveCvars(me);
-       }
-}
-void XonoticGametypeButton_loadCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       me.checked = cvar(me.cvarName);
-}
-void XonoticGametypeButton_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       cvar_set(me.cvarName, ftos(me.checked));
-}
-void GameTypeButton_Click(entity me, entity other)
-{
-       RadioButton_Click(me, other);
-       me.parent.gameTypeChangeNotify(me.parent);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/gametypebutton.qc b/qcsrc/menu/xonotic/gametypebutton.qc
new file mode 100644 (file)
index 0000000..cc10f3d
--- /dev/null
@@ -0,0 +1,73 @@
+#ifdef INTERFACE
+CLASS(XonoticGametypeButton) EXTENDS(RadioButton)
+       METHOD(XonoticGametypeButton, configureXonoticGametypeButton, void(entity, float, string, string))
+       METHOD(XonoticGametypeButton, setChecked, void(entity, float))
+       ATTRIB(XonoticGametypeButton, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticGametypeButton, image, string, SKINGFX_BUTTON_BIG)
+       ATTRIB(XonoticGametypeButton, color, vector, SKINCOLOR_BUTTON_N)
+       ATTRIB(XonoticGametypeButton, colorC, vector, SKINCOLOR_BUTTON_C)
+       ATTRIB(XonoticGametypeButton, colorF, vector, SKINCOLOR_BUTTON_F)
+       ATTRIB(XonoticGametypeButton, colorD, vector, SKINCOLOR_BUTTON_D)
+       ATTRIB(XonoticGametypeButton, srcMulti, float, 1)
+       ATTRIB(XonoticGametypeButton, useDownAsChecked, float, 1)
+
+       ATTRIB(XonoticGametypeButton, cvarName, string, string_null)
+       METHOD(XonoticGametypeButton, loadCvars, void(entity))
+       METHOD(XonoticGametypeButton, saveCvars, void(entity))
+
+       ATTRIB(XonoticGametypeButton, alpha, float, SKINALPHA_TEXT)
+       ATTRIB(XonoticGametypeButton, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(XonoticGametypeButton)
+entity makeXonoticGametypeButton(float, string, string);
+#endif
+
+#ifdef IMPLEMENTATION
+void GameTypeButton_Click(entity me, entity other);
+entity makeXonoticGametypeButton(float theGroup, string theCvar, string theText)
+{
+       entity me;
+       me = spawnXonoticGametypeButton();
+       me.configureXonoticGametypeButton(me, theGroup, theCvar, theText);
+       return me;
+}
+void XonoticGametypeButton_configureXonoticGametypeButton(entity me, float theGroup, string theCvar, string theText)
+{
+       if(theCvar)
+       {
+               me.cvarName = theCvar;
+               me.tooltip = getZonedTooltipForIdentifier(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 XonoticGametypeButton_setChecked(entity me, float val)
+{
+       if(val != me.checked)
+       {
+               me.checked = val;
+               me.saveCvars(me);
+       }
+}
+void XonoticGametypeButton_loadCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       me.checked = cvar(me.cvarName);
+}
+void XonoticGametypeButton_saveCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       cvar_set(me.cvarName, ftos(me.checked));
+}
+void GameTypeButton_Click(entity me, entity other)
+{
+       RadioButton_Click(me, other);
+       me.parent.gameTypeChangeNotify(me.parent);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/gametypelist.c b/qcsrc/menu/xonotic/gametypelist.c
deleted file mode 100644 (file)
index e3df844..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticGametypeList) EXTENDS(XonoticListBox)
-       METHOD(XonoticGametypeList, configureXonoticGametypeList, void(entity))
-       ATTRIB(XonoticGametypeList, rowsPerItem, float, 2)
-       METHOD(XonoticGametypeList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticGametypeList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticGametypeList, setSelected, void(entity, float))
-       METHOD(XonoticGametypeList, loadCvars, void(entity))
-       METHOD(XonoticGametypeList, saveCvars, void(entity))
-       METHOD(XonoticGametypeList, keyDown, float(entity, float, float, float))
-
-       ATTRIB(XonoticGametypeList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticGametypeList, realUpperMargin, float, 0)
-       ATTRIB(XonoticGametypeList, columnIconOrigin, float, 0)
-       ATTRIB(XonoticGametypeList, columnIconSize, float, 0)
-       ATTRIB(XonoticGametypeList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticGametypeList, columnNameSize, float, 0)
-ENDCLASS(XonoticGametypeList)
-entity makeXonoticGametypeList();
-#endif
-
-#ifdef IMPLEMENTATION
-
-entity makeXonoticGametypeList(void)
-{
-       entity me;
-       me = spawnXonoticGametypeList();
-       me.configureXonoticGametypeList(me);
-       return me;
-}
-void XonoticGametypeList_configureXonoticGametypeList(entity me)
-{
-       float i;
-       me.configureXonoticListBox(me);
-       me.nItems = GameType_GetCount();
-
-       // we want the pics mipmapped
-       for(i = 0; i < GameType_GetCount(); ++i)
-               draw_PreloadPictureWithFlags(GameType_GetIcon(i), PRECACHE_PIC_MIPMAP);
-
-       me.loadCvars(me);
-}
-void XonoticGametypeList_setSelected(entity me, float i)
-{
-       SUPER(XonoticGametypeList).setSelected(me, i);
-       me.saveCvars(me);
-}
-
-void XonoticGametypeList_loadCvars(entity me)
-{
-       float t;
-       t = MapInfo_CurrentGametype();
-       float i;
-       for(i = 0; i < GameType_GetCount(); ++i)
-               if(t == GameType_GetID(i))
-                       break;
-       if(i >= GameType_GetCount())
-       {
-               for(i = 0; i < GameType_GetCount(); ++i)
-                       if(t == MAPINFO_TYPE_DEATHMATCH)
-                               break;
-               if(i >= GameType_GetCount())
-                       i = 0;
-       }
-       me.setSelected(me, i);
-       // do we need this: me.parent.gameTypeChangeNotify(me.parent); // to make sure
-}
-void XonoticGametypeList_saveCvars(entity me)
-{
-       float t;
-       t = GameType_GetID(me.selectedItem);
-       if(t == MapInfo_CurrentGametype())
-               return;
-       MapInfo_SwitchGameType(t);
-       me.parent.gameTypeChangeNotify(me.parent);
-}
-void XonoticGametypeList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string s1, s2;
-
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-
-       draw_Picture(me.columnIconOrigin * eX, GameType_GetIcon(i), me.columnIconSize * eX + eY, '1 1 1', SKINALPHA_LISTBOX_SELECTED);
-       s1 = GameType_GetName(i);
-       
-       if(_MapInfo_GetTeamPlayBool(GameType_GetID(i)))
-               s2 = _("teamplay");
-       else
-               s2 = _("free for all");
-
-       vector save_fontscale = draw_fontscale;
-       float f = draw_CondensedFontFactor(strcat(s1, " ", s2), FALSE, me.realFontSize, 1);
-       draw_fontscale_x *= f;
-       vector fs = me.realFontSize;
-       fs_x *= f;
-       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s1, fs, '1 1 1', SKINALPHA_TEXT, 0);
-       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 1.0 * (me.columnNameSize - draw_TextWidth(s2, 0, fs))) * eX, s2, fs, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
-       draw_fontscale = save_fontscale;
-}
-void XonoticGametypeList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemAbsSize = '0 0 0';
-       SUPER(XonoticServerList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
-       me.columnIconOrigin = 0;
-       me.columnIconSize = me.itemAbsSize_y / me.itemAbsSize_x;
-       me.columnNameOrigin = me.columnIconOrigin + me.columnIconSize + (0.5 * me.realFontSize_x);
-       me.columnNameSize = 1 - me.columnIconSize - (1.5 * me.realFontSize_x);
-}
-
-float XonoticGametypeList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if(scan == K_ENTER || scan == K_KP_ENTER)
-       {
-               me.parent.gameTypeSelectNotify(me.parent);
-               return 1;
-       }
-
-       return SUPER(XonoticGametypeList).keyDown(me, scan, ascii, shift);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/gametypelist.qc b/qcsrc/menu/xonotic/gametypelist.qc
new file mode 100644 (file)
index 0000000..e3df844
--- /dev/null
@@ -0,0 +1,125 @@
+#ifdef INTERFACE
+CLASS(XonoticGametypeList) EXTENDS(XonoticListBox)
+       METHOD(XonoticGametypeList, configureXonoticGametypeList, void(entity))
+       ATTRIB(XonoticGametypeList, rowsPerItem, float, 2)
+       METHOD(XonoticGametypeList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticGametypeList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticGametypeList, setSelected, void(entity, float))
+       METHOD(XonoticGametypeList, loadCvars, void(entity))
+       METHOD(XonoticGametypeList, saveCvars, void(entity))
+       METHOD(XonoticGametypeList, keyDown, float(entity, float, float, float))
+
+       ATTRIB(XonoticGametypeList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticGametypeList, realUpperMargin, float, 0)
+       ATTRIB(XonoticGametypeList, columnIconOrigin, float, 0)
+       ATTRIB(XonoticGametypeList, columnIconSize, float, 0)
+       ATTRIB(XonoticGametypeList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticGametypeList, columnNameSize, float, 0)
+ENDCLASS(XonoticGametypeList)
+entity makeXonoticGametypeList();
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeXonoticGametypeList(void)
+{
+       entity me;
+       me = spawnXonoticGametypeList();
+       me.configureXonoticGametypeList(me);
+       return me;
+}
+void XonoticGametypeList_configureXonoticGametypeList(entity me)
+{
+       float i;
+       me.configureXonoticListBox(me);
+       me.nItems = GameType_GetCount();
+
+       // we want the pics mipmapped
+       for(i = 0; i < GameType_GetCount(); ++i)
+               draw_PreloadPictureWithFlags(GameType_GetIcon(i), PRECACHE_PIC_MIPMAP);
+
+       me.loadCvars(me);
+}
+void XonoticGametypeList_setSelected(entity me, float i)
+{
+       SUPER(XonoticGametypeList).setSelected(me, i);
+       me.saveCvars(me);
+}
+
+void XonoticGametypeList_loadCvars(entity me)
+{
+       float t;
+       t = MapInfo_CurrentGametype();
+       float i;
+       for(i = 0; i < GameType_GetCount(); ++i)
+               if(t == GameType_GetID(i))
+                       break;
+       if(i >= GameType_GetCount())
+       {
+               for(i = 0; i < GameType_GetCount(); ++i)
+                       if(t == MAPINFO_TYPE_DEATHMATCH)
+                               break;
+               if(i >= GameType_GetCount())
+                       i = 0;
+       }
+       me.setSelected(me, i);
+       // do we need this: me.parent.gameTypeChangeNotify(me.parent); // to make sure
+}
+void XonoticGametypeList_saveCvars(entity me)
+{
+       float t;
+       t = GameType_GetID(me.selectedItem);
+       if(t == MapInfo_CurrentGametype())
+               return;
+       MapInfo_SwitchGameType(t);
+       me.parent.gameTypeChangeNotify(me.parent);
+}
+void XonoticGametypeList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s1, s2;
+
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       draw_Picture(me.columnIconOrigin * eX, GameType_GetIcon(i), me.columnIconSize * eX + eY, '1 1 1', SKINALPHA_LISTBOX_SELECTED);
+       s1 = GameType_GetName(i);
+       
+       if(_MapInfo_GetTeamPlayBool(GameType_GetID(i)))
+               s2 = _("teamplay");
+       else
+               s2 = _("free for all");
+
+       vector save_fontscale = draw_fontscale;
+       float f = draw_CondensedFontFactor(strcat(s1, " ", s2), FALSE, me.realFontSize, 1);
+       draw_fontscale_x *= f;
+       vector fs = me.realFontSize;
+       fs_x *= f;
+       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s1, fs, '1 1 1', SKINALPHA_TEXT, 0);
+       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 1.0 * (me.columnNameSize - draw_TextWidth(s2, 0, fs))) * eX, s2, fs, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
+       draw_fontscale = save_fontscale;
+}
+void XonoticGametypeList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticServerList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+       me.columnIconOrigin = 0;
+       me.columnIconSize = me.itemAbsSize_y / me.itemAbsSize_x;
+       me.columnNameOrigin = me.columnIconOrigin + me.columnIconSize + (0.5 * me.realFontSize_x);
+       me.columnNameSize = 1 - me.columnIconSize - (1.5 * me.realFontSize_x);
+}
+
+float XonoticGametypeList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_KP_ENTER)
+       {
+               me.parent.gameTypeSelectNotify(me.parent);
+               return 1;
+       }
+
+       return SUPER(XonoticGametypeList).keyDown(me, scan, ascii, shift);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/image.c b/qcsrc/menu/xonotic/image.c
deleted file mode 100644 (file)
index 9f0de67..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticImage) EXTENDS(Image)
-       METHOD(XonoticImage, configureXonoticImage, void(entity, string, float))
-ENDCLASS(XonoticImage)
-entity makeXonoticImage(string theImage, float theAspect);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticImage(string theImage, float theAspect)
-{
-       entity me;
-       me = spawnXonoticImage();
-       me.configureXonoticImage(me, theImage, theAspect);
-       return me;
-}
-void XonoticImage_configureXonoticImage(entity me, string theImage, float theAspect)
-{
-       me.configureImage(me, theImage);
-       me.forcedAspect = theAspect;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/image.qc b/qcsrc/menu/xonotic/image.qc
new file mode 100644 (file)
index 0000000..9f0de67
--- /dev/null
@@ -0,0 +1,21 @@
+#ifdef INTERFACE
+CLASS(XonoticImage) EXTENDS(Image)
+       METHOD(XonoticImage, configureXonoticImage, void(entity, string, float))
+ENDCLASS(XonoticImage)
+entity makeXonoticImage(string theImage, float theAspect);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticImage(string theImage, float theAspect)
+{
+       entity me;
+       me = spawnXonoticImage();
+       me.configureXonoticImage(me, theImage, theAspect);
+       return me;
+}
+void XonoticImage_configureXonoticImage(entity me, string theImage, float theAspect)
+{
+       me.configureImage(me, theImage);
+       me.forcedAspect = theAspect;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/inputbox.c b/qcsrc/menu/xonotic/inputbox.c
deleted file mode 100644 (file)
index 5d7d179..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticInputBox) EXTENDS(InputBox)
-       METHOD(XonoticInputBox, configureXonoticInputBox, void(entity, float, string))
-       METHOD(XonoticInputBox, focusLeave, void(entity))
-       METHOD(XonoticInputBox, setText, void(entity, string))
-       ATTRIB(XonoticInputBox, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticInputBox, image, string, SKINGFX_INPUTBOX)
-       ATTRIB(XonoticInputBox, onChange, void(entity, entity), func_null)
-       ATTRIB(XonoticInputBox, onChangeEntity, entity, NULL)
-       ATTRIB(XonoticInputBox, onEnter, void(entity, entity), func_null)
-       ATTRIB(XonoticInputBox, onEnterEntity, entity, NULL)
-       ATTRIB(XonoticInputBox, marginLeft, float, SKINMARGIN_INPUTBOX_CHARS)
-       ATTRIB(XonoticInputBox, marginRight, float, SKINMARGIN_INPUTBOX_CHARS)
-       ATTRIB(XonoticInputBox, color, vector, SKINCOLOR_INPUTBOX_N)
-       ATTRIB(XonoticInputBox, colorF, vector, SKINCOLOR_INPUTBOX_F)
-
-       ATTRIB(XonoticInputBox, alpha, float, SKINALPHA_TEXT)
-
-       // Clear button attributes
-       ATTRIB(XonoticInputBox, cb_offset, float, SKINOFFSET_CLEARBUTTON) // bound to range -1, 0
-       ATTRIB(XonoticInputBox, cb_src, string, SKINGFX_CLEARBUTTON)
-       ATTRIB(XonoticInputBox, cb_color, vector, SKINCOLOR_CLEARBUTTON_N)
-       ATTRIB(XonoticInputBox, cb_colorF, vector, SKINCOLOR_CLEARBUTTON_F)
-       ATTRIB(XonoticInputBox, cb_colorC, vector, SKINCOLOR_CLEARBUTTON_C)
-
-       ATTRIB(XonoticInputBox, cvarName, string, string_null)
-       METHOD(XonoticInputBox, loadCvars, void(entity))
-       METHOD(XonoticInputBox, saveCvars, void(entity))
-       ATTRIB(XonoticInputBox, sendCvars, float, 0)
-       METHOD(XonoticInputBox, keyDown, float(entity, float, float, float))
-
-       ATTRIB(XonoticInputBox, saveImmediately, float, 0)
-ENDCLASS(XonoticInputBox)
-entity makeXonoticInputBox(float, string);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticInputBox(float doEditColorCodes, string theCvar)
-{
-       entity me;
-       me = spawnXonoticInputBox();
-       me.configureXonoticInputBox(me, doEditColorCodes, theCvar);
-       return me;
-}
-void XonoticInputBox_configureXonoticInputBox(entity me, float doEditColorCodes, string theCvar)
-{
-       me.configureInputBox(me, "", 0, me.fontSize, me.image);
-       me.editColorCodes = doEditColorCodes;
-       if(theCvar)
-       {
-               me.cvarName = theCvar;
-               me.tooltip = getZonedTooltipForIdentifier(theCvar);
-               me.loadCvars(me);
-       }
-       me.cursorPos = strlen(me.text);
-}
-void XonoticInputBox_focusLeave(entity me)
-{
-       me.saveCvars(me);
-}
-void XonoticInputBox_setText(entity me, string new)
-{
-       if(me.text != new)
-       {
-               SUPER(XonoticInputBox).setText(me, new);
-               if(me.onChange)
-                       me.onChange(me, me.onChangeEntity);
-               if(me.saveImmediately)
-                       me.saveCvars(me);
-       }
-       else
-               SUPER(XonoticInputBox).setText(me, new);
-}
-void XonoticInputBox_loadCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-       SUPER(XonoticInputBox).setText(me, cvar_string(me.cvarName));
-}
-void XonoticInputBox_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-       cvar_set(me.cvarName, me.text);
-       CheckSendCvars(me, me.cvarName);
-}
-float XonoticInputBox_keyDown(entity me, float key, float ascii, float shift)
-{
-       float r;
-       r = 0;
-       if(key == K_ENTER || key == K_KP_ENTER)
-       {
-               if(me.cvarName)
-               {
-                       me.saveCvars(me);
-                       r = 1;
-               }
-               if(me.onEnter)
-                       me.onEnter(me, me.onEnterEntity);
-       }
-       if(SUPER(XonoticInputBox).keyDown(me, key, ascii, shift))
-               r = 1;
-       return r;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/inputbox.qc b/qcsrc/menu/xonotic/inputbox.qc
new file mode 100644 (file)
index 0000000..5d7d179
--- /dev/null
@@ -0,0 +1,105 @@
+#ifdef INTERFACE
+CLASS(XonoticInputBox) EXTENDS(InputBox)
+       METHOD(XonoticInputBox, configureXonoticInputBox, void(entity, float, string))
+       METHOD(XonoticInputBox, focusLeave, void(entity))
+       METHOD(XonoticInputBox, setText, void(entity, string))
+       ATTRIB(XonoticInputBox, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticInputBox, image, string, SKINGFX_INPUTBOX)
+       ATTRIB(XonoticInputBox, onChange, void(entity, entity), func_null)
+       ATTRIB(XonoticInputBox, onChangeEntity, entity, NULL)
+       ATTRIB(XonoticInputBox, onEnter, void(entity, entity), func_null)
+       ATTRIB(XonoticInputBox, onEnterEntity, entity, NULL)
+       ATTRIB(XonoticInputBox, marginLeft, float, SKINMARGIN_INPUTBOX_CHARS)
+       ATTRIB(XonoticInputBox, marginRight, float, SKINMARGIN_INPUTBOX_CHARS)
+       ATTRIB(XonoticInputBox, color, vector, SKINCOLOR_INPUTBOX_N)
+       ATTRIB(XonoticInputBox, colorF, vector, SKINCOLOR_INPUTBOX_F)
+
+       ATTRIB(XonoticInputBox, alpha, float, SKINALPHA_TEXT)
+
+       // Clear button attributes
+       ATTRIB(XonoticInputBox, cb_offset, float, SKINOFFSET_CLEARBUTTON) // bound to range -1, 0
+       ATTRIB(XonoticInputBox, cb_src, string, SKINGFX_CLEARBUTTON)
+       ATTRIB(XonoticInputBox, cb_color, vector, SKINCOLOR_CLEARBUTTON_N)
+       ATTRIB(XonoticInputBox, cb_colorF, vector, SKINCOLOR_CLEARBUTTON_F)
+       ATTRIB(XonoticInputBox, cb_colorC, vector, SKINCOLOR_CLEARBUTTON_C)
+
+       ATTRIB(XonoticInputBox, cvarName, string, string_null)
+       METHOD(XonoticInputBox, loadCvars, void(entity))
+       METHOD(XonoticInputBox, saveCvars, void(entity))
+       ATTRIB(XonoticInputBox, sendCvars, float, 0)
+       METHOD(XonoticInputBox, keyDown, float(entity, float, float, float))
+
+       ATTRIB(XonoticInputBox, saveImmediately, float, 0)
+ENDCLASS(XonoticInputBox)
+entity makeXonoticInputBox(float, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticInputBox(float doEditColorCodes, string theCvar)
+{
+       entity me;
+       me = spawnXonoticInputBox();
+       me.configureXonoticInputBox(me, doEditColorCodes, theCvar);
+       return me;
+}
+void XonoticInputBox_configureXonoticInputBox(entity me, float doEditColorCodes, string theCvar)
+{
+       me.configureInputBox(me, "", 0, me.fontSize, me.image);
+       me.editColorCodes = doEditColorCodes;
+       if(theCvar)
+       {
+               me.cvarName = theCvar;
+               me.tooltip = getZonedTooltipForIdentifier(theCvar);
+               me.loadCvars(me);
+       }
+       me.cursorPos = strlen(me.text);
+}
+void XonoticInputBox_focusLeave(entity me)
+{
+       me.saveCvars(me);
+}
+void XonoticInputBox_setText(entity me, string new)
+{
+       if(me.text != new)
+       {
+               SUPER(XonoticInputBox).setText(me, new);
+               if(me.onChange)
+                       me.onChange(me, me.onChangeEntity);
+               if(me.saveImmediately)
+                       me.saveCvars(me);
+       }
+       else
+               SUPER(XonoticInputBox).setText(me, new);
+}
+void XonoticInputBox_loadCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+       SUPER(XonoticInputBox).setText(me, cvar_string(me.cvarName));
+}
+void XonoticInputBox_saveCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+       cvar_set(me.cvarName, me.text);
+       CheckSendCvars(me, me.cvarName);
+}
+float XonoticInputBox_keyDown(entity me, float key, float ascii, float shift)
+{
+       float r;
+       r = 0;
+       if(key == K_ENTER || key == K_KP_ENTER)
+       {
+               if(me.cvarName)
+               {
+                       me.saveCvars(me);
+                       r = 1;
+               }
+               if(me.onEnter)
+                       me.onEnter(me, me.onEnterEntity);
+       }
+       if(SUPER(XonoticInputBox).keyDown(me, key, ascii, shift))
+               r = 1;
+       return r;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/keybinder.c b/qcsrc/menu/xonotic/keybinder.c
deleted file mode 100644 (file)
index 6f3e56f..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticKeyBinder) EXTENDS(XonoticListBox)
-       METHOD(XonoticKeyBinder, configureXonoticKeyBinder, void(entity))
-       ATTRIB(XonoticKeyBinder, rowsPerItem, float, 1)
-       METHOD(XonoticKeyBinder, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticKeyBinder, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticKeyBinder, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticKeyBinder, setSelected, void(entity, float))
-       METHOD(XonoticKeyBinder, keyDown, float(entity, float, float, float))
-       METHOD(XonoticKeyBinder, keyGrabbed, void(entity, float, float))
-
-       ATTRIB(XonoticKeyBinder, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticKeyBinder, realUpperMargin, float, 0)
-       ATTRIB(XonoticKeyBinder, columnFunctionOrigin, float, 0)
-       ATTRIB(XonoticKeyBinder, columnFunctionSize, float, 0)
-       ATTRIB(XonoticKeyBinder, columnKeysOrigin, float, 0)
-       ATTRIB(XonoticKeyBinder, columnKeysSize, float, 0)
-
-       ATTRIB(XonoticKeyBinder, previouslySelected, float, -1)
-       ATTRIB(XonoticKeyBinder, inMouseHandler, float, 0)
-       ATTRIB(XonoticKeyBinder, userbindEditButton, entity, NULL)
-       ATTRIB(XonoticKeyBinder, keyGrabButton, entity, NULL)
-       ATTRIB(XonoticKeyBinder, clearButton, entity, NULL)
-       ATTRIB(XonoticKeyBinder, userbindEditDialog, entity, NULL)
-       METHOD(XonoticKeyBinder, editUserbind, void(entity, string, string, string))
-ENDCLASS(XonoticKeyBinder)
-entity makeXonoticKeyBinder();
-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
-
-const string KEY_NOT_BOUND_CMD = "// not bound";
-
-const float MAX_KEYS_PER_FUNCTION = 2;
-const float MAX_KEYBINDS = 256;
-string Xonotic_KeyBinds_Functions[MAX_KEYBINDS];
-string Xonotic_KeyBinds_Descriptions[MAX_KEYBINDS];
-var float Xonotic_KeyBinds_Count = -1;
-
-void Xonotic_KeyBinds_Read()
-{
-       float fh;
-       string s;
-
-       Xonotic_KeyBinds_Count = 0;
-       fh = fopen(language_filename("keybinds.txt"), FILE_READ);
-       if(fh < 0)
-               return;
-       while((s = fgets(fh)))
-       {
-               if(tokenize_console(s) != 2)
-                       continue;
-               Xonotic_KeyBinds_Functions[Xonotic_KeyBinds_Count] = strzone(argv(0));
-               Xonotic_KeyBinds_Descriptions[Xonotic_KeyBinds_Count] = strzone(argv(1));
-               ++Xonotic_KeyBinds_Count;
-               if(Xonotic_KeyBinds_Count >= MAX_KEYBINDS)
-                       break;
-       }
-       fclose(fh);
-}
-
-entity makeXonoticKeyBinder()
-{
-       entity me;
-       me = spawnXonoticKeyBinder();
-       me.configureXonoticKeyBinder(me);
-       return me;
-}
-void replace_bind(string from, string to)
-{
-       float n, j, k;
-       n = tokenize(findkeysforcommand(from, 0)); // uses '...' strings
-       for(j = 0; j < n; ++j)
-       {
-               k = stof(argv(j));
-               if(k != -1)
-                       localcmd("\nbind \"", keynumtostring(k), "\" \"", to, "\"\n");
-       }
-       if(n)
-               cvar_set("_hud_showbinds_reload", "1");
-}
-void XonoticKeyBinder_configureXonoticKeyBinder(entity me)
-{
-       me.configureXonoticListBox(me);
-       if(Xonotic_KeyBinds_Count < 0)
-               Xonotic_KeyBinds_Read();
-       me.nItems = Xonotic_KeyBinds_Count;
-       me.setSelected(me, 0);
-
-       // TEMP: Xonotic 0.1 to later
-       replace_bind("impulse 1", "weapon_group_1");
-       replace_bind("impulse 2", "weapon_group_2");
-       replace_bind("impulse 3", "weapon_group_3");
-       replace_bind("impulse 4", "weapon_group_4");
-       replace_bind("impulse 5", "weapon_group_5");
-       replace_bind("impulse 6", "weapon_group_6");
-       replace_bind("impulse 7", "weapon_group_7");
-       replace_bind("impulse 8", "weapon_group_8");
-       replace_bind("impulse 9", "weapon_group_9");
-       replace_bind("impulse 14", "weapon_group_0");
-}
-void XonoticKeyBinder_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(XonoticKeyBinder).resizeNotify(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(Xonotic_KeyBinds_Descriptions[me.selectedItem], 0, 1) != "$");
-}
-void KeyBinder_Bind_Change(entity btn, entity me)
-{
-       string func;
-
-       func = Xonotic_KeyBinds_Functions[me.selectedItem];
-       if(func == "")
-               return;
-
-       me.keyGrabButton.forcePressed = 1;
-       me.clearButton.disabled = 1;
-       keyGrabber = me;
-}
-void XonoticKeyBinder_keyGrabbed(entity me, float key, float ascii)
-{
-       float n, j, k, nvalid;
-       string func;
-
-       me.keyGrabButton.forcePressed = 0;
-       me.clearButton.disabled = 0;
-
-       if(key == K_ESCAPE)
-               return;
-
-       // forbid these keys from being bound in the menu
-       if(key == K_CAPSLOCK || key == K_NUMLOCK)
-       {
-               KeyBinder_Bind_Change(me, me);
-               return;
-       }
-
-       func = Xonotic_KeyBinds_Functions[me.selectedItem];
-       if(func == "")
-               return;
-
-       n = tokenize(findkeysforcommand(func, 0)); // uses '...' strings
-       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(k), "\" \"", KEY_NOT_BOUND_CMD, "\"\n");
-               }
-       }
-       localcmd("\nbind \"", keynumtostring(key), "\" \"", func, "\"\n");
-       localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
-       cvar_set("_hud_showbinds_reload", "1");
-}
-void XonoticKeyBinder_editUserbind(entity me, string theName, string theCommandPress, string theCommandRelease)
-{
-       string func, descr;
-
-       if(!me.userbindEditDialog)
-               return;
-
-       func = Xonotic_KeyBinds_Functions[me.selectedItem];
-       if(func == "")
-               return;
-
-       descr = Xonotic_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 = Xonotic_KeyBinds_Functions[me.selectedItem];
-       if(func == "")
-               return;
-
-       descr = Xonotic_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 = Xonotic_KeyBinds_Functions[me.selectedItem];
-       if(func == "")
-               return;
-
-       n = tokenize(findkeysforcommand(func, 0)); // uses '...' strings
-       for(j = 0; j < n; ++j)
-       {
-               k = stof(argv(j));
-               if(k != -1)
-                       //localcmd("\nunbind \"", keynumtostring(k), "\"\n");
-                       localcmd("\nbind \"", keynumtostring(k), "\" \"", KEY_NOT_BOUND_CMD, "\"\n");
-       }
-       localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
-       cvar_set("_hud_showbinds_reload", "1");
-}
-void KeyBinder_Bind_Reset_All(entity btn, entity me)
-{
-       localcmd("unbindall\n");
-       localcmd("exec binds-default.cfg\n");
-       localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
-       cvar_set("_hud_showbinds_reload", "1");
-}
-void XonoticKeyBinder_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       KeyBinder_Bind_Change(NULL, me);
-}
-void XonoticKeyBinder_setSelected(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) && (Xonotic_KeyBinds_Functions[i] == ""))
-                               ++i;
-               }
-               while((i > 0) && (Xonotic_KeyBinds_Functions[i] == ""))
-                       --i;
-               while((i < me.nItems - 1) && (Xonotic_KeyBinds_Functions[i] == ""))
-                       ++i;
-       }
-       if(me.pressed == 3) // released the mouse - fall back to last valid item
-       {
-               if(Xonotic_KeyBinds_Functions[i] == "")
-                       i = me.previouslySelected;
-       }
-       if(Xonotic_KeyBinds_Functions[i] != "")
-               me.previouslySelected = i;
-       if(me.userbindEditButton)
-               me.userbindEditButton.disabled = (substring(Xonotic_KeyBinds_Descriptions[i], 0, 1) != "$");
-       SUPER(XonoticKeyBinder).setSelected(me, i);
-}
-float XonoticKeyBinder_keyDown(entity me, float key, float ascii, float shift)
-{
-       float r;
-       r = 1;
-       switch(key)
-       {
-               case K_ENTER:
-               case K_KP_ENTER:
-               case K_SPACE:
-                       KeyBinder_Bind_Change(me, me);
-                       break;
-               case K_DEL:
-               case K_KP_DEL:
-               case K_BACKSPACE:
-                       KeyBinder_Bind_Clear(me, me);
-                       break;
-               default:
-                       r = SUPER(XonoticKeyBinder).keyDown(me, key, ascii, shift);
-                       break;
-       }
-       return r;
-}
-void XonoticKeyBinder_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string s;
-       float j, k, n;
-       vector theColor;
-       float theAlpha;
-       string func, descr;
-       float extraMargin;
-
-       descr = Xonotic_KeyBinds_Descriptions[i];
-       func = Xonotic_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;
-       }
-
-       s = draw_TextShortenToWidth(descr, me.columnFunctionSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + extraMargin * eX, s, me.realFontSize, theColor, theAlpha, 0);
-       if(func != "")
-       {
-               n = tokenize(findkeysforcommand(func, 0)); // uses '...' strings
-               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, 0, me.realFontSize);
-               draw_CenterText(me.realUpperMargin * eY + (me.columnKeysOrigin + 0.5 * me.columnKeysSize) * eX, s, me.realFontSize, theColor, theAlpha, 0);
-       }
-}
-#endif
diff --git a/qcsrc/menu/xonotic/keybinder.qc b/qcsrc/menu/xonotic/keybinder.qc
new file mode 100644 (file)
index 0000000..6f3e56f
--- /dev/null
@@ -0,0 +1,363 @@
+#ifdef INTERFACE
+CLASS(XonoticKeyBinder) EXTENDS(XonoticListBox)
+       METHOD(XonoticKeyBinder, configureXonoticKeyBinder, void(entity))
+       ATTRIB(XonoticKeyBinder, rowsPerItem, float, 1)
+       METHOD(XonoticKeyBinder, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticKeyBinder, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticKeyBinder, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticKeyBinder, setSelected, void(entity, float))
+       METHOD(XonoticKeyBinder, keyDown, float(entity, float, float, float))
+       METHOD(XonoticKeyBinder, keyGrabbed, void(entity, float, float))
+
+       ATTRIB(XonoticKeyBinder, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticKeyBinder, realUpperMargin, float, 0)
+       ATTRIB(XonoticKeyBinder, columnFunctionOrigin, float, 0)
+       ATTRIB(XonoticKeyBinder, columnFunctionSize, float, 0)
+       ATTRIB(XonoticKeyBinder, columnKeysOrigin, float, 0)
+       ATTRIB(XonoticKeyBinder, columnKeysSize, float, 0)
+
+       ATTRIB(XonoticKeyBinder, previouslySelected, float, -1)
+       ATTRIB(XonoticKeyBinder, inMouseHandler, float, 0)
+       ATTRIB(XonoticKeyBinder, userbindEditButton, entity, NULL)
+       ATTRIB(XonoticKeyBinder, keyGrabButton, entity, NULL)
+       ATTRIB(XonoticKeyBinder, clearButton, entity, NULL)
+       ATTRIB(XonoticKeyBinder, userbindEditDialog, entity, NULL)
+       METHOD(XonoticKeyBinder, editUserbind, void(entity, string, string, string))
+ENDCLASS(XonoticKeyBinder)
+entity makeXonoticKeyBinder();
+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
+
+const string KEY_NOT_BOUND_CMD = "// not bound";
+
+const float MAX_KEYS_PER_FUNCTION = 2;
+const float MAX_KEYBINDS = 256;
+string Xonotic_KeyBinds_Functions[MAX_KEYBINDS];
+string Xonotic_KeyBinds_Descriptions[MAX_KEYBINDS];
+var float Xonotic_KeyBinds_Count = -1;
+
+void Xonotic_KeyBinds_Read()
+{
+       float fh;
+       string s;
+
+       Xonotic_KeyBinds_Count = 0;
+       fh = fopen(language_filename("keybinds.txt"), FILE_READ);
+       if(fh < 0)
+               return;
+       while((s = fgets(fh)))
+       {
+               if(tokenize_console(s) != 2)
+                       continue;
+               Xonotic_KeyBinds_Functions[Xonotic_KeyBinds_Count] = strzone(argv(0));
+               Xonotic_KeyBinds_Descriptions[Xonotic_KeyBinds_Count] = strzone(argv(1));
+               ++Xonotic_KeyBinds_Count;
+               if(Xonotic_KeyBinds_Count >= MAX_KEYBINDS)
+                       break;
+       }
+       fclose(fh);
+}
+
+entity makeXonoticKeyBinder()
+{
+       entity me;
+       me = spawnXonoticKeyBinder();
+       me.configureXonoticKeyBinder(me);
+       return me;
+}
+void replace_bind(string from, string to)
+{
+       float n, j, k;
+       n = tokenize(findkeysforcommand(from, 0)); // uses '...' strings
+       for(j = 0; j < n; ++j)
+       {
+               k = stof(argv(j));
+               if(k != -1)
+                       localcmd("\nbind \"", keynumtostring(k), "\" \"", to, "\"\n");
+       }
+       if(n)
+               cvar_set("_hud_showbinds_reload", "1");
+}
+void XonoticKeyBinder_configureXonoticKeyBinder(entity me)
+{
+       me.configureXonoticListBox(me);
+       if(Xonotic_KeyBinds_Count < 0)
+               Xonotic_KeyBinds_Read();
+       me.nItems = Xonotic_KeyBinds_Count;
+       me.setSelected(me, 0);
+
+       // TEMP: Xonotic 0.1 to later
+       replace_bind("impulse 1", "weapon_group_1");
+       replace_bind("impulse 2", "weapon_group_2");
+       replace_bind("impulse 3", "weapon_group_3");
+       replace_bind("impulse 4", "weapon_group_4");
+       replace_bind("impulse 5", "weapon_group_5");
+       replace_bind("impulse 6", "weapon_group_6");
+       replace_bind("impulse 7", "weapon_group_7");
+       replace_bind("impulse 8", "weapon_group_8");
+       replace_bind("impulse 9", "weapon_group_9");
+       replace_bind("impulse 14", "weapon_group_0");
+}
+void XonoticKeyBinder_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(XonoticKeyBinder).resizeNotify(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(Xonotic_KeyBinds_Descriptions[me.selectedItem], 0, 1) != "$");
+}
+void KeyBinder_Bind_Change(entity btn, entity me)
+{
+       string func;
+
+       func = Xonotic_KeyBinds_Functions[me.selectedItem];
+       if(func == "")
+               return;
+
+       me.keyGrabButton.forcePressed = 1;
+       me.clearButton.disabled = 1;
+       keyGrabber = me;
+}
+void XonoticKeyBinder_keyGrabbed(entity me, float key, float ascii)
+{
+       float n, j, k, nvalid;
+       string func;
+
+       me.keyGrabButton.forcePressed = 0;
+       me.clearButton.disabled = 0;
+
+       if(key == K_ESCAPE)
+               return;
+
+       // forbid these keys from being bound in the menu
+       if(key == K_CAPSLOCK || key == K_NUMLOCK)
+       {
+               KeyBinder_Bind_Change(me, me);
+               return;
+       }
+
+       func = Xonotic_KeyBinds_Functions[me.selectedItem];
+       if(func == "")
+               return;
+
+       n = tokenize(findkeysforcommand(func, 0)); // uses '...' strings
+       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(k), "\" \"", KEY_NOT_BOUND_CMD, "\"\n");
+               }
+       }
+       localcmd("\nbind \"", keynumtostring(key), "\" \"", func, "\"\n");
+       localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
+       cvar_set("_hud_showbinds_reload", "1");
+}
+void XonoticKeyBinder_editUserbind(entity me, string theName, string theCommandPress, string theCommandRelease)
+{
+       string func, descr;
+
+       if(!me.userbindEditDialog)
+               return;
+
+       func = Xonotic_KeyBinds_Functions[me.selectedItem];
+       if(func == "")
+               return;
+
+       descr = Xonotic_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 = Xonotic_KeyBinds_Functions[me.selectedItem];
+       if(func == "")
+               return;
+
+       descr = Xonotic_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 = Xonotic_KeyBinds_Functions[me.selectedItem];
+       if(func == "")
+               return;
+
+       n = tokenize(findkeysforcommand(func, 0)); // uses '...' strings
+       for(j = 0; j < n; ++j)
+       {
+               k = stof(argv(j));
+               if(k != -1)
+                       //localcmd("\nunbind \"", keynumtostring(k), "\"\n");
+                       localcmd("\nbind \"", keynumtostring(k), "\" \"", KEY_NOT_BOUND_CMD, "\"\n");
+       }
+       localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
+       cvar_set("_hud_showbinds_reload", "1");
+}
+void KeyBinder_Bind_Reset_All(entity btn, entity me)
+{
+       localcmd("unbindall\n");
+       localcmd("exec binds-default.cfg\n");
+       localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
+       cvar_set("_hud_showbinds_reload", "1");
+}
+void XonoticKeyBinder_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       KeyBinder_Bind_Change(NULL, me);
+}
+void XonoticKeyBinder_setSelected(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) && (Xonotic_KeyBinds_Functions[i] == ""))
+                               ++i;
+               }
+               while((i > 0) && (Xonotic_KeyBinds_Functions[i] == ""))
+                       --i;
+               while((i < me.nItems - 1) && (Xonotic_KeyBinds_Functions[i] == ""))
+                       ++i;
+       }
+       if(me.pressed == 3) // released the mouse - fall back to last valid item
+       {
+               if(Xonotic_KeyBinds_Functions[i] == "")
+                       i = me.previouslySelected;
+       }
+       if(Xonotic_KeyBinds_Functions[i] != "")
+               me.previouslySelected = i;
+       if(me.userbindEditButton)
+               me.userbindEditButton.disabled = (substring(Xonotic_KeyBinds_Descriptions[i], 0, 1) != "$");
+       SUPER(XonoticKeyBinder).setSelected(me, i);
+}
+float XonoticKeyBinder_keyDown(entity me, float key, float ascii, float shift)
+{
+       float r;
+       r = 1;
+       switch(key)
+       {
+               case K_ENTER:
+               case K_KP_ENTER:
+               case K_SPACE:
+                       KeyBinder_Bind_Change(me, me);
+                       break;
+               case K_DEL:
+               case K_KP_DEL:
+               case K_BACKSPACE:
+                       KeyBinder_Bind_Clear(me, me);
+                       break;
+               default:
+                       r = SUPER(XonoticKeyBinder).keyDown(me, key, ascii, shift);
+                       break;
+       }
+       return r;
+}
+void XonoticKeyBinder_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s;
+       float j, k, n;
+       vector theColor;
+       float theAlpha;
+       string func, descr;
+       float extraMargin;
+
+       descr = Xonotic_KeyBinds_Descriptions[i];
+       func = Xonotic_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;
+       }
+
+       s = draw_TextShortenToWidth(descr, me.columnFunctionSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + extraMargin * eX, s, me.realFontSize, theColor, theAlpha, 0);
+       if(func != "")
+       {
+               n = tokenize(findkeysforcommand(func, 0)); // uses '...' strings
+               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, 0, me.realFontSize);
+               draw_CenterText(me.realUpperMargin * eY + (me.columnKeysOrigin + 0.5 * me.columnKeysSize) * eX, s, me.realFontSize, theColor, theAlpha, 0);
+       }
+}
+#endif
diff --git a/qcsrc/menu/xonotic/languagelist.c b/qcsrc/menu/xonotic/languagelist.c
deleted file mode 100644 (file)
index d34062d..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticLanguageList) EXTENDS(XonoticListBox)
-       METHOD(XonoticLanguageList, configureXonoticLanguageList, void(entity))
-       ATTRIB(XonoticLanguageList, rowsPerItem, float, 1)
-       METHOD(XonoticLanguageList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticLanguageList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticLanguageList, setSelected, void(entity, float))
-       METHOD(XonoticLanguageList, loadCvars, void(entity))
-       METHOD(XonoticLanguageList, saveCvars, void(entity))
-
-       ATTRIB(XonoticLanguageList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticLanguageList, realUpperMargin, float, 0)
-       ATTRIB(XonoticLanguageList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticLanguageList, columnNameSize, float, 0)
-       ATTRIB(XonoticLanguageList, columnPercentageOrigin, float, 0)
-       ATTRIB(XonoticLanguageList, columnPercentageSize, float, 0)
-
-       METHOD(XonoticLanguageList, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticLanguageList, keyDown, float(entity, float, float, float)) // enter handling
-
-       METHOD(XonoticLanguageList, destroy, void(entity))
-
-       ATTRIB(XonoticLanguageList, languagelist, float, -1)
-       METHOD(XonoticLanguageList, getLanguages, void(entity))
-       METHOD(XonoticLanguageList, setLanguage, void(entity))
-       METHOD(XonoticLanguageList, languageParameter, string(entity, float, float))
-
-       ATTRIB(XonoticLanguageList, name, string, "languageselector") // change this to make it noninteractive (for first run dialog)
-ENDCLASS(XonoticLanguageList)
-
-entity makeXonoticLanguageList();
-void SetLanguage_Click(entity btn, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-
-const float LANGPARM_ID = 0;
-const float LANGPARM_NAME = 1;
-const float LANGPARM_NAME_LOCALIZED = 2;
-const float LANGPARM_PERCENTAGE = 3;
-const float LANGPARM_COUNT = 4;
-
-entity makeXonoticLanguageList()
-{
-       entity me;
-       me = spawnXonoticLanguageList();
-       me.configureXonoticLanguageList(me);
-       return me;
-}
-
-void XonoticLanguageList_configureXonoticLanguageList(entity me)
-{
-       me.configureXonoticListBox(me);
-       me.getLanguages(me);
-       me.loadCvars(me);
-}
-
-void XonoticLanguageList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string s, p;
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-
-       s = me.languageParameter(me, i, LANGPARM_NAME_LOCALIZED);
-
-       vector save_fontscale = draw_fontscale;
-       float f = draw_CondensedFontFactor(s, FALSE, me.realFontSize, 1);
-       draw_fontscale_x *= f;
-       vector fs = me.realFontSize;
-       fs_x *= f;
-       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, fs, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
-       draw_fontscale = save_fontscale;
-
-       p = me.languageParameter(me, i, LANGPARM_PERCENTAGE);
-       if(p != "")
-       {
-               vector save_fontscale = draw_fontscale;
-               float f = draw_CondensedFontFactor(p, FALSE, me.realFontSize, 1);
-               draw_fontscale_x *= f;
-               vector fs = me.realFontSize;
-               fs_x *= f;
-               draw_Text(me.realUpperMargin * eY + (me.columnPercentageOrigin + (me.columnPercentageSize - draw_TextWidth(p, 0, fs))) * eX, p, fs, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
-               draw_fontscale = save_fontscale;
-       }
-}
-
-void XonoticLanguageList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(XonoticLanguageList).resizeNotify(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.columnPercentageSize = me.realFontSize_x * 3;
-       me.columnPercentageOrigin = 1 - me.columnPercentageSize;
-       me.columnNameOrigin = 0;
-       me.columnNameSize = me.columnPercentageOrigin;
-}
-
-void XonoticLanguageList_setSelected(entity me, float i)
-{
-       SUPER(XonoticLanguageList).setSelected(me, i);
-       me.saveCvars(me);
-}
-
-void XonoticLanguageList_loadCvars(entity me)
-{
-       string s;
-       float i, n;
-       s = cvar_string("_menu_prvm_language");
-       n = me.nItems;
-
-       // default to English
-       for(i = 0; i < n; ++i)
-       {
-               if(me.languageParameter(me, i, LANGPARM_ID) == "en")
-               {
-                       me.selectedItem = i;
-                       break;
-               }
-       }
-
-        // otherwise, find the language
-       for(i = 0; i < n; ++i)
-       {
-               if(me.languageParameter(me, i, LANGPARM_ID) == s)
-               {
-                       me.selectedItem = i;
-                       break;
-               }
-       }
-
-       // save it off (turning anything unknown into "en")
-       me.saveCvars(me);
-}
-
-void XonoticLanguageList_saveCvars(entity me)
-{
-       cvar_set("_menu_prvm_language", me.languageParameter(me, me.selectedItem, LANGPARM_ID));
-}
-
-void XonoticLanguageList_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       me.setLanguage(me);
-}
-
-float XonoticLanguageList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if(scan == K_ENTER || scan == K_KP_ENTER) {
-               me.setLanguage(me);
-               return 1;
-       }
-       else
-               return SUPER(XonoticLanguageList).keyDown(me, scan, ascii, shift);
-}
-
-void XonoticLanguageList_destroy(entity me)
-{
-       buf_del(me.languagelist);
-}
-
-void XonoticLanguageList_getLanguages(entity me)
-{
-       float buf, i, n, fh;
-       string s;
-
-       buf = buf_create();
-
-       fh = fopen("languages.txt", FILE_READ);
-       i = 0;
-       while((s = fgets(fh)))
-       {
-               n = tokenize_console(s);
-               if(n < 3)
-                       continue;
-               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_ID, argv(0));
-               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_NAME, argv(1));
-               float k = strstrofs(argv(2), "(", 0);
-               if(k > 0)
-               if(substring(argv(2), strlen(argv(2)) - 1, 1) == ")")
-               {
-                       string percent = substring(argv(2), k + 1, -2);
-                       if(percent != "100%")
-                               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_PERCENTAGE, percent);
-               }
-               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_NAME_LOCALIZED, (k < 0) ? argv(2) : substring(argv(2), 0, k - 1));
-               ++i;
-       }
-       fclose(fh);
-
-       me.languagelist = buf;
-       me.nItems = i;
-}
-
-void XonoticLanguageList_setLanguage(entity me)
-{
-       if(prvm_language != cvar_string("_menu_prvm_language"))
-       {
-               if(!(gamestatus & GAME_CONNECTED))
-                       localcmd("\nprvm_language \"$_menu_prvm_language\"; menu_restart; menu_cmd languageselect\n");
-               else
-                       DialogOpenButton_Click(me, main.languageWarningDialog);
-       }
-}
-
-string XonoticLanguageList_languageParameter(entity me, float i, float key)
-{
-       return bufstr_get(me.languagelist, i * LANGPARM_COUNT + key);
-}
-
-void SetLanguage_Click(entity btn, entity me)
-{
-       me.setLanguage(me);
-}
-
-#endif
diff --git a/qcsrc/menu/xonotic/languagelist.qc b/qcsrc/menu/xonotic/languagelist.qc
new file mode 100644 (file)
index 0000000..d34062d
--- /dev/null
@@ -0,0 +1,215 @@
+#ifdef INTERFACE
+CLASS(XonoticLanguageList) EXTENDS(XonoticListBox)
+       METHOD(XonoticLanguageList, configureXonoticLanguageList, void(entity))
+       ATTRIB(XonoticLanguageList, rowsPerItem, float, 1)
+       METHOD(XonoticLanguageList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticLanguageList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticLanguageList, setSelected, void(entity, float))
+       METHOD(XonoticLanguageList, loadCvars, void(entity))
+       METHOD(XonoticLanguageList, saveCvars, void(entity))
+
+       ATTRIB(XonoticLanguageList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticLanguageList, realUpperMargin, float, 0)
+       ATTRIB(XonoticLanguageList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticLanguageList, columnNameSize, float, 0)
+       ATTRIB(XonoticLanguageList, columnPercentageOrigin, float, 0)
+       ATTRIB(XonoticLanguageList, columnPercentageSize, float, 0)
+
+       METHOD(XonoticLanguageList, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticLanguageList, keyDown, float(entity, float, float, float)) // enter handling
+
+       METHOD(XonoticLanguageList, destroy, void(entity))
+
+       ATTRIB(XonoticLanguageList, languagelist, float, -1)
+       METHOD(XonoticLanguageList, getLanguages, void(entity))
+       METHOD(XonoticLanguageList, setLanguage, void(entity))
+       METHOD(XonoticLanguageList, languageParameter, string(entity, float, float))
+
+       ATTRIB(XonoticLanguageList, name, string, "languageselector") // change this to make it noninteractive (for first run dialog)
+ENDCLASS(XonoticLanguageList)
+
+entity makeXonoticLanguageList();
+void SetLanguage_Click(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+
+const float LANGPARM_ID = 0;
+const float LANGPARM_NAME = 1;
+const float LANGPARM_NAME_LOCALIZED = 2;
+const float LANGPARM_PERCENTAGE = 3;
+const float LANGPARM_COUNT = 4;
+
+entity makeXonoticLanguageList()
+{
+       entity me;
+       me = spawnXonoticLanguageList();
+       me.configureXonoticLanguageList(me);
+       return me;
+}
+
+void XonoticLanguageList_configureXonoticLanguageList(entity me)
+{
+       me.configureXonoticListBox(me);
+       me.getLanguages(me);
+       me.loadCvars(me);
+}
+
+void XonoticLanguageList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s, p;
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       s = me.languageParameter(me, i, LANGPARM_NAME_LOCALIZED);
+
+       vector save_fontscale = draw_fontscale;
+       float f = draw_CondensedFontFactor(s, FALSE, me.realFontSize, 1);
+       draw_fontscale_x *= f;
+       vector fs = me.realFontSize;
+       fs_x *= f;
+       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, fs, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
+       draw_fontscale = save_fontscale;
+
+       p = me.languageParameter(me, i, LANGPARM_PERCENTAGE);
+       if(p != "")
+       {
+               vector save_fontscale = draw_fontscale;
+               float f = draw_CondensedFontFactor(p, FALSE, me.realFontSize, 1);
+               draw_fontscale_x *= f;
+               vector fs = me.realFontSize;
+               fs_x *= f;
+               draw_Text(me.realUpperMargin * eY + (me.columnPercentageOrigin + (me.columnPercentageSize - draw_TextWidth(p, 0, fs))) * eX, p, fs, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
+               draw_fontscale = save_fontscale;
+       }
+}
+
+void XonoticLanguageList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(XonoticLanguageList).resizeNotify(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.columnPercentageSize = me.realFontSize_x * 3;
+       me.columnPercentageOrigin = 1 - me.columnPercentageSize;
+       me.columnNameOrigin = 0;
+       me.columnNameSize = me.columnPercentageOrigin;
+}
+
+void XonoticLanguageList_setSelected(entity me, float i)
+{
+       SUPER(XonoticLanguageList).setSelected(me, i);
+       me.saveCvars(me);
+}
+
+void XonoticLanguageList_loadCvars(entity me)
+{
+       string s;
+       float i, n;
+       s = cvar_string("_menu_prvm_language");
+       n = me.nItems;
+
+       // default to English
+       for(i = 0; i < n; ++i)
+       {
+               if(me.languageParameter(me, i, LANGPARM_ID) == "en")
+               {
+                       me.selectedItem = i;
+                       break;
+               }
+       }
+
+        // otherwise, find the language
+       for(i = 0; i < n; ++i)
+       {
+               if(me.languageParameter(me, i, LANGPARM_ID) == s)
+               {
+                       me.selectedItem = i;
+                       break;
+               }
+       }
+
+       // save it off (turning anything unknown into "en")
+       me.saveCvars(me);
+}
+
+void XonoticLanguageList_saveCvars(entity me)
+{
+       cvar_set("_menu_prvm_language", me.languageParameter(me, me.selectedItem, LANGPARM_ID));
+}
+
+void XonoticLanguageList_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       me.setLanguage(me);
+}
+
+float XonoticLanguageList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_KP_ENTER) {
+               me.setLanguage(me);
+               return 1;
+       }
+       else
+               return SUPER(XonoticLanguageList).keyDown(me, scan, ascii, shift);
+}
+
+void XonoticLanguageList_destroy(entity me)
+{
+       buf_del(me.languagelist);
+}
+
+void XonoticLanguageList_getLanguages(entity me)
+{
+       float buf, i, n, fh;
+       string s;
+
+       buf = buf_create();
+
+       fh = fopen("languages.txt", FILE_READ);
+       i = 0;
+       while((s = fgets(fh)))
+       {
+               n = tokenize_console(s);
+               if(n < 3)
+                       continue;
+               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_ID, argv(0));
+               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_NAME, argv(1));
+               float k = strstrofs(argv(2), "(", 0);
+               if(k > 0)
+               if(substring(argv(2), strlen(argv(2)) - 1, 1) == ")")
+               {
+                       string percent = substring(argv(2), k + 1, -2);
+                       if(percent != "100%")
+                               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_PERCENTAGE, percent);
+               }
+               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_NAME_LOCALIZED, (k < 0) ? argv(2) : substring(argv(2), 0, k - 1));
+               ++i;
+       }
+       fclose(fh);
+
+       me.languagelist = buf;
+       me.nItems = i;
+}
+
+void XonoticLanguageList_setLanguage(entity me)
+{
+       if(prvm_language != cvar_string("_menu_prvm_language"))
+       {
+               if(!(gamestatus & GAME_CONNECTED))
+                       localcmd("\nprvm_language \"$_menu_prvm_language\"; menu_restart; menu_cmd languageselect\n");
+               else
+                       DialogOpenButton_Click(me, main.languageWarningDialog);
+       }
+}
+
+string XonoticLanguageList_languageParameter(entity me, float i, float key)
+{
+       return bufstr_get(me.languagelist, i * LANGPARM_COUNT + key);
+}
+
+void SetLanguage_Click(entity btn, entity me)
+{
+       me.setLanguage(me);
+}
+
+#endif
diff --git a/qcsrc/menu/xonotic/listbox.c b/qcsrc/menu/xonotic/listbox.c
deleted file mode 100644 (file)
index 23fa58d..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticListBox) EXTENDS(ListBox)
-       METHOD(XonoticListBox, configureXonoticListBox, void(entity))
-       ATTRIB(XonoticListBox, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticListBox, scrollbarWidth, float, SKINWIDTH_SCROLLBAR)
-       ATTRIB(XonoticListBox, src, string, SKINGFX_SCROLLBAR)
-       ATTRIB(XonoticListBox, tolerance, vector, SKINTOLERANCE_SLIDER)
-       ATTRIB(XonoticListBox, rowsPerItem, float, 1)
-       METHOD(XonoticListBox, resizeNotify, void(entity, vector, vector, vector, vector))
-       ATTRIB(XonoticListBox, color, vector, SKINCOLOR_SCROLLBAR_N)
-       ATTRIB(XonoticListBox, colorF, vector, SKINCOLOR_SCROLLBAR_F)
-       ATTRIB(XonoticListBox, color2, vector, SKINCOLOR_SCROLLBAR_S)
-       ATTRIB(XonoticListBox, colorC, vector, SKINCOLOR_SCROLLBAR_C)
-       ATTRIB(XonoticListBox, colorBG, vector, SKINCOLOR_LISTBOX_BACKGROUND)
-       ATTRIB(XonoticListBox, alphaBG, float, SKINALPHA_LISTBOX_BACKGROUND)
-ENDCLASS(XonoticListBox)
-entity makeXonoticListBox();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticListBox()
-{
-       entity me;
-       me = spawnXonoticListBox();
-       me.configureXonoticListBox(me);
-       return me;
-}
-void XonoticListBox_configureXonoticListBox(entity me)
-{
-       me.configureListBox(me, me.scrollbarWidth, 1); // item height gets set up later
-}
-void XonoticListBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemHeight = me.rowsPerItem * me.fontSize / absSize_y;
-       SUPER(XonoticListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/listbox.qc b/qcsrc/menu/xonotic/listbox.qc
new file mode 100644 (file)
index 0000000..23fa58d
--- /dev/null
@@ -0,0 +1,37 @@
+#ifdef INTERFACE
+CLASS(XonoticListBox) EXTENDS(ListBox)
+       METHOD(XonoticListBox, configureXonoticListBox, void(entity))
+       ATTRIB(XonoticListBox, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticListBox, scrollbarWidth, float, SKINWIDTH_SCROLLBAR)
+       ATTRIB(XonoticListBox, src, string, SKINGFX_SCROLLBAR)
+       ATTRIB(XonoticListBox, tolerance, vector, SKINTOLERANCE_SLIDER)
+       ATTRIB(XonoticListBox, rowsPerItem, float, 1)
+       METHOD(XonoticListBox, resizeNotify, void(entity, vector, vector, vector, vector))
+       ATTRIB(XonoticListBox, color, vector, SKINCOLOR_SCROLLBAR_N)
+       ATTRIB(XonoticListBox, colorF, vector, SKINCOLOR_SCROLLBAR_F)
+       ATTRIB(XonoticListBox, color2, vector, SKINCOLOR_SCROLLBAR_S)
+       ATTRIB(XonoticListBox, colorC, vector, SKINCOLOR_SCROLLBAR_C)
+       ATTRIB(XonoticListBox, colorBG, vector, SKINCOLOR_LISTBOX_BACKGROUND)
+       ATTRIB(XonoticListBox, alphaBG, float, SKINALPHA_LISTBOX_BACKGROUND)
+ENDCLASS(XonoticListBox)
+entity makeXonoticListBox();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticListBox()
+{
+       entity me;
+       me = spawnXonoticListBox();
+       me.configureXonoticListBox(me);
+       return me;
+}
+void XonoticListBox_configureXonoticListBox(entity me)
+{
+       me.configureListBox(me, me.scrollbarWidth, 1); // item height gets set up later
+}
+void XonoticListBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemHeight = me.rowsPerItem * me.fontSize / absSize_y;
+       SUPER(XonoticListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/mainwindow.c b/qcsrc/menu/xonotic/mainwindow.c
deleted file mode 100644 (file)
index 6fa40bf..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-#ifdef INTERFACE
-CLASS(MainWindow) EXTENDS(ModalController)
-       METHOD(MainWindow, configureMainWindow, void(entity))
-       METHOD(MainWindow, draw, void(entity))
-       ATTRIB(MainWindow, firstRunDialog, entity, NULL)
-       ATTRIB(MainWindow, advancedDialog, entity, NULL)
-       ATTRIB(MainWindow, mutatorsDialog, entity, NULL)
-       ATTRIB(MainWindow, mapInfoDialog, entity, NULL)
-       ATTRIB(MainWindow, userbindEditDialog, entity, NULL)
-       ATTRIB(MainWindow, winnerDialog, entity, NULL)
-       ATTRIB(MainWindow, serverInfoDialog, entity, NULL)
-       ATTRIB(MainWindow, cvarsDialog, entity, NULL)
-       ATTRIB(MainWindow, screenshotViewerDialog, entity, NULL)
-       ATTRIB(MainWindow, viewDialog, entity, NULL)
-       ATTRIB(MainWindow, hudconfirmDialog, entity, NULL)
-       ATTRIB(MainWindow, languageWarningDialog, entity, NULL)
-       ATTRIB(MainWindow, mainNexposee, entity, NULL)
-       ATTRIB(MainWindow, fadedAlpha, float, SKINALPHA_BEHIND)
-       ATTRIB(MainWindow, dialogToShow, entity, NULL)
-       ATTRIB(MainWindow, demostartconfirmDialog, entity, NULL)
-       ATTRIB(MainWindow, demotimeconfirmDialog, entity, NULL)
-       ATTRIB(MainWindow, resetDialog, entity, NULL)
-ENDCLASS(MainWindow)
-#endif
-
-#ifdef IMPLEMENTATION
-void MainWindow_draw(entity me)
-{
-       SUPER(MainWindow).draw(me);
-
-       if(me.dialogToShow)
-       {
-               DialogOpenButton_Click_withCoords(world, me.dialogToShow, '0 0 0', eX * conwidth + eY * conheight);
-               me.dialogToShow = NULL;
-       }
-}
-
-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 MainWindow_configureMainWindow(entity me)
-{
-       entity n, i;
-
-       // dialog run upon startup
-       me.firstRunDialog = i = spawnXonoticFirstRunDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-
-       // hud_configure dialogs
-       i = spawnXonoticHUDExitDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDNotificationDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDAmmoDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDHealthArmorDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDChatDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDModIconsDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDPowerupsDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDPressedKeysDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDRaceTimerDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDRadarDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDScoreDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDTimerDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDVoteDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDWeaponsDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDEngineInfoDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDInfoMessagesDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       i = spawnXonoticHUDPhysicsDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       me.screenshotViewerDialog = i = spawnXonoticScreenshotViewerDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDCenterprintDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticHUDBuffsDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-
-       // dialogs used by settings
-       me.userbindEditDialog = i = spawnXonoticUserbindEditDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       me.cvarsDialog = i = spawnXonoticCvarsDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       me.resetDialog = i = spawnXonoticResetDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       me.languageWarningDialog = i = spawnXonoticLanguageWarningDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       me.hudconfirmDialog = i = spawnXonoticHUDConfirmDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-
-       // dialog used by singleplayer
-       me.winnerDialog = i = spawnXonoticWinnerDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-
-       // dialog used by multiplayer/join
-       me.serverInfoDialog = i = spawnXonoticServerInfoDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-       
-       me.demostartconfirmDialog = i = spawnXonoticDemoStartConfirmDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       me.demotimeconfirmDialog = i = spawnXonoticDemoTimeConfirmDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-
-       // dialogs used by multiplayer/create
-       me.mapInfoDialog = i = spawnXonoticMapInfoDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       me.mutatorsDialog = i = spawnXonoticMutatorsDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       // mutator dialogs
-       i = spawnXonoticSandboxToolsDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
-
-
-       // miscellaneous dialogs
-       i = spawnXonoticTeamSelectDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
-
-       i = spawnXonoticMonsterToolsDialog();
-       i.configureDialog(i);
-       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
-
-
-       // main dialogs/windows
-       me.mainNexposee = n = spawnXonoticNexposee();
-       /*
-               if(checkextension("DP_GECKO_SUPPORT"))
-               {
-                       i = spawnXonoticNewsDialog();
-                       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 = spawnXonoticSingleplayerDialog();
-               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 = spawnXonoticMultiplayerDialog();
-               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 = spawnXonoticSettingsDialog();
-               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 = spawnXonoticCreditsDialog();
-               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 = spawnXonoticQuitDialog();
-               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);
-
-       if(cvar_string("_cl_name") == cvar_defstring("_cl_name"))
-               me.dialogToShow = me.firstRunDialog;
-}
-#endif
-
-/* Click. The c-word is here so you can grep for it :-) */
diff --git a/qcsrc/menu/xonotic/mainwindow.qc b/qcsrc/menu/xonotic/mainwindow.qc
new file mode 100644 (file)
index 0000000..6fa40bf
--- /dev/null
@@ -0,0 +1,253 @@
+#ifdef INTERFACE
+CLASS(MainWindow) EXTENDS(ModalController)
+       METHOD(MainWindow, configureMainWindow, void(entity))
+       METHOD(MainWindow, draw, void(entity))
+       ATTRIB(MainWindow, firstRunDialog, entity, NULL)
+       ATTRIB(MainWindow, advancedDialog, entity, NULL)
+       ATTRIB(MainWindow, mutatorsDialog, entity, NULL)
+       ATTRIB(MainWindow, mapInfoDialog, entity, NULL)
+       ATTRIB(MainWindow, userbindEditDialog, entity, NULL)
+       ATTRIB(MainWindow, winnerDialog, entity, NULL)
+       ATTRIB(MainWindow, serverInfoDialog, entity, NULL)
+       ATTRIB(MainWindow, cvarsDialog, entity, NULL)
+       ATTRIB(MainWindow, screenshotViewerDialog, entity, NULL)
+       ATTRIB(MainWindow, viewDialog, entity, NULL)
+       ATTRIB(MainWindow, hudconfirmDialog, entity, NULL)
+       ATTRIB(MainWindow, languageWarningDialog, entity, NULL)
+       ATTRIB(MainWindow, mainNexposee, entity, NULL)
+       ATTRIB(MainWindow, fadedAlpha, float, SKINALPHA_BEHIND)
+       ATTRIB(MainWindow, dialogToShow, entity, NULL)
+       ATTRIB(MainWindow, demostartconfirmDialog, entity, NULL)
+       ATTRIB(MainWindow, demotimeconfirmDialog, entity, NULL)
+       ATTRIB(MainWindow, resetDialog, entity, NULL)
+ENDCLASS(MainWindow)
+#endif
+
+#ifdef IMPLEMENTATION
+void MainWindow_draw(entity me)
+{
+       SUPER(MainWindow).draw(me);
+
+       if(me.dialogToShow)
+       {
+               DialogOpenButton_Click_withCoords(world, me.dialogToShow, '0 0 0', eX * conwidth + eY * conheight);
+               me.dialogToShow = NULL;
+       }
+}
+
+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 MainWindow_configureMainWindow(entity me)
+{
+       entity n, i;
+
+       // dialog run upon startup
+       me.firstRunDialog = i = spawnXonoticFirstRunDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+
+       // hud_configure dialogs
+       i = spawnXonoticHUDExitDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDNotificationDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDAmmoDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDHealthArmorDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDChatDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDModIconsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDPowerupsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDPressedKeysDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDRaceTimerDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDRadarDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDScoreDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDTimerDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDVoteDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDWeaponsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDEngineInfoDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDInfoMessagesDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+       
+       i = spawnXonoticHUDPhysicsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+       
+       me.screenshotViewerDialog = i = spawnXonoticScreenshotViewerDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDCenterprintDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticHUDBuffsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+
+       // dialogs used by settings
+       me.userbindEditDialog = i = spawnXonoticUserbindEditDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       me.cvarsDialog = i = spawnXonoticCvarsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+       
+       me.resetDialog = i = spawnXonoticResetDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       me.languageWarningDialog = i = spawnXonoticLanguageWarningDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       me.hudconfirmDialog = i = spawnXonoticHUDConfirmDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+
+       // dialog used by singleplayer
+       me.winnerDialog = i = spawnXonoticWinnerDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+
+       // dialog used by multiplayer/join
+       me.serverInfoDialog = i = spawnXonoticServerInfoDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+       
+       me.demostartconfirmDialog = i = spawnXonoticDemoStartConfirmDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       me.demotimeconfirmDialog = i = spawnXonoticDemoTimeConfirmDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+
+       // dialogs used by multiplayer/create
+       me.mapInfoDialog = i = spawnXonoticMapInfoDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       me.mutatorsDialog = i = spawnXonoticMutatorsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       // mutator dialogs
+       i = spawnXonoticSandboxToolsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
+
+
+       // miscellaneous dialogs
+       i = spawnXonoticTeamSelectDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z);
+
+       i = spawnXonoticMonsterToolsDialog();
+       i.configureDialog(i);
+       me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS);
+
+
+       // main dialogs/windows
+       me.mainNexposee = n = spawnXonoticNexposee();
+       /*
+               if(checkextension("DP_GECKO_SUPPORT"))
+               {
+                       i = spawnXonoticNewsDialog();
+                       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 = spawnXonoticSingleplayerDialog();
+               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 = spawnXonoticMultiplayerDialog();
+               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 = spawnXonoticSettingsDialog();
+               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 = spawnXonoticCreditsDialog();
+               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 = spawnXonoticQuitDialog();
+               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);
+
+       if(cvar_string("_cl_name") == cvar_defstring("_cl_name"))
+               me.dialogToShow = me.firstRunDialog;
+}
+#endif
+
+/* Click. The c-word is here so you can grep for it :-) */
diff --git a/qcsrc/menu/xonotic/maplist.c b/qcsrc/menu/xonotic/maplist.c
deleted file mode 100644 (file)
index e05c764..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticMapList) EXTENDS(XonoticListBox)
-       METHOD(XonoticMapList, configureXonoticMapList, void(entity))
-       ATTRIB(XonoticMapList, rowsPerItem, float, 4)
-       METHOD(XonoticMapList, draw, void(entity))
-       METHOD(XonoticMapList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticMapList, clickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticMapList, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticMapList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticMapList, refilter, void(entity))
-       METHOD(XonoticMapList, refilterCallback, void(entity, entity))
-       METHOD(XonoticMapList, keyDown, float(entity, float, float, float))
-
-       ATTRIB(XonoticMapList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticMapList, columnPreviewOrigin, float, 0)
-       ATTRIB(XonoticMapList, columnPreviewSize, float, 0)
-       ATTRIB(XonoticMapList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticMapList, columnNameSize, float, 0)
-       ATTRIB(XonoticMapList, checkMarkOrigin, vector, '0 0 0')
-       ATTRIB(XonoticMapList, checkMarkSize, vector, '0 0 0')
-       ATTRIB(XonoticMapList, realUpperMargin1, float, 0)
-       ATTRIB(XonoticMapList, realUpperMargin2, float, 0)
-
-       ATTRIB(XonoticMapList, lastGametype, float, 0)
-       ATTRIB(XonoticMapList, lastFeatures, float, 0)
-
-       ATTRIB(XonoticMapList, origin, vector, '0 0 0')
-       ATTRIB(XonoticMapList, itemAbsSize, vector, '0 0 0')
-
-       ATTRIB(XonoticMapList, g_maplistCache, string, string_null)
-       METHOD(XonoticMapList, g_maplistCacheToggle, void(entity, float))
-       METHOD(XonoticMapList, g_maplistCacheQuery, float(entity, float))
-
-       ATTRIB(XonoticMapList, startButton, entity, NULL)
-
-       METHOD(XonoticMapList, loadCvars, void(entity))
-
-       ATTRIB(XonoticMapList, typeToSearchString, string, string_null)
-       ATTRIB(XonoticMapList, typeToSearchTime, float, 0)
-
-       METHOD(XonoticMapList, destroy, void(entity))
-
-       ATTRIB(XonoticListBox, alphaBG, float, 0)
-ENDCLASS(XonoticMapList)
-entity makeXonoticMapList();
-void MapList_All(entity btn, entity me);
-void MapList_None(entity btn, entity me);
-void MapList_LoadMap(entity btn, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticMapList_destroy(entity me)
-{
-       MapInfo_Shutdown();
-}
-
-entity makeXonoticMapList()
-{
-       entity me;
-       me = spawnXonoticMapList();
-       me.configureXonoticMapList(me);
-       return me;
-}
-
-void XonoticMapList_configureXonoticMapList(entity me)
-{
-       me.configureXonoticListBox(me);
-       me.refilter(me);
-}
-
-void XonoticMapList_loadCvars(entity me)
-{
-       me.refilter(me);
-}
-
-float XonoticMapList_g_maplistCacheQuery(entity me, float i)
-{
-       return stof(substring(me.g_maplistCache, i, 1));
-}
-void XonoticMapList_g_maplistCacheToggle(entity me, float i)
-{
-       string a, b, c, s, bspname;
-       float n;
-       s = me.g_maplistCache;
-       if (!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 (!((bspname = MapInfo_BSPName_ByID(i))))
-               return;
-       if(b == "1")
-               cvar_set("g_maplist", strcat(bspname, " ", cvar_string("g_maplist")));
-       else
-       {
-               s = "";
-               n = tokenize_console(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 XonoticMapList_draw(entity me)
-{
-       if(me.startButton)
-               me.startButton.disabled = ((me.selectedItem < 0) || (me.selectedItem >= me.nItems));
-       SUPER(XonoticMapList).draw(me);
-}
-
-void XonoticMapList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemAbsSize = '0 0 0';
-       SUPER(XonoticMapList).resizeNotify(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 XonoticMapList_clickListBoxItem(entity me, float i, vector where)
-{
-       if(where_x <= me.columnPreviewOrigin + me.columnPreviewSize)
-               if(where_x >= 0)
-                       me.g_maplistCacheToggle(me, i);
-}
-
-void XonoticMapList_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       if(where_x >= me.columnNameOrigin)
-               if(where_x <= 1)
-               {
-                       // pop up map info screen
-                       main.mapInfoDialog.loadMapInfo(main.mapInfoDialog, i, me);
-                       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));
-               }
-}
-
-void XonoticMapList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       // layout: Ping, Map name, Map name, NP, TP, MP
-       string s;
-       float theAlpha;
-       float included;
-
-       if(!MapInfo_Get_ByID(i))
-               return;
-
-       included = me.g_maplistCacheQuery(me, i);
-       if(included || isSelected)
-               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);
-
-       if(draw_PictureSize(strcat("/maps/", MapInfo_Map_bspname)) == '0 0 0')
-               draw_Picture(me.columnPreviewOrigin * eX, "nopreview_map", me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
-       else
-               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(strdecolorize(MapInfo_Map_titlestring), me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_MAPLIST_TITLE, theAlpha, 0);
-       s = draw_TextShortenToWidth(strdecolorize(MapInfo_Map_author), me.columnNameSize, 0,  me.realFontSize);
-       draw_Text(me.realUpperMargin2 * eY + (me.columnNameOrigin + 1.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_MAPLIST_AUTHOR, theAlpha, 0);
-
-       MapInfo_ClearTemps();
-}
-
-void XonoticMapList_refilter(entity me)
-{
-       float i, j, n;
-       string s;
-       float gt, f;
-       gt = MapInfo_CurrentGametype();
-       f = MapInfo_CurrentFeatures();
-       MapInfo_FilterGametype(gt, f, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 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_console(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 XonoticMapList_refilterCallback(entity me, entity cb)
-{
-       me.refilter(me);
-}
-
-void MapList_All(entity btn, entity me)
-{
-       float i;
-       string s;
-       MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, MapInfo_ForbiddenFlags(), 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;
-       float i;
-
-       i = me.selectedItem;
-
-       if(btn.parent.instanceOfXonoticMapInfoDialog)
-       {
-               i = btn.parent.currentMapIndex;
-               Dialog_Close(btn, btn.parent);
-       }
-
-       if(i >= me.nItems || i < 0)
-               return;
-
-       m = MapInfo_BSPName_ByID(i);
-       if (!m)
-       {
-               print(_("Huh? Can't play this (m is NULL). Refiltering so this won't happen again.\n"));
-               me.refilter(me);
-               return;
-       }
-       if(MapInfo_CheckMap(m))
-       {
-               localcmd("\nmenu_loadmap_prepare\n");
-               if(cvar("menu_use_default_hostname"))
-                       localcmd("hostname \"", sprintf(_("%s's Xonotic Server"), strdecolorize(cvar_string("_cl_name"))), "\"\n");
-               MapInfo_LoadMap(m, 1);
-       }
-       else
-       {
-               print(_("Huh? Can't play this (invalid game type). Refiltering so this won't happen again.\n"));
-               me.refilter(me);
-               return;
-       }
-}
-
-float XonoticMapList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       string ch, save;
-       if(me.nItems <= 0)
-               return SUPER(XonoticMapList).keyDown(me, scan, ascii, shift);
-       if(scan == K_MOUSE2 || scan == K_SPACE || scan == K_ENTER || scan == K_KP_ENTER)
-       {
-               // pop up map info screen
-               main.mapInfoDialog.loadMapInfo(main.mapInfoDialog, me.selectedItem, me);
-               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_MOUSE3 || scan == K_INS || scan == K_KP_INS)
-       {
-               me.g_maplistCacheToggle(me, me.selectedItem);
-       }
-       else if(ascii == 43) // +
-       {
-               if (!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 SUPER(XonoticMapList).keyDown(me, scan, ascii, shift);
-       return 1;
-}
-
-#endif
diff --git a/qcsrc/menu/xonotic/maplist.qc b/qcsrc/menu/xonotic/maplist.qc
new file mode 100644 (file)
index 0000000..e05c764
--- /dev/null
@@ -0,0 +1,353 @@
+#ifdef INTERFACE
+CLASS(XonoticMapList) EXTENDS(XonoticListBox)
+       METHOD(XonoticMapList, configureXonoticMapList, void(entity))
+       ATTRIB(XonoticMapList, rowsPerItem, float, 4)
+       METHOD(XonoticMapList, draw, void(entity))
+       METHOD(XonoticMapList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticMapList, clickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticMapList, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticMapList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticMapList, refilter, void(entity))
+       METHOD(XonoticMapList, refilterCallback, void(entity, entity))
+       METHOD(XonoticMapList, keyDown, float(entity, float, float, float))
+
+       ATTRIB(XonoticMapList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticMapList, columnPreviewOrigin, float, 0)
+       ATTRIB(XonoticMapList, columnPreviewSize, float, 0)
+       ATTRIB(XonoticMapList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticMapList, columnNameSize, float, 0)
+       ATTRIB(XonoticMapList, checkMarkOrigin, vector, '0 0 0')
+       ATTRIB(XonoticMapList, checkMarkSize, vector, '0 0 0')
+       ATTRIB(XonoticMapList, realUpperMargin1, float, 0)
+       ATTRIB(XonoticMapList, realUpperMargin2, float, 0)
+
+       ATTRIB(XonoticMapList, lastGametype, float, 0)
+       ATTRIB(XonoticMapList, lastFeatures, float, 0)
+
+       ATTRIB(XonoticMapList, origin, vector, '0 0 0')
+       ATTRIB(XonoticMapList, itemAbsSize, vector, '0 0 0')
+
+       ATTRIB(XonoticMapList, g_maplistCache, string, string_null)
+       METHOD(XonoticMapList, g_maplistCacheToggle, void(entity, float))
+       METHOD(XonoticMapList, g_maplistCacheQuery, float(entity, float))
+
+       ATTRIB(XonoticMapList, startButton, entity, NULL)
+
+       METHOD(XonoticMapList, loadCvars, void(entity))
+
+       ATTRIB(XonoticMapList, typeToSearchString, string, string_null)
+       ATTRIB(XonoticMapList, typeToSearchTime, float, 0)
+
+       METHOD(XonoticMapList, destroy, void(entity))
+
+       ATTRIB(XonoticListBox, alphaBG, float, 0)
+ENDCLASS(XonoticMapList)
+entity makeXonoticMapList();
+void MapList_All(entity btn, entity me);
+void MapList_None(entity btn, entity me);
+void MapList_LoadMap(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticMapList_destroy(entity me)
+{
+       MapInfo_Shutdown();
+}
+
+entity makeXonoticMapList()
+{
+       entity me;
+       me = spawnXonoticMapList();
+       me.configureXonoticMapList(me);
+       return me;
+}
+
+void XonoticMapList_configureXonoticMapList(entity me)
+{
+       me.configureXonoticListBox(me);
+       me.refilter(me);
+}
+
+void XonoticMapList_loadCvars(entity me)
+{
+       me.refilter(me);
+}
+
+float XonoticMapList_g_maplistCacheQuery(entity me, float i)
+{
+       return stof(substring(me.g_maplistCache, i, 1));
+}
+void XonoticMapList_g_maplistCacheToggle(entity me, float i)
+{
+       string a, b, c, s, bspname;
+       float n;
+       s = me.g_maplistCache;
+       if (!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 (!((bspname = MapInfo_BSPName_ByID(i))))
+               return;
+       if(b == "1")
+               cvar_set("g_maplist", strcat(bspname, " ", cvar_string("g_maplist")));
+       else
+       {
+               s = "";
+               n = tokenize_console(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 XonoticMapList_draw(entity me)
+{
+       if(me.startButton)
+               me.startButton.disabled = ((me.selectedItem < 0) || (me.selectedItem >= me.nItems));
+       SUPER(XonoticMapList).draw(me);
+}
+
+void XonoticMapList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticMapList).resizeNotify(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 XonoticMapList_clickListBoxItem(entity me, float i, vector where)
+{
+       if(where_x <= me.columnPreviewOrigin + me.columnPreviewSize)
+               if(where_x >= 0)
+                       me.g_maplistCacheToggle(me, i);
+}
+
+void XonoticMapList_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       if(where_x >= me.columnNameOrigin)
+               if(where_x <= 1)
+               {
+                       // pop up map info screen
+                       main.mapInfoDialog.loadMapInfo(main.mapInfoDialog, i, me);
+                       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));
+               }
+}
+
+void XonoticMapList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       // layout: Ping, Map name, Map name, NP, TP, MP
+       string s;
+       float theAlpha;
+       float included;
+
+       if(!MapInfo_Get_ByID(i))
+               return;
+
+       included = me.g_maplistCacheQuery(me, i);
+       if(included || isSelected)
+               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);
+
+       if(draw_PictureSize(strcat("/maps/", MapInfo_Map_bspname)) == '0 0 0')
+               draw_Picture(me.columnPreviewOrigin * eX, "nopreview_map", me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
+       else
+               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(strdecolorize(MapInfo_Map_titlestring), me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_MAPLIST_TITLE, theAlpha, 0);
+       s = draw_TextShortenToWidth(strdecolorize(MapInfo_Map_author), me.columnNameSize, 0,  me.realFontSize);
+       draw_Text(me.realUpperMargin2 * eY + (me.columnNameOrigin + 1.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_MAPLIST_AUTHOR, theAlpha, 0);
+
+       MapInfo_ClearTemps();
+}
+
+void XonoticMapList_refilter(entity me)
+{
+       float i, j, n;
+       string s;
+       float gt, f;
+       gt = MapInfo_CurrentGametype();
+       f = MapInfo_CurrentFeatures();
+       MapInfo_FilterGametype(gt, f, MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 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_console(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 XonoticMapList_refilterCallback(entity me, entity cb)
+{
+       me.refilter(me);
+}
+
+void MapList_All(entity btn, entity me)
+{
+       float i;
+       string s;
+       MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, MapInfo_ForbiddenFlags(), 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;
+       float i;
+
+       i = me.selectedItem;
+
+       if(btn.parent.instanceOfXonoticMapInfoDialog)
+       {
+               i = btn.parent.currentMapIndex;
+               Dialog_Close(btn, btn.parent);
+       }
+
+       if(i >= me.nItems || i < 0)
+               return;
+
+       m = MapInfo_BSPName_ByID(i);
+       if (!m)
+       {
+               print(_("Huh? Can't play this (m is NULL). Refiltering so this won't happen again.\n"));
+               me.refilter(me);
+               return;
+       }
+       if(MapInfo_CheckMap(m))
+       {
+               localcmd("\nmenu_loadmap_prepare\n");
+               if(cvar("menu_use_default_hostname"))
+                       localcmd("hostname \"", sprintf(_("%s's Xonotic Server"), strdecolorize(cvar_string("_cl_name"))), "\"\n");
+               MapInfo_LoadMap(m, 1);
+       }
+       else
+       {
+               print(_("Huh? Can't play this (invalid game type). Refiltering so this won't happen again.\n"));
+               me.refilter(me);
+               return;
+       }
+}
+
+float XonoticMapList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       string ch, save;
+       if(me.nItems <= 0)
+               return SUPER(XonoticMapList).keyDown(me, scan, ascii, shift);
+       if(scan == K_MOUSE2 || scan == K_SPACE || scan == K_ENTER || scan == K_KP_ENTER)
+       {
+               // pop up map info screen
+               main.mapInfoDialog.loadMapInfo(main.mapInfoDialog, me.selectedItem, me);
+               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_MOUSE3 || scan == K_INS || scan == K_KP_INS)
+       {
+               me.g_maplistCacheToggle(me, me.selectedItem);
+       }
+       else if(ascii == 43) // +
+       {
+               if (!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 SUPER(XonoticMapList).keyDown(me, scan, ascii, shift);
+       return 1;
+}
+
+#endif
diff --git a/qcsrc/menu/xonotic/nexposee.c b/qcsrc/menu/xonotic/nexposee.c
deleted file mode 100644 (file)
index b375393..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticNexposee) EXTENDS(Nexposee)
-       METHOD(XonoticNexposee, configureXonoticNexposee, void(entity))
-       METHOD(XonoticNexposee, close, void(entity))
-ENDCLASS(XonoticNexposee)
-entity makeXonoticNexposee();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticNexposee()
-{
-       entity me;
-       me = spawnXonoticNexposee();
-       me.configureXonoticNexposee(me);
-       return me;
-}
-
-void XonoticNexposee_configureXonoticNexposee(entity me)
-{
-}
-
-void XonoticNexposee_close(entity me)
-{
-       m_goto(string_null); // hide
-}
-#endif
diff --git a/qcsrc/menu/xonotic/nexposee.qc b/qcsrc/menu/xonotic/nexposee.qc
new file mode 100644 (file)
index 0000000..b375393
--- /dev/null
@@ -0,0 +1,26 @@
+#ifdef INTERFACE
+CLASS(XonoticNexposee) EXTENDS(Nexposee)
+       METHOD(XonoticNexposee, configureXonoticNexposee, void(entity))
+       METHOD(XonoticNexposee, close, void(entity))
+ENDCLASS(XonoticNexposee)
+entity makeXonoticNexposee();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticNexposee()
+{
+       entity me;
+       me = spawnXonoticNexposee();
+       me.configureXonoticNexposee(me);
+       return me;
+}
+
+void XonoticNexposee_configureXonoticNexposee(entity me)
+{
+}
+
+void XonoticNexposee_close(entity me)
+{
+       m_goto(string_null); // hide
+}
+#endif
diff --git a/qcsrc/menu/xonotic/playerlist.c b/qcsrc/menu/xonotic/playerlist.c
deleted file mode 100644 (file)
index c60b34e..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticPlayerList) EXTENDS(XonoticListBox)
-       ATTRIB(XonoticPlayerList, rowsPerItem, float, 1)
-       METHOD(XonoticPlayerList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticPlayerList, drawListBoxItem, void(entity, float, vector, float))
-       ATTRIB(XonoticPlayerList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticPlayerList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticPlayerList, columnNameSize, float, 0)
-       ATTRIB(XonoticPlayerList, columnScoreOrigin, float, 0)
-       ATTRIB(XonoticPlayerList, columnScoreSize, float, 0)
-       ATTRIB(XonoticPlayerList, realUpperMargin, float, 0)
-       ATTRIB(XonoticPlayerList, origin, vector, '0 0 0')
-       ATTRIB(XonoticPlayerList, itemAbsSize, vector, '0 0 0')
-       METHOD(XonoticPlayerList, setPlayerList, void(entity, string))
-       METHOD(XonoticPlayerList, getPlayerList, string(entity, float, float))
-       ATTRIB(XonoticPlayerList, playerList, float, -1)
-ENDCLASS(XonoticPlayerList)
-entity makeXonoticPlayerList();
-#endif
-
-#ifdef IMPLEMENTATION
-
-const float PLAYERPARM_SCORE = 0;
-const float PLAYERPARM_PING = 1;
-const float PLAYERPARM_TEAM = 2;
-const float PLAYERPARM_NAME = 3;
-const float PLAYERPARM_COUNT = 4;
-
-entity makeXonoticPlayerList()
-{
-       entity me;
-       me = spawnXonoticPlayerList();
-       me.configureXonoticListBox(me);
-       return me;
-}
-
-void XonoticPlayerList_setPlayerList(entity me, string plist)
-{
-       float buf,i,n;
-       string s;
-
-       buf = buf_create();
-       me.nItems = tokenizebyseparator(plist, "\n");
-       for(i = 0; i < me.nItems; ++i)
-       {
-               bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME, argv(i)); // -666 100 "^4Nex ^2Player"
-       }
-
-       for(i = 0; i < me.nItems; ++i)
-       {
-               s = bufstr_get(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME);
-               n = tokenize_console(s);
-
-               if(n == 4)
-               {
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_SCORE, argv(0)); // -666
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_PING,  argv(1)); // 100
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_TEAM,  argv(2)); // 0 for spec, else 1, 2, 3, 4
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME,  argv(3)); // ^4Nex ^2Player
-               }
-               else
-               {
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_SCORE, argv(0)); // -666
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_PING,  argv(1)); // 100
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_TEAM,  "-1");
-                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME,  argv(2)); // ^4Nex ^2Player
-               }
-       }
-       me.playerList = buf;
-}
-
-string XonoticPlayerList_getPlayerList(entity me, float i, float key)
-{
-       return bufstr_get(me.playerList, i * PLAYERPARM_COUNT + key);
-}
-
-void XonoticPlayerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemAbsSize = '0 0 0';
-       SUPER(XonoticPlayerList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
-
-       // this list does 1 char left and right margin
-       me.columnScoreSize = 5 * me.realFontSize_x;
-       me.columnNameSize = 1 - 3 * me.realFontSize_x - me.columnScoreSize;
-
-       me.columnNameOrigin = me.realFontSize_x;
-       me.columnScoreOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
-}
-
-void XonoticPlayerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string s;
-       string score;
-       float t;
-       vector rgb;
-
-       t = stof(me.getPlayerList(me, i, PLAYERPARM_TEAM));
-       if(t == 1)
-               rgb = colormapPaletteColor(4, 0);
-       else if(t == 2)
-               rgb = colormapPaletteColor(13, 0);
-       else if(t == 3)
-               rgb = colormapPaletteColor(12, 0);
-       else if(t == 4)
-               rgb = colormapPaletteColor(9, 0);
-       else
-               rgb = SKINCOLOR_TEXT;
-
-       s = me.getPlayerList(me, i, PLAYERPARM_NAME);
-       score = me.getPlayerList(me, i, PLAYERPARM_SCORE);
-
-       if(substring(score, strlen(score) - 10, 10) == ":spectator")
-       {
-               score = _("spectator");
-       }
-       else
-       {
-               if((t = strstrofs(score, ":", 0)) >= 0)
-                       score = substring(score, 0, t);
-               if((t = strstrofs(score, ",", 0)) >= 0)
-                       score = substring(score, 0, t);
-
-               if(stof(score) == -666)
-                       score = _("spectator");
-       }
-
-       s = draw_TextShortenToWidth(s, me.columnNameSize, 1, me.realFontSize);
-       draw_Text(me.realUpperMargin2 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 1, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', 1, 1);
-
-       score = draw_TextShortenToWidth(score, me.columnScoreSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin2 * eY + (me.columnScoreOrigin + 1.00 * (me.columnScoreSize - draw_TextWidth(score, 1, me.realFontSize))) * eX, score, me.realFontSize, rgb, 1, 0);
-}
-
-#endif
diff --git a/qcsrc/menu/xonotic/playerlist.qc b/qcsrc/menu/xonotic/playerlist.qc
new file mode 100644 (file)
index 0000000..c60b34e
--- /dev/null
@@ -0,0 +1,138 @@
+#ifdef INTERFACE
+CLASS(XonoticPlayerList) EXTENDS(XonoticListBox)
+       ATTRIB(XonoticPlayerList, rowsPerItem, float, 1)
+       METHOD(XonoticPlayerList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticPlayerList, drawListBoxItem, void(entity, float, vector, float))
+       ATTRIB(XonoticPlayerList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticPlayerList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticPlayerList, columnNameSize, float, 0)
+       ATTRIB(XonoticPlayerList, columnScoreOrigin, float, 0)
+       ATTRIB(XonoticPlayerList, columnScoreSize, float, 0)
+       ATTRIB(XonoticPlayerList, realUpperMargin, float, 0)
+       ATTRIB(XonoticPlayerList, origin, vector, '0 0 0')
+       ATTRIB(XonoticPlayerList, itemAbsSize, vector, '0 0 0')
+       METHOD(XonoticPlayerList, setPlayerList, void(entity, string))
+       METHOD(XonoticPlayerList, getPlayerList, string(entity, float, float))
+       ATTRIB(XonoticPlayerList, playerList, float, -1)
+ENDCLASS(XonoticPlayerList)
+entity makeXonoticPlayerList();
+#endif
+
+#ifdef IMPLEMENTATION
+
+const float PLAYERPARM_SCORE = 0;
+const float PLAYERPARM_PING = 1;
+const float PLAYERPARM_TEAM = 2;
+const float PLAYERPARM_NAME = 3;
+const float PLAYERPARM_COUNT = 4;
+
+entity makeXonoticPlayerList()
+{
+       entity me;
+       me = spawnXonoticPlayerList();
+       me.configureXonoticListBox(me);
+       return me;
+}
+
+void XonoticPlayerList_setPlayerList(entity me, string plist)
+{
+       float buf,i,n;
+       string s;
+
+       buf = buf_create();
+       me.nItems = tokenizebyseparator(plist, "\n");
+       for(i = 0; i < me.nItems; ++i)
+       {
+               bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME, argv(i)); // -666 100 "^4Nex ^2Player"
+       }
+
+       for(i = 0; i < me.nItems; ++i)
+       {
+               s = bufstr_get(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME);
+               n = tokenize_console(s);
+
+               if(n == 4)
+               {
+                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_SCORE, argv(0)); // -666
+                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_PING,  argv(1)); // 100
+                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_TEAM,  argv(2)); // 0 for spec, else 1, 2, 3, 4
+                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME,  argv(3)); // ^4Nex ^2Player
+               }
+               else
+               {
+                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_SCORE, argv(0)); // -666
+                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_PING,  argv(1)); // 100
+                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_TEAM,  "-1");
+                       bufstr_set(buf, i * PLAYERPARM_COUNT + PLAYERPARM_NAME,  argv(2)); // ^4Nex ^2Player
+               }
+       }
+       me.playerList = buf;
+}
+
+string XonoticPlayerList_getPlayerList(entity me, float i, float key)
+{
+       return bufstr_get(me.playerList, i * PLAYERPARM_COUNT + key);
+}
+
+void XonoticPlayerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticPlayerList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+
+       // this list does 1 char left and right margin
+       me.columnScoreSize = 5 * me.realFontSize_x;
+       me.columnNameSize = 1 - 3 * me.realFontSize_x - me.columnScoreSize;
+
+       me.columnNameOrigin = me.realFontSize_x;
+       me.columnScoreOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
+}
+
+void XonoticPlayerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s;
+       string score;
+       float t;
+       vector rgb;
+
+       t = stof(me.getPlayerList(me, i, PLAYERPARM_TEAM));
+       if(t == 1)
+               rgb = colormapPaletteColor(4, 0);
+       else if(t == 2)
+               rgb = colormapPaletteColor(13, 0);
+       else if(t == 3)
+               rgb = colormapPaletteColor(12, 0);
+       else if(t == 4)
+               rgb = colormapPaletteColor(9, 0);
+       else
+               rgb = SKINCOLOR_TEXT;
+
+       s = me.getPlayerList(me, i, PLAYERPARM_NAME);
+       score = me.getPlayerList(me, i, PLAYERPARM_SCORE);
+
+       if(substring(score, strlen(score) - 10, 10) == ":spectator")
+       {
+               score = _("spectator");
+       }
+       else
+       {
+               if((t = strstrofs(score, ":", 0)) >= 0)
+                       score = substring(score, 0, t);
+               if((t = strstrofs(score, ",", 0)) >= 0)
+                       score = substring(score, 0, t);
+
+               if(stof(score) == -666)
+                       score = _("spectator");
+       }
+
+       s = draw_TextShortenToWidth(s, me.columnNameSize, 1, me.realFontSize);
+       draw_Text(me.realUpperMargin2 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 1, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', 1, 1);
+
+       score = draw_TextShortenToWidth(score, me.columnScoreSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin2 * eY + (me.columnScoreOrigin + 1.00 * (me.columnScoreSize - draw_TextWidth(score, 1, me.realFontSize))) * eX, score, me.realFontSize, rgb, 1, 0);
+}
+
+#endif
diff --git a/qcsrc/menu/xonotic/playermodel.c b/qcsrc/menu/xonotic/playermodel.c
deleted file mode 100644 (file)
index 0a0d6f9..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticPlayerModelSelector) EXTENDS(XonoticImage)
-       METHOD(XonoticPlayerModelSelector, configureXonoticPlayerModelSelector, void(entity))
-       METHOD(XonoticPlayerModelSelector, loadCvars, void(entity))
-       METHOD(XonoticPlayerModelSelector, saveCvars, void(entity))
-       METHOD(XonoticPlayerModelSelector, draw, void(entity))
-       METHOD(XonoticPlayerModelSelector, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticPlayerModelSelector, showNotify, void(entity))
-       ATTRIB(XonoticPlayerModelSelector, currentModel, string, string_null)
-       ATTRIB(XonoticPlayerModelSelector, currentSkin, float, 0)
-       ATTRIB(XonoticPlayerModelSelector, currentModelImage, string, string_null)
-       ATTRIB(XonoticPlayerModelSelector, currentModelTitle, string, string_null)
-       ATTRIB(XonoticPlayerModelSelector, currentModelDescription, string, string_null)
-       METHOD(XonoticPlayerModelSelector, go, void(entity, float))
-       METHOD(XonoticPlayerModelSelector, destroy, void(entity))
-       ATTRIB(XonoticPlayerModelSelector, origin, vector, '0 0 0')
-       ATTRIB(XonoticPlayerModelSelector, size, vector, '0 0 0')
-       ATTRIB(XonoticPlayerModelSelector, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticPlayerModelSelector, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticPlayerModelSelector, titleFontSize, float, SKINFONTSIZE_TITLE)
-       ATTRIB(XonoticPlayerModelSelector, bufModels, float, -1)
-       ATTRIB(XonoticPlayerModelSelector, numModels, float, -1)
-       ATTRIB(XonoticPlayerModelSelector, idxModels, float, -1)
-ENDCLASS(XonoticPlayerModelSelector)
-entity makeXonoticPlayerModelSelector();
-void PlayerModelSelector_Next_Click(entity btn, entity me);
-void PlayerModelSelector_Prev_Click(entity btn, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticPlayerModelSelector()
-{
-       entity me;
-       me = spawnXonoticPlayerModelSelector();
-       me.configureXonoticPlayerModelSelector(me);
-       return me;
-}
-
-const float BUFMODELS_TITLE = 0;
-const float BUFMODELS_IMAGE = 1;
-const float BUFMODELS_MODEL = 2;
-const float BUFMODELS_SKIN = 3;
-const float BUFMODELS_DESC = 4;
-const float BUFMODELS_COUNT = 5;
-
-#define XONVOTE186 1 // (nyov) removal of model text description
-
-void XonoticPlayerModelSelector_configureXonoticPlayerModelSelector(entity me)
-{
-       float sortbuf, glob, i;
-       string fn;
-
-       glob = search_begin(language_filename(get_model_datafilename(string_null, -1, "txt")), TRUE, TRUE);
-       if (glob < 0)
-               return;
-
-       me.configureXonoticImage(me, string_null, -1);
-
-       sortbuf = buf_create();
-       for(i = 0; i < search_getsize(glob); ++i)
-       {
-               // select model #i!
-               fn = search_getfilename(glob, i);
-               if(!get_model_parameters(fn, -1))
-                       continue;
-               bufstr_add(sortbuf, sprintf("%-128s%s", get_model_parameters_name, fn), 1);
-       }
-       search_end(glob);
-       buf_sort(sortbuf, 128, 0);
-       me.numModels = buf_getsize(sortbuf);
-       me.bufModels = buf_create();
-       for(i = 0; i < me.numModels; ++i)
-       {
-               fn = substring(bufstr_get(sortbuf, i), 128, -1);
-               if(!get_model_parameters(fn, -1))
-                       error("But it JUST worked!");
-               bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_TITLE, get_model_parameters_name);
-               bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_IMAGE, strcat("/", substring(get_model_datafilename(get_model_parameters_modelname, get_model_parameters_modelskin, "tga"), 0, -5)));
-               bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_MODEL, get_model_parameters_modelname);
-               bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_SKIN, ftos(get_model_parameters_modelskin));
-               get_model_parameters_desc = strcat(get_model_parameters_desc, "\n");
-#if XONVOTE186
-               if(get_model_parameters_sex)
-                       get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\n%s", get_model_parameters_sex));
-#else
-               if(get_model_parameters_description)
-                       get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\n%s\n", get_model_parameters_description));
-               if(get_model_parameters_sex)
-                       get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\nSex: %s", get_model_parameters_sex));
-               if(get_model_parameters_weight)
-                       get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\nWeight: %g kg", get_model_parameters_weight));
-               if(get_model_parameters_age)
-                       get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\nAge: %g", get_model_parameters_age));
-#endif
-               while(substring(get_model_parameters_desc, -1, 1) == "\n")
-                       get_model_parameters_desc = substring(get_model_parameters_desc, 0, -2);
-               bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_DESC, get_model_parameters_desc);
-       }
-       buf_del(sortbuf);
-       get_model_parameters(string_null, 0);
-       me.loadCvars(me); // this will select the initial model, depending on the current cvars
-       me.go(me, 0); // this will set the vars for the selected model
-}
-void XonoticPlayerModelSelector_destroy(entity me)
-{
-       buf_del(me.bufModels);
-       me.bufModels = -1;
-}
-
-void XonoticPlayerModelSelector_loadCvars(entity me)
-{
-       string skin, modelname;
-       float i;
-
-       skin = cvar_string("_cl_playerskin");
-       modelname = cvar_string("_cl_playermodel");
-
-       for(i = 0; i < me.numModels; ++i)
-       {
-               if(bufstr_get(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_MODEL) == modelname)
-               if(bufstr_get(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_SKIN) == skin)
-                       break;
-       }
-       if(i >= me.numModels) // fail
-               i = 0;
-       me.idxModels = i;
-}
-
-void XonoticPlayerModelSelector_go(entity me, float d)
-{
-       me.idxModels = mod(me.idxModels + d + me.numModels, me.numModels);
-
-       if(me.currentModel)
-               strunzone(me.currentModel);
-       if(me.currentModelTitle)
-               strunzone(me.currentModelTitle);
-       if(me.currentModelImage)
-               strunzone(me.currentModelImage);
-       if(me.currentModelDescription)
-               strunzone(me.currentModelDescription);
-
-       // select model #i!
-       me.currentModelTitle = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_TITLE));
-       me.currentModelImage = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_IMAGE));
-       me.currentSkin = stof(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_SKIN));
-       me.currentModel = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_MODEL));
-       me.currentModelDescription = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_DESC));
-
-       // fix the image
-       if(draw_PictureSize(me.currentModelImage) == '0 0 0')
-               me.src = "nopreview_player";
-       else
-               me.src = me.currentModelImage;
-       me.updateAspect(me);
-}
-
-void PlayerModelSelector_Next_Click(entity btn, entity me)
-{
-       if (me.numModels <= 0)
-               return;
-       me.go(me, +1);
-       me.saveCvars(me);
-}
-
-void PlayerModelSelector_Prev_Click(entity btn, entity me)
-{
-       if (me.numModels <= 0)
-               return;
-       me.go(me, -1);
-       me.saveCvars(me);
-}
-
-void XonoticPlayerModelSelector_saveCvars(entity me)
-{
-       // we can't immediately apply here because of flood control
-       cvar_set("_cl_playermodel", me.currentModel);
-       cvar_set("_cl_playerskin", ftos(me.currentSkin));
-}
-
-void XonoticPlayerModelSelector_draw(entity me)
-{
-       float i, n;
-       vector o;
-
-       if (me.numModels <= 0)
-       {
-               draw_CenterText('0.5 0.5 0', _("<no model found>"), me.realFontSize, SKINCOLOR_TEXT, 0.6, FALSE);
-               return;
-       }
-
-       SUPER(XonoticPlayerModelSelector).draw(me);
-       // draw text on the image, handle \n in the description
-
-       draw_beginBoldFont();
-
-#if XONVOTE186 // (nyov) lower name display looks better when there is no description text
-       draw_CenterText('0.5 0.8 0', me.currentModelTitle, me.realFontSize * (me.titleFontSize / me.fontSize), SKINCOLOR_MODELTITLE, SKINALPHA_MODELTITLE, FALSE);
-#else
-       draw_CenterText('0.5 0 0', me.currentModelTitle, me.realFontSize * (me.titleFontSize / me.fontSize), SKINCOLOR_MODELTITLE, SKINALPHA_MODELTITLE, FALSE);
-#endif
-
-       draw_endBoldFont();
-
-       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, SKINCOLOR_TEXT, 1, FALSE);
-               o += eY * me.realFontSize_y;
-       }
-}
-
-void XonoticPlayerModelSelector_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(XonoticPlayerModelSelector).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       me.realFontSize_y = me.fontSize / absSize_y;
-       me.realFontSize_x = me.fontSize / absSize_x;
-}
-
-void XonoticPlayerModelSelector_showNotify(entity me)
-{
-       me.configureXonoticPlayerModelSelector(me);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/playermodel.qc b/qcsrc/menu/xonotic/playermodel.qc
new file mode 100644 (file)
index 0000000..0a0d6f9
--- /dev/null
@@ -0,0 +1,223 @@
+#ifdef INTERFACE
+CLASS(XonoticPlayerModelSelector) EXTENDS(XonoticImage)
+       METHOD(XonoticPlayerModelSelector, configureXonoticPlayerModelSelector, void(entity))
+       METHOD(XonoticPlayerModelSelector, loadCvars, void(entity))
+       METHOD(XonoticPlayerModelSelector, saveCvars, void(entity))
+       METHOD(XonoticPlayerModelSelector, draw, void(entity))
+       METHOD(XonoticPlayerModelSelector, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticPlayerModelSelector, showNotify, void(entity))
+       ATTRIB(XonoticPlayerModelSelector, currentModel, string, string_null)
+       ATTRIB(XonoticPlayerModelSelector, currentSkin, float, 0)
+       ATTRIB(XonoticPlayerModelSelector, currentModelImage, string, string_null)
+       ATTRIB(XonoticPlayerModelSelector, currentModelTitle, string, string_null)
+       ATTRIB(XonoticPlayerModelSelector, currentModelDescription, string, string_null)
+       METHOD(XonoticPlayerModelSelector, go, void(entity, float))
+       METHOD(XonoticPlayerModelSelector, destroy, void(entity))
+       ATTRIB(XonoticPlayerModelSelector, origin, vector, '0 0 0')
+       ATTRIB(XonoticPlayerModelSelector, size, vector, '0 0 0')
+       ATTRIB(XonoticPlayerModelSelector, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticPlayerModelSelector, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticPlayerModelSelector, titleFontSize, float, SKINFONTSIZE_TITLE)
+       ATTRIB(XonoticPlayerModelSelector, bufModels, float, -1)
+       ATTRIB(XonoticPlayerModelSelector, numModels, float, -1)
+       ATTRIB(XonoticPlayerModelSelector, idxModels, float, -1)
+ENDCLASS(XonoticPlayerModelSelector)
+entity makeXonoticPlayerModelSelector();
+void PlayerModelSelector_Next_Click(entity btn, entity me);
+void PlayerModelSelector_Prev_Click(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticPlayerModelSelector()
+{
+       entity me;
+       me = spawnXonoticPlayerModelSelector();
+       me.configureXonoticPlayerModelSelector(me);
+       return me;
+}
+
+const float BUFMODELS_TITLE = 0;
+const float BUFMODELS_IMAGE = 1;
+const float BUFMODELS_MODEL = 2;
+const float BUFMODELS_SKIN = 3;
+const float BUFMODELS_DESC = 4;
+const float BUFMODELS_COUNT = 5;
+
+#define XONVOTE186 1 // (nyov) removal of model text description
+
+void XonoticPlayerModelSelector_configureXonoticPlayerModelSelector(entity me)
+{
+       float sortbuf, glob, i;
+       string fn;
+
+       glob = search_begin(language_filename(get_model_datafilename(string_null, -1, "txt")), TRUE, TRUE);
+       if (glob < 0)
+               return;
+
+       me.configureXonoticImage(me, string_null, -1);
+
+       sortbuf = buf_create();
+       for(i = 0; i < search_getsize(glob); ++i)
+       {
+               // select model #i!
+               fn = search_getfilename(glob, i);
+               if(!get_model_parameters(fn, -1))
+                       continue;
+               bufstr_add(sortbuf, sprintf("%-128s%s", get_model_parameters_name, fn), 1);
+       }
+       search_end(glob);
+       buf_sort(sortbuf, 128, 0);
+       me.numModels = buf_getsize(sortbuf);
+       me.bufModels = buf_create();
+       for(i = 0; i < me.numModels; ++i)
+       {
+               fn = substring(bufstr_get(sortbuf, i), 128, -1);
+               if(!get_model_parameters(fn, -1))
+                       error("But it JUST worked!");
+               bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_TITLE, get_model_parameters_name);
+               bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_IMAGE, strcat("/", substring(get_model_datafilename(get_model_parameters_modelname, get_model_parameters_modelskin, "tga"), 0, -5)));
+               bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_MODEL, get_model_parameters_modelname);
+               bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_SKIN, ftos(get_model_parameters_modelskin));
+               get_model_parameters_desc = strcat(get_model_parameters_desc, "\n");
+#if XONVOTE186
+               if(get_model_parameters_sex)
+                       get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\n%s", get_model_parameters_sex));
+#else
+               if(get_model_parameters_description)
+                       get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\n%s\n", get_model_parameters_description));
+               if(get_model_parameters_sex)
+                       get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\nSex: %s", get_model_parameters_sex));
+               if(get_model_parameters_weight)
+                       get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\nWeight: %g kg", get_model_parameters_weight));
+               if(get_model_parameters_age)
+                       get_model_parameters_desc = strcat(get_model_parameters_desc, sprintf("\nAge: %g", get_model_parameters_age));
+#endif
+               while(substring(get_model_parameters_desc, -1, 1) == "\n")
+                       get_model_parameters_desc = substring(get_model_parameters_desc, 0, -2);
+               bufstr_set(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_DESC, get_model_parameters_desc);
+       }
+       buf_del(sortbuf);
+       get_model_parameters(string_null, 0);
+       me.loadCvars(me); // this will select the initial model, depending on the current cvars
+       me.go(me, 0); // this will set the vars for the selected model
+}
+void XonoticPlayerModelSelector_destroy(entity me)
+{
+       buf_del(me.bufModels);
+       me.bufModels = -1;
+}
+
+void XonoticPlayerModelSelector_loadCvars(entity me)
+{
+       string skin, modelname;
+       float i;
+
+       skin = cvar_string("_cl_playerskin");
+       modelname = cvar_string("_cl_playermodel");
+
+       for(i = 0; i < me.numModels; ++i)
+       {
+               if(bufstr_get(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_MODEL) == modelname)
+               if(bufstr_get(me.bufModels, BUFMODELS_COUNT*i+BUFMODELS_SKIN) == skin)
+                       break;
+       }
+       if(i >= me.numModels) // fail
+               i = 0;
+       me.idxModels = i;
+}
+
+void XonoticPlayerModelSelector_go(entity me, float d)
+{
+       me.idxModels = mod(me.idxModels + d + me.numModels, me.numModels);
+
+       if(me.currentModel)
+               strunzone(me.currentModel);
+       if(me.currentModelTitle)
+               strunzone(me.currentModelTitle);
+       if(me.currentModelImage)
+               strunzone(me.currentModelImage);
+       if(me.currentModelDescription)
+               strunzone(me.currentModelDescription);
+
+       // select model #i!
+       me.currentModelTitle = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_TITLE));
+       me.currentModelImage = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_IMAGE));
+       me.currentSkin = stof(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_SKIN));
+       me.currentModel = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_MODEL));
+       me.currentModelDescription = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_DESC));
+
+       // fix the image
+       if(draw_PictureSize(me.currentModelImage) == '0 0 0')
+               me.src = "nopreview_player";
+       else
+               me.src = me.currentModelImage;
+       me.updateAspect(me);
+}
+
+void PlayerModelSelector_Next_Click(entity btn, entity me)
+{
+       if (me.numModels <= 0)
+               return;
+       me.go(me, +1);
+       me.saveCvars(me);
+}
+
+void PlayerModelSelector_Prev_Click(entity btn, entity me)
+{
+       if (me.numModels <= 0)
+               return;
+       me.go(me, -1);
+       me.saveCvars(me);
+}
+
+void XonoticPlayerModelSelector_saveCvars(entity me)
+{
+       // we can't immediately apply here because of flood control
+       cvar_set("_cl_playermodel", me.currentModel);
+       cvar_set("_cl_playerskin", ftos(me.currentSkin));
+}
+
+void XonoticPlayerModelSelector_draw(entity me)
+{
+       float i, n;
+       vector o;
+
+       if (me.numModels <= 0)
+       {
+               draw_CenterText('0.5 0.5 0', _("<no model found>"), me.realFontSize, SKINCOLOR_TEXT, 0.6, FALSE);
+               return;
+       }
+
+       SUPER(XonoticPlayerModelSelector).draw(me);
+       // draw text on the image, handle \n in the description
+
+       draw_beginBoldFont();
+
+#if XONVOTE186 // (nyov) lower name display looks better when there is no description text
+       draw_CenterText('0.5 0.8 0', me.currentModelTitle, me.realFontSize * (me.titleFontSize / me.fontSize), SKINCOLOR_MODELTITLE, SKINALPHA_MODELTITLE, FALSE);
+#else
+       draw_CenterText('0.5 0 0', me.currentModelTitle, me.realFontSize * (me.titleFontSize / me.fontSize), SKINCOLOR_MODELTITLE, SKINALPHA_MODELTITLE, FALSE);
+#endif
+
+       draw_endBoldFont();
+
+       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, SKINCOLOR_TEXT, 1, FALSE);
+               o += eY * me.realFontSize_y;
+       }
+}
+
+void XonoticPlayerModelSelector_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(XonoticPlayerModelSelector).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+       me.realFontSize_y = me.fontSize / absSize_y;
+       me.realFontSize_x = me.fontSize / absSize_x;
+}
+
+void XonoticPlayerModelSelector_showNotify(entity me)
+{
+       me.configureXonoticPlayerModelSelector(me);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/playlist.c b/qcsrc/menu/xonotic/playlist.c
deleted file mode 100644 (file)
index e918ada..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticPlayList) EXTENDS(XonoticListBox)
-       METHOD(XonoticPlayList, configureXonoticPlayList, void(entity))
-       ATTRIB(XonoticPlayList, rowsPerItem, float, 1)
-       METHOD(XonoticPlayList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticPlayList, draw, void(entity))
-       METHOD(XonoticPlayList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticPlayList, stopSound, void(entity))
-       METHOD(XonoticPlayList, startSound, void(entity, float))
-       METHOD(XonoticPlayList, resumeSound, void(entity))
-       METHOD(XonoticPlayList, pauseSound, void(entity))
-       METHOD(XonoticPlayList, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticPlayList, keyDown, float(entity, float, float, float))
-       METHOD(XonoticPlayList, mouseDrag, float(entity, vector))
-
-       METHOD(XonoticPlayList, addToPlayList, void(entity, string))
-       METHOD(XonoticPlayList, removeSelectedFromPlayList, void(entity))
-       ATTRIB(XonoticPlayList, playingTrack, float, -1)
-
-       ATTRIB(XonoticPlayList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticPlayList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticPlayList, columnNameSize, float, 0)
-       ATTRIB(XonoticPlayList, columnNumberOrigin, float, 0)
-       ATTRIB(XonoticPlayList, columnNumberSize, float, 0)
-       ATTRIB(XonoticPlayList, realUpperMargin, float, 0)
-       ATTRIB(XonoticPlayList, origin, vector, '0 0 0')
-       ATTRIB(XonoticPlayList, itemAbsSize, vector, '0 0 0')
-ENDCLASS(XonoticPlayList)
-
-entity makeXonoticPlayList();
-void PlayList_Remove(entity btn, entity me);
-void PlayList_Remove_All(entity btn, entity me);
-void StopSound_Click(entity btn, entity me);
-void StartSound_Click(entity btn, entity me);
-void PauseSound_Click(entity btn, entity me);
-void PrevSound_Click(entity btn, entity me);
-void NextSound_Click(entity btn, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-
-entity makeXonoticPlayList()
-{
-       entity me;
-       me = spawnXonoticPlayList();
-       me.configureXonoticPlayList(me);
-       return me;
-}
-
-void XonoticPlayList_configureXonoticPlayList(entity me)
-{
-       me.nItems = tokenize_console(cvar_string("music_playlist_list0"));
-       me.configureXonoticListBox(me);
-}
-
-void XonoticPlayList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemAbsSize = '0 0 0';
-       SUPER(XonoticPlayList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
-
-       me.columnNumberOrigin = 0;
-       me.columnNumberSize = 3 * me.realFontSize_x;
-
-       me.columnNameOrigin = me.columnNumberSize + me.realFontSize_x;
-       me.columnNameSize = 1 - me.columnNameOrigin - me.realFontSize_x;
-}
-
-void XonoticPlayList_addToPlayList(entity me, string track)
-{
-       me.nItems = tokenize_console(cvar_string("music_playlist_list0"));
-       if(me.nItems == 0)
-       {
-               cvar_set("music_playlist_list0", track);
-               return;
-       }
-       float i;
-       for(i = 0; i < me.nItems; ++i)
-       {
-               if(argv(i) == track)
-                       return; // track is already in playlist
-       }
-       cvar_set("music_playlist_list0", strcat(cvar_string("music_playlist_list0"), " ", track));
-}
-
-void XonoticPlayList_removeSelectedFromPlayList(entity me)
-{
-       float i, cpt = FALSE;
-       string s = "";
-       me.nItems = tokenize_console(cvar_string("music_playlist_list0"));
-       if(me.nItems == 0)
-               return;
-       for(i = 0; i < me.nItems; ++i)
-       {
-               if(i == me.selectedItem)
-               {
-                       if(i == me.nItems - 1)
-                               me.setSelected(me, me.selectedItem - 1);
-                       if(cvar("music_playlist_index") == 0 || cvar("music_playlist_index") == 999)
-                       {
-                               if(cvar("music_playlist_current0") == i)
-                                       cpt = TRUE; // current playing track (we can't start next track here because startSound calls tokenize_console)
-                               else if(cvar("music_playlist_current0") > i)
-                                       cvar_set("music_playlist_current0", ftos(cvar("music_playlist_current0") - 1));
-                       }
-                       continue;
-               }
-               s = strcat(s, " ", argv(i));
-       }
-       // we must stop the current playing track if it has been removed
-       // otherwise pause/play button will resume from another track
-       if(s == "")
-       {
-               cvar_set("music_playlist_list0", "");
-               if(cpt)
-                       me.stopSound(me);
-       }
-       else
-       {
-               cvar_set("music_playlist_list0", substring(s, 1, strlen(s))); // remove initial space
-               if(cpt)
-                       me.startSound(me, 0);
-       }
-}
-
-void PlayList_Remove(entity btn, entity me)
-{
-       me.removeSelectedFromPlayList(me);
-}
-
-void PlayList_Remove_All(entity btn, entity me)
-{
-       cvar_set("music_playlist_list0", "");
-       me.stopSound(me);
-       me.selectedItem = 0;
-}
-
-float XonoticPlayList_mouseDrag(entity me, vector pos)
-{
-       float f, i;
-       i = me.selectedItem;
-       f = SUPER(XonoticPlayList).mouseDrag(me, pos);
-
-       if(me.pressed != 1) // don't change priority if the person is just scrolling
-       {
-               if(me.selectedItem != i)
-               {
-                       cvar_set("music_playlist_list0", swapInPriorityList(cvar_string("music_playlist_list0"), me.selectedItem, i));
-                       float c = cvar("music_playlist_current0");
-                       if(c == i)
-                               cvar_set("music_playlist_current0", ftos(me.selectedItem));
-                       else if(c == me.selectedItem)
-                               cvar_set("music_playlist_current0", ftos(i));
-               }
-       }
-
-       return f;
-}
-
-void XonoticPlayList_draw(entity me)
-{
-       me.nItems = tokenize_console(cvar_string("music_playlist_list0"));
-       if(cvar("music_playlist_index") == 0 || cvar("music_playlist_index") == 999)
-               me.playingTrack = cvar("music_playlist_current0");
-       else
-               me.playingTrack = -1;
-       SUPER(XonoticPlayList).draw(me);
-}
-
-void XonoticPlayList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string s;
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-
-       if(i == me.playingTrack)
-       {
-               float f = cvar("music_playlist_sampleposition0");
-               if(f <= 0 || (((time * 2) & 1) && f > 0))
-                       draw_Text(me.realUpperMargin * eY + (me.columnNumberOrigin + me.columnNumberSize) * eX, "\xE2\x96\xB6", me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
-       }
-
-       s = ftos(i+1);
-       draw_CenterText(me.realUpperMargin * eY + (me.columnNumberOrigin + 0.5 * me.columnNumberSize) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
-
-       s = draw_TextShortenToWidth(argv(i), me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
-}
-
-void XonoticPlayList_stopSound(entity me)
-{
-       // STOP: list 0 is disabled by setting the index to -1
-       // we set sampleposition0 to 0 to forget the position that the engine saves in this frame (for this reason we need to wait a frame)
-       if(cvar("music_playlist_index") == 0 || cvar("music_playlist_index") == 999)
-       {
-               cvar_set("music_playlist_index", "-1");
-               localcmd("\nwait; music_playlist_sampleposition0 0\n");
-               localcmd("\ndefer 3 \"cd play $menu_cdtrack\"\n");
-       }
-}
-
-void StopSound_Click(entity btn, entity me)
-{
-       me.stopSound(me);
-}
-
-void XonoticPlayList_startSound(entity me, float offset)
-{
-       float f;
-       me.nItems = tokenize_console(cvar_string("music_playlist_list0"));
-       if(offset)
-       {
-               if(cvar("music_playlist_index") == -1)
-                       return;
-               f = bound(0, cvar("music_playlist_current0") + offset, me.nItems - 1);
-               if(f == cvar("music_playlist_current0"))
-                       return;
-       }
-       else
-       {
-               f = me.selectedItem;
-               // if it was paused then resume
-               if(f == cvar("music_playlist_current0"))
-               if(cvar("music_playlist_index") == 999)
-               {
-                       me.resumeSound(me);
-                       return;
-               }
-               // if it was not paused then proceed with restart
-       }
-
-       // START: list 0 is disabled by setting the index to 999
-       // we set current0 to the selected track and sampleposition0 to 0 to forget the position that the engine saves in this frame (for this reason we need to wait a frame)
-       // then we switch back to list 0
-       cvar_set("music_playlist_index", "999");
-       cvar_set("music_playlist_current0", ftos(f));
-       localcmd("\nwait; music_playlist_sampleposition0 0; wait; music_playlist_index 0\n");
-}
-
-void StartSound_Click(entity btn, entity me)
-{
-       me.startSound(me, 0);
-}
-
-void PrevSound_Click(entity btn, entity me)
-{
-       me.startSound(me, -1);
-}
-
-void NextSound_Click(entity btn, entity me)
-{
-       me.startSound(me, +1);
-}
-
-void XonoticPlayList_resumeSound(entity me)
-{
-       // RESUME: list 0 is enabled by setting the index to 0
-       // (we reset sampleposition0 to 0 to mark the track as in playing back state)
-       if(cvar("music_playlist_index") == 999)
-               localcmd("\nmusic_playlist_index 0; wait; music_playlist_sampleposition0 0\n");
-}
-void XonoticPlayList_pauseSound(entity me)
-{
-       // PAUSE: list 0 is disabled by setting the index to 999
-       // (we know the track is paused because the engine sets sampleposition0 to remember current position)
-       if(cvar("music_playlist_index") == 0)
-               localcmd("\nmusic_playlist_index 999\n");
-       else me.resumeSound(me);
-}
-
-void PauseSound_Click(entity btn, entity me)
-{
-       me.pauseSound(me);
-}
-
-void XonoticPlayList_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       me.startSound(me, 0);
-}
-
-float XonoticPlayList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if(scan == K_ENTER || scan == K_KP_ENTER) {
-               me.startSound(me, 0);
-               return 1;
-       }
-       else if(scan == K_SPACE) {
-               me.pauseSound(me);
-               return 1;
-       }
-       else if(scan == K_DEL || scan == K_KP_DEL || scan == K_BACKSPACE || scan == K_MOUSE3) {
-               me.removeSelectedFromPlayList(me);
-               return 1;
-       }
-       else
-               return SUPER(XonoticPlayList).keyDown(me, scan, ascii, shift);
-}
-#endif
-
diff --git a/qcsrc/menu/xonotic/playlist.qc b/qcsrc/menu/xonotic/playlist.qc
new file mode 100644 (file)
index 0000000..e918ada
--- /dev/null
@@ -0,0 +1,302 @@
+#ifdef INTERFACE
+CLASS(XonoticPlayList) EXTENDS(XonoticListBox)
+       METHOD(XonoticPlayList, configureXonoticPlayList, void(entity))
+       ATTRIB(XonoticPlayList, rowsPerItem, float, 1)
+       METHOD(XonoticPlayList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticPlayList, draw, void(entity))
+       METHOD(XonoticPlayList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticPlayList, stopSound, void(entity))
+       METHOD(XonoticPlayList, startSound, void(entity, float))
+       METHOD(XonoticPlayList, resumeSound, void(entity))
+       METHOD(XonoticPlayList, pauseSound, void(entity))
+       METHOD(XonoticPlayList, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticPlayList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticPlayList, mouseDrag, float(entity, vector))
+
+       METHOD(XonoticPlayList, addToPlayList, void(entity, string))
+       METHOD(XonoticPlayList, removeSelectedFromPlayList, void(entity))
+       ATTRIB(XonoticPlayList, playingTrack, float, -1)
+
+       ATTRIB(XonoticPlayList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticPlayList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticPlayList, columnNameSize, float, 0)
+       ATTRIB(XonoticPlayList, columnNumberOrigin, float, 0)
+       ATTRIB(XonoticPlayList, columnNumberSize, float, 0)
+       ATTRIB(XonoticPlayList, realUpperMargin, float, 0)
+       ATTRIB(XonoticPlayList, origin, vector, '0 0 0')
+       ATTRIB(XonoticPlayList, itemAbsSize, vector, '0 0 0')
+ENDCLASS(XonoticPlayList)
+
+entity makeXonoticPlayList();
+void PlayList_Remove(entity btn, entity me);
+void PlayList_Remove_All(entity btn, entity me);
+void StopSound_Click(entity btn, entity me);
+void StartSound_Click(entity btn, entity me);
+void PauseSound_Click(entity btn, entity me);
+void PrevSound_Click(entity btn, entity me);
+void NextSound_Click(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeXonoticPlayList()
+{
+       entity me;
+       me = spawnXonoticPlayList();
+       me.configureXonoticPlayList(me);
+       return me;
+}
+
+void XonoticPlayList_configureXonoticPlayList(entity me)
+{
+       me.nItems = tokenize_console(cvar_string("music_playlist_list0"));
+       me.configureXonoticListBox(me);
+}
+
+void XonoticPlayList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticPlayList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+
+       me.columnNumberOrigin = 0;
+       me.columnNumberSize = 3 * me.realFontSize_x;
+
+       me.columnNameOrigin = me.columnNumberSize + me.realFontSize_x;
+       me.columnNameSize = 1 - me.columnNameOrigin - me.realFontSize_x;
+}
+
+void XonoticPlayList_addToPlayList(entity me, string track)
+{
+       me.nItems = tokenize_console(cvar_string("music_playlist_list0"));
+       if(me.nItems == 0)
+       {
+               cvar_set("music_playlist_list0", track);
+               return;
+       }
+       float i;
+       for(i = 0; i < me.nItems; ++i)
+       {
+               if(argv(i) == track)
+                       return; // track is already in playlist
+       }
+       cvar_set("music_playlist_list0", strcat(cvar_string("music_playlist_list0"), " ", track));
+}
+
+void XonoticPlayList_removeSelectedFromPlayList(entity me)
+{
+       float i, cpt = FALSE;
+       string s = "";
+       me.nItems = tokenize_console(cvar_string("music_playlist_list0"));
+       if(me.nItems == 0)
+               return;
+       for(i = 0; i < me.nItems; ++i)
+       {
+               if(i == me.selectedItem)
+               {
+                       if(i == me.nItems - 1)
+                               me.setSelected(me, me.selectedItem - 1);
+                       if(cvar("music_playlist_index") == 0 || cvar("music_playlist_index") == 999)
+                       {
+                               if(cvar("music_playlist_current0") == i)
+                                       cpt = TRUE; // current playing track (we can't start next track here because startSound calls tokenize_console)
+                               else if(cvar("music_playlist_current0") > i)
+                                       cvar_set("music_playlist_current0", ftos(cvar("music_playlist_current0") - 1));
+                       }
+                       continue;
+               }
+               s = strcat(s, " ", argv(i));
+       }
+       // we must stop the current playing track if it has been removed
+       // otherwise pause/play button will resume from another track
+       if(s == "")
+       {
+               cvar_set("music_playlist_list0", "");
+               if(cpt)
+                       me.stopSound(me);
+       }
+       else
+       {
+               cvar_set("music_playlist_list0", substring(s, 1, strlen(s))); // remove initial space
+               if(cpt)
+                       me.startSound(me, 0);
+       }
+}
+
+void PlayList_Remove(entity btn, entity me)
+{
+       me.removeSelectedFromPlayList(me);
+}
+
+void PlayList_Remove_All(entity btn, entity me)
+{
+       cvar_set("music_playlist_list0", "");
+       me.stopSound(me);
+       me.selectedItem = 0;
+}
+
+float XonoticPlayList_mouseDrag(entity me, vector pos)
+{
+       float f, i;
+       i = me.selectedItem;
+       f = SUPER(XonoticPlayList).mouseDrag(me, pos);
+
+       if(me.pressed != 1) // don't change priority if the person is just scrolling
+       {
+               if(me.selectedItem != i)
+               {
+                       cvar_set("music_playlist_list0", swapInPriorityList(cvar_string("music_playlist_list0"), me.selectedItem, i));
+                       float c = cvar("music_playlist_current0");
+                       if(c == i)
+                               cvar_set("music_playlist_current0", ftos(me.selectedItem));
+                       else if(c == me.selectedItem)
+                               cvar_set("music_playlist_current0", ftos(i));
+               }
+       }
+
+       return f;
+}
+
+void XonoticPlayList_draw(entity me)
+{
+       me.nItems = tokenize_console(cvar_string("music_playlist_list0"));
+       if(cvar("music_playlist_index") == 0 || cvar("music_playlist_index") == 999)
+               me.playingTrack = cvar("music_playlist_current0");
+       else
+               me.playingTrack = -1;
+       SUPER(XonoticPlayList).draw(me);
+}
+
+void XonoticPlayList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s;
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       if(i == me.playingTrack)
+       {
+               float f = cvar("music_playlist_sampleposition0");
+               if(f <= 0 || (((time * 2) & 1) && f > 0))
+                       draw_Text(me.realUpperMargin * eY + (me.columnNumberOrigin + me.columnNumberSize) * eX, "\xE2\x96\xB6", me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+       }
+
+       s = ftos(i+1);
+       draw_CenterText(me.realUpperMargin * eY + (me.columnNumberOrigin + 0.5 * me.columnNumberSize) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+
+       s = draw_TextShortenToWidth(argv(i), me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+}
+
+void XonoticPlayList_stopSound(entity me)
+{
+       // STOP: list 0 is disabled by setting the index to -1
+       // we set sampleposition0 to 0 to forget the position that the engine saves in this frame (for this reason we need to wait a frame)
+       if(cvar("music_playlist_index") == 0 || cvar("music_playlist_index") == 999)
+       {
+               cvar_set("music_playlist_index", "-1");
+               localcmd("\nwait; music_playlist_sampleposition0 0\n");
+               localcmd("\ndefer 3 \"cd play $menu_cdtrack\"\n");
+       }
+}
+
+void StopSound_Click(entity btn, entity me)
+{
+       me.stopSound(me);
+}
+
+void XonoticPlayList_startSound(entity me, float offset)
+{
+       float f;
+       me.nItems = tokenize_console(cvar_string("music_playlist_list0"));
+       if(offset)
+       {
+               if(cvar("music_playlist_index") == -1)
+                       return;
+               f = bound(0, cvar("music_playlist_current0") + offset, me.nItems - 1);
+               if(f == cvar("music_playlist_current0"))
+                       return;
+       }
+       else
+       {
+               f = me.selectedItem;
+               // if it was paused then resume
+               if(f == cvar("music_playlist_current0"))
+               if(cvar("music_playlist_index") == 999)
+               {
+                       me.resumeSound(me);
+                       return;
+               }
+               // if it was not paused then proceed with restart
+       }
+
+       // START: list 0 is disabled by setting the index to 999
+       // we set current0 to the selected track and sampleposition0 to 0 to forget the position that the engine saves in this frame (for this reason we need to wait a frame)
+       // then we switch back to list 0
+       cvar_set("music_playlist_index", "999");
+       cvar_set("music_playlist_current0", ftos(f));
+       localcmd("\nwait; music_playlist_sampleposition0 0; wait; music_playlist_index 0\n");
+}
+
+void StartSound_Click(entity btn, entity me)
+{
+       me.startSound(me, 0);
+}
+
+void PrevSound_Click(entity btn, entity me)
+{
+       me.startSound(me, -1);
+}
+
+void NextSound_Click(entity btn, entity me)
+{
+       me.startSound(me, +1);
+}
+
+void XonoticPlayList_resumeSound(entity me)
+{
+       // RESUME: list 0 is enabled by setting the index to 0
+       // (we reset sampleposition0 to 0 to mark the track as in playing back state)
+       if(cvar("music_playlist_index") == 999)
+               localcmd("\nmusic_playlist_index 0; wait; music_playlist_sampleposition0 0\n");
+}
+void XonoticPlayList_pauseSound(entity me)
+{
+       // PAUSE: list 0 is disabled by setting the index to 999
+       // (we know the track is paused because the engine sets sampleposition0 to remember current position)
+       if(cvar("music_playlist_index") == 0)
+               localcmd("\nmusic_playlist_index 999\n");
+       else me.resumeSound(me);
+}
+
+void PauseSound_Click(entity btn, entity me)
+{
+       me.pauseSound(me);
+}
+
+void XonoticPlayList_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       me.startSound(me, 0);
+}
+
+float XonoticPlayList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_KP_ENTER) {
+               me.startSound(me, 0);
+               return 1;
+       }
+       else if(scan == K_SPACE) {
+               me.pauseSound(me);
+               return 1;
+       }
+       else if(scan == K_DEL || scan == K_KP_DEL || scan == K_BACKSPACE || scan == K_MOUSE3) {
+               me.removeSelectedFromPlayList(me);
+               return 1;
+       }
+       else
+               return SUPER(XonoticPlayList).keyDown(me, scan, ascii, shift);
+}
+#endif
+
diff --git a/qcsrc/menu/xonotic/radiobutton.c b/qcsrc/menu/xonotic/radiobutton.c
deleted file mode 100644 (file)
index 85cc4fc..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticRadioButton) EXTENDS(RadioButton)
-       METHOD(XonoticRadioButton, configureXonoticRadioButton, void(entity, float, string, string, string))
-       METHOD(XonoticRadioButton, draw, void(entity))
-       METHOD(XonoticRadioButton, setChecked, void(entity, float))
-       ATTRIB(XonoticRadioButton, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticRadioButton, image, string, SKINGFX_RADIOBUTTON)
-       ATTRIB(XonoticRadioButton, color, vector, SKINCOLOR_RADIOBUTTON_N)
-       ATTRIB(XonoticRadioButton, colorC, vector, SKINCOLOR_RADIOBUTTON_C)
-       ATTRIB(XonoticRadioButton, colorF, vector, SKINCOLOR_RADIOBUTTON_F)
-       ATTRIB(XonoticRadioButton, colorD, vector, SKINCOLOR_RADIOBUTTON_D)
-
-       ATTRIB(XonoticRadioButton, cvarName, string, string_null)
-       ATTRIB(XonoticRadioButton, cvarValue, string, string_null)
-       ATTRIB(XonoticRadioButton, cvarOffValue, string, string_null)
-       ATTRIB(XonoticRadioButton, getCvarValueFromCvar, float, 0)
-       METHOD(XonoticRadioButton, loadCvars, void(entity))
-       METHOD(XonoticRadioButton, saveCvars, void(entity))
-
-       ATTRIB(XonoticRadioButton, alpha, float, SKINALPHA_TEXT)
-       ATTRIB(XonoticRadioButton, disabledAlpha, float, SKINALPHA_DISABLED)
-ENDCLASS(XonoticRadioButton)
-entity makeXonoticRadioButton(float, string, string, string);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticRadioButton(float theGroup, string theCvar, string theValue, string theText)
-{
-       entity me;
-       me = spawnXonoticRadioButton();
-       me.configureXonoticRadioButton(me, theGroup, theCvar, theValue, theText);
-       return me;
-}
-void XonoticRadioButton_configureXonoticRadioButton(entity me, float theGroup, string theCvar, string theValue, string theText)
-{
-       if(theCvar)
-       {
-               me.cvarName = theCvar;
-               me.cvarValue = theValue;
-               me.tooltip = getZonedTooltipForIdentifier(theCvar);
-               me.loadCvars(me);
-       }
-       me.configureRadioButton(me, theText, me.fontSize, me.image, theGroup, 0);
-}
-void XonoticRadioButton_setChecked(entity me, float val)
-{
-       if(val != me.checked)
-       {
-               me.checked = val;
-               me.saveCvars(me);
-       }
-}
-void XonoticRadioButton_loadCvars(entity me)
-{
-       if(me.cvarValue)
-       {
-               if(me.cvarName)
-                       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 XonoticRadioButton_draw(entity me)
-{
-       if (!me.cvarValue)
-               if (!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);
-               }
-       SUPER(XonoticRadioButton).draw(me);
-}
-void XonoticRadioButton_saveCvars(entity me)
-{
-       if(me.cvarValue)
-       {
-               if(me.cvarName)
-               {
-                       if(me.checked)
-                       {
-                               if(me.getCvarValueFromCvar)
-                                       cvar_set(me.cvarName, cvar_string(me.cvarValue));
-                               else
-                                       cvar_set(me.cvarName, me.cvarValue);
-                       }
-                       else if(me.cvarOffValue)
-                               cvar_set(me.cvarName, me.cvarOffValue);
-               }
-       }
-       else
-       {
-               if(me.cvarName)
-               {
-                       cvar_set(me.cvarName, ftos(me.checked));
-               }
-       }
-}
-#endif
diff --git a/qcsrc/menu/xonotic/radiobutton.qc b/qcsrc/menu/xonotic/radiobutton.qc
new file mode 100644 (file)
index 0000000..85cc4fc
--- /dev/null
@@ -0,0 +1,120 @@
+#ifdef INTERFACE
+CLASS(XonoticRadioButton) EXTENDS(RadioButton)
+       METHOD(XonoticRadioButton, configureXonoticRadioButton, void(entity, float, string, string, string))
+       METHOD(XonoticRadioButton, draw, void(entity))
+       METHOD(XonoticRadioButton, setChecked, void(entity, float))
+       ATTRIB(XonoticRadioButton, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticRadioButton, image, string, SKINGFX_RADIOBUTTON)
+       ATTRIB(XonoticRadioButton, color, vector, SKINCOLOR_RADIOBUTTON_N)
+       ATTRIB(XonoticRadioButton, colorC, vector, SKINCOLOR_RADIOBUTTON_C)
+       ATTRIB(XonoticRadioButton, colorF, vector, SKINCOLOR_RADIOBUTTON_F)
+       ATTRIB(XonoticRadioButton, colorD, vector, SKINCOLOR_RADIOBUTTON_D)
+
+       ATTRIB(XonoticRadioButton, cvarName, string, string_null)
+       ATTRIB(XonoticRadioButton, cvarValue, string, string_null)
+       ATTRIB(XonoticRadioButton, cvarOffValue, string, string_null)
+       ATTRIB(XonoticRadioButton, getCvarValueFromCvar, float, 0)
+       METHOD(XonoticRadioButton, loadCvars, void(entity))
+       METHOD(XonoticRadioButton, saveCvars, void(entity))
+
+       ATTRIB(XonoticRadioButton, alpha, float, SKINALPHA_TEXT)
+       ATTRIB(XonoticRadioButton, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(XonoticRadioButton)
+entity makeXonoticRadioButton(float, string, string, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticRadioButton(float theGroup, string theCvar, string theValue, string theText)
+{
+       entity me;
+       me = spawnXonoticRadioButton();
+       me.configureXonoticRadioButton(me, theGroup, theCvar, theValue, theText);
+       return me;
+}
+void XonoticRadioButton_configureXonoticRadioButton(entity me, float theGroup, string theCvar, string theValue, string theText)
+{
+       if(theCvar)
+       {
+               me.cvarName = theCvar;
+               me.cvarValue = theValue;
+               me.tooltip = getZonedTooltipForIdentifier(theCvar);
+               me.loadCvars(me);
+       }
+       me.configureRadioButton(me, theText, me.fontSize, me.image, theGroup, 0);
+}
+void XonoticRadioButton_setChecked(entity me, float val)
+{
+       if(val != me.checked)
+       {
+               me.checked = val;
+               me.saveCvars(me);
+       }
+}
+void XonoticRadioButton_loadCvars(entity me)
+{
+       if(me.cvarValue)
+       {
+               if(me.cvarName)
+                       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 XonoticRadioButton_draw(entity me)
+{
+       if (!me.cvarValue)
+               if (!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);
+               }
+       SUPER(XonoticRadioButton).draw(me);
+}
+void XonoticRadioButton_saveCvars(entity me)
+{
+       if(me.cvarValue)
+       {
+               if(me.cvarName)
+               {
+                       if(me.checked)
+                       {
+                               if(me.getCvarValueFromCvar)
+                                       cvar_set(me.cvarName, cvar_string(me.cvarValue));
+                               else
+                                       cvar_set(me.cvarName, me.cvarValue);
+                       }
+                       else if(me.cvarOffValue)
+                               cvar_set(me.cvarName, me.cvarOffValue);
+               }
+       }
+       else
+       {
+               if(me.cvarName)
+               {
+                       cvar_set(me.cvarName, ftos(me.checked));
+               }
+       }
+}
+#endif
diff --git a/qcsrc/menu/xonotic/rootdialog.c b/qcsrc/menu/xonotic/rootdialog.c
deleted file mode 100644 (file)
index e8c9db3..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticRootDialog) EXTENDS(XonoticDialog)
-       // still to be customized by user
-       /*
-       ATTRIB(XonoticDialog, closable, float, 1)
-       ATTRIB(XonoticDialog, title, string, _("Form1")) // ;)
-       ATTRIB(XonoticDialog, color, vector, '1 0.5 1')
-       ATTRIB(XonoticDialog, intendedWidth, float, 0)
-       ATTRIB(XonoticDialog, rows, float, 3)
-       ATTRIB(XonoticDialog, columns, float, 2)
-       */
-       METHOD(XonoticRootDialog, close, void(entity))
-ENDCLASS(XonoticRootDialog)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticRootDialog_close(entity me)
-{
-       m_goto(string_null);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/rootdialog.qc b/qcsrc/menu/xonotic/rootdialog.qc
new file mode 100644 (file)
index 0000000..e8c9db3
--- /dev/null
@@ -0,0 +1,21 @@
+#ifdef INTERFACE
+CLASS(XonoticRootDialog) EXTENDS(XonoticDialog)
+       // still to be customized by user
+       /*
+       ATTRIB(XonoticDialog, closable, float, 1)
+       ATTRIB(XonoticDialog, title, string, _("Form1")) // ;)
+       ATTRIB(XonoticDialog, color, vector, '1 0.5 1')
+       ATTRIB(XonoticDialog, intendedWidth, float, 0)
+       ATTRIB(XonoticDialog, rows, float, 3)
+       ATTRIB(XonoticDialog, columns, float, 2)
+       */
+       METHOD(XonoticRootDialog, close, void(entity))
+ENDCLASS(XonoticRootDialog)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticRootDialog_close(entity me)
+{
+       m_goto(string_null);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/screenshotimage.c b/qcsrc/menu/xonotic/screenshotimage.c
deleted file mode 100644 (file)
index 469f177..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticScreenshotImage) EXTENDS(XonoticImage)
-       METHOD(XonoticScreenshotImage, configureXonoticScreenshotImage, void(entity))
-       METHOD(XonoticScreenshotImage, load, void(entity, string))
-       METHOD(XonoticScreenshotImage, draw, void(entity))
-       ATTRIB(XonoticScreenshotImage, focusable, float, 1) // mousePress and mouseDrag work only if focusable is set
-       METHOD(XonoticScreenshotImage, mousePress, float(entity, vector))
-       METHOD(XonoticScreenshotImage, mouseDrag, float(entity, vector))
-       METHOD(XonoticScreenshotImage, mouseMove, float(entity, vector))
-       METHOD(XonoticScreenshotImage, resizeNotify, void(entity, vector, vector, vector, vector))
-       ATTRIB(XonoticScreenshotImage, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticScreenshotImage, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticScreenshotImage, showTitle, float, 1)
-       ATTRIB(XonoticScreenshotImage, screenshotTime, float, 0)
-       ATTRIB(XonoticScreenshotImage, screenshotTitle, string, string_null)
-ENDCLASS(XonoticScreenshotImage)
-entity makeXonoticScreenshotImage();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticScreenshotImage()
-{
-       entity me;
-       me = spawnXonoticScreenshotImage();
-       me.configureXonoticScreenshotImage(me);
-       return me;
-}
-
-void XonoticScreenshotImage_configureXonoticScreenshotImage(entity me)
-{
-       me.configureXonoticImage(me, string_null, -2);
-       me.zoomLimitedByTheBox = FALSE; // enable this to forbid enlarging the image more than the containing box (if making use of draw_SetClip is a too bad thing)
-       me.zoomSnapToTheBox = FALSE; // disabled: it's cooler
-}
-
-void XonoticScreenshotImage_load(entity me, string theImage)
-{
-       me.screenshotTime = time;
-       me.src = theImage;
-       if (me.screenshotTitle)
-               strunzone(me.screenshotTitle);
-       me.screenshotTitle = strzone(substring(me.src, 13, strlen(theImage) - 13)); //strip "/screenshots/"
-
-       me.initZoom(me); // this image may have a different size
-       me.setZoom(me, 0, 0);
-}
-
-float XonoticScreenshotImage_mousePress(entity me, vector coords)
-{
-       return me.drag_setStartPos(me, coords);
-}
-
-float XonoticScreenshotImage_mouseDrag(entity me, vector coords)
-{
-       return me.drag(me, coords);
-}
-
-float XonoticScreenshotImage_mouseMove(entity me, vector coords)
-{
-       return me.drag_setStartPos(me, coords);
-}
-
-void XonoticScreenshotImage_draw(entity me)
-{
-       if (me.src != "")
-       {
-               float theAlpha;
-               SUPER(XonoticScreenshotImage).draw(me);
-               if (me.showTitle && time < me.screenshotTime + 4) // 3 seconds at full alpha, 1 second fading out
-               {
-                       theAlpha = (4 - (time - me.screenshotTime));
-                       draw_CenterText('0.5 0 0', me.screenshotTitle, me.realFontSize, '1 1 1', theAlpha, FALSE);
-               }
-               if (time < me.zoomTime + 2) // 1 seconds at full alpha, 1 second fading out
-               {
-                       string zoomString;
-                       float z;
-                       z = me.zoomFactor * 100;
-                       if (z - floor(z) == 0)
-                               zoomString = sprintf("%d%%", z);
-                       else
-                               zoomString = sprintf("%.2f%%", z);
-                       theAlpha = (2 - (time - me.zoomTime));
-                       draw_Text('0.05 0.95 0', zoomString, me.realFontSize, '1 1 1', theAlpha, FALSE);
-               }
-       }
-}
-
-void XonoticScreenshotImage_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(XonoticScreenshotImage).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       me.realFontSize_y = me.fontSize / absSize_y;
-       me.realFontSize_x = me.fontSize / absSize_x;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/screenshotimage.qc b/qcsrc/menu/xonotic/screenshotimage.qc
new file mode 100644 (file)
index 0000000..469f177
--- /dev/null
@@ -0,0 +1,95 @@
+#ifdef INTERFACE
+CLASS(XonoticScreenshotImage) EXTENDS(XonoticImage)
+       METHOD(XonoticScreenshotImage, configureXonoticScreenshotImage, void(entity))
+       METHOD(XonoticScreenshotImage, load, void(entity, string))
+       METHOD(XonoticScreenshotImage, draw, void(entity))
+       ATTRIB(XonoticScreenshotImage, focusable, float, 1) // mousePress and mouseDrag work only if focusable is set
+       METHOD(XonoticScreenshotImage, mousePress, float(entity, vector))
+       METHOD(XonoticScreenshotImage, mouseDrag, float(entity, vector))
+       METHOD(XonoticScreenshotImage, mouseMove, float(entity, vector))
+       METHOD(XonoticScreenshotImage, resizeNotify, void(entity, vector, vector, vector, vector))
+       ATTRIB(XonoticScreenshotImage, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticScreenshotImage, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticScreenshotImage, showTitle, float, 1)
+       ATTRIB(XonoticScreenshotImage, screenshotTime, float, 0)
+       ATTRIB(XonoticScreenshotImage, screenshotTitle, string, string_null)
+ENDCLASS(XonoticScreenshotImage)
+entity makeXonoticScreenshotImage();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticScreenshotImage()
+{
+       entity me;
+       me = spawnXonoticScreenshotImage();
+       me.configureXonoticScreenshotImage(me);
+       return me;
+}
+
+void XonoticScreenshotImage_configureXonoticScreenshotImage(entity me)
+{
+       me.configureXonoticImage(me, string_null, -2);
+       me.zoomLimitedByTheBox = FALSE; // enable this to forbid enlarging the image more than the containing box (if making use of draw_SetClip is a too bad thing)
+       me.zoomSnapToTheBox = FALSE; // disabled: it's cooler
+}
+
+void XonoticScreenshotImage_load(entity me, string theImage)
+{
+       me.screenshotTime = time;
+       me.src = theImage;
+       if (me.screenshotTitle)
+               strunzone(me.screenshotTitle);
+       me.screenshotTitle = strzone(substring(me.src, 13, strlen(theImage) - 13)); //strip "/screenshots/"
+
+       me.initZoom(me); // this image may have a different size
+       me.setZoom(me, 0, 0);
+}
+
+float XonoticScreenshotImage_mousePress(entity me, vector coords)
+{
+       return me.drag_setStartPos(me, coords);
+}
+
+float XonoticScreenshotImage_mouseDrag(entity me, vector coords)
+{
+       return me.drag(me, coords);
+}
+
+float XonoticScreenshotImage_mouseMove(entity me, vector coords)
+{
+       return me.drag_setStartPos(me, coords);
+}
+
+void XonoticScreenshotImage_draw(entity me)
+{
+       if (me.src != "")
+       {
+               float theAlpha;
+               SUPER(XonoticScreenshotImage).draw(me);
+               if (me.showTitle && time < me.screenshotTime + 4) // 3 seconds at full alpha, 1 second fading out
+               {
+                       theAlpha = (4 - (time - me.screenshotTime));
+                       draw_CenterText('0.5 0 0', me.screenshotTitle, me.realFontSize, '1 1 1', theAlpha, FALSE);
+               }
+               if (time < me.zoomTime + 2) // 1 seconds at full alpha, 1 second fading out
+               {
+                       string zoomString;
+                       float z;
+                       z = me.zoomFactor * 100;
+                       if (z - floor(z) == 0)
+                               zoomString = sprintf("%d%%", z);
+                       else
+                               zoomString = sprintf("%.2f%%", z);
+                       theAlpha = (2 - (time - me.zoomTime));
+                       draw_Text('0.05 0.95 0', zoomString, me.realFontSize, '1 1 1', theAlpha, FALSE);
+               }
+       }
+}
+
+void XonoticScreenshotImage_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(XonoticScreenshotImage).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+       me.realFontSize_y = me.fontSize / absSize_y;
+       me.realFontSize_x = me.fontSize / absSize_x;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/screenshotlist.c b/qcsrc/menu/xonotic/screenshotlist.c
deleted file mode 100644 (file)
index c8f3bec..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticScreenshotList) EXTENDS(XonoticListBox)
-       METHOD(XonoticScreenshotList, configureXonoticScreenshotList, void(entity))
-       ATTRIB(XonoticScreenshotList, rowsPerItem, float, 1)
-       METHOD(XonoticScreenshotList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticScreenshotList, setSelected, void(entity, float))
-       METHOD(XonoticScreenshotList, draw, void(entity))
-       METHOD(XonoticScreenshotList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticScreenshotList, getScreenshots, void(entity))
-       METHOD(XonoticScreenshotList, previewScreenshot, void(entity))
-       METHOD(XonoticScreenshotList, startScreenshot, void(entity))
-       METHOD(XonoticScreenshotList, screenshotName, string(entity, float))
-       METHOD(XonoticScreenshotList, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticScreenshotList, keyDown, float(entity, float, float, float))
-       METHOD(XonoticScreenshotList, destroy, void(entity))
-       METHOD(XonoticScreenshotList, showNotify, void(entity))
-       ATTRIB(XonoticScreenshotList, listScreenshot, float, -1)
-       ATTRIB(XonoticScreenshotList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticScreenshotList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticScreenshotList, columnNameSize, float, 0)
-       ATTRIB(XonoticScreenshotList, realUpperMargin, float, 0)
-       ATTRIB(XonoticScreenshotList, origin, vector, '0 0 0')
-       ATTRIB(XonoticScreenshotList, itemAbsSize, vector, '0 0 0')
-       ATTRIB(XonoticScreenshotList, filterString, string, string_null)
-       ATTRIB(XonoticScreenshotList, filterBox, entity, NULL)
-       ATTRIB(XonoticScreenshotList, filterTime, float, 0)
-
-       ATTRIB(XonoticScreenshotList, newScreenshotTime, float, 0)
-       ATTRIB(XonoticScreenshotList, newSlideShowScreenshotTime, float, 0)
-       ATTRIB(XonoticScreenshotList, prevSelectedItem, float, 0)
-
-       ATTRIB(XonoticScreenshotList, screenshotBrowserDialog, entity, NULL)
-       ATTRIB(XonoticScreenshotList, screenshotPreview, entity, NULL)
-       ATTRIB(XonoticScreenshotList, screenshotViewerDialog, entity, NULL)
-       METHOD(XonoticScreenshotList, goScreenshot, void(entity, float))
-       METHOD(XonoticScreenshotList, startSlideShow, void(entity))
-       METHOD(XonoticScreenshotList, stopSlideShow, void(entity))
-ENDCLASS(XonoticScreenshotList)
-
-entity makeXonoticScreenshotList();
-void StartScreenshot_Click(entity btn, entity me);
-void ScreenshotList_Refresh_Click(entity btn, entity me);
-void ScreenshotList_Filter_Would_Change(entity box, entity me);
-void ScreenshotList_Filter_Change(entity box, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-
-entity makeXonoticScreenshotList()
-{
-       entity me;
-       me = spawnXonoticScreenshotList();
-       me.configureXonoticScreenshotList(me);
-       return me;
-}
-
-void XonoticScreenshotList_configureXonoticScreenshotList(entity me)
-{
-       me.configureXonoticListBox(me);
-       me.getScreenshots(me);
-}
-
-string XonoticScreenshotList_screenshotName(entity me, float i)
-{
-       string s;
-       s = bufstr_get(me.listScreenshot, i);
-
-       if(substring(s, 0, 1) == "/")
-               s = substring(s, 1, strlen(s) - 1);  // remove the first forward slash
-
-       return s;
-}
-
-// if subdir is TRUE look in subdirectories too (1 level)
-void getScreenshots_for_ext(entity me, string ext, float subdir)
-{
-       string s;
-       if (subdir)
-               s="screenshots/*/";
-       else
-               s="screenshots/";
-       if(me.filterString)
-               s=strcat(s, me.filterString, ext);
-       else
-               s=strcat(s, "*", ext);
-
-       float list, i, n;
-       list = search_begin(s, FALSE, TRUE);
-       if(list >= 0)
-       {
-               n = search_getsize(list);
-               for(i = 0; i < n; ++i)
-               {
-                       s = search_getfilename(list, i); // get initial full file name
-                       s = substring(s, 12, (strlen(s) - 12 - 4)); // remove "screenshots/" prefix and ".<ext>" suffix
-                       s = strdecolorize(s); // remove any pre-existing colors
-                       if(subdir)
-                       {
-                               s = strreplace("/", "^7/", s); // clear colors at the forward slash
-                               s = strcat("/", rgb_to_hexcolor(SKINCOLOR_SCREENSHOTLIST_SUBDIR), s); // add a forward slash for sorting, then color
-                               bufstr_add(me.listScreenshot, s, TRUE);
-                       }
-                       else { bufstr_add(me.listScreenshot, s, TRUE); }
-               }
-               search_end(list);
-       }
-
-       if (subdir)
-               getScreenshots_for_ext(me, ext, FALSE);
-}
-
-void XonoticScreenshotList_getScreenshots(entity me)
-{
-       if (me.listScreenshot >= 0)
-               buf_del(me.listScreenshot);
-       me.listScreenshot = buf_create();
-       if (me.listScreenshot < 0)
-       {
-               me.nItems = 0;
-               return;
-       }
-       getScreenshots_for_ext(me, ".jpg", TRUE);
-       getScreenshots_for_ext(me, ".tga", TRUE);
-       getScreenshots_for_ext(me, ".png", TRUE);
-       me.nItems = buf_getsize(me.listScreenshot);
-       if(me.nItems > 0)
-               buf_sort(me.listScreenshot, 128, FALSE);
-}
-
-void XonoticScreenshotList_destroy(entity me)
-{
-       if(me.nItems > 0)
-               buf_del(me.listScreenshot);
-}
-
-void XonoticScreenshotList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemAbsSize = '0 0 0';
-       SUPER(XonoticScreenshotList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
-
-       me.columnNameOrigin = me.realFontSize_x;
-       me.columnNameSize = 1 - 2 * me.realFontSize_x;
-}
-
-void XonoticScreenshotList_setSelected(entity me, float i)
-{
-       if (me.newSlideShowScreenshotTime)
-               me.startSlideShow(me);
-       me.prevSelectedItem = me.selectedItem;
-       SUPER(XonoticScreenshotList).setSelected(me, i);
-       if (me.pressed && me.selectedItem != me.prevSelectedItem)
-       {
-               // while dragging the scrollbar (or an item)
-               // for a smooth mouse movement do not load immediately the new selected images
-               me.newScreenshotTime = time + 0.22; // dragging an item we need a delay > 0.2 (from listbox: me.dragScrollTimer = time + 0.2;)
-       }
-       else if (time > me.newScreenshotTime)
-       {
-               me.newScreenshotTime = 0;
-               me.previewScreenshot(me); // load the preview on selection change
-       }
-}
-
-void XonoticScreenshotList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string s;
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-
-       s = me.screenshotName(me,i);
-       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
-}
-
-void XonoticScreenshotList_showNotify(entity me)
-{
-       me.getScreenshots(me);
-       me.previewScreenshot(me);
-}
-
-void ScreenshotList_Refresh_Click(entity btn, entity me)
-{
-       me.getScreenshots(me);
-       me.setSelected(me, 0); //always select the first element after a list update
-}
-
-void ScreenshotList_Filter_Change(entity box, entity me)
-{
-       if(me.filterString)
-               strunzone(me.filterString);
-
-       if(box.text != "")
-       {
-               if (strstrofs(box.text, "*", 0) >= 0 || strstrofs(box.text, "?", 0) >= 0)
-                       me.filterString = strzone(box.text);
-               else
-                       me.filterString = strzone(strcat("*", box.text, "*"));
-       }
-       else
-               me.filterString = string_null;
-
-       ScreenshotList_Refresh_Click(world, me);
-}
-
-void ScreenshotList_Filter_Would_Change(entity box, entity me)
-{
-       me.filterBox = box;
-       me.filterTime = time + 0.5;
-}
-
-void XonoticScreenshotList_draw(entity me)
-{
-       if (me.filterTime && time > me.filterTime)
-       {
-               ScreenshotList_Filter_Change(me.filterBox, me);
-               me.filterTime = 0;
-       }
-       if (me.newScreenshotTime && time > me.newScreenshotTime)
-       {
-               me.previewScreenshot(me);
-               me.newScreenshotTime = 0;
-       }
-       else if (me.newSlideShowScreenshotTime && time > me.newSlideShowScreenshotTime)
-       {
-               if (me.selectedItem == me.nItems - 1) //last screenshot?
-               {
-                       // restart from the first screenshot
-                       me.setSelected(me, 0);
-                       me.goScreenshot(me, +0);
-               }
-               else
-                       me.goScreenshot(me, +1);
-       }
-       SUPER(XonoticScreenshotList).draw(me);
-}
-
-void XonoticScreenshotList_startSlideShow(entity me)
-{
-       me.newSlideShowScreenshotTime = time + 3;
-}
-
-void XonoticScreenshotList_stopSlideShow(entity me)
-{
-       me.newSlideShowScreenshotTime = 0;
-}
-
-void XonoticScreenshotList_goScreenshot(entity me, float d)
-{
-       if(!me.screenshotViewerDialog)
-               return;
-       me.setSelected(me, me.selectedItem + d);
-       me.screenshotViewerDialog.loadScreenshot(me.screenshotViewerDialog, strcat("/screenshots/", strdecolorize(me.screenshotName(me,me.selectedItem))));
-}
-
-void XonoticScreenshotList_startScreenshot(entity me)
-{
-       me.screenshotViewerDialog.loadScreenshot(me.screenshotViewerDialog, strcat("/screenshots/", strdecolorize(me.screenshotName(me,me.selectedItem))));
-       // pop up screenshot
-       DialogOpenButton_Click_withCoords(NULL, me.screenshotViewerDialog, 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));
-}
-
-void XonoticScreenshotList_previewScreenshot(entity me)
-{
-       if(!me.screenshotBrowserDialog)
-               return;
-       if (me.nItems <= 0)
-               me.screenshotBrowserDialog.loadPreviewScreenshot(me.screenshotBrowserDialog, "");
-       else
-               me.screenshotBrowserDialog.loadPreviewScreenshot(me.screenshotBrowserDialog, strcat("/screenshots/", strdecolorize(me.screenshotName(me,me.selectedItem))));
-}
-
-void StartScreenshot_Click(entity btn, entity me)
-{
-       me.startScreenshot(me);
-}
-
-void XonoticScreenshotList_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       me.startScreenshot(me);
-}
-
-float XonoticScreenshotList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if(scan == K_ENTER || scan == K_KP_ENTER || scan == K_MOUSE2 || scan == K_SPACE) {
-               me.startScreenshot(me);
-               return 1;
-       }
-       if(scan == K_MWHEELUP || scan == K_MWHEELDOWN)
-               me.newScreenshotTime = time + 0.2;
-       return SUPER(XonoticScreenshotList).keyDown(me, scan, ascii, shift);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/screenshotlist.qc b/qcsrc/menu/xonotic/screenshotlist.qc
new file mode 100644 (file)
index 0000000..c8f3bec
--- /dev/null
@@ -0,0 +1,296 @@
+#ifdef INTERFACE
+CLASS(XonoticScreenshotList) EXTENDS(XonoticListBox)
+       METHOD(XonoticScreenshotList, configureXonoticScreenshotList, void(entity))
+       ATTRIB(XonoticScreenshotList, rowsPerItem, float, 1)
+       METHOD(XonoticScreenshotList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticScreenshotList, setSelected, void(entity, float))
+       METHOD(XonoticScreenshotList, draw, void(entity))
+       METHOD(XonoticScreenshotList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticScreenshotList, getScreenshots, void(entity))
+       METHOD(XonoticScreenshotList, previewScreenshot, void(entity))
+       METHOD(XonoticScreenshotList, startScreenshot, void(entity))
+       METHOD(XonoticScreenshotList, screenshotName, string(entity, float))
+       METHOD(XonoticScreenshotList, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticScreenshotList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticScreenshotList, destroy, void(entity))
+       METHOD(XonoticScreenshotList, showNotify, void(entity))
+       ATTRIB(XonoticScreenshotList, listScreenshot, float, -1)
+       ATTRIB(XonoticScreenshotList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticScreenshotList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticScreenshotList, columnNameSize, float, 0)
+       ATTRIB(XonoticScreenshotList, realUpperMargin, float, 0)
+       ATTRIB(XonoticScreenshotList, origin, vector, '0 0 0')
+       ATTRIB(XonoticScreenshotList, itemAbsSize, vector, '0 0 0')
+       ATTRIB(XonoticScreenshotList, filterString, string, string_null)
+       ATTRIB(XonoticScreenshotList, filterBox, entity, NULL)
+       ATTRIB(XonoticScreenshotList, filterTime, float, 0)
+
+       ATTRIB(XonoticScreenshotList, newScreenshotTime, float, 0)
+       ATTRIB(XonoticScreenshotList, newSlideShowScreenshotTime, float, 0)
+       ATTRIB(XonoticScreenshotList, prevSelectedItem, float, 0)
+
+       ATTRIB(XonoticScreenshotList, screenshotBrowserDialog, entity, NULL)
+       ATTRIB(XonoticScreenshotList, screenshotPreview, entity, NULL)
+       ATTRIB(XonoticScreenshotList, screenshotViewerDialog, entity, NULL)
+       METHOD(XonoticScreenshotList, goScreenshot, void(entity, float))
+       METHOD(XonoticScreenshotList, startSlideShow, void(entity))
+       METHOD(XonoticScreenshotList, stopSlideShow, void(entity))
+ENDCLASS(XonoticScreenshotList)
+
+entity makeXonoticScreenshotList();
+void StartScreenshot_Click(entity btn, entity me);
+void ScreenshotList_Refresh_Click(entity btn, entity me);
+void ScreenshotList_Filter_Would_Change(entity box, entity me);
+void ScreenshotList_Filter_Change(entity box, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeXonoticScreenshotList()
+{
+       entity me;
+       me = spawnXonoticScreenshotList();
+       me.configureXonoticScreenshotList(me);
+       return me;
+}
+
+void XonoticScreenshotList_configureXonoticScreenshotList(entity me)
+{
+       me.configureXonoticListBox(me);
+       me.getScreenshots(me);
+}
+
+string XonoticScreenshotList_screenshotName(entity me, float i)
+{
+       string s;
+       s = bufstr_get(me.listScreenshot, i);
+
+       if(substring(s, 0, 1) == "/")
+               s = substring(s, 1, strlen(s) - 1);  // remove the first forward slash
+
+       return s;
+}
+
+// if subdir is TRUE look in subdirectories too (1 level)
+void getScreenshots_for_ext(entity me, string ext, float subdir)
+{
+       string s;
+       if (subdir)
+               s="screenshots/*/";
+       else
+               s="screenshots/";
+       if(me.filterString)
+               s=strcat(s, me.filterString, ext);
+       else
+               s=strcat(s, "*", ext);
+
+       float list, i, n;
+       list = search_begin(s, FALSE, TRUE);
+       if(list >= 0)
+       {
+               n = search_getsize(list);
+               for(i = 0; i < n; ++i)
+               {
+                       s = search_getfilename(list, i); // get initial full file name
+                       s = substring(s, 12, (strlen(s) - 12 - 4)); // remove "screenshots/" prefix and ".<ext>" suffix
+                       s = strdecolorize(s); // remove any pre-existing colors
+                       if(subdir)
+                       {
+                               s = strreplace("/", "^7/", s); // clear colors at the forward slash
+                               s = strcat("/", rgb_to_hexcolor(SKINCOLOR_SCREENSHOTLIST_SUBDIR), s); // add a forward slash for sorting, then color
+                               bufstr_add(me.listScreenshot, s, TRUE);
+                       }
+                       else { bufstr_add(me.listScreenshot, s, TRUE); }
+               }
+               search_end(list);
+       }
+
+       if (subdir)
+               getScreenshots_for_ext(me, ext, FALSE);
+}
+
+void XonoticScreenshotList_getScreenshots(entity me)
+{
+       if (me.listScreenshot >= 0)
+               buf_del(me.listScreenshot);
+       me.listScreenshot = buf_create();
+       if (me.listScreenshot < 0)
+       {
+               me.nItems = 0;
+               return;
+       }
+       getScreenshots_for_ext(me, ".jpg", TRUE);
+       getScreenshots_for_ext(me, ".tga", TRUE);
+       getScreenshots_for_ext(me, ".png", TRUE);
+       me.nItems = buf_getsize(me.listScreenshot);
+       if(me.nItems > 0)
+               buf_sort(me.listScreenshot, 128, FALSE);
+}
+
+void XonoticScreenshotList_destroy(entity me)
+{
+       if(me.nItems > 0)
+               buf_del(me.listScreenshot);
+}
+
+void XonoticScreenshotList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticScreenshotList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+
+       me.columnNameOrigin = me.realFontSize_x;
+       me.columnNameSize = 1 - 2 * me.realFontSize_x;
+}
+
+void XonoticScreenshotList_setSelected(entity me, float i)
+{
+       if (me.newSlideShowScreenshotTime)
+               me.startSlideShow(me);
+       me.prevSelectedItem = me.selectedItem;
+       SUPER(XonoticScreenshotList).setSelected(me, i);
+       if (me.pressed && me.selectedItem != me.prevSelectedItem)
+       {
+               // while dragging the scrollbar (or an item)
+               // for a smooth mouse movement do not load immediately the new selected images
+               me.newScreenshotTime = time + 0.22; // dragging an item we need a delay > 0.2 (from listbox: me.dragScrollTimer = time + 0.2;)
+       }
+       else if (time > me.newScreenshotTime)
+       {
+               me.newScreenshotTime = 0;
+               me.previewScreenshot(me); // load the preview on selection change
+       }
+}
+
+void XonoticScreenshotList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s;
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       s = me.screenshotName(me,i);
+       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
+}
+
+void XonoticScreenshotList_showNotify(entity me)
+{
+       me.getScreenshots(me);
+       me.previewScreenshot(me);
+}
+
+void ScreenshotList_Refresh_Click(entity btn, entity me)
+{
+       me.getScreenshots(me);
+       me.setSelected(me, 0); //always select the first element after a list update
+}
+
+void ScreenshotList_Filter_Change(entity box, entity me)
+{
+       if(me.filterString)
+               strunzone(me.filterString);
+
+       if(box.text != "")
+       {
+               if (strstrofs(box.text, "*", 0) >= 0 || strstrofs(box.text, "?", 0) >= 0)
+                       me.filterString = strzone(box.text);
+               else
+                       me.filterString = strzone(strcat("*", box.text, "*"));
+       }
+       else
+               me.filterString = string_null;
+
+       ScreenshotList_Refresh_Click(world, me);
+}
+
+void ScreenshotList_Filter_Would_Change(entity box, entity me)
+{
+       me.filterBox = box;
+       me.filterTime = time + 0.5;
+}
+
+void XonoticScreenshotList_draw(entity me)
+{
+       if (me.filterTime && time > me.filterTime)
+       {
+               ScreenshotList_Filter_Change(me.filterBox, me);
+               me.filterTime = 0;
+       }
+       if (me.newScreenshotTime && time > me.newScreenshotTime)
+       {
+               me.previewScreenshot(me);
+               me.newScreenshotTime = 0;
+       }
+       else if (me.newSlideShowScreenshotTime && time > me.newSlideShowScreenshotTime)
+       {
+               if (me.selectedItem == me.nItems - 1) //last screenshot?
+               {
+                       // restart from the first screenshot
+                       me.setSelected(me, 0);
+                       me.goScreenshot(me, +0);
+               }
+               else
+                       me.goScreenshot(me, +1);
+       }
+       SUPER(XonoticScreenshotList).draw(me);
+}
+
+void XonoticScreenshotList_startSlideShow(entity me)
+{
+       me.newSlideShowScreenshotTime = time + 3;
+}
+
+void XonoticScreenshotList_stopSlideShow(entity me)
+{
+       me.newSlideShowScreenshotTime = 0;
+}
+
+void XonoticScreenshotList_goScreenshot(entity me, float d)
+{
+       if(!me.screenshotViewerDialog)
+               return;
+       me.setSelected(me, me.selectedItem + d);
+       me.screenshotViewerDialog.loadScreenshot(me.screenshotViewerDialog, strcat("/screenshots/", strdecolorize(me.screenshotName(me,me.selectedItem))));
+}
+
+void XonoticScreenshotList_startScreenshot(entity me)
+{
+       me.screenshotViewerDialog.loadScreenshot(me.screenshotViewerDialog, strcat("/screenshots/", strdecolorize(me.screenshotName(me,me.selectedItem))));
+       // pop up screenshot
+       DialogOpenButton_Click_withCoords(NULL, me.screenshotViewerDialog, 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));
+}
+
+void XonoticScreenshotList_previewScreenshot(entity me)
+{
+       if(!me.screenshotBrowserDialog)
+               return;
+       if (me.nItems <= 0)
+               me.screenshotBrowserDialog.loadPreviewScreenshot(me.screenshotBrowserDialog, "");
+       else
+               me.screenshotBrowserDialog.loadPreviewScreenshot(me.screenshotBrowserDialog, strcat("/screenshots/", strdecolorize(me.screenshotName(me,me.selectedItem))));
+}
+
+void StartScreenshot_Click(entity btn, entity me)
+{
+       me.startScreenshot(me);
+}
+
+void XonoticScreenshotList_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       me.startScreenshot(me);
+}
+
+float XonoticScreenshotList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_KP_ENTER || scan == K_MOUSE2 || scan == K_SPACE) {
+               me.startScreenshot(me);
+               return 1;
+       }
+       if(scan == K_MWHEELUP || scan == K_MWHEELDOWN)
+               me.newScreenshotTime = time + 0.2;
+       return SUPER(XonoticScreenshotList).keyDown(me, scan, ascii, shift);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/serverlist.c b/qcsrc/menu/xonotic/serverlist.c
deleted file mode 100644 (file)
index 50ce594..0000000
+++ /dev/null
@@ -1,1314 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticServerList) EXTENDS(XonoticListBox)
-       METHOD(XonoticServerList, configureXonoticServerList, void(entity))
-       ATTRIB(XonoticServerList, rowsPerItem, float, 1)
-       METHOD(XonoticServerList, draw, void(entity))
-       METHOD(XonoticServerList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticServerList, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticServerList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticServerList, keyDown, float(entity, float, float, float))
-       METHOD(XonoticServerList, toggleFavorite, void(entity, string))
-
-       ATTRIB(XonoticServerList, iconsSizeFactor, float, 0.85)
-
-       ATTRIB(XonoticServerList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticServerList, realUpperMargin, float, 0)
-       ATTRIB(XonoticServerList, columnIconsOrigin, float, 0)
-       ATTRIB(XonoticServerList, columnIconsSize, float, 0)
-       ATTRIB(XonoticServerList, columnPingOrigin, float, 0)
-       ATTRIB(XonoticServerList, columnPingSize, float, 0)
-       ATTRIB(XonoticServerList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticServerList, columnNameSize, float, 0)
-       ATTRIB(XonoticServerList, columnMapOrigin, float, 0)
-       ATTRIB(XonoticServerList, columnMapSize, float, 0)
-       ATTRIB(XonoticServerList, columnTypeOrigin, float, 0)
-       ATTRIB(XonoticServerList, columnTypeSize, float, 0)
-       ATTRIB(XonoticServerList, columnPlayersOrigin, float, 0)
-       ATTRIB(XonoticServerList, columnPlayersSize, float, 0)
-
-       ATTRIB(XonoticServerList, selectedServer, string, string_null) // to restore selected server when needed
-       METHOD(XonoticServerList, setSelected, void(entity, float))
-       METHOD(XonoticServerList, setSortOrder, void(entity, float, float))
-       ATTRIB(XonoticServerList, filterShowEmpty, float, 1)
-       ATTRIB(XonoticServerList, filterShowFull, float, 1)
-       ATTRIB(XonoticServerList, filterString, string, string_null)
-       ATTRIB(XonoticServerList, controlledTextbox, entity, NULL)
-       ATTRIB(XonoticServerList, ipAddressBox, entity, NULL)
-       ATTRIB(XonoticServerList, favoriteButton, entity, NULL)
-       ATTRIB(XonoticServerList, nextRefreshTime, float, 0)
-       METHOD(XonoticServerList, refreshServerList, void(entity, float)) // refresh mode: REFRESHSERVERLIST_*
-       ATTRIB(XonoticServerList, needsRefresh, float, 1)
-       METHOD(XonoticServerList, focusEnter, void(entity))
-       METHOD(XonoticServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))
-       ATTRIB(XonoticServerList, sortButton1, entity, NULL)
-       ATTRIB(XonoticServerList, sortButton2, entity, NULL)
-       ATTRIB(XonoticServerList, sortButton3, entity, NULL)
-       ATTRIB(XonoticServerList, sortButton4, entity, NULL)
-       ATTRIB(XonoticServerList, sortButton5, entity, NULL)
-       ATTRIB(XonoticServerList, connectButton, entity, NULL)
-       ATTRIB(XonoticServerList, infoButton, entity, NULL)
-       ATTRIB(XonoticServerList, currentSortOrder, float, 0)
-       ATTRIB(XonoticServerList, currentSortField, float, -1)
-
-       ATTRIB(XonoticServerList, ipAddressBoxFocused, float, -1)
-
-       ATTRIB(XonoticServerList, seenIPv4, float, 0)
-       ATTRIB(XonoticServerList, seenIPv6, float, 0)
-       ATTRIB(XonoticServerList, categoriesHeight, float, 1.25)
-
-       METHOD(XonoticServerList, getTotalHeight, float(entity))
-       METHOD(XonoticServerList, getItemAtPos, float(entity, float))
-       METHOD(XonoticServerList, getItemStart, float(entity, float))
-       METHOD(XonoticServerList, getItemHeight, float(entity, float))
-ENDCLASS(XonoticServerList)
-entity makeXonoticServerList();
-
-#ifndef IMPLEMENTATION
-float autocvar_menu_slist_categories;
-float autocvar_menu_slist_categories_onlyifmultiple; 
-float autocvar_menu_slist_purethreshold;
-float autocvar_menu_slist_modimpurity;
-float autocvar_menu_slist_recommendations;
-float autocvar_menu_slist_recommendations_maxping;
-float autocvar_menu_slist_recommendations_minfreeslots; 
-float autocvar_menu_slist_recommendations_minhumans;
-float autocvar_menu_slist_recommendations_purethreshold; 
-
-// server cache fields
-#define SLIST_FIELDS \
-       SLIST_FIELD(CNAME,       "cname") \
-       SLIST_FIELD(PING,        "ping") \
-       SLIST_FIELD(GAME,        "game") \
-       SLIST_FIELD(MOD,         "mod") \
-       SLIST_FIELD(MAP,         "map") \
-       SLIST_FIELD(NAME,        "name") \
-       SLIST_FIELD(MAXPLAYERS,  "maxplayers") \
-       SLIST_FIELD(NUMPLAYERS,  "numplayers") \
-       SLIST_FIELD(NUMHUMANS,   "numhumans") \
-       SLIST_FIELD(NUMBOTS,     "numbots") \
-       SLIST_FIELD(PROTOCOL,    "protocol") \
-       SLIST_FIELD(FREESLOTS,   "freeslots") \
-       SLIST_FIELD(PLAYERS,     "players") \
-       SLIST_FIELD(QCSTATUS,    "qcstatus") \
-       SLIST_FIELD(CATEGORY,    "category") \
-       SLIST_FIELD(ISFAVORITE,  "isfavorite")
-
-#define SLIST_FIELD(suffix,name) float SLIST_FIELD_##suffix;
-SLIST_FIELDS
-#undef SLIST_FIELD
-
-const float REFRESHSERVERLIST_RESORT = 0;    // sort the server list again to update for changes to e.g. favorite status, categories
-const float REFRESHSERVERLIST_REFILTER = 1;  // ..., also update filter and sort criteria
-const float REFRESHSERVERLIST_ASK = 2;       // ..., also suggest querying servers now
-const float REFRESHSERVERLIST_RESET = 3;     // ..., also clear the list first
-
-// function declarations
-float IsServerInList(string list, string srv);
-#define IsFavorite(srv) IsServerInList(cvar_string("net_slist_favorites"), srv)
-#define IsPromoted(srv) IsServerInList(_Nex_ExtResponseSystem_PromotedServers, srv)
-#define IsRecommended(srv) IsServerInList(_Nex_ExtResponseSystem_RecommendedServers, srv)
-
-entity RetrieveCategoryEnt(float catnum);
-
-float CheckCategoryOverride(float cat);
-float CheckCategoryForEntry(float entry); 
-float m_gethostcachecategory(float entry) { return CheckCategoryOverride(CheckCategoryForEntry(entry)); }
-
-void RegisterSLCategories();
-
-void ServerList_Connect_Click(entity btn, entity me);
-void ServerList_Categories_Click(entity box, 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);
-void ServerList_Favorite_Click(entity btn, entity me);
-void ServerList_Info_Click(entity btn, entity me);
-void ServerList_Update_favoriteButton(entity btn, entity me);
-
-// fields for category entities
-const float MAX_CATEGORIES = 9;
-const float CATEGORY_FIRST = 1;
-entity categories[MAX_CATEGORIES];
-float category_ent_count;
-.string cat_name;
-.string cat_string;
-.string cat_enoverride_string;
-.string cat_dioverride_string;
-.float cat_enoverride;
-.float cat_dioverride;
-
-// fields for drawing categories
-float category_name[MAX_CATEGORIES];
-float category_item[MAX_CATEGORIES];
-float category_draw_count;
-
-#define SLIST_CATEGORIES \
-       SLIST_CATEGORY(CAT_FAVORITED,    "",            "",             ZCTX(_("SLCAT^Favorites"))) \
-       SLIST_CATEGORY(CAT_RECOMMENDED,  "",            "",             ZCTX(_("SLCAT^Recommended"))) \
-       SLIST_CATEGORY(CAT_NORMAL,       "",            "CAT_SERVERS",  ZCTX(_("SLCAT^Normal Servers"))) \
-       SLIST_CATEGORY(CAT_SERVERS,      "CAT_NORMAL",  "CAT_SERVERS",  ZCTX(_("SLCAT^Servers"))) \
-       SLIST_CATEGORY(CAT_XPM,          "CAT_NORMAL",  "CAT_SERVERS",  ZCTX(_("SLCAT^Competitive Mode"))) \
-       SLIST_CATEGORY(CAT_MODIFIED,     "",            "CAT_SERVERS",  ZCTX(_("SLCAT^Modified Servers"))) \
-       SLIST_CATEGORY(CAT_OVERKILL,     "",            "CAT_SERVERS",  ZCTX(_("SLCAT^Overkill Mode"))) \
-       SLIST_CATEGORY(CAT_INSTAGIB,     "",            "CAT_SERVERS",  ZCTX(_("SLCAT^InstaGib Mode"))) \
-       SLIST_CATEGORY(CAT_DEFRAG,       "",            "CAT_SERVERS",  ZCTX(_("SLCAT^Defrag Mode")))
-
-#define SLIST_CATEGORY_AUTOCVAR(name) autocvar_menu_slist_categories_##name##_override
-#define SLIST_CATEGORY(name,enoverride,dioverride,str) \
-       float name; \
-       var string SLIST_CATEGORY_AUTOCVAR(name) = enoverride;
-SLIST_CATEGORIES
-#undef SLIST_CATEGORY
-
-#endif
-#endif
-#ifdef IMPLEMENTATION
-
-void RegisterSLCategories()
-{
-       entity cat;
-       #define SLIST_CATEGORY(name,enoverride,dioverride,str) \
-               SET_FIELD_COUNT(name, CATEGORY_FIRST, category_ent_count) \
-               CHECK_MAX_COUNT(name, MAX_CATEGORIES, category_ent_count, "SLIST_CATEGORY") \
-               cat = spawn(); \
-               categories[name - 1] = cat; \
-               cat.classname = "slist_category"; \
-               cat.cat_name = strzone(#name); \
-               cat.cat_enoverride_string = strzone(SLIST_CATEGORY_AUTOCVAR(name)); \
-               cat.cat_dioverride_string = strzone(dioverride); \
-               cat.cat_string = strzone(str);
-       SLIST_CATEGORIES
-       #undef SLIST_CATEGORY
-
-       float i, x, catnum;
-       string s;
-
-       #define PROCESS_OVERRIDE(override_string,override_field) \
-               for(i = 0; i < category_ent_count; ++i) \
-               { \
-                       s = categories[i].override_string; \
-                       if((s != "") && (s != categories[i].cat_name)) \
-                       { \
-                               catnum = 0; \
-                               for(x = 0; x < category_ent_count; ++x) \
-                               { if(categories[x].cat_name == s) { \
-                                       catnum = (x+1); \
-                                       break; \
-                               } } \
-                               if(catnum) \
-                               { \
-                                       strunzone(categories[i].override_string); \
-                                       categories[i].override_field = catnum; \
-                                       continue; \
-                               } \
-                               else \
-                               { \
-                                       printf( \
-                                               "RegisterSLCategories(): Improper override '%s' for category '%s'!\n", \
-                                               s, \
-                                               categories[i].cat_name \
-                                       ); \
-                               } \
-                       } \
-                       strunzone(categories[i].override_string); \
-                       categories[i].override_field = 0; \
-               }
-       PROCESS_OVERRIDE(cat_enoverride_string, cat_enoverride)
-       PROCESS_OVERRIDE(cat_dioverride_string, cat_dioverride)
-       #undef PROCESS_OVERRIDE
-}
-
-// Supporting Functions
-entity RetrieveCategoryEnt(float catnum)
-{
-       if((catnum > 0) && (catnum <= category_ent_count))
-       {
-               return categories[catnum - 1];
-       }
-       else
-       {
-               error(sprintf("RetrieveCategoryEnt(%d): Improper category number!\n", catnum));
-               return world;
-       }
-}
-
-float IsServerInList(string list, string srv)
-{
-       string p;
-       float i, n;
-       if(srv == "")
-               return FALSE;
-       srv = netaddress_resolve(srv, 26000);
-       if(srv == "")
-               return FALSE;
-       p = crypto_getidfp(srv);
-       n = tokenize_console(list);
-       for(i = 0; i < n; ++i)
-       {
-               if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
-               {
-                       if(p)
-                               if(argv(i) == p)
-                                       return TRUE;
-               }
-               else
-               {
-                       if(srv == netaddress_resolve(argv(i), 26000))
-                               return TRUE;
-               }
-       }
-       return FALSE;
-}
-
-float CheckCategoryOverride(float cat)
-{
-       entity catent = RetrieveCategoryEnt(cat);
-       if(catent)
-       {
-               float override = (autocvar_menu_slist_categories ? catent.cat_enoverride : catent.cat_dioverride); 
-               if(override) { return override; }
-               else { return cat; }
-       }
-       else
-       {
-               error(sprintf("CheckCategoryOverride(%d): Improper category number!\n", cat));
-               return cat;
-       }
-}
-
-float CheckCategoryForEntry(float entry)
-{
-       string s, k, v, modtype = "";
-       float j, m, impure = 0, freeslots = 0, sflags = 0;
-       s = gethostcachestring(SLIST_FIELD_QCSTATUS, entry);
-       m = tokenizebyseparator(s, ":");
-
-       for(j = 2; j < m; ++j)
-       {
-               if(argv(j) == "") { break; }
-               k = substring(argv(j), 0, 1);
-               v = substring(argv(j), 1, -1);
-               switch(k)
-               {
-                       case "P": { impure = stof(v); break; }
-                       case "S": { freeslots = stof(v); break; }
-                       case "F": { sflags = stof(v); break; }
-                       case "M": { modtype = strtolower(v); break; }
-               }
-       }
-
-       if(modtype != "xonotic") { impure += autocvar_menu_slist_modimpurity; }
-
-       // check if this server is favorited
-       if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, entry)) { return CAT_FAVORITED; }
-
-       // now check if it's recommended
-       if(autocvar_menu_slist_recommendations)
-       {
-               string cname = gethostcachestring(SLIST_FIELD_CNAME, entry);
-               
-               if(IsPromoted(cname)) { return CAT_RECOMMENDED; }
-               else
-               {
-                       float recommended = 0;
-                       if(autocvar_menu_slist_recommendations & 1)
-                       {
-                               if(IsRecommended(cname)) { ++recommended; }
-                               else { --recommended; }
-                       }
-                       if(autocvar_menu_slist_recommendations & 2)
-                       {
-                               if(
-                                       ///// check for minimum free slots
-                                       (freeslots >= autocvar_menu_slist_recommendations_minfreeslots)
-                                       
-                                       && // check for purity requirement
-                                       (
-                                               (autocvar_menu_slist_recommendations_purethreshold < 0)
-                                               ||
-                                               (impure <= autocvar_menu_slist_recommendations_purethreshold)
-                                       )
-                                       
-                                       && // check for minimum amount of humans
-                                       (
-                                               gethostcachenumber(SLIST_FIELD_NUMHUMANS, entry)
-                                               >=
-                                               autocvar_menu_slist_recommendations_minhumans
-                                       )
-                                       
-                                       && // check for maximum latency
-                                       (
-                                               gethostcachenumber(SLIST_FIELD_PING, entry)
-                                               <=
-                                               autocvar_menu_slist_recommendations_maxping
-                                       )
-                               )
-                                       { ++recommended; }
-                               else
-                                       { --recommended; }
-                       }
-                       if(recommended > 0) { return CAT_RECOMMENDED; }
-               }
-       }
-
-       // if not favorited or recommended, check modname
-       if(modtype != "xonotic")
-       {
-               switch(modtype)
-               {
-                       // old servers which don't report their mod name are considered modified now
-                       case "": { return CAT_MODIFIED; }
-                       
-                       case "xpm": { return CAT_XPM; }
-                       case "minstagib":
-                       case "instagib": { return CAT_INSTAGIB; }
-                       case "overkill": { return CAT_OVERKILL; }
-                       //case "nix": { return CAT_NIX; }
-                       //case "newtoys": { return CAT_NEWTOYS; }
-
-                       // "cts" is allowed as compat, xdf is replacement
-                       case "cts": 
-                       case "xdf": { return CAT_DEFRAG; }
-                       
-                       default: { dprintf("Found strange mod type: %s\n", modtype); return CAT_MODIFIED; }
-               }
-       }
-
-       // must be normal or impure server
-       return ((impure > autocvar_menu_slist_purethreshold) ? CAT_MODIFIED : CAT_NORMAL);
-}
-
-void XonoticServerList_toggleFavorite(entity me, string srv)
-{
-       string s, s0, s1, s2, srv_resolved, p;
-       float i, n, f;
-       srv_resolved = netaddress_resolve(srv, 26000);
-       p = crypto_getidfp(srv_resolved);
-       s = cvar_string("net_slist_favorites");
-       n = tokenize_console(s);
-       f = 0;
-       for(i = 0; i < n; ++i)
-       {
-               if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
-               {
-                       if(p)
-                               if(argv(i) != p)
-                                       continue;
-               }
-               else
-               {
-                       if(srv_resolved != netaddress_resolve(argv(i), 26000))
-                               continue;
-               }
-               s0 = s1 = s2 = "";
-               if(i > 0)
-                       s0 = substring(s, 0, argv_end_index(i - 1));
-               if(i < n-1)
-                       s2 = substring(s, argv_start_index(i + 1), -1);
-               if(s0 != "" && s2 != "")
-                       s1 = " ";
-               cvar_set("net_slist_favorites", strcat(s0, s1, s2));
-               s = cvar_string("net_slist_favorites");
-               n = tokenize_console(s);
-               f = 1;
-               --i;
-       }
-
-       if(!f)
-       {
-               s1 = "";
-               if(s != "")
-                       s1 = " ";
-               if(p)
-                       cvar_set("net_slist_favorites", strcat(s, s1, p));
-               else
-                       cvar_set("net_slist_favorites", strcat(s, s1, srv));
-       }
-
-       me.refreshServerList(me, REFRESHSERVERLIST_RESORT);
-}
-
-void ServerList_Update_favoriteButton(entity btn, entity me)
-{
-       me.favoriteButton.setText(me.favoriteButton,
-               (IsFavorite(me.ipAddressBox.text) ?
-                       _("Remove") : _("Favorite")
-               )
-       );
-}
-
-entity makeXonoticServerList()
-{
-       entity me;
-       me = spawnXonoticServerList();
-       me.configureXonoticServerList(me);
-       return me;
-}
-void XonoticServerList_configureXonoticServerList(entity me)
-{
-       me.configureXonoticListBox(me);
-
-       // update field ID's
-       #define SLIST_FIELD(suffix,name) SLIST_FIELD_##suffix = gethostcacheindexforkey(name);
-       SLIST_FIELDS
-       #undef SLIST_FIELD
-
-       // clear list
-       me.nItems = 0;
-}
-void XonoticServerList_setSelected(entity me, float i)
-{
-       float save;
-       save = me.selectedItem;
-       SUPER(XonoticServerList).setSelected(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));
-
-       me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
-       me.ipAddressBox.cursorPos = strlen(me.selectedServer);
-       me.ipAddressBoxFocused = -1;
-}
-void XonoticServerList_refreshServerList(entity me, float mode)
-{
-       //print("refresh of type ", ftos(mode), "\n");
-
-       if(mode >= REFRESHSERVERLIST_REFILTER)
-       {
-               float m, i, n;
-               float listflags = 0;
-               string s, typestr, modstr;
-
-               s = me.filterString;
-
-               m = strstrofs(s, ":", 0);
-               if(m >= 0)
-               {
-                       typestr = substring(s, 0, m);
-                       s = substring(s, m + 1, strlen(s) - m - 1);
-                       while(substring(s, 0, 1) == " ")
-                               s = substring(s, 1, strlen(s) - 1);
-               }
-               else
-                       typestr = "";
-
-               modstr = cvar_string("menu_slist_modfilter");
-
-               m = SLIST_MASK_AND - 1;
-               resethostcachemasks();
-
-               // ping: reject negative ping (no idea why this happens in the first place, engine bug)
-               sethostcachemasknumber(++m, SLIST_FIELD_PING, 0, SLIST_TEST_GREATEREQUAL);
-
-               // show full button
-               if(!me.filterShowFull)
-               {
-                       sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL); // legacy
-                       sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, ":S0:", SLIST_TEST_NOTCONTAIN); // g_maxplayers support
-               }
-
-               // show empty button
-               if(!me.filterShowEmpty)
-                       sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
-
-               // gametype filtering
-               if(typestr != "")
-                       sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
-
-               // mod filtering
-               if(modstr != "")
-               {
-                       if(substring(modstr, 0, 1) == "!")
-                               sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
-                       else
-                               sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
-               }
-
-               // server banning
-               n = tokenizebyseparator(_Nex_ExtResponseSystem_BannedServers, " ");
-               for(i = 0; i < n; ++i)
-                       if(argv(i) != "")
-                               sethostcachemaskstring(++m, SLIST_FIELD_CNAME, argv(i), SLIST_TEST_NOTSTARTSWITH);
-
-               m = SLIST_MASK_OR - 1;
-               if(s != "")
-               {
-                       sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
-                       sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
-                       sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
-                       sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
-               }
-
-               // sorting flags
-               //listflags |= SLSF_FAVORITES;
-               listflags |= SLSF_CATEGORIES;
-               if(me.currentSortOrder < 0) { listflags |= SLSF_DESCENDING; }
-               sethostcachesort(me.currentSortField, listflags);
-       }
-       
-       resorthostcache();
-       if(mode >= REFRESHSERVERLIST_ASK)
-               refreshhostcache(mode >= REFRESHSERVERLIST_RESET);
-}
-void XonoticServerList_focusEnter(entity me)
-{
-       if(time < me.nextRefreshTime)
-       {
-               //print("sorry, no refresh yet\n");
-               return;
-       }
-       me.nextRefreshTime = time + 10;
-       me.refreshServerList(me, REFRESHSERVERLIST_ASK);
-}
-
-void XonoticServerList_draw(entity me)
-{
-       float i, found, owned;
-
-       if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
-       {
-               if(!me.needsRefresh)
-                       me.needsRefresh = 2;
-               _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0;
-       }
-
-       if(_Nex_ExtResponseSystem_PromotedServersNeedsRefresh)
-       {
-               if(!me.needsRefresh)
-                       me.needsRefresh = 3;
-               _Nex_ExtResponseSystem_PromotedServersNeedsRefresh = 0;
-       }
-
-       if(_Nex_ExtResponseSystem_RecommendedServersNeedsRefresh)
-       {
-               if(!me.needsRefresh)
-                       me.needsRefresh = 3;
-               _Nex_ExtResponseSystem_RecommendedServersNeedsRefresh = 0;
-       }
-
-       if(me.currentSortField == -1)
-       {
-               me.setSortOrder(me, SLIST_FIELD_PING, +1);
-               me.refreshServerList(me, REFRESHSERVERLIST_RESET);
-       }
-       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, REFRESHSERVERLIST_REFILTER);
-       }
-       else if(me.needsRefresh == 3)
-       {
-               me.needsRefresh = 0;
-               me.refreshServerList(me, REFRESHSERVERLIST_RESORT);
-       }
-
-       owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
-
-       for(i = 0; i < category_draw_count; ++i) { category_name[i] = -1; category_item[i] = -1; }
-       category_draw_count = 0;
-
-       if(autocvar_menu_slist_categories >= 0) // if less than 0, don't even draw a category heading for favorites
-       {
-               float itemcount = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
-               me.nItems = itemcount;
-               
-               //float visible = floor(me.scrollPos / me.itemHeight);
-               // ^ unfortunately no such optimization can be made-- we must process through the
-               // entire list, otherwise there is no way to know which item is first in its category.
-
-               // binary search method suggested by div
-               float x;
-               float begin = 0;
-               for(x = 1; x <= category_ent_count; ++x) {
-                       float first = begin;
-                       float last = (itemcount - 1);
-                       if (first > last) {
-                               // List is empty.
-                               break;
-                       }
-                       float catf = gethostcachenumber(SLIST_FIELD_CATEGORY, first);
-                       float catl = gethostcachenumber(SLIST_FIELD_CATEGORY, last);
-                       if (catf > x) {
-                               // The first one is already > x.
-                               // Therefore, category x does not exist.
-                               // Higher numbered categories do exist though.
-                       } else if (catl < x) {
-                               // The last one is < x.
-                               // Thus this category - and any following -
-                               // don't exist.
-                               break;
-                       } else if (catf == x) {
-                               // Starts at first. This breaks the loop
-                               // invariant in the binary search and thus has
-                               // to be handled separately.
-                               if(gethostcachenumber(SLIST_FIELD_CATEGORY, first) != x)
-                                       error("Category mismatch I");
-                               if(first > 0)
-                                       if(gethostcachenumber(SLIST_FIELD_CATEGORY, first - 1) == x)
-                                               error("Category mismatch II");
-                               category_name[category_draw_count] = x;
-                               category_item[category_draw_count] = first;
-                               ++category_draw_count;
-                               begin = first + 1;
-                       } else {
-                               // At this point, catf <= x < catl, thus
-                               // catf < catl, thus first < last.
-                               // INVARIANTS:
-                               // last - first >= 1
-                               // catf == gethostcachenumber(SLIST_FIELD_CATEGORY(first)
-                               // catl == gethostcachenumber(SLIST_FIELD_CATEGORY(last)
-                               // catf < x
-                               // catl >= x
-                               while (last - first > 1) {
-                                       float middle = floor((first + last) / 2);
-                                       // By loop condition, middle != first && middle != last.
-                                       float cat = gethostcachenumber(SLIST_FIELD_CATEGORY, middle);
-                                       if (cat >= x) {
-                                               last = middle;
-                                               catl = cat;
-                                       } else {
-                                               first = middle;
-                                               catf = cat;
-                                       }
-                               }
-                               if (catl == x) {
-                                       if(gethostcachenumber(SLIST_FIELD_CATEGORY, last) != x)
-                                               error("Category mismatch III");
-                                       if(last > 0)
-                                               if(gethostcachenumber(SLIST_FIELD_CATEGORY, last - 1) == x)
-                                                       error("Category mismatch IV");
-                                       category_name[category_draw_count] = x;
-                                       category_item[category_draw_count] = last;
-                                       ++category_draw_count;
-                                       begin = last + 1; // already scanned through these, skip 'em
-                               }
-                               else
-                                       begin = last; // already scanned through these, skip 'em
-                       }
-               }
-               if(autocvar_menu_slist_categories_onlyifmultiple && (category_draw_count == 1))
-               {
-                       category_name[0] = -1;
-                       category_item[0] = -1;
-                       category_draw_count = 0;
-                       me.nItems = itemcount;
-               }
-       }
-       else { me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT); }
-
-       me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
-       me.infoButton.disabled = ((me.nItems == 0) || !owned);
-       me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
-
-       found = 0;
-       if(me.selectedServer)
-       {
-               for(i = 0; i < me.nItems; ++i)
-               {
-                       if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
-                       {
-                               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));
-               }
-       }
-       
-       if(owned)
-       {
-               if(me.selectedServer != me.ipAddressBox.text)
-               {
-                       me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
-                       me.ipAddressBox.cursorPos = strlen(me.selectedServer);
-                       me.ipAddressBoxFocused = -1;
-               }
-       }
-
-       if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
-       {
-               if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
-                       ServerList_Update_favoriteButton(NULL, me);
-               me.ipAddressBoxFocused = me.ipAddressBox.focused;
-       }
-
-       SUPER(XonoticServerList).draw(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_TypeSort_Click(entity btn, entity me)
-{
-       string s, t;
-       float i, m;
-       s = me.filterString;
-       m = strstrofs(s, ":", 0);
-       if(m >= 0)
-       {
-               s = substring(s, 0, m);
-               while(substring(s, m+1, 1) == " ") // skip spaces
-                       ++m;
-       }
-       else
-               s = "";
-
-       for(i = 1; ; i *= 2) // 20 modes ought to be enough for anyone
-       {
-               t = MapInfo_Type_ToString(i);
-               if(i > 1)
-                       if(t == "") // it repeats (default case)
-                       {
-                               // no type was found
-                               // choose the first one
-                               s = MapInfo_Type_ToString(1);
-                               break;
-                       }
-               if(s == t)
-               {
-                       // the type was found
-                       // choose the next one
-                       s = MapInfo_Type_ToString(i * 2);
-                       if(s == "")
-                               s = MapInfo_Type_ToString(1);
-                       break;
-               }
-       }
-
-       if(s != "")
-               s = strcat(s, ":");
-       s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
-
-       me.controlledTextbox.setText(me.controlledTextbox, s);
-       me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
-       me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
-       //ServerList_Filter_Change(me.controlledTextbox, me);
-}
-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, REFRESHSERVERLIST_REFILTER);
-
-       me.ipAddressBox.setText(me.ipAddressBox, "");
-       me.ipAddressBox.cursorPos = 0;
-       me.ipAddressBoxFocused = -1;
-}
-void ServerList_Categories_Click(entity box, entity me)
-{
-       box.setChecked(box, autocvar_menu_slist_categories = !autocvar_menu_slist_categories);
-       me.refreshServerList(me, REFRESHSERVERLIST_RESORT);
-
-       me.ipAddressBox.setText(me.ipAddressBox, "");
-       me.ipAddressBox.cursorPos = 0;
-       me.ipAddressBoxFocused = -1;
-}
-void ServerList_ShowEmpty_Click(entity box, entity me)
-{
-       box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
-       me.refreshServerList(me, REFRESHSERVERLIST_REFILTER);
-
-       me.ipAddressBox.setText(me.ipAddressBox, "");
-       me.ipAddressBox.cursorPos = 0;
-       me.ipAddressBoxFocused = -1;
-}
-void ServerList_ShowFull_Click(entity box, entity me)
-{
-       box.setChecked(box, me.filterShowFull = !me.filterShowFull);
-       me.refreshServerList(me, REFRESHSERVERLIST_REFILTER);
-
-       me.ipAddressBox.setText(me.ipAddressBox, "");
-       me.ipAddressBox.cursorPos = 0;
-       me.ipAddressBoxFocused = -1;
-}
-void XonoticServerList_setSortOrder(entity me, float fld, float direction)
-{
-       if(me.currentSortField == fld)
-               direction = -me.currentSortOrder;
-       me.currentSortOrder = direction;
-       me.currentSortField = fld;
-       me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
-       me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
-       me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
-       me.sortButton4.forcePressed = 0;
-       me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
-       me.selectedItem = 0;
-       if(me.selectedServer)
-               strunzone(me.selectedServer);
-       me.selectedServer = string_null;
-       me.refreshServerList(me, REFRESHSERVERLIST_REFILTER);
-}
-void XonoticServerList_positionSortButton(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 XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(XonoticServerList).resizeNotify(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.columnIconsOrigin = 0;
-       me.columnIconsSize = me.realFontSize_x * 4 * me.iconsSizeFactor;
-       me.columnPingSize = me.realFontSize_x * 3;
-       me.columnMapSize = me.realFontSize_x * 10;
-       me.columnTypeSize = me.realFontSize_x * 4;
-       me.columnPlayersSize = me.realFontSize_x * 5;
-       me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
-       me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
-       me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
-       me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
-       me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
-       me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + 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.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
-       me.positionSortButton(me, me.sortButton5, 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)
-{
-       localcmd(sprintf("connect %s\n",
-               ((me.ipAddressBox.text != "") ?
-                       me.ipAddressBox.text : me.selectedServer
-               )
-       ));
-}
-void ServerList_Favorite_Click(entity btn, entity me)
-{
-       string ipstr;
-       ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
-       if(ipstr != "")
-       {
-               me.toggleFavorite(me, me.ipAddressBox.text);
-               me.ipAddressBoxFocused = -1;
-       }
-}
-void ServerList_Info_Click(entity btn, entity me)
-{
-       if (me.nItems != 0)
-               main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
-
-       vector org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
-       vector sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
-       DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
-}
-void XonoticServerList_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       ServerList_Connect_Click(NULL, me);
-}
-void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       // layout: Ping, Server name, Map name, NP, TP, MP
-       float p, q;
-       float isv4, isv6;
-       vector theColor;
-       float theAlpha;
-       float m, pure, freeslots, j, sflags;
-       string s, typestr, versionstr, k, v, modname;
-
-       //printf("time: %f, i: %d, item: %d, nitems: %d\n", time, i, item, me.nItems);
-
-       vector oldscale = draw_scale;
-       vector oldshift = draw_shift;
-#define SET_YRANGE(start,end) \
-       draw_scale = boxToGlobalSize(eX * 1 + eY * (end - start), oldscale); \
-       draw_shift = boxToGlobal(eY * start, oldshift, oldscale);
-
-       for (j = 0; j < category_draw_count; ++j) {
-               // Matches exactly the headings with increased height.
-               if (i == category_item[j])
-                       break;
-       }
-
-       if (j < category_draw_count)
-       {
-               entity catent = RetrieveCategoryEnt(category_name[j]);
-               if(catent)
-               {
-                       SET_YRANGE(
-                               (me.categoriesHeight - 1) / (me.categoriesHeight + 1),
-                               me.categoriesHeight / (me.categoriesHeight + 1)
-                       );
-                       draw_Text(
-                               eY * me.realUpperMargin
-                               +
-#if 0
-                               eX * (me.columnNameOrigin + (me.columnNameSize - draw_TextWidth(catent.cat_string, 0, me.realFontSize)) * 0.5),
-                               catent.cat_string,
-#else
-                               eX * (me.columnNameOrigin),
-                               strcat(catent.cat_string, ":"),
-#endif
-                               me.realFontSize,
-                               SKINCOLOR_SERVERLIST_CATEGORY,
-                               SKINALPHA_SERVERLIST_CATEGORY,
-                               0
-                       );
-                       SET_YRANGE(me.categoriesHeight / (me.categoriesHeight + 1), 1);
-               }
-       }
-       
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-
-       s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
-       m = tokenizebyseparator(s, ":");
-       typestr = "";
-       if(m >= 2)
-       {
-               typestr = argv(0);
-               versionstr = argv(1);
-       }
-       freeslots = -1;
-       sflags = -1;
-       modname = "";
-       pure = 0;
-       for(j = 2; j < m; ++j)
-       {
-               if(argv(j) == "")
-                       break;
-               k = substring(argv(j), 0, 1);
-               v = substring(argv(j), 1, -1);
-               if(k == "P")
-                       pure = stof(v);
-               else if(k == "S")
-                       freeslots = stof(v);
-               else if(k == "F")
-                       sflags = stof(v);
-               else if(k == "M")
-                       modname = v;
-       }
-
-#ifdef COMPAT_NO_MOD_IS_XONOTIC
-       if(modname == "")
-               modname = "Xonotic";
-#endif
-
-       /*
-       SLIST_FIELD_MOD = gethostcacheindexforkey("mod");
-       s = gethostcachestring(SLIST_FIELD_MOD, i);
-       if(s != "data")
-               if(modname == "Xonotic")
-                       modname = s;
-       */
-
-       // list the mods here on which the pure server check actually works
-       if(modname != "Xonotic")
-       if(modname != "InstaGib" || modname != "MinstaGib")
-       if(modname != "CTS")
-       if(modname != "NIX")
-       if(modname != "NewToys")
-               pure = 0;
-
-       if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
-               theAlpha = SKINALPHA_SERVERLIST_FULL;
-       else if(freeslots == 0)
-               theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
-       else if (!gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
-               theAlpha = SKINALPHA_SERVERLIST_EMPTY;
-       else
-               theAlpha = 1;
-
-       p = gethostcachenumber(SLIST_FIELD_PING, i);
-       const float PING_LOW = 75;
-       const float PING_MED = 200;
-       const float PING_HIGH = 500;
-       if(p < PING_LOW)
-               theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
-       else if(p < PING_MED)
-               theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
-       else if(p < PING_HIGH)
-       {
-               theColor = SKINCOLOR_SERVERLIST_HIGHPING;
-               theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
-       }
-       else
-       {
-               theColor = eX;
-               theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
-       }
-
-       if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
-       {
-               theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
-               theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
-       }
-
-       s = gethostcachestring(SLIST_FIELD_CNAME, i);
-
-       isv4 = isv6 = 0;
-       if(substring(s, 0, 1) == "[")
-       {
-               isv6 = 1;
-               me.seenIPv6 += 1;
-       }
-       else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
-       {
-               isv4 = 1;
-               me.seenIPv4 += 1;
-       }
-
-       q = stof(substring(crypto_getencryptlevel(s), 0, 1));
-       if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
-       {
-               theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
-               theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
-       }
-
-       if(q == 1)
-       {
-               if(cvar("crypto_aeslevel") >= 2)
-                       q |= 4;
-       }
-       if(q == 2)
-       {
-               if(cvar("crypto_aeslevel") >= 1)
-                       q |= 4;
-       }
-       if(q == 3)
-               q = 5;
-       else if(q >= 3)
-               q -= 2;
-       // possible status:
-       // 0: crypto off
-       // 1: AES possible
-       // 2: AES recommended but not available
-       // 3: AES possible and will be used
-       // 4: AES recommended and will be used
-       // 5: AES required
-
-       // --------------
-       //  RENDER ICONS
-       // --------------
-       vector iconSize = '0 0 0';
-       iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
-       iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
-
-       vector iconPos = '0 0 0';
-       iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
-       iconPos_y = (1 - iconSize_y) * 0.5;
-
-       string n;
-
-       if (!(me.seenIPv4 && me.seenIPv6))
-       {
-               iconPos_x += iconSize_x * 0.5;
-       }
-       else if(me.seenIPv4 && me.seenIPv6)
-       {
-               n = string_null;
-               if(isv6)
-                       draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), 0); // PRECACHE_PIC_MIPMAP
-               else if(isv4)
-                       draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), 0); // PRECACHE_PIC_MIPMAP
-               if(n)
-                       draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
-               iconPos_x += iconSize_x;
-       }
-
-       if(q > 0)
-       {
-               draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), 0); // PRECACHE_PIC_MIPMAP
-               draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
-       }
-       iconPos_x += iconSize_x;
-
-       if(modname == "Xonotic")
-       {
-               if(pure == 0)
-               {
-                       draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_pure1"), PRECACHE_PIC_MIPMAP);
-                       draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
-               }
-       }
-       else
-       {
-               draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_", modname), PRECACHE_PIC_MIPMAP);
-               if(draw_PictureSize(n) == '0 0 0')
-                       draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_"), PRECACHE_PIC_MIPMAP);
-               if(pure == 0)
-                       draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
-               else
-                       draw_Picture(iconPos, n, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
-       }
-       iconPos_x += iconSize_x;
-
-       if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS))
-       {
-               draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_stats1"), 0); // PRECACHE_PIC_MIPMAP
-               draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
-       }
-       iconPos_x += iconSize_x;
-       
-       // --------------
-       //  RENDER TEXT
-       // --------------
-       
-       // ping
-       s = ftos(p);
-       draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
-
-       // server name
-       s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
-
-       // server map
-       s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
-
-       // server gametype
-       s = draw_TextShortenToWidth(typestr, me.columnTypeSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
-
-       // server playercount
-       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)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
-}
-
-float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       vector org, sz;
-
-       org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
-       sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
-
-       if(scan == K_ENTER || scan == K_KP_ENTER)
-       {
-               ServerList_Connect_Click(NULL, me);
-               return 1;
-       }
-       else if(scan == K_MOUSE2 || scan == K_SPACE)
-       {
-               if(me.nItems != 0)
-               {
-                       main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
-                       DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
-                       return 1;
-               }
-               return 0;
-       }
-       else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
-       {
-               if(me.nItems != 0)
-               {
-                       me.toggleFavorite(me, me.selectedServer);
-                       me.ipAddressBoxFocused = -1;
-                       return 1;
-               }
-               return 0;
-       }
-       else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
-               return 1;
-       else if(!me.controlledTextbox)
-               return 0;
-       else
-               return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);
-}
-
-float XonoticServerList_getTotalHeight(entity me) {
-       float num_normal_rows = me.nItems;
-       float num_headers = category_draw_count;
-       return me.itemHeight * (num_normal_rows + me.categoriesHeight * num_headers);
-}
-float XonoticServerList_getItemAtPos(entity me, float pos) {
-       pos = pos / me.itemHeight;
-       float i;
-       for (i = category_draw_count - 1; i >= 0; --i) {
-               float itemidx = category_item[i];
-               float itempos = i * me.categoriesHeight + category_item[i];
-               if (pos >= itempos + me.categoriesHeight + 1)
-                       return itemidx + 1 + floor(pos - (itempos + me.categoriesHeight + 1));
-               if (pos >= itempos)
-                       return itemidx;
-       }
-       // No category matches? Note that category 0 is... 0. Therefore no headings exist at all.
-       return floor(pos);
-}
-float XonoticServerList_getItemStart(entity me, float item) {
-       float i;
-       for (i = category_draw_count - 1; i >= 0; --i) {
-               float itemidx = category_item[i];
-               float itempos = i * me.categoriesHeight + category_item[i];
-               if (item >= itemidx + 1)
-                       return (itempos + me.categoriesHeight + 1 + item - (itemidx + 1)) * me.itemHeight;
-               if (item >= itemidx)
-                       return itempos * me.itemHeight;
-       }
-       // No category matches? Note that category 0 is... 0. Therefore no headings exist at all.
-       return item * me.itemHeight;
-}
-float XonoticServerList_getItemHeight(entity me, float item) {
-       float i;
-       for (i = 0; i < category_draw_count; ++i) {
-               // Matches exactly the headings with increased height.
-               if (item == category_item[i])
-                       return me.itemHeight * (me.categoriesHeight + 1);
-       }
-       return me.itemHeight;
-}
-
-#endif
diff --git a/qcsrc/menu/xonotic/serverlist.qc b/qcsrc/menu/xonotic/serverlist.qc
new file mode 100644 (file)
index 0000000..50ce594
--- /dev/null
@@ -0,0 +1,1314 @@
+#ifdef INTERFACE
+CLASS(XonoticServerList) EXTENDS(XonoticListBox)
+       METHOD(XonoticServerList, configureXonoticServerList, void(entity))
+       ATTRIB(XonoticServerList, rowsPerItem, float, 1)
+       METHOD(XonoticServerList, draw, void(entity))
+       METHOD(XonoticServerList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticServerList, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticServerList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticServerList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticServerList, toggleFavorite, void(entity, string))
+
+       ATTRIB(XonoticServerList, iconsSizeFactor, float, 0.85)
+
+       ATTRIB(XonoticServerList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticServerList, realUpperMargin, float, 0)
+       ATTRIB(XonoticServerList, columnIconsOrigin, float, 0)
+       ATTRIB(XonoticServerList, columnIconsSize, float, 0)
+       ATTRIB(XonoticServerList, columnPingOrigin, float, 0)
+       ATTRIB(XonoticServerList, columnPingSize, float, 0)
+       ATTRIB(XonoticServerList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticServerList, columnNameSize, float, 0)
+       ATTRIB(XonoticServerList, columnMapOrigin, float, 0)
+       ATTRIB(XonoticServerList, columnMapSize, float, 0)
+       ATTRIB(XonoticServerList, columnTypeOrigin, float, 0)
+       ATTRIB(XonoticServerList, columnTypeSize, float, 0)
+       ATTRIB(XonoticServerList, columnPlayersOrigin, float, 0)
+       ATTRIB(XonoticServerList, columnPlayersSize, float, 0)
+
+       ATTRIB(XonoticServerList, selectedServer, string, string_null) // to restore selected server when needed
+       METHOD(XonoticServerList, setSelected, void(entity, float))
+       METHOD(XonoticServerList, setSortOrder, void(entity, float, float))
+       ATTRIB(XonoticServerList, filterShowEmpty, float, 1)
+       ATTRIB(XonoticServerList, filterShowFull, float, 1)
+       ATTRIB(XonoticServerList, filterString, string, string_null)
+       ATTRIB(XonoticServerList, controlledTextbox, entity, NULL)
+       ATTRIB(XonoticServerList, ipAddressBox, entity, NULL)
+       ATTRIB(XonoticServerList, favoriteButton, entity, NULL)
+       ATTRIB(XonoticServerList, nextRefreshTime, float, 0)
+       METHOD(XonoticServerList, refreshServerList, void(entity, float)) // refresh mode: REFRESHSERVERLIST_*
+       ATTRIB(XonoticServerList, needsRefresh, float, 1)
+       METHOD(XonoticServerList, focusEnter, void(entity))
+       METHOD(XonoticServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))
+       ATTRIB(XonoticServerList, sortButton1, entity, NULL)
+       ATTRIB(XonoticServerList, sortButton2, entity, NULL)
+       ATTRIB(XonoticServerList, sortButton3, entity, NULL)
+       ATTRIB(XonoticServerList, sortButton4, entity, NULL)
+       ATTRIB(XonoticServerList, sortButton5, entity, NULL)
+       ATTRIB(XonoticServerList, connectButton, entity, NULL)
+       ATTRIB(XonoticServerList, infoButton, entity, NULL)
+       ATTRIB(XonoticServerList, currentSortOrder, float, 0)
+       ATTRIB(XonoticServerList, currentSortField, float, -1)
+
+       ATTRIB(XonoticServerList, ipAddressBoxFocused, float, -1)
+
+       ATTRIB(XonoticServerList, seenIPv4, float, 0)
+       ATTRIB(XonoticServerList, seenIPv6, float, 0)
+       ATTRIB(XonoticServerList, categoriesHeight, float, 1.25)
+
+       METHOD(XonoticServerList, getTotalHeight, float(entity))
+       METHOD(XonoticServerList, getItemAtPos, float(entity, float))
+       METHOD(XonoticServerList, getItemStart, float(entity, float))
+       METHOD(XonoticServerList, getItemHeight, float(entity, float))
+ENDCLASS(XonoticServerList)
+entity makeXonoticServerList();
+
+#ifndef IMPLEMENTATION
+float autocvar_menu_slist_categories;
+float autocvar_menu_slist_categories_onlyifmultiple; 
+float autocvar_menu_slist_purethreshold;
+float autocvar_menu_slist_modimpurity;
+float autocvar_menu_slist_recommendations;
+float autocvar_menu_slist_recommendations_maxping;
+float autocvar_menu_slist_recommendations_minfreeslots; 
+float autocvar_menu_slist_recommendations_minhumans;
+float autocvar_menu_slist_recommendations_purethreshold; 
+
+// server cache fields
+#define SLIST_FIELDS \
+       SLIST_FIELD(CNAME,       "cname") \
+       SLIST_FIELD(PING,        "ping") \
+       SLIST_FIELD(GAME,        "game") \
+       SLIST_FIELD(MOD,         "mod") \
+       SLIST_FIELD(MAP,         "map") \
+       SLIST_FIELD(NAME,        "name") \
+       SLIST_FIELD(MAXPLAYERS,  "maxplayers") \
+       SLIST_FIELD(NUMPLAYERS,  "numplayers") \
+       SLIST_FIELD(NUMHUMANS,   "numhumans") \
+       SLIST_FIELD(NUMBOTS,     "numbots") \
+       SLIST_FIELD(PROTOCOL,    "protocol") \
+       SLIST_FIELD(FREESLOTS,   "freeslots") \
+       SLIST_FIELD(PLAYERS,     "players") \
+       SLIST_FIELD(QCSTATUS,    "qcstatus") \
+       SLIST_FIELD(CATEGORY,    "category") \
+       SLIST_FIELD(ISFAVORITE,  "isfavorite")
+
+#define SLIST_FIELD(suffix,name) float SLIST_FIELD_##suffix;
+SLIST_FIELDS
+#undef SLIST_FIELD
+
+const float REFRESHSERVERLIST_RESORT = 0;    // sort the server list again to update for changes to e.g. favorite status, categories
+const float REFRESHSERVERLIST_REFILTER = 1;  // ..., also update filter and sort criteria
+const float REFRESHSERVERLIST_ASK = 2;       // ..., also suggest querying servers now
+const float REFRESHSERVERLIST_RESET = 3;     // ..., also clear the list first
+
+// function declarations
+float IsServerInList(string list, string srv);
+#define IsFavorite(srv) IsServerInList(cvar_string("net_slist_favorites"), srv)
+#define IsPromoted(srv) IsServerInList(_Nex_ExtResponseSystem_PromotedServers, srv)
+#define IsRecommended(srv) IsServerInList(_Nex_ExtResponseSystem_RecommendedServers, srv)
+
+entity RetrieveCategoryEnt(float catnum);
+
+float CheckCategoryOverride(float cat);
+float CheckCategoryForEntry(float entry); 
+float m_gethostcachecategory(float entry) { return CheckCategoryOverride(CheckCategoryForEntry(entry)); }
+
+void RegisterSLCategories();
+
+void ServerList_Connect_Click(entity btn, entity me);
+void ServerList_Categories_Click(entity box, 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);
+void ServerList_Favorite_Click(entity btn, entity me);
+void ServerList_Info_Click(entity btn, entity me);
+void ServerList_Update_favoriteButton(entity btn, entity me);
+
+// fields for category entities
+const float MAX_CATEGORIES = 9;
+const float CATEGORY_FIRST = 1;
+entity categories[MAX_CATEGORIES];
+float category_ent_count;
+.string cat_name;
+.string cat_string;
+.string cat_enoverride_string;
+.string cat_dioverride_string;
+.float cat_enoverride;
+.float cat_dioverride;
+
+// fields for drawing categories
+float category_name[MAX_CATEGORIES];
+float category_item[MAX_CATEGORIES];
+float category_draw_count;
+
+#define SLIST_CATEGORIES \
+       SLIST_CATEGORY(CAT_FAVORITED,    "",            "",             ZCTX(_("SLCAT^Favorites"))) \
+       SLIST_CATEGORY(CAT_RECOMMENDED,  "",            "",             ZCTX(_("SLCAT^Recommended"))) \
+       SLIST_CATEGORY(CAT_NORMAL,       "",            "CAT_SERVERS",  ZCTX(_("SLCAT^Normal Servers"))) \
+       SLIST_CATEGORY(CAT_SERVERS,      "CAT_NORMAL",  "CAT_SERVERS",  ZCTX(_("SLCAT^Servers"))) \
+       SLIST_CATEGORY(CAT_XPM,          "CAT_NORMAL",  "CAT_SERVERS",  ZCTX(_("SLCAT^Competitive Mode"))) \
+       SLIST_CATEGORY(CAT_MODIFIED,     "",            "CAT_SERVERS",  ZCTX(_("SLCAT^Modified Servers"))) \
+       SLIST_CATEGORY(CAT_OVERKILL,     "",            "CAT_SERVERS",  ZCTX(_("SLCAT^Overkill Mode"))) \
+       SLIST_CATEGORY(CAT_INSTAGIB,     "",            "CAT_SERVERS",  ZCTX(_("SLCAT^InstaGib Mode"))) \
+       SLIST_CATEGORY(CAT_DEFRAG,       "",            "CAT_SERVERS",  ZCTX(_("SLCAT^Defrag Mode")))
+
+#define SLIST_CATEGORY_AUTOCVAR(name) autocvar_menu_slist_categories_##name##_override
+#define SLIST_CATEGORY(name,enoverride,dioverride,str) \
+       float name; \
+       var string SLIST_CATEGORY_AUTOCVAR(name) = enoverride;
+SLIST_CATEGORIES
+#undef SLIST_CATEGORY
+
+#endif
+#endif
+#ifdef IMPLEMENTATION
+
+void RegisterSLCategories()
+{
+       entity cat;
+       #define SLIST_CATEGORY(name,enoverride,dioverride,str) \
+               SET_FIELD_COUNT(name, CATEGORY_FIRST, category_ent_count) \
+               CHECK_MAX_COUNT(name, MAX_CATEGORIES, category_ent_count, "SLIST_CATEGORY") \
+               cat = spawn(); \
+               categories[name - 1] = cat; \
+               cat.classname = "slist_category"; \
+               cat.cat_name = strzone(#name); \
+               cat.cat_enoverride_string = strzone(SLIST_CATEGORY_AUTOCVAR(name)); \
+               cat.cat_dioverride_string = strzone(dioverride); \
+               cat.cat_string = strzone(str);
+       SLIST_CATEGORIES
+       #undef SLIST_CATEGORY
+
+       float i, x, catnum;
+       string s;
+
+       #define PROCESS_OVERRIDE(override_string,override_field) \
+               for(i = 0; i < category_ent_count; ++i) \
+               { \
+                       s = categories[i].override_string; \
+                       if((s != "") && (s != categories[i].cat_name)) \
+                       { \
+                               catnum = 0; \
+                               for(x = 0; x < category_ent_count; ++x) \
+                               { if(categories[x].cat_name == s) { \
+                                       catnum = (x+1); \
+                                       break; \
+                               } } \
+                               if(catnum) \
+                               { \
+                                       strunzone(categories[i].override_string); \
+                                       categories[i].override_field = catnum; \
+                                       continue; \
+                               } \
+                               else \
+                               { \
+                                       printf( \
+                                               "RegisterSLCategories(): Improper override '%s' for category '%s'!\n", \
+                                               s, \
+                                               categories[i].cat_name \
+                                       ); \
+                               } \
+                       } \
+                       strunzone(categories[i].override_string); \
+                       categories[i].override_field = 0; \
+               }
+       PROCESS_OVERRIDE(cat_enoverride_string, cat_enoverride)
+       PROCESS_OVERRIDE(cat_dioverride_string, cat_dioverride)
+       #undef PROCESS_OVERRIDE
+}
+
+// Supporting Functions
+entity RetrieveCategoryEnt(float catnum)
+{
+       if((catnum > 0) && (catnum <= category_ent_count))
+       {
+               return categories[catnum - 1];
+       }
+       else
+       {
+               error(sprintf("RetrieveCategoryEnt(%d): Improper category number!\n", catnum));
+               return world;
+       }
+}
+
+float IsServerInList(string list, string srv)
+{
+       string p;
+       float i, n;
+       if(srv == "")
+               return FALSE;
+       srv = netaddress_resolve(srv, 26000);
+       if(srv == "")
+               return FALSE;
+       p = crypto_getidfp(srv);
+       n = tokenize_console(list);
+       for(i = 0; i < n; ++i)
+       {
+               if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
+               {
+                       if(p)
+                               if(argv(i) == p)
+                                       return TRUE;
+               }
+               else
+               {
+                       if(srv == netaddress_resolve(argv(i), 26000))
+                               return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+float CheckCategoryOverride(float cat)
+{
+       entity catent = RetrieveCategoryEnt(cat);
+       if(catent)
+       {
+               float override = (autocvar_menu_slist_categories ? catent.cat_enoverride : catent.cat_dioverride); 
+               if(override) { return override; }
+               else { return cat; }
+       }
+       else
+       {
+               error(sprintf("CheckCategoryOverride(%d): Improper category number!\n", cat));
+               return cat;
+       }
+}
+
+float CheckCategoryForEntry(float entry)
+{
+       string s, k, v, modtype = "";
+       float j, m, impure = 0, freeslots = 0, sflags = 0;
+       s = gethostcachestring(SLIST_FIELD_QCSTATUS, entry);
+       m = tokenizebyseparator(s, ":");
+
+       for(j = 2; j < m; ++j)
+       {
+               if(argv(j) == "") { break; }
+               k = substring(argv(j), 0, 1);
+               v = substring(argv(j), 1, -1);
+               switch(k)
+               {
+                       case "P": { impure = stof(v); break; }
+                       case "S": { freeslots = stof(v); break; }
+                       case "F": { sflags = stof(v); break; }
+                       case "M": { modtype = strtolower(v); break; }
+               }
+       }
+
+       if(modtype != "xonotic") { impure += autocvar_menu_slist_modimpurity; }
+
+       // check if this server is favorited
+       if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, entry)) { return CAT_FAVORITED; }
+
+       // now check if it's recommended
+       if(autocvar_menu_slist_recommendations)
+       {
+               string cname = gethostcachestring(SLIST_FIELD_CNAME, entry);
+               
+               if(IsPromoted(cname)) { return CAT_RECOMMENDED; }
+               else
+               {
+                       float recommended = 0;
+                       if(autocvar_menu_slist_recommendations & 1)
+                       {
+                               if(IsRecommended(cname)) { ++recommended; }
+                               else { --recommended; }
+                       }
+                       if(autocvar_menu_slist_recommendations & 2)
+                       {
+                               if(
+                                       ///// check for minimum free slots
+                                       (freeslots >= autocvar_menu_slist_recommendations_minfreeslots)
+                                       
+                                       && // check for purity requirement
+                                       (
+                                               (autocvar_menu_slist_recommendations_purethreshold < 0)
+                                               ||
+                                               (impure <= autocvar_menu_slist_recommendations_purethreshold)
+                                       )
+                                       
+                                       && // check for minimum amount of humans
+                                       (
+                                               gethostcachenumber(SLIST_FIELD_NUMHUMANS, entry)
+                                               >=
+                                               autocvar_menu_slist_recommendations_minhumans
+                                       )
+                                       
+                                       && // check for maximum latency
+                                       (
+                                               gethostcachenumber(SLIST_FIELD_PING, entry)
+                                               <=
+                                               autocvar_menu_slist_recommendations_maxping
+                                       )
+                               )
+                                       { ++recommended; }
+                               else
+                                       { --recommended; }
+                       }
+                       if(recommended > 0) { return CAT_RECOMMENDED; }
+               }
+       }
+
+       // if not favorited or recommended, check modname
+       if(modtype != "xonotic")
+       {
+               switch(modtype)
+               {
+                       // old servers which don't report their mod name are considered modified now
+                       case "": { return CAT_MODIFIED; }
+                       
+                       case "xpm": { return CAT_XPM; }
+                       case "minstagib":
+                       case "instagib": { return CAT_INSTAGIB; }
+                       case "overkill": { return CAT_OVERKILL; }
+                       //case "nix": { return CAT_NIX; }
+                       //case "newtoys": { return CAT_NEWTOYS; }
+
+                       // "cts" is allowed as compat, xdf is replacement
+                       case "cts": 
+                       case "xdf": { return CAT_DEFRAG; }
+                       
+                       default: { dprintf("Found strange mod type: %s\n", modtype); return CAT_MODIFIED; }
+               }
+       }
+
+       // must be normal or impure server
+       return ((impure > autocvar_menu_slist_purethreshold) ? CAT_MODIFIED : CAT_NORMAL);
+}
+
+void XonoticServerList_toggleFavorite(entity me, string srv)
+{
+       string s, s0, s1, s2, srv_resolved, p;
+       float i, n, f;
+       srv_resolved = netaddress_resolve(srv, 26000);
+       p = crypto_getidfp(srv_resolved);
+       s = cvar_string("net_slist_favorites");
+       n = tokenize_console(s);
+       f = 0;
+       for(i = 0; i < n; ++i)
+       {
+               if(substring(argv(i), 0, 1) != "[" && strlen(argv(i)) == 44 && strstrofs(argv(i), ".", 0) < 0)
+               {
+                       if(p)
+                               if(argv(i) != p)
+                                       continue;
+               }
+               else
+               {
+                       if(srv_resolved != netaddress_resolve(argv(i), 26000))
+                               continue;
+               }
+               s0 = s1 = s2 = "";
+               if(i > 0)
+                       s0 = substring(s, 0, argv_end_index(i - 1));
+               if(i < n-1)
+                       s2 = substring(s, argv_start_index(i + 1), -1);
+               if(s0 != "" && s2 != "")
+                       s1 = " ";
+               cvar_set("net_slist_favorites", strcat(s0, s1, s2));
+               s = cvar_string("net_slist_favorites");
+               n = tokenize_console(s);
+               f = 1;
+               --i;
+       }
+
+       if(!f)
+       {
+               s1 = "";
+               if(s != "")
+                       s1 = " ";
+               if(p)
+                       cvar_set("net_slist_favorites", strcat(s, s1, p));
+               else
+                       cvar_set("net_slist_favorites", strcat(s, s1, srv));
+       }
+
+       me.refreshServerList(me, REFRESHSERVERLIST_RESORT);
+}
+
+void ServerList_Update_favoriteButton(entity btn, entity me)
+{
+       me.favoriteButton.setText(me.favoriteButton,
+               (IsFavorite(me.ipAddressBox.text) ?
+                       _("Remove") : _("Favorite")
+               )
+       );
+}
+
+entity makeXonoticServerList()
+{
+       entity me;
+       me = spawnXonoticServerList();
+       me.configureXonoticServerList(me);
+       return me;
+}
+void XonoticServerList_configureXonoticServerList(entity me)
+{
+       me.configureXonoticListBox(me);
+
+       // update field ID's
+       #define SLIST_FIELD(suffix,name) SLIST_FIELD_##suffix = gethostcacheindexforkey(name);
+       SLIST_FIELDS
+       #undef SLIST_FIELD
+
+       // clear list
+       me.nItems = 0;
+}
+void XonoticServerList_setSelected(entity me, float i)
+{
+       float save;
+       save = me.selectedItem;
+       SUPER(XonoticServerList).setSelected(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));
+
+       me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
+       me.ipAddressBox.cursorPos = strlen(me.selectedServer);
+       me.ipAddressBoxFocused = -1;
+}
+void XonoticServerList_refreshServerList(entity me, float mode)
+{
+       //print("refresh of type ", ftos(mode), "\n");
+
+       if(mode >= REFRESHSERVERLIST_REFILTER)
+       {
+               float m, i, n;
+               float listflags = 0;
+               string s, typestr, modstr;
+
+               s = me.filterString;
+
+               m = strstrofs(s, ":", 0);
+               if(m >= 0)
+               {
+                       typestr = substring(s, 0, m);
+                       s = substring(s, m + 1, strlen(s) - m - 1);
+                       while(substring(s, 0, 1) == " ")
+                               s = substring(s, 1, strlen(s) - 1);
+               }
+               else
+                       typestr = "";
+
+               modstr = cvar_string("menu_slist_modfilter");
+
+               m = SLIST_MASK_AND - 1;
+               resethostcachemasks();
+
+               // ping: reject negative ping (no idea why this happens in the first place, engine bug)
+               sethostcachemasknumber(++m, SLIST_FIELD_PING, 0, SLIST_TEST_GREATEREQUAL);
+
+               // show full button
+               if(!me.filterShowFull)
+               {
+                       sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL); // legacy
+                       sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, ":S0:", SLIST_TEST_NOTCONTAIN); // g_maxplayers support
+               }
+
+               // show empty button
+               if(!me.filterShowEmpty)
+                       sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
+
+               // gametype filtering
+               if(typestr != "")
+                       sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);
+
+               // mod filtering
+               if(modstr != "")
+               {
+                       if(substring(modstr, 0, 1) == "!")
+                               sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);
+                       else
+                               sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);
+               }
+
+               // server banning
+               n = tokenizebyseparator(_Nex_ExtResponseSystem_BannedServers, " ");
+               for(i = 0; i < n; ++i)
+                       if(argv(i) != "")
+                               sethostcachemaskstring(++m, SLIST_FIELD_CNAME, argv(i), SLIST_TEST_NOTSTARTSWITH);
+
+               m = SLIST_MASK_OR - 1;
+               if(s != "")
+               {
+                       sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);
+                       sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);
+                       sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);
+                       sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);
+               }
+
+               // sorting flags
+               //listflags |= SLSF_FAVORITES;
+               listflags |= SLSF_CATEGORIES;
+               if(me.currentSortOrder < 0) { listflags |= SLSF_DESCENDING; }
+               sethostcachesort(me.currentSortField, listflags);
+       }
+       
+       resorthostcache();
+       if(mode >= REFRESHSERVERLIST_ASK)
+               refreshhostcache(mode >= REFRESHSERVERLIST_RESET);
+}
+void XonoticServerList_focusEnter(entity me)
+{
+       if(time < me.nextRefreshTime)
+       {
+               //print("sorry, no refresh yet\n");
+               return;
+       }
+       me.nextRefreshTime = time + 10;
+       me.refreshServerList(me, REFRESHSERVERLIST_ASK);
+}
+
+void XonoticServerList_draw(entity me)
+{
+       float i, found, owned;
+
+       if(_Nex_ExtResponseSystem_BannedServersNeedsRefresh)
+       {
+               if(!me.needsRefresh)
+                       me.needsRefresh = 2;
+               _Nex_ExtResponseSystem_BannedServersNeedsRefresh = 0;
+       }
+
+       if(_Nex_ExtResponseSystem_PromotedServersNeedsRefresh)
+       {
+               if(!me.needsRefresh)
+                       me.needsRefresh = 3;
+               _Nex_ExtResponseSystem_PromotedServersNeedsRefresh = 0;
+       }
+
+       if(_Nex_ExtResponseSystem_RecommendedServersNeedsRefresh)
+       {
+               if(!me.needsRefresh)
+                       me.needsRefresh = 3;
+               _Nex_ExtResponseSystem_RecommendedServersNeedsRefresh = 0;
+       }
+
+       if(me.currentSortField == -1)
+       {
+               me.setSortOrder(me, SLIST_FIELD_PING, +1);
+               me.refreshServerList(me, REFRESHSERVERLIST_RESET);
+       }
+       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, REFRESHSERVERLIST_REFILTER);
+       }
+       else if(me.needsRefresh == 3)
+       {
+               me.needsRefresh = 0;
+               me.refreshServerList(me, REFRESHSERVERLIST_RESORT);
+       }
+
+       owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));
+
+       for(i = 0; i < category_draw_count; ++i) { category_name[i] = -1; category_item[i] = -1; }
+       category_draw_count = 0;
+
+       if(autocvar_menu_slist_categories >= 0) // if less than 0, don't even draw a category heading for favorites
+       {
+               float itemcount = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
+               me.nItems = itemcount;
+               
+               //float visible = floor(me.scrollPos / me.itemHeight);
+               // ^ unfortunately no such optimization can be made-- we must process through the
+               // entire list, otherwise there is no way to know which item is first in its category.
+
+               // binary search method suggested by div
+               float x;
+               float begin = 0;
+               for(x = 1; x <= category_ent_count; ++x) {
+                       float first = begin;
+                       float last = (itemcount - 1);
+                       if (first > last) {
+                               // List is empty.
+                               break;
+                       }
+                       float catf = gethostcachenumber(SLIST_FIELD_CATEGORY, first);
+                       float catl = gethostcachenumber(SLIST_FIELD_CATEGORY, last);
+                       if (catf > x) {
+                               // The first one is already > x.
+                               // Therefore, category x does not exist.
+                               // Higher numbered categories do exist though.
+                       } else if (catl < x) {
+                               // The last one is < x.
+                               // Thus this category - and any following -
+                               // don't exist.
+                               break;
+                       } else if (catf == x) {
+                               // Starts at first. This breaks the loop
+                               // invariant in the binary search and thus has
+                               // to be handled separately.
+                               if(gethostcachenumber(SLIST_FIELD_CATEGORY, first) != x)
+                                       error("Category mismatch I");
+                               if(first > 0)
+                                       if(gethostcachenumber(SLIST_FIELD_CATEGORY, first - 1) == x)
+                                               error("Category mismatch II");
+                               category_name[category_draw_count] = x;
+                               category_item[category_draw_count] = first;
+                               ++category_draw_count;
+                               begin = first + 1;
+                       } else {
+                               // At this point, catf <= x < catl, thus
+                               // catf < catl, thus first < last.
+                               // INVARIANTS:
+                               // last - first >= 1
+                               // catf == gethostcachenumber(SLIST_FIELD_CATEGORY(first)
+                               // catl == gethostcachenumber(SLIST_FIELD_CATEGORY(last)
+                               // catf < x
+                               // catl >= x
+                               while (last - first > 1) {
+                                       float middle = floor((first + last) / 2);
+                                       // By loop condition, middle != first && middle != last.
+                                       float cat = gethostcachenumber(SLIST_FIELD_CATEGORY, middle);
+                                       if (cat >= x) {
+                                               last = middle;
+                                               catl = cat;
+                                       } else {
+                                               first = middle;
+                                               catf = cat;
+                                       }
+                               }
+                               if (catl == x) {
+                                       if(gethostcachenumber(SLIST_FIELD_CATEGORY, last) != x)
+                                               error("Category mismatch III");
+                                       if(last > 0)
+                                               if(gethostcachenumber(SLIST_FIELD_CATEGORY, last - 1) == x)
+                                                       error("Category mismatch IV");
+                                       category_name[category_draw_count] = x;
+                                       category_item[category_draw_count] = last;
+                                       ++category_draw_count;
+                                       begin = last + 1; // already scanned through these, skip 'em
+                               }
+                               else
+                                       begin = last; // already scanned through these, skip 'em
+                       }
+               }
+               if(autocvar_menu_slist_categories_onlyifmultiple && (category_draw_count == 1))
+               {
+                       category_name[0] = -1;
+                       category_item[0] = -1;
+                       category_draw_count = 0;
+                       me.nItems = itemcount;
+               }
+       }
+       else { me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT); }
+
+       me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
+       me.infoButton.disabled = ((me.nItems == 0) || !owned);
+       me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
+
+       found = 0;
+       if(me.selectedServer)
+       {
+               for(i = 0; i < me.nItems; ++i)
+               {
+                       if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
+                       {
+                               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));
+               }
+       }
+       
+       if(owned)
+       {
+               if(me.selectedServer != me.ipAddressBox.text)
+               {
+                       me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
+                       me.ipAddressBox.cursorPos = strlen(me.selectedServer);
+                       me.ipAddressBoxFocused = -1;
+               }
+       }
+
+       if(me.ipAddressBoxFocused != me.ipAddressBox.focused)
+       {
+               if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)
+                       ServerList_Update_favoriteButton(NULL, me);
+               me.ipAddressBoxFocused = me.ipAddressBox.focused;
+       }
+
+       SUPER(XonoticServerList).draw(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_TypeSort_Click(entity btn, entity me)
+{
+       string s, t;
+       float i, m;
+       s = me.filterString;
+       m = strstrofs(s, ":", 0);
+       if(m >= 0)
+       {
+               s = substring(s, 0, m);
+               while(substring(s, m+1, 1) == " ") // skip spaces
+                       ++m;
+       }
+       else
+               s = "";
+
+       for(i = 1; ; i *= 2) // 20 modes ought to be enough for anyone
+       {
+               t = MapInfo_Type_ToString(i);
+               if(i > 1)
+                       if(t == "") // it repeats (default case)
+                       {
+                               // no type was found
+                               // choose the first one
+                               s = MapInfo_Type_ToString(1);
+                               break;
+                       }
+               if(s == t)
+               {
+                       // the type was found
+                       // choose the next one
+                       s = MapInfo_Type_ToString(i * 2);
+                       if(s == "")
+                               s = MapInfo_Type_ToString(1);
+                       break;
+               }
+       }
+
+       if(s != "")
+               s = strcat(s, ":");
+       s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));
+
+       me.controlledTextbox.setText(me.controlledTextbox, s);
+       me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);
+       me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);
+       //ServerList_Filter_Change(me.controlledTextbox, me);
+}
+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, REFRESHSERVERLIST_REFILTER);
+
+       me.ipAddressBox.setText(me.ipAddressBox, "");
+       me.ipAddressBox.cursorPos = 0;
+       me.ipAddressBoxFocused = -1;
+}
+void ServerList_Categories_Click(entity box, entity me)
+{
+       box.setChecked(box, autocvar_menu_slist_categories = !autocvar_menu_slist_categories);
+       me.refreshServerList(me, REFRESHSERVERLIST_RESORT);
+
+       me.ipAddressBox.setText(me.ipAddressBox, "");
+       me.ipAddressBox.cursorPos = 0;
+       me.ipAddressBoxFocused = -1;
+}
+void ServerList_ShowEmpty_Click(entity box, entity me)
+{
+       box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);
+       me.refreshServerList(me, REFRESHSERVERLIST_REFILTER);
+
+       me.ipAddressBox.setText(me.ipAddressBox, "");
+       me.ipAddressBox.cursorPos = 0;
+       me.ipAddressBoxFocused = -1;
+}
+void ServerList_ShowFull_Click(entity box, entity me)
+{
+       box.setChecked(box, me.filterShowFull = !me.filterShowFull);
+       me.refreshServerList(me, REFRESHSERVERLIST_REFILTER);
+
+       me.ipAddressBox.setText(me.ipAddressBox, "");
+       me.ipAddressBox.cursorPos = 0;
+       me.ipAddressBoxFocused = -1;
+}
+void XonoticServerList_setSortOrder(entity me, float fld, float direction)
+{
+       if(me.currentSortField == fld)
+               direction = -me.currentSortOrder;
+       me.currentSortOrder = direction;
+       me.currentSortField = fld;
+       me.sortButton1.forcePressed = (fld == SLIST_FIELD_PING);
+       me.sortButton2.forcePressed = (fld == SLIST_FIELD_NAME);
+       me.sortButton3.forcePressed = (fld == SLIST_FIELD_MAP);
+       me.sortButton4.forcePressed = 0;
+       me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
+       me.selectedItem = 0;
+       if(me.selectedServer)
+               strunzone(me.selectedServer);
+       me.selectedServer = string_null;
+       me.refreshServerList(me, REFRESHSERVERLIST_REFILTER);
+}
+void XonoticServerList_positionSortButton(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 XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(XonoticServerList).resizeNotify(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.columnIconsOrigin = 0;
+       me.columnIconsSize = me.realFontSize_x * 4 * me.iconsSizeFactor;
+       me.columnPingSize = me.realFontSize_x * 3;
+       me.columnMapSize = me.realFontSize_x * 10;
+       me.columnTypeSize = me.realFontSize_x * 4;
+       me.columnPlayersSize = me.realFontSize_x * 5;
+       me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnIconsSize - me.columnTypeSize - 5 * me.realFontSize_x;
+       me.columnPingOrigin = me.columnIconsOrigin + me.columnIconsSize + me.realFontSize_x;
+       me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
+       me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
+       me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
+       me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + 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.columnTypeOrigin, me.columnTypeSize, _("Type"), ServerList_TypeSort_Click);
+       me.positionSortButton(me, me.sortButton5, 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)
+{
+       localcmd(sprintf("connect %s\n",
+               ((me.ipAddressBox.text != "") ?
+                       me.ipAddressBox.text : me.selectedServer
+               )
+       ));
+}
+void ServerList_Favorite_Click(entity btn, entity me)
+{
+       string ipstr;
+       ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);
+       if(ipstr != "")
+       {
+               me.toggleFavorite(me, me.ipAddressBox.text);
+               me.ipAddressBoxFocused = -1;
+       }
+}
+void ServerList_Info_Click(entity btn, entity me)
+{
+       if (me.nItems != 0)
+               main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
+
+       vector org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
+       vector sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
+       DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
+}
+void XonoticServerList_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       ServerList_Connect_Click(NULL, me);
+}
+void XonoticServerList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       // layout: Ping, Server name, Map name, NP, TP, MP
+       float p, q;
+       float isv4, isv6;
+       vector theColor;
+       float theAlpha;
+       float m, pure, freeslots, j, sflags;
+       string s, typestr, versionstr, k, v, modname;
+
+       //printf("time: %f, i: %d, item: %d, nitems: %d\n", time, i, item, me.nItems);
+
+       vector oldscale = draw_scale;
+       vector oldshift = draw_shift;
+#define SET_YRANGE(start,end) \
+       draw_scale = boxToGlobalSize(eX * 1 + eY * (end - start), oldscale); \
+       draw_shift = boxToGlobal(eY * start, oldshift, oldscale);
+
+       for (j = 0; j < category_draw_count; ++j) {
+               // Matches exactly the headings with increased height.
+               if (i == category_item[j])
+                       break;
+       }
+
+       if (j < category_draw_count)
+       {
+               entity catent = RetrieveCategoryEnt(category_name[j]);
+               if(catent)
+               {
+                       SET_YRANGE(
+                               (me.categoriesHeight - 1) / (me.categoriesHeight + 1),
+                               me.categoriesHeight / (me.categoriesHeight + 1)
+                       );
+                       draw_Text(
+                               eY * me.realUpperMargin
+                               +
+#if 0
+                               eX * (me.columnNameOrigin + (me.columnNameSize - draw_TextWidth(catent.cat_string, 0, me.realFontSize)) * 0.5),
+                               catent.cat_string,
+#else
+                               eX * (me.columnNameOrigin),
+                               strcat(catent.cat_string, ":"),
+#endif
+                               me.realFontSize,
+                               SKINCOLOR_SERVERLIST_CATEGORY,
+                               SKINALPHA_SERVERLIST_CATEGORY,
+                               0
+                       );
+                       SET_YRANGE(me.categoriesHeight / (me.categoriesHeight + 1), 1);
+               }
+       }
+       
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);
+       m = tokenizebyseparator(s, ":");
+       typestr = "";
+       if(m >= 2)
+       {
+               typestr = argv(0);
+               versionstr = argv(1);
+       }
+       freeslots = -1;
+       sflags = -1;
+       modname = "";
+       pure = 0;
+       for(j = 2; j < m; ++j)
+       {
+               if(argv(j) == "")
+                       break;
+               k = substring(argv(j), 0, 1);
+               v = substring(argv(j), 1, -1);
+               if(k == "P")
+                       pure = stof(v);
+               else if(k == "S")
+                       freeslots = stof(v);
+               else if(k == "F")
+                       sflags = stof(v);
+               else if(k == "M")
+                       modname = v;
+       }
+
+#ifdef COMPAT_NO_MOD_IS_XONOTIC
+       if(modname == "")
+               modname = "Xonotic";
+#endif
+
+       /*
+       SLIST_FIELD_MOD = gethostcacheindexforkey("mod");
+       s = gethostcachestring(SLIST_FIELD_MOD, i);
+       if(s != "data")
+               if(modname == "Xonotic")
+                       modname = s;
+       */
+
+       // list the mods here on which the pure server check actually works
+       if(modname != "Xonotic")
+       if(modname != "InstaGib" || modname != "MinstaGib")
+       if(modname != "CTS")
+       if(modname != "NIX")
+       if(modname != "NewToys")
+               pure = 0;
+
+       if(gethostcachenumber(SLIST_FIELD_FREESLOTS, i) <= 0)
+               theAlpha = SKINALPHA_SERVERLIST_FULL;
+       else if(freeslots == 0)
+               theAlpha = SKINALPHA_SERVERLIST_FULL; // g_maxplayers support
+       else if (!gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
+               theAlpha = SKINALPHA_SERVERLIST_EMPTY;
+       else
+               theAlpha = 1;
+
+       p = gethostcachenumber(SLIST_FIELD_PING, i);
+       const float PING_LOW = 75;
+       const float PING_MED = 200;
+       const float PING_HIGH = 500;
+       if(p < PING_LOW)
+               theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);
+       else if(p < PING_MED)
+               theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));
+       else if(p < PING_HIGH)
+       {
+               theColor = SKINCOLOR_SERVERLIST_HIGHPING;
+               theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));
+       }
+       else
+       {
+               theColor = eX;
+               theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;
+       }
+
+       if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))
+       {
+               theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;
+               theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;
+       }
+
+       s = gethostcachestring(SLIST_FIELD_CNAME, i);
+
+       isv4 = isv6 = 0;
+       if(substring(s, 0, 1) == "[")
+       {
+               isv6 = 1;
+               me.seenIPv6 += 1;
+       }
+       else if(strstrofs("0123456789", substring(s, 0, 1), 0) >= 0)
+       {
+               isv4 = 1;
+               me.seenIPv4 += 1;
+       }
+
+       q = stof(substring(crypto_getencryptlevel(s), 0, 1));
+       if((q <= 0 && cvar("crypto_aeslevel") >= 3) || (q >= 3 && cvar("crypto_aeslevel") <= 0))
+       {
+               theColor = SKINCOLOR_SERVERLIST_IMPOSSIBLE;
+               theAlpha = SKINALPHA_SERVERLIST_IMPOSSIBLE;
+       }
+
+       if(q == 1)
+       {
+               if(cvar("crypto_aeslevel") >= 2)
+                       q |= 4;
+       }
+       if(q == 2)
+       {
+               if(cvar("crypto_aeslevel") >= 1)
+                       q |= 4;
+       }
+       if(q == 3)
+               q = 5;
+       else if(q >= 3)
+               q -= 2;
+       // possible status:
+       // 0: crypto off
+       // 1: AES possible
+       // 2: AES recommended but not available
+       // 3: AES possible and will be used
+       // 4: AES recommended and will be used
+       // 5: AES required
+
+       // --------------
+       //  RENDER ICONS
+       // --------------
+       vector iconSize = '0 0 0';
+       iconSize_y = me.realFontSize_y * me.iconsSizeFactor;
+       iconSize_x = me.realFontSize_x * me.iconsSizeFactor;
+
+       vector iconPos = '0 0 0';
+       iconPos_x = (me.columnIconsSize - 3 * iconSize_x) * 0.5;
+       iconPos_y = (1 - iconSize_y) * 0.5;
+
+       string n;
+
+       if (!(me.seenIPv4 && me.seenIPv6))
+       {
+               iconPos_x += iconSize_x * 0.5;
+       }
+       else if(me.seenIPv4 && me.seenIPv6)
+       {
+               n = string_null;
+               if(isv6)
+                       draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv6"), 0); // PRECACHE_PIC_MIPMAP
+               else if(isv4)
+                       draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_ipv4"), 0); // PRECACHE_PIC_MIPMAP
+               if(n)
+                       draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
+               iconPos_x += iconSize_x;
+       }
+
+       if(q > 0)
+       {
+               draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_aeslevel", ftos(q)), 0); // PRECACHE_PIC_MIPMAP
+               draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
+       }
+       iconPos_x += iconSize_x;
+
+       if(modname == "Xonotic")
+       {
+               if(pure == 0)
+               {
+                       draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_pure1"), PRECACHE_PIC_MIPMAP);
+                       draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
+               }
+       }
+       else
+       {
+               draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_", modname), PRECACHE_PIC_MIPMAP);
+               if(draw_PictureSize(n) == '0 0 0')
+                       draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_mod_"), PRECACHE_PIC_MIPMAP);
+               if(pure == 0)
+                       draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
+               else
+                       draw_Picture(iconPos, n, iconSize, '1 1 1', SKINALPHA_SERVERLIST_ICON_NONPURE);
+       }
+       iconPos_x += iconSize_x;
+
+       if(sflags >= 0 && (sflags & SERVERFLAG_PLAYERSTATS))
+       {
+               draw_PreloadPictureWithFlags(n = strcat(SKINGFX_SERVERLIST_ICON, "_stats1"), 0); // PRECACHE_PIC_MIPMAP
+               draw_Picture(iconPos, n, iconSize, '1 1 1', 1);
+       }
+       iconPos_x += iconSize_x;
+       
+       // --------------
+       //  RENDER TEXT
+       // --------------
+       
+       // ping
+       s = ftos(p);
+       draw_Text(me.realUpperMargin * eY + (me.columnPingOrigin + me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);
+
+       // server name
+       s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
+
+       // server map
+       s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
+
+       // server gametype
+       s = draw_TextShortenToWidth(typestr, me.columnTypeSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
+
+       // server playercount
+       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)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);
+}
+
+float XonoticServerList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       vector org, sz;
+
+       org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);
+       sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);
+
+       if(scan == K_ENTER || scan == K_KP_ENTER)
+       {
+               ServerList_Connect_Click(NULL, me);
+               return 1;
+       }
+       else if(scan == K_MOUSE2 || scan == K_SPACE)
+       {
+               if(me.nItems != 0)
+               {
+                       main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);
+                       DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);
+                       return 1;
+               }
+               return 0;
+       }
+       else if(scan == K_INS || scan == K_MOUSE3 || scan == K_KP_INS)
+       {
+               if(me.nItems != 0)
+               {
+                       me.toggleFavorite(me, me.selectedServer);
+                       me.ipAddressBoxFocused = -1;
+                       return 1;
+               }
+               return 0;
+       }
+       else if(SUPER(XonoticServerList).keyDown(me, scan, ascii, shift))
+               return 1;
+       else if(!me.controlledTextbox)
+               return 0;
+       else
+               return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);
+}
+
+float XonoticServerList_getTotalHeight(entity me) {
+       float num_normal_rows = me.nItems;
+       float num_headers = category_draw_count;
+       return me.itemHeight * (num_normal_rows + me.categoriesHeight * num_headers);
+}
+float XonoticServerList_getItemAtPos(entity me, float pos) {
+       pos = pos / me.itemHeight;
+       float i;
+       for (i = category_draw_count - 1; i >= 0; --i) {
+               float itemidx = category_item[i];
+               float itempos = i * me.categoriesHeight + category_item[i];
+               if (pos >= itempos + me.categoriesHeight + 1)
+                       return itemidx + 1 + floor(pos - (itempos + me.categoriesHeight + 1));
+               if (pos >= itempos)
+                       return itemidx;
+       }
+       // No category matches? Note that category 0 is... 0. Therefore no headings exist at all.
+       return floor(pos);
+}
+float XonoticServerList_getItemStart(entity me, float item) {
+       float i;
+       for (i = category_draw_count - 1; i >= 0; --i) {
+               float itemidx = category_item[i];
+               float itempos = i * me.categoriesHeight + category_item[i];
+               if (item >= itemidx + 1)
+                       return (itempos + me.categoriesHeight + 1 + item - (itemidx + 1)) * me.itemHeight;
+               if (item >= itemidx)
+                       return itempos * me.itemHeight;
+       }
+       // No category matches? Note that category 0 is... 0. Therefore no headings exist at all.
+       return item * me.itemHeight;
+}
+float XonoticServerList_getItemHeight(entity me, float item) {
+       float i;
+       for (i = 0; i < category_draw_count; ++i) {
+               // Matches exactly the headings with increased height.
+               if (item == category_item[i])
+                       return me.itemHeight * (me.categoriesHeight + 1);
+       }
+       return me.itemHeight;
+}
+
+#endif
diff --git a/qcsrc/menu/xonotic/skinlist.c b/qcsrc/menu/xonotic/skinlist.c
deleted file mode 100644 (file)
index 6d11fe9..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticSkinList) EXTENDS(XonoticListBox)
-       METHOD(XonoticSkinList, configureXonoticSkinList, void(entity))
-       ATTRIB(XonoticSkinList, rowsPerItem, float, 4)
-       METHOD(XonoticSkinList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticSkinList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticSkinList, getSkins, void(entity))
-       METHOD(XonoticSkinList, setSkin, void(entity))
-       METHOD(XonoticSkinList, loadCvars, void(entity))
-       METHOD(XonoticSkinList, saveCvars, void(entity))
-       METHOD(XonoticSkinList, skinParameter, string(entity, float, float))
-       METHOD(XonoticSkinList, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticSkinList, keyDown, float(entity, float, float, float))
-       METHOD(XonoticSkinList, destroy, void(entity))
-
-       ATTRIB(XonoticSkinList, skinlist, float, -1)
-       ATTRIB(XonoticSkinList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticSkinList, columnPreviewOrigin, float, 0)
-       ATTRIB(XonoticSkinList, columnPreviewSize, float, 0)
-       ATTRIB(XonoticSkinList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticSkinList, columnNameSize, float, 0)
-       ATTRIB(XonoticSkinList, realUpperMargin1, float, 0)
-       ATTRIB(XonoticSkinList, realUpperMargin2, float, 0)
-       ATTRIB(XonoticSkinList, origin, vector, '0 0 0')
-       ATTRIB(XonoticSkinList, itemAbsSize, vector, '0 0 0')
-
-       ATTRIB(XonoticSkinList, name, string, "skinselector")
-ENDCLASS(XonoticSkinList)
-
-entity makeXonoticSkinList();
-void SetSkin_Click(entity btn, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-
-const float SKINPARM_NAME = 0;
-const float SKINPARM_TITLE = 1;
-const float SKINPARM_AUTHOR = 2;
-const float SKINPARM_PREVIEW = 3;
-const float SKINPARM_COUNT = 4;
-
-entity makeXonoticSkinList()
-{
-       entity me;
-       me = spawnXonoticSkinList();
-       me.configureXonoticSkinList(me);
-       return me;
-}
-
-void XonoticSkinList_configureXonoticSkinList(entity me)
-{
-       me.configureXonoticListBox(me);
-       me.getSkins(me);
-       me.loadCvars(me);
-}
-
-void XonoticSkinList_loadCvars(entity me)
-{
-       string s;
-       float i, n;
-       s = cvar_string("menu_skin");
-       n = me.nItems;
-       for(i = 0; i < n; ++i)
-       {
-               if(me.skinParameter(me, i, SKINPARM_NAME) == s)
-               {
-                       me.selectedItem = i;
-                       break;
-               }
-       }
-}
-
-void XonoticSkinList_saveCvars(entity me)
-{
-       cvar_set("menu_skin", me.skinParameter(me, me.selectedItem, SKINPARM_NAME));
-}
-
-string XonoticSkinList_skinParameter(entity me, float i, float key)
-{
-       return bufstr_get(me.skinlist, i * SKINPARM_COUNT + key);
-}
-
-void XonoticSkinList_getSkins(entity me)
-{
-       float glob, buf, i, n, fh;
-       string s;
-
-       buf = buf_create();
-       glob = search_begin("gfx/menu/*/skinvalues.txt", TRUE, TRUE);
-       if(glob < 0)
-       {
-               me.skinlist = buf;
-               me.nItems = 0;
-               return;
-       }
-
-       n = search_getsize(glob);
-       for(i = 0; i < n; ++i)
-       {
-               s = search_getfilename(glob, i);
-               bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_NAME, substring(s, 9, strlen(s) - 24)); // the * part
-               bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_TITLE, _("<TITLE>"));
-               bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_AUTHOR, _("<AUTHOR>"));
-               if(draw_PictureSize(strcat("/gfx/menu/", substring(s, 9, strlen(s) - 24), "/skinpreview")) == '0 0 0')
-                       bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_PREVIEW, "nopreview_menuskin");
-               else
-                       bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_PREVIEW, strcat("/gfx/menu/", substring(s, 9, strlen(s) - 24), "/skinpreview"));
-               fh = fopen(language_filename(s), FILE_READ);
-               if(fh < 0)
-               {
-                       print("Warning: can't open skinvalues.txt file\n");
-                       continue;
-               }
-               while((s = fgets(fh)))
-               {
-                       // these two are handled by skinlist.qc
-                       if(substring(s, 0, 6) == "title ")
-                               bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_TITLE, substring(s, 6, strlen(s) - 6));
-                       else if(substring(s, 0, 7) == "author ")
-                               bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_AUTHOR, substring(s, 7, strlen(s) - 7));
-               }
-               fclose(fh);
-       }
-
-       search_end(glob);
-
-       me.skinlist = buf;
-       me.nItems = n;
-}
-
-void XonoticSkinList_destroy(entity me)
-{
-       buf_del(me.skinlist);
-}
-
-void XonoticSkinList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemAbsSize = '0 0 0';
-       SUPER(XonoticSkinList).resizeNotify(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;
-}
-
-void XonoticSkinList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string s;
-
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-
-       s = me.skinParameter(me, i, SKINPARM_PREVIEW);
-       draw_Picture(me.columnPreviewOrigin * eX, s, me.columnPreviewSize * eX + eY, '1 1 1', 1);
-
-       s = me.skinParameter(me, i, SKINPARM_TITLE);
-       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_SKINLIST_TITLE, SKINALPHA_TEXT, 0);
-
-       s = me.skinParameter(me, i, SKINPARM_AUTHOR);
-       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin2 * eY + (me.columnNameOrigin + 1.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_SKINLIST_AUTHOR, SKINALPHA_TEXT, 0);
-}
-
-void XonoticSkinList_setSkin(entity me)
-{
-       me.saveCvars(me);
-       localcmd("\nmenu_restart\nmenu_cmd skinselect\n");
-}
-
-void SetSkin_Click(entity btn, entity me)
-{
-       me.setSkin(me);
-}
-
-void XonoticSkinList_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       me.setSkin(me);
-}
-
-float XonoticSkinList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if(scan == K_ENTER || scan == K_KP_ENTER) {
-               me.setSkin(me);
-               return 1;
-       }
-       else
-               return SUPER(XonoticSkinList).keyDown(me, scan, ascii, shift);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/skinlist.qc b/qcsrc/menu/xonotic/skinlist.qc
new file mode 100644 (file)
index 0000000..6d11fe9
--- /dev/null
@@ -0,0 +1,196 @@
+#ifdef INTERFACE
+CLASS(XonoticSkinList) EXTENDS(XonoticListBox)
+       METHOD(XonoticSkinList, configureXonoticSkinList, void(entity))
+       ATTRIB(XonoticSkinList, rowsPerItem, float, 4)
+       METHOD(XonoticSkinList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticSkinList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticSkinList, getSkins, void(entity))
+       METHOD(XonoticSkinList, setSkin, void(entity))
+       METHOD(XonoticSkinList, loadCvars, void(entity))
+       METHOD(XonoticSkinList, saveCvars, void(entity))
+       METHOD(XonoticSkinList, skinParameter, string(entity, float, float))
+       METHOD(XonoticSkinList, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticSkinList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticSkinList, destroy, void(entity))
+
+       ATTRIB(XonoticSkinList, skinlist, float, -1)
+       ATTRIB(XonoticSkinList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticSkinList, columnPreviewOrigin, float, 0)
+       ATTRIB(XonoticSkinList, columnPreviewSize, float, 0)
+       ATTRIB(XonoticSkinList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticSkinList, columnNameSize, float, 0)
+       ATTRIB(XonoticSkinList, realUpperMargin1, float, 0)
+       ATTRIB(XonoticSkinList, realUpperMargin2, float, 0)
+       ATTRIB(XonoticSkinList, origin, vector, '0 0 0')
+       ATTRIB(XonoticSkinList, itemAbsSize, vector, '0 0 0')
+
+       ATTRIB(XonoticSkinList, name, string, "skinselector")
+ENDCLASS(XonoticSkinList)
+
+entity makeXonoticSkinList();
+void SetSkin_Click(entity btn, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+
+const float SKINPARM_NAME = 0;
+const float SKINPARM_TITLE = 1;
+const float SKINPARM_AUTHOR = 2;
+const float SKINPARM_PREVIEW = 3;
+const float SKINPARM_COUNT = 4;
+
+entity makeXonoticSkinList()
+{
+       entity me;
+       me = spawnXonoticSkinList();
+       me.configureXonoticSkinList(me);
+       return me;
+}
+
+void XonoticSkinList_configureXonoticSkinList(entity me)
+{
+       me.configureXonoticListBox(me);
+       me.getSkins(me);
+       me.loadCvars(me);
+}
+
+void XonoticSkinList_loadCvars(entity me)
+{
+       string s;
+       float i, n;
+       s = cvar_string("menu_skin");
+       n = me.nItems;
+       for(i = 0; i < n; ++i)
+       {
+               if(me.skinParameter(me, i, SKINPARM_NAME) == s)
+               {
+                       me.selectedItem = i;
+                       break;
+               }
+       }
+}
+
+void XonoticSkinList_saveCvars(entity me)
+{
+       cvar_set("menu_skin", me.skinParameter(me, me.selectedItem, SKINPARM_NAME));
+}
+
+string XonoticSkinList_skinParameter(entity me, float i, float key)
+{
+       return bufstr_get(me.skinlist, i * SKINPARM_COUNT + key);
+}
+
+void XonoticSkinList_getSkins(entity me)
+{
+       float glob, buf, i, n, fh;
+       string s;
+
+       buf = buf_create();
+       glob = search_begin("gfx/menu/*/skinvalues.txt", TRUE, TRUE);
+       if(glob < 0)
+       {
+               me.skinlist = buf;
+               me.nItems = 0;
+               return;
+       }
+
+       n = search_getsize(glob);
+       for(i = 0; i < n; ++i)
+       {
+               s = search_getfilename(glob, i);
+               bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_NAME, substring(s, 9, strlen(s) - 24)); // the * part
+               bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_TITLE, _("<TITLE>"));
+               bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_AUTHOR, _("<AUTHOR>"));
+               if(draw_PictureSize(strcat("/gfx/menu/", substring(s, 9, strlen(s) - 24), "/skinpreview")) == '0 0 0')
+                       bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_PREVIEW, "nopreview_menuskin");
+               else
+                       bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_PREVIEW, strcat("/gfx/menu/", substring(s, 9, strlen(s) - 24), "/skinpreview"));
+               fh = fopen(language_filename(s), FILE_READ);
+               if(fh < 0)
+               {
+                       print("Warning: can't open skinvalues.txt file\n");
+                       continue;
+               }
+               while((s = fgets(fh)))
+               {
+                       // these two are handled by skinlist.qc
+                       if(substring(s, 0, 6) == "title ")
+                               bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_TITLE, substring(s, 6, strlen(s) - 6));
+                       else if(substring(s, 0, 7) == "author ")
+                               bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_AUTHOR, substring(s, 7, strlen(s) - 7));
+               }
+               fclose(fh);
+       }
+
+       search_end(glob);
+
+       me.skinlist = buf;
+       me.nItems = n;
+}
+
+void XonoticSkinList_destroy(entity me)
+{
+       buf_del(me.skinlist);
+}
+
+void XonoticSkinList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticSkinList).resizeNotify(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;
+}
+
+void XonoticSkinList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s;
+
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       s = me.skinParameter(me, i, SKINPARM_PREVIEW);
+       draw_Picture(me.columnPreviewOrigin * eX, s, me.columnPreviewSize * eX + eY, '1 1 1', 1);
+
+       s = me.skinParameter(me, i, SKINPARM_TITLE);
+       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin1 * eY + (me.columnNameOrigin + 0.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_SKINLIST_TITLE, SKINALPHA_TEXT, 0);
+
+       s = me.skinParameter(me, i, SKINPARM_AUTHOR);
+       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin2 * eY + (me.columnNameOrigin + 1.00 * (me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize))) * eX, s, me.realFontSize, SKINCOLOR_SKINLIST_AUTHOR, SKINALPHA_TEXT, 0);
+}
+
+void XonoticSkinList_setSkin(entity me)
+{
+       me.saveCvars(me);
+       localcmd("\nmenu_restart\nmenu_cmd skinselect\n");
+}
+
+void SetSkin_Click(entity btn, entity me)
+{
+       me.setSkin(me);
+}
+
+void XonoticSkinList_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       me.setSkin(me);
+}
+
+float XonoticSkinList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_KP_ENTER) {
+               me.setSkin(me);
+               return 1;
+       }
+       else
+               return SUPER(XonoticSkinList).keyDown(me, scan, ascii, shift);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/slider.c b/qcsrc/menu/xonotic/slider.c
deleted file mode 100644 (file)
index d63fe1c..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticSlider) EXTENDS(Slider)
-       METHOD(XonoticSlider, configureXonoticSlider, void(entity, float, float, float, string))
-       METHOD(XonoticSlider, setValue, void(entity, float))
-       ATTRIB(XonoticSlider, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT)
-       ATTRIB(XonoticSlider, image, string, SKINGFX_SLIDER)
-       ATTRIB(XonoticSlider, tolerance, vector, SKINTOLERANCE_SLIDER)
-       ATTRIB(XonoticSlider, align, float, 0.5)
-       ATTRIB(XonoticSlider, color, vector, SKINCOLOR_SLIDER_N)
-       ATTRIB(XonoticSlider, colorC, vector, SKINCOLOR_SLIDER_C)
-       ATTRIB(XonoticSlider, colorF, vector, SKINCOLOR_SLIDER_F)
-       ATTRIB(XonoticSlider, colorD, vector, SKINCOLOR_SLIDER_D)
-       ATTRIB(XonoticSlider, color2, vector, SKINCOLOR_SLIDER_S)
-
-       ATTRIB(XonoticSlider, cvarName, string, string_null)
-       METHOD(XonoticSlider, loadCvars, void(entity))
-       METHOD(XonoticSlider, saveCvars, void(entity))
-       ATTRIB(XonoticSlider, sendCvars, float, 0)
-
-       ATTRIB(XonoticSlider, alpha, float, SKINALPHA_TEXT)
-       ATTRIB(XonoticSlider, disabledAlpha, float, SKINALPHA_DISABLED)
-ENDCLASS(XonoticSlider)
-entity makeXonoticSlider(float, float, float, string);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticSlider(float theValueMin, float theValueMax, float theValueStep, string theCvar)
-{
-       entity me;
-       me = spawnXonoticSlider();
-       me.configureXonoticSlider(me, theValueMin, theValueMax, theValueStep, theCvar);
-       return me;
-}
-void XonoticSlider_configureXonoticSlider(entity me, float theValueMin, float theValueMax, float theValueStep, string theCvar)
-{
-       float vp;
-       vp = theValueStep * 10;
-       while(fabs(vp) < fabs(theValueMax - theValueMin) / 40)
-               vp *= 10;
-
-       me.configureSliderVisuals(me, me.fontSize, me.align, me.valueSpace, me.image);
-
-       if(theCvar)
-       {
-               // Prevent flickering of the slider button by initialising the
-               // slider out of bounds to hide the button before loading the cvar
-               me.configureSliderValues(me, theValueMin, theValueMin-theValueStep, theValueMax, theValueStep, theValueStep, vp);
-               me.cvarName = theCvar;
-               me.loadCvars(me);
-               me.tooltip = getZonedTooltipForIdentifier(theCvar);
-       }
-       else
-               me.configureSliderValues(me, theValueMin, theValueMin, theValueMax, theValueStep, theValueStep, vp);
-}
-void XonoticSlider_setValue(entity me, float val)
-{
-       if(val != me.value)
-       {
-               SUPER(XonoticSlider).setValue( me, val );
-               me.saveCvars(me);
-       }
-}
-void XonoticSlider_loadCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       me.setValue( me, cvar(me.cvarName) );
-}
-void XonoticSlider_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       cvar_set(me.cvarName, ftos(me.value));
-
-       CheckSendCvars(me, me.cvarName);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/slider.qc b/qcsrc/menu/xonotic/slider.qc
new file mode 100644 (file)
index 0000000..d63fe1c
--- /dev/null
@@ -0,0 +1,80 @@
+#ifdef INTERFACE
+CLASS(XonoticSlider) EXTENDS(Slider)
+       METHOD(XonoticSlider, configureXonoticSlider, void(entity, float, float, float, string))
+       METHOD(XonoticSlider, setValue, void(entity, float))
+       ATTRIB(XonoticSlider, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT)
+       ATTRIB(XonoticSlider, image, string, SKINGFX_SLIDER)
+       ATTRIB(XonoticSlider, tolerance, vector, SKINTOLERANCE_SLIDER)
+       ATTRIB(XonoticSlider, align, float, 0.5)
+       ATTRIB(XonoticSlider, color, vector, SKINCOLOR_SLIDER_N)
+       ATTRIB(XonoticSlider, colorC, vector, SKINCOLOR_SLIDER_C)
+       ATTRIB(XonoticSlider, colorF, vector, SKINCOLOR_SLIDER_F)
+       ATTRIB(XonoticSlider, colorD, vector, SKINCOLOR_SLIDER_D)
+       ATTRIB(XonoticSlider, color2, vector, SKINCOLOR_SLIDER_S)
+
+       ATTRIB(XonoticSlider, cvarName, string, string_null)
+       METHOD(XonoticSlider, loadCvars, void(entity))
+       METHOD(XonoticSlider, saveCvars, void(entity))
+       ATTRIB(XonoticSlider, sendCvars, float, 0)
+
+       ATTRIB(XonoticSlider, alpha, float, SKINALPHA_TEXT)
+       ATTRIB(XonoticSlider, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(XonoticSlider)
+entity makeXonoticSlider(float, float, float, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticSlider(float theValueMin, float theValueMax, float theValueStep, string theCvar)
+{
+       entity me;
+       me = spawnXonoticSlider();
+       me.configureXonoticSlider(me, theValueMin, theValueMax, theValueStep, theCvar);
+       return me;
+}
+void XonoticSlider_configureXonoticSlider(entity me, float theValueMin, float theValueMax, float theValueStep, string theCvar)
+{
+       float vp;
+       vp = theValueStep * 10;
+       while(fabs(vp) < fabs(theValueMax - theValueMin) / 40)
+               vp *= 10;
+
+       me.configureSliderVisuals(me, me.fontSize, me.align, me.valueSpace, me.image);
+
+       if(theCvar)
+       {
+               // Prevent flickering of the slider button by initialising the
+               // slider out of bounds to hide the button before loading the cvar
+               me.configureSliderValues(me, theValueMin, theValueMin-theValueStep, theValueMax, theValueStep, theValueStep, vp);
+               me.cvarName = theCvar;
+               me.loadCvars(me);
+               me.tooltip = getZonedTooltipForIdentifier(theCvar);
+       }
+       else
+               me.configureSliderValues(me, theValueMin, theValueMin, theValueMax, theValueStep, theValueStep, vp);
+}
+void XonoticSlider_setValue(entity me, float val)
+{
+       if(val != me.value)
+       {
+               SUPER(XonoticSlider).setValue( me, val );
+               me.saveCvars(me);
+       }
+}
+void XonoticSlider_loadCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       me.setValue( me, cvar(me.cvarName) );
+}
+void XonoticSlider_saveCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       cvar_set(me.cvarName, ftos(me.value));
+
+       CheckSendCvars(me, me.cvarName);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/slider_decibels.c b/qcsrc/menu/xonotic/slider_decibels.c
deleted file mode 100644 (file)
index bf847e3..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticDecibelsSlider) EXTENDS(XonoticSlider)
-       METHOD(XonoticDecibelsSlider, loadCvars, void(entity))
-       METHOD(XonoticDecibelsSlider, saveCvars, void(entity))
-       METHOD(XonoticDecibelsSlider, valueToText, string(entity, float))
-ENDCLASS(XonoticDecibelsSlider)
-entity makeXonoticDecibelsSlider(float, float, float, string);
-#endif
-
-#ifdef IMPLEMENTATION
-
-float toDecibelOfSquare(float f, float mi)
-{
-       float A = log(10) / 20; // note: about 0.115; inverse: about 8.686
-       if(mi != 0)
-       {
-               // linear scale part
-               float t = 1 / A + mi;
-               float y = exp(1 + A * mi);
-               if(f <= y)
-                       return mi + (t - mi) * (f / y);
-       }
-       return log(f) / A;
-}
-
-float fromDecibelOfSquare(float f, float mi)
-{
-       float A = log(10) / 20; // note: about 0.115; inverse: about 8.686
-       if(mi != 0)
-       {
-               // linear scale part
-               float t = 1 / A + mi;
-               float y = exp(1 + A * mi);
-               if(f <= t)
-                       return y * ((f - mi) / (t - mi));
-       }
-       return exp(A * f);
-}
-
-entity makeXonoticDecibelsSlider(float theValueMin, float theValueMax, float theValueStep, string theCvar)
-{
-       entity me;
-       me = spawnXonoticDecibelsSlider();
-       me.configureXonoticSlider(me, theValueMin, theValueMax, theValueStep, theCvar);
-       return me;
-}
-void XonoticDecibelsSlider_loadCvars(entity me)
-{
-       float v;
-
-       if (!me.cvarName)
-               return;
-
-       v = cvar(me.cvarName);
-
-       // snapping
-       if(v > fromDecibelOfSquare(me.valueMax - 0.5 * me.valueStep, me.valueMin))
-               Slider_setValue(me, me.valueMax);
-       else
-               Slider_setValue(me, me.valueStep * floor(0.5 + toDecibelOfSquare(v, me.valueMin) / me.valueStep) );
-}
-void XonoticDecibelsSlider_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       if(me.value > me.valueMax - 0.5 * me.valueStep)
-               cvar_set(me.cvarName, ftos(fromDecibelOfSquare(me.valueMax, me.valueMin)));
-       else
-               cvar_set(me.cvarName, ftos(fromDecibelOfSquare(me.value, me.valueMin)));
-}
-
-float autocvar_menu_snd_sliderscale;
-string XonoticDecibelsSlider_valueToText(entity me, float v)
-{
-       if(v > me.valueMax - 0.5 * me.valueStep)
-               return CTX(_("VOL^MAX"));
-       else if(v <= me.valueMin)
-               return CTX(_("VOL^OFF"));
-       else if(autocvar_menu_snd_sliderscale == 3) // fake percent scale
-               return sprintf("%d %%", (v - me.valueMin) / (me.valueMax - me.valueMin) * 100);
-       else if(autocvar_menu_snd_sliderscale == 2) // 0..10 scale
-               return sprintf("%.1f", (v - me.valueMin) / (me.valueMax - me.valueMin) * 10);
-       else if(autocvar_menu_snd_sliderscale == 1) // real percent scale
-               return sprintf("%.2f %%", fromDecibelOfSquare(v, me.valueMin) * 100);
-       else // decibel scale
-               return sprintf(_("%s dB"), ftos_decimals(toDecibelOfSquare(fromDecibelOfSquare(v, me.valueMin), 0), me.valueDigits));
-}
-
-void _TEST_XonoticDecibelsSlider()
-{
-       float i;
-       for(i = -400; i < 0; ++i)
-       {
-               float db = i * 0.1;
-               float v = fromDecibelOfSquare(db, -40);
-               float dbv = toDecibelOfSquare(v, -40);
-               float d = dbv - db;
-               printf("%f -> %f -> %f (diff: %f)\n", db, v, dbv, d);
-               TEST_Check(fabs(d) > 0.02);
-       }
-       TEST_OK();
-}
-
-#endif
diff --git a/qcsrc/menu/xonotic/slider_decibels.qc b/qcsrc/menu/xonotic/slider_decibels.qc
new file mode 100644 (file)
index 0000000..bf847e3
--- /dev/null
@@ -0,0 +1,105 @@
+#ifdef INTERFACE
+CLASS(XonoticDecibelsSlider) EXTENDS(XonoticSlider)
+       METHOD(XonoticDecibelsSlider, loadCvars, void(entity))
+       METHOD(XonoticDecibelsSlider, saveCvars, void(entity))
+       METHOD(XonoticDecibelsSlider, valueToText, string(entity, float))
+ENDCLASS(XonoticDecibelsSlider)
+entity makeXonoticDecibelsSlider(float, float, float, string);
+#endif
+
+#ifdef IMPLEMENTATION
+
+float toDecibelOfSquare(float f, float mi)
+{
+       float A = log(10) / 20; // note: about 0.115; inverse: about 8.686
+       if(mi != 0)
+       {
+               // linear scale part
+               float t = 1 / A + mi;
+               float y = exp(1 + A * mi);
+               if(f <= y)
+                       return mi + (t - mi) * (f / y);
+       }
+       return log(f) / A;
+}
+
+float fromDecibelOfSquare(float f, float mi)
+{
+       float A = log(10) / 20; // note: about 0.115; inverse: about 8.686
+       if(mi != 0)
+       {
+               // linear scale part
+               float t = 1 / A + mi;
+               float y = exp(1 + A * mi);
+               if(f <= t)
+                       return y * ((f - mi) / (t - mi));
+       }
+       return exp(A * f);
+}
+
+entity makeXonoticDecibelsSlider(float theValueMin, float theValueMax, float theValueStep, string theCvar)
+{
+       entity me;
+       me = spawnXonoticDecibelsSlider();
+       me.configureXonoticSlider(me, theValueMin, theValueMax, theValueStep, theCvar);
+       return me;
+}
+void XonoticDecibelsSlider_loadCvars(entity me)
+{
+       float v;
+
+       if (!me.cvarName)
+               return;
+
+       v = cvar(me.cvarName);
+
+       // snapping
+       if(v > fromDecibelOfSquare(me.valueMax - 0.5 * me.valueStep, me.valueMin))
+               Slider_setValue(me, me.valueMax);
+       else
+               Slider_setValue(me, me.valueStep * floor(0.5 + toDecibelOfSquare(v, me.valueMin) / me.valueStep) );
+}
+void XonoticDecibelsSlider_saveCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       if(me.value > me.valueMax - 0.5 * me.valueStep)
+               cvar_set(me.cvarName, ftos(fromDecibelOfSquare(me.valueMax, me.valueMin)));
+       else
+               cvar_set(me.cvarName, ftos(fromDecibelOfSquare(me.value, me.valueMin)));
+}
+
+float autocvar_menu_snd_sliderscale;
+string XonoticDecibelsSlider_valueToText(entity me, float v)
+{
+       if(v > me.valueMax - 0.5 * me.valueStep)
+               return CTX(_("VOL^MAX"));
+       else if(v <= me.valueMin)
+               return CTX(_("VOL^OFF"));
+       else if(autocvar_menu_snd_sliderscale == 3) // fake percent scale
+               return sprintf("%d %%", (v - me.valueMin) / (me.valueMax - me.valueMin) * 100);
+       else if(autocvar_menu_snd_sliderscale == 2) // 0..10 scale
+               return sprintf("%.1f", (v - me.valueMin) / (me.valueMax - me.valueMin) * 10);
+       else if(autocvar_menu_snd_sliderscale == 1) // real percent scale
+               return sprintf("%.2f %%", fromDecibelOfSquare(v, me.valueMin) * 100);
+       else // decibel scale
+               return sprintf(_("%s dB"), ftos_decimals(toDecibelOfSquare(fromDecibelOfSquare(v, me.valueMin), 0), me.valueDigits));
+}
+
+void _TEST_XonoticDecibelsSlider()
+{
+       float i;
+       for(i = -400; i < 0; ++i)
+       {
+               float db = i * 0.1;
+               float v = fromDecibelOfSquare(db, -40);
+               float dbv = toDecibelOfSquare(v, -40);
+               float d = dbv - db;
+               printf("%f -> %f -> %f (diff: %f)\n", db, v, dbv, d);
+               TEST_Check(fabs(d) > 0.02);
+       }
+       TEST_OK();
+}
+
+#endif
diff --git a/qcsrc/menu/xonotic/slider_particles.c b/qcsrc/menu/xonotic/slider_particles.c
deleted file mode 100644 (file)
index db29f55..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticParticlesSlider) EXTENDS(XonoticTextSlider)
-       METHOD(XonoticParticlesSlider, configureXonoticParticlesSlider, void(entity))
-       METHOD(XonoticParticlesSlider, loadCvars, void(entity))
-       METHOD(XonoticParticlesSlider, saveCvars, void(entity))
-ENDCLASS(XonoticParticlesSlider)
-entity makeXonoticParticlesSlider();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticParticlesSlider()
-{
-       entity me;
-       me = spawnXonoticParticlesSlider();
-       me.configureXonoticParticlesSlider(me);
-       return me;
-}
-void XonoticParticlesSlider_configureXonoticParticlesSlider(entity me)
-{
-       me.configureXonoticTextSlider(me, "cl_particles_quality");
-       if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^OMG")),      "0.4 250 0"); }
-       me.addValue(me,                         ZCTX(_("PART^Low")),      "0.4 500 0");
-       me.addValue(me,                         ZCTX(_("PART^Medium")),   "0.8 750 0");
-       me.addValue(me,                         ZCTX(_("PART^Normal")),   "1.0 1000 1");
-       me.addValue(me,                         ZCTX(_("PART^High")),     "1.0 1500 1");
-       me.addValue(me,                         ZCTX(_("PART^Ultra")),    "1.0 2000 2");
-       if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^Ultimate")), "1.0 3000 2"); }
-       me.configureXonoticTextSliderValues(me);
-}
-void XonoticParticlesSlider_loadCvars(entity me)
-{
-       me.setValueFromIdentifier(me, sprintf("%s %s %s",
-               cvar_string("cl_particles_quality"),
-               cvar_string("r_drawparticles_drawdistance"),
-               cvar_string("cl_damageeffect")
-       ));
-}
-void XonoticParticlesSlider_saveCvars(entity me)
-{
-       if(me.value >= 0 || me.value < me.nValues)
-       {
-               tokenize_console(me.getIdentifier(me));
-               cvar_set("cl_particles_quality", argv(0));
-               cvar_set("r_drawparticles_drawdistance", argv(1));
-               cvar_set("cl_damageeffect", argv(2)); 
-       }
-}
-#endif
diff --git a/qcsrc/menu/xonotic/slider_particles.qc b/qcsrc/menu/xonotic/slider_particles.qc
new file mode 100644 (file)
index 0000000..db29f55
--- /dev/null
@@ -0,0 +1,48 @@
+#ifdef INTERFACE
+CLASS(XonoticParticlesSlider) EXTENDS(XonoticTextSlider)
+       METHOD(XonoticParticlesSlider, configureXonoticParticlesSlider, void(entity))
+       METHOD(XonoticParticlesSlider, loadCvars, void(entity))
+       METHOD(XonoticParticlesSlider, saveCvars, void(entity))
+ENDCLASS(XonoticParticlesSlider)
+entity makeXonoticParticlesSlider();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticParticlesSlider()
+{
+       entity me;
+       me = spawnXonoticParticlesSlider();
+       me.configureXonoticParticlesSlider(me);
+       return me;
+}
+void XonoticParticlesSlider_configureXonoticParticlesSlider(entity me)
+{
+       me.configureXonoticTextSlider(me, "cl_particles_quality");
+       if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^OMG")),      "0.4 250 0"); }
+       me.addValue(me,                         ZCTX(_("PART^Low")),      "0.4 500 0");
+       me.addValue(me,                         ZCTX(_("PART^Medium")),   "0.8 750 0");
+       me.addValue(me,                         ZCTX(_("PART^Normal")),   "1.0 1000 1");
+       me.addValue(me,                         ZCTX(_("PART^High")),     "1.0 1500 1");
+       me.addValue(me,                         ZCTX(_("PART^Ultra")),    "1.0 2000 2");
+       if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^Ultimate")), "1.0 3000 2"); }
+       me.configureXonoticTextSliderValues(me);
+}
+void XonoticParticlesSlider_loadCvars(entity me)
+{
+       me.setValueFromIdentifier(me, sprintf("%s %s %s",
+               cvar_string("cl_particles_quality"),
+               cvar_string("r_drawparticles_drawdistance"),
+               cvar_string("cl_damageeffect")
+       ));
+}
+void XonoticParticlesSlider_saveCvars(entity me)
+{
+       if(me.value >= 0 || me.value < me.nValues)
+       {
+               tokenize_console(me.getIdentifier(me));
+               cvar_set("cl_particles_quality", argv(0));
+               cvar_set("r_drawparticles_drawdistance", argv(1));
+               cvar_set("cl_damageeffect", argv(2)); 
+       }
+}
+#endif
diff --git a/qcsrc/menu/xonotic/slider_picmip.c b/qcsrc/menu/xonotic/slider_picmip.c
deleted file mode 100644 (file)
index ddedc4b..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticPicmipSlider) EXTENDS(XonoticTextSlider)
-       METHOD(XonoticPicmipSlider, configureXonoticPicmipSlider, void(entity))
-       METHOD(XonoticPicmipSlider, draw, void(entity))
-       METHOD(XonoticPicmipSlider, autofix, void(entity))
-       ATTRIB(XonoticPicmipSlider, have_s3tc, float, 0)
-ENDCLASS(XonoticPicmipSlider)
-entity makeXonoticPicmipSlider(); // note: you still need to call addValue and configureXonoticTextSliderValues!
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticPicmipSlider()
-{
-       entity me;
-       me = spawnXonoticPicmipSlider();
-       me.configureXonoticPicmipSlider(me);
-       return me;
-}
-void XonoticPicmipSlider_configureXonoticPicmipSlider(entity me)
-{
-       me.configureXonoticTextSlider(me, "gl_picmip");
-       me.autofix(me);
-       me.have_s3tc = GL_Have_TextureCompression();
-}
-float texmemsize(float s3tc)
-{
-       return
-       (
-                 2500 * pow(0.25, max(0, cvar("gl_picmip") + cvar("gl_picmip_other")))
-               + 1500 * pow(0.25, max(0, cvar("gl_picmip") + cvar("gl_picmip_world")))
-       ) * ((s3tc && (cvar("r_texture_dds_load") || cvar("gl_texturecompression"))) ? 0.2 : 1.0); // TC: normalmaps 50%, other 25%, few incompressible, guessing 40% as conservative average
-}
-void XonoticPicmipSlider_autofix(entity me)
-{
-       float max_hard, max_soft;
-       if(cvar("menu_picmip_bypass"))
-               return;
-       max_hard = cvar("sys_memsize_virtual");
-       max_soft = cvar("sys_memsize_physical");
-       if(max_hard > 0)
-       {
-               while(me.value > 0 && texmemsize(me.have_s3tc) > max_hard)
-                       me.setValue(me, me.value - 1);
-       }
-       // TODO also check the soft limit!
-       // TODO better handling than clamping the slider!
-}
-void XonoticPicmipSlider_draw(entity me)
-{
-       me.autofix(me);
-       SUPER(XonoticPicmipSlider).draw(me);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/slider_picmip.qc b/qcsrc/menu/xonotic/slider_picmip.qc
new file mode 100644 (file)
index 0000000..ddedc4b
--- /dev/null
@@ -0,0 +1,53 @@
+#ifdef INTERFACE
+CLASS(XonoticPicmipSlider) EXTENDS(XonoticTextSlider)
+       METHOD(XonoticPicmipSlider, configureXonoticPicmipSlider, void(entity))
+       METHOD(XonoticPicmipSlider, draw, void(entity))
+       METHOD(XonoticPicmipSlider, autofix, void(entity))
+       ATTRIB(XonoticPicmipSlider, have_s3tc, float, 0)
+ENDCLASS(XonoticPicmipSlider)
+entity makeXonoticPicmipSlider(); // note: you still need to call addValue and configureXonoticTextSliderValues!
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticPicmipSlider()
+{
+       entity me;
+       me = spawnXonoticPicmipSlider();
+       me.configureXonoticPicmipSlider(me);
+       return me;
+}
+void XonoticPicmipSlider_configureXonoticPicmipSlider(entity me)
+{
+       me.configureXonoticTextSlider(me, "gl_picmip");
+       me.autofix(me);
+       me.have_s3tc = GL_Have_TextureCompression();
+}
+float texmemsize(float s3tc)
+{
+       return
+       (
+                 2500 * pow(0.25, max(0, cvar("gl_picmip") + cvar("gl_picmip_other")))
+               + 1500 * pow(0.25, max(0, cvar("gl_picmip") + cvar("gl_picmip_world")))
+       ) * ((s3tc && (cvar("r_texture_dds_load") || cvar("gl_texturecompression"))) ? 0.2 : 1.0); // TC: normalmaps 50%, other 25%, few incompressible, guessing 40% as conservative average
+}
+void XonoticPicmipSlider_autofix(entity me)
+{
+       float max_hard, max_soft;
+       if(cvar("menu_picmip_bypass"))
+               return;
+       max_hard = cvar("sys_memsize_virtual");
+       max_soft = cvar("sys_memsize_physical");
+       if(max_hard > 0)
+       {
+               while(me.value > 0 && texmemsize(me.have_s3tc) > max_hard)
+                       me.setValue(me, me.value - 1);
+       }
+       // TODO also check the soft limit!
+       // TODO better handling than clamping the slider!
+}
+void XonoticPicmipSlider_draw(entity me)
+{
+       me.autofix(me);
+       SUPER(XonoticPicmipSlider).draw(me);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/slider_resolution.c b/qcsrc/menu/xonotic/slider_resolution.c
deleted file mode 100644 (file)
index 66f48f9..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticResolutionSlider) EXTENDS(XonoticTextSlider)
-       METHOD(XonoticResolutionSlider, configureXonoticResolutionSlider, void(entity))
-       METHOD(XonoticResolutionSlider, loadResolutions, void(entity, float))
-       METHOD(XonoticResolutionSlider, addResolution, void(entity, float, float, float))
-       METHOD(XonoticResolutionSlider, loadCvars, void(entity))
-       METHOD(XonoticResolutionSlider, saveCvars, void(entity))
-       METHOD(XonoticResolutionSlider, draw, void(entity))
-       ATTRIB(XonoticResolutionSlider, vid_fullscreen, float, -1)
-ENDCLASS(XonoticResolutionSlider)
-entity makeXonoticResolutionSlider();
-float updateConwidths(float width, float height, float pixelheight);
-#endif
-
-#ifdef IMPLEMENTATION
-
-/* private static */ float XonoticResolutionSlider_DataHasChanged;
-
-// Updates cvars (to be called by menu.qc at startup or on detected res change)
-float updateConwidths(float width, float height, float pixelheight)
-{
-       vector r, c;
-       float minfactor, maxfactor;
-       float sz, f;
-
-       sz = cvar("menu_vid_scale");
-       if (sz < -1)
-               return 0;  // No recalculation.
-
-       // Save off current settings.
-       cvar_set("_menu_vid_width", ftos(width));
-       cvar_set("_menu_vid_height", ftos(height));
-       cvar_set("_menu_vid_pixelheight", ftos(pixelheight));
-       cvar_set("_menu_vid_desktopfullscreen", cvar_string("vid_desktopfullscreen"));
-
-       r_x = width;
-       r_y = height;
-       r_z = pixelheight;
-
-       // calculate the base resolution
-       c_z = 0;
-       c_x = 800;
-       c_y = c_x * r_y * r_z / r_x;
-       if(c_y < 600)
-       {
-               c_y = 600;
-               c_x = c_y * r_x / (r_y * r_z);
-       }
-
-       f = min(r_x / c_x, r_y / c_y);
-       if(f < 1)
-               c = c * f; // ensures that c_x <= r_x and c_y <= r_y
-
-       minfactor = min(1, 640 / c_x);            // can be > 1 only if c_x is <640
-       maxfactor = max(1, r_x / c_x, r_y / c_y); // can be < 1 only if r_x < c_x and r_y < c_y
-       dprint("min factor: ", ftos(minfactor), "\n");
-       dprint("max factor: ", ftos(maxfactor), "\n");
-
-       if(sz < 0)
-               f = 1 - (maxfactor - 1) * sz;
-       else if(sz > 0)
-               f = 1 + (minfactor - 1) * sz;
-       else
-               f = 1;
-       c = c * f; // fteqcc fail
-
-       c_x = rint(c_x);
-       c_y = rint(c_y);
-
-       // Please reload resolutions list and such stuff.
-       XonoticResolutionSlider_DataHasChanged = TRUE;
-
-       if (c_x != cvar("vid_conwidth") || c_y != cvar("vid_conheight"))
-       {
-               cvar_set("vid_conwidth", ftos(c_x));
-               cvar_set("vid_conheight", ftos(c_y));
-               return 1;
-       }
-       return 0;
-}
-entity makeXonoticResolutionSlider()
-{
-       entity me;
-       me = spawnXonoticResolutionSlider();
-       me.configureXonoticResolutionSlider(me);
-       return me;
-}
-void XonoticResolutionSlider_addResolution(entity me, float w, float h, float pixelheight)
-{
-       float i;
-       for (i = 0; i < me.nValues; ++i)
-       {
-               tokenize_console(me.valueToIdentifier(me, i));
-               if (w > stof(argv(0))) continue;
-               if (w < stof(argv(0))) break;
-               if (h > stof(argv(1))) continue;
-               if (h < stof(argv(1))) break;
-               if (pixelheight > stof(argv(2)) + 0.01) continue;
-               if (pixelheight < stof(argv(2)) - 0.01) break;
-               return;  // already there
-       }
-       if (pixelheight != 1)
-       {
-               float aspect = w / (h * pixelheight);
-               float bestdenom = rint(aspect);
-               float bestnum = 1;
-               float denom;
-               for (denom = 2; denom < 10; ++denom) {
-                       float num = rint(aspect * denom);
-                       if (fabs(num / denom - aspect) < fabs(bestnum / bestdenom - aspect))
-                       {
-                               bestnum = num;
-                               bestdenom = denom;
-                       }
-               }
-               me.insertValue(me, i, strzone(sprintf(_("%dx%d (%d:%d)"), w, h, bestnum, bestdenom)), strzone(strcat(ftos(w), " ", ftos(h), " ", ftos(pixelheight))));
-       }
-       else
-               me.insertValue(me, i, strzone(sprintf(_("%dx%d"), w, h)), strzone(strcat(ftos(w), " ", ftos(h), " ", ftos(pixelheight))));
-}
-float autocvar_menu_vid_allowdualscreenresolution;
-void XonoticResolutionSlider_configureXonoticResolutionSlider(entity me)
-{
-       me.configureXonoticTextSlider(me, "_menu_vid_width");
-       me.loadResolutions(me, cvar("vid_fullscreen"));
-}
-void XonoticResolutionSlider_loadResolutions(entity me, float fullscreen)
-{
-       float i;
-       vector r;
-
-       // HACK: text slider assumes the strings are constants, so clearValues
-       // will not unzone them
-       for(i = 0; i < me.nValues; ++i)
-       {
-               strunzone(me.valueToIdentifier(me, i));
-               strunzone(me.valueToText(me, i));
-       }
-       // NOW we can safely clear.
-       me.clearValues(me);
-
-       if (fullscreen)
-       {
-               for(i = 0;; ++i)
-               {
-                       r = getresolution(i);
-                       if(r_x == 0 && r_y == 0)
-                               break;
-                       if(r_x < 640 || r_y < 480)
-                               continue;
-                       if(r_x > 2 * r_y) // likely dualscreen resolution, skip this one
-                               if(autocvar_menu_vid_allowdualscreenresolution <= 0)
-                                       continue;
-                       me.addResolution(me, r_x, r_y, r_z);
-               }
-               r = getresolution(-1);
-               if(r_x != 0 || r_y != 0)
-                       me.addResolution(me, r_x, r_y, r_z);
-               dprint("Added system resolutions.\n");
-       }
-
-       if(me.nValues == 0)
-       {
-               me.addResolution(me, 640, 480, 1); // pc res
-#if 0
-               me.addResolution(me, 720, 480, 1.125); // DVD NTSC 4:3
-               me.addResolution(me, 720, 576, 0.9375); // DVD PAL 4:3
-               me.addResolution(me, 720, 480, 0.84375); // DVD NTSC 16:9
-               me.addResolution(me, 720, 576, 0.703125); // DVD PAL 16:9
-#endif
-               me.addResolution(me, 800, 480, 1); // 480p at 1:1 pixel aspect
-               me.addResolution(me, 800, 600, 1); // pc res
-               me.addResolution(me, 1024, 600, 1); // notebook res
-               me.addResolution(me, 1024, 768, 1); // pc res
-               me.addResolution(me, 1280, 720, 1); // 720p
-               me.addResolution(me, 1280, 960, 1); // pc res
-               me.addResolution(me, 1280, 1024, 1); // pc res
-               me.addResolution(me, 1920, 1080, 1); // 1080p
-               dprint("Added default resolutions.\n");
-       }
-       dprint("Total number of resolutions detected: ", ftos(me.nValues), "\n");
-
-       me.vid_fullscreen = fullscreen;
-
-       me.configureXonoticTextSliderValues(me);
-}
-void XonoticResolutionSlider_loadCvars(entity me)
-{
-       me.setValueFromIdentifier(me, strcat(cvar_string("_menu_vid_width"), " ", cvar_string("_menu_vid_height"), " ", cvar_string("_menu_vid_pixelheight")));
-}
-void XonoticResolutionSlider_saveCvars(entity me)
-{
-       if(me.value >= 0 || me.value < me.nValues)
-       {
-               tokenize_console(me.getIdentifier(me));
-               cvar_set("_menu_vid_width", argv(0));
-               cvar_set("_menu_vid_height", argv(1));
-               cvar_set("_menu_vid_pixelheight", argv(2));
-               vector r = getresolution(-1);
-               if (stof(argv(0)) == r_x && stof(argv(1)) == r_y && fabs(stof(argv(2)) - r_z) < 0.01)
-                       cvar_set("_menu_vid_desktopfullscreen", "1");
-               else
-                       cvar_set("_menu_vid_desktopfullscreen", "0");
-       }
-}
-void XonoticResolutionSlider_draw(entity me)
-{
-       if (cvar("vid_fullscreen") != me.vid_fullscreen)
-       {
-               me.loadResolutions(me, cvar("vid_fullscreen"));
-               XonoticResolutionSlider_DataHasChanged = TRUE;
-       }
-       if (XonoticResolutionSlider_DataHasChanged)
-       {
-               XonoticResolutionSlider_DataHasChanged = FALSE;
-               me.loadCvars(me);
-       }
-       SUPER(XonoticResolutionSlider).draw(me);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/slider_resolution.qc b/qcsrc/menu/xonotic/slider_resolution.qc
new file mode 100644 (file)
index 0000000..66f48f9
--- /dev/null
@@ -0,0 +1,220 @@
+#ifdef INTERFACE
+CLASS(XonoticResolutionSlider) EXTENDS(XonoticTextSlider)
+       METHOD(XonoticResolutionSlider, configureXonoticResolutionSlider, void(entity))
+       METHOD(XonoticResolutionSlider, loadResolutions, void(entity, float))
+       METHOD(XonoticResolutionSlider, addResolution, void(entity, float, float, float))
+       METHOD(XonoticResolutionSlider, loadCvars, void(entity))
+       METHOD(XonoticResolutionSlider, saveCvars, void(entity))
+       METHOD(XonoticResolutionSlider, draw, void(entity))
+       ATTRIB(XonoticResolutionSlider, vid_fullscreen, float, -1)
+ENDCLASS(XonoticResolutionSlider)
+entity makeXonoticResolutionSlider();
+float updateConwidths(float width, float height, float pixelheight);
+#endif
+
+#ifdef IMPLEMENTATION
+
+/* private static */ float XonoticResolutionSlider_DataHasChanged;
+
+// Updates cvars (to be called by menu.qc at startup or on detected res change)
+float updateConwidths(float width, float height, float pixelheight)
+{
+       vector r, c;
+       float minfactor, maxfactor;
+       float sz, f;
+
+       sz = cvar("menu_vid_scale");
+       if (sz < -1)
+               return 0;  // No recalculation.
+
+       // Save off current settings.
+       cvar_set("_menu_vid_width", ftos(width));
+       cvar_set("_menu_vid_height", ftos(height));
+       cvar_set("_menu_vid_pixelheight", ftos(pixelheight));
+       cvar_set("_menu_vid_desktopfullscreen", cvar_string("vid_desktopfullscreen"));
+
+       r_x = width;
+       r_y = height;
+       r_z = pixelheight;
+
+       // calculate the base resolution
+       c_z = 0;
+       c_x = 800;
+       c_y = c_x * r_y * r_z / r_x;
+       if(c_y < 600)
+       {
+               c_y = 600;
+               c_x = c_y * r_x / (r_y * r_z);
+       }
+
+       f = min(r_x / c_x, r_y / c_y);
+       if(f < 1)
+               c = c * f; // ensures that c_x <= r_x and c_y <= r_y
+
+       minfactor = min(1, 640 / c_x);            // can be > 1 only if c_x is <640
+       maxfactor = max(1, r_x / c_x, r_y / c_y); // can be < 1 only if r_x < c_x and r_y < c_y
+       dprint("min factor: ", ftos(minfactor), "\n");
+       dprint("max factor: ", ftos(maxfactor), "\n");
+
+       if(sz < 0)
+               f = 1 - (maxfactor - 1) * sz;
+       else if(sz > 0)
+               f = 1 + (minfactor - 1) * sz;
+       else
+               f = 1;
+       c = c * f; // fteqcc fail
+
+       c_x = rint(c_x);
+       c_y = rint(c_y);
+
+       // Please reload resolutions list and such stuff.
+       XonoticResolutionSlider_DataHasChanged = TRUE;
+
+       if (c_x != cvar("vid_conwidth") || c_y != cvar("vid_conheight"))
+       {
+               cvar_set("vid_conwidth", ftos(c_x));
+               cvar_set("vid_conheight", ftos(c_y));
+               return 1;
+       }
+       return 0;
+}
+entity makeXonoticResolutionSlider()
+{
+       entity me;
+       me = spawnXonoticResolutionSlider();
+       me.configureXonoticResolutionSlider(me);
+       return me;
+}
+void XonoticResolutionSlider_addResolution(entity me, float w, float h, float pixelheight)
+{
+       float i;
+       for (i = 0; i < me.nValues; ++i)
+       {
+               tokenize_console(me.valueToIdentifier(me, i));
+               if (w > stof(argv(0))) continue;
+               if (w < stof(argv(0))) break;
+               if (h > stof(argv(1))) continue;
+               if (h < stof(argv(1))) break;
+               if (pixelheight > stof(argv(2)) + 0.01) continue;
+               if (pixelheight < stof(argv(2)) - 0.01) break;
+               return;  // already there
+       }
+       if (pixelheight != 1)
+       {
+               float aspect = w / (h * pixelheight);
+               float bestdenom = rint(aspect);
+               float bestnum = 1;
+               float denom;
+               for (denom = 2; denom < 10; ++denom) {
+                       float num = rint(aspect * denom);
+                       if (fabs(num / denom - aspect) < fabs(bestnum / bestdenom - aspect))
+                       {
+                               bestnum = num;
+                               bestdenom = denom;
+                       }
+               }
+               me.insertValue(me, i, strzone(sprintf(_("%dx%d (%d:%d)"), w, h, bestnum, bestdenom)), strzone(strcat(ftos(w), " ", ftos(h), " ", ftos(pixelheight))));
+       }
+       else
+               me.insertValue(me, i, strzone(sprintf(_("%dx%d"), w, h)), strzone(strcat(ftos(w), " ", ftos(h), " ", ftos(pixelheight))));
+}
+float autocvar_menu_vid_allowdualscreenresolution;
+void XonoticResolutionSlider_configureXonoticResolutionSlider(entity me)
+{
+       me.configureXonoticTextSlider(me, "_menu_vid_width");
+       me.loadResolutions(me, cvar("vid_fullscreen"));
+}
+void XonoticResolutionSlider_loadResolutions(entity me, float fullscreen)
+{
+       float i;
+       vector r;
+
+       // HACK: text slider assumes the strings are constants, so clearValues
+       // will not unzone them
+       for(i = 0; i < me.nValues; ++i)
+       {
+               strunzone(me.valueToIdentifier(me, i));
+               strunzone(me.valueToText(me, i));
+       }
+       // NOW we can safely clear.
+       me.clearValues(me);
+
+       if (fullscreen)
+       {
+               for(i = 0;; ++i)
+               {
+                       r = getresolution(i);
+                       if(r_x == 0 && r_y == 0)
+                               break;
+                       if(r_x < 640 || r_y < 480)
+                               continue;
+                       if(r_x > 2 * r_y) // likely dualscreen resolution, skip this one
+                               if(autocvar_menu_vid_allowdualscreenresolution <= 0)
+                                       continue;
+                       me.addResolution(me, r_x, r_y, r_z);
+               }
+               r = getresolution(-1);
+               if(r_x != 0 || r_y != 0)
+                       me.addResolution(me, r_x, r_y, r_z);
+               dprint("Added system resolutions.\n");
+       }
+
+       if(me.nValues == 0)
+       {
+               me.addResolution(me, 640, 480, 1); // pc res
+#if 0
+               me.addResolution(me, 720, 480, 1.125); // DVD NTSC 4:3
+               me.addResolution(me, 720, 576, 0.9375); // DVD PAL 4:3
+               me.addResolution(me, 720, 480, 0.84375); // DVD NTSC 16:9
+               me.addResolution(me, 720, 576, 0.703125); // DVD PAL 16:9
+#endif
+               me.addResolution(me, 800, 480, 1); // 480p at 1:1 pixel aspect
+               me.addResolution(me, 800, 600, 1); // pc res
+               me.addResolution(me, 1024, 600, 1); // notebook res
+               me.addResolution(me, 1024, 768, 1); // pc res
+               me.addResolution(me, 1280, 720, 1); // 720p
+               me.addResolution(me, 1280, 960, 1); // pc res
+               me.addResolution(me, 1280, 1024, 1); // pc res
+               me.addResolution(me, 1920, 1080, 1); // 1080p
+               dprint("Added default resolutions.\n");
+       }
+       dprint("Total number of resolutions detected: ", ftos(me.nValues), "\n");
+
+       me.vid_fullscreen = fullscreen;
+
+       me.configureXonoticTextSliderValues(me);
+}
+void XonoticResolutionSlider_loadCvars(entity me)
+{
+       me.setValueFromIdentifier(me, strcat(cvar_string("_menu_vid_width"), " ", cvar_string("_menu_vid_height"), " ", cvar_string("_menu_vid_pixelheight")));
+}
+void XonoticResolutionSlider_saveCvars(entity me)
+{
+       if(me.value >= 0 || me.value < me.nValues)
+       {
+               tokenize_console(me.getIdentifier(me));
+               cvar_set("_menu_vid_width", argv(0));
+               cvar_set("_menu_vid_height", argv(1));
+               cvar_set("_menu_vid_pixelheight", argv(2));
+               vector r = getresolution(-1);
+               if (stof(argv(0)) == r_x && stof(argv(1)) == r_y && fabs(stof(argv(2)) - r_z) < 0.01)
+                       cvar_set("_menu_vid_desktopfullscreen", "1");
+               else
+                       cvar_set("_menu_vid_desktopfullscreen", "0");
+       }
+}
+void XonoticResolutionSlider_draw(entity me)
+{
+       if (cvar("vid_fullscreen") != me.vid_fullscreen)
+       {
+               me.loadResolutions(me, cvar("vid_fullscreen"));
+               XonoticResolutionSlider_DataHasChanged = TRUE;
+       }
+       if (XonoticResolutionSlider_DataHasChanged)
+       {
+               XonoticResolutionSlider_DataHasChanged = FALSE;
+               me.loadCvars(me);
+       }
+       SUPER(XonoticResolutionSlider).draw(me);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/slider_sbfadetime.c b/qcsrc/menu/xonotic/slider_sbfadetime.c
deleted file mode 100644 (file)
index 39f91f9..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticScoreboardFadeTimeSlider) EXTENDS(XonoticTextSlider)
-       METHOD(XonoticScoreboardFadeTimeSlider, configureXonoticScoreboardFadeTimeSlider, void(entity))
-       METHOD(XonoticScoreboardFadeTimeSlider, loadCvars, void(entity))
-       METHOD(XonoticScoreboardFadeTimeSlider, saveCvars, void(entity))
-ENDCLASS(XonoticScoreboardFadeTimeSlider)
-entity makeXonoticScoreboardFadeTimeSlider();
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticScoreboardFadeTimeSlider()
-{
-       entity me;
-       me = spawnXonoticScoreboardFadeTimeSlider();
-       me.configureXonoticScoreboardFadeTimeSlider(me);
-       return me;
-}
-void XonoticScoreboardFadeTimeSlider_configureXonoticScoreboardFadeTimeSlider(entity me)
-{
-       me.configureXonoticTextSlider(me, "scoreboard_fadeinspeed");
-       me.addValue(me, ZCTX(_("PART^Slow")),     "5 2.5");
-       me.addValue(me, ZCTX(_("PART^Normal")),   "10 5");
-       me.addValue(me, ZCTX(_("PART^Fast")),     "15 7.5");
-       me.addValue(me, ZCTX(_("PART^Instant")),  "0 0");
-       me.configureXonoticTextSliderValues(me);
-}
-void XonoticScoreboardFadeTimeSlider_loadCvars(entity me)
-{
-       me.setValueFromIdentifier(me, sprintf("%s %s",
-               cvar_string("scoreboard_fadeinspeed"),
-               cvar_string("scoreboard_fadeoutspeed")
-       ));
-}
-void XonoticScoreboardFadeTimeSlider_saveCvars(entity me)
-{
-       if(me.value >= 0 || me.value < me.nValues)
-       {
-               tokenize_console(me.getIdentifier(me));
-               cvar_set("scoreboard_fadeinspeed", argv(0));
-               cvar_set("scoreboard_fadeoutspeed", argv(1));
-       }
-}
-#endif
diff --git a/qcsrc/menu/xonotic/slider_sbfadetime.qc b/qcsrc/menu/xonotic/slider_sbfadetime.qc
new file mode 100644 (file)
index 0000000..39f91f9
--- /dev/null
@@ -0,0 +1,43 @@
+#ifdef INTERFACE
+CLASS(XonoticScoreboardFadeTimeSlider) EXTENDS(XonoticTextSlider)
+       METHOD(XonoticScoreboardFadeTimeSlider, configureXonoticScoreboardFadeTimeSlider, void(entity))
+       METHOD(XonoticScoreboardFadeTimeSlider, loadCvars, void(entity))
+       METHOD(XonoticScoreboardFadeTimeSlider, saveCvars, void(entity))
+ENDCLASS(XonoticScoreboardFadeTimeSlider)
+entity makeXonoticScoreboardFadeTimeSlider();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticScoreboardFadeTimeSlider()
+{
+       entity me;
+       me = spawnXonoticScoreboardFadeTimeSlider();
+       me.configureXonoticScoreboardFadeTimeSlider(me);
+       return me;
+}
+void XonoticScoreboardFadeTimeSlider_configureXonoticScoreboardFadeTimeSlider(entity me)
+{
+       me.configureXonoticTextSlider(me, "scoreboard_fadeinspeed");
+       me.addValue(me, ZCTX(_("PART^Slow")),     "5 2.5");
+       me.addValue(me, ZCTX(_("PART^Normal")),   "10 5");
+       me.addValue(me, ZCTX(_("PART^Fast")),     "15 7.5");
+       me.addValue(me, ZCTX(_("PART^Instant")),  "0 0");
+       me.configureXonoticTextSliderValues(me);
+}
+void XonoticScoreboardFadeTimeSlider_loadCvars(entity me)
+{
+       me.setValueFromIdentifier(me, sprintf("%s %s",
+               cvar_string("scoreboard_fadeinspeed"),
+               cvar_string("scoreboard_fadeoutspeed")
+       ));
+}
+void XonoticScoreboardFadeTimeSlider_saveCvars(entity me)
+{
+       if(me.value >= 0 || me.value < me.nValues)
+       {
+               tokenize_console(me.getIdentifier(me));
+               cvar_set("scoreboard_fadeinspeed", argv(0));
+               cvar_set("scoreboard_fadeoutspeed", argv(1));
+       }
+}
+#endif
diff --git a/qcsrc/menu/xonotic/soundlist.c b/qcsrc/menu/xonotic/soundlist.c
deleted file mode 100644 (file)
index 7d15150..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticSoundList) EXTENDS(XonoticListBox)
-       METHOD(XonoticSoundList, configureXonoticSoundList, void(entity))
-       ATTRIB(XonoticSoundList, rowsPerItem, float, 1)
-       METHOD(XonoticSoundList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticSoundList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticSoundList, getSounds, void(entity))
-       METHOD(XonoticSoundList, soundName, string(entity, float))
-       METHOD(XonoticSoundList, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticSoundList, keyDown, float(entity, float, float, float))
-       METHOD(XonoticSoundList, destroy, void(entity))
-       METHOD(XonoticSoundList, showNotify, void(entity))
-
-       ATTRIB(XonoticSoundList, listSound, float, -1)
-       ATTRIB(XonoticSoundList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticSoundList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticSoundList, columnNameSize, float, 0)
-       ATTRIB(XonoticSoundList, columnNumberOrigin, float, 0)
-       ATTRIB(XonoticSoundList, columnNumberSize, float, 0)
-       ATTRIB(XonoticSoundList, realUpperMargin, float, 0)
-       ATTRIB(XonoticSoundList, origin, vector, '0 0 0')
-       ATTRIB(XonoticSoundList, itemAbsSize, vector, '0 0 0')
-
-       ATTRIB(XonoticSoundList, filterString, string, string_null)
-       ATTRIB(XonoticSoundList, playlist, entity, world)
-ENDCLASS(XonoticSoundList)
-
-entity makeXonoticSoundList();
-void SoundList_Filter_Change(entity box, entity me);
-void SoundList_Add(entity box, entity me);
-void SoundList_Add_All(entity box, entity me);
-void SoundList_Menu_Track_Change(entity box, entity me);
-void SoundList_Menu_Track_Reset(entity box, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-
-entity makeXonoticSoundList()
-{
-       entity me;
-       me = spawnXonoticSoundList();
-       me.configureXonoticSoundList(me);
-       return me;
-}
-
-void XonoticSoundList_configureXonoticSoundList(entity me)
-{
-       me.configureXonoticListBox(me);
-       me.getSounds(me);
-}
-
-string XonoticSoundList_soundName(entity me, float i )
-{
-       string s;
-       s = search_getfilename(me.listSound, i);
-       s = substring(s, 15, strlen(s) - 15 - 4);  // sound/cdtracks/, .ogg
-       return s;
-}
-
-
-void XonoticSoundList_getSounds(entity me)
-{
-       string s;
-
-       if(me.filterString)
-               //subdirectory in filterString allowed
-               s = strcat("sound/cdtracks/*", me.filterString, "*.ogg");
-       else
-               s = "sound/cdtracks/*.ogg";
-
-       if(me.listSound >= 0)
-               search_end(me.listSound);
-
-       me.listSound = search_begin(s, FALSE, TRUE);
-
-       if(me.listSound < 0)
-               me.nItems=0;
-       else
-               me.nItems=search_getsize(me.listSound);
-}
-
-void XonoticSoundList_destroy(entity me)
-{
-       if(me.listSound >= 0)
-               search_end(me.listSound);
-}
-
-void XonoticSoundList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemAbsSize = '0 0 0';
-       SUPER(XonoticSoundList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
-
-       me.columnNumberOrigin = 0;
-       me.columnNumberSize = me.realFontSize_x * 3;
-
-       me.columnNameOrigin = me.columnNumberSize;
-       me.columnNameSize = 1 - me.columnNameOrigin - me.realFontSize_x;
-}
-
-void XonoticSoundList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       string s;
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-
-       s = me.soundName(me,i);
-       if(s == cvar_string("menu_cdtrack")) // current menu track
-               draw_CenterText((me.columnNumberOrigin + 0.5 * me.columnNumberSize) * eX + me.realUpperMargin * eY, "[C]", me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
-       else if(s == cvar_defstring("menu_cdtrack")) // default menu track
-               draw_CenterText((me.columnNumberOrigin + 0.5 * me.columnNumberSize) * eX + me.realUpperMargin * eY, "[D]", me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
-
-       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
-}
-
-void XonoticSoundList_showNotify(entity me)
-{
-       me.getSounds(me);
-}
-
-void SoundList_Menu_Track_Change(entity box, entity me)
-{
-       cvar_set("menu_cdtrack", me.soundName(me,me.selectedItem));
-}
-
-void SoundList_Menu_Track_Reset(entity box, entity me)
-{
-       cvar_set("menu_cdtrack", cvar_defstring("menu_cdtrack"));
-}
-
-void SoundList_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.getSounds(me);
-}
-
-void SoundList_Add(entity box, entity me)
-{
-       me.playlist.addToPlayList(me.playlist, me.soundName(me, me.selectedItem));
-}
-
-void SoundList_Add_All(entity box, entity me)
-{
-       float i;
-       for(i = 0; i < me.nItems; ++i)
-               me.playlist.addToPlayList(me.playlist, me.soundName(me, i));
-}
-
-void XonoticSoundList_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       me.playlist.addToPlayList(me.playlist, me.soundName(me, i));
-}
-
-float XonoticSoundList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if(scan == K_ENTER || scan == K_KP_ENTER || scan == K_SPACE) {
-               me.playlist.addToPlayList(me.playlist, me.soundName(me, me.selectedItem));
-               return 1;
-       }
-       else
-               return SUPER(XonoticSoundList).keyDown(me, scan, ascii, shift);
-}
-#endif
-
diff --git a/qcsrc/menu/xonotic/soundlist.qc b/qcsrc/menu/xonotic/soundlist.qc
new file mode 100644 (file)
index 0000000..7d15150
--- /dev/null
@@ -0,0 +1,175 @@
+#ifdef INTERFACE
+CLASS(XonoticSoundList) EXTENDS(XonoticListBox)
+       METHOD(XonoticSoundList, configureXonoticSoundList, void(entity))
+       ATTRIB(XonoticSoundList, rowsPerItem, float, 1)
+       METHOD(XonoticSoundList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticSoundList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticSoundList, getSounds, void(entity))
+       METHOD(XonoticSoundList, soundName, string(entity, float))
+       METHOD(XonoticSoundList, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticSoundList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticSoundList, destroy, void(entity))
+       METHOD(XonoticSoundList, showNotify, void(entity))
+
+       ATTRIB(XonoticSoundList, listSound, float, -1)
+       ATTRIB(XonoticSoundList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticSoundList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticSoundList, columnNameSize, float, 0)
+       ATTRIB(XonoticSoundList, columnNumberOrigin, float, 0)
+       ATTRIB(XonoticSoundList, columnNumberSize, float, 0)
+       ATTRIB(XonoticSoundList, realUpperMargin, float, 0)
+       ATTRIB(XonoticSoundList, origin, vector, '0 0 0')
+       ATTRIB(XonoticSoundList, itemAbsSize, vector, '0 0 0')
+
+       ATTRIB(XonoticSoundList, filterString, string, string_null)
+       ATTRIB(XonoticSoundList, playlist, entity, world)
+ENDCLASS(XonoticSoundList)
+
+entity makeXonoticSoundList();
+void SoundList_Filter_Change(entity box, entity me);
+void SoundList_Add(entity box, entity me);
+void SoundList_Add_All(entity box, entity me);
+void SoundList_Menu_Track_Change(entity box, entity me);
+void SoundList_Menu_Track_Reset(entity box, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeXonoticSoundList()
+{
+       entity me;
+       me = spawnXonoticSoundList();
+       me.configureXonoticSoundList(me);
+       return me;
+}
+
+void XonoticSoundList_configureXonoticSoundList(entity me)
+{
+       me.configureXonoticListBox(me);
+       me.getSounds(me);
+}
+
+string XonoticSoundList_soundName(entity me, float i )
+{
+       string s;
+       s = search_getfilename(me.listSound, i);
+       s = substring(s, 15, strlen(s) - 15 - 4);  // sound/cdtracks/, .ogg
+       return s;
+}
+
+
+void XonoticSoundList_getSounds(entity me)
+{
+       string s;
+
+       if(me.filterString)
+               //subdirectory in filterString allowed
+               s = strcat("sound/cdtracks/*", me.filterString, "*.ogg");
+       else
+               s = "sound/cdtracks/*.ogg";
+
+       if(me.listSound >= 0)
+               search_end(me.listSound);
+
+       me.listSound = search_begin(s, FALSE, TRUE);
+
+       if(me.listSound < 0)
+               me.nItems=0;
+       else
+               me.nItems=search_getsize(me.listSound);
+}
+
+void XonoticSoundList_destroy(entity me)
+{
+       if(me.listSound >= 0)
+               search_end(me.listSound);
+}
+
+void XonoticSoundList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticSoundList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+
+       me.columnNumberOrigin = 0;
+       me.columnNumberSize = me.realFontSize_x * 3;
+
+       me.columnNameOrigin = me.columnNumberSize;
+       me.columnNameSize = 1 - me.columnNameOrigin - me.realFontSize_x;
+}
+
+void XonoticSoundList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       string s;
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       s = me.soundName(me,i);
+       if(s == cvar_string("menu_cdtrack")) // current menu track
+               draw_CenterText((me.columnNumberOrigin + 0.5 * me.columnNumberSize) * eX + me.realUpperMargin * eY, "[C]", me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+       else if(s == cvar_defstring("menu_cdtrack")) // default menu track
+               draw_CenterText((me.columnNumberOrigin + 0.5 * me.columnNumberSize) * eX + me.realUpperMargin * eY, "[D]", me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+
+       s = draw_TextShortenToWidth(s, me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0);
+}
+
+void XonoticSoundList_showNotify(entity me)
+{
+       me.getSounds(me);
+}
+
+void SoundList_Menu_Track_Change(entity box, entity me)
+{
+       cvar_set("menu_cdtrack", me.soundName(me,me.selectedItem));
+}
+
+void SoundList_Menu_Track_Reset(entity box, entity me)
+{
+       cvar_set("menu_cdtrack", cvar_defstring("menu_cdtrack"));
+}
+
+void SoundList_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.getSounds(me);
+}
+
+void SoundList_Add(entity box, entity me)
+{
+       me.playlist.addToPlayList(me.playlist, me.soundName(me, me.selectedItem));
+}
+
+void SoundList_Add_All(entity box, entity me)
+{
+       float i;
+       for(i = 0; i < me.nItems; ++i)
+               me.playlist.addToPlayList(me.playlist, me.soundName(me, i));
+}
+
+void XonoticSoundList_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       me.playlist.addToPlayList(me.playlist, me.soundName(me, i));
+}
+
+float XonoticSoundList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_KP_ENTER || scan == K_SPACE) {
+               me.playlist.addToPlayList(me.playlist, me.soundName(me, me.selectedItem));
+               return 1;
+       }
+       else
+               return SUPER(XonoticSoundList).keyDown(me, scan, ascii, shift);
+}
+#endif
+
diff --git a/qcsrc/menu/xonotic/statslist.c b/qcsrc/menu/xonotic/statslist.c
deleted file mode 100644 (file)
index c7b744a..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticStatsList) EXTENDS(XonoticListBox)
-       METHOD(XonoticStatsList, configureXonoticStatsList, void(entity))
-       ATTRIB(XonoticStatsList, rowsPerItem, float, 1.4)
-       METHOD(XonoticStatsList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticStatsList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticStatsList, getStats, void(entity))
-       METHOD(XonoticStatsList, doubleClickListBoxItem, void(entity, float, vector))
-       METHOD(XonoticStatsList, keyDown, float(entity, float, float, float))
-       METHOD(XonoticStatsList, destroy, void(entity))
-       METHOD(XonoticStatsList, showNotify, void(entity))
-
-       ATTRIB(XonoticStatsList, listStats, float, -1)
-       ATTRIB(XonoticStatsList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticStatsList, realUpperMargin, float, 0)
-       ATTRIB(XonoticStatsList, columnNameOrigin, float, 0)
-       ATTRIB(XonoticStatsList, columnNameSize, float, 0)
-ENDCLASS(XonoticStatsList)
-
-entity statslist; // for reference elsewhere
-entity makeXonoticStatsList();
-#endif
-
-#ifdef IMPLEMENTATION
-
-entity makeXonoticStatsList()
-{
-       entity me;
-       me = spawnXonoticStatsList();
-       me.configureXonoticStatsList(me);
-       return me;
-}
-
-void XonoticStatsList_configureXonoticStatsList(entity me)
-{
-       me.configureXonoticListBox(me);
-       me.getStats(me);
-}
-
-string XonoticStatsList_convertDate(string input)
-{
-       // 2013-12-21
-       // 0123456789
-       if(strlen(input) != 10)
-               return input;
-
-       string monthname = "";
-
-       switch(stof(substring(input, 5, 2)))
-       {
-               case 1:  monthname = _("January");    break;
-               case 2:  monthname = _("February");   break;
-               case 3:  monthname = _("March");      break;
-               case 4:  monthname = _("April");      break;
-               case 5:  monthname = _("May");        break;
-               case 6:  monthname = _("June");       break;
-               case 7:  monthname = _("July");       break;
-               case 8:  monthname = _("August");     break;
-               case 9:  monthname = _("September");  break;
-               case 10: monthname = _("October");    break;
-               case 11: monthname = _("November");   break;
-               case 12: monthname = _("December");   break;
-               default: return input; // failed, why?
-       }
-
-       return sprintf(
-               "%s %s, %d",
-               monthname,
-               count_ordinal(stof(substring(input, 8, 2))),
-               stof(substring(input, 0, 4))
-       );
-}
-
-void XonoticStatsList_getStats(entity me)
-{
-       dprint("XonoticStatsList_getStats() at time: ", ftos(time), "\n");
-       // delete the old buffer if it exists
-       if(me.listStats >= 0)
-               buf_del(me.listStats);
-
-       // create the new buffer if we have a stats buffer
-       if(PS_D_IN_DB >= 0)
-               me.listStats = buf_create();
-
-       // now confirmation, if we didn't create a buffer then just return now
-       if(me.listStats < 0)
-       {
-               me.nItems = 0;
-               return;
-       }
-
-       float order = 0;
-       string e = "", en = "", data = "";
-
-       string outstr = ""; // NOTE: out string MUST use underscores for spaces here, we'll replace them later
-       string orderstr = "";
-
-       float out_total_matches = -1;
-       float out_total_wins = -1;
-       float out_total_losses = -1;
-
-       float out_total_kills = -1;
-       float out_total_deaths = -1;
-
-       for(e = PS_D_IN_EVL; (en = db_get(PS_D_IN_DB, e)) != ""; e = en)
-       {
-               order = 0;
-               outstr = "";
-               orderstr = "";
-               data = db_get(PS_D_IN_DB, sprintf("#%s", e));
-
-               // non-gamemode specific stuff
-               switch(e)
-               {
-                       case "overall/joined_dt":
-                       {
-                               order = 1;
-                               outstr = _("Joined:");
-                               data = XonoticStatsList_convertDate(car(data));
-                               break;
-                       }
-                       case "overall/last_seen_dt":
-                       {
-                               order = 1;
-                               outstr = _("Last_Seen:");
-                               data = XonoticStatsList_convertDate(car(data));
-                               break;
-                       }
-                       case "overall/alivetime":
-                       {
-                               order = 1;
-                               outstr = _("Time_Played:");
-                               data = process_time(3, stof(data));
-                               break;
-                       }
-                       case "overall/favorite-map":
-                       {
-                               order = 2;
-                               outstr = _("Favorite_Map:");
-                               data = car(data);
-                               break;
-                       }
-                       case "overall/matches":
-                       {
-                               order = -1;
-                               out_total_matches = stof(data);
-                               break;
-                       }
-                       case "overall/wins":
-                       {
-                               order = -1;
-                               out_total_wins = stof(data);
-                               break;
-                       }
-                       case "overall/total-kills":
-                       {
-                               order = -1;
-                               out_total_kills = stof(data);
-                               break;
-                       }
-                       case "overall/total-deaths":
-                       {
-                               order = -1;
-                               out_total_deaths = stof(data);
-                               break;
-                       }
-               }
-
-               if((order == -1) && (out_total_matches >= 0) && (out_total_wins >= 0))
-               {
-                       bufstr_add(me.listStats, sprintf("003Matches: %d", out_total_matches), TRUE);
-                       
-                       if(out_total_matches > 0) // don't show extra info if there are no matches played
-                       {
-                               out_total_losses = max(0, (out_total_matches - out_total_wins));
-                               bufstr_add(me.listStats, sprintf("003Wins/Losses: %d/%d", out_total_wins, out_total_losses), TRUE);
-                               bufstr_add(me.listStats, sprintf("004Win_Percentage: %d%%", ((out_total_wins / out_total_matches) * 100)), TRUE);
-                       }
-
-                       out_total_matches = -1;
-                       out_total_wins = -1;
-                       out_total_losses = -1;
-                       continue;
-               }
-
-               if((order == -1) && (out_total_kills >= 0) && (out_total_deaths >= 0))
-               {
-                       bufstr_add(me.listStats, sprintf("005Kills/Deaths: %d/%d", out_total_kills, out_total_deaths), TRUE);
-
-                       // if there are no deaths, just show kill count 
-                       if(out_total_deaths > 0)
-                               bufstr_add(me.listStats, sprintf("006Kill_Ratio: %.2f", (out_total_kills / out_total_deaths)), TRUE);
-                       else
-                               bufstr_add(me.listStats, sprintf("006Kill_Ratio: %.2f", out_total_kills), TRUE);
-
-                       out_total_kills = -1;
-                       out_total_deaths = -1;
-                       continue;
-               }
-
-               // game mode specific stuff
-               if(order > 0)
-               {
-                       orderstr = sprintf("%03d", order);
-               }
-               else
-               {
-                       float dividerpos = strstrofs(e, "/", 0);
-                       
-                       string gametype = substring(e, 0, dividerpos);
-                       if(gametype == "overall") { continue; }
-                       
-                       string event = substring(e, (dividerpos + 1), strlen(e) - (dividerpos + 1));
-
-                       // if we are ranked, read these sets of possible options
-                       if(stof(db_get(PS_D_IN_DB, sprintf("#%s/rank", gametype))))
-                       {
-                               switch(event)
-                               {
-                                       case "matches":
-                                       {
-                                               order = 1;
-                                               outstr = sprintf(_("%s_Matches:"), strtoupper(gametype));
-                                               //data = sprintf(_("%d (unranked)"), data);
-                                               break;
-                                       }
-                                       case "elo":
-                                       {
-                                               order = 2;
-                                               outstr = sprintf(_("%s_ELO:"), strtoupper(gametype));
-                                               data = sprintf("%d", stof(data));
-                                               break;
-                                       }
-                                       case "rank":
-                                       {
-                                               order = 3;
-                                               outstr = sprintf(_("%s_Rank:"), strtoupper(gametype));
-                                               data = sprintf("%d", stof(data));
-                                               break;
-                                       }
-                                       case "percentile":
-                                       {
-                                               order = 4;
-                                               outstr = sprintf(_("%s_Percentile:"), strtoupper(gametype));
-                                               data = sprintf("%d%%", stof(data));
-                                               break;
-                                       }
-                                       
-                                       #if 0
-                                       case "favorite-map":
-                                       {
-                                               order = 5;
-                                               outstr = sprintf(_("%s_Favorite_Map:"), strtoupper(gametype));
-                                               //data = sprintf(_("%d (unranked)"), data);
-                                               break;
-                                       }
-                                       #endif
-                                       
-                                       default: continue; // nothing to see here
-                               }
-
-                               // now set up order for sorting later
-                               orderstr = sprintf("%2.2s%d", gametype, order);
-                       }
-                       else if(event == "matches")
-                       {
-                               outstr = sprintf(_("%s_Matches:"), strtoupper(gametype));
-                               data = sprintf(_("%d (unranked)"), stof(data));
-
-                               // unranked game modes ALWAYS get put last
-                               orderstr = "zzz";
-                       }
-                       else { continue; }
-               }
-
-               bufstr_add(me.listStats, sprintf("%s%s %s", orderstr, outstr, data), TRUE);
-       }
-
-       me.nItems = buf_getsize(me.listStats);
-       if(me.nItems > 0)
-               buf_sort(me.listStats, 128, FALSE);
-}
-
-void XonoticStatsList_destroy(entity me)
-{
-       if(me.nItems > 0)
-               buf_del(me.listStats);
-}
-
-void XonoticStatsList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.itemAbsSize = '0 0 0';
-       SUPER(XonoticStatsList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
-
-#if 0
-       me.columnNameOrigin = me.realFontSize_x;
-       me.columnNameSize = 0.5 - me.realFontSize_x; // end halfway at maximum length
-       me.columnDataOrigin = me.columnNameOrigin + me.columnNameSize;
-       me.columnDataSize = 1 - me.columnNameSize - me.realFontSize_x; // fill the rest of the control
-#else
-       me.columnNameOrigin = me.realFontSize_x;
-       me.columnNameSize = 1 - 2 * me.realFontSize_x;
-#endif
-}
-
-void XonoticStatsList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-
-       string data = bufstr_get(me.listStats, i);
-       string s = car(data);
-       string d = cdr(data);
-       
-       s = substring(s, 3, strlen(s) - 3);
-       s = strreplace("_", " ", s);
-       s = draw_TextShortenToWidth(s, 0.5 * me.columnNameSize, 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
-
-       d = draw_TextShortenToWidth(d, me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize), 0, me.realFontSize);
-       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 1 * (me.columnNameSize - draw_TextWidth(d, 0, me.realFontSize))) * eX, d, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
-}
-
-void XonoticStatsList_showNotify(entity me)
-{
-       PlayerStats_PlayerDetail_CheckUpdate();
-}
-
-void XonoticStatsList_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       //DemoConfirm_ListClick_Check_Gamestatus(me);
-}
-
-float XonoticStatsList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if(scan == K_ENTER || scan == K_KP_ENTER)
-       {
-               //DemoConfirm_ListClick_Check_Gamestatus(me);
-               return 1;
-       }
-       else
-       {
-               return SUPER(XonoticStatsList).keyDown(me, scan, ascii, shift);
-       }
-}
-#endif
-
diff --git a/qcsrc/menu/xonotic/statslist.qc b/qcsrc/menu/xonotic/statslist.qc
new file mode 100644 (file)
index 0000000..c7b744a
--- /dev/null
@@ -0,0 +1,351 @@
+#ifdef INTERFACE
+CLASS(XonoticStatsList) EXTENDS(XonoticListBox)
+       METHOD(XonoticStatsList, configureXonoticStatsList, void(entity))
+       ATTRIB(XonoticStatsList, rowsPerItem, float, 1.4)
+       METHOD(XonoticStatsList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticStatsList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticStatsList, getStats, void(entity))
+       METHOD(XonoticStatsList, doubleClickListBoxItem, void(entity, float, vector))
+       METHOD(XonoticStatsList, keyDown, float(entity, float, float, float))
+       METHOD(XonoticStatsList, destroy, void(entity))
+       METHOD(XonoticStatsList, showNotify, void(entity))
+
+       ATTRIB(XonoticStatsList, listStats, float, -1)
+       ATTRIB(XonoticStatsList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticStatsList, realUpperMargin, float, 0)
+       ATTRIB(XonoticStatsList, columnNameOrigin, float, 0)
+       ATTRIB(XonoticStatsList, columnNameSize, float, 0)
+ENDCLASS(XonoticStatsList)
+
+entity statslist; // for reference elsewhere
+entity makeXonoticStatsList();
+#endif
+
+#ifdef IMPLEMENTATION
+
+entity makeXonoticStatsList()
+{
+       entity me;
+       me = spawnXonoticStatsList();
+       me.configureXonoticStatsList(me);
+       return me;
+}
+
+void XonoticStatsList_configureXonoticStatsList(entity me)
+{
+       me.configureXonoticListBox(me);
+       me.getStats(me);
+}
+
+string XonoticStatsList_convertDate(string input)
+{
+       // 2013-12-21
+       // 0123456789
+       if(strlen(input) != 10)
+               return input;
+
+       string monthname = "";
+
+       switch(stof(substring(input, 5, 2)))
+       {
+               case 1:  monthname = _("January");    break;
+               case 2:  monthname = _("February");   break;
+               case 3:  monthname = _("March");      break;
+               case 4:  monthname = _("April");      break;
+               case 5:  monthname = _("May");        break;
+               case 6:  monthname = _("June");       break;
+               case 7:  monthname = _("July");       break;
+               case 8:  monthname = _("August");     break;
+               case 9:  monthname = _("September");  break;
+               case 10: monthname = _("October");    break;
+               case 11: monthname = _("November");   break;
+               case 12: monthname = _("December");   break;
+               default: return input; // failed, why?
+       }
+
+       return sprintf(
+               "%s %s, %d",
+               monthname,
+               count_ordinal(stof(substring(input, 8, 2))),
+               stof(substring(input, 0, 4))
+       );
+}
+
+void XonoticStatsList_getStats(entity me)
+{
+       dprint("XonoticStatsList_getStats() at time: ", ftos(time), "\n");
+       // delete the old buffer if it exists
+       if(me.listStats >= 0)
+               buf_del(me.listStats);
+
+       // create the new buffer if we have a stats buffer
+       if(PS_D_IN_DB >= 0)
+               me.listStats = buf_create();
+
+       // now confirmation, if we didn't create a buffer then just return now
+       if(me.listStats < 0)
+       {
+               me.nItems = 0;
+               return;
+       }
+
+       float order = 0;
+       string e = "", en = "", data = "";
+
+       string outstr = ""; // NOTE: out string MUST use underscores for spaces here, we'll replace them later
+       string orderstr = "";
+
+       float out_total_matches = -1;
+       float out_total_wins = -1;
+       float out_total_losses = -1;
+
+       float out_total_kills = -1;
+       float out_total_deaths = -1;
+
+       for(e = PS_D_IN_EVL; (en = db_get(PS_D_IN_DB, e)) != ""; e = en)
+       {
+               order = 0;
+               outstr = "";
+               orderstr = "";
+               data = db_get(PS_D_IN_DB, sprintf("#%s", e));
+
+               // non-gamemode specific stuff
+               switch(e)
+               {
+                       case "overall/joined_dt":
+                       {
+                               order = 1;
+                               outstr = _("Joined:");
+                               data = XonoticStatsList_convertDate(car(data));
+                               break;
+                       }
+                       case "overall/last_seen_dt":
+                       {
+                               order = 1;
+                               outstr = _("Last_Seen:");
+                               data = XonoticStatsList_convertDate(car(data));
+                               break;
+                       }
+                       case "overall/alivetime":
+                       {
+                               order = 1;
+                               outstr = _("Time_Played:");
+                               data = process_time(3, stof(data));
+                               break;
+                       }
+                       case "overall/favorite-map":
+                       {
+                               order = 2;
+                               outstr = _("Favorite_Map:");
+                               data = car(data);
+                               break;
+                       }
+                       case "overall/matches":
+                       {
+                               order = -1;
+                               out_total_matches = stof(data);
+                               break;
+                       }
+                       case "overall/wins":
+                       {
+                               order = -1;
+                               out_total_wins = stof(data);
+                               break;
+                       }
+                       case "overall/total-kills":
+                       {
+                               order = -1;
+                               out_total_kills = stof(data);
+                               break;
+                       }
+                       case "overall/total-deaths":
+                       {
+                               order = -1;
+                               out_total_deaths = stof(data);
+                               break;
+                       }
+               }
+
+               if((order == -1) && (out_total_matches >= 0) && (out_total_wins >= 0))
+               {
+                       bufstr_add(me.listStats, sprintf("003Matches: %d", out_total_matches), TRUE);
+                       
+                       if(out_total_matches > 0) // don't show extra info if there are no matches played
+                       {
+                               out_total_losses = max(0, (out_total_matches - out_total_wins));
+                               bufstr_add(me.listStats, sprintf("003Wins/Losses: %d/%d", out_total_wins, out_total_losses), TRUE);
+                               bufstr_add(me.listStats, sprintf("004Win_Percentage: %d%%", ((out_total_wins / out_total_matches) * 100)), TRUE);
+                       }
+
+                       out_total_matches = -1;
+                       out_total_wins = -1;
+                       out_total_losses = -1;
+                       continue;
+               }
+
+               if((order == -1) && (out_total_kills >= 0) && (out_total_deaths >= 0))
+               {
+                       bufstr_add(me.listStats, sprintf("005Kills/Deaths: %d/%d", out_total_kills, out_total_deaths), TRUE);
+
+                       // if there are no deaths, just show kill count 
+                       if(out_total_deaths > 0)
+                               bufstr_add(me.listStats, sprintf("006Kill_Ratio: %.2f", (out_total_kills / out_total_deaths)), TRUE);
+                       else
+                               bufstr_add(me.listStats, sprintf("006Kill_Ratio: %.2f", out_total_kills), TRUE);
+
+                       out_total_kills = -1;
+                       out_total_deaths = -1;
+                       continue;
+               }
+
+               // game mode specific stuff
+               if(order > 0)
+               {
+                       orderstr = sprintf("%03d", order);
+               }
+               else
+               {
+                       float dividerpos = strstrofs(e, "/", 0);
+                       
+                       string gametype = substring(e, 0, dividerpos);
+                       if(gametype == "overall") { continue; }
+                       
+                       string event = substring(e, (dividerpos + 1), strlen(e) - (dividerpos + 1));
+
+                       // if we are ranked, read these sets of possible options
+                       if(stof(db_get(PS_D_IN_DB, sprintf("#%s/rank", gametype))))
+                       {
+                               switch(event)
+                               {
+                                       case "matches":
+                                       {
+                                               order = 1;
+                                               outstr = sprintf(_("%s_Matches:"), strtoupper(gametype));
+                                               //data = sprintf(_("%d (unranked)"), data);
+                                               break;
+                                       }
+                                       case "elo":
+                                       {
+                                               order = 2;
+                                               outstr = sprintf(_("%s_ELO:"), strtoupper(gametype));
+                                               data = sprintf("%d", stof(data));
+                                               break;
+                                       }
+                                       case "rank":
+                                       {
+                                               order = 3;
+                                               outstr = sprintf(_("%s_Rank:"), strtoupper(gametype));
+                                               data = sprintf("%d", stof(data));
+                                               break;
+                                       }
+                                       case "percentile":
+                                       {
+                                               order = 4;
+                                               outstr = sprintf(_("%s_Percentile:"), strtoupper(gametype));
+                                               data = sprintf("%d%%", stof(data));
+                                               break;
+                                       }
+                                       
+                                       #if 0
+                                       case "favorite-map":
+                                       {
+                                               order = 5;
+                                               outstr = sprintf(_("%s_Favorite_Map:"), strtoupper(gametype));
+                                               //data = sprintf(_("%d (unranked)"), data);
+                                               break;
+                                       }
+                                       #endif
+                                       
+                                       default: continue; // nothing to see here
+                               }
+
+                               // now set up order for sorting later
+                               orderstr = sprintf("%2.2s%d", gametype, order);
+                       }
+                       else if(event == "matches")
+                       {
+                               outstr = sprintf(_("%s_Matches:"), strtoupper(gametype));
+                               data = sprintf(_("%d (unranked)"), stof(data));
+
+                               // unranked game modes ALWAYS get put last
+                               orderstr = "zzz";
+                       }
+                       else { continue; }
+               }
+
+               bufstr_add(me.listStats, sprintf("%s%s %s", orderstr, outstr, data), TRUE);
+       }
+
+       me.nItems = buf_getsize(me.listStats);
+       if(me.nItems > 0)
+               buf_sort(me.listStats, 128, FALSE);
+}
+
+void XonoticStatsList_destroy(entity me)
+{
+       if(me.nItems > 0)
+               buf_del(me.listStats);
+}
+
+void XonoticStatsList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       me.itemAbsSize = '0 0 0';
+       SUPER(XonoticStatsList).resizeNotify(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.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
+
+#if 0
+       me.columnNameOrigin = me.realFontSize_x;
+       me.columnNameSize = 0.5 - me.realFontSize_x; // end halfway at maximum length
+       me.columnDataOrigin = me.columnNameOrigin + me.columnNameSize;
+       me.columnDataSize = 1 - me.columnNameSize - me.realFontSize_x; // fill the rest of the control
+#else
+       me.columnNameOrigin = me.realFontSize_x;
+       me.columnNameSize = 1 - 2 * me.realFontSize_x;
+#endif
+}
+
+void XonoticStatsList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+
+       string data = bufstr_get(me.listStats, i);
+       string s = car(data);
+       string d = cdr(data);
+       
+       s = substring(s, 3, strlen(s) - 3);
+       s = strreplace("_", " ", s);
+       s = draw_TextShortenToWidth(s, 0.5 * me.columnNameSize, 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
+
+       d = draw_TextShortenToWidth(d, me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize), 0, me.realFontSize);
+       draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 1 * (me.columnNameSize - draw_TextWidth(d, 0, me.realFontSize))) * eX, d, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
+}
+
+void XonoticStatsList_showNotify(entity me)
+{
+       PlayerStats_PlayerDetail_CheckUpdate();
+}
+
+void XonoticStatsList_doubleClickListBoxItem(entity me, float i, vector where)
+{
+       //DemoConfirm_ListClick_Check_Gamestatus(me);
+}
+
+float XonoticStatsList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(scan == K_ENTER || scan == K_KP_ENTER)
+       {
+               //DemoConfirm_ListClick_Check_Gamestatus(me);
+               return 1;
+       }
+       else
+       {
+               return SUPER(XonoticStatsList).keyDown(me, scan, ascii, shift);
+       }
+}
+#endif
+
diff --git a/qcsrc/menu/xonotic/tab.c b/qcsrc/menu/xonotic/tab.c
deleted file mode 100644 (file)
index d1a867a..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticTab) EXTENDS(Tab)
-       // still to be customized by user
-       /*
-       ATTRIB(XonoticTab, intendedWidth, float, 0)
-       ATTRIB(XonoticTab, rows, float, 3)
-       ATTRIB(XonoticTab, columns, float, 2)
-       */
-       METHOD(XonoticTab, showNotify, void(entity))
-
-       ATTRIB(XonoticTab, marginTop, float, 0) // pixels
-       ATTRIB(XonoticTab, marginBottom, float, 0) // pixels
-       ATTRIB(XonoticTab, marginLeft, float, 0) // pixels
-       ATTRIB(XonoticTab, marginRight, float, 0) // pixels
-       ATTRIB(XonoticTab, columnSpacing, float, SKINMARGIN_COLUMNS) // pixels
-       ATTRIB(XonoticTab, rowSpacing, float, SKINMARGIN_ROWS) // pixels
-       ATTRIB(XonoticTab, rowHeight, float, SKINFONTSIZE_NORMAL * SKINHEIGHT_NORMAL) // pixels
-       ATTRIB(XonoticTab, titleHeight, float, SKINFONTSIZE_TITLE * SKINHEIGHT_TITLE) // pixels
-
-       ATTRIB(XonoticTab, backgroundImage, string, string_null)
-ENDCLASS(XonoticTab)
-#endif
-
-#ifdef IMPLEMENTATION
-void XonoticTab_showNotify(entity me)
-{
-       loadAllCvars(me);
-       SUPER(XonoticTab).showNotify(me);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/tab.qc b/qcsrc/menu/xonotic/tab.qc
new file mode 100644 (file)
index 0000000..d1a867a
--- /dev/null
@@ -0,0 +1,30 @@
+#ifdef INTERFACE
+CLASS(XonoticTab) EXTENDS(Tab)
+       // still to be customized by user
+       /*
+       ATTRIB(XonoticTab, intendedWidth, float, 0)
+       ATTRIB(XonoticTab, rows, float, 3)
+       ATTRIB(XonoticTab, columns, float, 2)
+       */
+       METHOD(XonoticTab, showNotify, void(entity))
+
+       ATTRIB(XonoticTab, marginTop, float, 0) // pixels
+       ATTRIB(XonoticTab, marginBottom, float, 0) // pixels
+       ATTRIB(XonoticTab, marginLeft, float, 0) // pixels
+       ATTRIB(XonoticTab, marginRight, float, 0) // pixels
+       ATTRIB(XonoticTab, columnSpacing, float, SKINMARGIN_COLUMNS) // pixels
+       ATTRIB(XonoticTab, rowSpacing, float, SKINMARGIN_ROWS) // pixels
+       ATTRIB(XonoticTab, rowHeight, float, SKINFONTSIZE_NORMAL * SKINHEIGHT_NORMAL) // pixels
+       ATTRIB(XonoticTab, titleHeight, float, SKINFONTSIZE_TITLE * SKINHEIGHT_TITLE) // pixels
+
+       ATTRIB(XonoticTab, backgroundImage, string, string_null)
+ENDCLASS(XonoticTab)
+#endif
+
+#ifdef IMPLEMENTATION
+void XonoticTab_showNotify(entity me)
+{
+       loadAllCvars(me);
+       SUPER(XonoticTab).showNotify(me);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/tabcontroller.c b/qcsrc/menu/xonotic/tabcontroller.c
deleted file mode 100644 (file)
index 1faa625..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticTabController) EXTENDS(ModalController)
-       METHOD(XonoticTabController, configureXonoticTabController, void(entity, float))
-       METHOD(XonoticTabController, makeTabButton, entity(entity, string, entity))
-       ATTRIB(XonoticTabController, rows, float, 0)
-       ATTRIB(XonoticTabController, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticTabController, image, string, SKINGFX_BUTTON)
-ENDCLASS(XonoticTabController)
-entity makeXonoticTabController(float theRows);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticTabController(float theRows)
-{
-       entity me;
-       me = spawnXonoticTabController();
-       me.configureXonoticTabController(me, theRows);
-       return me;
-}
-void XonoticTabController_configureXonoticTabController(entity me, float theRows)
-{
-       me.rows = theRows;
-}
-entity XonoticTabController_makeTabButton(entity me, string theTitle, entity tab)
-{
-       entity b;
-       if(me.rows != tab.rows)
-               error("Tab dialog height mismatch!");
-       b = makeXonoticButton(theTitle, '0 0 0');
-               me.addTab(me, tab, b);
-       // TODO make this real tab buttons (with color parameters, and different gfx)
-       return b;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/tabcontroller.qc b/qcsrc/menu/xonotic/tabcontroller.qc
new file mode 100644 (file)
index 0000000..1faa625
--- /dev/null
@@ -0,0 +1,34 @@
+#ifdef INTERFACE
+CLASS(XonoticTabController) EXTENDS(ModalController)
+       METHOD(XonoticTabController, configureXonoticTabController, void(entity, float))
+       METHOD(XonoticTabController, makeTabButton, entity(entity, string, entity))
+       ATTRIB(XonoticTabController, rows, float, 0)
+       ATTRIB(XonoticTabController, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticTabController, image, string, SKINGFX_BUTTON)
+ENDCLASS(XonoticTabController)
+entity makeXonoticTabController(float theRows);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticTabController(float theRows)
+{
+       entity me;
+       me = spawnXonoticTabController();
+       me.configureXonoticTabController(me, theRows);
+       return me;
+}
+void XonoticTabController_configureXonoticTabController(entity me, float theRows)
+{
+       me.rows = theRows;
+}
+entity XonoticTabController_makeTabButton(entity me, string theTitle, entity tab)
+{
+       entity b;
+       if(me.rows != tab.rows)
+               error("Tab dialog height mismatch!");
+       b = makeXonoticButton(theTitle, '0 0 0');
+               me.addTab(me, tab, b);
+       // TODO make this real tab buttons (with color parameters, and different gfx)
+       return b;
+}
+#endif
diff --git a/qcsrc/menu/xonotic/textlabel.c b/qcsrc/menu/xonotic/textlabel.c
deleted file mode 100644 (file)
index c0e0806..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticTextLabel) EXTENDS(Label)
-       METHOD(XonoticTextLabel, configureXonoticTextLabel, void(entity, float, string))
-       METHOD(XonoticTextLabel, draw, void(entity))
-       ATTRIB(XonoticTextLabel, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticTextLabel, alpha, float, SKINALPHA_TEXT)
-       ATTRIB(XonoticTextLabel, disabledAlpha, float, SKINALPHA_DISABLED)
-ENDCLASS(XonoticTextLabel)
-entity makeXonoticTextLabel(float theAlign, string theText);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticTextLabel(float theAlign, string theText)
-{
-       entity me;
-       me = spawnXonoticTextLabel();
-       me.configureXonoticTextLabel(me, theAlign, theText);
-       return me;
-}
-entity makeXonoticHeaderLabel(string theText)
-{
-       entity me;
-       me = makeXonoticTextLabel(0.5, theText);
-       me.colorL = SKINCOLOR_HEADER;
-       me.alpha = SKINALPHA_HEADER;
-       me.isBold = TRUE;
-       return me;
-}
-void XonoticTextLabel_configureXonoticTextLabel(entity me, float theAlign, string theText)
-{
-       me.configureLabel(me, theText, me.fontSize, theAlign);
-}
-void XonoticTextLabel_draw(entity me)
-{
-       SUPER(XonoticTextLabel).draw(me);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/textlabel.qc b/qcsrc/menu/xonotic/textlabel.qc
new file mode 100644 (file)
index 0000000..c0e0806
--- /dev/null
@@ -0,0 +1,37 @@
+#ifdef INTERFACE
+CLASS(XonoticTextLabel) EXTENDS(Label)
+       METHOD(XonoticTextLabel, configureXonoticTextLabel, void(entity, float, string))
+       METHOD(XonoticTextLabel, draw, void(entity))
+       ATTRIB(XonoticTextLabel, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticTextLabel, alpha, float, SKINALPHA_TEXT)
+       ATTRIB(XonoticTextLabel, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(XonoticTextLabel)
+entity makeXonoticTextLabel(float theAlign, string theText);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticTextLabel(float theAlign, string theText)
+{
+       entity me;
+       me = spawnXonoticTextLabel();
+       me.configureXonoticTextLabel(me, theAlign, theText);
+       return me;
+}
+entity makeXonoticHeaderLabel(string theText)
+{
+       entity me;
+       me = makeXonoticTextLabel(0.5, theText);
+       me.colorL = SKINCOLOR_HEADER;
+       me.alpha = SKINALPHA_HEADER;
+       me.isBold = TRUE;
+       return me;
+}
+void XonoticTextLabel_configureXonoticTextLabel(entity me, float theAlign, string theText)
+{
+       me.configureLabel(me, theText, me.fontSize, theAlign);
+}
+void XonoticTextLabel_draw(entity me)
+{
+       SUPER(XonoticTextLabel).draw(me);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/textslider.c b/qcsrc/menu/xonotic/textslider.c
deleted file mode 100644 (file)
index 844b3ef..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticTextSlider) EXTENDS(TextSlider)
-       METHOD(XonoticTextSlider, configureXonoticTextSlider, void(entity, string))
-       METHOD(XonoticTextSlider, setValue, void(entity, float))
-       METHOD(XonoticTextSlider, configureXonoticTextSliderValues, void(entity))
-       ATTRIB(XonoticTextSlider, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticTextSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT)
-       ATTRIB(XonoticTextSlider, image, string, SKINGFX_SLIDER)
-       ATTRIB(XonoticTextSlider, tolerance, vector, SKINTOLERANCE_SLIDER)
-       ATTRIB(XonoticTextSlider, align, float, 0.5)
-       ATTRIB(XonoticTextSlider, color, vector, SKINCOLOR_SLIDER_N)
-       ATTRIB(XonoticTextSlider, colorC, vector, SKINCOLOR_SLIDER_C)
-       ATTRIB(XonoticTextSlider, colorF, vector, SKINCOLOR_SLIDER_F)
-       ATTRIB(XonoticTextSlider, colorD, vector, SKINCOLOR_SLIDER_D)
-       ATTRIB(XonoticTextSlider, color2, vector, SKINCOLOR_SLIDER_S)
-
-       ATTRIB(XonoticTextSlider, cvarName, string, string_null)
-       METHOD(XonoticTextSlider, loadCvars, void(entity))
-       METHOD(XonoticTextSlider, saveCvars, void(entity))
-       ATTRIB(XonoticTextSlider, sendCvars, float, 0)
-
-       ATTRIB(XonoticTextSlider, alpha, float, SKINALPHA_TEXT)
-       ATTRIB(XonoticTextSlider, disabledAlpha, float, SKINALPHA_DISABLED)
-ENDCLASS(XonoticTextSlider)
-entity makeXonoticTextSlider(string); // note: you still need to call addValue and configureXonoticTextSliderValues!
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticTextSlider(string theCvar)
-{
-       entity me;
-       me = spawnXonoticTextSlider();
-       me.configureXonoticTextSlider(me, theCvar);
-       return me;
-}
-void XonoticTextSlider_configureXonoticTextSlider(entity me, string theCvar)
-{
-       me.configureSliderVisuals(me, me.fontSize, me.align, me.valueSpace, me.image);
-       if(theCvar)
-       {
-               me.cvarName = theCvar;
-               me.tooltip = getZonedTooltipForIdentifier(theCvar);
-               // don't load it yet
-       }
-}
-void XonoticTextSlider_setValue(entity me, float val)
-{
-       if(val != me.value)
-       {
-               SUPER(XonoticTextSlider).setValue( me, val );
-               me.saveCvars(me);
-       }
-}
-void XonoticTextSlider_loadCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       var float n = tokenize_console(me.cvarName);
-       var string s = cvar_string(argv(0));
-       float i;
-       for(i = 1; i < n; ++i)
-               s = strcat(s, " ", cvar_string(argv(i)));
-       me.setValueFromIdentifier(me, s);
-       if(me.value < 0 && n > 1)
-       {
-               // if it failed: check if all cvars have the same value
-               // if yes, try its value as 1-word identifier
-               for(i = 1; i < n; ++i)
-                       if(cvar_string(argv(i)) != cvar_string(argv(i-1)))
-                               break;
-               if(i >= n)
-                       me.setValueFromIdentifier(me, cvar_string(argv(0)));
-       }
-}
-void XonoticTextSlider_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       if(me.value >= 0 && me.value < me.nValues)
-       {
-               var float n = tokenize_console(me.cvarName);
-               if(n == 1)
-               {
-                       // this is a special case to allow spaces in the identifiers
-                       cvar_set(argv(0), me.getIdentifier(me));
-                       CheckSendCvars(me, argv(0));
-               }
-               else
-               {
-                       float i;
-                       var float m = tokenize_console(strcat(me.cvarName, " ", me.getIdentifier(me)));
-                       if(m == n + 1)
-                       {
-                               for(i = 0; i < n; ++i)
-                               {
-                                       cvar_set(argv(i), argv(n));
-                                       CheckSendCvars(me, argv(i));
-                               }
-                       }
-                       else if(m == n * 2)
-                       {
-                               for(i = 0; i < n; ++i)
-                               {
-                                       cvar_set(argv(i), argv(i + n));
-                                       CheckSendCvars(me, argv(i));
-                               }
-                       }
-                       else
-                               error("XonoticTextSlider: invalid identifier ", me.getIdentifier(me), " does not match cvar list ", me.cvarName);
-               }
-       }
-}
-void XonoticTextSlider_configureXonoticTextSliderValues(entity me)
-{
-       me.configureTextSliderValues(me, string_null);
-       me.loadCvars(me);
-}
-#endif
diff --git a/qcsrc/menu/xonotic/textslider.qc b/qcsrc/menu/xonotic/textslider.qc
new file mode 100644 (file)
index 0000000..844b3ef
--- /dev/null
@@ -0,0 +1,120 @@
+#ifdef INTERFACE
+CLASS(XonoticTextSlider) EXTENDS(TextSlider)
+       METHOD(XonoticTextSlider, configureXonoticTextSlider, void(entity, string))
+       METHOD(XonoticTextSlider, setValue, void(entity, float))
+       METHOD(XonoticTextSlider, configureXonoticTextSliderValues, void(entity))
+       ATTRIB(XonoticTextSlider, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticTextSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT)
+       ATTRIB(XonoticTextSlider, image, string, SKINGFX_SLIDER)
+       ATTRIB(XonoticTextSlider, tolerance, vector, SKINTOLERANCE_SLIDER)
+       ATTRIB(XonoticTextSlider, align, float, 0.5)
+       ATTRIB(XonoticTextSlider, color, vector, SKINCOLOR_SLIDER_N)
+       ATTRIB(XonoticTextSlider, colorC, vector, SKINCOLOR_SLIDER_C)
+       ATTRIB(XonoticTextSlider, colorF, vector, SKINCOLOR_SLIDER_F)
+       ATTRIB(XonoticTextSlider, colorD, vector, SKINCOLOR_SLIDER_D)
+       ATTRIB(XonoticTextSlider, color2, vector, SKINCOLOR_SLIDER_S)
+
+       ATTRIB(XonoticTextSlider, cvarName, string, string_null)
+       METHOD(XonoticTextSlider, loadCvars, void(entity))
+       METHOD(XonoticTextSlider, saveCvars, void(entity))
+       ATTRIB(XonoticTextSlider, sendCvars, float, 0)
+
+       ATTRIB(XonoticTextSlider, alpha, float, SKINALPHA_TEXT)
+       ATTRIB(XonoticTextSlider, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(XonoticTextSlider)
+entity makeXonoticTextSlider(string); // note: you still need to call addValue and configureXonoticTextSliderValues!
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticTextSlider(string theCvar)
+{
+       entity me;
+       me = spawnXonoticTextSlider();
+       me.configureXonoticTextSlider(me, theCvar);
+       return me;
+}
+void XonoticTextSlider_configureXonoticTextSlider(entity me, string theCvar)
+{
+       me.configureSliderVisuals(me, me.fontSize, me.align, me.valueSpace, me.image);
+       if(theCvar)
+       {
+               me.cvarName = theCvar;
+               me.tooltip = getZonedTooltipForIdentifier(theCvar);
+               // don't load it yet
+       }
+}
+void XonoticTextSlider_setValue(entity me, float val)
+{
+       if(val != me.value)
+       {
+               SUPER(XonoticTextSlider).setValue( me, val );
+               me.saveCvars(me);
+       }
+}
+void XonoticTextSlider_loadCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       var float n = tokenize_console(me.cvarName);
+       var string s = cvar_string(argv(0));
+       float i;
+       for(i = 1; i < n; ++i)
+               s = strcat(s, " ", cvar_string(argv(i)));
+       me.setValueFromIdentifier(me, s);
+       if(me.value < 0 && n > 1)
+       {
+               // if it failed: check if all cvars have the same value
+               // if yes, try its value as 1-word identifier
+               for(i = 1; i < n; ++i)
+                       if(cvar_string(argv(i)) != cvar_string(argv(i-1)))
+                               break;
+               if(i >= n)
+                       me.setValueFromIdentifier(me, cvar_string(argv(0)));
+       }
+}
+void XonoticTextSlider_saveCvars(entity me)
+{
+       if (!me.cvarName)
+               return;
+
+       if(me.value >= 0 && me.value < me.nValues)
+       {
+               var float n = tokenize_console(me.cvarName);
+               if(n == 1)
+               {
+                       // this is a special case to allow spaces in the identifiers
+                       cvar_set(argv(0), me.getIdentifier(me));
+                       CheckSendCvars(me, argv(0));
+               }
+               else
+               {
+                       float i;
+                       var float m = tokenize_console(strcat(me.cvarName, " ", me.getIdentifier(me)));
+                       if(m == n + 1)
+                       {
+                               for(i = 0; i < n; ++i)
+                               {
+                                       cvar_set(argv(i), argv(n));
+                                       CheckSendCvars(me, argv(i));
+                               }
+                       }
+                       else if(m == n * 2)
+                       {
+                               for(i = 0; i < n; ++i)
+                               {
+                                       cvar_set(argv(i), argv(i + n));
+                                       CheckSendCvars(me, argv(i));
+                               }
+                       }
+                       else
+                               error("XonoticTextSlider: invalid identifier ", me.getIdentifier(me), " does not match cvar list ", me.cvarName);
+               }
+       }
+}
+void XonoticTextSlider_configureXonoticTextSliderValues(entity me)
+{
+       me.configureTextSliderValues(me, string_null);
+       me.loadCvars(me);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/weaponarenacheckbox.c b/qcsrc/menu/xonotic/weaponarenacheckbox.c
deleted file mode 100644 (file)
index 163f9c6..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticWeaponarenaCheckBox) EXTENDS(CheckBox)
-       METHOD(XonoticWeaponarenaCheckBox, configureXonoticWeaponarenaCheckBox, void(entity, string, string))
-       METHOD(XonoticWeaponarenaCheckBox, setChecked, void(entity, float))
-       ATTRIB(XonoticWeaponarenaCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticWeaponarenaCheckBox, image, string, SKINGFX_CHECKBOX)
-       ATTRIB(XonoticWeaponarenaCheckBox, netname, string, string_null)
-
-       METHOD(XonoticWeaponarenaCheckBox, loadCvars, void(entity))
-       METHOD(XonoticWeaponarenaCheckBox, saveCvars, void(entity))
-ENDCLASS(XonoticWeaponarenaCheckBox)
-entity makeXonoticWeaponarenaCheckBox(string, string);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticWeaponarenaCheckBox(string theWeapon, string theText)
-{
-       entity me;
-       me = spawnXonoticWeaponarenaCheckBox();
-       me.configureXonoticWeaponarenaCheckBox(me, theWeapon, theText);
-       return me;
-}
-void XonoticWeaponarenaCheckBox_configureXonoticWeaponarenaCheckBox(entity me, string theWeapon, string theText)
-{
-       me.netname = theWeapon;
-       me.checked = FALSE;
-       me.loadCvars(me);
-       me.configureCheckBox(me, theText, me.fontSize, me.image);
-}
-void XonoticWeaponarenaCheckBox_setChecked(entity me, float foo)
-{
-       me.checked = !me.checked;
-       me.saveCvars(me);
-}
-void XonoticWeaponarenaCheckBox_loadCvars(entity me)
-{
-       float n = tokenize_console(cvar_string("menu_weaponarena"));
-       float i;
-       for(i=0; i<n; ++i)
-       {
-               if(argv(i) == me.netname)
-               {
-                       me.checked = TRUE;
-                       break;
-               }
-       }
-}
-
-void XonoticWeaponarenaCheckBox_saveCvars(entity me)
-{
-       if(me.checked)
-               localcmd(strcat("\nmenu_cmd addtolist menu_weaponarena ", me.netname, "\n"));
-       else
-               localcmd(strcat("\nmenu_cmd removefromlist menu_weaponarena ", me.netname, "\n"));
-       localcmd("\ng_weaponarena \"$menu_weaponarena\"\n");
-}
-#endif
diff --git a/qcsrc/menu/xonotic/weaponarenacheckbox.qc b/qcsrc/menu/xonotic/weaponarenacheckbox.qc
new file mode 100644 (file)
index 0000000..163f9c6
--- /dev/null
@@ -0,0 +1,57 @@
+#ifdef INTERFACE
+CLASS(XonoticWeaponarenaCheckBox) EXTENDS(CheckBox)
+       METHOD(XonoticWeaponarenaCheckBox, configureXonoticWeaponarenaCheckBox, void(entity, string, string))
+       METHOD(XonoticWeaponarenaCheckBox, setChecked, void(entity, float))
+       ATTRIB(XonoticWeaponarenaCheckBox, fontSize, float, SKINFONTSIZE_NORMAL)
+       ATTRIB(XonoticWeaponarenaCheckBox, image, string, SKINGFX_CHECKBOX)
+       ATTRIB(XonoticWeaponarenaCheckBox, netname, string, string_null)
+
+       METHOD(XonoticWeaponarenaCheckBox, loadCvars, void(entity))
+       METHOD(XonoticWeaponarenaCheckBox, saveCvars, void(entity))
+ENDCLASS(XonoticWeaponarenaCheckBox)
+entity makeXonoticWeaponarenaCheckBox(string, string);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticWeaponarenaCheckBox(string theWeapon, string theText)
+{
+       entity me;
+       me = spawnXonoticWeaponarenaCheckBox();
+       me.configureXonoticWeaponarenaCheckBox(me, theWeapon, theText);
+       return me;
+}
+void XonoticWeaponarenaCheckBox_configureXonoticWeaponarenaCheckBox(entity me, string theWeapon, string theText)
+{
+       me.netname = theWeapon;
+       me.checked = FALSE;
+       me.loadCvars(me);
+       me.configureCheckBox(me, theText, me.fontSize, me.image);
+}
+void XonoticWeaponarenaCheckBox_setChecked(entity me, float foo)
+{
+       me.checked = !me.checked;
+       me.saveCvars(me);
+}
+void XonoticWeaponarenaCheckBox_loadCvars(entity me)
+{
+       float n = tokenize_console(cvar_string("menu_weaponarena"));
+       float i;
+       for(i=0; i<n; ++i)
+       {
+               if(argv(i) == me.netname)
+               {
+                       me.checked = TRUE;
+                       break;
+               }
+       }
+}
+
+void XonoticWeaponarenaCheckBox_saveCvars(entity me)
+{
+       if(me.checked)
+               localcmd(strcat("\nmenu_cmd addtolist menu_weaponarena ", me.netname, "\n"));
+       else
+               localcmd(strcat("\nmenu_cmd removefromlist menu_weaponarena ", me.netname, "\n"));
+       localcmd("\ng_weaponarena \"$menu_weaponarena\"\n");
+}
+#endif
diff --git a/qcsrc/menu/xonotic/weaponslist.c b/qcsrc/menu/xonotic/weaponslist.c
deleted file mode 100644 (file)
index 8a8e220..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticWeaponsList) EXTENDS(XonoticListBox)
-       METHOD(XonoticWeaponsList, configureXonoticWeaponsList, void(entity))
-       METHOD(XonoticWeaponsList, toString, string(entity))
-       ATTRIB(XonoticWeaponsList, rowsPerItem, float, 1)
-       METHOD(XonoticWeaponsList, draw, void(entity))
-       METHOD(XonoticWeaponsList, drawListBoxItem, void(entity, float, vector, float))
-       METHOD(XonoticWeaponsList, resizeNotify, void(entity, vector, vector, vector, vector))
-       METHOD(XonoticWeaponsList, keyDown, float(entity, float, float, float))
-       ATTRIB(XonoticWeaponsList, realFontSize, vector, '0 0 0')
-       ATTRIB(XonoticWeaponsList, realUpperMargin, float, 0)
-       METHOD(XonoticWeaponsList, mouseDrag, float(entity, vector))
-ENDCLASS(XonoticWeaponsList)
-entity makeXonoticWeaponsList();
-void WeaponsList_MoveUp_Click(entity btn, entity me);
-void WeaponsList_MoveDown_Click(entity box, entity me);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticWeaponsList()
-{
-       entity me;
-       me = spawnXonoticWeaponsList();
-       me.configureXonoticWeaponsList(me);
-       return me;
-}
-void XonoticWeaponsList_configureXonoticWeaponsList(entity me)
-{
-       me.configureXonoticListBox(me);
-}
-void XonoticWeaponsList_draw(entity me)
-{
-       // read in cvar?
-       string s, t;
-       s = W_NumberWeaponOrder(cvar_string("cl_weaponpriority"));
-       t = W_FixWeaponOrder(s, 1);
-       if(t != s)
-               cvar_set("cl_weaponpriority", W_NameWeaponOrder(t));
-       me.nItems = tokenize_console(t);
-       SUPER(XonoticWeaponsList).draw(me);
-}
-void WeaponsList_MoveUp_Click(entity box, entity me)
-{
-       if(me.selectedItem > 0)
-       {
-               cvar_set("cl_weaponpriority", swapInPriorityList(cvar_string("cl_weaponpriority"), me.selectedItem - 1, me.selectedItem));
-               me.selectedItem -= 1;
-       }
-}
-void WeaponsList_MoveDown_Click(entity box, entity me)
-{
-       if(me.selectedItem < me.nItems - 1)
-       {
-               cvar_set("cl_weaponpriority", swapInPriorityList(cvar_string("cl_weaponpriority"), me.selectedItem, me.selectedItem + 1));
-               me.selectedItem += 1;
-       }
-}
-void XonoticWeaponsList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(XonoticWeaponsList).resizeNotify(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);
-}
-float XonoticWeaponsList_mouseDrag(entity me, vector pos)
-{
-       float f, i;
-       i = me.selectedItem;
-       f = SUPER(XonoticWeaponsList).mouseDrag(me, pos);
-
-       if(me.pressed != 1) // don't change priority if the person is just scrolling
-       {
-               if(me.selectedItem != i)
-                       cvar_set("cl_weaponpriority", swapInPriorityList(cvar_string("cl_weaponpriority"), me.selectedItem, i));
-       }
-
-       return f;
-}
-string XonoticWeaponsList_toString(entity me)
-{
-       float n, i;
-       string s;
-       entity e;
-       n = tokenize_console(W_NumberWeaponOrder(cvar_string("cl_weaponpriority")));
-       s = "";
-       for(i = 0; i < n; ++i)
-       {
-               e = get_weaponinfo(stof(argv(i)));
-               s = strcat(s, e.message, ", ");
-       }
-       return substring(s, 0, strlen(s) - 2);
-}
-void XonoticWeaponsList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
-{
-       entity e;
-       if(isSelected)
-               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
-       e = get_weaponinfo(stof(argv(i)));
-       string msg = e.message;
-       if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
-               msg = sprintf(_("%s (mutator weapon)"), msg);
-
-       vector save_fontscale = draw_fontscale;
-       float f = draw_CondensedFontFactor(msg, FALSE, me.realFontSize, 1);
-       draw_fontscale_x *= f;
-       vector fs = me.realFontSize;
-       fs_x *= f;
-       draw_Text(me.realUpperMargin * eY, msg, fs, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
-       draw_fontscale = save_fontscale;
-}
-
-float XonoticWeaponsList_keyDown(entity me, float scan, float ascii, float shift)
-{
-       if(ascii == 43) // +
-       {
-               WeaponsList_MoveUp_Click(NULL, me);
-               return 1;
-       }
-       else if(ascii == 45) // -
-       {
-               WeaponsList_MoveDown_Click(NULL, me);
-               return 1;
-       }
-       else if(SUPER(XonoticWeaponsList).keyDown(me, scan, ascii, shift))
-               return 1;
-       return 0;
-}
-#endif
diff --git a/qcsrc/menu/xonotic/weaponslist.qc b/qcsrc/menu/xonotic/weaponslist.qc
new file mode 100644 (file)
index 0000000..8a8e220
--- /dev/null
@@ -0,0 +1,129 @@
+#ifdef INTERFACE
+CLASS(XonoticWeaponsList) EXTENDS(XonoticListBox)
+       METHOD(XonoticWeaponsList, configureXonoticWeaponsList, void(entity))
+       METHOD(XonoticWeaponsList, toString, string(entity))
+       ATTRIB(XonoticWeaponsList, rowsPerItem, float, 1)
+       METHOD(XonoticWeaponsList, draw, void(entity))
+       METHOD(XonoticWeaponsList, drawListBoxItem, void(entity, float, vector, float))
+       METHOD(XonoticWeaponsList, resizeNotify, void(entity, vector, vector, vector, vector))
+       METHOD(XonoticWeaponsList, keyDown, float(entity, float, float, float))
+       ATTRIB(XonoticWeaponsList, realFontSize, vector, '0 0 0')
+       ATTRIB(XonoticWeaponsList, realUpperMargin, float, 0)
+       METHOD(XonoticWeaponsList, mouseDrag, float(entity, vector))
+ENDCLASS(XonoticWeaponsList)
+entity makeXonoticWeaponsList();
+void WeaponsList_MoveUp_Click(entity btn, entity me);
+void WeaponsList_MoveDown_Click(entity box, entity me);
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticWeaponsList()
+{
+       entity me;
+       me = spawnXonoticWeaponsList();
+       me.configureXonoticWeaponsList(me);
+       return me;
+}
+void XonoticWeaponsList_configureXonoticWeaponsList(entity me)
+{
+       me.configureXonoticListBox(me);
+}
+void XonoticWeaponsList_draw(entity me)
+{
+       // read in cvar?
+       string s, t;
+       s = W_NumberWeaponOrder(cvar_string("cl_weaponpriority"));
+       t = W_FixWeaponOrder(s, 1);
+       if(t != s)
+               cvar_set("cl_weaponpriority", W_NameWeaponOrder(t));
+       me.nItems = tokenize_console(t);
+       SUPER(XonoticWeaponsList).draw(me);
+}
+void WeaponsList_MoveUp_Click(entity box, entity me)
+{
+       if(me.selectedItem > 0)
+       {
+               cvar_set("cl_weaponpriority", swapInPriorityList(cvar_string("cl_weaponpriority"), me.selectedItem - 1, me.selectedItem));
+               me.selectedItem -= 1;
+       }
+}
+void WeaponsList_MoveDown_Click(entity box, entity me)
+{
+       if(me.selectedItem < me.nItems - 1)
+       {
+               cvar_set("cl_weaponpriority", swapInPriorityList(cvar_string("cl_weaponpriority"), me.selectedItem, me.selectedItem + 1));
+               me.selectedItem += 1;
+       }
+}
+void XonoticWeaponsList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+{
+       SUPER(XonoticWeaponsList).resizeNotify(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);
+}
+float XonoticWeaponsList_mouseDrag(entity me, vector pos)
+{
+       float f, i;
+       i = me.selectedItem;
+       f = SUPER(XonoticWeaponsList).mouseDrag(me, pos);
+
+       if(me.pressed != 1) // don't change priority if the person is just scrolling
+       {
+               if(me.selectedItem != i)
+                       cvar_set("cl_weaponpriority", swapInPriorityList(cvar_string("cl_weaponpriority"), me.selectedItem, i));
+       }
+
+       return f;
+}
+string XonoticWeaponsList_toString(entity me)
+{
+       float n, i;
+       string s;
+       entity e;
+       n = tokenize_console(W_NumberWeaponOrder(cvar_string("cl_weaponpriority")));
+       s = "";
+       for(i = 0; i < n; ++i)
+       {
+               e = get_weaponinfo(stof(argv(i)));
+               s = strcat(s, e.message, ", ");
+       }
+       return substring(s, 0, strlen(s) - 2);
+}
+void XonoticWeaponsList_drawListBoxItem(entity me, float i, vector absSize, float isSelected)
+{
+       entity e;
+       if(isSelected)
+               draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
+       e = get_weaponinfo(stof(argv(i)));
+       string msg = e.message;
+       if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
+               msg = sprintf(_("%s (mutator weapon)"), msg);
+
+       vector save_fontscale = draw_fontscale;
+       float f = draw_CondensedFontFactor(msg, FALSE, me.realFontSize, 1);
+       draw_fontscale_x *= f;
+       vector fs = me.realFontSize;
+       fs_x *= f;
+       draw_Text(me.realUpperMargin * eY, msg, fs, SKINCOLOR_TEXT, SKINALPHA_TEXT, 0);
+       draw_fontscale = save_fontscale;
+}
+
+float XonoticWeaponsList_keyDown(entity me, float scan, float ascii, float shift)
+{
+       if(ascii == 43) // +
+       {
+               WeaponsList_MoveUp_Click(NULL, me);
+               return 1;
+       }
+       else if(ascii == 45) // -
+       {
+               WeaponsList_MoveDown_Click(NULL, me);
+               return 1;
+       }
+       else if(SUPER(XonoticWeaponsList).keyDown(me, scan, ascii, shift))
+               return 1;
+       return 0;
+}
+#endif