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 line in default:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
152 index = default:find("[+-]?[%d.-e]+", index) + line:len()
153 table.insert(values, line)
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)
325 local builtin_path = core.get_builtin_path() .. FILENAME
326 local file = io.open(builtin_path, "r")
329 core.log("error", "Can't load " .. FILENAME)
333 parse_single_file(file, builtin_path, read_all, settings, 0, true)
339 local games_category_initialized = false
341 local game = pkgmgr.get_game(index)
343 local path = game.path .. DIR_DELIM .. FILENAME
344 local file = io.open(path, "r")
346 if not games_category_initialized then
347 local translation = fgettext_ne("Games"), -- not used, but needed for xgettext
348 table.insert(settings, {
353 games_category_initialized = true
356 table.insert(settings, {
362 parse_single_file(file, path, read_all, settings, 2, false)
368 game = pkgmgr.get_game(index)
372 local mods_category_initialized = false
374 get_mods(core.get_modpath(), mods)
375 for _, mod in ipairs(mods) do
376 local path = mod.path .. DIR_DELIM .. FILENAME
377 local file = io.open(path, "r")
379 if not mods_category_initialized then
380 local translation = fgettext_ne("Mods"), -- not used, but needed for xgettext
381 table.insert(settings, {
386 mods_category_initialized = true
389 table.insert(settings, {
395 parse_single_file(file, path, read_all, settings, 2, false)
405 local function filter_settings(settings, searchstring)
406 if not searchstring or searchstring == "" then
410 -- Setup the keyword list
412 for word in searchstring:lower():gmatch("%S+") do
413 table.insert(keywords, word)
417 local category_stack = {}
418 local current_level = 0
419 local best_setting = nil
420 for _, entry in pairs(settings) do
421 if entry.type == "category" then
422 -- Remove all settingless categories
423 while #category_stack > 0 and entry.level <= current_level do
424 table.remove(category_stack, #category_stack)
425 if #category_stack > 0 then
426 current_level = category_stack[#category_stack].level
432 -- Push category onto stack
433 category_stack[#category_stack + 1] = entry
434 current_level = entry.level
436 -- See if setting matches keywords
437 local setting_score = 0
438 for k = 1, #keywords do
439 local keyword = keywords[k]
441 if string.find(entry.name:lower(), keyword, 1, true) then
442 setting_score = setting_score + 1
445 if entry.readable_name and
446 string.find(fgettext(entry.readable_name):lower(), keyword, 1, true) then
447 setting_score = setting_score + 1
451 string.find(fgettext_ne(entry.comment):lower(), keyword, 1, true) then
452 setting_score = setting_score + 1
456 -- Add setting to results if match
457 if setting_score > 0 then
458 -- Add parent categories
459 for _, category in pairs(category_stack) do
460 result[#result + 1] = category
465 result[#result + 1] = entry
466 entry.score = setting_score
468 if not best_setting or
469 setting_score > result[best_setting].score then
470 best_setting = #result
475 return result, best_setting or -1
478 local full_settings = parse_config_file(false, true)
479 local search_string = ""
480 local settings = full_settings
481 local selected_setting = 1
483 local function get_current_value(setting)
484 local value = core.settings:get(setting.name)
486 value = setting.default
491 local function get_current_np_group(setting)
492 local value = core.settings:get_np_group(setting.name)
497 table.insert(t, value.offset)
498 table.insert(t, value.scale)
499 table.insert(t, value.spread.x)
500 table.insert(t, value.spread.y)
501 table.insert(t, value.spread.z)
502 table.insert(t, value.seed)
503 table.insert(t, value.octaves)
504 table.insert(t, value.persistence)
505 table.insert(t, value.lacunarity)
506 table.insert(t, value.flags)
511 local function get_current_np_group_as_string(setting)
512 local value = core.settings:get_np_group(setting.name)
517 t = value.offset .. ", " ..
518 value.scale .. ", (" ..
519 value.spread.x .. ", " ..
520 value.spread.y .. ", " ..
521 value.spread.z .. "), " ..
522 value.seed .. ", " ..
523 value.octaves .. ", " ..
524 value.persistence .. ", " ..
526 if value.flags ~= "" then
527 t = t .. ", " .. value.flags
533 local checkboxes = {} -- handle checkboxes events
535 local function create_change_setting_formspec(dialogdata)
536 local setting = settings[selected_setting]
537 -- Final formspec will be created at the end of this function
538 -- Default values below, may be changed depending on setting type
541 local description_height = 3
544 -- Setting-specific formspec elements
545 if setting.type == "bool" then
546 local selected_index = 1
547 if core.is_yes(get_current_value(setting)) then
550 formspec = "dropdown[3," .. height .. ";4,1;dd_setting_value;"
551 .. fgettext("Disabled") .. "," .. fgettext("Enabled") .. ";"
552 .. selected_index .. "]"
553 height = height + 1.25
555 elseif setting.type == "enum" then
556 local selected_index = 0
557 formspec = "dropdown[3," .. height .. ";4,1;dd_setting_value;"
558 for index, value in ipairs(setting.values) do
559 -- translating value is not possible, since it's the value
560 -- that we set the setting to
561 formspec = formspec .. core.formspec_escape(value) .. ","
562 if get_current_value(setting) == value then
563 selected_index = index
566 if #setting.values > 0 then
567 formspec = formspec:sub(1, -2) -- remove trailing comma
569 formspec = formspec .. ";" .. selected_index .. "]"
570 height = height + 1.25
572 elseif setting.type == "path" or setting.type == "filepath" then
573 local current_value = dialogdata.selected_path
574 if not current_value then
575 current_value = get_current_value(setting)
577 formspec = "field[0.28," .. height + 0.15 .. ";8,1;te_setting_value;;"
578 .. core.formspec_escape(current_value) .. "]"
579 .. "button[8," .. height - 0.15 .. ";2,1;btn_browser_"
580 .. setting.type .. ";" .. fgettext("Browse") .. "]"
581 height = height + 1.15
583 elseif setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
584 local t = get_current_np_group(setting)
586 if setting.type == "noise_params_2d" then
590 -- More space for 3x3 fields
591 description_height = description_height - 1.5
592 height = height - 1.5
595 local function add_field(x, name, label, value)
596 fields[#fields + 1] = ("field[%f,%f;3.3,1;%s;%s;%s]"):format(
597 x, height, name, label, core.formspec_escape(value or "")
601 height = height + 0.3
602 add_field(0.3, "te_offset", fgettext("Offset"), t[1])
603 add_field(3.6, "te_scale", fgettext("Scale"), t[2])
604 add_field(6.9, "te_seed", fgettext("Seed"), t[6])
605 height = height + 1.1
608 add_field(0.3, "te_spreadx", fgettext("X spread"), t[3])
609 if dimension == 3 then
610 add_field(3.6, "te_spready", fgettext("Y spread"), t[4])
612 fields[#fields + 1] = "label[4," .. height - 0.2 .. ";" ..
613 fgettext("2D Noise") .. "]"
615 add_field(6.9, "te_spreadz", fgettext("Z spread"), t[5])
616 height = height + 1.1
619 add_field(0.3, "te_octaves", fgettext("Octaves"), t[7])
620 add_field(3.6, "te_persist", fgettext("Persistance"), t[8])
621 add_field(6.9, "te_lacun", fgettext("Lacunarity"), t[9])
622 height = height + 1.1
625 local enabled_flags = flags_to_table(t[10])
627 for _, name in ipairs(enabled_flags) do
628 -- Index by name, to avoid iterating over all enabled_flags for every possible flag.
631 for _, name in ipairs(setting.flags) do
632 local checkbox_name = "cb_" .. name
633 local is_enabled = flags[name] == true -- to get false if nil
634 checkboxes[checkbox_name] = is_enabled
637 formspec = table.concat(fields)
638 .. "checkbox[0.5," .. height - 0.6 .. ";cb_defaults;"
639 .. fgettext("defaults") .. ";" -- defaults
640 .. tostring(flags["defaults"] == true) .. "]" -- to get false if nil
641 .. "checkbox[5," .. height - 0.6 .. ";cb_eased;"
642 .. fgettext("eased") .. ";" -- eased
643 .. tostring(flags["eased"] == true) .. "]"
644 .. "checkbox[5," .. height - 0.15 .. ";cb_absvalue;"
645 .. fgettext("absvalue") .. ";" -- absvalue
646 .. tostring(flags["absvalue"] == true) .. "]"
649 elseif setting.type == "v3f" then
650 local val = get_current_value(setting)
652 for line in val:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
653 table.insert(v3f, line)
656 height = height + 0.3
658 .. "field[0.3," .. height .. ";3.3,1;te_x;"
659 .. fgettext("X") .. ";" -- X
660 .. core.formspec_escape(v3f[1] or "") .. "]"
661 .. "field[3.6," .. height .. ";3.3,1;te_y;"
662 .. fgettext("Y") .. ";" -- Y
663 .. core.formspec_escape(v3f[2] or "") .. "]"
664 .. "field[6.9," .. height .. ";3.3,1;te_z;"
665 .. fgettext("Z") .. ";" -- Z
666 .. core.formspec_escape(v3f[3] or "") .. "]"
667 height = height + 1.1
669 elseif setting.type == "flags" then
670 local enabled_flags = flags_to_table(get_current_value(setting))
672 for _, name in ipairs(enabled_flags) do
673 -- Index by name, to avoid iterating over all enabled_flags for every possible flag.
676 local flags_count = #setting.possible
677 local max_height = flags_count / 4
679 -- More space for flags
680 description_height = description_height - 1
683 local fields = {} -- To build formspec
684 for i, name in ipairs(setting.possible) do
686 local y = height + i / 2 - 0.75
687 if i - 1 >= flags_count / 2 then -- 2nd column
691 local checkbox_name = "cb_" .. name
692 local is_enabled = flags[name] == true -- to get false if nil
693 checkboxes[checkbox_name] = is_enabled
695 fields[#fields + 1] = ("checkbox[%f,%f;%s;%s;%s]"):format(
696 x, y, checkbox_name, name, tostring(is_enabled)
699 formspec = table.concat(fields)
700 height = height + max_height + 0.25
703 -- TODO: fancy input for float, int
704 local text = get_current_value(setting)
705 if dialogdata.error_message and dialogdata.entered_text then
706 text = dialogdata.entered_text
708 formspec = "field[0.28," .. height + 0.15 .. ";" .. width .. ",1;te_setting_value;;"
709 .. core.formspec_escape(text) .. "]"
710 height = height + 1.15
713 -- Box good, textarea bad. Calculate textarea size from box.
714 local function create_textfield(size, label, text, bg_color)
719 h = size.h * 1.16 + 0.12
721 return ("box[%f,%f;%f,%f;%s]textarea[%f,%f;%f,%f;;%s;%s]"):format(
722 size.x, size.y, size.w, size.h, bg_color or "#000",
723 textarea.x, textarea.y, textarea.w, textarea.h,
724 core.formspec_escape(label), core.formspec_escape(text)
729 -- When there's an error: Shrink description textarea and add error below
730 if dialogdata.error_message then
733 y = description_height - 0.4,
737 formspec = formspec ..
738 create_textfield(error_box, "", dialogdata.error_message, "#600")
739 description_height = description_height - 0.75
742 -- Get description field
743 local description_box = {
747 h = description_height
750 local setting_name = setting.name
751 if setting.readable_name then
752 setting_name = fgettext_ne(setting.readable_name) ..
753 " (" .. setting.name .. ")"
756 local comment_text = ""
757 if setting.comment == "" then
758 comment_text = fgettext_ne("(No description of setting given)")
760 comment_text = fgettext_ne(setting.comment)
764 "size[" .. width .. "," .. height + 0.25 .. ",true]" ..
765 create_textfield(description_box, setting_name, comment_text) ..
767 "button[" .. width / 2 - 2.5 .. "," .. height - 0.4 .. ";2.5,1;btn_done;" ..
768 fgettext("Save") .. "]" ..
769 "button[" .. width / 2 .. "," .. height - 0.4 .. ";2.5,1;btn_cancel;" ..
770 fgettext("Cancel") .. "]"
774 local function handle_change_setting_buttons(this, fields)
775 local setting = settings[selected_setting]
776 if fields["btn_done"] or fields["key_enter"] then
777 if setting.type == "bool" then
778 local new_value = fields["dd_setting_value"]
779 -- Note: new_value is the actual (translated) value shown in the dropdown
780 core.settings:set_bool(setting.name, new_value == fgettext("Enabled"))
782 elseif setting.type == "enum" then
783 local new_value = fields["dd_setting_value"]
784 core.settings:set(setting.name, new_value)
786 elseif setting.type == "int" then
787 local new_value = tonumber(fields["te_setting_value"])
788 if not new_value or math.floor(new_value) ~= new_value then
789 this.data.error_message = fgettext_ne("Please enter a valid integer.")
790 this.data.entered_text = fields["te_setting_value"]
791 core.update_formspec(this:get_formspec())
794 if setting.min and new_value < setting.min then
795 this.data.error_message = fgettext_ne("The value must be at least $1.", setting.min)
796 this.data.entered_text = fields["te_setting_value"]
797 core.update_formspec(this:get_formspec())
800 if setting.max and new_value > setting.max then
801 this.data.error_message = fgettext_ne("The value must not be larger than $1.", setting.max)
802 this.data.entered_text = fields["te_setting_value"]
803 core.update_formspec(this:get_formspec())
806 core.settings:set(setting.name, new_value)
808 elseif setting.type == "float" then
809 local new_value = tonumber(fields["te_setting_value"])
810 if not new_value then
811 this.data.error_message = fgettext_ne("Please enter a valid number.")
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 == "flags" then
832 for _, name in ipairs(setting.possible) do
833 if checkboxes["cb_" .. name] then
834 table.insert(values, name)
840 local new_value = table.concat(values, ", ")
841 core.settings:set(setting.name, new_value)
843 elseif setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
845 for _, name in ipairs(setting.flags) do
846 if checkboxes["cb_" .. name] then
847 table.insert(np_flags, name)
853 if setting.type == "noise_params_2d" then
854 fields["te_spready"] = fields["te_spreadz"]
857 offset = fields["te_offset"],
858 scale = fields["te_scale"],
860 x = fields["te_spreadx"],
861 y = fields["te_spready"],
862 z = fields["te_spreadz"]
864 seed = fields["te_seed"],
865 octaves = fields["te_octaves"],
866 persistence = fields["te_persist"],
867 lacunarity = fields["te_lacun"],
868 flags = table.concat(np_flags, ", ")
870 core.settings:set_np_group(setting.name, new_value)
872 elseif setting.type == "v3f" then
873 local new_value = "("
874 .. fields["te_x"] .. ", "
875 .. fields["te_y"] .. ", "
876 .. fields["te_z"] .. ")"
877 core.settings:set(setting.name, new_value)
880 local new_value = fields["te_setting_value"]
881 core.settings:set(setting.name, new_value)
883 core.settings:write()
888 if fields["btn_cancel"] then
893 if fields["btn_browser_path"] then
894 core.show_path_select_dialog("dlg_browse_path",
895 fgettext_ne("Select directory"), false)
898 if fields["btn_browser_filepath"] then
899 core.show_path_select_dialog("dlg_browse_path",
900 fgettext_ne("Select file"), true)
903 if fields["dlg_browse_path_accepted"] then
904 this.data.selected_path = fields["dlg_browse_path_accepted"]
905 core.update_formspec(this:get_formspec())
908 if setting.type == "flags"
909 or setting.type == "noise_params_2d"
910 or setting.type == "noise_params_3d" then
911 for name, value in pairs(fields) do
912 if name:sub(1, 3) == "cb_" then
913 checkboxes[name] = value == "true"
921 local function create_settings_formspec(tabview, name, tabdata)
922 local formspec = "size[12,5.4;true]" ..
923 "tablecolumns[color;tree;text,width=28;text]" ..
924 "tableoptions[background=#00000000;border=false]" ..
925 "field[0.3,0.1;10.2,1;search_string;;" .. core.formspec_escape(search_string) .. "]" ..
926 "field_close_on_enter[search_string;false]" ..
927 "button[10.2,-0.2;2,1;search;" .. fgettext("Search") .. "]" ..
928 "table[0,0.8;12,3.5;list_settings;"
930 local current_level = 0
931 for _, entry in ipairs(settings) do
933 if not core.settings:get_bool("main_menu_technical_settings") and entry.readable_name then
934 name = fgettext_ne(entry.readable_name)
939 if entry.type == "category" then
940 current_level = entry.level
941 formspec = formspec .. "#FFFF00," .. current_level .. "," .. fgettext(name) .. ",,"
943 elseif entry.type == "bool" then
944 local value = get_current_value(entry)
945 if core.is_yes(value) then
946 value = fgettext("Enabled")
948 value = fgettext("Disabled")
950 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
953 elseif entry.type == "key" then
954 -- ignore key settings, since we have a special dialog for them
956 elseif entry.type == "noise_params_2d" or entry.type == "noise_params_3d" then
957 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
958 .. core.formspec_escape(get_current_np_group_as_string(entry)) .. ","
961 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
962 .. core.formspec_escape(get_current_value(entry)) .. ","
966 if #settings > 0 then
967 formspec = formspec:sub(1, -2) -- remove trailing comma
969 formspec = formspec .. ";" .. selected_setting .. "]" ..
970 "button[0,4.9;4,1;btn_back;".. fgettext("< Back to Settings page") .. "]" ..
971 "button[10,4.9;2,1;btn_edit;" .. fgettext("Edit") .. "]" ..
972 "button[7,4.9;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" ..
973 "checkbox[0,4.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";"
974 .. dump(core.settings:get_bool("main_menu_technical_settings")) .. "]"
979 local function handle_settings_buttons(this, fields, tabname, tabdata)
980 local list_enter = false
981 if fields["list_settings"] then
982 selected_setting = core.get_table_index("list_settings")
983 if core.explode_table_event(fields["list_settings"]).type == "DCL" then
984 -- Directly toggle booleans
985 local setting = settings[selected_setting]
986 if setting and setting.type == "bool" then
987 local current_value = get_current_value(setting)
988 core.settings:set_bool(setting.name, not core.is_yes(current_value))
989 core.settings:write()
999 if fields.search or fields.key_enter_field == "search_string" then
1000 if search_string == fields.search_string then
1001 if selected_setting > 0 then
1002 -- Go to next result on enter press
1003 local i = selected_setting + 1
1004 local looped = false
1005 while i > #settings or settings[i].type == "category" do
1007 if i > #settings then
1008 -- Stop infinte looping
1016 selected_setting = i
1017 core.update_formspec(this:get_formspec())
1021 -- Search for setting
1022 search_string = fields.search_string
1023 settings, selected_setting = filter_settings(full_settings, search_string)
1024 core.update_formspec(this:get_formspec())
1029 if fields["btn_edit"] or list_enter then
1030 local setting = settings[selected_setting]
1031 if setting and setting.type ~= "category" then
1032 local edit_dialog = dialog_create("change_setting", create_change_setting_formspec,
1033 handle_change_setting_buttons)
1034 edit_dialog:set_parent(this)
1041 if fields["btn_restore"] then
1042 local setting = settings[selected_setting]
1043 if setting and setting.type ~= "category" then
1044 core.settings:remove(setting.name)
1045 core.settings:write()
1046 core.update_formspec(this:get_formspec())
1051 if fields["btn_back"] then
1056 if fields["cb_tech_settings"] then
1057 core.settings:set("main_menu_technical_settings", fields["cb_tech_settings"])
1058 core.settings:write()
1059 core.update_formspec(this:get_formspec())
1066 function create_adv_settings_dlg()
1067 local dlg = dialog_create("settings_advanced",
1068 create_settings_formspec,
1069 handle_settings_buttons,
1075 -- Uncomment to generate minetest.conf.example and settings_translation_file.cpp
1076 -- For RUN_IN_PLACE the generated files may appear in the bin folder
1078 --assert(loadfile(core.get_builtin_path().."mainmenu"..DIR_DELIM.."generate_from_settingtypes.lua"))(parse_config_file(true, false))