kriNon

Untitled

Dec 29th, 2015
54
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 38.29 KB | None | 0 0
  1.  
  2.  
  3. -- EU Control Center (EUCC) v0.3
  4. -- by Hansbald
  5. -- PLEASE NOTE
  6. -- This is HEAVILY based on RF Control Center (RFCC) v0.3 by dragonlord
  7. -- I only changed some things to make it work with EU
  8.  
  9.  
  10. -- Main configuration
  11. local tArgs = {...}
  12. local CONFIG_FILE = "power_conf"
  13.  
  14. local CONFIG_TEMPLATE = [[-- adjust these configuration options as necessary.
  15. -- delay for checking all capacitors
  16. TICK_DELAY = ${tickDelay}
  17.  
  18. -- threshold in percentages
  19. GREEN_ZONE = ${greenZone}
  20. YELLOW_ZONE = ${yellowZone}
  21.  
  22. NORMAL_POWER_THRESHOLD = ${nomalPowerThreshold}
  23. LOW_POWER_THRESHOLD = ${lowPowerThreshold}
  24.  
  25. -- configures what side to emit when low power
  26. -- a valid side is required.
  27. SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER = "${sideForRedstone}"
  28.  
  29. -- Active monitors on startup
  30. MONITORS_ACTIVE = ${monitorsActive}
  31. ]]
  32.  
  33. local MONITORS_ACTIVE = {}
  34.  
  35. do
  36. if #tArgs > 0 and tArgs[1] == "update" then
  37. print("This fork doesnt support update yet :(")
  38. end
  39. end
  40.  
  41. local function interpolate(s, params)
  42. return s:gsub('($%b{})', function(w) return params[w:sub(3, -2)] or w end)
  43. end
  44.  
  45. local function saveSettings()
  46. local h = fs.open("/"..CONFIG_FILE, "w")
  47.  
  48. local settings = {
  49. tickDelay = TICK_DELAY or 100,
  50. greenZone = GREEN_ZONE or 70,
  51. yellowZone = YELLOW_ZONE or 30,
  52. nomalPowerThreshold = NORMAL_POWER_THRESHOLD or 90,
  53. lowPowerThreshold = LOW_POWER_THRESHOLD or 10,
  54. sideForRedstone = SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER or "bottom",
  55. monitorsActive = textutils.serialize(MONITORS_ACTIVE)
  56. }
  57.  
  58. h.write(interpolate(CONFIG_TEMPLATE, settings))
  59. h.close()
  60. end
  61.  
  62.  
  63. if fs.exists(CONFIG_FILE) == false then
  64. print("EU Control Center by Hansbald | A fork of dragonlord's EUCC")
  65. print("I can't find my configuration file.")
  66. print("Generating one for you.")
  67.  
  68. saveSettings()
  69.  
  70. print("")
  71. print("Configuration file is located at /"..CONFIG_FILE)
  72. print("You may edit this file to change my default settings.")
  73. print("Once satisfied, run me again.")
  74. return
  75. else
  76. os.unloadAPI(CONFIG_FILE)
  77.  
  78. if os.loadAPI("/"..CONFIG_FILE) == false then
  79. error("Could not load the config file!")
  80. end
  81.  
  82. CONFIG = nil
  83. for k, v in pairs(_G) do
  84. if k == CONFIG_FILE then
  85. CONFIG = v
  86. break
  87. end
  88. end
  89.  
  90. if CONFIG == nil then
  91. print("I could not find the necessary config.")
  92. print("You probably screwed something up.")
  93. error()
  94. end
  95. end
  96.  
  97. term.setCursorPos(1, 1)
  98. term.clear()
  99. print("Starting EU Control Center...")
  100. sleep(2)
  101.  
  102. -- Constants
  103. local GET_ENERGY_STORED_FUNCTION="getEnergyStored"
  104. local GET_MAX_ENERGY_STORED_FUNCTION="getMaxEnergyStored"
  105.  
  106. local GET_ENERGY_STORED_FUNCTION_MFSU="getEUStored"
  107. local GET_MAX_ENERGY_STORED_FUNCTION_MFSU="getEUCapacity"
  108.  
  109. local TICK_DELAY = CONFIG.TICK_DELAY
  110. local PAUSE_TIME_IN_SECONDS = TICK_DELAY / 20
  111.  
  112. -- threshold in percentages
  113. local GREEN_ZONE = CONFIG.GREEN_ZONE
  114. local YELLOW_ZONE = CONFIG.YELLOW_ZONE
  115.  
  116. local NORMAL_POWER_THRESHOLD = CONFIG.NORMAL_POWER_THRESHOLD
  117. local LOW_POWER_THRESHOLD = CONFIG.LOW_POWER_THRESHOLD
  118.  
  119. -- configures what side to emit when low power
  120. local SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER = CONFIG.SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER
  121.  
  122. MONITORS_ACTIVE = CONFIG.MONITORS_ACTIVE
  123.  
  124. -- state variables
  125. local clickableLines = {}
  126. local clickableOutputMonitors = {}
  127. local monitors = {}
  128. local capacitors = {}
  129. local dashboardButtons = {}
  130. local totalEnergyAvailable, totalCapacity, totalFlowRate = 0, 0, 0
  131.  
  132. -- Capacitor basic functions
  133. do
  134. capacitors.add = function(params)
  135. table.insert(capacitors, params)
  136. end
  137.  
  138. capacitors.get = function(name)
  139. for i, v in ipairs(capacitors) do
  140. if name == v.name then
  141. return v
  142. end
  143. end
  144.  
  145. return nil
  146. end
  147.  
  148. capacitors.remove = function(name)
  149. local found = nil
  150. for i, v in ipairs(capacitors) do
  151. if name == v.name then
  152. found = i
  153. break
  154. end
  155. end
  156.  
  157. if found then
  158. table.remove(capacitors, found)
  159. end
  160. end
  161.  
  162. capacitors.clear = function()
  163. for i, v in ipairs(capacitors) do
  164. capacitors[i] = nil
  165. end
  166. end
  167. end
  168.  
  169.  
  170. -- Special Windows
  171. local nativeDisplayTabs = {}
  172. local nativeMonitorTabWindow
  173. local consoleWindow
  174. local monitorSelectionWindow
  175.  
  176. do
  177. local nativeTerm = term.native()
  178. local width, height = term.getSize()
  179. local x, y = 1, 2
  180. local newWidth, newHeight = width, height - 1
  181.  
  182. nativeTerm.setCursorPos(x, y)
  183.  
  184. nativeMonitorTabWindow = window.create(nativeTerm, 1, 1, width, 1, false)
  185.  
  186. consoleWindow = window.create(nativeTerm, x, y, newWidth, newHeight, false)
  187. consoleWindow.active = true
  188.  
  189. monitorSelectionWindow = window.create(nativeTerm, x, y, newWidth, newHeight, false)
  190. monitorSelectionWindow.active = true
  191. end
  192.  
  193. -- TODO: break up this humongous script into smaller chunks that can be loaded
  194. -- via os.loadAPI().
  195.  
  196.  
  197. -- basic functions
  198. local function tableSize(targetTable)
  199. local i = 0
  200. for k, v in pairs(targetTable) do
  201. i = i + 1
  202. end
  203.  
  204. return i
  205. end
  206.  
  207. local function padRight(text, width, padCharacter)
  208. if width == nil then
  209. width = term.getSize()
  210. end
  211.  
  212. padCount = width - string.len(text)
  213.  
  214. if padCharacter == nil then
  215. padCharacter = " "
  216. end
  217.  
  218. if padCount > 0 then
  219. return text..string.rep(padCharacter, padCount)
  220. else
  221. return text
  222. end
  223. end
  224.  
  225. local function padLeft(text, width, padCharacter)
  226. if width == nil then
  227. width = term.getSize()
  228. end
  229.  
  230. padCount = width - string.len(text)
  231.  
  232. if padCharacter == nil then
  233. padCharacter = " "
  234. end
  235.  
  236. if padCount > 0 then
  237. return string.rep(padCharacter, padCount)..text
  238. else
  239. return text
  240. end
  241. end
  242.  
  243. local function printZoneText(percent, callback)
  244. if percent >= GREEN_ZONE then
  245. term.setTextColor(colors.green)
  246. elseif percent >= YELLOW_ZONE and percent < GREEN_ZONE then
  247. term.setTextColor(colors.yellow)
  248. else
  249. term.setTextColor(colors.red)
  250. end
  251.  
  252. callback()
  253.  
  254. term.setTextColor(colors.white)
  255. end
  256.  
  257. local function resetRedstoneState()
  258. for k,v in pairs(rs.getSides()) do
  259. rs.setOutput(v, false)
  260. end
  261. end
  262. -- basic functions
  263.  
  264.  
  265. -- line drawing API
  266. local function drawVerticalLine(targetWindow, x, y, height)
  267. targetWindow.setCursorPos(x, y)
  268.  
  269. targetWindow.setBackgroundColor(colors.blue)
  270. for i = 1, height do
  271. targetWindow.write(" ")
  272. targetWindow.setCursorPos(x, i)
  273. end
  274. targetWindow.setBackgroundColor(colors.black)
  275. end
  276.  
  277. local function drawHorizontalLine(targetWindow, x, y, width)
  278. targetWindow.setCursorPos(x, y)
  279. targetWindow.setBackgroundColor(colors.blue)
  280. targetWindow.write(string.rep(" ", width))
  281. targetWindow.setBackgroundColor(colors.black)
  282. end
  283. -- line drawing API
  284.  
  285.  
  286. -- window management
  287. local console = {
  288. log = function(message)
  289. local currentTerm = term.current()
  290. term.redirect(consoleWindow)
  291.  
  292. print(message)
  293.  
  294. term.redirect(currentTerm)
  295. end
  296. }
  297.  
  298. local function showWindows(...)
  299. for i, v in ipairs(arg) do
  300. if v.active == true then
  301. v.setVisible(true)
  302. else
  303. v.setVisible(false)
  304. end
  305. end
  306. end
  307.  
  308. local function hideWindows(...)
  309. for i, v in ipairs(arg) do
  310. v.setVisible(false)
  311. end
  312. end
  313.  
  314. local function getCursorPositionRelativeToParent(currentWindow)
  315. -- determine offset of current window from parent
  316. local x, y = currentWindow.getPosition()
  317. local xOffset, yOffset = x - 1, y - 1
  318.  
  319. local cursorX, cursorY = currentWindow.getCursorPos()
  320. return cursorX + xOffset, cursorY + yOffset
  321. end
  322.  
  323. local function createInformationWindow(parentWindow)
  324. local width, height = parentWindow.getSize()
  325.  
  326. local widthOffset = 2
  327. local heightOffset = 2
  328.  
  329. local windowWidth = width - (widthOffset * 2)
  330. local windowHeight = height - (heightOffset * 2)
  331.  
  332. local informationWindow = window.create(parentWindow, 1 + widthOffset, 1 + heightOffset, windowWidth, windowHeight, false)
  333. informationWindow.active = false
  334.  
  335. drawHorizontalLine(informationWindow, 1, 1, windowWidth)
  336. drawHorizontalLine(informationWindow, 1, windowHeight, windowWidth)
  337.  
  338. drawVerticalLine(informationWindow, 1, 1, windowHeight)
  339. drawVerticalLine(informationWindow, windowWidth, 1, windowHeight)
  340.  
  341. return informationWindow
  342. end
  343.  
  344. local function createSummaryWindow(parentWindow, x, y)
  345. local width, height = parentWindow.getSize()
  346.  
  347. -- we make use of the parent window's cursor position to make it more convenient.
  348. local x, y = parentWindow.getCursorPos()
  349. local newHeight = height - (y - 1)
  350.  
  351. local summaryWindow = window.create(parentWindow, x, y, width, newHeight, false)
  352. summaryWindow.active = false
  353.  
  354. return summaryWindow
  355. end
  356.  
  357. local function printToWindow(targetWindow, widthOffset, text)
  358. local x, y = targetWindow.getCursorPos()
  359. local width, height = targetWindow.getSize()
  360. local maxTextSize = width - (widthOffset * 2)
  361.  
  362. targetWindow.write(text:sub(1, maxTextSize))
  363. targetWindow.setCursorPos(x, y+1)
  364. end
  365.  
  366. local function createDashboardWindows(parentWindow)
  367. -- order is important here!
  368. local summaryWindow = createSummaryWindow(parentWindow)
  369. summaryWindow.active = true
  370. local informationWindow = createInformationWindow(parentWindow)
  371. informationWindow.active = false
  372.  
  373. local windows = {
  374. [1] = summaryWindow,
  375. [2] = informationWindow,
  376.  
  377. getSummaryWindow = function()
  378. return summaryWindow
  379. end,
  380.  
  381. getInformationWindow = function()
  382. return informationWindow
  383. end
  384. }
  385.  
  386. return windows
  387. end
  388.  
  389. local function initializeNativeDisplayTabs()
  390. local nativeTerm = term.native()
  391. nativeTerm.setCursorPos(1, 2)
  392.  
  393. local dashboardWindows = createDashboardWindows(nativeTerm)
  394.  
  395. table.insert(nativeDisplayTabs, {
  396. tab = {
  397. label = "Dashboard",
  398. event = "dashboard_clicked",
  399. active = true,
  400. startX = 0,
  401. startY = 0
  402. },
  403.  
  404. windows = dashboardWindows
  405. })
  406. table.insert(nativeDisplayTabs, {
  407. tab = {
  408. label = "Monitors",
  409. event = "monitors_clicked",
  410. startX = 0,
  411. startY = 0
  412. },
  413.  
  414. windows = { monitorSelectionWindow }
  415. })
  416. table.insert(nativeDisplayTabs, {
  417. tab = {
  418. label = "Console",
  419. event = "console_clicked",
  420. startX = 0,
  421. startY = 0
  422. },
  423.  
  424. windows = { consoleWindow }
  425. })
  426.  
  427. nativeDisplayTabs.getSelectedTab = function(x, y)
  428. if x == nil or y == nil then
  429. return nil
  430. end
  431.  
  432. for i, v in ipairs(nativeDisplayTabs) do
  433. local tab = v.tab
  434. local withinX = x >= tab.startX and x <= tab.endX
  435. local withinY = y >= tab.startY and y <= tab.endY
  436.  
  437. if withinX and withinY then
  438. return i
  439. end
  440. end
  441.  
  442. return nil
  443. end
  444.  
  445. nativeDisplayTabs.setSelectedTab = function(selected)
  446. for i, v in ipairs(nativeDisplayTabs) do
  447. if i == selected then
  448. v.tab.active = true
  449. else
  450. v.tab.active = false
  451. end
  452. end
  453. end
  454.  
  455. nativeDisplayTabs.getActiveTab = function()
  456. for i, v in ipairs(nativeDisplayTabs) do
  457. if v.tab.active == true then
  458. return i
  459. end
  460. end
  461. end
  462.  
  463. nativeDisplayTabs.getDashboardWindows = function()
  464. return dashboardWindows
  465. end
  466. end
  467.  
  468. -- window management
  469.  
  470.  
  471. --Name check
  472.  
  473. local function findPeripheral(_type)
  474. for _,name in pairs(peripheral.getNames()) do
  475. if peripheral.getType(name) == _type then
  476. return peripheral.wrap(name)
  477. end
  478. end
  479. end
  480.  
  481. --TODO
  482.  
  483. -- capacitor management
  484. local function addCapacitors(...)
  485. local peripheralList = arg
  486.  
  487.  
  488. if #peripheralList == 0 then
  489. peripheralList = peripheral.getNames()
  490. capacitors.clear()
  491. end
  492.  
  493. for i, p in ipairs(peripheralList) do
  494. local currentPeripheral = peripheral.wrap(p)
  495.  
  496.  
  497. if currentPeripheral[GET_ENERGY_STORED_FUNCTION_MFSU] ~= nil and currentPeripheral[GET_MAX_ENERGY_STORED_FUNCTION_MFSU] ~= nil then
  498. console.log("Adding new capacitor: "..p)
  499. capacitors.add({
  500. name = p,
  501. peripheral = currentPeripheral,
  502. lastReading = 0,
  503. flowRate = 0,
  504. percent = 0
  505. })
  506. end
  507.  
  508.  
  509. end
  510. end
  511.  
  512. local function removeCapacitors(...)
  513. for i, k in ipairs(arg) do
  514. capacitors.remove(k)
  515. end
  516. end
  517.  
  518. local function getReading()
  519. local totalEnergyAvailable, totalCapacity, totalFlowRate = 0, 0, 0
  520.  
  521. local currentReading = 0
  522. local capacity = 0
  523.  
  524. for i, v in ipairs(capacitors) do
  525.  
  526.  
  527. currentReading = v.peripheral[GET_ENERGY_STORED_FUNCTION_MFSU]() or 0
  528. capacity = v.peripheral[GET_MAX_ENERGY_STORED_FUNCTION_MFSU]() or 0
  529.  
  530. --error(currentReading)
  531. if currentReading ~= nil then
  532. v.flowRate = (currentReading - v.lastReading) / TICK_DELAY
  533. v.lastReading = currentReading
  534.  
  535. if capacity == 0 then
  536. v.percent = 0
  537. else
  538. v.percent = math.floor((currentReading / capacity) * 100)
  539. end
  540.  
  541. totalEnergyAvailable = totalEnergyAvailable + v.lastReading
  542. totalFlowRate = totalFlowRate + v.flowRate
  543. end
  544.  
  545. totalCapacity = totalCapacity + capacity
  546. end
  547.  
  548. local sortByLastReading = function(a, b)
  549. return a.percent > b.percent
  550. end
  551.  
  552. table.sort(capacitors, sortByLastReading)
  553.  
  554. return totalEnergyAvailable, totalCapacity, totalFlowRate
  555. end
  556.  
  557. local function emitRedstoneSignalOnLowPower(percent)
  558. if rs.getOutput(SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER) == false then
  559. rs.setAnalogOutput(SIDE_TO_EMIT_REDSTONE_ON_LOW_POWER, ((percent / 100)* 15))
  560. end
  561. end
  562. -- capacitor management
  563.  
  564.  
  565. -- monitor management
  566. local function addMonitors(...)
  567. local monitorList = arg
  568.  
  569. if #monitorList == 0 then
  570. monitorList = peripheral.getNames()
  571. monitors = {}
  572. end
  573.  
  574. for i, m in ipairs(monitorList) do
  575. local currentPeripheral = peripheral.wrap(m)
  576.  
  577. if "monitor" == peripheral.getType(m) and currentPeripheral.isColour() == true then
  578. console.log("Adding new monitor: "..m)
  579. currentPeripheral.setCursorPos(1, 1)
  580. monitors[m] = {
  581. peripheral = currentPeripheral,
  582. windows = createDashboardWindows(currentPeripheral),
  583. active = false
  584. }
  585. end
  586. end
  587. end
  588.  
  589. local function removeMonitors(...)
  590. local activeMonitorsCount = tableSize(MONITORS_ACTIVE)
  591.  
  592. for i, k in ipairs(arg) do
  593. monitors[k] = nil
  594. dashboardButtons[k] = nil
  595. MONITORS_ACTIVE[k] = nil
  596. end
  597.  
  598. if activeMonitorsCount ~= tableSize(MONITORS_ACTIVE) then
  599. saveSettings()
  600. end
  601. end
  602. -- monitor management
  603.  
  604.  
  605. -- hotplug system
  606. local function doWhileMonitorSuspended(callback)
  607. os.queueEvent("pause_monitor")
  608. callback()
  609. os.queueEvent("resume_monitor")
  610. end
  611.  
  612. local function hotplugPeripherals()
  613. while true do
  614. local event, name = os.pullEvent()
  615. local callback = nil
  616.  
  617. if event == "peripheral" then
  618. console.log("Detected new peripheral: "..name)
  619.  
  620. callback = function()
  621. addMonitors(name)
  622. addCapacitors(name)
  623. end
  624. elseif event == "peripheral_detach" then
  625. console.log("Peripheral removed: "..name)
  626.  
  627. callback = function()
  628. removeMonitors(name)
  629. removeCapacitors(name)
  630. end
  631. elseif event == "monitor_resize" then
  632. console.log("Monitor resized: "..name)
  633.  
  634. callback = function()
  635. monitors[name].peripheral.setCursorPos(1, 1)
  636. monitors[name].windows = createDashboardWindows(monitors[name].peripheral)
  637. dashboardButtons[name] = nil
  638.  
  639. if monitors[name].active == true then
  640. showWindows(unpack(monitors[name].windows))
  641. end
  642. end
  643. end
  644.  
  645. if callback ~= nil then
  646. doWhileMonitorSuspended(callback)
  647. end
  648. end
  649. end
  650. -- hotplug system
  651.  
  652.  
  653. -- information window for the capacitors
  654. local function addClickableLine(monitorName, key, currentY)
  655. clickableLines[monitorName][key] = {
  656. line = currentY
  657. }
  658. end
  659.  
  660. local function toggleInformationWindow(summaryWindow, informationWindow, capacitorName)
  661. if capacitorName == nil then
  662. summaryWindow.active = true
  663. informationWindow.active = false
  664. else
  665. summaryWindow.active = not summaryWindow.active
  666. informationWindow.active = not informationWindow.active
  667. end
  668.  
  669. local capacitor = capacitors.get(capacitorName)
  670.  
  671. if informationWindow.active == true then
  672. widthOffset = 3
  673. heightOffset = 3
  674.  
  675. informationWindow.setCursorPos(widthOffset, heightOffset)
  676. local width, height = informationWindow.getSize()
  677. local labelWidth = width - (widthOffset * 2)
  678. local capacity = 0
  679. --Capcacity
  680. if(findPeripheral("mfsu")) then
  681. capacity = capacitor.peripheral[GET_MAX_ENERGY_STORED_FUNCTION_MFSU]()
  682. else
  683. capacity = capacitor.peripheral[GET_MAX_ENERGY_STORED_FUNCTION]("north")
  684. end
  685. --Capacity
  686.  
  687.  
  688. printToWindow(informationWindow, widthOffset, "Capacitor name:")
  689. printToWindow(informationWindow, widthOffset, padRight(" "..capacitorName, labelWidth))
  690. printToWindow(informationWindow, widthOffset, "Capacitor type:")
  691. printToWindow(informationWindow, widthOffset, padRight(" "..peripheral.getType(capacitorName), labelWidth))
  692. printToWindow(informationWindow, widthOffset, "Capacity:")
  693. printToWindow(informationWindow, widthOffset, padRight(" "..capacity.." EU", labelWidth))
  694. printToWindow(informationWindow, widthOffset, "Available:")
  695. printToWindow(informationWindow, widthOffset, padRight(" "..capacitor.lastReading.." EU", labelWidth))
  696.  
  697. local closeLabel = " Click anywhere to close "
  698.  
  699. local x = math.floor(((width - string.len(closeLabel)) / 2 ) + 0.5)
  700.  
  701. informationWindow.setCursorPos(x, height-2)
  702.  
  703. informationWindow.setBackgroundColor(colors.red)
  704. informationWindow.write(closeLabel)
  705. informationWindow.setBackgroundColor(colors.black)
  706. end
  707.  
  708. showWindows(summaryWindow, informationWindow)
  709. end
  710.  
  711. local function checkForSelectableLine(monitorName, x, y)
  712. if clickableLines[monitorName] == nil then
  713. return nil
  714. end
  715.  
  716. for k,v in pairs(clickableLines[monitorName]) do
  717. if y == v.line then
  718. return k
  719. end
  720. end
  721.  
  722. return nil
  723. end
  724.  
  725. local function getSelectedDashboardButton(monitorName, x, y)
  726. if x == nil or y == nil then
  727. return nil
  728. end
  729.  
  730. local v = dashboardButtons[monitorName]
  731.  
  732. local nextButtonSelected = (x >= v.next.startX and x <= v.next.endX) and (y >= v.next.startY and y <= v.next.endY)
  733. local prevButtonSelected = (x >= v.prev.startX and x <= v.prev.endX) and (y >= v.prev.startY and y <= v.prev.endY)
  734.  
  735. if nextButtonSelected then
  736. return "next"
  737. elseif prevButtonSelected then
  738. return "prev"
  739. end
  740.  
  741. return nil
  742. end
  743.  
  744. -- information window for the capacitors
  745.  
  746.  
  747. -- main display
  748. local function renderPaginationButtons(monitorName, max)
  749. local width, height = term.getSize()
  750. local nextButton = " Next "
  751. local previousButton = " Prev "
  752. local spacer = " "
  753.  
  754. local dashboardButtonsToRender = previousButton..spacer..nextButton
  755. local buttonOffset = (width - (string.len(dashboardButtonsToRender))) / 2
  756.  
  757. term.setCursorPos(buttonOffset, height)
  758. local x, y = getCursorPositionRelativeToParent(term.current())
  759.  
  760. if dashboardButtons[monitorName] == nil then
  761. dashboardButtons[monitorName] = {
  762. prev = {
  763. startX = x,
  764. startY = y,
  765. endX = x,
  766. endY = y
  767. },
  768.  
  769. next = {
  770. startX = x,
  771. startY = y,
  772. endX = x,
  773. endY = y
  774. },
  775.  
  776. offset = 1,
  777. max = max
  778. }
  779. end
  780.  
  781. if dashboardButtons[monitorName].offset == 1 then
  782. dashboardButtons[monitorName].max = max
  783. end
  784.  
  785. term.setBackgroundColor(colors.red)
  786. term.write(previousButton)
  787. dashboardButtons[monitorName].prev.endX, dashboardButtons[monitorName].prev.endY = getCursorPositionRelativeToParent(term.current())
  788.  
  789. term.setBackgroundColor(colors.black)
  790. term.write(spacer)
  791.  
  792. dashboardButtons[monitorName].next.startX, dashboardButtons[monitorName].next.startY = getCursorPositionRelativeToParent(term.current())
  793. term.setBackgroundColor(colors.red)
  794. term.write(nextButton)
  795. dashboardButtons[monitorName].next.endX, dashboardButtons[monitorName].next.endY = getCursorPositionRelativeToParent(term.current())
  796.  
  797. term.setBackgroundColor(colors.black)
  798. end
  799.  
  800. local function writeSummary(monitorName, totalEnergyAvailable, totalCapacity, totalFlowRate)
  801. local width, height = term.getSize()
  802. local gridLabel = os.getComputerLabel() or "No name set"
  803. local gridLabelOffset = (width - (string.len(gridLabel))) / 2
  804.  
  805. term.setCursorPos(gridLabelOffset, 1)
  806. term.write(gridLabel)
  807. term.setCursorPos(1, 3)
  808.  
  809. print(padRight("Total Capacitors: "..tostring(#capacitors)))
  810. print(padRight("Max Energy Storage: "..totalCapacity.." EU"))
  811.  
  812. local totalPercentRemaining = math.floor((totalEnergyAvailable / totalCapacity) * 100)
  813. emitRedstoneSignalOnLowPower(totalPercentRemaining)
  814.  
  815. if totalEnergyAvailable > totalCapacity then
  816. printZoneText(totalPercentRemaining, function() print(padRight("Energy Available: "..totalCapacity.." EU")) end)
  817. else
  818. printZoneText(totalPercentRemaining, function() print(padRight("Energy Available: "..totalEnergyAvailable.." EU")) end)
  819. end
  820.  
  821.  
  822. if totalFlowRate < 0 then
  823. term.setTextColor(colors.red)
  824. elseif totalFlowRate > 0 then
  825. term.setTextColor(colors.green)
  826. else
  827. term.setTextColor(colors.white)
  828. end
  829.  
  830. print(padRight("Flow Rate: "..totalFlowRate.." EU/t"))
  831. term.setTextColor(colors.white)
  832.  
  833. local currentX, currentY = term.getCursorPos()
  834. term.setCursorPos(1, currentY+1)
  835.  
  836. clickableLines[monitorName] = {}
  837. local pagination = dashboardButtons[monitorName] or {}
  838. local offset = pagination.offset or 1
  839.  
  840. local count = 0
  841. for i = offset, #capacitors do
  842. local v = capacitors[i]
  843. local name = string.format(" %03d", i)..": "
  844. local percent = v.percent
  845.  
  846. printZoneText(percent, function() term.write(name) end)
  847.  
  848. local labelLength = string.len(name)
  849. local powerBarLength = width - labelLength - 1
  850. local powerBarReading = math.floor((width - labelLength - 1) * (percent/100))
  851.  
  852. local zoneColor = colors.red
  853. local textColor = colors.white
  854. if percent >= GREEN_ZONE then
  855. zoneColor = colors.green
  856. elseif percent >= YELLOW_ZONE and percent < GREEN_ZONE then
  857. zoneColor = colors.yellow
  858. textColor = colors.blue
  859. end
  860.  
  861. local stats = padRight(string.format(" %d", percent).."%, "..v.flowRate.." EU/t", powerBarLength)
  862.  
  863. term.setTextColor(textColor)
  864. term.setBackgroundColor(zoneColor)
  865. j = 1
  866. for c in stats:gmatch(".") do
  867. if(j>powerBarReading) then
  868. term.setBackgroundColor(colors.black)
  869. end
  870.  
  871. term.write(c)
  872.  
  873. j = j + 1
  874. end
  875. term.setTextColor(colors.white)
  876. term.setBackgroundColor(colors.black)
  877.  
  878. local currentX, currentY = getCursorPositionRelativeToParent(term.current())
  879. addClickableLine(monitorName, v.name, currentY)
  880.  
  881. local termX, termY = term.getCursorPos()
  882. term.setCursorPos(1, termY+2)
  883. count = count + 1
  884.  
  885. if termY > (height - 4) then
  886. max = count
  887. break
  888. end
  889. end
  890.  
  891. local currentX, currentY = term.getCursorPos()
  892. for k = currentY, height-1 do
  893. term.setCursorPos(1, k)
  894. term.clearLine()
  895. end
  896.  
  897. renderPaginationButtons(monitorName, count)
  898. end
  899.  
  900. local function displaySummary(totalEnergyAvailable, totalCapacity, totalFlowRate, targetMonitor)
  901. local listOfSummaryWindows = {
  902. native = nativeDisplayTabs.getDashboardWindows().getSummaryWindow()
  903. }
  904.  
  905. for k, v in pairs(monitors) do
  906. listOfSummaryWindows[k] = v.windows.getSummaryWindow()
  907. end
  908.  
  909. for k, v in pairs(listOfSummaryWindows) do
  910. if targetMonitor == nil or (k == targetMonitor) then
  911. local currentTerm = term.current()
  912.  
  913. term.redirect(v)
  914.  
  915. writeSummary(k, totalEnergyAvailable, totalCapacity, totalFlowRate)
  916.  
  917. term.redirect(currentTerm)
  918.  
  919. if k == targetMonitor then
  920. return
  921. end
  922. end
  923. end
  924. end
  925.  
  926. local function monitorCapacitors()
  927. totalEnergyAvailable, totalCapacity, totalFlowRate = 0, 0, 0
  928.  
  929. while true do
  930. -- show reading
  931. displaySummary(totalEnergyAvailable, totalCapacity, totalFlowRate)
  932.  
  933. -- need to call this first to get most current sample
  934. getReading()
  935.  
  936. local samplingTimer = os.startTimer(PAUSE_TIME_IN_SECONDS)
  937. while true do
  938. local event, p1 = os.pullEvent()
  939. if event == "timer" and p1 == samplingTimer then
  940. totalEnergyAvailable, totalCapacity, totalFlowRate = getReading()
  941. break
  942. elseif event == "pause_monitor" then
  943. os.pullEvent("resume_monitor")
  944. break
  945. end
  946. end
  947. end
  948. end
  949.  
  950. local function changePages(monitor, x, y, isInformationWindowActive)
  951. local selectedButton = getSelectedDashboardButton(monitor, x, y)
  952. local showSummary = false
  953.  
  954. if selectedButton == "next" and not isInformationWindowActive then
  955. local newOffset = dashboardButtons[monitor].offset + (dashboardButtons[monitor].max or 0)
  956. if newOffset <= #capacitors then
  957. dashboardButtons[monitor].offset = newOffset
  958.  
  959. showSummary = true
  960. end
  961. elseif selectedButton == "prev" and not isInformationWindowActive then
  962. local newOffset = dashboardButtons[monitor].offset - (dashboardButtons[monitor].max or 0)
  963. if newOffset > 0 then
  964. dashboardButtons[monitor].offset = newOffset
  965. else
  966. dashboardButtons[monitor].offset = 1
  967. end
  968.  
  969. showSummary = true
  970. end
  971.  
  972. if showSummary then
  973. displaySummary(totalEnergyAvailable, totalCapacity, totalFlowRate, p1)
  974. return true
  975. end
  976.  
  977. return false
  978. end
  979.  
  980. local function nativeDashboardHandler()
  981. while true do
  982. local event, x, y = os.pullEvent("dashboard_clicked")
  983. local isInformationWindowActive = nativeDisplayTabs.getDashboardWindows().getInformationWindow().active
  984.  
  985. if not changePages("native", x, y, isInformationWindowActive) then
  986. local selectedCapacitor = checkForSelectableLine("native", x, y)
  987.  
  988. local summaryWindow = nativeDisplayTabs.getDashboardWindows().getSummaryWindow()
  989. local informationWindow = nativeDisplayTabs.getDashboardWindows().getInformationWindow()
  990.  
  991. toggleInformationWindow(summaryWindow, informationWindow, selectedCapacitor)
  992. end
  993. end
  994. end
  995.  
  996. local function monitorDashboardHandler()
  997. while true do
  998. local event, monitor, x, y = os.pullEvent("monitor_touch")
  999.  
  1000. if monitors[monitor].active == true then
  1001. local summaryWindow = monitors[monitor].windows.getSummaryWindow()
  1002. local informationWindow = monitors[monitor].windows.getInformationWindow()
  1003.  
  1004. if not changePages(monitor, x, y, informationWindow.active) then
  1005. local selectedCapacitor = checkForSelectableLine(monitor, x, y)
  1006. toggleInformationWindow(summaryWindow, informationWindow, selectedCapacitor)
  1007. end
  1008. end
  1009. end
  1010. end
  1011. -- main display
  1012.  
  1013.  
  1014. -- monitor selection screen (if monitor is attached)
  1015. local function addClickableOutputMonitor(k, currentY)
  1016. clickableOutputMonitors[k] = {
  1017. line = currentY
  1018. }
  1019. end
  1020.  
  1021. local function toggleMonitor(monitorName)
  1022. monitors[monitorName].active = not monitors[monitorName].active
  1023.  
  1024. if monitors[monitorName].active then
  1025. console.log("Enabling "..monitorName)
  1026. MONITORS_ACTIVE[monitorName] = true
  1027. else
  1028. console.log("Disabling "..monitorName)
  1029. MONITORS_ACTIVE[monitorName] = nil
  1030.  
  1031. hideWindows(unpack(monitors[monitorName].windows))
  1032. monitors[monitorName].peripheral.setBackgroundColor(colors.black)
  1033. monitors[monitorName].peripheral.clear()
  1034. end
  1035.  
  1036. saveSettings()
  1037. end
  1038.  
  1039. local function showMonitorSelection(targetWindow)
  1040. local currentTerm = term.current()
  1041.  
  1042. term.redirect(targetWindow)
  1043. term.setCursorPos(1, 1)
  1044. term.clear()
  1045.  
  1046. local width, height = term.getSize()
  1047.  
  1048. if tableSize(monitors) > 0 then
  1049. printToWindow(term, 0, "Select Output Monitor: ")
  1050. else
  1051. printToWindow(term, 0, "No Monitors found.")
  1052. end
  1053.  
  1054. printToWindow(term, 0, "")
  1055.  
  1056. local currentX, currentY = term.getCursorPos()
  1057. term.setCursorPos(currentX + 2, currentY)
  1058.  
  1059. clickableOutputMonitors = {}
  1060. for k, v in pairs(monitors) do
  1061. currentX, currentY = getCursorPositionRelativeToParent(targetWindow)
  1062. term.setBackgroundColor(colors.black)
  1063.  
  1064. if v.active == true then
  1065. term.setBackgroundColor(colors.blue)
  1066. showWindows(unpack(v.windows))
  1067. end
  1068.  
  1069. label = padRight(" "..k, width-4)
  1070. printToWindow(term, 0, label)
  1071.  
  1072. addClickableOutputMonitor(k, currentY)
  1073. end
  1074. term.setBackgroundColor(colors.black)
  1075.  
  1076. term.redirect(currentTerm)
  1077.  
  1078. while true do
  1079. local event, x, y = os.pullEvent()
  1080.  
  1081. if "monitors_clicked" == event then
  1082. for k, v in pairs(clickableOutputMonitors) do
  1083. if v.line == y then
  1084. toggleMonitor(k)
  1085. return
  1086. end
  1087. end
  1088. elseif event == "peripheral" or event == "peripheral_detach" then
  1089. coroutine.yield()
  1090. return
  1091. end
  1092. end
  1093. end
  1094.  
  1095. local function monitorSelection()
  1096. for k, v in pairs(MONITORS_ACTIVE) do
  1097. if monitors[k] then
  1098. monitors[k].active = true
  1099. end
  1100. end
  1101.  
  1102. while true do
  1103. showMonitorSelection(monitorSelectionWindow)
  1104. end
  1105. end
  1106.  
  1107. local function nativeDisplay()
  1108. while true do
  1109. local currentTerm = term.current()
  1110.  
  1111. term.redirect(nativeMonitorTabWindow)
  1112. nativeMonitorTabWindow.setVisible(true)
  1113.  
  1114. term.setCursorPos(1, 1)
  1115. term.setBackgroundColor(colors.gray)
  1116. term.clearLine()
  1117. term.setTextColor(colors.yellow)
  1118.  
  1119. for i, v in ipairs(nativeDisplayTabs) do
  1120. hideWindows(unpack(v.windows))
  1121. end
  1122.  
  1123. for i, v in ipairs(nativeDisplayTabs) do
  1124. local tab = v.tab
  1125. tab.startX, tab.startY = getCursorPositionRelativeToParent(term.current())
  1126.  
  1127. if tab.active then
  1128. term.setBackgroundColor(colors.black)
  1129. showWindows(unpack(v.windows))
  1130. else
  1131. term.setBackgroundColor(colors.gray)
  1132. end
  1133.  
  1134. term.write(" "..tab.label.." ")
  1135. tab.endX, tab.endY = getCursorPositionRelativeToParent(term.current())
  1136. end
  1137. term.setTextColor(colors.white)
  1138. term.redirect(currentTerm)
  1139.  
  1140. while true do
  1141. local event, selectedTab = os.pullEvent("selected_tab")
  1142.  
  1143. if selectedTab then
  1144. nativeDisplayTabs.setSelectedTab(selectedTab)
  1145. break
  1146. end
  1147. end
  1148. end
  1149. end
  1150.  
  1151. local function mouseClickEventMonitor()
  1152. while true do
  1153. local event, type, x, y = os.pullEvent("mouse_click")
  1154. local selectedTab = nativeDisplayTabs.getSelectedTab(x, y)
  1155.  
  1156. if selectedTab and nativeDisplayTabs.getDashboardWindows().getInformationWindow().active == false then
  1157. os.queueEvent("selected_tab", selectedTab)
  1158. elseif selectedTab == nil then
  1159. local activeTab = nativeDisplayTabs[nativeDisplayTabs.getActiveTab()]
  1160.  
  1161. os.queueEvent(activeTab.tab.event, x, y)
  1162. end
  1163. end
  1164. end
  1165.  
  1166. -- Initialization
  1167. initializeNativeDisplayTabs()
  1168. resetRedstoneState()
  1169. addCapacitors()
  1170. addMonitors()
  1171.  
  1172. while true do
  1173. parallel.waitForAll(mouseClickEventMonitor, nativeDisplay, monitorSelection, hotplugPeripherals, monitorCapacitors, nativeDashboardHandler, monitorDashboardHandler)
  1174. end
Add Comment
Please, Sign In to add comment