141 lines
4.0 KiB
Lua
141 lines
4.0 KiB
Lua
local deepCopy = require("libraries/utils").deepCopy
|
|
local expect = require("libraries/expect")
|
|
|
|
local PropertySystem = {}
|
|
PropertySystem.__index = PropertySystem
|
|
|
|
PropertySystem._properties = {}
|
|
|
|
function PropertySystem.defineProperty(class, name, config)
|
|
if not rawget(class, '_properties') then
|
|
class._properties = {}
|
|
end
|
|
|
|
class._properties[name] = {
|
|
type = config.type,
|
|
default = config.default,
|
|
canTriggerRender = config.canTriggerRender,
|
|
getter = config.getter,
|
|
setter = config.setter,
|
|
}
|
|
|
|
local capitalizedName = name:sub(1,1):upper() .. name:sub(2)
|
|
|
|
class["get" .. capitalizedName] = function(self)
|
|
expect(1, self, "element")
|
|
local value = self._values[name]
|
|
return config.getter and config.getter(value) or value
|
|
end
|
|
|
|
class["set" .. capitalizedName] = function(self, value)
|
|
expect(1, self, "element")
|
|
expect(2, value, config.type)
|
|
if config.setter then
|
|
value = config.setter(self, value)
|
|
end
|
|
|
|
self:_updateProperty(name, value)
|
|
return self
|
|
end
|
|
end
|
|
|
|
function PropertySystem:__init()
|
|
self._values = {}
|
|
self._observers = {}
|
|
|
|
self.set = function(name, value)
|
|
local oldValue = self._values[name]
|
|
self._values[name] = value
|
|
if(self._properties[name].setter) then
|
|
value = self._properties[name].setter(self, value)
|
|
end
|
|
if oldValue ~= value and self._observers[name] then
|
|
for _, callback in ipairs(self._observers[name]) do
|
|
callback(self, value, oldValue)
|
|
end
|
|
end
|
|
end
|
|
|
|
self.get = function(name)
|
|
return self._values[name]
|
|
end
|
|
|
|
local properties = {}
|
|
local currentClass = getmetatable(self).__index
|
|
|
|
while currentClass do
|
|
if rawget(currentClass, '_properties') then
|
|
for name, config in pairs(currentClass._properties) do
|
|
if not properties[name] then
|
|
properties[name] = config
|
|
end
|
|
end
|
|
end
|
|
currentClass = getmetatable(currentClass) and rawget(getmetatable(currentClass), '__index')
|
|
end
|
|
|
|
self._properties = properties
|
|
|
|
local originalMT = getmetatable(self)
|
|
local originalIndex = originalMT.__index
|
|
setmetatable(self, {
|
|
__index = function(t, k)
|
|
if self._properties[k] then
|
|
return self._values[k]
|
|
end
|
|
if type(originalIndex) == "function" then
|
|
return originalIndex(t, k)
|
|
else
|
|
return originalIndex[k]
|
|
end
|
|
end,
|
|
__newindex = function(t, k, v)
|
|
if self._properties[k] then
|
|
if self._properties[k].setter then
|
|
v = self._properties[k].setter(self, v)
|
|
end
|
|
self:_updateProperty(k, v)
|
|
else
|
|
rawset(t, k, v)
|
|
end
|
|
end,
|
|
__tostring = function(self)
|
|
return string.format("Object: %s (id: %s)", self._values.type, self.id)
|
|
end
|
|
})
|
|
|
|
for name, config in pairs(properties) do
|
|
if self._values[name] == nil then
|
|
if type(config.default) == "table" then
|
|
self._values[name] = deepCopy(config.default)
|
|
else
|
|
self._values[name] = config.default
|
|
end
|
|
end
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
function PropertySystem:_updateProperty(name, value)
|
|
local oldValue = self._values[name]
|
|
if oldValue ~= value then
|
|
self._values[name] = value
|
|
if self._properties[name].canTriggerRender then
|
|
self:updateRender()
|
|
end
|
|
if self._observers[name] then
|
|
for _, callback in ipairs(self._observers[name]) do
|
|
callback(self, value, oldValue)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function PropertySystem:observe(name, callback)
|
|
self._observers[name] = self._observers[name] or {}
|
|
table.insert(self._observers[name], callback)
|
|
return self
|
|
end
|
|
|
|
return PropertySystem |