37 m_shiftNavigation =
false;
39 m_cursorVisible =
true;
40 m_cursorInRange =
true;
45 m_changeCursorImage =
true;
46 m_selectionReference = 0;
49 m_updatesEnabled =
true;
54 m_glyphsMustRecache =
true;
68 int textLength =
m_text.length();
73 bool glyphsMustRecache = m_glyphsMustRecache;
74 if (glyphsMustRecache)
75 m_glyphsMustRecache =
false;
78 if (glyphsMustRecache) {
79 m_glyphsTextCoordsBuffer.
clear();
80 for (
int i = 0; i < textLength; ++i)
81 m_glyphsTextCoordsBuffer.
addRect(m_glyphsCoords[i], m_glyphsTexCoords[i]);
88 if (glyphsMustRecache) {
89 m_glyphsSelectCoordsBuffer.
clear();
90 for (
int i = m_selectionStart; i < m_selectionEnd; ++i)
91 m_glyphsSelectCoordsBuffer.
addRect(m_glyphsCoords[i], m_glyphsTexCoords[i]);
101 assert(m_cursorPos <= textLength);
103 const int delay = 333;
105 if (elapsed <= delay) {
108 if (m_cursorPos == 0)
111 cursorRect =
Rect(m_glyphsCoords[m_cursorPos - 1].right(), m_glyphsCoords[m_cursorPos - 1].top(), 1,
m_font->
getGlyphHeight());
113 if (
hasSelection() && m_cursorPos >= m_selectionStart && m_cursorPos <= m_selectionEnd)
120 else if (elapsed >= 2 * delay) {
128 void UITextEdit::update(
bool focusCursor)
130 if (!m_updatesEnabled)
135 int textLength = text.length();
163 if (textLength >
static_cast<int>(m_glyphsCoords.size())) {
164 m_glyphsCoords.resize(textLength);
165 m_glyphsTexCoords.resize(textLength);
168 Point oldTextAreaOffset = m_textVirtualOffset;
171 m_textVirtualOffset.
x = 0;
173 m_textVirtualOffset.
y = 0;
176 m_cursorInRange =
false;
177 if (focusCursor && m_autoScroll) {
178 if (m_cursorPos > 0 && textLength > 0) {
179 assert(m_cursorPos <= textLength);
181 int pos = m_cursorPos - 1;
182 glyph =
static_cast<uchar>(text[pos]);
183 Rect glyphRect(glyphsPositions[pos], glyphsSize[glyph]);
186 if (!virtualRect.contains(glyphRect.topLeft()) || !virtualRect.contains(glyphRect.bottomRight())) {
189 startGlyphPos.
y = std::max<int>(glyphRect.bottom() - virtualRect.height(), 0);
190 startGlyphPos.
x = std::max<int>(glyphRect.right() - virtualRect.width(), 0);
193 for (pos = 0; pos < textLength; ++pos) {
194 glyph =
static_cast<uchar>(text[pos]);
195 glyphRect =
Rect(glyphsPositions[pos], glyphsSize[glyph]);
200 if (glyphRect.topLeft() >= startGlyphPos) {
201 m_textVirtualOffset.
x = glyphsPositions[pos].x;
209 m_textVirtualOffset =
Point(0, 0);
211 m_cursorInRange =
true;
214 if (m_cursorPos > 0 && textLength > 0) {
216 int pos = m_cursorPos - 1;
217 glyph =
static_cast<uchar>(text[pos]);
218 Rect glyphRect(glyphsPositions[pos], glyphsSize[glyph]);
219 if (virtualRect.contains(glyphRect.topLeft()) && virtualRect.contains(glyphRect.bottomRight()))
220 m_cursorInRange =
true;
223 m_cursorInRange =
true;
227 bool fireAreaUpdate =
false;
228 if (oldTextAreaOffset != m_textVirtualOffset)
229 fireAreaUpdate =
true;
236 m_drawArea = textScreenCoords;
238 if (textScreenCoords.
size() != m_textVirtualSize) {
239 m_textVirtualSize = textScreenCoords.
size();
240 fireAreaUpdate =
true;
243 Size totalSize = textBoxSize;
244 if (totalSize.
width() < m_textVirtualSize.
width())
248 if (m_textTotalSize != totalSize) {
249 m_textTotalSize = totalSize;
250 fireAreaUpdate =
true;
272 for (
int i = 0; i < textLength; ++i) {
273 glyph =
static_cast<uchar>(text[i]);
274 m_glyphsCoords[i].clear();
277 if (glyph < 32 && glyph !=
static_cast<uchar>(
'\n'))
281 Rect glyphScreenCoords(glyphsPositions[i], glyphsSize[glyph]);
282 Rect glyphTextureCoords = glyphsTextureCoords[glyph];
289 glyphScreenCoords.translate(0, (textScreenCoords.
height() - textBoxSize.
height()) / 2);
296 glyphScreenCoords.translate(textScreenCoords.
width() - textBoxSize.
width(), 0);
299 glyphScreenCoords.translate((textScreenCoords.
width() - textBoxSize.
width()) / 2, 0);
306 if (glyphScreenCoords.bottom() < m_textVirtualOffset.
y || glyphScreenCoords.right() < m_textVirtualOffset.
x)
310 if (glyphScreenCoords.top() < m_textVirtualOffset.
y) {
311 glyphTextureCoords.
setTop(glyphTextureCoords.
top() + (m_textVirtualOffset.
y - glyphScreenCoords.top()));
312 glyphScreenCoords.setTop(m_textVirtualOffset.
y);
314 if (glyphScreenCoords.left() < m_textVirtualOffset.
x) {
315 glyphTextureCoords.
setLeft(glyphTextureCoords.
left() + (m_textVirtualOffset.
x - glyphScreenCoords.left()));
316 glyphScreenCoords.setLeft(m_textVirtualOffset.
x);
320 glyphScreenCoords.translate(-m_textVirtualOffset);
323 glyphScreenCoords.translate(textScreenCoords.
topLeft());
326 if (!textScreenCoords.
intersects(glyphScreenCoords))
330 if (glyphScreenCoords.bottom() > textScreenCoords.
bottom()) {
331 glyphTextureCoords.
setBottom(glyphTextureCoords.
bottom() + (textScreenCoords.
bottom() - glyphScreenCoords.bottom()));
332 glyphScreenCoords.setBottom(textScreenCoords.
bottom());
334 if (glyphScreenCoords.right() > textScreenCoords.
right()) {
335 glyphTextureCoords.
setRight(glyphTextureCoords.
right() + (textScreenCoords.
right() - glyphScreenCoords.right()));
336 glyphScreenCoords.setRight(textScreenCoords.
right());
340 m_glyphsCoords[i] = glyphScreenCoords;
341 m_glyphsTexCoords[i] = glyphTextureCoords;
355 if (pos != m_cursorPos) {
358 else if (
static_cast<uint>(pos) >=
m_text.length())
359 m_cursorPos =
m_text.length();
368 if (start == m_selectionStart && end == m_selectionEnd)
377 m_selectionStart = stdext::clamp<int>(start, 0,
static_cast<int>(
m_text.length()));
378 m_selectionEnd = stdext::clamp<int>(end, 0,
static_cast<int>(
m_text.length()));
390 m_textVirtualOffset = offset;
399 if (m_cursorPos >= 0) {
406 if (text.length() > 0) {
408 if (m_maxLength > 0 &&
m_text.length() + text.length() > m_maxLength)
412 if (!m_validCharacters.empty()) {
413 for (
char i : text) {
414 if (m_validCharacters.find(i) == std::string::npos)
420 tmp.insert(m_cursorPos, text);
421 m_cursorPos += text.length();
429 if ((c ==
'\n' && !m_multiline) || c ==
'\r')
435 if (m_cursorPos >= 0) {
436 if (m_maxLength > 0 &&
m_text.length() + 1 > m_maxLength)
439 if (!m_validCharacters.empty() && m_validCharacters.find(c) == std::string::npos)
444 std::string tmp2 =
m_text;
445 tmp2.insert(m_cursorPos, tmp);
454 if (m_cursorPos >= 0 && tmp.length() > 0) {
455 if (
static_cast<uint>(m_cursorPos) >= tmp.length()) {
456 tmp.erase(tmp.begin() + (--m_cursorPos));
460 tmp.erase(tmp.begin() + m_cursorPos);
461 else if (m_cursorPos > 0)
462 tmp.erase(tmp.begin() + --m_cursorPos);
478 tmp.erase(m_selectionStart, m_selectionEnd - m_selectionStart);
507 std::string text =
copy();
520 if (
static_cast<uint>(m_cursorPos) + 1 <=
m_text.length())
526 if (m_cursorPos - 1 >= 0)
529 m_cursorPos =
m_text.length();
543 int textLength =
m_text.length();
546 int candidatePos = -1;
547 Rect firstGlyphRect, lastGlyphRect;
548 for (
int i = 0; i < textLength; ++i) {
549 Rect clickGlyphRect = m_glyphsCoords[i];
553 firstGlyphRect = clickGlyphRect;
554 lastGlyphRect = clickGlyphRect;
561 else if (pos.
y >= clickGlyphRect.
top() && pos.
y <= clickGlyphRect.
bottom()) {
562 if (pos.
x <= clickGlyphRect.
left()) {
566 else if (pos.
x >= clickGlyphRect.
right())
567 candidatePos = i + 1;
571 if (textLength > 0) {
572 if (pos.
y < firstGlyphRect.
top())
574 else if (pos.
y > lastGlyphRect.
bottom())
585 text = std::string(
m_text.length(),
'*');
598 return std::string();
599 return m_text.substr(m_selectionStart, m_selectionEnd - m_selectionStart);
604 if (m_cursorPos >
static_cast<int>(
m_text.length()))
605 m_cursorPos =
m_text.length();
610 m_selectionStart = 0;
619 if (m_changeCursorImage) {
632 if (node->tag() ==
"text") {
636 else if (node->tag() ==
"text-hidden")
638 else if (node->tag() ==
"shift-navigation")
640 else if (node->tag() ==
"multiline")
642 else if (node->tag() ==
"max-length")
644 else if (node->tag() ==
"editable")
646 else if (node->tag() ==
"selectable")
648 else if (node->tag() ==
"selection-color")
650 else if (node->tag() ==
"selection-background-color")
652 else if (node->tag() ==
"selection") {
656 else if (node->tag() ==
"cursor-visible")
658 else if (node->tag() ==
"change-cursor-image")
660 else if (node->tag() ==
"auto-scroll")
680 else if (m_selectable)
703 else if (keyCode ==
Fw::KeyRight && !m_shiftNavigation) {
708 else if (keyCode ==
Fw::KeyLeft && !m_shiftNavigation) {
714 if (m_cursorPos != 0) {
721 if (m_cursorPos !=
static_cast<int>(
m_text.length())) {
727 else if (keyCode ==
Fw::KeyTab && !m_shiftNavigation) {
733 else if (keyCode ==
Fw::KeyEnter && m_multiline && m_editable) {
737 else if (keyCode ==
Fw::KeyUp && !m_shiftNavigation && m_multiline) {
741 else if (keyCode ==
Fw::KeyDown && !m_shiftNavigation && m_multiline) {
747 if (keyCode ==
Fw::KeyV && m_editable) {
751 else if (keyCode ==
Fw::KeyX && m_editable && m_selectable) {
757 else if (keyCode ==
Fw::KeyC && m_selectable) {
763 else if (keyCode ==
Fw::KeyA && m_selectable) {
764 if (
m_text.length() > 0) {
771 if (keyCode ==
Fw::KeyTab && !m_shiftNavigation) {
778 int oldCursorPos = m_cursorPos;
785 if (m_shiftNavigation)
789 m_selectionReference = oldCursorPos;
795 if (m_cursorPos != 0) {
802 if (m_cursorPos !=
static_cast<int>(
m_text.length())) {
833 m_selectionReference = pos;
867 if (m_selectable &&
m_text.length() > 0) {
876 callLuaField(
"onTextAreaUpdate", offset, visibleSize, totalSize);