Add core library and element classes for Basalt framework
This commit is contained in:
141
src/propertySystem.lua
Normal file
141
src/propertySystem.lua
Normal file
@@ -0,0 +1,141 @@
|
||||
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
|
||||
Reference in New Issue
Block a user