Ticket #2596: ticket2596.2.patch

File ticket2596.2.patch, 23.0 KB (added by mimo, 8 years ago)

updated version with update of messages.json and checks on function use

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

     
    11var g_hasCallback = false;
    22var g_controls;
    3 /**
    4  * This array holds the data to populate the general section with.
    5  * Data is in the form [Title, Tooltip, {ActionType:Action}, InputType].
    6  */
    7 var options = {
    8     "generalSetting":
    9     [
    10         [translate("Windowed Mode"), translate("Start 0 A.D. in a window"), {"config":"windowed"}, "boolean"],
    11         [translate("Background Pause"), translate("Pause single player games when window loses focus"), {"config":"pauseonfocusloss"}, "boolean"],
    12         [translate("Disable Welcome Screen"), translate("If you disable this screen completely, you may miss important announcements.\nYou can still launch it using the main menu."), {"config":"splashscreendisable"}, "boolean"],
    13         [translate("Detailed Tooltips"), translate("Show detailed tooltips for trainable units in unit-producing buildings."), {"config":"showdetailedtooltips"}, "boolean"],
    14         [translate("FPS Overlay"), translate("Show frames per second in top right corner."), {"config":"overlay.fps"}, "boolean"],
    15         [translate("Realtime Overlay"), translate("Show current system time in top right corner."), {"config":"overlay.realtime"}, "boolean"],
    16         [translate("Gametime Overlay"), translate("Show current simulation time in top right corner."), {"config":"gui.session.timeelapsedcounter"}, "boolean"],
    17         [translate("Ceasefire Time Overlay"), translate("Always show the remaining ceasefire time."), {"config":"gui.session.ceasefirecounter"}, "boolean"],
    18         [translate("Persist Match Settings"), translate("Save and restore match settings for quick reuse when hosting another game"), {"config":"persistmatchsettings"}, "boolean"],
    19     ],
    20     "graphicsSetting":
    21     [
    22         [translate("Prefer GLSL"), translate("Use OpenGL 2.0 shaders (recommended)"), {"renderer":"PreferGLSL", "config":"preferglsl"}, "boolean"],
    23         [translate("Post Processing"), translate("Use screen-space postprocessing filters (HDR, Bloom, DOF, etc)"), {"renderer":"Postproc", "config":"postproc"}, "boolean"],
    24         [translate("Shadows"), translate("Enable shadows"), {"renderer":"Shadows", "config":"shadows"}, "boolean"],
    25         [translate("Particles"), translate("Enable particles"), {"renderer":"Particles", "config":"particles"}, "boolean"],
    26         [translate("Show Sky"), translate("Render Sky"), {"renderer":"ShowSky", "config":"showsky"}, "boolean"],
    27         [translate("Smooth LOS"), translate("Lift darkness and fog-of-war smoothly"), {"renderer":"SmoothLOS", "config":"smoothlos"}, "boolean"],
    28         [translate("Unit Silhouettes"), translate("Show outlines of units behind buildings"), {"renderer":"Silhouettes", "config":"silhouettes"}, "boolean"],
    29         [translate("Shadow Filtering"), translate("Smooth shadows"), {"renderer":"ShadowPCF", "config":"shadowpcf"}, "boolean"],
    30         [translate("Fast & Ugly Water"), translate("Use the lowest settings possible to render water. This makes other settings irrelevant."), {"renderer":"WaterUgly", "config":"waterugly"}, "boolean"],
    31         [translate("HQ Water Effects"), translate("Use higher-quality effects for water, rendering coastal waves, shore foam, and ships trails."), {"renderer":"WaterFancyEffects", "config":"waterfancyeffects"}, "boolean"],
    32         [translate("Real Water Depth"), translate("Use actual water depth in rendering calculations"), {"renderer":"WaterRealDepth", "config":"waterrealdepth"}, "boolean"],
    33         [translate("Water Reflections"), translate("Allow water to reflect a mirror image"), {"renderer":"WaterReflection", "config":"waterreflection"}, "boolean"],
    34         [translate("Water Refraction"), translate("Use a real water refraction map and not transparency"), {"renderer":"WaterRefraction", "config":"waterrefraction"}, "boolean"],
    35         [translate("Shadows on Water"), translate("Cast shadows on water"), {"renderer":"WaterShadows", "config":"watershadows"}, "boolean"],
    36         [translate("VSync"), translate("Run vertical sync to fix screen tearing. REQUIRES GAME RESTART"), {"config":"vsync"}, "boolean"],
    37         [translate("Limit FPS in Menus"), translate("Limit FPS to 50 in all menus, to save power."), {"config":"gui.menu.limitfps"}, "boolean"],
    38         [translate("Graphics quality"), translate("Graphics quality. REQUIRES GAME RESTART"), {"config":"materialmgr.quality", "min": "0", "max": "10"}, "number"],
    39     ],
    40     "soundSetting":
    41     [
    42         [translate("Master Gain"), translate("Master audio gain"), {"config":"sound.mastergain", "function":"Engine.SetMasterGain(Number(this.caption));", "min": "0"}, "number"],
    43         [translate("Music Gain"), translate("In game music gain"), {"config":"sound.musicgain", "function":"Engine.SetMusicGain(Number(this.caption));", "min": "0"}, "number"],
    44         [translate("Ambient Gain"), translate("In game ambient sound gain"), {"config":"sound.ambientgain", "function":"Engine.SetAmbientGain(Number(this.caption));", "min": "0"}, "number"],
    45         [translate("Action Gain"), translate("In game unit action sound gain"), {"config":"sound.actiongain", "function":"Engine.SetActionGain(Number(this.caption));", "min": "0"}, "number"],
    46         [translate("UI Gain"), translate("UI sound gain"), {"config":"sound.uigain", "function":"Engine.SetUIGain(Number(this.caption));", "min": "0"}, "number"],
    47     ],
    48     "lobbySetting":
    49     [
    50         [translate("Chat Backlog"), translate("Number of backlogged messages to load when joining the lobby"), {"config":"lobby.history", "min": "0"}, "number"],
    51         [translate("Chat Timestamp"), translate("Show time that messages are posted in the lobby chat"), {"config":"lobby.chattimestamp"}, "boolean"],
    52     ],
    53 };
    543
    554function init(data)
    565{
     
    598    let revert = data && data.revert;
    609    g_controls = [];
    6110
    62     // WARNING: We assume a strict formatting of the XML and do minimal checking.
    63     for (let prefix of Object.keys(options))
     11    var options = Engine.ReadJSONFile("gui/options/options.json");
     12    for (let category of Object.keys(options))
    6413    {
    6514        let lastSize;
    66         for (let i = 0; i < options[prefix].length; i++)
     15        for (let i = 0; i < options[category].length; ++i)
    6716        {
    68             let body = Engine.GetGUIObjectByName(prefix + "[" + i + "]");
    69             let label = Engine.GetGUIObjectByName(prefix + "Label[" + i + "]");
     17            let body = Engine.GetGUIObjectByName(category + "[" + i + "]");
     18            let label = Engine.GetGUIObjectByName(category + "Label[" + i + "]");
    7019            // Setup control.
    71             setupControl(options[prefix][i], i, prefix, revert);
     20            let option = options[category][i];
     21            setupControl(option, i, category, revert);
    7222            // Setup label.
    73             label.caption = options[prefix][i][0];
    74             label.tooltip = options[prefix][i][1];
     23            label.caption = option.label ? translate(option.label) : translate("unknown");
     24            label.tooltip = option.tooltip ? translate(option.tooltip) : "";
    7525            // Move each element to the correct place.
    7626            if (i > 0)
    7727            {
     
    10050 * @param option Structure containing the data to setup an option.
    10151 * @param prefix Prefix to use when accessing control, for example "generalSetting" when the tickbox name is generalSettingTickbox[i].
    10252 */
    103 function setupControl(option, i, prefix, revert)
     53function setupControl(option, i, category, revert)
    10454{
    10555    var control;
    106     var onPress;
     56    var onUpdate;
    10757
    108     switch (option[3])
     58    switch (option.type)
    10959    {
    11060    case "boolean":
    11161        // More space for the label
    112         let text = Engine.GetGUIObjectByName(prefix + "Label[" + i + "]");
     62        let text = Engine.GetGUIObjectByName(category + "Label[" + i + "]");
    11363        let size = text.size;
    11464        size.rright = 87;
    11565        text.size = size;
    116         control = Engine.GetGUIObjectByName(prefix + "Tickbox[" + i + "]");
     66        control = Engine.GetGUIObjectByName(category + "Tickbox[" + i + "]");
    11767        var checked;
    11868        var keyRenderer;
    11969        var keyConfig;
    12070        var functionBody;
    12171
    122         for (let action of Object.keys(option[2]))
     72        for (let param of Object.keys(option.parameters))
    12373        {
    124             switch (action)
     74            switch (param)
    12575            {
    12676            case "config":
    127                 keyConfig = option[2].config;
     77                keyConfig = option.parameters.config;
    12878                if (checked === undefined || revert)
    12979                    checked = Engine.ConfigDB_GetValue("user", keyConfig) === "true";
    13080                else if ((Engine.ConfigDB_GetValue("user", keyConfig) === "true") !== checked)
     
    13181                    Engine.ConfigDB_CreateValue("user", keyConfig, String(checked));
    13282                break;
    13383            case "renderer":
    134                 keyRenderer = option[2].renderer;
     84                keyRenderer = option.parameters.renderer;
     85                if (!Engine["Renderer_Get" + keyRenderer + "Enabled"])
     86                {
     87                    warn(" invalid renderer key " + keyRenderer);
     88                    keyRenderer = undefined;
     89                    break;
     90                }
    13591                if (checked === undefined)
    13692                    checked = eval("Engine.Renderer_Get" + keyRenderer + "Enabled()");
    13793                else if (eval("Engine.Renderer_Get" + keyRenderer + "Enabled()") !== checked)
    13894                    eval("Engine.Renderer_Set" + keyRenderer + "Enabled(" + checked + ")");
    13995                break;
    140             case "function":
    141                 // This allows for doing low-level actions, like hiding/showing UI elements.
    142                 functionBody = option[2].function;
    143                 break;
    14496            default:
    145                 warn("Unknown option source type '" + action + "'");
     97                warn("Unknown option source type '" + param + "'");
    14698            }
    14799        }
    148100
    149         onPress = function(keyRenderer, keyConfig, functionBody)
     101        onUpdate = function(keyRenderer, keyConfig)
    150102        {
    151103            return function()
    152104            {
     
    154106                    eval("Engine.Renderer_Set" + keyRenderer + "Enabled(" + this.checked + ")");
    155107                if (keyConfig)
    156108                    Engine.ConfigDB_CreateValue("user", keyConfig, String(this.checked));
    157                 if (functionBody)
    158                     eval(functionBody);
    159109                updateStatus(true);
    160110            };
    161         }(keyRenderer, keyConfig, functionBody);
     111        }(keyRenderer, keyConfig);
    162112
    163113        // Load final data to the control element.
    164114        control.checked = checked;
    165         control.onPress = onPress;
     115        control.onPress = onUpdate;
    166116        break;
    167117    case "number":
    168118        // TODO: Slider
    169119    case "string":
    170         control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]");
     120        control = Engine.GetGUIObjectByName(category + "Input[" + i + "]");
    171121        var caption;
    172122        var key;
    173123        var functionBody;
     
    174124        var minval;
    175125        var maxval;
    176126
    177         for (let action of Object.keys(option[2]))
     127        for (let param of Object.keys(option.parameters))
    178128        {
    179             switch (action)
     129            switch (param)
    180130            {
    181131            case "config":
    182                 key = option[2].config;
     132                key = option.parameters.config;
    183133                caption = Engine.ConfigDB_GetValue("user", key);
    184134                break;
    185135            case "function":
    186                 // This allows for doing low-level actions, like hiding/showing UI elements.
    187                 functionBody = option[2].function;
     136                if (Engine[option.parameters.function])
     137                    functionBody = option.parameters.function;
    188138                break;
    189139            case "min":
    190                 minval = option[2].min;
     140                minval = option.parameters.min;
    191141                break;
    192142            case "max":
    193                 maxval = option[2].max;
     143                maxval = option.parameters.max;
    194144                break;
    195145            default:
    196146                warn("Unknown option source type '" + action + "'");
     
    201151        // - when the mouse leave the control (MouseLeave event)
    202152        // - or when saving or closing the window (registerChanges function)
    203153        // so we must ensure that something has indeed been modified
    204         onPress = function(key, functionBody, minval, maxval)
     154        onUpdate = function(key, functionBody, minval, maxval)
    205155        {
    206156            return function()
    207157            {
     
    213163                    return;
    214164                Engine.ConfigDB_CreateValue("user", key, this.caption);
    215165                if (functionBody)
    216                     eval(functionBody);
     166                {
     167                    let val = +this.caption;
     168                    Engine[functionBody](val);
     169                }
    217170                updateStatus(true);
    218171            };
    219172        }(key, functionBody, minval, maxval);
    220173
    221174        control.caption = caption;
    222         control.onPress = onPress;
    223         control.onMouseLeave = onPress;
     175        control.onPress = onUpdate;
     176        control.onMouseLeave = onUpdate;
    224177        g_controls.push(control);
    225178        break;
     179    case "dropdown":
     180        control = Engine.GetGUIObjectByName(category + "Dropdown[" + i + "]");
     181        var caption;
     182        var key;
     183        var functionBody;
     184        var minval;
     185        var maxval;
     186
     187        for (let param of Object.keys(option.parameters))
     188        {
     189            switch (param)
     190            {
     191            case "config":
     192                key = option.parameters.config;
     193                let val = Engine.ConfigDB_GetValue("user", key);
     194                if (key === "materialmgr.quality")
     195                    val = val > 5 ? 2 : val > 2 ? 1 : 0;
     196                control.selected = val;
     197                break;
     198            case "list":
     199                control.list = option.parameters.list;
     200                break;
     201            default:
     202                warn("Unknown option source type '" + action + "'");
     203            }
     204        }
     205
     206        onUpdate = function(key)
     207        {
     208            return function()
     209            {
     210                let val = this.selected;
     211                if (key === "materialmgr.quality")
     212                    val = val == 0 ? 2 : val == 1 ? 5 : 8;
     213                Engine.ConfigDB_CreateValue("user", key, val);
     214                updateStatus(true);
     215            };
     216        }(key);
     217
     218        control.onSelectionChange = onUpdate;
     219        break;
    226220    default:
    227         warn("Unknown option type '" + option[3] + "', assuming string. Valid types are 'number', 'string', or 'bool'.");
    228         control = Engine.GetGUIObjectByName(prefix + "Input[" + i + "]");
     221        warn("Unknown option type '" + option.type + "', assuming string. Valid types are 'number', 'string', or 'bool'.");
     222        control = Engine.GetGUIObjectByName(category + "Input[" + i + "]");
    229223        break;
    230224    }
    231225    control.hidden = false;
    232     control.tooltip = option[1];
     226    control.tooltip = option.tooltip ? translate(option.tooltip) : "";
    233227    return control;
    234228}
    235229
  • binaries/data/mods/public/gui/options/options.json

     
     1{
     2    "generalSetting":
     3    [
     4        {
     5            "type": "boolean",
     6            "label": "Windowed Mode",
     7            "tooltip": "Start 0 A.D. in a window",
     8            "parameters": { "config": "windowed" }
     9        },
     10        {
     11            "type": "boolean",
     12            "label": "Background Pause",
     13            "tooltip": "Pause single player games when window loses focus",
     14            "parameters": { "config": "pauseonfocusloss" }
     15        },
     16        {
     17            "type": "boolean",
     18            "label": "Disable Welcome Screen",
     19            "tooltip": "If you disable this screen completely, you may miss important announcements.\nYou can still launch it using the main menu.",
     20            "parameters": { "config": "splashscreendisable" }
     21        },
     22        {
     23            "type": "boolean",
     24            "label": "Detailed Tooltips",
     25            "tooltip": "Show detailed tooltips for trainable units in unit-producing buildings.",
     26            "parameters": { "config": "showdetailedtooltips" }
     27        },
     28        {
     29            "type": "boolean",
     30            "label": "FPS Overlay",
     31            "tooltip": "Show frames per second in top right corner.",
     32            "parameters": { "config": "overlay.fps" }
     33        },
     34        {
     35            "type": "boolean",
     36            "label": "Realtime Overlay",
     37            "tooltip": "Show current system time in top right corner.",
     38            "parameters": { "config": "overlay.realtime" }
     39        },
     40        {
     41            "type": "boolean",
     42            "label": "Gametime Overlay",
     43            "tooltip": "Show current simulation time in top right corner.",
     44            "parameters": { "config": "gui.session.timeelapsedcounter" }
     45        },
     46        {
     47            "type": "boolean",
     48            "label": "Ceasefire Time Overlay",
     49            "tooltip": "Always show the remaining ceasefire time.",
     50            "parameters": { "config": "gui.session.ceasefirecounter" }
     51        },
     52        {
     53            "type": "boolean",
     54            "label": "Persist Match Settings",
     55            "tooltip": "Save and restore match settings for quick reuse when hosting another game",
     56            "parameters": { "config": "persistmatchsettings" }
     57        }
     58    ],
     59    "graphicsSetting":
     60    [
     61        {
     62            "type": "boolean",
     63            "label": "Prefer GLSL",
     64            "tooltip": "Use OpenGL 2.0 shaders (recommended)",
     65            "parameters": { "renderer": "PreferGLSL", "config": "preferglsl" }
     66        },
     67        {
     68            "type": "boolean",
     69            "label": "Post Processing",
     70            "tooltip": "Use screen-space postprocessing filters (HDR, Bloom, DOF, etc)",
     71            "parameters": { "renderer": "Postproc", "config": "postproc" }
     72        },
     73        {
     74            "type": "boolean",
     75            "label": "Shadows",
     76            "tooltip": "Enable shadows",
     77            "parameters": { "renderer": "Shadows", "config": "shadows"}
     78        },
     79        {
     80            "type": "boolean",
     81            "label": "Particles",
     82            "tooltip": "Enable particles",
     83            "parameters": { "renderer": "Particles", "config": "particles" }
     84        },
     85        {
     86            "type": "boolean",
     87            "label": "Show Sky",
     88            "tooltip": "Render Sky",
     89            "parameters": { "renderer": "ShowSky", "config": "showsky" }
     90        },
     91        {
     92            "type": "boolean",
     93            "label": "Smooth LOS",
     94            "tooltip": "Lift darkness and fog-of-war smoothly",
     95            "parameters": { "renderer": "SmoothLOS", "config": "smoothlos" }
     96        },
     97        {
     98            "type": "boolean",
     99            "label": "Unit Silhouettes",
     100            "tooltip": "Show outlines of units behind buildings",
     101            "parameters": { "renderer": "Silhouettes", "config": "silhouettes" }
     102        },
     103        {
     104            "type": "boolean",
     105            "label": "Shadow Filtering",
     106            "tooltip": "Smooth shadows",
     107            "parameters": { "renderer": "ShadowPCF", "config": "shadowpcf" }
     108        },
     109        {
     110            "type": "boolean",
     111            "label": "Fast & Ugly Water",
     112            "tooltip": "Use the lowest settings possible to render water. This makes other settings irrelevant.",
     113            "parameters": { "renderer": "WaterUgly", "config": "waterugly" }
     114        },
     115        {
     116            "type": "boolean",
     117            "label": "HQ Water Effects",
     118            "tooltip": "Use higher-quality effects for water, rendering coastal waves, shore foam, and ships trails.",
     119            "parameters": { "renderer": "WaterFancyEffects", "config": "waterfancyeffects" }
     120        },
     121        {
     122            "type": "boolean",
     123            "label": "Real Water Depth",
     124            "tooltip": "Use actual water depth in rendering calculations",
     125            "parameters": { "renderer": "WaterRealDepth", "config": "waterrealdepth" }
     126        },
     127        {
     128            "type": "boolean",
     129            "label": "Water Reflections",
     130            "tooltip": "Allow water to reflect a mirror image",
     131            "parameters": { "renderer": "WaterReflection", "config": "waterreflection" }
     132        },
     133        {
     134            "type": "boolean",
     135            "label": "Water Refraction",
     136            "tooltip": "Use a real water refraction map and not transparency",
     137            "parameters": { "renderer": "WaterRefraction", "config": "waterrefraction" }
     138        },
     139        {
     140            "type": "boolean",
     141            "label": "Shadows on Water",
     142            "tooltip": "Cast shadows on water",
     143            "parameters": { "renderer": "WaterShadows", "config": "watershadows" }
     144        },
     145        {
     146            "type": "boolean",
     147            "label": "VSync",
     148            "tooltip": "Run vertical sync to fix screen tearing. REQUIRES GAME RESTART",
     149            "parameters": { "config": "vsync" }
     150        },
     151        {
     152            "type": "boolean",
     153            "label": "Limit FPS in Menus",
     154            "tooltip": "Limit FPS to 50 in all menus, to save power.",
     155            "parameters": { "config": "gui.menu.limitfps" }
     156        },
     157        {
     158            "type": "dropdown",
     159            "label": "Graphics quality",
     160            "tooltip": "Graphics quality. REQUIRES GAME RESTART",
     161            "parameters": { "list": [ "Low", "Medium", "High" ], "config": "materialmgr.quality" }
     162
     163        }
     164    ],
     165    "soundSetting":
     166    [
     167        {
     168            "type": "number",
     169            "label": "Master Gain",
     170            "tooltip": "Master audio gain",
     171            "parameters": { "config": "sound.mastergain", "function": "SetMasterGain", "min": "0" }
     172        },
     173        {
     174            "type": "number",
     175            "label": "Music Gain",
     176            "tooltip": "In game music gain",
     177            "parameters": { "config": "sound.musicgain", "function": "SetMusicGain", "min": "0" }
     178        },
     179        {
     180            "type": "number",
     181            "label": "Ambient Gain",
     182            "tooltip": "In game ambient sound gain",
     183            "parameters": { "config": "sound.ambientgain", "function": "SetAmbientGain", "min": "0" }
     184        },
     185        {
     186            "type": "number",
     187            "label": "Action Gain",
     188            "tooltip": "In game unit action sound gain",
     189            "parameters": { "config": "sound.actiongain", "function": "SetActionGain", "min": "0" }
     190        },
     191        {
     192            "type": "number",
     193            "label": "UI Gain",
     194            "tooltip": "UI sound gain",
     195            "parameters": { "config": "sound.uigain", "function": "SetUIGain", "min": "0" }
     196        }
     197    ],
     198    "lobbySetting":
     199    [
     200        {
     201            "type": "number",
     202            "label": "Chat Backlog",
     203            "tooltip": "Number of backlogged messages to load when joining the lobby",
     204            "parameters": { "config": "lobby.history", "min": "0" }
     205        },
     206        {
     207            "type": "boolean",
     208            "label": "Chat Timestamp",
     209            "tooltip": "Show time that messages are posted in the lobby chat",
     210            "parameters": { "config": "lobby.chattimestamp" }
     211        }
     212    ]
     213}
  • binaries/data/mods/public/gui/options/options.xml

     
    2626                    <object name="generalSettingLabel[n]" size="0 0 65% 100%" type="text" style="ModernLabelText" text_align="left"/>
    2727                    <object name="generalSettingTickbox[n]" size="90% 5 100% 100%+5" type="checkbox" style="ModernTickBox" hidden="true"/>
    2828                    <object name="generalSettingInput[n]" size="70% 0 100%-8 100%" type="input" style="ModernInput" hidden="true"/>
     29                    <object name="generalSettingDropdown[n]" size="70% 0 100%-8 100%" type="dropdown" style="ModernDropDown" hidden="true"/>
    2930                </object>
    3031            </repeat>
    3132        </object>
     
    3839                    <object name="graphicsSettingLabel[n]" size="0 0 65% 100%" type="text" style="ModernLabelText" text_align="left"/>
    3940                    <object name="graphicsSettingTickbox[n]" size="90% 5 100% 100%+5" type="checkbox" style="ModernTickBox" hidden="true"/>
    4041                    <object name="graphicsSettingInput[n]" size="70% 0 100%-8 100%" type="input" style="ModernInput" hidden="true"/>
     42                    <object name="graphicsSettingDropdown[n]" size="70% 0 100%-8 100%" type="dropdown" style="ModernDropDown" hidden="true"/>
    4143                </object>
    4244            </repeat>
    4345        </object>
     
    5052                    <object name="soundSettingLabel[n]" size="0 0 65% 100%" type="text" style="ModernLabelText" text_align="left"/>
    5153                    <object name="soundSettingTickbox[n]" size="90% 5 100% 100%+5" type="checkbox" style="ModernTickBox" hidden="true"/>
    5254                    <object name="soundSettingInput[n]" size="70% 0 100%-8 100%" type="input" style="ModernInput" hidden="true"/>
     55                    <object name="soundSettingDropdown[n]" size="70% 0 100%-8 100%" type="dropdown" style="ModernDropDown" hidden="true"/>
    5356                </object>
    5457            </repeat>
    5558        </object>
     
    6265                    <object name="lobbySettingLabel[n]" size="0 0 65% 100%" type="text" style="ModernLabelText" text_align="left"/>
    6366                    <object name="lobbySettingTickbox[n]" size="90% 5 100% 100%+5" type="checkbox" style="ModernTickBox" hidden="true"/>
    6467                    <object name="lobbySettingInput[n]" size="70% 0 100%-8 100%" type="input" style="ModernInput" hidden="true"/>
     68                    <object name="lobbySettingDropdown[n]" size="70% 0 100%-8 100%" type="dropdown" style="ModernDropDown" hidden="true"/>
    6569                </object>
    6670            </repeat>
    6771        </object>
  • binaries/data/mods/public/l10n/messages.json

     
    288288                }
    289289            },
    290290            {
     291                "extractor": "json",
     292                "filemasks": [
     293                    "gui/options/**.json",
     294                ],
     295                "options": {
     296                    "keywords": [
     297                        "label",
     298                        "tooltip",
     299                        "list"
     300                    ]
     301                }
     302            },
     303            {
    291304                "extractor": "txt",
    292305                "filemasks": [
    293306                    "gui/splashscreen/splashscreen.txt",