continued refactor
This commit is contained in:
@@ -325,188 +325,8 @@ function TextEditor:_wrapLine(line, maxWidth)
|
||||
return { { text = line, startIdx = 0, endIdx = utf8.len(line) } }
|
||||
end
|
||||
|
||||
local font = self:_getFont()
|
||||
if not font then
|
||||
return { { text = line, startIdx = 0, endIdx = utf8.len(line) } }
|
||||
end
|
||||
|
||||
local wrappedParts = {}
|
||||
local currentLine = ""
|
||||
local startIdx = 0
|
||||
|
||||
-- Helper function to extract a UTF-8 character by character index
|
||||
local function getUtf8Char(str, charIndex)
|
||||
local byteStart = utf8.offset(str, charIndex)
|
||||
if not byteStart then
|
||||
return ""
|
||||
end
|
||||
local byteEnd = utf8.offset(str, charIndex + 1)
|
||||
if byteEnd then
|
||||
return str:sub(byteStart, byteEnd - 1)
|
||||
else
|
||||
return str:sub(byteStart)
|
||||
end
|
||||
end
|
||||
|
||||
if self.textWrap == "word" then
|
||||
-- Tokenize into words and whitespace, preserving exact spacing
|
||||
local tokens = {}
|
||||
local pos = 1
|
||||
local lineLen = utf8.len(line)
|
||||
|
||||
while pos <= lineLen do
|
||||
local char = getUtf8Char(line, pos)
|
||||
if char:match("%s") then
|
||||
-- Collect whitespace sequence
|
||||
local wsStart = pos
|
||||
while pos <= lineLen and getUtf8Char(line, pos):match("%s") do
|
||||
pos = pos + 1
|
||||
end
|
||||
table.insert(tokens, {
|
||||
type = "space",
|
||||
text = line:sub(utf8.offset(line, wsStart), utf8.offset(line, pos) and utf8.offset(line, pos) - 1 or #line),
|
||||
startPos = wsStart - 1,
|
||||
length = pos - wsStart,
|
||||
})
|
||||
else
|
||||
-- Collect word
|
||||
local wordStart = pos
|
||||
while pos <= lineLen and not getUtf8Char(line, pos):match("%s") do
|
||||
pos = pos + 1
|
||||
end
|
||||
table.insert(tokens, {
|
||||
type = "word",
|
||||
text = line:sub(utf8.offset(line, wordStart), utf8.offset(line, pos) and utf8.offset(line, pos) - 1 or #line),
|
||||
startPos = wordStart - 1,
|
||||
length = pos - wordStart,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- Process tokens and wrap
|
||||
local charPos = 0
|
||||
for i, token in ipairs(tokens) do
|
||||
if token.type == "word" then
|
||||
local testLine = currentLine .. token.text
|
||||
local width = font:getWidth(testLine)
|
||||
|
||||
if width > maxWidth and currentLine ~= "" then
|
||||
-- Current line is full, wrap before this word
|
||||
local currentLineLen = utf8.len(currentLine)
|
||||
table.insert(wrappedParts, {
|
||||
text = currentLine,
|
||||
startIdx = startIdx,
|
||||
endIdx = startIdx + currentLineLen,
|
||||
})
|
||||
startIdx = charPos
|
||||
currentLine = token.text
|
||||
charPos = charPos + token.length
|
||||
|
||||
-- Check if the word itself is too long
|
||||
if font:getWidth(token.text) > maxWidth then
|
||||
local wordLen = utf8.len(token.text)
|
||||
local charLine = ""
|
||||
local charStartIdx = startIdx
|
||||
|
||||
for j = 1, wordLen do
|
||||
local char = getUtf8Char(token.text, j)
|
||||
local testCharLine = charLine .. char
|
||||
local charWidth = font:getWidth(testCharLine)
|
||||
|
||||
if charWidth > maxWidth and charLine ~= "" then
|
||||
table.insert(wrappedParts, {
|
||||
text = charLine,
|
||||
startIdx = charStartIdx,
|
||||
endIdx = charStartIdx + utf8.len(charLine),
|
||||
})
|
||||
charStartIdx = charStartIdx + utf8.len(charLine)
|
||||
charLine = char
|
||||
else
|
||||
charLine = testCharLine
|
||||
end
|
||||
end
|
||||
|
||||
currentLine = charLine
|
||||
startIdx = charStartIdx
|
||||
end
|
||||
elseif width > maxWidth and currentLine == "" then
|
||||
-- Word is too long to fit on a line by itself
|
||||
local wordLen = utf8.len(token.text)
|
||||
local charLine = ""
|
||||
local charStartIdx = startIdx
|
||||
|
||||
for j = 1, wordLen do
|
||||
local char = getUtf8Char(token.text, j)
|
||||
local testCharLine = charLine .. char
|
||||
local charWidth = font:getWidth(testCharLine)
|
||||
|
||||
if charWidth > maxWidth and charLine ~= "" then
|
||||
table.insert(wrappedParts, {
|
||||
text = charLine,
|
||||
startIdx = charStartIdx,
|
||||
endIdx = charStartIdx + utf8.len(charLine),
|
||||
})
|
||||
charStartIdx = charStartIdx + utf8.len(charLine)
|
||||
charLine = char
|
||||
else
|
||||
charLine = testCharLine
|
||||
end
|
||||
end
|
||||
|
||||
currentLine = charLine
|
||||
startIdx = charStartIdx
|
||||
charPos = charPos + token.length
|
||||
else
|
||||
currentLine = testLine
|
||||
charPos = charPos + token.length
|
||||
end
|
||||
else
|
||||
-- It's whitespace - add to current line
|
||||
currentLine = currentLine .. token.text
|
||||
charPos = charPos + token.length
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Character wrapping
|
||||
local lineLength = utf8.len(line)
|
||||
for i = 1, lineLength do
|
||||
local char = getUtf8Char(line, i)
|
||||
local testLine = currentLine .. char
|
||||
local width = font:getWidth(testLine)
|
||||
|
||||
if width > maxWidth and currentLine ~= "" then
|
||||
table.insert(wrappedParts, {
|
||||
text = currentLine,
|
||||
startIdx = startIdx,
|
||||
endIdx = startIdx + utf8.len(currentLine),
|
||||
})
|
||||
currentLine = char
|
||||
startIdx = i - 1
|
||||
else
|
||||
currentLine = testLine
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add remaining text
|
||||
if currentLine ~= "" then
|
||||
table.insert(wrappedParts, {
|
||||
text = currentLine,
|
||||
startIdx = startIdx,
|
||||
endIdx = startIdx + utf8.len(currentLine),
|
||||
})
|
||||
end
|
||||
|
||||
-- Ensure at least one part
|
||||
if #wrappedParts == 0 then
|
||||
table.insert(wrappedParts, {
|
||||
text = "",
|
||||
startIdx = 0,
|
||||
endIdx = 0,
|
||||
})
|
||||
end
|
||||
|
||||
return wrappedParts
|
||||
-- Delegate to Renderer
|
||||
return self._element._renderer:wrapLine(self._element, line, maxWidth)
|
||||
end
|
||||
|
||||
-- ====================
|
||||
@@ -1712,19 +1532,8 @@ function TextEditor:_getFont()
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Resolve font path
|
||||
local fontPath = nil
|
||||
if self._element.fontFamily then
|
||||
local Theme = req("Theme")
|
||||
local themeToUse = self._element.theme and Theme.get(self._element.theme) or Theme.getActive()
|
||||
if themeToUse and themeToUse.fonts and themeToUse.fonts[self._element.fontFamily] then
|
||||
fontPath = themeToUse.fonts[self._element.fontFamily]
|
||||
else
|
||||
fontPath = self._element.fontFamily
|
||||
end
|
||||
end
|
||||
|
||||
return FONT_CACHE.getFont(self._element.textSize, fontPath)
|
||||
-- Delegate to Renderer
|
||||
return self._element._renderer:getFont(self._element)
|
||||
end
|
||||
|
||||
---Save state to StateManager (for immediate mode)
|
||||
|
||||
Reference in New Issue
Block a user