Advertisement
Guest User

Untitled

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