Advertisement
Oeed

Sketch - Photoshop Inspired Image Editor for ComputerCraft

Mar 19th, 2014
6,283
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 108.13 KB | None | 0 0
  1. if OneOS then
  2.     --running under OneOS
  3.     OneOS.ToolBarColour = colours.grey
  4.     OneOS.ToolBarTextColour = colours.white
  5. end
  6.  
  7. colours.transparent = -1
  8. colors.transparent = -1
  9.  
  10. --APIS--
  11.  
  12. --This is my drawing API, is is pretty much identical to what drives OneOS, PearOS, etc.
  13. local _w, _h = term.getSize()
  14.  
  15. local round = function(num, idp)
  16.     local mult = 10^(idp or 0)
  17.     return math.floor(num * mult + 0.5) / mult
  18. end
  19.  
  20. Clipboard = {
  21.     Content = nil,
  22.     Type = nil,
  23.     IsCut = false,
  24.  
  25.     Empty = function()
  26.         Clipboard.Content = nil
  27.         Clipboard.Type = nil
  28.         Clipboard.IsCut = false
  29.     end,
  30.  
  31.     isEmpty = function()
  32.         return Clipboard.Content == nil
  33.     end,
  34.  
  35.     Copy = function(content, _type)
  36.         Clipboard.Content = content
  37.         Clipboard.Type = _type or 'generic'
  38.         Clipboard.IsCut = false
  39.     end,
  40.  
  41.     Cut = function(content, _type)
  42.         Clipboard.Content = content
  43.         Clipboard.Type = _type or 'generic'
  44.         Clipboard.IsCut = true
  45.     end,
  46.  
  47.     Paste = function()
  48.         local c, t = Clipboard.Content, Clipboard.Type
  49.         if Clipboard.IsCut then
  50.             Clipboard.Empty()
  51.         end
  52.         return c, t
  53.     end
  54. }
  55.  
  56. if OneOS and OneOS.Clipboard then
  57.     Clipboard = OneOS.Clipboard
  58. end
  59.  
  60. Drawing = {
  61.    
  62.     Screen = {
  63.         Width = _w,
  64.         Height = _h
  65.     },
  66.  
  67.     DrawCharacters = function (x, y, characters, textColour,bgColour)
  68.         Drawing.WriteStringToBuffer(x, y, characters, textColour, bgColour)
  69.     end,
  70.    
  71.     DrawBlankArea = function (x, y, w, h, colour)
  72.         Drawing.DrawArea (x, y, w, h, " ", 1, colour)
  73.     end,
  74.  
  75.     DrawArea = function (x, y, w, h, character, textColour, bgColour)
  76.         --width must be greater than 1, other wise we get a stack overflow
  77.         if w < 0 then
  78.             w = w * -1
  79.         elseif w == 0 then
  80.             w = 1
  81.         end
  82.  
  83.         for ix = 1, w do
  84.             local currX = x + ix - 1
  85.             for iy = 1, h do
  86.                 local currY = y + iy - 1
  87.                 Drawing.WriteToBuffer(currX, currY, character, textColour, bgColour)
  88.             end
  89.         end
  90.     end,
  91.  
  92.     DrawImage = function(_x,_y,tImage, w, h)
  93.         if tImage then
  94.             for y = 1, h do
  95.                 if not tImage[y] then
  96.                     break
  97.                 end
  98.                 for x = 1, w do
  99.                     if not tImage[y][x] then
  100.                         break
  101.                     end
  102.                     local bgColour = tImage[y][x]
  103.                     local textColour = tImage.textcol[y][x] or colours.white
  104.                     local char = tImage.text[y][x]
  105.                     Drawing.WriteToBuffer(x+_x-1, y+_y-1, char, textColour, bgColour)
  106.                 end
  107.             end
  108.         elseif w and h then
  109.             Drawing.DrawBlankArea(x, y, w, h, colours.green)
  110.         end
  111.     end,
  112.     --using .nft
  113.     LoadImage = function(path)
  114.         local image = {
  115.             text = {},
  116.             textcol = {}
  117.         }
  118.         local _fs = fs
  119.         if OneOS then
  120.             _fs = OneOS.FS
  121.         end
  122.         if _fs.exists(path) then
  123.             local _open = io.open
  124.             if OneOS then
  125.                 _open = OneOS.IO.open
  126.             end
  127.             local file = _open(path, "r")
  128.             local sLine = file:read()
  129.             local num = 1
  130.             while sLine do  
  131.                     table.insert(image, num, {})
  132.                     table.insert(image.text, num, {})
  133.                     table.insert(image.textcol, num, {})
  134.                                                
  135.                     --As we're no longer 1-1, we keep track of what index to write to
  136.                     local writeIndex = 1
  137.                     --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour
  138.                     local bgNext, fgNext = false, false
  139.                     --The current background and foreground colours
  140.                     local currBG, currFG = nil,nil
  141.                     for i=1,#sLine do
  142.                             local nextChar = string.sub(sLine, i, i)
  143.                             if nextChar:byte() == 30 then
  144.                                 bgNext = true
  145.                             elseif nextChar:byte() == 31 then
  146.                                 fgNext = true
  147.                             elseif bgNext then
  148.                                 currBG = Drawing.GetColour(nextChar)
  149.                                 bgNext = false
  150.                             elseif fgNext then
  151.                                 currFG = Drawing.GetColour(nextChar)
  152.                                 fgNext = false
  153.                             else
  154.                                 if nextChar ~= " " and currFG == nil then
  155.                                        currFG = colours.white
  156.                                 end
  157.                                 image[num][writeIndex] = currBG
  158.                                 image.textcol[num][writeIndex] = currFG
  159.                                 image.text[num][writeIndex] = nextChar
  160.                                 writeIndex = writeIndex + 1
  161.                             end
  162.                     end
  163.                     num = num+1
  164.                     sLine = file:read()
  165.             end
  166.             file:close()
  167.         end
  168.         return image
  169.     end,
  170.  
  171.     DrawCharactersCenter = function(x, y, w, h, characters, textColour,bgColour)
  172.         w = w or Drawing.Screen.Width
  173.         h = h or Drawing.Screen.Height
  174.         x = x or 0
  175.         y = y or 0
  176.         x = math.ceil((w - #characters) / 2) + x
  177.         y = math.floor(h / 2) + y
  178.  
  179.         Drawing.DrawCharacters(x, y, characters, textColour, bgColour)
  180.     end,
  181.  
  182.     GetColour = function(hex)
  183.         if hex == ' ' then
  184.             return colours.transparent
  185.         end
  186.         local value = tonumber(hex, 16)
  187.         if not value then return nil end
  188.         value = math.pow(2,value)
  189.         return value
  190.     end,
  191.  
  192.     Clear = function (_colour)
  193.         _colour = _colour or colours.black
  194.         Drawing.ClearBuffer()
  195.         Drawing.DrawBlankArea(1, 1, Drawing.Screen.Width, Drawing.Screen.Height, _colour)
  196.     end,
  197.  
  198.     Buffer = {},
  199.     BackBuffer = {},
  200.  
  201.     DrawBuffer = function()
  202.         for y,row in pairs(Drawing.Buffer) do
  203.             for x,pixel in pairs(row) do
  204.                 local shouldDraw = true
  205.                 local hasBackBuffer = true
  206.                 if Drawing.BackBuffer[y] == nil or Drawing.BackBuffer[y][x] == nil or #Drawing.BackBuffer[y][x] ~= 3 then
  207.                     hasBackBuffer = false
  208.                 end
  209.                 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
  210.                     shouldDraw = false
  211.                 end
  212.                 if shouldDraw then
  213.                     term.setBackgroundColour(pixel[3])
  214.                     term.setTextColour(pixel[2])
  215.                     term.setCursorPos(x, y)
  216.                     term.write(pixel[1])
  217.                 end
  218.             end
  219.         end
  220.         Drawing.BackBuffer = Drawing.Buffer
  221.         Drawing.Buffer = {}
  222.         term.setCursorPos(1,1)
  223.     end,
  224.  
  225.     ClearBuffer = function()
  226.         Drawing.Buffer = {}
  227.     end,
  228.  
  229.     WriteStringToBuffer = function (x, y, characters, textColour,bgColour)
  230.         for i = 1, #characters do
  231.             local character = characters:sub(i,i)
  232.             Drawing.WriteToBuffer(x + i - 1, y, character, textColour, bgColour)
  233.         end
  234.     end,
  235.  
  236.     WriteToBuffer = function(x, y, character, textColour,bgColour)
  237.         x = round(x)
  238.         y = round(y)
  239.         if bgColour == colours.transparent then
  240.             Drawing.Buffer[y] = Drawing.Buffer[y] or {}
  241.             Drawing.Buffer[y][x] = Drawing.Buffer[y][x] or {"", colours.white, colours.black}
  242.             Drawing.Buffer[y][x][1] = character
  243.             Drawing.Buffer[y][x][2] = textColour
  244.         else
  245.             Drawing.Buffer[y] = Drawing.Buffer[y] or {}
  246.             Drawing.Buffer[y][x] = {character, textColour, bgColour}
  247.         end
  248.     end,
  249. }
  250.  
  251. --Colour Deffitions--
  252. UIColours = {
  253.     Toolbar = colours.grey,
  254.     ToolbarText = colours.lightGrey,
  255.     ToolbarSelected = colours.lightBlue,
  256.     ControlText = colours.white,
  257.     ToolbarItemTitle = colours.black,
  258.     Background = colours.lightGrey,
  259.     MenuBackground = colours.white,
  260.     MenuText = colours.black,
  261.     MenuSeparatorText = colours.grey,
  262.     MenuDisabledText = colours.lightGrey,
  263.     Shadow = colours.grey,
  264.     TransparentBackgroundOne = colours.white,
  265.     TransparentBackgroundTwo = colours.lightGrey,
  266.     MenuBarActive = colours.white
  267. }
  268.  
  269. --Lists--
  270. Current = {
  271.     Artboard = nil,
  272.     Layer = nil,
  273.     Tool = nil,
  274.     ToolSize = 1,
  275.     Toolbar = nil,
  276.     Colour = colours.lightBlue,
  277.     Menu = nil,
  278.     MenuBar = nil,
  279.     Window = nil,
  280.     Input = nil,
  281.     CursorPos = {1,1},
  282.     CursorColour = colours.black,
  283.     InterfaceVisible = true,
  284.     Selection = {},
  285.     SelectionDrawTimer = nil,
  286.     HandDragStart = {},
  287.     Modified = false,
  288. }
  289.  
  290. local isQuitting = false
  291.  
  292. function PrintCentered(text, y)
  293.     local w, h = term.getSize()
  294.     x = math.ceil(math.ceil((w / 2) - (#text / 2)), 0)+1
  295.     term.setCursorPos(x, y)
  296.     print(text)
  297. end
  298.  
  299. function DoVanillaClose()
  300.     term.setBackgroundColour(colours.black)
  301.     term.setTextColour(colours.white)
  302.     term.clear()
  303.     term.setCursorPos(1, 1)
  304.     PrintCentered("Thanks for using Sketch!", (Drawing.Screen.Height/2)-1)
  305.     term.setTextColour(colours.lightGrey)
  306.     PrintCentered("Photoshop Inspired Image Editor for ComputerCraft", (Drawing.Screen.Height/2))
  307.     term.setTextColour(colours.white)
  308.     PrintCentered("(c) oeed 2013 - 2014", (Drawing.Screen.Height/2)+3)
  309.     term.setCursorPos(1, Drawing.Screen.Height)
  310.     error('', 0)
  311. end
  312.  
  313. function Close()
  314.     if isQuitting or not Current.Artboard or not Current.Modified then
  315.         if not OneOS then
  316.             DoVanillaClose()
  317.         end
  318.         return true
  319.     else
  320.         local _w = ButtonDialougeWindow:Initialise('Quit Sketch?', 'You have unsaved changes, do you want to quit anyway?', 'Quit', 'Cancel', function(window, success)
  321.             if success then
  322.                 if OneOS then
  323.                     OneOS.Close(true)
  324.                 else
  325.                     DoVanillaClose()
  326.                 end
  327.             end
  328.             window:Close()
  329.             Draw()
  330.         end):Show()
  331.         --it's hacky but it works
  332.         os.queueEvent('mouse_click', 1, _w.X, _w.Y)
  333.         return false
  334.     end
  335. end
  336.  
  337. if OneOS then
  338.     OneOS.CanClose = function()
  339.         return Close()
  340.     end
  341. end
  342.  
  343. Lists = {
  344.     Artboards = {},
  345.     Interface = {
  346.         Toolbars = {}
  347.     }  
  348. }
  349.  
  350. Events = {
  351.    
  352. }
  353.  
  354. --Setters--
  355.  
  356. function SetColour(colour)
  357.     Current.Colour = colour
  358.     Draw()
  359. end
  360.  
  361. function SetTool(tool)
  362.     if tool and tool.Select and tool:Select() then
  363.         Current.Input = nil
  364.         Current.Tool = tool
  365.         return true
  366.     end
  367.     return false
  368. end
  369.  
  370. function GetAbsolutePosition(object)
  371.     local obj = object
  372.     local i = 0
  373.     local x = 1
  374.     local y = 1
  375.     while true do
  376.         x = x + obj.X - 1
  377.         y = y + obj.Y - 1
  378.  
  379.         if not obj.Parent then
  380.             return {X = x, Y = y}
  381.         end
  382.  
  383.         obj = obj.Parent
  384.  
  385.         if i > 32 then
  386.             return {X = 1, Y = 1}
  387.         end
  388.  
  389.         i = i + 1
  390.     end
  391.  
  392. end
  393.  
  394. --Object Defintions--
  395.  
  396. Pixel = {
  397.     TextColour = colours.black,
  398.     BackgroundColour = colours.white,
  399.     Character = " ",
  400.     Layer = nil,
  401.  
  402.     Draw = function(self, x, y)
  403.         if self.BackgroundColour ~= colours.transparent or self.Character ~= ' ' then
  404.             Drawing.WriteToBuffer(self.Layer.Artboard.X + x - 1, self.Layer.Artboard.Y + y - 1, self.Character, self.TextColour, self.BackgroundColour)
  405.         end
  406.     end,
  407.  
  408.     Initialise = function(self, textColour, backgroundColour, character, layer)
  409.         local new = {}    -- the new instance
  410.         setmetatable( new, {__index = self} )
  411.         new.TextColour = textColour or self.TextColour
  412.         new.BackgroundColour = backgroundColour or self.BackgroundColour
  413.         new.Character = character or self.Character
  414.         new.Layer = layer
  415.         return new
  416.     end,
  417.  
  418.     Set = function(self, textColour, backgroundColour, character)
  419.         self.TextColour = textColour or self.TextColour
  420.         self.BackgroundColour = backgroundColour or self.BackgroundColour
  421.         self.Character = character or self.Character
  422.     end
  423. }
  424.  
  425. Layer = {
  426.     Name = "",
  427.     Pixels = {
  428.  
  429.     },
  430.     Artboard = nil,
  431.     BackgroundColour = colours.white,
  432.     Visible = true,
  433.     Index = 1,
  434.  
  435.     Draw = function(self)
  436.         if self.Visible then
  437.             for x = 1, self.Artboard.Width do
  438.                 for y = 1, self.Artboard.Height do
  439.                     self.Pixels[x][y]:Draw(x, y)
  440.                 end
  441.             end
  442.         end
  443.     end,
  444.  
  445.     Remove = function(self)
  446.         for i, v in ipairs(self.Artboard.Layers) do
  447.             if v == Current.Layer then
  448.                 Current.Artboard.Layers[i] = nil
  449.                 Current.Layer = Current.Artboard.Layers[1]
  450.                 ModuleNamed('Layers'):Update()
  451.             end
  452.         end
  453.     end,
  454.  
  455.     Initialise = function(self, name, backgroundColour, artboard, index, pixels)
  456.         local new = {}    -- the new instance
  457.         setmetatable( new, {__index = self} )
  458.         new.Name = name
  459.         new.Pixels = {}
  460.         new.BackgroundColour = backgroundColour
  461.         new.Artboard = artboard
  462.         new.Index = index or #artboard.Layers + 1
  463.         if not pixels then
  464.             new:MakeAllBlankPixels()
  465.         else
  466.             new:MakeAllBlankPixels()
  467.             for x, col in ipairs(pixels) do
  468.                 for y, pixel in ipairs(col) do
  469.                     new:SetPixel(x, y, pixel.TextColour, pixel.BackgroundColour, pixel.Character)
  470.                 end
  471.             end
  472.         end
  473.        
  474.         return new
  475.     end,
  476.  
  477.     SetPixel = function(self, x, y, textColour, backgroundColour, character)
  478.         textColour = textColour or Current.Colour
  479.         backgroundColour = backgroundColour or Current.Colour
  480.         character = character or " "
  481.  
  482.         if x < 1 or y < 1 or x > self.Artboard.Width or y > self.Artboard.Height then
  483.             return
  484.         end
  485.  
  486.         if self.Pixels[x][y] then
  487.             self.Pixels[x][y]:Set(textColour, backgroundColour, character)
  488.             self.Pixels[x][y]:Draw(x,y)
  489.         end
  490.     end,
  491.  
  492.     MakePixel = function(self, x, y, backgroundColour)
  493.         backgroundColour = backgroundColour or self.BackgroundColour           
  494.         self.Pixels[x][y] = Pixel:Initialise(nil, backgroundColour, nil, self)
  495.     end,
  496.  
  497.     MakeColumn = function(self, x)
  498.         self.Pixels[x] = {}
  499.     end,
  500.  
  501.     MakeAllBlankPixels = function(self)
  502.         for x = 1, self.Artboard.Width do
  503.             if not self.Pixels[x] then
  504.                 self:MakeColumn(x)
  505.             end
  506.  
  507.             for y = 1, self.Artboard.Height do         
  508.            
  509.                 if not self.Pixels[x][y] then
  510.                     self:MakePixel(x, y)
  511.                 end
  512.  
  513.             end
  514.         end
  515.     end,
  516.  
  517.     PixelsInSelection = function(self, cut)
  518.         local pixels = {}
  519.         if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  520.             local point1 = Current.Selection[1]
  521.             local point2 = Current.Selection[2]
  522.  
  523.             local size = point2 - point1
  524.             local cornerX = point1.x
  525.             local cornerY = point1.y
  526.             for x = 1, size.x + 1 do
  527.                 for y = 1, size.y + 1 do
  528.                     if not pixels[x] then
  529.                         pixels[x] = {}
  530.                     end
  531.                     if not self.Pixels[cornerX + x - 1] or not self.Pixels[cornerX + x - 1][cornerY + y - 1] then
  532.                         break
  533.                     end
  534.                     local pixel =  self.Pixels[cornerX + x - 1][cornerY + y - 1]
  535.                     pixels[x][y] = Pixel:Initialise(pixel.TextColour, pixel.BackgroundColour, pixel.Character, Current.Layer)
  536.                     if cut then
  537.                         Current.Layer:SetPixel(cornerX + x - 1, cornerY + y - 1, nil, Current.Layer.BackgroundColour, nil)
  538.                     end
  539.                 end
  540.             end
  541.         end
  542.         return pixels
  543.     end,
  544.  
  545.     EraseSelection = function(self)
  546.         if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  547.             local point1 = Current.Selection[1]
  548.             local point2 = Current.Selection[2]
  549.  
  550.             local size = point2 - point1
  551.             local cornerX = point1.x
  552.             local cornerY = point1.y
  553.             for x = 1, size.x + 1 do
  554.                 for y = 1, size.y + 1 do
  555.                     Current.Layer:SetPixel(cornerX + x - 1, cornerY + y - 1, nil, Current.Layer.BackgroundColour, nil)
  556.                 end
  557.             end
  558.         end
  559.     end,
  560.  
  561.     InsertPixels = function(self, pixels)
  562.         local cornerX = Current.Selection[1].x
  563.         local cornerY = Current.Selection[1].y
  564.         for x, col in ipairs(pixels) do
  565.             for y, pixel in ipairs(col) do
  566.                 Current.Layer:SetPixel(cornerX + x - 1, cornerY + y - 1, pixel.TextColour, pixel.BackgroundColour, pixel.Character)
  567.             end
  568.         end
  569.     end
  570. }
  571.  
  572. Artboard = {
  573.     X = 0,
  574.     Y = 0,
  575.     Name = "",
  576.     Path = "",
  577.     Width = 1,
  578.     Height = 1,
  579.     Layers = {},
  580.     Format = nil,
  581.     SelectionIsBlack = true,
  582.  
  583.     Draw = function(self)
  584.         Drawing.DrawBlankArea(self.X + 1, self.Y + 1, self.Width, self.Height, UIColours.Shadow)
  585.  
  586.         local odd
  587.         for x = 1, self.Width do
  588.             odd = x % 2
  589.             if odd == 1 then
  590.                 odd = true
  591.             else
  592.                 odd = false
  593.             end
  594.             for y = 1, self.Height do
  595.                 if odd then
  596.                     Drawing.WriteToBuffer(self.X + x - 1, self.Y + y - 1, ":", UIColours.TransparentBackgroundTwo, UIColours.TransparentBackgroundOne)
  597.                 else
  598.                     Drawing.WriteToBuffer(self.X + x - 1, self.Y + y - 1, ":", UIColours.TransparentBackgroundOne, UIColours.TransparentBackgroundTwo)
  599.                 end
  600.  
  601.                 odd = not odd
  602.             end
  603.         end
  604.  
  605.         for i, layer in ipairs(self.Layers) do
  606.             layer:Draw()
  607.         end
  608.  
  609.         if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  610.             local point1 = Current.Selection[1]
  611.             local point2 = Current.Selection[2]
  612.  
  613.             local size = point2 - point1
  614.  
  615.             local isBlack = self.SelectionIsBlack
  616.  
  617.             local function c()
  618.                 local c = colours.white
  619.                 if isBlack then
  620.                     c = colours.black
  621.                 end
  622.                 isBlack = not isBlack
  623.                 return c
  624.             end
  625.  
  626.             function horizontal(y)
  627.                 Drawing.WriteToBuffer(self.X - 1 + point1.x, self.Y - 1 + y, '+', c(), colours.transparent)
  628.                 if size.x > 0 then
  629.                     for i = 1, size.x - 1 do
  630.                         Drawing.WriteToBuffer(self.X - 1 + point1.x + i, self.Y - 1 + y, '-', c(), colours.transparent)
  631.                     end
  632.                 else
  633.                     for i = 1, (-1 * size.x) - 1 do
  634.                         Drawing.WriteToBuffer(self.X - 1 + point1.x - i, self.Y - 1 + y, '-', c(), colours.transparent)
  635.                     end
  636.                 end
  637.  
  638.                 Drawing.WriteToBuffer(self.X - 1 + point1.x + size.x, self.Y - 1 + y, '+', c(), colours.transparent)
  639.             end
  640.  
  641.             function vertical(x)
  642.                 if size.y < 0 then
  643.                     for i = 1, (-1 * size.y) - 1 do
  644.                         Drawing.WriteToBuffer(self.X - 1 + x, self.Y - 1 + point1.y  - i, '|', c(), colours.transparent)
  645.                     end
  646.                 else
  647.                     for i = 1, size.y - 1 do
  648.                         Drawing.WriteToBuffer(self.X - 1 + x, self.Y - 1 + point1.y  + i, '|', c(), colours.transparent)
  649.                     end
  650.                 end
  651.             end
  652.  
  653.             horizontal(point1.y)
  654.             vertical(point1.x)
  655.             horizontal(point1.y + size.y)
  656.             vertical(point1.x + size.x)
  657.         end
  658.     end,
  659.  
  660.     Initialise = function(self, name, path, width, height, format, backgroundColour, layers)
  661.         local new = {}    -- the new instance
  662.         setmetatable( new, {__index = self} )
  663.         new.Y = 3
  664.         new.X = 2
  665.         new.Name = name
  666.         new.Path = path
  667.         new.Width = width
  668.         new.Height = height
  669.         new.Format = format
  670.         new.Layers = {}
  671.         if not layers then
  672.             new:MakeLayer('Background', backgroundColour)
  673.         else
  674.             for i, layer in ipairs(layers) do
  675.                 new:MakeLayer(layer.Name, layer.BackgroundColour, layer.Index, layer.Pixels)
  676.                 new.Layers[i].Visible = layer.Visible
  677.             end
  678.             Current.Layer = new.Layers[#new.Layers]
  679.         end
  680.         return new
  681.     end,
  682.  
  683.     Resize = function(self, top, bottom, left, right)
  684.         self.Height = self.Height + top + bottom
  685.         self.Width = self.Width + left + right
  686.  
  687.         for i, layer in ipairs(self.Layers) do
  688.  
  689.             if left < 0 then
  690.                 for x = 1, -left do
  691.                     table.remove(layer.Pixels, 1)
  692.                 end
  693.             end
  694.  
  695.             if right < 0 then
  696.                 for x = 1, -right do
  697.                     table.remove(layer.Pixels, #layer.Pixels)
  698.                 end
  699.             end
  700.  
  701.             for x = 1, left do
  702.                 table.insert(layer.Pixels, 1, {})
  703.                 for y = 1, self.Height do
  704.                     layer:MakePixel(1, y)
  705.                 end
  706.             end
  707.  
  708.             for x = 1, right do
  709.                 table.insert(layer.Pixels, {})
  710.                 for y = 1, self.Height do
  711.                     layer:MakePixel(#layer.Pixels, y)
  712.                 end
  713.             end
  714.  
  715.             for y = 1, top do
  716.                 for x = 1, self.Width do
  717.                     table.insert(layer.Pixels[x], 1, {})
  718.                     layer:MakePixel(x, 1)
  719.                 end
  720.             end
  721.  
  722.             for y = 1, bottom do
  723.                 for x = 1, self.Width do
  724.                     table.insert(layer.Pixels[x], {})
  725.                     layer:MakePixel(x, #layer.Pixels[x])
  726.                 end
  727.             end
  728.  
  729.             if top < 0 then
  730.                 for y = 1, -top do
  731.                     for x = 1, self.Width do
  732.                         table.remove(layer.Pixels[x], 1)
  733.                     end
  734.                 end
  735.             end
  736.  
  737.             if bottom < 0 then
  738.                 for y = 1, -bottom do
  739.                     for x = 1, self.Width do
  740.                         table.remove(layer.Pixels[x], #layer.Pixels[x])
  741.                     end
  742.                 end
  743.             end
  744.         end
  745.     end,
  746.  
  747.     MakeLayer = function(self, name, backgroundColour, index, pixels)
  748.         backgroundColour = backgroundColour or colours.white
  749.         name = name or "Layer"
  750.         local layer = Layer:Initialise(name, backgroundColour, self, index, pixels)
  751.         table.insert(self.Layers, layer)
  752.         Current.Layer = layer
  753.         ModuleNamed('Layers'):Update()
  754.         return layer
  755.     end,
  756.  
  757.     New = function(self, name, path, width, height, format, backgroundColour, layers)
  758.         local new = self:Initialise(name, path, width, height, format, backgroundColour, layers)
  759.         table.insert(Lists.Artboards, new)
  760.         Current.Artboard = new
  761.         --new:Save()
  762.         return new
  763.     end,
  764.  
  765.     Save = function(self, path)
  766.         Current.Artboard = self
  767.         path = path or self.Path
  768.         local _open = io.open
  769.         if OneOS then
  770.             _open = OneOS.IO.open
  771.         end
  772.         local file = _open(path, "w", true)
  773.         if self.Format == '.skch' then
  774.             file:write(textutils.serialize(SaveSKCH()))
  775.         else
  776.             local lines = {}
  777.             if self.Format == '.nfp' then
  778.                 lines = SaveNFP()
  779.             elseif self.Format == '.nft' then
  780.                 lines = SaveNFT()
  781.             end
  782.  
  783.             for i, line in ipairs(lines) do
  784.                 file:write(line.."\n")
  785.             end
  786.         end
  787.         file:close()
  788.         Current.Modified = false
  789.     end,
  790.  
  791.     Click = function(self, side, x, y, drag)
  792.         if Current.Tool and Current.Layer and Current.Layer.Visible then
  793.             Current.Tool:Use(x, y, side, drag)
  794.             Current.Modified = true
  795.             return true
  796.         end
  797.     end
  798. }
  799.  
  800. Toolbar = {
  801.     X = 0,
  802.     Y = 0,
  803.     Width = 0,
  804.     ExpandedWidth = 14,
  805.     ClosedWidth = 2,
  806.     Height = 0,
  807.     Expanded = true,
  808.     ToolbarItems = {},
  809.  
  810.     AbsolutePosition = function(self)
  811.         return {X = self.X, Y = self.Y}
  812.     end,
  813.  
  814.     Draw = function(self)
  815.         self:CalculateToolbarItemPositions()
  816.         --Drawing.DrawArea(self.X - 1, self.Y, 1, self.Height, "|", UIColours.ToolbarText, UIColours.Background)
  817.  
  818.        
  819.  
  820.         --if not Current.Window then
  821.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.Toolbar)
  822.         --else
  823.         --  Drawing.DrawArea(self.X, self.Y, self.Width, self.Height, '|', colours.lightGrey, UIColours.Toolbar)
  824.         --end
  825.         for i, toolbarItem in ipairs(self.ToolbarItems) do
  826.             toolbarItem:Draw()
  827.         end
  828.     end,
  829.  
  830.     Initialise = function(self, side, expanded)
  831.         local new = {}    -- the new instance
  832.         setmetatable( new, {__index = self} )
  833.         new.Expanded = expanded
  834.  
  835.         if expanded then
  836.             new.Width = new.ExpandedWidth
  837.         else
  838.             new.Width = new.ClosedWidth
  839.         end
  840.  
  841.         if side == 'right' then
  842.             new.X = Drawing.Screen.Width - new.Width + 1
  843.         end
  844.  
  845.         if side == 'right' or side == 'left' then
  846.             new.Height = Drawing.Screen.Width
  847.         end
  848.  
  849.         new.Y = 1
  850.  
  851.         return new
  852.     end,
  853.  
  854.     AddToolbarItem = function(self, item)
  855.         table.insert(self.ToolbarItems, item)
  856.         self:CalculateToolbarItemPositions()
  857.     end,
  858.  
  859.     CalculateToolbarItemPositions = function(self)
  860.         local currY = 1
  861.         for i, toolbarItem in ipairs(self.ToolbarItems) do
  862.             toolbarItem.Y = currY
  863.             currY = currY + toolbarItem.Height
  864.         end
  865.     end,
  866.  
  867.     Update = function(self)
  868.         for i, toolbarItem in ipairs(self.ToolbarItems) do
  869.             if toolbarItem.Module.Update then
  870.                 toolbarItem.Module:Update(toolbarItem)
  871.             end
  872.         end
  873.     end,
  874.  
  875.     New = function(self, side, expanded)
  876.         local new = self:Initialise(side, expanded)
  877.  
  878.         --new:AddToolbarItem(ToolbarItem:Initialise("Colours", nil, true, new))
  879.         --new:AddToolbarItem(ToolbarItem:Initialise("IDK", true, new))
  880.  
  881.         table.insert(Lists.Interface.Toolbars, new)
  882.         return new
  883.     end,
  884.  
  885.     Click = function(self, side, x, y)
  886.         return false
  887.     end
  888. }
  889.  
  890. ToolbarItem = {
  891.     X = 0,
  892.     Y = 0,
  893.     Width = 0,
  894.     Height = 0,
  895.     ExpandedHeight = 5,
  896.     Expanded = true,
  897.     Toolbar = nil,
  898.     Title = "",
  899.     MenuIcon = "=",
  900.     ExpandedIcon = "+",
  901.     ContractIcon = "-",
  902.     ContentView = nil,
  903.     Module = nil,
  904.     MenuItems = nil,
  905.  
  906.     Draw = function(self)
  907.         Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, UIColours.ToolbarItemTitle)
  908.         Drawing.DrawCharacters(self.X + 1, self.Y, self.Title, UIColours.ToolbarText, UIColours.ToolbarItemTitle)
  909.  
  910.         Drawing.DrawCharacters(self.X + self.Width - 1, self.Y, self.MenuIcon, UIColours.ToolbarText, UIColours.ToolbarItemTitle)
  911.  
  912.         local expandContractIcon = self.ContractIcon
  913.         if not self.Expanded then
  914.             expandContractIcon = self.ExpandedIcon
  915.         end
  916.  
  917.         if self.Expanded and self.ContentView then
  918.             self.ContentView:Draw()
  919.         end
  920.  
  921.         Drawing.DrawCharacters(self.X + self.Width - 2, self.Y, expandContractIcon, UIColours.ToolbarText, UIColours.ToolbarItemTitle)
  922.     end,
  923.  
  924.     Initialise = function(self, module, height, expanded, toolbar, menuItems)
  925.         local new = {}    -- the new instance
  926.         setmetatable( new, {__index = self} )
  927.         new.Expanded = expanded
  928.         new.Title = module.Title
  929.         new.Width = toolbar.Width
  930.         new.Height = height or 5
  931.         new.Module = module
  932.         new.MenuItems = menuItems or {}
  933.         table.insert(new.MenuItems,
  934.             {
  935.                 Title = 'Shrink',
  936.                 Click = function()
  937.                     new:ToggleExpanded()
  938.                 end
  939.             })
  940.         new.ExpandedHeight = height or 5
  941.         new.Y = 1
  942.         new.X = toolbar.X
  943.         new.ContentView = ContentView:Initialise(1, 2, new.Width, new.Height - 1, nil, new)
  944.         new.Toolbar = toolbar
  945.  
  946.         return new
  947.     end,
  948.  
  949.     ToggleExpanded = function(self)
  950.         self.Expanded = not self.Expanded
  951.         if self.Expanded then
  952.             self.Height = self.ExpandedHeight
  953.         else
  954.             self.Height = 1
  955.         end
  956.     end,
  957.  
  958.     Click = function(self, side, x, y)
  959.         local pos = GetAbsolutePosition(self)
  960.         if x == self.Width and y == 1 then
  961.             local expandContract = "Shrink"
  962.  
  963.             if not self.Expanded then
  964.                 expandContract = "Expand"
  965.             end
  966.             self.MenuItems[#self.MenuItems].Title = expandContract
  967.             Menu:New(pos.X + x, pos.Y + y, self.MenuItems, self)
  968.             return true
  969.         elseif x == self.Width - 1 and y == 1 then
  970.             self:ToggleExpanded()
  971.             return true
  972.         elseif y ~= 1 then
  973.             return self.ContentView:Click(side,  x - self.ContentView.X + 1,  y - self.ContentView.Y + 1)
  974.         end
  975.  
  976.         return false
  977.     end
  978. }
  979.  
  980. ContentView = {
  981.     X = 1,
  982.     Y = 1,
  983.     Width = 0,
  984.     Height = 0,
  985.     Parent = nil,
  986.     Views = {},
  987.  
  988.     AbsolutePosition = function(self)
  989.         return self.Parent:AbsolutePosition()
  990.     end,
  991.  
  992.     Draw = function(self)
  993.         for i, view in ipairs(self.Views) do
  994.             view:Draw()
  995.         end
  996.     end,
  997.  
  998.     Initialise = function(self, x, y, width, height, views, parent)
  999.         local new = {}    -- the new instance
  1000.         setmetatable( new, {__index = self} )
  1001.         new.Width = width
  1002.         new.Height = height
  1003.         new.Y = y
  1004.         new.X = x
  1005.         new.Views = views or {}
  1006.         new.Parent = parent
  1007.         return new
  1008.     end,
  1009.  
  1010.     Click = function(self, side, x, y)
  1011.         for k, view in pairs(self.Views) do
  1012.             if DoClick(view, side, x, y) then
  1013.                 return true
  1014.             end
  1015.         end
  1016.     end
  1017. }
  1018.  
  1019. Button = {
  1020.     X = 1,
  1021.     Y = 1,
  1022.     Width = 0,
  1023.     Height = 0,
  1024.     BackgroundColour = colours.lightGrey,
  1025.     TextColour = colours.white,
  1026.     ActiveBackgroundColour = colours.lightGrey,
  1027.     Text = "",
  1028.     Parent = nil,
  1029.     _Click = nil,
  1030.     Toggle = nil,
  1031.  
  1032.     AbsolutePosition = function(self)
  1033.         return self.Parent:AbsolutePosition()
  1034.     end,
  1035.  
  1036.     Draw = function(self)
  1037.         local bg = self.BackgroundColour
  1038.         local tc = self.TextColour
  1039.         if type(bg) == 'function' then
  1040.             bg = bg()
  1041.         end
  1042.  
  1043.         if self.Toggle then
  1044.             tc = UIColours.MenuBarActive
  1045.             bg = self.ActiveBackgroundColour
  1046.         end
  1047.  
  1048.         local pos = GetAbsolutePosition(self)
  1049.         Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, bg)
  1050.         Drawing.DrawCharactersCenter(pos.X, pos.Y, self.Width, self.Height, self.Text, tc, bg)
  1051.     end,
  1052.  
  1053.     Initialise = function(self, x, y, width, height, backgroundColour, parent, click, text, textColour, toggle, activeBackgroundColour)
  1054.         local new = {}    -- the new instance
  1055.         setmetatable( new, {__index = self} )
  1056.         height = height or 1
  1057.         new.Width = width or #text + 2
  1058.         new.Height = height
  1059.         new.Y = y
  1060.         new.X = x
  1061.         new.Text = text or ""
  1062.         new.BackgroundColour = backgroundColour or colours.lightGrey
  1063.         new.TextColour = textColour or colours.white
  1064.         new.ActiveBackgroundColour = activeBackgroundColour or colours.lightGrey
  1065.         new.Parent = parent
  1066.         new._Click = click
  1067.         new.Toggle = toggle
  1068.         return new
  1069.     end,
  1070.  
  1071.     Click = function(self, side, x, y)
  1072.         if self._Click then
  1073.             if self:_Click(side, x, y, not self.Toggle) ~= false and self.Toggle ~= nil then
  1074.                 self.Toggle = not self.Toggle
  1075.                 Draw()
  1076.             end
  1077.             return true
  1078.         else
  1079.             return false
  1080.         end
  1081.     end
  1082. }
  1083.  
  1084. TextBox = {
  1085.     X = 1,
  1086.     Y = 1,
  1087.     Width = 0,
  1088.     Height = 0,
  1089.     BackgroundColour = colours.lightGrey,
  1090.     TextColour = colours.black,
  1091.     Parent = nil,
  1092.     TextInput = nil,
  1093.  
  1094.     AbsolutePosition = function(self)
  1095.         return self.Parent:AbsolutePosition()
  1096.     end,
  1097.  
  1098.     Draw = function(self)      
  1099.         local pos = GetAbsolutePosition(self)
  1100.         Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, self.BackgroundColour)
  1101.         local text = self.TextInput.Value
  1102.         if #text > (self.Width - 2) then
  1103.             text = text:sub(#text-(self.Width - 3))
  1104.             if Current.Input == self.TextInput then
  1105.                 Current.CursorPos = {pos.X + 1 + self.Width-2, pos.Y}
  1106.             end
  1107.         else
  1108.             if Current.Input == self.TextInput then
  1109.                 Current.CursorPos = {pos.X + 1 + self.TextInput.CursorPos, pos.Y}
  1110.             end
  1111.         end
  1112.         Drawing.DrawCharacters(pos.X + 1, pos.Y, text, self.TextColour, self.BackgroundColour)
  1113.  
  1114.         term.setCursorBlink(true)
  1115.        
  1116.         Current.CursorColour = self.TextColour
  1117.     end,
  1118.  
  1119.     Initialise = function(self, x, y, width, height, parent, text, backgroundColour, textColour, done, numerical)
  1120.         local new = {}    -- the new instance
  1121.         setmetatable( new, {__index = self} )
  1122.         height = height or 1
  1123.         new.Width = width or #text + 2
  1124.         new.Height = height
  1125.         new.Y = y
  1126.         new.X = x
  1127.         new.TextInput = TextInput:Initialise(text or '', function(key)
  1128.             if done then
  1129.                 done(key)
  1130.             end
  1131.             Draw()
  1132.         end, numerical)
  1133.         new.BackgroundColour = backgroundColour or colours.lightGrey
  1134.         new.TextColour = textColour or colours.black
  1135.         new.Parent = parent
  1136.         return new
  1137.     end,
  1138.  
  1139.     Click = function(self, side, x, y)
  1140.         Current.Input = self.TextInput
  1141.         self:Draw()
  1142.     end
  1143. }
  1144.  
  1145. TextInput = {
  1146.     Value = "",
  1147.     Change = nil,
  1148.     CursorPos = nil,
  1149.     Numerical = false,
  1150.  
  1151.     Initialise = function(self, value, change, numerical)
  1152.         local new = {}    -- the new instance
  1153.         setmetatable( new, {__index = self} )
  1154.         new.Value = value
  1155.         new.Change = change
  1156.         new.CursorPos = #value
  1157.         new.Numerical = numerical
  1158.         return new
  1159.     end,
  1160.  
  1161.     Char = function(self, char)
  1162.         if self.Numerical then
  1163.             char = tostring(tonumber(char))
  1164.         end
  1165.         if char == 'nil' then
  1166.             return
  1167.         end
  1168.         self.Value = string.sub(self.Value, 1, self.CursorPos ) .. char .. string.sub( self.Value, self.CursorPos + 1 )
  1169.        
  1170.         self.CursorPos = self.CursorPos + 1
  1171.         self.Change(key)
  1172.     end,
  1173.  
  1174.     Key = function(self, key)
  1175.         if key == keys.enter then
  1176.             self.Change(key)       
  1177.         elseif key == keys.left then
  1178.             -- Left
  1179.             if self.CursorPos > 0 then
  1180.                 self.CursorPos = self.CursorPos - 1
  1181.                 self.Change(key)
  1182.             end
  1183.            
  1184.         elseif key == keys.right then
  1185.             -- Right               
  1186.             if self.CursorPos < string.len(self.Value) then
  1187.                 self.CursorPos = self.CursorPos + 1
  1188.                 self.Change(key)
  1189.             end
  1190.        
  1191.         elseif key == keys.backspace then
  1192.             -- Backspace
  1193.             if self.CursorPos > 0 then
  1194.                 self.Value = string.sub( self.Value, 1, self.CursorPos - 1 ) .. string.sub( self.Value, self.CursorPos + 1 )
  1195.                 self.CursorPos = self.CursorPos - 1
  1196.             end
  1197.             self.Change(key)
  1198.         elseif key == keys.home then
  1199.             -- Home
  1200.             self.CursorPos = 0
  1201.             self.Change(key)
  1202.         elseif key == keys.delete then
  1203.             if self.CursorPos < string.len(self.Value) then
  1204.                 self.Value = string.sub( self.Value, 1, self.CursorPos ) .. string.sub( self.Value, self.CursorPos + 2 )               
  1205.                 self.Change(key)
  1206.             end
  1207.         elseif key == keys["end"] then
  1208.             -- End
  1209.             self.CursorPos = string.len(self.Value)
  1210.             self.Change(key)
  1211.         end
  1212.     end
  1213. }
  1214.  
  1215. LayerItem = {
  1216.     X = 1,
  1217.     Y = 1,
  1218.     Parent = nil,
  1219.     Layer = nil,
  1220.  
  1221.     Draw = function(self)
  1222.         self.Y = self.Layer.Index
  1223.  
  1224.         local pos = GetAbsolutePosition(self)
  1225.  
  1226.         local tc = colours.lightGrey
  1227.  
  1228.         if Current.Layer == self.Layer then
  1229.             tc = colours.white
  1230.         end
  1231.  
  1232.         Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, UIColours.Toolbar)
  1233.        
  1234.         Drawing.DrawCharacters(pos.X + 3, pos.Y, self.Layer.Name, tc, UIColours.Toolbar)
  1235.  
  1236.         if self.Layer.Visible then
  1237.             Drawing.DrawCharacters(pos.X + 1, pos.Y, "@", tc, UIColours.Toolbar)
  1238.         else
  1239.             Drawing.DrawCharacters(pos.X + 1, pos.Y, "X", tc, UIColours.Toolbar)
  1240.         end
  1241.  
  1242.     end,
  1243.  
  1244.     Initialise = function(self, layer, parent)
  1245.         local new = {}    -- the new instance
  1246.         setmetatable( new, {__index = self} )
  1247.         new.Width = parent.Width
  1248.         new.Height = 1
  1249.         new.Y = 1
  1250.         new.X = 1
  1251.         new.Layer = layer
  1252.         new.Parent = parent
  1253.         return new
  1254.     end,
  1255.  
  1256.     Click = function(self, side, x, y)
  1257.         if x == 2 then
  1258.             self.Layer.Visible = not self.Layer.Visible
  1259.         else
  1260.             Current.Layer = self.Layer
  1261.         end
  1262.         return true
  1263.     end
  1264. }
  1265.  
  1266. Menu = {
  1267.     X = 0,
  1268.     Y = 0,
  1269.     Width = 0,
  1270.     Height = 0,
  1271.     Owner = nil,
  1272.     Items = {},
  1273.     RemoveTop = false,
  1274.  
  1275.     Draw = function(self)
  1276.         Drawing.DrawBlankArea(self.X + 1, self.Y + 1, self.Width, self.Height, UIColours.Shadow)
  1277.         if not self.RemoveTop then
  1278.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.MenuBackground)
  1279.             for i, item in ipairs(self.Items) do
  1280.                 if item.Separator then
  1281.                     Drawing.DrawArea(self.X, self.Y + i, self.Width, 1, '-', colours.grey, UIColours.MenuBackground)
  1282.                 else
  1283.                     local textColour = UIColours.MenuText
  1284.                     if (item.Enabled and type(item.Enabled) == 'function' and item.Enabled() == false) or item.Enabled == false then
  1285.                         textColour = UIColours.MenuDisabledText
  1286.                     end
  1287.                     Drawing.DrawCharacters(self.X + 1, self.Y + i, item.Title, textColour, UIColours.MenuBackground)
  1288.                 end
  1289.             end
  1290.         else
  1291.             Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.MenuBackground)
  1292.             for i, item in ipairs(self.Items) do
  1293.                 if item.Separator then
  1294.                     Drawing.DrawArea(self.X, self.Y + i - 1, self.Width, 1, '-', colours.grey, UIColours.MenuBackground)
  1295.                 else
  1296.                     local textColour = UIColours.MenuText
  1297.                     if (item.Enabled and type(item.Enabled) == 'function' and item.Enabled() == false) or item.Enabled == false then
  1298.                         textColour = UIColours.MenuDisabledText
  1299.                     end
  1300.                     Drawing.DrawCharacters(self.X + 1, self.Y + i - 1, item.Title, textColour, UIColours.MenuBackground)
  1301.  
  1302.                     Drawing.DrawCharacters(self.X - 1 + self.Width-#item.KeyName, self.Y + i - 1, item.KeyName, textColour, UIColours.MenuBackground)
  1303.                 end
  1304.             end
  1305.         end
  1306.     end,
  1307.  
  1308.     NameForKey = function(self, key)
  1309.         if key == keys.leftCtrl then
  1310.             return '^'
  1311.         elseif key == keys.tab then
  1312.             return 'Tab'
  1313.         elseif key == keys.delete then
  1314.             return 'Delete'
  1315.         elseif key == keys.n then
  1316.             return 'N'
  1317.         elseif key == keys.s then
  1318.             return 'S'
  1319.         elseif key == keys.o then
  1320.             return 'O'
  1321.         elseif key == keys.z then
  1322.             return 'Z'
  1323.         elseif key == keys.y then
  1324.             return 'Y'
  1325.         elseif key == keys.c then
  1326.             return 'C'
  1327.         elseif key == keys.x then
  1328.             return 'X'
  1329.         elseif key == keys.v then
  1330.             return 'V'
  1331.         elseif key == keys.r then
  1332.             return 'R'
  1333.         elseif key == keys.l then
  1334.             return 'L'
  1335.         elseif key == keys.t then
  1336.             return 'T'
  1337.         elseif key == keys.h then
  1338.             return 'H'
  1339.         elseif key == keys.e then
  1340.             return 'E'
  1341.         elseif key == keys.p then
  1342.             return 'P'
  1343.         elseif key == keys.f then
  1344.             return 'F'
  1345.         elseif key == keys.m then
  1346.             return 'M'
  1347.         else
  1348.             return '?'     
  1349.         end
  1350.     end,
  1351.  
  1352.     Initialise = function(self, x, y, items, owner, removeTop)
  1353.         local new = {}    -- the new instance
  1354.         setmetatable( new, {__index = self} )
  1355.         if not owner then
  1356.             return
  1357.         end
  1358.  
  1359.         local keyNames = {}
  1360.  
  1361.         for i, v in ipairs(items) do
  1362.             items[i].KeyName = ''
  1363.             if v.Keys then
  1364.                 for _i, key in ipairs(v.Keys) do
  1365.                     items[i].KeyName = items[i].KeyName .. self:NameForKey(key)
  1366.                 end
  1367.             end
  1368.             if items[i].KeyName ~= '' then
  1369.                 table.insert(keyNames, items[i].KeyName)
  1370.             end
  1371.         end
  1372.         local keysLength = LongestString(keyNames)
  1373.         if keysLength > 0 then
  1374.             keysLength = keysLength + 2
  1375.         end
  1376.  
  1377.         new.Width = LongestString(items, 'Title') + 2 + keysLength
  1378.         if new.Width < 10 then
  1379.             new.Width = 10
  1380.         end
  1381.         new.Height = #items + 2
  1382.         new.RemoveTop = removeTop or false
  1383.         if removeTop then
  1384.             new.Height = new.Height - 1
  1385.         end
  1386.        
  1387.         if y < 1 then
  1388.             y = 1
  1389.         end
  1390.         if x < 1 then
  1391.             x = 1
  1392.         end
  1393.  
  1394.         if y + new.Height > Drawing.Screen.Height + 1 then
  1395.             y = Drawing.Screen.Height - new.Height
  1396.         end
  1397.         if x + new.Width > Drawing.Screen.Width + 1 then
  1398.             x = Drawing.Screen.Width - new.Width
  1399.         end
  1400.  
  1401.  
  1402.         new.Y = y
  1403.         new.X = x
  1404.         new.Items = items
  1405.         new.Owner = owner
  1406.         return new
  1407.     end,
  1408.  
  1409.     New = function(self, x, y, items, owner, removeTop)
  1410.         if Current.Menu and Current.Menu.Owner == owner then
  1411.             Current.Menu = nil
  1412.             return
  1413.         end
  1414.  
  1415.         local new = self:Initialise(x, y, items, owner, removeTop)
  1416.         Current.Menu = new
  1417.         return new
  1418.     end,
  1419.  
  1420.     Click = function(self, side, x, y)
  1421.         local i = y-1
  1422.         if self.RemoveTop then
  1423.             i = y
  1424.         end
  1425.         if i >= 1 and y < self.Height then
  1426.             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
  1427.                 self.Items[i]:Click()
  1428.                 if Current.Menu.Owner and Current.Menu.Owner.Toggle then
  1429.                     Current.Menu.Owner.Toggle = false
  1430.                 end
  1431.                 Current.Menu = nil
  1432.                 self = nil
  1433.             end
  1434.             return true
  1435.         end
  1436.     end
  1437. }
  1438.  
  1439. MenuBar = {
  1440.     X = 1,
  1441.     Y = 1,
  1442.     Width = Drawing.Screen.Width,
  1443.     Height = 1,
  1444.     MenuBarItems = {},
  1445.  
  1446.     AbsolutePosition = function(self)
  1447.         return {X = self.X, Y = self.Y}
  1448.     end,
  1449.  
  1450.     Draw = function(self)
  1451.         --Drawing.DrawArea(self.X - 1, self.Y, 1, self.Height, "|", UIColours.ToolbarText, UIColours.Background)
  1452.  
  1453.         Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.Toolbar)
  1454.         for i, button in ipairs(self.MenuBarItems) do
  1455.             button:Draw()
  1456.         end
  1457.     end,
  1458.  
  1459.     Initialise = function(self, items)
  1460.         local new = {}    -- the new instance
  1461.         setmetatable( new, {__index = self} )
  1462.         new.X = 1
  1463.         new.Y = 1
  1464.         new.MenuBarItems = items
  1465.         return new
  1466.     end,
  1467.  
  1468.     AddToolbarItem = function(self, item)
  1469.         table.insert(self.ToolbarItems, item)
  1470.         self:CalculateToolbarItemPositions()
  1471.     end,
  1472.  
  1473.     CalculateToolbarItemPositions = function(self)
  1474.         local currY = 1
  1475.         for i, toolbarItem in ipairs(self.ToolbarItems) do
  1476.             toolbarItem.Y = currY
  1477.             currY = currY + toolbarItem.Height
  1478.         end
  1479.     end,
  1480.  
  1481.     Click = function(self, side, x, y)
  1482.         for i, item in ipairs(self.MenuBarItems) do
  1483.             if item.X <= x and item.X + item.Width > x then
  1484.                 if item:Click(item, side, x - item.X + 1, 1) then
  1485.                     break
  1486.                 end
  1487.             end
  1488.         end
  1489.         return false
  1490.     end
  1491. }
  1492.  
  1493. --Modules--
  1494.  
  1495. Modules = {
  1496.     {
  1497.         Title = "Colours",
  1498.         ToolbarItem = nil,
  1499.         Initialise = function(self)
  1500.             self.ToolbarItem = ToolbarItem:Initialise(self, nil, true, Current.Toolbar)
  1501.  
  1502.             local buttons = {}
  1503.  
  1504.             local i = 0
  1505.  
  1506.             local coloursWidth = 8
  1507.             local _colours = {
  1508.                 colours.brown,
  1509.                 colours.yellow,
  1510.                 colours.orange,
  1511.                 colours.red,
  1512.                 colours.green,
  1513.                 colours.lime,
  1514.                 colours.magenta,
  1515.                 colours.pink,
  1516.                 colours.purple,
  1517.                 colours.blue,
  1518.                 colours.cyan,
  1519.                 colours.lightBlue,
  1520.                 colours.lightGrey,
  1521.                 colours.grey,
  1522.                 colours.black,
  1523.                 colours.white
  1524.             }
  1525.  
  1526.             for k, colour in pairs(_colours) do
  1527.                 if type(colour) == 'number' and colour ~= -1 then
  1528.                     i = i + 1
  1529.  
  1530.                     local y = math.floor(i/(coloursWidth/2))
  1531.  
  1532.                     local x = (i%(coloursWidth/2))
  1533.                     if x == 0 then
  1534.                         x = (coloursWidth/2)
  1535.                         y = y -1
  1536.                     end
  1537.  
  1538.                     table.insert(buttons,
  1539.                         {
  1540.                             X = x*2 - 2 + self.ToolbarItem.Width - coloursWidth,
  1541.                             Y = y+1,
  1542.                             Width = 2,
  1543.                             Height = 1,
  1544.                             BackgroundColour = colour,
  1545.                             Click = function(self, side, x, y)
  1546.                                 SetColour(self.BackgroundColour)
  1547.                             end
  1548.                         }
  1549.                     )
  1550.                 end
  1551.             end
  1552.  
  1553.             for i, button in ipairs(buttons) do
  1554.                 table.insert(self.ToolbarItem.ContentView.Views,
  1555.                     Button:Initialise(button.X, button.Y, button.Width, button.Height, button.BackgroundColour, self.ToolbarItem.ContentView, button.Click))   
  1556.             end
  1557.            
  1558.             table.insert(self.ToolbarItem.ContentView.Views,
  1559.                     Button:Initialise(1, 1, 4, 3, function()return Current.Colour end, self.ToolbarItem.ContentView, nil))
  1560.        
  1561.             Current.Toolbar:AddToolbarItem(self.ToolbarItem)
  1562.         end
  1563.     },
  1564.  
  1565.     {
  1566.         Title = "Tools",
  1567.         ToolbarItem = nil,
  1568.         Update = function(self)
  1569.             for i, view in ipairs(self.ToolbarItem.ContentView.Views) do
  1570.                 if (Current.Tool and Current.Tool.Name == view.Text) then
  1571.                     view.TextColour = colours.white
  1572.                 else
  1573.                     view.TextColour = colours.lightGrey
  1574.                 end
  1575.             end
  1576.             self.ToolbarItem.ContentView.Views[1].Text = 'Size: '..Current.ToolSize
  1577.         end,
  1578.  
  1579.         Initialise = function(self)
  1580.             self.ToolbarItem = ToolbarItem:Initialise(self, #Tools+2, true, Current.Toolbar,
  1581.                 {{
  1582.                     Title = "Change Tool Size",
  1583.                     Click = function()
  1584.                         DisplayToolSizeWindow()
  1585.                     end,
  1586.                 }})
  1587.  
  1588.             table.insert(self.ToolbarItem.ContentView.Views, Button:Initialise(1, 1, self.ToolbarItem.Width, 1, UIColours.Toolbar, self.ToolbarItem.ContentView, DisplayToolSizeWindow, 'Size: '..Current.ToolSize))
  1589.  
  1590.             local y = 2
  1591.             for i, tool in ipairs(Tools) do
  1592.                 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))
  1593.                 y = y + 1
  1594.             end
  1595.  
  1596.             self:Update(self.ToolbarItem)
  1597.  
  1598.             Current.Toolbar:AddToolbarItem(self.ToolbarItem)
  1599.         end
  1600.     },
  1601.  
  1602.     {
  1603.         Title = "Layers",
  1604.         ToolbarItem = nil,
  1605.         Update = function(self)
  1606.             if Current.Artboard then
  1607.                 self.ToolbarItem.ContentView.Views = {}
  1608.                 for i = 1, #Current.Artboard.Layers do
  1609.                     table.insert(self.ToolbarItem.ContentView.Views, LayerItem:Initialise(Current.Artboard.Layers[#Current.Artboard.Layers-i+1], self.ToolbarItem.ContentView))
  1610.                 end                
  1611.             end
  1612.         end,
  1613.  
  1614.         Initialise = function(self)
  1615.             self.ToolbarItem = ToolbarItem:Initialise(self, nil, true, Current.Toolbar,
  1616.                 {{
  1617.                     Title = "New Layer",
  1618.                     Click = function()
  1619.                         MakeNewLayer()
  1620.                     end,
  1621.                     Enabled = function()
  1622.                         return CheckOpenArtboard()
  1623.                     end
  1624.                 },
  1625.                 {
  1626.                     Title = 'Delete Layer',
  1627.                     Click = function()
  1628.                         DeleteLayer()
  1629.                     end,
  1630.                     Enabled = function()
  1631.                         return CheckSelectedLayer()
  1632.                     end
  1633.                 },
  1634.                 {
  1635.                     Title = 'Rename Layer...',
  1636.                     Click = function()
  1637.                         RenameLayer()
  1638.                     end,
  1639.                     Enabled = function()
  1640.                         return CheckSelectedLayer()
  1641.                     end
  1642.                 }})
  1643.            
  1644.             self:Update()
  1645.  
  1646.             Current.Toolbar:AddToolbarItem(self.ToolbarItem)
  1647.         end
  1648.     }
  1649.  
  1650. }
  1651.  
  1652. function ModuleNamed(name)
  1653.     for i, v in ipairs(Modules) do
  1654.         if v.Title == name then
  1655.             return v
  1656.         end
  1657.     end
  1658. end
  1659.  
  1660. --Tools--
  1661.  
  1662. function ToolAffectedPixels(x, y)
  1663.     if not CheckSelectedLayer() then
  1664.         return {}
  1665.     end
  1666.     if Current.ToolSize == 1 then
  1667.         if Current.Layer.Pixels[x] and Current.Layer.Pixels[x][y] then
  1668.             return {{Current.Layer.Pixels[x][y], x, y}}
  1669.         end
  1670.     else
  1671.         local pixels = {}
  1672.         local cornerX = x - math.ceil(Current.ToolSize/2)
  1673.         local cornerY = y - math.ceil(Current.ToolSize/2)
  1674.         for _x = 1, Current.ToolSize do
  1675.             for _y = 1, Current.ToolSize do
  1676.                 if Current.Layer.Pixels[cornerX + _x] and Current.Layer.Pixels[cornerX + _x][cornerY + _y] then
  1677.                     table.insert(pixels, {Current.Layer.Pixels[cornerX + _x][cornerY + _y], cornerX + _x, cornerY + _y})
  1678.                 end
  1679.             end
  1680.         end
  1681.         return pixels
  1682.     end
  1683. end
  1684. local moveStartPoint = {}
  1685. Tools = {
  1686.     {
  1687.         Name = "Hand",
  1688.         Use = function(self, x, y, side, drag)
  1689.             Current.Input = nil
  1690.             if drag and Current.HandDragStart and Current.HandDragStart[1] and Current.HandDragStart[2] then
  1691.                 local deltaX = x - Current.HandDragStart[1]
  1692.                 local deltaY = y - Current.HandDragStart[2]
  1693.                 Current.Artboard.X = Current.Artboard.X + deltaX
  1694.                 Current.Artboard.Y = Current.Artboard.Y + deltaY
  1695.             else
  1696.                 Current.HandDragStart = {x, y}
  1697.             end
  1698.             sleep(0)
  1699.         end,
  1700.         Select = function(self)
  1701.             return true
  1702.         end
  1703.     },
  1704.  
  1705.     {
  1706.         Name = "Pencil",
  1707.         Use = function(self, _x, _y, side, artboard)
  1708.             Current.Input = nil
  1709.             for i, pixel in ipairs(ToolAffectedPixels(_x, _y)) do
  1710.                 if side == 1 then
  1711.                     pixel[1].BackgroundColour = Current.Colour
  1712.                 elseif side == 2 then
  1713.                     pixel[1].TextColour = Current.Colour
  1714.                 end
  1715.                 pixel[1]:Draw(pixel[2], pixel[3])
  1716.             end
  1717.         end,
  1718.         Select = function(self)
  1719.             return true
  1720.         end
  1721.     },
  1722.  
  1723.     {
  1724.         Name = "Eraser",
  1725.         Use = function(self, x, y, side)
  1726.             Current.Input = nil
  1727.             Current.Layer:SetPixel(x, y, nil, Current.Layer.BackgroundColour, nil)
  1728.             for i, pixel in ipairs(ToolAffectedPixels(x, y)) do
  1729.                 Current.Layer:SetPixel(pixel[2], pixel[3], nil, Current.Layer.BackgroundColour, nil)
  1730.             end
  1731.         end,
  1732.         Select = function(self)
  1733.             return true
  1734.         end
  1735.     },
  1736.  
  1737.     {
  1738.         Name = "Fill Bucket",
  1739.         Use = function(self, x, y, side)
  1740.             local replaceColour = Current.Layer.Pixels[x][y].BackgroundColour
  1741.             if side == 2 then
  1742.                 replaceColour = Current.Layer.Pixels[x][y].TextColour
  1743.             end
  1744.  
  1745.             local nodes = {{X = x, Y = y}}
  1746.  
  1747.             while #nodes > 0 do
  1748.                 local node = nodes[1]
  1749.                 if Current.Layer.Pixels[node.X] and Current.Layer.Pixels[node.X][node.Y] then
  1750.                     local replacing = Current.Layer.Pixels[node.X][node.Y].BackgroundColour
  1751.                     if side == 2 then
  1752.                         replacing = Current.Layer.Pixels[node.X][node.Y].TextColour
  1753.                     end
  1754.                     if replacing == replaceColour and replacing ~= Current.Colour then
  1755.                         if side == 1 then
  1756.                             Current.Layer.Pixels[node.X][node.Y].BackgroundColour = Current.Colour
  1757.                         elseif side == 2 then
  1758.                             Current.Layer.Pixels[node.X][node.Y].TextColour = Current.Colour
  1759.                         end
  1760.                         table.insert(nodes, {X = node.X, Y = node.Y + 1})
  1761.                         table.insert(nodes, {X = node.X + 1, Y = node.Y})
  1762.                         if x > 1 then
  1763.                             table.insert(nodes, {X = node.X - 1, Y = node.Y})
  1764.                         end
  1765.                         if y > 1 then
  1766.                             table.insert(nodes, {X = node.X, Y = node.Y - 1})
  1767.                         end
  1768.                     end
  1769.                 end
  1770.                 table.remove(nodes, 1)
  1771.             end
  1772.             Draw()
  1773.         end,
  1774.         Select = function(self)
  1775.             return true
  1776.         end
  1777.     },
  1778.  
  1779.     {
  1780.         Name = "Select",
  1781.         Use = function(self, x, y, side, drag)
  1782.             Current.Input = nil
  1783.             if not drag then
  1784.                 Current.Selection[1] = vector.new(x, y, 0)
  1785.                 Current.Selection[2] = nil
  1786.             else
  1787.                 Current.Selection[2] = vector.new(x, y, 0)
  1788.             end
  1789.         end,
  1790.         Select = function(self)
  1791.             return true
  1792.         end
  1793.     },
  1794.  
  1795.     {
  1796.         Name = "Move",
  1797.         Use = function(self, x, y, side, drag)
  1798.             Current.Input = nil
  1799.  
  1800.             if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  1801.                 if drag and moveStartPoint then
  1802.                     local pixels = Current.Layer:PixelsInSelection(true)
  1803.                     local size = Current.Selection[1] - Current.Selection[2]
  1804.                     Current.Selection[1] = vector.new(x-moveStartPoint[1], y-moveStartPoint[2], 0)
  1805.                     Current.Selection[2] = vector.new(x-moveStartPoint[1]-size.x, y-moveStartPoint[2]-size.y, 0)
  1806.                     Current.Layer:InsertPixels(pixels)
  1807.                 else
  1808.                     moveStartPoint = {x-Current.Selection[1].x, y-Current.Selection[1].y}
  1809.                 end
  1810.             end
  1811.         end,
  1812.         Select = function(self)
  1813.             return true
  1814.         end
  1815.     },
  1816.  
  1817.     {
  1818.         Name = "Text",
  1819.         Use = function(self, x, y)
  1820.             Current.Input = TextInput:Initialise('', function(key)
  1821.                 if key == keys.delete or key == keys.backspace then
  1822.                     if #Current.Input.Value == 0 then
  1823.                         if Current.Layer.Pixels[x] and Current.Layer.Pixels[x][y] then
  1824.                             Current.Layer.Pixels[x][y]:Set(nil, nil, ' ')
  1825.                             local newPos = Current.CursorPos[1] - Current.Artboard.X
  1826.                             if newPos < Current.Artboard.X - 1 then
  1827.                                 newPos = Current.Artboard.X - 1
  1828.                             end
  1829.                             Current.Tool:Use(newPos, Current.CursorPos[2] - Current.Artboard.Y + 1)
  1830.                             Draw()
  1831.                         end
  1832.                         return
  1833.                     else
  1834.                         if Current.Layer.Pixels[x+#Current.Input.Value] and Current.Layer.Pixels[x+#Current.Input.Value][y] then
  1835.                             Current.Layer.Pixels[x+#Current.Input.Value][y]:Set(nil, nil, ' ')
  1836.                         end
  1837.                     end
  1838.                 else
  1839.                     local i = #Current.Input.Value
  1840.                     if Current.Layer.Pixels[x+i-1] then
  1841.                         Current.Layer.Pixels[x+i-1][y]:Set(Current.Colour, nil, Current.Input.Value:sub(i,i))
  1842.                         Current.Layer.Pixels[x+i-1][y]:Draw(x+i-1, y)
  1843.                     end
  1844.                 end
  1845.  
  1846.                 local newPos = x+Current.Input.CursorPos
  1847.  
  1848.                 if newPos > Current.Artboard.Width then
  1849.                     Current.Input.CursorPos = Current.Input.CursorPos - 1
  1850.                 end
  1851.  
  1852.                 Current.CursorPos = {x+Current.Input.CursorPos + Current.Artboard.X - 1, y + Current.Artboard.Y - 1}
  1853.                 Current.CursorColour = Current.Colour
  1854.                 Draw()
  1855.             end)
  1856.  
  1857.             Current.CursorPos = {x + Current.Artboard.X - 1, y + Current.Artboard.Y - 1}
  1858.             Current.CursorColour = Current.Colour
  1859.         end,
  1860.         Select = function(self)
  1861.             if Current.Artboard.Format == '.nfp' then
  1862.                 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)
  1863.                     window:Close()
  1864.                 end):Show()
  1865.                 return false
  1866.             else
  1867.                 return true
  1868.             end
  1869.         end
  1870.     }
  1871. }
  1872.  
  1873.  
  1874. function ToolNamed(name)
  1875.     for i, v in ipairs(Tools) do
  1876.         if v.Name == name then
  1877.             return v
  1878.         end
  1879.     end
  1880. end
  1881.  
  1882. --Windows--
  1883.  
  1884. NewDocumentWindow = {
  1885.     X = 1,
  1886.     Y = 1,
  1887.     Width = 0,
  1888.     Height = 0,
  1889.     CursorPos = 1,
  1890.     Visible = true,
  1891.     Return = nil,
  1892.     OkButton = nil,
  1893.     Format = '.skch',
  1894.     ImageBackgroundColour = colours.white,
  1895.     NameLabelHighlight = false,
  1896.     SizeLabelHighlight = false,
  1897.  
  1898.  
  1899.     AbsolutePosition = function(self)
  1900.         return {X = self.X, Y = self.Y}
  1901.     end,
  1902.  
  1903.     Draw = function(self)
  1904.         if not self.Visible then
  1905.             return
  1906.         end
  1907.         Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  1908.         Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  1909.         Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  1910.         Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  1911.  
  1912.         local nameLabelColour = colours.black
  1913.         if self.NameLabelHighlight then
  1914.             nameLabelColour = colours.red
  1915.         end
  1916.  
  1917.         Drawing.DrawCharacters(self.X+1, self.Y+2, "Name", nameLabelColour, colours.white)
  1918.         Drawing.DrawCharacters(self.X+1, self.Y+4, "Type", colours.black, colours.white)
  1919.  
  1920.         local sizeLabelColour = colours.black
  1921.         if self.SizeLabelHighlight then
  1922.             sizeLabelColour = colours.red
  1923.         end
  1924.         Drawing.DrawCharacters(self.X+1, self.Y+6, "Size", sizeLabelColour, colours.white)
  1925.         Drawing.DrawCharacters(self.X+11, self.Y+6, "x", colours.black, colours.white)
  1926.         Drawing.DrawCharacters(self.X+1, self.Y+8, "Background", colours.black, colours.white)
  1927.  
  1928.         self.OkButton:Draw()
  1929.         self.CancelButton:Draw()
  1930.         self.SKCHButton:Draw()
  1931.         self.NFTButton:Draw()
  1932.         self.NFPButton:Draw()
  1933.         self.PathTextBox:Draw()
  1934.         self.WidthTextBox:Draw()
  1935.         self.HeightTextBox:Draw()
  1936.         self.WhiteButton:Draw()
  1937.         self.BlackButton:Draw()
  1938.         self.TransparentButton:Draw()
  1939.     end,   
  1940.  
  1941.     Initialise = function(self, returnFunc)
  1942.         local new = {}    -- the new instance
  1943.         setmetatable( new, {__index = self} )
  1944.         new.Width = 32
  1945.         new.Height = 13
  1946.         new.Return = returnFunc
  1947.         new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  1948.         new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  1949.         new.Title = 'New Document'
  1950.         new.Visible = true
  1951.         new.NameLabelHighlight = false
  1952.         new.SizeLabelHighlight = false
  1953.         new.Format = '.skch'
  1954.         new.OkButton = Button:Initialise(new.Width - 4, new.Height - 1, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  1955.             local path = new.PathTextBox.TextInput.Value
  1956.             local ok = true
  1957.             new.NameLabelHighlight = false
  1958.             new.SizeLabelHighlight = false
  1959.             local _fs = fs
  1960.             if OneOS then
  1961.                 _fs = OneOS.FS
  1962.             end
  1963.             if path:sub(-1) == '/' or _fs.isDir(path) or #path == 0 then
  1964.                 ok = false
  1965.                 new.NameLabelHighlight = true
  1966.             end
  1967.  
  1968.             if #new.WidthTextBox.TextInput.Value == 0 or tonumber(new.WidthTextBox.TextInput.Value) <= 0 then
  1969.                 ok = false
  1970.                 new.SizeLabelHighlight = true
  1971.             end
  1972.  
  1973.             if #new.HeightTextBox.TextInput.Value == 0 or tonumber(new.HeightTextBox.TextInput.Value) <= 0 then
  1974.                 ok = false
  1975.                 new.SizeLabelHighlight = true
  1976.             end
  1977.  
  1978.             if ok then
  1979.                 returnFunc(new, true, path, tonumber(new.WidthTextBox.TextInput.Value), tonumber(new.HeightTextBox.TextInput.Value), new.Format, new.ImageBackgroundColour)
  1980.             else
  1981.                 Draw()
  1982.             end
  1983.         end, 'Ok', colours.black)
  1984.         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)
  1985.  
  1986.         new.SKCHButton = Button:Initialise(7, 5, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  1987.             new.NFTButton.Toggle = false
  1988.             new.NFPButton.Toggle = false
  1989.             self.Toggle = false
  1990.             new.Format = '.skch'
  1991.         end, '.skch', colours.black, true, colours.lightBlue)
  1992.         new.NFTButton = Button:Initialise(15, 5, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  1993.             new.SKCHButton.Toggle = false
  1994.             new.NFPButton.Toggle = false
  1995.             self.Toggle = false
  1996.             new.Format = '.nft'
  1997.         end, '.nft', colours.black, false, colours.lightBlue)
  1998.         new.NFPButton = Button:Initialise(22, 5, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  1999.             new.SKCHButton.Toggle = false
  2000.             new.NFTButton.Toggle = false
  2001.             self.Toggle = false
  2002.             new.Format = '.nfp'
  2003.         end, '.nfp', colours.black, false, colours.lightBlue)
  2004.  
  2005.         local path = ''
  2006.         if OneOS then
  2007.             path = '/Desktop/'
  2008.         end
  2009.         new.PathTextBox = TextBox:Initialise(7, 3, new.Width - 7, 1, new, path, nil, nil, function(key)
  2010.             if key == keys.enter or key == keys.tab then
  2011.                 Current.Input = new.WidthTextBox.TextInput
  2012.             end        
  2013.         end)
  2014.         new.WidthTextBox = TextBox:Initialise(7, 7, 4, 1, new, tostring(15), nil, nil, function()
  2015.             if key == keys.enter or key == keys.tab then
  2016.                 Current.Input = new.HeightTextBox.TextInput
  2017.             end
  2018.         end, true)
  2019.         new.HeightTextBox = TextBox:Initialise(14, 7, 4, 1, new, tostring(10), nil, nil, function()
  2020.             if key == keys.enter or key == keys.tab then
  2021.                 Current.Input = new.PathTextBox.TextInput
  2022.             end
  2023.         end, true)
  2024.         Current.Input = new.PathTextBox.TextInput
  2025.  
  2026.  
  2027.         new.WhiteButton = Button:Initialise(2, 10, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  2028.             new.TransparentButton.Toggle = false
  2029.             new.BlackButton.Toggle = false
  2030.             self.Toggle = false
  2031.             new.ImageBackgroundColour = colours.white
  2032.         end, 'White', colours.black, true, colours.lightBlue)
  2033.         new.BlackButton = Button:Initialise(10, 10, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  2034.             new.TransparentButton.Toggle = false
  2035.             new.WhiteButton.Toggle = false
  2036.             self.Toggle = false
  2037.             new.ImageBackgroundColour = colours.black
  2038.         end, 'Black', colours.black, false, colours.lightBlue)
  2039.         new.TransparentButton = Button:Initialise(18, 10, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  2040.             new.WhiteButton.Toggle = false
  2041.             new.BlackButton.Toggle = false
  2042.             self.Toggle = false
  2043.             new.ImageBackgroundColour = colours.transparent
  2044.         end, 'Transparent', colours.black, false, colours.lightBlue)
  2045.  
  2046.         return new
  2047.     end,
  2048.  
  2049.     Show = function(self)
  2050.         Current.Window = self
  2051.         return self
  2052.     end,
  2053.  
  2054.     Close = function(self)
  2055.         Current.Input = nil
  2056.         Current.Window = nil
  2057.         self = nil
  2058.     end,
  2059.  
  2060.     Flash = function(self)
  2061.         self.Visible = false
  2062.         Draw()
  2063.         sleep(0.15)
  2064.         self.Visible = true
  2065.         Draw()
  2066.         sleep(0.15)
  2067.         self.Visible = false
  2068.         Draw()
  2069.         sleep(0.15)
  2070.         self.Visible = true
  2071.         Draw()
  2072.     end,
  2073.  
  2074.     ButtonClick = function(self, button, x, y)
  2075.         if button.X <= x and button.Y <= y and button.X + button.Width > x and button.Y + button.Height > y then
  2076.             button:Click()
  2077.         end
  2078.     end,
  2079.  
  2080.     Click = function(self, side, x, y)
  2081.         local items = {self.OkButton, self.CancelButton, self.SKCHButton, self.NFTButton, self.NFPButton, self.PathTextBox, self.WidthTextBox, self.HeightTextBox, self.WhiteButton, self.BlackButton, self.TransparentButton}
  2082.         for i, v in ipairs(items) do
  2083.             if CheckClick(v, x, y) then
  2084.                 v:Click(side, x, y)
  2085.             end
  2086.         end
  2087.         return true
  2088.     end
  2089. }
  2090.  
  2091. local TidyPath = function(path)
  2092.     path = '/'..path
  2093.     local _fs = fs
  2094.     if OneOS then
  2095.         _fs = OneOS.FS
  2096.     end
  2097.     if _fs.isDir(path) then
  2098.         path = path .. '/'
  2099.     end
  2100.  
  2101.     path, n = path:gsub("//", "/")
  2102.     while n > 0 do
  2103.         path, n = path:gsub("//", "/")
  2104.     end
  2105.     return path
  2106. end
  2107.  
  2108. local WrapText = function(text, maxWidth)
  2109.     local lines = {''}
  2110.     for word, space in text:gmatch('(%S+)(%s*)') do
  2111.             local temp = lines[#lines] .. word .. space:gsub('\n','')
  2112.             if #temp > maxWidth then
  2113.                     table.insert(lines, '')
  2114.             end
  2115.             if space:find('\n') then
  2116.                     lines[#lines] = lines[#lines] .. word
  2117.                    
  2118.                     space = space:gsub('\n', function()
  2119.                             table.insert(lines, '')
  2120.                             return ''
  2121.                     end)
  2122.             else
  2123.                     lines[#lines] = lines[#lines] .. word .. space
  2124.             end
  2125.     end
  2126.     return lines
  2127. end
  2128.  
  2129. OpenDocumentWindow = {
  2130.     X = 1,
  2131.     Y = 1,
  2132.     Width = 0,
  2133.     Height = 0,
  2134.     CursorPos = 1,
  2135.     Visible = true,
  2136.     Return = nil,
  2137.     OpenButton = nil,
  2138.     PathTextBox = nil,
  2139.     CurrentDirectory = '/',
  2140.     Scroll = 0,
  2141.     MaxScroll = 0,
  2142.     GoUpButton = nil,
  2143.     SelectedFile = '',
  2144.     Files = {},
  2145.     Typed = false,
  2146.  
  2147.     AbsolutePosition = function(self)
  2148.         return {X = self.X, Y = self.Y}
  2149.     end,
  2150.  
  2151.     Draw = function(self)
  2152.         if not self.Visible then
  2153.             return
  2154.         end
  2155.         Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  2156.         Drawing.DrawBlankArea(self.X, self.Y, self.Width, 3, colours.lightGrey)
  2157.         Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-6, colours.white)
  2158.         Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  2159.         Drawing.DrawBlankArea(self.X, self.Y + self.Height - 5, self.Width, 5, colours.lightGrey)
  2160.         self:DrawFiles()
  2161.  
  2162.         local _fs = fs
  2163.         if OneOS then
  2164.             _fs = OneOS.FS
  2165.         end
  2166.         if (_fs.exists(self.PathTextBox.TextInput.Value)) or (self.SelectedFile and #self.SelectedFile > 0 and _fs.exists(self.CurrentDirectory .. self.SelectedFile)) then
  2167.             self.OpenButton.TextColour = colours.black
  2168.         else
  2169.             self.OpenButton.TextColour = colours.lightGrey
  2170.         end
  2171.  
  2172.         self.PathTextBox:Draw()
  2173.         self.OpenButton:Draw()
  2174.         self.CancelButton:Draw()
  2175.         self.GoUpButton:Draw()
  2176.     end,
  2177.  
  2178.     DrawFiles = function(self)
  2179.         local _fs = fs
  2180.         if OneOS then
  2181.             _fs = OneOS.FS
  2182.         end
  2183.         for i, file in ipairs(self.Files) do
  2184.             if i > self.Scroll and i - self.Scroll <= 11 then
  2185.                 if file == self.SelectedFile then
  2186.                     Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.white, colours.lightBlue)
  2187.                 elseif string.find(file, '%.skch') or string.find(file, '%.nft') or string.find(file, '%.nfp') or _fs.isDir(self.CurrentDirectory .. file) then
  2188.                     Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.black, colours.white)
  2189.                 else
  2190.                     Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.grey, colours.white)
  2191.                 end
  2192.             end
  2193.         end
  2194.         self.MaxScroll = #self.Files - 11
  2195.         if self.MaxScroll < 0 then
  2196.             self.MaxScroll = 0
  2197.         end
  2198.     end,
  2199.  
  2200.     Initialise = function(self, returnFunc)
  2201.         local new = {}    -- the new instance
  2202.         setmetatable( new, {__index = self} )
  2203.         new.Width = 32
  2204.         new.Height = 17
  2205.         new.Return = returnFunc
  2206.         new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  2207.         new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  2208.         new.Title = 'Open Document'
  2209.         new.Visible = true
  2210.         new.CurrentDirectory = '/'
  2211.         new.SelectedFile = nil
  2212.         if OneOS then
  2213.             new.CurrentDirectory = '/Desktop/'
  2214.         end
  2215.         local _fs = fs
  2216.         if OneOS then
  2217.             _fs = OneOS.FS
  2218.         end
  2219.         new.OpenButton = Button:Initialise(new.Width - 6, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  2220.             if _fs.exists(new.PathTextBox.TextInput.Value) and self.TextColour == colours.black and not _fs.isDir(new.PathTextBox.TextInput.Value) then
  2221.                 returnFunc(new, true, TidyPath(new.PathTextBox.TextInput.Value))
  2222.             elseif new.SelectedFile and self.TextColour == colours.black and _fs.isDir(new.CurrentDirectory .. new.SelectedFile) then
  2223.                 new:GoToDirectory(new.CurrentDirectory .. new.SelectedFile)
  2224.             elseif new.SelectedFile and self.TextColour == colours.black then
  2225.                 returnFunc(new, true, TidyPath(new.CurrentDirectory .. '/' .. new.SelectedFile))
  2226.             end
  2227.         end, 'Open', colours.black)
  2228.         new.CancelButton = Button:Initialise(new.Width - 15, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  2229.             returnFunc(new, false)
  2230.         end, 'Cancel', colours.black)
  2231.         new.GoUpButton = Button:Initialise(2, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle)
  2232.             local folderName = _fs.getName(new.CurrentDirectory)
  2233.             local parentDirectory = new.CurrentDirectory:sub(1, #new.CurrentDirectory-#folderName-1)
  2234.             new:GoToDirectory(parentDirectory)
  2235.         end, 'Go Up', colours.black)
  2236.         new.PathTextBox = TextBox:Initialise(2, new.Height - 3, new.Width - 2, 1, new, new.CurrentDirectory, colours.white, colours.black)
  2237.         new:GoToDirectory(new.CurrentDirectory)
  2238.         return new
  2239.     end,
  2240.  
  2241.     Show = function(self)
  2242.         Current.Window = self
  2243.         return self
  2244.     end,
  2245.  
  2246.     Close = function(self)
  2247.         Current.Input = nil
  2248.         Current.Window = nil
  2249.         self = nil
  2250.     end,
  2251.  
  2252.     GoToDirectory = function(self, path)
  2253.         path = TidyPath(path)
  2254.         self.CurrentDirectory = path
  2255.         self.Scroll = 0
  2256.         self.SelectedFile = nil
  2257.         self.Typed = false
  2258.         self.PathTextBox.TextInput.Value = path
  2259.         local _fs = fs
  2260.         if OneOS then
  2261.             _fs = OneOS.FS
  2262.         end
  2263.         self.Files = _fs.list(self.CurrentDirectory)
  2264.         Draw()
  2265.     end,
  2266.  
  2267.     Flash = function(self)
  2268.         self.Visible = false
  2269.         Draw()
  2270.         sleep(0.15)
  2271.         self.Visible = true
  2272.         Draw()
  2273.         sleep(0.15)
  2274.         self.Visible = false
  2275.         Draw()
  2276.         sleep(0.15)
  2277.         self.Visible = true
  2278.         Draw()
  2279.     end,
  2280.  
  2281.     Click = function(self, side, x, y)
  2282.         local items = {self.OpenButton, self.CancelButton, self.PathTextBox, self.GoUpButton}
  2283.         local found = false
  2284.         for i, v in ipairs(items) do
  2285.             if CheckClick(v, x, y) then
  2286.                 v:Click(side, x, y)
  2287.                 found = true
  2288.             end
  2289.         end
  2290.  
  2291.         if not found then
  2292.             if y <= 12 then
  2293.                 local _fs = fs
  2294.                 if OneOS then
  2295.                     _fs = OneOS.FS
  2296.                 end
  2297.                 self.SelectedFile = _fs.list(self.CurrentDirectory)[y-1]
  2298.                 self.PathTextBox.TextInput.Value = TidyPath(self.CurrentDirectory .. '/' .. self.SelectedFile)
  2299.                 Draw()
  2300.             end
  2301.         end
  2302.         return true
  2303.     end
  2304. }
  2305.  
  2306. ButtonDialougeWindow = {
  2307.     X = 1,
  2308.     Y = 1,
  2309.     Width = 0,
  2310.     Height = 0,
  2311.     CursorPos = 1,
  2312.     Visible = true,
  2313.     CancelButton = nil,
  2314.     OkButton = nil,
  2315.     Lines = {},
  2316.  
  2317.     AbsolutePosition = function(self)
  2318.         return {X = self.X, Y = self.Y}
  2319.     end,
  2320.  
  2321.     Draw = function(self)
  2322.         if not self.Visible then
  2323.             return
  2324.         end
  2325.         Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  2326.         Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  2327.         Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  2328.         Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  2329.  
  2330.         for i, text in ipairs(self.Lines) do
  2331.             Drawing.DrawCharacters(self.X + 1, self.Y + 1 + i, text, colours.black, colours.white)
  2332.         end
  2333.  
  2334.         self.OkButton:Draw()
  2335.         if self.CancelButton then
  2336.             self.CancelButton:Draw()
  2337.         end
  2338.     end,
  2339.  
  2340.     Initialise = function(self, title, message, okText, cancelText, returnFunc)
  2341.         local new = {}    -- the new instance
  2342.         setmetatable( new, {__index = self} )
  2343.         new.Width = 28
  2344.         new.Lines = WrapText(message, new.Width - 2)
  2345.         new.Height = 5 + #new.Lines
  2346.         new.Return = returnFunc
  2347.         new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  2348.         new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  2349.         new.Title = title
  2350.         new.Visible = true
  2351.         new.Visible = true
  2352.         new.OkButton = Button:Initialise(new.Width - #okText - 2, new.Height - 1, nil, 1, nil, new, function()
  2353.             returnFunc(new, true)
  2354.         end, okText)
  2355.         if cancelText then
  2356.             new.CancelButton = Button:Initialise(new.Width - #okText - 2 - 1 - #cancelText - 2, new.Height - 1, nil, 1, nil, new, function()
  2357.                 returnFunc(new, false)
  2358.             end, cancelText)
  2359.         end
  2360.  
  2361.         return new
  2362.     end,
  2363.  
  2364.     Show = function(self)
  2365.         Current.Window = self
  2366.         return self
  2367.     end,
  2368.  
  2369.     Close = function(self)
  2370.         Current.Window = nil
  2371.         self = nil
  2372.     end,
  2373.  
  2374.     Flash = function(self)
  2375.         self.Visible = false
  2376.         Draw()
  2377.         sleep(0.15)
  2378.         self.Visible = true
  2379.         Draw()
  2380.         sleep(0.15)
  2381.         self.Visible = false
  2382.         Draw()
  2383.         sleep(0.15)
  2384.         self.Visible = true
  2385.         Draw()
  2386.     end,
  2387.  
  2388.     Click = function(self, side, x, y)
  2389.         local items = {self.OkButton, self.CancelButton}
  2390.         local found = false
  2391.         for i, v in ipairs(items) do
  2392.             if CheckClick(v, x, y) then
  2393.                 v:Click(side, x, y)
  2394.                 found = true
  2395.             end
  2396.         end
  2397.         return true
  2398.     end
  2399. }
  2400.  
  2401. TextDialougeWindow = {
  2402.     X = 1,
  2403.     Y = 1,
  2404.     Width = 0,
  2405.     Height = 0,
  2406.     CursorPos = 1,
  2407.     Visible = true,
  2408.     CancelButton = nil,
  2409.     OkButton = nil,
  2410.     Lines = {},
  2411.     TextInput = nil,
  2412.  
  2413.     AbsolutePosition = function(self)
  2414.         return {X = self.X, Y = self.Y}
  2415.     end,
  2416.  
  2417.     Draw = function(self)
  2418.         if not self.Visible then
  2419.             return
  2420.         end
  2421.         Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  2422.         Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  2423.         Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  2424.         Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  2425.  
  2426.         for i, text in ipairs(self.Lines) do
  2427.             Drawing.DrawCharacters(self.X + 1, self.Y + 1 + i, text, colours.black, colours.white)
  2428.         end
  2429.  
  2430.  
  2431.         Drawing.DrawBlankArea(self.X + 1, self.Y + self.Height - 4, self.Width - 2, 1, colours.lightGrey)
  2432.         Drawing.DrawCharacters(self.X + 2, self.Y + self.Height - 4, self.TextInput.Value, colours.black, colours.lightGrey)
  2433.         Current.CursorPos = {self.X + 2 + self.TextInput.CursorPos, self.Y + self.Height - 4}
  2434.         Current.CursorColour = colours.black
  2435.  
  2436.         self.OkButton:Draw()
  2437.         if self.CancelButton then
  2438.             self.CancelButton:Draw()
  2439.         end
  2440.     end,
  2441.  
  2442.     Initialise = function(self, title, message, okText, cancelText, returnFunc, numerical)
  2443.         local new = {}    -- the new instance
  2444.         setmetatable( new, {__index = self} )
  2445.         new.Width = 28
  2446.         new.Lines = WrapText(message, new.Width - 2)
  2447.         new.Height = 7 + #new.Lines
  2448.         new.Return = returnFunc
  2449.         new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  2450.         new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  2451.         new.Title = title
  2452.         new.Visible = true
  2453.         new.Visible = true
  2454.         new.OkButton = Button:Initialise(new.Width - #okText - 2, new.Height - 1, nil, 1, nil, new, function()
  2455.             if #new.TextInput.Value > 0 then
  2456.                 returnFunc(new, true, new.TextInput.Value)
  2457.             end
  2458.         end, okText)
  2459.         if cancelText then
  2460.             new.CancelButton = Button:Initialise(new.Width - #okText - 2 - 1 - #cancelText - 2, new.Height - 1, nil, 1, nil, new, function()
  2461.                 returnFunc(new, false)
  2462.             end, cancelText)
  2463.         end
  2464.         new.TextInput = TextInput:Initialise('', function(enter)
  2465.             if enter then
  2466.                 new.OkButton:Click()
  2467.             end
  2468.             Draw()
  2469.         end, numerical)
  2470.  
  2471.         Current.Input = new.TextInput
  2472.  
  2473.         return new
  2474.     end,
  2475.  
  2476.     Show = function(self)
  2477.         Current.Window = self
  2478.         return self
  2479.     end,
  2480.  
  2481.     Close = function(self)
  2482.         Current.Window = nil
  2483.         Current.Input = nil
  2484.         self = nil
  2485.     end,
  2486.  
  2487.     Flash = function(self)
  2488.         self.Visible = false
  2489.         Draw()
  2490.         sleep(0.15)
  2491.         self.Visible = true
  2492.         Draw()
  2493.         sleep(0.15)
  2494.         self.Visible = false
  2495.         Draw()
  2496.         sleep(0.15)
  2497.         self.Visible = true
  2498.         Draw()
  2499.     end,
  2500.  
  2501.     Click = function(self, side, x, y)
  2502.         local items = {self.OkButton, self.CancelButton}
  2503.         local found = false
  2504.         for i, v in ipairs(items) do
  2505.             if CheckClick(v, x, y) then
  2506.                 v:Click(side, x, y)
  2507.                 found = true
  2508.             end
  2509.         end
  2510.         return true
  2511.     end
  2512. }
  2513.  
  2514. ResizeDocumentWindow = {
  2515.     X = 1,
  2516.     Y = 1,
  2517.     Width = 0,
  2518.     Height = 0,
  2519.     CursorPos = 1,
  2520.     Visible = true,
  2521.     Return = nil,
  2522.     OkButton = nil,
  2523.     AnchorPosition = 5,
  2524.     WidthLabelHighlight = false,
  2525.     HeightLabelHighlight = false,
  2526.  
  2527.     AbsolutePosition = function(self)
  2528.         return {X = self.X, Y = self.Y}
  2529.     end,
  2530.  
  2531.     Draw = function(self)
  2532.         if not self.Visible then
  2533.             return
  2534.         end
  2535.         Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey)
  2536.         Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey)
  2537.         Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white)
  2538.         Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey)
  2539.  
  2540.         Drawing.DrawCharacters(self.X+1, self.Y+2, "New Size", colours.lightGrey, colours.white)
  2541.         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
  2542.             Drawing.DrawCharacters(self.X+1, self.Y+8, "Clipping will occur!", colours.red, colours.white)
  2543.         end
  2544.  
  2545.         local widthLabelColour = colours.black
  2546.         if self.WidthLabelHighlight then
  2547.             widthLabelColour = colours.red
  2548.         end
  2549.        
  2550.         local heightLabelColour = colours.black
  2551.         if self.HeightLabelHighlight then
  2552.             heightLabelColour = colours.red
  2553.         end
  2554.  
  2555.         Drawing.DrawCharacters(self.X+1, self.Y+4, "Width", widthLabelColour, colours.white)
  2556.         Drawing.DrawCharacters(self.X+1, self.Y+6, "Height", heightLabelColour, colours.white)
  2557.  
  2558.         Drawing.DrawCharacters(self.X+14, self.Y+2, "Anchor", colours.lightGrey, colours.white)
  2559.  
  2560.         self.WidthTextBox:Draw()
  2561.         self.HeightTextBox:Draw()
  2562.         self.OkButton:Draw()
  2563.         self.Anchor1:Draw()
  2564.         self.Anchor2:Draw()
  2565.         self.Anchor3:Draw()
  2566.         self.Anchor4:Draw()
  2567.         self.Anchor5:Draw()
  2568.         self.Anchor6:Draw()
  2569.         self.Anchor7:Draw()
  2570.         self.Anchor8:Draw()
  2571.         self.Anchor9:Draw()
  2572.     end,   
  2573.  
  2574.     Initialise = function(self, returnFunc)
  2575.         local new = {}    -- the new instance
  2576.         setmetatable( new, {__index = self} )
  2577.         new.Width = 27
  2578.         new.Height = 10
  2579.         new.Return = returnFunc
  2580.         new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2)
  2581.         new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2)
  2582.         new.Title = 'Resize Document'
  2583.         new.Visible = true
  2584.  
  2585.         new.WidthTextBox = TextBox:Initialise(9, 5, 4, 1, new, tostring(Current.Artboard.Width), nil, nil, function()
  2586.             new:UpdateAnchorButtons()
  2587.         end, true)
  2588.         new.HeightTextBox = TextBox:Initialise(9, 7, 4, 1, new, tostring(Current.Artboard.Height), nil, nil, function()
  2589.             new:UpdateAnchorButtons()
  2590.         end, true)
  2591.         new.OkButton = Button:Initialise(new.Width - 4, new.Height - 1, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle)
  2592.             local ok = true
  2593.             new.WidthLabelHighlight = false
  2594.             new.HeightLabelHighlight = false
  2595.  
  2596.             if #new.WidthTextBox.TextInput.Value == 0 or tonumber(new.WidthTextBox.TextInput.Value) <= 0 then
  2597.                 ok = false
  2598.                 new.WidthLabelHighlight = true
  2599.             end
  2600.  
  2601.             if #new.HeightTextBox.TextInput.Value == 0 or tonumber(new.HeightTextBox.TextInput.Value) <= 0 then
  2602.                 ok = false
  2603.                 new.HeightLabelHighlight = true
  2604.             end
  2605.  
  2606.             if ok then
  2607.                 returnFunc(new, tonumber(new.WidthTextBox.TextInput.Value), tonumber(new.HeightTextBox.TextInput.Value), new.AnchorPosition)
  2608.             else
  2609.                 Draw()
  2610.             end
  2611.         end, 'Ok', colours.black)
  2612.  
  2613.         local anchorX = 15
  2614.         local anchorY = 5
  2615.         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)
  2616.         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)
  2617.         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)
  2618.         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)
  2619.         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)
  2620.         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)
  2621.         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)
  2622.         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)
  2623.         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)
  2624.  
  2625.         return new
  2626.     end,
  2627.  
  2628.     UpdateAnchorButtons = function(self)
  2629.         local anchor1 = ' '
  2630.         local anchor2 = ' '
  2631.         local anchor3 = ' '
  2632.         local anchor4 = ' '
  2633.         local anchor5 = ' '
  2634.         local anchor6 = ' '
  2635.         local anchor7 = ' '
  2636.         local anchor8 = ' '
  2637.         local anchor9 = ' '
  2638.         self.AnchorPosition = self.AnchorPosition or 5
  2639.         if self.AnchorPosition == 1 then
  2640.             anchor1 = '#'
  2641.             anchor2 = '>'
  2642.             anchor4 = 'v'
  2643.         elseif self.AnchorPosition == 2 then
  2644.             anchor1 = '<'
  2645.             anchor2 = '#'
  2646.             anchor3 = '>'
  2647.             anchor5 = 'v'
  2648.         elseif self.AnchorPosition == 3 then
  2649.             anchor2 = '<'
  2650.             anchor3 = '#'
  2651.             anchor6 = 'v'
  2652.         elseif self.AnchorPosition == 4 then
  2653.             anchor1 = '^'
  2654.             anchor4 = '#'
  2655.             anchor5 = '>'
  2656.             anchor7 = 'v'
  2657.         elseif self.AnchorPosition == 5 then
  2658.             anchor2 = '^'
  2659.             anchor4 = '<'
  2660.             anchor5 = '#'
  2661.             anchor6 = '>'
  2662.             anchor8 = 'v'
  2663.         elseif self.AnchorPosition == 6 then
  2664.             anchor3 = '^'
  2665.             anchor6 = '#'
  2666.             anchor5 = '<'
  2667.             anchor9 = 'v'
  2668.         elseif self.AnchorPosition == 7 then
  2669.             anchor4 = '^'
  2670.             anchor7 = '#'
  2671.             anchor8 = '>'
  2672.         elseif self.AnchorPosition == 8 then
  2673.             anchor5 = '^'
  2674.             anchor8 = '#'
  2675.             anchor7 = '<'
  2676.             anchor9 = '>'
  2677.         elseif self.AnchorPosition == 9 then
  2678.             anchor6 = '^'
  2679.             anchor9 = '#'
  2680.             anchor8 = '<'
  2681.         end
  2682.  
  2683.         if #self.HeightTextBox.TextInput.Value > 0 and Current.Artboard.Height > tonumber(self.HeightTextBox.TextInput.Value) then
  2684.             local r = function(str)
  2685.                 if string.find(str, "%^") then
  2686.                     str = str:gsub('%^','v')
  2687.                 elseif string.find(str, "v") then
  2688.                     str = str:gsub('v','%^')
  2689.                 end
  2690.                 return str
  2691.             end
  2692.             anchor1 = r(anchor1)
  2693.             anchor2 = r(anchor2)
  2694.             anchor3 = r(anchor3)
  2695.             anchor4 = r(anchor4)
  2696.             anchor5 = r(anchor5)
  2697.             anchor6 = r(anchor6)
  2698.             anchor7 = r(anchor7)
  2699.             anchor8 = r(anchor8)
  2700.             anchor9 = r(anchor9)
  2701.         end
  2702.  
  2703.         if #self.WidthTextBox.TextInput.Value > 0 and Current.Artboard.Width > tonumber(self.WidthTextBox.TextInput.Value) then
  2704.             local r = function(str)
  2705.                 if string.find(str, ">") then
  2706.                     str = str:gsub('>','<')
  2707.                 elseif string.find(str, "<") then
  2708.                     str = str:gsub('<','>')
  2709.                 end
  2710.                 return str
  2711.             end
  2712.             anchor1 = r(anchor1)
  2713.             anchor2 = r(anchor2)
  2714.             anchor3 = r(anchor3)
  2715.             anchor4 = r(anchor4)
  2716.             anchor5 = r(anchor5)
  2717.             anchor6 = r(anchor6)
  2718.             anchor7 = r(anchor7)
  2719.             anchor8 = r(anchor8)
  2720.             anchor9 = r(anchor9)
  2721.         end
  2722.  
  2723.         self.Anchor1.Text = anchor1
  2724.         self.Anchor2.Text = anchor2
  2725.         self.Anchor3.Text = anchor3
  2726.         self.Anchor4.Text = anchor4
  2727.         self.Anchor5.Text = anchor5
  2728.         self.Anchor6.Text = anchor6
  2729.         self.Anchor7.Text = anchor7
  2730.         self.Anchor8.Text = anchor8
  2731.         self.Anchor9.Text = anchor9
  2732.     end,
  2733.  
  2734.     Show = function(self)
  2735.         Current.Window = self
  2736.         return self
  2737.     end,
  2738.  
  2739.     Close = function(self)
  2740.         Current.Input = nil
  2741.         Current.Window = nil
  2742.         self = nil
  2743.     end,
  2744.  
  2745.     Flash = function(self)
  2746.         self.Visible = false
  2747.         Draw()
  2748.         sleep(0.15)
  2749.         self.Visible = true
  2750.         Draw()
  2751.         sleep(0.15)
  2752.         self.Visible = false
  2753.         Draw()
  2754.         sleep(0.15)
  2755.         self.Visible = true
  2756.         Draw()
  2757.     end,
  2758.  
  2759.     ButtonClick = function(self, button, x, y)
  2760.         if button.X <= x and button.Y <= y and button.X + button.Width > x and button.Y + button.Height > y then
  2761.             button:Click()
  2762.         end
  2763.     end,
  2764.  
  2765.     Click = function(self, side, x, y)
  2766.         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}
  2767.         for i, v in ipairs(items) do
  2768.             if CheckClick(v, x, y) then
  2769.                 v:Click(side, x, y)
  2770.             end
  2771.         end
  2772.         return true
  2773.     end
  2774. }
  2775.  
  2776. ----------------------
  2777.  
  2778. function CheckOpenArtboard()
  2779.     if Current.Artboard then
  2780.         return true
  2781.     else
  2782.         return false
  2783.     end
  2784. end
  2785.  
  2786. function CheckSelectedLayer()
  2787.     if Current.Artboard and Current.Layer then
  2788.         return true
  2789.     else
  2790.         return false
  2791.     end
  2792. end
  2793.  
  2794. function DisplayNewDocumentWindow()
  2795.     NewDocumentWindow:Initialise(function(self, success, path, width, height, format, backgroundColour)
  2796.         if success then
  2797.             if path:sub(-4) ~= format then
  2798.                 path = path .. format
  2799.             end
  2800.             local oldWindow = self
  2801.             Current.Input = nil
  2802.             Current.Window = nil
  2803.             makeDocument = function()oldWindow:Close()NewDocument(path, width, height, format, backgroundColour)end
  2804.             local _fs = fs
  2805.             if OneOS then
  2806.                 _fs = OneOS.FS
  2807.             end
  2808.             if _fs.exists(path) then
  2809.                 ButtonDialougeWindow:Initialise('File Exists', path..' already exists! Use a different name and try again.', 'Ok', nil, function(window, ok)
  2810.                     window:Close()
  2811.                     oldWindow:Show()
  2812.                 end):Show()
  2813.             elseif format == '.nfp' then
  2814.                 Current.Window = nil
  2815.                 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)
  2816.                     window:Close()
  2817.                     if ok then
  2818.                         makeDocument()
  2819.                     else
  2820.                         oldWindow:Show()
  2821.                     end
  2822.                 end):Show()
  2823.             elseif format == '.nft' then
  2824.                 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)
  2825.                     window:Close()
  2826.                     if ok then
  2827.                         makeDocument()
  2828.                     else
  2829.                         oldWindow:Show()
  2830.                     end
  2831.                 end):Show()
  2832.             else
  2833.                 makeDocument()
  2834.             end
  2835.  
  2836.            
  2837.         else
  2838.             self:Close()
  2839.         end
  2840.     end):Show()
  2841. end
  2842.  
  2843. function NewDocument(path, width, height, format, backgroundColour)
  2844.     local _fs = fs
  2845.     if OneOS then
  2846.         _fs = OneOS.FS
  2847.     end
  2848.     ab = Artboard:New(_fs.getName(path), path, width, height, format, backgroundColour)
  2849.     Current.Tool = Tools[2]
  2850.     Current.Toolbar:Update()
  2851.     Current.Modified = false
  2852.     Draw()
  2853. end
  2854.  
  2855. function DisplayToolSizeWindow()
  2856.     if not CheckOpenArtboard() then
  2857.         return
  2858.     end
  2859.     TextDialougeWindow:Initialise('Change Tool Size', 'Enter the new tool size you\'d like to use.', 'Ok', 'Cancel', function(window, success, value)
  2860.         if success then
  2861.             Current.ToolSize = math.ceil(tonumber(value))
  2862.             if Current.ToolSize < 1 then
  2863.                 Current.ToolSize = 1
  2864.             elseif Current.ToolSize > 50 then
  2865.                 Current.ToolSize = 50
  2866.             end
  2867.             ModuleNamed('Tools'):Update()
  2868.         end
  2869.         window:Close()
  2870.     end, true):Show()  
  2871. end
  2872.  
  2873. --[[
  2874.     Attempt to figure out what format the image is if it doesn't have an extension
  2875. ]]--
  2876. function GetFormat(path)
  2877.     local _fs = fs
  2878.     if OneOS then
  2879.         _fs = OneOS.FS
  2880.     end
  2881.     local file = _fs.open(path, 'r')
  2882.     local content = file.readAll()
  2883.     file.close()
  2884.     if type(textutils.unserialize(content)) == 'table' then
  2885.         -- It's a serlized table, asume sketch
  2886.         return '.skch'
  2887.     elseif string.find(content, string.char(30)) or string.find(content, string.char(31)) then
  2888.         -- Contains the characters that set colours, asume nft
  2889.         return '.nft'
  2890.     else
  2891.         -- Otherwise asume nfp
  2892.         return '.nfp'
  2893.     end
  2894. end
  2895.  
  2896. function DisplayOpenDocumentWindow()
  2897.     OpenDocumentWindow:Initialise(function(self, success, path)
  2898.         self:Close()
  2899.         if success then
  2900.             OpenDocument(path)
  2901.         end
  2902.     end):Show()
  2903. end
  2904.  
  2905.  
  2906. local function Extension(path, addDot)
  2907.     if not path then
  2908.         return nil
  2909.     elseif not string.find(fs.getName(path), '%.') then
  2910.         if not addDot then
  2911.             return fs.getName(path)
  2912.         else
  2913.             return ''
  2914.         end
  2915.     else
  2916.         local _path = path
  2917.         if path:sub(#path) == '/' then
  2918.             _path = path:sub(1,#path-1)
  2919.         end
  2920.         local extension = _path:gmatch('\.[0-9a-z]+$')()
  2921.         if extension then
  2922.             extension = extension:sub(2)
  2923.         else
  2924.             --extension = nil
  2925.             return ''
  2926.         end
  2927.         if addDot then
  2928.             extension = '.'..extension
  2929.         end
  2930.         return extension:lower()
  2931.     end
  2932. end
  2933.  
  2934. local RemoveExtension = function(path)
  2935.     if path:sub(1,1) == '.' then
  2936.         return path
  2937.     end
  2938.     local extension = Extension(path)
  2939.     if extension == path then
  2940.         return fs.getName(path)
  2941.     end
  2942.     return string.gsub(path, extension, ''):sub(1, -2)
  2943. end
  2944. --[[
  2945.     Open a documet at a given path
  2946. ]]--
  2947. function OpenDocument(path)
  2948.     local _fs = fs
  2949.     if OneOS then
  2950.         _fs = OneOS.FS
  2951.     end
  2952.     if _fs.exists(path) and not _fs.isDir(path) then
  2953.         local format = Extension(path, true)
  2954.         if (not format or format == '') and (format ~= '.nfp' and format ~= '.nft' and format ~= '.skch') then
  2955.             format = GetFormat(path)
  2956.         end
  2957.         local layers = {}
  2958.         if format == '.nfp' then
  2959.             layers = ReadNFP(path)
  2960.         elseif format == '.nft' then
  2961.             layers = ReadNFT(path)     
  2962.         elseif format == '.skch' then
  2963.             layers = ReadSKCH(path)
  2964.         end
  2965.  
  2966.         for i, layer in ipairs(layers) do
  2967.             if layer.Visible == nil then
  2968.                 layer.Visible = true
  2969.             end
  2970.             if layer.Index == nil then
  2971.                 layer.Index = 1
  2972.             end
  2973.             if layer.Name == nil then
  2974.                 if layer.Index == 1 then
  2975.                     layer.Name = 'Background'
  2976.                 else
  2977.                     layer.Name = 'Layer'
  2978.                 end
  2979.             end
  2980.             if layer.BackgroundColour == nil then
  2981.                 layer.BackgroundColour = colours.white
  2982.             end
  2983.         end
  2984.  
  2985.         if not layers[1] then
  2986.             --log('File could not be read.')
  2987.             return
  2988.         end
  2989.  
  2990.         local width = #layers[1].Pixels
  2991.         local height = #layers[1].Pixels[1]
  2992.  
  2993.         Current.Artboard = nil
  2994.         local _fs = fs
  2995.         if OneOS then
  2996.             _fs = OneOS.FS
  2997.         end
  2998.         ab = Artboard:New(_fs.getName('Image'), path, width, height, format, nil, layers)
  2999.         Current.Tool = Tools[2]
  3000.         Current.Toolbar:Update()
  3001.         Current.Modified = false
  3002.         Draw()
  3003.     end
  3004. end
  3005.  
  3006. function MakeNewLayer()
  3007.     if not CheckOpenArtboard() then
  3008.         return
  3009.     end
  3010.     if Current.Artboard.Format == '.skch' then
  3011.         TextDialougeWindow:Initialise('New Layer Name', 'Enter the name you want for the next layer.', 'Ok', 'Cancel', function(window, success, value)
  3012.             if success then
  3013.                 Current.Artboard:MakeLayer(value, colours.transparent)
  3014.             end
  3015.             window:Close()
  3016.         end):Show()
  3017.     else
  3018.         local format = 'NFP'
  3019.         if Current.Artboard.Format == '.nft' then
  3020.             format = 'NFT'
  3021.         end
  3022.         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)
  3023.             window:Close()
  3024.         end):Show()
  3025.     end
  3026. end
  3027.  
  3028. function ResizeDocument()
  3029.     if not CheckOpenArtboard() then
  3030.         return
  3031.     end
  3032.     ResizeDocumentWindow:Initialise(function(window, width, height, anchor)
  3033.         window:Close()
  3034.         local topResize = 0
  3035.         local rightResize = 0
  3036.         local bottomResize = 0
  3037.         local leftResize = 0
  3038.  
  3039.         if anchor == 1 then
  3040.             rightResize = 1
  3041.             bottomResize = 1
  3042.         elseif anchor == 2 then
  3043.             rightResize = 0.5
  3044.             leftResize = 0.5
  3045.             bottomResize = 1
  3046.         elseif anchor == 3 then
  3047.             leftResize = 1
  3048.             bottomResize = 1
  3049.         elseif anchor == 4 then
  3050.             rightResize = 1
  3051.             bottomResize = 0.5
  3052.             topResize = 0.5
  3053.         elseif anchor == 5 then
  3054.             rightResize = 0.5
  3055.             leftResize = 0.5
  3056.             bottomResize = 0.5
  3057.             topResize = 0.5
  3058.         elseif anchor == 6 then
  3059.             leftResize = 1
  3060.             bottomResize = 0.5
  3061.             topResize = 0.5
  3062.         elseif anchor == 7 then
  3063.             rightResize = 1
  3064.             topResize = 1
  3065.         elseif anchor == 8 then
  3066.             rightResize = 0.5
  3067.             leftResize = 0.5
  3068.             topResize = 1
  3069.         elseif anchor == 9 then
  3070.             leftResize = 1
  3071.             topResize = 1
  3072.         end
  3073.  
  3074.         topResize = topResize * (height - Current.Artboard.Height)
  3075.         if topResize > 0 then
  3076.             topResize = math.floor(topResize)
  3077.         else
  3078.             topResize = math.ceil(topResize)
  3079.         end
  3080.  
  3081.         bottomResize = bottomResize * (height - Current.Artboard.Height)
  3082.         if bottomResize > 0 then
  3083.             bottomResize = math.ceil(bottomResize)
  3084.         else
  3085.             bottomResize = math.floor(bottomResize)
  3086.         end
  3087.  
  3088.         leftResize = leftResize * (width - Current.Artboard.Width)
  3089.         if leftResize > 0 then
  3090.             leftResize = math.floor(leftResize)
  3091.         else
  3092.             leftResize = math.ceil(leftResize)
  3093.         end
  3094.  
  3095.         rightResize = rightResize * (width - Current.Artboard.Width)
  3096.         if rightResize > 0 then
  3097.             rightResize = math.ceil(rightResize)
  3098.         else
  3099.             rightResize = math.floor(rightResize)
  3100.         end
  3101.  
  3102.         Current.Artboard:Resize(topResize, bottomResize, leftResize, rightResize)
  3103.     end):Show()
  3104. end
  3105.  
  3106. function RenameLayer()
  3107.     if not CheckOpenArtboard() then
  3108.         return
  3109.     end
  3110.     if Current.Artboard.Format == '.skch' then
  3111.         TextDialougeWindow:Initialise("Rename Layer '"..Current.Layer.Name.."'", 'Enter the new name you want the layer to be called.', 'Ok', 'Cancel', function(window, success, value)
  3112.             if success then
  3113.                 Current.Layer.Name = value
  3114.             end
  3115.             window:Close()
  3116.         end):Show()
  3117.     else
  3118.         local format = 'NFP'
  3119.         if Current.Artboard.Format == '.nft' then
  3120.             format = 'NFT'
  3121.         end
  3122.         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)
  3123.             window:Close()
  3124.         end):Show()
  3125.     end
  3126. end
  3127.  
  3128. function DeleteLayer()
  3129.     if not CheckOpenArtboard() then
  3130.         return
  3131.     end
  3132.     if Current.Artboard.Format == '.skch' then
  3133.         if #Current.Artboard.Layers > 1 then
  3134.             ButtonDialougeWindow:Initialise("Delete Layer '"..Current.Layer.Name.."'?", 'Are you sure you want delete the layer?', 'Ok', 'Cancel', function(window, success)
  3135.                 if success then
  3136.                     Current.Layer:Remove()
  3137.                 end
  3138.                 window:Close()
  3139.             end):Show()
  3140.         else
  3141.             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)
  3142.                 window:Close()
  3143.             end):Show()
  3144.         end
  3145.     else
  3146.         local format = 'NFP'
  3147.         if Current.Artboard.Format == '.nft' then
  3148.             format = 'NFT'
  3149.         end
  3150.         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)
  3151.             window:Close()
  3152.         end):Show()
  3153.     end
  3154. end
  3155.  
  3156. needsDraw = false
  3157. isDrawing = false
  3158. function Draw()
  3159.     if isDrawing then
  3160.         needsDraw = true
  3161.         return
  3162.     end
  3163.     needsDraw = false
  3164.     isDrawing = true
  3165.     if not Current.Window then
  3166.         Drawing.Clear(UIColours.Background)
  3167.     else
  3168.         Drawing.DrawArea(1, 2, Drawing.Screen.Width, Drawing.Screen.Height, '|', colours.black, colours.lightGrey)
  3169.     end
  3170.  
  3171.     if Current.Artboard then
  3172.         ab:Draw()
  3173.     end
  3174.  
  3175.     if Current.InterfaceVisible then
  3176.         Current.MenuBar:Draw()
  3177.         Current.Toolbar.Width = Current.Toolbar.ExpandedWidth
  3178.         Current.Toolbar:Draw()
  3179.     else
  3180.         Current.Toolbar.Width = Current.Toolbar.ExpandedWidth
  3181.     end
  3182.  
  3183.     if Current.InterfaceVisible and Current.Menu then
  3184.         Current.Menu:Draw()
  3185.     end
  3186.  
  3187.     if Current.Window then
  3188.         Current.Window:Draw()
  3189.     end
  3190.  
  3191.     if not Current.InterfaceVisible then
  3192.         ShowInterfaceButton:Draw()
  3193.     end
  3194.  
  3195.     Drawing.DrawBuffer()
  3196.     if Current.Input and not Current.Menu then
  3197.         term.setCursorPos(Current.CursorPos[1], Current.CursorPos[2])
  3198.         term.setCursorBlink(true)
  3199.         term.setTextColour(Current.CursorColour)
  3200.     else
  3201.         term.setCursorBlink(false)
  3202.     end
  3203.  
  3204.     if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  3205.         Current.SelectionDrawTimer = os.startTimer(0.5)
  3206.     end
  3207.     isDrawing = false
  3208.     if needsDraw then
  3209.         Draw()
  3210.     end
  3211. end
  3212.  
  3213. function LoadMenuBar()
  3214.     Current.MenuBar = MenuBar:Initialise({
  3215.         Button:Initialise(1, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  3216.             if toggle then
  3217.                 Menu:New(1, 2, {
  3218.                     {
  3219.                         Title = "New...",
  3220.                         Click = function()
  3221.                             DisplayNewDocumentWindow()
  3222.                         end,
  3223.                         Keys = {
  3224.                             keys.leftCtrl,
  3225.                             keys.n
  3226.                         }
  3227.                     },
  3228.                     {
  3229.                         Title = 'Open...',
  3230.                         Click = function()
  3231.                             DisplayOpenDocumentWindow()
  3232.                         end,
  3233.                         Keys = {
  3234.                             keys.leftCtrl,
  3235.                             keys.o
  3236.                         }
  3237.                     },
  3238.                     {
  3239.                         Separator = true
  3240.                     },
  3241.                     {
  3242.                         Title = 'Save...',
  3243.                         Click = function()
  3244.                             Current.Artboard:Save()
  3245.                         end,
  3246.                         Keys = {
  3247.                             keys.leftCtrl,
  3248.                             keys.s
  3249.                         },
  3250.                         Enabled = function()
  3251.                             return CheckOpenArtboard()
  3252.                         end
  3253.                     },
  3254.                     {
  3255.                         Separator = true
  3256.                     },
  3257.                     {
  3258.                         Title = 'Quit',
  3259.                         Click = function()
  3260.                             if Close() then
  3261.                                 OneOS.Close()
  3262.                             end
  3263.                         end
  3264.                     },
  3265.             --[[
  3266.                     {
  3267.                         Title = 'Save As...',
  3268.                         Click = function()
  3269.  
  3270.                         end
  3271.                     }  
  3272.             ]]--
  3273.                 }, self, true)
  3274.             else
  3275.                 Current.Menu = nil
  3276.             end
  3277.             return true
  3278.         end, 'File', colours.lightGrey, false),
  3279.         Button:Initialise(7, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  3280.             if not self.Toggle then
  3281.                 Menu:New(7, 2, {
  3282.             --[[
  3283.                     {
  3284.                         Title = "Undo",
  3285.                         Click = function()
  3286.                         end,
  3287.                         Keys = {
  3288.                             keys.leftCtrl,
  3289.                             keys.z
  3290.                         },
  3291.                         Enabled = function()
  3292.                             return false
  3293.                         end
  3294.                     },
  3295.                     {
  3296.                         Title = 'Redo',
  3297.                         Click = function()
  3298.                            
  3299.                         end,
  3300.                         Keys = {
  3301.                             keys.leftCtrl,
  3302.                             keys.y
  3303.                         },
  3304.                         Enabled = function()
  3305.                             return false
  3306.                         end
  3307.                     },
  3308.                     {
  3309.                         Separator = true
  3310.                     },
  3311.             ]]--
  3312.                     {
  3313.                         Title = 'Cut',
  3314.                         Click = function()
  3315.                             Clipboard.Cut(Current.Layer:PixelsInSelection(true), 'sketchpixels')
  3316.                         end,
  3317.                         Keys = {
  3318.                             keys.leftCtrl,
  3319.                             keys.x
  3320.                         },
  3321.                         Enabled = function()
  3322.                             return Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil
  3323.                         end
  3324.                     },
  3325.                     {
  3326.                         Title = 'Copy',
  3327.                         Click = function()
  3328.                             Clipboard.Copy(Current.Layer:PixelsInSelection(), 'sketchpixels')
  3329.                         end,
  3330.                         Keys = {
  3331.                             keys.leftCtrl,
  3332.                             keys.c
  3333.                         },
  3334.                         Enabled = function()
  3335.                             return Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil
  3336.                         end
  3337.                     },
  3338.                     {
  3339.                         Title = 'Paste',
  3340.                         Click = function()
  3341.                             Current.Layer:InsertPixels(Clipboard.Paste())
  3342.                         end,
  3343.                         Keys = {
  3344.                             keys.leftCtrl,
  3345.                             keys.v
  3346.                         },
  3347.                         Enabled = function()
  3348.                             return (not Clipboard.isEmpty()) and Clipboard.Type == 'sketchpixels'
  3349.                         end
  3350.                     }
  3351.                 }, self, true)
  3352.             else
  3353.                 Current.Menu = nil
  3354.             end
  3355.             return true
  3356.         end, 'Edit', colours.lightGrey, false),
  3357.         Button:Initialise(13, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  3358.             if toggle then
  3359.                 Menu:New(13, 2, {
  3360.                     {
  3361.                         Title = "Resize...",
  3362.                         Click = function()
  3363.                             ResizeDocument()
  3364.                         end,
  3365.                         Keys = {
  3366.                             keys.leftCtrl,
  3367.                             keys.r
  3368.                         },
  3369.                         Enabled = function()
  3370.                             return CheckOpenArtboard()
  3371.                         end
  3372.                     },
  3373.                     {
  3374.                         Title = "Crop",
  3375.                         Click = function()
  3376.                             local top = 0
  3377.                             local left = 0
  3378.                             local bottom = 0
  3379.                             local right = 0
  3380.                             if Current.Selection[1].x < Current.Selection[2].x then
  3381.                                 left = Current.Selection[1].x - 1
  3382.                                 right = Current.Artboard.Width - Current.Selection[2].x
  3383.                             else
  3384.                                 left = Current.Selection[2].x - 1
  3385.                                 right = Current.Artboard.Width - Current.Selection[1].x
  3386.                             end
  3387.                             if Current.Selection[1].y < Current.Selection[2].y then
  3388.                                 top = Current.Selection[1].y - 1
  3389.                                 bottom = Current.Artboard.Height - Current.Selection[2].y
  3390.                             else
  3391.                                 top = Current.Selection[2].y - 1
  3392.                                 bottom = Current.Artboard.Height - Current.Selection[1].y
  3393.                             end
  3394.                             Current.Artboard:Resize(-1*top, -1*bottom, -1*left, -1*right)
  3395.  
  3396.                             Current.Selection[2] = nil
  3397.                         end,
  3398.                         Enabled = function()
  3399.                             if CheckSelectedLayer() and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  3400.                                 return true
  3401.                             else
  3402.                                 return false
  3403.                             end
  3404.                         end
  3405.                     },
  3406.                     {
  3407.                         Separator = true
  3408.                     },
  3409.                     {
  3410.                         Title = 'New Layer...',
  3411.                         Click = function()
  3412.                             MakeNewLayer()
  3413.                         end,
  3414.                         Keys = {
  3415.                             keys.leftCtrl,
  3416.                             keys.l
  3417.                         },
  3418.                         Enabled = function()
  3419.                             return CheckOpenArtboard()
  3420.                         end
  3421.                     },
  3422.                     {
  3423.                         Title = 'Delete Layer',
  3424.                         Click = function()
  3425.                             DeleteLayer()
  3426.                         end,
  3427.                         Enabled = function()
  3428.                             return CheckSelectedLayer()
  3429.                         end
  3430.                     },
  3431.                     {
  3432.                         Title = 'Rename Layer...',
  3433.                         Click = function()
  3434.                             RenameLayer()
  3435.                         end,
  3436.                         Enabled = function()
  3437.                             return CheckSelectedLayer()
  3438.                         end
  3439.                     },
  3440.                     {
  3441.                         Separator = true
  3442.                     },
  3443.                     {
  3444.                         Title = 'Erase Selection',
  3445.                         Click = function()
  3446.                             Current.Layer:EraseSelection()
  3447.                         end,
  3448.                         Keys = {
  3449.                             keys.delete
  3450.                         },
  3451.                         Enabled = function()
  3452.                             if CheckSelectedLayer() and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then
  3453.                                 return true
  3454.                             else
  3455.                                 return false
  3456.                             end
  3457.                         end
  3458.                     },
  3459.                     {
  3460.                         Separator = true
  3461.                     },
  3462.                     {
  3463.                         Title = 'Hide Interface',
  3464.                         Click = function()
  3465.                             Current.InterfaceVisible = not Current.InterfaceVisible
  3466.                         end,
  3467.                         Keys = {
  3468.                             keys.tab
  3469.                         }
  3470.                     }
  3471.                 }, self, true)
  3472.             else
  3473.                 Current.Menu = nil
  3474.             end
  3475.             return true
  3476.         end, 'Image', colours.lightGrey, false),
  3477.        
  3478.         Button:Initialise(20, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle)
  3479.             if toggle then
  3480.                 local menuItems = {{
  3481.                         Title = "Change Size",
  3482.                         Click = function()
  3483.                             DisplayToolSizeWindow()
  3484.                         end,
  3485.                         Keys = {
  3486.                             keys.leftCtrl,
  3487.                             keys.t
  3488.                         }
  3489.                     },
  3490.                     {
  3491.                         Separator = true
  3492.                     }
  3493.                 }
  3494.                
  3495.                 local _keys = {'h','p','e','f','s','m','t'}
  3496.                 for i, tool in ipairs(Tools) do
  3497.                     table.insert(menuItems, {
  3498.                         Title = tool.Name,
  3499.                         Click = function()
  3500.                             SetTool(tool)
  3501.                             local m = ModuleNamed('Tools')
  3502.                             m:Update(m.ToolbarItem)
  3503.                         end,
  3504.                         Keys = {
  3505.                             keys[_keys[i]]
  3506.                         },
  3507.                         Enabled = function()
  3508.                             return CheckOpenArtboard()
  3509.                         end
  3510.                     })
  3511.                 end
  3512.  
  3513.                 Menu:New(20, 2, menuItems, self, true)
  3514.             else
  3515.                 Current.Menu = nil
  3516.             end
  3517.             return true
  3518.         end, 'Tools', colours.lightGrey, false),
  3519.     })
  3520. end
  3521.  
  3522. function Timer(event, timer)
  3523.     if timer == Current.ControlPressedTimer then
  3524.         Current.ControlPressedTimer = nil
  3525.     elseif timer == Current.SelectionDrawTimer then
  3526.         if Current.Artboard then
  3527.             Current.Artboard.SelectionIsBlack = not Current.Artboard.SelectionIsBlack
  3528.             Draw()
  3529.         end
  3530.     end
  3531. end
  3532.  
  3533. function Initialise(arg)
  3534.     if not OneOS then
  3535.         SplashScreen()
  3536.     end
  3537.     EventRegister('mouse_click', TryClick)
  3538.     EventRegister('mouse_drag', function(event, side, x, y)TryClick(event, side, x, y, true)end)
  3539.     EventRegister('mouse_scroll', Scroll)
  3540.     EventRegister('key', HandleKey)
  3541.     EventRegister('char', HandleKey)
  3542.     EventRegister('timer', Timer)
  3543.     EventRegister('terminate', function(event) if Close() then error( "Terminated", 0 ) end end)
  3544.  
  3545.  
  3546.     Current.Toolbar = Toolbar:New('right', true)
  3547.  
  3548.     for k, v in pairs(Modules) do
  3549.         v:Initialise()
  3550.     end
  3551.    
  3552.     --term.setBackgroundColour(UIColours.Background)
  3553.     --term.clear()
  3554.  
  3555.     LoadMenuBar()
  3556.  
  3557.     local _fs = fs
  3558.     if OneOS then
  3559.         _fs = OneOS.FS
  3560.     end
  3561.     if arg and _fs.exists(arg) then
  3562.         OpenDocument(arg)
  3563.     else
  3564.         DisplayNewDocumentWindow()
  3565.         Current.Window.Visible = false
  3566.     end
  3567.  
  3568.     ShowInterfaceButton = Button:Initialise(Drawing.Screen.Width - 15, 1, nil, 1, colours.grey, nil, function(self)
  3569.         Current.InterfaceVisible = true
  3570.         Draw()
  3571.     end, 'Show Interface')
  3572.  
  3573.     Draw()
  3574.     if Current.Window then
  3575.         Current.Window.Visible = true
  3576.         Draw()
  3577.     end
  3578.  
  3579.     EventHandler()
  3580. end
  3581.  
  3582. function SplashScreen()
  3583.     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,},},}
  3584.     Drawing.Clear(colours.white)
  3585.     Drawing.DrawImage((Drawing.Screen.Width - 14)/2, (Drawing.Screen.Height - 13)/2, splashIcon, 14, 13)
  3586.     Drawing.DrawBuffer()
  3587.     parallel.waitForAny(function()sleep(1)end, function()os.pullEvent('mouse_click')end)
  3588. end
  3589.  
  3590. LongestString = function(input, key)
  3591.     local length = 0
  3592.     for i = 1, #input do
  3593.         local value = input[i]
  3594.         if key then
  3595.             if value[key] then
  3596.                 value = value[key]
  3597.             else
  3598.                 value = ''
  3599.             end
  3600.         end
  3601.         local titleLength = string.len(value)
  3602.         if titleLength > length then
  3603.             length = titleLength
  3604.         end
  3605.     end
  3606.     return length
  3607. end
  3608.  
  3609. function HandleKey(...)
  3610.     local args = {...}
  3611.     local event = args[1]
  3612.     local keychar = args[2]
  3613.     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
  3614.         local currentPos = {Current.CursorPos[1] - Current.Artboard.X + 1, Current.CursorPos[2] - Current.Artboard.Y + 1}
  3615.         if keychar == keys.up then
  3616.             currentPos[2] = currentPos[2] - 1
  3617.         elseif keychar == keys.down then
  3618.             currentPos[2] = currentPos[2] + 1
  3619.         elseif keychar == keys.left then
  3620.             currentPos[1] = currentPos[1] - 1
  3621.         elseif keychar == keys.right then
  3622.             currentPos[1] = currentPos[1] + 1
  3623.         end
  3624.  
  3625.         if currentPos[1] < 1 then
  3626.             currentPos[1] = 1
  3627.         end
  3628.  
  3629.         if currentPos[1] > Current.Artboard.Width then
  3630.             currentPos[1] = Current.Artboard.Width
  3631.         end
  3632.  
  3633.         if currentPos[2] < 1 then
  3634.             currentPos[2] = 1
  3635.         end
  3636.  
  3637.         if currentPos[2] > Current.Artboard.Height then
  3638.             currentPos[2] = Current.Artboard.Height
  3639.         end
  3640.  
  3641.         Current.Tool:Use(currentPos[1], currentPos[2])
  3642.         Current.Modified = true
  3643.         Draw()
  3644.     elseif Current.Input then
  3645.         if event == 'char' then
  3646.             Current.Input:Char(keychar)
  3647.         elseif event == 'key' then
  3648.             Current.Input:Key(keychar)
  3649.         end
  3650.     elseif event == 'key' then
  3651.         CheckKeyboardShortcut(keychar)
  3652.     end
  3653. end
  3654.  
  3655. function Scroll(event, direction, x, y)
  3656.     if Current.Window and Current.Window.OpenButton then
  3657.         Current.Window.Scroll = Current.Window.Scroll + direction
  3658.         if Current.Window.Scroll < 0 then
  3659.             Current.Window.Scroll = 0
  3660.         elseif Current.Window.Scroll > Current.Window.MaxScroll then
  3661.             Current.Window.Scroll = Current.Window.MaxScroll
  3662.         end
  3663.     end
  3664.     Draw()
  3665. end
  3666.  
  3667. function CheckKeyboardShortcut(key)
  3668.     local shortcuts = {}
  3669.  
  3670.     if key == keys.leftCtrl then
  3671.         Current.ControlPressedTimer = os.startTimer(0.5)
  3672.         return
  3673.     end
  3674.     if Current.ControlPressedTimer then
  3675.         shortcuts[keys.n] = function() DisplayNewDocumentWindow() end
  3676.         shortcuts[keys.o] = function() DisplayOpenDocumentWindow() end
  3677.         shortcuts[keys.s] = function() Current.Artboard:Save() end
  3678.         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
  3679.         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
  3680.         shortcuts[keys.v] = function() if (not Clipboard.isEmpty()) and Clipboard.Type == 'sketchpixels' then Current.Layer:InsertPixels(Clipboard.Paste()) end end
  3681.         shortcuts[keys.r] = function() ResizeDocument() end
  3682.         shortcuts[keys.l] = function() MakeNewLayer() end
  3683.     end
  3684.  
  3685.     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
  3686.     shortcuts[keys.backspace] = shortcuts[keys.delete]
  3687.     shortcuts[keys.tab] = function() Current.InterfaceVisible = not Current.InterfaceVisible Draw() end
  3688.  
  3689.     shortcuts[keys.h] = function() SetTool(ToolNamed('Hand')) ModuleNamed('Tools'):Update() Draw() end
  3690.     shortcuts[keys.e] = function() SetTool(ToolNamed('Eraser')) ModuleNamed('Tools'):Update() Draw() end
  3691.     shortcuts[keys.p] = function() SetTool(ToolNamed('Pencil')) ModuleNamed('Tools'):Update() Draw() end
  3692.     shortcuts[keys.f] = function() SetTool(ToolNamed('Fill Bucket')) ModuleNamed('Tools'):Update() Draw() end
  3693.     shortcuts[keys.m] = function() SetTool(ToolNamed('Move')) ModuleNamed('Tools'):Update() Draw() end
  3694.     shortcuts[keys.s] = function() SetTool(ToolNamed('Select')) ModuleNamed('Tools'):Update() Draw() end
  3695.     shortcuts[keys.t] = function() SetTool(ToolNamed('Text')) ModuleNamed('Tools'):Update() Draw() end
  3696.  
  3697.     if shortcuts[key] then
  3698.         shortcuts[key]()
  3699.         return true
  3700.     else
  3701.         return false
  3702.     end
  3703. end
  3704.  
  3705. --[[
  3706.     Check if the given object falls under the click coordinates
  3707. ]]--
  3708. function CheckClick(object, x, y)
  3709.     if object.X <= x and object.Y <= y and object.X + object.Width > x and object.Y + object.Height > y then
  3710.         return true
  3711.     end
  3712. end
  3713.  
  3714. --[[
  3715.     Attempt to clicka given object
  3716. ]]--
  3717. function DoClick(object, side, x, y, drag)
  3718.     if object and CheckClick(object, x, y) then
  3719.         return object:Click(side, x - object.X + 1, y - object.Y + 1, drag)
  3720.     end
  3721. end
  3722.  
  3723. --[[
  3724.     Try to click at the given coordinates
  3725. ]]--
  3726. function TryClick(event, side, x, y, drag)
  3727.     if Current.InterfaceVisible and Current.Menu then
  3728.         if DoClick(Current.Menu, side, x, y, drag) then
  3729.             Draw()
  3730.             return
  3731.         else
  3732.             if Current.Menu.Owner and Current.Menu.Owner.Toggle then
  3733.                 Current.Menu.Owner.Toggle = false
  3734.             end
  3735.             Current.Menu = nil
  3736.             Draw()
  3737.             return
  3738.         end
  3739.     elseif Current.Window then
  3740.         if DoClick(Current.Window, side, x, y, drag) then
  3741.             Draw()
  3742.             return
  3743.         else
  3744.             Current.Window:Flash()
  3745.             return
  3746.         end
  3747.     end
  3748.     local interfaceElements = {}
  3749.  
  3750.     if Current.InterfaceVisible then
  3751.         table.insert(interfaceElements, Current.MenuBar)
  3752.     else
  3753.         table.insert(interfaceElements, ShowInterfaceButton)
  3754.     end
  3755.  
  3756.     for i, v in ipairs(Lists.Interface.Toolbars) do
  3757.         for i, v2 in ipairs(v.ToolbarItems) do
  3758.             table.insert(interfaceElements, v2)
  3759.         end
  3760.         table.insert(interfaceElements, v)
  3761.     end
  3762.  
  3763.     table.insert(interfaceElements, Current.Artboard)
  3764.  
  3765.     for i, object in ipairs(interfaceElements) do
  3766.         if DoClick(object, side, x, y, drag) then
  3767.             Draw()
  3768.             return
  3769.         end    
  3770.     end
  3771.     Draw()
  3772. end
  3773.  
  3774. --[[
  3775.     Registers functions to run on certain events
  3776. ]]--
  3777. function EventRegister(event, func)
  3778.     if not Events[event] then
  3779.         Events[event] = {}
  3780.     end
  3781.  
  3782.     table.insert(Events[event], func)
  3783. end
  3784.  
  3785. --[[
  3786.     The main loop event handler, runs registered event functinos
  3787. ]]--
  3788. function EventHandler()
  3789.     while true do
  3790.         local event, arg1, arg2, arg3, arg4 = os.pullEventRaw()
  3791.         if Events[event] then
  3792.             for i, e in ipairs(Events[event]) do
  3793.                 e(event, arg1, arg2, arg3, arg4)
  3794.             end
  3795.         end
  3796.     end
  3797. end
  3798.  
  3799. --[[
  3800.     Thanks to NitrogenFingers for the colour functions and NFT + NFP read/write functions
  3801. ]]--
  3802.  
  3803. --[[
  3804.     Gets the hex value from a colour
  3805. ]]--
  3806. local hexnums = { [10] = "a", [11] = "b", [12] = "c", [13] = "d", [14] = "e" , [15] = "f" }
  3807. local function getHexOf(colour)
  3808.     if colour == colours.transparent or not colour or not tonumber(colour) then
  3809.             return " "
  3810.     end
  3811.     local value = math.log(colour)/math.log(2)
  3812.     if value > 9 then
  3813.             value = hexnums[value]
  3814.     end
  3815.     return value
  3816. end
  3817.  
  3818. --[[
  3819.     Gets the colour from a hex value
  3820. ]]--
  3821. local function getColourOf(hex)
  3822.     if hex == ' ' then
  3823.         return colours.transparent
  3824.     end
  3825.     local value = tonumber(hex, 16)
  3826.     if not value then return nil end
  3827.     value = math.pow(2,value)
  3828.     return value
  3829. end
  3830.  
  3831. --[[
  3832.     Saves the current artboard in .skch format
  3833. ]]--
  3834. function SaveSKCH()
  3835.     local layers = {}
  3836.     for i, l in ipairs(Current.Artboard.Layers) do
  3837.         local pixels = SaveNFT(i)
  3838.         local layer = {
  3839.             Name = l.Name,
  3840.             Pixels = pixels,
  3841.             BackgroundColour = l.BackgroundColour,
  3842.             Visible = l.Visible,
  3843.             Index = l.Index,
  3844.         }
  3845.         table.insert(layers, layer)
  3846.     end
  3847.     return layers
  3848. end
  3849.  
  3850. --[[
  3851.     Saves the current artboard in .nft format
  3852. ]]--
  3853. function SaveNFT(layer)
  3854.     layer = layer or 1
  3855.     local lines = {}
  3856.     local width = Current.Artboard.Width
  3857.     local height = Current.Artboard.Height
  3858.     for y = 1, height do
  3859.         local line = ''
  3860.         local currentBackgroundColour = nil
  3861.         local currentTextColour = nil
  3862.         for x = 1, width do
  3863.             local pixel = Current.Artboard.Layers[layer].Pixels[x][y]
  3864.             if pixel.BackgroundColour ~= currentBackgroundColour then
  3865.                 line = line..string.char(30)..getHexOf(pixel.BackgroundColour)
  3866.                 currentBackgroundColour = pixel.BackgroundColour
  3867.             end
  3868.             if pixel.TextColour ~= currentTextColour then
  3869.                 line = line..string.char(31)..getHexOf(pixel.TextColour)
  3870.                 currentTextColour = pixel.TextColour
  3871.             end
  3872.             line = line .. pixel.Character
  3873.         end
  3874.         table.insert(lines, line)
  3875.     end
  3876.     return lines
  3877. end
  3878.  
  3879. --[[
  3880.     Saves the current artboard in .nfp format
  3881. ]]--
  3882. function SaveNFP()
  3883.     local lines = {}
  3884.     local width = Current.Artboard.Width
  3885.     local height = Current.Artboard.Height
  3886.     for y = 1, height do
  3887.         local line = ''
  3888.         for x = 1, width do
  3889.             line = line .. getHexOf(Current.Artboard.Layers[1].Pixels[x][y].BackgroundColour)
  3890.         end
  3891.         table.insert(lines, line)
  3892.     end
  3893.     return lines
  3894. end
  3895.  
  3896. --[[
  3897.     Reads a .nfp file from the given path
  3898. ]]--
  3899. function ReadNFP(path)
  3900.     local pixels = {}
  3901.     local _fs = fs
  3902.     if OneOS then
  3903.         _fs = OneOS.FS
  3904.     end
  3905.     local file = _fs.open(path, 'r')
  3906.     local line = file.readLine()
  3907.     local y = 1
  3908.     while line do
  3909.         for x = 1, #line do
  3910.             if not pixels[x] then
  3911.                 pixels[x] = {}
  3912.             end
  3913.             pixels[x][y] = {BackgroundColour = getColourOf(line:sub(x,x))}
  3914.         end
  3915.         y = y + 1
  3916.         line = file.readLine()
  3917.     end
  3918.     file.close()
  3919.     return {{Pixels = pixels}}
  3920. end
  3921.  
  3922. --[[
  3923.     Reads a .nft file from the given path
  3924. ]]--
  3925. function ReadNFT(path)
  3926.     local _fs = fs
  3927.     if OneOS then
  3928.         _fs = OneOS.FS
  3929.     end
  3930.     local file = _fs.open(path, 'r')
  3931.     local line = file.readLine()
  3932.     local lines = {}
  3933.     while line do
  3934.         table.insert(lines, line)
  3935.         line = file.readLine()
  3936.     end
  3937.     file.close()
  3938.     return {{Pixels = ParseNFT(lines)}}
  3939. end
  3940.  
  3941. --[[
  3942.     Converts the lines of an .nft document to readble pixel data
  3943. ]]--
  3944. function ParseNFT(lines)
  3945.     local pixels = {}
  3946.     for y, line in ipairs(lines) do
  3947.         local bgNext, fgNext = false, false
  3948.         local currBG, currFG = nil,nil
  3949.         local writePosition = 1
  3950.         for x = 1, #line do
  3951.             if not pixels[writePosition] then
  3952.                 pixels[writePosition] = {}
  3953.             end
  3954.  
  3955.             local nextChar = string.sub(line, x, x)
  3956.             if nextChar:byte() == 30 then
  3957.                     bgNext = true
  3958.             elseif nextChar:byte() == 31 then
  3959.                     fgNext = true
  3960.             elseif bgNext then
  3961.                     currBG = getColourOf(nextChar)
  3962.                     if currBG == nil then
  3963.                         currBG = colours.transparent
  3964.                     end
  3965.                     bgNext = false
  3966.             elseif fgNext then
  3967.                     currFG = getColourOf(nextChar)
  3968.                     fgNext = false
  3969.             else
  3970.                     if nextChar ~= " " and currFG == nil then
  3971.                             currFG = colours.white
  3972.                     end
  3973.                     pixels[writePosition][y] = {BackgroundColour = currBG, TextColour = currFG, Character = nextChar}
  3974.                     writePosition = writePosition + 1
  3975.             end
  3976.         end
  3977.     end
  3978.     return pixels
  3979. end
  3980.  
  3981. --[[
  3982.     Read a .skch file from the given path
  3983. ]]--
  3984. function ReadSKCH(path)
  3985.     local _fs = fs
  3986.     if OneOS then
  3987.         _fs = OneOS.FS
  3988.     end
  3989.     local file = _fs.open(path, 'r')
  3990.     local _layers = textutils.unserialize(file.readAll())
  3991.     file.close()
  3992.     local layers = {}
  3993.  
  3994.     for i, l in ipairs(_layers) do
  3995.         local layer = {
  3996.             Name = l.Name,
  3997.             Pixels = ParseNFT(l.Pixels),
  3998.             BackgroundColour = l.BackgroundColour,
  3999.             Visible = l.Visible,
  4000.             Index = l.Index,
  4001.         }
  4002.         table.insert(layers, layer)
  4003.     end
  4004.     return layers
  4005. end
  4006.  
  4007. --[[
  4008.     Start the program after all functions and tables are loaded
  4009. ]]--
  4010. if term.isColor and term.isColor() then
  4011.     Initialise(...)
  4012. else
  4013.     print('Sorry, but Sketch only works on Advanced (gold) Computers')
  4014. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement