1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-31 18:45:36 +00:00
openmw/files/data/scripts/omw/settings/render.lua

424 lines
13 KiB
Lua
Raw Normal View History

2022-03-07 20:28:05 +00:00
local ui = require('openmw.ui')
local util = require('openmw.util')
local async = require('openmw.async')
local core = require('openmw.core')
local storage = require('openmw.storage')
2022-05-14 10:27:30 +00:00
local I = require('openmw.interfaces')
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-05-24 19:11:13 +00:00
local interfaceL10n = core.l10n('Interface')
2022-04-29 17:35:01 +00:00
local pages = {}
local groups = {}
local pageOptions = {}
2022-05-14 10:27:30 +00:00
local interval = { template = I.MWUI.templates.interval }
local growingIntreval = {
template = I.MWUI.templates.interval,
external = {
grow = 1,
},
}
2022-05-14 10:27:30 +00:00
local spacer = {
props = {
2022-05-14 10:27:30 +00:00
size = util.vector2(0, 10),
},
}
2022-05-14 10:27:30 +00:00
local bigSpacer = {
props = {
2022-05-14 10:27:30 +00:00
size = util.vector2(0, 50),
},
}
local stretchingLine = {
template = I.MWUI.templates.horizontalLine,
external = {
stretch = 1,
},
}
2022-05-14 10:27:30 +00:00
local spacedLines = function(count)
local content = {}
table.insert(content, spacer)
table.insert(content, stretchingLine)
for i = 2, count do
table.insert(content, interval)
table.insert(content, stretchingLine)
end
table.insert(content, spacer)
return {
type = ui.TYPE.Flex,
external = {
stretch = 1,
},
content = ui.content(content),
}
end
local function interlaceSeparator(layouts, separator)
local result = {}
result[1] = layouts[1]
for i = 2, #layouts do
table.insert(result, separator)
table.insert(result, layouts[i])
end
return result
end
local function setSettingValue(global, groupKey, settingKey, value)
if global then
core.sendGlobalEvent(common.setGlobalEvent, {
groupKey = groupKey,
settingKey = settingKey,
value = value,
})
else
storage.playerSection(groupKey):set(settingKey, value)
end
end
2022-03-07 20:28:05 +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
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
local set = function(value)
2022-05-14 10:27:30 +00:00
setSettingValue(global, group.key, setting.key, value)
end
local l10n = core.l10n(group.l10n)
2022-05-14 10:27:30 +00:00
local titleLayout = {
type = ui.TYPE.Flex,
content = ui.content {
{
2022-05-14 10:27:30 +00:00
template = I.MWUI.templates.textNormal,
props = {
2022-05-14 10:27:30 +00:00
text = l10n(setting.name),
textSize = 18,
},
2022-05-14 10:27:30 +00:00
},
},
}
if setting.description then
titleLayout.content:add(interval)
titleLayout.content:add {
template = I.MWUI.templates.textNormal,
props = {
text = l10n(setting.description),
textSize = 16,
},
}
end
2022-05-19 19:49:14 +00:00
local argument = common.getArgumentSection(global, group.key):get(setting.key)
2022-05-14 10:27:30 +00:00
return {
name = setting.key,
type = ui.TYPE.Flex,
props = {
horizontal = true,
arrange = ui.ALIGNMENT.Center,
},
external = {
stretch = 1,
},
content = ui.content {
titleLayout,
growingIntreval,
2022-05-19 19:49:14 +00:00
renderFunction(value, set, argument),
2022-05-14 10:27:30 +00:00
},
}
end
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 valueSection = common.getSection(global, group.key)
local settingLayouts = {}
local sortedSettings = {}
for _, setting in pairs(group.settings) do
sortedSettings[setting.order] = setting
end
for _, setting in ipairs(sortedSettings) do
table.insert(settingLayouts, renderSetting(group, setting, valueSection:get(setting.key), global))
end
local settingsContent = ui.content(interlaceSeparator(settingLayouts, spacedLines(1)))
local resetButtonLayout = {
template = I.MWUI.templates.box,
content = ui.content {
{
template = I.MWUI.templates.padding,
content = ui.content {
{
2022-05-14 10:27:30 +00:00
template = I.MWUI.templates.textNormal,
props = {
2022-05-24 19:11:13 +00:00
text = interfaceL10n('Reset')
},
events = {
mouseClick = async:callback(function()
2022-05-14 10:27:30 +00:00
for _, setting in pairs(group.settings) do
setSettingValue(global, group.key, setting.key, setting.default)
end
end),
},
},
},
},
},
}
2022-03-07 20:28:05 +00:00
2022-05-14 10:27:30 +00:00
local titleLayout = {
type = ui.TYPE.Flex,
external = {
stretch = 1,
},
content = ui.content {
{
template = I.MWUI.templates.textHeader,
props = {
text = l10n(group.name),
textSize = 20,
},
}
},
}
if group.description then
titleLayout.content:add(interval)
titleLayout.content:add {
template = I.MWUI.templates.textHeader,
props = {
text = l10n(group.description),
textSize = 18,
},
}
end
2022-05-14 10:27:30 +00:00
return {
name = groupLayoutName(group.key, global),
type = ui.TYPE.Flex,
2022-05-14 10:27:30 +00:00
external = {
stretch = 1,
},
content = ui.content {
{
type = ui.TYPE.Flex,
props = {
horizontal = true,
2022-05-14 10:27:30 +00:00
arrange = ui.ALIGNMENT.Center,
},
external = {
stretch = 1,
},
content = ui.content {
2022-05-14 10:27:30 +00:00
titleLayout,
growingIntreval,
resetButtonLayout,
},
},
2022-05-14 10:27:30 +00:00
spacedLines(2),
{
name = 'settings',
type = ui.TYPE.Flex,
2022-05-14 10:27:30 +00:00
content = settingsContent,
external = {
stretch = 1,
},
},
},
}
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))
2022-05-14 10:27:30 +00:00
if page.description then
table.insert(hints, l10n(page.description))
end
2022-04-29 17:35:01 +00:00
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))
2022-05-14 10:27:30 +00:00
if group.description then
table.insert(hints, l10n(group.description))
end
2022-04-29 17:35:01 +00:00
for _, setting in pairs(group.settings) do
table.insert(hints, l10n(setting.name))
2022-05-14 10:27:30 +00:00
if setting.description then
table.insert(hints, l10n(setting.description))
end
2022-04-29 17:35:01 +00:00
end
end
return table.concat(hints, ' ')
end
local function renderPage(page)
local l10n = core.l10n(page.l10n)
2022-05-14 10:27:30 +00:00
local sortedGroups = {}
for i, v in ipairs(groups[page.key]) do sortedGroups[i] = v end
table.sort(sortedGroups, pageGroupComparator)
local groupLayouts = {}
for _, pageGroup in ipairs(sortedGroups) do
local group = common.getSection(pageGroup.global, common.groupSectionKey):get(pageGroup.key)
table.insert(groupLayouts, renderGroup(group, pageGroup.global))
end
local groupsLayout = {
name = 'groups',
type = ui.TYPE.Flex,
external = {
stretch = 1,
},
content = ui.content(interlaceSeparator(groupLayouts, bigSpacer)),
}
local titleLayout = {
type = ui.TYPE.Flex,
2022-05-14 10:27:30 +00:00
external = {
stretch = 1,
},
content = ui.content {
{
2022-05-14 10:27:30 +00:00
template = I.MWUI.templates.textHeader,
props = {
2022-05-14 10:27:30 +00:00
text = l10n(page.name),
textSize = 22,
},
},
2022-05-14 10:27:30 +00:00
spacedLines(3),
},
}
2022-05-14 10:27:30 +00:00
if page.description then
titleLayout.content:add {
template = I.MWUI.templates.textNormal,
props = {
text = l10n(page.description),
textSize = 20,
},
}
end
2022-05-14 10:27:30 +00:00
local layout = {
name = page.key,
type = ui.TYPE.Flex,
props = {
position = util.vector2(10, 10),
},
content = ui.content {
titleLayout,
bigSpacer,
groupsLayout,
bigSpacer,
},
}
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
local function onSettingChanged(global)
return async:callback(function(groupKey, settingKey)
local group = common.getSection(global, common.groupSectionKey):get(groupKey)
2022-05-14 10:27:30 +00:00
if not group or not pageOptions[group.page] then return end
local value = common.getSection(global, group.key):get(settingKey)
2022-05-14 10:27:30 +00:00
local element = pageOptions[group.page].element
local groupsLayout = element.layout.content.groups
local groupLayout = groupsLayout.content[groupLayoutName(group.key, global)]
local settingsContent = groupLayout.content.settings.content
settingsContent[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 = {
key = group.key,
global = global,
2022-04-29 17:23:20 +00:00
order = group.order,
}
table.insert(groups[group.page], pageGroup)
common.getSection(global, group.key):subscribe(onSettingChanged(global))
2022-05-19 19:49:14 +00:00
common.getArgumentSection(global, group.key):subscribe(async:callback(function(_, settingKey)
local groupKey = group.key
local group = common.getSection(global, common.groupSectionKey):get(groupKey)
if not group or not pageOptions[group.page] then return end
local value = common.getSection(global, group.key):get(settingKey)
local element = pageOptions[group.page].element
local groupsLayout = element.layout.content.groups
local groupLayout = groupsLayout.content[groupLayoutName(group.key, global)]
local settingsContent = groupLayout.content.settings.content
settingsContent[settingKey] = renderSetting(group, group.settings[settingKey], value, global)
element:update()
end))
2022-04-29 17:35:01 +00:00
if not pages[group.page] then return end
local options = renderPage(pages[group.page])
2022-05-24 19:11:13 +00:00
if pageOptions[group.page] then
pageOptions[group.page].element:destroy()
else
pageOptions[group.page] = {}
end
2022-04-29 17:35:01 +00:00
for k, v in pairs(options) do
pageOptions[group.page][k] = v
2022-04-29 17:23:20 +00:00
end
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
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
2022-05-14 10:27:30 +00:00
if options.description ~= nil and type(options.description) ~= 'string' then
error('Page description key must be a string')
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
groups[page.key] = groups[page.key] or {}
pageOptions[page.key] = renderPage(page)
ui.registerSettingsPage(pageOptions[page.key])
end
2022-03-07 20:28:05 +00:00
return {
registerPage = registerPage,
2022-03-07 20:28:05 +00:00
registerRenderer = registerRenderer,
}