]> git.lizzy.rs Git - minetest.git/blobdiff - builtin/mainmenu/dlg_settings_advanced.lua
All settings: Fix missing flags checkbox caused by 'possible flags' order (#8997)
[minetest.git] / builtin / mainmenu / dlg_settings_advanced.lua
index d8d20465d81adf29a871fe757b62efdf24a3b0db..24b71d957870bcf66ad54e704cb8b19641e576d3 100644 (file)
@@ -148,9 +148,9 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
                local values = {}
                local ti = 1
                local index = 1
-               for line in default:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
-                       index = default:find("[+-]?[%d.-e]+", index) + line:len()
-                       table.insert(values, line)
+               for match in default:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
+                       index = default:find("[+-]?[%d.-e]+", index) + match:len()
+                       table.insert(values, match)
                        ti = ti + 1
                        if ti > 9 then
                                break
@@ -322,17 +322,20 @@ end
 -- read_all: whether to ignore certain setting types for GUI or not
 -- parse_mods: whether to parse settingtypes.txt in mods and games
 local function parse_config_file(read_all, parse_mods)
-       local builtin_path = core.get_builtin_path() .. FILENAME
-       local file = io.open(builtin_path, "r")
        local settings = {}
-       if not file then
-               core.log("error", "Can't load " .. FILENAME)
-               return settings
-       end
 
-       parse_single_file(file, builtin_path, read_all, settings, 0, true)
+       do
+               local builtin_path = core.get_builtin_path() .. FILENAME
+               local file = io.open(builtin_path, "r")
+               if not file then
+                       core.log("error", "Can't load " .. FILENAME)
+                       return settings
+               end
 
-       file:close()
+               parse_single_file(file, builtin_path, read_all, settings, 0, true)
+
+               file:close()
+       end
 
        if parse_mods then
                -- Parse games
@@ -344,7 +347,7 @@ local function parse_config_file(read_all, parse_mods)
                        local file = io.open(path, "r")
                        if file then
                                if not games_category_initialized then
-                                       local translation = fgettext_ne("Games"), -- not used, but needed for xgettext
+                                       fgettext_ne("Games") -- not used, but needed for xgettext
                                        table.insert(settings, {
                                                name = "Games",
                                                level = 0,
@@ -377,7 +380,7 @@ local function parse_config_file(read_all, parse_mods)
                        local file = io.open(path, "r")
                        if file then
                                if not mods_category_initialized then
-                                       local translation = fgettext_ne("Mods"), -- not used, but needed for xgettext
+                                       fgettext_ne("Mods") -- not used, but needed for xgettext
                                        table.insert(settings, {
                                                name = "Mods",
                                                level = 0,
@@ -522,8 +525,10 @@ local function get_current_np_group_as_string(setting)
                        value.seed .. ", " ..
                        value.octaves .. ", " ..
                        value.persistence .. ", " ..
-                       value.lacunarity .. ", " ..
-                       value.flags
+                       value.lacunarity
+               if value.flags ~= "" then
+                       t = t .. ", " .. value.flags
+               end
        end
        return t
 end
@@ -532,59 +537,27 @@ local checkboxes = {} -- handle checkboxes events
 
 local function create_change_setting_formspec(dialogdata)
        local setting = settings[selected_setting]
-       local height = 5.2
-       if setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
-               -- Three flags, checkboxes on 2 columns, with a vertical space of 1/2 unit
-               height = 8.7
-       elseif setting.type == "flags" then
-               -- Checkboxes on 2 columns, with a vertical space of 1/2 unit
-               height = 5.2 + math.ceil(#setting.possible / 2) / 2
-       end
-       local formspec = "size[10," .. height .. ",true]" ..
-                       "button[5," .. height - 0.7 .. ";2,1;btn_done;" .. fgettext("Save") .. "]" ..
-                       "button[3," .. height - 0.7 .. ";2,1;btn_cancel;" .. fgettext("Cancel") .. "]" ..
-                       "tablecolumns[color;text]" ..
-                       "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
-                       "table[0,0;10,3;info;"
-
-       if setting.readable_name then
-               formspec = formspec .. "#FFFF00," .. fgettext(setting.readable_name)
-                               .. " (" .. core.formspec_escape(setting.name) .. "),"
-       else
-               formspec = formspec .. "#FFFF00," .. core.formspec_escape(setting.name) .. ","
-       end
-
-       formspec = formspec .. ",,"
-
-       local comment_text = ""
-
-       if setting.comment == "" then
-               comment_text = fgettext_ne("(No description of setting given)")
-       else
-               comment_text = fgettext_ne(setting.comment)
-       end
-       for _, comment_line in ipairs(comment_text:split("\n", true)) do
-               formspec = formspec .. "," .. core.formspec_escape(comment_line) .. ","
-       end
-
-       formspec = formspec:sub(1, -2) -- remove trailing comma
-
-       formspec = formspec .. ";1]"
-
+       -- Final formspec will be created at the end of this function
+       -- Default values below, may be changed depending on setting type
+       local width = 10
+       local height = 3.5
+       local description_height = 3
+       local formspec = ""
+
+       -- Setting-specific formspec elements
        if setting.type == "bool" then
-               local selected_index
+               local selected_index = 1
                if core.is_yes(get_current_value(setting)) then
                        selected_index = 2
-               else
-                       selected_index = 1
                end
-               formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;"
+               formspec = "dropdown[3," .. height .. ";4,1;dd_setting_value;"
                                .. fgettext("Disabled") .. "," .. fgettext("Enabled") .. ";"
                                .. selected_index .. "]"
+               height = height + 1.25
 
        elseif setting.type == "enum" then
                local selected_index = 0
-               formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;"
+               formspec = "dropdown[3," .. height .. ";4,1;dd_setting_value;"
                for index, value in ipairs(setting.values) do
                        -- translating value is not possible, since it's the value
                        --  that we set the setting to
@@ -597,15 +570,18 @@ local function create_change_setting_formspec(dialogdata)
                        formspec = formspec:sub(1, -2) -- remove trailing comma
                end
                formspec = formspec .. ";" .. selected_index .. "]"
+               height = height + 1.25
 
        elseif setting.type == "path" or setting.type == "filepath" then
                local current_value = dialogdata.selected_path
                if not current_value then
                        current_value = get_current_value(setting)
                end
-               formspec = formspec .. "field[0.5,4;7.5,1;te_setting_value;;"
+               formspec = "field[0.28," .. height + 0.15 .. ";8,1;te_setting_value;;"
                                .. core.formspec_escape(current_value) .. "]"
-                               .. "button[8,3.75;2,1;btn_browser_" .. setting.type .. ";" .. fgettext("Browse") .. "]"
+                               .. "button[8," .. height - 0.15 .. ";2,1;btn_browser_"
+                               .. setting.type .. ";" .. fgettext("Browse") .. "]"
+               height = height + 1.15
 
        elseif setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
                local t = get_current_np_group(setting)
@@ -614,27 +590,40 @@ local function create_change_setting_formspec(dialogdata)
                        dimension = 2
                end
 
-               formspec = formspec
-                               .. "label[0,2.5;(" .. dimension .. "D Noise)]"
-                               .. "field[0.5,4;3.3,1;te_offset;Offset;" -- Offset
-                               .. core.formspec_escape(t[1] or "") .. "]"
-                               .. "field[3.8,4;3.3,1;te_scale;Scale;" -- Scale
-                               .. core.formspec_escape(t[2] or "") .. "]"
-                               .. "field[7.1,4;3.3,1;te_seed;Seed;" -- Seed
-                               .. core.formspec_escape(t[6] or "") .. "]"
-                               .. "label[0.5,4.7;Spread]" -- Spread
-                               .. "field[2.0,5;2.8,1;te_spreadx;X;"
-                               .. core.formspec_escape(t[3] or "") .. "]"
-                               .. "field[4.8,5;2.8,1;te_spready;Y;"
-                               .. core.formspec_escape(t[4] or "") .. "]"
-                               .. "field[7.6,5;2.8,1;te_spreadz;Z;"
-                               .. core.formspec_escape(t[5] or "") .. "]"
-                               .. "field[0.5,6;3.3,1;te_octaves;Octaves;" -- Octaves
-                               .. core.formspec_escape(t[7] or "") .. "]"
-                               .. "field[3.8,6;3.3,1;te_persist;Persistance;" -- Persistance
-                               .. core.formspec_escape(t[8] or "") .. "]"
-                               .. "field[7.1,6;3.3,1;te_lacun;Lacunarity;" -- Lacunarity
-                               .. core.formspec_escape(t[9] or "") .. "]"
+               -- More space for 3x3 fields
+               description_height = description_height - 1.5
+               height = height - 1.5
+
+               local fields = {}
+               local function add_field(x, name, label, value)
+                       fields[#fields + 1] = ("field[%f,%f;3.3,1;%s;%s;%s]"):format(
+                               x, height, name, label, core.formspec_escape(value or "")
+                       )
+               end
+               -- First row
+               height = height + 0.3
+               add_field(0.3, "te_offset", fgettext("Offset"), t[1])
+               add_field(3.6, "te_scale",  fgettext("Scale"),  t[2])
+               add_field(6.9, "te_seed",   fgettext("Seed"),   t[6])
+               height = height + 1.1
+
+               -- Second row
+               add_field(0.3, "te_spreadx", fgettext("X spread"), t[3])
+               if dimension == 3 then
+                       add_field(3.6, "te_spready", fgettext("Y spread"), t[4])
+               else
+                       fields[#fields + 1] = "label[4," .. height - 0.2 .. ";" ..
+                                       fgettext("2D Noise") .. "]"
+               end
+               add_field(6.9, "te_spreadz", fgettext("Z spread"), t[5])
+               height = height + 1.1
+
+               -- Third row
+               add_field(0.3, "te_octaves", fgettext("Octaves"),     t[7])
+               add_field(3.6, "te_persist", fgettext("Persistance"), t[8])
+               add_field(6.9, "te_lacun",   fgettext("Lacunarity"),  t[9])
+               height = height + 1.1
+
 
                local enabled_flags = flags_to_table(t[10])
                local flags = {}
@@ -642,14 +631,23 @@ local function create_change_setting_formspec(dialogdata)
                        -- Index by name, to avoid iterating over all enabled_flags for every possible flag.
                        flags[name] = true
                end
+               for _, name in ipairs(setting.flags) do
+                       local checkbox_name = "cb_" .. name
+                       local is_enabled = flags[name] == true -- to get false if nil
+                       checkboxes[checkbox_name] = is_enabled
+               end
                -- Flags
-               formspec = formspec
-                               .. "checkbox[0.5,6.5;cb_defaults;defaults;" -- defaults
+               formspec = table.concat(fields)
+                               .. "checkbox[0.5," .. height - 0.6 .. ";cb_defaults;"
+                               .. fgettext("defaults") .. ";" -- defaults
                                .. tostring(flags["defaults"] == true) .. "]" -- to get false if nil
-                               .. "checkbox[5,6.5;cb_eased;eased;" -- eased
+                               .. "checkbox[5," .. height - 0.6 .. ";cb_eased;"
+                               .. fgettext("eased") .. ";" -- eased
                                .. tostring(flags["eased"] == true) .. "]"
-                               .. "checkbox[5,7.0;cb_absvalue;absvalue;" -- absvalue
+                               .. "checkbox[5," .. height - 0.15 .. ";cb_absvalue;"
+                               .. fgettext("absvalue") .. ";" -- absvalue
                                .. tostring(flags["absvalue"] == true) .. "]"
+               height = height + 1
 
        elseif setting.type == "v3f" then
                local val = get_current_value(setting)
@@ -658,56 +656,130 @@ local function create_change_setting_formspec(dialogdata)
                        table.insert(v3f, line)
                end
 
+               height = height + 0.3
                formspec = formspec
-                               .. "field[0.5,4;3.3,1;te_x;X;" -- X
+                               .. "field[0.3," .. height .. ";3.3,1;te_x;"
+                               .. fgettext("X") .. ";" -- X
                                .. core.formspec_escape(v3f[1] or "") .. "]"
-                               .. "field[3.8,4;3.3,1;te_y;Y;" -- Y
+                               .. "field[3.6," .. height .. ";3.3,1;te_y;"
+                               .. fgettext("Y") .. ";" -- Y
                                .. core.formspec_escape(v3f[2] or "") .. "]"
-                               .. "field[7.1,4;3.3,1;te_z;Z;" -- Z
+                               .. "field[6.9," .. height .. ";3.3,1;te_z;"
+                               .. fgettext("Z") .. ";" -- Z
                                .. core.formspec_escape(v3f[3] or "") .. "]"
+               height = height + 1.1
 
        elseif setting.type == "flags" then
-               local enabled_flags = flags_to_table(get_current_value(setting))
+               local current_flags = flags_to_table(get_current_value(setting))
                local flags = {}
-               for _, name in ipairs(enabled_flags) do
+               for _, name in ipairs(current_flags) do
                        -- Index by name, to avoid iterating over all enabled_flags for every possible flag.
-                       flags[name] = true
+                       if name:sub(1, 2) == "no" then
+                               flags[name:sub(3)] = false
+                       else
+                               flags[name] = true
+                       end
                end
-               local flags_count = #setting.possible
-               for i, name in ipairs(setting.possible) do
-                       local x = 0.5
-                       local y = 3.5 + i / 2
-                       if i - 1 >= flags_count / 2 then -- 2nd column
-                               x = 5
-                               y = y - flags_count / 4
+               local flags_count = #setting.possible / 2
+               local max_height = math.ceil(flags_count / 2) / 2
+
+               -- More space for flags
+               description_height = description_height - 1
+               height = height - 1
+
+               local fields = {} -- To build formspec
+               local j = 1
+               for _, name in ipairs(setting.possible) do
+                       if name:sub(1, 2) ~= "no" then
+                               local x = 0.5
+                               local y = height + j / 2 - 0.75
+                               if j - 1 >= flags_count / 2 then -- 2nd column
+                                       x = 5
+                                       y = y - max_height
+                               end
+                               j = j + 1;
+                               local checkbox_name = "cb_" .. name
+                               local is_enabled = flags[name] == true -- to get false if nil
+                               checkboxes[checkbox_name] = is_enabled
+
+                               fields[#fields + 1] = ("checkbox[%f,%f;%s;%s;%s]"):format(
+                                       x, y, checkbox_name, name, tostring(is_enabled)
+                               )
                        end
-                       local checkbox_name = "cb_" .. name
-                       local is_enabled = flags[name] == true -- to get false if nil
-                       checkboxes[checkbox_name] = is_enabled
-                       formspec = formspec .. "checkbox["
-                                       .. x .. "," .. y
-                                       .. ";" .. checkbox_name .. ";"
-                                       .. name .. ";" .. tostring(is_enabled) .. "]"
                end
+               formspec = table.concat(fields)
+               height = height + max_height + 0.25
 
        else
                -- TODO: fancy input for float, int
-               local width = 10
                local text = get_current_value(setting)
-               if dialogdata.error_message then
-                       formspec = formspec .. "tablecolumns[color;text]" ..
-                       "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
-                       "table[5,3.9;5,0.6;error_message;#FF0000,"
-                                       .. core.formspec_escape(dialogdata.error_message) .. ";0]"
-                       width = 5
-                       if dialogdata.entered_text then
-                               text = dialogdata.entered_text
-                       end
+               if dialogdata.error_message and dialogdata.entered_text then
+                       text = dialogdata.entered_text
                end
-               formspec = formspec .. "field[0.28,4;" .. width .. ",1;te_setting_value;;"
+               formspec = "field[0.28," .. height + 0.15 .. ";" .. width .. ",1;te_setting_value;;"
                                .. core.formspec_escape(text) .. "]"
+               height = height + 1.15
        end
-       return formspec
+
+       -- Box good, textarea bad. Calculate textarea size from box.
+       local function create_textfield(size, label, text, bg_color)
+               local textarea = {
+                       x = size.x + 0.3,
+                       y = size.y,
+                       w = size.w + 0.25,
+                       h = size.h * 1.16 + 0.12
+               }
+               return ("box[%f,%f;%f,%f;%s]textarea[%f,%f;%f,%f;;%s;%s]"):format(
+                       size.x, size.y, size.w, size.h, bg_color or "#000",
+                       textarea.x, textarea.y, textarea.w, textarea.h,
+                       core.formspec_escape(label), core.formspec_escape(text)
+               )
+
+       end
+
+       -- When there's an error: Shrink description textarea and add error below
+       if dialogdata.error_message then
+               local error_box = {
+                       x = 0,
+                       y = description_height - 0.4,
+                       w = width - 0.25,
+                       h = 0.5
+               }
+               formspec = formspec ..
+                       create_textfield(error_box, "", dialogdata.error_message, "#600")
+               description_height = description_height - 0.75
+       end
+
+       -- Get description field
+       local description_box = {
+               x = 0,
+               y = 0.2,
+               w = width - 0.25,
+               h = description_height
+       }
+
+       local setting_name = setting.name
+       if setting.readable_name then
+               setting_name = fgettext_ne(setting.readable_name) ..
+                       " (" .. setting.name .. ")"
+       end
+
+       local comment_text
+       if setting.comment == "" then
+               comment_text = fgettext_ne("(No description of setting given)")
+       else
+               comment_text = fgettext_ne(setting.comment)
+       end
+
+       return (
+               "size[" .. width .. "," .. height + 0.25 .. ",true]" ..
+               create_textfield(description_box, setting_name, comment_text) ..
+               formspec ..
+               "button[" .. width / 2 - 2.5 .. "," .. height - 0.4 .. ";2.5,1;btn_done;" ..
+                       fgettext("Save") .. "]" ..
+               "button[" .. width / 2 .. "," .. height - 0.4 .. ";2.5,1;btn_cancel;" ..
+                       fgettext("Cancel") .. "]"
+       )
 end
 
 local function handle_change_setting_buttons(this, fields)
@@ -769,8 +841,12 @@ local function handle_change_setting_buttons(this, fields)
                elseif setting.type == "flags" then
                        local values = {}
                        for _, name in ipairs(setting.possible) do
-                               if checkboxes["cb_" .. name] then
-                                       table.insert(values, name)
+                               if name:sub(1, 2) ~= "no" then
+                                       if checkboxes["cb_" .. name] then
+                                               table.insert(values, name)
+                                       else
+                                               table.insert(values, "no" .. name)
+                                       end
                                end
                        end
 
@@ -789,6 +865,9 @@ local function handle_change_setting_buttons(this, fields)
 
                        checkboxes = {}
 
+                       if setting.type == "noise_params_2d" then
+                                fields["te_spready"] = fields["te_spreadz"]
+                       end
                        local new_value = {
                                offset = fields["te_offset"],
                                scale = fields["te_scale"],
@@ -854,7 +933,7 @@ local function handle_change_setting_buttons(this, fields)
        return false
 end
 
-local function create_settings_formspec(tabview, name, tabdata)
+local function create_settings_formspec(tabview, _, tabdata)
        local formspec = "size[12,5.4;true]" ..
                        "tablecolumns[color;tree;text,width=28;text]" ..
                        "tableoptions[background=#00000000;border=false]" ..
@@ -886,7 +965,7 @@ local function create_settings_formspec(tabview, name, tabdata)
                        formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
                                        .. value .. ","
 
-               elseif entry.type == "key" then
+               elseif entry.type == "key" then --luacheck: ignore
                        -- ignore key settings, since we have a special dialog for them
 
                elseif entry.type == "noise_params_2d" or entry.type == "noise_params_3d" then
@@ -965,8 +1044,8 @@ local function handle_settings_buttons(this, fields, tabname, tabdata)
        if fields["btn_edit"] or list_enter then
                local setting = settings[selected_setting]
                if setting and setting.type ~= "category" then
-                       local edit_dialog = dialog_create("change_setting", create_change_setting_formspec,
-                                       handle_change_setting_buttons)
+                       local edit_dialog = dialog_create("change_setting",
+                                       create_change_setting_formspec, handle_change_setting_buttons)
                        edit_dialog:set_parent(this)
                        this:hide()
                        edit_dialog:show()
@@ -1008,7 +1087,9 @@ function create_adv_settings_dlg()
                                return dlg
 end
 
--- Uncomment to generate minetest.conf.example and settings_translation_file.cpp
--- For RUN_IN_PLACE the generated files may appear in the bin folder
+-- Uncomment to generate 'minetest.conf.example' and 'settings_translation_file.cpp'.
+-- For RUN_IN_PLACE the generated files may appear in the 'bin' folder.
+-- See comment and alternative line at the end of 'generate_from_settingtypes.lua'.
 
---assert(loadfile(core.get_builtin_path().."mainmenu"..DIR_DELIM.."generate_from_settingtypes.lua"))(parse_config_file(true, false))
+--assert(loadfile(core.get_builtin_path().."mainmenu"..DIR_DELIM..
+--             "generate_from_settingtypes.lua"))(parse_config_file(true, false))