suit/input.lua
Whitecl4ws 8404c2ff79 Added both password and label support
Label is set only once when the focus is not on the box, it can also be reset by setting the label again (the label is set to "" when the focus is on the input)
Password can also be toggled on and off depending on your needs
2017-01-28 11:33:10 -05:00

115 lines
3.7 KiB
Lua

-- This file is part of SUIT, copyright (c) 2016 Matthias Richter
local BASE = (...):match('(.-)[^%.]+$')
local utf8 = require 'utf8'
local function split(str, pos)
local offset = utf8.offset(str, pos) or 0
return str:sub(1, offset-1), str:sub(offset)
end
return function(core, input, ...)
local opt, x,y,w,h = core.getOptionsAndSize(...)
opt.id = opt.id or input
opt.font = opt.font or love.graphics.getFont()
local text_width = opt.font:getWidth(input.text)
w = w or text_width + 6
h = h or opt.font:getHeight() + 4
input.label = input.label or ""
input.password = input.password or false
input.text = input.text or ""
if input.label ~= "" then input.text = input.label end
input.cursor = math.max(1, math.min(utf8.len(input.text)+1, input.cursor or utf8.len(input.text)+1))
-- cursor is position *before* the character (including EOS) i.e. in "hello":
-- position 1: |hello
-- position 2: h|ello
-- ...
-- position 6: hello|
-- get size of text and cursor position
opt.cursor_pos = 0
if input.cursor > 1 then
local s = input.text:sub(1, utf8.offset(input.text, input.cursor)-1)
if password then opt.cursor_pos = opt.font:getWidth(string.rep("*", string.len(input.text)))
else opt.cursor_pos = opt.font:getWidth(s) end
end
-- compute drawing offset
local wm = w - 6 -- consider margin
input.text_draw_offset = input.text_draw_offset or 0
if opt.cursor_pos - input.text_draw_offset < 0 then
-- cursor left of input box
input.text_draw_offset = opt.cursor_pos
end
if opt.cursor_pos - input.text_draw_offset > wm then
-- cursor right of input box
input.text_draw_offset = opt.cursor_pos - wm
end
if text_width - input.text_draw_offset < wm and text_width > wm then
-- text bigger than input box, but does not fill it
input.text_draw_offset = text_width - wm
end
-- user interaction
opt.state = core:registerHitbox(opt.id, x,y,w,h)
opt.hasKeyboardFocus = core:grabKeyboardFocus(opt.id)
if opt.hasKeyboardFocus then
if input.label ~= "" then input.text = "" input.label = "" input.cursor = 1 end
local keycode,char = core:getPressedKey()
-- text input
if char and char ~= "" then
local a,b = split(input.text, input.cursor)
input.text = table.concat{a, char, b}
input.cursor = input.cursor + utf8.len(char)
end
-- text editing
if keycode == 'backspace' then
local a,b = split(input.text, input.cursor)
input.text = table.concat{split(a,utf8.len(a)), b}
input.cursor = math.max(1, input.cursor-1)
elseif keycode == 'delete' then
local a,b = split(input.text, input.cursor)
local _,b = split(b, 2)
input.text = table.concat{a, b}
end
-- cursor movement
if keycode =='left' then
input.cursor = math.max(0, input.cursor-1)
elseif keycode =='right' then -- cursor movement
input.cursor = math.min(utf8.len(input.text)+1, input.cursor+1)
elseif keycode =='home' then -- cursor movement
input.cursor = 1
elseif keycode =='end' then -- cursor movement
input.cursor = utf8.len(input.text)+1
end
-- move cursor position with mouse when clicked on
if core:mouseReleasedOn(opt.id) then
local mx = core:getMousePosition() - x + input.text_draw_offset
input.cursor = utf8.len(input.text) + 1
for c = 1,input.cursor do
local s = input.text:sub(0, utf8.offset(input.text, c)-1)
if opt.font:getWidth(s) >= mx then
input.cursor = c-1
break
end
end
end
end
core:registerDraw(opt.draw or core.theme.Input, input, opt, x,y,w,h)
return {
id = opt.id,
hit = core:mouseReleasedOn(opt.id),
submitted = core:keyPressedOn(opt.id, "return"),
hovered = core:isHovered(opt.id),
entered = core:isHovered(opt.id) and not core:wasHovered(opt.id),
left = not core:isHovered(opt.id) and core:wasHovered(opt.id)
}
end