diff --git a/src/class.lua b/src/class.lua index 9ea89e0..87c8a6c 100644 --- a/src/class.lua +++ b/src/class.lua @@ -11,20 +11,20 @@ function module.init(shared) ---@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 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 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); @@ -32,11 +32,7 @@ function module.init(shared) return item; end - -- TODO: refactor getProperty - -- local propertyGetterRaw = {} - -- local propertySetterRaw = {} - - local function getProperty(item,index,ClassName) + 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"); @@ -44,7 +40,7 @@ function module.init(shared) 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"); end - return round.getRound(item); + 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; @@ -60,9 +56,9 @@ function module.init(shared) end return item[index]; end - new.getProperty = getProperty + new.GetProperty = GetProperty - local function setProperty(item,index,value,ClassName) + 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"); @@ -70,8 +66,8 @@ function module.init(shared) 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"); end - round.setRound(item,value); - elseif index == "UiRoundSize" or index == "uiRoundSize" or index == "UIRoundSize" then + 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 @@ -94,37 +90,39 @@ function module.init(shared) item[index] = value; -- set property end end - new.setProperty = setProperty + new.SetProperty = SetProperty - local function rawGetProperty(item,index) + local function RawGetProperty(item,index) return item[index]; end - local function pcallGetProperty(item,index) - local ok,err = pcall(rawGetProperty,item,index); + local function PcallGetProperty(item,index) + 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) + local function ProcessQuadProperty(processedProperty,iprop,holder,item,className,index,value) if processedProperty[index] then return; end 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) - -- child - local quadType = valueType == "table" and pcallGetProperty(value,"__type") - if indexType == "string" and valueType == "table" and quadType == "quad_register" then -- register (bind to store event) processedProperty[index] = true; -- ignore next + -- store reading do 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?"; end - setProperty(item,index,setValue,className); + SetProperty(item,index,setValue,className); end - -- adding event function (bindding) + -- adding handle function (bindding) local function regFn(_,newValue,key) local setValue,tween = value:calcWithNewValue(item,newValue,key); if tween then @@ -142,9 +140,9 @@ function module.init(shared) 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); @@ -158,7 +156,7 @@ function module.init(shared) elseif indexType == "string" then 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 @@ -166,7 +164,7 @@ function module.init(shared) 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 @@ -231,11 +229,11 @@ function module.init(shared) 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 diff --git a/src/init.lua b/src/init.lua index 95dfe13..bb43b55 100644 --- a/src/init.lua +++ b/src/init.lua @@ -1,12 +1,21 @@ ---@class quad local module = {}; +local IS_TEST = true +local VER = "1.14" .. (IS_TEST and "B" or "") +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"; + +-- submodule local _,advancedTween = pcall(require,"libs.AdvancedTween"); local _,round = pcall(require,"libs.round"); @@ -15,41 +24,44 @@ local idSpace = {}; ---@return quad_export this ---@return quad_module_round round ---@return quad_module_tween tween -function module.init(id) +function module.Init(id) + -- return old items if id then - local this = idSpace[id]; + local this = idSpace[id] if this then - 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 end end ---@class quad_export - local this = {__type = "quad_module_init",items = {}}; + local this = {__type = "quad_module_init"} - this.require = require; + this.require = require this.warn = function(err) - warn(tostring(err)); - print(debug.traceback()); - end; - 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 - this.class = class.init(this); ---@type quad_module_class - - if id then - idSpace[id] = this; + warn(tostring(err)) + print(debug.traceback()) end - return this,this.round,this.class,this.mount,this.store,this.event,this.tween,this.style; + 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 + this.Class = class.init(this) ---@type quad_module_class + + -- save + if id then + idSpace[id] = this + end + + return this end local function cleanup(space) - -- space.items + -- TODO : Destroy objects end -function module.uninit(id) +function module.Uninit(id) pcall(cleanup,idSpace[id]) idSpace[id] = nil; end diff --git a/src/libs/AdvancedTween/EasingFunctions.lua b/src/libs/AdvancedTween/EasingFunctions.lua index e616ef8..6f13380 100644 --- a/src/libs/AdvancedTween/EasingFunctions.lua +++ b/src/libs/AdvancedTween/EasingFunctions.lua @@ -110,6 +110,7 @@ EasingFunctions["Sin"] = Sin local Circle = {} do local sqrt = math.sqrt + Circle.Reverse = false Circle.Run = function(Index) if Index == 1 then return 1 end if Index == 0 then return 0 end diff --git a/src/libs/AdvancedTween/init.lua b/src/libs/AdvancedTween/init.lua index 7d4fba9..24810c3 100644 --- a/src/libs/AdvancedTween/init.lua +++ b/src/libs/AdvancedTween/init.lua @@ -50,6 +50,7 @@ end module.EasingDirections = { Out = "Out"; -- 반전된 방향 In = "In" ; -- 기본방향 + InOut = "InOut"; -- 두 방향 모두 가감속 } ---@deprecated @@ -76,7 +77,7 @@ local DefaultLerpableItems = { -- 예전 값,목표 값,알파를 주고 각각 해당하는 속성에 입력해줌 -- 기본적으로 모든 속성값 적용은 여기에서 이루워짐 -function LerpProperties(Item,Old,New,Alpha,Setter) +local function LerpProperties(Item,Old,New,Alpha,Setter) for Property,OldValue in pairs(Old) do local NewValue = New[Property] local Type = type(OldValue) @@ -130,6 +131,57 @@ function LerpProperties(Item,Old,New,Alpha,Setter) end module.LerpProperties = LerpProperties +-- Easing 값을 계산함 +local function CalcEasing(Easing,Direction,Reverse,Index) + if Index >= 1 then + return 1 + elseif Direction == "Out" then + if Reverse then + return 1 - Easing(1 - Index) + else + return Easing(Index) + end + elseif Direction == "In" then + if Reverse then + return Easing(Index) + else + return 1 - Easing(1 - Index) + end + elseif Direction == "InOut" then + if Index<0.5 then + -- In + if Reverse then + return Easing(Index*2)/2 + else + return 0.5 - Easing(1 - Index*2)/2 + end + else + -- Out + if Reverse then + return 1 - Easing(2-Index*2)/2 + else + return Easing(Index*2-1)/2+0.5 + end + end + end +end +function module.CalcEasing(Data_Easing,Direction,X) + local Reverse + local Easing do + Data_Easing = Easing or EasingFunctions.Exp2 + local Data_EasingType = type(Data_Easing) + if Data_EasingType == "string" then + Data_Easing = EasingFunctions[Data_Easing] + Data_EasingType = "table" + end + Easing = (Data_EasingType == "function" and Data_Easing) or (Data_EasingType == "table" and Data_Easing.Run) + if Data_EasingType == "table" and Data_Easing.Reverse then + Reverse = true + end + end + return CalcEasing(Easing,Direction,Reverse,X) +end + ------------------------------------ -- 모듈 함수 지정 ------------------------------------ @@ -188,6 +240,7 @@ function module.RunTween(Item,Data,Properties,Ended,OnStepped,Setter,Getter,_) -- 이징 효과 가져오기 local Direction = Data.Direction or "Out" + local Reverse local Easing do local Data_Easing = Data.Easing or EasingFunctions.Exp2 local Data_EasingType = type(Data_Easing) @@ -197,7 +250,7 @@ function module.RunTween(Item,Data,Properties,Ended,OnStepped,Setter,Getter,_) end Easing = (Data_EasingType == "function" and Data_Easing) or (Data_EasingType == "table" and Data_Easing.Run) if Data_EasingType == "table" and Data_Easing.Reverse then - Direction = Direction == "Out" and "In" or "Out" + Reverse = true end end @@ -238,10 +291,12 @@ function module.RunTween(Item,Data,Properties,Ended,OnStepped,Setter,Getter,_) local Now = clock() local Index = 1 - (EndTime - Now) / Time - local Alpha = Direction == "Out" and Easing(Index) or (1 - Easing(1 - Index)) + local Alpha if Now >= EndTime then Index = 1 Alpha = 1 + else + Alpha = CalcEasing(Easing,Direction,Reverse,Index) end -- 속성 Lerp 수행 @@ -338,9 +393,18 @@ function module.StopPropertyTween(Item,PropertyName,_) end -- 해당 개체가 트윈중인지 반환 -function module.IsTweening(Item,_) +function module.IsTweening(ItemOrStep,_) if Item == module then warn "AdvancedTween:IsTweening() is deprecated, Use AdvancedTween.IsTweening() instead"; Item = _ end + if type(ItemOrStep) == "function" then + local pos = find(BindedFunctions,ItemOrStep) + if pos then + return true + else + return false + end + end + if module.PlayIndex[Item] == nil then return false end diff --git a/src/libs/round.lua b/src/libs/round.lua index e1b909d..8b92654 100644 --- a/src/libs/round.lua +++ b/src/libs/round.lua @@ -11,24 +11,24 @@ local roundScaleType = Enum.ScaleType.Slice; local roundSliceCenter = Rect.new(Vector2.new(516,516),Vector2.new(516,516)); local roundSliceScale = 0.0019166666666667; -function round.setRound(ImageFrame,RoundSize) +function round.SetRound(ImageFrame,RoundSize) ImageFrame.Image = roundImage; ImageFrame.ScaleType = roundScaleType; ImageFrame.SliceCenter = roundSliceCenter; ImageFrame.SliceScale = roundSliceScale * RoundSize; return ImageFrame; end -function round.setOutline(ImageFrame,RoundSize) +function round.SetOutline(ImageFrame,RoundSize) ImageFrame.Image = outlineImage ImageFrame.ScaleType = outlineScaleType; ImageFrame.SliceCenter = outlineSliceCenter; ImageFrame.SliceScale = outlineSliceScale * RoundSize; return ImageFrame; end -function round.getRound(ImageFrame) +function round.GetRound(ImageFrame) return ImageFrame.SliceScale / roundSliceScale; end -function round.getOutline(ImageFrame) +function round.GetOutline(ImageFrame) return ImageFrame.SliceScale / outlineSliceScale; end diff --git a/src/signal.lua b/src/signal.lua index 7c79d07..0a74985 100644 --- a/src/signal.lua +++ b/src/signal.lua @@ -1,16 +1,53 @@ local module = {} -local signal + +local running = coroutine.running +local resume = coroutine.resume +local yield = coroutine.yield +local insert = table.insert + +local customConnection = {} +customConnection.__index = customConnection +function customConnection.new(signal,func) + func +end local customSignal = {} customSignal.__index = customSignal -function customSignal:emit(name,...) +function customSignal:emit(...) + local waitting = self.waitting + self.waitting = {} + for _,v in pairs(waitting) do + task.spawn(resume,v,...) + end + + for _,v in pairs(self.connection) do + task.spawn(v,...) + end end -function customSignal:Connect() +function customSignal:Wait() + insert(self.waitting,running()) + return yield() +end +function customSignal:Connect(func) + local connection = self.connection + for _,v in pairs(connection) do + if v == func then + error("Function %s Connected already") + end + end + insert(self.connection,func) + return customConnection.new(self,func) +end +local function onceWaitter(targetFunction) + +end +function customSignal:Once() + end function customSignal.new() - local self = {} + local self = {waitting={},onceConnection={},connection={}} setmetatable(self,customSignal) end function this.new(...) diff --git a/src/store.lua b/src/store.lua index 364225d..02ae84c 100644 --- a/src/store.lua +++ b/src/store.lua @@ -27,7 +27,8 @@ function module.init(shared) local warn = shared.warn; ---@class quad_module_store local new = {__type = "quad_module_store"}; - local items = shared.items; + local items = {}; + new.items = items -- id space (array of object) local objectListClass = {__type = "quad_objectlist"}; diff --git a/src/types.lua b/src/types.lua index 65f8bd7..bcb00cf 100644 --- a/src/types.lua +++ b/src/types.lua @@ -2,30 +2,35 @@ -- module_class ------------------- export type extend = { - getter: {[string]: ()->any|any?}; - setter: {[string]: ()->()?}; + Getter: {[string]: ()->any|any?}; + Setter: {[string]: ()->()?}; + New: (prop:DOM_constructor)->DOM; + Init: (self:DOM)->(); } export type DOM = { - [string]: any; + [string]: any; + Destroy: (self:DOM)->(); + GetPropertyChangedSignal: (self:DOM,propertyName:string)->(RBXScriptSignal|signal); + Update: (self:DOM)->(); } export type DOM_constructor = { - [event]: - (DOM,...any)->() - &{self: any,func: ()->()}; + [event]: + (DOM,...any)->() + &{self: any,func: (...any)->(...any)}; } & { [number]: DOM|style; } & { [string]: any|register; } export type DOM_creator = (DOM_constructor,...DOM_constructor)->DOM export type imported = - {[string]:any} - &(ids:ObjectIdList)->DOM_creator - &DOM_creator + {[string]:any} + &(ids:ObjectIdList)->DOM_creator + &DOM_creator export type import = (ClassName:string|ModuleScript|extend|()->()|{any},defaultProperties:DOM_constructor?)->imported export type module_class = { - extend: ()->extend; - import: import; - getProperty: (item:extend|any,index:string,ClassName:string?)->any; - setProperty: (item:extend|any,index:string,value:any,ClassName:string?)->(); - make: (ClassName:string|(...any)->any|extend,...{any})->any; + Extend: ()->extend; + Import: import; + GetProperty: (item:extend|any,index:string,ClassName:string?)->any; + SetProperty: (item:extend|any,index:string,value:any,ClassName:string?)->(); + Make: (ClassName:string|(...any)->any|extend,...{any})->any; } & import ------------------- @@ -33,46 +38,46 @@ export type module_class = { ------------------- export type event = string export type disconnecter = { - add: (self:disconnecter,connection:RBXScriptConnection)->(); - destroy: (self:disconnecter)->(); - disconnect: (self:disconnecter)->(); + Add: (self:disconnecter,connection:RBXScriptConnection)->(); + Destroy: (self:disconnecter)->(); + Disconnect: (self:disconnecter)->(); } export type module_event = { - prop: (propName:string)->event; - createdAsync: event; - created: event; - bind: (this:DOM|any,key:event|string,func:(...any)->(),typefunc:string?)->(); - disconnecter: (id:string?)->disconnecter; + Prop: (propName:string)->event; + CreatedAsync: event; + Created: event; + Bind: (this:DOM|any,key:event|string,func:(...any)->(),typefunc:string?)->(); + Disconnecter: (id:string?)->disconnecter; } & (eventName:string)->event; ------------------- -- module_signal ------------------- +export type signal = {} export type module_signal = {} ------------------- -- module_register ------------------- export type register = { - register: (self:register,()->())->(); - with: (self:R®ister,handler:{any}|(store:store,value:any,key:any,item:DOM)->any)->R®ister; - default: (self:R®ister,value:any)->R®ister; - add: (self:R®ister,value:any)->R®ister; - tween: (self:R®ister,tween:TweenOptions)->R®ister; + Register: (self:register,()->())->(); + With: (self:R®ister,handler:{any}|(store:store,value:any,key:any,item:DOM)->any)->R®ister; + Default: (self:R®ister,value:any)->R®ister; + Add: (self:R®ister,value:any)->R®ister; + Tween: (self:R®ister,tween:TweenOptions)->R®ister; } export type store = {} export type objectList = { - each: (self:objectList,(item:DOM,index:number)->())->(); - eachSync: (self:objectList,(item:DOM,index:number)->())->(); - remove: (self:objectList,index:number|DOM)->(DOM?,number?); - isEmpty: (self:objectList)->boolean; + Each: (self:objectList,(item:DOM,index:number)->())->(); + EachSync: (self:objectList,(item:DOM,index:number)->())->(); + Remove: (self:objectList,index:number|DOM)->(DOM?,number?); + IsEmpty: (self:objectList)->boolean; } export type ObjectIdList = string export type module_store = { - getObjects: (ids:ObjectIdList)->objectList; - getObject: (id:string)->DOM?; - addObject: (ids:ObjectIdList)->(); - + GetObjects: (ids:ObjectIdList)->objectList; + SetObject: (id:string)->DOM?; + AddObject: (ids:ObjectIdList)->(); } ------------------- @@ -87,16 +92,27 @@ export type module_style = {} export type module_mount = {} ------------------- --- module_signal +-- module_tween ------------------- - export type TweenOnStepped = (Item:DOM|any,Alpha:number,AbsolutePercent:number)->() export type TweenEnded = (Item:DOM|any)->() export type TweenSetter = (Item:DOM|any,Property:string,Value:Lerpable)->() export type TweenGetter = (Item:DOM|any,Property:string)->() export type TweenOptions = { - Easing: EasingFunction?; - Direction: EasingDirection?; + Easing: "Linear" + |"Quint" + |"Quart" + |"Cubic" + |"Quad" + |"Sin" + |"Circle" + |"Expo" + |"Elastic" + |"Bounce" + |"Exp2" + |"Exp4" + |EasingFunction?; + Direction: "Out"|"InOut"|"In"|EasingDirection?; CallBack: {[number|"*"|string]:(Item:DOM|any,Alpha:number,AbsolutePercent:number)->()}?; OnStepped: TweenOnStepped?; -- Same as CallBack{["*"]:()->()} But faster then CallBack due to table loop Ended: TweenEnded?; @@ -119,47 +135,52 @@ export type EasingFunctions = { -- Old things Exp2: EasingFunction; ---덜 가파른 지수. i=math.exp(x), x=-4 ~ 2 Exp4: EasingFunction; ---더 가파른 지수. i=math.exp(x), x=-4 ~ 4 - Exp2Max4: EasingFunction; ---@deprecated } export type EasingDirection = string export type EasingDirections = { Out: EasingDirection&"Out"; In: EasingDirection&"In"; + InOut: EasingDirection&"InOut"; } export type Lerpable = Color3|UDim|UDim2|number|Vector2|Vector3|CFrame export type TweenHandler = ()->(); -export type AdvancedTween = { +export type module_tween = { EasingFunctions:EasingFunctions; EasingDirections:EasingDirections; LerpProperties: (item:item&(DOM|any),old:{[string]:Lerpable},new:{[string]:Lerpable},alpha:number,setter:(item:item&(DOM|any),property:string,value:Lerpable)->()?)->(); RunTween: (Item:DOM|any,Option:TweenOptions,Properties:{[string]:Lerpable},Ended:TweenEnded?,OnStepped:TweenOnStepped?,Setter:TweenSetter?,Getter:TweenGetter?)->TweenHandler; + RunTweens: (Items:{[number]:DOM|any},Option:TweenOptions,Properties:{[string]:Lerpable},Ended:TweenEnded?,OnStepped:TweenOnStepped?,Setter:TweenSetter?,Getter:TweenGetter?)->(); + StopTween: (ItemOrStep:TweenHandler|DOM|any)->(); + StopPropertyTween: (Item:DOM|any,PropertyName:string)->(); + IsTweening: (ItemOrStep:TweenHandler|DOM|any)->boolean; + IsPropertyTweening: (Item:DOM|any,PropertyName:string)->boolean; } ------------------- -- module_signal ------------------- export type round = { - setRound: (ImageFrame:ImageLabel|ImageButton,RoundSize:number)->(ImageLabel|ImageButton); - setOutline: (ImageFrame:ImageLabel|ImageButton,RoundSize:number)->(ImageLabel|ImageButton); - getRound: (ImageFrame:ImageLabel|ImageButton)->number; - getOutline: (ImageFrame:ImageLabel|ImageButton)->number; + SetRound: (ImageFrame:ImageLabel|ImageButton,RoundSize:number)->(ImageLabel|ImageButton); + SetOutline: (ImageFrame:ImageLabel|ImageButton,RoundSize:number)->(ImageLabel|ImageButton); + GetRound: (ImageFrame:ImageLabel|ImageButton)->number; + GetOutline: (ImageFrame:ImageLabel|ImageButton)->number; } ------------------- -- module ------------------- export type module_exported = { - round: round; - tween: AdvancedTween; - style: module_style; - event: module_event; - store: module_store; - mount: module_mount; - class: module_class; + Round: round; + Tween: module_tween; + Style: module_style; + Event: module_event; + Store: module_store; + Mount: module_mount; + Class: module_class; } export type module = { - uninit: (id:string)->(); - init: (id:string)->module_exported; + Uninit: (id:string)->(); + Init: (id:string)->module_exported; } return {} diff --git a/src/vercheck.lua b/src/vercheck.lua deleted file mode 100644 index b514865..0000000 --- a/src/vercheck.lua +++ /dev/null @@ -1,11 +0,0 @@ - -local IS_TEST = true -local VER = "1.14" .. (IS_TEST and "B" or "") - -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 - -return { - version = VER -} diff --git a/test.project.json b/test.project.json index 5085496..297f1a0 100644 --- a/test.project.json +++ b/test.project.json @@ -1,19 +1,13 @@ { - "name": "Plugin", + "name": "quadTesting", "tree": { "$className": "DataModel", "ReplicatedStorage": { "$className": "ReplicatedStorage", - "Quad": { - "$path": "./" - } - }, - "StarterGui": { - "$className": "StarterGui", - "QuadTesting": { - "$className": "ScreenGui", - "testScript": { - "$path": "testScript.client.lua" + "QuadTest": { + "$path": "./testing", + "Quad": { + "$path": "./" } } } diff --git a/testing/init.lua b/testing/init.lua new file mode 100644 index 0000000..af1d087 --- /dev/null +++ b/testing/init.lua @@ -0,0 +1,85 @@ + +local module = {} + +local Quad = require(script.Quad) + +local isTestMode = script.Name:match("testing_") + +function module.setTheme(global) + local isDark + local hasPermissionToGetSettings = pcall(function() + isDark = tostring(settings().Studio.Theme) == "Dark" + end) + if isDark == nil then isDark = true end + + -- topbar + global.topbarColor = isDark + and Color3.fromRGB(142, 21, 255) + or Color3.fromRGB(163, 65, 255) + global.topbarTextColor = isDark + and Color3.fromRGB(255, 255, 255) + or Color3.fromRGB(0, 0, 0) + + -- background + global.backgroundColor = isDark + and Color3.fromRGB(32, 32, 32) + or Color3.fromRGB(255, 255, 255) + + -- texts + global.textColor = isDark + and Color3.fromRGB(255, 255, 255) + or Color3.fromRGB(0, 0, 0) + global.editableTextColor = isDark + and Color3.fromRGB(240, 240, 240) + or Color3.fromRGB(25, 25, 25) + global.placeholderTextColor = isDark + and Color3.fromRGB(170, 170, 170) + or Color3.fromRGB(124, 124, 124) + + -- init theme chnaged handler + if hasPermissionToGetSettings and (not global.themeConnection) then + global.themeConnection = settings().Studio.ThemeChanged:Connect(function() + module.setTheme(global) + end) + end +end + +function module.init() + local quad = Quad.init("ui") + local round,class,mount,store,event,tween,style + = quad.round,quad.class,quad.mount,quad.store,quad.event,quad.tween,quad.style + + local frame = class "Frame" + local gui = class "ScreenGui" + + local global = store.getStore "global" + local tweenTest = class(script.tween) + + module.setTheme(global) + + gui "MainGui" { + frame "Main" { + Size = UDim2.fromOffset(400,640); + Position = UDim2.fromScale(0.5,0.5); + AnchorPoint = Vector2.new(0.5,0.5); + tweenTest{}; + } + } + mount(game.StarterGui,store.getObject "MainGui") + _G.uiinstance = store.getObject "MainGui" +end + +function module.deinit() + if isTestMode then + local lastInstance = _G.uiinstance + Quad.uninit("ui") + if lastInstance then + lastInstance:Destroy() + end + _G.uiinstance = nil + return + end + Quad.uninit("ui") +end + +return module diff --git a/testing/test/init.lua b/testing/test/init.lua new file mode 100644 index 0000000..ea414f7 --- /dev/null +++ b/testing/test/init.lua @@ -0,0 +1,65 @@ + +local function remove() + local lastModule = _G.uilastmodule + if lastModule then + require(lastModule).deinit() + end +end + +local function reload() + local lastModule = _G.uilastmodule + if lastModule then + local passed,module = pcall(require,lastModule) + if passed then + module.deinit() + _G.uiloaded = false + end + lastModule:Destroy() + end + _G.uilastmodule = nil + + lastModule = script.Parent:Clone() + lastModule.Archivable = false + lastModule.Name = "testing_" .. lastModule.Name + if lastModule:FindFirstChild("loader") then + lastModule.loader.Disabled = true + end + lastModule.Parent = script.Parent.Parent + _G.uilastmodule = lastModule + + local module = require(lastModule) + if _G.uiloaded then + module.deinit() + _G.uiloaded = false + end + + module.init() + _G.uiloaded = true +end + +return { + track = function () + + reload() + + if not _G.uichangetracker then + ---@module "src.test.tracker" + local tracker = require(script.tracker) + local changeTracker = tracker.new(script.Parent) + + changeTracker:connect("updated",function () + reload() + end) + changeTracker:init() + _G.uichangetracker = changeTracker + end + end, + untrack = function () + _G.uichangetracker:deinit() + _G.uichangetracker = nil + remove() + end +} + + + diff --git a/testing/test/tracker.lua b/testing/test/tracker.lua new file mode 100644 index 0000000..a929ecd --- /dev/null +++ b/testing/test/tracker.lua @@ -0,0 +1,111 @@ +-- module name : handling rojo tree changes + +if false then if not task then _G.task = {} end end +---@class tracker_rojo +local module = {} +module.__index = module + +module.scheduleDelay = 0.1 + +function module:__emit(eventName,...) + for _,func in ipairs(self.events[eventName]) do + func(...) + end +end + +function module:__update() + -- do updates + self:__emit("updated") +end + +function module:__scheduleUpdate() + -- already timer setted + if self.__onTimer then return end + + self.__onTimer = true + task.delay(self.scheduleDelay,function () + self.__onTimer = false + self:__update() + end) +end + +function module:__track(ins) + self.connections[ins] = ins.Changed:Connect(function () + self:__scheduleUpdate() + end) +end + +function module:__drop(ins) + local signal = self.connections[ins] + if type(signal) == "table" then + for _,v in pairs(signal) do + v:Disconnect() + end + self.connections[ins] = nil + elseif signal then + signal:Disconnect() + self.connections[ins] = nil + end +end + +function module:init() + local mainConnections = {} + self.connections[self.main] = mainConnections + + mainConnections[1] = self.main.DescendantAdded:Connect(function (ins) + self:__track(ins) + self:__scheduleUpdate() + end) + + for _,ins in pairs(self.main:GetDescendants()) do + self:__track(ins) + end + + mainConnections[2] = self.main.DescendantRemoving:Connect(function (ins) + self:__drop(ins) + self:__scheduleUpdate() + end) + + self:__track(self.main) + mainConnections[3] = self.main.Destroying:Connect(function () + self:__drop(self.main) + end) + self:__scheduleUpdate() + + return self +end + +function module:connect(eventName,func) + table.insert(self.events[eventName],func) +end + +function module:deinit() + for i,signal in pairs(self.connections) do + if type(signal) == "table" then + for _,v in pairs(signal) do + signal:Disconnect() + end + self.connections[i] = nil + elseif signal then + signal:Disconnect() + self.connections[i] = nil + end + end +end + +---@return tracker_rojo +function module.new(ins) + local this = { + main = ins, + connections = {}, + events = { + updated = {}, + }, + __onTimer = false, + } + + setmetatable(this,module) + return this +end + +return module diff --git a/testing/tween.lua b/testing/tween.lua new file mode 100644 index 0000000..c569d07 --- /dev/null +++ b/testing/tween.lua @@ -0,0 +1,115 @@ + +local module = {} + +---@module Quad.src.types +local types = require(script.Parent.Quad.types) +local quad = (require(script.Parent.Quad) :: types.module).init("ui") +local round,class,mount,store,event,tween,style += quad.round,quad.class,quad.mount,quad.store,quad.event,quad.tween,quad.style + +local global = store.getStore "global" + +-- Import classes +local frame = class "Frame" +frame.BorderSizePixel = 0 +frame.BackgroundColor3 = global "backgroundColor" +local textLabel = class "TextLabel" +textLabel.BackgroundTransparency = 1 +textLabel.BorderSizePixel = 0 +textLabel.Font = Enum.Font.Gotham; +textLabel.TextColor3 = global "textColor" +textLabel.TextSize = 16; + +local tweenTestFrameStyle = style "tweenTestFrame" { + BackgroundTransparency = 0; + Size = UDim2.fromOffset(60,30); + BackgroundColor3 = Color3.fromRGB(0, 0, 0); +}; + +-- Create GUI +local tweenTest = class.extend() + +function tweenTest:init(prop) + prop:default("tweenTest",UDim2.fromOffset(50,0)) + local on = false + task.spawn(function() + while wait(2) do + on = not on + prop.tweenTest = on and UDim2.new(1,-50-60,0,0) or UDim2.fromOffset(50,0) + end + end) +end + +function tweenTest:render(prop) + return frame { + Size = UDim2.fromScale(1,1); + textLabel "tweenTestFrame" { + Text = "Linear"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,80)):tween{Direction = "InOut",Time = 2,Easing = "Linear"}; + }; + textLabel "tweenTestFrame" { + Text = "Expo"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,120)):tween{Direction = "InOut",Time = 2,Easing = "Expo"}; + }; + textLabel "tweenTestFrame" { + Text = "Quint"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,160)):tween{Direction = "InOut",Time = 2,Easing = "Quint"}; + }; + textLabel "tweenTestFrame" { + Text = "Quart"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,200)):tween{Direction = "InOut",Time = 2,Easing = "Quart"}; + }; + textLabel "tweenTestFrame" { + Text = "Cubic"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,240)):tween{Direction = "InOut",Time = 2,Easing = "Cubic"}; + }; + textLabel "tweenTestFrame" { + Text = "Quad"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,280)):tween{Direction = "InOut",Time = 2,Easing = "Quad"}; + }; + textLabel "tweenTestFrame" { + Text = "Sin"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,320)):tween{Direction = "InOut",Time = 2,Easing = "Sin"}; + }; + textLabel "tweenTestFrame" { + Text = "Circle"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,360)):tween{Direction = "InOut",Time = 2,Easing = "Circle"}; + }; + textLabel "tweenTestFrame" { + Text = "Exp2"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,400)):tween{Direction = "InOut",Time = 2,Easing = "Exp2"}; + }; + textLabel "tweenTestFrame" { + Text = "Exp4"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,440)):tween{Direction = "InOut",Time = 2,Easing = "Exp4"}; + }; + textLabel "tweenTestFrame" { + Text = "Elastic"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,480)):tween{Direction = "InOut",Time = 2,Easing = "Elastic"}; + }; + textLabel "tweenTestFrame" { + Text = "Bounce"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,520)):tween{Direction = "InOut",Time = 2,Easing = "Bounce"}; + }; + textLabel "tweenTestFrame" { + Text = "Back"; + Position = prop "tweenTest":add(UDim2.fromOffset(0,560)):tween{Direction = "InOut",Time = 2,Easing = "Back"}; + }; + -- frame { + -- Size = UDim2.new(100,100); + -- [event.created] = function(self) + -- for i = 1,100 do + -- mount(self,frame{ + -- Size = UDim2.fromOffset(3,3); + -- AnchorPoint = Vector2.new(0.5,0.5); + -- Position = UDim2.fromOffset(100-i,tween.CalcEasing(tween.EasingFunctions.Circle,tween.EasingDirections.InOut,i/100)*100); + -- BackgroundColor3 = Color3.fromRGB(110, 110, 255); + -- }) + -- end + -- end; + -- BackgroundColor3 = Color3.fromRGB(0,0,0); + -- }; + } +end + +return tweenTest