From 3515baaa3a3a561c5f35ae6ff58a03ce9b9272a0 Mon Sep 17 00:00:00 2001 From: Qwreey Date: Mon, 2 Jan 2023 06:22:24 +0900 Subject: [PATCH] feat: new Style system, add optimization by preventing same property setted multiply --- src/class.lua | 191 +++++++++++++++++++++++++++++--------------------- src/event.lua | 2 + src/init.lua | 4 +- src/mount.lua | 2 + src/store.lua | 3 + src/style.lua | 73 +++++++++++++++++++ 6 files changed, 193 insertions(+), 82 deletions(-) create mode 100644 src/style.lua diff --git a/src/class.lua b/src/class.lua index 5bd4c4b..1bbe5eb 100644 --- a/src/class.lua +++ b/src/class.lua @@ -1,6 +1,9 @@ local module = {}; local pack = table.pack; +local match = string.match; +---@param shared quad_export +---@return quad_module_class function module.init(shared) ---@class quad_module_class local new = {__type = "quad_module_class"}; @@ -13,6 +16,9 @@ function module.init(shared) 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 @@ -84,9 +90,102 @@ function module.init(shared) end end + local function processQuadProperty(processedProperty,iprop,holder,item,className,index,value) + if processedProperty[index] then return; end + + local valueType = typeof(value); + local indexType = typeof(index); + + -- child + if indexType == "string" and valueType == "table" and value.t == "reg" then -- register (bind to store event) + processedProperty[index] = true; -- ignore next + -- store binding + local with = value.wfunc; + local tstore = value.store; + local rawKey = value.key; + local tween = value.tvalue; + local from = value.fvalue; + local add = value.avalue; + local set = tstore[rawKey]; + if set ~= nil or (rawKey:match(",") and with) then + if add then + set = set + add; + end + if from then + set = from[set]; + end + if with then + set = with(tstore,set,value.key,item); + end + setProperty(item,index,set,className); + else + local dset = value.dvalue; + if dset then + setProperty(item,index,dset,className); + end + end + + -- adding event function + local function regFn(_,newValue,key) + if add then + newValue = newValue + add; + end + if from then + newValue = from[newValue]; + end + if with then + newValue = with(tstore,newValue,key,item); + end + 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"; + end + local ended, onStepped; + if tween.Ended then + ended = function (...) + tween.Ended(item,...); + end + end + if tween.OnStepped then + onStepped = function (...) + tween.OnStepped(item,...); + end + end + advancedTween.RunTween(item,tween,{[index] = newValue},ended,onStepped,setProperty,getProperty); + else + setProperty(item,index,newValue,className); + end + end + 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); + 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 + -- prop set + setProperty(item,index,value,className); + elseif indexType == "number" and valueType == "table" and value.__type == "quad_style" then -- style + -- style parsing + for _,thisStyle in ipairs(parseStyles(value)) do + for styleIndex,styleValue in pairs(thisStyle) do + if type(styleValue) ~= "table" or styleValue.__type ~= "quad_style" then + processQuadProperty(processedProperty,iprop,holder,item,className,styleIndex,styleValue); + end + end + end + elseif indexType == "number" and valueType ~= "boolean" then -- object + -- child object + 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 - -- make thing + -- make object from 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 @@ -131,88 +230,13 @@ function module.init(shared) -- set property and adding child and binding functions local holder = getHolder(item); -- to __holder or holder or it self (for tabled) -- for iprop,prop in ipairs({...}) do - local props = pack(...); - for iprop = props.n,1,-1 do - local prop = props[iprop]; + 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 - local valueType = typeof(value); - local indexType = typeof(index); - - -- child - if indexType == "string" and valueType == "table" and value.t == "reg" then -- register (bind to store event) - -- store binding - local with = value.wfunc; - local tstore = value.store; - local rawKey = value.key; - local tween = value.tvalue; - local from = value.fvalue; - local add = value.avalue; - local set = tstore[rawKey]; - if set ~= nil or (rawKey:match(",") and with) then - if add then - set = set + add; - end - if from then - set = from[set]; - end - if with then - set = with(tstore,set,value.key,item); - end - setProperty(item,index,set,ClassName); - else - local dset = value.dvalue; - if dset then - setProperty(item,index,dset,ClassName); - end - end - - -- adding event function - local function regFn(_,newValue,key) - if add then - newValue = newValue + add; - end - if from then - newValue = from[newValue]; - end - if with then - newValue = with(tstore,newValue,key,item); - end - 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"; - end - local ended, onStepped; - if tween.Ended then - ended = function (...) - tween.Ended(item,...); - end - end - if tween.OnStepped then - onStepped = function (...) - tween.OnStepped(item,...); - end - end - advancedTween.RunTween(item,tween,{[index] = newValue},ended,onStepped,setProperty,getProperty); - else - setProperty(item,index,newValue,ClassName); - end - end - 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); - elseif (valueType == "function" or valueType == "table") and indexType == "string" and bind(item,index,value,valueType) then -- connect event - -- event binding - elseif indexType == "string" then - -- prop set - setProperty(item,index,value,ClassName); - elseif indexType == "number" and valueType ~= "boolean" then -- object - -- child object - mountfunc(item,((iprop == 1) and value or value:Clone()),holder); - end + processQuadProperty(processedProperty,iprop,holder,item,ClassName,index,value); end end end @@ -235,6 +259,11 @@ function module.init(shared) return function (nprop,...) nprop = nprop or {}; nprop.Name = lastName; + for styleName,styleObj in pairs(styleList) do + if match(prop,styleName) then + insert(nprop,styleObj); + end + end local item = make(ClassName,nprop,...,this); addObject(lastName,item); return item; diff --git a/src/event.lua b/src/event.lua index 3d92b4c..fc51abf 100644 --- a/src/event.lua +++ b/src/event.lua @@ -2,6 +2,8 @@ local module = {}; local unpack = table.unpack; local wrap = coroutine.wrap; +---@param shared quad_export +---@return quad_module_event function module.init(shared) ---@class quad_module_event local new = {__type = "quad_module_event"}; diff --git a/src/init.lua b/src/init.lua index 778fdc1..986edd1 100644 --- a/src/init.lua +++ b/src/init.lua @@ -2,6 +2,7 @@ local module = {}; local require = require(script.require); +local style = require "style"; local event = require "event"; local store = require "store"; local class = require "class"; @@ -28,6 +29,7 @@ function module.init(id) this.require = require; this.round = type(round) == "table" and round; ---@type quad_module_round this.tween = type(advancedTween) == "table" and advancedTween; ---@type quad_module_tween + this.style = style.init(this); ---@type quad_module_style this.event = event.init(this); ---@type quad_module_event this.store = store.init(this); ---@type quad_module_store this.mount = mount.init(this); ---@type quad_module_mount @@ -36,7 +38,7 @@ function module.init(id) if id then idSpace[id] = this; end - return this,this.round,this.class,this.mount,this.store,this.event,this.tween; + return this,this.round,this.class,this.mount,this.store,this.event,this.tween,this.style; end function module.uninit(id) diff --git a/src/mount.lua b/src/mount.lua index 6c6c16f..03041e2 100644 --- a/src/mount.lua +++ b/src/mount.lua @@ -2,6 +2,8 @@ local module = {}; local insert = table.insert; local pack = table.pack; +---@param shared quad_export +---@return quad_module_mount function module.init(shared) ---@class quad_module_mount local new = {__type = "quad_module_mount"}; diff --git a/src/store.lua b/src/store.lua index 1446050..056d92e 100644 --- a/src/store.lua +++ b/src/store.lua @@ -17,6 +17,9 @@ local function catch(...) end local week = {__mode = "v"}; + +---@param shared quad_export +---@return quad_module_store function module.init(shared) ---@class quad_module_store local new = {__type = "quad_module_store"}; diff --git a/src/style.lua b/src/style.lua new file mode 100644 index 0000000..3c1b6a4 --- /dev/null +++ b/src/style.lua @@ -0,0 +1,73 @@ +local module = {}; +local insert = table.insert; + +---@param shared quad_export +---@return quad_module_style +function module.init(shared) + ---@class quad_module_style + local new = {__type = "quad_module_style"}; + + local styles = {}; + new.styles = styles; + + ---@class quad_style + local styleClass = {__type = "quad_style"}; + styleClass.__index = styleClass; + + function new.new(props) + return setmetatable(props,styleClass); + end + local newStyle = new.new; + + setmetatable(new,{ + ---@return quad_style + __call = function (_,styleTable) + if type(styleTable) == "string" then + return function (nstyleTable) + local this = newStyle(nstyleTable); + styles[styleTable] = this; + return this; + end + end + return newStyle(styleTable); + end + }); + + local function recursionStyleParse(style,parseTable) + for _,value in ipairs(parseTable) do + if value == style then + warn("[Quad] infinity recursion detected on parsing style. ignored recursion"); + return; + end + end + insert(parseTable,style); + for key,value in pairs(style) do + if type(key) == "number" and type(value) == "table" and value.__type == "quad_style" then + recursionStyleParse(value,parseTable); + end + end + end + + local parsed = {}; + function new.parseStyles(style) + do -- check cache + local cached = parsed[style]; + if cached then return cached; end + end + + -- type check + if type(style) ~= "table" or style.__type ~= "quad_style" then + error(("Unknown type type '%s:%s' got"):format(tostring(style),tostring(type(style)))); + end + + local this = {} + recursionStyleParse(style,this); + + parsed[style] = this; + return this; + end + + return new; +end + +return module;