mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
parent
285026c1fa
commit
8ea75b9501
@ -1,36 +1,58 @@
|
|||||||
local log = require("scada-common.log")
|
local log = require("scada-common.log")
|
||||||
local util = require("scada-common.util")
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local displaybox = require("graphics.elements.displaybox")
|
||||||
|
local structs = require("graphics.structs")
|
||||||
|
|
||||||
local renderer = {}
|
local renderer = {}
|
||||||
|
|
||||||
|
local gconf = {
|
||||||
|
-- root boxes
|
||||||
|
root = {
|
||||||
|
fgd = colors.black,
|
||||||
|
bkg = colors.lightGray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- render engine
|
||||||
local engine = {
|
local engine = {
|
||||||
monitors = nil,
|
monitors = nil,
|
||||||
dmesg_window = nil
|
dmesg_window = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
---@param monitors monitors_struct
|
-- UI elements
|
||||||
function renderer.set_displays(monitors)
|
local ui = {
|
||||||
engine.monitors = monitors
|
main_box = nil,
|
||||||
end
|
unit_boxes = {}
|
||||||
|
}
|
||||||
|
|
||||||
function renderer.reset()
|
-- reset a display to the "default", but set text scale to 0.5
|
||||||
-- reset primary monitor
|
local function _reset_display(monitor)
|
||||||
engine.monitors.primary.setTextScale(0.5)
|
|
||||||
engine.monitors.primary.setTextColor(colors.white)
|
|
||||||
engine.monitors.primary.setBackgroundColor(colors.black)
|
|
||||||
engine.monitors.primary.clear()
|
|
||||||
engine.monitors.primary.setCursorPos(1, 1)
|
|
||||||
|
|
||||||
-- reset unit displays
|
|
||||||
for _, monitor in pairs(engine.monitors.unit_displays) do
|
|
||||||
monitor.setTextScale(0.5)
|
monitor.setTextScale(0.5)
|
||||||
monitor.setTextColor(colors.white)
|
monitor.setTextColor(colors.white)
|
||||||
monitor.setBackgroundColor(colors.black)
|
monitor.setBackgroundColor(colors.black)
|
||||||
monitor.clear()
|
monitor.clear()
|
||||||
monitor.setCursorPos(1, 1)
|
monitor.setCursorPos(1, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- link to the monitor peripherals
|
||||||
|
---@param monitors monitors_struct
|
||||||
|
function renderer.set_displays(monitors)
|
||||||
|
engine.monitors = monitors
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- reset all displays in use by the renderer
|
||||||
|
function renderer.reset()
|
||||||
|
-- reset primary monitor
|
||||||
|
_reset_display(engine.monitors.primary)
|
||||||
|
|
||||||
|
-- reset unit displays
|
||||||
|
for _, monitor in pairs(engine.monitors.unit_displays) do
|
||||||
|
_reset_display(monitor)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- initialize the dmesg output window
|
||||||
function renderer.init_dmesg()
|
function renderer.init_dmesg()
|
||||||
local disp_x, disp_y = engine.monitors.primary.getSize()
|
local disp_x, disp_y = engine.monitors.primary.getSize()
|
||||||
engine.dmesg_window = window.create(engine.monitors.primary, 1, 1, disp_x, disp_y)
|
engine.dmesg_window = window.create(engine.monitors.primary, 1, 1, disp_x, disp_y)
|
||||||
@ -38,4 +60,22 @@ function renderer.init_dmesg()
|
|||||||
log.direct_dmesg(engine.dmesg_window)
|
log.direct_dmesg(engine.dmesg_window)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- start the coordinator GUI
|
||||||
|
function renderer.start_ui()
|
||||||
|
local palette = structs.graphics.cpair(gconf.root.fgd, gconf.root.bkg)
|
||||||
|
|
||||||
|
ui.main_box = displaybox{window = engine.monitors.primary, fg_bg = palette}
|
||||||
|
|
||||||
|
for _, monitor in pairs(engine.monitors.unit_displays) do
|
||||||
|
table.insert(ui.unit_boxes, displaybox{window = engine.monitors.primary, fg_bg = palette})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- close out the UI
|
||||||
|
function renderer.close_ui()
|
||||||
|
-- clear root UI elements
|
||||||
|
ui.main_box = nil
|
||||||
|
ui.unit_boxes = {}
|
||||||
|
end
|
||||||
|
|
||||||
return renderer
|
return renderer
|
||||||
|
@ -12,7 +12,7 @@ local config = require("coordinator.config")
|
|||||||
local coordinator = require("coordinator.coordinator")
|
local coordinator = require("coordinator.coordinator")
|
||||||
local renderer = require("coordinator.renderer")
|
local renderer = require("coordinator.renderer")
|
||||||
|
|
||||||
local COORDINATOR_VERSION = "alpha-v0.1.4"
|
local COORDINATOR_VERSION = "alpha-v0.1.5"
|
||||||
|
|
||||||
local print = util.print
|
local print = util.print
|
||||||
local println = util.println
|
local println = util.println
|
||||||
@ -81,3 +81,12 @@ if modem == nil then
|
|||||||
end
|
end
|
||||||
|
|
||||||
log.dmesg("wireless modem connected", "COMMS", colors.purple)
|
log.dmesg("wireless modem connected", "COMMS", colors.purple)
|
||||||
|
|
||||||
|
log.dmesg("starting UI...", "GRAPHICS", colors.green)
|
||||||
|
util.psleep(3)
|
||||||
|
|
||||||
|
local ui_ok = pcall(renderer.start_ui)
|
||||||
|
if not ui_ok then
|
||||||
|
renderer.close_ui()
|
||||||
|
log.dmesg("UI draw failed", "GRAPHICS", colors.green)
|
||||||
|
end
|
||||||
|
73
graphics/core.lua
Normal file
73
graphics/core.lua
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
local core = {}
|
||||||
|
|
||||||
|
local events = {}
|
||||||
|
|
||||||
|
---@class monitor_touch
|
||||||
|
---@field monitor string
|
||||||
|
---@field x integer
|
||||||
|
---@field y integer
|
||||||
|
|
||||||
|
---@param monitor string
|
||||||
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
---@return monitor_touch
|
||||||
|
function events.touch(monitor, x, y)
|
||||||
|
return {
|
||||||
|
monitor = monitor,
|
||||||
|
x = x,
|
||||||
|
y = y
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
core.events = events
|
||||||
|
|
||||||
|
local graphics = {}
|
||||||
|
|
||||||
|
---@alias TEXT_ALIGN integer
|
||||||
|
graphics.TEXT_ALIGN = {
|
||||||
|
LEFT = 1,
|
||||||
|
CENTER = 2,
|
||||||
|
RIGHT = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
---@class graphics_frame
|
||||||
|
---@field x integer
|
||||||
|
---@field y integer
|
||||||
|
---@field w integer
|
||||||
|
---@field h integer
|
||||||
|
|
||||||
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
---@param w integer
|
||||||
|
---@param h integer
|
||||||
|
---@return graphics_frame
|
||||||
|
function graphics.gframe(x, y, w, h)
|
||||||
|
return {
|
||||||
|
x = x,
|
||||||
|
y = y,
|
||||||
|
w = w,
|
||||||
|
h = h
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class cpair
|
||||||
|
---@field fgd color
|
||||||
|
---@field bkg color
|
||||||
|
---@field blit_fgd string
|
||||||
|
---@field blit_bkg string
|
||||||
|
|
||||||
|
---@param foreground color
|
||||||
|
---@param background color
|
||||||
|
---@return cpair
|
||||||
|
function graphics.cpair(foreground, background)
|
||||||
|
return {
|
||||||
|
fgd = foreground,
|
||||||
|
bkg = background,
|
||||||
|
blit_fgd = colors.toBlit(foreground),
|
||||||
|
blit_bkg = colors.toBlit(background)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
core.graphics = graphics
|
||||||
|
|
||||||
|
return core
|
124
graphics/element.lua
Normal file
124
graphics/element.lua
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
local core = require("graphics.core")
|
||||||
|
|
||||||
|
local element = {}
|
||||||
|
|
||||||
|
---@class graphics_args_generic
|
||||||
|
---@field window? table
|
||||||
|
---@field parent? graphics_element
|
||||||
|
---@field x? integer 1 if omitted
|
||||||
|
---@field y? integer 1 if omitted
|
||||||
|
---@field width? integer parent width if omitted
|
||||||
|
---@field height? integer parent height if omitted
|
||||||
|
---@field gframe? graphics_frame frame instead of x/y/width/height
|
||||||
|
---@field fg_bg? cpair foreground/background colors
|
||||||
|
|
||||||
|
-- a base graphics element, should not be created on its own
|
||||||
|
---@param args graphics_args_generic arguments
|
||||||
|
function element.new(args)
|
||||||
|
local self = {
|
||||||
|
p_window = nil, ---@type table
|
||||||
|
position = { x = 1, y = 1 },
|
||||||
|
bounds = { x1 = 1, y1 = 1, x2 = 1, y2 = 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
local protected = {
|
||||||
|
window = nil, ---@type table
|
||||||
|
frame = core.graphics.gframe(1, 1, 1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
-- SETUP --
|
||||||
|
|
||||||
|
-- get the parent window
|
||||||
|
self.p_window = args.window or args.parent.window()
|
||||||
|
|
||||||
|
assert(self.p_window, "graphics.element: no parent window provided")
|
||||||
|
|
||||||
|
-- get frame coordinates/size
|
||||||
|
if args.gframe ~= nil then
|
||||||
|
protected.frame.x = args.gframe.x
|
||||||
|
protected.frame.y = args.gframe.y
|
||||||
|
protected.frame.w = args.gframe.w
|
||||||
|
protected.frame.h = args.gframe.h
|
||||||
|
else
|
||||||
|
local w, h = self.p_window.getSize()
|
||||||
|
protected.frame.x = args.x or 1
|
||||||
|
protected.frame.y = args.y or 1
|
||||||
|
protected.frame.w = args.width or w
|
||||||
|
protected.frame.h = args.height or h
|
||||||
|
end
|
||||||
|
|
||||||
|
-- create window
|
||||||
|
local f = protected.frame
|
||||||
|
protected.window = window.create(self.p_window, f.x, f.y, f.w, f.h, true)
|
||||||
|
|
||||||
|
-- init display box
|
||||||
|
if args.fg_bg ~= nil then
|
||||||
|
protected.window.setBackgroundColor(args.fg_bg.bkg)
|
||||||
|
protected.window.setTextColor(args.fg_bg.fgd)
|
||||||
|
protected.window.clear()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- record position
|
||||||
|
self.position.x, self.position.y = protected.window.getPosition()
|
||||||
|
|
||||||
|
-- calculate bounds
|
||||||
|
self.bounds.x1 = self.position.x
|
||||||
|
self.bounds.x2 = self.position.x + f.w - 1
|
||||||
|
self.bounds.y1 = self.position.y
|
||||||
|
self.bounds.y2 = self.position.y + f.h - 1
|
||||||
|
|
||||||
|
-- PROTECTED FUNCTIONS --
|
||||||
|
|
||||||
|
-- handle a touch event
|
||||||
|
---@param event table monitor_touch event
|
||||||
|
function protected.handle_touch(event)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle data value changes
|
||||||
|
function protected.on_update(...)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@class graphics_element
|
||||||
|
local public = {}
|
||||||
|
|
||||||
|
-- get public interface
|
||||||
|
function protected.get() return public end
|
||||||
|
|
||||||
|
-- PUBLIC FUNCTIONS --
|
||||||
|
|
||||||
|
-- get the window object
|
||||||
|
function public.window() return protected.window end
|
||||||
|
|
||||||
|
-- handle a monitor touch
|
||||||
|
---@param event monitor_touch monitor touch event
|
||||||
|
function public.handle_touch(event)
|
||||||
|
local in_x = event.x >= self.bounds.x1 and event.x <= self.bounds.x2
|
||||||
|
local in_y = event.y >= self.bounds.y1 and event.y <= self.bounds.y2
|
||||||
|
|
||||||
|
if in_x and in_y then
|
||||||
|
-- handle the touch event, transformed into the window frame
|
||||||
|
protected.handle_touch(core.events.touch(event.monitor,
|
||||||
|
(event.x - self.position.x) + 1,
|
||||||
|
(event.y - self.position.y) + 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- draw the element given new data
|
||||||
|
function public.draw(...)
|
||||||
|
protected.on_update(...)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- show the element
|
||||||
|
function public.show()
|
||||||
|
protected.window.setVisible(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- hide the element
|
||||||
|
function public.hide()
|
||||||
|
protected.window.setVisible(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
return protected
|
||||||
|
end
|
||||||
|
|
||||||
|
return element
|
21
graphics/elements/displaybox.lua
Normal file
21
graphics/elements/displaybox.lua
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
-- Root Display Box Graphics Element
|
||||||
|
|
||||||
|
local element = require("graphics.element")
|
||||||
|
|
||||||
|
---@class displaybox_args
|
||||||
|
---@field window table
|
||||||
|
---@field x? integer 1 if omitted
|
||||||
|
---@field y? integer 1 if omitted
|
||||||
|
---@field width? integer parent width if omitted
|
||||||
|
---@field height? integer parent height if omitted
|
||||||
|
---@field gframe? graphics_frame frame instead of x/y/width/height
|
||||||
|
---@field fg_bg? cpair foreground/background colors
|
||||||
|
|
||||||
|
-- new root display box
|
||||||
|
---@param args displaybox_args
|
||||||
|
local function displaybox(args)
|
||||||
|
-- create new graphics element base object
|
||||||
|
return element.new(args).get()
|
||||||
|
end
|
||||||
|
|
||||||
|
return displaybox
|
74
graphics/elements/textbox.lua
Normal file
74
graphics/elements/textbox.lua
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
-- Text Box Graphics Element
|
||||||
|
|
||||||
|
local element = require("graphics.element")
|
||||||
|
|
||||||
|
---@class textbox_args
|
||||||
|
---@field text string text to show
|
||||||
|
---@field parent graphics_element
|
||||||
|
---@field x? integer 1 if omitted
|
||||||
|
---@field y? integer 1 if omitted
|
||||||
|
---@field width? integer parent width if omitted
|
||||||
|
---@field height? integer parent height if omitted
|
||||||
|
---@field gframe? graphics_frame frame instead of x/y/width/height
|
||||||
|
---@field fg_bg? cpair foreground/background colors
|
||||||
|
|
||||||
|
-- new text box
|
||||||
|
---@param args textbox_args
|
||||||
|
local function textbox(args)
|
||||||
|
assert(args.text ~= nil, "graphics.elements.textbox: empty text box")
|
||||||
|
|
||||||
|
-- create new graphics element base object
|
||||||
|
local e = element.new(args)
|
||||||
|
|
||||||
|
-- write text
|
||||||
|
|
||||||
|
local text = args.text
|
||||||
|
local lines = { text }
|
||||||
|
|
||||||
|
local w = e.frame.w
|
||||||
|
local h = e.frame.h
|
||||||
|
|
||||||
|
-- wrap if needed
|
||||||
|
if string.len(text) > w then
|
||||||
|
local remaining = true
|
||||||
|
local s_start = 1
|
||||||
|
local s_end = w
|
||||||
|
local i = 1
|
||||||
|
|
||||||
|
lines = {}
|
||||||
|
|
||||||
|
while remaining do
|
||||||
|
local line = string.sub(text, s_start, s_end)
|
||||||
|
|
||||||
|
if line == "" then
|
||||||
|
remaining = false
|
||||||
|
else
|
||||||
|
lines[i] = line
|
||||||
|
|
||||||
|
s_start = s_end + 1
|
||||||
|
s_end = s_end + w
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- output message
|
||||||
|
for i = 1, #lines do
|
||||||
|
local cur_x, cur_y = e.window.getCursorPos()
|
||||||
|
|
||||||
|
if i > 1 and cur_x > 1 then
|
||||||
|
if cur_y == h then
|
||||||
|
e.window.scroll(1)
|
||||||
|
e.window.setCursorPos(1, cur_y)
|
||||||
|
else
|
||||||
|
e.window.setCursorPos(1, cur_y + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
e.window.write(lines[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
return e.get()
|
||||||
|
end
|
||||||
|
|
||||||
|
return textbox
|
Loading…
Reference in New Issue
Block a user