Advertisement
Oeed

oeedPay PocketPay

Nov 8th, 2014
251
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 104.23 KB | None | 0 0
  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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement