MigasRocha

Paint Program Turtle

Jan 5th, 2024
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.85 KB | Gaming | 0 0
  1. -- Paint created by nitrogenfingers (edited by dan200)
  2. -- http://www.youtube.com/user/NitrogenFingers
  3.  
  4. ------------
  5. -- Fields --
  6. ------------
  7.  
  8. -- The width and height of the terminal
  9. local w,h = term.getSize()
  10.  
  11. -- The selected colours on the left and right mouse button, and the colour of the canvas
  12. local leftColour, rightColour = colours.white, nil
  13. local canvasColour = colours.black
  14.  
  15. -- The values stored in the canvas
  16. local canvas = {}
  17.  
  18. -- The menu options
  19. local mChoices = { "Save","Exit" }
  20.  
  21. -- The message displayed in the footer bar
  22. local fMessage = "Press Ctrl to access menu"
  23.  
  24. -------------------------
  25. -- Initialisation --
  26. -------------------------
  27.  
  28. -- Determine if we can even run this
  29. if not term.isColour() then
  30.     print("Requires an Advanced Computer")
  31.     return
  32. end
  33.  
  34. -- Determines if the file exists, and can be edited on this computer
  35. local tArgs = {...}
  36. if #tArgs == 0 then
  37.     print("Usage: paint <path>")
  38.     return
  39. end
  40. local sPath = shell.resolve(tArgs[1])
  41. local bReadOnly = fs.isReadOnly(sPath)
  42. if fs.exists(sPath) and fs.isDir(sPath) then
  43.     print("Cannot edit a directory.")
  44.     return
  45. end
  46.  
  47. ---------------
  48. -- Functions --
  49. ---------------
  50.  
  51. local function getCanvasPixel( x, y )
  52.     if canvas[y] then
  53.         return canvas[y][x]
  54.     end
  55.     return nil
  56. end
  57.  
  58. --[[
  59.     Converts a colour value to a text character
  60.     params: colour = the number to convert to a hex value
  61.     returns: a string representing the chosen colour
  62. ]]
  63. local function getCharOf( colour )
  64.     -- Incorrect values always convert to nil
  65.     if type(colour) == "number" then
  66.         local value = math.floor( math.log(colour) / math.log(2) ) + 1
  67.         if value >= 1 and value <= 16 then
  68.             return string.sub( "0123456789abcdef", value, value )
  69.         end
  70.     end
  71.     return " "
  72. end    
  73.  
  74. --[[
  75.     Converts a text character to colour value
  76.     params: char = the char (from string.byte) to convert to number
  77.     returns: the colour number of the hex value
  78. ]]
  79. local tColourLookup = {}
  80. for n=1,16 do
  81.     tColourLookup[ string.byte( "0123456789abcdef",n,n ) ] = 2^(n-1)
  82. end
  83. local function getColourOf( char )
  84.     -- Values not in the hex table are transparent (canvas coloured)
  85.     return tColourLookup[char]
  86. end
  87.  
  88. --[[
  89.     Loads the file into the canvas
  90.     params: path = the path of the file to open
  91.     returns: nil
  92. ]]
  93. local function load(path)
  94.     -- Load the file
  95.     if fs.exists(path) then
  96.         local file = fs.open(sPath, "r")
  97.         local sLine = file.readLine()
  98.         while sLine do
  99.             local line = {}
  100.             for x=1,w-2 do
  101.                 line[x] = getColourOf( string.byte(sLine,x,x) )
  102.             end
  103.             table.insert( canvas, line )
  104.             sLine = file.readLine()
  105.         end
  106.         file.close()
  107.     end
  108. end
  109.  
  110. --[[  
  111.     Saves the current canvas to file  
  112.     params: path = the path of the file to save
  113.     returns: true if save was successful, false otherwise
  114. ]]
  115. local function save(path)
  116.     -- Open file
  117.     local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath))
  118.     if not fs.exists(sDir) then
  119.         fs.makeDir(sDir)
  120.     end
  121.  
  122.     local file = fs.open( path, "w" )
  123.     if not file then
  124.         return false
  125.     end
  126.  
  127.     -- Encode (and trim)
  128.     local tLines = {}
  129.     local nLastLine = 0
  130.     for y=1,h-1 do
  131.         local sLine = ""
  132.         local nLastChar = 0
  133.         for x=1,w-2 do
  134.             local c = getCharOf( getCanvasPixel( x, y ) )
  135.             sLine = sLine .. c
  136.             if c ~= " " then
  137.                 nLastChar = x
  138.             end
  139.         end
  140.         sLine = string.sub( sLine, 1, nLastChar )
  141.         tLines[y] = sLine
  142.         if string.len( sLine ) > 0 then
  143.             nLastLine = y
  144.         end
  145.     end
  146.  
  147.     -- Save out
  148.     for n=1,nLastLine do
  149.            file.writeLine( tLines[ n ] )
  150.     end
  151.     file.close()
  152.     return true
  153. end
  154.  
  155. --[[  
  156.     Draws colour picker sidebar, the pallette and the footer
  157.     returns: nil
  158. ]]
  159. local function drawInterface()
  160.     -- Footer
  161.     term.setCursorPos(1, h)
  162.     term.setBackgroundColour(colours.black)
  163.     term.setTextColour(colours.yellow)
  164.     term.clearLine()
  165.     term.write(fMessage)
  166.    
  167.     -- Colour Picker
  168.     for i=1,16 do
  169.         term.setCursorPos(w-1, i)
  170.         term.setBackgroundColour( 2^(i-1) )
  171.         term.write("  ")
  172.     end
  173.  
  174.     term.setCursorPos(w-1, 17)
  175.     term.setBackgroundColour( canvasColour )
  176.     term.setTextColour( colours.grey )
  177.     term.write("XX")
  178.            
  179.     -- Left and Right Selected Colours
  180.     for i=18,18 do
  181.         term.setCursorPos(w-1, i)
  182.         if leftColour ~= nil then
  183.             term.setBackgroundColour( leftColour )
  184.             term.write(" ")
  185.         else
  186.             term.setBackgroundColour( canvasColour )
  187.             term.setTextColour( colours.grey )
  188.             term.write("X")
  189.         end
  190.         if rightColour ~= nil then
  191.             term.setBackgroundColour( rightColour )
  192.             term.write(" ")
  193.         else
  194.             term.setBackgroundColour( canvasColour )
  195.             term.setTextColour( colours.grey )
  196.             term.write("X")
  197.         end
  198.     end
  199.  
  200.     -- Padding
  201.     term.setBackgroundColour( canvasColour )
  202.     for i=20,h-1 do
  203.         term.setCursorPos(w-1, i)
  204.         term.write("  ")
  205.     end
  206. end
  207.  
  208. --[[  
  209.     Converts a single pixel of a single line of the canvas and draws it
  210.     returns: nil
  211. ]]
  212. local function drawCanvasPixel( x, y )
  213.     local pixel = getCanvasPixel( x, y )
  214.     if pixel then
  215.         term.setBackgroundColour( pixel or canvasColour )
  216.         term.setCursorPos(x, y)
  217.         term.write(" ")
  218.     else
  219.         term.setBackgroundColour( canvasColour )
  220.         term.setTextColour( colours.grey )
  221.         term.setCursorPos(x, y)
  222.         term.write("-")
  223.     end
  224. end
  225.  
  226. --[[  
  227.     Converts each colour in a single line of the canvas and draws it
  228.     returns: nil
  229. ]]
  230. local function drawCanvasLine( y )
  231.     for x = 1, w-2 do
  232.         drawCanvasPixel( x, y )
  233.     end
  234. end
  235.  
  236. --[[  
  237.     Converts each colour in the canvas and draws it
  238.     returns: nil
  239. ]]
  240. local function drawCanvas()
  241.     for y = 1, h-1 do
  242.         drawCanvasLine( y )
  243.     end
  244. end
  245.  
  246. --[[
  247.     Draws menu options and handles input from within the menu.
  248.     returns: true if the program is to be exited; false otherwise
  249. ]]
  250. local function accessMenu()
  251.     -- Selected menu option
  252.     local selection = 1
  253.    
  254.     term.setBackgroundColour(colours.black)
  255.     while true do
  256.         -- Draw the menu
  257.         term.setCursorPos(1,h)
  258.         term.clearLine()
  259.         term.setTextColour(colours.white)
  260.         for k,v in pairs(mChoices) do
  261.             if selection==k then
  262.                 term.setTextColour(colours.yellow)
  263.                 local ox,_ = term.getCursorPos()
  264.                 term.write("["..string.rep(" ",#v).."]")
  265.                 term.setCursorPos(ox+1,h)
  266.                 term.setTextColour(colours.white)
  267.                 term.write(v)
  268.                 term.setCursorPos(term.getCursorPos()+1,h)
  269.             else
  270.                 term.write(" "..v.." ")
  271.             end
  272.         end
  273.        
  274.         -- Handle input in the menu
  275.         local id,key = os.pullEvent("key")
  276.         if id == "key" then
  277.             -- S and E are shortcuts
  278.             if key == keys.s then
  279.                 selection = 1
  280.                 key = keys.enter
  281.             elseif key == keys.e then
  282.                 selection = 2
  283.                 key = keys.enter
  284.             end
  285.        
  286.             if key == keys.right then
  287.                 -- Move right
  288.                 selection = selection + 1
  289.                 if selection > #mChoices then
  290.                     selection = 1
  291.                 end
  292.                
  293.             elseif key == keys.left and selection > 1 then
  294.                 -- Move left
  295.                 selection = selection - 1
  296.                 if selection < 1 then
  297.                     selection = #mChoices
  298.                 end
  299.                
  300.             elseif key == keys.enter then
  301.                 -- Select an option
  302.                 if mChoices[selection]=="Save" then
  303.                     if bReadOnly then
  304.                         fMessage = "Access Denied"
  305.                         return false
  306.                     end
  307.                     local success = save(sPath)
  308.                     if success then
  309.                         fMessage = "Saved to "..sPath
  310.                     else
  311.                         fMessage = "Error saving to "..sPath
  312.                     end
  313.                     return false
  314.                 elseif mChoices[selection]=="Exit" then
  315.                     return true
  316.                 end
  317.             elseif key == keys.leftCtrl or keys == keys.rightCtrl then
  318.                 -- Cancel the menu
  319.                 return false
  320.             end
  321.         end
  322.     end
  323. end
  324.  
  325. --[[  
  326.     Runs the main thread of execution. Draws the canvas and interface, and handles
  327.     mouse and key events.
  328.     returns: nil
  329. ]]
  330. local function handleEvents()
  331.     local programActive = true
  332.     while programActive do
  333.         local id,p1,p2,p3 = os.pullEvent()
  334.         if id=="mouse_click" or id=="mouse_drag" then
  335.             if p2 >= w-1 and p3 >= 1 and p3 <= 17 then
  336.                 if id ~= "mouse_drag" then
  337.                     -- Selecting an items in the colour picker
  338.                     if p3 <= 16 then
  339.                         if p1==1 then
  340.                             leftColour = 2^(p3-1)
  341.                         else
  342.                             rightColour = 2^(p3-1)
  343.                         end
  344.                     else
  345.                         if p1==1 then
  346.                             leftColour = nil
  347.                         else
  348.                             rightColour = nil
  349.                         end
  350.                     end
  351.                     --drawCanvas()
  352.                     drawInterface()
  353.                 end
  354.             elseif p2 < w-1 and p3 <= h-1 then
  355.                 -- Clicking on the canvas
  356.                 local paintColour = nil
  357.                 if p1==1 then
  358.                     paintColour = leftColour
  359.                 elseif p1==2 then
  360.                     paintColour = rightColour
  361.                 end
  362.                 if not canvas[p3] then
  363.                     canvas[p3] = {}
  364.                 end
  365.                 canvas[p3][p2] = paintColour
  366.  
  367.                 drawCanvasPixel( p2, p3 )
  368.             end
  369.         elseif id=="key" then
  370.             if p1==keys.leftCtrl or p1==keys.rightCtrl then
  371.                 programActive = not accessMenu()
  372.                 drawInterface()
  373.             end
  374.         elseif id=="term_resize" then
  375.             w,h = term.getSize()
  376.             drawCanvas()
  377.             drawInterface()
  378.         end
  379.     end
  380. end
  381.  
  382. -- Init
  383. load(sPath)
  384. drawCanvas()
  385. drawInterface()
  386.  
  387. -- Main loop
  388. handleEvents()
  389.  
  390. -- Shutdown
  391. term.setBackgroundColour(colours.black)
  392. term.setTextColour(colours.white)
  393. term.clear()
  394. term.setCursorPos(1,1)
Add Comment
Please, Sign In to add comment