dannysmc95

FusionOS

Jan 26th, 2015
2,054
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 430.55 KB | None | 0 0
  1. --[[
  2.     Name: Fusion OS
  3.     Created By: DannySMc
  4.     Platform: Lua Virtual Machine
  5.     Creation Start: (on) 20/01/2015 (at) 22:00
  6.     Creation Finish: (on) 26/01/2015 (at) 16:21
  7.    
  8.     Login
  9.     Desktop
  10.     Main Menu
  11.     File Explorer
  12.     Sketch
  13.     Ink
  14.     Email Client
  15.     LuaIDE
  16.     File Share
  17.     Settings
  18.     Help
  19.  
  20.     Folders:
  21.     /core/
  22.         /user/
  23.             /<username>/
  24.         /help/
  25.             /Apps/
  26.             /Users/
  27.             /API/
  28.             /Controls/
  29.             /Tablet/
  30.             /Credits/
  31.             /License/
  32.         /apps/
  33.             /AppStore/
  34.             /Chat/
  35.             /Translate/
  36.         /conf/
  37.             /colours/
  38.             /imgmaps/
  39.             /settings/
  40.  
  41.     File Extensions:
  42.     .fusa - Fusion App
  43.     .fusi - Fusion Image
  44.     .fusc - Fusion Config
  45.     .fush - Fusion Help
  46.     .fusu - Fusion User
  47.     .fusp - Fusion Colour Palette
  48.     .fuso - Fusion Operating System
  49.     .fusd - Fusion Update File
  50.     .fusb - Fusion Bios File
  51.     .fusl - Fusion Link File
  52.     .fuse - Fusion Encrypted File
  53.  
  54.     Program Arguments:
  55.     fusion update -> Will attempt to update the console with an update file, this is used when the update function has been run.
  56.     fusion devmode <app> -> Will load the console into a dev mode state that will load the taskbar and screen size and allow you to test apps.
  57. ]]
  58.  
  59. -- Set Tables/Configuration/Variables
  60. local tArgs = {...}
  61.  
  62. local nVersion = "1.0.5"
  63. local nAPIVersion = "4.5"
  64. local nSysCoreFolder = "/core/"
  65.  
  66. local tColours = {
  67.     "white",
  68.     "blue",
  69.     "cyan",
  70.     "lightGrey",
  71.     "pink",
  72.     "lime",
  73.     "orange",
  74.     "green",
  75. }
  76.  
  77. local tFolders = {
  78.     "/core/",
  79.     "/core/user/",
  80.     "/core/apps/",
  81.     "/core/conf/",
  82.     "/core/xplore/",
  83.     "/core/addons/",
  84.     "/core/conf/colours/",
  85.     "/core/conf/imgmaps/",
  86.     "/core/conf/settings/",
  87. }
  88.  
  89. local tExtensions = {
  90.     App = ".fusa",
  91.     Image = ".fusi",
  92.     Config = ".fusc",
  93.     Help = ".fush",
  94.     User = ".fusu",
  95.     Palette = ".fusp",
  96.     OS = ".fuso",
  97.     Update = ".fusd",
  98.     Bios = ".fusb",
  99.     Link = ".fusl",
  100.     Encrypted = ".fuse",
  101.     XplorePage = ".xpl"
  102. }
  103.  
  104. -- Current defaults before overwriting
  105. maintc = "lightBlue"
  106. mainbc = "grey"
  107. texttc = "black"
  108. textbc = "white"
  109. currenttc = "lightGrey"
  110. timetc = "lime"
  111. titletc = "white"
  112. extratc = "red"
  113.  
  114. local tUrls = {
  115.     CCSystems = "https://dannysmc.com/files/php/emailsystem.php",
  116.     FusionUpdate = "https://dannysmc.com/programs/fusion/fusion",
  117.     FusionNews = "https://dannysmc.com/programs/fusion/news.fusa",
  118.     FusionHelpFiles = "https://dannysmc.com/programs/fusion/help.fush",
  119.     FusionFiles = "https://dannysmc.com/programs/fusion/imgmaps.fusc",
  120.     FusionBugreport = "https://dannysmc.com/ccdb/email.php",
  121.     FusionUserImage = "https://dannysmc.com/programs/fusion/core/conf/imgmaps/defuser.fusi"
  122. }
  123.  
  124. if tArgs[1] == "devmode" then
  125.     init("devmode")
  126. end
  127.  
  128. function init(command)
  129.     if command == "install" then
  130.         -- Create folders
  131.         col.screen("white", "white")
  132.         drawScreen("taskbar", "Install", "Install Process", "Please Wait")
  133.         col.set("cyan", "white")
  134.         term.setCursorPos(1,5)
  135.  
  136.         print("Welcome to Fusion Graphical User Interface, we are going to attempt to install Fusion...")
  137.         sleep(1)
  138.  
  139.         print("Creating Directories...")
  140.         sleep(0.5)
  141.         for _, v in ipairs(tFolders) do
  142.             print("> Creating Folder: "..v)
  143.             sleep(0.5)
  144.             fs.makeDir(v)
  145.         end
  146.  
  147.         print("> Downloading Default User Image Map...")
  148.         local img = [[
  149. 33333333333
  150. 33377733333
  151. 33733373333
  152. 33333373333
  153. 33333733333
  154. 33337333333
  155. 33333333333
  156.  
  157.         ]]
  158.         local tempimg = fs.open("/core/conf/imgmaps/defuser.fusi", "w")
  159.         tempimg.write(img)
  160.         tempimg.close()
  161.         sleep(0.5)
  162.  
  163.         print("> Creating Settings File...")
  164.         sleep(0.5)
  165.         -- Create Config File
  166.         local confFile = {
  167.             {
  168.                 "Enable Rednet Connections",
  169.                 "Update Fusion System / API",
  170.                 "Uninstall Fusion System",
  171.                 "Empty Setting 4",
  172.                 "Empty Setting 5",
  173.                 "Empty Setting 6",
  174.                 "Empty Setting 7",
  175.             },
  176.             {
  177.                 false,
  178.                 false,
  179.                 false,
  180.                 false,
  181.                 false,
  182.                 false,
  183.                 false,
  184.             },
  185.         }
  186.         local configFile = config.save(confFile, "/core/conf/settings/settings.fusc")
  187.  
  188.         print("> Creating Startup File...")
  189.         sleep(0.5)
  190.         local startFile = fs.open("startup", "w")
  191.         startFile.write('shell.run("fusion")')
  192.         startFile.close()
  193.  
  194.         print("> Starting Login...")
  195.         sleep(1)
  196.  
  197.         -- Go to login
  198.         login()
  199.     elseif command == "uninstall" then
  200.         col.screen("white", "white")
  201.         drawScreen("taskbar", "Uninstall", "Uninstall Process", "Please Wait")
  202.         col.set("cyan", "white")
  203.         term.setCursorPos(1,5)
  204.         print("> Uninstall Fusion, please wait")
  205.         for _, v in ipairs(tFolders) do
  206.             print("Deleting Folder: "..v)
  207.             sleep(0.5)
  208.             fs.delete(v)
  209.         end
  210.         print("> Deleting Startup File")
  211.         fs.delete("startup")
  212.         print("> Leaving The Fusion File...")
  213.         sleep(0.5)
  214.         print("> Rebooting...")
  215.         sleep(1.5)
  216.         os.reboot()
  217.     elseif command == "devmode" then
  218.         print("> Not Completed...")
  219.         sleep(2)
  220.         os.shutdown()
  221.     end
  222. end
  223.  
  224. function drawScreen(object, running, title, extra)
  225.     if object == "boot" then
  226.  
  227.     elseif object == "option" then
  228.         draw.box(8, 36, 7, 3, " ", "lightBlue", "lightBlue")
  229.         draw.box(8, 36, 7, 3, " ", "lightBlue", "lightBlue")
  230.         draw.textc(running, 7, false, "white", "lightBlue")
  231.         draw.box(9, 34, 8, 1, " ", "white", "white")
  232.         col.set("black", "white")
  233.         term.setCursorPos(9,8)
  234.         write("> ")
  235.         local textinput = tostring(read())
  236.         return textinput
  237.     elseif object == "apps" then
  238.         draw.texta("Download App", 5, 18, false, "grey", "white")
  239.         draw.texta("Delete App", 37, 18, false, "grey", "white")
  240.  
  241.     elseif object == "login" then
  242.         draw.texta("Register", 5, 18, false, "black", "white")
  243.         draw.texta("Login", 42, 18, false, "red", "white")
  244.         image.draw(21, 5, "/core/conf/imgmaps/defuser")
  245.         draw.box(8, 36, 14, 1, " ", "lightBlue", "lightBlue")
  246.     elseif object == "register" then
  247.         draw.texta("Register", 5, 18, false, "red", "white")
  248.         draw.texta("Login", 42, 18, false, "black", "white")
  249.         draw.texta("Username:", 8, 6, false, "grey", "white")
  250.         draw.texta("Password:", 8, 9, false, "grey", "white")
  251.         draw.texta("Email:", 8, 12, false, "grey", "white")
  252.         draw.box(8, 36, 7, 1, " ", "lightBlue", "lightBlue")
  253.         draw.box(8, 36, 10, 1, " ", "lightBlue", "lightBlue")
  254.         draw.box(8, 36, 13, 1, " ", "lightBlue", "lightBlue")
  255.     elseif object == "desktop" then
  256.         --// Draw File Explorer Shortcut
  257.         draw.texta("         ", 5, 6, false, "orange", "orange")
  258.         draw.texta("All FILES", 5, 7, false, "grey", "yellow")
  259.         draw.texta("         ", 5, 8, false, "yellow", "yellow")
  260.  
  261.         --// Draw LuaIDE Shortcut
  262.         draw.texta("1:", 16, 6, false, "lightBlue", "grey")
  263.         draw.texta("2:", 16, 7, false, "lightBlue", "grey")
  264.         draw.texta("3:", 16, 8, false, "lightBlue", "grey")
  265.         draw.texta(" LuaIDE", 18, 6, false, "white", "lightGrey")
  266.         draw.texta(" - - - ", 18, 7, false, "white", "lightGrey")
  267.         draw.texta(" - - - ", 18, 8, false, "white", "lightGrey")
  268.  
  269.         --// Draw Ink Shortcut
  270.         draw.box(27, 9, 6, 3, " ", "white", "grey")
  271.         draw.texta("   INK   ", 27, 6, false, "lightBlue", "grey")
  272.         draw.texta("AaBbCc-", 28, 7, false, "white", "lightGrey")
  273.         draw.texta("-------", 28, 8, false, "white", "lightGrey")
  274.  
  275.         --// Draw Sketch Shortcut
  276.         draw.box(38, 9, 6, 3, " ", "white", "lightGrey")
  277.         draw.box(38, 1, 6, 3, " ", "white", "blue")
  278.         draw.box(39, 1, 6, 2, " ", "white", "yellow")
  279.         draw.box(40, 2, 7, 2, " ", "white", "red")
  280.         draw.box(42, 1, 6, 3, " ", "white", "pink")
  281.         draw.box(43, 2, 6, 3, " ", "white", "orange")
  282.         draw.box(45, 1, 6, 3, " ", "white", "green")
  283.         draw.box(46, 1, 6, 3, " ", "white", "lightBlue")
  284.         draw.texta("/", 39, 7, false, "cyan", "yellow")
  285.         draw.texta("S", 40, 7, false, "lime", "red")
  286.         draw.texta("K", 41, 7, false, "lime", "red")
  287.         draw.texta("E", 42, 7, false, "red", "pink")
  288.         draw.texta("T", 43, 7, false, "blue", "orange")
  289.         draw.texta("C", 44, 7, false, "blue", "orange")
  290.         draw.texta("H", 45, 7, false, "white", "green")
  291.  
  292.         --// Draw X-Plore Shortcut
  293.         draw.box(5, 1, 11, 1, ">", "lime", "grey")
  294.         draw.texta(" URL    ", 6, 11, false, "white", "lightGrey")
  295.         draw.texta("         ", 5, 12, false, "red", "lightBlue")
  296.         draw.texta(" X-PLORE ", 5, 13, false, "red", "lightBlue")
  297.  
  298.         --// Draw Apps Shortcut
  299.         draw.texta("         ", 16, 11, false, "orange", "orange")
  300.         draw.texta("  >APPS  ", 16, 12, false, "grey", "yellow")
  301.         draw.texta("         ", 16, 13, false, "yellow", "yellow")
  302.  
  303.         --// Draw Settings Shortcut
  304.         draw.texta(" C.Panel ", 27, 11, false, "white", "grey")
  305.         draw.texta("[x] Touch", 27, 12, false, "white", "lightGrey")
  306.         draw.texta("[o] Shell", 27, 13, false, "white", "lightGrey")
  307.  
  308.         --// Draw HelpFilesShortcut
  309.         draw.texta(" ?     ? ", 38, 11, false, "grey", "orange")
  310.         draw.texta("HELP FILE", 38, 12, false, "grey", "yellow")
  311.         draw.texta(" ?     ? ", 38, 13, false, "grey", "yellow")
  312.  
  313.         draw.texta("System", 5, 18, false, "grey", "white")
  314.         draw.texta("License", 22, 18, false, "grey", "white")
  315.         draw.texta("Credits", 40, 18, false, "grey", "white")
  316.  
  317.     elseif object == "desktop2" then
  318.  
  319.         --// Draw Bug Report Shortcut
  320.         draw.texta(" [ERROR] ", 5, 6, false, "red", "lightGrey")
  321.         draw.texta("Bug Form:", 5, 7, false, "white", "grey")
  322.         draw.texta("         ", 5, 8, false, "red", "lightGrey")
  323.  
  324.         --// Draw Addons Shortcut
  325.         draw.texta("  ADDON  ", 16, 6, false, "lime", "grey")
  326.         draw.texta("1:", 16, 7, false, "lightBlue", "grey")
  327.         draw.texta("2:", 16, 8, false, "lightBlue", "grey")
  328.         draw.texta(" HTTPS ", 18, 7, false, "lightBlue", "lightGrey")
  329.         draw.texta(" RUN   ", 18, 8, false, "lightBlue", "lightGrey")
  330.  
  331.         --// Draw Fusion Shell Shortcut
  332.         draw.texta("  Shell  ", 27, 6, false, "white", "red")
  333.         draw.texta("> Explode", 27, 7, false, "green", "pink")
  334.         draw.texta("'BANG' -@", 27, 8, false, "green", "pink")
  335.  
  336.         --[[ // Draw App Store Shortcut
  337.         draw.texta(" Fusions ", 38, 6, false, "white", "blue")
  338.         draw.texta("   App   ", 38, 7, false, "white", "lightBlue")
  339.         draw.texta("  Store  ", 38, 8, false, "white", "blue")
  340.  
  341.         draw.texta("System", 5, 18, false, "grey", "white")
  342.         draw.texta("License", 22, 18, false, "grey", "white")
  343.         draw.texta("Credits", 40, 18, false, "grey", "white")]]
  344.  
  345.     elseif object == "taskbar" then
  346.         draw.box(1, 51, 1, 3, " ", maintc, mainbc)
  347.         draw.box(1, 51, 2, 1, " ", maintc, mainbc)
  348.  
  349.         local tLetters = {"U", "S", "I", "O", "N", ":"}
  350.         for k ,v in ipairs(tLetters) do
  351.             if k == 1 then
  352.                 draw.texta("F", 1, 1, false, tColours[math.random(8)], mainbc)
  353.             end
  354.             draw.texta(v, k+1, 1, false, tColours[math.random(8)], mainbc)
  355.         end
  356.  
  357.         draw.texta(running, 9, 1, false, currenttc, mainbc)
  358.         draw.texta(misc.time(), 47, 1, false, timetc, mainbc)
  359.         draw.textc(title, 2, false, titletc, mainbc)
  360.         if extra then
  361.             draw.textc(extra, 3, false, extratc, mainbc)
  362.         end
  363.     end
  364. end
  365.  
  366. function infoScreen(object, pageID)
  367.     if object == "system" then
  368.         -- Show System Storage / Versions etc.
  369.         col.screen("white", "white")
  370.         drawScreen("taskbar", "System", "System Information", "Click Fusion to go back")
  371.         local freeSpace = fs.getFreeSpace("/")
  372.         local osSize = fs.getSize("fusion")
  373.         if tostring(freeSpace) == "inf" then
  374.             freeSpace = "Unlimited"
  375.         end
  376.         local applist = fs.list("/core/apps/")
  377.         local appsize = 0
  378.         for _, v in pairs(applist) do
  379.             appsize = appsize + fs.getSize("/core/apps/"..v)
  380.         end
  381.         local osSize = fs.getSize("fusion")
  382.         draw.texta("STORAGE", 7, 5, false, "black", "white")
  383.         draw.texta("Free Space: ", 3, 7, false, "red", "white")
  384.         draw.texta("Fusion Size: ", 3, 10, false, "red", "white")
  385.         draw.texta("Apps Folder Size: ", 3, 13, false, "red", "white")
  386.         draw.texta(tostring(freeSpace).." Bytes", 6, 8, false, "blue", "white")
  387.         draw.texta(tostring(osSize).." Bytes", 6, 11, false, "blue", "white")
  388.         draw.texta(tostring(appsize).." Bytes", 6, 14, false, "blue", "white")
  389.  
  390.         draw.texta("VERSION", 36, 5, false, "black", "white")
  391.         draw.texta("Fusion Version: ", 32, 7, false, "red", "white")
  392.         draw.texta("Fusion API Version: ", 32, 10, false, "red", "white")
  393.         draw.texta("System Core Folder: ", 32, 13, false, "red", "white")
  394.         draw.texta(nVersion, 35, 8, false, "blue", "white")
  395.         draw.texta(nAPIVersion, 35, 11, false, "blue", "white")
  396.         draw.texta(nSysCoreFolder, 35, 14, false, "blue", "white")
  397.  
  398.         col.set("green", "white")
  399.         term.setCursorPos(1, 16)
  400.         print("Please take note of these and include them in any")
  401.         print("type of bug reports/fixes so I know what version")
  402.         print("you are running.")
  403.  
  404.         while true do
  405.             local args = { os.pullEvent() }
  406.             if args[1] == "timer" then
  407.                 drawScreen("taskbar", "System", "System Information", "Click Fusion to go back")
  408.             elseif args[1] == "mouse_click" then
  409.                 if (args[3] >= 1 and args[3] <= 8) and (args[4] == 1) then
  410.                     desktop()
  411.                 end
  412.             end
  413.         end
  414.     elseif object == "license" then
  415.         -- Show Fusion License
  416.         col.screen("white", "white")
  417.         drawScreen("taskbar", "License", "Fusion's License", "Click Fusion to go back")
  418.         draw.box(1, 51, 19, 1, " ", "blue", "lightGrey")
  419.         if pageID == 1 then
  420.             draw.texta("< Back", 1, 19, false, "lightBlue", "lightGrey")
  421.             draw.texta("Next >", 46, 19, false, "blue", "lightGrey")
  422.         elseif pageID == 3 then
  423.             draw.texta("< Back", 1, 19, false, "blue", "lightGrey")
  424.             draw.texta("Next >", 46, 19, false, "lightBlue", "lightGrey")
  425.         else
  426.             draw.texta("< Back", 1, 19, false, "blue", "lightGrey")
  427.             draw.texta("Next >", 46, 19, false, "blue", "lightGrey")
  428.         end
  429.         draw.textc(pageID.." / 3", 19, false, "blue", "lightGrey")
  430.  
  431.         if pageID == 1 then
  432.             term.setCursorPos(1, 5)
  433.             col.set("red", "white")
  434.             print("This work is licensed under the Creative Commons")
  435.             print("Attribution-NonCommercial-NoDerivatives 4.0")
  436.             print("International License. To view a copy of this")
  437.             print("license, visit:")
  438.             col.set("cyan", "white")
  439.             term.setCursorPos(1, 10)
  440.             print("http://creativecommons.org/licenses/by-nc-nd/4.0/.")
  441.             term.setCursorPos(1, 12)
  442.             col.set("green", "white")
  443.             print("You are free to:")
  444.             col.set("blue", "white")
  445.             write("Share ")
  446.             col.set("grey", "white")
  447.             print("- copy and redistribute the material in any")
  448.             print("medium or format (The licensor cannot revoke these")
  449.             print("freedoms as long as you follow the license terms.)")
  450.         elseif pageID == 2 then
  451.             term.setCursorPos(1, 5)
  452.             col.set("green", "white")
  453.             print("Under the following terms:")
  454.             col.set("blue", "white")
  455.             write("Attribution ")
  456.             col.set("grey", "white")
  457.             print("- You must give appropriate credit, ")
  458.             print("provide a link to the license, and indicate if")
  459.             print("changes were made. You may do so in any reasonable")
  460.             print("manner, but not in any way that suggests the")
  461.             print("licensor endorses you or your use.")
  462.             term.setCursorPos(1, 13)
  463.             col.set("blue", "white")
  464.             write("NonCommercial ")
  465.             col.set("grey", "white")
  466.             print("- You may not use the material")
  467.             print("for commercial purposes.")
  468.         elseif pageID == 3 then
  469.             term.setCursorPos(1, 5)
  470.             col.set("blue", "white")
  471.             write("NoDerivatives ")
  472.             col.set("grey", "white")
  473.             print("- If you remix, transform, or build")
  474.             print("upon the material, you may not distribute the")
  475.             print("modified material.")
  476.             term.setCursorPos(1, 9)
  477.             col.set("blue", "white")
  478.             write("No additional restrictions ")
  479.             col.set("grey", "white")
  480.             print("- You may not apply")
  481.             print("legal terms or technological measures that legally")
  482.             print("restrict others from doing anything the license")
  483.             print("permits.")
  484.         end
  485.        
  486.  
  487.         while true do
  488.             local args = { os.pullEvent() }
  489.             if args[1] == "timer" then
  490.                 drawScreen("taskbar", "License", "Fusion's License", "Click Fusion to go back")
  491.             elseif args[1] == "mouse_click" then
  492.                 if (args[3] >= 1 and args[3] <= 8) and (args[4] == 1) then
  493.                     desktop()
  494.                 elseif (args[3] >= 1 and args[3] <= 6) and (args[4] == 19) then
  495.                     if pageID > 1 then
  496.                         pageID = pageID - 1
  497.                         infoScreen("license", pageID)
  498.                         break
  499.                     end
  500.                 elseif (args[3] >= 45 and args[3] <= 51) and (args[4] == 19) then
  501.                     if pageID < 3 then
  502.                         pageID = pageID + 1
  503.                         infoScreen("license", pageID)
  504.                         break
  505.                     end
  506.                 end
  507.             end
  508.         end
  509.     elseif object == "credits" then
  510.         -- Show Fusion Credits
  511.         col.screen("white", "white")
  512.         drawScreen("taskbar", "Credits", "All Credits", "Click Fusion to go back")
  513.         col.set("black", "white")
  514.         term.setCursorPos(1,5)
  515.         print("Here are the credits for Fusion, these include")
  516.         print("programs, code help and testers:")
  517.         term.setCursorPos(1, 8)
  518.         col.set("blue", "white")
  519.         write("GravityScore ")
  520.         col.set("red", "white")
  521.         print("- For the LuaIDE program and of course")
  522.         print("the Sublime Text 3 Package")
  523.         term.setCursorPos(1, 11)
  524.         col.set("blue", "white")
  525.         write("OEED ")
  526.         col.set("red", "white")
  527.         print("- For the Sketch and Ink programs")
  528.         term.setCursorPos(1, 13)
  529.         col.set("blue", "white")
  530.         write("Friends ")
  531.         col.set("red", "white")
  532.         print("- For testing it out before release.")
  533.         term.setCursorPos(1, 15)
  534.         col.set("blue", "white")
  535.         write("wieselkatze ")
  536.         col.set("red", "white")
  537.         print("- For editing a code snippet to help with the file browser.")
  538.         term.setCursorPos(1, 18)
  539.         col.set("blue", "white")
  540.         write("Fusion Users ")
  541.         col.set("red", "white")
  542.         term.setCursorPos(14, 18)
  543.         write("- For actually using the OS and/or at")
  544.         term.setCursorPos(1, 19)
  545.         write("least testing it and giving me feedback.")
  546.  
  547.         while true do
  548.             local args = { os.pullEvent() }
  549.             if args[1] == "timer" then
  550.                 drawScreen("taskbar", "Credits", "All Credits", "Click Fusion to go back")
  551.             elseif args[1] == "mouse_click" then
  552.                 if (args[3] >= 1 and args[3] <= 8) and (args[4] == 1) then
  553.                     desktop()
  554.                 end
  555.             end
  556.         end
  557.     end
  558. end
  559.  
  560. function fusionshell()
  561.     col.screen("white", "white")
  562.     drawScreen("taskbar", "Shell", "Fusion's Shell", "Type 'help' for the help menu")
  563.     col.set("cyan", "white")
  564.     term.setCursorPos(1,5)
  565.  
  566.     local tHistory = {}
  567.  
  568.     local helpdata = {
  569.         {
  570.             "delete",
  571.             "move",
  572.             "copy",
  573.             "edit",
  574.             "exit",
  575.             "redraw",
  576.             "dir",
  577.             "help",
  578.             "mkdir",
  579.             "time",
  580.         },
  581.         {
  582.             "This will delete a file using the argument you give it.",
  583.             "This will move the file path given in the first argument, to the file path given in the second.",
  584.             "This will copy a file with from the first argument path to the second argument path.",
  585.             "Edit will automatically send you to LuaIDE (GravityScore).",
  586.             "Exit will exit the shell and send you back to the desktop.",
  587.             "This will redraw the shell as it may get mucked up due to the shell being printed on.",
  588.             "This will get the current files at the specified path.",
  589.             "This will display the help menu.",
  590.             "This will make a folder at the specified path.",
  591.             "This will print Minecraft's current time and day.",
  592.         },
  593.     }
  594.    
  595.     while true do
  596.         write("> ")
  597.         command = read()
  598.  
  599.         tCommand = {}
  600.         for id in command:gmatch("%S+") do
  601.             table.insert(tCommand, id)
  602.         end
  603.  
  604.         if tCommand[1] == "help" then
  605.             if #tCommand == 1 then
  606.                 print(table.concat(helpdata[1], ", "))
  607.                 print("Use: help <topic>")
  608.             else
  609.                 for k, v in ipairs(helpdata[1]) do
  610.                     if tCommand[2] == v then
  611.                         print(helpdata[2][k])
  612.                     end
  613.                 end
  614.             end
  615.         elseif tCommand[1] == "delete" then
  616.             if #tCommand >= 2 then
  617.                 fs.delete(tCommand[2])
  618.             else
  619.                 print("Wrong Usage")
  620.             end
  621.         elseif tCommand[1] == "move" then
  622.             if #tCommand >= 3 then
  623.                 fs.move(tCommand[2], tCommand[3])
  624.             else
  625.                 print("Wrong Usage")
  626.             end
  627.         elseif tCommand[1] == "copy" then
  628.             if #tCommand >= 3 then
  629.                 fs.copy(tCommand[2], tCommand[3])
  630.             else
  631.                 print("Wrong Usage")
  632.             end
  633.         elseif tCommand[1] == "edit" then
  634.             if #tCommand >= 2 then
  635.                 gravityscore_luaide()
  636.                 fusionshell()
  637.             else
  638.                 print("Wrong Usage")
  639.             end
  640.         elseif tCommand[1] == "exit" then
  641.             desktop(2)
  642.         elseif tCommand[1] == "redraw" then
  643.             fusionshell()
  644.         elseif tCommand[1] == "dir" then
  645.             if #tCommand >= 2 then
  646.                 local list = fs.list(tCommand[2])
  647.                 print(table.concat(list, ", "))
  648.             else
  649.                 print("Wrong Usage")
  650.             end
  651.         elseif tCommand[1] == "mkdir" then
  652.             if #tCommand >= 2 then
  653.                 fs.makeDir(tCommand[2])
  654.             else
  655.                 print("Wrong Usage")
  656.             end
  657.         elseif tCommand[1] == "time" then
  658.             print("Time: "..textutils.formatTime(os.time()))
  659.             print("Day: "..os.day())
  660.         else
  661.             print("> Couldn't recognise that command...")
  662.         end
  663.     end
  664. end
  665.  
  666.  
  667. -- Program Code Start:
  668.  
  669. function bugreport()
  670.     -- Allows a user to report a bug
  671.     col.screen("white", "white")
  672.     drawScreen("taskbar", "Report", "Report A Bug Form")
  673.     draw.box(8, 36, 6, 1, " ", "lightBlue", "lightBlue")
  674.     draw.texta("Email Address*:", 8, 5, false, "grey", "white")
  675.     draw.box(8, 36, 9, 1, " ", "lightBlue", "lightBlue")
  676.     draw.texta("Program/Function*:", 8, 8, false, "grey", "white")
  677.     draw.box(8, 36, 12, 1, " ", "lightBlue", "lightBlue")
  678.     draw.texta("What was the bug*:", 8, 11, false, "grey", "white")
  679.     draw.box(8, 36, 15, 1, " ", "lightBlue", "lightBlue")
  680.     draw.texta("Error Code:", 8, 14, false, "grey", "white")
  681.     draw.textc("SUBMIT", 17, false, "red", "lightBlue")
  682.     draw.textc("* is required", 19, false, "lightGrey", "white")
  683.  
  684.     while true do
  685.         local args = { os.pullEvent() }
  686.         if args[1] == "timer" then
  687.             drawScreen("taskbar", "Report", "Report A Bug Form")
  688.         elseif args[1] == "mouse_click" then
  689.             if (args[3] >= 1 and args[3] <= 8) and (args[4] == 1) then
  690.                 desktop(2)
  691.             elseif (args[3] >= 8 and args[3] <= 44) and (args[4] == 6) then
  692.                 if bug_email then
  693.                     draw.box(8, 36, 6, 1, " ", "lightBlue", "lightBlue")
  694.                 end
  695.                 col.set("white", "lightBlue")
  696.                 term.setCursorPos(8, 6)
  697.                 write("> ")
  698.                 bug_email = tostring(read())
  699.             elseif (args[3] >= 8 and args[3] <= 44) and (args[4] == 9) then
  700.                 if bug_prog then
  701.                     draw.box(8, 36, 9, 1, " ", "lightBlue", "lightBlue")
  702.                 end
  703.                 col.set("white", "lightBlue")
  704.                 term.setCursorPos(8, 9)
  705.                 write("> ")
  706.                 bug_prog = tostring(read())
  707.             elseif (args[3] >= 8 and args[3] <= 44) and (args[4] == 12) then
  708.                 if bug_desc then
  709.                     draw.box(8, 36, 12, 1, " ", "lightBlue", "lightBlue")
  710.                 end
  711.                 col.set("white", "lightBlue")
  712.                 term.setCursorPos(8, 12)
  713.                 write("> ")
  714.                 bug_desc = tostring(read())
  715.             elseif (args[3] >= 8 and args[3] <= 44) and (args[4] == 15) then
  716.                 if bug_error then
  717.                     draw.box(8, 36, 15, 1, " ", "lightBlue", "lightBlue")
  718.                 end
  719.                 col.set("white", "lightBlue")
  720.                 term.setCursorPos(8, 15)
  721.                 write("> ")
  722.                 bug_error = tostring(read())
  723.             elseif (args[3] >= 8 and args[3] <= 44) and (args[4] == 17) then
  724.                 -- Submit
  725.                 ccsys.submitbug(bug_email, bug_prog, bug_desc, bug_error)
  726.                 sleep(0.5)
  727.                 desktop(2)
  728.             end
  729.         end
  730.     end
  731. end
  732.  
  733. function login()
  734.     col.screen("white", "white")
  735.     drawScreen("taskbar", "Login", "Login Screen", "Enter Username")
  736.     drawScreen("login")
  737.  
  738.     while true do
  739.         local args = { os.pullEvent() }
  740.         if args[1] == "timer" then
  741.             drawScreen("taskbar", "Login", "Login Screen", "Enter Username")
  742.         elseif args[1] == "mouse_click" then
  743.             if (args[3] >= 8 and args[3] <= 44) and (args[4] == 14) then
  744.                 col.set("black", "lightBlue")
  745.                 term.setCursorPos(8, 14)
  746.                 write("> ")
  747.                 local username = tostring(read())
  748.                 if fs.exists("/core/conf/imgmaps/"..username.."/profileimage.fusi") then
  749.                     image.draw(21, 5, "/core/conf/imgmaps/"..username.."/profileimage")
  750.                 end
  751.                 drawScreen("taskbar", "Login", "Login Screen", "Enter Password")
  752.                 draw.textc(" "..username, 12, false, "grey", "white")
  753.                 draw.box(8, 36, 14, 1, " ", "cyan", "cyan")
  754.                 col.set("black", "cyan")
  755.                 term.setCursorPos(8, 14)
  756.                 write("> ")
  757.                 local password = tostring(read("*"))
  758.                 local status = user.login(username, password)
  759.                 if status then
  760.                     sleep(0.5)
  761.                     desktop()
  762.                     break
  763.                 else
  764.                     sleep(0.5)
  765.                     draw.popup("Username and password invalid!")
  766.                     sleep(1.5)
  767.                     login()
  768.                 end
  769.             elseif (args[3] >= 5 and args[3] <= 12) and (args[4] == 18) then
  770.                 register()
  771.             elseif (args[3] >= 42 and args[3] <= 46) and (args[4] == 18) then
  772.                 login()
  773.             end
  774.         end
  775.     end
  776. end
  777.  
  778. function register()
  779.     -- Allow users to register to the CCSystems User Database
  780.     col.screen("white", "white")
  781.     drawScreen("taskbar", "Register", "Register To CCSystems", "Enter Username")
  782.     drawScreen("register")
  783.  
  784.     while true do
  785.         local args = { os.pullEvent() }
  786.         if args[1] == "timer" then
  787.             drawScreen("taskbar", "Register", "Register To CCSystems", "Enter Username")
  788.         elseif args[1] == "mouse_click" then
  789.             if (args[3] >= 8 and args[3] <= 44) and (args[4] >= 7 and args[4] <= 13) then
  790.                 -- Set up register form
  791.                 col.set("black", "lightBlue")
  792.                 term.setCursorPos(8,7)
  793.                 write("> ")
  794.                 local username = tostring(read())
  795.                 drawScreen("taskbar", "Register", "Register To CCSystems", "Enter Password")
  796.                 term.setCursorPos(8,10)
  797.                 col.set("black", "lightBlue")
  798.                 write("> ")
  799.                 local password = tostring(read("*"))
  800.                 drawScreen("taskbar", "Register", "Register To CCSystems", "Enter Email Address")
  801.                 term.setCursorPos(8,13)
  802.                 col.set("black", "lightBlue")
  803.                 write("> ")
  804.                 local email = tostring(read())
  805.                 local status = user.register(username, password, email)
  806.                 if status then
  807.                     sleep(0.5)
  808.                     login()
  809.                     break
  810.                 else
  811.                     sleep(0.5)
  812.                     draw.popup("Problem with adding user...")
  813.                     sleep(1.5)
  814.                     login()
  815.                 end
  816.             elseif (args[3] >= 5 and args[3] <= 12) and (args[4] == 18) then
  817.                 register()
  818.             elseif (args[3] >= 42 and args[3] <= 46) and (args[4] == 18) then
  819.                 login()
  820.             end
  821.         end
  822.     end
  823. end
  824.  
  825. function desktop(screen)
  826.     screens = 2
  827.     if screen == nil then
  828.         screen = 1
  829.     end
  830.  
  831.     col.screen("white", "white")
  832.  
  833.     local csettings = config.load("/core/conf/settings/settings.fusc")
  834.     if csettings[2][1] then
  835.         if http then
  836.             rednet.open(misc.find("modem"))
  837.         end
  838.     end
  839.  
  840.     if screen == 1 then
  841.         drawScreen("taskbar", "Desktop", "Home ("..tostring(screen).."/"..screens..")")
  842.         draw.texta("->", 50, 19, false, "grey", "white")
  843.     elseif screen == 2 then
  844.         drawScreen("taskbar", "Desktop", "Home ("..tostring(screen).."/"..screens..")")
  845.         draw.texta("<-", 1, 19, false, "grey", "white")
  846.     end
  847.  
  848.     if screen == 1 then
  849.         drawScreen("desktop")
  850.     elseif screen == 2 then
  851.         drawScreen("desktop2")
  852.     end
  853.  
  854.     while true do
  855.         local args = { os.pullEvent() }
  856.         if args[1] == "timer" then
  857.             if screen == 1 then
  858.                 drawScreen("taskbar", "Desktop", "Home ("..tostring(screen).."/"..screens..")")
  859.                 draw.texta("->", 50, 19, false, "grey", "white")
  860.             elseif screen == 2 then
  861.                 drawScreen("taskbar", "Desktop", "Home ("..tostring(screen).."/"..screens..")")
  862.                 draw.texta("<-", 1, 19, false, "grey", "white")
  863.             end
  864.         elseif args[1] == "mouse_click" then
  865.             if screen == 1 then
  866.                 if (args[3] >= 50 and args[3] <= 51) and (args[4] == 19) then
  867.                     desktop(2)
  868.                 elseif (args[3] >= 1 and args[3] <= 8) and (args[4] >= 1 and args[4] <= 1) then
  869.                     desktop()
  870.                     sleep(0.5)
  871.                     desktop()
  872.                 elseif (args[3] >= 5 and args[3] <= 13) and (args[4] >= 6 and args[4] <= 8) then
  873.                     finder()
  874.                     sleep(0.5)
  875.                     desktop()
  876.                 elseif (args[3] >= 16 and args[3] <= 25) and (args[4] >= 6 and args[4] <= 8) then
  877.                     gravityscore_luaide()
  878.                     sleep(0.5)
  879.                     desktop()
  880.                 elseif (args[3] >= 28 and args[3] <= 36) and (args[4] >= 6 and args[4] <= 8) then
  881.                     oeed_ink()
  882.                     sleep(0.5)
  883.                     desktop()
  884.                 elseif (args[3] >= 39 and args[3] <= 47) and (args[4] >= 6 and args[4] <= 8) then
  885.                     oeed_sketch()
  886.                     sleep(0.5)
  887.                     desktop()
  888.                 elseif (args[3] >= 5 and args[3] <= 13) and (args[4] >= 11 and args[4] <= 13) then
  889.                     Xplore()
  890.                     sleep(0.5)
  891.                     desktop()
  892.                 elseif (args[3] >= 16 and args[3] <= 25) and (args[4] >= 11 and args[4] <= 13) then
  893.                     appslist()
  894.                     sleep(0.5)
  895.                     desktop()
  896.                 elseif (args[3] >= 28 and args[3] <= 36) and (args[4] >= 11 and args[4] <= 13) then
  897.                     settings()
  898.                     sleep(0.5)
  899.                     desktop()
  900.                 elseif (args[3] >= 39 and args[3] <= 47) and (args[4] >= 11 and args[4] <= 13) then
  901.                     helpcontent()
  902.                     sleep(0.5)
  903.                     desktop()
  904.                 elseif (args[3] >= 5 and args[3] <= 10) and (args[4] >= 18 and args[4] <= 18) then
  905.                     infoScreen("system")
  906.                     sleep(0.5)
  907.                     desktop()
  908.                 elseif (args[3] >= 22 and args[3] <= 28) and (args[4] >= 18 and args[4] <= 18) then
  909.                     infoScreen("license", 1)
  910.                     sleep(0.5)
  911.                     desktop()
  912.                 elseif (args[3] >= 40 and args[3] <= 47) and (args[4] >= 18 and args[4] <= 18) then
  913.                     infoScreen("credits")
  914.                     sleep(0.5)
  915.                     desktop()
  916.                 end
  917.             elseif screen == 2 then
  918.                 if (args[3] >= 1 and args[3] <= 2) and (args[4] == 19) then
  919.                     desktop(1)
  920.                 elseif (args[3] >= 1 and args[3] <= 8) and (args[4] >= 1 and args[4] <= 1) then
  921.                     desktop()
  922.                     sleep(0.5)
  923.                     desktop()
  924.                 elseif (args[3] >= 5 and args[3] <= 13) and (args[4] >= 6 and args[4] <= 8) then
  925.                     -- OPTION 1
  926.                     bugreport()
  927.                     sleep(0.5)
  928.                     desktop()
  929.                 elseif (args[3] >= 16 and args[3] <= 25) and (args[4] >= 6 and args[4] <= 8) then
  930.                     -- OPTION 2
  931.                     addons()
  932.                     sleep(0.5)
  933.                     desktop()
  934.                 elseif (args[3] >= 28 and args[3] <= 36) and (args[4] >= 6 and args[4] <= 8) then
  935.                     -- OPTION 3
  936.                     fusionshell()
  937.                     sleep(0.5)
  938.                     desktop()
  939.                 elseif (args[3] >= 39 and args[3] <= 47) and (args[4] >= 6 and args[4] <= 8) then
  940.                     -- OPTION 4
  941.                     sleep(0.5)
  942.                     desktop()
  943.                 elseif (args[3] >= 5 and args[3] <= 13) and (args[4] >= 11 and args[4] <= 13) then
  944.                     -- OPTION 5
  945.                     sleep(0.5)
  946.                     desktop()
  947.                 elseif (args[3] >= 16 and args[3] <= 25) and (args[4] >= 11 and args[4] <= 13) then
  948.                     -- OPTION 6
  949.                     sleep(0.5)
  950.                     desktop()
  951.                 elseif (args[3] >= 28 and args[3] <= 36) and (args[4] >= 11 and args[4] <= 13) then
  952.                     -- OPTION 7
  953.                     sleep(0.5)
  954.                     desktop()
  955.                 elseif (args[3] >= 39 and args[3] <= 47) and (args[4] >= 11 and args[4] <= 13) then
  956.                     -- OPTION 8
  957.                     sleep(0.5)
  958.                     desktop()
  959.                 elseif (args[3] >= 5 and args[3] <= 10) and (args[4] >= 18 and args[4] <= 18) then
  960.                     infoScreen("system")
  961.                     sleep(0.5)
  962.                     desktop()
  963.                 elseif (args[3] >= 22 and args[3] <= 28) and (args[4] >= 18 and args[4] <= 18) then
  964.                     infoScreen("license", 1)
  965.                     sleep(0.5)
  966.                     desktop()
  967.                 elseif (args[3] >= 40 and args[3] <= 47) and (args[4] >= 18 and args[4] <= 18) then
  968.                     infoScreen("credits")
  969.                     sleep(0.5)
  970.                     desktop()
  971.                 end
  972.             end
  973.         elseif args[1] == "char" then
  974.             if args[2] == "d" then
  975.                 local args = drawScreen("option", "Type Arguments to pass to Fusion")
  976.                 shell.run("fusion "..args)
  977.                 os.reboot()
  978.             end
  979.         end
  980.     end
  981. end
  982.  
  983.  
  984. -- IF YOU MAKE AN ADDON READ THIS:
  985. --[[
  986.     Addons have to be registered using the addons system, to do so, if one doesn't already exist, make a folder called: addons in the core folder and then add a file called tAddons.fusc and then it's a dual table, like so:
  987.     {
  988.         {
  989.             "<Here add in the addon name>",
  990.         },
  991.         {
  992.             "<Here out your username as you are the creator>",
  993.         },
  994.     }
  995.  
  996.     This will now show in the addons page.
  997. ]]
  998. function addons()
  999.     col.screen("white", "white")
  1000.     drawScreen("taskbar", "Addons", "Installed Addons", "Addons will appear here if installed.")
  1001.     draw.textc("BACK", 18, false, "black", "white")
  1002.  
  1003.     if fs.exists("/core/addons/current.fusc") then
  1004.         local addondata = config.load("/core/addons/current.fusc")
  1005.         for k, v in ipairs(addondata[1]) do
  1006.             draw.texta(k..": "..v.." - "..addondata[2][k], 1, k + 4, false, "blue", "white")
  1007.         end
  1008.     end
  1009.  
  1010.     while true do
  1011.         local args = { os.pullEvent() }
  1012.         if args[1] == "timer" then
  1013.             drawScreen("taskbar", "Addons", "Installed Addons", "Addons will appear here if installed.")
  1014.         elseif args[1] == "mouse_click" then
  1015.             if (args[3] >= 1 and args[3] <= 8) and (args[4] == 1) then
  1016.                 desktop(2)
  1017.             elseif (args[3] >= 20 and args[3] <= 31) and (args[4] == 18) then
  1018.                 desktop(2)
  1019.             end
  1020.         end
  1021.     end
  1022. end
  1023.  
  1024. function appslist()
  1025.     col.screen("white", "white")
  1026.     local applist = fs.list("/core/apps/")
  1027.     drawScreen("taskbar", "Apps", "Installed Apps")
  1028.     drawScreen("apps")
  1029.  
  1030.     local intx = 4
  1031.     local intx1 = 1
  1032.     local inty = 4
  1033.     for k, v in ipairs(applist) do
  1034.         if inty == 17 then
  1035.             intx = 30
  1036.             intx1 = 26
  1037.             inty = 4
  1038.         elseif intx == 26 and inty == 17 then
  1039.             break
  1040.         end
  1041.         draw.texta(tostring(k), intx1, inty, false, "blue", "white")
  1042.         term.setCursorPos(intx, inty)
  1043.         col.set("grey", "white")
  1044.         print(v)
  1045.         inty = inty + 1
  1046.     end
  1047.  
  1048.     while true do
  1049.         local args = { os.pullEvent() }
  1050.         if args[1] == "timer" then
  1051.             drawScreen("taskbar", "Apps", "Installed Apps")
  1052.         elseif args[1] == "mouse_click" then
  1053.             if (args[3] >= 1 and args[3] <= 8) and (args[4] >= 1 and args[4] <= 1) then
  1054.                 desktop()
  1055.             elseif (args[3] >= 5 and args[3] <= 17) and (args[4] == 18) then
  1056.                 -- Download from pastebin/url
  1057.                 local code = drawScreen("option", "Download Pastebin / URL App")
  1058.                 local name = drawScreen("option", "App Name")
  1059.                 if string.len(code) < 8 then
  1060.                     draw.popup("8 Chars for pastebin, more for url")
  1061.                     sleep(1.5)
  1062.                     appslist()
  1063.                 end
  1064.                 if string.len(code) == 8 then
  1065.                     shell.run("pastebin get "..code.." /core/apps/"..name)
  1066.                 else
  1067.                     local data = http.get(code)
  1068.                     local tempapp = fs.open(name, "w")
  1069.                     tempapp.write(data.readAll())
  1070.                     tempapp.close()
  1071.                 end
  1072.                 appslist()
  1073.             elseif (args[3] >= 37 and args[3] <= 47) and (args[4] == 18) then
  1074.                 -- Delete App
  1075.                 drawScreen("taskbar", "Apps", "Installed Apps", "Click app to delete or click Fusion to exit")
  1076.                 while true do
  1077.                     local args1 = { os.pullEvent("mouse_click") }
  1078.                     if (args1[3] >= 1 and args1[3] <= 8) and (args1[4] == 1) then
  1079.                         break
  1080.                     else
  1081.                         if (args1[3] >= 1 and args1[3] <= 25) then
  1082.                             args1[4] = args1[4] - 3
  1083.                             if #applist >= args1[4] then
  1084.                                 fs.delete("/core/apps/"..applist[args1[4]])
  1085.                             end
  1086.                             appslist()
  1087.                         elseif (args1[3] >= 26 and args1[3] <= 51) then
  1088.                             args1[4] = args1[4] + 24
  1089.                             if #applist >= args1[4] then
  1090.                                 fs.delete("/core/apps/"..applist[args1[4]])
  1091.                             end
  1092.                             appslist()
  1093.                         end
  1094.                     end
  1095.                 end
  1096.             else
  1097.                 while true do
  1098.                     local args1 = { os.pullEvent("mouse_click") }
  1099.                     if (args1[3] >= 1 and args1[3] <= 8) and (args1[4] == 1) then
  1100.                         break
  1101.                     else
  1102.                         if (args1[3] >= 1 and args1[3] <= 25) then
  1103.                             args1[4] = args1[4] - 3
  1104.                             if #applist >= args1[4] then
  1105.                                 shell.run("/core/apps/"..applist[args1[4]])
  1106.                             end
  1107.                             appslist()
  1108.                         elseif (args1[3] >= 26 and args1[3] <= 51) then
  1109.                             args1[4] = args1[4] + 24
  1110.                             if #applist >= args1[4] then
  1111.                                 shell.run("/core/apps/"..applist[args1[4]])
  1112.                             end
  1113.                             appslist()
  1114.                         end
  1115.                     end
  1116.                 end
  1117.             end
  1118.         end
  1119.     end
  1120. end
  1121.  
  1122. function settings()
  1123.     col.screen("white", "white")
  1124.     drawScreen("taskbar", "Settings", "Control Panel", "Click the option to toggle")
  1125.     local configuration = config.load("/core/conf/settings/settings.fusc")
  1126.     draw.textc("Option statuses: lime = true, red = false", 19, false, "blue", "white")
  1127.    
  1128.     local inty = 5
  1129.     for k, v in ipairs(configuration[1]) do
  1130.         draw.box(2, 44, inty, 1, " ", "lightBlue", "lightBlue")
  1131.         draw.texta(" "..k..": "..v, 2, inty, false, "white", "lightBlue")
  1132.         if configuration[2][k] then
  1133.             draw.box(48, 3, inty, 1, " ", "lime", "lime")
  1134.         else
  1135.             draw.box(48, 3, inty, 1, " ", "red", "red")
  1136.         end
  1137.         inty = inty + 2
  1138.     end
  1139.  
  1140.  
  1141.     while true do
  1142.         local args = { os.pullEvent() }
  1143.         if args[1] == "timer" then
  1144.             drawScreen("taskbar", "Settings", "Control Panel", "Click the option to toggle")
  1145.         elseif args[1] == "mouse_click" then
  1146.             if (args[3] >= 1 and args[3] <= 8) and (args[4] == 1) then
  1147.                 desktop(1)
  1148.             elseif (args[3] >= 1 and args[3] <= 40) then
  1149.                 if args[4] == 5 then
  1150.                     local configFile = config.load("/core/conf/settings/settings.fusc")
  1151.                     if configFile[2][1] == true then
  1152.                         configFile[2][1] = false
  1153.                     else
  1154.                         configFile[2][1] = true
  1155.                     end
  1156.                     config.save(configFile, "/core/conf/settings/settings.fusc")
  1157.                     draw.popup("Setting Changed")
  1158.                     sleep(0.5)
  1159.                     settings()
  1160.                 elseif args[4] == 7 then
  1161.                     local configFile = config.load("/core/conf/settings/settings.fusc")
  1162.                     col.screen("white", "white")
  1163.                     drawScreen("taskbar", "Update", "Update Fusion", "Fusion is going to attempt to update")
  1164.                     sleep(0.5)
  1165.                     term.setCursorPos(1, 5)
  1166.                     col.set("cyan", "white")
  1167.                     print("Fusion is about to update, please don't touch or edit the file system.")
  1168.                     print(" ")
  1169.                     print("Downloading Fusion")
  1170.                     local updatefile = http.get(tUrls["FusionUpdate"])
  1171.                     local newFile = fs.open("fusionUpdate.fuso", "w")
  1172.                     newFile.write(updatefile.readAll())
  1173.                     newFile.close()
  1174.                     print("File downloaded and ready, updating Fusion...")
  1175.                     sleep(0.5)
  1176.                     fs.delete("fusion")
  1177.                     fs.move("fusionUpdate.fuso", "fusion")
  1178.                     print("Rebooting, please wait...")
  1179.                     sleep(1.5)
  1180.                     os.reboot()
  1181.                 elseif args[4] == 9 then
  1182.                     init("uninstall")
  1183.                     break
  1184.                 elseif args[4] == 11 then
  1185.                     local configFile = config.load("/core/conf/settings/settings.fusc")
  1186.                     if configFile[2][4] == true then
  1187.                         configFile[2][4] = false
  1188.                     else
  1189.                         configFile[2][4] = true
  1190.                     end
  1191.                     config.save(configFile, "/core/conf/settings/settings.fusc")
  1192.                     draw.popup("Setting Changed")
  1193.                     sleep(0.5)
  1194.                     settings()
  1195.                 elseif args[4] == 13 then
  1196.                     local configFile = config.load("/core/conf/settings/settings.fusc")
  1197.                     if configFile[2][5] == true then
  1198.                         configFile[2][5] = false
  1199.                     else
  1200.                         configFile[2][5] = true
  1201.                     end
  1202.                     config.save(configFile, "/core/conf/settings/settings.fusc")
  1203.                     draw.popup("Setting Changed")
  1204.                     sleep(0.5)
  1205.                     settings()
  1206.                 elseif args[4] == 15 then
  1207.                     local configFile = config.load("/core/conf/settings/settings.fusc")
  1208.                     if configFile[2][6] == true then
  1209.                         configFile[2][6] = false
  1210.                     else
  1211.                         configFile[2][6] = true
  1212.                     end
  1213.                     config.save(configFile, "/core/conf/settings/settings.fusc")
  1214.                     draw.popup("Setting Changed")
  1215.                     sleep(0.5)
  1216.                     settings()
  1217.                 elseif args[4] == 17 then
  1218.                     local configFile = config.load("/core/conf/settings/settings.fusc")
  1219.                     if configFile[2][7] == true then
  1220.                         configFile[2][7] = false
  1221.                     else
  1222.                         configFile[2][7] = true
  1223.                     end
  1224.                     config.save(configFile, "/core/conf/settings/settings.fusc")
  1225.                     draw.popup("Setting Changed")
  1226.                     sleep(0.5)
  1227.                     settings()
  1228.                 end
  1229.             end
  1230.         end
  1231.     end
  1232. end
  1233.  
  1234. function helpcontent()
  1235.     col.screen("white", "white")
  1236.     drawScreen("taskbar", "Help", "Help Menu", "Choose a help item")
  1237.     local sText = "Choose a help item to display help information, please make sure your HTTP is enabled, as this all done using internet. This will just display some simple information for you to read. The Creating An App, will explain how to and/or to install them."
  1238.     local tText = data.wordwrap(sText, 22)
  1239.     local HelpItems = {"About Fusion", "Fusion Controls", "Using Logins", "Using Apps", "Creating An App", "Deleting Apps", "Fusion Addons"}
  1240.     local intx = 29
  1241.     local inty = 5
  1242.     for _,v in ipairs(tText) do
  1243.         draw.texta(v, intx, inty, false, "red", "white")
  1244.         inty = inty + 1
  1245.     end
  1246.  
  1247.     local inty = 5
  1248.     for k, v in ipairs(HelpItems) do
  1249.         draw.box(1, 27, inty, 1, " ", "lightBlue", "lightBlue")
  1250.         draw.texta(k..": "..v, 1, inty, false, "red", "lightBlue")
  1251.         inty = inty + 2
  1252.     end
  1253.  
  1254.     while true do
  1255.         local args = { os.pullEvent() }
  1256.         if args[1] == "timer" then
  1257.             drawScreen("taskbar", "Help", "Help Menu", "Choose a help item")
  1258.         elseif args[1] == "mouse_click" then
  1259.             if (args[3] >= 1 and args[3] <= 8) then
  1260.                 desktop(1)
  1261.             elseif (args[3] >= 1 and args[3] <= 27) then
  1262.                 if args[4] == 5 then
  1263.                     getHelpContent("about")
  1264.                     sleep(0.5)
  1265.                     helpcontent()
  1266.                 elseif args[4] == 7 then
  1267.                     getHelpContent("controls")
  1268.                     sleep(0.5)
  1269.                     helpcontent()
  1270.                 elseif args[4] == 9 then
  1271.                     getHelpContent("logins")
  1272.                     sleep(0.5)
  1273.                     helpcontent()
  1274.                 elseif args[4] == 11 then
  1275.                     getHelpContent("apps")
  1276.                     sleep(0.5)
  1277.                     helpcontent()
  1278.                 elseif args[4] == 13 then
  1279.                     getHelpContent("creatingapps")
  1280.                     sleep(0.5)
  1281.                     helpcontent()
  1282.                 elseif args[4] == 15 then
  1283.                     getHelpContent("deletingapps")
  1284.                     sleep(0.5)
  1285.                     helpcontent()
  1286.                 elseif args[4] == 17 then
  1287.                     getHelpContent("addons")
  1288.                     sleep(0.5)
  1289.                     helpcontent()
  1290.                 end
  1291.             end
  1292.         end
  1293.     end
  1294. end
  1295.  
  1296. function getHelpContent(helpcode)
  1297.     col.screen("white", "white")
  1298.     drawScreen("taskbar", "Help", "Help: About Fusion")
  1299.     draw.textc("Getting content, please wait", 8, false, "blue", "white")
  1300.     local content = http.get("https://dannysmc.com/files/fusion/help/"..helpcode..".fush")
  1301.     draw.textc("BACK", 18, false, "grey", "white")
  1302.     term.setCursorPos(1, 5)
  1303.     col.set("grey", "white")
  1304.     for _, v in ipairs(data.wordwrap(content.readAll(), 51)) do
  1305.         print(v)
  1306.     end
  1307.  
  1308.     while true do
  1309.         local args = { os.pullEvent() }
  1310.         if args[1] == "timer" then
  1311.             drawScreen("taskbar", "Help", "Help: About Fusion")
  1312.         elseif args[1] == "mouse_click" then
  1313.             if (args[3] >= 20 and args[3] <= 31) and (args[4] == 18) then
  1314.                 helpcontent()
  1315.             elseif (args[3] >= 1 and args[3] <= 8) and (args[4] == 1) then
  1316.                 desktop(1)
  1317.             end
  1318.         end
  1319.     end
  1320. end
  1321.  
  1322. function Xplore()
  1323.     -- Set Vars
  1324.     local url = "//:Home"
  1325.     local his = {"//:Home"}
  1326.  
  1327.     -- Draws URL Bar (w/ time)
  1328.     function drawurlbar()
  1329.         draw.box(1, 51, 1, 2, " ", "grey", "grey")
  1330.         draw.texta("Xplore", 3, 1, false, "white", "grey")
  1331.         draw.texta(misc.time(), 47, 1, false, timetc, mainbc)
  1332.         draw.box(5, 39, 2, 1, " ", "lightGrey", "lightGrey")
  1333.         draw.texta("URL:", 1, 2, false, "lightBlue", "grey")
  1334.         draw.texta(":<:", 45, 2, false, "lime", "lightGrey")
  1335.         draw.texta(":R:", 49, 2, false, "yellow", "lightGrey")
  1336.         draw.texta(his[#his], 5, 2, false, "red", "lightGrey")
  1337.         draw.texta("X", 1, 1, false, "lime", "red")
  1338.     end
  1339.  
  1340.     -- Main Browser
  1341.     function browser()
  1342.     col.screen("white", "white")
  1343.     drawurlbar()
  1344.  
  1345.     while true do
  1346.         local args = { os.pullEvent() }
  1347.             if args[1] == "timer" then
  1348.                 drawurlbar()
  1349.             elseif args[1] == "mouse_click" then
  1350.                 if (args[3] >= 5 and args[3] <= 44) and (args[4] == 2) then
  1351.                     --// Enter URL
  1352.                     draw.box(5, 39, 2, 1, " ", "lightGrey", "lightGrey")
  1353.                     term.setCursorPos(5,2)
  1354.                     col.set("red", "lightGrey")
  1355.                     local newUrl = tostring(read())
  1356.                     table.insert(his, newUrl)
  1357.                     col.screen("white", "white")
  1358.                     pagerequest(newUrl)
  1359.                     drawurlbar()
  1360.                 elseif (args[3] >= 45 and args[3] <= 47) and (args[4] == 2) then
  1361.                     if #his == 0 then
  1362.                         col.screen("white", "white")
  1363.                         pagerequest("//:Home")
  1364.                         drawurlbar()
  1365.                     else
  1366.                         col.screen("white", "white")
  1367.                         table.remove(his)
  1368.                         pagerequest(his[#his])
  1369.                         drawurlbar()
  1370.                     end
  1371.                 elseif (args[3] >= 48 and args[3] <= 51) and (args[4] == 2) then
  1372.                     col.screen("white", "white")
  1373.                     pagerequest(his[#his])
  1374.                     drawurlbar()
  1375.                 elseif (args[3] ==1) and (args[4] == 1) then
  1376.                     desktop()
  1377.                 end
  1378.             end
  1379.         end
  1380.     end
  1381.  
  1382.     function pagerequest(url)
  1383.         if url == "//:Home" then
  1384.             url = url
  1385.             local pagedata = fs.open("/core/xplore/home.xpl", "r")
  1386.             local pagedata = pagedata.readAll()
  1387.             local tpagedata = data.wordwrap(pagedata, 51)
  1388.             term.setCursorPos(1, 3)
  1389.             col.set("black", "white")
  1390.             for _, v in ipairs(tpagedata) do
  1391.                 print(v)
  1392.             end
  1393.         else
  1394.             local pagedata = http.get(url)
  1395.             local pagedata = pagedata.readAll()
  1396.             local tpagedata = data.wordwrap(pagedata, 51)
  1397.             term.setCursorPos(1, 3)
  1398.             col.set("black", "white")
  1399.             for _, v in ipairs(tpagedata) do
  1400.                 print(v)
  1401.             end
  1402.             url = url
  1403.         end
  1404.     end
  1405.  
  1406.     browser()
  1407. end
  1408.  
  1409. function finder()
  1410.     -- Set Vars:
  1411. scroll = 1
  1412. histFold = {}
  1413. table.insert(histFold, "/")
  1414.  
  1415. function fb_getClick(sButton, nX, nY, scroll, sDir)
  1416.         if sButton == 1 then
  1417.                 local tFilesClean = tFilesClean
  1418.                 tFilesCount = #tFilesClean
  1419.                 local count = nY - 2 - scroll
  1420.                 oldDir = sDir
  1421.                 if sDir == "/" then
  1422.                         newDir = sDir..""..(tFilesClean[count])
  1423.                 else
  1424.                         newDir = sDir.."/"..tFilesClean[count]
  1425.                 end
  1426.                 sDir = newDir
  1427.  
  1428.                 if fs.isDir(newDir) then
  1429.                         table.insert(histFold, sDir)
  1430.                         fb_finder(newDir)
  1431.                 else
  1432.                         fb_runFile(newDir, sDir)
  1433.                 end
  1434.         elseif sButton == 2 then
  1435.                 -- Do delete or edit
  1436.                 if sOption == "delete" then
  1437.                         local tFilesClean = tFilesClean
  1438.                         tFilesCount = #tFilesClean
  1439.                         local count = nY - 2 - scroll
  1440.                         oldDir = sDir
  1441.                         if sDir == "/" then
  1442.                                 newDir = sDir..""..(tFilesClean[count])
  1443.                         else
  1444.                                 newDir = sDir.."/"..tFilesClean[count]
  1445.                         end
  1446.                         fs.delete(newDir)
  1447.                         fb_finder(sDir)
  1448.                 elseif sOption == "edit" then
  1449.                         -- Empty
  1450.                 else
  1451.                         fb_drawOptions(nX, nY, sDir)
  1452.                 end
  1453.         end
  1454. end
  1455.  
  1456. function fb_drawOptions(tempX, tempY, sDir)
  1457.         draw.box(tempX, 8, tempY, 2, " ", "black", "lightGrey")
  1458.         draw.texta("Delete", tempX, tempY, false, "black", "lightGrey")
  1459.         draw.texta("Edit", tempX, tempY + 1, false, "black", "lightGrey")
  1460.  
  1461.         while true do
  1462.                 local args = { os.pullEvent() }
  1463.                 if args[1] == "mouse_click" then
  1464.                         if args[2] == 1 then
  1465.                                 if args[3] >= tempX and args[3] <= tempX + 8 then
  1466.                                         if args[4] == tempY then
  1467.                                                 local tFilesClean = tFilesClean
  1468.                                                 tFilesCount = #tFilesClean
  1469.                                                 local count = tempY - 2 - scroll
  1470.                                                 oldDir = sDir
  1471.                                                 if sDir == "/" then
  1472.                                                         newDir = sDir..""..(tFilesClean[count])
  1473.                                                 else
  1474.                                                         newDir = sDir.."/"..tFilesClean[count]
  1475.                                                 end
  1476.                                                 fs.delete(newDir)
  1477.                                                 fb_finder(sDir)
  1478.                                         elseif args[4] == tempY + 1 then
  1479.                                                 local tFilesClean = tFilesClean
  1480.                                                 tFilesCount = #tFilesClean
  1481.                                                 local count = tempY - 2 - scroll
  1482.                                                 oldDir = sDir
  1483.                                                 if sDir == "/" then
  1484.                                                         newDir = sDir..""..(tFilesClean[count])
  1485.                                                 else
  1486.                                                         newDir = sDir.."/"..tFilesClean[count]
  1487.                                                 end
  1488.                                                 shell.run("edit "..newDir)
  1489.                                                 fb_finder(sDir)
  1490.                                         else
  1491.                                                 fb_finder(sDir)
  1492.                                         end
  1493.                                 else
  1494.                                         fb_finder(sDir)
  1495.                                 end
  1496.                         else
  1497.                                 fb_finder(sDir)
  1498.                         end
  1499.                 end
  1500.         end
  1501. end
  1502.  
  1503. function fb_runFile(path, sDir)
  1504.         draw.cscreen()
  1505.         col.set("black", "white")
  1506.         shell.run(path)
  1507.         fb_finder(sDir)
  1508. end
  1509.  
  1510. function fb_drawMenu(sDir)
  1511.         -- Get files
  1512.         maintc = "blue"
  1513.         mainbc = "grey"
  1514.         mainbc2 = "lightGrey"
  1515.         texttc = "black"
  1516.         textbc = "white"
  1517.         dirtc = "red"
  1518.         xtc = "lime"
  1519.         sidetc = "white"
  1520.         sidebc = "cyan"
  1521.         sidetc1 = "lime"
  1522.         col.set("white", "white")
  1523.         draw.cscreen()
  1524.         draw.box(1, 51, 1, 1, " ", maintc, mainbc)
  1525.         draw.texta(" "..misc.time().." ", 44, 1, false, maintc, mainbc2)
  1526.         draw.texta("X", 1, 1, false, xtc, dirtc)
  1527.         draw.texta(" Path: ", 3, 1, false, texttc, mainbc2)
  1528.         draw.texta(sDir.." ", 10, 1, false, dirtc, mainbc2)
  1529.         draw.box(40, 12, 2, 18, " ", sidetc, sidebc)
  1530.         draw.box(41, 10, 3, 16, " ", sidetc, sidebc)
  1531.         draw.box(42, 8, 4, 14, " ", sidetc, sidebc)
  1532.         draw.box(43, 6, 5, 12, " ", sidetc, sidebc)
  1533.         draw.box(44, 4, 6, 10, " ", sidetc, sidebc)
  1534.         draw.box(45, 2, 7, 8, " ", sidetc, sidebc)
  1535.         draw.texta("< ..", 2, 3, false, "blue", "white")
  1536.         draw.texta("Create", 41, 3, false, sidetc1, sidebc)
  1537.         draw.texta("File", 43, 4, false, sidetc, sidebc)
  1538.         draw.texta("Folder", 43, 5, false, sidetc, sidebc)
  1539.         col.set(texttc, textbc)
  1540. end
  1541.  
  1542. function fb_finder(sDir)
  1543.         -- Get files
  1544.         fb_drawMenu(sDir)
  1545.         fb_drawDir(sDir, scroll)
  1546.  
  1547.         while true do
  1548.                 local args = { os.pullEvent() }
  1549.                 if args[1] == "timer" then
  1550.                         fb_drawMenu(sDir)
  1551.                         fb_drawDir(sDir, scroll)
  1552.                 elseif args[1] == "mouse_scroll" then
  1553.                         if args[2] == 1 then
  1554.                                 scroll = scroll + 1
  1555.                                 fb_drawMenu(sDir)
  1556.                                 fb_drawDir(sDir, scroll)
  1557.                         elseif args[2] == -1 then
  1558.                                 scroll = scroll - 1
  1559.                                 fb_drawMenu(sDir)
  1560.                                 fb_drawDir(sDir, scroll)
  1561.                         end
  1562.                 elseif args[1] == "mouse_click" then
  1563.                         if args[3] == 1 and args[4] == 1 then
  1564.                                 if RunningUnder == "Fusion" then
  1565.                                         desktop()
  1566.                                 else
  1567.                                         setCol("white", "black")
  1568.                                         break
  1569.                                 end
  1570.                         elseif (args[3] >= 2 and args[3] <= 40) and (args[4] == 3) then
  1571.                                 table.remove(histFold)
  1572.                                 historyCount = #histFold
  1573.                                 sDir = histFold[historyCount]
  1574.                                 fb_finder(sDir)
  1575.                         elseif (args[3] >= 2 and args[3] <= 40) and (args[4] >= 4 and args[4] <= 18) then
  1576.                                 fb_getClick(args[2], args[3], args[4], scroll, sDir)
  1577.                         elseif (args[3] >= 43 and args[3] <= 50) then
  1578.                                 if args[4] == 4 then
  1579.                                         fb_drawInput("file", sDir)
  1580.                                 elseif args[4] == 5 then
  1581.                                         fb_drawInput("folder", sDir)
  1582.                                 end
  1583.                         end
  1584.                 end
  1585.         end
  1586. end
  1587.  
  1588. function fb_drawInput(object, sDir)
  1589.         poptc1 = "white"
  1590.         popbc1 = "red"
  1591.         poptc2 = "black"
  1592.         popbc2 = "white"
  1593.         if object == "file" then
  1594.                 draw.box(6, 39, 6, 3, " ", poptc1, popbc1)
  1595.                 draw.box(6, 39, 7, 1, " ", poptc1, popbc1)
  1596.                 draw.box(7, 37, 7, 1, " ", poptc2, popbc2)
  1597.                 draw.textc("Name For File:", 6, false, poptc1, popbc1)
  1598.                 col.set(poptc2, popbc2)
  1599.                 term.setCursorPos(7,7)
  1600.                 write(": ")
  1601.                 local newFileName = tostring(read())
  1602.                 if sDir == "/" then
  1603.                         fileDirName = "/"..newFileName
  1604.                 else
  1605.                         fileDirName = sDir.."/"..newFileName
  1606.                 end
  1607.                 shell.run("edit "..fileDirName)
  1608.                 fb_finder(sDir)
  1609.         elseif object == "folder" then
  1610.                 draw.box(6, 39, 6, 3, " ", poptc1, popbc1)
  1611.                 draw.box(6, 39, 7, 1, " ", poptc1, popbc1)
  1612.                 draw.box(7, 37, 7, 1, " ", poptc2, popbc2)
  1613.                 draw.textc("Name For Folder:", 6, false, poptc1, popbc1)
  1614.                 col.set(poptc2, popbc2)
  1615.                 term.setCursorPos(7,7)
  1616.                 write(": ")
  1617.                 local newFolderName = tostring(read())
  1618.                 if sDir == "/" then
  1619.                         fileDirName = "/"..newFolderName
  1620.                 else
  1621.                         fileDirName = sDir.."/"..newFolderName
  1622.                 end
  1623.                 fs.makeDir(fileDirName)
  1624.                 fb_finder(sDir)
  1625.         end
  1626. end
  1627.  
  1628. -- Code by: wieselkatze (Modified by dannysmc95)
  1629.  
  1630. local function fb_getDir( sDir )
  1631.     sDir = ( "/" .. sDir .. "/" ):gsub( "\\+", "/" ):gsub( "/+", "/" )
  1632.     local folder, list = sDir:match( ".*/" ), {}
  1633.  
  1634.     tFilesClean = {}
  1635.  
  1636.     if not fs.isDir( sDir ) then
  1637.         return {}
  1638.     end
  1639.  
  1640.     for k, v in pairs( fs.list( sDir ) ) do
  1641.         if fs.isDir( folder .. v ) then
  1642.             table.insert( list, 1, "+ " .. v )
  1643.             table.insert( tFilesClean, 1, v)
  1644.         else
  1645.             list[ #list+1 ] = "- " .. v
  1646.             tFilesClean[ #tFilesClean + 1 ] = v
  1647.         end
  1648.     end
  1649.  
  1650.     return list
  1651. end
  1652.  
  1653. function fb_drawDir(sDir, scroll)
  1654.         local intX = 2
  1655.         local intY = 4
  1656.  
  1657.         tFiles = fb_getDir(sDir)
  1658.  
  1659.         for k, v in ipairs(tFiles) do
  1660.                 if k >= scroll and k <= 15 then
  1661.                         term.setCursorPos(intX, intY)
  1662.                         if v:find("+") then
  1663.                                 col.set("blue", "white")
  1664.                                 print(v)
  1665.                         else
  1666.                                 col.set("red", "white")
  1667.                                 print(v)
  1668.                         end
  1669.                         intY = intY + 1
  1670.                 end
  1671.         end
  1672. end
  1673.  
  1674. function fb_main()
  1675.         if fs.exists("fusion") then
  1676.                 RunningUnder = "Fusion"
  1677.         else
  1678.                 RunningUnder = "Unknown"
  1679.         end
  1680.         fb_finder("/")
  1681. end
  1682. fb_main()
  1683. end
  1684.  
  1685. function gravityscore_luaide()
  1686.     --  
  1687.     --  Lua IDE
  1688.     --  Made by GravityScore
  1689.     --  
  1690.  
  1691.  
  1692.     --  -------- Variables
  1693.  
  1694.     -- Version
  1695.     local version = "1.0"
  1696.     local args = {}
  1697.  
  1698.     -- Editing
  1699.     local w, h = term.getSize()
  1700.     local tabWidth = 2
  1701.  
  1702.     local autosaveInterval = 20
  1703.     local allowEditorEvent = true
  1704.     local keyboardShortcutTimeout = 0.4
  1705.  
  1706.     -- Clipboard
  1707.     local clipboard = nil
  1708.  
  1709.     -- Theme
  1710.     local theme = {}
  1711.  
  1712.     -- Language
  1713.     local languages = {}
  1714.     local curLanguage = {}
  1715.  
  1716.     -- Events
  1717.     local event_distract = "luaide_distractionEvent"
  1718.  
  1719.     -- Locations
  1720.     local updateURL = "https://raw.github.com/GravityScore/LuaIDE/master/luaide.lua"
  1721.     local ideLocation = "/" .. shell.getRunningProgram()
  1722.     local themeLocation = "/.LuaIDE-Theme"
  1723.  
  1724.     local function isAdvanced() return term.isColor and term.isColor() end
  1725.  
  1726.  
  1727.     --  -------- Utilities
  1728.  
  1729.     local function modRead(properties)
  1730.         local w, h = term.getSize()
  1731.         local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil,
  1732.             liveUpdates = nil, exitOnKey = nil}
  1733.         if not properties then properties = {} end
  1734.         for k, v in pairs(defaults) do if not properties[k] then properties[k] = v end end
  1735.         if properties.replaceChar then properties.replaceChar = properties.replaceChar:sub(1, 1) end
  1736.         if not properties.visibleLength then properties.visibleLength = w end
  1737.  
  1738.         local sx, sy = term.getCursorPos()
  1739.         local line = ""
  1740.         local pos = 0
  1741.         local historyPos = nil
  1742.  
  1743.         local function redraw(repl)
  1744.             local scroll = 0
  1745.             if properties.visibleLength and sx + pos > properties.visibleLength + 1 then
  1746.                 scroll = (sx + pos) - (properties.visibleLength + 1)
  1747.             end
  1748.  
  1749.             term.setCursorPos(sx, sy)
  1750.             local a = repl or properties.replaceChar
  1751.             if a then term.write(string.rep(a, line:len() - scroll))
  1752.             else term.write(line:sub(scroll + 1, -1)) end
  1753.             term.setCursorPos(sx + pos - scroll, sy)
  1754.         end
  1755.  
  1756.         local function sendLiveUpdates(event, ...)
  1757.             if type(properties.liveUpdates) == "function" then
  1758.                 local ox, oy = term.getCursorPos()
  1759.                 local a, data = properties.liveUpdates(line, event, ...)
  1760.                 if a == true and data == nil then
  1761.                     term.setCursorBlink(false)
  1762.                     return line
  1763.                 elseif a == true and data ~= nil then
  1764.                     term.setCursorBlink(false)
  1765.                     return data
  1766.                 end
  1767.                 term.setCursorPos(ox, oy)
  1768.             end
  1769.         end
  1770.  
  1771.         term.setCursorBlink(true)
  1772.         while true do
  1773.             local e, but, x, y, p4, p5 = os.pullEvent()
  1774.  
  1775.             if e == "char" then
  1776.                 local s = false
  1777.                 if properties.textLength and line:len() < properties.textLength then s = true
  1778.                 elseif not properties.textLength then s = true end
  1779.  
  1780.                 local canType = true
  1781.                 if not properties.grantPrint and properties.refusePrint then
  1782.                     local canTypeKeys = {}
  1783.                     if type(properties.refusePrint) == "table" then
  1784.                         for _, v in pairs(properties.refusePrint) do
  1785.                             table.insert(canTypeKeys, tostring(v):sub(1, 1))
  1786.                         end
  1787.                     elseif type(properties.refusePrint) == "string" then
  1788.                         for char in properties.refusePrint:gmatch(".") do
  1789.                             table.insert(canTypeKeys, char)
  1790.                         end
  1791.                     end
  1792.                     for _, v in pairs(canTypeKeys) do if but == v then canType = false end end
  1793.                 elseif properties.grantPrint then
  1794.                     canType = false
  1795.                     local canTypeKeys = {}
  1796.                     if type(properties.grantPrint) == "table" then
  1797.                         for _, v in pairs(properties.grantPrint) do
  1798.                             table.insert(canTypeKeys, tostring(v):sub(1, 1))
  1799.                         end
  1800.                     elseif type(properties.grantPrint) == "string" then
  1801.                         for char in properties.grantPrint:gmatch(".") do
  1802.                             table.insert(canTypeKeys, char)
  1803.                         end
  1804.                     end
  1805.                     for _, v in pairs(canTypeKeys) do if but == v then canType = true end end
  1806.                 end
  1807.  
  1808.                 if s and canType then
  1809.                     line = line:sub(1, pos) .. but .. line:sub(pos + 1, -1)
  1810.                     pos = pos + 1
  1811.                     redraw()
  1812.                 end
  1813.             elseif e == "key" then
  1814.                 if but == keys.enter then break
  1815.                 elseif but == keys.left then if pos > 0 then pos = pos - 1 redraw() end
  1816.                 elseif but == keys.right then if pos < line:len() then pos = pos + 1 redraw() end
  1817.                 elseif (but == keys.up or but == keys.down) and properties.history then
  1818.                     redraw(" ")
  1819.                     if but == keys.up then
  1820.                         if historyPos == nil and #properties.history > 0 then
  1821.                             historyPos = #properties.history
  1822.                         elseif historyPos > 1 then
  1823.                             historyPos = historyPos - 1
  1824.                         end
  1825.                     elseif but == keys.down then
  1826.                         if historyPos == #properties.history then historyPos = nil
  1827.                         elseif historyPos ~= nil then historyPos = historyPos + 1 end
  1828.                     end
  1829.  
  1830.                     if properties.history and historyPos then
  1831.                         line = properties.history[historyPos]
  1832.                         pos = line:len()
  1833.                     else
  1834.                         line = ""
  1835.                         pos = 0
  1836.                     end
  1837.  
  1838.                     redraw()
  1839.                     local a = sendLiveUpdates("history")
  1840.                     if a then return a end
  1841.                 elseif but == keys.backspace and pos > 0 then
  1842.                     redraw(" ")
  1843.                     line = line:sub(1, pos - 1) .. line:sub(pos + 1, -1)
  1844.                     pos = pos - 1
  1845.                     redraw()
  1846.                     local a = sendLiveUpdates("delete")
  1847.                     if a then return a end
  1848.                 elseif but == keys.home then
  1849.                     pos = 0
  1850.                     redraw()
  1851.                 elseif but == keys.delete and pos < line:len() then
  1852.                     redraw(" ")
  1853.                     line = line:sub(1, pos) .. line:sub(pos + 2, -1)
  1854.                     redraw()
  1855.                     local a = sendLiveUpdates("delete")
  1856.                     if a then return a end
  1857.                 elseif but == keys["end"] then
  1858.                     pos = line:len()
  1859.                     redraw()
  1860.                 elseif properties.exitOnKey then
  1861.                     if but == properties.exitOnKey or (properties.exitOnKey == "control" and
  1862.                             (but == 29 or but == 157)) then
  1863.                         term.setCursorBlink(false)
  1864.                         return nil
  1865.                     end
  1866.                 end
  1867.             end
  1868.             local a = sendLiveUpdates(e, but, x, y, p4, p5)
  1869.             if a then return a end
  1870.         end
  1871.  
  1872.         term.setCursorBlink(false)
  1873.         if line ~= nil then line = line:gsub("^%s*(.-)%s*$", "%1") end
  1874.         return line
  1875.     end
  1876.  
  1877.  
  1878.     --  -------- Themes
  1879.  
  1880.     local defaultTheme = {
  1881.         background = "gray",
  1882.         backgroundHighlight = "lightGray",
  1883.         prompt = "cyan",
  1884.         promptHighlight = "lightBlue",
  1885.         err = "red",
  1886.         errHighlight = "pink",
  1887.  
  1888.         editorBackground = "gray",
  1889.         editorLineHightlight = "lightBlue",
  1890.         editorLineNumbers = "gray",
  1891.         editorLineNumbersHighlight = "lightGray",
  1892.         editorError = "pink",
  1893.         editorErrorHighlight = "red",
  1894.  
  1895.         textColor = "white",
  1896.         conditional = "yellow",
  1897.         constant = "orange",
  1898.         ["function"] = "magenta",
  1899.         string = "red",
  1900.         comment = "lime"
  1901.     }
  1902.  
  1903.     local normalTheme = {
  1904.         background = "black",
  1905.         backgroundHighlight = "black",
  1906.         prompt = "black",
  1907.         promptHighlight = "black",
  1908.         err = "black",
  1909.         errHighlight = "black",
  1910.  
  1911.         editorBackground = "black",
  1912.         editorLineHightlight = "black",
  1913.         editorLineNumbers = "black",
  1914.         editorLineNumbersHighlight = "white",
  1915.         editorError = "black",
  1916.         editorErrorHighlight = "black",
  1917.  
  1918.         textColor = "white",
  1919.         conditional = "white",
  1920.         constant = "white",
  1921.         ["function"] = "white",
  1922.         string = "white",
  1923.         comment = "white"
  1924.     }
  1925.  
  1926.     local availableThemes = {
  1927.         {"Water (Default)", "https://raw.github.com/GravityScore/LuaIDE/master/themes/default.txt"},
  1928.         {"Fire", "https://raw.github.com/GravityScore/LuaIDE/master/themes/fire.txt"},
  1929.         {"Sublime Text 2", "https://raw.github.com/GravityScore/LuaIDE/master/themes/st2.txt"},
  1930.         {"Midnight", "https://raw.github.com/GravityScore/LuaIDE/master/themes/midnight.txt"},
  1931.         {"TheOriginalBIT", "https://raw.github.com/GravityScore/LuaIDE/master/themes/bit.txt"},
  1932.         {"Superaxander", "https://raw.github.com/GravityScore/LuaIDE/master/themes/superaxander.txt"},
  1933.         {"Forest", "https://raw.github.com/GravityScore/LuaIDE/master/themes/forest.txt"},
  1934.         {"Night", "https://raw.github.com/GravityScore/LuaIDE/master/themes/night.txt"},
  1935.         {"Original", "https://raw.github.com/GravityScore/LuaIDE/master/themes/original.txt"},
  1936.     }
  1937.  
  1938.     local function loadTheme(path)
  1939.         local f = io.open(path)
  1940.         local l = f:read("*l")
  1941.         local config = {}
  1942.         while l ~= nil do
  1943.             local k, v = string.match(l, "^(%a+)=(%a+)")
  1944.             if k and v then config[k] = v end
  1945.             l = f:read("*l")
  1946.         end
  1947.         f:close()
  1948.         return config
  1949.     end
  1950.  
  1951.     -- Load Theme
  1952.     if isAdvanced() then theme = defaultTheme
  1953.     else theme = normalTheme end
  1954.  
  1955.  
  1956.     --  -------- Drawing
  1957.  
  1958.     local function centerPrint(text, ny)
  1959.         if type(text) == "table" then for _, v in pairs(text) do centerPrint(v) end
  1960.         else
  1961.             local x, y = term.getCursorPos()
  1962.             local w, h = term.getSize()
  1963.             term.setCursorPos(w/2 - text:len()/2 + (#text % 2 == 0 and 1 or 0), ny or y)
  1964.             print(text)
  1965.         end
  1966.     end
  1967.  
  1968.     local function title(t)
  1969.         term.setTextColor(colors[theme.textColor])
  1970.         term.setBackgroundColor(colors[theme.background])
  1971.         term.clear()
  1972.  
  1973.         term.setBackgroundColor(colors[theme.backgroundHighlight])
  1974.         for i = 2, 4 do term.setCursorPos(1, i) term.clearLine() end
  1975.         term.setCursorPos(3, 3)
  1976.         term.write(t)
  1977.     end
  1978.  
  1979.     local function centerRead(wid, begt)
  1980.         local function liveUpdate(line, e, but, x, y, p4, p5)
  1981.             if isAdvanced() and e == "mouse_click" and x >= w/2 - wid/2 and x <= w/2 - wid/2 + 10
  1982.                     and y >= 13 and y <= 15 then
  1983.                 return true, ""
  1984.             end
  1985.         end
  1986.  
  1987.         if not begt then begt = "" end
  1988.         term.setTextColor(colors[theme.textColor])
  1989.         term.setBackgroundColor(colors[theme.promptHighlight])
  1990.         for i = 8, 10 do
  1991.             term.setCursorPos(w/2 - wid/2, i)
  1992.             term.write(string.rep(" ", wid))
  1993.         end
  1994.  
  1995.         if isAdvanced() then
  1996.             term.setBackgroundColor(colors[theme.errHighlight])
  1997.             for i = 13, 15 do
  1998.                 term.setCursorPos(w/2 - wid/2 + 1, i)
  1999.                 term.write(string.rep(" ", 10))
  2000.             end
  2001.             term.setCursorPos(w/2 - wid/2 + 2, 14)
  2002.             term.write("> Cancel")
  2003.         end
  2004.  
  2005.         term.setBackgroundColor(colors[theme.promptHighlight])
  2006.         term.setCursorPos(w/2 - wid/2 + 1, 9)
  2007.         term.write("> " .. begt)
  2008.         return modRead({visibleLength = w/2 + wid/2, liveUpdates = liveUpdate})
  2009.     end
  2010.  
  2011.  
  2012.     --  -------- Prompt
  2013.  
  2014.     local function prompt(list, dir, isGrid)
  2015.         local function draw(sel)
  2016.             for i, v in ipairs(list) do
  2017.                 if i == sel then term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])
  2018.                 else term.setBackgroundColor(v.bg or colors[theme.prompt]) end
  2019.                 term.setTextColor(v.tc or colors[theme.textColor])
  2020.                 for i = -1, 1 do
  2021.                     term.setCursorPos(v[2], v[3] + i)
  2022.                     term.write(string.rep(" ", v[1]:len() + 4))
  2023.                 end
  2024.  
  2025.                 term.setCursorPos(v[2], v[3])
  2026.                 if i == sel then
  2027.                     term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])
  2028.                     term.write(" > ")
  2029.                 else term.write(" - ") end
  2030.                 term.write(v[1] .. " ")
  2031.             end
  2032.         end
  2033.  
  2034.         local key1 = dir == "horizontal" and 203 or 200
  2035.         local key2 = dir == "horizontal" and 205 or 208
  2036.         local sel = 1
  2037.         draw(sel)
  2038.  
  2039.         while true do
  2040.             local e, but, x, y = os.pullEvent()
  2041.             if e == "key" and but == 28 then
  2042.                 return list[sel][1]
  2043.             elseif e == "key" and but == key1 and sel > 1 then
  2044.                 sel = sel - 1
  2045.                 draw(sel)
  2046.             elseif e == "key" and but == key2 and ((err == true and sel < #list - 1) or (sel < #list)) then
  2047.                 sel = sel + 1
  2048.                 draw(sel)
  2049.             elseif isGrid and e == "key" and but == 203 and sel > 2 then
  2050.                 sel = sel - 2
  2051.                 draw(sel)
  2052.             elseif isGrid and e == "key" and but == 205 and sel < 3 then
  2053.                 sel = sel + 2
  2054.                 draw(sel)
  2055.             elseif e == "mouse_click" then
  2056.                 for i, v in ipairs(list) do
  2057.                     if x >= v[2] - 1 and x <= v[2] + v[1]:len() + 3 and y >= v[3] - 1 and y <= v[3] + 1 then
  2058.                         return list[i][1]
  2059.                     end
  2060.                 end
  2061.             end
  2062.         end
  2063.     end
  2064.  
  2065.     local function scrollingPrompt(list)
  2066.         local function draw(items, sel, loc)
  2067.             for i, v in ipairs(items) do
  2068.                 local bg = colors[theme.prompt]
  2069.                 local bghigh = colors[theme.promptHighlight]
  2070.                 if v:find("Back") or v:find("Return") then
  2071.                     bg = colors[theme.err]
  2072.                     bghigh = colors[theme.errHighlight]
  2073.                 end
  2074.  
  2075.                 if i == sel then term.setBackgroundColor(bghigh)
  2076.                 else term.setBackgroundColor(bg) end
  2077.                 term.setTextColor(colors[theme.textColor])
  2078.                 for x = -1, 1 do
  2079.                     term.setCursorPos(3, (i * 4) + x + 4)
  2080.                     term.write(string.rep(" ", w - 13))
  2081.                 end
  2082.  
  2083.                 term.setCursorPos(3, i * 4 + 4)
  2084.                 if i == sel then
  2085.                     term.setBackgroundColor(bghigh)
  2086.                     term.write(" > ")
  2087.                 else term.write(" - ") end
  2088.                 term.write(v .. " ")
  2089.             end
  2090.         end
  2091.  
  2092.         local function updateDisplayList(items, loc, len)
  2093.             local ret = {}
  2094.             for i = 1, len do
  2095.                 local item = items[i + loc - 1]
  2096.                 if item then table.insert(ret, item) end
  2097.             end
  2098.             return ret
  2099.         end
  2100.  
  2101.         -- Variables
  2102.         local sel = 1
  2103.         local loc = 1
  2104.         local len = 3
  2105.         local disList = updateDisplayList(list, loc, len)
  2106.         draw(disList, sel, loc)
  2107.  
  2108.         -- Loop
  2109.         while true do
  2110.             local e, key, x, y = os.pullEvent()
  2111.  
  2112.             if e == "mouse_click" then
  2113.                 for i, v in ipairs(disList) do
  2114.                     if x >= 3 and x <= w - 11 and y >= i * 4 + 3 and y <= i * 4 + 5 then return v end
  2115.                 end
  2116.             elseif e == "key" and key == 200 then
  2117.                 if sel > 1 then
  2118.                     sel = sel - 1
  2119.                     draw(disList, sel, loc)
  2120.                 elseif loc > 1 then
  2121.                     loc = loc - 1
  2122.                     disList = updateDisplayList(list, loc, len)
  2123.                     draw(disList, sel, loc)
  2124.                 end
  2125.             elseif e == "key" and key == 208 then
  2126.                 if sel < len then
  2127.                     sel = sel + 1
  2128.                     draw(disList, sel, loc)
  2129.                 elseif loc + len - 1 < #list then
  2130.                     loc = loc + 1
  2131.                     disList = updateDisplayList(list, loc, len)
  2132.                     draw(disList, sel, loc)
  2133.                 end
  2134.             elseif e == "mouse_scroll" then
  2135.                 os.queueEvent("key", key == -1 and 200 or 208)
  2136.             elseif e == "key" and key == 28 then
  2137.                 return disList[sel]
  2138.             end
  2139.         end
  2140.     end
  2141.  
  2142.     function monitorKeyboardShortcuts()
  2143.         local ta, tb = nil, nil
  2144.         local allowChar = false
  2145.         local shiftPressed = false
  2146.         while true do
  2147.             local event, char = os.pullEvent()
  2148.             if event == "key" and (char == 42 or char == 52) then
  2149.                 shiftPressed = true
  2150.                 tb = os.startTimer(keyboardShortcutTimeout)
  2151.             elseif event == "key" and (char == 29 or char == 157 or char == 219 or char == 220) then
  2152.                 allowEditorEvent = false
  2153.                 allowChar = true
  2154.                 ta = os.startTimer(keyboardShortcutTimeout)
  2155.             elseif event == "key" and allowChar then
  2156.                 local name = nil
  2157.                 for k, v in pairs(keys) do
  2158.                     if v == char then
  2159.                         if shiftPressed then os.queueEvent("shortcut", "ctrl shift", k:lower())
  2160.                         else os.queueEvent("shortcut", "ctrl", k:lower()) end
  2161.                         sleep(0.005)
  2162.                         allowEditorEvent = true
  2163.                     end
  2164.                 end
  2165.                 if shiftPressed then os.queueEvent("shortcut", "ctrl shift", char)
  2166.                 else os.queueEvent("shortcut", "ctrl", char) end
  2167.             elseif event == "timer" and char == ta then
  2168.                 allowEditorEvent = true
  2169.                 allowChar = false
  2170.             elseif event == "timer" and char == tb then
  2171.                 shiftPressed = false
  2172.             end
  2173.         end
  2174.     end
  2175.  
  2176.  
  2177.     --  -------- Saving and Loading
  2178.  
  2179.     local function download(url, path)
  2180.         for i = 1, 3 do
  2181.             local response = http.get(url)
  2182.             if response then
  2183.                 local data = response.readAll()
  2184.                 response.close()
  2185.                 if path then
  2186.                     local f = io.open(path, "w")
  2187.                     f:write(data)
  2188.                     f:close()
  2189.                 end
  2190.                 return true
  2191.             end
  2192.         end
  2193.  
  2194.         return false
  2195.     end
  2196.  
  2197.     local function saveFile(path, lines)
  2198.         local dir = path:sub(1, path:len() - fs.getName(path):len())
  2199.         if not fs.exists(dir) then fs.makeDir(dir) end
  2200.         if not fs.isDir(path) and not fs.isReadOnly(path) then
  2201.             local a = ""
  2202.             for _, v in pairs(lines) do a = a .. v .. "\n" end
  2203.  
  2204.             local f = io.open(path, "w")
  2205.             f:write(a)
  2206.             f:close()
  2207.             return true
  2208.         else return false end
  2209.     end
  2210.  
  2211.     local function loadFile(path)
  2212.         if not fs.exists(path) then
  2213.             local dir = path:sub(1, path:len() - fs.getName(path):len())
  2214.             if not fs.exists(dir) then fs.makeDir(dir) end
  2215.             local f = io.open(path, "w")
  2216.             f:write("")
  2217.             f:close()
  2218.         end
  2219.  
  2220.         local l = {}
  2221.         if fs.exists(path) and not fs.isDir(path) then
  2222.             local f = io.open(path, "r")
  2223.             if f then
  2224.                 local a = f:read("*l")
  2225.                 while a do
  2226.                     table.insert(l, a)
  2227.                     a = f:read("*l")
  2228.                 end
  2229.                 f:close()
  2230.             end
  2231.         else return nil end
  2232.  
  2233.         if #l < 1 then table.insert(l, "") end
  2234.         return l
  2235.     end
  2236.  
  2237.  
  2238.     --  -------- Languages
  2239.  
  2240.     languages.lua = {}
  2241.     languages.brainfuck = {}
  2242.     languages.none = {}
  2243.  
  2244.     --  Lua
  2245.  
  2246.     languages.lua.helpTips = {
  2247.         "A function you tried to call doesn't exist.",
  2248.         "You made a typo.",
  2249.         "The index of an array is nil.",
  2250.         "The wrong variable type was passed.",
  2251.         "A function/variable doesn't exist.",
  2252.         "You missed an 'end'.",
  2253.         "You missed a 'then'.",
  2254.         "You declared a variable incorrectly.",
  2255.         "One of your variables is mysteriously nil."
  2256.     }
  2257.  
  2258.     languages.lua.defaultHelpTips = {
  2259.         2, 5
  2260.     }
  2261.  
  2262.     languages.lua.errors = {
  2263.         ["Attempt to call nil."] = {1, 2},
  2264.         ["Attempt to index nil."] = {3, 2},
  2265.         [".+ expected, got .+"] = {4, 2, 9},
  2266.         ["'end' expected"] = {6, 2},
  2267.         ["'then' expected"] = {7, 2},
  2268.         ["'=' expected"] = {8, 2}
  2269.     }
  2270.  
  2271.     languages.lua.keywords = {
  2272.         ["and"] = "conditional",
  2273.         ["break"] = "conditional",
  2274.         ["do"] = "conditional",
  2275.         ["else"] = "conditional",
  2276.         ["elseif"] = "conditional",
  2277.         ["end"] = "conditional",
  2278.         ["for"] = "conditional",
  2279.         ["function"] = "conditional",
  2280.         ["if"] = "conditional",
  2281.         ["in"] = "conditional",
  2282.         ["local"] = "conditional",
  2283.         ["not"] = "conditional",
  2284.         ["or"] = "conditional",
  2285.         ["repeat"] = "conditional",
  2286.         ["return"] = "conditional",
  2287.         ["then"] = "conditional",
  2288.         ["until"] = "conditional",
  2289.         ["while"] = "conditional",
  2290.  
  2291.         ["true"] = "constant",
  2292.         ["false"] = "constant",
  2293.         ["nil"] = "constant",
  2294.  
  2295.         ["print"] = "function",
  2296.         ["write"] = "function",
  2297.         ["sleep"] = "function",
  2298.         ["pairs"] = "function",
  2299.         ["ipairs"] = "function",
  2300.         ["loadstring"] = "function",
  2301.         ["loadfile"] = "function",
  2302.         ["dofile"] = "function",
  2303.         ["rawset"] = "function",
  2304.         ["rawget"] = "function",
  2305.         ["setfenv"] = "function",
  2306.         ["getfenv"] = "function",
  2307.     }
  2308.  
  2309.     languages.lua.parseError = function(e)
  2310.         local ret = {filename = "unknown", line = -1, display = "Unknown!", err = ""}
  2311.         if e and e ~= "" then
  2312.             ret.err = e
  2313.             if e:find(":") then
  2314.                 ret.filename = e:sub(1, e:find(":") - 1):gsub("^%s*(.-)%s*$", "%1")
  2315.                 -- The "" is needed to circumvent a CC bug
  2316.                 e = (e:sub(e:find(":") + 1) .. ""):gsub("^%s*(.-)%s*$", "%1")
  2317.                 if e:find(":") then
  2318.                     ret.line = e:sub(1, e:find(":") - 1)
  2319.                     e = e:sub(e:find(":") + 2):gsub("^%s*(.-)%s*$", "%1") .. ""
  2320.                 end
  2321.             end
  2322.             ret.display = e:sub(1, 1):upper() .. e:sub(2, -1) .. "."
  2323.         end
  2324.  
  2325.         return ret
  2326.     end
  2327.  
  2328.     languages.lua.getCompilerErrors = function(code)
  2329.         code = "local function ee65da6af1cb6f63fee9a081246f2fd92b36ef2(...)\n\n" .. code .. "\n\nend"
  2330.         local fn, err = loadstring(code)
  2331.         if not err then
  2332.             local _, e = pcall(fn)
  2333.             if e then err = e end
  2334.         end
  2335.  
  2336.         if err then
  2337.             local a = err:find("]", 1, true)
  2338.             if a then err = "string" .. err:sub(a + 1, -1) end
  2339.             local ret = languages.lua.parseError(err)
  2340.             if tonumber(ret.line) then ret.line = tonumber(ret.line) end
  2341.             return ret
  2342.         else return languages.lua.parseError(nil) end
  2343.     end
  2344.  
  2345.     languages.lua.run = function(path, ar)
  2346.         local fn, err = loadfile(path)
  2347.         setfenv(fn, getfenv())
  2348.         if not err then
  2349.             _, err = pcall(function() fn(unpack(ar)) end)
  2350.         end
  2351.         return err
  2352.     end
  2353.  
  2354.  
  2355.     --  Brainfuck
  2356.  
  2357.     languages.brainfuck.helpTips = {
  2358.         "Well idk...",
  2359.         "Isn't this the whole point of the language?",
  2360.         "Ya know... Not being able to debug it?",
  2361.         "You made a typo."
  2362.     }
  2363.  
  2364.     languages.brainfuck.defaultHelpTips = {
  2365.         1, 2, 3
  2366.     }
  2367.  
  2368.     languages.brainfuck.errors = {
  2369.         ["No matching '['"] = {1, 2, 3, 4}
  2370.     }
  2371.  
  2372.     languages.brainfuck.keywords = {}
  2373.  
  2374.     languages.brainfuck.parseError = function(e)
  2375.         local ret = {filename = "unknown", line = -1, display = "Unknown!", err = ""}
  2376.         if e and e ~= "" then
  2377.             ret.err = e
  2378.             ret.line = e:sub(1, e:find(":") - 1)
  2379.             e = e:sub(e:find(":") + 2):gsub("^%s*(.-)%s*$", "%1") .. ""
  2380.             ret.display = e:sub(1, 1):upper() .. e:sub(2, -1) .. "."
  2381.         end
  2382.  
  2383.         return ret
  2384.     end
  2385.  
  2386.     languages.brainfuck.mapLoops = function(code)
  2387.         -- Map loops
  2388.         local loopLocations = {}
  2389.         local loc = 1
  2390.         local line = 1
  2391.         for let in string.gmatch(code, ".") do
  2392.             if let == "[" then
  2393.                 loopLocations[loc] = true
  2394.             elseif let == "]" then
  2395.                 local found = false
  2396.                 for i = loc, 1, -1 do
  2397.                     if loopLocations[i] == true then
  2398.                         loopLocations[i] = loc
  2399.                         found = true
  2400.                     end
  2401.                 end
  2402.  
  2403.                 if not found then
  2404.                     return line .. ": No matching '['"
  2405.                 end
  2406.             end
  2407.  
  2408.             if let == "\n" then line = line + 1 end
  2409.             loc = loc + 1
  2410.         end
  2411.         return loopLocations
  2412.     end
  2413.  
  2414.     languages.brainfuck.getCompilerErrors = function(code)
  2415.         local a = languages.brainfuck.mapLoops(code)
  2416.         if type(a) == "string" then return languages.brainfuck.parseError(a)
  2417.         else return languages.brainfuck.parseError(nil) end
  2418.     end
  2419.  
  2420.     languages.brainfuck.run = function(path)
  2421.         -- Read from file
  2422.         local f = io.open(path, "r")
  2423.         local content = f:read("*a")
  2424.         f:close()
  2425.  
  2426.         -- Define environment
  2427.         local dataCells = {}
  2428.         local dataPointer = 1
  2429.         local instructionPointer = 1
  2430.  
  2431.         -- Map loops
  2432.         local loopLocations = languages.brainfuck.mapLoops(content)
  2433.         if type(loopLocations) == "string" then return loopLocations end
  2434.  
  2435.         -- Execute code
  2436.         while true do
  2437.             local let = content:sub(instructionPointer, instructionPointer)
  2438.  
  2439.             if let == ">" then
  2440.                 dataPointer = dataPointer + 1
  2441.                 if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end
  2442.             elseif let == "<" then
  2443.                 if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end
  2444.                 dataPointer = dataPointer - 1
  2445.                 if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end
  2446.             elseif let == "+" then
  2447.                 if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end
  2448.                 dataCells[tostring(dataPointer)] = dataCells[tostring(dataPointer)] + 1
  2449.             elseif let == "-" then
  2450.                 if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end
  2451.                 dataCells[tostring(dataPointer)] = dataCells[tostring(dataPointer)] - 1
  2452.             elseif let == "." then
  2453.                 if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end
  2454.                 if term.getCursorPos() >= w then print("") end
  2455.                 write(string.char(math.max(1, dataCells[tostring(dataPointer)])))
  2456.             elseif let == "," then
  2457.                 if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end
  2458.                 term.setCursorBlink(true)
  2459.                 local e, but = os.pullEvent("char")
  2460.                 term.setCursorBlink(false)
  2461.                 dataCells[tostring(dataPointer)] = string.byte(but)
  2462.                 if term.getCursorPos() >= w then print("") end
  2463.                 write(but)
  2464.             elseif let == "/" then
  2465.                 if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end
  2466.                 if term.getCursorPos() >= w then print("") end
  2467.                 write(dataCells[tostring(dataPointer)])
  2468.             elseif let == "[" then
  2469.                 if dataCells[tostring(dataPointer)] == 0 then
  2470.                     for k, v in pairs(loopLocations) do
  2471.                         if k == instructionPointer then instructionPointer = v end
  2472.                     end
  2473.                 end
  2474.             elseif let == "]" then
  2475.                 for k, v in pairs(loopLocations) do
  2476.                     if v == instructionPointer then instructionPointer = k - 1 end
  2477.                 end
  2478.             end
  2479.  
  2480.             instructionPointer = instructionPointer + 1
  2481.             if instructionPointer > content:len() then print("") break end
  2482.         end
  2483.     end
  2484.  
  2485.     --  None
  2486.  
  2487.     languages.none.helpTips = {}
  2488.     languages.none.defaultHelpTips = {}
  2489.     languages.none.errors = {}
  2490.     languages.none.keywords = {}
  2491.  
  2492.     languages.none.parseError = function(err)
  2493.         return {filename = "", line = -1, display = "", err = ""}
  2494.     end
  2495.  
  2496.     languages.none.getCompilerErrors = function(code)
  2497.         return languages.none.parseError(nil)
  2498.     end
  2499.  
  2500.     languages.none.run = function(path) end
  2501.  
  2502.  
  2503.     -- Load language
  2504.     curLanguage = languages.lua
  2505.  
  2506.  
  2507.     --  -------- Run GUI
  2508.  
  2509.     local function viewErrorHelp(e)
  2510.         title("LuaIDE - Error Help")
  2511.  
  2512.         local tips = nil
  2513.         for k, v in pairs(curLanguage.errors) do
  2514.             if e.display:find(k) then tips = v break end
  2515.         end
  2516.  
  2517.         term.setBackgroundColor(colors[theme.err])
  2518.         for i = 6, 8 do
  2519.             term.setCursorPos(5, i)
  2520.             term.write(string.rep(" ", 35))
  2521.         end
  2522.  
  2523.         term.setBackgroundColor(colors[theme.prompt])
  2524.         for i = 10, 18 do
  2525.             term.setCursorPos(5, i)
  2526.             term.write(string.rep(" ", 46))
  2527.         end
  2528.  
  2529.         if tips then
  2530.             term.setBackgroundColor(colors[theme.err])
  2531.             term.setCursorPos(6, 7)
  2532.             term.write("Error Help")
  2533.  
  2534.             term.setBackgroundColor(colors[theme.prompt])
  2535.             for i, v in ipairs(tips) do
  2536.                 term.setCursorPos(7, i + 10)
  2537.                 term.write("- " .. curLanguage.helpTips[v])
  2538.             end
  2539.         else
  2540.             term.setBackgroundColor(colors[theme.err])
  2541.             term.setCursorPos(6, 7)
  2542.             term.write("No Error Tips Available!")
  2543.  
  2544.             term.setBackgroundColor(colors[theme.prompt])
  2545.             term.setCursorPos(6, 11)
  2546.             term.write("There are no error tips available, but")
  2547.             term.setCursorPos(6, 12)
  2548.             term.write("you could see if it was any of these:")
  2549.  
  2550.             for i, v in ipairs(curLanguage.defaultHelpTips) do
  2551.                 term.setCursorPos(7, i + 12)
  2552.                 term.write("- " .. curLanguage.helpTips[v])
  2553.             end
  2554.         end
  2555.  
  2556.         prompt({{"Back", w - 8, 7}}, "horizontal")
  2557.     end
  2558.  
  2559.     local function run(path, lines, useArgs)
  2560.         local ar = {}
  2561.         if useArgs then
  2562.             title("LuaIDE - Run " .. fs.getName(path))
  2563.             local s = centerRead(w - 13, fs.getName(path) .. " ")
  2564.             for m in string.gmatch(s, "[^ \t]+") do ar[#ar + 1] = m:gsub("^%s*(.-)%s*$", "%1") end
  2565.         end
  2566.        
  2567.         saveFile(path, lines)
  2568.         term.setCursorBlink(false)
  2569.         term.setBackgroundColor(colors.black)
  2570.         term.setTextColor(colors.white)
  2571.         term.clear()
  2572.         term.setCursorPos(1, 1)
  2573.         local err = curLanguage.run(path, ar)
  2574.  
  2575.         term.setBackgroundColor(colors.black)
  2576.         print("\n")
  2577.         if err then
  2578.             if isAdvanced() then term.setTextColor(colors.red) end
  2579.             centerPrint("The program has crashed!")
  2580.         end
  2581.         term.setTextColor(colors.white)
  2582.         centerPrint("Press any key to return to LuaIDE...")
  2583.         while true do
  2584.             local e = os.pullEvent()
  2585.             if e == "key" then break end
  2586.         end
  2587.  
  2588.         -- To prevent key from showing up in editor
  2589.         os.queueEvent(event_distract)
  2590.         os.pullEvent()
  2591.  
  2592.         if err then
  2593.             if curLanguage == languages.lua and err:find("]") then
  2594.                 err = fs.getName(path) .. err:sub(err:find("]", 1, true) + 1, -1)
  2595.             end
  2596.  
  2597.             while true do
  2598.                 title("LuaIDE - Error!")
  2599.  
  2600.                 term.setBackgroundColor(colors[theme.err])
  2601.                 for i = 6, 8 do
  2602.                     term.setCursorPos(3, i)
  2603.                     term.write(string.rep(" ", w - 5))
  2604.                 end
  2605.                 term.setCursorPos(4, 7)
  2606.                 term.write("The program has crashed!")
  2607.  
  2608.                 term.setBackgroundColor(colors[theme.prompt])
  2609.                 for i = 10, 14 do
  2610.                     term.setCursorPos(3, i)
  2611.                     term.write(string.rep(" ", w - 5))
  2612.                 end
  2613.  
  2614.                 local formattedErr = curLanguage.parseError(err)
  2615.                 term.setCursorPos(4, 11)
  2616.                 term.write("Line: " .. formattedErr.line)
  2617.                 term.setCursorPos(4, 12)
  2618.                 term.write("Error:")
  2619.                 term.setCursorPos(5, 13)
  2620.  
  2621.                 local a = formattedErr.display
  2622.                 local b = nil
  2623.                 if a:len() > w - 8 then
  2624.                     for i = a:len(), 1, -1 do
  2625.                         if a:sub(i, i) == " " then
  2626.                             b = a:sub(i + 1, -1)
  2627.                             a = a:sub(1, i)
  2628.                             break
  2629.                         end
  2630.                     end
  2631.                 end
  2632.  
  2633.                 term.write(a)
  2634.                 if b then
  2635.                     term.setCursorPos(5, 14)
  2636.                     term.write(b)
  2637.                 end
  2638.                
  2639.                 local opt = prompt({{"Error Help", w/2 - 15, 17}, {"Go To Line", w/2 + 2, 17}},
  2640.                     "horizontal")
  2641.                 if opt == "Error Help" then
  2642.                     viewErrorHelp(formattedErr)
  2643.                 elseif opt == "Go To Line" then
  2644.                     -- To prevent key from showing up in editor
  2645.                     os.queueEvent(event_distract)
  2646.                     os.pullEvent()
  2647.  
  2648.                     return "go to", tonumber(formattedErr.line)
  2649.                 end
  2650.             end
  2651.         end
  2652.     end
  2653.  
  2654.  
  2655.     --  -------- Functions
  2656.  
  2657.     local function goto()
  2658.         term.setBackgroundColor(colors[theme.backgroundHighlight])
  2659.         term.setCursorPos(2, 1)
  2660.         term.clearLine()
  2661.         term.write("Line: ")
  2662.         local line = modRead({visibleLength = w - 2})
  2663.  
  2664.         local num = tonumber(line)
  2665.         if num and num > 0 then return num
  2666.         else
  2667.             term.setCursorPos(2, 1)
  2668.             term.clearLine()
  2669.             term.write("Not a line number!")
  2670.             sleep(1.6)
  2671.             return nil
  2672.         end
  2673.     end
  2674.  
  2675.     local function setsyntax()
  2676.         local opts = {
  2677.             "[Lua]   Brainfuck    None ",
  2678.             " Lua   [Brainfuck]   None ",
  2679.             " Lua    Brainfuck   [None]"
  2680.         }
  2681.         local sel = 1
  2682.  
  2683.         term.setCursorBlink(false)
  2684.         term.setBackgroundColor(colors[theme.backgroundHighlight])
  2685.         term.setCursorPos(2, 1)
  2686.         term.clearLine()
  2687.         term.write(opts[sel])
  2688.         while true do
  2689.             local e, but, x, y = os.pullEvent("key")
  2690.             if but == 203 then
  2691.                 sel = math.max(1, sel - 1)
  2692.                 term.setCursorPos(2, 1)
  2693.                 term.clearLine()
  2694.                 term.write(opts[sel])
  2695.             elseif but == 205 then
  2696.                 sel = math.min(#opts, sel + 1)
  2697.                 term.setCursorPos(2, 1)
  2698.                 term.clearLine()
  2699.                 term.write(opts[sel])
  2700.             elseif but == 28 then
  2701.                 if sel == 1 then curLanguage = languages.lua
  2702.                 elseif sel == 2 then curLanguage = languages.brainfuck
  2703.                 elseif sel == 3 then curLanguage = languages.none end
  2704.                 term.setCursorBlink(true)
  2705.                 return
  2706.             end
  2707.         end
  2708.     end
  2709.  
  2710.  
  2711.     --  -------- Re-Indenting
  2712.  
  2713.     local tabWidth = 2
  2714.  
  2715.     local comments = {}
  2716.     local strings = {}
  2717.  
  2718.     local increment = {
  2719.         "if%s+.+%s+then%s*$",
  2720.         "for%s+.+%s+do%s*$",
  2721.         "while%s+.+%s+do%s*$",
  2722.         "repeat%s*$",
  2723.         "function%s+[a-zA-Z_0-9](.*)%s*$"
  2724.     }
  2725.  
  2726.     local decrement = {
  2727.         "end",
  2728.         "until%s+.+"
  2729.     }
  2730.  
  2731.     local special = {
  2732.         "else%s*$",
  2733.         "elseif%s+.+%s+then%s*$"
  2734.     }
  2735.  
  2736.     local function check(func)
  2737.         for _, v in pairs(func) do
  2738.             local cLineStart = v["lineStart"]
  2739.             local cLineEnd = v["lineEnd"]
  2740.             local cCharStart = v["charStart"]
  2741.             local cCharEnd = v["charEnd"]
  2742.  
  2743.             if line >= cLineStart and line <= cLineEnd then
  2744.                 if line == cLineStart then return cCharStart < charNumb
  2745.                 elseif line == cLineEnd then return cCharEnd > charNumb
  2746.                 else return true end
  2747.             end
  2748.         end
  2749.     end
  2750.  
  2751.     local function isIn(line, loc)
  2752.         if check(comments) then return true end
  2753.         if check(strings) then return true end
  2754.         return false
  2755.     end
  2756.  
  2757.     local function setComment(ls, le, cs, ce)
  2758.         comments[#comments + 1] = {}
  2759.         comments[#comments].lineStart = ls
  2760.         comments[#comments].lineEnd = le
  2761.         comments[#comments].charStart = cs
  2762.         comments[#comments].charEnd = ce
  2763.     end
  2764.  
  2765.     local function setString(ls, le, cs, ce)
  2766.         strings[#strings + 1] = {}
  2767.         strings[#strings].lineStart = ls
  2768.         strings[#strings].lineEnd = le
  2769.         strings[#strings].charStart = cs
  2770.         strings[#strings].charEnd = ce
  2771.     end
  2772.  
  2773.     local function map(contents)
  2774.         local inCom = false
  2775.         local inStr = false
  2776.  
  2777.         for i = 1, #contents do
  2778.             if content[i]:find("%-%-%[%[") and not inStr and not inCom then
  2779.                 local cStart = content[i]:find("%-%-%[%[")
  2780.                 setComment(i, nil, cStart, nil)
  2781.                 inCom = true
  2782.             elseif content[i]:find("%-%-%[=%[") and not inStr and not inCom then
  2783.                 local cStart = content[i]:find("%-%-%[=%[")
  2784.                 setComment(i, nil, cStart, nil)
  2785.                 inCom = true
  2786.             elseif content[i]:find("%[%[") and not inStr and not inCom then
  2787.                 local cStart = content[i]:find("%[%[")
  2788.                 setString(i, nil, cStart, nil)
  2789.                 inStr = true
  2790.             elseif content[i]:find("%[=%[") and not inStr and not inCom then
  2791.                 local cStart = content[i]:find("%[=%[")
  2792.                 setString(i, nil, cStart, nil)
  2793.                 inStr = true
  2794.             end
  2795.  
  2796.             if content[i]:find("%]%]") and inStr and not inCom then
  2797.                 local cStart, cEnd = content[i]:find("%]%]")
  2798.                 strings[#strings].lineEnd = i
  2799.                 strings[#strings].charEnd = cEnd
  2800.                 inStr = false
  2801.             elseif content[i]:find("%]=%]") and inStr and not inCom then
  2802.                 local cStart, cEnd = content[i]:find("%]=%]")
  2803.                 strings[#strings].lineEnd = i
  2804.                 strings[#strings].charEnd = cEnd
  2805.                 inStr = false
  2806.             end
  2807.  
  2808.             if content[i]:find("%]%]") and not inStr and inCom then
  2809.                 local cStart, cEnd = content[i]:find("%]%]")
  2810.                 comments[#comments].lineEnd = i
  2811.                 comments[#comments].charEnd = cEnd
  2812.                 inCom = false
  2813.             elseif content[i]:find("%]=%]") and not inStr and inCom then
  2814.                 local cStart, cEnd = content[i]:find("%]=%]")
  2815.                 comments[#comments].lineEnd = i
  2816.                 comments[#comments].charEnd = cEnd
  2817.                 inCom = false
  2818.             end
  2819.  
  2820.             if content[i]:find("%-%-") and not inStr and not inCom then
  2821.                 local cStart = content[i]:find("%-%-")
  2822.                 setComment(i, i, cStart, -1)
  2823.             elseif content[i]:find("'") and not inStr and not inCom then
  2824.                 local cStart, cEnd = content[i]:find("'")
  2825.                 local nextChar = content[i]:sub(cEnd + 1, string.len(content[i]))
  2826.                 local _, cEnd = nextChar:find("'")
  2827.                 setString(i, i, cStart, cEnd)
  2828.             elseif content[i]:find('"') and not inStr and not inCom then
  2829.                 local cStart, cEnd = content[i]:find('"')
  2830.                 local nextChar = content[i]:sub(cEnd + 1, string.len(content[i]))
  2831.                 local _, cEnd = nextChar:find('"')
  2832.                 setString(i, i, cStart, cEnd)
  2833.             end
  2834.         end
  2835.     end
  2836.  
  2837.     local function reindent(contents)
  2838.         local err = nil
  2839.         if curLanguage ~= languages.lua then
  2840.             err = "Cannot indent languages other than Lua!"
  2841.         elseif curLanguage.getCompilerErrors(table.concat(contents, "\n")).line ~= -1 then
  2842.             err = "Cannot indent a program with errors!"
  2843.         end
  2844.  
  2845.         if err then
  2846.             term.setCursorBlink(false)
  2847.             term.setCursorPos(2, 1)
  2848.             term.setBackgroundColor(colors[theme.backgroundHighlight])
  2849.             term.clearLine()
  2850.             term.write(err)
  2851.             sleep(1.6)
  2852.             return contents
  2853.         end
  2854.  
  2855.         local new = {}
  2856.         local level = 0
  2857.         for k, v in pairs(contents) do
  2858.             local incrLevel = false
  2859.             local foundIncr = false
  2860.             for _, incr in pairs(increment) do
  2861.                 if v:find(incr) and not isIn(k, v:find(incr)) then
  2862.                     incrLevel = true
  2863.                 end
  2864.                 if v:find(incr:sub(1, -2)) and not isIn(k, v:find(incr)) then
  2865.                     foundIncr = true
  2866.                 end
  2867.             end
  2868.  
  2869.             local decrLevel = false
  2870.             if not incrLevel then
  2871.                 for _, decr in pairs(decrement) do
  2872.                     if v:find(decr) and not isIn(k, v:find(decr)) and not foundIncr then
  2873.                         level = math.max(0, level - 1)
  2874.                         decrLevel = true
  2875.                     end
  2876.                 end
  2877.             end
  2878.  
  2879.             if not decrLevel then
  2880.                 for _, sp in pairs(special) do
  2881.                     if v:find(sp) and not isIn(k, v:find(sp)) then
  2882.                         incrLevel = true
  2883.                         level = math.max(0, level - 1)
  2884.                     end
  2885.                 end
  2886.             end
  2887.  
  2888.             new[k] = string.rep(" ", level * tabWidth) .. v
  2889.             if incrLevel then level = level + 1 end
  2890.         end
  2891.  
  2892.         return new
  2893.     end
  2894.  
  2895.  
  2896.     --  -------- Menu
  2897.  
  2898.     local menu = {
  2899.         [1] = {"File",
  2900.     --      "About",
  2901.     --      "Settings",
  2902.     --      "",
  2903.             "New File  ^+N",
  2904.             "Open File ^+O",
  2905.             "Save File ^+S",
  2906.             "Close     ^+W",
  2907.             "Print     ^+P",
  2908.             "Quit      ^+Q"
  2909.         }, [2] = {"Edit",
  2910.             "Cut Line   ^+X",
  2911.             "Copy Line  ^+C",
  2912.             "Paste Line ^+V",
  2913.             "Delete Line",
  2914.             "Clear Line"
  2915.         }, [3] = {"Functions",
  2916.             "Go To Line    ^+G",
  2917.             "Re-Indent     ^+I",
  2918.             "Set Syntax    ^+E",
  2919.             "Start of Line ^+<",
  2920.             "End of Line   ^+>"
  2921.         }, [4] = {"Run",
  2922.             "Run Program       ^+R",
  2923.             "Run w/ Args ^+Shift+R"
  2924.         }
  2925.     }
  2926.  
  2927.     local shortcuts = {
  2928.         -- File
  2929.         ["ctrl n"] = "New File  ^+N",
  2930.         ["ctrl o"] = "Open File ^+O",
  2931.         ["ctrl s"] = "Save File ^+S",
  2932.         ["ctrl w"] = "Close     ^+W",
  2933.         ["ctrl p"] = "Print     ^+P",
  2934.         ["ctrl q"] = "Quit      ^+Q",
  2935.  
  2936.         -- Edit
  2937.         ["ctrl x"] = "Cut Line   ^+X",
  2938.         ["ctrl c"] = "Copy Line  ^+C",
  2939.         ["ctrl v"] = "Paste Line ^+V",
  2940.  
  2941.         -- Functions
  2942.         ["ctrl g"] = "Go To Line    ^+G",
  2943.         ["ctrl i"] = "Re-Indent     ^+I",
  2944.         ["ctrl e"] = "Set Syntax    ^+E",
  2945.         ["ctrl 203"] = "Start of Line ^+<",
  2946.         ["ctrl 205"] = "End of Line   ^+>",
  2947.  
  2948.         -- Run
  2949.         ["ctrl r"] = "Run Program       ^+R",
  2950.         ["ctrl shift r"] = "Run w/ Args ^+Shift+R"
  2951.     }
  2952.  
  2953.     local menuFunctions = {
  2954.         -- File
  2955.     --  ["About"] = function() end,
  2956.     --  ["Settings"] = function() end,
  2957.         ["New File  ^+N"] = function(path, lines) saveFile(path, lines) return "new" end,
  2958.         ["Open File ^+O"] = function(path, lines) saveFile(path, lines) return "open" end,
  2959.         ["Save File ^+S"] = function(path, lines) saveFile(path, lines) end,
  2960.         ["Close     ^+W"] = function(path, lines) saveFile(path, lines) return "menu" end,
  2961.         ["Print     ^+P"] = function(path, lines) saveFile(path, lines) return nil end,
  2962.         ["Quit      ^+Q"] = function(path, lines) saveFile(path, lines) return "exit" end,
  2963.  
  2964.         -- Edit
  2965.         ["Cut Line   ^+X"] = function(path, lines, y)
  2966.             clipboard = lines[y] table.remove(lines, y) return nil, lines end,
  2967.         ["Copy Line  ^+C"] = function(path, lines, y) clipboard = lines[y] end,
  2968.         ["Paste Line ^+V"] = function(path, lines, y)
  2969.             if clipboard then table.insert(lines, y, clipboard) end return nil, lines end,
  2970.         ["Delete Line"] = function(path, lines, y) table.remove(lines, y) return nil, lines end,
  2971.         ["Clear Line"] = function(path, lines, y) lines[y] = "" return nil, lines, "cursor" end,
  2972.  
  2973.         -- Functions
  2974.         ["Go To Line    ^+G"] = function() return nil, "go to", goto() end,
  2975.         ["Re-Indent     ^+I"] = function(path, lines)
  2976.             local a = reindent(lines) saveFile(path, lines) return nil, a
  2977.         end,
  2978.         ["Set Syntax    ^+E"] = function(path, lines)
  2979.             setsyntax()
  2980.             if curLanguage == languages.brainfuck and lines[1] ~= "-- Syntax: Brainfuck" then
  2981.                 table.insert(lines, 1, "-- Syntax: Brainfuck")
  2982.                 return nil, lines
  2983.             end
  2984.         end,
  2985.         ["Start of Line ^+<"] = function() os.queueEvent("key", 199) end,
  2986.         ["End of Line   ^+>"] = function() os.queueEvent("key", 207) end,
  2987.  
  2988.         -- Run
  2989.         ["Run Program       ^+R"] = function(path, lines)
  2990.             saveFile(path, lines)
  2991.             return nil, run(path, lines, false)
  2992.         end,
  2993.         ["Run w/ Args ^+Shift+R"] = function(path, lines)
  2994.             saveFile(path, lines)
  2995.             return nil, run(path, lines, true)
  2996.         end,
  2997.     }
  2998.  
  2999.     local function drawMenu(open)
  3000.         term.setCursorPos(1, 1)
  3001.         term.setTextColor(colors[theme.textColor])
  3002.         term.setBackgroundColor(colors[theme.backgroundHighlight])
  3003.         term.clearLine()
  3004.         local curX = 0
  3005.         for _, v in pairs(menu) do
  3006.             term.setCursorPos(3 + curX, 1)
  3007.             term.write(v[1])
  3008.             curX = curX + v[1]:len() + 3
  3009.         end
  3010.  
  3011.         if open then
  3012.             local it = {}
  3013.             local x = 1
  3014.             for _, v in pairs(menu) do
  3015.                 if open == v[1] then
  3016.                     it = v
  3017.                     break
  3018.                 end
  3019.                 x = x + v[1]:len() + 3
  3020.             end
  3021.             x = x + 1
  3022.  
  3023.             local items = {}
  3024.             for i = 2, #it do
  3025.                 table.insert(items, it[i])
  3026.             end
  3027.  
  3028.             local len = 1
  3029.             for _, v in pairs(items) do if v:len() + 2 > len then len = v:len() + 2 end end
  3030.  
  3031.             for i, v in ipairs(items) do
  3032.                 term.setCursorPos(x, i + 1)
  3033.                 term.write(string.rep(" ", len))
  3034.                 term.setCursorPos(x + 1, i + 1)
  3035.                 term.write(v)
  3036.             end
  3037.             term.setCursorPos(x, #items + 2)
  3038.             term.write(string.rep(" ", len))
  3039.             return items, len
  3040.         end
  3041.     end
  3042.  
  3043.     local function triggerMenu(cx, cy)
  3044.         -- Determine clicked menu
  3045.         local curX = 0
  3046.         local open = nil
  3047.         for _, v in pairs(menu) do
  3048.             if cx >= curX + 3 and cx <= curX + v[1]:len() + 2 then
  3049.                 open = v[1]
  3050.                 break
  3051.             end
  3052.             curX = curX + v[1]:len() + 3
  3053.         end
  3054.         local menux = curX + 2
  3055.         if not open then return false end
  3056.  
  3057.         -- Flash menu item
  3058.         term.setCursorBlink(false)
  3059.         term.setCursorPos(menux, 1)
  3060.         term.setBackgroundColor(colors[theme.background])
  3061.         term.write(string.rep(" ", open:len() + 2))
  3062.         term.setCursorPos(menux + 1, 1)
  3063.         term.write(open)
  3064.         sleep(0.1)
  3065.         local items, len = drawMenu(open)
  3066.  
  3067.         local ret = true
  3068.  
  3069.         -- Pull events on menu
  3070.         local ox, oy = term.getCursorPos()
  3071.         while type(ret) ~= "string" do
  3072.             local e, but, x, y = os.pullEvent()
  3073.             if e == "mouse_click" then
  3074.                 -- If clicked outside menu
  3075.                 if x < menux - 1 or x > menux + len - 1 then break
  3076.                 elseif y > #items + 2 then break
  3077.                 elseif y == 1 then break end
  3078.  
  3079.                 for i, v in ipairs(items) do
  3080.                     if y == i + 1 and x >= menux and x <= menux + len - 2 then
  3081.                         -- Flash when clicked
  3082.                         term.setCursorPos(menux, y)
  3083.                         term.setBackgroundColor(colors[theme.background])
  3084.                         term.write(string.rep(" ", len))
  3085.                         term.setCursorPos(menux + 1, y)
  3086.                         term.write(v)
  3087.                         sleep(0.1)
  3088.                         drawMenu(open)
  3089.  
  3090.                         -- Return item
  3091.                         ret = v
  3092.                         break
  3093.                     end
  3094.                 end
  3095.             end
  3096.         end
  3097.  
  3098.         term.setCursorPos(ox, oy)
  3099.         term.setCursorBlink(true)
  3100.         return ret
  3101.     end
  3102.  
  3103.  
  3104.     --  -------- Editing
  3105.  
  3106.     local standardsCompletions = {
  3107.         "if%s+.+%s+then%s*$",
  3108.         "for%s+.+%s+do%s*$",
  3109.         "while%s+.+%s+do%s*$",
  3110.         "repeat%s*$",
  3111.         "function%s+[a-zA-Z_0-9]?(.*)%s*$",
  3112.         "=%s*function%s*(.*)%s*$",
  3113.         "else%s*$",
  3114.         "elseif%s+.+%s+then%s*$"
  3115.     }
  3116.  
  3117.     local liveCompletions = {
  3118.         ["("] = ")",
  3119.         ["{"] = "}",
  3120.         ["["] = "]",
  3121.         ["\""] = "\"",
  3122.         ["'"] = "'",
  3123.     }
  3124.  
  3125.     local x, y = 0, 0
  3126.     local edw, edh = 0, h - 1
  3127.     local offx, offy = 0, 1
  3128.     local scrollx, scrolly = 0, 0
  3129.     local lines = {}
  3130.     local liveErr = curLanguage.parseError(nil)
  3131.     local displayCode = true
  3132.     local lastEventClock = os.clock()
  3133.  
  3134.     local function attemptToHighlight(line, regex, col)
  3135.         local match = string.match(line, regex)
  3136.         if match then
  3137.             if type(col) == "number" then term.setTextColor(col)
  3138.             elseif type(col) == "function" then term.setTextColor(col(match)) end
  3139.             term.write(match)
  3140.             term.setTextColor(colors[theme.textColor])
  3141.             return line:sub(match:len() + 1, -1)
  3142.         end
  3143.         return nil
  3144.     end
  3145.  
  3146.     local function writeHighlighted(line)
  3147.         if curLanguage == languages.lua then
  3148.             while line:len() > 0 do
  3149.                 line = attemptToHighlight(line, "^%-%-%[%[.-%]%]", colors[theme.comment]) or
  3150.                     attemptToHighlight(line, "^%-%-.*", colors[theme.comment]) or
  3151.                     attemptToHighlight(line, "^\".*[^\\]\"", colors[theme.string]) or
  3152.                     attemptToHighlight(line, "^\'.*[^\\]\'", colors[theme.string]) or
  3153.                     attemptToHighlight(line, "^%[%[.-%]%]", colors[theme.string]) or
  3154.                     attemptToHighlight(line, "^[%w_]+", function(match)
  3155.                         if curLanguage.keywords[match] then
  3156.                             return colors[theme[curLanguage.keywords[match]]]
  3157.                         end
  3158.                         return colors[theme.textColor]
  3159.                     end) or
  3160.                     attemptToHighlight(line, "^[^%w_]", colors[theme.textColor])
  3161.             end
  3162.         else term.write(line) end
  3163.     end
  3164.  
  3165.     local function draw()
  3166.         -- Menu
  3167.         term.setTextColor(colors[theme.textColor])
  3168.         term.setBackgroundColor(colors[theme.editorBackground])
  3169.         term.clear()
  3170.         drawMenu()
  3171.  
  3172.         -- Line numbers
  3173.         offx, offy = tostring(#lines):len() + 1, 1
  3174.         edw, edh = w - offx, h - 1
  3175.  
  3176.         -- Draw text
  3177.         for i = 1, edh do
  3178.             local a = lines[scrolly + i]
  3179.             if a then
  3180.                 local ln = string.rep(" ", offx - 1 - tostring(scrolly + i):len()) .. tostring(scrolly + i)
  3181.                 local l = a:sub(scrollx + 1, edw + scrollx + 1)
  3182.                 ln = ln .. ":"
  3183.  
  3184.                 if liveErr.line == scrolly + i then ln = string.rep(" ", offx - 2) .. "!:" end
  3185.  
  3186.                 term.setCursorPos(1, i + offy)
  3187.                 term.setBackgroundColor(colors[theme.editorBackground])
  3188.                 if scrolly + i == y then
  3189.                     if scrolly + i == liveErr.line and os.clock() - lastEventClock > 3 then
  3190.                         term.setBackgroundColor(colors[theme.editorErrorHighlight])
  3191.                     else term.setBackgroundColor(colors[theme.editorLineHightlight]) end
  3192.                     term.clearLine()
  3193.                 elseif scrolly + i == liveErr.line then
  3194.                     term.setBackgroundColor(colors[theme.editorError])
  3195.                     term.clearLine()
  3196.                 end
  3197.  
  3198.                 term.setCursorPos(1 - scrollx + offx, i + offy)
  3199.                 if scrolly + i == y then
  3200.                     if scrolly + i == liveErr.line and os.clock() - lastEventClock > 3 then
  3201.                         term.setBackgroundColor(colors[theme.editorErrorHighlight])
  3202.                     else term.setBackgroundColor(colors[theme.editorLineHightlight]) end
  3203.                 elseif scrolly + i == liveErr.line then term.setBackgroundColor(colors[theme.editorError])
  3204.                 else term.setBackgroundColor(colors[theme.editorBackground]) end
  3205.                 if scrolly + i == liveErr.line then
  3206.                     if displayCode then term.write(a)
  3207.                     else term.write(liveErr.display) end
  3208.                 else writeHighlighted(a) end
  3209.  
  3210.                 term.setCursorPos(1, i + offy)
  3211.                 if scrolly + i == y then
  3212.                     if scrolly + i == liveErr.line and os.clock() - lastEventClock > 3 then
  3213.                         term.setBackgroundColor(colors[theme.editorError])
  3214.                     else term.setBackgroundColor(colors[theme.editorLineNumbersHighlight]) end
  3215.                 elseif scrolly + i == liveErr.line then
  3216.                     term.setBackgroundColor(colors[theme.editorErrorHighlight])
  3217.                 else term.setBackgroundColor(colors[theme.editorLineNumbers]) end
  3218.                 term.write(ln)
  3219.             end
  3220.         end
  3221.         term.setCursorPos(x - scrollx + offx, y - scrolly + offy)
  3222.     end
  3223.  
  3224.     local function drawLine(...)
  3225.         local ls = {...}
  3226.         offx = tostring(#lines):len() + 1
  3227.         for _, ly in pairs(ls) do
  3228.             local a = lines[ly]
  3229.             if a then
  3230.                 local ln = string.rep(" ", offx - 1 - tostring(ly):len()) .. tostring(ly)
  3231.                 local l = a:sub(scrollx + 1, edw + scrollx + 1)
  3232.                 ln = ln .. ":"
  3233.  
  3234.                 if liveErr.line == ly then ln = string.rep(" ", offx - 2) .. "!:" end
  3235.  
  3236.                 term.setCursorPos(1, (ly - scrolly) + offy)
  3237.                 term.setBackgroundColor(colors[theme.editorBackground])
  3238.                 if ly == y then
  3239.                     if ly == liveErr.line and os.clock() - lastEventClock > 3 then
  3240.                         term.setBackgroundColor(colors[theme.editorErrorHighlight])
  3241.                     else term.setBackgroundColor(colors[theme.editorLineHightlight]) end
  3242.                 elseif ly == liveErr.line then
  3243.                     term.setBackgroundColor(colors[theme.editorError])
  3244.                 end
  3245.                 term.clearLine()
  3246.  
  3247.                 term.setCursorPos(1 - scrollx + offx, (ly - scrolly) + offy)
  3248.                 if ly == y then
  3249.                     if ly == liveErr.line and os.clock() - lastEventClock > 3 then
  3250.                         term.setBackgroundColor(colors[theme.editorErrorHighlight])
  3251.                     else term.setBackgroundColor(colors[theme.editorLineHightlight]) end
  3252.                 elseif ly == liveErr.line then term.setBackgroundColor(colors[theme.editorError])
  3253.                 else term.setBackgroundColor(colors[theme.editorBackground]) end
  3254.                 if ly == liveErr.line then
  3255.                     if displayCode then term.write(a)
  3256.                     else term.write(liveErr.display) end
  3257.                 else writeHighlighted(a) end
  3258.  
  3259.                 term.setCursorPos(1, (ly - scrolly) + offy)
  3260.                 if ly == y then
  3261.                     if ly == liveErr.line and os.clock() - lastEventClock > 3 then
  3262.                         term.setBackgroundColor(colors[theme.editorError])
  3263.                     else term.setBackgroundColor(colors[theme.editorLineNumbersHighlight]) end
  3264.                 elseif ly == liveErr.line then
  3265.                     term.setBackgroundColor(colors[theme.editorErrorHighlight])
  3266.                 else term.setBackgroundColor(colors[theme.editorLineNumbers]) end
  3267.                 term.write(ln)
  3268.             end
  3269.         end
  3270.         term.setCursorPos(x - scrollx + offx, y - scrolly + offy)
  3271.     end
  3272.  
  3273.     local function cursorLoc(x, y, force)
  3274.         local sx, sy = x - scrollx, y - scrolly
  3275.         local redraw = false
  3276.         if sx < 1 then
  3277.             scrollx = x - 1
  3278.             sx = 1
  3279.             redraw = true
  3280.         elseif sx > edw then
  3281.             scrollx = x - edw
  3282.             sx = edw
  3283.             redraw = true
  3284.         end if sy < 1 then
  3285.             scrolly = y - 1
  3286.             sy = 1
  3287.             redraw = true
  3288.         elseif sy > edh then
  3289.             scrolly = y - edh
  3290.             sy = edh
  3291.             redraw = true
  3292.         end if redraw or force then draw() end
  3293.         term.setCursorPos(sx + offx, sy + offy)
  3294.     end
  3295.  
  3296.     local function executeMenuItem(a, path)
  3297.         if type(a) == "string" and menuFunctions[a] then
  3298.             local opt, nl, gtln = menuFunctions[a](path, lines, y)
  3299.             if type(opt) == "string" then term.setCursorBlink(false) return opt end
  3300.             if type(nl) == "table" then
  3301.                 if #lines < 1 then table.insert(lines, "") end
  3302.                 y = math.min(y, #lines)
  3303.                 x = math.min(x, lines[y]:len() + 1)
  3304.                 lines = nl
  3305.             elseif type(nl) == "string" then
  3306.                 if nl == "go to" and gtln then
  3307.                     x, y = 1, math.min(#lines, gtln)
  3308.                     cursorLoc(x, y)
  3309.                 end
  3310.             end
  3311.         end
  3312.         term.setCursorBlink(true)
  3313.         draw()
  3314.         term.setCursorPos(x - scrollx + offx, y - scrolly + offy)
  3315.     end
  3316.  
  3317.     local function edit(path)
  3318.         -- Variables
  3319.         x, y = 1, 1
  3320.         offx, offy = 0, 1
  3321.         scrollx, scrolly = 0, 0
  3322.         lines = loadFile(path)
  3323.         if not lines then return "menu" end
  3324.  
  3325.         -- Enable brainfuck
  3326.         if lines[1] == "-- Syntax: Brainfuck" then
  3327.             curLanguage = languages.brainfuck
  3328.         end
  3329.  
  3330.         -- Clocks
  3331.         local autosaveClock = os.clock()
  3332.         local scrollClock = os.clock() -- To prevent redraw flicker
  3333.         local liveErrorClock = os.clock()
  3334.         local hasScrolled = false
  3335.  
  3336.         -- Draw
  3337.         draw()
  3338.         term.setCursorPos(x + offx, y + offy)
  3339.         term.setCursorBlink(true)
  3340.        
  3341.         -- Main loop
  3342.         local tid = os.startTimer(3)
  3343.         while true do
  3344.             local e, key, cx, cy = os.pullEvent()
  3345.             if e == "key" and allowEditorEvent then
  3346.                 if key == 200 and y > 1 then
  3347.                     -- Up
  3348.                     x, y = math.min(x, lines[y - 1]:len() + 1), y - 1
  3349.                     drawLine(y, y + 1)
  3350.                     cursorLoc(x, y)
  3351.                 elseif key == 208 and y < #lines then
  3352.                     -- Down
  3353.                     x, y = math.min(x, lines[y + 1]:len() + 1), y + 1
  3354.                     drawLine(y, y - 1)
  3355.                     cursorLoc(x, y)
  3356.                 elseif key == 203 and x > 1 then
  3357.                     -- Left
  3358.                     x = x - 1
  3359.                     local force = false
  3360.                     if y - scrolly + offy < offy + 1 then force = true end
  3361.                     cursorLoc(x, y, force)
  3362.                 elseif key == 205 and x < lines[y]:len() + 1 then
  3363.                     -- Right
  3364.                     x = x + 1
  3365.                     local force = false
  3366.                     if y - scrolly + offy < offy + 1 then force = true end
  3367.                     cursorLoc(x, y, force)
  3368.                 elseif (key == 28 or key == 156) and (displayCode and true or y + scrolly - 1 ==
  3369.                         liveErr.line) then
  3370.                     -- Enter
  3371.                     local f = nil
  3372.                     for _, v in pairs(standardsCompletions) do
  3373.                         if lines[y]:find(v) then f = v end
  3374.                     end
  3375.  
  3376.                     local _, spaces = lines[y]:find("^[ ]+")
  3377.                     if not spaces then spaces = 0 end
  3378.                     if f then
  3379.                         table.insert(lines, y + 1, string.rep(" ", spaces + 2))
  3380.                         if not f:find("else", 1, true) and not f:find("elseif", 1, true) then
  3381.                             table.insert(lines, y + 2, string.rep(" ", spaces) ..
  3382.                                 (f:find("repeat", 1, true) and "until " or f:find("{", 1, true) and "}" or
  3383.                                 "end"))
  3384.                         end
  3385.                         x, y = spaces + 3, y + 1
  3386.                         cursorLoc(x, y, true)
  3387.                     else
  3388.                         local oldLine = lines[y]
  3389.  
  3390.                         lines[y] = lines[y]:sub(1, x - 1)
  3391.                         table.insert(lines, y + 1, string.rep(" ", spaces) .. oldLine:sub(x, -1))
  3392.  
  3393.                         x, y = spaces + 1, y + 1
  3394.                         cursorLoc(x, y, true)
  3395.                     end
  3396.                 elseif key == 14 and (displayCode and true or y + scrolly - 1 == liveErr.line) then
  3397.                     -- Backspace
  3398.                     if x > 1 then
  3399.                         local f = false
  3400.                         for k, v in pairs(liveCompletions) do
  3401.                             if lines[y]:sub(x - 1, x - 1) == k then f = true end
  3402.                         end
  3403.  
  3404.                         lines[y] = lines[y]:sub(1, x - 2) .. lines[y]:sub(x + (f and 1 or 0), -1)
  3405.                         drawLine(y)
  3406.                         x = x - 1
  3407.                         cursorLoc(x, y)
  3408.                     elseif y > 1 then
  3409.                         local prevLen = lines[y - 1]:len() + 1
  3410.                         lines[y - 1] = lines[y - 1] .. lines[y]
  3411.                         table.remove(lines, y)
  3412.                         x, y = prevLen, y - 1
  3413.                         cursorLoc(x, y, true)
  3414.                     end
  3415.                 elseif key == 199 then
  3416.                     -- Home
  3417.                     x = 1
  3418.                     local force = false
  3419.                     if y - scrolly + offy < offy + 1 then force = true end
  3420.                     cursorLoc(x, y, force)
  3421.                 elseif key == 207 then
  3422.                     -- End
  3423.                     x = lines[y]:len() + 1
  3424.                     local force = false
  3425.                     if y - scrolly + offy < offy + 1 then force = true end
  3426.                     cursorLoc(x, y, force)
  3427.                 elseif key == 211 and (displayCode and true or y + scrolly - 1 == liveErr.line) then
  3428.                     -- Forward Delete
  3429.                     if x < lines[y]:len() + 1 then
  3430.                         lines[y] = lines[y]:sub(1, x - 1) .. lines[y]:sub(x + 1)
  3431.                         local force = false
  3432.                         if y - scrolly + offy < offy + 1 then force = true end
  3433.                         drawLine(y)
  3434.                         cursorLoc(x, y, force)
  3435.                     elseif y < #lines then
  3436.                         lines[y] = lines[y] .. lines[y + 1]
  3437.                         table.remove(lines, y + 1)
  3438.                         draw()
  3439.                         cursorLoc(x, y)
  3440.                     end
  3441.                 elseif key == 15 and (displayCode and true or y + scrolly - 1 == liveErr.line) then
  3442.                     -- Tab
  3443.                     lines[y] = string.rep(" ", tabWidth) .. lines[y]
  3444.                     x = x + 2
  3445.                     local force = false
  3446.                     if y - scrolly + offy < offy + 1 then force = true end
  3447.                     drawLine(y)
  3448.                     cursorLoc(x, y, force)
  3449.                 elseif key == 201 then
  3450.                     -- Page up
  3451.                     y = math.min(math.max(y - edh, 1), #lines)
  3452.                     x = math.min(lines[y]:len() + 1, x)
  3453.                     cursorLoc(x, y, true)
  3454.                 elseif key == 209 then
  3455.                     -- Page down
  3456.                     y = math.min(math.max(y + edh, 1), #lines)
  3457.                     x = math.min(lines[y]:len() + 1, x)
  3458.                     cursorLoc(x, y, true)
  3459.                 end
  3460.             elseif e == "char" and allowEditorEvent and (displayCode and true or
  3461.                     y + scrolly - 1 == liveErr.line) then
  3462.                 local shouldIgnore = false
  3463.                 for k, v in pairs(liveCompletions) do
  3464.                     if key == v and lines[y]:find(k, 1, true) and lines[y]:sub(x, x) == v then
  3465.                         shouldIgnore = true
  3466.                     end
  3467.                 end
  3468.  
  3469.                 local addOne = false
  3470.                 if not shouldIgnore then
  3471.                     for k, v in pairs(liveCompletions) do
  3472.                         if key == k and lines[y]:sub(x, x) ~= k then key = key .. v addOne = true end
  3473.                     end
  3474.                     lines[y] = lines[y]:sub(1, x - 1) .. key .. lines[y]:sub(x, -1)
  3475.                 end
  3476.  
  3477.                 x = x + (addOne and 1 or key:len())
  3478.                 local force = false
  3479.                 if y - scrolly + offy < offy + 1 then force = true end
  3480.                 drawLine(y)
  3481.                 cursorLoc(x, y, force)
  3482.             elseif e == "mouse_click" and key == 1 then
  3483.                 if cy > 1 then
  3484.                     if cx <= offx and cy - offy == liveErr.line - scrolly then
  3485.                         displayCode = not displayCode
  3486.                         drawLine(liveErr.line)
  3487.                     else
  3488.                         local oldy = y
  3489.                         y = math.min(math.max(scrolly + cy - offy, 1), #lines)
  3490.                         x = math.min(math.max(scrollx + cx - offx, 1), lines[y]:len() + 1)
  3491.                         if oldy ~= y then drawLine(oldy, y) end
  3492.                         cursorLoc(x, y)
  3493.                     end
  3494.                 else
  3495.                     local a = triggerMenu(cx, cy)
  3496.                     if a then
  3497.                         local opt = executeMenuItem(a, path)
  3498.                         if opt then return opt end
  3499.                     end
  3500.                 end
  3501.             elseif e == "shortcut" then
  3502.                 local a = shortcuts[key .. " " .. cx]
  3503.                 if a then
  3504.                     local parent = nil
  3505.                     local curx = 0
  3506.                     for i, mv in ipairs(menu) do
  3507.                         for _, iv in pairs(mv) do
  3508.                             if iv == a then
  3509.                                 parent = menu[i][1]
  3510.                                 break
  3511.                             end
  3512.                         end
  3513.                         if parent then break end
  3514.                         curx = curx + mv[1]:len() + 3
  3515.                     end
  3516.                     local menux = curx + 2
  3517.  
  3518.                     -- Flash menu item
  3519.                     term.setCursorBlink(false)
  3520.                     term.setCursorPos(menux, 1)
  3521.                     term.setBackgroundColor(colors[theme.background])
  3522.                     term.write(string.rep(" ", parent:len() + 2))
  3523.                     term.setCursorPos(menux + 1, 1)
  3524.                     term.write(parent)
  3525.                     sleep(0.1)
  3526.                     drawMenu()
  3527.  
  3528.                     -- Execute item
  3529.                     local opt = executeMenuItem(a, path)
  3530.                     if opt then return opt end
  3531.                 end
  3532.             elseif e == "mouse_scroll" then
  3533.                 if key == -1 and scrolly > 0 then
  3534.                     scrolly = scrolly - 1
  3535.                     if os.clock() - scrollClock > 0.0005 then
  3536.                         draw()
  3537.                         term.setCursorPos(x - scrollx + offx, y - scrolly + offy)
  3538.                     end
  3539.                     scrollClock = os.clock()
  3540.                     hasScrolled = true
  3541.                 elseif key == 1 and scrolly < #lines - edh then
  3542.                     scrolly = scrolly + 1
  3543.                     if os.clock() - scrollClock > 0.0005 then
  3544.                         draw()
  3545.                         term.setCursorPos(x - scrollx + offx, y - scrolly + offy)
  3546.                     end
  3547.                     scrollClock = os.clock()
  3548.                     hasScrolled = true
  3549.                 end
  3550.             elseif e == "timer" and key == tid then
  3551.                 drawLine(y)
  3552.                 tid = os.startTimer(3)
  3553.             end
  3554.  
  3555.             -- Draw
  3556.             if hasScrolled and os.clock() - scrollClock > 0.1 then
  3557.                 draw()
  3558.                 term.setCursorPos(x - scrollx + offx, y - scrolly + offy)
  3559.                 hasScrolled = false
  3560.             end
  3561.  
  3562.             -- Autosave
  3563.             if os.clock() - autosaveClock > autosaveInterval then
  3564.                 saveFile(path, lines)
  3565.                 autosaveClock = os.clock()
  3566.             end
  3567.  
  3568.             -- Errors
  3569.             if os.clock() - liveErrorClock > 1 then
  3570.                 local prevLiveErr = liveErr
  3571.                 liveErr = curLanguage.parseError(nil)
  3572.                 local code = ""
  3573.                 for _, v in pairs(lines) do code = code .. v .. "\n" end
  3574.  
  3575.                 liveErr = curLanguage.getCompilerErrors(code)
  3576.                 liveErr.line = math.min(liveErr.line - 2, #lines)
  3577.                 if liveErr ~= prevLiveErr then draw() end
  3578.                 liveErrorClock = os.clock()
  3579.             end
  3580.         end
  3581.  
  3582.         return "menu"
  3583.     end
  3584.  
  3585.  
  3586.     --  -------- Open File
  3587.  
  3588.     local function newFile()
  3589.         local wid = w - 13
  3590.  
  3591.         -- Get name
  3592.         title("Lua IDE - New File")
  3593.         local name = centerRead(wid, "/")
  3594.         if not name or name == "" then return "menu" end
  3595.         name = "/" .. name
  3596.  
  3597.         -- Clear
  3598.         title("Lua IDE - New File")
  3599.         term.setTextColor(colors[theme.textColor])
  3600.         term.setBackgroundColor(colors[theme.promptHighlight])
  3601.         for i = 8, 10 do
  3602.             term.setCursorPos(w/2 - wid/2, i)
  3603.             term.write(string.rep(" ", wid))
  3604.         end
  3605.         term.setCursorPos(1, 9)
  3606.         if fs.isDir(name) then
  3607.             centerPrint("Cannot Edit a Directory!")
  3608.             sleep(1.6)
  3609.             return "menu"
  3610.         elseif fs.exists(name) then
  3611.             centerPrint("File Already Exists!")
  3612.             local opt = prompt({{"Open", w/2 - 9, 14}, {"Cancel", w/2 + 2, 14}}, "horizontal")
  3613.             if opt == "Open" then return "edit", name
  3614.             elseif opt == "Cancel" then return "menu" end
  3615.         else return "edit", name end
  3616.     end
  3617.  
  3618.     local function openFile()
  3619.         local wid = w - 13
  3620.  
  3621.         -- Get name
  3622.         title("Lua IDE - Open File")
  3623.         local name = centerRead(wid, "/")
  3624.         if not name or name == "" then return "menu" end
  3625.         name = "/" .. name
  3626.  
  3627.         -- Clear
  3628.         title("Lua IDE - New File")
  3629.         term.setTextColor(colors[theme.textColor])
  3630.         term.setBackgroundColor(colors[theme.promptHighlight])
  3631.         for i = 8, 10 do
  3632.             term.setCursorPos(w/2 - wid/2, i)
  3633.             term.write(string.rep(" ", wid))
  3634.         end
  3635.         term.setCursorPos(1, 9)
  3636.         if fs.isDir(name) then
  3637.             centerPrint("Cannot Open a Directory!")
  3638.             sleep(1.6)
  3639.             return "menu"
  3640.         elseif not fs.exists(name) then
  3641.             centerPrint("File Doesn't Exist!")
  3642.             local opt = prompt({{"Create", w/2 - 11, 14}, {"Cancel", w/2 + 2, 14}}, "horizontal")
  3643.             if opt == "Create" then return "edit", name
  3644.             elseif opt == "Cancel" then return "menu" end
  3645.         else return "edit", name end
  3646.     end
  3647.  
  3648.  
  3649.     --  -------- Settings
  3650.  
  3651.     local function update()
  3652.         local function draw(status)
  3653.             title("LuaIDE - Update")
  3654.             term.setBackgroundColor(colors[theme.prompt])
  3655.             term.setTextColor(colors[theme.textColor])
  3656.             for i = 8, 10 do
  3657.                 term.setCursorPos(w/2 - (status:len() + 4), i)
  3658.                 write(string.rep(" ", status:len() + 4))
  3659.             end
  3660.             term.setCursorPos(w/2 - (status:len() + 4), 9)
  3661.             term.write(" - " .. status .. " ")
  3662.  
  3663.             term.setBackgroundColor(colors[theme.errHighlight])
  3664.             for i = 8, 10 do
  3665.                 term.setCursorPos(w/2 + 2, i)
  3666.                 term.write(string.rep(" ", 10))
  3667.             end
  3668.             term.setCursorPos(w/2 + 2, 9)
  3669.             term.write(" > Cancel ")
  3670.         end
  3671.  
  3672.         if not http then
  3673.             draw("HTTP API Disabled!")
  3674.             sleep(1.6)
  3675.             return "settings"
  3676.         end
  3677.  
  3678.         draw("Updating...")
  3679.         local tID = os.startTimer(10)
  3680.         http.request(updateURL)
  3681.         while true do
  3682.             local e, but, x, y = os.pullEvent()
  3683.             if (e == "key" and but == 28) or
  3684.                     (e == "mouse_click" and x >= w/2 + 2 and x <= w/2 + 12 and y == 9) then
  3685.                 draw("Cancelled")
  3686.                 sleep(1.6)
  3687.                 break
  3688.             elseif e == "http_success" and but == updateURL then
  3689.                 local new = x.readAll()
  3690.                 local curf = io.open(ideLocation, "r")
  3691.                 local cur = curf:read("*a")
  3692.                 curf:close()
  3693.  
  3694.                 if cur ~= new then
  3695.                     draw("Update Found")
  3696.                     sleep(1.6)
  3697.                     local f = io.open(ideLocation, "w")
  3698.                     f:write(new)
  3699.                     f:close()
  3700.  
  3701.                     draw("Click to Exit")
  3702.                     while true do
  3703.                         local e = os.pullEvent()
  3704.                         if e == "mouse_click" or (not isAdvanced() and e == "key") then break end
  3705.                     end
  3706.                     return "exit"
  3707.                 else
  3708.                     draw("No Updates Found!")
  3709.                     sleep(1.6)
  3710.                     break
  3711.                 end
  3712.             elseif e == "http_failure" or (e == "timer" and but == tID) then
  3713.                 draw("Update Failed!")
  3714.                 sleep(1.6)
  3715.                 break
  3716.             end
  3717.         end
  3718.  
  3719.         return "settings"
  3720.     end
  3721.  
  3722.     local function changeTheme()
  3723.         title("LuaIDE - Theme")
  3724.  
  3725.         if isAdvanced() then
  3726.             local disThemes = {"Back"}
  3727.             for _, v in pairs(availableThemes) do table.insert(disThemes, v[1]) end
  3728.             local t = scrollingPrompt(disThemes)
  3729.             local url = nil
  3730.             for _, v in pairs(availableThemes) do if v[1] == t then url = v[2] end end
  3731.  
  3732.             if not url then return "settings" end
  3733.             if t == "Dawn (Default)" then
  3734.                 term.setBackgroundColor(colors[theme.backgroundHighlight])
  3735.                 term.setCursorPos(3, 3)
  3736.                 term.clearLine()
  3737.                 term.write("LuaIDE - Loaded Theme!")
  3738.                 sleep(1.6)
  3739.  
  3740.                 fs.delete(themeLocation)
  3741.                 theme = defaultTheme
  3742.                 return "menu"
  3743.             end
  3744.  
  3745.             term.setBackgroundColor(colors[theme.backgroundHighlight])
  3746.             term.setCursorPos(3, 3)
  3747.             term.clearLine()
  3748.             term.write("LuaIDE - Downloading...")
  3749.  
  3750.             fs.delete("/.LuaIDE_temp_theme_file")
  3751.             download(url, "/.LuaIDE_temp_theme_file")
  3752.             local a = loadTheme("/.LuaIDE_temp_theme_file")
  3753.  
  3754.             term.setCursorPos(3, 3)
  3755.             term.clearLine()
  3756.             if a then
  3757.                 term.write("LuaIDE - Loaded Theme!")
  3758.                 fs.delete(themeLocation)
  3759.                 fs.move("/.LuaIDE_temp_theme_file", themeLocation)
  3760.                 theme = a
  3761.                 sleep(1.6)
  3762.                 return "menu"
  3763.             end
  3764.            
  3765.             term.write("LuaIDE - Could Not Load Theme!")
  3766.             fs.delete("/.LuaIDE_temp_theme_file")
  3767.             sleep(1.6)
  3768.             return "settings"
  3769.         else
  3770.             term.setCursorPos(1, 8)
  3771.             centerPrint("Themes are not available on")
  3772.             centerPrint("normal computers!")
  3773.         end
  3774.     end
  3775.  
  3776.     local function settings()
  3777.         title("LuaIDE - Settings")
  3778.  
  3779.         local opt = prompt({{"Change Theme", w/2 - 17, 8}, {"Return to Menu", w/2 - 22, 13},
  3780.             {"Check for Updates", w/2 + 2, 8}, {"Exit IDE", w/2 + 2, 13, bg = colors[theme.err],
  3781.             highlight = colors[theme.errHighlight]}}, "vertical", true)
  3782.         if opt == "Change Theme" then return changeTheme()
  3783.         elseif opt == "Check for Updates" then return update()
  3784.         elseif opt == "Return to Menu" then return "menu"
  3785.         elseif opt == "Exit IDE" then return "exit" end
  3786.     end
  3787.  
  3788.  
  3789.     --  -------- Menu
  3790.  
  3791.     local function menu()
  3792.         title("Welcome to LuaIDE " .. version)
  3793.  
  3794.         local opt = prompt({{"New File", w/2 - 13, 8}, {"Open File", w/2 - 14, 13},
  3795.             {"Settings", w/2 + 2, 8}, {"Exit IDE", w/2 + 2, 13, bg = colors[theme.err],
  3796.             highlight = colors[theme.errHighlight]}}, "vertical", true)
  3797.         if opt == "New File" then return "new"
  3798.         elseif opt == "Open File" then return "open"
  3799.         elseif opt == "Settings" then return "settings"
  3800.         elseif opt == "Exit IDE" then return "exit" end
  3801.     end
  3802.  
  3803.  
  3804.     --  -------- Main
  3805.  
  3806.     local function main(arguments)
  3807.         local opt, data = "menu", nil
  3808.  
  3809.         -- Check arguments
  3810.         if type(arguments) == "table" and #arguments > 0 then
  3811.             local f = "/" .. shell.resolve(arguments[1])
  3812.             if fs.isDir(f) then print("Cannot edit a directory.") end
  3813.             opt, data = "edit", f
  3814.         end
  3815.  
  3816.         -- Main run loop
  3817.         while true do
  3818.             -- Menu
  3819.             if opt == "menu" then opt = menu() end
  3820.  
  3821.             -- Other
  3822.             if opt == "new" then opt, data = newFile()
  3823.             elseif opt == "open" then opt, data = openFile()
  3824.             elseif opt == "settings" then opt = settings()
  3825.             end if opt == "exit" then break end
  3826.  
  3827.             -- Edit
  3828.             if opt == "edit" and data then opt = edit(data) end
  3829.         end
  3830.     end
  3831.  
  3832.     -- Load Theme
  3833.     if fs.exists(themeLocation) then theme = loadTheme(themeLocation) end
  3834.     if not theme and isAdvanced() then theme = defaultTheme
  3835.     elseif not theme then theme = normalTheme end
  3836.  
  3837.     -- Run
  3838.     local _, err = pcall(function()
  3839.         parallel.waitForAny(function() main(args) end, monitorKeyboardShortcuts)
  3840.     end)
  3841.  
  3842.     -- Catch errors
  3843.     if err and not err:find("Terminated") then
  3844.         term.setCursorBlink(false)
  3845.         title("LuaIDE - Crash! D:")
  3846.  
  3847.         term.setBackgroundColor(colors[theme.err])
  3848.         for i = 6, 8 do
  3849.             term.setCursorPos(5, i)
  3850.             term.write(string.rep(" ", 36))
  3851.         end
  3852.         term.setCursorPos(6, 7)
  3853.         term.write("LuaIDE Has Crashed! D:")
  3854.  
  3855.         term.setBackgroundColor(colors[theme.background])
  3856.         term.setCursorPos(2, 10)
  3857.         print(err)
  3858.  
  3859.         term.setBackgroundColor(colors[theme.prompt])
  3860.         local _, cy = term.getCursorPos()
  3861.         for i = cy + 1, cy + 4 do
  3862.             term.setCursorPos(5, i)
  3863.             term.write(string.rep(" ", 36))
  3864.         end
  3865.         term.setCursorPos(6, cy + 2)
  3866.         term.write("Please report this error to")
  3867.         term.setCursorPos(6, cy + 3)
  3868.         term.write("GravityScore! ")
  3869.        
  3870.         term.setBackgroundColor(colors[theme.background])
  3871.         if isAdvanced() then centerPrint("Click to Exit...", h - 1)
  3872.         else centerPrint("Press Any Key to Exit...", h - 1) end
  3873.         while true do
  3874.             local e = os.pullEvent()
  3875.             if e == "mouse_click" or (not isAdvanced() and e == "key") then break end
  3876.         end
  3877.  
  3878.         -- Prevent key from being shown
  3879.         os.queueEvent(event_distract)
  3880.         os.pullEvent()
  3881.     end
  3882.  
  3883.     -- Exit
  3884.     term.setBackgroundColor(colors.black)
  3885.     term.setTextColor(colors.white)
  3886.     term.clear()
  3887.     term.setCursorPos(1, 1)
  3888.     centerPrint("Thank You for Using Lua IDE " .. version)
  3889.     centerPrint("Made by GravityScore")
  3890.     sleep(1)
  3891. end
  3892.  
  3893. function oeed_sketch()
  3894.     if OneOS then
  3895.         --running under OneOS
  3896.         OneOS.ToolBarColour = colours.grey
  3897.         OneOS.ToolBarTextColour = colours.white
  3898.     end
  3899.  
  3900.     colours.transparent = -1
  3901.     colors.transparent = -1
  3902.  
  3903.     --APIS--
  3904.  
  3905.     --This is my drawing API, is is pretty much identical to what drives OneOS, PearOS, etc.
  3906.     local _w, _h = term.getSize()
  3907.  
  3908.     local round = function(num, idp)
  3909.         local mult = 10^(idp or 0)
  3910.         return math.floor(num * mult + 0.5) / mult
  3911.     end
  3912.  
  3913.     Clipboard = {
  3914.         Content = nil,
  3915.         Type = nil,
  3916.         IsCut = false,
  3917.  
  3918.         Empty = function()
  3919.             Clipboard.Content = nil
  3920.             Clipboard.Type = nil
  3921.             Clipboard.IsCut = false
  3922.         end,
  3923.  
  3924.         isEmpty = function()
  3925.             return Clipboard.Content == nil
  3926.         end,
  3927.  
  3928.         Copy = function(content, _type)
  3929.             Clipboard.Content = content
  3930.             Clipboard.Type = _type or 'generic'
  3931.             Clipboard.IsCut = false
  3932.         end,
  3933.  
  3934.         Cut = function(content, _type)
  3935.             Clipboard.Content = content
  3936.             Clipboard.Type = _type or 'generic'
  3937.             Clipboard.IsCut = true
  3938.         end,
  3939.  
  3940.         Paste = function()
  3941.             local c, t = Clipboard.Content, Clipboard.Type
  3942.             if Clipboard.IsCut then
  3943.                 Clipboard.Empty()
  3944.             end
  3945.             return c, t
  3946.         end
  3947.     }
  3948.  
  3949.     if OneOS and OneOS.Clipboard then
  3950.         Clipboard = OneOS.Clipboard
  3951.     end
  3952.  
  3953.     Drawing = {
  3954.        
  3955.         Screen = {
  3956.             Width = _w,
  3957.             Height = _h
  3958.         },
  3959.  
  3960.         DrawCharacters = function (x, y, characters, textColour,bgColour)
  3961.             Drawing.WriteStringToBuffer(x, y, characters, textColour, bgColour)
  3962.         end,
  3963.        
  3964.         DrawBlankArea = function (x, y, w, h, colour)
  3965.             Drawing.DrawArea (x, y, w, h, " ", 1, colour)
  3966.         end,
  3967.  
  3968.         DrawArea = function (x, y, w, h, character, textColour, bgColour)
  3969.             --width must be greater than 1, other wise we get a stack overflow
  3970.             if w < 0 then
  3971.                 w = w * -1
  3972.             elseif w == 0 then
  3973.                 w = 1
  3974.             end
  3975.  
  3976.             for ix = 1, w do
  3977.                 local currX = x + ix - 1
  3978.                 for iy = 1, h do
  3979.                     local currY = y + iy - 1
  3980.                     Drawing.WriteToBuffer(currX, currY, character, textColour, bgColour)
  3981.                 end
  3982.             end
  3983.         end,
  3984.  
  3985.         DrawImage = function(_x,_y,tImage, w, h)
  3986.             if tImage then
  3987.                 for y = 1, h do
  3988.                     if not tImage[y] then
  3989.                         break
  3990.                     end
  3991.                     for x = 1, w do
  3992.                         if not tImage[y][x] then
  3993.                             break
  3994.                         end
  3995.                         local bgColour = tImage[y][x]
  3996.                         local textColour = tImage.textcol[y][x] or colours.white
  3997.                         local char = tImage.text[y][x]
  3998.                         Drawing.WriteToBuffer(x+_x-1, y+_y-1, char, textColour, bgColour)
  3999.                     end
  4000.                 end
  4001.             elseif w and h then
  4002.                 Drawing.DrawBlankArea(x, y, w, h, colours.green)
  4003.             end
  4004.         end,
  4005.         --using .nft
  4006.         LoadImage = function(path)
  4007.             local image = {
  4008.                 text = {},
  4009.                 textcol = {}
  4010.             }
  4011.             local _fs = fs
  4012.             if OneOS then
  4013.                 _fs = OneOS.FS
  4014.             end
  4015.             if _fs.exists(path) then
  4016.                 local _open = io.open
  4017.                 if OneOS then
  4018.                     _open = OneOS.IO.open
  4019.                 end
  4020.                 local file = _open(path, "r")
  4021.                 local sLine = file:read()
  4022.                 local num = 1
  4023.                 while sLine do  
  4024.                         table.insert(image, num, {})
  4025.                         table.insert(image.text, num, {})
  4026.                         table.insert(image.textcol, num, {})
  4027.                                                    
  4028.                         --As we're no longer 1-1, we keep track of what index to write to
  4029.                         local writeIndex = 1
  4030.                         --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour
  4031.                         local bgNext, fgNext = false, false
  4032.                         --The current background and foreground colours
  4033.                         local currBG, currFG = nil,nil
  4034.                         for i=1,#sLine do
  4035.                                 local nextChar = string.sub(sLine, i, i)
  4036.                                 if nextChar:byte() == 30 then
  4037.                                     bgNext = true
  4038.                                 elseif nextChar:byte() == 31 then
  4039.                                     fgNext = true
  4040.                                 elseif bgNext then
  4041.                                     currBG = Drawing.GetColour(nextChar)
  4042.                                     bgNext = false
  4043.                                 elseif fgNext then
  4044.                                     currFG = Drawing.GetColour(nextChar)
  4045.                                     fgNext = false
  4046.                                 else
  4047.                                     if nextChar ~= " " and currFG == nil then
  4048.                                            currFG = colours.white
  4049.                                     end
  4050.                                     image[num][writeIndex] = currBG
  4051.                                     image.textcol[num][writeIndex] = currFG
  4052.                                     image.text[num][writeIndex] = nextChar
  4053.                                     writeIndex = writeIndex + 1
  4054.                                 end
  4055.                         end
  4056.                         num = num+1
  4057.                         sLine = file:read()
  4058.                 end
  4059.                 file:close()
  4060.             end
  4061.             return image
  4062.         end,
  4063.  
  4064.         DrawCharactersCenter = function(x, y, w, h, characters, textColour,bgColour)
  4065.             w = w or Drawing.Screen.Width
  4066.             h = h or Drawing.Screen.Height
  4067.             x = x or 0
  4068.             y = y or 0
  4069.             x = math.ceil((w - #characters) / 2) + x
  4070.             y = math.floor(h / 2) + y
  4071.  
  4072.             Drawing.DrawCharacters(x, y, characters, textColour, bgColour)
  4073.         end,
  4074.  
  4075.         GetColour = function(hex)
  4076.             if hex == ' ' then
  4077.                 return colours.transparent
  4078.             end
  4079.             local value = tonumber(hex, 16)
  4080.             if not value then return nil end
  4081.             value = math.pow(2,value)
  4082.             return value
  4083.         end,
  4084.  
  4085.         Clear = function (_colour)
  4086.             _colour = _colour or colours.black
  4087.             Drawing.ClearBuffer()
  4088.             Drawing.DrawBlankArea(1, 1, Drawing.Screen.Width, Drawing.Screen.Height, _colour)
  4089.         end,
  4090.  
  4091.         Buffer = {},
  4092.         BackBuffer = {},
  4093.  
  4094.         DrawBuffer = function()
  4095.             for y,row in pairs(Drawing.Buffer) do
  4096.                 for x,pixel in pairs(row) do
  4097.                     local shouldDraw = true
  4098.                     local hasBackBuffer = true
  4099.                     if Drawing.BackBuffer[y] == nil or Drawing.BackBuffer[y][x] == nil or #Drawing.BackBuffer[y][x] ~= 3 then
  4100.                         hasBackBuffer = false
  4101.                     end
  4102.                     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
  4103.                         shouldDraw = false
  4104.                     end
  4105.                     if shouldDraw then
  4106.                         term.setBackgroundColour(pixel[3])
  4107.                         term.setTextColour(pixel[2])
  4108.                         term.setCursorPos(x, y)
  4109.                         term.write(pixel[1])
  4110.                     end
  4111.                 end
  4112.             end
  4113.             Drawing.BackBuffer = Drawing.Buffer
  4114.             Drawing.Buffer = {}
  4115.             term.setCursorPos(1,1)
  4116.         end,
  4117.  
  4118.         ClearBuffer = function()
  4119.             Drawing.Buffer = {}
  4120.         end,
  4121.  
  4122.         WriteStringToBuffer = function (x, y, characters, textColour,bgColour)
  4123.             for i = 1, #characters do
  4124.                 local character = characters:sub(i,i)
  4125.                 Drawing.WriteToBuffer(x + i - 1, y, character, textColour, bgColour)
  4126.             end
  4127.         end,
  4128.  
  4129.         WriteToBuffer = function(x, y, character, textColour,bgColour)
  4130.             x = round(x)
  4131.             y = round(y)
  4132.             if bgColour == colours.transparent then
  4133.                 Drawing.Buffer[y] = Drawing.Buffer[y] or {}
  4134.                 Drawing.Buffer[y][x] = Drawing.Buffer[y][x] or {"", colours.white, colours.black}
  4135.                 Drawing.Buffer[y][x][1] = character
  4136.                 Drawing.Buffer[y][x][2] = textColour
  4137.             else
  4138.                 Drawing.Buffer[y] = Drawing.Buffer[y] or {}
  4139.                 Drawing.Buffer[y][x] = {character, textColour, bgColour}
  4140.             end
  4141.         end,
  4142.     }
  4143.  
  4144.     --Colour Deffitions--
  4145.     UIColours = {
  4146.         Toolbar = colours.grey,
  4147.         ToolbarText = colours.lightGrey,
  4148.         ToolbarSelected = colours.lightBlue,
  4149.         ControlText = colours.white,
  4150.         ToolbarItemTitle = colours.black,
  4151.         Background = colours.lightGrey,
  4152.         MenuBackground = colours.white,
  4153.         MenuText = colours.black,
  4154.         MenuSeparatorText = colours.grey,
  4155.         MenuDisabledText = colours.lightGrey,
  4156.         Shadow = colours.grey,
  4157.         TransparentBackgroundOne = colours.white,
  4158.         TransparentBackgroundTwo = colours.lightGrey,
  4159.         MenuBarActive = colours.white
  4160.     }
  4161.  
  4162.     --Lists--
  4163.     Current = {
  4164.         Artboard = nil,
  4165.         Layer = nil,
  4166.         Tool = nil,
  4167.         ToolSize = 1,
  4168.         Toolbar = nil,
  4169.         Colour = colours.lightBlue,
  4170.         Menu = nil,
  4171.         MenuBar = nil,
  4172.         Window = nil,
  4173.         Input = nil,
  4174.         CursorPos = {1,1},
  4175.         CursorColour = colours.black,
  4176.         InterfaceVisible = true,
  4177.         Selection = {},
  4178.         SelectionDrawTimer = nil,
  4179.         HandDragStart = {},
  4180.         Modified = false,
  4181.     }
  4182.  
  4183.     local isQuitting = false
  4184.  
  4185.     function PrintCentered(text, y)
  4186.         local w, h = term.getSize()
  4187.         x = math.ceil(math.ceil((w / 2) - (#text / 2)), 0)+1
  4188.         term.setCursorPos(x, y)
  4189.         print(text)
  4190.     end
  4191.  
  4192.     function DoVanillaClose()
  4193.         term.setBackgroundColour(colours.black)
  4194.         term.setTextColour(colours.white)
  4195.         term.clear()
  4196.         term.setCursorPos(1, 1)
  4197.         PrintCentered("Thanks for using Sketch!", (Drawing.Screen.Height/2)-1)
  4198.         term.setTextColour(colours.lightGrey)
  4199.         PrintCentered("Photoshop Inspired Image Editor for ComputerCraft", (Drawing.Screen.Height/2))
  4200.         term.setTextColour(colours.white)
  4201.         PrintCentered("(c) oeed 2013 - 2014", (Drawing.Screen.Height/2)+3)
  4202.         term.setCursorPos(1, Drawing.Screen.Height)
  4203.         desktop()
  4204.     end
  4205.  
  4206.     function Close()
  4207.         if isQuitting or not Current.Artboard or not Current.Modified then
  4208.             if not OneOS then
  4209.                 DoVanillaClose()
  4210.             end
  4211.             return true
  4212.         else
  4213.             local _w = ButtonDialougeWindow:Initialise('Quit Sketch?', 'You have unsaved changes, do you want to quit anyway?', 'Quit', 'Cancel', function(window, success)
  4214.                 if success then
  4215.                     if OneOS then
  4216.                         OneOS.Close(true)
  4217.                     else
  4218.                         DoVanillaClose()
  4219.                     end
  4220.                 end
  4221.                 window:Close()
  4222.                 Draw()
  4223.             end):Show()
  4224.             --it's hacky but it works
  4225.             os.queueEvent('mouse_click', 1, _w.X, _w.Y)
  4226.             return false
  4227.         end
  4228.     end
  4229.  
  4230.     if OneOS then
  4231.         OneOS.CanClose = function()
  4232.             return Close()
  4233.         end
  4234.     end
  4235.  
  4236.     Lists = {
  4237.         Artboards = {},
  4238.         Interface = {
  4239.             Toolbars = {}
  4240.         }  
  4241.     }
  4242.  
  4243.     Events = {
  4244.        
  4245.     }
  4246.  
  4247.     --Setters--
  4248.  
  4249.     function SetColour(colour)
  4250.         Current.Colour = colour
  4251.         Draw()
  4252.     end
  4253.  
  4254.     function SetTool(tool)
  4255.         if tool and tool.Select and tool:Select() then
  4256.             Current.Input = nil
  4257.             Current.Tool = tool
  4258.             return true
  4259.         end
  4260.         return false
  4261.     end
  4262.  
  4263.     function GetAbsolutePosition(object)
  4264.         local obj = object
  4265.         local i = 0
  4266.         local x = 1
  4267.         local y = 1
  4268.         while true do
  4269.             x = x + obj.X - 1
  4270.             y = y + obj.Y - 1
  4271.  
  4272.             if not obj.Parent then
  4273.                 return {X = x, Y = y}
  4274.             end
  4275.  
  4276.             obj = obj.Parent
  4277.  
  4278.             if i > 32 then
  4279.                 return {X = 1, Y = 1}
  4280.             end
  4281.  
  4282.             i = i + 1
  4283.         end
  4284.  
  4285.     end
  4286.  
  4287.     --Object Defintions--
  4288.  
  4289.     Pixel = {
  4290.         TextColour = colours.black,
  4291.         BackgroundColour = colours.white,
  4292.         Character = " ",
  4293.         Layer = nil,
  4294.  
  4295.         Draw = function(self, x, y)
  4296.             if self.BackgroundColour ~= colours.transparent or self.Character ~= ' ' then
  4297.                 Drawing.WriteToBuffer(self.Layer.Artboard.X + x - 1, self.Layer.Artboard.Y + y - 1, self.Character, self.TextColour, self.BackgroundColour)
  4298.             end
  4299.         end,
  4300.  
  4301.         Initialise = function(self, textColour, backgroundColour, character, layer)
  4302.             local new = {}    -- the new instance
  4303.             setmetatable( new, {__index = self} )
  4304.             new.TextColour = textColour or self.TextColour
  4305.             new.BackgroundColour = backgroundColour or self.BackgroundColour
  4306.             new.Character = character or self.Character
  4307.             new.Layer = layer
  4308.             return new
  4309.         end,
  4310.  
  4311.         Set = function(self, textColour, backgroundColour, character)
  4312.             self.TextColour = textColour or self.TextColour
  4313.             self.BackgroundColour = backgroundColour or self.BackgroundColour
  4314.             self.Character = character or self.Character
  4315.         end
  4316.     }
  4317.  
  4318.     Layer = {
  4319.         Name = "",
  4320.         Pixels = {
  4321.  
  4322.         },
  4323.         Artboard = nil,
  4324.         BackgroundColour = colours.white,
  4325.         Visible = true,
  4326.         Index = 1,
  4327.  
  4328.         Draw = function(self)
  4329.             if self.Visible then
  4330.                 for x = 1, self.Artboard.Width do
  4331.                     for y = 1, self.Artboard.Height do
  4332.                         self.Pixels[x][y]:Draw(x, y)
  4333.                     end
  4334.                 end
  4335.             end
  4336.         end,
  4337.  
  4338.         Remove = function(self)
  4339.             for i, v in ipairs(self.Artboard.Layers) do
  4340.                 if v == Current.Layer then
  4341.                     Current.Artboard.Layers[i] = nil
  4342.                     Current.Layer = Current.Artboard.Layers[1]
  4343.                     ModuleNamed('Layers'):Update()
  4344.                 end
  4345.             end
  4346.         end,
  4347.  
  4348.         Initialise = function(self, name, backgroundColour, artboard, index, pixels)
  4349.             local new = {}    -- the new instance
  4350.             setmetatable( new, {__index = self} )
  4351.             new.Name = name
  4352.             new.Pixels = {}
  4353.             new.BackgroundColour = backgroundColour
  4354.             new.Artboard = artboard
  4355.             new.Index = index or #artboard.Layers + 1
  4356.             if not pixels then
  4357.                 new:MakeAllBlankPixels()
  4358.             else
  4359.                 new:MakeAllBlankPixels()
  4360.                 for x, col in ipairs(pixels) do
  4361.                     for y, pixel in ipairs(col) do
  4362.                         new:SetPixel(x, y, pixel.TextColour, pixel.BackgroundColour, pixel.Character)
  4363.                     end
  4364.                 end
  4365.             end
  4366.            
  4367.             return new
  4368.         end,
  4369.  
  4370.         SetPixel = function(self, x, y, textColour, backgroundColour, character)
  4371.             textColour = textColour or Current.Colour
  4372.             backgroundColour = backgroundColour or Current.Colour
  4373.             character = character or " "
  4374.  
  4375.             if x < 1 or y < 1 or x > self.Artboard.Width or y > self.Artboard.Height then
  4376.                 return
  4377.             end
  4378.  
  4379.             if self.Pixels[x][y] then
  4380.                 self.Pixels[x][y]:Set(textColour, backgroundColour, character)
  4381.                 self.Pixels[x][y]:Draw(x,y)
  4382.             end
  4383.         end,
  4384.  
  4385.         MakePixel = function(self, x, y, backgroundColour)
  4386.             backgroundColour = backgroundColour or self.BackgroundColour            
  4387.             self.Pixels[x][y] = Pixel:Initialise(nil, backgroundColour, nil, self)
  4388.         end,
  4389.  
  4390.         MakeColumn = function(self, x)
  4391.             self.Pixels[x] = {}
  4392.         end,
  4393.  
  4394.         MakeAllBlankPixels = function(self)
  4395.             for x = 1, self.Artboard.Width do
  4396.                 if not self.Pixels[x] then
  4397.                     self:MakeColumn(x)
  4398.                 end
  4399.  
  4400.                 for y = 1, self.Artboard.Height do          
  4401.                
  4402.                     if not self.Pixels[x][y] then
  4403.                         self:MakePixel(x, y)
  4404.                     end
  4405.  
  4406.                 end
  4407.             end
  4408.         end,
  4409.  
  4410.         PixelsInSelection = function(self, cut)
  4411.             local pixels = {}
  4412.             if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  4413.                 local point1 = Current.Selection[1]
  4414.                 local point2 = Current.Selection[2]
  4415.  
  4416.                 local size = point2 - point1
  4417.                 local cornerX = point1.x
  4418.                 local cornerY = point1.y
  4419.                 for x = 1, size.x + 1 do
  4420.                     for y = 1, size.y + 1 do
  4421.                         if not pixels[x] then
  4422.                             pixels[x] = {}
  4423.                         end
  4424.                         if not self.Pixels[cornerX + x - 1] or not self.Pixels[cornerX + x - 1][cornerY + y - 1] then
  4425.                             break
  4426.                         end
  4427.                         local pixel =  self.Pixels[cornerX + x - 1][cornerY + y - 1]
  4428.                         pixels[x][y] = Pixel:Initialise(pixel.TextColour, pixel.BackgroundColour, pixel.Character, Current.Layer)
  4429.                         if cut then
  4430.                             Current.Layer:SetPixel(cornerX + x - 1, cornerY + y - 1, nil, Current.Layer.BackgroundColour, nil)
  4431.                         end
  4432.                     end
  4433.                 end
  4434.             end
  4435.             return pixels
  4436.         end,
  4437.  
  4438.         EraseSelection = function(self)
  4439.             if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  4440.                 local point1 = Current.Selection[1]
  4441.                 local point2 = Current.Selection[2]
  4442.  
  4443.                 local size = point2 - point1
  4444.                 local cornerX = point1.x
  4445.                 local cornerY = point1.y
  4446.                 for x = 1, size.x + 1 do
  4447.                     for y = 1, size.y + 1 do
  4448.                         Current.Layer:SetPixel(cornerX + x - 1, cornerY + y - 1, nil, Current.Layer.BackgroundColour, nil)
  4449.                     end
  4450.                 end
  4451.             end
  4452.         end,
  4453.  
  4454.         InsertPixels = function(self, pixels)
  4455.             local cornerX = Current.Selection[1].x
  4456.             local cornerY = Current.Selection[1].y
  4457.             for x, col in ipairs(pixels) do
  4458.                 for y, pixel in ipairs(col) do
  4459.                     Current.Layer:SetPixel(cornerX + x - 1, cornerY + y - 1, pixel.TextColour, pixel.BackgroundColour, pixel.Character)
  4460.                 end
  4461.             end
  4462.         end
  4463.     }
  4464.  
  4465.     Artboard = {
  4466.         X = 0,
  4467.         Y = 0,
  4468.         Name = "",
  4469.         Path = "",
  4470.         Width = 1,
  4471.         Height = 1,
  4472.         Layers = {},
  4473.         Format = nil,
  4474.         SelectionIsBlack = true,
  4475.  
  4476.         Draw = function(self)
  4477.             Drawing.DrawBlankArea(self.X + 1, self.Y + 1, self.Width, self.Height, UIColours.Shadow)
  4478.  
  4479.             local odd
  4480.             for x = 1, self.Width do
  4481.                 odd = x % 2
  4482.                 if odd == 1 then
  4483.                     odd = true
  4484.                 else
  4485.                     odd = false
  4486.                 end
  4487.                 for y = 1, self.Height do
  4488.                     if odd then
  4489.                         Drawing.WriteToBuffer(self.X + x - 1, self.Y + y - 1, ":", UIColours.TransparentBackgroundTwo, UIColours.TransparentBackgroundOne)
  4490.                     else
  4491.                         Drawing.WriteToBuffer(self.X + x - 1, self.Y + y - 1, ":", UIColours.TransparentBackgroundOne, UIColours.TransparentBackgroundTwo)
  4492.                     end
  4493.  
  4494.                     odd = not odd
  4495.                 end
  4496.             end
  4497.  
  4498.             for i, layer in ipairs(self.Layers) do
  4499.                 layer:Draw()
  4500.             end
  4501.  
  4502.             if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  4503.                 local point1 = Current.Selection[1]
  4504.                 local point2 = Current.Selection[2]
  4505.  
  4506.                 local size = point2 - point1
  4507.  
  4508.                 local isBlack = self.SelectionIsBlack
  4509.  
  4510.                 local function c()
  4511.                     local c = colours.white
  4512.                     if isBlack then
  4513.                         c = colours.black
  4514.                     end
  4515.                     isBlack = not isBlack
  4516.                     return c
  4517.                 end
  4518.  
  4519.                 function horizontal(y)
  4520.                     Drawing.WriteToBuffer(self.X - 1 + point1.x, self.Y - 1 + y, '+', c(), colours.transparent)
  4521.                     if size.x > 0 then
  4522.                         for i = 1, size.x - 1 do
  4523.                             Drawing.WriteToBuffer(self.X - 1 + point1.x + i, self.Y - 1 + y, '-', c(), colours.transparent)
  4524.                         end
  4525.                     else
  4526.                         for i = 1, (-1 * size.x) - 1 do
  4527.                             Drawing.WriteToBuffer(self.X - 1 + point1.x - i, self.Y - 1 + y, '-', c(), colours.transparent)
  4528.                         end
  4529.                     end
  4530.  
  4531.                     Drawing.WriteToBuffer(self.X - 1 + point1.x + size.x, self.Y - 1 + y, '+', c(), colours.transparent)
  4532.                 end
  4533.  
  4534.                 function vertical(x)
  4535.                     if size.y < 0 then
  4536.                         for i = 1, (-1 * size.y) - 1 do
  4537.                             Drawing.WriteToBuffer(self.X - 1 + x, self.Y - 1 + point1.y  - i, '|', c(), colours.transparent)
  4538.                         end
  4539.                     else
  4540.                         for i = 1, size.y - 1 do
  4541.                             Drawing.WriteToBuffer(self.X - 1 + x, self.Y - 1 + point1.y  + i, '|', c(), colours.transparent)
  4542.                         end
  4543.                     end
  4544.                 end
  4545.  
  4546.                 horizontal(point1.y)
  4547.                 vertical(point1.x)
  4548.                 horizontal(point1.y + size.y)
  4549.                 vertical(point1.x + size.x)
  4550.             end
  4551.         end,
  4552.  
  4553.         Initialise = function(self, name, path, width, height, format, backgroundColour, layers)
  4554.             local new = {}    -- the new instance
  4555.             setmetatable( new, {__index = self} )
  4556.             new.Y = 3
  4557.             new.X = 2
  4558.             new.Name = name
  4559.             new.Path = path
  4560.             new.Width = width
  4561.             new.Height = height
  4562.             new.Format = format
  4563.             new.Layers = {}
  4564.             if not layers then
  4565.                 new:MakeLayer('Background', backgroundColour)
  4566.             else
  4567.                 for i, layer in ipairs(layers) do
  4568.                     new:MakeLayer(layer.Name, layer.BackgroundColour, layer.Index, layer.Pixels)
  4569.                     new.Layers[i].Visible = layer.Visible
  4570.                 end
  4571.                 Current.Layer = new.Layers[#new.Layers]
  4572.             end
  4573.             return new
  4574.         end,
  4575.  
  4576.         Resize = function(self, top, bottom, left, right)
  4577.             self.Height = self.Height + top + bottom
  4578.             self.Width = self.Width + left + right
  4579.  
  4580.             for i, layer in ipairs(self.Layers) do
  4581.  
  4582.                 if left < 0 then
  4583.                     for x = 1, -left do
  4584.                         table.remove(layer.Pixels, 1)
  4585.                     end
  4586.                 end
  4587.  
  4588.                 if right < 0 then
  4589.                     for x = 1, -right do
  4590.                         table.remove(layer.Pixels, #layer.Pixels)
  4591.                     end
  4592.                 end
  4593.  
  4594.                 for x = 1, left do
  4595.                     table.insert(layer.Pixels, 1, {})
  4596.                     for y = 1, self.Height do
  4597.                         layer:MakePixel(1, y)
  4598.                     end
  4599.                 end
  4600.  
  4601.                 for x = 1, right do
  4602.                     table.insert(layer.Pixels, {})
  4603.                     for y = 1, self.Height do
  4604.                         layer:MakePixel(#layer.Pixels, y)
  4605.                     end
  4606.                 end
  4607.  
  4608.                 for y = 1, top do
  4609.                     for x = 1, self.Width do
  4610.                         table.insert(layer.Pixels[x], 1, {})
  4611.                         layer:MakePixel(x, 1)
  4612.                     end
  4613.                 end
  4614.  
  4615.                 for y = 1, bottom do
  4616.                     for x = 1, self.Width do
  4617.                         table.insert(layer.Pixels[x], {})
  4618.                         layer:MakePixel(x, #layer.Pixels[x])
  4619.                     end
  4620.                 end
  4621.  
  4622.                 if top < 0 then
  4623.                     for y = 1, -top do
  4624.                         for x = 1, self.Width do
  4625.                             table.remove(layer.Pixels[x], 1)
  4626.                         end
  4627.                     end
  4628.                 end
  4629.  
  4630.                 if bottom < 0 then
  4631.                     for y = 1, -bottom do
  4632.                         for x = 1, self.Width do
  4633.                             table.remove(layer.Pixels[x], #layer.Pixels[x])
  4634.                         end
  4635.                     end
  4636.                 end
  4637.             end
  4638.         end,
  4639.  
  4640.         MakeLayer = function(self, name, backgroundColour, index, pixels)
  4641.             backgroundColour = backgroundColour or colours.white
  4642.             name = name or "Layer"
  4643.             local layer = Layer:Initialise(name, backgroundColour, self, index, pixels)
  4644.             table.insert(self.Layers, layer)
  4645.             Current.Layer = layer
  4646.             ModuleNamed('Layers'):Update()
  4647.             return layer
  4648.         end,
  4649.  
  4650.         New = function(self, name, path, width, height, format, backgroundColour, layers)
  4651.             local new = self:Initialise(name, path, width, height, format, backgroundColour, layers)
  4652.             table.insert(Lists.Artboards, new)
  4653.             Current.Artboard = new
  4654.             --new:Save()
  4655.             return new
  4656.         end,
  4657.  
  4658.         Save = function(self, path)
  4659.             Current.Artboard = self
  4660.             path = path or self.Path
  4661.             local _open = io.open
  4662.             if OneOS then
  4663.                 _open = OneOS.IO.open
  4664.             end
  4665.             local file = _open(path, "w", true)
  4666.             if self.Format == '.skch' then
  4667.                 file:write(textutils.serialize(SaveSKCH()))
  4668.             else
  4669.                 local lines = {}
  4670.                 if self.Format == '.nfp' then
  4671.                     lines = SaveNFP()
  4672.                 elseif self.Format == '.nft' then
  4673.                     lines = SaveNFT()
  4674.                 end
  4675.  
  4676.                 for i, line in ipairs(lines) do
  4677.                     file:write(line.."\n")
  4678.                 end
  4679.             end
  4680.             file:close()
  4681.             Current.Modified = false
  4682.         end,
  4683.  
  4684.         Click = function(self, side, x, y, drag)
  4685.             if Current.Tool and Current.Layer and Current.Layer.Visible then
  4686.                 Current.Tool:Use(x, y, side, drag)
  4687.                 Current.Modified = true
  4688.                 return true
  4689.             end
  4690.         end
  4691.     }
  4692.  
  4693.     Toolbar = {
  4694.         X = 0,
  4695.         Y = 0,
  4696.         Width = 0,
  4697.         ExpandedWidth = 14,
  4698.         ClosedWidth = 2,
  4699.         Height = 0,
  4700.         Expanded = true,
  4701.         ToolbarItems = {},
  4702.  
  4703.         AbsolutePosition = function(self)
  4704.             return {X = self.X, Y = self.Y}
  4705.         end,
  4706.  
  4707.         Draw = function(self)
  4708.             self:CalculateToolbarItemPositions()
  4709.             --Drawing.DrawArea(self.X - 1, self.Y, 1, self.Height, "|", UIColours.ToolbarText, UIColours.Background)
  4710.  
  4711.            
  4712.  
  4713.             --if not Current.Window then
  4714.                 Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.Toolbar)
  4715.             --else
  4716.             --  Drawing.DrawArea(self.X, self.Y, self.Width, self.Height, '|', colours.lightGrey, UIColours.Toolbar)
  4717.             --end
  4718.             for i, toolbarItem in ipairs(self.ToolbarItems) do
  4719.                 toolbarItem:Draw()
  4720.             end
  4721.         end,
  4722.  
  4723.         Initialise = function(self, side, expanded)
  4724.             local new = {}    -- the new instance
  4725.             setmetatable( new, {__index = self} )
  4726.             new.Expanded = expanded
  4727.  
  4728.             if expanded then
  4729.                 new.Width = new.ExpandedWidth
  4730.             else
  4731.                 new.Width = new.ClosedWidth
  4732.             end
  4733.  
  4734.             if side == 'right' then
  4735.                 new.X = Drawing.Screen.Width - new.Width + 1
  4736.             end
  4737.  
  4738.             if side == 'right' or side == 'left' then
  4739.                 new.Height = Drawing.Screen.Width
  4740.             end
  4741.  
  4742.             new.Y = 1
  4743.  
  4744.             return new
  4745.         end,
  4746.  
  4747.         AddToolbarItem = function(self, item)
  4748.             table.insert(self.ToolbarItems, item)
  4749.             self:CalculateToolbarItemPositions()
  4750.         end,
  4751.  
  4752.         CalculateToolbarItemPositions = function(self)
  4753.             local currY = 1
  4754.             for i, toolbarItem in ipairs(self.ToolbarItems) do
  4755.                 toolbarItem.Y = currY
  4756.                 currY = currY + toolbarItem.Height
  4757.             end
  4758.         end,
  4759.  
  4760.         Update = function(self)
  4761.             for i, toolbarItem in ipairs(self.ToolbarItems) do
  4762.                 if toolbarItem.Module.Update then
  4763.                     toolbarItem.Module:Update(toolbarItem)
  4764.                 end
  4765.             end
  4766.         end,
  4767.  
  4768.         New = function(self, side, expanded)
  4769.             local new = self:Initialise(side, expanded)
  4770.  
  4771.             --new:AddToolbarItem(ToolbarItem:Initialise("Colours", nil, true, new))
  4772.             --new:AddToolbarItem(ToolbarItem:Initialise("IDK", true, new))
  4773.  
  4774.             table.insert(Lists.Interface.Toolbars, new)
  4775.             return new
  4776.         end,
  4777.  
  4778.         Click = function(self, side, x, y)
  4779.             return false
  4780.         end
  4781.     }
  4782.  
  4783.     ToolbarItem = {
  4784.         X = 0,
  4785.         Y = 0,
  4786.         Width = 0,
  4787.         Height = 0,
  4788.         ExpandedHeight = 5,
  4789.         Expanded = true,
  4790.         Toolbar = nil,
  4791.         Title = "",
  4792.         MenuIcon = "=",
  4793.         ExpandedIcon = "+",
  4794.         ContractIcon = "-",
  4795.         ContentView = nil,
  4796.         Module = nil,
  4797.         MenuItems = nil,
  4798.  
  4799.         Draw = function(self)
  4800.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, UIColours.ToolbarItemTitle)
  4801.             Drawing.DrawCharacters(self.X + 1, self.Y, self.Title, UIColours.ToolbarText, UIColours.ToolbarItemTitle)
  4802.  
  4803.             Drawing.DrawCharacters(self.X + self.Width - 1, self.Y, self.MenuIcon, UIColours.ToolbarText, UIColours.ToolbarItemTitle)
  4804.  
  4805.             local expandContractIcon = self.ContractIcon
  4806.             if not self.Expanded then
  4807.                 expandContractIcon = self.ExpandedIcon
  4808.             end
  4809.  
  4810.             if self.Expanded and self.ContentView then
  4811.                 self.ContentView:Draw()
  4812.             end
  4813.  
  4814.             Drawing.DrawCharacters(self.X + self.Width - 2, self.Y, expandContractIcon, UIColours.ToolbarText, UIColours.ToolbarItemTitle)
  4815.         end,
  4816.  
  4817.         Initialise = function(self, module, height, expanded, toolbar, menuItems)
  4818.             local new = {}    -- the new instance
  4819.             setmetatable( new, {__index = self} )
  4820.             new.Expanded = expanded
  4821.             new.Title = module.Title
  4822.             new.Width = toolbar.Width
  4823.             new.Height = height or 5
  4824.             new.Module = module
  4825.             new.MenuItems = menuItems or {}
  4826.             table.insert(new.MenuItems,
  4827.                 {
  4828.                     Title = 'Shrink',
  4829.                     Click = function()
  4830.                         new:ToggleExpanded()
  4831.                     end
  4832.                 })
  4833.             new.ExpandedHeight = height or 5
  4834.             new.Y = 1
  4835.             new.X = toolbar.X
  4836.             new.ContentView = ContentView:Initialise(1, 2, new.Width, new.Height - 1, nil, new)
  4837.             new.Toolbar = toolbar
  4838.  
  4839.             return new
  4840.         end,
  4841.  
  4842.         ToggleExpanded = function(self)
  4843.             self.Expanded = not self.Expanded
  4844.             if self.Expanded then
  4845.                 self.Height = self.ExpandedHeight
  4846.             else
  4847.                 self.Height = 1
  4848.             end
  4849.         end,
  4850.  
  4851.         Click = function(self, side, x, y)
  4852.             local pos = GetAbsolutePosition(self)
  4853.             if x == self.Width and y == 1 then
  4854.                 local expandContract = "Shrink"
  4855.  
  4856.                 if not self.Expanded then
  4857.                     expandContract = "Expand"
  4858.                 end
  4859.                 self.MenuItems[#self.MenuItems].Title = expandContract
  4860.                 Menu:New(pos.X + x, pos.Y + y, self.MenuItems, self)
  4861.                 return true
  4862.             elseif x == self.Width - 1 and y == 1 then
  4863.                 self:ToggleExpanded()
  4864.                 return true
  4865.             elseif y ~= 1 then
  4866.                 return self.ContentView:Click(side,  x - self.ContentView.X + 1,  y - self.ContentView.Y + 1)
  4867.             end
  4868.  
  4869.             return false
  4870.         end
  4871.     }
  4872.  
  4873.     ContentView = {
  4874.         X = 1,
  4875.         Y = 1,
  4876.         Width = 0,
  4877.         Height = 0,
  4878.         Parent = nil,
  4879.         Views = {},
  4880.  
  4881.         AbsolutePosition = function(self)
  4882.             return self.Parent:AbsolutePosition()
  4883.         end,
  4884.  
  4885.         Draw = function(self)
  4886.             for i, view in ipairs(self.Views) do
  4887.                 view:Draw()
  4888.             end
  4889.         end,
  4890.  
  4891.         Initialise = function(self, x, y, width, height, views, parent)
  4892.             local new = {}    -- the new instance
  4893.             setmetatable( new, {__index = self} )
  4894.             new.Width = width
  4895.             new.Height = height
  4896.             new.Y = y
  4897.             new.X = x
  4898.             new.Views = views or {}
  4899.             new.Parent = parent
  4900.             return new
  4901.         end,
  4902.  
  4903.         Click = function(self, side, x, y)
  4904.             for k, view in pairs(self.Views) do
  4905.                 if DoClick(view, side, x, y) then
  4906.                     return true
  4907.                 end
  4908.             end
  4909.         end
  4910.     }
  4911.  
  4912.     Button = {
  4913.         X = 1,
  4914.         Y = 1,
  4915.         Width = 0,
  4916.         Height = 0,
  4917.         BackgroundColour = colours.lightGrey,
  4918.         TextColour = colours.white,
  4919.         ActiveBackgroundColour = colours.lightGrey,
  4920.         Text = "",
  4921.         Parent = nil,
  4922.         _Click = nil,
  4923.         Toggle = nil,
  4924.  
  4925.         AbsolutePosition = function(self)
  4926.             return self.Parent:AbsolutePosition()
  4927.         end,
  4928.  
  4929.         Draw = function(self)
  4930.             local bg = self.BackgroundColour
  4931.             local tc = self.TextColour
  4932.             if type(bg) == 'function' then
  4933.                 bg = bg()
  4934.             end
  4935.  
  4936.             if self.Toggle then
  4937.                 tc = UIColours.MenuBarActive
  4938.                 bg = self.ActiveBackgroundColour
  4939.             end
  4940.  
  4941.             local pos = GetAbsolutePosition(self)
  4942.             Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, bg)
  4943.             Drawing.DrawCharactersCenter(pos.X, pos.Y, self.Width, self.Height, self.Text, tc, bg)
  4944.         end,
  4945.  
  4946.         Initialise = function(self, x, y, width, height, backgroundColour, parent, click, text, textColour, toggle, activeBackgroundColour)
  4947.             local new = {}    -- the new instance
  4948.             setmetatable( new, {__index = self} )
  4949.             height = height or 1
  4950.             new.Width = width or #text + 2
  4951.             new.Height = height
  4952.             new.Y = y
  4953.             new.X = x
  4954.             new.Text = text or ""
  4955.             new.BackgroundColour = backgroundColour or colours.lightGrey
  4956.             new.TextColour = textColour or colours.white
  4957.             new.ActiveBackgroundColour = activeBackgroundColour or colours.lightGrey
  4958.             new.Parent = parent
  4959.             new._Click = click
  4960.             new.Toggle = toggle
  4961.             return new
  4962.         end,
  4963.  
  4964.         Click = function(self, side, x, y)
  4965.             if self._Click then
  4966.                 if self:_Click(side, x, y, not self.Toggle) ~= false and self.Toggle ~= nil then
  4967.                     self.Toggle = not self.Toggle
  4968.                     Draw()
  4969.                 end
  4970.                 return true
  4971.             else
  4972.                 return false
  4973.             end
  4974.         end
  4975.     }
  4976.  
  4977.     TextBox = {
  4978.         X = 1,
  4979.         Y = 1,
  4980.         Width = 0,
  4981.         Height = 0,
  4982.         BackgroundColour = colours.lightGrey,
  4983.         TextColour = colours.black,
  4984.         Parent = nil,
  4985.         TextInput = nil,
  4986.  
  4987.         AbsolutePosition = function(self)
  4988.             return self.Parent:AbsolutePosition()
  4989.         end,
  4990.  
  4991.         Draw = function(self)      
  4992.             local pos = GetAbsolutePosition(self)
  4993.             Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, self.BackgroundColour)
  4994.             local text = self.TextInput.Value
  4995.             if #text > (self.Width - 2) then
  4996.                 text = text:sub(#text-(self.Width - 3))
  4997.                 if Current.Input == self.TextInput then
  4998.                     Current.CursorPos = {pos.X + 1 + self.Width-2, pos.Y}
  4999.                 end
  5000.             else
  5001.                 if Current.Input == self.TextInput then
  5002.                     Current.CursorPos = {pos.X + 1 + self.TextInput.CursorPos, pos.Y}
  5003.                 end
  5004.             end
  5005.             Drawing.DrawCharacters(pos.X + 1, pos.Y, text, self.TextColour, self.BackgroundColour)
  5006.  
  5007.             term.setCursorBlink(true)
  5008.            
  5009.             Current.CursorColour = self.TextColour
  5010.         end,
  5011.  
  5012.         Initialise = function(self, x, y, width, height, parent, text, backgroundColour, textColour, done, numerical)
  5013.             local new = {}    -- the new instance
  5014.             setmetatable( new, {__index = self} )
  5015.             height = height or 1
  5016.             new.Width = width or #text + 2
  5017.             new.Height = height
  5018.             new.Y = y
  5019.             new.X = x
  5020.             new.TextInput = TextInput:Initialise(text or '', function(key)
  5021.                 if done then
  5022.                     done(key)
  5023.                 end
  5024.                 Draw()
  5025.             end, numerical)
  5026.             new.BackgroundColour = backgroundColour or colours.lightGrey
  5027.             new.TextColour = textColour or colours.black
  5028.             new.Parent = parent
  5029.             return new
  5030.         end,
  5031.  
  5032.         Click = function(self, side, x, y)
  5033.             Current.Input = self.TextInput
  5034.             self:Draw()
  5035.         end
  5036.     }
  5037.  
  5038.     TextInput = {
  5039.         Value = "",
  5040.         Change = nil,
  5041.         CursorPos = nil,
  5042.         Numerical = false,
  5043.  
  5044.         Initialise = function(self, value, change, numerical)
  5045.             local new = {}    -- the new instance
  5046.             setmetatable( new, {__index = self} )
  5047.             new.Value = value
  5048.             new.Change = change
  5049.             new.CursorPos = #value
  5050.             new.Numerical = numerical
  5051.             return new
  5052.         end,
  5053.  
  5054.         Char = function(self, char)
  5055.             if self.Numerical then
  5056.                 char = tostring(tonumber(char))
  5057.             end
  5058.             if char == 'nil' then
  5059.                 return
  5060.             end
  5061.             self.Value = string.sub(self.Value, 1, self.CursorPos ) .. char .. string.sub( self.Value, self.CursorPos + 1 )
  5062.            
  5063.             self.CursorPos = self.CursorPos + 1
  5064.             self.Change(key)
  5065.         end,
  5066.  
  5067.         Key = function(self, key)
  5068.             if key == keys.enter then
  5069.                 self.Change(key)        
  5070.             elseif key == keys.left then
  5071.                 -- Left
  5072.                 if self.CursorPos > 0 then
  5073.                     self.CursorPos = self.CursorPos - 1
  5074.                     self.Change(key)
  5075.                 end
  5076.                
  5077.             elseif key == keys.right then
  5078.                 -- Right                
  5079.                 if self.CursorPos < string.len(self.Value) then
  5080.                     self.CursorPos = self.CursorPos + 1
  5081.                     self.Change(key)
  5082.                 end
  5083.            
  5084.             elseif key == keys.backspace then
  5085.                 -- Backspace
  5086.                 if self.CursorPos > 0 then
  5087.                     self.Value = string.sub( self.Value, 1, self.CursorPos - 1 ) .. string.sub( self.Value, self.CursorPos + 1 )
  5088.                     self.CursorPos = self.CursorPos - 1
  5089.                 end
  5090.                 self.Change(key)
  5091.             elseif key == keys.home then
  5092.                 -- Home
  5093.                 self.CursorPos = 0
  5094.                 self.Change(key)
  5095.             elseif key == keys.delete then
  5096.                 if self.CursorPos < string.len(self.Value) then
  5097.                     self.Value = string.sub( self.Value, 1, self.CursorPos ) .. string.sub( self.Value, self.CursorPos + 2 )                
  5098.                     self.Change(key)
  5099.                 end
  5100.             elseif key == keys["end"] then
  5101.                 -- End
  5102.                 self.CursorPos = string.len(self.Value)
  5103.                 self.Change(key)
  5104.             end
  5105.         end
  5106.     }
  5107.  
  5108.     LayerItem = {
  5109.         X = 1,
  5110.         Y = 1,
  5111.         Parent = nil,
  5112.         Layer = nil,
  5113.  
  5114.         Draw = function(self)
  5115.             self.Y = self.Layer.Index
  5116.  
  5117.             local pos = GetAbsolutePosition(self)
  5118.  
  5119.             local tc = colours.lightGrey
  5120.  
  5121.             if Current.Layer == self.Layer then
  5122.                 tc = colours.white
  5123.             end
  5124.  
  5125.             Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, UIColours.Toolbar)
  5126.            
  5127.             Drawing.DrawCharacters(pos.X + 3, pos.Y, self.Layer.Name, tc, UIColours.Toolbar)
  5128.  
  5129.             if self.Layer.Visible then
  5130.                 Drawing.DrawCharacters(pos.X + 1, pos.Y, "@", tc, UIColours.Toolbar)
  5131.             else
  5132.                 Drawing.DrawCharacters(pos.X + 1, pos.Y, "X", tc, UIColours.Toolbar)
  5133.             end
  5134.  
  5135.         end,
  5136.  
  5137.         Initialise = function(self, layer, parent)
  5138.             local new = {}    -- the new instance
  5139.             setmetatable( new, {__index = self} )
  5140.             new.Width = parent.Width
  5141.             new.Height = 1
  5142.             new.Y = 1
  5143.             new.X = 1
  5144.             new.Layer = layer
  5145.             new.Parent = parent
  5146.             return new
  5147.         end,
  5148.  
  5149.         Click = function(self, side, x, y)
  5150.             if x == 2 then
  5151.                 self.Layer.Visible = not self.Layer.Visible
  5152.             else
  5153.                 Current.Layer = self.Layer
  5154.             end
  5155.             return true
  5156.         end
  5157.     }
  5158.  
  5159.     Menu = {
  5160.         X = 0,
  5161.         Y = 0,
  5162.         Width = 0,
  5163.         Height = 0,
  5164.         Owner = nil,
  5165.         Items = {},
  5166.         RemoveTop = false,
  5167.  
  5168.         Draw = function(self)
  5169.             Drawing.DrawBlankArea(self.X + 1, self.Y + 1, self.Width, self.Height, UIColours.Shadow)
  5170.             if not self.RemoveTop then
  5171.                 Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.MenuBackground)
  5172.                 for i, item in ipairs(self.Items) do
  5173.                     if item.Separator then
  5174.                         Drawing.DrawArea(self.X, self.Y + i, self.Width, 1, '-', colours.grey, UIColours.MenuBackground)
  5175.                     else
  5176.                         local textColour = UIColours.MenuText
  5177.                         if (item.Enabled and type(item.Enabled) == 'function' and item.Enabled() == false) or item.Enabled == false then
  5178.                             textColour = UIColours.MenuDisabledText
  5179.                         end
  5180.                         Drawing.DrawCharacters(self.X + 1, self.Y + i, item.Title, textColour, UIColours.MenuBackground)
  5181.                     end
  5182.                 end
  5183.             else
  5184.                 Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.MenuBackground)
  5185.                 for i, item in ipairs(self.Items) do
  5186.                     if item.Separator then
  5187.                         Drawing.DrawArea(self.X, self.Y + i - 1, self.Width, 1, '-', colours.grey, UIColours.MenuBackground)
  5188.                     else
  5189.                         local textColour = UIColours.MenuText
  5190.                         if (item.Enabled and type(item.Enabled) == 'function' and item.Enabled() == false) or item.Enabled == false then
  5191.                             textColour = UIColours.MenuDisabledText
  5192.                         end
  5193.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - 1, item.Title, textColour, UIColours.MenuBackground)
  5194.  
  5195.                         Drawing.DrawCharacters(self.X - 1 + self.Width-#item.KeyName, self.Y + i - 1, item.KeyName, textColour, UIColours.MenuBackground)
  5196.                     end
  5197.                 end
  5198.             end
  5199.         end,
  5200.  
  5201.         NameForKey = function(self, key)
  5202.             if key == keys.leftCtrl then
  5203.                 return '^'
  5204.             elseif key == keys.tab then
  5205.                 return 'Tab'
  5206.             elseif key == keys.delete then
  5207.                 return 'Delete'
  5208.             elseif key == keys.n then
  5209.                 return 'N'
  5210.             elseif key == keys.s then
  5211.                 return 'S'
  5212.             elseif key == keys.o then
  5213.                 return 'O'
  5214.             elseif key == keys.z then
  5215.                 return 'Z'
  5216.             elseif key == keys.y then
  5217.                 return 'Y'
  5218.             elseif key == keys.c then
  5219.                 return 'C'
  5220.             elseif key == keys.x then
  5221.                 return 'X'
  5222.             elseif key == keys.v then
  5223.                 return 'V'
  5224.             elseif key == keys.r then
  5225.                 return 'R'
  5226.             elseif key == keys.l then
  5227.                 return 'L'
  5228.             elseif key == keys.t then
  5229.                 return 'T'
  5230.             elseif key == keys.h then
  5231.                 return 'H'
  5232.             elseif key == keys.e then
  5233.                 return 'E'
  5234.             elseif key == keys.p then
  5235.                 return 'P'
  5236.             elseif key == keys.f then
  5237.                 return 'F'
  5238.             elseif key == keys.m then
  5239.                 return 'M'
  5240.             else
  5241.                 return '?'      
  5242.             end
  5243.         end,
  5244.  
  5245.         Initialise = function(self, x, y, items, owner, removeTop)
  5246.             local new = {}    -- the new instance
  5247.             setmetatable( new, {__index = self} )
  5248.             if not owner then
  5249.                 return
  5250.             end
  5251.  
  5252.             local keyNames = {}
  5253.  
  5254.             for i, v in ipairs(items) do
  5255.                 items[i].KeyName = ''
  5256.                 if v.Keys then
  5257.                     for _i, key in ipairs(v.Keys) do
  5258.                         items[i].KeyName = items[i].KeyName .. self:NameForKey(key)
  5259.                     end
  5260.                 end
  5261.                 if items[i].KeyName ~= '' then
  5262.                     table.insert(keyNames, items[i].KeyName)
  5263.                 end
  5264.             end
  5265.             local keysLength = LongestString(keyNames)
  5266.             if keysLength > 0 then
  5267.                 keysLength = keysLength + 2
  5268.             end
  5269.  
  5270.             new.Width = LongestString(items, 'Title') + 2 + keysLength
  5271.             if new.Width < 10 then
  5272.                 new.Width = 10
  5273.             end
  5274.             new.Height = #items + 2
  5275.             new.RemoveTop = removeTop or false
  5276.             if removeTop then
  5277.                 new.Height = new.Height - 1
  5278.             end
  5279.            
  5280.             if y < 1 then
  5281.                 y = 1
  5282.             end
  5283.             if x < 1 then
  5284.                 x = 1
  5285.             end
  5286.  
  5287.             if y + new.Height > Drawing.Screen.Height + 1 then
  5288.                 y = Drawing.Screen.Height - new.Height
  5289.             end
  5290.             if x + new.Width > Drawing.Screen.Width + 1 then
  5291.                 x = Drawing.Screen.Width - new.Width
  5292.             end
  5293.  
  5294.  
  5295.             new.Y = y
  5296.             new.X = x
  5297.             new.Items = items
  5298.             new.Owner = owner
  5299.             return new
  5300.         end,
  5301.  
  5302.         New = function(self, x, y, items, owner, removeTop)
  5303.             if Current.Menu and Current.Menu.Owner == owner then
  5304.                 Current.Menu = nil
  5305.                 return
  5306.             end
  5307.  
  5308.             local new = self:Initialise(x, y, items, owner, removeTop)
  5309.             Current.Menu = new
  5310.             return new
  5311.         end,
  5312.  
  5313.         Click = function(self, side, x, y)
  5314.             local i = y-1
  5315.             if self.RemoveTop then
  5316.                 i = y
  5317.             end
  5318.             if i >= 1 and y < self.Height then
  5319.                 if not ((self.Items[i].Enabled and type(self.Items[i].Enabled) == 'function' and self.Items[i].Enabled() == false) or self.Items[i].Enabled == false) and self.Items[i].Click then
  5320.                     self.Items[i]:Click()
  5321.                     if Current.Menu.Owner and Current.Menu.Owner.Toggle then
  5322.                         Current.Menu.Owner.Toggle = false
  5323.                     end
  5324.                     Current.Menu = nil
  5325.                     self = nil
  5326.                 end
  5327.                 return true
  5328.             end
  5329.         end
  5330.     }
  5331.  
  5332.     MenuBar = {
  5333.         X = 1,
  5334.         Y = 1,
  5335.         Width = Drawing.Screen.Width,
  5336.         Height = 1,
  5337.         MenuBarItems = {},
  5338.  
  5339.         AbsolutePosition = function(self)
  5340.             return {X = self.X, Y = self.Y}
  5341.         end,
  5342.  
  5343.         Draw = function(self)
  5344.             --Drawing.DrawArea(self.X - 1, self.Y, 1, self.Height, "|", UIColours.ToolbarText, UIColours.Background)
  5345.  
  5346.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.Toolbar)
  5347.             for i, button in ipairs(self.MenuBarItems) do
  5348.                 button:Draw()
  5349.             end
  5350.         end,
  5351.  
  5352.         Initialise = function(self, items)
  5353.             local new = {}    -- the new instance
  5354.             setmetatable( new, {__index = self} )
  5355.             new.X = 1
  5356.             new.Y = 1
  5357.             new.MenuBarItems = items
  5358.             return new
  5359.         end,
  5360.  
  5361.         AddToolbarItem = function(self, item)
  5362.             table.insert(self.ToolbarItems, item)
  5363.             self:CalculateToolbarItemPositions()
  5364.         end,
  5365.  
  5366.         CalculateToolbarItemPositions = function(self)
  5367.             local currY = 1
  5368.             for i, toolbarItem in ipairs(self.ToolbarItems) do
  5369.                 toolbarItem.Y = currY
  5370.                 currY = currY + toolbarItem.Height
  5371.             end
  5372.         end,
  5373.  
  5374.         Click = function(self, side, x, y)
  5375.             for i, item in ipairs(self.MenuBarItems) do
  5376.                 if item.X <= x and item.X + item.Width > x then
  5377.                     if item:Click(item, side, x - item.X + 1, 1) then
  5378.                         break
  5379.                     end
  5380.                 end
  5381.             end
  5382.             return false
  5383.         end
  5384.     }
  5385.  
  5386.     --Modules--
  5387.  
  5388.     Modules = {
  5389.         {
  5390.             Title = "Colours",
  5391.             ToolbarItem = nil,
  5392.             Initialise = function(self)
  5393.                 self.ToolbarItem = ToolbarItem:Initialise(self, nil, true, Current.Toolbar)
  5394.  
  5395.                 local buttons = {}
  5396.  
  5397.                 local i = 0
  5398.  
  5399.                 local coloursWidth = 8
  5400.                 local _colours = {
  5401.                     colours.brown,
  5402.                     colours.yellow,
  5403.                     colours.orange,
  5404.                     colours.red,
  5405.                     colours.green,
  5406.                     colours.lime,
  5407.                     colours.magenta,
  5408.                     colours.pink,
  5409.                     colours.purple,
  5410.                     colours.blue,
  5411.                     colours.cyan,
  5412.                     colours.lightBlue,
  5413.                     colours.lightGrey,
  5414.                     colours.grey,
  5415.                     colours.black,
  5416.                     colours.white
  5417.                 }
  5418.  
  5419.                 for k, colour in pairs(_colours) do
  5420.                     if type(colour) == 'number' and colour ~= -1 then
  5421.                         i = i + 1
  5422.  
  5423.                         local y = math.floor(i/(coloursWidth/2))
  5424.  
  5425.                         local x = (i%(coloursWidth/2))
  5426.                         if x == 0 then
  5427.                             x = (coloursWidth/2)
  5428.                             y = y -1
  5429.                         end
  5430.  
  5431.                         table.insert(buttons,
  5432.                             {
  5433.                                 X = x*2 - 2 + self.ToolbarItem.Width - coloursWidth,
  5434.                                 Y = y+1,
  5435.                                 Width = 2,
  5436.                                 Height = 1,
  5437.                                 BackgroundColour = colour,
  5438.                                 Click = function(self, side, x, y)
  5439.                                     SetColour(self.BackgroundColour)
  5440.                                 end
  5441.                             }
  5442.                         )
  5443.                     end
  5444.                 end
  5445.  
  5446.                 for i, button in ipairs(buttons) do
  5447.                     table.insert(self.ToolbarItem.ContentView.Views,
  5448.                         Button:Initialise(button.X, button.Y, button.Width, button.Height, button.BackgroundColour, self.ToolbarItem.ContentView, button.Click))    
  5449.                 end
  5450.                
  5451.                 table.insert(self.ToolbarItem.ContentView.Views,
  5452.                         Button:Initialise(1, 1, 4, 3, function()return Current.Colour end, self.ToolbarItem.ContentView, nil))
  5453.            
  5454.                 Current.Toolbar:AddToolbarItem(self.ToolbarItem)
  5455.             end
  5456.         },
  5457.  
  5458.         {
  5459.             Title = "Tools",
  5460.             ToolbarItem = nil,
  5461.             Update = function(self)
  5462.                 for i, view in ipairs(self.ToolbarItem.ContentView.Views) do
  5463.                     if (Current.Tool and Current.Tool.Name == view.Text) then
  5464.                         view.TextColour = colours.white
  5465.                     else
  5466.                         view.TextColour = colours.lightGrey
  5467.                     end
  5468.                 end
  5469.                 self.ToolbarItem.ContentView.Views[1].Text = 'Size: '..Current.ToolSize
  5470.             end,
  5471.  
  5472.             Initialise = function(self)
  5473.                 self.ToolbarItem = ToolbarItem:Initialise(self, #Tools+2, true, Current.Toolbar,
  5474.                     {{
  5475.                         Title = "Change Tool Size",
  5476.                         Click = function()
  5477.                             DisplayToolSizeWindow()
  5478.                         end,
  5479.                     }})
  5480.  
  5481.                 table.insert(self.ToolbarItem.ContentView.Views, Button:Initialise(1, 1, self.ToolbarItem.Width, 1, UIColours.Toolbar, self.ToolbarItem.ContentView, DisplayToolSizeWindow, 'Size: '..Current.ToolSize))
  5482.  
  5483.                 local y = 2
  5484.                 for i, tool in ipairs(Tools) do
  5485.                     table.insert(self.ToolbarItem.ContentView.Views, Button:Initialise(1, y, self.ToolbarItem.Width, 1, UIColours.Toolbar, self.ToolbarItem.ContentView, function() SetTool(tool) self:Update(self.ToolbarItem) end, tool.Name))
  5486.                     y = y + 1
  5487.                 end
  5488.  
  5489.                 self:Update(self.ToolbarItem)
  5490.  
  5491.                 Current.Toolbar:AddToolbarItem(self.ToolbarItem)
  5492.             end
  5493.         },
  5494.  
  5495.         {
  5496.             Title = "Layers",
  5497.             ToolbarItem = nil,
  5498.             Update = function(self)
  5499.                 if Current.Artboard then
  5500.                     self.ToolbarItem.ContentView.Views = {}
  5501.                     for i = 1, #Current.Artboard.Layers do
  5502.                         table.insert(self.ToolbarItem.ContentView.Views, LayerItem:Initialise(Current.Artboard.Layers[#Current.Artboard.Layers-i+1], self.ToolbarItem.ContentView))
  5503.                     end                
  5504.                 end
  5505.             end,
  5506.  
  5507.             Initialise = function(self)
  5508.                 self.ToolbarItem = ToolbarItem:Initialise(self, nil, true, Current.Toolbar,
  5509.                     {{
  5510.                         Title = "New Layer",
  5511.                         Click = function()
  5512.                             MakeNewLayer()
  5513.                         end,
  5514.                         Enabled = function()
  5515.                             return CheckOpenArtboard()
  5516.                         end
  5517.                     },
  5518.                     {
  5519.                         Title = 'Delete Layer',
  5520.                         Click = function()
  5521.                             DeleteLayer()
  5522.                         end,
  5523.                         Enabled = function()
  5524.                             return CheckSelectedLayer()
  5525.                         end
  5526.                     },
  5527.                     {
  5528.                         Title = 'Rename Layer...',
  5529.                         Click = function()
  5530.                             RenameLayer()
  5531.                         end,
  5532.                         Enabled = function()
  5533.                             return CheckSelectedLayer()
  5534.                         end
  5535.                     }})
  5536.                
  5537.                 self:Update()
  5538.  
  5539.                 Current.Toolbar:AddToolbarItem(self.ToolbarItem)
  5540.             end
  5541.         }
  5542.  
  5543.     }
  5544.  
  5545.     function ModuleNamed(name)
  5546.         for i, v in ipairs(Modules) do
  5547.             if v.Title == name then
  5548.                 return v
  5549.             end
  5550.         end
  5551.     end
  5552.  
  5553.     --Tools--
  5554.  
  5555.     function ToolAffectedPixels(x, y)
  5556.         if not CheckSelectedLayer() then
  5557.             return {}
  5558.         end
  5559.         if Current.ToolSize == 1 then
  5560.             if Current.Layer.Pixels[x] and Current.Layer.Pixels[x][y] then
  5561.                 return {{Current.Layer.Pixels[x][y], x, y}}
  5562.             end
  5563.         else
  5564.             local pixels = {}
  5565.             local cornerX = x - math.ceil(Current.ToolSize/2)
  5566.             local cornerY = y - math.ceil(Current.ToolSize/2)
  5567.             for _x = 1, Current.ToolSize do
  5568.                 for _y = 1, Current.ToolSize do
  5569.                     if Current.Layer.Pixels[cornerX + _x] and Current.Layer.Pixels[cornerX + _x][cornerY + _y] then
  5570.                         table.insert(pixels, {Current.Layer.Pixels[cornerX + _x][cornerY + _y], cornerX + _x, cornerY + _y})
  5571.                     end
  5572.                 end
  5573.             end
  5574.             return pixels
  5575.         end
  5576.     end
  5577.     local moveStartPoint = {}
  5578.     Tools = {
  5579.         {
  5580.             Name = "Hand",
  5581.             Use = function(self, x, y, side, drag)
  5582.                 Current.Input = nil
  5583.                 if drag and Current.HandDragStart and Current.HandDragStart[1] and Current.HandDragStart[2] then
  5584.                     local deltaX = x - Current.HandDragStart[1]
  5585.                     local deltaY = y - Current.HandDragStart[2]
  5586.                     Current.Artboard.X = Current.Artboard.X + deltaX
  5587.                     Current.Artboard.Y = Current.Artboard.Y + deltaY
  5588.                 else
  5589.                     Current.HandDragStart = {x, y}
  5590.                 end
  5591.                 sleep(0)
  5592.             end,
  5593.             Select = function(self)
  5594.                 return true
  5595.             end
  5596.         },
  5597.  
  5598.         {
  5599.             Name = "Pencil",
  5600.             Use = function(self, _x, _y, side, artboard)
  5601.                 Current.Input = nil
  5602.                 for i, pixel in ipairs(ToolAffectedPixels(_x, _y)) do
  5603.                     if side == 1 then
  5604.                         pixel[1].BackgroundColour = Current.Colour
  5605.                     elseif side == 2 then
  5606.                         pixel[1].TextColour = Current.Colour
  5607.                     end
  5608.                     pixel[1]:Draw(pixel[2], pixel[3])
  5609.                 end
  5610.             end,
  5611.             Select = function(self)
  5612.                 return true
  5613.             end
  5614.         },
  5615.  
  5616.         {
  5617.             Name = "Eraser",
  5618.             Use = function(self, x, y, side)
  5619.                 Current.Input = nil
  5620.                 Current.Layer:SetPixel(x, y, nil, Current.Layer.BackgroundColour, nil)
  5621.                 for i, pixel in ipairs(ToolAffectedPixels(x, y)) do
  5622.                     Current.Layer:SetPixel(pixel[2], pixel[3], nil, Current.Layer.BackgroundColour, nil)
  5623.                 end
  5624.             end,
  5625.             Select = function(self)
  5626.                 return true
  5627.             end
  5628.         },
  5629.  
  5630.         {
  5631.             Name = "Fill Bucket",
  5632.             Use = function(self, x, y, side)
  5633.                 local replaceColour = Current.Layer.Pixels[x][y].BackgroundColour
  5634.                 if side == 2 then
  5635.                     replaceColour = Current.Layer.Pixels[x][y].TextColour
  5636.                 end
  5637.  
  5638.                 local nodes = {{X = x, Y = y}}
  5639.  
  5640.                 while #nodes > 0 do
  5641.                     local node = nodes[1]
  5642.                     if Current.Layer.Pixels[node.X] and Current.Layer.Pixels[node.X][node.Y] then
  5643.                         local replacing = Current.Layer.Pixels[node.X][node.Y].BackgroundColour
  5644.                         if side == 2 then
  5645.                             replacing = Current.Layer.Pixels[node.X][node.Y].TextColour
  5646.                         end
  5647.                         if replacing == replaceColour and replacing ~= Current.Colour then
  5648.                             if side == 1 then
  5649.                                 Current.Layer.Pixels[node.X][node.Y].BackgroundColour = Current.Colour
  5650.                             elseif side == 2 then
  5651.                                 Current.Layer.Pixels[node.X][node.Y].TextColour = Current.Colour
  5652.                             end
  5653.                             table.insert(nodes, {X = node.X, Y = node.Y + 1})
  5654.                             table.insert(nodes, {X = node.X + 1, Y = node.Y})
  5655.                             if x > 1 then
  5656.                                 table.insert(nodes, {X = node.X - 1, Y = node.Y})
  5657.                             end
  5658.                             if y > 1 then
  5659.                                 table.insert(nodes, {X = node.X, Y = node.Y - 1})
  5660.                             end
  5661.                         end
  5662.                     end
  5663.                     table.remove(nodes, 1)
  5664.                 end
  5665.                 Draw()
  5666.             end,
  5667.             Select = function(self)
  5668.                 return true
  5669.             end
  5670.         },
  5671.  
  5672.         {
  5673.             Name = "Select",
  5674.             Use = function(self, x, y, side, drag)
  5675.                 Current.Input = nil
  5676.                 if not drag then
  5677.                     Current.Selection[1] = vector.new(x, y, 0)
  5678.                     Current.Selection[2] = nil
  5679.                 else
  5680.                     Current.Selection[2] = vector.new(x, y, 0)
  5681.                 end
  5682.             end,
  5683.             Select = function(self)
  5684.                 return true
  5685.             end
  5686.         },
  5687.  
  5688.         {
  5689.             Name = "Move",
  5690.             Use = function(self, x, y, side, drag)
  5691.                 Current.Input = nil
  5692.  
  5693.                 if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  5694.                     if drag and moveStartPoint then
  5695.                         local pixels = Current.Layer:PixelsInSelection(true)
  5696.                         local size = Current.Selection[1] - Current.Selection[2]
  5697.                         Current.Selection[1] = vector.new(x-moveStartPoint[1], y-moveStartPoint[2], 0)
  5698.                         Current.Selection[2] = vector.new(x-moveStartPoint[1]-size.x, y-moveStartPoint[2]-size.y, 0)
  5699.                         Current.Layer:InsertPixels(pixels)
  5700.                     else
  5701.                         moveStartPoint = {x-Current.Selection[1].x, y-Current.Selection[1].y}
  5702.                     end
  5703.                 end
  5704.             end,
  5705.             Select = function(self)
  5706.                 return true
  5707.             end
  5708.         },
  5709.  
  5710.         {
  5711.             Name = "Text",
  5712.             Use = function(self, x, y)
  5713.                 Current.Input = TextInput:Initialise('', function(key)
  5714.                     if key == keys.delete or key == keys.backspace then
  5715.                         if #Current.Input.Value == 0 then
  5716.                             if Current.Layer.Pixels[x] and Current.Layer.Pixels[x][y] then
  5717.                                 Current.Layer.Pixels[x][y]:Set(nil, nil, ' ')
  5718.                                 local newPos = Current.CursorPos[1] - Current.Artboard.X
  5719.                                 if newPos < Current.Artboard.X - 1 then
  5720.                                     newPos = Current.Artboard.X - 1
  5721.                                 end
  5722.                                 Current.Tool:Use(newPos, Current.CursorPos[2] - Current.Artboard.Y + 1)
  5723.                                 Draw()
  5724.                             end
  5725.                             return
  5726.                         else
  5727.                             if Current.Layer.Pixels[x+#Current.Input.Value] and Current.Layer.Pixels[x+#Current.Input.Value][y] then
  5728.                                 Current.Layer.Pixels[x+#Current.Input.Value][y]:Set(nil, nil, ' ')
  5729.                             end
  5730.                         end
  5731.                     else
  5732.                         local i = #Current.Input.Value
  5733.                         if Current.Layer.Pixels[x+i-1] then
  5734.                             Current.Layer.Pixels[x+i-1][y]:Set(Current.Colour, nil, Current.Input.Value:sub(i,i))
  5735.                             Current.Layer.Pixels[x+i-1][y]:Draw(x+i-1, y)
  5736.                         end
  5737.                     end
  5738.  
  5739.                     local newPos = x+Current.Input.CursorPos
  5740.  
  5741.                     if newPos > Current.Artboard.Width then
  5742.                         Current.Input.CursorPos = Current.Input.CursorPos - 1
  5743.                     end
  5744.  
  5745.                     Current.CursorPos = {x+Current.Input.CursorPos + Current.Artboard.X - 1, y + Current.Artboard.Y - 1}
  5746.                     Current.CursorColour = Current.Colour
  5747.                     Draw()
  5748.                 end)
  5749.  
  5750.                 Current.CursorPos = {x + Current.Artboard.X - 1, y + Current.Artboard.Y - 1}
  5751.                 Current.CursorColour = Current.Colour
  5752.             end,
  5753.             Select = function(self)
  5754.                 if Current.Artboard.Format == '.nfp' then
  5755.                     ButtonDialougeWindow:Initialise('NFP does not support text!', 'The format you are using, NFP, does not support text. Use NFT or SKCH to use text.', 'Ok', nil, function(window)
  5756.                         window:Close()
  5757.                     end):Show()
  5758.                     return false
  5759.                 else
  5760.                     return true
  5761.                 end
  5762.             end
  5763.         }
  5764.     }
  5765.  
  5766.  
  5767.     function ToolNamed(name)
  5768.         for i, v in ipairs(Tools) do
  5769.             if v.Name == name then
  5770.                 return v
  5771.             end
  5772.         end
  5773.     end
  5774.  
  5775.     --Windows--
  5776.  
  5777.     NewDocumentWindow = {
  5778.         X = 1,
  5779.         Y = 1,
  5780.         Width = 0,
  5781.         Height = 0,
  5782.         CursorPos = 1,
  5783.         Visible = true,
  5784.         Return = nil,
  5785.         OkButton = nil,
  5786.         Format = '.skch',
  5787.         ImageBackgroundColour = colours.white,
  5788.         NameLabelHighlight = false,
  5789.         SizeLabelHighlight = false,
  5790.  
  5791.  
  5792.         AbsolutePosition = function(self)
  5793.             return {X = self.X, Y = self.Y}
  5794.         end,
  5795.  
  5796.         Draw = function(self)
  5797.             if not self.Visible then
  5798.                 return
  5799.             end
  5800.             Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  5801.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  5802.             Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  5803.             Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  5804.  
  5805.             local nameLabelColour = colours.black
  5806.             if self.NameLabelHighlight then
  5807.                 nameLabelColour = colours.red
  5808.             end
  5809.  
  5810.             Drawing.DrawCharacters(self.X+1, self.Y+2, "Name", nameLabelColour, colours.white)
  5811.             Drawing.DrawCharacters(self.X+1, self.Y+4, "Type", colours.black, colours.white)
  5812.  
  5813.             local sizeLabelColour = colours.black
  5814.             if self.SizeLabelHighlight then
  5815.                 sizeLabelColour = colours.red
  5816.             end
  5817.             Drawing.DrawCharacters(self.X+1, self.Y+6, "Size", sizeLabelColour, colours.white)
  5818.             Drawing.DrawCharacters(self.X+11, self.Y+6, "x", colours.black, colours.white)
  5819.             Drawing.DrawCharacters(self.X+1, self.Y+8, "Background", colours.black, colours.white)
  5820.  
  5821.             self.OkButton:Draw()
  5822.             self.CancelButton:Draw()
  5823.             self.SKCHButton:Draw()
  5824.             self.NFTButton:Draw()
  5825.             self.NFPButton:Draw()
  5826.             self.PathTextBox:Draw()
  5827.             self.WidthTextBox:Draw()
  5828.             self.HeightTextBox:Draw()
  5829.             self.WhiteButton:Draw()
  5830.             self.BlackButton:Draw()
  5831.             self.TransparentButton:Draw()
  5832.         end,    
  5833.  
  5834.         Initialise = function(self, returnFunc)
  5835.             local new = {}    -- the new instance
  5836.             setmetatable( new, {__index = self} )
  5837.             new.Width = 32
  5838.             new.Height = 13
  5839.             new.Return = returnFunc
  5840.             new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  5841.             new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  5842.             new.Title = 'New Document'
  5843.             new.Visible = true
  5844.             new.NameLabelHighlight = false
  5845.             new.SizeLabelHighlight = false
  5846.             new.Format = '.skch'
  5847.             new.OkButton = Button:Initialise(new.Width - 4, new.Height - 1, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  5848.                 local path = new.PathTextBox.TextInput.Value
  5849.                 local ok = true
  5850.                 new.NameLabelHighlight = false
  5851.                 new.SizeLabelHighlight = false
  5852.                 local _fs = fs
  5853.                 if OneOS then
  5854.                     _fs = OneOS.FS
  5855.                 end
  5856.                 if path:sub(-1) == '/' or _fs.isDir(path) or #path == 0 then
  5857.                     ok = false
  5858.                     new.NameLabelHighlight = true
  5859.                 end
  5860.  
  5861.                 if #new.WidthTextBox.TextInput.Value == 0 or tonumber(new.WidthTextBox.TextInput.Value) <= 0 then
  5862.                     ok = false
  5863.                     new.SizeLabelHighlight = true
  5864.                 end
  5865.  
  5866.                 if #new.HeightTextBox.TextInput.Value == 0 or tonumber(new.HeightTextBox.TextInput.Value) <= 0 then
  5867.                     ok = false
  5868.                     new.SizeLabelHighlight = true
  5869.                 end
  5870.  
  5871.                 if ok then
  5872.                     returnFunc(new, true, path, tonumber(new.WidthTextBox.TextInput.Value), tonumber(new.HeightTextBox.TextInput.Value), new.Format, new.ImageBackgroundColour)
  5873.                 else
  5874.                     Draw()
  5875.                 end
  5876.             end, 'Ok', colours.black)
  5877.             new.CancelButton = Button:Initialise(new.Width - 13, new.Height - 1, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)returnFunc(new, false)end, 'Cancel', colours.black)
  5878.  
  5879.             new.SKCHButton = Button:Initialise(7, 5, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  5880.                 new.NFTButton.Toggle = false
  5881.                 new.NFPButton.Toggle = false
  5882.                 self.Toggle = false
  5883.                 new.Format = '.skch'
  5884.             end, '.skch', colours.black, true, colours.lightBlue)
  5885.             new.NFTButton = Button:Initialise(15, 5, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  5886.                 new.SKCHButton.Toggle = false
  5887.                 new.NFPButton.Toggle = false
  5888.                 self.Toggle = false
  5889.                 new.Format = '.nft'
  5890.             end, '.nft', colours.black, false, colours.lightBlue)
  5891.             new.NFPButton = Button:Initialise(22, 5, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  5892.                 new.SKCHButton.Toggle = false
  5893.                 new.NFTButton.Toggle = false
  5894.                 self.Toggle = false
  5895.                 new.Format = '.nfp'
  5896.             end, '.nfp', colours.black, false, colours.lightBlue)
  5897.  
  5898.             local path = ''
  5899.             if OneOS then
  5900.                 path = '/Desktop/'
  5901.             end
  5902.             new.PathTextBox = TextBox:Initialise(7, 3, new.Width - 7, 1, new, path, nil, nil, function(key)
  5903.                 if key == keys.enter or key == keys.tab then
  5904.                     Current.Input = new.WidthTextBox.TextInput
  5905.                 end        
  5906.             end)
  5907.             new.WidthTextBox = TextBox:Initialise(7, 7, 4, 1, new, tostring(15), nil, nil, function()
  5908.                 if key == keys.enter or key == keys.tab then
  5909.                     Current.Input = new.HeightTextBox.TextInput
  5910.                 end
  5911.             end, true)
  5912.             new.HeightTextBox = TextBox:Initialise(14, 7, 4, 1, new, tostring(10), nil, nil, function()
  5913.                 if key == keys.enter or key == keys.tab then
  5914.                     Current.Input = new.PathTextBox.TextInput
  5915.                 end
  5916.             end, true)
  5917.             Current.Input = new.PathTextBox.TextInput
  5918.  
  5919.  
  5920.             new.WhiteButton = Button:Initialise(2, 10, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  5921.                 new.TransparentButton.Toggle = false
  5922.                 new.BlackButton.Toggle = false
  5923.                 self.Toggle = false
  5924.                 new.ImageBackgroundColour = colours.white
  5925.             end, 'White', colours.black, true, colours.lightBlue)
  5926.             new.BlackButton = Button:Initialise(10, 10, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  5927.                 new.TransparentButton.Toggle = false
  5928.                 new.WhiteButton.Toggle = false
  5929.                 self.Toggle = false
  5930.                 new.ImageBackgroundColour = colours.black
  5931.             end, 'Black', colours.black, false, colours.lightBlue)
  5932.             new.TransparentButton = Button:Initialise(18, 10, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  5933.                 new.WhiteButton.Toggle = false
  5934.                 new.BlackButton.Toggle = false
  5935.                 self.Toggle = false
  5936.                 new.ImageBackgroundColour = colours.transparent
  5937.             end, 'Transparent', colours.black, false, colours.lightBlue)
  5938.  
  5939.             return new
  5940.         end,
  5941.  
  5942.         Show = function(self)
  5943.             Current.Window = self
  5944.             return self
  5945.         end,
  5946.  
  5947.         Close = function(self)
  5948.             Current.Input = nil
  5949.             Current.Window = nil
  5950.             self = nil
  5951.         end,
  5952.  
  5953.         Flash = function(self)
  5954.             self.Visible = false
  5955.             Draw()
  5956.             sleep(0.15)
  5957.             self.Visible = true
  5958.             Draw()
  5959.             sleep(0.15)
  5960.             self.Visible = false
  5961.             Draw()
  5962.             sleep(0.15)
  5963.             self.Visible = true
  5964.             Draw()
  5965.         end,
  5966.  
  5967.         ButtonClick = function(self, button, x, y)
  5968.             if button.X <= x and button.Y <= y and button.X + button.Width > x and button.Y + button.Height > y then
  5969.                 button:Click()
  5970.             end
  5971.         end,
  5972.  
  5973.         Click = function(self, side, x, y)
  5974.             local items = {self.OkButton, self.CancelButton, self.SKCHButton, self.NFTButton, self.NFPButton, self.PathTextBox, self.WidthTextBox, self.HeightTextBox, self.WhiteButton, self.BlackButton, self.TransparentButton}
  5975.             for i, v in ipairs(items) do
  5976.                 if CheckClick(v, x, y) then
  5977.                     v:Click(side, x, y)
  5978.                 end
  5979.             end
  5980.             return true
  5981.         end
  5982.     }
  5983.  
  5984.     local TidyPath = function(path)
  5985.         path = '/'..path
  5986.         local _fs = fs
  5987.         if OneOS then
  5988.             _fs = OneOS.FS
  5989.         end
  5990.         if _fs.isDir(path) then
  5991.             path = path .. '/'
  5992.         end
  5993.  
  5994.         path, n = path:gsub("//", "/")
  5995.         while n > 0 do
  5996.             path, n = path:gsub("//", "/")
  5997.         end
  5998.         return path
  5999.     end
  6000.  
  6001.     local WrapText = function(text, maxWidth)
  6002.         local lines = {''}
  6003.         for word, space in text:gmatch('(%S+)(%s*)') do
  6004.                 local temp = lines[#lines] .. word .. space:gsub('\n','')
  6005.                 if #temp > maxWidth then
  6006.                         table.insert(lines, '')
  6007.                 end
  6008.                 if space:find('\n') then
  6009.                         lines[#lines] = lines[#lines] .. word
  6010.                        
  6011.                         space = space:gsub('\n', function()
  6012.                                 table.insert(lines, '')
  6013.                                 return ''
  6014.                         end)
  6015.                 else
  6016.                         lines[#lines] = lines[#lines] .. word .. space
  6017.                 end
  6018.         end
  6019.         return lines
  6020.     end
  6021.  
  6022.     OpenDocumentWindow = {
  6023.         X = 1,
  6024.         Y = 1,
  6025.         Width = 0,
  6026.         Height = 0,
  6027.         CursorPos = 1,
  6028.         Visible = true,
  6029.         Return = nil,
  6030.         OpenButton = nil,
  6031.         PathTextBox = nil,
  6032.         CurrentDirectory = '/',
  6033.         Scroll = 0,
  6034.         MaxScroll = 0,
  6035.         GoUpButton = nil,
  6036.         SelectedFile = '',
  6037.         Files = {},
  6038.         Typed = false,
  6039.  
  6040.         AbsolutePosition = function(self)
  6041.             return {X = self.X, Y = self.Y}
  6042.         end,
  6043.  
  6044.         Draw = function(self)
  6045.             if not self.Visible then
  6046.                 return
  6047.             end
  6048.             Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  6049.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 3, colours.lightGrey)
  6050.             Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-6, colours.white)
  6051.             Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  6052.             Drawing.DrawBlankArea(self.X, self.Y + self.Height - 5, self.Width, 5, colours.lightGrey)
  6053.             self:DrawFiles()
  6054.  
  6055.             local _fs = fs
  6056.             if OneOS then
  6057.                 _fs = OneOS.FS
  6058.             end
  6059.             if (_fs.exists(self.PathTextBox.TextInput.Value)) or (self.SelectedFile and #self.SelectedFile > 0 and _fs.exists(self.CurrentDirectory .. self.SelectedFile)) then
  6060.                 self.OpenButton.TextColour = colours.black
  6061.             else
  6062.                 self.OpenButton.TextColour = colours.lightGrey
  6063.             end
  6064.  
  6065.             self.PathTextBox:Draw()
  6066.             self.OpenButton:Draw()
  6067.             self.CancelButton:Draw()
  6068.             self.GoUpButton:Draw()
  6069.         end,
  6070.  
  6071.         DrawFiles = function(self)
  6072.             local _fs = fs
  6073.             if OneOS then
  6074.                 _fs = OneOS.FS
  6075.             end
  6076.             for i, file in ipairs(self.Files) do
  6077.                 if i > self.Scroll and i - self.Scroll <= 11 then
  6078.                     if file == self.SelectedFile then
  6079.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.white, colours.lightBlue)
  6080.                     elseif string.find(file, '%.skch') or string.find(file, '%.nft') or string.find(file, '%.nfp') or _fs.isDir(self.CurrentDirectory .. file) then
  6081.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.black, colours.white)
  6082.                     else
  6083.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.grey, colours.white)
  6084.                     end
  6085.                 end
  6086.             end
  6087.             self.MaxScroll = #self.Files - 11
  6088.             if self.MaxScroll < 0 then
  6089.                 self.MaxScroll = 0
  6090.             end
  6091.         end,
  6092.  
  6093.         Initialise = function(self, returnFunc)
  6094.             local new = {}    -- the new instance
  6095.             setmetatable( new, {__index = self} )
  6096.             new.Width = 32
  6097.             new.Height = 17
  6098.             new.Return = returnFunc
  6099.             new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  6100.             new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  6101.             new.Title = 'Open Document'
  6102.             new.Visible = true
  6103.             new.CurrentDirectory = '/'
  6104.             new.SelectedFile = nil
  6105.             if OneOS then
  6106.                 new.CurrentDirectory = '/Desktop/'
  6107.             end
  6108.             local _fs = fs
  6109.             if OneOS then
  6110.                 _fs = OneOS.FS
  6111.             end
  6112.             new.OpenButton = Button:Initialise(new.Width - 6, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  6113.                 if _fs.exists(new.PathTextBox.TextInput.Value) and self.TextColour == colours.black and not _fs.isDir(new.PathTextBox.TextInput.Value) then
  6114.                     returnFunc(new, true, TidyPath(new.PathTextBox.TextInput.Value))
  6115.                 elseif new.SelectedFile and self.TextColour == colours.black and _fs.isDir(new.CurrentDirectory .. new.SelectedFile) then
  6116.                     new:GoToDirectory(new.CurrentDirectory .. new.SelectedFile)
  6117.                 elseif new.SelectedFile and self.TextColour == colours.black then
  6118.                     returnFunc(new, true, TidyPath(new.CurrentDirectory .. '/' .. new.SelectedFile))
  6119.                 end
  6120.             end, 'Open', colours.black)
  6121.             new.CancelButton = Button:Initialise(new.Width - 15, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  6122.                 returnFunc(new, false)
  6123.             end, 'Cancel', colours.black)
  6124.             new.GoUpButton = Button:Initialise(2, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  6125.                 local folderName = _fs.getName(new.CurrentDirectory)
  6126.                 local parentDirectory = new.CurrentDirectory:sub(1, #new.CurrentDirectory-#folderName-1)
  6127.                 new:GoToDirectory(parentDirectory)
  6128.             end, 'Go Up', colours.black)
  6129.             new.PathTextBox = TextBox:Initialise(2, new.Height - 3, new.Width - 2, 1, new, new.CurrentDirectory, colours.white, colours.black)
  6130.             new:GoToDirectory(new.CurrentDirectory)
  6131.             return new
  6132.         end,
  6133.  
  6134.         Show = function(self)
  6135.             Current.Window = self
  6136.             return self
  6137.         end,
  6138.  
  6139.         Close = function(self)
  6140.             Current.Input = nil
  6141.             Current.Window = nil
  6142.             self = nil
  6143.         end,
  6144.  
  6145.         GoToDirectory = function(self, path)
  6146.             path = TidyPath(path)
  6147.             self.CurrentDirectory = path
  6148.             self.Scroll = 0
  6149.             self.SelectedFile = nil
  6150.             self.Typed = false
  6151.             self.PathTextBox.TextInput.Value = path
  6152.             local _fs = fs
  6153.             if OneOS then
  6154.                 _fs = OneOS.FS
  6155.             end
  6156.             self.Files = _fs.list(self.CurrentDirectory)
  6157.             Draw()
  6158.         end,
  6159.  
  6160.         Flash = function(self)
  6161.             self.Visible = false
  6162.             Draw()
  6163.             sleep(0.15)
  6164.             self.Visible = true
  6165.             Draw()
  6166.             sleep(0.15)
  6167.             self.Visible = false
  6168.             Draw()
  6169.             sleep(0.15)
  6170.             self.Visible = true
  6171.             Draw()
  6172.         end,
  6173.  
  6174.         Click = function(self, side, x, y)
  6175.             local items = {self.OpenButton, self.CancelButton, self.PathTextBox, self.GoUpButton}
  6176.             local found = false
  6177.             for i, v in ipairs(items) do
  6178.                 if CheckClick(v, x, y) then
  6179.                     v:Click(side, x, y)
  6180.                     found = true
  6181.                 end
  6182.             end
  6183.  
  6184.             if not found then
  6185.                 if y <= 12 then
  6186.                     local _fs = fs
  6187.                     if OneOS then
  6188.                         _fs = OneOS.FS
  6189.                     end
  6190.                     self.SelectedFile = _fs.list(self.CurrentDirectory)[y-1]
  6191.                     self.PathTextBox.TextInput.Value = TidyPath(self.CurrentDirectory .. '/' .. self.SelectedFile)
  6192.                     Draw()
  6193.                 end
  6194.             end
  6195.             return true
  6196.         end
  6197.     }
  6198.  
  6199.     ButtonDialougeWindow = {
  6200.         X = 1,
  6201.         Y = 1,
  6202.         Width = 0,
  6203.         Height = 0,
  6204.         CursorPos = 1,
  6205.         Visible = true,
  6206.         CancelButton = nil,
  6207.         OkButton = nil,
  6208.         Lines = {},
  6209.  
  6210.         AbsolutePosition = function(self)
  6211.             return {X = self.X, Y = self.Y}
  6212.         end,
  6213.  
  6214.         Draw = function(self)
  6215.             if not self.Visible then
  6216.                 return
  6217.             end
  6218.             Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  6219.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  6220.             Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  6221.             Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  6222.  
  6223.             for i, text in ipairs(self.Lines) do
  6224.                 Drawing.DrawCharacters(self.X + 1, self.Y + 1 + i, text, colours.black, colours.white)
  6225.             end
  6226.  
  6227.             self.OkButton:Draw()
  6228.             if self.CancelButton then
  6229.                 self.CancelButton:Draw()
  6230.             end
  6231.         end,
  6232.  
  6233.         Initialise = function(self, title, message, okText, cancelText, returnFunc)
  6234.             local new = {}    -- the new instance
  6235.             setmetatable( new, {__index = self} )
  6236.             new.Width = 28
  6237.             new.Lines = WrapText(message, new.Width - 2)
  6238.             new.Height = 5 + #new.Lines
  6239.             new.Return = returnFunc
  6240.             new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  6241.             new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  6242.             new.Title = title
  6243.             new.Visible = true
  6244.             new.Visible = true
  6245.             new.OkButton = Button:Initialise(new.Width - #okText - 2, new.Height - 1, nil, 1, nil, new, function()
  6246.                 returnFunc(new, true)
  6247.             end, okText)
  6248.             if cancelText then
  6249.                 new.CancelButton = Button:Initialise(new.Width - #okText - 2 - 1 - #cancelText - 2, new.Height - 1, nil, 1, nil, new, function()
  6250.                     returnFunc(new, false)
  6251.                 end, cancelText)
  6252.             end
  6253.  
  6254.             return new
  6255.         end,
  6256.  
  6257.         Show = function(self)
  6258.             Current.Window = self
  6259.             return self
  6260.         end,
  6261.  
  6262.         Close = function(self)
  6263.             Current.Window = nil
  6264.             self = nil
  6265.         end,
  6266.  
  6267.         Flash = function(self)
  6268.             self.Visible = false
  6269.             Draw()
  6270.             sleep(0.15)
  6271.             self.Visible = true
  6272.             Draw()
  6273.             sleep(0.15)
  6274.             self.Visible = false
  6275.             Draw()
  6276.             sleep(0.15)
  6277.             self.Visible = true
  6278.             Draw()
  6279.         end,
  6280.  
  6281.         Click = function(self, side, x, y)
  6282.             local items = {self.OkButton, self.CancelButton}
  6283.             local found = false
  6284.             for i, v in ipairs(items) do
  6285.                 if CheckClick(v, x, y) then
  6286.                     v:Click(side, x, y)
  6287.                     found = true
  6288.                 end
  6289.             end
  6290.             return true
  6291.         end
  6292.     }
  6293.  
  6294.     TextDialougeWindow = {
  6295.         X = 1,
  6296.         Y = 1,
  6297.         Width = 0,
  6298.         Height = 0,
  6299.         CursorPos = 1,
  6300.         Visible = true,
  6301.         CancelButton = nil,
  6302.         OkButton = nil,
  6303.         Lines = {},
  6304.         TextInput = nil,
  6305.  
  6306.         AbsolutePosition = function(self)
  6307.             return {X = self.X, Y = self.Y}
  6308.         end,
  6309.  
  6310.         Draw = function(self)
  6311.             if not self.Visible then
  6312.                 return
  6313.             end
  6314.             Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  6315.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  6316.             Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  6317.             Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  6318.  
  6319.             for i, text in ipairs(self.Lines) do
  6320.                 Drawing.DrawCharacters(self.X + 1, self.Y + 1 + i, text, colours.black, colours.white)
  6321.             end
  6322.  
  6323.  
  6324.             Drawing.DrawBlankArea(self.X + 1, self.Y + self.Height - 4, self.Width - 2, 1, colours.lightGrey)
  6325.             Drawing.DrawCharacters(self.X + 2, self.Y + self.Height - 4, self.TextInput.Value, colours.black, colours.lightGrey)
  6326.             Current.CursorPos = {self.X + 2 + self.TextInput.CursorPos, self.Y + self.Height - 4}
  6327.             Current.CursorColour = colours.black
  6328.  
  6329.             self.OkButton:Draw()
  6330.             if self.CancelButton then
  6331.                 self.CancelButton:Draw()
  6332.             end
  6333.         end,
  6334.  
  6335.         Initialise = function(self, title, message, okText, cancelText, returnFunc, numerical)
  6336.             local new = {}    -- the new instance
  6337.             setmetatable( new, {__index = self} )
  6338.             new.Width = 28
  6339.             new.Lines = WrapText(message, new.Width - 2)
  6340.             new.Height = 7 + #new.Lines
  6341.             new.Return = returnFunc
  6342.             new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  6343.             new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  6344.             new.Title = title
  6345.             new.Visible = true
  6346.             new.Visible = true
  6347.             new.OkButton = Button:Initialise(new.Width - #okText - 2, new.Height - 1, nil, 1, nil, new, function()
  6348.                 if #new.TextInput.Value > 0 then
  6349.                     returnFunc(new, true, new.TextInput.Value)
  6350.                 end
  6351.             end, okText)
  6352.             if cancelText then
  6353.                 new.CancelButton = Button:Initialise(new.Width - #okText - 2 - 1 - #cancelText - 2, new.Height - 1, nil, 1, nil, new, function()
  6354.                     returnFunc(new, false)
  6355.                 end, cancelText)
  6356.             end
  6357.             new.TextInput = TextInput:Initialise('', function(enter)
  6358.                 if enter then
  6359.                     new.OkButton:Click()
  6360.                 end
  6361.                 Draw()
  6362.             end, numerical)
  6363.  
  6364.             Current.Input = new.TextInput
  6365.  
  6366.             return new
  6367.         end,
  6368.  
  6369.         Show = function(self)
  6370.             Current.Window = self
  6371.             return self
  6372.         end,
  6373.  
  6374.         Close = function(self)
  6375.             Current.Window = nil
  6376.             Current.Input = nil
  6377.             self = nil
  6378.         end,
  6379.  
  6380.         Flash = function(self)
  6381.             self.Visible = false
  6382.             Draw()
  6383.             sleep(0.15)
  6384.             self.Visible = true
  6385.             Draw()
  6386.             sleep(0.15)
  6387.             self.Visible = false
  6388.             Draw()
  6389.             sleep(0.15)
  6390.             self.Visible = true
  6391.             Draw()
  6392.         end,
  6393.  
  6394.         Click = function(self, side, x, y)
  6395.             local items = {self.OkButton, self.CancelButton}
  6396.             local found = false
  6397.             for i, v in ipairs(items) do
  6398.                 if CheckClick(v, x, y) then
  6399.                     v:Click(side, x, y)
  6400.                     found = true
  6401.                 end
  6402.             end
  6403.             return true
  6404.         end
  6405.     }
  6406.  
  6407.     ResizeDocumentWindow = {
  6408.         X = 1,
  6409.         Y = 1,
  6410.         Width = 0,
  6411.         Height = 0,
  6412.         CursorPos = 1,
  6413.         Visible = true,
  6414.         Return = nil,
  6415.         OkButton = nil,
  6416.         AnchorPosition = 5,
  6417.         WidthLabelHighlight = false,
  6418.         HeightLabelHighlight = false,
  6419.  
  6420.         AbsolutePosition = function(self)
  6421.             return {X = self.X, Y = self.Y}
  6422.         end,
  6423.  
  6424.         Draw = function(self)
  6425.             if not self.Visible then
  6426.                 return
  6427.             end
  6428.             Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  6429.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  6430.             Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  6431.             Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  6432.  
  6433.             Drawing.DrawCharacters(self.X+1, self.Y+2, "New Size", colours.lightGrey, colours.white)
  6434.             if (#self.WidthTextBox.TextInput.Value > 0 and tonumber(self.WidthTextBox.TextInput.Value) < Current.Artboard.Width) or (#self.HeightTextBox.TextInput.Value > 0 and tonumber(self.HeightTextBox.TextInput.Value) < Current.Artboard.Height) then
  6435.                 Drawing.DrawCharacters(self.X+1, self.Y+8, "Clipping will occur!", colours.red, colours.white)
  6436.             end
  6437.  
  6438.             local widthLabelColour = colours.black
  6439.             if self.WidthLabelHighlight then
  6440.                 widthLabelColour = colours.red
  6441.             end
  6442.            
  6443.             local heightLabelColour = colours.black
  6444.             if self.HeightLabelHighlight then
  6445.                 heightLabelColour = colours.red
  6446.             end
  6447.  
  6448.             Drawing.DrawCharacters(self.X+1, self.Y+4, "Width", widthLabelColour, colours.white)
  6449.             Drawing.DrawCharacters(self.X+1, self.Y+6, "Height", heightLabelColour, colours.white)
  6450.  
  6451.             Drawing.DrawCharacters(self.X+14, self.Y+2, "Anchor", colours.lightGrey, colours.white)
  6452.  
  6453.             self.WidthTextBox:Draw()
  6454.             self.HeightTextBox:Draw()
  6455.             self.OkButton:Draw()
  6456.             self.Anchor1:Draw()
  6457.             self.Anchor2:Draw()
  6458.             self.Anchor3:Draw()
  6459.             self.Anchor4:Draw()
  6460.             self.Anchor5:Draw()
  6461.             self.Anchor6:Draw()
  6462.             self.Anchor7:Draw()
  6463.             self.Anchor8:Draw()
  6464.             self.Anchor9:Draw()
  6465.         end,    
  6466.  
  6467.         Initialise = function(self, returnFunc)
  6468.             local new = {}    -- the new instance
  6469.             setmetatable( new, {__index = self} )
  6470.             new.Width = 27
  6471.             new.Height = 10
  6472.             new.Return = returnFunc
  6473.             new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  6474.             new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  6475.             new.Title = 'Resize Document'
  6476.             new.Visible = true
  6477.  
  6478.             new.WidthTextBox = TextBox:Initialise(9, 5, 4, 1, new, tostring(Current.Artboard.Width), nil, nil, function()
  6479.                 new:UpdateAnchorButtons()
  6480.             end, true)
  6481.             new.HeightTextBox = TextBox:Initialise(9, 7, 4, 1, new, tostring(Current.Artboard.Height), nil, nil, function()
  6482.                 new:UpdateAnchorButtons()
  6483.             end, true)
  6484.             new.OkButton = Button:Initialise(new.Width - 4, new.Height - 1, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  6485.                 local ok = true
  6486.                 new.WidthLabelHighlight = false
  6487.                 new.HeightLabelHighlight = false
  6488.  
  6489.                 if #new.WidthTextBox.TextInput.Value == 0 or tonumber(new.WidthTextBox.TextInput.Value) <= 0 then
  6490.                     ok = false
  6491.                     new.WidthLabelHighlight = true
  6492.                 end
  6493.  
  6494.                 if #new.HeightTextBox.TextInput.Value == 0 or tonumber(new.HeightTextBox.TextInput.Value) <= 0 then
  6495.                     ok = false
  6496.                     new.HeightLabelHighlight = true
  6497.                 end
  6498.  
  6499.                 if ok then
  6500.                     returnFunc(new, tonumber(new.WidthTextBox.TextInput.Value), tonumber(new.HeightTextBox.TextInput.Value), new.AnchorPosition)
  6501.                 else
  6502.                     Draw()
  6503.                 end
  6504.             end, 'Ok', colours.black)
  6505.  
  6506.             local anchorX = 15
  6507.             local anchorY = 5
  6508.             new.Anchor1 = Button:Initialise(anchorX, anchorY, 1, 1, colours.lightGrey, new, function(self, side, x, y, toggle)new.AnchorPosition = 1 new:UpdateAnchorButtons() end, ' ', colours.black)
  6509.             new.Anchor2 = Button:Initialise(anchorX+1, anchorY, 1, 1, colours.lightGrey, new, function(self, side, x, y, toggle)new.AnchorPosition = 2 new:UpdateAnchorButtons() end, '^', colours.black)
  6510.             new.Anchor3 = Button:Initialise(anchorX+2, anchorY, 1, 1, colours.lightGrey, new, function(self, side, x, y, toggle)new.AnchorPosition = 3 new:UpdateAnchorButtons() end, ' ', colours.black)
  6511.             new.Anchor4 = Button:Initialise(anchorX, anchorY+1, 1, 1, colours.lightGrey, new, function(self, side, x, y, toggle)new.AnchorPosition = 4 new:UpdateAnchorButtons() end, '<', colours.black)
  6512.             new.Anchor5 = Button:Initialise(anchorX+1, anchorY+1, 1, 1, colours.lightGrey, new, function(self, side, x, y, toggle)new.AnchorPosition = 5 new:UpdateAnchorButtons() end, '#', colours.black)
  6513.             new.Anchor6 = Button:Initialise(anchorX+2, anchorY+1, 1, 1, colours.lightGrey, new, function(self, side, x, y, toggle)new.AnchorPosition = 6 new:UpdateAnchorButtons() end, '>', colours.black)
  6514.             new.Anchor7 = Button:Initialise(anchorX, anchorY+2, 1, 1, colours.lightGrey, new, function(self, side, x, y, toggle)new.AnchorPosition = 7 new:UpdateAnchorButtons() end, ' ', colours.black)
  6515.             new.Anchor8 = Button:Initialise(anchorX+1, anchorY+2, 1, 1, colours.lightGrey, new, function(self, side, x, y, toggle)new.AnchorPosition = 8 new:UpdateAnchorButtons() end, 'v', colours.black)
  6516.             new.Anchor9 = Button:Initialise(anchorX+2, anchorY+2, 1, 1, colours.lightGrey, new, function(self, side, x, y, toggle)new.AnchorPosition = 9 new:UpdateAnchorButtons() end, ' ', colours.black)
  6517.  
  6518.             return new
  6519.         end,
  6520.  
  6521.         UpdateAnchorButtons = function(self)
  6522.             local anchor1 = ' '
  6523.             local anchor2 = ' '
  6524.             local anchor3 = ' '
  6525.             local anchor4 = ' '
  6526.             local anchor5 = ' '
  6527.             local anchor6 = ' '
  6528.             local anchor7 = ' '
  6529.             local anchor8 = ' '
  6530.             local anchor9 = ' '
  6531.             self.AnchorPosition = self.AnchorPosition or 5
  6532.             if self.AnchorPosition == 1 then
  6533.                 anchor1 = '#'
  6534.                 anchor2 = '>'
  6535.                 anchor4 = 'v'
  6536.             elseif self.AnchorPosition == 2 then
  6537.                 anchor1 = '<'
  6538.                 anchor2 = '#'
  6539.                 anchor3 = '>'
  6540.                 anchor5 = 'v'
  6541.             elseif self.AnchorPosition == 3 then
  6542.                 anchor2 = '<'
  6543.                 anchor3 = '#'
  6544.                 anchor6 = 'v'
  6545.             elseif self.AnchorPosition == 4 then
  6546.                 anchor1 = '^'
  6547.                 anchor4 = '#'
  6548.                 anchor5 = '>'
  6549.                 anchor7 = 'v'
  6550.             elseif self.AnchorPosition == 5 then
  6551.                 anchor2 = '^'
  6552.                 anchor4 = '<'
  6553.                 anchor5 = '#'
  6554.                 anchor6 = '>'
  6555.                 anchor8 = 'v'
  6556.             elseif self.AnchorPosition == 6 then
  6557.                 anchor3 = '^'
  6558.                 anchor6 = '#'
  6559.                 anchor5 = '<'
  6560.                 anchor9 = 'v'
  6561.             elseif self.AnchorPosition == 7 then
  6562.                 anchor4 = '^'
  6563.                 anchor7 = '#'
  6564.                 anchor8 = '>'
  6565.             elseif self.AnchorPosition == 8 then
  6566.                 anchor5 = '^'
  6567.                 anchor8 = '#'
  6568.                 anchor7 = '<'
  6569.                 anchor9 = '>'
  6570.             elseif self.AnchorPosition == 9 then
  6571.                 anchor6 = '^'
  6572.                 anchor9 = '#'
  6573.                 anchor8 = '<'
  6574.             end
  6575.  
  6576.             if #self.HeightTextBox.TextInput.Value > 0 and Current.Artboard.Height > tonumber(self.HeightTextBox.TextInput.Value) then
  6577.                 local r = function(str)
  6578.                     if string.find(str, "%^") then
  6579.                         str = str:gsub('%^','v')
  6580.                     elseif string.find(str, "v") then
  6581.                         str = str:gsub('v','%^')
  6582.                     end
  6583.                     return str
  6584.                 end
  6585.                 anchor1 = r(anchor1)
  6586.                 anchor2 = r(anchor2)
  6587.                 anchor3 = r(anchor3)
  6588.                 anchor4 = r(anchor4)
  6589.                 anchor5 = r(anchor5)
  6590.                 anchor6 = r(anchor6)
  6591.                 anchor7 = r(anchor7)
  6592.                 anchor8 = r(anchor8)
  6593.                 anchor9 = r(anchor9)
  6594.             end
  6595.  
  6596.             if #self.WidthTextBox.TextInput.Value > 0 and Current.Artboard.Width > tonumber(self.WidthTextBox.TextInput.Value) then
  6597.                 local r = function(str)
  6598.                     if string.find(str, ">") then
  6599.                         str = str:gsub('>','<')
  6600.                     elseif string.find(str, "<") then
  6601.                         str = str:gsub('<','>')
  6602.                     end
  6603.                     return str
  6604.                 end
  6605.                 anchor1 = r(anchor1)
  6606.                 anchor2 = r(anchor2)
  6607.                 anchor3 = r(anchor3)
  6608.                 anchor4 = r(anchor4)
  6609.                 anchor5 = r(anchor5)
  6610.                 anchor6 = r(anchor6)
  6611.                 anchor7 = r(anchor7)
  6612.                 anchor8 = r(anchor8)
  6613.                 anchor9 = r(anchor9)
  6614.             end
  6615.  
  6616.             self.Anchor1.Text = anchor1
  6617.             self.Anchor2.Text = anchor2
  6618.             self.Anchor3.Text = anchor3
  6619.             self.Anchor4.Text = anchor4
  6620.             self.Anchor5.Text = anchor5
  6621.             self.Anchor6.Text = anchor6
  6622.             self.Anchor7.Text = anchor7
  6623.             self.Anchor8.Text = anchor8
  6624.             self.Anchor9.Text = anchor9
  6625.         end,
  6626.  
  6627.         Show = function(self)
  6628.             Current.Window = self
  6629.             return self
  6630.         end,
  6631.  
  6632.         Close = function(self)
  6633.             Current.Input = nil
  6634.             Current.Window = nil
  6635.             self = nil
  6636.         end,
  6637.  
  6638.         Flash = function(self)
  6639.             self.Visible = false
  6640.             Draw()
  6641.             sleep(0.15)
  6642.             self.Visible = true
  6643.             Draw()
  6644.             sleep(0.15)
  6645.             self.Visible = false
  6646.             Draw()
  6647.             sleep(0.15)
  6648.             self.Visible = true
  6649.             Draw()
  6650.         end,
  6651.  
  6652.         ButtonClick = function(self, button, x, y)
  6653.             if button.X <= x and button.Y <= y and button.X + button.Width > x and button.Y + button.Height > y then
  6654.                 button:Click()
  6655.             end
  6656.         end,
  6657.  
  6658.         Click = function(self, side, x, y)
  6659.             local items = {self.OkButton, self.WidthTextBox, self.HeightTextBox, self.Anchor1, self.Anchor2, self.Anchor3, self.Anchor4, self.Anchor5, self.Anchor6, self.Anchor7, self.Anchor8, self.Anchor9}
  6660.             for i, v in ipairs(items) do
  6661.                 if CheckClick(v, x, y) then
  6662.                     v:Click(side, x, y)
  6663.                 end
  6664.             end
  6665.             return true
  6666.         end
  6667.     }
  6668.  
  6669.     ----------------------
  6670.  
  6671.     function CheckOpenArtboard()
  6672.         if Current.Artboard then
  6673.             return true
  6674.         else
  6675.             return false
  6676.         end
  6677.     end
  6678.  
  6679.     function CheckSelectedLayer()
  6680.         if Current.Artboard and Current.Layer then
  6681.             return true
  6682.         else
  6683.             return false
  6684.         end
  6685.     end
  6686.  
  6687.     function DisplayNewDocumentWindow()
  6688.         NewDocumentWindow:Initialise(function(self, success, path, width, height, format, backgroundColour)
  6689.             if success then
  6690.                 if path:sub(-4) ~= format then
  6691.                     path = path .. format
  6692.                 end
  6693.                 local oldWindow = self
  6694.                 Current.Input = nil
  6695.                 Current.Window = nil
  6696.                 makeDocument = function()oldWindow:Close()NewDocument(path, width, height, format, backgroundColour)end
  6697.                 local _fs = fs
  6698.                 if OneOS then
  6699.                     _fs = OneOS.FS
  6700.                 end
  6701.                 if _fs.exists(path) then
  6702.                     ButtonDialougeWindow:Initialise('File Exists', path..' already exists! Use a different name and try again.', 'Ok', nil, function(window, ok)
  6703.                         window:Close()
  6704.                         oldWindow:Show()
  6705.                     end):Show()
  6706.                 elseif format == '.nfp' then
  6707.                     Current.Window = nil
  6708.                     ButtonDialougeWindow:Initialise('Use NFP?', 'The NFT format does not support text or layers, if you use it you will only be able to use 1 layer and not have any text.', 'Use NFP', 'Cancel', function(window, ok)
  6709.                         window:Close()
  6710.                         if ok then
  6711.                             makeDocument()
  6712.                         else
  6713.                             oldWindow:Show()
  6714.                         end
  6715.                     end):Show()
  6716.                 elseif format == '.nft' then
  6717.                     ButtonDialougeWindow:Initialise('Use NFT?', 'The NFT format does not support layers, if you use it you will only be able to use 1 layer.', 'Use NFT', 'Cancel', function(window, ok)
  6718.                         window:Close()
  6719.                         if ok then
  6720.                             makeDocument()
  6721.                         else
  6722.                             oldWindow:Show()
  6723.                         end
  6724.                     end):Show()
  6725.                 else
  6726.                     makeDocument()
  6727.                 end
  6728.  
  6729.                
  6730.             else
  6731.                 self:Close()
  6732.             end
  6733.         end):Show()
  6734.     end
  6735.  
  6736.     function NewDocument(path, width, height, format, backgroundColour)
  6737.         local _fs = fs
  6738.         if OneOS then
  6739.             _fs = OneOS.FS
  6740.         end
  6741.         ab = Artboard:New(_fs.getName(path), path, width, height, format, backgroundColour)
  6742.         Current.Tool = Tools[2]
  6743.         Current.Toolbar:Update()
  6744.         Current.Modified = false
  6745.         Draw()
  6746.     end
  6747.  
  6748.     function DisplayToolSizeWindow()
  6749.         if not CheckOpenArtboard() then
  6750.             return
  6751.         end
  6752.         TextDialougeWindow:Initialise('Change Tool Size', 'Enter the new tool size you\'d like to use.', 'Ok', 'Cancel', function(window, success, value)
  6753.             if success then
  6754.                 Current.ToolSize = math.ceil(tonumber(value))
  6755.                 if Current.ToolSize < 1 then
  6756.                     Current.ToolSize = 1
  6757.                 elseif Current.ToolSize > 50 then
  6758.                     Current.ToolSize = 50
  6759.                 end
  6760.                 ModuleNamed('Tools'):Update()
  6761.             end
  6762.             window:Close()
  6763.         end, true):Show()  
  6764.     end
  6765.  
  6766.     --[[
  6767.         Attempt to figure out what format the image is if it doesn't have an extension
  6768.     ]]--
  6769.     function GetFormat(path)
  6770.         local _fs = fs
  6771.         if OneOS then
  6772.             _fs = OneOS.FS
  6773.         end
  6774.         local file = _fs.open(path, 'r')
  6775.         local content = file.readAll()
  6776.         file.close()
  6777.         if type(textutils.unserialize(content)) == 'table' then
  6778.             -- It's a serlized table, asume sketch
  6779.             return '.skch'
  6780.         elseif string.find(content, string.char(30)) or string.find(content, string.char(31)) then
  6781.             -- Contains the characters that set colours, asume nft
  6782.             return '.nft'
  6783.         else
  6784.             -- Otherwise asume nfp
  6785.             return '.nfp'
  6786.         end
  6787.     end
  6788.  
  6789.     function DisplayOpenDocumentWindow()
  6790.         OpenDocumentWindow:Initialise(function(self, success, path)
  6791.             self:Close()
  6792.             if success then
  6793.                 OpenDocument(path)
  6794.             end
  6795.         end):Show()
  6796.     end
  6797.  
  6798.  
  6799.     local function Extension(path, addDot)
  6800.         if not path then
  6801.             return nil
  6802.         elseif not string.find(fs.getName(path), '%.') then
  6803.             if not addDot then
  6804.                 return fs.getName(path)
  6805.             else
  6806.                 return ''
  6807.             end
  6808.         else
  6809.             local _path = path
  6810.             if path:sub(#path) == '/' then
  6811.                 _path = path:sub(1,#path-1)
  6812.             end
  6813.             local extension = _path:gmatch('[0-9a-z]+$')()
  6814.             if extension then
  6815.                 extension = extension:sub(2)
  6816.             else
  6817.                 --extension = nil
  6818.                 return ''
  6819.             end
  6820.             if addDot then
  6821.                 extension = '.'..extension
  6822.             end
  6823.             return extension:lower()
  6824.         end
  6825.     end
  6826.  
  6827.     local RemoveExtension = function(path)
  6828.         if path:sub(1,1) == '.' then
  6829.             return path
  6830.         end
  6831.         local extension = Extension(path)
  6832.         if extension == path then
  6833.             return fs.getName(path)
  6834.         end
  6835.         return string.gsub(path, extension, ''):sub(1, -2)
  6836.     end
  6837.     --[[
  6838.         Open a documet at a given path
  6839.     ]]--
  6840.     function OpenDocument(path)
  6841.         local _fs = fs
  6842.         if OneOS then
  6843.             _fs = OneOS.FS
  6844.         end
  6845.         if _fs.exists(path) and not _fs.isDir(path) then
  6846.             local format = Extension(path, true)
  6847.             if (not format or format == '') and (format ~= '.nfp' and format ~= '.nft' and format ~= '.skch') then
  6848.                 format = GetFormat(path)
  6849.             end
  6850.             local layers = {}
  6851.             if format == '.nfp' then
  6852.                 layers = ReadNFP(path)
  6853.             elseif format == '.nft' then
  6854.                 layers = ReadNFT(path)      
  6855.             elseif format == '.skch' then
  6856.                 layers = ReadSKCH(path)
  6857.             end
  6858.  
  6859.             for i, layer in ipairs(layers) do
  6860.                 if layer.Visible == nil then
  6861.                     layer.Visible = true
  6862.                 end
  6863.                 if layer.Index == nil then
  6864.                     layer.Index = 1
  6865.                 end
  6866.                 if layer.Name == nil then
  6867.                     if layer.Index == 1 then
  6868.                         layer.Name = 'Background'
  6869.                     else
  6870.                         layer.Name = 'Layer'
  6871.                     end
  6872.                 end
  6873.                 if layer.BackgroundColour == nil then
  6874.                     layer.BackgroundColour = colours.white
  6875.                 end
  6876.             end
  6877.  
  6878.             if not layers[1] then
  6879.                 --log('File could not be read.')
  6880.                 return
  6881.             end
  6882.  
  6883.             local width = #layers[1].Pixels
  6884.             local height = #layers[1].Pixels[1]
  6885.  
  6886.             Current.Artboard = nil
  6887.             local _fs = fs
  6888.             if OneOS then
  6889.                 _fs = OneOS.FS
  6890.             end
  6891.             ab = Artboard:New(_fs.getName('Image'), path, width, height, format, nil, layers)
  6892.             Current.Tool = Tools[2]
  6893.             Current.Toolbar:Update()
  6894.             Current.Modified = false
  6895.             Draw()
  6896.         end
  6897.     end
  6898.  
  6899.     function MakeNewLayer()
  6900.         if not CheckOpenArtboard() then
  6901.             return
  6902.         end
  6903.         if Current.Artboard.Format == '.skch' then
  6904.             TextDialougeWindow:Initialise('New Layer Name', 'Enter the name you want for the next layer.', 'Ok', 'Cancel', function(window, success, value)
  6905.                 if success then
  6906.                     Current.Artboard:MakeLayer(value, colours.transparent)
  6907.                 end
  6908.                 window:Close()
  6909.             end):Show()
  6910.         else
  6911.             local format = 'NFP'
  6912.             if Current.Artboard.Format == '.nft' then
  6913.                 format = 'NFT'
  6914.             end
  6915.             ButtonDialougeWindow:Initialise(format..' does not support layers!', 'The format you are using, '..format..', does not support multiple layers. Use SKCH to have more than one layer.', 'Ok', nil, function(window)
  6916.                 window:Close()
  6917.             end):Show()
  6918.         end
  6919.     end
  6920.  
  6921.     function ResizeDocument()
  6922.         if not CheckOpenArtboard() then
  6923.             return
  6924.         end
  6925.         ResizeDocumentWindow:Initialise(function(window, width, height, anchor)
  6926.             window:Close()
  6927.             local topResize = 0
  6928.             local rightResize = 0
  6929.             local bottomResize = 0
  6930.             local leftResize = 0
  6931.  
  6932.             if anchor == 1 then
  6933.                 rightResize = 1
  6934.                 bottomResize = 1
  6935.             elseif anchor == 2 then
  6936.                 rightResize = 0.5
  6937.                 leftResize = 0.5
  6938.                 bottomResize = 1
  6939.             elseif anchor == 3 then
  6940.                 leftResize = 1
  6941.                 bottomResize = 1
  6942.             elseif anchor == 4 then
  6943.                 rightResize = 1
  6944.                 bottomResize = 0.5
  6945.                 topResize = 0.5
  6946.             elseif anchor == 5 then
  6947.                 rightResize = 0.5
  6948.                 leftResize = 0.5
  6949.                 bottomResize = 0.5
  6950.                 topResize = 0.5
  6951.             elseif anchor == 6 then
  6952.                 leftResize = 1
  6953.                 bottomResize = 0.5
  6954.                 topResize = 0.5
  6955.             elseif anchor == 7 then
  6956.                 rightResize = 1
  6957.                 topResize = 1
  6958.             elseif anchor == 8 then
  6959.                 rightResize = 0.5
  6960.                 leftResize = 0.5
  6961.                 topResize = 1
  6962.             elseif anchor == 9 then
  6963.                 leftResize = 1
  6964.                 topResize = 1
  6965.             end
  6966.  
  6967.             topResize = topResize * (height - Current.Artboard.Height)
  6968.             if topResize > 0 then
  6969.                 topResize = math.floor(topResize)
  6970.             else
  6971.                 topResize = math.ceil(topResize)
  6972.             end
  6973.  
  6974.             bottomResize = bottomResize * (height - Current.Artboard.Height)
  6975.             if bottomResize > 0 then
  6976.                 bottomResize = math.ceil(bottomResize)
  6977.             else
  6978.                 bottomResize = math.floor(bottomResize)
  6979.             end
  6980.  
  6981.             leftResize = leftResize * (width - Current.Artboard.Width)
  6982.             if leftResize > 0 then
  6983.                 leftResize = math.floor(leftResize)
  6984.             else
  6985.                 leftResize = math.ceil(leftResize)
  6986.             end
  6987.  
  6988.             rightResize = rightResize * (width - Current.Artboard.Width)
  6989.             if rightResize > 0 then
  6990.                 rightResize = math.ceil(rightResize)
  6991.             else
  6992.                 rightResize = math.floor(rightResize)
  6993.             end
  6994.  
  6995.             Current.Artboard:Resize(topResize, bottomResize, leftResize, rightResize)
  6996.         end):Show()
  6997.     end
  6998.  
  6999.     function RenameLayer()
  7000.         if not CheckOpenArtboard() then
  7001.             return
  7002.         end
  7003.         if Current.Artboard.Format == '.skch' then
  7004.             TextDialougeWindow:Initialise("Rename Layer '"..Current.Layer.Name.."'", 'Enter the new name you want the layer to be called.', 'Ok', 'Cancel', function(window, success, value)
  7005.                 if success then
  7006.                     Current.Layer.Name = value
  7007.                 end
  7008.                 window:Close()
  7009.             end):Show()
  7010.         else
  7011.             local format = 'NFP'
  7012.             if Current.Artboard.Format == '.nft' then
  7013.                 format = 'NFT'
  7014.             end
  7015.             ButtonDialougeWindow:Initialise(format..' does not support layers!', 'The format you are using, '..format..', does not support renaming layers. Use SKCH to rename layers.', 'Ok', nil, function(window)
  7016.                 window:Close()
  7017.             end):Show()
  7018.         end
  7019.     end
  7020.  
  7021.     function DeleteLayer()
  7022.         if not CheckOpenArtboard() then
  7023.             return
  7024.         end
  7025.         if Current.Artboard.Format == '.skch' then
  7026.             if #Current.Artboard.Layers > 1 then
  7027.                 ButtonDialougeWindow:Initialise("Delete Layer '"..Current.Layer.Name.."'?", 'Are you sure you want delete the layer?', 'Ok', 'Cancel', function(window, success)
  7028.                     if success then
  7029.                         Current.Layer:Remove()
  7030.                     end
  7031.                     window:Close()
  7032.                 end):Show()
  7033.             else
  7034.                 ButtonDialougeWindow:Initialise('Can not delete layer!', 'You can not delete the last layer of an image! Make another layer to delete this one.', 'Ok', nil, function(window)
  7035.                     window:Close()
  7036.                 end):Show()
  7037.             end
  7038.         else
  7039.             local format = 'NFP'
  7040.             if Current.Artboard.Format == '.nft' then
  7041.                 format = 'NFT'
  7042.             end
  7043.             ButtonDialougeWindow:Initialise(format..' does not support layers!', 'The format you are using, '..format..', does not support deleting layers. Use SKCH to deleting layers.', 'Ok', nil, function(window)
  7044.                 window:Close()
  7045.             end):Show()
  7046.         end
  7047.     end
  7048.  
  7049.     needsDraw = false
  7050.     isDrawing = false
  7051.     function Draw()
  7052.         if isDrawing then
  7053.             needsDraw = true
  7054.             return
  7055.         end
  7056.         needsDraw = false
  7057.         isDrawing = true
  7058.         if not Current.Window then
  7059.             Drawing.Clear(UIColours.Background)
  7060.         else
  7061.             Drawing.DrawArea(1, 2, Drawing.Screen.Width, Drawing.Screen.Height, '|', colours.black, colours.lightGrey)
  7062.         end
  7063.  
  7064.         if Current.Artboard then
  7065.             ab:Draw()
  7066.         end
  7067.  
  7068.         if Current.InterfaceVisible then
  7069.             Current.MenuBar:Draw()
  7070.             Current.Toolbar.Width = Current.Toolbar.ExpandedWidth
  7071.             Current.Toolbar:Draw()
  7072.         else
  7073.             Current.Toolbar.Width = Current.Toolbar.ExpandedWidth
  7074.         end
  7075.  
  7076.         if Current.InterfaceVisible and Current.Menu then
  7077.             Current.Menu:Draw()
  7078.         end
  7079.  
  7080.         if Current.Window then
  7081.             Current.Window:Draw()
  7082.         end
  7083.  
  7084.         if not Current.InterfaceVisible then
  7085.             ShowInterfaceButton:Draw()
  7086.         end
  7087.  
  7088.         Drawing.DrawBuffer()
  7089.         if Current.Input and not Current.Menu then
  7090.             term.setCursorPos(Current.CursorPos[1], Current.CursorPos[2])
  7091.             term.setCursorBlink(true)
  7092.             term.setTextColour(Current.CursorColour)
  7093.         else
  7094.             term.setCursorBlink(false)
  7095.         end
  7096.  
  7097.         if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  7098.             Current.SelectionDrawTimer = os.startTimer(0.5)
  7099.         end
  7100.         isDrawing = false
  7101.         if needsDraw then
  7102.             Draw()
  7103.         end
  7104.     end
  7105.  
  7106.     function LoadMenuBar()
  7107.         Current.MenuBar = MenuBar:Initialise({
  7108.             Button:Initialise(1, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  7109.                 if toggle then
  7110.                     Menu:New(1, 2, {
  7111.                         {
  7112.                             Title = "New...",
  7113.                             Click = function()
  7114.                                 DisplayNewDocumentWindow()
  7115.                             end,
  7116.                             Keys = {
  7117.                                 keys.leftCtrl,
  7118.                                 keys.n
  7119.                             }
  7120.                         },
  7121.                         {
  7122.                             Title = 'Open...',
  7123.                             Click = function()
  7124.                                 DisplayOpenDocumentWindow()
  7125.                             end,
  7126.                             Keys = {
  7127.                                 keys.leftCtrl,
  7128.                                 keys.o
  7129.                             }
  7130.                         },
  7131.                         {
  7132.                             Separator = true
  7133.                         },
  7134.                         {
  7135.                             Title = 'Save...',
  7136.                             Click = function()
  7137.                                 Current.Artboard:Save()
  7138.                             end,
  7139.                             Keys = {
  7140.                                 keys.leftCtrl,
  7141.                                 keys.s
  7142.                             },
  7143.                             Enabled = function()
  7144.                                 return CheckOpenArtboard()
  7145.                             end
  7146.                         },
  7147.                         {
  7148.                             Separator = true
  7149.                         },
  7150.                         {
  7151.                             Title = 'Quit',
  7152.                             Click = function()
  7153.                                 if Close() then
  7154.                                     OneOS.Close()
  7155.                                 end
  7156.                             end
  7157.                         },
  7158.                 --[[
  7159.                         {
  7160.                             Title = 'Save As...',
  7161.                             Click = function()
  7162.  
  7163.                             end
  7164.                         }  
  7165.                 ]]--
  7166.                     }, self, true)
  7167.                 else
  7168.                     Current.Menu = nil
  7169.                 end
  7170.                 return true
  7171.             end, 'File', colours.lightGrey, false),
  7172.             Button:Initialise(7, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  7173.                 if not self.Toggle then
  7174.                     Menu:New(7, 2, {
  7175.                 --[[
  7176.                         {
  7177.                             Title = "Undo",
  7178.                             Click = function()
  7179.                             end,
  7180.                             Keys = {
  7181.                                 keys.leftCtrl,
  7182.                                 keys.z
  7183.                             },
  7184.                             Enabled = function()
  7185.                                 return false
  7186.                             end
  7187.                         },
  7188.                         {
  7189.                             Title = 'Redo',
  7190.                             Click = function()
  7191.                                
  7192.                             end,
  7193.                             Keys = {
  7194.                                 keys.leftCtrl,
  7195.                                 keys.y
  7196.                             },
  7197.                             Enabled = function()
  7198.                                 return false
  7199.                             end
  7200.                         },
  7201.                         {
  7202.                             Separator = true
  7203.                         },
  7204.                 ]]--
  7205.                         {
  7206.                             Title = 'Cut',
  7207.                             Click = function()
  7208.                                 Clipboard.Cut(Current.Layer:PixelsInSelection(true), 'sketchpixels')
  7209.                             end,
  7210.                             Keys = {
  7211.                                 keys.leftCtrl,
  7212.                                 keys.x
  7213.                             },
  7214.                             Enabled = function()
  7215.                                 return Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil
  7216.                             end
  7217.                         },
  7218.                         {
  7219.                             Title = 'Copy',
  7220.                             Click = function()
  7221.                                 Clipboard.Copy(Current.Layer:PixelsInSelection(), 'sketchpixels')
  7222.                             end,
  7223.                             Keys = {
  7224.                                 keys.leftCtrl,
  7225.                                 keys.c
  7226.                             },
  7227.                             Enabled = function()
  7228.                                 return Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil
  7229.                             end
  7230.                         },
  7231.                         {
  7232.                             Title = 'Paste',
  7233.                             Click = function()
  7234.                                 Current.Layer:InsertPixels(Clipboard.Paste())
  7235.                             end,
  7236.                             Keys = {
  7237.                                 keys.leftCtrl,
  7238.                                 keys.v
  7239.                             },
  7240.                             Enabled = function()
  7241.                                 return (not Clipboard.isEmpty()) and Clipboard.Type == 'sketchpixels'
  7242.                             end
  7243.                         }
  7244.                     }, self, true)
  7245.                 else
  7246.                     Current.Menu = nil
  7247.                 end
  7248.                 return true
  7249.             end, 'Edit', colours.lightGrey, false),
  7250.             Button:Initialise(13, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  7251.                 if toggle then
  7252.                     Menu:New(13, 2, {
  7253.                         {
  7254.                             Title = "Resize...",
  7255.                             Click = function()
  7256.                                 ResizeDocument()
  7257.                             end,
  7258.                             Keys = {
  7259.                                 keys.leftCtrl,
  7260.                                 keys.r
  7261.                             },
  7262.                             Enabled = function()
  7263.                                 return CheckOpenArtboard()
  7264.                             end
  7265.                         },
  7266.                         {
  7267.                             Title = "Crop",
  7268.                             Click = function()
  7269.                                 local top = 0
  7270.                                 local left = 0
  7271.                                 local bottom = 0
  7272.                                 local right = 0
  7273.                                 if Current.Selection[1].x < Current.Selection[2].x then
  7274.                                     left = Current.Selection[1].x - 1
  7275.                                     right = Current.Artboard.Width - Current.Selection[2].x
  7276.                                 else
  7277.                                     left = Current.Selection[2].x - 1
  7278.                                     right = Current.Artboard.Width - Current.Selection[1].x
  7279.                                 end
  7280.                                 if Current.Selection[1].y < Current.Selection[2].y then
  7281.                                     top = Current.Selection[1].y - 1
  7282.                                     bottom = Current.Artboard.Height - Current.Selection[2].y
  7283.                                 else
  7284.                                     top = Current.Selection[2].y - 1
  7285.                                     bottom = Current.Artboard.Height - Current.Selection[1].y
  7286.                                 end
  7287.                                 Current.Artboard:Resize(-1*top, -1*bottom, -1*left, -1*right)
  7288.  
  7289.                                 Current.Selection[2] = nil
  7290.                             end,
  7291.                             Enabled = function()
  7292.                                 if CheckSelectedLayer() and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  7293.                                     return true
  7294.                                 else
  7295.                                     return false
  7296.                                 end
  7297.                             end
  7298.                         },
  7299.                         {
  7300.                             Separator = true
  7301.                         },
  7302.                         {
  7303.                             Title = 'New Layer...',
  7304.                             Click = function()
  7305.                                 MakeNewLayer()
  7306.                             end,
  7307.                             Keys = {
  7308.                                 keys.leftCtrl,
  7309.                                 keys.l
  7310.                             },
  7311.                             Enabled = function()
  7312.                                 return CheckOpenArtboard()
  7313.                             end
  7314.                         },
  7315.                         {
  7316.                             Title = 'Delete Layer',
  7317.                             Click = function()
  7318.                                 DeleteLayer()
  7319.                             end,
  7320.                             Enabled = function()
  7321.                                 return CheckSelectedLayer()
  7322.                             end
  7323.                         },
  7324.                         {
  7325.                             Title = 'Rename Layer...',
  7326.                             Click = function()
  7327.                                 RenameLayer()
  7328.                             end,
  7329.                             Enabled = function()
  7330.                                 return CheckSelectedLayer()
  7331.                             end
  7332.                         },
  7333.                         {
  7334.                             Separator = true
  7335.                         },
  7336.                         {
  7337.                             Title = 'Erase Selection',
  7338.                             Click = function()
  7339.                                 Current.Layer:EraseSelection()
  7340.                             end,
  7341.                             Keys = {
  7342.                                 keys.delete
  7343.                             },
  7344.                             Enabled = function()
  7345.                                 if CheckSelectedLayer() and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  7346.                                     return true
  7347.                                 else
  7348.                                     return false
  7349.                                 end
  7350.                             end
  7351.                         },
  7352.                         {
  7353.                             Separator = true
  7354.                         },
  7355.                         {
  7356.                             Title = 'Hide Interface',
  7357.                             Click = function()
  7358.                                 Current.InterfaceVisible = not Current.InterfaceVisible
  7359.                             end,
  7360.                             Keys = {
  7361.                                 keys.tab
  7362.                             }
  7363.                         }
  7364.                     }, self, true)
  7365.                 else
  7366.                     Current.Menu = nil
  7367.                 end
  7368.                 return true
  7369.             end, 'Image', colours.lightGrey, false),
  7370.            
  7371.             Button:Initialise(20, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  7372.                 if toggle then
  7373.                     local menuItems = {{
  7374.                             Title = "Change Size",
  7375.                             Click = function()
  7376.                                 DisplayToolSizeWindow()
  7377.                             end,
  7378.                             Keys = {
  7379.                                 keys.leftCtrl,
  7380.                                 keys.t
  7381.                             }
  7382.                         },
  7383.                         {
  7384.                             Separator = true
  7385.                         }
  7386.                     }
  7387.                    
  7388.                     local _keys = {'h','p','e','f','s','m','t'}
  7389.                     for i, tool in ipairs(Tools) do
  7390.                         table.insert(menuItems, {
  7391.                             Title = tool.Name,
  7392.                             Click = function()
  7393.                                 SetTool(tool)
  7394.                                 local m = ModuleNamed('Tools')
  7395.                                 m:Update(m.ToolbarItem)
  7396.                             end,
  7397.                             Keys = {
  7398.                                 keys[_keys[i]]
  7399.                             },
  7400.                             Enabled = function()
  7401.                                 return CheckOpenArtboard()
  7402.                             end
  7403.                         })
  7404.                     end
  7405.  
  7406.                     Menu:New(20, 2, menuItems, self, true)
  7407.                 else
  7408.                     Current.Menu = nil
  7409.                 end
  7410.                 return true
  7411.             end, 'Tools', colours.lightGrey, false),
  7412.         })
  7413.     end
  7414.  
  7415.     function Timer(event, timer)
  7416.         if timer == Current.ControlPressedTimer then
  7417.             Current.ControlPressedTimer = nil
  7418.         elseif timer == Current.SelectionDrawTimer then
  7419.             if Current.Artboard then
  7420.                 Current.Artboard.SelectionIsBlack = not Current.Artboard.SelectionIsBlack
  7421.                 Draw()
  7422.             end
  7423.         end
  7424.     end
  7425.  
  7426.     function Initialise(arg)
  7427.         if not OneOS then
  7428.             SplashScreen()
  7429.         end
  7430.         EventRegister('mouse_click', TryClick)
  7431.         EventRegister('mouse_drag', function(event, side, x, y)TryClick(event, side, x, y, true)end)
  7432.         EventRegister('mouse_scroll', Scroll)
  7433.         EventRegister('key', HandleKey)
  7434.         EventRegister('char', HandleKey)
  7435.         EventRegister('timer', Timer)
  7436.         EventRegister('terminate', function(event) if Close() then error( "Terminated", 0 ) end end)
  7437.  
  7438.  
  7439.         Current.Toolbar = Toolbar:New('right', true)
  7440.  
  7441.         for k, v in pairs(Modules) do
  7442.             v:Initialise()
  7443.         end
  7444.        
  7445.         --term.setBackgroundColour(UIColours.Background)
  7446.         --term.clear()
  7447.  
  7448.         LoadMenuBar()
  7449.  
  7450.         local _fs = fs
  7451.         if OneOS then
  7452.             _fs = OneOS.FS
  7453.         end
  7454.         if arg and _fs.exists(arg) then
  7455.             OpenDocument(arg)
  7456.         else
  7457.             DisplayNewDocumentWindow()
  7458.             Current.Window.Visible = false
  7459.         end
  7460.  
  7461.         ShowInterfaceButton = Button:Initialise(Drawing.Screen.Width - 15, 1, nil, 1, colours.grey, nil, function(self)
  7462.             Current.InterfaceVisible = true
  7463.             Draw()
  7464.         end, 'Show Interface')
  7465.  
  7466.         Draw()
  7467.         if Current.Window then
  7468.             Current.Window.Visible = true
  7469.             Draw()
  7470.         end
  7471.  
  7472.         EventHandler()
  7473.     end
  7474.  
  7475.     function SplashScreen()
  7476.         local splashIcon = {{1,1,1,256,256,256,256,256,256,256,256,1,1,1,},{1,256,256,8,8,8,8,8,8,8,8,256,256,1,},{256,8,8,8,8,8,8,8,8,8,8,8,8,256,},{256,256,256,8,8,8,8,8,8,8,8,256,256,256,},{256,256,256,256,256,256,256,256,256,256,256,256,256,256,},{2048,2048,256,256,256,256,256,256,256,256,256,256,2048,2048,},{2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,},{2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,},{2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,},{2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,},{256,256,2048,2048,2048,2048,2048,2048,2048,2048,2048,2048,256,256,},{1,256,256,256,256,256,256,256,256,256,256,256,256,1,},{1,1,1,256,256,256,256,256,256,256,256,1,1,1,},["text"]={{" "," "," "," "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," ","S","k","e","t","c","h"," "," "," "," ",},{" "," "," "," "," "," ","b","y"," "," "," "," "," "," ",},{" "," "," "," "," ","o","e","e","d"," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," "," "," "," ",},},["textcol"]={{32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,},{32768,32768,32768,256,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,},{32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,},{32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,},{32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,},{32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,},{32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,},{32768,32768,32768,32768,1,1,1,1,1,1,32768,32768,32768,32768,},{32768,32768,32768,32768,8,8,8,8,8,8,8,32768,32768,32768,},{32768,32768,32768,32768,1,1,1,1,1,32768,8,32768,32768,32768,},{32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,},{32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,},{32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,},},}
  7477.         Drawing.Clear(colours.white)
  7478.         Drawing.DrawImage((Drawing.Screen.Width - 14)/2, (Drawing.Screen.Height - 13)/2, splashIcon, 14, 13)
  7479.         Drawing.DrawBuffer()
  7480.         parallel.waitForAny(function()sleep(1)end, function()os.pullEvent('mouse_click')end)
  7481.     end
  7482.  
  7483.     LongestString = function(input, key)
  7484.         local length = 0
  7485.         for i = 1, #input do
  7486.             local value = input[i]
  7487.             if key then
  7488.                 if value[key] then
  7489.                     value = value[key]
  7490.                 else
  7491.                     value = ''
  7492.                 end
  7493.             end
  7494.             local titleLength = string.len(value)
  7495.             if titleLength > length then
  7496.                 length = titleLength
  7497.             end
  7498.         end
  7499.         return length
  7500.     end
  7501.  
  7502.     function HandleKey(...)
  7503.         local args = {...}
  7504.         local event = args[1]
  7505.         local keychar = args[2]
  7506.         if event == 'key' and Current.Tool and Current.Tool.Name == 'Text' and Current.Input and (keychar == keys.up or keychar == keys.down or keychar == keys.left or keychar == keys.right) then
  7507.             local currentPos = {Current.CursorPos[1] - Current.Artboard.X + 1, Current.CursorPos[2] - Current.Artboard.Y + 1}
  7508.             if keychar == keys.up then
  7509.                 currentPos[2] = currentPos[2] - 1
  7510.             elseif keychar == keys.down then
  7511.                 currentPos[2] = currentPos[2] + 1
  7512.             elseif keychar == keys.left then
  7513.                 currentPos[1] = currentPos[1] - 1
  7514.             elseif keychar == keys.right then
  7515.                 currentPos[1] = currentPos[1] + 1
  7516.             end
  7517.  
  7518.             if currentPos[1] < 1 then
  7519.                 currentPos[1] = 1
  7520.             end
  7521.  
  7522.             if currentPos[1] > Current.Artboard.Width then
  7523.                 currentPos[1] = Current.Artboard.Width
  7524.             end
  7525.  
  7526.             if currentPos[2] < 1 then
  7527.                 currentPos[2] = 1
  7528.             end
  7529.  
  7530.             if currentPos[2] > Current.Artboard.Height then
  7531.                 currentPos[2] = Current.Artboard.Height
  7532.             end
  7533.  
  7534.             Current.Tool:Use(currentPos[1], currentPos[2])
  7535.             Current.Modified = true
  7536.             Draw()
  7537.         elseif Current.Input then
  7538.             if event == 'char' then
  7539.                 Current.Input:Char(keychar)
  7540.             elseif event == 'key' then
  7541.                 Current.Input:Key(keychar)
  7542.             end
  7543.         elseif event == 'key' then
  7544.             CheckKeyboardShortcut(keychar)
  7545.         end
  7546.     end
  7547.  
  7548.     function Scroll(event, direction, x, y)
  7549.         if Current.Window and Current.Window.OpenButton then
  7550.             Current.Window.Scroll = Current.Window.Scroll + direction
  7551.             if Current.Window.Scroll < 0 then
  7552.                 Current.Window.Scroll = 0
  7553.             elseif Current.Window.Scroll > Current.Window.MaxScroll then
  7554.                 Current.Window.Scroll = Current.Window.MaxScroll
  7555.             end
  7556.         end
  7557.         Draw()
  7558.     end
  7559.  
  7560.     function CheckKeyboardShortcut(key)
  7561.         local shortcuts = {}
  7562.  
  7563.         if key == keys.leftCtrl then
  7564.             Current.ControlPressedTimer = os.startTimer(0.5)
  7565.             return
  7566.         end
  7567.         if Current.ControlPressedTimer then
  7568.             shortcuts[keys.n] = function() DisplayNewDocumentWindow() end
  7569.             shortcuts[keys.o] = function() DisplayOpenDocumentWindow() end
  7570.             shortcuts[keys.s] = function() Current.Artboard:Save() end
  7571.             shortcuts[keys.x] = function() if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then Clipboard.Cut(Current.Layer:PixelsInSelection(true), 'sketchpixels') end end
  7572.             shortcuts[keys.c] = function() if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then Clipboard.Copy(Current.Layer:PixelsInSelection(), 'sketchpixels') end end
  7573.             shortcuts[keys.v] = function() if (not Clipboard.isEmpty()) and Clipboard.Type == 'sketchpixels' then Current.Layer:InsertPixels(Clipboard.Paste()) end end
  7574.             shortcuts[keys.r] = function() ResizeDocument() end
  7575.             shortcuts[keys.l] = function() MakeNewLayer() end
  7576.         end
  7577.  
  7578.         shortcuts[keys.delete] = function() if CheckSelectedLayer() and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then Current.Layer:EraseSelection() Draw() end end
  7579.         shortcuts[keys.backspace] = shortcuts[keys.delete]
  7580.         shortcuts[keys.tab] = function() Current.InterfaceVisible = not Current.InterfaceVisible Draw() end
  7581.  
  7582.         shortcuts[keys.h] = function() SetTool(ToolNamed('Hand')) ModuleNamed('Tools'):Update() Draw() end
  7583.         shortcuts[keys.e] = function() SetTool(ToolNamed('Eraser')) ModuleNamed('Tools'):Update() Draw() end
  7584.         shortcuts[keys.p] = function() SetTool(ToolNamed('Pencil')) ModuleNamed('Tools'):Update() Draw() end
  7585.         shortcuts[keys.f] = function() SetTool(ToolNamed('Fill Bucket')) ModuleNamed('Tools'):Update() Draw() end
  7586.         shortcuts[keys.m] = function() SetTool(ToolNamed('Move')) ModuleNamed('Tools'):Update() Draw() end
  7587.         shortcuts[keys.s] = function() SetTool(ToolNamed('Select')) ModuleNamed('Tools'):Update() Draw() end
  7588.         shortcuts[keys.t] = function() SetTool(ToolNamed('Text')) ModuleNamed('Tools'):Update() Draw() end
  7589.  
  7590.         if shortcuts[key] then
  7591.             shortcuts[key]()
  7592.             return true
  7593.         else
  7594.             return false
  7595.         end
  7596.     end
  7597.  
  7598.     --[[
  7599.         Check if the given object falls under the click coordinates
  7600.     ]]--
  7601.     function CheckClick(object, x, y)
  7602.         if object.X <= x and object.Y <= y and object.X + object.Width > x and object.Y + object.Height > y then
  7603.             return true
  7604.         end
  7605.     end
  7606.  
  7607.     --[[
  7608.         Attempt to clicka given object
  7609.     ]]--
  7610.     function DoClick(object, side, x, y, drag)
  7611.         if object and CheckClick(object, x, y) then
  7612.             return object:Click(side, x - object.X + 1, y - object.Y + 1, drag)
  7613.         end
  7614.     end
  7615.  
  7616.     --[[
  7617.         Try to click at the given coordinates
  7618.     ]]--
  7619.     function TryClick(event, side, x, y, drag)
  7620.         if Current.InterfaceVisible and Current.Menu then
  7621.             if DoClick(Current.Menu, side, x, y, drag) then
  7622.                 Draw()
  7623.                 return
  7624.             else
  7625.                 if Current.Menu.Owner and Current.Menu.Owner.Toggle then
  7626.                     Current.Menu.Owner.Toggle = false
  7627.                 end
  7628.                 Current.Menu = nil
  7629.                 Draw()
  7630.                 return
  7631.             end
  7632.         elseif Current.Window then
  7633.             if DoClick(Current.Window, side, x, y, drag) then
  7634.                 Draw()
  7635.                 return
  7636.             else
  7637.                 Current.Window:Flash()
  7638.                 return
  7639.             end
  7640.         end
  7641.         local interfaceElements = {}
  7642.  
  7643.         if Current.InterfaceVisible then
  7644.             table.insert(interfaceElements, Current.MenuBar)
  7645.         else
  7646.             table.insert(interfaceElements, ShowInterfaceButton)
  7647.         end
  7648.  
  7649.         for i, v in ipairs(Lists.Interface.Toolbars) do
  7650.             for i, v2 in ipairs(v.ToolbarItems) do
  7651.                 table.insert(interfaceElements, v2)
  7652.             end
  7653.             table.insert(interfaceElements, v)
  7654.         end
  7655.  
  7656.         table.insert(interfaceElements, Current.Artboard)
  7657.  
  7658.         for i, object in ipairs(interfaceElements) do
  7659.             if DoClick(object, side, x, y, drag) then
  7660.                 Draw()
  7661.                 return
  7662.             end    
  7663.         end
  7664.         Draw()
  7665.     end
  7666.  
  7667.     --[[
  7668.         Registers functions to run on certain events
  7669.     ]]--
  7670.     function EventRegister(event, func)
  7671.         if not Events[event] then
  7672.             Events[event] = {}
  7673.         end
  7674.  
  7675.         table.insert(Events[event], func)
  7676.     end
  7677.  
  7678.     --[[
  7679.         The main loop event handler, runs registered event functinos
  7680.     ]]--
  7681.     function EventHandler()
  7682.         while true do
  7683.             local event, arg1, arg2, arg3, arg4 = os.pullEventRaw()
  7684.             if Events[event] then
  7685.                 for i, e in ipairs(Events[event]) do
  7686.                     e(event, arg1, arg2, arg3, arg4)
  7687.                 end
  7688.             end
  7689.         end
  7690.     end
  7691.  
  7692.     --[[
  7693.         Thanks to NitrogenFingers for the colour functions and NFT + NFP read/write functions
  7694.     ]]--
  7695.  
  7696.     --[[
  7697.         Gets the hex value from a colour
  7698.     ]]--
  7699.     local hexnums = { [10] = "a", [11] = "b", [12] = "c", [13] = "d", [14] = "e" , [15] = "f" }
  7700.     local function getHexOf(colour)
  7701.         if colour == colours.transparent or not colour or not tonumber(colour) then
  7702.                 return " "
  7703.         end
  7704.         local value = math.log(colour)/math.log(2)
  7705.         if value > 9 then
  7706.                 value = hexnums[value]
  7707.         end
  7708.         return value
  7709.     end
  7710.  
  7711.     --[[
  7712.         Gets the colour from a hex value
  7713.     ]]--
  7714.     local function getColourOf(hex)
  7715.         if hex == ' ' then
  7716.             return colours.transparent
  7717.         end
  7718.         local value = tonumber(hex, 16)
  7719.         if not value then return nil end
  7720.         value = math.pow(2,value)
  7721.         return value
  7722.     end
  7723.  
  7724.     --[[
  7725.         Saves the current artboard in .skch format
  7726.     ]]--
  7727.     function SaveSKCH()
  7728.         local layers = {}
  7729.         for i, l in ipairs(Current.Artboard.Layers) do
  7730.             local pixels = SaveNFT(i)
  7731.             local layer = {
  7732.                 Name = l.Name,
  7733.                 Pixels = pixels,
  7734.                 BackgroundColour = l.BackgroundColour,
  7735.                 Visible = l.Visible,
  7736.                 Index = l.Index,
  7737.             }
  7738.             table.insert(layers, layer)
  7739.         end
  7740.         return layers
  7741.     end
  7742.  
  7743.     --[[
  7744.         Saves the current artboard in .nft format
  7745.     ]]--
  7746.     function SaveNFT(layer)
  7747.         layer = layer or 1
  7748.         local lines = {}
  7749.         local width = Current.Artboard.Width
  7750.         local height = Current.Artboard.Height
  7751.         for y = 1, height do
  7752.             local line = ''
  7753.             local currentBackgroundColour = nil
  7754.             local currentTextColour = nil
  7755.             for x = 1, width do
  7756.                 local pixel = Current.Artboard.Layers[layer].Pixels[x][y]
  7757.                 if pixel.BackgroundColour ~= currentBackgroundColour then
  7758.                     line = line..string.char(30)..getHexOf(pixel.BackgroundColour)
  7759.                     currentBackgroundColour = pixel.BackgroundColour
  7760.                 end
  7761.                 if pixel.TextColour ~= currentTextColour then
  7762.                     line = line..string.char(31)..getHexOf(pixel.TextColour)
  7763.                     currentTextColour = pixel.TextColour
  7764.                 end
  7765.                 line = line .. pixel.Character
  7766.             end
  7767.             table.insert(lines, line)
  7768.         end
  7769.         return lines
  7770.     end
  7771.  
  7772.     --[[
  7773.         Saves the current artboard in .nfp format
  7774.     ]]--
  7775.     function SaveNFP()
  7776.         local lines = {}
  7777.         local width = Current.Artboard.Width
  7778.         local height = Current.Artboard.Height
  7779.         for y = 1, height do
  7780.             local line = ''
  7781.             for x = 1, width do
  7782.                 line = line .. getHexOf(Current.Artboard.Layers[1].Pixels[x][y].BackgroundColour)
  7783.             end
  7784.             table.insert(lines, line)
  7785.         end
  7786.         return lines
  7787.     end
  7788.  
  7789.     --[[
  7790.         Reads a .nfp file from the given path
  7791.     ]]--
  7792.     function ReadNFP(path)
  7793.         local pixels = {}
  7794.         local _fs = fs
  7795.         if OneOS then
  7796.             _fs = OneOS.FS
  7797.         end
  7798.         local file = _fs.open(path, 'r')
  7799.         local line = file.readLine()
  7800.         local y = 1
  7801.         while line do
  7802.             for x = 1, #line do
  7803.                 if not pixels[x] then
  7804.                     pixels[x] = {}
  7805.                 end
  7806.                 pixels[x][y] = {BackgroundColour = getColourOf(line:sub(x,x))}
  7807.             end
  7808.             y = y + 1
  7809.             line = file.readLine()
  7810.         end
  7811.         file.close()
  7812.         return {{Pixels = pixels}}
  7813.     end
  7814.  
  7815.     --[[
  7816.         Reads a .nft file from the given path
  7817.     ]]--
  7818.     function ReadNFT(path)
  7819.         local _fs = fs
  7820.         if OneOS then
  7821.             _fs = OneOS.FS
  7822.         end
  7823.         local file = _fs.open(path, 'r')
  7824.         local line = file.readLine()
  7825.         local lines = {}
  7826.         while line do
  7827.             table.insert(lines, line)
  7828.             line = file.readLine()
  7829.         end
  7830.         file.close()
  7831.         return {{Pixels = ParseNFT(lines)}}
  7832.     end
  7833.  
  7834.     --[[
  7835.         Converts the lines of an .nft document to readble pixel data
  7836.     ]]--
  7837.     function ParseNFT(lines)
  7838.         local pixels = {}
  7839.         for y, line in ipairs(lines) do
  7840.             local bgNext, fgNext = false, false
  7841.             local currBG, currFG = nil,nil
  7842.             local writePosition = 1
  7843.             for x = 1, #line do
  7844.                 if not pixels[writePosition] then
  7845.                     pixels[writePosition] = {}
  7846.                 end
  7847.  
  7848.                 local nextChar = string.sub(line, x, x)
  7849.                 if nextChar:byte() == 30 then
  7850.                         bgNext = true
  7851.                 elseif nextChar:byte() == 31 then
  7852.                         fgNext = true
  7853.                 elseif bgNext then
  7854.                         currBG = getColourOf(nextChar)
  7855.                         if currBG == nil then
  7856.                             currBG = colours.transparent
  7857.                         end
  7858.                         bgNext = false
  7859.                 elseif fgNext then
  7860.                         currFG = getColourOf(nextChar)
  7861.                         fgNext = false
  7862.                 else
  7863.                         if nextChar ~= " " and currFG == nil then
  7864.                                 currFG = colours.white
  7865.                         end
  7866.                         pixels[writePosition][y] = {BackgroundColour = currBG, TextColour = currFG, Character = nextChar}
  7867.                         writePosition = writePosition + 1
  7868.                 end
  7869.             end
  7870.         end
  7871.         return pixels
  7872.     end
  7873.  
  7874.     --[[
  7875.         Read a .skch file from the given path
  7876.     ]]--
  7877.     function ReadSKCH(path)
  7878.         local _fs = fs
  7879.         if OneOS then
  7880.             _fs = OneOS.FS
  7881.         end
  7882.         local file = _fs.open(path, 'r')
  7883.         local _layers = textutils.unserialize(file.readAll())
  7884.         file.close()
  7885.         local layers = {}
  7886.  
  7887.         for i, l in ipairs(_layers) do
  7888.             local layer = {
  7889.                 Name = l.Name,
  7890.                 Pixels = ParseNFT(l.Pixels),
  7891.                 BackgroundColour = l.BackgroundColour,
  7892.                 Visible = l.Visible,
  7893.                 Index = l.Index,
  7894.             }
  7895.             table.insert(layers, layer)
  7896.         end
  7897.         return layers
  7898.     end
  7899.  
  7900.     --[[
  7901.         Start the program after all functions and tables are loaded
  7902.     ]]--
  7903.     if term.isColor and term.isColor() then
  7904.         Initialise()
  7905.     else
  7906.         print('Sorry, but Sketch only works on Advanced (gold) Computers')
  7907.     end
  7908. end
  7909.  
  7910. function oeed_ink()
  7911.     tArgs = {}
  7912.  
  7913.     if OneOS then
  7914.         --running under OneOS
  7915.         OneOS.ToolBarColour = colours.grey
  7916.         OneOS.ToolBarTextColour = colours.white
  7917.     end
  7918.  
  7919.     local _w, _h = term.getSize()
  7920.  
  7921.     local round = function(num, idp)
  7922.         local mult = 10^(idp or 0)
  7923.         return math.floor(num * mult + 0.5) / mult
  7924.     end
  7925.  
  7926.     UIColours = {
  7927.         Toolbar = colours.grey,
  7928.         ToolbarText = colours.lightGrey,
  7929.         ToolbarSelected = colours.lightBlue,
  7930.         ControlText = colours.white,
  7931.         ToolbarItemTitle = colours.black,
  7932.         Background = colours.lightGrey,
  7933.         MenuBackground = colours.white,
  7934.         MenuText = colours.black,
  7935.         MenuSeparatorText = colours.grey,
  7936.         MenuDisabledText = colours.lightGrey,
  7937.         Shadow = colours.grey,
  7938.         TransparentBackgroundOne = colours.white,
  7939.         TransparentBackgroundTwo = colours.lightGrey,
  7940.         MenuBarActive = colours.white
  7941.     }
  7942.  
  7943.     local getNames = peripheral.getNames or function()
  7944.         local tResults = {}
  7945.         for n,sSide in ipairs( rs.getSides() ) do
  7946.             if peripheral.isPresent( sSide ) then
  7947.                 table.insert( tResults, sSide )
  7948.                 local isWireless = false
  7949.                 if not pcall(function()isWireless = peripheral.call(sSide, 'isWireless') end) then
  7950.                     isWireless = true
  7951.                 end    
  7952.                 if peripheral.getType( sSide ) == "modem" and not isWireless then
  7953.                     local tRemote = peripheral.call( sSide, "getNamesRemote" )
  7954.                     for n,sName in ipairs( tRemote ) do
  7955.                         table.insert( tResults, sName )
  7956.                     end
  7957.                 end
  7958.             end
  7959.         end
  7960.         return tResults
  7961.     end
  7962.  
  7963.     Peripheral = {
  7964.         GetPeripheral = function(_type)
  7965.             for i, p in ipairs(Peripheral.GetPeripherals()) do
  7966.                 if p.Type == _type then
  7967.                     return p
  7968.                 end
  7969.             end
  7970.         end,
  7971.  
  7972.         Call = function(type, ...)
  7973.             local tArgs = {...}
  7974.             local p = Peripheral.GetPeripheral(type)
  7975.             peripheral.call(p.Side, unpack(tArgs))
  7976.         end,
  7977.  
  7978.         GetPeripherals = function(filterType)
  7979.             local peripherals = {}
  7980.             for i, side in ipairs(getNames()) do
  7981.                 local name = peripheral.getType(side):gsub("^%l", string.upper)
  7982.                 local code = string.upper(side:sub(1,1))
  7983.                 if side:find('_') then
  7984.                     code = side:sub(side:find('_')+1)
  7985.                 end
  7986.  
  7987.                 local dupe = false
  7988.                 for i, v in ipairs(peripherals) do
  7989.                     if v[1] == name .. ' ' .. code then
  7990.                         dupe = true
  7991.                     end
  7992.                 end
  7993.  
  7994.                 if not dupe then
  7995.                     local _type = peripheral.getType(side)
  7996.                     local isWireless = false
  7997.                     if _type == 'modem' then
  7998.                         if not pcall(function()isWireless = peripheral.call(sSide, 'isWireless') end) then
  7999.                             isWireless = true
  8000.                         end    
  8001.                         if isWireless then
  8002.                             _type = 'wireless_modem'
  8003.                             name = 'W '..name
  8004.                         end
  8005.                     end
  8006.                     if not filterType or _type == filterType then
  8007.                         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})
  8008.                     end
  8009.                 end
  8010.             end
  8011.             return peripherals
  8012.         end,
  8013.  
  8014.         PresentNamed = function(name)
  8015.             return peripheral.isPresent(name)
  8016.         end,
  8017.  
  8018.         CallType = function(type, ...)
  8019.             local tArgs = {...}
  8020.             local p = GetPeripheral(type)
  8021.             return peripheral.call(p.Side, unpack(tArgs))
  8022.         end,
  8023.  
  8024.         CallNamed = function(name, ...)
  8025.             local tArgs = {...}
  8026.             return peripheral.call(name, unpack(tArgs))
  8027.         end
  8028.     }
  8029.  
  8030.     TextLine = {
  8031.         Text = "",
  8032.         Alignment = AlignmentLeft,
  8033.  
  8034.         Initialise = function(self, text, alignment)
  8035.             local new = {}    -- the new instance
  8036.             setmetatable( new, {__index = self} )
  8037.             new.Text = text
  8038.             new.Alignment = alignment or AlignmentLeft
  8039.             return new
  8040.         end
  8041.     }
  8042.  
  8043.     local StripColours = function(str)
  8044.         return str:gsub('['..string.char(14)..'-'..string.char(29)..']','')
  8045.     end
  8046.  
  8047.     Printer = {
  8048.         Name = nil,
  8049.         PeripheralType = 'printer',
  8050.  
  8051.         paperLevel = function(self)
  8052.             return Peripheral.CallNamed(self.Name, 'getPaperLevel')
  8053.         end,
  8054.  
  8055.         newPage = function(self)
  8056.             return Peripheral.CallNamed(self.Name, 'newPage')
  8057.         end,
  8058.  
  8059.         endPage = function(self)
  8060.             return Peripheral.CallNamed(self.Name, 'endPage')
  8061.         end,
  8062.  
  8063.         pageWrite = function(self, text)
  8064.             return Peripheral.CallNamed(self.Name, 'write', text)
  8065.         end,
  8066.  
  8067.         setPageTitle = function(self, title)
  8068.             return Peripheral.CallNamed(self.Name, 'setPageTitle', title)
  8069.         end,
  8070.  
  8071.         inkLevel = function(self)
  8072.             return Peripheral.CallNamed(self.Name, 'getInkLevel')
  8073.         end,
  8074.  
  8075.         getCursorPos = function(self)
  8076.             return Peripheral.CallNamed(self.Name, 'getCursorPos')
  8077.         end,
  8078.  
  8079.         setCursorPos = function(self, x, y)
  8080.             return Peripheral.CallNamed(self.Name, 'setCursorPos', x, y)
  8081.         end,
  8082.  
  8083.         pageSize = function(self)
  8084.             return Peripheral.CallNamed(self.Name, 'getPageSize')
  8085.         end,
  8086.  
  8087.         Present = function()
  8088.             if Peripheral.GetPeripheral(Printer.PeripheralType) == nil then
  8089.                 return false
  8090.             else
  8091.                 return true
  8092.             end
  8093.         end,
  8094.  
  8095.         PrintLines = function(self, lines, title, copies)
  8096.             local pages = {}
  8097.             local pageLines = {}
  8098.             for i, line in ipairs(lines) do
  8099.                 table.insert(pageLines, TextLine:Initialise(StripColours(line)))
  8100.                 if i % 25 == 0 then
  8101.                     table.insert(pages, pageLines)
  8102.                     pageLines = {}
  8103.                 end
  8104.             end
  8105.             if #pageLines ~= 0 then
  8106.                     table.insert(pages, pageLines)
  8107.             end
  8108.             return self:PrintPages(pages, title, copies)
  8109.         end,
  8110.  
  8111.         PrintPages = function(self, pages, title, copies)
  8112.             copies = copies or 1
  8113.             for c = 1, copies do
  8114.                 for p, page in ipairs(pages) do
  8115.                     if self:paperLevel() < #pages * copies then
  8116.                         return 'Add more paper to the printer'
  8117.                     end
  8118.                     if self:inkLevel() < #pages * copies then
  8119.                         return 'Add more ink to the printer'
  8120.                     end
  8121.                     self:newPage()
  8122.                     for i, line in ipairs(page) do
  8123.                         self:setCursorPos(1, i)
  8124.                         self:pageWrite(StripColours(line.Text))
  8125.                     end
  8126.                     if title then
  8127.                         self:setPageTitle(title)
  8128.                     end
  8129.                     self:endPage()
  8130.                 end
  8131.             end
  8132.         end,
  8133.  
  8134.         Initialise = function(self, name)
  8135.             if Printer.Present() then --fix
  8136.                 local new = {}    -- the new instance
  8137.                 setmetatable( new, {__index = self} )
  8138.                 if name and Peripheral.PresentNamed(name) then
  8139.                     new.Name = name
  8140.                 else
  8141.                     new.Name = Peripheral.GetPeripheral(Printer.PeripheralType).Side
  8142.                 end
  8143.                 return new
  8144.             end
  8145.         end
  8146.     }
  8147.  
  8148.     Clipboard = {
  8149.         Content = nil,
  8150.         Type = nil,
  8151.         IsCut = false,
  8152.  
  8153.         Empty = function()
  8154.             Clipboard.Content = nil
  8155.             Clipboard.Type = nil
  8156.             Clipboard.IsCut = false
  8157.         end,
  8158.  
  8159.         isEmpty = function()
  8160.             return Clipboard.Content == nil
  8161.         end,
  8162.  
  8163.         Copy = function(content, _type)
  8164.             Clipboard.Content = content
  8165.             Clipboard.Type = _type or 'generic'
  8166.             Clipboard.IsCut = false
  8167.         end,
  8168.  
  8169.         Cut = function(content, _type)
  8170.             Clipboard.Content = content
  8171.             Clipboard.Type = _type or 'generic'
  8172.             Clipboard.IsCut = true
  8173.         end,
  8174.  
  8175.         Paste = function()
  8176.             local c, t = Clipboard.Content, Clipboard.Type
  8177.             if Clipboard.IsCut then
  8178.                 Clipboard.Empty()
  8179.             end
  8180.             return c, t
  8181.         end
  8182.     }
  8183.  
  8184.     if OneOS and OneOS.Clipboard then
  8185.         Clipboard = OneOS.Clipboard
  8186.     end
  8187.  
  8188.     Drawing = {
  8189.        
  8190.         Screen = {
  8191.             Width = _w,
  8192.             Height = _h
  8193.         },
  8194.  
  8195.         DrawCharacters = function (x, y, characters, textColour,bgColour)
  8196.             Drawing.WriteStringToBuffer(x, y, characters, textColour, bgColour)
  8197.         end,
  8198.        
  8199.         DrawBlankArea = function (x, y, w, h, colour)
  8200.             Drawing.DrawArea (x, y, w, h, " ", 1, colour)
  8201.         end,
  8202.  
  8203.         DrawArea = function (x, y, w, h, character, textColour, bgColour)
  8204.             --width must be greater than 1, other wise we get a stack overflow
  8205.             if w < 0 then
  8206.                 w = w * -1
  8207.             elseif w == 0 then
  8208.                 w = 1
  8209.             end
  8210.  
  8211.             for ix = 1, w do
  8212.                 local currX = x + ix - 1
  8213.                 for iy = 1, h do
  8214.                     local currY = y + iy - 1
  8215.                     Drawing.WriteToBuffer(currX, currY, character, textColour, bgColour)
  8216.                 end
  8217.             end
  8218.         end,
  8219.  
  8220.         DrawImage = function(_x,_y,tImage, w, h)
  8221.             if tImage then
  8222.                 for y = 1, h do
  8223.                     if not tImage[y] then
  8224.                         break
  8225.                     end
  8226.                     for x = 1, w do
  8227.                         if not tImage[y][x] then
  8228.                             break
  8229.                         end
  8230.                         local bgColour = tImage[y][x]
  8231.                         local textColour = tImage.textcol[y][x] or colours.white
  8232.                         local char = tImage.text[y][x]
  8233.                         Drawing.WriteToBuffer(x+_x-1, y+_y-1, char, textColour, bgColour)
  8234.                     end
  8235.                 end
  8236.             elseif w and h then
  8237.                 Drawing.DrawBlankArea(x, y, w, h, colours.green)
  8238.             end
  8239.         end,
  8240.         --using .nft
  8241.         LoadImage = function(path)
  8242.             local image = {
  8243.                 text = {},
  8244.                 textcol = {}
  8245.             }
  8246.             local fs = fs
  8247.             if OneOS then
  8248.                 fs = OneOS.FS
  8249.             end
  8250.             if fs.exists(path) then
  8251.                 local _open = io.open
  8252.                 if OneOS then
  8253.                     _open = OneOS.IO.open
  8254.                 end
  8255.                 local file = _open(path, "r")
  8256.                 local sLine = file:read()
  8257.                 local num = 1
  8258.                 while sLine do  
  8259.                         table.insert(image, num, {})
  8260.                         table.insert(image.text, num, {})
  8261.                         table.insert(image.textcol, num, {})
  8262.                                                    
  8263.                         --As we're no longer 1-1, we keep track of what index to write to
  8264.                         local writeIndex = 1
  8265.                         --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour
  8266.                         local bgNext, fgNext = false, false
  8267.                         --The current background and foreground colours
  8268.                         local currBG, currFG = nil,nil
  8269.                         for i=1,#sLine do
  8270.                                 local nextChar = string.sub(sLine, i, i)
  8271.                                 if nextChar:byte() == 30 then
  8272.                                     bgNext = true
  8273.                                 elseif nextChar:byte() == 31 then
  8274.                                     fgNext = true
  8275.                                 elseif bgNext then
  8276.                                     currBG = Drawing.GetColour(nextChar)
  8277.                                     bgNext = false
  8278.                                 elseif fgNext then
  8279.                                     currFG = Drawing.GetColour(nextChar)
  8280.                                     fgNext = false
  8281.                                 else
  8282.                                     if nextChar ~= " " and currFG == nil then
  8283.                                            currFG = colours.white
  8284.                                     end
  8285.                                     image[num][writeIndex] = currBG
  8286.                                     image.textcol[num][writeIndex] = currFG
  8287.                                     image.text[num][writeIndex] = nextChar
  8288.                                     writeIndex = writeIndex + 1
  8289.                                 end
  8290.                         end
  8291.                         num = num+1
  8292.                         sLine = file:read()
  8293.                 end
  8294.                 file:close()
  8295.             end
  8296.             return image
  8297.         end,
  8298.  
  8299.         DrawCharactersCenter = function(x, y, w, h, characters, textColour,bgColour)
  8300.             w = w or Drawing.Screen.Width
  8301.             h = h or Drawing.Screen.Height
  8302.             x = x or 0
  8303.             y = y or 0
  8304.             x = math.ceil((w - #characters) / 2) + x
  8305.             y = math.floor(h / 2) + y
  8306.  
  8307.             Drawing.DrawCharacters(x, y, characters, textColour, bgColour)
  8308.         end,
  8309.  
  8310.         GetColour = function(hex)
  8311.             if hex == ' ' then
  8312.                 return colours.transparent
  8313.             end
  8314.             local value = tonumber(hex, 16)
  8315.             if not value then return nil end
  8316.             value = math.pow(2,value)
  8317.             return value
  8318.         end,
  8319.  
  8320.         Clear = function (_colour)
  8321.             _colour = _colour or colours.black
  8322.             Drawing.ClearBuffer()
  8323.             Drawing.DrawBlankArea(1, 1, Drawing.Screen.Width, Drawing.Screen.Height, _colour)
  8324.         end,
  8325.  
  8326.         Buffer = {},
  8327.         BackBuffer = {},
  8328.  
  8329.         DrawBuffer = function()
  8330.             for y,row in pairs(Drawing.Buffer) do
  8331.                 for x,pixel in pairs(row) do
  8332.                     local shouldDraw = true
  8333.                     local hasBackBuffer = true
  8334.                     if Drawing.BackBuffer[y] == nil or Drawing.BackBuffer[y][x] == nil or #Drawing.BackBuffer[y][x] ~= 3 then
  8335.                         hasBackBuffer = false
  8336.                     end
  8337.                     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
  8338.                         shouldDraw = false
  8339.                     end
  8340.                     if shouldDraw then
  8341.                         term.setBackgroundColour(pixel[3])
  8342.                         term.setTextColour(pixel[2])
  8343.                         term.setCursorPos(x, y)
  8344.                         term.write(pixel[1])
  8345.                     end
  8346.                 end
  8347.             end
  8348.             Drawing.BackBuffer = Drawing.Buffer
  8349.             Drawing.Buffer = {}
  8350.             term.setCursorPos(1,1)
  8351.         end,
  8352.  
  8353.         ClearBuffer = function()
  8354.             Drawing.Buffer = {}
  8355.         end,
  8356.  
  8357.         WriteStringToBuffer = function (x, y, characters, textColour,bgColour)
  8358.             for i = 1, #characters do
  8359.                 local character = characters:sub(i,i)
  8360.                 Drawing.WriteToBuffer(x + i - 1, y, character, textColour, bgColour)
  8361.             end
  8362.         end,
  8363.  
  8364.         WriteToBuffer = function(x, y, character, textColour,bgColour)
  8365.             x = round(x)
  8366.             y = round(y)
  8367.             if bgColour == colours.transparent then
  8368.                 Drawing.Buffer[y] = Drawing.Buffer[y] or {}
  8369.                 Drawing.Buffer[y][x] = Drawing.Buffer[y][x] or {"", colours.white, colours.black}
  8370.                 Drawing.Buffer[y][x][1] = character
  8371.                 Drawing.Buffer[y][x][2] = textColour
  8372.             else
  8373.                 Drawing.Buffer[y] = Drawing.Buffer[y] or {}
  8374.                 Drawing.Buffer[y][x] = {character, textColour, bgColour}
  8375.             end
  8376.         end,
  8377.     }
  8378.  
  8379.     Current = {
  8380.         Document = nil,
  8381.         TextInput = nil,
  8382.         CursorPos = {1,1},
  8383.         CursorColour = colours.black,
  8384.         Selection = {8, 36},
  8385.         Window = nil,
  8386.         Modified = false,
  8387.     }
  8388.  
  8389.     local isQuitting = false
  8390.  
  8391.     function OrderSelection()
  8392.         if Current.Selection then
  8393.             if Current.Selection[1] <= Current.Selection[2] then
  8394.                 return Current.Selection
  8395.             else
  8396.                 return {Current.Selection[2], Current.Selection[1]}
  8397.             end
  8398.         end
  8399.     end
  8400.  
  8401.     function StripColours(str)
  8402.         return str:gsub('['..string.char(14)..'-'..string.char(29)..']','')
  8403.     end
  8404.  
  8405.     function FindColours(str)
  8406.         local _, count = str:gsub('['..string.char(14)..'-'..string.char(29)..']','')
  8407.         return count
  8408.     end
  8409.  
  8410.     ColourFromCharacter = function(character)
  8411.         local n = character:byte() - 14
  8412.         if n > 16 then
  8413.             return nil
  8414.         else
  8415.             return 2^n
  8416.         end
  8417.     end
  8418.  
  8419.     CharacterFromColour = function(colour)
  8420.         return string.char(math.floor(math.log(colour)/math.log(2))+14)
  8421.     end
  8422.  
  8423.     Events = {}
  8424.  
  8425.     Button = {
  8426.         X = 1,
  8427.         Y = 1,
  8428.         Width = 0,
  8429.         Height = 0,
  8430.         BackgroundColour = colours.lightGrey,
  8431.         TextColour = colours.white,
  8432.         ActiveBackgroundColour = colours.lightGrey,
  8433.         Text = "",
  8434.         Parent = nil,
  8435.         _Click = nil,
  8436.         Toggle = nil,
  8437.  
  8438.         AbsolutePosition = function(self)
  8439.             return self.Parent:AbsolutePosition()
  8440.         end,
  8441.  
  8442.         Draw = function(self)
  8443.             local bg = self.BackgroundColour
  8444.             local tc = self.TextColour
  8445.             if type(bg) == 'function' then
  8446.                 bg = bg()
  8447.             end
  8448.  
  8449.             if self.Toggle then
  8450.                 tc = UIColours.MenuBarActive
  8451.                 bg = self.ActiveBackgroundColour
  8452.             end
  8453.  
  8454.             local pos = GetAbsolutePosition(self)
  8455.             Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, bg)
  8456.             Drawing.DrawCharactersCenter(pos.X, pos.Y, self.Width, self.Height, self.Text, tc, bg)
  8457.         end,
  8458.  
  8459.         Initialise = function(self, x, y, width, height, backgroundColour, parent, click, text, textColour, toggle, activeBackgroundColour)
  8460.             local new = {}    -- the new instance
  8461.             setmetatable( new, {__index = self} )
  8462.             height = height or 1
  8463.             new.Width = width or #text + 2
  8464.             new.Height = height
  8465.             new.Y = y
  8466.             new.X = x
  8467.             new.Text = text or ""
  8468.             new.BackgroundColour = backgroundColour or colours.lightGrey
  8469.             new.TextColour = textColour or colours.white
  8470.             new.ActiveBackgroundColour = activeBackgroundColour or colours.lightGrey
  8471.             new.Parent = parent
  8472.             new._Click = click
  8473.             new.Toggle = toggle
  8474.             return new
  8475.         end,
  8476.  
  8477.         Click = function(self, side, x, y)
  8478.             if self._Click then
  8479.                 if self:_Click(side, x, y, not self.Toggle) ~= false and self.Toggle ~= nil then
  8480.                     self.Toggle = not self.Toggle
  8481.                     Draw()
  8482.                 end
  8483.                 return true
  8484.             else
  8485.                 return false
  8486.             end
  8487.         end
  8488.     }
  8489.  
  8490.     TextBox = {
  8491.         X = 1,
  8492.         Y = 1,
  8493.         Width = 0,
  8494.         Height = 0,
  8495.         BackgroundColour = colours.lightGrey,
  8496.         TextColour = colours.black,
  8497.         Parent = nil,
  8498.         TextInput = nil,
  8499.         Placeholder = '',
  8500.  
  8501.         AbsolutePosition = function(self)
  8502.             return self.Parent:AbsolutePosition()
  8503.         end,
  8504.  
  8505.         Draw = function(self)      
  8506.             local pos = GetAbsolutePosition(self)
  8507.             Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, self.BackgroundColour)
  8508.             local text = self.TextInput.Value
  8509.             if #tostring(text) > (self.Width - 2) then
  8510.                 text = text:sub(#text-(self.Width - 3))
  8511.                 if Current.TextInput == self.TextInput then
  8512.                     Current.CursorPos = {pos.X + 1 + self.Width-2, pos.Y}
  8513.                 end
  8514.             else
  8515.                 if Current.TextInput == self.TextInput then
  8516.                     Current.CursorPos = {pos.X + 1 + self.TextInput.CursorPos, pos.Y}
  8517.                 end
  8518.             end
  8519.            
  8520.             if #tostring(text) == 0 then
  8521.                 Drawing.DrawCharacters(pos.X + 1, pos.Y, self.Placeholder, colours.lightGrey, self.BackgroundColour)
  8522.             else
  8523.                 Drawing.DrawCharacters(pos.X + 1, pos.Y, text, self.TextColour, self.BackgroundColour)
  8524.             end
  8525.  
  8526.             term.setCursorBlink(true)
  8527.            
  8528.             Current.CursorColour = self.TextColour
  8529.         end,
  8530.  
  8531.         Initialise = function(self, x, y, width, height, parent, text, backgroundColour, textColour, done, numerical)
  8532.             local new = {}    -- the new instance
  8533.             setmetatable( new, {__index = self} )
  8534.             height = height or 1
  8535.             new.Width = width or #text + 2
  8536.             new.Height = height
  8537.             new.Y = y
  8538.             new.X = x
  8539.             new.TextInput = TextInput:Initialise(text or '', function(key)
  8540.                 if done then
  8541.                     done(key)
  8542.                 end
  8543.                 Draw()
  8544.             end, numerical)
  8545.             new.BackgroundColour = backgroundColour or colours.lightGrey
  8546.             new.TextColour = textColour or colours.black
  8547.             new.Parent = parent
  8548.             return new
  8549.         end,
  8550.  
  8551.         Click = function(self, side, x, y)
  8552.             Current.Input = self.TextInput
  8553.             self:Draw()
  8554.         end
  8555.     }
  8556.  
  8557.     TextInput = {
  8558.         Value = "",
  8559.         Change = nil,
  8560.         CursorPos = nil,
  8561.         Numerical = false,
  8562.         IsDocument = nil,
  8563.  
  8564.         Initialise = function(self, value, change, numerical, isDocument)
  8565.             local new = {}    -- the new instance
  8566.             setmetatable( new, {__index = self} )
  8567.             new.Value = tostring(value)
  8568.             new.Change = change
  8569.             new.CursorPos = #tostring(value)
  8570.             new.Numerical = numerical
  8571.             new.IsDocument = isDocument or false
  8572.             return new
  8573.         end,
  8574.  
  8575.         Insert = function(self, str)
  8576.             if self.Numerical then
  8577.                 str = tostring(tonumber(str))
  8578.             end
  8579.  
  8580.             local selection = OrderSelection()
  8581.  
  8582.             if self.IsDocument and selection then
  8583.                 self.Value = string.sub(self.Value, 1, selection[1]-1) .. str .. string.sub( self.Value, selection[2]+2)
  8584.                 self.CursorPos = selection[1]
  8585.                 Current.Selection = nil
  8586.             else
  8587.                 local _, newLineAdjust = string.gsub(self.Value:sub(1, self.CursorPos), '\n','')
  8588.  
  8589.                 self.Value = string.sub(self.Value, 1, self.CursorPos + newLineAdjust) .. str .. string.sub( self.Value, self.CursorPos + 1  + newLineAdjust)
  8590.                 self.CursorPos = self.CursorPos + 1
  8591.             end
  8592.            
  8593.             self.Change(key)
  8594.         end,
  8595.  
  8596.         Extract = function(self, remove)
  8597.             local selection = OrderSelection()
  8598.             if self.IsDocument and selection then
  8599.                 local _, newLineAdjust = string.gsub(self.Value:sub(selection[1], selection[2]), '\n','')
  8600.                 local str = string.sub(self.Value, selection[1], selection[2]+1+newLineAdjust)
  8601.                 if remove then
  8602.                     self.Value = string.sub(self.Value, 1, selection[1]-1) .. string.sub( self.Value, selection[2]+2+newLineAdjust)
  8603.                     self.CursorPos = selection[1] - 1
  8604.                     Current.Selection = nil
  8605.                 end
  8606.                 return str
  8607.             end
  8608.         end,
  8609.  
  8610.         Char = function(self, char)
  8611.             if char == 'nil' then
  8612.                 return
  8613.             end
  8614.             self:Insert(char)
  8615.         end,
  8616.  
  8617.         Key = function(self, key)
  8618.             if key == keys.enter then
  8619.                 if self.IsDocument then
  8620.                     self.Value = string.sub(self.Value, 1, self.CursorPos ) .. '\n' .. string.sub( self.Value, self.CursorPos + 1 )
  8621.                     self.CursorPos = self.CursorPos + 1
  8622.                 end
  8623.                 self.Change(key)        
  8624.             elseif key == keys.left then
  8625.                 -- Left
  8626.                 if self.CursorPos > 0 then
  8627.                     local colShift = FindColours(string.sub( self.Value, self.CursorPos, self.CursorPos))
  8628.                     self.CursorPos = self.CursorPos - 1 - colShift
  8629.                     self.Change(key)
  8630.                 end
  8631.                
  8632.             elseif key == keys.right then
  8633.                 -- Right                
  8634.                 if self.CursorPos < string.len(self.Value) then
  8635.                     local colShift = FindColours(string.sub( self.Value, self.CursorPos+1, self.CursorPos+1))
  8636.                     self.CursorPos = self.CursorPos + 1 + colShift
  8637.                     self.Change(key)
  8638.                 end
  8639.            
  8640.             elseif key == keys.backspace then
  8641.                 -- Backspace
  8642.                 if self.IsDocument and Current.Selection then
  8643.                     self:Extract(true)
  8644.                     self.Change(key)
  8645.                 elseif self.CursorPos > 0 then
  8646.                     local colShift = FindColours(string.sub( self.Value, self.CursorPos, self.CursorPos))
  8647.                     local _, newLineAdjust = string.gsub(self.Value:sub(1, self.CursorPos), '\n','')
  8648.  
  8649.                     self.Value = string.sub( self.Value, 1, self.CursorPos - 1 - colShift + newLineAdjust) .. string.sub( self.Value, self.CursorPos + 1 - colShift + newLineAdjust)
  8650.                     self.CursorPos = self.CursorPos - 1 - colShift
  8651.                     self.Change(key)
  8652.                 end
  8653.             elseif key == keys.home then
  8654.                 -- Home
  8655.                 self.CursorPos = 0
  8656.                 self.Change(key)
  8657.             elseif key == keys.delete then
  8658.                 if self.IsDocument and Current.Selection then
  8659.                     self:Extract(true)
  8660.                     self.Change(key)
  8661.                 elseif self.CursorPos < string.len(self.Value) then
  8662.                     self.Value = string.sub( self.Value, 1, self.CursorPos ) .. string.sub( self.Value, self.CursorPos + 2 )                
  8663.                     self.Change(key)
  8664.                 end
  8665.             elseif key == keys["end"] then
  8666.                 -- End
  8667.                 self.CursorPos = string.len(self.Value)
  8668.                 self.Change(key)
  8669.             elseif key == keys.up and self.IsDocument then
  8670.                 -- Up
  8671.                 if Current.Document.CursorPos then
  8672.                     local page = Current.Document.Pages[Current.Document.CursorPos.Page]
  8673.                     self.CursorPos = page:GetCursorPosFromPoint(Current.Document.CursorPos.Collum + page.MarginX, Current.Document.CursorPos.Line - page.MarginY - 1 + Current.Document.ScrollBar.Scroll, true)
  8674.                     self.Change(key)
  8675.                 end
  8676.             elseif key == keys.down and self.IsDocument then
  8677.                 -- Down
  8678.                 if Current.Document.CursorPos then
  8679.                     local page = Current.Document.Pages[Current.Document.CursorPos.Page]
  8680.                     self.CursorPos = page:GetCursorPosFromPoint(Current.Document.CursorPos.Collum + page.MarginX, Current.Document.CursorPos.Line - page.MarginY + 1 + Current.Document.ScrollBar.Scroll, true)
  8681.                     self.Change(key)
  8682.                 end
  8683.             end
  8684.         end
  8685.     }
  8686.  
  8687.     Menu = {
  8688.         X = 0,
  8689.         Y = 0,
  8690.         Width = 0,
  8691.         Height = 0,
  8692.         Owner = nil,
  8693.         Items = {},
  8694.         RemoveTop = false,
  8695.  
  8696.         Draw = function(self)
  8697.             Drawing.DrawBlankArea(self.X + 1, self.Y + 1, self.Width, self.Height, UIColours.Shadow)
  8698.             if not self.RemoveTop then
  8699.                 Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.MenuBackground)
  8700.                 for i, item in ipairs(self.Items) do
  8701.                     if item.Separator then
  8702.                         Drawing.DrawArea(self.X, self.Y + i, self.Width, 1, '-', colours.grey, UIColours.MenuBackground)
  8703.                     else
  8704.                         local textColour = item.Colour or UIColours.MenuText
  8705.                         if (item.Enabled and type(item.Enabled) == 'function' and item.Enabled() == false) or item.Enabled == false then
  8706.                             textColour = UIColours.MenuDisabledText
  8707.                         end
  8708.                         Drawing.DrawCharacters(self.X + 1, self.Y + i, item.Title, textColour, UIColours.MenuBackground)
  8709.                     end
  8710.                 end
  8711.             else
  8712.                 Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.MenuBackground)
  8713.                 for i, item in ipairs(self.Items) do
  8714.                     if item.Separator then
  8715.                         Drawing.DrawArea(self.X, self.Y + i - 1, self.Width, 1, '-', colours.grey, UIColours.MenuBackground)
  8716.                     else
  8717.                         local textColour = item.Colour or UIColours.MenuText
  8718.                         if (item.Enabled and type(item.Enabled) == 'function' and item.Enabled() == false) or item.Enabled == false then
  8719.                             textColour = UIColours.MenuDisabledText
  8720.                         end
  8721.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - 1, item.Title, textColour, UIColours.MenuBackground)
  8722.  
  8723.                         Drawing.DrawCharacters(self.X - 1 + self.Width-#item.KeyName, self.Y + i - 1, item.KeyName, textColour, UIColours.MenuBackground)
  8724.                     end
  8725.                 end
  8726.             end
  8727.         end,
  8728.  
  8729.         NameForKey = function(self, key)
  8730.             if key == keys.leftCtrl then
  8731.                 return '^'
  8732.             elseif key == keys.tab then
  8733.                 return 'Tab'
  8734.             elseif key == keys.delete then
  8735.                 return 'Delete'
  8736.             elseif key == keys.n then
  8737.                 return 'N'
  8738.             elseif key == keys.a then
  8739.                 return 'A'
  8740.             elseif key == keys.s then
  8741.                 return 'S'
  8742.             elseif key == keys.o then
  8743.                 return 'O'
  8744.             elseif key == keys.z then
  8745.                 return 'Z'
  8746.             elseif key == keys.y then
  8747.                 return 'Y'
  8748.             elseif key == keys.c then
  8749.                 return 'C'
  8750.             elseif key == keys.x then
  8751.                 return 'X'
  8752.             elseif key == keys.v then
  8753.                 return 'V'
  8754.             elseif key == keys.r then
  8755.                 return 'R'
  8756.             elseif key == keys.l then
  8757.                 return 'L'
  8758.             elseif key == keys.t then
  8759.                 return 'T'
  8760.             elseif key == keys.h then
  8761.                 return 'H'
  8762.             elseif key == keys.e then
  8763.                 return 'E'
  8764.             elseif key == keys.p then
  8765.                 return 'P'
  8766.             elseif key == keys.f then
  8767.                 return 'F'
  8768.             elseif key == keys.m then
  8769.                 return 'M'
  8770.             elseif key == keys.q then
  8771.                 return 'Q'
  8772.             else
  8773.                 return '?'      
  8774.             end
  8775.         end,
  8776.  
  8777.         Initialise = function(self, x, y, items, owner, removeTop)
  8778.             local new = {}    -- the new instance
  8779.             setmetatable( new, {__index = self} )
  8780.             if not owner then
  8781.                 return
  8782.             end
  8783.  
  8784.             local keyNames = {}
  8785.  
  8786.             for i, v in ipairs(items) do
  8787.                 items[i].KeyName = ''
  8788.                 if v.Keys then
  8789.                     for _i, key in ipairs(v.Keys) do
  8790.                         items[i].KeyName = items[i].KeyName .. self:NameForKey(key)
  8791.                     end
  8792.                 end
  8793.                 if items[i].KeyName ~= '' then
  8794.                     table.insert(keyNames, items[i].KeyName)
  8795.                 end
  8796.             end
  8797.             local keysLength = LongestString(keyNames)
  8798.             if keysLength > 0 then
  8799.                 keysLength = keysLength + 2
  8800.             end
  8801.  
  8802.             new.Width = LongestString(items, 'Title') + 2 + keysLength
  8803.             if new.Width < 10 then
  8804.                 new.Width = 10
  8805.             end
  8806.             new.Height = #items + 2
  8807.             new.RemoveTop = removeTop or false
  8808.             if removeTop then
  8809.                 new.Height = new.Height - 1
  8810.             end
  8811.            
  8812.             if y < 1 then
  8813.                 y = 1
  8814.             end
  8815.             if x < 1 then
  8816.                 x = 1
  8817.             end
  8818.  
  8819.             if y + new.Height > Drawing.Screen.Height + 1 then
  8820.                 y = Drawing.Screen.Height - new.Height
  8821.             end
  8822.             if x + new.Width > Drawing.Screen.Width + 1 then
  8823.                 x = Drawing.Screen.Width - new.Width
  8824.             end
  8825.  
  8826.  
  8827.             new.Y = y
  8828.             new.X = x
  8829.             new.Items = items
  8830.             new.Owner = owner
  8831.             return new
  8832.         end,
  8833.  
  8834.         New = function(self, x, y, items, owner, removeTop)
  8835.             if Current.Menu and Current.Menu.Owner == owner then
  8836.                 Current.Menu = nil
  8837.                 return
  8838.             end
  8839.  
  8840.             local new = self:Initialise(x, y, items, owner, removeTop)
  8841.             Current.Menu = new
  8842.             return new
  8843.         end,
  8844.  
  8845.         Click = function(self, side, x, y)
  8846.             local i = y-1
  8847.             if self.RemoveTop then
  8848.                 i = y
  8849.             end
  8850.             if i >= 1 and y < self.Height then
  8851.                 if not ((self.Items[i].Enabled and type(self.Items[i].Enabled) == 'function' and self.Items[i].Enabled() == false) or self.Items[i].Enabled == false) and self.Items[i].Click then
  8852.                     self.Items[i]:Click()
  8853.                     if Current.Menu.Owner and Current.Menu.Owner.Toggle then
  8854.                         Current.Menu.Owner.Toggle = false
  8855.                     end
  8856.                     Current.Menu = nil
  8857.                     self = nil
  8858.                 end
  8859.                 return true
  8860.             end
  8861.         end
  8862.     }
  8863.  
  8864.     MenuBar = {
  8865.         X = 1,
  8866.         Y = 1,
  8867.         Width = Drawing.Screen.Width,
  8868.         Height = 1,
  8869.         MenuBarItems = {},
  8870.  
  8871.         AbsolutePosition = function(self)
  8872.             return {X = self.X, Y = self.Y}
  8873.         end,
  8874.  
  8875.         Draw = function(self)
  8876.             --Drawing.DrawArea(self.X - 1, self.Y, 1, self.Height, "|", UIColours.ToolbarText, UIColours.Background)
  8877.  
  8878.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, colours.grey)
  8879.             for i, button in ipairs(self.MenuBarItems) do
  8880.                 button:Draw()
  8881.             end
  8882.         end,
  8883.  
  8884.         Initialise = function(self, items)
  8885.             local new = {}    -- the new instance
  8886.             setmetatable( new, {__index = self} )
  8887.             new.X = 1
  8888.             new.Y = 1
  8889.             new.MenuBarItems = items
  8890.             return new
  8891.         end,
  8892.  
  8893.         AddToolbarItem = function(self, item)
  8894.             table.insert(self.ToolbarItems, item)
  8895.             self:CalculateToolbarItemPositions()
  8896.         end,
  8897.  
  8898.         CalculateToolbarItemPositions = function(self)
  8899.             local currY = 1
  8900.             for i, toolbarItem in ipairs(self.ToolbarItems) do
  8901.                 toolbarItem.Y = currY
  8902.                 currY = currY + toolbarItem.Height
  8903.             end
  8904.         end,
  8905.  
  8906.         Click = function(self, side, x, y)
  8907.             for i, item in ipairs(self.MenuBarItems) do
  8908.                 if item.X <= x and item.X + item.Width > x then
  8909.                     if item:Click(item, side, x - item.X + 1, 1) then
  8910.                         return true
  8911.                     end
  8912.                 end
  8913.             end
  8914.             return false
  8915.         end
  8916.     }
  8917.  
  8918.     TextFormatPlainText = 1
  8919.     TextFormatInkText = 2
  8920.  
  8921.     Document = {
  8922.         X = 1,
  8923.         Y = 1,
  8924.         PageSize = {Width = 25, Height = 21},
  8925.         TextInput = nil,
  8926.         Pages = {},
  8927.         Format = TextFormatPlainText,
  8928.         Title = '',
  8929.         Path = nil,
  8930.         ScrollBar = nil,
  8931.         Lines = {},
  8932.         CursorPos = nil,
  8933.  
  8934.         CalculateLineWrapping = function(self)
  8935.             local limit = self.PageSize.Width
  8936.             local text = self.TextInput.Value
  8937.             local lines = {''}
  8938.             local words = {}
  8939.  
  8940.             for word, space in text:gmatch('(%S+)(%s*)') do
  8941.                 for i = 1, math.ceil(#word/limit) do
  8942.                     local _space = ''
  8943.                     if i == math.ceil(#word/limit) then
  8944.                         _space = space
  8945.                     end
  8946.                     table.insert(words, {word:sub(1+limit*(i-1), limit*i), _space})
  8947.                 end
  8948.             end
  8949.  
  8950.             for i, ws in ipairs(words) do
  8951.                     local word = ws[1]
  8952.                     local space = ws[2]
  8953.                     local temp = lines[#lines] .. word .. space:gsub('\n','')
  8954.                     if #temp > limit then
  8955.                         table.insert(lines, '')
  8956.                     end
  8957.                     if space:find('\n') then
  8958.                         lines[#lines] = lines[#lines] .. word
  8959.                        
  8960.                         space = space:gsub('\n', function()
  8961.                                 table.insert(lines, '')
  8962.                                 return ''
  8963.                         end)
  8964.                     else
  8965.                         lines[#lines] = lines[#lines] .. word .. space
  8966.                     end
  8967.             end
  8968.             return lines
  8969.         end,
  8970.  
  8971.         CalculateCursorPos = function(self)
  8972.             local passedCharacters = 0
  8973.             Current.CursorPos = nil
  8974.             for p, page in ipairs(self.Pages) do
  8975.                 page:Draw()
  8976.                 if not Current.CursorPos then
  8977.                     for i, line in ipairs(page.Lines) do
  8978.                         local relCursor = self.TextInput.CursorPos - FindColours(self.TextInput.Value:sub(1,self.TextInput.CursorPos))
  8979.                         if passedCharacters + #StripColours(line.Text:gsub('\n','')) >= relCursor then
  8980.                             Current.CursorPos = {self.X + page.MarginX + (relCursor - passedCharacters), page.Y + 1 + i}
  8981.                             self.CursorPos = {Page = p, Line = i, Collum = relCursor - passedCharacters - FindColours(self.TextInput.Value:sub(1,self.TextInput.CursorPos-1))}
  8982.                             break
  8983.                         end
  8984.                         passedCharacters = passedCharacters + #StripColours(line.Text:gsub('\n',''))
  8985.                     end
  8986.                 end
  8987.             end
  8988.         end,
  8989.  
  8990.         Draw = function(self)
  8991.             self:CalculatePages()
  8992.             self:CalculateCursorPos()
  8993.             self.ScrollBar:Draw()
  8994.         end,
  8995.  
  8996.         CalculatePages = function(self)
  8997.             self.Pages = {}
  8998.             local lines = self:CalculateLineWrapping()
  8999.             self.Lines = lines
  9000.             local pageLines = {}
  9001.             local totalPageHeight = (3 + self.PageSize.Height + 2 * Page.MarginY)
  9002.             for i, line in ipairs(lines) do
  9003.                 table.insert(pageLines, TextLine:Initialise(line))
  9004.                 if i % self.PageSize.Height == 0 then
  9005.                     table.insert(self.Pages, Page:Initialise(self, pageLines, 3 - self.ScrollBar.Scroll + totalPageHeight*(#self.Pages)))
  9006.                     pageLines = {}
  9007.                 end
  9008.             end
  9009.             if #pageLines ~= 0 then
  9010.                 table.insert(self.Pages, Page:Initialise(self, pageLines, 3 - self.ScrollBar.Scroll + totalPageHeight*(#self.Pages)))
  9011.             end
  9012.  
  9013.             self.ScrollBar.MaxScroll = totalPageHeight*(#self.Pages) - Drawing.Screen.Height + 1
  9014.         end,
  9015.  
  9016.         ScrollToCursor = function(self)
  9017.             self:CalculateCursorPos()
  9018.             if Current.CursorPos and
  9019.                 (Current.CursorPos[2] > Drawing.Screen.Height
  9020.                 or Current.CursorPos[2] < 2) then
  9021.                 self.ScrollBar:DoScroll(Current.CursorPos[2] - Drawing.Screen.Height)
  9022.             end
  9023.         end,
  9024.  
  9025.         SetSelectionColour = function(self, colour)
  9026.             local selection = OrderSelection()
  9027.             local text = self.TextInput:Extract(true)
  9028.             local colChar = CharacterFromColour(colour)
  9029.             local precedingColour = ''
  9030.             if FindColours(self.TextInput.Value:sub(self.TextInput.CursorPos+1, self.TextInput.CursorPos+1)) == 0 then
  9031.                 for i = 1, self.TextInput.CursorPos do
  9032.                     local c = self.TextInput.Value:sub(self.TextInput.CursorPos - i,self.TextInput.CursorPos - i)
  9033.                     if FindColours(c) == 1 then
  9034.                         precedingColour = c
  9035.                         break
  9036.                     end
  9037.                 end
  9038.                 if precedingColour == '' then
  9039.                     precedingColour = CharacterFromColour(colours.black)
  9040.                 end
  9041.             end
  9042.  
  9043.             self.TextInput:Insert(colChar..StripColours(text)..precedingColour)
  9044.             --text = text:gsub('['..string.char(14)..'-'..string.char(29)..']','')
  9045.         end,
  9046.  
  9047.         Initialise = function(self, text, title, path)
  9048.             local new = {}    -- the new instance
  9049.             setmetatable( new, {__index = self} )
  9050.             new.Title = title or 'New Document'
  9051.             new.Path = path
  9052.             new.X = (Drawing.Screen.Width - (new.PageSize.Width + 2*(Page.MarginX)))/2
  9053.             new.Y = 2
  9054.             new.TextInput = TextInput:Initialise(text, function()
  9055.                 new:ScrollToCursor()
  9056.                 Current.Modified = true
  9057.                 Draw()
  9058.             end, false, true)
  9059.             new.ScrollBar = ScrollBar:Initialise(Drawing.Screen.Width, new.Y, Drawing.Screen.Height-1, 0, nil, nil, nil, function()end)
  9060.             Current.TextInput = new.TextInput
  9061.             Current.ScrollBar = new.ScrollBar
  9062.             return new
  9063.         end
  9064.     }
  9065.  
  9066.     ScrollBar = {
  9067.         X = 1,
  9068.         Y = 1,
  9069.         Width = 1,
  9070.         Height = 1,
  9071.         BackgroundColour = colours.grey,
  9072.         BarColour = colours.lightBlue,
  9073.         Parent = nil,
  9074.         Change = nil,
  9075.         Scroll = 0,
  9076.         MaxScroll = 0,
  9077.         ClickPoint = nil,
  9078.  
  9079.         AbsolutePosition = function(self)
  9080.             return self.Parent:AbsolutePosition()
  9081.         end,
  9082.  
  9083.         Draw = function(self)
  9084.             local pos = GetAbsolutePosition(self)
  9085.             local barHeight = self.Height - self.MaxScroll
  9086.             if barHeight < 3 then
  9087.               barHeight = 3
  9088.             end
  9089.             local percentage = (self.Scroll/self.MaxScroll)
  9090.  
  9091.             Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, self.BackgroundColour)
  9092.             Drawing.DrawBlankArea(pos.X, pos.Y + round(self.Height*percentage - barHeight*percentage), self.Width, barHeight, self.BarColour)
  9093.         end,
  9094.  
  9095.         Initialise = function(self, x, y, height, maxScroll, backgroundColour, barColour, parent, change)
  9096.             local new = {}    -- the new instance
  9097.             setmetatable( new, {__index = self} )
  9098.             new.Width = 1
  9099.             new.Height = height
  9100.             new.Y = y
  9101.             new.X = x
  9102.             new.BackgroundColour = backgroundColour or colours.grey
  9103.             new.BarColour = barColour or colours.lightBlue
  9104.             new.Parent = parent
  9105.             new.Change = change or function()end
  9106.             new.MaxScroll = maxScroll
  9107.             new.Scroll = 0
  9108.             return new
  9109.         end,
  9110.  
  9111.         DoScroll = function(self, amount)
  9112.             amount = round(amount)
  9113.             if self.Scroll < 0 or self.Scroll > self.MaxScroll then
  9114.                 return false
  9115.             end
  9116.             self.Scroll = self.Scroll + amount
  9117.             if self.Scroll < 0 then
  9118.                 self.Scroll = 0
  9119.             elseif self.Scroll > self.MaxScroll then
  9120.                 self.Scroll = self.MaxScroll
  9121.             end
  9122.             self.Change()
  9123.             return true
  9124.         end,
  9125.  
  9126.         Click = function(self, side, x, y, drag)
  9127.             local percentage = (self.Scroll/self.MaxScroll)
  9128.             local barHeight = (self.Height - self.MaxScroll)
  9129.             if barHeight < 3 then
  9130.                 barHeight = 3
  9131.             end
  9132.             local relScroll = (self.MaxScroll*(y + barHeight*percentage)/self.Height)
  9133.             if not drag then
  9134.                 self.ClickPoint = self.Scroll - relScroll + 1
  9135.             end
  9136.  
  9137.             if self.Scroll-1 ~= relScroll then
  9138.                 self:DoScroll(relScroll-self.Scroll-1 + self.ClickPoint)
  9139.             end
  9140.             return true
  9141.         end
  9142.     }
  9143.  
  9144.     AlignmentLeft = 1
  9145.     AlignmentCentre = 2
  9146.     AlignmentRight = 3
  9147.  
  9148.     TextLine = {
  9149.         Text = "",
  9150.         Alignment = AlignmentLeft,
  9151.  
  9152.         Initialise = function(self, text, alignment)
  9153.             local new = {}    -- the new instance
  9154.             setmetatable( new, {__index = self} )
  9155.             new.Text = text
  9156.             new.Alignment = alignment or AlignmentLeft
  9157.             return new
  9158.         end
  9159.     }
  9160.  
  9161.     local clickPos = 1
  9162.     Page = {
  9163.         X = 1,
  9164.         Y = 1,
  9165.         Width = 1,
  9166.         Height = 1,
  9167.         MarginX = 3,
  9168.         MarginY = 2,
  9169.         BackgroundColour = colours.white,
  9170.         TextColour = colours.white,
  9171.         ActiveBackgroundColour = colours.lightGrey,
  9172.         Lines = {},
  9173.         Parent = nil,
  9174.  
  9175.         AbsolutePosition = function(self)
  9176.             return self.Parent:AbsolutePosition()
  9177.         end,
  9178.  
  9179.         Draw = function(self)
  9180.             local pos = GetAbsolutePosition(self)
  9181.  
  9182.             if pos.Y > Drawing.Screen.Height or pos.Y + self.Height < 1 then
  9183.                 return
  9184.             end
  9185.  
  9186.             Drawing.DrawBlankArea(pos.X+self.Width,pos.Y -1 + 1, 1, self.Height, UIColours.Shadow)
  9187.             Drawing.DrawBlankArea(pos.X+1, pos.Y -1 + self.Height, self.Width, 1, UIColours.Shadow)
  9188.             Drawing.DrawBlankArea(pos.X, pos.Y -1, self.Width, self.Height, self.BackgroundColour)
  9189.  
  9190.             local textColour = self.TextColour
  9191.             if not Current.Selection then
  9192.                 for i, line in ipairs(self.Lines) do
  9193.                     local _c = 1
  9194.                     for c = 1, #line.Text do
  9195.                         local col = ColourFromCharacter(line.Text:sub(c,c))
  9196.                         if col then
  9197.                             textColour = col
  9198.                         else
  9199.                             Drawing.WriteToBuffer(pos.X + self.MarginX - 1 + _c, pos.Y -2 + i + self.MarginY, line.Text:sub(c,c), textColour, self.BackgroundColour)
  9200.                             _c = _c + 1
  9201.                         end
  9202.                     end
  9203.                 end
  9204.             else
  9205.                 local selection = OrderSelection()
  9206.                 local char = 1
  9207.                 local textColour = self.TextColour
  9208.                 for i, line in ipairs(self.Lines) do
  9209.                     local _c = 1
  9210.                     for c = 1, #line.Text do
  9211.                         local col = ColourFromCharacter(line.Text:sub(c,c))
  9212.                         if col then
  9213.                             textColour = col
  9214.                         else
  9215.                             local tc = textColour
  9216.                             local colour = colours.white
  9217.                             if char >= selection[1] and char <= selection[2] then
  9218.                                 colour = colours.lightBlue
  9219.                                 tc = colours.white
  9220.                             end
  9221.  
  9222.                             Drawing.WriteToBuffer(pos.X + self.MarginX - 1 + _c, pos.Y -2 + i + self.MarginY, line.Text:sub(c,c), tc, colour)
  9223.                             _c = _c + 1
  9224.                         end
  9225.                         char = char + 1
  9226.                     end
  9227.                 end
  9228.             end
  9229.         end,
  9230.  
  9231.         Initialise = function(self, parent, lines, y)
  9232.             local new = {}    -- the new instanc
  9233.             setmetatable( new, {__index = self} )
  9234.             new.Height = parent.PageSize.Height + 2 * self.MarginY
  9235.             new.Width = parent.PageSize.Width + 2 * self.MarginX
  9236.             new.X = 1
  9237.             new.Y = y or 1
  9238.             new.Lines = lines or {}
  9239.             new.BackgroundColour = colours.white
  9240.             new.TextColour = colours.black
  9241.             new.Parent = parent
  9242.             new.ClickPos = 1
  9243.             return new
  9244.         end,
  9245.  
  9246.         GetCursorPosFromPoint = function(self, x, y, rel)
  9247.             local pos = GetAbsolutePosition(self)
  9248.             if rel then
  9249.                 pos = {Y = 0, X = 0}
  9250.             end
  9251.             local row = y - pos.Y + self.MarginY - self.Parent.ScrollBar.Scroll
  9252.             local col = x - self.MarginX - pos.X + 1
  9253.             local cursorPos = 0
  9254.             if row <= 0 or col <= 0 then
  9255.                 return 0
  9256.             end
  9257.  
  9258.             if row > #self.Lines then
  9259.                 for i, v in ipairs(self.Lines) do
  9260.                     cursorPos = cursorPos + #v.Text-- - FindColours(v.Text)
  9261.                 end
  9262.                 return cursorPos
  9263.             end
  9264.  
  9265.             --term.setCursorPos(1,3)
  9266.             local prevLineCount = 0
  9267.             for i, v in ipairs(self.Lines) do
  9268.                 if i == row then
  9269.                     if col > #v.Text then
  9270.                         col = #v.Text-- + FindColours(v.Text)
  9271.                     else
  9272.                         col = col + FindColours(v.Text:sub(1, col))
  9273.                     end
  9274.                     --term.setCursorPos(1,2)
  9275.                     --print(prevLineCount)
  9276.                     cursorPos = cursorPos + col + 2 - i - prevLineCount
  9277.                     break
  9278.                 else
  9279.                     prevLineCount = FindColours(v.Text)
  9280.                     if prevLineCount ~= 0 then
  9281.                         prevLineCount = prevLineCount
  9282.                     end
  9283.                     cursorPos = cursorPos + #v.Text + 2 - i + FindColours(v.Text)
  9284.                 end
  9285.             end
  9286.  
  9287.             return cursorPos - 2
  9288.         end,
  9289.  
  9290.         Click = function(self, side, x, y, drag)
  9291.             local cursorPos = self:GetCursorPosFromPoint(x, y)
  9292.             self.Parent.TextInput.CursorPos = cursorPos
  9293.             if drag == nil then
  9294.                 Current.Selection = nil
  9295.                 clickPos = x
  9296.             else
  9297.                 local relCursor = cursorPos-- - FindColours(self.Parent.TextInput.Value:sub(1,cursorPos)) + 1
  9298.                 if not Current.Selection then
  9299.                     local adder = 1
  9300.                     if clickPos and clickPos < x then
  9301.                         adder = 0
  9302.                     end
  9303.                     Current.Selection = {relCursor + adder, relCursor + 1 + adder}
  9304.                 else
  9305.                     Current.Selection[2] = relCursor + 1
  9306.                 end
  9307.             end
  9308.             Draw()
  9309.             return true
  9310.         end
  9311.     }
  9312.  
  9313.     function GetAbsolutePosition(object)
  9314.         local obj = object
  9315.         local i = 0
  9316.         local x = 1
  9317.         local y = 1
  9318.         while true do
  9319.             x = x + obj.X - 1
  9320.             y = y + obj.Y - 1
  9321.  
  9322.             if not obj.Parent then
  9323.                 return {X = x, Y = y}
  9324.             end
  9325.  
  9326.             obj = obj.Parent
  9327.  
  9328.             if i > 32 then
  9329.                 return {X = 1, Y = 1}
  9330.             end
  9331.  
  9332.             i = i + 1
  9333.         end
  9334.  
  9335.     end
  9336.  
  9337.     function Draw()
  9338.         if not Current.Window then
  9339.             Drawing.Clear(colours.lightGrey)
  9340.         else
  9341.             Drawing.DrawArea(1, 2, Drawing.Screen.Width, Drawing.Screen.Height, '|', colours.black, colours.lightGrey)
  9342.         end
  9343.  
  9344.         if Current.Document then
  9345.             Current.Document:Draw()
  9346.         end
  9347.  
  9348.         Current.MenuBar:Draw()
  9349.  
  9350.         if Current.Window then
  9351.             Current.Window:Draw()
  9352.         end
  9353.  
  9354.         if Current.Menu then
  9355.             Current.Menu:Draw()
  9356.         end
  9357.  
  9358.         Drawing.DrawBuffer()
  9359.  
  9360.         if Current.TextInput and Current.CursorPos and not Current.Menu and not(Current.Window and Current.Document and Current.TextInput == Current.Document.TextInput) and Current.CursorPos[2] > 1 then
  9361.             term.setCursorPos(Current.CursorPos[1], Current.CursorPos[2])
  9362.             term.setCursorBlink(true)
  9363.             term.setTextColour(Current.CursorColour)
  9364.         else
  9365.             term.setCursorBlink(false)
  9366.         end
  9367.     end
  9368.     MainDraw = Draw
  9369.  
  9370.     LongestString = function(input, key)
  9371.         local length = 0
  9372.         for i = 1, #input do
  9373.             local value = input[i]
  9374.             if key then
  9375.                 if value[key] then
  9376.                     value = value[key]
  9377.                 else
  9378.                     value = ''
  9379.                 end
  9380.             end
  9381.             local titleLength = string.len(value)
  9382.             if titleLength > length then
  9383.                 length = titleLength
  9384.             end
  9385.         end
  9386.         return length
  9387.     end
  9388.  
  9389.     function LoadMenuBar()
  9390.         Current.MenuBar = MenuBar:Initialise({
  9391.             Button:Initialise(1, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  9392.                 if toggle then
  9393.                     Menu:New(1, 2, {
  9394.                         {
  9395.                             Title = "New...",
  9396.                             Click = function()
  9397.                                 Current.Document = Document:Initialise('')                          
  9398.                             end,
  9399.                             Keys = {
  9400.                                 keys.leftCtrl,
  9401.                                 keys.n
  9402.                             }
  9403.                         },
  9404.                         {
  9405.                             Title = 'Open...',
  9406.                             Click = function()
  9407.                                 DisplayOpenDocumentWindow()
  9408.                             end,
  9409.                             Keys = {
  9410.                                 keys.leftCtrl,
  9411.                                 keys.o
  9412.                             }
  9413.                         },
  9414.                         {
  9415.                             Separator = true
  9416.                         },
  9417.                         {
  9418.                             Title = 'Save...',
  9419.                             Click = function()
  9420.                                 SaveDocument()
  9421.                             end,
  9422.                             Keys = {
  9423.                                 keys.leftCtrl,
  9424.                                 keys.s
  9425.                             },
  9426.                             Enabled = function()
  9427.                                 return true
  9428.                             end
  9429.                         },
  9430.                         {
  9431.                             Separator = true
  9432.                         },
  9433.                         {
  9434.                             Title = 'Print...',
  9435.                             Click = function()
  9436.                                 PrintDocument()
  9437.                             end,
  9438.                             Keys = {
  9439.                                 keys.leftCtrl,
  9440.                                 keys.p
  9441.                             },
  9442.                             Enabled = function()
  9443.                                 return true
  9444.                             end
  9445.                         },
  9446.                         {
  9447.                             Separator = true
  9448.                         },
  9449.                         {
  9450.                             Title = 'Quit',
  9451.                             Click = function()
  9452.                                 Close()
  9453.                             end
  9454.                         },
  9455.                 --[[
  9456.                         {
  9457.                             Title = 'Save As...',
  9458.                             Click = function()
  9459.  
  9460.                             end
  9461.                         }  
  9462.                 ]]--
  9463.                     }, self, true)
  9464.                 else
  9465.                     Current.Menu = nil
  9466.                 end
  9467.                 return true
  9468.             end, 'File', colours.lightGrey, false),
  9469.             Button:Initialise(7, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  9470.                 if not self.Toggle then
  9471.                     Menu:New(7, 2, {
  9472.                 --[[
  9473.                         {
  9474.                             Title = "Undo",
  9475.                             Click = function()
  9476.                             end,
  9477.                             Keys = {
  9478.                                 keys.leftCtrl,
  9479.                                 keys.z
  9480.                             },
  9481.                             Enabled = function()
  9482.                                 return false
  9483.                             end
  9484.                         },
  9485.                         {
  9486.                             Title = 'Redo',
  9487.                             Click = function()
  9488.                                
  9489.                             end,
  9490.                             Keys = {
  9491.                                 keys.leftCtrl,
  9492.                                 keys.y
  9493.                             },
  9494.                             Enabled = function()
  9495.                                 return false
  9496.                             end
  9497.                         },
  9498.                         {
  9499.                             Separator = true
  9500.                         },
  9501.                 ]]--
  9502.                         {
  9503.                             Title = 'Cut',
  9504.                             Click = function()
  9505.                                 Clipboard.Cut(Current.Document.TextInput:Extract(true), 'text')
  9506.                             end,
  9507.                             Keys = {
  9508.                                 keys.leftCtrl,
  9509.                                 keys.x
  9510.                             },
  9511.                             Enabled = function()
  9512.                                 return Current.Document ~= nil and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil
  9513.                             end
  9514.                         },
  9515.                         {
  9516.                             Title = 'Copy',
  9517.                             Click = function()
  9518.                                 Clipboard.Copy(Current.Document.TextInput:Extract(), 'text')
  9519.                             end,
  9520.                             Keys = {
  9521.                                 keys.leftCtrl,
  9522.                                 keys.c
  9523.                             },
  9524.                             Enabled = function()
  9525.                                 return Current.Document ~= nil and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil
  9526.                             end
  9527.                         },
  9528.                         {
  9529.                             Title = 'Paste',
  9530.                             Click = function()
  9531.                                 local paste = Clipboard.Paste()
  9532.                                 Current.Document.TextInput:Insert(paste)
  9533.                                 Current.Document.TextInput.CursorPos = Current.Document.TextInput.CursorPos + #paste - 1
  9534.                             end,
  9535.                             Keys = {
  9536.                                 keys.leftCtrl,
  9537.                                 keys.v
  9538.                             },
  9539.                             Enabled = function()
  9540.                                 return Current.Document ~= nil and (not Clipboard.isEmpty()) and Clipboard.Type == 'text'
  9541.                             end
  9542.                         },
  9543.                         {
  9544.                             Separator = true,  
  9545.                         },
  9546.                         {
  9547.                             Title = 'Select All',
  9548.                             Click = function()
  9549.                                 Current.Selection = {1, #Current.Document.TextInput.Value:gsub('\n','')}
  9550.                             end,
  9551.                             Keys = {
  9552.                                 keys.leftCtrl,
  9553.                                 keys.a
  9554.                             },
  9555.                             Enabled = function()
  9556.                                 return Current.Document ~= nil
  9557.                             end
  9558.                         }
  9559.                     }, self, true)
  9560.                 else
  9561.                     Current.Menu = nil
  9562.                 end
  9563.                 return true
  9564.             end, 'Edit', colours.lightGrey, false)
  9565.         })
  9566.     end
  9567.  
  9568.     function LoadMenuBar()
  9569.         Current.MenuBar = MenuBar:Initialise({
  9570.             Button:Initialise(1, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  9571.                 if toggle then
  9572.                     Menu:New(1, 2, {
  9573.                         {
  9574.                             Title = "New...",
  9575.                             Click = function()
  9576.                                 Current.Document = Document:Initialise('')                          
  9577.                             end,
  9578.                             Keys = {
  9579.                                 keys.leftCtrl,
  9580.                                 keys.n
  9581.                             }
  9582.                         },
  9583.                         {
  9584.                             Title = 'Open...',
  9585.                             Click = function()
  9586.                                 DisplayOpenDocumentWindow()
  9587.                             end,
  9588.                             Keys = {
  9589.                                 keys.leftCtrl,
  9590.                                 keys.o
  9591.                             }
  9592.                         },
  9593.                         {
  9594.                             Separator = true
  9595.                         },
  9596.                         {
  9597.                             Title = 'Save...',
  9598.                             Click = function()
  9599.                                 SaveDocument()
  9600.                             end,
  9601.                             Keys = {
  9602.                                 keys.leftCtrl,
  9603.                                 keys.s
  9604.                             },
  9605.                             Enabled = function()
  9606.                                 return Current.Document ~= nil
  9607.                             end
  9608.                         },
  9609.                         {
  9610.                             Separator = true
  9611.                         },
  9612.                         {
  9613.                             Title = 'Print...',
  9614.                             Click = function()
  9615.                                 PrintDocument()
  9616.                             end,
  9617.                             Keys = {
  9618.                                 keys.leftCtrl,
  9619.                                 keys.p
  9620.                             },
  9621.                             Enabled = function()
  9622.                                 return true
  9623.                             end
  9624.                         },
  9625.                         {
  9626.                             Separator = true
  9627.                         },
  9628.                         {
  9629.                             Title = 'Quit',
  9630.                             Click = function()
  9631.                                 if Close() and OneOS then
  9632.                                     OneOS.Close()
  9633.                                 end
  9634.                             end,
  9635.                             Keys = {
  9636.                                 keys.leftCtrl,
  9637.                                 keys.q
  9638.                             }
  9639.                         },
  9640.                 --[[
  9641.                         {
  9642.                             Title = 'Save As...',
  9643.                             Click = function()
  9644.  
  9645.                             end
  9646.                         }  
  9647.                 ]]--
  9648.                     }, self, true)
  9649.                 else
  9650.                     Current.Menu = nil
  9651.                 end
  9652.                 return true
  9653.             end, 'File', colours.lightGrey, false),
  9654.             Button:Initialise(7, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  9655.                 if not self.Toggle then
  9656.                     Menu:New(7, 2, {
  9657.                 --[[
  9658.                         {
  9659.                             Title = "Undo",
  9660.                             Click = function()
  9661.                             end,
  9662.                             Keys = {
  9663.                                 keys.leftCtrl,
  9664.                                 keys.z
  9665.                             },
  9666.                             Enabled = function()
  9667.                                 return false
  9668.                             end
  9669.                         },
  9670.                         {
  9671.                             Title = 'Redo',
  9672.                             Click = function()
  9673.                                
  9674.                             end,
  9675.                             Keys = {
  9676.                                 keys.leftCtrl,
  9677.                                 keys.y
  9678.                             },
  9679.                             Enabled = function()
  9680.                                 return false
  9681.                             end
  9682.                         },
  9683.                         {
  9684.                             Separator = true
  9685.                         },
  9686.                 ]]--
  9687.                         {
  9688.                             Title = 'Cut',
  9689.                             Click = function()
  9690.                                 Clipboard.Cut(Current.Document.TextInput:Extract(true), 'text')
  9691.                             end,
  9692.                             Keys = {
  9693.                                 keys.leftCtrl,
  9694.                                 keys.x
  9695.                             },
  9696.                             Enabled = function()
  9697.                                 return Current.Document ~= nil and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil
  9698.                             end
  9699.                         },
  9700.                         {
  9701.                             Title = 'Copy',
  9702.                             Click = function()
  9703.                                 Clipboard.Copy(Current.Document.TextInput:Extract(), 'text')
  9704.                             end,
  9705.                             Keys = {
  9706.                                 keys.leftCtrl,
  9707.                                 keys.c
  9708.                             },
  9709.                             Enabled = function()
  9710.                                 return Current.Document ~= nil and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil
  9711.                             end
  9712.                         },
  9713.                         {
  9714.                             Title = 'Paste',
  9715.                             Click = function()
  9716.                                 local paste = Clipboard.Paste()
  9717.                                 Current.Document.TextInput:Insert(paste)
  9718.                                 Current.Document.TextInput.CursorPos = Current.Document.TextInput.CursorPos + #paste - 1
  9719.                             end,
  9720.                             Keys = {
  9721.                                 keys.leftCtrl,
  9722.                                 keys.v
  9723.                             },
  9724.                             Enabled = function()
  9725.                                 return Current.Document ~= nil and (not Clipboard.isEmpty()) and Clipboard.Type == 'text'
  9726.                             end
  9727.                         },
  9728.                         {
  9729.                             Separator = true,  
  9730.                         },
  9731.                         {
  9732.                             Title = 'Select All',
  9733.                             Click = function()
  9734.                                 Current.Selection = {1, #Current.Document.TextInput.Value:gsub('\n','')}
  9735.                             end,
  9736.                             Keys = {
  9737.                                 keys.leftCtrl,
  9738.                                 keys.a
  9739.                             },
  9740.                             Enabled = function()
  9741.                                 return Current.Document ~= nil
  9742.                             end
  9743.                         }
  9744.                     }, self, true)
  9745.                 else
  9746.                     Current.Menu = nil
  9747.                 end
  9748.                 return true
  9749.             end, 'Edit', colours.lightGrey, false),
  9750.             Button:Initialise(13, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  9751.                 if not self.Toggle then
  9752.                     Menu:New(13, 2, {
  9753.                         {
  9754.                             Title = 'Red',
  9755.                             Click = function(item)
  9756.                                 Current.Document:SetSelectionColour(item.Colour)
  9757.                             end,
  9758.                             Colour = colours.red,
  9759.                             Enabled = function()
  9760.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9761.                             end
  9762.                         },
  9763.                         {
  9764.                             Title = 'Orange',
  9765.                             Click = function(item)
  9766.                                 Current.Document:SetSelectionColour(item.Colour)
  9767.                             end,
  9768.                             Colour = colours.orange,
  9769.                             Enabled = function()
  9770.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9771.                             end
  9772.                         },
  9773.                         {
  9774.                             Title = 'Yellow',
  9775.                             Click = function(item)
  9776.                                 Current.Document:SetSelectionColour(item.Colour)
  9777.                             end,
  9778.                             Colour = colours.yellow,
  9779.                             Enabled = function()
  9780.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9781.                             end
  9782.                         },
  9783.                         {
  9784.                             Title = 'Pink',
  9785.                             Click = function(item)
  9786.                                 Current.Document:SetSelectionColour(item.Colour)
  9787.                             end,
  9788.                             Colour = colours.pink,
  9789.                             Enabled = function()
  9790.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9791.                             end
  9792.                         },
  9793.                         {
  9794.                             Title = 'Magenta',
  9795.                             Click = function(item)
  9796.                                 Current.Document:SetSelectionColour(item.Colour)
  9797.                             end,
  9798.                             Colour = colours.magenta,
  9799.                             Enabled = function()
  9800.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9801.                             end
  9802.                         },
  9803.                         {
  9804.                             Title = 'Purple',
  9805.                             Click = function(item)
  9806.                                 Current.Document:SetSelectionColour(item.Colour)
  9807.                             end,
  9808.                             Colour = colours.purple,
  9809.                             Enabled = function()
  9810.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9811.                             end
  9812.                         },
  9813.                         {
  9814.                             Title = 'Light Blue',
  9815.                             Click = function(item)
  9816.                                 Current.Document:SetSelectionColour(item.Colour)
  9817.                             end,
  9818.                             Colour = colours.lightBlue,
  9819.                             Enabled = function()
  9820.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9821.                             end
  9822.                         },
  9823.                         {
  9824.                             Title = 'Cyan',
  9825.                             Click = function(item)
  9826.                                 Current.Document:SetSelectionColour(item.Colour)
  9827.                             end,
  9828.                             Colour = colours.cyan,
  9829.                             Enabled = function()
  9830.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9831.                             end
  9832.                         },
  9833.                         {
  9834.                             Title = 'Blue',
  9835.                             Click = function(item)
  9836.                                 Current.Document:SetSelectionColour(item.Colour)
  9837.                             end,
  9838.                             Colour = colours.blue,
  9839.                             Enabled = function()
  9840.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9841.                             end
  9842.                         },
  9843.                         {
  9844.                             Title = 'Green',
  9845.                             Click = function(item)
  9846.                                 Current.Document:SetSelectionColour(item.Colour)
  9847.                             end,
  9848.                             Colour = colours.green,
  9849.                             Enabled = function()
  9850.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9851.                             end
  9852.                         },
  9853.                         {
  9854.                             Title = 'Light Grey',
  9855.                             Click = function(item)
  9856.                                 Current.Document:SetSelectionColour(item.Colour)
  9857.                             end,
  9858.                             Colour = colours.lightGrey,
  9859.                             Enabled = function()
  9860.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9861.                             end
  9862.                         },
  9863.                         {
  9864.                             Title = 'Grey',
  9865.                             Click = function(item)
  9866.                                 Current.Document:SetSelectionColour(item.Colour)
  9867.                             end,
  9868.                             Colour = colours.grey,
  9869.                             Enabled = function()
  9870.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9871.                             end
  9872.                         },
  9873.                         {
  9874.                             Title = 'Black',
  9875.                             Click = function(item)
  9876.                                 Current.Document:SetSelectionColour(item.Colour)
  9877.                             end,
  9878.                             Colour = colours.black,
  9879.                             Enabled = function()
  9880.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9881.                             end
  9882.                         },
  9883.                         {
  9884.                             Title = 'Brown',
  9885.                             Click = function(item)
  9886.                                 Current.Document:SetSelectionColour(item.Colour)
  9887.                             end,
  9888.                             Colour = colours.brown,
  9889.                             Enabled = function()
  9890.                                 return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil)
  9891.                             end
  9892.                         }
  9893.                     }, self, true)
  9894.                 else
  9895.                     Current.Menu = nil
  9896.                 end
  9897.                 return true
  9898.             end, 'Colour', colours.lightGrey, false)
  9899.         })
  9900.     end
  9901.  
  9902.     function SplashScreen()
  9903.         local w = colours.white
  9904.         local b = colours.black
  9905.         local u = colours.blue
  9906.         local lb = colours.lightBlue
  9907.         local splashIcon = {{w,w,w,b,w,w,w,b,w,w,w,},{w,w,w,b,w,w,w,b,w,w,w,},{w,w,w,b,u,u,u,b,w,w,w,},{w,b,b,u,u,u,u,u,b,b,w,},{b,u,u,lb,lb,u,u,u,u,u,b,},{b,u,lb,lb,u,u,u,u,u,u,b,},{b,u,lb,lb,u,u,u,u,u,u,b,},{b,u,u,u,u,u,u,u,u,u,b,},{w,b,b,b,b,b,b,b,b,b,w,},
  9908.         ["text"]={{" "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," ","I","n","k"," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," ",},{" "," ","b","y"," ","o","e","e","d"," "," "},{" "," "," "," "," "," "," "," "," "," "," ",},},
  9909.         ["textcol"]={{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{lb,lb,lb,lb,lb,lb,lb,lb,lb,lb,lb,},{w,w,w,w,w,w,w,w,w,w,w,},},}
  9910.         Drawing.Clear(colours.white)
  9911.         Drawing.DrawImage((Drawing.Screen.Width - 11)/2, (Drawing.Screen.Height - 9)/2, splashIcon, 11, 9)
  9912.         Drawing.DrawBuffer()
  9913.         Drawing.Clear(colours.black)
  9914.         parallel.waitForAny(function()sleep(1)end, function()os.pullEvent('mouse_click')end)
  9915.     end
  9916.  
  9917.     function Initialise(arg)
  9918.         if OneOS then
  9919.             fs = OneOS.FS
  9920.         end
  9921.  
  9922.         if not OneOS then
  9923.             SplashScreen()
  9924.         end
  9925.         EventRegister('mouse_click', TryClick)
  9926.         EventRegister('mouse_drag', function(event, side, x, y)TryClick(event, side, x, y, true)end)
  9927.         EventRegister('mouse_scroll', Scroll)
  9928.         EventRegister('key', HandleKey)
  9929.         EventRegister('char', HandleKey)
  9930.         EventRegister('timer', Timer)
  9931.         EventRegister('terminate', function(event) if Close() then error( "Terminated", 0 ) end end)
  9932.        
  9933.         LoadMenuBar()
  9934.  
  9935.         --Current.Document = Document:Initialise('abcdefghijklmnopqrtuvwxy')--'Hello everybody!')
  9936.         if tArgs[1] then
  9937.             if fs.exists(tArgs[1]) then
  9938.                 OpenDocument(tArgs[1])
  9939.             else
  9940.                 --new
  9941.             end
  9942.         else
  9943.             Current.Document = Document:Initialise('')--'Hello everybody!')
  9944.         end
  9945.  
  9946.         --[[
  9947.         if arg and fs.exists(arg) then
  9948.                 OpenDocument(arg)
  9949.             else
  9950.                 DisplayNewDocumentWindow()
  9951.             end
  9952.         ]]--
  9953.         Draw()
  9954.  
  9955.         EventHandler()
  9956.     end
  9957.  
  9958.     local isControlPushed = false
  9959.     controlPushedTimer = nil
  9960.     closeWindowTimer = nil
  9961.     function Timer(event, timer)
  9962.         if timer == closeWindowTimer then
  9963.             if Current.Window then
  9964.                 Current.Window:Close()
  9965.             end
  9966.             Draw()
  9967.         elseif timer == controlPushedTimer then
  9968.             isControlPushed = false
  9969.         end
  9970.     end
  9971.  
  9972.     local ignoreNextChar = false
  9973.     function HandleKey(...)
  9974.         local args = {...}
  9975.         local event = args[1]
  9976.         local keychar = args[2]
  9977.                                                                                                 --Mac left command character
  9978.         if event == 'key' and keychar == keys.leftCtrl or keychar == keys.rightCtrl or keychar == 219 then
  9979.             isControlPushed = true
  9980.             controlPushedTimer = os.startTimer(0.5)
  9981.         elseif isControlPushed then
  9982.             if event == 'key' then
  9983.                 if CheckKeyboardShortcut(keychar) then
  9984.                     isControlPushed = false
  9985.                     ignoreNextChar = true
  9986.                 end
  9987.             end
  9988.         elseif ignoreNextChar then
  9989.             ignoreNextChar = false
  9990.         elseif Current.TextInput then
  9991.             if event == 'char' then
  9992.                 Current.TextInput:Char(keychar)
  9993.             elseif event == 'key' then
  9994.                 Current.TextInput:Key(keychar)
  9995.             end
  9996.         end
  9997.     end
  9998.  
  9999.     function CheckKeyboardShortcut(key)
  10000.         local shortcuts = {}
  10001.         shortcuts[keys.n] = function() Current.Document = Document:Initialise('') end
  10002.         shortcuts[keys.o] = function() DisplayOpenDocumentWindow() end
  10003.         shortcuts[keys.s] = function() if Current.Document ~= nil then SaveDocument() end end
  10004.         shortcuts[keys.left] = function() if Current.TextInput then Current.TextInput:Key(keys.home) end end
  10005.         shortcuts[keys.right] = function() if Current.TextInput then Current.TextInput:Key(keys["end"]) end end
  10006.     --  shortcuts[keys.q] = function() DisplayOpenDocumentWindow() end
  10007.         if Current.Document ~= nil then
  10008.             shortcuts[keys.s] = function() SaveDocument() end
  10009.             shortcuts[keys.p] = function() PrintDocument() end
  10010.             if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  10011.                 shortcuts[keys.x] = function() Clipboard.Cut(Current.Document.TextInput:Extract(true), 'text') end
  10012.                 shortcuts[keys.c] = function() Clipboard.Copy(Current.Document.TextInput:Extract(), 'text') end
  10013.             end
  10014.             if (not Clipboard.isEmpty()) and Clipboard.Type == 'text' then
  10015.                 shortcuts[keys.v] = function() local paste = Clipboard.Paste()
  10016.                                         Current.Document.TextInput:Insert(paste)
  10017.                                         Current.Document.TextInput.CursorPos = Current.Document.TextInput.CursorPos + #paste - 1
  10018.                                     end
  10019.             end
  10020.             shortcuts[keys.a] = function() Current.Selection = {1, #Current.Document.TextInput.Value:gsub('\n','')} end
  10021.         end
  10022.                                
  10023.         if shortcuts[key] then
  10024.             shortcuts[key]()
  10025.             Draw()
  10026.             return true
  10027.         else
  10028.             return false
  10029.         end
  10030.     end
  10031.  
  10032.     --[[
  10033.         Check if the given object falls under the click coordinates
  10034.     ]]--
  10035.     function CheckClick(object, x, y)
  10036.         if object.X <= x and object.Y <= y and object.X + object.Width > x and object.Y + object.Height > y then
  10037.             return true
  10038.         end
  10039.     end
  10040.  
  10041.     --[[
  10042.         Attempt to clicka given object
  10043.     ]]--
  10044.     function DoClick(object, side, x, y, drag)
  10045.         local obj = GetAbsolutePosition(object)
  10046.         obj.Width = object.Width
  10047.         obj.Height = object.Height
  10048.         if object and CheckClick(obj, x, y) then
  10049.             return object:Click(side, x - object.X + 1, y - object.Y + 1, drag)
  10050.         end
  10051.     end
  10052.  
  10053.     --[[
  10054.         Try to click at the given coordinates
  10055.     ]]--
  10056.     function TryClick(event, side, x, y, drag)
  10057.         if Current.Menu then
  10058.             if DoClick(Current.Menu, side, x, y, drag) then
  10059.                 Draw()
  10060.                 return
  10061.             else
  10062.                 if Current.Menu.Owner and Current.Menu.Owner.Toggle then
  10063.                     Current.Menu.Owner.Toggle = false
  10064.                 end
  10065.                 Current.Menu = nil
  10066.                 Draw()
  10067.                 return
  10068.             end
  10069.         elseif Current.Window then
  10070.             if DoClick(Current.Window, side, x, y, drag) then
  10071.                 Draw()
  10072.                 return
  10073.             else
  10074.                 Current.Window:Flash()
  10075.                 return
  10076.             end
  10077.         end
  10078.         local interfaceElements = {}
  10079.  
  10080.         table.insert(interfaceElements, Current.MenuBar)
  10081.         table.insert(interfaceElements, Current.ScrollBar)
  10082.         for i, page in ipairs(Current.Document.Pages) do
  10083.             table.insert(interfaceElements, page)
  10084.         end
  10085.  
  10086.         for i, object in ipairs(interfaceElements) do
  10087.             if DoClick(object, side, x, y, drag) then
  10088.                 Draw()
  10089.                 return
  10090.             end    
  10091.         end
  10092.         Draw()
  10093.     end
  10094.  
  10095.     function Scroll(event, direction, x, y)
  10096.         if Current.Window and Current.Window.OpenButton then
  10097.             Current.Document.Scroll = Current.Document.Scroll + direction
  10098.             if Current.Window.Scroll < 0 then
  10099.                 Current.Window.Scroll = 0
  10100.             elseif Current.Window.Scroll > Current.Window.MaxScroll then
  10101.                 Current.Window.Scroll = Current.Window.MaxScroll
  10102.             end
  10103.             Draw()
  10104.         elseif Current.ScrollBar then
  10105.             if Current.ScrollBar:DoScroll(direction*2) then
  10106.                 Draw()
  10107.             end
  10108.         end
  10109.     end
  10110.  
  10111.  
  10112.     --[[
  10113.         Registers functions to run on certain events
  10114.     ]]--
  10115.     function EventRegister(event, func)
  10116.         if not Events[event] then
  10117.             Events[event] = {}
  10118.         end
  10119.  
  10120.         table.insert(Events[event], func)
  10121.     end
  10122.  
  10123.     --[[
  10124.         The main loop event handler, runs registered event functinos
  10125.     ]]--
  10126.     function EventHandler()
  10127.         while true do
  10128.             local event, arg1, arg2, arg3, arg4 = os.pullEventRaw()
  10129.             if Events[event] then
  10130.                 for i, e in ipairs(Events[event]) do
  10131.                     e(event, arg1, arg2, arg3, arg4)
  10132.                 end
  10133.             end
  10134.         end
  10135.     end
  10136.  
  10137.  
  10138.     local function Extension(path, addDot)
  10139.         if not path then
  10140.             return nil
  10141.         elseif not string.find(fs.getName(path), '%.') then
  10142.             if not addDot then
  10143.                 return fs.getName(path)
  10144.             else
  10145.                 return ''
  10146.             end
  10147.         else
  10148.             local _path = path
  10149.             if path:sub(#path) == '/' then
  10150.                 _path = path:sub(1,#path-1)
  10151.             end
  10152.             local extension = _path:gmatch('%.[0-9a-z]+$')()
  10153.             if extension then
  10154.                 extension = extension:sub(2)
  10155.             else
  10156.                 --extension = nil
  10157.                 return ''
  10158.             end
  10159.             if addDot then
  10160.                 extension = '.'..extension
  10161.             end
  10162.             return extension:lower()
  10163.         end
  10164.     end
  10165.  
  10166.     local RemoveExtension = function(path)
  10167.         if path:sub(1,1) == '.' then
  10168.             return path
  10169.         end
  10170.         local extension = Extension(path)
  10171.         if extension == path then
  10172.             return fs.getName(path)
  10173.         end
  10174.         return string.gsub(path, extension, ''):sub(1, -2)
  10175.     end
  10176.  
  10177.     local acknowledgedColour = false
  10178.     function PrintDocument()
  10179.         if OneOS then
  10180.             OneOS.LoadAPI('/System/API/Helpers.lua')
  10181.             OneOS.LoadAPI('/System/API/Peripheral.lua')
  10182.             OneOS.LoadAPI('/System/API/Printer.lua')
  10183.         end
  10184.  
  10185.         local doPrint = function()
  10186.             local window = PrintDocumentWindow:Initialise():Show()
  10187.         end
  10188.  
  10189.         if Peripheral.GetPeripheral('printer') == nil then
  10190.             ButtonDialougeWindow:Initialise('No Printer Found', 'Please place a printer next to your computer. Ensure you also insert dye (left slot) and paper (top slots)', 'Ok', nil, function(window, ok)
  10191.                 window:Close()
  10192.             end):Show()
  10193.         elseif not acknowledgedColour and FindColours(Current.Document.TextInput.Value) ~= 0 then
  10194.             ButtonDialougeWindow:Initialise('Important', 'Due to the way printers work, you can\'t print in more than one colour. The dye you use will be the colour of the text.', 'Ok', nil, function(window, ok)
  10195.                 acknowledgedColour = true
  10196.                 window:Close()
  10197.                 doPrint()
  10198.             end):Show()
  10199.         else
  10200.             doPrint()
  10201.         end
  10202.     end
  10203.  
  10204.     function SaveDocument()
  10205.         local function save()
  10206.             local h = fs.open(Current.Document.Path, 'w')
  10207.             if h then
  10208.                 if Current.Document.Format == TextFormatPlainText then
  10209.                     h.write(Current.Document.TextInput.Value)
  10210.                 else
  10211.                     local lines = {}
  10212.                     for p, page in ipairs(Current.Document.Pages) do
  10213.                         for i, line in ipairs(page.Lines) do
  10214.                             table.insert(lines, line)
  10215.                         end
  10216.                     end
  10217.                     h.write(textutils.serialize(lines))
  10218.                 end
  10219.                 Current.Modified = false
  10220.             else
  10221.                 ButtonDialougeWindow:Initialise('Error', 'An error occured while saving the file, try again.', 'Ok', nil, function(window, ok)
  10222.                     window:Close()
  10223.                 end):Show()
  10224.             end
  10225.             h.close()
  10226.         end
  10227.  
  10228.         if not Current.Document.Path then
  10229.             SaveDocumentWindow:Initialise(function(self, success, path)
  10230.                 self:Close()
  10231.                 if success then
  10232.                     local extension = ''
  10233.                     if Current.Document.Format == TextFormatPlainText then
  10234.                         extension = '.txt'
  10235.                     elseif Current.Document.Format == TextFormatInkText then
  10236.                         extension = '.ink'
  10237.                     end
  10238.                    
  10239.                     if path:sub(-4) ~= extension then
  10240.                         path = path .. extension
  10241.                     end
  10242.  
  10243.                     Current.Document.Path = path
  10244.                     Current.Document.Title = fs.getName(path)
  10245.                     save()
  10246.                 end
  10247.                 if Current.Document then
  10248.                     Current.TextInput = Current.Document.TextInput
  10249.                 end
  10250.             end):Show()
  10251.         else
  10252.             save()
  10253.         end
  10254.     end
  10255.  
  10256.     function DisplayOpenDocumentWindow()
  10257.         OpenDocumentWindow:Initialise(function(self, success, path)
  10258.             self:Close()
  10259.             if success then
  10260.                 OpenDocument(path)
  10261.             end
  10262.         end):Show()
  10263.     end
  10264.  
  10265.     function OpenDocument(path)
  10266.         Current.Selection = nil
  10267.         local h = fs.open(path, 'r')
  10268.         if h then
  10269.             Current.Document = Document:Initialise(h.readAll(), RemoveExtension(fs.getName(path)), path)
  10270.         else
  10271.             ButtonDialougeWindow:Initialise('Error', 'An error occured while opening the file, try again.', 'Ok', nil, function(window, ok)
  10272.                 window:Close()
  10273.                 if Current.Document then
  10274.                     Current.TextInput = Current.Document.TextInput
  10275.                 end
  10276.             end):Show()
  10277.         end
  10278.         h.close()
  10279.     end
  10280.  
  10281.     local TidyPath = function(path)
  10282.         path = '/'..path
  10283.         local fs = fs
  10284.         if OneOS then
  10285.             fs = OneOS.FS
  10286.         end
  10287.         if fs.isDir(path) then
  10288.             path = path .. '/'
  10289.         end
  10290.  
  10291.         path, n = path:gsub("//", "/")
  10292.         while n > 0 do
  10293.             path, n = path:gsub("//", "/")
  10294.         end
  10295.         return path
  10296.     end
  10297.  
  10298.     OpenDocumentWindow = {
  10299.         X = 1,
  10300.         Y = 1,
  10301.         Width = 0,
  10302.         Height = 0,
  10303.         CursorPos = 1,
  10304.         Visible = true,
  10305.         Return = nil,
  10306.         OpenButton = nil,
  10307.         PathTextBox = nil,
  10308.         CurrentDirectory = '/',
  10309.         Scroll = 0,
  10310.         MaxScroll = 0,
  10311.         GoUpButton = nil,
  10312.         SelectedFile = '',
  10313.         Files = {},
  10314.         Typed = false,
  10315.  
  10316.         AbsolutePosition = function(self)
  10317.             return {X = self.X, Y = self.Y}
  10318.         end,
  10319.  
  10320.         Draw = function(self)
  10321.             if not self.Visible then
  10322.                 return
  10323.             end
  10324.             Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  10325.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 3, colours.lightGrey)
  10326.             Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-6, colours.white)
  10327.             Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  10328.             Drawing.DrawBlankArea(self.X, self.Y + self.Height - 5, self.Width, 5, colours.lightGrey)
  10329.             self:DrawFiles()
  10330.  
  10331.             if (fs.exists(self.PathTextBox.TextInput.Value)) or (self.SelectedFile and #self.SelectedFile > 0 and fs.exists(self.CurrentDirectory .. self.SelectedFile)) then
  10332.                 self.OpenButton.TextColour = colours.black
  10333.             else
  10334.                 self.OpenButton.TextColour = colours.lightGrey
  10335.             end
  10336.  
  10337.             self.PathTextBox:Draw()
  10338.             self.OpenButton:Draw()
  10339.             self.CancelButton:Draw()
  10340.             self.GoUpButton:Draw()
  10341.         end,
  10342.  
  10343.         DrawFiles = function(self)
  10344.             for i, file in ipairs(self.Files) do
  10345.                 if i > self.Scroll and i - self.Scroll <= 11 then
  10346.                     if file == self.SelectedFile then
  10347.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.white, colours.lightBlue)
  10348.                     elseif string.find(file, '%.txt') or string.find(file, '%.text') or string.find(file, '%.ink') or fs.isDir(self.CurrentDirectory .. file) then
  10349.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.black, colours.white)
  10350.                     else
  10351.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.grey, colours.white)
  10352.                     end
  10353.                 end
  10354.             end
  10355.             self.MaxScroll = #self.Files - 11
  10356.             if self.MaxScroll < 0 then
  10357.                 self.MaxScroll = 0
  10358.             end
  10359.         end,
  10360.  
  10361.         Initialise = function(self, returnFunc)
  10362.             local new = {}    -- the new instance
  10363.             setmetatable( new, {__index = self} )
  10364.             new.Width = 32
  10365.             new.Height = 17
  10366.             new.Return = returnFunc
  10367.             new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  10368.             new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  10369.             new.Title = 'Open Document'
  10370.             new.Visible = true
  10371.             new.CurrentDirectory = '/'
  10372.             new.SelectedFile = nil
  10373.             if OneOS and fs.exists('/Desktop/Documents/') then
  10374.                 new.CurrentDirectory = '/Desktop/Documents/'
  10375.             end
  10376.             new.OpenButton = Button:Initialise(new.Width - 6, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  10377.                 if fs.exists(new.PathTextBox.TextInput.Value) and self.TextColour == colours.black and not fs.isDir(new.PathTextBox.TextInput.Value) then
  10378.                     returnFunc(new, true, TidyPath(new.PathTextBox.TextInput.Value))
  10379.                 elseif new.SelectedFile and self.TextColour == colours.black and fs.isDir(new.CurrentDirectory .. new.SelectedFile) then
  10380.                     new:GoToDirectory(new.CurrentDirectory .. new.SelectedFile)
  10381.                 elseif new.SelectedFile and self.TextColour == colours.black then
  10382.                     returnFunc(new, true, TidyPath(new.CurrentDirectory .. '/' .. new.SelectedFile))
  10383.                 end
  10384.             end, 'Open', colours.black)
  10385.             new.CancelButton = Button:Initialise(new.Width - 15, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  10386.                 returnFunc(new, false)
  10387.             end, 'Cancel', colours.black)
  10388.             new.GoUpButton = Button:Initialise(2, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  10389.                 local folderName = fs.getName(new.CurrentDirectory)
  10390.                 local parentDirectory = new.CurrentDirectory:sub(1, #new.CurrentDirectory-#folderName-1)
  10391.                 new:GoToDirectory(parentDirectory)
  10392.             end, 'Go Up', colours.black)
  10393.             new.PathTextBox = TextBox:Initialise(2, new.Height - 3, new.Width - 2, 1, new, new.CurrentDirectory, colours.white, colours.black)
  10394.             new:GoToDirectory(new.CurrentDirectory)
  10395.             return new
  10396.         end,
  10397.  
  10398.         Show = function(self)
  10399.             Current.Window = self
  10400.             return self
  10401.         end,
  10402.  
  10403.         Close = function(self)
  10404.             Current.Input = nil
  10405.             Current.Window = nil
  10406.             self = nil
  10407.         end,
  10408.  
  10409.         GoToDirectory = function(self, path)
  10410.             path = TidyPath(path)
  10411.             self.CurrentDirectory = path
  10412.             self.Scroll = 0
  10413.             self.SelectedFile = nil
  10414.             self.Typed = false
  10415.             self.PathTextBox.TextInput.Value = path
  10416.             local fs = fs
  10417.             if OneOS then
  10418.                 fs = OneOS.FS
  10419.             end
  10420.             self.Files = fs.list(self.CurrentDirectory)
  10421.             Draw()
  10422.         end,
  10423.  
  10424.         Flash = function(self)
  10425.             self.Visible = false
  10426.             Draw()
  10427.             sleep(0.15)
  10428.             self.Visible = true
  10429.             Draw()
  10430.             sleep(0.15)
  10431.             self.Visible = false
  10432.             Draw()
  10433.             sleep(0.15)
  10434.             self.Visible = true
  10435.             Draw()
  10436.         end,
  10437.  
  10438.         Click = function(self, side, x, y)
  10439.             local items = {self.OpenButton, self.CancelButton, self.PathTextBox, self.GoUpButton}
  10440.             local found = false
  10441.             for i, v in ipairs(items) do
  10442.                 if CheckClick(v, x, y) then
  10443.                     v:Click(side, x, y)
  10444.                     found = true
  10445.                 end
  10446.             end
  10447.  
  10448.             if not found then
  10449.                 if y <= 12 then
  10450.                     local fs = fs
  10451.                     if OneOS then
  10452.                         fs = OneOS.FS
  10453.                     end
  10454.                     self.SelectedFile = fs.list(self.CurrentDirectory)[y-1]
  10455.                     self.PathTextBox.TextInput.Value = TidyPath(self.CurrentDirectory .. '/' .. self.SelectedFile)
  10456.                     Draw()
  10457.                 end
  10458.             end
  10459.             return true
  10460.         end
  10461.     }
  10462.  
  10463.     PrintDocumentWindow = {
  10464.         X = 1,
  10465.         Y = 1,
  10466.         Width = 0,
  10467.         Height = 0,
  10468.         CursorPos = 1,
  10469.         Visible = true,
  10470.         Return = nil,
  10471.         PrintButton = nil,
  10472.         CopiesTextBox = nil,
  10473.         Scroll = 0,
  10474.         MaxScroll = 0,
  10475.         PrinterSelectButton = nil,
  10476.         Title = '',
  10477.         Status = 0, --0 = neutral, 1 = good, -1 = error
  10478.         StatusText = '',
  10479.         SelectedPrinter = nil,
  10480.  
  10481.         AbsolutePosition = function(self)
  10482.             return {X = self.X, Y = self.Y}
  10483.         end,
  10484.  
  10485.         Draw = function(self)
  10486.             if not self.Visible then
  10487.                 return
  10488.             end
  10489.             Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  10490.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  10491.             Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  10492.             Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  10493.            
  10494.             self.PrinterSelectButton:Draw()
  10495.             Drawing.DrawCharactersCenter(self.X,  self.Y + self.PrinterSelectButton.Y - 2, self.Width, 1, 'Printer', colours.black, colours.white)
  10496.             Drawing.DrawCharacters(self.X + self.Width - 3, self.Y + self.PrinterSelectButton.Y - 1, '\\/', colours.black, colours.lightGrey)
  10497.             Drawing.DrawCharacters(self.X + 1, self.Y + self.CopiesTextBox.Y - 1, 'Copies', colours.black, colours.white)
  10498.             local statusColour = colours.grey
  10499.             if self.Status == -1 then
  10500.                 statusColour = colours.red
  10501.             elseif self.Status == 1 then
  10502.                 statusColour = colours.green
  10503.             end
  10504.             Drawing.DrawCharacters(self.X + 1, self.Y + self.CopiesTextBox.Y + 1, self.StatusText, statusColour, colours.white)
  10505.  
  10506.             self.CopiesTextBox:Draw()
  10507.             self.PrintButton:Draw()
  10508.             self.CancelButton:Draw()
  10509.         end,
  10510.  
  10511.         Initialise = function(self)
  10512.             local new = {}    -- the new instance
  10513.             setmetatable( new, {__index = self} )
  10514.             new.Width = 32
  10515.             new.Height = 11
  10516.             new.Return = returnFunc
  10517.             new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  10518.             new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  10519.             new.Title = 'Print Document'
  10520.             new.Visible = true
  10521.             new.PrintButton = Button:Initialise(new.Width - 7, new.Height - 1, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  10522.                 local doPrint = true
  10523.                 if new.SelectedPrinter == nil then
  10524.                     local p = Peripheral.GetPeripheral('printer')
  10525.                     if p then
  10526.                         new.SelectedPrinter = p.Side
  10527.                         new.PrinterSelectButton.Text = p.Fullname
  10528.                     else
  10529.                         new.StatusText = 'No Connected Printer'
  10530.                         new.Status = -1
  10531.                         doPrint = false
  10532.                     end
  10533.                 end
  10534.                 if doPrint then
  10535.                     local printer = Printer:Initialise(new.SelectedPrinter)
  10536.                     local err = printer:PrintLines(Current.Document.Lines, Current.Document.Title, tonumber(new.CopiesTextBox.TextInput.Value))
  10537.                     if not err then
  10538.                         new.StatusText = 'Document Printed!'
  10539.                         new.Status = 1
  10540.                         closeWindowTimer = os.startTimer(1)
  10541.                     else
  10542.                         new.StatusText = err
  10543.                         new.Status = -1
  10544.                     end
  10545.                 end
  10546.             end, 'Print', colours.black)
  10547.             new.CancelButton = Button:Initialise(new.Width - 15, new.Height - 1, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  10548.                 new:Close()
  10549.                 Draw()
  10550.             end, 'Close', colours.black)
  10551.             new.PrinterSelectButton = Button:Initialise(2, 4, new.Width - 2, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  10552.                 local printers = {
  10553.                         {
  10554.                             Title = "Automatic",
  10555.                             Click = function()
  10556.                                 new.SelectedPrinter = nil
  10557.                                 new.PrinterSelectButton.Text = 'Automatic'
  10558.                             end
  10559.                         },
  10560.                         {
  10561.                             Separator = true
  10562.                         }
  10563.                     }
  10564.                 for i, p in ipairs(Peripheral.GetPeripherals('printer')) do
  10565.                     table.insert(printers, {
  10566.                         Title = p.Fullname,
  10567.                         Click = function(self)
  10568.                             new.SelectedPrinter = p.Side
  10569.                             new.PrinterSelectButton.Text = p.Fullname
  10570.                         end
  10571.                     })
  10572.                 end
  10573.                 Current.Menu = Menu:New(x, y+4, printers, self, true)
  10574.             end, 'Automatic', colours.black)
  10575.             new.CopiesTextBox = TextBox:Initialise(9, 6, 4, 1, new, 1, colours.lightGrey, colours.black, nil, true)
  10576.             Current.TextInput = new.CopiesTextBox.TextInput
  10577.             new.StatusText = 'Waiting...'
  10578.             new.Status = 0
  10579.             return new
  10580.         end,
  10581.  
  10582.         Show = function(self)
  10583.             Current.Window = self
  10584.             return self
  10585.         end,
  10586.  
  10587.         Close = function(self)
  10588.             Current.Input = nil
  10589.             Current.Window = nil
  10590.             self = nil
  10591.         end,
  10592.  
  10593.         Flash = function(self)
  10594.             self.Visible = false
  10595.             Draw()
  10596.             sleep(0.15)
  10597.             self.Visible = true
  10598.             Draw()
  10599.             sleep(0.15)
  10600.             self.Visible = false
  10601.             Draw()
  10602.             sleep(0.15)
  10603.             self.Visible = true
  10604.             Draw()
  10605.         end,
  10606.  
  10607.         Click = function(self, side, x, y)
  10608.             local items = {self.PrintButton, self.CancelButton, self.CopiesTextBox, self.PrinterSelectButton}
  10609.             for i, v in ipairs(items) do
  10610.                 if CheckClick(v, x, y) then
  10611.                     v:Click(side, x, y)
  10612.                 end
  10613.             end
  10614.             return true
  10615.         end
  10616.     }
  10617.  
  10618.     SaveDocumentWindow = {
  10619.         X = 1,
  10620.         Y = 1,
  10621.         Width = 0,
  10622.         Height = 0,
  10623.         CursorPos = 1,
  10624.         Visible = true,
  10625.         Return = nil,
  10626.         SaveButton = nil,
  10627.         PathTextBox = nil,
  10628.         CurrentDirectory = '/',
  10629.         Scroll = 0,
  10630.         MaxScroll = 0,
  10631.         ScrollBar = nil,
  10632.         GoUpButton = nil,
  10633.         Files = {},
  10634.         Typed = false,
  10635.  
  10636.         AbsolutePosition = function(self)
  10637.             return {X = self.X, Y = self.Y}
  10638.         end,
  10639.  
  10640.         Draw = function(self)
  10641.             if not self.Visible then
  10642.                 return
  10643.             end
  10644.             Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  10645.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 3, colours.lightGrey)
  10646.             Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-6, colours.white)
  10647.             Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  10648.             Drawing.DrawBlankArea(self.X, self.Y + self.Height - 5, self.Width, 5, colours.lightGrey)
  10649.             Drawing.DrawCharacters(self.X + 1, self.Y + self.Height - 5, self.CurrentDirectory, colours.grey, colours.lightGrey)
  10650.             self:DrawFiles()
  10651.  
  10652.             if (self.PathTextBox.TextInput.Value) then
  10653.                 self.SaveButton.TextColour = colours.black
  10654.             else
  10655.                 self.SaveButton.TextColour = colours.lightGrey
  10656.             end
  10657.  
  10658.             self.PathTextBox:Draw()
  10659.             self.SaveButton:Draw()
  10660.             self.CancelButton:Draw()
  10661.             self.GoUpButton:Draw()
  10662.         end,
  10663.  
  10664.         DrawFiles = function(self)
  10665.             for i, file in ipairs(self.Files) do
  10666.                 if i > self.Scroll and i - self.Scroll <= 10 then
  10667.                     if file == self.SelectedFile then
  10668.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.white, colours.lightBlue)
  10669.                     elseif fs.isDir(self.CurrentDirectory .. file) then
  10670.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.black, colours.white)
  10671.                     else
  10672.                         Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.lightGrey, colours.white)
  10673.                     end
  10674.                 end
  10675.             end
  10676.             self.MaxScroll = #self.Files - 11
  10677.             if self.MaxScroll < 0 then
  10678.                 self.MaxScroll = 0
  10679.             end
  10680.         end,
  10681.  
  10682.         Initialise = function(self, returnFunc)
  10683.             local new = {}    -- the new instance
  10684.             setmetatable( new, {__index = self} )
  10685.             new.Width = 32
  10686.             new.Height = 16
  10687.             new.Return = returnFunc
  10688.             new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  10689.             new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  10690.             new.Title = 'Save Document'
  10691.             new.Visible = true
  10692.             new.CurrentDirectory = '/'
  10693.             if OneOS and fs.exists('/Desktop/Documents/') then
  10694.                 new.CurrentDirectory = '/Desktop/Documents/'
  10695.             end
  10696.             new.SaveButton = Button:Initialise(new.Width - 6, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  10697.                 if self.TextColour == colours.black and not fs.isDir(new.CurrentDirectory ..'/' .. new.PathTextBox.TextInput.Value) then
  10698.                     returnFunc(new, true, TidyPath(new.CurrentDirectory ..'/' .. new.PathTextBox.TextInput.Value))
  10699.                 elseif new.SelectedFile and self.TextColour == colours.black and fs.isDir(new.CurrentDirectory .. new.SelectedFile) then
  10700.                     new:GoToDirectory(new.CurrentDirectory .. new.SelectedFile)
  10701.                 end
  10702.             end, 'Save', colours.black)
  10703.             new.CancelButton = Button:Initialise(new.Width - 15, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  10704.                 returnFunc(new, false)
  10705.             end, 'Cancel', colours.black)
  10706.             new.GoUpButton = Button:Initialise(2, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  10707.                 local folderName = fs.getName(new.CurrentDirectory)
  10708.                 local parentDirectory = new.CurrentDirectory:sub(1, #new.CurrentDirectory-#folderName-1)
  10709.                 new:GoToDirectory(parentDirectory)
  10710.             end, 'Go Up', colours.black)
  10711.             new.PathTextBox = TextBox:Initialise(2, new.Height - 3, new.Width - 2, 1, new, '', colours.white, colours.black, function(key)
  10712.                 if key == keys.enter then
  10713.                     new.SaveButton:Click()
  10714.                 end
  10715.             end)
  10716.             new.PathTextBox.Placeholder = 'Document Name'
  10717.             Current.TextInput = new.PathTextBox.TextInput
  10718.             new:GoToDirectory(new.CurrentDirectory)
  10719.             return new
  10720.         end,
  10721.  
  10722.         Show = function(self)
  10723.             Current.Window = self
  10724.             return self
  10725.         end,
  10726.  
  10727.         Close = function(self)
  10728.             Current.Input = nil
  10729.             Current.Window = nil
  10730.             self = nil
  10731.         end,
  10732.  
  10733.         GoToDirectory = function(self, path)
  10734.             path = TidyPath(path)
  10735.             self.CurrentDirectory = path
  10736.             self.Scroll = 0
  10737.             self.Typed = false
  10738.             local fs = fs
  10739.             if OneOS then
  10740.                 fs = OneOS.FS
  10741.             end
  10742.             self.Files = fs.list(self.CurrentDirectory)
  10743.             Draw()
  10744.         end,
  10745.  
  10746.         Flash = function(self)
  10747.             self.Visible = false
  10748.             Draw()
  10749.             sleep(0.15)
  10750.             self.Visible = true
  10751.             Draw()
  10752.             sleep(0.15)
  10753.             self.Visible = false
  10754.             Draw()
  10755.             sleep(0.15)
  10756.             self.Visible = true
  10757.             Draw()
  10758.         end,
  10759.  
  10760.         Click = function(self, side, x, y)
  10761.             local items = {self.SaveButton, self.CancelButton, self.PathTextBox, self.GoUpButton}
  10762.             local found = false
  10763.             for i, v in ipairs(items) do
  10764.                 if CheckClick(v, x, y) then
  10765.                     v:Click(side, x, y)
  10766.                     found = true
  10767.                 end
  10768.             end
  10769.  
  10770.             if not found then
  10771.                 if y <= 11 then
  10772.                     local files = fs.list(self.CurrentDirectory)
  10773.                     if files[y-1] then
  10774.                         self:GoToDirectory(self.CurrentDirectory..files[y-1])
  10775.                         Draw()
  10776.                     end
  10777.                 end
  10778.             end
  10779.             return true
  10780.         end
  10781.     }
  10782.  
  10783.     local WrapText = function(text, maxWidth)
  10784.         local lines = {''}
  10785.         for word, space in text:gmatch('(%S+)(%s*)') do
  10786.                 local temp = lines[#lines] .. word .. space:gsub('\n','')
  10787.                 if #temp > maxWidth then
  10788.                         table.insert(lines, '')
  10789.                 end
  10790.                 if space:find('\n') then
  10791.                         lines[#lines] = lines[#lines] .. word
  10792.                        
  10793.                         space = space:gsub('\n', function()
  10794.                                 table.insert(lines, '')
  10795.                                 return ''
  10796.                         end)
  10797.                 else
  10798.                         lines[#lines] = lines[#lines] .. word .. space
  10799.                 end
  10800.         end
  10801.         return lines
  10802.     end
  10803.  
  10804.     ButtonDialougeWindow = {
  10805.         X = 1,
  10806.         Y = 1,
  10807.         Width = 0,
  10808.         Height = 0,
  10809.         CursorPos = 1,
  10810.         Visible = true,
  10811.         CancelButton = nil,
  10812.         OkButton = nil,
  10813.         Lines = {},
  10814.  
  10815.         AbsolutePosition = function(self)
  10816.             return {X = self.X, Y = self.Y}
  10817.         end,
  10818.  
  10819.         Draw = function(self)
  10820.             if not self.Visible then
  10821.                 return
  10822.             end
  10823.             Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  10824.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  10825.             Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  10826.             Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  10827.  
  10828.             for i, text in ipairs(self.Lines) do
  10829.                 Drawing.DrawCharacters(self.X + 1, self.Y + 1 + i, text, colours.black, colours.white)
  10830.             end
  10831.  
  10832.             self.OkButton:Draw()
  10833.             if self.CancelButton then
  10834.                 self.CancelButton:Draw()
  10835.             end
  10836.         end,
  10837.  
  10838.         Initialise = function(self, title, message, okText, cancelText, returnFunc)
  10839.             local new = {}    -- the new instance
  10840.             setmetatable( new, {__index = self} )
  10841.             new.Width = 28
  10842.             new.Lines = WrapText(message, new.Width - 2)
  10843.             new.Height = 5 + #new.Lines
  10844.             new.Return = returnFunc
  10845.             new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  10846.             new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  10847.             new.Title = title
  10848.             new.Visible = true
  10849.             new.Visible = true
  10850.             new.OkButton = Button:Initialise(new.Width - #okText - 2, new.Height - 1, nil, 1, nil, new, function()
  10851.                 returnFunc(new, true)
  10852.             end, okText)
  10853.             if cancelText then
  10854.                 new.CancelButton = Button:Initialise(new.Width - #okText - 2 - 1 - #cancelText - 2, new.Height - 1, nil, 1, nil, new, function()
  10855.                     returnFunc(new, false)
  10856.                 end, cancelText)
  10857.             end
  10858.  
  10859.             return new
  10860.         end,
  10861.  
  10862.         Show = function(self)
  10863.             Current.Window = self
  10864.             return self
  10865.         end,
  10866.  
  10867.         Close = function(self)
  10868.             Current.Window = nil
  10869.             self = nil
  10870.         end,
  10871.  
  10872.         Flash = function(self)
  10873.             self.Visible = false
  10874.             Draw()
  10875.             sleep(0.15)
  10876.             self.Visible = true
  10877.             Draw()
  10878.             sleep(0.15)
  10879.             self.Visible = false
  10880.             Draw()
  10881.             sleep(0.15)
  10882.             self.Visible = true
  10883.             Draw()
  10884.         end,
  10885.  
  10886.         Click = function(self, side, x, y)
  10887.             local items = {self.OkButton, self.CancelButton}
  10888.             local found = false
  10889.             for i, v in ipairs(items) do
  10890.                 if CheckClick(v, x, y) then
  10891.                     v:Click(side, x, y)
  10892.                     found = true
  10893.                 end
  10894.             end
  10895.             return true
  10896.         end
  10897.     }
  10898.  
  10899.     TextDialougeWindow = {
  10900.         X = 1,
  10901.         Y = 1,
  10902.         Width = 0,
  10903.         Height = 0,
  10904.         CursorPos = 1,
  10905.         Visible = true,
  10906.         CancelButton = nil,
  10907.         OkButton = nil,
  10908.         Lines = {},
  10909.         TextInput = nil,
  10910.  
  10911.         AbsolutePosition = function(self)
  10912.             return {X = self.X, Y = self.Y}
  10913.         end,
  10914.  
  10915.         Draw = function(self)
  10916.             if not self.Visible then
  10917.                 return
  10918.             end
  10919.             Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  10920.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  10921.             Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  10922.             Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  10923.  
  10924.             for i, text in ipairs(self.Lines) do
  10925.                 Drawing.DrawCharacters(self.X + 1, self.Y + 1 + i, text, colours.black, colours.white)
  10926.             end
  10927.  
  10928.  
  10929.             Drawing.DrawBlankArea(self.X + 1, self.Y + self.Height - 4, self.Width - 2, 1, colours.lightGrey)
  10930.             Drawing.DrawCharacters(self.X + 2, self.Y + self.Height - 4, self.TextInput.Value, colours.black, colours.lightGrey)
  10931.             Current.CursorPos = {self.X + 2 + self.TextInput.CursorPos, self.Y + self.Height - 4}
  10932.             Current.CursorColour = colours.black
  10933.  
  10934.             self.OkButton:Draw()
  10935.             if self.CancelButton then
  10936.                 self.CancelButton:Draw()
  10937.             end
  10938.         end,
  10939.  
  10940.         Initialise = function(self, title, message, okText, cancelText, returnFunc, numerical)
  10941.             local new = {}    -- the new instance
  10942.             setmetatable( new, {__index = self} )
  10943.             new.Width = 28
  10944.             new.Lines = WrapText(message, new.Width - 2)
  10945.             new.Height = 7 + #new.Lines
  10946.             new.Return = returnFunc
  10947.             new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  10948.             new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  10949.             new.Title = title
  10950.             new.Visible = true
  10951.             new.Visible = true
  10952.             new.OkButton = Button:Initialise(new.Width - #okText - 2, new.Height - 1, nil, 1, nil, new, function()
  10953.                 if #new.TextInput.Value > 0 then
  10954.                     returnFunc(new, true, new.TextInput.Value)
  10955.                 end
  10956.             end, okText)
  10957.             if cancelText then
  10958.                 new.CancelButton = Button:Initialise(new.Width - #okText - 2 - 1 - #cancelText - 2, new.Height - 1, nil, 1, nil, new, function()
  10959.                     returnFunc(new, false)
  10960.                 end, cancelText)
  10961.             end
  10962.             new.TextInput = TextInput:Initialise('', function(enter)
  10963.                 if enter then
  10964.                     new.OkButton:Click()
  10965.                 end
  10966.                 Draw()
  10967.             end, numerical)
  10968.  
  10969.             Current.Input = new.TextInput
  10970.  
  10971.             return new
  10972.         end,
  10973.  
  10974.         Show = function(self)
  10975.             Current.Window = self
  10976.             return self
  10977.         end,
  10978.  
  10979.         Close = function(self)
  10980.             Current.Window = nil
  10981.             Current.Input = nil
  10982.             self = nil
  10983.         end,
  10984.  
  10985.         Flash = function(self)
  10986.             self.Visible = false
  10987.             Draw()
  10988.             sleep(0.15)
  10989.             self.Visible = true
  10990.             Draw()
  10991.             sleep(0.15)
  10992.             self.Visible = false
  10993.             Draw()
  10994.             sleep(0.15)
  10995.             self.Visible = true
  10996.             Draw()
  10997.         end,
  10998.  
  10999.         Click = function(self, side, x, y)
  11000.             local items = {self.OkButton, self.CancelButton}
  11001.             local found = false
  11002.             for i, v in ipairs(items) do
  11003.                 if CheckClick(v, x, y) then
  11004.                     v:Click(side, x, y)
  11005.                     found = true
  11006.                 end
  11007.             end
  11008.             return true
  11009.         end
  11010.     }
  11011.  
  11012.     function PrintCentered(text, y)
  11013.         local w, h = term.getSize()
  11014.         x = math.ceil(math.ceil((w / 2) - (#text / 2)), 0)+1
  11015.         term.setCursorPos(x, y)
  11016.         print(text)
  11017.     end
  11018.  
  11019.     function DoVanillaClose()
  11020.         term.setBackgroundColour(colours.black)
  11021.         term.setTextColour(colours.white)
  11022.         term.clear()
  11023.         term.setCursorPos(1, 1)
  11024.         PrintCentered("Thanks for using Ink!", (Drawing.Screen.Height/2)-1)
  11025.         term.setTextColour(colours.lightGrey)
  11026.         PrintCentered("Word Proccessor for ComputerCraft", (Drawing.Screen.Height/2))
  11027.         term.setTextColour(colours.white)
  11028.         PrintCentered("(c) oeed 2014", (Drawing.Screen.Height/2)+3)
  11029.         term.setCursorPos(1, Drawing.Screen.Height)
  11030.         desktop()
  11031.     end
  11032.  
  11033.     function Close()
  11034.         if isQuitting or not Current.Document or not Current.Modified then
  11035.             if not OneOS then
  11036.                 DoVanillaClose()
  11037.             end
  11038.             return true
  11039.         else
  11040.             local _w = ButtonDialougeWindow:Initialise('Quit Ink?', 'You have unsaved changes, do you want to quit anyway?', 'Quit', 'Cancel', function(window, success)
  11041.                 if success then
  11042.                     if OneOS then
  11043.                         OneOS.Close(true)
  11044.                     else
  11045.                         DoVanillaClose()
  11046.                     end
  11047.                 end
  11048.                 window:Close()
  11049.                 Draw()
  11050.             end):Show()
  11051.             --it's hacky but it works
  11052.             os.queueEvent('mouse_click', 1, _w.X, _w.Y)
  11053.             return false
  11054.         end
  11055.     end
  11056.  
  11057.     if OneOS then
  11058.         OneOS.CanClose = function()
  11059.             return Close()
  11060.         end
  11061.     end
  11062.  
  11063.     Initialise()
  11064. end
  11065.  
  11066.  
  11067.  
  11068.  
  11069.  
  11070.  
  11071.  
  11072.  
  11073.  
  11074.  
  11075.  
  11076.  
  11077.  
  11078.  
  11079.  
  11080.  
  11081.  
  11082.  
  11083.  
  11084.  
  11085.  
  11086.  
  11087.  
  11088.  
  11089.  
  11090.  
  11091.  
  11092.  
  11093.  
  11094.  
  11095.  
  11096.  
  11097.  
  11098.  
  11099.  
  11100.  
  11101.  
  11102.  
  11103.  
  11104.  
  11105.  
  11106.  
  11107.  
  11108.  
  11109.  
  11110.  
  11111.  
  11112.  
  11113.  
  11114.  
  11115. --[[###################################################################################################################################################
  11116. ###########################################                   END OF PROGRAM CODE                       ###############################################
  11117. #####################################################################################################################################################]]
  11118.  
  11119. --[[
  11120.         APPLICATION PROGRAMMING INTERFACE INTERNALLY BASED
  11121. ]]
  11122.  
  11123. draw = {}
  11124. draw.__index = draw
  11125.  
  11126. config = {}
  11127. config.__index = config
  11128.  
  11129. db = {}
  11130. db.__index = db
  11131.  
  11132. crypt = {}
  11133. crypt.__index = crypt
  11134.  
  11135. col = {}
  11136. col.__index = col
  11137.  
  11138. misc = {}
  11139. misc.__index = misc
  11140.  
  11141. data = {}
  11142. data.__index = data
  11143.  
  11144. help = {}
  11145. help.__index = help
  11146.  
  11147. user = {}
  11148. user.__index = user
  11149.  
  11150. email = {}
  11151. email.__index = email
  11152.  
  11153. chat = {}
  11154. chat.__index = chat
  11155.  
  11156. image = {}
  11157. image.__index = image
  11158.  
  11159. ccsys = {}
  11160. ccsys.__index = ccsys
  11161.  
  11162. function user.login(user, pass)
  11163.     local pass = crypt.sha256(pass)
  11164.     local req = http.post("http://api.dannysmc.com/user.php", "cmd="..textutils.urlEncode(tostring("login")).."&username="..textutils.urlEncode(tostring(user)).."&password="..textutils.urlEncode(tostring(pass)))
  11165.     local req = textutils.unserialize(req.readAll())
  11166.     if req.status then
  11167.         return true
  11168.     else
  11169.         return false
  11170.     end
  11171. end
  11172.  
  11173. function user.register(user, pass, email)
  11174.     local pass = crypt.sha256(pass)
  11175.     local req = http.post("http://api.dannysmc.com/user.php", "cmd="..textutils.urlEncode(tostring("register")).."&username="..textutils.urlEncode(tostring(user)).."&password="..textutils.urlEncode(tostring(pass)).."&email="..textutils.urlEncode(tostring(email)))
  11176.     local req = textutils.unserialize(req.readAll())
  11177.     if req.status then
  11178.         return true
  11179.     else
  11180.         return false
  11181.     end
  11182. end
  11183.  
  11184. function ccsys.submitbug(email, prog, desc, code)
  11185.     local req = http.post(tUrls["FusionBugreport"], "username="..textutils.urlEncode(tostring(email)).."&".."emailto="..textutils.urlEncode(tostring("danny.smc95@gmail.com")).."&".."emailsubject="..textutils.urlEncode(tostring(prog)).."&".."emailmessage="..textutils.urlEncode(tostring("DESC: "..desc..". Code: "..code)))
  11186. end
  11187.  
  11188. function config.save(table, file)
  11189.   fConfig = fs.open(file, "w") or error("Cannot open file "..file, 2)
  11190.   fConfig.write(textutils.serialize(table))
  11191.   fConfig.close()
  11192. end
  11193.  
  11194. function config.load(file)
  11195.   fConfig = fs.open(file, "r")
  11196.   ret = textutils.unserialize(fConfig.readAll())
  11197.   return ret
  11198. end
  11199.  
  11200. function image.draw(intx, inty, imgpath)
  11201.     local tempImage = paintutils.loadImage(imgpath..".fusi")
  11202.     paintutils.drawImage(tempImage, intx, inty)
  11203. end
  11204.  
  11205. function draw.cscreen()
  11206.     term.clear()
  11207.     term.setCursorPos(1,1)
  11208.     return
  11209. end
  11210.  
  11211. function draw.textc(Text, Line, NextLine, Color, BkgColor)
  11212.     local x, y = term.getSize()
  11213.     x = x/2 - #Text/2
  11214.     term.setCursorPos(x, Line)
  11215.     if Color then
  11216.         col.set(Color, BkgColor)
  11217.     end
  11218.     term.write(Text)
  11219.     if NextLine then
  11220.         term.setCursorPos(1, NextLine)
  11221.     end
  11222.     if Color then
  11223.         col.reset(Color, BkgColor)
  11224.     end
  11225.     return true  
  11226. end
  11227.  
  11228. function draw.texta(Text, xx, yy, NextLine, Color, BkgColor)
  11229.     term.setCursorPos(xx,yy)
  11230.     if Color then
  11231.         col.set(Color, BkgColor)
  11232.     end
  11233.     term.write(Text)
  11234.     if NextLine then  
  11235.         term.setCursorPos(1, NextLine)
  11236.     end
  11237.     if Color then
  11238.         col.reset(Color, BkgColor)
  11239.     end
  11240.     return true  
  11241. end
  11242.  
  11243. function draw.cline(Line, NextLine)
  11244.     local x, y = term.getSize()
  11245.     for i = 1, x do
  11246.         term.setCursorPos(i, Line)
  11247.         term.write(" ")
  11248.     end  
  11249.     if not NextLine then  
  11250.         x, y = term.getCursorPos()
  11251.         term.setCursorPos(1, y+1)
  11252.     end
  11253.     return true  
  11254. end
  11255.  
  11256. function draw.popup(text)
  11257.     draw.box(1, 51, 8, 1, " ", "lime", "red")
  11258.     draw.textc(text, 8, false, "lime", "red")
  11259.     sleep(1.5)
  11260. end
  11261.  
  11262. function draw.box(StartX, lengthX, StartY, lengthY, Text, Color, BkgColor)
  11263.     local x, y = term.getSize()
  11264.     if Color then
  11265.         col.set(Color, BkgColor)
  11266.     end
  11267.     if not Text then
  11268.         Text = "*"
  11269.     end
  11270.     lengthX = lengthX - 1
  11271.     lengthY = lengthY - 1
  11272.     EndX = StartX + lengthX  
  11273.     EndY = StartY + lengthY
  11274.     term.setCursorPos(StartX, StartY)
  11275.     term.write(string.rep(Text, lengthX))
  11276.     term.setCursorPos(StartX, EndY)
  11277.     term.write(string.rep(Text, lengthX))
  11278.     for i = StartY, EndY do
  11279.         term.setCursorPos(StartX, i)
  11280.         term.write(Text)
  11281.         term.setCursorPos(EndX, i)    
  11282.         term.write(Text)
  11283.     end
  11284.     col.reset(Color, BkgColor)
  11285.     return true  
  11286. end
  11287.  
  11288. function db.delete(Filename)
  11289.     if fs.exists(Filename) then
  11290.         fs.delete(Filename)
  11291.         return true
  11292.     end
  11293.     return false
  11294. end
  11295.  
  11296. function db.load(Filename)
  11297.     if not fs.exists(Filename) then
  11298.         local F = fs.open(Filename, "w")
  11299.         F.write("{}")
  11300.         F.close()
  11301.     end
  11302.     local F = fs.open(Filename, "r")
  11303.     local Data = F.readAll()
  11304.     F.close()
  11305.     Data = textutils.unserialize(Data)
  11306.     return Data
  11307. end
  11308.  
  11309. function db.save(Filename, ATable)
  11310.     local Data = textutils.serialize(ATable)
  11311.     local F = fs.open(Filename, "w")
  11312.     F.write(Data)
  11313.     F.close()
  11314.     return true
  11315. end
  11316.  
  11317. function db.search(searchstring, ATable)
  11318.     for i, V in pairs(ATable) do
  11319.         if tostring(ATable[i]) == tostring(searchstring) then
  11320.             return i
  11321.         end
  11322.     end
  11323.     return 0
  11324. end
  11325.  
  11326. function db.removeString(Filename, AString)
  11327.     local TempT = db.load(Filename)
  11328.     if type(TempT) ~= "table" then
  11329.         return false
  11330.     end
  11331.     local Pos = db.search(AString, TempT)
  11332.     if Pos > 0 then
  11333.         table.remove(TempT, Pos)
  11334.         db.save(Filename, TempT)
  11335.         return true
  11336.     else
  11337.         return false
  11338.     end
  11339. end
  11340.  
  11341. function db.insertString(Filename, AString)
  11342.     local TempT = db.load(Filename)
  11343.     if type(TempT) ~= "table" then
  11344.         TempT = {}
  11345.     end
  11346.     table.insert(TempT, AString)
  11347.     db.save(Filename, TempT)
  11348.     return true
  11349. end
  11350.  
  11351. local MOD = 2^32
  11352. local MODM = MOD-1
  11353. local function memoize(f)
  11354.     local mt = {}
  11355.     local t = setmetatable({}, mt)
  11356.     function mt:__index(k)
  11357.         local v = f(k)
  11358.         t[k] = v
  11359.         return v
  11360.     end
  11361.     return t
  11362. end
  11363. local function make_bitop_uncached(t, m)
  11364.     local function bitop(a, b)
  11365.         local res,p = 0,1
  11366.         while a ~= 0 and b ~= 0 do
  11367.             local am, bm = a % m, b % m
  11368.             res = res + t[am][bm] * p
  11369.             a = (a - am) / m
  11370.             b = (b - bm) / m
  11371.             p = p*m
  11372.         end
  11373.         res = res + (a + b) * p
  11374.         return res
  11375.     end
  11376.     return bitop
  11377. end
  11378. local function make_bitop(t)
  11379.     local op1 = make_bitop_uncached(t,2^1)
  11380.     local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end)
  11381.     return make_bitop_uncached(op2, 2 ^ (t.n or 1))
  11382. end
  11383. local bxor1 = make_bitop({[0] = {[0] = 0,[1] = 1}, [1] = {[0] = 1, [1] = 0}, n = 4})
  11384. local function bxor(a, b, c, ...)
  11385.     local z = nil
  11386.     if b then
  11387.         a = a % MOD
  11388.         b = b % MOD
  11389.         z = bxor1(a, b)
  11390.         if c then z = bxor(z, c, ...) end
  11391.         return z
  11392.     elseif a then return a % MOD
  11393.     else return 0 end
  11394. end
  11395. local function band(a, b, c, ...)
  11396.     local z
  11397.     if b then
  11398.         a = a % MOD
  11399.         b = b % MOD
  11400.         z = ((a + b) - bxor1(a,b)) / 2
  11401.         if c then z = bit32_band(z, c, ...) end
  11402.         return z
  11403.     elseif a then return a % MOD
  11404.     else return MODM end
  11405. end
  11406. local function bnot(x) return (-1 - x) % MOD end
  11407. local function rshift1(a, disp)
  11408.     if disp < 0 then return lshift(a,-disp) end
  11409.     return math.floor(a % 2 ^ 32 / 2 ^ disp)
  11410. end
  11411. local function rshift(x, disp)
  11412.     if disp > 31 or disp < -31 then return 0 end
  11413.     return rshift1(x % MOD, disp)
  11414. end
  11415. local function lshift(a, disp)
  11416.     if disp < 0 then return rshift(a,-disp) end
  11417.     return (a * 2 ^ disp) % 2 ^ 32
  11418. end
  11419. local function rrotate(x, disp)
  11420.     x = x % MOD
  11421.     disp = disp % 32
  11422.     local low = band(x, 2 ^ disp - 1)
  11423.     return rshift(x, disp) + lshift(low, 32 - disp)
  11424. end
  11425. local k = {
  11426.     0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
  11427.     0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  11428.     0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
  11429.     0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
  11430.     0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
  11431.     0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
  11432.     0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
  11433.     0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
  11434.     0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
  11435.     0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
  11436.     0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
  11437.     0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
  11438.     0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
  11439.     0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
  11440.     0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
  11441.     0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
  11442. }
  11443. local function str2hexa(s)
  11444.     return (string.gsub(s, ".", function(c) return string.format("%02x", string.byte(c)) end))
  11445. end
  11446. local function num2s(l, n)
  11447.     local s = ""
  11448.     for i = 1, n do
  11449.         local rem = l % 256
  11450.         s = string.char(rem) .. s
  11451.         l = (l - rem) / 256
  11452.     end
  11453.     return s
  11454. end
  11455. local function s232num(s, i)
  11456.     local n = 0
  11457.     for i = i, i + 3 do n = n*256 + string.byte(s, i) end
  11458.     return n
  11459. end
  11460. local function preproc(msg, len)
  11461.     local extra = 64 - ((len + 9) % 64)
  11462.     len = num2s(8 * len, 8)
  11463.     msg = msg .. "\128" .. string.rep("\0", extra) .. len
  11464.     assert(#msg % 64 == 0)
  11465.     return msg
  11466. end
  11467. local function initH256(H)
  11468.     H[1] = 0x6a09e667
  11469.     H[2] = 0xbb67ae85
  11470.     H[3] = 0x3c6ef372
  11471.     H[4] = 0xa54ff53a
  11472.     H[5] = 0x510e527f
  11473.     H[6] = 0x9b05688c
  11474.     H[7] = 0x1f83d9ab
  11475.     H[8] = 0x5be0cd19
  11476.     return H
  11477. end
  11478. local function digestblock(msg, i, H)
  11479.     local w = {}
  11480.     for j = 1, 16 do w[j] = s232num(msg, i + (j - 1)*4) end
  11481.     for j = 17, 64 do
  11482.         local v = w[j - 15]
  11483.         local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))
  11484.         v = w[j - 2]
  11485.         w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))
  11486.     end
  11487.     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]
  11488.     for i = 1, 64 do
  11489.         local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))
  11490.         local maj = bxor(band(a, b), band(a, c), band(b, c))
  11491.         local t2 = s0 + maj
  11492.         local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))
  11493.         local ch = bxor (band(e, f), band(bnot(e), g))
  11494.         local t1 = h + s1 + ch + k[i] + w[i]
  11495.         h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2
  11496.     end
  11497.     H[1] = band(H[1] + a)
  11498.     H[2] = band(H[2] + b)
  11499.     H[3] = band(H[3] + c)
  11500.     H[4] = band(H[4] + d)
  11501.     H[5] = band(H[5] + e)
  11502.     H[6] = band(H[6] + f)
  11503.     H[7] = band(H[7] + g)
  11504.     H[8] = band(H[8] + h)
  11505. end
  11506. function crypt.sha256(msg)
  11507.     msg = preproc(msg, #msg)
  11508.     local H = initH256({})
  11509.     for i = 1, #msg, 64 do digestblock(msg, i, H) end
  11510.     return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) ..
  11511.         num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4))
  11512. end
  11513.  
  11514. local function zfill(N)
  11515.     N=string.format("%X",N)
  11516.     Zs=""
  11517.     if #N==1 then
  11518.         Zs="0"
  11519.     end
  11520.     return Zs..N
  11521. end
  11522.  
  11523. local function serializeImpl(t)
  11524.     local sType = type(t)
  11525.     if sType == "table" then
  11526.         local lstcnt=0
  11527.         for k,v in pairs(t) do
  11528.             lstcnt = lstcnt + 1
  11529.         end
  11530.         local result = "{"
  11531.         local aset=1
  11532.         for k,v in pairs(t) do
  11533.             if k==aset then
  11534.                 result = result..serializeImpl(v)..","
  11535.                 aset=aset+1
  11536.             else
  11537.                 result = result..("["..serializeImpl(k).."]="..serializeImpl(v)..",")
  11538.             end
  11539.         end
  11540.         result = result.."}"
  11541.         return result
  11542.     elseif sType == "string" then
  11543.         return string.format("%q",t)
  11544.     elseif sType == "number" or sType == "boolean" or sType == "nil" then
  11545.         return tostring(t)
  11546.     elseif sType == "function" then
  11547.         local status,data=pcall(string.dump,t)
  11548.         if status then
  11549.             return 'func('..string.format("%q",data)..')'
  11550.         else
  11551.             error()
  11552.         end
  11553.     else
  11554.         error()
  11555.     end
  11556. end
  11557.  
  11558. local function split(T,func)
  11559.     if func then
  11560.         T=func(T)
  11561.     end
  11562.     local Out={}
  11563.     if type(T)=="table" then
  11564.         for k,v in pairs(T) do
  11565.             Out[split(k)]=split(v)
  11566.         end
  11567.     else
  11568.         Out=T
  11569.     end
  11570.     return Out
  11571. end
  11572.  
  11573. local function serialize( t )
  11574.     t=split(t)
  11575.     return serializeImpl( t, tTracking )
  11576. end
  11577.  
  11578. local function unserialize( s )
  11579.     local func, e = loadstring( "return "..s, "serialize" )
  11580.     local funcs={}
  11581.     if not func then
  11582.         return e
  11583.     end
  11584.     setfenv( func, {
  11585.         func=function(S)
  11586.             local new={}
  11587.             funcs[new]=S
  11588.             return new
  11589.         end,
  11590.     })
  11591.     return split(func(),function(val)
  11592.         if funcs[val] then
  11593.             return loadstring(funcs[val])
  11594.         else
  11595.             return val
  11596.         end
  11597.     end)
  11598. end
  11599.  
  11600. local function sure(N,n)
  11601.     if (l2-n)<1 then N="0" end
  11602.     return N
  11603. end
  11604.  
  11605. local function splitnum(S)
  11606.     Out=""
  11607.     for l1=1,#S,2 do
  11608.         l2=(#S-l1)+1
  11609.         CNum=tonumber("0x"..sure(string.sub(S,l2-1,l2-1),1) .. sure(string.sub(S,l2,l2),0))
  11610.         Out=string.char(CNum)..Out
  11611.     end
  11612.     return Out
  11613. end
  11614.  
  11615. local function wrap(N)
  11616.     return N-(math.floor(N/256)*256)
  11617. end
  11618.  
  11619. function checksum(S,num) -- args strInput and intPassNumber
  11620.     local sum=0
  11621.     for char in string.gmatch(S,".") do
  11622.         for l1=1,(num or 1) do
  11623.             math.randomseed(string.byte(char)+sum)
  11624.             sum=sum+math.random(0,9999)
  11625.         end
  11626.     end
  11627.     math.randomseed(sum)
  11628.     return sum
  11629. end
  11630.  
  11631. local function genkey(len,psw)
  11632.     checksum(psw)
  11633.     local key={}
  11634.     local tKeys={}
  11635.     for l1=1,len do
  11636.         local num=math.random(1,len)
  11637.         while tKeys[num] do
  11638.             num=math.random(1,len)
  11639.         end
  11640.         tKeys[num]=true
  11641.         key[l1]={num,math.random(0,255)}
  11642.     end
  11643.     return key
  11644. end
  11645.  
  11646. function crypt.encrypt(data,psw) -- args strInput and strPassword
  11647.     data=serialize(data)
  11648.     local chs=checksum(data)
  11649.     local key=genkey(#data,psw)
  11650.     local out={}
  11651.     local cnt=1
  11652.     for char in string.gmatch(data,".") do
  11653.         table.insert(out,key[cnt][1],zfill(wrap(string.byte(char)+key[cnt][2])),chars)
  11654.         cnt=cnt+1
  11655.     end
  11656.     return string.sub(serialize({chs,table.concat(out)}),2,-3)
  11657. end
  11658.  
  11659. function crypt.decrypt(data,psw) -- args strInput and strPassword
  11660.     local oData=data
  11661.     data=unserialize("{"..data.."}")
  11662.     if type(data)~="table" then
  11663.         return oData
  11664.     end
  11665.     local chs=data[1]
  11666.     data=data[2]
  11667.     local key=genkey((#data)/2,psw)
  11668.     local sKey={}
  11669.     for k,v in pairs(key) do
  11670.         sKey[v[1]]={k,v[2]}
  11671.     end
  11672.     local str=splitnum(data)
  11673.     local cnt=1
  11674.     local out={}
  11675.     for char in string.gmatch(str,".") do
  11676.         table.insert(out,sKey[cnt][1],string.char(wrap(string.byte(char)-sKey[cnt][2])))
  11677.         cnt=cnt+1
  11678.     end
  11679.     out=table.concat(out)
  11680.     if checksum(out or "")==chs then
  11681.         return unserialize(out)
  11682.     end
  11683.     return oData,out,chs
  11684. end
  11685.  
  11686. function col.set(textColour, backgroundColour)
  11687.     if textColour and backgroundColour then
  11688.         if term.isColour() then
  11689.             term.setTextColour(colours[textColour])
  11690.             term.setBackgroundColour(colours[backgroundColour])
  11691.             return true
  11692.         else
  11693.             return false
  11694.         end
  11695.     else
  11696.         return false
  11697.     end
  11698. end
  11699.  
  11700. function col.screen(txtCol, bkgCol)
  11701.     intX = 1
  11702.     intY = 1
  11703.     col.set(txtCol, bkgCol)
  11704.     repeat
  11705.         intX = 1
  11706.         repeat
  11707.             term.setCursorPos(intX, intY)
  11708.             write(" ")
  11709.             intX = intX + 1
  11710.         until intX == 52
  11711.         intY = intY + 1
  11712.     until intY == 20
  11713. end
  11714.  
  11715. function col.reset()
  11716.     if term.isColour then
  11717.         term.setTextColour(colours.white)
  11718.         term.setBackgroundColour(colours.black)
  11719.         return true
  11720.     else
  11721.         return false
  11722.     end
  11723. end
  11724.  
  11725. function misc.find(Perihp)
  11726.   for _,s in ipairs(rs.getSides()) do
  11727.     if peripheral.isPresent(s) and peripheral.getType(s) == Perihp then
  11728.       return s  
  11729.     end
  11730.   end
  11731.   return false
  11732. end
  11733.  
  11734. function misc.serialgen(digits)
  11735.   local serial
  11736.   for i = 1, digits do
  11737.     if i == 1 then
  11738.       serial = math.random(9)
  11739.     else
  11740.       serial = serial.. math.random(9)
  11741.     end
  11742.   end
  11743.   serial = tonumber(serial)
  11744.   return serial
  11745. end
  11746.  
  11747. function misc.time()
  11748.     local nTime = textutils.formatTime(os.time(), true)
  11749.     if string.len(nTime) == 4 then
  11750.         nTime = "0"..nTime
  11751.     end
  11752.     os.startTimer(1)
  11753.     return nTime
  11754. end
  11755.  
  11756. function data.wordwrap(str, limit)
  11757.   limit = limit or 72
  11758.   local here = 1
  11759.   local buf = ""
  11760.   local t = {}
  11761.   str:gsub("(%s*)()(%S+)()",
  11762.   function(sp, st, word, fi)
  11763.         if fi-here > limit then
  11764.            --# Break the line
  11765.            here = st
  11766.            table.insert(t, buf)
  11767.            buf = word
  11768.         else
  11769.            buf = buf..sp..word  --# Append
  11770.         end
  11771.   end)
  11772.   --# Tack on any leftovers
  11773.   if(buf ~= "") then
  11774.         table.insert(t, buf)
  11775.   end
  11776.   return t
  11777. end
  11778.  
  11779.  
  11780.  
  11781.  
  11782.  
  11783. -- Start Program Inititator:
  11784. if fs.exists("/core/") then
  11785.     login()
  11786. else
  11787.     init("install")
  11788. end
Add Comment
Please, Sign In to add comment