Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Desktop Shell by PaymentOption
- 31 October 2012
- This is a simple clickable desktop interface for ComputerCraft 1.46
- by dan200.
- Change Log:
- - 0.1: Initial Release.
- - 0.2:
- * Added scrolling for directories with more entries than the screen would permit.
- * Fixed some bugs with the backgrounds of the lists being abnormally long.
- * Refactored the way directory and position in the computer is handled.
- - 0.3: Changed scrolling from click triggered to mouse-wheel triggered.
- - 0.4: Added a fairly crass way to call programs with arguments using a text field.
- --]]
- --=VARIABLES===========================--
- local tScreenBuffer = {} -- This will be all of the text that is written to the screen that shouldn't be removed.
- local screenWidth, screenHeight = term.getSize() -- The x and y dimensions of the screen.
- local scrollOffset = 1 -- The amount of offsetting done by scrolling.
- local currentDirectory = nil -- The current directory that we are in. nil = Start menu.
- local EXIT_KEY = 14 -- This is the key that must be pressed to exit the program.
- --=END VARIABLES=======================--
- --=SCREEN BUFFER FUNCTIONS===============--
- -- Writes text to the screen while also adding an entry to the screen buffer.
- -- NOTE: Will reset the text color back to white and the background color
- -- back to black after the function completes.
- function writeToScreen(text, givenColor, givenBackgroundColor, givenPath)
- -- If the color given was invalid, then set it to white.
- local x, y = term.getCursorPos()
- giveColor = isColorValid(givenColor) or colors.white
- givenBackgroundColor = isColorValid(givenBackgroundColor) or colors.black
- table.insert(tScreenBuffer, {text = text, path = givenPath, xPos = x, yPos = y, textColor = givenColor, backgroundColor = givenBackgroundColor})
- term.setTextColor(givenColor)
- term.setBackgroundColor(givenBackgroundColor)
- term.write(text)
- -- Reset the text color to white and the background color to black.
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- end
- -- Empties the screen buffer.
- function dumpBuffer()
- tScreenBuffer = {}
- end
- -- Dumps the screen buffer and initializes it with the start option.
- function initalizeBuffer()
- dumpBuffer()
- term.setCursorPos(1, screenHeight)
- writeToScreen("START", colors.white, colors.blue)
- end
- -- Redraws all contents of the screen buffer to the screen.
- -- NOTE: Will reset the text color back to white and the background color
- -- back to black after the function completes.
- function redrawBuffer()
- for index, item in pairs(tScreenBuffer) do
- term.setBackgroundColor(item.backgroundColor)
- term.setTextColor(item.textColor)
- term.setCursorPos(item.xPos, item.yPos)
- term.write(item.text)
- end
- -- Reset the text color to white and the background color to black.
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- end
- -- Uses the screen buffer to draw the contents of a directory like a list.
- function drawDirectoryContents(directoryPath, xPos, yPos)
- -- Make sure that the directory given exists.
- if fs.isDir(directoryPath) then
- -- Get the contents of the directory.
- local directoryContents = fs.list(directoryPath)
- -- Append the length of all entries to the length of the longest entry in the table.
- -- This way when we draw the backgrounds for the items their backgroudns will all be the same length.
- directoryContents = appendContentsLengths(directoryContents, directoryPath)
- -- Use the 'writeToScreen' function to draw this directory's contents.
- for index = 1, #directoryContents do
- term.setCursorPos(xPos, yPos - index + 1)
- writeToScreen(directoryContents[index].label, colors.white, colors.gray, directoryContents[index].path)
- end
- end
- end
- -- Uses a table to draw the contents of a directory like a list.
- function drawTable(contents, xPos, yPos)
- for index = 1, #contents do
- term.setCursorPos(xPos, yPos - index + 1)
- writeToScreen(contents[index].label, colors.white, colors.gray, contents[index].path)
- end
- end
- --=END SCREEN BUFFER FUNCTIONS===========--
- --=COLOR FUNCTIONS=======================--
- -- Checks if a given color is valid. If the color is valid,
- -- then this function returns aforementioned color; if it's false,
- -- then nil is returned.
- function isColorValid(givenColor)
- for index, color in pairs(colors) do
- if color == givenColor then
- return givenColor
- end
- end
- -- If the loop completed without returning, then the color
- -- given is invalid and therefore this function will return nil.
- return nil
- end
- --=END COLOR FUNCTIONS===================--
- --=TEXT MANIPULATING FUNCTIONS===========--
- -- Returns the longest length of a string found in a given table.
- function getLongestLength(directoryPath)
- local directoryContents = fs.list(directoryPath) -- The contents of the directory to get the longest label of.
- local longestLength = 0 -- This will be the length of the longest entry in the table.
- for index, item in ipairs(directoryContents) do
- longestLength = math.max(longestLength, item:len()) -- Add one to accomodate the space for the '>' later.
- end
- return longestLength
- end
- -- Appends the length of all entries in a directory table with spaces so their
- -- lengths are all equal (the longest entry in the table).
- function appendContentsLengths(directoryContents, directoryPath)
- local longestLength = getLongestLength(directoryPath)
- -- Append the labels for all of the entries in the directory table using 'longestLength'
- -- so that they are of equal length.
- local appendage = "" -- The text to be added to t=each item.
- for index, item in ipairs(directoryContents) do
- -- If the current item is a directory, then add a '>' to the end of its label.
- if fs.isDir(directoryPath .. '/' .. item) then
- directoryContents[index] = {label = item .. string.rep(' ', longestLength - item:len()) .. '>', path = directoryPath .. '/' .. item}
- else
- directoryContents[index] = {label = item .. string.rep(' ', longestLength - item:len()) .. ' ', path = directoryPath .. '/' .. item}
- end
- end
- -- Return the appended directory contents as a table.
- return directoryContents
- end
- -- From a list of arguments seperated by spacing, this function returns a table
- -- with each argument separated by a space. BORROWED FROM: http://lua-users.org/wiki/SplitJoin
- -- Compatibility: Lua-5.1
- function splitArgs(str, pat)
- local t = {} -- NOTE: use {n = 0} in Lua-5.0
- local fpat = "(.-)" .. pat
- local last_end = 1
- local s, e, cap = str:find(fpat, 1)
- while s do
- if s ~= 1 or cap ~= "" then
- table.insert(t,cap)
- end
- last_end = e+1
- s, e, cap = str:find(fpat, last_end)
- end
- if last_end <= #str then
- cap = str:sub(last_end)
- table.insert(t, cap)
- end
- return t
- end
- --=END TEXT MANIPULATING FUNCTIONS=======--
- --=SCREEN UTILITY FUNCTIONS==============--
- -- Clears the screen of all text and repositions the cursor to the origin of the screen (1, 1).
- function clearScreen()
- term.clear()
- term.setCursorPos(1, 1)
- end
- -- Draws the current directory to the screen.
- function displayPath()
- -- If the current directory is longer than 25 characters, then truncate it to be drawn on the screen.
- local directory = currentDirectory
- if directory:len() > 25 then
- directory = directory:sub(1, 25)
- end
- -- Set the text color to yellow, the background to black, draw the directory, then reset the colors to white and black.
- term.setTextColor(colors.yellow)
- term.setBackgroundColor(colors.black)
- term.setCursorPos(screenWidth - directory:len(), screenHeight)
- term.write(directory)
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- end
- -- Gets a list of arguments from the user using read(), then returns those values
- -- in a table.
- function getArgumentsForProgram()
- term.setCursorPos(7, screenHeight)
- term.setTextColor(colors.yellow)
- term.setBackgroundColor(colors.purple)
- term.write(string.rep(' ', screenWidth - 7))
- term.setCursorPos(7, screenHeight)
- term.write("Args: ")
- local stringArguments = read()
- local tableArguments = splitArgs(stringArguments, ' ')
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- return tableArguments
- end
- --=END SCREEN UTILITY FUNCTIONS==========--
- --=MOUSE HANDLING FUNCTIONS==============--
- -- Checks if a mouse click was on an item drawn to the screen.
- -- Returns the index of the item clicked, or nil if no item was clicked.
- function getItemClicked(xClickPos, yClickPos)
- local itemIndex = nil -- The index of the item clicked if any.
- for index, item in pairs(tScreenBuffer) do
- -- Check if the click was on this item's line.
- if yClickPos == item.yPos then
- -- Check if the click's xPosition was within the area of the item.
- if xClickPos <= item.xPos + item.text:len() - 1 and xClickPos >= item.xPos then
- itemIndex = index
- end
- end
- end
- -- If any item was clicked, then the value returned will not be nil.
- return itemIndex
- end
- -- Performs the appropriate action in the case of a click.
- function handleClick(xClickPos, yClickPos, clickType)
- -- If there was a right click and we are deeper than the root directory, then back up one directory.
- if clickType == 2 then
- handleRightClick()
- scrollOffset = 1
- return
- end
- local itemIndex = getItemClicked(xClickPos, yClickPos)
- -- If an option was clicked then handle it.
- if itemIndex then
- -- If the start option was clicked some directory, no matter what, is expanded, then
- --- dump and reinitalize the buffer.
- if itemIndex == 1 then
- if #tScreenBuffer > 1 then
- initalizeBuffer()
- currentDirectory = nil
- scrollOffset = 1
- else
- initalizeBuffer()
- currentDirectory = ""
- scrollOffset = 1
- end
- else
- -- Loop through the contents of the screen buffer and check for items clicked.
- for index, item in pairs(tScreenBuffer) do
- if itemIndex == index then
- -- If the item clicked was a file, then run the file.
- if not fs.isDir(item.path) then
- -- Get arguments for the program to be called, then run the program.
- local tableArguments = getArgumentsForProgram()
- clearScreen()
- shell.run(item.path, unpack(tableArguments))
- -- If the item clicked was a directory, then reinitialize the buffer and
- -- expanded the directory.
- else
- initalizeBuffer()
- currentDirectory = item.path
- end
- end
- end
- end
- -- If no item was clicked, then dump and reinitialize the screen buffer.
- else
- initalizeBuffer()
- currentDirectory = nil
- scrollOffset = 1
- return
- end
- -- Draw the current directory.
- -- If the current directory has value 'nil' then we can assume this is the start menu; don't draw any directory.
- if currentDirectory then
- drawDirectoryContents(currentDirectory, 1, screenHeight - 1)
- end
- end
- -- Handles right clicks appropriately.
- function handleRightClick()
- if #tScreenBuffer > 1 then
- if currentDirectory then
- -- If the directory is the root, then initialize the buffer so only the start screen is displayed.
- if currentDirectory == '/' or currentDirectory == "" then
- currentDirectory = nil
- initalizeBuffer()
- -- If the directory is anything else, then back up the directory once.
- else
- local namePos = currentDirectory:find(fs.getName(currentDirectory))
- currentDirectory = currentDirectory:sub(1, namePos - 1)
- initalizeBuffer()
- drawDirectoryContents(currentDirectory, 1, screenHeight - 1)
- end
- end
- end
- end
- -- Handles the scrolling of the screen via mouse clicks.
- -- NOTE: Uses a global variable to handle the scroll offsetting.
- function handleScrollingWithMouse(clickedUp, directoryPath)
- local directoryContents = appendContentsLengths(fs.list(directoryPath), directoryPath)
- -- ^^The contents of the directory that will be scrollable.
- local scrolledDirectoryContents = {} -- The appended directory contents that incorporates the scroll offset.
- -- If the user clicked up, then scroll the list up one item.
- if clickedUp then
- -- Make sure the screen can be scrolled up more.
- if #directoryContents - scrollOffset + 1 > screenHeight - 1 then
- -- Get a scrolled up version of the directory contents.
- scrollOffset = scrollOffset + 1
- end
- -- If the user clicked down, then scroll the list down one item.
- else
- -- Make sure the screen can be scrolled down more.
- if #directoryContents + scrollOffset - 1 > #directoryContents then
- -- Get a scrolled down version of the directory contents.
- scrollOffset = scrollOffset - 1
- end
- end
- -- Append the directory contents with the scrolled directory contents table.
- for index = scrollOffset, #directoryContents do
- table.insert(scrolledDirectoryContents, directoryContents[index])
- end
- return scrolledDirectoryContents
- end
- --=END MOUSE HANDLING FUNCTIONS==========--
- --=LOGOS=================================--
- -- Draws the cannonShell logo with the screen buffer.
- function drawLogo()
- local tLogo = {
- [1] = "__ __ ",
- [2] = "\\ \\ / / ",
- [3] = " \\ v / __ ___ ___ _____ _ __",
- [4] = " > < / \\/ / |/ / |/ / _ \\| |/ /",
- [5] = " / ^ ( () <| / /| / ( (_) ) / / ",
- [6] = "/_/ \\_\\__/\\_\\__/ |__/ \\___/|__/ "
- }
- term.setTextColor(colors.cyan)
- for line = 4, #tLogo + 4 do
- term.setCursorPos(screenWidth/2 - tLogo[1]:len()/2, line)
- term.write(tLogo[line - 3])
- end
- end
- --=END LOGOS=============================--
- initalizeBuffer() -- Add the start option to the buffer.
- while true do
- clearScreen()
- drawLogo()
- redrawBuffer()
- -- if currentDirectory then displayPath() end -- Display the current directory that we are in.
- local event, clickType, xClickPos, yClickPos = os.pullEvent()
- -- If the mouse was clicked then handle aforementioned click appropriately.
- if event == "mouse_click" then
- handleClick(xClickPos, yClickPos, clickType)
- -- If the mouse wheel was scrolled then handle the scroll appropriately.
- elseif event == "mouse_scroll" then
- -- If the directory is not the start menu, then check for scrolling.
- if currentDirectory then
- initalizeBuffer()
- local scrollType = clickType == -1 and true or false
- drawTable(handleScrollingWithMouse(scrollType, currentDirectory), 1, screenHeight - 1)
- end
- -- If the exit key was pressed, then exit the program.
- elseif event == "key" then
- -- If escape was pressed then exit the program.
- if clickType == EXIT_KEY then
- clearScreen()
- term.setTextColor(colors.yellow)
- print(os.version())
- term.setTextColor(colors.white)
- break
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement