This repository was archived by the owner on Jun 21, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathAPLib-mini.lua
More file actions
16 lines (14 loc) · 67.9 KB
/
APLib-mini.lua
File metadata and controls
16 lines (14 loc) · 67.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
--[[
Copyright (c) 2022, Marco4413 : https://github.com/Marco4413/APLib
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.
--]]
info={ver='1.29.0',author='Marco4413',website='https://github.com/Marco4413/APLib'}globalMonitor=term;globalMonitorName='term'globalMonitorGroup={enabled=false,list={}}globalMonitorWidth,globalMonitorHeight=globalMonitor.getSize()globalMonitorBuffer={enabled=false,frames={lastFrame={},newFrame={}},clear=function()globalMonitorBuffer.frames.newFrame={}end,write=function(a,b,text,c,d,e)assert(type(a)=='number','globalMonitorBuffer.write: x must be a number, got '..type(a))assert(type(b)=='number','globalMonitorBuffer.write: y must be a number, got '..type(b))assert(type(c)=='number','globalMonitorBuffer.write: fg must be a number, got '..type(c))assert(type(d)=='number'or e,'globalMonitorBuffer.write: bg must be a number, got '..type(d))b=tostring(b)if not globalMonitorBuffer.frames.newFrame[b]then globalMonitorBuffer.frames.newFrame[b]={}end;text=tostring(text)for f in text:gmatch('.')do local g=globalMonitorBuffer.frames.newFrame[b][tostring(a)]local h=d;if e then if g then h=g.bg else h=globalMonitor.getBackgroundColor()end end;globalMonitorBuffer.frames.newFrame[b][tostring(a)]={char=f,fg=c,bg=h}a=a+1 end end,draw=function()if not globalMonitorBuffer.enabled then return end;local i,j=globalMonitor.getCursorPos()local k=globalMonitor.getTextColor()local l=globalMonitor.getBackgroundColor()for b=1,globalMonitorHeight do local m=globalMonitorBuffer.frames.newFrame[tostring(b)]for a=1,globalMonitorWidth do globalMonitor.setCursorPos(a,b)if m then local g=m[tostring(a)]if g then globalMonitor.setTextColor(g.fg)globalMonitor.setBackgroundColor(g.bg)globalMonitor.write(g.char)else globalMonitor.setBackgroundColor(l)globalMonitor.write(' ')end else globalMonitor.setBackgroundColor(l)globalMonitor.write(string.rep(' ',globalMonitorWidth))break end end end;globalMonitor.setCursorPos(i,j)globalMonitor.setTextColor(k)globalMonitor.setBackgroundColor(l)globalMonitorBuffer.frames.lastFrame=tableCopy(globalMonitorBuffer.frames.newFrame)end}function setRenderer(n)assert(type(n)=='number','setRenderer: type must be a number, got '..type(n))if n==1 then globalMonitorBuffer.enabled=false elseif n==2 then globalMonitorBuffer.enabled=true end end;globalColor=colors.white;globalTextColor=colors.white;globalBackgroundTextColor=colors.black;globalRectangleType=1;globalLoop={enabled=false,autoClear=true,drawOnClock=true,clockSpeed=0.5,timerSpeed=0.1,clock=0,APLWDBroadcastOnClock=false,APLWDClearCacheOnDraw=true,stats={automaticPos=true,automaticPosOffset={x=0,y=0}},callbacks={onInit=function()end,onStop=function()end,onClock=function()end,onEvent=function()end,onTimer=function()end,onMonitorChange=function()end},events={draw={},touch={},tick={},key={},char={},mouse_drag={}},wasGroupChanged=false,selectedGroup='none',group={none={callbacks={onClock=function()end,onEvent=function()end,onTimer=function()end,onMonitorChange=function()end,onSet=function()end,onUnset=function()end},objs={}},LIBPrivate={callbacks={onClock=function()end,onEvent=function()end,onTimer=function()end,onMonitorChange=function()end,onSet=function()end,onUnset=function()end},objs={}}}}globalCallbacks={onBClear=function()end,onSetMonitor=function()end}renderEngine={classic=1,experimental=2}rectangleTypes={filled=1,hollow=2,checker=3}event={global={onBClear=1,onSetMonitor=2},clock={onClock=1},point={onDraw=1,onPress=2,onFailedPress=3},rectangle={onDraw=1,onPress=2,onFailedPress=3},header={onDraw=1,onPress=2,onFailedPress=3},label={onDraw=1,onPress=2,onFailedPress=3},button={onDraw=1,onPress=2,onFailedPress=3},menu={onDraw=1,onPress=2,onFailedPress=3,onButtonPress=4,onFailedButtonPress=5},percentagebar={onDraw=1,onPress=2,onFailedPress=3},memo={onDraw=1,onPress=2,onFailedPress=3,onEdit=4,onCursorBlink=5,onActivated=6,onDeactivated=7},window={onDraw=1,onPress=2,onFailedPress=3,onOBJPress=4,onFailedOBJPress=5,onEvent=6},objGroup={onDraw=1,onOBJPress=2,onFailedOBJPress=3},loop={group={onClock=1,onEvent=2,onTimer=3,onMonitorChange=4,onSet=5,onUnset=6},onInit=1,onStop=2,onClock=3,onEvent=4,onTimer=5,onMonitorChange=6}}function stringSplit(o,p)o=tostring(o)p=tostring(p)local q={}while true do local r=o:find(p)if r then table.insert(q,o:sub(1,r-1))o=o:sub(r+1)else table.insert(q,o)break end end;return q end;function tablesAreEqual(s,t)assert(type(s)=='table','tablesAreEqual: t1 must be a table, got '..type(s))assert(type(t)=='table','tablesAreEqual: t2 must be a table, got '..type(t))local function u(s,t,v)if#s~=#t then return false end;for w,x in pairs(s)do if type(x)=='table'and type(t[w])=='table'then u(x,t[w])elseif x~=t[w]then return false end end;return v or u(t,s,true)end;return u(s,t)end;function tableCopy(y)assert(type(y)=='table','tableCopy: table must be a table, got '..type(y))local z={}for w,x in pairs(y)do if type(x)=='table'then z[w]=tableCopy(x)else z[w]=x end end;return z end;function tableHasKey(y,A)assert(type(y)=='table','tableHasKey: table must be a table, got '..type(y))assert(type(A)=='string'or type(A)=='number','tableHasKey: key must be a string or a number, got '..type(A))for w,x in pairs(y)do if w==A then return true,x end end;return false end;function tableHasValue(y,B)assert(type(y)=='table','tableHasValue: table must be a table, got '..type(y))for w,x in pairs(y)do if x==B then return true,w end end;return false end;OSSettings={settingsPath='/.settings',set=function(C,B)assert(type(B)~='nil',"OSSettings.set: value can't be nil, got "..type(B))settings.set(tostring(C),B)return settings.save(OSSettings.settingsPath)end,get=function(C)return settings.get(tostring(C))end,getNames=function()return settings.getNames()end,unset=function(C)settings.unset(tostring(C))return settings.save(OSSettings.settingsPath)end}function setGlobalCallback(D,E)assert(type(E)=='function','setGlobalCallback: callback must be a function, got '..type(E))if D==1 then globalCallbacks.onBClear=E elseif D==2 then globalCallbacks.onSetMonitor=E end end;function bClear()if globalMonitorBuffer.enabled then globalMonitorBuffer.clear()else globalMonitor.clear()globalMonitor.setCursorPos(1,1)end;globalCallbacks.onBClear()if not APLWD.isReceiver and APLWD.cacheWritable then table.insert(APLWD.cache,{type='bClear'})end end;function bClearMonitorGroup()if globalMonitorGroup.enabled then globalLoop.group[globalLoop.selectedGroup].callbacks.onMonitorChange(monitorName)bClear()local F=APLWD.cacheWritable;if APLWD.enabled and F then APLWD.cacheWritable=false end;local G=globalMonitorName;for H,monitorName in pairs(globalMonitorGroup.list)do if monitorName~=G then setMonitor(monitorName)globalLoop.group[globalLoop.selectedGroup].callbacks.onMonitorChange(monitorName)bClear()end end;setMonitor(G)if APLWD.enabled and F then APLWD.cacheWritable=true end else bClear()end end;function setMonitor(I)I=tostring(I)globalCallbacks.onSetMonitor(globalMonitor,globalMonitorName,globalMonitorWidth,globalMonitorHeight)if I=='term'then globalMonitor=term;globalMonitorName='term'globalMonitorWidth,globalMonitorHeight=globalMonitor.getSize()else assert(tostring(peripheral.getType(I))=='monitor','setMonitor: '..I..' must be a monitor, got '..tostring(peripheral.getType(I)))local J=peripheral.wrap(I)globalMonitor=J;globalMonitorName=I;globalMonitorWidth,globalMonitorHeight=globalMonitor.getSize()end end;function getMonitorSize()return globalMonitorWidth,globalMonitorHeight end;function setMonitorGroup(K)assert(type(K)=='table','setMonitorGroup: monitorNameList must be a table, got '..type(K))for w,x in pairs(K)do x=tostring(x)if x~='term'then assert(tostring(peripheral.getType(x))=='monitor','setMonitorGroup: '..x..' must be a monitor, got '..tostring(peripheral.getType(x)))end end;globalMonitorGroup.list=K end;function setMonitorGroupEnabled(L)assert(type(L)=='boolean','setMonitorGroupEnabled: bool must be a boolean, got '..type(L))globalMonitorGroup.enabled=L end;function resetMonitorGroup()globalMonitorGroup.list={}end;APLWD={enabled=false,cacheWritable=true,clearOnDraw=false,protocol='APLWD-'..info.ver,senderName='SendeR',receiverName='ReceiveR',isReceiver=true,myName='',senderID='',modemName='',cache={}}APLWD.enable=function(L)assert(type(L)=='boolean','APLWD.enable: bool must be a boolean, got '..type(L))APLWD.enabled=L end;APLWD.broadcastOnLoopClock=function()globalLoop.APLWDBroadcastOnClock=true end;APLWD.dontBroadcastOnLoopClock=function()globalLoop.APLWDBroadcastOnClock=false end;APLWD.enableClearCacheOnLoopDraw=function(L)assert(type(L)=='boolean','APLWD.enableClearCacheOnLoopDraw: bool must be a boolean, got '..type(L))globalLoop.APLWDClearCacheOnDraw=L end;APLWD.host=function(M,N)if APLWD.enabled then M=tostring(M)if N then N=tostring(N)else N=tostring(os.getComputerID())end;assert(tostring(peripheral.getType(M))=='modem','APLWD.host: modemName must be a modem, got '..tostring(peripheral.getType(M)))rednet.open(M)if rednet.lookup(APLWD.protocol,APLWD.senderName..N)then rednet.close(M)error("APLWD.host: There's already someone connected with hostname: "..N)end;rednet.host(APLWD.protocol,APLWD.senderName..N)APLWD.isReceiver=false;APLWD.myName=APLWD.senderName..N;APLWD.modemName=M end end;APLWD.connect=function(M,O,N)if APLWD.enabled then M=tostring(M)if N then N=tostring(N)else N=tostring(os.getComputerID())end;O=tostring(O)assert(tostring(peripheral.getType(M))=='modem','APLWD.connect: modemName must be a modem, got '..tostring(peripheral.getType(M)))rednet.open(M)if rednet.lookup(APLWD.protocol,APLWD.receiverName..N)then rednet.close(M)error("APLWD.connect: There's already someone connected with hostname: "..N)end;local P=rednet.lookup(APLWD.protocol,APLWD.senderName..O)if not P then rednet.close(M)error("APLWD.connect: Didn't find any sender with name: "..O)end;rednet.host(APLWD.protocol,APLWD.receiverName..N)APLWD.isReceiver=true;APLWD.myName=APLWD.receiverName..N;APLWD.senderID=P;APLWD.modemName=M end end;APLWD.close=function()if APLWD.modemName~=''then if not APLWD.isReceiver then rednet.broadcast('disconnected',APLWD.protocol)end;rednet.unhost(APLWD.protocol,APLWD.myName)rednet.close(APLWD.modemName)APLWD.enable(false)APLWD.clearCache()APLWD.isReceiver=true;APLWD.myName=''APLWD.senderID=''APLWD.modemName=''end end;APLWD.broadcastCache=function()if APLWD.enabled then local Q=rednet.isOpen()assert(Q,'APLWD.broadcastCache: rednet connection must be opened first, connection '..tostring(Q))rednet.broadcast(APLWD.cache,APLWD.protocol)APLWD.clearCache()end end;APLWD.receiveCache=function(R)if APLWD.enabled then local Q=rednet.isOpen()assert(Q,'APLWD.receiveCache: rednet connection must be opened first, connection '..tostring(Q))local P,S,T=rednet.receive(APLWD.protocol,tonumber(R))if type(S)=='table'then if P==APLWD.senderID then APLWD.cache=S;return true end elseif S=='disconnected'then APLWD.close()return false,'disconnected'end;return false end end;APLWD.drawCache=function()if APLWD.enabled then local function U()for w,x in pairs(APLWD.cache)do if x.type=='bClear'then bClearMonitorGroup()elseif x.type=='background'then setBackgroundMonitorGroup(x.color)elseif x.type=='text'then local k=globalTextColor;local V=globalBackgroundTextColor;setTextColor(x.colors.textColor)setBackgroundTextColor(x.colors.backgroundTextColor)text(x.pos.x,x.pos.y,x.text,x.colors.transparentBG)setTextColor(k)setBackgroundTextColor(V)elseif x.type=='point'then local W=globalColor;setColor(x.color)point(x.pos.x,x.pos.y)setColor(W)elseif x.type=='rectangle'then local W=globalColor;setColor(x.color)rectangle(x.pos.x1,x.pos.y1,x.pos.x2,x.pos.y2)setColor(W)end end end;if globalMonitorGroup.enabled then if APLWD.clearOnDraw then bClear()end;U()if globalMonitorBuffer.enabled then globalMonitorBuffer.draw()end;local G=globalMonitorName;for H,monitorName in pairs(globalMonitorGroup.list)do if monitorName~=G then setMonitor(monitorName)globalLoop.group[globalLoop.selectedGroup].callbacks.onMonitorChange(monitorName)if globalMonitorBuffer.enabled then globalMonitorBuffer.draw()else U()end end end;setMonitor(G)else if APLWD.clearOnDraw then bClear()end;U()if globalMonitorBuffer.enabled then globalMonitorBuffer.draw()end end;APLWD.clearCache()end end;APLWD.clearCache=function()APLWD.cache={}end;function setColor(X)assert(type(X)=='number','setColor: color must be a number, got '..type(X))globalColor=X end;function setTextColor(X)assert(type(X)=='number','setTextColor: color must be a number, got '..type(X))globalTextColor=X end;function setBackgroundTextColor(X)assert(type(X)=='number','setBackgroundTextColor: color must be a number, got '..type(X))globalBackgroundTextColor=X end;function setBackground(X)assert(type(X)=='number','setBackgroundColor: color must be a number, got '..type(X))if globalMonitorBuffer.enabled then globalMonitor.setBackgroundColor(X)else globalMonitor.setBackgroundColor(X)local F=APLWD.cacheWritable;if APLWD.enabled and F then APLWD.cacheWritable=false end;bClear()if APLWD.enabled and F then APLWD.cacheWritable=true end end;if not APLWD.isReceiver and APLWD.cacheWritable then table.insert(APLWD.cache,{type='background',color=X})end end;function setBackgroundMonitorGroup(X)assert(type(X)=='number','setBackgroundMonitorGroup: color must be a number, got '..type(X))if globalMonitorGroup.enabled then globalLoop.group[globalLoop.selectedGroup].callbacks.onMonitorChange(monitorName)setBackground(X)local F=APLWD.cacheWritable;if APLWD.enabled and F then APLWD.cacheWritable=false end;local G=globalMonitorName;for H,monitorName in pairs(globalMonitorGroup.list)do if monitorName~=G then setMonitor(monitorName)globalLoop.group[globalLoop.selectedGroup].callbacks.onMonitorChange(monitorName)setBackground(X)end end;setMonitor(G)if APLWD.enabled and F then APLWD.cacheWritable=true end else setBackground(X)end end;function setRectangleType(n)assert(type(n)=='number','setRectangleType: type must be a number, got '..type(n))globalRectangleType=n end;function text(Y,Z,_,a0)assert(type(Y)=='number','text: x must be a number, got '..type(Y))assert(type(Z)=='number','text: y must be a number, got '..type(Z))_=tostring(_)local i,j=globalMonitor.getCursorPos()local k=globalMonitor.getTextColor()local l=globalMonitor.getBackgroundColor()globalMonitor.setTextColor(globalTextColor)globalMonitor.setBackgroundColor(globalBackgroundTextColor)local a1=stringSplit(_,'\n')for w,x in pairs(a1)do if globalMonitorBuffer.enabled then globalMonitorBuffer.write(Y,Z+w-1,x,globalTextColor,globalBackgroundTextColor,a0)else globalMonitor.setCursorPos(Y,Z+w-1)globalMonitor.write(x)end end;globalMonitor.setCursorPos(i,j)globalMonitor.setTextColor(k)globalMonitor.setBackgroundColor(l)if not APLWD.isReceiver and APLWD.cacheWritable then table.insert(APLWD.cache,{type='text',text=_,pos={x=Y,y=Z},colors={textColor=globalTextColor,backgroundTextColor=globalBackgroundTextColor,transparentBG=a0}})end end;function point(Y,Z)assert(type(Y)=='number','point: x must be a number, got '..type(Y))assert(type(Z)=='number','point: y must be a number, got '..type(Z))local i,j=globalMonitor.getCursorPos()local l=globalMonitor.getBackgroundColor()globalMonitor.setBackgroundColor(globalColor)if globalMonitorBuffer.enabled then globalMonitorBuffer.write(Y,Z,' ',globalColor,globalColor)else globalMonitor.setCursorPos(Y,Z)globalMonitor.write(' ')end;globalMonitor.setCursorPos(i,j)globalMonitor.setBackgroundColor(l)if not APLWD.isReceiver and APLWD.cacheWritable then table.insert(APLWD.cache,{type='point',pos={x=Y,y=Z},color=globalColor})end end;function line(a2,a3,a4,a5)assert(type(a2)=='number','line: x1 must be a number, got '..type(a2))assert(type(a3)=='number','line: y1 must be a number, got '..type(a3))assert(type(a4)=='number','line: x2 must be a number, got '..type(a4))assert(type(a5)=='number','line: y2 must be a number, got '..type(a5))local function a6(a2,a3,a4,a5)local a7=1;if a2>a4 then a7=-1 end;local a8=a4-a2;local a9=a5-a3;local aa=1;if a9<0 then aa=-1;a9=-a9 end;local ab=2*a9-a8;local b=a3;for a=a2,a4,a7 do point(a,b)if ab>0 then b=b+aa;ab=ab-2*a8 end;ab=ab+2*a9 end end;local function ac(a2,a3,a4,a5)local a7=1;if a3>a5 then a7=-1 end;local a8=a4-a2;local a9=a5-a3;local ad=1;if a8<0 then ad=-1;a8=-a8 end;local ab=2*a8-a9;local a=a2;for b=a3,a5,a7 do point(a,b)if ab>0 then a=a+ad;ab=ab-2*a9 end;ab=ab+2*a8 end end;if math.abs(a5-a3)<math.abs(a4-a2)then if a2>a4 then a6(a4,a5,a2,a3)else a6(a2,a3,a4,a5)end else if a3>a5 then ac(a4,a5,a2,a3)else ac(a2,a3,a4,a5)end end end;function rectangle(ae,af,ag,ah)assert(type(ae)=='number','rectangle: x1 must be a number, got '..type(ae))assert(type(af)=='number','rectangle: y1 must be a number, got '..type(af))assert(type(ag)=='number','rectangle: x2 must be a number, got '..type(ag))assert(type(ah)=='number','rectangle: y2 must be a number, got '..type(ah))local ai=1;local aj=1;if ae>ag then ai=-1 end;if af>ah then aj=-1 end;local F=APLWD.cacheWritable;if APLWD.enabled and F then APLWD.cacheWritable=false end;if globalRectangleType==1 then for a=ae,ag,ai do for b=af,ah,aj do point(a,b)end end elseif globalRectangleType==2 then for a=ae,ag,ai do point(a,af)point(a,ah)end;for b=af,ah,aj do point(ae,b)point(ag,b)end elseif globalRectangleType==3 then local ak=true;for a=ae,ag,ai do for b=af,ah,aj do if ak then point(a,b)end;ak=not ak end;if math.abs(ae-ag)%2~=0 then ak=not ak end end end;if APLWD.enabled and F then APLWD.cacheWritable=true end;if not APLWD.isReceiver and APLWD.cacheWritable then table.insert(APLWD.cache,{type='rectangle',pos={x1=ae,y1=af,x2=ag,y2=ah},color=globalColor})end end;function ellipse(al,am,an)assert(type(al)=='number','ellipse: xCenter must be a number, got '..type(al))assert(type(am)=='number','ellipse: yCenter must be a number, got '..type(am))assert(type(an)=='number','ellipse: radius must be a number, got '..type(an))local ao=an*an;point(al,am+an)point(al,am-an)point(al+an,am)point(al-an,am)local a=1;local b=math.floor(math.sqrt(ao-1)+0.5)while a<b do point(al+a,am+b)point(al+a,am-b)point(al-a,am+b)point(al-a,am-b)point(al+b,am+a)point(al+b,am-a)point(al-b,am+a)point(al-b,am-a)a=a+1;b=math.floor(math.sqrt(ao-a*a)+0.5)end;if a==b then point(al+a,am+b)point(al+a,am-b)point(al-a,am+b)point(al-a,am-b)end end;function checkAreaPress(ae,af,ag,ah,ap,aq)assert(type(ae)=='number','checkAreaPress: x1 must be a number, got '..type(ae))assert(type(af)=='number','checkAreaPress: y1 must be a number, got '..type(af))assert(type(ag)=='number','checkAreaPress: x2 must be a number, got '..type(ag))assert(type(ah)=='number','checkAreaPress: y2 must be a number, got '..type(ah))assert(type(ap)=='number','checkAreaPress: xPressed must be a number, got '..type(ap))assert(type(aq)=='number','checkAreaPress: yPressed must be a number, got '..type(aq))if ae<ag then if not(ap>=ae and ap<=ag)then return false end else if not(ap<=ae and ap>=ag)then return false end end;if af<ah then if not(aq>=af and aq<=ah)then return false end else if not(aq<=af and aq>=ah)then return false end end;return true end;Clock={}function Clock.new(ar)assert(type(ar)=='number','Clock.new: interval must be a number, got '..type(ar))local as={clock=os.clock(),interval=ar,callbacks={onClock=function()end}}setmetatable(as,Clock)return as end;function Clock:setCallback(D,E)assert(type(E)=='function','Clock.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onClock=E end end;function Clock:tick(D)if os.clock()>=self.clock+self.interval then self.clock=os.clock()self.callbacks.onClock(self,D)return true end;return false end;Clock.__index=Clock;Point={}function Point.new(Y,Z,at)at=at or{}if at[1]~=nil then at.color=at[1]at[1]=nil end;assert(type(Y)=='number','Point.new: x must be a number, got '..type(Y))assert(type(Z)=='number','Point.new: y must be a number, got '..type(Z))assert(type(at)=='table','Point.new: args must be a table or nil, got '..type(at))local au={color=tonumber(at.color)or globalColor,hidden=false,pos={x=Y,y=Z},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end}}setmetatable(au,Point)return au end;function Point:draw()if not self.hidden then self.callbacks.onDraw(self)local W=globalColor;setColor(self.color)point(self.pos.x,self.pos.y)setColor(W)end end;function Point:setCallback(D,E)assert(type(E)=='function','Point.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onDraw=E elseif D==2 then self.callbacks.onPress=E elseif D==3 then self.callbacks.onFailedPress=E end end;function Point:touch(Y,Z,D,av)assert(type(Y)=='number','Point.touch: x must be a number, got '..type(Y))assert(type(Z)=='number','Point.touch: y must be a number, got '..type(Z))if not self.hidden then if not av then if self.pos.x==Y and self.pos.y==Z then self.callbacks.onPress(self,D,av)return true else self.callbacks.onFailedPress(self,D,av)return false end else self.callbacks.onFailedPress(self,D,av)end end;return false end;function Point:hide(L)assert(type(L)=='boolean','Point.hide: bool must be a boolean, got '..type(L))self.hidden=L end;Point.__index=Point;Rectangle={}function Rectangle.new(ae,af,ag,ah,at)at=at or{}if at[1]~=nil then at.color=at[1]at[1]=nil end;if at[2]~=nil then at.type=at[2]at[2]=nil end;assert(type(ae)=='number','Rectangle.new: x1 must be a number, got '..type(ae))assert(type(af)=='number','Rectangle.new: y1 must be a number, got '..type(af))assert(type(ag)=='number','Rectangle.new: x2 must be a number, got '..type(ag))assert(type(ah)=='number','Rectangle.new: y2 must be a number, got '..type(ah))assert(type(at)=='table','Rectangle.new: args must be a table or nil, got '..type(at))local aw={color=tonumber(at.color)or globalColor,type=tonumber(at.type)or globalRectangleType,hidden=false,pos={x1=ae,y1=af,x2=ag,y2=ah},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end}}setmetatable(aw,Rectangle)return aw end;function Rectangle:draw()if not self.hidden then self.callbacks.onDraw(self)local ax=globalRectangleType;local W=globalColor;setRectangleType(self.type)setColor(self.color)rectangle(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2)setRectangleType(ax)setColor(W)end end;function Rectangle:setCallback(D,E)assert(type(E)=='function','Rectangle.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onDraw=E elseif D==2 then self.callbacks.onPress=E elseif D==3 then self.callbacks.onFailedPress=E end end;function Rectangle:touch(Y,Z,D,av)assert(type(Y)=='number','Rectangle.touch: x must be a number, got '..type(Y))assert(type(Z)=='number','Rectangle.touch: y must be a number, got '..type(Z))if not self.hidden then if not av then if checkAreaPress(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2,Y,Z)then self.callbacks.onPress(self,D,av)return true else self.callbacks.onFailedPress(self,D,av)return false end else self.callbacks.onFailedPress(self,D,av)end end;return false end;function Rectangle:hide(L)assert(type(L)=='boolean','Rectangle.hide: bool must be a boolean, got '..type(L))self.hidden=L end;Rectangle.__index=Rectangle;Header={}function Header.new(Z,at)at=at or{}if at[1]~=nil then at.text=at[1]at[1]=nil end;if at[2]~=nil then at.textColor=at[2]at[2]=nil end;if at[3]~=nil then at.backgroundTextColor=at[3]at[3]=nil end;if at[4]~=nil then at.transparentBG=at[4]at[4]=nil end;assert(type(Z)=='number','Header.new: y must be a number, got '..type(Z))assert(type(at)=='table','Header.new: args must be a table or nil, got '..type(at))if not at.text then at.text=''end;at.text=tostring(at.text)local ay={text=at.text,hidden=false,pos={x=math.floor((globalMonitorWidth-string.len(at.text)+1)/2),y=Z},colors={textColor=tonumber(at.textColor)or globalTextColor,backgroundTextColor=tonumber(at.backgroundTextColor),transparentBG=at.transparentBG},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end}}setmetatable(ay,Header)return ay end;function Header:draw()if not self.hidden then self.callbacks.onDraw(self)local k=globalTextColor;local V=globalBackgroundTextColor;local az=globalMonitor.getBackgroundColor()setTextColor(self.colors.textColor)if self.colors.backgroundTextColor then setBackgroundTextColor(self.colors.backgroundTextColor)else setBackgroundTextColor(az)end;local a1=stringSplit(self.text,'\n')self.pos.x=math.floor((globalMonitorWidth-string.len(a1[1])+1)/2)text(self.pos.x,self.pos.y,a1[1],self.colors.transparentBG)table.remove(a1,1)for w,x in pairs(a1)do local aA=math.floor((globalMonitorWidth-string.len(x)+1)/2)local aB=self.pos.y+w;text(aA,aB,x)end;setTextColor(k)setBackgroundTextColor(V)end end;function Header:setCallback(D,E)assert(type(E)=='function','Header.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onDraw=E elseif D==2 then self.callbacks.onPress=E elseif D==3 then self.callbacks.onFailedPress=E end end;function Header:touch(Y,Z,D,av)assert(type(Y)=='number','Header.touch: x must be a number, got '..type(Y))assert(type(Z)=='number','Header.touch: y must be a number, got '..type(Z))if not self.hidden then if not av then self.pos.x=math.floor((globalMonitorWidth-string.len(self.text)+1)/2)local ag=self.pos.x+string.len(self.text)-1;if checkAreaPress(self.pos.x,self.pos.y,ag,self.pos.y,Y,Z)then self.callbacks.onPress(self,D,av)return true else self.callbacks.onFailedPress(self,D,av)return false end else self.callbacks.onFailedPress(self,D,av)end end;return false end;function Header:hide(L)assert(type(L)=='boolean','Header.hide: bool must be a boolean, got '..type(L))self.hidden=L end;Header.__index=Header;Label={}function Label.new(Y,Z,at)at=at or{}if at[1]~=nil then at.text=at[1]at[1]=nil end;if at[2]~=nil then at.textColor=at[2]at[2]=nil end;if at[3]~=nil then at.backgroundTextColor=at[3]at[3]=nil end;if at[4]~=nil then at.transparentBG=at[4]at[4]=nil end;assert(type(Y)=='number','Label.new: x must be a number, got '..type(Y))assert(type(Z)=='number','Label.new: y must be a number, got '..type(Z))assert(type(at)=='table','Label.new: args must be a table or nil, got '..type(at))if not at.text then at.text=''end;at.text=tostring(at.text)local aC={text=at.text,hidden=false,pos={x=Y,y=Z},colors={textColor=tonumber(at.textColor)or globalTextColor,backgroundTextColor=tonumber(at.backgroundTextColor),transparentBG=at.transparentBG},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end}}setmetatable(aC,Label)return aC end;function Label:draw()if not self.hidden then self.callbacks.onDraw(self)local k=globalTextColor;local V=globalBackgroundTextColor;local az=globalMonitor.getBackgroundColor()setTextColor(self.colors.textColor)if self.colors.backgroundTextColor then setBackgroundTextColor(self.colors.backgroundTextColor)else setBackgroundTextColor(az)end;text(self.pos.x,self.pos.y,self.text,self.colors.transparentBG)setTextColor(k)setBackgroundTextColor(V)end end;function Label:setCallback(D,E)assert(type(E)=='function','Label.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onDraw=E elseif D==2 then self.callbacks.onPress=E elseif D==3 then self.callbacks.onFailedPress=E end end;function Label:touch(Y,Z,D,av)assert(type(Y)=='number','Label.touch: x must be a number, got '..type(Y))assert(type(Z)=='number','Label.touch: y must be a number, got '..type(Z))if not self.hidden then if not av then local ag=self.pos.x+string.len(self.text)-1;if checkAreaPress(self.pos.x,self.pos.y,ag,self.pos.y,Y,Z)then self.callbacks.onPress(self,D,av)return true else self.callbacks.onFailedPress(self,D,av)return false end else self.callbacks.onFailedPress(self,D,av)end end;return false end;function Label:hide(L)assert(type(L)=='boolean','Label.hide: bool must be a boolean, got '..type(L))self.hidden=L end;Label.__index=Label;Button={}function Button.new(ae,af,ag,ah,at)at=at or{}if at[1]~=nil then at.text=at[1]at[1]=nil end;if at[2]~=nil then at.textColor=at[2]at[2]=nil end;if at[3]~=nil then at.backgroundTextColor=at[3]at[3]=nil end;if at[4]~=nil then at.pressedButtonColor=at[4]at[4]=nil end;if at[5]~=nil then at.notPressedButtonColor=at[5]at[5]=nil end;assert(type(ae)=='number','Button.new: x1 must be a number, got '..type(ae))assert(type(af)=='number','Button.new: y1 must be a number, got '..type(af))assert(type(ag)=='number','Button.new: x2 must be a number, got '..type(ag))assert(type(ah)=='number','Button.new: y2 must be a number, got '..type(ah))assert(type(at)=='table','Button.new: args must be a table or nil, got '..type(at))if not at.text then at.text=''end;at.text=tostring(at.text)local aD={text=at.text,state=false,hidden=false,pos={x1=ae,y1=af,x2=ag,y2=ah},colors={textColor=tonumber(at.textColor)or globalTextColor,backgroundTextColor=tonumber(at.backgroundTextColor),pressedButtonColor=tonumber(at.pressedButtonColor)or globalColor,notPressedButtonColor=tonumber(at.notPressedButtonColor)or globalColor},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end}}setmetatable(aD,Button)return aD end;function Button:draw()if not self.hidden then self.callbacks.onDraw(self)local ax=globalRectangleType;local W=globalColor;local k=globalTextColor;local V=globalBackgroundTextColor;setRectangleType(rectangleTypes.filled)if self.state then setColor(self.colors.pressedButtonColor)if self.colors.backgroundTextColor then setBackgroundTextColor(self.colors.backgroundTextColor)else setBackgroundTextColor(self.colors.pressedButtonColor)end else setColor(self.colors.notPressedButtonColor)if self.colors.backgroundTextColor then setBackgroundTextColor(self.colors.backgroundTextColor)else setBackgroundTextColor(self.colors.notPressedButtonColor)end end;setTextColor(self.colors.textColor)rectangle(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2)local aE=self.pos.x1+math.floor((self.pos.x2-self.pos.x1-string.len(self.text)+1)/2)local aF=self.pos.y1+math.floor((self.pos.y2-self.pos.y1)/2)text(aE,aF,self.text)setRectangleType(ax)setColor(W)setTextColor(k)setBackgroundTextColor(V)end end;function Button:setCallback(D,E)assert(type(E)=='function','Button.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onDraw=E elseif D==2 then self.callbacks.onPress=E elseif D==3 then self.callbacks.onFailedPress=E end end;function Button:touch(Y,Z,D,av)assert(type(Y)=='number','Button.touch: x must be a number, got '..type(Y))assert(type(Z)=='number','Button.touch: y must be a number, got '..type(Z))if not self.hidden then if not av then if checkAreaPress(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2,Y,Z)then self.state=not self.state;self.callbacks.onPress(self,D,av)return true else self.callbacks.onFailedPress(self,D,av)return false end else self.callbacks.onFailedPress(self,D,av)end end;return false end;function Button:hide(L)assert(type(L)=='boolean','Button.hide: bool must be a boolean, got '..type(L))self.hidden=L end;Button.__index=Button;Menu={}function Menu.new(ae,af,ag,ah,at)at=at or{}if at[1]~=nil then at.color=at[1]at[1]=nil end;assert(type(ae)=='number','Menu.new: x1 must be a number, got '..type(ae))assert(type(af)=='number','Menu.new: y1 must be a number, got '..type(af))assert(type(ag)=='number','Menu.new: x2 must be a number, got '..type(ag))assert(type(ah)=='number','Menu.new: y2 must be a number, got '..type(ah))assert(type(at)=='table','Menu.new: args must be a table or nil, got '..type(at))local aG={color=tonumber(at.color)or globalColor,objs={},hidden=true,pos={x1=ae,y1=af,x2=ag,y2=ah},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end,onButtonPress=function()end,onFailedButtonPress=function()end}}setmetatable(aG,Menu)return aG end;function Menu:draw()if not self.hidden then self.callbacks.onDraw(self)local ax=globalRectangleType;local W=globalColor;setColor(self.color)rectangle(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2)for aH=#self.objs,1,-1 do local aI=self.objs[aH]aI:draw()end;setColor(W)end end;function Menu:setCallback(D,E)assert(type(E)=='function','Menu.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onDraw=E elseif D==2 then self.callbacks.onPress=E elseif D==3 then self.callbacks.onFailedPress=E elseif D==4 then self.callbacks.onButtonPress=E elseif D==5 then self.callbacks.onFailedButtonPress=E end end;function Menu:set(y,aJ)for w,aI in pairs(y)do assert(getmetatable(aI)==Button,'Menu.set: you can only attach buttons to menus.')end;local aK=math.abs(self.pos.x2-self.pos.x1)+1;local aL=math.abs(self.pos.y2-self.pos.y1)+1;for aH=aL+1,#y do table.remove(y,aL+1)end;local aM=math.floor(aL/#y)local aN=math.min(self.pos.x1,self.pos.x2)local aO=math.max(self.pos.x1,self.pos.x2)local aP=math.min(self.pos.y1,self.pos.y2)local aQ=math.max(self.pos.y1,self.pos.y2)for w,aI in pairs(y)do aI.pos.x1=aN;aI.pos.x2=aO;if aJ then aI.pos.y1=aP+(w-1)*aM;aI.pos.y2=aP+(w-1)*aM+aM-1 else aI.pos.y1=aP+w-1;aI.pos.y2=aP+w-1 end;aI.text=string.sub(aI.text,0,aK)table.insert(self.objs,aI)end end;function Menu:touch(Y,Z,D,av)assert(type(Y)=='number','Menu.touch: x must be a number, got '..type(Y))assert(type(Z)=='number','Menu.touch: y must be a number, got '..type(Z))if not self.hidden then if not av then if checkAreaPress(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2,Y,Z)then self.callbacks.onPress(self,D)local aR=false;for w,aI in pairs(self.objs)do if aI:touch(Y,Z,D,aR)then self.callbacks.onButtonPress(self,aI,D,av)aR=true else self.callbacks.onFailedButtonPress(self,aI,D,av)end end;return aR else self.callbacks.onFailedPress(self,D,av)return false end else self.callbacks.onFailedPress(self,D,av)end end;return false end;function Menu:hide(L)assert(type(L)=='boolean','Menu.hide: bool must be a boolean, got '..type(L))self.hidden=L end;Menu.__index=Menu;PercentageBar={}function PercentageBar.new(ae,af,ag,ah,B,aS,aT,at)at=at or{}if at[1]~=nil then at.drawValue=at[1]at[1]=nil end;if at[2]~=nil then at.valueColor=at[2]at[2]=nil end;if at[3]~=nil then at.backgroundValueColor=at[3]at[3]=nil end;if at[4]~=nil then at.barColor=at[4]at[4]=nil end;if at[5]~=nil then at.backgroundBarColor=at[5]at[5]=nil end;assert(type(ae)=='number','PercentageBar.new: x1 must be a number, got '..type(ae))assert(type(af)=='number','PercentageBar.new: y1 must be a number, got '..type(af))assert(type(ag)=='number','PercentageBar.new: x2 must be a number, got '..type(ag))assert(type(ah)=='number','PercentageBar.new: y2 must be a number, got '..type(ah))assert(type(B)=='number','PercentageBar.new: value must be a number, got '..type(B))assert(type(aS)=='number','PercentageBar.new: min must be a number, got '..type(aS))assert(type(aT)=='number','PercentageBar.new: max must be a number, got '..type(aT))assert(type(at)=='table','PercentageBar.new: args must be a table or nil, got '..type(at))local aU={hidden=false,value={draw=at.drawValue,drawOnPB=true,percentage=nil,current=nil,max=aT,min=aS},pos={x1=ae,y1=af,x2=ag,y2=ah},colors={valueColor=tonumber(at.valueColor)or globalTextColor,backgroundValueColor=tonumber(at.backgroundValueColor),barColor=tonumber(at.barColor)or globalColor,backgroundBarColor=tonumber(at.backgroundBarColor)},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end}}PercentageBar.setValue(aU,B)setmetatable(aU,PercentageBar)return aU end;function PercentageBar:draw()if not self.hidden then self.callbacks.onDraw(self)local ax=globalRectangleType;local W=globalColor;local k=globalTextColor;local V=globalBackgroundTextColor;local az=globalMonitor.getBackgroundColor()setRectangleType(rectangleTypes.filled)local aV=self.pos.x1+(self.pos.x2-self.pos.x1)*self.value.percentage/100;if self.colors.backgroundBarColor then setColor(self.colors.backgroundBarColor)rectangle(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2)if self.value.percentage>0 then setColor(self.colors.barColor)rectangle(self.pos.x1,self.pos.y1,aV,self.pos.y2)end else if self.value.percentage>0 then setColor(self.colors.barColor)rectangle(self.pos.x1,self.pos.y1,aV,self.pos.y2)end end;if self.value.draw then local aW=self.value.percentage..'%'local aX=self.pos.x1+math.floor((self.pos.x2-self.pos.x1-string.len(aW)+1)/2)local aY;if self.value.drawOnPB then aY=self.pos.y1+math.floor((self.pos.y2-self.pos.y1)/2)else if self.pos.y1>self.pos.y2 then aY=self.pos.y1+1 else aY=self.pos.y2+1 end end;setTextColor(self.colors.valueColor)if self.colors.backgroundValueColor then setBackgroundTextColor(self.colors.backgroundValueColor)text(aX,aY,aW)else if self.value.drawOnPB then if self.colors.backgroundBarColor then setBackgroundTextColor(self.colors.backgroundBarColor)else setBackgroundTextColor(az)end;if self.pos.x1<self.pos.x2 then local aZ=math.floor(aV)-aX+1;if aZ<0 then aZ=0 elseif aZ>string.len(aW)then aZ=string.len(aW)end;if aZ<string.len(aW)then text(aX,aY,aW)end;if aZ>0 then setBackgroundTextColor(self.colors.barColor)text(aX,aY,string.sub(aW,1,aZ))end else local aZ=aX+string.len(aW)-math.ceil(aV)if aZ<0 then aZ=0 elseif aZ>string.len(aW)then aZ=string.len(aW)end;if aZ<string.len(aW)then text(aX,aY,aW)end;if aZ>0 then setBackgroundTextColor(self.colors.barColor)text(aX+string.len(aW)-aZ,aY,string.sub(aW,-aZ))end end else setBackgroundTextColor(az)text(aX,aY,self.value.percentage..'%')end end end;setRectangleType(ax)setColor(W)setTextColor(k)setBackgroundTextColor(V)end end;function PercentageBar:setCallback(D,E)assert(type(E)=='function','PercentageBar.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onDraw=E elseif D==2 then self.callbacks.onPress=E elseif D==3 then self.callbacks.onFailedPress=E end end;function PercentageBar:setValue(B)assert(type(B)=='number','PercentageBar.setValue: value must be a number, got '..type(B))if B<self.value.min then B=self.value.min end;if B>self.value.max then B=self.value.max end;self.value.current=B;self.value.percentage=math.floor((self.value.current-self.value.min)/(self.value.max-self.value.min)*100)end;function PercentageBar:touch(Y,Z,D,av)assert(type(Y)=='number','PercentageBar.touch: x must be a number, got '..type(Y))assert(type(Z)=='number','PercentageBar.touch: y must be a number, got '..type(Z))if not self.hidden then if not av then if checkAreaPress(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2,Y,Z)then self.callbacks.onPress(self,D,av)return true else self.callbacks.onFailedPress(self,D,av)return false end else self.callbacks.onFailedPress(self,D,av)end end;return false end;function PercentageBar:hide(L)assert(type(L)=='boolean','PercentageBar.hide: bool must be a boolean, got '..type(L))self.hidden=L end;PercentageBar.__index=PercentageBar;Memo={}function Memo.new(ae,af,ag,ah,at)at=at or{}if at[1]~=nil then at.textColor=at[1]at[1]=nil end;if at[2]~=nil then at.backgroundTextColor=at[2]at[2]=nil end;if at[3]~=nil then at.color=at[3]at[3]=nil end;if at[4]~=nil then at.cursorColor=at[4]at[4]=nil end;assert(type(ae)=='number','Memo.new: x1 must be a number, got '..type(ae))assert(type(af)=='number','Memo.new: y1 must be a number, got '..type(af))assert(type(ag)=='number','Memo.new: x2 must be a number, got '..type(ag))assert(type(ah)=='number','Memo.new: y2 must be a number, got '..type(ah))assert(type(at)=='table','Memo.new: args must be a table or nil, got '..type(at))local a_={active=false,hidden=false,selfLoop=false,lines={},pos={x1=ae,y1=af,x2=ag,y2=ah},editSettings={editable=true,charEvent=true,keyEvent=true},cursor={text=' ',colors={textColor=tonumber(at.textColor)or globalTextColor,backgroundTextColor=tonumber(at.cursorColor)or colors.white},visible=false,blink={automatic=true,enabled=false,clock=os.clock(),speed=0.5},pos={char=1,line=1},limits={enabled=true,char=math.abs(ag-ae)+1,line=math.abs(ah-af)+1}},colors={textColor=tonumber(at.textColor)or globalTextColor,backgroundTextColor=tonumber(at.backgroundTextColor),color=tonumber(at.color)or globalColor},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end,onEdit=function()end,onCursorBlink=function()end,onActivated=function()end,onDeactivated=function()end}}setmetatable(a_,Memo)return a_ end;function Memo:draw()if not self.hidden then self.callbacks.onDraw(self)local ax=globalRectangleType;local W=globalColor;local k=globalTextColor;local V=globalBackgroundTextColor;local az=globalMonitor.getBackgroundColor()local b0=math.min(self.pos.x1,self.pos.x2)local b1=math.max(self.pos.x1,self.pos.x2)local b2=math.min(self.pos.y1,self.pos.y2)local b3=math.max(self.pos.y1,self.pos.y2)setRectangleType(rectangleTypes.filled)setColor(self.colors.color)setTextColor(self.colors.textColor)if self.colors.backgroundTextColor then setBackgroundTextColor(self.colors.backgroundTextColor)else setBackgroundTextColor(self.colors.color)end;rectangle(b0,b2,b1,b3)local b4=b1-b0;local b5=b3-b2;local b6={x=self.cursor.pos.char-1,y=self.cursor.pos.line-1}if b6.x>b4 then b6.x=b4 elseif b6.x<0 then b6.x=0 end;if b6.y>b5 then b6.y=b5 elseif b6.y<0 then b6.y=0 end;for aH=0,math.abs(b3-b2)do if self.cursor.pos.line-1<=b5 then if self.lines[aH+1]then if self.cursor.pos.char-1<=b4 then text(b0,b2+aH,string.sub(self.lines[aH+1],1,b4+1))else text(b0,b2+aH,string.sub(self.lines[aH+1],self.cursor.pos.char-b4,self.cursor.pos.char))end end else if self.lines[aH+self.cursor.pos.line-b5]then if self.cursor.pos.char-1<=b4 then text(b0,b2+aH,string.sub(self.lines[aH+self.cursor.pos.line-b5],1,b4+1))else text(b0,b2+aH,string.sub(self.lines[aH+self.cursor.pos.line-b5],self.cursor.pos.char-b4,self.cursor.pos.char))end end end end;if self.cursor.visible then setTextColor(self.cursor.colors.textColor)setBackgroundTextColor(self.cursor.colors.backgroundTextColor)text(b0+b6.x,b2+b6.y,self.cursor.text)end;setRectangleType(ax)setColor(W)setTextColor(k)setBackgroundTextColor(V)end end;function Memo:setCallback(D,E)assert(type(E)=='function','Memo.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onDraw=E elseif D==2 then self.callbacks.onPress=E elseif D==3 then self.callbacks.onFailedPress=E elseif D==4 then self.callbacks.onEdit=E elseif D==5 then self.callbacks.onCursorBlink=E elseif D==6 then self.callbacks.onActivated=E elseif D==7 then self.callbacks.onDeactivated=E end end;function Memo:setCursorLimits(b7,b8)assert(type(b7)=='number'or type(b7)=='nil','Memo.setCursorLimits: char must be a number or nil, got '..type(b7))assert(type(b8)=='number'or type(b8)=='nil','Memo.setCursorLimits: line must be a number or nil, got '..type(b8))self.cursor.limits.char=b7;self.cursor.limits.line=b8 end;function Memo:setCursorPos(b7,b8,b9)assert(type(b7)=='number','Memo.setCursorPos: char must be a number, got '..type(b7))assert(type(b8)=='number','Memo.setCursorPos: line must be a number, got '..type(b8))if b7<1 then b7=1 end;if b8<1 then b8=1 end;if self.cursor.limits.enabled then if self.cursor.limits.char then if b7>self.cursor.limits.char+1 then b7=self.cursor.limits.char+1 end end;if self.cursor.limits.line then if b8>self.cursor.limits.line then b8=self.cursor.limits.line end end end;if not self.lines[b8]then if b9 then for aH=#self.lines+1,b8 do table.insert(self.lines,'')end else if#self.lines>0 then b8=#self.lines else b8=1 end end end;if self.lines[b8]then if b7>#self.lines[b8]+1 then b7=#self.lines[b8]+1 end else b7=1 end;self.cursor.pos.char=b7;self.cursor.pos.line=b8 end;function Memo:edit(D)if not self.editSettings.editable then return end;if not self.hidden then local function ba(event)if not event then return false end;if not self.lines[1]then self:setCursorPos(1,1,true)end;self.callbacks.onEdit(self,event)if self.cursor.limits.enabled then if self.cursor.limits.line then if#self.lines>self.cursor.limits.line then for aH=self.cursor.limits.line+1,#self.lines+1 do table.remove(self.lines,self.cursor.limits.line)end end end;for w,x in pairs(self.lines)do if self.cursor.limits.char then if#x>self.cursor.limits.char then self.lines[w]=x:sub(1,self.cursor.limits.char)end end end end;if event[1]=='monitor_touch'and(event[2]==globalMonitorName or globalMonitorGroup.enabled and tableHasValue(globalMonitorGroup.list,event[2]))then if checkAreaPress(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2,event[3],event[4])then return true else return false end elseif event[1]=='mouse_click'and(globalMonitorName=='term'or globalMonitorGroup.enabled and tableHasValue(globalMonitorGroup.list,'term'))then if checkAreaPress(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2,event[3],event[4])then return true else return false end elseif event[1]=='char'and self.editSettings.charEvent then self:write(tostring(event[2]))elseif event[1]=='key'and self.editSettings.keyEvent then local bb=self.lines[self.cursor.pos.line]if event[2]==28 then self:write('\n')elseif event[2]==14 then if self.cursor.pos.char>1 then self.lines[self.cursor.pos.line]=bb:sub(0,self.cursor.pos.char-2)..bb:sub(self.cursor.pos.char,#bb)self:setCursorPos(self.cursor.pos.char-1,self.cursor.pos.line)elseif self.cursor.pos.line>1 then local bc=#self.lines[self.cursor.pos.line-1]if self.cursor.limits.enabled then if self.cursor.limits.char then if bc+#bb<=self.cursor.limits.char then self.lines[self.cursor.pos.line-1]=self.lines[self.cursor.pos.line-1]..bb:sub(self.cursor.pos.char,#bb)table.remove(self.lines,self.cursor.pos.line)self:setCursorPos(bc+1,self.cursor.pos.line-1)end else self.lines[self.cursor.pos.line-1]=self.lines[self.cursor.pos.line-1]..bb:sub(self.cursor.pos.char,#bb)table.remove(self.lines,self.cursor.pos.line)self:setCursorPos(bc+1,self.cursor.pos.line-1)end else self.lines[self.cursor.pos.line-1]=self.lines[self.cursor.pos.line-1]..bb:sub(self.cursor.pos.char,#bb)table.remove(self.lines,self.cursor.pos.line)self:setCursorPos(bc+1,self.cursor.pos.line-1)end end elseif event[2]==211 then if self.cursor.pos.char>#bb then if self.lines[self.cursor.pos.line+1]then if self.cursor.limits.enabled then if self.cursor.limits.char then if#self.lines[self.cursor.pos.line+1]+#bb<=self.cursor.limits.char then self.lines[self.cursor.pos.line]=bb..self.lines[self.cursor.pos.line+1]table.remove(self.lines,self.cursor.pos.line+1)end else self.lines[self.cursor.pos.line]=bb..self.lines[self.cursor.pos.line+1]table.remove(self.lines,self.cursor.pos.line+1)end else self.lines[self.cursor.pos.line]=bb..self.lines[self.cursor.pos.line+1]table.remove(self.lines,self.cursor.pos.line+1)end end else self.lines[self.cursor.pos.line]=bb:sub(0,self.cursor.pos.char-1)..bb:sub(self.cursor.pos.char+1,#bb)end elseif event[2]==203 then if self.cursor.pos.char==1 then if self.cursor.pos.line>1 then self:setCursorPos(#self.lines[self.cursor.pos.line-1]+1,self.cursor.pos.line-1)end else self:setCursorPos(self.cursor.pos.char-1,self.cursor.pos.line)end elseif event[2]==205 then if self.cursor.limits.enabled and self.cursor.limits.char then if self.cursor.pos.char>=self.cursor.limits.char and self.lines[self.cursor.pos.line+1]then self:setCursorPos(1,self.cursor.pos.line+1)else self:setCursorPos(self.cursor.pos.char+1,self.cursor.pos.line)end else self:setCursorPos(self.cursor.pos.char+1,self.cursor.pos.line)end elseif event[2]==200 then self:setCursorPos(self.cursor.pos.char,self.cursor.pos.line-1)elseif event[2]==208 then self:setCursorPos(self.cursor.pos.char,self.cursor.pos.line+1)end end;return true end;if not self.selfLoop then ba(D)else self.active=true;while self.active do local bd=os.startTimer(self.cursor.blink.speed/2)D={os.pullEvent()}if not ba(D)then break end;self:draw()if globalMonitorBuffer.enabled then globalMonitorBuffer.draw()end;if self.cursor.blink.enabled then if os.clock()>=self.cursor.blink.clock+self.cursor.blink.speed then self.cursor.blink.clock=os.clock()self.callbacks.onCursorBlink(self,D)self.cursor.visible=not self.cursor.visible end end;os.cancelTimer(bd)end end end end;function Memo:touch(Y,Z,D,av)assert(type(Y)=='number','Memo.touch: x must be a number, got '..type(Y))assert(type(Z)=='number','Memo.touch: y must be a number, got '..type(Z))if not self.hidden then if not av and checkAreaPress(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2,Y,Z)then self.callbacks.onPress(self,D,av)self.active=true;self.callbacks.onActivated(self,D,av)if self.selfLoop then self.cursor.blink.enabled=true;self.cursor.visible=true;self:edit(D)self.active=false;self.callbacks.onDeactivated(self,D,av)self.cursor.blink.enabled=false;self.cursor.visible=false elseif self.editSettings.editable and self.cursor.blink.automatic then self.cursor.blink.enabled=true;self.cursor.visible=true end;return true else self.callbacks.onFailedPress(self,D,av)if self.active then self.active=false;self.callbacks.onDeactivated(self,D,av)if self.editSettings.editable and self.cursor.blink.automatic then self.cursor.blink.enabled=false;self.cursor.visible=false end end;return false end end;if self.active then self.active=false;self.callbacks.onDeactivated(self,D,av)end;return false end;function Memo:tick(D)if not self.hidden then if not self.selfLoop then if self.cursor.blink.enabled then if os.clock()>=self.cursor.blink.clock+self.cursor.blink.speed then self.cursor.blink.clock=os.clock()self.callbacks.onCursorBlink(self,D)self.cursor.visible=not self.cursor.visible end end end end end;function Memo:key(D)if not self.hidden then if not self.selfLoop then if self.active then self:edit(D)end end end end;function Memo:char(D)if not self.hidden then if not self.selfLoop then if self.active then self:edit(D)end end end end;function Memo:write(o)if not o then o=''end;o=tostring(o)if not self.lines[1]then self:setCursorPos(1,1,true)end;self.callbacks.onEdit(self,{'write',o})local a1=stringSplit(o,'\n')for w,line in pairs(a1)do if w~=1 then local bb=self.lines[self.cursor.pos.line]local be=bb:sub(self.cursor.pos.char)self.lines[self.cursor.pos.line]=bb:sub(0,self.cursor.pos.char-1)table.insert(self.lines,self.cursor.pos.line+1,be)self:setCursorPos(1,self.cursor.pos.line+1)end;local bb=self.lines[self.cursor.pos.line]if self.cursor.limits.enabled and self.cursor.limits.char then line=line:sub(0,self.cursor.limits.char-#bb)bb=bb:sub(0,self.cursor.pos.char-1)..line..bb:sub(self.cursor.pos.char,#bb)else bb=bb:sub(0,self.cursor.pos.char-1)..line..bb:sub(self.cursor.pos.char,#bb)end;self.lines[self.cursor.pos.line]=bb;self:setCursorPos(self.cursor.pos.char+#line,self.cursor.pos.line)end end;function Memo:print(o)if not o then o=''end;o=tostring(o)self:write(o..'\n')end;function Memo:clear()self.cursor.pos.char=1;self.cursor.pos.line=1;self.lines={}end;function Memo:enableSelfLoop(L)assert(type(L)=='boolean','Memo.enableSelfLoop: bool must be a boolean, got '..type(L))self.selfLoop=L end;function Memo:limits(L)assert(type(L)=='boolean','Memo.limits: bool must be a boolean, got '..type(L))self.cursor.limits.enabled=L end;function Memo:editable(L)assert(type(L)=='boolean','Memo.editable: bool must be a boolean, got '..type(L))self.editSettings.editable=L end;function Memo:hide(L)assert(type(L)=='boolean','Memo.hide: bool must be a boolean, got '..type(L))self.hidden=L end;Memo.__index=Memo;Window={}function Window.new(ae,af,ag,ah,at)at=at or{}if at[1]~=nil then at.color=at[1]at[1]=nil end;assert(type(ae)=='number','Window.new: x1 must be a number, got '..type(ae))assert(type(af)=='number','Window.new: y1 must be a number, got '..type(af))assert(type(ag)=='number','Window.new: x2 must be a number, got '..type(ag))assert(type(ah)=='number','Window.new: y2 must be a number, got '..type(ah))assert(type(at)=='table','Window.new: args must be a table or nil, got '..type(at))local bf={active=false,hidden=false,color=tonumber(at.color)or term.getBackgroundColor(),grabbedFrom={x=1,y=1},shadow={enabled=true,color=colors.black,offset={x=1,y=1}},objs={list={},events={draw={},touch={},tick={},key={},char={},mouse_drag={}}},pos={x1=ae,y1=af,x2=ag,y2=ah},callbacks={onDraw=function()end,onPress=function()end,onFailedPress=function()end,onOBJPress=function()end,onFailedOBJPress=function()end,onEvent=function()end}}setmetatable(bf,Window)return bf end;function Window:draw()if not self.hidden then self.callbacks.onDraw(self)local ax=globalRectangleType;local W=globalColor;setRectangleType(rectangleTypes.filled)if self.shadow.enabled then setColor(self.shadow.color)local bg=self.shadow.offset.x;local bh=self.shadow.offset.y;local a2=self.pos.x1+bg;local a4=self.pos.x2+bg;local a3=self.pos.y1+bh;local a5=self.pos.y2+bh;rectangle(a2,a3,a4,a5)end;setColor(self.color)rectangle(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2)setRectangleType(ax)setColor(W)for H,aI in pairs(self.objs.events.draw)do aI:draw()end end end;function Window:setCallback(D,E)assert(type(E)=='function','Window.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onDraw=E elseif D==2 then self.callbacks.onPress=E elseif D==3 then self.callbacks.onFailedPress=E elseif D==4 then self.callbacks.onOBJPress=E elseif D==5 then self.callbacks.onFailedOBJPress=E elseif D==6 then self.callbacks.onEvent=E end end;function Window:set(bi,bj)assert(type(bi)=='table','Window.set: objGroup must be a table, got '..type(bi))self.objs.list=bi;local a2=math.min(self.pos.x1,self.pos.x2)local a3=math.min(self.pos.y1,self.pos.y2)for H,aI in pairs(self.objs.list)do aI.parent=self;if bj then if aI.pos then if aI.pos.x1 then aI.pos.x1=aI.pos.x1+a2-1 end;if aI.pos.x2 then aI.pos.x2=aI.pos.x2+a2-1 end;if aI.pos.y1 then aI.pos.y1=aI.pos.y1+a3-1 end;if aI.pos.y2 then aI.pos.y2=aI.pos.y2+a3-1 end;if aI.pos.x then aI.pos.x=aI.pos.x+a2-1 end;if aI.pos.y then aI.pos.y=aI.pos.y+a3-1 end end end end;self.objs.events=getOBJSEvents(bi)end;function Window:touch(Y,Z,D,av)assert(type(Y)=='number','Window.touch: x must be a number, got '..type(Y))assert(type(Z)=='number','Window.touch: y must be a number, got '..type(Z))if not self.hidden then self.callbacks.onEvent(self,D)if not av then if checkAreaPress(self.pos.x1,self.pos.y1,self.pos.x2,self.pos.y2,Y,Z)then self.active=true;self.grabbedFrom.x=Y;self.grabbedFrom.y=Z;self.callbacks.onPress(self,D,av)local aR=false;for H,aI in pairs(self.objs.events.touch)do if aI:touch(Y,Z,D,aR)then self.callbacks.onOBJPress(self,aI,D,av)aR=true else self.callbacks.onFailedOBJPress(self,aI,D,av)end end;return true else self.active=false;self.callbacks.onFailedPress(self,D,av)return false end else self.active=false;self.callbacks.onFailedPress(self,D,av)end end;return false end;function Window:mouse_drag(D)if not self.hidden then self.callbacks.onEvent(self,D)if self.active then local bk=D[3]-self.grabbedFrom.x;local bl=D[4]-self.grabbedFrom.y;self.grabbedFrom.x=D[3]self.grabbedFrom.y=D[4]self.pos.x1=self.pos.x1+bk;self.pos.x2=self.pos.x2+bk;self.pos.y1=self.pos.y1+bl;self.pos.y2=self.pos.y2+bl;for H,aI in pairs(self.objs.list)do if aI.pos then if aI.pos.x then aI.pos.x=aI.pos.x+bk end;if aI.pos.x1 then aI.pos.x1=aI.pos.x1+bk end;if aI.pos.x2 then aI.pos.x2=aI.pos.x2+bk end;if aI.pos.y then aI.pos.y=aI.pos.y+bl end;if aI.pos.y1 then aI.pos.y1=aI.pos.y1+bl end;if aI.pos.y2 then aI.pos.y2=aI.pos.y2+bl end end end end end end;function Window:tick(D)if not self.hidden then self.callbacks.onEvent(self,D)for w,aI in pairs(self.objs.events.tick)do aI:tick(D)end end end;function Window:key(D)if not self.hidden then self.callbacks.onEvent(self,D)for w,aI in pairs(self.objs.events.key)do aI:key(D)end end end;function Window:char(D)if not self.hidden then self.callbacks.onEvent(self,D)for w,aI in pairs(self.objs.events.char)do aI:char(D)end end end;function Window:hide(L)assert(type(L)=='boolean','Window.hide: bool must be a boolean, got '..type(L))self.hidden=L end;Window.__index=Window;OBJGroup={}function OBJGroup.new()local bm={objs={list={},events={draw={},touch={},tick={},key={},char={},mouse_drag={}}},hidden=false,callbacks={onDraw=function()end,onOBJPress=function()end,onFailedOBJPress=function()end}}setmetatable(bm,OBJGroup)return bm end;function OBJGroup:draw()if not self.hidden then self.callbacks.onDraw(self)for H,aI in pairs(self.objs.events.draw)do aI:draw()end end end;function OBJGroup:setCallback(D,E)assert(type(E)=='function','OBJGroup.setCallback: callback must be a function, got '..type(E))if D==1 then self.callbacks.onDraw=E elseif D==2 then self.callbacks.onOBJPress=E elseif D==3 then self.callbacks.onFailedOBJPress=E end end;function OBJGroup:set(bi)assert(type(bi)=='table','OBJGroup.set: objGroup must be a table, got '..type(bi))self.objs.list=bi;for H,aI in pairs(self.objs.list)do aI.parent=self end;self.objs.events=getOBJSEvents(bi)end;function OBJGroup:touch(Y,Z,D,av)assert(type(Y)=='number','OBJGroup.touch: x must be a number, got '..type(Y))assert(type(Z)=='number','OBJGroup.touch: y must be a number, got '..type(Z))if not self.hidden then if not av then local aR=false;for H,aI in pairs(self.objs.events.touch)do if aI:touch(Y,Z,D,aR)then self.callbacks.onOBJPress(self,aI,D,av)aR=true else self.callbacks.onFailedOBJPress(self,aI,D,av)end end;return aR end end;return false end;function OBJGroup:tick(D)if not self.hidden then for w,aI in pairs(self.objs.events.tick)do aI:tick(D)end end end;function OBJGroup:key(D)if not self.hidden then for w,aI in pairs(self.objs.events.key)do aI:key(D)end end end;function OBJGroup:char(D)if not self.hidden then for w,aI in pairs(self.objs.events.char)do aI:char(D)end end end;function OBJGroup:mouse_drag(D)if not self.hidden then for w,aI in pairs(self.objs.events.mouse_drag)do aI:mouse_drag(D)end end end;function OBJGroup:hide(L)assert(type(L)=='boolean','OBJGroup.hide: bool must be a boolean, got '..type(L))self.hidden=L end;OBJGroup.__index=OBJGroup;globalLoop.stats.FPS=Label.new(0,0,{text='0FPS',transparentBG=true})globalLoop.stats.EPS=Label.new(0,0,{text='0EPS',transparentBG=true})globalLoop.stats.FPS.hidden=true;globalLoop.stats.EPS.hidden=true;table.insert(globalLoop.group.LIBPrivate.objs,globalLoop.stats.FPS)table.insert(globalLoop.group.LIBPrivate.objs,globalLoop.stats.EPS)function drawOnLoopClock()globalLoop.drawOnClock=true end;function drawOnLoopEvent()globalLoop.drawOnClock=false end;function drawLoopStats(L)assert(type(L)=='boolean','enableLoopStats: bool must be a boolean, got '..type(L))if L and globalLoop.stats.automaticPos then local bn=globalLoop.stats.automaticPosOffset.x;local bo=globalLoop.stats.automaticPosOffset.y;globalLoop.stats.FPS.pos.x=globalMonitorWidth-#globalLoop.stats.FPS.text+1+bn;globalLoop.stats.FPS.pos.y=globalMonitorHeight-1+bo;globalLoop.stats.EPS.pos.x=globalMonitorWidth-#globalLoop.stats.EPS.text+1+bn;globalLoop.stats.EPS.pos.y=globalMonitorHeight+bo end;globalLoop.stats.FPS.hidden=not L;globalLoop.stats.EPS.hidden=not L end;function setLoopClockSpeed(bp)assert(type(bp)=='number','setLoopClockSpeed: sec must be a number, got '..type(bp))globalLoop.clockSpeed=bp end;function setLoopTimerSpeed(bp)assert(type(bp)=='number','setLoopTimerSpeed: sec must be a number, got '..type(bp))globalLoop.timerSpeed=bp end;function setLoopCallback(D,E)assert(type(E)=='function','setLoopCallback: callback must be a function, got '..type(E))if D==1 then globalLoop.callbacks.onInit=E elseif D==2 then globalLoop.callbacks.onStop=E elseif D==3 then globalLoop.callbacks.onClock=E elseif D==4 then globalLoop.callbacks.onEvent=E elseif D==5 then globalLoop.callbacks.onTimer=E elseif D==6 then globalLoop.callbacks.onMonitorChange=E end end;function loopAutoClear(L)assert(type(L)=='boolean','loopAutoClear: bool must be a boolean, got '..type(L))globalLoop.autoClear=L end;function addLoopGroup(bq,br)bq=tostring(bq)assert(bq~='LIBPrivate'or bq~='none',"addLoopGroup: can't overwrite Lib's Private groups")assert(type(br)=='table','addLoopGroup: group must be a table, got '..type(br))globalLoop.group[bq]={callbacks={onClock=function()end,onEvent=function()end,onTimer=function()end,onMonitorChange=function()end,onSet=function()end,onUnset=function()end},objs=br}end;function removeLoopGroup(bq)bq=tostring(bq)assert(bq~='LIBPrivate'or bq~='none',"removeLoopGroup: can't remove Lib's Private groups")globalLoop.group[bq]=nil end;function setLoopGroup(bq)bq=tostring(bq)assert(globalLoop.group[bq],'setLoopGroup: groupName must be a valid group.')local bs=globalLoop.group[globalLoop.selectedGroup]local bt=globalLoop.group[bq]bs.callbacks.onUnset(bs,bt)globalLoop.selectedGroup=bq;bt.callbacks.onSet(bt,bs)globalLoop.wasGroupChanged=true end;function setLoopGroupCallback(bq,D,E)bq=tostring(bq)assert(bq~='LIBPrivate'or bq~='none',"setLoopGroupCallback: can't overwrite Lib's Private groups' callbacks")assert(globalLoop.group[bq],'setLoopGroupCallback: groupName must be a valid group.')assert(type(E)=='function','setLoopGroupCallback: callback must be a function, got '..type(E))if D==1 then globalLoop.group[bq].callbacks.onClock=E elseif D==2 then globalLoop.group[bq].callbacks.onEvent=E elseif D==3 then globalLoop.group[bq].callbacks.onTimer=E elseif D==4 then globalLoop.group[bq].callbacks.onMonitorChange=E elseif D==5 then globalLoop.group[bq].callbacks.onSet=E elseif D==6 then globalLoop.group[bq].callbacks.onUnset=E end end;function resetLoopSettings()globalLoop.APLWDBroadcastOnClock=false;globalLoop.APLWDClearCacheOnDraw=true;globalLoop.stats.FPS.hidden=true;globalLoop.stats.EPS.hidden=true;globalLoop.callbacks.onInit=function()end;globalLoop.callbacks.onEvent=function()end;globalLoop.callbacks.onClock=function()end;globalLoop.selectedGroup='none'globalLoop.group={none={callbacks={onClock=function()end,onEvent=function()end,onTimer=function()end,onMonitorChange=function()end,onSet=function()end,onUnset=function()end},objs={}},LIBPrivate={callbacks={onClock=function()end,onEvent=function()end,onTimer=function()end,onMonitorChange=function()end,onSet=function()end,onUnset=function()end},objs={}}}globalLoop.events={draw={},touch={},tick={},key={},char={},mouse_drag={}}end;function stopLoop()globalLoop.enabled=false;globalLoop.callbacks.onStop()globalLoop.events={draw={},touch={},tick={},key={},char={},mouse_drag={}}end;function loop()globalLoop.enabled=true;if globalLoop.autoClear then bClearMonitorGroup()end;updateLoopEvents()globalLoop.callbacks.onInit()drawLoopOBJs()local bu=Clock.new(1)bu.FPS=0;bu.EPS=0;bu:setCallback(event.clock.onClock,function(self,event)globalLoop.stats.FPS.text=tostring(self.FPS)..'FPS'globalLoop.stats.EPS.text=tostring(self.EPS)..'EPS'if globalLoop.stats.automaticPos then local bn=globalLoop.stats.automaticPosOffset.x;local bo=globalLoop.stats.automaticPosOffset.y;globalLoop.stats.FPS.pos.x=globalMonitorWidth-#globalLoop.stats.FPS.text+1+bn;globalLoop.stats.FPS.pos.y=globalMonitorHeight-1+bo;globalLoop.stats.EPS.pos.x=globalMonitorWidth-#globalLoop.stats.EPS.text+1+bn;globalLoop.stats.EPS.pos.y=globalMonitorHeight+bo end;self.FPS=0;self.EPS=0 end)local bv=os.clock()while globalLoop.enabled do if globalLoop.wasGroupChanged then updateLoopEvents()globalLoop.wasGroupChanged=false end;local bd=os.startTimer(globalLoop.timerSpeed)local event={os.pullEvent()}if event[1]=='monitor_touch'and(event[2]==globalMonitorName or globalMonitorGroup.enabled and tableHasValue(globalMonitorGroup.list,event[2]))then touchLoopOBJs(event[3],event[4],event)elseif event[1]=='mouse_click'and(globalMonitorName=='term'or globalMonitorGroup.enabled and tableHasValue(globalMonitorGroup.list,'term'))then touchLoopOBJs(event[3],event[4],event)elseif event[1]=='key'then for H,aI in pairs(globalLoop.events.key)do aI:key(event)end elseif event[1]=='char'then for H,aI in pairs(globalLoop.events.char)do aI:char(event)end elseif event[1]=='mouse_drag'then for H,aI in pairs(globalLoop.events.mouse_drag)do aI:mouse_drag(event)end elseif event[1]=='timer'then globalLoop.callbacks.onTimer(event)globalLoop.group[globalLoop.selectedGroup].callbacks.onTimer(event)end;globalLoop.clock=os.clock()if globalLoop.clock>=bv+globalLoop.clockSpeed then bv=os.clock()if globalLoop.drawOnClock then if APLWD.enabled and globalLoop.APLWDClearCacheOnDraw then APLWD.clearCache()end;if globalLoop.autoClear and not globalMonitorBuffer.enabled then bClearMonitorGroup()end;globalLoop.callbacks.onClock(event)globalLoop.group[globalLoop.selectedGroup].callbacks.onClock(event)drawLoopOBJs()bu.FPS=bu.FPS+1 else globalLoop.callbacks.onClock(event)globalLoop.group[globalLoop.selectedGroup].callbacks.onClock(event)end;if APLWD.enabled and globalLoop.APLWDBroadcastOnClock then APLWD.broadcastCache()end end;if not globalLoop.drawOnClock then if APLWD.enabled and globalLoop.APLWDClearCacheOnDraw then APLWD.clearCache()end;if globalLoop.autoClear and not globalMonitorBuffer.enabled then bClearMonitorGroup()end;globalLoop.callbacks.onEvent(event)globalLoop.group[globalLoop.selectedGroup].callbacks.onEvent(event)drawLoopOBJs()bu.FPS=bu.FPS+1 else globalLoop.callbacks.onEvent(event)globalLoop.group[globalLoop.selectedGroup].callbacks.onEvent(event)end;for H,aI in pairs(globalLoop.events.tick)do aI:tick(event)end;bu:tick()bu.EPS=bu.EPS+1;os.cancelTimer(bd)end end;function getOBJSEvents(y)assert(type(y)=='table','getOBJSEvents: table must be a table, got '..type(y))local bw={draw={},touch={},tick={},key={},char={},mouse_drag={}}for H,aI in pairs(y)do if aI.draw then table.insert(bw.draw,1,aI)end;if aI.touch then table.insert(bw.touch,aI)end;if aI.tick then table.insert(bw.tick,aI)end;if aI.key then table.insert(bw.key,aI)end;if aI.char then table.insert(bw.char,aI)end;if aI.mouse_drag then table.insert(bw.mouse_drag,aI)end end;return bw end;function updateLoopEvents()local bx={}for H,aI in pairs(globalLoop.group.LIBPrivate.objs)do table.insert(bx,aI)end;for H,aI in pairs(globalLoop.group[globalLoop.selectedGroup].objs)do table.insert(bx,aI)end;globalLoop.events=getOBJSEvents(bx)end;function drawLoopOBJs()if globalMonitorGroup.enabled then if globalMonitorBuffer.enabled then globalMonitorBuffer.clear()end;globalLoop.callbacks.onMonitorChange(monitorName)globalLoop.group[globalLoop.selectedGroup].callbacks.onMonitorChange(monitorName)for w,aI in pairs(globalLoop.events.draw)do aI:draw()end;if globalMonitorBuffer.enabled then globalMonitorBuffer.draw()end;local F=APLWD.cacheWritable;if APLWD.enabled and F then APLWD.cacheWritable=false end;local G=globalMonitorName;for H,monitorName in pairs(globalMonitorGroup.list)do if monitorName~=G then setMonitor(monitorName)globalLoop.callbacks.onMonitorChange(monitorName)globalLoop.group[globalLoop.selectedGroup].callbacks.onMonitorChange(monitorName)if globalMonitorBuffer.enabled then globalMonitorBuffer.draw()else for w,aI in pairs(globalLoop.events.draw)do aI:draw()end end end end;setMonitor(G)if APLWD.enabled and F then APLWD.cacheWritable=true end else if globalMonitorBuffer.enabled then globalMonitorBuffer.clear()end;for w,aI in pairs(globalLoop.events.draw)do aI:draw()end;if globalMonitorBuffer.enabled then globalMonitorBuffer.draw()end end end;function touchLoopOBJs(Y,Z,D)assert(type(Y)=='number','touchLoopOBJs: x must be a number, got '..type(Y))assert(type(Z)=='number','touchLoopOBJs: y must be a number, got '..type(Z))local by=false;for H,aI in pairs(globalLoop.events.touch)do if aI:touch(Y,Z,D,by)then by=true end end end;local bz={...}if table.maxn(bz)>0 then bz[1]=string.lower(bz[1])if bz[1]=='ver'then print('Lib version: '..info.ver)elseif bz[1]=='setup'then if shell then local bA='/'..shell.getRunningProgram()OSSettings.set('APLibPath',bA)print('Setup completed!\nAPLibPath: '..tostring(settings.get('APLibPath')))sleep(2)os.reboot()else error('Setup failed, shell API not available!')end elseif bz[1]=='create'then if bz[2]then local _='\n-- //AUTO-GENERATED-CODE//\nlocal APLibPath = settings.get(\'APLibPath\')\n\nassert( -- check if setup was done before, if not return with an error\n type(APLibPath) == \'string\',\n \'Couldn\\\'t open APLib through path: \'..tostring(\n APLibPath\n )..\'; probably you haven\\\'t completed Lib setup via \\\'LIBFILE setup\\\' or the setup failed\'\n)\n\nassert( -- check if Lib is still there, if not return with an error\n fs.exists(APLibPath),\n \'Couldn\\\'t open APLib through path: \'..tostring(\n APLibPath\n )..\'; remember that if you move the Lib\\\'s folder you must set it up again via \\\'LIBFILE setup\\\'\'\n)\n\nos.loadAPI(APLibPath) -- load Lib with CraftOS\'s built-in feature\n\nAPLibPath = fs.getName(APLibPath)\nif APLibPath:sub(#APLibPath - 3) == \'.lua\' then APLibPath = APLibPath:sub(1, #APLibPath - 4); end\nlocal APLib = _ENV[APLibPath]\nAPLib.APLibPath = APLibPath\nAPLibPath = nil\n-- //MAIN-PROGRAM//\n\n\n\n-- //AUTO-GENERATED-CODE//\nos.unloadAPI(APLib.APLibPath)\n-- //--//'local bB=bz[2]if bB:sub(1,1)~='/'then bB='/'..bB end;if fs.exists(bB)then print('Are you sure you want to overwrite: '..bB)print('Press ENTER to confirm or another key to cancel.')local event={os.pullEvent('key')}if event[2]==28 then local bC=fs.open(bB,'w')if bC then bC.write(_)bC.close()print('File succesfully created!')else print('Couldn\'t create file.')end else print('File wasn\'t created!')end else local bC=fs.open(bB,'w')if bC then bC.write(_)bC.close()print('File succesfully created!')else print('Couldn\'t create file.')end end else print('You must specify the name of the file you want to create.')end end end