diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua index 203aa17a9..2c4760e2b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua @@ -1,5 +1,15 @@ local setPos, write, setCol, blit = term.setCursorPos, term.write, term.setBackgroundColour, term.blit +local maxn = table.maxn or function( tTable ) + local maxn = 0 + for n in pairs( tTable ) do + if type( n ) == "number" and n > max then + maxn = n + end + end + return maxn +end + local tColourLookup = {} for n=1,16 do tColourLookup[ string.sub( "0123456789abcdef",n,n ) ] = 2^(n-1) @@ -33,15 +43,22 @@ function saveImage( tImage, sPath ) end local file = fs.open(sPath, "w" ) + if not file then return false end - for y=1,#tImage do - local tOld, tNew = tImage[y], {} - for x=1,#tOld do - tNew[x] = tColourLookup[ tOld[x] ] or " " - end - file.writeLine( table.concat( tNew ) ) + for y=1,maxn( tImage ) do + local tOld, tNew, last = tImage[y], {}, 0 + if tOld then for x=1,maxn( tOld ) do + local thisCol = tColourLookup[ tOld[x] ] + if thisCol then + tNew[x], last = thisCol, x + else + tNew[x] = " " + end + end end + file.writeLine( table.concat( tNew, "", 1, last ) ) end file.close() + return true end function drawPixel( xPos, yPos, nColour ) @@ -93,9 +110,8 @@ function drawLine( startX, startY, endX, endY, nColour ) local yDiff = maxY - minY if minY == maxY then - local sStr = string.rep( " ", xDiff + 1 ) setPos( minX, minY ) - write( sStr ) + write( string.rep( " ", xDiff + 1 ) ) return end @@ -193,9 +209,9 @@ function drawImage( tImage, xPos, yPos ) if type( tImage ) ~= "table" or type( xPos ) ~= "number" or type( yPos ) ~= "number" then error( "Expected image, x, y", 2 ) end - for y=1,#tImage do + for y=1,maxn( tImage ) do local tLine, sBG, counter = tImage[y], {}, 0 - for x=1,#tLine+1 do + if tLine then for x=1,maxn( tLine )+1 do local px = tLine[x] or 0 if px > 0 then counter = counter + 1 @@ -206,6 +222,6 @@ function drawImage( tImage, xPos, yPos ) blit( sT, sT, table.concat( sBG ) ) sBG, counter = {}, 0 end - end + end end end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua index bba2f67a3..dbdfa831c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -1,4 +1,4 @@ --- Paint created by nitrogenfingers (edited by dan200) +-- Paint created by nitrogenfingers (edited by dan200 & co) -- http://www.youtube.com/user/NitrogenFingers ------------ @@ -21,9 +21,15 @@ local mChoices = { "Save","Exit" } -- The message displayed in the footer bar local fMessage = "Press Ctrl to access menu" -------------------------- --- Initialisation -- -------------------------- +-- Colour to character conversions +local tColourLookup = {} +for n=1,16 do + tColourLookup[ 2^(n-1) ] = string.sub( "0123456789abcdef",n,n ) +end + +----------------------- +-- Pre-Flight Checks -- +----------------------- -- Determine if we can even run this if not term.isColour() then @@ -32,14 +38,13 @@ if not term.isColour() then end -- Determines if the file exists, and can be edited on this computer -local tArgs = {...} -if #tArgs == 0 then +local sPath = ... +if not sPath then print("Usage: paint ") return end -local sPath = shell.resolve(tArgs[1]) -local bReadOnly = fs.isReadOnly(sPath) -if fs.exists(sPath) and fs.isDir(sPath) then +sPath = shell.resolve( sPath ) +if fs.isDir( sPath ) then print("Cannot edit a directory.") return end @@ -52,117 +57,14 @@ if not fs.exists( sPath ) and not string.find( sPath, "%." ) then end end +local bReadOnly = fs.isReadOnly(sPath) --------------- -- Functions -- --------------- -local function getCanvasPixel( x, y ) - if canvas[y] then - return canvas[y][x] - end - return nil -end - ---[[ - Converts a colour value to a text character - params: colour = the number to convert to a hex value - returns: a string representing the chosen colour -]] -local function getCharOf( colour ) - -- Incorrect values always convert to nil - if type(colour) == "number" then - local value = math.floor( math.log(colour) / math.log(2) ) + 1 - if value >= 1 and value <= 16 then - return string.sub( "0123456789abcdef", value, value ) - end - end - return " " -end - ---[[ - Converts a text character to colour value - params: char = the char (from string.byte) to convert to number - returns: the colour number of the hex value -]] -local tColourLookup = {} -for n=1,16 do - tColourLookup[ string.byte( "0123456789abcdef",n,n ) ] = 2^(n-1) -end -local function getColourOf( char ) - -- Values not in the hex table are transparent (canvas coloured) - return tColourLookup[char] -end - ---[[ - Loads the file into the canvas - params: path = the path of the file to open - returns: nil -]] -local function load(path) - -- Load the file - if fs.exists(path) then - local file = fs.open(sPath, "r") - local sLine = file.readLine() - while sLine do - local line = {} - for x=1,w-2 do - line[x] = getColourOf( string.byte(sLine,x,x) ) - end - table.insert( canvas, line ) - sLine = file.readLine() - end - file.close() - end -end - --[[ - Saves the current canvas to file - params: path = the path of the file to save - returns: true if save was successful, false otherwise -]] -local function save(path) - -- Open file - local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath)) - if not fs.exists(sDir) then - fs.makeDir(sDir) - end - - local file = fs.open( path, "w" ) - if not file then - return false - end - - -- Encode (and trim) - local tLines = {} - local nLastLine = 0 - for y=1,h-1 do - local sLine = "" - local nLastChar = 0 - for x=1,w-2 do - local c = getCharOf( getCanvasPixel( x, y ) ) - sLine = sLine .. c - if c ~= " " then - nLastChar = x - end - end - sLine = string.sub( sLine, 1, nLastChar ) - tLines[y] = sLine - if string.len( sLine ) > 0 then - nLastLine = y - end - end - - -- Save out - for n=1,nLastLine do - file.writeLine( tLines[ n ] ) - end - file.close() - return true -end - ---[[ - Draws colour picker sidebar, the pallette and the footer + Draws colour picker sidebar, the palette and the footer returns: nil ]] local function drawInterface() @@ -186,24 +88,22 @@ local function drawInterface() term.write("\127\127") -- Left and Right Selected Colours - for i=18,18 do - term.setCursorPos(w-1, i) - if leftColour ~= nil then - term.setBackgroundColour( leftColour ) - term.write(" ") - else - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) - term.write("\127") - end - if rightColour ~= nil then - term.setBackgroundColour( rightColour ) - term.write(" ") - else - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) - term.write("\127") - end + term.setCursorPos(w-1, 18) + if leftColour ~= nil then + term.setBackgroundColour( leftColour ) + term.write(" ") + else + term.setBackgroundColour( canvasColour ) + term.setTextColour( colours.grey ) + term.write("\127") + end + if rightColour ~= nil then + term.setBackgroundColour( rightColour ) + term.write(" ") + else + term.setBackgroundColour( canvasColour ) + term.setTextColour( colours.grey ) + term.write("\127") end -- Padding @@ -214,41 +114,24 @@ local function drawInterface() end end ---[[ - Converts a single pixel of a single line of the canvas and draws it - returns: nil -]] -local function drawCanvasPixel( x, y ) - local pixel = getCanvasPixel( x, y ) - if pixel then - term.setBackgroundColour( pixel or canvasColour ) - term.setCursorPos(x, y) - term.write(" ") - else - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) - term.setCursorPos(x, y) - term.write("\127") - end -end - ---[[ - Converts each colour in a single line of the canvas and draws it - returns: nil -]] -local function drawCanvasLine( y ) - for x = 1, w-2 do - drawCanvasPixel( x, y ) - end -end - --[[ Converts each colour in the canvas and draws it returns: nil ]] local function drawCanvas() + local TC = string.rep( "7", w-2 ) for y = 1, h-1 do - drawCanvasLine( y ) + local T, BC = {}, {} + for x = 1, w-2 do + local pixel = canvas[y] and canvas[y][x] + if pixel and pixel ~= 0 then + T[x], BC[x] = " ", tColourLookup[pixel] + else + T[x], BC[x] = "\127", tColourLookup[canvasColour] + end + end + term.setCursorPos( 1, y ) + term.blit( table.concat( T ), TC, table.concat( BC ) ) end end @@ -259,22 +142,15 @@ end local function accessMenu() -- Selected menu option local selection = 1 - + term.setTextColour(colours.white) term.setBackgroundColour(colours.black) while true do -- Draw the menu term.setCursorPos(1,h) term.clearLine() - term.setTextColour(colours.white) for k,v in pairs(mChoices) do if selection==k then - term.setTextColour(colours.yellow) - local ox,_ = term.getCursorPos() - term.write("["..string.rep(" ",#v).."]") - term.setCursorPos(ox+1,h) - term.setTextColour(colours.white) - term.write(v) - term.setCursorPos(term.getCursorPos()+1,h) + term.blit( "["..v.."]", "4"..string.rep(" ",#v).."4", string.rep("f",#v+2) ) else term.write(" "..v.." ") end @@ -282,51 +158,39 @@ local function accessMenu() -- Handle input in the menu local id,key = os.pullEvent("key") - if id == "key" then - -- S and E are shortcuts - if key == keys.s then - selection = 1 - key = keys.enter - elseif key == keys.e then - selection = 2 - key = keys.enter - end - if key == keys.right then - -- Move right - selection = selection + 1 - if selection > #mChoices then - selection = 1 - end - - elseif key == keys.left and selection > 1 then - -- Move left - selection = selection - 1 - if selection < 1 then - selection = #mChoices - end - - elseif key == keys.enter then - -- Select an option - if mChoices[selection]=="Save" then - if bReadOnly then - fMessage = "Access Denied" - return false - end - local success = save(sPath) - if success then - fMessage = "Saved to "..sPath - else - fMessage = "Error saving to "..sPath - end + -- S and E are shortcuts + if key == keys.s then + selection = 1 + key = keys.enter + elseif key == keys.e then + selection = 2 + key = keys.enter + end + + if key == keys.right then + -- Move right + selection = selection == #mChoices and 1 or (selection + 1) + + elseif key == keys.left then + -- Move left + selection = selection == 1 and #mChoices or (selection - 1) + + elseif key == keys.enter then + -- Select an option + if mChoices[selection]=="Save" then + if bReadOnly then + fMessage = "Access Denied" return false - elseif mChoices[selection]=="Exit" then - return true end - elseif key == keys.leftCtrl or keys == keys.rightCtrl then - -- Cancel the menu - return false + fMessage = (paintutils.saveImage( canvas, sPath ) and "Saved to " or "Error saving to ")..sPath + return false + elseif mChoices[selection]=="Exit" then + return true end + elseif key == keys.leftCtrl or keys == keys.rightCtrl then + -- Cancel the menu + return false end end end @@ -337,11 +201,10 @@ end returns: nil ]] local function handleEvents() - local programActive = true - while programActive do + while true do local id,p1,p2,p3 = os.pullEvent() - if id=="mouse_click" or id=="mouse_drag" then - if p2 >= w-1 and p3 >= 1 and p3 <= 17 then + if id=="mouse_click" or id=="mouse_drag" and p1 < 3 and p2 > 0 and p2 <= w and p3 > 0 and p3 < h then + if p2 >= w-1 and p3 <= 17 then if id ~= "mouse_drag" then -- Selecting an items in the colour picker if p3 <= 16 then @@ -357,15 +220,14 @@ local function handleEvents() rightColour = nil end end - --drawCanvas() drawInterface() end - elseif p2 < w-1 and p3 <= h-1 then + elseif p2 < w-1 then -- Clicking on the canvas - local paintColour = nil + local paintColour if p1==1 then paintColour = leftColour - elseif p1==2 then + else paintColour = rightColour end if not canvas[p3] then @@ -373,11 +235,16 @@ local function handleEvents() end canvas[p3][p2] = paintColour - drawCanvasPixel( p2, p3 ) + term.setCursorPos( p2, p3 ) + if paintColour then + term.blit( " ", " ", tColourLookup[paintColour] ) + else + term.blit( "\127", "7", tColourLookup[canvasColour] ) + end end elseif id=="key" then if p1==keys.leftCtrl or p1==keys.rightCtrl then - programActive = not accessMenu() + if accessMenu() then return end drawInterface() end elseif id=="term_resize" then @@ -388,15 +255,24 @@ local function handleEvents() end end --- Init -load(sPath) +-------------------- +-- Initialisation -- +-------------------- + +if fs.exists( sPath ) then canvas = paintutils.loadImage( sPath ) end drawCanvas() drawInterface() --- Main loop +--------------- +-- Main Loop -- +--------------- + handleEvents() --- Shutdown +-------------- +-- Shutdown -- +-------------- + term.setBackgroundColour(colours.black) term.setTextColour(colours.white) term.clear()