Changing setting renderer arguments

openmw-fix_osx_build_maybe
uramer 3 years ago committed by Petr Mikheev
parent b832ba5c83
commit 1fe794d935

@ -38,7 +38,7 @@ namespace LuaUtil
void LuaStorage::Section::runCallbacks(sol::optional<std::string_view> changedKey) void LuaStorage::Section::runCallbacks(sol::optional<std::string_view> changedKey)
{ {
mStorage->mRunningCallbacks = true; mStorage->mRunningCallbacks.insert(this);
mCallbacks.erase(std::remove_if(mCallbacks.begin(), mCallbacks.end(), [&](const Callback& callback) mCallbacks.erase(std::remove_if(mCallbacks.begin(), mCallbacks.end(), [&](const Callback& callback)
{ {
bool valid = callback.isValid(); bool valid = callback.isValid();
@ -46,13 +46,20 @@ namespace LuaUtil
callback.tryCall(mSectionName, changedKey); callback.tryCall(mSectionName, changedKey);
return !valid; return !valid;
}), mCallbacks.end()); }), mCallbacks.end());
mStorage->mRunningCallbacks = false; mStorage->mRunningCallbacks.erase(this);
}
void LuaStorage::Section::throwIfCallbackRecursionIsTooDeep()
{
if (mStorage->mRunningCallbacks.count(this) > 0)
throw std::runtime_error("Storage handler shouldn't change the storage section it handles (leads to an infinite recursion)");
if (mStorage->mRunningCallbacks.size() > 10)
throw std::runtime_error("Too many subscribe callbacks triggering in a chain, likely an infinite recursion");
} }
void LuaStorage::Section::set(std::string_view key, const sol::object& value) void LuaStorage::Section::set(std::string_view key, const sol::object& value)
{ {
if (mStorage->mRunningCallbacks) throwIfCallbackRecursionIsTooDeep();
throw std::runtime_error("Not allowed to change storage in storage handlers because it can lead to an infinite recursion");
if (value != sol::nil) if (value != sol::nil)
mValues[std::string(key)] = Value(value); mValues[std::string(key)] = Value(value);
else else
@ -68,8 +75,7 @@ namespace LuaUtil
void LuaStorage::Section::setAll(const sol::optional<sol::table>& values) void LuaStorage::Section::setAll(const sol::optional<sol::table>& values)
{ {
if (mStorage->mRunningCallbacks) throwIfCallbackRecursionIsTooDeep();
throw std::runtime_error("Not allowed to change storage in storage handlers because it can lead to an infinite recursion");
mValues.clear(); mValues.clear();
if (values) if (values)
{ {

@ -62,6 +62,7 @@ namespace LuaUtil
void setAll(const sol::optional<sol::table>& values); void setAll(const sol::optional<sol::table>& values);
sol::table asTable(); sol::table asTable();
void runCallbacks(sol::optional<std::string_view> changedKey); void runCallbacks(sol::optional<std::string_view> changedKey);
void throwIfCallbackRecursionIsTooDeep();
LuaStorage* mStorage; LuaStorage* mStorage;
std::string mSectionName; std::string mSectionName;
@ -81,7 +82,7 @@ namespace LuaUtil
lua_State* mLua; lua_State* mLua;
std::map<std::string_view, std::shared_ptr<Section>> mData; std::map<std::string_view, std::shared_ptr<Section>> mData;
const Listener* mListener = nullptr; const Listener* mListener = nullptr;
bool mRunningCallbacks = false; std::set<const Section*> mRunningCallbacks;
}; };
} }

@ -27,7 +27,7 @@ set(LUA_BUILTIN_FILES
scripts/omw/mwui/constants.lua scripts/omw/mwui/constants.lua
scripts/omw/mwui/borders.lua scripts/omw/mwui/borders.lua
scripts/omw/mwui/box.lua scripts/omw/mwui/filters.lua
scripts/omw/mwui/text.lua scripts/omw/mwui/text.lua
scripts/omw/mwui/textEdit.lua scripts/omw/mwui/textEdit.lua
scripts/omw/mwui/space.lua scripts/omw/mwui/space.lua

@ -6,7 +6,7 @@ local auxUi = require('openmw_aux.ui')
local constants = require('scripts.omw.mwui.constants') local constants = require('scripts.omw.mwui.constants')
local v2 = util.vector2 local v2 = util.vector2
local whiteTexture = ui.texture{ path = 'white' } local whiteTexture = constants.whiteTexture
local menuTransparency = ui._getMenuTransparency() local menuTransparency = ui._getMenuTransparency()
local sideParts = { local sideParts = {

@ -1,45 +0,0 @@
local ui = require('openmw.ui')
local util = require('openmw.util')
local whiteTexture = ui.texture{ path = 'white' }
local menuTransparency = ui._getMenuTransparency()
return function(templates)
templates.backgroundTransparent = {
props = {
resource = whiteTexture,
color = util.color.rgb(0, 0, 0),
alpha = menuTransparency,
},
}
templates.backgroundSolid = {
props = {
resource = whiteTexture,
color = util.color.rgb(0, 0, 0),
},
}
templates.box = {
props = {
inheritAlpha = false,
},
content = ui.content {
{
type = ui.TYPE.Image,
template = templates.backgroundTransparent,
props = {
relativeSize = util.vector2(1, 1),
},
},
{
template = templates.borders,
props = {
relativeSize = util.vector2(1, 1),
},
external = {
slot = true,
},
},
},
}
end

@ -1,3 +1,4 @@
local ui = require('openmw.ui')
local util = require('openmw.util') local util = require('openmw.util')
return { return {
@ -8,4 +9,5 @@ return {
border = 2, border = 2,
thickBorder = 4, thickBorder = 4,
padding = 2, padding = 2,
whiteTexture = ui.texture { path = 'white' },
} }

@ -0,0 +1,31 @@
local ui = require('openmw.ui')
local util = require('openmw.util')
local constants = require('scripts.omw.mwui.constants')
return function(templates)
templates.disabled = {
type = ui.TYPE.Container,
props = {
alpha = 0.6,
},
content = ui.content {
{
props = {
relativeSize = util.vector2(1, 1),
},
external = {
slot = true,
},
},
{
type = ui.TYPE.Image,
props = {
resource = constants.whiteTexture,
color = util.color.rgb(0, 0, 0),
relativeSize = util.vector2(1, 1),
},
},
},
}
end

@ -93,6 +93,11 @@ require('scripts.omw.mwui.text')(templates)
-- @field [parent=#Templates] openmw.ui#Layout textEditBox -- @field [parent=#Templates] openmw.ui#Layout textEditBox
require('scripts.omw.mwui.textEdit')(templates) require('scripts.omw.mwui.textEdit')(templates)
---
-- Shades its children and makes them uninteractible
-- @field [parent=#Templates] openmw.ui#Layout disabled
require('scripts.omw.mwui.filters')(templates)
--- ---
-- Interface version -- Interface version
-- @field [parent=#MWUI] #number version -- @field [parent=#MWUI] #number version

@ -1,7 +1,10 @@
local storage = require('openmw.storage') local storage = require('openmw.storage')
local contextSection = storage.playerSection or storage.globalSection
local groupSectionKey = 'OmwSettingGroups' local groupSectionKey = 'OmwSettingGroups'
local conventionPrefix = 'Settings'
local argumentSectionPostfix = 'Arguments'
local contextSection = storage.playerSection or storage.globalSection
local groupSection = contextSection(groupSectionKey) local groupSection = contextSection(groupSectionKey)
groupSection:removeOnExit() groupSection:removeOnExit()
@ -30,7 +33,6 @@ local function validateGroupOptions(options)
if type(options.key) ~= 'string' then if type(options.key) ~= 'string' then
error('Group must have a key') error('Group must have a key')
end end
local conventionPrefix = "Settings"
if options.key:sub(1, conventionPrefix:len()) ~= conventionPrefix then if options.key:sub(1, conventionPrefix:len()) ~= conventionPrefix then
print(("Group key %s doesn't start with %s"):format(options.key, conventionPrefix)) print(("Group key %s doesn't start with %s"):format(options.key, conventionPrefix))
end end
@ -88,6 +90,8 @@ local function registerGroup(options)
settings = {}, settings = {},
} }
local valueSection = contextSection(options.key) local valueSection = contextSection(options.key)
local argumentSection = contextSection(options.key .. argumentSectionPostfix)
argumentSection:removeOnExit()
for i, opt in ipairs(options.settings) do for i, opt in ipairs(options.settings) do
local setting = registerSetting(opt) local setting = registerSetting(opt)
setting.order = i setting.order = i
@ -95,9 +99,10 @@ local function registerGroup(options)
error(('Duplicate setting key %s'):format(options.key)) error(('Duplicate setting key %s'):format(options.key))
end end
group.settings[setting.key] = setting group.settings[setting.key] = setting
if not valueSection:get(setting.key) then if valueSection:get(setting.key) == nil then
valueSection:set(setting.key, setting.default) valueSection:set(setting.key, setting.default)
end end
argumentSection:set(setting.key, setting.argument)
end end
groupSection:set(group.key, group) groupSection:set(group.key, group)
end end
@ -106,6 +111,13 @@ return {
getSection = function(global, key) getSection = function(global, key)
return (global and storage.globalSection or storage.playerSection)(key) return (global and storage.globalSection or storage.playerSection)(key)
end, end,
getArgumentSection = function(global, key)
return (global and storage.globalSection or storage.playerSection)(key .. argumentSectionPostfix)
end,
updateRendererArgument = function(groupKey, settingKey, argument)
local argumentSection = contextSection(groupKey .. argumentSectionPostfix)
argumentSection:set(settingKey, argument)
end,
setGlobalEvent = 'OMWSettingsGlobalSet', setGlobalEvent = 'OMWSettingsGlobalSet',
groupSectionKey = groupSectionKey, groupSectionKey = groupSectionKey,
onLoad = function(saved) onLoad = function(saved)

@ -6,6 +6,7 @@ return {
interfaceName = 'Settings', interfaceName = 'Settings',
interface = { interface = {
registerGroup = common.registerGroup, registerGroup = common.registerGroup,
updateRendererArgument = common.updateRendererArgument,
}, },
engineHandlers = { engineHandlers = {
onLoad = common.onLoad, onLoad = common.onLoad,

@ -137,6 +137,13 @@ return {
-- } -- }
-- } -- }
registerGroup = common.registerGroup, registerGroup = common.registerGroup,
---
-- @function [parent=#Settings] updateRendererArgument Change the renderer argument of a setting
-- available both in player and global scripts
-- @param #string groupKey A settings group key
-- @param #string settingKey A setting key
-- @param argument A renderer argument
updateRendererArgument = common.updateRendererArgument,
}, },
engineHandlers = { engineHandlers = {
onLoad = common.onLoad, onLoad = common.onLoad,

@ -110,6 +110,7 @@ local function renderSetting(group, setting, value, global)
}, },
} }
end end
local argument = common.getArgumentSection(global, group.key):get(setting.key)
return { return {
name = setting.key, name = setting.key,
type = ui.TYPE.Flex, type = ui.TYPE.Flex,
@ -123,7 +124,7 @@ local function renderSetting(group, setting, value, global)
content = ui.content { content = ui.content {
titleLayout, titleLayout,
growingIntreval, growingIntreval,
renderFunction(value, set, setting.argument), renderFunction(value, set, argument),
}, },
} }
end end
@ -350,6 +351,20 @@ local function onGroupRegistered(global, key)
} }
table.insert(groups[group.page], pageGroup) table.insert(groups[group.page], pageGroup)
common.getSection(global, group.key):subscribe(onSettingChanged(global)) common.getSection(global, group.key):subscribe(onSettingChanged(global))
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))
if not pages[group.page] then return end if not pages[group.page] then return end
local options = renderPage(pages[group.page]) local options = renderPage(pages[group.page])

@ -2,38 +2,80 @@ local ui = require('openmw.ui')
local async = require('openmw.async') local async = require('openmw.async')
local I = require('openmw.interfaces') local I = require('openmw.interfaces')
return function(registerRenderer) local function applyDefaults(argument, defaults)
registerRenderer('textLine', function(value, set) if not argument then return defaults end
if pairs(defaults) and pairs(argument) then
local result = {}
for k, v in pairs(defaults) do
result[k] = v
end
for k, v in pairs(argument) do
result[k] = v
end
return result
end
return argument
end
local function disable(disabled, layout)
if disabled then
return { return {
template = I.MWUI.templates.textEditLine, template = I.MWUI.templates.disabled,
props = { content = ui.content {
text = tostring(value), layout,
},
events = {
textChanged = async:callback(function(s) set(s) end),
}, },
} }
end) else
return layout
end
end
registerRenderer('yesNo', function(value, set) return function(registerRenderer)
return { do
template = I.MWUI.templates.box, local defaultArgument = {
content = ui.content { disabled = false,
{ }
template = I.MWUI.templates.padding, registerRenderer('textLine', function(value, set, argument)
content = ui.content { argument = applyDefaults(argument, defaultArgument)
{ return disable(argument.disabled, {
template = I.MWUI.templates.textNormal, template = I.MWUI.templates.textEditLine,
props = { props = {
text = value and 'Yes' or 'No', text = tostring(value),
}, },
events = { events = {
mouseClick = async:callback(function() set(not value) end), textChanged = async:callback(function(s) set(s) end),
},
})
end)
end
do
local defaultArgument = {
disabled = false,
trueLabel = 'Yes',
falseLabel = 'No',
}
registerRenderer('checkbox', function(value, set, argument)
argument = applyDefaults(argument, defaultArgument)
return disable(argument.disabled, {
template = I.MWUI.templates.box,
content = ui.content {
{
template = I.MWUI.templates.padding,
content = ui.content {
{
template = I.MWUI.templates.textNormal,
props = {
text = value and argument.trueLabel or argument.falseLabel
},
events = {
mouseClick = async:callback(function() set(not value) end),
},
}, },
}, },
}, },
}, },
}, })
} end)
end) end
end end
Loading…
Cancel
Save