Skip to content

Commit

Permalink
Settings GUI: Add setting dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenwardy committed Aug 5, 2023
1 parent 752ce1a commit 212affa
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
end_of_line = lf

[*.{cpp,h,lua,txt,glsl,md,c,cmake,java,gradle}]
charset = utf8
charset = utf-8
indent_size = 4
indent_style = tab
insert_final_newline = true
Expand Down
140 changes: 114 additions & 26 deletions builtin/mainmenu/settings/dlg_settings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ end

local change_keys = {
query_text = "Change keys",
requires = {
keyboard_mouse = true,
},
get_formspec = function(self, avail_w)
local btn_w = math.min(avail_w, 3)
return ("button[0,0;%f,0.8;btn_change_keys;%s]"):format(btn_w, fgettext("Change keys")), 0.8
Expand Down Expand Up @@ -173,7 +176,7 @@ end

local function filter_page_content(page, query_keywords)
if #query_keywords == 0 then
return page.content
return page.content, 0
end

local retval = {}
Expand Down Expand Up @@ -209,12 +212,6 @@ local function update_filtered_pages(query)
filtered_pages = {}
filtered_page_by_id = {}

if query == "" or query == nil then
filtered_pages = all_pages
filtered_page_by_id = page_by_id
return filtered_pages[1].id
end

local query_keywords = {}
for word in query:lower():gmatch("%S+") do
table.insert(query_keywords, word)
Expand All @@ -225,7 +222,7 @@ local function update_filtered_pages(query)

for _, page in ipairs(all_pages) do
local content, page_weight = filter_page_content(page, query_keywords)
if #content > 0 then
if page_has_contents(content) then
local new_page = table.copy(page)
new_page.content = content

Expand All @@ -243,28 +240,113 @@ local function update_filtered_pages(query)
end


local function check_requirements(name, requires)
if requires == nil then
return true
end

local video_driver = core.get_active_driver()
local shaders_support = video_driver == "opengl" or video_driver == "ogles2"
local special = {
android = PLATFORM == "Android",
desktop = PLATFORM ~= "Android",
touchscreen_gui = TOUCHSCREEN_GUI,
keyboard_mouse = not TOUCHSCREEN_GUI,
shaders_support = shaders_support,
shaders = core.settings:get_bool("enable_shaders") and shaders_support,
opengl = video_driver == "opengl",
gles = video_driver:sub(1, 5) == "ogles",
}

for req_key, req_value in pairs(requires) do
if special[req_key] == nil then
local required_setting = get_setting_info(req_key)
if required_setting == nil then
core.log("warning", "Unknown setting " .. req_key .. " required by " .. name)
end
local actual_value = core.settings:get_bool(req_key,
required_setting and core.is_yes(required_setting.default))
if actual_value ~= req_value then
return false
end
elseif special[req_key] ~= req_value then
return false
end
end

return true
end


function page_has_contents(content)
for _, item in ipairs(content) do
if item == false or item.heading then --luacheck: ignore
-- skip
elseif type(item) == "string" then
local setting = get_setting_info(item)
assert(setting, "Unknown setting: " .. item)
if check_requirements(setting.name, setting.requires) then
return true
end
elseif item.get_formspec then
if check_requirements(item.id, item.requires) then
return true
end
else
error("Unknown content in page: " .. dump(item))
end
end

return false
end


local function build_page_components(page)
local retval = {}
local j = 1
for i, content in ipairs(page.content) do
if content == false then
-- false is used to disable components conditionally (ie: Android specific)
j = j - 1
elseif type(content) == "string" then
local setting = get_setting_info(content)
assert(setting, "Unknown setting: " .. content)
-- Filter settings based on requirements
local content = {}
local last_heading
for _, item in ipairs(page.content) do
if item == false then --luacheck: ignore
-- skip
elseif item.heading then
last_heading = item
else
local name, requires
if type(item) == "string" then
local setting = get_setting_info(item)
assert(setting, "Unknown setting: " .. item)
name = setting.name
requires = setting.requires
elseif item.get_formspec then
name = item.id
requires = item.requires
else
error("Unknown content in page: " .. dump(item))
end

if check_requirements(name, requires) then
if last_heading then
content[#content + 1] = last_heading
last_heading = nil
end
content[#content + 1] = item
end
end
end

-- Create components
local retval = {}
for i, item in ipairs(content) do
if type(item) == "string" then
local setting = get_setting_info(item)
local component_func = component_funcs[setting.type]
assert(component_func, "Unknown setting type: " .. setting.type)
retval[j] = component_func(setting)
elseif content.get_formspec then
retval[j] = content
elseif content.heading then
retval[j] = component_funcs.heading(content.heading)
else
error("Unknown content in page: " .. dump(content))
retval[i] = component_func(setting)
elseif item.get_formspec then
retval[i] = item
elseif item.heading then
retval[i] = component_funcs.heading(item.heading)
end
j = j + 1
end
return retval
end
Expand Down Expand Up @@ -343,7 +425,8 @@ local function get_formspec(dialogdata)
local last_section = nil
for _, other_page in ipairs(filtered_pages) do
if other_page.section ~= last_section then
fs[#fs + 1] = ("label[0.1,%f;%s]"):format(y + 0.41, core.colorize("#ff0", fgettext(other_page.section)))
fs[#fs + 1] = ("label[0.1,%f;%s]"):format(
y + 0.41, core.colorize("#ff0", fgettext(other_page.section)))
last_section = other_page.section
y = y + 0.82
end
Expand Down Expand Up @@ -487,10 +570,15 @@ local function buttonhandler(this, fields)

for i, comp in ipairs(dialogdata.components) do
if comp.on_submit and comp:on_submit(fields, this) then
-- Clear components so they regenerate
dialogdata.components = nil
return true
end
if comp.setting and fields["reset_" .. i] then
core.settings:remove(comp.setting.name)

-- Clear components so they regenerate
dialogdata.components = nil
return true
end
end
Expand Down
53 changes: 38 additions & 15 deletions builtin/mainmenu/settings/settingtypes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,14 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
-- 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
settings.current_comment[#settings.current_comment + 1] = comment
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 = ""
settings.current_comment = {}

-- empty lines
if line:match("^" .. CHAR_CLASSES.SPACE .. "*$") then
Expand Down Expand Up @@ -103,6 +99,25 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
return "Tried to add \"secure.\" setting"
end

local requires = {}
local last_line = #current_comment > 0 and current_comment[#current_comment]:trim()
if last_line and last_line:lower():sub(1, 9) == "requires:" then
local parts = last_line:sub(10):split(",")
current_comment[#current_comment] = nil

for _, part in ipairs(parts) do
part = part:trim()

local value = true
if part:sub(1, 1) == "!" then
value = false
part = part:sub(2):trim()
end

requires[part] = value
end
end

if readable_name == "" then
readable_name = nil
end
Expand All @@ -129,7 +144,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
default = default,
min = min,
max = max,
comment = current_comment,
requires = requires,
comment = table.concat(current_comment, "\n"):trim(),
})
return
end
Expand All @@ -151,7 +167,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
readable_name = readable_name,
type = setting_type,
default = default,
comment = current_comment,
requires = requires,
comment = table.concat(current_comment, "\n"):trim(),
})
return
end
Expand Down Expand Up @@ -203,7 +220,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
flags = values[10]
},
values = values,
comment = current_comment,
requires = requires,
comment = table.concat(current_comment, "\n"):trim(),
noise_params = true,
flags = flags_to_table("defaults,eased,absvalue")
})
Expand All @@ -220,7 +238,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
readable_name = readable_name,
type = "bool",
default = remaining_line,
comment = current_comment,
requires = requires,
comment = table.concat(current_comment, "\n"):trim(),
})
return
end
Expand All @@ -246,7 +265,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
default = default,
min = min,
max = max,
comment = current_comment,
requires = requires,
comment = table.concat(current_comment, "\n"):trim(),
})
return
end
Expand All @@ -268,7 +288,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
type = "enum",
default = default,
values = values:split(",", true),
comment = current_comment,
requires = requires,
comment = table.concat(current_comment, "\n"):trim(),
})
return
end
Expand All @@ -285,7 +306,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
readable_name = readable_name,
type = setting_type,
default = default,
comment = current_comment,
requires = requires,
comment = table.concat(current_comment, "\n"):trim(),
})
return
end
Expand Down Expand Up @@ -314,7 +336,8 @@ local function parse_setting_line(settings, line, read_all, base_level, allow_se
type = "flags",
default = default,
possible = flags_to_table(possible),
comment = current_comment,
requires = requires,
comment = table.concat(current_comment, "\n"):trim(),
})
return
end
Expand All @@ -324,7 +347,7 @@ 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 = ""
result.current_comment = {}

local line = file:read("*line")
while line do
Expand Down

0 comments on commit 212affa

Please sign in to comment.