--[[ Copyright (c) 2022, Marco4413 : https://github.com/Marco4413/YAGUI Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --]] local a={ver="1.43",author="Marco4413",website="https://github.com/Marco4413/YAGUI/",documentation="https://Marco4413.github.io/YAGUI/",copyright="Copyright (c) 2022, Marco4413 : https://github.com/Marco4413/YAGUI\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.",nfp="1.0.0",nft="1.0.0",yai="1.0.0"}local b={TIMER="timer",TOUCH="screen_touch",MOUSEUP="mouse_up",MOUSEDRAG="mouse_drag",MOUSEMOVE="mouse_move",MOUSESCROLL="mouse_scroll",CHAR="char",KEY="key",KEYUP="key_up",PASTE="paste",REDNET="rednet_message",MODEM="modem_message",TERMINATE="terminate",TERMRESIZE="term_resize",COROUTINE="coroutine",DELETED="DELETED",NONE="NONE",ALL="ALL",SEND="SEND",RECEIVE="RECEIVE",HOST="HOST",USER="USER",DISCONNECTED="DISCONNECTED",CONNECTION_REQUEST="CONNECTION_REQUEST",OK="OK",NO="NO",ERROR="ERROR",LOW_PRIORITY=1,HIGH_PRIORITY=2,ONSTART=1,ONSTOP=2,ONDRAW=3,ONPRESS=4,ONFAILEDPRESS=5,ONTIMEOUT=6,ONCLOCK=7,ONEVENT=8,ONFOCUS=9,ONKEY=10,ONCHAR=11,ONMOUSESCROLL=12,ONCURSORCHANGE=13,ONWRITE=14,ONCONNECT=15,ONDISCONNECT=16,ONSEND=17,ONRECEIVE=18,ONDRAG=19,ONRESIZE=20,ONPASTE=21,ONHOVER=22,ONRELEASE=23,MOUSE_LEFT=1,MOUSE_RIGHT=2,MOUSE_MIDDLE=3,SCROLL_UP=-1,SCROLL_DOWN=1,COMPUTER="computer",TURTLE="turtle",POCKET="pocket",ALIGN_LEFT=1,ALIGN_CENTER=2,ALIGN_RIGHT=3}for c,d in next,keys do if type(d)=="number"then b["KEY_"..c:upper()]=d end end;local e={TOP=string.char(131),BOTTOM=string.char(143),LEFT=string.char(149),RIGHT=string.char(149),MIDDLE=string.char(140),TOPLEFT=string.char(151),TOPRIGHT=string.char(148),BOTTOMLEFT=string.char(138),BOTTOMRIGHT=string.char(133),MIDDLELEFT=string.char(132),MIDDLERIGHT=string.char(136)}local f={}local g={}local h={}local i={}local j={}local k={}local l={}local m={}f={set_callback=function(n,o,p)n:set_callback(o,p)end,get_computer_type=function()local q=b.COMPUTER;if turtle then q=b.TURTLE elseif pocket then q=b.POCKET end;return q,term.isColor()end,expect=function(r,...)local s={...}local t="[/%.,]"r=type(r)=="string"and table.concat({" to '",r,"'"})or""local u=false;local v;for w=1,#s,2 do local x=tostring(s[w])local y=true;local z;for A,B in next,g.split(x,t)do local C=s[w+1]local D=type(C)if D~=B then z=D else y=false;break end end;if y then local E=g.split(x,t)local F=table.remove(E,#E)local G=#E==0 and F or table.concat({table.concat(E,", ")," or ",F})v=string.format("bad argument #%d%s (%s expected, got %s)",(w+1)/2,r,G,z)u=true;break end end;if u then error(v,3)return false end;return true end,get_type=function(H)local I=type(H)return I=="table"and type(H._type)=="string"and H._type or I end}g={magic_characters={"(",")",".","%","+","-","*","?","[","]","^","$"},join=table.concat,split=function(J,K)if not string.find(J,K)then return{J}end;local L={}local M=table.concat({"(.-)",K,"()"})local N;for O,P in string.gfind(J,M)do L[#L+1]=O;N=P end;L[#L+1]=string.sub(J,N)return L end,split_by_char=function(J,Q)local R={}local S=1;for w=1,#J do if J:sub(w,w)==Q then R[#R+1]=w==S and""or J:sub(S,w-1)S=w+1 end end;R[#R+1]=J:sub(S,#J)return R end,compare_versions=function(T,U)local V=g.split(T,".")local W=g.split(U,".")local X=#V;local Y=#W;for w=1,math.min(X,Y)do if tonumber(V[w])>tonumber(W[w])then return 1 elseif tonumber(V[w])Y then return 1 elseif X0 then return table.concat({a2,".",a4})end;return a2 end,trim=function(J)return J:gsub("^%s*(.*)%s*$","%1")end}h={Vector2={new=function(a5,a6)local a7={x=a5 or 0,y=a6 or 0}setmetatable(a7,h.Vector2)return a7 end,duplicate=function(self)return h.Vector2.new(self.x,self.y)end,length_sq=function(self)return self.x*self.x+self.y*self.y end,length=function(self)return math.sqrt(self.x*self.x+self.y*self.y)end,unit=function(self)return self/self:length()end,dot=function(self,a8)return self.x*a8.x+self.y*a8.y end,cross=function(self,a8)return self.x*a8.y-self.y*a8.x end,rotate=function(self,a9)local aa=math.cos(a9)local ab=math.sin(a9)return h.Vector2.new(aa*self.x-ab*self.y,ab*self.x+aa*self.y)end,string=function(self,a1)if a1 then return string.format(table.concat({"(%.",a1,"f; %.",a1,"f)"}),self.x,self.y)else return string.format("(%f; %f)",self.x,self.y)end end,__tostring=function(self)return self:string(0)end,__len=function(self)return self:length()end,__add=function(self,a8)return h.Vector2.new(self.x+a8.x,self.y+a8.y)end,__sub=function(self,a8)return h.Vector2.new(self.x-a8.x,self.y-a8.y)end,__mul=function(self,a0)if type(self)=="number"then return h.Vector2.new(a0.x*self,a0.y*self)else return h.Vector2.new(self.x*a0,self.y*a0)end end,__div=function(self,a0)return h.Vector2.new(self.x/a0,self.y/a0)end,__eq=function(self,a8)return self.x==a8.x and self.y==a8.y end,__lt=function(self,a8)return self:length_sq()0 then ar[aW[aV]],aW[#aW+1],ar[w]=ar[w],w;aV=aV+1 end end end}i.serialize=i.serialise;j={colors={[1]="0",[2]="1",[4]="2",[8]="3",[16]="4",[32]="5",[64]="6",[128]="7",[256]="8",[512]="9",[1024]="a",[2048]="b",[4096]="c",[8192]="d",[16384]="e",[32768]="f"},paint={},color_to_paint=function(aX)return j.colors[aX]end,paint_to_color=function(aY)return j.paint[aY]end}for d,H in next,j.colors do j.paint[H]=d end;k={in_area=function(aZ,a_,a5,a6,b0,b1)if aZ>=a5 and aZ=a6 and a_bj then bl=-1 end;local bm=bj-bh;local bn=bk-bi;local bo=1;if bn<0 then bo=-1;bn=-bn end;local bp=2*bn-bm;local a6=bi;for a5=bh,bj,bl do bg.buffer:set_pixel(a5,a6," ",aX,aX)if bp>0 then a6=a6+bo;bp=bp-2*bm end;bp=bp+2*bn end end,lineHigh=function(bg,bh,bi,bj,bk,aX)local bl=1;if bi>bk then bl=-1 end;local bm=bj-bh;local bn=bk-bi;local bq=1;if bm<0 then bq=-1;bm=-bm end;local bp=2*bm-bn;local a5=bh;for a6=bi,bk,bl do bg.buffer:set_pixel(a5,a6," ",aX,aX)if bp>0 then a5=a5+bq;bp=bp-2*bn end;bp=bp+2*bm end end,get_rect_char=function(a5,a6,br,bs)if bs==1 then if br==1 then return e.MIDDLE,true else if a5==1 then return e.MIDDLERIGHT,true elseif a5==br then return e.MIDDLELEFT,true else return e.MIDDLE,true end end elseif a6==1 then if a5==1 then return e.TOPLEFT,false elseif a5==br then return e.TOPRIGHT,true else return e.TOP,false end elseif a6==bs then if a5==1 then return e.BOTTOMLEFT,true elseif a5==br then return e.BOTTOMRIGHT,true else return e.BOTTOM,true end elseif a5==1 then return e.LEFT,false elseif a5==br then return e.RIGHT,true else return" ",false end end,buffer={is_pixel_custom=function(self,a5,a6)return self.pixels[a6]and self.pixels[a6][a5]and true or false end,get_pixel=function(self,a5,a6)return self.pixels[a6]and self.pixels[a6][a5]or{char=self.background.char,foreground=self.background.foreground,background=self.background.background,inverted=self.background.inverted}end,set_pixel=function(self,a5,a6,Q,ba,bb,bt)a5,a6=math.floor(a5),math.floor(a6)local bu=self:get_pixel(a5,a6)if Q then bu.char=Q:sub(1,1)end;if bt then bu.foreground,bu.background=bb or bu.foreground,ba or bu.background else if bu.inverted then bu.foreground,bu.background=ba or bu.background,bb or bu.foreground else bu.foreground,bu.background=ba or bu.foreground,bb or bu.background end end;bu.inverted=bt;if not self.pixels[a6]then self.pixels[a6]={}end;self.pixels[a6][a5]=bu end,remove_pixel=function(self,a5,a6)if self.pixels[a6]then self.pixels[a6][a5]=nil end end,clear=function(self)self.pixels={}end}}local bv={frame={pixels={},background=nil},screens={terminal=term},clear_after_draw=true,buffer={pixels={},background={char=" ",foreground=colors.black,background=colors.black,inverted=false}},set_screens=function(self,bw)self.screens=m.get_monitors(bw)end,set_monitors=function(self,b6)self:set_screens(b6)end,clear=function(self)self.buffer:clear()end,draw=function(self)local bx={}for by,bz in next,self.screens do local bA,bB=bz.getCursorPos()local b0,b1=bz.getSize()for a6=1,b1 do local bC,bD,bE={},{},{}for a5=bx[a6]and#bx[a6].text+1 or 1,b0 do local bu=self.buffer:get_pixel(a5,a6)bC[#bC+1]=bu.char;bD[#bD+1]=j.colors[bu.foreground]bE[#bE+1]=j.colors[bu.background]end;bx[a6]={text=table.concat({bx[a6]and bx[a6].text or"",table.concat(bC)}),fg=table.concat({bx[a6]and bx[a6].fg or"",table.concat(bD)}),bg=table.concat({bx[a6]and bx[a6].bg or"",table.concat(bE)})}bz.setCursorPos(1,a6)bz.blit(bx[a6].text:sub(0,b0),bx[a6].fg:sub(0,b0),bx[a6].bg:sub(0,b0))end;bz.setCursorPos(bA,bB)end;self.frame.pixels=self.buffer.pixels;self.frame.background=self.buffer.background;if self.clear_after_draw then self:clear()end end,point=function(self,a5,a6,aX)if not aX then return end;self.buffer:set_pixel(a5,a6," ",aX,aX)end,write=function(self,a5,a6,bF,ba,bb)for bG=0,#bF-1 do local Q=bF:sub(bG+1,bG+1)self.buffer:set_pixel(a5+bG,a6,Q,ba,bb)end end,blit=function(self,a5,a6,bF,ba,bb)local bH=""local bI=""ba=ba or""bb=bb or""for bG=0,#bF-1 do local Q=bF:sub(bG+1,bG+1)local bJ=ba:sub(bG+1,bG+1)bJ=#bJ>0 and bJ or bH;local bK=bb:sub(bG+1,bG+1)bK=#bK>0 and bK or bI;self.buffer:set_pixel(a5+bG,a6,Q,j.paint[bJ],j.paint[bK])bH=bJ;bI=bK end end,rectangle=function(self,a5,a6,b0,b1,aX,bL,bM,bN)if not aX then if bL and bM then bN=true else return end end;if bN then for bO=1,b0 do if bL then local Q,bt=bf.get_rect_char(bO,1,b0,b1)self.buffer:set_pixel(a5+bO-1,a6,Q,bM,aX,bt)Q,bt=bf.get_rect_char(bO,b1,b0,b1)self.buffer:set_pixel(a5+bO-1,a6+b1-1,Q,bM,aX,bt)else self.buffer:set_pixel(a5+bO-1,a6," ",aX,aX)self.buffer:set_pixel(a5+bO-1,a6+b1-1," ",aX,aX)end end;for bP=2,b1-1 do if bL then local Q,bt=bf.get_rect_char(1,bP,b0,b1)self.buffer:set_pixel(a5,a6+bP-1,Q,bM,aX,bt)Q,bt=bf.get_rect_char(b0,bP,b0,b1)self.buffer:set_pixel(a5+b0-1,a6+bP-1,Q,bM,aX,bt)else self.buffer:set_pixel(a5,a6+bP-1," ",aX,aX)self.buffer:set_pixel(a5+b0-1,a6+bP-1," ",aX,aX)end end else for bO=1,b0 do for bP=1,b1 do if bL then local Q,bt=bf.get_rect_char(bO,bP,b0,b1)self.buffer:set_pixel(a5+bO-1,a6+bP-1,Q,bM,aX,bt)else self.buffer:set_pixel(a5+bO-1,a6+bP-1," ",aX,aX)end end end end end,nfp_image=function(self,a5,a6,bQ,bR,bS,bT,bU)bR,bS=bR or 1,bS or 1;local bG,bV=1,1;for w=1,#bQ do if bU and bV>=bU+bS then break end;local Q=bQ:sub(w,w)if Q=="\n"then bG,bV=1,bV+1 else if bV>=bS and bG>=bR and(not bT or bG=bU+bS then break end;local Q=bQ:sub(w,w)if bW then bY=j.paint[Q]bW=false elseif bX then bZ=j.paint[Q]bX=false elseif Q=="\30"then bW=true elseif Q=="\31"then bX=true elseif Q=="\n"then bG,bV,bW,bX,bY,bZ=1,bV+1 else if bV>=bS and bG>=bR and(not bT or bG=bU+bS then break end;local Q=bQ:sub(w,w)if Q=="\9"then w=w+1;bY=j.paint[bQ:sub(w,w)]elseif Q=="\13"then w=w+1;bZ=j.paint[bQ:sub(w,w)]elseif Q=="\n"then bG,bV,bY,bZ=1,bV+1 elseif Q=="["then local b_=bQ:sub(w):find("%]")local c0=tonumber(bQ:sub(w+1,w+b_-2))w=w+b_;local c1=bQ:sub(w,w)if not(c1==" "and not(bY and bZ))then for aV=0,c0-1 do if bV>=bS and bG+aV>=bR then if not bT or bG+aV0 then if ca<4 and not(cb=="[")then c8[#c8+1]=cb:rep(ca)else c8[#c8+1]="["c8[#c8+1]=ca;c8[#c8+1]="]"c8[#c8+1]=cb end;ca=0;cb=nil end end;for a6=a6,b1 and a6+b1-1 or c7 do c8={}ca,cb,bI,bH=0;for a5=a5,b0 and a5+b0-1 or c6 do local bu=c2 and not self.frame:is_pixel_custom(a5,a6)and{char=" "}or self.frame:get_pixel(a5,a6)if bu.background~=bI then cc()c8[#c8+1]="\9"c8[#c8+1]=j.colors[bu.background]or" "bI=bu.background end;if bu.foreground~=bH then cc()c8[#c8+1]="\13"c8[#c8+1]=j.colors[bu.foreground]or" "bH=bu.foreground end;local Q=(bu.char=="\13"or bu.char=="\9")and" "or bu.char;if Q~=cb then cc()ca=1;cb=Q else ca=ca+1 end end;if not(cb==" "and not(bH and bI))then cc()end;c3[#c3+1]=table.concat(c8)end;return table.concat(c3,"\n")end,line=function(self,bh,bi,bj,bk,aX)if not aX then return end;if math.abs(bk-bi)bj then bf.lineLow(self,bj,bk,bh,bi,aX)else bf.lineLow(self,bh,bi,bj,bk,aX)end else if bi>bk then bf.lineHigh(self,bj,bk,bh,bi,aX)else bf.lineHigh(self,bh,bi,bj,bk,aX)end end end,circle=function(self,cd,ce,cf,aX,bN)if not aX then return end;local cg=cf*cf;if bN then self.buffer:set_pixel(cd,ce+cf," ",aX,aX)self.buffer:set_pixel(cd,ce-cf," ",aX,aX)self.buffer:set_pixel(cd+cf,ce," ",aX,aX)self.buffer:set_pixel(cd-cf,ce," ",aX,aX)else self:line(cd,ce+cf,cd,ce-cf,aX)self:line(cd+cf,ce,cd-cf,ce,aX)end;local a5=1;local a6=math.floor(math.sqrt(cg-1)+0.5)while a50)then return false end;for ck,d in next,keys do if not self:is_key_pressed(false,d)then return false end end;if cj then self:remove_keys(table.unpack(keys))end;return true end,add_key=function(self,d)self.pressed_keys[d]=true end,remove_key=function(self,d)self.pressed_keys[d]=nil end,remove_keys=function(self,...)local keys={...}for ck,d in next,keys do self:remove_key(d)end end,manage_event=function(self,formatted_event)if formatted_event.name==b.KEY then self:add_key(formatted_event.key)elseif formatted_event.name==b.KEYUP then self:remove_key(formatted_event.key)end end}local cl={}local cm={}cl={Label={_type="Label",new=function(a5,a6,bF,ba,bb)local cn={draw_priority=b.LOW_PRIORITY,focussed=false,hidden=false,text_alignment=b.ALIGN_LEFT,text=bF,pos=h.Vector2.new(a5,a6),colors={foreground=ba,background=bb},callbacks={onDraw=function()end}}setmetatable(cn,cl.Label)return cn end,draw=function(self,delta_time)if self.hidden then return end;if self.callbacks.onDraw(self,delta_time)then return end;local R=g.split_by_char(self.text,"\n")if self.text_alignment==b.ALIGN_LEFT then for d,co in next,R do bv:write(self.pos.x,self.pos.y+d-1,co,self.colors.foreground,self.colors.background)end elseif self.text_alignment==b.ALIGN_CENTER then for d,co in next,R do bv:write(self.pos.x-#co/2+1,self.pos.y+d-1,co,self.colors.foreground,self.colors.background)end elseif self.text_alignment==b.ALIGN_RIGHT then for d,co in next,R do bv:write(self.pos.x-#co+1,self.pos.y+d-1,co,self.colors.foreground,self.colors.background)end end end},Button={_type="Button",new=function(a5,a6,b0,b1,bF,ba,cp,cq,cr)local cs={draw_priority=b.LOW_PRIORITY,focussed=false,hidden=false,hoverable=cr and true or false,active=false,hovered=false,shortcut_once=true,shortcut={},text_alignment=b.ALIGN_CENTER,text=bF,pos=h.Vector2.new(a5,a6),size=h.Vector2.new(b0,b1),border=false,hold=false,timed={enabled=false,clock=cm.Clock.new(0.5)},colors={foreground=ba,hover_background=cr,active_background=cp,unactive_background=cq,border_color=colors.white},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end,onTimeout=function()end,onHover=function()end,onRelease=function()end}}cs.timed.clock.binded_button=cs;cs.timed.clock.oneshot=true;cs.timed.clock:stop()cs.timed.clock:set_callback(b.ONCLOCK,function(self,formatted_event)self.binded_button.active=false;self.binded_button.callbacks.onPress(self.binded_button,formatted_event)self.binded_button.callbacks.onTimeout(self.binded_button,formatted_event)end)setmetatable(cs,cl.Button)return cs end,draw=function(self,delta_time)if self.hidden then return end;if self.callbacks.onDraw(self,delta_time)then return end;if self.active then bv:rectangle(self.pos.x,self.pos.y,self.size.x,self.size.y,self.colors.active_background,self.border,self.colors.border_color)elseif self.hovered then bv:rectangle(self.pos.x,self.pos.y,self.size.x,self.size.y,self.colors.hover_background,self.border,self.colors.border_color)else bv:rectangle(self.pos.x,self.pos.y,self.size.x,self.size.y,self.colors.unactive_background,self.border,self.colors.border_color)end;local R=g.split_by_char(self.text,"\n")local ct=(self.size.y-#R)/2+self.pos.y;for bV=0,#R-1 do local co=R[bV+1]local cu;if self.text_alignment==b.ALIGN_LEFT then cu=self.pos.x elseif self.text_alignment==b.ALIGN_CENTER then cu=(self.size.x-#co)/2+self.pos.x elseif self.text_alignment==b.ALIGN_RIGHT then cu=self.pos.x+self.size.x-#co end;bv:write(cu,ct+bV,co,self.colors.foreground)end end,event=function(self,formatted_event)if self.hidden then return false end;if formatted_event.name==b.TOUCH then if k.in_area(formatted_event.x,formatted_event.y,self.pos.x,self.pos.y,self.size.x,self.size.y)then self:press(formatted_event)return true else self.callbacks.onFailedPress(self,formatted_event)end elseif formatted_event.name==b.KEY then if ch:are_keys_pressed(self.shortcut_once,table.unpack(self.shortcut))then self:press(formatted_event)end elseif self.hoverable then if formatted_event.name==b.MOUSEMOVE or formatted_event.name==b.MOUSEDRAG then if not formatted_event.x or not formatted_event.y then if self.hovered then self.hovered=false;self.callbacks.onHover(self,formatted_event)end elseif k.in_area(formatted_event.x,formatted_event.y,self.pos.x,self.pos.y,self.size.x,self.size.y)then if not self.hovered then self.hovered=true;self.callbacks.onHover(self,formatted_event)end;return true elseif self.hovered then self.hovered=false;self.callbacks.onHover(self,formatted_event)end elseif self.hovered and formatted_event.name==b.DELETED then self.hovered=false;self.callbacks.onHover(self,formatted_event)end end;if self.hold then local o=formatted_event.name==b.DELETED and formatted_event.deleted or formatted_event;if o.name==b.MOUSEUP then if self.active then self.active=false;if k.in_area(o.x,o.y,self.pos.x,self.pos.y,self.size.x,self.size.y)then self.callbacks.onRelease(self,formatted_event)end end end elseif self.timed.enabled then self.timed.clock:event(formatted_event)end end,press=function(self,formatted_event)if self.hold then if not self.active then self.active=true;self.callbacks.onPress(self,formatted_event)end elseif self.timed.enabled then self.timed.clock:start()if not self.active then self.active=true;self.callbacks.onPress(self,formatted_event)end else self.active=not self.active;self.callbacks.onPress(self,formatted_event)end end},Progressbar={_type="Progressbar",new=function(a5,a6,b0,b1,aP,al,am,ba,cv,cw)local cx={draw_priority=b.LOW_PRIORITY,focussed=false,hidden=false,active=false,pos=h.Vector2.new(a5,a6),size=h.Vector2.new(b0,b1),value={max=am,min=al,current=aP,draw_percentage=true,percentage_precision=2},colors={foreground=ba,filled_background=cv,unfilled_background=cw},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end}}setmetatable(cx,cl.Progressbar)return cx end,draw=function(self,delta_time)if self.hidden then return end;if self.callbacks.onDraw(self,delta_time)then return end;local cy=h.map(self.value.current,self.value.min,self.value.max,0,1,true)local cz=self.size.x*cy;bv:rectangle(self.pos.x,self.pos.y,cz,self.size.y,self.colors.filled_background)bv:rectangle(self.pos.x+cz,self.pos.y,self.size.x-cz,self.size.y,self.colors.unfilled_background)if self.value.draw_percentage then local cA=table.concat({g.format_number(cy*100,self.value.percentage_precision),"%"})local cB=(self.size.x-#cA)/2+self.pos.x;local ct=(self.size.y-1)/2+self.pos.y;bv:write(cB,ct,cA,self.colors.foreground)end end,event=function(self,formatted_event)if self.hidden then return false end;if formatted_event.name==b.TOUCH then if k.in_area(formatted_event.x,formatted_event.y,self.pos.x,self.pos.y,self.size.x,self.size.y)then self.callbacks.onPress(self,formatted_event)end end end,set=function(self,H)local cC=h.constrain(H,self.value.min,self.value.max)self.value.current=cC end},Memo={_type="Memo",new=function(a5,a6,b0,b1,ba,bb)local cD={draw_priority=b.LOW_PRIORITY,focussed=false,hidden=false,pos=h.Vector2.new(a5,a6),size=h.Vector2.new(b0,b1),editable=true,tab_spaces=" ",rich_text={},lines={},first_visible_line=1,first_visible_char=1,cursor={visible=false,text=" ",blink=cm.Clock.new(0.5),pos=h.Vector2.new(1,1)},limits=h.Vector2.new(0,0),whitelist={},blacklist={},border=false,colors={foreground=ba,background=bb,cursor=colors.white,cursor_text=colors.black,border_color=colors.white},callbacks={onDraw=function()end,onEvent=function()end,onPress=function()end,onFailedPress=function()end,onFocus=function()end,onKey=function()end,onChar=function()end,onMouseScroll=function()end,onCursorChange=function()end,onWrite=function()end,onPaste=function()end}}cD.cursor.blink.binded_cursor=cD.cursor;cD.cursor.blink:set_callback(b.ONCLOCK,function(self,formatted_event)self.binded_cursor.visible=not self.binded_cursor.visible end)setmetatable(cD,cl.Memo)return cD end,draw=function(self,delta_time)if self.hidden then return end;if self.callbacks.onDraw(self,delta_time)then return end;bv:rectangle(self.pos.x,self.pos.y,self.size.x,self.size.y,self.colors.background,self.border,self.colors.border_color)local cE=self.pos.x;local cF=self.pos.y;local cG=self.size.x;local cH=self.size.y;if self.border then cE=cE+1;cF=cF+1;cG=cG-2;cH=cH-2 end;local cI=self.cursor.pos.x-self.first_visible_char;local cJ=self.cursor.pos.y-self.first_visible_line;for a6=1,cH do local cK=a6+self.first_visible_line-1;local cL=self.rich_text[cK]or{}local co=self.lines[cK]or""local cM=self.first_visible_char;local cN=self.first_visible_char+cG-1;local cO=co:sub(cM,cN)local cP=cF+a6-1;if cL.background then if type(cL.background)=="string"then local bY=cL.background:sub(cM,cN)bY=#bY>0 and bY or cL.background:sub(#cL.background)bv:blit(cE,cP,string.rep(" ",cG),nil,bY)else bv:rectangle(cE,cP,cG,1,cL.background)end end;if cL.foreground then if type(cL.foreground)=="string"then local bZ=cL.foreground:sub(cM,cN)bZ=#bZ>0 and bZ or cL.foreground:sub(#cL.foreground)bv:blit(cE,cP,cO,bZ)else bv:write(cE,cP,cO,cL.foreground)end else bv:write(cE,cP,cO,self.colors.foreground)end end;if self.cursor.visible and cI>=0 and cI=0 and cJ1 then local cQ=self.lines[self.cursor.pos.y-1]local cR=self.lines[self.cursor.pos.y]self.lines[self.cursor.pos.y-1]=""table.remove(self.lines,self.cursor.pos.y)local bA=self.cursor.pos.x;self:set_cursor(1,self.cursor.pos.y-1)self:write(table.concat({cR,"\n",cQ}))self:set_cursor(bA,self.cursor.pos.y-1)end;return true elseif ch:are_keys_pressed(false,b.KEY_LEFTALT,b.KEY_DOWN)then local cR=self.lines[self.cursor.pos.y]local cS=self.lines[self.cursor.pos.y+1]if not cS then return false end;self.lines[self.cursor.pos.y]=""table.remove(self.lines,self.cursor.pos.y+1)local bA=self.cursor.pos.x;self:set_cursor(1,self.cursor.pos.y)self:write(table.concat({cS,"\n",cR}))self:set_cursor(bA,self.cursor.pos.y)return true elseif formatted_event.key==b.KEY_UP then self:set_cursor(self.cursor.pos.x,self.cursor.pos.y-1)return true elseif formatted_event.key==b.KEY_DOWN then self:set_cursor(self.cursor.pos.x,self.cursor.pos.y+1)return true elseif formatted_event.key==b.KEY_RIGHT then local co=self.lines[self.cursor.pos.y]if self.lines[self.cursor.pos.y+1]and self.cursor.pos.x>=#co+1 then self:set_cursor(1,self.cursor.pos.y+1)else self:set_cursor(self.cursor.pos.x+1,self.cursor.pos.y)end;return true elseif formatted_event.key==b.KEY_LEFT then if self.cursor.pos.x<=1 and self.cursor.pos.y>1 then local cT=self.lines[self.cursor.pos.y-1]self:set_cursor(#cT+1,self.cursor.pos.y-1)else self:set_cursor(self.cursor.pos.x-1,self.cursor.pos.y)end;return true elseif formatted_event.key==b.KEY_BACKSPACE then local co=self.lines[self.cursor.pos.y]if self.cursor.pos.x<=1 then if self.cursor.pos.y>1 then table.remove(self.lines,self.cursor.pos.y)local cU=#self.lines[self.cursor.pos.y-1]+1;local cV=self.cursor.pos.y-1;self:set_cursor(cU,cV)self:write(co)self:set_cursor(cU,cV)end else local aA=table.concat({co:sub(1,self.cursor.pos.x-2),co:sub(self.cursor.pos.x)})self.lines[self.cursor.pos.y]=aA;self:set_cursor(self.cursor.pos.x-1,self.cursor.pos.y)self.callbacks.onWrite(self,aA,{aA})end;return true elseif formatted_event.key==b.KEY_DELETE then local co=self.lines[self.cursor.pos.y]local cW=co:sub(self.cursor.pos.x)if#cW>0 then local aA=table.concat({co:sub(1,self.cursor.pos.x-1),co:sub(self.cursor.pos.x+1)})self.lines[self.cursor.pos.y]=aA;self.callbacks.onWrite(self,aA,{aA})else local cS=self.lines[self.cursor.pos.y+1]if cS then local cU=self.cursor.pos.x;local cV=self.cursor.pos.y;table.remove(self.lines,self.cursor.pos.y+1)self:write(cS)self:set_cursor(cU,cV)end end;return true elseif formatted_event.key==b.KEY_ENTER then local cX=self.lines[self.cursor.pos.y]:sub(0,self.cursor.pos.x-1)local cY=cX:gsub("(%s*).*","%1")self:write(table.concat({"\n",cY}))return true elseif formatted_event.key==b.KEY_END then self:set_cursor(#self.lines[self.cursor.pos.y]+1,self.cursor.pos.y)return true elseif formatted_event.key==b.KEY_HOME then local cX=self.lines[self.cursor.pos.y]:sub(0,self.cursor.pos.x-1)local cY=cX:gsub("(%s*).*","%1")self:set_cursor(#cY+1,self.cursor.pos.y)return true elseif ch:are_keys_pressed(false,b.KEY_LEFTSHIFT,b.KEY_TAB)then local cZ=self.lines[self.cursor.pos.y]local cY=cZ:gsub("^(%s*).*$","%1")local c_=math.min(#self.tab_spaces,#cY)local aA=cZ:sub(c_+1)self.lines[self.cursor.pos.y]=aA;self:set_cursor(self.cursor.pos.x-c_,self.cursor.pos.y)self.callbacks.onWrite(self,aA,{aA})return true elseif formatted_event.key==b.KEY_TAB then local bA=self.cursor.pos.x;local d0=#self.lines[self.cursor.pos.y]self:set_cursor(1,self.cursor.pos.y)self:write(self.tab_spaces)local d1=#self.lines[self.cursor.pos.y]-d0;self:set_cursor(bA+d1,self.cursor.pos.y)return true end elseif formatted_event.name==b.MOUSESCROLL then if self.callbacks.onMouseScroll(self,formatted_event)then return true end;self.first_visible_line=h.constrain(self.first_visible_line+formatted_event.direction,1,#self.lines)return true end end end,focus=function(self,d2,formatted_event)if d2 then self.focussed=true;self.callbacks.onFocus(self,formatted_event)else self.focussed=false;self.cursor.visible=false;self.callbacks.onFocus(self,formatted_event)end end,set_cursor=function(self,cU,cV,d3)if not self.lines[1]then self.lines[1]=""end;if self.limits.y>0 then cV=h.constrain(cV,1,self.limits.y)end;if d3 then for a6=#self.lines+1,cV do if not self.lines[a6]then self.lines[a6]=""end end else cV=h.constrain(cV,1,#self.lines)end;cU=h.constrain(cU,1,#self.lines[cV]+1)local cI=cU-self.first_visible_char;local cJ=cV-self.first_visible_line;local cG=self.size.x;local cH=self.size.y;if self.border then cG=cG-2;cH=cH-2 end;if cI>=cG then self.first_visible_char=self.first_visible_char+cI-cG+1 elseif cI<0 then self.first_visible_char=self.first_visible_char+cI end;if cJ>=cH then self.first_visible_line=self.first_visible_line+cJ-cH+1 elseif cJ<0 then self.first_visible_line=self.first_visible_line+cJ end;self.callbacks.onCursorChange(self,cU,cV)self.cursor.pos=h.Vector2.new(cU,cV)end,write=function(self,...)local bF=table.concat({...})local R=g.split_by_char(bF,"\n")self:set_cursor(self.cursor.pos.x,self.cursor.pos.y,true)if#self.whitelist>0 then local M=table.concat({"[^",g.escape_magic_characters(table.concat(self.whitelist)),"]"})for d,co in next,R do R[d]=co:gsub(M,"")end elseif#self.blacklist>0 then local M=table.concat({"[",g.escape_magic_characters(table.concat(self.blacklist)),"]"})for d,co in next,R do R[d]=co:gsub(M,"")end end;if self.limits.y>0 then for a6=1,#self.lines+#R-1-self.limits.y do table.remove(R)end;if#R==0 then return end end;if#R>1 then for d4,co in next,R do if d4==1 then local d5=self.lines[self.cursor.pos.y]local d6=d5:sub(1,self.cursor.pos.x-1)local cW=d5:sub(self.cursor.pos.x)local d7=R[#R]if self.limits.x>0 then co=co:sub(1,self.limits.x-#d6)d7=d7:sub(1,self.limits.x-#cW)end;self.lines[self.cursor.pos.y]=table.concat({d6,co})table.insert(self.lines,self.cursor.pos.y+1,table.concat({d7,cW}))self:set_cursor(#d7+1,self.cursor.pos.y+1)elseif d4==#R then break else if self.limits.x>0 then co=co:sub(1,self.limits.x)end;table.insert(self.lines,self.cursor.pos.y,co)self:set_cursor(self.cursor.pos.x,self.cursor.pos.y+1)end end else local d5=self.lines[self.cursor.pos.y]local d6=d5:sub(1,self.cursor.pos.x-1)local cW=d5:sub(self.cursor.pos.x)if self.limits.x>0 then R[1]=R[1]:sub(1,self.limits.x-(#d6+#cW))end;self.lines[self.cursor.pos.y]=table.concat({d6,R[1],cW})self:set_cursor(self.cursor.pos.x+#R[1],self.cursor.pos.y)end;self.callbacks.onWrite(self,bF,R)end,print=function(self,...)local bF=table.concat({...})local aA=#self.lines>0 and"\n"or""self:write(table.concat({aA,bF}))end,clear=function(self)self.lines={}self.callbacks.onCursorChange(self,1,1)self.cursor.pos=h.Vector2.new(1,1)end},Window={_type="Window",new=function(a5,a6,b0,b1,bb,d8)local d9={draw_priority=b.HIGH_PRIORITY,focussed=false,hidden=false,pos=h.Vector2.new(a5,a6),size=h.Vector2.new(b0,b1),can_drag=false,border=false,dragging={enabled=true,from=h.Vector2.new(1,1)},resizing={enabled=true,corner=h.Vector2.new(-1,1),enabled_directions={[-1]={[1]=true,[0]=true,[-1]=true},[0]={[1]=true,[0]=false,[-1]=true},[1]={[1]=true,[0]=true,[-1]=true}},pinned={x=false,y=false},min_size=h.Vector2.new(b0,b1),max_size=h.Vector2.new(b0,b1)*2},shadow={enabled=d8,offset=h.Vector2.new(1,1)},elements={},colors={background=bb,shadow=colors.black,border_color=colors.white},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end,onEvent=function()end,onFocus=function()end,onDrag=function()end,onResize=function()end}}setmetatable(d9,cl.Window)return d9 end,draw=function(self,delta_time)if self.hidden then return end;if self.callbacks.onDraw(self,delta_time)then return end;if self.shadow.enabled then bv:rectangle(self.pos.x+self.shadow.offset.x,self.pos.y+self.shadow.offset.y,self.size.x,self.size.y,self.colors.shadow)end;bv:rectangle(self.pos.x,self.pos.y,self.size.x,self.size.y,self.colors.background,self.border,self.colors.border_color)self:draw_elements(delta_time)end,event=function(self,formatted_event)if self.hidden then return false end;if self.callbacks.onEvent(self,formatted_event)then return true end;local da=self:event_elements(formatted_event)if not da then if formatted_event.name==b.TOUCH then if k.in_area(formatted_event.x,formatted_event.y,self.pos.x,self.pos.y,self.size.x,self.size.y)then self.can_drag=false;if self.resizing.enabled then local db=true;local dc=formatted_event.y==self.pos.y+self.size.y-1;local dd=formatted_event.y==self.pos.y;if formatted_event.x==self.pos.x+self.size.x-1 then if self.resizing.enabled_directions[1][1]and dc then self.resizing.corner=self.pos.ONE:duplicate()self.resizing.pinned.x=false;self.resizing.pinned.y=false elseif self.resizing.enabled_directions[1][-1]and dd then self.resizing.corner=self.pos.UP+self.pos.RIGHT;self.resizing.pinned.x=false;self.resizing.pinned.y=false elseif self.resizing.enabled_directions[1][0]and not(dc or dd)then self.resizing.corner=self.pos.UP+self.pos.RIGHT;self.resizing.pinned.x=false;self.resizing.pinned.y=true else db=false end elseif formatted_event.x==self.pos.x then if self.resizing.enabled_directions[-1][1]and dc then self.resizing.corner=self.pos.DOWN+self.pos.LEFT;self.resizing.pinned.x=false;self.resizing.pinned.y=false elseif self.resizing.enabled_directions[-1][-1]and dd then self.resizing.corner=self.pos.ONE*-1;self.resizing.pinned.x=false;self.resizing.pinned.y=false elseif self.resizing.enabled_directions[-1][0]and not(dc or dd)then self.resizing.corner=self.pos.ONE*-1;self.resizing.pinned.x=false;self.resizing.pinned.y=true else db=false end elseif self.resizing.enabled_directions[0][1]and dc then self.resizing.corner=self.pos.DOWN+self.pos.RIGHT;self.resizing.pinned.x=true;self.resizing.pinned.y=false elseif self.resizing.enabled_directions[0][-1]and dd then self.resizing.corner=self.pos.UP+self.pos.RIGHT;self.resizing.pinned.x=true;self.resizing.pinned.y=false else db=false end;if not db then self.resizing.corner=self.pos.ZERO:duplicate()self.dragging.from=h.Vector2.new(formatted_event.x,formatted_event.y)self.can_drag=self.dragging.enabled and true end else self.dragging.from=h.Vector2.new(formatted_event.x,formatted_event.y)self.can_drag=self.dragging.enabled and true end;self.focussed=true;self.callbacks.onPress(self,formatted_event)self.callbacks.onFocus(self,formatted_event)return true else self.focussed=false;self.callbacks.onFailedPress(self,formatted_event)self.callbacks.onFocus(self,formatted_event)end elseif formatted_event.name==b.MOUSEDRAG and self.focussed then if self.can_drag then self:drag(formatted_event.x,formatted_event.y)else self:resize(formatted_event.x,formatted_event.y,self.resizing.pinned.x,self.resizing.pinned.y)end;return true elseif self.focussed and formatted_event.name==b.MOUSEMOVE and formatted_event.x and formatted_event.y then if k.in_area(formatted_event.x,formatted_event.y,self.pos.x,self.pos.y,self.size.x,self.size.y)then return true end elseif formatted_event.name==b.DELETED then self.focussed=false;self.callbacks.onFocus(self,formatted_event)end else self.focussed=false;self.callbacks.onFocus(self,formatted_event)end;return da end,drag=function(self,a5,a6)if self.dragging.enabled then local de=self.pos:duplicate()self.pos=self.pos+h.Vector2.new(a5-self.dragging.from.x,a6-self.dragging.from.y)self.dragging.from=h.Vector2.new(a5,a6)self.callbacks.onDrag(self,de.x,de.y)end end,resize=function(self,a5,a6,df,dg)if self.resizing.enabled and self.resizing.corner~=self.pos.ZERO then local function dh()self.size.x=h.constrain(self.size.x,self.resizing.min_size.x,self.resizing.max_size.x)self.size.y=h.constrain(self.size.y,self.resizing.min_size.y,self.resizing.max_size.y)end;local di=h.Vector2.new(a5,a6)local de=self.pos:duplicate()local dj=self.size:duplicate()if self.resizing.corner==self.pos.ONE then self.size.x=di.x-self.pos.x+1;self.size.y=di.y-self.pos.y+1;dh()elseif self.resizing.corner==self.pos.ONE*-1 then self.size.x=self.size.x+self.pos.x-di.x;self.size.y=self.size.y+self.pos.y-di.y;dh()local dk=dj-self.size;self.pos=self.pos+dk elseif self.resizing.corner==self.pos.UP+self.pos.RIGHT then self.size.x=di.x-self.pos.x+1;self.size.y=self.size.y+self.pos.y-di.y;dh()local dl=dj.y-self.size.y;self.pos.y=self.pos.y+dl elseif self.resizing.corner==self.pos.DOWN+self.pos.LEFT then self.size.x=self.size.x+self.pos.x-di.x;self.size.y=di.y-self.pos.y+1;dh()local d1=dj.x-self.size.x;self.pos.x=self.pos.x+d1 end;if df then self.size.x=dj.x;self.pos.x=de.x end;if dg then self.size.y=dj.y;self.pos.y=de.y end;self.callbacks.onResize(self,de.x,de.y,dj.x,dj.y)end end,set_elements=function(self,dm)self.elements={}for d,dn in next,dm do table.insert(self.elements,1,dn)end end,draw_elements=function(self,delta_time)for d=1,#self.elements do local dn=self.elements[d]if dn.draw then dn.pos=dn.pos+self.pos-self.pos.ONE;dn:draw(delta_time)dn.pos=dn.pos-self.pos+self.pos.ONE end end end,event_elements=function(self,formatted_event)if formatted_event.name==b.DELETED then if formatted_event.deleted.x and formatted_event.deleted.y then local dp=k.format_event(formatted_event.deleted.raw)dp.x,dp.y=dp.x-self.pos.x+1,dp.y-self.pos.y+1;formatted_event=k.delete_event(dp)end else if formatted_event.x and formatted_event.y then formatted_event=k.format_event(formatted_event.raw)formatted_event.x,formatted_event.y=formatted_event.x-self.pos.x+1,formatted_event.y-self.pos.y+1 end end;for w=#self.elements,1,-1 do local dn=self.elements[w]if dn.event and dn:event(formatted_event)and formatted_event.name~=b.DELETED then formatted_event=k.delete_event(formatted_event)end end;return formatted_event.name==b.DELETED end},Canvas={_type="Canvas",new=function(a5,a6,b0,b1)local dq={draw_priority=b.LOW_PRIORITY,hidden=false,pos=h.Vector2.new(a5,a6),size=h.Vector2.new(b0,b1),transparent=false,buffer={pixels={},background={char=" ",foreground=colors.black,background=colors.black,inverted=false}},callbacks={onDraw=function()end}}setmetatable(dq.buffer,bv.buffer)setmetatable(dq,cl.Canvas)return dq end,draw=function(self)if self.hidden then return end;if self.callbacks.onDraw(self,delta_time)then return end;self:cast(bv)end,cast=function(self,a8)if self.transparent then for a6=1,self.size.y do if self.buffer.pixels[a6]then for a5=1,self.size.x do local bu=self.buffer.pixels[a6][a5]if bu then if bu.inverted then a8.buffer:set_pixel(self.pos.x+a5-1,self.pos.y+a6-1,bu.char,bu.background,bu.foreground,true)else a8.buffer:set_pixel(self.pos.x+a5-1,self.pos.y+a6-1,bu.char,bu.foreground,bu.background)end end end end end else for a6=1,self.size.y do for a5=1,self.size.x do local bu=self.buffer:get_pixel(a5,a6)if bu.inverted then a8.buffer:set_pixel(self.pos.x+a5-1,self.pos.y+a6-1,bu.char,bu.background,bu.foreground,true)else a8.buffer:set_pixel(self.pos.x+a5-1,self.pos.y+a6-1,bu.char,bu.foreground,bu.background)end end end end end,to_nfp=function(self,...)return bv.frame_to_nfp({frame=self.buffer},...)end,to_nft=function(self,...)return bv.frame_to_nft({frame=self.buffer},...)end,to_yai=function(self,...)return bv.frame_to_yai({frame=self.buffer},...)end}}cl.Label.__index=cl.Label;cl.Button.__index=cl.Button;cl.Progressbar.__index=cl.Progressbar;cl.Memo.__index=cl.Memo;cl.Window.__index=cl.Window;for d,dr in next,bv do if type(dr)=="function"and not cl.Canvas[d]and not d:find("set_")and not d:find("frame")then cl.Canvas[d]=dr end end;cl.Canvas.__index=cl.Canvas;cm={Clock={_type="Clock",new=function(ds)local dt={enabled=true,oneshot=false,clock=os.clock(),interval=ds,callbacks={onClock=function()end}}setmetatable(dt,cm.Clock)return dt end,event=function(self,formatted_event)if not self.enabled then self:reset_timer()return end;local du=os.clock()if du>=self.clock+self.interval then local delta_time=du-self.clock;self:reset_timer()self.callbacks.onClock(self,formatted_event,delta_time)if self.oneshot then self:stop()end end end,start=function(self)self:reset_timer()self.enabled=true end,stop=function(self)self.enabled=false end,reset_timer=function(self)self.clock=os.clock()end},WSS={_type="WSS",new=function(dv)local dw={draw_priority=b.LOW_PRIORITY,enabled=true,buffer={},events_whitelist={[b.TOUCH]=true,[b.KEY]=true,[b.KEYUP]=true,[b.CHAR]=true,[b.MOUSEDRAG]=true,[b.MOUSESCROLL]=true,[b.MOUSEUP]=true},close_on_host_disconnect=true,side=b.NONE,mode=b.NONE,host_id=b.NONE,users={},protocol="YAGUI-"..a.ver.."_WSS",broadcast_clock=cm.Clock.new(dv or 4),callbacks={onDraw=function()end,onEvent=function()end,onConnect=function()end,onDisconnect=function()end}}dw.broadcast_clock.WSS=dw;dw.broadcast_clock:set_callback(b.ONCLOCK,function(self,formatted_event)rednet.broadcast(bv.frame,self.WSS.protocol)end)setmetatable(dw,cm.WSS)return dw end,draw=function(self,delta_time)if not self.enabled then return false end;if self.callbacks.onDraw(self,delta_time)then return end;if self.mode==b.USER then if self.buffer and self.buffer.background and self.buffer.pixels then bv.buffer.background=self.buffer.background;bv.buffer.pixels=self.buffer.pixels end end end,event=function(self,formatted_event)if not self.enabled then return false end;if self.callbacks.onEvent(self,formatted_event)then return true end;local dx=false;if formatted_event.name==b.REDNET then if formatted_event.protocol==self.protocol then local b4=formatted_event.message;if self.mode==b.HOST then if b4==b.CONNECTION_REQUEST then rednet.send(formatted_event.from,b.OK,self.protocol)self.users[formatted_event.from]=true;dx=true;self.callbacks.onConnect(self,formatted_event)elseif b4==b.DISCONNECTED then self.users[formatted_event.from]=nil;dx=true;self.callbacks.onDisconnect(self,formatted_event)elseif type(b4)=="table"and self.events_whitelist[b4.name]and self.users[formatted_event.from]then if b4.raw then os.queueEvent(table.unpack(b4.raw))end;dx=true end elseif self.mode==b.USER then if formatted_event.from==self.host_id then if b4==b.DISCONNECTED then if self.close_on_host_disconnect then self:close()end;dx=true;self.callbacks.onDisconnect(self,formatted_event)elseif type(b4)=="table"then self.buffer=b4;dx=true end end end end end;if self.mode==b.USER then if formatted_event.name==b.TOUCH then dx=true end;if self.events_whitelist[formatted_event.name]then rednet.send(self.host_id,formatted_event,self.protocol)dx=true end elseif self.mode==b.HOST then self.broadcast_clock:event(formatted_event)end;return dx end,use_side=function(self,dy)self.side=dy end,connect=function(self,dz,dA,dB)dA=dA or 2;dB=dB or 10;rednet.open(self.side)self.host_id=dz;self.mode=b.USER;rednet.send(self.host_id,b.CONNECTION_REQUEST,self.protocol)local dC=0;while true do dC=dC+1;local dD={rednet.receive(self.protocol,dA)}if dD[1]==dz and dD[2]==b.OK and dD[3]==self.protocol then return b.OK elseif dC>=dB then local dE=string.format("Connection timed out on attempt %d after %d ms",dC,dA*1000)if#dD>0 then dE=string.format("Connection timed out on attempt %d: invalid response (The traffic on the network may be high, try to increase max attempts)",dC,dA*1000)end;WSS:close()error(dE,2)end end;self.callbacks.onConnect(self,dz)end,host=function(self)rednet.open(self.side)self.host_id=os.getComputerID()self.mode=b.HOST end,close=function(self)if rednet.isOpen()then if self.mode==b.HOST then rednet.broadcast(b.DISCONNECTED,self.protocol)elseif self.mode==b.USER then rednet.send(self.host_id,b.DISCONNECTED,self.protocol)end;rednet.close(self.side)end;self.host_id=b.NONE;self.mode=b.NONE end},FT={_type="FT",new=function(dF)local dG={enabled=true,computer_whitelist={},side=b.NONE,mode=b.ALL,password=dF or b.NONE,protocol="YAGUI-"..a.ver.."_FT",save_dir="/FT",callbacks={onEvent=function()end,onConnect=function()end,onSend=function()end,onReceive=function()end}}setmetatable(dG,cm.FT)return dG end,event=function(self,formatted_event)if not self.enabled then return false end;if self.callbacks.onEvent(self,formatted_event)then return true end;if formatted_event.name==b.REDNET and formatted_event.protocol==self.protocol then if self.mode==b.ALL or self.mode==b.RECEIVE then local dz=formatted_event.from;if self.computer_whitelist[dz]or self.callbacks.onConnect(self,formatted_event)then local b4=formatted_event.message;if type(b4)=="table"and b4.name and b4.content then if b4.psw==self.password then local b5=fs.getName(tostring(b4.name))local _=fs.combine(self.save_dir,b5)if fs.exists(_)then rednet.send(dz,b.NO,self.protocol)else local dH=tostring(b4.content)if self.callbacks.onReceive(self,formatted_event,dz,b5,_,dH)then return true end;local dI=fs.open(_,"w")if dI then dI.write(dH)dI.close()rednet.send(dz,b.OK,self.protocol)else rednet.send(dz,b.ERROR,self.protocol)end end else rednet.send(dz,b.NO,self.protocol)end else rednet.send(dz,b.ERROR,self.protocol)end else rednet.send(dz,b.NO,self.protocol)end end end end,send=function(self,dJ,dK,dL,dM)if self.mode==b.ALL or self.mode==b.SEND then dM=dM or fs.getName(dL)dK=dK or b.NONE;local dI=fs.open(dL,"r")local dH=dI.readAll()dI.close()local b4={psw=dK,name=dM,content=dH}if self.callbacks.onSend(self,formatted_event,b4)then return true end;rednet.send(dJ,b4,self.protocol)end end,open=function(self,dy)self.side=dy;rednet.open(dy)end,close=function(self)if rednet.isOpen()then rednet.close(self.side)end end}}cm.Clock.__index=cm.Clock;cm.WSS.__index=cm.WSS;cm.FT.__index=cm.FT;cm.wireless_screen_share=cm.WSS;cm.file_transfer=cm.FT;local dN={}dN={_type="Loop",new=function(dO,dP)local dQ={enabled=false,options={raw_mode=false,stop_on_terminate=true,FPS_target=dO,EPS_target=dP},monitors={terminal=term},threads={queue_event=true,draw={},event={}},elements={high_priority={},low_priority={},loop={}},internal_elements={draw_clock=cm.Clock.new(1/dO)},stats={pos=h.Vector2.new(1,1),show=function(self,dR)self.FPS_label.hidden=not dR;self.EPS_label.hidden=not dR end,update_pos=function(self)self.FPS_label.pos=self.pos;self.EPS_label.pos=self.pos+h.Vector2.DOWN end,Events=0,FPS=0,EPS=0,clock=cm.Clock.new(1),FPS_label=cl.Label.new(1,1,"1 FPS",colors.white),EPS_label=cl.Label.new(1,2,"1 EPS",colors.white)},callbacks={onStart=function()end,onStop=function()end,onDraw=function()end,onEvent=function()end}}dQ.elements.loop={dQ.stats.EPS_label,dQ.stats.FPS_label,dQ.internal_elements.draw_clock}dQ.stats.clock.stats=dQ.stats;dQ.stats.clock:set_callback(b.ONCLOCK,function(self,formatted_event,delta_time)self.stats:update_pos()self.stats.FPS_label.text=table.concat({math.floor(self.stats.FPS+0.5)," FPS"})self.stats.EPS_label.text=table.concat({math.floor(self.stats.EPS+0.5)," EPS"})end)dQ.stats:show(false)dQ.internal_elements.draw_clock.loop=dQ;dQ.internal_elements.draw_clock:set_callback(b.ONCLOCK,function(self,formatted_event,delta_time)self.loop.stats.FPS=1/delta_time;self.loop.stats.EPS=self.loop.stats.Events/delta_time;self.loop.stats.Events=0;self.loop:resume_threads("draw",delta_time)self.loop:draw_elements(delta_time)self.interval=1/self.loop.options.FPS_target end)setmetatable(dQ,dN)return dQ end,set_monitors=function(self,b6)self.monitors=m.get_monitors(b6)end,set_elements=function(self,dm)self.elements.high_priority={}self.elements.low_priority={}for d,H in next,dm do if H.draw_priority==b.HIGH_PRIORITY then table.insert(self.elements.high_priority,1,H)else table.insert(self.elements.low_priority,1,H)end end end,draw_elements=function(self,delta_time)local function dS(ar)for d=1,#ar do local dn=ar[d]if dn.draw then dn:draw(delta_time)end end end;if self.callbacks.onDraw(self,delta_time)then return end;local dT=bv.screens;bv.screens=self.monitors;dS(self.elements.low_priority)dS(self.elements.high_priority)dS(self.elements.loop)bv:draw()bv.screens=dT end,event_elements=function(self,formatted_event)local function b2(ar)for w=#ar,1,-1 do local dn=ar[w]if dn.event then if dn:event(formatted_event)then formatted_event=k.delete_event(formatted_event)end end end end;if formatted_event.name~=b.COROUTINE then self:resume_threads("event",formatted_event)end;if self.callbacks.onEvent(self,formatted_event)then formatted_event=k.delete_event(formatted_event)end;if self.options.stop_on_terminate and formatted_event.name==b.TERMINATE then self:stop()return end;if formatted_event.name==b.TOUCH then local dU=self.monitors[formatted_event.from]and true or false;if dU then if formatted_event.raw[1]=="monitor_touch"then os.queueEvent("mouse_up",1,formatted_event.x,formatted_event.y)end else formatted_event=k.delete_event(formatted_event)end end;b2(self.elements.loop)local dV={}local dW={}for w=#self.elements.high_priority,1,-1 do local dn=self.elements.high_priority[w]if dn:event(formatted_event)then formatted_event=k.delete_event(formatted_event)dV[#dV+1]=dn;dW[#dW+1]=w end end;i.better_remove(self.elements.high_priority,table.unpack(dW))for w=#dV,1,-1 do self.elements.high_priority[#self.elements.high_priority+1]=dV[w]end;b2(self.elements.low_priority)end,resume_threads=function(self,d,...)local dX=self.threads[d]if dX and#dX>0 then local dY={}for w=1,#dX do local dZ=dX[w]if coroutine.status(dZ)=="dead"then dY[#dY+1]=w else local d_={coroutine.resume(dZ,self,...)}if self.threads.queue_event then os.queueEvent("coroutine",dZ,coroutine.status(dZ),table.unpack(d_))end end end;if#dY>0 then i.better_remove(dX,table.unpack(dY))end end end,start=function(self)self.enabled=true;ch:reset()self.stats:update_pos()self.callbacks.onStart(self)while self.enabled do local e0=os.startTimer(1/self.options.EPS_target)local e1;if self.options.raw_mode then e1={os.pullEventRaw()}else e1={os.pullEvent()}end;local formatted_event=k.format_event(e1)ch:manage_event(formatted_event)self:event_elements(formatted_event)self.stats.Events=self.stats.Events+1;os.cancelTimer(e0)end;ch:reset()self.callbacks.onStop(self)end,stop=function(self)self.enabled=false end}dN.__index=dN;local e2={__call=function(self,...)return self.new(...)end}e2.__index=e2;local e3={__call=function(self,...)return self.new(...)end,set_callback=function(self,o,p)if o==b.ONSTART then self.callbacks.onStart=p elseif o==b.ONSTOP then self.callbacks.onStop=p elseif o==b.ONDRAW then self.callbacks.onDraw=p elseif o==b.ONPRESS then self.callbacks.onPress=p elseif o==b.ONFAILEDPRESS then self.callbacks.onFailedPress=p elseif o==b.ONTIMEOUT then self.callbacks.onTimeout=p elseif o==b.ONCLOCK then self.callbacks.onClock=p elseif o==b.ONEVENT then self.callbacks.onEvent=p elseif o==b.ONFOCUS then self.callbacks.onFocus=p elseif o==b.ONKEY then self.callbacks.onKey=p elseif o==b.ONCHAR then self.callbacks.onChar=p elseif o==b.ONMOUSESCROLL then self.callbacks.onMouseScroll=p elseif o==b.ONCURSORCHANGE then self.callbacks.onCursorChange=p elseif o==b.ONWRITE then self.callbacks.onWrite=p elseif o==b.ONCONNECT then self.callbacks.onConnect=p elseif o==b.ONDISCONNECT then self.callbacks.onDisconnect=p elseif o==b.ONSEND then self.callbacks.onSend=p elseif o==b.ONRECEIVE then self.callbacks.onReceive=p elseif o==b.ONDRAG then self.callbacks.onDrag=p elseif o==b.ONRESIZE then self.callbacks.onResize=p elseif o==b.ONPASTE then self.callbacks.onPaste=p elseif o==b.ONHOVER then self.callbacks.onHover=p elseif o==b.ONRELEASE then self.callbacks.onRelease=p end end}e3.__index=e3;setmetatable(h.Vector2,e2)setmetatable(h.Vector3,e2)for d,dn in next,cm do setmetatable(dn,e3)end;for d,dn in next,cl do setmetatable(dn,e3)end;setmetatable(dN,e3)local e4={...}if e4[1]=="help"then local R={{text="LIBFILE ",foreground=colors.green,background=nil},{text=" - help (shows this list of commands)",foreground=colors.blue,background=nil},{text=" - info (prints info about the lib)",foreground=colors.yellow,background=nil},{text=" - ver (prints version of the lib)",foreground=colors.green,background=nil},{text=" - copyright (prints copyright of the lib)",foreground=colors.blue,background=nil},{text=" - setup (adds YAGUI_PATH to computer's settings)",foreground=colors.yellow,background=nil},{text=" - create (creates a new YAGUI project)",foreground=colors.green,background=nil}}for d,co in next,R do m.better_print(term,co.foreground,co.background,co.text)end elseif e4[1]=="info"then m.better_print(term,colors.red,nil,"Library Version: ",a.ver)m.better_print(term,colors.yellow,nil,"Library Author: ",a.author)m.better_print(term,colors.green,nil,"Library Website: ",a.website)m.better_print(term,colors.blue,nil,"Library Documentation: ",a.documentation)elseif e4[1]=="ver"then m.better_print(term,colors.red,nil,"Library Version: ",a.ver)elseif e4[1]=="copyright"then local e5={colors.red,colors.yellow,colors.green}local e6=g.split(a.copyright,"\n\n")for d,e7 in next,e6 do m.better_print(term,e5[d],nil,e7)if d<#e6 then read("")end end elseif e4[1]=="setup"then if shell then local e8="YAGUI_PATH"local _="/"..shell.getRunningProgram()l.set(e8,_)m.better_print(term,colors.green,nil,"Lib path was set to \"",l.get(e8),"\".")else m.better_print(term,colors.red,nil,"SHELL API ISN'T AVAILABLE!")end elseif e4[1]=="create"then if e4[2]then local _=shell.resolve(e4[2])if g.get_extension(_)~="lua"then _=_..".lua"end;if fs.exists(_)then m.better_print(term,colors.red,nil,"PATH: \"/",_,"\" already exists, please use another path or delete it.")else local dI=fs.open(_,"w")dI.write("\n-- AUTO-GENERATED with \"YAGUI create\"\nlocal YAGUI_PATH = settings.get(\"YAGUI_PATH\")\nif not (type(YAGUI_PATH) == \"string\") then printError(\"YAGUI is not installed, please install it by opening it with argument \\\"setup\\\".\"); return; end\nif not fs.exists(YAGUI_PATH) then printError(\"Couldn't find YAGUI in path: \\\"\"..YAGUI_PATH..\"\\\", Please reinstall it by opening it with argument \\\"setup\\\".\"); return; end\nlocal YAGUI = dofile(YAGUI_PATH)\n-- End of AUTO-GENERATED code\n\n")dI.close()m.better_print(term,colors.green,nil,"New project was created at \"/",_,"\".")end else m.better_print(term,colors.red,nil,"You must specify a path to create a new project.")end elseif e4[1]then m.better_print(term,colors.red,nil,"UNKNOWN COMMAND: \"",e4[1],"\"")m.better_print(term,colors.green,nil,"Use \"help\" to get a list of available commands!")end;local e9={info=a,generic_utils=f,string_utils=g,math_utils=h,table_utils=i,color_utils=j,event_utils=k,setting_utils=l,monitor_utils=m,screen_buffer=bv,input=ch,gui_elements=cl,logic_elements=cm,Loop=dN}for d,H in next,b do e9[d]=H end;return e9