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 = gamemgr.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 = gamemgr.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 .. ", " ..
525 value.lacunarity .. ", " ..
531 local checkboxes = {} -- handle checkboxes events
533 local function create_change_setting_formspec(dialogdata)
534 local setting = settings[selected_setting]
536 if setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
537 -- Three flags, checkboxes on 2 columns, with a vertical space of 1/2 unit
539 elseif setting.type == "flags" then
540 -- Checkboxes on 2 columns, with a vertical space of 1/2 unit
541 height = 5.2 + math.ceil(#setting.possible / 2) / 2
543 local formspec = "size[10," .. height .. ",true]" ..
544 "button[5," .. height - 0.7 .. ";2,1;btn_done;" .. fgettext("Save") .. "]" ..
545 "button[3," .. height - 0.7 .. ";2,1;btn_cancel;" .. fgettext("Cancel") .. "]" ..
546 "tablecolumns[color;text]" ..
547 "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
548 "table[0,0;10,3;info;"
550 if setting.readable_name then
551 formspec = formspec .. "#FFFF00," .. fgettext(setting.readable_name)
552 .. " (" .. core.formspec_escape(setting.name) .. "),"
554 formspec = formspec .. "#FFFF00," .. core.formspec_escape(setting.name) .. ","
557 formspec = formspec .. ",,"
559 local comment_text = ""
561 if setting.comment == "" then
562 comment_text = fgettext_ne("(No description of setting given)")
564 comment_text = fgettext_ne(setting.comment)
566 for _, comment_line in ipairs(comment_text:split("\n", true)) do
567 formspec = formspec .. "," .. core.formspec_escape(comment_line) .. ","
570 formspec = formspec:sub(1, -2) -- remove trailing comma
572 formspec = formspec .. ";1]"
574 if setting.type == "bool" then
576 if core.is_yes(get_current_value(setting)) then
581 formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;"
582 .. fgettext("Disabled") .. "," .. fgettext("Enabled") .. ";"
583 .. selected_index .. "]"
585 elseif setting.type == "enum" then
586 local selected_index = 0
587 formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;"
588 for index, value in ipairs(setting.values) do
589 -- translating value is not possible, since it's the value
590 -- that we set the setting to
591 formspec = formspec .. core.formspec_escape(value) .. ","
592 if get_current_value(setting) == value then
593 selected_index = index
596 if #setting.values > 0 then
597 formspec = formspec:sub(1, -2) -- remove trailing comma
599 formspec = formspec .. ";" .. selected_index .. "]"
601 elseif setting.type == "path" or setting.type == "filepath" then
602 local current_value = dialogdata.selected_path
603 if not current_value then
604 current_value = get_current_value(setting)
606 formspec = formspec .. "field[0.5,4;7.5,1;te_setting_value;;"
607 .. core.formspec_escape(current_value) .. "]"
608 .. "button[8,3.75;2,1;btn_browser_" .. setting.type .. ";" .. fgettext("Browse") .. "]"
610 elseif setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
611 local t = get_current_np_group(setting)
613 if setting.type == "noise_params_2d" then
618 .. "label[0,2.5;(" .. dimension .. "D Noise)]"
619 .. "field[0.5,4;3.3,1;te_offset;Offset;" -- Offset
620 .. core.formspec_escape(t[1] or "") .. "]"
621 .. "field[3.8,4;3.3,1;te_scale;Scale;" -- Scale
622 .. core.formspec_escape(t[2] or "") .. "]"
623 .. "field[7.1,4;3.3,1;te_seed;Seed;" -- Seed
624 .. core.formspec_escape(t[6] or "") .. "]"
625 .. "label[0.5,4.7;Spread]" -- Spread
626 .. "field[2.0,5;2.8,1;te_spreadx;X;"
627 .. core.formspec_escape(t[3] or "") .. "]"
628 .. "field[4.8,5;2.8,1;te_spready;Y;"
629 .. core.formspec_escape(t[4] or "") .. "]"
630 .. "field[7.6,5;2.8,1;te_spreadz;Z;"
631 .. core.formspec_escape(t[5] or "") .. "]"
632 .. "field[0.5,6;3.3,1;te_octaves;Octaves;" -- Octaves
633 .. core.formspec_escape(t[7] or "") .. "]"
634 .. "field[3.8,6;3.3,1;te_persist;Persistance;" -- Persistance
635 .. core.formspec_escape(t[8] or "") .. "]"
636 .. "field[7.1,6;3.3,1;te_lacun;Lacunarity;" -- Lacunarity
637 .. core.formspec_escape(t[9] or "") .. "]"
639 local enabled_flags = flags_to_table(t[10])
641 for _, name in ipairs(enabled_flags) do
642 -- Index by name, to avoid iterating over all enabled_flags for every possible flag.
647 .. "checkbox[0.5,6.5;cb_defaults;defaults;" -- defaults
648 .. tostring(flags["defaults"] == true) .. "]" -- to get false if nil
649 .. "checkbox[5,6.5;cb_eased;eased;" -- eased
650 .. tostring(flags["eased"] == true) .. "]"
651 .. "checkbox[5,7.0;cb_absvalue;absvalue;" -- absvalue
652 .. tostring(flags["absvalue"] == true) .. "]"
654 elseif setting.type == "v3f" then
655 local val = get_current_value(setting)
657 for line in val:gmatch("[+-]?[%d.-e]+") do -- All numeric characters
658 table.insert(v3f, line)
662 .. "field[0.5,4;3.3,1;te_x;X;" -- X
663 .. core.formspec_escape(v3f[1] or "") .. "]"
664 .. "field[3.8,4;3.3,1;te_y;Y;" -- Y
665 .. core.formspec_escape(v3f[2] or "") .. "]"
666 .. "field[7.1,4;3.3,1;te_z;Z;" -- Z
667 .. core.formspec_escape(v3f[3] or "") .. "]"
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 for i, name in ipairs(setting.possible) do
679 local y = 3.5 + i / 2
680 if i - 1 >= flags_count / 2 then -- 2nd column
682 y = y - flags_count / 4
684 local checkbox_name = "cb_" .. name
685 local is_enabled = flags[name] == true -- to get false if nil
686 checkboxes[checkbox_name] = is_enabled
687 formspec = formspec .. "checkbox["
689 .. ";" .. checkbox_name .. ";"
690 .. name .. ";" .. tostring(is_enabled) .. "]"
694 -- TODO: fancy input for float, int
696 local text = get_current_value(setting)
697 if dialogdata.error_message then
698 formspec = formspec .. "tablecolumns[color;text]" ..
699 "tableoptions[background=#00000000;highlight=#00000000;border=false]" ..
700 "table[5,3.9;5,0.6;error_message;#FF0000,"
701 .. core.formspec_escape(dialogdata.error_message) .. ";0]"
703 if dialogdata.entered_text then
704 text = dialogdata.entered_text
707 formspec = formspec .. "field[0.5,4;" .. width .. ",1;te_setting_value;;"
708 .. core.formspec_escape(text) .. "]"
713 local function handle_change_setting_buttons(this, fields)
714 local setting = settings[selected_setting]
715 if fields["btn_done"] or fields["key_enter"] then
716 if setting.type == "bool" then
717 local new_value = fields["dd_setting_value"]
718 -- Note: new_value is the actual (translated) value shown in the dropdown
719 core.settings:set_bool(setting.name, new_value == fgettext("Enabled"))
721 elseif setting.type == "enum" then
722 local new_value = fields["dd_setting_value"]
723 core.settings:set(setting.name, new_value)
725 elseif setting.type == "int" then
726 local new_value = tonumber(fields["te_setting_value"])
727 if not new_value or math.floor(new_value) ~= new_value then
728 this.data.error_message = fgettext_ne("Please enter a valid integer.")
729 this.data.entered_text = fields["te_setting_value"]
730 core.update_formspec(this:get_formspec())
733 if setting.min and new_value < setting.min then
734 this.data.error_message = fgettext_ne("The value must be at least $1.", setting.min)
735 this.data.entered_text = fields["te_setting_value"]
736 core.update_formspec(this:get_formspec())
739 if setting.max and new_value > setting.max then
740 this.data.error_message = fgettext_ne("The value must not be larger than $1.", setting.max)
741 this.data.entered_text = fields["te_setting_value"]
742 core.update_formspec(this:get_formspec())
745 core.settings:set(setting.name, new_value)
747 elseif setting.type == "float" then
748 local new_value = tonumber(fields["te_setting_value"])
749 if not new_value then
750 this.data.error_message = fgettext_ne("Please enter a valid number.")
751 this.data.entered_text = fields["te_setting_value"]
752 core.update_formspec(this:get_formspec())
755 if setting.min and new_value < setting.min then
756 this.data.error_message = fgettext_ne("The value must be at least $1.", setting.min)
757 this.data.entered_text = fields["te_setting_value"]
758 core.update_formspec(this:get_formspec())
761 if setting.max and new_value > setting.max then
762 this.data.error_message = fgettext_ne("The value must not be larger than $1.", setting.max)
763 this.data.entered_text = fields["te_setting_value"]
764 core.update_formspec(this:get_formspec())
767 core.settings:set(setting.name, new_value)
769 elseif setting.type == "flags" then
771 for _, name in ipairs(setting.possible) do
772 if checkboxes["cb_" .. name] then
773 table.insert(values, name)
779 local new_value = table.concat(values, ", ")
780 core.settings:set(setting.name, new_value)
782 elseif setting.type == "noise_params_2d" or setting.type == "noise_params_3d" then
784 for _, name in ipairs(setting.flags) do
785 if checkboxes["cb_" .. name] then
786 table.insert(np_flags, name)
793 offset = fields["te_offset"],
794 scale = fields["te_scale"],
796 x = fields["te_spreadx"],
797 y = fields["te_spready"],
798 z = fields["te_spreadz"]
800 seed = fields["te_seed"],
801 octaves = fields["te_octaves"],
802 persistence = fields["te_persist"],
803 lacunarity = fields["te_lacun"],
804 flags = table.concat(np_flags, ", ")
806 core.settings:set_np_group(setting.name, new_value)
808 elseif setting.type == "v3f" then
809 local new_value = "("
810 .. fields["te_x"] .. ", "
811 .. fields["te_y"] .. ", "
812 .. fields["te_z"] .. ")"
813 core.settings:set(setting.name, new_value)
816 local new_value = fields["te_setting_value"]
817 core.settings:set(setting.name, new_value)
819 core.settings:write()
824 if fields["btn_cancel"] then
829 if fields["btn_browser_path"] then
830 core.show_path_select_dialog("dlg_browse_path",
831 fgettext_ne("Select directory"), false)
834 if fields["btn_browser_filepath"] then
835 core.show_path_select_dialog("dlg_browse_path",
836 fgettext_ne("Select file"), true)
839 if fields["dlg_browse_path_accepted"] then
840 this.data.selected_path = fields["dlg_browse_path_accepted"]
841 core.update_formspec(this:get_formspec())
844 if setting.type == "flags"
845 or setting.type == "noise_params_2d"
846 or setting.type == "noise_params_3d" then
847 for name, value in pairs(fields) do
848 if name:sub(1, 3) == "cb_" then
849 checkboxes[name] = value == "true"
857 local function create_settings_formspec(tabview, name, tabdata)
858 local formspec = "size[12,6.5;true]" ..
859 "tablecolumns[color;tree;text,width=32;text]" ..
860 "tableoptions[background=#00000000;border=false]" ..
861 "field[0.3,0.1;10.2,1;search_string;;" .. core.formspec_escape(search_string) .. "]" ..
862 "field_close_on_enter[search_string;false]" ..
863 "button[10.2,-0.2;2,1;search;" .. fgettext("Search") .. "]" ..
864 "table[0,0.8;12,4.5;list_settings;"
866 local current_level = 0
867 for _, entry in ipairs(settings) do
869 if not core.settings:get_bool("main_menu_technical_settings") and entry.readable_name then
870 name = fgettext_ne(entry.readable_name)
875 if entry.type == "category" then
876 current_level = entry.level
877 formspec = formspec .. "#FFFF00," .. current_level .. "," .. fgettext(name) .. ",,"
879 elseif entry.type == "bool" then
880 local value = get_current_value(entry)
881 if core.is_yes(value) then
882 value = fgettext("Enabled")
884 value = fgettext("Disabled")
886 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
889 elseif entry.type == "key" then
890 -- ignore key settings, since we have a special dialog for them
892 elseif entry.type == "noise_params_2d" or entry.type == "noise_params_3d" then
893 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
894 .. core.formspec_escape(get_current_np_group_as_string(entry)) .. ","
897 formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. ","
898 .. core.formspec_escape(get_current_value(entry)) .. ","
902 if #settings > 0 then
903 formspec = formspec:sub(1, -2) -- remove trailing comma
905 formspec = formspec .. ";" .. selected_setting .. "]" ..
906 "button[0,6;4,1;btn_back;".. fgettext("< Back to Settings page") .. "]" ..
907 "button[10,6;2,1;btn_edit;" .. fgettext("Edit") .. "]" ..
908 "button[7,6;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" ..
909 "checkbox[0,5.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";"
910 .. dump(core.settings:get_bool("main_menu_technical_settings")) .. "]"
915 local function handle_settings_buttons(this, fields, tabname, tabdata)
916 local list_enter = false
917 if fields["list_settings"] then
918 selected_setting = core.get_table_index("list_settings")
919 if core.explode_table_event(fields["list_settings"]).type == "DCL" then
920 -- Directly toggle booleans
921 local setting = settings[selected_setting]
922 if setting and setting.type == "bool" then
923 local current_value = get_current_value(setting)
924 core.settings:set_bool(setting.name, not core.is_yes(current_value))
925 core.settings:write()
935 if fields.search or fields.key_enter_field == "search_string" then
936 if search_string == fields.search_string then
937 if selected_setting > 0 then
938 -- Go to next result on enter press
939 local i = selected_setting + 1
941 while i > #settings or settings[i].type == "category" do
943 if i > #settings then
944 -- Stop infinte looping
953 core.update_formspec(this:get_formspec())
957 -- Search for setting
958 search_string = fields.search_string
959 settings, selected_setting = filter_settings(full_settings, search_string)
960 core.update_formspec(this:get_formspec())
965 if fields["btn_edit"] or list_enter then
966 local setting = settings[selected_setting]
967 if setting and setting.type ~= "category" then
968 local edit_dialog = dialog_create("change_setting", create_change_setting_formspec,
969 handle_change_setting_buttons)
970 edit_dialog:set_parent(this)
977 if fields["btn_restore"] then
978 local setting = settings[selected_setting]
979 if setting and setting.type ~= "category" then
980 if setting.type == "noise_params_2d"
981 or setting.type == "noise_params_3d" then
982 core.settings:set_np_group(setting.name, setting.default_table)
984 core.settings:set(setting.name, setting.default)
986 core.settings:write()
987 core.update_formspec(this:get_formspec())
992 if fields["btn_back"] then
997 if fields["cb_tech_settings"] then
998 core.settings:set("main_menu_technical_settings", fields["cb_tech_settings"])
999 core.settings:write()
1000 core.update_formspec(this:get_formspec())
1007 function create_adv_settings_dlg()
1008 local dlg = dialog_create("settings_advanced",
1009 create_settings_formspec,
1010 handle_settings_buttons,
1016 -- Uncomment to generate minetest.conf.example and settings_translation_file.cpp
1017 -- For RUN_IN_PLACE the generated files may appear in the bin folder
1019 --assert(loadfile(core.get_builtin_path().."mainmenu"..DIR_DELIM.."generate_from_settingtypes.lua"))(parse_config_file(true, false))