Savage_Me55iah

powermonitor savage

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