3.6 KiB
local PropertySystem = require("propertySystem") local errorManager = require("errorManager") local BaseElement = {}
function BaseElement.setup(element) element.defineProperty(element, "states", {default = {}, type = "table"}) element.defineProperty(element, "computedStates", {default = {}, type = "table"}) element.defineProperty(element, "stateUpdate", { default = {key = "", value = nil, oldValue = nil}, type = "table" }) end
function BaseElement:initializeState(name, default, canTriggerRender, persist, path) local states = self.get("states")
if states[name] then
errorManager.error("State '" .. name .. "' already exists")
return self
end
if persist then
local file = path or ("states/" .. self.get("name") .. "_" .. name .. ".state")
if fs.exists(file) then
local f = fs.open(file, "r")
states[name] = {
value = textutils.unserialize(f.readAll()),
persist = true,
file = file
}
f.close()
else
states[name] = {
value = default,
persist = true,
file = file,
canTriggerRender = canTriggerRender
}
end
else
states[name] = {
value = default,
canTriggerRender = canTriggerRender
}
end
return self
end
function BaseElement:setState(name, value) local states = self.get("states") if not states[name] then error("State '"..name.."' not initialized") end
local oldValue = states[name].value
states[name].value = value
if states[name].persist then
local dir = fs.getDir(states[name].file)
if not fs.exists(dir) then
fs.makeDir(dir)
end
local f = fs.open(states[name].file, "w")
f.write(textutils.serialize(value))
f.close()
end
if states[name].canTriggerRender then
self:updateRender()
end
self.set("stateUpdate", {
key = name,
value = value,
oldValue = oldValue
})
return self
end
function BaseElement:getState(name) local states = self.get("states") if not states[name] then errorManager.error("State '"..name.."' not initialized") end return states[name].value end
function BaseElement:computed(key, computeFn) local computed = self.get("computedStates") computed[key] = setmetatable({}, { __call = function() return computeFn(self) end }) return self end
function BaseElement:shareState(stateKey, ...) local value = self:getState(stateKey)
for _, element in ipairs({...}) do
if element.get("states")[stateKey] then
errorManager.error("Cannot share state '" .. stateKey .. "': Target element already has this state")
return self
end
element:initializeState(stateKey, value)
self:observe("stateUpdate", function(self, update)
if update.key == stateKey then
element:setState(stateKey, update.value)
end
end)
end
return self
end
function BaseElement:onStateChange(stateName, callback) if not self.get("states")[stateName] then errorManager.error("Cannot observe state '" .. stateName .. "': State not initialized") return self end
self:observe("stateUpdate", function(self, update)
if update.key == stateName then
callback(self, update.value, update.oldValue)
end
end)
return self
end
return { BaseElement = BaseElement }