mirror of
https://github.com/airstruck/luigi.git
synced 2025-11-18 12:25:06 +00:00
Clean up text widget.
This fixes a visual bug where the highlighted area wouldn't update when the widget was reshaped, and fixes some weirdness with local functions in preparation for exposing them as part of a rich API for the text widget.
This commit is contained in:
@@ -8,47 +8,38 @@ local ROOT = (...):gsub('[^.]*.[^.]*$', '')
|
||||
local utf8 = require(ROOT .. 'utf8')
|
||||
local Backend = require(ROOT .. 'backend')
|
||||
|
||||
local function updateHighlight (self)
|
||||
local value = self.value
|
||||
local font = self:getFont()
|
||||
local startIndex, endIndex = self.startIndex, self.endIndex
|
||||
local offset = self:getRectangle(true, true) - self.scrollX
|
||||
self.startX = font:getAdvance(value:sub(1, startIndex)) + offset
|
||||
self.endX = font:getAdvance(value:sub(1, endIndex)) + offset
|
||||
end
|
||||
|
||||
local function scrollToCaret (self)
|
||||
local x1, y1, w, h = self:getRectangle(true, true)
|
||||
local x2, y2 = x1 + w, y1 + h
|
||||
local oldX = self.endX
|
||||
local newX
|
||||
local oldX = self.endX or x1
|
||||
|
||||
if oldX <= x1 then
|
||||
self.scrollX = self.scrollX - (x1 - oldX)
|
||||
newX = x1
|
||||
elseif oldX >= x2 then
|
||||
self.scrollX = self.scrollX + (oldX - x2 + 1)
|
||||
newX = x2 - 1
|
||||
end
|
||||
|
||||
if newX then
|
||||
self.endX = newX
|
||||
self.startX = self.startX + (newX - oldX)
|
||||
end
|
||||
updateHighlight(self)
|
||||
end
|
||||
|
||||
local function findCaretFromText (self, text)
|
||||
local font = self:getFont()
|
||||
local x = self:getRectangle(true, true)
|
||||
return #text, font:getAdvance(text) + x - self.scrollX
|
||||
end
|
||||
|
||||
local function setCaretFromText (self, text, mode)
|
||||
local index, x = findCaretFromText(self, text)
|
||||
|
||||
if mode == 'start' or not mode then
|
||||
self.startIndex, self.startX = index, x
|
||||
end
|
||||
if mode == 'end' or not mode then
|
||||
self.endIndex, self.endX = index, x
|
||||
end
|
||||
local function selectRange (self, startIndex, endIndex)
|
||||
if startIndex then self.startIndex = startIndex end
|
||||
if endIndex then self.endIndex = endIndex end
|
||||
|
||||
scrollToCaret(self)
|
||||
end
|
||||
|
||||
-- return caret index and x position
|
||||
local function findCaretFromPoint (self, x, y)
|
||||
-- return caret index
|
||||
local function findIndexFromPoint (self, x, y)
|
||||
local x1 = self:getRectangle(true, true)
|
||||
|
||||
local font = self.fontData
|
||||
@@ -61,54 +52,46 @@ local function findCaretFromPoint (self, x, y)
|
||||
width = font:getAdvance(text)
|
||||
if width > x + self.scrollX - x1 then
|
||||
if position == 1 then
|
||||
return 0, x1 - self.scrollX
|
||||
return 0
|
||||
end
|
||||
return lastPosition, lastWidth + x1 - self.scrollX
|
||||
return lastPosition
|
||||
end
|
||||
lastPosition = position - 1
|
||||
end
|
||||
|
||||
for position in utf8.codes(self.value) do
|
||||
local a, b = checkPosition(position)
|
||||
if a then return a, b end
|
||||
local index = checkPosition(position)
|
||||
if index then return index end
|
||||
end
|
||||
|
||||
local a, b = checkPosition(#self.value + 1)
|
||||
if a then return a, b end
|
||||
local index = checkPosition(#self.value + 1)
|
||||
if index then return index end
|
||||
|
||||
return #self.value, width + x1 - self.scrollX
|
||||
return #self.value
|
||||
end
|
||||
|
||||
-- move the caret one character to the left
|
||||
local function moveCaretLeft (self, alterRange)
|
||||
local text, endIndex = self.value, self.endIndex
|
||||
|
||||
-- if cursor is at beginning, do nothing
|
||||
if endIndex < 1 then
|
||||
return false
|
||||
end
|
||||
-- clamp caret to beginning
|
||||
if endIndex < 1 then endIndex = 1 end
|
||||
|
||||
-- move left
|
||||
local mode = alterRange and 'end'
|
||||
local offset = utf8.offset(text, -1, endIndex + 1) or 0
|
||||
|
||||
setCaretFromText(self, text:sub(1, offset - 1), mode)
|
||||
local index = (utf8.offset(text, -1, endIndex + 1) or 0) - 1
|
||||
selectRange(self, not alterRange and index, index)
|
||||
end
|
||||
|
||||
-- move the caret one character to the right
|
||||
local function moveCaretRight (self, alterRange)
|
||||
local text, endIndex = self.value, self.endIndex
|
||||
|
||||
-- if cursor is at end, do nothing
|
||||
if endIndex == #text then
|
||||
return false
|
||||
end
|
||||
|
||||
local mode = alterRange and 'end'
|
||||
local offset = utf8.offset(text, 2, endIndex + 1) or #text
|
||||
-- clamp caret to end
|
||||
if endIndex >= #text then endIndex = #text - 1 end
|
||||
|
||||
-- move right
|
||||
setCaretFromText(self, text:sub(1, offset - 1), mode)
|
||||
local index = (utf8.offset(text, 2, endIndex + 1) or #text) - 1
|
||||
selectRange(self, not alterRange and index, index)
|
||||
end
|
||||
|
||||
local function getRange (self)
|
||||
@@ -126,9 +109,9 @@ local function deleteRange (self)
|
||||
-- if expanded range is selected, delete text in range
|
||||
if first ~= last then
|
||||
local left = text:sub(1, first)
|
||||
text = left .. text:sub(last + 1)
|
||||
self.value = text
|
||||
setCaretFromText(self, left)
|
||||
local index = #left
|
||||
self.value = left .. text:sub(last + 1)
|
||||
selectRange(self, index, index)
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -145,9 +128,9 @@ local function deleteCharacterLeft (self)
|
||||
-- delete character to the left
|
||||
local offset = utf8.offset(text, -1, last + 1) or 0
|
||||
local left = text:sub(1, offset - 1)
|
||||
text = left .. text:sub(first + 1)
|
||||
self.value = text
|
||||
setCaretFromText(self, left)
|
||||
local index = #left
|
||||
self.value = left .. text:sub(first + 1)
|
||||
selectRange(self, index, index)
|
||||
end
|
||||
|
||||
local function copyRangeToClipboard (self)
|
||||
@@ -163,21 +146,24 @@ local function pasteFromClipboard (self)
|
||||
local pasted = Backend.getClipboardText() or ''
|
||||
local first, last = getRange(self)
|
||||
local left = text:sub(1, first) .. pasted
|
||||
text = left .. text:sub(last + 1)
|
||||
self.value = text
|
||||
setCaretFromText(self, left)
|
||||
local index = #left
|
||||
self.value = left .. text:sub(last + 1)
|
||||
selectRange(self, index, index)
|
||||
end
|
||||
|
||||
local function insertText (self, newText)
|
||||
local text = self.value
|
||||
local first, last = getRange(self)
|
||||
local left = text:sub(1, first) .. newText
|
||||
|
||||
local index = #left
|
||||
self.value = left .. text:sub(last + 1)
|
||||
setCaretFromText(self, left)
|
||||
selectRange(self, index, index)
|
||||
end
|
||||
|
||||
return function (self)
|
||||
self.startIndex, self.endIndex = 0, 0
|
||||
self.startX, self.endX = -1, -1
|
||||
self.scrollX = 0
|
||||
self.value = tostring(self.value or self.text or '')
|
||||
self.text = ''
|
||||
|
||||
@@ -203,19 +189,16 @@ This color is used to indicate the selected range of text.
|
||||
@section end
|
||||
--]]--
|
||||
|
||||
self.scrollX = 0
|
||||
|
||||
setCaretFromText(self, self.value)
|
||||
|
||||
self:onPressStart(function (event)
|
||||
if event.button ~= 'left' then return end
|
||||
self.startIndex, self.startX = findCaretFromPoint(self, event.x)
|
||||
self.endIndex, self.endX = self.startIndex, self.startX
|
||||
self.startIndex = findIndexFromPoint(self, event.x)
|
||||
self.endIndex = self.startIndex
|
||||
scrollToCaret(self)
|
||||
end)
|
||||
|
||||
self:onPressDrag(function (event)
|
||||
if event.button ~= 'left' then return end
|
||||
self.endIndex, self.endX = findCaretFromPoint(self, event.x)
|
||||
self.endIndex = findIndexFromPoint(self, event.x)
|
||||
scrollToCaret(self)
|
||||
end)
|
||||
|
||||
@@ -270,7 +253,7 @@ This color is used to indicate the selected range of text.
|
||||
end)
|
||||
|
||||
self:onDisplay(function (event)
|
||||
local startX, endX = self.startX or 0, self.endX or 0
|
||||
local startX, endX = self.startX, self.endX
|
||||
local x, y, w, h = self:getRectangle(true, true)
|
||||
local width, height = endX - startX, h
|
||||
local font = self:getFont()
|
||||
@@ -302,4 +285,8 @@ This color is used to indicate the selected range of text.
|
||||
|
||||
Backend.pop()
|
||||
end)
|
||||
|
||||
self:onReshape(function ()
|
||||
updateHighlight(self)
|
||||
end)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user