2023-09-20 03:51:58 +00:00
|
|
|
-- Text Value Entry Graphics Element
|
|
|
|
|
|
|
|
local util = require("scada-common.util")
|
2023-09-23 04:09:37 +00:00
|
|
|
local events = require("graphics.events")
|
2023-09-20 03:51:58 +00:00
|
|
|
|
|
|
|
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 ""
|
|
|
|
|
2023-09-23 04:09:37 +00:00
|
|
|
local max_len = args.max_len or e.frame.w
|
2023-09-20 03:51:58 +00:00
|
|
|
local frame_start = 1
|
|
|
|
local visible_text = e.value
|
|
|
|
local cursor_pos = string.len(visible_text) + 1
|
|
|
|
|
|
|
|
local function frame__update_visible()
|
2023-09-23 04:09:37 +00:00
|
|
|
visible_text = string.sub(e.value, frame_start, frame_start + math.min(string.len(e.value), e.frame.w) - 1)
|
2023-09-20 03:51:58 +00:00
|
|
|
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
|
2023-09-23 04:09:37 +00:00
|
|
|
return true
|
2023-09-20 03:51:58 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function frame__try_rshift()
|
2023-09-23 04:09:37 +00:00
|
|
|
if (frame_start + e.frame.w - 1) < string.len(e.value) then
|
2023-09-20 03:51:58 +00:00
|
|
|
frame_start = frame_start + 1
|
2023-09-23 04:09:37 +00:00
|
|
|
return true
|
2023-09-20 03:51:58 +00:00
|
|
|
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
|
2023-09-23 04:09:37 +00:00
|
|
|
if e.enabled then
|
|
|
|
if core.events.was_clicked(event.type) then
|
|
|
|
e.req_focus()
|
2023-09-20 03:51:58 +00:00
|
|
|
|
2023-09-23 04:09:37 +00:00
|
|
|
if event.type == MOUSE_CLICK.UP then
|
|
|
|
cursor_pos = math.min(event.current.x, string.len(visible_text) + 1)
|
|
|
|
show()
|
|
|
|
end
|
2023-09-20 03:51:58 +00:00
|
|
|
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()
|
2023-09-23 04:09:37 +00:00
|
|
|
elseif frame__try_rshift() then show() end
|
2023-09-20 03:51:58 +00:00
|
|
|
elseif event.type == KEY_CLICK.DOWN or event.type == KEY_CLICK.HELD then
|
|
|
|
if (event.key == keys.backspace or event.key == keys.delete) then
|
2023-09-23 04:09:37 +00:00
|
|
|
-- remove charcter at cursor if there is anything to remove
|
|
|
|
if frame_start + cursor_pos > 2 then
|
|
|
|
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()
|
|
|
|
elseif frame__try_lshift() then show() end
|
|
|
|
end
|
2023-09-20 03:51:58 +00:00
|
|
|
elseif event.key == keys.left then
|
|
|
|
if cursor_pos > 1 then
|
|
|
|
cursor_pos = cursor_pos - 1
|
|
|
|
show()
|
2023-09-23 04:09:37 +00:00
|
|
|
elseif frame__try_lshift() then show() end
|
2023-09-20 03:51:58 +00:00
|
|
|
elseif event.key == keys.right then
|
|
|
|
if cursor_pos <= string.len(visible_text) then
|
|
|
|
cursor_pos = cursor_pos + 1
|
|
|
|
show()
|
2023-09-23 04:09:37 +00:00
|
|
|
elseif frame__try_rshift() then show() end
|
2023-09-20 03:51:58 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- set the value
|
|
|
|
---@param val string string to show
|
|
|
|
function e.set_value(val)
|
2023-09-23 04:09:37 +00:00
|
|
|
e.value = string.sub(val, 1, math.min(max_len, string.len(val)))
|
|
|
|
frame_start = 1 + math.max(0, string.len(val) - e.frame.w)
|
2023-09-20 03:51:58 +00:00
|
|
|
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
|