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;
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) {
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)
119 }
else if(elapsed >= 2*delay) {
127 void UITextEdit::update(
bool focusCursor)
129 if(!m_updatesEnabled)
134 int textLength = text.length();
162 if(textLength > (
int)m_glyphsCoords.size()) {
163 m_glyphsCoords.resize(textLength);
164 m_glyphsTexCoords.resize(textLength);
167 Point oldTextAreaOffset = m_textVirtualOffset;
170 m_textVirtualOffset.
x = 0;
172 m_textVirtualOffset.
y = 0;
175 m_cursorInRange =
false;
176 if(focusCursor && m_autoScroll) {
177 if(m_cursorPos > 0 && textLength > 0) {
178 assert(m_cursorPos <= textLength);
180 int pos = m_cursorPos - 1;
181 glyph = (
uchar)text[pos];
182 Rect glyphRect(glyphsPositions[pos], glyphsSize[glyph]);
185 if(!virtualRect.contains(glyphRect.topLeft()) || !virtualRect.contains(glyphRect.bottomRight())) {
188 startGlyphPos.
y = std::max<int>(glyphRect.bottom() - virtualRect.height(), 0);
189 startGlyphPos.
x = std::max<int>(glyphRect.right() - virtualRect.width(), 0);
192 for(pos = 0; pos < textLength; ++pos) {
193 glyph = (
uchar)text[pos];
194 glyphRect =
Rect(glyphsPositions[pos], glyphsSize[glyph]);
199 if(glyphRect.topLeft() >= startGlyphPos) {
200 m_textVirtualOffset.
x = glyphsPositions[pos].x;
207 m_textVirtualOffset =
Point(0,0);
209 m_cursorInRange =
true;
211 if(m_cursorPos > 0 && textLength > 0) {
213 int pos = m_cursorPos - 1;
214 glyph = (
uchar)text[pos];
215 Rect glyphRect(glyphsPositions[pos], glyphsSize[glyph]);
216 if(virtualRect.contains(glyphRect.topLeft()) && virtualRect.contains(glyphRect.bottomRight()))
217 m_cursorInRange =
true;
219 m_cursorInRange =
true;
223 bool fireAreaUpdate =
false;
224 if(oldTextAreaOffset != m_textVirtualOffset)
225 fireAreaUpdate =
true;
232 m_drawArea = textScreenCoords;
234 if(textScreenCoords.
size() != m_textVirtualSize) {
235 m_textVirtualSize = textScreenCoords.
size();
236 fireAreaUpdate =
true;
239 Size totalSize = textBoxSize;
240 if(totalSize.
width() < m_textVirtualSize.
width())
244 if(m_textTotalSize != totalSize) {
245 m_textTotalSize = totalSize;
246 fireAreaUpdate =
true;
264 for(
int i = 0; i < textLength; ++i) {
265 glyph = (
uchar)text[i];
266 m_glyphsCoords[i].clear();
269 if(glyph < 32 && glyph != (
uchar)
'\n')
273 Rect glyphScreenCoords(glyphsPositions[i], glyphsSize[glyph]);
274 Rect glyphTextureCoords = glyphsTextureCoords[glyph];
280 glyphScreenCoords.translate(0, (textScreenCoords.
height() - textBoxSize.
height()) / 2);
286 glyphScreenCoords.translate(textScreenCoords.
width() - textBoxSize.
width(), 0);
288 glyphScreenCoords.translate((textScreenCoords.
width() - textBoxSize.
width()) / 2, 0);
294 if(glyphScreenCoords.bottom() < m_textVirtualOffset.
y || glyphScreenCoords.right() < m_textVirtualOffset.
x)
298 if(glyphScreenCoords.top() < m_textVirtualOffset.
y) {
299 glyphTextureCoords.
setTop(glyphTextureCoords.
top() + (m_textVirtualOffset.
y - glyphScreenCoords.top()));
300 glyphScreenCoords.setTop(m_textVirtualOffset.
y);
302 if(glyphScreenCoords.left() < m_textVirtualOffset.
x) {
303 glyphTextureCoords.
setLeft(glyphTextureCoords.
left() + (m_textVirtualOffset.
x - glyphScreenCoords.left()));
304 glyphScreenCoords.setLeft(m_textVirtualOffset.
x);
308 glyphScreenCoords.translate(-m_textVirtualOffset);
311 glyphScreenCoords.translate(textScreenCoords.
topLeft());
314 if(!textScreenCoords.
intersects(glyphScreenCoords))
318 if(glyphScreenCoords.bottom() > textScreenCoords.
bottom()) {
319 glyphTextureCoords.
setBottom(glyphTextureCoords.
bottom() + (textScreenCoords.
bottom() - glyphScreenCoords.bottom()));
320 glyphScreenCoords.setBottom(textScreenCoords.
bottom());
322 if(glyphScreenCoords.right() > textScreenCoords.
right()) {
323 glyphTextureCoords.
setRight(glyphTextureCoords.
right() + (textScreenCoords.
right() - glyphScreenCoords.right()));
324 glyphScreenCoords.setRight(textScreenCoords.
right());
328 m_glyphsCoords[i] = glyphScreenCoords;
329 m_glyphsTexCoords[i] = glyphTextureCoords;
343 if(pos != m_cursorPos) {
347 m_cursorPos =
m_text.length();
356 if(start == m_selectionStart && end == m_selectionEnd)
365 m_selectionStart = stdext::clamp<int>(start, 0, (
int)
m_text.length());
366 m_selectionEnd = stdext::clamp<int>(end, 0, (
int)
m_text.length());
378 m_textVirtualOffset = offset;
387 if(m_cursorPos >= 0) {
394 if(text.length() > 0) {
396 if(m_maxLength > 0 &&
m_text.length() + text.length() > m_maxLength)
400 if(!m_validCharacters.empty()) {
402 if(m_validCharacters.find(i) == std::string::npos)
408 tmp.insert(m_cursorPos, text);
409 m_cursorPos += text.length();
417 if((c ==
'\n' && !m_multiline) || c ==
'\r')
423 if(m_cursorPos >= 0) {
424 if(m_maxLength > 0 &&
m_text.length() + 1 > m_maxLength)
427 if(!m_validCharacters.empty() && m_validCharacters.find(c) == std::string::npos)
432 std::string tmp2 =
m_text;
433 tmp2.insert(m_cursorPos, tmp);
442 if(m_cursorPos >= 0 && tmp.length() > 0) {
443 if((
uint)m_cursorPos >= tmp.length()) {
444 tmp.erase(tmp.begin() + (--m_cursorPos));
447 tmp.erase(tmp.begin() + m_cursorPos);
448 else if(m_cursorPos > 0)
449 tmp.erase(tmp.begin() + --m_cursorPos);
465 tmp.erase(m_selectionStart, m_selectionEnd - m_selectionStart);
493 std::string text =
copy();
511 if(m_cursorPos-1 >= 0)
514 m_cursorPos =
m_text.length();
528 int textLength =
m_text.length();
531 int candidatePos = -1;
532 Rect firstGlyphRect, lastGlyphRect;
533 for(
int i=0;i<textLength;++i) {
534 Rect clickGlyphRect = m_glyphsCoords[i];
538 firstGlyphRect = clickGlyphRect;
539 lastGlyphRect = clickGlyphRect;
546 else if(pos.
y >= clickGlyphRect.
top() && pos.
y <= clickGlyphRect.
bottom()) {
547 if(pos.
x <= clickGlyphRect.
left()) {
550 }
else if(pos.
x >= clickGlyphRect.
right())
556 if(pos.
y < firstGlyphRect.
top())
558 else if(pos.
y > lastGlyphRect.
bottom())
569 text = std::string(
m_text.length(),
'*');
582 return std::string();
583 return m_text.substr(m_selectionStart, m_selectionEnd - m_selectionStart);
588 if(m_cursorPos > (
int)
m_text.length())
589 m_cursorPos =
m_text.length();
594 m_selectionStart = 0;
603 if(m_changeCursorImage) {
616 if(node->tag() ==
"text") {
619 }
else if(node->tag() ==
"text-hidden")
621 else if(node->tag() ==
"shift-navigation")
623 else if(node->tag() ==
"multiline")
625 else if(node->tag() ==
"max-length")
627 else if(node->tag() ==
"editable")
629 else if(node->tag() ==
"selectable")
631 else if(node->tag() ==
"selection-color")
633 else if(node->tag() ==
"selection-background-color")
635 else if(node->tag() ==
"selection") {
639 else if(node->tag() ==
"cursor-visible")
641 else if(node->tag() ==
"change-cursor-image")
643 else if(node->tag() ==
"auto-scroll")
662 }
else if(m_selectable)
683 }
else if(keyCode ==
Fw::KeyRight && !m_shiftNavigation) {
687 }
else if(keyCode ==
Fw::KeyLeft && !m_shiftNavigation) {
692 if(m_cursorPos != 0) {
698 if(m_cursorPos != (
int)
m_text.length()) {
703 }
else if(keyCode ==
Fw::KeyTab && !m_shiftNavigation) {
708 }
else if(keyCode ==
Fw::KeyEnter && m_multiline && m_editable) {
711 }
else if(keyCode ==
Fw::KeyUp && !m_shiftNavigation && m_multiline) {
714 }
else if(keyCode ==
Fw::KeyDown && !m_shiftNavigation && m_multiline) {
719 if(keyCode ==
Fw::KeyV && m_editable) {
722 }
else if(keyCode ==
Fw::KeyX && m_editable && m_selectable) {
727 }
else if(keyCode ==
Fw::KeyC && m_selectable) {
732 }
else if(keyCode ==
Fw::KeyA && m_selectable) {
739 if(keyCode ==
Fw::KeyTab && !m_shiftNavigation) {
745 int oldCursorPos = m_cursorPos;
752 if(m_shiftNavigation)
756 m_selectionReference = oldCursorPos;
761 if(m_cursorPos != 0) {
767 if(m_cursorPos != (
int)
m_text.length()) {
798 m_selectionReference = pos;
832 if(m_selectable &&
m_text.length() > 0) {
841 callLuaField(
"onTextAreaUpdate", offset, visibleSize, totalSize);