Advertisement
GhastTearz

Menu API

Dec 19th, 2018
1,056
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.35 KB | None | 0 0
  1. -- Menu API
  2. --
  3. -- Written By: GhastTearz
  4. -- Version: 2.0.0
  5. --
  6. -- This program is a simple and flexible way to get
  7. -- menus in your program.
  8. --
  9. -- The format of menu strings is very simple. Each
  10. -- line of the string is a line in the menu. To add
  11. -- a "link" to a function or screen just as a tag
  12. -- somewhere in the line e.g. "@tag". See the demo
  13. -- program for more information at
  14. -- https://pastebin.com/ZNYdQzaR
  15. --
  16. -- KEYBINDINGS
  17. -- w, k, up           =  move up the menu
  18. -- a, h, left         =  go to previous screen
  19. -- s, j, down         =  move down the menu
  20. -- d, l, right, enter = select an item
  21. -- q, x = quit
  22. -- page up = go up a page
  23. -- page down = go down a page
  24. --
  25. ---------------------------------------------------
  26.  
  27. function addFunc(menu, tag, func, ...)
  28.  
  29.   if menu == nil or type(menu) ~= "table" then
  30.     error("Expected a menu table.")
  31.   end
  32.   if tag == nil or type(tag) ~= "string" then
  33.     error("Expected a tag string.")
  34.   end
  35.   if func == nil or type(func) ~= "function" then
  36.     error("Expected a function.")
  37.   end
  38.  
  39.   if menu[tag] ~= nil then
  40.     error("The tag "..tag.." is already in use.")
  41.   end
  42.  
  43.   local args = ...
  44.   menu[tag] = function() func(args) end
  45.  
  46. end
  47.  
  48. function addScreen(menu, tag, screen)
  49.  
  50.   if menu == nil or type(menu) ~= "table" then
  51.     error("Expected a menu table.")
  52.   end
  53.   if tag == nil or type(tag) ~= "string" then
  54.     error("Expected a tag string.")
  55.   end
  56.   if screen == nil or type(screen) ~= "string" then
  57.     error("Expected a screen string.")
  58.   end
  59.  
  60.   if menu[tag] ~= nil then
  61.     error("The tag "..tag.." is already in use.")
  62.   end
  63.  
  64.   menu[tag] = {}
  65.  
  66.   -- parse the screen string into a table    
  67.   local line = 1
  68.   local text = ""
  69.   local ref  = ""
  70.  
  71.   local i = 1
  72.   while i < #screen do
  73.    
  74.     if screen:sub(i,i) == '@' then
  75.       if screen:sub(i+1,i+1) == '@' then
  76.       --escape two @s by skipping a char
  77.         i = i + 1
  78.       else
  79.         if ref ~= "" then
  80.           error("On input line "..line
  81.                 .." for screen "..tag
  82.                 .." there is more than one tag.")
  83.         end
  84.      
  85.         i = i + 1
  86.         while screen:sub(i,i) ~= "" and
  87.               screen:sub(i,i) ~= ' ' and
  88.               screen:sub(i,i) ~= '\t' and
  89.               screen:sub(i,i) ~= '\n' do
  90.            
  91.           ref = ref..screen:sub(i,i)
  92.           i = i + 1      
  93.         end
  94.      
  95.         if ref == "" then
  96.           error("On input line "..line
  97.                 .." for screen "..tag
  98.                 .." the tag is empty.")
  99.         end
  100.       end
  101.     end
  102.    
  103.     if screen:sub(i,i) == '\n' or
  104.        screen:sub(i,i) == "" then
  105.        
  106.       menu[tag][line] = {}
  107.       menu[tag][line].text = text
  108.       menu[tag][line].ref  = ref
  109.       text = ""
  110.       ref  = ""
  111.       line = line + 1
  112.      
  113.     else
  114.       text = text..screen:sub(i,i)
  115.      
  116.     end
  117.    
  118.     i = i + 1
  119.  
  120.   end
  121. end
  122.  
  123. function displayScreen(menu, tag)
  124.  
  125.   if menu == nil or type(menu) ~= "table" then
  126.     error("Expected a menu table.")
  127.   end
  128.   if tag == nil or type(tag) ~= "string" then
  129.     error("Expected a tag string.")
  130.   end
  131.   if menu[tag] == nil then
  132.     error("The tag "..tag.." does not exist.")
  133.   end
  134.   if type(menu[tag]) ~= "table" then
  135.     error("The tag "..tag.." is not a screen.")
  136.   end
  137.  
  138.   --Check that all the tags refer to something
  139.   for k, v in pairs(menu) do
  140.     if type(menu[k]) == "table" then
  141.       for l = 1, #menu[k] do
  142.         local r = menu[k][l].ref
  143.         if r ~= "" and menu[r] == nil then
  144.           error("The tag "..r.." is not defined.")
  145.         end
  146.       end
  147.     end
  148.   end
  149.  
  150.  
  151.   local currentScreen = menu[tag]
  152.  
  153.   local screenStack = {}
  154.   screenStack[1] = menu[tag]
  155.  
  156.   local width, height = term.getSize()
  157.  
  158.  
  159.   -- These are indexes into the screen.
  160.   -- Top is the first line to be printed.
  161.   -- Bottom is the last line to be printed.
  162.   -- Selection is the line the user might select.
  163.   local top = 1
  164.   local bottom = height
  165.   local selection = 0
  166.  
  167.   local function printScreen()
  168.    
  169.     term.clear()
  170.     term.setCursorPos(1,1)
  171.    
  172.     for i = top, bottom do
  173.       if i > #currentScreen then
  174.         break
  175.       end
  176.  
  177.       local y = i % height
  178.       if y == 0 then
  179.         y = height
  180.       end
  181.  
  182.       term.setCursorPos(1, y)
  183.       if i == selection then
  184.         write("->"..currentScreen[i].text)
  185.       else
  186.         write("  "..currentScreen[i].text)
  187.       end
  188.     end
  189.   end
  190.  
  191.   local function setSelection()
  192.     selection = 0
  193.     for i = top, bottom do
  194.       if i > #currentScreen then
  195.         break
  196.       end
  197.       if currentScreen[i].ref ~= "" then
  198.         selection = i
  199.         break
  200.       end
  201.     end
  202.   end
  203.  
  204.   local function pageUp()
  205.     if top > 1 then
  206.       top = top - height
  207.       bottom = bottom - height
  208.       setSelection()
  209.     end
  210.   end
  211.  
  212.   local function pageDown()
  213.     if #currentScreen > bottom then
  214.       top = top + height
  215.       bottom = bottom + height
  216.       setSelection()
  217.    end
  218.   end
  219.  
  220.  
  221.   setSelection()
  222.   printScreen()
  223.  
  224.   while true do
  225.  
  226.     local e, key = os.pullEvent("key")
  227.  
  228.     -- go up the screen
  229.     if key == 17 or
  230.        key == 37 or
  231.        key == 200 then
  232.        
  233.       -- find prev item with a ref
  234.       local prevItem
  235.       for i = selection - 1, 1, -1 do    
  236.         if currentScreen[i].ref ~= "" then
  237.           prevItem = i
  238.           break
  239.         end      
  240.       end
  241.      
  242.       if prevItem == nil then
  243.         pageUp()
  244.       else
  245.         selection = prevItem
  246.         if prevItem < top then    
  247.           pageUp()
  248.         end
  249.       end
  250.        
  251.     end
  252.    
  253.     -- go down the screen
  254.     if key == 31 or
  255.        key == 36 or
  256.        key == 208 then
  257.        
  258.       -- find the next item with a ref
  259.       local nextItem
  260.       for i = selection + 1, #currentScreen do
  261.         if currentScreen[i].ref ~= "" then
  262.           nextItem = i
  263.           break
  264.         end
  265.       end
  266.      
  267.       if nextItem == nil then
  268.         pageDown()
  269.       else
  270.         selection = nextItem
  271.         if nextItem > bottom then
  272.           pageDown()
  273.         end
  274.       end
  275.  
  276.     end
  277.    
  278.     -- select the current item
  279.     if (key == 32 or
  280.        key == 38 or
  281.        key == 205 or
  282.        key == 28 ) and
  283.        currentScreen[selection] ~= nil then
  284.        
  285.       local r = currentScreen[selection].ref
  286.  
  287.       if type(menu[r]) == "function" then
  288.         term.clear()
  289.         term.setCursorPos(1,1)
  290.         return menu[r]  
  291.       else
  292.         screenStack[#screenStack + 1] = menu[r]
  293.         currentScreen = menu[r]
  294.         top = 1
  295.         bottom = height
  296.         setSelection()
  297.       end
  298.  
  299.     end
  300.    
  301.     -- Go back to previous screen
  302.     if (key == 30 or
  303.        key == 35 or
  304.        key == 203) and
  305.        #screenStack > 1 then
  306.      
  307.       screenStack[#screenStack] = nil
  308.       currentScreen = screenStack[#screenStack]
  309.       top = 1
  310.       bottom = height
  311.       setSelection()
  312.     end
  313.    
  314.     -- quit the menu
  315.     if key == 16 or
  316.        key == 45 then
  317.       term.clear()
  318.       term.setCursorPos(1,1)
  319.       return
  320.     end
  321.    
  322.     if key == 201 then
  323.       pageUp()    
  324.     end
  325.    
  326.     if key == 209 then
  327.       pageDown()
  328.     end
  329.  
  330.     printScreen()
  331.    
  332.   end
  333.  
  334. end
  335.  
  336.  
  337. function new()
  338.   local t = {}
  339.   t.addFunc       = addFunc
  340.   t.addScreen     = addScreen
  341.   t.displayScreen = displayScreen
  342.   return t
  343. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement