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 enabled_flags = flags_to_table(get_current_value(setting))
675 for _, name in ipairs(enabled_flags) do
676 -- Index by name, to avoid iterating over all enabled_flags for every possible flag.
679 local flags_count = #setting.possible
680 local max_height = flags_count / 4
682 -- More space for flags
683 description_height = description_height - 1
686 local fields = {} -- To build formspec
687 for i, name in ipairs(setting.possible) do
689 local y = height + i / 2 - 0.75
690 if i - 1 >= flags_count / 2 then -- 2nd column
694 local checkbox_name = "cb_" .. name
695 local is_enabled = flags[name] == true -- to get false if nil
696 checkboxes[checkbox_name] = is_enabled
698 fields[#fields + 1] = ("checkbox[%f,%f;%s;%s;%s]"):format(
699 x, y, checkbox_name, name, tostring(is_enabled)
702 formspec = table.concat(fields)
703 height = height + max_height + 0.25
706 -- TODO: fancy input for float, int
707 local text = get_current_value(setting)
708 if dialogdata.error_message and dialogdata.entered_text then
709 text = dialogdata.entered_text
711 formspec = "field[0.28," .. height + 0.15 .. ";" .. width .. ",1;te_setting_value;;"
712 .. core.formspec_escape(text) .. "]"
713 height = height + 1.15
716 -- Box good, textarea bad. Calculate textarea size from box.
717 local function create_textfield(size, label, text, bg_color)
722 h = size.h * 1.16 + 0.12
724 return ("box[%f,%f;%f,%f;%s]textarea[%f,%f;%f,%f;;%s;%s]"):format(
725 size.x, size.y, size.w, size.h, bg_color or "#000",
726 textarea.x, textarea.y, textarea.w, textarea.h,
727 core.formspec_escape(label), core.formspec_escape(text)
732 -- When there's an error: Shrink description textarea and add error below
733 if dialogdata.error_message then
736 y = description_height - 0.4,
740 formspec = formspec ..
741 create_textfield(error_box, "", dialogdata.error_message, "#600")
742 description_height = description_height - 0.75
745 -- Get description field
746 local description_box = {
750 h = description_height
753 local setting_name = setting.name
754 if setting.readable_name then
755 setting_name = fgettext_ne(setting.readable_name) ..
756 " (" .. setting.name .. ")"
760 if setting.comment == "" then
761 comment_text = fgettext_ne("(No description of setting given)")
763 comment_text = fgettext_ne(setting.comment)
767 "size[" .. width .. "," .. height + 0.25 .. ",true]" ..
768 create_textfield(description_box, setting_name, comment_text) ..
770 "button[" .. width / 2 - 2.5 .. "," .. height - 0.4 .. ";2.5,1;btn_done;" ..
771 fgettext("Save") .. "]" ..
772 "button[" .. width / 2 .. "," .. height - 0.4 .. ";2.5,1;btn_cancel;" ..
773 fgettext("Cancel") .. "]"
777 local function handle_change_setting_buttons(this, fields)
778 local setting = settings[selected_setting]
779 if fields["btn_done"] or fields["key_enter"] then
780 if setting.type == "bool" then
781 local new_value = fields["dd_setting_value"]
782 -- Note: new_value is the actual (translated) value shown in the dropdown
783 core.settings:set_bool(setting.name, new_value == fgettext("Enabled"))
785 elseif setting.type == "enum" then
786 local new_value = fields["dd_setting_value"]
787 core.settings:set(setting.name, new_value)
789 elseif setting.type == "int" then
790 local new_value = tonumber(fields["te_setting_value"])
791 if not new_value or math.floor(new_value) ~= new_value then
792 this.data.error_message = fgettext_ne("Please enter a valid integer.")
793 this.data.entered_text = fields["te_setting_value"]
794 core.update_formspec(this:get_formspec())
797 if setting.min and new_value < setting.min then
798 this.data.error_message = fgettext_ne("The value must be at least $1.", setting.min)
799 this.data.entered_text = fields["te_setting_value"]
800 core.update_formspec(this:get_formspec())
803 if setting.max and new_value > setting.max then
804 this.data.error_message = fgettext_ne("The value must not be larger than $1.", setting.max)
805 this.data.entered_text = fields["te_setting_value"]
806 core.update_formspec(this:get_formspec())
809 core.settings:set(setting.name, new_value)
811 elseif setting.type == "float" then
812 local new_value = tonumber(fields["te_setting_value"])
813 if not new_value then
814 this.data.error_message = fgettext_ne("Please enter a valid number.")
815 this.data.entered_text = fields["te_setting_value"]
816 core.update_formspec(this:get_formspec())
819 if setting.min and new_value < setting.min then
820 this.data.error_message = fgettext_ne("The value must be at least $1.", setting.min)
821 this.data.entered_text = fields["te_setting_value"]
822 core.update_formspec(this:get_formspec())
825 if setting.max and new_value > setting.max then
826 this.data.error_message = fgettext_ne("The value must not be larger than $1.", setting.max)
827 this.data.entered_text = fields["te_setting_value"]
828 core.update_formspec(this:get_formspec())
831 core.settings:set(setting.name, new_value)
833 elseif setting.type == "flags" then
835 for _, name in ipairs(setting.possible) do
836 if checkboxes["cb_" .. name] then
837 table.insert(values, name)
843 local new_value = table.concat(values, ", ")
844 core.settings:set(setting.name, new_value)
846 elseif setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
848 for _, name in ipairs(setting.flags) do
849 if checkboxes["cb_" .. name] then
850 table.insert(np_flags, name)
856 if setting.type == "noise_params_2d" then
857 fields["te_spready"] = fields["te_spreadz"]
860 offset = fields["te_offset"],
861 scale = fields["te_scale"],
863 x = fields["te_spreadx"],
864 y = fields["te_spready"],
865 z = fields["te_spreadz"]
867 seed = fields["te_seed"],
868 octaves = fields["te_octaves"],
869 persistence = fields["te_persist"],
870 lacunarity = fields["te_lacun"],
871 flags = table.concat(np_flags, ", ")
873 core.settings:set_np_group(setting.name, new_value)
875 elseif setting.type == "v3f" then
876 local new_value = "("
877 .. fields["te_x"] .. ", "
878 .. fields["te_y"] .. ", "
879 .. fields["te_z"] .. ")"
880 core.settings:set(setting.name, new_value)
883 local new_value = fields["te_setting_value"]
884 core.settings:set(setting.name, new_value)
886 core.settings:write()
891 if fields["btn_cancel"] then
896 if fields["btn_browser_path"] then
897 core.show_path_select_dialog("dlg_browse_path",
898 fgettext_ne("Select directory"), false)
901 if fields["btn_browser_filepath"] then
902 core.show_path_select_dialog("dlg_browse_path",
903 fgettext_ne("Select file"), true)
906 if fields["dlg_browse_path_accepted"] then
907 this.data.selected_path = fields["dlg_browse_path_accepted"]
908 core.update_formspec(this:get_formspec())
911 if setting.type == "flags"
912 or setting.type == "noise_params_2d"
913 or setting.type == "noise_params_3d" then
914 for name, value in pairs(fields) do
915 if name:sub(1, 3) == "cb_" then
916 checkboxes[name] = value == "true"
924 local function create_settings_formspec(tabview, _, tabdata)
925 local formspec = "size[12,5.4;true]" ..
926 "tablecolumns[color;tree;text,width=28;text]" ..
927 "tableoptions[background=#00000000;border=false]" ..
928 "field[0.3,0.1;10.2,1;search_string;;" .. core.formspec_escape(search_string) .. "]" ..
929 "field_close_on_enter[search_string;false]" ..
930 "button[10.2,-0.2;2,1;search;" .. fgettext("Search") .. "]" ..
931 "table[0,0.8;12,3.5;list_settings;"
933 local current_level = 0
934 for _, entry in ipairs(settings) do
936 if not core.settings:get_bool("main_menu_technical_settings") and entry.readable_name then
937 name = fgettext_ne(entry.readable_name)
942 if entry.type == "category" then
943 current_level = entry.level
944 formspec = formspec .. "#FFFF00," .. current_level .. "," .. fgettext(name) .. ",,"
946 elseif entry.type == "bool" then
947 local value = get_current_value(entry)
948 if core.is_yes(value) then
949 value = fgettext("Enabled")
951 value = fgettext("Disabled")
953 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
956 elseif entry.type == "key" then --luacheck: ignore
957 -- ignore key settings, since we have a special dialog for them
959 elseif entry.type == "noise_params_2d" or entry.type == "noise_params_3d" then
960 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
961 .. core.formspec_escape(get_current_np_group_as_string(entry)) .. ","
964 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
965 .. core.formspec_escape(get_current_value(entry)) .. ","
969 if #settings > 0 then
970 formspec = formspec:sub(1, -2) -- remove trailing comma
972 formspec = formspec .. ";" .. selected_setting .. "]" ..
973 "button[0,4.9;4,1;btn_back;".. fgettext("< Back to Settings page") .. "]" ..
974 "button[10,4.9;2,1;btn_edit;" .. fgettext("Edit") .. "]" ..
975 "button[7,4.9;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" ..
976 "checkbox[0,4.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";"
977 .. dump(core.settings:get_bool("main_menu_technical_settings")) .. "]"
982 local function handle_settings_buttons(this, fields, tabname, tabdata)
983 local list_enter = false
984 if fields["list_settings"] then
985 selected_setting = core.get_table_index("list_settings")
986 if core.explode_table_event(fields["list_settings"]).type == "DCL" then
987 -- Directly toggle booleans
988 local setting = settings[selected_setting]
989 if setting and setting.type == "bool" then
990 local current_value = get_current_value(setting)
991 core.settings:set_bool(setting.name, not core.is_yes(current_value))
992 core.settings:write()
1002 if fields.search or fields.key_enter_field == "search_string" then
1003 if search_string == fields.search_string then
1004 if selected_setting > 0 then
1005 -- Go to next result on enter press
1006 local i = selected_setting + 1
1007 local looped = false
1008 while i > #settings or settings[i].type == "category" do
1010 if i > #settings then
1011 -- Stop infinte looping
1019 selected_setting = i
1020 core.update_formspec(this:get_formspec())
1024 -- Search for setting
1025 search_string = fields.search_string
1026 settings, selected_setting = filter_settings(full_settings, search_string)
1027 core.update_formspec(this:get_formspec())
1032 if fields["btn_edit"] or list_enter then
1033 local setting = settings[selected_setting]
1034 if setting and setting.type ~= "category" then
1035 local edit_dialog = dialog_create("change_setting",
1036 create_change_setting_formspec, handle_change_setting_buttons)
1037 edit_dialog:set_parent(this)
1044 if fields["btn_restore"] then
1045 local setting = settings[selected_setting]
1046 if setting and setting.type ~= "category" then
1047 core.settings:remove(setting.name)
1048 core.settings:write()
1049 core.update_formspec(this:get_formspec())
1054 if fields["btn_back"] then
1059 if fields["cb_tech_settings"] then
1060 core.settings:set("main_menu_technical_settings", fields["cb_tech_settings"])
1061 core.settings:write()
1062 core.update_formspec(this:get_formspec())
1069 function create_adv_settings_dlg()
1070 local dlg = dialog_create("settings_advanced",
1071 create_settings_formspec,
1072 handle_settings_buttons,
1078 -- Uncomment to generate 'minetest.conf.example' and 'settings_translation_file.cpp'.
1079 -- For RUN_IN_PLACE the generated files may appear in the 'bin' folder.
1080 -- See comment and alternative line at the end of 'generate_from_settingtypes.lua'.
1082 --assert(loadfile(core.get_builtin_path().."mainmenu"..DIR_DELIM..
1083 -- "generate_from_settingtypes.lua"))(parse_config_file(true, false))