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 |