#344 work in progress on text field & paste events, re-show number field on val/min/max changes

This commit is contained in:
Mikayla Fischler 2023-09-19 23:51:58 -04:00
parent 7a87499aa4
commit a2182d9566
4 changed files with 207 additions and 4 deletions

View File

@ -34,6 +34,7 @@ local element = {}
---|switch_button_args
---|tabbar_args
---|number_field_args
---|text_field_args
---|alarm_indicator_light
---|core_map_args
---|data_indicator_args
@ -340,6 +341,10 @@ function element.new(args, child_offset_x, child_offset_y)
---@param event key_interaction key interaction event
function protected.handle_key(event) end
-- handle a paste event
---@param text string pasted text
function protected.handle_paste(text) end
-- handle data value changes
---@vararg any value(s)
function protected.on_update(...) end
@ -603,6 +608,7 @@ function element.new(args, child_offset_x, child_offset_y)
if protected.enabled then
protected.enabled = false
protected.disable()
public.unfocus_all()
end
end
@ -614,7 +620,7 @@ function element.new(args, child_offset_x, child_offset_y)
-- focus the element
function public.focus()
if args.can_focus and not self.focused then
if args.can_focus and protected.enabled and not self.focused then
self.focused = true
protected.on_focused()
end
@ -698,6 +704,16 @@ function element.new(args, child_offset_x, child_offset_y)
end
end
-- handle text paste
---@param text string pasted text
function public.handle_paste(text)
if protected.window.isVisible() then
-- handle the paste event then pass to children
if self.focused then protected.handle_paste(text) end
for _, child in pairs(protected.children) do child.get().handle_paste(text) end
end
end
-- draw the element given new data
---@vararg any new data
function public.update(...) protected.on_update(...) end

View File

@ -131,6 +131,7 @@ local function push_button(args)
end
end
-- handle focus change
e.on_focused = show_pressed
e.on_unfocused = show_unpressed

View File

@ -98,15 +98,24 @@ local function number_field(args)
-- set the value
---@param val number number to show
function e.set_value(val) e.value = val end
function e.set_value(val)
e.value = val
show()
end
-- set minimum input value
---@param min integer minimum allowed value
function e.set_min(min) args.min = min end
function e.set_min(min)
args.min = min
show()
end
-- set maximum input value
---@param max integer maximum allowed value
function e.set_max(max) args.max = max end
function e.set_max(max)
args.max = max
show()
end
-- handle focused
e.on_focused = show

View File

@ -0,0 +1,177 @@
-- Text 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
local MOUSE_CLICK = core.events.MOUSE_CLICK
---@class text_field_args
---@field value? string initial value
---@field max_len? integer maximum string length
---@field dis_fg_bg? cpair foreground/background colors when disabled
---@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 text entry field
---@param args text_field_args
---@return graphics_element element, element_id id
local function text_field(args)
args.height = 1
args.can_focus = true
-- create new graphics element base object
local e = element.new(args)
-- set initial value
e.value = args.value or ""
local max_len = 1000 -- temporary
local frame_start = 1
local visible_text = e.value
local cursor_pos = string.len(visible_text) + 1
local function frame__update_visible()
visible_text = string.sub(e.value, frame_start, frame_start + math.min(string.len(e.value), args.width) - 1)
end
-- draw input
local function show()
frame__update_visible()
if e.enabled then
e.w_set_bkg(args.fg_bg.bkg)
e.w_set_fgd(args.fg_bg.fgd)
else
e.w_set_bkg(args.dis_fg_bg.bkg)
e.w_set_fgd(args.dis_fg_bg.fgd)
end
-- clear and print
e.w_set_cur(1, 1)
e.w_write(string.rep(" ", e.frame.w))
e.w_set_cur(1, 1)
if e.is_focused() and e.enabled then
-- write text with cursor
if cursor_pos == (string.len(visible_text) + 1) then
-- write text with cursor at the end, no need to blit
e.w_write(visible_text)
e.w_set_fgd(colors.lightGray)
e.w_write("_")
else
local a, b = "", ""
if cursor_pos <= string.len(visible_text) then
a = args.fg_bg.blit_bkg
b = args.fg_bg.blit_fgd
end
local b_fgd = string.rep(args.fg_bg.blit_fgd, cursor_pos - 1) .. a .. string.rep(args.fg_bg.blit_fgd, string.len(visible_text) - cursor_pos)
local b_bkg = string.rep(args.fg_bg.blit_bkg, cursor_pos - 1) .. b .. string.rep(args.fg_bg.blit_bkg, string.len(visible_text) - cursor_pos)
e.w_blit(visible_text, b_fgd, b_bkg)
end
else
-- write text without cursor
e.w_write(visible_text)
end
end
local function frame__try_lshift()
if frame_start > 1 then
frame_start = frame_start - 1
show()
end
end
local function frame__try_rshift()
if (frame_start + args.width - 1) < string.len(e.value) then
frame_start = frame_start + 1
show()
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()
if event.type == MOUSE_CLICK.UP then
cursor_pos = math.min(event.current.x, string.len(visible_text) + 1)
show()
end
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) < max_len then
e.value = string.sub(e.value, 1, frame_start + cursor_pos - 2) .. event.name .. string.sub(e.value, frame_start + cursor_pos - 1, string.len(e.value))
frame__update_visible()
if cursor_pos <= string.len(visible_text) then
cursor_pos = cursor_pos + 1
show()
else frame__try_rshift() end
elseif event.type == KEY_CLICK.DOWN or event.type == KEY_CLICK.HELD then
if (event.key == keys.backspace or event.key == keys.delete) then
-- remove charcter at cursor
e.value = string.sub(e.value, 1, frame_start + cursor_pos - 3) .. string.sub(e.value, frame_start + cursor_pos - 1, string.len(e.value))
if cursor_pos > 1 then
cursor_pos = cursor_pos - 1
show()
else frame__try_lshift() end
elseif event.key == keys.left then
if cursor_pos > 1 then
cursor_pos = cursor_pos - 1
show()
else frame__try_lshift() end
elseif event.key == keys.right then
if cursor_pos <= string.len(visible_text) then
cursor_pos = cursor_pos + 1
show()
else frame__try_rshift() end
end
end
end
-- set the value
---@param val string string to show
function e.set_value(val)
e.value = val
frame_start = 1 + math.max(0, string.len(val) - args.width)
frame__update_visible()
cursor_pos = string.len(visible_text) + 1
show()
end
function e.handle_paste(text)
e.set_value(text)
end
-- handle focus
e.on_focused = show
e.on_unfocused = show
-- on enable/disable
e.enable = show
e.disable = show
-- initial draw
show()
return e.complete()
end
return text_field