mirror of
https://codeberg.org/1414codeforge/yui.git
synced 2025-06-05 22:19:11 +02:00
[*] Initial commit.
This commit is contained in:
184
input.lua
Normal file
184
input.lua
Normal file
@ -0,0 +1,184 @@
|
||||
local BASE = (...):gsub('input', '')
|
||||
|
||||
local Widget = require BASE..'widget'
|
||||
local core = require BASE..'core'
|
||||
|
||||
local utf8 = require 'utf8'
|
||||
|
||||
-- Grabs keyboard on focus
|
||||
local Input = setmetatable({ grabkeyboard = true }, Widget)
|
||||
Input.__index = Input
|
||||
|
||||
|
||||
local function split(str, pos)
|
||||
local ofs = utf8.offset(str, pos) or 0
|
||||
return str:sub(1, ofs-1), str:sub(ofs)
|
||||
end
|
||||
|
||||
function Input.new(args)
|
||||
local self = setmetatable(args, Input)
|
||||
|
||||
self.text = self.text or ""
|
||||
self.color = self.color or core.theme.color
|
||||
self.cornerRadius = self.cornerRadius or core.theme.cornerRadius
|
||||
self.cursor = math.max(1, math.min(utf8.len(self.text)+1,
|
||||
self.cursor or utf8.len(self.text)+1))
|
||||
self.candidate = { text = "", start = 0, length = 0 }
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function Input:onPointerInput(px,py, clicked)
|
||||
if clicked then
|
||||
self:grabFocus()
|
||||
|
||||
-- Schedule cursor reposition for next draw()
|
||||
self.px = px
|
||||
self.py = py
|
||||
end
|
||||
end
|
||||
|
||||
function Input:textedited(text, start, length)
|
||||
self.candidate.text = text
|
||||
self.candidate.start = start
|
||||
self.candidate.length = length
|
||||
end
|
||||
|
||||
function Input:textinput(text)
|
||||
if text ~= "" then
|
||||
local a,b = split(self.text, self.cursor)
|
||||
|
||||
self.text = table.concat {a, text, b}
|
||||
self.cursor = self.cursor + utf8.len(text)
|
||||
end
|
||||
end
|
||||
|
||||
function Input:keypressed(key, code, isrepeat)
|
||||
if isrepeat == nil then
|
||||
-- LOVE sends 3 types of keypressed() events,
|
||||
-- 1. with isrepeat = true
|
||||
-- 2. with isrepeat = false
|
||||
-- 3. with isrepeat = nil
|
||||
--
|
||||
-- We're only interested in the first 2.
|
||||
return
|
||||
end
|
||||
|
||||
if self.candidate.length == 0 then
|
||||
if key == 'backspace' then
|
||||
local a,b = split(self.text, self.cursor)
|
||||
|
||||
self.text = table.concat { split(a, utf8.len(a)), b }
|
||||
self.cursor = math.max(1, self.cursor-1)
|
||||
|
||||
elseif key == 'delete' then
|
||||
local a,b = split(self.text, self.cursor)
|
||||
local _,b = split(b, 2)
|
||||
|
||||
self.text = table.concat { a, b }
|
||||
|
||||
elseif key == 'left' then
|
||||
self.cursor = math.max(0, self.cursor-1)
|
||||
|
||||
elseif key == 'right' then
|
||||
self.cursor = math.min(utf8.len(self.text)+1, self.cursor+1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Input:keyreleased(key)
|
||||
if self.candidate.length == 0 then
|
||||
if key == 'home' then
|
||||
self.cursor = 1
|
||||
elseif key == 'end' then
|
||||
self.cursor = utf8.len(self.text)+1
|
||||
elseif key == 'return' then
|
||||
self:onChange(self.text)
|
||||
self.cursor = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Input:draw()
|
||||
-- Cursor position is before the char (including EOS) i.e. in "hello":
|
||||
-- position 1: |hello
|
||||
-- position 2: h|ello
|
||||
-- ...
|
||||
-- position 6: hello|
|
||||
|
||||
local x,y,w,h = self.x,self.y,self.w,self.h
|
||||
local font = self.font or love.graphics.getFont()
|
||||
local th = font:getHeight()
|
||||
local tw = font:getWidth(self.text)
|
||||
|
||||
-- Get size of text and cursor position
|
||||
local cursor_pos = 0
|
||||
if self.cursor > 1 then
|
||||
local s = self.text:sub(1, utf8.offset(self.text, self.cursor)-1)
|
||||
cursor_pos = font:getWidth(s)
|
||||
end
|
||||
|
||||
-- Compute drawing offset
|
||||
if self.px ~= nil then
|
||||
-- Mouse movement
|
||||
local mx = self.px - self.x
|
||||
|
||||
self.cursor = utf8.len(self.text) + 1
|
||||
for c = 1,self.cursor do
|
||||
local s = self.text:sub(0, utf8.offset(self.text, c)-1)
|
||||
if font:getWidth(s) >= mx then
|
||||
self.cursor = c-1
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
self.px,self.py = nil,nil
|
||||
end
|
||||
|
||||
core.drawBox(x,y,w,h, self.color.normal, self.cornerRadius)
|
||||
|
||||
-- Apply text margins
|
||||
w = math.max(w - 6, 0)
|
||||
x = math.min(x + 3, x + w)
|
||||
|
||||
-- Set scissors
|
||||
local sx, sy, sw, sh = love.graphics.getScissor()
|
||||
love.graphics.setScissor(x-1,y,w+2,h)
|
||||
|
||||
-- Text
|
||||
love.graphics.setColor(self.color.normal.fg)
|
||||
love.graphics.setFont(font)
|
||||
love.graphics.print(self.text, x, y + (h-th)/2)
|
||||
|
||||
if self.candidate.length > 0 then
|
||||
-- Candidate text
|
||||
local ctw = font:getWidth(self.candidate.text)
|
||||
|
||||
love.graphics.setColor(self.color.normal.fg)
|
||||
love.graphics.print(self.candidate.text, x + tw, y + (h-th)/2)
|
||||
|
||||
-- Candidate text rectangle box
|
||||
love.graphics.rectangle('line', x + tw, y + (h-th)/2, ctw, th)
|
||||
|
||||
self.candidate.text = ""
|
||||
self.candidate.start = 0
|
||||
self.candidate.length = 0
|
||||
end
|
||||
|
||||
-- Cursor
|
||||
if self:isFocused() and (love.timer.getTime() % 1) > .5 then
|
||||
local ct = self.candidate
|
||||
local ss = ct.text:sub(1, utf8.offset(ct.text, ct.start))
|
||||
local ws = ct.start > 0 and font:getWidth(ss) or 0
|
||||
|
||||
love.graphics.setLineWidth(1)
|
||||
love.graphics.setLineStyle('rough')
|
||||
love.graphics.line(x + cursor_pos + ws, y + (h-th)/2,
|
||||
x + cursor_pos + ws, y + (h+th)/2)
|
||||
end
|
||||
|
||||
-- Reset scissor
|
||||
love.graphics.setScissor(sx,sy,sw,sh)
|
||||
end
|
||||
|
||||
return Input
|
Reference in New Issue
Block a user