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