#344 element redraws and shorter assert messages

This commit is contained in:
Mikayla Fischler 2023-09-29 19:34:10 -04:00
parent 70831b49d2
commit ed4180a072
35 changed files with 610 additions and 556 deletions

View File

@ -360,6 +360,8 @@ function element.new(args, child_offset_x, child_offset_y)
---@param result any
function protected.response_callback(result) end
-- accessors and control --
-- get value
---@nodiscard
function protected.get_value() return protected.value end
@ -387,6 +389,9 @@ function element.new(args, child_offset_x, child_offset_y)
-- luacheck: pop
---@diagnostic enable: unused-local, unused-vararg
-- re-draw this element
function protected.redraw() end
-- start animations
function protected.start_anim() end

View File

@ -1,7 +1,5 @@
-- Color Map Graphics Element
local util = require("scada-common.util")
local element = require("graphics.element")
---@class colormap_args
@ -16,7 +14,7 @@ local element = require("graphics.element")
---@return graphics_element element, element_id id
local function colormap(args)
local bkg = "008877FFCCEE114455DD9933BBAA2266"
local spaces = util.spaces(32)
local spaces = string.rep(" ", 32)
args.width = 32
args.height = 1
@ -25,8 +23,13 @@ local function colormap(args)
local e = element.new(args)
-- draw color map
function e.redraw()
e.w_set_cur(1, 1)
e.w_blit(spaces, bkg, bkg)
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -24,10 +24,10 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK
---@param args app_button_args
---@return graphics_element element, element_id id
local function app_button(args)
assert(type(args.text) == "string", "graphics.elements.controls.app: text is a required field")
assert(type(args.title) == "string", "graphics.elements.controls.app: title is a required field")
assert(type(args.callback) == "function", "graphics.elements.controls.app: callback is a required field")
assert(type(args.app_fg_bg) == "table", "graphics.elements.controls.app: app_fg_bg is a required field")
assert(type(args.text) == "string", "controls.app: text is a required field")
assert(type(args.title) == "string", "controls.app: title is a required field")
assert(type(args.callback) == "function", "controls.app: callback is a required field")
assert(type(args.app_fg_bg) == "table", "controls.app: app_fg_bg is a required field")
args.height = 4
args.width = 5
@ -35,10 +35,6 @@ local function app_button(args)
-- create new graphics element base object
local e = element.new(args)
-- write app title, centered
e.w_set_cur(math.floor((e.frame.w - string.len(args.title)) / 2) + 1, 4)
e.w_write(args.title)
-- draw the app button
local function draw()
local fgd = args.app_fg_bg.fgd
@ -120,8 +116,18 @@ local function app_button(args)
if val then e.handle_mouse(core.events.mouse_generic(core.events.MOUSE_CLICK.UP, 1, 1)) end
end
-- initial draw
-- element redraw
function e.redraw()
-- write app title, centered
e.w_set_cur(math.floor((e.frame.w - string.len(args.title)) / 2) + 1, 4)
e.w_write(args.title)
-- draw button
draw()
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -18,8 +18,8 @@ local element = require("graphics.element")
---@param args checkbox_args
---@return graphics_element element, element_id id
local function checkbox(args)
assert(type(args.label) == "string", "graphics.elements.controls.checkbox: label is a required field")
assert(type(args.box_fg_bg) == "table", "graphics.elements.controls.checkbox: box_fg_bg is a required field")
assert(type(args.label) == "string", "controls.checkbox: label is a required field")
assert(type(args.box_fg_bg) == "table", "controls.checkbox: box_fg_bg is a required field")
args.can_focus = true
args.height = 1
@ -105,9 +105,14 @@ local function checkbox(args)
e.on_enabled = draw_label
e.on_disabled = draw_label
-- initial draw
-- element redraw
function e.redraw()
draw()
draw_label()
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -21,21 +21,16 @@ local element = require("graphics.element")
---@param args hazard_button_args
---@return graphics_element element, element_id id
local function hazard_button(args)
assert(type(args.text) == "string", "graphics.elements.controls.hazard_button: text is a required field")
assert(type(args.accent) == "number", "graphics.elements.controls.hazard_button: accent is a required field")
assert(type(args.callback) == "function", "graphics.elements.controls.hazard_button: callback is a required field")
assert(type(args.text) == "string", "controls.hazard_button: text is a required field")
assert(type(args.accent) == "number", "controls.hazard_button: accent is a required field")
assert(type(args.callback) == "function", "controls.hazard_button: callback is a required field")
-- static dimensions
args.height = 3
args.width = string.len(args.text) + 4
-- create new graphics element base object
local e = element.new(args)
-- write the button text
e.w_set_cur(3, 2)
e.w_write(args.text)
-- draw border
---@param accent color accent color
local function draw_border(accent)
@ -158,7 +153,6 @@ local function hazard_button(args)
-- 1.5 second timeout
tcd.dispatch(1.5, on_timeout)
-- call the touch callback
args.callback()
end
end
@ -195,8 +189,16 @@ local function hazard_button(args)
e.w_write(args.text)
end
-- initial draw of border
-- element redraw
function e.redraw()
-- write the button text and draw border
e.w_set_cur(3, 2)
e.w_write(args.text)
draw_border(args.accent)
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -29,13 +29,11 @@ local element = require("graphics.element")
---@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(#args.options > 0, "graphics.elements.controls.multi_button: at least one option is required")
assert(type(args.callback) == "function", "graphics.elements.controls.multi_button: callback is a required field")
assert(type(args.default) == "nil" or (type(args.default) == "number" and args.default > 0),
"graphics.elements.controls.multi_button: default must be nil or a number > 0")
assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0),
"graphics.elements.controls.multi_button: min_width must be nil or a number > 0")
assert(type(args.options) == "table", "controls.multi_button: options is a required field")
assert(#args.options > 0, "controls.multi_button: at least one option is required")
assert(type(args.callback) == "function", "controls.multi_button: callback is a required field")
assert(type(args.default) == "nil" or (type(args.default) == "number" and args.default > 0), "controls.multi_button: default must be nil or a number > 0")
assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0), "controls.multi_button: min_width must be nil or a number > 0")
-- single line
args.height = 1
@ -71,7 +69,7 @@ local function multi_button(args)
end
-- show the button state
local function draw()
function e.redraw()
for i = 1, #args.options do
local opt = args.options[i] ---@type button_option
@ -115,7 +113,7 @@ local function multi_button(args)
-- tap always has identical coordinates, so this always passes for taps
if button_ini == button_cur and button_cur ~= nil then
e.value = button_cur
draw()
e.redraw()
args.callback(e.value)
end
end
@ -125,11 +123,11 @@ local function multi_button(args)
---@param val integer new value
function e.set_value(val)
e.value = val
draw()
e.redraw()
end
-- initial draw
draw()
e.redraw()
return e.complete()
end

View File

@ -26,10 +26,9 @@ local KEY_CLICK = core.events.KEY_CLICK
---@param args push_button_args
---@return graphics_element element, element_id id
local function push_button(args)
assert(type(args.text) == "string", "graphics.elements.controls.push_button: text is a required field")
assert(type(args.callback) == "function", "graphics.elements.controls.push_button: callback is a required field")
assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0),
"graphics.elements.controls.push_button: min_width must be nil or a number > 0")
assert(type(args.text) == "string", "controls.push_button: text is a required field")
assert(type(args.callback) == "function", "controls.push_button: callback is a required field")
assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0), "controls.push_button: min_width must be nil or a number > 0")
local text_width = string.len(args.text)
@ -46,7 +45,7 @@ local function push_button(args)
local v_pad = math.floor(e.frame.h / 2) + 1
-- draw the button
local function draw()
function e.redraw()
e.window.clear()
-- write the button text
@ -60,7 +59,7 @@ local function push_button(args)
e.value = true
e.w_set_fgd(args.active_fg_bg.fgd)
e.w_set_bkg(args.active_fg_bg.bkg)
draw()
e.redraw()
end
end
@ -70,7 +69,7 @@ local function push_button(args)
e.value = false
e.w_set_fgd(e.fg_bg.fgd)
e.w_set_bkg(e.fg_bg.bkg)
draw()
e.redraw()
end
end
@ -117,7 +116,7 @@ local function push_button(args)
e.value = false
e.w_set_fgd(e.fg_bg.fgd)
e.w_set_bkg(e.fg_bg.bkg)
draw()
e.redraw()
end
end
@ -127,7 +126,7 @@ local function push_button(args)
e.value = false
e.w_set_fgd(args.dis_fg_bg.fgd)
e.w_set_bkg(args.dis_fg_bg.bkg)
draw()
e.redraw()
end
end
@ -136,7 +135,7 @@ local function push_button(args)
e.on_unfocused = show_unpressed
-- initial draw
draw()
e.redraw()
return e.complete()
end

View File

@ -27,11 +27,12 @@ local element = require("graphics.element")
---@param args radio_2d_args
---@return graphics_element element, element_id id
local function radio_2d_button(args)
assert(type(args.options) == "table" and #args.options > 0, "graphics.elements.controls.radio_2d: options should be a table with length >= 1")
assert(type(args.radio_colors) == "table", "graphics.elements.controls.radio_2d: radio_colors is a required field")
assert(type(args.select_color) == "number" or type(args.color_map) == "table", "graphics.elements.controls.radio_2d: select_color or color_map is required")
assert(type(args.default) == "nil" or (type(args.default) == "number" and args.default > 0),
"graphics.elements.controls.radio_2d: default must be nil or a number > 0")
assert(type(args.options) == "table" and #args.options > 0, "controls.radio_2d: options should be a table with length >= 1")
assert(util.is_int(args.rows) and util.is_int(args.columns), "controls.radio_2d: rows/columns must be integers")
assert((args.rows * args.columns) >= #args.options, "controls.radio_2d: rows x columns size insufficient for provided number of options")
assert(type(args.radio_colors) == "table", "controls.radio_2d: radio_colors is a required field")
assert(type(args.select_color) == "number" or type(args.color_map) == "table", "controls.radio_2d: select_color or color_map is required")
assert(type(args.default) == "nil" or (type(args.default) == "number" and args.default > 0), "controls.radio_2d: default must be nil or a number > 0")
local array = {}
local col_widths = {}
@ -74,8 +75,8 @@ local function radio_2d_button(args)
-- selected option (convert nil to 1 if missing)
e.value = args.default or 1
-- show the args.options/states
local function draw()
-- draw the element
function e.redraw()
local col_x = 1
local radio_color_b = util.trinary(type(args.disable_color) == "number" and not e.enabled, args.disable_color, args.radio_colors.color_b)
@ -135,7 +136,7 @@ local function radio_2d_button(args)
if elem ~= nil and event.initial.x >= elem.x_1 and event.initial.x <= elem.x_2 and event.current.x >= elem.x_1 and event.current.x <= elem.x_2 then
e.value = elem.id
focused_opt = elem.id
draw()
e.redraw()
if type(args.callback) == "function" then args.callback(e.value) end
break
end
@ -149,30 +150,30 @@ local function radio_2d_button(args)
if event.type == core.events.KEY_CLICK.DOWN or event.type == core.events.KEY_CLICK.HELD then
if event.type == core.events.KEY_CLICK.DOWN and (event.key == keys.space or event.key == keys.enter or event.key == keys.numPadEnter) then
e.value = focused_opt
draw()
e.redraw()
if type(args.callback) == "function" then args.callback(e.value) end
elseif event.key == keys.down then
if focused_opt < #args.options then
focused_opt = focused_opt + 1
draw()
e.redraw()
end
elseif event.key == keys.up then
if focused_opt > 1 then
focused_opt = focused_opt - 1
draw()
e.redraw()
end
elseif event.key == keys.right then
if array[focus_y + 1] and array[focus_y + 1][focus_x] then
focused_opt = array[focus_y + 1][focus_x].id
else focused_opt = array[1][focus_x].id end
draw()
e.redraw()
elseif event.key == keys.left then
if array[focus_y - 1] and array[focus_y - 1][focus_x] then
focused_opt = array[focus_y - 1][focus_x].id
draw()
e.redraw()
elseif array[#array][focus_x] then
focused_opt = array[#array][focus_x].id
draw()
e.redraw()
end
end
end
@ -183,20 +184,20 @@ local function radio_2d_button(args)
function e.set_value(val)
if val > 0 and val <= #args.options then
e.value = val
draw()
e.redraw()
end
end
-- handle focus
e.on_focused = draw
e.on_unfocused = draw
e.on_focused = e.redraw
e.on_unfocused = e.redraw
-- handle enable
e.on_enabled = draw
e.on_disabled = draw
e.on_enabled = e.redraw
e.on_disabled = e.redraw
-- initial draw
draw()
e.redraw()
return e.complete()
end

View File

@ -25,14 +25,14 @@ local KEY_CLICK = core.events.KEY_CLICK
---@param args radio_button_args
---@return graphics_element element, element_id id
local function radio_button(args)
assert(type(args.options) == "table", "graphics.elements.controls.radio_button: options is a required field")
assert(#args.options > 0, "graphics.elements.controls.radio_button: at least one option is required")
assert(type(args.radio_colors) == "table", "graphics.elements.controls.radio_button: radio_colors is a required field")
assert(type(args.select_color) == "number", "graphics.elements.controls.radio_button: select_color is a required field")
assert(type(args.options) == "table", "controls.radio_button: options is a required field")
assert(#args.options > 0, "controls.radio_button: at least one option is required")
assert(type(args.radio_colors) == "table", "controls.radio_button: radio_colors is a required field")
assert(type(args.select_color) == "number", "controls.radio_button: select_color is a required field")
assert(type(args.default) == "nil" or (type(args.default) == "number" and args.default > 0),
"graphics.elements.controls.radio_button: default must be nil or a number > 0")
"controls.radio_button: default must be nil or a number > 0")
assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0),
"graphics.elements.controls.radio_button: min_width must be nil or a number > 0")
"controls.radio_button: min_width must be nil or a number > 0")
-- determine widths
local max_width = 1
@ -59,7 +59,7 @@ local function radio_button(args)
e.value = args.default or 1
-- show the button state
local function draw()
function e.redraw()
for i = 1, #args.options do
local opt = args.options[i] ---@type string
@ -97,7 +97,7 @@ local function radio_button(args)
if args.options[event.current.y] ~= nil then
e.value = event.current.y
focused_opt = e.value
draw()
e.redraw()
if type(args.callback) == "function" then args.callback(e.value) end
end
end
@ -109,17 +109,17 @@ local function radio_button(args)
if event.type == KEY_CLICK.DOWN or event.type == KEY_CLICK.HELD then
if event.type == KEY_CLICK.DOWN and (event.key == keys.space or event.key == keys.enter or event.key == keys.numPadEnter) then
e.value = focused_opt
draw()
e.redraw()
if type(args.callback) == "function" then args.callback(e.value) end
elseif event.key == keys.down then
if focused_opt < #args.options then
focused_opt = focused_opt + 1
draw()
e.redraw()
end
elseif event.key == keys.up then
if focused_opt > 1 then
focused_opt = focused_opt - 1
draw()
e.redraw()
end
end
end
@ -130,20 +130,20 @@ local function radio_button(args)
function e.set_value(val)
if val > 0 and val <= #args.options then
e.value = val
draw()
e.redraw()
end
end
-- handle focus
e.on_focused = draw
e.on_unfocused = draw
e.on_focused = e.redraw
e.on_unfocused = e.redraw
-- handle enable
e.on_enabled = draw
e.on_disabled = draw
e.on_enabled = e.redraw
e.on_disabled = e.redraw
-- initial draw
draw()
e.redraw()
return e.complete()
end

View File

@ -1,6 +1,7 @@
-- Sidebar Graphics Element
local tcd = require("scada-common.tcd")
local util = require("scada-common.util")
local core = require("graphics.core")
local element = require("graphics.element")
@ -26,11 +27,10 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK
---@param args sidebar_args
---@return graphics_element element, element_id id
local function sidebar(args)
assert(type(args.tabs) == "table", "graphics.elements.controls.sidebar: tabs is a required field")
assert(#args.tabs > 0, "graphics.elements.controls.sidebar: at least one tab is required")
assert(type(args.callback) == "function", "graphics.elements.controls.sidebar: callback is a required field")
assert(type(args.tabs) == "table", "controls.sidebar: tabs is a required field")
assert(#args.tabs > 0, "controls.sidebar: at least one tab is required")
assert(type(args.callback) == "function", "controls.sidebar: callback is a required field")
-- always 3 wide
args.width = 3
-- create new graphics element base object
@ -41,10 +41,14 @@ local function sidebar(args)
-- default to 1st tab
e.value = 1
local was_pressed = false
-- show the button state
---@param pressed boolean if the currently selected tab should appear as actively pressed
---@param pressed? boolean if the currently selected tab should appear as actively pressed
---@param pressed_idx? integer optional index to show as held (that is not yet selected)
local function draw(pressed, pressed_idx)
pressed = util.trinary(pressed == nil, was_pressed, pressed)
was_pressed = pressed
pressed_idx = pressed_idx or e.value
for i = 1, #args.tabs do
@ -65,12 +69,8 @@ local function sidebar(args)
e.w_write(" ")
e.w_set_cur(1, y + 1)
if e.value == i then
-- show as selected
e.w_write(" " .. tab.char .. "\x10")
else
-- show as unselected
e.w_write(" " .. tab.char .. " ")
end
else e.w_write(" " .. tab.char .. " ") end
e.w_set_cur(1, y + 2)
e.w_write(" ")
end
@ -113,8 +113,10 @@ local function sidebar(args)
draw(false)
end
-- initial draw
draw(false)
-- element redraw
e.redraw = draw
e.redraw()
return e.complete()
end

View File

@ -29,8 +29,8 @@ local function spinbox(args)
local wn_prec = args.whole_num_precision
local fr_prec = args.fractional_precision
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(util.is_int(wn_prec), "controls.spinbox_numeric: whole number precision must be an integer")
assert(util.is_int(fr_prec), "controls.spinbox_numeric: fractional precision must be an integer")
local fmt, fmt_init ---@type string, string
@ -44,7 +44,7 @@ local function spinbox(args)
local dec_point_x = args.whole_num_precision + 1
assert(type(args.arrow_fg_bg) == "table", "graphics.element.spinbox_numeric: arrow_fg_bg is a required field")
assert(type(args.arrow_fg_bg) == "table", "controls.spinbox_numeric: arrow_fg_bg is a required field")
-- determine widths
args.width = wn_prec + fr_prec + util.trinary(fr_prec > 0, 1, 0)
@ -72,8 +72,6 @@ local function spinbox(args)
end
end
draw_arrows(args.arrow_fg_bg.fgd)
-- populate digits from current value
local function set_digits()
local initial_str = util.sprintf(fmt_init, e.value)
@ -125,9 +123,6 @@ local function spinbox(args)
e.w_write(util.sprintf(fmt, e.value))
end
-- init with the default value
show_num()
-- handle mouse interaction
---@param event mouse_interaction mouse event
function e.handle_mouse(event)
@ -138,10 +133,8 @@ local function spinbox(args)
local idx = util.trinary(event.current.x > dec_point_x, event.current.x - 1, event.current.x)
if digits[idx] ~= nil then
if event.current.y == 1 then
-- increment
digits[idx] = digits[idx] + 1
elseif event.current.y == 3 then
-- decrement
digits[idx] = digits[idx] - 1
end
@ -176,18 +169,19 @@ local function spinbox(args)
end
-- enable this input
function e.on_enabled()
draw_arrows(args.arrow_fg_bg.fgd)
end
function e.on_enabled() draw_arrows(args.arrow_fg_bg.fgd) end
-- disable this input
function e.on_disabled()
draw_arrows(args.arrow_disable or colors.lightGray)
function e.on_disabled() draw_arrows(args.arrow_disable or colors.lightGray) end
-- element redraw
function e.redraw()
show_num()
draw_arrows(util.trinary(e.enabled, args.arrow_fg_bg.fgd, args.arrow_disable or colors.lightGray))
end
-- default to zero, init digits table
e.value = 0
set_digits()
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -21,15 +21,13 @@ local element = require("graphics.element")
---@param args switch_button_args
---@return graphics_element element, element_id id
local function switch_button(args)
assert(type(args.text) == "string", "graphics.elements.controls.switch_button: text is a required field")
assert(type(args.callback) == "function", "graphics.elements.controls.switch_button: callback is a required field")
assert(type(args.active_fg_bg) == "table", "graphics.elements.controls.switch_button: active_fg_bg is a required field")
assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0),
"graphics.elements.controls.switch_button: min_width must be nil or a number > 0")
assert(type(args.text) == "string", "controls.switch_button: text is a required field")
assert(type(args.callback) == "function", "controls.switch_button: callback is a required field")
assert(type(args.active_fg_bg) == "table", "controls.switch_button: active_fg_bg is a required field")
assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0), "controls.switch_button: min_width must be nil or a number > 0")
local text_width = string.len(args.text)
-- single line height, calculate width
args.height = 1
args.min_width = args.min_width or 0
args.width = math.max(text_width, args.min_width)
@ -37,44 +35,32 @@ 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) + 1
local v_pad = math.floor(e.frame.h / 2) + 1
-- show the button state
local function draw_state()
function e.redraw()
if e.value then
-- show as pressed
e.w_set_fgd(args.active_fg_bg.fgd)
e.w_set_bkg(args.active_fg_bg.bkg)
else
-- show as unpressed
e.w_set_fgd(e.fg_bg.fgd)
e.w_set_bkg(e.fg_bg.bkg)
end
-- clear to redraw background
e.window.clear()
-- write the button text
e.w_set_cur(h_pad, v_pad)
e.w_write(args.text)
end
-- initial draw
draw_state()
-- handle mouse interaction
---@param event mouse_interaction mouse event
function e.handle_mouse(event)
if e.enabled and core.events.was_clicked(event.type) then
-- toggle state
e.value = not e.value
draw_state()
-- call the touch callback with state
e.redraw()
args.callback(e.value)
end
end
@ -82,11 +68,13 @@ local function switch_button(args)
-- set the value
---@param val boolean new value
function e.set_value(val)
-- set state
e.value = val
draw_state()
e.redraw()
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -27,13 +27,11 @@ local element = require("graphics.element")
---@param args tabbar_args
---@return graphics_element element, element_id id
local function tabbar(args)
assert(type(args.tabs) == "table", "graphics.elements.controls.tabbar: tabs is a required field")
assert(#args.tabs > 0, "graphics.elements.controls.tabbar: at least one tab is required")
assert(type(args.callback) == "function", "graphics.elements.controls.tabbar: callback is a required field")
assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0),
"graphics.elements.controls.tabbar: min_width must be nil or a number > 0")
assert(type(args.tabs) == "table", "controls.tabbar: tabs is a required field")
assert(#args.tabs > 0, "controls.tabbar: at least one tab is required")
assert(type(args.callback) == "function", "controls.tabbar: callback is a required field")
assert(type(args.min_width) == "nil" or (type(args.min_width) == "number" and args.min_width > 0), "controls.tabbar: min_width must be nil or a number > 0")
-- always 1 tall
args.height = 1
-- determine widths
@ -67,7 +65,7 @@ local function tabbar(args)
end
-- show the tab state
local function draw()
function e.redraw()
for i = 1, #args.tabs do
local tab = args.tabs[i] ---@type tabbar_tab
@ -109,7 +107,7 @@ local function tabbar(args)
-- tap always has identical coordinates, so this always passes for taps
if tab_ini == tab_cur and tab_cur ~= nil then
e.value = tab_cur
draw()
e.redraw()
args.callback(e.value)
end
end
@ -119,11 +117,11 @@ local function tabbar(args)
---@param val integer new value
function e.set_value(val)
e.value = val
draw()
e.redraw()
end
-- initial draw
draw()
e.redraw()
return e.complete()
end

View File

@ -42,30 +42,6 @@ local function number_field(args)
-- make an interactive field manager
local ifield = core.new_ifield(e, args.max_digits, args.fg_bg, args.dis_fg_bg)
-- draw input
local function show()
if e.enabled then
e.w_set_bkg(args.fg_bg.bkg)
e.w_set_fgd(args.fg_bg.fgd)
else
e.w_set_bkg(args.dis_fg_bg.bkg)
e.w_set_fgd(args.dis_fg_bg.fgd)
end
-- clear and print
e.w_set_cur(1, 1)
e.w_write(string.rep(" ", e.frame.w))
e.w_set_cur(1, 1)
e.w_write(e.value)
-- show cursor if focused
if e.is_focused() and e.enabled then
e.w_set_fgd(colors.lightGray)
e.w_write("_")
end
end
-- handle mouse interaction
---@param event mouse_interaction mouse event
function e.handle_mouse(event)
@ -117,9 +93,7 @@ local function number_field(args)
-- set the value (must be a number)
---@param val number number to show
function e.set_value(val)
if tonumber(val) then
ifield.set_value("" .. tonumber(val))
end
if tonumber(val) then ifield.set_value("" .. tonumber(val)) end
end
-- set minimum input value
@ -140,9 +114,6 @@ local function number_field(args)
end
end
-- handle focused
e.on_focused = show
-- handle unfocused
function e.on_unfocused()
local val = tonumber(e.value)
@ -162,12 +133,14 @@ local function number_field(args)
ifield.show()
end
-- handle enable
-- handle focus (not unfocus), enable, and redraw with show()
e.on_focused = ifield.show
e.on_enabled = ifield.show
e.on_disabled = ifield.show
e.redraw = ifield.show
-- initial draw
ifield.show()
e.redraw()
return e.complete()
end

View File

@ -88,16 +88,15 @@ local function text_field(args)
ifield.set_value(text)
end
-- handle focus
-- handle focus, enable, and redraw with show()
e.on_focused = ifield.show
e.on_unfocused = ifield.show
-- handle enable
e.on_enabled = ifield.show
e.on_disabled = ifield.show
e.redraw = ifield.show
-- initial draw
ifield.show()
e.redraw()
local elem, id = e.complete()
return elem, id, ifield.censor

View File

@ -25,13 +25,13 @@ local flasher = require("graphics.flasher")
---@param args alarm_indicator_light
---@return graphics_element element, element_id id
local function alarm_indicator_light(args)
assert(type(args.label) == "string", "graphics.elements.indicators.alight: label is a required field")
assert(type(args.c1) == "number", "graphics.elements.indicators.alight: c1 is a required field")
assert(type(args.c2) == "number", "graphics.elements.indicators.alight: c2 is a required field")
assert(type(args.c3) == "number", "graphics.elements.indicators.alight: c3 is a required field")
assert(type(args.label) == "string", "indicators.alight: label is a required field")
assert(type(args.c1) == "number", "indicators.alight: c1 is a required field")
assert(type(args.c2) == "number", "indicators.alight: c2 is a required field")
assert(type(args.c3) == "number", "indicators.alight: c3 is a required field")
if args.flash then
assert(util.is_int(args.period), "graphics.elements.indicators.alight: period is a required field if flash is enabled")
assert(util.is_int(args.period), "indicators.alight: period is a required field if flash is enabled")
end
-- single line
@ -51,6 +51,8 @@ local function alarm_indicator_light(args)
-- create new graphics element base object
local e = element.new(args)
e.value = 1
-- called by flasher when enabled
local function flash_callback()
e.w_set_cur(1, 1)
@ -105,9 +107,14 @@ local function alarm_indicator_light(args)
---@param val integer indicator state
function e.set_value(val) e.on_update(val) end
-- write label and initial indicator light
e.on_update(1)
-- draw label and indicator light
function e.redraw()
e.on_update(e.value)
e.w_write(args.label)
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -18,8 +18,8 @@ local element = require("graphics.element")
---@param args core_map_args
---@return graphics_element element, element_id id
local function core_map(args)
assert(util.is_int(args.reactor_l), "graphics.elements.indicators.coremap: reactor_l is a required field")
assert(util.is_int(args.reactor_w), "graphics.elements.indicators.coremap: reactor_w is a required field")
assert(util.is_int(args.reactor_l), "indicators.coremap: reactor_l is a required field")
assert(util.is_int(args.reactor_w), "indicators.coremap: reactor_w is a required field")
-- require max dimensions
args.width = 18
@ -31,6 +31,8 @@ local function core_map(args)
-- create new graphics element base object
local e = element.new(args)
e.value = 0
local alternator = true
local core_l = args.reactor_l - 2
@ -157,11 +159,14 @@ local function core_map(args)
e.on_update(e.value)
end
-- initial (one-time except for resize()) frame draw
-- redraw both frame and core
function e.redraw()
draw_frame()
draw_core(e.value)
end
-- initial draw
e.on_update(0)
e.redraw()
return e.complete()
end

View File

@ -24,25 +24,17 @@ local element = require("graphics.element")
---@param args data_indicator_args
---@return graphics_element element, element_id id
local function data(args)
assert(type(args.label) == "string", "graphics.elements.indicators.data: label is a required field")
assert(type(args.format) == "string", "graphics.elements.indicators.data: format is a required field")
assert(args.value ~= nil, "graphics.elements.indicators.data: value is a required field")
assert(util.is_int(args.width), "graphics.elements.indicators.data: width is a required field")
assert(type(args.label) == "string", "indicators.data: label is a required field")
assert(type(args.format) == "string", "indicators.data: format is a required field")
assert(args.value ~= nil, "indicators.data: value is a required field")
assert(util.is_int(args.width), "indicators.data: width is a required field")
-- single line
args.height = 1
-- create new graphics element base object
local e = element.new(args)
-- label color
if args.lu_colors ~= nil then
e.w_set_fgd(args.lu_colors.color_a)
end
-- write label
e.w_set_cur(1, 1)
e.w_write(args.label)
e.value = args.value
local value_color = e.fg_bg.fgd
local label_len = string.len(args.label)
@ -93,8 +85,17 @@ local function data(args)
e.on_update(e.value)
end
-- initial value draw
e.on_update(args.value)
-- element redraw
function e.redraw()
if args.lu_colors ~= nil then e.w_set_fgd(args.lu_colors.color_a) end
e.w_set_cur(1, 1)
e.w_write(args.label)
e.on_update(e.value)
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -28,10 +28,12 @@ local function hbar(args)
-- create new graphics element base object
local e = element.new(args)
e.value = 0.0
-- bar width is width - 5 characters for " 100%" if showing percent
local bar_width = util.trinary(args.show_percent, e.frame.w - 5, e.frame.w)
assert(bar_width > 0, "graphics.elements.indicators.hbar: too small for bar")
assert(bar_width > 0, "indicators.hbar: too small for bar")
-- determine bar colors
local bar_bkg = e.fg_bg.blit_bkg
@ -105,20 +107,21 @@ local function hbar(args)
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
if type(e.value) == "number" then
e.on_update(e.value)
end
e.redraw()
end
-- set the percentage value
---@param val number 0.0 to 1.0
function e.set_value(val) e.on_update(val) end
-- initialize to 0
e.on_update(0)
-- element redraw
function e.redraw()
last_num_bars = -1
e.on_update(e.value)
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -23,18 +23,17 @@ local element = require("graphics.element")
---@param args icon_indicator_args
---@return graphics_element element, element_id id
local function icon(args)
assert(type(args.label) == "string", "graphics.elements.indicators.icon: label is a required field")
assert(type(args.states) == "table", "graphics.elements.indicators.icon: states is a required field")
assert(type(args.label) == "string", "indicators.icon: label is a required field")
assert(type(args.states) == "table", "indicators.icon: states is a required field")
-- single line
args.height = 1
-- determine width
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)
e.value = args.value or 1
-- state blit strings
local state_blit_cmds = {}
for i = 1, #args.states do
@ -47,10 +46,6 @@ local function icon(args)
})
end
-- write label and initial indicator light
e.w_set_cur(5, 1)
e.w_write(args.label)
-- on state change
---@param new_state integer indicator state
function e.on_update(new_state)
@ -64,8 +59,16 @@ local function icon(args)
---@param val integer indicator state
function e.set_value(val) e.on_update(val) end
-- initial icon draw
e.on_update(args.value or 1)
-- element redraw
function e.redraw()
e.w_set_cur(5, 1)
e.w_write(args.label)
e.on_update(e.value)
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -23,25 +23,23 @@ local flasher = require("graphics.flasher")
---@param args indicator_led_args
---@return graphics_element element, element_id id
local function indicator_led(args)
assert(type(args.label) == "string", "graphics.elements.indicators.led: label is a required field")
assert(type(args.colors) == "table", "graphics.elements.indicators.led: colors is a required field")
assert(type(args.label) == "string", "indicators.led: label is a required field")
assert(type(args.colors) == "table", "indicators.led: colors is a required field")
if args.flash then
assert(util.is_int(args.period), "graphics.elements.indicators.led: period is a required field if flash is enabled")
assert(util.is_int(args.period), "indicators.led: period is a required field if flash is enabled")
end
-- single line
args.height = 1
-- determine width
args.width = math.max(args.min_label_width or 0, string.len(args.label)) + 2
-- flasher state
local flash_on = true
-- create new graphics element base object
local e = element.new(args)
e.value = false
-- called by flasher when enabled
local function flash_callback()
e.w_set_cur(1, 1)
@ -88,12 +86,17 @@ local function indicator_led(args)
---@param val boolean indicator state
function e.set_value(val) e.on_update(val) end
-- write label and initial indicator light
e.on_update(false)
-- draw label and indicator light
function e.redraw()
e.on_update(e.value)
if string.len(args.label) > 0 then
e.w_set_cur(3, 1)
e.w_write(args.label)
end
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -25,25 +25,20 @@ local flasher = require("graphics.flasher")
---@param args indicator_led_pair_args
---@return graphics_element element, element_id id
local function indicator_led_pair(args)
assert(type(args.label) == "string", "graphics.elements.indicators.ledpair: label is a required field")
assert(type(args.off) == "number", "graphics.elements.indicators.ledpair: off is a required field")
assert(type(args.c1) == "number", "graphics.elements.indicators.ledpair: c1 is a required field")
assert(type(args.c2) == "number", "graphics.elements.indicators.ledpair: c2 is a required field")
assert(type(args.label) == "string", "indicators.ledpair: label is a required field")
assert(type(args.off) == "number", "indicators.ledpair: off is a required field")
assert(type(args.c1) == "number", "indicators.ledpair: c1 is a required field")
assert(type(args.c2) == "number", "indicators.ledpair: c2 is a required field")
if args.flash then
assert(util.is_int(args.period), "graphics.elements.indicators.ledpair: period is a required field if flash is enabled")
assert(util.is_int(args.period), "indicators.ledpair: period is a required field if flash is enabled")
end
-- single line
args.height = 1
-- determine width
args.width = math.max(args.min_label_width or 0, string.len(args.label)) + 2
-- flasher state
local flash_on = true
-- blit translations
local co = colors.toBlit(args.off)
local c1 = colors.toBlit(args.c1)
local c2 = colors.toBlit(args.c2)
@ -51,7 +46,6 @@ local function indicator_led_pair(args)
-- create new graphics element base object
local e = element.new(args)
-- init value for initial check in on_update
e.value = 1
-- called by flasher when enabled
@ -86,7 +80,6 @@ local function indicator_led_pair(args)
elseif new_state <= 1 then
flash_on = false
flasher.stop(flash_callback)
e.w_blit("\x8c", co, e.fg_bg.blit_bkg)
end
elseif new_state == 2 then
@ -102,12 +95,17 @@ local function indicator_led_pair(args)
---@param val integer indicator state
function e.set_value(val) e.on_update(val) end
-- write label and initial indicator light
e.on_update(1)
-- draw label and indicator light
function e.redraw()
e.on_update(e.value)
if string.len(args.label) > 0 then
e.w_set_cur(3, 1)
e.w_write(args.label)
end
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -18,19 +18,15 @@ local element = require("graphics.element")
---@param args indicator_led_rgb_args
---@return graphics_element element, element_id id
local function indicator_led_rgb(args)
assert(type(args.label) == "string", "graphics.elements.indicators.ledrgb: label is a required field")
assert(type(args.colors) == "table", "graphics.elements.indicators.ledrgb: colors is a required field")
assert(type(args.label) == "string", "indicators.ledrgb: label is a required field")
assert(type(args.colors) == "table", "indicators.ledrgb: colors is a required field")
-- single line
args.height = 1
-- determine width
args.width = math.max(args.min_label_width or 0, string.len(args.label)) + 2
-- create new graphics element base object
local e = element.new(args)
-- init value for initial check in on_update
e.value = 1
-- on state change
@ -47,12 +43,17 @@ local function indicator_led_rgb(args)
---@param val integer indicator state
function e.set_value(val) e.on_update(val) end
-- write label and initial indicator light
e.on_update(1)
-- draw label and indicator light
function e.redraw()
e.on_update(e.value)
if string.len(args.label) > 0 then
e.w_set_cur(3, 1)
e.w_write(args.label)
end
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -23,25 +23,23 @@ local flasher = require("graphics.flasher")
---@param args indicator_light_args
---@return graphics_element element, element_id id
local function indicator_light(args)
assert(type(args.label) == "string", "graphics.elements.indicators.light: label is a required field")
assert(type(args.colors) == "table", "graphics.elements.indicators.light: colors is a required field")
assert(type(args.label) == "string", "indicators.light: label is a required field")
assert(type(args.colors) == "table", "indicators.light: colors is a required field")
if args.flash then
assert(util.is_int(args.period), "graphics.elements.indicators.light: period is a required field if flash is enabled")
assert(util.is_int(args.period), "indicators.light: period is a required field if flash is enabled")
end
-- single line
args.height = 1
-- determine width
args.width = math.max(args.min_label_width or 1, string.len(args.label)) + 2
-- flasher state
local flash_on = true
-- create new graphics element base object
local e = element.new(args)
e.value = false
-- called by flasher when enabled
local function flash_callback()
e.w_set_cur(1, 1)
@ -88,10 +86,15 @@ local function indicator_light(args)
---@param val boolean indicator state
function e.set_value(val) e.on_update(val) end
-- write label and initial indicator light
-- draw label and indicator light
function e.redraw()
e.on_update(false)
e.w_set_cur(3, 1)
e.w_write(args.label)
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -9,7 +9,7 @@ local element = require("graphics.element")
---@field format string power format override (lua string format)
---@field rate boolean? whether to append /t to the end (power per tick)
---@field lu_colors? cpair label foreground color (a), unit foreground color (b)
---@field value any default value
---@field value number default value
---@field parent graphics_element
---@field id? string element id
---@field x? integer 1 if omitted
@ -23,26 +23,17 @@ local element = require("graphics.element")
---@param args power_indicator_args
---@return graphics_element element, element_id id
local function power(args)
assert(args.value ~= nil, "graphics.elements.indicators.power: value is a required field")
assert(util.is_int(args.width), "graphics.elements.indicators.power: width is a required field")
assert(type(args.value) == "number", "indicators.power: value is a required number field")
assert(util.is_int(args.width), "indicators.power: width is a required field")
-- single line
args.height = 1
-- create new graphics element base object
local e = element.new(args)
-- label color
if args.lu_colors ~= nil then
e.w_set_fgd(args.lu_colors.color_a)
end
e.value = args.value
-- write label
e.w_set_cur(1, 1)
e.w_write(args.label)
local data_start = string.len(args.label) + 2
if string.len(args.label) == 0 then data_start = 1 end
local data_start = 0
-- on state change
---@param value any new value
@ -77,8 +68,20 @@ local function power(args)
---@param val any new value
function e.set_value(val) e.on_update(val) end
-- initial value draw
e.on_update(args.value)
-- element redraw
function e.redraw()
if args.lu_colors ~= nil then e.w_set_fgd(args.lu_colors.color_a) end
e.w_set_cur(1, 1)
e.w_write(args.label)
data_start = string.len(args.label) + 2
if string.len(args.label) == 0 then data_start = 1 end
e.on_update(e.value)
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -10,7 +10,7 @@ local element = require("graphics.element")
---@field format string data format (lua string format)
---@field commas? boolean whether to use commas if a number is given (default to false)
---@field lu_colors? cpair label foreground color (a), unit foreground color (b)
---@field value any default value
---@field value number default value
---@field parent graphics_element
---@field id? string element id
---@field x? integer 1 if omitted
@ -24,24 +24,17 @@ local element = require("graphics.element")
---@param args rad_indicator_args
---@return graphics_element element, element_id id
local function rad(args)
assert(type(args.label) == "string", "graphics.elements.indicators.rad: label is a required field")
assert(type(args.format) == "string", "graphics.elements.indicators.rad: format is a required field")
assert(util.is_int(args.width), "graphics.elements.indicators.rad: width is a required field")
assert(type(args.value) ~= "number", "indicators.rad: value is a required number field")
assert(type(args.label) == "string", "indicators.rad: label is a required field")
assert(type(args.format) == "string", "indicators.rad: format is a required field")
assert(util.is_int(args.width), "indicators.rad: width is a required field")
-- single line
args.height = 1
-- create new graphics element base object
local e = element.new(args)
-- label color
if args.lu_colors ~= nil then
e.w_set_fgd(args.lu_colors.color_a)
end
-- write label
e.w_set_cur(1, 1)
e.w_write(args.label)
e.value = types.new_zero_radiation_reading()
local label_len = string.len(args.label)
local data_start = 1
@ -82,8 +75,17 @@ local function rad(args)
---@param val any new value
function e.set_value(val) e.on_update(val) end
-- initial value draw
e.on_update(types.new_zero_radiation_reading())
-- element redraw
function e.redraw()
if args.lu_colors ~= nil then e.w_set_fgd(args.lu_colors.color_a) end
e.w_set_cur(1, 1)
e.w_write(args.label)
e.on_update(e.value)
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -25,16 +25,14 @@ local element = require("graphics.element")
---@param args state_indicator_args
---@return graphics_element element, element_id id
local function state_indicator(args)
assert(type(args.states) == "table", "graphics.elements.indicators.state: states is a required field")
assert(type(args.states) == "table", "indicators.state: states is a required field")
-- determine height
if util.is_int(args.height) then
assert(args.height % 2 == 1, "graphics.elements.indicators.state: height should be an odd number")
assert(args.height % 2 == 1, "indicators.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
@ -42,7 +40,6 @@ local function state_indicator(args)
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
@ -59,13 +56,20 @@ local function state_indicator(args)
-- create new graphics element base object
local e = element.new(args)
e.value = args.value or 1
-- element redraw
function e.redraw()
local blit_cmd = state_blit_cmds[e.value]
e.w_set_cur(1, 1)
e.w_blit(blit_cmd.text, blit_cmd.fgd, blit_cmd.bkg)
end
-- on state change
---@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.w_set_cur(1, 1)
e.w_blit(blit_cmd.text, blit_cmd.fgd, blit_cmd.bkg)
e.redraw()
end
-- set indicator state
@ -73,7 +77,7 @@ local function state_indicator(args)
function e.set_value(val) e.on_update(val) end
-- initial draw
e.on_update(args.value or 1)
e.redraw()
return e.complete()
end

View File

@ -25,35 +25,29 @@ local flasher = require("graphics.flasher")
---@param args tristate_indicator_light_args
---@return graphics_element element, element_id id
local function tristate_indicator_light(args)
assert(type(args.label) == "string", "graphics.elements.indicators.trilight: label is a required field")
assert(type(args.c1) == "number", "graphics.elements.indicators.trilight: c1 is a required field")
assert(type(args.c2) == "number", "graphics.elements.indicators.trilight: c2 is a required field")
assert(type(args.c3) == "number", "graphics.elements.indicators.trilight: c3 is a required field")
assert(type(args.label) == "string", "indicators.trilight: label is a required field")
assert(type(args.c1) == "number", "indicators.trilight: c1 is a required field")
assert(type(args.c2) == "number", "indicators.trilight: c2 is a required field")
assert(type(args.c3) == "number", "indicators.trilight: c3 is a required field")
if args.flash then
assert(util.is_int(args.period), "graphics.elements.indicators.trilight: period is a required field if flash is enabled")
assert(util.is_int(args.period), "indicators.trilight: period is a required field if flash is enabled")
end
-- single line
args.height = 1
-- determine width
args.width = math.max(args.min_label_width or 1, string.len(args.label)) + 2
-- flasher state
local flash_on = true
-- blit translations
local c1 = colors.toBlit(args.c1)
local c2 = colors.toBlit(args.c2)
local c3 = colors.toBlit(args.c3)
-- create new graphics element base object
local e = element.new(args)
-- init value for initial check in on_update
e.value = 1
local flash_on = true
local c1 = colors.toBlit(args.c1)
local c2 = colors.toBlit(args.c2)
local c3 = colors.toBlit(args.c3)
-- called by flasher when enabled
local function flash_callback()
e.w_set_cur(1, 1)
@ -102,9 +96,14 @@ local function tristate_indicator_light(args)
---@param val integer indicator state
function e.set_value(val) e.on_update(val) end
-- write label and initial indicator light
-- draw light and label
function e.redraw()
e.on_update(1)
e.w_write(args.label)
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -20,13 +20,13 @@ local element = require("graphics.element")
---@param args vbar_args
---@return graphics_element element, element_id id
local function vbar(args)
-- properties/state
local last_num_bars = -1
-- create new graphics element base object
local e = element.new(args)
-- blit strings
e.value = 0.0
local last_num_bars = -1
local fgd = string.rep(e.fg_bg.blit_fgd, e.frame.w)
local bkg = string.rep(e.fg_bg.blit_bkg, e.frame.w)
local spaces = util.spaces(e.frame.w)
@ -52,10 +52,7 @@ local function vbar(args)
if num_bars ~= last_num_bars then
last_num_bars = num_bars
-- start bottom up
local y = e.frame.h
-- start at base of vertical bar
e.w_set_cur(1, y)
-- fill percentage
@ -83,22 +80,26 @@ local function vbar(args)
end
end
-- set the percentage value
---@param val number 0.0 to 1.0
function e.set_value(val) e.on_update(val) end
-- element redraw
function e.redraw()
last_num_bars = -1
e.on_update(e.value)
end
-- change bar color
---@param fg_bg cpair new bar colors
function e.recolor(fg_bg)
fgd = string.rep(fg_bg.blit_fgd, e.frame.w)
bkg = string.rep(fg_bg.blit_bkg, e.frame.w)
-- re-draw
last_num_bars = 0
if type(e.value) == "number" then
e.on_update(e.value)
end
e.redraw()
end
-- set the percentage value
---@param val number 0.0 to 1.0
function e.set_value(val) e.on_update(val) end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -274,9 +274,21 @@ local function listbox(args)
end
end
-- element redraw
function e.redraw()
draw_arrows(0)
draw_bar()
-- redraw all children
for i = 1, #list do
local item = list[i] ---@type listbox_item
item.e.redraw()
end
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -19,23 +19,30 @@ local element = require("graphics.element")
---@param args multipane_args
---@return graphics_element element, element_id id
local function multipane(args)
assert(type(args.panes) == "table", "graphics.elements.multipane: panes is a required field")
assert(type(args.panes) == "table", "multipane: panes is a required field")
-- create new graphics element base object
local e = element.new(args)
e.value = 1
-- show the selected pane
function e.redraw()
for i = 1, #args.panes do args.panes[i].hide() end
args.panes[e.value].show()
end
-- select which pane is shown
---@param value integer pane to show
function e.set_value(value)
if (e.value ~= value) and (value > 0) and (value <= #args.panes) then
e.value = value
for i = 1, #args.panes do args.panes[i].hide() end
args.panes[value].show()
e.redraw()
end
end
e.set_value(1)
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -24,12 +24,11 @@ local element = require("graphics.element")
---@param args pipenet_args
---@return graphics_element element, element_id id
local function pipenet(args)
assert(type(args.pipes) == "table", "graphics.elements.indicators.pipenet: pipes is a required field")
assert(type(args.pipes) == "table", "pipenet: pipes is a required field")
args.width = 0
args.height = 0
-- determine width/height
for i = 1, #args.pipes do
local pipe = args.pipes[i] ---@type pipe
@ -57,8 +56,8 @@ local function pipenet(args)
if any_thin then break end
end
if not any_thin then
-- draw all pipes
-- draw all pipes by drawing out lines
local function vector_draw()
for p = 1, #args.pipes do
local pipe = args.pipes[p] ---@type pipe
@ -161,65 +160,17 @@ local function pipenet(args)
end
end
end
else
-- build map if using thin pipes, easist way to check adjacent blocks (cannot 'cheat' like with standard width)
local map = {}
-- allocate map
for x = 1, args.width do
table.insert(map, {})
for _ = 1, args.height do table.insert(map[x], false) end
end
-- build map
for p = 1, #args.pipes do
local pipe = args.pipes[p] ---@type pipe
local x = 1 + pipe.x1
local y = 1 + pipe.y1
local x_step = util.trinary(pipe.x1 >= pipe.x2, -1, 1)
local y_step = util.trinary(pipe.y1 >= pipe.y2, -1, 1)
local entry = { atr = pipe.align_tr, thin = pipe.thin, fg = colors.toBlit(pipe.color), bg = e.fg_bg.blit_bkg }
if pipe.align_tr then
-- cross width then height
for _ = 1, pipe.w do
map[x][y] = entry
x = x + x_step
end
x = x - x_step -- back up one
for _ = 1, pipe.h do
map[x][y] = entry
y = y + y_step
end
else
-- cross height then width
for _ = 1, pipe.h do
map[x][y] = entry
y = y + y_step
end
y = y - y_step -- back up one
for _ = 1, pipe.w do
map[x][y] = entry
x = x + x_step
end
end
end
-- render
for x = 1, args.width do
for y = 1, args.height do
local entry = map[x][y] ---@type _pipe_map_entry|false
-- draw a particular map cell
---@param map table 2D cell map
---@param x integer x coord
---@param y integer y coord
local function draw_map_cell(map, x, y)
local entry = map[x][y] ---@type _pipe_map_entry already confirmed not false
local char
local invert = false
if entry ~= false then
local function check(cx, cy)
return (map[cx] ~= nil) and (map[cx][cy] ~= nil) and (map[cx][cy] ~= false) and (map[cx][cy].fg == entry.fg)
end
@ -306,10 +257,74 @@ local function pipenet(args)
e.w_blit(char, entry.fg, entry.bg)
end
end
-- draw all pipes by assembling and marking up a 2D map<br>
-- this is an easy way to check adjacent blocks, which is required to properly draw thin pipes
local function map_draw()
local map = {}
for x = 1, args.width do
table.insert(map, {})
for _ = 1, args.height do table.insert(map[x], false) end
end
-- build map
for p = 1, #args.pipes do
local pipe = args.pipes[p] ---@type pipe
local x = 1 + pipe.x1
local y = 1 + pipe.y1
local x_step = util.trinary(pipe.x1 >= pipe.x2, -1, 1)
local y_step = util.trinary(pipe.y1 >= pipe.y2, -1, 1)
local entry = { atr = pipe.align_tr, thin = pipe.thin, fg = colors.toBlit(pipe.color), bg = e.fg_bg.blit_bkg }
if pipe.align_tr then
-- cross width then height
for _ = 1, pipe.w do
map[x][y] = entry
x = x + x_step
end
x = x - x_step -- back up one
for _ = 1, pipe.h do
map[x][y] = entry
y = y + y_step
end
else
-- cross height then width
for _ = 1, pipe.h do
map[x][y] = entry
y = y + y_step
end
y = y - y_step -- back up one
for _ = 1, pipe.w do
map[x][y] = entry
x = x + x_step
end
end
end
-- render
for x = 1, args.width do
for y = 1, args.height do
if map[x][y] ~= false then draw_map_cell(map, x, y) end
end
end
end
-- element redraw
function e.redraw()
if any_thin then map_draw() else vector_draw() end
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -22,7 +22,7 @@ local element = require("graphics.element")
---@param args rectangle_args
---@return graphics_element element, element_id id
local function rectangle(args)
assert(args.border ~= nil or args.thin ~= true, "graphics.elements.rectangle: thin requires border to be provided")
assert(args.border ~= nil or args.thin ~= true, "rectangle: thin requires border to be provided")
-- if thin, then width will always need to be 1
if args.thin == true then
@ -65,8 +65,8 @@ local function rectangle(args)
local inner_width = e.frame.w - width_x2
-- check dimensions
assert(width_x2 <= e.frame.w, "graphics.elements.rectangle: border too thick for width")
assert(width_x2 <= e.frame.h, "graphics.elements.rectangle: border too thick for height")
assert(width_x2 <= e.frame.w, "rectangle: border too thick for width")
assert(width_x2 <= e.frame.h, "rectangle: border too thick for height")
-- form the basic line strings and top/bottom blit strings
local spaces = util.spaces(e.frame.w)
@ -126,6 +126,7 @@ local function rectangle(args)
end
-- draw rectangle with borders
function e.redraw()
for y = 1, e.frame.h do
e.w_set_cur(1, y)
-- top border
@ -186,6 +187,10 @@ local function rectangle(args)
end
end
-- initial draw of border
e.redraw()
end
return e.complete()
end

View File

@ -24,19 +24,20 @@ local TEXT_ALIGN = core.TEXT_ALIGN
---@param args textbox_args
---@return graphics_element element, element_id id
local function textbox(args)
assert(type(args.text) == "string", "graphics.elements.textbox: text is a required field")
assert(type(args.text) == "string", "textbox: text is a required field")
-- create new graphics element base object
local e = element.new(args)
e.value = args.text
local alignment = args.alignment or TEXT_ALIGN.LEFT
-- draw textbox
function e.redraw()
e.window.clear()
local function display_text(text)
e.value = text
local lines = util.strwrap(text, e.frame.w)
local lines = util.strwrap(e.value, e.frame.w)
for i = 1, #lines do
if i > e.frame.h then break end
@ -56,15 +57,16 @@ local function textbox(args)
end
end
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)
e.value = val
e.redraw()
end
-- initial draw
e.redraw()
return e.complete()
end

View File

@ -22,13 +22,11 @@ local element = require("graphics.element")
---@param args tiling_args
---@return graphics_element element, element_id id
local function tiling(args)
assert(type(args.fill_c) == "table", "graphics.elements.tiling: fill_c is a required field")
assert(type(args.fill_c) == "table", "tiling: fill_c is a required field")
-- create new graphics element base object
local e = element.new(args)
-- draw tiling box
local fill_a = args.fill_c.blit_a
local fill_b = args.fill_c.blit_b
@ -38,13 +36,9 @@ local function tiling(args)
local start_y = 1
local inner_width = math.floor(e.frame.w / util.trinary(even, 2, 1))
local inner_height = e.frame.h
local alternator = true
-- border
if args.border_c ~= nil then
e.w_set_bkg(args.border_c)
e.window.clear()
start_x = 1 + util.trinary(even, 2, 1)
start_y = 2
@ -53,12 +47,21 @@ local function tiling(args)
end
-- check dimensions
assert(inner_width > 0, "graphics.elements.tiling: inner_width <= 0")
assert(inner_height > 0, "graphics.elements.tiling: inner_height <= 0")
assert(start_x <= inner_width, "graphics.elements.tiling: start_x > inner_width")
assert(start_y <= inner_height, "graphics.elements.tiling: start_y > inner_height")
assert(inner_width > 0, "tiling: inner_width <= 0")
assert(inner_height > 0, "tiling: inner_height <= 0")
assert(start_x <= inner_width, "tiling: start_x > inner_width")
assert(start_y <= inner_height, "tiling: start_y > inner_height")
-- create pattern
-- draw tiling box
function e.redraw()
local alternator = true
if args.border_c ~= nil then
e.w_set_bkg(args.border_c)
e.window.clear()
end
-- draw pattern
for y = start_y, inner_height + (start_y - 1) do
e.w_set_cur(start_x, y)
for _ = 1, inner_width do
@ -81,6 +84,10 @@ local function tiling(args)
if inner_width % 2 == 0 then alternator = not alternator end
end
end
-- initial draw
e.redraw()
return e.complete()
end