dofile(core.get_builtin_path().."common/settings/settingtypes.lua") -- Some categories, like Accessibility and Theme, do not appear -- in the builtin settingtypes.txt, so they are added to the state table here. local function inject_settings(state) -- Theme table.insert(state.categories, 1, "Theme") state.settings.Theme = { { comment = "The background color of containers.", context = "client", default = "#fff", name = "theme.container_bg_color", readable_name = "Container background color", requires = {}, type = "string", value = imfs.state("#fff") } } -- Accessibility table.insert(state.categories, 2, "Accessibility") state.settings.Accessibility = { { comment = "Smooths rotation of camera, also called look or mouse smoothing. 0 to disable.", context = "client", default = "0.0", max = 0.99, min = 0, name = "camera_smoothing", readable_name = "Camera smoothing", requires = {}, type = "float", value = imfs.state("0.0") } } end local function search_settings(state, search) if state.search == "" then return state.settings, state.categories end local words = search:lower():trim():split(" ") local out = {} for category, settings in pairs(state.settings) do for i = 1, #settings do for j = 1, #words do local passed = true if not (settings[i].readable_name:lower():find(words[j], 1, true) or settings[i].name:find(words[j], 1, true)) then passed = false end if passed then if not out[category] then out[category] = {settings[i]} else table.insert(out[category], settings[i]) end end end end end local categories = {} for i = 1, #state.categories do local category = state.categories[i] if category.name then for j = 1, #state.categories do if out[category[j]] then if not categories[category.name] then table.insert(categories, {name = category.name}) end table.insert(categories[#categories], category[j]) break end end else if out[category] then table.insert(categories, category) break end end end return out, categories end return function(state) imfs.begin(size.x, size.y) :padding(0, 0) :bgcolor(theme.styles.bg_color, true) if not state.settings then state.settings = {} state.categories = {} local category local settings = settingtypes.parse_config_file(false, false) for _, x in ipairs(settings) do if x.type == "category" then if x.level == 0 then state.categories[#state.categories + 1] = {name = x.name} elseif x.level == 1 then local group = state.categories[#state.categories] group[#group + 1] = x.name state.settings[x.name] = {} category = x.name end else local s = state.settings[category] x.value = imfs.state() if x.type == "string" or x.type == "float" or x.type == "int" or x.type == "enum" then x.value._val = minetest.settings:get(x.name) or x.default elseif x.type == "bool" then x.value._val = minetest.settings:get_bool(x.name, x.default) end s[#s +1] = x end end inject_settings(state) state.settings_shown._val = state.settings state.categories_shown._val = state.categories end imfs.box(0, 0, "100%", 1, theme.styles.container.bg_color) imfs.row(0.2, 0.125, "100% - 0.4", 0.75) :gap(0.1) theme.field(0, 0, "1x", "100%", state.search) :onchange(function(value) state.search = value end) :onenter(function() local settings, categories = search_settings(state, state.search) if categories[1] then local first = categories[1].name and categories[1][1] or categories[1] state.category(first) end state.categories_shown(categories) state.settings_shown(settings) end) imfs.button(0, 0, 0.75, 0.75) :image(theme.icon("search")) :style({ bgimg = theme.get_background_image("button"), bgimg_middle = theme.styles.button.border_width, }) :tooltip("Search settings") :onclick(function() local settings, categories = search_settings(state, state.search) if categories[1] then local first = categories[1].name and categories[1][1] or categories[1] state.category(first) end state.categories_shown(categories) state.settings_shown(settings) end) imfs.button(0, 0, 0.75, 0.75) :image(theme.icon("cancel")) :style({ bgimg = theme.get_background_image("button"), bgimg_middle = theme.styles.button.border_width, }) :tooltip("Clear search") :onclick(function() state.search = "" state.settings_shown(state.settings) state.categories_shown(state.categories) end) imfs.button(0, 0, 2, "100%", "Back") :onclick(function() show_meta_menu() end) imfs.row_end() imfs.box(0, 1, "20%", "100% - 1", theme.styles.container.bg_color) imfs.box(0, 0.95, "100%", 0.1, theme.styles.container.border_color) imfs.scroll_container(0.2, 1.05, "20% - 0.45", "100% - 1.05") local categories = state.categories_shown() if categories then local y = 0.1 for i = 1, #categories do local group = categories[i] if not group then break end -- Top-level categories. if type(group) == "string" then imfs.button(0, y, "100%", 0.5, group) :onclick(function() if state.category() ~= group then state.category(group) end end) y = y + 0.55 -- Grouped categories. else imfs.arealabel(0, y + 0.125, "100%", 0.375, group.name) y = y + 0.425 local h = 0 for j = 1, #group do local category = group[j] imfs.box(0.12, y + 0.245, 0.25, 0.01, theme.styles.text_color) imfs.button(0.25, y, "100% - 0.25", 0.5, category) :onclick(function() if state.category() ~= category then state.category(category) end end) h = h + 0.55 y = y + 0.55 end imfs.box(0.12, y - h, 0.01, h - 0.3, theme.styles.text_color) end end end imfs.scroll_container_end() imfs.box("20% - 0.05", 1, 0.1, "100% - 1", theme.styles.container.border_color) imfs.scroll_container("20% + 0.25", 1.05, "80% - 0.45", "100% - 1.05") imfs.column(0, 0, "100%", 1000) :gap(0.1) local settings = state.settings_shown()[state.category()] if settings then for i = 1, #settings do local setting = settings[i] if not setting then break end if setting.type == "bool" then local active = minetest.settings:get_bool(setting.name, setting.default) theme.checkbox(0, 0, setting.readable_name, setting.value, setting.comment) elseif setting.type == "float" or setting.type == "int" then imfs.arealabel(0, 0, "100%", 0.325, setting.readable_name) imfs.row(0, 0, "100%", 0.75) :gap(0.1) theme.number_field(0, 0, "1x", 0.75, setting.value) :tooltip(setting.comment) imfs.button(0, 0, 2, 0.75, "Set") imfs.row_end() elseif setting.type == "string" then imfs.arealabel(0, 0, "100%", 0.325, setting.readable_name) imfs.row(0, 0, "100%", 0.75) :gap(0.1) theme.field(0, 0, "1x", 0.75, setting.value) :tooltip(setting.comment) if setting.value._val ~= setting.default then imfs.button(0, 0, 0.75, 0.75) :image(theme.icon("refresh")) :style({ bgimg = theme.get_background_image("button"), bgimg_middle = theme.styles.button.border_width, }) :tooltip("Reset to default") end imfs.button(0, 0, 2, 0.75, "Set") imfs.row_end() elseif setting.type == "enum" then imfs.scope(setting.name) imfs.arealabel(0, 0, "100%", 0.325, setting.readable_name) imfs.row(0, 0, "100%", "fit") :gap(0.1) theme.dropdown(0, 0, "1x", 0.75, setting.values, setting.value) :tooltip(setting.comment) imfs.button(0, 0, 2, 0.75, "Set") imfs.row_end() imfs.scope_end() else print(dump(setting)) end end end imfs.column_end() imfs.scroll_container_end() return imfs.end_() end