jaklsfjlsak

福瑞导航api.lua

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