bans-automata/automata/reactor/windows/status.lua

288 lines
7.3 KiB
Lua

local Assert = require("lib.assert")
local Box = require("lib.widget.container.box")
local Class = require("lib.class")
local Label = require("lib.widget.display.label")
local Separator = require("lib.widget.display.separator")
local StatusBar = require("lib.widget.display.statusbar")
local Window = require("lib.widget.display.window")
local Widget = require("lib.widget")
local StatusWindow = Class("StatusWindow", Window)
function StatusWindow:init(model)
Window.init(self)
self.model = model
local status = StatusBar:new()
self.statusLeft = status:addLabelStart("Reactor Status")
self.statusRight = status:addLabelEnd()
self.updaters = {}
local reactorGroup = self:createStatusGroup("Reactor Status", {
{
field = "burnRate",
name = "Fuel Burn Rate",
unit = "mB/T",
format = "%.2f",
color = function(value)
local v = value.current:get()
if v < value.max / 2 then
return colors.green
else
return colors.red
end
end
},
{
field = "fuel",
name = "Fuel",
unit = "mB",
format = "%.2f",
color = function(value)
local v = value.current:get()
if v < value.max / 2 then
return colors.red
elseif v < value.max then
return colors.orange
else
return colors.green
end
end
},
{
field = "fuelWaste",
name = "Fuel Waste",
unit = "B",
format = "%.2f",
color = function(value)
local v = value.current:get()
if v > value.max / 2 then
return colors.red
elseif v > 0 then
return colors.orange
else
return colors.green
end
end
},
Separator:new("horizontal"),
{
field = "boilEfficiency",
name = "Boil Efficiency",
format = "%.2f",
color = function(value)
local v = value.current:get()
if v > 0.75 then
return colors.green
elseif v > 0.5 then
return colors.orange
else
return colors.red
end
end
},
{
field = "temperature",
name = "Temperature",
unit = "K",
format = "%.2f"
},
{
field = "heating",
name = "Heating Rate",
unit = "mB/T",
format = function(value)
local current = value.current:get()
return string.format("%d (%.2f %%)", current, (current / value.max) * 100.0)
end
},
{
field = "coolant",
name = "Coolant",
unit = "B",
format = function(value)
local current = value.current:get() / 1000
local max = value.max / 1000
return string.format("%d (%.2f %%)", current, (current / max) * 100.0)
end,
color = function(value)
local current = value.current:get()
if current < value.max * 0.5 then
return colors.red
elseif current < value.max * 0.75 then
return colors.orange
else
return colors.green
end
end
},
{
field = "heatedCoolant",
name = "Heated Coolant",
unit = "mB",
format = "%d",
color = function(value)
local v = value.current:get()
if v > value.max / 2 then
return colors.red
elseif v > 0 then
return colors.orange
else
return colors.green
end
end
},
Separator:new("horizontal"),
{
field = "damage",
name = "Damage",
unit = "%",
format = "%.2f",
color = function(value)
local v = value.current:get()
if v > 0 then
return colors.red
else
return colors.green
end
end
},
})
local powerGroup = self:createStatusGroup("Power Status", {})
local row = Box:new("horizontal")
row:setSpacing(1)
row:addChild(reactorGroup, "start", true, true)
row:addChild(Separator:new("horizontal", colors.gray), "start", false, false)
row:addChild(powerGroup, "start", true, true)
local box = Box:new("vertical")
box:addChild(row, "start", true, true)
box:addChild(status, "start", false, false)
self:setChild(box)
end
function StatusWindow:createStatusGroup(title, fields)
local vbox1 = Box:new("vertical")
local vbox2 = Box:new("vertical")
for _, field in ipairs(fields) do
if Widget:isInstance(field) then
vbox1:addChild(field)
vbox2:addChild(Label:new(""))
else
Assert.assertIsTable(field)
Assert.assertIsString(field.field)
local row = Box:new("horizontal")
local gradient = Label:new(" ")
row:addChild(gradient, "start", false, false, 0)
local name = Label:new(field.name or field.field)
row:addChild(name, "start", true, true)
local render
if field.format then
if type(field.format) == "function" then
render = field.format
elseif type(field.format) == "string" then
render = function(value)
return string.format(field.format, value.current:get())
end
else
error(("Field formatter must be a string or a function; found '%s'"):format(type(field.format)))
end
else
render = function(value)
return tostring(value.current:get())
end
end
local value = Label:new(render(self.model[field.field]))
if field.color then
local color = field.color(self.model[field.field])
if color then
name:setForeground(color)
value:setForeground(color)
end
end
row:addChild(value)
table.insert(self.updaters, function(model)
local v = model[field.field]
if field.color then
local new_color = field.color(v)
if new_color then
name:setForeground(new_color)
value:setForeground(new_color)
else
name:setForeground(colors.white)
value:setForeground(colors.white)
end
end
local rate = v.current:getRate()
if rate == nil then
gradient:setText(" ")
elseif rate > 0 then
gradient:setText("+ ")
elseif rate < 0 then
gradient:setText("- ")
else
gradient:setText(" ")
end
value:setText(render(v))
end)
vbox1:addChild(row, "start", false, false)
if field.unit then
Assert.assertIsString(field.unit)
vbox2:addChild(Label:new(field.unit))
else
vbox2:addChild(Label:new(""))
end
end
end
local group = Box:new("vertical")
group:addChild(Label:new(title, nil, nil, "center"), "start", false, false)
group:setChildPadding(1, 1)
local data = Box:new("horizontal")
data:addChild(vbox1, "start", true, true)
data:addChild(Separator:new("vertical"), "start", false, false)
data:addChild(vbox2, "start", false, false)
group:addChild(data, "start", true, true)
return group
end
function StatusWindow:updateStatusString()
self.statusLeft:setText(("Reactor Status"))
local time = os.time()
local hour = math.floor(time)
local minute = math.floor(60 * (time - hour))
self.statusRight:setText(("%02d:%02d"):format(hour, minute))
end
function StatusWindow:update()
self:updateStatusString()
for _, updater in ipairs(self.updaters) do
updater(self.model)
end
end
return StatusWindow