-- 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.controls.spinbox_numeric: whole number precision must be an integer") assert(util.is_int(fr_prec), "graphics.element.controls.spinbox_numeric: fractional precision must be an integer") assert(type(args.arrow_fg_bg) == "table", "graphics.element.spinbox_numeric: arrow_fg_bg is a required field") 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 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 end end -- get current value ---@return number|integer function e.get_value() return value end return e.get() end return spinbox