optionsMenu.tscript 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  1. //options settings
  2. //Screen and Display menu
  3. //Renderer Mode
  4. //Screen resolution
  5. //Windowed/fullscreen(borderless?)
  6. //VSync
  7. //Screen brightness
  8. //screen brightness
  9. //screen gamma
  10. //Lighting Menu
  11. //Shadow Distance(Distance shadows are drawn to. Also affects shadowmap slices)
  12. //Shadow Quality(Resolution of shadows rendered, setting to none disables dynamic shadows)
  13. //Soft Shadows(Whether shadow softening is used)
  14. //Shadow caching(If the lights enable it, shadow caching is activated)
  15. //Light Draw Distance(How far away lights are still drawn. Doesn't impact vector lights like the sun)
  16. //Mesh and Textures Menu
  17. //Draw distance(Overall draw distance) -slider
  18. //Object draw distance(Draw distance from small/unimportant objects) -slider
  19. //Mesh quality
  20. //Texture quality
  21. //Foliage draw distance
  22. //Terrain Quality
  23. //Decal Quality
  24. //Effects Menu
  25. //Parallax
  26. //HDR
  27. //Light shafts
  28. //Motion Blur
  29. //Depth of Field
  30. //SSAO
  31. //AA(ModelXAmount)[defualt is FXAA]
  32. //Anisotropic filtering
  33. //Keybinds
  34. //Camera
  35. //horizontal mouse sensitivity
  36. //vert mouse sensitivity
  37. //invert vertical
  38. //zoom mouse sensitivities(both horz/vert)
  39. //headbob
  40. //FOV
  41. $yesNoList = "No\tYes";
  42. $onOffList = "Off\tOn";
  43. function OptionsMenu::onAdd(%this)
  44. {
  45. if(!isObject(%this.optionsCategories))
  46. {
  47. %this.optionsCategories = new ArrayObject();
  48. }
  49. if(!isObject(%this.unappliedChanges))
  50. {
  51. %this.unappliedChanges = new ArrayObject(OptionsMenuUnappliedChanges);
  52. }
  53. %this.currentCategory = "";
  54. addOptionsMenuCategory("Display", "populateDisplaySettingsList();");
  55. addOptionsMenuCategory("Graphics", "populateGraphicsSettingsList();");
  56. addOptionsMenuCategory("Audio", "populateAudioSettingsList();");
  57. addOptionsMenuCategory("Keyboard & Mouse", "populateKeyboardMouseSettingsList();");
  58. addOptionsMenuCategory("Gamepad", "populateGamepadSettingsList();");
  59. callOnModules("populateOptionsMenuCategories", "Game");
  60. }
  61. function OptionsMenu::onOpen(%this)
  62. {
  63. OptionsMenuCategoryList.clear();
  64. for(%i=0; %i < %this.optionsCategories.count(); %i++)
  65. {
  66. %catName = %this.optionsCategories.getKey(%i);
  67. %callback = %this.optionsCategories.getValue(%i);
  68. %newCatButton = new GuiButtonCtrl() {
  69. text = %catName;
  70. groupNum = "-1";
  71. buttonType = "PushButton";
  72. useMouseEvents = "0";
  73. position = "0 180";
  74. extent = "248 35";
  75. minExtent = "8 2";
  76. horizSizing = "right";
  77. vertSizing = "bottom";
  78. profile = "GuiMenuButtonProfile";
  79. visible = "1";
  80. active = "1";
  81. command = %callback;
  82. tooltipProfile = "GuiToolTipProfile";
  83. hovertime = "1000";
  84. isContainer = "0";
  85. canSave = "1";
  86. canSaveDynamicFields = "0";
  87. };
  88. OptionsMenuCategoryList.add(%newCatButton);
  89. }
  90. %this.unappliedChanges.empty();
  91. $pref::Video::displayDeviceId = "";
  92. OptionsMenuCategoryList.setAsActiveMenuList();
  93. $activeMenuButtonContainer-->button1.set("btn_back", "R", "Reset", "OptionsMenu.resetToDefaults();");
  94. $activeMenuButtonContainer-->button2.disable();
  95. $activeMenuButtonContainer-->button3.set("", "Space", "Apply", "OptionsMenu.apply();");
  96. $activeMenuButtonContainer-->button4.set("btn_a", "", "Select", "OptionsMenu.select();");
  97. $activeMenuButtonContainer-->button5.set("btn_b", "Escape", "Back", %this @ ".navigation.popPage();");
  98. }
  99. //We capitalize on the canClose test here, because we want to prompt for unapplied options changes before
  100. //backing out. So when the UINavigation test canClose, we can see if we have unapplied settings and prompt
  101. //that via the message box and return false.
  102. //This gives the user a chance to choose how they wish to proceed before we allow the
  103. //UINavigation to move away from the options menu
  104. function OptionsMenu::canClose(%this)
  105. {
  106. //Another special case is us catching the 'back/pop' action by just shifting from one
  107. //menu list to another. In this case, we check if we were on the settings list as our active MenuList
  108. //if so, then the back/pop just moves us to the Category list as our active and we inform the
  109. //UINavigation to not close the page
  110. if(OptionsMenuSettingsList.isActiveMenuList())
  111. {
  112. OptionsMenuCategoryList.setAsActiveMenuList();
  113. return false;
  114. }
  115. else
  116. {
  117. //Here, we're on the category list as our active, so we're actually trying to leae the page
  118. //If we have unapplied changes, we want to prompt about them before closing the page and navigating away
  119. //If we don't, then we can process the popPage as normal and let the OptionsMenu close
  120. if(%this.unappliedChanges.count() != 0)
  121. {
  122. MessageBoxOKCancel("Discard Changes?", "You have unapplied changes to your settings, do you wish to apply or discard them?",
  123. "OptionsMenu.apply(); MainMenuGUI.popPage();", "" @ %this @ ".unappliedChanges.empty(); " @ %this @ ".navigation.popPage();",
  124. "Apply", "Discard");
  125. return false;
  126. }
  127. }
  128. return true;
  129. }
  130. function OptionsMenu::onClose(%this)
  131. {
  132. }
  133. function OptionsMenuSettingsList::onAdd(%this)
  134. {
  135. }
  136. function OptionsMenuSettingsList::getOptionsList(%this, %index)
  137. {
  138. }
  139. function OptionsMenu::select(%this)
  140. {
  141. if(OptionsMenuCategoryList.isActiveMenuList())
  142. {
  143. OptionsMenuSettingsList.setAsActiveMenuList();
  144. }
  145. }
  146. function OptionsMenu::apply(%this)
  147. {
  148. //Now we run through our list of unapplied changes and... apply them.
  149. %hasKeybindChanges = false;
  150. %hasVideoChanges = false;
  151. %hasPostFXChanges = false;
  152. %hasAudioChanges = false;
  153. %hasGraphicsChanges = false;
  154. for(%i=0; %i < %this.unappliedChanges.count(); %i++)
  155. {
  156. %targetVar = %this.unappliedChanges.getKey(%i);
  157. %newValue = strReplace(%this.unappliedChanges.getValue(%i), "\"", "");
  158. //First, lets just check through our action map names, see if any match
  159. %wasKeybind = false;
  160. for(%am=0; %am < ActionMapGroup.getCount(); %am++)
  161. {
  162. %actionMap = ActionMapGroup.getObject(%am);
  163. if(%actionMap == GlobalActionMap.getId())
  164. continue;
  165. %actionMapName = %actionMap.humanReadableName $= "" ? %actionMap.getName() : %actionMap.humanReadableName;
  166. if(%actionMapName $= %targetVar)
  167. {
  168. %hasKeybindChanges = true;
  169. %wasKeybind = true;
  170. break;
  171. }
  172. }
  173. if(!%wasKeybind)
  174. {
  175. %sanitizedVar = strReplace(%targetVar, "[", "");
  176. %sanitizedVar = strReplace(%sanitizedVar, "]", "");
  177. %sanitizedVar = strReplace(%sanitizedVar, ",", "_");
  178. %currentValue = getVariable(%sanitizedVar);
  179. if(%currentValue !$= %newValue)
  180. {
  181. setVariable(%targetVar, %newValue);
  182. //now, lets check for special cases that need additional handling
  183. //for updates
  184. if ( %targetVar $= "$pref::Video::displayDevice" )
  185. {
  186. schedule(32, 0, "MessageBoxOK", "Change requires restart", "Please restart the game for a display device change to take effect.");
  187. }
  188. else if(startsWith(%targetVar, "$pref::PostFX::"))
  189. {
  190. %hasPostFXChanges = true;
  191. }
  192. else if(startsWith(%targetVar, "$pref::Video::"))
  193. {
  194. %hasVideoChanges = true;
  195. //if it's the resolution, it's possible we got the human-friendly
  196. //version stored off. if so, reprocess into the usable state
  197. if(%targetVar $= "$pref::Video::Resolution")
  198. {
  199. if(strpos(%newValue, " x ") != -1)
  200. {
  201. %newValue = strreplace(%newValue, " x ", " ");
  202. setVariable(%targetVar, %newValue);
  203. }
  204. }
  205. //This is a bit of hackery to have an intermediate variable because we display in text
  206. //but save by index, so we take the applied name and get the index of the deviceId
  207. else if(%targetVar $= "$pref::Video::displayDeviceId")
  208. {
  209. %deviceId = getDisplayDeviceId($pref::Video::displayDeviceId);
  210. if(%deviceId == -1)
  211. %deviceId = 0;
  212. $pref::Video::deviceId = %deviceId;
  213. $pref::Video::displayDeviceId = "";
  214. }
  215. }
  216. else if(startsWith(%targetVar, "$pref::SFX::"))
  217. {
  218. %hasAudioChanges = true;
  219. }
  220. else if(startsWith(%targetVar, "$pref::Graphics::"))
  221. {
  222. %hasGraphicsChanges = true;
  223. }
  224. }
  225. }
  226. }
  227. //If we had keybind changes, go ahead and save those out
  228. if(%hasKeybindChanges)
  229. {
  230. %prefPath = getPrefpath();
  231. %actionMapCount = ActionMapGroup.getCount();
  232. %actionMapList = "";
  233. %append = false;
  234. for(%i=0; %i < %actionMapCount; %i++)
  235. {
  236. %actionMap = ActionMapGroup.getObject(%i);
  237. if(%actionMap == GlobalActionMap.getId())
  238. continue;
  239. %actionMap.save( %prefPath @ "/keybinds." @ $TorqueScriptFileExtension, %append );
  240. if(%append != true)
  241. %append = true;
  242. }
  243. }
  244. if(%hasPostFXChanges)
  245. {
  246. updatePostFXSettings();
  247. }
  248. if(%hasVideoChanges)
  249. {
  250. updateDisplaySettings();
  251. }
  252. if(%hasAudioChanges)
  253. {
  254. updateAudioSettings();
  255. }
  256. if(%hasGraphicsChanges)
  257. {
  258. updateGraphicsSettings();
  259. }
  260. //Finally, write our prefs to file
  261. %prefPath = getPrefpath();
  262. export("$pref::*", %prefPath @ "/clientPrefs." @ $TorqueScriptFileExtension, false);
  263. OptionsMenu.unappliedChanges.empty();
  264. }
  265. function OptionsMenu::resetToDefaults(%this)
  266. {
  267. MessageBoxOKCancel("", "This will set the graphical settings back to the auto-detected defaults. Do you wish to continue?", "AutodetectGraphics();", "");
  268. }
  269. function OptionsMenu::refresh(%this)
  270. {
  271. //cache our scroll position so we can ensure we end up back at it after the refresh
  272. %lastScrollPos = OptionsMenuSettingsScroll.getScrollPosition();
  273. %cat = %this.currentCategory;
  274. if(%this.currentCategory !$= "")
  275. {
  276. if(!isInt(%this.currentCategory))
  277. {
  278. %this.currentCategory = getOptionsCategoryIndexByName(%this.currentCategory);
  279. }
  280. if(%this.currentCategory == -1)
  281. return;
  282. %category = %this.optionsCategories.getKey(%this.currentCategory);
  283. %command = %this.optionsCategories.getValue(%this.currentCategory);
  284. eval(%command);
  285. }
  286. //now, because we reconstruct the displayed set, we'll force the mouse(if we're using it as our input)
  287. //to be poked so we can re-track to whatever control, if any, we're over
  288. if($activeControllerType !$= "gamepad")
  289. {
  290. Canvas.setCursorPos(Canvas.getCursorPos());
  291. }
  292. //restore scroll position
  293. OptionsMenuSettingsScroll.setScrollPosition(%lastScrollPos.x, %lastScrollPos.y);
  294. }
  295. function OptionsMenu::getOptionVariableValue(%this, %variableName)
  296. {
  297. %unappliedPrefIndex = %this.unappliedChanges.getIndexFromKey(%variableName);
  298. if(%unappliedPrefIndex != -1)
  299. {
  300. %value = %this.unappliedChanges.getValue(%unappliedPrefIndex);
  301. return strreplace(%value, "\"", "");
  302. }
  303. %sanitizedVar = strReplace(%variableName, "[", "");
  304. %sanitizedVar = strReplace(%sanitizedVar, "]", "");
  305. %sanitizedVar = strReplace(%sanitizedVar, ",", "_");
  306. return getVariable(%sanitizedVar);
  307. }
  308. function OptionsMenuSelectButton::onVisible(%this, %state)
  309. {
  310. //We're sorta cheating here.
  311. //This button should only be displayed when we're in the categories list
  312. //so whenever the status changes, such as automatically refreshing due to
  313. //navigation events, we'll just do a quick check to ensure we're
  314. //in the right visibility mode
  315. if(%state && OptionsMenuSettingsList.isActiveMenuList())
  316. {
  317. %this.setHidden(true);
  318. }
  319. }
  320. //
  321. //
  322. //
  323. function populateDisplaySettingsList()
  324. {
  325. OptionsMenuSettingsList.clear();
  326. OptionsMenu.currentCategory = "Display";
  327. if(isObject(OptionName))
  328. OptionName.setText("");
  329. if(isObject(OptionDescription))
  330. OptionDescription.setText("");
  331. %apiList = "";
  332. %apiCount = GFXInit::getAdapterCount();
  333. %apiIdx = 0;
  334. for(%i=0; %i < %apiCount; %i++)
  335. {
  336. %api = GFXInit::getAdapterType(%i);
  337. if(%api !$= "NullDevice")
  338. {
  339. if(%apiIdx==0)
  340. %apiList = %api;
  341. else
  342. %apiList = %apiList TAB %api;
  343. %apiIdx++;
  344. }
  345. }
  346. trim(%apiList);
  347. %displayDevice = OptionsMenu.getOptionVariableValue("$pref::Video::displayDevice");
  348. if(%displayDevice $= "")
  349. %displayDevice = getDisplayDeviceType();
  350. OptionsMenuSettingsList.addOptionRow("Display API", "$pref::Video::displayDevice", %apiList, false, "", true, "The display API used for rendering.", %displayDevice);
  351. %numDevices = Canvas.getMonitorCount();
  352. %devicesList = getDisplayDeviceList();
  353. if($pref::Video::displayDeviceId $= "")
  354. $pref::Video::displayDeviceId = getField(%devicesList, $pref::Video::deviceId);
  355. OptionsMenuSettingsList.addOptionRow("Display Device", "$pref::Video::displayDeviceId", %devicesList, false, "", true, "The display devices the window should be on.");
  356. if (%numDevices > 1)
  357. OptionsMenuSettingsList.setRowEnabled(1, true);
  358. else
  359. OptionsMenuSettingsList.setRowEnabled(1, false);
  360. %mode = OptionsMenu.getOptionVariableValue("$pref::Video::deviceMode");
  361. if(isInt(%mode))
  362. %mode = getField($Video::ModeTags, $pref::Video::deviceMode);
  363. OptionsMenuSettingsList.addOptionRow("Window Mode", "$pref::Video::deviceMode", $Video::ModeTags, false, "", true, "", %mode);
  364. if(%mode !$= "Borderless")
  365. {
  366. %resolutionList = getScreenResolutionList($pref::Video::deviceId, $Video::Mode[%mode]);
  367. %resolution = OptionsMenu.getOptionVariableValue("$pref::Video::Resolution");
  368. if(%resolution $= "")
  369. %resolution = $pref::Video::mode;
  370. %resolution = _makePrettyResString(%resolution);
  371. OptionsMenuSettingsList.addOptionRow("Resolution", "$pref::Video::Resolution", %resolutionList, false, "", true, "Resolution of the game window", %resolution);
  372. // If the requested resolution could not be set, mark the control and pref as changed.
  373. %resControl = OptionsMenuSettingsList.getObject(OptionsMenuSettingsList.getCount()-1);
  374. if (%resControl.getCurrentOption() !$= %resolution)
  375. %resControl.onChange();
  376. }
  377. OptionsMenuSettingsList.addOptionBoolRow("VSync", "$pref::Video::enableVerticalSync", $YesNoList, false, "", true, "", "");
  378. %refreshList = getScreenRefreshList($pref::Video::mode);
  379. OptionsMenuSettingsList.addOptionRow("Refresh Rate", "$pref::Video::RefreshRate", %refreshList, false, "", true, "", OptionsMenu.getOptionVariableValue("$pref::Video::RefreshRate"));
  380. //move to gameplay tab
  381. //OptionsMenuSettingsList.addSliderRow("Field of View", "", 75, 5, "65 100", "");
  382. //OptionsMenuSettingsList.addSliderRow("Brightness", "", 0.5, 0.1, "0 1", "");
  383. //OptionsMenuSettingsList.addSliderRow("Contrast", "", 0.5, 0.1, "0 1", "");
  384. }
  385. //
  386. //
  387. //
  388. function populateGraphicsSettingsList()
  389. {
  390. OptionsMenuSettingsList.clear();
  391. OptionsMenu.currentCategory = "Graphics";
  392. if(isObject(OptionName))
  393. OptionName.setText("");
  394. if(isObject(OptionDescription))
  395. OptionDescription.setText("");
  396. %yesNoList = "No\tYes";
  397. %onOffList = "Off\tOn";
  398. %anisoFilter = "Off\t4\t8\t16";
  399. %aaTypeFilter = "None\tFXAA\tSMAA\tSMAA High";
  400. OptionsMenuSettingsList.addOptionQualityLevelRow("Lighting Quality", "$pref::Graphics::LightingQuality",
  401. LightingQualityList, false, "", true, "Amount and drawdistance of local lights");
  402. OptionsMenuSettingsList.addOptionQualityLevelRow("Shadow Quality", "$pref::Graphics::ShadowQuality",
  403. ShadowQualityList, false, "", true, "Shadow revolution quality");
  404. %shadowQuality = OptionsMenu.getOptionVariableValue("$pref::Graphics::ShadowQuality");
  405. if(%shadowQuality !$= "None")
  406. {
  407. OptionsMenuSettingsList.addOptionQualityLevelRow("Soft Shadow Quality", "$pref::Graphics::SoftShadowQuality",
  408. SoftShadowList, false, "", true, "Amount of softening applied to shadowmaps");
  409. }
  410. OptionsMenuSettingsList.addOptionQualityLevelRow("Mesh Quality", "$pref::Graphics::MeshQuality",
  411. MeshQualityGroup, false, "", true, "Fidelity of rendering of mesh objects");
  412. OptionsMenuSettingsList.addOptionQualityLevelRow("Object Draw Distance", "$pref::Graphics::ObjectDrawDistance",
  413. MeshDrawDistQualityGroup, false, "", true, "Dictates if and when static objects fade out in the distance");
  414. OptionsMenuSettingsList.addOptionQualityLevelRow("Texture Quality", "$pref::Graphics::TextureQuality",
  415. TextureQualityGroup, false, "", true, "Fidelity of textures");
  416. OptionsMenuSettingsList.addOptionQualityLevelRow("Terrain Quality", "$pref::Graphics::TerrainQuality",
  417. TerrainQualityGroup, false, "", true, "Quality level of terrain objects");
  418. OptionsMenuSettingsList.addOptionQualityLevelRow("Decal Lifetime", "$pref::Graphics::DecalLifetime",
  419. DecalLifetimeGroup, false, "", true, "How long decals are rendered");
  420. OptionsMenuSettingsList.addOptionQualityLevelRow("Ground Cover Density", "$pref::Graphics::GroundCoverDensity",
  421. GroundCoverDensityGroup, false, "", true, "Density of ground cover items, such as grass");
  422. OptionsMenuSettingsList.addOptionQualityLevelRow("Shader Quality", "$pref::Graphics::ShaderQuality",
  423. ShaderQualityGroup, false, "", true, "Dictates the overall shader quality level, adjusting what features are enabled.");
  424. OptionsMenuSettingsList.addOptionRow("Anisotropic Filtering", "$pref::Video::defaultAnisotropy", %anisoFilter, false, "", true, "Amount of Anisotropic Filtering on textures, which dictates their sharpness at a distance");
  425. OptionsMenuSettingsList.addOptionRow("Anti-Aliasing Type", "$pref::Video::AAMode", %aaTypeFilter, false, "", true, "The Anti-Aliasing Method applied to rendering");
  426. OptionsMenuSettingsList.addOptionBoolRow("Parallax", "$pref::Video::enableParallaxMapping", %onOffList, false, "", true, "Whether the surface parallax shader effect is enabled", "");
  427. OptionsMenuSettingsList.addOptionBoolRow("Water Reflections", "$pref::Water::enableTrueReflections", %onOffList, false, "", true, "Whether water reflections are enabled", "");
  428. OptionsMenuSettingsList.addOptionBoolRow("SSAO", "$pref::PostFX::EnableSSAO", %onOffList, false, "", true, "Whether Screen-Space Ambient Occlusion is enabled");
  429. OptionsMenuSettingsList.addOptionBoolRow("Depth of Field", "$pref::PostFX::EnableDOF", %onOffList, false, "", true, "Whether the Depth of Field effect is enabled");
  430. OptionsMenuSettingsList.addOptionBoolRow("Vignette", "$pref::PostFX::EnableVignette", %onOffList, false, "", true, "Whether the vignette effect is enabled");
  431. OptionsMenuSettingsList.addOptionBoolRow("Light Rays", "$pref::PostFX::EnableLightRays", %onOffList, false, "", true, "Whether the light rays effect is enabled");
  432. }
  433. function updateGraphicsSettings()
  434. {
  435. if($pref::Graphics::LightingQuality !$= getCurrentQualityLevel(LightingQualityList))
  436. LightingQualityList.applySetting($pref::Graphics::LightingQuality);
  437. if($pref::Graphics::ShadowQuality !$= getCurrentQualityLevel(ShadowQualityList))
  438. ShadowQualityList.applySetting($pref::Graphics::ShadowQuality);
  439. if($pref::Graphics::SoftShadowQuality !$= getCurrentQualityLevel(SoftShadowList))
  440. SoftShadowList.applySetting($pref::Graphics::SoftShadowQuality);
  441. if($pref::Graphics::MeshQuality !$= getCurrentQualityLevel(MeshQualityGroup))
  442. MeshQualityGroup.applySetting($pref::Graphics::MeshQuality);
  443. if($pref::Graphics::ObjectDrawDistance !$= getCurrentQualityLevel(MeshDrawDistQualityGroup))
  444. MeshDrawDistQualityGroup.applySetting($pref::Graphics::ObjectDrawDistance);
  445. if($pref::Graphics::TextureQuality !$= getCurrentQualityLevel(TextureQualityGroup))
  446. {
  447. TextureQualityGroup.applySetting($pref::Graphics::TextureQuality);
  448. reloadTextures();
  449. }
  450. if($pref::Graphics::TerrainQuality !$= getCurrentQualityLevel(TerrainQualityGroup))
  451. TerrainQualityGroup.applySetting($pref::Graphics::TerrainQuality);
  452. if($pref::Graphics::DecalLifetime !$= getCurrentQualityLevel(DecalLifetimeGroup))
  453. DecalLifetimeGroup.applySetting($pref::Graphics::DecalLifetime);
  454. if($pref::Graphics::GroundCoverDensity !$= getCurrentQualityLevel(GroundCoverDensityGroup))
  455. GroundCoverDensityGroup.applySetting($pref::Graphics::GroundCoverDensity);
  456. if($pref::Graphics::ShaderQuality !$= getCurrentQualityLevel(ShaderQualityGroup))
  457. {
  458. ShaderQualityGroup.applySetting($pref::Graphics::ShaderQuality);
  459. //this has ties into postFX behaviors, so we'll force an update to it here
  460. updatePostFXSettings();
  461. }
  462. }
  463. function updateDisplaySettings()
  464. {
  465. //Update the display settings now
  466. %deviceName = getDisplayDeviceName();
  467. %newDeviceID = getWord(%deviceName, 0) - 1;
  468. if(!isInt($pref::Video::deviceMode))
  469. {
  470. //probably saved out as the mode name, so just translate it back
  471. for(%i=0; %i < getFieldCount($Video::ModeTags); %i++)
  472. {
  473. if(getField($Video::ModeTags, %i) $= $pref::Video::deviceMode)
  474. {
  475. $pref::Video::deviceMode = %i;
  476. break;
  477. }
  478. }
  479. }
  480. %deviceModeName = getField($Video::ModeTags, $pref::Video::deviceMode);
  481. %newDeviceMode = 0;
  482. foreach$(%modeName in $Video::ModeTags)
  483. {
  484. if (%deviceModeName $= %modeName)
  485. break;
  486. else
  487. %newDeviceMode++;
  488. }
  489. if($pref::Video::deviceMode == $Video::ModeBorderless)
  490. {
  491. //if we're changing to borderless, we swap to the full resolution of the desktop
  492. $pref::Video::mode = Canvas.getBestCanvasRes($pref::Video::deviceId, $pref::Video::deviceMode);
  493. $pref::Video::Resolution = $pref::Video::mode.x SPC $pref::Video::mode.y;
  494. }
  495. %newRes = $pref::Video::Resolution;
  496. %newBpp = 32; // ... its not 1997 anymore.
  497. %newFullScreen = %deviceModeName $= "Fullscreen" ? true : false;
  498. %newRefresh = $pref::Video::RefreshRate;
  499. %newVsync = $pref::Video::enableVerticalSync;
  500. %newAA = $pref::Video::AA;
  501. // Build the final mode string.
  502. %newMode = $pref::Video::Resolution SPC %newFullScreen SPC %newBpp SPC %newRefresh SPC %newAA;
  503. // Change the video mode.
  504. if ( %newMode !$= $pref::Video::mode || %newDeviceID != $pref::Video::deviceId ||
  505. %newVsync != $pref::Video::enableVerticalSync || %newDeviceMode != $pref::Video::deviceMode)
  506. {
  507. //****Edge Case Hack
  508. // If we're in fullscreen mode and switching to a different monitor at the
  509. // same resolution and maintaining fullscreen, GFX...WindowTarget::resetMode()
  510. // will early-out because there is no "mode change" and the monitor change
  511. // will not get applied. Instead of modifying platform code, we're going to
  512. // move onto the new monitor in borderless and immediately switch to FS.
  513. if (%newFullScreen && $pref::Video::FullScreen &&
  514. ($pref::Video::Resolution $= %newRes) && ($pref::Video::deviceId != %newDeviceID))
  515. {
  516. $pref::Video::deviceId = %newDeviceID;
  517. $pref::Video::deviceMode = $Video::ModeBorderless;
  518. %tmpModeStr = Canvas.getMonitorMode(%newDeviceID, 0);
  519. Canvas.setVideoMode(%tmpModeStr.x, %tmpModeStr.y, false, 32, getWord(%tmpModeStr, $WORD::REFRESH), %newAA);
  520. }
  521. $pref::Video::mode = %newMode;
  522. $pref::Video::enableVerticalSync = %newVsync;
  523. $pref::Video::deviceId = %newDeviceID;
  524. $pref::Video::deviceMode = %newDeviceMode;
  525. $pref::Video::Resolution = %newRes;
  526. $pref::Video::FullScreen = %newFullScreen;
  527. $pref::Video::RefreshRate = %newRefresh;
  528. $pref::Video::AA = %newAA;
  529. configureCanvas();
  530. }
  531. }
  532. function updatePostFXSettings()
  533. {
  534. PostFXManager.settingsEffectSetEnabled(SSAOPostFx, $pref::PostFX::EnableSSAO);
  535. PostFXManager.settingsEffectSetEnabled(DepthOfFieldPostFX, $pref::PostFX::EnableDOF);
  536. PostFXManager.settingsEffectSetEnabled(LightRayPostFX, $pref::PostFX::EnableLightRays);
  537. PostFXManager.settingsEffectSetEnabled(vignettePostFX, $pref::PostFX::EnableVignette);
  538. }
  539. //
  540. //
  541. //
  542. function populateAudioSettingsList()
  543. {
  544. OptionsMenuSettingsList.clear();
  545. OptionsMenu.currentCategory = "Audio";
  546. if(isObject(OptionName))
  547. OptionName.setText("");
  548. if(isObject(OptionDescription))
  549. OptionDescription.setText("");
  550. %buffer = sfxGetAvailableDevices();
  551. %count = getRecordCount( %buffer );
  552. %audioDriverList = "";
  553. %audioProviderList = "";
  554. %audioDeviceList = "";
  555. $currentAudioProvider = $currentAudioProvider $= "" ? $pref::SFX::provider : $currentAudioProvider;
  556. for(%i = 0; %i < %count; %i++)
  557. {
  558. %record = getRecord(%buffer, %i);
  559. %provider = getField(%record, 0);
  560. %device = getField(%record, 1);
  561. //When the client is actually running, we don't care about null audo devices
  562. if(%provider $= "null")
  563. continue;
  564. if(%audioProviderList $= "")
  565. %audioProviderList = %provider;
  566. else
  567. %audioProviderList = %audioProviderList @ "\t" @ %provider;
  568. if(%provider $= $currentAudioProvider)
  569. {
  570. if(%audioDeviceList $= "")
  571. %audioDeviceList = %device;
  572. else
  573. %audioDeviceList = %audioDeviceList @ "\t" @ %device;
  574. }
  575. }
  576. OptionsMenuSettingsList.addOptionRow("Audio Provider", "$pref::SFX::AudioProvider", %audioProviderList, false, "audioProviderChanged", true, "");
  577. OptionsMenuSettingsList.addOptionRow("Audio Device", "$pref::SFX::device", %audioDeviceList, false, "", true);
  578. OptionsMenuSettingsList.addSliderRow("Master Volume", "$pref::SFX::masterVolume", 0.1, "0 1", "");
  579. OptionsMenuSettingsList.addSliderRow("GUI Volume", "$pref::SFX::channelVolume[" @ $GuiAudioType @ "]", 0.1, "0 1", "");
  580. OptionsMenuSettingsList.addSliderRow("Effects Volume", "$pref::SFX::channelVolume[" @ $SimAudioType @ "]", 0.1, "0 1", "");
  581. OptionsMenuSettingsList.addSliderRow("Music Volume", "$pref::SFX::channelVolume[" @ $MusicAudioType @ "]", 0.1, "0 1", "");
  582. }
  583. function audioProviderChanged()
  584. {
  585. //Get the option we have set for the provider
  586. %provider = OptionsMenuSettingsList.getCurrentOption(0);
  587. $currentAudioProvider = %provider;
  588. //And now refresh the list to get the correct devices
  589. populateAudioSettingsList();
  590. }
  591. function updateAudioSettings()
  592. {
  593. //$pref::SFX::masterVolume = OptionsMenuSettingsList.getValue(2);
  594. sfxSetMasterVolume( $pref::SFX::masterVolume );
  595. //$pref::SFX::channelVolume[ $GuiAudioType ] = OptionsMenuSettingsList.getValue(3);
  596. //$pref::SFX::channelVolume[ $SimAudioType ] = OptionsMenuSettingsList.getValue(4);
  597. //$pref::SFX::channelVolume[ $MusicAudioType ] = OptionsMenuSettingsList.getValue(5);
  598. sfxSetChannelVolume( $GuiAudioType, $pref::SFX::channelVolume[ $GuiAudioType ] );
  599. sfxSetChannelVolume( $SimAudioType, $pref::SFX::channelVolume[ $SimAudioType ] );
  600. sfxSetChannelVolume( $MusicAudioType, $pref::SFX::channelVolume[ $MusicAudioType ] );
  601. //$pref::SFX::provider = OptionsMenuSettingsList.getCurrentOption(0);
  602. //$pref::SFX::device = OptionsMenuSettingsList.getCurrentOption(1);
  603. if ( !sfxCreateDevice( $pref::SFX::provider,
  604. $pref::SFX::device,
  605. $pref::SFX::useHardware,
  606. -1 ) )
  607. error( "Unable to create SFX device: " @ $pref::SFX::provider
  608. SPC $pref::SFX::device
  609. SPC $pref::SFX::useHardware );
  610. if( !isObject( $AudioTestHandle ) )
  611. {
  612. sfxPlay(menuButtonPressed);
  613. }
  614. }
  615. //
  616. //
  617. //
  618. function populateKeyboardMouseSettingsList()
  619. {
  620. OptionsMenuSettingsList.clear();
  621. OptionsMenu.currentCategory = "Keyboard & Mouse";
  622. if(isObject(OptionName))
  623. OptionName.setText("");
  624. if(isObject(OptionDescription))
  625. OptionDescription.setText("");
  626. $remapListDevice = "keyboard";
  627. fillRemapList();
  628. //OptionsMenuSettingsList.refresh();
  629. }
  630. function populateGamepadSettingsList()
  631. {
  632. OptionsMenuSettingsList.clear();
  633. OptionsMenu.currentCategory = "Gamepad";
  634. if(isObject(OptionName))
  635. OptionName.setText("");
  636. if(isObject(OptionDescription))
  637. OptionDescription.setText("");
  638. $remapListDevice = "gamepad";
  639. fillRemapList();
  640. OptionsMenuSettingsList.updateStack();
  641. }
  642. //
  643. //
  644. //
  645. function getDisplayDeviceList()
  646. {
  647. %numDevices = Canvas.getMonitorCount();
  648. %devicesList = "";
  649. for(%i = 0; %i < %numDevices; %i++)
  650. {
  651. %device = (%i+1) @ " - " @ Canvas.getMonitorName(%i);
  652. if(%i==0)
  653. %devicesList = %device;
  654. else
  655. %devicesList = %devicesList @ "\t" @ %device;
  656. }
  657. return %devicesList;
  658. }
  659. function getDisplayDeviceId(%displayDeviceName)
  660. {
  661. %deviceList = getDisplayDeviceList();
  662. %deviceCount = getFieldCount(%deviceList);
  663. for(%d = 0; %d < %deviceCount; %d++)
  664. {
  665. %deviceName = getField(%deviceList, %d);
  666. if(%deviceName $= %displayDeviceName)
  667. return %d;
  668. }
  669. return -1;
  670. }
  671. //
  672. //
  673. //
  674. function OptionsMenuList::activateRow(%this)
  675. {
  676. //OptionsMenuSettingsList.setFirstResponder();
  677. OptionsMenuSettingsList.setAsActiveMenuList();
  678. }
  679. function OptionsMenuSettingsList::setRowEnabled(%this, %row, %status)
  680. {
  681. %option = %this.getObject(%row);
  682. if(isObject(%option))
  683. {
  684. %option.setEnabled(%status);
  685. }
  686. }
  687. function OptionsMenuSettingsList::addOptionRow(%this, %label, %targetPrefVar, %optionsList, %wrapOptions, %callback, %enabled, %description, %defaultValue)
  688. {
  689. if(%enabled $= "")
  690. %enabled = true;
  691. %optionsRowSize = 30;
  692. %optionColumnWidth = %this.extent.x * 0.5;//todo, calculate off longest option text?
  693. %option = new GuiGameSettingsCtrl() {
  694. class = "MenuOptionsButton";
  695. profile = "GuiMenuButtonProfile";
  696. horizSizing = "width";
  697. vertSizing = "bottom";
  698. position = "0 0";
  699. extent = %this.extent.x SPC %optionsRowSize;
  700. columnSplit = %optionColumnWidth;
  701. useMouseEvents = true;
  702. previousBitmapAsset = "UI:previousOption_n_image";
  703. nextBitmapAsset = "UI:nextOption_n_image";
  704. };
  705. %option.targetPrefVar = %targetPrefVar; //create a var-option association
  706. if(%defaultValue $= "")
  707. {
  708. %unappliedPrefIndex = OptionsMenu.unappliedChanges.getIndexFromKey(%targetPrefVar);
  709. if(%unappliedPrefIndex != -1)
  710. {
  711. %value = OptionsMenu.unappliedChanges.getValue(%unappliedPrefIndex);
  712. %defaultValue = strreplace(%value, "\"", "");
  713. }
  714. if(%defaultValue $= "")
  715. {
  716. %sanitizedVar = strReplace(%targetPrefVar, "[", "");
  717. %sanitizedVar = strReplace(%sanitizedVar, "]", "");
  718. %sanitizedVar = strReplace(%sanitizedVar, ",", "_");
  719. %defaultValue = getVariable(%sanitizedVar);
  720. }
  721. }
  722. /*if(%defaultValue $= "Off" || %defaultValue $= "No")
  723. %defaultValue = "0";
  724. if(%defaultValue $= "On" || %defaultValue $= "Yes")
  725. %defaultValue = "1";*/
  726. %option.setListSetting(%label, %optionsList, %wrapOptions, %callback, %enabled, %description, %defaultValue);
  727. %this.add(%option);
  728. }
  729. function OptionsMenuSettingsList::addOptionQualityLevelRow(%this, %label, %targetPrefVar, %qualityLevelList, %wrapOptions, %callback, %enabled, %description, %defaultValue)
  730. {
  731. if(%defaultValue $= "")
  732. {
  733. %unappliedPrefIndex = OptionsMenu.unappliedChanges.getIndexFromKey(%targetPrefVar);
  734. if(%unappliedPrefIndex != -1)
  735. {
  736. %value = OptionsMenu.unappliedChanges.getValue(%unappliedPrefIndex);
  737. %defaultValue = strreplace(%value, "\"", "");
  738. }
  739. if(%defaultValue $= "")
  740. {
  741. %sanitizedVar = strReplace(%targetPrefVar, "[", "");
  742. %sanitizedVar = strReplace(%sanitizedVar, "]", "");
  743. %sanitizedVar = strReplace(%sanitizedVar, ",", "_");
  744. %defaultValue = getVariable(%sanitizedVar);
  745. }
  746. if(%defaultValue $= "")
  747. %defaultValue = getCurrentQualityLevel(%qualityLevelList);
  748. }
  749. return %this.addOptionRow(%label, %targetPrefVar, getQualityLevels(%qualityLevelList),
  750. %wrapOptions, %callback, %enabled, %description, %defaultValue);
  751. }
  752. function OptionsMenuSettingsList::addOptionBoolRow(%this, %label, %targetPrefVar, %qualityLevelList, %wrapOptions, %callback, %enabled, %description, %defaultValue, %inverted)
  753. {
  754. if(%defaultValue $= "")
  755. %defaultValue = OptionsMenu.getOptionVariableValue(%targetPrefVar);
  756. if(%inverted $= "")
  757. %inverted = false;
  758. //Lame and hacky, but some variables are 'disabled' and some are 'enabled'
  759. if(isInt(%defaultValue) && %inverted)
  760. {
  761. if(%defaultValue == 0)
  762. %defaultValue = 1;
  763. else
  764. %defaultValue = 0;
  765. }
  766. if(%qualityLevelList $= $yesNoList && isInt(%defaultValue))
  767. {
  768. %defaultValue = convertBoolToYesNo(%defaultValue);
  769. }
  770. else if(%qualityLevelList $= $onOffList && isInt(%defaultValue))
  771. {
  772. %defaultValue = convertBoolToOnOff(%defaultValue);
  773. }
  774. return %this.addOptionRow(%label, %targetPrefVar, %qualityLevelList,
  775. %wrapOptions, %callback, %enabled, %description, %defaultValue);
  776. }
  777. function OptionsMenuSettingsList::addSliderRow(%this, %label, %targetPrefVar, %increment, %range, %callback, %enabled, %description, %defaultValue)
  778. {
  779. if(%enabled $= "")
  780. %enabled = true;
  781. %optionsRowSize = 30;
  782. %optionColumnWidth = %this.extent.x * 0.5;//todo, calculate off longest option text?
  783. %option = new GuiGameSettingsCtrl() {
  784. class = "MenuOptionsButton";
  785. profile = "GuiMenuButtonProfile";
  786. horizSizing = "width";
  787. vertSizing = "bottom";
  788. position = "0 0";
  789. extent = %this.extent.x SPC %optionsRowSize;
  790. columnSplit = %optionColumnWidth;
  791. useMouseEvents = true;
  792. };
  793. %option.targetPrefVar = %targetPrefVar; //create a var-option association
  794. if(%defaultValue $= "")
  795. %defaultValue = OptionsMenu.getOptionVariableValue(%targetPrefVar);
  796. %option.setSliderSetting(%label, %defaultValue, %increment, %range, %callback, %enabled, %description);
  797. %this.add(%option);
  798. }
  799. function OptionsMenuSettingsList::addKeybindRow(%this, %label, %bitmapName, %callback, %enabled, %description)
  800. {
  801. if(%enabled $= "")
  802. %enabled = true;
  803. %optionsRowSize = 40;
  804. %optionColumnWidth = %this.extent.x * 0.5;//todo, calculate off longest option text?
  805. %option = new GuiGameSettingsCtrl() {
  806. class = "MenuOptionsButton";
  807. profile = "GuiMenuButtonProfile";
  808. horizSizing = "width";
  809. vertSizing = "bottom";
  810. position = "0 0";
  811. extent = %this.extent.x SPC %optionsRowSize;
  812. columnSplit = %optionColumnWidth;
  813. useMouseEvents = true;
  814. };
  815. %option.setKeybindSetting(%label, %bitmapName, %callback, %enabled, %description);
  816. %this.add(%option);
  817. }
  818. //
  819. function OptionsMenuCategoryList::onNavigate(%this, %index)
  820. {
  821. OptionsMenu.currentCategory = %index;
  822. %this.getObject(%index).performClick();
  823. }
  824. function convertOptionToBool(%val)
  825. {
  826. if(%val $= "yes" || %val $= "on")
  827. return 1;
  828. else
  829. return 0;
  830. }
  831. function convertBoolToYesNo(%val)
  832. {
  833. if(%val == 1)
  834. return "Yes";
  835. else if(%val == 0)
  836. return "No";
  837. return %val;
  838. }
  839. function convertBoolToOnOff(%val)
  840. {
  841. if(%val == 1)
  842. return "On";
  843. else if(%val == 0)
  844. return "Off";
  845. return %val;
  846. }
  847. function getDisplayDeviceName()
  848. {
  849. %numDevices = Canvas.getMonitorCount();
  850. %devicesList = "";
  851. for(%i = 0; %i < %numDevices; %i++)
  852. {
  853. %device = (%i+1) @ " - " @ Canvas.getMonitorName(%i);
  854. if(%i==0)
  855. %devicesList = %device;
  856. else
  857. %devicesList = %devicesList @ "\t" @ %device;
  858. }
  859. return getField(%devicesList, $pref::Video::deviceId);
  860. }
  861. //
  862. //
  863. //
  864. function MenuOptionsButton::onMouseEnter(%this)
  865. {
  866. if(isObject(OptionName))
  867. OptionName.setText(%this.getLabel());
  868. if(isObject(OptionDescription))
  869. OptionDescription.setText(%this.getToolTip());
  870. }
  871. function MenuOptionsButton::onMouseLeave(%this)
  872. {
  873. if(isObject(OptionName))
  874. OptionName.setText("");
  875. if(isObject(OptionDescription))
  876. OptionDescription.setText("");
  877. }
  878. function MenuOptionsButton::onHighlighted(%this, %state)
  879. {
  880. MenuListButton::onHighlighted(%this, %state);
  881. }
  882. function MenuOptionsButton::onChange(%this)
  883. {
  884. %optionMode = %this.getMode();
  885. %optionName = %this.getLabel();
  886. %tooltipText = %this.getTooltip();
  887. %targetVar = %this.targetPrefVar;
  888. OptionName.setText(%optionName);
  889. OptionDescription.setText(%tooltipText);
  890. if(%optionMode == 0)
  891. {
  892. %currentValue = %this.getCurrentOption();
  893. if(%currentValue !$= "")
  894. {
  895. if(%currentValue $= "yes" || %currentValue $= "on")
  896. %saveReadyValue = 1;
  897. else if(%currentValue $= "no" || %currentValue $= "off")
  898. %saveReadyValue = 0;
  899. else
  900. %saveReadyValue = %currentValue;
  901. %prefIndex = OptionsMenu.unappliedChanges.getIndexFromKey(%targetVar);
  902. if(%prefIndex == -1)
  903. {
  904. echo("Setting UnappliedChanges via add: key:" @ %targetVar @", value: " @ %saveReadyValue);
  905. OptionsMenu.unappliedChanges.add(%targetVar, "\"" @ %saveReadyValue @ "\"" );
  906. }
  907. else
  908. {
  909. echo("Setting UnappliedChanges via modify: key:" @ %targetVar @", value: " @ %saveReadyValue);
  910. OptionsMenu.unappliedChanges.setValue("\"" @ %saveReadyValue @ "\"", %prefIndex);
  911. }
  912. }
  913. }
  914. else if(%optionMode == 1)
  915. {
  916. %currentValue = %this.getValue();
  917. %prefIndex = OptionsMenu.unappliedChanges.getIndexFromKey(%targetVar);
  918. if(%prefIndex == -1)
  919. {
  920. echo("Setting UnappliedChanges via add: key:" @ %targetVar @", value: " @ %currentValue);
  921. OptionsMenu.unappliedChanges.add(%targetVar, "\"" @ %currentValue @ "\"" );
  922. }
  923. else
  924. {
  925. OptionsMenu.unappliedChanges.setValue("\"" @ %currentValue @ "\"", %prefIndex);
  926. }
  927. }
  928. //Update the UI in case there's responsive logic
  929. OptionsMenu.schedule(32, "refresh");
  930. }
  931. function OptionsMenu::onKeybindChanged(%this, %actionMap, %keybind)
  932. {
  933. %prefIndex = OptionsMenu.unappliedChanges.getIndexFromKey(%actionMap);
  934. if(%prefIndex == -1)
  935. OptionsMenu.unappliedChanges.add(%actionMap, %keybind);
  936. else
  937. OptionsMenu.unappliedChanges.setValue(%keybind, %prefIndex);
  938. }
  939. //
  940. // Indicates what category the options item should be added into
  941. //
  942. function addOptionsMenuCategory(%categoryName, %selectCallback)
  943. {
  944. //Don't add duplicates!
  945. %index = OptionsMenu.optionsCategories.getIndexFromKey(%categoryName);
  946. if(%index == -1)
  947. OptionsMenu.optionsCategories.add(%categoryName, %selectCallback);
  948. }
  949. function removeOptionsMenuCategory(%categoryName)
  950. {
  951. %index = OptionsMenu.optionsCategories.getIndexFromKey(%categoryName);
  952. if(%index != -1)
  953. OptionsMenu.optionsCategories.erase(%index);
  954. }
  955. function getOptionsCategoryIndexByName(%categoryName)
  956. {
  957. for(%i=0; %i < OptionsMenu.optionsCategories.count(); %i++)
  958. {
  959. if(OptionsMenu.optionsCategories.getKey(%i) $= %categoryName)
  960. return %i;
  961. }
  962. return -1;
  963. }
  964. function addListOption(%label, %description, %targetPrefVar, %optionsList, %wrapOptions, %callback, %enabled)
  965. {
  966. if(%wrapOptions $= "")
  967. %wrapOptions = false;
  968. if(%enabled $= "")
  969. %enabled = true;
  970. OptionsMenuSettingsList.addOptionRow(%label, %targetPrefVar, %optionsList, %wrapOptions, %callback, %enabled, %description, %targetPrefVar);
  971. }
  972. function addSliderOption(%label, %description, %targetPrefVar, %defaultValue, %increment, %range, %callback, %enabled)
  973. {
  974. if(%enabled $= "")
  975. %enabled = true;
  976. OptionsMenuSettingsList.addSliderRow(%label, %targetPrefVar, %defaultValue, %increment, %range, %callback, %enabled, %description);
  977. }
  978. function addKeybindOption(%label, %description, %bitmapName, %callback, %enabled)
  979. {
  980. if(%enabled $= "")
  981. %enabled = true;
  982. OptionsMenuSettingsList.addSliderRow(%label, %bitmapName, %callback, %enabled, %description);
  983. }