Advertisement
HPWebcamAble

[CC][2.0.1] File Manager

Sep 6th, 2015
2,785
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 37.00 KB | None | 0 0
  1. --[[
  2. HPWebcamAble Presents...
  3. File Manager
  4.  
  5. === Description ====
  6. This program adds a user interface for file browsing
  7.  
  8.  
  9. ==== Documentation ====
  10. ComputerCraft Forum:
  11. http://www.computercraft.info/forums2/index.php?/topic/24579-file-manager-20-history-run-w-args-grayscale-support/
  12.  
  13. Youtube Video:
  14. NOTE: This video is for Version 1.0, and is a little outdated now
  15. https://www.youtube.com/watch?v=pdaWStx-rwA
  16.  
  17.  
  18. ==== Installation and Use ====
  19. Pastebin Code: jKZBPFTs
  20.  
  21. pastebin get <code> fm
  22.  
  23. Then run 'fm' (Or what you called it)
  24.  
  25.  
  26. ==== Update History ====
  27. Pastebin will always have the most recent version
  28.  
  29. |2.0.1| <- This program
  30.   -Fixed detection of grayscale computers in CC 1.76
  31.  
  32. |2.0|
  33.   -Rewrite of almost entire program!
  34.   -Auto adjusts to display on almost any screen size
  35.   -Dipslay items as a list, or tiles
  36.   -Right click menu
  37.   -Click a selected item to open it
  38.   -Assign programs that should be used to run file endings
  39.     *For example: Use 'edit' to open .txt files
  40.   -Run programs with arguments (finally...)
  41.  
  42. |Before 2.0|
  43.   -Old, but still on PB:
  44.   http://pastebin.com/uz2f7Xbe
  45. ]]
  46.  
  47. --=== Variables ===--
  48. local version = "2.0.1"
  49. local w,h = term.getSize()
  50. local settings = {
  51.   colors = {
  52.     ["Full Color"] = {
  53.       headingText = colors.white,
  54.       headingBack = colors.blue,
  55.       back = colors.white,
  56.       text = colors.black,
  57.       selected = colors.lightBlue,
  58.       selectedText = colors.white,
  59.       folder = colors.yellow,
  60.       folderText = colors.white,
  61.       file = colors.lightGray,
  62.       fileText = colors.white,
  63.       inputBack = colors.black,
  64.       inputText = colors.white,
  65.       menuBack = colors.gray,
  66.       menuButtons = { text = colors.black, textSelected = colors.white, default = colors.lime, cancel = colors.red, disabled = colors.lightGray},
  67.     },
  68.     ["Gray Scale"] = {
  69.       headingText = colors.white,
  70.       headingBack = colors.black,
  71.       back = colors.white,
  72.       text = colors.black,
  73.       selected = colors.lightGray,
  74.       selectedText = colors.white,
  75.       folder = colors.gray,
  76.       folderText = colors.white,
  77.       file = colors.lightGray,
  78.       fileText = colors.white,
  79.       inputBack = colors.black,
  80.       inputText = colors.white,
  81.       menuBack = colors.gray,
  82.       menuButtons = { text = colors.white, textSelected = colors.white, default = colors.black, cancel = colors.black, disabled = colors.black},
  83.     },
  84.     ["Black and White"] = {
  85.       -- WIP
  86.     }
  87.   }
  88. }
  89. local colorType
  90.  
  91. local displayViews = { "List" , "Tiles" }
  92. local curView = displayViews[1]
  93.  
  94. local showText
  95.  
  96. --Directory stuff
  97. local curPath = {}
  98. local dir
  99. local pathFolders
  100. local pathFiles
  101. local selected
  102. local numSelect = 0
  103. local pathHistory = {{""}}
  104. local historyPos = 1
  105.  
  106. --Page stuff
  107. local perPage = 0
  108. local pages = 0
  109. local page = 0
  110.  
  111. --Screen constraints
  112. local minY = 3
  113. local maxY = h-1
  114. local minX = 1
  115. local maxX = w-1
  116.  
  117. --Types of items (File Endings)
  118. local items = {
  119.   {
  120.     name = "File",
  121.     create = function(path)
  122.       local f = fs.open(path,"w")
  123.       if not f then return false end
  124.       f.close()
  125.       return true
  126.     end,
  127.     equals = function(name)
  128.       local temp = split(name,".")
  129.       return #temp < 2
  130.     end,
  131.     open = function(path)
  132.       runProgram(path)
  133.     end
  134.   },
  135.   {
  136.     name = "Folder",
  137.     create = function(path)
  138.       fs.makeDir(path)
  139.       return fs.exists(path) and fs.isDir(path)
  140.     end,
  141.     equals = function(path)
  142.       return fs.isDir(path)
  143.     end
  144.   }
  145. }
  146. local itemsByName = {}
  147. for i = 1, #items do
  148.   itemsByName[items[i].name] = i
  149. end
  150.  
  151. --Key states
  152. local shiftHeld = false
  153. local ctrlHeld = false
  154.  
  155. --List view variables
  156. local midPage
  157.  
  158. --Screen API Vars
  159. local screens = {}
  160. local curScreen
  161. local default = {
  162.   object = {
  163.     test = "default",
  164.     name = "default",
  165.     minX = 1,
  166.     maxX = 7,
  167.     minY = 1,
  168.     maxY = 3,
  169.     colors = {
  170.       text = {
  171.         on = colors.white,
  172.         off = colors.white
  173.       },
  174.       back = {
  175.         on = colors.lime,
  176.         off = colors.red
  177.       }
  178.     },
  179.     hasClickArea = true,
  180.     state = true
  181.     --action isn't here, it isn't necesarry for the program to work
  182.   },
  183.   clickArea = {
  184.     name = "default",
  185.     minX = 1,
  186.     maxX = 5,
  187.     minY = 1,
  188.     maxY = 3,
  189.     state = true
  190.     --Again, action is left out
  191.   }
  192. }
  193.  
  194.  
  195. --=== Functions ===--
  196. local function printC(text,y,onlyCalc)--Prints text centered at y
  197.   y = tonumber(y)
  198.   if not y or not text then error("expected string,number got "..type(text)..","..type(y),2) end
  199.   local tLenght = #tostring(text)
  200.   local sStart = math.ceil(w/2-tLenght/2)
  201.   local sEnd = sStart + tLenght
  202.   term.setCursorPos(sStart,y)
  203.   term.write(text)
  204.   return sStart,sEnd
  205. end
  206.  
  207. local function split(sString,sep)
  208.   if sep == nil then sep = "%s" end
  209.   local t={}
  210.   for str in string.gmatch(sString, "([^"..sep.."]+)") do
  211.     table.insert(t,str)
  212.   end
  213.   return t
  214. end
  215.  
  216. local function scrollRead(x,y,nLength,insertText) --This is a simple scrolling-read function I made
  217.   if insertText then
  218.     insertText = tostring(insertText)
  219.     cPos = #insertText+1
  220.     cInput = insertText
  221.   else
  222.     cPos = 1
  223.     cInput = ""
  224.   end
  225.   term.setCursorBlink(true)
  226.   while true do
  227.     term.setCursorPos(x,y)
  228.     term.write(string.rep(" ",nLength))
  229.     term.setCursorPos(x,y)
  230.     if string.len(cInput) > nLength-1 then
  231.       term.write(string.sub(cInput,(nLength-1)*-1))
  232.     else
  233.       term.write(cInput)
  234.     end
  235.     if cPos > nLength-1 then
  236.       term.setCursorPos(x+nLength-1,y)
  237.     else  
  238.      term.setCursorPos(x+cPos-1,y)
  239.     end
  240.     local event,p1 = os.pullEvent()
  241.     if event == "char" then
  242.       cInput = string.sub(cInput,1,cPos)..p1..string.sub(cInput,cPos+1)
  243.       cPos = cPos + 1                  
  244.     elseif event == "key" then
  245.       if p1 == keys.enter then
  246.         break
  247.       elseif p1 == keys.backspace then
  248.         if cPos > 1 then
  249.           cInput = string.sub(cInput,1,cPos-2)..string.sub(cInput,cPos)
  250.           cPos = cPos - 1
  251.         end
  252.       elseif p1 == keys["end"] then
  253.         cPos = string.len(cInput)+1
  254.       end    
  255.     end
  256.   end
  257.   term.setCursorBlink(false)
  258.   return cInput
  259. end
  260.  
  261. local bytesInKiloByte = 1024
  262. local function toKiloBytes(nBytes)
  263.   return math.ceil(nBytes / bytesInKiloByte)
  264. end
  265.  
  266. local function getSize(path,shrink)
  267.   if not fs.exists(path) then return 0 end
  268.   if fs.isDir(path) then return 0 end
  269.   local size = fs.getSize(path)
  270.   if size == 0 then return "1 Byte" end
  271.   if size < bytesInKiloByte then return size.." Byte"..(size > 0 and "s" or "") end
  272.   return toKiloBytes(size)..(shrink and " KB" or " KiloBytes")
  273. end
  274.  
  275. --Functions from my Screen API
  276. local function assert(statement,errorText,errorLevel)
  277.   if not statement then
  278.     error(errorText,errorLevel+1)
  279.   end
  280. end
  281.  
  282. local function fillTable(toFill,fillWith) --Used by the API
  283.   for a,b in pairs(fillWith) do
  284.     if type(b) == "table" then
  285.       if not toFill then toFill = {} end
  286.       toFill[a] = fillTable(toFill[a],b)
  287.     else
  288.       if not toFill then toFill = {} end
  289.       toFill[a] = toFill[a] or b
  290.     end
  291.   end
  292.   return toFill
  293. end
  294.  
  295. --Misc--
  296. function checkPos(x,y,screen)
  297.   screen = screen or curScreen
  298.   assert(screens[screen],"screen '"..screen.."' doesn't exsist",2)
  299.   x = tonumber(x)
  300.   y = tonumber(y)
  301.   assert(x and y,"expected number,number",2)
  302.   local insideArea = {}
  303.   for name,data in pairs(screens[screen].clickAreas) do
  304.     if x >= data.minX and x <= data.maxX and y >= data.minY and y <= data.maxY and data.state == true then
  305.       if data.action then
  306.         return data.action()
  307.       else
  308.         return "click_area",name
  309.       end
  310.     end
  311.   end
  312.   for name,data in pairs(screens[screen].objects) do
  313.     if data.hasClickArea and data.state ~= "off" and x >= data.minX and x <= data.maxX and y >= data.minY and y <= data.maxY then
  314.       if data.action then
  315.         return data.action()
  316.       else
  317.         return "object",name
  318.       end
  319.     end
  320.   end
  321. end
  322.  
  323. function handleEvents(screen,useRaw)
  324.   screen = screen or curScreen
  325.   assert(screens[screen],"screen '"..screen.."' doesn't exsist",2)
  326.   local pull = os.pullEvent
  327.   if useRaw == true then
  328.     pull = os.pullEventRaw
  329.   end
  330.   local eArgs = {pull()}
  331.   if eArgs[1] == "mouse_click" then
  332.     local cType,name = checkPos(eArgs[3],eArgs[4],screen)
  333.     if type(name) == "string" then
  334.       return cType,name,eArgs[2]
  335.     end
  336.   end
  337.   return unpack(eArgs)
  338. end
  339.  
  340. function setDefaultObject(newDefaultObject)
  341.   assert(type(newDefaultObject) == "table","expected table, got "..type(newDefaultObject),2)
  342.   newDefaultObject = fillTable(newDefaultObject,default.object)
  343.   default.object = newDefaultObject
  344. end
  345.  
  346. function setDefaultClickArea(newDefaultClickArea)
  347.   assert(type(newDefaultClickArea) == "table","expected table, got "..type(newDefaultClickArea),2)
  348.   newDefaultClickArea = fillTable(newDefaultClickArea,default.clickArea)
  349.   default.clickArea = newDefaultClickArea
  350. end
  351.  
  352. --Screens--
  353. function addScreen(name,backColor,setToCurScreen)
  354.   assert(name,"expected name",2)
  355.   assert(screens[name] == nil,"screen '"..name.."' already exsits",2)
  356.   screens[name] = {
  357.     background = backColor or colors.white,
  358.     objects = {},
  359.     clickAreas = {}
  360.   }
  361.   if setToCurScreen then curScreen = name end
  362. end
  363.  
  364. function setScreen(name)
  365.   assert(screens[name] ~= nil,"screen doesn't exist",2)
  366.   curScreen = name
  367. end
  368.  
  369. function draw(name,place)
  370.   name = name or curScreen
  371.   assert(screens[name] ~= nil,"screen doesn't exist",2)
  372.   place = place or term
  373.   assert(type(place) == "table","place should be a table, or nil",2)
  374.   place.setBackgroundColor(screens[name].background)
  375.   place.clear()
  376.   for objName,objData in pairs(screens[name].objects) do
  377.     if objData.state ~= "off" then
  378.       drawObject(objName,name,place)
  379.     end
  380.   end
  381. end
  382.  
  383. function getScreen(name)
  384.   name = name or curScreen
  385.   assert(screens[name] ~= nil,"screen doesn't exist",2)
  386.   return screens[name]
  387. end
  388.  
  389. --Click Areas--
  390. function addClickArea(clickAreaInfo,screen)
  391.   screen = screen or curScreen
  392.   assert(screens[screen] ~= nil,"screen doesn't exist",2)
  393.   assert(type(clickAreaInfo) == "table","expected table, got "..type(clickAreaInfo),2)
  394.   clickAreaInfo = fillTable(clickAreaInfo,default.clickArea)
  395.   assert( screens[screen].clickAreas[clickAreaInfo.name] == nil,"a click area with the name '"..clickAreaInfo.name.."' already exsists")
  396.   screens[screen].clickAreas[clickAreaInfo.name] = clickAreaInfo
  397. end
  398.  
  399. function toggleClickArea(name,screen)
  400.   screen = screen or curScreen
  401.   assert(screens[screen] ~= nil,"screen doesn't exist",2)
  402.   assert(screens[screen].clickAreas[name] ~= nil,"Click Area '"..name.."' doesn't exsist",2)
  403.   screens[screen].clickAreas[name].state = not screens[screen].clickAreas[name].state
  404.   return screens[screen].clickAreas[name]
  405. end
  406.  
  407. --Objects--
  408. function addObject(objectInfo,screen)
  409.   screen = screen or curScreen
  410.   assert(screens[screen] ~= nil,"screen '"..screen.."' doesn't exist",2)
  411.   assert(type(objectInfo) == "table","expected table, got "..type(objectInfo),2)
  412.   objectInfo = fillTable(objectInfo,default.object)
  413.   assert(screens[screen].objects[objectInfo.name] == nil,"an object with the name '"..objectInfo.name.."' already exsists")
  414.   screens[screen].objects[objectInfo.name] = objectInfo
  415. end
  416.  
  417. function drawObject(name,screen,place)
  418.   screen = screen or curScreen
  419.   assert(screens[screen] ~= nil,"screen doesn't exist",2)
  420.   assert(screens[screen].objects[name] ~= nil,"Object '"..name.."' doesn't exsist",2)
  421.   place = place or term
  422.   assert(type(place) == "table","place should be a table, or nil",2)
  423.   local objData = screens[screen].objects[name]
  424.   assert(type(objData.state) == "boolean","Object '"..name.."' is off, and can't be drawn",2)
  425.   if objData.state == true then
  426.     place.setBackgroundColor(objData.colors.back.on)
  427.     place.setTextColor(objData.colors.text.on)
  428.   else
  429.     place.setBackgroundColor(objData.colors.back.off)
  430.     place.setTextColor(objData.colors.text.off)
  431.   end
  432.   for i = 0, objData.maxY-objData.minY do
  433.     place.setCursorPos(objData.minX,objData.minY+i)
  434.     place.write(string.rep(" ",objData.maxX-objData.minX+1))
  435.   end
  436.   if objData.text then
  437.     local xPos = objData.minX+math.ceil((objData.maxX-objData.minX+1)/2) - math.ceil(#tostring(objData.text)/2)
  438.     local yPos = objData.minY+(objData.maxY-objData.minY)/2
  439.     place.setCursorPos(xPos,yPos)
  440.     place.write(objData.text)
  441.   end  
  442. end
  443.  
  444. function toggleObjectState(name,screen)
  445.   screen = screen or curScreen
  446.   assert(screens[screen] ~= nil,"screen doesn't exist",2)
  447.   assert(screens[screen].objects[name] ~= nil,"Object '"..name.."' doesn't exsist",2)
  448.   if screens[screen].objects[name].state ~= true and screens[screen].objects[name].state ~= false then
  449.     screens[screen].objects[name].state = true
  450.   else
  451.     screens[screen].objects[name].state = not screens[screen].objects[name].state
  452.   end
  453.   return screens[screen].objects[name].state
  454. end
  455.  
  456. function getObjectState(name,screen)
  457.   screen = screen or curScreen
  458.   assert(screens[screen] ~= nil,"screen doesn't exist",2)
  459.   assert(screens[screen].objects[name] ~= nil,"Object '"..name.."' doesn't exsist",2)
  460.   return screens[screen].objects[name].state
  461. end
  462.  
  463. function changeObjectText(name,newText,screen)
  464.   screen = screen or curScreen
  465.   assert(screens[screen] ~= nil,"screen doesn't exist",2)
  466.   assert(screens[screen].objects[name] ~= nil,"Object '"..name.."' doesn't exsist",2)
  467.   assert(type(newText) == "nil" or type(newText) == "string","expected string,string or string,nil, got string"..type(newText))
  468.   screens[screen].objects[name].text = newText
  469. end
  470.  
  471. function toggleObject(name,screen)
  472.   screen = screen or curScreen
  473.   assert(screens[screen] ~= nil,"screen doesn't exist",2)
  474.   assert(screens[screen].objects[name] ~= nil,"Object '"..name.."' doesn't exsist",2)
  475.   if type(screens[screen].objects[name].state) == "boolean" then
  476.     screens[screen].objects[name].state = "off"
  477.   else
  478.     screens[screen].objects[name].state = true
  479.   end
  480.   return screens[screen].objects[name].state
  481. end
  482.  
  483. function setObjectText(name,setText,screen)
  484.   screen = screen or curScreen
  485.   assert(screens[screen] ~= nil,"screen doesn't exist",2)
  486.   assert(screens[screen].objects[name] ~= nil,"Object '"..name.."' doesn't exsist",2)
  487.   screens[screen].objects[name].text = setText
  488. end
  489. --End of Screen API
  490.  
  491. local function getPath(name)
  492.   local toReturn = table.concat(curPath,"/")
  493.   if name then
  494.     toReturn = toReturn.."/"..name
  495.   elseif #curPath == 0 then
  496.     return ""
  497.   end
  498.   return toReturn
  499. end
  500.  
  501. local function getCol(index,...)
  502.   local args = {...}
  503.   local col = settings.colors[colorType][index]
  504.   if type(col) == "table" then
  505.     col = col[args[1]]
  506.   end
  507.   if type(col) ~= "number" then
  508.     error("Color Scheme '"..colorType.."' doesn't have the color '"..index.."'",2)
  509.   end
  510.   return col
  511. end
  512.  
  513. local function textColor(...)
  514.   term.setTextColor( getCol(...) )
  515. end
  516.  
  517. local function backColor(...)
  518.   term.setBackgroundColor( getCol(...) )
  519. end
  520.  
  521. local viewSizeCalc = {
  522.   Tiles = function()
  523.    
  524.   end,
  525.   List = function()
  526.     maxY = h-1
  527.     maxX = w-1
  528.     perPage = maxY-minY
  529.     midPage = math.ceil(w/2)
  530.     pages = math.ceil(#dir/perPage)
  531.     if pages < 1 then pages = 1 end
  532.     page = 1
  533.     setScreen("screen_List")
  534.     for i = 1, perPage do
  535.       screens.screen_List.clickAreas[tostring(i)] = nil
  536.       addClickArea({
  537.         name = tostring(i),
  538.         minX = minX,
  539.         maxX = maxX,
  540.         minY = minY+i-1,
  541.         maxY = minY+i-1
  542.       })
  543.     end
  544.   end
  545. }
  546.  
  547. local viewDrawScreen = {
  548.   Tiles = function()
  549.    
  550.   end,
  551.   List = function()
  552.     for i = 1, perPage do
  553.       local curIndex = i+perPage*(page-1)
  554.       if curIndex > #dir then break end
  555.       local cur = dir[curIndex]
  556.       local back = getCol("back")
  557.       local text = getCol("text")
  558.       if cur.name == selected then back = getCol("selected") text = getCol("selectedText") end
  559.       term.setCursorPos(minX,minY+i-1)
  560.       term.setBackgroundColor(cur.back) term.write(" ") backColor("back") term.write(" ")
  561.       local toWrite = cur.name
  562.       if #toWrite > midPage-(minX+2) then
  563.         toWrite = toWrite:sub(1,midPage-(minX+2)-3).."..."
  564.       end
  565.       term.setBackgroundColor(back) term.setTextColor(text) term.write( toWrite..string.rep(" ",maxX-2-#toWrite) )
  566.       local size = getSize(getPath(cur.name),true)
  567.       if size ~= 0 then
  568.         term.setCursorPos(midPage+1,minY+i-1) term.write(size)
  569.       end
  570.     end
  571.   end
  572. }
  573.  
  574. local function sortDir()
  575.   selected = nil numSelect = 0
  576.   dir = fs.list(getPath())
  577.   pathFolders,pathFiles = {},{}
  578.   for i = 1, #dir do
  579.     local fullPath = getPath(dir[i])
  580.     if fs.isDir( fullPath ) then
  581.       table.insert(pathFolders,dir[i])
  582.     else
  583.       table.insert(pathFiles,dir[i])
  584.     end
  585.   end
  586.   dir = {}
  587.   for i = 1, #pathFolders do table.insert(dir,{name = pathFolders[i],text = getCol("folderText"),back = getCol("folder"),type = "Folder"}) end
  588.   for i = 1, #pathFiles do table.insert(dir,{name = pathFiles[i],text = getCol("fileText"),back = getCol("file"),type = "File"}) end
  589. end
  590.  
  591. local function drawScreen()
  592.   setScreen("main")
  593.   backColor("back")
  594.   term.clear()
  595.   paintutils.drawLine(1,1,w,1,getCol("headingBack"))
  596.   textColor("headingText")
  597.   printC( getPath() == "" and "Root - File Manager "..version or "/"..getPath() ,1)
  598.   backColor("back")
  599.   textColor("text")
  600.   printC("Page "..page.." of "..pages,h)
  601.   screens.main.objects.page_up.state = page > 1
  602.   drawObject("page_up")
  603.   screens.main.objects.page_down.state = page < pages
  604.   drawObject("page_down")
  605.   screens.main.objects.back.state = historyPos > 1
  606.   drawObject("back")
  607.   screens.main.objects.forward.state = historyPos < #pathHistory
  608.   drawObject("forward")
  609.   screens.main.objects.level_up.state = (getPath() ~= "")
  610.   drawObject("level_up")
  611.   viewDrawScreen[ curView ]()
  612.   textColor("text") backColor("back")
  613.   if showText then
  614.     printC(showText,h-1)
  615.   elseif selected then
  616.     printC(selected,h-1)
  617.   else
  618.     printC("Press 'h' for controls",h-1)
  619.   end
  620. end
  621.  
  622. local function pageUp()
  623.   if page > 1 then page = page-1 drawScreen() end
  624. end
  625.  
  626. local function pageDown()
  627.   if page < pages then page = page+1 drawScreen() end
  628. end
  629.  
  630. local doSizeCalc = nil -- Thanks for this tip, Lignum :)
  631.  
  632. local function back()
  633.   if historyPos > 1 then
  634.     historyPos = historyPos - 1
  635.     curPath = pathHistory[historyPos]
  636.     sortDir()
  637.     doSizeCalc()
  638.     drawScreen()
  639.   end
  640. end
  641.  
  642. local function forward()
  643.   if historyPos < #pathHistory then
  644.     historyPos = historyPos + 1
  645.     curPath = pathHistory[historyPos]
  646.     sortDir()
  647.     doSizeCalc()
  648.     drawScreen()
  649.   end
  650. end
  651.  
  652. local changePath = nil
  653. local function up()
  654.   if getPath() ~= "" then
  655.     local temp = {unpack(curPath)}
  656.     table.remove(temp,#temp)
  657.     changePath(temp)
  658.     selected = nil numSelect = 0
  659.     sortDir()
  660.     doSizeCalc()
  661.     drawScreen()
  662.   end
  663. end
  664.  
  665. doSizeCalc = function()
  666.   w,h = term.getSize()
  667.   screens.main.objects = {}
  668.   setScreen("main")
  669.   addObject({
  670.     name = "page_down", text = "v",
  671.     minX = w, maxX = w,
  672.     minY = h-2, maxY = h-2,
  673.     colors = { back = { on = getCol("menuButtons","default"), off = getCol("menuButtons","disabled")}},
  674.     action = pageDown
  675.   })
  676.   addObject({
  677.     name = "page_up", text = "^",
  678.     minX = w, maxX = w,
  679.     minY = 3, maxY = 3,
  680.     colors = { back = { on = getCol("menuButtons","default"), off = getCol("menuButtons","disabled")}},
  681.     action = pageUp
  682.   })
  683.   addObject({
  684.     name = "back", text = "<",
  685.     minX = 3, maxX = 3,
  686.     minY = 2, maxY = 2,
  687.     colors = { back = { on = getCol("menuButtons","default"), off = getCol("menuButtons","disabled")}},
  688.     action = back
  689.   })
  690.   addObject({
  691.     name = "forward", text = ">",
  692.     minX = 5, maxX = 5,
  693.     minY = 2, maxY = 2,
  694.     colors = { back = { on = getCol("menuButtons","default"), off = getCol("menuButtons","disabled")}},
  695.     action = forward
  696.   })
  697.   addObject({
  698.     name = "level_up", text = "Go Up",
  699.     minX = 7, maxX = 11,
  700.     minY = 2, maxY = 2,
  701.     colors = { back = { on = getCol("menuButtons","default"), off = getCol("menuButtons","disabled")}},
  702.     action = up
  703.   })
  704.   viewSizeCalc[ curView ]()
  705. end
  706.  
  707. changePath = function(newPath)
  708.   while historyPos < #pathHistory do
  709.     table.remove(pathHistory,#pathHistory)
  710.   end
  711.   curPath = newPath
  712.   if curPath[1] == "" then table.remove(curPath,1) end
  713.   table.insert(pathHistory,curPath)
  714.   historyPos = #pathHistory
  715.   sortDir()
  716.   showText = nil
  717. end
  718.  
  719. local function openDir(name)
  720.   if fs.isDir(getPath(name)) then
  721.     selected = nil
  722.     numSelect = 0
  723.     local temp = {unpack(curPath)}
  724.     table.insert(temp,name)
  725.     changePath(temp)
  726.     doSizeCalc()
  727.     showText = nil
  728.     drawScreen()
  729.     return true
  730.   end
  731.   return false
  732. end
  733.  
  734. local function enterDir()
  735.   backColor("headingBack") textColor("headingText")
  736.   local input = scrollRead(1,1,w,getPath())
  737.   if fs.isDir(input) then
  738.     changePath(split(input,"/"))
  739.     doSizeCalc()
  740.   else
  741.     showText = "Not a valid path"
  742.   end
  743.   drawScreen()
  744. end
  745.  
  746. local function runProgram(path,...)
  747.   if multishell then
  748.     shell.run("fg",path,...)
  749.   else
  750.     term.setBackgroundColor(colors.black) term.setTextColor(colors.white) term.clear() term.setCursorPos(1,1)
  751.     shell.run(path,...)
  752.     term.setCursorBlink( false )
  753.     print( "Press enter to continue" )
  754.     repeat
  755.       local event,key = os.pullEvent("key")
  756.     until key == keys.enter
  757.     drawScreen()
  758.   end
  759. end
  760.  
  761. local function properties()
  762.   local path,name
  763.   if selected then
  764.     path = getPath(selected)
  765.     name = selected
  766.   else
  767.     path = getPath()
  768.     name = fs.getName(path)
  769.   end
  770.  
  771.   local function drawPropertiesScreen()
  772.     backColor("back") term.clear()
  773.     paintutils.drawLine(1,1,w,1,getCol("headingBack"))
  774.     textColor("headingText")
  775.     printC("Properties",1)
  776.     backColor("back") textColor("text")
  777.     term.setCursorPos(2,3) term.write("Name: "..name)
  778.     local writePath = path
  779.     if writePath == "" then
  780.       writePath = "/"
  781.     end
  782.     term.setCursorPos(2,4) term.write("Path: "..writePath)
  783.     term.setCursorPos(2,6) term.write("Type: ")
  784.     if fs.isDir(path) then
  785.       term.write("Folder")
  786.     else
  787.       term.write("File")
  788.       term.setCursorPos(2,7) term.write("Size: "..getSize(path))
  789.     end
  790.     local attributes = {}
  791.     if fs.isReadOnly(path) then table.insert(attributes,"Read-Only") end
  792.     if name == shell.getRunningProgram() then table.insert(attributes,"Running") end
  793.     if #attributes > 0 then
  794.       term.setCursorPos(2,8) term.write("Attributes: "..table.concat(attributes,","))
  795.     end
  796.     printC("Click anywhere or hit a key to close",h)
  797.   end
  798.  
  799.   drawPropertiesScreen()
  800.   repeat
  801.     local event = os.pullEvent()
  802.   until event == "mouse_click" or event == "key"
  803.   doSizeCalc()
  804.   drawScreen()
  805. end
  806.  
  807. local function window(heading,height,width)
  808.   width = width or #heading + 4
  809.   local windowMinY = math.ceil(h/2-height/2)
  810.   local minX = math.ceil(w/2-width/2)
  811.   if heading then
  812.     term.setCursorPos(minX,windowMinY) textColor("headingText") backColor("headingBack")
  813.     term.write(string.rep(" ",width)) printC(heading,windowMinY)
  814.   end
  815.   backColor("menuBack")
  816.   for i = 1, height do
  817.     term.setCursorPos(minX,windowMinY+i)
  818.     term.write(string.rep(" ",width))
  819.   end
  820.   return minX,minX+width,windowMinY
  821. end
  822.  
  823. local function option(heading,choices,width,cancel)
  824.   if cancel then
  825.     table.insert(choices,{text = "Cancel",color = getCol("menuButtons","cancel")})
  826.   end
  827.   local _,_,windowMinY = window(heading,(#choices*2)+1,width)
  828.   if screens[name] then screens[name] = nil end
  829.   addScreen("option",colors.white,true)
  830.   local largest = 0
  831.   for i = 1, #choices do
  832.     if #choices[i].text > largest then
  833.       largest = #choices[i].text
  834.     end
  835.   end
  836.   largest = largest + 2
  837.   local pos = 2
  838.   local minButtonX = math.floor(w/2 - largest/2)
  839.   for i = 1, #choices do
  840.     addObject({
  841.       text = choices[i].text,
  842.       name = tostring(i),
  843.       minX = minButtonX,
  844.       maxX = minButtonX+largest,
  845.       minY = windowMinY+pos,
  846.       maxY = windowMinY+pos,
  847.       colors = {
  848.         text = { on = getCol("menuButtons","textSelected"), off = getCol("menuButtons","text")},
  849.         back = {
  850.           on = getCol("selected"),
  851.           off = (choices[i].color or getCol("menuButtons","default"))
  852.         }
  853.       }
  854.     })
  855.     toggleObjectState(tostring(i))
  856.     drawObject(tostring(i))
  857.     pos = pos+2
  858.   end
  859.   toggleObjectState("1")
  860.   drawObject("1")
  861.   local selectButton = 1
  862.   while true do
  863.     local event = {os.pullEvent()}
  864.     if event[1] == "mouse_click" then
  865.       local _,name = checkPos(event[3],event[4])
  866.       if name then selectButton = tonumber(name) break end
  867.     elseif event[1] == "key" then
  868.       if event[2] == keys.down then
  869.         if selectButton < #choices then
  870.           toggleObjectState(tostring(selectButton))
  871.           drawObject(tostring(selectButton))
  872.           selectButton = selectButton+1
  873.           toggleObjectState(tostring(selectButton))
  874.           drawObject(tostring(selectButton))
  875.         end
  876.       elseif event[2] == keys.up then
  877.         if selectButton > 1 then
  878.           toggleObjectState(tostring(selectButton))
  879.           drawObject(tostring(selectButton))
  880.           selectButton = selectButton-1
  881.           toggleObjectState(tostring(selectButton))
  882.           drawObject(tostring(selectButton))
  883.         end
  884.       elseif event[2] == keys.enter then
  885.         break
  886.       end
  887.     end
  888.   end
  889.   screens.option = nil
  890.   doSizeCalc()
  891.   drawScreen()
  892.   return selectButton
  893. end
  894.  
  895. local function getInput(heading,insertText,requireText)
  896.   os.queueEvent("Distraction") os.pullEvent("Distraction")
  897.   heading = heading or "Enter Text"
  898.   local windowMinX,windowMaxX,windowMinY = window(heading,3)
  899.   backColor("inputBack") textColor("inputText")
  900.   local input
  901.   repeat
  902.     input = scrollRead(windowMinX+1,windowMinY+2,windowMaxX-windowMinX-2,insertText)
  903.   until input ~= "" or not requireText
  904.   doSizeCalc()
  905.   drawScreen()
  906.   return input
  907. end
  908.  
  909. local function displayList(heading,elements)
  910.   local listTop = 3
  911.   local listBottom = h-2
  912.   local listLeft = 2
  913.   local perPage = listBottom-listTop
  914.   local tLines = {}
  915.  
  916.   for e = 1, #elements do
  917.     if e ~= 1 then table.insert(tLines," ") end
  918.     table.insert(tLines,elements[e][1])
  919.     for a = 1, #elements[e][2] do
  920.       table.insert(tLines,"  "..elements[e][2][a])
  921.     end
  922.   end
  923.  
  924.   pages = math.ceil(#tLines/perPage)
  925.  
  926.   local function redrawList()
  927.     backColor("back") term.clear()
  928.     paintutils.drawLine(1,1,w,1,getCol("headingBack"))
  929.     textColor("headingText") printC(heading,1)
  930.     for i = 1, #tLines do
  931.       if i > perPage then break end
  932.       local cur = i+perPage*(page-1)
  933.       if cur > #tLines then break end
  934.       textColor("text") backColor("back")
  935.       term.setCursorPos(listLeft,listTop+i-1)
  936.       term.write(tLines[cur])
  937.     end
  938.     printC("Hit 'enter' to continue",h)
  939.   end
  940.  
  941.   redrawList()
  942.   while true do
  943.     local event = {os.pullEvent()}
  944.     if event[1] == "key" then
  945.       if event[2] == keys.enter then
  946.         if page < pages then
  947.           page = page + 1
  948.           redrawList()
  949.         else
  950.           doSizeCalc()
  951.           drawScreen()
  952.           return
  953.         end
  954.       end
  955.     end
  956.   end
  957. end
  958.  
  959. local function runProgArgs(path)
  960.   local args = split(getInput("Enter Args - Separate each with a space",nil,true))
  961.   runProgram(path,unpack(args))
  962. end
  963.  
  964. local function rename()
  965.   if not fs.isReadOnly(getPath(selected)) then
  966.     local input = getInput("  Rename Item  ",selected,true)
  967.     if fs.exists(getPath(input)) then
  968.       showText = "Already exists!"
  969.     else
  970.       fs.move( getPath(selected) , getPath(input) )
  971.       selected = nil
  972.       numSelect = 0
  973.       sortDir()
  974.     end
  975.   else
  976.     showText = "This item is read-only"
  977.   end
  978.   drawScreen()
  979. end
  980.  
  981. local function create()
  982.   if not fs.isReadOnly(getPath()) then
  983.     local options = {}
  984.     for i = 1, #items do
  985.       options[i] = {text = items[i].name}
  986.     end
  987.     local choice = option("Create...",options,nil,true)
  988.     if choice ~= #options then
  989.       local input = getInput(" Enter ".. items[choice].name .." Name ",nil,true)
  990.       local itemPath = getPath(input)
  991.       if not fs.exists(itemPath) then
  992.         if not fs.isReadOnly(getPath()) then
  993.           if not items[choice].create( itemPath ) then
  994.             showText = "Unable to create "..items[choice].name
  995.           end
  996.         else
  997.         end
  998.       else
  999.         showText = input.." already exists"
  1000.       end
  1001.       sortDir()
  1002.     end
  1003.   else
  1004.     showText = "This folder is read-only"
  1005.   end
  1006.   drawScreen()
  1007. end
  1008.  
  1009. local function delete()
  1010.   if not fs.isReadOnly(getPath(selected)) then
  1011.     if option("Delete selected item?",{{text = "Delete"},{text = "Cancel"}}) == 1 then
  1012.       fs.delete(getPath(selected))
  1013.       sortDir()
  1014.     end    
  1015.   else
  1016.     showText = "This item is read-only"
  1017.   end
  1018.   drawScreen()
  1019. end
  1020.  
  1021. local function selectView()
  1022.   local temp = {}
  1023.   for i = 1, #displayViews do
  1024.     table.insert(temp,{text = displayViews[i]})
  1025.   end
  1026.   local choice = option("Select View (Current:"..curView..")",temp)
  1027.   screens["screen_"..curView] = nil
  1028.   curView = displayViews[choice]
  1029.   doSizeCalc()
  1030.   drawScreen()
  1031. end
  1032.  
  1033. local function help()
  1034.   displayList("File Manager Help",{
  1035.     {"General",
  1036.       {
  1037.         "Click / Use arrows to select an item",
  1038.         "Click / Enter to open selected item",
  1039.         "< and > / Forward and Back to navigate history",
  1040.         "Go Up / 'u' to go up a level",
  1041.         "Ctrl + (Click / Enter) to run with arguments"
  1042.       }
  1043.     },
  1044.     {"Mouse Controls",
  1045.       {
  1046.         "Left click to select an item",
  1047.         "Left click selected item to open or run",
  1048.         "Right Click background for options",
  1049.         "Right Click an item for options",
  1050.         "Click 'v' / '^' or scroll to navagate pages"
  1051.       }
  1052.     },
  1053.     {"Keyboard Controls",
  1054.       {
  1055.         "'x' to quit",
  1056.         "'o' for selected item options",
  1057.         "'o' with nothing selected for more options",
  1058.         "'c' to create an item",
  1059.         "'Tab' to enter a path",
  1060.         "Page Up / Down to navagate pages",
  1061.         "'e' to edit current item (Files only)",
  1062.         "'p' for selected item's Properties",
  1063.         "'r' to rename selected item",
  1064.         "'d' to delete selected item",
  1065.         "'u' to go up a level",
  1066.         "'Enter' to run or open",
  1067.         "Left / Right Arrow to navagate history",
  1068.       }
  1069.     }
  1070.   })
  1071. end
  1072.  
  1073. local function itemOptions()
  1074.   local temp = {
  1075.     {text = "Run"},
  1076.     {text = "Run with args"},
  1077.     {text = "Edit"},
  1078.     {text = "Rename"},
  1079.     {text = "Delete"},
  1080.     {text = "New..."},
  1081.     {text = "Properties"}
  1082.   }
  1083.   local choice = option(nil,temp,22,true)
  1084.   if choice == 1 then
  1085.     runProgram(selected)
  1086.   elseif choice == 2 then
  1087.     runProgArgs(getPath(selected))
  1088.   elseif choice == 3 then
  1089.     runProgram("edit",selected)
  1090.   elseif choice == 4 then
  1091.     rename()
  1092.   elseif choice == 5 then
  1093.     delete()
  1094.   elseif choice == 6 then
  1095.     create()
  1096.   elseif choice == 7 then
  1097.     properties()
  1098.   end
  1099. end
  1100.  
  1101. local function dirOptions()
  1102.   local temp = {
  1103.     {text = "View..."},
  1104.     {text = "New..."},
  1105.     {text = "Controls"},
  1106.     {text = "Properties"},
  1107.     {text = "Quit File Manager"}
  1108.   }
  1109.   local choice = option(nil,temp,22,true)
  1110.   if choice == 1 then
  1111.     selectView()
  1112.   elseif choice == 2 then
  1113.     create()
  1114.   elseif choice == 3 then
  1115.     help()
  1116.   elseif choice == 4 then
  1117.     properties()
  1118.   elseif choice == 5 then
  1119.     error("Terminated")
  1120.   end
  1121. end
  1122.  
  1123.  
  1124. --=== Program ===--
  1125. --Determine which color scheme to use
  1126. if term.isColor() then
  1127.   colorType = "Full Color"
  1128. elseif _CC_VERSION or _HOST then
  1129.   colorType = "Gray Scale"
  1130. else -- Must be using a CC version before Gray Scale
  1131.   print("Black and White displays are not supported at this time")
  1132.   print("You'll need to use and Advanced (Gold) Computer")
  1133.   return
  1134.   --colorType = "Black and White"
  1135. end
  1136.  
  1137. --Main Loop
  1138. local function main()
  1139.   addScreen("main",colors.white,true)
  1140.   addScreen("screen_List",colors.white)
  1141.   sortDir()
  1142.   doSizeCalc()
  1143.   drawScreen()
  1144.   while true do
  1145.     local event = { os.pullEvent() }
  1146.    
  1147.     if event[1] == "mouse_click" then
  1148.       if event[4] == 1 then
  1149.         enterDir()
  1150.       elseif not checkPos(event[3],event[4],"main") then
  1151.         local element,name = checkPos(event[3],event[4],"screen_List")
  1152.         if name then
  1153.           local cur = tonumber(name)+perPage*(page-1)
  1154.           if cur <= #dir then
  1155.             if event[2] == 1 then
  1156.               if cur == numSelect then
  1157.                 if not openDir(selected) then
  1158.                   if ctrlHeld then
  1159.                     runProgArgs(getPath(selected))
  1160.                   else
  1161.                     runProgram(getPath(selected))
  1162.                   end
  1163.                 end
  1164.               else
  1165.                 selected = dir[cur].name
  1166.                 numSelect = cur
  1167.                 drawScreen()
  1168.               end
  1169.             elseif event[2] == 2 then
  1170.               selected = dir[cur].name
  1171.               numSelect = cur
  1172.               drawScreen()
  1173.               itemOptions()
  1174.             end
  1175.           else
  1176.             selected = nil
  1177.             numSelect = nil
  1178.             drawScreen()
  1179.             if event[2] == 2 then dirOptions() end
  1180.           end
  1181.         else
  1182.           selected = nil
  1183.           numSelect = nil
  1184.           drawScreen()
  1185.         end
  1186.       end
  1187.     elseif event[1] == "key" then
  1188.       if event[2] == keys.down then
  1189.         if not selected and #dir ~= 0 then
  1190.           numSelect = 1
  1191.           selected = dir[numSelect].name
  1192.           page = 1
  1193.           drawScreen()
  1194.         elseif numSelect < #dir then
  1195.           numSelect = numSelect+1
  1196.           selected = dir[numSelect].name
  1197.           local selectedPage = math.ceil(numSelect/perPage)
  1198.           if selectedPage ~= page then page = selectedPage end
  1199.           drawScreen()
  1200.         end
  1201.       elseif event[2] == keys.up then
  1202.         if not selected and #dir ~= 0 then
  1203.           numSelect = 1
  1204.           selected = dir[numSelect].name
  1205.           drawScreen()
  1206.         elseif numSelect > 1 then
  1207.           numSelect = numSelect-1
  1208.           selected = dir[numSelect].name
  1209.           local selectedPage = math.ceil(numSelect/perPage)
  1210.           if selectedPage ~= page then page = selectedPage end
  1211.           drawScreen()
  1212.         end
  1213.       elseif event[2] == keys.enter then
  1214.         if selected then
  1215.           if not openDir(selected) then
  1216.             if ctrlHeld then
  1217.               runProgArgs(getPath(selected))
  1218.             else
  1219.               runProgram(getPath(selected))
  1220.             end
  1221.           end
  1222.         end
  1223.       elseif event[2] == keys.leftShift then
  1224.         shiftHeld = true
  1225.       elseif event[2] == keys.leftCtrl then
  1226.         ctrlHeld = true
  1227.       elseif event[2] == keys.pageUp then
  1228.         pageUp()
  1229.       elseif event[2] == keys.pageDown then
  1230.         pageDown()
  1231.       elseif event[2] == keys.tab then
  1232.         enterDir()
  1233.       elseif event[2] == keys.x then
  1234.         error("Terminated")
  1235.       elseif event[2] == keys.e then
  1236.         os.pullEvent("char") -- Get that stray 'e' char event
  1237.         runProgram("/rom/programs/edit",getPath(selected))
  1238.       elseif event[2] == keys.p then
  1239.         properties()
  1240.       elseif event[2] == keys.r and selected then
  1241.         rename()
  1242.       elseif event[2] == keys.c then
  1243.         create()
  1244.       elseif event[2] == keys.d and selected then
  1245.         delete()
  1246.       elseif event[2] == keys.u then
  1247.         up()
  1248.       elseif event[2] == keys.left then
  1249.         back()
  1250.       elseif event[2] == keys.right then
  1251.         forward()
  1252.       elseif event[2] == keys.h then
  1253.         help()
  1254.       elseif event[2] == keys.o then
  1255.         if selected then
  1256.           itemOptions()
  1257.         else
  1258.           dirOptions()
  1259.         end
  1260.       end
  1261.     elseif event[1] == "key_up" then
  1262.       if event[2] == keys.leftShift then
  1263.         shiftHeld = false
  1264.       elseif event[2] == keys.leftCtrl then
  1265.         ctrlHeld = false
  1266.       end
  1267.     elseif event[1] == "term_resize" then
  1268.       doSizeCalc()
  1269.       drawScreen()
  1270.     elseif event[1] == "mouse_scroll" then
  1271.       if event[2] > 0 then
  1272.         pageDown()
  1273.       else
  1274.         pageUp()
  1275.       end
  1276.     end
  1277.   end
  1278. end
  1279.  
  1280. local state,err = pcall(main)
  1281. if not state then
  1282.   if err then
  1283.     if err:find("Terminated") then
  1284.       term.setBackgroundColor(colors.black) term.setTextColor(colors.white)
  1285.       term.clear()
  1286.       printC("Thanks for using File Manager "..version,1)
  1287.       printC("By HPWebcamAble",2)
  1288.       term.setCursorPos(1,3)
  1289.     elseif err:find("FORCEQUIT") then
  1290.       -- Do nothing
  1291.     else
  1292.       term.setBackgroundColor(colors.black)
  1293.       term.setTextColor(colors.white)
  1294.       term.write("X")
  1295.       paintutils.drawLine(1,1,w,1,colors.black)
  1296.       printC("Error - Press Enter",1)
  1297.       repeat
  1298.         local event,key = os.pullEvent("key")
  1299.       until key == keys.enter
  1300.       term.clear()
  1301.       printC("Error!",1)
  1302.       term.setCursorPos(1,2)
  1303.       print(err)
  1304.       print(" ")    
  1305.     end
  1306.   else
  1307.     term.setBackgroundColor(colors.black) term.setTextColor(colors.white)
  1308.     term.clear()
  1309.     printC("An known error occured",1)
  1310.     print(" ")
  1311.   end
  1312. end
  1313.  
  1314. os.queueEvent("Distraction")
  1315. os.pullEvent("Distraction") -- Clear the event queue
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement