-
Notifications
You must be signed in to change notification settings - Fork 2
/
ticuare.min.lua
12 lines (10 loc) · 14.7 KB
/
ticuare.min.lua
1
2
3
4
5
6
7
8
9
10
11
12
-- title: TICuare
-- author: Crutiatix
-- desc: UI library for TIC-80 v0.8.0
-- script: lua
-- input: mouse
-- Copyright (c) 2017 Crutiatix
-- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ticuare={name="ticuare",elements={},z=1,hz=nil}ticuare.__index=ticuare;ticuare.me={nothing=0,click=1,noclick=2,none=3}local a={__index=ticuare}local function b(c,d,e,f,g,h)return c>e and c<e+g and d>f and d<f+h end;local function i(j,k,l)for m,n in pairs(k)do if type(n)=="table"then if type(j[m]or false)=="table"then i(j[m]or{},k[m]or{},l)else if not j[m]or l then j[m]=n end end else if not j[m]or l then j[m]=n end end end;return j end;local function o(p,q)if p==nil and q==nil then for r=0,15 do poke4(0x3FF0*2+r,r)end else poke4(0x3FF0*2+p,q)end end;function ticuare.lerp(s,t,m)if s==t then return s else if math.abs(s-t)<0.005 then return t else return s*(1-m)+t*m end end end;local function u(v)local w={}local function x(v)if type(v)~="table"then return v elseif w[v]then return w[v]end;local y={}w[v]=y;for r,n in pairs(v)do y[x(r)]=x(n)end;return setmetatable(y,getmetatable(v))end;return x(v)end;local function z(A,B,C,D,E)if A then return C elseif B then return D else return E end end;function ticuare.print(F,e,f,G,H,I)H=H or false;I=I or 1;local J,K=F:gsub("\n","")local L,M=0,0;if G then L,M=print(F,e,f,G,H,I),(6+K)*I*(K+1)end;return L,M end;function ticuare.font(F,e,f,N,O,P,Q,H,I)O=O or-1;P=P or 8;Q=Q or 8;H=H or false;I=I or 1;local J,K=F:gsub("\n","")if type(O)=="table"and type(O[1])=="table"then for R,S in ipairs(O[1])do if type(N)=="table"then o(S,N[R])else o(S,N)end end;O=O[2]end;local L;if N then L=font(F,e,f,O,P,Q,H,I)end;o()return L,(Q+K)*I*(1+K)end;function ticuare.element(T,U)if not U then U=T;T="element"end;local V=U;setmetatable(V,ticuare)V.hover,V.click=false,false;V.activity=U.activity or true;V.drag=U.drag or{activity=false}V.align=U.align or{x=0,y=0}V.visibility=U.visibility or true;if V.content then if not V.content.scroll then V.content.scroll={x=0,y=0}end;V.content.w,V.content.h=V.content.w or V.w,V.content.h or V.h end;V.type,V.z=T,ticuare.z;ticuare.z=ticuare.z+1;ticuare.hz=ticuare.z;table.insert(ticuare.elements,V)return V end;function ticuare.Element(W)return ticuare.element("element",W)end;function ticuare.Style(W)return W end;function ticuare.Group()local X={type="group",elements={}}setmetatable(X,ticuare)return X end;function ticuare:updateSelf(Y)if Y.mouse_x and Y.mouse_y and Y.event then mouse_x=Y.mouse_x;mouse_y=Y.mouse_y;mouse_press=Y.press;mouse_event=Y.event;local Z,_,a0,a1,a2,a3,a4;local a5,a6,a7=ticuare.me,self.x-(self.align.x==1 and self.w*.5 or(self.align.x==2 and self.w or 0)),self.y-(self.align.y==1 and self.h*.5-1 or(self.align.y==2 and self.h-1 or 0))Z=mouse_event~=a5.none and mouse_press or false;_=b(mouse_x,mouse_y,a6,a7,self.w,self.h)a0=mouse_event~=a5.none and _ or false;a1,a2=self.hover,self.hold;self.hover=a0 or self.drag.active and ticuare.draging_obj and ticuare.draging_obj.obj==self;self.hold=mouse_event==a5.click and a0 and true or Z and self.hold or a0 and mouse_event~=a5.noclick and self.hold;if mouse_event==a5.click and a0 and self.onClick then self.onClick(self)elseif mouse_event==a5.noclick and a0 and a2 and self.onCleanRelease then self.onCleanRelease(self)elseif(mouse_event==a5.noclick and a0 and a2 or self.hold and not a0)and self.onRelease then self.onRelease(self)elseif self.hold and self.onPress then self.onPress(self)elseif not a1 and self.hover and self.onStartHover then self.onStartHover(self)elseif self.hover and self.onHover then self.onHover(self)elseif a1 and not self.hover and self.onReleaseHover then self.onReleaseHover(self)end;if self.hold and(not a0 or self.drag.active)and not ticuare.draging_obj then self.hold=self.drag.active;ticuare.draging_obj={obj=self,d={x=a6-mouse_x,y=a7-mouse_y}}elseif not self.hold and a0 and(ticuare.draging_obj and ticuare.draging_obj.obj==self)then self.hold=true;ticuare.draging_obj=nil end;if ticuare.draging_obj and ticuare.draging_obj.obj==self and self.drag.active then self.x=(not self.drag.fixed or not self.drag.fixed.x)and mouse_x+ticuare.draging_obj.d.x or self.x;self.y=(not self.drag.fixed or not self.drag.fixed.y)and mouse_y+ticuare.draging_obj.d.y or self.y;local a8=self.drag.bounds;if a8 then if a8.x then self.x=a8.x[1]and self.x<a8.x[1]and a8.x[1]or self.x;self.x=a8.x[2]and self.x>a8.x[2]and a8.x[2]or self.x end;if a8.y then self.y=a8.y[1]and self.y<a8.y[1]and a8.y[1]or self.y;self.y=a8.y[2]and self.y>a8.y[2]and a8.y[2]or self.y end end;if self.track then self:anchor(self.track.ref)end end;return a0 elseif Y.focused_element and Y.event then local a5,a9,aa,a0,a1,a2=ticuare.me;a9=Y.event~=a5.none and Y.press or false;aa=self==Y.focused_element;a0=Y.event~=a5.none and aa or false;a1,a2=self.hover,self.hold;self.hover=a0;self.hold=Y.event==a5.click and a0 and true or a9 and self.hold or a0 and Y.event~=a5.noclick and self.hold;if Y.event==a5.click and a0 and self.onClick then self.onClick(self)elseif Y.event==a5.noclick and a0 and a2 and self.onCleanRelease then self.onCleanRelease(self)elseif(Y.event==a5.noclick and a0 and a2 or self.hold and not a0)and self.onRelease then self.onRelease(self)elseif self.hold and self.onPress then self.onPress(self)elseif not a1 and self.hover and self.onStartHover then self.onStartHover(self)elseif self.hover and self.onHover then self.onHover(self)elseif a1 and not self.hover and self.onReleaseHover then self.onReleaseHover(self)end;return a0 else error("updateSelf error in arguments!")end end;function ticuare:updateTrack()local a8,ab=self.drag.bounds,self.track;if ab then self.x,self.y=ab.ref.x+ab.d.x,ab.ref.y+ab.d.y;if a8 and a8.relative then if a8.x then a8.x[1]=ab.ref.x+ab.b.x[1]or nil;a8.x[2]=ab.ref.x+ab.b.x[2]or nil end;if a8.y then a8.y[1]=ab.ref.y+ab.b.y[1]or nil;a8.y[2]=ab.ref.y+ab.b.y[2]or nil end end end end;function ticuare:drawSelf()if self.visibility then local G,ac,ad,ae,af,ag,ah,ai,a6,a7,aj,ak,al,am,an,ao,ap,aq,ar,as,at,au,av,aw,ax;local ay,az,F,aA,aB,N=self.shadow,self.border,self.text,self.icon,self.tiled,self.colors;a6=self.x-(self.align.x==1 and self.w*.5-1 or(self.align.x==2 and self.w-1 or 0))a7=self.y-(self.align.y==1 and self.h*.5-1 or(self.align.y==2 and self.h-1 or 0))if ay and ay.colors then ay.offset=ay.offset or{x=1,y=1}ac=z(self.hold,self.hover,ay.colors[3],ay.colors[2],ay.colors[1])if ac then rect(a6+ay.offset.x,a7+ay.offset.y,self.w,self.h,ac)end end;if N then G=z(self.hold,self.hover,N[3],N[2],N[1])if G then rect(a6,a7,self.w,self.h,G)end end;as=az and az.width or 0;aw=2*as;if aB then aB.scale=aB.scale or 1;aB.key=aB.key or-1;aB.flip=aB.flip or 0;aB.rotate=aB.rotate or 0;aB.w=aB.w or 1;aB.h=aB.h or 1;av=z(self.hold,self.hover,aB.sprites[3],aB.sprites[2],aB.sprites[1])if av then clip(a6+as,a7+as,self.w-aw,self.h-aw)for e=0,self.w+8*aB.w*aB.scale,8*aB.w*aB.scale do for f=0,self.h+8*aB.h*aB.scale,8*aB.h*aB.scale do spr(av,a6+e+as,a7+f+as,aB.key,aB.scale,aB.flip,aB.rotate,aB.w,aB.h)end end;clip()end end;if self.content and self.drawContent then if self.content.wrap and clip then clip(a6+as,a7+as,self.w-aw,self.h-aw)end;self:renderContent()if self.content.wrap and clip then clip()end end;if az and az.colors then an=az.colors;ad=z(self.hold,self.hover,an[3],an[2],an[1])if ad then for t=0,az.width-1 do rectb(a6+t,a7+t,self.w-2*t,self.h-2*t,ad)end end end;if az and az.sprites then at=az.key or-1;au=z(self.hold,self.hover,az.sprites[3],az.sprites[2],az.sprites[1])if au then clip(a6+8,a7,self.w-16+1,self.h)for e=8,self.w-9,8 do spr(au[2],a6+e,a7,at,1,0,0)spr(au[2],a6+e,a7+self.h-8,at,1,0,2)end;clip()spr(au[1],a6,a7,at,1,0,0)spr(au[1],a6+self.w-8,a7,at,1,0,1)clip(a6,a7+8,self.w,self.h-16+1)for f=8,self.h-9,8 do spr(au[2],a6,a7+f,at,1,0,3)spr(au[2],a6+self.w-8,a7+f,at,1,2,1)end;clip()spr(au[1],a6+self.w-8,a7+self.h-8,at,1,0,2)spr(au[1],a6,a7+self.h-8,at,1,0,3)end end;if aA and aA.sprites and#aA.sprites>0 then ai=self.hold and aA.sprites[3]and aA.sprites[3]or self.hover and aA.sprites[2]and aA.sprites[2]or aA.sprites[1]ao=aA.offset or{x=0,y=0}aA.align=aA.align or{x=0,y=0}spr(ai,a6+(aA.align.x==1 and self.w*.5-aA.scale*8/2 or(aA.align.x==2 and self.w-aA.scale*8 or 0))+ao.x,a7+(aA.align.y==1 and self.h*.5-aA.scale*8/2 or(aA.align.y==2 and self.h-aA.scale*8 or 0))+ao.y,aA.key,aA.scale,aA.flip,aA.rotate,aA.w,aA.h)end;if F and F.print then ah=F.colors or{15,15,15}ah[1]=ah[1]or 15;if not F.font and type(F.colors[1])=="table"then trace("If text.font is true, then text.colors has to be array of numbers!",6)trace("Traceback: Element with text:\""..F.print.."\"")exit()end;af=z(self.hold,self.hover,ah[3],ah[2],ah[1])if F.shadow then ag=F.shadow;ae=z(self.hold,self.hover,ag.colors[3],ag.colors[2],ag.colors[1])aq=ag.offset or{x=1,y=1}end;ap=F.offset or{x=0,y=0}if F.font then F.space=F.space or{w=8,h=8}aj,ak=ticuare.font(F.print,0,200,-1,F.key,F.space.w,F.space.h,F.fixed,F.scale)else aj,ak=ticuare.print(F.print,0,200,-1,F.fixed,F.scale)end;ax=F.align or{x=0,y=0}al=ax.x==1 and a6+self.w*.5-aj*.5+ap.x or(ax.x==2 and a6+self.w-aj+ap.x-as or a6+ap.x+as)am=ax.y==1 and a7+self.h*.5-ak*.5+ap.y or(ax.y==2 and a7+self.h-ak+ap.y-as or a7+ap.y+as)if F.font then if type(ae)=="table"then ticuare.font(F.print,al+aq.x,am+aq.y,ae,F.key,F.space.w,F.space.h,F.fixed,F.scale)end;ticuare.font(F.print,al,am,af,F.key,F.space.w,F.space.h,F.fixed,F.scale)else if ae then ticuare.print(F.print,al+aq.x,am+aq.y,ae,F.fixed,F.scale)end;ticuare.print(F.print,al,am,af,F.fixed,F.scale)end end end end;function ticuare:renderContent()local aC,aD,az,aE,aF,aG;aG=self.align;aC=self.x-(aG.x==1 and self.w*.5 or(aG.x==2 and self.w or 0))aD=self.y-(aG.y==1 and self.h*.5-1 or(aG.y==2 and self.h-1 or 0))az=self.border and self.border.width or 1;aE=aC-(self.content.scroll.x or 0)*(self.content.w-self.w)+az;aF=aD-(self.content.scroll.y or 0)*(self.content.h-self.h)+az;self.drawContent(self,aE,aF)end;function ticuare:Content(W)self.drawContent=W;return self end;function ticuare:scroll(W)if W~=nil then W.x=W.x or 0;W.y=W.y or 0;if self.content then W.x=W.x<0 and 0 or W.x>1 and 1 or W.x;W.y=W.y<0 and 0 or W.y>1 and 1 or W.y;self.content.scroll.x,self.content.scroll.y=W.x or self.content.scroll.x,W.y or self.content.scroll.y end;return self else if self.content then return self.content.scroll end end end;function ticuare.update(mouse_x,mouse_y,aH)local a5,aI=ticuare.me,ticuare.elements;local mouse_event,aJ,aK,aL=a5.nothing,false,{},nil;if type(mouse_x)=="table"then aH=mouse_y end;if mouse_x then if ticuare.click and not aH then ticuare.click=false;mouse_event=a5.noclick;ticuare.draging_obj=nil elseif not ticuare.click and aH then ticuare.click=true;mouse_event=a5.click;ticuare.draging_obj=nil end;for r=1,#aI do table.insert(aK,aI[r])end;table.sort(aK,function(s,t)return s.z>t.z end)for r=1,#aK do aL=aK[r]if aL then if type(mouse_x)=="table"then if aL:updateSelf{focused_element=mouse_x,press=aH,event=(aJ or not aL.activity)and a5.none or mouse_event}then aJ=true end elseif mouse_x and mouse_y and type(mouse_x)~="table"then if aL:updateSelf{mouse_x=mouse_x,mouse_y=mouse_y,press=aH,event=(aJ or ticuare.draging_obj and ticuare.draging_obj.obj~=aL or not aL.activity)and a5.none or mouse_event}then aJ=true end else error("Wrong arguments for update()")end end end;for r=#aI,1,-1 do if aI[r]then aI[r]:updateTrack()end end end end;function ticuare.draw()local aM={}for r=1,#ticuare.elements do if ticuare.elements[r].draw then table.insert(aM,ticuare.elements[r])end end;table.sort(aM,function(s,t)return s.z<t.z end)for r=1,#aM do aM[r]:drawSelf()end end;function ticuare:style(aN)if self.type=="group"then for m,n in pairs(self.elements)do i(n,u(aN),false)end else i(self,u(aN),false)end;return self end;function ticuare:anchor(aO)if self.type=="group"then for m,n in pairs(self.elements)do n:anchor(aO)end else local a8,aP,aQ,aR,aS=self.drag.bounds,nil,nil,nil,nil;if a8 and a8.x then aP=a8.x[1]-aO.x;aQ=a8.x[2]-aO.x elseif a8 and a8.y then aR=a8.y[1]-aO.y;aS=a8.y[2]-aO.y end;self.track={ref=aO,d={x=self.x-aO.x,y=self.y-aO.y},b={x={aP,aQ},y={aR,aS}}}end;return self end;function ticuare:group(aT,aU)if aU then aT.elements[aU]=self else table.insert(aT.elements,self)end;return self end;function ticuare:active(aV)if aV~=nil then if self.type=="group"then for m,n in pairs(self.elements)do n:active(aV)end else self.activity=aV end;return self else if self.type=="group"then local aW={}for m,n in pairs(self.elements)do aW[m]=n:active()end;return aW else if self.activity~=nil then return self.activity end end end end;function ticuare:visible(aV)if aV~=nil then if self.type=="group"then for m,n in pairs(self.elements)do n:visible(aV)end else self.visibility=aV end;return self else if self.type=="group"then local aW={}for m,n in pairs(self.elements)do aW[m]=n:visible()end;return aW else if self.activity~=nil then return self.visibility end end end end;function ticuare:dragBounds(a8)if a8~=nil then self.drag.bounds=a8 else return self.drag.bounds end end;function ticuare:horizontalRange(aX)local a8=self.drag.bounds;if aX~=nil then self.x=a8.x[1]+(a8.x[2]-a8.x[1])*aX else assert(a8 and a8.x and#a8.x==2,"X bounds error!")return(self.x-a8.x[1])/(a8.x[2]-a8.x[1])end end;function ticuare:verticalRange(aX)local a8=self.drag.bounds;if aX~=nil then self.y=a8.y[1]+(a8.y[2]-a8.y[1])*aX else assert(a8 and a8.y and#a8.y==2,"Y bounds error!")return(self.y-a8.y[1])/(a8.y[2]-a8.y[1])end end;function ticuare:index(aY)if aY~=nil then if self.type=="group"then local aZ;for m,n in pairs(self.elements)do if not aZ or n.z<aZ then aZ=n.z end end;for m,n in pairs(self.elements)do local a_=n.z-aZ+aY;n:index(a_)end else self.z=aY;if aY>ticuare.hz then ticuare.hz=aY end end else return self.z end;return end;function ticuare:toFront()if self.z<ticuare.hz or self.type=="group"then return self:index(ticuare.hz+1)end end;function ticuare:remove()for r=#ticuare.elements,1,-1 do if ticuare.elements[r]==self then table.remove(ticuare.elements,r)self=nil end end end;function ticuare.empty()for r=1,#ticuare.elements do ticuare.elements[r]=nil end end