mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#342 added element focusing feature to graphics library
This commit is contained in:
parent
1cb240b1b0
commit
29e910ba3c
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -5,6 +5,7 @@
|
|||||||
"colors",
|
"colors",
|
||||||
"fs",
|
"fs",
|
||||||
"http",
|
"http",
|
||||||
|
"keys",
|
||||||
"parallel",
|
"parallel",
|
||||||
"periphemu",
|
"periphemu",
|
||||||
"peripheral",
|
"peripheral",
|
||||||
|
@ -7,7 +7,7 @@ local flasher = require("graphics.flasher")
|
|||||||
|
|
||||||
local core = {}
|
local core = {}
|
||||||
|
|
||||||
core.version = "1.1.3"
|
core.version = "2.0.0"
|
||||||
|
|
||||||
core.flasher = flasher
|
core.flasher = flasher
|
||||||
core.events = events
|
core.events = events
|
||||||
@ -15,11 +15,7 @@ core.events = events
|
|||||||
-- Core Types
|
-- Core Types
|
||||||
|
|
||||||
---@enum TEXT_ALIGN
|
---@enum TEXT_ALIGN
|
||||||
core.TEXT_ALIGN = {
|
core.TEXT_ALIGN = { LEFT = 1, CENTER = 2, RIGHT = 3 }
|
||||||
LEFT = 1,
|
|
||||||
CENTER = 2,
|
|
||||||
RIGHT = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
---@class graphics_border
|
---@class graphics_border
|
||||||
---@field width integer
|
---@field width integer
|
||||||
@ -73,15 +69,9 @@ end
|
|||||||
function core.cpair(a, b)
|
function core.cpair(a, b)
|
||||||
return {
|
return {
|
||||||
-- color pairs
|
-- color pairs
|
||||||
color_a = a,
|
color_a = a, color_b = b, blit_a = colors.toBlit(a), blit_b = colors.toBlit(b),
|
||||||
color_b = b,
|
|
||||||
blit_a = colors.toBlit(a),
|
|
||||||
blit_b = colors.toBlit(b),
|
|
||||||
-- aliases
|
-- aliases
|
||||||
fgd = a,
|
fgd = a, bkg = b, blit_fgd = colors.toBlit(a), blit_bkg = colors.toBlit(b)
|
||||||
bkg = b,
|
|
||||||
blit_fgd = colors.toBlit(a),
|
|
||||||
blit_bkg = colors.toBlit(b)
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ local element = {}
|
|||||||
---@field gframe? graphics_frame frame instead of x/y/width/height
|
---@field gframe? graphics_frame frame instead of x/y/width/height
|
||||||
---@field fg_bg? cpair foreground/background colors
|
---@field fg_bg? cpair foreground/background colors
|
||||||
---@field hidden? boolean true to hide on initial draw
|
---@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
|
---@alias graphics_args graphics_args_generic
|
||||||
---|waiting_args
|
---|waiting_args
|
||||||
@ -32,6 +33,7 @@ local element = {}
|
|||||||
---|spinbox_args
|
---|spinbox_args
|
||||||
---|switch_button_args
|
---|switch_button_args
|
||||||
---|tabbar_args
|
---|tabbar_args
|
||||||
|
---|number_field_args
|
||||||
---|alarm_indicator_light
|
---|alarm_indicator_light
|
||||||
---|core_map_args
|
---|core_map_args
|
||||||
---|data_indicator_args
|
---|data_indicator_args
|
||||||
@ -69,6 +71,7 @@ local element = {}
|
|||||||
function element.new(args, child_offset_x, child_offset_y)
|
function element.new(args, child_offset_x, child_offset_y)
|
||||||
local self = {
|
local self = {
|
||||||
id = nil, ---@type element_id|nil
|
id = nil, ---@type element_id|nil
|
||||||
|
is_root = args.parent == nil,
|
||||||
elem_type = debug.getinfo(2).name,
|
elem_type = debug.getinfo(2).name,
|
||||||
define_completed = false,
|
define_completed = false,
|
||||||
p_window = nil, ---@type table
|
p_window = nil, ---@type table
|
||||||
@ -78,6 +81,7 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
next_id = 0, -- next child ID
|
next_id = 0, -- next child ID
|
||||||
subscriptions = {},
|
subscriptions = {},
|
||||||
button_down = { events.new_coord_2d(-1, -1), events.new_coord_2d(-1, -1), events.new_coord_2d(-1, -1) },
|
button_down = { events.new_coord_2d(-1, -1), events.new_coord_2d(-1, -1), events.new_coord_2d(-1, -1) },
|
||||||
|
focused = false,
|
||||||
mt = {}
|
mt = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +93,8 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
content_window = nil, ---@type table|nil
|
content_window = nil, ---@type table|nil
|
||||||
fg_bg = core.cpair(colors.white, colors.black),
|
fg_bg = core.cpair(colors.white, colors.black),
|
||||||
frame = core.gframe(1, 1, 1, 1),
|
frame = core.gframe(1, 1, 1, 1),
|
||||||
children = {}
|
children = {},
|
||||||
|
child_id_map = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
local name_brief = "graphics.element{" .. self.elem_type .. "}: "
|
local name_brief = "graphics.element{" .. self.elem_type .. "}: "
|
||||||
@ -104,6 +109,69 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
|
|
||||||
setmetatable(public, self.mt)
|
setmetatable(public, self.mt)
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
-- PRIVATE FUNCTIONS --
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
-- use tab to jump to the next focusable field
|
||||||
|
---@param reverse boolean
|
||||||
|
local function _tab_focusable(reverse)
|
||||||
|
local first_f = nil ---@type graphics_element|nil
|
||||||
|
local prev_f = nil ---@type graphics_element|nil
|
||||||
|
local cur_f = nil ---@type graphics_element|nil
|
||||||
|
local done = false
|
||||||
|
|
||||||
|
---@param elem graphics_element
|
||||||
|
local function handle_element(elem)
|
||||||
|
if elem.is_visible() and elem.is_focusable() and elem.is_enabled() then
|
||||||
|
if first_f == nil then first_f = elem end
|
||||||
|
|
||||||
|
if cur_f == nil then
|
||||||
|
if elem.is_focused() then
|
||||||
|
cur_f = elem
|
||||||
|
if (not done) and (reverse and prev_f ~= nil) then
|
||||||
|
cur_f.unfocus()
|
||||||
|
prev_f.focus()
|
||||||
|
done = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if elem.is_focused() then
|
||||||
|
elem.unfocus()
|
||||||
|
elseif not (reverse or done) then
|
||||||
|
cur_f.unfocus()
|
||||||
|
elem.focus()
|
||||||
|
done = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
prev_f = elem
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param children table
|
||||||
|
local function traverse(children)
|
||||||
|
for i = 1, #children do
|
||||||
|
local child = children[i] ---@type graphics_base
|
||||||
|
handle_element(child.get())
|
||||||
|
if child.get().is_visible() then traverse(child.children) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
traverse(protected.children)
|
||||||
|
|
||||||
|
-- if no element was focused, wrap focus
|
||||||
|
if first_f ~= nil and not done then
|
||||||
|
if reverse then
|
||||||
|
if cur_f ~= nil then cur_f.unfocus() end
|
||||||
|
if prev_f ~= nil then prev_f.focus() end
|
||||||
|
else
|
||||||
|
if cur_f ~= nil then cur_f.unfocus() end
|
||||||
|
first_f.focus()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
-- PROTECTED FUNCTIONS --
|
-- PROTECTED FUNCTIONS --
|
||||||
-------------------------
|
-------------------------
|
||||||
@ -214,85 +282,6 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
return in_x and in_y
|
return in_x and in_y
|
||||||
end
|
end
|
||||||
|
|
||||||
-- luacheck: push ignore
|
|
||||||
---@diagnostic disable: unused-local, unused-vararg
|
|
||||||
|
|
||||||
-- handle a child element having been added
|
|
||||||
---@param id element_id element identifier
|
|
||||||
---@param child graphics_element child element
|
|
||||||
function protected.on_added(id, child)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- handle a child element having been removed
|
|
||||||
---@param id element_id element identifier
|
|
||||||
function protected.on_removed(id)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- handle a mouse event
|
|
||||||
---@param event mouse_interaction mouse interaction event
|
|
||||||
function protected.handle_mouse(event)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- handle data value changes
|
|
||||||
---@vararg any value(s)
|
|
||||||
function protected.on_update(...)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- callback on control press responses
|
|
||||||
---@param result any
|
|
||||||
function protected.response_callback(result)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get value
|
|
||||||
---@nodiscard
|
|
||||||
function protected.get_value()
|
|
||||||
return protected.value
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set value
|
|
||||||
---@param value any value to set
|
|
||||||
function protected.set_value(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set minimum input value
|
|
||||||
---@param min integer minimum allowed value
|
|
||||||
function protected.set_min(min)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set maximum input value
|
|
||||||
---@param max integer maximum allowed value
|
|
||||||
function protected.set_max(max)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- enable the control
|
|
||||||
function protected.enable()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- disable the control
|
|
||||||
function protected.disable()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- custom recolor command, varies by element if implemented
|
|
||||||
---@vararg cpair|color color(s)
|
|
||||||
function protected.recolor(...)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- custom resize command, varies by element if implemented
|
|
||||||
---@vararg integer sizing
|
|
||||||
function protected.resize(...)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- luacheck: pop
|
|
||||||
---@diagnostic enable: unused-local, unused-vararg
|
|
||||||
|
|
||||||
-- start animations
|
|
||||||
function protected.start_anim()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- stop animations
|
|
||||||
function protected.stop_anim()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get public interface
|
-- get public interface
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@return graphics_element element, element_id id
|
---@return graphics_element element, element_id id
|
||||||
@ -306,6 +295,98 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
return public, self.id
|
return public, self.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- protected version of public is_focused()
|
||||||
|
---@nodiscard
|
||||||
|
---@return boolean is_focused
|
||||||
|
function protected.is_focused() return self.focused end
|
||||||
|
|
||||||
|
-- defocus this element
|
||||||
|
function protected.defocus() public.unfocus_all() end
|
||||||
|
|
||||||
|
-- request focus management to focus this element
|
||||||
|
function protected.req_focus() args.parent.__focus_child(public) end
|
||||||
|
|
||||||
|
-- action handlers --
|
||||||
|
|
||||||
|
-- luacheck: push ignore
|
||||||
|
---@diagnostic disable: unused-local, unused-vararg
|
||||||
|
|
||||||
|
-- handle a child element having been added
|
||||||
|
---@param id element_id element identifier
|
||||||
|
---@param child graphics_element child element
|
||||||
|
function protected.on_added(id, child) end
|
||||||
|
|
||||||
|
-- handle a child element having been removed
|
||||||
|
---@param id element_id element identifier
|
||||||
|
function protected.on_removed(id) end
|
||||||
|
|
||||||
|
-- handle this element having been focused
|
||||||
|
function protected.on_focused() end
|
||||||
|
|
||||||
|
-- handle this element having been unfocused
|
||||||
|
function protected.on_unfocused() end
|
||||||
|
|
||||||
|
-- handle this element having been shown
|
||||||
|
function protected.on_shown() end
|
||||||
|
|
||||||
|
-- handle this element having been hidden
|
||||||
|
function protected.on_hidden() end
|
||||||
|
|
||||||
|
-- handle a mouse event
|
||||||
|
---@param event mouse_interaction mouse interaction event
|
||||||
|
function protected.handle_mouse(event) end
|
||||||
|
|
||||||
|
-- handle a keyboard event
|
||||||
|
---@param event key_interaction key interaction event
|
||||||
|
function protected.handle_key(event) end
|
||||||
|
|
||||||
|
-- handle data value changes
|
||||||
|
---@vararg any value(s)
|
||||||
|
function protected.on_update(...) end
|
||||||
|
|
||||||
|
-- callback on control press responses
|
||||||
|
---@param result any
|
||||||
|
function protected.response_callback(result) end
|
||||||
|
|
||||||
|
-- get value
|
||||||
|
---@nodiscard
|
||||||
|
function protected.get_value() return protected.value end
|
||||||
|
|
||||||
|
-- set value
|
||||||
|
---@param value any value to set
|
||||||
|
function protected.set_value(value) end
|
||||||
|
|
||||||
|
-- set minimum input value
|
||||||
|
---@param min integer minimum allowed value
|
||||||
|
function protected.set_min(min) end
|
||||||
|
|
||||||
|
-- set maximum input value
|
||||||
|
---@param max integer maximum allowed value
|
||||||
|
function protected.set_max(max) end
|
||||||
|
|
||||||
|
-- enable the control
|
||||||
|
function protected.enable() end
|
||||||
|
|
||||||
|
-- disable the control
|
||||||
|
function protected.disable() end
|
||||||
|
|
||||||
|
-- custom recolor command, varies by element if implemented
|
||||||
|
---@vararg cpair|color color(s)
|
||||||
|
function protected.recolor(...) end
|
||||||
|
|
||||||
|
-- custom resize command, varies by element if implemented
|
||||||
|
---@vararg integer sizing
|
||||||
|
function protected.resize(...) end
|
||||||
|
|
||||||
|
-- luacheck: pop
|
||||||
|
---@diagnostic enable: unused-local, unused-vararg
|
||||||
|
|
||||||
|
-- start animations
|
||||||
|
function protected.start_anim() end
|
||||||
|
|
||||||
|
-- stop animations
|
||||||
|
function protected.stop_anim() end
|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
-- SETUP --
|
-- SETUP --
|
||||||
-----------
|
-----------
|
||||||
@ -324,7 +405,7 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
self.id = args.id or "__ROOT__"
|
self.id = args.id or "__ROOT__"
|
||||||
protected.prepare_template(0, 0, 1)
|
protected.prepare_template(0, 0, 1)
|
||||||
else
|
else
|
||||||
self.id = args.parent.__add_child(args.id, protected)
|
self.id, self.ordinal = args.parent.__add_child(args.id, protected)
|
||||||
end
|
end
|
||||||
|
|
||||||
----------------------
|
----------------------
|
||||||
@ -358,7 +439,7 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
|
|
||||||
-- delete all children
|
-- delete all children
|
||||||
for k, v in pairs(protected.children) do
|
for k, v in pairs(protected.children) do
|
||||||
v.delete()
|
v.get().delete()
|
||||||
protected.children[k] = nil
|
protected.children[k] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -380,47 +461,59 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
|
|
||||||
self.next_y = child.frame.y + child.frame.h
|
self.next_y = child.frame.y + child.frame.h
|
||||||
|
|
||||||
local child_element = child.get()
|
|
||||||
|
|
||||||
local id = key ---@type string|integer|nil
|
local id = key ---@type string|integer|nil
|
||||||
if id == nil then
|
if id == nil then
|
||||||
id = self.next_id
|
id = self.next_id
|
||||||
self.next_id = self.next_id + 1
|
self.next_id = self.next_id + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
protected.children[id] = child_element
|
table.insert(protected.children, child)
|
||||||
|
|
||||||
|
protected.child_id_map[id] = #protected.children
|
||||||
|
|
||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
|
|
||||||
-- remove a child element
|
-- remove a child element
|
||||||
---@param key element_id id
|
---@param id element_id id
|
||||||
function public.__remove_child(key)
|
function public.__remove_child(id)
|
||||||
if protected.children[key] ~= nil then
|
local index = protected.child_id_map[id]
|
||||||
protected.on_removed(key)
|
if protected.children[index] ~= nil then
|
||||||
protected.children[key] = nil
|
protected.on_removed(id)
|
||||||
|
protected.children[index] = nil
|
||||||
|
protected.child_id_map[id] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- actions to take upon a child element becoming ready (initial draw/construction completed)
|
-- actions to take upon a child element becoming ready (initial draw/construction completed)
|
||||||
---@param key element_id id
|
---@param key element_id id
|
||||||
---@param child graphics_element
|
---@param child graphics_element
|
||||||
function public.__child_ready(key, child)
|
function public.__child_ready(key, child) protected.on_added(key, child) end
|
||||||
protected.on_added(key, child)
|
|
||||||
|
-- focus solely on this child
|
||||||
|
---@param child graphics_element
|
||||||
|
function public.__focus_child(child)
|
||||||
|
if self.is_root then
|
||||||
|
public.unfocus_all()
|
||||||
|
child.focus()
|
||||||
|
else args.parent.__focus_child(child) end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- get a child element
|
-- get a child element
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param id element_id
|
---@param id element_id
|
||||||
---@return graphics_element
|
---@return graphics_element
|
||||||
function public.get_child(id) return protected.children[id] end
|
function public.get_child(id) return protected.children[protected.child_id_map[id]].get() end
|
||||||
|
|
||||||
-- remove a child element
|
-- remove a child element
|
||||||
---@param id element_id
|
---@param id element_id
|
||||||
function public.remove(id)
|
function public.remove(id)
|
||||||
if protected.children[id] ~= nil then
|
local index = protected.child_id_map[id]
|
||||||
protected.children[id].delete()
|
if protected.children[index] ~= nil then
|
||||||
|
protected.children[index].get().delete()
|
||||||
protected.on_removed(id)
|
protected.on_removed(id)
|
||||||
protected.children[id] = nil
|
protected.children[index] = nil
|
||||||
|
protected.child_id_map[id] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -429,16 +522,13 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
---@param id element_id
|
---@param id element_id
|
||||||
---@return graphics_element|nil element
|
---@return graphics_element|nil element
|
||||||
function public.get_element_by_id(id)
|
function public.get_element_by_id(id)
|
||||||
if protected.children[id] == nil then
|
local index = protected.child_id_map[id]
|
||||||
|
if protected.children[index] == nil then
|
||||||
for _, child in pairs(protected.children) do
|
for _, child in pairs(protected.children) do
|
||||||
local elem = child.get_element_by_id(id)
|
local elem = child.get().get_element_by_id(id)
|
||||||
if elem ~= nil then return elem end
|
if elem ~= nil then return elem end
|
||||||
end
|
end
|
||||||
else
|
else return protected.children[index].get() end
|
||||||
return protected.children[id]
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- AUTO-PLACEMENT --
|
-- AUTO-PLACEMENT --
|
||||||
@ -450,97 +540,113 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
|
|
||||||
-- PROPERTIES --
|
-- PROPERTIES --
|
||||||
|
|
||||||
-- get the foreground/background colors
|
-- get element id
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@return cpair fg_bg
|
---@return element_id
|
||||||
function public.get_fg_bg()
|
function public.get_id() return self.id end
|
||||||
return protected.fg_bg
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get element x
|
-- get element x
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@return integer x
|
---@return integer x
|
||||||
function public.get_x()
|
function public.get_x() return protected.frame.x end
|
||||||
return protected.frame.x
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get element y
|
-- get element y
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@return integer y
|
---@return integer y
|
||||||
function public.get_y()
|
function public.get_y() return protected.frame.y end
|
||||||
return protected.frame.y
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get element width
|
-- get element width
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@return integer width
|
---@return integer width
|
||||||
function public.get_width()
|
function public.get_width() return protected.frame.w end
|
||||||
return protected.frame.w
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get element height
|
-- get element height
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@return integer height
|
---@return integer height
|
||||||
function public.get_height()
|
function public.get_height() return protected.frame.h end
|
||||||
return protected.frame.h
|
|
||||||
end
|
-- get the foreground/background colors
|
||||||
|
---@nodiscard
|
||||||
|
---@return cpair fg_bg
|
||||||
|
function public.get_fg_bg() return protected.fg_bg end
|
||||||
|
|
||||||
-- get the element value
|
-- get the element value
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@return any value
|
---@return any value
|
||||||
function public.get_value()
|
function public.get_value() return protected.get_value() end
|
||||||
return protected.get_value()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set the element value
|
-- set the element value
|
||||||
---@param value any new value
|
---@param value any new value
|
||||||
function public.set_value(value)
|
function public.set_value(value) protected.set_value(value) end
|
||||||
protected.set_value(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set minimum input value
|
-- set minimum input value
|
||||||
---@param min integer minimum allowed value
|
---@param min integer minimum allowed value
|
||||||
function public.set_min(min)
|
function public.set_min(min) protected.set_min(min) end
|
||||||
protected.set_min(min)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set maximum input value
|
-- set maximum input value
|
||||||
---@param max integer maximum allowed value
|
---@param max integer maximum allowed value
|
||||||
function public.set_max(max)
|
function public.set_max(max) protected.set_max(max) end
|
||||||
protected.set_max(max)
|
|
||||||
end
|
-- check if this element is enabled
|
||||||
|
function public.is_enabled() return protected.enabled end
|
||||||
|
|
||||||
-- enable the element
|
-- enable the element
|
||||||
function public.enable()
|
function public.enable()
|
||||||
protected.enabled = true
|
if not protected.enabled then
|
||||||
protected.enable()
|
protected.enabled = true
|
||||||
|
protected.enable()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- disable the element
|
-- disable the element
|
||||||
function public.disable()
|
function public.disable()
|
||||||
protected.enabled = false
|
if protected.enabled then
|
||||||
protected.disable()
|
protected.enabled = false
|
||||||
|
protected.disable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- can this element be focused
|
||||||
|
function public.is_focusable() return args.can_focus end
|
||||||
|
|
||||||
|
-- is this element focused
|
||||||
|
function public.is_focused() return self.focused end
|
||||||
|
|
||||||
|
-- focus the element
|
||||||
|
function public.focus()
|
||||||
|
if args.can_focus and not self.focused then
|
||||||
|
self.focused = true
|
||||||
|
protected.on_focused()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- unfocus this element
|
||||||
|
function public.unfocus()
|
||||||
|
if args.can_focus and self.focused then
|
||||||
|
self.focused = false
|
||||||
|
protected.on_unfocused()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- unfocus this element and all its children
|
||||||
|
function public.unfocus_all()
|
||||||
|
public.unfocus()
|
||||||
|
for _, child in pairs(protected.children) do child.get().unfocus() end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- custom recolor command, varies by element if implemented
|
-- custom recolor command, varies by element if implemented
|
||||||
---@vararg cpair|color color(s)
|
---@vararg cpair|color color(s)
|
||||||
function public.recolor(...)
|
function public.recolor(...) protected.recolor(...) end
|
||||||
protected.recolor(...)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- resize attributes of the element value if supported
|
-- resize attributes of the element value if supported
|
||||||
---@vararg number dimensions (element specific)
|
---@vararg number dimensions (element specific)
|
||||||
function public.resize(...)
|
function public.resize(...) protected.resize(...) end
|
||||||
protected.resize(...)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- reposition the element window<br>
|
-- reposition the element window<br>
|
||||||
-- offsets relative to parent frame are where (1, 1) would be on top of the parent's top left corner
|
-- offsets relative to parent frame are where (1, 1) would be on top of the parent's top left corner
|
||||||
---@param x integer x position relative to parent frame
|
---@param x integer x position relative to parent frame
|
||||||
---@param y integer y position relative to parent frame
|
---@param y integer y position relative to parent frame
|
||||||
function public.reposition(x, y)
|
function public.reposition(x, y) protected.window.reposition(x, y) end
|
||||||
protected.window.reposition(x, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- FUNCTION CALLBACKS --
|
-- FUNCTION CALLBACKS --
|
||||||
|
|
||||||
@ -553,12 +659,12 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
local ini_in = protected.in_window_bounds(x_ini, y_ini)
|
local ini_in = protected.in_window_bounds(x_ini, y_ini)
|
||||||
|
|
||||||
if ini_in then
|
if ini_in then
|
||||||
if event.type == events.CLICK_TYPE.UP or event.type == events.CLICK_TYPE.DRAG then
|
if event.type == events.MOUSE_CLICK.UP or event.type == events.MOUSE_CLICK.DRAG then
|
||||||
-- make sure we don't handle mouse events that started before this element was made visible
|
-- make sure we don't handle mouse events that started before this element was made visible
|
||||||
if (event.initial.x ~= self.button_down[event.button].x) or (event.initial.y ~= self.button_down[event.button].y) then
|
if (event.initial.x ~= self.button_down[event.button].x) or (event.initial.y ~= self.button_down[event.button].y) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
elseif event.type == events.CLICK_TYPE.DOWN then
|
elseif event.type == events.MOUSE_CLICK.DOWN then
|
||||||
self.button_down[event.button] = event.initial
|
self.button_down[event.button] = event.initial
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -566,25 +672,39 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
|
|
||||||
-- handle the mouse event then pass to children
|
-- handle the mouse event then pass to children
|
||||||
protected.handle_mouse(event_T)
|
protected.handle_mouse(event_T)
|
||||||
for _, child in pairs(protected.children) do child.handle_mouse(event_T) end
|
for _, child in pairs(protected.children) do child.get().handle_mouse(event_T) end
|
||||||
|
elseif event.type == events.MOUSE_CLICK.DOWN or event.type == events.MOUSE_CLICK.TAP then
|
||||||
|
-- clicked out, unfocus this element and children
|
||||||
|
public.unfocus_all()
|
||||||
end
|
end
|
||||||
elseif event.type == events.CLICK_TYPE.DOWN then
|
else
|
||||||
-- don't track this click
|
-- don't track clicks while hidden
|
||||||
self.button_down[event.button] = events.new_coord_2d(-1, -1)
|
self.button_down[event.button] = events.new_coord_2d(-1, -1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- handle a keyboard click if this element is visible and focused
|
||||||
|
---@param event key_interaction keyboard interaction event
|
||||||
|
function public.handle_key(event)
|
||||||
|
if protected.window.isVisible() then
|
||||||
|
if self.is_root and (event.type == events.KEY_CLICK.DOWN) and (event.key == keys.tab) then
|
||||||
|
-- try to jump to the next/previous focusable field
|
||||||
|
_tab_focusable(event.shift)
|
||||||
|
else
|
||||||
|
-- handle the key event then pass to children
|
||||||
|
if self.focused then protected.handle_key(event) end
|
||||||
|
for _, child in pairs(protected.children) do child.get().handle_key(event) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- draw the element given new data
|
-- draw the element given new data
|
||||||
---@vararg any new data
|
---@vararg any new data
|
||||||
function public.update(...)
|
function public.update(...) protected.on_update(...) end
|
||||||
protected.on_update(...)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- on a control request response
|
-- on a control request response
|
||||||
---@param result any
|
---@param result any
|
||||||
function public.on_response(result)
|
function public.on_response(result) protected.response_callback(result) end
|
||||||
protected.response_callback(result)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- register a callback with a PSIL, allowing for automatic unregister on delete<br>
|
-- register a callback with a PSIL, allowing for automatic unregister on delete<br>
|
||||||
-- do not use graphics elements directly with PSIL subscribe()
|
-- do not use graphics elements directly with PSIL subscribe()
|
||||||
@ -598,6 +718,9 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
|
|
||||||
-- VISIBILITY & ANIMATIONS --
|
-- VISIBILITY & ANIMATIONS --
|
||||||
|
|
||||||
|
-- check if this element is visible
|
||||||
|
function public.is_visible() return protected.window.isVisible() end
|
||||||
|
|
||||||
-- show the element and enables animations by default
|
-- show the element and enables animations by default
|
||||||
---@param animate? boolean true (default) to automatically resume animations
|
---@param animate? boolean true (default) to automatically resume animations
|
||||||
function public.show(animate)
|
function public.show(animate)
|
||||||
@ -610,44 +733,39 @@ function element.new(args, child_offset_x, child_offset_y)
|
|||||||
---@see graphics_element.content_redraw
|
---@see graphics_element.content_redraw
|
||||||
function public.hide()
|
function public.hide()
|
||||||
public.freeze_all() -- stop animations for efficiency/performance
|
public.freeze_all() -- stop animations for efficiency/performance
|
||||||
|
public.unfocus_all()
|
||||||
protected.window.setVisible(false)
|
protected.window.setVisible(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- start/resume animation(s)
|
-- start/resume animation(s)
|
||||||
function public.animate()
|
function public.animate() protected.start_anim() end
|
||||||
protected.start_anim()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- start/resume animation(s) for this element and all its children<br>
|
-- start/resume animation(s) for this element and all its children<br>
|
||||||
-- only animates if a window is visible
|
-- only animates if a window is visible
|
||||||
function public.animate_all()
|
function public.animate_all()
|
||||||
if protected.window.isVisible() then
|
if protected.window.isVisible() then
|
||||||
public.animate()
|
public.animate()
|
||||||
for _, child in pairs(protected.children) do child.animate_all() end
|
for _, child in pairs(protected.children) do child.get().animate_all() end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- freeze animation(s)
|
-- freeze animation(s)
|
||||||
function public.freeze()
|
function public.freeze() protected.stop_anim() end
|
||||||
protected.stop_anim()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- freeze animation(s) for this element and all its children
|
-- freeze animation(s) for this element and all its children
|
||||||
function public.freeze_all()
|
function public.freeze_all()
|
||||||
public.freeze()
|
public.freeze()
|
||||||
for _, child in pairs(protected.children) do child.freeze_all() end
|
for _, child in pairs(protected.children) do child.get().freeze_all() end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- re-draw the element
|
-- re-draw the element
|
||||||
function public.redraw()
|
function public.redraw() protected.window.redraw() end
|
||||||
protected.window.redraw()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if a content window is set, clears it then re-draws all children
|
-- if a content window is set, clears it then re-draws all children
|
||||||
function public.content_redraw()
|
function public.content_redraw()
|
||||||
if protected.content_window ~= nil then
|
if protected.content_window ~= nil then
|
||||||
protected.content_window.clear()
|
protected.content_window.clear()
|
||||||
for _, child in pairs(protected.children) do child.redraw() end
|
for _, child in pairs(protected.children) do child.get().redraw() end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ local tcd = require("scada-common.tcd")
|
|||||||
local core = require("graphics.core")
|
local core = require("graphics.core")
|
||||||
local element = require("graphics.element")
|
local element = require("graphics.element")
|
||||||
|
|
||||||
local CLICK_TYPE = core.events.CLICK_TYPE
|
local MOUSE_CLICK = core.events.MOUSE_CLICK
|
||||||
|
|
||||||
---@class app_button_args
|
---@class app_button_args
|
||||||
---@field text string app icon text
|
---@field text string app icon text
|
||||||
@ -98,14 +98,14 @@ local function app_button(args)
|
|||||||
---@param event mouse_interaction mouse event
|
---@param event mouse_interaction mouse event
|
||||||
function e.handle_mouse(event)
|
function e.handle_mouse(event)
|
||||||
if e.enabled then
|
if e.enabled then
|
||||||
if event.type == CLICK_TYPE.TAP then
|
if event.type == MOUSE_CLICK.TAP then
|
||||||
show_pressed()
|
show_pressed()
|
||||||
-- show as unpressed in 0.25 seconds
|
-- show as unpressed in 0.25 seconds
|
||||||
if args.active_fg_bg ~= nil then tcd.dispatch(0.25, show_unpressed) end
|
if args.active_fg_bg ~= nil then tcd.dispatch(0.25, show_unpressed) end
|
||||||
args.callback()
|
args.callback()
|
||||||
elseif event.type == CLICK_TYPE.DOWN then
|
elseif event.type == MOUSE_CLICK.DOWN then
|
||||||
show_pressed()
|
show_pressed()
|
||||||
elseif event.type == CLICK_TYPE.UP then
|
elseif event.type == MOUSE_CLICK.UP then
|
||||||
show_unpressed()
|
show_unpressed()
|
||||||
if e.in_frame_bounds(event.current.x, event.current.y) then
|
if e.in_frame_bounds(event.current.x, event.current.y) then
|
||||||
args.callback()
|
args.callback()
|
||||||
@ -117,7 +117,7 @@ local function app_button(args)
|
|||||||
-- set the value (true simulates pressing the app button)
|
-- set the value (true simulates pressing the app button)
|
||||||
---@param val boolean new value
|
---@param val boolean new value
|
||||||
function e.set_value(val)
|
function e.set_value(val)
|
||||||
if val then e.handle_mouse(core.events.mouse_generic(core.events.CLICK_TYPE.UP, 1, 1)) end
|
if val then e.handle_mouse(core.events.mouse_generic(core.events.MOUSE_CLICK.UP, 1, 1)) end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- initial draw
|
-- initial draw
|
||||||
|
@ -174,7 +174,7 @@ local function hazard_button(args)
|
|||||||
-- set the value (true simulates pressing the button)
|
-- set the value (true simulates pressing the button)
|
||||||
---@param val boolean new value
|
---@param val boolean new value
|
||||||
function e.set_value(val)
|
function e.set_value(val)
|
||||||
if val then e.handle_mouse(core.events.mouse_generic(core.events.CLICK_TYPE.UP, 1, 1)) end
|
if val then e.handle_mouse(core.events.mouse_generic(core.events.MOUSE_CLICK.UP, 1, 1)) end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- show the button as disabled
|
-- show the button as disabled
|
||||||
|
@ -5,7 +5,8 @@ local tcd = require("scada-common.tcd")
|
|||||||
local core = require("graphics.core")
|
local core = require("graphics.core")
|
||||||
local element = require("graphics.element")
|
local element = require("graphics.element")
|
||||||
|
|
||||||
local CLICK_TYPE = core.events.CLICK_TYPE
|
local MOUSE_CLICK = core.events.MOUSE_CLICK
|
||||||
|
local KEY_CLICK = core.events.KEY_CLICK
|
||||||
|
|
||||||
---@class push_button_args
|
---@class push_button_args
|
||||||
---@field text string button text
|
---@field text string button text
|
||||||
@ -32,7 +33,8 @@ local function push_button(args)
|
|||||||
|
|
||||||
local text_width = string.len(args.text)
|
local text_width = string.len(args.text)
|
||||||
|
|
||||||
-- single line height, calculate width
|
-- set automatic settings
|
||||||
|
args.can_focus = true
|
||||||
args.height = 1
|
args.height = 1
|
||||||
args.min_width = args.min_width or 0
|
args.min_width = args.min_width or 0
|
||||||
args.width = math.max(text_width, args.min_width)
|
args.width = math.max(text_width, args.min_width)
|
||||||
@ -76,14 +78,14 @@ local function push_button(args)
|
|||||||
---@param event mouse_interaction mouse event
|
---@param event mouse_interaction mouse event
|
||||||
function e.handle_mouse(event)
|
function e.handle_mouse(event)
|
||||||
if e.enabled then
|
if e.enabled then
|
||||||
if event.type == CLICK_TYPE.TAP then
|
if event.type == MOUSE_CLICK.TAP then
|
||||||
show_pressed()
|
show_pressed()
|
||||||
-- show as unpressed in 0.25 seconds
|
-- show as unpressed in 0.25 seconds
|
||||||
if args.active_fg_bg ~= nil then tcd.dispatch(0.25, show_unpressed) end
|
if args.active_fg_bg ~= nil then tcd.dispatch(0.25, show_unpressed) end
|
||||||
args.callback()
|
args.callback()
|
||||||
elseif event.type == CLICK_TYPE.DOWN then
|
elseif event.type == MOUSE_CLICK.DOWN then
|
||||||
show_pressed()
|
show_pressed()
|
||||||
elseif event.type == CLICK_TYPE.UP then
|
elseif event.type == MOUSE_CLICK.UP then
|
||||||
show_unpressed()
|
show_unpressed()
|
||||||
if e.in_frame_bounds(event.current.x, event.current.y) then
|
if e.in_frame_bounds(event.current.x, event.current.y) then
|
||||||
args.callback()
|
args.callback()
|
||||||
@ -92,10 +94,21 @@ local function push_button(args)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- handle keyboard interaction
|
||||||
|
---@param event key_interaction key event
|
||||||
|
function e.handle_key(event)
|
||||||
|
if event.type == KEY_CLICK.DOWN then
|
||||||
|
if event.key == keys.space or event.key == keys.enter or event.key == keys.numPadEnter then
|
||||||
|
args.callback()
|
||||||
|
e.defocus()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- set the value (true simulates pressing the button)
|
-- set the value (true simulates pressing the button)
|
||||||
---@param val boolean new value
|
---@param val boolean new value
|
||||||
function e.set_value(val)
|
function e.set_value(val)
|
||||||
if val then e.handle_mouse(core.events.mouse_generic(core.events.CLICK_TYPE.UP, 1, 1)) end
|
if val then e.handle_mouse(core.events.mouse_generic(core.events.MOUSE_CLICK.UP, 1, 1)) end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- show butten as enabled
|
-- show butten as enabled
|
||||||
@ -118,6 +131,9 @@ local function push_button(args)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
e.on_focused = show_pressed
|
||||||
|
e.on_unfocused = show_unpressed
|
||||||
|
|
||||||
-- initial draw
|
-- initial draw
|
||||||
draw()
|
draw()
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ local tcd = require("scada-common.tcd")
|
|||||||
local core = require("graphics.core")
|
local core = require("graphics.core")
|
||||||
local element = require("graphics.element")
|
local element = require("graphics.element")
|
||||||
|
|
||||||
local CLICK_TYPE = core.events.CLICK_TYPE
|
local MOUSE_CLICK = core.events.MOUSE_CLICK
|
||||||
|
|
||||||
---@class sidebar_tab
|
---@class sidebar_tab
|
||||||
---@field char string character identifier
|
---@field char string character identifier
|
||||||
@ -85,22 +85,22 @@ local function sidebar(args)
|
|||||||
local ini_idx = math.ceil(event.initial.y / 3)
|
local ini_idx = math.ceil(event.initial.y / 3)
|
||||||
|
|
||||||
if args.tabs[cur_idx] ~= nil then
|
if args.tabs[cur_idx] ~= nil then
|
||||||
if event.type == CLICK_TYPE.TAP then
|
if event.type == MOUSE_CLICK.TAP then
|
||||||
e.value = cur_idx
|
e.value = cur_idx
|
||||||
draw(true)
|
draw(true)
|
||||||
-- show as unpressed in 0.25 seconds
|
-- show as unpressed in 0.25 seconds
|
||||||
tcd.dispatch(0.25, function () draw(false) end)
|
tcd.dispatch(0.25, function () draw(false) end)
|
||||||
args.callback(e.value)
|
args.callback(e.value)
|
||||||
elseif event.type == CLICK_TYPE.DOWN then
|
elseif event.type == MOUSE_CLICK.DOWN then
|
||||||
draw(true, cur_idx)
|
draw(true, cur_idx)
|
||||||
elseif event.type == CLICK_TYPE.UP then
|
elseif event.type == MOUSE_CLICK.UP then
|
||||||
if cur_idx == ini_idx and e.in_frame_bounds(event.current.x, event.current.y) then
|
if cur_idx == ini_idx and e.in_frame_bounds(event.current.x, event.current.y) then
|
||||||
e.value = cur_idx
|
e.value = cur_idx
|
||||||
draw(false)
|
draw(false)
|
||||||
args.callback(e.value)
|
args.callback(e.value)
|
||||||
else draw(false) end
|
else draw(false) end
|
||||||
end
|
end
|
||||||
elseif event.type == CLICK_TYPE.UP then
|
elseif event.type == MOUSE_CLICK.UP then
|
||||||
draw(false)
|
draw(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
136
graphics/elements/form/number_field.lua
Normal file
136
graphics/elements/form/number_field.lua
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
-- Numeric Value Entry Graphics Element
|
||||||
|
|
||||||
|
local util = require("scada-common.util")
|
||||||
|
|
||||||
|
local core = require("graphics.core")
|
||||||
|
local element = require("graphics.element")
|
||||||
|
|
||||||
|
local KEY_CLICK = core.events.KEY_CLICK
|
||||||
|
|
||||||
|
---@class number_field_args
|
||||||
|
---@field default? number default value, defaults to 0
|
||||||
|
---@field min? number minimum, forced on unfocus
|
||||||
|
---@field max? number maximum, forced on unfocus
|
||||||
|
---@field max_digits? integer maximum number of digits, defaults to width
|
||||||
|
---@field allow_decimal? boolean true to allow decimals
|
||||||
|
---@field allow_negative? boolean true to allow negative numbers
|
||||||
|
---@field parent graphics_element
|
||||||
|
---@field id? string element id
|
||||||
|
---@field x? integer 1 if omitted
|
||||||
|
---@field y? integer auto incremented if omitted
|
||||||
|
---@field width? integer parent width if omitted
|
||||||
|
---@field fg_bg? cpair foreground/background colors
|
||||||
|
---@field hidden? boolean true to hide on initial draw
|
||||||
|
|
||||||
|
-- new numeric form field
|
||||||
|
---@param args number_field_args
|
||||||
|
---@return graphics_element element, element_id id
|
||||||
|
local function number_field(args)
|
||||||
|
args.height = 1
|
||||||
|
args.can_focus = true
|
||||||
|
|
||||||
|
-- create new graphics element base object
|
||||||
|
local e = element.new(args)
|
||||||
|
|
||||||
|
local has_decimal = false
|
||||||
|
|
||||||
|
args.max_digits = args.max_digits or e.frame.w
|
||||||
|
|
||||||
|
-- set initial value
|
||||||
|
e.value = "" .. (args.default or 0)
|
||||||
|
|
||||||
|
local function show()
|
||||||
|
-- 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_set_fgd(colors.black)
|
||||||
|
e.w_write(e.value)
|
||||||
|
if e.is_focused() 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)
|
||||||
|
-- only handle if on an increment or decrement arrow
|
||||||
|
if e.enabled and core.events.was_clicked(event.type) then
|
||||||
|
e.req_focus()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- handle keyboard interaction
|
||||||
|
---@param event key_interaction key event
|
||||||
|
function e.handle_key(event)
|
||||||
|
if event.type == KEY_CLICK.CHAR and string.len(e.value) < args.max_digits then
|
||||||
|
if tonumber(event.name) then
|
||||||
|
e.value = util.trinary(e.value == "0", "", e.value) .. tonumber(event.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
show()
|
||||||
|
elseif event.type == KEY_CLICK.DOWN then
|
||||||
|
if (event.key == keys.backspace or event.key == keys.delete) and (string.len(e.value) > 0) then
|
||||||
|
e.value = string.sub(e.value, 1, string.len(e.value) - 1)
|
||||||
|
has_decimal = string.find(e.value, "%.") ~= nil
|
||||||
|
show()
|
||||||
|
elseif (event.key == keys.period or event.key == keys.numPadDecimal) and (not has_decimal) and args.allow_decimal then
|
||||||
|
e.value = e.value .. "."
|
||||||
|
has_decimal = true
|
||||||
|
show()
|
||||||
|
elseif (event.key == keys.minus or event.key == keys.numPadSubtract) and (string.len(e.value) == 0) and args.allow_negative then
|
||||||
|
e.value = "-"
|
||||||
|
show()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set the value
|
||||||
|
---@param val number number to show
|
||||||
|
function e.set_value(val) e.value = val end
|
||||||
|
|
||||||
|
-- set minimum input value
|
||||||
|
---@param min integer minimum allowed value
|
||||||
|
function e.set_min(min) args.min = min end
|
||||||
|
|
||||||
|
-- set maximum input value
|
||||||
|
---@param max integer maximum allowed value
|
||||||
|
function e.set_max(max) args.max = max end
|
||||||
|
|
||||||
|
-- handle focus change
|
||||||
|
e.on_focused = show
|
||||||
|
|
||||||
|
function e.on_unfocused()
|
||||||
|
local val = tonumber(e.value)
|
||||||
|
local max = tonumber(args.max)
|
||||||
|
local min = tonumber(args.min)
|
||||||
|
|
||||||
|
if type(val) == "number" then
|
||||||
|
if type(args.max) == "number" and val > max then
|
||||||
|
e.value = "" .. max
|
||||||
|
elseif type(args.min) == "number" and val < min then
|
||||||
|
e.value = "" .. min
|
||||||
|
end
|
||||||
|
else
|
||||||
|
e.value = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
show()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- enable this input
|
||||||
|
function e.enable()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- disable this input
|
||||||
|
function e.disable()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- initial draw
|
||||||
|
show()
|
||||||
|
|
||||||
|
return e.complete()
|
||||||
|
end
|
||||||
|
|
||||||
|
return number_field
|
@ -5,7 +5,7 @@ local tcd = require("scada-common.tcd")
|
|||||||
local core = require("graphics.core")
|
local core = require("graphics.core")
|
||||||
local element = require("graphics.element")
|
local element = require("graphics.element")
|
||||||
|
|
||||||
local CLICK_TYPE = core.events.CLICK_TYPE
|
local MOUSE_CLICK = core.events.MOUSE_CLICK
|
||||||
|
|
||||||
---@class listbox_args
|
---@class listbox_args
|
||||||
---@field scroll_height integer height of internal scrolling container (must fit all elements vertically tiled)
|
---@field scroll_height integer height of internal scrolling container (must fit all elements vertically tiled)
|
||||||
@ -223,7 +223,7 @@ local function listbox(args)
|
|||||||
---@param event mouse_interaction mouse event
|
---@param event mouse_interaction mouse event
|
||||||
function e.handle_mouse(event)
|
function e.handle_mouse(event)
|
||||||
if e.enabled then
|
if e.enabled then
|
||||||
if event.type == CLICK_TYPE.TAP then
|
if event.type == MOUSE_CLICK.TAP then
|
||||||
if event.current.x == e.frame.w then
|
if event.current.x == e.frame.w then
|
||||||
if event.current.y == 1 or event.current.y < bar_bounds[1] then
|
if event.current.y == 1 or event.current.y < bar_bounds[1] then
|
||||||
draw_arrows(1)
|
draw_arrows(1)
|
||||||
@ -235,7 +235,7 @@ local function listbox(args)
|
|||||||
if args.nav_active ~= nil then tcd.dispatch(0.25, function () draw_arrows(0) end) end
|
if args.nav_active ~= nil then tcd.dispatch(0.25, function () draw_arrows(0) end) end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif event.type == CLICK_TYPE.DOWN then
|
elseif event.type == MOUSE_CLICK.DOWN then
|
||||||
if event.current.x == e.frame.w then
|
if event.current.x == e.frame.w then
|
||||||
if event.current.y == 1 or event.current.y < bar_bounds[1] then
|
if event.current.y == 1 or event.current.y < bar_bounds[1] then
|
||||||
draw_arrows(1)
|
draw_arrows(1)
|
||||||
@ -250,10 +250,10 @@ local function listbox(args)
|
|||||||
mouse_last_y = event.current.y
|
mouse_last_y = event.current.y
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif event.type == CLICK_TYPE.UP then
|
elseif event.type == MOUSE_CLICK.UP then
|
||||||
holding_bar = false
|
holding_bar = false
|
||||||
draw_arrows(0)
|
draw_arrows(0)
|
||||||
elseif event.type == CLICK_TYPE.DRAG then
|
elseif event.type == MOUSE_CLICK.DRAG then
|
||||||
if holding_bar then
|
if holding_bar then
|
||||||
-- if mouse is within vertical frame, including the grip point
|
-- if mouse is within vertical frame, including the grip point
|
||||||
if event.current.y > (1 + bar_grip_pos) and event.current.y <= ((e.frame.h - bar_height) + bar_grip_pos) then
|
if event.current.y > (1 + bar_grip_pos) and event.current.y <= ((e.frame.h - bar_height) + bar_grip_pos) then
|
||||||
@ -266,9 +266,9 @@ local function listbox(args)
|
|||||||
mouse_last_y = event.current.y
|
mouse_last_y = event.current.y
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif event.type == CLICK_TYPE.SCROLL_DOWN then
|
elseif event.type == MOUSE_CLICK.SCROLL_DOWN then
|
||||||
scroll_down()
|
scroll_down()
|
||||||
elseif event.type == CLICK_TYPE.SCROLL_UP then
|
elseif event.type == MOUSE_CLICK.SCROLL_UP then
|
||||||
scroll_up()
|
scroll_up()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -14,8 +14,8 @@ events.CLICK_BUTTON = {
|
|||||||
MID_BUTTON = 3
|
MID_BUTTON = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
---@enum CLICK_TYPE
|
---@enum MOUSE_CLICK
|
||||||
events.CLICK_TYPE = {
|
local MOUSE_CLICK = {
|
||||||
TAP = 1, -- screen tap (complete click)
|
TAP = 1, -- screen tap (complete click)
|
||||||
DOWN = 2, -- button down
|
DOWN = 2, -- button down
|
||||||
UP = 3, -- button up (completed a click)
|
UP = 3, -- button up (completed a click)
|
||||||
@ -24,6 +24,18 @@ events.CLICK_TYPE = {
|
|||||||
SCROLL_UP = 6 -- scroll up
|
SCROLL_UP = 6 -- scroll up
|
||||||
}
|
}
|
||||||
|
|
||||||
|
events.MOUSE_CLICK = MOUSE_CLICK
|
||||||
|
|
||||||
|
---@enum KEY_CLICK
|
||||||
|
local KEY_CLICK = {
|
||||||
|
DOWN = 1,
|
||||||
|
HELD = 2,
|
||||||
|
UP = 3,
|
||||||
|
CHAR = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
events.KEY_CLICK = KEY_CLICK
|
||||||
|
|
||||||
-- create a new 2D coordinate
|
-- create a new 2D coordinate
|
||||||
---@param x integer
|
---@param x integer
|
||||||
---@param y integer
|
---@param y integer
|
||||||
@ -35,13 +47,25 @@ events.new_coord_2d = _coord2d
|
|||||||
---@class mouse_interaction
|
---@class mouse_interaction
|
||||||
---@field monitor string
|
---@field monitor string
|
||||||
---@field button CLICK_BUTTON
|
---@field button CLICK_BUTTON
|
||||||
---@field type CLICK_TYPE
|
---@field type MOUSE_CLICK
|
||||||
---@field initial coordinate_2d
|
---@field initial coordinate_2d
|
||||||
---@field current coordinate_2d
|
---@field current coordinate_2d
|
||||||
|
|
||||||
|
---@class key_interaction
|
||||||
|
---@field type KEY_CLICK
|
||||||
|
---@field key number key code
|
||||||
|
---@field name string key character name
|
||||||
|
---@field shift boolean shift held
|
||||||
|
---@field ctrl boolean ctrl held
|
||||||
|
---@field alt boolean alt held
|
||||||
|
|
||||||
local handler = {
|
local handler = {
|
||||||
-- left, right, middle button down tracking
|
-- left, right, middle button down tracking
|
||||||
button_down = { _coord2d(0, 0), _coord2d(0, 0), _coord2d(0, 0) }
|
button_down = { _coord2d(0, 0), _coord2d(0, 0), _coord2d(0, 0) },
|
||||||
|
-- keyboard modifiers
|
||||||
|
shift = false,
|
||||||
|
alt = false,
|
||||||
|
ctrl = false
|
||||||
}
|
}
|
||||||
|
|
||||||
-- create a new monitor touch mouse interaction event
|
-- create a new monitor touch mouse interaction event
|
||||||
@ -54,7 +78,7 @@ local function _monitor_touch(monitor, x, y)
|
|||||||
return {
|
return {
|
||||||
monitor = monitor,
|
monitor = monitor,
|
||||||
button = events.CLICK_BUTTON.GENERIC,
|
button = events.CLICK_BUTTON.GENERIC,
|
||||||
type = events.CLICK_TYPE.TAP,
|
type = MOUSE_CLICK.TAP,
|
||||||
initial = _coord2d(x, y),
|
initial = _coord2d(x, y),
|
||||||
current = _coord2d(x, y)
|
current = _coord2d(x, y)
|
||||||
}
|
}
|
||||||
@ -63,7 +87,7 @@ end
|
|||||||
-- create a new mouse button mouse interaction event
|
-- create a new mouse button mouse interaction event
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param button CLICK_BUTTON mouse button
|
---@param button CLICK_BUTTON mouse button
|
||||||
---@param type CLICK_TYPE click type
|
---@param type MOUSE_CLICK click type
|
||||||
---@param x1 integer initial x
|
---@param x1 integer initial x
|
||||||
---@param y1 integer initial y
|
---@param y1 integer initial y
|
||||||
---@param x2 integer current x
|
---@param x2 integer current x
|
||||||
@ -81,7 +105,7 @@ end
|
|||||||
|
|
||||||
-- create a new generic mouse interaction event
|
-- create a new generic mouse interaction event
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param type CLICK_TYPE
|
---@param type MOUSE_CLICK
|
||||||
---@param x integer
|
---@param x integer
|
||||||
---@param y integer
|
---@param y integer
|
||||||
---@return mouse_interaction
|
---@return mouse_interaction
|
||||||
@ -113,8 +137,8 @@ end
|
|||||||
|
|
||||||
-- check if an event qualifies as a click (tap or up)
|
-- check if an event qualifies as a click (tap or up)
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param t CLICK_TYPE
|
---@param t MOUSE_CLICK
|
||||||
function events.was_clicked(t) return t == events.CLICK_TYPE.TAP or t == events.CLICK_TYPE.UP end
|
function events.was_clicked(t) return t == MOUSE_CLICK.TAP or t == MOUSE_CLICK.UP end
|
||||||
|
|
||||||
-- create a new mouse event to pass onto graphics renderer<br>
|
-- create a new mouse event to pass onto graphics renderer<br>
|
||||||
-- supports: mouse_click, mouse_up, mouse_drag, mouse_scroll, and monitor_touch
|
-- supports: mouse_click, mouse_up, mouse_drag, mouse_scroll, and monitor_touch
|
||||||
@ -127,32 +151,65 @@ function events.new_mouse_event(event_type, opt, x, y)
|
|||||||
if event_type == "mouse_click" then
|
if event_type == "mouse_click" then
|
||||||
---@cast opt 1|2|3
|
---@cast opt 1|2|3
|
||||||
handler.button_down[opt] = _coord2d(x, y)
|
handler.button_down[opt] = _coord2d(x, y)
|
||||||
return _mouse_event(opt, events.CLICK_TYPE.DOWN, x, y, x, y)
|
return _mouse_event(opt, MOUSE_CLICK.DOWN, x, y, x, y)
|
||||||
elseif event_type == "mouse_up" then
|
elseif event_type == "mouse_up" then
|
||||||
---@cast opt 1|2|3
|
---@cast opt 1|2|3
|
||||||
local initial = handler.button_down[opt] ---@type coordinate_2d
|
local initial = handler.button_down[opt] ---@type coordinate_2d
|
||||||
return _mouse_event(opt, events.CLICK_TYPE.UP, initial.x, initial.y, x, y)
|
return _mouse_event(opt, MOUSE_CLICK.UP, initial.x, initial.y, x, y)
|
||||||
elseif event_type == "monitor_touch" then
|
elseif event_type == "monitor_touch" then
|
||||||
---@cast opt string
|
---@cast opt string
|
||||||
return _monitor_touch(opt, x, y)
|
return _monitor_touch(opt, x, y)
|
||||||
elseif event_type == "mouse_drag" then
|
elseif event_type == "mouse_drag" then
|
||||||
---@cast opt 1|2|3
|
---@cast opt 1|2|3
|
||||||
local initial = handler.button_down[opt] ---@type coordinate_2d
|
local initial = handler.button_down[opt] ---@type coordinate_2d
|
||||||
return _mouse_event(opt, events.CLICK_TYPE.DRAG, initial.x, initial.y, x, y)
|
return _mouse_event(opt, MOUSE_CLICK.DRAG, initial.x, initial.y, x, y)
|
||||||
elseif event_type == "mouse_scroll" then
|
elseif event_type == "mouse_scroll" then
|
||||||
---@cast opt 1|-1
|
---@cast opt 1|-1
|
||||||
local scroll_direction = util.trinary(opt == 1, events.CLICK_TYPE.SCROLL_DOWN, events.CLICK_TYPE.SCROLL_UP)
|
local scroll_direction = util.trinary(opt == 1, MOUSE_CLICK.SCROLL_DOWN, MOUSE_CLICK.SCROLL_UP)
|
||||||
return _mouse_event(events.CLICK_BUTTON.GENERIC, scroll_direction, x, y, x, y)
|
return _mouse_event(events.CLICK_BUTTON.GENERIC, scroll_direction, x, y, x, y)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- create a new key event to pass onto graphics renderer<br>
|
-- create a new keyboard interaction event
|
||||||
|
---@nodiscard
|
||||||
|
---@param click_type KEY_CLICK key click type
|
||||||
|
---@param key integer|string keyboard key code or character for 'char' event
|
||||||
|
---@return key_interaction
|
||||||
|
local function _key_event(click_type, key)
|
||||||
|
local name = key
|
||||||
|
if type(key) == "number" then name = keys.getName(key) end
|
||||||
|
return { type = click_type, key = key, name = name, shift = handler.shift, ctrl = handler.ctrl, alt = handler.alt }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- create a new keyboard event to pass onto graphics renderer<br>
|
||||||
-- supports: char, key, and key_up
|
-- supports: char, key, and key_up
|
||||||
---@param event_type os_event
|
---@param event_type os_event OS event to handle
|
||||||
function events.new_key_event(event_type)
|
---@param key integer keyboard key code
|
||||||
|
---@param held boolean? if the key is being held (for 'key' event)
|
||||||
|
---@return key_interaction|nil
|
||||||
|
function events.new_key_event(event_type, key, held)
|
||||||
if event_type == "char" then
|
if event_type == "char" then
|
||||||
|
return _key_event(KEY_CLICK.CHAR, key)
|
||||||
elseif event_type == "key" then
|
elseif event_type == "key" then
|
||||||
|
if key == keys.leftShift or key == keys.rightShift then
|
||||||
|
handler.shift = true
|
||||||
|
elseif key == keys.leftCtrl or key == keys.rightCtrl then
|
||||||
|
handler.ctrl = true
|
||||||
|
elseif key == keys.leftAlt or key == keys.rightAlt then
|
||||||
|
handler.alt = true
|
||||||
|
else
|
||||||
|
return _key_event(util.trinary(held, KEY_CLICK.HELD, KEY_CLICK.DOWN), key)
|
||||||
|
end
|
||||||
elseif event_type == "key_up" then
|
elseif event_type == "key_up" then
|
||||||
|
if key == keys.leftShift or key == keys.rightShift then
|
||||||
|
handler.shift = false
|
||||||
|
elseif key == keys.leftCtrl or key == keys.rightCtrl then
|
||||||
|
handler.ctrl = false
|
||||||
|
elseif key == keys.leftAlt or key == keys.rightAlt then
|
||||||
|
handler.alt = false
|
||||||
|
else
|
||||||
|
return _key_event(KEY_CLICK.UP, key)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user