2022-03-07 20:28:05 +00:00
|
|
|
local ui = require('openmw.ui')
|
|
|
|
local util = require('openmw.util')
|
2022-04-13 18:08:33 +00:00
|
|
|
local async = require('openmw.async')
|
2022-04-16 08:41:20 +00:00
|
|
|
local core = require('openmw.core')
|
2022-04-27 19:28:16 +00:00
|
|
|
local storage = require('openmw.storage')
|
2022-03-07 20:28:05 +00:00
|
|
|
|
|
|
|
local common = require('scripts.omw.settings.common')
|
|
|
|
|
|
|
|
local renderers = {}
|
|
|
|
local function registerRenderer(name, renderFunction)
|
|
|
|
renderers[name] = renderFunction
|
|
|
|
end
|
|
|
|
|
2022-04-29 17:35:01 +00:00
|
|
|
local pages = {}
|
2022-04-27 19:28:16 +00:00
|
|
|
local groups = {}
|
|
|
|
local pageOptions = {}
|
2022-04-16 08:41:20 +00:00
|
|
|
|
|
|
|
local padding = function(size)
|
|
|
|
return {
|
|
|
|
props = {
|
|
|
|
size = util.vector2(size, size),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
2022-04-27 19:28:16 +00:00
|
|
|
local smallPadding = padding(10)
|
|
|
|
local bigPadding = padding(25)
|
2022-04-16 08:41:20 +00:00
|
|
|
|
2022-04-27 19:28:16 +00:00
|
|
|
local pageHeader = {
|
2022-04-16 08:41:20 +00:00
|
|
|
props = {
|
|
|
|
textColor = util.color.rgb(1, 1, 1),
|
|
|
|
textSize = 30,
|
|
|
|
},
|
|
|
|
}
|
2022-04-27 19:28:16 +00:00
|
|
|
local groupHeader = {
|
2022-04-16 08:41:20 +00:00
|
|
|
props = {
|
|
|
|
textColor = util.color.rgb(1, 1, 1),
|
|
|
|
textSize = 25,
|
|
|
|
},
|
|
|
|
}
|
2022-04-27 19:28:16 +00:00
|
|
|
local normal = {
|
|
|
|
props = {
|
|
|
|
textColor = util.color.rgb(1, 1, 1),
|
|
|
|
textSize = 20,
|
|
|
|
},
|
|
|
|
}
|
2022-03-07 20:28:05 +00:00
|
|
|
|
2022-04-27 19:28:16 +00:00
|
|
|
local function renderSetting(group, setting, value, global)
|
2022-03-07 20:28:05 +00:00
|
|
|
local renderFunction = renderers[setting.renderer]
|
|
|
|
if not renderFunction then
|
2022-04-27 19:28:16 +00:00
|
|
|
error(('Setting %s of %s has unknown renderer %s'):format(setting.key, group.key, setting.renderer))
|
2022-03-07 20:28:05 +00:00
|
|
|
end
|
2022-04-13 18:08:33 +00:00
|
|
|
local set = function(value)
|
2022-04-27 19:28:16 +00:00
|
|
|
if global then
|
|
|
|
core.sendGlobalEvent(common.setGlobalEvent, {
|
|
|
|
groupKey = group.key,
|
|
|
|
settingKey = setting.key,
|
|
|
|
value = value,
|
|
|
|
})
|
|
|
|
else
|
|
|
|
storage.playerSection(group.key):set(setting.key, value)
|
|
|
|
end
|
2022-04-13 18:08:33 +00:00
|
|
|
end
|
2022-04-27 19:28:16 +00:00
|
|
|
local l10n = core.l10n(group.l10n)
|
|
|
|
return {
|
2022-04-13 18:08:33 +00:00
|
|
|
name = setting.key,
|
|
|
|
type = ui.TYPE.Flex,
|
|
|
|
content = ui.content {
|
|
|
|
{
|
2022-04-16 08:41:20 +00:00
|
|
|
type = ui.TYPE.Flex,
|
2022-04-13 18:08:33 +00:00
|
|
|
props = {
|
2022-04-16 08:41:20 +00:00
|
|
|
horizontal = true,
|
|
|
|
align = ui.ALIGNMENT.Start,
|
|
|
|
arrange = ui.ALIGNMENT.End,
|
2022-04-13 18:08:33 +00:00
|
|
|
},
|
2022-04-16 08:41:20 +00:00
|
|
|
content = ui.content {
|
|
|
|
{
|
|
|
|
type = ui.TYPE.Text,
|
|
|
|
template = normal,
|
|
|
|
props = {
|
2022-04-27 19:28:16 +00:00
|
|
|
text = l10n(setting.name),
|
2022-04-16 08:41:20 +00:00
|
|
|
},
|
|
|
|
},
|
2022-04-27 19:28:16 +00:00
|
|
|
smallPadding,
|
2022-04-16 08:41:20 +00:00
|
|
|
renderFunction(value, set, setting.argument),
|
2022-04-27 19:28:16 +00:00
|
|
|
smallPadding,
|
2022-04-16 08:41:20 +00:00
|
|
|
{
|
|
|
|
type = ui.TYPE.Text,
|
|
|
|
template = normal,
|
|
|
|
props = {
|
|
|
|
text = 'Reset',
|
|
|
|
},
|
|
|
|
events = {
|
|
|
|
mouseClick = async:callback(function()
|
|
|
|
set(setting.default)
|
|
|
|
end),
|
|
|
|
},
|
|
|
|
},
|
2022-04-13 18:08:33 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2022-03-07 20:28:05 +00:00
|
|
|
end
|
|
|
|
|
2022-04-27 19:28:16 +00:00
|
|
|
local groupLayoutName = function(key, global)
|
|
|
|
return ('%s%s'):format(global and 'global_' or 'player_', key)
|
|
|
|
end
|
|
|
|
|
|
|
|
local function renderGroup(group, global)
|
|
|
|
local l10n = core.l10n(group.l10n)
|
|
|
|
local layout = {
|
|
|
|
name = groupLayoutName(group.key, global),
|
2022-04-09 17:58:32 +00:00
|
|
|
type = ui.TYPE.Flex,
|
|
|
|
content = ui.content {
|
|
|
|
{
|
2022-04-16 08:41:20 +00:00
|
|
|
type = ui.TYPE.Flex,
|
2022-04-09 17:58:32 +00:00
|
|
|
props = {
|
2022-04-16 08:41:20 +00:00
|
|
|
horizontal = true,
|
|
|
|
align = ui.ALIGNMENT.Start,
|
2022-04-27 20:05:39 +00:00
|
|
|
arrange = ui.ALIGNMENT.End,
|
2022-04-16 08:41:20 +00:00
|
|
|
},
|
|
|
|
content = ui.content {
|
|
|
|
{
|
|
|
|
name = 'name',
|
|
|
|
type = ui.TYPE.Text,
|
2022-04-27 19:28:16 +00:00
|
|
|
template = groupHeader,
|
2022-04-16 08:41:20 +00:00
|
|
|
props = {
|
2022-04-27 19:28:16 +00:00
|
|
|
text = l10n(group.name),
|
2022-04-16 08:41:20 +00:00
|
|
|
},
|
|
|
|
},
|
2022-04-27 19:28:16 +00:00
|
|
|
smallPadding,
|
2022-04-16 08:41:20 +00:00
|
|
|
{
|
|
|
|
name = 'description',
|
|
|
|
type = ui.TYPE.Text,
|
|
|
|
template = normal,
|
|
|
|
props = {
|
2022-04-27 19:28:16 +00:00
|
|
|
text = l10n(group.description),
|
2022-04-16 08:41:20 +00:00
|
|
|
},
|
|
|
|
},
|
2022-04-09 17:58:32 +00:00
|
|
|
},
|
|
|
|
},
|
2022-04-27 19:28:16 +00:00
|
|
|
smallPadding,
|
2022-04-13 18:08:33 +00:00
|
|
|
{
|
|
|
|
name = 'settings',
|
|
|
|
type = ui.TYPE.Flex,
|
|
|
|
content = ui.content{},
|
|
|
|
},
|
2022-04-27 19:28:16 +00:00
|
|
|
bigPadding,
|
2022-04-09 17:58:32 +00:00
|
|
|
},
|
|
|
|
}
|
2022-04-27 19:28:16 +00:00
|
|
|
local settingsContent = layout.content.settings.content
|
|
|
|
local valueSection = common.getSection(global, group.key)
|
2022-04-16 08:41:20 +00:00
|
|
|
for _, setting in pairs(group.settings) do
|
2022-04-27 19:28:16 +00:00
|
|
|
settingsContent:add(renderSetting(group, setting, valueSection:get(setting.key), global))
|
2022-04-16 08:41:20 +00:00
|
|
|
end
|
2022-04-27 19:28:16 +00:00
|
|
|
return layout
|
2022-04-16 08:41:20 +00:00
|
|
|
end
|
|
|
|
|
2022-04-29 17:23:20 +00:00
|
|
|
local function pageGroupComparator(a, b)
|
|
|
|
return a.order < b.order or (
|
|
|
|
a.order == b.order and a.key < b.key
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2022-04-29 17:35:01 +00:00
|
|
|
local function generateSearchHints(page)
|
|
|
|
local hints = {}
|
|
|
|
local l10n = core.l10n(page.l10n)
|
|
|
|
table.insert(hints, l10n(page.name))
|
|
|
|
table.insert(hints, l10n(page.description))
|
|
|
|
local pageGroups = groups[page.key]
|
|
|
|
for _, pageGroup in pairs(pageGroups) do
|
|
|
|
local group = common.getSection(pageGroup.global, common.groupSectionKey):get(pageGroup.key)
|
|
|
|
local l10n = core.l10n(group.l10n)
|
|
|
|
table.insert(hints, l10n(group.name))
|
|
|
|
table.insert(hints, l10n(group.description))
|
|
|
|
for _, setting in pairs(group.settings) do
|
|
|
|
table.insert(hints, l10n(setting.name))
|
|
|
|
table.insert(hints, l10n(setting.description))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return table.concat(hints, ' ')
|
|
|
|
end
|
|
|
|
|
2022-04-27 19:28:16 +00:00
|
|
|
local function renderPage(page)
|
|
|
|
local l10n = core.l10n(page.l10n)
|
|
|
|
local layout = {
|
|
|
|
name = page.key,
|
|
|
|
type = ui.TYPE.Flex,
|
|
|
|
content = ui.content {
|
|
|
|
smallPadding,
|
|
|
|
{
|
|
|
|
type = ui.TYPE.Flex,
|
|
|
|
props = {
|
|
|
|
horizontal = true,
|
|
|
|
align = ui.ALIGNMENT.Start,
|
2022-04-27 20:05:39 +00:00
|
|
|
arrange = ui.ALIGNMENT.End,
|
2022-04-27 19:28:16 +00:00
|
|
|
},
|
|
|
|
content = ui.content {
|
|
|
|
{
|
|
|
|
name = 'name',
|
|
|
|
type = ui.TYPE.Text,
|
|
|
|
template = pageHeader,
|
|
|
|
props = {
|
|
|
|
text = l10n(page.name),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
smallPadding,
|
|
|
|
{
|
|
|
|
name = 'description',
|
|
|
|
type = ui.TYPE.Text,
|
|
|
|
template = normal,
|
|
|
|
props = {
|
|
|
|
text = l10n(page.description),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
bigPadding,
|
|
|
|
{
|
|
|
|
name = 'groups',
|
|
|
|
type = ui.TYPE.Flex,
|
|
|
|
content = ui.content {},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
local groupsContent = layout.content.groups.content
|
2022-04-29 17:23:20 +00:00
|
|
|
local pageGroups = groups[page.key]
|
|
|
|
local sortedGroups = {}
|
|
|
|
for i, v in ipairs(pageGroups) do sortedGroups[i] = v end
|
|
|
|
table.sort(sortedGroups, pageGroupComparator)
|
|
|
|
for _, pageGroup in ipairs(sortedGroups) do
|
2022-04-27 19:28:16 +00:00
|
|
|
local group = common.getSection(pageGroup.global, common.groupSectionKey):get(pageGroup.key)
|
|
|
|
groupsContent:add(renderGroup(group, pageGroup.global))
|
|
|
|
end
|
|
|
|
return {
|
|
|
|
name = l10n(page.name),
|
|
|
|
element = ui.create(layout),
|
2022-04-29 17:35:01 +00:00
|
|
|
searchHints = generateSearchHints(page),
|
2022-03-07 20:28:05 +00:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2022-04-27 19:28:16 +00:00
|
|
|
local function onSettingChanged(global)
|
|
|
|
return async:callback(function(groupKey, settingKey)
|
|
|
|
local group = common.getSection(global, common.groupSectionKey):get(groupKey)
|
|
|
|
if not pageOptions[group.page] then return end
|
|
|
|
|
|
|
|
local element = pageOptions[group.page].element
|
|
|
|
local groupLayout = element.layout.content.groups.content[groupLayoutName(group.key, global)]
|
|
|
|
local settingsLayout = groupLayout.content.settings
|
|
|
|
local value = common.getSection(global, group.key):get(settingKey)
|
|
|
|
settingsLayout.content[settingKey] = renderSetting(group, group.settings[settingKey], value, global)
|
|
|
|
element:update()
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
local function onGroupRegistered(global, key)
|
|
|
|
local group = common.getSection(global, common.groupSectionKey):get(key)
|
|
|
|
groups[group.page] = groups[group.page] or {}
|
2022-04-29 17:23:20 +00:00
|
|
|
local pageGroup = {
|
2022-04-27 19:28:16 +00:00
|
|
|
key = group.key,
|
|
|
|
global = global,
|
2022-04-29 17:23:20 +00:00
|
|
|
order = group.order,
|
|
|
|
}
|
|
|
|
table.insert(groups[group.page], pageGroup)
|
2022-04-27 19:28:16 +00:00
|
|
|
common.getSection(global, group.key):subscribe(onSettingChanged(global))
|
|
|
|
|
2022-04-29 17:35:01 +00:00
|
|
|
if not pages[group.page] then return end
|
|
|
|
local options = renderPage(pages[group.page])
|
|
|
|
pageOptions[group.page].element:destroy()
|
|
|
|
for k, v in pairs(options) do
|
|
|
|
pageOptions[group.page][k] = v
|
2022-04-29 17:23:20 +00:00
|
|
|
end
|
2022-04-27 19:28:16 +00:00
|
|
|
end
|
|
|
|
local globalGroups = storage.globalSection(common.groupSectionKey)
|
|
|
|
for groupKey in pairs(globalGroups:asTable()) do
|
|
|
|
onGroupRegistered(true, groupKey)
|
|
|
|
end
|
|
|
|
globalGroups:subscribe(async:callback(function(_, key)
|
|
|
|
if key then onGroupRegistered(true, key) end
|
|
|
|
end))
|
|
|
|
storage.playerSection(common.groupSectionKey):subscribe(async:callback(function(_, key)
|
|
|
|
if key then onGroupRegistered(false, key) end
|
|
|
|
end))
|
|
|
|
|
|
|
|
local function registerPage(options)
|
2022-04-29 16:56:37 +00:00
|
|
|
if type(options) ~= 'table' then
|
|
|
|
error('Page options must be a table')
|
|
|
|
end
|
2022-04-27 19:28:16 +00:00
|
|
|
if type(options.key) ~= 'string' then
|
|
|
|
error('Page must have a key')
|
|
|
|
end
|
|
|
|
if type(options.l10n) ~= 'string' then
|
|
|
|
error('Page must have a localization context')
|
|
|
|
end
|
|
|
|
if type(options.name) ~= 'string' then
|
|
|
|
error('Page must have a name')
|
|
|
|
end
|
|
|
|
if type(options.description) ~= 'string' then
|
|
|
|
error('Page must have a description')
|
|
|
|
end
|
|
|
|
local page = {
|
|
|
|
key = options.key,
|
|
|
|
l10n = options.l10n,
|
|
|
|
name = options.name,
|
|
|
|
description = options.description,
|
|
|
|
}
|
2022-04-29 17:35:01 +00:00
|
|
|
pages[page.key] = page
|
2022-04-27 19:28:16 +00:00
|
|
|
groups[page.key] = groups[page.key] or {}
|
|
|
|
pageOptions[page.key] = renderPage(page)
|
|
|
|
ui.registerSettingsPage(pageOptions[page.key])
|
2022-04-18 06:42:02 +00:00
|
|
|
end
|
|
|
|
|
2022-03-07 20:28:05 +00:00
|
|
|
return {
|
2022-04-27 19:28:16 +00:00
|
|
|
registerPage = registerPage,
|
2022-03-07 20:28:05 +00:00
|
|
|
registerRenderer = registerRenderer,
|
|
|
|
}
|