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)
-               // --><