diff --git a/pain.lua b/pain.lua index 0c9b8f5..0fca38a 100644 --- a/pain.lua +++ b/pain.lua @@ -4,7 +4,7 @@ wget https://raw.githubusercontent.com/LDDestroier/CC/master/pain.lua pain pastebin get wJQ7jav0 pain std ld pain pain - + This is a stable release. You fool! --]] local askToSerialize = false @@ -96,6 +96,7 @@ local firstBG = term.getBackgroundColor() local firstTX = term.getTextColor() local changedImage = false local isCurrentlyFilling = false +local theClipboard = {} local _ local tableconcat = table.concat @@ -165,8 +166,8 @@ end local cutString = function(max_line_length, str) -- from stack overflow local lines = {} local line - str:gsub('(%s*)(%S+)', - function(spc, word) + str:gsub('(%s*)(%S+)', + function(spc, word) if not line or #line + #spc + #word > max_line_length then lines[#lines+1] = line line = word @@ -271,20 +272,20 @@ Hotkeys: left/right ctrl: Toggle the menu left click: - +left shift = Drag and let go to make a line - -alone = Place pixel + +left shift = Drag and let go to draw a line + -alone = Place a dot - right click: delete pixel + Right Click: delete pixel - middle click OR "t": Place text down with current colors, cancel with X + Middle Click, or "T": Place text down with current colors; cancel with X - "z": + "Z": +left alt = Redo -alone = Undo - "p": Pick colors from position onscreen; cancel with X + "P": Pick colors from position onscreen; cancel with X - "n": + "N": +left shift = Change character to that of a special character -alone = Change box character for drawing (cancel with CTRL, N, or by clicking outside) @@ -303,11 +304,11 @@ Hotkeys: "F3:" -alone = View all connected monitors - spacebar: + Spacebar: +shift = Toggle background grid -alone = Toggle bar visibility - arrow keys: + Arrow keys: +shift = Displaces the entire frame +tab = Moves canvas one pixel at a time -alone = Looks around the canvas smoothly @@ -325,23 +326,29 @@ Hotkeys: (oh good, you're actually reading this stuff) - "a": Set the coordinates to 0,0 + "A": Set the coordinates to 0,0 - "n": Open block character selection + "N": Open block character selection - "b": Toggle redirect to blittle, to preview in teletext characters + "B": Toggle redirect to blittle, to preview in teletext characters - "c": Input coordinates to scroll over to + "c": + +alt = Select region to copy to specified clipboard + -alone = Input coordinates to scroll over to - "g": toggle grayscale mode. + "LeftAlt + X": Select region to cut to specified clipboard + + "LeftAlt + X": Pastes from specified clipboard + + "G": toggle grayscale mode. Everything is in shades of gray. If you Save, it saves in grayscale. - "f": + "F": +left shift = fill all empty pixels with background color and selected box character -alone = activate fill tool - click anywhere to fill with color - "m": set metadata for pixels (for game makers, otherwise please ignore) + "M": set metadata for pixels (for game makers, otherwise please ignore) ================================== Thy Menu (accessible with CTRL): @@ -832,7 +839,7 @@ local renderPainyThings = function(xscroll,yscroll,doGrid) local badchar = "/" local blittlelabel = "blittle max" local screenlabel = "screen max" - + local dotBuffChar, dotBuffBack = "", "" --only used if gridBleedThrough is true local doot if doGrid then @@ -1332,7 +1339,7 @@ local NFPserializeImage = function(str) output[y] = {} for x = 1, #bepis[y] do output[y][x] = BTC(bepis[y]:sub(x,x),true) - end + end end return textutils.unserialize(textutils.serialize(output):gsub("\n",""):gsub(" ",""):gsub(",}","}")) end @@ -1567,15 +1574,15 @@ local exportToNFT = function(input) local bgcode, txcode = "\30", "\31" local output = "" local text, back - + local doot, pheight, pwidths = tableFormatPE(input) - + for y = 1, pheight do - + text, back = "0", "f" if doot[y] then for x = 1, pwidths[y] do - + if doot[y][x] then if doot[y][x].back ~= back then back = doot[y][x].back @@ -1589,10 +1596,10 @@ local exportToNFT = function(input) else output = output .. " " end - + end end - + if y < pheight then output = output .. "\n" end @@ -1975,13 +1982,13 @@ local specialCharSelector = function() end local evt, butt, x, y render() - + term.setCursorPos(1,scr_y) term.setBackgroundColor(colors.lightGray) term.setTextColor(colors.black) term.clearLine() term.write("Press CTRL or 'N' when ready.") - + while true do evt, butt, x, y = os.pullEvent() if (evt == "mouse_click" or evt == "mouse_drag") then @@ -2368,7 +2375,7 @@ local displayMenu = function() end local aboutPAIN = function() local helpText = [[ - +                  @@ -2767,6 +2774,68 @@ local listAllMonitors = function() doRender = true end +local selectRegion = function() + local position = {} + local mevt, id, x1, y1 = os.pullEvent("mouse_click") + local x2, y2, pos, redrawID + local renderRectangle = true + redrawID = os.startTimer(0.5) + while true do + mevt, id, x2, y2 = os.pullEvent() + if mevt == "mouse_up" or mevt == "mouse_drag" or mevt == "mouse_click" then + pos = {{ + x1 < x2 and x1 or x2, + y1 < y2 and y1 or y2 + },{ + x1 < x2 and x2 or x1, + y1 < y2 and y2 or y1 + }} + end + if mevt == "mouse_up" then + break + end + if (mevt == "mouse_drag") or (mevt == "timer" and id == redrawID) then + renderAllPAIN() + if renderRectangle then + term.setTextColor(rendback.t) + term.setBackgroundColor(rendback.b) + for y = pos[1][2], pos[2][2] do + if y ~= scr_y then + term.setCursorPos(pos[1][1], y) + if (y == pos[1][2] or y == pos[2][2]) then + term.write(("#"):rep(1 + pos[2][1] - pos[1][1])) + else + term.write("#") + term.setCursorPos(pos[2][1], y) + term.write("#") + end + end + end + end + end + if (mevt == "timer" and id == redrawID) then + renderRectangle = not renderRectangle + redrawID = os.startTimer(0.25) + end + end + local output = {} + for k,v in pairs(paintEncoded[frame]) do + if v.x >= pos[1][1] and v.x <= pos[2][1] then + if v.y >= pos[1][2] and v.y <= pos[2][2] then + output[#output+1] = { + x = v.x - pos[1][1], + y = v.y - pos[1][2], + t = v.t, + c = v.c, + b = v.b, + m = v.m + } + end + end + end + return output, pos[1][1], pos[1][2], pos[2][1], pos[2][2] +end + local getInput = function() --gotta catch them all local button, x, y, oldmx, oldmy, origx, origy local isDragging = false @@ -2819,12 +2888,12 @@ local getInput = function() --gotta catch them all end linePoses = {{x=oldmx,y=oldmy},{x=x,y=y}} miceDown[button] = true - doRender = true if y <= scr_y-(renderBlittle and 0 or doRenderBar) then if (button == 3) then putDownText(x,y) miceDown = {} keysDown = {} + doRender = true elseif button == 1 then if keysDown[keys.leftShift] and evt[1] == "mouse_click" then isDragging = true @@ -2834,6 +2903,12 @@ local getInput = function() --gotta catch them all dragPoses[1] = {x=x,y=y} end dragPoses[2] = {x=x,y=y} + local points = getDotsInLine(dragPoses[1].x,dragPoses[1].y,dragPoses[2].x,dragPoses[2].y) + renderAllPAIN() + for a = 1, #points do + term.setCursorPos(points[a].x, points[a].y) + term.blit(paint.c, CTB(paint.t), CTB(paint.b)) + end elseif (not dontDragThisTime) then if evt[1] == "mouse_drag" then local points = getDotsInLine(linePoses[1].x,linePoses[1].y,linePoses[2].x,linePoses[2].y) @@ -2844,11 +2919,13 @@ local getInput = function() --gotta catch them all putDotDown({x=x, y=y}) end changedImage = true + doRender = true end dontDragThisTime = false elseif button == 2 and y <= scr_y-(renderBlittle and 0 or doRenderBar) then deleteDot(x+paint.scrollX,y+paint.scrollY) changedImage = true + doRender = true end elseif origy >= scr_y-(renderBlittle and 0 or doRenderBar) then miceDown = {} @@ -2921,9 +2998,64 @@ local getInput = function() --gotta catch them all if (not renderBlittle) then -- you know what's coming if (key == keys.c) then - + local board = bottomPrompt("Copy to board: ") + renderAllPAIN() + renderBottomBar("Select region to copy.") + local selectedDots = selectRegion() + theClipboard[board] = selectedDots + barmsg = "Copied to '"..board.."'" + doRender = true + keysDown = {} + miceDown = {} + elseif (key == keys.x) then + local board = bottomPrompt("Cut to board: ") + renderAllPAIN() + renderBottomBar("Select region to copy.") + local selectedDots, x1, y1, x2, y2 = selectRegion() + theClipboard[board] = selectedDots + local dot + for i = #paintEncoded[frame], 1, -1 do + dot = paintEncoded[frame][i] + if dot.x >= x1 and dot.x <= x2 then + if dot.y >= y1 and dot.y <= y2 then + table.remove(paintEncoded[frame], i) + end + end + end + barmsg = "Cut to '"..board.."'" + doRender = true + saveToUndoBuffer() + keysDown = {} + miceDown = {} elseif (key == keys.v) then - + local board = bottomPrompt("Paste from board: ") + renderAllPAIN() + renderBottomBar("Click to paste. (top left corner)") + if theClipboard[board] then + local mevt + repeat + mevt = {os.pullEvent()} + until (mevt[1] == "key" and mevt[2] == keys.x) or (mevt[1] == "mouse_click" and mevt[2] == 1 and (mevt[4] or scr_y) <= scr_y-1) + for k,v in pairs(theClipboard[board]) do + paintEncoded[frame][#paintEncoded[frame]+1] = { + x = v.x + paint.scrollX + (mevt[3]), + y = v.y + paint.scrollY + (mevt[4]), + c = v.c, + t = v.t, + b = v.b, + m = v.m + } + end + paintEncoded[frame] = clearRedundant(paintEncoded[frame]) + barmsg = "Pasted from '"..board.."'" + doRender = true + saveToUndoBuffer() + keysDown = {} + miceDown = {} + else + barmsg = "No such clipboard." + doRender = true + end end end else @@ -3093,7 +3225,7 @@ local getInput = function() --gotta catch them all changedImage = true isDragging = false end - if key == keys.p then + if key == keys.p then renderBottomBar("Pick color with cursor:") paintEncoded = clearAllRedundant(paintEncoded) local mevt @@ -3229,7 +3361,7 @@ runPainEditor = function(...) --needs to be cleaned up if not (tArg[1] == "-n" or (not tArg[1])) then fileName = shell.resolve(tostring(tArg[1])) end - + if not fileName then paintEncoded = {{}} elseif not fs.exists(fileName) then @@ -3267,7 +3399,7 @@ runPainEditor = function(...) --needs to be cleaned up return print(defaultSaveFormat) end end - + local asyncFillTool = function() local event, frameNo, x, y, dot isCurrentlyFilling = false @@ -3280,7 +3412,7 @@ runPainEditor = function(...) --needs to be cleaned up reRenderPAIN(doRenderBar == 0) end end - + if not paintEncoded[frame] then paintEncoded = {paintEncoded} end if pMode == 1 then doRenderBar = 0 @@ -3293,7 +3425,7 @@ runPainEditor = function(...) --needs to be cleaned up lastPaintEncoded = deepCopy(paintEncoded) undoBuffer = {deepCopy(paintEncoded)} parallel.waitForAny(getInput, doNonEventDrivenMovement, asyncFillTool) - + term.setCursorPos(1,scr_y) term.setBackgroundColor(colors.black) term.clearLine()