mirror of https://github.com/OpenMW/openmw.git
Move implementation of UI Content to Lua
parent
22c62a8c38
commit
fc1430af95
@ -1,108 +1,33 @@
|
||||
#include "content.hpp"
|
||||
|
||||
namespace LuaUi
|
||||
namespace LuaUi::Content
|
||||
{
|
||||
int64_t Content::sInstanceCount = 0;
|
||||
|
||||
Content::Content(const sol::table& table)
|
||||
{
|
||||
sInstanceCount++;
|
||||
size_t size = table.size();
|
||||
for (size_t index = 0; index < size; ++index)
|
||||
{
|
||||
sol::object value = table.get<sol::object>(index + 1);
|
||||
if (value.is<sol::table>())
|
||||
assign(index, value.as<sol::table>());
|
||||
else
|
||||
throw std::logic_error("UI Content children must all be tables.");
|
||||
}
|
||||
}
|
||||
|
||||
void Content::assign(size_t index, const sol::table& table)
|
||||
{
|
||||
if (mOrdered.size() < index)
|
||||
throw std::logic_error("Can't have gaps in UI Content.");
|
||||
if (index == mOrdered.size())
|
||||
mOrdered.push_back(table);
|
||||
else
|
||||
{
|
||||
sol::optional<std::string> oldName = mOrdered[index]["name"];
|
||||
if (oldName.has_value())
|
||||
mNamed.erase(oldName.value());
|
||||
mOrdered[index] = table;
|
||||
}
|
||||
sol::optional<std::string> name = table["name"];
|
||||
if (name.has_value())
|
||||
mNamed[name.value()] = index;
|
||||
}
|
||||
|
||||
void Content::assign(std::string_view name, const sol::table& table)
|
||||
{
|
||||
auto it = mNamed.find(name);
|
||||
if (it != mNamed.end())
|
||||
assign(it->second, table);
|
||||
else
|
||||
throw std::logic_error(std::string("Can't find a UI Content child with name ") += name);
|
||||
}
|
||||
|
||||
void Content::insert(size_t index, const sol::table& table)
|
||||
namespace
|
||||
{
|
||||
if (mOrdered.size() < index)
|
||||
throw std::logic_error("Can't have gaps in UI Content.");
|
||||
mOrdered.insert(mOrdered.begin() + index, table);
|
||||
for (size_t i = index; i < mOrdered.size(); ++i)
|
||||
sol::table loadMetatable(sol::state_view sol)
|
||||
{
|
||||
sol::optional<std::string> name = mOrdered[i]["name"];
|
||||
if (name.has_value())
|
||||
mNamed[name.value()] = index;
|
||||
std::string scriptBody =
|
||||
#include "content.lua"
|
||||
;
|
||||
auto result = sol.safe_script(scriptBody);
|
||||
if (result.get_type() != sol::type::table)
|
||||
throw std::logic_error("Expected a meta table");
|
||||
return result.get<sol::table>();
|
||||
}
|
||||
}
|
||||
|
||||
sol::table Content::at(size_t index) const
|
||||
{
|
||||
if (index > size())
|
||||
throw std::logic_error("Invalid UI Content index.");
|
||||
return mOrdered.at(index);
|
||||
}
|
||||
|
||||
sol::table Content::at(std::string_view name) const
|
||||
{
|
||||
auto it = mNamed.find(name);
|
||||
if (it == mNamed.end())
|
||||
throw std::logic_error("Invalid UI Content name.");
|
||||
return mOrdered.at(it->second);
|
||||
}
|
||||
|
||||
size_t Content::remove(size_t index)
|
||||
sol::protected_function makeFactory(sol::state_view sol)
|
||||
{
|
||||
sol::table table = at(index);
|
||||
sol::optional<std::string> name = table["name"];
|
||||
if (name.has_value())
|
||||
{
|
||||
auto it = mNamed.find(name.value());
|
||||
if (it != mNamed.end())
|
||||
mNamed.erase(it);
|
||||
}
|
||||
mOrdered.erase(mOrdered.begin() + index);
|
||||
return index;
|
||||
sol::table metatable = loadMetatable(sol);
|
||||
if (metatable["new"].get_type() != sol::type::function)
|
||||
throw std::logic_error("Expected function");
|
||||
return metatable["new"].get<sol::protected_function>();
|
||||
}
|
||||
|
||||
size_t Content::remove(std::string_view name)
|
||||
{
|
||||
auto it = mNamed.find(name);
|
||||
if (it == mNamed.end())
|
||||
throw std::logic_error("Invalid UI Content name.");
|
||||
size_t index = it->second;
|
||||
remove(index);
|
||||
return index;
|
||||
}
|
||||
int64_t View::sInstanceCount = 0;
|
||||
|
||||
size_t Content::indexOf(const sol::table& table) const
|
||||
int64_t getInstanceCount()
|
||||
{
|
||||
auto it = std::find(mOrdered.begin(), mOrdered.end(), table);
|
||||
if (it == mOrdered.end())
|
||||
return size();
|
||||
else
|
||||
return it - mOrdered.begin();
|
||||
return View::sInstanceCount;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,144 @@
|
||||
R"(
|
||||
local M = {}
|
||||
M.__Content = true
|
||||
M.new = function(source)
|
||||
local result = {}
|
||||
result.__nameIndex = {}
|
||||
for i, v in ipairs(source) do
|
||||
if type(v) ~= 'table' then
|
||||
error("Content can only contain tables")
|
||||
end
|
||||
result[i] = v
|
||||
if type(v.name) == 'string' then
|
||||
result.__nameIndex[v.name] = i
|
||||
end
|
||||
end
|
||||
return setmetatable(result, M)
|
||||
end
|
||||
local function validateIndex(self, index)
|
||||
if type(index) ~= 'number' then
|
||||
error('Unexpected Content key: ' .. tostring(index))
|
||||
end
|
||||
if index < 1 or (#self + 1) < index then
|
||||
error('Invalid Content index: ' .. tostring(index))
|
||||
end
|
||||
end
|
||||
local function getIndexFromKey(self, key)
|
||||
local index = key
|
||||
if type(key) == 'string' then
|
||||
index = self.__nameIndex[key]
|
||||
if not index then
|
||||
error("Unexpected content key:" .. key)
|
||||
end
|
||||
end
|
||||
validateIndex(self, index)
|
||||
return index
|
||||
end
|
||||
local function nameAt(self, index)
|
||||
local v = rawget(self, index)
|
||||
return v and type(v.name) == 'string' and v.name
|
||||
end
|
||||
local methods = {
|
||||
insert = function(self, index, value)
|
||||
validateIndex(self, index)
|
||||
if type(value) ~= 'table' then
|
||||
error('Content can only contain tables')
|
||||
end
|
||||
for i = #self, index, -1 do
|
||||
rawset(self, i + 1, rawget(self, i))
|
||||
local name = rawget(self, i + 1)
|
||||
if name then
|
||||
self.__nameIndex[name] = i + 1
|
||||
end
|
||||
end
|
||||
rawset(self, index, value)
|
||||
if value.name then
|
||||
self.__nameIndex[value.name] = index
|
||||
end
|
||||
end,
|
||||
indexOf = function(self, value)
|
||||
if type(value) == 'string' then
|
||||
return self.__nameIndex[value]
|
||||
elseif type(value) == 'table' then
|
||||
for i = 1, #self do
|
||||
if rawget(self, i) == value then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end,
|
||||
add = function(self, value)
|
||||
self:insert(#self + 1, value)
|
||||
return #self
|
||||
end,
|
||||
}
|
||||
M.__index = function(self, key)
|
||||
if methods[key] then return methods[key] end
|
||||
local index = getIndexFromKey(self, key)
|
||||
return rawget(self, index)
|
||||
end
|
||||
local function remove(self, index)
|
||||
print('remove', #self, index)
|
||||
local oldName = nameAt(self, index)
|
||||
if oldName then
|
||||
self.__nameIndex[oldName] = nil
|
||||
end
|
||||
if index > #self then
|
||||
error('Invalid Content index:' .. tostring(index))
|
||||
end
|
||||
for i = index, #self - 1 do
|
||||
local v = rawget(self, i + 1)
|
||||
rawset(self, i, v)
|
||||
if type(v.name) == 'string' then
|
||||
self.__nameIndex[v.name] = i
|
||||
end
|
||||
end
|
||||
rawset(self, #self, nil)
|
||||
print('removed', #self)
|
||||
end
|
||||
local function assign(self, index, value)
|
||||
local oldName = nameAt(self, index)
|
||||
if oldName then
|
||||
self.__nameIndex[oldName] = nil
|
||||
end
|
||||
rawset(self, index, value)
|
||||
if value.name then
|
||||
self.__nameIndex[value.name] = index
|
||||
end
|
||||
end
|
||||
M.__newindex = function(self, key, value)
|
||||
print('__newindex ', key, value)
|
||||
local index = getIndexFromKey(self, key)
|
||||
if value == nil then
|
||||
remove(self, index)
|
||||
elseif type(value) == 'table' then
|
||||
assign(self, index, value)
|
||||
else
|
||||
error('Content can only contain tables')
|
||||
end
|
||||
end
|
||||
local function next(self, index)
|
||||
local v = rawget(self, index)
|
||||
if v then
|
||||
return index + 1, v
|
||||
else
|
||||
return nil, nil
|
||||
end
|
||||
end
|
||||
M.__pairs = function(self)
|
||||
return next, self, 1
|
||||
end
|
||||
M.__ipairs = M.__pairs
|
||||
|
||||
local test = M.new({})
|
||||
test:insert(1, {})
|
||||
test[2] = {}
|
||||
assert(#test == 2, "Wrong size")
|
||||
test:add({ name = 'a' })
|
||||
assert(getIndexFromKey(test, 'a') == 3, getIndexFromKey(test, 'a'))
|
||||
assert(type(test.a) == 'table', type(test.a))
|
||||
assert(test.a.name == 'a', 'wrong table')
|
||||
|
||||
return M
|
||||
)"
|
Loading…
Reference in New Issue