diff --git a/graphics/elements/indicator_data.lua b/graphics/elements/indicator_data.lua new file mode 100644 index 0000000..a9677c5 --- /dev/null +++ b/graphics/elements/indicator_data.lua @@ -0,0 +1,61 @@ +-- Data Indicator Graphics Element + +local util = require("scada-common.util") + +local element = require("graphics.element") + +---@class data_indicator_args +---@field label string indicator label +---@field unit? string indicator unit +---@field format string data format (lua string format) +---@field label_unit_colors? cpair label foreground color (a), unit foreground color (b) +---@field default any default value +---@field parent graphics_element +---@field x? integer 1 if omitted +---@field y? integer 1 if omitted +---@field width integer length +---@field fg_bg cpair foreground/background colors + +-- new data indicator +---@param args data_indicator_args +local function data_indicator(args) + -- create new graphics element base object + local e = element.new(args) + + -- label color + if args.label_unit_colors ~= nil then + e.window.setForegroundColor(args.label_unit_colors.color_a) + end + + -- write label + e.setCursorPos(1, 1) + e.window.write(args.label) + + local data_start = string.len(args.label) + 2 + + -- on state change + ---@param value any new value + function e.on_update(value) + local data_str = util.sprintf(args.format, value) + + -- write data + e.window.setCursorPos(data_start, 1) + e.window.setForegroundColor(e.fg_bg.fgd) + e.window.write(data_str) + + -- write label + if args.unit ~= nil then + if args.label_unit_colors ~= nil then + e.window.setForegroundColor(args.label_unit_colors.color_b) + end + e.window.write(" " .. args.unit) + end + end + + -- initial value draw + e.on_update(args.default) + + return e.get() +end + +return data_indicator diff --git a/graphics/elements/indicator_icon.lua b/graphics/elements/indicator_icon.lua index d36dbe7..fc06a29 100644 --- a/graphics/elements/indicator_icon.lua +++ b/graphics/elements/indicator_icon.lua @@ -9,21 +9,20 @@ local element = require("graphics.element") ---@field symbol string ---@class icon_indicator_args ----@field text string indicator text +---@field label string indicator label ---@field states table state color and symbol table ---@field default? integer default state, defaults to 1 ----@field min_text_width? integer text length if omitted +---@field min_label_width? integer label length if omitted ---@field parent graphics_element ---@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 icon indicator ---@param args icon_indicator_args local function icon_indicator(args) -- determine width - args.width = (args.min_text_width or string.len(args.text)) + 4 + args.width = math.max(args.min_label_width or 1, string.len(args.label)) + 4 -- create new graphics element base object local e = element.new(args) @@ -40,9 +39,9 @@ local function icon_indicator(args) }) end - -- write text and initial indicator light + -- write label and initial indicator light e.setCursorPos(5, 1) - e.window.write(args.text) + e.window.write(args.label) -- on state change ---@param new_state integer indicator state diff --git a/graphics/elements/indicator_light.lua b/graphics/elements/indicator_light.lua index b3357e8..9192099 100644 --- a/graphics/elements/indicator_light.lua +++ b/graphics/elements/indicator_light.lua @@ -5,20 +5,19 @@ local util = require("scada-common.util") local element = require("graphics.element") ---@class indicator_light_args ----@field text string indicator text +---@field label string indicator label ---@field colors cpair on/off colors (a/b respectively) ----@field min_text_width? integer text length if omitted +---@field min_label_width? integer label length if omitted ---@field parent graphics_element ---@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 indicator light ---@param args indicator_light_args local function indicator_light(args) -- determine width - args.width = (args.min_text_width or string.len(args.text)) + 3 + args.width = math.max(args.min_label_width or 1, string.len(args.label)) + 3 -- create new graphics element base object local e = element.new(args) @@ -27,10 +26,10 @@ local function indicator_light(args) local on_blit = util.strrep(args.colors.blit_a, 2) local off_blit = util.strrep(args.colors.blit_b, 2) - -- write text and initial indicator light + -- write label and initial indicator light e.setCursorPos(1, 1) e.window.blit(" ", "000", off_blit .. e.fg_bg.blit_bkg) - e.window.write(args.text) + e.window.write(args.label) -- on state change ---@param new_state boolean indicator state diff --git a/graphics/elements/indicator_state.lua b/graphics/elements/indicator_state.lua new file mode 100644 index 0000000..422259f --- /dev/null +++ b/graphics/elements/indicator_state.lua @@ -0,0 +1,72 @@ +-- State (Text) Indicator Graphics Element + +local util = require("scada-common.util") + +local element = require("graphics.element") + +---@class state_text_color +---@field color cpair +---@field text string + +---@class state_indicator_args +---@field states table state color and text table +---@field default? integer default state, defaults to 1 +---@field min_width? integer max state text length if omitted +---@field parent graphics_element +---@field x? integer 1 if omitted +---@field y? integer 1 if omitted +---@field height? integer 1 if omitted, must be an odd number +---@field fg_bg cpair foreground/background colors + +-- new state indicator +---@param args state_indicator_args +local function state_indicator(args) + -- determine height + if util.is_int(args.height) then + assert(args.height % 2 == 1, "graphics.elements.indicator_state: height should be an odd number") + else + args.height = 1 + end + + -- initial guess at width + args.width = args.min_width or 1 + + -- state blit strings + local state_blit_cmds = {} + for i = 1, #args.states do + local state_def = args.states[i] ---@type state_text_color + + -- re-determine width + if string.len(state_def.text) > args.width then + args.width = string.len(state_def.text) + end + + local len = string.len(state_def.text) + local lpad = math.floor((args.width - len) / 2) + local rpad = len - lpad + + table.insert(state_blit_cmds, { + text = util.spaces(lpad) .. state_def.text .. util.spaces(rpad), + fgd = util.strrep(state_def.color.blit_fgd, 3), + bkg = util.strrep(state_def.color.blit_bkg, 3) + }) + end + + -- create new graphics element base object + local e = element.new(args) + + -- on state change + ---@param new_state integer indicator state + function e.on_update(new_state) + local blit_cmd = state_blit_cmds[new_state] + e.window.setCursorPos(1, 1) + e.window.blit(blit_cmd.text, blit_cmd.fgd, blit_cmd.bkg) + end + + -- initial draw + e.on_update(args.default or 1) + + return e.get() +end + +return state_indicator