#243 graphics core updates for content windows, redrawing, and handling of addition/removal of children

This commit is contained in:
Mikayla Fischler 2023-05-30 19:51:10 -04:00
parent 270726e276
commit de9cb3bd3a
41 changed files with 113 additions and 78 deletions

View File

@ -20,7 +20,7 @@ local sounder = require("coordinator.sounder")
local apisessions = require("coordinator.session.apisessions")
local COORDINATOR_VERSION = "v0.15.3"
local COORDINATOR_VERSION = "v0.15.4"
local println = util.println
local println_ts = util.println_ts

View File

@ -33,7 +33,7 @@ local period = core.flasher.PERIOD
---@param x integer top left x
---@param y integer top left y
local function new_view(root, x, y)
assert(root.height() >= (y + 24), "main display not of sufficient vertical resolution (add an additional row of monitors)")
assert(root.get_height() >= (y + 24), "main display not of sufficient vertical resolution (add an additional row of monitors)")
local facility = iocontrol.get_db().facility
local units = iocontrol.get_db().units

View File

@ -38,7 +38,7 @@ local function make(parent, x, y, unit)
height = 17
end
assert(parent.height() >= (y + height), "main display not of sufficient vertical resolution (add an additional row of monitors)")
assert(parent.get_height() >= (y + height), "main display not of sufficient vertical resolution (add an additional row of monitors)")
-- bounding box div
local root = Div{parent=parent,x=x,y=y,width=80,height=height}

View File

@ -32,7 +32,7 @@ local function init(main)
local header = TextBox{parent=main,y=1,text="Nuclear Generation Facility SCADA Coordinator",alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=style.header}
local ping = DataIndicator{parent=main,x=1,y=1,label="SVTT",format="%d",value=0,unit="ms",lu_colors=cpair(colors.lightGray, colors.white),width=12,fg_bg=style.header}
-- max length example: "01:23:45 AM - Wednesday, September 28 2022"
local datetime = TextBox{parent=main,x=(header.width()-42),y=1,text="",alignment=TEXT_ALIGN.RIGHT,width=42,height=1,fg_bg=style.header}
local datetime = TextBox{parent=main,x=(header.get_width()-42),y=1,text="",alignment=TEXT_ALIGN.RIGHT,width=42,height=1,fg_bg=style.header}
ping.register(facility.ps, "sv_ping", ping.update)
datetime.register(facility.ps, "date_time", datetime.set_value)
@ -45,12 +45,12 @@ local function init(main)
-- unit overviews
if facility.num_units >= 1 then
uo_1 = unit_overview(main, 2, 3, units[1])
row_1_height = uo_1.height()
row_1_height = uo_1.get_height()
end
if facility.num_units >= 2 then
uo_2 = unit_overview(main, 84, 3, units[2])
row_1_height = math.max(row_1_height, uo_2.height())
row_1_height = math.max(row_1_height, uo_2.get_height())
end
cnc_y_start = cnc_y_start + row_1_height + 1
@ -60,11 +60,11 @@ local function init(main)
local row_2_offset = cnc_y_start
uo_3 = unit_overview(main, 2, row_2_offset, units[3])
cnc_y_start = row_2_offset + uo_3.height() + 1
cnc_y_start = row_2_offset + uo_3.get_height() + 1
if facility.num_units == 4 then
uo_4 = unit_overview(main, 84, row_2_offset, units[4])
cnc_y_start = math.max(cnc_y_start, row_2_offset + uo_4.height() + 1)
cnc_y_start = math.max(cnc_y_start, row_2_offset + uo_4.get_height() + 1)
end
end
@ -73,11 +73,11 @@ local function init(main)
cnc_y_start = cnc_y_start
-- induction matrix and process control interfaces are 24 tall + space needed for divider
local cnc_bottom_align_start = main.height() - 26
local cnc_bottom_align_start = main.get_height() - 26
assert(cnc_bottom_align_start >= cnc_y_start, "main display not of sufficient vertical resolution (add an additional row of monitors)")
TextBox{parent=main,y=cnc_bottom_align_start,text=util.strrep("\x8c", header.width()),alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=cpair(colors.lightGray,colors.gray)}
TextBox{parent=main,y=cnc_bottom_align_start,text=util.strrep("\x8c", header.get_width()),alignment=TEXT_ALIGN.CENTER,height=1,fg_bg=cpair(colors.lightGray,colors.gray)}
cnc_bottom_align_start = cnc_bottom_align_start + 2

View File

@ -68,21 +68,22 @@ function element.new(args)
define_completed = false,
p_window = nil, ---@type table
position = { x = 1, y = 1 }, ---@type coordinate_2d
child_offset = { x = 0, y = 0 },
child_offset = { x = 0, y = 0 }, ---@type coordinate_2d
bounds = { x1 = 1, y1 = 1, x2 = 1, y2 = 1 }, ---@class element_bounds
next_y = 1,
children = {},
subscriptions = {},
mt = {}
}
---@class graphics_template
---@class graphics_base
local protected = {
enabled = true,
value = nil, ---@type any
window = nil, ---@type table
value = nil, ---@type any
window = nil, ---@type table
content_window = nil, ---@type table|nil
fg_bg = core.cpair(colors.white, colors.black),
frame = core.gframe(1, 1, 1, 1)
frame = core.gframe(1, 1, 1, 1),
children = {}
}
local name_brief = "graphics.element{" .. self.elem_type .. "}: "
@ -199,15 +200,15 @@ function element.new(args)
-- luacheck: push ignore
---@diagnostic disable: unused-local, unused-vararg
-- dynamically insert a child element
-- handle a child element having been added
---@param id string|integer element identifier
---@param elem graphics_element element
function protected.insert(id, elem)
---@param child graphics_element child element
function protected.on_added(id, child)
end
-- dynamically remove a child element
-- handle a child element having been removed
---@param id string|integer element identifier
function protected.remove(id)
function protected.on_removed(id)
end
-- handle a mouse event
@ -280,6 +281,14 @@ function element.new(args)
---@return graphics_element element, element_id id
function protected.get() return public, self.id end
-- report completion of element instantiation and get the public interface
---@nodiscard
---@return graphics_element element, element_id id
function protected.complete()
if args.parent ~= nil then args.parent.__child_ready(self.id, public) end
return public, self.id
end
-----------
-- SETUP --
-----------
@ -306,11 +315,19 @@ function element.new(args)
-- get the window object
---@nodiscard
function public.window() return protected.window end
function public.window() return protected.content_window or protected.window end
-- delete this element (hide and unsubscribe from PSIL)
function public.delete()
-- hide + stop animations
-- grab parent fg/bg so we can clear cleanly
if args.parent ~= nil then
local fg_bg = args.parent.get_fg_bg()
protected.window.setBackgroundColor(fg_bg.bkg)
protected.window.setTextColor(fg_bg.fgd)
end
-- clear, hide, and stop animations
protected.window.clear()
public.hide()
-- unsubscribe from PSIL
@ -320,9 +337,9 @@ function element.new(args)
end
-- delete all children
for k, v in pairs(self.children) do
for k, v in pairs(protected.children) do
v.delete()
self.children[k] = nil
protected.children[k] = nil
end
end
@ -331,7 +348,7 @@ function element.new(args)
-- add a child element
---@nodiscard
---@param key string|nil id
---@param child graphics_template
---@param child graphics_base
---@return integer|string key
function public.__add_child(key, child)
-- offset first automatic placement
@ -346,26 +363,34 @@ function element.new(args)
local child_element = child.get()
if key == nil then
table.insert(self.children, child_element)
return #self.children
table.insert(protected.children, child_element)
return #protected.children
else
self.children[key] = child_element
protected.children[key] = child_element
return key
end
end
-- actions to take upon a child element becoming ready (initial draw/construction completed)
---@param key string|integer id
---@param child graphics_element
function public.__child_ready(key, child)
protected.on_added(key, child)
end
-- get a child element
---@nodiscard
---@param id element_id
---@return graphics_element
function public.get_child(id) return self.children[id] end
function public.get_child(id) return protected.children[id] end
-- remove a child element
---@param id element_id
function public.remove(id)
if self.children[id] ~= nil then
self.children[id].delete()
self.children[id] = nil
if protected.children[id] ~= nil then
protected.children[id].delete()
protected.children[id] = nil
protected.on_removed(id)
end
end
@ -374,13 +399,13 @@ function element.new(args)
---@param id element_id
---@return graphics_element|nil element
function public.get_element_by_id(id)
if self.children[id] == nil then
for _, child in pairs(self.children) do
if protected.children[id] == nil then
for _, child in pairs(protected.children) do
local elem = child.get_element_by_id(id)
if elem ~= nil then return elem end
end
else
return self.children[id]
return protected.children[id]
end
return nil
@ -419,14 +444,14 @@ function element.new(args)
-- get element width
---@nodiscard
---@return integer width
function public.width()
function public.get_width()
return protected.frame.w
end
-- get element height
---@nodiscard
---@return integer height
function public.height()
function public.get_height()
return protected.frame.h
end
@ -501,7 +526,7 @@ function element.new(args)
-- handle the mouse event then pass to children
protected.handle_mouse(event_T)
for _, child in pairs(self.children) do child.handle_mouse(event_T) end
for _, child in pairs(protected.children) do child.handle_mouse(event_T) end
end
end
@ -536,7 +561,9 @@ function element.new(args)
if animate ~= false then public.animate_all() end
end
-- hide the element and disables animations
-- hide the element and disables animations<br>
-- this alone does not cause an element to be fully hidden, it only prevents updates from being shown<br>
---@see graphics_element.content_redraw
function public.hide()
public.freeze_all() -- stop animations for efficiency/performance
protected.window.setVisible(false)
@ -552,7 +579,7 @@ function element.new(args)
function public.animate_all()
if protected.window.isVisible() then
public.animate()
for _, child in pairs(self.children) do child.animate_all() end
for _, child in pairs(protected.children) do child.animate_all() end
end
end
@ -564,7 +591,7 @@ function element.new(args)
-- freeze animation(s) for this element and all its children
function public.freeze_all()
public.freeze()
for _, child in pairs(self.children) do child.freeze_all() end
for _, child in pairs(protected.children) do child.freeze_all() end
end
-- re-draw the element
@ -572,6 +599,14 @@ function element.new(args)
protected.window.redraw()
end
-- if a content window is set, clears it then re-draws all children
function public.content_redraw()
if protected.content_window ~= nil then
protected.content_window.clear()
for _, child in pairs(protected.children) do child.redraw() end
end
end
return protected
end

View File

@ -103,7 +103,7 @@ local function waiting(args)
e.start_anim()
return e.get()
return e.complete()
end
return waiting

View File

@ -28,7 +28,7 @@ local function colormap(args)
e.window.setCursorPos(1, 1)
e.window.blit(spaces, bkg, bkg)
return e.get()
return e.complete()
end
return colormap

View File

@ -199,7 +199,7 @@ local function hazard_button(args)
-- initial draw of border
draw_border(args.accent)
return e.get()
return e.complete()
end
return hazard_button

View File

@ -131,7 +131,7 @@ local function multi_button(args)
-- initial draw
draw()
return e.get()
return e.complete()
end
return multi_button

View File

@ -121,7 +121,7 @@ local function push_button(args)
-- initial draw
draw()
return e.get()
return e.complete()
end
return push_button

View File

@ -104,7 +104,7 @@ local function radio_button(args)
-- initial draw
draw()
return e.get()
return e.complete()
end
return radio_button

View File

@ -116,7 +116,7 @@ local function sidebar(args)
-- initial draw
draw(false)
return e.get()
return e.complete()
end
return sidebar

View File

@ -189,7 +189,7 @@ local function spinbox(args)
e.value = 0
set_digits()
return e.get()
return e.complete()
end
return spinbox

View File

@ -87,7 +87,7 @@ local function switch_button(args)
draw_state()
end
return e.get()
return e.complete()
end
return switch_button

View File

@ -125,7 +125,7 @@ local function tabbar(args)
-- initial draw
draw()
return e.get()
return e.complete()
end
return tabbar

View File

@ -17,7 +17,7 @@ local element = require("graphics.element")
---@param args displaybox_args
local function displaybox(args)
-- create new graphics element base object
return element.new(args).get()
return element.new(args).complete()
end
return displaybox

View File

@ -19,7 +19,7 @@ local element = require("graphics.element")
---@return graphics_element element, element_id id
local function div(args)
-- create new graphics element base object
return element.new(args).get()
return element.new(args).complete()
end
return div

View File

@ -109,7 +109,7 @@ local function alarm_indicator_light(args)
e.on_update(1)
e.window.write(args.label)
return e.get()
return e.complete()
end
return alarm_indicator_light

View File

@ -163,7 +163,7 @@ local function core_map(args)
-- initial draw
e.on_update(0)
return e.get()
return e.complete()
end
return core_map

View File

@ -97,7 +97,7 @@ local function data(args)
-- initial value draw
e.on_update(args.value)
return e.get()
return e.complete()
end
return data

View File

@ -120,7 +120,7 @@ local function hbar(args)
-- initialize to 0
e.on_update(0)
return e.get()
return e.complete()
end
return hbar

View File

@ -69,7 +69,7 @@ local function icon(args)
-- initial icon draw
e.on_update(args.value or 1)
return e.get()
return e.complete()
end
return icon

View File

@ -95,7 +95,7 @@ local function indicator_led(args)
e.window.write(args.label)
end
return e.get()
return e.complete()
end
return indicator_led

View File

@ -109,7 +109,7 @@ local function indicator_led_pair(args)
e.window.write(args.label)
end
return e.get()
return e.complete()
end
return indicator_led_pair

View File

@ -54,7 +54,7 @@ local function indicator_led_rgb(args)
e.window.write(args.label)
end
return e.get()
return e.complete()
end
return indicator_led_rgb

View File

@ -93,7 +93,7 @@ local function indicator_light(args)
e.window.setCursorPos(3, 1)
e.window.write(args.label)
return e.get()
return e.complete()
end
return indicator_light

View File

@ -80,7 +80,7 @@ local function power(args)
-- initial value draw
e.on_update(args.value)
return e.get()
return e.complete()
end
return power

View File

@ -85,7 +85,7 @@ local function rad(args)
-- initial value draw
e.on_update(types.new_zero_radiation_reading())
return e.get()
return e.complete()
end
return rad

View File

@ -75,7 +75,7 @@ local function state_indicator(args)
-- initial draw
e.on_update(args.value or 1)
return e.get()
return e.complete()
end
return state_indicator

View File

@ -106,7 +106,7 @@ local function tristate_indicator_light(args)
e.on_update(1)
e.window.write(args.label)
return e.get()
return e.complete()
end
return tristate_indicator_light

View File

@ -100,7 +100,7 @@ local function vbar(args)
---@param val number 0.0 to 1.0
function e.set_value(val) e.on_update(val) end
return e.get()
return e.complete()
end
return vbar

View File

@ -37,7 +37,7 @@ local function multipane(args)
e.set_value(1)
return e.get()
return e.complete()
end
return multipane

View File

@ -142,7 +142,7 @@ local function pipenet(args)
end
return e.get()
return e.complete()
end
return pipenet

View File

@ -178,7 +178,7 @@ local function rectangle(args)
end
end
return e.get()
return e.complete()
end
return rectangle

View File

@ -65,7 +65,7 @@ local function textbox(args)
display_text(val)
end
return e.get()
return e.complete()
end
return textbox

View File

@ -82,7 +82,7 @@ local function tiling(args)
if inner_width % 2 == 0 then alternator = not alternator end
end
return e.get()
return e.complete()
end
return tiling

View File

@ -17,7 +17,7 @@ local coreio = require("pocket.coreio")
local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer")
local POCKET_VERSION = "alpha-v0.3.3"
local POCKET_VERSION = "alpha-v0.3.4"
local println = util.println
local println_ts = util.println_ts

View File

@ -25,7 +25,7 @@ local function init(parent, y, is_api)
-- bounding box div
local box = Div{parent=root,x=1,y=y,height=5}
local waiting_x = math.floor(parent.width() / 2) - 1
local waiting_x = math.floor(parent.get_width() / 2) - 1
if is_api then
WaitingAnim{parent=box,x=waiting_x,y=1,fg_bg=cpair(colors.blue,style.root.bkg)}

View File

@ -18,7 +18,7 @@ local plc = require("reactor-plc.plc")
local renderer = require("reactor-plc.renderer")
local threads = require("reactor-plc.threads")
local R_PLC_VERSION = "v1.3.3"
local R_PLC_VERSION = "v1.3.4"
local println = util.println
local println_ts = util.println_ts

View File

@ -28,7 +28,7 @@ local sna_rtu = require("rtu.dev.sna_rtu")
local sps_rtu = require("rtu.dev.sps_rtu")
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
local RTU_VERSION = "v1.2.3"
local RTU_VERSION = "v1.2.4"
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE

View File

@ -19,7 +19,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions")
local SUPERVISOR_VERSION = "v0.16.3"
local SUPERVISOR_VERSION = "v0.16.4"
local println = util.println
local println_ts = util.println_ts