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 --[[~ "defaults" is a noise parameter flag.
643 It describes the default processing options
644 for noise settings in main menu -> "All Settings". ]]
645 .. fgettext("defaults") .. ";" -- defaults
646 .. tostring(flags["defaults"] == true) .. "]" -- to get false if nil
647 .. "checkbox[5," .. height - 0.6 .. ";cb_eased;"
648 --[[~ "eased" is a noise parameter flag.
649 It is used to make the map smoother and
650 can be enabled in noise settings in
651 main menu -> "All Settings". ]]
652 .. fgettext("eased") .. ";" -- eased
653 .. tostring(flags["eased"] == true) .. "]"
654 .. "checkbox[5," .. height - 0.15 .. ";cb_absvalue;"
655 --[[~ "absvalue" is a noise parameter flag.
656 It is short for "absolute value".
657 It can be enabled in noise settings in
658 main menu -> "All Settings". ]]
659 .. fgettext("absvalue") .. ";" -- absvalue
660 .. tostring(flags["absvalue"] == true) .. "]"
663 elseif setting.type == "v3f" then
664 local val = get_current_value(setting)
666 for line in val:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
667 table.insert(v3f, line)
670 height = height + 0.3
672 .. "field[0.3," .. height .. ";3.3,1;te_x;"
673 .. fgettext("X") .. ";" -- X
674 .. core.formspec_escape(v3f[1] or "") .. "]"
675 .. "field[3.6," .. height .. ";3.3,1;te_y;"
676 .. fgettext("Y") .. ";" -- Y
677 .. core.formspec_escape(v3f[2] or "") .. "]"
678 .. "field[6.9," .. height .. ";3.3,1;te_z;"
679 .. fgettext("Z") .. ";" -- Z
680 .. core.formspec_escape(v3f[3] or "") .. "]"
681 height = height + 1.1
683 elseif setting.type == "flags" then
684 local current_flags = flags_to_table(get_current_value(setting))
686 for _, name in ipairs(current_flags) do
687 -- Index by name, to avoid iterating over all enabled_flags for every possible flag.
688 if name:sub(1, 2) == "no" then
689 flags[name:sub(3)] = false
694 local flags_count = #setting.possible / 2
695 local max_height = math.ceil(flags_count / 2) / 2
697 -- More space for flags
698 description_height = description_height - 1
701 local fields = {} -- To build formspec
703 for _, name in ipairs(setting.possible) do
704 if name:sub(1, 2) ~= "no" then
706 local y = height + j / 2 - 0.75
707 if j - 1 >= flags_count / 2 then -- 2nd column
712 local checkbox_name = "cb_" .. name
713 local is_enabled = flags[name] == true -- to get false if nil
714 checkboxes[checkbox_name] = is_enabled
716 fields[#fields + 1] = ("checkbox[%f,%f;%s;%s;%s]"):format(
717 x, y, checkbox_name, name, tostring(is_enabled)
721 formspec = table.concat(fields)
722 height = height + max_height + 0.25
725 -- TODO: fancy input for float, int
726 local text = get_current_value(setting)
727 if dialogdata.error_message and dialogdata.entered_text then
728 text = dialogdata.entered_text
730 formspec = "field[0.28," .. height + 0.15 .. ";" .. width .. ",1;te_setting_value;;"
731 .. core.formspec_escape(text) .. "]"
732 height = height + 1.15
735 -- Box good, textarea bad. Calculate textarea size from box.
736 local function create_textfield(size, label, text, bg_color)
741 h = size.h * 1.16 + 0.12
743 return ("box[%f,%f;%f,%f;%s]textarea[%f,%f;%f,%f;;%s;%s]"):format(
744 size.x, size.y, size.w, size.h, bg_color or "#000",
745 textarea.x, textarea.y, textarea.w, textarea.h,
746 core.formspec_escape(label), core.formspec_escape(text)
751 -- When there's an error: Shrink description textarea and add error below
752 if dialogdata.error_message then
755 y = description_height - 0.4,
759 formspec = formspec ..
760 create_textfield(error_box, "", dialogdata.error_message, "#600")
761 description_height = description_height - 0.75
764 -- Get description field
765 local description_box = {
769 h = description_height
772 local setting_name = setting.name
773 if setting.readable_name then
774 setting_name = fgettext_ne(setting.readable_name) ..
775 " (" .. setting.name .. ")"
779 if setting.comment == "" then
780 comment_text = fgettext_ne("(No description of setting given)")
782 comment_text = fgettext_ne(setting.comment)
786 "size[" .. width .. "," .. height + 0.25 .. ",true]" ..
787 create_textfield(description_box, setting_name, comment_text) ..
789 "button[" .. width / 2 - 2.5 .. "," .. height - 0.4 .. ";2.5,1;btn_done;" ..
790 fgettext("Save") .. "]" ..
791 "button[" .. width / 2 .. "," .. height - 0.4 .. ";2.5,1;btn_cancel;" ..
792 fgettext("Cancel") .. "]"
796 local function handle_change_setting_buttons(this, fields)
797 local setting = settings[selected_setting]
798 if fields["btn_done"] or fields["key_enter"] then
799 if setting.type == "bool" then
800 local new_value = fields["dd_setting_value"]
801 -- Note: new_value is the actual (translated) value shown in the dropdown
802 core.settings:set_bool(setting.name, new_value == fgettext("Enabled"))
804 elseif setting.type == "enum" then
805 local new_value = fields["dd_setting_value"]
806 core.settings:set(setting.name, new_value)
808 elseif setting.type == "int" then
809 local new_value = tonumber(fields["te_setting_value"])
810 if not new_value or math.floor(new_value) ~= new_value then
811 this.data.error_message = fgettext_ne("Please enter a valid integer.")
812 this.data.entered_text = fields["te_setting_value"]
813 core.update_formspec(this:get_formspec())
816 if setting.min and new_value < setting.min then
817 this.data.error_message = fgettext_ne("The value must be at least $1.", setting.min)
818 this.data.entered_text = fields["te_setting_value"]
819 core.update_formspec(this:get_formspec())
822 if setting.max and new_value > setting.max then
823 this.data.error_message = fgettext_ne("The value must not be larger than $1.", setting.max)
824 this.data.entered_text = fields["te_setting_value"]
825 core.update_formspec(this:get_formspec())
828 core.settings:set(setting.name, new_value)
830 elseif setting.type == "float" then
831 local new_value = tonumber(fields["te_setting_value"])
832 if not new_value then
833 this.data.error_message = fgettext_ne("Please enter a valid number.")
834 this.data.entered_text = fields["te_setting_value"]
835 core.update_formspec(this:get_formspec())
838 if setting.min and new_value < setting.min then
839 this.data.error_message = fgettext_ne("The value must be at least $1.", setting.min)
840 this.data.entered_text = fields["te_setting_value"]
841 core.update_formspec(this:get_formspec())
844 if setting.max and new_value > setting.max then
845 this.data.error_message = fgettext_ne("The value must not be larger than $1.", setting.max)
846 this.data.entered_text = fields["te_setting_value"]
847 core.update_formspec(this:get_formspec())
850 core.settings:set(setting.name, new_value)
852 elseif setting.type == "flags" then
854 for _, name in ipairs(setting.possible) do
855 if name:sub(1, 2) ~= "no" then
856 if checkboxes["cb_" .. name] then
857 table.insert(values, name)
859 table.insert(values, "no" .. name)
866 local new_value = table.concat(values, ", ")
867 core.settings:set(setting.name, new_value)
869 elseif setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
871 for _, name in ipairs(setting.flags) do
872 if checkboxes["cb_" .. name] then
873 table.insert(np_flags, name)
879 if setting.type == "noise_params_2d" then
880 fields["te_spready"] = fields["te_spreadz"]
883 offset = fields["te_offset"],
884 scale = fields["te_scale"],
886 x = fields["te_spreadx"],
887 y = fields["te_spready"],
888 z = fields["te_spreadz"]
890 seed = fields["te_seed"],
891 octaves = fields["te_octaves"],
892 persistence = fields["te_persist"],
893 lacunarity = fields["te_lacun"],
894 flags = table.concat(np_flags, ", ")
896 core.settings:set_np_group(setting.name, new_value)
898 elseif setting.type == "v3f" then
899 local new_value = "("
900 .. fields["te_x"] .. ", "
901 .. fields["te_y"] .. ", "
902 .. fields["te_z"] .. ")"
903 core.settings:set(setting.name, new_value)
906 local new_value = fields["te_setting_value"]
907 core.settings:set(setting.name, new_value)
909 core.settings:write()
914 if fields["btn_cancel"] then
919 if fields["btn_browser_path"] then
920 core.show_path_select_dialog("dlg_browse_path",
921 fgettext_ne("Select directory"), false)
924 if fields["btn_browser_filepath"] then
925 core.show_path_select_dialog("dlg_browse_path",
926 fgettext_ne("Select file"), true)
929 if fields["dlg_browse_path_accepted"] then
930 this.data.selected_path = fields["dlg_browse_path_accepted"]
931 core.update_formspec(this:get_formspec())
934 if setting.type == "flags"
935 or setting.type == "noise_params_2d"
936 or setting.type == "noise_params_3d" then
937 for name, value in pairs(fields) do
938 if name:sub(1, 3) == "cb_" then
939 checkboxes[name] = value == "true"
947 local function create_settings_formspec(tabview, _, tabdata)
948 local formspec = "size[12,5.4;true]" ..
949 "tablecolumns[color;tree;text,width=28;text]" ..
950 "tableoptions[background=#00000000;border=false]" ..
951 "field[0.3,0.1;10.2,1;search_string;;" .. core.formspec_escape(search_string) .. "]" ..
952 "field_close_on_enter[search_string;false]" ..
953 "button[10.2,-0.2;2,1;search;" .. fgettext("Search") .. "]" ..
954 "table[0,0.8;12,3.5;list_settings;"
956 local current_level = 0
957 for _, entry in ipairs(settings) do
959 if not core.settings:get_bool("main_menu_technical_settings") and entry.readable_name then
960 name = fgettext_ne(entry.readable_name)
965 if entry.type == "category" then
966 current_level = entry.level
967 formspec = formspec .. "#FFFF00," .. current_level .. "," .. fgettext(name) .. ",,"
969 elseif entry.type == "bool" then
970 local value = get_current_value(entry)
971 if core.is_yes(value) then
972 value = fgettext("Enabled")
974 value = fgettext("Disabled")
976 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
979 elseif entry.type == "key" then --luacheck: ignore
980 -- ignore key settings, since we have a special dialog for them
982 elseif entry.type == "noise_params_2d" or entry.type == "noise_params_3d" then
983 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
984 .. core.formspec_escape(get_current_np_group_as_string(entry)) .. ","
987 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
988 .. core.formspec_escape(get_current_value(entry)) .. ","
992 if #settings > 0 then
993 formspec = formspec:sub(1, -2) -- remove trailing comma
995 formspec = formspec .. ";" .. selected_setting .. "]" ..
996 "button[0,4.9;4,1;btn_back;".. fgettext("< Back to Settings page") .. "]" ..
997 "button[10,4.9;2,1;btn_edit;" .. fgettext("Edit") .. "]" ..
998 "button[7,4.9;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" ..
999 "checkbox[0,4.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";"
1000 .. dump(core.settings:get_bool("main_menu_technical_settings")) .. "]"
1005 local function handle_settings_buttons(this, fields, tabname, tabdata)
1006 local list_enter = false
1007 if fields["list_settings"] then
1008 selected_setting = core.get_table_index("list_settings")
1009 if core.explode_table_event(fields["list_settings"]).type == "DCL" then
1010 -- Directly toggle booleans
1011 local setting = settings[selected_setting]
1012 if setting and setting.type == "bool" then
1013 local current_value = get_current_value(setting)
1014 core.settings:set_bool(setting.name, not core.is_yes(current_value))
1015 core.settings:write()
1025 if fields.search or fields.key_enter_field == "search_string" then
1026 if search_string == fields.search_string then
1027 if selected_setting > 0 then
1028 -- Go to next result on enter press
1029 local i = selected_setting + 1
1030 local looped = false
1031 while i > #settings or settings[i].type == "category" do
1033 if i > #settings then
1034 -- Stop infinte looping
1042 selected_setting = i
1043 core.update_formspec(this:get_formspec())
1047 -- Search for setting
1048 search_string = fields.search_string
1049 settings, selected_setting = filter_settings(full_settings, search_string)
1050 core.update_formspec(this:get_formspec())
1055 if fields["btn_edit"] or list_enter then
1056 local setting = settings[selected_setting]
1057 if setting and setting.type ~= "category" then
1058 local edit_dialog = dialog_create("change_setting",
1059 create_change_setting_formspec, handle_change_setting_buttons)
1060 edit_dialog:set_parent(this)
1067 if fields["btn_restore"] then
1068 local setting = settings[selected_setting]
1069 if setting and setting.type ~= "category" then
1070 core.settings:remove(setting.name)
1071 core.settings:write()
1072 core.update_formspec(this:get_formspec())
1077 if fields["btn_back"] then
1082 if fields["cb_tech_settings"] then
1083 core.settings:set("main_menu_technical_settings", fields["cb_tech_settings"])
1084 core.settings:write()
1085 core.update_formspec(this:get_formspec())
1092 function create_adv_settings_dlg()
1093 local dlg = dialog_create("settings_advanced",
1094 create_settings_formspec,
1095 handle_settings_buttons,
1101 -- Uncomment to generate 'minetest.conf.example' and 'settings_translation_file.cpp'.
1102 -- For RUN_IN_PLACE the generated files may appear in the 'bin' folder.
1103 -- See comment and alternative line at the end of 'generate_from_settingtypes.lua'.
1105 --assert(loadfile(core.get_builtin_path().."mainmenu"..DIR_DELIM..
1106 -- "generate_from_settingtypes.lua"))(parse_config_file(true, false))