Otclient 1.0  14/8/2020
uitextedit.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 OTClient <https://github.com/edubart/otclient>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 #include "uitextedit.h"
27 #include <framework/core/clock.h>
30 #include <framework/input/mouse.h>
31 
33 {
34  m_cursorPos = 0;
36  m_textHidden = false;
37  m_shiftNavigation = false;
38  m_multiline = false;
39  m_cursorVisible = true;
40  m_cursorInRange = true;
41  m_maxLength = 0;
42  m_editable = true;
43  m_selectable = true;
44  m_autoScroll = true;
45  m_changeCursorImage = true;
46  m_selectionReference = 0;
47  m_selectionStart = 0;
48  m_selectionEnd = 0;
49  m_updatesEnabled = true;
50  m_selectionColor = Color::white;
51  m_selectionBackgroundColor = Color::black;
52  m_glyphsTextCoordsBuffer.enableHardwareCaching();
53  m_glyphsSelectCoordsBuffer.enableHardwareCaching();
54  m_glyphsMustRecache = true;
55  blinkCursor();
56 }
57 
59 {
60  if ((drawPane & Fw::ForegroundPane) == 0)
61  return;
62 
67 
68  int textLength = m_text.length();
69  const TexturePtr& texture = m_font->getTexture();
70  if (!texture)
71  return;
72 
73  bool glyphsMustRecache = m_glyphsMustRecache;
74  if (glyphsMustRecache)
75  m_glyphsMustRecache = false;
76 
77  if (m_color != Color::alpha) {
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]);
82  }
84  g_painter->drawTextureCoords(m_glyphsTextCoordsBuffer, texture);
85  }
86 
87  if (hasSelection()) {
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]);
92  }
93  g_painter->setColor(m_selectionBackgroundColor);
94  g_painter->drawFillCoords(m_glyphsSelectCoordsBuffer);
95  g_painter->setColor(m_selectionColor);
96  g_painter->drawTextureCoords(m_glyphsSelectCoordsBuffer, texture);
97  }
98 
99  // render cursor
100  if (isExplicitlyEnabled() && m_cursorVisible && m_cursorInRange && isActive() && m_cursorPos >= 0) {
101  assert(m_cursorPos <= textLength);
102  // draw every 333ms
103  const int delay = 333;
104  int elapsed = g_clock.millis() - m_cursorTicks;
105  if (elapsed <= delay) {
106  Rect cursorRect;
107  // when cursor is at 0
108  if (m_cursorPos == 0)
109  cursorRect = Rect(m_rect.left() + m_padding.left, m_rect.top() + m_padding.top, 1, m_font->getGlyphHeight());
110  else
111  cursorRect = Rect(m_glyphsCoords[m_cursorPos - 1].right(), m_glyphsCoords[m_cursorPos - 1].top(), 1, m_font->getGlyphHeight());
112 
113  if (hasSelection() && m_cursorPos >= m_selectionStart && m_cursorPos <= m_selectionEnd)
114  g_painter->setColor(m_selectionColor);
115  else
117 
118  g_painter->drawFilledRect(cursorRect);
119  }
120  else if (elapsed >= 2 * delay) {
121  m_cursorTicks = g_clock.millis();
122  }
123  }
124 
126 }
127 
128 void UITextEdit::update(bool focusCursor)
129 {
130  if (!m_updatesEnabled)
131  return;
132 
133  std::string text = getDisplayedText();
134  m_drawText = text;
135  int textLength = text.length();
136 
137  // prevent glitches
138  if (m_rect.isEmpty())
139  return;
140 
141  // recache coords buffers
142  recacheGlyphs();
143 
144  // map glyphs positions
145  Size textBoxSize;
146  const std::vector<Point>& glyphsPositions = m_font->calculateGlyphsPositions(text, m_textAlign, &textBoxSize);
147  const Rect* glyphsTextureCoords = m_font->getGlyphsTextureCoords();
148  const Size* glyphsSize = m_font->getGlyphsSize();
149  int glyph;
150 
151  // update rect size
154  Size size = getSize();
155  if (size.width() <= 0 || (m_textHorizontalAutoResize && !m_textWrap))
156  size.setWidth(textBoxSize.width());
157  if (size.height() <= 0 || m_textVerticalAutoResize)
158  size.setHeight(textBoxSize.height());
159  setSize(size);
160  }
161 
162  // resize just on demand
163  if (textLength > static_cast<int>(m_glyphsCoords.size())) {
164  m_glyphsCoords.resize(textLength);
165  m_glyphsTexCoords.resize(textLength);
166  }
167 
168  Point oldTextAreaOffset = m_textVirtualOffset;
169 
170  if (textBoxSize.width() <= getPaddingRect().width())
171  m_textVirtualOffset.x = 0;
172  if (textBoxSize.height() <= getPaddingRect().height())
173  m_textVirtualOffset.y = 0;
174 
175  // readjust start view area based on cursor position
176  m_cursorInRange = false;
177  if (focusCursor && m_autoScroll) {
178  if (m_cursorPos > 0 && textLength > 0) {
179  assert(m_cursorPos <= textLength);
180  Rect virtualRect(m_textVirtualOffset, m_rect.size() - Size(m_padding.left + m_padding.right, 0)); // previous rendered virtual rect
181  int pos = m_cursorPos - 1; // element before cursor
182  glyph = static_cast<uchar>(text[pos]); // glyph of the element before cursor
183  Rect glyphRect(glyphsPositions[pos], glyphsSize[glyph]);
184 
185  // if the cursor is not on the previous rendered virtual rect we need to update it
186  if (!virtualRect.contains(glyphRect.topLeft()) || !virtualRect.contains(glyphRect.bottomRight())) {
187  // calculate where is the first glyph visible
188  Point startGlyphPos;
189  startGlyphPos.y = std::max<int>(glyphRect.bottom() - virtualRect.height(), 0);
190  startGlyphPos.x = std::max<int>(glyphRect.right() - virtualRect.width(), 0);
191 
192  // find that glyph
193  for (pos = 0; pos < textLength; ++pos) {
194  glyph = static_cast<uchar>(text[pos]);
195  glyphRect = Rect(glyphsPositions[pos], glyphsSize[glyph]);
196  glyphRect.setTop(std::max<int>(glyphRect.top() - m_font->getYOffset() - m_font->getGlyphSpacing().height(), 0));
197  glyphRect.setLeft(std::max<int>(glyphRect.left() - m_font->getGlyphSpacing().width(), 0));
198 
199  // first glyph entirely visible found
200  if (glyphRect.topLeft() >= startGlyphPos) {
201  m_textVirtualOffset.x = glyphsPositions[pos].x;
202  m_textVirtualOffset.y = glyphsPositions[pos].y - m_font->getYOffset();
203  break;
204  }
205  }
206  }
207  }
208  else {
209  m_textVirtualOffset = Point(0, 0);
210  }
211  m_cursorInRange = true;
212  }
213  else {
214  if (m_cursorPos > 0 && textLength > 0) {
215  Rect virtualRect(m_textVirtualOffset, m_rect.size() - Size(2 * m_padding.left + m_padding.right, 0)); // previous rendered virtual rect
216  int pos = m_cursorPos - 1; // element before cursor
217  glyph = static_cast<uchar>(text[pos]); // glyph of the element before cursor
218  Rect glyphRect(glyphsPositions[pos], glyphsSize[glyph]);
219  if (virtualRect.contains(glyphRect.topLeft()) && virtualRect.contains(glyphRect.bottomRight()))
220  m_cursorInRange = true;
221  }
222  else {
223  m_cursorInRange = true;
224  }
225  }
226 
227  bool fireAreaUpdate = false;
228  if (oldTextAreaOffset != m_textVirtualOffset)
229  fireAreaUpdate = true;
230 
231  Rect textScreenCoords = m_rect;
232  textScreenCoords.expandLeft(-m_padding.left);
233  textScreenCoords.expandRight(-m_padding.right);
234  textScreenCoords.expandBottom(-m_padding.bottom);
235  textScreenCoords.expandTop(-m_padding.top);
236  m_drawArea = textScreenCoords;
237 
238  if (textScreenCoords.size() != m_textVirtualSize) {
239  m_textVirtualSize = textScreenCoords.size();
240  fireAreaUpdate = true;
241  }
242 
243  Size totalSize = textBoxSize;
244  if (totalSize.width() < m_textVirtualSize.width())
245  totalSize.setWidth(m_textVirtualSize.height());
246  if (totalSize.height() < m_textVirtualSize.height())
247  totalSize.setHeight(m_textVirtualSize.height());
248  if (m_textTotalSize != totalSize) {
249  m_textTotalSize = totalSize;
250  fireAreaUpdate = true;
251  }
252 
254  m_drawArea.translate(0, textScreenCoords.height() - textBoxSize.height());
255  }
257  m_drawArea.translate(0, (textScreenCoords.height() - textBoxSize.height()) / 2);
258  }
259  else { // AlignTop
260  }
261 
262  if (m_textAlign & Fw::AlignRight) {
263  m_drawArea.translate(textScreenCoords.width() - textBoxSize.width(), 0);
264  }
266  m_drawArea.translate((textScreenCoords.width() - textBoxSize.width()) / 2, 0);
267  }
268  else { // AlignLeft
269 
270  }
271 
272  for (int i = 0; i < textLength; ++i) {
273  glyph = static_cast<uchar>(text[i]);
274  m_glyphsCoords[i].clear();
275 
276  // skip invalid glyphs
277  if (glyph < 32 && glyph != static_cast<uchar>('\n'))
278  continue;
279 
280  // calculate initial glyph rect and texture coords
281  Rect glyphScreenCoords(glyphsPositions[i], glyphsSize[glyph]);
282  Rect glyphTextureCoords = glyphsTextureCoords[glyph];
283 
284  // first translate to align position
286  glyphScreenCoords.translate(0, textScreenCoords.height() - textBoxSize.height());
287  }
289  glyphScreenCoords.translate(0, (textScreenCoords.height() - textBoxSize.height()) / 2);
290  }
291  else { // AlignTop
292  // nothing to do
293  }
294 
295  if (m_textAlign & Fw::AlignRight) {
296  glyphScreenCoords.translate(textScreenCoords.width() - textBoxSize.width(), 0);
297  }
299  glyphScreenCoords.translate((textScreenCoords.width() - textBoxSize.width()) / 2, 0);
300  }
301  else { // AlignLeft
302  // nothing to do
303  }
304 
305  // only render glyphs that are after startRenderPosition
306  if (glyphScreenCoords.bottom() < m_textVirtualOffset.y || glyphScreenCoords.right() < m_textVirtualOffset.x)
307  continue;
308 
309  // bound glyph topLeft to startRenderPosition
310  if (glyphScreenCoords.top() < m_textVirtualOffset.y) {
311  glyphTextureCoords.setTop(glyphTextureCoords.top() + (m_textVirtualOffset.y - glyphScreenCoords.top()));
312  glyphScreenCoords.setTop(m_textVirtualOffset.y);
313  }
314  if (glyphScreenCoords.left() < m_textVirtualOffset.x) {
315  glyphTextureCoords.setLeft(glyphTextureCoords.left() + (m_textVirtualOffset.x - glyphScreenCoords.left()));
316  glyphScreenCoords.setLeft(m_textVirtualOffset.x);
317  }
318 
319  // subtract startInternalPos
320  glyphScreenCoords.translate(-m_textVirtualOffset);
321 
322  // translate rect to screen coords
323  glyphScreenCoords.translate(textScreenCoords.topLeft());
324 
325  // only render if glyph rect is visible on screenCoords
326  if (!textScreenCoords.intersects(glyphScreenCoords))
327  continue;
328 
329  // bound glyph bottomRight to screenCoords bottomRight
330  if (glyphScreenCoords.bottom() > textScreenCoords.bottom()) {
331  glyphTextureCoords.setBottom(glyphTextureCoords.bottom() + (textScreenCoords.bottom() - glyphScreenCoords.bottom()));
332  glyphScreenCoords.setBottom(textScreenCoords.bottom());
333  }
334  if (glyphScreenCoords.right() > textScreenCoords.right()) {
335  glyphTextureCoords.setRight(glyphTextureCoords.right() + (textScreenCoords.right() - glyphScreenCoords.right()));
336  glyphScreenCoords.setRight(textScreenCoords.right());
337  }
338 
339  // render glyph
340  m_glyphsCoords[i] = glyphScreenCoords;
341  m_glyphsTexCoords[i] = glyphTextureCoords;
342  }
343 
344  if (fireAreaUpdate)
345  onTextAreaUpdate(m_textVirtualOffset, m_textVirtualSize, m_textTotalSize);
346 
347  g_app.repaint();
348 }
349 
351 {
352  if (pos < 0)
353  pos = m_text.length();
354 
355  if (pos != m_cursorPos) {
356  if (pos < 0)
357  m_cursorPos = 0;
358  else if (static_cast<uint>(pos) >= m_text.length())
359  m_cursorPos = m_text.length();
360  else
361  m_cursorPos = pos;
362  update(true);
363  }
364 }
365 
366 void UITextEdit::setSelection(int start, int end)
367 {
368  if (start == m_selectionStart && end == m_selectionEnd)
369  return;
370 
371  if (start > end)
372  std::swap(start, end);
373 
374  if (end == -1)
375  end = m_text.length();
376 
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()));
379  recacheGlyphs();
380 }
381 
383 {
384  m_textHidden = true;
385  update(true);
386 }
387 
389 {
390  m_textVirtualOffset = offset;
391  update();
392 }
393 
394 void UITextEdit::appendText(std::string text)
395 {
396  if (hasSelection())
397  del();
398 
399  if (m_cursorPos >= 0) {
400  // replace characters that are now allowed
401  if (!m_multiline)
402  stdext::replace_all(text, "\n", " ");
403  stdext::replace_all(text, "\r", "");
404  stdext::replace_all(text, "\t", " ");
405 
406  if (text.length() > 0) {
407  // only add text if textedit can add it
408  if (m_maxLength > 0 && m_text.length() + text.length() > m_maxLength)
409  return;
410 
411  // only ignore text append if it contains invalid characters
412  if (!m_validCharacters.empty()) {
413  for (char i : text) {
414  if (m_validCharacters.find(i) == std::string::npos)
415  return;
416  }
417  }
418 
419  std::string tmp = m_text;
420  tmp.insert(m_cursorPos, text);
421  m_cursorPos += text.length();
422  setText(tmp);
423  }
424  }
425 }
426 
428 {
429  if ((c == '\n' && !m_multiline) || c == '\r')
430  return;
431 
432  if (hasSelection())
433  del();
434 
435  if (m_cursorPos >= 0) {
436  if (m_maxLength > 0 && m_text.length() + 1 > m_maxLength)
437  return;
438 
439  if (!m_validCharacters.empty() && m_validCharacters.find(c) == std::string::npos)
440  return;
441 
442  std::string tmp;
443  tmp = c;
444  std::string tmp2 = m_text;
445  tmp2.insert(m_cursorPos, tmp);
446  m_cursorPos++;
447  setText(tmp2);
448  }
449 }
450 
452 {
453  std::string tmp = m_text;
454  if (m_cursorPos >= 0 && tmp.length() > 0) {
455  if (static_cast<uint>(m_cursorPos) >= tmp.length()) {
456  tmp.erase(tmp.begin() + (--m_cursorPos));
457  }
458  else {
459  if (right)
460  tmp.erase(tmp.begin() + m_cursorPos);
461  else if (m_cursorPos > 0)
462  tmp.erase(tmp.begin() + --m_cursorPos);
463  }
464  setText(tmp);
465  }
466 }
467 
469 {
470  m_cursorTicks = g_clock.millis();
471  g_app.repaint();
472 }
473 
474 void UITextEdit::del(bool right)
475 {
476  if (hasSelection()) {
477  std::string tmp = m_text;
478  tmp.erase(m_selectionStart, m_selectionEnd - m_selectionStart);
479 
480  setCursorPos(m_selectionStart);
481  clearSelection();
482  setText(tmp);
483  }
484  else
485  removeCharacter(right);
486 }
487 
488 void UITextEdit::paste(const std::string& text)
489 {
490  if (hasSelection())
491  del();
492  appendText(text);
493 }
494 
495 std::string UITextEdit::copy()
496 {
497  std::string text;
498  if (hasSelection()) {
499  text = getSelection();
501  }
502  return text;
503 }
504 
505 std::string UITextEdit::cut()
506 {
507  std::string text = copy();
508  del();
509  return text;
510 }
511 
513 {
515 }
516 
518 {
519  if (right) {
520  if (static_cast<uint>(m_cursorPos) + 1 <= m_text.length())
521  m_cursorPos++;
522  else
523  m_cursorPos = 0;
524  }
525  else {
526  if (m_cursorPos - 1 >= 0)
527  m_cursorPos--;
528  else
529  m_cursorPos = m_text.length();
530  }
531 
532  blinkCursor();
533  update(true);
534 }
535 
537 {
538  //TODO
539 }
540 
542 {
543  int textLength = m_text.length();
544 
545  // find any glyph that is actually on the
546  int candidatePos = -1;
547  Rect firstGlyphRect, lastGlyphRect;
548  for (int i = 0; i < textLength; ++i) {
549  Rect clickGlyphRect = m_glyphsCoords[i];
550  if (!clickGlyphRect.isValid())
551  continue;
552  if (!firstGlyphRect.isValid())
553  firstGlyphRect = clickGlyphRect;
554  lastGlyphRect = clickGlyphRect;
555  clickGlyphRect.expandTop(m_font->getYOffset() + m_font->getGlyphSpacing().height());
556  clickGlyphRect.expandLeft(m_font->getGlyphSpacing().width() + 1);
557  if (clickGlyphRect.contains(pos)) {
558  candidatePos = i;
559  break;
560  }
561  else if (pos.y >= clickGlyphRect.top() && pos.y <= clickGlyphRect.bottom()) {
562  if (pos.x <= clickGlyphRect.left()) {
563  candidatePos = i;
564  break;
565  }
566  else if (pos.x >= clickGlyphRect.right())
567  candidatePos = i + 1;
568  }
569  }
570 
571  if (textLength > 0) {
572  if (pos.y < firstGlyphRect.top())
573  return 0;
574  else if (pos.y > lastGlyphRect.bottom())
575  return textLength;
576  }
577 
578  return candidatePos;
579 }
580 
582 {
583  std::string text;
584  if (m_textHidden)
585  text = std::string(m_text.length(), '*');
586  else
587  text = m_text;
588 
589  if (m_textWrap && m_rect.isValid())
590  text = m_font->wrapText(text, getPaddingRect().width() - m_textOffset.x);
591 
592  return text;
593 }
594 
596 {
597  if (!hasSelection())
598  return std::string();
599  return m_text.substr(m_selectionStart, m_selectionEnd - m_selectionStart);
600 }
601 
603 {
604  if (m_cursorPos > static_cast<int>(m_text.length()))
605  m_cursorPos = m_text.length();
606 
607  // any text changes reset the selection
608  if (m_selectable) {
609  m_selectionEnd = 0;
610  m_selectionStart = 0;
611  }
612 
613  blinkCursor();
614  update(true);
615 }
616 
617 void UITextEdit::onHoverChange(bool hovered)
618 {
619  if (m_changeCursorImage) {
620  if (hovered && !g_mouse.isCursorChanged())
621  g_mouse.pushCursor("text");
622  else
623  g_mouse.popCursor("text");
624  }
625 }
626 
627 void UITextEdit::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
628 {
629  UIWidget::onStyleApply(styleName, styleNode);
630 
631  for (const OTMLNodePtr& node : styleNode->children()) {
632  if (node->tag() == "text") {
633  setText(node->value());
634  setCursorPos(m_text.length());
635  }
636  else if (node->tag() == "text-hidden")
637  setTextHidden(node->value<bool>());
638  else if (node->tag() == "shift-navigation")
639  setShiftNavigation(node->value<bool>());
640  else if (node->tag() == "multiline")
641  setMultiline(node->value<bool>());
642  else if (node->tag() == "max-length")
643  setMaxLength(node->value<int>());
644  else if (node->tag() == "editable")
645  setEditable(node->value<bool>());
646  else if (node->tag() == "selectable")
647  setSelectable(node->value<bool>());
648  else if (node->tag() == "selection-color")
649  setSelectionColor(node->value<Color>());
650  else if (node->tag() == "selection-background-color")
651  setSelectionBackgroundColor(node->value<Color>());
652  else if (node->tag() == "selection") {
653  Point selectionRange = node->value<Point>();
654  setSelection(selectionRange.x, selectionRange.y);
655  }
656  else if (node->tag() == "cursor-visible")
657  setCursorVisible(node->value<bool>());
658  else if (node->tag() == "change-cursor-image")
659  setChangeCursorImage(node->value<bool>());
660  else if (node->tag() == "auto-scroll")
661  setAutoScroll(node->value<bool>());
662  }
663 }
664 
665 void UITextEdit::onGeometryChange(const Rect& oldRect, const Rect& newRect)
666 {
667  update(true);
668  UIWidget::onGeometryChange(oldRect, newRect);
669 }
670 
671 void UITextEdit::onFocusChange(bool focused, Fw::FocusReason reason)
672 {
673  if (focused) {
674  if (reason == Fw::KeyboardFocusReason)
675  setCursorPos(m_text.length());
676  else
677  blinkCursor();
678  update(true);
679  }
680  else if (m_selectable)
681  clearSelection();
682  UIWidget::onFocusChange(focused, reason);
683 }
684 
685 bool UITextEdit::onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeatTicks)
686 {
687  if (UIWidget::onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks))
688  return true;
689 
690  if (keyboardModifiers == Fw::KeyboardNoModifier) {
691  if (keyCode == Fw::KeyDelete && m_editable) { // erase right character
692  if (hasSelection() || !m_text.empty()) {
693  del(true);
694  return true;
695  }
696  }
697  else if (keyCode == Fw::KeyBackspace && m_editable) { // erase left character
698  if (hasSelection() || !m_text.empty()) {
699  del(false);
700  return true;
701  }
702  }
703  else if (keyCode == Fw::KeyRight && !m_shiftNavigation) { // move cursor right
704  clearSelection();
706  return true;
707  }
708  else if (keyCode == Fw::KeyLeft && !m_shiftNavigation) { // move cursor left
709  clearSelection();
710  moveCursorHorizontally(false);
711  return true;
712  }
713  else if (keyCode == Fw::KeyHome) { // move cursor to first character
714  if (m_cursorPos != 0) {
715  clearSelection();
716  setCursorPos(0);
717  return true;
718  }
719  }
720  else if (keyCode == Fw::KeyEnd) { // move cursor to last character
721  if (m_cursorPos != static_cast<int>(m_text.length())) {
722  clearSelection();
723  setCursorPos(m_text.length());
724  return true;
725  }
726  }
727  else if (keyCode == Fw::KeyTab && !m_shiftNavigation) {
728  clearSelection();
729  if (UIWidgetPtr parent = getParent())
730  parent->focusNextChild(Fw::KeyboardFocusReason, true);
731  return true;
732  }
733  else if (keyCode == Fw::KeyEnter && m_multiline && m_editable) {
734  appendCharacter('\n');
735  return true;
736  }
737  else if (keyCode == Fw::KeyUp && !m_shiftNavigation && m_multiline) {
738  moveCursorVertically(true);
739  return true;
740  }
741  else if (keyCode == Fw::KeyDown && !m_shiftNavigation && m_multiline) {
742  moveCursorVertically(false);
743  return true;
744  }
745  }
746  else if (keyboardModifiers == Fw::KeyboardCtrlModifier) {
747  if (keyCode == Fw::KeyV && m_editable) {
749  return true;
750  }
751  else if (keyCode == Fw::KeyX && m_editable && m_selectable) {
752  if (hasSelection()) {
753  cut();
754  return true;
755  }
756  }
757  else if (keyCode == Fw::KeyC && m_selectable) {
758  if (hasSelection()) {
759  copy();
760  return true;
761  }
762  }
763  else if (keyCode == Fw::KeyA && m_selectable) {
764  if (m_text.length() > 0) {
765  selectAll();
766  return true;
767  }
768  }
769  }
770  else if (keyboardModifiers == Fw::KeyboardShiftModifier) {
771  if (keyCode == Fw::KeyTab && !m_shiftNavigation) {
772  if (UIWidgetPtr parent = getParent())
773  parent->focusPreviousChild(Fw::KeyboardFocusReason, true);
774  return true;
775  }
776  else if (keyCode == Fw::KeyRight || keyCode == Fw::KeyLeft) {
777 
778  int oldCursorPos = m_cursorPos;
779 
780  if (keyCode == Fw::KeyRight) // move cursor right
782  else if (keyCode == Fw::KeyLeft) // move cursor left
783  moveCursorHorizontally(false);
784 
785  if (m_shiftNavigation)
786  clearSelection();
787  else {
788  if (!hasSelection())
789  m_selectionReference = oldCursorPos;
790  setSelection(m_selectionReference, m_cursorPos);
791  }
792  return true;
793  }
794  else if (keyCode == Fw::KeyHome) { // move cursor to first character
795  if (m_cursorPos != 0) {
796  setSelection(m_cursorPos, 0);
797  setCursorPos(0);
798  return true;
799  }
800  }
801  else if (keyCode == Fw::KeyEnd) { // move cursor to last character
802  if (m_cursorPos != static_cast<int>(m_text.length())) {
803  setSelection(m_cursorPos, m_text.length());
804  setCursorPos(m_text.length());
805  return true;
806  }
807  }
808  }
809 
810  return false;
811 }
812 
813 bool UITextEdit::onKeyText(const std::string& keyText)
814 {
815  if (m_editable) {
816  appendText(keyText);
817  return true;
818  }
819  return false;
820 }
821 
822 bool UITextEdit::onMousePress(const Point& mousePos, Fw::MouseButton button)
823 {
824  if (UIWidget::onMousePress(mousePos, button))
825  return true;
826 
827  if (button == Fw::MouseLeftButton) {
828  int pos = getTextPos(mousePos);
829  if (pos >= 0) {
830  setCursorPos(pos);
831 
832  if (m_selectable) {
833  m_selectionReference = pos;
834  setSelection(pos, pos);
835  }
836  }
837  return true;
838  }
839  return false;
840 }
841 
842 bool UITextEdit::onMouseRelease(const Point& mousePos, Fw::MouseButton button)
843 {
844  return UIWidget::onMouseRelease(mousePos, button);
845 }
846 
847 bool UITextEdit::onMouseMove(const Point& mousePos, const Point& mouseMoved)
848 {
849  if (UIWidget::onMouseMove(mousePos, mouseMoved))
850  return true;
851 
852  if (m_selectable && isPressed()) {
853  int pos = getTextPos(mousePos);
854  if (pos >= 0) {
855  setSelection(m_selectionReference, pos);
856  setCursorPos(pos);
857  }
858  return true;
859  }
860  return false;
861 }
862 
863 bool UITextEdit::onDoubleClick(const Point& mousePos)
864 {
865  if (UIWidget::onDoubleClick(mousePos))
866  return true;
867  if (m_selectable && m_text.length() > 0) {
868  selectAll();
869  return true;
870  }
871  return false;
872 }
873 
874 void UITextEdit::onTextAreaUpdate(const Point& offset, const Size& visibleSize, const Size& totalSize)
875 {
876  callLuaField("onTextAreaUpdate", offset, visibleSize, totalSize);
877 }
UITextEdit::setCursorPos
void setCursorPos(int pos)
Definition: uitextedit.cpp:350
TRect::contains
bool contains(const TPoint< T > &p, bool insideOnly=false) const
Definition: rect.h:141
Fw::KeyUp
@ KeyUp
Definition: const.h:72
UIWidget::onFocusChange
virtual void onFocusChange(bool focused, Fw::FocusReason reason)
Definition: uiwidget.cpp:1517
Painter::setColor
virtual void setColor(const Color &color)
Definition: painter.h:77
UITextEdit::getDisplayedText
std::string getDisplayedText()
Definition: uitextedit.cpp:581
Mouse::popCursor
void popCursor(const std::string &name)
Definition: mouse.cpp:76
EdgeGroup::right
T right
Definition: uiwidget.h:41
UIWidget::getPaddingRect
Rect getPaddingRect()
Definition: uiwidget.cpp:1061
Fw::KeyBackspace
@ KeyBackspace
Definition: const.h:61
UIWidget::isActive
bool isActive()
Definition: uiwidget.h:225
Fw::KeyEnter
@ KeyEnter
Definition: const.h:63
graphics.h
Mouse::pushCursor
bool pushCursor(const std::string &name)
Definition: mouse.cpp:64
UITextEdit::getSelection
std::string getSelection()
Definition: uitextedit.cpp:595
UIWidget::isPressed
bool isPressed()
Definition: uiwidget.h:230
std::swap
void swap(stdext::packed_vector< T, U > &lhs, stdext::packed_vector< T, U > &rhs)
Definition: packed_vector.h:158
Color
Definition: color.h:32
TRect::expandTop
void expandTop(T add)
Definition: rect.h:92
TPoint::y
T y
Definition: point.h:83
PlatformWindow::setClipboardText
virtual void setClipboardText(const std::string &text)=0
TSize::setWidth
void setWidth(T w)
Definition: size.h:47
platformwindow.h
UITextEdit::wrapText
void wrapText()
Definition: uitextedit.cpp:512
UIWidget::m_textOffset
Point m_textOffset
Definition: uiwidget.h:484
TRect< int >
UITextEdit::onKeyPress
virtual bool onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeatTicks)
Definition: uitextedit.cpp:685
UIWidget::m_textWrap
stdext::boolean< false > m_textWrap
Definition: uiwidget.h:485
UITextEdit::setShiftNavigation
void setShiftNavigation(bool enable)
Definition: uitextedit.h:46
UIWidget::onStyleApply
virtual void onStyleApply(const std::string &styleName, const OTMLNodePtr &styleNode)
Definition: uiwidget.cpp:1480
UITextEdit::onStyleApply
virtual void onStyleApply(const std::string &styleName, const OTMLNodePtr &styleNode)
Definition: uitextedit.cpp:627
UITextEdit::selectAll
void selectAll()
Definition: uitextedit.h:67
Fw::KeyboardNoModifier
@ KeyboardNoModifier
Definition: const.h:260
UITextEdit::setTextHidden
void setTextHidden(bool hidden)
Definition: uitextedit.cpp:382
UIWidget::m_textAlign
Fw::AlignmentFlag m_textAlign
Definition: uiwidget.h:483
Fw::AlignTopLeft
@ AlignTopLeft
Definition: const.h:200
EdgeGroup::top
T top
Definition: uiwidget.h:40
TRect::left
T left() const
Definition: rect.h:52
UITextEdit::onFocusChange
virtual void onFocusChange(bool focused, Fw::FocusReason reason)
Definition: uitextedit.cpp:671
TRect::isEmpty
bool isEmpty() const
Definition: rect.h:49
UITextEdit::copy
std::string copy()
Definition: uitextedit.cpp:495
Fw::KeyRight
@ KeyRight
Definition: const.h:75
UITextEdit::onMouseMove
virtual bool onMouseMove(const Point &mousePos, const Point &mouseMoved)
Definition: uitextedit.cpp:847
UITextEdit::drawSelf
void drawSelf(Fw::DrawPane drawPane)
Definition: uitextedit.cpp:58
UITextEdit::getTextPos
int getTextPos(Point pos)
Definition: uitextedit.cpp:541
Fw::KeyX
@ KeyX
Definition: const.h:141
TRect::setTop
void setTop(T pos)
Definition: rect.h:76
UITextEdit::paste
void paste(const std::string &text)
Definition: uitextedit.cpp:488
Fw::KeyboardFocusReason
@ KeyboardFocusReason
Definition: const.h:223
UITextEdit::onGeometryChange
virtual void onGeometryChange(const Rect &oldRect, const Rect &newRect)
Definition: uitextedit.cpp:665
Fw::KeyC
@ KeyC
Definition: const.h:120
TPoint::toSize
TSize< T > toSize() const
Definition: point.h:42
OTMLNode::children
OTMLNodeList children()
Definition: otmlnode.cpp:171
UITextEdit::appendText
void appendText(std::string text)
Definition: uitextedit.cpp:394
uitextedit.h
TRect::bottom
T bottom() const
Definition: rect.h:55
Point
TPoint< int > Point
Definition: point.h:86
Fw::KeyboardShiftModifier
@ KeyboardShiftModifier
Definition: const.h:263
PlatformWindow::getClipboardText
virtual std::string getClipboardText()=0
Fw::KeyLeft
@ KeyLeft
Definition: const.h:74
TRect::setLeft
void setLeft(T pos)
Definition: rect.h:75
UIWidget::m_textVerticalAutoResize
stdext::boolean< false > m_textVerticalAutoResize
Definition: uiwidget.h:486
UIWidget::m_text
std::string m_text
Definition: uiwidget.h:481
TSize::width
int width() const
Definition: size.h:43
UIWidget::m_rect
Rect m_rect
Definition: uiwidget.h:62
UIWidget::drawBorder
void drawBorder(const Rect &screenCoords)
Definition: uiwidgetbasestyle.cpp:348
Fw::FocusReason
FocusReason
Definition: const.h:221
Fw::MouseLeftButton
@ MouseLeftButton
Definition: const.h:248
CoordsBuffer::enableHardwareCaching
void enableHardwareCaching(HardwareBuffer::UsagePattern usagePattern=HardwareBuffer::DynamicDraw)
Definition: coordsbuffer.cpp:86
clock.h
TRect::expandLeft
void expandLeft(T add)
Definition: rect.h:91
UITextEdit::cut
std::string cut()
Definition: uitextedit.cpp:505
UITextEdit::setSelectable
void setSelectable(bool selectable)
Definition: uitextedit.h:51
UIWidget::onGeometryChange
virtual void onGeometryChange(const Rect &oldRect, const Rect &newRect)
Definition: uiwidget.cpp:1496
UIWidget::m_font
BitmapFontPtr m_font
Definition: uiwidget.h:489
TRect::setRight
void setRight(T pos)
Definition: rect.h:77
UITextEdit::setCursorVisible
void setCursorVisible(bool enable)
Definition: uitextedit.h:42
TRect::topLeft
TPoint< T > topLeft() const
Definition: rect.h:60
UITextEdit::onMousePress
virtual bool onMousePress(const Point &mousePos, Fw::MouseButton button)
Definition: uitextedit.cpp:822
UITextEdit::setSelection
void setSelection(int start, int end)
Definition: uitextedit.cpp:366
UITextEdit::clearSelection
void clearSelection()
Definition: uitextedit.h:68
g_window
PlatformWindow & g_window
Definition: platformwindow.cpp:37
Fw::KeyEnd
@ KeyEnd
Definition: const.h:69
UITextEdit::setMultiline
void setMultiline(bool enable)
Definition: uitextedit.h:47
g_mouse
Mouse g_mouse
Definition: mouse.cpp:28
BitmapFont::wrapText
std::string wrapText(const std::string &text, int maxWidth)
Definition: bitmapfont.cpp:293
TRect::expandRight
void expandRight(T add)
Definition: rect.h:93
uint
unsigned int uint
Definition: types.h:31
TSize::setHeight
void setHeight(T h)
Definition: size.h:48
UIWidget::m_padding
EdgeGroup< int > m_padding
Definition: uiwidget.h:292
LuaObject::callLuaField
R callLuaField(const std::string &field, const T &... args)
Definition: luaobject.h:172
UIWidget::onMouseRelease
virtual bool onMouseRelease(const Point &mousePos, Fw::MouseButton button)
Definition: uiwidget.cpp:1595
UITextEdit::moveCursorVertically
void moveCursorVertically(bool up)
Definition: uitextedit.cpp:536
UITextEdit::hasSelection
bool hasSelection()
Definition: uitextedit.h:83
Fw::AlignHorizontalCenter
@ AlignHorizontalCenter
Definition: const.h:198
UITextEdit::setSelectionColor
void setSelectionColor(const Color &color)
Definition: uitextedit.h:52
BitmapFont::getGlyphSpacing
Size getGlyphSpacing()
Definition: bitmapfont.h:64
mouse.h
Color::white
static const Color white
Definition: color.h:101
CoordsBuffer::clear
void clear()
Definition: coordsbuffer.h:38
UITextEdit::appendCharacter
void appendCharacter(char c)
Definition: uitextedit.cpp:427
UIWidget::setText
void setText(std::string text, bool dontFireLuaCall=false)
Definition: uiwidgettext.cpp:117
BitmapFont::getTexture
const TexturePtr & getTexture()
Definition: bitmapfont.h:62
Fw::KeyHome
@ KeyHome
Definition: const.h:68
UIWidget::getParent
UIWidgetPtr getParent()
Definition: uiwidget.h:255
Size
TSize< int > Size
Definition: size.h:107
Fw::KeyA
@ KeyA
Definition: const.h:118
UITextEdit::removeCharacter
void removeCharacter(bool right)
Definition: uitextedit.cpp:451
TPoint::x
T x
Definition: point.h:83
Mouse::isCursorChanged
bool isCursorChanged()
Definition: mouse.cpp:102
UIWidget::onMousePress
virtual bool onMousePress(const Point &mousePos, Fw::MouseButton button)
Definition: uiwidget.cpp:1579
UIWidget::onDoubleClick
virtual bool onDoubleClick(const Point &mousePos)
Definition: uiwidget.cpp:1615
UITextEdit::onDoubleClick
virtual bool onDoubleClick(const Point &mousePos)
Definition: uitextedit.cpp:863
g_app
ConsoleApplication g_app
Definition: consoleapplication.cpp:32
Color::black
static const Color black
Definition: color.h:102
UIWidget::getSize
Size getSize()
Definition: uiwidget.h:357
UIWidget::drawIcon
void drawIcon(const Rect &screenCoords)
Definition: uiwidgetbasestyle.cpp:380
Rect
TRect< int > Rect
Definition: rect.h:319
UIWidget::isExplicitlyEnabled
bool isExplicitlyEnabled()
Definition: uiwidget.h:240
UITextEdit::setMaxLength
void setMaxLength(uint maxLength)
Definition: uitextedit.h:48
Color::alpha
static const Color alpha
Definition: color.h:100
BitmapFont::getGlyphsTextureCoords
const Rect * getGlyphsTextureCoords()
Definition: bitmapfont.h:60
UIWidget::drawImage
void drawImage(const Rect &screenCoords)
Definition: uiwidgetimage.cpp:78
UITextEdit::setTextVirtualOffset
void setTextVirtualOffset(const Point &offset)
Definition: uitextedit.cpp:388
UIWidget::m_textHorizontalAutoResize
stdext::boolean< false > m_textHorizontalAutoResize
Definition: uiwidget.h:487
TSize::height
int height() const
Definition: size.h:44
Painter::resetColor
void resetColor()
Definition: painter.h:108
uchar
unsigned char uchar
Definition: types.h:29
Painter::drawFillCoords
virtual void drawFillCoords(CoordsBuffer &coordsBuffer)=0
TRect::right
T right() const
Definition: rect.h:54
BitmapFont::getYOffset
int getYOffset()
Definition: bitmapfont.h:63
TRect::isValid
bool isValid() const
Definition: rect.h:50
otmlnode.h
Fw::DrawPane
DrawPane
Definition: const.h:285
UITextEdit::setEditable
void setEditable(bool editable)
Definition: uitextedit.h:50
stdext::shared_object_ptr< Texture >
Fw::KeyV
@ KeyV
Definition: const.h:139
BitmapFont::calculateGlyphsPositions
const std::vector< Point > & calculateGlyphsPositions(const std::string &text, Fw::AlignmentFlag align=Fw::AlignTopLeft, Size *textBoxSize=nullptr)
Calculate glyphs positions to use on render, also calculates textBoxSize if wanted.
Definition: bitmapfont.cpp:172
bitmapfont.h
TRect::intersects
bool intersects(const TRect< T > &r) const
Definition: rect.h:181
UITextEdit::setChangeCursorImage
void setChangeCursorImage(bool enable)
Definition: uitextedit.h:43
UITextEdit::updateText
void updateText()
Definition: uitextedit.cpp:602
CoordsBuffer::addRect
void addRect(const Rect &dest)
Definition: coordsbuffer.h:48
Fw::ForegroundPane
@ ForegroundPane
Definition: const.h:286
TRect::expandBottom
void expandBottom(T add)
Definition: rect.h:94
stdext::replace_all
void replace_all(std::string &str, const std::string &search, const std::string &replacement)
Definition: string.cpp:268
g_painter
Painter * g_painter
Definition: painter.cpp:28
UITextEdit::del
void del(bool right=false)
Definition: uitextedit.cpp:474
UITextEdit::setAutoScroll
void setAutoScroll(bool autoScroll)
Definition: uitextedit.h:54
UIWidget::setSize
void setSize(const Size &size)
Definition: uiwidget.h:303
TRect::height
T height() const
Definition: rect.h:70
BitmapFont::getGlyphHeight
int getGlyphHeight()
Definition: bitmapfont.h:59
Fw::KeyDown
@ KeyDown
Definition: const.h:73
UITextEdit::setSelectionBackgroundColor
void setSelectionBackgroundColor(const Color &color)
Definition: uitextedit.h:53
TRect::top
T top() const
Definition: rect.h:53
UITextEdit::moveCursorHorizontally
void moveCursorHorizontally(bool right)
Definition: uitextedit.cpp:517
Clock::millis
ticks_t millis()
Definition: clock.h:37
UIWidget::onMouseMove
virtual bool onMouseMove(const Point &mousePos, const Point &mouseMoved)
Definition: uiwidget.cpp:1600
Fw::KeyboardCtrlModifier
@ KeyboardCtrlModifier
Definition: const.h:261
Fw::AlignBottom
@ AlignBottom
Definition: const.h:197
UITextEdit::onTextAreaUpdate
virtual void onTextAreaUpdate(const Point &vitualOffset, const Size &visibleSize, const Size &totalSize)
Definition: uitextedit.cpp:874
UITextEdit::onHoverChange
virtual void onHoverChange(bool hovered)
Definition: uitextedit.cpp:617
TPoint< int >
TRect::size
TSize< T > size() const
Definition: rect.h:71
EdgeGroup::bottom
T bottom
Definition: uiwidget.h:42
EdgeGroup::left
T left
Definition: uiwidget.h:43
Painter::drawFilledRect
virtual void drawFilledRect(const Rect &dest)=0
UIWidget::m_drawText
std::string m_drawText
Definition: uiwidget.h:482
TRect::width
T width() const
Definition: rect.h:69
UIWidget::onKeyPress
virtual bool onKeyPress(uchar keyCode, int keyboardModifiers, int autoRepeatTicks)
Definition: uiwidget.cpp:1569
Fw::AlignVerticalCenter
@ AlignVerticalCenter
Definition: const.h:199
UITextEdit::onMouseRelease
virtual bool onMouseRelease(const Point &mousePos, Fw::MouseButton button)
Definition: uitextedit.cpp:842
TSize< int >
g_clock
Clock g_clock
Definition: clock.cpp:25
Painter::drawTextureCoords
virtual void drawTextureCoords(CoordsBuffer &coordsBuffer, const TexturePtr &texture)=0
BitmapFont::getGlyphsSize
const Size * getGlyphsSize()
Definition: bitmapfont.h:61
Fw::MouseButton
MouseButton
Definition: const.h:246
TRect::translate
void translate(T x, T y)
Definition: rect.h:98
Fw::KeyDelete
@ KeyDelete
Definition: const.h:65
Fw::AlignRight
@ AlignRight
Definition: const.h:195
UITextEdit::blinkCursor
void blinkCursor()
Definition: uitextedit.cpp:468
Fw::KeyTab
@ KeyTab
Definition: const.h:60
UITextEdit::UITextEdit
UITextEdit()
Definition: uitextedit.cpp:32
TRect::setBottom
void setBottom(T pos)
Definition: rect.h:78
application.h
UITextEdit::onKeyText
virtual bool onKeyText(const std::string &keyText)
Definition: uitextedit.cpp:813
UIWidget::drawBackground
void drawBackground(const Rect &screenCoords)
Definition: uiwidgetbasestyle.cpp:336
UIWidget::m_color
Color m_color
Definition: uiwidget.h:281