mirror of
https://github.com/airstruck/luigi.git
synced 2026-01-10 08:18:22 +00:00
text entry, partial support
This commit is contained in:
@@ -19,7 +19,7 @@ end
|
|||||||
|
|
||||||
local eventNames = {
|
local eventNames = {
|
||||||
'Reshape', -- widget's dimensions changed
|
'Reshape', -- widget's dimensions changed
|
||||||
'Display', -- widget is being drawn
|
'PreDisplay', 'Display', -- before/after widget is drawn
|
||||||
'KeyPress', 'KeyRelease', -- keyboard key pressed/released
|
'KeyPress', 'KeyRelease', -- keyboard key pressed/released
|
||||||
'TextInput', -- text is entered
|
'TextInput', -- text is entered
|
||||||
'Move', -- cursor moves, no button pressed
|
'Move', -- cursor moves, no button pressed
|
||||||
@@ -29,7 +29,7 @@ local eventNames = {
|
|||||||
'PressDrag', -- pressed cursor moves, targets originating widget
|
'PressDrag', -- pressed cursor moves, targets originating widget
|
||||||
'PressMove', -- pressed cursor moves, targets widget at cursor position
|
'PressMove', -- pressed cursor moves, targets widget at cursor position
|
||||||
'Press', -- cursor is pressed and released on same widget
|
'Press', -- cursor is pressed and released on same widget
|
||||||
'Change', -- widget's value changed via Widget:setValue
|
'Change', -- widget's value changed via Widget:setValue
|
||||||
}
|
}
|
||||||
|
|
||||||
local weakKeyMeta = { __mode = 'k' }
|
local weakKeyMeta = { __mode = 'k' }
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ end
|
|||||||
function Input:handlePressEnd (button, x, y, widget, accelerator)
|
function Input:handlePressEnd (button, x, y, widget, accelerator)
|
||||||
local widget = widget or self.layout:getWidgetAt(x, y)
|
local widget = widget or self.layout:getWidgetAt(x, y)
|
||||||
local originWidget = self.pressedWidgets[button]
|
local originWidget = self.pressedWidgets[button]
|
||||||
|
if not originWidget then return end
|
||||||
originWidget.pressed = nil
|
originWidget.pressed = nil
|
||||||
widget:bubbleEvent('PressEnd', {
|
widget:bubbleEvent('PressEnd', {
|
||||||
origin = originWidget,
|
origin = originWidget,
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ local Hooker = require(ROOT .. 'hooker')
|
|||||||
|
|
||||||
local Layout = Base:extend()
|
local Layout = Base:extend()
|
||||||
|
|
||||||
local weakValueMeta = { __mode = 'v' }
|
|
||||||
|
|
||||||
function Layout:constructor (data)
|
function Layout:constructor (data)
|
||||||
self.accelerators = {}
|
self.accelerators = {}
|
||||||
self:setStyle()
|
self:setStyle()
|
||||||
@@ -19,9 +17,9 @@ function Layout:constructor (data)
|
|||||||
self.isMousePressed = false
|
self.isMousePressed = false
|
||||||
self.isManagingInput = false
|
self.isManagingInput = false
|
||||||
self.hooks = {}
|
self.hooks = {}
|
||||||
self.root = Widget(self, data or {})
|
self.root = Widget(self, data)
|
||||||
|
|
||||||
self:addDefaultHandlers ()
|
self:addDefaultHandlers()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- focus a widget if it's focusable, and return success
|
-- focus a widget if it's focusable, and return success
|
||||||
@@ -110,7 +108,8 @@ function Layout:addDefaultHandlers ()
|
|||||||
|
|
||||||
-- space / enter presses focused widget
|
-- space / enter presses focused widget
|
||||||
local widget = self.focusedWidget
|
local widget = self.focusedWidget
|
||||||
if widget and (event.key == 'return' or event.key == 'space') then
|
if widget and event.key == 'space' or event.key == ' '
|
||||||
|
or event.key == 'return' then
|
||||||
self.input:handlePressStart(event.key, event.x, event.y,
|
self.input:handlePressStart(event.key, event.x, event.y,
|
||||||
widget, event.key)
|
widget, event.key)
|
||||||
return
|
return
|
||||||
@@ -130,7 +129,8 @@ function Layout:addDefaultHandlers ()
|
|||||||
|
|
||||||
-- space / enter presses focused widget
|
-- space / enter presses focused widget
|
||||||
local widget = self.focusedWidget
|
local widget = self.focusedWidget
|
||||||
if widget and (event.key == 'return' or event.key == 'space') then
|
if widget and event.key == 'space' or event.key == ' '
|
||||||
|
or event.key == 'return' then
|
||||||
self.input:handlePressEnd(event.key, event.x, event.y,
|
self.input:handlePressEnd(event.key, event.x, event.y,
|
||||||
widget, event.key)
|
widget, event.key)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -252,13 +252,14 @@ function Renderer:renderChildren (widget)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Renderer:render (widget)
|
function Renderer:render (widget)
|
||||||
Event.Display:emit(widget, { target = widget }, function()
|
Event.PreDisplay:emit(widget, { target = widget }, function()
|
||||||
self:renderBackground(widget)
|
self:renderBackground(widget)
|
||||||
self:renderOutline(widget)
|
self:renderOutline(widget)
|
||||||
self:renderSlices(widget)
|
self:renderSlices(widget)
|
||||||
self:renderIconAndText(widget)
|
self:renderIconAndText(widget)
|
||||||
return self:renderChildren(widget)
|
return self:renderChildren(widget)
|
||||||
end)
|
end)
|
||||||
|
Event.Display:emit(widget, { target = widget })
|
||||||
end
|
end
|
||||||
|
|
||||||
return Renderer
|
return Renderer
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ return function (config)
|
|||||||
|
|
||||||
local backColor = config.backColor or { 240, 240, 240 }
|
local backColor = config.backColor or { 240, 240, 240 }
|
||||||
local lineColor = config.lineColor or { 220, 220, 220 }
|
local lineColor = config.lineColor or { 220, 220, 220 }
|
||||||
local white = config.white or { 255, 255, 255 }
|
|
||||||
local highlight = config.highlight or { 0x19, 0xAE, 0xFF }
|
local highlight = config.highlight or { 0x19, 0xAE, 0xFF }
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -64,6 +63,7 @@ return function (config)
|
|||||||
minimumHeight = 24,
|
minimumHeight = 24,
|
||||||
canFocus = true,
|
canFocus = true,
|
||||||
cursor = 'ibeam',
|
cursor = 'ibeam',
|
||||||
|
highlight = highlight,
|
||||||
},
|
},
|
||||||
text_focused = {
|
text_focused = {
|
||||||
slices = RESOURCE .. 'text_focused.png',
|
slices = RESOURCE .. 'text_focused.png',
|
||||||
|
|||||||
Binary file not shown.
@@ -1,3 +1,160 @@
|
|||||||
return function (self)
|
local utf8 = require 'utf8'
|
||||||
|
|
||||||
|
local blendMultiply = love._version_minor < 10 and 'multiplicative'
|
||||||
|
or 'multiply'
|
||||||
|
|
||||||
|
local function setCaretPosition (self, text)
|
||||||
|
local font = self.fontData.font
|
||||||
|
local x1, y1, x2, y2 = self:getRectangle(true, true)
|
||||||
|
self.startIndex = #text
|
||||||
|
self.startX = font:getWidth(text) + x1
|
||||||
|
self.endIndex, self.endX = self.startIndex, self.startX
|
||||||
|
end
|
||||||
|
|
||||||
|
-- return caret index and x position
|
||||||
|
local function getCaretFromEvent (self, event)
|
||||||
|
local x1, y1, x2, y2 = self:getRectangle(true, true)
|
||||||
|
|
||||||
|
if event.x <= x1 then
|
||||||
|
return 0, x1
|
||||||
|
end
|
||||||
|
|
||||||
|
local font = self.fontData.font
|
||||||
|
local width, lastWidth = 0
|
||||||
|
|
||||||
|
for position in utf8.codes(self.value) do
|
||||||
|
local index = utf8.offset(self.value, position)
|
||||||
|
text = self.value:sub(1, index)
|
||||||
|
lastWidth = width
|
||||||
|
width = font:getWidth(text)
|
||||||
|
if width > event.x - x1 then
|
||||||
|
if position == 1 then
|
||||||
|
return 0, x1
|
||||||
|
end
|
||||||
|
return utf8.offset(self.value, position - 1), lastWidth + x1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return #self.value, width + x1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getRange (self)
|
||||||
|
if self.startIndex <= self.endIndex then
|
||||||
|
return self.startIndex, self.endIndex
|
||||||
|
end
|
||||||
|
|
||||||
|
return self.endIndex, self.startIndex
|
||||||
|
end
|
||||||
|
|
||||||
|
return function (self)
|
||||||
|
self.value = self.value or self.text or ''
|
||||||
|
self.text = ''
|
||||||
|
self:setValue(self.value)
|
||||||
|
self.highlight = self.highlight or { 0x80, 0x80, 0x80 }
|
||||||
|
|
||||||
|
self:onPressStart(function (event)
|
||||||
|
self.startIndex, self.startX = getCaretFromEvent(self, event)
|
||||||
|
self.endIndex, self.endX = self.startIndex, self.startX
|
||||||
|
end)
|
||||||
|
|
||||||
|
self:onPressMove(function (event)
|
||||||
|
self.endIndex, self.endX = getCaretFromEvent(self, event)
|
||||||
|
end)
|
||||||
|
|
||||||
|
self:onTextInput(function (event)
|
||||||
|
local text = self.value
|
||||||
|
local first, last = getRange(self)
|
||||||
|
local left = text:sub(1, first) .. event.text
|
||||||
|
|
||||||
|
self.value = left .. text:sub(last + 1)
|
||||||
|
self:setValue(self.value)
|
||||||
|
setCaretPosition(self, left)
|
||||||
|
end)
|
||||||
|
|
||||||
|
self:onKeyPress(function (event)
|
||||||
|
if event.key == 'backspace' then
|
||||||
|
|
||||||
|
local text = self.value
|
||||||
|
local first, last = getRange(self)
|
||||||
|
|
||||||
|
-- if expanded range is selected, delete text in range
|
||||||
|
if first ~= last then
|
||||||
|
local left = text:sub(1, first)
|
||||||
|
self.value = left .. text:sub(last + 1)
|
||||||
|
self:setValue(self.value)
|
||||||
|
setCaretPosition(self, left)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if cursor is at beginning, do nothing
|
||||||
|
if first < 1 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- delete character to the left
|
||||||
|
local offset = utf8.offset(self.value, -1, first) or 0
|
||||||
|
local left = self.value:sub(1, offset)
|
||||||
|
self.value = left .. self.value:sub(first + 1)
|
||||||
|
self:setValue(self.value)
|
||||||
|
setCaretPosition(self, left)
|
||||||
|
|
||||||
|
elseif event.key == 'left' then
|
||||||
|
|
||||||
|
local text, endIndex = self.value, self.endIndex
|
||||||
|
|
||||||
|
-- if cursor is at beginning, do nothing
|
||||||
|
if endIndex < 1 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- move cursor left
|
||||||
|
local offset = utf8.offset(text, -1, endIndex) or 0
|
||||||
|
|
||||||
|
setCaretPosition(self, text:sub(1, offset))
|
||||||
|
|
||||||
|
elseif event.key == 'right' then
|
||||||
|
|
||||||
|
local text, endIndex = self.value, self.endIndex
|
||||||
|
|
||||||
|
-- if cursor is at end, do nothing
|
||||||
|
if endIndex == #text then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local offset = endIndex < 1 and utf8.offset(text, 1)
|
||||||
|
or utf8.offset(text, 2, endIndex) or #text
|
||||||
|
|
||||||
|
-- move cursor right
|
||||||
|
setCaretPosition(self, text:sub(1, offset))
|
||||||
|
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end)
|
||||||
|
|
||||||
|
self:onDisplay(function (event)
|
||||||
|
local startX, endX = self.startX or 0, self.endX or 0
|
||||||
|
local x1, y1, x2, y2 = self:getRectangle(true, true)
|
||||||
|
local width, height = endX - startX, y2 - y1
|
||||||
|
local fontData = self.fontData
|
||||||
|
local font = fontData.font
|
||||||
|
local textColor = fontData.color
|
||||||
|
local textTop = math.floor(y1 + ((y2 - y1) - font:getHeight()) / 2)
|
||||||
|
|
||||||
|
love.graphics.push('all')
|
||||||
|
love.graphics.setFont(font)
|
||||||
|
love.graphics.setColor(textColor)
|
||||||
|
love.graphics.print(self.value, x1, textTop)
|
||||||
|
if not self.focused then
|
||||||
|
love.graphics.pop()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
love.graphics.setBlendMode(blendMultiply)
|
||||||
|
love.graphics.setColor(self.highlight)
|
||||||
|
love.graphics.rectangle('fill', startX, y1, width, height)
|
||||||
|
if love.timer.getTime() % 2 < 1.75 then
|
||||||
|
love.graphics.setColor(textColor)
|
||||||
|
love.graphics.rectangle('fill', endX, y1, 1, height)
|
||||||
|
end
|
||||||
|
love.graphics.pop()
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user