Fix indents, method names
This commit is contained in:
parent
83bb7ee817
commit
46da90f5f8
9 changed files with 553 additions and 531 deletions
431
src/class.lua
431
src/class.lua
|
|
@ -1,323 +1,343 @@
|
|||
local module = {};
|
||||
local pack = table.pack;
|
||||
local match = string.match;
|
||||
local insert = table.insert;
|
||||
local module = {}
|
||||
local pack = table.pack
|
||||
local match = string.match
|
||||
local insert = table.insert
|
||||
local gsub = string.gsub
|
||||
|
||||
---@param shared quad_export
|
||||
---@return quad_module_class
|
||||
function module.init(shared)
|
||||
local warn = shared.warn;
|
||||
local warn = shared.warn
|
||||
---@class quad_module_class
|
||||
local new = {__type = "quad_module_class"};
|
||||
local InstanceNew = Instance.new;
|
||||
local event = shared.Event; ---@type quad_module_event
|
||||
local bind = event.Bind;
|
||||
local store = shared.Store; ---@type quad_module_store
|
||||
local initStoreRegisterBinding = store.__initStoreRegisterBinding;
|
||||
local addObject = store.AddObject;
|
||||
local storeNew = store.New;
|
||||
local mount = shared.Mount; ---@type quad_module_mount
|
||||
local getHolder = mount.GetHolder;
|
||||
local mountfunc = mount.Mount;
|
||||
local style = shared.Style; ---@type quad_module_style
|
||||
local styleList = style.Styles;
|
||||
local parseStyles = style.ParseStyles;
|
||||
local advancedTween = shared.Tween; ---@type quad_module_tween
|
||||
local round = shared.Round; ---@type quad_module_round
|
||||
local new = {__type = "quad_module_class"}
|
||||
local InstanceNew = Instance.new
|
||||
local event = shared.Event ---@type quad_module_event
|
||||
local bind = event.Bind
|
||||
local store = shared.Store ---@type quad_module_store
|
||||
local initStoreRegisterBinding = store.__initStoreRegisterBinding
|
||||
local addObject = store.AddObject
|
||||
local storeNew = store.New
|
||||
local mount = shared.Mount ---@type quad_module_mount
|
||||
local getHolder = mount.GetHolder
|
||||
local mountfunc = mount.Mount
|
||||
local style = shared.Style ---@type quad_module_style
|
||||
local styleList = style.Styles
|
||||
local parseStyles = style.ParseStyles
|
||||
local advancedTween = shared.Tween ---@type quad_module_tween
|
||||
local round = shared.Round ---@type quad_module_round
|
||||
|
||||
local function InstanceNewWithName(classname,parent,name)
|
||||
local item = InstanceNew(classname,parent);
|
||||
item.Name = name;
|
||||
return item;
|
||||
local item = InstanceNew(classname,parent)
|
||||
item.Name = name
|
||||
return item
|
||||
end
|
||||
|
||||
local function GetProperty(item,index,ClassName)
|
||||
if type(item) == "table" then return item[index]; end
|
||||
ClassName = ClassName or item.ClassName;
|
||||
local isImage = (ClassName == "ImageLabel" or ClassName == "ImageButton");
|
||||
if (index == "RoundSize" or index == "roundSize") and isImage then
|
||||
if type(item) == "table" then return item[index] end
|
||||
ClassName = ClassName or item.ClassName
|
||||
local isImage = (ClassName == "ImageLabel" or ClassName == "ImageButton")
|
||||
if (index == "RoundSize") and isImage then
|
||||
if not round then
|
||||
error("module 'round' needs to be loaded for get image round size but it is not found on 'src.libs'. you should adding that to src.libs directory");
|
||||
error("module 'round' needs to be loaded for get image round size but it is not found on 'src.libs'. you should adding that to src.libs directory")
|
||||
end
|
||||
return round.GetRound(item);
|
||||
elseif index == "UiRoundSize" or index == "uiRoundSize" or index == "UIRoundSize" then
|
||||
local target = (ClassName == "UICorner" and item) or item:FindFirstChildOfClass("UICorner");
|
||||
return (target and target.CornerRadius.Offset) or 0;
|
||||
elseif index == "PaddingAll" or index == "paddingAll" then
|
||||
local target = (ClassName == "UIPadding" and item) or item:FindFirstChildOfClass("UIPadding");
|
||||
return (target and target.PaddingLeft) or UDim.new(0,0);
|
||||
elseif index == "PaddingAllOffset" or index == "paddingAllOffset" then
|
||||
local target = (ClassName == "UIPadding" and item) or item:FindFirstChildOfClass("UIPadding");
|
||||
return (target and target.PaddingLeft.Offset) or 0;
|
||||
return round.GetRound(item)
|
||||
elseif index == "Corner" then
|
||||
local target = (ClassName == "UICorner" and item) or item:FindFirstChildOfClass("UICorner")
|
||||
return (target and target.CornerRadius.Offset) or 0
|
||||
elseif index == "PaddingAll" then
|
||||
local target = (ClassName == "UIPadding" and item) or item:FindFirstChildOfClass("UIPadding")
|
||||
return (target and target.PaddingLeft) or UDim.new(0,0)
|
||||
elseif index == "PaddingAllOffset" then
|
||||
local target = (ClassName == "UIPadding" and item) or item:FindFirstChildOfClass("UIPadding")
|
||||
return (target and target.PaddingLeft.Offset) or 0
|
||||
elseif index == "Scale" then
|
||||
local target = (ClassName == "UIScale" and item) or item:FindFirstChildOfClass("UIScale");
|
||||
return (target and target.Scale) or 1;
|
||||
local target = (ClassName == "UIScale" and item) or item:FindFirstChildOfClass("UIScale")
|
||||
return (target and target.Scale) or 1
|
||||
end
|
||||
return item[index];
|
||||
return item[index]
|
||||
end
|
||||
new.GetProperty = GetProperty
|
||||
|
||||
local function SetProperty(item,index,value,ClassName)
|
||||
if type(item) == "table" then item[index] = value; return; end
|
||||
ClassName = ClassName or item.ClassName;
|
||||
local isImage = (ClassName == "ImageLabel" or ClassName == "ImageButton");
|
||||
if (index == "RoundSize" or index == "roundSize") and isImage then
|
||||
-- if it is not a roblox instance, just call __index
|
||||
if type(item) == "table" then
|
||||
item[index] = value
|
||||
return
|
||||
end
|
||||
|
||||
-- check class name
|
||||
ClassName = ClassName or item.ClassName
|
||||
-- check is ImageLabel or ImageButton
|
||||
local isImage = (ClassName == "ImageLabel" or ClassName == "ImageButton")
|
||||
|
||||
-- Round Image
|
||||
if index == "RoundSize" and isImage then
|
||||
if not round then
|
||||
error("[QUAD] module 'round' needs to be loaded for set image round size but it is not found on 'src.libs'. you should adding that to src.libs directory");
|
||||
error("[QUAD] module 'round' needs to be loaded for set image round size but it is not found on 'src.libs'. you should adding that to src.libs directory")
|
||||
end
|
||||
round.SetRound(item,value);
|
||||
elseif index == "UIRoundSize" or index == "uiRoundSize" or index == "UiRoundSize" then
|
||||
local uiCorner = (ClassName == "UICorner" and item) or item:FindFirstChildOfClass("UICorner") or InstanceNewWithName("UICorner",item,"_quad_round");
|
||||
uiCorner.CornerRadius = UDim.new(0,value);
|
||||
elseif index == "PaddingAll" or index == "paddingAll" then
|
||||
local target = (ClassName == "UIPadding" and item) or item:FindFirstChildOfClass("UIPadding") or InstanceNewWithName("UIPadding",item,"_quad_padding");
|
||||
target.PaddingLeft = value;
|
||||
target.PaddingRight = value;
|
||||
target.PaddingTop = value;
|
||||
target.PaddingBottom = value;
|
||||
elseif index == "PaddingAllOffset" or index == "paddingAllOffset" then
|
||||
local target = (ClassName == "UIPadding" and item) or item:FindFirstChildOfClass("UIPadding") or InstanceNewWithName("UIPadding",item,"_quad_padding");
|
||||
local padding = UDim.new(0,value);
|
||||
target.PaddingLeft = padding;
|
||||
target.PaddingRight = padding;
|
||||
target.PaddingTop = padding;
|
||||
target.PaddingBottom = padding;
|
||||
round.SetRound(item,value)
|
||||
-- UIRound
|
||||
elseif index == "Corner" then
|
||||
local uiCorner = (ClassName == "UICorner" and item) or item:FindFirstChildOfClass("UICorner") or InstanceNewWithName("UICorner",item,"_quad_round")
|
||||
uiCorner.CornerRadius = UDim.new(0,value)
|
||||
-- PaddingAll
|
||||
elseif index == "PaddingAll" then
|
||||
local target = (ClassName == "UIPadding" and item) or item:FindFirstChildOfClass("UIPadding") or InstanceNewWithName("UIPadding",item,"_quad_padding")
|
||||
target.PaddingLeft = value
|
||||
target.PaddingRight = value
|
||||
target.PaddingTop = value
|
||||
target.PaddingBottom = value
|
||||
-- PaddingAll with Offset
|
||||
elseif index == "PaddingAllOffset" then
|
||||
local target = (ClassName == "UIPadding" and item) or item:FindFirstChildOfClass("UIPadding") or InstanceNewWithName("UIPadding",item,"_quad_padding")
|
||||
local padding = UDim.new(0,value)
|
||||
target.PaddingLeft = padding
|
||||
target.PaddingRight = padding
|
||||
target.PaddingTop = padding
|
||||
target.PaddingBottom = padding
|
||||
-- Scale
|
||||
elseif index == "Scale" then
|
||||
local target = (ClassName == "UIScale" and item) or item:FindFirstChildOfClass("UIScale") or InstanceNewWithName("UIScale",item,"_quad_scale");
|
||||
target.Scale = value;
|
||||
local target = (ClassName == "UIScale" and item) or item:FindFirstChildOfClass("UIScale") or InstanceNewWithName("UIScale",item,"_quad_scale")
|
||||
target.Scale = value
|
||||
else
|
||||
item[index] = value; -- set property
|
||||
-- other, just set property
|
||||
item[index] = value
|
||||
end
|
||||
end
|
||||
new.SetProperty = SetProperty
|
||||
|
||||
local function RawGetProperty(item,index)
|
||||
return item[index];
|
||||
return item[index]
|
||||
end
|
||||
local function PcallGetProperty(item,index)
|
||||
local ok,err = pcall(RawGetProperty,item,index);
|
||||
if ok then return err; end
|
||||
return nil;
|
||||
local ok,err = pcall(RawGetProperty,item,index)
|
||||
if ok then return err end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function ProcessQuadProperty(processedProperty,iprop,holder,item,className,index,value)
|
||||
if processedProperty[index] then return; end
|
||||
if processedProperty[index] then
|
||||
return
|
||||
end
|
||||
|
||||
local valueType = typeof(value);
|
||||
local indexType = typeof(index);
|
||||
local valueType = typeof(value)
|
||||
local indexType = typeof(index)
|
||||
local quadType = valueType == "table" and PcallGetProperty(value,"__type")
|
||||
|
||||
if indexType == "string" and quadType == "quad_register" then
|
||||
-- register (bind to store event)
|
||||
|
||||
processedProperty[index] = true; -- ignore next
|
||||
processedProperty[index] = true -- ignore next
|
||||
|
||||
-- store reading
|
||||
do
|
||||
local setValue = value:calcWithDefault(item);
|
||||
local setValue = value:calcWithDefault(item)
|
||||
if setValue == nil then
|
||||
warn "[Quad] register return value must not be nil, but got nil. did you inited values before?";
|
||||
warn "[Quad] register return value must not be nil, but got nil. did you inited values before?"
|
||||
end
|
||||
SetProperty(item,index,setValue,className);
|
||||
SetProperty(item,index,setValue,className)
|
||||
end
|
||||
|
||||
-- adding handle function (bindding)
|
||||
local function regFn(_,newValue,key)
|
||||
local setValue,tween = value:calcWithNewValue(item,newValue,key);
|
||||
local setValue,tween = value:calcWithNewValue(item,newValue,key)
|
||||
if tween then
|
||||
if not advancedTween then
|
||||
return warn "[QUAD] module 'AdvancedTween' needs to be loaded for tween properties but it is not found on 'src.libs'. you should adding that to src.libs directory";
|
||||
return warn "[QUAD] module 'AdvancedTween' needs to be loaded for tween properties but it is not found on 'src.libs'. you should adding that to src.libs directory"
|
||||
end
|
||||
local ended, onStepped;
|
||||
local ended, onStepped
|
||||
if tween.Ended then
|
||||
ended = function (...)
|
||||
tween.Ended(item,...);
|
||||
tween.Ended(item,...)
|
||||
end
|
||||
end
|
||||
if tween.OnStepped then
|
||||
onStepped = function (...)
|
||||
tween.OnStepped(item,...);
|
||||
tween.OnStepped(item,...)
|
||||
end
|
||||
end
|
||||
advancedTween.RunTween(item,tween,{[index] = setValue},ended,onStepped,SetProperty,GetProperty);
|
||||
advancedTween.RunTween(item,tween,{[index] = setValue},ended,onStepped,SetProperty,GetProperty)
|
||||
else
|
||||
SetProperty(item,index,setValue,className);
|
||||
SetProperty(item,index,setValue,className)
|
||||
end
|
||||
end
|
||||
value:register(regFn);
|
||||
value:register(regFn)
|
||||
|
||||
-- this is using hacky of roblox instance
|
||||
-- this is will keep reference from week table until
|
||||
-- inscance got GCed
|
||||
item:GetPropertyChangedSignal("ClassName"):Connect(regFn);
|
||||
item:GetPropertyChangedSignal("ClassName"):Connect(regFn)
|
||||
elseif (valueType == "function" or valueType == "table") and indexType == "string" and bind(item,index,value,valueType) then -- connect event
|
||||
-- event binding
|
||||
elseif indexType == "string" then
|
||||
processedProperty[index] = true; -- ignore next
|
||||
processedProperty[index] = true -- ignore next
|
||||
-- prop set
|
||||
SetProperty(item,index,value,className);
|
||||
SetProperty(item,index,value,className)
|
||||
elseif indexType == "number" and valueType == "table" and quadType == "quad_style" then -- style
|
||||
-- style parsing
|
||||
for _,thisStyle in ipairs(parseStyles(value)) do
|
||||
if not processedProperty[thisStyle] then
|
||||
processedProperty[thisStyle] = true;
|
||||
processedProperty[thisStyle] = true
|
||||
for styleIndex,styleValue in pairs(thisStyle) do
|
||||
if type(styleValue) ~= "table" or pcall(styleValue,"__type") ~= "quad_style" then
|
||||
ProcessQuadProperty(processedProperty,iprop,holder,item,className,styleIndex,styleValue);
|
||||
ProcessQuadProperty(processedProperty,iprop,holder,item,className,styleIndex,styleValue)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif indexType == "number" and valueType ~= "boolean" then -- object
|
||||
-- child object
|
||||
mountfunc(item,((iprop == 1) and value or value:Clone()),holder);
|
||||
mountfunc(item,((iprop == 1) and value or value:Clone()),holder)
|
||||
end
|
||||
end
|
||||
|
||||
-- make object that from instance, class and more
|
||||
function new.make(ClassName,...) -- render object
|
||||
function new.Make(ClassName,...) -- render object
|
||||
-- make object from ClassName
|
||||
local item;
|
||||
local classOfClassName = type(ClassName);
|
||||
local item
|
||||
local classOfClassName = type(ClassName)
|
||||
if classOfClassName == "string" then -- if classname is a string value, cdall instance.new for making new roblox instance
|
||||
item = InstanceNew(ClassName);
|
||||
item = InstanceNew(ClassName)
|
||||
elseif classOfClassName == "function" then -- if classname is a function value, call it for making new object (OOP object)
|
||||
item = ClassName();
|
||||
item = ClassName()
|
||||
elseif classOfClassName == "table" then -- if classname is a calss what is included new function, call it for making new object (object)
|
||||
local func = ClassName.new or ClassName.New or ClassName.__new;
|
||||
local func = ClassName.new or ClassName.New or ClassName.__new
|
||||
if ClassName.__noSetup then -- if is support initing props
|
||||
local childs,props,parsed,binds = {},pack(...),{},{};
|
||||
local childs,props,parsed,binds = {},pack(...),{},{}
|
||||
for iprop = props.n,1,-1 do
|
||||
local prop = props[iprop];
|
||||
local prop = props[iprop]
|
||||
if prop then
|
||||
for i,v in pairs(prop) do
|
||||
if type(i) == "number" then
|
||||
childs[i] = ((iprop == 1) and v or v:Clone());
|
||||
childs[i] = ((iprop == 1) and v or v:Clone())
|
||||
elseif bind(i) then
|
||||
binds[i] = v;
|
||||
binds[i] = v
|
||||
else
|
||||
parsed[i] = v;
|
||||
parsed[i] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
item = func(parsed);
|
||||
local holder = getHolder(item);
|
||||
item = func(parsed)
|
||||
local holder = getHolder(item)
|
||||
for _,v in ipairs(childs) do
|
||||
mountfunc(item,v,holder);
|
||||
mountfunc(item,v,holder)
|
||||
end
|
||||
for i,v in pairs(binds) do
|
||||
bind(item,i,v);
|
||||
bind(item,i,v)
|
||||
end
|
||||
return item;
|
||||
return item
|
||||
end
|
||||
item = func();
|
||||
item = func()
|
||||
end
|
||||
if not item then -- if cannot make new object, ignore this call
|
||||
local str = tostring(ClassName);
|
||||
warn(("[Quad] fail to make item '%s', did you forget to checking the class '%s' is exist?"):format(str,str));
|
||||
local str = tostring(ClassName)
|
||||
warn(("[Quad] fail to make item '%s', did you forget to checking the class '%s' is exist?"):format(str,str))
|
||||
end
|
||||
|
||||
-- set property and adding child and binding functions
|
||||
local holder = getHolder(item); -- to __holder or holder or it self (for tabled)
|
||||
local holder = getHolder(item) -- to __holder or holder or it self (for tabled)
|
||||
-- for iprop,prop in ipairs({...}) do
|
||||
local propsListArray = pack(...);
|
||||
local processedProperty = {};
|
||||
local propsListArray = pack(...)
|
||||
local processedProperty = {}
|
||||
for iprop = 1,propsListArray.n do
|
||||
local prop = propsListArray[iprop]
|
||||
if prop then
|
||||
for index,value in pairs(prop) do
|
||||
if type(index) ~= "number" then
|
||||
ProcessQuadProperty(processedProperty,iprop,holder,item,ClassName,index,value);
|
||||
ProcessQuadProperty(processedProperty,iprop,holder,item,ClassName,index,value)
|
||||
end
|
||||
end
|
||||
for index,value in ipairs(prop) do
|
||||
ProcessQuadProperty(processedProperty,iprop,holder,item,ClassName,index,value);
|
||||
ProcessQuadProperty(processedProperty,iprop,holder,item,ClassName,index,value)
|
||||
end
|
||||
end
|
||||
end
|
||||
return item;
|
||||
return item
|
||||
end
|
||||
local make = new.make;
|
||||
local make = new.Make
|
||||
|
||||
-- import quad object
|
||||
function new.import(ClassName,defaultProperties) -- make new quad class object
|
||||
function new.Import(ClassName,defaultProperties) -- make new quad class object
|
||||
if type(ClassName) == "userdata" and ClassName.ClassName == "ModuleScript" then
|
||||
ClassName = require(ClassName);
|
||||
ClassName = require(ClassName)
|
||||
end
|
||||
local this = defaultProperties or {};
|
||||
local this = defaultProperties or {}
|
||||
setmetatable(this,{
|
||||
__type = "quad_imported_class",
|
||||
__call = function (self,prop,...)
|
||||
local propType = type(prop);
|
||||
local propType = type(prop)
|
||||
if propType == "string" then
|
||||
local lastName = prop;
|
||||
local lastName = prop
|
||||
return function (nprop,...)
|
||||
nprop = nprop or {};
|
||||
nprop.Name = gsub(gsub(match(lastName,"[^,]+")," +$",""),"^ +","");
|
||||
nprop = nprop or {}
|
||||
nprop.Name = gsub(gsub(match(lastName,"[^,]+")," +$",""),"^ +","")
|
||||
for styleName,styleObj in pairs(styleList) do
|
||||
if match(prop,styleName) then
|
||||
insert(nprop,styleObj);
|
||||
insert(nprop,styleObj)
|
||||
end
|
||||
end
|
||||
local item = make(ClassName,nprop,...,this);
|
||||
addObject(lastName,item);
|
||||
return item;
|
||||
end;
|
||||
local item = make(ClassName,nprop,...,this)
|
||||
addObject(lastName,item)
|
||||
return item
|
||||
end
|
||||
elseif propType == "nil" then
|
||||
return make(ClassName,this);
|
||||
return make(ClassName,this)
|
||||
end
|
||||
return make(ClassName,prop,...,this);
|
||||
end;
|
||||
});
|
||||
return this;
|
||||
return make(ClassName,prop,...,this)
|
||||
end
|
||||
})
|
||||
return this
|
||||
end
|
||||
|
||||
-- set module calling function
|
||||
setmetatable(new,{
|
||||
__call = function (self,...)
|
||||
return new.import(...);
|
||||
end;
|
||||
});
|
||||
return new.Import(...)
|
||||
end
|
||||
})
|
||||
|
||||
-- make class
|
||||
function new.extend()
|
||||
local this = {__type = "quad_extend"};
|
||||
function new.Extend()
|
||||
local this = {__type = "quad_extend"}
|
||||
|
||||
--- make new object
|
||||
function this.new(prop)
|
||||
function this.New(prop)
|
||||
-- make metatable
|
||||
prop = storeNew(prop,nil);
|
||||
local parent = prop and (prop.Parent or prop.parent);
|
||||
local self = {__prop = prop; __parent = parent,__propertyChangedSignals = {}};
|
||||
local init = this.init;
|
||||
prop = storeNew(prop,nil)
|
||||
local parent = prop and (prop.Parent or prop.parent)
|
||||
local self = {
|
||||
__prop = prop;
|
||||
__parent = parent;
|
||||
__propertyChangedSignals = {};
|
||||
}
|
||||
local init = this.Init
|
||||
if init then
|
||||
init(self,prop);
|
||||
init(self,prop)
|
||||
end
|
||||
setmetatable(self,this);
|
||||
initStoreRegisterBinding(prop,this);
|
||||
setmetatable(self,this)
|
||||
initStoreRegisterBinding(prop,this)
|
||||
|
||||
-- render that
|
||||
local object = self:render(prop);
|
||||
rawset(self,"__object",object);
|
||||
rawset(self,"__holder",object);
|
||||
local object = self:Render(prop)
|
||||
rawset(self,"__object",object)
|
||||
rawset(self,"__holder",object)
|
||||
if parent then
|
||||
rawset(self,"__parent",parent);
|
||||
rawset(self,"__parent",parent)
|
||||
mountfunc(self,parent)
|
||||
end
|
||||
-- prevent gc
|
||||
((type(object) == "table" and object.__object) or object)
|
||||
:GetPropertyChangedSignal "ClassName":Connect(function()
|
||||
return self;
|
||||
end);
|
||||
return self
|
||||
end)
|
||||
|
||||
--after render
|
||||
local afterRender = this.afterRender;
|
||||
local afterRender = this.AfterRender
|
||||
if afterRender then
|
||||
afterRender(self,object);
|
||||
afterRender(self,object)
|
||||
end
|
||||
return self;
|
||||
return self
|
||||
end
|
||||
|
||||
function this:GetPropertyChangedSignal(propertyName)
|
||||
|
|
@ -333,126 +353,123 @@ function module.init(shared)
|
|||
end
|
||||
|
||||
--- re-render object (if some props chaged, call this to render again)
|
||||
function this:update() -- swap object
|
||||
local object = rawget(self,"__object"); -- get last instance
|
||||
local parent = object and object.Parent; -- date parent
|
||||
function this:Update() -- swap object
|
||||
local object = rawget(self,"__object") -- get last instance
|
||||
local parent = object and object.Parent -- date parent
|
||||
if not object then
|
||||
parent = rawget(self,"__parent");
|
||||
parent = rawget(self,"__parent")
|
||||
end
|
||||
local lastObject = object;
|
||||
local lastObject = object
|
||||
if lastObject then
|
||||
lastObject.Parent = nil;
|
||||
lastObject.Parent = nil
|
||||
end
|
||||
|
||||
object = self:render(self.__prop); -- new instance
|
||||
rawset(self,"__holder",object);
|
||||
rawset(self,"__object",object);
|
||||
object.Parent = getHolder(parent); -- update parent
|
||||
object = self:Render(self.__prop) -- new instance
|
||||
rawset(self,"__holder",object)
|
||||
rawset(self,"__object",object)
|
||||
object.Parent = getHolder(parent) -- update parent
|
||||
|
||||
-- restore childs
|
||||
local child = rawget(self,"__child");
|
||||
local child = rawget(self,"__child")
|
||||
if child then
|
||||
for _,v in pairs(child) do
|
||||
if v then
|
||||
v.Parent = object;
|
||||
v.Parent = object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- prevnet gc
|
||||
((type(object) == "table" and object.__object) or object):GetPropertyChangedSignal "ClassName":Connect(function()
|
||||
return self;
|
||||
end);
|
||||
return self
|
||||
end)
|
||||
if lastObject then -- remove old instance
|
||||
self:Destroy(lastObject);
|
||||
self:Destroy(lastObject)
|
||||
end
|
||||
|
||||
--after render
|
||||
local afterRender = this.afterRender;
|
||||
local afterRender = this.AfterRender
|
||||
if afterRender then
|
||||
afterRender(self,object);
|
||||
afterRender(self,object)
|
||||
end
|
||||
end
|
||||
|
||||
-- define destroy method
|
||||
function this:Destroy(object)
|
||||
local unload = rawget(self,"unload");
|
||||
object = object or rawget(self,"__object");
|
||||
local unload = this.Unload
|
||||
object = object or rawget(self,"__object")
|
||||
if object then
|
||||
if unload then
|
||||
unload(self,object);
|
||||
unload(self,object)
|
||||
else
|
||||
local destroy = (object.Destroy or object.destroy);
|
||||
local destroy = (object.Destroy or object.destroy)
|
||||
if destroy then
|
||||
pcall(destroy,object);
|
||||
pcall(destroy,object)
|
||||
end
|
||||
end
|
||||
end
|
||||
self = nil;
|
||||
self = nil
|
||||
end
|
||||
|
||||
--- link to new
|
||||
function this.__call(self,...)
|
||||
return (self.new or self.New or self.__new)(...);
|
||||
end;
|
||||
return (self.new or self.New or self.__new)(...)
|
||||
end
|
||||
|
||||
-- indexer (getter)
|
||||
function this:__index(k)
|
||||
if k == "destroy" then
|
||||
return self.Destroy;
|
||||
end
|
||||
local getter = this.getter[k];
|
||||
local getter = this.Getter[k]
|
||||
if getter then
|
||||
return getter(self,rawget(self,"__object"));
|
||||
return getter(self,rawget(self,"__object"))
|
||||
end
|
||||
|
||||
-- from this (have more priority)
|
||||
local fromThis = this[k];
|
||||
local fromThis = this[k]
|
||||
if fromThis then
|
||||
return fromThis;
|
||||
return fromThis
|
||||
end
|
||||
|
||||
-- from prop, not start with '_' (private value)
|
||||
if k:sub(1,1) ~= "_" then
|
||||
return self.__prop[k];
|
||||
return self.__prop[k]
|
||||
end
|
||||
end
|
||||
|
||||
--- new indexer (setter)
|
||||
function this:__newindex(k,v)
|
||||
-- from setter
|
||||
local setter = this.setter[k];
|
||||
local setter = this.Setter[k]
|
||||
if setter then
|
||||
return setter(self,v,rawget(self,"__object"));
|
||||
return setter(self,v,rawget(self,"__object"))
|
||||
end
|
||||
|
||||
-- is private (self value)
|
||||
if k == "holder" or k:sub(1,1) == "_" then
|
||||
return rawset(self,k,v);
|
||||
return rawset(self,k,v)
|
||||
end
|
||||
|
||||
-- prop update
|
||||
self.__prop[k] = v;
|
||||
if this.updateTriggers[k] then
|
||||
self:update();
|
||||
self.__prop[k] = v
|
||||
if this.UpdateTriggers[k] then
|
||||
self:Update()
|
||||
end
|
||||
end
|
||||
|
||||
this.getter = {};
|
||||
this.setter = {
|
||||
this.Getter = {}
|
||||
this.Setter = {
|
||||
Parent = function(self,parent,object)
|
||||
rawset(self,"__parent",parent);
|
||||
rawset(self,"__parent",parent)
|
||||
if object then
|
||||
object.Parent = getHolder(parent);
|
||||
object.Parent = getHolder(parent)
|
||||
end
|
||||
end;
|
||||
};
|
||||
this.updateTriggers = {};
|
||||
this.__noSetup = true;
|
||||
return this;
|
||||
end
|
||||
}
|
||||
this.UpdateTriggers = {}
|
||||
this.__noSetup = true
|
||||
return this
|
||||
end
|
||||
|
||||
return new;
|
||||
return new
|
||||
end
|
||||
|
||||
return module;
|
||||
return module
|
||||
|
|
|
|||
120
src/event.lua
120
src/event.lua
|
|
@ -1,139 +1,101 @@
|
|||
local module = {};
|
||||
local unpack = table.unpack;
|
||||
local wrap = coroutine.wrap;
|
||||
local module = {}
|
||||
local unpack = table.unpack
|
||||
local wrap = coroutine.wrap
|
||||
|
||||
---@param shared quad_export
|
||||
---@return quad_module_event
|
||||
function module.init(shared)
|
||||
local warn = shared.warn;
|
||||
local warn = shared.warn
|
||||
---@class quad_module_event
|
||||
local new = {__type = "quad_module_event"};
|
||||
local new = {__type = "quad_module_event"}
|
||||
|
||||
local prefix = "Event::";
|
||||
local prefix = "Event::"
|
||||
local special = {
|
||||
["Property::(.+)"] = function (this,func,property)
|
||||
this:GetPropertyChangedSignal(property):Connect(function()
|
||||
func(this,this[property]);
|
||||
end);
|
||||
func(this,this[property])
|
||||
end)
|
||||
end;
|
||||
["CreatedSync::"] = function (this,func)
|
||||
func(this);
|
||||
func(this)
|
||||
end;
|
||||
["CreatedAsync::"] = function (this,func)
|
||||
wrap(func)(this);
|
||||
wrap(func)(this)
|
||||
end;
|
||||
};
|
||||
}
|
||||
|
||||
local prefixLen = #prefix;
|
||||
local prefixLen = #prefix
|
||||
setmetatable(new,{
|
||||
__call = function(self,eventName)
|
||||
return prefix .. eventName;
|
||||
return prefix .. eventName
|
||||
end;
|
||||
__index = function(self,key)
|
||||
if key == "createdSync" then
|
||||
warn "[Quad] event.createdSync is deprecated. Use event.created instead"
|
||||
return self.created;
|
||||
return self.created
|
||||
end
|
||||
end;
|
||||
});
|
||||
})
|
||||
|
||||
-- try binding, if key dose match with anything, ignore call
|
||||
function new.bind(this,key,func,typefunc)
|
||||
function new.Bind(this,key,func,typefunc)
|
||||
if not key then
|
||||
key = this;
|
||||
this = nil;
|
||||
key = this
|
||||
this = nil
|
||||
end
|
||||
|
||||
-- if is advanced binding (self setted)
|
||||
typefunc = typefunc or type(func);
|
||||
local self;
|
||||
typefunc = typefunc or type(func)
|
||||
local self
|
||||
if typefunc == "table" then
|
||||
local t = func;
|
||||
self = t.self;
|
||||
func = t.func;
|
||||
if not self then self = t[1]; end
|
||||
if not func then func = t[2]; end
|
||||
local t = func
|
||||
self = t.self
|
||||
func = t.func
|
||||
if not self then self = t[1] end
|
||||
if not func then func = t[2] end
|
||||
end
|
||||
-- check prefix
|
||||
if key:sub(1,prefixLen) ~= prefix then
|
||||
return;
|
||||
return
|
||||
end
|
||||
key = key:sub(prefixLen + 1,-1);
|
||||
key = key:sub(prefixLen + 1,-1)
|
||||
|
||||
-- find special bindings
|
||||
for specKey,specFunc in pairs(special) do
|
||||
local find = {key:match(specKey)};
|
||||
local find = {key:match(specKey)}
|
||||
if #find ~= 0 then
|
||||
if func then
|
||||
specFunc(this,func,unpack(find));
|
||||
specFunc(this,func,unpack(find))
|
||||
end
|
||||
return true;
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- binding normal events
|
||||
if this then
|
||||
local event = this[key];
|
||||
local event = this[key]
|
||||
if event then
|
||||
if func then
|
||||
event:Connect(function(...)
|
||||
func(self or this,...);
|
||||
end);
|
||||
func(self or this,...)
|
||||
end)
|
||||
end
|
||||
return true;
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- property changed binding
|
||||
local prefixProperty = prefix .. "Property::";
|
||||
function new.prop(name)
|
||||
return prefixProperty .. name;
|
||||
local prefixProperty = prefix .. "Property::"
|
||||
function new.Prop(name)
|
||||
return prefixProperty .. name
|
||||
end
|
||||
|
||||
-- when created binding
|
||||
new.createdAsync = prefix .. "CreatedAsync::";
|
||||
new.created = prefix .. "CreatedSync::";
|
||||
new.CreatedAsync = prefix .. "CreatedAsync::"
|
||||
new.Created = prefix .. "CreatedSync::"
|
||||
|
||||
-- roblox connections disconnecter
|
||||
local insert = table.insert;
|
||||
local idSpace = {};
|
||||
local disconnecterClass = {__type = "quad_disconnecter"};
|
||||
function disconnecterClass:add(connection)
|
||||
insert(self,connection);
|
||||
end
|
||||
function disconnecterClass:disconnect()
|
||||
for i,v in pairs(self) do
|
||||
pcall(v.Disconnect,v);
|
||||
self[i] = nil;
|
||||
end
|
||||
end
|
||||
function disconnecterClass:destroy()
|
||||
local id = self.id;
|
||||
if id then
|
||||
idSpace[id] = nil;
|
||||
end
|
||||
for i,v in pairs(self) do
|
||||
pcall(v.Disconnect,v);
|
||||
self[i] = nil;
|
||||
end
|
||||
end
|
||||
disconnecterClass.__index = disconnecterClass;
|
||||
function new.disconnecter(id)
|
||||
if id then
|
||||
local old = idSpace[id];
|
||||
if old then
|
||||
return old;
|
||||
end
|
||||
end
|
||||
local this = setmetatable({id = id},disconnecterClass);
|
||||
if id then
|
||||
idSpace[id] = this;
|
||||
end
|
||||
return this;
|
||||
end
|
||||
|
||||
return new;
|
||||
return new
|
||||
end
|
||||
|
||||
return module;
|
||||
return module
|
||||
26
src/init.lua
26
src/init.lua
|
|
@ -1,5 +1,5 @@
|
|||
---@class quad
|
||||
local module = {};
|
||||
local module = {}
|
||||
|
||||
local IS_TEST = true
|
||||
local VER = "1.14" .. (IS_TEST and "B" or "")
|
||||
|
|
@ -7,19 +7,19 @@ if IS_TEST then
|
|||
warn("You are using BETA version of quad now. Many features may change in the future and unstable. AS USING BETA VERSION OF QUAD, YOU SHOULD KNOW IT WILL BUGGY SOMETIME. still on development - you can ignore this message if have no issue. if you have issue on using quad, please report issue on github. VERSION: "..VER)
|
||||
end
|
||||
|
||||
local require = require(script.require);
|
||||
local style = require "style";
|
||||
local event = require "event";
|
||||
local store = require "store";
|
||||
local class = require "class";
|
||||
local mount = require "mount";
|
||||
-- local lang = require "lang";
|
||||
local require = require(script.require)
|
||||
local style = require "style"
|
||||
local event = require "event"
|
||||
local store = require "store"
|
||||
local class = require "class"
|
||||
local mount = require "mount"
|
||||
-- local lang = require "lang"
|
||||
|
||||
-- submodule
|
||||
local _,advancedTween = pcall(require,"libs.AdvancedTween");
|
||||
local _,round = pcall(require,"libs.round");
|
||||
local _,advancedTween = pcall(require,"libs.AdvancedTween")
|
||||
local _,round = pcall(require,"libs.round")
|
||||
|
||||
local idSpace = {};
|
||||
local idSpace = {}
|
||||
|
||||
---@return quad_export this
|
||||
---@return quad_module_round round
|
||||
|
|
@ -63,7 +63,7 @@ end
|
|||
|
||||
function module.Uninit(id)
|
||||
pcall(cleanup,idSpace[id])
|
||||
idSpace[id] = nil;
|
||||
idSpace[id] = nil
|
||||
end
|
||||
|
||||
return module;
|
||||
return module
|
||||
|
|
|
|||
|
|
@ -8,28 +8,28 @@ local IsRoblox = version and version() or nil
|
|||
|
||||
local module = {}
|
||||
function module.BindStep(StepFunction)
|
||||
if IsRoblox then
|
||||
if module.Connection then
|
||||
error("Function was binded already")
|
||||
end
|
||||
local RunService = game:GetService("RunService")
|
||||
if RunService:IsStudio() and (not RunService:IsRunning()) and RunService:IsEdit() then
|
||||
module.Connection = RunService.Heartbeat:Connect(StepFunction)
|
||||
else
|
||||
-- RunService:BindToRenderStep("advancedTween",1,StepFunction)
|
||||
module.Connection = RunService.RenderStepped:Connect(StepFunction)
|
||||
end
|
||||
else
|
||||
-- do something here
|
||||
end
|
||||
if IsRoblox then
|
||||
if module.Connection then
|
||||
error("Function was binded already")
|
||||
end
|
||||
local RunService = game:GetService("RunService")
|
||||
if RunService:IsStudio() and (not RunService:IsRunning()) and RunService:IsEdit() then
|
||||
module.Connection = RunService.Heartbeat:Connect(StepFunction)
|
||||
else
|
||||
-- RunService:BindToRenderStep("advancedTween",1,StepFunction)
|
||||
module.Connection = RunService.RenderStepped:Connect(StepFunction)
|
||||
end
|
||||
else
|
||||
-- do something here
|
||||
end
|
||||
end
|
||||
|
||||
function module.UnbindAll()
|
||||
if not module.Connection then
|
||||
error("Function was not binded yet")
|
||||
end
|
||||
module.Connection:Disconnect()
|
||||
module.Connection = nil
|
||||
if not module.Connection then
|
||||
error("Function was not binded yet")
|
||||
end
|
||||
module.Connection:Disconnect()
|
||||
module.Connection = nil
|
||||
end
|
||||
|
||||
return module
|
||||
|
|
|
|||
|
|
@ -63,9 +63,9 @@ module.EasingFunction = module.EasingFunctions
|
|||
------------------------------------
|
||||
-- 이중 선형, Alpha 를 받아서 값을 구해옴
|
||||
local function Lerp(start,goal,alpha)
|
||||
if alpha == 1 then return goal end
|
||||
if alpha == 0 then return start end
|
||||
return start + ((goal - start) * alpha)
|
||||
if alpha == 1 then return goal end
|
||||
if alpha == 0 then return start end
|
||||
return start + ((goal - start) * alpha)
|
||||
end
|
||||
|
||||
-- 기본적으로 로블록스가 Lerp 를 지원하는 Class
|
||||
|
|
|
|||
103
src/mount.lua
103
src/mount.lua
|
|
@ -1,97 +1,102 @@
|
|||
local module = {};
|
||||
local insert = table.insert;
|
||||
local pack = table.pack;
|
||||
local module = {}
|
||||
local insert = table.insert
|
||||
local pack = table.pack
|
||||
|
||||
---@param shared quad_export
|
||||
---@return quad_module_mount
|
||||
function module.init(shared)
|
||||
local warn = shared.warn;
|
||||
local warn = shared.warn
|
||||
---@class quad_module_mount
|
||||
local new = {__type = "quad_module_mount"};
|
||||
local new = {__type = "quad_module_mount"}
|
||||
|
||||
local mountClass = {__type = "quad_mount"};
|
||||
mountClass.__index = mountClass;
|
||||
function mountClass:unmount()
|
||||
-- get Holder object
|
||||
local function getHolder(item)
|
||||
return (type(item) == "table") and (item._holder or item.holder or item.__holder) or item
|
||||
end
|
||||
new.GetHolder = getHolder
|
||||
|
||||
-- mount class
|
||||
local mountClass = {__type = "quad_mount"}
|
||||
mountClass.__index = mountClass
|
||||
function mountClass:Unmount()
|
||||
local this = self.this
|
||||
local typeThis = type(this);
|
||||
local typeThis = type(this)
|
||||
if typeThis == "userdata" then
|
||||
this:Destroy();
|
||||
this:Destroy()
|
||||
elseif typeThis == "table" then
|
||||
pcall(function()
|
||||
this.Parent = nil;
|
||||
end);
|
||||
local destroyThis = this.Destroy;
|
||||
this.Parent = nil
|
||||
end)
|
||||
local destroyThis = this.Destroy
|
||||
if destroyThis then
|
||||
pcall(destroyThis,this);
|
||||
pcall(destroyThis,this)
|
||||
end
|
||||
--if sef.to when
|
||||
-- todo for remove child on parent
|
||||
end
|
||||
end
|
||||
|
||||
function new.getHolder(item)
|
||||
return (type(item) == "table") and (item._holder or item.holder or item.__holder) or item;
|
||||
end
|
||||
local getHolder = new.getHolder;
|
||||
|
||||
-- we should add plugin support
|
||||
function new.mount(to,this,holder)
|
||||
local thisObject = this;
|
||||
-- mount function
|
||||
local function mount(to,this,holder)
|
||||
local thisObject = this
|
||||
if type(this) == "table" then
|
||||
thisObject = rawget(this,"__object");
|
||||
local parent = rawget(this,"__parent");
|
||||
thisObject = rawget(this,"__object")
|
||||
local parent = rawget(this,"__parent")
|
||||
if type(parent) == "table" then
|
||||
local parentChild = rawget(parent,"__child");
|
||||
local parentChild = rawget(parent,"__child")
|
||||
if parentChild then
|
||||
for i,v in pairs(parentChild) do
|
||||
if v == this then
|
||||
parentChild[i] = nil;
|
||||
parentChild[i] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rawset(this,"__parent",to);
|
||||
rawset(this,"__parent",to)
|
||||
end
|
||||
if thisObject then
|
||||
thisObject.Parent = holder or getHolder(to);
|
||||
thisObject.Parent = holder or getHolder(to)
|
||||
else
|
||||
this.Parent = holder or getHolder(to);
|
||||
this.Parent = holder or getHolder(to)
|
||||
end
|
||||
if type(to) == "table" then
|
||||
local child = rawget(to,"__child");
|
||||
local child = rawget(to,"__child")
|
||||
if not child then
|
||||
child = {};
|
||||
rawset(to,"__child",child);
|
||||
child = {}
|
||||
rawset(to,"__child",child)
|
||||
end
|
||||
insert(child,this);
|
||||
insert(child,this)
|
||||
end
|
||||
return setmetatable({to = to,this = this},mountClass);
|
||||
return setmetatable({to = to,this = this},mountClass)
|
||||
end
|
||||
local mount = new.mount;
|
||||
new.Mount = mount
|
||||
|
||||
local mountsClass = {__type = "quad_mounts"};
|
||||
mountsClass.__index = mountsClass;
|
||||
function mountsClass:unmount()
|
||||
-- mount(s) class
|
||||
local mountsClass = {__type = "quad_mounts"}
|
||||
mountsClass.__index = mountsClass
|
||||
function mountsClass:Unmount()
|
||||
for _,v in ipairs(self) do
|
||||
v:unmount();
|
||||
v:unmount()
|
||||
end
|
||||
end
|
||||
|
||||
-- handle __call
|
||||
setmetatable(new,{
|
||||
__call = function (self,to,...)
|
||||
if select("#",...) == 1 then
|
||||
return new.mount(to,...);
|
||||
return mount(to,...)
|
||||
end
|
||||
local mounts = {};
|
||||
local items = pack(...);
|
||||
local mounts = {}
|
||||
local items = pack(...)
|
||||
for _,item in ipairs(items) do
|
||||
insert(mounts,mount(to,item));
|
||||
insert(mounts,mount(to,item))
|
||||
end
|
||||
setmetatable(mounts,mountsClass);
|
||||
return mounts;
|
||||
end;
|
||||
});
|
||||
setmetatable(mounts,mountsClass)
|
||||
return mounts
|
||||
end
|
||||
})
|
||||
|
||||
return new;
|
||||
return new
|
||||
end
|
||||
|
||||
return module;
|
||||
return module
|
||||
|
|
|
|||
|
|
@ -2,30 +2,30 @@
|
|||
-- now, we can call modules with string path
|
||||
|
||||
if (not workspace) and (not game) and (not script) then
|
||||
return;
|
||||
return
|
||||
end
|
||||
|
||||
return function (query)
|
||||
local typeQuery = type(query);
|
||||
local typeQuery = type(query)
|
||||
|
||||
if typeQuery == "string" then
|
||||
local object = script.Parent;
|
||||
query = query:gsub("/",".");
|
||||
-- local index = 0;
|
||||
local object = script.Parent
|
||||
query = query:gsub("/",".")
|
||||
-- local index = 0
|
||||
query:gsub("[^%.]+",function (this)
|
||||
-- index = index + 1;
|
||||
-- index = index + 1
|
||||
-- if index == 1 and this == "src" then
|
||||
-- return;
|
||||
-- return
|
||||
-- end
|
||||
local lastObject = object;
|
||||
object = object[this];
|
||||
local lastObject = object
|
||||
object = object[this]
|
||||
if not object then
|
||||
object = lastObject.libs
|
||||
error(("[Quad] (require) object %s was not found from this worktree, require failed"):format(query));
|
||||
error(("[Quad] (require) object %s was not found from this worktree, require failed"):format(query))
|
||||
end
|
||||
end);
|
||||
return require(object);
|
||||
end)
|
||||
return require(object)
|
||||
elseif typeQuery == "userdata" then
|
||||
return require(query);
|
||||
return require(query)
|
||||
end
|
||||
end;
|
||||
end
|
||||
|
|
@ -14,7 +14,7 @@ end
|
|||
|
||||
local customSignal = {}
|
||||
customSignal.__index = customSignal
|
||||
function customSignal:emit(...)
|
||||
function customSignal:Fire(...)
|
||||
local waitting = self.waitting
|
||||
self.waitting = {}
|
||||
|
||||
|
|
@ -54,3 +54,41 @@ function this.new(...)
|
|||
customSignal.new(...)
|
||||
end
|
||||
this.customSignal = customSignal
|
||||
|
||||
-- roblox connections disconnecter
|
||||
local insert = table.insert
|
||||
local idSpace = {}
|
||||
local disconnecterClass = {__type = "quad_disconnecter"}
|
||||
function disconnecterClass:Add(connection)
|
||||
insert(self,connection)
|
||||
end
|
||||
function disconnecterClass:Disconnect()
|
||||
for i,v in pairs(self) do
|
||||
pcall(v.Disconnect,v)
|
||||
self[i] = nil
|
||||
end
|
||||
end
|
||||
function disconnecterClass:Destroy()
|
||||
local id = self.id
|
||||
if id then
|
||||
idSpace[id] = nil
|
||||
end
|
||||
for i,v in pairs(self) do
|
||||
pcall(v.Disconnect,v)
|
||||
self[i] = nil
|
||||
end
|
||||
end
|
||||
function disconnecterClass.New(id)
|
||||
if id then
|
||||
local old = idSpace[id];
|
||||
if old then
|
||||
return old;
|
||||
end
|
||||
end
|
||||
local this = setmetatable({id = id},disconnecterClass);
|
||||
if id then
|
||||
idSpace[id] = this;
|
||||
end
|
||||
return this;
|
||||
end
|
||||
disconnecterClass.__index = disconnecterClass
|
||||
|
|
|
|||
290
src/store.lua
290
src/store.lua
|
|
@ -1,97 +1,97 @@
|
|||
local module = {};
|
||||
local module = {}
|
||||
|
||||
--[[
|
||||
this feature allows get object without making some created callback and local var
|
||||
but, it can't allows mulit id and object
|
||||
this feature should be upgraded
|
||||
]]
|
||||
local wrap = coroutine.wrap;
|
||||
local insert = table.insert;
|
||||
local remove = table.remove;
|
||||
local gmatch = string.gmatch;
|
||||
local gsub = string.gsub;
|
||||
local match = string.match;
|
||||
local wrap = coroutine.wrap
|
||||
local insert = table.insert
|
||||
local remove = table.remove
|
||||
local gmatch = string.gmatch
|
||||
local gsub = string.gsub
|
||||
local match = string.match
|
||||
|
||||
local function catch(...)
|
||||
local passed,err = pcall(...);
|
||||
local passed,err = pcall(...)
|
||||
if not passed then
|
||||
warn ("[QUAD] Error occured while operating async task\n" .. tostring(err));
|
||||
warn ("[QUAD] Error occured while operating async task\n" .. tostring(err))
|
||||
end
|
||||
end
|
||||
|
||||
local week = {__mode = "v"};
|
||||
local week = {__mode = "v"}
|
||||
|
||||
---@param shared quad_export
|
||||
---@return quad_module_store
|
||||
function module.init(shared)
|
||||
local warn = shared.warn;
|
||||
local warn = shared.warn
|
||||
---@class quad_module_store
|
||||
local new = {__type = "quad_module_store"};
|
||||
local items = {};
|
||||
local new = {__type = "quad_module_store"}
|
||||
local items = {}
|
||||
new.items = items
|
||||
|
||||
-- id space (array of object)
|
||||
local objectListClass = {__type = "quad_objectlist"};
|
||||
local objectListClass = {__type = "quad_objectlist"}
|
||||
function objectListClass:each(func)
|
||||
local index = 1;
|
||||
local index = 1
|
||||
for i,v in pairs(self) do
|
||||
wrap(catch)(func,index,v);
|
||||
index = index + 1;
|
||||
wrap(catch)(func,index,v)
|
||||
index = index + 1
|
||||
end
|
||||
end
|
||||
function objectListClass:eachSync(func)
|
||||
local index = 1;
|
||||
local index = 1
|
||||
for _,v in pairs(self) do
|
||||
local ret = func(index,v);
|
||||
index = index + 1;
|
||||
local ret = func(index,v)
|
||||
index = index + 1
|
||||
if ret then
|
||||
break;
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
function objectListClass:remove(indexOrItem)
|
||||
local thisType = type(indexOrItem);
|
||||
local thisType = type(indexOrItem)
|
||||
if thisType == "number" then
|
||||
return remove(self,indexOrItem),indexOrItem;
|
||||
return remove(self,indexOrItem),indexOrItem
|
||||
else
|
||||
for i,v in pairs(self) do
|
||||
if v == indexOrItem then
|
||||
return remove(self,i),i;
|
||||
return remove(self,i),i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function objectListClass:isEmpty()
|
||||
if next(self) then return true; end
|
||||
return false;
|
||||
if next(self) then return true end
|
||||
return false
|
||||
end
|
||||
function objectListClass.__new()
|
||||
return setmetatable({},objectListClass);
|
||||
return setmetatable({},objectListClass)
|
||||
end
|
||||
function objectListClass:__newIndex(key,value) -- props setter
|
||||
self:each(function (this)
|
||||
this[key] = value;
|
||||
end);
|
||||
this[key] = value
|
||||
end)
|
||||
end
|
||||
objectListClass.__mode = "kv"; -- week link for gc
|
||||
objectListClass.__index = objectListClass;
|
||||
objectListClass.__mode = "kv" -- week link for gc
|
||||
objectListClass.__index = objectListClass
|
||||
|
||||
-- get object array with id (objSpace)
|
||||
function new.getObjects(ids)
|
||||
if match(ids,",") then
|
||||
local list = items[ids];
|
||||
if list then return list; end
|
||||
list = objectListClass.__new();
|
||||
items[ids] = list;
|
||||
return list;
|
||||
local list = items[ids]
|
||||
if list then return list end
|
||||
list = objectListClass.__new()
|
||||
items[ids] = list
|
||||
return list
|
||||
else
|
||||
local list = objectListClass.__new();
|
||||
local list = objectListClass.__new()
|
||||
for id in gmatch(ids,"[^,]+") do -- split by ,
|
||||
id = gsub(gsub(id,"^ +","")," +$","");
|
||||
local idItem = items[id];
|
||||
id = gsub(gsub(id,"^ +","")," +$","")
|
||||
local idItem = items[id]
|
||||
if idItem then
|
||||
for _,item in pairs(idItem) do
|
||||
insert(list,item);
|
||||
insert(list,item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -100,227 +100,227 @@ function module.init(shared)
|
|||
end
|
||||
-- get first object with id (not array)
|
||||
function new.getObject(id)
|
||||
local item = items[id];
|
||||
return item and item[next(item)];
|
||||
local item = items[id]
|
||||
return item and item[next(item)]
|
||||
end
|
||||
--TODO: if item is exist already, ignore this call
|
||||
-- adding object with id
|
||||
function new.addObject(ids,object)
|
||||
for id in gmatch(ids,"[^,]+") do -- split by ,
|
||||
-- remove trailing, heading spaces
|
||||
id = gsub(gsub(id,"^ +","")," +$","");
|
||||
local array = items[id];
|
||||
id = gsub(gsub(id,"^ +","")," +$","")
|
||||
local array = items[id]
|
||||
if not array then
|
||||
array = objectListClass.__new();
|
||||
items[id] = array;
|
||||
array = objectListClass.__new()
|
||||
items[id] = array
|
||||
end
|
||||
insert(array, object);
|
||||
insert(array, object)
|
||||
end
|
||||
end
|
||||
|
||||
local registerClass = {
|
||||
__type = "quad_register";
|
||||
register = function (s,efunc)
|
||||
local self = s.store;
|
||||
local events = self.__evt;
|
||||
local self = s.store
|
||||
local events = self.__evt
|
||||
for key in s.key:gmatch("[^,]+") do
|
||||
key = key:gsub("^ +",""):gsub(" +$","");
|
||||
local event = events[key];
|
||||
key = key:gsub("^ +",""):gsub(" +$","")
|
||||
local event = events[key]
|
||||
if not event then
|
||||
event = setmetatable({},week);
|
||||
events[key] = event;
|
||||
event = setmetatable({},week)
|
||||
events[key] = event
|
||||
end
|
||||
insert(event,efunc);
|
||||
insert(event,efunc)
|
||||
end
|
||||
end;
|
||||
with = function (s,wfunc)
|
||||
-- s.wfunc = wfunc;
|
||||
-- return s;
|
||||
return setmetatable({wfunc = wfunc},{__index = s});
|
||||
-- s.wfunc = wfunc
|
||||
-- return s
|
||||
return setmetatable({wfunc = wfunc},{__index = s})
|
||||
end;
|
||||
default = function (s,dvalue)
|
||||
-- s.dvalue = dvalue;
|
||||
-- return s;
|
||||
return setmetatable({dvalue = dvalue},{__index = s});
|
||||
-- s.dvalue = dvalue
|
||||
-- return s
|
||||
return setmetatable({dvalue = dvalue},{__index = s})
|
||||
end;
|
||||
tween = function (s,tvalue)
|
||||
-- s.tvalue = tvalue;
|
||||
-- return s;
|
||||
return setmetatable({tvalue = tvalue},{__index = s});
|
||||
-- s.tvalue = tvalue
|
||||
-- return s
|
||||
return setmetatable({tvalue = tvalue},{__index = s})
|
||||
end;
|
||||
---@deprecated
|
||||
from = function (s,fvalue)
|
||||
warn "[QUAD] register:from() is deprecated. Use register:add(t:table|function) instead";
|
||||
-- s.fvalue = fvalue;
|
||||
-- return s;
|
||||
return setmetatable({fvalue = fvalue},{__index = s});
|
||||
warn "[QUAD] register:from() is deprecated. Use register:add(t:table|function) instead"
|
||||
-- s.fvalue = fvalue
|
||||
-- return s
|
||||
return setmetatable({fvalue = fvalue},{__index = s})
|
||||
end;
|
||||
add = function (s,avalue)
|
||||
-- s.avalue = avalue;
|
||||
-- return s;
|
||||
return setmetatable({avalue = avalue},{__index = s});
|
||||
-- s.avalue = avalue
|
||||
-- return s
|
||||
return setmetatable({avalue = avalue},{__index = s})
|
||||
end;
|
||||
-- return init data
|
||||
calcWithDefault = function (s,withItem)
|
||||
local with = s.wfunc;
|
||||
local tstore = s.store;
|
||||
local rawKey = s.key;
|
||||
local tween = s.tvalue or tstore.__tweens[rawKey];
|
||||
local from = s.fvalue;
|
||||
local add = s.avalue;
|
||||
local set = tstore[rawKey];
|
||||
local with = s.wfunc
|
||||
local tstore = s.store
|
||||
local rawKey = s.key
|
||||
local tween = s.tvalue or tstore.__tweens[rawKey]
|
||||
local from = s.fvalue
|
||||
local add = s.avalue
|
||||
local set = tstore[rawKey]
|
||||
if set ~= nil or (rawKey:match(",") and with) then
|
||||
if add then
|
||||
set = set + add;
|
||||
set = set + add
|
||||
end
|
||||
if from then
|
||||
set = from[set];
|
||||
set = from[set]
|
||||
end
|
||||
if with then
|
||||
set = with(tstore,set,rawKey,withItem);
|
||||
set = with(tstore,set,rawKey,withItem)
|
||||
end
|
||||
return set,tween;
|
||||
return set,tween
|
||||
else
|
||||
local dset = s.dvalue;
|
||||
local dset = s.dvalue
|
||||
if dset ~= nil then
|
||||
return dset,tween;
|
||||
return dset,tween
|
||||
end
|
||||
warn "[Quad] no default value found.";
|
||||
warn "[Quad] no default value found."
|
||||
end
|
||||
end;
|
||||
calcWithNewValue = function(s,withItem,newValue,key)
|
||||
local with = s.wfunc;
|
||||
local tstore = s.store;
|
||||
local rawKey = s.key;
|
||||
local tween = s.tvalue or tstore.__tweens[rawKey];
|
||||
local from = s.fvalue;
|
||||
local add = s.avalue;
|
||||
local with = s.wfunc
|
||||
local tstore = s.store
|
||||
local rawKey = s.key
|
||||
local tween = s.tvalue or tstore.__tweens[rawKey]
|
||||
local from = s.fvalue
|
||||
local add = s.avalue
|
||||
if add then
|
||||
newValue = newValue + add;
|
||||
newValue = newValue + add
|
||||
end
|
||||
if from then
|
||||
newValue = from[newValue];
|
||||
newValue = from[newValue]
|
||||
end
|
||||
if with then
|
||||
newValue = with(tstore,newValue,key,withItem);
|
||||
newValue = with(tstore,newValue,key,withItem)
|
||||
end
|
||||
return newValue,tween;
|
||||
return newValue,tween
|
||||
end
|
||||
};
|
||||
registerClass.__index = registerClass;
|
||||
}
|
||||
registerClass.__index = registerClass
|
||||
|
||||
-- bindable store object
|
||||
local store = {__type = "quad_store"};
|
||||
local storeIdSpace = {};
|
||||
local store = {__type = "quad_store"}
|
||||
local storeIdSpace = {}
|
||||
function store:__index(key)
|
||||
local this = self.__self[key];
|
||||
local this = self.__self[key]
|
||||
if this ~= nil then
|
||||
return this;
|
||||
return this
|
||||
end
|
||||
return store[key];
|
||||
return store[key]
|
||||
end
|
||||
function store:__newindex(key,value)
|
||||
-- if got register, just copy data to self and connect
|
||||
if type(value) == "table" and value.__type == "quad_register" then
|
||||
-- warn "[Quad] adding register value on store is only allowed when init store. set value request was ignored";
|
||||
-- warn "[Quad] adding register value on store is only allowed when init store. set value request was ignored"
|
||||
|
||||
local selfValues = self.__self;
|
||||
local selfTweens = self.__tweens;
|
||||
local selfValues = self.__self
|
||||
local selfTweens = self.__tweens
|
||||
|
||||
-- fetch data from origin
|
||||
do
|
||||
local tstore = value.store;
|
||||
local tstore = value.store
|
||||
for tkey in value.key:gmatch("^[,]") do
|
||||
if not selfValues[tkey] then
|
||||
selfValues[tkey] = tstore[tkey];
|
||||
selfValues[tkey] = tstore[tkey]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- calc value
|
||||
do
|
||||
local setValue,tween = value:calcWithDefault(self);
|
||||
selfValues[key] = setValue;
|
||||
selfTweens[key] = tween;
|
||||
local setValue,tween = value:calcWithDefault(self)
|
||||
selfValues[key] = setValue
|
||||
selfTweens[key] = tween
|
||||
end
|
||||
|
||||
-- make event connection
|
||||
value:register(function (_,newValue,eventKey)
|
||||
-- !HOLD IT SELF TO PREVENT THIS REGISTER BEGIN REMOVED FROM MEMORY
|
||||
local setValue = value:calcWithNewValue(self,newValue,eventKey);
|
||||
self[key] = setValue;
|
||||
end);
|
||||
local setValue = value:calcWithNewValue(self,newValue,eventKey)
|
||||
self[key] = setValue
|
||||
end)
|
||||
|
||||
return;
|
||||
return
|
||||
end
|
||||
self.__self[key] = value;
|
||||
local event = self.__evt[key];
|
||||
self.__self[key] = value
|
||||
local event = self.__evt[key]
|
||||
if event then
|
||||
for _,v in pairs(event) do -- NO ipairs here
|
||||
wrap(catch)(v,store,value,key);
|
||||
wrap(catch)(v,store,value,key)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- init bindings
|
||||
function new.__initStoreRegisterBinding(self,withItem)
|
||||
local selfTweens = self.__tweens;
|
||||
local selfValues = self.__self;
|
||||
local selfKeep = self.__keep;
|
||||
local selfTweens = self.__tweens
|
||||
local selfValues = self.__self
|
||||
local selfKeep = self.__keep
|
||||
for key,item in pairs(selfValues) do
|
||||
if type(item) == "table" and item.__type == "quad_register" then
|
||||
-- fetch data from origin
|
||||
do
|
||||
local tstore = item.store;
|
||||
local tstore = item.store
|
||||
for tkey in item.key:gmatch("^[,]") do
|
||||
if not selfValues[tkey] then
|
||||
selfValues[tkey] = tstore[tkey];
|
||||
selfValues[tkey] = tstore[tkey]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- calc value
|
||||
do
|
||||
local setValue,tween = item:calcWithDefault(withItem);
|
||||
selfValues[key] = setValue;
|
||||
selfTweens[key] = tween;
|
||||
local setValue,tween = item:calcWithDefault(withItem)
|
||||
selfValues[key] = setValue
|
||||
selfTweens[key] = tween
|
||||
end
|
||||
|
||||
-- make event connection
|
||||
local function regFn(_,newValue,eventKey)
|
||||
-- !HOLD IT SELF TO PREVENT THIS REGISTER BEGIN REMOVED FROM MEMORY
|
||||
local setValue = item:calcWithNewValue(withItem,newValue,eventKey);
|
||||
self[key] = setValue;
|
||||
local setValue = item:calcWithNewValue(withItem,newValue,eventKey)
|
||||
self[key] = setValue
|
||||
end
|
||||
item:register(regFn);
|
||||
insert(selfKeep,item);
|
||||
insert(selfKeep,regFn);
|
||||
item:register(regFn)
|
||||
insert(selfKeep,item)
|
||||
insert(selfKeep,regFn)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- create register
|
||||
function store:__call(key,func)
|
||||
local last = self.__self[key];
|
||||
local last = self.__self[key]
|
||||
if last and type(last) == "table" and getmetatable(last) == registerClass then
|
||||
return last;
|
||||
return last
|
||||
end
|
||||
local register = self.__reg[key];
|
||||
local register = self.__reg[key]
|
||||
if not register then
|
||||
register = setmetatable({
|
||||
key = key;
|
||||
store = self;
|
||||
},registerClass);
|
||||
self.__reg[key] = register;
|
||||
},registerClass)
|
||||
self.__reg[key] = register
|
||||
end
|
||||
|
||||
if func then
|
||||
register.register(func);
|
||||
register.register(func)
|
||||
end
|
||||
return register;
|
||||
return register
|
||||
end
|
||||
function store:default(key,value)
|
||||
if self[key] == nil then
|
||||
self[key] = value;
|
||||
return;
|
||||
self[key] = value
|
||||
return
|
||||
end
|
||||
end
|
||||
function new.new(self,id)
|
||||
|
|
@ -332,18 +332,18 @@ function module.init(shared)
|
|||
__tweens = {}, -- tweens (if inited with register, save tween and use as default tween data)
|
||||
__keep = {} -- store data which should not be destoryed
|
||||
},store
|
||||
);
|
||||
)
|
||||
if id then -- save in id space
|
||||
storeIdSpace[id] = this;
|
||||
storeIdSpace[id] = this
|
||||
end
|
||||
return this;
|
||||
return this
|
||||
end
|
||||
local storeNew = new.new;
|
||||
local storeNew = new.new
|
||||
function new.getStore(id)
|
||||
return storeIdSpace[id] or storeNew({},id);
|
||||
return storeIdSpace[id] or storeNew({},id)
|
||||
end
|
||||
|
||||
return new;
|
||||
return new
|
||||
end
|
||||
|
||||
return module;
|
||||
return module
|
||||
|
|
|
|||
Loading…
Reference in a new issue