Advertisement
pickar

warpdriveCommons.lua

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