Skiret

warpdriveCommons.lua

Nov 29th, 2020
772
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local w
  2.  
  3. -- APIs
  4. local component = require("component")
  5. local computer = require("computer")
  6. local term = require("term")
  7. local event = require("event")
  8. local fs = require("filesystem")
  9. local serialization = require("serialization")
  10. local colors = {-- loosely based on CC colors
  11.   green     = 0x008000,
  12.   brown     = 0x804040,
  13.   black     = 0x000000,
  14.   pink      = 0xFF8000,
  15.   yellow    = 0xFFFF00,
  16.   orange    = 0xFFB040,
  17.   purple    = 0x800080,
  18.   magenta   = 0xFF80FF,
  19.   red       = 0xFF0000,
  20.   cyan      = 0x008080,
  21.   white     = 0xFFFFFF,
  22.   lightBlue = 0x8080FF,
  23.   blue      = 0x0000FF,
  24.   gray      = 0x404040,
  25.   lightGray = 0xB0B0B0, -- silver
  26.   lime      = 0x66FF66,
  27. }
  28.  
  29. -- properties
  30. local data = { }
  31. local data_name = nil
  32. local data_handlers = { }
  33.  
  34. local device_handlers = {}
  35.  
  36. local event_handlers = {}
  37.  
  38. local monitors = {}
  39. local monitor_textScale = 0.5
  40.  
  41. -- colors are cached to reduce GPU load on OC
  42. local monitor_colorFront = colors.white
  43. local monitor_colorBackground = colors.black
  44.  
  45. local page_handlers = {}
  46. local page_endText = ""
  47. local page_callbackDisplay
  48. local page_callbackKey
  49.  
  50. local event_refreshPeriod_s = 5.0
  51. local event_refreshTimerId = -1
  52.  
  53. local styles = {
  54.   normal   = { front = colors.black    , back = colors.lightGray },
  55.   good     = { front = colors.lime     , back = colors.lightGray },
  56.   bad      = { front = colors.red      , back = colors.lightGray },
  57.   disabled = { front = colors.gray     , back = colors.lightGray },
  58.   help     = { front = colors.white    , back = colors.blue      },
  59.   header   = { front = colors.orange   , back = colors.black     },
  60.   control  = { front = colors.white    , back = colors.blue      },
  61.   selected = { front = colors.black    , back = colors.lightBlue },
  62.   warning  = { front = colors.white    , back = colors.red       },
  63.   success  = { front = colors.white    , back = colors.lime      },
  64. }
  65.  
  66. ----------- Terminal & monitor support
  67.  
  68. local function setMonitorColorFrontBack(colorFront, colorBackground)
  69.   if monitor_colorFront ~= colorFront then
  70.     monitor_colorFront = colorFront
  71.     component.gpu.setForeground(monitor_colorFront)
  72.   end
  73.   if monitor_colorBackground ~= colorBackground then
  74.     monitor_colorBackground = colorBackground
  75.     component.gpu.setBackground(monitor_colorBackground)
  76.   end
  77. end
  78.  
  79. local function write(text)
  80.   if term.isAvailable() then
  81.     local xSize, ySize = w.getResolution()
  82.     if xSize then
  83.       local x, y = w.getCursorPos()
  84.       component.gpu.set(x, y, text)
  85.       w.setCursorPos(x + #text, y)
  86.     end
  87.   end
  88. end
  89.  
  90. function send_coords()
  91.   local internet = require("internet")
  92.   ship = require"component".warpdriveShipController
  93.   ship_x, ship_y, ship_z = ship.position()
  94.   if ship_x == nil then
  95.     ship_x, ship_y, ship_z = 0, 0, 0
  96.   end
  97.   local dx, dy, dz = ship.getOrientation()
  98.   if dx == nil then
  99.     dx, dy, dz = 0, 0, 0
  100.   end
  101.   mov_x, mov_y, mov_z = ship.movement()
  102.   local addr = ""--cURL сюда
  103.   local worldMovement = { x = 0, y = 0, z = 0 }
  104.     worldMovement.x = dx * mov_x - dz * mov_z
  105.     worldMovement.y = mov_y
  106.     worldMovement.z = dz * mov_x + dx * mov_z
  107.     xTarget = ship_x + worldMovement.x
  108.     yTarget = ship_y + worldMovement.y
  109.     zTarget = ship_z + worldMovement.z
  110.   local req = internet.request(addr, {ship_name(), ship_x, ship_y, ship_z, xTarget, yTarget, zTarget})
  111. end
  112.  
  113. local function getCursorPos()
  114.   local x, y = term.getCursor()
  115.   return x, y
  116. end
  117.  
  118. local function setCursorPos(x, y)
  119.   if term.isAvailable() then
  120.     term.setCursor(x, y)
  121.   end
  122. end
  123.  
  124. local function getResolution()
  125.   local sizeX, sizeY = component.gpu.getResolution()
  126.   return sizeX, sizeY
  127. end
  128.  
  129. local function setColorNormal()
  130.   w.setMonitorColorFrontBack(styles.normal.front, styles.normal.back)
  131. end
  132.  
  133. local function setColorGood()
  134.   w.setMonitorColorFrontBack(styles.good.front, styles.good.back)
  135. end
  136.  
  137. local function setColorBad()
  138.   w.setMonitorColorFrontBack(styles.bad.front, styles.bad.back)
  139. end
  140.  
  141. local function setColorDisabled()
  142.   w.setMonitorColorFrontBack(styles.disabled.front, styles.disabled.back)
  143. end
  144.  
  145. local function setColorHelp()
  146.   w.setMonitorColorFrontBack(styles.help.front, styles.help.back)
  147. end
  148.  
  149. local function setColorHeader()
  150.   w.setMonitorColorFrontBack(styles.header.front, styles.header.back)
  151. end
  152.  
  153. local function setColorControl()
  154.   w.setMonitorColorFrontBack(styles.control.front, styles.control.back)
  155. end
  156.  
  157. local function setColorSelected()
  158.   w.setMonitorColorFrontBack(styles.selected.front, styles.selected.back)
  159. end
  160.  
  161. local function setColorWarning()
  162.   w.setMonitorColorFrontBack(styles.warning.front, styles.warning.back)
  163. end
  164.  
  165. local function setColorSuccess()
  166.   w.setMonitorColorFrontBack(styles.success.front, styles.success.back)
  167. end
  168.  
  169. local function clear(colorFront, colorBack)
  170.   if colorFront == nil or colorBack == nil then
  171.     w.setColorNormal()
  172.   else
  173.     w.setMonitorColorFrontBack(colorFront, colorBack)
  174.   end
  175.   term.clear()
  176.   w.setCursorPos(1, 1)
  177. end
  178.  
  179. local function clearLine()
  180.   term.clearLine()
  181.   local x, y = w.getCursorPos()
  182.   w.setCursorPos(1, y)
  183. end
  184.  
  185. local function writeLn(text)
  186.   if term.isAvailable() then
  187.     w.write(text)
  188.     local x, y = w.getCursorPos()
  189.     local xSize, ySize = w.getResolution()
  190.     if y > ySize - 1 then
  191.       y = 1
  192.     end
  193.     w.setCursorPos(1, y + 1)
  194.   end
  195. end
  196.  
  197. local function writeCentered(y, text)
  198.   local unused
  199.   if text == nil then
  200.     text = y
  201.     unused, y = w.getCursorPos()
  202.   end
  203.  
  204.   if term.isAvailable() then
  205.     local xSize, ySize = w.getResolution()
  206.     if xSize ~= nil then
  207.       component.gpu.set((xSize - text:len()) / 2, y, text)
  208.     end
  209.     w.setCursorPos(1, y + 1)
  210.   end
  211. end
  212.  
  213. local function writeFullLine(text)
  214.   if term.isAvailable() then
  215.     w.write(text)
  216.     local xSize, ySize = w.getResolution()
  217.     local xCursor, yCursor = w.getCursorPos()
  218.     for i = xCursor, xSize do
  219.       w.write(" ")
  220.     end
  221.     w.setCursorPos(1, yCursor + 1)
  222.   end
  223. end
  224.  
  225. ----------- Page support
  226.  
  227. local function page_begin(text)
  228.   w.clear()
  229.   w.setCursorPos(1, 1)
  230.   w.setColorHeader()
  231.   w.clearLine()
  232.   w.writeCentered(1, text)
  233.   w.status_refresh()
  234.   w.setCursorPos(1, 2)
  235.   w.setColorNormal()
  236. end
  237.  
  238. local function page_colors()
  239.   w.clear(colors.white, colors.black)
  240.   for key, value in pairs(colors) do
  241.     local text = string.format("%12s", key)
  242.     w.setMonitorColorFrontBack(colors.white, colors.black)
  243.     w.write(text .. " ")
  244.     w.setMonitorColorFrontBack(value, colors.black)
  245.     w.write(" " .. text .. " ")
  246.     w.setMonitorColorFrontBack(colors.black, value)
  247.     w.write(" " .. text .. " ")
  248.     w.setMonitorColorFrontBack(colors.white, value)
  249.     w.write(" " .. text .. " ")
  250.     w.setMonitorColorFrontBack(value, colors.white)
  251.     w.write(" " .. text .. " ")
  252.     w.writeLn("")
  253.   end
  254.   w.writeLn("")
  255.   local index = 0
  256.   for key, value in pairs(styles) do
  257.     local text = string.format("%12s", key)
  258.     if index % 2 == 0 then
  259.       w.setMonitorColorFrontBack(colors.white, colors.black)
  260.       w.write(text .. " ")
  261.       w.setMonitorColorFrontBack(value.front, value.back)
  262.       w.write(" " .. text .. " ")
  263.     else
  264.       w.setMonitorColorFrontBack(value.front, value.back)
  265.       w.write(" " .. text .. " ")
  266.       w.setMonitorColorFrontBack(colors.white, colors.black)
  267.       w.write(text .. " ")
  268.       w.writeLn("")
  269.     end
  270.     index = index + 1
  271.   end
  272.   w.setMonitorColorFrontBack(colors.white, colors.black)
  273. end
  274.  
  275. local function page_end()
  276.   w.setCursorPos(1, 23)
  277.   w.setColorControl()
  278.   w.writeFullLine(page_endText)
  279. end
  280.  
  281. local function page_getCallbackDisplay()
  282.   return page_callbackDisplay
  283. end
  284.  
  285. local function page_register(index, callbackDisplay, callbackKey)
  286.   page_handlers[index] = { display = callbackDisplay, key = callbackKey }
  287. end
  288.  
  289. local function page_setEndText(text)
  290.   page_endText = text
  291. end
  292.  
  293. ----------- Status line support
  294.  
  295. local status_clockTarget = -1 -- < 0 when stopped, < clock when elapsed, > clock when ticking
  296. local status_isWarning = false
  297. local status_text = ""
  298. local function status_clear()
  299.   if status_clockTarget > 0 then
  300.     status_clockTarget = -1
  301.     local xSize, ySize = w.getResolution()
  302.     w.setCursorPos(1, ySize)
  303.     w.setColorNormal()
  304.     w.clearLine()
  305.   end
  306. end
  307. local function status_isActive()
  308.   return status_clockTarget > 0 and w.event_clock() < status_clockTarget
  309. end
  310. local function status_show(isWarning, text)
  311.   if isWarning or not w.status_isActive() then
  312.     if isWarning then
  313.       status_clockTarget = w.event_clock() + 1.0
  314.     else
  315.       status_clockTarget = w.event_clock() + 0.5
  316.     end
  317.     status_isWarning = isWarning
  318.     if text ~= nil then
  319.       status_text = text
  320.     else
  321.       status_text = "???"
  322.     end
  323.     w.status_refresh()
  324.   end
  325. end
  326. local function status_refresh()
  327.   if status_clockTarget > 0 then
  328.     local xSize, ySize = w.getResolution()
  329.     w.setCursorPos(1, ySize)
  330.     w.setColorNormal()
  331.     w.clearLine()
  332.    
  333.     if w.event_clock() < status_clockTarget then
  334.       if status_isWarning then
  335.         w.setColorWarning()
  336.       else
  337.         w.setColorSuccess()
  338.       end
  339.       w.setCursorPos((xSize - status_text:len() - 2) / 2, ySize)
  340.       w.write(" " .. status_text .. " ")
  341.       w.setColorNormal()
  342.     else
  343.       status_clockTarget = -1
  344.     end
  345.   end
  346. end
  347. local function status_showWarning(text)
  348.   w.status_show(true, text)
  349. end
  350. local function status_showSuccess(text)
  351.   w.status_show(false, text)
  352. end
  353. local function status_tick()
  354.   if status_clockTarget > 0 and w.event_clock() > status_clockTarget then
  355.     local xSize, ySize = w.getResolution()
  356.     w.setCursorPos(1, ySize)
  357.     w.setColorNormal()
  358.     w.clearLine()
  359.     status_clockTarget = -1
  360.   end
  361. end
  362.  
  363. ----------- Formatting
  364.  
  365. local function format_float(value, nbchar)
  366.   local str = "?"
  367.   if value ~= nil then
  368.     if type(value) == "number" then
  369.       str = string.format("%g", value)
  370.     else
  371.       str = type(value)
  372.     end
  373.   end
  374.   if nbchar ~= nil then
  375.     str = string.sub("               " .. str, -nbchar)
  376.   end
  377.   return str
  378. end
  379.  
  380. local function format_integer(value, nbchar)
  381.   local str = "?"
  382.   if value ~= nil then
  383.     if type(value) == "number" then
  384.       str = string.format("%d", math.floor(value))
  385.     else
  386.       str = type(value)
  387.     end
  388.   end
  389.   if nbchar ~= nil then
  390.     str = string.sub("               " .. str, -nbchar)
  391.   end
  392.   return str
  393. end
  394.  
  395. local function format_boolean(value, strTrue, strFalse)
  396.   if value ~= nil then
  397.     if type(value) == "boolean" then
  398.       if value then
  399.         return strTrue
  400.       else
  401.         return strFalse
  402.       end
  403.     else
  404.       return type(value)
  405.     end
  406.   end
  407.   return "?"
  408. end
  409.  
  410. local function format_string(value, nbchar)
  411.   local str = "?"
  412.   if value ~= nil then
  413.     str = "" .. value
  414.   end
  415.   if nbchar ~= nil then
  416.     if #str > math.abs(nbchar) then
  417.       str = string.sub(str, 1, math.abs(nbchar) - 1) .. "~"
  418.     else
  419.       str = string.sub(str .. "                                                  ", 1, nbchar)
  420.     end
  421.   end
  422.   return str
  423. end
  424.  
  425. local function format_address(value)
  426.   local str = "?"
  427.   if value ~= nil then
  428.     str = "" .. value
  429.   end
  430.   str = string.sub(str, 10, 100)
  431.   return str
  432. end
  433.  
  434. ----------- Input controls
  435.  
  436. local function input_readInteger(currentValue)
  437.   local inputAbort = false
  438.   local input = w.format_integer(currentValue)
  439.   if input == "0" then
  440.     input = ""
  441.   end
  442.   local ignoreNextChar = false
  443.   local x, y = w.getCursorPos()
  444.  
  445.   term.setCursorBlink(true)
  446.   repeat
  447.     w.status_tick()
  448.     w.setCursorPos(x, y)
  449.     w.setColorNormal()
  450.     w.write(input .. "            ")
  451.     input = string.sub(input, -9)
  452.     w.setCursorPos(x + #input, y)
  453.    
  454.     local params = { event.pull() }
  455.     local eventName = params[1]
  456.     local address = params[2]
  457.     if address == nil then address = "none" end
  458.     local firstParam = params[3]
  459.     if firstParam == nil then firstParam = "none" end
  460.     if eventName == "key_down" then
  461.       local character = string.char(params[3])
  462.       local keycode = params[4]
  463.      
  464.       if keycode >= 2 and keycode <= 10 then -- 1 to 9
  465.         input = input .. w.format_integer(keycode - 1)
  466.         ignoreNextChar = true
  467.       elseif keycode == 11 or keycode == 82 then -- 0 & keypad 0
  468.         input = input .. "0"
  469.         ignoreNextChar = true
  470.       elseif keycode >= 79 and keycode <= 81 then -- keypad 1 to 3
  471.         input = input .. w.format_integer(keycode - 78)
  472.         ignoreNextChar = true
  473.       elseif keycode >= 75 and keycode <= 77 then -- keypad 4 to 6
  474.         input = input .. w.format_integer(keycode - 71)
  475.         ignoreNextChar = true
  476.       elseif keycode >= 71 and keycode <= 73 then -- keypad 7 to 9
  477.         input = input .. w.format_integer(keycode - 64)
  478.         ignoreNextChar = true
  479.       elseif keycode == 14 then -- Backspace
  480.         input = string.sub(input, 1, string.len(input) - 1)
  481.         ignoreNextChar = true
  482.       elseif keycode == 211 then -- Delete
  483.         input = ""
  484.         ignoreNextChar = true
  485.       elseif keycode == 28 then -- Enter
  486.         inputAbort = true
  487.         ignoreNextChar = true
  488.       elseif keycode == 74 or keycode == 12 or keycode == 49 then -- - on numeric keypad or - on US top or n letter
  489.         if string.sub(input, 1, 1) == "-" then
  490.           input = string.sub(input, 2)
  491.         else
  492.           input = "-" .. input
  493.         end
  494.         ignoreNextChar = true
  495.       elseif keycode == 78 then -- +
  496.         if string.sub(input, 1, 1) == "-" then
  497.           input = string.sub(input, 2)
  498.         end
  499.         ignoreNextChar = true
  500.       else
  501.         ignoreNextChar = false
  502.         -- w.status_showWarning("Key " .. keycode .. " is not supported here")
  503.       end
  504.      
  505.       if ignoreNextChar then
  506.         ignoreNextChar = false
  507.         -- w.status_showWarning("Ignored char #" .. string.byte(character) .. " '" .. character .. "'")
  508.       elseif character >= '0' and character <= '9' then -- 0 to 9
  509.         input = input .. character
  510.       elseif character == '-' or character == 'n' or character == 'N' then -- - or N
  511.         if string.sub(input, 1, 1) == "-" then
  512.           input = string.sub(input, 2)
  513.         else
  514.           input = "-" .. input
  515.         end
  516.       elseif character == '+' or character == 'p' or character == 'P' then -- + or P
  517.         if string.sub(input, 1, 1) == "-" then
  518.           input = string.sub(input, 2)
  519.         end
  520.       else
  521.         w.status_showWarning("Key '" .. character .. "' is not supported here (" .. string.byte(character) .. ")")
  522.       end
  523.      
  524.     elseif eventName == "interrupted" then
  525.       inputAbort = true
  526.      
  527.     else
  528.       local isSupported, needRedraw = w.event_handler(eventName, firstParam)
  529.       if not isSupported then
  530.         w.status_showWarning("Event '" .. eventName .. "', " .. address .. " , " .. firstParam .. " is unsupported")
  531.       end
  532.     end
  533.   until inputAbort
  534.   term.setCursorBlink(false)
  535.   w.setCursorPos(1, y + 1)
  536.   if input == "" or input == "-" then
  537.     return currentValue
  538.   else
  539.     return tonumber(input)
  540.   end
  541. end
  542.  
  543. local function input_readText(currentValue)
  544.   local inputAbort = false
  545.   local input = w.format_string(currentValue)
  546.   local ignoreNextChar = false
  547.   local x, y = w.getCursorPos()
  548.  
  549.   term.setCursorBlink(true)
  550.   repeat
  551.     w.status_tick()
  552.     -- update display clearing extra characters
  553.     w.setCursorPos(x, y)
  554.     w.setColorNormal()
  555.     w.write(w.format_string(input, 37))
  556.     -- truncate input and set caret position
  557.     input = string.sub(input, -36)
  558.     w.setCursorPos(x + #input, y)
  559.    
  560.     local params = { event.pull() }
  561.     local eventName = params[1]
  562.     local address = params[2]
  563.     if address == nil then address = "none" end
  564.     local firstParam = params[3]
  565.     if firstParam == nil then firstParam = "none" end
  566.     if eventName == "key_down" then
  567.       local character = string.char(params[3])
  568.       local keycode = params[4]
  569.      
  570.       if keycode == 14 then -- Backspace
  571.         input = string.sub(input, 1, string.len(input) - 1)
  572.         ignoreNextChar = true
  573.       elseif keycode == 211 then -- Delete
  574.         input = ""
  575.         ignoreNextChar = true
  576.       elseif keycode == 28 then -- Enter
  577.         inputAbort = true
  578.         ignoreNextChar = true
  579.       else
  580.         ignoreNextChar = false
  581.         -- w.status_showWarning("Key " .. keycode .. " is not supported here")
  582.       end
  583.      
  584.       if ignoreNextChar then
  585.         ignoreNextChar = false
  586.         -- w.status_showWarning("Ignored char #" .. string.byte(character) .. " '" .. character .. "'")
  587.       elseif character >= ' ' and character <= '~' then -- any ASCII table minus controls and DEL
  588.         input = input .. character
  589.       else
  590.         w.status_showWarning("Key '" .. character .. "' is not supported here (" .. string.byte(character) .. ")")
  591.       end
  592.      
  593.     elseif eventName == "interrupted" then
  594.       inputAbort = true
  595.      
  596.     else
  597.       local isSupported, needRedraw = w.event_handler(eventName, firstParam)
  598.       if not isSupported then
  599.         w.status_showWarning("Event '" .. eventName .. "', " .. address .. ", " .. firstParam .. " is unsupported")
  600.       end
  601.     end
  602.   until inputAbort
  603.   term.setCursorBlink(false)
  604.   w.setCursorPos(1, y + 1)
  605.   if input == "" then
  606.     return currentValue
  607.   else
  608.     return input
  609.   end
  610. end
  611.  
  612. local function input_readConfirmation(message)
  613.   if message == nil then
  614.     message = "Are you sure? (Y/n)"
  615.   end
  616.   w.status_showWarning(message)
  617.   repeat
  618.     local params = { event.pull() }
  619.     local eventName = params[1]
  620.     local address = params[2]
  621.     if address == nil then address = "none" end
  622.     local firstParam = params[3]
  623.     if firstParam == nil then firstParam = "none" end
  624.     if eventName == "key_down" then
  625.       local character = string.char(params[3])
  626.       local keycode = params[4]
  627.      
  628.       if keycode == 28 then -- Return or Enter
  629.         w.status_clear()
  630.         return true
  631.       end
  632.      
  633.       w.status_clear()
  634.       if character == 'y' or character == 'Y' then -- Y
  635.         return true
  636.       else
  637.         return false
  638.       end
  639.      
  640.     elseif eventName == "interrupted" then
  641.       return false
  642.      
  643.     else
  644.       local isSupported, needRedraw = w.event_handler(eventName, firstParam)
  645.       if not isSupported then
  646.         w.status_showWarning("Event '" .. eventName .. "', " .. firstParam .. " is unsupported")
  647.       end
  648.     end
  649.     if not w.status_isActive() then
  650.       w.status_showWarning(message)
  651.     end
  652.   until false
  653. end
  654.  
  655. local function input_readEnum(currentValue, list, toValue, toDescription, noValue)
  656.   local inputAbort = false
  657.   local inputKey = nil
  658.   local input = nil
  659.   local inputDescription = nil
  660.   local ignoreNextChar = false
  661.   local x, y = w.getCursorPos()
  662.  
  663.   w.setCursorPos(1, 17)
  664.   for key, entry in pairs(list) do
  665.     if toValue(entry) == currentValue then
  666.       inputKey = key
  667.     end
  668.   end
  669.  
  670.   term.setCursorBlink(true)
  671.   repeat
  672.     w.status_tick()
  673.     w.setCursorPos(x, y)
  674.     w.setColorNormal()
  675.     if #list == 0 then
  676.       inputKey = nil
  677.     end
  678.     if inputKey == nil then
  679.       if currentValue ~= nil then
  680.         input = noValue
  681.         inputDescription = "Press enter to return previous entry"
  682.       else
  683.         input = noValue
  684.         inputDescription = "Press enter to close listing"
  685.       end
  686.     else
  687.       if inputKey < 1 then
  688.         inputKey = #list
  689.       elseif inputKey > #list then
  690.         inputKey = 1
  691.       end
  692.      
  693.       input = toValue(list[inputKey])
  694.       inputDescription = toDescription(list[inputKey])
  695.     end
  696.     w.setColorNormal()
  697.     w.write(input .. "                                                  ")
  698.     w.setCursorPos(1, y + 1)
  699.     w.setColorDisabled()
  700.     w.write(inputDescription .. "                                                  ")
  701.    
  702.     local params = { event.pull() }
  703.     local eventName = params[1]
  704.     local address = params[2]
  705.     if address == nil then address = "none" end
  706.     local firstParam = params[3]
  707.     if firstParam == nil then firstParam = "none" end
  708.     if eventName == "key_down" then
  709.       local character = string.char(params[3])
  710.       local keycode = params[4]
  711.      
  712.       if keycode == 14 or keycode == 211 then -- Backspace or Delete
  713.         inputKey = nil
  714.         ignoreNextChar = true
  715.       elseif keycode == 200 or keycode == 203 or keycode == 78 then -- Up or Left or +
  716.         if inputKey == nil then
  717.           inputKey = 1
  718.         else
  719.           inputKey = inputKey - 1
  720.         end
  721.         ignoreNextChar = true
  722.       elseif keycode == 208 or keycode == 205 or keycode == 74 then -- Down or Right or -
  723.         if inputKey == nil then
  724.           inputKey = 1
  725.         else
  726.           inputKey = inputKey + 1
  727.         end
  728.         ignoreNextChar = true
  729.       elseif keycode == 28 then -- Enter
  730.         inputAbort = true
  731.         ignoreNextChar = true
  732.       else
  733.         ignoreNextChar = false
  734.         -- w.status_showWarning("Key " .. keycode .. " is not supported here")
  735.       end
  736.      
  737.       if ignoreNextChar then
  738.         ignoreNextChar = false
  739.         -- w.status_showWarning("Ignored char #" .. string.byte(character) .. " '" .. character .. "'")
  740.       elseif character == '+' then -- +
  741.         if inputKey == nil then
  742.           inputKey = 1
  743.         else
  744.           inputKey = inputKey - 1
  745.         end
  746.       elseif character == '-' then -- -
  747.         if inputKey == nil then
  748.           inputKey = 1
  749.         else
  750.           inputKey = inputKey + 1
  751.         end
  752.       else
  753.         w.status_showWarning("Key '" .. character .. "' is not supported here (" .. string.byte(character) .. ")")
  754.       end
  755.      
  756.     elseif eventName == "interrupted" then
  757.       inputAbort = true
  758.      
  759.     elseif not w.event_handler(eventName, firstParam) then
  760.       w.status_showWarning("Event '" .. eventName .. "', " .. address .. ", " .. firstParam .. " is unsupported")
  761.     end
  762.   until inputAbort
  763.   term.setCursorBlink(false)
  764.   w.setCursorPos(1, y + 1)
  765.   w.clearLine()
  766.   if inputKey == nil then
  767.     return nil
  768.   else
  769.     return toValue(list[inputKey])
  770.   end
  771. end
  772.  
  773. ----------- Event handlers
  774.  
  775. local function reboot()
  776.   computer.shutdown(true)
  777. end
  778.  
  779. local function sleep(delay)
  780.   os.sleep(delay)
  781. end
  782.  
  783. -- return a global clock measured in second
  784. local function event_clock()
  785.   return computer.uptime()
  786. end
  787.  
  788. local function event_refresh_start()
  789.   if event_refreshTimerId == -1 then
  790.     event_refreshTimerId = event.timer(event_refreshPeriod_s, function () w.event_refresh_tick() end, math.huge)
  791.   end
  792. end
  793.  
  794. local function event_refresh_stop()
  795.   if event_refreshTimerId ~= -1 then
  796.     event.cancel(event_refreshTimerId)
  797.     event_refreshTimerId = -1
  798.   end
  799. end
  800.  
  801. local function event_refresh_tick()
  802.   event.push("timer_refresh")
  803. end
  804.  
  805. local function event_register(eventName, callback)
  806.   event_handlers[eventName] = callback
  807. end
  808.  
  809. -- returns isSupported, needRedraw
  810. local function event_handler(eventName, param)
  811.   local needRedraw = false
  812.   if eventName == "redstone" then
  813.     -- w.redstone_event(param)
  814.   elseif eventName == "timer_refresh" then
  815.     needRedraw = page_callbackDisplay ~= page_handlers['0'].display
  816.   elseif eventName == "key_up" then
  817.   elseif eventName == "touch" then
  818.     w.status_showSuccess("Use the keyboard, Luke!")
  819.   elseif eventName == "drop" then
  820.   elseif eventName == "drag" then
  821.   elseif eventName == "scroll" then
  822.   elseif eventName == "walk" then
  823.   elseif eventName == "component_added" then
  824.   elseif eventName == "component_removed" then
  825.   elseif eventName == "component_available" then
  826.   elseif eventName == "component_unavailable" then
  827.   elseif eventName == "gpu_bound" then-- OpenOS internal event?
  828.   elseif eventName == "term_available" then
  829.     needRedraw = true
  830.   elseif eventName == "term_unavailable" then
  831.     needRedraw = true
  832.   -- not supported: task_complete, rednet_message, modem_message
  833.   elseif event_handlers[eventName] ~= nil then
  834.     needRedraw = event_handlers[eventName](eventName, param)
  835.   else
  836.     return false, needRedraw
  837.   end
  838.   return true, needRedraw
  839. end
  840.  
  841. ----------- Configuration
  842.  
  843. local function data_get()
  844.   return data
  845. end
  846.  
  847. local function data_inspect(key, value)
  848.   local stringValue = type(value) .. ","
  849.   if type(value) == "boolean" then
  850.     if value then
  851.       stringValue = "true,"
  852.     else
  853.       stringValue = "false,"
  854.     end
  855.   elseif type(value) == "number" then
  856.     stringValue = value .. ","
  857.   elseif type(value) == "string" then
  858.     stringValue = "'" .. value .. "',"
  859.   elseif type(value) == "table" then
  860.     stringValue = "{"
  861.   end
  862.   print(" " .. key .. " = " .. stringValue)
  863.   if type(value) == "table" then
  864.     for subkey, subvalue in pairs(value) do
  865.       w.data_inspect(subkey, subvalue)
  866.     end
  867.     print("}")
  868.   end
  869. end
  870.  
  871. local function data_read()
  872.   w.data_shouldUpdateName()
  873.  
  874.   data = { }
  875.   if fs.exists("/etc/shipdata.txt") then
  876.     local size = fs.size("/etc/shipdata.txt")
  877.     if size > 0 then
  878.       local file = io.open("/etc/shipdata.txt", "r")
  879.       if file ~= nil then
  880.         local rawData = file:read("*all")
  881.         if rawData ~= nil then
  882.           data = serialization.unserialize(rawData)
  883.         end
  884.         file:close()
  885.         if data == nil then
  886.           data = {}
  887.         end
  888.       end
  889.     end
  890.   end
  891.  
  892.   for name, handlers in pairs(data_handlers) do
  893.     handlers.read(data)
  894.   end
  895. end
  896.  
  897. local function data_save()
  898.   for name, handlers in pairs(data_handlers) do
  899.     handlers.save(data)
  900.   end
  901.  
  902.   local file = io.open("/etc/shipdata.txt", "w")
  903.   if file ~= nil then
  904.     file:write(serialization.serialize(data))
  905.     file:close()
  906.   else
  907.     w.status_showWarning("No file system")
  908.     w.sleep(3.0)
  909.   end
  910. end
  911.  
  912. local function data_getName()
  913.   if data_name ~= nil then
  914.     return data_name
  915.   else
  916.     return "-noname-"
  917.   end
  918. end
  919.  
  920. local function data_setName()
  921.   -- check if any named component is connected
  922.   local component = "computer"
  923.   for name, handlers in pairs(data_handlers) do
  924.     if handlers.name ~= nil then
  925.       component = name
  926.     end
  927.   end
  928.  
  929.   -- ask for a new name
  930.   w.page_begin("<==== Set " .. component .. " name ====>")
  931.   w.setCursorPos(1, 4)
  932.   w.setColorHelp()
  933.   w.writeFullLine(" Press enter to validate.")
  934.   w.setCursorPos(1, 3)
  935.   w.setColorNormal()
  936.   w.write("Enter " .. component .. " name: ")
  937.   data_name = w.input_readText(data_name)
  938.  
  939.   -- OpenComputers only allows to label filesystems => out
  940.  
  941.   -- update connected components
  942.   for name, handlers in pairs(data_handlers) do
  943.     if handlers.name ~= nil then
  944.       handlers.name(data_name)
  945.     end
  946.   end
  947.  
  948.   -- w.reboot() -- not needed
  949. end
  950.  
  951. local function data_shouldUpdateName()
  952.   local shouldUpdateName = false
  953.  
  954.   -- check computer name
  955.   data_name = "" .. computer.address()
  956.   local nameDefault = data_name
  957.  
  958.   -- check connected components names
  959.   for name, handlers in pairs(data_handlers) do
  960.     if handlers.name ~= nil then
  961.       local componentName = handlers.name()
  962.       if componentName == "default" or componentName == "" then
  963.         shouldUpdateName = true
  964.       elseif shouldUpdateName then
  965.         data_name = componentName
  966.       elseif data_name ~= componentName then
  967.         shouldUpdateName = data_name ~= nameDefault
  968.         data_name = componentName
  969.       end
  970.     end
  971.   end
  972.  
  973.   return shouldUpdateName
  974. end
  975.  
  976. local function data_splitString(source, sep)
  977.   local sep = sep or ":"
  978.   local fields = {}
  979.   local pattern = string.format("([^%s]+)", sep)
  980.   source:gsub(pattern, function(c) fields[#fields + 1] = c end)
  981.   return fields
  982. end
  983.  
  984. local function data_register(name, callbackRead, callbackSave, callbackName)
  985.   -- read/save callbacks are always defined
  986.   if callbackRead == nil then
  987.     callbackRead = function() end
  988.   end
  989.   if callbackSave == nil then
  990.     callbackSave = function() end
  991.   end
  992.  
  993.   -- name callback is nil when not defined
  994.  
  995.   data_handlers[name] = { read = callbackRead, save = callbackSave, name = callbackName }
  996. end
  997.  
  998. ----------- Devices
  999.  
  1000. local function device_get(address)
  1001.   return component.proxy(address)
  1002. end
  1003.  
  1004. local function device_getMonitors()
  1005.   return monitors
  1006. end
  1007.  
  1008. local function device_register(deviceType, callbackRegister, callbackUnregister)
  1009.   device_handlers[deviceType] = { register = callbackRegister, unregister = callbackUnregister }
  1010. end
  1011.  
  1012. ----------- Main loop
  1013.  
  1014.  
  1015. local function boot()
  1016.   if not term.isAvailable() then
  1017.     computer.beep()
  1018.     os.exit()
  1019.   end
  1020.   if component.gpu.getDepth() < 4 then
  1021.     print("A tier 2 or higher GPU required")
  1022.     print("A tier 2 or higher screen required")
  1023.     os.exit()
  1024.   end
  1025.   print("loading...")
  1026.  
  1027.   math.randomseed(os.time())
  1028.  
  1029.   -- read configuration
  1030.   w.data_read()
  1031.   w.clear()
  1032.   print("data_read...")
  1033.  
  1034.   -- initial scanning
  1035.   monitors = {}
  1036.   w.page_begin(data_name .. " - Connecting...")
  1037.   w.writeLn("")
  1038.  
  1039.   for address, deviceType in component.list() do
  1040.     w.sleep(0)
  1041.     w.write("Checking " .. address .. " ")
  1042.     w.write(deviceType .. " ")
  1043.     local handlers = device_handlers[deviceType]
  1044.     if handlers ~= nil then
  1045.       w.write("wrapping!")
  1046.       handlers.register(deviceType, address, w.device_get(address))
  1047.     end
  1048.    
  1049.     w.writeLn("")
  1050.   end
  1051.  
  1052.   -- synchronize computer and connected components names
  1053.   local shouldUpdateName = w.data_shouldUpdateName()
  1054.   if shouldUpdateName then
  1055.     w.data_setName()
  1056.   end
  1057.  
  1058.   -- peripheral boot up
  1059.   if page_handlers['0'] == nil then
  1060.     w.status_showWarning("Missing handler for connection page '0'!")
  1061.     os.exit()
  1062.   end
  1063.   page_handlers['0'].display(true)
  1064. end
  1065.  
  1066. local function run()
  1067.   local abort = false
  1068.   local refresh = true
  1069.   local ignoreNextChar = false
  1070.  
  1071.   local function selectPage(index)
  1072.     if page_handlers[index] ~= nil then
  1073.       page_callbackDisplay = page_handlers[index].display
  1074.       page_callbackKey = page_handlers[index].key
  1075.       refresh = true
  1076.       return true
  1077.     end
  1078.     return false
  1079.   end
  1080.  
  1081.   -- start refresh timer
  1082.   w.event_refresh_start()
  1083.  
  1084.   -- main loop
  1085.   selectPage('0')
  1086.   repeat
  1087.     w.status_tick()
  1088.     if refresh then
  1089.       w.clear()
  1090.       page_callbackDisplay(false)
  1091.       w.page_end()
  1092.       refresh = false
  1093.     end
  1094.     local params = { event.pull() }
  1095.     local eventName = params[1]
  1096.     local address = params[2]
  1097.     if address == nil then address = "none" end
  1098.     local firstParam = params[3]
  1099.     if firstParam == nil then firstParam = "none" end
  1100.     -- w.writeLn("...")
  1101.     -- w.writeLn("Event '" .. eventName .. "', " .. firstParam .. " received")
  1102.     -- w.sleep(0.2)
  1103.    
  1104.     if eventName == "key_down" then
  1105.       local character = string.char(params[3])
  1106.       local keycode = params[4]
  1107.      
  1108.       ignoreNextChar = false
  1109.       if keycode == 11 or keycode == 82 then -- 0
  1110.         if selectPage('0') then
  1111.           ignoreNextChar = true
  1112.         end
  1113.       elseif keycode == 2 or keycode == 79 then -- 1
  1114.         if selectPage('1') then
  1115.           ignoreNextChar = true
  1116.         end
  1117.       elseif keycode == 3 or keycode == 80 then -- 2
  1118.         if selectPage('2') then
  1119.           ignoreNextChar = true
  1120.         end
  1121.       elseif keycode == 4 or keycode == 81 then -- 3
  1122.         if selectPage('3') then
  1123.           ignoreNextChar = true
  1124.         end
  1125.       elseif keycode == 5 or keycode == 82 then -- 4
  1126.         if selectPage('4') then
  1127.           ignoreNextChar = true
  1128.         end
  1129.       elseif keycode == 6 or keycode == 83 then -- 5
  1130.         if selectPage('5') then
  1131.           ignoreNextChar = true
  1132.         end
  1133.       else
  1134.         ignoreNextChar = false
  1135.         -- w.status_showWarning("Key " .. keycode .. " is not supported here")
  1136.       end
  1137.      
  1138.       if ignoreNextChar then
  1139.         ignoreNextChar = false
  1140.         -- w.status_showWarning("Ignored char #" .. string.byte(character) .. " '" .. character .. "'")
  1141. --      elseif character == 'x' or character == 'X' then -- x for eXit
  1142. --        -- event.pull() -- remove key_up event
  1143. --        abort = true
  1144.       elseif character == '0' then
  1145.         selectPage('0')
  1146.       elseif character == '1' then
  1147.         selectPage('1')
  1148.       elseif character == '2' then
  1149.         selectPage('2')
  1150.       elseif character == '3' then
  1151.         selectPage('3')
  1152.       elseif character == '4' then
  1153.         selectPage('4')
  1154.       elseif character == '5' then
  1155.         selectPage('5')
  1156.       elseif page_callbackKey ~= nil and page_callbackKey(character, keycode) then
  1157.         refresh = true
  1158.       elseif string.byte(character) ~= 0 then -- not a control char
  1159.         w.status_showWarning("Key '" .. character .. "' is not supported here (" .. string.byte(character) .. ")")
  1160.       end
  1161.      
  1162.     elseif eventName == "interrupted" then
  1163.       abort = true
  1164.      
  1165.     else
  1166.       local isSupported, needRedraw = w.event_handler(eventName, firstParam)
  1167.       if not isSupported then
  1168.         w.status_showWarning("Event '" .. eventName .. "', " .. firstParam .. " is unsupported")
  1169.       end
  1170.       refresh = needRedraw
  1171.     end
  1172.   until abort
  1173.  
  1174.   -- stop refresh timer
  1175.   w.event_refresh_stop()
  1176. end
  1177.  
  1178. local function close()
  1179.   w.clear(colors.white, colors.black)
  1180.   for key, handlers in pairs(device_handlers) do
  1181.     w.writeLn("Closing " .. key)
  1182.     if handlers.unregister ~= nil then
  1183.       handlers.unregister(key)
  1184.     end
  1185.   end
  1186.  
  1187.   w.clear(colors.white, colors.black)
  1188.   w.setCursorPos(1, 1)
  1189.   w.writeLn("Program closed")
  1190.   w.writeLn("Type reboot to return to home page")
  1191. end
  1192.  
  1193. w = {
  1194.   setMonitorColorFrontBack = setMonitorColorFrontBack,
  1195.   send_coords = send_coords,
  1196.   write = write,
  1197.   getCursorPos = getCursorPos,
  1198.   setCursorPos = setCursorPos,
  1199.   getResolution = getResolution,
  1200.   setColorNormal = setColorNormal,
  1201.   setColorGood = setColorGood,
  1202.   setColorBad = setColorBad,
  1203.   setColorDisabled = setColorDisabled,
  1204.   setColorHelp = setColorHelp,
  1205.   setColorHeader = setColorHeader,
  1206.   setColorControl = setColorControl,
  1207.   setColorSelected = setColorSelected,
  1208.   setColorWarning = setColorWarning,
  1209.   setColorSuccess = setColorSuccess,
  1210.   clear = clear,
  1211.   clearLine = clearLine,
  1212.   writeLn = writeLn,
  1213.   writeCentered = writeCentered,
  1214.   writeFullLine = writeFullLine,
  1215.   page_begin = page_begin,
  1216.   page_colors = page_colors,
  1217.   page_end = page_end,
  1218.   page_getCallbackDisplay = page_getCallbackDisplay,
  1219.   page_register = page_register,
  1220.   page_setEndText = page_setEndText,
  1221.   status_clear = status_clear,
  1222.   status_isActive = status_isActive,
  1223.   status_show = status_show,
  1224.   status_refresh = status_refresh,
  1225.   status_showWarning = status_showWarning,
  1226.   status_showSuccess = status_showSuccess,
  1227.   status_tick = status_tick,
  1228.   format_float = format_float,
  1229.   format_integer = format_integer,
  1230.   format_boolean = format_boolean,
  1231.   format_string = format_string,
  1232.   format_address = format_address,
  1233.   input_readInteger = input_readInteger,
  1234.   input_readText = input_readText,
  1235.   input_readConfirmation = input_readConfirmation,
  1236.   input_readEnum = input_readEnum,
  1237.   reboot = reboot,
  1238.   sleep = sleep,
  1239.   event_clock = event_clock,
  1240.   event_refresh_start = event_refresh_start,
  1241.   event_refresh_stop = event_refresh_stop,
  1242.   event_refresh_tick = event_refresh_tick,
  1243.   event_register = event_register,
  1244.   event_handler = event_handler,
  1245.   data_get = data_get,
  1246.   data_inspect = data_inspect,
  1247.   data_read = data_read,
  1248.   data_save = data_save,
  1249.   data_getName = data_getName,
  1250.   data_setName = data_setName,
  1251.   data_shouldUpdateName = data_shouldUpdateName,
  1252.   data_splitString = data_splitString,
  1253.   data_register = data_register,
  1254.   device_get = device_get,
  1255.   device_getMonitors = device_getMonitors,
  1256.   device_register = device_register,
  1257.   boot = boot,
  1258.   run = run,
  1259.   close = close,
  1260. }
  1261.  
  1262. return w
RAW Paste Data