Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qquicktextinput.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquicktextinput_p.h"
6#include "qquickwindow.h"
7
8#include <private/qqmlglobal_p.h>
9#include <private/qv4scopedvalue_p.h>
10
11#include <QtCore/qcoreapplication.h>
12#include <QtCore/qmimedata.h>
13#include <QtQml/qqmlinfo.h>
14#include <QtGui/qevent.h>
15#include <QTextBoundaryFinder>
16#include "qquicktextnode_p.h"
17#include <QtQuick/qsgsimplerectnode.h>
18
19#include <QtGui/qstylehints.h>
20#include <QtGui/qinputmethod.h>
21#include <QtCore/qmath.h>
22
23#if QT_CONFIG(accessibility)
24#include "qaccessible.h"
26#endif
27
28#include <QtGui/private/qtextengine_p.h>
29#include <QtGui/private/qinputcontrol_p.h>
30
32
33DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
34Q_LOGGING_CATEGORY(lcQuickTextInput, "qt.quick.textInput")
35
36
59{
60 Q_D(QQuickTextInput);
61 d->init();
62}
63
66{
67 Q_D(QQuickTextInput);
68 d->init();
69}
70
72{
73}
74
76{
77 Q_D(QQuickTextInput);
78
80
81 d->checkIsValid();
82 d->updateLayout();
83 updateCursorRectangle();
84 if (d->cursorComponent && isCursorVisible())
86}
87
102{
103 Q_D(const QQuickTextInput);
104
105 QString content = d->m_text;
106 QString res = d->m_maskData ? d->stripString(content) : content;
107 return (res.isNull() ? QString::fromLatin1("") : res);
108}
109
111{
112 Q_D(QQuickTextInput);
113 d->updateLayout();
114 invalidateFontCaches();
115}
116
118{
119 Q_D(QQuickTextInput);
120 if (s == text())
121 return;
122
123#if QT_CONFIG(im)
124 d->cancelPreedit();
125#endif
126 d->internalSetText(s, -1, false);
127}
128
129
148{
149 Q_D(const QQuickTextInput);
150 return d->renderType;
151}
152
154{
155 Q_D(QQuickTextInput);
156 if (d->renderType == renderType)
157 return;
158
159 d->renderType = renderType;
161
163 d->updateLayout();
164}
165
179{
180 Q_D(const QQuickTextInput);
181 return d->m_text.size();
182}
183
193{
194 Q_D(const QQuickTextInput);
195
196 if (start > end)
197 qSwap(start, end);
198
199 return d->m_text.mid(start, end - start);
200}
201
203{
204 QString res = m_maskData ? stripString(m_text) : m_text;
205 return (res.isNull() ? QString::fromLatin1("") : res);
206}
207
392{
393 Q_D(const QQuickTextInput);
394 return d->sourceFont;
395}
396
398{
399 Q_D(QQuickTextInput);
400 if (d->sourceFont == font)
401 return;
402
403 d->sourceFont = font;
404 QFont oldFont = d->font;
405 d->font = font;
406 if (d->font.pointSizeF() != -1) {
407 // 0.5pt resolution
408 qreal size = qRound(d->font.pointSizeF()*2.0);
409 d->font.setPointSizeF(size/2.0);
410 }
411 if (oldFont != d->font) {
412 d->updateLayout();
413 updateCursorRectangle();
414#if QT_CONFIG(im)
416#endif
417 }
418 emit fontChanged(d->sourceFont);
419}
420
427{
428 Q_D(const QQuickTextInput);
429 return d->color;
430}
431
433{
434 Q_D(QQuickTextInput);
435 if (c != d->color) {
436 d->color = c;
437 d->textLayoutDirty = true;
439 polish();
440 update();
442 }
443}
444
445
452{
453 Q_D(const QQuickTextInput);
454 return d->selectionColor;
455}
456
458{
459 Q_D(QQuickTextInput);
460 if (d->selectionColor == color)
461 return;
462
463 d->selectionColor = color;
464 if (d->hasSelectedText()) {
465 d->textLayoutDirty = true;
467 polish();
468 update();
469 }
471}
478{
479 Q_D(const QQuickTextInput);
480 return d->selectedTextColor;
481}
482
484{
485 Q_D(QQuickTextInput);
486 if (d->selectedTextColor == color)
487 return;
488
489 d->selectedTextColor = color;
490 if (d->hasSelectedText()) {
491 d->textLayoutDirty = true;
493 polish();
494 update();
495 }
497}
498
535{
536 Q_D(const QQuickTextInput);
537 return d->hAlign;
538}
539
541{
542 Q_D(QQuickTextInput);
543 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
544 d->hAlignImplicit = false;
545 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
546 d->updateLayout();
547 updateCursorRectangle();
548 }
549}
550
552{
553 Q_D(QQuickTextInput);
554 d->hAlignImplicit = true;
555 if (d->determineHorizontalAlignment() && isComponentComplete()) {
556 d->updateLayout();
557 updateCursorRectangle();
558 }
559}
560
562{
563 Q_D(const QQuickTextInput);
564 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
565 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
566 switch (d->hAlign) {
568 effectiveAlignment = QQuickTextInput::AlignRight;
569 break;
571 effectiveAlignment = QQuickTextInput::AlignLeft;
572 break;
573 default:
574 break;
575 }
576 }
577 return effectiveAlignment;
578}
579
581{
582 Q_Q(QQuickTextInput);
583 if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
584 QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
586 emit q->horizontalAlignmentChanged(alignment);
587 if (oldEffectiveHAlign != q->effectiveHAlign())
588 emit q->effectiveHorizontalAlignmentChanged();
589 return true;
590 }
591 return false;
592}
593
595{
597#if QT_CONFIG(im)
598 if (text.isEmpty())
600#endif
601
602 const QChar *character = text.constData();
603 while (!character->isNull()) {
604 switch (character->direction()) {
605 case QChar::DirL:
606 return Qt::LeftToRight;
607 case QChar::DirR:
608 case QChar::DirAL:
609 case QChar::DirAN:
610 return Qt::RightToLeft;
611 default:
612 break;
613 }
614 character++;
615 }
617}
618
620{
624#if QT_CONFIG(im)
627#endif
628 }
630}
631
633{
634 if (hAlignImplicit) {
635 // if no explicit alignment has been set, follow the natural layout direction of the text
637#if QT_CONFIG(im)
640#endif
642 }
643 return false;
644}
645
647{
648 Q_D(const QQuickTextInput);
649 return d->vAlign;
650}
651
653{
654 Q_D(QQuickTextInput);
655 if (alignment == d->vAlign)
656 return;
657 d->vAlign = alignment;
659 if (isComponentComplete()) {
660 updateCursorRectangle();
661 d->updateBaselineOffset();
662 }
663}
664
686{
687 Q_D(const QQuickTextInput);
688 return d->wrapMode;
689}
690
692{
693 Q_D(QQuickTextInput);
694 if (mode == d->wrapMode)
695 return;
696 d->wrapMode = mode;
697 d->updateLayout();
698 updateCursorRectangle();
700}
701
703{
704 Q_Q(QQuickTextInput);
705 if (q->isComponentComplete()) {
707 q->updateCursorRectangle();
708 emit q->effectiveHorizontalAlignmentChanged();
709 }
710 }
711}
712
723{
724 Q_D(const QQuickTextInput);
725 return d->m_readOnly;
726}
727
729{
730 Q_D(QQuickTextInput);
731 if (d->m_readOnly == ro)
732 return;
733
734#if QT_CONFIG(im)
735 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
736#endif
737 d->m_readOnly = ro;
738 d->setCursorPosition(d->end());
739#if QT_CONFIG(im)
740 updateInputMethod(Qt::ImEnabled);
741#endif
742 q_canPasteChanged();
743 d->emitUndoRedoChanged();
745 if (ro) {
746 setCursorVisible(false);
747 } else if (hasActiveFocus()) {
748 setCursorVisible(true);
749 }
750 update();
751}
752
762{
763 Q_D(const QQuickTextInput);
764 return d->m_maxLength;
765}
766
768{
769 Q_D(QQuickTextInput);
770 if (d->m_maxLength == ml || d->m_maskData)
771 return;
772
773 d->m_maxLength = ml;
774 d->internalSetText(d->m_text, -1, false);
775
777}
778
806{
807 Q_D(const QQuickTextInput);
808 return d->cursorVisible;
809}
810
812{
813 Q_D(QQuickTextInput);
814 if (d->cursorVisible == on)
815 return;
816 d->cursorVisible = on;
817 if (on && isComponentComplete())
819 if (!d->cursorItem)
820 d->updateCursorBlinking();
821 emit cursorVisibleChanged(d->cursorVisible);
822}
823
841{
842 Q_D(const QQuickTextInput);
843 return d->m_cursor;
844}
845
847{
848 Q_D(QQuickTextInput);
849 if (cp < 0 || cp > text().size())
850 return;
851 d->moveCursor(cp);
852}
853
866{
867 Q_D(const QQuickTextInput);
868
869 int c = d->m_cursor;
870#if QT_CONFIG(im)
871 c += d->m_preeditCursor;
872#endif
873 if (d->m_echoMode == NoEcho)
874 c = 0;
875 QTextLine l = d->m_textLayout.lineForTextPosition(c);
876 if (!l.isValid())
877 return QRectF();
878 qreal x = l.cursorToX(c) - d->hscroll + leftPadding();
879 qreal y = l.y() - d->vscroll + topPadding();
880 qreal w = 1;
881 if (d->overwriteMode) {
882 if (c < text().size())
883 w = l.cursorToX(c + 1) - x;
884 else
885 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw()
886 }
887 return QRectF(x, y, w, l.height());
888}
889
902{
903 Q_D(const QQuickTextInput);
904 return d->lastSelectionStart;
905}
918{
919 Q_D(const QQuickTextInput);
920 return d->lastSelectionEnd;
921}
936{
937 Q_D(QQuickTextInput);
938 if (start < 0 || end < 0 || start > d->m_text.size() || end > d->m_text.size())
939 return;
940 d->setSelection(start, end-start);
941}
942
959{
960 Q_D(const QQuickTextInput);
961 return d->selectedText();
962}
963
971{
972 Q_D(const QQuickTextInput);
973 return d->focusOnPress;
974}
975
977{
978 Q_D(QQuickTextInput);
979 if (d->focusOnPress == b)
980 return;
981
982 d->focusOnPress = b;
983
984 emit activeFocusOnPressChanged(d->focusOnPress);
985}
995{
996 Q_D(const QQuickTextInput);
997 return d->autoScroll;
998}
999
1001{
1002 Q_D(QQuickTextInput);
1003 if (d->autoScroll == b)
1004 return;
1005
1006 d->autoScroll = b;
1007 //We need to repaint so that the scrolling is taking into account.
1008 updateCursorRectangle();
1009 emit autoScrollChanged(d->autoScroll);
1010}
1011
1012#if QT_CONFIG(validator)
1037QValidator* QQuickTextInput::validator() const
1038{
1039 Q_D(const QQuickTextInput);
1040 return d->m_validator;
1041}
1042
1043void QQuickTextInput::setValidator(QValidator* v)
1044{
1045 Q_D(QQuickTextInput);
1046 if (d->m_validator == v)
1047 return;
1048
1049 if (d->m_validator) {
1051 d->m_validator, QValidator, SIGNAL(changed()),
1052 this, QQuickTextInput, SLOT(q_validatorChanged()));
1053 }
1054
1055 d->m_validator = v;
1056
1057 if (d->m_validator) {
1059 d->m_validator, QValidator, SIGNAL(changed()),
1060 this, QQuickTextInput, SLOT(q_validatorChanged()));
1061 }
1062
1063 if (isComponentComplete())
1064 d->checkIsValid();
1065
1066 emit validatorChanged();
1067}
1068
1069void QQuickTextInput::q_validatorChanged()
1070{
1071 Q_D(QQuickTextInput);
1072 d->checkIsValid();
1073}
1074#endif // validator
1075
1077{
1078 Q_Q(const QQuickTextInput);
1079 QRectF rect;
1080 int a;
1081 // Unfortunately we cannot use selectionStart() and selectionEnd()
1082 // since they always assume that the selectionStart is logically before selectionEnd.
1083 // To rely on that would cause havoc if the user was interactively moving the end selection
1084 // handle to become before the start selection
1085 if (m_selstart == m_selend)
1086 // This is to handle the case when there is "no selection" while moving the handle onto the
1087 // same position as the other handle (in which case it would hide the selection handles)
1088 a = m_cursor;
1089 else
1091 if (a >= 0) {
1092#if QT_CONFIG(im)
1093 a += m_preeditCursor;
1094#endif
1096 a = 0;
1098 if (l.isValid()) {
1099 qreal x = l.cursorToX(a) - hscroll + q->leftPadding();
1100 qreal y = l.y() - vscroll + q->topPadding();
1101 rect.setRect(x, y, 1, l.height());
1102 }
1103 }
1104 return rect;
1105}
1106
1107void QQuickTextInputPrivate::checkIsValid()
1108{
1109 Q_Q(QQuickTextInput);
1110
1111 ValidatorState state = hasAcceptableInput(m_text);
1112 if (!m_maskData)
1113 m_validInput = state != InvalidInput;
1114 if (state != AcceptableInput) {
1115 if (m_acceptableInput) {
1116 m_acceptableInput = false;
1117 emit q->acceptableInputChanged();
1118 }
1119 } else if (!m_acceptableInput) {
1120 m_acceptableInput = true;
1121 emit q->acceptableInputChanged();
1122 }
1123}
1124
1135{
1136 Q_D(const QQuickTextInput);
1137 return d->inputMask();
1138}
1139
1141{
1142 Q_D(QQuickTextInput);
1143 QString canonicalInputMask = im;
1144 if (im.lastIndexOf(QLatin1Char(';')) == -1)
1145 canonicalInputMask.append(QLatin1String("; "));
1146 if (d->inputMask() == canonicalInputMask)
1147 return;
1148
1149 d->setInputMask(im);
1150 emit inputMaskChanged(d->inputMask());
1151}
1152
1163{
1164 Q_D(const QQuickTextInput);
1165 return d->m_acceptableInput;
1166}
1167
1197#if QT_CONFIG(im)
1198Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1199{
1200 Qt::InputMethodHints hints = inputMethodHints;
1202 hints |= Qt::ImhHiddenText;
1204 hints &= ~Qt::ImhHiddenText;
1207 return hints;
1208}
1209#endif
1210
1224{
1225 Q_D(const QQuickTextInput);
1226 return QQuickTextInput::EchoMode(d->m_echoMode);
1227}
1228
1230{
1231 Q_D(QQuickTextInput);
1232 if (echoMode() == echo)
1233 return;
1234 d->cancelPasswordEchoTimer();
1235 d->m_echoMode = echo;
1236 d->m_passwordEchoEditing = false;
1237#if QT_CONFIG(im)
1238 updateInputMethod(Qt::ImHints);
1239#endif
1240 d->updateDisplayText();
1241 updateCursorRectangle();
1242
1243 // If this control is used for password input, we want to minimize
1244 // the possibility of string reallocation not to leak (parts of)
1245 // the password.
1246 if (d->m_echoMode != QQuickTextInput::Normal)
1247 d->m_text.reserve(30);
1248
1250}
1251
1289Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1290{
1291#if !QT_CONFIG(im)
1292 return Qt::ImhNone;
1293#else
1294 Q_D(const QQuickTextInput);
1295 return d->inputMethodHints;
1296#endif // im
1297}
1298
1299void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1300{
1301#if !QT_CONFIG(im)
1302 Q_UNUSED(hints);
1303#else
1304 Q_D(QQuickTextInput);
1305
1306 if (hints == d->inputMethodHints)
1307 return;
1308
1309 d->inputMethodHints = hints;
1310 updateInputMethod(Qt::ImHints);
1312#endif // im
1313}
1314
1329{
1330 Q_D(const QQuickTextInput);
1331 return d->cursorComponent;
1332}
1333
1335{
1336 Q_D(QQuickTextInput);
1338}
1339
1340void QQuickTextInput::createCursor()
1341{
1342 Q_D(QQuickTextInput);
1343 d->cursorPending = true;
1345}
1346
1357{
1358 Q_D(const QQuickTextInput);
1359 if (d->m_echoMode == NoEcho)
1360 pos = 0;
1361#if QT_CONFIG(im)
1362 else if (pos > d->m_cursor)
1363 pos += d->preeditAreaText().size();
1364#endif
1365 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1366 if (!l.isValid())
1367 return QRectF();
1368 qreal x = l.cursorToX(pos) - d->hscroll;
1369 qreal y = l.y() - d->vscroll;
1370 qreal w = 1;
1371 if (d->overwriteMode) {
1372 if (pos < text().size())
1373 w = l.cursorToX(pos + 1) - x;
1374 else
1375 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw()
1376 }
1377 return QRectF(x, y, w, l.height());
1378}
1379
1404{
1405 Q_D(const QQuickTextInput);
1406
1407 qreal x = 0;
1408 qreal y = 0;
1410
1411 if (args->length() < 1)
1412 return;
1413
1414 int i = 0;
1415 QV4::Scope scope(args->v4engine());
1416 QV4::ScopedValue arg(scope, (*args)[0]);
1417 x = arg->toNumber();
1418
1419 if (++i < args->length()) {
1420 arg = (*args)[i];
1421 y = arg->toNumber();
1422 }
1423
1424 if (++i < args->length()) {
1425 arg = (*args)[i];
1427 }
1428
1429 int pos = d->positionAt(x, y, position);
1430 const int cursor = d->m_cursor;
1431 if (pos > cursor) {
1432#if QT_CONFIG(im)
1433 const int preeditLength = d->preeditAreaText().size();
1434 pos = pos > cursor + preeditLength
1435 ? pos - preeditLength
1436 : cursor;
1437#else
1438 pos = cursor;
1439#endif
1440 }
1441 args->setReturnValue(QV4::Encode(pos));
1442}
1443
1445{
1446 Q_Q(const QQuickTextInput);
1447 x += hscroll - q->leftPadding();
1448 y += vscroll - q->topPadding();
1450 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1451 QTextLine nextLine = m_textLayout.lineAt(i);
1452
1453 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1454 break;
1455 line = nextLine;
1456 }
1457 return line.isValid() ? line.xToCursor(x, position) : 0;
1458}
1459
1476{
1477 Q_D(const QQuickTextInput);
1478 return d->overwriteMode;
1479}
1480
1482{
1483 Q_D(QQuickTextInput);
1484 if (d->overwriteMode == overwrite)
1485 return;
1486 d->overwriteMode = overwrite;
1487 emit overwriteModeChanged(overwrite);
1488}
1489
1491{
1492 Q_D(QQuickTextInput);
1493 // Don't allow MacOSX up/down support, and we don't allow a completer.
1494 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1495 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1496 // Ignore when moving off the end unless there is a selection,
1497 // because then moving will do something (deselect).
1498 int cursorPosition = d->m_cursor;
1499 if (cursorPosition == 0)
1500 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1501 if (!ignore && cursorPosition == d->m_text.size())
1502 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1503 }
1504 if (ignore) {
1505 ev->ignore();
1506 } else {
1507 d->processKeyEvent(ev);
1508 }
1509 if (!ev->isAccepted())
1511}
1512
1513#if QT_CONFIG(im)
1514void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1515{
1516 Q_D(QQuickTextInput);
1517 const bool wasComposing = d->hasImState;
1518 d->processInputMethodEvent(ev);
1519 if (!ev->isAccepted())
1520 QQuickImplicitSizeItem::inputMethodEvent(ev);
1521
1522 if (wasComposing != d->hasImState)
1524}
1525#endif
1526
1528{
1529 Q_D(QQuickTextInput);
1530
1531 if (d->selectByMouse && event->button() == Qt::LeftButton &&
1533#if QT_CONFIG(im)
1534 d->commitPreedit();
1535#endif
1536 int cursor = d->positionAt(event->position());
1537 d->selectWordAtPos(cursor);
1538 event->setAccepted(true);
1539 if (!d->hasPendingTripleClick()) {
1540 d->tripleClickStartPoint = event->position();
1541 d->tripleClickTimer.start();
1542 }
1543 } else {
1544 if (d->sendMouseEventToInputContext(event))
1545 return;
1547 }
1548}
1549
1551{
1552 Q_D(QQuickTextInput);
1553
1554 d->pressPos = event->position();
1555
1556 if (d->sendMouseEventToInputContext(event))
1557 return;
1558
1560 if (d->selectByMouse &&
1561 (isMouse
1562#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1563 || d->selectByTouchDrag
1564#endif
1565 )) {
1566 setKeepMouseGrab(false);
1567 d->selectPressed = true;
1568 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1569 if (d->hasPendingTripleClick()
1571 event->setAccepted(true);
1572 selectAll();
1573 return;
1574 }
1575 }
1576
1577 if (isMouse) {
1578 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1579 int cursor = d->positionAt(event->position());
1580 d->moveCursor(cursor, mark);
1581 }
1582
1583 if (d->focusOnPress && !qGuiApp->styleHints()->setFocusOnTouchRelease())
1584 ensureActiveFocus(Qt::MouseFocusReason);
1585
1586 event->setAccepted(true);
1587}
1588
1590{
1591 Q_D(QQuickTextInput);
1593#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1594 && ! d->selectByTouchDrag
1595#endif
1596 )
1597 return;
1598
1599 if (d->selectPressed) {
1600 if (qAbs(int(event->position().x() - d->pressPos.x())) > QGuiApplication::styleHints()->startDragDistance())
1601 setKeepMouseGrab(true);
1602
1603#if QT_CONFIG(im)
1604 if (d->composeMode()) {
1605 // start selection
1606 int startPos = d->positionAt(d->pressPos);
1607 int currentPos = d->positionAt(event->position());
1608 if (startPos != currentPos)
1609 d->setSelection(startPos, currentPos - startPos);
1610 } else
1611#endif
1612 {
1613 moveCursorSelection(d->positionAt(event->position()), d->mouseSelectionMode);
1614 }
1615 event->setAccepted(true);
1616 } else {
1618 }
1619}
1620
1622{
1623 Q_D(QQuickTextInput);
1624 if (d->sendMouseEventToInputContext(event))
1625 return;
1626 if (d->selectPressed) {
1627 d->selectPressed = false;
1628 setKeepMouseGrab(false);
1629 }
1631#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1632 || d->selectByTouchDrag
1633#endif
1634 ;
1635
1636#if QT_CONFIG(clipboard)
1637 if (isMouse && QGuiApplication::clipboard()->supportsSelection()) {
1638 if (event->button() == Qt::LeftButton) {
1639 d->copy(QClipboard::Selection);
1640 } else if (!d->m_readOnly && event->button() == Qt::MiddleButton) {
1641 d->deselect();
1643 }
1644 }
1645#endif
1646
1647 // On a touchscreen or with a stylus, set cursor position and focus on release, not on press;
1648 // if Flickable steals the grab in the meantime, the cursor won't move.
1649 // Check d->hasSelectedText() to keep touch-and-hold word selection working.
1650 if (!isMouse && !d->hasSelectedText())
1651 d->moveCursor(d->positionAt(event->position()), false);
1652
1653 if (d->focusOnPress && qGuiApp->styleHints()->setFocusOnTouchRelease())
1654 ensureActiveFocus(Qt::MouseFocusReason);
1655
1656 if (!event->isAccepted())
1658}
1659
1661{
1662#if QT_CONFIG(im)
1663 if (composeMode()) {
1664 int tmp_cursor = positionAt(event->position());
1665 int mousePos = tmp_cursor - m_cursor;
1666 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().size()) {
1667 if (event->type() == QEvent::MouseButtonRelease) {
1669 }
1670 return true;
1671 }
1672 }
1673#else
1674 Q_UNUSED(event);
1675#endif
1676
1677 return false;
1678}
1679
1681{
1682 Q_D(QQuickTextInput);
1683 d->selectPressed = false;
1684 setKeepMouseGrab(false);
1685}
1686
1688{
1689#if QT_CONFIG(shortcut)
1690 Q_D(QQuickTextInput);
1691 if (ev->type() == QEvent::ShortcutOverride) {
1692 if (d->m_readOnly) {
1693 ev->ignore();
1694 return false;
1695 }
1696 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1697 if (ke == QKeySequence::Copy
1698 || ke == QKeySequence::Paste
1699 || ke == QKeySequence::Cut
1700 || ke == QKeySequence::Redo
1701 || ke == QKeySequence::Undo
1716 ke->accept();
1717 return true;
1718 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1719 || ke->modifiers() == Qt::KeypadModifier) {
1720 if (ke->key() < Qt::Key_Escape) {
1721 ke->accept();
1722 return true;
1723 } else {
1724 switch (ke->key()) {
1725 case Qt::Key_Delete:
1726 case Qt::Key_Home:
1727 case Qt::Key_End:
1728 case Qt::Key_Backspace:
1729 case Qt::Key_Left:
1730 case Qt::Key_Right:
1731 ke->accept();
1732 return true;
1733 default:
1734 break;
1735 }
1736 }
1737 }
1738 ev->ignore();
1739 }
1740#endif
1741
1743}
1744
1746 const QRectF &oldGeometry)
1747{
1748 Q_D(QQuickTextInput);
1749 if (!d->inLayout) {
1750 if (newGeometry.width() != oldGeometry.width())
1751 d->updateLayout();
1752 else if (newGeometry.height() != oldGeometry.height() && d->vAlign != QQuickTextInput::AlignTop)
1753 d->updateBaselineOffset();
1754 updateCursorRectangle();
1755 }
1756 QQuickImplicitSizeItem::geometryChange(newGeometry, oldGeometry);
1757}
1758
1759void QQuickTextInputPrivate::ensureVisible(int position, int preeditCursor, int preeditLength)
1760{
1761 Q_Q(QQuickTextInput);
1762 QTextLine textLine = m_textLayout.lineForTextPosition(position + preeditCursor);
1763 const qreal width = qMax<qreal>(0, q->width() - q->leftPadding() - q->rightPadding());
1764 qreal cix = 0;
1765 qreal widthUsed = 0;
1766 if (textLine.isValid()) {
1767 cix = textLine.cursorToX(position + preeditLength);
1768 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1769 widthUsed = qMax(textLine.naturalTextWidth(), cursorWidth);
1770 }
1771 int previousScroll = hscroll;
1772
1773 if (widthUsed <= width) {
1774 hscroll = 0;
1775 } else {
1776 Q_ASSERT(textLine.isValid());
1777 if (cix - hscroll >= width) {
1778 // text doesn't fit, cursor is to the right of br (scroll right)
1779 hscroll = cix - width;
1780 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1781 // text doesn't fit, cursor is to the left of br (scroll left)
1782 hscroll = cix;
1783 } else if (widthUsed - hscroll < width) {
1784 // text doesn't fit, text document is to the left of br; align
1785 // right
1786 hscroll = widthUsed - width;
1787 } else if (width - hscroll > widthUsed) {
1788 // text doesn't fit, text document is to the right of br; align
1789 // left
1790 hscroll = width - widthUsed;
1791 }
1792#if QT_CONFIG(im)
1793 if (preeditLength > 0) {
1794 // check to ensure long pre-edit text doesn't push the cursor
1795 // off to the left
1796 cix = textLine.cursorToX(position + qMax(0, preeditCursor - 1));
1797 if (cix < hscroll)
1798 hscroll = cix;
1799 }
1800#endif
1801 }
1802 if (previousScroll != hscroll)
1803 textLayoutDirty = true;
1804}
1805
1807{
1809#if QT_CONFIG(im)
1810 const int preeditLength = m_textLayout.preeditAreaText().size();
1811 ensureVisible(m_cursor, m_preeditCursor, preeditLength);
1812#else
1814#endif
1815 } else {
1816 hscroll = 0;
1817 }
1818}
1819
1821{
1822 Q_Q(QQuickTextInput);
1823#if QT_CONFIG(im)
1824 const int preeditLength = m_textLayout.preeditAreaText().size();
1825#endif
1826 const qreal height = qMax<qreal>(0, q->height() - q->topPadding() - q->bottomPadding());
1827 qreal heightUsed = contentSize.height();
1828 qreal previousScroll = vscroll;
1829
1830 if (!autoScroll || heightUsed <= height) {
1831 // text fits in br; use vscroll for alignment
1834 } else {
1835#if QT_CONFIG(im)
1836 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1837#else
1839#endif
1840 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1841 qreal top = r.top();
1842 int bottom = r.bottom();
1843
1844 if (bottom - vscroll >= height) {
1845 // text doesn't fit, cursor is to the below the br (scroll down)
1846 vscroll = bottom - height;
1847 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1848 // text doesn't fit, cursor is above br (scroll up)
1849 vscroll = top;
1850 } else if (heightUsed - vscroll < height) {
1851 // text doesn't fit, text document is to the left of br; align
1852 // right
1853 vscroll = heightUsed - height;
1854 }
1855#if QT_CONFIG(im)
1856 if (preeditLength > 0) {
1857 // check to ensure long pre-edit text doesn't push the cursor
1858 // off the top
1859 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1860 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1861 if (top < vscroll)
1862 vscroll = top;
1863 }
1864#endif
1865 }
1866 if (previousScroll != vscroll)
1867 textLayoutDirty = true;
1868}
1869
1870void QQuickTextInput::triggerPreprocess()
1871{
1872 Q_D(QQuickTextInput);
1873 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1875 polish();
1876 update();
1877}
1878
1880{
1881 invalidateFontCaches();
1882}
1883
1884void QQuickTextInput::invalidateFontCaches()
1885{
1886 Q_D(QQuickTextInput);
1887
1888 if (d->m_textLayout.engine() != nullptr)
1889 d->m_textLayout.engine()->resetFontEngineCache();
1890}
1891
1892void QQuickTextInput::ensureActiveFocus(Qt::FocusReason reason)
1893{
1894 bool hadActiveFocus = hasActiveFocus();
1895 forceActiveFocus(reason);
1896#if QT_CONFIG(im)
1897 Q_D(QQuickTextInput);
1898 // re-open input panel on press if already focused
1899 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1900 qGuiApp->inputMethod()->show();
1901#else
1902 Q_UNUSED(hadActiveFocus);
1903#endif
1904}
1905
1907{
1908 Q_UNUSED(data);
1909 Q_D(QQuickTextInput);
1910
1911 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != nullptr) {
1912 // Update done in preprocess() in the nodes
1914 return oldNode;
1915 }
1916
1918
1919 QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
1920 if (node == nullptr)
1921 node = new QQuickTextNode(this);
1922 d->textNode = node;
1923
1924 const bool showCursor = !isReadOnly() && d->cursorItem == nullptr && d->cursorVisible && d->m_blinkStatus;
1925
1926 if (!d->textLayoutDirty && oldNode != nullptr) {
1927 if (showCursor)
1928 node->setCursor(cursorRectangle(), d->color);
1929 else
1930 node->clearCursor();
1931 } else {
1932 node->setUseNativeRenderer(d->renderType == NativeRendering);
1933 node->deleteContent();
1934 node->setMatrix(QMatrix4x4());
1935
1937 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
1938 QFontMetricsF fm(d->font);
1939 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1940 offset += -QPointF(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
1941 } else {
1942 offset += -QPointF(d->hscroll, d->vscroll);
1943 }
1944
1945 if (!d->m_textLayout.text().isEmpty()
1946#if QT_CONFIG(im)
1947 || !d->m_textLayout.preeditAreaText().isEmpty()
1948#endif
1949 ) {
1950 node->addTextLayout(offset, &d->m_textLayout, d->color,
1952 d->selectionColor, d->selectedTextColor,
1953 d->selectionStart(),
1954 d->selectionEnd() - 1); // selectionEnd() returns first char after
1955 // selection
1956 }
1957
1958 if (showCursor)
1959 node->setCursor(cursorRectangle(), d->color);
1960
1961 d->textLayoutDirty = false;
1962 }
1963
1964 invalidateFontCaches();
1965
1966 return node;
1967}
1968
1969#if QT_CONFIG(im)
1970QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1971{
1972#ifdef Q_OS_ANDROID
1973 // QTBUG-61652
1975 Q_D(const QQuickItem);
1976 // Do not change if type was set manually
1977 if (!d->extra.isAllocated()
1978 || d->extra->enterKeyAttached == nullptr
1979 || d->extra->enterKeyAttached->type() == Qt::EnterKeyDefault) {
1980
1981 QQuickItem *next = const_cast<QQuickTextInput*>(this)->nextItemInFocusChain();
1982 while (next && next != this && !next->activeFocusOnTab())
1983 next = next->nextItemInFocusChain();
1984 if (next) {
1985 const auto nextYPos = next->mapToGlobal(QPoint(0, 0)).y();
1986 const auto currentYPos = this->mapToGlobal(QPoint(0, 0)).y();
1987 if (currentYPos < nextYPos)
1988 // Set EnterKey to KeyNext type only if the next item
1989 // in the focus chain is below current QQuickTextInput
1990 return Qt::EnterKeyNext;
1991 }
1992 }
1993 }
1994#endif
1995 return inputMethodQuery(property, QVariant());
1996}
1997
1998QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, const QVariant &argument) const
1999{
2000 Q_D(const QQuickTextInput);
2001 switch (property) {
2002 case Qt::ImEnabled:
2003 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
2004 case Qt::ImHints:
2005 return QVariant((int) d->effectiveInputMethodHints());
2007 return cursorRectangle();
2009 return d->anchorRectangle();
2010 case Qt::ImFont:
2011 return font();
2012 case Qt::ImCursorPosition: {
2013 const QPointF pt = argument.toPointF();
2014 if (!pt.isNull())
2015 return QVariant(d->positionAt(pt));
2016 return QVariant(d->m_cursor);
2017 }
2019 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
2020 return QVariant(displayText());
2021 } else {
2022 return QVariant(d->realText());
2023 }
2025 return QVariant(selectedText());
2027 return QVariant(maxLength());
2029 if (d->selectionStart() == d->selectionEnd())
2030 return QVariant(d->m_cursor);
2031 else if (d->selectionStart() == d->m_cursor)
2032 return QVariant(d->selectionEnd());
2033 else
2034 return QVariant(d->selectionStart());
2036 return QVariant(d->m_cursor);
2038 if (argument.isValid())
2039 return QVariant(d->m_text.mid(d->m_cursor, argument.toInt()));
2040 return QVariant(d->m_text.mid(d->m_cursor));
2042 if (argument.isValid())
2043 return QVariant(QStringView{d->m_text}.left(d->m_cursor).right(argument.toInt()).toString());
2044 return QVariant(d->m_text.left(d->m_cursor));
2045 case Qt::ImReadOnly:
2046 return QVariant(d->m_readOnly);
2047 default:
2048 return QQuickItem::inputMethodQuery(property);
2049 }
2050}
2051#endif // im
2052
2059{
2060 Q_D(QQuickTextInput);
2061 d->deselect();
2062}
2063
2070{
2071 Q_D(QQuickTextInput);
2072 d->setSelection(0, text().size());
2073}
2074
2082{
2083 if (start > end) {
2084 qmlWarning(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
2085 return false;
2086 } else {
2088 }
2089}
2090
2091#if QT_CONFIG(clipboard)
2101void QQuickTextInput::cut()
2102{
2103 Q_D(QQuickTextInput);
2104 if (!d->m_readOnly && d->m_echoMode == QQuickTextInput::Normal) {
2105 d->copy();
2106 d->del();
2107 }
2108}
2109
2119void QQuickTextInput::copy()
2120{
2121 Q_D(QQuickTextInput);
2122 d->copy();
2123}
2124
2130void QQuickTextInput::paste()
2131{
2132 Q_D(QQuickTextInput);
2133 if (!d->m_readOnly)
2134 d->paste();
2135}
2136#endif // clipboard
2137
2147{
2148 Q_D(QQuickTextInput);
2149 if (!d->m_readOnly) {
2150 d->cancelInput();
2151 d->internalUndo();
2152 d->finishChange(-1, true);
2153 }
2154}
2155
2163{
2164 Q_D(QQuickTextInput);
2165 if (!d->m_readOnly) {
2166 d->cancelInput();
2167 d->internalRedo();
2168 d->finishChange();
2169 }
2170}
2171
2179{
2180 Q_D(QQuickTextInput);
2181 if (d->m_echoMode == QQuickTextInput::Password) {
2182 if (d->m_passwordMaskDelay > 0)
2183 d->m_passwordEchoTimer.start(d->m_passwordMaskDelay, this);
2184 }
2185 if (position < 0 || position > d->m_text.size())
2186 return;
2187
2188 const int priorState = d->m_undoState;
2189
2190 QString insertText = text;
2191
2192 if (d->hasSelectedText()) {
2194 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2195 }
2196 if (d->m_maskData) {
2197 insertText = d->maskString(position, insertText);
2198 for (int i = 0; i < insertText.size(); ++i) {
2200 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
2202 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2203 }
2204 d->m_text.replace(position, insertText.size(), insertText);
2205 if (!insertText.isEmpty())
2206 d->m_textDirty = true;
2207 if (position < d->m_selend && position + insertText.size() > d->m_selstart)
2208 d->m_selDirty = true;
2209 } else {
2210 int remaining = d->m_maxLength - d->m_text.size();
2211 if (remaining != 0) {
2212 insertText = insertText.left(remaining);
2213 d->m_text.insert(position, insertText);
2214 for (int i = 0; i < insertText.size(); ++i)
2216 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2217 if (d->m_cursor >= position)
2218 d->m_cursor += insertText.size();
2219 if (d->m_selstart >= position)
2220 d->m_selstart += insertText.size();
2221 if (d->m_selend >= position)
2222 d->m_selend += insertText.size();
2223 d->m_textDirty = true;
2224 if (position >= d->m_selstart && position <= d->m_selend)
2225 d->m_selDirty = true;
2226 }
2227 }
2228
2230 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2231 d->finishChange(priorState);
2232
2233 if (d->lastSelectionStart != d->lastSelectionEnd) {
2234 if (d->m_selstart != d->lastSelectionStart) {
2235 d->lastSelectionStart = d->m_selstart;
2237 }
2238 if (d->m_selend != d->lastSelectionEnd) {
2239 d->lastSelectionEnd = d->m_selend;
2241 }
2242 }
2243}
2244
2252{
2253 Q_D(QQuickTextInput);
2254
2255 start = qBound(0, start, d->m_text.size());
2256 end = qBound(0, end, d->m_text.size());
2257
2258 if (start > end)
2259 qSwap(start, end);
2260 else if (start == end)
2261 return;
2262
2263 if (start < d->m_selend && end > d->m_selstart)
2264 d->m_selDirty = true;
2265
2266 const int priorState = d->m_undoState;
2267
2269 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2270
2271 if (start <= d->m_cursor && d->m_cursor < end) {
2272 // cursor is within the selection. Split up the commands
2273 // to be able to restore the correct cursor position
2274 for (int i = d->m_cursor; i >= start; --i) {
2276 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2277 }
2278 for (int i = end - 1; i > d->m_cursor; --i) {
2280 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2281 }
2282 } else {
2283 for (int i = end - 1; i >= start; --i) {
2285 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2286 }
2287 }
2288 if (d->m_maskData) {
2289 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2290 for (int i = 0; i < end - start; ++i) {
2292 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2293 }
2294 } else {
2295 d->m_text.remove(start, end - start);
2296
2297 if (d->m_cursor > start)
2298 d->m_cursor -= qMin(d->m_cursor, end) - start;
2299 if (d->m_selstart > start)
2300 d->m_selstart -= qMin(d->m_selstart, end) - start;
2301 if (d->m_selend >= end)
2302 d->m_selend -= end - start;
2303 }
2305 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2306
2307 d->m_textDirty = true;
2308 d->finishChange(priorState);
2309
2310 if (d->lastSelectionStart != d->lastSelectionEnd) {
2311 if (d->m_selstart != d->lastSelectionStart) {
2312 d->lastSelectionStart = d->m_selstart;
2314 }
2315 if (d->m_selend != d->lastSelectionEnd) {
2316 d->lastSelectionEnd = d->m_selend;
2318 }
2319 }
2320}
2321
2322
2329{
2330 Q_D(QQuickTextInput);
2331 d->selectWordAtPos(d->m_cursor);
2332}
2333
2346{
2347 Q_D(const QQuickTextInput);
2348 return QString(d->m_passwordCharacter);
2349}
2350
2352{
2353 Q_D(QQuickTextInput);
2354 if (str.size() < 1)
2355 return;
2356 d->m_passwordCharacter = str.constData()[0];
2357 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2358 d->updateDisplayText();
2360}
2361
2371{
2372 Q_D(const QQuickTextInput);
2373 return d->m_passwordMaskDelay;
2374}
2375
2377{
2378 Q_D(QQuickTextInput);
2379 if (d->m_passwordMaskDelay != delay) {
2380 d->m_passwordMaskDelay = delay;
2381 emit passwordMaskDelayChanged(delay);
2382 }
2383}
2384
2386{
2387 setPasswordMaskDelay(qGuiApp->styleHints()->passwordMaskDelay());
2388}
2389
2407{
2408 Q_D(const QQuickTextInput);
2409 return d->m_textLayout.text().insert(d->m_textLayout.preeditAreaPosition(), d->m_textLayout.preeditAreaText());
2410}
2411
2425{
2426 Q_D(const QQuickTextInput);
2427 return d->m_textLayout.preeditAreaText();
2428}
2429
2449{
2450 Q_D(const QQuickTextInput);
2451 return d->selectByMouse;
2452}
2453
2455{
2456 Q_D(QQuickTextInput);
2457 if (d->selectByMouse != on) {
2458 d->selectByMouse = on;
2460 }
2461}
2462
2475{
2476 Q_D(const QQuickTextInput);
2477 return d->mouseSelectionMode;
2478}
2479
2481{
2482 Q_D(QQuickTextInput);
2483 if (d->mouseSelectionMode != mode) {
2484 d->mouseSelectionMode = mode;
2486 }
2487}
2488
2497{
2498 Q_D(const QQuickTextInput);
2499 return d->persistentSelection;
2500}
2501
2503{
2504 Q_D(QQuickTextInput);
2505 if (d->persistentSelection == on)
2506 return;
2507 d->persistentSelection = on;
2509}
2510
2519{
2520#if QT_CONFIG(clipboard)
2521 Q_D(const QQuickTextInput);
2522 if (!d->canPasteValid) {
2524 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText();
2525 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2526 }
2527 return d->canPaste;
2528#else
2529 return false;
2530#endif
2531}
2532
2542{
2543 Q_D(const QQuickTextInput);
2544 return d->canUndo;
2545}
2546
2556{
2557 Q_D(const QQuickTextInput);
2558 return d->canRedo;
2559}
2560
2570{
2571 Q_D(const QQuickTextInput);
2572 return d->contentSize.width();
2573}
2574
2584{
2585 Q_D(const QQuickTextInput);
2586 return d->contentSize.height();
2587}
2588
2590{
2591 Q_D(QQuickTextInput);
2592 d->moveCursor(position, true);
2593}
2594
2632{
2633 Q_D(QQuickTextInput);
2634
2635 if (mode == SelectCharacters) {
2636 d->moveCursor(pos, true);
2637 } else if (pos != d->m_cursor) {
2638 const int cursor = d->m_cursor;
2639 int anchor;
2640 if (!d->hasSelectedText())
2641 anchor = d->m_cursor;
2642 else if (d->selectionStart() == d->m_cursor)
2643 anchor = d->selectionEnd();
2644 else
2645 anchor = d->selectionStart();
2646
2647 if (anchor < pos || (anchor == pos && cursor < pos)) {
2648 const QString text = this->text();
2650 finder.setPosition(anchor);
2651
2652 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2653 if (anchor < text.size() && (reasons == QTextBoundaryFinder::NotAtBoundary
2654 || (reasons & QTextBoundaryFinder::EndOfItem))) {
2655 finder.toPreviousBoundary();
2656 }
2657 anchor = finder.position() != -1 ? finder.position() : 0;
2658
2659 finder.setPosition(pos);
2660 if (pos > 0 && !finder.boundaryReasons())
2661 finder.toNextBoundary();
2662 const int cursor = finder.position() != -1 ? finder.position() : text.size();
2663
2664 d->setSelection(anchor, cursor - anchor);
2665 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2666 const QString text = this->text();
2668 finder.setPosition(anchor);
2669
2670 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2671 if (anchor > 0 && (reasons == QTextBoundaryFinder::NotAtBoundary
2672 || (reasons & QTextBoundaryFinder::StartOfItem))) {
2673 finder.toNextBoundary();
2674 }
2675 anchor = finder.position() != -1 ? finder.position() : text.size();
2676
2677 finder.setPosition(pos);
2678 if (pos < text.size() && !finder.boundaryReasons())
2679 finder.toPreviousBoundary();
2680 const int cursor = finder.position() != -1 ? finder.position() : 0;
2681
2682 d->setSelection(anchor, cursor - anchor);
2683 }
2684 }
2685}
2686
2688{
2689 Q_D(QQuickTextInput);
2690 d->handleFocusEvent(event);
2692}
2693
2695{
2696 Q_Q(QQuickTextInput);
2697 bool focus = event->gotFocus();
2698 if (!m_readOnly) {
2699 q->setCursorVisible(focus);
2701 }
2702 if (focus) {
2703 q->q_updateAlignment();
2704#if QT_CONFIG(im)
2705 if (focusOnPress && !m_readOnly)
2706 qGuiApp->inputMethod()->show();
2707 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2708 q, SLOT(q_updateAlignment()));
2709#endif
2710 } else {
2712 updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2713 }
2714
2715 if (event->reason() != Qt::ActiveWindowFocusReason
2716 && event->reason() != Qt::PopupFocusReason
2717 && hasSelectedText()
2719 deselect();
2720
2721 if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
2722 emit q->editingFinished();
2723
2724#if QT_CONFIG(im)
2725 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2726 q, SLOT(q_updateAlignment()));
2727#endif
2728 }
2729}
2730
2732{
2733 Q_D(QQuickTextInput);
2734 d->handleFocusEvent(event);
2736}
2737
2751{
2752#if !QT_CONFIG(im)
2753 return false;
2754#else
2755 Q_D(const QQuickTextInput);
2756 return d->hasImState;
2757#endif
2758}
2759
2761 : padding(0)
2762 , topPadding(0)
2763 , leftPadding(0)
2764 , rightPadding(0)
2765 , bottomPadding(0)
2766 , explicitTopPadding(false)
2767 , explicitLeftPadding(false)
2768 , explicitRightPadding(false)
2769 , explicitBottomPadding(false)
2770 , implicitResize(true)
2771{
2772}
2773
2775{
2776 Q_Q(QQuickTextInput);
2777#if QT_CONFIG(clipboard)
2778 if (QGuiApplication::clipboard()->supportsSelection())
2779 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2780 else
2781#endif
2782 q->setAcceptedMouseButtons(Qt::LeftButton);
2783
2784#if QT_CONFIG(im)
2785 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2786#endif
2788#if QT_CONFIG(clipboard)
2790 q, QQuickTextInput, SLOT(q_canPasteChanged()));
2791#endif // clipboard
2792
2794 lastSelectionEnd = 0;
2796
2797 if (!qmlDisableDistanceField()) {
2801 }
2802
2804}
2805
2807{
2808#if QT_CONFIG(im)
2809 Q_Q(QQuickTextInput);
2810 if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
2811 cancelPreedit();
2812#endif // im
2813}
2814
2815void QQuickTextInput::updateCursorRectangle(bool scroll)
2816{
2817 Q_D(QQuickTextInput);
2818 if (!isComponentComplete())
2819 return;
2820
2821 if (scroll) {
2822 d->updateHorizontalScroll();
2823 d->updateVerticalScroll();
2824 }
2826 polish();
2827 update();
2828 emit cursorRectangleChanged();
2829 if (d->cursorItem) {
2830 QRectF r = cursorRectangle();
2831 d->cursorItem->setPosition(r.topLeft());
2832 d->cursorItem->setHeight(r.height());
2833 }
2834#if QT_CONFIG(im)
2835 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
2836#endif
2837}
2838
2839void QQuickTextInput::selectionChanged()
2840{
2841 Q_D(QQuickTextInput);
2842 d->textLayoutDirty = true; //TODO: Only update rect in selection
2844 polish();
2845 update();
2846 emit selectedTextChanged();
2847
2848 if (d->lastSelectionStart != d->selectionStart()) {
2849 d->lastSelectionStart = d->selectionStart();
2850 if (d->lastSelectionStart == -1)
2851 d->lastSelectionStart = d->m_cursor;
2852 emit selectionStartChanged();
2853 }
2854 if (d->lastSelectionEnd != d->selectionEnd()) {
2855 d->lastSelectionEnd = d->selectionEnd();
2856 if (d->lastSelectionEnd == -1)
2857 d->lastSelectionEnd = d->m_cursor;
2858 emit selectionEndChanged();
2859 }
2860}
2861
2863{
2864 Q_D(const QQuickTextInput);
2865
2866 int cursorWidth = d->cursorItem ? 0 : 1;
2867
2868 qreal hscroll = d->hscroll;
2869 if (!d->autoScroll || d->contentSize.width() < width())
2870 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
2871
2872 // Could include font max left/right bearings to either side of rectangle.
2873 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2874 r.setRight(r.right() + cursorWidth);
2875 return r;
2876}
2877
2879{
2880 Q_D(const QQuickTextInput);
2881
2882 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2883
2884 // Could include font max left/right bearings to either side of rectangle.
2886 r.setRight(r.right() + cursorWidth);
2887 return r;
2888}
2889
2890void QQuickTextInput::q_canPasteChanged()
2891{
2892 Q_D(QQuickTextInput);
2893 bool old = d->canPaste;
2894#if QT_CONFIG(clipboard)
2896 d->canPaste = !d->m_readOnly && mimeData->hasText();
2897 else
2898 d->canPaste = false;
2899#endif
2900
2901 bool changed = d->canPaste != old || !d->canPasteValid;
2902 d->canPasteValid = true;
2903 if (changed)
2904 emit canPasteChanged();
2905
2906}
2907
2908void QQuickTextInput::q_updateAlignment()
2909{
2910 Q_D(QQuickTextInput);
2911 if (d->determineHorizontalAlignment()) {
2912 d->updateLayout();
2913 updateCursorRectangle();
2914 }
2915}
2916
2923void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
2924{
2925 QString orig = m_textLayout.text();
2926 QString str;
2929 else
2930 str = m_text;
2931
2935 int cursor = m_cursor - 1;
2936 QChar uc = m_text.at(cursor);
2937 str[cursor] = uc;
2938 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
2939 // second half of a surrogate, check if we have the first half as well,
2940 // if yes restore both at once
2941 uc = m_text.at(cursor - 1);
2942 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
2943 str[cursor - 1] = uc;
2944 }
2945 }
2948 }
2949
2950 // replace certain non-printable characters with spaces (to avoid
2951 // drawing boxes when using fonts that don't have glyphs for such
2952 // characters)
2953 QChar* uc = str.data();
2954 for (int i = 0; i < str.size(); ++i) {
2955 if (uc[i] == QChar::LineSeparator
2958 uc[i] = QChar(0x0020);
2959 }
2960
2961 if (str != orig || forceUpdate) {
2963 updateLayout(); // polish?
2964 emit q_func()->displayTextChanged();
2965 }
2966}
2967
2969{
2970 Q_Q(const QQuickTextInput);
2972
2977 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
2978 layout.setTextOption(option);
2979 layout.setFont(font);
2980#if QT_CONFIG(im)
2982#endif
2983 layout.beginLayout();
2984
2985 QTextLine line = layout.createLine();
2986 line.setLineWidth(INT_MAX);
2987 const qreal theImplicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding();
2988
2989 layout.endLayout();
2990 return theImplicitWidth;
2991}
2992
2994{
2995 Q_Q(const QQuickTextInput);
2996 if (!requireImplicitWidth) {
2997 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
2998 d->requireImplicitWidth = true;
2999
3000 if (q->isComponentComplete())
3001 d->implicitWidth = calculateImplicitWidthForText(m_text);
3002 }
3003 return implicitWidth;
3004}
3005
3007{
3008 Q_Q(QQuickTextInput);
3009 qreal oldPadding = q->topPadding();
3010 if (!reset || extra.isAllocated()) {
3011 extra.value().topPadding = value;
3012 extra.value().explicitTopPadding = !reset;
3013 }
3014 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3015 updateLayout();
3016 q->updateCursorRectangle();
3017 emit q->topPaddingChanged();
3018 }
3019}
3020
3022{
3023 Q_Q(QQuickTextInput);
3024 qreal oldPadding = q->leftPadding();
3025 if (!reset || extra.isAllocated()) {
3026 extra.value().leftPadding = value;
3027 extra.value().explicitLeftPadding = !reset;
3028 }
3029 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3030 updateLayout();
3031 q->updateCursorRectangle();
3032 emit q->leftPaddingChanged();
3033 }
3034}
3035
3037{
3038 Q_Q(QQuickTextInput);
3039 qreal oldPadding = q->rightPadding();
3040 if (!reset || extra.isAllocated()) {
3041 extra.value().rightPadding = value;
3042 extra.value().explicitRightPadding = !reset;
3043 }
3044 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3045 updateLayout();
3046 q->updateCursorRectangle();
3047 emit q->rightPaddingChanged();
3048 }
3049}
3050
3052{
3053 Q_Q(QQuickTextInput);
3054 qreal oldPadding = q->bottomPadding();
3055 if (!reset || extra.isAllocated()) {
3056 extra.value().bottomPadding = value;
3057 extra.value().explicitBottomPadding = !reset;
3058 }
3059 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3060 updateLayout();
3061 q->updateCursorRectangle();
3062 emit q->bottomPaddingChanged();
3063 }
3064}
3065
3067{
3068 return !extra.isAllocated() || extra->implicitResize;
3069}
3070
3072{
3073 if (!enabled)
3074 extra.value().implicitResize = false;
3075 else if (extra.isAllocated())
3076 extra->implicitResize = true;
3077}
3078
3080{
3081 Q_Q(QQuickTextInput);
3082
3083 if (!q->isComponentComplete())
3084 return;
3085
3086
3090 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3091 if (!qmlDisableDistanceField())
3092 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
3093
3096
3098
3101 line.setLineWidth(INT_MAX);
3102 const bool wasInLayout = inLayout;
3103 inLayout = true;
3105 q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding());
3106 inLayout = wasInLayout;
3107 if (inLayout) // probably the result of a binding loop, but by letting it
3108 return; // get this far we'll get a warning to that effect.
3109 }
3110 qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX;
3111 qreal height = 0;
3112 qreal width = 0;
3113 do {
3114 line.setLineWidth(lineWidth);
3115 line.setPosition(QPointF(0, height));
3116
3117 height += line.height();
3118 width = qMax(width, line.naturalTextWidth());
3119
3121 } while (line.isValid());
3123
3124 option.setWrapMode(QTextOption::NoWrap);
3126
3127 textLayoutDirty = true;
3128
3129 const QSizeF previousSize = contentSize;
3131
3133 q->polish();
3134 q->update();
3135
3137 if (!requireImplicitWidth && !q->widthValid())
3138 q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding());
3139 else
3140 q->setImplicitHeight(height + q->topPadding() + q->bottomPadding());
3141 }
3142
3144
3145 if (previousSize != contentSize)
3146 emit q->contentSizeChanged();
3147}
3148
3156{
3157 Q_Q(QQuickTextInput);
3158 if (!q->isComponentComplete())
3159 return;
3160 QFontMetricsF fm(font);
3161 qreal yoff = 0;
3162 if (q->heightValid()) {
3163 const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding();
3165 yoff = surplusHeight;
3167 yoff = surplusHeight/2;
3168 }
3169 q->setBaselineOffset(fm.ascent() + yoff + q->topPadding());
3170}
3171
3172#if QT_CONFIG(clipboard)
3183void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
3184{
3186 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
3188 }
3189}
3190
3199void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
3200{
3201 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
3202 if (!clip.isEmpty() || hasSelectedText()) {
3203 separate(); //make it a separate undo/redo command
3204 insert(clip);
3205 separate();
3206 }
3207}
3208
3209#endif // clipboard
3210
3211#if QT_CONFIG(im)
3215void QQuickTextInputPrivate::commitPreedit()
3216{
3217 Q_Q(QQuickTextInput);
3218
3219 if (!hasImState)
3220 return;
3221
3223
3224 if (!hasImState)
3225 return;
3226
3229}
3230
3231void QQuickTextInputPrivate::cancelPreedit()
3232{
3233 Q_Q(QQuickTextInput);
3234
3235 if (!hasImState)
3236 return;
3237
3239
3242}
3243#endif // im
3244
3255{
3256 int priorState = m_undoState;
3257 if (separateSelection()) {
3258 removeSelectedText();
3259 } else if (m_cursor) {
3260 --m_cursor;
3261 if (m_maskData)
3263 QChar uc = m_text.at(m_cursor);
3264 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3265 // second half of a surrogate, check if we have the first half as well,
3266 // if yes delete both at once
3267 uc = m_text.at(m_cursor - 1);
3268 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
3269 internalDelete(true);
3270 --m_cursor;
3271 }
3272 }
3273 internalDelete(true);
3274 }
3275 finishChange(priorState);
3276}
3277
3288{
3289 int priorState = m_undoState;
3290 if (separateSelection()) {
3291 removeSelectedText();
3292 } else {
3294 while (n--)
3295 internalDelete();
3296 }
3297 finishChange(priorState);
3298}
3299
3308{
3309 int priorState = m_undoState;
3310 if (separateSelection())
3311 removeSelectedText();
3312 internalInsert(newText);
3313 finishChange(priorState);
3314}
3315
3322{
3323 int priorState = m_undoState;
3324 separateSelection();
3325 m_selstart = 0;
3326 m_selend = m_text.size();
3327 removeSelectedText();
3328 separate();
3329 finishChange(priorState, /*update*/false, /*edited*/false);
3330}
3331
3341{
3342 Q_Q(QQuickTextInput);
3343#if QT_CONFIG(im)
3344 commitPreedit();
3345#endif
3346
3347 if (start < 0 || start > m_text.size()) {
3348 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
3349 return;
3350 }
3351
3352 if (length > 0) {
3353 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
3354 return;
3355 m_selstart = start;
3358 } else if (length < 0) {
3360 return;
3361 m_selstart = qMax(start + length, 0);
3362 m_selend = start;
3364 } else if (m_selstart != m_selend) {
3365 m_selstart = 0;
3366 m_selend = 0;
3367 m_cursor = start;
3368 } else {
3369 m_cursor = start;
3370 emitCursorPositionChanged();
3371 return;
3372 }
3373 emit q->selectionChanged();
3374 emitCursorPositionChanged();
3375#if QT_CONFIG(im)
3378#endif
3379}
3380
3390{
3392 m_passwordEchoEditing = editing;
3393 updateDisplayText();
3394}
3395
3403bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3404{
3405#if QT_CONFIG(validator)
3406 if (m_validator) {
3407 QString textCopy = m_text;
3408 int cursorCopy = m_cursor;
3409 m_validator->fixup(textCopy);
3410 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3411 if (textCopy != m_text || cursorCopy != m_cursor)
3412 internalSetText(textCopy, cursorCopy);
3413 return true;
3414 }
3415 }
3416#endif
3417 return false;
3418}
3419
3427{
3428 Q_Q(QQuickTextInput);
3429#if QT_CONFIG(im)
3430 commitPreedit();
3431#endif
3432
3433 if (pos != m_cursor) {
3434 separate();
3435 if (m_maskData)
3437 }
3438 if (mark) {
3439 int anchor;
3441 anchor = m_selend;
3442 else if (m_selend > m_selstart && m_cursor == m_selend)
3443 anchor = m_selstart;
3444 else
3445 anchor = m_cursor;
3446 m_selstart = qMin(anchor, pos);
3447 m_selend = qMax(anchor, pos);
3448 } else {
3449 internalDeselect();
3450 }
3451 m_cursor = pos;
3452 if (mark || m_selDirty) {
3453 m_selDirty = false;
3454 emit q->selectionChanged();
3455 }
3456 emitCursorPositionChanged();
3457#if QT_CONFIG(im)
3458 q->updateInputMethod();
3459#endif
3460}
3461
3462#if QT_CONFIG(im)
3469void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3470{
3471 Q_Q(QQuickTextInput);
3472
3473 int priorState = -1;
3474 bool isGettingInput = !event->commitString().isEmpty()
3475 || event->preeditString() != preeditAreaText()
3476 || event->replacementLength() > 0;
3477 bool cursorPositionChanged = false;
3478 bool selectionChange = false;
3479 m_preeditDirty = event->preeditString() != preeditAreaText();
3480
3481 if (isGettingInput) {
3482 // If any text is being input, remove selected text.
3483 priorState = m_undoState;
3484 separateSelection();
3487 m_selstart = 0;
3488 m_selend = m_text.size();
3489 }
3490 removeSelectedText();
3491 }
3492
3493 int c = m_cursor; // cursor position after insertion of commit string
3494 if (event->replacementStart() <= 0)
3495 c += event->commitString().size() - qMin(-event->replacementStart(), event->replacementLength());
3496
3497 int cursorInsertPos = m_cursor + event->replacementStart();
3498 if (cursorInsertPos < 0)
3499 cursorInsertPos = 0;
3500
3501 // insert commit string
3502 if (event->replacementLength()) {
3503 m_selstart = cursorInsertPos;
3504 m_selend = m_selstart + event->replacementLength();
3506 removeSelectedText();
3507 }
3508 m_cursor = cursorInsertPos;
3509
3510 if (!event->commitString().isEmpty()) {
3511 internalInsert(event->commitString());
3512 cursorPositionChanged = true;
3513 } else {
3514 m_cursor = qBound(0, c, m_text.size());
3515 }
3516
3517 for (int i = 0; i < event->attributes().size(); ++i) {
3518 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3519 if (a.type == QInputMethodEvent::Selection) {
3520 // If we already called internalInsert(), the cursor position will
3521 // already be adjusted correctly. The attribute.start does
3522 // not seem to take the mask into account, so it will reset cursor
3523 // to an invalid position in such case.
3524 if (!cursorPositionChanged)
3525 m_cursor = qBound(0, a.start + a.length, m_text.size());
3526 if (a.length) {
3527 m_selstart = qMax(0, qMin(a.start, m_text.size()));
3529 if (m_selend < m_selstart) {
3531 }
3532 selectionChange = true;
3533 } else {
3534 selectionChange = m_selstart != m_selend;
3535 m_selstart = m_selend = 0;
3536 }
3537 cursorPositionChanged = true;
3538 }
3539 }
3540 QString oldPreeditString = m_textLayout.preeditAreaText();
3541 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3542 if (oldPreeditString != m_textLayout.preeditAreaText()) {
3543 emit q->preeditTextChanged();
3544 if (!event->preeditString().isEmpty() && m_undoPreeditState == -1)
3545 // Pre-edit text started. Remember state for undo purpose.
3546 m_undoPreeditState = priorState;
3547 }
3548 const int oldPreeditCursor = m_preeditCursor;
3549 m_preeditCursor = event->preeditString().size();
3550 hasImState = !event->preeditString().isEmpty();
3551 bool cursorVisible = true;
3553 for (int i = 0; i < event->attributes().size(); ++i) {
3554 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3555 if (a.type == QInputMethodEvent::Cursor) {
3556 hasImState = true;
3557 m_preeditCursor = a.start;
3558 cursorVisible = a.length != 0;
3559 } else if (a.type == QInputMethodEvent::TextFormat) {
3560 hasImState = true;
3561 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3562 if (f.isValid()) {
3564 o.start = a.start + m_cursor;
3565 o.length = a.length;
3566 o.format = f;
3567 formats.append(o);
3568 }
3569 }
3570 }
3572
3573 updateDisplayText(/*force*/ true);
3574 if (cursorPositionChanged && emitCursorPositionChanged())
3575 q->updateInputMethod(Qt::ImCursorPosition | Qt::ImAnchorPosition);
3576 else if (m_preeditCursor != oldPreeditCursor || isGettingInput)
3577 q->updateCursorRectangle();
3578
3579 if (isGettingInput)
3580 finishChange(priorState);
3581
3582 q->setCursorVisible(cursorVisible);
3583
3584 if (selectionChange) {
3585 emit q->selectionChanged();
3586 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle
3588 }
3589
3590 // Empty pre-edit text handled. Clean m_undoPreeditState
3591 if (event->preeditString().isEmpty())
3592 m_undoPreeditState = -1;
3593
3594}
3595#endif // im
3596
3605{
3606 int next = cursor + 1;
3607 if (next > end())
3608 --next;
3610 moveCursor(c, false);
3611 // ## text layout should support end of words.
3613 while (end > cursor && m_text[end-1].isSpace())
3614 --end;
3615 moveCursor(end, true);
3616}
3617
3630bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool edited)
3631{
3632 Q_Q(QQuickTextInput);
3633
3634 Q_UNUSED(update);
3635#if QT_CONFIG(im)
3636 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3637#endif
3638 bool alignmentChanged = false;
3639 bool textChanged = false;
3640
3641 if (m_textDirty) {
3642 // do validation
3643 bool wasValidInput = m_validInput;
3644 bool wasAcceptable = m_acceptableInput;
3645 m_validInput = true;
3646 m_acceptableInput = true;
3647#if QT_CONFIG(validator)
3648 if (m_validator) {
3649 QString textCopy = m_text;
3650 if (m_maskData)
3651 textCopy = maskString(0, m_text, true);
3652 int cursorCopy = m_cursor;
3653 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3654 if (m_maskData)
3655 textCopy = m_text;
3658 if (m_validInput && !m_maskData) {
3659 if (m_text != textCopy) {
3660 internalSetText(textCopy, cursorCopy);
3661 return true;
3662 }
3663 m_cursor = cursorCopy;
3664 }
3665 }
3666#endif
3667 if (m_maskData)
3668 checkIsValid();
3669
3670#if QT_CONFIG(im)
3671 // If we were during pre-edit, validateFromState should point to the state before pre-edit
3672 // has been started. Choose the correct oldest remembered state
3673 if (m_undoPreeditState >= 0 && (m_undoPreeditState < validateFromState || validateFromState < 0))
3674 validateFromState = m_undoPreeditState;
3675#endif
3676 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3677 if (m_transactions.size())
3678 return false;
3679 internalUndo(validateFromState);
3680 m_history.resize(m_undoState);
3681 m_validInput = true;
3682 m_acceptableInput = wasAcceptable;
3683 m_textDirty = false;
3684 }
3685
3686 if (m_textDirty) {
3687 textChanged = true;
3688 m_textDirty = false;
3689#if QT_CONFIG(im)
3690 m_preeditDirty = false;
3691#endif
3692 alignmentChanged = determineHorizontalAlignment();
3693 if (edited)
3694 emit q->textEdited();
3695 emit q->textChanged();
3696 }
3697
3698 updateDisplayText(alignmentChanged);
3699
3700 if (m_acceptableInput != wasAcceptable)
3701 emit q->acceptableInputChanged();
3702 }
3703#if QT_CONFIG(im)
3704 if (m_preeditDirty) {
3705 m_preeditDirty = false;
3707 alignmentChanged = true;
3708 updateLayout();
3709 }
3710 }
3711#endif
3712
3713 if (m_selDirty) {
3714 m_selDirty = false;
3715 emit q->selectionChanged();
3716 }
3717
3718#if QT_CONFIG(im)
3719 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3720 if (inputMethodAttributesChanged)
3721 q->updateInputMethod();
3722#endif
3723 emitUndoRedoChanged();
3724
3725 if (!emitCursorPositionChanged() && (alignmentChanged || textChanged))
3726 q->updateCursorRectangle();
3727
3728 return true;
3729}
3730
3736void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3737{
3738 internalDeselect();
3739 QString oldText = m_text;
3740 if (m_maskData) {
3741 m_text = maskString(0, txt, true);
3742 m_text += clearString(m_text.size(), m_maxLength - m_text.size());
3743 } else {
3744 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3745 }
3746 m_history.clear();
3747 m_undoState = 0;
3748#if QT_CONFIG(im)
3749 m_undoPreeditState = -1;
3750#endif
3751 m_cursor = (pos < 0 || pos > m_text.size()) ? m_text.size() : pos;
3752 m_textDirty = (oldText != m_text);
3753
3754 bool changed = finishChange(-1, true, edited);
3755#if !QT_CONFIG(accessibility)
3756 Q_UNUSED(changed);
3757#else
3758 Q_Q(QQuickTextInput);
3759 if (changed && QAccessible::isActive()) {
3760 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
3761 QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
3762 QAccessible::updateAccessibility(&ev);
3763 }
3764 }
3765#endif
3766}
3767
3768
3775void QQuickTextInputPrivate::addCommand(const Command &cmd)
3776{
3778 m_history.resize(m_undoState + 2);
3780 } else {
3781 m_history.resize(m_undoState + 1);
3782 }
3783 m_separator = false;
3784 m_history[m_undoState++] = cmd;
3785}
3786
3797void QQuickTextInputPrivate::internalInsert(const QString &s)
3798{
3799 Q_Q(QQuickTextInput);
3801 if (m_passwordMaskDelay > 0)
3803 }
3804 Q_ASSERT(!hasSelectedText()); // insert(), processInputMethodEvent() call removeSelectedText() first.
3805 if (m_maskData) {
3806 QString ms = maskString(m_cursor, s);
3807 for (int i = 0; i < ms.size(); ++i) {
3808 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3809 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3810 }
3811 m_text.replace(m_cursor, ms.size(), ms);
3812 m_cursor += ms.size();
3814 m_textDirty = true;
3815 } else {
3816 int remaining = m_maxLength - m_text.size();
3817 if (remaining != 0) {
3818 const QStringView remainingStr = QStringView{s}.left(remaining);
3819 m_text.insert(m_cursor, remainingStr);
3820 for (auto e : remainingStr)
3821 addCommand(Command(Insert, m_cursor++, e, -1, -1));
3822 m_textDirty = true;
3823 }
3824 }
3825}
3826
3838void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3839{
3840 if (m_cursor < m_text.size()) {
3842 Q_ASSERT(!hasSelectedText()); // del(), backspace() call removeSelectedText() first.
3843 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3844 m_cursor, m_text.at(m_cursor), -1, -1));
3845 if (m_maskData) {
3846 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3847 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3848 } else {
3850 }
3851 m_textDirty = true;
3852 }
3853}
3854
3864void QQuickTextInputPrivate::removeSelectedText()
3865{
3866 if (m_selstart < m_selend && m_selend <= m_text.size()) {
3868 int i ;
3869 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3870 // cursor is within the selection. Split up the commands
3871 // to be able to restore the correct cursor position
3872 for (i = m_cursor; i >= m_selstart; --i)
3873 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3874 for (i = m_selend - 1; i > m_cursor; --i)
3875 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3876 } else {
3877 for (i = m_selend-1; i >= m_selstart; --i)
3878 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3879 }
3880 if (m_maskData) {
3882 for (int i = 0; i < m_selend - m_selstart; ++i)
3883 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3884 } else {
3886 }
3887 if (m_cursor > m_selstart)
3889 internalDeselect();
3890 m_textDirty = true;
3891 }
3892}
3893
3902bool QQuickTextInputPrivate::separateSelection()
3903{
3904 if (hasSelectedText()) {
3905 separate();
3906 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
3907 return true;
3908 } else {
3909 return false;
3910 }
3911}
3912
3919void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
3920{
3921 int delimiter = maskFields.indexOf(QLatin1Char(';'));
3922 if (maskFields.isEmpty() || delimiter == 0) {
3923 if (m_maskData) {
3924 m_maskData.reset(nullptr);
3925 m_maxLength = 32767;
3926 internalSetText(QString());
3927 }
3928 return;
3929 }
3930
3931 if (delimiter == -1) {
3932 m_blank = QLatin1Char(' ');
3933 m_inputMask = maskFields;
3934 } else {
3935 m_inputMask = maskFields.left(delimiter);
3936 m_blank = (delimiter + 1 < maskFields.size()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
3937 }
3938
3939 // calculate m_maxLength / m_maskData length
3940 m_maxLength = 0;
3941 QChar c = u'\0';
3942 for (int i=0; i<m_inputMask.size(); i++) {
3943 c = m_inputMask.at(i);
3944 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
3945 m_maxLength++;
3946 continue;
3947 }
3948 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
3949 c != QLatin1Char('<') && c != QLatin1Char('>') &&
3950 c != QLatin1Char('{') && c != QLatin1Char('}') &&
3951 c != QLatin1Char('[') && c != QLatin1Char(']'))
3952 m_maxLength++;
3953 }
3954
3955 m_maskData.reset(new MaskInputData[m_maxLength]);
3956
3958 c = u'\0';
3959 bool s;
3960 bool escape = false;
3961 int index = 0;
3962 for (int i = 0; i < m_inputMask.size(); i++) {
3963 c = m_inputMask.at(i);
3964 if (escape) {
3965 s = true;
3966 m_maskData[index].maskChar = c;
3967 m_maskData[index].separator = s;
3968 m_maskData[index].caseMode = m;
3969 index++;
3970 escape = false;
3971 } else if (c == QLatin1Char('<')) {
3973 } else if (c == QLatin1Char('>')) {
3975 } else if (c == QLatin1Char('!')) {
3977 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
3978 switch (c.unicode()) {
3979 case 'A':
3980 case 'a':
3981 case 'N':
3982 case 'n':
3983 case 'X':
3984 case 'x':
3985 case '9':
3986 case '0':
3987 case 'D':
3988 case 'd':
3989 case '#':
3990 case 'H':
3991 case 'h':
3992 case 'B':
3993 case 'b':
3994 s = false;
3995 break;
3996 case '\\':
3997 escape = true;
3998 Q_FALLTHROUGH();
3999 default:
4000 s = true;
4001 break;
4002 }
4003
4004 if (!escape) {
4005 m_maskData[index].maskChar = c;
4006 m_maskData[index].separator = s;
4007 m_maskData[index].caseMode = m;
4008 index++;
4009 }
4010 }
4011 }
4012 internalSetText(m_text);
4013}
4014
4015
4021bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
4022{
4023 switch (mask.unicode()) {
4024 case 'A':
4025 if (key.isLetter())
4026 return true;
4027 break;
4028 case 'a':
4029 if (key.isLetter() || key == m_blank)
4030 return true;
4031 break;
4032 case 'N':
4033 if (key.isLetterOrNumber())
4034 return true;
4035 break;
4036 case 'n':
4037 if (key.isLetterOrNumber() || key == m_blank)
4038 return true;
4039 break;
4040 case 'X':
4041 if (key.isPrint() && key != m_blank)
4042 return true;
4043 break;
4044 case 'x':
4045 if (key.isPrint() || key == m_blank)
4046 return true;
4047 break;
4048 case '9':
4049 if (key.isNumber())
4050 return true;
4051 break;
4052 case '0':
4053 if (key.isNumber() || key == m_blank)
4054 return true;
4055 break;
4056 case 'D':
4057 if (key.isNumber() && key.digitValue() > 0)
4058 return true;
4059 break;
4060 case 'd':
4061 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
4062 return true;
4063 break;
4064 case '#':
4065 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
4066 return true;
4067 break;
4068 case 'B':
4069 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
4070 return true;
4071 break;
4072 case 'b':
4073 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
4074 return true;
4075 break;
4076 case 'H':
4077 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
4078 return true;
4079 break;
4080 case 'h':
4081 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
4082 return true;
4083 break;
4084 default:
4085 break;
4086 }
4087 return false;
4088}
4089
4098QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
4099{
4100#if QT_CONFIG(validator)
4101 QString textCopy = str;
4102 int cursorCopy = m_cursor;
4103 if (m_validator) {
4104 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
4106 return ValidatorState(state);
4107 }
4108#endif
4109
4110 if (!m_maskData)
4111 return AcceptableInput;
4112
4113 if (str.size() != m_maxLength)
4114 return InvalidInput;
4115
4116 for (int i=0; i < m_maxLength; ++i) {
4117 if (m_maskData[i].separator) {
4118 if (str.at(i) != m_maskData[i].maskChar)
4119 return InvalidInput;
4120 } else {
4121 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
4122 return InvalidInput;
4123 }
4124 }
4125 return AcceptableInput;
4126}
4127
4136QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
4137{
4138 if (pos >= (uint)m_maxLength)
4139 return QString::fromLatin1("");
4140
4141 QString fill;
4142 fill = clear ? clearString(0, m_maxLength) : m_text;
4143
4144 int strIndex = 0;
4146 int i = pos;
4147 while (i < m_maxLength) {
4148 if (strIndex < str.size()) {
4149 if (m_maskData[i].separator) {
4150 s += m_maskData[i].maskChar;
4151 if (str[strIndex] == m_maskData[i].maskChar)
4152 strIndex++;
4153 ++i;
4154 } else {
4155 if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
4156 switch (m_maskData[i].caseMode) {
4158 s += str[strIndex].toUpper();
4159 break;
4161 s += str[strIndex].toLower();
4162 break;
4163 default:
4164 s += str[strIndex];
4165 }
4166 ++i;
4167 } else {
4168 // search for separator first
4169 int n = findInMask(i, true, true, str[strIndex]);
4170 if (n != -1) {
4171 if (str.size() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
4172 s += QStringView{fill}.mid(i, n-i+1);
4173 i = n + 1; // update i to find + 1
4174 }
4175 } else {
4176 // search for valid m_blank if not
4177 n = findInMask(i, true, false, str[strIndex]);
4178 if (n != -1) {
4179 s += QStringView{fill}.mid(i, n-i);
4180 switch (m_maskData[n].caseMode) {
4182 s += str[strIndex].toUpper();
4183 break;
4185 s += str[strIndex].toLower();
4186 break;
4187 default:
4188 s += str[strIndex];
4189 }
4190 i = n + 1; // updates i to find + 1
4191 }
4192 }
4193 }
4194 ++strIndex;
4195 }
4196 } else
4197 break;
4198 }
4199
4200 return s;
4201}
4202
4203
4204
4211QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
4212{
4213 if (pos >= (uint)m_maxLength)
4214 return QString();
4215
4216 QString s;
4217 int end = qMin((uint)m_maxLength, pos + len);
4218 for (int i = pos; i < end; ++i)
4219 if (m_maskData[i].separator)
4220 s += m_maskData[i].maskChar;
4221 else
4222 s += m_blank;
4223
4224 return s;
4225}
4226
4233QString QQuickTextInputPrivate::stripString(const QString &str) const
4234{
4235 if (!m_maskData)
4236 return str;
4237
4238 QString s;
4239 int end = qMin(m_maxLength, str.size());
4240 for (int i = 0; i < end; ++i) {
4241 if (m_maskData[i].separator)
4242 s += m_maskData[i].maskChar;
4243 else if (str[i] != m_blank)
4244 s += str[i];
4245 }
4246
4247 return s;
4248}
4249
4254int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
4255{
4256 if (pos >= m_maxLength || pos < 0)
4257 return -1;
4258
4259 int end = forward ? m_maxLength : -1;
4260 int step = forward ? 1 : -1;
4261 int i = pos;
4262
4263 while (i != end) {
4264 if (findSeparator) {
4265 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
4266 return i;
4267 } else {
4268 if (!m_maskData[i].separator) {
4269 if (searchChar.isNull())
4270 return i;
4271 else if (isValidInput(searchChar, m_maskData[i].maskChar))
4272 return i;
4273 }
4274 }
4275 i += step;
4276 }
4277 return -1;
4278}
4279
4280void QQuickTextInputPrivate::internalUndo(int until)
4281{
4282 if (!isUndoAvailable())
4283 return;
4285 internalDeselect();
4286 while (m_undoState && m_undoState > until) {
4287 Command& cmd = m_history[--m_undoState];
4288 switch (cmd.type) {
4289 case Insert:
4290 m_text.remove(cmd.pos, 1);
4291 m_cursor = cmd.pos;
4292 break;
4293 case SetSelection:
4294 m_selstart = cmd.selStart;
4295 m_selend = cmd.selEnd;
4296 m_cursor = cmd.pos;
4297 break;
4298 case Remove:
4299 case RemoveSelection:
4300 m_text.insert(cmd.pos, cmd.uc);
4301 m_cursor = cmd.pos + 1;
4302 break;
4303 case Delete:
4304 case DeleteSelection:
4305 m_text.insert(cmd.pos, cmd.uc);
4306 m_cursor = cmd.pos;
4307 break;
4308 case Separator:
4309 continue;
4310 }
4311 if (until < 0 && m_undoState) {
4312 Command& next = m_history[m_undoState-1];
4313 if (next.type != cmd.type
4314 && next.type < RemoveSelection
4315 && (cmd.type < RemoveSelection || next.type == Separator)) {
4316 break;
4317 }
4318 }
4319 }
4320 separate();
4321 m_textDirty = true;
4322}
4323
4324void QQuickTextInputPrivate::internalRedo()
4325{
4326 if (!isRedoAvailable())
4327 return;
4328 internalDeselect();
4329 while (m_undoState < m_history.size()) {
4330 Command& cmd = m_history[m_undoState++];
4331 switch (cmd.type) {
4332 case Insert:
4333 m_text.insert(cmd.pos, cmd.uc);
4334 m_cursor = cmd.pos + 1;
4335 break;
4336 case SetSelection:
4337 m_selstart = cmd.selStart;
4338 m_selend = cmd.selEnd;
4339 m_cursor = cmd.pos;
4340 break;
4341 case Remove:
4342 case Delete:
4343 case RemoveSelection:
4344 case DeleteSelection:
4345 m_text.remove(cmd.pos, 1);
4346 m_selstart = cmd.selStart;
4347 m_selend = cmd.selEnd;
4348 m_cursor = cmd.pos;
4349 break;
4350 case Separator:
4351 m_selstart = cmd.selStart;
4352 m_selend = cmd.selEnd;
4353 m_cursor = cmd.pos;
4354 break;
4355 }
4356 if (m_undoState < m_history.size()) {
4357 Command& next = m_history[m_undoState];
4358 if (next.type != cmd.type
4359 && cmd.type < RemoveSelection
4360 && next.type != Separator
4361 && (next.type < RemoveSelection || cmd.type == Separator)) {
4362 break;
4363 }
4364 }
4365 }
4366 m_textDirty = true;
4367}
4368
4369void QQuickTextInputPrivate::emitUndoRedoChanged()
4370{
4371 Q_Q(QQuickTextInput);
4372 const bool previousUndo = canUndo;
4373 const bool previousRedo = canRedo;
4374
4377
4378 if (previousUndo != canUndo)
4379 emit q->canUndoChanged();
4380 if (previousRedo != canRedo)
4381 emit q->canRedoChanged();
4382}
4383
4390bool QQuickTextInputPrivate::emitCursorPositionChanged()
4391{
4392 Q_Q(QQuickTextInput);
4393 if (m_cursor != m_lastCursorPos) {
4395
4396 q->updateCursorRectangle();
4397 emit q->cursorPositionChanged();
4398
4399 if (!hasSelectedText()) {
4402 emit q->selectionStartChanged();
4403 }
4404 if (lastSelectionEnd != m_cursor) {
4406 emit q->selectionEndChanged();
4407 }
4408 }
4409
4410#if QT_CONFIG(accessibility)
4411 if (QAccessible::isActive()) {
4412 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
4413 QAccessibleTextCursorEvent ev(acc, m_cursor);
4414 QAccessible::updateAccessibility(&ev);
4415 }
4416 }
4417#endif
4418
4419 return true;
4420 }
4421 return false;
4422}
4423
4424
4426{
4427 if (enable == m_blinkEnabled)
4428 return;
4429
4432
4433 if (enable)
4435 else
4437}
4438
4440{
4441 Q_Q(QQuickTextInput);
4442
4443 if (m_blinkTimer) {
4444 q->killTimer(m_blinkTimer);
4445 m_blinkTimer = 0;
4446 }
4447
4449 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
4450 if (flashTime >= 2)
4451 m_blinkTimer = q->startTimer(flashTime / 2);
4452 }
4453
4454 m_blinkStatus = 1;
4456 q->polish();
4457 q->update();
4458}
4459
4461{
4462 Q_D(QQuickTextInput);
4463 if (event->timerId() == d->m_blinkTimer) {
4464 d->m_blinkStatus = !d->m_blinkStatus;
4466 polish();
4467 update();
4468 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4469 d->m_passwordEchoTimer.stop();
4470 d->updateDisplayText();
4471 updateCursorRectangle();
4472 }
4473}
4474
4476{
4477 Q_Q(QQuickTextInput);
4478
4479 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4480 if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
4481
4483 inputMethod->commit();
4484
4485 if (activeFocus) {
4486 // If we lost focus after hiding the virtual keyboard, we've already emitted
4487 // editingFinished from handleFocusEvent. Otherwise we emit it now.
4488 emit q->editingFinished();
4489 }
4490
4491 emit q->accepted();
4492 }
4493 event->ignore();
4494 return;
4495 }
4496
4497 if (m_blinkEnabled)
4499
4502 && !m_readOnly
4503 && !event->text().isEmpty()
4504 && !(event->modifiers() & Qt::ControlModifier)) {
4505 // Clear the edit and reset to normal echo mode while editing; the
4506 // echo mode switches back when the edit loses focus
4507 // ### resets current content. dubious code; you can
4508 // navigate with keys up, down, back, and select(?), but if you press
4509 // "left" or "right" it clears?
4511 clear();
4512 }
4513
4514 bool unknown = false;
4515#if QT_CONFIG(shortcut)
4516 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4517#endif
4518
4519 if (false) {
4520 }
4521#if QT_CONFIG(shortcut)
4522 else if (event == QKeySequence::Undo) {
4523 q->undo();
4524 }
4525 else if (event == QKeySequence::Redo) {
4526 q->redo();
4527 }
4528 else if (event == QKeySequence::SelectAll) {
4529 selectAll();
4530 }
4531#if QT_CONFIG(clipboard)
4532 else if (event == QKeySequence::Copy) {
4533 copy();
4534 }
4535 else if (event == QKeySequence::Paste) {
4536 if (!m_readOnly) {
4538 paste(mode);
4539 }
4540 }
4541 else if (event == QKeySequence::Cut) {
4542 q->cut();
4543 }
4545 if (!m_readOnly)
4546 deleteEndOfLine();
4547 }
4548#endif // clipboard
4550 home(0);
4551 }
4553 end(0);
4554 }
4556 home(1);
4557 }
4559 end(1);
4560 }
4561 else if (event == QKeySequence::MoveToNextChar) {
4562 if (hasSelectedText()) {
4563 moveCursor(selectionEnd(), false);
4564 } else {
4565 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4566 }
4567 }
4568 else if (event == QKeySequence::SelectNextChar) {
4569 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4570 }
4572 if (hasSelectedText()) {
4573 moveCursor(selectionStart(), false);
4574 } else {
4575 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4576 }
4577 }
4579 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4580 }
4581 else if (event == QKeySequence::MoveToNextWord) {
4584 else
4585 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4586 }
4590 else if (!m_readOnly) {
4591 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4592 }
4593 }
4594 else if (event == QKeySequence::SelectNextWord) {
4597 else
4598 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4599 }
4603 else
4604 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4605 }
4606 else if (event == QKeySequence::Delete) {
4607 if (!m_readOnly)
4608 del();
4609 }
4611 if (!m_readOnly)
4612 deleteEndOfWord();
4613 }
4615 if (!m_readOnly)
4616 deleteStartOfWord();
4618 if (!m_readOnly) {
4619 selectAll();
4620#if QT_CONFIG(clipboard)
4621 copy();
4622#endif
4623 del();
4624 }
4625 }
4626#endif // shortcut
4627 else {
4628 bool handled = false;
4629 if (event->modifiers() & Qt::ControlModifier) {
4630 switch (event->key()) {
4631 case Qt::Key_Backspace:
4632 if (!m_readOnly)
4633 deleteStartOfWord();
4634 break;
4635 default:
4636 if (!handled)
4637 unknown = true;
4638 }
4639 } else { // ### check for *no* modifier
4640 switch (event->key()) {
4641 case Qt::Key_Backspace:
4642 if (!m_readOnly) {
4643 backspace();
4644 }
4645 break;
4646 default:
4647 if (!handled)
4648 unknown = true;
4649 }
4650 }
4651 }
4652
4653 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4655 unknown = false;
4656 }
4657
4658 if (unknown && !m_readOnly) {
4660 if (overwriteMode
4661 // no need to call del() if we have a selection, insert
4662 // does it already
4663 && !hasSelectedText()
4664 && !(m_cursor == q_func()->text().size())) {
4665 del();
4666 }
4667
4668 insert(event->text());
4669 event->accept();
4670 return;
4671 }
4672 }
4673
4674 if (unknown)
4675 event->ignore();
4676 else
4677 event->accept();
4678}
4679
4686void QQuickTextInputPrivate::deleteStartOfWord()
4687{
4688 int priorState = m_undoState;
4689 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4690 separate();
4691 cursorWordBackward(true);
4692 addCommand(cmd);
4693 removeSelectedText();
4694 finishChange(priorState);
4695}
4696
4703void QQuickTextInputPrivate::deleteEndOfWord()
4704{
4705 int priorState = m_undoState;
4706 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4707 separate();
4708 cursorWordForward(true);
4709 // moveCursor (sometimes) calls separate() so we need to add the command after that so the
4710 // cursor position and selection are restored in the same undo operation as the remove.
4711 addCommand(cmd);
4712 removeSelectedText();
4713 finishChange(priorState);
4714}
4715
4722void QQuickTextInputPrivate::deleteEndOfLine()
4723{
4724 int priorState = m_undoState;
4725 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4726 separate();
4728 addCommand(cmd);
4729 removeSelectedText();
4730 finishChange(priorState);
4731}
4732
4742void QQuickTextInput::ensureVisible(int position)
4743{
4744 Q_D(QQuickTextInput);
4745 d->ensureVisible(position);
4746 updateCursorRectangle(false);
4747}
4748
4760void QQuickTextInput::clear()
4761{
4762 Q_D(QQuickTextInput);
4763 d->cancelInput();
4764 d->clear();
4765}
4766
4791{
4792 Q_D(const QQuickTextInput);
4793 return d->padding();
4794}
4795
4797{
4798 Q_D(QQuickTextInput);
4799 if (qFuzzyCompare(d->padding(), padding))
4800 return;
4801
4802 d->extra.value().padding = padding;
4803 d->updateLayout();
4804 updateCursorRectangle();
4805 emit paddingChanged();
4806 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
4807 emit topPaddingChanged();
4808 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
4809 emit leftPaddingChanged();
4810 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
4811 emit rightPaddingChanged();
4812 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
4813 emit bottomPaddingChanged();
4814}
4815
4817{
4818 setPadding(0);
4819}
4820
4822{
4823 Q_D(const QQuickTextInput);
4824 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
4825 return d->extra->topPadding;
4826 return d->padding();
4827}
4828
4830{
4831 Q_D(QQuickTextInput);
4832 d->setTopPadding(padding);
4833}
4834
4836{
4837 Q_D(QQuickTextInput);
4838 d->setTopPadding(0, true);
4839}
4840
4842{
4843 Q_D(const QQuickTextInput);
4844 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
4845 return d->extra->leftPadding;
4846 return d->padding();
4847}
4848
4850{
4851 Q_D(QQuickTextInput);
4852 d->setLeftPadding(padding);
4853}
4854
4856{
4857 Q_D(QQuickTextInput);
4858 d->setLeftPadding(0, true);
4859}
4860
4862{
4863 Q_D(const QQuickTextInput);
4864 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
4865 return d->extra->rightPadding;
4866 return d->padding();
4867}
4868
4870{
4871 Q_D(QQuickTextInput);
4872 d->setRightPadding(padding);
4873}
4874
4876{
4877 Q_D(QQuickTextInput);
4878 d->setRightPadding(0, true);
4879}
4880
4882{
4883 Q_D(const QQuickTextInput);
4884 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
4885 return d->extra->bottomPadding;
4886 return d->padding();
4887}
4888
4890{
4891 Q_D(QQuickTextInput);
4892 d->setBottomPadding(padding);
4893}
4894
4896{
4897 Q_D(QQuickTextInput);
4898 d->setBottomPadding(0, true);
4899}
4900
4901#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
4902void QQuickTextInput::setOldSelectionDefault()
4903{
4904 Q_D(QQuickTextInput);
4905 d->selectByMouse = false;
4906 d->selectByTouchDrag = true;
4907 qCDebug(lcQuickTextInput, "pre-6.4 behavior chosen: selectByMouse defaults false; if enabled, touchscreen acts like a mouse");
4908}
4909
4910// TODO in 6.7.0: remove the note about versions prior to 6.4 in selectByMouse() documentation
4911QQuickPre64TextInput::QQuickPre64TextInput(QQuickItem *parent)
4913{
4914 setOldSelectionDefault();
4915}
4916#endif
4917
4919
4920#include "moc_qquicktextinput_p.cpp"
void start(int msec, QObject *obj)
\obsolete Use chrono overload instead.
bool isActive() const noexcept
Returns true if the timer is running and has not been stopped; otherwise returns false.
Definition qbasictimer.h:34
\inmodule QtCore
Definition qchar.h:48
@ ObjectReplacementCharacter
Definition qchar.h:60
@ ParagraphSeparator
Definition qchar.h:63
@ LineSeparator
Definition qchar.h:64
Direction direction() const noexcept
Returns the character's direction.
Definition qchar.h:437
@ DirL
Definition qchar.h:346
@ DirAN
Definition qchar.h:346
@ DirAL
Definition qchar.h:347
@ DirR
Definition qchar.h:346
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
Definition qchar.h:458
constexpr bool isNull() const noexcept
Returns true if the character is the Unicode character 0x0000 ('\0'); otherwise returns false.
Definition qchar.h:463
The QClipboard class provides access to the window system clipboard.
Definition qclipboard.h:20
void setText(const QString &, Mode mode=Clipboard)
Copies text into the clipboard as plain text.
QString text(Mode mode=Clipboard) const
Returns the clipboard text as plain text, or an empty string if the clipboard does not contain any te...
Mode
\keyword clipboard mode
Definition qclipboard.h:27
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
\inmodule QtCore
Definition qcoreevent.h:45
@ ShortcutOverride
Definition qcoreevent.h:158
@ MouseButtonRelease
Definition qcoreevent.h:61
Type type() const
Returns the event type.
Definition qcoreevent.h:299
void ignore()
Clears the accept flag parameter of the event object, the equivalent of calling setAccepted(false).
Definition qcoreevent.h:306
bool isAccepted() const
Definition qcoreevent.h:303
void accept()
Sets the accept flag of the event object, the equivalent of calling setAccepted(true).
Definition qcoreevent.h:305
The QFocusEvent class contains event parameters for widget focus events.
Definition qevent.h:469
\reentrant \inmodule QtGui
qreal ascent() const
Returns the ascent of the font.
\reentrant \inmodule QtGui
int horizontalAdvance(const QString &, int len=-1) const
Returns the horizontal advance in pixels of the first len characters of text.
\reentrant
Definition qfont.h:20
static QClipboard * clipboard()
Returns the object for interacting with the clipboard.
static QStyleHints * styleHints()
Returns the application's style hints.
static QInputMethod * inputMethod()
returns the input method.
bool isAcceptableInput(const QKeyEvent *event) const
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:624
The QInputMethod class provides access to the active text input method.
Qt::LayoutDirection inputDirection
Current input direction.
void commit()
Commits the word user is currently composing to the editor.
void invokeAction(Action a, int cursorPosition)
Called by the input item when the word currently being composed is tapped by the user,...
void reset()
Resets the input method state.
The QKeyEvent class describes a key event.
Definition qevent.h:423
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately after the event occurred.
Definition qevent.cpp:1465
int key() const
Returns the code of the key that was pressed or released.
Definition qevent.h:433
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
qsizetype length() const noexcept
Definition qlist.h:388
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
\inmodule QtCore
Definition qmimedata.h:16
bool hasText() const
Returns true if the object can return plain text (MIME type text/plain); otherwise returns false.
\inmodule QtGui
Definition qevent.h:195
QObject * parent
Definition qobject.h:61
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:298
\inmodule QtCore
Definition qobject.h:90
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1363
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal manhattanLength() const
Definition qpoint.h:323
bool isNull() const noexcept
Returns true if both the x and y coordinates are set to 0.0 (ignoring the sign); otherwise returns fa...
Definition qpoint.h:328
\inmodule QtCore\reentrant
Definition qpoint.h:23
The QQmlComponent class encapsulates a QML component definition.
virtual void componentComplete()=0
Invoked after the root component that caused this instantiation has completed construction.
static bool isEventFromMouseOrTouchpad(const QPointerEvent *ev)
QString state() const
QQuickAnchorLine top() const
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:64
virtual void focusOutEvent(QFocusEvent *)
This event handler can be reimplemented in a subclass to receive focus-out events for an item.
virtual void mouseReleaseEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse release events for an item.
Flags flags() const
Returns the item flags for this item.
virtual void mouseDoubleClickEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse double-click events for an ite...
void setFlag(Flag flag, bool enabled=true)
Enables the specified flag for this item if enabled is true; if enabled is false, the flag is disable...
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
virtual void keyPressEvent(QKeyEvent *event)
This event handler can be reimplemented in a subclass to receive key press events for an item.
qreal x
\qmlproperty real QtQuick::Item::x \qmlproperty real QtQuick::Item::y \qmlproperty real QtQuick::Item...
Definition qquickitem.h:73
qreal y
Defines the item's y position relative to its parent.
Definition qquickitem.h:74
bool hasActiveFocus() const
QSizeF size() const
bool isComponentComplete() const
Returns true if construction of the QML component is complete; otherwise returns false.
QPointF position() const
void setKeepMouseGrab(bool)
Sets whether the mouse input should remain exclusively with this item.
Q_INVOKABLE void forceActiveFocus()
\qmlmethod point QtQuick::Item::mapToItem(Item item, real x, real y) \qmlmethod point QtQuick::Item::...
virtual QRectF clipRect() const
Returns the rectangular area within this item that is currently visible in \l viewportItem(),...
virtual void focusInEvent(QFocusEvent *)
This event handler can be reimplemented in a subclass to receive focus-in events for an item.
void update()
Schedules a call to updatePaintNode() for this item.
void polish()
Schedules a polish event for this item.
virtual void mouseMoveEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse move events for an item.
void updatePasswordEchoEditing(bool editing)
qreal getImplicitWidth() const override
void setLeftPadding(qreal value, bool reset=false)
void setSelection(int start, int length)
void setImplicitResizeEnabled(bool enabled)
qreal calculateImplicitWidthForText(const QString &text) const
QQuickTextInput::WrapMode wrapMode
Qt::LayoutDirection layoutDirection() const
void cursorWordBackward(bool mark)
Qt::LayoutDirection textDirection() const
void setLayoutDirection(Qt::LayoutDirection direction)
void setRightPadding(qreal value, bool reset=false)
Qt::CursorMoveStyle cursorMoveStyle() const
QQuickTextInput::VAlignment vAlign
void moveCursor(int pos, bool mark=false)
void setTopPadding(qreal value, bool reset=false)
std::unique_ptr< MaskInputData[]> m_maskData
QLazilyAllocated< ExtraData > extra
QQuickTextInput::HAlignment hAlign
void updateBaselineOffset()
QQuickTextInputPrivate::updateBaselineOffset.
QVector< Command > m_history
void cursorForward(bool mark, int steps)
bool sendMouseEventToInputContext(QMouseEvent *event)
void setBottomPadding(qreal value, bool reset=false)
Qt::LayoutDirection m_layoutDirection
void setBlinkingCursorEnabled(bool enable)
void processKeyEvent(QKeyEvent *ev)
void ensureVisible(int position, int preeditCursor=0, int preeditLength=0)
QQuickTextInput::RenderType renderType
bool setHAlign(QQuickTextInput::HAlignment, bool forceAlign=false)
int positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const
void insert(const QString &)
void cursorWordForward(bool mark)
QQuickTextInput::EchoMode m_echoMode
void handleFocusEvent(QFocusEvent *event)
QSGNode * updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) override
Called on the render thread when it is time to sync the state of the item with the scene graph.
QRectF boundingRect() const override
Returns the extents of the item in its own coordinate system: a rectangle from {0,...
bool event(QEvent *e) override
\reimp
void inputMethodComposingChanged()
void renderTypeChanged()
void passwordCharacterChanged()
void redo()
\qmlmethod QtQuick::TextInput::redo()
void setMaxLength(int ml)
void undo()
\qmlmethod QtQuick::TextInput::undo()
VAlignment vAlign() const
void keyPressEvent(QKeyEvent *ev) override
This event handler can be reimplemented in a subclass to receive key press events for an item.
void selectAll()
\qmlmethod QtQuick::TextInput::selectAll()
void setBottomPadding(qreal padding)
QString preeditText
\qmlproperty string QtQuick::TextInput::preeditText \readonly
void activeFocusOnPressChanged(bool activeFocusOnPress)
void setRenderType(RenderType renderType)
void updatePolish() override
This function should perform any layout as required for this item.
void selectionColorChanged()
void setOverwriteMode(bool overwrite)
FINALQString displayText
Q_INVOKABLE void moveCursorSelection(int pos)
QRectF clipRect() const override
Returns the rectangular area within this item that is currently visible in \l viewportItem(),...
void setPasswordMaskDelay(int delay)
void mouseReleaseEvent(QMouseEvent *event) override
This event handler can be reimplemented in a subclass to receive mouse release events for an item.
void setRightPadding(qreal padding)
Qt::InputMethodHints inputMethodHints
FINALqreal bottomPadding
void setFocusOnPress(bool)
void setWrapMode(WrapMode w)
void fontChanged(const QFont &font)
Q_INVOKABLE void positionAt(QQmlV4Function *args) const
\qmlmethod int QtQuick::TextInput::positionAt(real x, real y, CursorPosition position)
FINALqreal rightPadding
void setPersistentSelection(bool persist)
QQuickTextInput(QQuickItem *parent=nullptr)
\qmltype TextInput \instantiates QQuickTextInput \inqmlmodule QtQuick\inherits Item
void setPasswordCharacter(const QString &str)
void focusOutEvent(QFocusEvent *event) override
This event handler can be reimplemented in a subclass to receive focus-out events for an item.
void setHAlign(HAlignment align)
void readOnlyChanged(bool isReadOnly)
void echoModeChanged(QQuickTextInput::EchoMode echoMode)
void setSelectByMouse(bool)
void setEchoMode(EchoMode echo)
bool focusOnPress() const
\qmlproperty bool QtQuick::TextInput::activeFocusOnPress
int maxLength() const
\qmlproperty int QtQuick::TextInput::maximumLength The maximum permitted length of the text in the Te...
void cursorVisibleChanged(bool isCursorVisible)
void verticalAlignmentChanged(QQuickTextInput::VAlignment alignment)
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
void inputMethodHintsChanged()
void mouseSelectionModeChanged(QQuickTextInput::SelectionMode mode)
void setText(const QString &)
void focusInEvent(QFocusEvent *event) override
This event handler can be reimplemented in a subclass to receive focus-in events for an item.
void overwriteModeChanged(bool overwriteMode)
void setVAlign(VAlignment align)
bool isReadOnly() const
\qmlproperty bool QtQuick::TextInput::readOnly
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
void setInputMask(const QString &im)
void setSelectedTextColor(const QColor &c)
void selectedTextColorChanged()
void setSelectionColor(const QColor &c)
Q_INVOKABLE QString getText(int start, int end) const
\qmlmethod string QtQuick::TextInput::getText(int start, int end)
bool hasAcceptableInput() const
\qmlproperty bool QtQuick::TextInput::acceptableInput \readonly
void mousePressEvent(QMouseEvent *event) override
This event handler can be reimplemented in a subclass to receive mouse press events for an item.
void setColor(const QColor &c)
void insert(int position, const QString &text)
\qmlmethod QtQuick::TextInput::insert(int position, string text)
void autoScrollChanged(bool autoScroll)
void setCursorPosition(int cp)
HAlignment effectiveHAlign() const
void mouseUngrabEvent() override
This event handler can be reimplemented in a subclass to be notified when a mouse ungrab event has oc...
void mouseDoubleClickEvent(QMouseEvent *event) override
This event handler can be reimplemented in a subclass to receive mouse double-click events for an ite...
void setPadding(qreal padding)
void selectByMouseChanged(bool selectByMouse)
void mouseMoveEvent(QMouseEvent *event) override
This event handler can be reimplemented in a subclass to receive mouse move events for an item.
void select(int start, int end)
\qmlmethod QtQuick::TextInput::select(int start, int end)
void wrapModeChanged()
void invalidate() override
bool isCursorVisible() const
\qmlproperty bool QtQuick::TextInput::cursorVisible Set to true when the TextInput shows a cursor.
HAlignment hAlign() const
\qmlproperty enumeration QtQuick::TextInput::effectiveHorizontalAlignment \readonly
bool isRightToLeft(int start, int end)
\qmlmethod QtQuick::TextInput::isRightToLeft(int start, int end)
void setLeftPadding(qreal padding)
void setMouseSelectionMode(SelectionMode mode)
void selectWord()
\qmlmethod QtQuick::TextInput::selectWord()
void inputMaskChanged(const QString &inputMask)
void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
void setCursorDelegate(QQmlComponent *)
void maximumLengthChanged(int maximumLength)
void remove(int start, int end)
\qmlmethod QtQuick::TextInput::remove(int start, int end)
SelectionMode mouseSelectionMode
void persistentSelectionChanged()
bool isInputMethodComposing() const
\qmlproperty bool QtQuick::TextInput::inputMethodComposing \readonly
void selectionEndChanged()
void setTopPadding(qreal padding)
Q_INVOKABLE QRectF positionToRectangle(int pos) const
\qmlmethod rect QtQuick::TextInput::positionToRectangle(int pos)
void setCursorVisible(bool on)
void selectionStartChanged()
void deselect()
\qmlmethod QtQuick::TextInput::deselect()
QQmlComponent * cursorDelegate
void setFont(const QFont &font)
void setInputMethodHints(Qt::InputMethodHints hints)
void setUseNativeRenderer(bool on)
void setCursor(const QRectF &rect, const QColor &color)
void addTextLayout(const QPointF &position, QTextLayout *textLayout, const QColor &color=QColor(), QQuickText::TextStyle style=QQuickText::Normal, const QColor &styleColor=QColor(), const QColor &anchorColor=QColor(), const QColor &selectionColor=QColor(), const QColor &selectedTextColor=QColor(), int selectionStart=-1, int selectionEnd=-1, int lineStart=0, int lineCount=-1)
static qreal alignedX(qreal textWidth, qreal itemWidth, int alignment)
static void createCursor(Private *d)
static qreal alignedY(qreal textHeight, qreal itemHeight, int alignment)
static void setCursorDelegate(Private *d, QQmlComponent *delegate)
\inmodule QtCore\reentrant
Definition qrect.h:483
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:497
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
void setMatrix(const QMatrix4x4 &matrix)
Sets this transform node's matrix to matrix.
Definition qsgnode.cpp:1160
\inmodule QtCore
Definition qsize.h:207
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:324
\inmodule QtCore
Definition qstringview.h:76
constexpr QStringView left(qsizetype n) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:279
QString & fill(QChar c, qsizetype size=-1)
Sets every character in the string to character ch.
Definition qstring.cpp:6198
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1101
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QString & insert(qsizetype i, QChar c)
Definition qstring.cpp:3110
QString toLower() const &
Definition qstring.h:368
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1095
QString & append(QChar c)
Definition qstring.cpp:3227
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
bool isRightToLeft() const
Returns true if the string is read right to left.
Definition qstring.cpp:9068
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3435
QString toUpper() const &
Definition qstring.h:372
int startDragDistance
the distance, in pixels, that the mouse must be moved with a button held down before a drag and drop ...
Definition qstylehints.h:39
void cursorFlashTimeChanged(int cursorFlashTime)
int cursorFlashTime
the text cursor's flash (blink) time in milliseconds.
Definition qstylehints.h:20
BoundaryReasons boundaryReasons() const
Returns the reasons for the boundary finder to have chosen the current position as a boundary.
void setPosition(qsizetype position)
Sets the current position of the QTextBoundaryFinder to position.
qsizetype toNextBoundary()
Moves the QTextBoundaryFinder to the next boundary position and returns that position.
qsizetype toPreviousBoundary()
Moves the QTextBoundaryFinder to the previous boundary position and returns that position.
qsizetype position() const
Returns the current position of the QTextBoundaryFinder.
QTextCharFormat toCharFormat() const
Returns this format as a character format.
\reentrant
Definition qtextlayout.h:70
const QTextOption & textOption() const
Returns the current text option used to control the layout process.
QTextLine lineForTextPosition(int pos) const
Returns the line that contains the cursor position specified by pos.
void setFont(const QFont &f)
Sets the layout's font to the given font.
QTextLine createLine()
Returns a new text line to be laid out if there is text to be inserted into the layout; otherwise ret...
void beginLayout()
Begins the layout process.
void setFormats(const QList< FormatRange > &overrides)
void setText(const QString &string)
Sets the layout's text to the given string.
QString text() const
Returns the layout's text.
int previousCursorPosition(int oldPos, CursorMode mode=SkipCharacters) const
Returns the first valid cursor position before oldPos that respects the given cursor mode.
int lineCount() const
Returns the number of lines in this text layout.
int preeditAreaPosition() const
Returns the position of the area in the text layout that will be processed before editing occurs.
QTextLine lineAt(int i) const
Returns the {i}-th line of text in this text layout.
int nextCursorPosition(int oldPos, CursorMode mode=SkipCharacters) const
Returns the next valid cursor position after oldPos that respects the given cursor mode.
void setTextOption(const QTextOption &option)
Sets the text option structure that controls the layout process to the given option.
void endLayout()
Ends the layout process.
QString preeditAreaText() const
Returns the text that is inserted in the layout before editing occurs.
void setPreeditArea(int position, const QString &text)
Sets the position and text of the area in the layout that is processed before editing occurs.
\reentrant
QRectF rect() const
Returns the line's bounding rectangle.
qreal height() const
Returns the line's height.
qreal cursorToX(int *cursorPos, Edge edge=Leading) const
Converts the cursor position cursorPos to the corresponding x position inside the line,...
qreal naturalTextWidth() const
Returns the width of the line that is occupied by text.
qreal y() const
Returns the line's y position.
CursorPosition
\value CursorBetweenCharacters \value CursorOnCharacter
@ CursorBetweenCharacters
bool isValid() const
Returns true if this text line is valid; otherwise returns false.
\reentrant
Definition qtextoption.h:18
void setTextDirection(Qt::LayoutDirection aDirection)
Sets the direction of the text layout defined by the option to the given direction.
Definition qtextoption.h:57
void setUseDesignMetrics(bool b)
If enable is true then the layout will use design metrics; otherwise it will use the metrics of the p...
Definition qtextoption.h:91
@ IncludeTrailingSpaces
Definition qtextoption.h:76
WrapMode
This enum describes how text is wrapped in a document.
Definition qtextoption.h:60
\inmodule QtCore
Definition qcoreevent.h:359
The QValidator class provides validation of input text.
Definition qvalidator.h:24
State
This enum type defines the states in which a validated string can exist.
Definition qvalidator.h:30
\inmodule QtCore
Definition qvariant.h:64
QString str
[2]
QString text
QCursor cursor
void textChanged(const QString &newText)
qSwap(pi, e)
double e
rect
[4]
uint alignment
direction
short next
Definition keywords.cpp:445
EGLint EGLint * formats
Combined button and popup list for selecting options.
InputMethodQuery
@ ImMaximumTextLength
@ ImTextBeforeCursor
@ ImAnchorRectangle
@ ImSurroundingText
@ ImCursorPosition
@ ImEnterKeyType
@ ImCurrentSelection
@ ImAbsolutePosition
@ ImReadOnly
@ ImFont
@ ImAnchorPosition
@ ImCursorRectangle
@ ImHints
@ ImEnabled
@ ImTextAfterCursor
@ AlignHorizontal_Mask
Definition qnamespace.h:150
@ AlignAbsolute
Definition qnamespace.h:149
@ LeftButton
Definition qnamespace.h:57
@ MiddleButton
Definition qnamespace.h:59
LayoutDirection
@ LeftToRight
@ LayoutDirectionAuto
@ RightToLeft
@ ImhNone
@ ImhNoPredictiveText
@ ImhSensitiveData
@ ImhHiddenText
@ ImhNoAutoUppercase
@ Key_Escape
Definition qnamespace.h:658
@ Key_Return
Definition qnamespace.h:662
@ Key_Right
Definition qnamespace.h:674
@ Key_Enter
Definition qnamespace.h:663
@ Key_Backspace
Definition qnamespace.h:661
@ Key_Direction_L
Definition qnamespace.h:726
@ Key_Left
Definition qnamespace.h:672
@ Key_Up
Definition qnamespace.h:673
@ Key_Down
Definition qnamespace.h:675
@ Key_Delete
Definition qnamespace.h:665
@ Key_Direction_R
Definition qnamespace.h:727
@ Key_Home
Definition qnamespace.h:670
@ Key_End
Definition qnamespace.h:671
@ ShiftModifier
@ ControlModifier
@ KeypadModifier
@ NoModifier
@ VisualMoveStyle
@ EnterKeyNext
@ EnterKeyDefault
FocusReason
@ PopupFocusReason
@ MouseFocusReason
@ ActiveWindowFocusReason
static jboolean copy(JNIEnv *, jobject)
static jboolean paste(JNIEnv *, jobject)
#define Q_FALLTHROUGH()
#define qApp
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:287
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
#define qGuiApp
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
int qCeil(T v)
Definition qmath.h:36
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum mode
const GLfloat * m
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLfloat GLfloat f
GLint GLsizei width
GLenum type
GLint GLint bottom
GLboolean enable
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLuint GLintptr offset
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLint y
struct _cl_event * event
GLboolean reset
GLuint res
const GLubyte * c
GLenum GLsizei len
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLdouble s
[6]
Definition qopenglext.h:235
GLuint GLenum option
#define qmlobject_disconnect(Sender, SenderType, Signal, Receiver, ReceiverType, Method)
Disconnect Signal of Sender from Method of Receiver.
#define qmlobject_connect(Sender, SenderType, Signal, Receiver, ReceiverType, Method)
Connect Signal of Sender to Method of Receiver.
#define DEFINE_BOOL_CONFIG_OPTION(name, var)
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
void forceUpdate(QQuickItem *item)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static const struct ImageFormatTab unknown[]
SSL_CTX int(*) void arg)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QT_CONFIG(feature)
#define emit
#define Q_UNUSED(x)
#define QT_VERSION_CHECK(major, minor, patch)
#define QT_VERSION
unsigned int uint
Definition qtypes.h:29
double qreal
Definition qtypes.h:92
static QString escape(const QString &input)
const char property[13]
Definition qwizard.cpp:101
QMimeData * mimeData
QVBoxLayout * layout
myObject disconnect()
[26]
ba fill(true)
Text files * txt
QAction * at
QDBusArgument argument
QJSValueList args
\inmodule QtCore \reentrant
Definition qchar.h:17
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent