2023-09-17 01:06:16 +00:00
|
|
|
-- Numeric Value Entry Graphics Element
|
|
|
|
|
|
|
|
local core = require("graphics.core")
|
|
|
|
local element = require("graphics.element")
|
|
|
|
|
|
|
|
local KEY_CLICK = core.events.KEY_CLICK
|
2023-09-23 16:49:31 +00:00
|
|
|
local MOUSE_CLICK = core.events.MOUSE_CLICK
|
2023-09-17 01:06:16 +00:00
|
|
|
|
|
|
|
---@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
|
2023-09-17 04:12:14 +00:00
|
|
|
---@field dis_fg_bg? cpair foreground/background colors when disabled
|
2023-09-17 01:06:16 +00:00
|
|
|
---@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
|
|
|
|
|
2023-09-17 04:12:14 +00:00
|
|
|
-- new numeric entry field
|
2023-09-17 01:06:16 +00:00
|
|
|
---@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
|
2023-09-23 16:49:31 +00:00
|
|
|
e.value = "" .. (args.default or 0)
|
|
|
|
|
|
|
|
-- make an interactive field manager
|
|
|
|
local ifield = core.new_ifield(e, args.max_digits, args.fg_bg, args.dis_fg_bg)
|
|
|
|
|
2023-09-17 01:06:16 +00:00
|
|
|
|
2023-09-17 04:12:14 +00:00
|
|
|
-- draw input
|
2023-09-17 01:06:16 +00:00
|
|
|
local function show()
|
2023-09-17 04:12:14 +00:00
|
|
|
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
|
|
|
|
|
2023-09-17 01:06:16 +00:00
|
|
|
-- 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_write(e.value)
|
2023-09-17 04:12:14 +00:00
|
|
|
|
|
|
|
-- show cursor if focused
|
|
|
|
if e.is_focused() and e.enabled then
|
2023-09-17 01:06:16 +00:00
|
|
|
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
|
2023-09-23 16:49:31 +00:00
|
|
|
if e.enabled then
|
|
|
|
if core.events.was_clicked(event.type) then
|
|
|
|
e.req_focus()
|
|
|
|
|
|
|
|
if event.type == MOUSE_CLICK.UP then
|
|
|
|
ifield.move_cursor(event.current.x)
|
|
|
|
end
|
|
|
|
elseif event.type == MOUSE_CLICK.DOUBLE_CLICK then
|
|
|
|
ifield.select_all()
|
|
|
|
end
|
2023-09-17 01:06:16 +00:00
|
|
|
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
|
2023-09-23 16:49:31 +00:00
|
|
|
if e.value == 0 then e.value = "" end
|
|
|
|
ifield.try_insert_char(event.name)
|
2023-09-17 01:06:16 +00:00
|
|
|
end
|
|
|
|
elseif event.type == KEY_CLICK.DOWN then
|
|
|
|
if (event.key == keys.backspace or event.key == keys.delete) and (string.len(e.value) > 0) then
|
2023-09-23 16:49:31 +00:00
|
|
|
ifield.backspace()
|
2023-09-17 01:06:16 +00:00
|
|
|
has_decimal = string.find(e.value, "%.") ~= nil
|
|
|
|
elseif (event.key == keys.period or event.key == keys.numPadDecimal) and (not has_decimal) and args.allow_decimal then
|
|
|
|
has_decimal = true
|
2023-09-23 16:49:31 +00:00
|
|
|
ifield.try_insert_char(".")
|
2023-09-17 01:06:16 +00:00
|
|
|
elseif (event.key == keys.minus or event.key == keys.numPadSubtract) and (string.len(e.value) == 0) and args.allow_negative then
|
2023-09-23 16:49:31 +00:00
|
|
|
ifield.set_value("-")
|
|
|
|
elseif event.key == keys.left then
|
|
|
|
ifield.nav_left()
|
|
|
|
elseif event.key == keys.right then
|
|
|
|
ifield.nav_right()
|
|
|
|
elseif event.key == keys.a and event.ctrl then
|
|
|
|
ifield.select_all()
|
2023-09-17 01:06:16 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-09-23 16:49:31 +00:00
|
|
|
-- set the value (must be a number)
|
2023-09-17 01:06:16 +00:00
|
|
|
---@param val number number to show
|
2023-09-20 03:51:58 +00:00
|
|
|
function e.set_value(val)
|
2023-09-23 16:49:31 +00:00
|
|
|
if tonumber(val) then
|
|
|
|
ifield.set_value("" .. tonumber(val))
|
|
|
|
end
|
2023-09-20 03:51:58 +00:00
|
|
|
end
|
2023-09-17 01:06:16 +00:00
|
|
|
|
|
|
|
-- set minimum input value
|
|
|
|
---@param min integer minimum allowed value
|
2023-09-23 16:49:31 +00:00
|
|
|
function e.set_min(min) args.min = min end
|
2023-09-17 01:06:16 +00:00
|
|
|
|
|
|
|
-- set maximum input value
|
|
|
|
---@param max integer maximum allowed value
|
2023-09-23 16:49:31 +00:00
|
|
|
function e.set_max(max) args.max = max end
|
|
|
|
|
|
|
|
-- replace text with pasted text if its a number
|
|
|
|
---@param text string string pasted
|
|
|
|
function e.handle_paste(text)
|
|
|
|
if tonumber(text) then
|
|
|
|
ifield.set_value("" .. tonumber(text))
|
|
|
|
else
|
|
|
|
ifield.set_value("0")
|
|
|
|
end
|
2023-09-20 03:51:58 +00:00
|
|
|
end
|
2023-09-17 01:06:16 +00:00
|
|
|
|
2023-09-17 04:12:14 +00:00
|
|
|
-- handle focused
|
2023-09-17 01:06:16 +00:00
|
|
|
e.on_focused = show
|
|
|
|
|
2023-09-17 04:12:14 +00:00
|
|
|
-- handle unfocused
|
2023-09-17 01:06:16 +00:00
|
|
|
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
|
|
|
|
|
2023-09-23 16:49:31 +00:00
|
|
|
ifield.show()
|
2023-09-17 01:06:16 +00:00
|
|
|
end
|
|
|
|
|
2023-09-17 04:12:14 +00:00
|
|
|
-- on enable/disable
|
2023-09-23 16:49:31 +00:00
|
|
|
e.enable = ifield.show
|
|
|
|
e.disable = ifield.show
|
2023-09-17 01:06:16 +00:00
|
|
|
|
|
|
|
-- initial draw
|
2023-09-23 16:49:31 +00:00
|
|
|
ifield.show()
|
2023-09-17 01:06:16 +00:00
|
|
|
|
|
|
|
return e.complete()
|
|
|
|
end
|
|
|
|
|
|
|
|
return number_field
|