diff --git a/graphics/element.lua b/graphics/element.lua index da296cb..1ed7afd 100644 --- a/graphics/element.lua +++ b/graphics/element.lua @@ -87,6 +87,11 @@ function element.new(args) function protected.on_update(...) end + -- get control value + function protected.get_value() + return nil + end + ---@class graphics_element local public = {} @@ -117,6 +122,11 @@ function element.new(args) protected.on_update(...) end + -- get the control value reading + function public.get_value() + return protected.get_value() + end + -- show the element function public.show() protected.window.setVisible(true) diff --git a/graphics/elements/spinbox_numeric.lua b/graphics/elements/spinbox_numeric.lua new file mode 100644 index 0000000..d77c3ea --- /dev/null +++ b/graphics/elements/spinbox_numeric.lua @@ -0,0 +1,90 @@ +-- Spinbox Numeric Graphics Element + +local element = require("graphics.element") +local util = require("scada-common.util") + +---@class spinbox_args +---@field default? number default value, defaults to 0.0 +---@field whole_num_precision integer number of whole number digits +---@field fractional_precision integer number of fractional digits +---@field arrow_fg_bg cpair arrow foreground/background colors +---@field parent graphics_element +---@field x? integer 1 if omitted +---@field y? integer 1 if omitted +---@field fg_bg cpair foreground/background colors + +-- new spinbox control +---@param args spinbox_args +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 + local dec_point_x = args.whole_num_precision + 1 + + assert(util.is_int(wn_prec), "graphics.element.spinbox_numeric: whole number precision must be an integer") + assert(util.is_int(fr_prec), "graphics.element.spinbox_numeric: fractional precision must be an integer") + + local initial_str = util.sprintf("%" .. wn_prec .. "." .. fr_prec .. "f", 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 + + -- create new graphics element base object + local e = element.new(args) + + -- draw the arrows + e.window.setBackgroundColor(args.arrow_fg_bg.bkg) + e.window.setTextColor(args.arrow_fg_bg.fgd) + e.window.setCursorPos(1, 1) + e.window.write(util.strrep("\x1e", wn_prec)) + e.window.setCursorPos(1, 3) + e.window.write(util.strrep("\x1f", wn_prec)) + if fr_prec > 0 then + e.window.setCursorPos(1, 1) + e.window.write(" " .. util.strrep("\x1e", fr_prec)) + e.window.setCursorPos(1, 3) + e.window.write(" " .. util.strrep("\x1f", fr_prec)) + end + + -- handle touch + ---@param event monitor_touch monitor touch event + function e.handle_touch(event) + -- only handle if on an increment or decrement arrow + if event.x ~= dec_point_x then + local idx = util.trinary(event.x > dec_point_x, event.x - 1, event.x) + if event.y == 1 then + -- increment + digits[idx] = digits[idx] + 1 + elseif event.y == 3 then + -- decrement + digits[idx] = digits[idx] - 1 + end + + -- update value + value = 0 + for i = 1, #digits do + if i <= wn_prec then + local pow = wn_prec - i + value = value + (digits[i] * (10 ^ pow)) + else + local pow = i - wn_prec + value = value + (digits[i] * (10 ^ -pow)) + end + end + end + end + + -- get current value + ---@return number|integer + function e.get_value() return value end + + return e.get() +end + +return spinbox