LDShadowLord

SublimeOS File Browser

Dec 30th, 2012
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.82 KB | None | 0 0
  1. --[[
  2.     A graphical user interface file browser (guifb)
  3.     Version 1.4.1
  4.     by inventor2514
  5. ]]--
  6.  
  7. if not term.isColor then
  8.     print("An advanced computer is required")
  9.     return
  10. else
  11.     if not term.isColor() then
  12.         print("An advanced computer is required")
  13.         return
  14.     end
  15. end
  16.  
  17. -- Configuration variables
  18. local sStartDir = ""
  19. local sEditPath = "/rom/programs/edit"
  20. local backMain = colors.lightGray
  21. local backMenu = colors.lightBlue
  22. local textMain = colors.black
  23. local textClose = colors.red
  24. local textButton = colors.blue
  25.  
  26. -- Initialize some variables for later
  27. local tDirIcon = {"", " /\\____", "|      |", "|      |", "|______|"}
  28. local tFileIcon = {" ______", "|      |", "| ~~~~ |", "| ~~~~ |", "|______|"}
  29. local xMax, yMax = term.getSize()
  30. local row = 4, 3, 1
  31. local sDir = sStartDir
  32. local maxCol, maxRow = 1, 1
  33. local tOrigins = {}
  34. local tData = {}
  35. local sClipboard = ""
  36.  
  37. -- Returns the maximum columns and rows of icons
  38. local function iconLimits()
  39.     local i, maxCol = 3, 0
  40.     while i <= xMax-9 do
  41.         i = i + 9
  42.         maxCol = maxCol + 1
  43.     end
  44.     local i, maxRow = 2, 0
  45.     while i <= yMax-6 do
  46.         i = i + 6
  47.         maxRow = maxRow + 1
  48.     end
  49.     return maxCol, maxRow
  50. end
  51.  
  52. -- Returns a table of possible icon origin positions
  53. local function originTable()
  54.     tOrigins = {}
  55.     for i=1, maxRow do
  56.         for j=1, maxCol do
  57.             table.insert(tOrigins, {3+9*(j-1), 2+6*(i-1)})
  58.         end
  59.     end
  60.     return tOrigins
  61. end
  62.  
  63. -- Returns a table containing file data in {sName, bDir} format
  64. local function fileData(sDir)
  65.     local tList = fs.list(sDir)
  66.     local tData = {}
  67.     for i,sName in ipairs(tList) do
  68.         if string.sub(sName, 1, 1) ~= "." then
  69.             local sPath = fs.combine(sDir, sName)
  70.             table.insert(tData, {sName, fs.isDir(sPath)})
  71.         end
  72.     end
  73.     return tData
  74. end
  75.  
  76. -- Writes text to the specified position
  77. local function output(x, y, sText, color)
  78.     if color then
  79.         term.setTextColor(color)
  80.     else
  81.         term.setTextColor(textMain)
  82.     end
  83.     term.setCursorPos(x, y)
  84.     term.write(sText)
  85. end
  86.  
  87. -- Draws a rectangular border
  88. local function drawBorder(x, y, xLen, yLen)
  89.     output(x, y, "/")
  90.     output(x+xLen-1, y, "\\")
  91.     output(x, y+yLen-1, "\\")
  92.     output(x+xLen-1, y+yLen-1, "/")
  93.     for i=x+1, x+xLen-2 do
  94.         output(i, y, "-")
  95.         output(i, y+yLen-1, "-")
  96.     end
  97.     for i=y+1, y+yLen-2 do
  98.         output(x, i, "|")
  99.         output(x+xLen-1, i, "|")
  100.     end
  101. end
  102.  
  103. -- Draws a window-like border and buttons
  104. local function drawMainBorder()
  105.     drawBorder(1, 1, xMax, yMax)
  106.     output(xMax-4, 1, "X", textClose)
  107.     output(xMax-6, 1, "<", textButton)
  108.     output(xMax, 3, "*", textButton)
  109.     output(xMax, yMax-2, "*", textButton)
  110.     output(3, 1, "[SublimeOS]", textButton)
  111. end
  112.  
  113. -- Draws an icon at the specified position
  114. local function drawIcon(x, y, tIcon, sName)
  115.     local tIcon = tIcon
  116.     for i, s in ipairs(tIcon) do
  117.         output(x, y+i-1, s)
  118.     end
  119.     if sName then output(x, y+#tIcon, sName) end
  120. end
  121.  
  122. -- Draws icons to represent file data
  123. local function drawIcons()
  124.     local pos = 1 + maxCol*(row-1)
  125.     local limit = pos-1+maxCol*maxRow
  126.     if #tData < limit then limit = #tData end
  127.     local icon = 1
  128.     for i = pos, limit do
  129.         local x, y, sName = tOrigins[icon][1], tOrigins[icon][2], string.sub(tData[i][1], 1, 8)
  130.         if tData[i][2] then
  131.             drawIcon(x, y, tDirIcon, sName)
  132.         else
  133.             drawIcon(x, y, tFileIcon, sName)
  134.         end
  135.         icon = icon + 1
  136.     end
  137. end
  138.  
  139. -- Draws a centered menu and returns origin, length, and height
  140. local function drawMenu(tMenu)
  141.     term.setBackgroundColor(backMenu)
  142.     local length, height = 0, #tMenu+2
  143.     for _, sLine in ipairs(tMenu) do
  144.         if string.len(sLine) > length then
  145.             length = string.len(sLine)+2
  146.         end
  147.     end
  148.     local sBlank = ""
  149.     for i=1, length-2 do sBlank = sBlank.." " end
  150.     local x, y = math.floor(xMax/2) - math.ceil(length/2), math.floor(yMax/2) - math.ceil(#tMenu/2)
  151.     drawBorder(x, y, length, height)
  152.     for i, sLine in ipairs(tMenu) do
  153.         output(x+1, y+i, sBlank)
  154.         output(x+1, y+i, sLine)
  155.     end
  156.     return {x, y}, length, height
  157. end
  158.  
  159. -- Runs a selection menu and returns a number or nil
  160. local function runSelectionMenu(...)
  161.     local tArgs = {...}
  162.     local tMenu = {}
  163.     for _, sOption in ipairs(tArgs) do
  164.         table.insert(tMenu, " ( ) "..sOption.." ")
  165.     end
  166.     table.insert(tMenu, " [Okay] [Cancel] ")
  167.     local origin, length, height = drawMenu(tMenu)
  168.     local selection = 1
  169.     local x, y = origin[1]+3, origin[2]+1
  170.     local bMenu = true
  171.     while bMenu do
  172.         output(origin[1]+3, origin[2]+selection, "#")
  173.         local sEvent, ret1, ret2, ret3 = os.pullEventRaw()
  174.         if sEvent == "mouse_click" and ret1 == 1 then
  175.             local x, y = ret2, ret3
  176.             if x > origin[1] and x < origin[1]+length-1 and y > origin[2] and y < origin[2]+height-1 then
  177.                 if y < origin[2]+height-2 then
  178.                     selection = y - origin[2]
  179.                 elseif x > origin[1]+1 and x < origin[1]+8 then
  180.                     bMenu = false
  181.                 elseif x > origin[1]+8 and x < origin[1]+17 then
  182.                     bMenu = false
  183.                     selection = nil
  184.                 end
  185.                 drawMenu(tMenu)
  186.             end
  187.         end
  188.     end
  189.     return selection
  190. end
  191.  
  192. -- Runs a text menu and returns a string
  193. local function runTextMenu(sPrompt, sStartText)
  194.     local tMenu = {" "..sPrompt..":", " {              } ", " [Done] "}
  195.     local origin, length, height = drawMenu(tMenu)
  196.     local sText = ""
  197.     if sStartText then sText = sStartText end
  198.     local bMenu = true
  199.     while bMenu do
  200.         output(origin[1]+3, origin[2]+2, string.sub(sText, 1, 14))
  201.         output(origin[1]+3, origin[2]+2, "              ")
  202.         output(origin[1]+3, origin[2]+2, string.sub(sText, -14))
  203.         local sEvent, ret1, ret2, ret3 = os.pullEventRaw()
  204.         if sEvent == "mouse_click" and ret1 == 1 then
  205.             local x, y = ret2, ret3
  206.             if y == origin[2]+height-2 and x > origin[1]+1 and x < origin[1]+8 then
  207.                 bMenu = false
  208.             end
  209.         elseif sEvent == "char" then
  210.             sText = sText .. ret1
  211.         elseif sEvent == "key" then
  212.             if ret1 == 14 then
  213.                 sText = string.sub(sText, 1, string.len(sText)-1)
  214.             end
  215.         end
  216.     end
  217.     return sText
  218. end
  219.  
  220. -- Runs a confirmation menu and returns a boolean
  221. local function runConfirmMenu(...)
  222.     local tArgs = {...}
  223.     local tMenu = {}
  224.     for _, sLine in ipairs(tArgs) do
  225.         tMenu[#tMenu+1] = " "..sLine.." "
  226.     end
  227.     table.insert(tMenu, " [Yes] [No] ")
  228.     local origin, length, height = drawMenu(tMenu)
  229.     local bMenu, bConfirm = true
  230.     while bMenu do
  231.         local sEvent, ret1, ret2, ret3 = os.pullEventRaw()
  232.         if sEvent == "mouse_click" and ret1 == 1 then
  233.             local x, y = ret2, ret3
  234.             if y == origin[2]+height-2 and x > origin[1]+1 and x < origin[1]+7 then
  235.                 bMenu, bConfirm = false, true
  236.             elseif y == origin[2]+height-2 and x > origin[1]+7 and x < origin[1]+12 then
  237.                 bMenu, bConfirm = false, false
  238.             end
  239.         end
  240.     end
  241.     return bConfirm
  242. end
  243.  
  244. -- Redraws the border and icons
  245. local function redraw()
  246.     term.setBackgroundColor(backMain)
  247.     term.clear()
  248.     drawIcons()
  249.     drawMainBorder()
  250. end
  251.  
  252. -- Recalculate the file data and icon variables
  253. local function recalculate()
  254.     row = 1
  255.     tData = fileData(sDir)
  256.     maxCol, maxRow = iconLimits()
  257.     tOrigins = originTable()
  258. end
  259.  
  260. -- Returns the data associated with an icon or nil
  261. local function iconData(x, y)
  262.     local pos = maxCol*(row-1)
  263.     for i=1, maxCol*maxRow do
  264.         local xMin, yMin = tOrigins[i][1], tOrigins[i][2]
  265.         if x >= xMin and y >= yMin and x <= xMin+8 and y <= yMin+5 then
  266.             tIconData = tData[pos+i]
  267.             if tIconData then
  268.                 if fs.exists(fs.combine(sDir, tIconData[1])) then
  269.                     return tIconData
  270.                 else
  271.                     recalculate()
  272.                     redraw()
  273.                 end
  274.             end
  275.         end
  276.     end
  277.     return nil
  278. end
  279.  
  280. -- Main program loop
  281. local bRun = true
  282. recalculate()
  283. redraw()
  284. local bCursorToggle = false
  285. while bRun do
  286.     local sEvent, ret1, ret2, ret3 = os.pullEventRaw()
  287.     if sEvent == "mouse_click" then
  288.         local x, y = ret2, ret3
  289.         -- left-click
  290.         if ret1 == 1 then
  291.             -- close button
  292.             if x == xMax-4 and y == 1 then
  293.                 bRun = false
  294.             -- back button
  295.             elseif x == xMax-6 and y == 1 then
  296.                 if sDir ~= "" then
  297.                     sDir = fs.combine(sDir, "..")
  298.                     recalculate()
  299.                     redraw()
  300.                 end
  301.             -- scroll up button
  302.             elseif x == xMax and y == 3 then   
  303.                 if row > 1 then
  304.                     row = row - 1
  305.                     redraw()
  306.                 end
  307.             -- scroll down button
  308.             elseif x == xMax and y == yMax-2 then
  309.                 if row < (math.ceil(#tData/maxCol)-(maxRow-1)) then
  310.                     row = row + 1
  311.                     redraw()
  312.                 end
  313.             -- file/dir icon
  314.             elseif iconData(x, y) then
  315.                 local tIconData = iconData(x, y)
  316.                 if tIconData[2] then
  317.                     sDir = fs.combine(sDir, tIconData[1])
  318.                     recalculate()
  319.                     redraw()
  320.                 else
  321.                     local sPath = "/" .. fs.combine(sDir, tIconData[1])
  322.                     shell.run(sEditPath, sPath)
  323.                     redraw()
  324.                 end
  325.             end
  326.         -- right-click
  327.         elseif ret1 == 2 then
  328.             if x == 1 or y == 1 or x == xMax or y == yMax then
  329.                 -- do nothing
  330.             elseif iconData(x, y) then
  331.                 local tIconData = iconData(x, y)
  332.                 if tIconData[2] then
  333.                     local sDiskSide = nil
  334.                     for i,sSide in ipairs( rs.getSides() ) do
  335.                         if disk.isPresent(sSide) then
  336.                             if tIconData[1] == disk.getMountPath(sSide) then
  337.                                 sDiskSide = sSide
  338.                             end
  339.                         end
  340.                     end
  341.                     if sDiskSide then
  342.                         local selection = runSelectionMenu("Enter Disk", "Label Disk", "Copy Disk", "Eject Disk")
  343.                         if selection and fs.exists(fs.combine(sDir, tIconData[1])) then
  344.                             -- enter disk
  345.                             if selection == 1 then
  346.                                 sDir = fs.combine(sDir, tIconData[1])
  347.                                 recalculate()
  348.                                 redraw()
  349.                             -- label disk
  350.                             elseif selection == 2 then
  351.                                 local sLabel = runTextMenu("Disk Label", disk.getLabel(sDiskSide))
  352.                                 if sLabel ~= "" and disk.isPresent(sDiskSide) then
  353.                                     disk.setLabel(sDiskSide, sLabel)
  354.                                 end
  355.                             -- copy disk
  356.                             elseif selection == 3 then
  357.                                 if fs.exists(".copy") then fs.delete(".copy") end
  358.                                 fs.copy(fs.combine(sDir, tIconData[1]), ".copy")
  359.                                 sClipboard = tIconData[1]
  360.                             -- eject disk
  361.                             elseif selection == 4 then
  362.                                 disk.eject(sDiskSide)
  363.                                 sleep(.3)
  364.                                 fs.delete(sDiskSide)
  365.                                 recalculate()
  366.                                 redraw()
  367.                             end
  368.                         end
  369.                     else
  370.                         local selection = runSelectionMenu("Open Dir", "Rename Dir", "Copy Dir", "Delete Dir")
  371.                         if selection then
  372.                             -- enter dir
  373.                             if selection == 1 then
  374.                                 sDir = fs.combine(sDir, tIconData[1])
  375.                                 recalculate()
  376.                                 redraw()
  377.                             -- rename dir
  378.                             elseif selection == 2 then
  379.                                 if not fs.isReadOnly(fs.combine(sDir, tIconData[1])) then
  380.                                     local sName = runTextMenu("Dir Name", tIconData[1])
  381.                                     if sName ~= "" and sName ~= tIconData[1] and not fs.isReadOnly(fs.combine(sDir, sName)) then
  382.                                         local bConfirm = true
  383.                                         if fs.exists(fs.combine(sDir,sName)) then
  384.                                             bConfirm = runConfirmMenu("Overwrite existing", "file with that name?")
  385.                                         end
  386.                                         if bConfirm then
  387.                                             fs.move(fs.combine(sDir, tIconData[1]), fs.combine(sDir, sName))
  388.                                             recalculate()
  389.                                         end
  390.                                     end
  391.                                 end
  392.                             -- copy dir
  393.                             elseif selection == 3 then
  394.                                 if fs.exists(".copy") then fs.delete(".copy") end
  395.                                 fs.copy(fs.combine(sDir, tIconData[1]), ".copy")
  396.                                 sClipboard = tIconData[1]
  397.                             -- delete dir
  398.                             elseif selection == 4 then
  399.                                 if not fs.isReadOnly(fs.combine(sDir, tIconData[1])) then
  400.                                     fs.delete(fs.combine(sDir, tIconData[1]))
  401.                                     recalculate()
  402.                                 end
  403.                             end
  404.                         end
  405.                     end
  406.                 else
  407.                     local selection = runSelectionMenu("Edit File", "Run as Script", "Rename File", "Copy File", "Delete File")
  408.                     if selection then
  409.                         -- edit file
  410.                         if selection == 1 then
  411.                             local sPath = "/" .. fs.combine(sDir, tIconData[1])
  412.                             shell.run(sEditPath, sPath)
  413.                         -- run file as script
  414.                         elseif selection == 2 then
  415.                             local sPath = "/" .. fs.combine(sDir, tIconData[1])
  416.                             local sArgs = runTextMenu("Parameters")
  417.                             term.setBackgroundColor(colors.black)
  418.                             term.clear()
  419.                             term.setCursorPos(1, 1)
  420.                             if sArgs ~= "" then
  421.                                 local tArgs = {}
  422.                                 for sMatch in string.gmatch(sArgs, "[^ ]+") do
  423.                                     table.insert(tArgs, sMatch)
  424.                                 end
  425.                                 shell.run(sPath, unpack(tArgs))
  426.                             else
  427.                                 shell.run(sPath)
  428.                             end
  429.                             sleep(2)
  430.                             print("= Press any key to return =")
  431.                             os.pullEventRaw("key")
  432.                         -- rename file
  433.                         elseif selection == 3 then
  434.                             if not fs.isReadOnly(fs.combine(sDir, tIconData[1])) then
  435.                                 local sName = runTextMenu("File Name", tIconData[1])
  436.                                 if sName ~= "" and sName ~= tIconData[1] and not fs.isReadOnly(fs.combine(sDir, sName)) then
  437.                                     local bConfirm = true
  438.                                     if fs.exists(fs.combine(sDir,sName)) then
  439.                                         bConfirm = runConfirmMenu("Overwrite existing", "file with that name?")
  440.                                     end
  441.                                     if bConfirm then
  442.                                         fs.move(fs.combine(sDir, tIconData[1]), fs.combine(sDir, sName))
  443.                                         recalculate()
  444.                                     end
  445.                                 end
  446.                             end
  447.                         -- copy file
  448.                         elseif selection == 4 then
  449.                             if fs.exists(".copy") then fs.delete(".copy") end
  450.                             fs.copy(fs.combine(sDir, tIconData[1]), ".copy")
  451.                             sClipboard = tIconData[1]
  452.                         -- delete file
  453.                         elseif selection == 5 then
  454.                             if not fs.isReadOnly(fs.combine(sDir, tIconData[1])) then
  455.                                 fs.delete(fs.combine(sDir, tIconData[1]))
  456.                                 recalculate()
  457.                             end
  458.                         end
  459.                     end
  460.                 end
  461.             else
  462.                 local selection = runSelectionMenu("New Dir", "New File", "Set Shell Dir", "Paste")
  463.                 if selection then
  464.                     -- new dir
  465.                     if selection == 1 then
  466.                         local sName = runTextMenu("Dir Name")
  467.                         if sName ~= "" and not fs.isReadOnly(fs.combine(sDir, sName)) then
  468.                             local bConfirm = true
  469.                             if fs.exists(fs.combine(sDir,sName)) then
  470.                                 bConfirm = runConfirmMenu("Overwrite existing", "file with that name?")
  471.                             end
  472.                             if bConfirm then
  473.                                 fs.makeDir(fs.combine(sDir,sName))
  474.                                 recalculate()
  475.                             end
  476.                         end
  477.                     -- new file
  478.                     elseif selection == 2 then
  479.                         local sName = runTextMenu("File Name")
  480.                         if sName ~= "" and not fs.isReadOnly(fs.combine(sDir, sName)) then
  481.                             local bConfirm = true
  482.                             if fs.exists(fs.combine(sDir,sName)) then
  483.                                 bConfirm = runConfirmMenu("Overwrite existing", "file with that name?")
  484.                             end
  485.                             if bConfirm then
  486.                                 local file = io.open(fs.combine(sDir, sName), "w")
  487.                                 file:write("\n")
  488.                                 file:close()
  489.                                 recalculate()
  490.                             end
  491.                         end
  492.                     -- set shell dir
  493.                     elseif selection == 3 then
  494.                         shell.setDir(sDir)
  495.                     -- paste
  496.                     elseif selection == 4 then
  497.                         local sName = runTextMenu("Paste Name", sClipboard)
  498.                         if sName ~= "" and not fs.isReadOnly(fs.combine(sDir, sName)) then
  499.                             local bConfirm = true
  500.                             if fs.exists(fs.combine(sDir,sName)) then
  501.                                 bConfirm = runConfirmMenu("Overwrite existing", "file with that name?")
  502.                             end
  503.                             if bConfirm then
  504.                                 fs.delete(fs.combine(sDir, sName))
  505.                                 fs.copy(".copy", fs.combine(sDir, sName))
  506.                                 recalculate()
  507.                             end
  508.                         end
  509.                     end
  510.                 end
  511.             end
  512.             redraw()
  513.         -- middle click
  514.         elseif ret1 ==3 then
  515.             if sDir ~= "" then
  516.                 sDir = fs.combine(sDir, "..")
  517.                 recalculate()
  518.                 redraw()
  519.             end
  520.         end
  521.     elseif sEvent == "mouse_scroll" then
  522.         -- scroll down
  523.         if ret1 == 1 then
  524.             if row < (math.ceil(#tData/maxCol)-(maxRow-1)) then
  525.                 row = row + 1
  526.                 redraw()
  527.             end
  528.         -- scroll up
  529.         else
  530.             if row > 1 then
  531.                 row = row - 1
  532.                 redraw()
  533.             end
  534.         end
  535.     elseif sEvent == "key" then
  536.         local key = ret1
  537.         -- page up "scroll up"
  538.         if key == 201 then
  539.             if row > 1 then
  540.                 row = row - 1
  541.                 redraw()
  542.             end
  543.         -- page down "scroll down"
  544.         elseif key == 209 then
  545.             if row < (math.ceil(#tData/maxCol)-(maxRow-1)) then
  546.                 row = row + 1
  547.                 redraw()
  548.             end
  549.         -- backspace "back"
  550.         elseif key == 14 then
  551.             if sDir ~= "" then
  552.                 sDir = fs.combine(sDir, "..")
  553.                 recalculate()
  554.                 redraw()
  555.             end
  556.         -- end "close"
  557.         elseif key == 207 then
  558.             bRun = false
  559.         end
  560.     end
  561. end
  562.  
  563. -- Cleanup
  564. if fs.exists(".copy") then fs.delete(".copy") end
  565. term.setBackgroundColor(colors.black)
  566. term.clear()
  567. term.setCursorPos(1, 1)
Advertisement
Add Comment
Please, Sign In to add comment