From ecc8b70182b9ad3aaec910d7c8b32fc54cac824a Mon Sep 17 00:00:00 2001 From: BlockMen Date: Fri, 19 Feb 2016 10:03:02 +0100 Subject: [PATCH] Restore simple settings tab and add advanced settings as dialog --- builtin/mainmenu/dlg_settings_advanced.lua | 756 ++++++++++++++ builtin/mainmenu/init.lua | 1 + builtin/mainmenu/tab_settings.lua | 1028 +++++++------------- 3 files changed, 1106 insertions(+), 679 deletions(-) create mode 100644 builtin/mainmenu/dlg_settings_advanced.lua diff --git a/builtin/mainmenu/dlg_settings_advanced.lua b/builtin/mainmenu/dlg_settings_advanced.lua new file mode 100644 index 000000000..35883f05f --- /dev/null +++ b/builtin/mainmenu/dlg_settings_advanced.lua @@ -0,0 +1,756 @@ +--Minetest +--Copyright (C) 2015 PilzAdam +-- +--This program is free software; you can redistribute it and/or modify +--it under the terms of the GNU Lesser General Public License as published by +--the Free Software Foundation; either version 2.1 of the License, or +--(at your option) any later version. +-- +--This program is distributed in the hope that it will be useful, +--but WITHOUT ANY WARRANTY; without even the implied warranty of +--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +--GNU Lesser General Public License for more details. +-- +--You should have received a copy of the GNU Lesser General Public License along +--with this program; if not, write to the Free Software Foundation, Inc., +--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +local FILENAME = "settingtypes.txt" + +local CHAR_CLASSES = { + SPACE = "[%s]", + VARIABLE = "[%w_%-%.]", + INTEGER = "[+-]?[%d]", + FLOAT = "[+-]?[%d%.]", + FLAGS = "[%w_%-%.,]", +} + +-- returns error message, or nil +local function parse_setting_line(settings, line, read_all, base_level, allow_secure) + -- comment + local comment = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$") + if comment then + if settings.current_comment == "" then + settings.current_comment = comment + else + settings.current_comment = settings.current_comment .. "\n" .. comment + end + return + end + + -- clear current_comment so only comments directly above a setting are bound to it + -- but keep a local reference to it for variables in the current line + local current_comment = settings.current_comment + settings.current_comment = "" + + -- empty lines + if line:match("^" .. CHAR_CLASSES.SPACE .. "*$") then + return + end + + -- category + local stars, category = line:match("^%[([%*]*)([^%]]+)%]$") + if category then + table.insert(settings, { + name = category, + level = stars:len() + base_level, + type = "category", + }) + return + end + + -- settings + local first_part, name, readable_name, setting_type = line:match("^" + -- this first capture group matches the whole first part, + -- so we can later strip it from the rest of the line + .. "(" + .. "([" .. CHAR_CLASSES.VARIABLE .. "+)" -- variable name + .. CHAR_CLASSES.SPACE .. "*" + .. "%(([^%)]*)%)" -- readable name + .. CHAR_CLASSES.SPACE .. "*" + .. "(" .. CHAR_CLASSES.VARIABLE .. "+)" -- type + .. CHAR_CLASSES.SPACE .. "*" + .. ")") + + if not first_part then + return "Invalid line" + end + + if name:match("secure%.[.]*") and not allow_secure then + return "Tried to add \"secure.\" setting" + end + + if readable_name == "" then + readable_name = nil + end + local remaining_line = line:sub(first_part:len() + 1) + + if setting_type == "int" then + local default, min, max = remaining_line:match("^" + -- first int is required, the last 2 are optional + .. "(" .. CHAR_CLASSES.INTEGER .. "+)" .. CHAR_CLASSES.SPACE .. "*" + .. "(" .. CHAR_CLASSES.INTEGER .. "*)" .. CHAR_CLASSES.SPACE .. "*" + .. "(" .. CHAR_CLASSES.INTEGER .. "*)" + .. "$") + + if not default or not tonumber(default) then + return "Invalid integer setting" + end + + min = tonumber(min) + max = tonumber(max) + table.insert(settings, { + name = name, + readable_name = readable_name, + type = "int", + default = default, + min = min, + max = max, + comment = current_comment, + }) + return + end + + if setting_type == "string" or setting_type == "noise_params" + or setting_type == "key" or setting_type == "v3f" then + local default = remaining_line:match("^(.*)$") + + if not default then + return "Invalid string setting" + end + if setting_type == "key" and not read_all then + -- ignore key type if read_all is false + return + end + + table.insert(settings, { + name = name, + readable_name = readable_name, + type = setting_type, + default = default, + comment = current_comment, + }) + return + end + + if setting_type == "bool" then + if remaining_line ~= "false" and remaining_line ~= "true" then + return "Invalid boolean setting" + end + + table.insert(settings, { + name = name, + readable_name = readable_name, + type = "bool", + default = remaining_line, + comment = current_comment, + }) + return + end + + if setting_type == "float" then + local default, min, max = remaining_line:match("^" + -- first float is required, the last 2 are optional + .. "(" .. CHAR_CLASSES.FLOAT .. "+)" .. CHAR_CLASSES.SPACE .. "?" + .. "(" .. CHAR_CLASSES.FLOAT .. "*)" .. CHAR_CLASSES.SPACE .. "?" + .. "(" .. CHAR_CLASSES.FLOAT .. "*)" + .."$") + + if not default or not tonumber(default) then + return "Invalid float setting" + end + + min = tonumber(min) + max = tonumber(max) + table.insert(settings, { + name = name, + readable_name = readable_name, + type = "float", + default = default, + min = min, + max = max, + comment = current_comment, + }) + return + end + + if setting_type == "enum" then + local default, values = remaining_line:match("^" + -- first value (default) may be empty (i.e. is optional) + .. "(" .. CHAR_CLASSES.VARIABLE .. "*)" .. CHAR_CLASSES.SPACE .. "*" + .. "(" .. CHAR_CLASSES.FLAGS .. "+)" + .. "$") + + if not default or values == "" then + return "Invalid enum setting" + end + + table.insert(settings, { + name = name, + readable_name = readable_name, + type = "enum", + default = default, + values = values:split(",", true), + comment = current_comment, + }) + return + end + + if setting_type == "path" then + local default = remaining_line:match("^(.*)$") + + if not default then + return "Invalid path setting" + end + + table.insert(settings, { + name = name, + readable_name = readable_name, + type = "path", + default = default, + comment = current_comment, + }) + return + end + + if setting_type == "flags" then + local default, possible = remaining_line:match("^" + -- first value (default) may be empty (i.e. is optional) + -- this is implemented by making the last value optional, and + -- swapping them around if it turns out empty. + .. "(" .. CHAR_CLASSES.FLAGS .. "+)" .. CHAR_CLASSES.SPACE .. "*" + .. "(" .. CHAR_CLASSES.FLAGS .. "*)" + .. "$") + + if not default or not possible then + return "Invalid flags setting" + end + + if possible == "" then + possible = default + default = "" + end + + table.insert(settings, { + name = name, + readable_name = readable_name, + type = "flags", + default = default, + possible = possible, + comment = current_comment, + }) + return + end + + return "Invalid setting type \"" .. setting_type .. "\"" +end + +local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure) + -- store this helper variable in the table so it's easier to pass to parse_setting_line() + result.current_comment = "" + + local line = file:read("*line") + while line do + local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure) + if error_msg then + core.log("error", error_msg .. " in " .. filepath .. " \"" .. line .. "\"") + end + line = file:read("*line") + end + + result.current_comment = nil +end + +-- read_all: whether to ignore certain setting types for GUI or not +-- parse_mods: whether to parse settingtypes.txt in mods and games +local function parse_config_file(read_all, parse_mods) + local builtin_path = core.get_builtin_path() .. DIR_DELIM .. FILENAME + local file = io.open(builtin_path, "r") + local settings = {} + if not file then + core.log("error", "Can't load " .. FILENAME) + return settings + end + + parse_single_file(file, builtin_path, read_all, settings, 0, true) + + file:close() + + if parse_mods then + -- Parse games + local games_category_initialized = false + local index = 1 + local game = gamemgr.get_game(index) + while game do + local path = game.path .. DIR_DELIM .. FILENAME + local file = io.open(path, "r") + if file then + if not games_category_initialized then + local translation = fgettext_ne("Games"), -- not used, but needed for xgettext + table.insert(settings, { + name = "Games", + level = 0, + type = "category", + }) + games_category_initialized = true + end + + table.insert(settings, { + name = game.name, + level = 1, + type = "category", + }) + + parse_single_file(file, path, read_all, settings, 2, false) + + file:close() + end + + index = index + 1 + game = gamemgr.get_game(index) + end + + -- Parse mods + local mods_category_initialized = false + local mods = {} + get_mods(core.get_modpath(), mods) + for _, mod in ipairs(mods) do + local path = mod.path .. DIR_DELIM .. FILENAME + local file = io.open(path, "r") + if file then + if not mods_category_initialized then + local translation = fgettext_ne("Mods"), -- not used, but needed for xgettext + table.insert(settings, { + name = "Mods", + level = 0, + type = "category", + }) + mods_category_initialized = true + end + + table.insert(settings, { + name = mod.name, + level = 1, + type = "category", + }) + + parse_single_file(file, path, read_all, settings, 2, false) + + file:close() + end + end + end + + return settings +end + +local settings = parse_config_file(false, true) +local selected_setting = 1 + +local function get_current_value(setting) + local value = core.setting_get(setting.name) + if value == nil then + value = setting.default + end + return value +end + +local function create_change_setting_formspec(dialogdata) + local setting = settings[selected_setting] + local formspec = "size[10,5.2,true]" .. + "button[5,4.5;2,1;btn_done;" .. fgettext("Save") .. "]" .. + "button[3,4.5;2,1;btn_cancel;" .. fgettext("Cancel") .. "]" .. + "tablecolumns[color;text]" .. + "tableoptions[background=#00000000;highlight=#00000000;border=false]" .. + "table[0,0;10,3;info;" + + if setting.readable_name then + formspec = formspec .. "#FFFF00," .. fgettext(setting.readable_name) + .. " (" .. core.formspec_escape(setting.name) .. ")," + else + formspec = formspec .. "#FFFF00," .. core.formspec_escape(setting.name) .. "," + end + + formspec = formspec .. ",," + + local comment_text = "" + + if setting.comment == "" then + comment_text = fgettext_ne("(No description of setting given)") + else + comment_text = fgettext_ne(setting.comment) + end + for _, comment_line in ipairs(comment_text:split("\n", true)) do + formspec = formspec .. "," .. core.formspec_escape(comment_line) .. "," + end + + if setting.type == "flags" then + formspec = formspec .. ",," + .. "," .. fgettext("Please enter a comma seperated list of flags.") .. "," + .. "," .. fgettext("Possible values are: ") + .. core.formspec_escape(setting.possible:gsub(",", ", ")) .. "," + elseif setting.type == "noise_params" then + formspec = formspec .. ",," + .. "," .. fgettext("Format: , , (, , ), , , ") .. "," + .. "," .. fgettext("Optionally the lacunarity can be appended with a leading comma.") .. "," + elseif setting.type == "v3f" then + formspec = formspec .. ",," + .. "," .. fgettext_ne("Format is 3 numbers separated by commas and inside brackets.") .. "," + end + + formspec = formspec:sub(1, -2) -- remove trailing comma + + formspec = formspec .. ";1]" + + if setting.type == "bool" then + local selected_index + if core.is_yes(get_current_value(setting)) then + selected_index = 2 + else + selected_index = 1 + end + formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;" + .. fgettext("Disabled") .. "," .. fgettext("Enabled") .. ";" + .. selected_index .. "]" + + elseif setting.type == "enum" then + local selected_index = 0 + formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;" + for index, value in ipairs(setting.values) do + -- translating value is not possible, since it's the value + -- that we set the setting to + formspec = formspec .. core.formspec_escape(value) .. "," + if get_current_value(setting) == value then + selected_index = index + end + end + if #setting.values > 0 then + formspec = formspec:sub(1, -2) -- remove trailing comma + end + formspec = formspec .. ";" .. selected_index .. "]" + + elseif setting.type == "path" then + local current_value = dialogdata.selected_path + if not current_value then + current_value = get_current_value(setting) + end + formspec = formspec .. "field[0.5,4;7.5,1;te_setting_value;;" + .. core.formspec_escape(current_value) .. "]" + .. "button[8,3.75;2,1;btn_browser_path;" .. fgettext("Browse") .. "]" + + else + -- TODO: fancy input for float, int, flags, noise_params, v3f + local width = 10 + local text = get_current_value(setting) + if dialogdata.error_message then + formspec = formspec .. "tablecolumns[color;text]" .. + "tableoptions[background=#00000000;highlight=#00000000;border=false]" .. + "table[5,3.9;5,0.6;error_message;#FF0000," + .. core.formspec_escape(dialogdata.error_message) .. ";0]" + width = 5 + if dialogdata.entered_text then + text = dialogdata.entered_text + end + end + formspec = formspec .. "field[0.5,4;" .. width .. ",1;te_setting_value;;" + .. core.formspec_escape(text) .. "]" + end + return formspec +end + +local function handle_change_setting_buttons(this, fields) + if fields["btn_done"] or fields["key_enter"] then + local setting = settings[selected_setting] + if setting.type == "bool" then + local new_value = fields["dd_setting_value"] + -- Note: new_value is the actual (translated) value shown in the dropdown + core.setting_setbool(setting.name, new_value == fgettext("Enabled")) + + elseif setting.type == "enum" then + local new_value = fields["dd_setting_value"] + core.setting_set(setting.name, new_value) + + elseif setting.type == "int" then + local new_value = tonumber(fields["te_setting_value"]) + if not new_value or math.floor(new_value) ~= new_value then + this.data.error_message = fgettext_ne("Please enter a valid integer.") + this.data.entered_text = fields["te_setting_value"] + core.update_formspec(this:get_formspec()) + return true + end + if setting.min and new_value < setting.min then + this.data.error_message = fgettext_ne("The value must be greater than $1.", setting.min) + this.data.entered_text = fields["te_setting_value"] + core.update_formspec(this:get_formspec()) + return true + end + if setting.max and new_value > setting.max then + this.data.error_message = fgettext_ne("The value must be lower than $1.", setting.max) + this.data.entered_text = fields["te_setting_value"] + core.update_formspec(this:get_formspec()) + return true + end + core.setting_set(setting.name, new_value) + + elseif setting.type == "float" then + local new_value = tonumber(fields["te_setting_value"]) + if not new_value then + this.data.error_message = fgettext_ne("Please enter a valid number.") + this.data.entered_text = fields["te_setting_value"] + core.update_formspec(this:get_formspec()) + return true + end + core.setting_set(setting.name, new_value) + + elseif setting.type == "flags" then + local new_value = fields["te_setting_value"] + for _,value in ipairs(new_value:split(",", true)) do + value = value:trim() + local possible = "," .. setting.possible .. "," + if not possible:find("," .. value .. ",", 0, true) then + this.data.error_message = fgettext_ne("\"$1\" is not a valid flag.", value) + this.data.entered_text = fields["te_setting_value"] + core.update_formspec(this:get_formspec()) + return true + end + end + core.setting_set(setting.name, new_value) + + else + local new_value = fields["te_setting_value"] + core.setting_set(setting.name, new_value) + end + core.setting_save() + this:delete() + return true + end + + if fields["btn_cancel"] then + this:delete() + return true + end + + if fields["btn_browser_path"] then + core.show_file_open_dialog("dlg_browse_path", fgettext_ne("Select path")) + end + + if fields["dlg_browse_path_accepted"] then + this.data.selected_path = fields["dlg_browse_path_accepted"] + core.update_formspec(this:get_formspec()) + end + + return false +end + +local function create_settings_formspec(tabview, name, tabdata) + local formspec = "size[12,6.5;true]" .. + "tablecolumns[color;tree;text;text]" .. + "tableoptions[background=#00000000;border=false]" .. + "table[0,0;12,5.5;list_settings;" + + local current_level = 0 + for _, entry in ipairs(settings) do + local name + if not core.setting_getbool("main_menu_technical_settings") and entry.readable_name then + name = fgettext_ne(entry.readable_name) + else + name = entry.name + end + + if entry.type == "category" then + current_level = entry.level + formspec = formspec .. "#FFFF00," .. current_level .. "," .. fgettext(name) .. ",," + + elseif entry.type == "bool" then + local value = get_current_value(entry) + if core.is_yes(value) then + value = fgettext("Enabled") + else + value = fgettext("Disabled") + end + formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. "," + .. value .. "," + + elseif entry.type == "key" then + -- ignore key settings, since we have a special dialog for them + + else + formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. "," + .. core.formspec_escape(get_current_value(entry)) .. "," + end + end + + if #settings > 0 then + formspec = formspec:sub(1, -2) -- remove trailing comma + end + formspec = formspec .. ";" .. selected_setting .. "]" .. + "button[0,6;4,1;btn_back;".. fgettext("< Back to Settings page") .. "]" .. + "button[10,6;2,1;btn_edit;" .. fgettext("Edit") .. "]" .. + "button[7,6;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" .. + "checkbox[0,5.3;cb_tech_settings;" .. fgettext("Show technical names") .. ";" + .. dump(core.setting_getbool("main_menu_technical_settings")) .. "]" + + return formspec +end + +local function handle_settings_buttons(this, fields, tabname, tabdata) + local list_enter = false + if fields["list_settings"] then + selected_setting = core.get_table_index("list_settings") + if core.explode_table_event(fields["list_settings"]).type == "DCL" then + -- Directly toggle booleans + local setting = settings[selected_setting] + if setting.type == "bool" then + local current_value = get_current_value(setting) + core.setting_setbool(setting.name, not core.is_yes(current_value)) + core.setting_save() + return true + else + list_enter = true + end + else + return true + end + end + + if fields["btn_edit"] or list_enter then + local setting = settings[selected_setting] + if setting.type ~= "category" then + local edit_dialog = dialog_create("change_setting", create_change_setting_formspec, + handle_change_setting_buttons) + edit_dialog:set_parent(this) + this:hide() + edit_dialog:show() + end + return true + end + + if fields["btn_restore"] then + local setting = settings[selected_setting] + if setting.type ~= "category" then + core.setting_set(setting.name, setting.default) + core.setting_save() + core.update_formspec(this:get_formspec()) + end + return true + end + + if fields["btn_back"] then + this:delete() + return true + end + + if fields["cb_tech_settings"] then + core.setting_set("main_menu_technical_settings", fields["cb_tech_settings"]) + core.setting_save() + core.update_formspec(this:get_formspec()) + return true + end + + return false +end + +function create_adv_settings_dlg() + local dlg = dialog_create("settings_advanced", + create_settings_formspec, + handle_settings_buttons, + nil) + + return dlg +end + +local function create_minetest_conf_example() + local result = "# This file contains a list of all available settings and their default value for minetest.conf\n" .. + "\n" .. + "# By default, all the settings are commented and not functional.\n" .. + "# Uncomment settings by removing the preceding #.\n" .. + "\n" .. + "# minetest.conf is read by default from:\n" .. + "# ../minetest.conf\n" .. + "# ../../minetest.conf\n" .. + "# Any other path can be chosen by passing the path as a parameter\n" .. + "# to the program, eg. \"minetest.exe --config ../minetest.conf.example\".\n" .. + "\n" .. + "# Further documentation:\n" .. + "# http://wiki.minetest.net/\n" .. + "\n" + + local settings = parse_config_file(true, false) + for _, entry in ipairs(settings) do + if entry.type == "category" then + if entry.level == 0 then + result = result .. "#\n# " .. entry.name .. "\n#\n\n" + else + for i = 1, entry.level do + result = result .. "#" + end + result = result .. "# " .. entry.name .. "\n\n" + end + else + if entry.comment ~= "" then + for _, comment_line in ipairs(entry.comment:split("\n", true)) do + result = result .."# " .. comment_line .. "\n" + end + end + result = result .. "# type: " .. entry.type + if entry.min then + result = result .. " min: " .. entry.min + end + if entry.max then + result = result .. " max: " .. entry.max + end + if entry.values then + result = result .. " values: " .. table.concat(entry.values, ", ") + end + if entry.possible then + result = result .. " possible values: " .. entry.possible:gsub(",", ", ") + end + result = result .. "\n" + result = result .. "# " .. entry.name .. " = ".. entry.default .. "\n\n" + end + end + return result +end + +local function create_translation_file() + local result = "// This file is automatically generated\n" .. + "// It conatins a bunch of fake gettext calls, to tell xgettext about the strings in config files\n" .. + "// To update it, refer to the bottom of builtin/mainmenu/tab_settings.lua\n\n" .. + "fake_function() {\n" + + local settings = parse_config_file(true, false) + for _, entry in ipairs(settings) do + if entry.type == "category" then + local name_escaped = entry.name:gsub("\"", "\\\"") + result = result .. "\tgettext(\"" .. name_escaped .. "\");\n" + else + if entry.readable_name then + local readable_name_escaped = entry.readable_name:gsub("\"", "\\\"") + result = result .. "\tgettext(\"" .. readable_name_escaped .. "\");\n" + end + if entry.comment ~= "" then + local comment_escaped = entry.comment:gsub("\n", "\\n") + comment_escaped = comment_escaped:gsub("\"", "\\\"") + result = result .. "\tgettext(\"" .. comment_escaped .. "\");\n" + end + end + end + result = result .. "}\n" + return result +end + +if false then + local file = io.open("minetest.conf.example", "w") + if file then + file:write(create_minetest_conf_example()) + file:close() + end +end + +if false then + local file = io.open("src/settings_translation_file.cpp", "w") + if file then + file:write(create_translation_file()) + file:close() + end +end diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index 176796bef..69536630d 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -41,6 +41,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_config_world.lua") dofile(menupath .. DIR_DELIM .. "tab_credits.lua") dofile(menupath .. DIR_DELIM .. "tab_mods.lua") dofile(menupath .. DIR_DELIM .. "tab_settings.lua") +dofile(menupath .. DIR_DELIM .. "dlg_settings_advanced.lua") if PLATFORM ~= "Android" then dofile(menupath .. DIR_DELIM .. "dlg_create_world.lua") dofile(menupath .. DIR_DELIM .. "dlg_delete_mod.lua") diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua index 99138a091..dc2bcff14 100644 --- a/builtin/mainmenu/tab_settings.lua +++ b/builtin/mainmenu/tab_settings.lua @@ -1,5 +1,5 @@ --Minetest ---Copyright (C) 2015 PilzAdam +--Copyright (C) 2013 sapier -- --This program is free software; you can redistribute it and/or modify --it under the terms of the GNU Lesser General Public License as published by @@ -15,739 +15,409 @@ --with this program; if not, write to the Free Software Foundation, Inc., --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -local FILENAME = "settingtypes.txt" +-------------------------------------------------------------------------------- -local CHAR_CLASSES = { - SPACE = "[%s]", - VARIABLE = "[%w_%-%.]", - INTEGER = "[+-]?[%d]", - FLOAT = "[+-]?[%d%.]", - FLAGS = "[%w_%-%.,]", +local leaves_style_labels = { + fgettext("Opaque Leaves"), + fgettext("Simple Leaves"), + fgettext("Fancy Leaves") } --- returns error message, or nil -local function parse_setting_line(settings, line, read_all, base_level, allow_secure) - -- comment - local comment = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$") - if comment then - if settings.current_comment == "" then - settings.current_comment = comment - else - settings.current_comment = settings.current_comment .. "\n" .. comment - end - return +local leaves_style = { + {leaves_style_labels[1] .. "," .. leaves_style_labels[2] .. "," .. leaves_style_labels[3]}, + {"opaque", "simple", "fancy"}, +} + +local dd_filter_labels = { + fgettext("No Filter"), + fgettext("Bilinear Filter"), + fgettext("Trilinear Filter") +} + +local filters = { + {dd_filter_labels[1] .. "," .. dd_filter_labels[2] .. "," .. dd_filter_labels[3]}, + {"", "bilinear_filter", "trilinear_filter"}, +} + +local dd_mipmap_labels = { + fgettext("No Mipmap"), + fgettext("Mipmap"), + fgettext("Mipmap + Aniso. Filter") +} + +local mipmap = { + {dd_mipmap_labels[1] .. "," .. dd_mipmap_labels[2] .. "," .. dd_mipmap_labels[3]}, + {"", "mip_map", "anisotropic_filter"}, +} + +local function getLeavesStyleSettingIndex() + local style = core.setting_get("leaves_style") + if (style == leaves_style[2][3]) then + return 3 + elseif (style == leaves_style[2][2]) then + return 2 end - - -- clear current_comment so only comments directly above a setting are bound to it - -- but keep a local reference to it for variables in the current line - local current_comment = settings.current_comment - settings.current_comment = "" - - -- empty lines - if line:match("^" .. CHAR_CLASSES.SPACE .. "*$") then - return - end - - -- category - local stars, category = line:match("^%[([%*]*)([^%]]+)%]$") - if category then - table.insert(settings, { - name = category, - level = stars:len() + base_level, - type = "category", - }) - return - end - - -- settings - local first_part, name, readable_name, setting_type = line:match("^" - -- this first capture group matches the whole first part, - -- so we can later strip it from the rest of the line - .. "(" - .. "([" .. CHAR_CLASSES.VARIABLE .. "+)" -- variable name - .. CHAR_CLASSES.SPACE .. "*" - .. "%(([^%)]*)%)" -- readable name - .. CHAR_CLASSES.SPACE .. "*" - .. "(" .. CHAR_CLASSES.VARIABLE .. "+)" -- type - .. CHAR_CLASSES.SPACE .. "*" - .. ")") - - if not first_part then - return "Invalid line" - end - - if name:match("secure%.[.]*") and not allow_secure then - return "Tried to add \"secure.\" setting" - end - - if readable_name == "" then - readable_name = nil - end - local remaining_line = line:sub(first_part:len() + 1) - - if setting_type == "int" then - local default, min, max = remaining_line:match("^" - -- first int is required, the last 2 are optional - .. "(" .. CHAR_CLASSES.INTEGER .. "+)" .. CHAR_CLASSES.SPACE .. "*" - .. "(" .. CHAR_CLASSES.INTEGER .. "*)" .. CHAR_CLASSES.SPACE .. "*" - .. "(" .. CHAR_CLASSES.INTEGER .. "*)" - .. "$") - - if not default or not tonumber(default) then - return "Invalid integer setting" - end - - min = tonumber(min) - max = tonumber(max) - table.insert(settings, { - name = name, - readable_name = readable_name, - type = "int", - default = default, - min = min, - max = max, - comment = current_comment, - }) - return - end - - if setting_type == "string" or setting_type == "noise_params" - or setting_type == "key" or setting_type == "v3f" then - local default = remaining_line:match("^(.*)$") - - if not default then - return "Invalid string setting" - end - if setting_type == "key" and not read_all then - -- ignore key type if read_all is false - return - end - - table.insert(settings, { - name = name, - readable_name = readable_name, - type = setting_type, - default = default, - comment = current_comment, - }) - return - end - - if setting_type == "bool" then - if remaining_line ~= "false" and remaining_line ~= "true" then - return "Invalid boolean setting" - end - - table.insert(settings, { - name = name, - readable_name = readable_name, - type = "bool", - default = remaining_line, - comment = current_comment, - }) - return - end - - if setting_type == "float" then - local default, min, max = remaining_line:match("^" - -- first float is required, the last 2 are optional - .. "(" .. CHAR_CLASSES.FLOAT .. "+)" .. CHAR_CLASSES.SPACE .. "*" - .. "(" .. CHAR_CLASSES.FLOAT .. "*)" .. CHAR_CLASSES.SPACE .. "*" - .. "(" .. CHAR_CLASSES.FLOAT .. "*)" - .."$") - - if not default or not tonumber(default) then - return "Invalid float setting" - end - - min = tonumber(min) - max = tonumber(max) - table.insert(settings, { - name = name, - readable_name = readable_name, - type = "float", - default = default, - min = min, - max = max, - comment = current_comment, - }) - return - end - - if setting_type == "enum" then - local default, values = remaining_line:match("^" - -- first value (default) may be empty (i.e. is optional) - .. "(" .. CHAR_CLASSES.VARIABLE .. "*)" .. CHAR_CLASSES.SPACE .. "*" - .. "(" .. CHAR_CLASSES.FLAGS .. "+)" - .. "$") - - if not default or values == "" then - return "Invalid enum setting" - end - - table.insert(settings, { - name = name, - readable_name = readable_name, - type = "enum", - default = default, - values = values:split(",", true), - comment = current_comment, - }) - return - end - - if setting_type == "path" then - local default = remaining_line:match("^(.*)$") - - if not default then - return "Invalid path setting" - end - - table.insert(settings, { - name = name, - readable_name = readable_name, - type = "path", - default = default, - comment = current_comment, - }) - return - end - - if setting_type == "flags" then - local default, possible = remaining_line:match("^" - -- first value (default) may be empty (i.e. is optional) - -- this is implemented by making the last value optional, and - -- swapping them around if it turns out empty. - .. "(" .. CHAR_CLASSES.FLAGS .. "+)" .. CHAR_CLASSES.SPACE .. "*" - .. "(" .. CHAR_CLASSES.FLAGS .. "*)" - .. "$") - - if not default or not possible then - return "Invalid flags setting" - end - - if possible == "" then - possible = default - default = "" - end - - table.insert(settings, { - name = name, - readable_name = readable_name, - type = "flags", - default = default, - possible = possible, - comment = current_comment, - }) - return - end - - return "Invalid setting type \"" .. setting_type .. "\"" + return 1 end -local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure) - -- store this helper variable in the table so it's easier to pass to parse_setting_line() - result.current_comment = "" +local dd_antialiasing_labels = { + fgettext("None"), + fgettext("2x"), + fgettext("4x"), + fgettext("8x"), +} - local line = file:read("*line") - while line do - local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure) - if error_msg then - core.log("error", error_msg .. " in " .. filepath .. " \"" .. line .. "\"") - end - line = file:read("*line") +local antialiasing = { + {dd_antialiasing_labels[1] .. "," .. dd_antialiasing_labels[2] .. "," .. + dd_antialiasing_labels[3] .. "," .. dd_antialiasing_labels[4]}, + {"0", "2", "4", "8"} +} + +local function getFilterSettingIndex() + if (core.setting_get(filters[2][3]) == "true") then + return 3 end - - result.current_comment = nil + if (core.setting_get(filters[2][3]) == "false" and core.setting_get(filters[2][2]) == "true") then + return 2 + end + return 1 end --- read_all: whether to ignore certain setting types for GUI or not --- parse_mods: whether to parse settingtypes.txt in mods and games -local function parse_config_file(read_all, parse_mods) - local builtin_path = core.get_builtin_path() .. DIR_DELIM .. FILENAME - local file = io.open(builtin_path, "r") - local settings = {} - if not file then - core.log("error", "Can't load " .. FILENAME) - return settings +local function getMipmapSettingIndex() + if (core.setting_get(mipmap[2][3]) == "true") then + return 3 end + if (core.setting_get(mipmap[2][3]) == "false" and core.setting_get(mipmap[2][2]) == "true") then + return 2 + end + return 1 +end - parse_single_file(file, builtin_path, read_all, settings, 0, true) +local function getAntialiasingSettingIndex() + local antialiasing_setting = core.setting_get("fsaa") + for i = 1, #(antialiasing[2]) do + if antialiasing_setting == antialiasing[2][i] then + return i + end + end + return 1 +end - file:close() +local function antialiasing_fname_to_name(fname) + for i = 1, #(dd_antialiasing_labels) do + if fname == dd_antialiasing_labels[i] then + return antialiasing[2][i] + end + end + return 0 +end - if parse_mods then - -- Parse games - local games_category_initialized = false - local index = 1 - local game = gamemgr.get_game(index) - while game do - local path = game.path .. DIR_DELIM .. FILENAME - local file = io.open(path, "r") - if file then - if not games_category_initialized then - local translation = fgettext_ne("Games"), -- not used, but needed for xgettext - table.insert(settings, { - name = "Games", - level = 0, - type = "category", - }) - games_category_initialized = true - end +local function dlg_confirm_reset_formspec(data) + local retval = + "size[8,3]" .. + "label[1,1;" .. fgettext("Are you sure to reset your singleplayer world?") .. "]" .. + "button[1,2;2.6,0.5;dlg_reset_singleplayer_confirm;" .. + fgettext("Yes") .. "]" .. + "button[4,2;2.8,0.5;dlg_reset_singleplayer_cancel;" .. + fgettext("No!!!") .. "]" + return retval +end - table.insert(settings, { - name = game.name, - level = 1, - type = "category", - }) +local function dlg_confirm_reset_btnhandler(this, fields, dialogdata) - parse_single_file(file, path, read_all, settings, 2, false) + if fields["dlg_reset_singleplayer_confirm"] ~= nil then + local worldlist = core.get_worlds() + local found_singleplayerworld = false - file:close() + for i = 1, #worldlist, 1 do + if worldlist[i].name == "singleplayerworld" then + found_singleplayerworld = true + gamedata.worldindex = i end - - index = index + 1 - game = gamemgr.get_game(index) end - -- Parse mods - local mods_category_initialized = false - local mods = {} - get_mods(core.get_modpath(), mods) - for _, mod in ipairs(mods) do - local path = mod.path .. DIR_DELIM .. FILENAME - local file = io.open(path, "r") - if file then - if not mods_category_initialized then - local translation = fgettext_ne("Mods"), -- not used, but needed for xgettext - table.insert(settings, { - name = "Mods", - level = 0, - type = "category", - }) - mods_category_initialized = true - end + if found_singleplayerworld then + core.delete_world(gamedata.worldindex) + end - table.insert(settings, { - name = mod.name, - level = 1, - type = "category", - }) + core.create_world("singleplayerworld", 1) - parse_single_file(file, path, read_all, settings, 2, false) + worldlist = core.get_worlds() - file:close() + found_singleplayerworld = false + + for i = 1, #worldlist, 1 do + if worldlist[i].name == "singleplayerworld" then + found_singleplayerworld = true + gamedata.worldindex = i end end end - return settings + this.parent:show() + this:hide() + this:delete() + return true end -local settings = parse_config_file(false, true) -local selected_setting = 1 +local function showconfirm_reset(tabview) + local new_dlg = dialog_create("reset_spworld", + dlg_confirm_reset_formspec, + dlg_confirm_reset_btnhandler, + nil) + new_dlg:set_parent(tabview) + tabview:hide() + new_dlg:show() +end -local function get_current_value(setting) - local value = core.setting_get(setting.name) - if value == nil then - value = setting.default +local function gui_scale_to_scrollbar() + local current_value = tonumber(core.setting_get("gui_scaling")) + + if (current_value == nil) or current_value < 0.25 then + return 0 end - return value + if current_value <= 1.25 then + return ((current_value - 0.25)/ 1.0) * 700 + end + if current_value <= 6 then + return ((current_value -1.25) * 100) + 700 + end + + return 1000 end -local function create_change_setting_formspec(dialogdata) - local setting = settings[selected_setting] - local formspec = "size[10,5.2,true]" .. - "button[5,4.5;2,1;btn_done;" .. fgettext("Save") .. "]" .. - "button[3,4.5;2,1;btn_cancel;" .. fgettext("Cancel") .. "]" .. - "tablecolumns[color;text]" .. - "tableoptions[background=#00000000;highlight=#00000000;border=false]" .. - "table[0,0;10,3;info;" +local function scrollbar_to_gui_scale(value) + value = tonumber(value) - if setting.readable_name then - formspec = formspec .. "#FFFF00," .. fgettext(setting.readable_name) - .. " (" .. core.formspec_escape(setting.name) .. ")," + if (value <= 700) then + return ((value / 700) * 1.0) + 0.25 + end + if (value <= 1000) then + return ((value - 700) / 100) + 1.25 + end + + return 1 +end + +local function formspec(tabview, name, tabdata) + local tab_string = + "box[0,0;3.5,4.3;#999999]" .. + "checkbox[0.25,0;cb_smooth_lighting;" .. fgettext("Smooth Lighting") + .. ";" .. dump(core.setting_getbool("smooth_lighting")) .. "]" .. + "checkbox[0.25,0.5;cb_particles;" .. fgettext("Enable Particles") .. ";" + .. dump(core.setting_getbool("enable_particles")) .. "]" .. + "checkbox[0.25,1;cb_3d_clouds;" .. fgettext("3D Clouds") .. ";" + .. dump(core.setting_getbool("enable_3d_clouds")) .. "]" .. + "checkbox[0.25,1.5;cb_opaque_water;" .. fgettext("Opaque Water") .. ";" + .. dump(core.setting_getbool("opaque_water")) .. "]" .. + "checkbox[0.25,2.0;cb_connected_glass;" .. fgettext("Connected Glass") .. ";" + .. dump(core.setting_getbool("connected_glass")) .. "]" .. + "checkbox[0.25,2.5;cb_node_highlighting;" .. fgettext("Node Highlighting") .. ";" + .. dump(core.setting_getbool("enable_node_highlighting")) .. "]" .. + "dropdown[0.25,3.4;3.3;dd_leaves_style;" .. leaves_style[1][1] .. ";" + .. getLeavesStyleSettingIndex() .. "]" .. + "box[3.75,0;3.75,3.45;#999999]" .. + "label[3.85,0.1;" .. fgettext("Texturing:") .. "]" .. + "dropdown[3.85,0.55;3.85;dd_filters;" .. filters[1][1] .. ";" + .. getFilterSettingIndex() .. "]" .. + "dropdown[3.85,1.35;3.85;dd_mipmap;" .. mipmap[1][1] .. ";" + .. getMipmapSettingIndex() .. "]" .. + "label[3.85,2.15;" .. fgettext("Antialiasing:") .. "]" .. + "dropdown[3.85,2.6;3.85;dd_antialiasing;" .. antialiasing[1][1] .. ";" + .. getAntialiasingSettingIndex() .. "]" .. + "box[7.75,0;4,4;#999999]" .. + "checkbox[8,0;cb_shaders;" .. fgettext("Shaders") .. ";" + .. dump(core.setting_getbool("enable_shaders")) .. "]" + + tab_string = tab_string .. + "button[8,4.75;3.75,0.5;btn_change_keys;" .. fgettext("Change keys") .. "]" .. + "button[0,4.75;3.75,0.5;btn_advanced_settings;" .. fgettext("Advanced Settings") .. "]" + + + if core.setting_get("touchscreen_threshold") ~= nil then + tab_string = tab_string .. + "label[4.3,4.1;" .. fgettext("Touchthreshold (px)") .. "]" .. + "dropdown[3.85,4.55;3.85;dd_touchthreshold;0,10,20,30,40,50;" .. + ((tonumber(core.setting_get("touchscreen_threshold"))/10)+1) .. "]" + end + + if core.setting_getbool("enable_shaders") then + tab_string = tab_string .. + "checkbox[8,0.5;cb_bumpmapping;" .. fgettext("Bumpmapping") .. ";" + .. dump(core.setting_getbool("enable_bumpmapping")) .. "]" .. + "checkbox[8,1.0;cb_generate_normalmaps;" .. fgettext("Generate Normalmaps") .. ";" + .. dump(core.setting_getbool("generate_normalmaps")) .. "]" .. + "checkbox[8,1.5;cb_parallax;" .. fgettext("Parallax Occlusion") .. ";" + .. dump(core.setting_getbool("enable_parallax_occlusion")) .. "]" .. + "checkbox[8,2.0;cb_waving_water;" .. fgettext("Waving Water") .. ";" + .. dump(core.setting_getbool("enable_waving_water")) .. "]" .. + "checkbox[8,2.5;cb_waving_leaves;" .. fgettext("Waving Leaves") .. ";" + .. dump(core.setting_getbool("enable_waving_leaves")) .. "]" .. + "checkbox[8,3.0;cb_waving_plants;" .. fgettext("Waving Plants") .. ";" + .. dump(core.setting_getbool("enable_waving_plants")) .. "]" else - formspec = formspec .. "#FFFF00," .. core.formspec_escape(setting.name) .. "," + tab_string = tab_string .. + "tablecolumns[color;text]" .. + "tableoptions[background=#00000000;highlight=#00000000;border=false]" .. + "table[8.33,0.7;3.5,4;shaders;" .. + "#888888," .. fgettext("Bumpmapping") .. "," .. + "#888888," .. fgettext("Generate Normalmaps") .. "," .. + "#888888," .. fgettext("Parallax Occlusion") .. "," .. + "#888888," .. fgettext("Waving Water") .. "," .. + "#888888," .. fgettext("Waving Leaves") .. "," .. + "#888888," .. fgettext("Waving Plants") .. "," .. + ";1]" end - formspec = formspec .. ",," - - local comment_text = "" - - if setting.comment == "" then - comment_text = fgettext_ne("(No description of setting given)") - else - comment_text = fgettext_ne(setting.comment) - end - for _, comment_line in ipairs(comment_text:split("\n", true)) do - formspec = formspec .. "," .. core.formspec_escape(comment_line) .. "," - end - - if setting.type == "flags" then - formspec = formspec .. ",," - .. "," .. fgettext("Please enter a comma seperated list of flags.") .. "," - .. "," .. fgettext("Possible values are: ") - .. core.formspec_escape(setting.possible:gsub(",", ", ")) .. "," - elseif setting.type == "noise_params" then - formspec = formspec .. ",," - .. "," .. fgettext("Format: , , (, , ), , , ") .. "," - .. "," .. fgettext("Optionally the lacunarity can be appended with a leading comma.") .. "," - elseif setting.type == "v3f" then - formspec = formspec .. ",," - .. "," .. fgettext_ne("Format is 3 numbers separated by commas and inside brackets.") .. "," - end - - formspec = formspec:sub(1, -2) -- remove trailing comma - - formspec = formspec .. ";1]" - - if setting.type == "bool" then - local selected_index - if core.is_yes(get_current_value(setting)) then - selected_index = 2 - else - selected_index = 1 - end - formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;" - .. fgettext("Disabled") .. "," .. fgettext("Enabled") .. ";" - .. selected_index .. "]" - - elseif setting.type == "enum" then - local selected_index = 0 - formspec = formspec .. "dropdown[0.5,3.5;3,1;dd_setting_value;" - for index, value in ipairs(setting.values) do - -- translating value is not possible, since it's the value - -- that we set the setting to - formspec = formspec .. core.formspec_escape(value) .. "," - if get_current_value(setting) == value then - selected_index = index - end - end - if #setting.values > 0 then - formspec = formspec:sub(1, -2) -- remove trailing comma - end - formspec = formspec .. ";" .. selected_index .. "]" - - elseif setting.type == "path" then - local current_value = dialogdata.selected_path - if not current_value then - current_value = get_current_value(setting) - end - formspec = formspec .. "field[0.5,4;7.5,1;te_setting_value;;" - .. core.formspec_escape(current_value) .. "]" - .. "button[8,3.75;2,1;btn_browser_path;" .. fgettext("Browse") .. "]" - - else - -- TODO: fancy input for float, int, flags, noise_params, v3f - local width = 10 - local text = get_current_value(setting) - if dialogdata.error_message then - formspec = formspec .. "tablecolumns[color;text]" .. - "tableoptions[background=#00000000;highlight=#00000000;border=false]" .. - "table[5,3.9;5,0.6;error_message;#FF0000," - .. core.formspec_escape(dialogdata.error_message) .. ";0]" - width = 5 - if dialogdata.entered_text then - text = dialogdata.entered_text - end - end - formspec = formspec .. "field[0.5,4;" .. width .. ",1;te_setting_value;;" - .. core.formspec_escape(text) .. "]" - end - return formspec -end - -local function handle_change_setting_buttons(this, fields) - if fields["btn_done"] or fields["key_enter"] then - local setting = settings[selected_setting] - if setting.type == "bool" then - local new_value = fields["dd_setting_value"] - -- Note: new_value is the actual (translated) value shown in the dropdown - core.setting_setbool(setting.name, new_value == fgettext("Enabled")) - - elseif setting.type == "enum" then - local new_value = fields["dd_setting_value"] - core.setting_set(setting.name, new_value) - - elseif setting.type == "int" then - local new_value = tonumber(fields["te_setting_value"]) - if not new_value or math.floor(new_value) ~= new_value then - this.data.error_message = fgettext_ne("Please enter a valid integer.") - this.data.entered_text = fields["te_setting_value"] - core.update_formspec(this:get_formspec()) - return true - end - if setting.min and new_value < setting.min then - this.data.error_message = fgettext_ne("The value must be greater than $1.", setting.min) - this.data.entered_text = fields["te_setting_value"] - core.update_formspec(this:get_formspec()) - return true - end - if setting.max and new_value > setting.max then - this.data.error_message = fgettext_ne("The value must be lower than $1.", setting.max) - this.data.entered_text = fields["te_setting_value"] - core.update_formspec(this:get_formspec()) - return true - end - core.setting_set(setting.name, new_value) - - elseif setting.type == "float" then - local new_value = tonumber(fields["te_setting_value"]) - if not new_value then - this.data.error_message = fgettext_ne("Please enter a valid number.") - this.data.entered_text = fields["te_setting_value"] - core.update_formspec(this:get_formspec()) - return true - end - core.setting_set(setting.name, new_value) - - elseif setting.type == "flags" then - local new_value = fields["te_setting_value"] - for _,value in ipairs(new_value:split(",", true)) do - value = value:trim() - local possible = "," .. setting.possible .. "," - if not possible:find("," .. value .. ",", 0, true) then - this.data.error_message = fgettext_ne("\"$1\" is not a valid flag.", value) - this.data.entered_text = fields["te_setting_value"] - core.update_formspec(this:get_formspec()) - return true - end - end - core.setting_set(setting.name, new_value) - - else - local new_value = fields["te_setting_value"] - core.setting_set(setting.name, new_value) - end - core.setting_save() - this:delete() - return true - end - - if fields["btn_cancel"] then - this:delete() - return true - end - - if fields["btn_browser_path"] then - core.show_file_open_dialog("dlg_browse_path", fgettext_ne("Select path")) - end - - if fields["dlg_browse_path_accepted"] then - this.data.selected_path = fields["dlg_browse_path_accepted"] - core.update_formspec(this:get_formspec()) - end - - return false -end - -local function create_settings_formspec(tabview, name, tabdata) - local formspec = "tablecolumns[color;tree;text;text]" .. - "tableoptions[background=#00000000;border=false]" .. - "table[0,0;12,4.5;list_settings;" - - local current_level = 0 - for _, entry in ipairs(settings) do - local name - if not core.setting_getbool("main_menu_technical_settings") and entry.readable_name then - name = fgettext_ne(entry.readable_name) - else - name = entry.name - end - - if entry.type == "category" then - current_level = entry.level - formspec = formspec .. "#FFFF00," .. current_level .. "," .. fgettext(name) .. ",," - - elseif entry.type == "bool" then - local value = get_current_value(entry) - if core.is_yes(value) then - value = fgettext("Enabled") - else - value = fgettext("Disabled") - end - formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. "," - .. value .. "," - - elseif entry.type == "key" then - -- ignore key settings, since we have a special dialog for them - - else - formspec = formspec .. "," .. (current_level + 1) .. "," .. core.formspec_escape(name) .. "," - .. core.formspec_escape(get_current_value(entry)) .. "," - end - end - - if #settings > 0 then - formspec = formspec:sub(1, -2) -- remove trailing comma - end - formspec = formspec .. ";" .. selected_setting .. "]" .. - "button[4,4.5;3,1;btn_change_keys;".. fgettext("Change keys") .. "]" .. - "button[10,4.5;2,1;btn_edit;" .. fgettext("Edit") .. "]" .. - "button[7,4.5;3,1;btn_restore;" .. fgettext("Restore Default") .. "]" .. - "checkbox[0,4.5;cb_tech_settings;" .. fgettext("Show technical names") .. ";" - .. dump(core.setting_getbool("main_menu_technical_settings")) .. "]" - - return formspec + return tab_string end +-------------------------------------------------------------------------------- local function handle_settings_buttons(this, fields, tabname, tabdata) - local list_enter = false - if fields["list_settings"] then - selected_setting = core.get_table_index("list_settings") - if core.explode_table_event(fields["list_settings"]).type == "DCL" then - -- Directly toggle booleans - local setting = settings[selected_setting] - if setting.type == "bool" then - local current_value = get_current_value(setting) - core.setting_setbool(setting.name, not core.is_yes(current_value)) - core.setting_save() - return true - else - list_enter = true - end + + if fields["btn_advanced_settings"] ~= nil then + local adv_settings_dlg = create_adv_settings_dlg() + adv_settings_dlg:set_parent(this) + this:hide() + adv_settings_dlg:show() + --mm_texture.update("singleplayer", current_game()) + return true + end + + if fields["cb_smooth_lighting"] then + core.setting_set("smooth_lighting", fields["cb_smooth_lighting"]) + return true + end + if fields["cb_particles"] then + core.setting_set("enable_particles", fields["cb_particles"]) + return true + end + if fields["cb_3d_clouds"] then + core.setting_set("enable_3d_clouds", fields["cb_3d_clouds"]) + return true + end + if fields["cb_opaque_water"] then + core.setting_set("opaque_water", fields["cb_opaque_water"]) + return true + end + if fields["cb_connected_glass"] then + core.setting_set("connected_glass", fields["cb_connected_glass"]) + return true + end + if fields["cb_node_highlighting"] then + core.setting_set("enable_node_highlighting", fields["cb_node_highlighting"]) + return true + end + if fields["cb_shaders"] then + if (core.setting_get("video_driver") == "direct3d8" + or core.setting_get("video_driver") == "direct3d9") then + core.setting_set("enable_shaders", "false") + gamedata.errormessage = fgettext("To enable shaders the OpenGL driver needs to be used.") else + core.setting_set("enable_shaders", fields["cb_shaders"]) + end + return true + end + if fields["cb_bumpmapping"] then + core.setting_set("enable_bumpmapping", fields["cb_bumpmapping"]) + end + if fields["cb_generate_normalmaps"] then + core.setting_set("generate_normalmaps", fields["cb_generate_normalmaps"]) + end + if fields["cb_parallax"] then + core.setting_set("enable_parallax_occlusion", fields["cb_parallax"]) + return true + end + if fields["cb_waving_water"] then + core.setting_set("enable_waving_water", fields["cb_waving_water"]) + return true + end + if fields["cb_waving_leaves"] then + core.setting_set("enable_waving_leaves", fields["cb_waving_leaves"]) + end + if fields["cb_waving_plants"] then + core.setting_set("enable_waving_plants", fields["cb_waving_plants"]) + return true + end + + if fields["sb_gui_scaling"] then + local event = core.explode_scrollbar_event(fields["sb_gui_scaling"]) + + if event.type == "CHG" then + local tosave = string.format("%.2f",scrollbar_to_gui_scale(event.value)) + core.setting_set("gui_scaling", tosave) return true end end - if fields["btn_edit"] or list_enter then - local setting = settings[selected_setting] - if setting.type ~= "category" then - local edit_dialog = dialog_create("change_setting", create_change_setting_formspec, - handle_change_setting_buttons) - edit_dialog:set_parent(this) - this:hide() - edit_dialog:show() - end - return true - end - - if fields["btn_restore"] then - local setting = settings[selected_setting] - if setting.type ~= "category" then - core.setting_set(setting.name, setting.default) - core.setting_save() - core.update_formspec(this:get_formspec()) - end - return true - end - if fields["btn_change_keys"] then core.show_keys_menu() return true end - - if fields["cb_tech_settings"] then - core.setting_set("main_menu_technical_settings", fields["cb_tech_settings"]) - core.setting_save() - core.update_formspec(this:get_formspec()) + if fields["cb_touchscreen_target"] then + core.setting_set("touchtarget", fields["cb_touchscreen_target"]) + return true + end + if fields["btn_reset_singleplayer"] then + showconfirm_reset(this) return true end - return false + --Note dropdowns have to be handled LAST! + local ddhandled = false + + if fields["dd_leaves_style"] == leaves_style_labels[1] then + core.setting_set("leaves_style", leaves_style[2][1]) + ddhandled = true + elseif fields["dd_leaves_style"] == leaves_style_labels[2] then + core.setting_set("leaves_style", leaves_style[2][2]) + ddhandled = true + elseif fields["dd_leaves_style"] == leaves_style_labels[3] then + core.setting_set("leaves_style", leaves_style[2][3]) + ddhandled = true + end + if fields["dd_filters"] == dd_filter_labels[1] then + core.setting_set("bilinear_filter", "false") + core.setting_set("trilinear_filter", "false") + ddhandled = true + elseif fields["dd_filters"] == dd_filter_labels[2] then + core.setting_set("bilinear_filter", "true") + core.setting_set("trilinear_filter", "false") + ddhandled = true + elseif fields["dd_filters"] == dd_filter_labels[3] then + core.setting_set("bilinear_filter", "false") + core.setting_set("trilinear_filter", "true") + ddhandled = true + end + if fields["dd_mipmap"] == dd_mipmap_labels[1] then + core.setting_set("mip_map", "false") + core.setting_set("anisotropic_filter", "false") + ddhandled = true + elseif fields["dd_mipmap"] == dd_mipmap_labels[2] then + core.setting_set("mip_map", "true") + core.setting_set("anisotropic_filter", "false") + ddhandled = true + elseif fields["dd_mipmap"] == dd_mipmap_labels[3] then + core.setting_set("mip_map", "true") + core.setting_set("anisotropic_filter", "true") + ddhandled = true + end + if fields["dd_antialiasing"] then + core.setting_set("fsaa", + antialiasing_fname_to_name(fields["dd_antialiasing"])) + ddhandled = true + end + if fields["dd_touchthreshold"] then + core.setting_set("touchscreen_threshold",fields["dd_touchthreshold"]) + ddhandled = true + end + + return ddhandled end tab_settings = { name = "settings", caption = fgettext("Settings"), - cbf_formspec = create_settings_formspec, - cbf_button_handler = handle_settings_buttons, + cbf_formspec = formspec, + cbf_button_handler = handle_settings_buttons } - -local function create_minetest_conf_example() - local result = "# This file contains a list of all available settings and their default value for minetest.conf\n" .. - "\n" .. - "# By default, all the settings are commented and not functional.\n" .. - "# Uncomment settings by removing the preceding #.\n" .. - "\n" .. - "# minetest.conf is read by default from:\n" .. - "# ../minetest.conf\n" .. - "# ../../minetest.conf\n" .. - "# Any other path can be chosen by passing the path as a parameter\n" .. - "# to the program, eg. \"minetest.exe --config ../minetest.conf.example\".\n" .. - "\n" .. - "# Further documentation:\n" .. - "# http://wiki.minetest.net/\n" .. - "\n" - - local settings = parse_config_file(true, false) - for _, entry in ipairs(settings) do - if entry.type == "category" then - if entry.level == 0 then - result = result .. "#\n# " .. entry.name .. "\n#\n\n" - else - for i = 1, entry.level do - result = result .. "#" - end - result = result .. "# " .. entry.name .. "\n\n" - end - else - if entry.comment ~= "" then - for _, comment_line in ipairs(entry.comment:split("\n", true)) do - result = result .."# " .. comment_line .. "\n" - end - end - result = result .. "# type: " .. entry.type - if entry.min then - result = result .. " min: " .. entry.min - end - if entry.max then - result = result .. " max: " .. entry.max - end - if entry.values then - result = result .. " values: " .. table.concat(entry.values, ", ") - end - if entry.possible then - result = result .. " possible values: " .. entry.possible:gsub(",", ", ") - end - result = result .. "\n" - result = result .. "# " .. entry.name .. " = ".. entry.default .. "\n\n" - end - end - return result -end - -local function create_translation_file() - local result = "// This file is automatically generated\n" .. - "// It conatins a bunch of fake gettext calls, to tell xgettext about the strings in config files\n" .. - "// To update it, refer to the bottom of builtin/mainmenu/tab_settings.lua\n\n" .. - "fake_function() {\n" - - local settings = parse_config_file(true, false) - for _, entry in ipairs(settings) do - if entry.type == "category" then - local name_escaped = entry.name:gsub("\"", "\\\"") - result = result .. "\tgettext(\"" .. name_escaped .. "\");\n" - else - if entry.readable_name then - local readable_name_escaped = entry.readable_name:gsub("\"", "\\\"") - result = result .. "\tgettext(\"" .. readable_name_escaped .. "\");\n" - end - if entry.comment ~= "" then - local comment_escaped = entry.comment:gsub("\n", "\\n") - comment_escaped = comment_escaped:gsub("\"", "\\\"") - result = result .. "\tgettext(\"" .. comment_escaped .. "\");\n" - end - end - end - result = result .. "}\n" - return result -end - -if false then - local file = io.open("minetest.conf.example", "w") - if file then - file:write(create_minetest_conf_example()) - file:close() - end -end - -if false then - local file = io.open("src/settings_translation_file.cpp", "w") - if file then - file:write(create_translation_file()) - file:close() - end -end