Advertisement
OneNight

TAPI

Jun 5th, 2014
230
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.17 KB | None | 0 0
  1. --  Touch API v0.5.0.1
  2. --
  3. --  Requirements:
  4. --    Make sure enableAPI_http=true in ComputerCraft.cfg
  5. --    Any computer or turtle
  6. --    Advanced monitor at any side
  7. --  
  8.  
  9. local saveFile = "touch.save"
  10. local debugMode, sideMonitor, noMonitor, canSave
  11. local buttons, debugInfo, titleData, waitForFuncs = {}, {}, {}, {}
  12. local defaultColors       = {colors.white, colors.black}
  13. local defaultButtonColors = {colors.lime, colors.black, colors.gray, colors.white}
  14. local defaultPopupColors  = {colors.white, colors.black, colors.lightGray}
  15.  
  16. args = function (...)
  17.   local args = {...}
  18.   if type(args[1]) == "table" then args = args[1] end
  19.   return args
  20. end
  21.  
  22. dbg = function (...)
  23.   if #{...} > 0 then
  24.     if debugMode then
  25.       if term.isColor() then term.setTextColor(colors.lime) end
  26.       print("DBG: ", ...)
  27.       if term.isColor() then term.setTextColor(colors.white) end
  28.     else
  29.       table.insert(debugInfo, {...})
  30.     end
  31.   else
  32.     debugMode = not debugMode
  33.     if debugMode then
  34.       for k, v in pairs(debugInfo) do dbg(unpack(v)) end
  35.       debugInfo = {}
  36.       dbg("Debug mode enabled.")
  37.     else
  38.       dbg("Debug mode disabled.")
  39.     end
  40.   end
  41.   return true
  42. end
  43.  
  44. err = function (...)
  45.   if term.isColor() then term.setTextColor(colors.red) end
  46.   print("ERR: ", ...)
  47.   if term.isColor() then term.setTextColor(colors.white) end
  48.   return false
  49. end
  50.  
  51. checkText = function (text)
  52.   if type(text) == "string" then return true end
  53.   if type(text) == "table" then
  54.     local result = true
  55.     for k, v in pairs(text) do
  56.       result = result and checkText(v)
  57.     end
  58.     return result
  59.   end
  60.   return false
  61. end
  62.  
  63. checkColor = function (color)
  64.   if type(color) == "number" then
  65.     if color >= 0 and color < 2^16 then
  66.       return true
  67.     end
  68.   end
  69.   return false
  70. end
  71.  
  72. setDefaultColors = function (...)
  73.   dbg("Changing default colors.")
  74.   for k, v in pairs(args(...)) do
  75.     if checkColor(v) then
  76.       defaultButtonColors[k] = v
  77.     end
  78.   end
  79. end
  80.  
  81. setMonitorSide = function (side)
  82.   if peripheral.getType(side) == "monitor" then
  83.     sideMonitor = side
  84.     return dbg("Connected to monitor. (", side, ")")
  85.   end
  86.   return err("No monitor on \"", side, "\" side.")
  87. end
  88.  
  89. setMonitor = function (side)
  90.   local validSide = false
  91.   for k, v in pairs(rs.getSides()) do
  92.     if v == side then
  93.       validSide = true
  94.       break
  95.     end
  96.   end
  97.   if validSide then
  98.     return setMonitorSide(side)
  99.   else
  100.     return err("Wrong side.")
  101.   end
  102. end
  103.  
  104. detectMonitor = function ()
  105.   for k, v in pairs(rs.getSides()) do
  106.     if peripheral.getType(v) == "monitor" then
  107.       return setMonitorSide(v)
  108.     end
  109.   end
  110.   return err("Can't find the monitor.")
  111. end
  112.  
  113. monitor = function (method, ...)
  114.   if not sideMonitor then
  115.     if noMonitor then return false end
  116.     dbg("Trying to detect monitor.")
  117.     if not detectMonitor() then
  118.       noMonitor = true
  119.       return false
  120.     end
  121.   end
  122.   return peripheral.call(sideMonitor, method, ...)
  123. end
  124.  
  125. getID = function (value)
  126.   if type(value) == "string" then
  127.     for id, data in pairs(buttons) do
  128.       if value == data.text then return id end
  129.     end
  130.   elseif type(value) == "number" then
  131.     if buttons[value] then return value end
  132.   end
  133.   return false
  134. end
  135.  
  136. getData = function (button)
  137.   local id = getID(button)
  138.   if id then
  139.     return id, buttons[id]
  140.   end
  141.   return false
  142. end
  143.  
  144. getAllData = function ()
  145.   return buttons
  146. end
  147.  
  148. addButton = function (text, func, coord, ...)
  149.   if type(text) == "number" then text = tostring(text) end
  150.   if not checkText(text) then return err("Wrong text type.") end
  151.   if type(coord[1]) ~= "number" or type(coord[2]) ~= "number" then
  152.     return err("Wrong coordinates.")
  153.   end
  154.   --dbg("Adding button: \"", text, "\" (ID: ", #buttons+1, ")")
  155.   local W, H = getTextSize(text)
  156.   if type(coord[3]) ~= "number" then coord[3] = W end
  157.   if type(coord[4]) ~= "number" then coord[4] = H end
  158.   local color = args(...)
  159.   for k, v in pairs(defaultButtonColors) do
  160.     if not checkColor(color[k]) then color[k] = v end
  161.   end
  162.   local button = {
  163.     ["active"] = false,
  164.     ["text"] = text,
  165.     ["func"] = func,
  166.     ["coord"] = {
  167.       ["X"] = coord[1],
  168.       ["Y"] = coord[2],
  169.       ["W"] = coord[3],
  170.       ["H"] = coord[4],
  171.     },
  172.     ["color"] = {
  173.       ["B"] = color[1],
  174.       ["T"] = color[2],
  175.       ["b"] = color[3],
  176.       ["t"] = color[4],
  177.     },
  178.   }
  179.   table.insert(buttons, button)
  180.   return #buttons, button
  181. end
  182.  
  183. deleteButton = function (...)
  184.   local arr = args(...)
  185.   if #arr < 1 then
  186.     dbg("Removing all buttons.")
  187.     buttons = {}
  188.     return true
  189.   end
  190.   for k, v in pairs(arr) do
  191.     local id, data = getData(v)
  192.     if id then
  193.       --dbg("Removing button: \"", data.text, "\" (ID: ", id, ")")
  194.       table.remove(buttons, id)
  195.     end
  196.   end
  197.   return true
  198. end
  199.  
  200. executeFunction = function (button)
  201.   local id, data = getData(button)
  202.   if id then
  203.     if type(data.func) == "function" then
  204.       dbg("Executing function. (ID: ", id, ")")
  205.       return data.func(id, data)
  206.     end
  207.   end
  208. end
  209.  
  210. simulateTouch = function (...)
  211.   for k, v in pairs(args(...)) do
  212.     sleep(0)
  213.     executeFunction(v)
  214.   end
  215. end
  216.  
  217. forEach = function (func)
  218.   for id, data in pairs(buttons) do
  219.     if type(func) == "function" then
  220.       func(id, data)
  221.     else
  222.       executeFunction(id)
  223.     end
  224.   end
  225. end
  226.  
  227. enableButton = function (...)
  228.   local arr = args(...)
  229.   if #arr < 1 then
  230.     dbg("Enabling all buttons.")
  231.     for id, data in pairs(buttons) do  
  232.       enableButton(id)
  233.     end
  234.     return true
  235.   end
  236.   for k, v in pairs(arr) do
  237.     local id, data = getData(v)
  238.     if id and not data.active then
  239.       --dbg("Changing \"", data.text, "\": ", data.active, " -> ", true)
  240.       data.active = true
  241.       drawButton(id)
  242.     end
  243.   end
  244.   return true
  245. end
  246.  
  247. disableButton = function (...)
  248.   local arr = args(...)
  249.   if #arr < 1 then
  250.     dbg("Disabling all buttons.")
  251.     for id, data in pairs(buttons) do  
  252.       disableButton(id)
  253.     end
  254.     return true
  255.   end
  256.   for k, v in pairs(arr) do
  257.     local id, data = getData(v)
  258.     if id and data.active then
  259.       --dbg("Changing \"", data.text, "\": ", data.active, " -> ", false)
  260.       data.active = false
  261.       drawButton(id)
  262.     end
  263.   end
  264.   return true
  265. end
  266.  
  267. toggleButton = function (...)
  268.   local arr = args(...)
  269.   if #arr < 1 then
  270.     dbg("Toggling all buttons.")
  271.     for id, data in pairs(buttons) do  
  272.       toggleButton(id)
  273.     end
  274.     return true
  275.   end
  276.   for k, v in pairs(arr) do
  277.     local id, data = getData(v)
  278.     if id then
  279.       --dbg("Changing \"", data.text, "\": ", data.active, " -> ", not data.active)
  280.       data.active = not data.active
  281.       drawButton(id)
  282.     end
  283.   end
  284.   return true
  285. end
  286.  
  287. blinkButton = function (button, delay)
  288.   if type(delay) ~= "number" then delay = 0.5 end
  289.   local id, data = getData(button)
  290.   if id then
  291.     dbg("Blinking \"", data.text, "\" for ", delay, " sec.")
  292.     toggleButton(id)
  293.     sleep(delay)
  294.     toggleButton(id)
  295.     return true
  296.   end
  297.   return false
  298. end
  299.  
  300. setColor1 = function (color)
  301.   if type(color) ~= "number" then color = defaultColors[1] end
  302.   --dbg("Set text color to: ", color)
  303.   monitor("setTextColor", color)
  304. end
  305.  
  306. setColor2 = function (color)
  307.   if type(color) ~= "number" then color = defaultColors[2] end
  308.   --dbg("Set background color to: ", color)
  309.   monitor("setBackgroundColor", color)
  310. end
  311.  
  312. setColors = function (color1, color2)
  313.   setColor1(color1)
  314.   setColor2(color2)
  315. end
  316.  
  317. getTextSize = function (text)
  318.   if not checkText(text) then return false end
  319.   if type(text) ~= "table" then text = {text} end
  320.   local len = {}
  321.   for k, v in pairs(text) do len[k] = string.len(v) end
  322.   return math.max(unpack(len)), #text
  323. end
  324.  
  325. drawText = function (X, Y, text, color)
  326.   if not X or not Y then return err("Expected X and Y.") end
  327.   if not text then text = " " end
  328.   if type(text) == "string" then
  329.     if string.len(text) > 1 then X = X-string.len(text)/2 end
  330.     if checkColor(color) then setColor1(color) end
  331.     monitor("setCursorPos", math.floor(X), math.floor(Y))
  332.     monitor("write", text)
  333.     if checkColor(color) then setColor1(color) end
  334.     return true
  335.   elseif type(text) == "table" and checkText(text) then
  336.     for k, v in pairs(text) do
  337.       drawText(X, Y-#text/2+k-1, v, color)
  338.     end
  339.     return true
  340.   else
  341.     return err("Wrong text type.")
  342.   end
  343. end
  344.  
  345. setTitle = function (text, color)
  346.   if type(text) == "string" then titleData[1] = text end
  347.   if checkColor(color) then titleData[2] = color end
  348.   return drawTitle()
  349. end
  350.  
  351. drawTitle = function ()
  352.   text, color = unpack(titleData)
  353.   if not text then return false end
  354.   dbg("Drawing title.")
  355.   return drawText(monitor("getSize")/2+1, 1, text, color)
  356. end
  357.  
  358. drawRectangle = function (X1, Y1, X2, Y2, color)
  359.   if color then setColor2(color) end
  360.   for Y = 0, Y2-Y1 do
  361.     if Y == 0 or Y == Y2-Y1 then
  362.       for X = 0, X2-X1 do
  363.         drawText(X1+X, Y1+Y)
  364.       end
  365.     else
  366.       drawText(X1, Y1+Y)
  367.       drawText(X2, Y1+Y)
  368.     end
  369.   end
  370.   if color then setColor2() end
  371. end
  372.  
  373. drawFilledRectangle = function (X1, Y1, X2, Y2, color)
  374.   if color then setColor2(color) end
  375.   for Y = 0, Y2-Y1 do
  376.     for X = 0, X2-X1 do
  377.       drawText(X1+X, Y1+Y)
  378.     end
  379.   end
  380.   if color then setColor2() end
  381. end
  382.  
  383. drawButton = function (button)
  384.   local id, data = getData(button)
  385.   if id then
  386.     --dbg("Drawing button: \"", data.text, "\"")
  387.     if data.active then
  388.       setColors(data.color.T, data.color.B)
  389.     else
  390.       setColors(data.color.t, data.color.b)
  391.     end
  392.     local X, Y = data.coord.X, data.coord.Y
  393.     local W, H = data.coord.W, data.coord.H
  394.     drawFilledRectangle(X, Y, X+W, Y+H)
  395.     drawText(X+W/2, Y+H/2, data.text)
  396.     setColors()
  397.     return true
  398.   elseif not button then
  399.     dbg("Drawing buttons.")
  400.     for id, data in pairs(buttons) do
  401.       drawButton(id)
  402.     end
  403.     return true
  404.   end
  405.   return err("Wrong button. Can't draw.")
  406. end
  407.  
  408. drawPopup = function (text, ...)
  409.   if not checkText(text) then return err("Wrong text. Can't draw popup.") end
  410.   dbg("Drawing popup.")
  411.   local color = args(...)
  412.   if color[1] and not color[3] then color[3] = color[1] end
  413.   for k, v in pairs(defaultPopupColors) do
  414.     if not checkColor(color[k]) then color[k] = v end
  415.   end
  416.   local mW, mH = monitor("getSize")
  417.   local tW, tH = getTextSize(text)
  418.   local X, Y = math.floor((mW-tW)/2), math.floor((mH-tH)/2)
  419.   drawRectangle      (X+1-2, Y+1-2, X+tW+2, Y+tH+2, color[3])
  420.   drawFilledRectangle(X+1-1, Y+1-1, X+tW+1, Y+tH+1, color[2])
  421.   setColors(color[1], color[2])
  422.   drawText(X+1+tW/2, Y+1+tH/2, text)
  423.   setColors()
  424.   return true
  425. end
  426.  
  427. whatButtonIs = function (X, Y)
  428.   for id, data in pairs(buttons) do
  429.     if X >= data.coord.X and X < data.coord.X + data.coord.W then
  430.       if Y >= data.coord.Y and Y < data.coord.Y + data.coord.H then
  431.         return id, data
  432.       end
  433.     end
  434.   end
  435.   return false
  436. end
  437.  
  438. waitForTouch = function ()
  439.   dbg("Waiting for touch.")
  440.   local event, side, X, Y = os.pullEvent("monitor_touch")
  441.   dbg("Touch: ", X, "*", Y)
  442.   return X, Y
  443. end
  444.  
  445. waitForButton = function (button)
  446.   local waitID = getID(button)
  447.   while true do
  448.     local X, Y = waitForTouch()
  449.     local id, data = whatButtonIs(X, Y)
  450.     if id then
  451.       dbg("Detected button: \"", data.text, "\" (ID: ", id, ")")
  452.       if not waitID or id == waitID then
  453.         executeFunction(id)
  454.         return id, data
  455.       end
  456.     end
  457.   end
  458. end
  459.  
  460. waitReboot = function ()
  461.   for k, v in pairs(rs.getSides()) do
  462.     if rednet.isOpen(v) then break end
  463.     if peripheral.getType(v) == "modem" then rednet.open(v) end
  464.   end
  465.   while true do
  466.     local event, id, text = os.pullEvent("rednet_message")
  467.     if text == "reboot" then os.reboot() end
  468.   end
  469.   return true
  470. end
  471.  
  472. waitFor = function (...)
  473.   local funcs = {}
  474.   for k, v in pairs(args(...)) do
  475.     if type(v) == "function" then
  476.       table.insert(funcs, v)
  477.     end
  478.   end
  479.   waitForFuncs = funcs
  480. end
  481.  
  482. waitForAny = function (...)
  483.   local funcs = {}
  484.   for k, v in pairs({unpack(waitForFuncs), unpack(args(...))}) do
  485.     if type(v) == "function" then
  486.       table.insert(funcs, function() v() return true end)
  487.     elseif type(v) == "number" then
  488.       table.insert(funcs, function() sleep(v) return true end)
  489.     end
  490.   end
  491.   table.insert(funcs, waitReboot)
  492.   parallel.waitForAny(unpack(funcs))
  493.   return X, Y
  494. end
  495.  
  496. touchOrAny = function (...)
  497.   local X, Y
  498.   waitForAny(function() X, Y = waitForTouch() end, ...)
  499.   return X, Y
  500. end
  501.  
  502. buttonOrAny = function (...)
  503.   local id, data
  504.   waitForAny(function() id, data = waitForButton() end, ...)
  505.   return id, data
  506. end
  507.  
  508. clear = function ()
  509.   dbg("Clearing.")
  510.   setColors()
  511.   monitor("clear")
  512.   monitor("setCursorPos", 1, 1)
  513.   return true
  514. end
  515.  
  516. redraw = function (delay)
  517.   if type(delay) == "number" then
  518.     touchOrAny(delay)
  519.   end
  520.   dbg("Redrawing.")
  521.   clear()
  522.   drawTitle()
  523.   drawButton()
  524.   return true
  525. end
  526.  
  527. prepare = function (...)
  528.   drawButton()
  529.   simulateTouch(...)
  530.   canSave = true
  531. end
  532.  
  533. run = function (...)
  534.   prepare(...)
  535.   dbg("Starting main processing cycle.")
  536.   while true do
  537.     buttonOrAny()
  538.   end
  539. end
  540.  
  541. save = function ()
  542.   if not canSave then return false end
  543.   dbg("Saving to \"", saveFile, "\".")
  544.   local f = fs.open(saveFile, "w")
  545.   if f then
  546.     for id, data in pairs(buttons) do
  547.       if data.active then
  548.         f.writeLine(tostring(id))
  549.       end
  550.     end
  551.     return f.close()
  552.   end
  553.   return err("Cannot save.")
  554. end
  555.  
  556. load = function ()
  557.   dbg("Loading from \"", saveFile, "\".")
  558.   local f, t = fs.open(saveFile, "r"), {}
  559.   if f then
  560.     while true do
  561.       local s = f.readLine()
  562.       if not s then break end
  563.       table.insert(t, tonumber(s))
  564.     end
  565.     f.close()
  566.     return t
  567.   end
  568.   return false
  569. end
  570.  
  571. default  = setDefaultColors
  572. color    = setDefaultColors
  573. set      = setMonitor
  574. title    = setTitle
  575. all      = getAllData
  576. data     = getData
  577. add      = addButton
  578. del      = deleteButton
  579. delete   = deleteButton
  580. enable   = enableButton
  581. on       = enableButton
  582. disable  = disableButton
  583. off      = disableButton
  584. toggle   = toggleButton
  585. blink    = blinkButton
  586. draw     = drawButton
  587. popup    = drawPopup
  588. simulate = simulateTouch
  589. touch    = simulateTouch
  590. wait     = waitFor
  591. touchOr  = touchOrAny
  592. buttonOr = buttonOrAny
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement