SHOW:
|
|
- or go back to the newest paste.
| 1 | function titleize(text) | |
| 2 | local x = term.getSize() | |
| 3 | if #text+2 > x then return text end | |
| 4 | text = " "..string.upper(text).." " | |
| 5 | for i=1, math.floor((x-#text)/2) do | |
| 6 | text = "="..text.."=" | |
| 7 | end | |
| 8 | return text | |
| 9 | end | |
| 10 | ||
| 11 | function menu(title, description, textTable, isNumbered, titleAlign, textAlign, prefixCharacter, suffixCharacter, incrementFunction) | |
| 12 | local x, y = term.getSize() --Screen size | |
| 13 | local alignments = { left = "left", center = "center", right = "right" } --Used for checking if alignment is valid
| |
| 14 | if not (title and textTable) then error("Requires title and menu list",2) end
| |
| 15 | if not type(textTable) == "table" and #textTable >= 1 then error("Menu list must be a table with values",2) end
| |
| 16 | if #title > x then error("Title too long",2) end --If the title is longer than a line, program messes up
| |
| 17 | if isNumbered == nil then isNumbered = true end --Setting isNumbered default | |
| 18 | titleAlign = alignments[titleAlign] or alignments.center --Default title alignment | |
| 19 | textAlign = alignments[textAlign] or alignments.left --Default options alignment | |
| 20 | prefixCharacter = prefixCharacter or "[" | |
| 21 | suffixCharacter = suffixCharacter or "]" | |
| 22 | if type(textTable[1]) == "table" then --This allows you to have tables of text, function pairs. So my function returns 1, and you call input[1].func() | |
| 23 | for i=1, #textTable do | |
| 24 | textTable[i] = textTable[i].text | |
| 25 | end | |
| 26 | end | |
| 27 | local function align(text, alignment) --Used to align text to a certain direction | |
| 28 | if alignment == "left" then return 1 end | |
| 29 | if alignment == "center" then return (x/2)-(#text/2) end | |
| 30 | if alignment == "right" then return x - #text end | |
| 31 | error("Invalid Alignment",3) --Three because is only called by output
| |
| 32 | end | |
| 33 | local function output(text,y, alignment) --My own term.write with more control | |
| 34 | local x = align(text, alignment) | |
| 35 | term.setCursorPos(x,y) | |
| 36 | term.clearLine() | |
| 37 | return term.write(text) | |
| 38 | end | |
| 39 | local currIndex, descriptionLines, scroll = 1, 0, 0 --currIndex is the item from the table it is on, scroll is how many down it should go. | |
| 40 | if description then --descriptionLines is how many lines the description takes up | |
| 41 | descriptionLines = print(description); term.clear(); term.setCursorPos(1,1)--This is my way of figuring out how many lines the description is | |
| 42 | end | |
| 43 | if descriptionLines > y-4 then error("Description takes up too many lines",2) end --So at least two options are on screen
| |
| 44 | local titleLines = descriptionLines + 2 --The title line, descriptions, plus extra line | |
| 45 | local top, bottom = 1, (y-titleLines) --These two are used to determine what options are on the screen right now (through scroll) | |
| 46 | while true do | |
| 47 | if currIndex <= top and top > 1 then --If index is at top, scroll up | |
| 48 | scroll = scroll - 1 | |
| 49 | top, bottom = top - 1, bottom - 1 | |
| 50 | end | |
| 51 | if currIndex >= bottom and bottom < #textTable then --If at bottom scroll down. Change to > instead of >= to only do on bottom line. Same for above | |
| 52 | scroll = scroll + 1 | |
| 53 | top, bottom = top + 1, bottom + 1 | |
| 54 | end | |
| 55 | term.clear() | |
| 56 | output(title,1, titleAlign) --Print title | |
| 57 | if descriptionLines == 1 then --Not an else because we don't want to print nothing | |
| 58 | output(description,2, titleAlign) | |
| 59 | elseif descriptionLines > 1 then | |
| 60 | term.setCursorPos(1,2); print(description) | |
| 61 | end | |
| 62 | for i = 1, math.min(y - titleLines,#textTable) do --The min because may be fewer table entries than the screen is big | |
| 63 | local prefix, suffix = "", "" --Stuff like spaces and numbers | |
| 64 | if isNumbered then prefix = tostring(i+scroll)..". " end --Attaches a number to the front | |
| 65 | if i + scroll == currIndex then prefix = prefixCharacter.." "..prefix; suffix = suffix.." "..suffixCharacter --Puts brackets on the one highlighted | |
| 66 | elseif textAlign == "left" then for i=1, #prefixCharacter+1 do prefix = " "..prefix end --This helps alignment | |
| 67 | elseif textAlign == "right" then for i=1, #suffixCharacter+1 do suffix = suffix.." " end --Same as above | |
| 68 | end | |
| 69 | if not (#(prefix..textTable[i+scroll]..suffix) <= x) then term.clear(); term.setCursorPos(1,1); error("Menu item "..tostring(i+scroll).." is longer than one line. Cannot Print",2) end
| |
| 70 | output(prefix..textTable[i+scroll]..suffix, i + titleLines, textAlign) | |
| 71 | end | |
| 72 | if type(incrementFunction) ~= "function" then --This allows you to have your own custom logic for how to shift up and down and press enter. | |
| 73 | incrementFunction = function() --e.g. You could use redstone on left to increment, right to decrement, front to press enter. | |
| 74 | _, key = os.pullEvent("key")
| |
| 75 | if key == 200 then return "up" | |
| 76 | elseif key == 208 then return "down" | |
| 77 | elseif key == 28 then return "enter" | |
| 78 | end | |
| 79 | end | |
| 80 | end | |
| 81 | action = incrementFunction() | |
| 82 | if action == "up" and currIndex > 1 then | |
| 83 | currIndex = currIndex - 1 | |
| 84 | end | |
| 85 | if action == "down" and currIndex < #textTable then | |
| 86 | currIndex = currIndex + 1 | |
| 87 | end | |
| 88 | if action == "enter" then | |
| 89 | return currIndex, textTable[currIndex] | |
| 90 | end | |
| 91 | end | |
| 92 | end |