diff --git a/graphics/element.lua b/graphics/element.lua index 6ed3434..d776c7f 100644 --- a/graphics/element.lua +++ b/graphics/element.lua @@ -37,6 +37,7 @@ function element.new(args) ---@class graphics_template local protected = { + value = nil, ---@type any window = nil, ---@type table fg_bg = core.graphics.cpair(colors.white, colors.black), frame = core.graphics.gframe(1, 1, 1, 1) @@ -136,11 +137,27 @@ function element.new(args) function protected.on_update(...) end - -- get control value + -- get value function protected.get_value() + return protected.value + end + + -- set value + ---@param value any value to set + function protected.set_value(value) return nil end + -- custom recolor command, varies by element if implemented + ---@vararg cpair|color color(s) + function protected.recolor(...) + end + + -- custom resize command, varies by element if implemented + ---@vararg integer sizing + function protected.resize(...) + end + -- start animations function protected.start_anim() end diff --git a/graphics/elements/controls/multi_button.lua b/graphics/elements/controls/multi_button.lua index 16ee85e..84aa65b 100644 --- a/graphics/elements/controls/multi_button.lua +++ b/graphics/elements/controls/multi_button.lua @@ -1,6 +1,7 @@ -- Button Graphics Element local element = require("graphics.element") + local util = require("scada-common.util") ---@class button_option @@ -33,9 +34,6 @@ local function multi_button(args) -- 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 @@ -52,6 +50,9 @@ local function multi_button(args) -- create new graphics element base object local e = element.new(args) + -- button state (convert nil to 1 if missing) + e.value = args.default or 1 + -- calculate required button information local next_x = 2 for i = 1, #args.options do @@ -72,7 +73,7 @@ local function multi_button(args) e.window.setCursorPos(opt._start_x, 2) - if state == i then + if e.value == i then -- show as pressed e.window.setTextColor(opt.active_fg_bg.fgd) e.window.setBackgroundColor(opt.active_fg_bg.bkg) @@ -86,9 +87,6 @@ local function multi_button(args) end end - -- initial draw - draw() - -- handle touch ---@param event monitor_touch monitor touch event function e.handle_touch(event) @@ -98,14 +96,25 @@ local function multi_button(args) local opt = args.options[i] ---@type button_option if event.x >= opt._start_x and event.x <= opt._end_x then - state = i + e.value = i draw() - args.callback(state) + args.callback(e.value) end end end end + -- set the value + ---@param val integer new value + function e.set_value(val) + e.value = val + draw() + args.callback(e.value) + end + + -- initial draw + draw() + return e.get() end diff --git a/graphics/elements/controls/push_button.lua b/graphics/elements/controls/push_button.lua index 227b8e0..d8a1755 100644 --- a/graphics/elements/controls/push_button.lua +++ b/graphics/elements/controls/push_button.lua @@ -2,6 +2,7 @@ local tcd = require("scada-common.tcallbackdsp") +local core = require("graphics.core") local element = require("graphics.element") ---@class push_button_args @@ -52,12 +53,14 @@ local function push_button(args) function e.handle_touch(event) if args.active_fg_bg ~= nil then -- show as pressed + e.value = true e.window.setTextColor(args.active_fg_bg.fgd) e.window.setBackgroundColor(args.active_fg_bg.bkg) draw() -- show as unpressed in 0.25 seconds tcd.dispatch(0.25, function () + e.value = false e.window.setTextColor(e.fg_bg.fgd) e.window.setBackgroundColor(e.fg_bg.bkg) draw() @@ -68,6 +71,12 @@ local function push_button(args) args.callback() end + -- set the value + ---@param val boolean new value + function e.set_value(val) + if val then e.handle_touch(core.events.touch("", 1, 1)) end + end + -- initial draw draw() diff --git a/graphics/elements/controls/scram_button.lua b/graphics/elements/controls/scram_button.lua index bac3045..fc12d67 100644 --- a/graphics/elements/controls/scram_button.lua +++ b/graphics/elements/controls/scram_button.lua @@ -3,7 +3,6 @@ local tcd = require("scada-common.tcallbackdsp") local core = require("graphics.core") - local element = require("graphics.element") ---@class scram_button_args @@ -65,6 +64,12 @@ local function scram_button(args) args.callback() end + -- set the value + ---@param val boolean new value + function e.set_value(val) + if val then e.handle_touch(core.events.touch("", 1, 1)) end + end + return e.get() end diff --git a/graphics/elements/controls/spinbox_numeric.lua b/graphics/elements/controls/spinbox_numeric.lua index 55b80ce..ac363b2 100644 --- a/graphics/elements/controls/spinbox_numeric.lua +++ b/graphics/elements/controls/spinbox_numeric.lua @@ -1,6 +1,7 @@ -- Spinbox Numeric Graphics Element local element = require("graphics.element") + local util = require("scada-common.util") ---@class spinbox_args @@ -19,7 +20,6 @@ local util = require("scada-common.util") ---@return graphics_element element, element_id id local function spinbox(args) -- properties - local value = args.default or 0.0 local digits = {} local wn_prec = args.whole_num_precision local fr_prec = args.fractional_precision @@ -33,11 +33,6 @@ local function spinbox(args) assert(type(args.arrow_fg_bg) == "table", "graphics.element.spinbox_numeric: arrow_fg_bg is a required field") - local initial_str = util.sprintf(fmt_init, value) - ----@diagnostic disable-next-line: discard-returns - initial_str:gsub("%d", function(char) table.insert(digits, char) end) - -- determine widths args.width = wn_prec + fr_prec + util.trinary(fr_prec > 0, 1, 0) args.height = 3 @@ -45,6 +40,14 @@ local function spinbox(args) -- create new graphics element base object local e = element.new(args) + -- set initial value + e.value = args.default or 0.0 + + local initial_str = util.sprintf(fmt_init, e.value) + +---@diagnostic disable-next-line: discard-returns + initial_str:gsub("%d", function (char) table.insert(digits, char) end) + -- draw the arrows e.window.setBackgroundColor(args.arrow_fg_bg.bkg) e.window.setTextColor(args.arrow_fg_bg.fgd) @@ -62,7 +65,7 @@ local function spinbox(args) -- zero the value local function zero() for i = 1, #digits do digits[i] = 0 end - value = 0 + e.value = 0 end -- print out the current value @@ -70,7 +73,42 @@ local function spinbox(args) e.window.setBackgroundColor(e.fg_bg.bkg) e.window.setTextColor(e.fg_bg.fgd) e.window.setCursorPos(1, 2) - e.window.write(util.sprintf(fmt, value)) + e.window.write(util.sprintf(fmt, e.value)) + end + + -- update the value per digits table + local function update_value() + e.value = 0 + for i = 1, #digits do + local pow = math.abs(wn_prec - i) + if i <= wn_prec then + e.value = e.value + (digits[i] * (10 ^ pow)) + else + e.value = e.value + (digits[i] * (10 ^ -pow)) + end + end + end + + -- enforce numeric limits + local function enforce_limits() + -- min 0 + if e.value < 0 then + zero() + -- max printable + elseif string.len(util.sprintf(fmt, e.value)) > args.width then + -- max out + for i = 1, #digits do digits[i] = 9 end + + -- re-update value + update_value() + end + end + + -- update value and show + local function parse_and_show() + update_value() + enforce_limits() + show_num() end -- init with the default value @@ -90,27 +128,16 @@ local function spinbox(args) digits[idx] = digits[idx] - 1 end - -- update value - value = 0 - for i = 1, #digits do - local pow = math.abs(wn_prec - i) - if i <= wn_prec then - value = value + (digits[i] * (10 ^ pow)) - else - value = value + (digits[i] * (10 ^ -pow)) - end - end - - -- min 0 - if value < 0 then zero() end - - show_num() + parse_and_show() end end - -- get current value - ---@return number|integer - function e.get_value() return value end + -- set the value + ---@param val number number to show + function e.set_value(val) + e.value = val + parse_and_show() + end return e.get() end diff --git a/graphics/elements/controls/start_button.lua b/graphics/elements/controls/start_button.lua index 45aba40..59c8580 100644 --- a/graphics/elements/controls/start_button.lua +++ b/graphics/elements/controls/start_button.lua @@ -3,7 +3,6 @@ local tcd = require("scada-common.tcallbackdsp") local core = require("graphics.core") - local element = require("graphics.element") ---@class start_button_args @@ -65,6 +64,12 @@ local function start_button(args) args.callback() end + -- set the value + ---@param val boolean new value + function e.set_value(val) + if val then e.handle_touch(core.events.touch("", 1, 1)) end + end + return e.get() end diff --git a/graphics/elements/controls/switch_button.lua b/graphics/elements/controls/switch_button.lua index f7a304f..2863747 100644 --- a/graphics/elements/controls/switch_button.lua +++ b/graphics/elements/controls/switch_button.lua @@ -26,9 +26,6 @@ local function switch_button(args) -- single line args.height = 1 - -- button state (convert nil to false if missing) - local state = args.default or false - -- determine widths local text_width = string.len(args.text) args.width = math.max(text_width + 2, args.min_width) @@ -36,12 +33,15 @@ local function switch_button(args) -- create new graphics element base object local e = element.new(args) + -- button state (convert nil to false if missing) + e.value = args.default or false + local h_pad = math.floor((e.frame.w - text_width) / 2) local v_pad = math.floor(e.frame.h / 2) + 1 -- show the button state local function draw_state() - if state then + if e.value then -- show as pressed e.window.setTextColor(args.active_fg_bg.fgd) e.window.setBackgroundColor(args.active_fg_bg.bkg) @@ -64,11 +64,22 @@ local function switch_button(args) ---@diagnostic disable-next-line: unused-local function e.handle_touch(event) -- toggle state - state = not state + e.value = not e.value draw_state() -- call the touch callback with state - args.callback(state) + args.callback(e.value) + end + + -- set the value + ---@param val boolean new value + function e.set_value(val) + -- set state + e.value = val + draw_state() + + -- call the touch callback with state + args.callback(e.value) end return e.get() diff --git a/graphics/elements/indicators/coremap.lua b/graphics/elements/indicators/coremap.lua index 6adb3c9..393575d 100644 --- a/graphics/elements/indicators/coremap.lua +++ b/graphics/elements/indicators/coremap.lua @@ -116,15 +116,18 @@ local function core_map(args) end end - -- initial draw at base temp - draw(300) - -- on state change ---@param temperature number temperature in Kelvin function e.on_update(temperature) + e.value = temperature draw(temperature) end + function e.set_value(val) e.on_update(val) end + + -- initial draw at base temp + e.on_update(300) + return e.get() end diff --git a/graphics/elements/indicators/data.lua b/graphics/elements/indicators/data.lua index 86e248b..64e2a23 100644 --- a/graphics/elements/indicators/data.lua +++ b/graphics/elements/indicators/data.lua @@ -70,6 +70,8 @@ local function data(args) -- on state change ---@param value any new value function e.on_update(value) + e.value = value + local data_str = util.sprintf(args.format, value) -- write data @@ -90,6 +92,8 @@ local function data(args) end end + function e.set_value(val) e.on_update(val) end + -- initial value draw e.on_update(args.value) diff --git a/graphics/elements/indicators/hbar.lua b/graphics/elements/indicators/hbar.lua index f433b91..4fc8532 100644 --- a/graphics/elements/indicators/hbar.lua +++ b/graphics/elements/indicators/hbar.lua @@ -42,6 +42,8 @@ local function hbar(args) -- handle data changes function e.on_update(fraction) + e.value = fraction + -- enforce minimum and maximum if fraction < 0 then fraction = 0.0 @@ -96,6 +98,18 @@ local function hbar(args) end end + ---@param bar_fg_bg cpair new bar colors + function e.recolor(bar_fg_bg) + bar_bkg = bar_fg_bg.blit_bkg + bar_fgd = bar_fg_bg.blit_fgd + + -- re-draw + last_num_bars = 0 + e.on_update(e.value) + end + + function e.set_value(val) e.on_update(val) end + -- initialize to 0 e.on_update(0) diff --git a/graphics/elements/indicators/icon.lua b/graphics/elements/indicators/icon.lua index cdbcf9e..728bfea 100644 --- a/graphics/elements/indicators/icon.lua +++ b/graphics/elements/indicators/icon.lua @@ -55,10 +55,13 @@ local function icon(args) ---@param new_state integer indicator state function e.on_update(new_state) local blit_cmd = state_blit_cmds[new_state] + e.value = new_state e.window.setCursorPos(1, 1) e.window.blit(blit_cmd.text, blit_cmd.fgd, blit_cmd.bkg) end + function e.set_value(val) e.on_update(val) end + -- initial icon draw e.on_update(args.value or 1) diff --git a/graphics/elements/indicators/light.lua b/graphics/elements/indicators/light.lua index 411982d..a1cc85b 100644 --- a/graphics/elements/indicators/light.lua +++ b/graphics/elements/indicators/light.lua @@ -31,6 +31,7 @@ local function indicator_light(args) -- on state change ---@param new_state boolean indicator state function e.on_update(new_state) + e.value = new_state e.window.setCursorPos(1, 1) if new_state then e.window.blit(" \x95", "0" .. args.colors.blit_a, args.colors.blit_a .. e.fg_bg.blit_bkg) @@ -39,6 +40,8 @@ local function indicator_light(args) end end + function e.set_value(val) e.on_update(val) end + -- write label and initial indicator light e.on_update(false) e.window.write(args.label) diff --git a/graphics/elements/indicators/state.lua b/graphics/elements/indicators/state.lua index 5dd39ee..4631a40 100644 --- a/graphics/elements/indicators/state.lua +++ b/graphics/elements/indicators/state.lua @@ -61,10 +61,13 @@ local function state_indicator(args) ---@param new_state integer indicator state function e.on_update(new_state) local blit_cmd = state_blit_cmds[new_state] + e.value = new_state e.window.setCursorPos(1, 1) e.window.blit(blit_cmd.text, blit_cmd.fgd, blit_cmd.bkg) end + function e.set_value(val) e.on_update(val) end + -- initial draw e.on_update(args.value or 1) diff --git a/graphics/elements/indicators/trilight.lua b/graphics/elements/indicators/trilight.lua index 9d8731e..435af84 100644 --- a/graphics/elements/indicators/trilight.lua +++ b/graphics/elements/indicators/trilight.lua @@ -40,6 +40,7 @@ local function tristate_indicator_light(args) -- on state change ---@param new_state integer indicator state function e.on_update(new_state) + e.value = new_state e.window.setCursorPos(1, 1) if new_state == 2 then e.window.blit(" \x95", "0" .. c2, c2 .. e.fg_bg.blit_bkg) @@ -50,6 +51,8 @@ local function tristate_indicator_light(args) end end + function e.set_value(val) e.on_update(val) end + -- write label and initial indicator light e.on_update(0) e.window.write(args.label) diff --git a/graphics/elements/indicators/vbar.lua b/graphics/elements/indicators/vbar.lua index 114fb77..7888033 100644 --- a/graphics/elements/indicators/vbar.lua +++ b/graphics/elements/indicators/vbar.lua @@ -33,6 +33,8 @@ local function vbar(args) -- handle data changes function e.on_update(fraction) + e.value = fraction + -- enforce minimum and maximum if fraction < 0 then fraction = 0.0 @@ -78,6 +80,8 @@ local function vbar(args) end end + function e.set_value(val) e.on_update(val) end + return e.get() end diff --git a/graphics/elements/textbox.lua b/graphics/elements/textbox.lua index 45eb92f..c911677 100644 --- a/graphics/elements/textbox.lua +++ b/graphics/elements/textbox.lua @@ -32,24 +32,36 @@ local function textbox(args) -- draw textbox - local text = args.text - local lines = util.strwrap(text, e.frame.w) + local function display_text(text) + e.value = text - for i = 1, #lines do - if i > e.frame.h then break end + local lines = util.strwrap(text, e.frame.w) - local len = string.len(lines[i]) + for i = 1, #lines do + if i > e.frame.h then break end - -- use cursor position to align this line - if alignment == TEXT_ALIGN.CENTER then - e.window.setCursorPos(math.floor((e.frame.w - len) / 2) + 1, i) - elseif alignment == TEXT_ALIGN.RIGHT then - e.window.setCursorPos((e.frame.w - len) + 1, i) - else - e.window.setCursorPos(1, i) + local len = string.len(lines[i]) + + -- use cursor position to align this line + if alignment == TEXT_ALIGN.CENTER then + e.window.setCursorPos(math.floor((e.frame.w - len) / 2) + 1, i) + elseif alignment == TEXT_ALIGN.RIGHT then + e.window.setCursorPos((e.frame.w - len) + 1, i) + else + e.window.setCursorPos(1, i) + end + + e.window.write(lines[i]) end + end - e.window.write(lines[i]) + display_text(args.text) + + -- set the string value and re-draw the text + ---@param val string value + function e.set_value(val) + e.window.clear() + display_text(val) end return e.get()