From a191f217b4fae743761d766611f7a8332e0867db Mon Sep 17 00:00:00 2001 From: blackhc Date: Tue, 28 Dec 2004 20:43:56 +0000 Subject: [PATCH] Adding my current version of the scmenu to the nexuiz cvs. git-svn-id: svn://svn.icculus.org/nexuiz/trunk@245 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- scmenu/constants.menu | 99 +++ scmenu/creategame.menu | 146 +++++ scmenu/data.menu | 458 ++++++++++++++ scmenu/ingame.menu | 4 + scmenu/joingame.menu | 178 ++++++ scmenu/main.menu | 43 ++ scmenu/menu | 16 + scmenu/normal.menu | 61 ++ scmenu/options.menu | 68 ++ scmenu/options/color.menu | 123 ++++ scmenu/options/key.menu | 282 +++++++++ scmenu/options/player.menu | 72 +++ scmenu/options/sound.menu | 31 + scmenu/options/video.menu | 44 ++ scmenu/quit.menu | 66 ++ scmenu/source/base/cursor.qc | 96 +++ scmenu/source/base/cursor.qh | 32 + scmenu/source/base/gfx.qc | 159 +++++ scmenu/source/base/gfx.qh | 45 ++ scmenu/source/base/hostcache.qc | 35 ++ scmenu/source/base/hostcache.qh | 15 + scmenu/source/base/key.qc | 68 ++ scmenu/source/base/key.qh | 15 + scmenu/source/base/snd.qc | 29 + scmenu/source/base/snd.qh | 8 + scmenu/source/base/timer.qc | 22 + scmenu/source/base/timer.qh | 11 + scmenu/source/control/_fx/float.qc | 55 ++ scmenu/source/control/_fx/fx.qh | 61 ++ scmenu/source/control/_fx/interpol.qc | 12 + scmenu/source/control/_fx/vector.qc | 71 +++ .../source/control/automation/automation.qc | 13 + .../source/control/automation/automation.qh | 30 + scmenu/source/control/automation/foreach.qc | 23 + scmenu/source/control/automation/job.qc | 22 + scmenu/source/control/cinematic.qc | 49 ++ scmenu/source/control/constants.qh | 13 + scmenu/source/control/container.qc | 7 + scmenu/source/control/custom.qc | 22 + scmenu/source/control/data/altstring.qc | 25 + scmenu/source/control/data/base.qc | 166 +++++ scmenu/source/control/data/container.qc | 38 ++ scmenu/source/control/data/cvar.qc | 88 +++ scmenu/source/control/data/data.qh | 112 ++++ scmenu/source/control/data/fastresync.qc | 33 + scmenu/source/control/data/router.qc | 32 + scmenu/source/control/data/text.qc | 32 + scmenu/source/control/data/textswitch.qc | 62 ++ scmenu/source/control/data/texttime.qc | 74 +++ scmenu/source/control/data/textvalue.qc | 33 + scmenu/source/control/data/value.qc | 79 +++ scmenu/source/control/data/valueswitch.qc | 59 ++ scmenu/source/control/fx/base.qc | 69 +++ scmenu/source/control/fx/fx.qh | 21 + scmenu/source/control/items.qh | 99 +++ scmenu/source/control/link.qc | 63 ++ scmenu/source/control/visual/button.qc | 190 ++++++ scmenu/source/control/visual/editbox.qc | 189 ++++++ scmenu/source/control/visual/floating.qc | 54 ++ scmenu/source/control/visual/label.qc | 64 ++ scmenu/source/control/visual/multilabel.qc | 110 ++++ scmenu/source/control/visual/picture.qc | 36 ++ scmenu/source/control/visual/rect.qc | 18 + scmenu/source/control/visual/scrollbar.qc | 8 + scmenu/source/control/visual/slider.qc | 146 +++++ scmenu/source/control/visual/switchbutton.qc | 42 ++ scmenu/source/control/visual/valuebutton.qc | 31 + scmenu/source/control/visual/visual.qh | 183 ++++++ scmenu/source/control/window/arrangement.qc | 76 +++ scmenu/source/control/window/eventwindow.qc | 13 + scmenu/source/control/window/frame.qc | 9 + scmenu/source/control/window/layout.qc | 66 ++ scmenu/source/control/window/reference.qc | 68 ++ scmenu/source/control/window/scroll.qc | 46 ++ scmenu/source/control/window/window.qc | 58 ++ scmenu/source/control/window/windows.qh | 51 ++ scmenu/source/custom/color.qm | 46 ++ scmenu/source/custom/creategame.qm | 86 +++ scmenu/source/custom/creategame/creategame.qh | 30 + scmenu/source/custom/creategame/maps.qc | 193 ++++++ scmenu/source/custom/creategame/mods.qc | 85 +++ scmenu/source/custom/custom.qh | 5 + scmenu/source/custom/globalkey.qm | 32 + scmenu/source/custom/joingame.qc | 108 ++++ scmenu/source/custom/joingame.qh | 29 + scmenu/source/custom/joingame.qm | 224 +++++++ scmenu/source/custom/key.qc | 162 +++++ scmenu/source/custom/key.qh | 13 + scmenu/source/custom/key.qm | 65 ++ scmenu/source/custom/option.qm | 92 +++ scmenu/source/custom/player.qm | 56 ++ scmenu/source/custom/player/avatar.qc | 236 +++++++ scmenu/source/custom/player/name.qc | 67 ++ scmenu/source/custom/player/player.qh | 26 + scmenu/source/custom/quit.qm | 45 ++ scmenu/source/custom/stresstest.qm | 14 + scmenu/source/custom/util.qm | 13 + scmenu/source/custom/video.qc | 67 ++ scmenu/source/custom/video.qh | 9 + scmenu/source/custom/video.qm | 10 + scmenu/source/custom/visible.qc | 14 + scmenu/source/custom/visible.qm | 96 +++ scmenu/source/mbuiltin.qc | 201 ++++++ scmenu/source/menu.qc | 132 ++++ scmenu/source/menu.qh | 27 + scmenu/source/msys.qc | 289 +++++++++ scmenu/source/progdefs.h | 13 + scmenu/source/progs.src | 171 +++++ scmenu/source/system/debug.qc | 164 +++++ scmenu/source/system/debug.qh | 67 ++ scmenu/source/system/event_helper.qc | 290 +++++++++ scmenu/source/system/events.qc | 435 +++++++++++++ scmenu/source/system/events.qh | 56 ++ scmenu/source/system/events_.qc | 419 +++++++++++++ scmenu/source/system/gc.qc | 72 +++ scmenu/source/system/gc.qh | 14 + scmenu/source/system/history.qc | 81 +++ scmenu/source/system/history.qh | 23 + scmenu/source/system/isframe.qc | 334 ++++++++++ scmenu/source/system/isframe.qh | 56 ++ scmenu/source/system/item.qh | 126 ++++ scmenu/source/system/mgfx.qc | 158 +++++ scmenu/source/system/mgfx.qh | 36 ++ scmenu/source/system/parser.qc | 536 ++++++++++++++++ scmenu/source/system/parser.qh | 81 +++ scmenu/source/system/structure.qc | 583 ++++++++++++++++++ scmenu/source/system/structure.qh | 84 +++ scmenu/source/todo | 72 +++ scmenu/source/util/altstring.qc | 260 ++++++++ scmenu/source/util/altstring.qh | 14 + scmenu/source/util/nfunction.qc | 9 + scmenu/source/util/property.qc | 275 +++++++++ scmenu/source/util/property.qh | 27 + scmenu/source/util/rect.qc | 189 ++++++ scmenu/source/util/rect.qh | 27 + scmenu/source/util/string.qc | 123 ++++ scmenu/source/util/string.qh | 22 + scmenu/source/util/text.qc | 59 ++ scmenu/source/util/text.qh | 7 + scmenu/source/util/uid.qc | 33 + scmenu/source/util/uid.qh | 7 + scmenu/source/util/util.qh | 22 + scmenu/templates.menu | 217 +++++++ scmenu/test.menu | 21 + 144 files changed, 12802 insertions(+) create mode 100644 scmenu/constants.menu create mode 100644 scmenu/creategame.menu create mode 100644 scmenu/data.menu create mode 100644 scmenu/ingame.menu create mode 100644 scmenu/joingame.menu create mode 100644 scmenu/main.menu create mode 100644 scmenu/menu create mode 100644 scmenu/normal.menu create mode 100644 scmenu/options.menu create mode 100644 scmenu/options/color.menu create mode 100644 scmenu/options/key.menu create mode 100644 scmenu/options/player.menu create mode 100644 scmenu/options/sound.menu create mode 100644 scmenu/options/video.menu create mode 100644 scmenu/quit.menu create mode 100644 scmenu/source/base/cursor.qc create mode 100644 scmenu/source/base/cursor.qh create mode 100644 scmenu/source/base/gfx.qc create mode 100644 scmenu/source/base/gfx.qh create mode 100644 scmenu/source/base/hostcache.qc create mode 100644 scmenu/source/base/hostcache.qh create mode 100644 scmenu/source/base/key.qc create mode 100644 scmenu/source/base/key.qh create mode 100644 scmenu/source/base/snd.qc create mode 100644 scmenu/source/base/snd.qh create mode 100644 scmenu/source/base/timer.qc create mode 100644 scmenu/source/base/timer.qh create mode 100644 scmenu/source/control/_fx/float.qc create mode 100644 scmenu/source/control/_fx/fx.qh create mode 100644 scmenu/source/control/_fx/interpol.qc create mode 100644 scmenu/source/control/_fx/vector.qc create mode 100644 scmenu/source/control/automation/automation.qc create mode 100644 scmenu/source/control/automation/automation.qh create mode 100644 scmenu/source/control/automation/foreach.qc create mode 100644 scmenu/source/control/automation/job.qc create mode 100644 scmenu/source/control/cinematic.qc create mode 100644 scmenu/source/control/constants.qh create mode 100644 scmenu/source/control/container.qc create mode 100644 scmenu/source/control/custom.qc create mode 100644 scmenu/source/control/data/altstring.qc create mode 100644 scmenu/source/control/data/base.qc create mode 100644 scmenu/source/control/data/container.qc create mode 100644 scmenu/source/control/data/cvar.qc create mode 100644 scmenu/source/control/data/data.qh create mode 100644 scmenu/source/control/data/fastresync.qc create mode 100644 scmenu/source/control/data/router.qc create mode 100644 scmenu/source/control/data/text.qc create mode 100644 scmenu/source/control/data/textswitch.qc create mode 100644 scmenu/source/control/data/texttime.qc create mode 100644 scmenu/source/control/data/textvalue.qc create mode 100644 scmenu/source/control/data/value.qc create mode 100644 scmenu/source/control/data/valueswitch.qc create mode 100644 scmenu/source/control/fx/base.qc create mode 100644 scmenu/source/control/fx/fx.qh create mode 100644 scmenu/source/control/items.qh create mode 100644 scmenu/source/control/link.qc create mode 100644 scmenu/source/control/visual/button.qc create mode 100644 scmenu/source/control/visual/editbox.qc create mode 100644 scmenu/source/control/visual/floating.qc create mode 100644 scmenu/source/control/visual/label.qc create mode 100644 scmenu/source/control/visual/multilabel.qc create mode 100644 scmenu/source/control/visual/picture.qc create mode 100644 scmenu/source/control/visual/rect.qc create mode 100644 scmenu/source/control/visual/scrollbar.qc create mode 100644 scmenu/source/control/visual/slider.qc create mode 100644 scmenu/source/control/visual/switchbutton.qc create mode 100644 scmenu/source/control/visual/valuebutton.qc create mode 100644 scmenu/source/control/visual/visual.qh create mode 100644 scmenu/source/control/window/arrangement.qc create mode 100644 scmenu/source/control/window/eventwindow.qc create mode 100644 scmenu/source/control/window/frame.qc create mode 100644 scmenu/source/control/window/layout.qc create mode 100644 scmenu/source/control/window/reference.qc create mode 100644 scmenu/source/control/window/scroll.qc create mode 100644 scmenu/source/control/window/window.qc create mode 100644 scmenu/source/control/window/windows.qh create mode 100644 scmenu/source/custom/color.qm create mode 100644 scmenu/source/custom/creategame.qm create mode 100644 scmenu/source/custom/creategame/creategame.qh create mode 100644 scmenu/source/custom/creategame/maps.qc create mode 100644 scmenu/source/custom/creategame/mods.qc create mode 100644 scmenu/source/custom/custom.qh create mode 100644 scmenu/source/custom/globalkey.qm create mode 100644 scmenu/source/custom/joingame.qc create mode 100644 scmenu/source/custom/joingame.qh create mode 100644 scmenu/source/custom/joingame.qm create mode 100644 scmenu/source/custom/key.qc create mode 100644 scmenu/source/custom/key.qh create mode 100644 scmenu/source/custom/key.qm create mode 100644 scmenu/source/custom/option.qm create mode 100644 scmenu/source/custom/player.qm create mode 100644 scmenu/source/custom/player/avatar.qc create mode 100644 scmenu/source/custom/player/name.qc create mode 100644 scmenu/source/custom/player/player.qh create mode 100644 scmenu/source/custom/quit.qm create mode 100644 scmenu/source/custom/stresstest.qm create mode 100644 scmenu/source/custom/util.qm create mode 100644 scmenu/source/custom/video.qc create mode 100644 scmenu/source/custom/video.qh create mode 100644 scmenu/source/custom/video.qm create mode 100644 scmenu/source/custom/visible.qc create mode 100644 scmenu/source/custom/visible.qm create mode 100644 scmenu/source/mbuiltin.qc create mode 100644 scmenu/source/menu.qc create mode 100644 scmenu/source/menu.qh create mode 100644 scmenu/source/msys.qc create mode 100644 scmenu/source/progdefs.h create mode 100644 scmenu/source/progs.src create mode 100644 scmenu/source/system/debug.qc create mode 100644 scmenu/source/system/debug.qh create mode 100644 scmenu/source/system/event_helper.qc create mode 100644 scmenu/source/system/events.qc create mode 100644 scmenu/source/system/events.qh create mode 100644 scmenu/source/system/events_.qc create mode 100644 scmenu/source/system/gc.qc create mode 100644 scmenu/source/system/gc.qh create mode 100644 scmenu/source/system/history.qc create mode 100644 scmenu/source/system/history.qh create mode 100644 scmenu/source/system/isframe.qc create mode 100644 scmenu/source/system/isframe.qh create mode 100644 scmenu/source/system/item.qh create mode 100644 scmenu/source/system/mgfx.qc create mode 100644 scmenu/source/system/mgfx.qh create mode 100644 scmenu/source/system/parser.qc create mode 100644 scmenu/source/system/parser.qh create mode 100644 scmenu/source/system/structure.qc create mode 100644 scmenu/source/system/structure.qh create mode 100644 scmenu/source/todo create mode 100644 scmenu/source/util/altstring.qc create mode 100644 scmenu/source/util/altstring.qh create mode 100644 scmenu/source/util/nfunction.qc create mode 100644 scmenu/source/util/property.qc create mode 100644 scmenu/source/util/property.qh create mode 100644 scmenu/source/util/rect.qc create mode 100644 scmenu/source/util/rect.qh create mode 100644 scmenu/source/util/string.qc create mode 100644 scmenu/source/util/string.qh create mode 100644 scmenu/source/util/text.qc create mode 100644 scmenu/source/util/text.qh create mode 100644 scmenu/source/util/uid.qc create mode 100644 scmenu/source/util/uid.qh create mode 100644 scmenu/source/util/util.qh create mode 100644 scmenu/templates.menu create mode 100644 scmenu/test.menu diff --git a/scmenu/constants.menu b/scmenu/constants.menu new file mode 100644 index 000000000..dfae91b32 --- /dev/null +++ b/scmenu/constants.menu @@ -0,0 +1,99 @@ +// Property of Alientrap +// +// Constants + +// Item flags +// TODO: keep this always in sync with its control/items.qh counterpart +#define FlagTemplate "1" // this is a template do not touch, do not draw - actually dont do anything with it +#define FlagEmbedded "2" // the item cant be selected and all its children are embedded into its parent +#define FlagHidden "4" // events wont be called and it wont be drawn, etc. +#define FlagNoSelect "8" // cant be selected (but events will be called) +#define FlagConnected "16" // only if connected (i.e. playing) +#define FlagServer "32" // only displayed if server +#define FlagDeveloper "64" // only displayed if developer +#define FlagDraw "128" // only the draw event will be called +#define FlagChildDraw "256" // used to make the children only drawable +#define FlagDrawUpdate "512" // only the draw and update event get called +#define FlagChildDrawUpdate "1024" // only the draw and refresh events are called for children +#define FlagSealOffMouse "2048" // used to seal all items under the item with this flag off from mouse events + +#define InfiniteFloat "10000000.0" +#define InfiniteVector "10000000.0 10000000.0 10000000.0" + +// Alignment constants +#define AlignLeft "0" +#define AlignCenter "1" +#define AlignRight "2" +#define AlignFixLeft "4" // |text - actually this isnt necessary +#define AlignFixCenter "8" // te|xt +#define AlignFixRight "16" // text| +#define AlignFirst "32" // for layouts: item| ... | being the origin + +// DrawFlag constants +#define DrawFlagNormal "0" +#define DrawFlagAdditive "1" +#define DrawFlagModulate "2" +#define DrawFlag2xModulate "3" + +// Item constants +#define DefaultFontSize "12 12 0" + +// Text constants +#define DefaultTextColor "1 1 1" +#define DefaultTextAlpha "1" +#define DefaultTextDrawFlag [DrawFlagNormal] + +#define DefaultSelTextColor "0 0 1" +#define DefaultSelTextAlpha "1" +#define DefaultSelTextDrawFlag [DrawFlagNormal] + +#define DefaultPreTextColor "1 0 0" +#define DefaultPreTextAlpha "1" +#define DefaultPreTextDrawFlag [DrawFlagNormal] + +// Picture constants +#define DefaultPicColor "1 1 1" +#define DefaultPicAlpha "1" +#define DefaultPicDrawFlag [DrawFlagNormal] + +#define DefaultSelPicColor "1 1 1" +#define DefaultSelPicAlpha "1" +#define DefaultSelPicDrawFlag [DrawFlagNormal] + +#define DefaultPrePicColor "1 1 1" +#define DefaultPrePicAlpha "1" +#define DefaultPrePicDrawFlag [DrawFlagNormal] + +// Sound constants +#define DefaultSelectSound "misc/menu1.wav" +#define DefaultPressSound "misc/mouseclick.wav" + +#define DefaultIncreaseSound "misc/increasevalue.wav" +#define DefaultDecreaseSound "misc/decreasevalue.wav" + +#define DefaultStartSound "misc/startgame.wav" +#define DefaultEndSound "misc/endgame.wav" + +// Slider +#define DefaultSliderBar "gfx/m_sliderbar" +#define DefaultSlider "gfx/m_slider" +#define DefaultProportions "0.073107 0.853785 0.073107" +#define DefaultDirection "0.5 0.5" + +// EditBoxs +#define DefaultCursorSize "1.375 12 0" +#define DefaultCursorFlashSize "1.375 12 0" +#define DefaultCursorColor "1 1 1" +#define DefaultCursorFlashColor "1 1 1" + +// slist field constants +#define SListFieldCName 0 +#define SListFieldPing 1 +#define SListFieldGame 2 +#define SListFieldMod 3 +#define SListFieldMap 4 +#define SListFieldName 5 +#define SListFieldMaxPlayers 6 +#define SListFieldNumPlayers 7 +#define SListFieldProtocol 8 + diff --git a/scmenu/creategame.menu b/scmenu/creategame.menu new file mode 100644 index 000000000..b03bf3d55 --- /dev/null +++ b/scmenu/creategame.menu @@ -0,0 +1,146 @@ +// Property of Alientrap/AK +// +// creategame.menu +Item Window CreateGame +{ + size '800 650' + Item Window Map + { + size '350 650' + flag [FlagEmbedded] + + Derive Picture Picture + { + picture "gfx/m_white" + size '350 300' + pos '0 14' + } + Derive MultiLabel Description + { + pos '0 314' + size '350 336' + wrap 29 + } + Derive TextButton Prev + { + normal "<<" + + action Nex_Action_Map_Prev + } + Derive Label Name + { + alignment [AlignCenter] + size '302 14' + pos '24 0' + } + Derive TextButton Next + { + normal ">>" + pos '326 0' + + action Nex_Action_Map_Next + } + Item Task_Job Job + { + init Nex_Automation_UpdateMap + } + } + Item Layout Settings + { + pos '350 0' + size '450 650' + origin '175 0' + alignment [AlignFirst] + direction [Nex_DefaultVertDirection] + flag [FlagEmbedded] + + DeriveTemplate Nex_Composition Nex_Option_EditBox + { + DeriveTemplate Nex_Automation_Option_EditBox Automation + {} + DeriveTemplate TextButton Description + {} + DeriveTemplate EditBox EditBox + { + size '260 12' + action Nex_Action_TestOnChange + select Nex_Action_TestOnSelect + } + } + + Derive Nex_Option_EditBox Hostname + { + text "Server Name" + target "Data::CreateGame::Hostname::Text" + } + Derive Nex_Composition Gametype + { + Derive TextButton Description + { + normal "Game Mode" + link "##next" + } + Derive SwitchButton Switch + { + target "Data::CreateGame::ServerProgs::Switch" + action Nex_Action_TestOnChange + } + } + Derive Nex_Composition PublicServer + { + Derive TextButton Description + { + normal "Public Server" + link "##next" + } + Derive SwitchButton Switch + { + target "Data::CreateGame::PublicServer::Switch" + action Nex_Action_TestOnChange + } + } + Derive Nex_Option_EditBox FragLimit + { + text "Frag Limit" + target "Data::CreateGame::FragLimit::Text" + } + Derive Nex_Option_EditBox TimeLimit + { + text "Time Limit" + target "Data::CreateGame::TimeLimit::Text" + } + Derive Nex_Option_EditBox MaxPlayer + { + text "Max Players" + target "Data::CreateGame::MaxPlayers::Text" + } + Derive Nex_Line Seperator1 + {} + Derive Nex_Option_EditBox NumBots + { + text "Bot Count" + target "Data::CreateGame::NumBots::Text" + } + Derive Nex_Composition BotSkill + { + Derive TextButton Description + { + normal "Skill Level" + link "##next" + } + Derive SwitchButton Switch + { + target "Data::CreateGame::BotSkill::Switch" + action Nex_Action_TestOnChange + } + } + Derive Nex_Void Seperator2 + {} + Derive TextButton StartMap + { + normal "Start" + + action Nex_Action_Map_Start + } + } +} diff --git a/scmenu/data.menu b/scmenu/data.menu new file mode 100644 index 000000000..8dd1eee04 --- /dev/null +++ b/scmenu/data.menu @@ -0,0 +1,458 @@ +// Property of Alientrap +// +// Cvar Definitions +Item Container Data +{ +#define DataLink_ZeroOneValue Derive "::DataLink_ZeroOneValue" Value {} +#define DataLink_OnOffSwitch Derive "::DataLink_OnOffSwitch" Switch {} + // v_color prefix and other color controlling cvars + Item Container Color + { + // normal options + Item Data_Cvar Gamma + { + cvarName "v_gamma" + defValue 1.0 + Item DataLink_Value Value + { + minValue 0.0 + maxValue 4.0 + stepValue 0.05 + link "##up" + } + } + Item Data_Cvar Brightness + { + cvarName "v_brightness" + defValue 0.0 + Item DataLink_Value Value + { + minValue 0.0 + maxValue 3.0 + stepValue 0.05 + link "##up" + } + } + Item Data_Cvar Contrast + { + cvarName "v_contrast" + defValue 1.0 + Item DataLink_Value Value + { + minValue 0.0 + maxValue 3.0 + stepValue 0.05 + link "##up" + } + } + Item Data_Cvar HWGamma // read-only + { + cvarName "v_hwgamma" + defValue 1.0 + Derive DataLink_OnOffSwitch Switch + { + link "##up" + } + } + // extended options + Item Container Extended + { + Item Data_Cvar Active + { + cvarName "v_color_enable" + defValue 0.0 + Derive DataLink_OnOffSwitch Switch + { + link "##up" + } + } + Item Container Low + { + Item Data_Cvar Red + { + cvarName "v_color_black_r" + defValue 0.0 + [DataLink_ZeroOneValue] + } + Item Data_Cvar Green + { + cvarName "v_color_black_g" + defValue 0.0 + [DataLink_ZeroOneValue] + } + Item Data_Cvar Blue + { + cvarName "v_color_black_b" + defValue 0.0 + [DataLink_ZeroOneValue] + } + } + Item Container Mid + { + Item Data_Cvar Red + { + cvarName "v_color_grey_r" + defValue 0.5 + [DataLink_ZeroOneValue] + } + Item Data_Cvar Green + { + cvarName "v_color_grey_g" + defValue 0.5 + [DataLink_ZeroOneValue] + } + Item Data_Cvar Blue + { + cvarName "v_color_grey_b" + defValue 0.5 + [DataLink_ZeroOneValue] + } + } + Item Container High + { + Item Data_Cvar Red + { + cvarName "v_color_white_r" + defValue 1.0 + [DataLink_ZeroOneValue] + } + Item Data_Cvar Green + { + cvarName "v_color_white_g" + defValue 1.0 + [DataLink_ZeroOneValue] + } + Item Data_Cvar Blue + { + cvarName "v_color_white_b" + defValue 1.0 + [DataLink_ZeroOneValue] + } + } + } + } + Item Container Player + { + Item Data_Nex_Name Name + { + defValue "NexPlayer" + Item DataLink_Text Text + { + maxValue 32 + link "##up" + } + } + Item Data_Nex_Avatar Avatar + { + } + } + Item Container Key + { + Item Data_Nex_Key Forward + { + target "+forward" + } + Item Data_Nex_Key Backward + { + target "+back" + } + Item Data_Nex_Key StrafeLeft + { + target "+moveleft" + } + Item Data_Nex_Key StrafeRight + { + target "+moveright" + } + Item Data_Nex_Key Jump + { + target "+jump" + } + Item Data_Nex_Key Crouch + { + target "+shift" + } + + Item Data_Nex_Key FirePrimary + { + target "+attack" + } + Item Data_Nex_Key FireSecondary + { + target "+button3" + } + Item Data_Nex_Key PrevWeapon + { + target "impulse 10" + } + Item Data_Nex_Key NextWeapon + { + target "impulse 12" + } + Item Container Weapon + { + Item Data_Nex_Key Laser + { + target "impulse 1" + } + Item Data_Nex_Key Uzi + { + target "impulse 2" + } + Item Data_Nex_Key Shotgun + { + target "impulse 3" + } + Item Data_Nex_Key Grenade + { + target "impulse 4" + } + Item Data_Nex_Key Electro + { + target "impulse 5" + } + Item Data_Nex_Key CryLink + { + target "impulse 6" + } + Item Data_Nex_Key NexGun + { + target "impulse 7" + } + Item Data_Nex_Key Hagar + { + target "impulse 8" + } + Item Data_Nex_Key Rocket + { + target "impulse 9" + } + } + + Item Data_Nex_Key ShowScores + { + target "+showscores" + } + } + Item Container CreateGame + { + Item Data_Nex_Map Map + { + defValue 0 + } + Item Data_Cvar Hostname + { + cvarName "hostname" + defValue "Nexuiz Server" + + Item DataLink_Text Text + { + link "##up" + maxValue 64 + } + } + Item Data_CvarCreateSave MaxPlayers + { + cvarName "_nex_maxplayers" + defValue 8 + + Item DataLink_Value Value + { + link "##up" + minValue 1 + stepValue 1 + maxValue 32 + } + Item DataLink_Text Text + { + link "##down" + maxValue 5 + + Item DataLink_TextValue TextValue + { + link "##up prev" + } + } + } + Item Data_Cvar TimeLimit + { + cvarName "timelimit" + defValue 0 + + Item DataLink_Value Value + { + maxValue 86400 + link "##up" + } + Item DataLink_Text Text + { + maxValue 8 + link "##down" + + Item DataLink_TextTime TextTime + { + link "##up prev" + } + } + } + Item Data_Cvar FragLimit + { + cvarName "fraglimit" + defValue 20 + + Item DataLink_Value Value + { + maxValue 999 + link "##up" + } + Item DataLink_Text Text + { + maxValue 3 + link "##down" + + Item DataLink_TextValue TextValue + { + link "##up prev" + } + } + } + Item Data_Cvar ServerProgs + { + cvarName "sv_progs" + defValue "progs.dat" + + Item DataLink_Nex_ModSwitch Switch + { + link "##up" + } + } + Item Data_CvarCreateSave NumBots + { + // TODO: add support for this in FrikQcc + cvarName "nex_numbots" + defValue 8 + + Item DataLink_Value Value + { + maxValue 16 + link "##up" + } + Item DataLink_Text Text + { + maxValue 5 + link "##down" + + Item DataLink_TextValue TextValue + { + link "##up prev" + } + } + } + Item Data_CvarCreateSave BotSkill + { + // TODO: add support for this in FrikQcc + cvarName "nex_botskill" + // from 0 to 3 + defValue 0 + + Item DataLink_ValueSwitch Switch + { + minValue 0 + stepValue 1 + maxValue 3 + descList "'Beginner''Easy''Medium''Hard'" + + link "##up" + } + } + Item Data_Cvar PublicServer + { + cvarName "sv_public" + defValue 1 + + Item DataLink_ValueSwitch Switch + { + maxValue 1 + descList "'Disabled''Enabled'" + + link "##up" + } + } + } + Item Container JoinGame + { + Item Data_Container QueryString + { + Item DataLink_Text Text + { + maxValue 1024 + link "##up" + } + } + } + Item Container Video + { + Item Data_Nex_Resolution Resolution + { + defValue "800 600" + + Item DataLink_TextSwitch Switch + { + valueList "'320 240' '640 480' '800 600' '1024 768' '1280 970' '1600 1200'" + descList "'320x240' '640x480' '800x600' '1024x768' '1280x970' '1600x1200'" + link "##up" + } + } + Item Data_Cvar BPP + { + cvarName "vid_bitsperpixel" + + Item DataLink_TextSwitch Switch + { + valueList "'16' '32'" + descList "'16-bit' '32-bit'" + link "##up" + } + } + Item Data_Cvar Fullscreen + { + cvarName "vid_fullscreen" + + Derive DataLink_OnOffSwitch Switch + { + link "##up" + } + } + } + Item Container Sound + { + Item Data_Cvar CDVolume + { + cvarName "bgmvolume" + defValue 0.5 + + [DataLink_ZeroOneValue] + } + Item Data_Cvar GameVolume + { + cvarName "volume" + defValue 1 + + [DataLink_ZeroOneValue] + } + Item Data_Cvar AmbientVolume + { + cvarName "snd_staticvolume" + defValue 0.5 + + [DataLink_ZeroOneValue] + } + Item Data_Cvar SwapStereo + { + cvarName "snd_swapstereo" + defValue 0 + + [DataLink_OnOffSwitch] + } + } +} diff --git a/scmenu/ingame.menu b/scmenu/ingame.menu new file mode 100644 index 000000000..17ce741de --- /dev/null +++ b/scmenu/ingame.menu @@ -0,0 +1,4 @@ +// Property of Alientrap +// +// Ingame main menu + diff --git a/scmenu/joingame.menu b/scmenu/joingame.menu new file mode 100644 index 000000000..18f712fc3 --- /dev/null +++ b/scmenu/joingame.menu @@ -0,0 +1,178 @@ +// Property of Alientrap/AK +// +// joingame.menu +Item Layout JoinGame +{ + size '900 650' + direction '0 10' + alignment [AlignCenter] + origin '450 0' +#define SList_Ping '50 15' +#define SList_Name '492 15' +#define SList_Map '120 15' +#define SList_Players '60 15' +#define SList_Mod '120 15' +#define SList_Direction '2 0' + + Derive Nex_Composition Query + { + Derive TextButton Description + { + normal "Query String:" + + link "##next" + } + Derive EditBox EditBox + { + size '700 12' + target "::Data::JoinGame::QueryString::Text" + + action Nex_Action_ExecuteQuery + } + } + + Item Layout TableDesc + { + direction [SList_Direction] + flag [FlagEmbedded] + size '900 15' + + DeriveTemplate Rect Theme + { + color '0.5 0.5 0.5' + alpha 0.5 + flag [FlagEmbedded] + } + Derive Theme Ping + { + size [SList_Ping] + Derive TextButton Text + { + normal "Ping" + + action Nex_Action_JoinGame_SortBy + stepValue [SListFieldPing] + } + } + Derive Theme Name + { + size [SList_Name] + Derive TextButton Text + { + normal "Server Name" + + action Nex_Action_JoinGame_SortBy + stepValue [SListFieldName] + } + } + Derive Theme Map + { + size [SList_Map] + Derive TextButton Text + { + normal "Map Name" + + action Nex_Action_JoinGame_SortBy + stepValue [SListFieldMap] + } + } + Derive Theme Players + { + size [SList_Players] + Item Arrangement Glue + { + direction '0.001 0 0' + flag [FlagEmbedded] + + Derive TextButton NumPlayers + { + normal "NP" + + action Nex_Action_JoinGame_SortBy + stepValue [SListFieldNumPlayers] + } + Derive Label Slash + { + text "/" + } + Derive TextButton MaxPlayers + { + normal "MP" + + action Nex_Action_JoinGame_SortBy + stepValue [SListFieldMaxPlayers] + } + } + } + Derive Theme Mod + { + size [SList_Mod] + Derive TextButton Text + { + normal "Mod Name" + + action Nex_Action_JoinGame_SortBy + stepValue [SListFieldMod] + } + } + } + Item ScrollWindow Scroll + { + flag [FlagEmbedded] + size '900 500' + + Item Arrangement Slist + { + direction '0 1 0' + flag [FlagEmbedded] + + DeriveTemplate Nex_HostCache_Entry Entry + { + size '852 15' + action Nex_Action_EntryConnect + + DeriveTemplate Nex_HostCache_ValueField Ping + { + pos '0 0' + size [SList_Ping] + stepValue [SListFieldPing] + alignment [AlignRight] + } + DeriveTemplate Nex_HostCache_StringField Name + { + pos '52 0' + size [SList_Name] + stepValue [SListFieldName] + } + DeriveTemplate Nex_HostCache_StringField Map + { + pos '546 0' + size [SList_Map] + stepValue [SListFieldMap] + } + DeriveTemplate Nex_HostCache_Players Players + { + pos '668 0' + size [SList_Players] + alignment [AlignRight] + } + DeriveTemplate Nex_HostCache_StringField Mod + { + pos '730 0' + size [SList_Mod] + stepValue [SListFieldMod] + } + } + Item Automation_Job Generator + { + action Nex_Automation_CreateEntries + } + } + } + Derive TextButton Refresh + { + normal "Refresh List" + + action Nex_Action_RefreshSlist + } +} diff --git a/scmenu/main.menu b/scmenu/main.menu new file mode 100644 index 000000000..250a3eae8 --- /dev/null +++ b/scmenu/main.menu @@ -0,0 +1,43 @@ +// Property of Alientrap +// +// Main menu +Item Arrangement Main +{ + pos '252 30' + direction '10 0' + + Derive TextButton Resume + { + normal "Resume" + flag [FlagConnected] + + } + Derive TextButton Create + { + normal "Create Game" + + target "CreateGame" + init Nex_Action_SetNormalPanelLink + } + Derive TextButton Join + { + normal "Join Game" + + target "JoinGame" + action Nex_Action_JumpToJoinGame + } + Derive TextButton Options + { + normal "Options" + + target "Options" + init Nex_Action_SetNormalPanelLink + } + Derive TextButton Quit + { + normal "Quit" + action Nex_Quit_Action + } +} + + diff --git a/scmenu/menu b/scmenu/menu new file mode 100644 index 000000000..0489b2f42 --- /dev/null +++ b/scmenu/menu @@ -0,0 +1,16 @@ +// Property of Alientrap +// +// Menu +#include "menu/constants.menu" +#include "menu/templates.menu" +//#include "menu/test.menu" +//Ignore { +#include "menu/data.menu" + +#include "menu/creategame.menu" +#include "menu/options.menu" +#include "menu/joingame.menu" +#include "menu/normal.menu" + +#include "menu/ingame.menu" +//} diff --git a/scmenu/normal.menu b/scmenu/normal.menu new file mode 100644 index 000000000..931462fb8 --- /dev/null +++ b/scmenu/normal.menu @@ -0,0 +1,61 @@ +// Property of Alientrap +// +// Normal main menu +Item Window Normal +{ + key Nex_Global_Key + size '1024 768' + Derive Rect BackgroundMod + { + pos '0 0' + color "0 0 0" + alpha 0.5 +Ignore +{ + Item Effect_Float AlphaPulse + { + targetFloat alpha + startFloat 0.8 + endFloat 0.4 + time '2 2 -1' + interpolForward FX_SquareInterpolation + interpolBackward FX_SquareInterpolation + } + Item Effect_Vector ColorPulse + { + targetVector color + startVector "0 0 0" + endVector "0.1 0 0.05" + time '2 2 -1' + interpolForward FX_SquareInterpolation + interpolBackward FX_SquareInterpolation + } +} + } + + // Include the main menu as first sub window + #include "menu/main.menu" + + Item Task_Job PanelReinit + { + init Nex_Action_SetLinkOnReinit + target "Panel::NexuizLogo" + } + Item Reference Panel + { + pos '62 80' + size '900 650' + + // The first thing you should see is our cool logo! + Derive Picture NexuizLogo + { + picture "gfx/m_strength" + pos '100 0' + size '600 600' + } + } + + #include "menu/quit.menu" +} + + diff --git a/scmenu/options.menu b/scmenu/options.menu new file mode 100644 index 000000000..90a85d604 --- /dev/null +++ b/scmenu/options.menu @@ -0,0 +1,68 @@ +// Property of Alientrap/AK +// Options menu + +Item Layout Options +{ + direction '20 0' + + Item Arrangement Menu + { + direction '0 10' + + Derive TextButton Game + { + normal "Game" + } + Derive TextButton Player + { + normal "Player" + + init Nex_Action_JumpToPage + target "Panel::Player" + } + Derive TextButton Input + { + normal "Input" + } + Derive TextButton Controls + { + normal "Controls" + + init Nex_Action_JumpToPage + target "Panel::KeyControl" + } + Derive TextButton Audio + { + normal "Audio" + } + Derive TextButton Video + { + normal "Video" + + init Nex_Action_JumpToPage + target "Panel::Video" + } + Derive TextButton ColorControl + { + normal "Color Control" + + init Nex_Action_JumpToPage + target "Panel::ColorControl" + } + Derive TextButton Effects + { + normal "Effects" + } + } + Item EventWindow Panel + { + size '600 600' + reinit Nex_Action_MakeFirstVisible + + #include "menu/options/sound.menu" + #include "menu/options/video.menu" + #include "menu/options/key.menu" + #include "menu/options/player.menu" + #include "menu/options/color.menu" + } +} diff --git a/scmenu/options/color.menu b/scmenu/options/color.menu new file mode 100644 index 000000000..8305fd849 --- /dev/null +++ b/scmenu/options/color.menu @@ -0,0 +1,123 @@ +// Property of Alientrap/AK +// options/color.menu +Item Window ColorControl +{ + size '600 600' + Derive Rect ClearWindow + { + pos '000 0' + size '600 600' + color '1 1 1' + drawFlag [DrawFlag2xModulate] + } + Item Layout Layout + { + direction [Nex_DefaultVertDirection] + size '600 600' + origin '300 50' + alignment [AlignFirst] + + // We want to see the changes immediatelly + DeriveTemplate Nex_Composition Nex_Color_Option_Slider + { + DeriveTemplate Nex_Automation_Option_Slider Automation + {} + DeriveTemplate TextButton Description + {} + DeriveTemplate Slider Slider + { + action Nex_Action_TestOnChange + } + DeriveTemplate ValueButton Value + {} + } + + Derive Nex_Option_Slider Brightness + { + text "Brightness" + target "::Data::Color::Brightness::Value" + } + Derive Nex_Option_Slider Contrast + { + text "Contrast" + target "::Data::Color::Contrast::Value" + } + Derive Nex_Option_Slider HWGamma + { + text "HW Gamma Support" + target "::Data::Color::HWGamma::Switch" + } + Derive Nex_Option_Slider Gamma + { + text "Gamma" + target "::Data::Color::Gamma::Value" + } + Derive Nex_Line Seperator1 + {} + Derive Nex_Option_Slider ExtendedControl + { + text "Color Control" + target "::Data::Color::Extended::Active::Switch" + } + // Low part + Derive Nex_Option_Slider DarkRed + { + text "Dark Red" + target "::Data::Color::Extended::Low::Red::Value" + } + Derive Nex_Option_Slider DarkGreen + { + text "Dark Green" + target "::Data::Color::Extended::Low::Green::Value" + } + Derive Nex_Option_Slider DarkBlue + { + text "Dark Blue" + target "::Data::Color::Extended::Low::Blue::Value" + } + // Mid part + Derive Nex_Option_Slider MidRed + { + text "Grey Red" + target "::Data::Color::Extended::Mid::Red::Value" + } + Derive Nex_Option_Slider MidGreen + { + text "Grey Green" + target "::Data::Color::Extended::Mid::Green::Value" + } + Derive Nex_Option_Slider MidBlue + { + text "Grey Blue" + target "::Data::Color::Extended::Mid::Blue::Value" + } + // High part + Derive Nex_Option_Slider HighRed + { + text "White Red" + target "::Data::Color::Extended::High::Red::Value" + } + Derive Nex_Option_Slider HighGreen + { + text "White Green" + target "::Data::Color::Extended::High::Green::Value" + } + Derive Nex_Option_Slider HighBlue + { + text "White Blue" + target "::Data::Color::Extended::High::Blue::Value" + } + Derive Nex_Line Seperator2 + {} + Derive TextButton Cancel + { + normal "Cancel changes" + action Nex_Action_Color_Cancel + } + Derive TextButton Reset + { + normal "Reset to default" + action Nex_Action_Color_Reset + } + } +} diff --git a/scmenu/options/key.menu b/scmenu/options/key.menu new file mode 100644 index 000000000..ba10bd227 --- /dev/null +++ b/scmenu/options/key.menu @@ -0,0 +1,282 @@ +// Property of Alientrap/AK +// options/key.menu +Item Window KeyControl +{ + Item Layout Layout + { + size '600 600' + origin '300 0' + alignment [AlignCenter] + direction [Nex_DefaultVertDirection] + flag [FlagEmbedded] + + Derive MultiLabel Description + { + size '500 24' + text + "Press [Enter] or [Mouse1] to change a key binding.\nPress [Delete] to remove the binding." + } + + // table: name key1 key2 + Item Layout TableDesc + { + size '600 15' + direction '10 0' + + Derive Rect Action + { + size '200 15' + color '0.5 0.5 0.5' + alpha 0.5 + + Derive Label Label + { + text "Action" + } + } + Derive Rect Key1 + { + pos '210 0' + size '190 15' + color '0.5 0.5 0.5' + alpha 0.5 + + Derive Label Label + { + text "Key/Button 1" + } + } + Derive Rect Key2 + { + pos '410 0' + size '190 15' + color '0.5 0.5 0.5' + alpha 0.5 + + Derive Label Label + { + text "Key/Button 2" + } + } + } + Item ScrollWindow Scroll + { + size '600 400' + flag [FlagEmbedded] + Item Arrangement Keys + { + direction [Nex_DefaultVertDirection] + flag [FlagEmbedded] + + Template Layout Nex_Key_Template + { + size '600 12' + flag [FlagEmbedded] + direction '10 0' + + Template Automation_Job Job + { + action Nex_Automation_Key + } + Derive Label Action + { + size '200 12' + } + Template DataLink_AltString Link1 + { + flag [FlagHidden] + stepValue 0 + } + DeriveTemplate Nex_KeyButton Key1 + { + pos '210 0' + size '190 12' + target "##down" + action Nex_Action_KeyButton + + Item DataLink_FastResync Resync + { + link "Link1" + } + } + Template DataLink_AltString Link2 + { + flag [FlagHidden] + stepValue 1 + } + DeriveTemplate Nex_KeyButton Key2 + { + pos '410 0' + size '190 12' + target "##down" + action Nex_Action_KeyButton + + Item DataLink_FastResync Resync + { + link "Link2" + } + } + } + DeriveTemplate Label Title + { + fontSize '13 13' + color '1.0 0.6 0.6' + } + Derive Title GroupMovement + { + text "[Movement]" + } + Derive Nex_Key_Template Forward + { + text "Move Forward" + target "Data::Key::Forward" + } + Derive Nex_Key_Template Backward + { + text "Move Backward" + target "Data::Key::Backward" + } + Derive Nex_Key_Template Left + { + text "Strafe Left" + target "Data::Key::StrafeLeft" + } + Derive Nex_Key_Template Right + { + text "Strafe Right" + target "Data::Key::StrafeRight" + } + Derive Nex_Key_Template Jump + { + text "Jump" + target "Data::Key::Jump" + } + Derive Nex_Key_Template Crouch + { + text "Crouch" + target "Data::Key::Crouch" + } + Derive Nex_Void Seperator1 + {} + Derive Title GroupFight + { + text "[Fight]" + } + Derive Nex_Key_Template Primary + { + text "Primary Attack" + target "Data::Key::FirePrimary" + } + Derive Nex_Key_Template Secondary + { + text "Secondary Attack" + target "Data::Key::FireSecondary" + } + Derive Nex_Key_Template PrevWeapon + { + text "Previous Weapon" + target "Data::Key::PrevWeapon" + } + Derive Nex_Key_Template NextWeapon + { + text "Next Weapon" + target "Data::Key::NextWeapon" + } + Derive Nex_Void Seperator2 + {} + Derive Title Weapons + { + text "[Weapon]" + } + Derive Nex_Key_Template Laser + { + text "Laser" + target "Data::Key::Weapon::Laser" + } + Derive Nex_Key_Template Uzi + { + text "Uzi" + target "Data::Key::Weapon::Uzi" + } + Derive Nex_Key_Template Shotgun + { + text "Shotgun" + target "Data::Key::Weapon::Shotgun" + } + Derive Nex_Key_Template Grenade + { + text "Uzi" + target "Data::Key::Weapon::Grenade" + } + Derive Nex_Key_Template Electro + { + text "Electro" + target "Data::Key::Weapon::Electro" + } + Derive Nex_Key_Template CryLink + { + text "CryLink" + target "Data::Key::Weapon::CryLink" + } + Derive Nex_Key_Template NexGun + { + text "NexGun" + target "Data::Key::Weapon::NexGun" + } + Derive Nex_Key_Template Hagar + { + text "Hagar" + target "Data::Key::Weapon::Hagar" + } + Derive Nex_Key_Template Rocket + { + text "Rocket" + target "Data::Key::Weapon::Rocket" + } + } + } + Item Layout Buttons + { + flag [FlagEmbedded] + } + } + + // info window + Item Window InfoWindow + { + size '300 50' + pos '150 200' + flag [FlagHidden] + + Derive Rect Background + { + color '0.1 0.1 0.1' + drawFlag [DrawFlagModulate] + flag [FlagSealOffMouse] + + Derive Rect Layer + { + color '0.2 0.2 0.2' + drawFlag [DrawFlagAdditive] + } + } + Item Window TextContainer + { + pos '2 2' + size '296 46' + Derive Rect Background + { + color '0.1 0.1 0.1' + drawFlag [DrawFlagAdditive] + } + Derive MultiLabel Info + { + pos '3 3' + wrap 24 + text "Now press the key you want to bind or press [Escape] to abort." + } + } + } +} + + diff --git a/scmenu/options/player.menu b/scmenu/options/player.menu new file mode 100644 index 000000000..7342aa769 --- /dev/null +++ b/scmenu/options/player.menu @@ -0,0 +1,72 @@ +// Property of Alientrap/AK +// options/player.menu +Item Window Player +{ + size '600 600' + + Item Window Avatar + { + size '250 600' + flag [FlagEmbedded] + + Derive Picture Picture + { + size '250 400' + picture "gfx/m_white" + } + Derive MultiLabel Description + { + size '250 200' + pos '0 400' + wrap 20 + } + Derive TextButton Prev + { + pos '0 0' + normal "<<" + + action Nex_Action_Avatar_Prev + } + Derive Label Name + { + pos '24 0' + size '202 12' + alignment [AlignCenter] + } + Derive TextButton Next + { + pos '226 0' + normal ">>" + + action Nex_Action_Avatar_Next + } + Item Task_Job Job + { + init Nex_Automation_UpdateAvatar + } + } + Item Layout Settings + { + pos '250 0' + origin '175 0' + size '350 600' + flag [FlagEmbedded] + alignment [AlignFirst] + direction [Nex_DefaultVertDirection] + + Derive Nex_Composition Name + { + Derive TextButton Description + { + normal "Player name" + link "EditBox" + } + Derive EditBox EditBox + { + size '156 20' + target "Data::Player::Name::Text" + action Nex_Action_TestOnChange + } + } + } +} diff --git a/scmenu/options/sound.menu b/scmenu/options/sound.menu new file mode 100644 index 000000000..5046a860b --- /dev/null +++ b/scmenu/options/sound.menu @@ -0,0 +1,31 @@ +// Property of Alientrap/AK +// options/sound.menu +Item Layout Sound +{ + direction [Nex_DefaultVertDirection] + size '600 600' + origin '300 0' + alignment [AlignFirst] + + + Derive Nex_Option_Slider MusicVolume + { + text "CD Volume" + target "::Data::Sound::CDVolume::Value" + } + Derive Nex_Option_Slider GameVolume + { + text "Game Volume" + target "::Data::Sound::GameVolume::Value" + } + Derive Nex_Option_Slider AmbientVolume + { + text "Ambient Volume" + target "::Data::Sound::AmbientVolume::Value" + } + Derive Nex_Option_Switch SwapStereo + { + text "Swap Stereo" + target "::Data::Sound::SwapStereo::Switch" + } +} diff --git a/scmenu/options/video.menu b/scmenu/options/video.menu new file mode 100644 index 000000000..275fc6fda --- /dev/null +++ b/scmenu/options/video.menu @@ -0,0 +1,44 @@ +// Property of Alientrap/AK +// options/key.menu +Item Layout Video +{ + direction [Nex_DefaultVertDirection] + size '600 600' + origin '300 0' + alignment [AlignFirst] + + DeriveTemplate Composition Nex_Video_Option_Switch + { + direction [Nex_DefaultHorzDirection] + + DeriveTemplate Nex_Automation_Option_Switch Automation + {} + DeriveTemplate TextButton Description + {} + DeriveTemplate SwitchButton Switch + {} + } + Derive Nex_Video_Option_Switch Resolution + { + text "Resolution" + target "::Data::Video::Resolution::Switch" + } + Derive Nex_Video_Option_Switch Bpp + { + text "Bits Per Pixel" + target "::Data::Video::BPP::Switch" + } + Derive Nex_Video_Option_Switch Fullscreen + { + text "Fullscreen" + target "::Data::Video::Fullscreen::Switch" + } + Derive Nex_Void Seperator1 + {} + Derive TextButton Apply + { + normal "Apply Changes" + + action Nex_Action_Video_Apply + } +} diff --git a/scmenu/quit.menu b/scmenu/quit.menu new file mode 100644 index 000000000..549c2e59a --- /dev/null +++ b/scmenu/quit.menu @@ -0,0 +1,66 @@ +// Property of Alientrap +// +// Quit window +Item Window QuitWnd +{ + pos '300 300' + size '400 80' + flag [FlagHidden] + + Derive Rect Background + { + color '0.1 0.1 0.1' + drawFlag [DrawFlagModulate] + flag [FlagSealOffMouse] + + Derive Rect Layer + { + color '0.3 0.3 0.3' + drawFlag [DrawFlagAdditive] + } + } + Item Layout Layout + { + origin '200 0' + direction '0.0 10' + flag [FlagEmbedded] + alignment [AlignCenter] + + Item FloatingArea Title + { + size '400 13' + target "##up up" + Derive Rect Background + { + color '0.5 0.5 0.5' + } + Derive TextButton Caption + { + size '400 11' + alignment [AlignCenter] + normal "Quit Window" + link "##up" + } + } + Derive Label Text + { + text "Do you really want to quit?" + } + Item Arrangement Buttons + { + direction '40 0' + key Nex_Quit_Key + + Derive TextButton Yes + { + normal "Yes" + action Nex_Quit_Yes + } + Derive TextButton No + { + normal "No" + action Nex_Quit_No + } + } + } +} diff --git a/scmenu/source/base/cursor.qc b/scmenu/source/base/cursor.qc new file mode 100644 index 000000000..221f561af --- /dev/null +++ b/scmenu/source/base/cursor.qc @@ -0,0 +1,96 @@ +// NG-Menu +// base/cursor.qc + +void() Cursor_Init = +{ + // default cursor (embedded into DP): ui/mousepointer.tga + if( Gfx_Precache( CURSOR_PATH ) ) + Cursor_Current = CURSOR_PATH; + else { + Cursor_Current = "ui/mousepointer.tga"; + Gfx_Precache( Cursor_Current ); + } + + Cursor_Position = Cursor_Relative = '0 0 0'; + + Cursor_Animation = Cursor_DefaultAnimation; +}; + +void() Cursor_Quit = +{ +}; + +void() Cursor_Display = +{ + setmousetarget( MT_MENU ); +}; + +void() Cursor_Hide = +{ + setmousetarget( MT_CLIENT ); +}; + +void() Cursor_Draw = +{ + local vector lPos; + local vector lSize; + + lSize = Gfx_GetImageSize( Cursor_Current ) * Cursor_Scale; + lPos_x = Cursor_Position_x + lSize_x * Cursor_Offset_x; + lPos_y = Cursor_Position_y + lSize_y * Cursor_Offset_y; + lPos_z = 0.0; + + Gfx_DrawPic( lPos, Cursor_Current, lSize, Cursor_Color, Cursor_Transparency, Cursor_Flag ); +}; + +void() Cursor_Update = +{ + local vector lRelPos; + + lRelPos = getmousepos(); + lRelPos = Gfx_ConToMen( lRelPos ); + + Cursor_Relative_x = lRelPos_x * Cursor_Speed_x; + Cursor_Relative_y = lRelPos_y * Cursor_Speed_y; + + Cursor_Relative_x = bound( 0.0, Cursor_Position_x + Cursor_Relative_x, Gfx_Menu_Width ) - Cursor_Position_x; + Cursor_Relative_y = bound( 0.0, Cursor_Position_y + Cursor_Relative_y, Gfx_Menu_Height ) - Cursor_Position_y; + + Cursor_Position_x = Cursor_Position_x + Cursor_Relative_x; + Cursor_Position_y = Cursor_Position_y + Cursor_Relative_y; + Cursor_Position_z = 0.0; + + Cursor_Animation(); +}; + +void() Cursor_DefaultAnimation = +{ +}; + +void( vector pRelPos, string pText, vector pScale, vector pColor, float pAlpha, float pDrawFlag ) Cursor_PrintInfo = +{ + local vector lPosition; + local vector lSize; + + lSize = Gfx_GetImageSize( Cursor_Current ) * Cursor_Scale; + + if( pRelPos_x != 0 ) { + if( pRelPos_x > 0 ) // align it on the left + lPosition_x = Cursor_Position_x + lSize_x * (Cursor_Offset_x + 0.5 + pRelPos_x / 2) ; + else if( pRelPos_x < 0 ) // align it on the right + lPosition_x = Cursor_Position_x + lSize_x * (Cursor_Offset_x + 0.5 + pRelPos_x / 2) - + pScale_x * strlen( pText ); + lPosition_y = Cursor_Position_y + lSize_y * (Cursor_Offset_y + 0.5 + pRelPos_y / 2 ) - pScale_y / 2; + } else + lPosition_x = Cursor_Position_x + lSize_x * (Cursor_Offset_x + 0.5) - + pScale_x * strlen( pText ) / 2; + + if( pRelPos_y != 0 ) { + if( pRelPos_y > 0 ) + lPosition_y = Cursor_Position_y + lSize_y * (Cursor_Offset_y + 0.5 - pRelPos_y / 2) - pScale_y; + else if( pRelPos_y < 0 ) + lPosition_y = Cursor_Position_y + lSize_y * (Cursor_Offset_y + 0.5 - pRelPos_y / 2); + } + + Gfx_DrawString( lPosition, pText, pScale, pColor, pAlpha, pDrawFlag ); +}; diff --git a/scmenu/source/base/cursor.qh b/scmenu/source/base/cursor.qh new file mode 100644 index 000000000..11f95abf2 --- /dev/null +++ b/scmenu/source/base/cursor.qh @@ -0,0 +1,32 @@ +// NG Menu +// cursor qh + +const string CURSOR_PATH = "gfx/m_cursor"; //"ui/mousepointer.tga"; + +string Cursor_Current; +var void() Cursor_Animation; + +vector Cursor_Relative; +vector Cursor_Position; +vector Cursor_Speed = '1 1 0'; + +vector Cursor_Position; // will be adjusted to be in the current origin + +float Cursor_Transparency = 1.0; +vector Cursor_Color = '1.0 1.0 1.0'; +float Cursor_Scale = 1.0; +float Cursor_Flag = 0; +vector Cursor_Offset = '-0.5 -0.5 0'; + +void() Cursor_Init; +void() Cursor_Quit; + +void() Cursor_Display; +void() Cursor_Hide; + +void() Cursor_Draw; +void() Cursor_Update; + +void() Cursor_DefaultAnimation; + +void( vector pRelPos, string pText, vector pScale, vector pColor, float pAlpha, float pDrawFlag ) Cursor_PrintInfo; diff --git a/scmenu/source/base/gfx.qc b/scmenu/source/base/gfx.qc new file mode 100644 index 000000000..1338eae4f --- /dev/null +++ b/scmenu/source/base/gfx.qc @@ -0,0 +1,159 @@ +// NG-Menu +// base/gfx.qc + +// cvar ngmenu_menu_height +void() gfx_updateres = +{ + Gfx_Real_Width = cvar( "vid_conwidth" ); + Gfx_Real_Height = cvar( "vid_conheight" ); + Gfx_Menu_Width = cvar( CVAR_SCMENU_MENU_WIDTH ); + Gfx_Menu_Height = cvar( CVAR_SCMENU_MENU_HEIGHT ); + + if( Gfx_Menu_Width == 0.0 ) + Gfx_Menu_Width = GFX_MENU_DEFAULT_WIDTH; + if( Gfx_Menu_Height == 0.0 ) + Gfx_Menu_Height = GFX_MENU_DEFAULT_HEIGHT; +}; + +void() Gfx_Init = +{ + local string lWidth, lHeight; + + lWidth = ftos( GFX_MENU_DEFAULT_WIDTH ); + lHeight = ftos( GFX_MENU_DEFAULT_HEIGHT ); + + registercvar( CVAR_SCMENU_MENU_WIDTH, lWidth, CVAR_SAVE ); + registercvar( CVAR_SCMENU_MENU_HEIGHT, lHeight, CVAR_SAVE ); + + gfx_updateres(); +}; + +void() Gfx_Quit = +{ +}; + +void() Gfx_Display = +{ + Gfx_ResetClipArea(); +}; + +void() Gfx_Hide = +{ +}; + +void() Gfx_Update = +{ + gfx_updateres(); +}; + +void() Gfx_Draw = +{ +}; + +bool( string pPic ) Gfx_IsCached = +{ + return iscachedpic( pPic ); +}; + +bool( string pPic ) Gfx_Precache = +{ + if( pPic == "" ) + return false; + + if( iscachedpic( pPic ) ) + return true; + if( precache_pic( pPic ) == pPic ) + return true; + return false; +}; + +void( string pPic ) Gfx_Free +{ + // DO NOTHING UNTIL A REF COUNTER IS IMPLEMENTED +}; + +vector( string pPic ) Gfx_GetImageSize +{ + return drawgetimagesize( pPic ); +}; + +vector( vector pPos ) Gfx_ConToMen = +{ + pPos_x = pPos_x * Gfx_Menu_Width / Gfx_Real_Width; + pPos_y = pPos_y * Gfx_Menu_Height / Gfx_Real_Height; + pPos_z = 0.0; + + return pPos; +}; + +vector( vector pPos ) Gfx_MenToCon = +{ + pPos_x = pPos_x * Gfx_Real_Width / Gfx_Menu_Width; + pPos_y = pPos_y * Gfx_Real_Height / Gfx_Menu_Height; + pPos_z = 0.0; + + return pPos; +}; + +void() Gfx_ResetClipArea = +{ + drawresetcliparea(); +}; + +vector( vector pPosition ) _Gfx_FitCenter = +{ + return (pPosition + '0.375 0.375 0'); +}; + +float( vector pPosition, float pCharacter, vector pScale, vector pRGB, float pAlpha, float pFlag ) +Gfx_DrawCharacter = +{ + pPosition = _Gfx_FitCenter( Gfx_MenToCon( pPosition ) ); + pScale = Gfx_MenToCon( pScale ); + + return drawcharacter( pPosition, pCharacter, pScale, pRGB, pAlpha, pFlag ); +}; + +float( vector pPosition, string pText, vector pScale, vector pRGB, float pAlpha, float pFlag ) +Gfx_DrawString = +{ + pPosition = _Gfx_FitCenter( Gfx_MenToCon( pPosition ) ); + pScale = Gfx_MenToCon( pScale ); + + return drawstring( pPosition, pText, pScale, pRGB, pAlpha, pFlag ); +}; + +float( vector pPosition, string pPicture, vector pSize, vector pRGB, float pAlpha, float pFlag ) +Gfx_DrawPic = +{ + pPosition = _Gfx_FitCenter( Gfx_MenToCon( pPosition ) ); + pSize = Gfx_MenToCon( pSize ); + + return drawpic( pPosition, pPicture, pSize, pRGB, pAlpha, pFlag ); +}; + +float( vector pPosition, vector pSize, vector pRGB, float pAlpha, float pFlag ) +Gfx_Fill = +{ + pPosition = _Gfx_FitCenter( Gfx_MenToCon( pPosition ) ); + pSize = Gfx_MenToCon( pSize ); + + return drawfill( pPosition, pSize, pRGB, pAlpha, pFlag ); +}; + +void( float pX, float pY, float pWidth, float pHeight ) +Gfx_SetClipArea = +{ + local vector lPosition, lSize; + + lPosition_x = pX; + lPosition_y = pY; + + lSize_x = pWidth; + lSize_y = pHeight; + + lPosition = _Gfx_FitCenter( Gfx_MenToCon( lPosition ) ); + lSize = Gfx_MenToCon( lSize ) + '1 1 0'; + + drawsetcliparea( lPosition_x, lPosition_y, lSize_x, lSize_y ); +}; diff --git a/scmenu/source/base/gfx.qh b/scmenu/source/base/gfx.qh new file mode 100644 index 000000000..6a2da86b8 --- /dev/null +++ b/scmenu/source/base/gfx.qh @@ -0,0 +1,45 @@ +// NG-Menu +// base/gfx.h + +const float GFX_MENU_DEFAULT_WIDTH = 1024; +const float GFX_MENU_DEFAULT_HEIGHT = 768; + +const string CVAR_SCMENU_MENU_WIDTH = "scmenu_menu_width"; +const string CVAR_SCMENU_MENU_HEIGHT = "scmenu_menu_height"; + +float Gfx_Menu_Width; +float Gfx_Menu_Height; +float Gfx_Real_Width; +float Gfx_Real_Height; + +void() Gfx_Init; +void() Gfx_Quit; +void() Gfx_Display; +void() Gfx_Hide; +void() Gfx_Update; +void() Gfx_Draw; + +bool( string pPic ) Gfx_IsCached; +bool( string pPic ) Gfx_Precache; +void( string pPic ) Gfx_Free; +vector( string pPic ) Gfx_GetImageSize; + +vector( vector pPos ) Gfx_ConToMen; +vector( vector pPos ) Gfx_MenToCon; + +void() Gfx_ResetClipArea; + +float( vector pPosition, float pCharacter, vector pScale, vector pRGB, float pAlpha, float pFlag ) +Gfx_DrawCharacter; + +float( vector pPosition, string pText, vector pScale, vector pRGB, float pAlpha, float pFlag ) +Gfx_DrawString; + +float( vector pPosition, string pPicture, vector pSize, vector pRGB, float pAlpha, float pFlag ) +Gfx_DrawPic; + +float( vector pPosition, vector pSize, vector pRGB, float pAlpha, float pFlag ) +Gfx_Fill; + +void( float pX, float pY, float pWidth, float pHeight ) +Gfx_SetClipArea; diff --git a/scmenu/source/base/hostcache.qc b/scmenu/source/base/hostcache.qc new file mode 100644 index 000000000..7c03c461e --- /dev/null +++ b/scmenu/source/base/hostcache.qc @@ -0,0 +1,35 @@ +// DP/Nex Menu +// base/hostcache.qc + +float HostCache_ViewCount; +float HostCache_TotalCount; +float HostCache_MasterQueryCount; +float HostCache_MasterReplyCount; +float HostCache_ServerQueryCount; +float HostCache_ServerReplyCount; +float HostCache_SortField; +float HostCache_SortDescending; + +void() HostCache_Update = +{ + HostCache_ViewCount = gethostcachevalue( SLIST_HOSTCACHEVIEWCOUNT ); + HostCache_TotalCount = gethostcachevalue( SLIST_HOSTCACHETOTALCOUNT ); + HostCache_MasterQueryCount = gethostcachevalue( SLIST_MASTERQUERYCOUNT ); + HostCache_MasterReplyCount = gethostcachevalue( SLIST_MASTERREPLYCOUNT ); + HostCache_ServerQueryCount = gethostcachevalue( SLIST_SERVERQUERYCOUNT ); + HostCache_ServerReplyCount = gethostcachevalue( SLIST_SERVERREPLYCOUNT ); + HostCache_SortField = gethostcachevalue( SLIST_SORTFIELD ); + HostCache_SortDescending = gethostcachevalue( SLIST_SORTDESCENDING ); +}; + +void() HostCache_ResortViewSet = +{ + resorthostcache(); + HostCache_Update(); +}; + +void() HostCache_RefreshHostCache = +{ + refreshhostcache(); + HostCache_Update(); +}; diff --git a/scmenu/source/base/hostcache.qh b/scmenu/source/base/hostcache.qh new file mode 100644 index 000000000..da86c4426 --- /dev/null +++ b/scmenu/source/base/hostcache.qh @@ -0,0 +1,15 @@ +// DP/Nex Menu +// base/hostcache.qh + +float HostCache_ViewCount; +float HostCache_TotalCount; +float HostCache_MasterQueryCount; +float HostCache_MasterReplyCount; +float HostCache_ServerQueryCount; +float HostCache_ServerReplyCount; +float HostCache_SortField; +float HostCache_SortDescending; + +void() HostCache_Update; +void() HostCache_ResortViewSet; +void() HostCache_RefreshHostCache; diff --git a/scmenu/source/base/key.qc b/scmenu/source/base/key.qc new file mode 100644 index 000000000..0106b53f0 --- /dev/null +++ b/scmenu/source/base/key.qc @@ -0,0 +1,68 @@ +// NG-Menu +// base/key.qc + +void() Key_Init = +{ +}; + +void() Key_Quit = +{ +}; + +void() Key_Display = +{ + setkeydest( KEY_MENU ); +}; + +void() Key_Hide = +{ + setkeydest( KEY_GAME ); +}; + +void( string pKey ) Key_Unbind = +{ + cmd( strcat( "unbind ", pKey, "\n" ) ); +}; + +string( float pKey ) Key_GetName = +{ + return keynumtostring( pKey ); +}; + +float( string pKey ) Key_GetNum = +{ + return stringtokeynum( pKey ); +}; + +string( string pCommand ) Key_GetBindList = +{ + return String_Zone( findkeysforcommand( pCommand ) ); +}; + +void(string pKey, string pCommand) Key_Bind = +{ + cmd( strcat( "bind \"", pKey, "\" \"", pCommand, "\"\n" ) ); +}; + +void(float pNum, string pCommand) Key_LimitBinds = +{ + local string lAltlist; + local float lCounter; + local float lMaxnum; + local float lValue; + + lAltlist = Key_GetBindList( pCommand ); + lMaxnum = Util_GetAltStringCount( lAltlist ); + + for( lCounter = 0 ; lCounter < lMaxnum ; lCounter = lCounter + 1 ) { + lValue = stof( String_Normal( Util_GetAltStringItem( lAltlist, lCounter ) ) ); + + if( lValue == -1 ) + break; + if( lCounter >= pNum ) + Key_Unbind( Key_GetName( lValue ) ); + } + + String_Free( lAltlist ); +}; + diff --git a/scmenu/source/base/key.qh b/scmenu/source/base/key.qh new file mode 100644 index 000000000..1c627ef54 --- /dev/null +++ b/scmenu/source/base/key.qh @@ -0,0 +1,15 @@ +// NG-Menu +// base/key.qh + +void() Key_Init; +void() Key_Quit; +void() Key_Display; +void() Key_Hide; + +void( string pKey ) Key_Unbind; +string( float pKey ) Key_GetName; +float( string pKey ) Key_GetNum; +string( string pCommand ) Key_GetBindList; // returns altstring containing keynrs +void( float pNum, string pCommand) Key_LimitBinds; +void( string pKey, string pCommand) Key_Bind; + diff --git a/scmenu/source/base/snd.qc b/scmenu/source/base/snd.qc new file mode 100644 index 000000000..d6ff49765 --- /dev/null +++ b/scmenu/source/base/snd.qc @@ -0,0 +1,29 @@ +// NG-Menu +// base/snd.qc + +void( string pText ) _Sound_DPrint = +{ + if( sys_debug_sound ) + print( pText ); +}; + +bool( string pSnd ) Sound_Precache = +{ + _Sound_DPrint( strcat( "Precaching sound '", pSnd, "'\n" ) ); + if( pSnd == "" ) + return false; + if( pSnd != precache_sound( pSnd ) ) + return false; + else + return true; +}; + +void( string pSnd ) Sound_Free = +{ +}; + +void( string pSnd) Sound_Play = +{ + _Sound_DPrint( strcat( "Playing sound '", pSnd, "'\n" ) ); + localsound( pSnd ); +}; diff --git a/scmenu/source/base/snd.qh b/scmenu/source/base/snd.qh new file mode 100644 index 000000000..84f7fe56e --- /dev/null +++ b/scmenu/source/base/snd.qh @@ -0,0 +1,8 @@ +// NG-Menu +// base/snd.qh + +bool( string pSnd ) Sound_Precache; + +void( string pSnd ) Sound_Free; + +void( string pSnd ) Sound_Play; diff --git a/scmenu/source/base/timer.qc b/scmenu/source/base/timer.qc new file mode 100644 index 000000000..6886acbc1 --- /dev/null +++ b/scmenu/source/base/timer.qc @@ -0,0 +1,22 @@ +// NG-Menu +// base/timer.qc + +float _Timer_LastTime; + +void() Timer_Init = +{ + Timer_Time = gettime(); + Timer_Delta = 0.0; +}; + +void() Timer_Update = +{ + _Timer_LastTime = Timer_Time; + Timer_Time = gettime(); + Timer_Delta = Timer_Time - _Timer_LastTime; +}; + +void() Timer_Quit = +{ +}; + diff --git a/scmenu/source/base/timer.qh b/scmenu/source/base/timer.qh new file mode 100644 index 000000000..52e631a00 --- /dev/null +++ b/scmenu/source/base/timer.qh @@ -0,0 +1,11 @@ +// NG-Menu +// base/timer.qh + +// timer +float Timer_Time; // current time +float Timer_Delta; // time difference to the last cycle + +void() Timer_Init; +void() Timer_Update; +void() Timer_Quit; + diff --git a/scmenu/source/control/_fx/float.qc b/scmenu/source/control/_fx/float.qc new file mode 100644 index 000000000..965d54120 --- /dev/null +++ b/scmenu/source/control/_fx/float.qc @@ -0,0 +1,55 @@ +// DP/Nex Menu +// control/effect/float.qc + +////////////////////// +// Item_Effect_Float +/// + +void() Item_Effect_Float_Update = +{ + if( self._state == ITEM_STATE_FORWARD ) { + if( self._presstime + self.time_x < Timer_Time ) { + self._parent.self.targetFloat = self.endFloat; + self._presstime = Timer_Time; + self._state = ITEM_STATE_BACKWARD; + } else + self._parent.self.targetFloat = self.interpolForward( self.startFloat, + self.endFloat, self.time_x, Timer_Time - self._presstime, + self._parent.self.targetFloat ); + } else { + if( self._presstime + self.time_y < Timer_Time ) { + self._parent.self.targetFloat = self.startFloat; + self._presstime = Timer_Time; + self._state = ITEM_STATE_FORWARD; + } else + self._parent.self.targetFloat = self.interpolForward( self.endFloat, + self.startFloat, self.time_y, Timer_Time - self._presstime, + self._parent.self.targetFloat ); + } + + // Check the task state + if( ( self.time_y == -1 && self._state == ITEM_STATE_BACKWARD ) || + ( self.time_z >= 0 && self.time_z >= Timer_Time ) ) + if( self.time_z == -2 ) + self._runFlag = self._runFlag | RUNFLAG_CHILDDRAWONLY | FLAG_DRAWONLY; + else + Menu_DeleteAfterFrame( self ); +}; + +void() Item_Effect_Float_Reinit = +{ + self._parent.self.targetFloat = self.startFloat; + self._presstime = Timer_Time; + self._state = ITEM_STATE_FORWARD; + if( self.flag & FLAG_DRAWONLY ) + self.flag = self.flag - FLAG_DRAWONLY; +}; + +void() Item_Effect_Float_Spawn = +{ + self.flag = self.flag | FLAG_HIDDEN; + + self._update = Item_Effect_Float_Update; + self._reinit = Item_Effect_Float_Reinit; +}; + diff --git a/scmenu/source/control/_fx/fx.qh b/scmenu/source/control/_fx/fx.qh new file mode 100644 index 000000000..abaae054f --- /dev/null +++ b/scmenu/source/control/_fx/fx.qh @@ -0,0 +1,61 @@ +// DP/Nex Menu +// control/fx/fx.qh + +// [Item_Changer] + +// An effect always affects its parent +// There are two kinds of effects periodic/loop effects and task-effects +// The difference is that a task-effect will be finished somewhen and then deactivate/remove itself +// while a loop effect will restart +// A loop task will have deltaTime2 set + +enum { + ITEM_STATE_FORWARD, + ITEM_STATE_BACKWARD +}; + +// [Item_Effect] +// deltaTime2 = -1 for a task effect +// deltaTime2 = -2 for a persistent task effect +// endTime = -1 for a infinite loop effect +.vector time; // + +.union { + .vector targetVector; + .float targetFloat; +}; +/* +.union { + struct { + vector startVector; + float startFloat; + }; + struct { + vector endVector; + float endFloat; + }; +};*/ +.float startFloat; +.vector startVector; +.float endFloat; +.vector endVector; + +.float _state; +.float _presstime; + +// returns new value +typedef float( float pStart, float pEnd, float pDeltaTime, float pT, float pValue ) InterpolFunction; + +.InterpolFunction interpolForward; +.InterpolFunction interpolBackward; + +// Item_Effect_Float +// Item_Effect_Vector + +void() Item_Effect_Vector_Reinit; +void() Item_Effect_Vector_Update; +void() Item_Effect_Vector_Spawn; + +// Interpolation functions +float( float pStart, float pEnd, float pDeltaTime, float pT, float pValue ) FX_LinearInterpolation; +float( float pStart, float pEnd, float pDeltaTime, float pT, float pValue ) FX_SquareInterpolation; diff --git a/scmenu/source/control/_fx/interpol.qc b/scmenu/source/control/_fx/interpol.qc new file mode 100644 index 000000000..feb046c69 --- /dev/null +++ b/scmenu/source/control/_fx/interpol.qc @@ -0,0 +1,12 @@ +// DP/Nex Menu +// control/fx/interpol.qc + +float( float pStart, float pEnd, float pDeltaTime, float pT, float pValue ) FX_LinearInterpolation = +{ + return pValue + ((pEnd - pStart) * Timer_Delta / pDeltaTime); +}; + +float( float pStart, float pEnd, float pDeltaTime, float pT, float pValue ) FX_SquareInterpolation = +{ + return pEnd - (pEnd - pStart) * (pDeltaTime - pT) * (pDeltaTime - pT) / pDeltaTime / pDeltaTime; +}; diff --git a/scmenu/source/control/_fx/vector.qc b/scmenu/source/control/_fx/vector.qc new file mode 100644 index 000000000..4bb9ff37f --- /dev/null +++ b/scmenu/source/control/_fx/vector.qc @@ -0,0 +1,71 @@ +// DP/Nex Menu +// control/fx/vector.qc + +////////////////////// +// Item_Effect_Vector +/// + +void( InterpolFunction pFunction, bool pForward ) _IEV_Interpolate = +{ + local vector lCopy; + local float lT; + + lT = Timer_Time - self._presstime; + lCopy = self._parent.self.targetVector; + if( pForward ) { + lCopy_x = pFunction( self.startVector_x, self.endVector_x, self.time_x, lT, lCopy_x ); + lCopy_y = pFunction( self.startVector_y, self.endVector_y, self.time_x, lT, lCopy_y ); + lCopy_z = pFunction( self.startVector_z, self.endVector_z, self.time_x, lT, lCopy_z ); + } else { + lCopy_x = pFunction( self.endVector_x, self.startVector_x, self.time_y, lT, lCopy_x ); + lCopy_y = pFunction( self.endVector_y, self.startVector_y, self.time_y, lT, lCopy_y ); + lCopy_z = pFunction( self.endVector_z, self.startVector_z, self.time_y, lT, lCopy_z ); + } + self._parent.self.targetVector = lCopy; +}; + +void() Item_Effect_Vector_Update = +{ + if( self._state == ITEM_STATE_FORWARD ) { + if( self._presstime + self.time_x < Timer_Time ) { + self._parent.self.targetVector = self.endVector; + self._presstime = Timer_Time; + self._state = ITEM_STATE_BACKWARD; + } else + _IEV_Interpolate( self.interpolForward, true ); + } else { + if( self._presstime + self.time_y < Timer_Time ) { + self._parent.self.targetVector = self.startVector; + self._presstime = Timer_Time; + self._state = ITEM_STATE_FORWARD; + } else + _IEV_Interpolate( self.interpolBackward, false ); + } + + // Check the task state + if( ( self.time_y == -1 && self._state == ITEM_STATE_BACKWARD ) || + ( self.time_z >= 0 && self.time_z >= Timer_Time ) ) + if( self.time_z == -2 ) + self._runFlag = self._runFlag | RUNFLAG_CHILDDRAWONLY | FLAG_DRAWONLY; + else + Menu_DeleteAfterFrame( self ); + +}; + +void() Item_Effect_Vector_Reinit = +{ + self._parent.self.targetVector = self.startVector; + self._presstime = Timer_Time; + self._state = ITEM_STATE_FORWARD; + if( self.flag & FLAG_DRAWONLY ) + self.flag = self.flag - FLAG_DRAWONLY; +}; + +void() Item_Effect_Vector_Spawn = +{ + self.flag = self.flag | FLAG_HIDDEN; + + self._update = Item_Effect_Vector_Update; + self._reinit = Item_Effect_Vector_Reinit; +}; + diff --git a/scmenu/source/control/automation/automation.qc b/scmenu/source/control/automation/automation.qc new file mode 100644 index 000000000..54d2ed018 --- /dev/null +++ b/scmenu/source/control/automation/automation.qc @@ -0,0 +1,13 @@ +// DP/Nex Menu +// control/automation/factory.qc + +void() Item_Automation_Init = +{ + self.flag = FLAG_TEMPLATE; + Menu_DeleteAfterFrame( self ); +}; + +void() Item_Task_Init = +{ + self.flag = FLAG_HIDDEN; +}; diff --git a/scmenu/source/control/automation/automation.qh b/scmenu/source/control/automation/automation.qh new file mode 100644 index 000000000..18107aa9e --- /dev/null +++ b/scmenu/source/control/automation/automation.qh @@ -0,0 +1,30 @@ +// DP/Nex Menu +// control/automation/automation.qh + +// [Item_Automation] +void() Item_Automation_Init; + +// Item_Automation_ForEach [Item_Automation] +.string target; // target type (with Item_) +.string link; // "" for current namespace, else path to objects +.entity _current; // current entity + +.event action; + +void() Item_Automation_ForEach_Spawn; + +// Item_Automation_Job [Item_Automation] +.event action; + +// [Item_Task] +void() Item_Task_Init; + +void() Item_Automation_Job_Spawn; + +// Item_Task_Job [Item_Task] +.event init; +.event reinit; +.event update; +.event destroy; + +void() Item_Task_Job_Spawn; diff --git a/scmenu/source/control/automation/foreach.qc b/scmenu/source/control/automation/foreach.qc new file mode 100644 index 000000000..78600e2f9 --- /dev/null +++ b/scmenu/source/control/automation/foreach.qc @@ -0,0 +1,23 @@ +// DP/Nex Menu +// control/automation/foreach.qc + +void() Item_Automation_ForEach_Spawn = +{ + local entity lLink; + + Item_Automation_Init(); + + if( self.link == "" ) + lLink = self._parent; + else + lLink = Menu_GetItem( self.link ); + if( !self.target || !isfunction( strcat( self.target, "_Spawn" ) ) ) { + objerror( "Bad target type!" ); + return; + } + + for( self._current = lLink._child ; self._current ; self._current = self._current._next ) + if( self._current.type == self.target ) + CtCall_Action(); +}; + diff --git a/scmenu/source/control/automation/job.qc b/scmenu/source/control/automation/job.qc new file mode 100644 index 000000000..6537ae3ff --- /dev/null +++ b/scmenu/source/control/automation/job.qc @@ -0,0 +1,22 @@ +// DP/Nex Menu +// control/automation/job.qc + +void() Item_Automation_Job_Spawn = +{ + Item_Automation_Init(); + + //print( "AutoJob: ", self.name, "\n" ); + + CtCall_Action(); +}; + +void() Item_Task_Job_Spawn = +{ + Item_Task_Init(); + + self._reinit = CtCall_Reinit; + self._destroy = CtCall_Destroy; + self._update = CtCall_Update; + + CtCall_Init(); +}; diff --git a/scmenu/source/control/cinematic.qc b/scmenu/source/control/cinematic.qc new file mode 100644 index 000000000..f0d3e47dc --- /dev/null +++ b/scmenu/source/control/cinematic.qc @@ -0,0 +1,49 @@ +// DP/Nex Menu +// control/cinematic.qc + +///////////////////// +// [Item_Cinematic] +/// + +/* +=================== +Item_Cinematic_Destroy +=================== +*/ +void() Item_Cinematic_Destroy = +{ + // close the video stream + cin_close( self.normal ); + + String_EntityFree( self, link ); + String_EntityFree( self, normal ); +} + +/* +=================== +Item_Cinematic_Init +=================== +*/ +void() Item_Cinematic_Init = +{ + self.flag = self.flag | FLAG_HIDDEN; + + String_EntityZone( self, link ); + String_EntityZone( self, normal ); + + cin_open( self.link, self.normal ); + + self._destroy = Item_Cinematic_Destroy; +}; + +///////////////////////// +// Item_Cinematic_Loop +/// + +void() Item_Cinematic_Loop_Spawn = +{ + Item_Cinematic_Init(); + + cin_setstate( self.normal, CINE_LOOP ); +}; + diff --git a/scmenu/source/control/constants.qh b/scmenu/source/control/constants.qh new file mode 100644 index 000000000..fa7353678 --- /dev/null +++ b/scmenu/source/control/constants.qh @@ -0,0 +1,13 @@ +// DP/Nex Menu +// control/constants.qh + +const string ITEM_SOUND_NOSELECT = "misc/temp.wav"; + +// Item_Button + +const float ITEM_BUTTON_ACTIONTIME = 0.2; + +// ITEM_EDITBOX constantes +const float ITEM_EDITBOX_CURSOR_FREQ = 2; +const float ITEM_EDITBOX_FLASHTIME = 0.1; +const float ITEM_EDITBOX_SCROLLDISTANCE = 1.5; diff --git a/scmenu/source/control/container.qc b/scmenu/source/control/container.qc new file mode 100644 index 000000000..1a1f19323 --- /dev/null +++ b/scmenu/source/control/container.qc @@ -0,0 +1,7 @@ +// DP/Nex Menu +// control/container.qc + +void() Item_Container_Spawn = +{ + self.flag = self.flag | FLAG_HIDDEN; +}; diff --git a/scmenu/source/control/custom.qc b/scmenu/source/control/custom.qc new file mode 100644 index 000000000..59ff1552f --- /dev/null +++ b/scmenu/source/control/custom.qc @@ -0,0 +1,22 @@ +// DP/Nex Menu +// control/custom.qc + +//////////////// +// Item_Custom +/// +// TODO: Remove Item_Custom - No, it should be the only customizable item + +void() Item_Custom_Spawn = +{ + self._reinit = CtCall_Reinit; + self._destroy = CtCall_Destroy; + self._key = CtCall_Key; + self._draw = CtCall_Draw; + self._mouseEnter = CtCall_MouseEnter; + self._mouseLeave = CtCall_MouseLeave; + self._select = CtCall_Select; + self._update = CtCall_Update; + + CtCall_Init(); +}; + diff --git a/scmenu/source/control/data/altstring.qc b/scmenu/source/control/data/altstring.qc new file mode 100644 index 000000000..35d33610f --- /dev/null +++ b/scmenu/source/control/data/altstring.qc @@ -0,0 +1,25 @@ +// DP/Nex Menu +// control/data/altstring.qc + +void( float pEvent ) Item_DataLink_AltString_DataEvent = +{ + Item_DataLink_Update(); + + if( !self._link ) + return; + if( pEvent == ITEM_DATALINK_SET ) { + self._link.value = Util_SetAltStringItem( self._link.value, self.stepValue, self.value ); + Raise_DataEvent( self._link, ITEM_DATALINK_SET ); + } else if( pEvent == ITEM_DATALINK_GET ) { + Raise_DataEvent( self._link, ITEM_DATALINK_GET ); + String_EntitySet( self, value, String_Normal( Util_GetAltStringItem( self._link.value, self.stepValue ) ) ); + } else + Raise_DataEvent( self._link, pEvent ); +}; + +void() Item_DataLink_AltString_Spawn = +{ + Item_DataLink_Init(); + + self._dataEvent = Item_DataLink_AltString_DataEvent; +}; diff --git a/scmenu/source/control/data/base.qc b/scmenu/source/control/data/base.qc new file mode 100644 index 000000000..0db1ad026 --- /dev/null +++ b/scmenu/source/control/data/base.qc @@ -0,0 +1,166 @@ +// DP/Nex Menu +// control/data/base.qc + +/* +=================== +Raise_DataEvent +=================== +*/ +void( entity pItem, float pEvent ) Raise_DataEvent = +{ + local entity lOld; + + if( !pItem._dataEvent ) + return; + + lOld = self; + self = pItem; + self._dataEvent( pEvent ); + self = lOld; +}; + +///////////////////// +// [Item_Data] +/// + +/* +=================== +Item_Data_Destroy +=================== +*/ +void() Item_Data_Destroy = +{ + String_EntityFree( self, value ); + String_EntityFree( self, defValue ); + String_EntityFree( self, _syncValue ); +}; + +/* +=================== +Item_Data_Init +=================== +*/ +void() Item_Data_Init = +{ + String_EntityZone( self, value ); + String_EntityZone( self, defValue ); + String_EntityCreate( self, _syncValue ); + + self.flag = self.flag | FLAG_HIDDEN; + + self._destroy = Item_Data_Destroy; +}; + +//////////////////// +// [Item_DataLink] +/// + +/* +=================== +Item_DataLink_Update +=================== +*/ +void() Item_DataLink_Update = +{ + if( self.link == "" ) + self._link = null_entity; + else if( self.link != self._link.name ) + self._link = Menu_GetItem( self.link ); +}; + +/* +=================== +Item_DataLink_Destroy +=================== +*/ +void() Item_DataLink_Destroy = +{ + String_EntityFree( self, link ); + String_EntityFree( self, value ); +}; + +/* +=================== +Item_DataLink_Init +=================== +*/ +void() Item_DataLink_Init = +{ + self.flag = self.flag | FLAG_HIDDEN; + + String_EntityZone( self, link ); + String_EntityZone( self, value ); + Item_DataLink_Update(); + + self._destroy = Item_DataLink_Destroy; +}; + +//////////////////// +// [Item_DataLink_Switch] +/// + +/* +=================== +Item_DataLink_Switch_Destroy +=================== +*/ +void() Item_DataLink_Switch_Destroy = +{ + Item_DataLink_Destroy(); + String_EntityFree( self, descList ); +}; + +/* +=================== +Item_DataLink_Switch_Init +=================== +*/ +void() Item_DataLink_Switch_Init = +{ + Item_DataLink_Value_Spawn(); + String_EntityZone( self, descList ); + + self._destroy = Item_DataLink_Switch_Destroy; +}; + +//////////////////// +// [Item_DataUser] +/// + +/* +=================== +Item_DataUser_Update +=================== +*/ +void() Item_DataUser_Update = +{ + if( self.target == "" ) + self._target = null_entity; + else if( self.target != self._target.name ) + self._target = Menu_GetItem( self.target ); +}; + +/* +=================== +Item_DataUser_Destroy +=================== +*/ +void() Item_DataUser_Destroy = +{ + String_EntityFree( self, target ); +}; + +/* +=================== +Item_DataUser_Init +=================== +*/ +void() Item_DataUser_Init = +{ + String_EntityZone( self, target ); + + Item_DataUser_Update(); + + self._destroy = Item_DataUser_Destroy; +}; + diff --git a/scmenu/source/control/data/container.qc b/scmenu/source/control/data/container.qc new file mode 100644 index 000000000..373be5584 --- /dev/null +++ b/scmenu/source/control/data/container.qc @@ -0,0 +1,38 @@ +// DP/Nex Menu +// control/data/container.qc + + +//////////////////////// +// Item_Data_Container +/// + +void() Item_Data_Container_Reinit = +{ + String_EntitySet( self, value, self._syncValue ); +}; + +void( float pEvent ) Item_Data_Container_DataEvent = +{ + switch( pEvent ) { + case ITEM_DATA_SYNC: + String_EntitySet( self, value, self._syncValue ); + break; + case ITEM_DATA_SEND: + String_EntitySet( self, _syncValue, self.value ); + break; + case ITEM_DATA_RESET: + String_EntitySet( self, value, self.defValue ); + String_EntitySet( self, _syncValue, self.defValue ); + break; + } +}; + +void() Item_Data_Container_Spawn = +{ + Item_Data_Init(); + + self._reinit = Item_Data_Container_Reinit; + self._dataEvent = Item_Data_Container_DataEvent; + + String_EntitySet( self, _syncValue, self.defValue ); +}; diff --git a/scmenu/source/control/data/cvar.qc b/scmenu/source/control/data/cvar.qc new file mode 100644 index 000000000..24b26920d --- /dev/null +++ b/scmenu/source/control/data/cvar.qc @@ -0,0 +1,88 @@ +// DP/Nex Menu +// control/data/cvar.qc + +/* +=================== +Item_Data_CvarCreateSave +=================== +*/ + +void() Item_Data_Cvar_Sync = +{ + String_EntitySet( self, _syncValue, str_cvar( self.cvarName ) ); + String_EntitySet( self, value, self._syncValue ); +}; + +void() Item_Data_Cvar_Send = +{ + cvar_set( self.cvarName, self.value ); + Item_Data_Cvar_Sync(); +}; + +void() Item_Data_Cvar_Reset = +{ + String_EntitySet( self, value, self.defValue ); + Item_Data_Cvar_Send(); +}; + +void() Item_Data_Cvar_Test_Start = +{ + cvar_set( self.cvarName, self.value ); +}; + +void() Item_Data_Cvar_Test_End = +{ + cvar_set( self.cvarName, self._syncValue ); +}; + +void( float pEvent ) Item_Data_Cvar_DataEvent = +{ + switch( pEvent ) { + case ITEM_DATA_SYNC: + Item_Data_Cvar_Sync(); + break; + case ITEM_DATA_SEND: + Item_Data_Cvar_Send(); + break; + case ITEM_DATA_RESET: + Item_Data_Cvar_Reset(); + break; + case ITEM_DATA_TEST_START: + Item_Data_Cvar_Test_Start(); + break; + case ITEM_DATA_TEST_END: + Item_Data_Cvar_Test_End(); + break; + } +}; + +void() Item_Data_Cvar_Destroy = +{ + Item_Data_Destroy(); + String_EntityFree( self, cvarName ); +}; + +void() Item_Data_Cvar_Spawn = +{ + String_EntityZone( self, cvarName ); + Item_Data_Init(); + + self.flag = self.flag | FLAG_HIDDEN; + + self._dataEvent = Item_Data_Cvar_DataEvent; + self._reinit = Item_Data_Cvar_Sync; + self._destroy = Item_Data_Cvar_Destroy; +}; + +/* +=================== +Item_Data_CvarCreateSave +=================== +*/ + +void() Item_Data_CvarCreateSave_Spawn = +{ + Item_Data_Cvar_Spawn(); + + registercvar( self.cvarName, self.defValue, CVAR_SAVE ); +}; diff --git a/scmenu/source/control/data/data.qh b/scmenu/source/control/data/data.qh new file mode 100644 index 000000000..633a5b0e9 --- /dev/null +++ b/scmenu/source/control/data/data.qh @@ -0,0 +1,112 @@ +// DP/Nex Menu +// control/data/data.qh + +enum { + ITEM_DATA_SYNC, // sync with the engine or whatever else this is linked to + ITEM_DATA_SEND, // set it + ITEM_DATA_RESET, // use the default value + ITEM_DATA_TEST_START, // set it but dont sync our backup + ITEM_DATA_TEST_END, // set our backup + ITEM_DATALINK_SET, + ITEM_DATALINK_GET +}; + +void( entity pItem, float pEvent ) Raise_DataEvent; + +// [Item_Data] +.string value; // current value in the menu +.string defValue; // default value (set for the menu) +.string _syncValue; // last value that is known from the real source + +.void( float pEvent ) _dataEvent; + +void() Item_Data_Init; +void() Item_Data_Destroy; + +// [Item_DataUser] +// In this case the target field points to a Item_Data* item +.string target; +.entity _target; + +void() Item_DataUser_Update; +void() Item_DataUser_Init; +void() Item_DataUser_Destroy; + +// [Item_DataLink] +// links to a [Item_Data] object +.string link; +.entity _link; +.string value; + +.void( float pEvent ) _dataEvent; + +void() Item_DataLink_Init; +void() Item_DataLink_Destroy; +void() Item_DataLink_Update; + +// Item_Data_Container [Item_Data] + +// Item_Data_Cvar [Item_Data] +.string cvarName; + +void( float pEvent ) Item_Data_Cvar_DataEvent; +void() Item_Data_Cvar_Spawn; + +// Item_Data_CvarCreateSave Item_Data_Cvar +void() Item_Data_CvarCreateSave_Spawn; + +// Item_DataLink_Text [Item_DataLink] +.float maxValue; // max length of the string (-1 for infinity) +.string value; // text + +// Item_DataLink_Value [Item_DataLink] +.float minValue; +.float stepValue; +.float maxValue; +.float _realValue; + +.string value; // read-only is most cases, but supplies are version of the data that can be displayed + +void() Item_DataLink_Value_Clamp; +void() Item_DataLink_Value_Spawn; + +// [Item_DataLink_Switch] Item_DataLink_Value +.string descList; // a altstring containing description strings + +void() Item_DataLink_Switch_Init; +void() Item_DataLink_Switch_Destroy; + +// Item_DataLink_ValueSwitch [Item_DataLink_Switch] +// the default value for stepValue is 1 +// maxValue is calculated if it is 0 + +void() Item_DataLink_ValueSwitch_Spawn; + +// Item_DataLink_TextSwitch [Item_DataLink_Switch] +// minValue is 0, stepValue is 1, maxValue is the number of items in descList/valueList +.string valueList; // contains the values for the different + +void( float pEvent ) Item_DataLink_TextSwitch_DataEvent; +void() Item_DataLink_TextSwitch_Destroy; +void() Item_DataLink_TextSwitch_Spawn; + +// Item_DataLink_FastResync [Item_DataLink] +.float _presstime; // no more than once a frame? + +void() Item_DataLink_FastResync_Spawn; + +// Item_DataLink_TextValue [Item_DataLink] +void() Item_DataLink_TextValue_Spawn; + +// Item_DataLink_TextTime [Item_DataLink] +// hour:min:sec +void() Item_DataLink_TextTime_Spawn; + +// Item_DataLink_AltString [Item_DataLink] +.float stepValue; // contains + +void() Item_DataLink_AltString_Spawn; + +// Item_DataLink_Router [Item_DataLink] +// sets value and _realValue of alll children to the float value of self._stepValue +void() Item_DataLink_Router_Spawn; diff --git a/scmenu/source/control/data/fastresync.qc b/scmenu/source/control/data/fastresync.qc new file mode 100644 index 000000000..0f2af9967 --- /dev/null +++ b/scmenu/source/control/data/fastresync.qc @@ -0,0 +1,33 @@ +// DP/Nex Menu +// control/data/fastresync.qc + +///////////////////////////// +// Item_DataLink_FastResync +//// + +void( float pEvent ) Item_DataLink_FastResync_DataEvent = +{ + if( pEvent == ITEM_DATALINK_GET ) { + if( self._presstime != Timer_Time ) { + Raise_DataEvent( self._link, ITEM_DATA_SYNC ); + self._presstime = Timer_Time; + } + Raise_DataEvent( self._link, ITEM_DATALINK_GET ); + String_EntitySet( self, value, self._link.value ); + } else if( pEvent == ITEM_DATALINK_SET ) { + if( self._link ) { + String_EntitySet( self._link, value, self.value ); + Raise_DataEvent( self._link, ITEM_DATALINK_SET ); + } + } else + Raise_DataEvent( self._link, pEvent ); +}; + +void() Item_DataLink_FastResync_Spawn = +{ + Item_DataLink_Init(); + + self._presstime = Timer_Time - 1; + + self._dataEvent = Item_DataLink_FastResync_DataEvent; +}; diff --git a/scmenu/source/control/data/router.qc b/scmenu/source/control/data/router.qc new file mode 100644 index 000000000..125f32280 --- /dev/null +++ b/scmenu/source/control/data/router.qc @@ -0,0 +1,32 @@ +// DP/Nex Menu +// control/data/router.qc + +void( float pEvent ) Item_DataLink_Router_DataEvent = +{ + local entity lChild; + + switch( pEvent ) { + case ITEM_DATALINK_SET: + for( lChild = self._child ; lChild ; lChild = lChild._next ) { + lChild._realValue = self._realValue; + Raise_DataEvent( lChild, ITEM_DATALINK_SET ); + } + case ITEM_DATALINK_GET: + if( self._child ) { + Raise_DataEvent( self._child, ITEM_DATALINK_GET ); + self._realValue = self._child._realValue; + } + break; + default: + for( lChild = self._child ; lChild ; lChild = lChild._next ) + Raise_DataEvent( lChild, pEvent ); + break; + } +}; + +void() Item_DataLink_Router_Spawn = +{ + Item_DataLink_Init(); + + self._dataEvent = Item_DataLink_Router_DataEvent; +}; diff --git a/scmenu/source/control/data/text.qc b/scmenu/source/control/data/text.qc new file mode 100644 index 000000000..7cbb32af5 --- /dev/null +++ b/scmenu/source/control/data/text.qc @@ -0,0 +1,32 @@ +// DP/Nex Menu +// control/data/text.qc + +void( float pEvent ) Item_DataLink_Text_DataEvent = +{ + Item_DataLink_Update(); + + if( pEvent == ITEM_DATALINK_SET ) { + if( self.maxValue >= 0 ) + String_EntitySet( self, value, substring( self.value, 0, self.maxValue ) ); + if( self._link ) { + String_EntitySet( self._link, value, self.value ); + Raise_DataEvent( self._link, ITEM_DATALINK_SET ); + } + } else if( !self._link ) + return; + else if( pEvent == ITEM_DATALINK_GET ) { + String_EntitySet( self, value, self._link.value ); + if( self.maxValue >= 0 ) { + Raise_DataEvent( self._link, ITEM_DATALINK_GET ); + String_EntitySet( self, value, substring( self.value, 0, self.maxValue ) ); + } + } else + Raise_DataEvent( self._link, pEvent ); +}; + +void() Item_DataLink_Text_Spawn = +{ + Item_DataLink_Init(); + + self._dataEvent = Item_DataLink_Text_DataEvent; +}; diff --git a/scmenu/source/control/data/textswitch.qc b/scmenu/source/control/data/textswitch.qc new file mode 100644 index 000000000..d9990ce0c --- /dev/null +++ b/scmenu/source/control/data/textswitch.qc @@ -0,0 +1,62 @@ +// DP/Nex Menu +// control/data/textswitch.qc + + +void( float pEvent ) Item_DataLink_TextSwitch_DataEvent = +{ + Item_DataLink_Update(); + + if( pEvent == ITEM_DATALINK_SET ) { + Item_DataLink_Value_Clamp(); + if( self._link ) { + String_EntitySet( self._link, value, String_Normal( Util_GetAltStringItem( self.valueList, self._realValue ) ) ); + Raise_DataEvent( self._link, ITEM_DATALINK_SET ); + } + } else if( !self._link ) + return; + else if( pEvent == ITEM_DATALINK_GET ) { + local float lPos, lCount; + // sync _link.value + Raise_DataEvent( self._link, ITEM_DATALINK_GET ); + + // check if we need a full resync + // TODO: Remove this check since we actually dont want to support twice-defined entries + if( String_Normal( Util_GetAltStringItem( self.valueList, self._realValue ) ) == self._link.value ) { + String_EntitySet( self, value, String_Normal( Util_GetAltStringItem( self.descList, self._realValue ) ) ); + return; + } + + // resync _link.value + lCount = Util_GetAltStringCount( self.valueList ); + for( lPos = 0 ; lPos < lCount ; ++lPos ) + if( String_Normal( Util_GetAltStringItem( self.valueList, lPos ) ) == self._link.value ) + break; + + self._realValue = lPos; + String_EntitySet( self, value, String_Normal( Util_GetAltStringItem( self.descList, lPos ) ) ); + } else + Raise_DataEvent( self._link, pEvent ); +}; + +void() Item_DataLink_TextSwitch_Destroy = +{ + String_EntityFree( self, valueList ); + Item_DataLink_Switch_Destroy(); +}; + +void() Item_DataLink_TextSwitch_Spawn = +{ + Item_DataLink_Switch_Init(); + String_EntityZone( self, valueList ); + + self.minValue = 0; + if( self.maxValue == 0.0 ) + self.maxValue = Util_GetAltStringCount( self.descList ) - 1; + if( self.maxValue == 0.0 ) + self.stepValue = 0.0; + else + self.stepValue = 1; + + self._destroy = Item_DataLink_TextSwitch_Destroy; + self._dataEvent = Item_DataLink_TextSwitch_DataEvent; +}; diff --git a/scmenu/source/control/data/texttime.qc b/scmenu/source/control/data/texttime.qc new file mode 100644 index 000000000..5b15dcf8f --- /dev/null +++ b/scmenu/source/control/data/texttime.qc @@ -0,0 +1,74 @@ +// DP/Nex Menu +// control/data/texttime.qc + +float() _IDLTT_ConvertTime = +{ + local float lTotal; + local float lCurrent; + local float lCount, lCounter; + + lTotal = 0; + + lCount = tokenize( self.value ); + for( lCounter = 0; lCounter < lCount; ++lCounter ) { + lCurrent = stof( argv( lCounter ) ); + lTotal = lTotal * 60 + lCurrent; + + if( argv( ++lCounter ) != ":" ) + break; + } + return rint( lTotal ); +}; + +string() _IDLTT_MakeString = +{ + local string lString; + local float lTotal; + local float lCurrent; + + lTotal = rint( self._realValue ); + lString = ""; + do { + lCurrent = mod( lTotal, 60 ); + + if( lString == "" ) + lString = String_Zone( ftos( lCurrent ) ); + else + lString = String_Set( lString, strcat( ftos( lCurrent ), ":", lString ) ); + + lTotal = floor( lTotal / 60 ); + } while( lTotal ); + + return lString; +}; + +void( float pEvent ) Item_DataLink_TextTime_DataEvent = +{ + Item_DataLink_Update(); + + if( pEvent == ITEM_DATALINK_SET ) { + self._link._realValue = _IDLTT_ConvertTime(); + Raise_DataEvent( self._link, ITEM_DATALINK_SET ); + self._realValue = self._link._realValue; + } else if( !self._link ) + return; + else if( pEvent == ITEM_DATALINK_GET ) { + Raise_DataEvent( self._link, ITEM_DATALINK_GET ); + if( self._link._realValue != self._realValue ) { + self._realValue = self._link._realValue; + String_EntitySet( self, value, String_Normal( _IDLTT_MakeString() ) ); + } + } else { + Raise_DataEvent( self._link, pEvent ); + self._realValue = self._link._realValue; + String_EntitySet( self, value, String_Normal( _IDLTT_MakeString() ) ); + } +}; + +void() Item_DataLink_TextTime_Spawn = +{ + Item_DataLink_Init(); + + self._dataEvent = Item_DataLink_TextTime_DataEvent; + self._realValue = self._link.minValue - 1; +}; diff --git a/scmenu/source/control/data/textvalue.qc b/scmenu/source/control/data/textvalue.qc new file mode 100644 index 000000000..921ea837a --- /dev/null +++ b/scmenu/source/control/data/textvalue.qc @@ -0,0 +1,33 @@ +// DP/Nex Menu +// control/data/textvalue.qc + +void( float pEvent ) Item_DataLink_TextValue_DataEvent = +{ + Item_DataLink_Update(); + + if( pEvent == ITEM_DATALINK_SET ) { + self._link._realValue = stof( self.value ); + Raise_DataEvent( self._link, ITEM_DATALINK_SET ); + self._realValue = self._link._realValue; + } else if( !self._link ) + return; + else if( pEvent == ITEM_DATALINK_GET ) { + Raise_DataEvent( self._link, ITEM_DATALINK_GET ); + if( self._link._realValue != self._realValue ) { + self._realValue = self._link._realValue; + String_EntitySet( self, value, self._link.value ); + } + } else { + Raise_DataEvent( self._link, pEvent ); + self._realValue = self._link._realValue; + String_EntitySet( self, value, self._link.value ); + } +}; + +void() Item_DataLink_TextValue_Spawn = +{ + Item_DataLink_Init(); + + self._dataEvent = Item_DataLink_TextValue_DataEvent; + self._realValue = self._link.minValue - 1; +}; diff --git a/scmenu/source/control/data/value.qc b/scmenu/source/control/data/value.qc new file mode 100644 index 000000000..de56c62dd --- /dev/null +++ b/scmenu/source/control/data/value.qc @@ -0,0 +1,79 @@ +// DP/Nex Menu +// control/data/value.qc + +/* +=================== +Item_DataLink_Value_Clamp +=================== +*/ +void() Item_DataLink_Value_Clamp = +{ + if( self._realValue > self.maxValue && self.maxValue > self.minValue ) + self._realValue = self.maxValue; + else if( self._realValue < self.minValue ) + self._realValue = self.minValue; + else // clamp is to stepValue + self._realValue = self.minValue + self.stepValue * rint( ( self._realValue - self.minValue ) / self.stepValue ); +}; + +/* +=================== +Item_DataLink_ClampText +=================== +*/ +string() Item_DataLink_ClampedValue = +{ + local float lLen; + local float lClampedStep; + if( self.stepValue == floor( self.stepValue ) ) + return ftos( self._realValue ); + // Get the integer length + lLen = strlen( ftos( rint( self._realValue + 0.375 ) ) ); + // Now add the step length + lClampedStep = rint( 1.0 / (self.stepValue - floor( self.stepValue )) ); + lLen += 1 + strlen( ftos( lClampedStep ) ); + return substring( ftos( self._realValue ), 0, lLen ); +} + +/* +=================== +Item_DataLink_Value_DataEvent +=================== +*/ +void( float pEvent ) Item_DataLink_Value_DataEvent = +{ + Item_DataLink_Update(); + + if( pEvent == ITEM_DATALINK_SET ) { + Item_DataLink_Value_Clamp(); + if( self._link ) { + self._link._realValue = self._realValue; + String_EntitySet( self._link, value, ftos( self._realValue ) ); + Raise_DataEvent( self._link, ITEM_DATALINK_SET ); + } + } else if( !self._link ) + return; + else if( pEvent == ITEM_DATALINK_GET ) { + Raise_DataEvent( self._link, ITEM_DATALINK_GET ); + self._realValue = stof( self._link.value ); + String_EntitySet( self, value, Item_DataLink_ClampedValue() ); + Item_DataLink_Value_Clamp(); + } else + Raise_DataEvent( self._link, pEvent ); +}; + +/* +=================== +Item_DataLink_Value_Spawn +=================== +*/ +void() Item_DataLink_Value_Spawn = +{ + Item_DataLink_Init(); + + if( self.stepValue == 0.0 ) + self.stepValue = 1; + + self._dataEvent = Item_DataLink_Value_DataEvent; +}; + diff --git a/scmenu/source/control/data/valueswitch.qc b/scmenu/source/control/data/valueswitch.qc new file mode 100644 index 000000000..5b894c8a8 --- /dev/null +++ b/scmenu/source/control/data/valueswitch.qc @@ -0,0 +1,59 @@ +// DP/Nex Menu +// control/data/valueswitch.qc + +/* +=================== +Item_DataLink_ValueSwitch_DataEvent +=================== +*/ +void( float pEvent ) Item_DataLink_ValueSwitch_DataEvent = +{ + Item_DataLink_Update(); + + if( pEvent == ITEM_DATALINK_SET ) { + Item_DataLink_Value_Clamp(); + if( self._link ) { + self._link._realValue = self._realValue; + String_EntitySet( self._link, value, ftos( self._realValue ) ); + Raise_DataEvent( self._link, ITEM_DATALINK_SET ); + } + } else if( !self._link ) + return; + else if( pEvent == ITEM_DATALINK_GET ) { + local float lPos; + + Raise_DataEvent( self._link, ITEM_DATALINK_GET ); + + self._realValue = stof( self._link.value ); + Item_DataLink_Value_Clamp(); + + lPos = rint( (self._realValue - self.minValue) / self.stepValue ); + String_EntitySet( self, value, String_Normal( Util_GetAltStringItem( self.descList, lPos ) ) ); + } else + Raise_DataEvent( self._link, pEvent ); +}; + +/* +=================== +Item_DataLink_ValueSwitch_Spawn +=================== +*/ +void() Item_DataLink_ValueSwitch_Spawn = +{ + Item_DataLink_Switch_Init(); + + if( self.maxValue == 0.0 ) + self.maxValue = self.minValue + (Util_GetAltStringCount( self.descList ) - 1) * self.stepValue; + else { + local float lCount; + + lCount = Util_GetAltStringCount( self.descList ); + if( lCount ) + self.stepValue = (self.maxValue - self.minValue ) / (lCount - 1); + else + self.stepValue = 0; + } + + self._dataEvent = Item_DataLink_ValueSwitch_DataEvent; + self._destroy = Item_DataLink_Switch_Destroy; +}; diff --git a/scmenu/source/control/fx/base.qc b/scmenu/source/control/fx/base.qc new file mode 100644 index 000000000..56cafa905 --- /dev/null +++ b/scmenu/source/control/fx/base.qc @@ -0,0 +1,69 @@ +// DP/Nex Menu +// control/fx/base.qc + +///////////////////// +// [Item_Fx_Mutator] +/// + +bool() Item_Fx_Mutator_IsActive = +{ + if( self._parent.time_z >= 0 ) // < 0 stopped + self.time_z = (self._parent.time_z - self.time_y) / self.time_x; + else + self.time_z = -1; + if( self.time_z > 0 ) + return true; + return false; +}; + +void() Item_Fx_Mutator_UpdateTarget = +{ + if( !self.target ) + self._target = self._parent._target; + else if( self.target != self._target.name ) + self._target = Menu_GetItemEx( self._parent._target.parent, self.target, true ); +}; + +void() Item_Fx_Mutator_Destroy = +{ + String_EntityFree( self, target ); +}; + +void() Item_Fx_Mutator_Init = +{ + String_EntityZone( self, target ); + + self._destroy = Item_Fx_Destroy; +}; + + +////////////////// +// Item_Effect +//// + +void() Item_Fx_Effect_Update = +{ + if( !self.target ) { + self._target = null_entity; + self.time_z = -1; + return; + } + + if( self.target != self._target.name ) + self._target = Menu_GetItem( self._target ); + if( self.time_y <= Timer_Time && self.time_y + self.time_x <= Timer_Time ) + self.time_z = (Timer_Time - self.time_y) / self.time_x; + else + self.time_z = -1; +}; + +void() Item_Fx_Effect_Spawn = +{ + Item_Fx_Init(); + + self.time_y = -1; + + self.flag = self.flag | FLAG_HIDDEN; + + self._update = Item_Fx_Effect_Update; +}; diff --git a/scmenu/source/control/fx/fx.qh b/scmenu/source/control/fx/fx.qh new file mode 100644 index 000000000..9dbf0ab02 --- /dev/null +++ b/scmenu/source/control/fx/fx.qh @@ -0,0 +1,21 @@ +// DP/Nex Menu +// control/fx/fx.qh + +// Note: the time components are arranged this way because I want to be able to nest effects +// [Item_Fx_Mutator] +.vector time; // all values from 0 to 1, so the parent can vary in its length +.string target; +.entity _target; + +bool() Item_Fx_Mutator_IsActive; +void() Item_Fx_Destroy; +void() Item_Fx_Init; +void() Item_UpdateTarget; + +// Item_Fx_Effect [Item_Fx_Mutator] + +void() Item_Fx_Effect_Update; +void() Item_Fx_Effect_Spawn; + +// Item_Fx_Effect_Control + diff --git a/scmenu/source/control/items.qh b/scmenu/source/control/items.qh new file mode 100644 index 000000000..1fc3c4842 --- /dev/null +++ b/scmenu/source/control/items.qh @@ -0,0 +1,99 @@ +// DP/Nex Menu +// control/items.qh + +/* +Items/Controls: + +This control is supported/required by the menu manager : +Item_Window +Item_Reference + +Item_Layout + +The rest is not required: +Item_Custom + +Item_Picture + +Item_Text + +Item_Rect + +ITEM_BUTTON +ITEM_TEXTBUTTON + + + +ITEM_SLIDER + +ITEM_TEXTSWITCH +*/ + +// INFO: some information about the spawn functions +// INFO: Since I dont want another namespace clutching all spawn functions will have a nice and neat +// INFO: "_Spawn" suffix. + +// item constants + +const float ITEM_ALIGN_LEFT = 0; +enumflags { + ITEM_ALIGN_CENTER, + ITEM_ALIGN_RIGHT, + ITEM_ALIGN_FIX_RIGHT, // |text - actually this isnt necessary + ITEM_ALIGN_FIX_CENTER, // te|xt + ITEM_ALIGN_FIX_LEFT, // text| + ITEM_ALIGN_FIRST // for layouts: Item| ... with | being the origin +}; + +// flags constant + +enumflags { + FLAG_TEMPLATE, // this is a template do not touch, do not draw - actually dont do anything with it + FLAG_EMBEDDED, // the item cant be selected and all its children are embedded into its parent + FLAG_HIDDEN, // events wont be called and it wont be drawn, etc. + FLAG_NOSELECT, // cant be selected (but events will be called) + FLAG_CONNECTEDONLY, // only if connected (i.e. playing) + FLAG_SERVERONLY, // only displayed if server + FLAG_DEVELOPERONLY, // only displayed if developer + FLAG_DRAWONLY, // only the draw event will be called + FLAG_CHILDDRAWONLY, // used to make the children only drawable + FLAG_DRAWUPDATEONLY, // only the draw and update event get called + FLAG_CHILDDRAWUPDATEONLY, // only the draw and refresh events are called for children + FLAG_SEALOFFMOUSE // used to seal all items under the item with this flag off from mouse events + // TODO: real seal off all events (not only items not being selected) +}; + +// [Item_Link] [Item} +.entity _link; // item link + +void() Item_Link_Init; +void() Item_Link_Destroy; +void() Item_Link_Update; +bool( float pKey, float pAscii ) Item_Link_Key; +void() Item_Link_MouseEnter; + +bool() Item_Link_IsSelected; + +// [Item_Cinematic] +.string link; // full name of the video +.string normal; // normal name used with cachepic + +void() Item_Cinematic_Destroy; +void() Item_Cinematic_Init; + +// Item_Cinematic_Loop [Item_Cinematic] +void() Item_Cinematic_Loop_Spawn; + +// Item_Container +// used for non-visible, non-selectable data +void() Item_Container_Spawn; + +// Parser_Define +.string name; +.string value; + +/* +// ITEM_EDITBOX (derived from ITEM_TEXT mostly) +.string format; // //wildcards are * for each letter except the next after it - \* for * and * / space ' ' for one letter e.g. " . . . " for an ip field +.float maxlen; // -1 for infinite +.float _cursorpos;*/ diff --git a/scmenu/source/control/link.qc b/scmenu/source/control/link.qc new file mode 100644 index 000000000..05d68e126 --- /dev/null +++ b/scmenu/source/control/link.qc @@ -0,0 +1,63 @@ +// DP/Nex Menu +// control/link.qc + +//////////////// +// [Item_Link] +/// + +/* +The Link is only established if self.link is valid. +If it is valid, the item is made no selectable since the link should be selectable +*/ + +void() Item_Link_Update = +{ + if( self.link == "" ) + self._link = null_entity; + else if( self.link != self._link.name ) { + self._link = Menu_GetItem( self.link ); + self.flag = self.flag | FLAG_NOSELECT; + } +}; + +bool( float pKey, float pAscii ) Item_Link_Key = +{ + if( self._link ) + return Raise_Key( self._link, pKey, pAscii ); + + return false; +}; + +void() Item_Link_MouseEnter = +{ + if( self._link && Menu_IsSelectable( self._link ) ) + Menu_Select( self._link, true ); +}; + +bool() Item_Link_IsSelected = +{ + if( Menu_ActiveItem == self ) + return true; + + if( self._link ) + return (Menu_ActiveItem == self._link); + else + return false; +}; + +void() Item_Link_Destroy = +{ + String_EntityFree( self, link ); +}; + +void() Item_Link_Init = +{ + String_EntityZone( self, link ); + + Item_Link_Update(); + + self._destroy = Item_Link_Destroy; + self._key = Item_Link_Key; + self._mouseEnter = Item_Link_MouseEnter; + self._update = Item_Link_MouseEnter; +}; diff --git a/scmenu/source/control/visual/button.qc b/scmenu/source/control/visual/button.qc new file mode 100644 index 000000000..3dfd53c87 --- /dev/null +++ b/scmenu/source/control/visual/button.qc @@ -0,0 +1,190 @@ +// DP/Nex Menu +// control/visual/button.qc + +//////////////// +// Item_Button +/// + +bool( string pString ) _IB_IsPicture = +{ + return (substring( pString, 0, 1 ) == "$" ); +}; + +string( string pString ) _IB_GetPath = +{ + return substring( pString, 1, 1000 ); +}; + +// pString should be strzoned +vector( string pString ) _IB_GetSize = +{ + local vector lSize; + if( _IB_IsPicture( pString ) ) + return Gfx_GetImageSize( _IB_GetPath( pString ) ); + + lSize_x = strlen( pString ) * self.fontSize_x; + lSize_y = self.fontSize_y; + lSize_z = 0; + + return lSize; +}; + +vector() _IB_GetMaxSize = +{ + local vector lNormal, lSelected, lPressed, lSize; + + lNormal = _IB_GetSize( self.normal ); + lSelected = _IB_GetSize( self.selected ); + lPressed = _IB_GetSize( self.pressed ); + + lSize_x = max( lNormal_x, lSelected_x, lPressed_x ); + lSize_y = max( lNormal_y, lSelected_y, lPressed_y ); + lSize_z = 0; + + return lSize; +}; + +void( string pName, vector pColor, float pAlpha, float pDrawFlag ) _IB_Draw = +{ + local vector lSize; + local vector lPos; + local vector lMaxSize; + + // Calculate the real size of the current state + lSize = _IB_GetSize( pName ); + lMaxSize = _IB_GetMaxSize(); + if( _IB_IsPicture( pName ) ) { + lSize_x = lSize_x * ( self.size_x / lMaxSize_x ); + lSize_y = lSize_y * ( self.size_y / lMaxSize_y ); + } + + // Get the position - it depends on the alignment + //if( self.alignment == ITEM_ALIGN_LEFT ) // do nothing + lPos_y = self.pos_y; + if( self.alignment == ITEM_ALIGN_LEFT ) + lPos_x = self.pos_x; + if( self.alignment == ITEM_ALIGN_CENTER ) + lPos_x = self.pos_x + (self.size_x - lSize_x ) / 2; + else if( self.alignment == ITEM_ALIGN_RIGHT ) + lPos_x = self.pos_x + self.size_x - lSize_x; + else + lPos_x = self.pos_x; + + if( _IB_IsPicture( pName ) ) + Menu_DrawPicture( lPos, _IB_GetPath( pName ), lSize, pColor, pAlpha, pDrawFlag ); + else + Menu_DrawString( lPos, pName, self.fontSize, pColor, pAlpha, pDrawFlag ); +}; + +void() Item_Button_Draw = +{ + local string lText; + + if( self._state == ITEM_STATE_NORMAL ) + _IB_Draw( self.normal, self.color, self.alphas_x, self.drawFlags_x ); + else if( self._state == ITEM_STATE_SELECTED ) { + if( self.selected ) + lText = self.selected; + else + lText = self.normal; + _IB_Draw( lText, self.colorSelected, self.alphas_y, self.drawFlags_y ); + } else if( self._state == ITEM_STATE_PRESSED ) { + if( self.pressed ) + lText = self.pressed; + else if( self.selected ) + lText = self.selected; + else + lText = self.normal; + _IB_Draw( lText, self.colorPressed, self.alphas_z, self.drawFlags_z ); + } +}; + +void() _IB_Calc = +{ + if( self.size == '0 0 0' ) + self.size = _IB_GetMaxSize(); +}; + +void() Item_Button_Update = +{ + Item_Link_Update(); + + _IB_Calc(); + + if( self._presstime + ITEM_BUTTON_ACTIONTIME > Timer_Time ) + self._state = ITEM_STATE_PRESSED; + else if( Item_Link_IsSelected() ) + self._state = ITEM_STATE_SELECTED; + else + self._state = ITEM_STATE_NORMAL; +}; + +void( bool pSelect, bool pUser ) Item_Button_Select = +{ + if( pSelect && pUser ) + Sound_Play( self.soundSelected ); +}; + +bool( float pKey, float pAscii ) Item_Button_Key = +{ + if( Item_Link_Key( pKey, pAscii ) ) + return true; + + if( pKey == K_SPACE || pKey == K_ENTER || pKey == K_MOUSE1 ) { + Sound_Play( self.soundPressed ); + self._presstime = Timer_Time; + + CtCall_Action(); + return true; + } + return false; +}; + +void() Item_Button_Destroy = +{ + CtCall_Destroy(); + + String_EntityFree( self, normal ); + String_EntityFree( self, selected ); + String_EntityFree( self, pressed ); + String_EntityFree( self, soundSelected ); + String_EntityFree( self, soundPressed ); + + Item_Link_Destroy(); +}; + +void() Item_Button_Spawn = +{ + self._presstime = Timer_Time - 1 - ITEM_BUTTON_ACTIONTIME; + + // zone all the strings + String_EntityZone( self, normal ); + String_EntityZone( self, selected ); + String_EntityZone( self, pressed ); + String_EntityZone( self, soundSelected ); + String_EntityZone( self, soundPressed ); + + Item_Link_Init(); + + // set the defaults, etc + if( _IB_IsPicture( self.normal ) ) + Gfx_Precache( _IB_GetPath( self.normal ) ); + if( _IB_IsPicture( self.selected ) ) + Gfx_Precache( _IB_GetPath( self.selected ) ); + if( _IB_IsPicture( self.pressed ) ) + Gfx_Precache( _IB_GetPath( self.pressed ) ); + + Sound_Precache( self.soundSelected ); + Sound_Precache( self.soundPressed ); + + _IB_Calc(); + + self._reinit = CtCall_Reinit; + self._destroy = Item_Button_Destroy; + self._key = Item_Button_Key; + self._draw = Item_Button_Draw; + self._select = Item_Button_Select; + self._update = Item_Button_Update; + + CtCall_Init(); +}; diff --git a/scmenu/source/control/visual/editbox.qc b/scmenu/source/control/visual/editbox.qc new file mode 100644 index 000000000..7fdcaafa3 --- /dev/null +++ b/scmenu/source/control/visual/editbox.qc @@ -0,0 +1,189 @@ +// DP/Nex Menu +// control/visual/editbox.qc + +///////////////// +// Item_EditBox +/// + +void() Item_EditBox_Draw = +{ + local vector lCursor; + local float lAlpha; + + if( !self._target ) + return; + + Raise_DataEvent( self._target, ITEM_DATALINK_GET ); + + if( self._state == ITEM_STATE_NORMAL ) { + Menu_DrawString( self.pos + self.origin, self._target.value, self.fontSize, self.color, self.alphas_x, self.drawFlags_x ); + return; + } + + lCursor_x = self._cursorPos * self.fontSize_x; + lCursor_y = self.fontSize_y; + + if( mod( Timer_Time * 1000, 1000 / ITEM_EDITBOX_CURSOR_FREQ ) > 500 / ITEM_EDITBOX_CURSOR_FREQ ) + lAlpha = 1; + else + lAlpha = 0; + //lAlpha = 1.2 - fabs( 1 + floor( Timer_Time * ITEM_EDITBOX_CURSOR_FREQ / 2 ) * 2 - Timer_Time * ITEM_EDITBOX_CURSOR_FREQ ); + + if( self._state == ITEM_STATE_SELECTED ) { + lCursor_y = lCursor_y - self.sizeCursor_y; + Menu_DrawString( self.pos + self.origin, self._target.value, self.fontSize, self.colorSelected, self.alphas_y, self.drawFlags_y ); + Menu_Fill( self.pos + self.origin + lCursor, self.sizeCursor, self.colorCursor, self.alphasCursor_x * lAlpha, self.drawFlagsCursor_x ); + } else { + lCursor_y = lCursor_y - self.sizeCursorFlash_y; + Menu_DrawString( self.pos + self.origin, self._target.value, self.fontSize, self.colorPressed, self.alphas_z, self.drawFlags_z ); + Menu_Fill( self.pos + self.origin + lCursor, self.sizeCursorFlash, self.colorCursorFlash, self.alphasCursor_y * lAlpha, self.drawFlagsCursor_y ); + } +}; + +void() Item_EditBox_Update = +{ + Item_DataUser_Update(); + + if( self._presstime + ITEM_EDITBOX_FLASHTIME > Timer_Time ) + self._state = ITEM_STATE_PRESSED; + else if( Menu_ActiveItem == self ) + self._state = ITEM_STATE_SELECTED; + else + self._state = ITEM_STATE_NORMAL; + + if( !self._target ) + return; + + // clamp the cursor position if necessary + Raise_DataEvent( self._target, ITEM_DATALINK_GET ); + self._cursorPos = bound( 0, self._cursorPos, strlen( self._target.value ) ); + + // scroll the text if necessary + // save the scrolled position in origin + self.origin_y = 0; + if( ( self._cursorPos + ITEM_EDITBOX_SCROLLDISTANCE > self.size_x / self.fontSize_x ) + && ( self._target.maxValue - ITEM_EDITBOX_SCROLLDISTANCE > self.size_x / self.fontSize_x ) ) + self.origin_x = self.fontSize_x * ( floor( self.size_x / self.fontSize_x ) - self._cursorPos - ITEM_EDITBOX_SCROLLDISTANCE ); + else + self.origin_x = 0; +}; + +void() _IEB_RemoveChar = +{ + local string lTemp; + local string lValue; + + lValue = self._target.value; + // TODO: perhaps use strlen perhaps + // FIXME: FteQCC bug: lTemp = strcat( substring( lValue, 0, self._cursorPos ), substring( lValue, self._cursorPos + 1, 100000 ) ); + lTemp = strcat( substring( lValue, 0, self._cursorPos ) ); + lTemp = strcat( lTemp, substring( lValue, self._cursorPos + 1, 100000 ) ); + String_EntitySet( self._target, value, lTemp ); + Raise_DataEvent( self._target, ITEM_DATALINK_SET ); + + self._presstime = Timer_Time; + Sound_Play( self.soundKey ); +}; + +void( float pAscii ) _IEB_InsertChar = +{ + local string lValue; + local string lTemp; + + lValue = self._target.value; + lTemp = strcat( substring( lValue, 0, self._cursorPos ) , chr( pAscii ) ); + lTemp = strcat( lTemp, substring( lValue, self._cursorPos, 100000 ) ); + // FIXME: FTEQCC bug: lTemp = strcat( substring( lValue, 0, self._cursorPos ) , chr( pAscii ), substring( lValue, self._cursorPos, 100000 ) ); + String_EntitySet( self._target, value, lTemp ); + Raise_DataEvent( self._target, ITEM_DATALINK_SET ); + + self._cursorPos = self._cursorPos + 1; + + self._presstime = Timer_Time; + Sound_Play( self.soundKey ); +}; + +bool( float pKey, float pAscii ) Item_EditBox_Key = +{ + if( !self._target ) + return false; + else if( pKey == K_ENTER ) { + CtCall_Action(); + Sound_Play( self.soundKey ); + return true; + } else if( pKey == K_LEFTARROW ) { + if( self._cursorPos ) + self._cursorPos = self._cursorPos - 1; + Sound_Play( self.soundMove ); + return true; + } else if( pKey == K_RIGHTARROW ) { + if( self._cursorPos < strlen( self._target.value ) ) + self._cursorPos = self._cursorPos + 1; + Sound_Play( self.soundMove ); + return true; + } else if( pKey == K_BACKSPACE ) { + if( self._cursorPos > 0 ) { + self._cursorPos = self._cursorPos - 1; + _IEB_RemoveChar(); + } + return true; + } else if( pKey == K_DEL ) { + if( self._cursorPos < strlen( self._target.value ) ) + _IEB_RemoveChar(); + return true; + } else if( 30 <= pAscii && pAscii <= 126 ) { + _IEB_InsertChar( pAscii ); + return true; + } + return false; +}; + +void( bool pSelect, bool pUser ) Item_EditBox_Select = +{ + CtCall_Select( pSelect, pUser ); + if( pSelect && pUser ) + Sound_Play( self.soundSelected ); +}; + +void() Item_EditBox_Destroy = +{ + CtCall_Destroy(); + Item_DataUser_Destroy(); + + String_EntityFree( self, soundSelected ); + String_EntityFree( self, soundKey ); + String_EntityFree( self, soundMove ); +}; + +void() Item_EditBox_Reinit = +{ + self._cursorPos = 0; + CtCall_Reinit(); +}; + +void() Item_EditBox_Spawn = +{ + Item_DataUser_Init(); + + String_EntityZone( self, soundSelected ); + String_EntityZone( self, soundKey ); + String_EntityZone( self, soundMove ); + + Sound_Precache( self.soundSelected ); + Sound_Precache( self.soundKey ); + Sound_Precache( self.soundMove ); + + if( self.size == '0 0 0' && self._target && self._target.maxValue >= 0 ) { + self.size_x = self.fontSize_x * self._target.maxValue + max( self.sizeCursor_x, self.sizeCursorFlash ); + self.size_y = self.fontSize_y; + } + + self._reinit = Item_EditBox_Reinit; + self._destroy = Item_EditBox_Destroy; + self._key = Item_EditBox_Key; + self._draw = Item_EditBox_Draw; + self._select = Item_EditBox_Select; + self._update = Item_EditBox_Update; + + CtCall_Init(); +}; diff --git a/scmenu/source/control/visual/floating.qc b/scmenu/source/control/visual/floating.qc new file mode 100644 index 000000000..89ba9fb4e --- /dev/null +++ b/scmenu/source/control/visual/floating.qc @@ -0,0 +1,54 @@ +// DP/Nex Menu +// control/visual/floating.qc + +bool( float pKey, float pAscii ) Item_FloatingArea_Key = +{ + if( pKey == K_MOUSE1 || pKey == K_ENTER ) { + if( self._state != ITEM_STATE_PRESSED ) + self._state = ITEM_STATE_PRESSED; + else + self._state = ITEM_STATE_NORMAL; + + return true; + } else if( pKey == K_ESCAPE ) + self._state = ITEM_STATE_NORMAL; + + return false; +}; + +void() Item_FloatingArea_Update = +{ + if( !self.target ) { + self._state = ITEM_STATE_NORMAL; + return; + } else if( self.target != self._target.name ) + self._target = Menu_GetItem( self.target ); + + if( self._state == ITEM_STATE_PRESSED ) + self._target.pos = self._target.pos + Cursor_Relative; + else if( Menu_ActiveItem == self ) + self._state = ITEM_STATE_SELECTED; +}; + +void() Item_FloatingArea_Destroy = +{ + String_EntityFree( self, target ); +}; + +void( bool pSelect, bool pUser ) Item_FloatingArea_Select = +{ + if( !pSelect && self._state == ITEM_STATE_PRESSED ) + Menu_Select( self, false ); +}; + +void() Item_FloatingArea_Spawn = +{ + self.flag = self.flag | FLAG_CHILDDRAWUPDATEONLY; + + String_EntityZone( self, target ); + + self._update = Item_FloatingArea_Update; + self._key = Item_FloatingArea_Key; + self._destroy = Item_FloatingArea_Destroy; + self._select = Item_FloatingArea_Select; +}; diff --git a/scmenu/source/control/visual/label.qc b/scmenu/source/control/visual/label.qc new file mode 100644 index 000000000..e5c5cb07b --- /dev/null +++ b/scmenu/source/control/visual/label.qc @@ -0,0 +1,64 @@ +// DP/Nex Menu +// control/visual/label.qc + +////////////// +// Item_Label +/// + +void() _IL_Calc = +{ + // calculate the size if necessary + if( self.size == '0 0 0' ) { + self.size_x = self.fontSize_x * strlen( self.text ); + self.size_y = self.fontSize_y; + } else if( self.fontSize == '0 0 0' ) { + self.fontSize_x = self.size_x / strlen( self.text ); + self.fontSize_y = self.size_y; + } +}; + +void() Item_Label_Update = +{ + _IL_Calc(); +}; + +void() Item_Label_Draw = +{ + local vector lAligned; + // do we need to align the text? + if( self.alignment == ITEM_ALIGN_LEFT ) + lAligned_x = self.pos_x; + else if( self.alignment & ITEM_ALIGN_CENTER ) + lAligned_x = self.pos_x + (self.size_x - strlen( self.text ) * self.fontSize_x) / 2; + else if( self.alignment & ITEM_ALIGN_RIGHT ) + lAligned_x = self.pos_x + self.size_x - strlen( self.text ) * self.fontSize_x; + else + lAligned_x = self.pos_x; + lAligned_y = self.pos_y; + + Menu_DrawString( lAligned, self.text, self.fontSize, self.color, self.alpha, self.drawFlag ); +}; + +void() Item_Label_Destroy = +{ + String_EntityFree( self, text ); +}; + +void() Item_Label_Spawn = +{ + if( self.flag == 0 ) + self.flag = self.flag | FLAG_DRAWUPDATEONLY; + + String_EntityZone( self, text ); + + _IL_Calc(); + + if( self.alignment & ITEM_ALIGN_FIX_CENTER ) + self.pos_x = self.pos_x - self.size_x / 2; + else if( self.alignment & ITEM_ALIGN_FIX_LEFT ) + self.pos_x = self.pos_x - self.size_x; + + self._destroy = Item_Label_Destroy; + self._draw = Item_Label_Draw; + self._update = Item_Label_Update; +}; diff --git a/scmenu/source/control/visual/multilabel.qc b/scmenu/source/control/visual/multilabel.qc new file mode 100644 index 000000000..45791b9a8 --- /dev/null +++ b/scmenu/source/control/visual/multilabel.qc @@ -0,0 +1,110 @@ +// DP/Nex Menu +// control/visual/multilabel.qc + +/* +=================== +_IML_Calc +=================== +*/ +void() _IML_Calc = +{ + local float lMaxWidth; + local float lLineNumber; + local vector lLine; + + lMaxWidth = 0; + lLineNumber = 0; + lLine = '0 0 0'; + do { + if( self.wrap ) + lLine = Util_GetEndOfWrappedLine( self.text, lLine, self.wrap ); + else + lLine = Util_GetEndOfLine( self.text, lLine ); + + ++lLineNumber; + lMaxWidth = max( lMaxWidth, lLine_z ); + } while( lLine_x != lLine_y ); + + self.size_x = lMaxWidth * self.fontSize_x; + self.size_y = lLineNumber * self.fontSize_y; +}; + +/* +=================== +_IML_DrawLine +=================== +*/ +void( vector pPosition, string pText ) _IML_DrawLine = +{ + if( self.alignment == ITEM_ALIGN_CENTER ) + pPosition_x = self.pos_x + (self.size_x - strlen( pText ) * self.fontSize_x) / 2; + else if( self.alignment == ITEM_ALIGN_RIGHT ) + pPosition_x = self.pos_x + self.size_x - strlen( pText ) * self.fontSize_x; + else + pPosition_x = self.pos_x; + + Menu_DrawString( pPosition, pText, self.fontSize, self.color, self.alpha, self.drawFlag ); +}; + +/* +=================== +Item_MultiLable_Draw +=================== +*/ +void() Item_MultiLabel_Draw = +{ + local vector lPosition; + local vector lLine; + + lPosition_y = self.pos_y; + lLine = '0 0 0'; + do { + if( self.wrap ) + lLine = Util_GetEndOfWrappedLine( self.text, lLine, self.wrap ); + else + lLine = Util_GetEndOfLine( self.text, lLine ); + + _IML_DrawLine( lPosition, substring( self.text, lLine_x - lLine_z + 1, lLine_z ) ); + lPosition_y = lPosition_y + self.fontSize_y; + } while( lLine_x != lLine_y ); +}; + +/* +=================== +Item_MultiLabel_Update +=================== +*/ +void() Item_MultiLabel_Update = +{ + if( self.size == '0 0 0' ) + _IML_Calc(); +}; + +/* +=================== +Item_MultiLabel_Destroy +=================== +*/ +void() Item_MultiLabel_Destroy = +{ + String_EntityFree( self, text ); +}; + +/* +=================== +Item_MultiLabel_Spawn +=================== +*/ +void() Item_MultiLabel_Spawn = +{ + if( self.flag == 0 ) + self.flag = self.flag | FLAG_DRAWUPDATEONLY; + + String_EntityZone( self, text ); + + Item_MultiLabel_Update(); + + self._destroy = Item_MultiLabel_Destroy; + self._draw = Item_MultiLabel_Draw; + self._update = Item_MultiLabel_Update; +}; diff --git a/scmenu/source/control/visual/picture.qc b/scmenu/source/control/visual/picture.qc new file mode 100644 index 000000000..b0beca409 --- /dev/null +++ b/scmenu/source/control/visual/picture.qc @@ -0,0 +1,36 @@ +// DP/Nex Menu +// control/visual/picture.qc + +///////////////// +// Item_Picture +/// + +void() Item_Picture_Draw = +{ + Menu_DrawPicture( self.pos, self.picture, self.size, self.color, self.alpha, self.drawFlag ); +}; + +void() Item_Picture_Destroy = +{ + String_EntityFree( self, picture ); +}; + +void() Item_Picture_Spawn = +{ + // this items needs a picture field + if( !self.picture ) { + Menu_DeleteAfterFrame( self ); + return; + } + + String_EntityZone( self, picture ); + + // load the picture if it isnt loaded already + Gfx_Precache( self.picture ); + + if( self.flag == 0 ) + self.flag = self.flag | FLAG_NOSELECT; + + self._destroy = Item_Picture_Destroy; + self._draw = Item_Picture_Draw; +}; diff --git a/scmenu/source/control/visual/rect.qc b/scmenu/source/control/visual/rect.qc new file mode 100644 index 000000000..0b2785366 --- /dev/null +++ b/scmenu/source/control/visual/rect.qc @@ -0,0 +1,18 @@ +// DP/Nex Menu +// control/visual/rect.qc + +/////////////// +// Item_Rect +/// + +void() Item_Rect_Draw = +{ + Menu_Fill( self.pos, self.size, self.color, self.alpha, self.drawFlag ); +}; + +void() Item_Rect_Spawn = +{ + self.flag = self.flag | FLAG_NOSELECT; + + self._draw = Item_Rect_Draw; +}; diff --git a/scmenu/source/control/visual/scrollbar.qc b/scmenu/source/control/visual/scrollbar.qc new file mode 100644 index 000000000..220f244bd --- /dev/null +++ b/scmenu/source/control/visual/scrollbar.qc @@ -0,0 +1,8 @@ +// DP/Nex Menu +// control/visual/scrollbar.qc + +bool() Item_HScrollBar_Key + +void() Item_HScrollBar_Spawn = +{ +}; diff --git a/scmenu/source/control/visual/slider.qc b/scmenu/source/control/visual/slider.qc new file mode 100644 index 000000000..02063f6a4 --- /dev/null +++ b/scmenu/source/control/visual/slider.qc @@ -0,0 +1,146 @@ +// DP/Nex Menu +// control/visual/slider.qc + +//////////////// +// Item_Slider +/// + +// returns a value in the range of 0..1 +float() _IS_GetValue = +{ + local float lValue; + local entity lLink; + + if( !self._target ) + return 0; + + lLink = self._target; + + Raise_DataEvent( lLink, ITEM_DATALINK_GET ); + + if( lLink.maxValue <= lLink.minValue ) + lValue = 0; + else + lValue = ( lLink._realValue - lLink.minValue ) / (lLink.maxValue - lLink.minValue); + return lValue; +}; + +void( bool pSelect, bool pUser ) Item_Slider_Select = +{ + if( pSelect & pUser ) + Sound_Play( self.soundSelected ); +}; + +void() Item_Slider_Draw = +{ + local float lValue; + local vector lSliderPos; + + lValue = _IS_GetValue(); + lSliderPos_x = self.pos_x + self.size_x * (self.proportions_x + lValue * self.proportions_y) - lValue * self.sizeSlider_x; + lSliderPos_y = self.pos_y + (self.size_y - self.sizeSlider_y) * (1 - (self.direction_y - self.direction_x) * lValue - self.direction_x); + + if( Menu_ActiveItem == self ) { + Menu_DrawPicture( self.pos, self.picture, self.size, self.colorSelected, self.alphas_y, self.drawFlags_y ); + Menu_DrawPicture( lSliderPos, self.pictureSlider, self.sizeSlider, self.colorSelected, self.alphas_y, self.drawFlags_y ); + } else { + Menu_DrawPicture( self.pos, self.picture, self.size, self.color, self.alphas_x, self.drawFlags_x ); + Menu_DrawPicture( lSliderPos, self.pictureSlider, self.sizeSlider, self.color, self.alphas_x, self.drawFlags_x ); + } +}; + +void( float pValue ) _IS_Change = +{ + if( pValue < 0 ) + Sound_Play( self.soundDecrease ); + else + Sound_Play( self.soundIncrease ); + + self._target._realValue = self._target._realValue + pValue; + // FIXME: self._target.realValue += pValue; FTEQCC BUG + Raise_DataEvent( self._target, ITEM_DATALINK_SET ); + + CtCall_Action(); +}; + +bool( float pKey, float pAscii ) Item_Slider_Key = +{ + if( !self._target ) + return false; + + switch( pKey ) { + case K_LEFTARROW: + _IS_Change( 0 - self._target.stepValue ); + return true; + break; + case K_RIGHTARROW: + _IS_Change( self._target.stepValue ); + return true; + break; + case K_MOUSE1: { + local float lPos; + + // test if it is within the slider area at all + // TODO: Check if this is necessary with the future composition implementations + if( !Util_InRect( Menu_Cursor_Position, self.pos, self.size ) ) + return false; + lPos = ( Menu_Cursor_Position_x - self.pos_x ) / self.size_x; + if( lPos <= self.proportions_x ) + _IS_Change( 0 - self._target.stepValue ); + else if( lPos <= self.proportions_x + self.proportions_y && self.proportions_y ) { + local float lValue; + + lValue = Menu_Cursor_Position_x - self.pos_x - self.sizeSlider_x / 2 - self.size_x * self.proportions_x; + lValue = lValue / (self.size_x * self.proportions_y - self.sizeSlider_x); + lValue = lValue * ( self._target.maxValue - self._target.minValue ) + self._target.minValue; + _IS_Change( lValue - self._target._realValue ); + } else + _IS_Change( self._target.stepValue ); + return true; + } + } + return false; +}; + +void() Item_Slider_Destroy = +{ + CtCall_Destroy(); + + Item_DataUser_Destroy(); + + String_EntityFree( self, picture ); + String_EntityFree( self, pictureSlider ); + String_EntityFree( self, soundSelected ); + String_EntityFree( self, soundIncrease ); + String_EntityFree( self, soundDecrease ); +}; + +void() Item_Slider_Spawn = +{ + String_EntityZone( self, picture ); + String_EntityZone( self, pictureSlider ); + String_EntityZone( self, soundSelected ); + String_EntityZone( self, soundIncrease ); + String_EntityZone( self, soundDecrease ); + Item_DataUser_Init(); + + Gfx_Precache( self.picture ); + Gfx_Precache( self.pictureSlider ); + Sound_Precache( self.soundSelected ); + Sound_Precache( self.soundIncrease ); + Sound_Precache( self.soundDecrease ); + + if( self.size == '0 0 0' ) + self.size = Gfx_GetImageSize( self.picture ); + if( self.sizeSlider == '0 0 0' ) + self.sizeSlider = Gfx_GetImageSize( self.pictureSlider ); + + self._reinit = CtCall_Reinit; + self._destroy = Item_Slider_Destroy; + self._key = Item_Slider_Key; + self._draw = Item_Slider_Draw; + self._select = Item_Slider_Select; + self._update = Item_DataUser_Update; + + CtCall_Init(); +}; diff --git a/scmenu/source/control/visual/switchbutton.qc b/scmenu/source/control/visual/switchbutton.qc new file mode 100644 index 000000000..db7792f35 --- /dev/null +++ b/scmenu/source/control/visual/switchbutton.qc @@ -0,0 +1,42 @@ +// DP/Nex Menu +// control/visual/switchbutton.qc + +bool( float pKey, float pAscii ) Item_SwitchButton_Key = +{ + if( !self._target ) + return false; + + if( pKey == K_SPACE || pKey == K_ENTER || pKey == K_MOUSE1 || pKey == K_RIGHTARROW ) { + Sound_Play( self.soundPressed ); + self._presstime = Timer_Time; + + self._target._realValue = self._target._realValue + 1; + if( self._target._realValue > self._target.maxValue ) + self._target._realValue = self._target.minValue; + Raise_DataEvent( self._target, ITEM_DATALINK_SET ); + + CtCall_Action(); + return true; + } else if( pKey == K_BACKSPACE || pKey == K_MOUSE2 || pKey == K_LEFTARROW ) { + Sound_Play( self.soundPressed ); + self._presstime = Timer_Time; + + self._target._realValue = self._target._realValue - 1; + if( self._target._realValue < self._target.minValue ) + self._target._realValue = self._target.maxValue; + + Raise_DataEvent( self._target, ITEM_DATALINK_SET ); + + CtCall_Action(); + return true; + } + + return false; +}; + +void() Item_SwitchButton_Spawn = +{ + Item_ValueButton_Spawn(); + + self._key = Item_SwitchButton_Key; +}; diff --git a/scmenu/source/control/visual/valuebutton.qc b/scmenu/source/control/visual/valuebutton.qc new file mode 100644 index 000000000..53a2e22c7 --- /dev/null +++ b/scmenu/source/control/visual/valuebutton.qc @@ -0,0 +1,31 @@ +// DP/Nex Menu +// control/visual/valuebutton.qc + +///////////////////// +// Item_ValueButton +/// + +void() Item_ValueButton_Update = +{ + Item_DataUser_Update(); + + Raise_DataEvent( self._target, ITEM_DATALINK_GET ); + String_EntitySet( self, normal, self._target.value ); + self.size = '0 0 0'; // FIXME: Do we really want this/need this? + Item_Button_Update(); +}; + +void() Item_ValueButton_Destroy = +{ + Item_DataUser_Destroy(); + Item_Button_Destroy(); +}; + +void() Item_ValueButton_Spawn = +{ + Item_DataUser_Init(); + Item_Button_Spawn(); + + self._destroy = Item_ValueButton_Destroy; + self._update = Item_ValueButton_Update; +}; diff --git a/scmenu/source/control/visual/visual.qh b/scmenu/source/control/visual/visual.qh new file mode 100644 index 000000000..c5708460c --- /dev/null +++ b/scmenu/source/control/visual/visual.qh @@ -0,0 +1,183 @@ +// DP/Nex Menu +// control/visual/visual.qh + +// Item states +enum { + ITEM_STATE_NORMAL, + ITEM_STATE_SELECTED, + ITEM_STATE_PRESSED +}; + +// Item_Picture +.string picture; +.vector color; +.float alpha; +.float drawFlag; + +void() Item_Picture_Draw; +void() Item_Picture_Destroy; +void() Item_Picture_Spawn; + +// Item_Rect +.vector color; +.float alpha; +.float drawFlag; + +void() Item_Rect_Draw; +void() Item_Rect_Spawn; + +// Item_Label +.vector color; +.float alpha; +.float drawFlag; +.string text; +.vector fontSize; +.float alignment; + +void() Item_Label_Draw; +void() Item_Label_Update; +void() Item_Label_Destroy; +void() Item_Label_Spawn; + +// Item_MultiLabel implements Item_Label +// multiline label +.vector color; +.float alpha; +.float drawFlag; +.string text; +.vector fontSize; +.float alignment; +.float wrap; // 0 for no wrapping + +void() Item_MultiLabel_Update; +void() Item_MultiLabel_Draw; +void() Item_MultiLabel_Destroy; +void() Item_MultiLabel_Spawn; + +// Item_Button [Item_Link] +// add $ to the text if you want to use pictures +// e.g. $gfx/menu_newgame +// if selected is "" then it falls back to normal +// if pressed is "" then it falls back to selected or normal (see above) +.vector fontSize; +.string normal; +.string selected; +.string pressed; +.vector colorSelected; +.vector colorPressed; +.vector drawFlags; // x = normal; y = selected; z = pressed +.vector alphas; +.string soundSelected; +.string soundPressed; +.float _presstime; +.float _state; + +// cevents supported by Item_Button +.event init; +.event reinit; +.event destroy; +.event action; + +void() Item_Button_Draw; +void() Item_Button_Update; +void( bool pSelect, bool pUser ) Item_Button_Select; +bool( float pKey, float pAscii ) Item_Button_Key; +void() Item_Button_Destroy; +void() Item_Button_Spawn; + +// Item_Slider [Item_DataUser] +// Item_Slider changes link's value when the slider is moved +// the slider is x-centered but not y +.vector proportions; // x is left margin, y is slider width and z is right margin (sum should be 1) +.string picture; // picture of the background +.string pictureSlider; // picture of the slider +.string soundSelected; +.string soundIncrease; +.string soundDecrease; +.vector sizeSlider; // size of the slider +.vector direction; // y values of the slider: _x for the start and _y for the end (as percentages of size_y) +// only has normal and selected +.vector color; +.vector colorSelected; +.vector drawFlags; +.vector alphas; + +// cevents supported by Item_Slider +.event init; +.event reinit; +.event action; // called when the slider is changed +.event destroy; + +void( bool pSelect, bool pUser ) Item_Slider_Select; +void() Item_Slider_Draw; +bool( float pKey, float pAscii ) Item_Slider_Key; +void() Item_Slider_Destroy; +void() Item_Slider_Spawn; + +// Item_EditBox [Item_DataUser] +.vector color; +.vector colorSelected; +.vector colorPressed; +.vector alphas; +.vector drawFlags; + +.vector colorCursor; +.vector colorCursorFlash; +.vector sizeCursor; +.vector sizeCursorFlash; +.vector alphasCursor; +.vector drawFlagsCursor; + +.string soundSelected; +.string soundKey; +.string soundMove; + +.float _presstime; +.float _state; +.float _cursorPos; + +// cevents supported by Item_EditBox +.event init; +.event reinit; +.event action; // called when the return key is pressed +.event destroy; +.selectEvent select; + +void() Item_EditBox_Draw; +void() Item_EditBox_Update; +bool( float pKey, float pAscii ) Item_EditBox_Key; +void( bool pSelect, bool pUser ) Item_EditBox_Select; +void() Item_EditBox_Destroy; +void() Item_EditBox_Reinit; +void() Item_EditBox_Spawn; + +// Item_ValueButton [Item_Button] [Item_DataUser] FIXME: actually this is bad practice + +void() Item_ValueButton_Update; +void() Item_ValueButton_Destroy; +void() Item_ValueButton_Spawn; + +// Item_SwitchButton Item_ValueButton +bool( float pKey, float pAscii ) Item_SwitchButton_Key; +void() Item_SwitchButton_Spawn; + +// Item_FloatingArea +// When you click on the area, the target will move with the mouse cursor until you click again +.float _state; +.string target; +.entity _target; +bool( float pKey, float pAscii ) Item_FloatingArea_Key; +void() Item_FloatingArea_Update; +void() Item_FloatingArea_Spawn; +/* +// Item_HScrollBar +// target should point to a ScrollWindow +.float minValue; +.float maxValue; +.vector current; +.string target; +.entity _target; +// TODO: Add pictureSlider support + +void() Item_HScrollBar_Spawn;*/ + diff --git a/scmenu/source/control/window/arrangement.qc b/scmenu/source/control/window/arrangement.qc new file mode 100644 index 000000000..3143ce510 --- /dev/null +++ b/scmenu/source/control/window/arrangement.qc @@ -0,0 +1,76 @@ +// DP/Nex Menu +// control/window/composition.qc + +/* +=================== +Item_Arrangement_CalculateSize +=================== +*/ +void() Item_Arrangement_CalculateSize = +{ + local vector lMin; + local vector lMax; + local entity lChild; + + // TODO: this is garbage, fix this + lMax = '0 0 0'; + lMin_x = INFINITY; + lMin_y = INFINITY; + for( lChild = self._child ; lChild ; lChild = lChild._next ) { + if( Menu_HasRunFlag( lChild, RUNFLAG_HIDDEN ) ) + continue; + + lMin_x = min( lMin_x, lChild.pos_x ); + lMin_y = min( lMin_y, lChild.pos_y ); + lMax_x = max( lMax_x, lChild.pos_x + lChild.size_x ); + lMax_y = max( lMax_y, lChild.pos_y + lChild.size_y ); + } + self.size = lMax - lMin; +}; + +/* +=================== +Item_Arrangement_Update +=================== +*/ +void() Item_Arrangement_Update = +{ + Item_Layout_Update(); + + Item_Arrangement_CalculateSize(); + + if( self.direction_x ) { + if( self.alignment == ITEM_ALIGN_LEFT ) + self.origin_y = 0; + else if( self.alignment == ITEM_ALIGN_CENTER ) + self.origin_y = self.size_y / 2; + else + self.origin_y = self.size_y; + } else + self.origin_y = 0; + if( self.direction_y ) { + if( self.alignment == ITEM_ALIGN_LEFT ) + self.origin_x = 0; + else if( self.alignment == ITEM_ALIGN_CENTER ) + self.origin_x = self.size_x / 2; + else + self.origin_x = self.size_x; + } else + self.origin_x = 0; +}; + +/* +=================== +Item_Arrangement_Spawn +=================== +*/ +void() Item_Arrangement_Spawn = +{ + Item_Layout_Spawn(); + + Item_Arrangement_Update(); + + self._update = Item_Arrangement_Update; +}; + + diff --git a/scmenu/source/control/window/eventwindow.qc b/scmenu/source/control/window/eventwindow.qc new file mode 100644 index 000000000..df2b87753 --- /dev/null +++ b/scmenu/source/control/window/eventwindow.qc @@ -0,0 +1,13 @@ +// DP/Nex Menu +// control/window/eventwindow.qc + +void() Item_EventWindow_Spawn = +{ + Item_Window_Spawn(); + + self._destroy = CtCall_Destroy; + self._reinit = CtCall_Reinit; + self._update = CtCall_Update; + + CtCall_Init(); +}; diff --git a/scmenu/source/control/window/frame.qc b/scmenu/source/control/window/frame.qc new file mode 100644 index 000000000..9b3dac31a --- /dev/null +++ b/scmenu/source/control/window/frame.qc @@ -0,0 +1,9 @@ +// DP/Nex Menu +// control/window/frame.qc + +void() Item_Frame_Spawn = +{ + Item_Window_Spawn(); + + self.flag = self.flag - FLAG_NOSELECT; +}; diff --git a/scmenu/source/control/window/layout.qc b/scmenu/source/control/window/layout.qc new file mode 100644 index 000000000..04dcfec3c --- /dev/null +++ b/scmenu/source/control/window/layout.qc @@ -0,0 +1,66 @@ +// DP/Nex Menu +// control/window/layout.qc + +//////////////// +// Item_Layout +/// + +/* +=================== +Item_Layout_Update +=================== +*/ +void() Item_Layout_Update = +{ + local entity lChild; + local vector lCurrent; + + lCurrent = '0.0 0.0 0.0'; + for( lChild = self._child ; lChild ; lChild = lChild._next ) { + if( Menu_HasRunFlag( lChild, RUNFLAG_HIDDEN ) ) + continue; + + if( self.direction_y ) { + if( self.alignment == ITEM_ALIGN_FIRST && lChild._child ) + lChild.pos_x = lCurrent_x - lChild._child.size_x; + else if( self.alignment == ITEM_ALIGN_LEFT ) + lChild.pos_x = lCurrent_x; + else if( self.alignment == ITEM_ALIGN_CENTER ) + lChild.pos_x = lCurrent_x - lChild.size_x / 2; + else + lChild.pos_x = lCurrent_x - lChild.size_x; + } else + lChild.pos_x = lCurrent_x; + + if( self.direction_x ) { + if( self.alignment == ITEM_ALIGN_LEFT ) + lChild.pos_y = lCurrent_y; + else if( self.alignment == ITEM_ALIGN_CENTER ) + lChild.pos_y = lCurrent_y - lChild.size_y / 2; + else if( self.alignment == ITEM_ALIGN_FIRST && lChild._child ) + lChild.pos_y = lCurrent_y - lChild._child.size_y; + else + lChild.pos_y = lCurrent_y - lChild.size_y; + } else + lChild.pos_y = lCurrent_y; + + if( self.direction_x ) + lCurrent_x += lChild.size_x + self.direction_x; + else if( self.direction_y ) + lCurrent_y += lChild.size_y + self.direction_y; + } +}; + +/* +=================== +Item_Layout_Spawn +=================== +*/ +void() Item_Layout_Spawn = +{ + Item_Window_Spawn(); + + Item_Layout_Update(); + + self._update = Item_Layout_Update; +}; diff --git a/scmenu/source/control/window/reference.qc b/scmenu/source/control/window/reference.qc new file mode 100644 index 000000000..d33a1baa2 --- /dev/null +++ b/scmenu/source/control/window/reference.qc @@ -0,0 +1,68 @@ +// DP/Nex Menu +// control/window/reference.qc + +////////////////// +// Item_Reference +/// +// NOTE: You use have multiple links to the same window, only one should be visible per frame, +// NOTE: else the behavior would be unexpectable +// NOTE: FIXME: Atm only references to windows with no parents( thus top layer ) work + +/* +=================== +Item_Reference_Update +=================== +*/ +void() Item_Reference_Update = +{ + // update the link and the link's parent + if( self.link == "" ) { + self._child = null_entity; + return; + } + + if( self.link != self._link.name ) + self._link = Menu_GetItem( self.link ); + + self._child = self._link; + self._child._parent = self; +}; + +/* +=================== +Item_Reference_Draw +=================== +*/ +void() Item_Reference_Draw = +{ + if( sys_debug_ref ) + Menu_Fill( self.pos, self.size, '0 0 0.2', 1.0, DRAWFLAG_ADDITIVE ); +}; + +/* +=================== +Item_Reference_Destroy +=================== +*/ +void() Item_Reference_Destroy = +{ + String_EntityFree( self, link ); +}; + +/* +=================== +Item_Reference_Spawn +=================== +*/ +void() Item_Reference_Spawn = +{ + self.flag = self.flag | FLAG_NOSELECT | FLAG_EMBEDDED; + + String_EntityZone( self, link ); + + Item_Reference_Update(); + + self._destroy = Item_Reference_Destroy; + self._draw = Item_Reference_Draw; + self._update = Item_Reference_Update; +}; diff --git a/scmenu/source/control/window/scroll.qc b/scmenu/source/control/window/scroll.qc new file mode 100644 index 000000000..8f81190d7 --- /dev/null +++ b/scmenu/source/control/window/scroll.qc @@ -0,0 +1,46 @@ +// DP/Nex Menu +// control/window/scroll.qc + +void() Item_ScrollWindow_Update = +{ + local float lLevel; + local float lOldLevel; + local entity lParent; + + if( !Menu_IsVisible( self ) || !_Menu_IsEmbeddedParentOf( Menu_ActiveItem, self._child ) ) + return; + + // find the lLevel + lLevel = Menu_ActiveItem.pos_y; + for( lParent = Menu_ActiveItem._parent; lParent != self ; lParent = lParent._parent ) + lLevel += lParent.origin_y + lParent.pos_y; + + // self.origin_y is negative to move everything up, -self.origin_y is the level + lOldLevel = -self.origin_y; + if( ( Menu_ActiveItem.size_y > self.size_y && lLevel + Menu_ActiveItem.size_y > lOldLevel && lLevel < self.size_y + lOldLevel ) + || ( lLevel >= lOldLevel && lLevel + Menu_ActiveItem.size_y < lOldLevel + self.size_y ) ) + return; + // adapt the origin + // TODO: make this a bit more flexible + if( lOldLevel < lLevel ) + self.origin_y = self.direction_x - lLevel; + else + self.origin_y = self.size_y - self.direction_x - lLevel; + + // now limit it + self.origin_y = bound( self.size_y - self._child.size_y, self.origin_y, 0 ); + //print( ftos( self.origin_y ), "\n" ); +}; + +void() Item_ScrollWindow_Reinit = +{ + self.origin_y = 0; +}; + +void() Item_ScrollWindow_Spawn = +{ + Item_Window_Spawn(); + + self._update = Item_ScrollWindow_Update; + self._reinit = Item_ScrollWindow_Reinit; +}; diff --git a/scmenu/source/control/window/window.qc b/scmenu/source/control/window/window.qc new file mode 100644 index 000000000..b90f88e38 --- /dev/null +++ b/scmenu/source/control/window/window.qc @@ -0,0 +1,58 @@ +// DP/Nex Menu +// control/window/normal.qc + +//////////////// +// Item_Window +/// + +/* +=================== +Item_Window_Key +=================== +*/ +bool( float pKey, float pAscii ) Item_Window_Key = +{ + if( CtCall_Key( pKey, pAscii ) ) + return true; + + return false; +}; + +void() Item_Window_Draw = +{ + if( !sys_debug) + return; + if( Menu_HasRunFlag( self, RUNFLAG_MOUSEINAREA ) ) { + if( sys_debug_area ) { + local entity lChild; + Menu_Fill( self.pos, self.size, '0.2 0 0', 0.2, DRAWFLAG_NORMAL ); + + for( lChild = self._child ; lChild ; lChild = lChild._next ) { + local vector lColor; + + if( !Menu_IsVisible( lChild ) ) + continue; + + lColor_x = mod( fabs( lChild.orderPos ) + 5, 9 ) / 8; + lColor_y = mod( fabs( lChild.orderPos * 8 ), 9 ) / 8; + lColor_z = mod( fabs( lChild.orderPos * 7 ), 9 ) / 8; + Menu_Fill( self.pos + self.origin + lChild.pos, lChild.size, lColor, 0.2, DRAWFLAG_NORMAL ); + } + } + if( sys_debug_mouse ) + sys_debug_cursor_localpos = Menu_Cursor_Position - self.origin - self.pos; + } +}; + +/* +=================== +Item_Window_Spawn +=================== +*/ +void() Item_Window_Spawn = +{ + self.flag = self.flag | FLAG_NOSELECT; + + self._key = Item_Window_Key; + self._draw = Item_Window_Draw; +}; diff --git a/scmenu/source/control/window/windows.qh b/scmenu/source/control/window/windows.qh new file mode 100644 index 000000000..de8217df7 --- /dev/null +++ b/scmenu/source/control/window/windows.qh @@ -0,0 +1,51 @@ +// DP/Nex Menu +// control/window/windows.qh + +// Item_Window +.keyEvent key; + +bool( float pKey, float pAscii ) Item_Window_Key; +void() Item_Window_Draw; +void() Item_Window_Spawn; + +// Item_Frame Item_Window +void() Item_Frame_Spawn; + +// Item_EventWindow Item_Window +// has a few events +.keyEvent key; +.event init; +.event reinit; +.event destroy; +.event update; + +void() Item_EventWindow_Spawn; + +// Item_Reference [Item] +.string link; // window link + +void() Item_Reference_Update; +void() Item_Reference_Draw; +void() Item_Reference_Destroy; +void() Item_Reference_Spawn; + +// Item_Layout Item_Window +.vector direction; // space between the items +.float alignment; + +void() Item_Layout_Spawn; +void() Item_Layout_Update; + +// Item_Arrangement Item_Layout + +void() Item_Arrangement_CalculateSize; +void() Item_Arrangement_Update; +void() Item_Arrangement_Spawn; + +// Item_ScrollWindow Item_Window +// It will adapt its origin to always make the currently selected item visible +// There always has to be only *one* child window, that has a valid size +.vector direction; // first is space between frame and item + +void() Item_ScrollWindow_Update; +void() Item_ScrollWindow_Spawn; diff --git a/scmenu/source/custom/color.qm b/scmenu/source/custom/color.qm new file mode 100644 index 000000000..11b6f6902 --- /dev/null +++ b/scmenu/source/custom/color.qm @@ -0,0 +1,46 @@ +// Property of Alientrap/AK +// custom/color.qm + +void() Nex_Action_Color_Cancel = +{ +#define ConCat(A,B) #A#B +#define Reset(pName) Raise_DataEvent(Menu_GetItem(ConCat("::Data::Color::",#pName)), ITEM_DATA_TEST_END) + Reset( "Brightness" ); + Reset( "Contrast" ); + Reset( "Gamma" ); + Reset( "HWGamma" ); + Reset( "Extended::Active" ); + Reset( "Extended::Low::Red" ); + Reset( "Extended::Low::Green" ); + Reset( "Extended::Low::Blue" ); + Reset( "Extended::Mid::Red" ); + Reset( "Extended::Mid::Green" ); + Reset( "Extended::Mid::Blue" ); + Reset( "Extended::High::Red" ); + Reset( "Extended::High::Green" ); + Reset( "Extended::High::Blue" ); +#undef ConCat +#undef Reset +}; + +void() Nex_Action_Color_Reset = +{ +#define ConCat(A,B) #A#B +#define Reset(pName) Raise_DataEvent(Menu_GetItem(ConCat("::Data::Color::",#pName)), ITEM_DATA_RESET) + Reset( "Brightness" ); + Reset( "Contrast" ); + Reset( "Gamma" ); + Reset( "HWGamma" ); + Reset( "Extended::Active" ); + Reset( "Extended::Low::Red" ); + Reset( "Extended::Low::Green" ); + Reset( "Extended::Low::Blue" ); + Reset( "Extended::Mid::Red" ); + Reset( "Extended::Mid::Green" ); + Reset( "Extended::Mid::Blue" ); + Reset( "Extended::High::Red" ); + Reset( "Extended::High::Green" ); + Reset( "Extended::High::Blue" ); +#undef ConCat +#undef Reset +}; diff --git a/scmenu/source/custom/creategame.qm b/scmenu/source/custom/creategame.qm new file mode 100644 index 000000000..6b97e59ab --- /dev/null +++ b/scmenu/source/custom/creategame.qm @@ -0,0 +1,86 @@ +// Property of Alientrap +// custom/creategame.qm + +// uses target and _target +// requires neighbors: Picture, Name, Description +void() Nex_Automation_UpdateMap_Update = +{ + local entity lItem; + local entity lTarget; + + if( self._target.name != "Data::CreateGame::Map" ) + self._target = Menu_GetItem( "Data::CreateGame::Map" ); + + lTarget = self._target; + + lItem = Menu_GetItem( "Picture" ); + String_EntitySet( lItem, picture, lTarget._link.picture ); + + lItem = Menu_GetItem( "Name" ); + String_EntitySet( lItem, text, lTarget._link.normal ); + + lItem = Menu_GetItem( "Description" ); + String_EntitySet( lItem, text, lTarget._link.text ); +}; + +void() Nex_Automation_UpdateMap_Destroy = +{ + String_EntityFree( self, target ); +}; + +void() Nex_Automation_UpdateMap = +{ + String_EntityZone( self, target ); + + self._update = Nex_Automation_UpdateMap_Update; + self._destroy = Nex_Automation_UpdateMap_Destroy; +}; + +// more concrete functions +void() Nex_Action_Map_Next = +{ + local entity lItem; + + lItem = Menu_GetItem( "Data::CreateGame::Map" ); + lItem._realValue = lItem._realValue + 1; + Raise_DataEvent( lItem, ITEM_DATA_SEND ); +}; + +void() Nex_Action_Map_Prev = +{ + local entity lItem; + + lItem = Menu_GetItem( "Data::CreateGame::Map" ); + lItem._realValue = lItem._realValue - 1; + Raise_DataEvent( lItem, ITEM_DATA_SEND ); +}; + +// TODO: Make MaxPlayers real Data items (no container with correct set behavior) +void() Nex_Action_Map_Start = +{ + local entity lItem; + local float lNumBots, lSkill; + // we need to set the following var + lItem = Menu_GetItem( "::Data::CreateGame::NumBots" ); + lNumBots = stof( lItem.value ); + lItem = Menu_GetItem( "::Data::CreateGame::BotSkill" ); + lSkill = stof( lItem.value ); + + cvar_set( "saved1", "1" ); + cvar_set( "scratch1", ftos( pow( 2, lNumBots ) - 1 ) ); + cvar_set( "scratch2", ftos( lSkill * (pow(4, min(lNumBots, 8)) - 1) / 3) ); + cvar_set( "scratch3", ftos( lSkill * (pow(4, min(lNumBots - 8, 8)) - 1) / 3) ); + // Set maxplayers + lItem = Menu_GetItem( "::Data::CreateGame::MaxPlayers" ); + cmd( "maxplayers \"" ); + cmd( lItem.value ); + cmd( "\"\n" ); + + lItem = Menu_GetItem( "::Data::CreateGame::Map" ); + cmd( "map \"" ); + cmd( lItem._link.link ); + cmd( "\"\n"); + + // force the menu to hide + m_hide(); +}; diff --git a/scmenu/source/custom/creategame/creategame.qh b/scmenu/source/custom/creategame/creategame.qh new file mode 100644 index 000000000..c5231f788 --- /dev/null +++ b/scmenu/source/custom/creategame/creategame.qh @@ -0,0 +1,30 @@ +// Property of Alientrap/AK +// custom/player/avatar.qh + +// Item_Nex_Map_Info +// its a valid item nevertheless +.string normal; // contains the map name +.string picture; // contains the picture that should be displayed +.string text; // contains the description text +.string link; // contains the path to the map + +void() Item_Nex_Map_Info_Destroy; +void() Item_Nex_Map_Info_Spawn; + +// see control/data/data.qh +// Item_Data_Nex_Map Item_DataLink_Value (implements more or less) +// _realValue should be a integer in the range 1..n where n is the number of found maps +.entity _link; + +void( float pEvent ) Item_Data_Nex_Map_DataEvent; +void() Item_Data_Nex_Map_Spawn; + +// see control/data/data.qh +// Item_Data_Nex_Name [Item_Data] +void( float pEvent ) Item_Data_Nex_Name_DataEvent; +void() Item_Data_Nex_Name_Spawn; + +// see control/data/data.qh +// Item_DataLink_Nex_ModSwitch Item_DataLink_TextSwitch + +void() Item_DataLink_Nex_ModSwitch_Spawn; diff --git a/scmenu/source/custom/creategame/maps.qc b/scmenu/source/custom/creategame/maps.qc new file mode 100644 index 000000000..56ccd3b59 --- /dev/null +++ b/scmenu/source/custom/creategame/maps.qc @@ -0,0 +1,193 @@ +// Property of Alientrap/AK +// custom/player/avatar.qm + +/* +=================== +Item_Nex_Map_Info +=================== +*/ + +void() Item_Nex_Map_Info_Destroy = +{ + String_EntityFree( self, link ); + String_EntityFree( self, picture ); + String_EntityFree( self, text ); + String_EntityFree( self, normal ); +}; + +void() Item_Nex_Map_Info_Spawn = +{ + String_EntityZone( self, link ); + String_EntityZone( self, picture ); + String_EntityZone( self, text ); + String_EntityZone( self, normal ); + + Gfx_Precache( self.picture ); + + self._destroy = Item_Nex_Map_Info_Destroy; +}; + +/* +=================== +Item_Data_Nex_Avatar +=================== +*/ + + +// Nex_Action_Map_BuildAvatarList +// model definition format +// name +// picture\n +// skin filename\n +// model filename\n +// rest: description text +void() _IDNM_BuildList = +{ + local float lSearchHandle; + local float lSearchSize; + local float lSearchCounter; + local entity lMap; + + Menu_EmptyWindow( self ); + + lSearchHandle = search_begin( "maps/*.bsp", true, true ); + if( lSearchHandle < 0 ) + return; + for( lSearchSize = search_getsize( lSearchHandle ), lSearchCounter = 0; + lSearchCounter < lSearchSize; ++lSearchCounter ) { + local float lHandle; + + local string lFilename; + local string lStripped; + local string lName; + local string lDescription; + + lFilename = search_getfilename( lSearchHandle, lSearchCounter ); + lStripped = String_Zone( substring( lFilename, 0, strlen( lFilename ) - 4 ) ); + lName = String_Zone( substring( lStripped, 5, 100000 ) ); + + lHandle = fopen( strcat( lStripped, ".txt" ), FILE_READ ); + if( lHandle < 0 ) + lDescription = String_Zone( strcat( "--NO INFORMATION AVAILABLE--\n", lFilename ) ); + else { + lDescription = String_Create(); + do { + local string lLine; + + lLine = fgets( lHandle ); + lDescription = String_Append( lDescription, strcat( lLine, "\n" ) ); + } while( validstring( lLine ) ); + + fclose( lHandle ); + } + + // add this avatar_info + lMap = Menu_CreateItem( "Item_Nex_Map_Info", ftos( lSearchCounter ), self.name ); + + lMap.link = lName; + lMap.picture = lStripped; + lMap.normal = lName; + lMap.text = lDescription; + + Menu_LinkItem( lMap ); + + String_Free( lName ); + String_Free( lStripped ); + String_Free( lDescription ); + } + + search_end( lSearchHandle ); + + Menu_LinkChildren( self ); + + self.minValue = 1; + self.stepValue = 1; + self.maxValue = fabs( lMap.orderPos ); +}; + +void() _IDNM_UpdateLink = +{ + local float lCurrent; + local float lTarget; + local entity lMatch; + + lCurrent = fabs( self._link.orderPos ); + lTarget = self._realValue; + if( lCurrent < lTarget ) + for( lMatch = self._link; lMatch._next && fabs( lMatch.orderPos ) != lTarget; lMatch = lMatch._next ); + else + for( lMatch = self._link; lMatch._prev && fabs( lMatch.orderPos ) != lTarget; lMatch = lMatch._prev ); + // lMatch always is valid if there are any children + self._link = lMatch; + + self._realValue = fabs( self._link.orderPos ); + String_EntitySet( self, value, ftos( self._realValue ) ); +}; + +void() _IDNM_Sync = +{ + String_EntitySet( self, value, ftos( self._realValue ) ); + String_EntitySet( self, _syncValue, ftos( self._realValue ) ); +}; + +void() _IDNM_Send = +{ + _IDNM_UpdateLink(); + String_EntitySet( self, _syncValue, self.value ); +}; + +void() _IDNM_Test_Start = +{ + _IDNM_UpdateLink(); +}; + +void() _IDNM_Test_End = +{ + String_EntitySet( self, value, self._syncValue ); + _IDNM_UpdateLink(); +}; + +void() _IDNM_Reset = +{ + String_EntitySet( self, value, self.defValue ); + _IDNM_Send(); +}; + +void( float pEvent ) Item_Data_Nex_Map_DataEvent = +{ + switch( pEvent ) { + case ITEM_DATA_SYNC: + _IDNM_Sync(); + break; + case ITEM_DATA_SEND: + _IDNM_Send(); + break; + case ITEM_DATA_RESET: + _IDNM_Reset(); + break; + case ITEM_DATA_TEST_START: + _IDNM_Test_Start(); + break; + case ITEM_DATA_TEST_END: + _IDNM_Test_End(); + break; + case ITEM_DATALINK_SET: + _IDNM_UpdateLink(); + break; + } +}; + +void() Item_Data_Nex_Map_Spawn = +{ + Item_Data_Init(); + + self.flag = self.flag | FLAG_HIDDEN; + + self._dataEvent = Item_Data_Nex_Map_DataEvent; + + _IDNM_BuildList(); + + self._link = self._child; + self._realValue = stof( self.defValue ); + _IDNM_UpdateLink(); +}; diff --git a/scmenu/source/custom/creategame/mods.qc b/scmenu/source/custom/creategame/mods.qc new file mode 100644 index 000000000..041182e4c --- /dev/null +++ b/scmenu/source/custom/creategame/mods.qc @@ -0,0 +1,85 @@ +// Property of Alientrap/AK +// custom/creategame/mods.qc + +/* +=================== +Item_DataLink_Nex_ModSwitch +=================== +*/ + +// first line filename +// second line mod name +// repeat +void() _IDLNMS_Build = +{ + local float lSearchHandle; + local float lSearchSize; + local float lSearchCounter; + + // FIXME: most stupid builtin bug ever: search only finds /*.modinfo, but fopen only opens *.modinfo + lSearchHandle = search_begin( "/*.modinfo", true, true ); + if( lSearchHandle < 0 ) { + String_EntitySet( self, valueList, "'progs.dat'" ); + String_EntitySet( self, descList, "'Deathmatch'" ); + return; + } + + for( lSearchSize = search_getsize( lSearchHandle ), lSearchCounter = 0; + lSearchCounter < lSearchSize; ++lSearchCounter ) { + local float lHandle; + local string lFilename; + + local string lModName; + local string lModPath; + local string lLine; + + lFilename = search_getfilename( lSearchHandle, lSearchCounter ); + lHandle = fopen( substring( lFilename, 1, 100000 ), FILE_READ ); + if( lHandle < 0 ) { + print( "Menu: Couldn't open modinfo file '", lFilename, "'\n" ); + continue; + } + + lModPath = String_Create(); + lModName = String_Create(); + while( 1 ) { + lLine = fgets( lHandle ); + if( !validstring( lLine ) ) + break; + + lModPath = String_Set( lModPath, lLine ); + + lLine = fgets( lHandle ); + if( !validstring( lLine ) ) + break; + + lModName = String_Set( lModName, lLine ); + + String_EntitySet( self, valueList, strcat( self.valueList, lModPath, " " ) ); + String_EntitySet( self, descList, strcat( self.descList, lModName, " " ) ); + } + String_Free( lModPath ); + String_Free( lModName ); + + fclose( lHandle ); + } + + search_end( lSearchHandle ); +}; + +void() Item_DataLink_Nex_ModSwitch_Spawn = +{ + local string lTemp1, lTemp2; + + String_EntityCreate( self, valueList ); + String_EntityCreate( self, descList ); + + _IDLNMS_Build(); + + lTemp1 = self.descList; + lTemp2 = self.valueList; + Item_DataLink_TextSwitch_Spawn(); + String_Free( lTemp1 ); + String_Free( lTemp2 ); +}; + diff --git a/scmenu/source/custom/custom.qh b/scmenu/source/custom/custom.qh new file mode 100644 index 000000000..748ad193d --- /dev/null +++ b/scmenu/source/custom/custom.qh @@ -0,0 +1,5 @@ +// Property of Alientrap/AK +// custom/custom.qh + +// Moves through all of pItem's neighbors and makes pItem the only visible item +void( entity pItem ) Nex_MakeOnlyVisible; diff --git a/scmenu/source/custom/globalkey.qm b/scmenu/source/custom/globalkey.qm new file mode 100644 index 000000000..826acac1f --- /dev/null +++ b/scmenu/source/custom/globalkey.qm @@ -0,0 +1,32 @@ +// Property of Alientrap/AK +// custom/globalkey.qm + +bool( float pKey, float pAscii ) Nex_Global_Key = +{ + switch( pKey ) { + case K_UPARROW: + case K_KP_UPARROW: + case K_LEFTARROW: + case K_KP_LEFTARROW: + Menu_SelectPrev( true ); + break; + case K_DOWNARROW: + case K_KP_DOWNARROW: + case K_RIGHTARROW: + case K_KP_RIGHTARROW: + Menu_SelectNext( true ); + break; + case K_ESCAPE: + case K_MOUSE2: + Menu_SelectUp( true ); + break; + case K_ENTER: + if( !Menu_SelectDown( true ) ) + Sound_Play( ITEM_SOUND_NOSELECT ); + break; + default: + break; + } + return true; +}; + diff --git a/scmenu/source/custom/joingame.qc b/scmenu/source/custom/joingame.qc new file mode 100644 index 000000000..adae7ca63 --- /dev/null +++ b/scmenu/source/custom/joingame.qc @@ -0,0 +1,108 @@ +// Property of Alientrap/AK +// custom/joingame/joingame.qc + +//////////////////////////////////// +// Item_Nex_HostCache_Entry +////// + +void() Item_Nex_HostCache_Entry_Update = +{ + if( HostCache_ViewCount <= self.stepValue ) { + self.flag = self.flag | FLAG_HIDDEN; + return; + } else if( self.flag & FLAG_HIDDEN ) + self.flag = self.flag - FLAG_HIDDEN; + + if( Menu_HasRunFlag( self, RUNFLAG_CLIPPED ) ) + return; + + Item_Button_Update(); +}; + +void() Item_Nex_HostCache_Entry_Draw = +{ + Item_Window_Draw(); + Item_Button_Draw(); +}; + +void() Item_Nex_HostCache_Entry_Spawn = +{ + Item_Window_Spawn(); + Item_Button_Spawn(); + + self.flag = self.flag | FLAG_HIDDEN; // we dont want to get this bloody hostcachestring warning + if( self.flag & FLAG_NOSELECT ) + self.flag = self.flag - FLAG_NOSELECT; + self._draw = Item_Nex_HostCache_Entry_Draw; + self._update = Item_Nex_HostCache_Entry_Update; +}; + +//////////////////////////////////// +// Item_Nex_HostCache_StringField +//////// + +void() Item_Nex_HostCache_StringField_Update = +{ + local float lMaxLen; + + if( HostCache_ViewCount <= self._parent.stepValue ) + return; + lMaxLen = floor( self.size_x / self.fontSize_x ); + String_EntitySet( self, text, gethostcachestring( self.stepValue, self._parent.stepValue ) ); + if( lMaxLen < strlen( self.text ) ) + String_EntitySet( self, text, strcat( substring( self.text, 0, lMaxLen - 3 ), "..." ) ); + + Item_Label_Update(); +}; + +void() Item_Nex_HostCache_StringField_Spawn = +{ + Item_Label_Spawn(); + + self._update = Item_Nex_HostCache_StringField_Update; +}; + +//////////////////////////////////// +// Item_Nex_HostCache_ValueField +//////// + +void() Item_Nex_HostCache_ValueField_Update = +{ + if( HostCache_ViewCount <= self._parent.stepValue ) + return; + String_EntitySet( self, text, ftos( gethostcachenumber( self.stepValue, self._parent.stepValue ) ) ); + + Item_Label_Update(); +}; + +void() Item_Nex_HostCache_ValueField_Spawn = +{ + Item_Label_Spawn(); + + self._update = Item_Nex_HostCache_ValueField_Update; +}; + +////////////////////////////////// +// Item_Nex_HostCache_Players +/////// + +void() Item_Nex_HostCache_Players_Update = +{ + local string lNum, lMax; + + if( HostCache_ViewCount <= self._parent.stepValue ) + return; + lNum = ftos( gethostcachenumber( SLIST_FIELD_NUMPLAYERS, self._parent.stepValue ) ); + lMax = ftos( gethostcachenumber( SLIST_FIELD_MAXPLAYERS, self._parent.stepValue ) ); + + String_EntitySet( self, text, strcat( lNum, "/", lMax ) ); + + Item_Label_Update(); +}; + +void() Item_Nex_HostCache_Players_Spawn = +{ + Item_Label_Spawn(); + + self._update = Item_Nex_HostCache_Players_Update; +}; diff --git a/scmenu/source/custom/joingame.qh b/scmenu/source/custom/joingame.qh new file mode 100644 index 000000000..0e48e3791 --- /dev/null +++ b/scmenu/source/custom/joingame.qh @@ -0,0 +1,29 @@ +// Property of Alientrap +// custom/joingame/joingame.qh + +// Item_Nex_HostCache_Entry Item_Arrangement +.string soundSelected; +.vector color; +.float alpha; +.float drawFlag; +.float stepValue; // contains the entry number + +void() Item_Nex_HostCache_Entry_Update; +void() Item_Nex_HostCache_Entry_Spawn; + +// Item_Nex_HostCache_StringField Item_Label +.float stepValue; // contains the field number + +void() Item_Nex_HostCache_StringField_Update; +void() Item_Nex_HostCache_StringField_Spawn; + +// Item_Nex_HostCache_ValueField Item_Label +.float stepValue; // contains the field number + +void() Item_Nex_HostCache_ValueField_Update; +void() Item_Nex_HostCache_ValueField_Spawn; + +// Item_Nex_HostCache_Players Item_Label +void() Item_Nex_HostCache_Players_Update; +void() Item_Nex_HostCache_Players_Spawn; + diff --git a/scmenu/source/custom/joingame.qm b/scmenu/source/custom/joingame.qm new file mode 100644 index 000000000..20f410ccc --- /dev/null +++ b/scmenu/source/custom/joingame.qm @@ -0,0 +1,224 @@ +// Property of Alientrap +// custom/joingame.qm + +// stepValue should contain the field name +void() Nex_Action_JoinGame_SortBy = +{ + if( HostCache_SortField == self.stepValue ) + sethostcachesort( self.stepValue, !HostCache_SortDescending ); + else + sethostcachesort( self.stepValue, true ); + HostCache_ResortViewSet(); +}; + +void() Nex_Automation_CreateEntries = +{ + local entity lTemplate; + local float lCounter; + + lTemplate = Menu_GetItem( "Entry" ); + for( lCounter = 0 ; lCounter < 64 ; ++lCounter ) { + local entity lEntry; + + lEntry = Menu_DeriveItem( lTemplate, strcat( "Entry", ftos( lCounter) ), self.parent, true ); + lEntry.stepValue = lCounter; + } + Menu_LinkItem( self._parent ); +}; + +void() Nex_Action_EntryConnect = +{ + cmd( "connect \"" ); + cmd( gethostcachestring( SLIST_FIELD_CNAME, self.stepValue ) ); + cmd( "\"\n" ); + + m_hide(); +}; + +void() Nex_Action_RefreshSlist = +{ + HostCache_RefreshHostCache(); +}; + +void() Nex_Action_JumpToJoinGame = +{ + local entity lItem; + + resethostcachemasks(); + HostCache_RefreshHostCache(); + + lItem = Menu_GetItem( "Normal::Panel" ); + String_EntitySet( lItem, link, "JoinGame" ); + + Raise_Update( lItem ); + Menu_UpdateRunFlags(); + Menu_JumpToWindow( lItem._link, false, false ); +}; + +// mask parser +/* query string format: + two types: +1) Prefix "mask" Advanced query + Format: ( and|or TYPE OP MASK [...] )* + TYPE : one of the slist fields + OP: + <;<=;>=;==;!= normal arithmetic comparison operators (default <=) (= instead of == also supported) + $$ 'does contain' (default string op) + !$ 'does not contain' + : leads to default op + + On every occurence of AND or OR a new mask of the spec type is created. + E.g. or name: "WWClan" ping: 200 and protocol == 3 maxplayers > 5 + will create an or and an and mask +2) No prefix: + keyword * + + notempty + compatible (same net protocol version) + goodping (ping <= 150) + mediumping (ping <= 250) +*/ +#define GetNextToken if( ++lTokenNum > lTokenCount ) goto finish; else lToken = argv( lTokenNum ) +void() Nex_Action_ExecuteQuery = +{ + local float lAndPos, lOrPos; + local float lTokenNum, lTokenCount; + + resethostcachemasks(); + lAndPos = SLIST_MASK_AND; + lOrPos = SLIST_MASK_OR; + + lTokenCount = tokenize( self._target.value ); + + for( lTokenNum = 0 ; lTokenNum < lTokenCount ; ++lTokenNum ) { + local string lToken; + lToken = argv( lTokenNum ); + + if( lToken == "notempty" ) { + sethostcachemasknumber( lAndPos, SLIST_FIELD_NUMPLAYERS, 0, SLIST_TEST_NOTEQUAL ); + ++lAndPos; + } else if( lToken == "compatible" ) { + sethostcachemasknumber( lAndPos, SLIST_FIELD_PROTOCOL, NET_CURRENTPROTOCOL, SLIST_TEST_EQUAL ); + ++lAndPos; + } else if( lToken == "goodping" ) { + sethostcachemasknumber( lAndPos, SLIST_FIELD_PING, 150, SLIST_TEST_LESSEQUAL ); + ++lAndPos; + } else if( lToken == "mediumping" ) { + sethostcachemasknumber( lAndPos, SLIST_FIELD_PROTOCOL, 250, SLIST_TEST_LESSEQUAL ); + ++lAndPos; + } else if( lToken == "mask" ) { + // start the query loop + GetNextToken; + while( 1 ) { + local bool lAndMask; + + if( lToken == "or" ) + lAndMask = false; + else if( lToken == "and" ) + lAndMask = true; + else + goto finish; // abort the parsing + // now parse all condition fields + while( 1 ) { + local float lField; + local float lOperator; + local bool lIsStringArg; + + GetNextToken; + // now get the field number + if( lToken == "cname" ) { + lField = SLIST_FIELD_CNAME; + lIsStringArg = true; + } + else if( lToken == "ping" ) { + lField = SLIST_FIELD_PING; + lIsStringArg = false; + } + else if( lToken == "game" ) { + lField = SLIST_FIELD_GAME; + lIsStringArg = true; + } + else if( lToken == "mod" ) { + lField = SLIST_FIELD_MOD; + lIsStringArg = true; + } + else if( lToken == "map" ) { + lField = SLIST_FIELD_MAP; + lIsStringArg = true; + } + else if( lToken == "name" ) { + lField = SLIST_FIELD_NAME; + lIsStringArg = true; + } + else if( lToken == "maxplayers" ) { + lField = SLIST_FIELD_MAXPLAYERS; + lIsStringArg = false; + } + else if( lToken == "numplayers" ) { + lField = SLIST_FIELD_NUMPLAYERS; + lIsStringArg = false; + } + else if( lToken == "protocol" ) { + lField = SLIST_FIELD_PROTOCOL; + lIsStringArg = false; + } + else + { // increment the mask pos and let upper check for or or and + if( lAndMask ) + ++lAndPos; + else + ++lOrPos; + break; + } + // now lets determine the comparison operator + GetNextToken; + if( lToken == "$$" ) + lOperator = SLIST_TEST_CONTAINS; + else if( lToken == "!$" ) + lOperator = SLIST_TEST_NOTCONTAIN; + else if( lToken == "<" ) + lOperator = SLIST_TEST_LESS; + else if( lToken == "<=" ) + lOperator = SLIST_TEST_LESSEQUAL; + else if( lToken == "==" || lToken == "=" ) + lOperator = SLIST_TEST_EQUAL; + else if( lToken == ">" ) + lOperator = SLIST_TEST_GREATER; + else if( lToken == ">=" ) + lOperator = SLIST_TEST_GREATEREQUAL; + else if( lToken == "!=" ) + lOperator = SLIST_TEST_NOTEQUAL; + else if( lToken == ":" ) + if( lIsStringArg ) + lOperator = SLIST_TEST_CONTAINS; + else + lOperator = SLIST_TEST_LESSEQUAL; + else + goto finish; // abort the parsing + + GetNextToken; + if( lIsStringArg ) + if( lAndMask ) + sethostcachemaskstring( lAndPos, lField, lToken, lOperator ); + else + sethostcachemaskstring( lOrPos, lField, lToken, lOperator ); + else + if( lAndMask ) + sethostcachemasknumber( lAndPos, lField, stof( lToken ), lOperator ); + else + sethostcachemasknumber( lOrPos, lField, stof( lToken ), lOperator ); + } + } + } else { // lets have a try it with or and string contain + sethostcachemaskstring( lOrPos, SLIST_FIELD_MAP, lToken, SLIST_TEST_CONTAINS ); + lOrPos = lOrPos + 1; + sethostcachemaskstring( lOrPos, SLIST_FIELD_NAME, lToken, SLIST_TEST_CONTAINS ); + lOrPos = lOrPos + 1; + //sethostcachemasknumber( lOrPos, SLIST_FIELD_MOD, lToken, SLIST_TEST_CONTAINS ); + //lOrPos = lOrPos + 1; + } + } +:finish + HostCache_ResortViewSet(); +#undef GetNextToken() +}; diff --git a/scmenu/source/custom/key.qc b/scmenu/source/custom/key.qc new file mode 100644 index 000000000..194348d74 --- /dev/null +++ b/scmenu/source/custom/key.qc @@ -0,0 +1,162 @@ +// Property of Alientrap/AK +// custom/key.qc + +void( float pEvent ) Item_Data_Nex_Key_DataEvent; + +void() _IDNK_Sync = +{ + String_EntitySet( self, value, String_Normal( Key_GetBindList( self.target ) ) ); + String_EntitySet( self, _syncValue, self.value ); +}; + +void() _IDNK_Set = +{ + local float lCount, lCounter; + + lCount = Util_GetAltStringCount( self.value ); + Key_LimitBinds( 0, self.target ); + + for( lCounter = 0 ; lCounter < lCount ; ++lCounter ) + Key_Bind( Key_GetName( stof( String_Normal( Util_GetAltStringItem( self.value, lCounter ) ) ) ), self.target ); +}; + +void() _IDNK_Send = +{ + _IDNK_Set(); + String_EntitySet( self, _syncValue, self.value ); +}; + +void() _IDNK_Reset = +{ + local float lCount, lCounter; + local string lKey; + // TODO: remove this - but we need this for testing purposes atm + // INFO: defValue should contain the key names used by DP not the key numbers! + if( !self.defValue ) + return; + + String_EntitySet( self, value, "" ); + + lCount = Util_GetAltStringCount( self.defValue ); + Key_LimitBinds( 0, self.target ); + + for( lCounter = 0 ; lCounter < lCount ; ++lCounter ) { + lKey = Util_GetAltStringItem( self.value, lCounter ); + Key_Bind( lKey, self.target ); + String_EntitySet( self, value, strcat( self.value, "'", Key_GetNum( lKey ), "'" ) ); + String_Free( lKey ); + } + + String_EntitySet( self, _syncValue, self.value ); +}; + +void() _IDNK_Test_Start = +{ + _IDNK_Set(); +}; + +void() _IDNK_Test_End = +{ + String_EntitySet( self, value, self._syncValue ); + _IDNK_Set(); +}; + +void( float pEvent ) Item_Data_Nex_Key_DataEvent = +{ + switch( pEvent ) { + case ITEM_DATA_SYNC: + _IDNK_Sync(); + break; + case ITEM_DATA_SEND: + _IDNK_Send(); + break; + case ITEM_DATA_RESET: + _IDNK_Reset(); + break; + case ITEM_DATA_TEST_START: + _IDNK_Test_Start(); + break; + case ITEM_DATA_TEST_END: + _IDNK_Test_End(); + break; + } +}; + +void() Item_Data_Nex_Key_Destroy = +{ + String_EntityFree( self, target ); + Item_Data_Destroy(); +}; + +void() Item_Data_Nex_Key_Spawn = +{ + Item_Data_Init(); + + String_EntityZone( self, target ); + + self._destroy = Item_Data_Nex_Key_Destroy; + self._reinit = _IDNK_Sync; + self._dataEvent = Item_Data_Nex_Key_DataEvent; +}; + + +/* +=================== +Item_Nex_KeyButton Item_Button +=================== +*/ + +bool( float pKey, float pAscii ) Item_Nex_KeyButton_Key = +{ + if( pKey == K_BACKSPACE ) { + local float lNum; + // unbind the key + Raise_DataEvent( self._target, ITEM_DATALINK_GET ); + lNum = stof( self._target.value ); + if( lNum >= 0 ) { + Key_Unbind( Key_GetName( lNum ) ); + Raise_DataEvent( self._target, ITEM_DATALINK_SET ); + } + return true; + } else if( pKey == K_UPARROW ) { + Menu_SelectPrev( false ); + Menu_SelectPrev( true ); + return true; + } else if( pKey == K_DOWNARROW ) { + Menu_SelectNext( false ); + Menu_SelectNext( true ); + return true; + } else + return Item_Button_Key( pKey, pAscii ); +}; + +void() Item_Nex_KeyButton_Update = +{ + local float lNum; + Item_DataUser_Update(); + + Raise_DataEvent( self._target, ITEM_DATALINK_GET ); + lNum = stof( self._target.value ); + if( lNum < 0 ) + String_EntitySet( self, normal, "-" ); + else + String_EntitySet( self, normal, Key_GetName( lNum ) ); + Item_Button_Update(); +}; + +void() Item_Nex_KeyButton_Destroy = +{ + Item_DataUser_Destroy(); + Item_Button_Destroy(); +}; + +void() Item_Nex_KeyButton_Spawn = +{ + Item_DataUser_Init(); + Item_Button_Spawn(); + + self._destroy = Item_Nex_KeyButton_Destroy; + self._update = Item_Nex_KeyButton_Update; + self._key = Item_Nex_KeyButton_Key; +}; + diff --git a/scmenu/source/custom/key.qh b/scmenu/source/custom/key.qh new file mode 100644 index 000000000..18ef4c621 --- /dev/null +++ b/scmenu/source/custom/key.qh @@ -0,0 +1,13 @@ +// Property of Alientrap/AK +// custom/key.qh + +// Item_Data_Nex_Key [Item_Data] +// value is an altstring which contains all assigned key names +// +.string target; // action name + +void( float pEvent ) Item_Data_Nex_Key_DataEvent; +void() Item_Data_Nex_Key_Spawn; + +// Item_Nex_KeyButton Item_Button +void() Item_Nex_KeyButton_Spawn; diff --git a/scmenu/source/custom/key.qm b/scmenu/source/custom/key.qm new file mode 100644 index 000000000..123ff46b5 --- /dev/null +++ b/scmenu/source/custom/key.qm @@ -0,0 +1,65 @@ +// Property of Alientrap +// custom/key.qm + +// link is the name of the datalink +.string target; +// text is the description text +.string text; + +/* +=================== +Nex_Automation_Key +=================== +*/ +// Embedded in a window with the following subitems: Action, Link1, Link2 +void() Nex_Automation_Key = +{ + local entity lAction, lLink1, lLink2; + + if( !self._parent.target ) { + objerror( "Bad target '", self._parent.target, "'" ); + return; + } + + // Get the children + lAction = Menu_GetItem( "Action" ); + lLink1 = Menu_GetItem( "Link1" ); + lLink2 = Menu_GetItem( "Link2" ); + + // Now set the properties + // (will be strzoned later by the Spawn functions) + lAction.text = self._parent.text; + + lLink1.link = self._parent.target; + lLink2.link = self._parent.target; +}; + +// more specific functions +// Menu_KeyHook_Target points to Link1/2 +void( float pKey, float pAscii ) Nex_Key_KeyHook = +{ + local entity lItem; + if( pKey != K_ESCAPE ) { + String_EntitySet( Menu_KeyHook_Target, value, ftos( pKey ) ); + Raise_DataEvent( Menu_KeyHook_Target, ITEM_DATALINK_SET ); + Raise_DataEvent( Menu_KeyHook_Target, ITEM_DATA_TEST_START ); + } + // hide the info window again + lItem = Menu_GetItemEx( Menu_KeyHook_Target, "InfoWindow", true ); + lItem.flag = lItem.flag | FLAG_HIDDEN; + + Menu_KeyHook = Util_NullFunction; +}; + +void() Nex_Action_KeyButton = +{ + local entity lItem; + + Menu_KeyHook_Target = self._target._link; + Menu_KeyHook = Nex_Key_KeyHook; + + // show the info window + lItem = Menu_GetItem( "InfoWindow" ); + lItem.flag = lItem.flag - (lItem.flag & FLAG_HIDDEN); +}; + diff --git a/scmenu/source/custom/option.qm b/scmenu/source/custom/option.qm new file mode 100644 index 000000000..7a0def736 --- /dev/null +++ b/scmenu/source/custom/option.qm @@ -0,0 +1,92 @@ +// Property of Alientrap +// custom/option.qm + +// link is the name of the datalink +.string target; +// text is the description text +.string text; + +/* +=================== +Nex_Automation_Option_Slider +=================== +*/ +// Embedded in a window with the following subitems: Description, Slider, Value +void() Nex_Automation_Option_Slider = +{ + local entity lDescription, lSlider, lValue; + + if( !self._parent.target ) { + objerror( "Bad target '", self._parent.target, "'" ); + return; + } + + // Get the children + lDescription = Menu_GetItem( "Description" ); + lSlider = Menu_GetItem( "Slider" ); + lValue = Menu_GetItem( "Value" ); + + // Now set the properties + // (will be strzoned later by the Spawn functions) + lDescription.normal = self._parent.text; + lDescription.link = lSlider.name; + + lSlider.target = self._parent.target; + + lValue.target = self._parent.target; + lValue.link = lSlider.name; +}; + +/* +=================== +Nex_Automation_Option_EditBox +=================== +*/ +// Embedded in a window with the following subitems: Description, EditBox +void() Nex_Automation_Option_EditBox = +{ + local entity lDescription, lEditBox; + + if( !self._parent.target ) { + objerror( "Bad target '", self._parent.target, "'" ); + return; + } + + // Get the children + lDescription = Menu_GetItem( "Description" ); + lEditBox = Menu_GetItem( "EditBox" ); + + // Now set the properties + // (will be strzoned later by the Spawn functions) + lDescription.normal = self._parent.text; + lDescription.link = lEditBox.name; + + lEditBox.target = self._parent.target; +}; + +/* +=================== +Nex_Automation_Option_Switch +=================== +*/ +// Embedded in a window with the following subitems: Description, Switch +void() Nex_Automation_Option_Switch = +{ + local entity lDescription, lSwitch; + + if( !self._parent.target ) { + objerror( "Bad target '", self._parent.target, "'" ); + return; + } + + // Get the children + lDescription = Menu_GetItem( "Description" ); + lSwitch = Menu_GetItem( "Switch" ); + + // Now set the properties + // (will be strzoned later by the Spawn functions) + lDescription.normal = self._parent.text; + lDescription.link = lSwitch.name; + + lSwitch.target = self._parent.target; +}; diff --git a/scmenu/source/custom/player.qm b/scmenu/source/custom/player.qm new file mode 100644 index 000000000..81ad4e434 --- /dev/null +++ b/scmenu/source/custom/player.qm @@ -0,0 +1,56 @@ +// Property of Alientrap/AK +// custom/player/player.qm + +// uses target and _target +// requires neighbors: Picture, Name, Description +void() Nex_Automation_UpdateAvatar_Update = +{ + local entity lItem; + local entity lTarget; + + if( self._target.name != "Data::Player::Avatar" ) + self._target = Menu_GetItem( "Data::Player::Avatar" ); + + lTarget = self._target; + + lItem = Menu_GetItem( "Picture" ); + String_EntitySet( lItem, picture, lTarget._link.picture ); + + lItem = Menu_GetItem( "Name" ); + String_EntitySet( lItem, text, lTarget._link.normal ); + + lItem = Menu_GetItem( "Description" ); + String_EntitySet( lItem, text, lTarget._link.text ); +}; + +void() Nex_Automation_UpdateAvatar_Destroy = +{ + String_EntityFree( self, target ); +}; + +void() Nex_Automation_UpdateAvatar = +{ + String_EntityZone( self, target ); + + self._update = Nex_Automation_UpdateAvatar_Update; + self._destroy = Nex_Automation_UpdateAvatar_Destroy; +}; + +// more concrete functions +void() Nex_Action_Avatar_Next = +{ + local entity lItem; + + lItem = Menu_GetItem( "Data::Player::Avatar" ); + lItem._realValue = lItem._realValue + 1; + Raise_DataEvent( lItem, ITEM_DATA_SEND ); +}; + +void() Nex_Action_Avatar_Prev = +{ + local entity lItem; + + lItem = Menu_GetItem( "Data::Player::Avatar" ); + lItem._realValue = lItem._realValue - 1; + Raise_DataEvent( lItem, ITEM_DATA_SEND ); +}; diff --git a/scmenu/source/custom/player/avatar.qc b/scmenu/source/custom/player/avatar.qc new file mode 100644 index 000000000..48766a216 --- /dev/null +++ b/scmenu/source/custom/player/avatar.qc @@ -0,0 +1,236 @@ +// Property of Alientrap/AK +// custom/player/avatar.qm + +/* +=================== +Item_Nex_Avatar_Info +=================== +*/ + +void() Item_Nex_Avatar_Info_Destroy = +{ + String_EntityFree( self, target ); + String_EntityFree( self, link ); + String_EntityFree( self, picture ); + String_EntityFree( self, text ); + String_EntityFree( self, normal ); +}; + +void() Item_Nex_Avatar_Info_Spawn = +{ + String_EntityZone( self, target ); + String_EntityZone( self, link ); + String_EntityZone( self, picture ); + String_EntityZone( self, text ); + String_EntityZone( self, normal ); + + Gfx_Precache( self.picture ); + + self._destroy = Item_Nex_Avatar_Info_Destroy; +}; + +/* +=================== +Item_Data_Nex_Avatar +=================== +*/ + + +// Nex_Action_Player_BuildAvatarList +// model definition format +// name +// picture\n +// skin filename\n +// model filename\n +// rest: description text +void() _IDNA_BuildList = +{ + local float lSearchHandle; + local float lSearchSize; + local float lSearchCounter; + local entity lAvatar; + + Menu_EmptyWindow( self ); + + // legacy mode + // TODO: + // FIXME: only accept *.mdef later + lSearchHandle = search_begin( "models/player/*.txt", true, true ); + if( lSearchHandle < 0 ) + return; + for( lSearchSize = search_getsize( lSearchHandle ), lSearchCounter = 0; + lSearchCounter < lSearchSize; ++lSearchCounter ) { + local string lFilename; + local float lHandle; + + local string lName; + local string lPicture; + local string lSkin; + local string lModel; + local string lDescription; + + lFilename = search_getfilename( lSearchHandle, lSearchCounter ); + lHandle = fopen( lFilename, FILE_READ ); + if( lHandle < 0 ) { + print( "Menu: Couldn't open model definition file '", lFilename, "'\n" ); + continue; + } + + lName = String_Zone( fgets( lHandle ) ); + lPicture = String_Zone( fgets( lHandle ) ); + lSkin = String_Zone( fgets( lHandle ) ); + lModel = String_Zone( fgets( lHandle ) ); + if( !lName || !lPicture || !lSkin || !lModel ) { + String_Free( lName ); + String_Free( lPicture ); + String_Free( lSkin ); + String_Free( lModel ); + print( "Menu: Couldn't parse model definition file '", + search_getfilename( lSearchHandle, lSearchCounter ), "'\n" ); + fclose( lHandle ); + continue; + } + lDescription = String_Create(); + do { + local string lLine; + + lLine = fgets( lHandle ); + lDescription = String_Append( lDescription, strcat( lLine, "\n" ) ); + } while( validstring( lLine ) ); + if( lDescription ) { // add this avatar_info + lAvatar = Menu_CreateItem( "Item_Nex_Avatar_Info", ftos( lSearchCounter ), self.name ); + + lAvatar.target = lModel; + lAvatar.link = lSkin; + lAvatar.picture = lPicture; + lAvatar.normal = lName; + lAvatar.text = lDescription; + + Menu_LinkItem( lAvatar ); + } + String_Free( lName ); + String_Free( lPicture ); + String_Free( lSkin ); + String_Free( lModel ); + String_Free( lDescription ); + fclose( lHandle ); + } + + search_end( lSearchHandle ); + + Menu_LinkChildren( self ); + + self.minValue = 1; + self.stepValue = 1; + self.maxValue = fabs( lAvatar.orderPos ); +}; + +void() _IDNA_Sync = +{ + local string lModel, lSkin; + local entity lMatch; + + lModel = String_Zone( str_cvar( "_cl_playermodel" ) ); + lSkin = String_Zone( str_cvar( "_cl_playerskin" ) ); + + for( lMatch = self._child ; lMatch._next ; lMatch = lMatch._next ) + if( lMatch.target == lModel && lMatch.link == lSkin ) + break; + + if( lMatch ) { + self._link = lMatch; + self._realValue = fabs( lMatch.orderPos ); + String_EntitySet( self, value, ftos( self._realValue ) ); + String_EntitySet( self, _syncValue, self.value ); + } + + String_Free( lModel ); + String_Free( lSkin ); +}; + +void() _IDNA_UpdateLink = +{ + local float lCurrent; + local float lTarget; + local entity lMatch; + + lCurrent = fabs( self._link.orderPos ); + lTarget = self._realValue; + if( lCurrent < lTarget ) + for( lMatch = self._link; lMatch._next && fabs( lMatch.orderPos ) != lTarget; lMatch = lMatch._next ); + else + for( lMatch = self._link; lMatch._prev && fabs( lMatch.orderPos ) != lTarget; lMatch = lMatch._prev ); + // lMatch always is valid if there are any children + self._link = lMatch; + + self._realValue = fabs( self._link.orderPos ); + String_EntitySet( self, value, ftos( self._realValue ) ); +}; + +void() _IDNA_RawSet = +{ + _IDNA_UpdateLink(); + + cmd( strcat( "playermodel \"", self._link.target, "\";" ) ); + cmd( strcat( "playerskin \"", self._link.link, "\"\n" ) ); +}; + +void() _IDNA_Send = +{ + _IDNA_RawSet(); + + String_EntitySet( self, _syncValue, self.value ); +}; + +void() _IDNA_Test_Start = +{ + _IDNA_RawSet(); +}; + +void() _IDNA_Test_End = +{ + String_EntitySet( self, value, self._syncValue ); + _IDNA_RawSet(); +}; + +void() _IDNA_Reset = +{ + String_EntitySet( self, value, self.defValue ); + _IDNA_Send(); +}; + +void( float pEvent ) Item_Data_Nex_Avatar_DataEvent = +{ + switch( pEvent ) { + case ITEM_DATA_SYNC: + _IDNA_Sync(); + break; + case ITEM_DATA_SEND: + _IDNA_Send(); + break; + case ITEM_DATA_RESET: + _IDNA_Reset(); + break; + case ITEM_DATA_TEST_START: + _IDNA_Test_Start(); + break; + case ITEM_DATA_TEST_END: + _IDNA_Test_End(); + break; + case ITEM_DATALINK_SET: + _IDNA_UpdateLink(); + break; + } +}; + +void() Item_Data_Nex_Avatar_Spawn = +{ + Item_Data_Init(); + + self.flag = self.flag | FLAG_HIDDEN; + + self._reinit = _IDNA_Sync; + self._dataEvent = Item_Data_Nex_Avatar_DataEvent; + + _IDNA_BuildList(); +}; diff --git a/scmenu/source/custom/player/name.qc b/scmenu/source/custom/player/name.qc new file mode 100644 index 000000000..23b249bd1 --- /dev/null +++ b/scmenu/source/custom/player/name.qc @@ -0,0 +1,67 @@ +// Property of Alientrap/AK +// custom/player/name.qc + +/* +=================== +Item_Data_Nex_Name +=================== +*/ + +void() _IDNN_Sync = +{ + String_EntitySet( self, value, str_cvar( "_cl_name" ) ); + String_EntitySet( self, _syncValue, self.value ); +}; +void() _IDNN_Send = +{ + cmd( strcat( "name \"", self.value, "\"\n" ) ); + String_EntitySet( self, _syncValue, self.value ); +}; + +void() _IDNN_Test_Start = +{ + cmd( strcat( "name \"", self.value, "\"\n" ) ); +}; + +void() _IDNN_Test_End = +{ + String_EntitySet( self, value, self._syncValue ); + cmd( strcat( "name \"", self.value, "\"\n" ) ); +}; + +void() _IDNN_Reset = +{ + String_EntitySet( self, value, self.defValue ); + _IDNN_Send(); +}; + +void( float pEvent ) Item_Data_Nex_Name_DataEvent = +{ + switch( pEvent ) { + case ITEM_DATA_SYNC: + _IDNN_Sync(); + break; + case ITEM_DATA_SEND: + _IDNN_Send(); + break; + case ITEM_DATA_RESET: + _IDNN_Reset(); + break; + case ITEM_DATA_TEST_START: + _IDNN_Test_Start(); + break; + case ITEM_DATA_TEST_END: + _IDNN_Test_End(); + break; + } +}; + +void() Item_Data_Nex_Name_Spawn = +{ + Item_Data_Init(); + + self.flag = self.flag | FLAG_HIDDEN; + + self._reinit = _IDNN_Sync; + self._dataEvent = Item_Data_Nex_Name_DataEvent; +}; diff --git a/scmenu/source/custom/player/player.qh b/scmenu/source/custom/player/player.qh new file mode 100644 index 000000000..b5a3a3427 --- /dev/null +++ b/scmenu/source/custom/player/player.qh @@ -0,0 +1,26 @@ +// Property of Alientrap/AK +// custom/player/avatar.qh + +// Item_Nex_Avatar_Info +// its a valid item nevertheless +.string normal; // contains the avatar name +.string target; // contains the model name +.string link; // contains the skin name +.string picture; // contains the picture that should be displayed +.string text; // contains the description text + +void() Item_Nex_Avatar_Info_Destroy; +void() Item_Nex_Avatar_Info_Spawn; + +// see control/data/data.qh +// Item_Data_Nex_Avatar Item_DataLink_Value (implements more or less) +// value should be a integer in the range 1..n where n is the number of found mdefs +.entity _link; + +void( float pEvent ) Item_Data_Nex_Avatar_DataEvent; +void() Item_Data_Nex_Avatar_Spawn; + +// see control/data/data.qh +// Item_Data_Nex_Name [Item_Data] +void( float pEvent ) Item_Data_Nex_Name_DataEvent; +void() Item_Data_Nex_Name_Spawn; diff --git a/scmenu/source/custom/quit.qm b/scmenu/source/custom/quit.qm new file mode 100644 index 000000000..81ae77c03 --- /dev/null +++ b/scmenu/source/custom/quit.qm @@ -0,0 +1,45 @@ +// Property of Alientrap/AK +// custom/quit.qm + +void() Nex_Quit_Toggle = +{ + local entity lEntity; + + lEntity = Menu_GetItem( "QuitWnd" ); + if( lEntity.flag & FLAG_HIDDEN ) { + lEntity.flag = lEntity.flag - FLAG_HIDDEN; + Menu_Select( Menu_GetItem( "QuitWnd::Layout::Buttons::No" ), false ); + } else { + lEntity.flag = lEntity.flag + FLAG_HIDDEN; + Menu_Reselect( false ); + } +} + +void() Nex_Quit_Action = +{ + local entity lEntity; + + lEntity = Menu_GetItem( "QuitWnd" ); + if( lEntity.flag & FLAG_HIDDEN ) + lEntity.flag = lEntity.flag - FLAG_HIDDEN; + Menu_Select( Menu_GetItem( "QuitWnd::Layout::Buttons::No" ), false ); +} + +bool( float pKey, float pAscii ) Nex_Quit_Key = +{ + if( pKey == K_ESCAPE ) { + Nex_Quit_Toggle(); + return true; + } + return false; +}; + +void() Nex_Quit_Yes = +{ + cmd( "quit\n" ); +}; + +void() Nex_Quit_No = +{ + Nex_Quit_Toggle(); +}; diff --git a/scmenu/source/custom/stresstest.qm b/scmenu/source/custom/stresstest.qm new file mode 100644 index 000000000..b96c6c8a6 --- /dev/null +++ b/scmenu/source/custom/stresstest.qm @@ -0,0 +1,14 @@ +// Property of Alientrap/AK +// custom/stresstest.qc + +void() Item_Nex_StressRepeat_Spawn = +{ + // at least a few times + local entity lItem; + local float lCounter; + + self.flag = self.flag | FLAG_EMBEDDED; + + for( lCounter = 0 ; lCounter < 100 ; ++lCounter ) + lItem = Menu_DeriveItem( self._child, ftos( lCounter ), self._parent.name, true ); +}; diff --git a/scmenu/source/custom/util.qm b/scmenu/source/custom/util.qm new file mode 100644 index 000000000..51203b903 --- /dev/null +++ b/scmenu/source/custom/util.qm @@ -0,0 +1,13 @@ +// Property of Alientrap/AK +// custom/util.qm + +void() Nex_Action_TestOnChange = +{ + Raise_DataEvent( self._target, ITEM_DATA_TEST_START ); +}; + +void( bool pSelect, bool pUser ) Nex_Action_TestOnSelect = +{ + if( !pSelect && pUser ) + Raise_DataEvent( self._target, ITEM_DATA_TEST_START ); +}; diff --git a/scmenu/source/custom/video.qc b/scmenu/source/custom/video.qc new file mode 100644 index 000000000..00906d58a --- /dev/null +++ b/scmenu/source/custom/video.qc @@ -0,0 +1,67 @@ +// Property of Alientrap +// custom/video.qc + +void() _IDNR_Sync = +{ + String_EntitySet( self, value, strcat( str_cvar( "vid_width" ), " ", str_cvar( "vid_height" ) ) ); + String_EntitySet( self, _syncValue, self.value ); +}; + +void() _IDNR_Set = +{ + tokenize( self.value ); + cvar_set( "vid_width", argv( 0 ) ); + cvar_set( "vid_height", argv( 1 ) ); +}; + +void() _IDNR_Send = +{ + _IDNR_Set(); + _IDNR_Sync(); +}; + +void() _IDNR_Reset = +{ + String_EntitySet( self, value, self.defValue ); + _IDNR_Send(); +}; + +void() _IDNR_Test_Start = +{ + _IDNR_Set(); +}; + +void() _IDNR_Test_End = +{ + String_EntitySet( self, value, self._syncValue ); + _IDNR_Send(); +}; + +void( float pEvent ) Item_Data_Nex_Resolution_DataEvent = +{ + switch( pEvent ) { + case ITEM_DATA_SYNC: + _IDNR_Sync(); + break; + case ITEM_DATA_SEND: + _IDNR_Send(); + break; + case ITEM_DATA_RESET: + _IDNR_Reset(); + break; + case ITEM_DATA_TEST_START: + _IDNR_Test_Start(); + break; + case ITEM_DATA_TEST_END: + _IDNR_Test_End(); + break; + } +}; + +void() Item_Data_Nex_Resolution_Spawn = +{ + Item_Data_Init(); + + self._dataEvent = Item_Data_Nex_Resolution_DataEvent; + self._reinit = _IDNR_Sync; +}; diff --git a/scmenu/source/custom/video.qh b/scmenu/source/custom/video.qh new file mode 100644 index 000000000..8b6049911 --- /dev/null +++ b/scmenu/source/custom/video.qh @@ -0,0 +1,9 @@ +// Property of Alientrap +// custom/video.qh + +// Item_Data_Nex_Resolution [Item_Data] +.string value; // contains the current resolution in the format "width height" + +void() Item_Data_Nex_Resolution_Spawn; + + diff --git a/scmenu/source/custom/video.qm b/scmenu/source/custom/video.qm new file mode 100644 index 000000000..b36206b16 --- /dev/null +++ b/scmenu/source/custom/video.qm @@ -0,0 +1,10 @@ +// Property of Alientrap +// custom/video.qm + +void() Nex_Action_Video_Apply = +{ + Raise_DataEvent( Menu_GetItem( "::Data::Video::Fullscreen" ), ITEM_DATA_SEND ); + Raise_DataEvent( Menu_GetItem( "::Data::Video::Resolution" ), ITEM_DATA_SEND ); + Raise_DataEvent( Menu_GetItem( "::Data::Video::BPP" ), ITEM_DATA_SEND ); + cmd( "vid_restart\n" ); +}; diff --git a/scmenu/source/custom/visible.qc b/scmenu/source/custom/visible.qc new file mode 100644 index 000000000..564f618fb --- /dev/null +++ b/scmenu/source/custom/visible.qc @@ -0,0 +1,14 @@ +// Property of Alientrap/AK +// custom/visible.qc + +void( entity pItem ) Nex_MakeOnlyVisible = +{ + local entity lChild; + + for( lChild = pItem._parent._child ; lChild ; lChild = lChild._next ) + lChild.flag = lChild.flag | FLAG_HIDDEN; + + pItem.flag = pItem.flag - FLAG_HIDDEN; + + Menu_UpdateRunFlags(); +}; diff --git a/scmenu/source/custom/visible.qm b/scmenu/source/custom/visible.qm new file mode 100644 index 000000000..3bf72c4a0 --- /dev/null +++ b/scmenu/source/custom/visible.qm @@ -0,0 +1,96 @@ +// Property of Alientrap/AK +// custom/visible.qm + +// uses .target to determine the target window + +void() Nex_Action_MakeOnlyVisible_Destroy = +{ + String_EntityFree( self, target ); +}; + +void() Nex_Action_MakeOnlyVisible_Action = +{ + Nex_MakeOnlyVisible( Menu_GetItem( self.target ) ); +}; + +void() Nex_Action_MakeOnlyVisible = +{ + String_EntityZone( self, target ); + + self.destroy = Nex_Action_MakeOnlyVisible_Destroy; + self.action = Nex_Action_MakeOnlyVisible_Action; +}; + +// makes the first child as only item in the window visible +void() Nex_Action_MakeFirstVisible = +{ + Nex_MakeOnlyVisible( self._child ); +}; + +// like MakeOnlyVisible, but also jumps to the window +void() Nex_Action_JumpToPage_Destroy = +{ + String_EntityFree( self, target ); +}; + +void() Nex_Action_JumpToPage_Action = +{ + local entity lItem; + lItem = Menu_GetItem( self.target ); + Nex_MakeOnlyVisible( lItem ); + Menu_JumpToWindow( lItem, false, false ); +}; + +void() Nex_Action_JumpToPage = +{ + String_EntityZone( self, target ); + + self.action = Nex_Action_JumpToPage_Action; + self.destroy = Nex_Action_JumpToPage_Destroy; +}; + +// sets the link field of Normal::Panel +void() Nex_Action_SetNormalPanelLink_Destroy = +{ + String_EntityFree( self, target ); +}; + +void() Nex_Action_SetNormalPanelLink_Action = +{ + local entity lItem; + + lItem = Menu_GetItem( "Normal::Panel" ); + String_EntitySet( lItem, link, self.target ); + + Raise_Update( lItem ); + Menu_UpdateRunFlags(); + Menu_JumpToWindow( lItem._link, false, false ); +}; + +void() Nex_Action_SetNormalPanelLink = +{ + String_EntityZone( self, target ); + + self.destroy = Nex_Action_SetNormalPanelLink_Destroy; + self.action = Nex_Action_SetNormalPanelLink_Action; +}; + +// sets the link field of Normal::Panel on reinit +void() Nex_Action_SetLinkOnReinit_Destroy = +{ + String_EntityFree( self, target ); +}; + +void() Nex_Action_SetLinkOnReinitk_Reinit = +{ + String_EntitySet( Menu_GetItem( "Normal::Panel" ), link, self.target ); +}; + +void() Nex_Action_SetLinkOnReinit = +{ + String_EntityZone( self, target ); + + self.destroy = Nex_Action_SetLinkOnReinit_Destroy; + self.reinit = Nex_Action_SetLinkOnReinitk_Reinit; +}; + diff --git a/scmenu/source/mbuiltin.qc b/scmenu/source/mbuiltin.qc new file mode 100644 index 000000000..b316a88ff --- /dev/null +++ b/scmenu/source/mbuiltin.qc @@ -0,0 +1,201 @@ +////////////////////////////////////////////////// +// common cmd +////////////////////////////////////////////////// +// AK FIXME: Create perhaps a special builtin file for the common cmds + +void checkextension(string ext) = #1; + +// error cmds +void error(string err,...) = #2; +void objerror(string err,...) = #3; + +// print + +void print(string text,...) = #4; +void bprint(string text,...) = #5; +void sprint(float clientnum, string text,...) = #6; +void centerprint(string text,...) = #7; + +// vector stuff + +vector normalize(vector v) = #8; +float vlen(vector v) = #9; +float vectoyaw(vector v) = #10; +vector vectoangles(vector v) = #11; + +float random(void) = #12; + +void cmd(string command) = #13; + +// cvar cmds + +float cvar(string name) = #14; +const string str_cvar(string name) = #71; +void cvar_set(string name, string value) = #15; + +void dprint(string text,...) = #16; + +// conversion functions + +string ftos(float f) = #17; +float fabs(float f) = #18; +string vtos(vector v) = #19; +string etos(entity e) = #20; + +float stof(string val,...) = #21; + +entity spawn(void) = #22; +void remove(entity e) = #23; + +entity findstring(entity start, .string _field, string match) = #24; +entity findfloat(entity start, .float _field, float match) = #25; +entity findentity(entity start, .entity _field, entity match) = #25; + +entity findchainstring(.string _field, string match) = #26; +entity findchainfloat(.float _field, float match) = #27; +entity findchainentity(.entity _field, entity match) = #27; + +string precache_file(string file) = #28; +string precache_sound(string sample) = #29; + +void crash(void) = #72; +void coredump(void) = #30; +void stackdump(void) = #73; +void traceon(void) = #31; +void traceoff(void) = #32; + +void eprint(entity e) = #33; +float rint(float f) = #34; +float floor(float f) = #35; +float ceil(float f) = #36; +entity nextent(entity e) = #37; +float sin(float f) = #38; +float cos(float f) = #39; +float sqrt(float f) = #40; +vector randomvec(void) = #41; + +float registercvar(string name, string value, float flags) = #42; // returns 1 if success +float min(float f,...) = #43; +float max(float f,...) = #44; +float bound(float min,float value, float max) = #45; +float pow(float a, float b) = #46; +void copyentity(entity src, entity dst) = #47; + +float fopen(string filename, float mode) = #48; +void fclose(float fhandle) = #49; +string fgets(float fhandle) = #50; +void fputs(float fhandle, string s) = #51; + +float strlen(string s) = #52; +//string strcat(string s1,string s2,...) = #53; +string strcat(string s1, ...) = #53; +string substring(string s, float start, float length) = #54; + +vector stov(string s) = #55; + +string strzone(string s) = #56; +void strunzone(string s) = #57; + +float tokenize(string s) = #58 +string argv(float n) = #59; + +float isserver(void) = #60; +float clientcount(void) = #61; +float clientstate(void) = #62; +void clientcommand(float client, string s) = #63; +void changelevel(string map) = #64; +void localsound(string sample) = #65; +vector getmousepos(void) = #66; +float gettime(void) = #67; +void loadfromdata(string data) = #68; +void loadfromfile(string file) = #69; + +float mod(float val, float m) = #70; + +float search_begin(string pattern, float caseinsensitive, float quiet) = #74; +void search_end(float handle) = #75; +float search_getsize(float handle) = #76; +string search_getfilename(float handle, float num) = #77; + +string chr(float ascii) = #78; + +float etof(entity ent) = #79; +entity ftoe(float num) = #80; + +float validstring(string str) = #81; + +float altstr_count(string str) = #82; +string altstr_prepare(string str) = #83; +string altstr_get(string str, float num) = #84; +string altstr_set(string str, float num, string set) = #85 + +///////////////////////////////////////////////// +// Write* Functions +///////////////////////////////////////////////// +void WriteByte(float data, float dest, float desto) = #401; +void WriteChar(float data, float dest, float desto) = #402; +void WriteShort(float data, float dest, float desto) = #403; +void WriteLong(float data, float dest, float desto) = #404; +void WriteAngle(float data, float dest, float desto) = #405; +void WriteCoord(float data, float dest, float desto) = #406; +void WriteString(string data, float dest, float desto)= #407; +void WriteEntity(entity data, float dest, float desto) = #408; + +////////////////////////////////////////////////// +// Draw funtions +////////////////////////////////////////////////// + +float iscachedpic(string name) = #451; +string precache_pic(string name) = #452; +void freepic(string name) = #453; + +float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) = #454; + +float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) = #455; + +float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) = #456; + +float drawfill(vector position, vector size, vector rgb, float alpha, float flag) = #457; + +void drawsetcliparea(float x, float y, float width, float height) = #458; + +void drawresetcliparea(void) = #459; + +vector drawgetimagesize(string pic) = #460; + +float cin_open(string file, string name) = #461; +void cin_close(string name) = #462; +void cin_setstate(string name, float type) = #463; +float cin_getstate(string name) = #464; + +//////////////////////////////////////////////// +// Menu functions +//////////////////////////////////////////////// + +void setkeydest(float dest) = #601; +float getkeydest(void) = #602; + +void setmousetarget(float trg) = #603; +float getmousetarget(void) = #604; + +float isfunction(string function_name) = #607; +void callfunction(...) = #605; +void writetofile(float fhandle, entity ent) = #606; +vector getresolution(float number) = #608; +string keynumtostring(float keynum) = #609; +string findkeysforcommand(string command) = #610; + +float gethostcachevalue(float type) = #611; +string gethostcachestring(float type, float hostnr) = #612; + +void parseentitydata(entity ent, string data) = #613; + +float stringtokeynum(string key) = #614; + +void resethostcachemasks(void) = #615; +void sethostcachemaskstring(float mask, float fld, string str, float op) = #616; +void sethostcachemasknumber(float mask, float fld, float num, float op) = #617; +void resorthostcache(void) = #618; +void sethostcachesort(float fld, float descending) = #619; +void refreshhostcache(void) = #620; +float gethostcachenumber(float fld, float hostnr) = #621; diff --git a/scmenu/source/menu.qc b/scmenu/source/menu.qc new file mode 100644 index 000000000..7f50d3355 --- /dev/null +++ b/scmenu/source/menu.qc @@ -0,0 +1,132 @@ +/////////////////////////////////////////////// +// Menu Source File +/////////////////////// +// This file belongs to dpmod/darkplaces +// AK contains all menu functions (especially the required ones) +/////////////////////////////////////////////// + +void() m_init = +{ + // init graphic + Gfx_Init(); + + // init cursor + Cursor_Init(); + + Key_Init(); + + // init menu + Menu_Init(); +}; + +// required menu functions +void( float pKey, float pAscii ) m_keydown = +{ + if(!Menu_Active) + return; + + // actually the menu is the only system that needs to react on key events + Menu_Key( pKey, pAscii ); +}; + +void() m_frame = +{ + Timer_Update(); + + HostCache_Update(); + + // graphic frame + Gfx_Update(); + + // cursor frame + Cursor_Update(); + + // menu frame + Menu_Frame(); +}; + +void() m_draw = +{ + if( !Menu_Active ) + return; + + // call m_frame cause draw is the only menu function called once per frame + m_frame(); + + // now the drawing code + Menu_Draw(); + + // draw the cursor on top of the menu + Cursor_Draw(); + + // and now the gfx drawing code (for special fx) + Gfx_Draw(); +}; + +void() m_display = +{ + Menu_Active = true; + + // update isserver and clientstate + gamestatus = 0; + if(isserver()) + gamestatus = gamestatus | GAME_ISSERVER; + if(clientstate() == CS_CONNECTED) + gamestatus = gamestatus | GAME_CONNECTED; + if(cvar("developer")) + gamestatus = gamestatus | GAME_DEVELOPER; + + // let also the snd and gfx know (perhaps for sfx) + Gfx_Display(); + Cursor_Display(); + Key_Display(); + + // let the menu manager know + Menu_PerformReinit(); +}; + +void() m_hide = +{ + Gfx_Hide(); + Cursor_Hide(); + Key_Hide(); + + // let the menu manager know + Menu_Hide(); + + Menu_Active = false; +}; + +void() m_toggle = +{ + Timer_Update(); + + if( Menu_Active ) + m_hide(); + else + m_display(); +}; + +void() m_shutdown = +{ + Timer_Update(); + + // shutdown menu + Menu_Shutdown(); + + // shutdown timer + Timer_Quit(); + + // shutdown key system + Key_Quit(); + + // shutdown cursor + Cursor_Quit(); + + // shutdown graphic + Gfx_Quit(); + + // make sure everything is reset + setkeydest( KEY_GAME ); + setmousetarget( MT_CLIENT ); +}; \ No newline at end of file diff --git a/scmenu/source/menu.qh b/scmenu/source/menu.qh new file mode 100644 index 000000000..02af4da27 --- /dev/null +++ b/scmenu/source/menu.qh @@ -0,0 +1,27 @@ +/////////////////////////////////////////////// +// Menu Header File +/////////////////////// +// This file belongs to dpmod/darkplaces +// AK contains all common constants, etc. +/////////////////////////////////////////////// +// constants + +const float GAME_ISSERVER = 1; +const float GAME_CONNECTED = 2; +const float GAME_DEVELOPER = 4; + +const float INFINITY = 10000000.0; + +// prototypes + +typedef float bool; + +// global vars + +//float time; // important for animations, etc. +bool Menu_Active; // is set when the menu is active + +// updated every time toggle is called +float gamestatus; + +#define USEFUNCTIONS diff --git a/scmenu/source/msys.qc b/scmenu/source/msys.qc new file mode 100644 index 000000000..010f405f8 --- /dev/null +++ b/scmenu/source/msys.qc @@ -0,0 +1,289 @@ +////////////////////////////////////////////////////////// +// sys globals + +entity self; + +///////////////////////////////////////////////////////// +void end_sys_globals; +///////////////////////////////////////////////////////// +// sys fields + +///////////////////////////////////////////////////////// +void end_sys_fields; +///////////////////////////////////////////////////////// +// sys functions + +void() m_init; +void(float keynr, float ascii) m_keydown; +void() m_draw; +void() m_display; // old NG Menu +void() m_toggle; +void() m_hide; // old NG Menu +void() m_shutdown; + +///////////////////////////////////////////////////////// +// sys constants +/////////////////////////// +// key constants + +// +// these are the key numbers that should be passed to Key_Event +// +float K_TAB = 9; +float K_ENTER = 13; +float K_ESCAPE = 27; +float K_SPACE = 32; + +// normal keys should be passed as lowercased ascii + +float K_BACKSPACE = 127; +float K_UPARROW = 128; +float K_DOWNARROW = 129; +float K_LEFTARROW = 130; +float K_RIGHTARROW = 131; + +float K_ALT = 132; +float K_CTRL = 133; +float K_SHIFT = 134; +float K_F1 = 135; +float K_F2 = 136; +float K_F3 = 137; +float K_F4 = 138; +float K_F5 = 139; +float K_F6 = 140; +float K_F7 = 141; +float K_F8 = 142; +float K_F9 = 143; +float K_F10 = 144; +float K_F11 = 145; +float K_F12 = 146; +float K_INS = 147; +float K_DEL = 148; +float K_PGDN = 149; +float K_PGUP = 150; +float K_HOME = 151; +float K_END = 152; + +float K_KP_HOME = 160; +float K_KP_UPARROW = 161; +float K_KP_PGUP = 162; +float K_KP_LEFTARROW = 163; +float K_KP_5 = 164; +float K_KP_RIGHTARROW = 165; +float K_KP_END = 166; +float K_KP_DOWNARROW = 167; +float K_KP_PGDN = 168; +float K_KP_ENTER = 169; +float K_KP_INS = 170; +float K_KP_DEL = 171; +float K_KP_SLASH = 172; +float K_KP_MINUS = 173; +float K_KP_PLUS = 174; + +float K_PAUSE = 255; + +// +// joystick buttons +// +float K_JOY1 = 768; +float K_JOY2 = 769; +float K_JOY3 = 770; +float K_JOY4 = 771; + +// +// aux keys are for multi-buttoned joysticks to generate so they can use +// the normal binding process +// +float K_AUX1 = 772; +float K_AUX2 = 773; +float K_AUX3 = 774; +float K_AUX4 = 775; +float K_AUX5 = 776; +float K_AUX6 = 777; +float K_AUX7 = 778; +float K_AUX8 = 779; +float K_AUX9 = 780; +float K_AUX10 = 781; +float K_AUX11 = 782; +float K_AUX12 = 783; +float K_AUX13 = 784; +float K_AUX14 = 785; +float K_AUX15 = 786; +float K_AUX16 = 787; +float K_AUX17 = 788; +float K_AUX18 = 789; +float K_AUX19 = 790; +float K_AUX20 = 791; +float K_AUX21 = 792; +float K_AUX22 = 793; +float K_AUX23 = 794; +float K_AUX24 = 795; +float K_AUX25 = 796; +float K_AUX26 = 797; +float K_AUX27 = 798; +float K_AUX28 = 799; +float K_AUX29 = 800; +float K_AUX30 = 801; +float K_AUX31 = 802; +float K_AUX32 = 803; + +// +// mouse buttons generate virtual keys +// +float K_MOUSE1 = 512; +float K_MOUSE2 = 513; +float K_MOUSE3 = 514; +float K_MOUSE4 = 515; +float K_MOUSE5 = 516; +float K_MOUSE6 = 517; +float K_MOUSE7 = 518; +float K_MOUSE8 = 519; +float K_MOUSE9 = 520; +float K_MOUSE10 = 521; + +float K_MWHEELDOWN = K_MOUSE4; +float K_MWHEELUP = K_MOUSE5; + +/////////////////////////// +// key dest constants + +float KEY_GAME = 0; +float KEY_MENU = 2; +float KEY_UNKNOWN = 3; + +/////////////////////////// +// file constants + +float FILE_READ = 0; +float FILE_APPEND = 1; +float FILE_WRITE = 2; + +/////////////////////////// +// logical constants (just for completeness) + +float TRUE = 1; +float FALSE = 0; + +/////////////////////////// +// boolean constants + +float true = 1; +float false = 0; + +/////////////////////////// +// msg constants + +float MSG_BROADCAST = 0; // unreliable to all +float MSG_ONE = 1; // reliable to one (msg_entity) +float MSG_ALL = 2; // reliable to all +float MSG_INIT = 3; // write to the init string + +///////////////////////////// +// mouse target constants + +float MT_MENU = 1; +float MT_CLIENT = 2; + +///////////////////////// +// client state constants + +float CS_DEDICATED = 0; +float CS_DISCONNECTED = 1; +float CS_CONNECTED = 2; + +/////////////////////////// +// blend flags + +float DRAWFLAG_NORMAL = 0; +float DRAWFLAG_ADDITIVE = 1; +float DRAWFLAG_MODULATE = 2; +float DRAWFLAG_2XMODULATE = 3; + + +/////////////////////////// +// cvar constants + +float CVAR_SAVE = 1; +float CVAR_NOTIFY = 2; +float CVAR_READONLY = 4; + +/////////////////////////// +// server list constants + +float SLIST_HOSTCACHEVIEWCOUNT = 0; +float SLIST_HOSTCACHETOTALCOUNT = 1; +float SLIST_MASTERQUERYCOUNT = 2; +float SLIST_MASTERREPLYCOUNT = 3; +float SLIST_SERVERQUERYCOUNT = 4; +float SLIST_SERVERREPLYCOUNT = 5; +float SLIST_SORTFIELD = 6; +float SLIST_SORTDESCENDING = 7; + +float SLIST_FIELD_CNAME = 0; +float SLIST_FIELD_PING = 1; +float SLIST_FIELD_GAME = 2; +float SLIST_FIELD_MOD = 3; +float SLIST_FIELD_MAP = 4; +float SLIST_FIELD_NAME = 5; +float SLIST_FIELD_MAXPLAYERS = 6; +float SLIST_FIELD_NUMPLAYERS = 7; +float SLIST_FIELD_PROTOCOL = 8; +float SLIST_FIELD_COUNT = 9; // not a real field (just so you can use it in a for loop + +float SLIST_LEGACY_LINE1 = 1024; +float SLIST_LEGACY_LINE2 = 1025; + +float SLIST_TEST_CONTAINS = 0; +float SLIST_TEST_NOTCONTAIN = 1; +float SLIST_TEST_LESSEQUAL = 2; +float SLIST_TEST_LESS = 3; +float SLIST_TEST_EQUAL = 4; +float SLIST_TEST_GREATER = 5; +float SLIST_TEST_GREATEREQUAL = 6; +float SLIST_TEST_NOTEQUAL = 7; + +float SLIST_MASK_AND = 0; +float SLIST_MASK_OR = 512; + +float NET_CURRENTPROTOCOL = 3; + +//////////////////////////////// +// cinematic action constants + +float CINE_PLAY = 1; +float CINE_LOOP = 2; +float CINE_PAUSE = 3; +float CINE_FIRSTFRAME = 4; +float CINE_RESETONWAKEUP= 5; + +/////////////////////////// +// null entity (actually it is the same like the world entity) + +entity null_entity; + +/////////////////////////// +// error constants + +// file handling +float ERR_CANNOTOPEN = -1; // fopen +float ERR_NOTENOUGHFILEHANDLES = -2; // fopen +float ERR_INVALIDMODE = -3; // fopen +float ERR_BADFILENAME = -4; // fopen + +// drawing functions + +float ERR_NULLSTRING = -1; +float ERR_BADDRAWFLAG = -2; +float ERR_BADSCALE = -3; +float ERR_BADSIZE = ERR_BADSCALE; +float ERR_NOTCACHED = -4; + +/* not supported at the moment +/////////////////////////// +// os constants + +float OS_WINDOWS = 0; +float OS_LINUX = 1; +float OS_MAC = 2; +*/ + diff --git a/scmenu/source/progdefs.h b/scmenu/source/progdefs.h new file mode 100644 index 000000000..d719f326a --- /dev/null +++ b/scmenu/source/progdefs.h @@ -0,0 +1,13 @@ + +/* file generated by qcc, do not modify */ + +typedef struct +{ int pad[28]; + int self; +} globalvars_t; + +typedef struct +{ +} entvars_t; + +#define PROGHEADER_CRC 10020 diff --git a/scmenu/source/progs.src b/scmenu/source/progs.src new file mode 100644 index 000000000..f2211247e --- /dev/null +++ b/scmenu/source/progs.src @@ -0,0 +1,171 @@ +/////////////////////////////////////////////// +// Progs file +/////////////////////// +// This file belongs to dpmod/darkplaces +// AK contains all file names which should be included into menu.dat +// this is absolutly beta +/////////////////////////////////////////////// +// menu.dat destination path +../../menu.dat + +// these are the default qc header files +msys.qc +mbuiltin.qc + +//////////////////////////// +// dpmod-specific menu files +/// + +// Header Files + +menu.qh + +// util functions +util/util.qh +util/altstring.qh +util/rect.qh +util/string.qh +util/text.qh +util/uid.qh +util/property.qh + +// base system +base/timer.qh +base/gfx.qh +base/snd.qh +base/cursor.qh +base/key.qh +base/hostcache.qh + +// main system +system/parser.qh +system/debug.qh +system/isframe.qh +system/mgfx.qh +system/item.qh +system/structure.qh +system/events.qh +system/history.qh +system/gc.qh + +// controls +control/items.qh +control/constants.qh +control/data/data.qh +control/window/windows.qh +control/visual/visual.qh +control/automation/automation.qh +//control/fx/fx.qh + +// custom (game specific) +custom/custom.qh +custom/player/player.qh +custom/creategame/creategame.qh +custom/joingame.qh +custom/key.qh +custom/video.qh + +// Source Files + +// custom (game specific) +custom/quit.qm +custom/option.qm +custom/globalkey.qm +custom/stresstest.qm +custom/visible.qm +custom/color.qm +custom/player.qm +custom/util.qm +custom/creategame.qm +custom/key.qm +custom/video.qm +custom/joingame.qm + +custom/player/avatar.qc +custom/player/name.qc + +custom/creategame/maps.qc +custom/creategame/mods.qc + +custom/visible.qc +custom/key.qc +custom/video.qc +custom/joingame.qc + +// controls +control/automation/automation.qc +control/automation/foreach.qc +control/automation/job.qc + +control/data/base.qc +control/data/container.qc +control/data/cvar.qc +control/data/text.qc +control/data/value.qc +control/data/textswitch.qc +control/data/valueswitch.qc +control/data/fastresync.qc +control/data/textvalue.qc +control/data/texttime.qc +control/data/altstring.qc +control/data/router.qc + +control/window/window.qc +control/window/reference.qc +control/window/layout.qc +control/window/arrangement.qc +control/window/scroll.qc +control/window/eventwindow.qc +control/window/frame.qc + +control/visual/button.qc +control/visual/editbox.qc +control/visual/label.qc +control/visual/multilabel.qc +control/visual/picture.qc +control/visual/rect.qc +control/visual/slider.qc +control/visual/valuebutton.qc +control/visual/floating.qc +control/visual/switchbutton.qc + +//control/fx/vector.qc +//control/fx/float.qc +//control/fx/interpol.qc + +control/cinematic.qc +control/container.qc +control/custom.qc +control/link.qc + +// main system +system/history.qc +system/events.qc +//system/events_.qc +system/event_helper.qc +system/structure.qc +system/mgfx.qc +system/isframe.qc +system/debug.qc +system/parser.qc +system/gc.qc + +// base systems +base/key.qc +base/cursor.qc +base/snd.qc +base/gfx.qc +base/timer.qc +base/hostcache.qc + +// util functions +util/property.qc +util/text.qc +util/uid.qc +util/string.qc +util/rect.qc +util/altstring.qc +util/nfunction.qc + +menu.qc + diff --git a/scmenu/source/system/debug.qc b/scmenu/source/system/debug.qc new file mode 100644 index 000000000..74c0b3eda --- /dev/null +++ b/scmenu/source/system/debug.qc @@ -0,0 +1,164 @@ +// SCMenu +// system/debug.qc + + +/* +=================== +Sys_Debug_Init +=================== +*/ +void() Sys_Debug_Init = +{ + registercvar( SYSTEM_CVAR_DEBUG, ftos( SYSTEM_CVAR_DEBUG_DEFAULT ), 0 ); + registercvar( SYSTEM_CVAR_DEBUG_REF, ftos( SYSTEM_CVAR_DEBUG_REF_DEFAULT ), 0 ); + registercvar( SYSTEM_CVAR_DEBUG_RUNFLAG, ftos( SYSTEM_CVAR_DEBUG_RUNFLAG_DEFAULT ), 0 ); + registercvar( SYSTEM_CVAR_DEBUG_PROCESS, ftos( SYSTEM_CVAR_DEBUG_PROCESS_DEFAULT ), 0 ); + registercvar( SYSTEM_CVAR_DEBUG_MGFX, ftos( SYSTEM_CVAR_DEBUG_MGFX_DEFAULT ), 0 ); + registercvar( SYSTEM_CVAR_DEBUG_STRUCTURE, ftos( SYSTEM_CVAR_DEBUG_STRUCTURE_DEFAULT ), 0 ); + registercvar( SYSTEM_CVAR_DEBUG_PARSER, SYSTEM_CVAR_DEBUG_PARSER_DEFAULT, 0 ); + registercvar( SYSTEM_CVAR_DEBUG_PROCESS_FILTER, SYSTEM_CVAR_DEBUG_PROCESS_FILTER_DEFAULT, 0 ); + registercvar( SYSTEM_CVAR_DEBUG_SOUND, ftos( SYSTEM_CVAR_DEBUG_SOUND_DEFAULT ), 0 ); + registercvar( SYSTEM_CVAR_DEBUG_DUMP_NAMES, "0", 0 ); + registercvar( SYSTEM_CVAR_DEBUG_AREA, ftos( SYSTEM_CVAR_DEBUG_AREA_DEFAULT ), 0 ); + registercvar( SYSTEM_CVAR_DEBUG_STEP, ftos( SYSTEM_CVAR_DEBUG_STEP_DEFAULT ), 0 ); + registercvar( SYSTEM_CVAR_DEBUG_MOUSE, ftos( SYSTEM_CVAR_DEBUG_MOUSE_DEFAULT ), 0 ); +}; + +/* +=================== +Sys_Debug_Frame +=================== +*/ +void() Sys_Debug_Frame = +{ + local float lTemp1, lTemp2; + sys_debug = cvar( SYSTEM_CVAR_DEBUG ); + if( sys_debug ) { + sys_debug_ref = cvar( SYSTEM_CVAR_DEBUG_REF ); + + sys_debug_area = cvar( SYSTEM_CVAR_DEBUG_AREA ); + + sys_debug_sound = cvar( SYSTEM_CVAR_DEBUG_SOUND ); + + sys_debug_structure = cvar( SYSTEM_CVAR_DEBUG_STRUCTURE ); + + sys_debug_mouse = cvar( SYSTEM_CVAR_DEBUG_MOUSE ); + + if( cvar( SYSTEM_CVAR_DEBUG_STEP ) ) { + m_hide(); + print( "Menu: -- Step: Time:", ftos( gettime() ), "\n" ); + } + + sys_debug_runflag = cvar( SYSTEM_CVAR_DEBUG_RUNFLAG ); + // FIXME: evil bug in fteqcc!! dont pass function calls to switches + switch( sys_debug_runflag ) { + case 0: + sys_debug_runflag = false; + break; + case 1: + cvar_set( SYSTEM_CVAR_DEBUG_RUNFLAG, "0" ); + case 2: + sys_debug_runflag = true; + break; + } + + sys_debug_process = cvar( SYSTEM_CVAR_DEBUG_PROCESS ); + switch( sys_debug_process ) { + case 0: + sys_debug_process = false; + break; + case 1: + cvar_set( SYSTEM_CVAR_DEBUG_PROCESS, "0" ); + case 2: + sys_debug_process = true; + break; + } + + sys_debug_mgfx = cvar( SYSTEM_CVAR_DEBUG_MGFX ); + switch( sys_debug_mgfx ) { + case 0: + sys_debug_mgfx = false; + break; + case 1: + cvar_set( SYSTEM_CVAR_DEBUG_MGFX, "0" ); + case 2: + sys_debug_mgfx = true; + break; + } + + lTemp1 = tokenize( str_cvar( SYSTEM_CVAR_DEBUG_PROCESS_FILTER ) ); + sys_debug_process_filter = 0; + for( lTemp2 = 0 ; lTemp2 < lTemp1 ; ++lTemp2 ) + if( argv( lTemp2 ) == "runflag" ) + sys_debug_process_filter = sys_debug_process_filter | MENU_PROCESS_RUNFLAG; + else if( argv( lTemp2 ) == "draw" ) + sys_debug_process_filter = sys_debug_process_filter | MENU_PROCESS_DRAW; + else if( argv( lTemp2 ) == "update" ) + sys_debug_process_filter = sys_debug_process_filter | MENU_PROCESS_UPDATE; + else if( argv( lTemp2 ) == "mouse" ) + sys_debug_process_filter = sys_debug_process_filter | MENU_PROCESS_MOUSE; + else if( argv( lTemp2 ) == "key" ) + sys_debug_process_filter = sys_debug_process_filter | MENU_PROCESS_KEY; + + lTemp1 = tokenize( str_cvar( SYSTEM_CVAR_DEBUG_PARSER ) ); + sys_debug_parser = 0; + for( lTemp2 = 0 ; lTemp2 < lTemp1 ; ++lTemp2 ) + if( argv( lTemp2 ) == "info" ) + sys_debug_parser = sys_debug_parser | PARSER_INFO; + else if( argv( lTemp2 ) == "high" ) + sys_debug_parser = sys_debug_parser | PARSER_HIGH; + else if( argv( lTemp2 ) == "low" ) + sys_debug_parser = sys_debug_parser | PARSER_LOW; + + + } else { + sys_debug_ref = false; + sys_debug_area = false; + sys_debug_sound = false; + sys_debug_runflag = 0; + sys_debug_process = 0; + sys_debug_mgfx = false; + sys_debug_structure = 0; + sys_debug_parser = 0; + sys_debug_process_filter = 0; + sys_debug_mouse = 0; + } + if( cvar( SYSTEM_CVAR_DEBUG_DUMP_NAMES ) ) { + Sys_Debug_DumpNames(); + cvar_set( SYSTEM_CVAR_DEBUG_DUMP_NAMES, "0" ); + } + sys_debug_cursor_localpos = '-1 -1 -1'; +}; + +/* +=================== +Sys_Debug_Draw +=================== +*/ +void() Sys_Debug_Draw = +{ + if( sys_debug_mouse == 1 ) + Cursor_PrintInfo( '1 0 0', strcat( ftos( floor( sys_debug_cursor_localpos_x ) ), + " ", ftos( floor( sys_debug_cursor_localpos_y ) ) ), '9 9 0', '0.8 0.8 0.8', + 1, DRAWFLAG_ADDITIVE ); + else if( sys_debug_mouse == 2 ) + Cursor_PrintInfo( '1 0 0', strcat( ftos( floor( Cursor_Position_x ) ), " ", + ftos( floor( Cursor_Position_y ) ) ), '9 9 0', '0.8 0.8 0.8', 1, DRAWFLAG_ADDITIVE ); +}; + +/* +=================== +Sys_Debug_DumpNames +=================== +*/ +void() Sys_Debug_DumpNames = +{ + local entity lNode; + + print( "Menu: Dumping names..\n" ); + + lNode = null_entity; + while( (lNode = nextent( lNode )) != null_entity ) + print( "Menu: ", etos( lNode ), " <-> ", lNode.name, "\n" ); + print( "\n" ); +}; diff --git a/scmenu/source/system/debug.qh b/scmenu/source/system/debug.qh new file mode 100644 index 000000000..7b24ebc7d --- /dev/null +++ b/scmenu/source/system/debug.qh @@ -0,0 +1,67 @@ +// SCMenu +// system/debug.qh + +// system cvars + +// 0 or 1 +const string SYSTEM_CVAR_DEBUG = "scmenu_debug"; +const string SYSTEM_CVAR_DEBUG_REF = "scmenu_debug_ref"; +const string SYSTEM_CVAR_DEBUG_SOUND = "scmenu_debug_sound"; +const string SYSTEM_CVAR_DEBUG_AREA = "scmenu_debug_area"; +const string SYSTEM_CVAR_DEBUG_STEP = "scmenu_debug_step"; + +// 0 for no info, 1 for local position, 2 for absolute position +const string SYSTEM_CVAR_DEBUG_MOUSE = "scmenu_debug_mouse"; + +// 0 for no output, 1 for medium output, 2 for extensive output +const string SYSTEM_CVAR_DEBUG_STRUCTURE = "scmenu_debug_structure"; + +// NOTE: set it to 1 to make it display the data for one frame, set it to 2 to display it always +const string SYSTEM_CVAR_DEBUG_RUNFLAG = "scmenu_debug_runflag"; +const string SYSTEM_CVAR_DEBUG_PROCESS = "scmenu_debug_process"; +const string SYSTEM_CVAR_DEBUG_MGFX = "scmenu_debug_mgfx"; + +// parser filter, possible values: info high low +const string SYSTEM_CVAR_DEBUG_PARSER = "scmenu_debug_parser"; + +// process_filter, possible values: runflag update draw mouse key +const string SYSTEM_CVAR_DEBUG_PROCESS_FILTER = "scmenu_debug_process_filter"; + +// dump item names +const string SYSTEM_CVAR_DEBUG_DUMP_NAMES = "scmenu_dumpnames"; + +const float SYSTEM_CVAR_DEBUG_DEFAULT = 0; +const float SYSTEM_CVAR_DEBUG_REF_DEFAULT = 0; +const float SYSTEM_CVAR_DEBUG_RUNFLAG_DEFAULT = 0; +const float SYSTEM_CVAR_DEBUG_PROCESS_DEFAULT = 0; +const float SYSTEM_CVAR_DEBUG_MGFX_DEFAULT = 0; +const float SYSTEM_CVAR_DEBUG_STRUCTURE_DEFAULT = 0; +const string SYSTEM_CVAR_DEBUG_PARSER_DEFAULT = ""; +const string SYSTEM_CVAR_DEBUG_PROCESS_FILTER_DEFAULT= ""; +const float SYSTEM_CVAR_DEBUG_SOUND_DEFAULT = 0; +const float SYSTEM_CVAR_DEBUG_AREA_DEFAULT = 0; +const float SYSTEM_CVAR_DEBUG_STEP_DEFAULT = 0; +const float SYSTEM_CVAR_DEBUG_MOUSE_DEFAULT = 0; + +bool sys_debug; +bool sys_debug_sound; +bool sys_debug_ref; +bool sys_debug_area; +bool sys_debug_runflag; +bool sys_debug_process; +bool sys_debug_mgfx; +float sys_debug_mouse; +float sys_debug_structure; +float sys_debug_parser; + +float sys_debug_process_filter; + +vector sys_debug_cursor_localpos; + +void() Sys_Debug_Init; +void() Sys_Debug_Frame; +void() Sys_Debug_Draw; + +void() Sys_Debug_DumpNames; + + diff --git a/scmenu/source/system/event_helper.qc b/scmenu/source/system/event_helper.qc new file mode 100644 index 000000000..554f98814 --- /dev/null +++ b/scmenu/source/system/event_helper.qc @@ -0,0 +1,290 @@ +// DP/Nex menu +// system/events.qc + +// raise function +/* template + +void( entity pEntity ) Raise_x = +{ + local entity lOld; + if( !pEntity._y ) + return; + + lOld = self; + self = pEntity; + self._y(); + self = lOld; +}; +*/ + +void( entity pEntity ) Raise_Reinit = +{ + local entity lOld; + if(!pEntity._reinit) + return; + + lOld = self; + self = pEntity; + self._reinit(); + self = lOld; +}; + +void( entity pEntity ) Raise_Destroy = +{ + local entity lOld; + if( !pEntity._destroy ) + return; + + lOld = self; + self = pEntity; + self._destroy(); + self = lOld; +}; + +bool( entity pEntity, float pKey, float pAscii) Raise_Key = +{ + local entity lOld; + local bool lResult; + + if( !pEntity._key ) + return false; + + lOld = self; + self = pEntity; + lResult = self._key( pKey, pAscii ); + self = lOld; + + return lResult; +}; + +void( entity pEntity ) Raise_Draw = +{ + local entity lOld; + if( !pEntity._draw ) + return; + + lOld = self; + self = pEntity; + self._draw(); + self = lOld; +}; + +void( entity pEntity ) Raise_MouseEnter = +{ + local entity lOld; + if( !pEntity._mouseEnter ) + return; + + lOld = self; + self = pEntity; + self._mouseEnter(); + self = lOld; +}; + +void( entity pEntity ) Raise_MouseLeave = +{ + local entity lOld; + if( !pEntity._mouseLeave ) + return; + + lOld = self; + self = pEntity; + self._mouseLeave(); + self = lOld; +}; + +void( entity pEntity ) Raise_Update = +{ + local entity lOld; + if( !pEntity._update ) + return; + + lOld = self; + self = pEntity; + self._update(); + self = lOld; +}; + +void( entity pEntity, bool pSelect, bool pUser ) Raise_Select = +{ + local entity lOld; + if( !pEntity._select ) + return; + + lOld = self; + self = pEntity; + self._select( pSelect, pUser ); + self = lOld; +}; + +// safe call control function functions +// default control functions +/* template + +void() CtCall_x = +{ + if( self.y ) + self.y(); +}; + +*/ +void() CtCall_Init = +{ + if( self.init ) + self.init(); +}; + +void() CtCall_Reinit = +{ + if( self.reinit ) + self.reinit(); +}; + +void() CtCall_Destroy = +{ + if( self.destroy ) + self.destroy(); +}; + +bool( float pKey, float pAscii ) CtCall_Key = +{ + if( self.key ) + return self.key( pKey, pAscii ); + return false; +}; + +void() CtCall_Draw = +{ + if( self.draw ) + self.draw(); +}; + +void() CtCall_MouseEnter = +{ + if( self.mouseEnter ) + self.mouseEnter(); +}; + +void() CtCall_MouseLeave = +{ + if( self.mouseLeave ) + self.mouseLeave(); +}; + +void() CtCall_Action = +{ + if( self.action ) + self.action(); +}; + +void() CtCall_Update = +{ + if( self.update ) + self.update(); +} + +void( bool pSelect, bool pUser ) CtCall_Select = +{ + if( self.select ) + self.select( pSelect, pUser ); +}; + +// default control functions +/* template (expect DefCt_Key) + +void(void) defct_x = +{ + CtCall_x(); +}; + +*/ +// defct_init not needed cause its the same like the type function + +void() DefCt_Reinit = +{ +}; + +void() DefCt_Destroy = +{ +}; + +bool( float pKey, float pAscii ) DefCt_Key = +{ + return false; +}; + +void() DefCt_Draw = +{ +}; + +void() DefCt_MouseEnter = +{ +}; + +void() DefCt_MouseLeave = +{ +}; + +void() DefCt_Action = +{ +}; + +void( float pSelect, bool pUser ) DefCt_Select = +{ +}; + +void() DefCt_Update = +{ +}; + +// default key function +/*void(float keynr, float ascii) def_keyevent = +{ + if(keynr == K_ESCAPE) + { + // move up to the parent + menu_selectup(); + } else if(keynr == K_LEFTARROW || keynr == K_UPARROW) + { + // move to the previous element + menu_loopprev(); + + if(Menu_ActiveItem == self) + { + if(self._prev) + { + Menu_ActiveItem = self._prev; + menu_selectdown(); + if(Menu_ActiveItem != self._prev) + { + return; + } + } + Menu_ActiveItem = self; + } + } else if(keynr == K_RIGHTARROW || keynr == K_DOWNARROW) + { + // move to the next element + menu_loopnext(); + + if(Menu_ActiveItem == self) + { + if(self._next) + { + Menu_ActiveItem = self._next; + menu_selectdown(); + if(Menu_ActiveItem != self._next) + { + return; + } + } + Menu_ActiveItem = self; + } + } else if(keynr == K_ENTER || keynr == K_MOUSE1) + { + if(self._action) + self._action(); + // move to the child menu + menu_selectdown(); + } +};*/ diff --git a/scmenu/source/system/events.qc b/scmenu/source/system/events.qc new file mode 100644 index 000000000..8c8898043 --- /dev/null +++ b/scmenu/source/system/events.qc @@ -0,0 +1,435 @@ +// DP/Nex menu +// system/events.qc + +// debug process output functions +bool _menu_process_filtered; +void( float pMode, float pSelectState ) _Menu_Process_Debug_Filter = +{ + if( !sys_debug_process ) + _menu_process_filtered = false; + else if( sys_debug_process_filter ) + _menu_process_filtered = (pMode & sys_debug_process_filter); + else + _menu_process_filtered = true; + if( _menu_process_filtered == MENU_PROCESS_MOUSE && pSelectState == MENU_SELECT_NEVER ) + _menu_process_filtered = false; +}; + +#ifdef USEFUNCTIONS +void( string pText ) _Menu_Process_Debug_Print = +{ + if( _menu_process_filtered ) + print( pText ); +}; +#else +#define _Menu_Process_Debug_Print(pText) if( _menu_process_filtered ) print( pText ) +#endif + +// process stacks + +void() Menu_Process_Setup = +{ + Menu_Origin = '0 0 0'; + Menu_Clip_Position = '0 0 0'; + Menu_Clip_Size = '0 0 0'; +}; + +void( entity pItem ) _Menu_Env_LoadClipArea +{ + Menu_Clip_Position = pItem._cache_clip_pos; + Menu_Clip_Size = pItem._cache_clip_size; + + if( sys_debug_mgfx && _menu_process_filtered ) + print( "MGFX Loaded clip area = (", vtos( Menu_Clip_Position ), "; ", vtos( Menu_Clip_Size ), ")\n" ); +}; + +void( entity pItem ) _Menu_Env_LoadOrigin = +{ + Menu_Origin = pItem._cache_origin; + Menu_Cursor_Position = Cursor_Position - Menu_Origin; + + if( sys_debug_mgfx && _menu_process_filtered ) + print( "MGFX Loaded org = ", vtos( Menu_Origin ), "\n" ); +}; + +void( entity pItem ) _Menu_Env_Reload = +{ + Menu_Origin = pItem._cache_origin; + Menu_Cursor_Position = Cursor_Position - Menu_Origin; + Menu_Clip_Position = pItem._cache_clip_pos; + Menu_Clip_Size = pItem._cache_clip_size; + + if( sys_debug_mgfx && _menu_process_filtered ) + print( "MGFX Reloaded env for: org = ", vtos( Menu_Origin ), "; clip area = (", vtos( Menu_Clip_Position ), "; ", vtos( Menu_Clip_Size ), ")\n" ); +}; + +void() _MGX_SetClipArea = +{ + if( Menu_Clip_Position == '0 0 0' && Menu_Clip_Size == '0 0 0' ) + Gfx_ResetClipArea(); + else + Gfx_SetClipArea( Menu_Clip_Position_x, Menu_Clip_Position_y, Menu_Clip_Size_x, Menu_Clip_Size_y ); +}; + +void( entity pItem ) _Menu_Env_SetupClipArea +{ + local vector lDelta, lPos, lSize; + + lPos = pItem.pos; + lSize = pItem.size; + if( lPos != '0 0 0' || lSize != '0 0 0' ) { + if( (Menu_Clip_Position != '0 0 0' || Menu_Clip_Size != '0 0 0') ) { + lPos = Menu_Origin + lPos; + lDelta = Util_GetClipDelta( lPos, Menu_Clip_Position, Menu_Clip_Size ); + lPos = lPos + lDelta; + lSize = Util_ClipRect( lPos, lSize - lDelta, Menu_Clip_Position, Menu_Clip_Size ); + } + + Menu_Clip_Position = lPos; + Menu_Clip_Size = lSize; + } + pItem._cache_clip_pos = Menu_Clip_Position; + pItem._cache_clip_size = Menu_Clip_Size; + + if( sys_debug_mgfx && _menu_process_filtered ) { + print( "MGFX Setup clip area: (", vtos( pItem.pos ), "; ", vtos( pItem.size ) ); + print( ") clipped to (", vtos( Menu_Clip_Position ), "; ", vtos( Menu_Clip_Size ), ")\n" ); + } +}; + +void( entity pItem ) _Menu_Env_SetupOrigin = +{ + Menu_Origin = Menu_Origin + pItem.origin + pItem.pos; + pItem._cache_origin = Menu_Origin; + + if( sys_debug_mgfx && _menu_process_filtered ) + print( "MGFX Setup org = ", vtos( Menu_Origin ), "\n" ); +}; + +void( entity pItem ) _Menu_ProcessRunFlag = +{ + local entity lChild; + + _Menu_Process_Debug_Print( strcat( "R ", pItem.name, "\n" ) ); + + // setup the cache and the Menu_* variables + _Menu_Env_SetupClipArea( pItem ); + + Menu_SetRunFlag( pItem ); + + // we adjust the origin for the children + _Menu_Env_SetupOrigin( pItem ); + + for( lChild = pItem._child ; lChild ; lChild = lChild._next ) { + Menu_InheritRunFlag( pItem, lChild ); + _Menu_ProcessRunFlag( lChild ); + // reload the cached state + _Menu_Env_Reload( pItem ); + } +}; + +void( entity pItem ) _Menu_ProcessDraw = +{ + local entity lChild; + + _Menu_Process_Debug_Print( strcat( "D ", pItem.name, " " ) ); + + if( !Menu_IsVisible( pItem ) ) { + _Menu_Process_Debug_Print( "Failed (Not visible)\n" ); + return; + } + _Menu_Process_Debug_Print( "\n" ); + + _Menu_Env_LoadClipArea( pItem ); + _MGX_SetClipArea(); + + Raise_Draw( pItem ); + + _Menu_Env_LoadOrigin( pItem ); + for( lChild = pItem._child ; lChild ; lChild = lChild._next ) { + _Menu_ProcessDraw( lChild ); + // reload old state + _Menu_Env_Reload( pItem ); + _MGX_SetClipArea(); + } +}; + +void( entity pItem ) _Menu_ProcessUpdate = +{ + local entity lChild; + + _Menu_Process_Debug_Print( strcat( "U ", pItem.name, " " ) ); + + if( Menu_HasRunFlag( pItem, RUNFLAG_CHILDDRAWONLY ) ) { + _Menu_Process_Debug_Print( "Failed (RUNFLAG_CHILDDRAWONLY)\n" ); + return; + } + + _Menu_Env_LoadClipArea( pItem ); + Raise_Update( pItem ); + + if( Menu_HasRunFlag( pItem, RUNFLAG_HIDDEN ) ) { + _Menu_Process_Debug_Print( "Aborted branching (RUNFLAG_HIDDEN)\n" ); + return; + } + _Menu_Process_Debug_Print( "\n" ); + + _Menu_Env_LoadOrigin( pItem ); + for( lChild = pItem._child ; lChild ; lChild = lChild._next ) { + _Menu_ProcessUpdate( lChild ); + _Menu_Env_Reload( lChild ); + } +}; + +void( entity pItem, float pSelectMode ) _Menu_ProcessMouse = +{ + local entity lChild; + + if( _menu_process_filtered ) { + print( "M " ); + switch( pSelectMode ) { + case MENU_SELECT_SELECTABLE: + print( "S " ); + break; + case MENU_SELECT_ALWAYS: + print( "A " ); + break; + case MENU_SELECT_NEVER: + print( "N " ); + break; + } + print( pItem.name, " " ); + } + + if( !Menu_IsVisible( pItem ) ) { + _Menu_Process_Debug_Print( "Failed (Not visible)\n" ); + return; + } + + _Menu_Env_LoadClipArea( pItem ); + // check if the mouse is even in the clip area + if( Util_InRect( Cursor_Position, Menu_Clip_Position, Menu_Clip_Size ) || + ( Menu_Clip_Position == '0 0 0' && Menu_Clip_Size == '0 0 0' ) ) { + pItem._runFlag = pItem._runFlag | RUNFLAG_MOUSEINAREA; + + if( !Menu_HasRunFlag( pItem, RUNFLAG_HADMOUSE ) && Menu_HasEvents( pItem ) ) + Raise_MouseEnter( pItem ); + if( pSelectMode != MENU_SELECT_NEVER && Menu_HasFlag( pItem, FLAG_SEALOFFMOUSE ) ) + Menu_ActiveItem = null_entity; + if( ( pSelectMode == MENU_SELECT_ALWAYS ) || + ( Menu_IsSelectable( pItem ) && pSelectMode == MENU_SELECT_SELECTABLE ) ) + Menu_ActiveItem = pItem; + } else { // if the mouse isnt in the clip area, neither the children will be! + if( Menu_HasRunFlag( pItem, RUNFLAG_HADMOUSE ) && Menu_HasEvents( pItem ) ) + Raise_MouseLeave( pItem ); + _Menu_Process_Debug_Print( "Aborted branching (Outside the clip area)\n" ); + return; + } + _Menu_Process_Debug_Print( "\n" ); + + _Menu_Env_LoadOrigin( pItem ); + for( lChild = pItem._child ; lChild ; lChild = lChild._next ) { + if( !Menu_HasRunFlag( pItem, RUNFLAG_CHILDDRAWUPDATEONLY ) || !Menu_HasRunFlag( pItem, RUNFLAG_CHILDDRAWONLY ) ) + _Menu_ProcessMouse( lChild, pSelectMode ); + else + _Menu_ProcessMouse( lChild, MENU_SELECT_NEVER ); + _Menu_Env_Reload( pItem ); + } +}; + +float( float pRetValue ) _Menu_Process_Debug_Return = +{ + if( _menu_process_filtered ) + switch( pRetValue ) { + case MENU_EVENT_NORMAL: + case MENU_EVENT_CONTINUE: + print( "MENU_EVENT_CONTINUE\n" ); + break; + case MENU_EVENT_RAISEPARENT: + print( "MENU_EVENT_RAISEPARENT\n" ); + break; + case MENU_EVENT_PROCESSED: + print( "MENU_EVENT_PROCESSED\n" ); + break; + } + + return pRetValue; +}; + +float( entity pItem, float pKey, float pAscii ) _Menu_ProcessKey = +{ + local entity lChild; + local float lResult; + + _Menu_Process_Debug_Print( strcat( "K ", ftos( pKey ), " ", pItem.name, " " ) ); + if( Menu_HasRunFlag( pItem, RUNFLAG_CHILDDRAWUPDATEONLY ) || Menu_HasRunFlag( pItem, RUNFLAG_CHILDDRAWONLY ) ) + return _Menu_Process_Debug_Return( MENU_EVENT_CONTINUE ); + + _Menu_Env_LoadClipArea( pItem ); + + if( Menu_ActiveItem == pItem ) { + if( Raise_Key( pItem, pKey, pAscii ) ) + lResult = MENU_EVENT_PROCESSED; + else + lResult = MENU_EVENT_RAISEPARENT; + + return _Menu_Process_Debug_Return( lResult ); + } + + _Menu_Env_LoadOrigin( pItem ); + for( lChild = pItem._child ; lChild ; lChild = lChild._next ) { + lResult = _Menu_ProcessKey( lChild, pKey, pAscii ); + _Menu_Env_Reload( pItem ); + + if( lResult == MENU_EVENT_PROCESSED ) + return _Menu_Process_Debug_Return( MENU_EVENT_PROCESSED ); + else if( lResult == MENU_EVENT_RAISEPARENT ) + if( Raise_Key( pItem, pKey, pAscii ) ) + return _Menu_Process_Debug_Return( MENU_EVENT_PROCESSED ); + else + return _Menu_Process_Debug_Return( MENU_EVENT_RAISEPARENT ); + } + + return _Menu_Process_Debug_Return( MENU_EVENT_CONTINUE ); +}; + +float( entity pItem, float pMode, float pSelectMode, float pKey, float pAscii ) Menu_Process = +{ + local vector lSize, lPos, lOrigin; + local float lResult; + + lSize = Menu_Clip_Size; + lPos = Menu_Clip_Position; + lOrigin = Menu_Origin; + + _Menu_Process_Debug_Filter( pMode, pSelectMode ); + + lResult = 0; + switch( pMode ) { + case MENU_PROCESS_RUNFLAG: + _Menu_ProcessRunFlag( pItem ); + break; + case MENU_PROCESS_UPDATE: + _Menu_ProcessUpdate( pItem ); + break; + case MENU_PROCESS_DRAW: + _Menu_ProcessDraw( pItem ); + break; + case MENU_PROCESS_MOUSE: + _Menu_ProcessMouse( pItem, pSelectMode ); + break; + case MENU_PROCESS_KEY: + lResult = _Menu_ProcessKey( pItem, pKey, pAscii ); + break; + } + + Menu_Clip_Size = lSize; + Menu_Clip_Position = lPos; + Menu_Origin = lOrigin; + Menu_Cursor_Position = Cursor_Position - Menu_Origin; + if( pMode == MENU_PROCESS_DRAW ) + _MGX_SetClipArea(); + + return lResult; +}; + +void() Menu_Frame = +{ + Sys_Debug_Frame(); + + Menu_UpdateRunFlags(); + // process the update event + Menu_Process_Setup(); + Menu_ProcessUpdate( Menu_ActiveWindow, MENU_PROCESS_UPDATE ); + + Menu_Process_Setup(); + // if mouse was moved, select an item + if( Cursor_Relative != '0 0 0' ) { + local entity lOld; + + lOld = Menu_ActiveItem; + Menu_ProcessMouse( Menu_ActiveWindow, MENU_SELECT_SELECTABLE ); + + if( !Menu_ActiveItem ) + Menu_ActiveItem = lOld; + else if( lOld != Menu_ActiveItem ) { + Raise_Select( lOld, false, true ); + Raise_Select( Menu_ActiveItem, true, true ); + } + } else // just update mouseinarea + Menu_ProcessMouse( Menu_ActiveWindow, MENU_SELECT_NEVER ); + + Menu_CollectGarbage( false ); +} + +void() Menu_Draw = +{ + // if Menu_ActiveWindow is visible loop though it + if( Menu_IsVisible( Menu_ActiveWindow ) ) + { + Menu_Process_Setup(); + Menu_ProcessDraw( Menu_ActiveWindow ); + } + + Sys_Debug_Draw(); +}; + +void( float pKey, float pAscii) Menu_Key = +{ + // is a keyhook set ? + if( Menu_KeyHook != Util_NullFunction ) { + // call it + Menu_KeyHook( pKey, pAscii ); + return; + } + // before calling the current keydown functions, process the mouse again + // to make sure the correct item is called + // (except mouse wheel up and down) + // if the mouse doesnt point to an item, there wont be a reaction on the clicking + if(K_MOUSE1 <= pKey && pKey <= K_MOUSE10) { + local entity lOld; + + lOld = Menu_ActiveItem; + Menu_ActiveItem = null_entity; + Menu_ProcessMouse( Menu_ActiveWindow, MENU_SELECT_SELECTABLE ); + + if( !Menu_ActiveItem ) { + Menu_ActiveItem = lOld; + return; + } else if( lOld != Menu_ActiveItem ) { + Raise_Select( lOld, false, true ); + Raise_Select( Menu_ActiveItem, true, true ); + } + } + + // call current selected keydown function + // if nothing is selected -> window has no items -> call window key + if(Menu_ActiveItem == null_entity) + Menu_Reselect( false ); + + if( ( !Menu_IsSelectable( Menu_ActiveItem ) && Menu_ActiveItem != Menu_ActiveWindow ) || + Menu_ProcessKey( Menu_ActiveWindow, pKey, pAscii ) != MENU_EVENT_PROCESSED ) + // If it goes really wrong: + if( pKey == K_ESCAPE ) + if( cvar( "developer" ) ) + error( " K_ESCAPE wasnt processed!\n" ); + else { + Menu_Toggle(); + cmd( "menu_restart\n" ); + } + else if( cvar( "developer" ) ) { + print( " Key ", ftos( pKey ), " ('" ); + print( chr( pAscii ), "') wasn't processed!\n" ); + } +}; + +bool() Menu_Toggle = +{ + // only let the qc toggle the menu if we are ingame or a developer + if( gamestatus & GAME_CONNECTED || cvar( "developer" ) ) { + // then allow toggling + m_hide(); + return true; + } else + return false; +}; diff --git a/scmenu/source/system/events.qh b/scmenu/source/system/events.qh new file mode 100644 index 000000000..669c031ac --- /dev/null +++ b/scmenu/source/system/events.qh @@ -0,0 +1,56 @@ +// DP/Nex Menu +// system/events.qh + +// menu_processmous states +enum { + MENU_SELECT_SELECTABLE, + MENU_SELECT_ALWAYS, + MENU_SELECT_NEVER +}; + +enum { + MENU_EVENT_NORMAL, + MENU_EVENT_CONTINUE = 0, + MENU_EVENT_RAISEPARENT, + MENU_EVENT_PROCESSED +}; + +enumflags { //enumflags because of the debug filter + MENU_PROCESS_RUNFLAG, + MENU_PROCESS_UPDATE, + MENU_PROCESS_DRAW, + MENU_PROCESS_MOUSE, + MENU_PROCESS_KEY +}; + +// used to build up the local coord system +vector Menu_Cursor_Position; + +// key hook - only as long as there is no history change or the menu is closed +entity Menu_KeyHook_Target; +var void( float pKey, float pAscii ) Menu_KeyHook; + +/////////////// +// prototypes +/// + +void() Menu_Frame; +void() Menu_Draw; +void(float pKey, float pAscii) Menu_Key; + +// decide whether to toggle the menu +bool() Menu_Toggle; + +void() Menu_Process_Setup; + +float( entity pItem, float pMode, float pSelectState, float pKey, float pAscii ) Menu_Process; +#define _Menu_Process(item,mode) Menu_Process( item, mode, 0, 0, 0 ) +#define Menu_ProcessDraw(item) _Menu_Process( item, MENU_PROCESS_DRAW ) +#define Menu_ProcessUpdate(item) _Menu_Process( item, MENU_PROCESS_UPDATE ) +#define Menu_ProcessRunFlag(item) _Menu_Process( item, MENU_PROCESS_RUNFLAG ) +#define Menu_ProcessMouse(item,select) Menu_Process( item, MENU_PROCESS_MOUSE, select, 0, 0 ) +#define Menu_ProcessKey(item,key,ascii) Menu_Process( item, MENU_PROCESS_KEY, 0, key, ascii ) + + + + diff --git a/scmenu/source/system/events_.qc b/scmenu/source/system/events_.qc new file mode 100644 index 000000000..82f01dc0d --- /dev/null +++ b/scmenu/source/system/events_.qc @@ -0,0 +1,419 @@ +// DP/Nex menu +// system/events.qc + +// process stacks + +void() Menu_Process_Setup = +{ + + Menu_Origin = '0 0 0'; + Menu_Clip_Position = '0 0 0'; + Menu_Clip_Size = '0 0 0'; + + Gfx_ResetClipArea(); +} + +void( vector pOrigin ) _Menu_Origin_Push = +{ + Menu_Origin = Menu_OrgToMen( pOrigin ); + + if( _menu_process_filtered ) { + print( "MGFX Pushed origin: ", vtos( pOrigin ), " Absolute ", vtos( Menu_Origin ), "\n" ); + //print( "MGFX Pushed origin: ", vtos( pOrigin ), " Absolute " ); + //print( vtos( Menu_Origin ), "\n" ); + } + + Menu_Cursor_Position = Cursor_Position - Menu_Origin; +}; + +void( vector pOldOrigin ) _Menu_Origin_Pop = +{ + Menu_Origin = pOldOrigin; + + if( _menu_process_filtered ) + print( "MGFX Popped origin for origin: ", vtos( Menu_Origin ), "\n" ); + + Menu_Cursor_Position = Cursor_Position - Menu_Origin; +}; + +void( vector pPos, vector pSize ) _Menu_Clip_Push = +{ + local vector lDelta; + + if( pPos != '0 0 0' || pSize != '0 0 0' ) { + if( (Menu_Clip_Position != '0 0 0' || Menu_Clip_Size != '0 0 0') ) { + pPos = Menu_OrgToMen( pPos ); + lDelta = Util_GetClipDelta( pPos, Menu_Clip_Position, Menu_Clip_Size ); + pPos = pPos + lDelta; + pSize = Util_ClipRect( pPos, pSize - lDelta, Menu_Clip_Position, Menu_Clip_Size ); + } + + Menu_Clip_Position = pPos; + Menu_Clip_Size = pSize; + Gfx_SetClipArea( Menu_Clip_Position_x, Menu_Clip_Position_y, Menu_Clip_Size_x, Menu_Clip_Size_y ); + } + + if( _menu_process_filtered ) { + print( "MGFX Pushed clipper: ", vtos( pPos ), " " ); + print( vtos( pSize ) ); + print( " Clipped to: ", vtos( Menu_Clip_Position ), " " ); + print( vtos( Menu_Clip_Size),"\n" ); + } +}; + +void( vector pOldPos, vector pOldSize ) _Menu_Clip_Pop = +{ + Menu_Clip_Position = pOldPos; + Menu_Clip_Size = pOldSize; + + if( sys_debug_mgfx ) { + print( "MGFX Popped clipper for clip area: ", vtos( Menu_Clip_Position ), " " ); + print( vtos( Menu_Clip_Size ), "\n" ); + } + + if( Menu_Clip_Position == '0 0 0' && Menu_Clip_Size == '0 0 0' ) + Gfx_ResetClipArea(); + else + Gfx_SetClipArea( Menu_Clip_Position_x, Menu_Clip_Position_y, Menu_Clip_Size_x, Menu_Clip_Size_y ); +}; + +// debug process functions +bool _menu_process_filtered; +void( float pMode, float pSelectState ) _Menu_Process_Debug_Filter = +{ + if( !sys_debug_process ) + _menu_process_filtered = false; + else if( sys_debug_process_filter ) + _menu_process_filtered = (pMode & sys_debug_process_filter); + else + _menu_process_filtered = true; + if( _menu_process_filtered == MENU_PROCESS_MOUSE && pSelectState == MENU_SELECT_NEVER ) + _menu_process_filtered = false; +}; + +void( string pText ) _Menu_Process_Debug_Print = +{ + if( _menu_process_filtered ) + print( pText ); +}; + +void( entity pItem, float pMode, float pSelectState, float pKey, float pAscii ) _Menu_Process_Debug_Header = +{ + if( sys_debug_process && _menu_process_filtered ) { + switch( pMode ) { + case MENU_PROCESS_RUNFLAG: + print( "R " ); + break; + case MENU_PROCESS_UPDATE: + print( "U " ); + break; + case MENU_PROCESS_DRAW: + print( "D " ); + break; + case MENU_PROCESS_MOUSE: + print( "M " ); + switch( pSelectState ) { + case MENU_SELECT_SELECTABLE: + print( "S " ); + break; + case MENU_SELECT_ALWAYS: + print( "A " ); + break; + case MENU_SELECT_NEVER: + print( "N " ); + break; + } + break; + case MENU_PROCESS_KEY: + print( "K " ); + print( ftos( pKey ), " " ); + break; + default: + print( "~ " ); + } + print( pItem.name, " " ); + } +}; + +void( float pRetValue ) _Menu_Process_Debug_Return = +{ + if( sys_debug_process && _menu_process_filtered ) + switch( pRetValue ) { + case MENU_EVENT_NORMAL: + case MENU_EVENT_CONTINUE: + print( "MENU_EVENT_CONTINUE\n" ); + break; + case MENU_EVENT_RAISEPARENT: + print( "MENU_EVENT_RAISEPARENT\n" ); + break; + case MENU_EVENT_PROCESSED: + print( "MENU_EVENT_PROCESSED\n" ); + break; + } +}; + +// main process functions +float( entity pItem, float pMode, float pSelectState, float pKey, float pAscii ) Menu_Process = +{ + local entity lChild; + local bool lContinue; + local float lResult; + // the new clip and origin stack + local vector lOldOrigin, lOldClipPos, lOldClipSize; + + // set the debug filter + _Menu_Process_Debug_Filter( pMode, pSelectState ); + + _Menu_Process_Debug_Header( pItem, pMode, pSelectState, pKey, pAscii ); + + // adjust the clip area + lOldClipPos = Menu_Clip_Position; + lOldClipSize = Menu_Clip_Size; + _Menu_Clip_Push( pItem.pos, pItem.size ); + + // test if its necessary to do anything + lContinue = false; + lResult = MENU_EVENT_NORMAL; + switch( pMode ) { + case MENU_PROCESS_RUNFLAG: + lContinue = true; + break; + case MENU_PROCESS_MOUSE: + if( !Menu_IsVisible( pItem ) ) + break; + lContinue = true; + break; + case MENU_PROCESS_DRAW: + if( !Menu_IsVisible( pItem ) ) + break; + lContinue = true; + break; + case MENU_PROCESS_UPDATE: + if( Menu_HasRunFlag( pItem, RUNFLAG_CHILDDRAWONLY ) ) + break; + lContinue = true; + break; + case MENU_PROCESS_KEY: + if( !Menu_HasEvents( pItem ) ) + break; + lContinue = true; + break; + default: + error( "Bad pMode in Menu_Processs!" ); + break; + } + if( !lContinue ) { + _Menu_Process_Debug_Print( "Condition failed\n" ); + _Menu_Clip_Pop( lOldClipPos, lOldClipSize ); + return lResult; + } + + // process the events for this item + lContinue = true; + switch( pMode ) { + case MENU_PROCESS_RUNFLAG: + Menu_SetRunFlag( pItem ); + break; + case MENU_PROCESS_UPDATE: + Raise_Update( pItem ); + if( Menu_HasRunFlag( pItem, RUNFLAG_HIDDEN ) ) + lContinue = false; + break; + case MENU_PROCESS_DRAW: + Raise_Draw( pItem ); + break; + case MENU_PROCESS_MOUSE: + // check if the mouse is even in the clip area + if( Util_InRect( Cursor_Position, Menu_Clip_Position, Menu_Clip_Size ) || + ( Menu_Clip_Position == '0 0 0' && Menu_Clip_Size == '0 0 0' ) ) { + pItem._runFlag = pItem._runFlag | RUNFLAG_MOUSEINAREA; + + if( !Menu_HasRunFlag( pItem, RUNFLAG_HADMOUSE ) && Menu_HasEvents( pItem ) ) + Raise_MouseEnter( pItem ); + if( pSelectState != MENU_SELECT_NEVER && Menu_HasFlag( pItem, FLAG_SEALOFFMOUSE ) ) + Menu_ActiveItem = null_entity; + if( ( pSelectState == MENU_SELECT_ALWAYS ) || + ( Menu_IsSelectable( pItem ) && pSelectState == MENU_SELECT_SELECTABLE ) ) + Menu_ActiveItem = pItem; + } else if( Menu_HasRunFlag( pItem, RUNFLAG_HADMOUSE ) && Menu_HasEvents( pItem ) ) + Raise_MouseLeave( pItem ); + break; + case MENU_PROCESS_KEY: + if( Menu_ActiveItem == pItem ) { + lContinue = false; + if( Raise_Key( pItem, pKey, pAscii ) ) + lResult = MENU_EVENT_PROCESSED; + else + lResult = MENU_EVENT_RAISEPARENT; + + _Menu_Process_Debug_Return( lResult ); + } + break; + } + if( !lContinue ) { + _Menu_Process_Debug_Print( "Early\n" ); + _Menu_Clip_Pop( lOldClipPos, lOldClipSize ); + return lResult; + } + + // we adjust the origin for the children + lOldOrigin = Menu_Origin; + _Menu_Origin_Push( pItem.pos + pItem.origin ); + + _Menu_Process_Debug_Print( "\n" ); + + switch( pMode ) { + case MENU_PROCESS_RUNFLAG: + for( lChild = pItem._child ; lChild ; lChild = lChild._next ) { + Menu_InheritRunFlag( pItem, lChild ); + Menu_ProcessRunFlag( lChild ); + } + break; + case MENU_PROCESS_DRAW: + for( lChild = pItem._child ; lChild ; lChild = lChild._next ) + Menu_ProcessDraw( lChild ); + break; + case MENU_PROCESS_UPDATE: + for( lChild = pItem._child ; lChild ; lChild = lChild._next ) + Menu_ProcessUpdate( lChild ); + break; + case MENU_PROCESS_MOUSE: + for( lChild = pItem._child ; lChild ; lChild = lChild._next ) + if( Menu_HasEvents( pItem ) ) + Menu_ProcessMouse( lChild, pSelectState ); + else + Menu_ProcessMouse( lChild, MENU_SELECT_NEVER ); + break; + case MENU_PROCESS_KEY: + for( lChild = pItem._child ; lContinue && lChild ; lChild = lChild._next ) { + local float lRet; + + lRet = Menu_ProcessKey( lChild, pKey, pAscii ); + + switch( lRet ) { + case MENU_EVENT_RAISEPARENT: + lContinue = false; + if( Raise_Key( pItem, pKey, pAscii ) ) + lResult = MENU_EVENT_PROCESSED; + else + lResult = MENU_EVENT_RAISEPARENT; + break; + case MENU_EVENT_PROCESSED: + lResult = lRet; + lContinue = false; + break; + case MENU_EVENT_CONTINUE: + lResult = lRet; + break; + } + } + _Menu_Process_Debug_Return( lResult ); + break; + } + + _Menu_Origin_Pop( lOldOrigin ); + + _Menu_Clip_Pop( lOldClipPos, lOldClipSize ); + return lResult; +}; + +void() Menu_Frame = +{ + Sys_Debug_Frame(); + + Menu_UpdateRunFlags(); + // process the update event + Menu_Process_Setup(); + Menu_ProcessUpdate( Menu_ActiveWindow, MENU_PROCESS_UPDATE ); + + Menu_Process_Setup(); + // if mouse was moved, select an item + if( Cursor_Relative != '0 0 0' ) { + local entity lOld; + + lOld = Menu_ActiveItem; + Menu_ProcessMouse( Menu_ActiveWindow, MENU_SELECT_SELECTABLE ); + + if( !Menu_ActiveItem ) + Menu_ActiveItem = lOld; + else if( lOld != Menu_ActiveItem ) { + Raise_Select( lOld, false, true ); + Raise_Select( Menu_ActiveItem, true, true ); + } + } else // just update mouseinarea + Menu_ProcessMouse( Menu_ActiveWindow, MENU_SELECT_NEVER ); + + Menu_CollectGarbage( false ); +} + +void() Menu_Draw = +{ + // if Menu_ActiveWindow is visible loop though it + if( Menu_IsVisible( Menu_ActiveWindow ) ) + { + Menu_Process_Setup(); + Menu_ProcessDraw( Menu_ActiveWindow ); + } + + Sys_Debug_Draw(); +}; + +void( float pKey, float pAscii) Menu_Key = +{ + // is a keyhook set ? + if( Menu_KeyHook != Util_NullFunction ) { + // call it + Menu_KeyHook( pKey, pAscii ); + return; + } + // before calling the current keydown functions, process the mouse again + // to make sure the correct item is called + // (except mouse wheel up and down) + // if the mouse doesnt point to an item, there wont be a reaction on the clicking + if(K_MOUSE1 <= pKey && pKey <= K_MOUSE10) { + local entity lOld; + + lOld = Menu_ActiveItem; + Menu_ActiveItem = null_entity; + Menu_ProcessMouse( Menu_ActiveWindow, MENU_SELECT_SELECTABLE ); + + if( !Menu_ActiveItem ) { + Menu_ActiveItem = lOld; + return; + } else if( lOld != Menu_ActiveItem ) { + Raise_Select( lOld, false, true ); + Raise_Select( Menu_ActiveItem, true, true ); + } + } + + // call current selected keydown function + // if nothing is selected -> window has no items -> call window key + if(Menu_ActiveItem == null_entity) + Menu_Reselect( false ); + + if( ( !Menu_IsSelectable( Menu_ActiveItem ) && Menu_ActiveItem != Menu_ActiveWindow ) || + Menu_ProcessKey( Menu_ActiveWindow, pKey, pAscii ) != MENU_EVENT_PROCESSED ) + // If it goes really wrong: + if( pKey == K_ESCAPE ) + if( cvar( "developer" ) ) + error( " K_ESCAPE wasnt processed!\n" ); + else { + Menu_Toggle(); + cmd( "menu_restart\n" ); + } + else if( cvar( "developer" ) ) { + print( " Key ", ftos( pKey ), " ('" ); + print( chr( pAscii ), "') wasn't processed!\n" ); + } +}; + +bool() Menu_Toggle = +{ + // only let the qc toggle the menu if we are ingame or a developer + if( gamestatus & GAME_CONNECTED || cvar( "developer" ) ) { + // then allow toggling + m_hide(); + return true; + } else + return false; +}; diff --git a/scmenu/source/system/gc.qc b/scmenu/source/system/gc.qc new file mode 100644 index 000000000..bd57fde8e --- /dev/null +++ b/scmenu/source/system/gc.qc @@ -0,0 +1,72 @@ +// DP/Nex Menu +// system/gc.qc + +void() Menu_InitGarbageStats = +{ + Menu_GarbageFrameCount = 0; + Menu_GarbageToggleCount = 0; +}; + +void() Menu_ResetGarbageStats = +{ + if( Menu_GarbageFrameCount ) + print( "Menu: GC: ", ftos( Menu_GarbageFrameCount ), " items marked for frame deletion but couldnt be reached!\n" ); + if( Menu_GarbageToggleCount ) + print( "Menu: GC: ", ftos( Menu_GarbageToggleCount ), " items marked for toggle delition but couldnt be reached!\n" ); + + Menu_GarbageFrameCount = 0; + Menu_GarbageToggleCount = 0; +}; + +bool( entity pItem ) Menu_CheckForGarbage = +{ + if( Menu_HasRunFlag( pItem, RUNFLAG_DELETEFRAME ) ) { + Menu_RemoveItem( pItem ); + --Menu_GarbageFrameCount; + return true; + } + return false; +}; + +void( bool pToggle ) Menu_CollectGarbage = +{ + local entity lNode; + + lNode = null_entity; + if( pToggle ) { + while( (Menu_GarbageFrameCount || Menu_GarbageToggleCount) && (lNode = nextent( lNode )) != null_entity ) + if( Menu_HasRunFlag( lNode, RUNFLAG_DELETEFRAME ) ) { + Menu_RemoveItem( lNode ); + --Menu_GarbageFrameCount; + } else if( Menu_HasRunFlag( lNode, RUNFLAG_DELETETOGGLE ) ) { + Menu_RemoveItem( lNode ); + --Menu_GarbageToggleCount; + } + } else while( Menu_GarbageFrameCount && (lNode = nextent( lNode )) != null_entity ) + if( Menu_HasRunFlag( lNode, RUNFLAG_DELETEFRAME ) ) { + Menu_RemoveItem( lNode ); + --Menu_GarbageFrameCount; + } +}; + +void( entity pItem ) Menu_DeleteAfterFrame = +{ + if( !Menu_HasRunFlag( pItem, RUNFLAG_DELETEFRAME ) ) { + if( Menu_HasRunFlag( pItem, RUNFLAG_DELETETOGGLE ) ) { + pItem._runFlag = pItem._runFlag + RUNFLAG_DELETEFRAME - RUNFLAG_DELETETOGGLE; + --Menu_GarbageToggleCount; + } else + pItem._runFlag = pItem._runFlag + RUNFLAG_DELETEFRAME; + ++Menu_GarbageFrameCount; + } +}; + +void( entity pItem ) Menu_DeleteAfterToggle = +{ + if( Menu_HasRunFlag( pItem, RUNFLAG_DELETEFRAME ) + || Menu_HasRunFlag( pItem, RUNFLAG_DELETETOGGLE ) ) + return; + pItem._runFlag = self._runFlag + RUNFLAG_DELETETOGGLE; + ++Menu_GarbageToggleCount; +}; + diff --git a/scmenu/source/system/gc.qh b/scmenu/source/system/gc.qh new file mode 100644 index 000000000..b2df766a1 --- /dev/null +++ b/scmenu/source/system/gc.qh @@ -0,0 +1,14 @@ +// DP/Nex Menu +// system/gc.qh + +float Menu_GarbageFrameCount; +float Menu_GarbageToggleCount; + +void() Menu_InitGarbageStats; +void() Menu_ResetGarbageStats; + +bool( entity pItem ) Menu_CheckForGarbage; // also removes it, only checks for framedelete + +void( bool pToggle ) Menu_CollectGarbage; +void( entity pItem ) Menu_DeleteAfterFrame; +void( entity pItem ) Menu_DeleteAfterToggle; diff --git a/scmenu/source/system/history.qc b/scmenu/source/system/history.qc new file mode 100644 index 000000000..65abbb141 --- /dev/null +++ b/scmenu/source/system/history.qc @@ -0,0 +1,81 @@ +// DP/Nex menu +// system/history.qc + + +/* +=================== +Menu_History_Push +=================== +*/ +void( entity pEntity, Menu_History_PopFunction pPopFunction ) Menu_History_Push = +{ + local entity lHistory; + + Menu_KeyHook = Util_NullFunction; + + lHistory = spawn(); + + lHistory.type = "MMANAGER_HISTORY"; + lHistory._prev = Menu_History; + lHistory._child = Menu_ActiveItem; + lHistory._parent = Menu_ActiveWindow; + lHistory._next = pEntity; // "used for" + lHistory._destroy = pPopFunction; + + Menu_History = lHistory; +}; + +/* +=================== +Menu_History_Pop +=================== +*/ +void() Menu_History_Pop = +{ + local entity lTemp; + + if( Menu_History == null_entity ) + return; + + Menu_KeyHook = Util_NullFunction; + + Menu_ActiveItem = Menu_History._child; + Menu_ActiveWindow = Menu_History._parent; + + lTemp = Menu_History; + // FIXME: use Menu_DestroyItem + Raise_Destroy( lTemp ); + Menu_History = Menu_History._prev; + remove( lTemp ); +}; + +/* +=================== +Menu_History_Verify +=================== +*/ +bool( entity pEntity ) Menu_History_Verify = +{ + if( Menu_History == null_entity ) + return false; + + if( Menu_History._next == pEntity ) + return true; + return false; +}; + +/* +=================== +Menu_History_Clear +=================== +*/ +void() Menu_History_Clear = +{ + local entity lEntity; + + lEntity = null_entity; + while( ( lEntity = findstring( lEntity, type, "MMANAGER_HISTORY" ) ) != null_entity) + remove( lEntity ); + + Menu_History = null_entity; +}; diff --git a/scmenu/source/system/history.qh b/scmenu/source/system/history.qh new file mode 100644 index 000000000..e8c20ca01 --- /dev/null +++ b/scmenu/source/system/history.qh @@ -0,0 +1,23 @@ +// DP/Nex Menu +// system/history.qh + +// MMANAGER_HISTORY +.entity _prev; // <- points to the previous history element +.entity _child; // <- points to the old/calling selected item +.entity _parent; // <- points to the old active window +.entity _next; // <- points to the item which the history is used for +.event _destroy; // <- points to the function that is called when the history is popped + +// points to the last element of the history +entity Menu_History; + +/////////////// +// prototypes +/// +typedef void() Menu_History_PopFunction; + +void( entity pEntity, Menu_History_PopFunction pPopFunction ) Menu_History_Push; +void() Menu_History_Pop; +bool( entity pEntity ) Menu_History_Verify; // Verifies the target item +void() Menu_History_Clear; + diff --git a/scmenu/source/system/isframe.qc b/scmenu/source/system/isframe.qc new file mode 100644 index 000000000..2c87567c6 --- /dev/null +++ b/scmenu/source/system/isframe.qc @@ -0,0 +1,334 @@ +// DP/Nex Menu +// system/isframe.qc + +void() Menu_Init = +{ + //registercvar("menu_reloadlist","0"); + + Sys_Debug_Init(); + // do one frame to make it possible to debug the parser + Sys_Debug_Frame(); + + Menu_InitGarbageStats(); + Menu_Load(); +}; + +void() Menu_Load = +{ + Parser_ParseMenu( MENU_MAINFILE ); + + Menu_LinkWindows(); +}; + +// the good thing is, finddef doesnt fuck up any chain lists +entity(entity pStart, .string pFind1, string pMatch, .float pFind2, float pMatch2) finddef = +{ + while( 1 ) { + pStart = findstring( pStart, pFind1, pMatch ); + if( pStart == null_entity ) + break; + if( pStart.pFind2 == pMatch2 ) + break; + } + + return pStart; +}; + +void( entity pParent ) Menu_LinkChildren = +{ + local entity lChild; + local float lOrder; + local entity lPrevious; + + // build a list of all children + lChild = findchainstring( parent, pParent.name ); + if( lChild == null_entity ) + return; + + // inverse the chain + lPrevious = null_entity; + while( lChild ) { + local entity lNext; + + lNext = lChild.chain; + lChild.chain = lPrevious; + lPrevious = lChild; + lChild = lNext; + } + lChild = lPrevious; + + lOrder = 1; // we start with orderPos 1 (0 is auto-set) + lPrevious = null_entity; + while( lChild ) { + local entity lOverwrite; + // try to find an item that has the current orderPos set + lOverwrite = finddef( null_entity, parent, pParent.name, orderPos, lOrder ); + if( lOverwrite == lChild ) + lChild.orderPos = lOrder; + else if( lOverwrite ) { // insert lOverwrite in front of lChild + local entity lOPrevious; + + lOPrevious = findentity( null_entity, chain, lOverwrite ); + lOPrevious.chain = lOverwrite.chain; + lOverwrite.chain = lChild; + lChild = lOverwrite; + } else + lChild.orderPos = 0 - lOrder; //INFO: HACK: tell Spike + + // link it + if( lPrevious ) + lPrevious._next = lChild; + else + pParent._child = lChild; + lChild._prev = lPrevious; + lChild._parent = pParent; + + lPrevious = lChild; + lChild = lChild.chain; + lOrder++; + } + lPrevious._next = null_entity; +}; + +void() Menu_LinkWindows = +{ + // first verify that MENU_NORMAL_NAME and MENU_INGAME_NAME exist + // if not add the default strings + local entity lEntity; + + dprint( "Loading defaults if necessary\n" ); + + lEntity = findstring( null_entity, name, MENU_NORMAL_NAME ); + if( lEntity == null_entity ) + loadfromdata( MENU_NORMAL_DEFAULT ); + + // verify again if MENU_NORMAL_NAME is there now + lEntity = findstring( null_entity, name, MENU_NORMAL_NAME ); + if( lEntity == null_entity ) + error( "Bad MENU_NORMAL_DEFAULT!\n" ); + + lEntity = findstring( null_entity, name, MENU_INGAME_NAME ); + if( lEntity == null_entity ) + loadfromdata( MENU_INGAME_DEFAULT ); + + // verify again if MENU_INGAME_NAME is there now + lEntity = findstring( null_entity, name, MENU_INGAME_NAME ); + if( lEntity == null_entity ) + error( "Bad MENU_INGAME_DEFAULT!\n" ); + + dprint( "Verifying that every name is used only once\n" ); + + // verify that every name is only used *once* + lEntity = null_entity; + while( ( lEntity = nextent( lEntity ) ) != null_entity ) { + self = lEntity; + while( ( self = findstring( self, name, lEntity.name ) ) != null_entity ) + if( self != null_entity ) + objerror( "Name ", lEntity.name, " already used!\n" ); + } + + dprint( "Verification of: name, type and parent fields\n" ); + + // now we have to : + // set the parent field with parent_name + // check the type field + self = null_entity; + while( ( self = nextent( self ) ) != null_entity ) { + if( self.name == "" ) { + objerror( "Name is missing!\n" ); + continue; + } + + if( self.type == "" ) { + objerror( "Type is missing!\n" ); + continue; + } + + if( !isfunction( strcat( self.type, "_Spawn" ) ) ) { + objerror( "Control ", self.type, " not found!\n" ); + continue; + } + + // find parent + // if parent_name is "" do nothing else check whether the parent exists + if( self.parent != "" ) { + lEntity = findstring( null_entity, name, self.parent ); + + if( lEntity == null_entity ) { + objerror( "Item ", self.parent, " not found!\n" ); + continue; + } + } + else + self._parent = null_entity; + } + + dprint( "Building the child lists\n" ); + // call LinkChildren for all entities + lEntity = null_entity; + while( ( lEntity = nextent( lEntity ) ) != null_entity ) + Menu_LinkChildren( lEntity ); + + dprint( "Calling the type functions\n" ); + + // call the type functions (former classname functions) + lEntity = null_entity; + while( ( lEntity = nextent( lEntity ) ) != null_entity ) { + self = lEntity; + //dprint("Calling ",self.type," (", etos(self),")\n"); + if( !Menu_HasFlag( self, FLAG_TEMPLATE ) && !Menu_HasRunFlag( self, RUNFLAG_SPAWNED ) ) { + //print( lEntity.name, "\n" ); + callfunction( strcat( self.type, "_Spawn" ) ); + self._runFlag = self._runFlag | RUNFLAG_SPAWNED; + } //else + //print( "X ", lEntity.name, "\n" ); + } + + dprint( "Linking windows finished.\n" ); +}; + +void( entity pItem ) Menu_LinkItem = +{ + local entity lEntity; + local entity lOldSelf; + + if( Menu_HasRunFlag( pItem, RUNFLAG_SPAWNED ) ) + return; + + // verify the type + if( pItem.type == "" ) + error( "LinkItem: Type is missing (", etos( pItem ), ")!\n" ); + + if( !isfunction( strcat( pItem.type, "_Spawn" ) ) ) + error( "LinkItem: Control ", pItem.type, " not found (", etos( pItem ), ")!\n" ); + + // verify name and parent + lEntity = null_entity; + while( (lEntity = findstring( lEntity, name, pItem.name )) != null_entity ) + if( lEntity != pItem ) + error( "LinkItem: Name '", pItem.name, "' already in use (", etos( pItem ), ", ", etos( lEntity ), ")!" ); + + if( pItem.parent != "" ) { + pItem._parent = findstring( null_entity, name, pItem.parent ); + + if( !pItem._parent ) + error( "LinkItem: Couldnt find parent '", pItem.parent, "' (", etos( pItem ), ")!" ); + } else + pItem._parent = null_entity; + + // Add the children + Menu_LinkChildren( pItem ); + + // link children + for( lEntity = pItem._child ; lEntity ; lEntity = lEntity._next ) + Menu_LinkItem( lEntity ); + + // call the spawn function + lOldSelf = self; + self = pItem; + if( !Menu_HasFlag( self, FLAG_TEMPLATE ) ) { + callfunction( strcat( self.type, "_Spawn" ) ); + self._runFlag = self._runFlag | RUNFLAG_SPAWNED; + } + self = lOldSelf; +}; + +void() Menu_Hide = +{ + Raise_Select( Menu_ActiveItem, false, false ); + Menu_CollectGarbage( true ); + Menu_ResetGarbageStats(); +}; + +void() Menu_PerformReinit = +{ + // clear history + Menu_History_Clear(); + + // reset the key hook (if necessary at all) + Menu_KeyHook = Util_NullFunction; + + // and reinit all menu items + self = null_entity; + while( (self = nextent( self ) ) != null_entity ) { + if( self.parent == "" ) + self._parent = null_entity; + //else actually this shouldnt happen + else if( self._parent.name != self.parent ) + objerror( "Parent (should be ", self.parent, ") of menu item ", self.name, " changed to ", self._parent.name, " !\n" ); + + Raise_Reinit( self ); // always call reinit + } + + // choose which menu to display + if( MENU_ALLOWINGAME && ( gamestatus & GAME_CONNECTED ) ) + Menu_ActiveWindow = findstring( null_entity, name, MENU_INGAME_NAME ); + else + Menu_ActiveWindow = findstring( null_entity, name, MENU_NORMAL_NAME ); + + // run one runflag frame to (re)init the runflags + Menu_UpdateRunFlags(); + + Menu_Reselect( false ); +}; + +void() Menu_Shutdown = +{ + // call the terminate event for each object + self = null_entity; + while( ( self = nextent( self ) ) != null_entity ) + Raise_Destroy( self ); +}; + +entity( string pType, string pName, string pParent ) Menu_CreateItem = +{ + local entity lItem; + + if( !pType ) + error( "Bad pType '", pType, "'!" ); + if( !pName ) + error( "Bad pName '", pName, "'!" ); + + lItem = spawn(); + parseentitydata( lItem, strcat( "{ type \"", pType, "\" name \"", strcat( pParent, "::", pName ), "\" parent \"", pParent, "\" }" ) ); + return lItem; +}; + +entity( entity pTemplate, string pName, string pParent, bool pTree ) Menu_DeriveItem = +{ + local entity lItem; + local entity lChild; + + if( !pTemplate ) + error( "Null pTemplate!" ); + if( !pName ) + error( "Bad pName '", pName, "'!" ); + + lItem = spawn(); + copyentity( pTemplate, lItem ); + if( lItem.flag & FLAG_TEMPLATE ) + lItem.flag = lItem.flag - FLAG_TEMPLATE; + if( lItem._runFlag & RUNFLAG_SPAWNED ) + lItem._runFlag = lItem._runFlag - RUNFLAG_SPAWNED; + parseentitydata( lItem, strcat( "{ name \"", strcat( pParent, "::", pName ), "\" parent \"", pParent, "\" }" ) ); + + if( pTree ) + for( lChild = pTemplate._child ; lChild ; lChild = lChild._next ) { + local string lName; + lName = String_Zone( substring( lChild.name, strlen( lChild.parent ) + 2, 100000 ) ); + Menu_DeriveItem( lChild, lName, lItem.name, true ); + String_Free( lName ); + } + + return lItem; +}; + +void( entity pItem, string pData ) Menu_AddEntityData = +{ + parseentitydata( pItem, pData ); +}; + +void( entity pWindow ) Menu_LinkWindow = +{ + Menu_LinkItem( pWindow ); +}; diff --git a/scmenu/source/system/isframe.qh b/scmenu/source/system/isframe.qh new file mode 100644 index 000000000..3f44433f6 --- /dev/null +++ b/scmenu/source/system/isframe.qh @@ -0,0 +1,56 @@ +// DP/Nex Menu +// system/isframe.qh + +// define these menus in the menu def files or dont +// if not defined there will be added default items +const string MENU_NORMAL_NAME = "Normal"; +const string MENU_INGAME_NAME = "Ingame"; + +const string MENU_NORMAL_DEFAULT = +"// default normal menu\n" +"{\n" +" \"type\" \"Item_Window\"\n" +" \"name\" \"Normal\"\n" +"}"; + +const string MENU_INGAME_DEFAULT = +"// default ingame menu\n" +"{\n" +" \"type\" \"Item_Window\"\n" +" \"name\" \"Ingame\"\n" +"}"; + +// insert the files here +var string MENU_MAINFILE = "menu/menu"; + +const bool MENU_ALLOWINGAME = false; + +/////////////// +// prototypes +/// + +// used for global managing +void() Menu_Init; +// loads all files the file lists consists of +void() Menu_Load; +// used to reset the menu states everytime the menu is activated +void() Menu_PerformReinit; +// called when the hide event is processed +void() Menu_Hide; +// unload the menu +void() Menu_Shutdown; + +// For runtime addition of items, there is one function: +// it supposes that the Item has already been embedded into its parent +void( entity pItem ) Menu_LinkItem; // does also link all children and call their spawn function if necessary +void( entity pWindow ) Menu_LinkWindow; + + // to make life easier +entity( string pType, string pName, string pParent ) Menu_CreateItem; +entity( entity pTemplate, string pName, string pParent, bool pTree ) Menu_DeriveItem; + +void( entity pItem, string pData ) Menu_AddEntityData; + +// these functions are pretty private, so dont call them ! +void( entity pParent ) Menu_LinkChildren; +void() Menu_LinkWindows; diff --git a/scmenu/source/system/item.qh b/scmenu/source/system/item.qh new file mode 100644 index 000000000..0fbdabdb7 --- /dev/null +++ b/scmenu/source/system/item.qh @@ -0,0 +1,126 @@ +// DP/Nex Menu +// system/item.qh + +enumflags { + RUNFLAG_TEMPLATE, + + RUNFLAG_HADMOUSE, + RUNFLAG_MOUSEINAREA, + + RUNFLAG_CHILDDRAWONLY, + RUNFLAG_CHILDDRAWUPDATEONLY, + + RUNFLAG_HIDDEN, + RUNFLAG_CLIPPED, // used to distinguish between intentionally hidden and casaully hidden + RUNFLAG_NOSELECT, + + RUNFLAG_USERSELECT, + + RUNFLAG_DELETEFRAME, + RUNFLAG_DELETETOGGLE, + + RUNFLAG_SPAWNED // set after the spawn function has been called +}; + +typedef void() event; +typedef bool(float,float) keyEvent; +typedef void(bool,bool) selectEvent; + +/////////// +// [Item] fields +/// + +.entity chain; + +// controly type +.string type; + +// managing stuff +.entity _parent; +.string parent; + +//.entity _history; // used to set up the history -> selectdown prefers _history over _parent + +.string name; + +.entity _next, _prev; // point to the next, respectively, the previous item + +.entity _child; // points to the first child + +// updating stuff +.float orderPos; // if FLAG_NOSELECT or FLAG_HIDDEN is set, it cant be selected + // has to be set always to a correct value or to 0 then it is set +.float flag; +.float _runFlag; + +// drawing +.vector pos; +.vector size; + +.vector origin; + +// event cache fields +.vector _cache_origin; +.vector _cache_clip_pos; +.vector _cache_clip_size; + +// function pointers +.event init; // called once at object creation +.event reinit; +.event destroy; +.event mouseEnter; +.event mouseLeave; +.event update; +.selectEvent select; +.event action; +.event draw; +.keyEvent key; // if it returns TRUE, the key was processed by the function + +// hidden function pointers - actually these are called by the manager +// and they call the normal ones (used to make controls more generic +.event _reinit; // called in performreinit +.event _destroy; // called when the item is removed -> menu_removeitem +.event _mouseEnter; +.event _mouseLeave; +.event _update; +.selectEvent _select; +.event _draw; +.keyEvent _key; + +///////////////////// +// Helper Functions +/// + +// default control functions - assign only to the _* event functions +// (assigning to the 'normal' event functions will crash the vm !) +// are used by ITEM_CUSTOM and can be used to test new ITEMs easily +void() DefCt_Reinit; +void() DefCt_Destroy; +bool( float pKey, float pAscii ) DefCt_Key; +void() DefCt_Draw; +void() DefCt_MouseEnter; +void() DefCt_MouseLeave; +void() DefCt_Update; +void( bool pSelect, bool pUser ) DefCt_Select; + +// use this to raise an event from another item or function +void( entity pEntity ) Raise_Reinit; +void( entity pEntity ) Raise_Destroy; +bool( entity pEntity, float pKey, float pAscii) Raise_Key; +void( entity pEntity ) Raise_Draw; +void( entity pEntity ) Raise_MouseEnter; +void( entity pEntity ) Raise_MouseLeave; +void( entity pEntity ) Raise_Update; +void( entity pEntity, bool pSelect, bool pUser ) Raise_Select; + +// safe call the normal control functions (only used by the mcontrols function) +void() CtCall_Init; +void() CtCall_Reinit; +void() CtCall_Destroy; +bool( float pKey, float pAscii) CtCall_Key; +void() CtCall_Draw; +void() CtCall_MouseEnter; +void() CtCall_MouseLeave; +void() CtCall_Action; +void() CtCall_Update; +void( bool pSelect, bool pUser ) CtCall_Select; diff --git a/scmenu/source/system/mgfx.qc b/scmenu/source/system/mgfx.qc new file mode 100644 index 000000000..7fb4c859f --- /dev/null +++ b/scmenu/source/system/mgfx.qc @@ -0,0 +1,158 @@ +// DP/Nex Menu +// system/mgfx.qc + +void( vector pPos, vector pSize, vector pColor, float pAlpha, float pDrawFlag, string pText ) _Mgfx_Debug_Info = +{ + if( !sys_debug_mgfx ) + return; + + pText = String_Zone( pText ); + + print( "MGFX output: ", vtos( pPos ), " - ", vtos( pSize), " C", vtos( pColor ) ); + print( " A", ftos( pAlpha ), " X", ftos( pDrawFlag ), " ", pText, "\n" ); + + String_Free( pText ); +}; + +/* +=================== +Menu_MenToOrg +=================== +*/ +vector( vector pPos ) Menu_MenToOrg = +{ + return pPos - Menu_Origin; +}; + +/* +=================== +Menu_OrgToMen +=================== +*/ +vector( vector pPos ) Menu_OrgToMen = +{ + return pPos + Menu_Origin; +}; + +/* +=================== +Menu_ConToOrg +=================== +*/ +vector( vector pPos ) Menu_ConToOrg = +{ + pPos = Gfx_ConToMen( pPos ); + return Menu_MenToOrg( pPos ); +}; + +/* +=================== +Menu_OrgToCon +=================== +*/ +vector( vector pPos ) Menu_OrgToCon = +{ + pPos = Menu_OrgToMen( pPos ); + return Gfx_MenToCon( pPos ); +}; + +/* +=================== +Menu_DrawCharacter +=================== +*/ +float( vector pPosition, float pCharacter, vector pScale, vector pRGB, float pAlpha, float pFlag ) +Menu_DrawCharacter = +{ + _Mgfx_Debug_Info( pPosition, pScale, pRGB, pAlpha, pFlag, strcat( "DrawChar: ", ftos( pCharacter ) ) ); + + pPosition = Menu_OrgToMen( pPosition ); + return Gfx_DrawCharacter( pPosition, pCharacter, pScale, pRGB, pAlpha, pFlag ); +}; + +/* +=================== +Menu_DrawString +=================== +*/ +float( vector pPosition, string pText, vector pScale, vector pRGB, float pAlpha, float pFlag ) +Menu_DrawString = +{ + // TODO: FIXME: do I really want this? + if( !pText ) + return 1; + + _Mgfx_Debug_Info( pPosition, pScale, pRGB, pAlpha, pFlag, strcat( "DrawString: ", pText ) ); + + pPosition = Menu_OrgToMen( pPosition ); + return Gfx_DrawString( pPosition, pText, pScale, pRGB, pAlpha, pFlag ); +}; + +/* +=================== +Menu_DrawPicture +=================== +*/ +float( vector pPosition, string pPicture, vector pSize, vector pRGB, float pAlpha, float pFlag ) +Menu_DrawPicture = +{ + _Mgfx_Debug_Info( pPosition, pSize, pRGB, pAlpha, pFlag, strcat( "DrawPicture: ", pPicture ) ); + + pPosition = Menu_OrgToMen( pPosition ); + return Gfx_DrawPic( pPosition, pPicture, pSize, pRGB, pAlpha, pFlag ); +}; + +/* +=================== +Menu_Fill +=================== +*/ +float( vector pPosition, vector pSize, vector pRGB, float pAlpha, float pFlag ) +Menu_Fill = +{ + _Mgfx_Debug_Info( pPosition, pSize, pRGB, pAlpha, pFlag, "Fill" ); + + pPosition = Menu_OrgToMen( pPosition ); + return Gfx_Fill( pPosition, pSize, pRGB, pAlpha, pFlag ); +}; + +/* +=================== +Menu_SetClipArea +=================== +*/ +void( float pX, float pY, float pWidth, float pHeight ) +Menu_SetClipArea = +{ + local vector lPosition; + local vector lDelta; + local vector lSize; + + lPosition_x = pX; + lPosition_y = pY; + lPosition = Menu_OrgToMen( lPosition); + + lSize_x = pWidth; + lSize_y = pHeight; + // clip it to the current clip area + lDelta = Util_GetClipDelta( lPosition, Menu_Clip_Position, Menu_Clip_Size ); + lPosition = lPosition + lDelta; + lSize = Util_ClipRect( lPosition, lSize - lDelta, Menu_Clip_Position, Menu_Clip_Size ); + + Gfx_SetClipArea( lPosition_x, lPosition_y, pWidth, pHeight ); +}; + +/* +=================== +Menu_ResetClipArea +=================== +*/ +void() +Menu_ResetClipArea = +{ + if( Menu_Clip_Position == '0 0 0' && Menu_Clip_Size == '0 0 0' ) + Gfx_ResetClipArea(); + else + Gfx_SetClipArea( Menu_Clip_Position_x, Menu_Clip_Position_y, Menu_Clip_Size_x, Menu_Clip_Size_y ); +} + diff --git a/scmenu/source/system/mgfx.qh b/scmenu/source/system/mgfx.qh new file mode 100644 index 000000000..8fcca8f79 --- /dev/null +++ b/scmenu/source/system/mgfx.qh @@ -0,0 +1,36 @@ +// DP/Nex Menu +// system/mgfx.qh + +vector Menu_Clip_Position; +vector Menu_Clip_Size; +vector Menu_Origin; + +vector( vector pPos ) Menu_OrgToMen; +vector( vector pPos ) Menu_MenToOrg; +vector( vector pPos ) Menu_ConToOrg; +vector( vector pPos ) Menu_OrgToCon; + +float( vector pPosition, float pCharacter, vector pScale, vector pRGB, float pAlpha, float pFlag ) +Menu_DrawCharacter; + +float( vector pPosition, string pText, vector pScale, vector pRGB, float pAlpha, float pFlag ) +Menu_DrawString; + +float( vector pPosition, string pPicture, vector pSize, vector pRGB, float pAlpha, float pFlag ) +Menu_DrawPicture; + +float( vector pPosition, vector pSize, vector pRGB, float pAlpha, float pFlag ) +Menu_Fill; + +void( float pX, float pY, float pWidth, float pHeight ) +Menu_SetClipArea; + +void() +Menu_ResetClipArea; + +#ifdef USEFUNCTIONS +void( string pText ) +_Menu_Process_Debug_Print; +#endif + +bool _menu_process_filtered; diff --git a/scmenu/source/system/parser.qc b/scmenu/source/system/parser.qc new file mode 100644 index 000000000..000f7be98 --- /dev/null +++ b/scmenu/source/system/parser.qc @@ -0,0 +1,536 @@ +// DP/Nex Menu +// system/parser.qc + +void() Parser_Define_Spawn = {}; + +void() Parser_TokenizeLine = +{ + Parser_NumTokens = tokenize( Parser_Line ); + Parser_TokenNum = 0; +}; + +bool() Parser_GetToken = +{ + local string lLine; + + if( Parser_TokenNum >= Parser_NumTokens ) { // get a new line + lLine = fgets( Parser_File ); + ++Parser_LineNumber; + if( !lLine ) + if( !validstring( lLine ) ) + return false; + else + return Parser_GetToken(); + + Parser_Line = String_Set( Parser_Line, lLine ); + Parser_TokenizeLine(); + return Parser_GetToken(); + } else { + Parser_Token = String_Set( Parser_Token, argv( Parser_TokenNum ) ); + Parser_TokenNum++; + } + + Parser_Print( PARSER_LOW, strcat( "Read token '", Parser_Token, "'" ) ); + + Parser_TokenType = Parser_GetTokenType(); + if( Parser_TokenType == PARSER_TT_BRACKETOPEN ) { + Parser_ProcessDefine(); + return Parser_GetToken(); + } + + return true; +}; + +float() Parser_GetTokenType = +{ + if( Parser_Token == "Item" ) + return PARSER_TT_ITEM; + else if( Parser_Token == "Template" ) + return PARSER_TT_TEMPLATE; + else if( Parser_Token == "Derive" ) + return PARSER_TT_DERIVE; + else if( Parser_Token == "DeriveTemplate" ) + return PARSER_TT_DERIVETEMPLATE; + else if( Parser_Token == "#define" ) + return PARSER_TT_DEFINE; + else if( Parser_Token == "Ignore" ) + return PARSER_TT_IGNORE; + else if( Parser_Token == "#undef" ) + return PARSER_TT_UNDEF; + else if( Parser_Token == "Namespace" ) + return PARSER_TT_NAMESPACE; + else if( Parser_Token == "#include" ) + return PARSER_TT_INCLUDE; + else if( Parser_Token == "}" ) + return PARSER_TT_BRACECLOSE; + else if( Parser_Token == "{" ) + return PARSER_TT_BRACEOPEN; + else if( Parser_Token == "[" ) + return PARSER_TT_BRACKETOPEN; + else if( Parser_Token == "]" ) + return PARSER_TT_BRACKETCLOSE; + + return PARSER_TT_TOKEN; +}; + +void( float pLevel, string pText ) _Parser_Print = +{ + if( pLevel == 0 || sys_debug_parser & pLevel ) + print( "Parser: ", pText, "\n" ); +}; + +void( float pLevel, string pInfo ) Parser_Print = +{ + if( pLevel == 0 || sys_debug_parser & pLevel ) + print( "Parser: ", Parser_Filename, ":", ftos( Parser_LineNumber ), ": ", pInfo, "\n" ); +}; + +void( string pInfo ) Parser_Error = +{ + print( "Parser: ", Parser_Filename, ":", ftos( Parser_LineNumber ), ": Error: '"); + print( Parser_Token, "' not expected (", pInfo, ")!\n" ); + fclose( Parser_File ); + error( "Error in the menu parser!" ); +}; + +void( float pType ) Parser_Expect = +{ + if( !Parser_GetToken() || ( Parser_TokenType != pType && Parser_TokenType != PARSER_TT_BRACKETOPEN ) ) + Parser_Error( strcat( "expected ", PARSER_TT_TEXT[ pType - PARSER_TT_ITEM ] ) ); +}; + +void( string pNamespace ) Parser_IncludeFile = +{ + local string lFilename, lLine; + local float lFile, lLineNumber, lNumTokens, lTokenNum; + + // #include file + Parser_Expect( PARSER_TT_TOKEN ); + + Parser_Print( PARSER_INFO, strcat( "#include: Including file '", Parser_Token, "'" ) ); + + Parser_FileList = String_Append( Parser_FileList, strcat( " {'", String_Normal( Util_AltStringPrepare( Parser_Token ) ), "'" ) ); + + lFilename = Parser_Filename; + lLine = Parser_Line; + + lFile = Parser_File; + lLineNumber = Parser_LineNumber; + lNumTokens = Parser_NumTokens; + lTokenNum = Parser_TokenNum; + + --Parser_IncludeDepth; + if( Parser_IncludeDepth > Parser_MaxIncludeDepth ) + Parser_Print( PARSER_NORMAL, "#include: Maximum depth reached!" ); + else + Parser_ParseFile( Parser_Token, pNamespace ); + --Parser_IncludeDepth; + + Parser_Filename = lFilename; + Parser_Line = lLine; + + Parser_File = lFile; + Parser_LineNumber = lLineNumber; + + // tokenize the line again, but jump to the old position + Parser_TokenizeLine(); + Parser_NumTokens = lNumTokens; + Parser_TokenNum = lTokenNum; + + Parser_FileList = String_Append( Parser_FileList, "}" ); +}; + +void() Parser_ParseDefine = +{ + local entity lDefine; + local float lOldLine; + + Parser_Print( 2, "Parsing #define..." ); + + // #define NAME CONSTANT + //Parser_Expect( PARSER_TT_BRACKETOPEN ); + Parser_Expect( PARSER_TT_TOKEN ); + + // check for double definitions (dont error just print a warning) + for( lDefine = Parser_DefineChain ; lDefine ; lDefine = lDefine.chain ) + if( Parser_Token == lDefine.name ) { + Parser_Print( PARSER_INFO, strcat( "#define: [", Parser_Token, "] already defined!" ) ); + Parser_Expect( PARSER_TT_TOKEN ); + return; + } + + + lDefine = spawn(); + lDefine.type = "Parser_Define"; + lDefine.name = String_Zone( Parser_Token ); + + //Parser_Expect( PARSER_TT_BRACKETCLOSE ); + // read the rest of the line + String_EntityZone( lDefine, value ); + lOldLine = Parser_LineNumber; + while( 1 ) + if( !Parser_GetToken() ) + break; + else if( lOldLine != Parser_LineNumber ) { + --Parser_TokenNum; + break; + } else if( Parser_Token == "\\" ) + ++lOldLine; + else + String_EntitySet( lDefine, value, strcat( lDefine.value, "\"", Parser_Token, "\" " ) ); + + Parser_Print( PARSER_HIGH, strcat( " Name = '", lDefine.name, "' Replacement = '", lDefine.value, "'" ) ); + + lDefine.chain = Parser_DefineChain; + Parser_DefineChain = lDefine; + + Parser_Print( PARSER_HIGH, "Done parsing #define" ); +}; + +void() Parser_ParseUndef = +{ + local entity lEntity, lPrevious; + + // #undef Name + Parser_Print( PARSER_HIGH, "Parsing #undef..." ); + Parser_Expect( PARSER_TT_TOKEN ); + + lPrevious = null_entity; + for( lEntity = Parser_DefineChain ; lEntity ; lPrevious = lEntity, lEntity = lEntity.chain ) + if( lEntity.name == Parser_Token ) { + if( lPrevious ) + lPrevious.chain = lEntity.chain; + else + Parser_DefineChain = lEntity.chain; + + Parser_Print( PARSER_INFO, strcat( "#undef: Removed [", Parser_Token, "]" ) ); + + String_Free( lEntity.name ); + String_Free( lEntity.value ); + + remove( lEntity ); + + return; + } + + Parser_Print( PARSER_INFO, strcat( "#undef: [", Parser_Token, "] not found!" ) ); +}; + +void() Parser_ProcessDefine = +{ + local string lConstant; + local entity lDefine; + + // [Name] + Parser_Expect( PARSER_TT_TOKEN ); + lConstant = String_Zone( Parser_Token ); + + Parser_Expect( PARSER_TT_BRACKETCLOSE ); + + Parser_Print( PARSER_HIGH, strcat( "Processing [", lConstant, "]..." ) ); + + for( lDefine = Parser_DefineChain ; lDefine ; lDefine = lDefine.chain ) + if( lDefine.name == lConstant ) { + // if you want to have a single token use \" or ' + Parser_Line = String_Set( Parser_Line, strcat( " ", lDefine.value ) ); + Parser_Print( PARSER_HIGH, strcat( "Replacing with '", Parser_Line, "'" ) ); + for( ; Parser_TokenNum < Parser_NumTokens ; Parser_TokenNum++ ) + Parser_Line = String_Set( Parser_Line, strcat( Parser_Line, " \"", argv( Parser_TokenNum ), "\"" ) ); + Parser_TokenizeLine(); + String_Free( lConstant ); + return; + } + + Parser_Token = String_Set( Parser_Token, String_Normal( lConstant ) ); + Parser_Print( PARSER_NORMAL, strcat( "#define: Couldn't find constant '", Parser_Token, "'!" ) ); + Parser_Error( "constant not found" ); +}; + +// Item [Template] +// Template +void( string pNamespace ) Parser_ParseDefinition = +{ + local entity lEntity; + + if( Parser_TokenType == PARSER_TT_ITEM ) + Parser_ParseItem( pNamespace ); + else if( Parser_TokenType == PARSER_TT_TEMPLATE ) { + lEntity = Parser_ParseItem( pNamespace ); + lEntity.flag = lEntity.flag | FLAG_TEMPLATE; + } else if( Parser_TokenType == PARSER_TT_DEFINE ) + Parser_ParseDefine(); + else if( Parser_TokenType == PARSER_TT_DERIVE ) + Parser_DeriveItem( pNamespace ); + else if( Parser_TokenType == PARSER_TT_DERIVETEMPLATE ) { + lEntity = Parser_DeriveItem( pNamespace ); + lEntity.flag = lEntity.flag | FLAG_TEMPLATE; + } else if( Parser_TokenType == PARSER_TT_UNDEF ) + Parser_ParseUndef(); + else if( Parser_TokenType == PARSER_TT_NAMESPACE ) + Parser_ParseNamespace( pNamespace ); + else if( Parser_TokenType == PARSER_TT_INCLUDE ) + Parser_IncludeFile( pNamespace ); + else if( Parser_TokenType == PARSER_TT_IGNORE ) + Parser_ParseIgnore(); + else + Parser_Error( "couldn't find type in Parser_ParseDef" ); +}; + +void() Parser_ParseIgnore = +{ + local float lBraceCount; + + Parser_Expect( PARSER_TT_BRACEOPEN ); + for( lBraceCount = 1 ; lBraceCount > 0 ; ) + if( !Parser_GetToken() ) + break; + else if( Parser_TokenType == PARSER_TT_BRACEOPEN ) + ++lBraceCount; + else if( Parser_TokenType == PARSER_TT_BRACECLOSE ) + --lBraceCount; +}; + +entity( string pNamespace ) Parser_ParseItem = +{ + local string lNamespace; + local string lEntityText; + local entity lEntity; + + Parser_Print( PARSER_HIGH, "Parsing item.." ); + + // get the item type + Parser_Expect( PARSER_TT_TOKEN ); + lEntityText = String_Zone( strcat( "{ \"type\" \"Item_", Parser_Token,"\" " ) ); + + Parser_Print( PARSER_HIGH, strcat( " Type = '", Parser_Token, "'" ) ); + + // get the item name + Parser_Expect( PARSER_TT_TOKEN ); + if( pNamespace != "" ) + lNamespace = String_Zone( strcat( pNamespace, "::", Parser_Token ) ); + else + lNamespace = String_Zone( Parser_Token ); + + lEntityText = String_Set( lEntityText, strcat( lEntityText, "\"name\" \"", lNamespace, "\" " ) ); + lEntityText = String_Set( lEntityText, strcat( lEntityText, "\"parent\" \"", pNamespace, "\" " ) ); + + Parser_Print( PARSER_HIGH, strcat( " Name = '", Parser_Token, "' Parent = '", pNamespace, + "' Namespace = '", lNamespace, "'" ) ); + + Parser_Expect( PARSER_TT_BRACEOPEN ); + lEntityText = Parser_ParseEntity( lNamespace, lEntityText ); + + // parse the entity (builtin) + lEntity = spawn(); + parseentitydata( lEntity, lEntityText ); + + String_Free( lEntityText ); + String_Free( lNamespace ); + + Parser_Print( PARSER_HIGH, strcat( "Parsing '", lEntity.name, "' finished" ) ); + + return lEntity; +}; + +void( entity pSource, entity pTarget ) Parser_CloneChildren = +{ + // we search for all items that are direct children of pSource and copy them + // and adapt their parent and names + local entity lNode; + + lNode = null_entity; + while ( (lNode = findstring( lNode, parent, pSource.name )) != null_entity ) { + local entity lClone; + local string lModifierString; + + lClone = spawn(); + copyentity( lNode, lClone ); + + if( lClone.flag & FLAG_TEMPLATE ) + lClone.flag = lClone.flag - FLAG_TEMPLATE; + + lModifierString = strcat( "{ name \"", pTarget.name, + substring( lNode.name, strlen( pSource.name ), 100000 ), "\" parent \"", pTarget.name, "\" }" ); + + parseentitydata( lClone, lModifierString ); + + Parser_CloneChildren( lNode, lClone ); + } +}; + +entity( string pNamespace ) Parser_DeriveItem = +{ + local string lNamespace; + local string lEntityText; + local entity lBase; + local string lBaseName; + local entity lEntity; + + Parser_Print( PARSER_HIGH, "Parsing derived item.." ); + + // get the base item + Parser_Expect( PARSER_TT_TOKEN ); + + if( substring( Parser_Token, 0, 2 ) == "::" ) + lBaseName = String_Zone( substring( Parser_Token, 2, strlen( Parser_Token ) - 2 ) ); + else if( pNamespace == "" ) + lBaseName = String_Zone( Parser_Token ); + else { + lBaseName = String_Zone( strcat( pNamespace, "::", Parser_Token ) ); + + // try the local namespace first, then try to find it in the global + if( findstring( null_entity, name, lBaseName ) == null_entity ) + lBaseName = String_Set( lBaseName, Parser_Token ); + } + + Parser_Print( PARSER_HIGH, strcat( " Base = '", lBaseName, "'" ) ); + + lBase = findstring( null_entity, name, lBaseName ); + if( lBase == null_entity ) + Parser_Error( "couldnt find item" ); + + // get the item name + Parser_Expect( PARSER_TT_TOKEN ); + if( pNamespace != "" ) + lNamespace = String_Zone( strcat( pNamespace, "::", Parser_Token ) ); + else + lNamespace = String_Zone( Parser_Token ); + + lEntityText = String_Zone( strcat( "{ \"name\" \"", lNamespace, "\" " ) ); + lEntityText = String_Set( lEntityText, strcat( lEntityText, "\"parent\" \"", pNamespace, "\" " ) ); + + Parser_Print( PARSER_HIGH, strcat( " Name = '", Parser_Token, "' Parent = '", pNamespace, + "' Namespace = '", lNamespace, "'" ) ); + + Parser_Expect( PARSER_TT_BRACEOPEN ); + lEntityText = Parser_ParseEntity( lNamespace, lEntityText ); + + // parse the entity (builtin) + lEntity = spawn(); + copyentity( lBase, lEntity ); + if( lEntity.flag & FLAG_TEMPLATE ) + lEntity.flag = lEntity.flag - FLAG_TEMPLATE; + parseentitydata( lEntity, lEntityText ); + + String_Free( lEntityText ); + String_Free( lNamespace ); + String_Free( lBaseName ); + + // now copy over all children + Parser_CloneChildren( lBase, lEntity ); + + Parser_Print( PARSER_HIGH, strcat( "Parsing '", lEntity.name, "' finished" ) ); + + return lEntity; +}; + +string( string pNamespace, string pEntityText ) Parser_ParseEntity = +{ + while( Parser_GetToken() ) { + if( Parser_TokenType == PARSER_TT_TOKEN ) { + // must be a property... + // store the key value + pEntityText = String_Set( pEntityText, strcat( pEntityText, "\"", Parser_Token, "\" " ) ); + Parser_Expect( PARSER_TT_TOKEN ); + pEntityText = String_Set( pEntityText, strcat( pEntityText, "\"", Parser_Token, "\" " ) ); + } else if( Parser_TokenType == PARSER_TT_BRACECLOSE ) + break; + else + Parser_ParseDefinition( pNamespace ); + } + + return String_Append( pEntityText, " }" ); +}; + +void( string pNamespace ) Parser_ParseNamespace = +{ + local string lNamespace; + + Parser_Print( PARSER_HIGH, "Parsing Namespace..." ); + // namespace Name { + Parser_Expect( PARSER_TT_TOKEN ); + if( pNamespace != "" ) + lNamespace = String_Zone( strcat( pNamespace, "::", Parser_Token ) ); + else + lNamespace = String_Zone( Parser_Token ); + Parser_Print( PARSER_HIGH, strcat( " Subnamespace = '", Parser_Token, "' New namespace = '", lNamespace, "'" ) ); + + Parser_Expect( PARSER_TT_BRACEOPEN ); + + while( Parser_GetToken() ) { + if( Parser_TokenType == PARSER_TT_BRACECLOSE ) + break; + + Parser_ParseDefinition( lNamespace ); + } + + Parser_Print( PARSER_HIGH, strcat( "Finished parsing Namespace. Namespace = '", pNamespace, "'" ) ); + + String_Free( lNamespace ); +}; + +void( string pFilename, string pNamespace ) Parser_ParseFile = +{ + Parser_Filename = String_Zone( pFilename ); + Parser_File = fopen( Parser_Filename, FILE_READ ); + if( Parser_File == -1 ) { + print( "Parser: Couldn't open ", Parser_Filename, "\n" ); + return; + } + + Parser_Line = String_Create(); + Parser_LineNumber = 0; + Parser_NumTokens = Parser_TokenNum = 0; + + while( Parser_GetToken() ) + Parser_ParseDefinition( pNamespace ); + + fclose( Parser_File ); + String_Free( Parser_Filename ); + String_Free( Parser_Line ); +}; + +void() Parser_Init = +{ + Parser_Token = String_Create(); + Parser_DefineChain = null_entity; + Parser_IncludeDepth = 0; + + Parser_FileList = String_Create(); +}; + +void() Parser_Quit = +{ + local entity lNext; + + _Parser_Print( PARSER_HIGH, "Deleting #defines:" ); + while( Parser_DefineChain ) { + lNext = Parser_DefineChain.chain; + _Parser_Print( PARSER_HIGH, strcat( " [", Parser_DefineChain.name, "]" ) ); + + String_Free( Parser_DefineChain.name ); + String_Free( Parser_DefineChain.value ); + + remove( Parser_DefineChain ); + Parser_DefineChain = lNext; + } + + + String_Free( Parser_Token ); + String_Free( Parser_FileList ); +}; + +void( string pMain ) Parser_ParseMenu = +{ + Parser_Init(); + + pMain = String_Zone( pMain ); + Parser_FileList = Util_AltStringPush( Parser_FileList, pMain ); + + Parser_ParseFile( pMain, "" ); + + _Parser_Print( PARSER_INFO, strcat( "Files parsed: ", Parser_FileList ) ); + + String_Free( pMain ); + Parser_Quit(); +}; diff --git a/scmenu/source/system/parser.qh b/scmenu/source/system/parser.qh new file mode 100644 index 000000000..68420be7f --- /dev/null +++ b/scmenu/source/system/parser.qh @@ -0,0 +1,81 @@ +// DP/Nex Menu +// system/parser.qh + +enum { + PARSER_TT_ITEM, + PARSER_TT_TEMPLATE, + PARSER_TT_DERIVE, + PARSER_TT_DERIVETEMPLATE, + PARSER_TT_DEFINE, + PARSER_TT_UNDEF, + PARSER_TT_IGNORE, + PARSER_TT_NAMESPACE, + PARSER_TT_INCLUDE, + PARSER_TT_BRACEOPEN, + PARSER_TT_BRACECLOSE, + PARSER_TT_BRACKETOPEN, + PARSER_TT_BRACKETCLOSE, + PARSER_TT_TOKEN, + PARSER_TT_SIZE +}; + +// FIXME: FTEQCC: const string PARSER_TT_TEXT[PARSER_TT_SIZE] = { +const string PARSER_TT_TEXT[14] = { + "Item", "Template", "Derive", "DeriveTemplate", "Define", "#undef", "Ignore", "Namespace", + "#include", "{", "}", "[", "]", "Token" +}; + +const float PARSER_NORMAL = 0; +enumflags { + PARSER_INFO, + PARSER_HIGH, + PARSER_LOW +}; + +const float Parser_MaxIncludeDepth = 32; + +string Parser_FileList; +float Parser_IncludeDepth; + +entity Parser_DefineChain; + +string Parser_Filename; +float Parser_LineNumber; + +float Parser_File; +string Parser_Line; + +float Parser_NumTokens; +float Parser_TokenNum; +string Parser_Token; +float Parser_TokenType; + +bool() Parser_GetToken; +float() Parser_GetTokenType; + +void() Parser_ParseDefine; +void() Parser_ProcessDefine; +void() Parser_ParseUndef; + +void( float pType ) Parser_Expect; + +void( string pInfo ) Parser_Error; +void( float pLevel, string pInfo ) Parser_Print; + +entity( string pNamespace ) Parser_ParseItem; +entity( string pNamespace ) Parser_DeriveItem; +string( string pNamespace, string pEntityText ) Parser_ParseEntity; +void( string pNamespace ) Parser_ParseDefinition; +void( string pNamespace ) Parser_ParseNamespace; +void() Parser_ParseIgnore; + +void( entity pSource, entity pTarget ) Parser_CloneChildren; + +void( string pNamespace ) Parser_IncludeFile; + +void( string pFilename, string pNamespace ) Parser_ParseFile; + +void( string pMain ) Parser_ParseMenu; + +void() Parser_Init; +void() Parser_Quit; diff --git a/scmenu/source/system/structure.qc b/scmenu/source/system/structure.qc new file mode 100644 index 000000000..ba9871df9 --- /dev/null +++ b/scmenu/source/system/structure.qc @@ -0,0 +1,583 @@ +// DP/Nex Menu +// system/structure.qc + +// TODO: finish the debug output +void( float pLevel, string pText ) _Menu_Structure_Debug = +{ + if( pLevel <= sys_debug_structure ) + print( pText ); +}; + +void( bool pUser ) _Menu_Select = +{ + Raise_Select( Menu_ActiveItem, true, pUser ); +}; + +entity( entity pItem ) _Menu_GetParent = +{ + if( !pItem._parent ) + return null_entity; + if( Menu_IsEmbedded( pItem._parent ) ) + return _Menu_GetParent( pItem._parent ); + return pItem._parent; +}; + +bool( entity pItem, entity pParent ) _Menu_IsEmbeddedParentOf = +{ + if( pItem._parent == pParent ) + return true; + if( Menu_IsEmbedded( pItem._parent ) ) + return _Menu_IsEmbeddedParentOf( pItem._parent, pParent ); + return false; +}; + +entity( entity pItem ) _Menu_GetFirst = +{ + if( Menu_IsEmbedded( pItem ) && pItem._child ) + return _Menu_GetFirst( pItem._child ); + return pItem; +}; + +entity( entity pItem ) _Menu_GetLast = +{ + if( Menu_IsEmbedded( pItem ) && pItem._child ) { + local entity lNode; + + for( lNode = pItem._child ; lNode._next ; lNode = lNode._next ); + return _Menu_GetLast( lNode ); + } + return pItem; +}; + +entity( entity pItem ) _Menu_GetNext = +{ + local entity lNext; + + lNext = pItem._next; + if( lNext ) + return _Menu_GetFirst( lNext ); + if( Menu_IsEmbedded( pItem._parent ) && pItem._parent != Menu_ActiveWindow ) + return _Menu_GetNext( pItem._parent ); + else + return null_entity; +}; + +entity( entity pItem ) _Menu_GetPrev = +{ + local entity lPrev; + + lPrev = pItem._prev; + if( lPrev ) + return _Menu_GetLast( lPrev ); + if( Menu_IsEmbedded( pItem._parent ) && pItem._parent != Menu_ActiveWindow ) + return _Menu_GetPrev( pItem._parent ); + else + return null_entity; +}; + +void() _Menu_SelectNext = +{ + local entity lTemp; + + if( !Menu_ActiveItem ) { + _Menu_Structure_Debug( 1, "_SelectNext: Bad Menu_ActiveItem!\n" ); + return; + } + + // try to select the next item + lTemp = Menu_ActiveItem; + while( (lTemp = _Menu_GetNext( lTemp )) != null_entity ) + if( Menu_IsSelectable( lTemp ) ) { + Menu_ActiveItem = lTemp; + _Menu_Structure_Debug( 1, strcat( "_SelectNext: ", lTemp.name, "\n" ) ); + return; + } + // loop + // only because of embedded: + for( lTemp = Menu_ActiveItem ; _Menu_GetPrev( lTemp ) ; lTemp = _Menu_GetPrev( lTemp ) ); +// TODO: rewrite _Menu_Select* to use an additional temp variable for storing the result of the functionc all + for( ; lTemp != Menu_ActiveItem ; lTemp = _Menu_GetNext( lTemp ) ) + if( Menu_IsSelectable( lTemp ) ) { + Menu_ActiveItem = lTemp; + _Menu_Structure_Debug( 1, strcat( "_SelectNext after loop: ", lTemp.name, "\n" ) ); + return; + } +}; + +void() _Menu_SelectPrev = +{ + local entity lTemp; + + if( !Menu_ActiveItem ) { + _Menu_Structure_Debug( 1, "_SelectPrev: Bad Menu_ActiveItem!\n" ); + return; + } + + // try to select the previous item + lTemp = Menu_ActiveItem; + while( (lTemp = _Menu_GetPrev( lTemp )) != null_entity ) + if( Menu_IsSelectable( lTemp ) ) { + Menu_ActiveItem = lTemp; + _Menu_Structure_Debug( 1, strcat( "_SelectPrev: ", lTemp.name, "\n" ) ); + return; + } + // loop + for( lTemp = Menu_ActiveItem ; _Menu_GetNext( lTemp ) ; lTemp = _Menu_GetNext( lTemp ) ); + for( ; lTemp != Menu_ActiveItem ; lTemp = _Menu_GetPrev( lTemp ) ) { + if( Menu_IsSelectable( lTemp ) ) { + Menu_ActiveItem = lTemp; + _Menu_Structure_Debug( 1, strcat( "_SelectPrev after loop: ", lTemp.name, "\n" ) ); + return; + } + } +}; + +bool() _Menu_SelectUp = +{ + // Menu_ActiveItem is the child + local entity lSelected, lParent, lNode; + + lSelected = Menu_ActiveItem; + if( !lSelected ) { + _Menu_Structure_Debug( 1, "_SelectUp: Bad Menu_ActiveItem!\n" ); + crash(); + return false; + } + + // If we try to select up the active window, we'll pop the menu history + if( lSelected == Menu_ActiveWindow ) { + // If there is no history, we quit the menu + _Menu_Structure_Debug( 2, "_SelectUp: Selecting up current active window..\n" ); + if( Menu_History == null_entity ) { + _Menu_Structure_Debug( 2, "_SelectUp: Empty history -> toggling menu..\n" ); + if( !Menu_Toggle() ) + Menu_Reselect( false ); + return true; + } + + _Menu_Structure_Debug( 2, "_SelectUp: Popping history..\n" ); + Menu_History_Pop(); + } + + lParent = _Menu_GetParent( lSelected ); + if( !lParent ) { + _Menu_Structure_Debug( 2, "_SelectUp: No parent and not active window!\n" ); + return false; + } + + // If this window is selectable, we know that there is at least one selectable item in the parent, + // thus we will select the parent + if( Menu_IsSelectable( lParent ) ) { + Menu_ActiveItem = lParent; + _Menu_Structure_Debug( 1, strcat( "_SelectUp: first parent: ", lParent.name, "\n" ) ); + return true; + } + + // if there is no parent window of this window (lParent), it's the active window + // else we have failed + if( lParent == Menu_ActiveWindow ) { + Menu_ActiveItem = Menu_ActiveWindow; + _Menu_Structure_Debug( 2, strcat( "_SelectUp: select up parent: ", Menu_ActiveItem.name, "\n" ) ); + if( _Menu_SelectUp() ) + return true; + Menu_ActiveItem = lSelected; + return false; + } else if( !lParent._parent ) { + _Menu_Structure_Debug( 1, "_SelectUp: No parent of parent and not active window!\n" ); + return false; + } + + // If not, we try to determine whether the window is the first window with a selectable children in + // the parent window. If lParent is the selected by selectdown, we move up, if not we have found it. + // IDEA: inline this + Menu_ActiveItem = _Menu_GetParent( lParent ); + _Menu_Structure_Debug( 2, strcat( "_SelectUp: SelectDown on parent of parent '", Menu_ActiveItem.name, "' \n" ) ); + _Menu_SelectDown(); + // thanks to embedded windows (and not only them) - added later on - perhaps doesnt really + // fit into the old logic behind it - take this with caution + for( lNode = Menu_ActiveItem ; lNode ; lNode = lNode._parent ) + if( lNode._parent == lParent ) { + Menu_ActiveItem = _Menu_GetParent( lSelected ); //lParent._parent; + if( _Menu_SelectUp() ) + return true; + Menu_ActiveItem = lSelected; + return false; + } + + // else we have already found the window we have searched! + return true; +}; + +void( entity pItem ) _Menu_PrintRunFlag; +bool() _Menu_SelectDown = +{ + // Menu_ActiveItem is the window + local entity lParent, lChild; + + lParent = Menu_ActiveItem; + if( !lParent ) { + _Menu_Structure_Debug( 1, "_SelectDown: Bad Menu_ActiveItem!\n" ); + return false; + } + + // lets find the first selectable item + for( lChild = _Menu_GetFirst( lParent._child ) ; lChild ; lChild = _Menu_GetNext( lChild ) ) + if( Menu_IsSelectable( lChild ) ) { + Menu_ActiveItem = lChild; + _Menu_PrintRunFlag( lChild ); + _Menu_Structure_Debug( 1, strcat( "_SelectDown: ", lChild.name, "\n" ) ); + return true; + } + + // lets find the first window that has a selectable item + for( lChild = _Menu_GetFirst( lParent._child ) ; lChild ; lChild = _Menu_GetNext( lChild ) ) + if( !Menu_IsEmbedded( lChild ) ) { + Menu_ActiveItem = lChild; + _Menu_Structure_Debug( 2, strcat( "_SelectDown: Try child: ", Menu_ActiveItem.name, "\n" ) ); + if( _Menu_SelectDown() ) + return true; + } + + Menu_ActiveItem = lParent; + return false; +}; + +void() _Menu_Reselect = +{ + Menu_ActiveItem = Menu_ActiveWindow; + _Menu_SelectDown(); +}; + +void( bool pUser ) Menu_SelectNext = +{ + Raise_Select( Menu_ActiveItem, false, pUser ); + _Menu_SelectNext(); + Raise_Select( Menu_ActiveItem, true, pUser ); +}; + +void( bool pUser ) Menu_SelectPrev = +{ + Raise_Select( Menu_ActiveItem, false, pUser ); + _Menu_SelectPrev(); + Raise_Select( Menu_ActiveItem, true, pUser ); +}; + +bool( bool pUser ) Menu_SelectUp = +{ + local entity lOld; + + lOld = Menu_ActiveItem; + if( _Menu_SelectUp() ) { + Raise_Select( lOld, false, pUser ); + Raise_Select( Menu_ActiveItem, true, pUser ); + return true; + } + return false; +}; + +bool( bool pUser ) Menu_SelectDown = +{ + local entity lOld; + + lOld = Menu_ActiveItem; + if( _Menu_SelectDown() ) { + Raise_Select( lOld, false, pUser ); + Raise_Select( Menu_ActiveItem, true, pUser ); + return true; + } + return false; +}; + +void( entity pItem, bool pUser ) Menu_Select = +{ + Raise_Select( Menu_ActiveItem, false, pUser ); + _Menu_Structure_Debug( 1, strcat( "Menu_Select: ", pItem.name, "\n" ) ); + Menu_ActiveItem = pItem; + Raise_Select( Menu_ActiveItem, true, pUser ); +}; + +void( bool pUser ) Menu_Reselect = +{ + Raise_Select( Menu_ActiveItem, false, pUser ); + _Menu_Reselect(); + Raise_Select( Menu_ActiveItem, true, pUser ); +}; + +void( entity pMenu, bool pMakeActive, bool pUser ) Menu_JumpToWindow = +{ + Raise_Select( Menu_ActiveItem, false, pUser ); + + // only jump to windows + if( !pMenu._child ) + error("Cant jump to ", pMenu.name, " !\n"); + + // add a history point + if( pMakeActive ) { + Menu_History_Push( pMenu, Util_NullFunction ); + Menu_ActiveWindow = pMenu; + } + + // now set the selected to the first selectable child + Menu_ActiveItem = pMenu; + if( !_Menu_SelectDown() ) + error( "Couldn't jump to ", pMenu.name, " !\n" ); + + Raise_Select( Menu_ActiveItem, true, pUser ); +}; + +#ifdef USEFUNCTIONS +bool( entity pEntity, float pFlag ) Menu_HasFlag = +{ + if( pEntity.flag & pFlag ) + return true; + return false; +}; + +bool( entity pEntity, float pRunFlag ) Menu_HasRunFlag = +{ + if( pEntity._runFlag & pRunFlag ) + return true; + return false; +}; +#endif + +entity( entity pOrigin, string pName, bool pThrow ) Menu_GetItemEx = +{ + local entity lItem; + + // FIXME: perhaps add another function or do this in some other way + if( substring( pName, 0, 2 ) == "::" ) + lItem = findstring( null_entity, name, substring( pName, 2, 100000 ) ); + // support for direction tokens, init token ## + else if( substring( pName, 0, 2 ) == "##" ) { + local string lToken; + local float lCount, lCounter; + lItem = pOrigin; + lCount = tokenize( substring( pName, 2, 100000 ) ); + // we have the following tokens atfer the ##: up down next prev + for( lCounter = 0 ; lCounter < lCount && lItem ; ++lCounter ) { + lToken = argv( lCounter ); + if( lToken == "up" ) + lItem = lItem._parent; + else if( lToken == "down" ) + lItem = lItem._child; + else if( lToken == "next" ) + lItem = lItem._next; + else if( lToken == "prev" ) + lItem = lItem._prev; + else + error( "Bad direction link(bad token): '", pName, "'!" ); + } + } else { + // we start from the current namespace and try to find the object + // by checking for it in all parent namespaces + lItem = null_entity; + while( !lItem && (pOrigin = pOrigin._parent) != null_entity ) + lItem = findstring( null_entity, name, strcat( pOrigin.name, "::", pName ) ); + + if( !lItem ) + lItem = findstring( null_entity, name, pName ); + } + + if( lItem == null_entity && pThrow ) + error( "Couldn't find item '", pName, "'!" ); + + return lItem; +}; + +entity( entity pOrigin, string pName, bool pThrow ) Menu_GetChildEx = +{ + local entity lItem; + + if( pOrigin ) + lItem = findstring( null_entity, name, strcat( pOrigin.name, "::", pName ) ); + else + lItem = findstring( null_entity, name, pName ); + + if( lItem == null_entity && pThrow ) + error( "Couldn't find item '", pName, "'!" ); + + return lItem; +}; + +entity( string pName ) Menu_GetItem = +{ + return Menu_GetItemEx( self, pName, true ); +}; + +entity( string pName ) Menu_GetChild = +{ + return Menu_GetChildEx( self, pName, true ); +}; + +void( entity pWindow ) Menu_EmptyWindow = +{ + local entity lChild; + + for( lChild = pWindow._child ; lChild ; lChild = lChild._next ) { + Menu_EmptyWindow( lChild ); + Raise_Destroy( lChild ); + remove( lChild ); + } + + pWindow._child = null_entity; +}; + +void( entity pEntity ) Menu_RemoveItem = +{ + local entity lParent; + // raise the destroy event + lParent = pEntity._parent; + Menu_EmptyWindow( pEntity ); + Raise_Destroy( pEntity ); + remove( pEntity ); + if( lParent ) + Menu_LinkChildren( lParent ); +}; + +void( entity pItem ) _Menu_PrintRunFlag = +{ + if( sys_debug_runflag ) { + print( " ", pItem.name, " Runflags: " ); + if( pItem._runFlag & RUNFLAG_TEMPLATE ) + print( "TEMPLATE " ); + if( pItem._runFlag & RUNFLAG_MOUSEINAREA ) + print( "MOUSEINAREA " ); + if( pItem._runFlag & RUNFLAG_HADMOUSE ) + print( "HADMOUSE " ); + if( pItem._runFlag & RUNFLAG_CHILDDRAWONLY ) + print( "CHILDDRAWONLY " ); + if( pItem._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY ) + print( "CHILDDRAWUPDATEONLY " ); + if( pItem._runFlag & RUNFLAG_HIDDEN ) + print( "HIDDEN " ); + if( pItem._runFlag & RUNFLAG_CLIPPED ) + print( "CLIPPED " ); + if( pItem._runFlag & RUNFLAG_NOSELECT ) + print( "NOSELECT " ); + print( "\n" ); + } +}; + +void( entity pItem ) Menu_SetRunFlag = +{ + // RUNFLAG_TEMPLATE + if( pItem.flag & FLAG_TEMPLATE ) + pItem._runFlag = pItem._runFlag | RUNFLAG_TEMPLATE; + // RUNFLAG_HADMOUSE, + if( pItem._runFlag & RUNFLAG_MOUSEINAREA ) + pItem._runFlag = (pItem._runFlag - RUNFLAG_MOUSEINAREA) | RUNFLAG_HADMOUSE; + // RUNFLAG_MOUSEINAREA, + // these will be handled in MENU_PROCESS_MOUSE + // RUNFLAG_CHILDDRAWONLY, + // RUNFLAG_CHILDDRAWONLY, + // these two are handled in InheritRunFlag + // RUNFLAG_CLIPPED, + // check if it is within the clipping area (ie. really visible) + // trick: since the position and size are clipped against the previous clipping area + // Menu_Clip_Size will be '0 0 0', if the areas dont overlap + if( Menu_Clip_Size == '0 0 0' && Menu_Clip_Position != '0 0 0' ) + pItem._runFlag = pItem._runFlag | RUNFLAG_CLIPPED; + // RUNFLAG_HIDDEN + if( ( pItem.flag & FLAG_HIDDEN ) || + ( pItem._runFlag & RUNFLAG_TEMPLATE ) || + ( ( pItem.flag & FLAG_SERVERONLY ) && !( gamestatus & GAME_ISSERVER ) ) || + ( ( pItem.flag & FLAG_CONNECTEDONLY ) && !( gamestatus & GAME_CONNECTED ) ) || + ( ( pItem.flag & FLAG_DEVELOPERONLY ) && !( gamestatus & GAME_DEVELOPER ) ) ) + pItem._runFlag = pItem._runFlag | RUNFLAG_HIDDEN; + // RUNFLAG_NOSELECT + if( ( pItem.flag & FLAG_NOSELECT ) || + ( pItem.flag & FLAG_DRAWONLY ) || + ( pItem.flag & FLAG_DRAWUPDATEONLY ) || + ( pItem.flag & FLAG_EMBEDDED ) || + ( pItem._runFlag & RUNFLAG_TEMPLATE ) || + ( pItem._runFlag & RUNFLAG_HIDDEN ) || + ( pItem._runFlag & RUNFLAG_CHILDDRAWONLY ) || + ( pItem._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY ) ) + pItem._runFlag = pItem._runFlag | RUNFLAG_NOSELECT; + + _Menu_PrintRunFlag( pItem ); +}; + +void( entity pParent, entity pItem ) Menu_InheritRunFlag = +{ + // reset the runflag + pItem._runFlag = pItem._runFlag & (RUNFLAG_MOUSEINAREA | RUNFLAG_DELETEFRAME | RUNFLAG_DELETETOGGLE | RUNFLAG_SPAWNED); + // inherit template + if( pParent._runFlag & RUNFLAG_TEMPLATE ) + pItem._runFlag = pItem._runFlag | RUNFLAG_TEMPLATE; + // inherit drawonly + if( ( pParent._runFlag & RUNFLAG_CHILDDRAWONLY ) || + ( pParent.flag & FLAG_CHILDDRAWONLY ) ) + pItem._runFlag = pItem._runFlag | RUNFLAG_CHILDDRAWONLY; + // inherit drawupdateonly + if( ( pParent._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY ) || + ( pParent.flag & FLAG_CHILDDRAWUPDATEONLY ) ) + pItem._runFlag = pItem._runFlag | RUNFLAG_CHILDDRAWUPDATEONLY; + if( pParent._runFlag & RUNFLAG_HIDDEN ) + pItem._runFlag = pItem._runFlag | RUNFLAG_HIDDEN; +}; + +void() Menu_UpdateRunFlags = +{ + local vector lPos, lSize, lOrg; + + lPos = Menu_Clip_Position; + lSize = Menu_Clip_Size; + lOrg = Menu_Origin; + + Menu_Process_Setup(); + + // set the runflag of the active window + Menu_ActiveWindow._runFlag = Menu_ActiveWindow._runFlag & RUNFLAG_MOUSEINAREA; + + // update runflag by using the view tree + Menu_ProcessRunFlag( Menu_ActiveWindow ); + + Menu_Clip_Size = lSize; + Menu_Clip_Position = lPos; + Menu_Origin = lOrg; + Menu_Cursor_Position = Cursor_Position - Menu_Origin; +}; + +bool( entity pEntity ) Menu_HasEvents = +{ + if( pEntity._runFlag & RUNFLAG_CHILDDRAWONLY ) + return false; + if( pEntity._runFlag & RUNFLAG_CHILDDRAWUPDATEONLY ) + return false; + if( pEntity.flag & FLAG_DRAWONLY ) + return false; + if( pEntity.flag & FLAG_DRAWUPDATEONLY ) + return false; + //if( pEntity._runflag & RUNFLAG_HIDDEN ) + // return false; + return true; +}; + +#ifdef USEFUNCTIONS +bool( entity pEntity ) Menu_IsVisible = +{ + return !(pEntity._runFlag & (RUNFLAG_HIDDEN | RUNFLAG_CLIPPED)); +}; + +bool( entity pEntity ) Menu_IsSelectable = +{ + return !(pEntity._runFlag & RUNFLAG_NOSELECT); // && !(pEntity._runFlag & RUNFLAG_TEMPLATE); +}; + +bool( entity pEntity ) Menu_IsTemplate = +{ + return pEntity._runFlag & RUNFLAG_TEMPLATE; +}; + +bool( entity pEntity ) Menu_IsEmbedded = +{ + return pEntity.flag & FLAG_EMBEDDED; +}; + +string( entity pItem ) Menu_GetName = +{ + return substring( pItem.name, strlen( pItem.parent ) + 2, 100000 ); +}; +#endif diff --git a/scmenu/source/system/structure.qh b/scmenu/source/system/structure.qh new file mode 100644 index 000000000..d53a0eaf3 --- /dev/null +++ b/scmenu/source/system/structure.qh @@ -0,0 +1,84 @@ +// DP/Nex Menu +// system/structure.qh + +entity Menu_ActiveWindow; + +// points to the lowest selected menu item (that has no child item selected) +entity Menu_ActiveItem; + +/////////////// +// prototypes +/// + +// help if you need to iterate through embedded items, too +entity( entity pItem ) _Menu_GetParent; +entity( entity pItem ) _Menu_GetFirst; +entity( entity pItem ) _Menu_GetLast; +entity( entity pItem ) _Menu_GetNext; +entity( entity pItem ) _Menu_GetPrev; +bool( entity pItem, entity pParent ) _Menu_IsEmbeddedParentOf; + +// INFO: SelectUp/Down rules: +// INFO: Down: +// INFO: 1. try to select a selectable item +// INFO: 2. try to select a subwindow +// INFO: Up: +// INFO: 1. try to select the parent +// INFO: 2. select down the parent +// INFO: 3. select up the parent + +// raw select +void() _Menu_SelectNext; +void() _Menu_SelectPrev; +bool() _Menu_SelectUp; +bool() _Menu_SelectDown; +void() _Menu_Reselect; + +void( bool pUser ) Menu_SelectNext; +void( bool pUser ) Menu_SelectPrev; +bool( bool pUser ) Menu_SelectUp; +bool( bool pUser ) Menu_SelectDown; +void( bool pUser ) Menu_Reselect; + +void( entity pItem, bool pUser ) Menu_Select; +void( entity pMenu, bool pMakeActive, bool pUser ) Menu_JumpToWindow; + +bool( entity pEntity ) Menu_HasEvents; + +#ifdef USEFUNCTIONS +bool( entity pEntity ) Menu_IsVisible; +bool( entity pEntity ) Menu_IsSelectable; +bool( entity pEntity ) Menu_IsTemplate; +bool( entity pEntity ) Menu_IsEmbedded; + +bool( entity pEntity, float pFlag ) Menu_HasFlag; +bool( entity pEntity, float pRunFlag ) Menu_HasRunFlag; +#else +#define Menu_IsVisible(pEntity) (!((pEntity)._runFlag & (RUNFLAG_HIDDEN | RUNFLAG_CLIPPED))) +#define Menu_IsSelectable(pEntity) (!((pEntity)._runFlag & RUNFLAG_NOSELECT)) +#define Menu_IsTemplate(pEntity) ((pEntity)._runFlag & RUNFLAG_TEMPLATE) +#define Menu_IsEmbedded(pEntity) ((pEntity).flag & FLAG_EMBEDDED) + +#define Menu_HasFlag(pEntity,pFlag) ((pEntity).flag & (pFlag)) +#define Menu_HasRunFlag(pEntity,pRunFlag) ((pEntity)._runFlag & (pRunFlag)) +#endif + +void( entity pEntity ) Menu_SetRunFlag; +void( entity pParent, entity pEntity ) Menu_InheritRunFlag; + +void() Menu_UpdateRunFlags; + +void( entity pWindow ) Menu_EmptyWindow; +void( entity pEntity ) Menu_RemoveItem; + +entity( entity pOrigin, string pName, bool pThrow ) Menu_GetItemEx; +entity( entity pOrigin, string pName, bool pThrow ) Menu_GetChildEx; + +entity( string pName ) Menu_GetItem; // pOrigin = self +entity( string pName ) Menu_GetChild; + +#ifdef USEFUNCTIONS +string( entity pItem ) Menu_GetName; // gets the name without the parent namespace +#else +#define Menu_GetName(pItem) (substring( (pItem) .name, strlen( (pItem) .parent ) + 2, 100000 )) +#endif diff --git a/scmenu/source/todo b/scmenu/source/todo new file mode 100644 index 000000000..8bb48f992 --- /dev/null +++ b/scmenu/source/todo @@ -0,0 +1,72 @@ +// Todo list + +*-Rename Item_Composition and make it not embedded by default +*-Add support for a MOUSECLIP flag which will make the menu not pass any mouse events to the items under it +*-Move the normal key function somewhere else perhaps?? +--Write a test menu +--Unroll as menu recursive functions as possible +f-Remove this bloody RUNFLAG_SPAWNED again +*-Only spawn an item once(even if its tried to spawn it multiple times) +-Think about the layout alignment and improve it +-Calculate the clip sizes and positions only once in PROCESS_RUNFLAG +-Add #enum and #enumflags to the parser +-Add effect support to all bloody items, use fixed names - if non existent ignore - change Menu_GetItem to a non-erroring version for this +-Add extended # commands like #add or #and, #complement, etc. +-Rewrite isframe to allow automation to create a good amount of new items +*-Clip the Item_DataLink_Value value strings (so it contains e.g. 1.45 instead of 1.450000) +*-Make all datalinks route all ITEM_DATA events +-Make FLOATING window clip its movement to the parent window's size so you cant hide it this way +-Fix orderPos in LinkChildren +-Add a slist subsystem to base! +-Do a big naming check to smooth things out +-Move the _menu_process stuff somewhere else +-Only call the mouse event when the position has been changed - since all changes happens then +-Perhaps make the RUNFLAGs be reset every frame for all items? +-Spend some time writing docs for the API - preferably at http://wiki.quakesrc.org :/ +-Write a parser readme file explaining every tiny, little bit of it +/-Add effects items/classes +/-Rewrite isframe +/-Think about when to support ctcalls and when not +//-Add full support for the template idea or remove it +?s-Make altstring and property conform with the new string param rules +?s-Make the Data items support runtime changes, too +?-Restructurize the controls +f-Add some kind of overlay control +f-Remove TokenType +f-Remove support for cliparea '0 0 0'-'0 0 0' => whole plane +s-Add a color and alpha stack to mgfx +s-Add a current namespace global that builds the current namespace from the parent lists +s-Add the abstract Item Item_Selectable +s-Remove all ctcall, customizeable events + +*-Add ._runflags to system/item.qc - which will be used to determine visibility, etc. of items +*-Add MENU_PROCESS_KEY to Menu_ProcessEvent +*-Add MENU_PROCESS_RUNFLAG +*-Add RUNFLAG_CLIPPED, so we can select items that arent visible (but arent hidden intentionally as well -> scrollwindows) +*-Add a .userselect event (Toddd) +*-Add a multiline label item class +*-Add a real #include to the parser +*-Add a scmenu_debug_process_filter cvar (only displays information on a specific process run) +*-Add a select event instead of userselect +*-Add a system controlled destruction of items similar to the NG Menu's system +*-Add direction tokens to Menu_GetItem +*-Add layout classes +*-Add more output to the parser (perhaps also a debug mode) +*-Finish the goddamn design +*-Finish the structure debug output +*-Finish this darn #include support!! +*-Fix the _FLAG_MOUSEINAREA bug: if the flag is set and the item is hidden somehow, it wont be unset +*-Fix the init function calling the spawn function for templates, too +*-Fix this strange clipping bug (items plop out of the void instead of shifting slowly in) +*-Implement an embedded window perhaps +*-Make FLAG_DRAWONLY and FLAG_DRAWUPDATEONLY only affect the parent item +*-Merge as many of the debug functions (especially clientarea and parentarea) +*-Move as many constants as possible to constants.menu +*-Remove Item_Init - its poison to deriving classes +*-Rename .refresh to .update and change all constants, too +*-Rename Spawn_ to _Spawn perhaps?? +*-Rename link to target in the DataUser class +*-Rewrite _menu_* to use the normal stack instead of an altstring stack +*-Rewrite all controls +*-Rewrite all gfx functions to reuse the params for conversions, etc. +*-Update scmenu_debug_parser to also support tokens instead of pure floats diff --git a/scmenu/source/util/altstring.qc b/scmenu/source/util/altstring.qc new file mode 100644 index 000000000..f64e433ea --- /dev/null +++ b/scmenu/source/util/altstring.qc @@ -0,0 +1,260 @@ +// NG-Menu +// util/altstring.qc + +#ifdef UTILALTSTRING +/* +=================== +Util_GetAltStringCount +=================== +*/ +float( string pStr ) Util_GetAltStringCount = +{ + local float lLength; + local float lCount; + local float lPosition; + local string lLetter; + + lPosition = lCount = 0; + for( lLength = strlen( pStr ) ; lPosition < lLength ; lPosition++ ) { + lLetter = substring( pStr, lPosition, 1 ); + if( lLetter == "'" ) + lCount++; + else if( lLetter == "\\" ) + lPosition++; + } + + return floor( lCount / 2 ); +}; + +/* +=================== +Util_GetAltStringItem +=================== +*/ +string( string pStr, float pCount ) Util_GetAltStringItem = +{ + local float lCount; + local float lPosition; + local float lLength; + local string lLetter; + local string lOut; + + pCount = pCount*2 + 1; // number of ' until item starts + lCount = lPosition = 0; + for( lLength = strlen( pStr ) ; lPosition < lLength && lCount < pCount ; lPosition++ ) { + lLetter = substring( pStr, lPosition, 1 ); + + if( lLetter == "'" ) + lCount = lCount + 1; + else if( lLetter == "\\" ) + lPosition++; + } + + if( lCount != pCount ) + return String_Create(); + + for( lOut = "" ; lPosition < lLength ; lPosition++ ) { + lLetter = substring( pStr, lPosition, 1 ); + + if( lLetter == "'" ) + break; + else if( lLetter == "\\" ) { + lPosition++; + if( lPosition >= lLength ) + break; + lLetter = substring( pStr, lPosition, 1 ); + } + + lOut = strcat( lOut, lLetter ); // no need for strzone since there are 16 buffers and we use 2 in the for + } + + return String_Zone( lOut ); // return a strzoned string +}; +#else +float( string pStr ) Util_GetAltStringCount = +{ + return altstr_count( pStr ); +}; +string( string pStr, float pCount ) Util_GetAltStringItem = +{ + return String_Zone( altstr_get( pStr, pCount ) ); +}; +#endif + + +/* +=================== +Util_SetAltStringItem +=================== +*/ +#ifdef UTILALTSTRING +string( string pAlt, float pIndex, string pSet ) Util_SetAltStringItem = +{ + local float lCount; + local float lPosition; + local float lStart; + local float lLength; + local string lLetter; + local string lOut; + + pSet = String_Zone( pSet ); + + pIndex = pIndex*2 + 1; // number of ' until item starts + lCount = lPosition = 0; + for( lLength = strlen( pAlt ) ; lPosition < lLength && lCount < pIndex ; lPosition = lPosition + 1 ) { + lLetter = substring( pAlt, lPosition, 1 ); + + if( lLetter == "'" ) + lCount = lCount + 1; + else if( lLetter == "\\" ) + lPosition = lPosition + 1; + } + + if( lCount != pIndex ) + return pAlt; + + lStart = lPosition; + // find the end of it + for( ; lPosition < lLength ; lPosition++ ) { + lLetter = substring( pAlt, lPosition, 1 ); + + if( lLetter == "'" ) + break; + else if( lLetter == "\\" ) + lPosition = lPosition + 1; + } + + lOut = String_Substring( pAlt, 0, lStart ); + pSet = Util_AltStringPrepare( String_Normal( pSet ) ); + lOut = strcat( lOut, String_Normal( pSet ), substring( pAlt, lPosition, lLength - lPosition ) ); + + return String_Set( pAlt, lOut ); +}; +#else +string( string pAlt, float pIndex, string pSet ) Util_SetAltStringItem = +{ + return String_Set( pAlt, altstr_set( pAlt, pIndex, pSet ) ); +}; +#endif + +/* +=================== +Util_DelAltStringItem +=================== +*/ +string( string pAlt, float pIndex ) Util_DelAltStringItem = +{ + local float lCount; + local float lPosition; + local float lStart; + local float lLength; + local string lLetter; + local string lOut; + + pIndex = pIndex*2 + 1; // number of ' until item starts + lCount = lPosition = 0; + for( lLength = strlen( pAlt ) ; lPosition < lLength && lCount < pIndex ; lPosition = lPosition + 1 ) { + lLetter = substring( pAlt, lPosition, 1 ); + + if( lLetter == "'" ) + lCount = lCount + 1; + else if( lLetter == "\\" ) + lPosition = lPosition + 1; + } + + if( lCount != pIndex ) + return pAlt; + + lStart = lPosition; + // find the end of it + for( ; lPosition < lLength ; lPosition++ ) { + lLetter = substring( pAlt, lPosition, 1 ); + + if( lLetter == "'" ) + break; + else if( lLetter == "\\" ) + lPosition = lPosition + 1; + } + + if( lStart > 0 ) + lOut = substring( pAlt, 0, lStart - 1 ); + if( lPosition < lLength - 1) + lOut = strcat( lOut, substring( pAlt, lPosition + 1, lLength - lPosition - 1) ); + + return String_Set( pAlt, lOut ); +}; + +/* +=================== +Util_AltStringPrepare +=================== +*/ +#ifdef UTILALTSTRING +string( string pString ) Util_AltStringPrepare = +{ + local string lOut, lChar; + local float lPos, lLength; + + pString = String_Zone( pString ); + + lOut = ""; + lLength = strlen( pString ); + for( lPos = 0; lPos < lLength ; lPos = lPos + 1 ) { + lChar = substring( pString, lPos, 1 ); + if( lChar == "'" ) + lChar = "\\'"; + lOut = strcat( lOut, lChar ); + } + + String_Free( pString ); + return String_Zone( lOut ); +}; +#else +string( string pString ) Util_AltStringPrepare = +{ + return String_Zone( altstr_prepare( pString ) ); +}; +#endif + +/* +=================== +Util_AltStringPush +=================== +*/ +string( string pAlt, string pPush ) Util_AltStringPush = +{ + return String_Set( pAlt, strcat( "'", String_Normal( Util_AltStringPrepare( pPush ) ), "'", pAlt ) ); +}; + +/* +=================== +Util_GetAltStringTop +=================== +*/ +string( string pAlt ) Util_GetAltStringTop = +{ + return Util_GetAltStringItem( pAlt, 0 ); +}; + +/* +=================== +Util_AltStringPop +=================== +*/ +string( string pAlt ) Util_AltStringPop = +{ + local float lPos, lCount, lLength; + local string lChar; + + lCount = 0; + lLength = strlen( pAlt ); + for( lPos = 0 ; lPos < lLength && lCount < 2 ; lPos++) { + lChar = substring( pAlt, lPos, 1 ); + if( lChar == "\\" ) + lPos++; + else if( lChar == "'" ) + lCount++; + } + + return String_Set( pAlt, substring( pAlt, lPos, lLength - lPos ) ); // no - 1 because this time we dont break after the ' +}; diff --git a/scmenu/source/util/altstring.qh b/scmenu/source/util/altstring.qh new file mode 100644 index 000000000..4b1e84bca --- /dev/null +++ b/scmenu/source/util/altstring.qh @@ -0,0 +1,14 @@ +// NG Menu +// util/altstring.qh + +// used to extract 'string' strings from a normal string +// INFO: the index into the altstring is the same like in a C array +float( string s) Util_GetAltStringCount; +string( string s, float c ) Util_GetAltStringItem; +string( string pAlt, float pIndex, string pSet ) Util_SetAltStringItem; +string( string pAlt, float pIndex ) Util_DelAltStringItem; + +string( string pString ) Util_AltStringPrepare; +string( string pAlt, string pPush ) Util_AltStringPush; //strzone +string( string pAlt ) Util_GetAltStringTop; +string( string pAlt ) Util_AltStringPop; // strzone diff --git a/scmenu/source/util/nfunction.qc b/scmenu/source/util/nfunction.qc new file mode 100644 index 000000000..0253ea2d2 --- /dev/null +++ b/scmenu/source/util/nfunction.qc @@ -0,0 +1,9 @@ +// NG Menu +// util/nfunction.qc + +void() Util_NullFunction = {}; +bool() Util_TrueFunction = { return true; }; +bool() Util_FalseFunction = { return false; }; +string() Util_StringFuntion = { return ""; }; +vector() Util_VectorFunction = { return '0 0 0'; }; +entity() Util_EntityFunction = { return null_entity; }; diff --git a/scmenu/source/util/property.qc b/scmenu/source/util/property.qc new file mode 100644 index 000000000..4df4b9ef4 --- /dev/null +++ b/scmenu/source/util/property.qc @@ -0,0 +1,275 @@ +// NG Menu +// util/property.qc + +#ifdef DEBUG + #define DebugValidate(str) Property_Validate( str ) +#else + #define DebugValidate(str) true +#endif + +/* +=================== +Property_Create +=================== +*/ +string() Property_Create = +{ + return String_Create(); +}; + +string( string pString ) Property_Zone = +{ + return String_Zone( pString ); +}; + +string( string pString ) Propery_Free = +{ + return String_Free( pString ); +}; + +/* +=================== +Property_Validate +=================== +*/ +bool( string pString ) Property_Validate = +{ + local float lCount; + + lCount = Util_GetAltStringCount( pString ); + // check whether this is a valid property string + if( rint( lCount / 2 ) != lCount / 2 ) +#ifdef STRICTRULES + error( __FUNC__, "Invalid property string \"", pString , "\"!\n" ); +#else + { + dprint( __FUNC__, "Invalid property string \"", pString, "\"!\n" ); + return false; + } +#endif + return true; +}; + +/* +=================== +Property_Exists +=================== +*/ +bool( string pString, string pName ) Property_Exists = +{ + local float lCount; + local float lCounter; + + if( !DebugValidate( pString ) ) + return false; + + lCount = Util_GetAltStringCount( pString ); + for( lCounter = 0 ; lCounter < lCount ; lCounter += 2 ) + if( String_Normal( Util_GetAltStringItem( pString, lCounter ) ) == pName ) + return true; + return false; +}; + +/* +=================== +Property_Register +=================== +*/ +string( string pString, string pName, string pInitValue ) Property_Register = +{ + local float lCount; + local float lCounter; + + if( !DebugValidate( pString ) ) + return pString; + + // If the entry already exists, do nothing (thus exit the function) + lCount = Util_GetAltStringCount( pString ); + for( lCounter = 0 ; lCounter < lCount ; lCounter += 2 ) + if( String_Normal( Util_GetAltStringItem( pString, lCounter ) ) == pName ) + return pString; + + // If it hasnt been added yet, create it + pString = Util_AltStringPush( pString, pInitValue ); + pString = Util_AltStringPush( pString, pName ); + + return pString; +} + +/* +=================== +Property_Set +=================== +*/ +string( string pString, string pName, string pValue ) Property_Set = +{ + local float lCount; + local float lCounter; + + if( !DebugValidate( pString ) ) + return pString; + + // Found the entry and set it to the new value + lCount = Util_GetAltStringCount( pString ); + for( lCounter = 0 ; lCounter < lCount ; lCounter += 2 ) + if( String_Normal( Util_GetAltStringItem( pString, lCounter ) ) == pName ) + return Util_SetAltStringItem( pString, lCounter + 1, pValue ); + + // If the property isnt found, it depends on DEBUG and STRICT +#ifdef STRICTRULES + error( __FUNC__, "The property \"", pName, "\" hasn't been declared!\npString = \"", pString, "\"" ); +#else + dprint( __FUNC__, "The property \"", pName, "\" hasn't been declared!\npString = \"", pString, "\"" ); +#endif + + return pString; +}; + +string( string pString, string pOldName, string pNewName ) Property_Rename = +{ + local float lCount; + local float lCounter; + + if( !DebugValidate( pString ) ) + return pString; + + // Found the entry if it already exists + lCount = Util_GetAltStringCount( pString ); + for( lCounter = 0 ; lCounter < lCount ; lCounter += 2 ) + if( String_Normal( Util_GetAltStringItem( pString, lCounter ) ) == pOldName ) + return Util_SetAltStringItem( pString, lCounter, pNewName ); + + // If the property isnt found, it depends on DEBUG and STRICT +#ifdef STRICTRULES + error( __FUNC__, "The property \"", pOldName, "\" hasn't been declared!\npString = \"", pString, "\"" ); +#else + dprint( __FUNC__, "The property \"", pOldName, "\" hasn't been declared!\npString = \"", pString, "\"" ); +#endif + return pString; +}; + +string( string pString, string pName ) Property_Delete = +{ + local float lCount; + local float lCounter; + + if( !DebugValidate( pString ) ) + return pString; + + // Found the entry if it already exists + lCount = Util_GetAltStringCount( pString ); + for( lCounter = 0 ; lCounter < lCount ; lCounter += 2 ) + if( String_Normal( Util_GetAltStringItem( pString, lCounter ) ) == pName ) { + pString = Util_DelAltStringItem( pString, lCounter ); + pString = Util_DelAltStringItem( pString, lCounter ); + return pString; + } + + // If the property isnt found, it depends on DEBUG and STRICT +#ifdef STRICTRULES + error( __FUNC__, "The property \"", pName, "\" hasn't been declared!\npString = \"", pString, "\"" ); +#else + dprint( __FUNC__, "The property \"", pName, "\" hasn't been declared!\npString = \"", pString, "\"" ); +#endif + return pString; +}; + +/* +=================== +Property_Set +=================== +*/ +/* +string( string pString, string pName, string pValue ) Property_Set = +{ + local float lCount; + local float lCounter; + local float lProp; + + // save pValue + pValue = strzone( pValue ); + + if( !DebugValidate( pString ) ) + return pString; + + // Found the entry if it already exists + lCount = Util_GetAltStringCount( pString ); + lProp = -1; + for( lCounter = 0 ; lCounter < lCount ; lCounter += 2 ) + if( Util_GetAltStringItem( pString, lCounter ) == pName ) { + lProp = lCounter; + break; + } + + // If it hasnt been added yet, create it + if( lProp == -1 ) { + pString = Util_AltStringPush( pString, pValue ); + pString = Util_AltStringPush( pString, pName ); + } else + pString = Util_SetAltStringItem( pString, lProp + 1, pValue ); + + strunzone( pValue ); + return pString; +}; +*/ + +/* +=================== +Property_Get +=================== +*/ +string( string pString, string pName ) Property_Get = +{ + local float lCount; + local float lCounter; + + if( !DebugValidate( pString ) ) + return pString; + + // Found the entry and return its value + lCount = Util_GetAltStringCount( pString ); + for( lCounter = 0 ; lCounter < lCount ; lCounter += 2 ) + if( String_Normal( Util_GetAltStringItem( pString, lCounter ) ) == pName ) + return Util_GetAltStringItem( pString, lCounter + 1); + + // If the property isnt found, it depends on DEBUG and STRICT +#ifdef STRICTRULES + error( "The property \"", pName, "\" hasn't been declared!\npString = \"", pString, "\"" ); +#else + dprint( "The property \"", pName, "\" hasn't been declared!\npString = \"", pString, "\"" ); +#endif + + return String_Zone( "" ); +}; + +/* +=================== +Property_GetString +=================== +*/ +string( string pString, string pName ) Property_GetString = +{ + return Property_Get( pString, pName ); +}; + +/* +=================== +Property_GetFloatProperty +=================== +*/ +float( string pString, string pName ) Property_GetFloat = +{ + return stof( String_Normal( Property_Get( pString, pName ) ) ); +}; + +vector( string pString, string pName ) Property_GetVector = +{ + return stov( String_Normal( Property_Get( pString, pName ) ) ); +}; + +entity( string pString, string pName ) Property_GetEntity = +{ + return ftoe( Property_GetFloat( pString, pName ) ); +}; + +#undef DebugValidate() diff --git a/scmenu/source/util/property.qh b/scmenu/source/util/property.qh new file mode 100644 index 000000000..c04d5000f --- /dev/null +++ b/scmenu/source/util/property.qh @@ -0,0 +1,27 @@ +// NG Menu +// util/property.qh + +// INFO: the property functions: +// INFO: to save some entity fields I support property strings, which use altstrings to manage a dynamic +// INFO: range of properties +// INFO: "'nameOfProp''Value''nameOfProp''Value'.." +// INFO: for speed reasons most of the Property_* functions assume that the property string has been validated +// INFO: by Property_Validate +// more or less generic functions +string() Property_Create; +string( string pString ) Property_Zone; +string( string pString ) Propery_Free; +bool( string pString ) Property_Validate; + +bool( string pString, string pName ) Property_Exists; +string( string pString, string pName, string pInitValue ) Property_Register; // doesnt change anything if the property does already exist +string( string pString, string pName, string pValue ) Property_Set; // errors if the property isnt found +//string( string pString, string pName, string pValue ) Property_Set; // if the property doesnt exist yet, it adds it +string( string pString, string pOldName, string pNewName ) Property_Rename; +string( string pString, string pName ) Property_Delete; + +string( string pString, string pName ) Property_Get; +string( string pString, string pName ) Property_GetString; +float( string pString, string pName ) Property_GetFloat; +vector( string pString, string pName ) Property_GetVector; +entity( string pString, string pName ) Property_GetEntity; diff --git a/scmenu/source/util/rect.qc b/scmenu/source/util/rect.qc new file mode 100644 index 000000000..ac59e352b --- /dev/null +++ b/scmenu/source/util/rect.qc @@ -0,0 +1,189 @@ +// NG Menu +// util/rect.qc + +/* +=================== +Util_InRect +=================== +*/ +bool( vector pPoint, vector pPos, vector pSize ) Util_InRect = +{ + if( pPoint_x < pPos_x || pPoint_y < pPos_y || pPoint_x > pPos_x + pSize_x || pPoint_y > pPos_y + pSize_y ) + return false; + return true; +}; + +bool( vector pPos1, vector pSize1, vector pPos2, vector pSize2 ) Util_RectInRect = +{ + local vector lFPos1, lFPos2; + + lFPos1 = pPos1 + pSize1; + lFPos2 = pPos2 + pSize2; + + if( pPos1_x <= lFPos2_x && pPos2_x <= lFPos1_x && pPos1_y <= lFPos2_y && pPos2_y <= lFPos1_y ) + return false; + return true; +}; + +/* +=================== +Util_ClipPoint +=================== +*/ +/* +vector( vector pPoint, vector pPos, vector pSize ) Util_ClipPoint = +{ + local vector lPoint; + lPoint_x = bound( pPos_x, pPoint_x, pPos_x + pSize_x ); + lPoint_y = bound( pPos_y, pPoint_y, pPos_y + pSize_y ); + lPoint_z = 0; + + return lPoint; +}; +*/ + +vector( vector pPoint, vector pClipPos, vector pClipSize ) Util_GetClipDelta = +{ + local vector lPoint; + lPoint_x = bound( pClipPos_x, pPoint_x, pClipPos_x + pClipSize_x ) - pPoint_x; + lPoint_y = bound( pClipPos_y, pPoint_y, pClipPos_y + pClipSize_y ) - pPoint_y; + lPoint_z = 0; + + return lPoint; +}; + +/* +=================== +Util_ClipRect +=================== +*/ +vector( vector pPos, vector pSize, vector pClipPos, vector pClipSize ) Util_ClipRect = +{ + vector lSize; + + //DEBUG: Safe version + //lSize_x = bound( pClipPos_x, pPos_x + pSize_x, pClipPos_x + pClipSize_x ) - bound( pClipPos_x, pPos_x, pClipPos_x + pClipSize_x ); + //lSize_y = bound( pClipPos_y, pPos_y + pSize_y, pClipPos_y + pClipSize_y ) - bound( pClipPos_y, pPos_y, pClipPos_y + pClipSize_y ); + //lSize_x = min( pPos_x + pSize_x, pClipPos_x + pClipSize_x ) - max( pPos_x, pClipPos_x ); + //lSize_y = min( pPos_y + pSize_y, pClipPos_y + pClipSize_y ) - max( pPos_y, pClipPos_y ); + //INFO: we suppose pPos to be already clipped and pSize to have been adjusted(!!) + lSize_x = min( pPos_x + pSize_x, pClipPos_x + pClipSize_x ) - pPos_x; + lSize_y = min( pPos_y + pSize_y, pClipPos_y + pClipSize_y ) - pPos_y; + lSize_z = 0; + + if( lSize_x <= 0 || lSize_y <= 0 ) + return '0 0 0'; + + return lSize; +}; + +/* +=================== +Util_ClipStack_Reset +=================== +*/ +string( string pStack ) Util_ClipStack_Reset = +{ + String_Free( pStack ); + return String_Create(); +}; + +/* +=================== +Util_ClipStack_Push +=================== +*/ +string( string pStack, vector pPos, vector pSize ) Util_ClipStack_Push = +{ + local vector lOldPos, lOldSize, lDelta; + + lOldPos = Util_ClipStack_GetPosition( pStack ); + lOldSize = Util_ClipStack_GetSize( pStack ); + + if( pPos == '0 0 0' && pSize == '0 0 0' ) { + pPos = lOldPos; + pSize = lOldSize; + } else if( lOldPos != '0 0 0' || lOldSize != '0 0 0' ) { + lDelta = Util_GetClipDelta( pPos, lOldPos, lOldSize ); + pPos = pPos + lDelta; + pSize = Util_ClipRect( pPos, pSize - lDelta, lOldPos, lOldSize ); + } + + pStack = Util_AltStringPush( pStack, vtos( pSize ) ); + pStack = Util_AltStringPush( pStack, vtos( pPos ) ); + + return pStack; +}; + +/* +=================== +Util_ClipStack_Pop +=================== +*/ +string( string pStack ) Util_ClipStack_Pop = +{ + pStack = Util_AltStringPop( pStack ); + pStack = Util_AltStringPop( pStack ); + return pStack; +}; + +/* +=================== +Util_ClipStack_GetPosition +=================== +*/ +vector( string pStack ) Util_ClipStack_GetPosition = +{ + return stov( String_Normal( Util_GetAltStringItem( pStack, 0 ) ) ); +}; + +/* +=================== +Util_ClipStack_GetSize +=================== +*/ +vector( string pStack ) Util_ClipStack_GetSize = +{ + return stov( String_Normal( Util_GetAltStringItem( pStack, 1 ) ) ); +}; + +/* +=================== +Util_OriginStack_Reset +=================== +*/ +string( string pStack ) Util_OriginStack_Reset = +{ + String_Free( pStack ); + return String_Create(); +}; + +/* +=================== +Util_OriginStack_Push +=================== +*/ +string( string pStack, vector pOrigin ) Util_OriginStack_Push = +{ + return Util_AltStringPush( pStack, vtos( pOrigin ) ); +}; + +/* +=================== +Util_OriginStack_Pop +=================== +*/ +string( string pStack ) Util_OriginStack_Pop = +{ + return Util_AltStringPop( pStack ); +}; + +/* +=================== +Util_OriginStack_Get +=================== +*/ +vector( string pStack ) Util_OriginStack_Get = +{ + return stov( String_Normal( Util_GetAltStringTop( pStack ) ) ); +}; diff --git a/scmenu/source/util/rect.qh b/scmenu/source/util/rect.qh new file mode 100644 index 000000000..5ac296f96 --- /dev/null +++ b/scmenu/source/util/rect.qh @@ -0,0 +1,27 @@ +// NG Menu +// util/rect.qh + +// rect utils +// a rect def. consists of 2 vectors (pos & size) +bool( vector pPoint, vector pPos, vector pSize ) Util_InRect; +vector( vector pPoint, vector pClipPos, vector pClipSize ) Util_GetClipDelta; +//vector( vector pPoint, vector pPos, vector pSize ) Util_ClipPoint; +// clips the rect [pPos, pSize] against [pClipPos, pClipSize] retuns the clipped size +vector( vector pPos, vector pSize, vector pClipPos, vector pClipSize ) Util_ClipRect; + +bool( vector pPos1, vector pSize1, vector pPos2, vector pSize2 ) Util_RectInRect; + +// clip stack functions +string( string pStack ) Util_ClipStack_Reset; +string( string pStack, vector pPos, vector pSize ) Util_ClipStack_Push; +string( string pStack ) Util_ClipStack_Pop; + +vector( string pStack ) Util_ClipStack_GetPosition; +vector( string pStack ) Util_ClipStack_GetSize; + +// origin stack functions +string( string pStack ) Util_OriginStack_Reset; +string( string pStack, vector pOrigin ) Util_OriginStack_Push; +string( string pStack ) Util_OriginStack_Pop; + +vector( string pStack ) Util_OriginStack_Get; diff --git a/scmenu/source/util/string.qc b/scmenu/source/util/string.qc new file mode 100644 index 000000000..1d08b72a7 --- /dev/null +++ b/scmenu/source/util/string.qc @@ -0,0 +1,123 @@ +// NG Menu +// util/string.qc + +/* +=================== +String_Create +=================== +*/ +string() String_Create = +{ + //return strzone( strcat( "Static, ", self.name ) ); + return strzone( "" ); +}; + +/* +=================== +String_Make +=================== +*/ +string( string pStr ) String_Zone = +{ + return strzone( pStr ); +}; + +/* +=================== +String_Normal +=================== +*/ +string( string pStr ) String_Normal = +{ + local string lResult; + + lResult = strcat( pStr ); + strunzone( pStr ); + + return lResult; +}; + +/* +=================== +String_Free +=================== +*/ +string( string pStr ) String_Free = +{ + strunzone( pStr ); + return ""; +}; + +/* +=================== +String_EntityCreate +=================== +*/ +void( entity pEntity, .string pField ) String_EntityCreate = +{ + //pEntity.pField = strzone( strcat( "Field, ", pEntity.name ) ); + pEntity.pField = strzone( "" ); +}; + +/* +=================== +String_EntityZone +=================== +*/ +void( entity pEntity, .string pField ) String_EntityZone = +{ + pEntity.pField = strzone( pEntity.pField ); +}; + +/* +=================== +String_EntitySet +=================== +*/ +void( entity pEntity, .string pField, string pSet ) String_EntitySet = +{ + strunzone( pEntity.pField ); + pEntity.pField = strzone( pSet ); +}; + +/* +=================== +String_EntityFree +=================== +*/ +void( entity pEntity, .string pField ) String_EntityFree = +{ + strunzone( pEntity.pField ); + pEntity.pField = ""; +}; + +/* +=================== +String_Append +=================== +*/ +string( string pStr, string pApp ) String_Append = +{ + return String_Set( pStr, strcat( pStr, pApp ) ); +}; + +/* +=================== +String_Substring +=================== +*/ +string( string pStr, float pStart, float pLength ) String_Substring = +{ + return strzone( substring( pStr, pStart, pLength ) ); +}; + +/* +=================== +String_Set +=================== +*/ +string( string pStr, string pSet ) String_Set = +{ + strunzone( pStr ); + return strzone( pSet ); +}; diff --git a/scmenu/source/util/string.qh b/scmenu/source/util/string.qh new file mode 100644 index 000000000..122392bf7 --- /dev/null +++ b/scmenu/source/util/string.qh @@ -0,0 +1,22 @@ +// NG Menu +// util/string.h + +// INFO: A function strzones all strings that are passed as params and strzones its return param if it +// INFO: is a string (except if the function knows that the string passed is a zone string). +// INFO: Generally, if you only call builtin functions, you can use a temp string +// INFO: You should know that the VM has 16 temp string buffers, so if you could count how many it takes +// INFO: before you have to strzone something +// TODO: convert altstring and property +string() String_Create; +string( string pStr ) String_Zone; // use this for constants +string( string pStr ) String_Normal; // strunzones pStr and returns a temp buffer version of it +string( string pStr, string pSet ) String_Set; // copies pSet to a new strzoned string +string( string pStr ) String_Free; + +string( string pStr, string pApp ) String_Append; +string( string pStr, float pStart, float pLength ) String_Substring; + +void( entity pEntity, .string pField ) String_EntityCreate; +void( entity pEntity, .string pField ) String_EntityZone; +void( entity pEntity, .string pField, string pSet ) String_EntitySet; +void( entity pEntity, .string pField ) String_EntityFree; diff --git a/scmenu/source/util/text.qc b/scmenu/source/util/text.qc new file mode 100644 index 000000000..cc5766e78 --- /dev/null +++ b/scmenu/source/util/text.qc @@ -0,0 +1,59 @@ +// NG Menu +// util/text.qc + +//INFO: I only care about \n and \0 and the col if in wrapped mode +vector( string pText, vector pLast ) Util_GetEndOfLine = +{ + local string lChar; + + pLast_x = pLast_y; + pLast_z = 0; + while( 1 ) { + lChar = substring( pText, pLast_x, 1 ); + + // newline -> the current char isnt valid + if( lChar == "\n" ) { + // the next valid is char can only be after the \n + pLast_y = pLast_x + 1; + --pLast_x; + return pLast; + } else if( lChar == "" ) { + pLast_y = --pLast_x; + return pLast; + } else { + ++pLast_x; + ++pLast_z; + } + } +}; + +vector( string pText, vector pLast, float pWrapLength ) Util_GetEndOfWrappedLine = +{ + local string lChar; + + pLast_x = pLast_y; + pLast_z = 0; + while( 1 ) { + lChar = substring( pText, pLast_x, 1 ); + + // newline -> the current char isnt valid + if( lChar == "\n" ) { + --pLast_x; + // the next valid is char can only be after the \n + pLast_y = pLast_x + 2; + return pLast; + } else if( lChar == "" ) { + pLast_y = --pLast_x; + return pLast; + } else { + ++pLast_x; + ++pLast_z; + if( !--pWrapLength ) { + // the current char is one too much + pLast_y = pLast_x; + --pLast_x; + return pLast; + } + } + } +}; diff --git a/scmenu/source/util/text.qh b/scmenu/source/util/text.qh new file mode 100644 index 000000000..0eb3890f1 --- /dev/null +++ b/scmenu/source/util/text.qh @@ -0,0 +1,7 @@ +// NG Menu +// util/text.qh + +// text tool functions +// returns a pair +vector( string pText, vector pLast ) Util_GetEndOfLine; +vector( string pText, vector pLast, float pWrapLength ) Util_GetEndOfWrappedLine; diff --git a/scmenu/source/util/uid.qc b/scmenu/source/util/uid.qc new file mode 100644 index 000000000..b86b8eed6 --- /dev/null +++ b/scmenu/source/util/uid.qc @@ -0,0 +1,33 @@ +// NG Menu +// util/uid.qc + +// name format: "M_UID_" number + +var float _m_uid_counter = 0; +string() Util_CreateUID = +{ + local string lName; + + lName = strzone( strcat( "M_UID_", ftos( _m_uid_counter ) ) ); + _m_uid_counter = _m_uid_counter + 1; + return lName; +}; + +string( float pNum ) Util_GetUIDName = +{ + local string lName; + + lName = strzone( strcat( "M_UID_", ftos( pNum ) ) ); + return lName; +}; + +float( string pUid ) Util_GetUIDNum = +{ + local string lNum; + + lNum = substring( pUid, 6, 100000 ); + return stof( lNum ); +}; + + + diff --git a/scmenu/source/util/uid.qh b/scmenu/source/util/uid.qh new file mode 100644 index 000000000..5e7d5e6ca --- /dev/null +++ b/scmenu/source/util/uid.qh @@ -0,0 +1,7 @@ +// NG Menu +// util/uid.qh + +// used to create unique names while the menu runs +string() Util_CreateUID; +string( float pNum ) Util_GetUIDName; +float( string pNum ) Util_GetUIDNum; diff --git a/scmenu/source/util/util.qh b/scmenu/source/util/util.qh new file mode 100644 index 000000000..2feb6769a --- /dev/null +++ b/scmenu/source/util/util.qh @@ -0,0 +1,22 @@ +// NG-Menu +// util/util.qh + +// empty functions for every return type +void() Util_NullFunction; +bool() Util_TrueFunction; +bool() Util_FalseFunction; +string() Util_StringFuntion; +vector() Util_VectorFunction; +entity() Util_EntityFunction; + +// function typedefs + +typedef void() voidFunction; +typedef float() floatFunction; +typedef string() stringFunction; +typedef vector() vectorFunction; + + + + + diff --git a/scmenu/templates.menu b/scmenu/templates.menu new file mode 100644 index 000000000..6270a8092 --- /dev/null +++ b/scmenu/templates.menu @@ -0,0 +1,217 @@ +// Property of Alientrap +// +// Templates + +////////////////////////////////////////////////////////////////////////////////// +// Basic default templates (setting default properties) +////////////////////////////////////////////////////////////////////////////////// +Template Rect Rect +{ + size [InfiniteVector] + alpha 1.0 + drawFlag [DrawFlagNormal] + color '1.0 1.0 1.0' +} +Template Label Label +{ + color [DefaultTextColor] + alpha [DefaultTextAlpha] + drawFlag [DefaultTextDrawFlag] + fontSize [DefaultFontSize] +} +Template Picture Picture +{ + color [DefaultPicColor] + alpha [DefaultPicAlpha] + drawFlag [DefaultPicDrawFlag] +} +Template Button TextButton +{ + fontSize [DefaultFontSize] + color [DefaultTextColor] + colorSelected [DefaultSelTextColor] + colorPressed [DefaultPreTextColor] + alphas_x [DefaultTextAlpha] + alphas_y [DefaultSelTextAlpha] + alphas_z [DefaultPreTextAlpha] + drawFlags_x [DefaultTextDrawFlag] + drawFlags_y [DefaultSelTextDrawFlag] + drawFlags_z [DefaultPreTextDrawFlag] + soundSelected [DefaultSelectSound] + soundPressed [DefaultPressSound] +} +Template Button PictureButton +{ + color [DefaultPicColor] + colorSelected [DefaultSelPicColor] + colorPressed [DefaultPrePicColor] + alphas_x [DefaultPicAlpha] + alphas_y [DefaultSelPicAlpha] + alphas_z [DefaultPrePicAlpha] + drawFlags_x [DefaultPicDrawFlag] + drawFlags_y [DefaultSelPicDrawFlag] + drawFlags_z [DefaultPrePicDrawFlag] + soundSelected [DefaultSelectSound] + soundPressed [DefaultPressSound] +} +Template Slider Slider +{ + color [DefaultPicColor] + //colorSelected [DefaultSelPicColor] + colorSelected "0.9 0.9 1.0" + alphas_x [DefaultPicAlpha] + alphas_y [DefaultSelPicAlpha] + drawFlags_x [DefaultPicDrawFlag] + drawFlags_y [DefaultSelPicDrawFlag] + soundSelected [DefaultSelectSound] + soundIncrease [DefaultIncreaseSound] + soundDecrease [DefaultDecreaseSound] + picture [DefaultSliderBar] + pictureSlider [DefaultSlider] + proportions [DefaultProportions] + direction [DefaultDirection] + size '144 12' + sizeSlider '12 12' +} +Template EditBox EditBox +{ + fontSize [DefaultFontSize] + color [DefaultTextColor] + colorSelected [DefaultTextColor] + colorPressed [DefaultPreTextColor] + alphas_x [DefaultTextAlpha] + alphas_y [DefaultSelTextAlpha] + alphas_z [DefaultPreTextAlpha] + drawFlags_x [DefaultTextDrawFlag] + drawFlags_y [DefaultSelTextDrawFlag] + drawFlags_z [DefaultPreTextDrawFlag] + colorCursor [DefaultCursorColor] + colorCursorFlash [DefaultCursorFlashColor] + alphasCursor_x [DefaultTextAlpha] + alphasCursor_y [DefaultSelTextAlpha] + drawFlagsCursor_x [DefaultTextDrawFlag] + drawFlagsCursor_y [DefaultSelTextDrawFlag] + sizeCursor [DefaultCursorSize] + sizeCursorFlash [DefaultCursorFlashSize] + soundSelected [DefaultSelectSound] + soundMove [DefaultIncreaseSound] + soundKey [DefaultDecreaseSound] +} +DeriveTemplate TextButton ValueButton +{ + type "Item_ValueButton" +} +DeriveTemplate Label MultiLabel +{ + type "Item_MultiLabel" +} +DeriveTemplate TextButton SwitchButton +{ + type "Item_SwitchButton" +} +////////////////////////////////////////////////////////////////////////////////// +// Derived items +////////////////////////////////////////////////////////////////////////////////// +Template Arrangement Composition +{ + flag [FlagEmbedded] +} +////////////////////////////////////////////////////////////////////////////////// +// Specialized items +////////////////////////////////////////////////////////////////////////////////// +Template DataLink_ValueSwitch DataLink_OnOffSwitch +{ + minValue 0.0 + maxValue 1.0 + descList "'Off' 'On'" + link "##up" +} +Template DataLink_Value DataLink_ZeroOneValue +{ + minValue 0.0 + maxValue 1.0 + stepValue 0.05 + link "##up" +} +////////////////////////////////////////////////////////////////////////////////// +// Nexuiz specialized items +////////////////////////////////////////////////////////////////////////////////// +#define Nex_DefaultHorzDirection '10 0 0' +#define Nex_DefaultVertDirection '0 10 0' +Template Automation_Job Nex_Automation_Option_Slider +{ + action Nex_Automation_Option_Slider +} +Template Automation_Job Nex_Automation_Option_EditBox +{ + action Nex_Automation_Option_EditBox +} +Template Automation_Job Nex_Automation_Option_Switch +{ + action Nex_Automation_Option_Switch +} +DeriveTemplate Composition Nex_Composition +{ + direction [Nex_DefaultHorzDirection] +} +DeriveTemplate Picture Nex_Line +{ + picture "gfx/m_dot" + size "200 10" +} +Item Custom Nex_Void +{ + size "200 12" + flag [FlagNoSelect] +} + +DeriveTemplate TextButton Nex_KeyButton +{ + type "Item_Nex_KeyButton" +} + +DeriveTemplate Label Nex_HostCache_StringField +{ + type "Item_Nex_HostCache_StringField" +} +DeriveTemplate Label Nex_HostCache_ValueField +{ + type "Item_Nex_HostCache_ValueField" +} +DeriveTemplate Label Nex_HostCache_Players +{ + type "Item_Nex_HostCache_Players" +} +DeriveTemplate TextButton Nex_HostCache_Entry +{ + normal "$gfx/white" + drawFlags [DrawFlagModulate] + type "Item_Nex_HostCache_Entry" +} + +DeriveTemplate Nex_Composition Nex_Option_Slider +{ + DeriveTemplate Nex_Automation_Option_Slider Automation + {} + DeriveTemplate TextButton Description + {} + DeriveTemplate Slider Slider + { + action Nex_Action_TestOnChange + } + DeriveTemplate ValueButton Value + {} +} +DeriveTemplate Composition Nex_Option_Switch + { + direction [Nex_DefaultHorzDirection] + + DeriveTemplate Nex_Automation_Option_Switch Automation + {} + DeriveTemplate TextButton Description + {} + DeriveTemplate SwitchButton Switch + { + action Nex_Action_TestOnChange + } + } diff --git a/scmenu/test.menu b/scmenu/test.menu new file mode 100644 index 000000000..9363eda0b --- /dev/null +++ b/scmenu/test.menu @@ -0,0 +1,21 @@ +// DP/Nex Menu +// Test Menu +Item Window Normal +{ + pos '100 100' + size '800 500' + + Item Window Test1 + { + pos '10 10' + origin '20 20' + size '100 100' + } + Item Window Test2 + { + pos '200 200' + origin '100 100' + size '300 300' + } +} + -- 2.39.2