You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
6.1 KiB
200 lines
6.1 KiB
local _, T = ...
|
|
local function assert(cnd, text, el)
|
|
return cnd or error(text, el or 3)((0)[0])
|
|
end
|
|
|
|
local XU, factory = {}, {}
|
|
function XU:Create(otype, ...)
|
|
return assert(factory[otype], 'unknown object type')(...)
|
|
end
|
|
function XU:RegisterFactory(otype, createfunc)
|
|
assert(type(otype) == "string", 'invalid object type')
|
|
assert(type(createfunc) == "function", 'invalid factory function')
|
|
assert(factory[otype] == nil, 'object type already registered')
|
|
factory[otype] = createfunc
|
|
end
|
|
|
|
local getWidgetData, newWidgetData, setWidgetData do
|
|
local S, skipProtoKeys = {}, {api=1, super=1, meta=1, init=1, ObjectType=1}
|
|
function getWidgetData(self, dataType)
|
|
local r = S[dataType]
|
|
return r and r[self[0]]
|
|
end
|
|
function newWidgetData(self, dataType, proto)
|
|
local d, pin = setWidgetData(self, dataType, {}), proto.init
|
|
if proto.super == nil then
|
|
local api = proto.api
|
|
proto.super = getmetatable(self).__index
|
|
for k,v in next, proto.super do
|
|
if api[k] == nil then
|
|
api[k] = v
|
|
end
|
|
end
|
|
proto.meta = {__index=api}
|
|
end
|
|
for k,v in next, proto do
|
|
if not skipProtoKeys[k] then
|
|
d[k] = v
|
|
end
|
|
end
|
|
d.self, d.proto = self, proto
|
|
setmetatable(self, proto.meta)
|
|
for i=1, pin and #pin or 0 do
|
|
pin[i](self, proto)
|
|
end
|
|
return d
|
|
end
|
|
function setWidgetData(self, dataType, dat)
|
|
local SD = S[dataType] or {}
|
|
if SD[self[0]] == nil then
|
|
S[dataType], SD[self[0]] = SD, dat
|
|
end
|
|
return dat
|
|
end
|
|
end
|
|
local AddObjectMethods, CallObjectScript do
|
|
local Object, loScriptName, loObjectType, temp = {}, {}, {exuiobject="exUIObject"}, {}
|
|
local ObjectData, objectProto = {}, {}
|
|
local function NIL_HANDLER() end
|
|
local function findScriptName(d, q)
|
|
local p = d.proto
|
|
if p[q] == NIL_HANDLER then
|
|
return q
|
|
end
|
|
local lq = loScriptName[q:lower()]
|
|
if p[lq] == NIL_HANDLER then
|
|
return lq
|
|
end
|
|
end
|
|
local function initObject(self, proto)
|
|
local d, op = {}, objectProto[proto]
|
|
for k, v in next, op do
|
|
if v == NIL_HANDLER then
|
|
d[k] = v
|
|
end
|
|
end
|
|
d.proto, op.super = op, op.super or proto.super
|
|
setWidgetData(self, ObjectData, d)
|
|
end
|
|
function CallObjectScript(self, handlerName, ...)
|
|
local d = assert(getWidgetData(self, ObjectData), "Invalid object type")
|
|
local dh = d[findScriptName(d, handlerName)]
|
|
if dh and dh ~= NIL_HANDLER then
|
|
return securecall(dh, self, ...)
|
|
end
|
|
end
|
|
|
|
function Object:GetObjectType()
|
|
local d = assert(getWidgetData(self, ObjectData), "Invalid object type")
|
|
return d.proto.ObjectType
|
|
end
|
|
function Object:IsObjectType(objectType)
|
|
local d = assert(getWidgetData(self, ObjectData), "Invalid object type")
|
|
assert(type(objectType) == "string", 'Syntax: is = Object:IsObjectType("objectType")')
|
|
local r = d.proto.isa[objectType]
|
|
if r == nil then
|
|
r = d.proto.isa[loObjectType[objectType:lower()]]
|
|
end
|
|
if r == nil then
|
|
return d.proto.super.IsObjectType(self, objectType)
|
|
end
|
|
return r ~= false
|
|
end
|
|
function Object:SetScript(handlerName, callback)
|
|
local d = assert(getWidgetData(self, ObjectData), "Invalid object type")
|
|
assert(type(handlerName) == 'string', 'Syntax: Object:SetScript("handlerName", callback)')
|
|
local hn = findScriptName(d, handlerName)
|
|
if not hn then
|
|
return d.proto.super.SetScript(self, handlerName, callback)
|
|
end
|
|
d[hn] = callback == nil and NIL_HANDLER or callback
|
|
end
|
|
function Object:HookScript(handlerName, callback)
|
|
local d = assert(getWidgetData(self, ObjectData), "Invalid object type")
|
|
assert(type(handlerName) == 'string', 'Syntax: Object:HookScript("handlerName", callback)')
|
|
local hn = findScriptName(d, handlerName)
|
|
if not hn then
|
|
return d.proto.super.HookScript(self, handlerName, callback)
|
|
end
|
|
local oc = Object.GetScript(self, hn)
|
|
if oc then
|
|
temp.f = oc
|
|
hooksecurefunc(temp, "f", callback)
|
|
callback, temp.f = temp.f
|
|
end
|
|
return Object.SetScript(self, hn, callback)
|
|
end
|
|
function Object:GetScript(handlerName)
|
|
local d = assert(getWidgetData(self, ObjectData), "Invalid object type")
|
|
assert(type(handlerName) == 'string', 'Syntax: callback = Object:GetScript("handlerName")')
|
|
local hn = findScriptName(d, handlerName)
|
|
if not hn then
|
|
return d.proto.super.GetScript(self, handlerName)
|
|
end
|
|
local dh = d[hn]
|
|
return dh ~= NIL_HANDLER and dh or nil
|
|
end
|
|
function Object:HasScript(handlerName)
|
|
local d = assert(getWidgetData(self, ObjectData), "Invalid object type")
|
|
assert(type(handlerName) == 'string', 'Syntax: hasScript = Object:HasScript("handlerName")')
|
|
return findScriptName(d, handlerName) and true or d.proto.super.HasScript(self, handlerName)
|
|
end
|
|
|
|
local function buildCaselessMap(sourceArray, caseMap, sideMap, sideValue, errorText)
|
|
for i=1, sourceArray and #sourceArray or 0 do
|
|
local ik = sourceArray[i]
|
|
local lo = ik:lower()
|
|
assert((caseMap[lo] or ik) == ik, errorText, 4)
|
|
sideMap[ik], caseMap[lo] = sideValue, ik
|
|
end
|
|
end
|
|
function AddObjectMethods(isarr, proto)
|
|
local api, scripts, pin = proto.api, proto.scripts, proto.init or {}
|
|
local op, isa = {}, {exUIObject=true}
|
|
proto.init, proto.scripts = pin, nil
|
|
for k,v in next, Object do
|
|
if api[k] == nil then
|
|
api[k] = v
|
|
end
|
|
end
|
|
for i=1,#pin+1 do
|
|
if (pin[i] or initObject) == initObject then
|
|
pin[i] = initObject
|
|
break
|
|
end
|
|
end
|
|
buildCaselessMap(isarr, loObjectType, isa, true, 'divergent object type case')
|
|
buildCaselessMap(scripts, loScriptName, op, NIL_HANDLER, 'divergent script name case')
|
|
objectProto[proto], op.isa, op.ObjectType, op.scripts = op, isa, isarr[1], scripts
|
|
return proto
|
|
end
|
|
end
|
|
do -- ObjectGroup
|
|
local mcache = {}
|
|
local function genMethod(t, k)
|
|
if k ~= nil and type(t[1][k]) == "function" then
|
|
local r = mcache[k]
|
|
if r == nil then
|
|
r = function(self, ...)
|
|
for i=#self,2,-1 do
|
|
securecall(self[i][k], self[i], ...)
|
|
end
|
|
return securecall(self[1][k], self[1], ...)
|
|
end
|
|
mcache[k] = r
|
|
end
|
|
return r
|
|
end
|
|
end
|
|
local groupMeta = {__index=genMethod, __metatable=false}
|
|
XU:RegisterFactory("ObjectGroup", function(...)
|
|
return setmetatable({...}, groupMeta)
|
|
end)
|
|
end
|
|
|
|
local hum = {}
|
|
function hum:GetImpl()
|
|
return assert, getWidgetData, newWidgetData, setWidgetData, AddObjectMethods, CallObjectScript
|
|
end
|
|
|
|
T.exUI, hum.HUM = setmetatable(XU, {__index=hum}), hum
|