SHARE
TWEET

oeedPay PocketPay

Oeed Nov 8th, 2014 (edited) 118 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --  Hideously Smashed Together by Compilr, a Hideous Smash-Stuff-Togetherer, (c) 2014 oeed  --
  2.  
  3. --  This file REALLLLLLLY isn't suitable to be used for anything other than being executed --
  4.  
  5. --  To extract all the files, run: "<filename> --extract" in the Shell --
  6. local files = {
  7.   cross = "0f  0   0f \
  8.  0 0f  0 0f  0 \
  9.  0  0f  0  \
  10.  0 0f  0 0f  0 \
  11. 0f  0   0f ",
  12.   startup = "-- oeedPay - (c) oeed 2014 --\
  13. \
  14. -- This program is for a payment point such as a shop or ATM --\
  15. if not pocket then\
  16.         print('This program must be run on a pocket computer!')\
  17. end\
  18. \
  19. if OneOS then\
  20.         OneOS.LoadAPI('/System/API/Wireless.lua')\
  21.         OneOS.LoadAPI('/System/API/Peripheral.lua')\
  22. else\
  23.         os.loadAPI('Peripheral')\
  24.         os.loadAPI('Wireless')\
  25. end\
  26. os.loadAPI('hash')\
  27. \
  28. \
  29. function comma_value(amount)\
  30.   local formatted = amount\
  31.   while true do  \
  32.     formatted, k = string.gsub(formatted, \"^(-?%d+)(%d%d%d)\", '%1,%2')\
  33.     if (k==0) then\
  34.       break\
  35.     end\
  36.   end\
  37.   return formatted\
  38. end\
  39. \
  40. function round(val, decimal)\
  41.   if (decimal) then\
  42.     return math.floor( (val * 10^decimal) + 0.5) / (10^decimal)\
  43.   else\
  44.     return math.floor(val+0.5)\
  45.   end\
  46. end\
  47. \
  48. function formatCurrency(amount, decimal, prefix, neg_prefix)\
  49.   local str_amount,  formatted, famount, remain\
  50.   decimal = decimal or 2  -- default 2 decimal places\
  51.   neg_prefix = neg_prefix or \"-\" -- default negative sign\
  52.   famount = math.abs(round(amount,decimal))\
  53.   famount = math.floor(famount)\
  54. \
  55.   remain = round(math.abs(amount) - famount, decimal)\
  56.   formatted = comma_value(famount)\
  57.   if (decimal > 0) then\
  58.     remain = string.sub(tostring(remain),3)\
  59.     formatted = formatted .. \".\" .. remain ..\
  60.                 string.rep(\"0\", decimal - string.len(remain))\
  61.   end\
  62.   formatted = (prefix or \"\") .. formatted \
  63.   if (amount<0) then\
  64.     if (neg_prefix==\"()\") then\
  65.       formatted = \"(\"..formatted ..\")\"\
  66.     else\
  67.       formatted = neg_prefix .. formatted \
  68.     end\
  69.   end\
  70. \
  71.   return formatted\
  72. end\
  73. \
  74. local bedrockPath='/' if OneOS then OneOS.LoadAPI('/System/API/Bedrock.lua', false)elseif fs.exists(bedrockPath..'/Bedrock')then os.loadAPI(bedrockPath..'/Bedrock')else if http then print('Downloading Bedrock...')local h=http.get('http://pastebin.com/raw.php?i=0MgKNqpN')if h then local f=fs.open(bedrockPath..'/Bedrock','w')f.write(h.readAll())f.close()h.close()os.loadAPI(bedrockPath..'/Bedrock')else error('Failed to download Bedrock. Is your internet working?') end else error('This program needs to download Bedrock to work. Please enable HTTP.') end end if Bedrock then Bedrock.BasePath = bedrockPath Bedrock.ProgramPath = shell.getRunningProgram() end\
  75. \
  76. local program = Bedrock:Initialise()\
  77. \
  78. os.setComputerLabel('PocketPay')\
  79. \
  80. local Current = {\
  81.         Payment = nil,\
  82.         Step = nil\
  83. }\
  84. \
  85. local Account\
  86. local function loadAccount()\
  87.         local f = fs.open('.Account.settings', 'r')\
  88.         if f then\
  89.                 Account = textutils.unserialize(f.readAll())\
  90.                 os.setComputerLabel(Account.Name .. \"'s PocketPay: \"..Account.Number)\
  91.                 f.close()\
  92.         end\
  93. end\
  94. \
  95. program.OnKeyChar = function(self, event, keychar)\
  96.         if keychar == '\\\\' then\
  97.                 os.reboot()\
  98.         end\
  99. end\
  100. \
  101. program:RegisterEvent('modem_message', function(self, event, side, channel, replyChannel, message, distance)\
  102.         Wireless.HandleMessage(event, side, channel, replyChannel, message, distance)\
  103. end)\
  104. \
  105. local refreshTimer\
  106. local timeoutTimer\
  107. \
  108. Wireless.Responder = function(event, side, channel, replyChannel, message, distance)\
  109.         if channel == Wireless.Channels.oeedPayPocketPayPing and Current.Step == 'main'  then\
  110.                 Wireless.SendMessage(replyChannel, 'Pong!')\
  111.                 -- program:LoadView('processing')\
  112.         elseif channel == Wireless.Channels.oeedPayPocketPayPaymentInfo and Current.Step == 'main' then\
  113.                 Current.Payment = message.content\
  114.                 Current.Payment.Requester = message.senderID\
  115.                 Wireless.SendMessage(Wireless.Channels.oeedPayGetAccountName, Current.Payment.Creditor, Wireless.Channels.oeedPayGetAccountNameReply)\
  116.         elseif channel == Wireless.Channels.oeedPayGetAccountNameReply and Current.Step == 'main' then\
  117.                 Current.Payment.CreditorName = message.content\
  118.                 program:LoadView('paymentdue')\
  119.         elseif channel == Wireless.Channels.oeedPayBalanceCheckReply and Current.Step == 'main' then\
  120.                 program:GetObject('StatusLabel').Text = 'Balance: $'..formatCurrency(tonumber(message.content))\
  121.                 program:GetObject('StatusLabel').TextColour = colours.lightGrey\
  122.                 timeoutTimer = program:StopTimer(timeoutTimer)\
  123.         elseif channel == Wireless.Channels.oeedPayPocketPayChallenge and Current.Step == 'processing' and Current.Payment.Requester == message.senderID then\
  124.                 Wireless.SendMessage(Wireless.Channels.oeedPayPocketPayChallengeReply, hash.sha256(Account.Hash .. message.content .. Current.Payment.Value), nil, nil, Current.Payment.Requester)\
  125.         elseif channel == Wireless.Channels.oeedPayPocketPayResult and Current.Step == 'processing' and Current.Payment.Requester == message.senderID then\
  126.                 if message.content == 'FAILED' then\
  127.                         program:LoadView('fail')\
  128.                 elseif message.content == 'SUCCESS' then\
  129.                         program:LoadView('complete')\
  130.                 end\
  131.         end\
  132. end\
  133. \
  134. local tooLongTimer\
  135. \
  136. program.OnViewLoad = function(viewName)\
  137.         Current.Step = viewName\
  138.         refreshTimer = program:StopTimer(refreshTimer)\
  139.         if viewName == 'main' then\
  140.                 Current.Payment = nil\
  141.                 Wireless.SendMessage(Wireless.Channels.oeedPayBalanceCheck, Account.Number)\
  142.                 timeoutTimer = program:StartTimer(function()\
  143.                         program:GetObject('StatusLabel').Text = 'No Connection'\
  144.                         program:GetObject('StatusLabel').TextColour = colours.red\
  145.                 end, 1)\
  146.                 refreshTimer = program:StartTimer(function()\
  147.                         if Current.Step == 'main' then\
  148.                                 program:LoadView('main')\
  149.                         end\
  150.                 end, 60)\
  151.         elseif viewName == 'processing' then\
  152.                 local cols ={\
  153.                         colours.lightBlue,\
  154.                         colours.white,\
  155.                         colours.white,\
  156.                         colours.white,\
  157.                         colours.lightBlue,\
  158.                         colours.blue,\
  159.                 }\
  160.                 local i = 1\
  161.                 program:StartRepeatingTimer(function()\
  162.                         if Current.Step ~= 'processing' then\
  163.                                 program:StopTimer(new)\
  164.                         else\
  165.                                 i = i + 1\
  166.                                 if i > #cols then\
  167.                                         i = 1\
  168.                                 end\
  169.                                 program:GetObject('ProcessingLabel').TextColour = cols[i]\
  170.                         end\
  171.                 end, 0.15)\
  172.         elseif viewName == 'paymentdue' then\
  173.                 tooLongTimer = program:StartTimer(function()\
  174.                         program:LoadView('main')\
  175.                 end, 60)\
  176.                 program:GetObject('AmountLabel').Text = formatCurrency(Current.Payment.Value, 2, '$')\
  177.                 program:GetObject('InfoLabel').Text = \"'\" .. Current.Payment.CreditorName .. \"' is requesting the following payment.\"\
  178.                 program:GetObject('AcceptButton').OnClick = function(self, event, side, x, y)\
  179.                         Wireless.SendMessage(Wireless.Channels.oeedPayPocketPayPaymentInfoReply, {status = 'ACCEPTED', accountNumber = Account.Number}, nil, nil, Current.Payment.Requester)\
  180.                         program:LoadView('processing')\
  181.                 end\
  182.                 program:GetObject('DenyButton').OnClick = function(self, event, side, x, y)\
  183.                         Wireless.SendMessage(Wireless.Channels.oeedPayPocketPayPaymentInfoReply, 'DENIED', nil, nil, Current.Payment.Requester)\
  184.                         program:LoadView('main')\
  185.                 end\
  186.         elseif viewName == 'fail' or viewName == 'complete' then\
  187.                 program:StartTimer(function()\
  188.                         program:LoadView('main')\
  189.                 end, 3)\
  190.         end\
  191. end\
  192. \
  193. loadAccount()\
  194. program:Run(function()\
  195.         -- program:LoadView('processing')\
  196. \
  197.         if Wireless.Present() then\
  198.                 Wireless.Initialise()\
  199.         end\
  200. end)",
  201.   tick = " d      0f \
  202.  d     0f  d \
  203. 0f  d   0f  d  \
  204.  d 0f  d 0f  d   \
  205.  d  0f  d    ",
  206.   Bedrock = "--Bedrock Build: 270\
  207. --This code is squished down in to one, rather hard to read file.\
  208. --As such it is not much good for anything other than being loaded as an API.\
  209. --If you want to look at the code to learn from it, copy parts or just take a look,\
  210. --you should go to the GitHub repo. http://github.com/oeed/Bedrock/\
  211. \
  212. --\
  213. --              Bedrock is the core program framework used by all OneOS and OneCode programs.\
  214. --                                                      Inspired by Apple's Cocoa framework.\
  215. --                                                                         (c) oeed 2014\
  216. --\
  217. --                For documentation see the Bedrock wiki, github.com/oeed/Bedrock/wiki/\
  218. --\
  219. \
  220. local apis = {\
  221. [\"Drawing\"] = [[\
  222. local round = function(num, idp)\
  223.         local mult = 10^(idp or 0)\
  224.         return math.floor(num * mult + 0.5) / mult\
  225. end\
  226. \
  227. local _w, _h = term.getSize()\
  228. local copyBuffer = nil\
  229. \
  230. Screen = {\
  231.         Width = _w,\
  232.         Height = _h\
  233. }\
  234. \
  235. Constraints = {\
  236.         \
  237. }\
  238. \
  239. CurrentConstraint = {1,1,_w,_h}\
  240. IgnoreConstraint = false\
  241. \
  242. function AddConstraint(x, y, width, height)\
  243.         local x2 = x + width - 1\
  244.         local y2 = y + height - 1\
  245.         table.insert(Drawing.Constraints, {x, y, x2, y2})\
  246.         Drawing.GetConstraint()\
  247. end\
  248. \
  249. function RemoveConstraint()\
  250.         --table.remove(Drawing.Constraints, #Drawing.Constraints)\
  251.         Drawing.Constraints[#Drawing.Constraints] = nil\
  252.         Drawing.GetConstraint()\
  253. end\
  254. \
  255. function GetConstraint()\
  256.         local x = 1\
  257.         local y = 1\
  258.         local x2 = Drawing.Screen.Width\
  259.         local y2 = Drawing.Screen.Height\
  260.         for i, c in ipairs(Drawing.Constraints) do\
  261.                 if x < c[1] then\
  262.                         x = c[1]\
  263.                 end\
  264.                 if y < c[2] then\
  265.                         y = c[2]\
  266.                 end\
  267.                 if x2 > c[3] then\
  268.                         x2 = c[3]\
  269.                 end\
  270.                 if y2 > c[4] then\
  271.                         y2 = c[4]\
  272.                 end\
  273.         end\
  274.         Drawing.CurrentConstraint = {x, y, x2, y2}\
  275. end\
  276. \
  277. function WithinContraint(x, y)\
  278.         return Drawing.IgnoreConstraint or\
  279.                   (x >= Drawing.CurrentConstraint[1] and\
  280.                    y >= Drawing.CurrentConstraint[2] and\
  281.                    x <= Drawing.CurrentConstraint[3] and\
  282.                    y <= Drawing.CurrentConstraint[4])\
  283. end\
  284. \
  285. colours.transparent = 0\
  286. colors.transparent = 0\
  287. \
  288. DrawCharacters = function (x, y, characters, textColour, bgColour)\
  289.         Drawing.WriteStringToBuffer(x, y, tostring(characters), textColour, bgColour)\
  290. end\
  291. \
  292. DrawBlankArea = function (x, y, w, h, colour)\
  293.         if colour ~= colours.transparent then\
  294.                 Drawing.DrawArea (x, y, w, h, \" \", 1, colour)\
  295.         end\
  296. end\
  297. \
  298. DrawArea = function (x, y, w, h, character, textColour, bgColour)\
  299.         --width must be greater than 1, otherwise we get problems\
  300.         if w < 0 then\
  301.                 w = w * -1\
  302.         elseif w == 0 then\
  303.                 w = 1\
  304.         end\
  305. \
  306.         for ix = 1, w do\
  307.                 local currX = x + ix - 1\
  308.                 for iy = 1, h do\
  309.                         local currY = y + iy - 1\
  310.                         Drawing.WriteToBuffer(currX, currY, character, textColour, bgColour)\
  311.                 end\
  312.         end\
  313. end\
  314. \
  315. DrawImage = function(_x,_y,tImage, w, h)\
  316.         if tImage then\
  317.                 for y = 1, h do\
  318.                         if not tImage[y] then\
  319.                                 break\
  320.                         end\
  321.                         for x = 1, w do\
  322.                                 if not tImage[y][x] then\
  323.                                         break\
  324.                                 end\
  325.                                 local bgColour = tImage[y][x]\
  326.                     local textColour = tImage.textcol[y][x] or colours.white\
  327.                     local char = tImage.text[y][x]\
  328.                     Drawing.WriteToBuffer(x+_x-1, y+_y-1, char, textColour, bgColour)\
  329.                         end\
  330.                 end\
  331.         elseif w and h then\
  332.                 Drawing.DrawBlankArea(_x, _y, w, h, colours.lightGrey)\
  333.         end\
  334. end\
  335. \
  336. --using .nft\
  337. LoadImage = function(path, global)\
  338.         local image = {\
  339.                 text = {},\
  340.                 textcol = {}\
  341.         }\
  342.         if fs.exists(path) then\
  343.                 local _io = io\
  344.                 if OneOS and global then\
  345.                         _io = OneOS.IO\
  346.                 end\
  347.         local file = _io.open(path, \"r\")\
  348.         if not file then\
  349.                 error('Error Occured. _io:'..tostring(_io)..' OneOS: '..tostring(OneOS)..' OneOS.IO'..tostring(OneOS.IO)..' io: '..tostring(io))\
  350.         end\
  351.         local sLine = file:read()\
  352.         local num = 1\
  353.         while sLine do  \
  354.             table.insert(image, num, {})\
  355.             table.insert(image.text, num, {})\
  356.             table.insert(image.textcol, num, {})\
  357.                                         \
  358.             --As we're no longer 1-1, we keep track of what index to write to\
  359.             local writeIndex = 1\
  360.             --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour\
  361.             local bgNext, fgNext = false, false\
  362.             --The current background and foreground colours\
  363.             local currBG, currFG = nil,nil\
  364.             for i=1,#sLine do\
  365.                     local nextChar = string.sub(sLine, i, i)\
  366.                     if nextChar:byte() == 30 then\
  367.                             bgNext = true\
  368.                     elseif nextChar:byte() == 31 then\
  369.                             fgNext = true\
  370.                     elseif bgNext then\
  371.                             currBG = Drawing.GetColour(nextChar)\
  372.                                     if currBG == nil then\
  373.                                         currBG = colours.transparent\
  374.                                     end\
  375.                             bgNext = false\
  376.                     elseif fgNext then\
  377.                             currFG = Drawing.GetColour(nextChar)\
  378.                                     if currFG == nil or currFG == colours.transparent then\
  379.                                         currFG = colours.white\
  380.                                     end\
  381.                             fgNext = false\
  382.                     else\
  383.                             if nextChar ~= \" \" and currFG == nil then\
  384.                                     currFG = colours.white\
  385.                             end\
  386.                             image[num][writeIndex] = currBG\
  387.                             image.textcol[num][writeIndex] = currFG\
  388.                             image.text[num][writeIndex] = nextChar\
  389.                             writeIndex = writeIndex + 1\
  390.                     end\
  391.             end\
  392.             num = num+1\
  393.             sLine = file:read()\
  394.         end\
  395.         file:close()\
  396.     else\
  397.         return nil\
  398.         end\
  399.         return image\
  400. end\
  401. \
  402. DrawCharactersCenter = function(x, y, w, h, characters, textColour,bgColour)\
  403.         w = w or Drawing.Screen.Width\
  404.         h = h or Drawing.Screen.Height\
  405.         x = x or 0\
  406.         y = y or 0\
  407.         x = math.floor((w - #characters) / 2) + x\
  408.         y = math.floor(h / 2) + y\
  409. \
  410.         Drawing.DrawCharacters(x, y, characters, textColour, bgColour)\
  411. end\
  412. \
  413. GetColour = function(hex)\
  414.         if hex == ' ' then\
  415.                 return colours.transparent\
  416.         end\
  417.     local value = tonumber(hex, 16)\
  418.     if not value then return nil end\
  419.     value = math.pow(2,value)\
  420.     return value\
  421. end\
  422. \
  423. Clear = function (_colour)\
  424.         _colour = _colour or colours.black\
  425.         Drawing.DrawBlankArea(1, 1, Drawing.Screen.Width, Drawing.Screen.Height, _colour)\
  426. end\
  427. \
  428. Buffer = {}\
  429. BackBuffer = {}\
  430. \
  431. TryRestore = false\
  432. \
  433. \
  434. --TODO: make this quicker\
  435. -- maybe sort the pixels in order of colour so it doesn't have to set the colour each time\
  436. DrawBuffer = function()\
  437.         if TryRestore and Restore then\
  438.                 Restore()\
  439.         end\
  440. \
  441.         for y,row in pairs(Drawing.Buffer) do\
  442.                 for x,pixel in pairs(row) do\
  443.                         local shouldDraw = true\
  444.                         local hasBackBuffer = true\
  445.                         if Drawing.BackBuffer[y] == nil or Drawing.BackBuffer[y][x] == nil or #Drawing.BackBuffer[y][x] ~= 3 then\
  446.                                 hasBackBuffer = false\
  447.                         end\
  448.                         if hasBackBuffer and Drawing.BackBuffer[y][x][1] == Drawing.Buffer[y][x][1] and Drawing.BackBuffer[y][x][2] == Drawing.Buffer[y][x][2] and Drawing.BackBuffer[y][x][3] == Drawing.Buffer[y][x][3] then\
  449.                                 shouldDraw = false\
  450.                         end\
  451.                         if shouldDraw then\
  452.                                 term.setBackgroundColour(pixel[3])\
  453.                                 term.setTextColour(pixel[2])\
  454.                                 term.setCursorPos(x, y)\
  455.                                 term.write(pixel[1])\
  456.                         end\
  457.                 end\
  458.         end\
  459.         Drawing.BackBuffer = Drawing.Buffer\
  460.         Drawing.Buffer = {}\
  461. end\
  462. \
  463. ClearBuffer = function()\
  464.         Drawing.Buffer = {}\
  465. end\
  466. \
  467. WriteStringToBuffer = function (x, y, characters, textColour,bgColour)\
  468.         for i = 1, #characters do\
  469.                 local character = characters:sub(i,i)\
  470.                 Drawing.WriteToBuffer(x + i - 1, y, character, textColour, bgColour)\
  471.         end\
  472. end\
  473. \
  474. WriteToBuffer = function(x, y, character, textColour,bgColour, cached)\
  475.         if not cached and not Drawing.WithinContraint(x, y) then\
  476.                 return\
  477.         end\
  478.         x = round(x)\
  479.         y = round(y)\
  480. \
  481.         if textColour == colours.transparent then\
  482.                 character = ' '\
  483.         end\
  484. \
  485.         if bgColour == colours.transparent then\
  486.                 Drawing.Buffer[y] = Drawing.Buffer[y] or {}\
  487.                 Drawing.Buffer[y][x] = Drawing.Buffer[y][x] or {\"\", colours.white, colours.black}\
  488.                 Drawing.Buffer[y][x][1] = character\
  489.                 Drawing.Buffer[y][x][2] = textColour\
  490.         else\
  491.                 Drawing.Buffer[y] = Drawing.Buffer[y] or {}\
  492.                 Drawing.Buffer[y][x] = {character, textColour, bgColour}\
  493.         end\
  494. \
  495.         if copyBuffer then\
  496.                 copyBuffer[y] = copyBuffer[y] or {}\
  497.                 copyBuffer[y][x] = {character, textColour, bgColour}            \
  498.         end\
  499. end\
  500. \
  501. DrawCachedBuffer = function(buffer)\
  502.         for y, row in pairs(buffer) do\
  503.                 for x, pixel in pairs(row) do\
  504.                         WriteToBuffer(x, y, pixel[1], pixel[2], pixel[3], true)\
  505.                 end\
  506.         end\
  507. end\
  508. \
  509. StartCopyBuffer = function()\
  510.         copyBuffer = {}\
  511. end\
  512. \
  513. EndCopyBuffer = function()\
  514.         local tmpCopy = copyBuffer\
  515.         copyBuffer = nil\
  516.         return tmpCopy\
  517. end\
  518. ]],\
  519. [\"Helpers\"] = [[\
  520. LongestString = function(input, key, isKey)\
  521.         local length = 0\
  522.         if isKey then\
  523.                 for k, v in pairs(input) do\
  524.                         local titleLength = string.len(k)\
  525.                         if titleLength > length then\
  526.                                 length = titleLength\
  527.                         end\
  528.                 end\
  529.         else\
  530.                 for i = 1, #input do\
  531.                         local value = input[i]\
  532.                         if key then\
  533.                                 if value[key] then\
  534.                                         value = value[key]\
  535.                                 else\
  536.                                         value = ''\
  537.                                 end\
  538.                         end\
  539.                         local titleLength = string.len(value)\
  540.                         if titleLength > length then\
  541.                                 length = titleLength\
  542.                         end\
  543.                 end\
  544.         end\
  545.         return length\
  546. end\
  547. \
  548. Split = function(str,sep)\
  549.     sep=sep or'/'\
  550.     return str:match(\"(.*\"..sep..\")\")\
  551. end\
  552. \
  553. Extension = function(path, addDot)\
  554.         if not path then\
  555.                 return nil\
  556.         elseif not string.find(fs.getName(path), '%.') then\
  557.                 if not addDot then\
  558.                         return fs.getName(path)\
  559.                 else\
  560.                         return ''\
  561.                 end\
  562.         else\
  563.                 local _path = path\
  564.                 if path:sub(#path) == '/' then\
  565.                         _path = path:sub(1,#path-1)\
  566.                 end\
  567.                 local extension = _path:gmatch('%.[0-9a-z]+$')()\
  568.                 if extension then\
  569.                         extension = extension:sub(2)\
  570.                 else\
  571.                         --extension = nil\
  572.                         return ''\
  573.                 end\
  574.                 if addDot then\
  575.                         extension = '.'..extension\
  576.                 end\
  577.                 return extension:lower()\
  578.         end\
  579. end\
  580. \
  581. RemoveExtension = function(path)\
  582. --local name = string.match(fs.getName(path), '(%a+)%.?.-')\
  583.         if path:sub(1,1) == '.' then\
  584.                 return path\
  585.         end\
  586.         local extension = Helpers.Extension(path)\
  587.         if extension == path then\
  588.                 return fs.getName(path)\
  589.         end\
  590.         return string.gsub(path, extension, ''):sub(1, -2)\
  591. end\
  592. \
  593. RemoveFileName = function(path)\
  594.         if string.sub(path, -1) == '/' then\
  595.                 path = string.sub(path, 1, -2)\
  596.         end\
  597.         local v = string.match(path, \"(.-)([^\\\\/]-%.?([^%.\\\\/]*))$\")\
  598.         if type(v) == 'string' then\
  599.                 return v\
  600.         end\
  601.         return v[1]\
  602. end\
  603. \
  604. TruncateString = function(sString, maxLength)\
  605.         if #sString > maxLength then\
  606.                 sString = sString:sub(1,maxLength-3)\
  607.                 if sString:sub(-1) == ' ' then\
  608.                         sString = sString:sub(1,maxLength-4)\
  609.                 end\
  610.                 sString = sString  .. '...'\
  611.         end\
  612.         return sString\
  613. end\
  614. \
  615. TruncateStringStart = function(sString, maxLength)\
  616.         local len = #sString\
  617.         if #sString > maxLength then\
  618.                 sString = sString:sub(len - maxLength, len - 3)\
  619.                 if sString:sub(-1) == ' ' then\
  620.                         sString = sString:sub(len - maxLength, len - 4)\
  621.                 end\
  622.                 sString = '...' .. sString\
  623.         end\
  624.         return sString\
  625. end\
  626. \
  627. WrapText = function(text, maxWidth)\
  628.         local lines = {''}\
  629.     for word, space in text:gmatch('(%S+)(%s*)') do\
  630.             local temp = lines[#lines] .. word .. space:gsub('\\n','')\
  631.             if #temp > maxWidth then\
  632.                     table.insert(lines, '')\
  633.             end\
  634.             if space:find('\\n') then\
  635.                     lines[#lines] = lines[#lines] .. word\
  636.                     \
  637.                     space = space:gsub('\\n', function()\
  638.                             table.insert(lines, '')\
  639.                             return ''\
  640.                     end)\
  641.             else\
  642.                     lines[#lines] = lines[#lines] .. word .. space\
  643.             end\
  644.     end\
  645.         return lines\
  646. end\
  647. \
  648. TidyPath = function(path)\
  649.         path = '/'..path\
  650.         if fs.exists(path) and fs.isDir(path) then\
  651.                 path = path .. '/'\
  652.         end\
  653. \
  654.         path, n = path:gsub(\"//\", \"/\")\
  655.         while n > 0 do\
  656.                 path, n = path:gsub(\"//\", \"/\")\
  657.         end\
  658.         return path\
  659. end\
  660. \
  661. Capitalise = function(str)\
  662.         return str:sub(1, 1):upper() .. str:sub(2, -1)\
  663. end\
  664. \
  665. Round = function(num, idp)\
  666.         local mult = 10^(idp or 0)\
  667.         return math.floor(num * mult + 0.5) / mult\
  668. end\
  669. ]],\
  670. [\"Object\"] = [[\
  671. X = 1\
  672. Y = 1\
  673. Width = 1\
  674. Height = 1\
  675. Parent = nil\
  676. OnClick = nil\
  677. Visible = true\
  678. IgnoreClick = false\
  679. Name = nil \
  680. ClipDrawing = true\
  681. UpdateDrawBlacklist = {}\
  682. Fixed = false\
  683. \
  684. DrawCache = {}\
  685. \
  686. NeedsDraw = function(self)\
  687.         if not self.Visible then\
  688.                 return false\
  689.         end\
  690.         \
  691.         if not self.DrawCache.Buffer or self.DrawCache.AlwaysDraw or self.DrawCache.NeedsDraw then\
  692.                 return true\
  693.         end\
  694. \
  695.         if self.OnNeedsUpdate then\
  696.                 if self.OnNeedsUpdate() then\
  697.                         return true\
  698.                 end\
  699.         end\
  700. \
  701.         if self.Children then\
  702.                 for i, v in ipairs(self.Children) do\
  703.                         if v:NeedsDraw() then\
  704.                                 return true\
  705.                         end\
  706.                 end\
  707.         end\
  708. end\
  709. \
  710. GetPosition = function(self)\
  711.         return self.Bedrock:GetAbsolutePosition(self)\
  712. end\
  713. \
  714. GetOffsetPosition = function(self)\
  715.         if not self.Parent then\
  716.                 return {X = 1, Y = 1}\
  717.         end\
  718. \
  719.         local offset = {X = 0, Y = 0}\
  720.         if not self.Fixed and self.Parent.ChildOffset then\
  721.                 offset = self.Parent.ChildOffset\
  722.         end\
  723. \
  724.         return {X = self.X + offset.X, Y = self.Y + offset.Y}\
  725. end\
  726. \
  727. Draw = function(self)\
  728.         if not self.Visible then\
  729.                 return\
  730.         end\
  731. \
  732.         self.DrawCache.NeedsDraw = false\
  733.         local pos = self:GetPosition()\
  734.         Drawing.StartCopyBuffer()\
  735. \
  736.         if self.ClipDrawing then\
  737.                 Drawing.AddConstraint(pos.X, pos.Y, self.Width, self.Height)\
  738.         end\
  739. \
  740.         if self.OnDraw then\
  741.                 self:OnDraw(pos.X, pos.Y)\
  742.         end\
  743. \
  744.         self.DrawCache.Buffer = Drawing.EndCopyBuffer()\
  745.         \
  746.         if self.Children then\
  747.                 for i, child in ipairs(self.Children) do\
  748.                         local pos = child:GetOffsetPosition()\
  749.                         if pos.Y + self.Height > 1 and pos.Y <= self.Height and pos.X + self.Width > 1 and pos.X <= self.Width then\
  750.                                 child:Draw()\
  751.                         end\
  752.                 end\
  753.         end\
  754. \
  755.         if self.ClipDrawing then\
  756.                 Drawing.RemoveConstraint()\
  757.         end     \
  758. end\
  759. \
  760. ForceDraw = function(self, ignoreChildren, ignoreParent, ignoreBedrock)\
  761.         if not ignoreBedrock and self.Bedrock then\
  762.                 self.Bedrock:ForceDraw()\
  763.         end\
  764.         self.DrawCache.NeedsDraw = true\
  765.         if not ignoreParent and self.Parent then\
  766.                 self.Parent:ForceDraw(true, nil, true)\
  767.         end\
  768.         if not ignoreChildren and self.Children then\
  769.                 for i, child in ipairs(self.Children) do\
  770.                         child:ForceDraw(nil, true, true)\
  771.                 end\
  772.         end\
  773. end\
  774. \
  775. OnRemove = function(self)\
  776.         if self == self.Bedrock:GetActiveObject() then\
  777.                 self.Bedrock:SetActiveObject()\
  778.         end\
  779. end\
  780. \
  781. local function ParseColour(value)\
  782.         if type(value) == 'string' then\
  783.                 if colours[value] and type(colours[value]) == 'number' then\
  784.                         return colours[value]\
  785.                 elseif colors[value] and type(colors[value]) == 'number' then\
  786.                         return colors[value]\
  787.                 end\
  788.         elseif type(value) == 'number' and (value == colours.transparent or (value >= colours.white and value <= colours.black)) then\
  789.                 return value\
  790.         end\
  791.         error('Invalid colour: \"'..tostring(value)..'\"')\
  792. end\
  793. \
  794. Initialise = function(self, values)\
  795.         local _new = values    -- the new instance\
  796.         _new.DrawCache = {\
  797.                 NeedsDraw = true,\
  798.                 AlwaysDraw = false,\
  799.                 Buffer = nil\
  800.         }\
  801.         setmetatable(_new, {__index = self} )\
  802. \
  803.         local new = {} -- the proxy\
  804.         setmetatable(new, {\
  805.                 __index = function(t, k)\
  806.                         if k:find('Color') then\
  807.                                 k = k:gsub('Color', 'Colour')\
  808.                         end\
  809. \
  810.                         if k:find('Colour') and type(_new[k]) ~= 'table' then\
  811.                                 if _new[k] then\
  812.                                         return ParseColour(_new[k])\
  813.                                 end\
  814.                         elseif _new[k] ~= nil then\
  815.                                 return _new[k]\
  816.                         end\
  817.                 end,\
  818. \
  819.                 __newindex = function (t,k,v)\
  820.                         if k:find('Color') then\
  821.                                 k = k:gsub('Color', 'Colour')\
  822.                         end\
  823. \
  824.                         if k == 'Width' or k == 'X' or k == 'Height' or k == 'Y' then\
  825.                                 v = new.Bedrock:ParseStringSize(new.Parent, k, v)\
  826.                         end\
  827. \
  828.                         if v ~= _new[k] then\
  829.                                 _new[k] = v\
  830.                                 if t.OnUpdate then\
  831.                                         t:OnUpdate(k)\
  832.                                 end\
  833. \
  834.                                 if t.UpdateDrawBlacklist[k] == nil then\
  835.                                         t:ForceDraw()\
  836.                                 end\
  837.                         end\
  838.                 end\
  839.         })\
  840.         if new.OnInitialise then\
  841.                 new:OnInitialise()\
  842.         end\
  843. \
  844.         return new\
  845. end\
  846. \
  847. Click = function(self, event, side, x, y)\
  848.         if self.Visible and not self.IgnoreClick then\
  849.                 if event == 'mouse_click' and self.OnClick and self:OnClick(event, side, x, y) ~= false then\
  850.                         return true\
  851.                 elseif event == 'mouse_drag' and self.OnDrag and self:OnDrag(event, side, x, y) ~= false then\
  852.                         return true\
  853.                 elseif event == 'mouse_scroll' and self.OnScroll and self:OnScroll(event, side, x, y) ~= false then\
  854.                         return true\
  855.                 else\
  856.                         return false\
  857.                 end\
  858.         else\
  859.                 return false\
  860.         end\
  861. \
  862. end\
  863. \
  864. ToggleMenu = function(self, name, x, y)\
  865.         return self.Bedrock:ToggleMenu(name, self, x, y)\
  866. end\
  867. \
  868. function OnUpdate(self, value)\
  869.         if value == 'Z' then\
  870.                 self.Bedrock:ReorderObjects()\
  871.         end\
  872. end\
  873. ]],\
  874. }\
  875. local objects = {\
  876. [\"Button\"] = [[\
  877. BackgroundColour = colours.lightGrey\
  878. ActiveBackgroundColour = colours.blue\
  879. ActiveTextColour = colours.white\
  880. TextColour = colours.black\
  881. DisabledTextColour = colours.lightGrey\
  882. Text = \"\"\
  883. Toggle = nil\
  884. Momentary = true\
  885. AutoWidthAutoWidth = true\
  886. Align = 'Center'\
  887. Enabled = true\
  888. \
  889. OnUpdate = function(self, value)\
  890.         if value == 'Text' and self.AutoWidth then\
  891.                 self.Width = #self.Text + 2\
  892.         end\
  893. end\
  894. \
  895. OnDraw = function(self, x, y)\
  896.         local bg = self.BackgroundColour\
  897. \
  898.         if self.Toggle then\
  899.                 bg = self.ActiveBackgroundColour\
  900.         end\
  901. \
  902.         local txt = self.TextColour\
  903.         if self.Toggle then\
  904.                 txt = self.ActiveTextColour\
  905.         end\
  906.         if not self.Enabled then\
  907.                 txt = self.DisabledTextColour\
  908.         end\
  909.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, bg)\
  910. \
  911.         local _x = 1\
  912.     if self.Align == 'Right' then\
  913.         _x = self.Width - #self.Text - 1\
  914.     elseif self.Align == 'Center' then\
  915.         _x = math.floor((self.Width - #self.Text) / 2)\
  916.     end\
  917. \
  918. \
  919.         Drawing.DrawCharacters(x + _x, y-1+math.ceil(self.Height/2), self.Text, txt, bg)\
  920. end\
  921. \
  922. OnLoad = function(self)\
  923.         if self.Toggle ~= nil then\
  924.                 self.Momentary = false\
  925.         end\
  926. end\
  927. \
  928. Click = function(self, event, side, x, y)\
  929.         if self.Visible and not self.IgnoreClick and self.Enabled and event ~= 'mouse_scroll' then\
  930.                 if self.OnClick then\
  931.                         if self.Momentary then\
  932.                                 self.Toggle = true\
  933.                                 self.Bedrock:StartTimer(function()self.Toggle = false end,0.25)\
  934.                         elseif self.Toggle ~= nil then\
  935.                                 self.Toggle = not self.Toggle\
  936.                         end\
  937. \
  938.                         self:OnClick(event, side, x, y, self.Toggle)\
  939.                 else\
  940.                         self.Toggle = not self.Toggle\
  941.                 end\
  942.                 return true\
  943.         else\
  944.                 return false\
  945.         end\
  946. end\
  947. ]],\
  948. [\"CollectionView\"] = [[\
  949. Inherit = 'ScrollView'\
  950. UpdateDrawBlacklist = {['NeedsItemUpdate']=true}\
  951. \
  952. TextColour = colours.black\
  953. BackgroundColour = colours.white\
  954. Items = false\
  955. NeedsItemUpdate = false\
  956. SpacingX = 2\
  957. SpacingY = 1\
  958. \
  959. OnDraw = function(self, x, y)\
  960.         if self.NeedsItemUpdate then\
  961.                 self:UpdateItems()\
  962.                 self.NeedsItemUpdate = false\
  963.         end\
  964.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  965. end\
  966. \
  967. local function MaxIcons(self, obj)\
  968.         local x, y = 2, 1\
  969.         if not obj.Height or not obj.Width then\
  970.                 error('You must provide each object\\'s height when adding to a CollectionView.')\
  971.         end\
  972.         local slotHeight = obj.Height + self.SpacingY\
  973.         local slotWidth = obj.Width + self.SpacingX\
  974.         local maxX = math.floor((self.Width - 2) / slotWidth)\
  975.         return x, y, maxX, slotWidth, slotHeight\
  976. end\
  977. \
  978. local function IconLocation(self, obj, i)\
  979.         local x, y, maxX, slotWidth, slotHeight = MaxIcons(self, obj)\
  980.         local rowPos = ((i - 1) % maxX)\
  981.         local colPos = math.ceil(i / maxX) - 1\
  982.         x = x + (slotWidth * rowPos)\
  983.         y = y + colPos * slotHeight\
  984.         return x, y\
  985. end\
  986. \
  987. local function AddItem(self, v, i)\
  988.         local toggle = false\
  989.         if not self.CanSelect then\
  990.                 toggle = nil\
  991.         end\
  992.         local x, y = IconLocation(self, v, i)\
  993.         local item = {\
  994.                 [\"X\"]=x,\
  995.                 [\"Y\"]=y,\
  996.                 [\"Name\"]=\"CollectionViewItem\",\
  997.                 [\"Type\"]=\"View\",\
  998.                 [\"TextColour\"]=self.TextColour,\
  999.                 [\"BackgroundColour\"]=0F,\
  1000.                 OnClick = function(itm)\
  1001.                         if self.CanSelect then\
  1002.                                 for i2, _v in ipairs(self.Children) do\
  1003.                                         _v.Toggle = false\
  1004.                                 end\
  1005.                                 self.Selected = itm\
  1006.                         end\
  1007.                 end\
  1008.     }\
  1009.         for k, _v in pairs(v) do\
  1010.                 item[k] = _v\
  1011.         end\
  1012.         self:AddObject(item)\
  1013. end\
  1014. \
  1015. \
  1016. UpdateItems = function(self)\
  1017.         self:RemoveAllObjects()\
  1018.         local groupMode = false\
  1019.         for k, v in pairs(self.Items) do\
  1020.                 if type(k) == 'string' then\
  1021.                         groupMode = true\
  1022.                         break\
  1023.                 end\
  1024.         end\
  1025. \
  1026.         for i, v in ipairs(self.Items) do\
  1027.                 AddItem(self, v, i)\
  1028.         end\
  1029.         self:UpdateScroll()\
  1030. end\
  1031. \
  1032. OnUpdate = function(self, value)\
  1033.         if value == 'Items' then\
  1034.                 self.NeedsItemUpdate = true\
  1035.         end\
  1036. end\
  1037. ]],\
  1038. [\"ImageView\"] = [[\
  1039. Image = false\
  1040. \
  1041. OnDraw = function(self, x, y)\
  1042.         Drawing.DrawImage(x, y, self.Image, self.Width, self.Height)\
  1043. end\
  1044. \
  1045. OnLoad = function(self)\
  1046.         if self.Path and fs.exists(self.Path) then\
  1047.                 self.Image = Drawing.LoadImage(self.Path)\
  1048.         end\
  1049. end\
  1050. \
  1051. OnUpdate = function(self, value)\
  1052.         if value == 'Path' then\
  1053.                 if self.Path and fs.exists(self.Path) then\
  1054.                         self.Image = Drawing.LoadImage(self.Path)\
  1055.                 end\
  1056.         end\
  1057. end\
  1058. ]],\
  1059. [\"Label\"] = [[\
  1060. TextColour = colours.black\
  1061. BackgroundColour = colours.transparent\
  1062. Text = \"\"\
  1063. AutoWidth = false\
  1064. Align = 'Left'\
  1065. \
  1066. local wrapText = function(text, maxWidth)\
  1067.     local lines = {''}\
  1068.     for word, space in text:gmatch('(%S+)(%s*)') do\
  1069.         local temp = lines[#lines] .. word .. space:gsub('\\n','')\
  1070.         if #temp > maxWidth then\
  1071.             table.insert(lines, '')\
  1072.         end\
  1073.         if space:find('\\n') then\
  1074.             lines[#lines] = lines[#lines] .. word\
  1075.             \
  1076.             space = space:gsub('\\n', function()\
  1077.                     table.insert(lines, '')\
  1078.                     return ''\
  1079.             end)\
  1080.         else\
  1081.             lines[#lines] = lines[#lines] .. word .. space\
  1082.         end\
  1083.     end\
  1084.     if #lines[1] == 0 then\
  1085.         table.remove(lines,1)\
  1086.     end\
  1087.     return lines\
  1088. end\
  1089. \
  1090. OnUpdate = function(self, value)\
  1091.     if value == 'Text' then\
  1092.         if self.AutoWidth then\
  1093.             self.Width = #self.Text\
  1094.         else\
  1095.             self.Height = #wrapText(self.Text, self.Width)\
  1096.         end\
  1097.     end\
  1098. end\
  1099. \
  1100. OnDraw = function(self, x, y)\
  1101.         for i, v in ipairs(wrapText(self.Text, self.Width)) do\
  1102.         local _x = 0\
  1103.         if self.Align == 'Right' then\
  1104.             _x = self.Width - #v\
  1105.         elseif self.Align == 'Center' then\
  1106.             _x = math.floor((self.Width - #v) / 2)\
  1107.         end\
  1108.                 Drawing.DrawCharacters(x + _x, y + i - 1, v, self.TextColour, self.BackgroundColour)\
  1109.         end\
  1110. end\
  1111. ]],\
  1112. [\"ListView\"] = [[\
  1113. Inherit = 'ScrollView'\
  1114. UpdateDrawBlacklist = {['NeedsItemUpdate']=true}\
  1115. \
  1116. TextColour = colours.black\
  1117. BackgroundColour = colours.white\
  1118. HeadingColour = colours.lightGrey\
  1119. SelectionBackgroundColour = colours.blue\
  1120. SelectionTextColour = colours.white\
  1121. Items = false\
  1122. CanSelect = false\
  1123. Selected = nil\
  1124. NeedsItemUpdate = false\
  1125. ItemMargin = 1\
  1126. HeadingMargin = 0\
  1127. TopMargin = 0\
  1128. \
  1129. OnDraw = function(self, x, y)\
  1130.         if self.NeedsItemUpdate then\
  1131.                 self:UpdateItems()\
  1132.         end\
  1133.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1134. end\
  1135. \
  1136. local function AddItem(self, v, x, y, group)\
  1137.         local toggle = false\
  1138.         if not self.CanSelect then\
  1139.                 toggle = nil\
  1140.         elseif v.Selected then\
  1141.                 toggle = true\
  1142.         end\
  1143.         local item = {\
  1144.                 [\"Width\"]=self.Width,\
  1145.                 [\"X\"]=x,\
  1146.                 [\"Y\"]=y,\
  1147.                 [\"Name\"]=\"ListViewItem\",\
  1148.                 [\"Type\"]=\"Button\",\
  1149.                 [\"TextColour\"]=self.TextColour,\
  1150.                 [\"BackgroundColour\"]=0,\
  1151.                 [\"ActiveTextColour\"]=self.SelectionTextColour,\
  1152.                 [\"ActiveBackgroundColour\"]=self.SelectionBackgroundColour,\
  1153.                 [\"Align\"]='Left',\
  1154.                 [\"Toggle\"]=toggle,\
  1155.                 [\"Group\"]=group,\
  1156.                 OnClick = function(itm)\
  1157.                         if self.CanSelect then\
  1158.                                 self:SelectItem(itm)\
  1159.                         elseif self.OnSelect then\
  1160.                                 self:OnSelect(itm.Text)\
  1161.                         end\
  1162.                 end\
  1163.     }\
  1164.     if type(v) == 'table' then\
  1165.         for k, _v in pairs(v) do\
  1166.                 item[k] = _v\
  1167.         end\
  1168.     else\
  1169.                 item.Text = v\
  1170.     end\
  1171.         \
  1172.         local itm = self:AddObject(item)\
  1173.         if v.Selected then\
  1174.                 self:SelectItem(itm)\
  1175.         end\
  1176. end\
  1177. \
  1178. UpdateItems = function(self)\
  1179.         if not self.Items or type(self.Items) ~= 'table' then\
  1180.                 self.Items = {}\
  1181.         end\
  1182.         self.Selected = nil\
  1183.         self:RemoveAllObjects()\
  1184.         local groupMode = false\
  1185.         for k, v in pairs(self.Items) do\
  1186.                 if type(k) == 'string' then\
  1187.                         groupMode = true\
  1188.                         break\
  1189.                 end\
  1190.         end\
  1191. \
  1192.         if not groupMode then\
  1193.                 for i, v in ipairs(self.Items) do\
  1194.                         AddItem(self, v, self.ItemMargin, i)\
  1195.                 end\
  1196.         else\
  1197.                 local y = self.TopMargin\
  1198.                 for k, v in pairs(self.Items) do\
  1199.                         y = y + 1\
  1200.                         AddItem(self, {Text = k, TextColour = self.HeadingColour, IgnoreClick = true}, self.HeadingMargin, y)\
  1201.                         for i, _v in ipairs(v) do\
  1202.                                 y = y + 1\
  1203.                                 AddItem(self, _v, 1, y, k)\
  1204.                         end\
  1205.                         y = y + 1\
  1206.                 end\
  1207.         end\
  1208.         self:UpdateScroll()\
  1209.         self.NeedsItemUpdate = false\
  1210. end\
  1211. \
  1212. OnKeyChar = function(self, event, keychar)\
  1213.         if keychar == keys.up or keychar == keys.down then\
  1214.                 local n = self:GetIndex(self.Selected)\
  1215.                 if keychar == keys.up then\
  1216.                         n = n - 1\
  1217.                 else\
  1218.                         n = n + 1\
  1219.                 end\
  1220.                 local new = self:GetNth(n)\
  1221.                 if new then\
  1222.                         self:SelectItem(new)\
  1223.                 end\
  1224.         elseif keychar == keys.enter and self.Selected then\
  1225.                 self.Selected:Click('mouse_click', 1, 1, 1)\
  1226.         end\
  1227. end\
  1228. \
  1229. --returns the index/'n' of the given item\
  1230. GetIndex = function(self, obj)\
  1231.         local n = 1\
  1232.         for i, v in ipairs(self.Children) do\
  1233.                 if not v.IgnoreClick then\
  1234.                         if obj == v then\
  1235.                                 return n\
  1236.                         end\
  1237.                         n = n + 1\
  1238.                 end\
  1239.         end\
  1240. end\
  1241. \
  1242. --gets the 'nth' list item (does not include headings)\
  1243. GetNth = function(self, n)\
  1244.         local _n = 1\
  1245.         for i, v in ipairs(self.Children) do\
  1246.                 if not v.IgnoreClick then\
  1247.                         if n == _n then\
  1248.                                 return v\
  1249.                         end\
  1250.                         _n = _n + 1\
  1251.                 end\
  1252.         end\
  1253. end\
  1254. \
  1255. SelectItem = function(self, item)\
  1256.         for i, v in ipairs(self.Children) do\
  1257.                 v.Toggle = false\
  1258.         end\
  1259.         self.Selected = item\
  1260.         item.Toggle = true\
  1261.         if self.OnSelect then\
  1262.                 self:OnSelect(item.Text)\
  1263.         end\
  1264. end\
  1265. \
  1266. OnUpdate = function(self, value)\
  1267.         if value == 'Items' then\
  1268.                 self.NeedsItemUpdate = true\
  1269.         end\
  1270. end\
  1271. ]],\
  1272. [\"Menu\"] = [[\
  1273. Inherit = 'View'\
  1274. \
  1275. TextColour = colours.black\
  1276. BackgroundColour = colours.white\
  1277. HideTop = false\
  1278. \
  1279. OnDraw = function(self, x, y)\
  1280.         Drawing.IgnoreConstraint = true\
  1281.         Drawing.DrawBlankArea(x + 1, y + (self.HideTop and 0 or 1), self.Width, self.Height + (self.HideTop and 1 or 0), colours.grey)\
  1282.         Drawing.IgnoreConstraint = false\
  1283.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1284. end\
  1285. \
  1286. OnLoad = function(self)\
  1287.         local owner = self.Owner\
  1288.         if type(owner) == 'string' then\
  1289.                 owner = self.Bedrock:GetObject(self.Owner)\
  1290.         end\
  1291. \
  1292.         if owner then\
  1293.                 if self.X == 0 and self.Y == 0 then\
  1294.                         local pos = owner:GetPosition()\
  1295.                         self.X = pos.X\
  1296.                         self.Y = pos.Y + owner.Height\
  1297.                 end\
  1298.                 self.Owner = owner\
  1299.         else\
  1300.                 self.Owner = nil\
  1301.         end\
  1302. end\
  1303. \
  1304. OnUpdate = function(self, value)\
  1305.         if value == 'Children' then\
  1306.                 self.Width = self.Bedrock.Helpers.LongestString(self.Children, 'Text') + 2\
  1307.                 self.Height = #self.Children + 1 + (self.HideTop and 0 or 1)\
  1308.                 if not self.BaseY then\
  1309.                         self.BaseY = self.Y\
  1310.                 end\
  1311. \
  1312.                 for i, v in ipairs(self.Children) do\
  1313.                         if v.TextColour then\
  1314.                                 v.TextColour = self.TextColour\
  1315.                         end\
  1316.                         if v.BackgroundColour then\
  1317.                                 v.BackgroundColour = colours.transparent\
  1318.                         end\
  1319.                         if v.Colour then\
  1320.                                 v.Colour = colours.lightGrey\
  1321.                         end\
  1322.                         v.Align = 'Left'\
  1323.                         v.X = 1\
  1324.                         v.Y = i + (self.HideTop and 0 or 1)\
  1325.                         v.Width = self.Width\
  1326.                         v.Height = 1\
  1327.                 end\
  1328. \
  1329.                 self.Y = self.BaseY\
  1330.                 local pos = self:GetPosition()\
  1331.                 if pos.Y + self.Height + 1 > Drawing.Screen.Height then\
  1332.                         self.Y = self.BaseY - ((self.Height +  pos.Y) - Drawing.Screen.Height)\
  1333.                 end\
  1334.                 \
  1335.                 if pos.X + self.Width > Drawing.Screen.Width then\
  1336.                         self.X = Drawing.Screen.Width - self.Width\
  1337.                 end\
  1338.         end\
  1339. end\
  1340. \
  1341. Close = function(self, isBedrockCall)\
  1342.         self.Bedrock.Menu = nil\
  1343.         self.Parent:RemoveObject(self)\
  1344.         if self.Owner and self.Owner.Toggle then\
  1345.                 self.Owner.Toggle = false\
  1346.         end\
  1347.         self.Parent:ForceDraw()\
  1348.         self = nil\
  1349. end\
  1350. \
  1351. OnChildClick = function(self, child, event, side, x, y)\
  1352.         self:Close()\
  1353. end\
  1354. ]],\
  1355. [\"ProgressBar\"] = [[\
  1356. BackgroundColour = colours.lightGrey\
  1357. BarColour = colours.blue\
  1358. TextColour = colours.white\
  1359. ShowText = false\
  1360. Value = 0\
  1361. Maximum = 1\
  1362. Indeterminate = false\
  1363. AnimationStep = 0\
  1364. \
  1365. OnDraw = function(self, x, y)\
  1366.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1367. \
  1368.         -- if self.Indeterminate then\
  1369.         --      for i = 1, self.Width do\
  1370.         --              local s = x + i - 1 + self.AnimationStep\
  1371.         --              if s % 4 == 1 or s % 4 == 2 then\
  1372.         --                      Drawing.DrawBlankArea(s, y, 1, self.Height, self.BarColour)\
  1373.         --              end\
  1374.         --      end\
  1375.         --      self.AnimationStep = self.AnimationStep + 1\
  1376.         --      if self.AnimationStep >= 4 then\
  1377.         --              self.AnimationStep = 0\
  1378.         --      end\
  1379.         --      self.Bedrock:StartTimer(function()\
  1380.         --              self:Draw()\
  1381.         --      end, 0.25)\
  1382.         -- else\
  1383.                 local values = self.Value\
  1384.                 local barColours = self.BarColour\
  1385.                 if type(values) == 'number' then\
  1386.                         values = {values}\
  1387.                 end\
  1388.                 if type(barColours) == 'number' then\
  1389.                         barColours = {barColours}\
  1390.                 end\
  1391.                 local total = 0\
  1392.                 local _x = x\
  1393.                 for i, v in ipairs(values) do\
  1394.                         local width = self.Bedrock.Helpers.Round((v / self.Maximum) * self.Width)\
  1395.                         total = total + v\
  1396.                         Drawing.DrawBlankArea(_x, y, width, self.Height, barColours[((i-1)%#barColours)+1])\
  1397.                         _x = _x + width\
  1398.                 end\
  1399. \
  1400.                 if self.ShowText then\
  1401.                         local text = self.Bedrock.Helpers.Round((total / self.Maximum) * 100) .. '%'\
  1402.                         Drawing.DrawCharactersCenter(x, y, self.Width, self.Height, text, self.TextColour, colours.transparent)\
  1403.                 end\
  1404.         -- end\
  1405. end\
  1406. ]],\
  1407. [\"ScrollBar\"] = [[\
  1408. BackgroundColour = colours.lightGrey\
  1409. BarColour = colours.lightBlue\
  1410. Scroll = 0\
  1411. MaxScroll = 0\
  1412. ClickPoint = nil\
  1413. Fixed = true\
  1414. \
  1415. OnUpdate = function(self, value)\
  1416.         if value == 'Text' and self.AutoWidth then\
  1417.                 self.Width = #self.Text + 2\
  1418.         end\
  1419. end\
  1420. \
  1421. OnDraw = function(self, x, y)\
  1422.         local barHeight = self.Height * (self.Height / (self.Height + self.MaxScroll))\
  1423.     if barHeight < 3 then\
  1424.       barHeight = 3\
  1425.     end\
  1426.     local percentage = (self.Scroll/self.MaxScroll)\
  1427. \
  1428.     Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1429.     Drawing.DrawBlankArea(x, y + math.ceil(self.Height*percentage - barHeight*percentage), self.Width, barHeight, self.BarColour)\
  1430. end\
  1431. \
  1432. OnScroll = function(self, event, direction, x, y)\
  1433.         if event == 'mouse_scroll' then\
  1434.                 direction = self.Bedrock.Helpers.Round(direction * 3)\
  1435.         end\
  1436.         if self.Scroll < 0 or self.Scroll > self.MaxScroll then\
  1437.                 return false\
  1438.         end\
  1439.         local old = self.Scroll\
  1440.         self.Scroll = self.Bedrock.Helpers.Round(self.Scroll + direction)\
  1441.         if self.Scroll < 0 then\
  1442.                 self.Scroll = 0\
  1443.         elseif self.Scroll > self.MaxScroll then\
  1444.                 self.Scroll = self.MaxScroll\
  1445.         end\
  1446. \
  1447.         if self.Scroll ~= old and self.OnChange then\
  1448.                 self:OnChange()\
  1449.         end\
  1450. end\
  1451. \
  1452. OnClick = function(self, event, side, x, y)\
  1453.         if event == 'mouse_click' then\
  1454.                 self.ClickPoint = y\
  1455.         else\
  1456.                 local gapHeight = self.Height - (self.Height * (self.Height / (self.Height + self.MaxScroll)))\
  1457.                 local barHeight = self.Height * (self.Height / (self.Height + self.MaxScroll))\
  1458.                 --local delta = (self.Height + self.MaxScroll) * ((y - self.ClickPoint) / barHeight)\
  1459.                 local delta = ((y - self.ClickPoint)/gapHeight)*self.MaxScroll\
  1460.                 --l(((y - self.ClickPoint)/gapHeight))\
  1461.                 --l(delta)\
  1462.                 self.Scroll = self.Bedrock.Helpers.Round(delta)\
  1463.                 --l(self.Scroll)\
  1464.                 --l('----')\
  1465.                 if self.Scroll < 0 then\
  1466.                         self.Scroll = 0\
  1467.                 elseif self.Scroll > self.MaxScroll then\
  1468.                         self.Scroll = self.MaxScroll\
  1469.                 end\
  1470.                 if self.OnChange then\
  1471.                         self:OnChange()\
  1472.                 end\
  1473.         end\
  1474. \
  1475.         local relScroll = self.MaxScroll * ((y-1)/self.Height)\
  1476.         if y == self.Height then\
  1477.                 relScroll = self.MaxScroll\
  1478.         end\
  1479.         self.Scroll = self.Bedrock.Helpers.Round(relScroll)\
  1480. \
  1481. \
  1482. end\
  1483. \
  1484. OnDrag = OnClick\
  1485. ]],\
  1486. [\"ScrollView\"] = [[\
  1487. Inherit = 'View'\
  1488. ChildOffset = false\
  1489. ContentWidth = 0\
  1490. ContentHeight = 0\
  1491. ScrollBarBackgroundColour = colours.lightGrey\
  1492. ScrollBarColour = colours.lightBlue\
  1493. \
  1494. CalculateContentSize = function(self)\
  1495.         local function calculateObject(obj)\
  1496.                 local pos = obj:GetPosition()\
  1497.                 local x2 = pos.X + obj.Width - 1\
  1498.                 local y2 = pos.Y + obj.Height - 1\
  1499.                 if obj.Children then\
  1500.                         for i, child in ipairs(obj.Children) do\
  1501.                                 local _x2, _y2 = calculateObject(child)\
  1502.                                 if _x2 > x2 then\
  1503.                                         x2 = _x2\
  1504.                                 end\
  1505.                                 if _y2 > y2 then\
  1506.                                         y2 = _y2\
  1507.                                 end\
  1508.                         end\
  1509.                 end\
  1510.                 return x2, y2\
  1511.         end\
  1512. \
  1513.         local pos = self:GetPosition()\
  1514.         local x2, y2 = calculateObject(self)\
  1515.         self.ContentWidth = x2 - pos.X + 1\
  1516.         self.ContentHeight = y2 - pos.Y + 1\
  1517. end\
  1518. \
  1519. UpdateScroll = function(self)\
  1520.         self.ChildOffset.Y = 0\
  1521.         self:CalculateContentSize()\
  1522.         if self.ContentHeight > self.Height then\
  1523.                 if not self:GetObject('ScrollViewScrollBar') then\
  1524.                         local _scrollBar = self:AddObject({\
  1525.                                 [\"Name\"] = 'ScrollViewScrollBar',\
  1526.                                 [\"Type\"] = 'ScrollBar',\
  1527.                                 [\"X\"] = self.Width,\
  1528.                                 [\"Y\"] = 1,\
  1529.                                 [\"Width\"] = 1,\
  1530.                                 [\"Height\"] = self.Height,\
  1531.                                 [\"BackgroundColour\"] = self.ScrollBarBackgroundColour,\
  1532.                                 [\"BarColour\"] = self.ScrollBarColour,\
  1533.                                 [\"Z\"]=999\
  1534.                         })\
  1535. \
  1536.                         _scrollBar.OnChange = function(scrollBar)\
  1537.                                 self.ChildOffset.Y = -scrollBar.Scroll\
  1538.                                 for i, child in ipairs(self.Children) do\
  1539.                                         child:ForceDraw()\
  1540.                                 end\
  1541.                         end\
  1542.                 end\
  1543.                 self:GetObject('ScrollViewScrollBar').MaxScroll = self.ContentHeight - self.Height\
  1544.         else\
  1545.                 self:RemoveObject('ScrollViewScrollBar')\
  1546.         end\
  1547. end\
  1548. \
  1549. OnScroll = function(self, event, direction, x, y)\
  1550.         if self:GetObject('ScrollViewScrollBar') then\
  1551.                 self:GetObject('ScrollViewScrollBar'):OnScroll(event, direction, x, y)\
  1552.         end\
  1553. end\
  1554. \
  1555. OnLoad = function(self)\
  1556.         if not self.ChildOffset or not self.ChildOffset.X or not self.ChildOffset.Y then\
  1557.                 self.ChildOffset = {X = 0, Y = 0}\
  1558.         end\
  1559. end\
  1560. ]],\
  1561. [\"SecureTextBox\"] = [[\
  1562. Inherit = 'TextBox'\
  1563. MaskCharacter = '*'\
  1564. \
  1565. OnDraw = function(self, x, y)\
  1566.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1567.         if self.CursorPos > #self.Text then\
  1568.                 self.CursorPos = #self.Text\
  1569.         elseif self.CursorPos < 0 then\
  1570.                 self.CursorPos = 0\
  1571.         end\
  1572.         local text = ''\
  1573. \
  1574.         for i = 1, #self.Text do\
  1575.                 text = text .. self.MaskCharacter\
  1576.         end\
  1577. \
  1578.         if self.Bedrock:GetActiveObject() == self then\
  1579.                 if #text > (self.Width - 2) then\
  1580.                         text = text:sub(#text-(self.Width - 3))\
  1581.                         self.Bedrock.CursorPos = {x + 1 + self.Width-2, y}\
  1582.                 else\
  1583.                         self.Bedrock.CursorPos = {x + 1 + self.CursorPos, y}\
  1584.                 end\
  1585.                 self.Bedrock.CursorColour = self.TextColour\
  1586.         end\
  1587. \
  1588.         if #tostring(text) == 0 then\
  1589.                 Drawing.DrawCharacters(x + 1, y, self.Placeholder, self.PlaceholderTextColour, self.BackgroundColour)\
  1590.         else\
  1591.                 if not self.Selected then\
  1592.                         Drawing.DrawCharacters(x + 1, y, text, self.TextColour, self.BackgroundColour)\
  1593.                 else\
  1594.                         for i = 1, #text do\
  1595.                                 local char = text:sub(i, i)\
  1596.                                 local textColour = self.TextColour\
  1597.                                 local backgroundColour = self.BackgroundColour\
  1598.                                 if i > self.DragStart and i - 1 <= self.CursorPos then\
  1599.                                         textColour = self.SelectedTextColour\
  1600.                                         backgroundColour = self.SelectedBackgroundColour\
  1601.                                 end\
  1602.                                 Drawing.DrawCharacters(x + i, y, char, textColour, backgroundColour)\
  1603.                         end\
  1604.                 end\
  1605.         end\
  1606. end\
  1607. ]],\
  1608. [\"Separator\"] = [[\
  1609. Colour = colours.grey\
  1610. \
  1611. OnDraw = function(self, x, y)\
  1612.         local char = \"|\"\
  1613.         if self.Width > self.Height then\
  1614.                 char = '-'\
  1615.         end\
  1616.         Drawing.DrawArea(x, y, self.Width, self.Height, char, self.Colour, colours.transparent)\
  1617. end\
  1618. ]],\
  1619. [\"TextBox\"] = [[\
  1620. BackgroundColour = colours.lightGrey\
  1621. SelectedBackgroundColour = colours.blue\
  1622. SelectedTextColour = colours.white\
  1623. TextColour = colours.black\
  1624. PlaceholderTextColour = colours.grey\
  1625. Placeholder = ''\
  1626. AutoWidth = false\
  1627. Text = \"\"\
  1628. CursorPos = nil\
  1629. Numerical = false\
  1630. DragStart = nil\
  1631. Selected = false\
  1632. SelectOnClick = false\
  1633. ActualDragStart = nil\
  1634. \
  1635. OnDraw = function(self, x, y)\
  1636.         Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1637.         if self.CursorPos > #self.Text then\
  1638.                 self.CursorPos = #self.Text\
  1639.         elseif self.CursorPos < 0 then\
  1640.                 self.CursorPos = 0\
  1641.         end\
  1642.         local text = self.Text\
  1643.         local offset = self:TextOffset()\
  1644.         if #text > (self.Width - 2) then\
  1645.                 text = text:sub(offset+1, offset + self.Width - 2)\
  1646.                 -- self.Bedrock.CursorPos = {x + 1 + self.Width-2, y}\
  1647.         -- else\
  1648.         end\
  1649.         if self.Bedrock:GetActiveObject() == self then\
  1650.                 self.Bedrock.CursorPos = {x + 1 + self.CursorPos - offset, y}\
  1651.                 self.Bedrock.CursorColour = self.TextColour\
  1652.         else\
  1653.                 self.Selected = false\
  1654.         end\
  1655. \
  1656.         if #tostring(text) == 0 then\
  1657.                 Drawing.DrawCharacters(x + 1, y, self.Placeholder, self.PlaceholderTextColour, self.BackgroundColour)\
  1658.         else\
  1659.                 if not self.Selected then\
  1660.                         Drawing.DrawCharacters(x + 1, y, text, self.TextColour, self.BackgroundColour)\
  1661.                 else\
  1662.                         local startPos = self.DragStart - offset\
  1663.                         local endPos = self.CursorPos - offset\
  1664.                         if startPos > endPos then\
  1665.                                 startPos = self.CursorPos - offset\
  1666.                                 endPos = self.DragStart - offset\
  1667.                         end\
  1668.                         for i = 1, #text do\
  1669.                                 local char = text:sub(i, i)\
  1670.                                 local textColour = self.TextColour\
  1671.                                 local backgroundColour = self.BackgroundColour\
  1672. \
  1673.                                 if i > startPos and i - 1 <= endPos then\
  1674.                                         textColour = self.SelectedTextColour\
  1675.                                         backgroundColour = self.SelectedBackgroundColour\
  1676.                                 end\
  1677.                                 Drawing.DrawCharacters(x + i, y, char, textColour, backgroundColour)\
  1678.                         end\
  1679.                 end\
  1680.         end\
  1681. end\
  1682. \
  1683. TextOffset = function(self)\
  1684.         if #self.Text < (self.Width - 2) then\
  1685.                 return 0\
  1686.         elseif self.Bedrock:GetActiveObject() ~= self then\
  1687.                 return 0\
  1688.         else\
  1689.                 local textWidth = (self.Width - 2)\
  1690.                 local offset = self.CursorPos - textWidth\
  1691.                 if offset < 0 then\
  1692.                         offset = 0\
  1693.                 end\
  1694.                 return offset\
  1695.         end\
  1696. end\
  1697. \
  1698. OnLoad = function(self)\
  1699.         if not self.CursorPos then\
  1700.                 self.CursorPos = #self.Text\
  1701.         end\
  1702. end\
  1703. \
  1704. OnClick = function(self, event, side, x, y)\
  1705.         if self.Bedrock:GetActiveObject() ~= self and self.SelectOnClick then\
  1706.                 self.CursorPos = #self.Text - 1\
  1707.                 self.DragStart = 0\
  1708.                 self.ActualDragStart = x - 2 + self:TextOffset()\
  1709.                 self.Selected = true\
  1710.         else\
  1711.                 self.CursorPos = x - 2 + self:TextOffset()\
  1712.                 self.DragStart = self.CursorPos\
  1713.                 self.Selected = false\
  1714.         end\
  1715.         self.Bedrock:SetActiveObject(self)\
  1716. end\
  1717. \
  1718. OnDrag = function(self, event, side, x, y)\
  1719.         self.CursorPos = x - 2 + self:TextOffset()\
  1720.         if self.ActualDragStart then\
  1721.                 self.DragStart = self.ActualDragStart\
  1722.                 self.ActualDragStart = nil\
  1723.         end\
  1724.         if self.DragStart then\
  1725.                 self.Selected = true\
  1726.         end\
  1727. end\
  1728. \
  1729. OnKeyChar = function(self, event, keychar)\
  1730.         local deleteSelected = function()\
  1731.                 if self.Selected then\
  1732.                         local startPos = self.DragStart\
  1733.                         local endPos = self.CursorPos\
  1734.                         if startPos > endPos then\
  1735.                                 startPos = self.CursorPos\
  1736.                                 endPos = self.DragStart\
  1737.                         end\
  1738.                         self.Text = self.Text:sub(1, startPos) .. self.Text:sub(endPos + 2)\
  1739.                         self.CursorPos = startPos\
  1740.                         self.DragStart = nil\
  1741.                         self.Selected = false\
  1742.                         return true\
  1743.                 end\
  1744.         end\
  1745. \
  1746.         if event == 'char' then\
  1747.                 deleteSelected()\
  1748.                 if self.Numerical then\
  1749.                         keychar = tostring(tonumber(keychar))\
  1750.                 end\
  1751.                 if keychar == 'nil' then\
  1752.                         return\
  1753.                 end\
  1754.                 self.Text = string.sub(self.Text, 1, self.CursorPos ) .. keychar .. string.sub( self.Text, self.CursorPos + 1 )\
  1755.                 if self.Numerical then\
  1756.                         self.Text = tostring(tonumber(self.Text))\
  1757.                         if self.Text == 'nil' then\
  1758.                                 self.Text = '1'\
  1759.                         end\
  1760.                 end\
  1761.                 \
  1762.                 self.CursorPos = self.CursorPos + 1\
  1763.                 if self.OnChange then\
  1764.                         self:OnChange(event, keychar)\
  1765.                 end\
  1766.                 return false\
  1767.         elseif event == 'key' then\
  1768.                 if keychar == keys.enter then\
  1769.                         if self.OnChange then\
  1770.                                 self:OnChange(event, keychar)\
  1771.                         end\
  1772.                 elseif keychar == keys.left then\
  1773.                         -- Left\
  1774.                         if self.CursorPos > 0 then\
  1775.                                 if self.Selected then\
  1776.                                         self.CursorPos = self.DragStart\
  1777.                                         self.DragStart = nil\
  1778.                                         self.Selected = false\
  1779.                                 else\
  1780.                                         self.CursorPos = self.CursorPos - 1\
  1781.                                 end\
  1782.                                 if self.OnChange then\
  1783.                                         self:OnChange(event, keychar)\
  1784.                                 end\
  1785.                         end\
  1786.                         \
  1787.                 elseif keychar == keys.right then\
  1788.                         -- Right                                \
  1789.                         if self.CursorPos < string.len(self.Text) then\
  1790.                                 if self.Selected then\
  1791.                                         self.CursorPos = self.CursorPos\
  1792.                                         self.DragStart = nil\
  1793.                                         self.Selected = false\
  1794.                                 else\
  1795.                                         self.CursorPos = self.CursorPos + 1\
  1796.                                 end\
  1797.                                 if self.OnChange then\
  1798.                                         self:OnChange(event, keychar)\
  1799.                                 end\
  1800.                         end\
  1801.                 \
  1802.                 elseif keychar == keys.backspace then\
  1803.                         -- Backspace\
  1804.                         if not deleteSelected() and self.CursorPos > 0 then\
  1805.                                 self.Text = string.sub( self.Text, 1, self.CursorPos - 1 ) .. string.sub( self.Text, self.CursorPos + 1 )\
  1806.                                 self.CursorPos = self.CursorPos - 1                                     \
  1807.                                 if self.Numerical then\
  1808.                                         self.Text = tostring(tonumber(self.Text))\
  1809.                                         if self.Text == 'nil' then\
  1810.                                                 self.Text = '1'\
  1811.                                         end\
  1812.                                 end\
  1813.                                 if self.OnChange then\
  1814.                                         self:OnChange(event, keychar)\
  1815.                                 end\
  1816.                         end\
  1817.                 elseif keychar == keys.home then\
  1818.                         -- Home\
  1819.                         self.CursorPos = 0\
  1820.                         if self.OnChange then\
  1821.                                 self:OnChange(event, keychar)\
  1822.                         end\
  1823.                 elseif keychar == keys.delete then\
  1824.                         if not deleteSelected() and self.CursorPos < string.len(self.Text) then\
  1825.                                 self.Text = string.sub( self.Text, 1, self.CursorPos ) .. string.sub( self.Text, self.CursorPos + 2 )           \
  1826.                                 if self.Numerical then\
  1827.                                         self.Text = tostring(tonumber(self.Text))\
  1828.                                         if self.Text == 'nil' then\
  1829.                                                 self.Text = '1'\
  1830.                                         end\
  1831.                                 end\
  1832.                                 if self.OnChange then\
  1833.                                         self:OnChange(keychar)\
  1834.                                 end\
  1835.                         end\
  1836.                 elseif keychar == keys[\"end\"] then\
  1837.                         -- End\
  1838.                         self.CursorPos = string.len(self.Text)\
  1839.                 else\
  1840.                         if self.OnChange then\
  1841.                                 self:OnChange(event, keychar)\
  1842.                         end\
  1843.                         return false\
  1844.                 end\
  1845.         end\
  1846. end\
  1847. ]],\
  1848. [\"View\"] = [[\
  1849. BackgroundColour = colours.transparent\
  1850. Children = {}\
  1851. \
  1852. OnDraw = function(self, x, y)\
  1853.         if self.BackgroundColour then\
  1854.                 Drawing.DrawBlankArea(x, y, self.Width, self.Height, self.BackgroundColour)\
  1855.         end\
  1856. end\
  1857. \
  1858. OnInitialise = function(self)\
  1859.         self.Children = {}\
  1860. end\
  1861. \
  1862. InitialiseFile = function(self, bedrock, file, name)\
  1863.         local _new = {}\
  1864.         _new.X = 1\
  1865.         _new.Y = 1\
  1866.         _new.Width = Drawing.Screen.Width\
  1867.         _new.Height = Drawing.Screen.Height\
  1868.         _new.BackgroundColour = file.BackgroundColour\
  1869.         _new.Name = name\
  1870.         _new.Children = {}\
  1871.         _new.Bedrock = bedrock\
  1872.         local new = self:Initialise(_new)\
  1873.         for i, obj in ipairs(file.Children) do\
  1874.                 local view = bedrock:ObjectFromFile(obj, new)\
  1875.                 if not view.Z then\
  1876.                         view.Z = i\
  1877.                 end\
  1878.                 view.Parent = new\
  1879.                 table.insert(new.Children, view)\
  1880.         end\
  1881.         return new\
  1882. end\
  1883. \
  1884. function CheckClick(self, object, x, y)\
  1885.         local offset = {X = 0, Y = 0}\
  1886.         if not object.Fixed and self.ChildOffset then\
  1887.                 offset = self.ChildOffset\
  1888.         end\
  1889.         if object.X + offset.X <= x and object.Y + offset.Y <= y and  object.X + offset.X + object.Width > x and object.Y + offset.Y + object.Height > y then\
  1890.                 return true\
  1891.         end\
  1892. end\
  1893. \
  1894. function DoClick(self, object, event, side, x, y)\
  1895.         if object then\
  1896.                 if self:CheckClick(object, x, y) then\
  1897.                         local offset = {X = 0, Y = 0}\
  1898.                         if not object.Fixed and self.ChildOffset then\
  1899.                                 offset = self.ChildOffset\
  1900.                         end\
  1901.                         return object:Click(event, side, x - object.X - offset.X + 1, y - object.Y + 1 - offset.Y)\
  1902.                 end\
  1903.         end     \
  1904. end\
  1905. \
  1906. Click = function(self, event, side, x, y, z)\
  1907.         if self.Visible and not self.IgnoreClick then\
  1908.                 for i = #self.Children, 1, -1 do --children are ordered from smallest Z to highest, so this is done in reverse\
  1909.                         local child = self.Children[i]\
  1910.                         if self:DoClick(child, event, side, x, y) then\
  1911.                                 if self.OnChildClick then\
  1912.                                         self:OnChildClick(child, event, side, x, y)\
  1913.                                 end\
  1914.                                 return true\
  1915.                         end\
  1916.                 end\
  1917.                 if event == 'mouse_click' and self.OnClick and self:OnClick(event, side, x, y) ~= false then\
  1918.                         return true\
  1919.                 elseif event == 'mouse_drag' and self.OnDrag and self:OnDrag(event, side, x, y) ~= false then\
  1920.                         return true\
  1921.                 elseif event == 'mouse_scroll' and self.OnScroll and self:OnScroll(event, side, x, y) ~= false then\
  1922.                         return true\
  1923.                 else\
  1924.                         return false\
  1925.                 end\
  1926.         else\
  1927.                 return false\
  1928.         end\
  1929. end\
  1930. \
  1931. OnRemove = function(self)\
  1932.         if self == self.Bedrock:GetActiveObject() then\
  1933.                 self.Bedrock:SetActiveObject()\
  1934.         end\
  1935.         for i, child in ipairs(self.Children) do\
  1936.                 child:OnRemove()\
  1937.         end\
  1938. end\
  1939. \
  1940. local function findObjectNamed(view, name, minI)\
  1941.         local minI = minI or 0\
  1942.         if view and view.Children then\
  1943.                 for i, child in ipairs(view.Children) do\
  1944.                         if child.Name == name or child == name then\
  1945.                                 return child, i, view\
  1946.                         elseif child.Children then\
  1947.                                 local found, index, foundView = findObjectNamed(child, name)\
  1948.                                 if found and minI <= index then\
  1949.                                         return found, index, foundView\
  1950.                                 end\
  1951.                         end\
  1952.                 end\
  1953.         end\
  1954. end\
  1955. \
  1956. function AddObject(self, info, extra)\
  1957.         if type(info) == 'string' then\
  1958.                 local h = fs.open(self.Bedrock.ViewPath..info..'.view', 'r')\
  1959.                 if h then\
  1960.                         info = textutils.unserialize(h.readAll())\
  1961.                         h.close()\
  1962.                 else\
  1963.                         error('Error in opening object: '..info)\
  1964.                 end\
  1965.         end\
  1966. \
  1967.         if extra then\
  1968.                 for k, v in pairs(extra) do\
  1969.                         if v then\
  1970.                                 info[k] = v\
  1971.                         end\
  1972.                 end\
  1973.         end\
  1974. \
  1975.         local view = self.Bedrock:ObjectFromFile(info, self)\
  1976.         if not view.Z then\
  1977.                 view.Z = #self.Children + 1\
  1978.         end\
  1979.         \
  1980.         table.insert(self.Children, view)\
  1981.         if self.Bedrock.View then\
  1982.                 self.Bedrock:ReorderObjects()\
  1983.         end\
  1984.         self:ForceDraw()\
  1985.         return view\
  1986. end\
  1987. \
  1988. function GetObject(self, name)\
  1989.         return findObjectNamed(self, name)\
  1990. end\
  1991. \
  1992. local function findObjects(view, name)\
  1993.         local objects = {}\
  1994.         if view and view.Children then\
  1995.                 for i, child in ipairs(view.Children) do\
  1996.                         if child.Name == name or child == name then\
  1997.                                 table.insert(objects, child)\
  1998.                         elseif child.Children then\
  1999.                                 local objs = findObjects(child, name)\
  2000.                                 if objs then\
  2001.                                         for i2, v in ipairs(objs) do\
  2002.                                                 table.insert(objects, v)\
  2003.                                         end\
  2004.                                 end\
  2005.                         end\
  2006.                 end\
  2007.         end\
  2008.         return objects\
  2009. end\
  2010. \
  2011. function GetObjects(self, name)\
  2012.         return findObjects(self, name)\
  2013. end\
  2014. \
  2015. function RemoveObject(self, name)\
  2016.         local obj, index, view = findObjectNamed(self, name, minI)\
  2017.         if index then\
  2018.                 view.Children[index]:OnRemove()\
  2019.                 table.remove(view.Children, index)\
  2020.                 if view.OnUpdate then\
  2021.                         view:OnUpdate('Children')\
  2022.                 end\
  2023.                 return true\
  2024.         end\
  2025.         return false\
  2026. end\
  2027. \
  2028. function RemoveObjects(self, name)\
  2029.         local i = 1\
  2030.         while self:RemoveObject(name) and i < 100 do\
  2031.                 i = i + 1\
  2032.         end\
  2033.         \
  2034. end\
  2035. \
  2036. function RemoveAllObjects(self)\
  2037.         for i, child in ipairs(self.Children) do\
  2038.                 child:OnRemove()\
  2039.                 self.Children[i] = nil\
  2040.         end\
  2041.         self:ForceDraw()\
  2042. end\
  2043. ]],\
  2044. [\"Window\"] = [[\
  2045. Inherit = 'View'\
  2046. \
  2047. ToolBarColour = colours.lightGrey\
  2048. ToolBarTextColour = colours.black\
  2049. ShadowColour = colours.grey\
  2050. Title = ''\
  2051. Flashing = false\
  2052. CanClose = true\
  2053. OnCloseButton = nil\
  2054. OldActiveObject = nil\
  2055. \
  2056. OnLoad = function(self)\
  2057.         --self:GetObject('View') = self.Bedrock:ObjectFromFile({Type = 'View',Width = 10, Height = 5, BackgroundColour = colours.red}, self)\
  2058. end\
  2059. \
  2060. LoadView = function(self)\
  2061.         local view = self:GetObject('View')\
  2062.         if view.ToolBarColour then\
  2063.                 window.ToolBarColour = view.ToolBarColour\
  2064.         end\
  2065.         if view.ToolBarTextColour then\
  2066.                 window.ToolBarTextColour = view.ToolBarTextColour\
  2067.         end\
  2068.         view.X = 1\
  2069.         view.Y = 2\
  2070. \
  2071.         view:ForceDraw()\
  2072.         self:OnUpdate('View')\
  2073.         if self.OnViewLoad then\
  2074.                 self.OnViewLoad(view)\
  2075.         end\
  2076.         self.OldActiveObject = self.Bedrock:GetActiveObject()\
  2077.         self.Bedrock:SetActiveObject(view)\
  2078. end\
  2079. \
  2080. SetView = function(self, view)\
  2081.         self:RemoveObject('View')\
  2082.         table.insert(self.Children, view)\
  2083.         view.Parent = self\
  2084.         self:LoadView()\
  2085. end\
  2086. \
  2087. Flash = function(self)\
  2088.         self.Flashing = true\
  2089.         self:ForceDraw()\
  2090.         self.Bedrock:StartTimer(function()self.Flashing = false end, 0.4)\
  2091. end\
  2092. \
  2093. OnDraw = function(self, x, y)\
  2094.         local toolBarColour = (self.Flashing and colours.white or self.ToolBarColour)\
  2095.         local toolBarTextColour = (self.Flashing and colours.black or self.ToolBarTextColour)\
  2096.         if toolBarColour then\
  2097.                 Drawing.DrawBlankArea(x, y, self.Width, 1, toolBarColour)\
  2098.         end\
  2099.         if toolBarTextColour then\
  2100.                 local title = self.Bedrock.Helpers.TruncateString(self.Title, self.Width - 2)\
  2101.                 Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, title, toolBarTextColour, toolBarColour)\
  2102.         end\
  2103.         Drawing.IgnoreConstraint = true\
  2104.         Drawing.DrawBlankArea(x + 1, y + 1, self.Width, self.Height, self.ShadowColour)\
  2105.         Drawing.IgnoreConstraint = false\
  2106. end\
  2107. \
  2108. Close = function(self)\
  2109.         self.Bedrock:SetActiveObject(self.OldActiveObject)\
  2110.         self.Bedrock.Window = nil\
  2111.         self.Bedrock:RemoveObject(self)\
  2112.         if self.OnClose then\
  2113.                 self:OnClose()\
  2114.         end\
  2115.         self = nil\
  2116. end\
  2117. \
  2118. OnUpdate = function(self, value)\
  2119.         if value == 'View' and self:GetObject('View') then\
  2120.                 self.Width = self:GetObject('View').Width\
  2121.                 self.Height = self:GetObject('View').Height + 1\
  2122.                 self.X = math.ceil((Drawing.Screen.Width - self.Width) / 2)\
  2123.                 self.Y = math.ceil((Drawing.Screen.Height - self.Height) / 2)\
  2124.         elseif value == 'CanClose' then\
  2125.                 self:RemoveObject('CloseButton')\
  2126.                 if self.CanClose then\
  2127.                         local button = self:AddObject({X = 1, Y = 1, Width = 1, Height = 1, Type = 'Button', BackgroundColour = colours.red, TextColour = colours.white, Text = 'x', Name = 'CloseButton'})\
  2128.                         button.OnClick = function(btn)\
  2129.                                 if self.OnCloseButton then\
  2130.                                         self:OnCloseButton()\
  2131.                                 end\
  2132.                                 self:Close()\
  2133.                         end\
  2134.                 end\
  2135.         end\
  2136. end\
  2137. ]],\
  2138. }\
  2139. \
  2140. BasePath = ''\
  2141. ProgramPath = nil\
  2142. \
  2143. -- Program functions...\
  2144. \
  2145. local function main(...)\
  2146.         -- Code here...\
  2147. end\
  2148. \
  2149. -- Run\
  2150. local args = {...}\
  2151. local _, err = pcall(function() main(unpack(args)) end)\
  2152. if err then\
  2153.         -- Make a nice error handling screen here...\
  2154.         term.setBackgroundColor(colors.black)\
  2155.         term.setTextColor(colors.white)\
  2156.         term.clear()\
  2157.         term.setCursorPos(1, 3)\
  2158.         print(\" An Error Has Occured! D:\\n\\n\")\
  2159.         print(\" \" .. tostring(err) .. \"\\n\\n\")\
  2160.         print(\" Press any key to exit...\")\
  2161.         os.pullEvent(\"key\")\
  2162. end\
  2163. \
  2164. \
  2165. \
  2166. function LoadAPIs(self)\
  2167.         local function loadAPI(name, content)\
  2168.                 local env = setmetatable({}, { __index = getfenv() })\
  2169.                 local func, err = loadstring(content, name..' (Bedrock API)')\
  2170.                 if not func then\
  2171.                         return false, printError(err)\
  2172.                 end\
  2173.                 setfenv(func, env)\
  2174.                 func()\
  2175.                 local api = {}\
  2176.                 for k,v in pairs(env) do\
  2177.                         api[k] = v\
  2178.                 end\
  2179.                 _G[name] = api\
  2180.                 return true\
  2181.         end\
  2182. \
  2183.         local env = getfenv()\
  2184.         local function loadObject(name, content)\
  2185.                 loadAPI(name, content)\
  2186.                 if env[name].Inherit then\
  2187.                         if not getfenv()[env[name].Inherit] then        \
  2188.                                 if objects[env[name].Inherit] then\
  2189.                                         loadObject(env[name].Inherit, objects[env[name].Inherit])\
  2190.                                 elseif fs.exists(self.ProgramPath..'/Objects/'..env[name].Inherit..'.lua') then\
  2191.                                 end\
  2192.                         end\
  2193.                         env[name].__index = getfenv()[env[name].Inherit]\
  2194.                 else\
  2195.                         env[name].__index = Object\
  2196.                 end\
  2197.                 setmetatable(env[name], env[name])\
  2198.         end\
  2199. \
  2200.         for k, v in pairs(apis) do\
  2201.                 loadAPI(k, v)\
  2202.                 if k == 'Helpers' then\
  2203.                         self.Helpers = Helpers\
  2204.                 end\
  2205.         end\
  2206. \
  2207.         for k, v in pairs(objects) do\
  2208.                 loadObject(k, v)\
  2209.         end\
  2210.         \
  2211.         local privateObjPath = self.ProgramPath..'/Objects/'\
  2212.         if fs.exists(privateObjPath) and fs.isDir(privateObjPath) then\
  2213.                 for i, v in ipairs(fs.list(privateObjPath)) do\
  2214.                         if v ~= '.DS_Store' then\
  2215.                                 local name = string.match(v, '(%a+)%.?.-')\
  2216.                                 local h = fs.open(privateObjPath..v, 'r')\
  2217.                                 loadObject(name, h.readAll())\
  2218.                                 h.close()\
  2219.                         end\
  2220.                 end\
  2221.         end\
  2222. end\
  2223. \
  2224. AllowTerminate = true\
  2225. \
  2226. View = nil\
  2227. Menu = nil\
  2228. \
  2229. ActiveObject = nil\
  2230. \
  2231. DrawTimer = nil\
  2232. DrawTimerExpiry = 0\
  2233. \
  2234. IsDrawing = false\
  2235. \
  2236. Running = true\
  2237. \
  2238. DefaultView = 'main'\
  2239. \
  2240. EventHandlers = {\
  2241.         \
  2242. }\
  2243. \
  2244. ObjectClickHandlers = {\
  2245.         \
  2246. }\
  2247. \
  2248. ObjectUpdateHandlers = {\
  2249.         \
  2250. }\
  2251. \
  2252. Timers = {\
  2253.         \
  2254. }\
  2255. \
  2256. function Initialise(self, programPath)\
  2257.         self.ProgramPath = programPath or self.ProgramPath\
  2258.         if not programPath then\
  2259.                 if self.ProgramPath then\
  2260.                         local prgPath = self.ProgramPath\
  2261.                         local prgName = fs.getName(prgPath)\
  2262.                         if prgPath:find('/') then \
  2263.                                 self.ProgramPath = prgPath:sub(1, #prgPath-#prgName-1)\
  2264.                                 self.ProgramPath = prgPath:sub(1, #prgPath-#prgName-1) \
  2265.                         else \
  2266.                                 self.ProgramPath = '' \
  2267.                         end\
  2268.                 else\
  2269.                         self.ProgramPath = ''\
  2270.                 end\
  2271.         end\
  2272.         self:LoadAPIs()\
  2273.         self.ViewPath = self.ProgramPath .. '/Views/'\
  2274.         --first, check that the barebones APIs are available\
  2275.         local requiredApis = {\
  2276.                 'Drawing',\
  2277.                 'View'\
  2278.         }\
  2279.         local env = getfenv()\
  2280.         for i,v in ipairs(requiredApis) do\
  2281.                 if not env[v] then\
  2282.                         error('The API: '..v..' is not loaded. Please make sure you load it to use Bedrock.')\
  2283.                 end\
  2284.         end\
  2285. \
  2286.         local copy = { }\
  2287.         for k, v in pairs(self) do\
  2288.                 if k ~= 'Initialise' then\
  2289.                         copy[k] = v\
  2290.                 end\
  2291.         end\
  2292.         return setmetatable(copy, getmetatable(self))\
  2293. end\
  2294. \
  2295. function HandleClick(self, event, side, x, y)\
  2296.         if self.Window then\
  2297.                 if not self.View:CheckClick(self.Window, x, y) then\
  2298.                         self.Window:Flash()\
  2299.                 else\
  2300.                         self.View:DoClick(self.Window, event, side, x, y)\
  2301.                 end\
  2302.         elseif self.Menu then\
  2303.                 if not self.View:DoClick(self.Menu, event, side, x, y) then\
  2304.                         self.Menu:Close()\
  2305.                 end\
  2306.         elseif self.View then\
  2307.                 if self.View:Click(event, side, x, y) ~= false then\
  2308.                 end             \
  2309.         end\
  2310. end\
  2311. \
  2312. function HandleKeyChar(self, event, keychar)\
  2313.         if self:GetActiveObject() then\
  2314.                 local activeObject = self:GetActiveObject()\
  2315.                 if activeObject.OnKeyChar then\
  2316.                         if activeObject:OnKeyChar(event, keychar) ~= false then\
  2317.                                 --self:Draw()\
  2318.                         end\
  2319.                 end\
  2320.         end\
  2321. end\
  2322. \
  2323. function ToggleMenu(self, name, owner, x, y)\
  2324.         if self.Menu then\
  2325.                 self.Menu:Close()\
  2326.                 return false\
  2327.         else\
  2328.                 self:SetMenu(name, owner, x, y)\
  2329.                 return true\
  2330.         end\
  2331. end\
  2332. \
  2333. function SetMenu(self, menu, owner, x, y)\
  2334.         x = x or 1\
  2335.         y = y or 1\
  2336.         if self.Menu then\
  2337.                 self.Menu:Close()\
  2338.         end     \
  2339.         if menu then\
  2340.                 local pos = owner:GetPosition()\
  2341.                 self.Menu = self:AddObject(menu, {Type = 'Menu', Owner = owner, X = pos.X + x - 1, Y = pos.Y + y})\
  2342.         end\
  2343. end\
  2344. \
  2345. function ObjectClick(self, name, func)\
  2346.         self.ObjectClickHandlers[name] = func\
  2347. end\
  2348. \
  2349. function ClickObject(self, object, event, side, x, y)\
  2350.         if self.ObjectClickHandlers[object.Name] then\
  2351.                 return self.ObjectClickHandlers[object.Name](object, event, side, x, y)\
  2352.         end\
  2353.         return false\
  2354. end\
  2355. \
  2356. function ObjectUpdate(self, name, func)\
  2357.         self.ObjectUpdateHandlers[name] = func\
  2358. end\
  2359. \
  2360. function UpdateObject(self, object, ...)\
  2361.         if self.ObjectUpdateHandlers[object.Name] then\
  2362.                 self.ObjectUpdateHandlers[object.Name](object, ...)\
  2363.                 --self:Draw()\
  2364.         end\
  2365. end\
  2366. \
  2367. function GetAbsolutePosition(self, obj)\
  2368.         if not obj.Parent then\
  2369.                 return {X = obj.X, Y = obj.Y}\
  2370.         else\
  2371.                 local pos = self:GetAbsolutePosition(obj.Parent)\
  2372.                 local x = pos.X + obj.X - 1\
  2373.                 local y = pos.Y + obj.Y - 1\
  2374.                 if not obj.Fixed and obj.Parent.ChildOffset then\
  2375.                         x = x + obj.Parent.ChildOffset.X\
  2376.                         y = y + obj.Parent.ChildOffset.Y\
  2377.                 end\
  2378.                 return {X = x, Y = y}\
  2379.         end\
  2380. end\
  2381. \
  2382. function LoadView(self, name, draw)\
  2383.         if self.View and self.OnViewClose then\
  2384.                 self.OnViewClose(self.View.Name)\
  2385.         end\
  2386.         if self.View then\
  2387.                 self.View:OnRemove()\
  2388.         end\
  2389.         local success = false\
  2390. \
  2391.         if not fs.exists(self.ViewPath..name..'.view') then\
  2392.                 error('The view: '..name..'.view does not exist.')\
  2393.         end\
  2394. \
  2395.         local h = fs.open(self.ViewPath..name..'.view', 'r')\
  2396.         if h then\
  2397.                 local view = textutils.unserialize(h.readAll())\
  2398.                 h.close()\
  2399.                 if view then\
  2400.                         self.View = View:InitialiseFile(self, view, name)\
  2401.                         self:ReorderObjects()\
  2402. \
  2403.                         if OneOS and view.ToolBarColour then\
  2404.                                 OneOS.ToolBarColour = view.ToolBarColour\
  2405.                         end\
  2406.                         if OneOS and view.ToolBarTextColour then\
  2407.                                 OneOS.ToolBarTextColour = view.ToolBarTextColour\
  2408.                         end\
  2409.                         if not self:GetActiveObject() then\
  2410.                                 self:SetActiveObject()\
  2411.                         end\
  2412.                         success = true\
  2413.                 end\
  2414.         end\
  2415. \
  2416.         if success and self.OnViewLoad then\
  2417.                 self.OnViewLoad(name)\
  2418.         end\
  2419. \
  2420.         if draw ~= false then\
  2421.                 self:Draw()\
  2422.         end\
  2423. \
  2424.         if not success then\
  2425.                 error('Failed to load view: '..name..'. It probably isn\\'t formatted correctly. Did you forget a } or ,?')\
  2426.         end\
  2427. \
  2428.         return success\
  2429. end\
  2430. \
  2431. function InheritFile(self, file, name)\
  2432.         local h = fs.open(self.ViewPath..name..'.view', 'r')\
  2433.         if h then\
  2434.                 local super = textutils.unserialize(h.readAll())\
  2435.                 if super then\
  2436.                         if type(super) ~= 'table' then\
  2437.                                 error('View: \"'..name..'.view\" is not formatted correctly.')\
  2438.                         end\
  2439. \
  2440.                         for k, v in pairs(super) do\
  2441.                                 if not file[k] then\
  2442.                                         file[k] = v\
  2443.                                 end\
  2444.                         end\
  2445.                         return file\
  2446.                 end\
  2447.         end\
  2448.         return file\
  2449. end\
  2450. \
  2451. function ParseStringSize(self, parent, k, v)\
  2452.                 local parentSize = parent.Width\
  2453.                 if k == 'Height' or k == 'Y' then\
  2454.                         parentSize = parent.Height\
  2455.                 end\
  2456.                 local parts = {v}\
  2457.                 if type(v) == 'string' and string.find(v, ',') then\
  2458.                         parts = {}\
  2459.                         for word in string.gmatch(v, '([^,]+)') do\
  2460.                             table.insert(parts, word)\
  2461.                         end\
  2462.                 end\
  2463. \
  2464.                 v = 0\
  2465.                 for i2, part in ipairs(parts) do\
  2466.                         if type(part) == 'string' and part:sub(#part) == '%' then\
  2467.                                 v = v + math.ceil(parentSize * (tonumber(part:sub(1, #part-1)) / 100))\
  2468.                         else\
  2469.                                 v = v + tonumber(part)\
  2470.                         end\
  2471.                 end\
  2472.                 return v\
  2473. end\
  2474. \
  2475. function ObjectFromFile(self, file, view)\
  2476.         local env = getfenv()\
  2477.         if env[file.Type] then\
  2478.                 if not env[file.Type].Initialise then\
  2479.                         error('Malformed Object: '..file.Type)\
  2480.                 end\
  2481.                 local object = {}\
  2482. \
  2483.                 if file.InheritView then\
  2484.                         file = self:InheritFile(file, file.InheritView)\
  2485.                 end\
  2486.                 \
  2487.                 object.AutoWidth = true\
  2488.                 for k, v in pairs(file) do\
  2489.                         if k == 'Width' or k == 'X' or k == 'Height' or k == 'Y' then\
  2490.                                 v = self:ParseStringSize(view, k, v)\
  2491.                         end\
  2492. \
  2493.                         if k == 'Width' then\
  2494.                                 object.AutoWidth = false\
  2495.                         end\
  2496.                         if k ~= 'Children' then\
  2497.                                 object[k] = v\
  2498.                         else\
  2499.                                 object[k] = {}\
  2500.                         end\
  2501.                 end\
  2502. \
  2503.                 object.Parent = view\
  2504.                 object.Bedrock = self\
  2505.                 if not object.Name then\
  2506.                         object.Name = file.Type\
  2507.                 end\
  2508. \
  2509.                 object = env[file.Type]:Initialise(object)\
  2510. \
  2511.                 if file.Children then\
  2512.                         for i, obj in ipairs(file.Children) do\
  2513.                                 local _view = self:ObjectFromFile(obj, object)\
  2514.                                 if not _view.Z then\
  2515.                                         _view.Z = i\
  2516.                                 end\
  2517.                                 _view.Parent = object\
  2518.                                 table.insert(object.Children, _view)\
  2519.                         end\
  2520.                 end\
  2521. \
  2522.                 if not object.OnClick then\
  2523.                         object.OnClick = function(...) return self:ClickObject(...) end\
  2524.                 end\
  2525.                 --object.OnUpdate = function(...) self:UpdateObject(...) end\
  2526. \
  2527.                 if object.OnUpdate then\
  2528.                         for k, v in pairs(env[file.Type]) do\
  2529.                                 object:OnUpdate(k)\
  2530.                         end\
  2531. \
  2532.                         for k, v in pairs(object.__index) do\
  2533.                                 object:OnUpdate(k)\
  2534.                         end\
  2535.                 end\
  2536. \
  2537.                 if object.Active then\
  2538.                         object.Bedrock:SetActiveObject(object)\
  2539.                 end\
  2540.                 if object.OnLoad then\
  2541.                         object:OnLoad()\
  2542.                 end\
  2543.                 return object\
  2544.         elseif not file.Type then\
  2545.                 error('No object type specified. (e.g. Type = \"Button\")')\
  2546.         else\
  2547.                 error('No Object: '..file.Type..'. The API probably isn\\'t loaded')\
  2548.         end\
  2549. end\
  2550. \
  2551. function ReorderObjects(self)\
  2552.         if self.View and self.View.Children then\
  2553.                 table.sort(self.View.Children, function(a,b)\
  2554.                         return a.Z < b.Z \
  2555.                 end)\
  2556.         end\
  2557. end\
  2558. \
  2559. function AddObject(self, info, extra)\
  2560.         return self.View:AddObject(info, extra)\
  2561. end\
  2562. \
  2563. function GetObject(self, name)\
  2564.         return self.View:GetObject(name)\
  2565. end\
  2566. \
  2567. function GetObjects(self, name)\
  2568.         return self.View:GetObjects(name)\
  2569. end\
  2570. \
  2571. function RemoveObject(self, name)\
  2572.         return self.View:RemoveObject(name)\
  2573. end\
  2574. \
  2575. function RemoveObjects(self, name)\
  2576.         return self.View:RemoveObjects(name)\
  2577. end\
  2578. \
  2579. function ForceDraw(self)\
  2580.         if not self.DrawTimer or self.DrawTimerExpiry <= os.clock() then\
  2581.                 self.DrawTimer = self:StartTimer(function()\
  2582.                         self.DrawTimer = nil\
  2583.                         self:Draw()\
  2584.                 end, 0.05)\
  2585.                 self.DrawTimerExpiry = os.clock() + 0.1\
  2586.         end\
  2587. end\
  2588. \
  2589. function DisplayWindow(self, _view, title, canClose)\
  2590.         if canClose == nil then\
  2591.                 canClose = true\
  2592.         end\
  2593.         if type(_view) == 'string' then\
  2594.                 local h = fs.open(self.ViewPath.._view..'.view', 'r')\
  2595.                 if h then\
  2596.                         _view = textutils.unserialize(h.readAll())\
  2597.                         h.close()\
  2598.                 end\
  2599.         end\
  2600. \
  2601.         self.Window = self:AddObject({Type = 'Window', Z = 999, Title = title, CanClose = canClose})\
  2602.         _view.Type = 'View'\
  2603.         _view.Name = 'View'\
  2604.         _view.BackgroundColour = _view.BackgroundColour or colours.white\
  2605.         self.Window:SetView(self:ObjectFromFile(_view, self.Window))\
  2606. end\
  2607. \
  2608. function DisplayAlertWindow(self, title, text, buttons, callback)\
  2609.         local func = function(btn)\
  2610.                 self.Window:Close()\
  2611.                 if callback then\
  2612.                         callback(btn.Text)\
  2613.                 end\
  2614.         end\
  2615.         local children = {}\
  2616.         local usedX = -1\
  2617.         if buttons then\
  2618.                 for i, text in ipairs(buttons) do\
  2619.                         usedX = usedX + 3 + #text\
  2620.                         table.insert(children, {\
  2621.                                 [\"Y\"]=\"100%,-1\",\
  2622.                                 [\"X\"]=\"100%,-\"..usedX,\
  2623.                                 [\"Name\"]=text..\"Button\",\
  2624.                                 [\"Type\"]=\"Button\",\
  2625.                                 [\"Text\"]=text,\
  2626.                                 OnClick = func\
  2627.                         })\
  2628.                 end\
  2629.         end\
  2630. \
  2631.         local width = usedX + 2\
  2632.         if width < 28 then\
  2633.                 width = 28\
  2634.         end\
  2635. \
  2636.         local canClose = true\
  2637.         if buttons and #buttons~=0 then\
  2638.                 canClose = false\
  2639.         end\
  2640. \
  2641.         local height = 0\
  2642.         if text then\
  2643.                 height = #Helpers.WrapText(text, width - 2)\
  2644.                 table.insert(children, {\
  2645.                         [\"Y\"]=2,\
  2646.                         [\"X\"]=2,\
  2647.                         [\"Width\"]=\"100%,-2\",\
  2648.                         [\"Height\"]=height,\
  2649.                         [\"Name\"]=\"Label\",\
  2650.                         [\"Type\"]=\"Label\",\
  2651.                         [\"Text\"]=text\
  2652.                 })\
  2653.         end\
  2654.         local view = {\
  2655.                 Children = children,\
  2656.                 Width=width,\
  2657.                 Height=3+height+(canClose and 0 or 1),\
  2658.                 OnKeyChar = function(_view, keychar)\
  2659.                         func({Text=buttons[1]})\
  2660.                 end\
  2661.         }\
  2662.         self:DisplayWindow(view, title, canClose)\
  2663. end\
  2664. \
  2665. function DisplayTextBoxWindow(self, title, text, callback, textboxText, cursorAtEnd)\
  2666.         textboxText = textboxText or ''\
  2667.         local func = function(btn)\
  2668.                 self.Window:Close()\
  2669.                 if callback then\
  2670.                         callback(btn.Text)\
  2671.                 end\
  2672.         end\
  2673.         local children = {\
  2674.                 {\
  2675.                         [\"Y\"]=\"100%,-1\",\
  2676.                         [\"X\"]=\"100%,-4\",\
  2677.                         [\"Name\"]=\"OkButton\",\
  2678.                         [\"Type\"]=\"Button\",\
  2679.                         [\"Text\"]=\"Ok\",\
  2680.                         OnClick = function()\
  2681.                                 local text = self.Window:GetObject('TextBox').Text\
  2682.                                 self.Window:Close()\
  2683.                                 callback(true, text)\
  2684.                         end\
  2685.                 },\
  2686.                 {\
  2687.                         [\"Y\"]=\"100%,-1\",\
  2688.                         [\"X\"]=\"100%,-13\",\
  2689.                         [\"Name\"]=\"CancelButton\",\
  2690.                         [\"Type\"]=\"Button\",\
  2691.                         [\"Text\"]=\"Cancel\",\
  2692.                         OnClick = function()\
  2693.                                 self.Window:Close()\
  2694.                                 callback(false)\
  2695.                         end\
  2696.                 }\
  2697.         }\
  2698. \
  2699.         local height = -1\
  2700.         if text and #text ~= 0 then\
  2701.                 height = #Helpers.WrapText(text, 26)\
  2702.                 table.insert(children, {\
  2703.                         [\"Y\"]=2,\
  2704.                         [\"X\"]=2,\
  2705.                         [\"Width\"]=\"100%,-2\",\
  2706.                         [\"Height\"]=height,\
  2707.                         [\"Name\"]=\"Label\",\
  2708.                         [\"Type\"]=\"Label\",\
  2709.                         [\"Text\"]=text\
  2710.                 })\
  2711.         end\
  2712.         table.insert(children,\
  2713.                 {\
  2714.                         [\"Y\"]=3+height,\
  2715.                         [\"X\"]=2,\
  2716.                         [\"Width\"]=\"100%,-2\",\
  2717.                         [\"Name\"]=\"TextBox\",\
  2718.                         [\"Type\"]=\"TextBox\",\
  2719.                         [\"Text\"]=textboxText,\
  2720.                         [\"CursorPos\"]=(cursorAtEnd and 0 or nil)\
  2721.                 })\
  2722.         local view = {\
  2723.                 Children = children,\
  2724.                 Width=28,\
  2725.                 Height=5+height+(canClose and 0 or 1),\
  2726.         }\
  2727.         self:DisplayWindow(view, title)\
  2728.         self.Window:GetObject('TextBox').OnUpdate = function(txtbox, keychar)\
  2729.                 if keychar == keys.enter then\
  2730.                         self.Window:Close()\
  2731.                         callback(true, txtbox.Text)\
  2732.                 end\
  2733.         end\
  2734.         self:SetActiveObject(self.Window:GetObject('TextBox'))\
  2735.         self.Window.OnCloseButton = function()callback(false)end\
  2736. end\
  2737. \
  2738. function DisplayOpenFileWindow(self, title, callback)\
  2739.         title = title or 'Open File'\
  2740.         local func = function(btn)\
  2741.                 self.Window:Close()\
  2742.                 if callback then\
  2743.                         callback(btn.Text)\
  2744.                 end\
  2745.         end\
  2746. \
  2747.         local sidebarItems = {}\
  2748. \
  2749.         --this is a really, really super bad way of doing it\
  2750.         local separator = '                               !'\
  2751. \
  2752.         local function addFolder(path, level)\
  2753.                 for i, v in ipairs(fs.list(path)) do\
  2754.                         local fPath = path .. '/' .. v\
  2755.                         if fPath ~= '/rom' and fs.isDir(fPath) then\
  2756.                                 table.insert(sidebarItems, level .. v..separator..fPath)\
  2757.                                 addFolder(fPath, level .. '  ')\
  2758.                         end\
  2759.                 end\
  2760.         end\
  2761.         addFolder('','')\
  2762. \
  2763.         local currentFolder = ''\
  2764.         local selectedPath = nil\
  2765. \
  2766.         local goToFolder = nil\
  2767. \
  2768.         local children = {\
  2769.                 {\
  2770.                         [\"Y\"]=\"100%,-2\",\
  2771.                         [\"X\"]=1,\
  2772.                         [\"Height\"]=3,\
  2773.                         [\"Width\"]=\"100%\",\
  2774.                         [\"BackgroundColour\"]=colours.lightGrey,\
  2775.                         [\"Name\"]=\"SidebarListView\",\
  2776.                         [\"Type\"]=\"View\"\
  2777.                 },\
  2778.                 {\
  2779.                         [\"Y\"]=\"100%,-1\",\
  2780.                         [\"X\"]=\"100%,-4\",\
  2781.                         [\"Name\"]=\"OkButton\",\
  2782.                         [\"Type\"]=\"Button\",\
  2783.                         [\"Text\"]=\"Ok\",\
  2784.                         [\"BackgroundColour\"]=colours.white,\
  2785.                         [\"Enabled\"]=false,\
  2786.                         OnClick = function()\
  2787.                                 if selectedPath then\
  2788.                                         self.Window:Close()\
  2789.                                         callback(true, Helpers.TidyPath(selectedPath))\
  2790.                                 end\
  2791.                         end\
  2792.                 },\
  2793.                 {\
  2794.                         [\"Y\"]=\"100%,-1\",\
  2795.                         [\"X\"]=\"100%,-13\",\
  2796.                         [\"Name\"]=\"CancelButton\",\
  2797.                         [\"Type\"]=\"Button\",\
  2798.                         [\"Text\"]=\"Cancel\",\
  2799.                         [\"BackgroundColour\"]=colours.white,\
  2800.                         OnClick = function()\
  2801.                                 self.Window:Close()\
  2802.                                 callback(false)\
  2803.                         end\
  2804.                 },\
  2805.                 {\
  2806.                         [\"Y\"]=1,\
  2807.                         [\"X\"]=1,\
  2808.                         [\"Height\"]=\"100%,-3\",\
  2809.                         [\"Width\"]=\"40%,-1\",\
  2810.                         [\"Name\"]=\"SidebarListView\",\
  2811.                         [\"Type\"]=\"ListView\",\
  2812.                         [\"CanSelect\"]=true,\
  2813.                         [\"Items\"]={\
  2814.                                 [\"Computer\"] = sidebarItems\
  2815.                         },\
  2816.                         OnSelect = function(listView, text)\
  2817.                                 local _,s = text:find(separator)\
  2818.                                 if s then\
  2819.                                         local path = text:sub(s + 1)\
  2820.                                         goToFolder(path)\
  2821.                                 end\
  2822.                         end,\
  2823.                         OnClick = function(listView, event, side, x, y)\
  2824.                                 if y == 1 then\
  2825.                                         goToFolder('/')\
  2826.                                 end\
  2827.                         end\
  2828.                 },\
  2829.                 {\
  2830.                         [\"Y\"]=1,\
  2831.                         [\"X\"]=\"40%\",\
  2832.                         [\"Height\"]=\"100%,-3\",\
  2833.                         [\"Width\"]=1,\
  2834.                         [\"Type\"]=\"Separator\"\
  2835.                 },\
  2836.                 {\
  2837.                         [\"Y\"]=1,\
  2838.                         [\"X\"]=\"40%,2\",\
  2839.                         [\"Width\"]=\"65%,-3\",\
  2840.                         [\"Height\"]=1,\
  2841.                         [\"Type\"]=\"Label\",\
  2842.                         [\"Name\"]=\"PathLabel\",\
  2843.                         [\"TextColour\"]=colours.lightGrey,\
  2844.                         [\"Text\"]='/hello/there'\
  2845.                 },\
  2846.                 {\
  2847.                         [\"Y\"]=2,\
  2848.                         [\"X\"]=\"40%,1\",\
  2849.                         [\"Height\"]=\"100%,-4\",\
  2850.                         [\"Width\"]=\"65%,-1\",\
  2851.                         [\"Name\"]=\"FilesListView\",\
  2852.                         [\"Type\"]=\"ListView\",\
  2853.                         [\"CanSelect\"]=true,\
  2854.                         [\"Items\"]={},\
  2855.                         OnSelect = function(listView, text)\
  2856.                                 selectedPath = Helpers.TidyPath(currentFolder .. '/' .. text)\
  2857.                                 self.Window:GetObject('OkButton').Enabled = true\
  2858.                         end,\
  2859.                         OnClick = function(listView, event, side, x, y)\
  2860.                                 if y == 1 then\
  2861.                                         goToFolder('/')\
  2862.                                 end\
  2863.                         end\
  2864.                 },\
  2865.         }\
  2866.         local view = {\
  2867.                 Children = children,\
  2868.                 Width=40,\
  2869.                 Height= Drawing.Screen.Height - 4\
  2870.         }\
  2871.         self:DisplayWindow(view, title)\
  2872. \
  2873.         goToFolder = function(path)\
  2874.                 path = Helpers.TidyPath(path)\
  2875.                 self.Window:GetObject('PathLabel').Text = path\
  2876.                 currentFolder = path\
  2877. \
  2878.                 local filesListItems = {}\
  2879.                 for i, v in ipairs(fs.list(path)) do\
  2880.                         if not fs.isDir(currentFolder .. v) then\
  2881.                                 table.insert(filesListItems, v)\
  2882.                         end\
  2883.                 end\
  2884.                 self.Window:GetObject('OkButton').Enabled = false\
  2885.                 selectedPath = nil\
  2886.                 self.Window:GetObject('FilesListView').Items = filesListItems\
  2887. \
  2888.         end\
  2889. \
  2890.         goToFolder('')\
  2891. \
  2892.         self.Window.OnCloseButton = function()callback(false)end\
  2893. end\
  2894. \
  2895. function RegisterEvent(self, event, func)\
  2896.         if not self.EventHandlers[event] then\
  2897.                 self.EventHandlers[event] = {}\
  2898.         end\
  2899.         table.insert(self.EventHandlers[event], func)\
  2900. end\
  2901. \
  2902. function StartRepeatingTimer(self, func, interval)\
  2903.         local int = interval\
  2904.         if type(int) == 'function' then\
  2905.                 int = int()\
  2906.         end\
  2907.         if not int or int <= 0 then\
  2908.                 return\
  2909.         end\
  2910.         local timer = os.startTimer(int)\
  2911. \
  2912.         self.Timers[timer] = {func, true, interval}\
  2913.         return timer\
  2914. end\
  2915. \
  2916. function StartTimer(self, func, delay)\
  2917.         local timer = os.startTimer(delay)\
  2918.         self.Timers[timer] = {func, false}\
  2919.         return timer\
  2920. end\
  2921. \
  2922. function StopTimer(self, timer)\
  2923.         if self.Timers[timer] then\
  2924.                 self.Timers[timer] = nil\
  2925.         end\
  2926. end\
  2927. \
  2928. function HandleTimer(self, event, timer)\
  2929.         if self.Timers[timer] then\
  2930.                 local oldTimer = self.Timers[timer]\
  2931.                 self.Timers[timer] = nil\
  2932.                 local new = nil\
  2933.                 if oldTimer[2] then\
  2934.                         new = self:StartRepeatingTimer(oldTimer[1], oldTimer[3])\
  2935.                 end\
  2936.                 if oldTimer and oldTimer[1] then\
  2937.                         oldTimer[1](new)\
  2938.                 end\
  2939.         elseif self.OnTimer then\
  2940.                 self.OnTimer(self, event, timer)\
  2941.         end\
  2942. end\
  2943. \
  2944. function SetActiveObject(self, object)\
  2945.         if object then\
  2946.                 if object ~= self.ActiveObject then\
  2947.                         self.ActiveObject = object\
  2948.                         object:ForceDraw()\
  2949.                 end\
  2950.         elseif self.ActiveObject ~= nil then\
  2951.                 self.ActiveObject = nil\
  2952.                 self.CursorPos = nil\
  2953.                 self.View:ForceDraw()\
  2954.         end\
  2955. end\
  2956. \
  2957. function GetActiveObject(self)\
  2958.         return self.ActiveObject\
  2959. end\
  2960. \
  2961. OnTimer = nil\
  2962. OnClick = nil\
  2963. OnKeyChar = nil\
  2964. OnDrag = nil\
  2965. OnScroll = nil\
  2966. OnViewLoad = nil\
  2967. OnViewClose = nil\
  2968. OnDraw = nil\
  2969. OnQuit = nil\
  2970. \
  2971. local eventFuncs = {\
  2972.         OnClick = {'mouse_click', 'monitor_touch'},\
  2973.         OnKeyChar = {'key', 'char'},\
  2974.         OnDrag = {'mouse_drag'},\
  2975.         OnScroll = {'mouse_scroll'},\
  2976.         HandleClick = {'mouse_click', 'mouse_drag', 'mouse_scroll', 'monitor_touch'},\
  2977.         HandleKeyChar = {'key', 'char'},\
  2978.         HandleTimer = {'timer'}\
  2979. }\
  2980. \
  2981. local drawCalls = 0\
  2982. local ignored = 0\
  2983. function Draw(self)\
  2984.         self.IsDrawing = true\
  2985.         if self.OnDraw then\
  2986.                 self:OnDraw()\
  2987.         end\
  2988. \
  2989.         if self.View and self.View:NeedsDraw() then\
  2990.                 self.View:Draw()\
  2991.                 Drawing.DrawBuffer()\
  2992.                 if isDebug then\
  2993.                         drawCalls = drawCalls + 1\
  2994.                 end\
  2995.         elseif not self.View then\
  2996.                 print('No loaded view. You need to do program:LoadView first.')\
  2997.         end     \
  2998. \
  2999.         if self:GetActiveObject() and self.CursorPos and type(self.CursorPos[1]) == 'number' and type(self.CursorPos[2]) == 'number' then\
  3000.                 term.setCursorPos(self.CursorPos[1], self.CursorPos[2])\
  3001.                 term.setTextColour(self.CursorColour)\
  3002.                 term.setCursorBlink(true)\
  3003.         else\
  3004.                 term.setCursorBlink(false)\
  3005.         end\
  3006. \
  3007.         self.IsDrawing = false\
  3008. end\
  3009. \
  3010. function EventHandler(self)\
  3011.         local event = { os.pullEventRaw() }\
  3012.         \
  3013.         if self.EventHandlers[event[1]] then\
  3014.                 for i, e in ipairs(self.EventHandlers[event[1]]) do\
  3015.                         e(self, unpack(event))\
  3016.                 end\
  3017.         end\
  3018. end\
  3019. \
  3020. function Quit(self)\
  3021.         self.Running = false\
  3022.         if self.OnQuit then\
  3023.                 self:OnQuit()\
  3024.         end\
  3025.         if OneOS then\
  3026.                 OneOS.Close()\
  3027.         end\
  3028. end\
  3029. \
  3030. function Run(self, ready)\
  3031.         for name, events in pairs(eventFuncs) do\
  3032.                 if self[name] then\
  3033.                         for i, event in ipairs(events) do\
  3034.                                 self:RegisterEvent(event, self[name])\
  3035.                         end\
  3036.                 end\
  3037.         end\
  3038. \
  3039.         if self.AllowTerminate then\
  3040.                 self:RegisterEvent('terminate', function()error('Terminated', 0) end)\
  3041.         end\
  3042. \
  3043.         if self.DefaultView and self.DefaultView ~= '' and fs.exists(self.ViewPath..self.DefaultView..'.view') then\
  3044.                 self:LoadView(self.DefaultView)\
  3045.         end\
  3046. \
  3047.         if ready then\
  3048.                 ready()\
  3049.         end\
  3050.         \
  3051.         self:Draw()\
  3052. \
  3053.         while self.Running do\
  3054.                 self:EventHandler()\
  3055.         end\
  3056. end",
  3057.   Peripheral = "GetPeripheral = function(_type)\
  3058.         for i, p in ipairs(GetPeripherals()) do\
  3059.                 if p.Type == _type then\
  3060.                         return p\
  3061.                 end\
  3062.         end\
  3063. end\
  3064. \
  3065. Call = function(type, ...)\
  3066.         local tArgs = {...}\
  3067.         local p = GetPeripheral(type)\
  3068.         peripheral.call(p.Side, unpack(tArgs))\
  3069. end\
  3070. \
  3071. local getNames = peripheral.getNames or function()\
  3072.         local tResults = {}\
  3073.         for n,sSide in ipairs( rs.getSides() ) do\
  3074.                 if peripheral.isPresent( sSide ) then\
  3075.                         table.insert( tResults, sSide )\
  3076.                         local isWireless = false\
  3077.                         if pcall(function()isWireless = peripheral.call(sSide, 'isWireless') end) then\
  3078.                                 isWireless = true\
  3079.                         end     \
  3080.                         if peripheral.getType( sSide ) == \"modem\" and not isWireless then\
  3081.                                 local tRemote = peripheral.call( sSide, \"getNamesRemote\" )\
  3082.                                 for n,sName in ipairs( tRemote ) do\
  3083.                                         table.insert( tResults, sName )\
  3084.                                 end\
  3085.                         end\
  3086.                 end\
  3087.         end\
  3088.         return tResults\
  3089. end\
  3090. \
  3091. GetPeripherals = function(filterType)\
  3092.         local peripherals = {}\
  3093.         for i, side in ipairs(getNames()) do\
  3094.                 local name = peripheral.getType(side):gsub(\"^%l\", string.upper)\
  3095.                 local code = string.upper(side:sub(1,1))\
  3096.                 if side:find('_') then\
  3097.                         code = side:sub(side:find('_')+1)\
  3098.                 end\
  3099. \
  3100.                 local dupe = false\
  3101.                 for i, v in ipairs(peripherals) do\
  3102.                         if v[1] == name .. ' ' .. code then\
  3103.                                 dupe = true\
  3104.                         end\
  3105.                 end\
  3106. \
  3107.                 if not dupe then\
  3108.                         local _type = peripheral.getType(side)\
  3109.                         local formattedType = _type:sub(1, 1):upper() .. _type:sub(2, -1)\
  3110.                         local isWireless = false\
  3111.                         if _type == 'modem' then\
  3112.                                 if not pcall(function()isWireless = peripheral.call(side, 'isWireless') end) then\
  3113.                                         isWireless = true\
  3114.                                 end     \
  3115.                                 if isWireless then\
  3116.                                         _type = 'wireless_modem'\
  3117.                                         formattedType = 'Wireless Modem'\
  3118.                                         name = 'W '..name\
  3119.                                 end\
  3120.                         end\
  3121.                         if not filterType or _type == filterType then\
  3122.                                 table.insert(peripherals, {Name = name:sub(1,8) .. ' '..code, Fullname = name .. ' ('..side:sub(1, 1):upper() .. side:sub(2, -1)..')', Side = side, Type = _type, Wireless = isWireless, FormattedType = formattedType})\
  3123.                         end\
  3124.                 end\
  3125.         end\
  3126.         return peripherals\
  3127. end\
  3128. \
  3129. GetSide = function(side)\
  3130.         for i, p in ipairs(GetPeripherals()) do\
  3131.                 if p.Side == side then\
  3132.                         return p\
  3133.                 end\
  3134.         end\
  3135. end\
  3136. \
  3137. PresentNamed = function(name)\
  3138.         return peripheral.isPresent(name)\
  3139. end\
  3140. \
  3141. CallType = function(type, ...)\
  3142.         local tArgs = {...}\
  3143.         local p = GetPeripheral(type)\
  3144.         return peripheral.call(p.Side, unpack(tArgs))\
  3145. end\
  3146. \
  3147. CallNamed = function(name, ...)\
  3148.         local tArgs = {...}\
  3149.         return peripheral.call(name, unpack(tArgs))\
  3150. end\
  3151. \
  3152. GetInfo = function(p)\
  3153.         local info = {}\
  3154.         local buttons = {}\
  3155.         if p.Type == 'computer' then\
  3156.                 local id = peripheral.call(p.Side:lower(),'getID')\
  3157.                 if id then\
  3158.                         info = {\
  3159.                                 ID = tostring(id)\
  3160.                         }\
  3161.                 else\
  3162.                         info = {}\
  3163.                 end\
  3164.         elseif p.Type == 'drive' then\
  3165.                 local discType = 'No Disc'\
  3166.                 local discID = nil\
  3167.                 local mountPath = nil\
  3168.                 local discLabel = nil\
  3169.                 local songName = nil\
  3170.                 if peripheral.call(p.Side:lower(), 'isDiskPresent') then\
  3171.                         if peripheral.call(p.Side:lower(), 'hasData') then\
  3172.                                 discType = 'Data'\
  3173.                                 discID = peripheral.call(p.Side:lower(), 'getDiskID')\
  3174.                                 if discID then\
  3175.                                         discID = tostring(discID)\
  3176.                                 else\
  3177.                                         discID = 'None'\
  3178.                                 end\
  3179.                                 mountPath = '/'..peripheral.call(p.Side:lower(), 'getMountPath')..'/'\
  3180.                                 discLabel = peripheral.call(p.Side:lower(), 'getDiskLabel')\
  3181.                         else\
  3182.                                 discType = 'Audio'\
  3183.                                 songName = peripheral.call(p.Side:lower(), 'getAudioTitle')\
  3184.                         end\
  3185.                 end\
  3186.                 if mountPath then\
  3187.                         table.insert(buttons, {Text = 'View Files', OnClick = function(self, event, side, x, y)GoToPath(mountPath)end})\
  3188.                 elseif discType == 'Audio' then\
  3189.                         table.insert(buttons, {Text = 'Play', OnClick = function(self, event, side, x, y)\
  3190.                                 if self.Text == 'Play' then\
  3191.                                         disk.playAudio(p.Side:lower())\
  3192.                                         self.Text = 'Stop'\
  3193.                                 else\
  3194.                                         disk.stopAudio(p.Side:lower())\
  3195.                                         self.Text = 'Play'\
  3196.                                 end\
  3197.                         end})\
  3198.                 else\
  3199.                         diskOpenButton = nil\
  3200.                 end\
  3201.                 if discType ~= 'No Disc' then\
  3202.                         table.insert(buttons, {Text = 'Eject', OnClick = function(self, event, side, x, y)disk.eject(p.Side:lower()) sleep(0) RefreshFiles() end})\
  3203.                 end\
  3204. \
  3205.                 info = {\
  3206.                         ['Disc Type'] = discType,\
  3207.                         ['Disc Label'] = discLabel,\
  3208.                         ['Song Title'] = songName,\
  3209.                         ['Disc ID'] = discID,\
  3210.                         ['Mount Path'] = mountPath\
  3211.                 }\
  3212.         elseif p.Type == 'printer' then\
  3213.                 local pageSize = 'No Loaded Page'\
  3214.                 local _, err = pcall(function() return tostring(peripheral.call(p.Side:lower(), 'getPgaeSize')) end)\
  3215.                 if not err then\
  3216.                         pageSize = tostring(peripheral.call(p.Side:lower(), 'getPageSize'))\
  3217.                 end\
  3218.                 info = {\
  3219.                         ['Paper Level'] = tostring(peripheral.call(p.Side:lower(), 'getPaperLevel')),\
  3220.                         ['Paper Size'] = pageSize,\
  3221.                         ['Ink Level'] = tostring(peripheral.call(p.Side:lower(), 'getInkLevel'))\
  3222.                 }\
  3223.         elseif p.Type == 'modem' then\
  3224.                 info = {\
  3225.                         ['Connected Peripherals'] = tostring(#peripheral.call(p.Side:lower(), 'getNamesRemote'))\
  3226.                 }\
  3227.         elseif p.Type == 'monitor' then\
  3228.                 local w, h = peripheral.call(p.Side:lower(), 'getSize')\
  3229.                 local screenType = 'Black and White'\
  3230.                 if peripheral.call(p.Side:lower(), 'isColour') then\
  3231.                         screenType = 'Colour'\
  3232.                 end\
  3233.                 local buttonTitle = 'Use as Screen'\
  3234.                 if OneOS.Settings:GetValues()['Monitor'] == p.Side:lower() then\
  3235.                         buttonTitle = 'Use Computer Screen'\
  3236.                 end\
  3237.                 table.insert(buttons, {Text = buttonTitle, OnClick = function(self, event, side, x, y)\
  3238.                                 self.Bedrock:DisplayAlertWindow('Reboot Required', \"To change screen you'll need to reboot your computer.\", {'Reboot', 'Cancel'}, function(value)\
  3239.                                         if value == 'Reboot' then\
  3240.                                                 if buttonTitle == 'Use Computer Screen' then\
  3241.                                                         OneOS.Settings:SetValue('Monitor', nil)\
  3242.                                                 else\
  3243.                                                         OneOS.Settings:SetValue('Monitor', p.Side:lower())\
  3244.                                                 end\
  3245.                                                 OneOS.Reboot()\
  3246.                                         end\
  3247.                                 end)\
  3248.                         end\
  3249.                 })\
  3250.                 info = {\
  3251.                         ['Type'] = screenType,\
  3252.                         ['Width'] = tostring(w),\
  3253.                         ['Height'] = tostring(h),\
  3254.                 }\
  3255.         end\
  3256.         info.Buttons = buttons\
  3257.         return info\
  3258. end",
  3259.   hash = "--\
  3260. --  Thanks to GravityScore for this!\
  3261. --  http://www.computercraft.info/forums2/index.php?/topic/8169-sha-256-in-pure-lua/\
  3262. --\
  3263. --  This is used to hash passwords sent with the secure text field. It just reduces the chance of people getting hacked.\
  3264. --\
  3265. \
  3266. --  \
  3267. --  Adaptation of the Secure Hashing Algorithm (SHA-244/256)\
  3268. --  Found Here: http://lua-users.org/wiki/SecureHashAlgorithm\
  3269. --  \
  3270. --  Using an adapted version of the bit library\
  3271. --  Found Here: https://bitbucket.org/Boolsheet/bslf/src/1ee664885805/bit.lua\
  3272. --  \
  3273. \
  3274. local MOD = 2^32\
  3275. local MODM = MOD-1\
  3276. \
  3277. local function memoize(f)\
  3278.         local mt = {}\
  3279.         local t = setmetatable({}, mt)\
  3280.         function mt:__index(k)\
  3281.                 local v = f(k)\
  3282.                 t[k] = v\
  3283.                 return v\
  3284.         end\
  3285.         return t\
  3286. end\
  3287. \
  3288. local function make_bitop_uncached(t, m)\
  3289.         local function bitop(a, b)\
  3290.                 local res,p = 0,1\
  3291.                 while a ~= 0 and b ~= 0 do\
  3292.                         local am, bm = a % m, b % m\
  3293.                         res = res + t[am][bm] * p\
  3294.                         a = (a - am) / m\
  3295.                         b = (b - bm) / m\
  3296.                         p = p*m\
  3297.                 end\
  3298.                 res = res + (a + b) * p\
  3299.                 return res\
  3300.         end\
  3301.         return bitop\
  3302. end\
  3303. \
  3304. local function make_bitop(t)\
  3305.         local op1 = make_bitop_uncached(t,2^1)\
  3306.         local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end)\
  3307.         return make_bitop_uncached(op2, 2 ^ (t.n or 1))\
  3308. end\
  3309. \
  3310. local bxor1 = make_bitop({[0] = {[0] = 0,[1] = 1}, [1] = {[0] = 1, [1] = 0}, n = 4})\
  3311. \
  3312. local function bxor(a, b, c, ...)\
  3313.         local z = nil\
  3314.         if b then\
  3315.                 a = a % MOD\
  3316.                 b = b % MOD\
  3317.                 z = bxor1(a, b)\
  3318.                 if c then z = bxor(z, c, ...) end\
  3319.                 return z\
  3320.         elseif a then return a % MOD\
  3321.         else return 0 end\
  3322. end\
  3323. \
  3324. local function band(a, b, c, ...)\
  3325.         local z\
  3326.         if b then\
  3327.                 a = a % MOD\
  3328.                 b = b % MOD\
  3329.                 z = ((a + b) - bxor1(a,b)) / 2\
  3330.                 if c then z = bit32_band(z, c, ...) end\
  3331.                 return z\
  3332.         elseif a then return a % MOD\
  3333.         else return MODM end\
  3334. end\
  3335. \
  3336. local function bnot(x) return (-1 - x) % MOD end\
  3337. \
  3338. local function rshift1(a, disp)\
  3339.         if disp < 0 then return lshift(a,-disp) end\
  3340.         return math.floor(a % 2 ^ 32 / 2 ^ disp)\
  3341. end\
  3342. \
  3343. local function rshift(x, disp)\
  3344.         if disp > 31 or disp < -31 then return 0 end\
  3345.         return rshift1(x % MOD, disp)\
  3346. end\
  3347. \
  3348. local function lshift(a, disp)\
  3349.         if disp < 0 then return rshift(a,-disp) end \
  3350.         return (a * 2 ^ disp) % 2 ^ 32\
  3351. end\
  3352. \
  3353. local function rrotate(x, disp)\
  3354.     x = x % MOD\
  3355.     disp = disp % 32\
  3356.     local low = band(x, 2 ^ disp - 1)\
  3357.     return rshift(x, disp) + lshift(low, 32 - disp)\
  3358. end\
  3359. \
  3360. local k = {\
  3361.         0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,\
  3362.         0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\
  3363.         0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\
  3364.         0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\
  3365.         0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\
  3366.         0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\
  3367.         0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,\
  3368.         0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\
  3369.         0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\
  3370.         0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\
  3371.         0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,\
  3372.         0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\
  3373.         0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,\
  3374.         0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\
  3375.         0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\
  3376.         0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\
  3377. }\
  3378. \
  3379. local function str2hexa(s)\
  3380.         return (string.gsub(s, \".\", function(c) return string.format(\"%02x\", string.byte(c)) end))\
  3381. end\
  3382. \
  3383. local function num2s(l, n)\
  3384.         local s = \"\"\
  3385.         for i = 1, n do\
  3386.                 local rem = l % 256\
  3387.                 s = string.char(rem) .. s\
  3388.                 l = (l - rem) / 256\
  3389.         end\
  3390.         return s\
  3391. end\
  3392. \
  3393. local function s232num(s, i)\
  3394.         local n = 0\
  3395.         for i = i, i + 3 do n = n*256 + string.byte(s, i) end\
  3396.         return n\
  3397. end\
  3398. \
  3399. local function preproc(msg, len)\
  3400.         local extra = 64 - ((len + 9) % 64)\
  3401.         len = num2s(8 * len, 8)\
  3402.         msg = msg .. \"\\128\" .. string.rep(\"\\0\", extra) .. len\
  3403.         assert(#msg % 64 == 0)\
  3404.         return msg\
  3405. end\
  3406. \
  3407. local function initH256(H)\
  3408.         H[1] = 0x6a09e667\
  3409.         H[2] = 0xbb67ae85\
  3410.         H[3] = 0x3c6ef372\
  3411.         H[4] = 0xa54ff53a\
  3412.         H[5] = 0x510e527f\
  3413.         H[6] = 0x9b05688c\
  3414.         H[7] = 0x1f83d9ab\
  3415.         H[8] = 0x5be0cd19\
  3416.         return H\
  3417. end\
  3418. \
  3419. local function digestblock(msg, i, H)\
  3420.         local w = {}\
  3421.         for j = 1, 16 do w[j] = s232num(msg, i + (j - 1)*4) end\
  3422.         for j = 17, 64 do\
  3423.                 local v = w[j - 15]\
  3424.                 local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))\
  3425.                 v = w[j - 2]\
  3426.                 w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))\
  3427.         end\
  3428. \
  3429.         local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]\
  3430.         for i = 1, 64 do\
  3431.                 local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))\
  3432.                 local maj = bxor(band(a, b), band(a, c), band(b, c))\
  3433.                 local t2 = s0 + maj\
  3434.                 local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))\
  3435.                 local ch = bxor (band(e, f), band(bnot(e), g))\
  3436.                 local t1 = h + s1 + ch + k[i] + w[i]\
  3437.                 h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2\
  3438.         end\
  3439. \
  3440.         H[1] = band(H[1] + a)\
  3441.         H[2] = band(H[2] + b)\
  3442.         H[3] = band(H[3] + c)\
  3443.         H[4] = band(H[4] + d)\
  3444.         H[5] = band(H[5] + e)\
  3445.         H[6] = band(H[6] + f)\
  3446.         H[7] = band(H[7] + g)\
  3447.         H[8] = band(H[8] + h)\
  3448. end\
  3449. \
  3450. function sha256(msg)\
  3451.         msg = preproc(msg, #msg)\
  3452.         local H = initH256({})\
  3453.         for i = 1, #msg, 64 do digestblock(msg, i, H) end\
  3454.         return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) ..\
  3455.                 num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4))\
  3456. end",
  3457.   [ ".Account.settings" ] = "{\
  3458.         Balance = 60,\
  3459.         Name = \"oeed\",\
  3460.         Hash = \"abcdef\",\
  3461.         Number = 123456789\
  3462. }",
  3463.   r = "os.reboot()",
  3464.   Wireless = "--This is just the OneOS Wireless API\
  3465. \
  3466. --OneOS uses channels between 4200 and 4300, avoid use where possible\
  3467. \
  3468. Channels = {\
  3469.         Ignored = 4299,\
  3470.         Ping = 4200,\
  3471.         PingReply = 4201,\
  3472.         oeedPayServerAvailable = 4260,\
  3473.         oeedPayServerAvailableReply = 4261,\
  3474.         oeedPayPocketPayPing = 4262,\
  3475.         oeedPayPocketPayPingReply = 4263,\
  3476.         oeedPayPocketPayPaymentInfo = 4264,\
  3477.         oeedPayPocketPayPaymentInfoReply = 4265,\
  3478.         oeedPayValidatePayment = 4266,\
  3479.         oeedPayValidatePaymentReply = 4267,\
  3480.         oeedPayPocketPayChallenge = 4268,\
  3481.         oeedPayPocketPayChallengeReply = 4269,\
  3482.         oeedPayPocketPayChallengeAnswer = 4270,\
  3483.         oeedPayPocketPayChallengeAnswerReply = 4271,\
  3484.         oeedPayPocketPayResult = 4272,\
  3485.         oeedPayBalanceCheck = 4273,\
  3486.         oeedPayBalanceCheckReply = 4274,\
  3487.         oeedPayAPIRequest = 4275,\
  3488.         oeedPayAPIRequestReply = 4276,\
  3489.         oeedPayNewAccount = 4277,\
  3490.         oeedPayNewAccountReply = 4278,\
  3491.         oeedPayGetAccountName = 4279,\
  3492.         oeedPayGetAccountNameReply = 4280,\
  3493. }\
  3494. \
  3495. local function isOpen(channel)\
  3496.         return Peripheral.CallType('wireless_modem', 'isOpen', channel)\
  3497. end\
  3498. \
  3499. local function open(channel)\
  3500.         if not isOpen(channel) then\
  3501.                 Peripheral.CallType('wireless_modem', 'open', channel)\
  3502.         end\
  3503. end\
  3504. \
  3505. Open = open\
  3506. \
  3507. local function close(channel)\
  3508.         Peripheral.CallType('wireless_modem', 'close', channel)\
  3509. end\
  3510. \
  3511. local function closeAll()\
  3512.         Peripheral.CallType('wireless_modem', 'closeAll')\
  3513. end\
  3514. \
  3515. local function transmit(channel, replyChannel, message)\
  3516.         Peripheral.CallType('wireless_modem', 'transmit', channel, replyChannel, textutils.serialize(message))\
  3517. end\
  3518. \
  3519. function Present()\
  3520.         if Peripheral.GetPeripheral('wireless_modem') == nil then\
  3521.                 return false\
  3522.         else\
  3523.                 return true\
  3524.         end\
  3525. end\
  3526. \
  3527. local function FormatMessage(message, messageID, destinationID)\
  3528.         return {\
  3529.                 content = textutils.serialize(message),\
  3530.                 senderID = os.getComputerID(),\
  3531.                 senderName = os.getComputerLabel(),\
  3532.                 channel = channel,\
  3533.                 replyChannel = reply,\
  3534.                 messageID = messageID or math.random(10000),\
  3535.                 destinationID = destinationID\
  3536.         }\
  3537. end\
  3538. \
  3539. local Timeout = function(func, time)\
  3540.         time = time or 1\
  3541.         parallel.waitForAny(func, function()\
  3542.                 sleep(time)\
  3543.                 --log('Timeout!'..time)\
  3544.         end)\
  3545. end\
  3546. \
  3547. RecieveMessage = function(_channel, messageID, timeout)\
  3548.         open(_channel)\
  3549.         local done = false\
  3550.         local event, side, channel, replyChannel, message = nil\
  3551.         Timeout(function()\
  3552.                 while not done do\
  3553.                         event, side, channel, replyChannel, message = os.pullEvent('modem_message')\
  3554.                         if channel ~= _channel then\
  3555.                                 event, side, channel, replyChannel, message = nil\
  3556.                         else\
  3557.                                 message = textutils.unserialize(message)\
  3558.                                 message.content = textutils.unserialize(message.content)\
  3559.                                 if messageID and messageID ~= message.messageID or (message.destinationID ~= nil and message.destinationID ~= os.getComputerID()) then\
  3560.                                         event, side, channel, replyChannel, message = nil\
  3561.                                 else\
  3562.                                         done = true\
  3563.                                 end\
  3564.                         end\
  3565.                 end\
  3566.         end,\
  3567.         timeout)\
  3568.         return event, side, channel, replyChannel, message\
  3569. end\
  3570. \
  3571. Initialise = function()\
  3572.         if Present() then\
  3573.                 for i, c in pairs(Channels) do\
  3574.                         open(c)\
  3575.                 end\
  3576.         end\
  3577. end\
  3578. \
  3579. HandleMessage = function(event, side, channel, replyChannel, message, distance)\
  3580.         message = textutils.unserialize(message)\
  3581.         message.content = textutils.unserialize(message.content)\
  3582. \
  3583.         if channel == Channels.Ping then\
  3584.                 if message.content == 'Ping!' then\
  3585.                         SendMessage(replyChannel, 'Pong!', nil, message.messageID)\
  3586.                 end\
  3587.         elseif message.destinationID ~= nil and message.destinationID ~= os.getComputerID() then\
  3588.         elseif Wireless.Responder then\
  3589.                 Wireless.Responder(event, side, channel, replyChannel, message, distance)\
  3590.         end\
  3591. end\
  3592. \
  3593. SendMessage = function(channel, message, reply, messageID, destinationID)\
  3594.         reply = reply or channel + 1\
  3595.         open(channel)\
  3596.         open(reply)\
  3597.         local _message = FormatMessage(message, messageID, destinationID)\
  3598.         transmit(channel, reply, _message)\
  3599.         return _message\
  3600. end\
  3601. \
  3602. Ping = function()\
  3603.         local message = SendMessage(Channels.Ping, 'Ping!', Channels.PingReply)\
  3604.         RecieveMessage(Channels.PingReply, message.messageID)\
  3605. end",
  3606.   Views = {
  3607.     [ "processing.view" ] = "{\
  3608.   [\"Children\"]={\
  3609.     [1]={\
  3610.       [\"Y\"]=\"50%\",\
  3611.       [\"X\"]=1,\
  3612.       [\"Width\"]=\"100%\",\
  3613.       [\"Type\"]=\"Label\",\
  3614.       [\"TextColour\"]=1,\
  3615.       [\"Text\"]=\"Processing Payment\",\
  3616.       [\"Align\"]=\"Center\",\
  3617.       [\"Name\"]=\"ProcessingLabel\"\
  3618.     },\
  3619.   },\
  3620.   [\"BackgroundColour\"]=2048,\
  3621. }",
  3622.     [ "main.view" ] = "{\
  3623.   [\"Children\"]={\
  3624.     [1]={\
  3625.       [\"Y\"]=1,\
  3626.       [\"X\"]=1,\
  3627.       [\"Height\"]=\"100%\",\
  3628.       [\"Width\"]=\"100%\",\
  3629.       [\"Type\"]=\"View\",\
  3630.       [\"BackgroundColour\"]=1,\
  3631.       [\"Children\"]={\
  3632.         [1]={\
  3633.           [\"Y\"]=\"50%\",\
  3634.           [\"X\"]=10,\
  3635.           [\"Type\"]=\"Label\",\
  3636.           [\"TextColour\"]=256,\
  3637.           [\"Text\"]=\"oeed\"\
  3638.         },\
  3639.         [2]={\
  3640.           [\"Y\"]=\"50%\",\
  3641.           [\"X\"]=14,\
  3642.           [\"Type\"]=\"Label\",\
  3643.           [\"TextColour\"]=128,\
  3644.           [\"Text\"]=\"Pay\"\
  3645.         },\
  3646.         [3]={\
  3647.           [\"Y\"]=\"100%\",\
  3648.           [\"X\"]=1,\
  3649.           [\"Width\"]=\"100%\",\
  3650.           [\"Type\"]=\"Label\",\
  3651.           [\"TextColour\"]=256,\
  3652.           [\"Align\"]=\"Center\",\
  3653.           [\"Text\"]=\"Connecting\",\
  3654.           [\"Name\"]=\"StatusLabel\"\
  3655.         },\
  3656.       }\
  3657.     },\
  3658.   },\
  3659.   [\"BackgroundColour\"]=1,\
  3660. }",
  3661.     [ "complete.view" ] = "{\
  3662.   [\"Children\"]={\
  3663.     [1]={\
  3664.       [\"Y\"]=\"50%,2\",\
  3665.       [\"X\"]=2,\
  3666.       [\"Width\"]=\"100%\",\
  3667.       [\"Type\"]=\"Label\",\
  3668.       [\"TextColour\"]=1,\
  3669.       [\"Text\"]=\"Payment Complete! \",\
  3670.       [\"Align\"]=\"Center\",\
  3671.     },\
  3672.     [2]={\
  3673.       [\"Y\"]=\"50%,-4\",\
  3674.       [\"X\"]=\"50%,-2\",\
  3675.       [\"Width\"]=7,\
  3676.       [\"Height\"]=5,\
  3677.       [\"Type\"]=\"ImageView\",\
  3678.       [\"Path\"]=\"tick\",\
  3679.     },\
  3680.   },\
  3681.   [\"BackgroundColour\"]=8192,\
  3682. }",
  3683.     [ "paymentdue.view" ] = "{\
  3684.   [\"Children\"]={\
  3685.     [1]={\
  3686.       [\"Y\"]=6,\
  3687.       [\"X\"]=1,\
  3688.       [\"Height\"]=3,\
  3689.       [\"Width\"]=\"100%\",\
  3690.       [\"Type\"]=\"View\",\
  3691.       [\"BackgroundColour\"]=128,\
  3692.       [\"Children\"]={\
  3693.         [1]={\
  3694.           [\"Y\"]=2,\
  3695.           [\"X\"]=1,\
  3696.           [\"Width\"]=\"100%\",\
  3697.           [\"Type\"]=\"Label\",\
  3698.           [\"TextColour\"]=1,\
  3699.           [\"Text\"]=\"$1.50\",\
  3700.           [\"Align\"]=\"Center\",\
  3701.           [\"Name\"]=\"AmountLabel\"\
  3702.         },\
  3703.       }\
  3704.     },\
  3705.     [2]={\
  3706.       [\"Y\"]=2,\
  3707.       [\"X\"]=1,\
  3708.       [\"Width\"]=\"100%\",\
  3709.       [\"Type\"]=\"Label\",\
  3710.       [\"TextColour\"]=128,\
  3711.       [\"Text\"]=\"'Blah Co' is requesting the following payment.\",\
  3712.       [\"Align\"]=\"Center\",\
  3713.       [\"Name\"]=\"InfoLabel\"\
  3714.     },\
  3715.     [3]={\
  3716.       [\"Y\"]=\"100%,-5\",\
  3717.       [\"X\"]=\"50%, 2\",\
  3718.       [\"Width\"]=10,\
  3719.       [\"Height\"]=3,\
  3720.       [\"Type\"]=\"Button\",\
  3721.       [\"BackgroundColour\"]=8192,\
  3722.       [\"TextColour\"]=1,\
  3723.       [\"Text\"]=\"Accept\",\
  3724.       [\"Align\"]=\"Center\",\
  3725.       [\"Name\"]=\"AcceptButton\"\
  3726.     },\
  3727.     [4]={\
  3728.       [\"Y\"]=\"100%,-5\",\
  3729.       [\"X\"]=\"50%,-10\",\
  3730.       [\"Width\"]=10,\
  3731.       [\"Height\"]=3,\
  3732.       [\"Type\"]=\"Button\",\
  3733.       [\"BackgroundColour\"]=16384,\
  3734.       [\"TextColour\"]=1,\
  3735.       [\"Text\"]=\"Deny\",\
  3736.       [\"Align\"]=\"Center\",\
  3737.       [\"Name\"]=\"DenyButton\"\
  3738.     },\
  3739.     [5]={\
  3740.       [\"Y\"]=\"100%\",\
  3741.       [\"X\"]=10,\
  3742.       [\"Type\"]=\"Label\",\
  3743.       [\"TextColour\"]=256,\
  3744.       [\"Text\"]=\"oeed\"\
  3745.     },\
  3746.     [6]={\
  3747.       [\"Y\"]=\"100%\",\
  3748.       [\"X\"]=14,\
  3749.       [\"Type\"]=\"Label\",\
  3750.       [\"TextColour\"]=128,\
  3751.       [\"Text\"]=\"Pay\"\
  3752.     },\
  3753.   },\
  3754.   [\"BackgroundColour\"]=1,\
  3755. }",
  3756.     [ "fail.view" ] = "{\
  3757.   [\"Children\"]={\
  3758.     [1]={\
  3759.       [\"Y\"]=\"50%,2\",\
  3760.       [\"X\"]=2,\
  3761.       [\"Width\"]=\"100%\",\
  3762.       [\"Type\"]=\"Label\",\
  3763.       [\"TextColour\"]=1,\
  3764.       [\"Text\"]=\"Payment Failed! \",\
  3765.       [\"Align\"]=\"Center\",\
  3766.     },\
  3767.     [2]={\
  3768.       [\"Y\"]=\"50%,-4\",\
  3769.       [\"X\"]=\"50%,-2\",\
  3770.       [\"Width\"]=5,\
  3771.       [\"Height\"]=5,\
  3772.       [\"Type\"]=\"ImageView\",\
  3773.       [\"Path\"]=\"cross\",\
  3774.     },\
  3775.   },\
  3776.   [\"BackgroundColour\"]=16384,\
  3777. }",
  3778.   },
  3779. }
  3780.  
  3781. local function run(tArgs)
  3782.  
  3783.   local fnFile, err = loadstring(files['startup'], 'startup')
  3784.   if err then
  3785.     error(err)
  3786.   end
  3787.  
  3788.   local function split(str, pat)
  3789.      local t = {}
  3790.      local fpat = "(.-)" .. pat
  3791.      local last_end = 1
  3792.      local s, e, cap = str:find(fpat, 1)
  3793.      while s do
  3794.         if s ~= 1 or cap ~= "" then
  3795.      table.insert(t,cap)
  3796.         end
  3797.         last_end = e+1
  3798.         s, e, cap = str:find(fpat, last_end)
  3799.      end
  3800.      if last_end <= #str then
  3801.         cap = str:sub(last_end)
  3802.         table.insert(t, cap)
  3803.      end
  3804.      return t
  3805.   end
  3806.  
  3807.   local function resolveTreeForPath(path, single)
  3808.     local _files = files
  3809.     local parts = split(path, '/')
  3810.     if parts then
  3811.       for i, v in ipairs(parts) do
  3812.         if #v > 0 then
  3813.           if _files[v] then
  3814.             _files = _files[v]
  3815.           else
  3816.             _files = nil
  3817.             break
  3818.           end
  3819.         end
  3820.       end
  3821.     elseif #path > 0 and path ~= '/' then
  3822.       _files = _files[path]
  3823.     end
  3824.     if not single or type(_files) == 'string' then
  3825.       return _files
  3826.     end
  3827.   end
  3828.  
  3829.   local oldFs = fs
  3830.   local env
  3831.   env = {
  3832.     fs = {
  3833.       list = function(path)
  3834.               local list = {}
  3835.               if fs.exists(path) then
  3836.             list = fs.list(path)
  3837.               end
  3838.         for k, v in pairs(resolveTreeForPath(path)) do
  3839.           if not fs.exists(path .. '/' ..k) then
  3840.             table.insert(list, k)
  3841.           end
  3842.         end
  3843.         return list
  3844.       end,
  3845.  
  3846.       exists = function(path)
  3847.         if fs.exists(path) then
  3848.           return true
  3849.         elseif resolveTreeForPath(path) then
  3850.           return true
  3851.         else
  3852.           return false
  3853.         end
  3854.       end,
  3855.  
  3856.       isDir = function(path)
  3857.         if fs.isDir(path) then
  3858.           return true
  3859.         else
  3860.           local tree = resolveTreeForPath(path)
  3861.           if tree and type(tree) == 'table' then
  3862.             return true
  3863.           else
  3864.             return false
  3865.           end
  3866.         end
  3867.       end,
  3868.  
  3869.       isReadOnly = function(path)
  3870.         if not fs.isReadOnly(path) then
  3871.           return false
  3872.         else
  3873.           return true
  3874.         end
  3875.       end,
  3876.  
  3877.       getName = fs.getName,
  3878.  
  3879.       getSize = fs.getSize,
  3880.  
  3881.       getFreespace = fs.getFreespace,
  3882.  
  3883.       makeDir = fs.makeDir,
  3884.  
  3885.       move = fs.move,
  3886.  
  3887.       copy = fs.copy,
  3888.  
  3889.       delete = fs.delete,
  3890.  
  3891.       combine = fs.combine,
  3892.  
  3893.       open = function(path, mode)
  3894.         if fs.exists(path) then
  3895.           return fs.open(path, mode)
  3896.         elseif type(resolveTreeForPath(path)) == 'string' then
  3897.           local handle = {close = function()end}
  3898.           if mode == 'r' then
  3899.             local content = resolveTreeForPath(path)
  3900.             handle.readAll = function()
  3901.               return content
  3902.             end
  3903.  
  3904.             local line = 1
  3905.             local lines = split(content, '\n')
  3906.             handle.readLine = function()
  3907.               if line > #lines then
  3908.                 return nil
  3909.               else
  3910.                 return lines[line]
  3911.               end
  3912.               line = line + 1
  3913.             end
  3914.                       return handle
  3915.           else
  3916.             error('Cannot write to read-only file (compilr archived).')
  3917.           end
  3918.         else
  3919.           return fs.open(path, mode)
  3920.         end
  3921.       end
  3922.     },
  3923.  
  3924.     io = {
  3925.       input = io.input,
  3926.       output = io.output,
  3927.       type = io.type,
  3928.       close = io.close,
  3929.       write = io.write,
  3930.       flush = io.flush,
  3931.       lines = io.lines,
  3932.       read = io.read,
  3933.       open = function(path, mode)
  3934.         if fs.exists(path) then
  3935.           return io.open(path, mode)
  3936.         elseif type(resolveTreeForPath(path)) == 'string' then
  3937.           local content = resolveTreeForPath(path)
  3938.           local f = fs.open(path, 'w')
  3939.           f.write(content)
  3940.           f.close()
  3941.           if mode == 'r' then
  3942.             return io.open(path, mode)
  3943.           else
  3944.             error('Cannot write to read-only file (compilr archived).')
  3945.           end
  3946.         else
  3947.           return io.open(path, mode)
  3948.         end
  3949.       end
  3950.     },
  3951.  
  3952.     loadfile = function( _sFile )
  3953.         local file = env.fs.open( _sFile, "r" )
  3954.         if file then
  3955.             local func, err = loadstring( file.readAll(), fs.getName( _sFile ) )
  3956.             file.close()
  3957.             return func, err
  3958.         end
  3959.         return nil, "File not found: ".._sFile
  3960.     end,
  3961.  
  3962.     dofile = function( _sFile )
  3963.         local fnFile, e = env.loadfile( _sFile )
  3964.         if fnFile then
  3965.             setfenv( fnFile, getfenv(2) )
  3966.             return fnFile()
  3967.         else
  3968.             error( e, 2 )
  3969.         end
  3970.     end
  3971.   }
  3972.  
  3973.   setmetatable( env, { __index = _G } )
  3974.  
  3975.   local tAPIsLoading = {}
  3976.   env.os.loadAPI = function( _sPath )
  3977.       local sName = fs.getName( _sPath )
  3978.       if tAPIsLoading[sName] == true then
  3979.           printError( "API "..sName.." is already being loaded" )
  3980.           return false
  3981.       end
  3982.       tAPIsLoading[sName] = true
  3983.          
  3984.       local tEnv = {}
  3985.       setmetatable( tEnv, { __index = env } )
  3986.       local fnAPI, err = env.loadfile( _sPath )
  3987.       if fnAPI then
  3988.           setfenv( fnAPI, tEnv )
  3989.           fnAPI()
  3990.       else
  3991.           printError( err )
  3992.           tAPIsLoading[sName] = nil
  3993.           return false
  3994.       end
  3995.      
  3996.       local tAPI = {}
  3997.       for k,v in pairs( tEnv ) do
  3998.           tAPI[k] =  v
  3999.       end
  4000.      
  4001.       env[sName] = tAPI    
  4002.       tAPIsLoading[sName] = nil
  4003.       return true
  4004.   end
  4005.  
  4006.   env.shell = shell
  4007.  
  4008.   setfenv( fnFile, env )
  4009.   fnFile(unpack(tArgs))
  4010. end
  4011.  
  4012. local function extract()
  4013.     local function node(path, tree)
  4014.         if type(tree) == 'table' then
  4015.             fs.makeDir(path)
  4016.             for k, v in pairs(tree) do
  4017.                 node(path .. '/' .. k, v)
  4018.             end
  4019.         else
  4020.             local f = fs.open(path, 'w')
  4021.             if f then
  4022.                 f.write(tree)
  4023.                 f.close()
  4024.             end
  4025.         end
  4026.     end
  4027.     node('', files)
  4028. end
  4029.  
  4030. local tArgs = {...}
  4031. if #tArgs == 1 and tArgs[1] == '--extract' then
  4032.   extract()
  4033. else
  4034.   run(tArgs)
  4035. end
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top