Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Coded by HPWebcamAble
- Name: Advanced Paint
- Description: The CC Paint program, but made for monitors!
- ComputerCraft Forum Post:
- http://www.computercraft.info/forums2/index.php?/topic/21558-advanced-paint
- Youtube Video:
- https://youtu.be/8jiNTgAaeos
- Version History:
- ####### 3.3 #######
- -Bug Fixes
- *ACTUALLY fixed monitor reassigning. Promise :)
- -You can no longer try to edit or draw a directory (oops)
- -Program now stops if a monitor is disconected or resized (a block is added or removed)
- -When reassinging monitors, the size is given in blocks and pixels
- -Added some more comments (in case somone is trying to figure out what I did)
- ####### 3.2 #######
- -Bug Fixes
- *Reassigning a monitor sometimes didn't work
- -Slightly tweaked reassigning monitors
- ####### 3.1 #######
- -Cleaned up Code
- *Removed a log method that wasn't used
- *Changed the way the screen is drawn
- *Implemented some debug errors
- -Added the Utiltiy Monitor!
- *change color
- *turn on and off clear mode
- *change the utility monitor
- *and save/exit from a monitor!
- -Fixed some bugs
- *invalid key to next when removing a remote monitor from the save
- ####### 3.0 and below #######
- Seperate programs
- ]]
- --Variables--
- args = {...}
- w,h = term.getSize()
- local fileName = "ap" --What this file should be called
- local offset
- local image = {} --a table of the monitors, which are a table of the pixels
- monitors = {} --a table of the monitors
- local dColor = colors.white --The default color of the monitors
- local cColor = colors.black --The current color
- local cColorPos = 16
- local clearM = false --Clear Mode - Touching a monitor with this on clears that monitor
- local lastColor = 32768 --the color black
- local rMonitors = {}
- local utilMonitor --The utility monitor, when the program starts, there isn't one
- local changeUtilMon = false --If the utility monitor is being changed or not
- local skip = {}
- local _color = 1
- colorPos = {} -- Table with colors to know which color was clicked
- for i = 1, 17 do -- Define all the colors up to black
- colorPos[i] = _color
- _color = _color*2
- if _color > lastColor then
- break
- end
- end
- --Functions--
- --Some functions to make codeing a bit faster; less typing XD
- function tw(...) term.write(...) end
- function cp(...) term.setCursorPos(...) end
- function clear() term.clear() end
- function color(textColor,backgroundColor)
- if term.isColor() then
- if textColor then
- term.setTextColor(textColor)
- end
- if backgroundColor then
- term.setBackgroundColor(backgroundColor)
- end
- end
- end
- local function usages()
- print("Usages:")
- print("ap draw <ap3 Save File>")
- print("ap edit <name>")
- end
- local function waitForKey(_key)
- while true do
- local event,p1 = os.pullEvent("key")
- if p1 == _key then
- break
- end
- end
- end
- function printC(text,y)
- if not y then
- error("printC:for text "..text..", y value expected")
- end
- tLenght = #tostring(text)
- local sStart = math.ceil(w/2-tLenght/2)
- local sEnd = sStart + tLenght
- cp(sStart,y)
- tw(text)
- return sStart,sEnd
- end
- local function registerMonitors()
- monitors = {}
- for a,b in pairs(peripheral.getNames()) do
- if peripheral.getType(b) == "monitor" and peripheral.call(b,"isColor") then
- table.insert(monitors,b)
- end
- end
- if #monitors == 0 then
- print("No monitors could be found")
- print("-Make sure any wired modems are on (Right click)")
- print("-Only Advanced (Gold) monitors work")
- error("FORCEQUIT")
- end
- end
- local function mW(mon,toWrite) --Write something on a monitor
- if not mon or not color then
- error("expected string,string",2)
- end
- peripheral.call(mon,"write",toWrite)
- end
- local function mC(mon,color) --Change a monitor's background color
- if not mon or not color then
- error("expected string,number",2)
- end
- peripheral.call(mon,"setBackgroundColor",color)
- end
- local function mP(mon,x,y) --Set the cursor's position on a monitor
- if not mon or not x or not y then
- error("expected string,number,number",2)
- end
- peripheral.call(mon,"setCursorPos",x,y)
- end
- local function itemsIn(tTable) --Count the items in a table
- if not tTable then return 0 end
- if not type(tTable) == "table" then error("Expected table",2) end
- local items = 0
- for a,b in pairs(tTable) do
- items = items+1
- end
- return items
- end
- local function checkImage() --Check all the monitors are there
- for a,b in pairs(image) do
- if not peripheral.isPresent(a) and itemsIn(image[a]) > 0 then
- if not skip[a] then
- return a --returns the first missing one
- end
- end
- end
- return false
- end
- local function draw()
- if not args[2] then
- print("Usage:")
- print("ap draw <ap3 save file>")
- error("FORCEQUIT")
- end
- if not fs.exists(args[2]) and not fs.isDir(args[2]) then
- print("That file doesn't exist")
- print("You can make it with 'ap edit <name>'")
- error("FORCEQUIT")
- else
- f = fs.open(args[2],"r")
- image = textutils.unserialize(f.readAll())
- f.close()
- end
- if not image then
- print("That file exists, but it doesn't seem to be in the correct Advanced Paint 3 format")
- error("FORCEQUIT")
- end
- if checkImage() then
- print("A monitor in this save is missing!")
- print("The image can't be displayed unless all monitors are present")
- print("Use 'ap edit "..args[2].."' to reassign the missing monitors")
- error("FORCEQUIT")
- end
- registerMonitors()
- for i = 1, #monitors do --Clear all the monitors
- if not rMonitors[monitors[i]] then
- mC(monitors[i],dColor)
- peripheral.call(monitors[i],"clear")
- end
- end
- for i = 1, #monitors do --Draw the image on the monitors
- if image[monitors[i]] then
- for a,b in pairs(image[monitors[i]]) do
- for c,d in pairs(b) do
- if type(c) == "number" and type(a) == "number" then
- mP(monitors[i],c,a)
- mC(monitors[i],d)
- mW(monitors[i]," ")
- end
- end
- end
- end
- end
- --Draw the thing the terminal displays
- color(nil,colors.white)
- clear()
- cp(1,1)
- color(colors.lightGray,colors.yellow)
- tw(string.rep(" ",w))
- printC("Advanced Paint 3",1)
- color(colors.black,colors.white)
- printC("'"..args[2].."'",6)
- printC("Is currently being displayed",7)
- color(colors.white,colors.red)
- printC(" Exit ",9)
- while true do
- local event,p1,p2,p3 = os.pullEvent("mouse_click")
- if p3 == 9 then --exit
- break
- end
- end
- end
- local function isSide(side)
- for a,b in pairs(rs.getSides()) do
- if side == b then
- return true
- end
- end
- return false
- end
- local function isMonitor(mon) --Checks if a monitor is part of the save
- for a,b in pairs(image) do
- if a == mon then
- return true
- end
- end
- return false
- end
- local function drawColorScreen()
- color(nil,colors.white)
- clear()
- cp(1,1)
- color(colors.lightGray,colors.yellow)
- tw(string.rep(" ",w))
- printC("Advanced Paint 3",1)
- color(colors.black,colors.white)
- if clearM then
- printC("Clear Mode is on",5)
- printC("Touch a monitor to clear it",7)
- color(colors.white,colors.lime)
- printC(" Done ",9)
- elseif changeUtilMon then
- printC("Change the Utility Monitor",5)
- printC("Touch a monitor to select it",7)
- printC("Minium size of 2x2 blocks",9)
- color(colors.white,colors.lime)
- printC("Cancel",11)
- else
- printC("Select Color",7)
- cp(18,9)
- for i = 1, #colorPos do
- color(nil,colorPos[i])
- tw(" ")
- end
- color(colors.black,colors.white)
- cp(1,8)
- tw(string.rep(" ",w))
- local cPos = 1
- local _cColor = cColor
- while _cColor>1 do
- _cColor = _cColor/2
- cPos = cPos+1
- end
- cp(cPos+17,8)
- tw("v")
- cp(18,10)
- tw(string.rep("^",16))
- color(colors.white,colors.lime)
- printC("Clear Mode",11)
- printC("Change Util Monitor",13)
- cp(1,h)
- tw(string.rep(" ",w))
- printC("Save and Exit",h)
- end
- end
- local function drawUtilMon() --Draws the screen of the utility monitor
- local uW,uH = 18,12 --Width and hight of the box
- mC(utilMonitor,colors.gray) --Draw the background
- for a = 1, uH do
- mP(utilMonitor,1,a)
- for b = 1, uW do
- mW(utilMonitor," ")
- end
- end
- peripheral.call(utilMonitor,"setTextColor",colors.white)
- if clearM then
- mP(utilMonitor,2,4)
- mW(utilMonitor,"Touch a monitor")
- mP(utilMonitor,4,5)
- mW(utilMonitor,"to clear it")
- mC(utilMonitor,colors.lime)
- mP(utilMonitor,7,7)
- mW(utilMonitor,"Done")
- elseif changeUtilMon then
- mP(utilMonitor,2,4)
- mW(utilMonitor,"Touch a monitor")
- mP(utilMonitor,4,5)
- mW(utilMonitor,"to choose it")
- mP(utilMonitor,1,7)
- mW(utilMonitor,"Minimum 2x2 blocks")
- mC(utilMonitor,colors.lime)
- mP(utilMonitor,7,9)
- mW(utilMonitor,"Cancel")
- else
- mP(utilMonitor,4,2)
- mW(utilMonitor,"Select Color")
- mP(utilMonitor,2,4)
- local _color = 1
- for i = 1, 17 do
- mC(utilMonitor,_color)
- mW(utilMonitor," ")
- _color = _color*2
- if _color > lastColor then
- break
- end
- end
- mP(utilMonitor,1,3)
- mC(utilMonitor,colors.gray)
- mW(string.rep(" ",uW))
- local cPos = 1
- local _cColor = cColor
- while _cColor>1 do
- _cColor = _cColor/2
- cPos = cPos+1
- end
- mP(utilMonitor,cPos+1,3)
- mW(utilMonitor,"v")
- mP(utilMonitor,2,5)
- for i = 1, 16 do
- mW(utilMonitor,"^")
- end
- mC(utilMonitor,colors.lime)
- mP(utilMonitor,5,6)
- mW(utilMonitor,"Clear Mode")
- mP(utilMonitor,3,8)
- mW(utilMonitor,"Save and Exit")
- mP(utilMonitor,1,10)
- mW(utilMonitor,"Change Utility Mon")
- end
- end
- local function redrawScreens()
- drawColorScreen()
- if utilMonitor then
- drawUtilMon()
- end
- end
- local function edit()
- if not args[2] then
- print("Usage:")
- print("ap edit <ap3 save file>")
- error("FORCEQUIT")
- end
- if fs.isDir(args[2]) then
- print("That's a directory")
- print("Usage:")
- print("ap edit <ap3 save file>")
- error("FORCEQUIT")
- end
- if not fs.exists(args[2]) then
- print("This file doesn't exist, so it will be created")
- print("Disconnect any monitors that you don't want included")
- color(colors.lime)
- print("Press 'Enter' to coninue")
- waitForKey(keys.enter)
- f = fs.open(args[2],"w")
- f.close()
- image = {}
- else
- f = fs.open(args[2],"r")
- image = textutils.unserialize(f.readAll())
- f.close()
- if not image then image = {} end
- end
- if image then --Load the image if it exists
- skip = {}
- while checkImage() do
- local a = checkImage()
- clear()
- cp(1,1)
- print("A monitor in this save is missing!")
- print("Name:"..a)
- if image[a]["size"] and image[a]["size"][1] and image[a]["size"][2] then
- print("Size: "..(image[a]["size"][1]/7).."x"..(image[a]["size"][2]/5).." blocks ("..image[a]["size"][1].."x"..image[a]["size"][2].." pixels)")
- else
- print("Size: Unknown")
- end
- print("1:Choose another to take its place this time")
- print("2:Choose another to permanantly take its place")
- print("3:Skip the monitor this time")
- print("4:Remove this monitor from the save")
- print("5:Cancel loading")
- local continue = true
- while continue do
- local event,p1 = os.pullEvent("key")
- if p1 == keys.one then --temp replace
- clear()
- cp(1,1)
- print("Touch a monitor to replace "..a)
- while true do
- local _event,_p1 = os.pullEvent("monitor_touch")
- if isMonitor(_p1) then
- print(_p1.." is already part of the save file")
- else
- skip[a] = true
- rMonitors[_p1] = a
- mC(_p1,dColor)
- peripheral.call(_p1,"clear")
- for a,b in pairs(image[a]) do
- for c,d in pairs(b) do
- if type(c) == "number" and type(a) == "number" then
- mP(_p1,c,a)
- mC(_p1,d)
- mW(_p1," ")
- end
- end
- end
- continue = false
- break
- end
- end
- elseif p1 == keys.two then --perm replace
- clear()
- cp(1,1)
- print("Touch a monitor to replace "..a.." permanantly")
- while true do
- local _event,_p1 = os.pullEvent("monitor_touch")
- if isMonitor(_p1) then
- print(_p1.." is already part of the save file")
- else
- image[_p1] = image[a]
- image[a] = nil
- continue = false
- break
- end
- end
- elseif p1 == keys.three then --skip this time
- skip[a] = true
- break
- elseif p1 == keys.four then --Remove
- image[a] = nil
- break
- elseif p1 == keys.five then --Cancel
- color(colors.red)
- print("Canceled")
- error("FORCEQUIT")
- end
- end
- end
- registerMonitors()
- for i = 1, #monitors do --Clear all the monitors
- if not rMonitors[monitors[i]] then
- mC(monitors[i],dColor)
- peripheral.call(monitors[i],"clear")
- end
- end
- for i = 1, #monitors do --Draw the image on the monitors
- if image[monitors[i]] then
- for a,b in pairs(image[monitors[i]]) do
- for c,d in pairs(b) do
- if type(c) == "number" and type(a) == "number" then
- mP(monitors[i],c,a)
- mC(monitors[i],d)
- mW(monitors[i]," ")
- end
- end
- end
- end
- end
- else --If the image doesn't exsist yet
- image["compID"] = os.getComputerID() --adds the comp id to the table. This is unused but could be nice to have someday
- end
- drawColorScreen()
- while true do --The main loop of the program
- event,p1,p2,p3 = os.pullEvent()
- if event == "monitor_touch" then --A monitor was right clicked
- if utilMonitor and p1 == utilMonitor then --Its the util monitor
- if clearM then --Turning clearmode off
- if p3 == 7 then
- clearM = false
- redrawScreens()
- end
- elseif changeUtilMon then --cancel this
- if p3 == 9 then
- changeUtilMon = false
- redrawScreens()
- end
- else --Change color,exit,clearmode,or change util mon
- if p3 == 4 and p2>1 and p2<18 then --color
- cColor = colorPos[p2-1]
- redrawScreens()
- elseif p3 == 6 then --Clear mode
- clearM = true
- redrawScreens()
- elseif p3 == 8 then --save and exit
- f = fs.open(args[2],"w")
- f.write(textutils.serialize(image))
- f.close()
- error("SAVED")
- elseif p3 == 10 then --Change util mon
- changeUtilMon = true
- redrawScreens()
- end
- end
- else --A regular Monitor
- if clearM then --Clear the monitor
- if rMonitors[p1] then --if the monitor is standing in for another
- p1 = rMonitors[p1]
- end
- image[p1] = {}
- image[p1]["size"] = {peripheral.call(p1,"getSize")}
- mC(p1,dColor)
- peripheral.call(p1,"clear")
- elseif changeUtilMon then --Possible select monitor for util monitor
- local _x,_y = peripheral.call(p1,"getSize")
- if _x > 17 and _y > 11 then --if its the right size
- if utilMonitor then
- mC(utilMonitor,dColor)
- peripheral.call(utilMonitor,"clear")
- if image[utilMonitor] then
- for a,b in pairs(image[utilMonitor]) do
- for c,d in pairs(b) do
- if type(c) == "number" and type(a) == "number" then
- mP(utilMonitor,c,a)
- mC(utilMonitor,d)
- mW(utilMonitor," ")
- end
- end
- end
- end
- end
- utilMonitor = p1
- changeUtilMon = false
- redrawScreens()
- end
- else --Drawing a pixel
- mP(p1,p2,p3) --Draw the pixel on the monitor
- mC(p1,cColor)
- mW(p1," ")
- if rMonitors[p1] then --if the monitor is standing in for another
- p1 = rMonitors[p1]
- end
- if not image[p1] then --Checks to make sure the tables exist
- image[p1] = {}
- image[p1]["size"] = {peripheral.call(p1,"getSize")}
- end
- if not image[p1][p3] then
- image[p1][p3] = {}
- end
- image[p1][p3][p2] = cColor --adds color here
- end
- end
- elseif event == "mouse_click" then --The mouse was clicked in the terminal
- if clearM then
- if p3 == 9 then
- clearM = false
- redrawScreens()
- end
- elseif changeUtilMon then
- if p3 == 11 then
- changeUtilMon = false
- redrawScreens()
- end
- else
- if p3 == 9 then --Select a color
- if p2>17 and p2<34 then
- cColor = colorPos[p2-17]
- redrawScreens()
- end
- elseif p3 == 11 then --Turn on clear mode
- clearM = not clearM
- redrawScreens()
- elseif p3 == 13 then --Change util mon
- changeUtilMon = true
- redrawScreens()
- elseif p3 == h then --save and exit
- f = fs.open(args[2],"w")
- f.write(textutils.serialize(image))
- f.close()
- error("SAVED")
- end
- end
- elseif event == "peripheral" then --a Peripheral was added
- if peripheral.getType(p1) == "monitor" then
- mC(p1,dColor)
- peripheral.call(p1,"clear")
- table.insert(monitors,p1)
- end
- elseif event == "monitor_resize" then --a monitor was broken or placed (on an exsisting monitor)
- error("STOPTOBESAFE:resize")
- elseif event == "peripheral_detach" then
- if itemsIn(image[p1]) > 0 then
- error("STOPTOBESAFE:detach")
- end
- end
- end
- end
- --Program--
- --Check everything is good
- color(colors.white,colors.black)
- if h ~= 19 or w ~= 51 then
- print("This doesn't work on pocket computers")
- return
- elseif shell.getRunningProgram() ~= fileName then
- print("This program should be named '"..fileName.."', not "..shell.getRunningProgram())
- if fs.exists(fileName) then
- color(colors.red)
- print("A program called '"..fileName.."' already exists, so this one couldn't be renamed")
- print("Please remove the program already named '"..fileName"'")
- color(colors.white)
- return
- end
- fs.move(shell.getRunningProgram(),fileName)
- print("File has been renamed")
- print("Try your operation again...")
- return
- end
- if args[1] == "draw" then --Displays a file, doens't allow editing
- state,err = pcall(function() draw() end)
- elseif args[1] == "edit" then --Displays a file
- state,err = pcall(function() edit() end)
- elseif args[1] == "delete" then
- print("Trying to delete something?")
- print("Just use 'delete <file>'")
- else
- usages()
- return
- end
- if not state then
- if string.find(err,"Terminated") then --Ctrl+t held
- term.setCursorBlink(false)
- color(colors.white,colors.black)
- clear()
- cp(1,1)
- print("Program terminated")
- elseif string.find(err,"FORCEQUIT") then --When i need to stop the program with no output
- --*clears throat*
- --Nothing to do here
- elseif string.find(err,"SAVED") then --When the file has been saved
- color(colors.lime,colors.black)
- clear()
- cp(1,1)
- print("Saved to '"..args[2].."'")
- color(colors.white)
- elseif string.find(err,"STOPTOBESAFE") then --When something went wrong
- color(colors.red,colors.black)
- clear()
- cp(1,1)
- if string.find(err,"resize") then
- print("A monitor's size was changed!")
- elseif string.find(err,"detach") then
- print("A monitor was removed!")
- end
- color(colors.white)
- print("The program stopped to prevent the save from being corrupted")
- print(" ")
- print("Do you want to save the changes made so far?")
- print("1:Yes")
- print("2:No")
- while true do
- local event,p1 = os.pullEvent("key")
- if p1 == keys.one then
- f = fs.open(args[2],"w")
- f.write(textutils.serialize(image))
- f.close()
- color(colors.lime)
- print("Saved")
- break
- elseif p1 == keys.two then
- color(colors.red)
- print("Not saved")
- break
- end
- end
- os.pullEvent("char")
- else --An actual error occurd
- color(colors.red,colors.black)
- tw("X")
- color(colors.white,colors.red)
- cp(1,1)
- tw(string.rep(" ",w))
- printC("Error - Press 'Tab'",1)
- waitForKey(keys.tab)
- color(colors.white,colors.black)
- clear()
- printC("Critical Error",1)
- cp(1,3)
- color(colors.white)
- if not err then
- print("The program errored, but no reason was given")
- else
- print(err)
- end
- end
- else
- color(colors.white,colors.black)
- clear()
- cp(1,1)
- print("Program Closed")
- end
- for i = 1, #monitors do --Clear all the monitors again
- mC(monitors[i],colors.black)
- peripheral.call(monitors[i],"clear")
- end
- if f then
- f.close()
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement