diff --git a/binaries/data/mods/public/gui/options/options.js b/binaries/data/mods/public/gui/options/options.js index af6ce688ca..7fed1fcf9a 100644 --- a/binaries/data/mods/public/gui/options/options.js +++ b/binaries/data/mods/public/gui/options/options.js @@ -1,4 +1,5 @@ var g_hasCallback = false; +var g_hasChanges = false; /** * This array holds the data to populate the general section with. * Data is in the form [Title, Tooltip, {ActionType:Action}, InputType]. @@ -54,24 +55,25 @@ function init(data) { if (data && data.callback) g_hasCallback = true; + let reload = data && data.reload; // WARNING: We assume a strict formatting of the XML and do minimal checking. - for each (var prefix in Object.keys(options)) + for (let prefix of Object.keys(options)) { - var lastSize; - for (var i = 0; i < options[prefix].length; i++) + let lastSize; + for (let i = 0; i < options[prefix].length; i++) { - var body = Engine.GetGUIObjectByName(prefix + "[" + i + "]"); - var label = Engine.GetGUIObjectByName(prefix + "Label[" + i + "]"); + let body = Engine.GetGUIObjectByName(prefix + "[" + i + "]"); + let label = Engine.GetGUIObjectByName(prefix + "Label[" + i + "]"); // Setup control. - setupControl(options[prefix][i], i, prefix); + setupControl(options[prefix][i], i, prefix, reload); // Setup label. label.caption = options[prefix][i][0]; label.tooltip = options[prefix][i][1]; // Move each element to the correct place. if (i > 0) { - var newSize = new GUISize(); + let newSize = new GUISize(); newSize.left = lastSize.left; newSize.rright = lastSize.rright; newSize.top = lastSize.bottom; @@ -80,9 +82,7 @@ function init(data) lastSize = newSize; } else - { lastSize = body.size; - } // Show element. body.hidden = false; } @@ -95,100 +95,117 @@ function init(data) * @param option Structure containing the data to setup an option. * @param prefix Prefix to use when accessing control, for example "generalSetting" when the tickbox name is generalSettingTickbox[i]. */ -function setupControl(option, i, prefix) +function setupControl(option, i, prefix, reload) { + var control; + var onPress = function(){ g_hasChanges = true; }; + switch (option[3]) { - case "boolean": - // More space for the label - let text = Engine.GetGUIObjectByName(prefix + "Label[" + i + "]"); - let size = text.size; - size.rright = 87; - text.size = size; - var control = Engine.GetGUIObjectByName(prefix + "Tickbox[" + i + "]"); - var checked; - var onPress = function(){}; - // Different option action load and save differently, so this switch is needed. - for each (var action in Object.keys(option[2])) + case "boolean": + // More space for the label + let text = Engine.GetGUIObjectByName(prefix + "Label[" + i + "]"); + let size = text.size; + size.rright = 87; + text.size = size; + control = Engine.GetGUIObjectByName(prefix + "Tickbox[" + i + "]"); + var checked; + // Different option action load and save differently, so this switch is needed. + for (let action of Object.keys(option[2])) + { + switch (action) { - switch (action) + case "config": + // Load initial value if not yet loaded. + if (!checked || typeof checked != "boolean") + checked = Engine.ConfigDB_GetValue("user", option[2][action]) === "true"; + // Hacky macro to create the callback. + var callback = function(key) { - case "config": - // Load initial value if not yet loaded. - if (!checked || typeof checked != "boolean") - checked = Engine.ConfigDB_GetValue("user", option[2][action]) === "true" ? true : false; - // Hacky macro to create the callback. - var callback = function(key) - { - return function() - Engine.ConfigDB_CreateValue("user", key, String(this.checked)); - }(option[2][action]); - // Merge the new callback with any existing callbacks. - onPress = mergeFunctions(callback, onPress); - break; - case "renderer": - // Load initial value if not yet loaded. - if (!checked || typeof checked != "boolean") - checked = eval("Engine.Renderer_Get" + option[2][action] + "Enabled()"); - // Hacky macro to create the callback. - var callback = function(key) - { - return function() - eval("Engine.Renderer_Set" + key + "Enabled(" + this.checked + ")"); - }(option[2][action]); - // Merge the new callback with any existing callbacks. - onPress = mergeFunctions(callback, onPress); - break; - case "function": - // This allows for doing low-level actions, like hiding/showing UI elements. - onPress = mergeFunctions(eval("function(){" + option[2][action] + "}"), onPress); - break; - default: - warn("Unknown option source type '" + action + "'"); + return function() + Engine.ConfigDB_CreateValue("user", key, String(this.checked)); + }(option[2][action]); + // Merge the new callback with any existing callbacks. + onPress = mergeFunctions(callback, onPress); + break; + case "renderer": + // If reloading, config values have priority, otherwise load initial value if not yet loaded + if (reload && option[2].config) + { + checked = Engine.ConfigDB_GetValue("user", option[2].config) === "true"; + let rendererChecked = eval("Engine.Renderer_Get" + option[2].renderer + "Enabled()"); + if (rendererChecked != checked) + eval("Engine.Renderer_Set" + option[2].renderer + "Enabled(" + checked + ")"); } + else if (!checked || typeof checked != "boolean") + checked = eval("Engine.Renderer_Get" + option[2][action] + "Enabled()"); + // Hacky macro to create the callback (updating also the config value if any). + var callback = function(key, keyConfig) + { + return function() + { + eval("Engine.Renderer_Set" + key + "Enabled(" + this.checked + ")"); + if (keyConfig) + Engine.ConfigDB_CreateValue("user", keyConfig, String(this.checked)); + } + }(option[2][action], option[2].config); + // Merge the new callback with any existing callbacks. + onPress = mergeFunctions(callback, onPress); + break; + case "function": + // This allows for doing low-level actions, like hiding/showing UI elements. + onPress = mergeFunctions(eval("function(){" + option[2][action] + "}"), onPress); + break; + default: + warn("Unknown option source type '" + action + "'"); } - // Load final data to the control element. - control.checked = checked; - control.onPress = onPress; - break; - case "number": - // TODO: Slider - case "string": - var control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]"); - var caption; - var onPress = function(){}; - for each (var action in Object.keys(option[2])) + } + // Load final data to the control element. + control.checked = checked; + control.onPress = onPress; + break; + case "number": + // TODO: Slider + case "string": + control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]"); + var caption; + for (let action of Object.keys(option[2])) + { + switch (action) { - switch (action) + case "config": + onPress = function(){}; + caption = Engine.ConfigDB_GetValue("user", option[2][action]); + // Hacky macro to create the callback. + var callback = function(key) { - case "config": - // Load initial value if not yet loaded. - if (!checked || typeof checked != boolean) - caption = Engine.ConfigDB_GetValue("user", option[2][action]); - // Hacky macro to create the callback. - var callback = function(key) - { - return function() - Engine.ConfigDB_CreateValue("user", key, String(this.caption)); - }(option[2][action]); - // Merge the new callback with any existing callbacks. - onPress = mergeFunctions(callback, onPress); - break; - case "function": - // This allows for doing low-level actions, like hiding/showing UI elements. - onPress = mergeFunctions(function(){eval(option[2][action])}, onPress); - break; - default: - warn("Unknown option source type '" + action + "'"); - } + return function() + { + if (Engine.ConfigDB_GetValue("user", key) == this.caption) + return; + Engine.ConfigDB_CreateValue("user", key, String(this.caption)); + g_hasChanges = true; + } + }(option[2][action]); + // Merge the new callback with any existing callbacks. + onPress = mergeFunctions(callback, onPress); + break; + case "function": + // This allows for doing low-level actions, like hiding/showing UI elements. + onPress = mergeFunctions(function(){eval(option[2][action])}, onPress); + break; + default: + warn("Unknown option source type '" + action + "'"); } - control.caption = caption; - control.onPress = onPress; - break; - default: - warn("Unknown option type '" + options[3] + "', assuming string. Valid types are 'number', 'string', or 'bool'."); - var control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]"); - break; + } + control.caption = caption; + control.onPress = onPress; + control.onMouseLeave = onPress; + break; + default: + warn("Unknown option type '" + options[3] + "', assuming string. Valid types are 'number', 'string', or 'bool'."); + control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]"); + break; } control.hidden = false; control.tooltip = option[1]; @@ -209,14 +226,37 @@ function mergeFunctions(function1, function2) }; } +function reloadDefaults() +{ + Engine.ConfigDB_Reload("user"); + init({ "reload": true }); + g_hasChanges = false; +} + +function saveDefaults() +{ + g_hasChanges = false; + Engine.ConfigDB_WriteFile("user", "config/user.cfg"); +} + /** * Close GUI page and call callbacks if they exist. **/ function closePage() { - // Revert all changes if they were not saved on the disk - Engine.ConfigDB_Reload("user"); + if (g_hasChanges) + { + let btCaptions = [translate("No"), translate("Yes")]; + let btCode = [null, function(){ closePageWithoutConfirmation(); }]; + messageBox(500, 200, translate("You have unsaved changes, are you sure you want to quit ?"), + translate("Warning"), 0, btCaptions, btCode); + } + else + closePageWithoutConfirmation(); +} +function closePageWithoutConfirmation() +{ if (g_hasCallback) Engine.PopGuiPageCB(); else diff --git a/binaries/data/mods/public/gui/options/options.xml b/binaries/data/mods/public/gui/options/options.xml index fd7e21ea42..7c41ab7340 100644 --- a/binaries/data/mods/public/gui/options/options.xml +++ b/binaries/data/mods/public/gui/options/options.xml @@ -17,7 +17,7 @@ Game Options - + General @@ -53,7 +53,7 @@ - + Lobby Settings @@ -65,13 +65,20 @@ - - Cancel - closePage(); + + Reload + Reload default values from file + reloadDefaults(); - + Save - Engine.ConfigDB_WriteFile("user", "config/user.cfg");closePage(); + Save changes to file + saveDefaults(); + + + Quit + Unsaved changes affect this session only + closePage();