Advertisement
AdditionalPylons

rspaint.lua

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