fix text selection in immediate mode

This commit is contained in:
Michael Freno
2025-12-06 11:59:00 -05:00
parent 63c31aed16
commit b790fb1d32
3 changed files with 55 additions and 27 deletions

View File

@@ -416,7 +416,15 @@ function Element.new(props)
onTextChange = props.onTextChange, onTextChange = props.onTextChange,
onEnter = props.onEnter, onEnter = props.onEnter,
}, textEditorDeps) }, textEditorDeps)
-- Initialize will be called after self is fully constructed
-- Restore TextEditor state from StateManager in immediate mode
if Element._Context._immediateMode and self._stateId and self._stateId ~= "" then
local state = Element._StateManager.getState(self._stateId)
if state and state.textEditor then
-- Restore from nested textEditor state (saved via saveState())
self._textEditor:setState(state.textEditor, self)
end
end
end end
-- Set parent first so it's available for size calculations -- Set parent first so it's available for size calculations
@@ -3305,6 +3313,14 @@ function Element:saveState()
end end
end end
-- Save drag tracking state for text selection
if self._mouseDownPosition ~= nil then
state._mouseDownPosition = self._mouseDownPosition
end
if self._textDragOccurred ~= nil then
state._textDragOccurred = self._textDragOccurred
end
return state return state
end end
@@ -3337,6 +3353,14 @@ function Element:restoreState(state)
self._scrollManager:setState(state.scrollManager) self._scrollManager:setState(state.scrollManager)
end end
-- Restore drag tracking state for text selection
if state._mouseDownPosition ~= nil then
self._mouseDownPosition = state._mouseDownPosition
end
if state._textDragOccurred ~= nil then
self._textDragOccurred = state._textDragOccurred
end
-- Note: Blur cache data is used for invalidation, not restoration -- Note: Blur cache data is used for invalidation, not restoration
end end

View File

@@ -801,33 +801,37 @@ function Renderer:drawText(element)
end end
-- Draw selection highlight for editable elements -- Draw selection highlight for editable elements
if element._textEditor and element._textEditor:isFocused() and element._textEditor:hasSelection() and element.text and element.text ~= "" then if element._textEditor and element._textEditor:isFocused() and element._textEditor:hasSelection() then
local selStart, selEnd = element._textEditor:getSelection() -- For editable elements, check TextEditor buffer instead of element.text
local selectionColor = element.selectionColor or self._Color.new(0.3, 0.5, 0.8, 0.5) local textBuffer = element._textEditor:getText()
local selectionWithOpacity = self._Color.new(selectionColor.r, selectionColor.g, selectionColor.b, selectionColor.a * self.opacity) if textBuffer and textBuffer ~= "" then
local selStart, selEnd = element._textEditor:getSelection()
local selectionColor = element.selectionColor or self._Color.new(0.3, 0.5, 0.8, 0.5)
local selectionWithOpacity = self._Color.new(selectionColor.r, selectionColor.g, selectionColor.b, selectionColor.a * self.opacity)
-- Get selection rectangles from TextEditor -- Get selection rectangles from TextEditor
local selectionRects = element._textEditor:_getSelectionRects(element, selStart, selEnd) local selectionRects = element._textEditor:_getSelectionRects(element, selStart, selEnd)
-- Apply scissor for single-line editable inputs -- Apply scissor for single-line editable inputs
if not element.multiline then if not element.multiline then
love.graphics.setScissor(contentX, contentY, textAreaWidth, textAreaHeight) love.graphics.setScissor(contentX, contentY, textAreaWidth, textAreaHeight)
end
-- Draw selection background rectangles
love.graphics.setColor(selectionWithOpacity:toRGBA())
for _, rect in ipairs(selectionRects) do
local rectX = contentX + rect.x
local rectY = contentY + rect.y
if not element.multiline and element._textEditor._textScrollX then
rectX = rectX - element._textEditor._textScrollX
end end
love.graphics.rectangle("fill", rectX, rectY, rect.width, rect.height)
end
-- Reset scissor -- Draw selection background rectangles
if not element.multiline then love.graphics.setColor(selectionWithOpacity:toRGBA())
love.graphics.setScissor() for _, rect in ipairs(selectionRects) do
local rectX = contentX + rect.x
local rectY = contentY + rect.y
if not element.multiline and element._textEditor._textScrollX then
rectX = rectX - element._textEditor._textScrollX
end
love.graphics.rectangle("fill", rectX, rectY, rect.width, rect.height)
end
-- Reset scissor
if not element.multiline then
love.graphics.setScissor()
end
end end
end end

View File

@@ -1500,14 +1500,14 @@ end
---@param mouseX number ---@param mouseX number
---@param mouseY number ---@param mouseY number
function TextEditor:handleTextDrag(element, mouseX, mouseY) function TextEditor:handleTextDrag(element, mouseX, mouseY)
if not self._focused or not self._mouseDownPosition then if not self._focused or not element._mouseDownPosition then
return return
end end
local currentPos = self:mouseToTextPosition(element, mouseX, mouseY) local currentPos = self:mouseToTextPosition(element, mouseX, mouseY)
if currentPos ~= self._mouseDownPosition then if currentPos ~= element._mouseDownPosition then
self:setSelection(element, self._mouseDownPosition, currentPos) self:setSelection(element, element._mouseDownPosition, currentPos)
self._cursorPosition = currentPos self._cursorPosition = currentPos
self._textDragOccurred = true self._textDragOccurred = true
else else