diff --git a/coordinator/startup.lua b/coordinator/startup.lua index afab9d3..b31307f 100644 --- a/coordinator/startup.lua +++ b/coordinator/startup.lua @@ -16,7 +16,7 @@ local config = require("coordinator.config") local coordinator = require("coordinator.coordinator") local renderer = require("coordinator.renderer") -local COORDINATOR_VERSION = "alpha-v0.3.11" +local COORDINATOR_VERSION = "alpha-v0.3.12" local print = util.print local println = util.println diff --git a/coordinator/ui/layout/unit_view.lua b/coordinator/ui/layout/unit_view.lua index a5edc05..1dcc8c7 100644 --- a/coordinator/ui/layout/unit_view.lua +++ b/coordinator/ui/layout/unit_view.lua @@ -19,6 +19,7 @@ local IndicatorLight = require("graphics.elements.indicators.light") local StateIndicator = require("graphics.elements.indicators.state") local VerticalBar = require("graphics.elements.indicators.vbar") +local MultiButton = require("graphics.elements.controls.multi_button") local PushButton = require("graphics.elements.controls.push_button") local SCRAMButton = require("graphics.elements.controls.scram_button") local SpinboxNumeric = require("graphics.elements.controls.spinbox_numeric") @@ -66,19 +67,15 @@ local function init(monitor, id) DataIndicator{parent=main,x=21,label="",format="%11.0f",value=0,unit="",lu_colors=lu_cpair,width=12,fg_bg=stat_fg_bg} main.line_break() - TextBox{parent=main,text="CR",x=21,y=12,height=1,width=3,fg_bg=style.label} - local ctrl_rods = HorizontalBar{parent=main,x=24,y=12,show_percent=false,bar_fg_bg=cpair(colors.black,colors.gray),height=1,width=9} - ctrl_rods.update(0.75) + TextBox{parent=main,text="FL",x=21,y=19,height=1,width=2,fg_bg=style.label} + TextBox{parent=main,text="WS",x=24,y=19,height=1,width=2,fg_bg=style.label} + TextBox{parent=main,text="CL",x=28,y=19,height=1,width=2,fg_bg=style.label} + TextBox{parent=main,text="HC",x=31,y=19,height=1,width=2,fg_bg=style.label} - TextBox{parent=main,text="FL",x=21,y=20,height=1,width=2,fg_bg=style.label} - TextBox{parent=main,text="WS",x=24,y=20,height=1,width=2,fg_bg=style.label} - TextBox{parent=main,text="CL",x=28,y=20,height=1,width=2,fg_bg=style.label} - TextBox{parent=main,text="HC",x=31,y=20,height=1,width=2,fg_bg=style.label} - - local fuel = VerticalBar{parent=main,x=21,y=14,fg_bg=cpair(colors.black,colors.gray),height=5,width=2} - local waste = VerticalBar{parent=main,x=24,y=14,fg_bg=cpair(colors.brown,colors.gray),height=5,width=2} - local ccool = VerticalBar{parent=main,x=28,y=14,fg_bg=cpair(colors.lightBlue,colors.gray),height=5,width=2} - local hcool = VerticalBar{parent=main,x=31,y=14,fg_bg=cpair(colors.orange,colors.gray),height=5,width=2} + local fuel = VerticalBar{parent=main,x=21,y=12,fg_bg=cpair(colors.black,colors.gray),height=6,width=2} + local waste = VerticalBar{parent=main,x=24,y=12,fg_bg=cpair(colors.brown,colors.gray),height=6,width=2} + local ccool = VerticalBar{parent=main,x=28,y=12,fg_bg=cpair(colors.lightBlue,colors.gray),height=6,width=2} + local hcool = VerticalBar{parent=main,x=31,y=12,fg_bg=cpair(colors.orange,colors.gray),height=6,width=2} ---@fixme test code fuel.update(1) @@ -89,7 +86,7 @@ local function init(monitor, id) local f = function () print("scram!") end local scram = SCRAMButton{parent=main,x=2,y=core_shift+4,callback=f,fg_bg=scram_fg_bg} - local burn_control = Div{parent=main,x=13,y=core_shift+4,width=19,height=3,fg_bg=cpair(colors.gray,colors.white)} + local burn_control = Div{parent=main,x=14,y=core_shift+4,width=19,height=3,fg_bg=cpair(colors.gray,colors.white)} local burn_rate = SpinboxNumeric{parent=burn_control,x=2,y=1,whole_num_precision=4,fractional_precision=1,arrow_fg_bg=cpair(colors.gray,colors.white),fg_bg=cpair(colors.black,colors.white)} local set_burn = function () print("set burn to " .. burn_rate.get_value()) end @@ -97,6 +94,33 @@ local function init(monitor, id) TextBox{parent=burn_control,x=9,y=2,text="mB/t"} PushButton{parent=burn_control,x=14,y=2,text="SET",min_width=5,fg_bg=cpair(colors.black,colors.yellow),active_fg_bg=cpair(colors.white,colors.gray),callback=set_burn} + local opts = { + { + text = "Auto", + fg_bg = cpair(colors.black, colors.lightGray), + active_fg_bg = cpair(colors.white, colors.gray) + }, + { + text = "Pu", + fg_bg = cpair(colors.black, colors.lightGray), + active_fg_bg = cpair(colors.black, colors.lime) + }, + { + text = "Po", + fg_bg = cpair(colors.black, colors.lightGray), + active_fg_bg = cpair(colors.black, colors.cyan) + }, + { + text = "AM", + fg_bg = cpair(colors.black, colors.lightGray), + active_fg_bg = cpair(colors.black, colors.purple) + } + } + + local waste_sel_f = function (s) print("waste: " .. s) end + local waste_sel = Div{parent=main,x=2,y=core_shift+8,width=31,height=3,fg_bg=cpair(colors.black, colors.white)} + MultiButton{parent=waste_sel,x=2,y=1,options=opts,callback=waste_sel_f,min_width=6,fg_bg=cpair(colors.black, colors.white)} + ---@fixme test code main.line_break() ColorMap{parent=main,x=2,y=51} diff --git a/graphics/elements/controls/multi_button.lua b/graphics/elements/controls/multi_button.lua new file mode 100644 index 0000000..16ee85e --- /dev/null +++ b/graphics/elements/controls/multi_button.lua @@ -0,0 +1,112 @@ +-- Button Graphics Element + +local element = require("graphics.element") +local util = require("scada-common.util") + +---@class button_option +---@field text string +---@field fg_bg cpair +---@field active_fg_bg cpair +---@field _lpad integer automatically calculated left pad +---@field _start_x integer starting touch x range (inclusive) +---@field _end_x integer ending touch x range (inclusive) + +---@class multi_button_args +---@field options table button options +---@field callback function function to call on touch +---@field default? boolean default state, defaults to options[1] +---@field min_width? integer text length + 2 if omitted +---@field parent graphics_element +---@field id? string element id +---@field x? integer 1 if omitted +---@field y? integer 1 if omitted +---@field height? integer parent height if omitted +---@field fg_bg? cpair foreground/background colors + +-- new multi button (latch selection, exclusively one button at a time) +---@param args multi_button_args +---@return graphics_element element, element_id id +local function multi_button(args) + assert(type(args.options) == "table", "graphics.elements.controls.multi_button: options is a required field") + assert(type(args.callback) == "function", "graphics.elements.controls.multi_button: callback is a required field") + + -- single line + args.height = 3 + + -- button state (convert nil to 1 if missing) + local state = args.default or 1 + + -- determine widths + local max_width = 1 + for i = 1, #args.options do + local opt = args.options[i] ---@type button_option + if string.len(opt.text) > max_width then + max_width = string.len(opt.text) + end + end + + local button_width = math.max(max_width, args.min_width or 1) + + args.width = (button_width * #args.options) + #args.options + 1 + + -- create new graphics element base object + local e = element.new(args) + + -- calculate required button information + local next_x = 2 + for i = 1, #args.options do + local opt = args.options[i] ---@type button_option + local w = string.len(opt.text) + + opt._lpad = math.floor((e.frame.w - w) / 2) + opt._start_x = next_x + opt._end_x = next_x + button_width - 1 + + next_x = next_x + (button_width + 1) + end + + -- show the button state + local function draw() + for i = 1, #args.options do + local opt = args.options[i] ---@type button_option + + e.window.setCursorPos(opt._start_x, 2) + + if state == i then + -- show as pressed + e.window.setTextColor(opt.active_fg_bg.fgd) + e.window.setBackgroundColor(opt.active_fg_bg.bkg) + else + -- show as unpressed + e.window.setTextColor(opt.fg_bg.fgd) + e.window.setBackgroundColor(opt.fg_bg.bkg) + end + + e.window.write(util.pad(opt.text, button_width)) + end + end + + -- initial draw + draw() + + -- handle touch + ---@param event monitor_touch monitor touch event + function e.handle_touch(event) + -- determine what was pressed + if event.y == 2 then + for i = 1, #args.options do + local opt = args.options[i] ---@type button_option + + if event.x >= opt._start_x and event.x <= opt._end_x then + state = i + draw() + args.callback(state) + end + end + end + end + + return e.get() +end + +return multi_button diff --git a/graphics/elements/controls/switch_button.lua b/graphics/elements/controls/switch_button.lua index 964eada..f7a304f 100644 --- a/graphics/elements/controls/switch_button.lua +++ b/graphics/elements/controls/switch_button.lua @@ -39,10 +39,6 @@ local function switch_button(args) local h_pad = math.floor((e.frame.w - text_width) / 2) local v_pad = math.floor(e.frame.h / 2) + 1 - -- write the button text - e.window.setCursorPos(h_pad, v_pad) - e.window.write(args.text) - -- show the button state local function draw_state() if state then @@ -55,7 +51,9 @@ local function switch_button(args) e.window.setBackgroundColor(e.fg_bg.bkg) end - e.window.redraw() + -- write the button text + e.window.setCursorPos(h_pad, v_pad) + e.window.write(args.text) end -- initial draw