diff --git a/graphics/core.lua b/graphics/core.lua index fe3b291..d42af53 100644 --- a/graphics/core.lua +++ b/graphics/core.lua @@ -124,10 +124,10 @@ end -- Interactive Field Manager ---@param e graphics_base element ----@param max_len any max value length ----@param fg_bg any enabled fg/bg ----@param dis_fg_bg any disabled fg/bg ----@param align_right any true to align content right while unfocused +---@param max_len integer max value length +---@param fg_bg cpair enabled fg/bg +---@param dis_fg_bg? cpair disabled fg/bg +---@param align_right? boolean true to align content right while unfocused function core.new_ifield(e, max_len, fg_bg, dis_fg_bg, align_right) local self = { frame_start = 1, diff --git a/graphics/element.lua b/graphics/element.lua index 1e94edd..402387b 100644 --- a/graphics/element.lua +++ b/graphics/element.lua @@ -11,8 +11,8 @@ local events = core.events local element = {} ----@class graphics_args_generic ----@field window? table +---@class graphics_args +---@field window? Window ---@field parent? graphics_element ---@field id? string element id ---@field x? integer 1 if omitted @@ -24,47 +24,6 @@ local element = {} ---@field hidden? boolean true to hide on initial draw ---@field can_focus? boolean true if this element can be focused, false by default ----@alias graphics_args graphics_args_generic ----|waiting_args ----|app_button_args ----|checkbox_args ----|hazard_button_args ----|multi_button_args ----|push_button_args ----|radio_2d_args ----|radio_button_args ----|sidebar_args ----|spinbox_args ----|switch_button_args ----|tabbar_args ----|number_field_args ----|text_field_args ----|alarm_indicator_light ----|core_map_args ----|data_indicator_args ----|hbar_args ----|icon_indicator_args ----|indicator_led_args ----|indicator_led_pair_args ----|indicator_led_rgb_args ----|indicator_light_args ----|power_indicator_args ----|rad_indicator_args ----|signal_bar_args ----|state_indicator_args ----|tristate_indicator_light_args ----|vbar_args ----|app_multipane_args ----|colormap_args ----|displaybox_args ----|div_args ----|listbox_args ----|multipane_args ----|pipenet_args ----|rectangle_args ----|textbox_args ----|tiling_args - ---@class element_subscription ---@field ps psil ps used ---@field key string data key @@ -92,14 +51,14 @@ function element.new(args, constraint, child_offset_x, child_offset_y) is_root = args.parent == nil, elem_type = debug.getinfo(2).name, define_completed = false, - p_window = nil, ---@type table + p_window = nil, ---@type Window position = events.new_coord_2d(1, 1), bounds = { x1 = 1, y1 = 1, x2 = 1, y2 = 1 }, ---@class element_bounds offset_x = 0, offset_y = 0, next_y = 1, -- next child y coordinate - next_id = 0, -- next child ID - subscriptions = {}, + next_id = 0, -- next child ID[ + subscriptions = {}, ---@type { ps: psil, key: string, func: function }[] button_down = { events.new_coord_2d(-1, -1), events.new_coord_2d(-1, -1), events.new_coord_2d(-1, -1) }, focused = false, mt = {} @@ -109,13 +68,13 @@ function element.new(args, constraint, child_offset_x, child_offset_y) local protected = { enabled = true, value = nil, ---@type any - window = nil, ---@type table - content_window = nil, ---@type table|nil + window = nil, ---@type Window + content_window = nil, ---@type Window|nil mouse_window_shift = { x = 0, y = 0 }, fg_bg = core.cpair(colors.white, colors.black), frame = core.gframe(1, 1, 1, 1), - children = {}, - child_id_map = {} + children = {}, ---@type graphics_base[] + child_id_map = {} ---@type { [element_id]: integer } } -- element as string @@ -168,10 +127,10 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end end - ---@param children table + ---@param children graphics_base[] local function traverse(children) for i = 1, #children do - local child = children[i] ---@type graphics_base + local child = children[i] handle_element(child.get()) if child.get().is_visible() then traverse(child.children) end end @@ -286,24 +245,29 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- alias functions - -- window set cursor position + -- window set cursor position
+ ---@see Window.setCursorPos ---@param x integer ---@param y integer function protected.w_set_cur(x, y) protected.window.setCursorPos(x, y) end - -- set background color + -- set background color
+ ---@see Window.setBackgroundColor ---@param c color function protected.w_set_bkg(c) protected.window.setBackgroundColor(c) end - -- set foreground (text) color + -- set foreground (text) color
+ ---@see Window.setTextColor ---@param c color function protected.w_set_fgd(c) protected.window.setTextColor(c) end - -- write text + -- write text
+ ---@see Window.write ---@param str string function protected.w_write(str) protected.window.write(str) end - -- blit text + -- blit text
+ ---@see Window.blit ---@param str string ---@param fg string ---@param bg string @@ -335,8 +299,10 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- report completion of element instantiation and get the public interface ---@nodiscard + ---@param redraw? boolean true to call redraw as part of completing this element ---@return graphics_element element, element_id id - function protected.complete() + function protected.complete(redraw) + if redraw then protected.redraw() end if args.parent ~= nil then args.parent.__child_ready(self.id, public) end return public, self.id end @@ -352,7 +318,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- focus this element and take away focus from all other elements function protected.take_focus() args.parent.__focus_child(public) end - -- action handlers -- + --#region Action Handlers -- luacheck: push ignore ---@diagnostic disable: unused-local, unused-vararg @@ -401,14 +367,15 @@ function element.new(args, constraint, child_offset_x, child_offset_y) function protected.handle_paste(text) end -- handle data value changes - ---@vararg any value(s) + ---@param ... any value(s) function protected.on_update(...) end -- callback on control press responses ---@param result any function protected.response_callback(result) end - -- accessors and control -- + --#endregion + --#region Accessors and Control -- -- get value ---@nodiscard @@ -427,11 +394,11 @@ function element.new(args, constraint, child_offset_x, child_offset_y) function protected.set_max(max) end -- custom recolor command, varies by element if implemented - ---@vararg cpair|color color(s) + ---@param ... cpair|color color(s) function protected.recolor(...) end -- custom resize command, varies by element if implemented - ---@vararg integer sizing + ---@param ... integer sizing function protected.resize(...) end -- luacheck: pop @@ -514,6 +481,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- ELEMENT TREE -- -- add a child element + ---@package ---@nodiscard ---@param key string|nil id ---@param child graphics_base @@ -523,7 +491,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) self.next_y = child.frame.y + child.frame.h - local id = key ---@type string|integer|nil + local id = key ---@type element_id|nil if id == nil then id = self.next_id self.next_id = self.next_id + 1 @@ -537,6 +505,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end -- remove a child element + ---@package ---@param id element_id id function public.__remove_child(id) local index = protected.child_id_map[id] @@ -548,11 +517,13 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end -- actions to take upon a child element becoming ready (initial draw/construction completed) + ---@package ---@param key element_id id ---@param child graphics_element function public.__child_ready(key, child) protected.on_added(key, child) end -- focus solely on this child + ---@package ---@param child graphics_element function public.__focus_child(child) if self.is_root then @@ -562,6 +533,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end -- a child was focused, used to make sure it is actually visible to the user in the content frame + ---@package ---@param child graphics_element function public.__child_focused(child) protected.on_child_focused(child) @@ -571,8 +543,8 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- get a child element ---@nodiscard ---@param id element_id - ---@return graphics_element - function public.get_child(id) return protected.children[protected.child_id_map[id]].get() end + ---@return graphics_element element + function public.get_child(id) return ({ protected.children[protected.child_id_map[id]].get() })[1] end -- get all children ---@nodiscard @@ -619,7 +591,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) local elem = child.get().get_element_by_id(id) if elem ~= nil then return elem end end - else return protected.children[index].get() end + else return ({ protected.children[index].get() })[1] end end -- AUTO-PLACEMENT -- @@ -631,17 +603,17 @@ function element.new(args, constraint, child_offset_x, child_offset_y) -- PROPERTIES -- - -- get element id + -- get element ID ---@nodiscard ---@return element_id function public.get_id() return self.id end - -- get element x + -- get element relative x position ---@nodiscard ---@return integer x function public.get_x() return protected.frame.x end - -- get element y + -- get element relative y position ---@nodiscard ---@return integer y function public.get_y() return protected.frame.y end @@ -661,12 +633,12 @@ function element.new(args, constraint, child_offset_x, child_offset_y) ---@return cpair fg_bg function public.get_fg_bg() return protected.fg_bg end - -- get the element value + -- get the element's value ---@nodiscard ---@return any value function public.get_value() return protected.get_value() end - -- set the element value + -- set the element's value ---@param value any new value function public.set_value(value) protected.set_value(value) end @@ -728,11 +700,11 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end -- custom recolor command, varies by element if implemented - ---@vararg cpair|color color(s) + ---@param ... cpair|color color(s) function public.recolor(...) protected.recolor(...) end -- resize attributes of the element value if supported - ---@vararg number dimensions (element specific) + ---@param ... number dimensions (element specific) function public.resize(...) protected.resize(...) end -- reposition the element window
@@ -818,7 +790,7 @@ function element.new(args, constraint, child_offset_x, child_offset_y) end -- draw the element given new data - ---@vararg any new data + ---@param ... any new data function public.update(...) protected.on_update(...) end -- on a control request response diff --git a/graphics/elements/appmultipane.lua b/graphics/elements/appmultipane.lua index 5973182..948cb32 100644 --- a/graphics/elements/appmultipane.lua +++ b/graphics/elements/appmultipane.lua @@ -24,15 +24,15 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new app multipane element +-- Create a new app multipane container element. ---@nodiscard ---@param args app_multipane_args ----@return graphics_element element, element_id id -local function multipane(args) +---@return AppMultiPane element, element_id id +return function (args) element.assert(type(args.panes) == "table", "panes is a required field") -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 1 @@ -100,10 +100,8 @@ local function multipane(args) end end - -- initial draw - e.redraw() + ---@class AppMultiPane:graphics_element + local AppMultiPane, id = e.complete(true) - return e.complete() + return AppMultiPane, id end - -return multipane diff --git a/graphics/elements/colormap.lua b/graphics/elements/colormap.lua index 7e3554f..1a4b0a7 100644 --- a/graphics/elements/colormap.lua +++ b/graphics/elements/colormap.lua @@ -9,10 +9,10 @@ local element = require("graphics.element") ---@field y? integer auto incremented if omitted ---@field hidden? boolean true to hide on initial draw --- new color map +-- Create a horizontal reference color map. Primarily used for tuning custom colors. ---@param args colormap_args ----@return graphics_element element, element_id id -local function colormap(args) +---@return ColorMap element, element_id id +return function (args) local bkg = "008877FFCCEE114455DD9933BBAA2266" local spaces = string.rep(" ", 32) @@ -20,7 +20,7 @@ local function colormap(args) args.height = 1 -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- draw color map function e.redraw() @@ -28,10 +28,8 @@ local function colormap(args) e.w_blit(spaces, bkg, bkg) end - -- initial draw - e.redraw() + ---@class ColorMap:graphics_element + local ColorMap, id = e.complete(true) - return e.complete() + return ColorMap, id end - -return colormap diff --git a/graphics/elements/displaybox.lua b/graphics/elements/displaybox.lua index 3578a63..ecfe03a 100644 --- a/graphics/elements/displaybox.lua +++ b/graphics/elements/displaybox.lua @@ -13,13 +13,16 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new root display box +-- Create a root display box. ---@nodiscard ---@param args displaybox_args ----@return graphics_element element, element_id id -local function displaybox(args) +---@return DisplayBox element, element_id id +return function (args) -- create new graphics element base object - return element.new(args).complete() -end + local e = element.new(args --[[@as graphics_args]]) -return displaybox + ---@class DisplayBox:graphics_element + local DisplayBox, id = e.complete() + + return DisplayBox, id +end diff --git a/graphics/elements/div.lua b/graphics/elements/div.lua index 0af3259..2be440b 100644 --- a/graphics/elements/div.lua +++ b/graphics/elements/div.lua @@ -13,13 +13,16 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new div element +-- Create a new div container element. ---@nodiscard ---@param args div_args ----@return graphics_element element, element_id id -local function div(args) +---@return Div element, element_id id +return function (args) -- create new graphics element base object - return element.new(args).complete() -end + local e = element.new(args --[[@as graphics_args]]) -return div + ---@class Div:graphics_element + local Div, id = e.complete() + + return Div, id +end diff --git a/graphics/elements/listbox.lua b/graphics/elements/listbox.lua index 86cacd4..e1c8dec 100644 --- a/graphics/elements/listbox.lua +++ b/graphics/elements/listbox.lua @@ -30,15 +30,15 @@ local MOUSE_CLICK = core.events.MOUSE_CLICK ---@field y integer y position ---@field h integer element height --- new listbox element +-- Create a new scrollable listbox container element. ---@nodiscard ---@param args listbox_args ----@return graphics_element element, element_id id -local function listbox(args) +---@return ListBox element, element_id id +return function (args) args.can_focus = true -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- create content window for child elements local scroll_frame = window.create(e.window, 1, 1, e.frame.w - 1, args.scroll_height, false) @@ -339,10 +339,8 @@ local function listbox(args) draw_bar() end - -- initial draw - e.redraw() + ---@class ListBox:graphics_element + local ListBox, id = e.complete(true) - return e.complete() + return ListBox, id end - -return listbox diff --git a/graphics/elements/multipane.lua b/graphics/elements/multipane.lua index a283ed8..aae22ac 100644 --- a/graphics/elements/multipane.lua +++ b/graphics/elements/multipane.lua @@ -14,15 +14,15 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new multipane element +-- Create a new multipane container element. ---@nodiscard ---@param args multipane_args ----@return graphics_element element, element_id id -local function multipane(args) +---@return MultiPane element, element_id id +return function (args) element.assert(type(args.panes) == "table", "panes is a required field") -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) e.value = 1 @@ -41,10 +41,8 @@ local function multipane(args) end end - -- initial draw - e.redraw() + ---@class MultiPane:graphics_element + local MultiPane, id = e.complete(true) - return e.complete() + return MultiPane, id end - -return multipane diff --git a/graphics/elements/pipenet.lua b/graphics/elements/pipenet.lua index 625a70d..7045bd0 100644 --- a/graphics/elements/pipenet.lua +++ b/graphics/elements/pipenet.lua @@ -20,10 +20,10 @@ local element = require("graphics.element") ---@field fg string foreground blit ---@field bg string background blit --- new pipe network +-- Create a pipe network diagram. ---@param args pipenet_args ----@return graphics_element element, element_id id -local function pipenet(args) +---@return PipeNetwork element, element_id id +return function (args) element.assert(type(args.pipes) == "table", "pipes is a required field") args.width = 0 @@ -47,7 +47,7 @@ local function pipenet(args) end -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) -- determine if there are any thin pipes involved local any_thin = false @@ -322,10 +322,8 @@ local function pipenet(args) if any_thin then map_draw() else vector_draw() end end - -- initial draw - e.redraw() + ---@class PipeNetwork:graphics_element + local PipeNetwork, id = e.complete(true) - return e.complete() + return PipeNetwork, id end - -return pipenet diff --git a/graphics/elements/rectangle.lua b/graphics/elements/rectangle.lua index eceb9bd..ce5fbba 100644 --- a/graphics/elements/rectangle.lua +++ b/graphics/elements/rectangle.lua @@ -18,10 +18,10 @@ local element = require("graphics.element") ---@field fg_bg? cpair foreground/background colors ---@field hidden? boolean true to hide on initial draw --- new rectangle +-- Create a new rectangle container element. ---@param args rectangle_args ----@return graphics_element element, element_id id -local function rectangle(args) +---@return Rectangle element, element_id id +return function (args) element.assert(args.border ~= nil or args.thin ~= true, "thin requires border to be provided") -- if thin, then width will always need to be 1 @@ -45,7 +45,7 @@ local function rectangle(args) end -- create new graphics element base object - local e = element.new(args, nil, offset_x, offset_y) + local e = element.new(args --[[@as graphics_args]], nil, offset_x, offset_y) -- create content window for child elements e.content_window = window.create(e.window, 1 + offset_x, 1 + offset_y, e.frame.w - (2 * offset_x), e.frame.h - (2 * offset_y)) @@ -191,7 +191,8 @@ local function rectangle(args) e.redraw() end - return e.complete() -end + ---@class Rectangle:graphics_element + local Rectangle, id = e.complete() -return rectangle + return Rectangle, id +end diff --git a/graphics/elements/textbox.lua b/graphics/elements/textbox.lua index a52d528..00ea3f3 100644 --- a/graphics/elements/textbox.lua +++ b/graphics/elements/textbox.lua @@ -23,8 +23,8 @@ local ALIGN = core.ALIGN -- new text box ---@param args textbox_args ----@return graphics_element element, element_id id -local function textbox(args) +---@return TextBox element, element_id id +return function (args) element.assert(type(args.text) == "string", "text is a required field") if args.anchor == true then args.can_focus = true end @@ -42,7 +42,7 @@ local function textbox(args) end -- create new graphics element base object - local e = element.new(args, constrain) + local e = element.new(args --[[@as graphics_args]], constrain) e.value = args.text @@ -82,10 +82,8 @@ local function textbox(args) e.redraw() end - -- initial draw - e.redraw() + ---@class TextBox:graphics_element + local TextBox, id = e.complete(true) - return e.complete() + return TextBox, id end - -return textbox diff --git a/graphics/elements/tiling.lua b/graphics/elements/tiling.lua index 02e2605..cd9a31e 100644 --- a/graphics/elements/tiling.lua +++ b/graphics/elements/tiling.lua @@ -20,12 +20,12 @@ local element = require("graphics.element") -- new tiling box ---@param args tiling_args ----@return graphics_element element, element_id id -local function tiling(args) +---@return Tiling element, element_id id +return function (args) element.assert(type(args.fill_c) == "table", "fill_c is a required field") -- create new graphics element base object - local e = element.new(args) + local e = element.new(args --[[@as graphics_args]]) local fill_a = args.fill_c.blit_a local fill_b = args.fill_c.blit_b @@ -52,7 +52,7 @@ local function tiling(args) element.assert(start_x <= inner_width, "start_x > inner_width") element.assert(start_y <= inner_height, "start_y > inner_height") - -- draw tiling box + -- draw the tiling box function e.redraw() local alternator = true @@ -86,10 +86,8 @@ local function tiling(args) end end - -- initial draw - e.redraw() + ---@class Tiling:graphics_element + local Tiling, id = e.complete(true) - return e.complete() + return Tiling, id end - -return tiling diff --git a/graphics/flasher.lua b/graphics/flasher.lua index 9412ac7..624822b 100644 --- a/graphics/flasher.lua +++ b/graphics/flasher.lua @@ -18,7 +18,7 @@ local PERIOD = { flasher.PERIOD = PERIOD local active = false -local registry = { {}, {}, {} } -- one registry table per period +local registry = { {}, {}, {} } ---@type [ function[], function[], function [] ] one registry table per period local callback_counter = 0 -- blink registered indicators