Posted 22 September 2012 - 08:01 AM
I just downloaded Computer Craft 1.42 pre-release, and I decided I wanted to write a decent looking word processor that you could print from, and here it is :D/>/>
UPDATE(S):
- Text is now centered when typing.
- The printing of new lines onto paper no longer appears as ?????? followed by what was in the previous lines.
- Margins are drawn to give the user a better feeling for where the end of the line is.
- A bug with the backspace method that allowed infinitely long lines was fixed.
- Tab support added (3 spaces).
- Arrow key movement added.
* Read routine rewritten to fix design flaws that were not allowing me to add certain features.
Here are some screenshots:
Code:
Pastebin link: http://pastebin.com/8GVsfU7b
I hope you like it! ;)/>/>
- PaymentOption
UPDATE(S):
- Text is now centered when typing.
- The printing of new lines onto paper no longer appears as ?????? followed by what was in the previous lines.
- Margins are drawn to give the user a better feeling for where the end of the line is.
- A bug with the backspace method that allowed infinitely long lines was fixed.
- Tab support added (3 spaces).
- Arrow key movement added.
* Read routine rewritten to fix design flaws that were not allowing me to add certain features.
Here are some screenshots:
Spoiler
ALBUM: http://imgur.com/a/FV3oCCode:
Spoiler
Trust me, it's much more organized in the pastebin paste. I lose a lot of indentation and white space when I post on the forums, so don't scowl too much when you see the following :P/>/>
-- Word processor written by PaymentOption for ComputerCraft 1.42 --
-- VARIABLES --
bPrinted = false -- Whether or not the document has been printed.
tDocument = {}
bHasPaper = false
nPaperCount = 0
nPaperWidth, nPaperHeight = 0,0
bHasInk = false
nInkCount = 0
bHasPrinter = false
sPrinterSide = nil
bFirstPage = false -- Whether or not the first page has been started.
-- The wrapped printer.
printer = nil
nScreenWidth, nScreenHeight = term.getSize()
nSelection = 1 -- The selection of the print confirmation dialog box.
---------------
-- INITIALIZATION METHODS --
-- Returns true and the side the printer exists on if there a printer is found.
function checkForPrinter()
local tSides = rs.getSides()
-- Run through all of the possible sides and check for a printer peripheral.
for index, side in ipairs( tSides ) do
-- If a printer is found.
if peripheral.isPresent( side ) and peripheral.getType( side ) == "printer" then
return true, side
end
end
-- No printer was found.
return false, nil
end
-- Returns the wrapped printer object.
function wrapPrinter( side )
return peripheral.wrap( side )
end
-- Returns true and the amount of paper if there is paper; false and nil if there is none.
function checkForPaper( side, printerWrap )
if printerWrap.getPaperLevel() > 0 then
return true, printerWrap.getPaperLevel()
else
return false, 0
end
end
-- Returns true and the amount of ink if there is ink; false and nil if there is none.
function checkForInk( side, printerWrap )
if printerWrap.getInkLevel() > 0 then
return true, printerWrap.getInkLevel()
else
return false, 0
end
end
-- Returns the width and height of the paper stored.
function getPaperDimensions( printerWrap )
return printerWrap.getPageSize()
end
-- Sets up the page to be printed on: clears it and repositions the cursor to (1, 1)
function setCursorToPrint( printerWrap )
clearPage() -- Clear the page of any previous data.
printerWrap.setCursorPos( 1, 1 )
end
-- Runs all necessary checks, if they pass then true is returned and all variables are setup.
function initializePrinterAndProgram()
local bPrinterExists, sSide = checkForPrinter()
local bPaper, bInk = false
local nPaper, nInk = 0
if bPrinterExists then
-- Assign the global printer wrap to the newly found and wrapped peripheral.
printer = wrapPrinter( sSide )
-- Check for paper and ink amounts.
bPaper, nPaper = checkForPaper( sSide, printer )
bInk, nInk = checkForInk( sSide, printer )
if bPaper and bInk then
-- Assign the global variables to their proper values.
bHasPaper = bPaper
bHasInk = bInk
nPaperCount = nPaper
nInkCount = nInk
bFirstPage = printer.newPage() -- Start the first page.
nPaperWidth, nPaperHeight = getPaperDimensions( printer )
setCursorToPrint( printer ) -- Setup the page so it is blank and the cursor is in the upper left hand corner (1, 1).
-- Report a successful printer initialization.
return true
-- There was either no paper, or no ink.
else
-- There was no paper.
if not bPaper then
return false, true -- bHasPaper = false, bHasInk = true
-- There was no ink, but there was paper.
else
return true, false -- bHasPaper = true, bHasInk = false
end
end
-- No printer was found.
else
return false
end
end
----------------------------
-- CUSTOM PRINTER METHODS --
-- Clears the current page of all textual data.
function clearPage()
for nCurrentHeight=1, nPaperHeight do
printer.setCursorPos( 1, nCurrentHeight )
printer.write( string.rep( " ", nPaperWidth ) )
end
end
-- Prints the page with the specified title and string.
function printPage( sTitle, tPage )
printer.setPageTitle( sTitle )
for nHeight=1, #tPage do
printer.setCursorPos( 1, nHeight )
printer.write( tPage[nHeight] )
end
if printer.endPage() then
return true
else
return false
end
end
----------------------------
-- TERMINAL ROUTINES (COMPUTER SPECIFIC METHODS) --
function clearScreen()
term.clear()
term.setCursorPos( 1, 1 )
end
-- Prints a string to the very center of the screen on the specified line.
function printCentered( nHeight, sString )
term.setCursorPos( nScreenWidth/2 - string.len( sString )/2, nHeight )
write( sString )
end
-- Prints a string to the very right of the screen on the specified line.
function printRight( nHeight, sString )
term.setCursorPos( nScreenWidth - string.len( sString ), nHeight )
write( sString )
end
-- Draws a box with a width of nBoxWidth.
function drawBox( nBoxWidth )
printCentered( 4, "+" .. string.rep( "-", nBoxWidth ) .. "+" )
for nHeight = 5, 12 do
printCentered( nHeight, "|" .. string.rep( " ", nBoxWidth ) .. "|" )
end
printCentered( 13, "+" .. string.rep( "-", nBoxWidth ) .. "+" )
end
-- Handles the key presses thrown when we're getting print confirmation.
function handleKeyPress( nKey )
-- If the right key is pressed and the current selection is 'YES'.
if nKey == 205 and nSelection == 1 then
nSelection = 2
-- If the left key is pressed and the current selection is 'NO'.
elseif nKey == 203 and nSelection == 2 then
nSelection = 1
-- If the enter key is pressed.
elseif nKey == 28 then
-- If the user wants to print then print the prompt the user for a tile to the document.
if nSelection == 1 then
local sPageTitle = getPageTitle()
if printPage( sPageTitle, tDocument ) then
-- End the program.
clearScreen()
print( os.version() )
bPrinted = true
else
clearScreen()
print( os.version() )
error( "Printing error!" )
end
-- If the user does not want to print the re-edit the document.
elseif nSelection == 2 then
tDocument = readLines( tDocument )
getConfirmation()
end
end
end
-- Reads a fixed amount of characters without ruining a GUI that may be printed on the same line.
function limitRead( nLength, cReplaceChar )
term.setCursorBlink( true )
nLength = nLength or -1 -- -1 is unlimited
sReturnString = ""
xPos, yPos = term.getCursorPos()
while true do
event, char = os.pullEvent()
if nLength ~= -1 and string.len( sReturnString ) >= nLength then term.setCursorBlink( false ); return sReturnString end -- Length check
if event == "char" then sReturnString = sReturnString .. char
elseif event == "key" and char == 28 then term.setCursorBlink( false ); return sReturnString -- Enter
elseif event == "key" and char == 14 then -- Backspace
term.setCursorPos( xPos, yPos )
term.write( string.rep( " ", string.len( sReturnString ) ) )
sReturnString = string.sub( sReturnString, 1, string.len( sReturnString )-1 )
term.setCursorPos( xPos, yPos )
if not cReplaceChar then term.write( sReturnString )
else term.write( string.rep( cReplaceChar, string.len( sReturnString ) ) ) end
end
term.setCursorPos( xPos, yPos )
term.write( string.rep( " ", string.len( sReturnString ) ) )
term.setCursorPos( xPos, yPos )
if not cReplaceChar then term.write( sReturnString )
else term.write( string.rep( cReplaceChar, string.len( sReturnString ) ) ) end
end
end
-- Takes a line and checks if a word has not finished. If it hasn't
-- then it returns the table of lines with the corrected new line.
--[[function fixTruncation( tLines )
-- Remove the n chracter.
sLine = sLine:sub( 1, string.len( sLine ) - 1 )
-- Check if the line has not finished.
if tLines[#tLines]:sub( 1, 2 ) ~= " " then
for in string.gfind( )
tLines[#tLines - 1] = tLines[#tLines - 1]:sub( 1, )
end
end--]]
-- TODO: Remove the truncation effect when jumping lines.
-- Reads multiple lines as one string.
function readLines( tLines )
term.setCursorBlink( true )
local bExistingDocument = nil
if tLines then
bExistingDocument = true
else
bExistingDocument = true
end
local tLines = tLines or {}
local nLineWidthCap = nPaperWidth
local nLineCap = nScreenHeight
-- Initialize the lines.
if #tLines == 0 then
for nLine = 1, nLineCap do
tLines[nLine] = ""
end
end
local nReturnKey = 207 -- 'End'
local nCursorPosX = 1
local nCurrentLine = 1
local nCurrentLineLength = 0
-- Draws the paper border so people know where the page ends.
local function drawBorder()
for nHeight = 1, nScreenHeight do
term.setCursorPos( 12, nHeight )
term.write( "|" )
term.setCursorPos( 12 + nPaperWidth + 1, nHeight )
term.write( "|" )
end
term.setCursorPos( 1, nScreenHeight )
term.write( "'END' menu" )
printRight( nScreenHeight, "Ln " .. nCurrentLine .. " of ".. nScreenHeight )
end
clearScreen()
drawBorder()
if bExistingDocument then
for nHeight=1, #tLines do
term.setCursorPos( 13, nHeight )
term.write( tLines[nHeight] )
end
end
while nCurrentLine < nLineCap do
term.setCursorPos( 13 + nCursorPosX - 1, nCurrentLine )
local sEvent, cChar = os.pullEvent()
if sEvent == "char" then
if tLines[nCurrentLine]:len() + 1 < nLineWidthCap then
tLines[nCurrentLine] = tLines[nCurrentLine]:sub( 1, nCursorPosX - 1 ) .. cChar .. tLines[nCurrentLine]:sub( nCursorPosX, tLines[nCurrentLine]:len() )
nCursorPosX = nCursorPosX + 1
else
if nCurrentLine + 1 <= nLineCap then
tLines[nCurrentLine] = tLines[nCurrentLine] .. cChar
nCurrentLine = nCurrentLine+1
nCursorPosX = 1
else
term.setCursorBlink( false )
return tLines
end
end
elseif sEvent == "key" then
if cChar == 14 then
if nCursorPosX - 1 > 0 then
tLines[nCurrentLine] = tLines[nCurrentLine]:sub( 1, nCursorPosX - 2 ) .. tLines[nCurrentLine]:sub( nCursorPosX, tLines[nCurrentLine]:len() )
nCursorPosX = nCursorPosX - 1
else
if nCurrentLine > 1 then
nCurrentLine = nCurrentLine - 1
if tLines[nCurrentLine]:len() == nLineWidthCap then
tLines[nCurrentLine] = tLines[nCurrentLine]:sub( 1, tLines[nCurrentLine]:len() - 1 )
end
nCursorPosX = tLines[nCurrentLine]:len() + 1
end
end
elseif cChar == 28 then
if nCurrentLine + 1 <= nLineCap then
nCurrentLine = nCurrentLine+1
nCursorPosX = 1
else
term.setCursorBlink( false )
return tLines
end
elseif cChar == 203 then
if nCursorPosX - 1 > 1 then
nCursorPosX = nCursorPosX - 1
end
elseif cChar == 205 then
if nCursorPosX + 1 < tLines[nCurrentLine]:len() + 2 then
nCursorPosX = nCursorPosX + 1
end
elseif cChar == 200 then
if nCurrentLine - 1 > 0 then
nCurrentLine = nCurrentLine - 1
if tLines[nCurrentLine]:len() < nCursorPosX then
if tLines[nCurrentLine]:len() > 0 then
nCursorPosX = tLines[nCurrentLine]:len()
else
nCursorPosX = 1
end
end
end
elseif cChar == 208 then
if nCurrentLine + 1 < #tLines then
nCurrentLine = nCurrentLine + 1
if tLines[nCurrentLine]:len() < nCursorPosX then
if tLines[nCurrentLine]:len() > 0 then
nCursorPosX = tLines[nCurrentLine]:len()
else
nCursorPosX = 1
end
end
end
elseif cChar == 15 then
if tLines[nCurrentLine]:len() + 3 > nLineWidthCap then
local nSpaceLeft = nLineWidthCap - tLines[nCurrentLine]:len()
if nSpaceLeft > 0 then
tLines[nCurrentLine] = tLines[nCurrentLine] .. string.rep( " ", nSpaceLeft )
end
nCurrentLine = nCurrentLine + 1
nCursorPosX = 1
else
tLines[nCurrentLine] = tLines[nCurrentLine] .. " "
nCursorPosX = nCursorPosX + 3
end
elseif cChar == nReturnKey then
term.setCursorBlink( false )
return tLines
end
end
clearScreen()
drawBorder()
for nHeight=1, #tLines do
term.setCursorPos( 13, nHeight )
term.write( tLines[nHeight] )
end
end
term.setCursorBlink( false )
return tLines
end
---------------------------------------------------
-- SCREENS --
-- This method gets whether or not the user wants to print the document typed. (used in drawAndGetPrintConfirmationScreen)
function getConfirmation()
local function drawSelections()
if nSelection == 1 then
printCentered( 9, "[YES] NO " )
elseif nSelection == 2 then
printCentered( 9, " YES [NO]" )
end
end
-- Draw the confirmation options.
drawBox( 20 )
printCentered( 6, "PRINT?" )
-- Get a 'YES' or 'NO' from the user with a simple menu.
while not bPrinted do
drawSelections()
local sEvent, nKey = os.pullEvent( "key" )
if nKey == 28 or nKey == 205 or nKey == 203 then
handleKeyPress( nKey )
end
end
return true
end
-- Gets the title for the page to be printed.
function getPageTitle()
drawBox( 20 )
printCentered( 6, "Page Title:" )
term.setCursorPos( nScreenWidth/2 - 9, 9 )
local sPageTitle = tostring( limitRead( 18 ) )
if not sPageTitle or string.len( sPageTitle ) == 0 then
sPageTitle = "Default_PageTitle"
end
return sPageTitle
end
-- This screen will prompt the user for a yes or no answer.
function drawAndGetPrintConfirmationScreen()
getConfirmation()
end
------------
initializePrinterAndProgram()
tDocument = readLines()
drawAndGetPrintConfirmationScreen()
Pastebin link: http://pastebin.com/8GVsfU7b
I hope you like it! ;)/>/>
- PaymentOption