View difference between Paste ID: ijBuuX0e and E4TJ2uCR
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