#200 work in progress unit views and sidebar/app updates

This commit is contained in:
Mikayla Fischler 2024-05-09 23:05:55 -04:00
parent 3bfcb1d83c
commit 0c6c7bf9a5
7 changed files with 435 additions and 54 deletions

View File

@ -30,7 +30,7 @@ local function app_button(args)
element.assert(type(args.app_fg_bg) == "table", "app_fg_bg is a required field")
args.height = 4
args.width = 5
args.width = 7
-- create new graphics element base object
local e = element.new(args)
@ -46,7 +46,7 @@ local function app_button(args)
end
-- draw icon
e.w_set_cur(1, 1)
e.w_set_cur(2, 1)
e.w_set_fgd(fgd)
e.w_set_bkg(bkg)
e.w_write("\x9f\x83\x83\x83")
@ -55,16 +55,16 @@ local function app_button(args)
e.w_write("\x90")
e.w_set_fgd(fgd)
e.w_set_bkg(bkg)
e.w_set_cur(1, 2)
e.w_set_cur(2, 2)
e.w_write("\x95 ")
e.w_set_fgd(bkg)
e.w_set_bkg(fgd)
e.w_write("\x95")
e.w_set_cur(1, 3)
e.w_set_cur(2, 3)
e.w_write("\x82\x8f\x8f\x8f\x81")
-- write the icon text
e.w_set_cur(3, 2)
e.w_set_cur(4, 2)
e.w_set_fgd(fgd)
e.w_set_bkg(bkg)
e.w_write(args.text)

View File

@ -8,13 +8,7 @@ local element = require("graphics.element")
local MOUSE_CLICK = core.events.MOUSE_CLICK
---@class sidebar_tab
---@field char string character identifier
---@field color cpair tab colors (fg/bg)
---@class sidebar_args
---@field tabs table sidebar tab options
---@field callback function function to call on tab change
---@field parent graphics_element
---@field id? string element id
---@field x? integer 1 if omitted
@ -27,21 +21,16 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK
---@param args sidebar_args
---@return graphics_element element, element_id id
local function sidebar(args)
element.assert(type(args.tabs) == "table", "tabs is a required field")
element.assert(#args.tabs > 0, "at least one tab is required")
element.assert(type(args.callback) == "function", "callback is a required field")
args.width = 3
-- create new graphics element base object
local e = element.new(args)
element.assert(e.frame.h >= (#args.tabs * 3), "height insufficent to display all tabs")
-- default to 1st tab
e.value = 1
local was_pressed = false
local tabs = {}
-- show the button state
---@param pressed? boolean if the currently selected tab should appear as actively pressed
@ -51,10 +40,18 @@ local function sidebar(args)
was_pressed = pressed
pressed_idx = pressed_idx or e.value
for i = 1, #args.tabs do
local tab = args.tabs[i] ---@type sidebar_tab
-- clear
e.w_set_fgd(e.fg_bg.fgd)
e.w_set_bkg(e.fg_bg.bkg)
for y = 1, e.frame.h do
e.w_set_cur(1, y)
e.w_write(" ")
end
local y = ((i - 1) * 3) + 1
-- draw tabs
for i = 1, #tabs do
local tab = tabs[i] ---@type sidebar_tab
local y = tab.y_start
e.w_set_cur(1, y)
@ -66,13 +63,29 @@ local function sidebar(args)
e.w_set_bkg(tab.color.bkg)
end
e.w_write(" ")
e.w_set_cur(1, y + 1)
if e.value == i then
e.w_write(" " .. tab.char .. "\x10")
else e.w_write(" " .. tab.char .. " ") end
e.w_set_cur(1, y + 2)
e.w_write(" ")
if tab.tall then
e.w_write(" ")
e.w_set_cur(1, y + 1)
end
e.w_write(tab.label)
if tab.tall then
e.w_set_cur(1, y + 2)
e.w_write(" ")
end
end
end
-- determine which tab was pressed
---@param y integer y coordinate
local function find_tab(y)
for i = 1, #tabs do
local tab = tabs[i] ---@type sidebar_tab
if y >= tab.y_start and y <= tab.y_end then
return i
end
end
end
@ -81,23 +94,23 @@ local function sidebar(args)
function e.handle_mouse(event)
-- determine what was pressed
if e.enabled then
local cur_idx = math.ceil(event.current.y / 3)
local ini_idx = math.ceil(event.initial.y / 3)
local cur_idx = find_tab(event.current.y)
local ini_idx = find_tab(event.initial.y)
if args.tabs[cur_idx] ~= nil then
if tabs[cur_idx] ~= nil then
if event.type == MOUSE_CLICK.TAP then
e.value = cur_idx
draw(true)
-- show as unpressed in 0.25 seconds
tcd.dispatch(0.25, function () draw(false) end)
args.callback(e.value)
tabs[cur_idx].callback()
elseif event.type == MOUSE_CLICK.DOWN then
draw(true, cur_idx)
elseif event.type == MOUSE_CLICK.UP then
if cur_idx == ini_idx and e.in_frame_bounds(event.current.x, event.current.y) then
e.value = cur_idx
draw(false)
args.callback(e.value)
tabs[cur_idx].callback()
else draw(false) end
end
elseif event.type == MOUSE_CLICK.UP then
@ -113,6 +126,35 @@ local function sidebar(args)
draw(false)
end
-- update the sidebar nav options
---@param items table sidebar entries
function e.on_update(items)
local next_y = 1
tabs = {}
for i = 1, #items do
local item = items[i]
local height = util.trinary(item.tall, 3, 1)
---@class sidebar_tab
local entry = {
y_start = next_y,
y_end = next_y + height - 1,
tall = item.tall,
label = item.label,
color = item.color,
callback = item.callback
}
next_y = next_y + height
tabs[i] = entry
end
draw()
end
-- element redraw
e.redraw = draw

View File

@ -5,8 +5,10 @@
local log = require("scada-common.log")
local psil = require("scada-common.psil")
local types = require("scada-common.types")
local util = require("scada-common.util")
local ALARM = types.ALARM
local ALARM_STATE = types.ALARM_STATE
---@todo nominal trip time is ping (0ms to 10ms usually)
local WARN_TT = 40
@ -72,6 +74,10 @@ function iocontrol.alloc_nav()
self.pane = root_pane
end
function io.nav.set_sidebar(sidebar)
self.sidebar = sidebar
end
-- register an app
---@param app_id POCKET_APP_ID app ID
---@param container graphics_element element that contains this app (usually a Div)
@ -79,18 +85,37 @@ function iocontrol.alloc_nav()
function io.nav.register_app(app_id, container, pane)
---@class pocket_app
local app = {
loaded = false,
load = nil,
root = { _p = nil, _c = {}, nav_to = function () end, tasks = {} }, ---@type nav_tree_page
cur_page = nil, ---@type nav_tree_page
pane = pane,
paned_pages = {}
paned_pages = {},
sidebar_items = {}
}
app.load = function () app.loaded = true end
-- delayed set of the pane if it wasn't ready at the start
---@param root_pane graphics_element multipane
function app.set_root_pane(root_pane)
app.pane = root_pane
end
function app.set_sidebar(items)
app.sidebar_items = items
if self.sidebar then self.sidebar.update(items) end
end
-- function to run on initial load into memory
---@param on_load function callback
function app.set_on_load(on_load)
app.load = function ()
on_load()
app.loaded = true
end
end
-- if a pane was provided, this will switch between numbered pages
---@param idx integer page index
function app.switcher(idx)
@ -160,9 +185,16 @@ function iocontrol.alloc_nav()
-- open a given app
---@param app_id POCKET_APP_ID
function io.nav.open_app(app_id)
if self.apps[app_id] then
local app = self.apps[app_id] ---@type pocket_app
if app then
if not app.loaded then app.load() end
self.cur_app = app_id
self.pane.set_value(app_id)
if #app.sidebar_items > 0 then
self.sidebar.update(app.sidebar_items)
end
else
log.debug("tried to open unknown app")
end
@ -262,6 +294,16 @@ function iocontrol.init_fac(conf, temp_scale)
auto_ramping = false,
auto_saturated = false,
auto_scram = false,
---@type ascram_status
ascram_status = {
matrix_dc = false,
matrix_fill = false,
crit_alarm = false,
radiation = false,
gen_fault = false
},
---@type WASTE_PRODUCT
auto_current_waste_product = types.WASTE_PRODUCT.PLUTONIUM,
auto_pu_fallback_active = false,
@ -282,6 +324,179 @@ function iocontrol.init_fac(conf, temp_scale)
env_d_ps = psil.create(),
env_d_data = {}
}
-- create induction and SPS tables (currently only 1 of each is supported)
table.insert(io.facility.induction_ps_tbl, psil.create())
table.insert(io.facility.induction_data_tbl, {})
table.insert(io.facility.sps_ps_tbl, psil.create())
table.insert(io.facility.sps_data_tbl, {})
-- determine tank information
if io.facility.tank_mode == 0 then
io.facility.tank_defs = {}
-- on facility tank mode 0, setup tank defs to match unit tank option
for i = 1, conf.num_units do
io.facility.tank_defs[i] = util.trinary(conf.cooling.r_cool[i].TankConnection, 1, 0)
end
io.facility.tank_list = { table.unpack(io.facility.tank_defs) }
else
-- decode the layout of tanks from the connections definitions
local tank_mode = io.facility.tank_mode
local tank_defs = io.facility.tank_defs
local tank_list = { table.unpack(tank_defs) }
local function calc_fdef(start_idx, end_idx)
local first = 4
for i = start_idx, end_idx do
if io.facility.tank_defs[i] == 2 then
if i < first then first = i end
end
end
return first
end
if tank_mode == 1 then
-- (1) 1 total facility tank (A A A A)
local first_fdef = calc_fdef(1, #tank_defs)
for i = 1, #tank_defs do
if i > first_fdef and tank_defs[i] == 2 then
tank_list[i] = 0
end
end
elseif tank_mode == 2 then
-- (2) 2 total facility tanks (A A A B)
local first_fdef = calc_fdef(1, math.min(3, #tank_defs))
for i = 1, #tank_defs do
if (i ~= 4) and (i > first_fdef) and (tank_defs[i] == 2) then
tank_list[i] = 0
end
end
elseif tank_mode == 3 then
-- (3) 2 total facility tanks (A A B B)
for _, a in pairs({ 1, 3 }) do
local b = a + 1
if (tank_defs[a] == 2) and (tank_defs[b] == 2) then
tank_list[b] = 0
end
end
elseif tank_mode == 4 then
-- (4) 2 total facility tanks (A B B B)
local first_fdef = calc_fdef(2, #tank_defs)
for i = 1, #tank_defs do
if (i ~= 1) and (i > first_fdef) and (tank_defs[i] == 2) then
tank_list[i] = 0
end
end
elseif tank_mode == 5 then
-- (5) 3 total facility tanks (A A B C)
local first_fdef = calc_fdef(1, math.min(2, #tank_defs))
for i = 1, #tank_defs do
if (not (i == 3 or i == 4)) and (i > first_fdef) and (tank_defs[i] == 2) then
tank_list[i] = 0
end
end
elseif tank_mode == 6 then
-- (6) 3 total facility tanks (A B B C)
local first_fdef = calc_fdef(2, math.min(3, #tank_defs))
for i = 1, #tank_defs do
if (not (i == 1 or i == 4)) and (i > first_fdef) and (tank_defs[i] == 2) then
tank_list[i] = 0
end
end
elseif tank_mode == 7 then
-- (7) 3 total facility tanks (A B C C)
local first_fdef = calc_fdef(3, #tank_defs)
for i = 1, #tank_defs do
if (not (i == 1 or i == 2)) and (i > first_fdef) and (tank_defs[i] == 2) then
tank_list[i] = 0
end
end
end
io.facility.tank_list = tank_list
end
-- create facility tank tables
for i = 1, #io.facility.tank_list do
if io.facility.tank_list[i] == 2 then
table.insert(io.facility.tank_ps_tbl, psil.create())
table.insert(io.facility.tank_data_tbl, {})
end
end
-- create unit data structures
io.units = {}
for i = 1, conf.num_units do
---@class pioctl_unit
local entry = {
unit_id = i,
num_boilers = 0,
num_turbines = 0,
num_snas = 0,
has_tank = conf.cooling.r_cool[i].TankConnection,
control_state = false,
burn_rate_cmd = 0.0,
radiation = types.new_zero_radiation_reading(),
sna_peak_rate = 0.0,
sna_max_rate = 0.0,
sna_out_rate = 0.0,
waste_mode = types.WASTE_MODE.MANUAL_PLUTONIUM,
waste_product = types.WASTE_PRODUCT.PLUTONIUM,
-- auto control group
a_group = 0,
---@type alarms
alarms = { ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE, ALARM_STATE.INACTIVE },
annunciator = {}, ---@type annunciator
unit_ps = psil.create(),
reactor_data = {}, ---@type reactor_db
boiler_ps_tbl = {},
boiler_data_tbl = {},
turbine_ps_tbl = {},
turbine_data_tbl = {},
tank_ps_tbl = {},
tank_data_tbl = {}
}
-- on other facility modes, overwrite unit TANK option with facility tank defs
if io.facility.tank_mode ~= 0 then
entry.has_tank = conf.cooling.fac_tank_defs[i] > 0
end
-- create boiler tables
for _ = 1, conf.cooling.r_cool[i].BoilerCount do
table.insert(entry.boiler_ps_tbl, psil.create())
table.insert(entry.boiler_data_tbl, {})
end
-- create turbine tables
for _ = 1, conf.cooling.r_cool[i].TurbineCount do
table.insert(entry.turbine_ps_tbl, psil.create())
table.insert(entry.turbine_data_tbl, {})
end
-- create tank tables
if io.facility.tank_defs[i] == 1 then
table.insert(entry.tank_ps_tbl, psil.create())
table.insert(entry.tank_data_tbl, {})
end
entry.num_boilers = #entry.boiler_data_tbl
entry.num_turbines = #entry.turbine_data_tbl
table.insert(io.units, entry)
end
end
-- set network link state

View File

@ -19,6 +19,8 @@ local function create_pages(root)
db.nav.register_app(iocontrol.APP_ID.DUMMY, main).new_page(nil, function () end)
TextBox{parent=main,text="This app is not implemented yet.",x=1,y=2,alignment=core.ALIGN.CENTER}
TextBox{parent=main,text=" pretend something cool is here \x03",x=1,y=10,alignment=core.ALIGN.CENTER,fg_bg=core.cpair(colors.gray,colors.black)}
end
return create_pages

View File

@ -71,10 +71,6 @@ local function init(main)
local page_div = Div{parent=main_pane,x=4,y=1}
local sidebar_tabs = {
{ char = "#", color = cpair(colors.black, colors.green) }
}
home_page(page_div)
unit_page(page_div)
@ -84,13 +80,13 @@ local function init(main)
assert(#db.nav.get_containers() == iocontrol.APP_ID.NUM_APPS, "app IDs were not sequential or some apps weren't registered")
local page_pane = MultiPane{parent=page_div,x=1,y=1,panes=db.nav.get_containers()}
db.nav.set_pane(page_pane)
Sidebar{parent=main_pane,x=1,y=1,tabs=sidebar_tabs,fg_bg=cpair(colors.white,colors.gray),callback=db.nav.open_app}
db.nav.set_pane(MultiPane{parent=page_div,x=1,y=1,panes=db.nav.get_containers()})
db.nav.set_sidebar(Sidebar{parent=main_pane,x=1,y=1,height=18,fg_bg=cpair(colors.white,colors.gray)})
PushButton{parent=main_pane,x=1,y=19,text="\x1b",min_width=3,fg_bg=cpair(colors.white,colors.gray),active_fg_bg=cpair(colors.gray,colors.black),callback=db.nav.nav_up}
db.nav.open_app(iocontrol.APP_ID.ROOT)
--#endregion
end

View File

@ -39,21 +39,26 @@ local function new_view(root)
local function open(id) db.nav.open_app(id) end
app.set_sidebar({
{ label = " #\x10", tall = true, color = core.cpair(colors.black, colors.green), callback = function () open(APP_ID.ROOT) end }
})
local active_fg_bg = cpair(colors.white,colors.gray)
App{parent=apps_1,x=3,y=2,text="U",title="Units",callback=function()open(APP_ID.UNITS)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=10,y=2,text="\x17",title="PRC",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.purple),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=17,y=2,text="\x15",title="CTL",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.green),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=3,y=7,text="\x08",title="DEV",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.lightGray),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=10,y=7,text="\x7f",title="Waste",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.brown),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=17,y=7,text="\xb6",title="Guide",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=3,y=12,text="?",title="About",callback=function()open(APP_ID.ABOUT)end,app_fg_bg=cpair(colors.black,colors.white),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=2,y=2,text="U",title="Units",callback=function()open(APP_ID.UNITS)end,app_fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=9,y=2,text="F",title="Facil",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=16,y=2,text="\x15",title="Control",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.green),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=2,y=7,text="\x17",title="Process",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.purple),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=9,y=7,text="\x7f",title="Waste",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.brown),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=16,y=7,text="\x08",title="Devices",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.lightGray),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=2,y=12,text="\xb6",title="Guide",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg}
App{parent=apps_1,x=9,y=12,text="?",title="About",callback=function()open(APP_ID.ABOUT)end,app_fg_bg=cpair(colors.black,colors.white),active_fg_bg=active_fg_bg}
TextBox{parent=apps_2,text="Diagnostic Apps",x=1,y=2,height=1,alignment=ALIGN.CENTER}
App{parent=apps_2,x=3,y=4,text="\x0f",title="Alarm",callback=function()open(APP_ID.ALARMS)end,app_fg_bg=cpair(colors.black,colors.red),active_fg_bg=active_fg_bg}
App{parent=apps_2,x=10,y=4,text="\x1e",title="LoopT",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg}
App{parent=apps_2,x=17,y=4,text="@",title="Comps",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg}
App{parent=apps_2,x=2,y=4,text="\x0f",title="Alarm",callback=function()open(APP_ID.ALARMS)end,app_fg_bg=cpair(colors.black,colors.red),active_fg_bg=active_fg_bg}
App{parent=apps_2,x=9,y=4,text="\x1e",title="LoopT",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.cyan),active_fg_bg=active_fg_bg}
App{parent=apps_2,x=16,y=4,text="@",title="Comps",callback=function()open(APP_ID.DUMMY)end,app_fg_bg=cpair(colors.black,colors.orange),active_fg_bg=active_fg_bg}
return main
end

View File

@ -3,13 +3,31 @@
--
local iocontrol = require("pocket.iocontrol")
local util = require("scada-common.util")
local core = require("graphics.core")
local Div = require("graphics.elements.div")
local MultiPane = require("graphics.elements.multipane")
local TextBox = require("graphics.elements.textbox")
local AlarmLight = require("graphics.elements.indicators.alight")
local CoreMap = require("graphics.elements.indicators.coremap")
local DataIndicator = require("graphics.elements.indicators.data")
local IconIndicator = require("graphics.elements.indicators.icon")
local IndicatorLight = require("graphics.elements.indicators.light")
local RadIndicator = require("graphics.elements.indicators.rad")
local TriIndicatorLight = require("graphics.elements.indicators.trilight")
local VerticalBar = require("graphics.elements.indicators.vbar")
local HazardButton = require("graphics.elements.controls.hazard_button")
local MultiButton = require("graphics.elements.controls.multi_button")
local PushButton = require("graphics.elements.controls.push_button")
local RadioButton = require("graphics.elements.controls.radio_button")
local SpinboxNumeric = require("graphics.elements.controls.spinbox_numeric")
local ALIGN = core.ALIGN
local cpair = core.cpair
-- new unit page view
---@param root graphics_element parent
@ -21,9 +39,112 @@ local function new_view(root)
local app = db.nav.register_app(iocontrol.APP_ID.UNITS, main)
app.new_page(nil, function () end)
TextBox{parent=main,y=2,text="UNITS",height=1,alignment=ALIGN.CENTER}
TextBox{parent=main,y=2,text="Units App",height=1,alignment=ALIGN.CENTER}
TextBox{parent=main,y=4,text="work in progress",height=1,alignment=ALIGN.CENTER}
TextBox{parent=main,y=4,text="Loading...",height=1,alignment=ALIGN.CENTER}
local page_div = Div{parent=main,x=2,y=2,width=main.get_width()-2}
local btn_fg_bg = cpair(colors.yellow, colors.black)
local btn_active = cpair(colors.white, colors.black)
local label = cpair(colors.lightGray, colors.black)
local function set_sidebar(unit)
app.set_sidebar({
{ label = " # ", tall = true, color = core.cpair(colors.black, colors.green), callback = function () db.nav.open_app(iocontrol.APP_ID.ROOT) end },
{ label = "U#" .. unit, color = core.cpair(colors.black, colors.yellow), callback = function () end },
{ label = "RPS", color = core.cpair(colors.black, colors.red), callback = function () end },
{ label = "RCS", color = core.cpair(colors.black, colors.blue), callback = function () end },
{ label = " R ", tall = true, color = core.cpair(colors.black, colors.orange), callback = function () end },
})
end
local function load()
local u_pages = {}
local active_unit = 1
set_sidebar(active_unit)
for _ = 1, db.facility.num_units do
local div = Div{parent=page_div}
table.insert(u_pages, div)
end
local u_pane = MultiPane{parent=page_div,x=1,y=1,panes=u_pages}
local function prev(x)
active_unit = util.trinary(x == 1, db.facility.num_units, x - 1)
u_pane.set_value(active_unit)
set_sidebar(active_unit)
end
local function next(x)
active_unit = util.trinary(x == db.facility.num_units, 1, x + 1)
u_pane.set_value(active_unit)
set_sidebar(active_unit)
end
for i = 1, db.facility.num_units do
local u_div = u_pages[i] ---@type graphics_element
local unit = db.units[i] ---@type pioctl_unit
TextBox{parent=u_div,y=1,text="Reactor Unit #"..i,height=1,alignment=ALIGN.CENTER}
PushButton{parent=u_div,x=1,y=1,text="<",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()prev(i)end}
PushButton{parent=u_div,x=21,y=1,text=">",fg_bg=btn_fg_bg,active_fg_bg=btn_active,callback=function()next(i)end}
local type = util.trinary(unit.num_boilers > 0, "Sodium Cooled Reactor", "Boiling Water Reactor")
TextBox{parent=u_div,y=3,text=type,height=1,alignment=ALIGN.CENTER,fg_bg=cpair(colors.gray,colors.black)}
local lu_col = cpair(colors.lightGray, colors.lightGray)
local text_fg = cpair(colors.white, colors._INHERIT)
local rate = DataIndicator{parent=u_div,y=5,lu_colors=lu_col,label="Rate",unit="mB/t",format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg}
local temp = DataIndicator{parent=u_div,lu_colors=lu_col,label="Temp",unit="K",format="%10.2f",value=0,commas=true,width=26,fg_bg=text_fg}
local basic_states = {
{ color = cpair(colors.black,colors.lightGray), symbol = "\x07" },
{ color = cpair(colors.black,colors.red), symbol = "-" },
{ color = cpair(colors.black,colors.yellow), symbol = "\x1e" },
{ color = cpair(colors.black,colors.green), symbol = "+" }
}
local mode_states = {
{ color = cpair(colors.black,colors.lightGray), symbol = "\x07" },
{ color = cpair(colors.black,colors.red), symbol = "-" },
{ color = cpair(colors.black,colors.green), symbol = "+" },
{ color = cpair(colors.black,colors.purple), symbol = "A" }
}
local ctrl = IconIndicator{parent=u_div,x=1,y=8,label="Control State",states=mode_states}
ctrl.update(i+1)
u_div.line_break()
local rct = IconIndicator{parent=u_div,x=1,label="Fission Reactor",states=basic_states}
local rps = IconIndicator{parent=u_div,x=1,label="Protection System",states=basic_states}
u_div.line_break()
local rcs = IconIndicator{parent=u_div,x=1,label="Coolant System",states=basic_states}
for b = 1, unit.num_boilers do
local blr = IconIndicator{parent=u_div,x=1,label="Boiler "..b,states=basic_states}
blr.update(b+2)
end
for t = 1, unit.num_turbines do
local trb = IconIndicator{parent=u_div,x=1,label="Turbine "..t,states=basic_states}
trb.update(t)
end
rct.update(4)
rps.update(3)
rcs.update(3)
end
end
app.set_on_load(load)
return main
end