Ticket #3511: cleanOptions.2.diff

File cleanOptions.2.diff, 9.0 KB (added by mimo, 8 years ago)

same as before, but with detection of changes to enable reload and save button only when needed

  • binaries/data/mods/public/gui/options/options.js

     
    8787            body.hidden = false;
    8888        }
    8989    }
     90
     91    if (!reload)
     92        updateChanges();
    9093}
    9194
    9295/**
     
    98101function setupControl(option, i, prefix, reload)
    99102{
    100103    var control;
    101     var onPress = function(){ g_hasChanges = true; };
    102104
    103105    switch (option[3])
    104106    {
     
    110112        text.size = size;
    111113        control = Engine.GetGUIObjectByName(prefix + "Tickbox[" + i + "]");
    112114        var checked;
    113         // Different option action load and save differently, so this switch is needed.
     115        var keyRenderer;
     116        var keyConfig;
     117        var functionBody;
     118
    114119        for (let action of Object.keys(option[2]))
    115120        {
    116121            switch (action)
    117122            {
    118123            case "config":
    119                 // Load initial value if not yet loaded.
    120                 if (!checked || typeof checked != "boolean")
    121                     checked = Engine.ConfigDB_GetValue("user", option[2][action]) === "true";
    122                 // Hacky macro to create the callback.
    123                 var callback = function(key)
    124                 {
    125                     return function()
    126                         Engine.ConfigDB_CreateValue("user", key, String(this.checked));
    127                 }(option[2][action]);
    128                 // Merge the new callback with any existing callbacks.
    129                 onPress = mergeFunctions(callback, onPress);
     124                keyConfig = option[2].config;
     125                if (checked === undefined || reload)
     126                    checked = Engine.ConfigDB_GetValue("user", keyConfig) === "true";
     127                else if ((Engine.ConfigDB_GetValue("user", keyConfig) === "true") !== checked)
     128                    Engine.ConfigDB_CreateValue("user", keyConfig, String(checked));
    130129                break;
    131130            case "renderer":
    132                 // If reloading, config values have priority, otherwise load initial value if not yet loaded
    133                 if (reload && option[2].config)
    134                 {
    135                     checked = Engine.ConfigDB_GetValue("user", option[2].config) === "true";
    136                     let rendererChecked = eval("Engine.Renderer_Get" + option[2].renderer + "Enabled()");
    137                     if (rendererChecked != checked)
    138                         eval("Engine.Renderer_Set" + option[2].renderer + "Enabled(" + checked + ")");
    139                 }
    140                 else if (!checked || typeof checked != "boolean")
    141                     checked = eval("Engine.Renderer_Get" + option[2][action] + "Enabled()");
    142                 // Hacky macro to create the callback (updating also the config value if any).
    143                 var callback = function(key, keyConfig)
    144                 {
    145                     return function()
    146                     {
    147                         eval("Engine.Renderer_Set" + key + "Enabled(" + this.checked + ")");
    148                         if (keyConfig)
    149                             Engine.ConfigDB_CreateValue("user", keyConfig, String(this.checked));
    150                     };
    151                 }(option[2][action], option[2].config);
    152                 // Merge the new callback with any existing callbacks.
    153                 onPress = mergeFunctions(callback, onPress);
     131                keyRenderer = option[2].renderer;
     132                if (checked === undefined)
     133                    checked = eval("Engine.Renderer_Get" + keyRenderer + "Enabled()");
     134                else if (eval("Engine.Renderer_Get" + keyRenderer + "Enabled()") !== checked)
     135                    eval("Engine.Renderer_Set" + keyRenderer + "Enabled(" + checked + ")");
    154136                break;
    155137            case "function":
    156138                // This allows for doing low-level actions, like hiding/showing UI elements.
    157                 onPress = mergeFunctions(eval("function(){" + option[2][action] + "}"), onPress);
     139                functionBody = option[2].function;
    158140                break;
    159141            default:
    160142                warn("Unknown option source type '" + action + "'");
    161143            }
    162144        }
     145
     146        var onPress = function(keyRenderer, keyConfig, functionBody)
     147        {
     148            return function()
     149            {
     150                if (keyRenderer)
     151                    eval("Engine.Renderer_Set" + keyRenderer + "Enabled(" + this.checked + ")");
     152                if (keyConfig)
     153                    Engine.ConfigDB_CreateValue("user", keyConfig, String(this.checked));
     154                if (functionBody)
     155                    eval(functionBody);
     156                updateChanges(true);
     157            };
     158        }(keyRenderer, keyConfig, functionBody);
     159
    163160        // Load final data to the control element.
    164161        control.checked = checked;
    165162        control.onPress = onPress;
     
    169166    case "string":
    170167        control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]");
    171168        var caption;
     169        var key;
     170        var functionBody;
     171
    172172        for (let action of Object.keys(option[2]))
    173173        {
    174174            switch (action)
    175175            {
    176176            case "config":
    177                 onPress = function(){};
    178                 caption = Engine.ConfigDB_GetValue("user", option[2][action]);
    179                 // Hacky macro to create the callback.
    180                 var callback = function(key)
    181                 {
    182                     return function()
    183                     {
    184                         if (Engine.ConfigDB_GetValue("user", key) == this.caption)
    185                             return;
    186                         Engine.ConfigDB_CreateValue("user", key, String(this.caption));
    187                         g_hasChanges = true;
    188                     };
    189                 }(option[2][action]);
    190                 // Merge the new callback with any existing callbacks.
    191                 onPress = mergeFunctions(callback, onPress);
     177                key = option[2].config;
     178                caption = Engine.ConfigDB_GetValue("user", key);
    192179                break;
    193180            case "function":
    194181                // This allows for doing low-level actions, like hiding/showing UI elements.
    195                 onPress = mergeFunctions(function(){eval(option[2][action]);}, onPress);
     182                functionBody = option[2].function;
    196183                break;
    197184            default:
    198185                warn("Unknown option source type '" + action + "'");
    199186            }
    200187        }
     188
     189        // as we use MouseLeave events, we must ensure that something has been modified
     190        var onMouseLeave = function(key, functionBody)
     191        {
     192            return function()
     193            {
     194                if (Engine.ConfigDB_GetValue("user", key) === this.caption)
     195                    return;
     196                Engine.ConfigDB_CreateValue("user", key, String(this.caption));
     197                if (functionBody)
     198                    eval(functionBody);
     199                updateChanges(true);
     200            };
     201        }(key, functionBody);
     202
    201203        control.caption = caption;
    202         control.onPress = onPress;
    203         control.onMouseLeave = onPress;
     204        control.onMouseLeave = onMouseLeave;
    204205        break;
    205206    default:
    206         warn("Unknown option type '" + options[3] + "', assuming string. Valid types are 'number', 'string', or 'bool'.");
     207        warn("Unknown option type '" + option[3] + "', assuming string. Valid types are 'number', 'string', or 'bool'.");
    207208        control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]");
    208209        break;
    209210    }
     
    212213    return control;
    213214}
    214215
    215 /**
    216  * Merge two functions which don't expect arguments.
    217  *
    218  * @return Merged function.
    219  */
    220 function mergeFunctions(function1, function2)
     216function updateChanges(val)
    221217{
    222     return function()
    223     {
    224         function1.apply(this);
    225         function2.apply(this);
    226     };
     218    if (typeof val == "boolean")
     219        Engine.ConfigDB_CreateValue("user", "nosave.haschanges", String(val));
     220    else
     221        val = Engine.ConfigDB_GetValue("user", "nosave.haschanges") === "true";
     222
     223    Engine.GetGUIObjectByName("loadOptions").enabled = val;
     224    Engine.GetGUIObjectByName("saveOptions").enabled = val;
    227225}
    228226
    229227function reloadDefaults()
    230228{
    231229    Engine.ConfigDB_Reload("user");
     230    updateChanges(false);
    232231    init({ "reload": true });
    233     g_hasChanges = false;
    234232}
    235233
    236234function saveDefaults()
    237235{
    238     g_hasChanges = false;
    239236    Engine.ConfigDB_WriteFile("user", "config/user.cfg");
     237    updateChanges(false);
    240238}
    241239
    242240/**
     
    244242 **/
    245243function closePage()
    246244{
    247     if (g_hasChanges)
     245    if (Engine.ConfigDB_GetValue("user", "nosave.haschanges") === "true")
    248246    {
    249247        let btCaptions = [translate("No"), translate("Yes")];
    250248        let btCode = [null, function(){ closePageWithoutConfirmation(); }];
  • binaries/data/mods/public/gui/options/options.xml

     
    6565                </object>
    6666            </repeat>
    6767        </object>
    68         <object type="button" style="ModernButtonRed" size="50%-170 100%-44 50%-70 100%-16" hotkey="cancel">
     68        <object name="loadOptions" type="button" style="ModernButtonRed" size="50%-170 100%-44 50%-70 100%-16" hotkey="cancel">
    6969            <translatableAttribute id="caption">Reload</translatableAttribute>
    70             <translatableAttribute id="tooltip">Reload default values from file</translatableAttribute>
     70            <translatableAttribute id="tooltip">Reload previous saved settings</translatableAttribute>
    7171            <action on="Press">reloadDefaults();</action>
    7272        </object>
    73         <object type="button" style="ModernButtonRed" size="50%-62 100%-44 50%+38 100%-16">
     73        <object name="saveOptions" type="button" style="ModernButtonRed" size="50%-62 100%-44 50%+38 100%-16">
    7474            <translatableAttribute id="caption">Save</translatableAttribute>
    75             <translatableAttribute id="tooltip">Save changes to file</translatableAttribute>
     75            <translatableAttribute id="tooltip">Save changes</translatableAttribute>
    7676            <action on="Press">saveDefaults();</action>
    7777        </object>
    7878        <object type="button" style="ModernButtonRed" size="50%+70 100%-44 50%+170 100%-16">
  • source/ps/ConfigDB.cpp

     
    378378    char* pos = (char*)buf.get();
    379379    for (const std::pair<CStr, CConfigValueSet>& p : m_Map[ns])
    380380    {
     381        if (boost::algorithm::starts_with(p.first, "nosave."))
     382            continue;
    381383        size_t i;
    382384        pos += sprintf(pos, "%s = ", p.first.c_str());
    383385        for (i = 0; i < p.second.size() - 1; ++i)