2 --Copyright (C) 2015 PilzAdam
4 --This program is free software; you can redistribute it and/or modify
5 --it under the terms of the GNU Lesser General Public License as published by
6 --the Free Software Foundation; either version 2.1 of the License, or
7 --(at your option) any later version.
9 --This program is distributed in the hope that it will be useful,
10 --but WITHOUT ANY WARRANTY; without even the implied warranty of
11 --MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 --GNU Lesser General Public License for more details.
14 --You should have received a copy of the GNU Lesser General Public License along
15 --with this program; if not, write to the Free Software Foundation, Inc.,
16 --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 local FILENAME = "settingtypes.txt"
20 local CHAR_CLASSES = {
22 VARIABLE = "[%w_%-%.]",
23 INTEGER = "[+-]?[%d]",
24 FLOAT = "[+-]?[%d%.]",
28 local function flags_to_table(flags)
29 return flags:gsub("%s+", ""):split(",", true) -- Remove all spaces and split
32 -- returns error message, or nil
33 local function parse_setting_line(settings, line, read_all, base_level, allow_secure)
35 local comment = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$")
37 if settings.current_comment == "" then
38 settings.current_comment = comment
40 settings.current_comment = settings.current_comment .. "\n" .. comment
45 -- clear current_comment so only comments directly above a setting are bound to it
46 -- but keep a local reference to it for variables in the current line
47 local current_comment = settings.current_comment
48 settings.current_comment = ""
51 if line:match("^" .. CHAR_CLASSES.SPACE .. "*$") then
56 local stars, category = line:match("^%[([%*]*)([^%]]+)%]$")
58 table.insert(settings, {
60 level = stars:len() + base_level,
67 local first_part, name, readable_name, setting_type = line:match("^"
68 -- this first capture group matches the whole first part,
69 -- so we can later strip it from the rest of the line
71 .. "([" .. CHAR_CLASSES.VARIABLE .. "+)" -- variable name
72 .. CHAR_CLASSES.SPACE .. "*"
73 .. "%(([^%)]*)%)" -- readable name
74 .. CHAR_CLASSES.SPACE .. "*"
75 .. "(" .. CHAR_CLASSES.VARIABLE .. "+)" -- type
76 .. CHAR_CLASSES.SPACE .. "*"
79 if not first_part then
83 if name:match("secure%.[.]*") and not allow_secure then
84 return "Tried to add \"secure.\" setting"
87 if readable_name == "" then
90 local remaining_line = line:sub(first_part:len() + 1)
92 if setting_type == "int" then
93 local default, min, max = remaining_line:match("^"
94 -- first int is required, the last 2 are optional
95 .. "(" .. CHAR_CLASSES.INTEGER .. "+)" .. CHAR_CLASSES.SPACE .. "*"
96 .. "(" .. CHAR_CLASSES.INTEGER .. "*)" .. CHAR_CLASSES.SPACE .. "*"
97 .. "(" .. CHAR_CLASSES.INTEGER .. "*)"
100 if not default or not tonumber(default) then
101 return "Invalid integer setting"
106 table.insert(settings, {
108 readable_name = readable_name,
113 comment = current_comment,
118 if setting_type == "string"
119 or setting_type == "key" or setting_type == "v3f" then
120 local default = remaining_line:match("^(.*)$")
123 return "Invalid string setting"
125 if setting_type == "key" and not read_all then
126 -- ignore key type if read_all is false
130 table.insert(settings, {
132 readable_name = readable_name,
135 comment = current_comment,
140 if setting_type == "noise_params_2d"
141 or setting_type == "noise_params_3d" then
142 local default = remaining_line:match("^(.*)$")
145 return "Invalid string setting"
151 for match in default:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
152 index = default:find("[+-]?[%d.-e]+", index) + match:len()
153 table.insert(values, match)
159 index = default:find("[^, ]", index)
162 flags = default:sub(index)
163 default = default:sub(1, index - 3) -- Make sure no flags in single-line format
165 table.insert(values, flags)
167 table.insert(settings, {
169 readable_name = readable_name,
182 persistence = values[8],
183 lacunarity = values[9],
187 comment = current_comment,
189 flags = flags_to_table("defaults,eased,absvalue")
194 if setting_type == "bool" then
195 if remaining_line ~= "false" and remaining_line ~= "true" then
196 return "Invalid boolean setting"
199 table.insert(settings, {
201 readable_name = readable_name,
203 default = remaining_line,
204 comment = current_comment,
209 if setting_type == "float" then
210 local default, min, max = remaining_line:match("^"
211 -- first float is required, the last 2 are optional
212 .. "(" .. CHAR_CLASSES.FLOAT .. "+)" .. CHAR_CLASSES.SPACE .. "*"
213 .. "(" .. CHAR_CLASSES.FLOAT .. "*)" .. CHAR_CLASSES.SPACE .. "*"
214 .. "(" .. CHAR_CLASSES.FLOAT .. "*)"
217 if not default or not tonumber(default) then
218 return "Invalid float setting"
223 table.insert(settings, {
225 readable_name = readable_name,
230 comment = current_comment,
235 if setting_type == "enum" then
236 local default, values = remaining_line:match("^"
237 -- first value (default) may be empty (i.e. is optional)
238 .. "(" .. CHAR_CLASSES.VARIABLE .. "*)" .. CHAR_CLASSES.SPACE .. "*"
239 .. "(" .. CHAR_CLASSES.FLAGS .. "+)"
242 if not default or values == "" then
243 return "Invalid enum setting"
246 table.insert(settings, {
248 readable_name = readable_name,
251 values = values:split(",", true),
252 comment = current_comment,
257 if setting_type == "path" or setting_type == "filepath" then
258 local default = remaining_line:match("^(.*)$")
261 return "Invalid path setting"
264 table.insert(settings, {
266 readable_name = readable_name,
269 comment = current_comment,
274 if setting_type == "flags" then
275 local default, possible = remaining_line:match("^"
276 -- first value (default) may be empty (i.e. is optional)
277 -- this is implemented by making the last value optional, and
278 -- swapping them around if it turns out empty.
279 .. "(" .. CHAR_CLASSES.FLAGS .. "+)" .. CHAR_CLASSES.SPACE .. "*"
280 .. "(" .. CHAR_CLASSES.FLAGS .. "*)"
283 if not default or not possible then
284 return "Invalid flags setting"
287 if possible == "" then
292 table.insert(settings, {
294 readable_name = readable_name,
297 possible = flags_to_table(possible),
298 comment = current_comment,
303 return "Invalid setting type \"" .. setting_type .. "\""
306 local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure)
307 -- store this helper variable in the table so it's easier to pass to parse_setting_line()
308 result.current_comment = ""
310 local line = file:read("*line")
312 local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure)
314 core.log("error", error_msg .. " in " .. filepath .. " \"" .. line .. "\"")
316 line = file:read("*line")
319 result.current_comment = nil
322 -- read_all: whether to ignore certain setting types for GUI or not
323 -- parse_mods: whether to parse settingtypes.txt in mods and games
324 local function parse_config_file(read_all, parse_mods)
328 local builtin_path = core.get_builtin_path() .. FILENAME
329 local file = io.open(builtin_path, "r")
331 core.log("error", "Can't load " .. FILENAME)
335 parse_single_file(file, builtin_path, read_all, settings, 0, true)
342 local games_category_initialized = false
344 local game = pkgmgr.get_game(index)
346 local path = game.path .. DIR_DELIM .. FILENAME
347 local file = io.open(path, "r")
349 if not games_category_initialized then
350 fgettext_ne("Games") -- not used, but needed for xgettext
351 table.insert(settings, {
356 games_category_initialized = true
359 table.insert(settings, {
365 parse_single_file(file, path, read_all, settings, 2, false)
371 game = pkgmgr.get_game(index)
375 local mods_category_initialized = false
377 get_mods(core.get_modpath(), mods)
378 for _, mod in ipairs(mods) do
379 local path = mod.path .. DIR_DELIM .. FILENAME
380 local file = io.open(path, "r")
382 if not mods_category_initialized then
383 fgettext_ne("Mods") -- not used, but needed for xgettext
384 table.insert(settings, {
389 mods_category_initialized = true
392 table.insert(settings, {
398 parse_single_file(file, path, read_all, settings, 2, false)
408 local function filter_settings(settings, searchstring)
409 if not searchstring or searchstring == "" then
413 -- Setup the keyword list
415 for word in searchstring:lower():gmatch("%S+") do
416 table.insert(keywords, word)
420 local category_stack = {}
421 local current_level = 0
422 local best_setting = nil
423 for _, entry in pairs(settings) do
424 if entry.type == "category" then
425 -- Remove all settingless categories
426 while #category_stack > 0 and entry.level <= current_level do
427 table.remove(category_stack, #category_stack)
428 if #category_stack > 0 then
429 current_level = category_stack[#category_stack].level
435 -- Push category onto stack
436 category_stack[#category_stack + 1] = entry
437 current_level = entry.level
439 -- See if setting matches keywords
440 local setting_score = 0
441 for k = 1, #keywords do
442 local keyword = keywords[k]
444 if string.find(entry.name:lower(), keyword, 1, true) then
445 setting_score = setting_score + 1
448 if entry.readable_name and
449 string.find(fgettext(entry.readable_name):lower(), keyword, 1, true) then
450 setting_score = setting_score + 1
454 string.find(fgettext_ne(entry.comment):lower(), keyword, 1, true) then
455 setting_score = setting_score + 1
459 -- Add setting to results if match
460 if setting_score > 0 then
461 -- Add parent categories
462 for _, category in pairs(category_stack) do
463 result[#result + 1] = category
468 result[#result + 1] = entry
469 entry.score = setting_score
471 if not best_setting or
472 setting_score > result[best_setting].score then
473 best_setting = #result
478 return result, best_setting or -1
481 local full_settings = parse_config_file(false, true)
482 local search_string = ""
483 local settings = full_settings
484 local selected_setting = 1
486 local function get_current_value(setting)
487 local value = core.settings:get(setting.name)
489 value = setting.default
494 local function get_current_np_group(setting)
495 local value = core.settings:get_np_group(setting.name)
500 table.insert(t, value.offset)
501 table.insert(t, value.scale)
502 table.insert(t, value.spread.x)
503 table.insert(t, value.spread.y)
504 table.insert(t, value.spread.z)
505 table.insert(t, value.seed)
506 table.insert(t, value.octaves)
507 table.insert(t, value.persistence)
508 table.insert(t, value.lacunarity)
509 table.insert(t, value.flags)
514 local function get_current_np_group_as_string(setting)
515 local value = core.settings:get_np_group(setting.name)
520 t = value.offset .. ", " ..
521 value.scale .. ", (" ..
522 value.spread.x .. ", " ..
523 value.spread.y .. ", " ..
524 value.spread.z .. "), " ..
525 value.seed .. ", " ..
526 value.octaves .. ", " ..
527 value.persistence .. ", " ..
529 if value.flags ~= "" then
530 t = t .. ", " .. value.flags
536 local checkboxes = {} -- handle checkboxes events
538 local function create_change_setting_formspec(dialogdata)
539 local setting = settings[selected_setting]
540 -- Final formspec will be created at the end of this function
541 -- Default values below, may be changed depending on setting type
544 local description_height = 3
547 -- Setting-specific formspec elements
548 if setting.type == "bool" then
549 local selected_index = 1
550 if core.is_yes(get_current_value(setting)) then
553 formspec = "dropdown[3," .. height .. ";4,1;dd_setting_value;"
554 .. fgettext("Disabled") .. "," .. fgettext("Enabled") .. ";"
555 .. selected_index .. "]"
556 height = height + 1.25
558 elseif setting.type == "enum" then
559 local selected_index = 0
560 formspec = "dropdown[3," .. height .. ";4,1;dd_setting_value;"
561 for index, value in ipairs(setting.values) do
562 -- translating value is not possible, since it's the value
563 -- that we set the setting to
564 formspec = formspec .. core.formspec_escape(value) .. ","
565 if get_current_value(setting) == value then
566 selected_index = index
569 if #setting.values > 0 then
570 formspec = formspec:sub(1, -2) -- remove trailing comma
572 formspec = formspec .. ";" .. selected_index .. "]"
573 height = height + 1.25
575 elseif setting.type == "path" or setting.type == "filepath" then
576 local current_value = dialogdata.selected_path
577 if not current_value then
578 current_value = get_current_value(setting)
580 formspec = "field[0.28," .. height + 0.15 .. ";8,1;te_setting_value;;"
581 .. core.formspec_escape(current_value) .. "]"
582 .. "button[8," .. height - 0.15 .. ";2,1;btn_browser_"
583 .. setting.type .. ";" .. fgettext("Browse") .. "]"
584 height = height + 1.15
586 elseif setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
587 local t = get_current_np_group(setting)
589 if setting.type == "noise_params_2d" then
593 -- More space for 3x3 fields
594 description_height = description_height - 1.5
595 height = height - 1.5
598 local function add_field(x, name, label, value)
599 fields[#fields + 1] = ("field[%f,%f;3.3,1;%s;%s;%s]"):format(
600 x, height, name, label, core.formspec_escape(value or "")
604 height = height + 0.3
605 add_field(0.3, "te_offset", fgettext("Offset"), t[1])
606 add_field(3.6, "te_scale", fgettext("Scale"), t[2])
607 add_field(6.9, "te_seed", fgettext("Seed"), t[6])
608 height = height + 1.1
611 add_field(0.3, "te_spreadx", fgettext("X spread"), t[3])
612 if dimension == 3 then
613 add_field(3.6, "te_spready", fgettext("Y spread"), t[4])
615 fields[#fields + 1] = "label[4," .. height - 0.2 .. ";" ..
616 fgettext("2D Noise") .. "]"
618 add_field(6.9, "te_spreadz", fgettext("Z spread"), t[5])
619 height = height + 1.1
622 add_field(0.3, "te_octaves", fgettext("Octaves"), t[7])
623 add_field(3.6, "te_persist", fgettext("Persistance"), t[8])
624 add_field(6.9, "te_lacun", fgettext("Lacunarity"), t[9])
625 height = height + 1.1
628 local enabled_flags = flags_to_table(t[10])
630 for _, name in ipairs(enabled_flags) do
631 -- Index by name, to avoid iterating over all enabled_flags for every possible flag.
634 for _, name in ipairs(setting.flags) do
635 local checkbox_name = "cb_" .. name
636 local is_enabled = flags[name] == true -- to get false if nil
637 checkboxes[checkbox_name] = is_enabled
640 formspec = table.concat(fields)
641 .. "checkbox[0.5," .. height - 0.6 .. ";cb_defaults;"
642 .. fgettext("defaults") .. ";" -- defaults
643 .. tostring(flags["defaults"] == true) .. "]" -- to get false if nil
644 .. "checkbox[5," .. height - 0.6 .. ";cb_eased;"
645 .. fgettext("eased") .. ";" -- eased
646 .. tostring(flags["eased"] == true) .. "]"
647 .. "checkbox[5," .. height - 0.15 .. ";cb_absvalue;"
648 .. fgettext("absvalue") .. ";" -- absvalue
649 .. tostring(flags["absvalue"] == true) .. "]"
652 elseif setting.type == "v3f" then
653 local val = get_current_value(setting)
655 for line in val:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
656 table.insert(v3f, line)
659 height = height + 0.3
661 .. "field[0.3," .. height .. ";3.3,1;te_x;"
662 .. fgettext("X") .. ";" -- X
663 .. core.formspec_escape(v3f[1] or "") .. "]"
664 .. "field[3.6," .. height .. ";3.3,1;te_y;"
665 .. fgettext("Y") .. ";" -- Y
666 .. core.formspec_escape(v3f[2] or "") .. "]"
667 .. "field[6.9," .. height .. ";3.3,1;te_z;"
668 .. fgettext("Z") .. ";" -- Z
669 .. core.formspec_escape(v3f[3] or "") .. "]"
670 height = height + 1.1
672 elseif setting.type == "flags" then
673 local current_flags = flags_to_table(get_current_value(setting))
675 for _, name in ipairs(current_flags) do
676 -- Index by name, to avoid iterating over all enabled_flags for every possible flag.
677 if name:sub(1, 2) == "no" then
678 flags[name:sub(3)] = false
683 local flags_count = #setting.possible / 2
684 local max_height = math.ceil(flags_count / 2) / 2
686 -- More space for flags
687 description_height = description_height - 1
690 local fields = {} -- To build formspec
692 for _, name in ipairs(setting.possible) do
693 if name:sub(1, 2) ~= "no" then
695 local y = height + j / 2 - 0.75
696 if j - 1 >= flags_count / 2 then -- 2nd column
701 local checkbox_name = "cb_" .. name
702 local is_enabled = flags[name] == true -- to get false if nil
703 checkboxes[checkbox_name] = is_enabled
705 fields[#fields + 1] = ("checkbox[%f,%f;%s;%s;%s]"):format(
706 x, y, checkbox_name, name, tostring(is_enabled)
710 formspec = table.concat(fields)
711 height = height + max_height + 0.25
714 -- TODO: fancy input for float, int
715 local text = get_current_value(setting)
716 if dialogdata.error_message and dialogdata.entered_text then
717 text = dialogdata.entered_text
719 formspec = "field[0.28," .. height + 0.15 .. ";" .. width .. ",1;te_setting_value;;"
720 .. core.formspec_escape(text) .. "]"
721 height = height + 1.15
724 -- Box good, textarea bad. Calculate textarea size from box.
725 local function create_textfield(size, label, text, bg_color)
730 h = size.h * 1.16 + 0.12
732 return ("box[%f,%f;%f,%f;%s]textarea[%f,%f;%f,%f;;%s;%s]"):format(
733 size.x, size.y, size.w, size.h, bg_color or "#000",
734 textarea.x, textarea.y, textarea.w, textarea.h,
735 core.formspec_escape(label), core.formspec_escape(text)
740 -- When there's an error: Shrink description textarea and add error below
741 if dialogdata.error_message then
744 y = description_height - 0.4,
748 formspec = formspec ..
749 create_textfield(error_box, "", dialogdata.error_message, "#600")
750 description_height = description_height - 0.75
753 -- Get description field
754 local description_box = {
758 h = description_height
761 local setting_name = setting.name
762 if setting.readable_name then
763 setting_name = fgettext_ne(setting.readable_name) ..
764 " (" .. setting.name .. ")"
768 if setting.comment == "" then
769 comment_text = fgettext_ne("(No description of setting given)")
771 comment_text = fgettext_ne(setting.comment)
775 "size[" .. width .. "," .. height + 0.25 .. ",true]" ..
776 create_textfield(description_box, setting_name, comment_text) ..
778 "button[" .. width / 2 - 2.5 .. "," .. height - 0.4 .. ";2.5,1;btn_done;" ..
779 fgettext("Save") .. "]" ..
780 "button[" .. width / 2 .. "," .. height - 0.4 .. ";2.5,1;btn_cancel;" ..
781 fgettext("Cancel") .. "]"
785 local function handle_change_setting_buttons(this, fields)
786 local setting = settings[selected_setting]
787 if fields["btn_done"] or fields["key_enter"] then
788 if setting.type == "bool" then
789 local new_value = fields["dd_setting_value"]
790 -- Note: new_value is the actual (translated) value shown in the dropdown
791 core.settings:set_bool(setting.name, new_value == fgettext("Enabled"))
793 elseif setting.type == "enum" then
794 local new_value = fields["dd_setting_value"]
795 core.settings:set(setting.name, new_value)
797 elseif setting.type == "int" then
798 local new_value = tonumber(fields["te_setting_value"])
799 if not new_value or math.floor(new_value) ~= new_value then
800 this.data.error_message = fgettext_ne("Please enter a valid integer.")
801 this.data.entered_text = fields["te_setting_value"]
802 core.update_formspec(this:get_formspec())
805 if setting.min and new_value < setting.min then
806 this.data.error_message = fgettext_ne("The value must be at least $1.", setting.min)
807 this.data.entered_text = fields["te_setting_value"]
808 core.update_formspec(this:get_formspec())
811 if setting.max and new_value > setting.max then
812 this.data.error_message = fgettext_ne("The value must not be larger than $1.", setting.max)
813 this.data.entered_text = fields["te_setting_value"]
814 core.update_formspec(this:get_formspec())
817 core.settings:set(setting.name, new_value)
819 elseif setting.type == "float" then
820 local new_value = tonumber(fields["te_setting_value"])
821 if not new_value then
822 this.data.error_message = fgettext_ne("Please enter a valid number.")
823 this.data.entered_text = fields["te_setting_value"]
824 core.update_formspec(this:get_formspec())
827 if setting.min and new_value < setting.min then
828 this.data.error_message = fgettext_ne("The value must be at least $1.", setting.min)
829 this.data.entered_text = fields["te_setting_value"]
830 core.update_formspec(this:get_formspec())
833 if setting.max and new_value > setting.max then
834 this.data.error_message = fgettext_ne("The value must not be larger than $1.", setting.max)
835 this.data.entered_text = fields["te_setting_value"]
836 core.update_formspec(this:get_formspec())
839 core.settings:set(setting.name, new_value)
841 elseif setting.type == "flags" then
843 for _, name in ipairs(setting.possible) do
844 if name:sub(1, 2) ~= "no" then
845 if checkboxes["cb_" .. name] then
846 table.insert(values, name)
848 table.insert(values, "no" .. name)
855 local new_value = table.concat(values, ", ")
856 core.settings:set(setting.name, new_value)
858 elseif setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
860 for _, name in ipairs(setting.flags) do
861 if checkboxes["cb_" .. name] then
862 table.insert(np_flags, name)
868 if setting.type == "noise_params_2d" then
869 fields["te_spready"] = fields["te_spreadz"]
872 offset = fields["te_offset"],
873 scale = fields["te_scale"],
875 x = fields["te_spreadx"],
876 y = fields["te_spready"],
877 z = fields["te_spreadz"]
879 seed = fields["te_seed"],
880 octaves = fields["te_octaves"],
881 persistence = fields["te_persist"],
882 lacunarity = fields["te_lacun"],
883 flags = table.concat(np_flags, ", ")
885 core.settings:set_np_group(setting.name, new_value)
887 elseif setting.type == "v3f" then
888 local new_value = "("
889 .. fields["te_x"] .. ", "
890 .. fields["te_y"] .. ", "
891 .. fields["te_z"] .. ")"
892 core.settings:set(setting.name, new_value)
895 local new_value = fields["te_setting_value"]
896 core.settings:set(setting.name, new_value)
898 core.settings:write()
903 if fields["btn_cancel"] then
908 if fields["btn_browser_path"] then
909 core.show_path_select_dialog("dlg_browse_path",
910 fgettext_ne("Select directory"), false)
913 if fields["btn_browser_filepath"] then
914 core.show_path_select_dialog("dlg_browse_path",
915 fgettext_ne("Select file"), true)
918 if fields["dlg_browse_path_accepted"] then
919 this.data.selected_path = fields["dlg_browse_path_accepted"]
920 core.update_formspec(this:get_formspec())
923 if setting.type == "flags"
924 or setting.type == "noise_params_2d"
925 or setting.type == "noise_params_3d" then
926 for name, value in pairs(fields) do
927 if name:sub(1, 3) == "cb_" then
928 checkboxes[name] = value == "true"
936 local function create_settings_formspec(tabview, _, tabdata)
937 local formspec = "size[12,5.4;true]" ..
938 "tablecolumns[color;tree;text,width=28;text]" ..
939 "tableoptions[background=#00000000;border=false]" ..
940 "field[0.3,0.1;10.2,1;search_string;;" .. core.formspec_escape(search_string) .. "]" ..
941 "field_close_on_enter[search_string;false]" ..
942 "button[10.2,-0.2;2,1;search;" .. fgettext("Search") .. "]" ..
943 "table[0,0.8;12,3.5;list_settings;"
945 local current_level = 0
946 for _, entry in ipairs(settings) do
948 if not core.settings:get_bool("main_menu_technical_settings") and entry.readable_name then
949 name = fgettext_ne(entry.readable_name)
954 if entry.type == "category" then
955 current_level = entry.level
956 formspec = formspec .. "#FFFF00," .. current_level .. "," .. fgettext(name) .. ",,"
958 elseif entry.type == "bool" then
959 local value = get_current_value(entry)
960 if core.is_yes(value) then
961 value = fgettext("Enabled")
963 value = fgettext("Disabled")
965 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
968 elseif entry.type == "key" then --luacheck: ignore
969 -- ignore key settings, since we have a special dialog for them
971 elseif entry.type == "noise_params_2d" or entry.type == "noise_params_3d" then
972 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
973 .. core.formspec_escape(get_current_np_group_as_string(entry)) .. ","
976 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
977 .. core.formspec_escape(get_current_value(entry)) .. ","
981 if #settings > 0 then
982 formspec = formspec:sub(1, -2) -- remove trailing comma
984 formspec = formspec .. ";" .. selected_setting .. "]" ..
985 "button[0,4.9;4,1;btn_back;".. fgettext("< Back to Settings page") .. "]" ..
986 "button[10,4.9;2,1;btn_edit;" .. fgettext("Edit") .. "]" ..
987 "button[7,4.9;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" ..
988 "checkbox[0,4.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";"
989 .. dump(core.settings:get_bool("main_menu_technical_settings")) .. "]"
994 local function handle_settings_buttons(this, fields, tabname, tabdata)
995 local list_enter = false
996 if fields["list_settings"] then
997 selected_setting = core.get_table_index("list_settings")
998 if core.explode_table_event(fields["list_settings"]).type == "DCL" then
999 -- Directly toggle booleans
1000 local setting = settings[selected_setting]
1001 if setting and setting.type == "bool" then
1002 local current_value = get_current_value(setting)
1003 core.settings:set_bool(setting.name, not core.is_yes(current_value))
1004 core.settings:write()
1014 if fields.search or fields.key_enter_field == "search_string" then
1015 if search_string == fields.search_string then
1016 if selected_setting > 0 then
1017 -- Go to next result on enter press
1018 local i = selected_setting + 1
1019 local looped = false
1020 while i > #settings or settings[i].type == "category" do
1022 if i > #settings then
1023 -- Stop infinte looping
1031 selected_setting = i
1032 core.update_formspec(this:get_formspec())
1036 -- Search for setting
1037 search_string = fields.search_string
1038 settings, selected_setting = filter_settings(full_settings, search_string)
1039 core.update_formspec(this:get_formspec())
1044 if fields["btn_edit"] or list_enter then
1045 local setting = settings[selected_setting]
1046 if setting and setting.type ~= "category" then
1047 local edit_dialog = dialog_create("change_setting",
1048 create_change_setting_formspec, handle_change_setting_buttons)
1049 edit_dialog:set_parent(this)
1056 if fields["btn_restore"] then
1057 local setting = settings[selected_setting]
1058 if setting and setting.type ~= "category" then
1059 core.settings:remove(setting.name)
1060 core.settings:write()
1061 core.update_formspec(this:get_formspec())
1066 if fields["btn_back"] then
1071 if fields["cb_tech_settings"] then
1072 core.settings:set("main_menu_technical_settings", fields["cb_tech_settings"])
1073 core.settings:write()
1074 core.update_formspec(this:get_formspec())
1081 function create_adv_settings_dlg()
1082 local dlg = dialog_create("settings_advanced",
1083 create_settings_formspec,
1084 handle_settings_buttons,
1090 -- Uncomment to generate 'minetest.conf.example' and 'settings_translation_file.cpp'.
1091 -- For RUN_IN_PLACE the generated files may appear in the 'bin' folder.
1092 -- See comment and alternative line at the end of 'generate_from_settingtypes.lua'.
1094 --assert(loadfile(core.get_builtin_path().."mainmenu"..DIR_DELIM..
1095 -- "generate_from_settingtypes.lua"))(parse_config_file(true, false))