Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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>
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
63
70
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
156{
157 Q_D(const QQuickTextInput);
158 return d->renderType;
159}
160
162{
163 Q_D(QQuickTextInput);
164 if (d->renderType == renderType)
165 return;
166
167 d->renderType = renderType;
169
171 d->updateLayout();
172}
173
187{
188 Q_D(const QQuickTextInput);
189 return d->m_text.size();
190}
191
201{
202 Q_D(const QQuickTextInput);
203
204 if (start > end)
205 qSwap(start, end);
206
207 return d->m_text.mid(start, end - start);
208}
209
211{
212 QString res = m_maskData ? stripString(m_text) : m_text;
213 return (res.isNull() ? QString::fromLatin1("") : res);
214}
215
414{
415 Q_D(const QQuickTextInput);
416 return d->sourceFont;
417}
418
420{
421 Q_D(QQuickTextInput);
422 if (d->sourceFont == font)
423 return;
424
425 d->sourceFont = font;
426 QFont oldFont = d->font;
427 d->font = font;
428 if (d->font.pointSizeF() != -1) {
429 // 0.5pt resolution
430 qreal size = qRound(d->font.pointSizeF()*2.0);
431 d->font.setPointSizeF(size/2.0);
432 }
433 if (oldFont != d->font) {
434 d->updateLayout();
435 updateCursorRectangle();
436#if QT_CONFIG(im)
438#endif
439 }
440 emit fontChanged(d->sourceFont);
441}
442
449{
450 Q_D(const QQuickTextInput);
451 return d->color;
452}
453
455{
456 Q_D(QQuickTextInput);
457 if (c != d->color) {
458 d->color = c;
459 d->textLayoutDirty = true;
461 polish();
462 update();
464 }
465}
466
467
474{
475 Q_D(const QQuickTextInput);
476 return d->selectionColor;
477}
478
480{
481 Q_D(QQuickTextInput);
482 if (d->selectionColor == color)
483 return;
484
485 d->selectionColor = color;
486 if (d->hasSelectedText()) {
487 d->textLayoutDirty = true;
489 polish();
490 update();
491 }
493}
500{
501 Q_D(const QQuickTextInput);
502 return d->selectedTextColor;
503}
504
506{
507 Q_D(QQuickTextInput);
508 if (d->selectedTextColor == color)
509 return;
510
511 d->selectedTextColor = color;
512 if (d->hasSelectedText()) {
513 d->textLayoutDirty = true;
515 polish();
516 update();
517 }
519}
520
557{
558 Q_D(const QQuickTextInput);
559 return d->hAlign;
560}
561
563{
564 Q_D(QQuickTextInput);
565
566 if (d->setHAlign(align, true) && isComponentComplete()) {
567 d->updateLayout();
568 updateCursorRectangle();
569 }
570}
571
573{
574 Q_D(QQuickTextInput);
575 d->hAlignImplicit = true;
576 if (d->determineHorizontalAlignment() && isComponentComplete()) {
577 d->updateLayout();
578 updateCursorRectangle();
579 }
580}
581
583{
584 Q_D(const QQuickTextInput);
585 QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
586 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
587 switch (d->hAlign) {
589 effectiveAlignment = QQuickTextInput::AlignRight;
590 break;
592 effectiveAlignment = QQuickTextInput::AlignLeft;
593 break;
594 default:
595 break;
596 }
597 }
598 return effectiveAlignment;
599}
600
602{
603 Q_Q(QQuickTextInput);
605 return false; // justify is not supported
606
607 if (hAlign == align && !forceAlign)
608 return false;
609
610 const bool wasImplicit = hAlignImplicit;
611 const auto oldEffectiveHAlign = q->effectiveHAlign();
612
613 hAlignImplicit = !forceAlign;
614 if (hAlign != align) {
615 hAlign = align;
616 emit q->horizontalAlignmentChanged(align);
617 }
618
619 if (q->effectiveHAlign() != oldEffectiveHAlign) {
620 emit q->effectiveHorizontalAlignmentChanged();
621 return true;
622 }
623
624 if (forceAlign && wasImplicit) {
625 // QTBUG-120052 - when horizontal text alignment is set explicitly,
626 // we need notify any other controls that may depend on it, like QQuickPlaceholderText
627 emit q->effectiveHorizontalAlignmentChanged();
628 }
629 return false;
630}
631
633{
635#if QT_CONFIG(im)
636 if (text.isEmpty())
638#endif
639
640 const QChar *character = text.constData();
641 while (!character->isNull()) {
642 switch (character->direction()) {
643 case QChar::DirL:
644 return Qt::LeftToRight;
645 case QChar::DirR:
646 case QChar::DirAL:
647 case QChar::DirAN:
648 return Qt::RightToLeft;
649 default:
650 break;
651 }
652 character++;
653 }
655}
656
669
671{
672 if (!hAlignImplicit)
673 return false;
674
675 // if no explicit alignment has been set, follow the natural layout direction of the text
677#if QT_CONFIG(im)
679 direction = QGuiApplication::inputMethod()->inputDirection();
680#endif
681
682 const auto implicitHAlign = direction == Qt::RightToLeft ?
684 return setHAlign(implicitHAlign);
685}
686
688{
689 Q_D(const QQuickTextInput);
690 return d->vAlign;
691}
692
694{
695 Q_D(QQuickTextInput);
696 if (alignment == d->vAlign)
697 return;
698 d->vAlign = alignment;
700 if (isComponentComplete()) {
701 updateCursorRectangle();
702 d->updateBaselineOffset();
703 }
704}
705
727{
728 Q_D(const QQuickTextInput);
729 return d->wrapMode;
730}
731
733{
734 Q_D(QQuickTextInput);
735 if (mode == d->wrapMode)
736 return;
737 d->wrapMode = mode;
738 d->updateLayout();
739 updateCursorRectangle();
741}
742
744{
745 Q_Q(QQuickTextInput);
746 if (q->isComponentComplete()) {
748 q->updateCursorRectangle();
749 emit q->effectiveHorizontalAlignmentChanged();
750 }
751 }
752}
753
764{
765 Q_D(const QQuickTextInput);
766 return d->m_readOnly;
767}
768
770{
771 Q_D(QQuickTextInput);
772 if (d->m_readOnly == ro)
773 return;
774
775#if QT_CONFIG(im)
776 setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
777#endif
778 d->m_readOnly = ro;
779 d->setCursorPosition(d->end());
780#if QT_CONFIG(im)
781 updateInputMethod(Qt::ImEnabled);
782#endif
783 q_canPasteChanged();
784 d->emitUndoRedoChanged();
786 if (ro) {
787 setCursorVisible(false);
788 } else if (hasActiveFocus()) {
789 setCursorVisible(true);
790 }
791 update();
792}
793
803{
804 Q_D(const QQuickTextInput);
805 return d->m_maxLength;
806}
807
809{
810 Q_D(QQuickTextInput);
811 if (d->m_maxLength == ml || d->m_maskData)
812 return;
813
814 d->m_maxLength = ml;
815 d->internalSetText(d->m_text, -1, false);
816
818}
819
847{
848 Q_D(const QQuickTextInput);
849 return d->cursorVisible;
850}
851
853{
854 Q_D(QQuickTextInput);
855 if (d->cursorVisible == on)
856 return;
857 d->cursorVisible = on;
858 if (on && isComponentComplete())
860 if (!d->cursorItem)
861 d->updateCursorBlinking();
862 emit cursorVisibleChanged(d->cursorVisible);
863}
864
882{
883 Q_D(const QQuickTextInput);
884 return d->m_cursor;
885}
886
888{
889 Q_D(QQuickTextInput);
890 if (cp < 0 || cp > text().size())
891 return;
892 d->moveCursor(cp);
893}
894
907{
908 Q_D(const QQuickTextInput);
909
910 int c = d->m_cursor;
911#if QT_CONFIG(im)
912 c += d->m_preeditCursor;
913#endif
914 if (d->m_echoMode == NoEcho)
915 c = 0;
916 QTextLine l = d->m_textLayout.lineForTextPosition(c);
917 if (!l.isValid())
918 return QRectF();
919 qreal x = l.cursorToX(c) - d->hscroll + leftPadding();
920 qreal y = l.y() - d->vscroll + topPadding();
921 qreal w = 1;
922 if (d->overwriteMode) {
923 if (c < text().size())
924 w = l.cursorToX(c + 1) - x;
925 else
926 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw()
927 }
928 return QRectF(x, y, w, l.height());
929}
930
943{
944 Q_D(const QQuickTextInput);
945 return d->lastSelectionStart;
946}
959{
960 Q_D(const QQuickTextInput);
961 return d->lastSelectionEnd;
962}
977{
978 Q_D(QQuickTextInput);
979 if (start < 0 || end < 0 || start > d->m_text.size() || end > d->m_text.size())
980 return;
981 d->setSelection(start, end-start);
982}
983
1000{
1001 Q_D(const QQuickTextInput);
1002 return d->selectedText();
1003}
1004
1012{
1013 Q_D(const QQuickTextInput);
1014 return d->focusOnPress;
1015}
1016
1018{
1019 Q_D(QQuickTextInput);
1020 if (d->focusOnPress == b)
1021 return;
1022
1023 d->focusOnPress = b;
1024
1025 emit activeFocusOnPressChanged(d->focusOnPress);
1026}
1036{
1037 Q_D(const QQuickTextInput);
1038 return d->autoScroll;
1039}
1040
1042{
1043 Q_D(QQuickTextInput);
1044 if (d->autoScroll == b)
1045 return;
1046
1047 d->autoScroll = b;
1048 //We need to repaint so that the scrolling is taking into account.
1049 updateCursorRectangle();
1050 emit autoScrollChanged(d->autoScroll);
1051}
1052
1053#if QT_CONFIG(validator)
1078QValidator* QQuickTextInput::validator() const
1079{
1080 Q_D(const QQuickTextInput);
1081 return d->m_validator;
1082}
1083
1084void QQuickTextInput::setValidator(QValidator* v)
1085{
1086 Q_D(QQuickTextInput);
1087 if (d->m_validator == v)
1088 return;
1089
1090 if (d->m_validator) {
1092 d->m_validator, QValidator, SIGNAL(changed()),
1093 this, QQuickTextInput, SLOT(q_validatorChanged()));
1094 }
1095
1096 d->m_validator = v;
1097
1098 if (d->m_validator) {
1100 d->m_validator, QValidator, SIGNAL(changed()),
1101 this, QQuickTextInput, SLOT(q_validatorChanged()));
1102 }
1103
1104 if (isComponentComplete())
1105 d->checkIsValid();
1106
1107 emit validatorChanged();
1108}
1109
1110void QQuickTextInput::q_validatorChanged()
1111{
1112 Q_D(QQuickTextInput);
1113 d->checkIsValid();
1114}
1115#endif // validator
1116
1118{
1119 Q_Q(const QQuickTextInput);
1120 QRectF rect;
1121 int a;
1122 // Unfortunately we cannot use selectionStart() and selectionEnd()
1123 // since they always assume that the selectionStart is logically before selectionEnd.
1124 // To rely on that would cause havoc if the user was interactively moving the end selection
1125 // handle to become before the start selection
1126 if (m_selstart == m_selend)
1127 // This is to handle the case when there is "no selection" while moving the handle onto the
1128 // same position as the other handle (in which case it would hide the selection handles)
1129 a = m_cursor;
1130 else
1132 if (a >= 0) {
1133#if QT_CONFIG(im)
1134 a += m_preeditCursor;
1135#endif
1137 a = 0;
1139 if (l.isValid()) {
1140 qreal x = l.cursorToX(a) - hscroll + q->leftPadding();
1141 qreal y = l.y() - vscroll + q->topPadding();
1142 rect.setRect(x, y, 1, l.height());
1143 }
1144 }
1145 return rect;
1146}
1147
1148void QQuickTextInputPrivate::checkIsValid()
1149{
1150 Q_Q(QQuickTextInput);
1151
1152 ValidatorState state = hasAcceptableInput(m_text);
1153 if (!m_maskData)
1154 m_validInput = state != InvalidInput;
1155 if (state != AcceptableInput) {
1156 if (m_acceptableInput) {
1157 m_acceptableInput = false;
1158 emit q->acceptableInputChanged();
1159 }
1160 } else if (!m_acceptableInput) {
1161 m_acceptableInput = true;
1162 emit q->acceptableInputChanged();
1163 }
1164}
1165
1176{
1177 Q_D(const QQuickTextInput);
1178 return d->inputMask();
1179}
1180
1182{
1183 Q_D(QQuickTextInput);
1184 QString canonicalInputMask = im;
1185 if (im.lastIndexOf(QLatin1Char(';')) == -1)
1186 canonicalInputMask.append(QLatin1String("; "));
1187 if (d->inputMask() == canonicalInputMask)
1188 return;
1189
1190 d->setInputMask(im);
1191 emit inputMaskChanged(d->inputMask());
1192}
1193
1204{
1205 Q_D(const QQuickTextInput);
1206 return d->m_acceptableInput;
1207}
1208
1238#if QT_CONFIG(im)
1239Qt::InputMethodHints QQuickTextInputPrivate::effectiveInputMethodHints() const
1240{
1241 Qt::InputMethodHints hints = inputMethodHints;
1243 hints |= Qt::ImhHiddenText;
1245 hints &= ~Qt::ImhHiddenText;
1248 return hints;
1249}
1250#endif
1251
1265{
1266 Q_D(const QQuickTextInput);
1267 return QQuickTextInput::EchoMode(d->m_echoMode);
1268}
1269
1271{
1272 Q_D(QQuickTextInput);
1273 if (echoMode() == echo)
1274 return;
1275 d->cancelPasswordEchoTimer();
1276 d->m_echoMode = echo;
1277 d->m_passwordEchoEditing = false;
1278#if QT_CONFIG(im)
1279 updateInputMethod(Qt::ImHints);
1280#endif
1281 d->updateDisplayText();
1282 updateCursorRectangle();
1283
1284 // If this control is used for password input, we want to minimize
1285 // the possibility of string reallocation not to leak (parts of)
1286 // the password.
1287 if (d->m_echoMode != QQuickTextInput::Normal)
1288 d->m_text.reserve(30);
1289
1291}
1292
1330Qt::InputMethodHints QQuickTextInput::inputMethodHints() const
1331{
1332#if !QT_CONFIG(im)
1333 return Qt::ImhNone;
1334#else
1335 Q_D(const QQuickTextInput);
1336 return d->inputMethodHints;
1337#endif // im
1338}
1339
1340void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints)
1341{
1342#if !QT_CONFIG(im)
1343 Q_UNUSED(hints);
1344#else
1345 Q_D(QQuickTextInput);
1346
1347 if (hints == d->inputMethodHints)
1348 return;
1349
1350 d->inputMethodHints = hints;
1351 updateInputMethod(Qt::ImHints);
1353#endif // im
1354}
1355
1370{
1371 Q_D(const QQuickTextInput);
1372 return d->cursorComponent;
1373}
1374
1380
1381void QQuickTextInput::createCursor()
1382{
1383 Q_D(QQuickTextInput);
1384 d->cursorPending = true;
1386}
1387
1398{
1399 Q_D(const QQuickTextInput);
1400 if (d->m_echoMode == NoEcho)
1401 pos = 0;
1402#if QT_CONFIG(im)
1403 else if (pos > d->m_cursor)
1404 pos += d->preeditAreaText().size();
1405#endif
1406 QTextLine l = d->m_textLayout.lineForTextPosition(pos);
1407 if (!l.isValid())
1408 return QRectF();
1409 qreal x = l.cursorToX(pos) - d->hscroll;
1410 qreal y = l.y() - d->vscroll;
1411 qreal w = 1;
1412 if (d->overwriteMode) {
1413 if (pos < text().size())
1414 w = l.cursorToX(pos + 1) - x;
1415 else
1416 w = QFontMetrics(font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw()
1417 }
1418 return QRectF(x, y, w, l.height());
1419}
1420
1445{
1446 Q_D(const QQuickTextInput);
1447
1448 qreal x = 0;
1449 qreal y = 0;
1451
1452 if (args->length() < 1)
1453 return;
1454
1455 int i = 0;
1456 QV4::Scope scope(args->v4engine());
1457 QV4::ScopedValue arg(scope, (*args)[0]);
1458 x = arg->toNumber();
1459
1460 if (++i < args->length()) {
1461 arg = (*args)[i];
1462 y = arg->toNumber();
1463 }
1464
1465 if (++i < args->length()) {
1466 arg = (*args)[i];
1468 }
1469
1470 int pos = d->positionAt(x, y, position);
1471 const int cursor = d->m_cursor;
1472 if (pos > cursor) {
1473#if QT_CONFIG(im)
1474 const int preeditLength = d->preeditAreaText().size();
1475 pos = pos > cursor + preeditLength
1476 ? pos - preeditLength
1477 : cursor;
1478#else
1479 pos = cursor;
1480#endif
1481 }
1482 args->setReturnValue(QV4::Encode(pos));
1483}
1484
1486{
1487 Q_Q(const QQuickTextInput);
1488 x += hscroll - q->leftPadding();
1489 y += vscroll - q->topPadding();
1491 for (int i = 1; i < m_textLayout.lineCount(); ++i) {
1492 QTextLine nextLine = m_textLayout.lineAt(i);
1493
1494 if (y < (line.rect().bottom() + nextLine.y()) / 2)
1495 break;
1496 line = nextLine;
1497 }
1498 return line.isValid() ? line.xToCursor(x, position) : 0;
1499}
1500
1517{
1518 Q_D(const QQuickTextInput);
1519 return d->overwriteMode;
1520}
1521
1523{
1524 Q_D(QQuickTextInput);
1525 if (d->overwriteMode == overwrite)
1526 return;
1527 d->overwriteMode = overwrite;
1528 emit overwriteModeChanged(overwrite);
1529}
1530
1532{
1533 Q_D(QQuickTextInput);
1534 // Don't allow MacOSX up/down support, and we don't allow a completer.
1535 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1536 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1537 // Ignore when moving off the end unless there is a selection,
1538 // because then moving will do something (deselect).
1539 int cursorPosition = d->m_cursor;
1540 if (cursorPosition == 0)
1541 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1542 if (!ignore && cursorPosition == d->m_text.size())
1543 ignore = ev->key() == (d->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1544 }
1545 if (ignore) {
1546 ev->ignore();
1547 } else {
1548 d->processKeyEvent(ev);
1549 }
1550 if (!ev->isAccepted())
1552}
1553
1554#if QT_CONFIG(im)
1555void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
1556{
1557 Q_D(QQuickTextInput);
1558 const bool wasComposing = d->hasImState;
1559 d->processInputMethodEvent(ev);
1560 if (!ev->isAccepted())
1561 QQuickImplicitSizeItem::inputMethodEvent(ev);
1562
1563 if (wasComposing != d->hasImState)
1565}
1566#endif
1567
1569{
1570 Q_D(QQuickTextInput);
1571
1572 if (d->selectByMouse && event->button() == Qt::LeftButton &&
1574#if QT_CONFIG(im)
1575 d->commitPreedit();
1576#endif
1577 int cursor = d->positionAt(event->position());
1578 d->selectWordAtPos(cursor);
1579 event->setAccepted(true);
1580 if (!d->hasPendingTripleClick()) {
1581 d->tripleClickStartPoint = event->position();
1582 d->tripleClickTimer.start();
1583 }
1584 } else {
1585 if (d->sendMouseEventToInputContext(event))
1586 return;
1588 }
1589}
1590
1592{
1593 Q_D(QQuickTextInput);
1594
1595 d->pressPos = event->position();
1596
1597 if (d->sendMouseEventToInputContext(event))
1598 return;
1599
1601 if (d->selectByMouse &&
1602 (isMouse
1603#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1604 || d->selectByTouchDrag
1605#endif
1606 )) {
1607 setKeepMouseGrab(false);
1608 d->selectPressed = true;
1609 QPointF distanceVector = d->pressPos - d->tripleClickStartPoint;
1610 if (d->hasPendingTripleClick()
1611 && distanceVector.manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) {
1612 event->setAccepted(true);
1613 selectAll();
1614 return;
1615 }
1616 }
1617
1618 if (isMouse
1619#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1620 || d->selectByTouchDrag
1621#endif
1622 ) {
1623 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1624 int cursor = d->positionAt(event->position());
1625 d->moveCursor(cursor, mark);
1626 }
1627
1628 if (d->focusOnPress && !qGuiApp->styleHints()->setFocusOnTouchRelease())
1629 ensureActiveFocus(Qt::MouseFocusReason);
1630
1631 event->setAccepted(true);
1632}
1633
1635{
1636 Q_D(QQuickTextInput);
1638#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1639 && ! d->selectByTouchDrag
1640#endif
1641 )
1642 return;
1643
1644 if (d->selectPressed) {
1645 if (qAbs(int(event->position().x() - d->pressPos.x())) > QGuiApplication::styleHints()->startDragDistance())
1646 setKeepMouseGrab(true);
1647
1648#if QT_CONFIG(im)
1649 if (d->composeMode()) {
1650 // start selection
1651 int startPos = d->positionAt(d->pressPos);
1652 int currentPos = d->positionAt(event->position());
1653 if (startPos != currentPos)
1654 d->setSelection(startPos, currentPos - startPos);
1655 } else
1656#endif
1657 {
1658 moveCursorSelection(d->positionAt(event->position()), d->mouseSelectionMode);
1659 }
1660 event->setAccepted(true);
1661 } else {
1663 }
1664}
1665
1667{
1668 Q_D(QQuickTextInput);
1669 if (d->sendMouseEventToInputContext(event))
1670 return;
1671 if (d->selectPressed) {
1672 d->selectPressed = false;
1673 setKeepMouseGrab(false);
1674 }
1676#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1677 || d->selectByTouchDrag
1678#endif
1679 ;
1680
1681#if QT_CONFIG(clipboard)
1682 if (isMouse && QGuiApplication::clipboard()->supportsSelection()) {
1683 if (event->button() == Qt::LeftButton) {
1684 d->copy(QClipboard::Selection);
1685 } else if (!d->m_readOnly && event->button() == Qt::MiddleButton) {
1686 d->deselect();
1688 }
1689 }
1690#endif
1691
1692 // On a touchscreen or with a stylus, set cursor position and focus on release, not on press;
1693 // if Flickable steals the grab in the meantime, the cursor won't move.
1694 // Check d->hasSelectedText() to keep touch-and-hold word selection working.
1695 if (!isMouse && !d->hasSelectedText())
1696 d->moveCursor(d->positionAt(event->position()), false);
1697
1698 if (d->focusOnPress && qGuiApp->styleHints()->setFocusOnTouchRelease())
1699 ensureActiveFocus(Qt::MouseFocusReason);
1700
1701 if (!event->isAccepted())
1703}
1704
1706{
1707#if QT_CONFIG(im)
1708 if (composeMode()) {
1709 int tmp_cursor = positionAt(event->position());
1710 int mousePos = tmp_cursor - m_cursor;
1711 if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().size()) {
1712 if (event->type() == QEvent::MouseButtonRelease) {
1713 QGuiApplication::inputMethod()->invokeAction(QInputMethod::Click, mousePos);
1714 }
1715 return true;
1716 }
1717 }
1718#else
1719 Q_UNUSED(event);
1720#endif
1721
1722 return false;
1723}
1724
1726{
1727 Q_D(QQuickTextInput);
1728 d->selectPressed = false;
1729 setKeepMouseGrab(false);
1730}
1731
1733{
1734#if QT_CONFIG(shortcut)
1735 Q_D(QQuickTextInput);
1736 if (ev->type() == QEvent::ShortcutOverride) {
1737 if (d->m_readOnly) {
1738 ev->ignore();
1739 return false;
1740 }
1741 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1742 if (ke == QKeySequence::Copy
1743 || ke == QKeySequence::Paste
1744 || ke == QKeySequence::Cut
1745 || ke == QKeySequence::Redo
1746 || ke == QKeySequence::Undo
1761 ke->accept();
1762 return true;
1763 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1764 || ke->modifiers() == Qt::KeypadModifier) {
1765 if (ke->key() < Qt::Key_Escape) {
1766 ke->accept();
1767 return true;
1768 } else {
1769 switch (ke->key()) {
1770 case Qt::Key_Delete:
1771 case Qt::Key_Home:
1772 case Qt::Key_End:
1773 case Qt::Key_Backspace:
1774 case Qt::Key_Left:
1775 case Qt::Key_Right:
1776 ke->accept();
1777 return true;
1778 default:
1779 break;
1780 }
1781 }
1782 }
1783 ev->ignore();
1784 }
1785#endif
1786
1788}
1789
1791 const QRectF &oldGeometry)
1792{
1793 Q_D(QQuickTextInput);
1794 if (!d->inLayout) {
1795 if (newGeometry.width() != oldGeometry.width())
1796 d->updateLayout();
1797 else if (newGeometry.height() != oldGeometry.height() && d->vAlign != QQuickTextInput::AlignTop)
1798 d->updateBaselineOffset();
1799 updateCursorRectangle();
1800 }
1801 QQuickImplicitSizeItem::geometryChange(newGeometry, oldGeometry);
1802}
1803
1805{
1806 Q_D(QQuickTextInput);
1807 Q_UNUSED(value);
1808 switch (change) {
1810 if (d->renderType == NativeRendering) {
1811 // Native rendering optimizes for a given pixel grid, so its results must not be scaled.
1812 // Text layout code respects the current device pixel ratio automatically, we only need
1813 // to rerun layout after the ratio changed.
1814 d->updateLayout();
1815 }
1816 break;
1817
1818 default:
1819 break;
1820 }
1822}
1823
1824void QQuickTextInputPrivate::ensureVisible(int position, int preeditCursor, int preeditLength)
1825{
1826 Q_Q(QQuickTextInput);
1827 QTextLine textLine = m_textLayout.lineForTextPosition(position + preeditCursor);
1828 const qreal width = qMax<qreal>(0, q->width() - q->leftPadding() - q->rightPadding());
1829 qreal cix = 0;
1830 qreal widthUsed = 0;
1831 if (textLine.isValid()) {
1832 cix = textLine.cursorToX(position + preeditLength);
1833 const qreal cursorWidth = cix >= 0 ? cix : width - cix;
1834 widthUsed = qMax(textLine.naturalTextWidth(), cursorWidth);
1835 }
1836 int previousScroll = hscroll;
1837
1838 if (widthUsed <= width) {
1839 hscroll = 0;
1840 } else {
1841 Q_ASSERT(textLine.isValid());
1842 if (cix - hscroll >= width) {
1843 // text doesn't fit, cursor is to the right of br (scroll right)
1844 hscroll = cix - width;
1845 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1846 // text doesn't fit, cursor is to the left of br (scroll left)
1847 hscroll = cix;
1848 } else if (widthUsed - hscroll < width) {
1849 // text doesn't fit, text document is to the left of br; align
1850 // right
1851 hscroll = widthUsed - width;
1852 } else if (width - hscroll > widthUsed) {
1853 // text doesn't fit, text document is to the right of br; align
1854 // left
1855 hscroll = width - widthUsed;
1856 }
1857#if QT_CONFIG(im)
1858 if (preeditLength > 0) {
1859 // check to ensure long pre-edit text doesn't push the cursor
1860 // off to the left
1861 cix = textLine.cursorToX(position + qMax(0, preeditCursor - 1));
1862 if (cix < hscroll)
1863 hscroll = cix;
1864 }
1865#endif
1866 }
1867 if (previousScroll != hscroll)
1868 textLayoutDirty = true;
1869}
1870
1872{
1874#if QT_CONFIG(im)
1875 const int preeditLength = m_textLayout.preeditAreaText().size();
1876 ensureVisible(m_cursor, m_preeditCursor, preeditLength);
1877#else
1879#endif
1880 } else {
1881 hscroll = 0;
1882 }
1883}
1884
1886{
1887 Q_Q(QQuickTextInput);
1888#if QT_CONFIG(im)
1889 const int preeditLength = m_textLayout.preeditAreaText().size();
1890#endif
1891 const qreal height = qMax<qreal>(0, q->height() - q->topPadding() - q->bottomPadding());
1892 qreal heightUsed = contentSize.height();
1893 qreal previousScroll = vscroll;
1894
1895 if (!autoScroll || heightUsed <= height) {
1896 // text fits in br; use vscroll for alignment
1899 } else {
1900#if QT_CONFIG(im)
1901 QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
1902#else
1904#endif
1905 QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
1906 qreal top = r.top();
1907 int bottom = r.bottom();
1908
1909 if (bottom - vscroll >= height) {
1910 // text doesn't fit, cursor is to the below the br (scroll down)
1911 vscroll = bottom - height;
1912 } else if (top - vscroll < 0 && vscroll < heightUsed) {
1913 // text doesn't fit, cursor is above br (scroll up)
1914 vscroll = top;
1915 } else if (heightUsed - vscroll < height) {
1916 // text doesn't fit, text document is to the left of br; align
1917 // right
1918 vscroll = heightUsed - height;
1919 }
1920#if QT_CONFIG(im)
1921 if (preeditLength > 0) {
1922 // check to ensure long pre-edit text doesn't push the cursor
1923 // off the top
1924 currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
1925 top = currentLine.isValid() ? currentLine.rect().top() : 0;
1926 if (top < vscroll)
1927 vscroll = top;
1928 }
1929#endif
1930 }
1931 if (previousScroll != vscroll)
1932 textLayoutDirty = true;
1933}
1934
1935void QQuickTextInput::triggerPreprocess()
1936{
1937 Q_D(QQuickTextInput);
1938 if (d->updateType == QQuickTextInputPrivate::UpdateNone)
1940 polish();
1941 update();
1942}
1943
1945{
1946 invalidateFontCaches();
1947}
1948
1949void QQuickTextInput::invalidateFontCaches()
1950{
1951 Q_D(QQuickTextInput);
1952
1953 if (d->m_textLayout.engine() != nullptr)
1954 d->m_textLayout.engine()->resetFontEngineCache();
1955}
1956
1957void QQuickTextInput::ensureActiveFocus(Qt::FocusReason reason)
1958{
1959 bool hadActiveFocus = hasActiveFocus();
1960 forceActiveFocus(reason);
1961#if QT_CONFIG(im)
1962 Q_D(QQuickTextInput);
1963 // re-open input panel on press if already focused
1964 if (hasActiveFocus() && hadActiveFocus && !d->m_readOnly)
1965 qGuiApp->inputMethod()->show();
1966#else
1967 Q_UNUSED(hadActiveFocus);
1968#endif
1969}
1970
1972{
1973 Q_UNUSED(data);
1974 Q_D(QQuickTextInput);
1975
1976 if (d->updateType != QQuickTextInputPrivate::UpdatePaintNode && oldNode != nullptr) {
1977 // Update done in preprocess() in the nodes
1979 return oldNode;
1980 }
1981
1983
1984 QSGInternalTextNode *node = static_cast<QSGInternalTextNode *>(oldNode);
1985 if (node == nullptr)
1986 node = d->sceneGraphContext()->createInternalTextNode(d->sceneGraphRenderContext());
1987 d->textNode = node;
1988
1989 const bool showCursor = !isReadOnly() && d->cursorItem == nullptr && d->cursorVisible && d->m_blinkStatus;
1990
1991 if (!d->textLayoutDirty && oldNode != nullptr) {
1992 if (showCursor)
1993 node->setCursor(cursorRectangle(), d->color);
1994 else
1995 node->clearCursor();
1996 } else {
1997 node->setRenderType(QSGTextNode::RenderType(d->renderType));
1998 node->clear();
1999 node->setMatrix(QMatrix4x4());
2001 node->setColor(d->color);
2002 node->setSelectionTextColor(d->selectedTextColor);
2003 node->setSelectionColor(d->selectionColor);
2005
2006 if (flags().testFlag(ItemObservesViewport))
2007 node->setViewport(clipRect());
2008 else
2009 node->setViewport(QRectF{});
2010
2012 if (d->autoScroll && d->m_textLayout.lineCount() > 0) {
2013 QFontMetricsF fm(d->font);
2014 // the y offset is there to keep the baseline constant in case we have script changes in the text.
2015 offset += -QPointF(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent());
2016 } else {
2017 offset += -QPointF(d->hscroll, d->vscroll);
2018 }
2019
2020 if (!d->m_textLayout.text().isEmpty()
2021#if QT_CONFIG(im)
2022 || !d->m_textLayout.preeditAreaText().isEmpty()
2023#endif
2024 ) {
2025 node->addTextLayout(offset, &d->m_textLayout,
2026 d->selectionStart(),
2027 d->selectionEnd() - 1); // selectionEnd() returns first char after
2028 // selection
2029 }
2030
2031 if (showCursor)
2032 node->setCursor(cursorRectangle(), d->color);
2033
2034 d->textLayoutDirty = false;
2035 }
2036
2037 invalidateFontCaches();
2038
2039 return node;
2040}
2041
2042#if QT_CONFIG(im)
2043QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
2044{
2045#ifdef Q_OS_ANDROID
2046 // QTBUG-61652
2048 Q_D(const QQuickItem);
2049 // Do not change if type was set manually
2050 if (!d->extra.isAllocated()
2051 || d->extra->enterKeyAttached == nullptr
2052 || d->extra->enterKeyAttached->type() == Qt::EnterKeyDefault) {
2053
2054 QQuickItem *next = const_cast<QQuickTextInput*>(this)->nextItemInFocusChain();
2055 QQuickItem *originalNext = next;
2056 while (next && next != this && !next->activeFocusOnTab()) {
2057 next = next->nextItemInFocusChain();
2058 if (next == originalNext) {
2059 // There seems to be no suitable element in the focus chain
2060 next = nullptr;
2061 }
2062 }
2063 if (next) {
2064 const auto nextYPos = next->mapToGlobal(QPoint(0, 0)).y();
2065 const auto currentYPos = this->mapToGlobal(QPoint(0, 0)).y();
2066 if (currentYPos < nextYPos)
2067 // Set EnterKey to KeyNext type only if the next item
2068 // in the focus chain is below current QQuickTextInput
2069 return Qt::EnterKeyNext;
2070 }
2071 }
2072 }
2073#endif
2074 return inputMethodQuery(property, QVariant());
2075}
2076
2077QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, const QVariant &argument) const
2078{
2079 Q_D(const QQuickTextInput);
2080 switch (property) {
2081 case Qt::ImEnabled:
2082 return QVariant((bool)(flags() & ItemAcceptsInputMethod));
2083 case Qt::ImHints:
2084 return QVariant((int) d->effectiveInputMethodHints());
2086 return cursorRectangle();
2088 return d->anchorRectangle();
2089 case Qt::ImFont:
2090 return font();
2091 case Qt::ImCursorPosition: {
2092 const QPointF pt = argument.toPointF();
2093 if (!pt.isNull())
2094 return QVariant(d->positionAt(pt));
2095 return QVariant(d->m_cursor);
2096 }
2098 if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) {
2099 return QVariant(displayText());
2100 } else {
2101 return QVariant(d->realText());
2102 }
2104 return QVariant(selectedText());
2106 return QVariant(maxLength());
2108 if (d->selectionStart() == d->selectionEnd())
2109 return QVariant(d->m_cursor);
2110 else if (d->selectionStart() == d->m_cursor)
2111 return QVariant(d->selectionEnd());
2112 else
2113 return QVariant(d->selectionStart());
2115 return QVariant(d->m_cursor);
2117 if (argument.isValid())
2118 return QVariant(d->m_text.mid(d->m_cursor, argument.toInt()));
2119 return QVariant(d->m_text.mid(d->m_cursor));
2121 if (argument.isValid())
2122 return QVariant(QStringView{d->m_text}.left(d->m_cursor).right(argument.toInt()).toString());
2123 return QVariant(d->m_text.left(d->m_cursor));
2124 case Qt::ImReadOnly:
2125 return QVariant(d->m_readOnly);
2126 default:
2127 return QQuickItem::inputMethodQuery(property);
2128 }
2129}
2130#endif // im
2131
2138{
2139 Q_D(QQuickTextInput);
2140 d->deselect();
2141}
2142
2149{
2150 Q_D(QQuickTextInput);
2151 d->setSelection(0, text().size());
2152}
2153
2161{
2162 if (start > end) {
2163 qmlWarning(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
2164 return false;
2165 } else {
2167 }
2168}
2169
2170#if QT_CONFIG(clipboard)
2180void QQuickTextInput::cut()
2181{
2182 Q_D(QQuickTextInput);
2183 if (!d->m_readOnly && d->m_echoMode == QQuickTextInput::Normal) {
2184 d->copy();
2185 d->del();
2186 }
2187}
2188
2198void QQuickTextInput::copy()
2199{
2200 Q_D(QQuickTextInput);
2201 d->copy();
2202}
2203
2209void QQuickTextInput::paste()
2210{
2211 Q_D(QQuickTextInput);
2212 if (!d->m_readOnly)
2213 d->paste();
2214}
2215#endif // clipboard
2216
2226{
2227 Q_D(QQuickTextInput);
2228 if (!d->m_readOnly) {
2229 d->cancelInput();
2230 d->internalUndo();
2231 d->finishChange(-1, true);
2232 }
2233}
2234
2242{
2243 Q_D(QQuickTextInput);
2244 if (!d->m_readOnly) {
2245 d->cancelInput();
2246 d->internalRedo();
2247 d->finishChange();
2248 }
2249}
2250
2258{
2259 Q_D(QQuickTextInput);
2260 if (d->m_echoMode == QQuickTextInput::Password) {
2261 if (d->m_passwordMaskDelay > 0)
2262 d->m_passwordEchoTimer.start(d->m_passwordMaskDelay, this);
2263 }
2264 if (position < 0 || position > d->m_text.size())
2265 return;
2266
2267 const int priorState = d->m_undoState;
2268
2269 QString insertText = text;
2270
2271 if (d->hasSelectedText()) {
2273 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2274 }
2275 if (d->m_maskData) {
2276 insertText = d->maskString(position, insertText);
2277 for (int i = 0; i < insertText.size(); ++i) {
2279 QQuickTextInputPrivate::DeleteSelection, position + i, d->m_text.at(position + i), -1, -1));
2281 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2282 }
2283 d->m_text.replace(position, insertText.size(), insertText);
2284 if (!insertText.isEmpty())
2285 d->m_textDirty = true;
2286 if (position < d->m_selend && position + insertText.size() > d->m_selstart)
2287 d->m_selDirty = true;
2288 } else {
2289 int remaining = d->m_maxLength - d->m_text.size();
2290 if (remaining != 0) {
2291 insertText = insertText.left(remaining);
2292 d->m_text.insert(position, insertText);
2293 for (int i = 0; i < insertText.size(); ++i)
2295 QQuickTextInputPrivate::Insert, position + i, insertText.at(i), -1, -1));
2296 if (d->m_cursor >= position)
2297 d->m_cursor += insertText.size();
2298 if (d->m_selstart >= position)
2299 d->m_selstart += insertText.size();
2300 if (d->m_selend >= position)
2301 d->m_selend += insertText.size();
2302 d->m_textDirty = true;
2303 if (position >= d->m_selstart && position <= d->m_selend)
2304 d->m_selDirty = true;
2305 }
2306 }
2307
2309 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2310 d->finishChange(priorState);
2311
2312 if (d->lastSelectionStart != d->lastSelectionEnd) {
2313 if (d->m_selstart != d->lastSelectionStart) {
2314 d->lastSelectionStart = d->m_selstart;
2316 }
2317 if (d->m_selend != d->lastSelectionEnd) {
2318 d->lastSelectionEnd = d->m_selend;
2320 }
2321 }
2322}
2323
2331{
2332 Q_D(QQuickTextInput);
2333
2334 start = qBound(0, start, d->m_text.size());
2335 end = qBound(0, end, d->m_text.size());
2336
2337 if (start > end)
2338 qSwap(start, end);
2339 else if (start == end)
2340 return;
2341
2342 if (start < d->m_selend && end > d->m_selstart)
2343 d->m_selDirty = true;
2344
2345 const int priorState = d->m_undoState;
2346
2348 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2349
2350 if (start <= d->m_cursor && d->m_cursor < end) {
2351 // cursor is within the selection. Split up the commands
2352 // to be able to restore the correct cursor position
2353 for (int i = d->m_cursor; i >= start; --i) {
2355 QQuickTextInputPrivate::DeleteSelection, i, d->m_text.at(i), -1, 1));
2356 }
2357 for (int i = end - 1; i > d->m_cursor; --i) {
2359 QQuickTextInputPrivate::DeleteSelection, i - d->m_cursor + start - 1, d->m_text.at(i), -1, -1));
2360 }
2361 } else {
2362 for (int i = end - 1; i >= start; --i) {
2364 QQuickTextInputPrivate::RemoveSelection, i, d->m_text.at(i), -1, -1));
2365 }
2366 }
2367 if (d->m_maskData) {
2368 d->m_text.replace(start, end - start, d->clearString(start, end - start));
2369 for (int i = 0; i < end - start; ++i) {
2371 QQuickTextInputPrivate::Insert, start + i, d->m_text.at(start + i), -1, -1));
2372 }
2373 } else {
2374 d->m_text.remove(start, end - start);
2375
2376 if (d->m_cursor > start)
2377 d->m_cursor -= qMin(d->m_cursor, end) - start;
2378 if (d->m_selstart > start)
2379 d->m_selstart -= qMin(d->m_selstart, end) - start;
2380 if (d->m_selend >= end)
2381 d->m_selend -= end - start;
2382 }
2384 QQuickTextInputPrivate::SetSelection, d->m_cursor, u'\0', d->m_selstart, d->m_selend));
2385
2386 d->m_textDirty = true;
2387 d->finishChange(priorState);
2388
2389 if (d->lastSelectionStart != d->lastSelectionEnd) {
2390 if (d->m_selstart != d->lastSelectionStart) {
2391 d->lastSelectionStart = d->m_selstart;
2393 }
2394 if (d->m_selend != d->lastSelectionEnd) {
2395 d->lastSelectionEnd = d->m_selend;
2397 }
2398 }
2399}
2400
2401
2408{
2409 Q_D(QQuickTextInput);
2410 d->selectWordAtPos(d->m_cursor);
2411}
2412
2425{
2426 Q_D(const QQuickTextInput);
2427 return QString(d->m_passwordCharacter);
2428}
2429
2431{
2432 Q_D(QQuickTextInput);
2433 if (str.size() < 1)
2434 return;
2435 d->m_passwordCharacter = str.constData()[0];
2436 if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
2437 d->updateDisplayText();
2439}
2440
2450{
2451 Q_D(const QQuickTextInput);
2452 return d->m_passwordMaskDelay;
2453}
2454
2456{
2457 Q_D(QQuickTextInput);
2458 if (d->m_passwordMaskDelay != delay) {
2459 d->m_passwordMaskDelay = delay;
2460 emit passwordMaskDelayChanged(delay);
2461 }
2462}
2463
2465{
2466 setPasswordMaskDelay(qGuiApp->styleHints()->passwordMaskDelay());
2467}
2468
2486{
2487 Q_D(const QQuickTextInput);
2488 return d->m_textLayout.text().insert(d->m_textLayout.preeditAreaPosition(), d->m_textLayout.preeditAreaText());
2489}
2490
2504{
2505 Q_D(const QQuickTextInput);
2506 return d->m_textLayout.preeditAreaText();
2507}
2508
2528{
2529 Q_D(const QQuickTextInput);
2530 return d->selectByMouse;
2531}
2532
2534{
2535 Q_D(QQuickTextInput);
2536 if (d->selectByMouse != on) {
2537 d->selectByMouse = on;
2539 }
2540}
2541
2554{
2555 Q_D(const QQuickTextInput);
2556 return d->mouseSelectionMode;
2557}
2558
2560{
2561 Q_D(QQuickTextInput);
2562 if (d->mouseSelectionMode != mode) {
2563 d->mouseSelectionMode = mode;
2565 }
2566}
2567
2576{
2577 Q_D(const QQuickTextInput);
2578 return d->persistentSelection;
2579}
2580
2582{
2583 Q_D(QQuickTextInput);
2584 if (d->persistentSelection == on)
2585 return;
2586 d->persistentSelection = on;
2588}
2589
2598{
2599#if QT_CONFIG(clipboard)
2600 Q_D(const QQuickTextInput);
2601 if (!d->canPasteValid) {
2603 const_cast<QQuickTextInputPrivate *>(d)->canPaste = !d->m_readOnly && mimeData->hasText() && !mimeData->text().isEmpty();
2604 const_cast<QQuickTextInputPrivate *>(d)->canPasteValid = true;
2605 }
2606 return d->canPaste;
2607#else
2608 return false;
2609#endif
2610}
2611
2621{
2622 Q_D(const QQuickTextInput);
2623 return d->canUndo;
2624}
2625
2635{
2636 Q_D(const QQuickTextInput);
2637 return d->canRedo;
2638}
2639
2649{
2650 Q_D(const QQuickTextInput);
2651 return d->contentSize.width();
2652}
2653
2663{
2664 Q_D(const QQuickTextInput);
2665 return d->contentSize.height();
2666}
2667
2669{
2670 Q_D(QQuickTextInput);
2671 d->moveCursor(position, true);
2672}
2673
2711{
2712 Q_D(QQuickTextInput);
2713
2714 if (mode == SelectCharacters) {
2715 d->moveCursor(pos, true);
2716 } else if (pos != d->m_cursor) {
2717 const int cursor = d->m_cursor;
2718 int anchor;
2719 if (!d->hasSelectedText())
2720 anchor = d->m_cursor;
2721 else if (d->selectionStart() == d->m_cursor)
2722 anchor = d->selectionEnd();
2723 else
2724 anchor = d->selectionStart();
2725
2726 if (anchor < pos || (anchor == pos && cursor < pos)) {
2727 const QString text = this->text();
2729 finder.setPosition(anchor);
2730
2731 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2732 if (anchor < text.size() && (reasons == QTextBoundaryFinder::NotAtBoundary
2733 || (reasons & QTextBoundaryFinder::EndOfItem))) {
2734 finder.toPreviousBoundary();
2735 }
2736 anchor = finder.position() != -1 ? finder.position() : 0;
2737
2738 finder.setPosition(pos);
2739 if (pos > 0 && !finder.boundaryReasons())
2740 finder.toNextBoundary();
2741 const int cursor = finder.position() != -1 ? finder.position() : text.size();
2742
2743 d->setSelection(anchor, cursor - anchor);
2744 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
2745 const QString text = this->text();
2747 finder.setPosition(anchor);
2748
2749 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
2750 if (anchor > 0 && (reasons == QTextBoundaryFinder::NotAtBoundary
2751 || (reasons & QTextBoundaryFinder::StartOfItem))) {
2752 finder.toNextBoundary();
2753 }
2754 anchor = finder.position() != -1 ? finder.position() : text.size();
2755
2756 finder.setPosition(pos);
2757 if (pos < text.size() && !finder.boundaryReasons())
2758 finder.toPreviousBoundary();
2759 const int cursor = finder.position() != -1 ? finder.position() : 0;
2760
2761 d->setSelection(anchor, cursor - anchor);
2762 }
2763 }
2764}
2765
2772
2774{
2775 Q_Q(QQuickTextInput);
2776 bool focus = event->gotFocus();
2777 if (!m_readOnly) {
2778 q->setCursorVisible(focus);
2780 }
2781 if (focus) {
2782 q->q_updateAlignment();
2783#if QT_CONFIG(im)
2784 if (focusOnPress && !m_readOnly)
2785 qGuiApp->inputMethod()->show();
2786 q->connect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2787 q, SLOT(q_updateAlignment()));
2788#endif
2789 } else {
2791 updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
2792 }
2793
2794 if (event->reason() != Qt::ActiveWindowFocusReason
2795 && event->reason() != Qt::PopupFocusReason
2796 && hasSelectedText()
2798 deselect();
2799
2800 if (hasAcceptableInput(m_text) == AcceptableInput || fixup())
2801 emit q->editingFinished();
2802
2803#if QT_CONFIG(im)
2804 q->disconnect(QGuiApplication::inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
2805 q, SLOT(q_updateAlignment()));
2806#endif
2807 }
2808}
2809
2816
2830{
2831#if !QT_CONFIG(im)
2832 return false;
2833#else
2834 Q_D(const QQuickTextInput);
2835 return d->hasImState;
2836#endif
2837}
2838
2840 : padding(0)
2841 , topPadding(0)
2842 , leftPadding(0)
2843 , rightPadding(0)
2844 , bottomPadding(0)
2845 , explicitTopPadding(false)
2846 , explicitLeftPadding(false)
2847 , explicitRightPadding(false)
2848 , explicitBottomPadding(false)
2849 , implicitResize(true)
2850{
2851}
2852
2854{
2855 Q_Q(QQuickTextInput);
2856#if QT_CONFIG(clipboard)
2857 if (QGuiApplication::clipboard()->supportsSelection())
2858 q->setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton);
2859 else
2860#endif
2861 q->setAcceptedMouseButtons(Qt::LeftButton);
2862
2863#if QT_CONFIG(im)
2864 q->setFlag(QQuickItem::ItemAcceptsInputMethod);
2865#endif
2867#if QT_CONFIG(clipboard)
2869 q, QQuickTextInput, SLOT(q_canPasteChanged()));
2870#endif // clipboard
2871
2873 lastSelectionEnd = 0;
2875
2876 if (!qmlDisableDistanceField()) {
2880 }
2881
2884}
2885
2887{
2888#if QT_CONFIG(im)
2889 Q_Q(QQuickTextInput);
2890 if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
2891 cancelPreedit();
2892#endif // im
2893}
2894
2895void QQuickTextInput::updateCursorRectangle(bool scroll)
2896{
2897 Q_D(QQuickTextInput);
2898 if (!isComponentComplete())
2899 return;
2900
2901 if (scroll) {
2902 d->updateHorizontalScroll();
2903 d->updateVerticalScroll();
2904 }
2906 polish();
2907 update();
2908 emit cursorRectangleChanged();
2909 if (d->cursorItem) {
2910 QRectF r = cursorRectangle();
2911 d->cursorItem->setPosition(r.topLeft());
2912 d->cursorItem->setHeight(r.height());
2913 }
2914#if QT_CONFIG(im)
2915 updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
2916#endif
2917}
2918
2919void QQuickTextInput::selectionChanged()
2920{
2921 Q_D(QQuickTextInput);
2922 d->textLayoutDirty = true; //TODO: Only update rect in selection
2924 polish();
2925 update();
2926 emit selectedTextChanged();
2927
2928 if (d->lastSelectionStart != d->selectionStart()) {
2929 d->lastSelectionStart = d->selectionStart();
2930 if (d->lastSelectionStart == -1)
2931 d->lastSelectionStart = d->m_cursor;
2932 emit selectionStartChanged();
2933 }
2934 if (d->lastSelectionEnd != d->selectionEnd()) {
2935 d->lastSelectionEnd = d->selectionEnd();
2936 if (d->lastSelectionEnd == -1)
2937 d->lastSelectionEnd = d->m_cursor;
2938 emit selectionEndChanged();
2939 }
2940}
2941
2943{
2944 Q_D(const QQuickTextInput);
2945
2946 int cursorWidth = d->cursorItem ? 0 : 1;
2947
2948 qreal hscroll = d->hscroll;
2949 if (!d->autoScroll || d->contentSize.width() < width())
2950 hscroll -= QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign());
2951
2952 // Could include font max left/right bearings to either side of rectangle.
2953 QRectF r(-hscroll, -d->vscroll, d->contentSize.width(), d->contentSize.height());
2954 r.setRight(r.right() + cursorWidth);
2955 return r;
2956}
2957
2959{
2960 Q_D(const QQuickTextInput);
2961
2962 int cursorWidth = d->cursorItem ? d->cursorItem->width() : 1;
2963
2964 // Could include font max left/right bearings to either side of rectangle.
2966 r.setRight(r.right() + cursorWidth);
2967 return r;
2968}
2969
2970void QQuickTextInput::q_canPasteChanged()
2971{
2972 Q_D(QQuickTextInput);
2973 bool old = d->canPaste;
2974#if QT_CONFIG(clipboard)
2976 d->canPaste = !d->m_readOnly && mimeData->hasText();
2977 else
2978 d->canPaste = false;
2979#endif
2980
2981 bool changed = d->canPaste != old || !d->canPasteValid;
2982 d->canPasteValid = true;
2983 if (changed)
2984 emit canPasteChanged();
2985
2986}
2987
2988void QQuickTextInput::q_updateAlignment()
2989{
2990 Q_D(QQuickTextInput);
2991 if (d->determineHorizontalAlignment()) {
2992 d->updateLayout();
2993 updateCursorRectangle();
2994 }
2995}
2996
3003void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
3004{
3005 QString orig = m_textLayout.text();
3006 QString str;
3009 else
3010 str = m_text;
3011
3015 int cursor = m_cursor - 1;
3016 QChar uc = m_text.at(cursor);
3017 str[cursor] = uc;
3018 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3019 // second half of a surrogate, check if we have the first half as well,
3020 // if yes restore both at once
3021 uc = m_text.at(cursor - 1);
3022 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
3023 str[cursor - 1] = uc;
3024 }
3025 }
3028 }
3029
3030 // replace certain non-printable characters with spaces (to avoid
3031 // drawing boxes when using fonts that don't have glyphs for such
3032 // characters)
3033 QChar* uc = str.data();
3034 for (int i = 0; i < str.size(); ++i) {
3035 if (uc[i] == QChar::LineSeparator
3036 || uc[i] == QChar::ParagraphSeparator
3037 || uc[i] == QChar::ObjectReplacementCharacter)
3038 uc[i] = QChar(0x0020);
3039 }
3040
3041 if (str != orig || forceUpdate) {
3043 updateLayout(); // polish?
3044 emit q_func()->displayTextChanged();
3045 }
3046}
3047
3049{
3050 Q_Q(const QQuickTextInput);
3052
3057 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3058 layout.setTextOption(option);
3059 layout.setFont(font);
3060#if QT_CONFIG(im)
3062#endif
3063 layout.beginLayout();
3064
3065 QTextLine line = layout.createLine();
3066 line.setLineWidth(INT_MAX);
3067 const qreal theImplicitWidth = qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding();
3068
3069 layout.endLayout();
3070 return theImplicitWidth;
3071}
3072
3074{
3075 Q_Q(const QQuickTextInput);
3076 if (!requireImplicitWidth) {
3077 QQuickTextInputPrivate *d = const_cast<QQuickTextInputPrivate *>(this);
3078 d->requireImplicitWidth = true;
3079
3080 if (q->isComponentComplete())
3081 d->implicitWidth = calculateImplicitWidthForText(m_text);
3082 }
3083 return implicitWidth;
3084}
3085
3087{
3088 Q_Q(QQuickTextInput);
3089 qreal oldPadding = q->topPadding();
3090 if (!reset || extra.isAllocated()) {
3091 extra.value().topPadding = value;
3092 extra.value().explicitTopPadding = !reset;
3093 }
3094 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3095 updateLayout();
3096 q->updateCursorRectangle();
3097 emit q->topPaddingChanged();
3098 }
3099}
3100
3102{
3103 Q_Q(QQuickTextInput);
3104 qreal oldPadding = q->leftPadding();
3105 if (!reset || extra.isAllocated()) {
3106 extra.value().leftPadding = value;
3107 extra.value().explicitLeftPadding = !reset;
3108 }
3109 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3110 updateLayout();
3111 q->updateCursorRectangle();
3112 emit q->leftPaddingChanged();
3113 }
3114}
3115
3117{
3118 Q_Q(QQuickTextInput);
3119 qreal oldPadding = q->rightPadding();
3120 if (!reset || extra.isAllocated()) {
3121 extra.value().rightPadding = value;
3122 extra.value().explicitRightPadding = !reset;
3123 }
3124 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3125 updateLayout();
3126 q->updateCursorRectangle();
3127 emit q->rightPaddingChanged();
3128 }
3129}
3130
3132{
3133 Q_Q(QQuickTextInput);
3134 qreal oldPadding = q->bottomPadding();
3135 if (!reset || extra.isAllocated()) {
3136 extra.value().bottomPadding = value;
3137 extra.value().explicitBottomPadding = !reset;
3138 }
3139 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
3140 updateLayout();
3141 q->updateCursorRectangle();
3142 emit q->bottomPaddingChanged();
3143 }
3144}
3145
3147{
3148 return !extra.isAllocated() || extra->implicitResize;
3149}
3150
3152{
3153 if (!enabled)
3154 extra.value().implicitResize = false;
3155 else if (extra.isAllocated())
3156 extra->implicitResize = true;
3157}
3158
3160{
3161 Q_Q(QQuickTextInput);
3162
3163 if (!q->isComponentComplete())
3164 return;
3165
3166
3170 option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
3171 if (!qmlDisableDistanceField())
3172 option.setUseDesignMetrics(renderType != QQuickTextInput::NativeRendering);
3173
3176
3178
3181 line.setLineWidth(INT_MAX);
3182 const bool wasInLayout = inLayout;
3183 inLayout = true;
3185 q->setImplicitWidth(qCeil(line.naturalTextWidth()) + q->leftPadding() + q->rightPadding());
3186 inLayout = wasInLayout;
3187 if (inLayout) // probably the result of a binding loop, but by letting it
3188 return; // get this far we'll get a warning to that effect.
3189 }
3190 qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX;
3191 qreal height = 0;
3192 qreal width = 0;
3193 do {
3194 line.setLineWidth(lineWidth);
3195 line.setPosition(QPointF(0, height));
3196
3197 height += line.height();
3198 width = qMax(width, line.naturalTextWidth());
3199
3201 } while (line.isValid());
3203
3204 option.setWrapMode(QTextOption::NoWrap);
3206
3207 textLayoutDirty = true;
3208
3209 const QSizeF previousSize = contentSize;
3211
3213 q->polish();
3214 q->update();
3215
3217 if (!requireImplicitWidth && !q->widthValid())
3218 q->setImplicitSize(width + q->leftPadding() + q->rightPadding(), height + q->topPadding() + q->bottomPadding());
3219 else
3220 q->setImplicitHeight(height + q->topPadding() + q->bottomPadding());
3221 }
3222
3224
3225 if (previousSize != contentSize)
3226 emit q->contentSizeChanged();
3227}
3228
3236{
3237 Q_Q(QQuickTextInput);
3238 if (!q->isComponentComplete())
3239 return;
3240 QFontMetricsF fm(font);
3241 qreal yoff = 0;
3242 if (q->heightValid()) {
3243 const qreal surplusHeight = q->height() - contentSize.height() - q->topPadding() - q->bottomPadding();
3245 yoff = surplusHeight;
3247 yoff = surplusHeight/2;
3248 }
3249 q->setBaselineOffset(fm.ascent() + yoff + q->topPadding());
3250}
3251
3252#if QT_CONFIG(clipboard)
3263void QQuickTextInputPrivate::copy(QClipboard::Mode mode) const
3264{
3266 if (!t.isEmpty() && m_echoMode == QQuickTextInput::Normal) {
3267 QGuiApplication::clipboard()->setText(t, mode);
3268 }
3269}
3270
3279void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
3280{
3281 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
3282 if (!clip.isEmpty() || hasSelectedText()) {
3283 separate(); //make it a separate undo/redo command
3284 insert(clip);
3285 separate();
3286 }
3287}
3288
3289#endif // clipboard
3290
3291#if QT_CONFIG(im)
3295void QQuickTextInputPrivate::commitPreedit()
3296{
3297 Q_Q(QQuickTextInput);
3298
3299 if (!hasImState)
3300 return;
3301
3302 QGuiApplication::inputMethod()->commit();
3303
3304 if (!hasImState)
3305 return;
3306
3309}
3310
3311void QQuickTextInputPrivate::cancelPreedit()
3312{
3313 Q_Q(QQuickTextInput);
3314
3315 if (!hasImState)
3316 return;
3317
3319
3322}
3323#endif // im
3324
3335{
3336 int priorState = m_undoState;
3337 if (separateSelection()) {
3338 removeSelectedText();
3339 } else if (m_cursor) {
3340 --m_cursor;
3341 if (m_maskData)
3343 QChar uc = m_text.at(m_cursor);
3344 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
3345 // second half of a surrogate, check if we have the first half as well,
3346 // if yes delete both at once
3347 uc = m_text.at(m_cursor - 1);
3348 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
3349 internalDelete(true);
3350 --m_cursor;
3351 }
3352 }
3353 internalDelete(true);
3354 }
3355 finishChange(priorState);
3356}
3357
3368{
3369 int priorState = m_undoState;
3370 if (separateSelection()) {
3371 removeSelectedText();
3372 } else {
3374 while (n--)
3375 internalDelete();
3376 }
3377 finishChange(priorState);
3378}
3379
3388{
3389 int priorState = m_undoState;
3390 if (separateSelection())
3391 removeSelectedText();
3392 internalInsert(newText);
3393 finishChange(priorState);
3394}
3395
3402{
3403 int priorState = m_undoState;
3404 separateSelection();
3405 m_selstart = 0;
3406 m_selend = m_text.size();
3407 removeSelectedText();
3408 separate();
3409 finishChange(priorState, /*update*/false, /*edited*/false);
3410}
3411
3421{
3422 Q_Q(QQuickTextInput);
3423#if QT_CONFIG(im)
3424 commitPreedit();
3425#endif
3426
3427 if (start < 0 || start > m_text.size()) {
3428 qWarning("QQuickTextInputPrivate::setSelection: Invalid start position");
3429 return;
3430 }
3431
3432 if (length > 0) {
3433 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
3434 return;
3435 m_selstart = start;
3438 } else if (length < 0) {
3440 return;
3441 m_selstart = qMax(start + length, 0);
3442 m_selend = start;
3444 } else if (m_selstart != m_selend) {
3445 m_selstart = 0;
3446 m_selend = 0;
3447 m_cursor = start;
3448 } else {
3449 m_cursor = start;
3450 emitCursorPositionChanged();
3451 return;
3452 }
3453 emit q->selectionChanged();
3454 emitCursorPositionChanged();
3455#if QT_CONFIG(im)
3458#endif
3459}
3460
3470{
3472 m_passwordEchoEditing = editing;
3473 updateDisplayText();
3474}
3475
3483bool QQuickTextInputPrivate::fixup() // this function assumes that validate currently returns != Acceptable
3484{
3485#if QT_CONFIG(validator)
3486 if (m_validator) {
3487 QString textCopy = m_text;
3488 int cursorCopy = m_cursor;
3489 m_validator->fixup(textCopy);
3490 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
3491 if (textCopy != m_text || cursorCopy != m_cursor)
3492 internalSetText(textCopy, cursorCopy);
3493 return true;
3494 }
3495 }
3496#endif
3497 return false;
3498}
3499
3507{
3508 Q_Q(QQuickTextInput);
3509#if QT_CONFIG(im)
3510 commitPreedit();
3511#endif
3512
3513 if (pos != m_cursor) {
3514 separate();
3515 if (m_maskData)
3517 }
3518 if (mark) {
3519 int anchor;
3521 anchor = m_selend;
3522 else if (m_selend > m_selstart && m_cursor == m_selend)
3523 anchor = m_selstart;
3524 else
3525 anchor = m_cursor;
3526 m_selstart = qMin(anchor, pos);
3527 m_selend = qMax(anchor, pos);
3528 } else {
3529 internalDeselect();
3530 }
3531 m_cursor = pos;
3532 if (mark || m_selDirty) {
3533 m_selDirty = false;
3534 emit q->selectionChanged();
3535 }
3536 emitCursorPositionChanged();
3537#if QT_CONFIG(im)
3538 q->updateInputMethod();
3539#endif
3540}
3541
3542#if QT_CONFIG(im)
3549void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
3550{
3551 Q_Q(QQuickTextInput);
3552
3553 int priorState = -1;
3554 bool isGettingInput = !event->commitString().isEmpty()
3555 || event->preeditString() != preeditAreaText()
3556 || event->replacementLength() > 0;
3557 bool cursorPositionChanged = false;
3558 bool selectionChange = false;
3559 m_preeditDirty = event->preeditString() != preeditAreaText();
3560
3561 if (isGettingInput) {
3562 // If any text is being input, remove selected text.
3563 priorState = m_undoState;
3564 separateSelection();
3567 m_selstart = 0;
3568 m_selend = m_text.size();
3569 }
3570 removeSelectedText();
3571 }
3572
3573 int c = m_cursor; // cursor position after insertion of commit string
3574 if (event->replacementStart() <= 0)
3575 c += event->commitString().size() - qMin(-event->replacementStart(), event->replacementLength());
3576
3577 int cursorInsertPos = m_cursor + event->replacementStart();
3578 if (cursorInsertPos < 0)
3579 cursorInsertPos = 0;
3580
3581 // insert commit string
3582 if (event->replacementLength()) {
3583 m_selstart = cursorInsertPos;
3584 m_selend = m_selstart + event->replacementLength();
3586 removeSelectedText();
3587 }
3588 m_cursor = cursorInsertPos;
3589
3590 if (!event->commitString().isEmpty()) {
3591 internalInsert(event->commitString());
3592 cursorPositionChanged = true;
3593 } else {
3594 m_cursor = qBound(0, c, m_text.size());
3595 }
3596
3597 for (int i = 0; i < event->attributes().size(); ++i) {
3598 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3599 if (a.type == QInputMethodEvent::Selection) {
3600 // If we already called internalInsert(), the cursor position will
3601 // already be adjusted correctly. The attribute.start does
3602 // not seem to take the mask into account, so it will reset cursor
3603 // to an invalid position in such case.
3604 if (!cursorPositionChanged)
3605 m_cursor = qBound(0, a.start + a.length, m_text.size());
3606 if (a.length) {
3607 m_selstart = qMax(0, qMin(a.start, m_text.size()));
3609 if (m_selend < m_selstart) {
3611 }
3612 selectionChange = true;
3613 } else {
3614 selectionChange = m_selstart != m_selend;
3615 m_selstart = m_selend = 0;
3616 }
3617 cursorPositionChanged = true;
3618 }
3619 }
3620 QString oldPreeditString = m_textLayout.preeditAreaText();
3621 m_textLayout.setPreeditArea(m_cursor, event->preeditString());
3622 if (oldPreeditString != m_textLayout.preeditAreaText()) {
3623 emit q->preeditTextChanged();
3624 if (!event->preeditString().isEmpty() && m_undoPreeditState == -1)
3625 // Pre-edit text started. Remember state for undo purpose.
3626 m_undoPreeditState = priorState;
3627 }
3628 const int oldPreeditCursor = m_preeditCursor;
3629 m_preeditCursor = event->preeditString().size();
3630 hasImState = !event->preeditString().isEmpty();
3631 bool cursorVisible = true;
3632 QVector<QTextLayout::FormatRange> formats;
3633 for (int i = 0; i < event->attributes().size(); ++i) {
3634 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
3635 if (a.type == QInputMethodEvent::Cursor) {
3636 hasImState = true;
3637 m_preeditCursor = a.start;
3638 cursorVisible = a.length != 0;
3639 } else if (a.type == QInputMethodEvent::TextFormat) {
3640 hasImState = true;
3641 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
3642 if (f.isValid()) {
3644 o.start = a.start + m_cursor;
3645 o.length = a.length;
3646 o.format = f;
3647 formats.append(o);
3648 }
3649 }
3650 }
3652
3653 updateDisplayText(/*force*/ true);
3654 if (cursorPositionChanged && emitCursorPositionChanged())
3655 q->updateInputMethod(Qt::ImCursorPosition | Qt::ImAnchorPosition);
3656 else if (m_preeditCursor != oldPreeditCursor || isGettingInput)
3657 q->updateCursorRectangle();
3658
3659 if (isGettingInput)
3660 finishChange(priorState);
3661
3662 q->setCursorVisible(cursorVisible);
3663
3664 if (selectionChange) {
3665 emit q->selectionChanged();
3666 q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle
3668 }
3669
3670 // Empty pre-edit text handled. Clean m_undoPreeditState
3671 if (event->preeditString().isEmpty())
3672 m_undoPreeditState = -1;
3673
3674}
3675#endif // im
3676
3685{
3686 int next = cursor + 1;
3687 if (next > end())
3688 --next;
3690 moveCursor(c, false);
3691 // ## text layout should support end of words.
3693 while (end > cursor && m_text.at(end - 1).isSpace())
3694 --end;
3695 moveCursor(end, true);
3696}
3697
3710bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bool edited)
3711{
3712 Q_Q(QQuickTextInput);
3713
3714 Q_UNUSED(update);
3715#if QT_CONFIG(im)
3716 bool inputMethodAttributesChanged = m_textDirty || m_selDirty;
3717#endif
3718 bool alignmentChanged = false;
3719 bool textChanged = false;
3720
3721 if (m_textDirty) {
3722 // do validation
3723 bool wasValidInput = m_validInput;
3724 bool wasAcceptable = m_acceptableInput;
3725 m_validInput = true;
3726 m_acceptableInput = true;
3727#if QT_CONFIG(validator)
3728 if (m_validator) {
3729 QString textCopy = m_text;
3730 if (m_maskData)
3731 textCopy = maskString(0, m_text, true);
3732 int cursorCopy = m_cursor;
3733 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
3734 if (m_maskData)
3735 textCopy = m_text;
3738 if (m_validInput && !m_maskData) {
3739 if (m_text != textCopy) {
3740 internalSetText(textCopy, cursorCopy);
3741 return true;
3742 }
3743 m_cursor = cursorCopy;
3744 }
3745 }
3746#endif
3747 if (m_maskData)
3748 checkIsValid();
3749
3750#if QT_CONFIG(im)
3751 // If we were during pre-edit, validateFromState should point to the state before pre-edit
3752 // has been started. Choose the correct oldest remembered state
3753 if (m_undoPreeditState >= 0 && (m_undoPreeditState < validateFromState || validateFromState < 0))
3754 validateFromState = m_undoPreeditState;
3755#endif
3756 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
3757 if (m_transactions.size())
3758 return false;
3759 internalUndo(validateFromState);
3760 m_history.resize(m_undoState);
3761 m_validInput = true;
3762 m_acceptableInput = wasAcceptable;
3763 m_textDirty = false;
3764 }
3765
3766 if (m_textDirty) {
3767 textChanged = true;
3768 m_textDirty = false;
3769#if QT_CONFIG(im)
3770 m_preeditDirty = false;
3771#endif
3772 alignmentChanged = determineHorizontalAlignment();
3773 if (edited)
3774 emit q->textEdited();
3775 emit q->textChanged();
3776 }
3777
3778 updateDisplayText(alignmentChanged);
3779
3780 if (m_acceptableInput != wasAcceptable)
3781 emit q->acceptableInputChanged();
3782 }
3783#if QT_CONFIG(im)
3784 if (m_preeditDirty) {
3785 m_preeditDirty = false;
3787 alignmentChanged = true;
3788 updateLayout();
3789 }
3790 }
3791#endif
3792
3793 if (m_selDirty) {
3794 m_selDirty = false;
3795 emit q->selectionChanged();
3796 }
3797
3798#if QT_CONFIG(im)
3799 inputMethodAttributesChanged |= (m_cursor != m_lastCursorPos);
3800 if (inputMethodAttributesChanged)
3801 q->updateInputMethod();
3802#endif
3803 emitUndoRedoChanged();
3804
3805 if (!emitCursorPositionChanged() && (alignmentChanged || textChanged))
3806 q->updateCursorRectangle();
3807
3808 return true;
3809}
3810
3816void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
3817{
3818 internalDeselect();
3819 QString oldText = m_text;
3820 if (m_maskData) {
3821 m_text = maskString(0, txt, true);
3822 m_text += clearString(m_text.size(), m_maxLength - m_text.size());
3823 } else {
3824 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
3825 }
3826 m_history.clear();
3827 m_undoState = 0;
3828#if QT_CONFIG(im)
3829 m_undoPreeditState = -1;
3830#endif
3831 m_cursor = (pos < 0 || pos > m_text.size()) ? m_text.size() : pos;
3832 m_textDirty = (oldText != m_text);
3833
3834 bool changed = finishChange(-1, true, edited);
3835#if !QT_CONFIG(accessibility)
3836 Q_UNUSED(changed);
3837#else
3838 Q_Q(QQuickTextInput);
3839 if (changed && QAccessible::isActive()) {
3840 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
3841 QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
3842 QAccessible::updateAccessibility(&ev);
3843 }
3844 }
3845#endif
3846}
3847
3848
3855void QQuickTextInputPrivate::addCommand(const Command &cmd)
3856{
3858 m_history.resize(m_undoState + 2);
3860 } else {
3861 m_history.resize(m_undoState + 1);
3862 }
3863 m_separator = false;
3864 m_history[m_undoState++] = cmd;
3865}
3866
3877void QQuickTextInputPrivate::internalInsert(const QString &s)
3878{
3879 Q_Q(QQuickTextInput);
3881 if (m_passwordMaskDelay > 0)
3883 }
3884 Q_ASSERT(!hasSelectedText()); // insert(), processInputMethodEvent() call removeSelectedText() first.
3885 if (m_maskData) {
3886 QString ms = maskString(m_cursor, s);
3887 for (int i = 0; i < ms.size(); ++i) {
3888 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
3889 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
3890 }
3891 m_text.replace(m_cursor, ms.size(), ms);
3892 m_cursor += ms.size();
3894 m_textDirty = true;
3895 } else {
3896 int remaining = m_maxLength - m_text.size();
3897 if (remaining != 0) {
3898 const QStringView remainingStr = QStringView{s}.left(remaining);
3899 m_text.insert(m_cursor, remainingStr);
3900 for (auto e : remainingStr)
3901 addCommand(Command(Insert, m_cursor++, e, -1, -1));
3902 m_textDirty = true;
3903 }
3904 }
3905}
3906
3918void QQuickTextInputPrivate::internalDelete(bool wasBackspace)
3919{
3920 if (m_cursor < m_text.size()) {
3922 Q_ASSERT(!hasSelectedText()); // del(), backspace() call removeSelectedText() first.
3923 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
3924 m_cursor, m_text.at(m_cursor), -1, -1));
3925 if (m_maskData) {
3926 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
3927 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
3928 } else {
3930 }
3931 m_textDirty = true;
3932 }
3933}
3934
3944void QQuickTextInputPrivate::removeSelectedText()
3945{
3946 if (m_selstart < m_selend && m_selend <= m_text.size()) {
3948 int i ;
3949 if (m_selstart <= m_cursor && m_cursor < m_selend) {
3950 // cursor is within the selection. Split up the commands
3951 // to be able to restore the correct cursor position
3952 for (i = m_cursor; i >= m_selstart; --i)
3953 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
3954 for (i = m_selend - 1; i > m_cursor; --i)
3955 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
3956 } else {
3957 for (i = m_selend-1; i >= m_selstart; --i)
3958 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
3959 }
3960 if (m_maskData) {
3962 for (int i = 0; i < m_selend - m_selstart; ++i)
3963 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
3964 } else {
3966 }
3967 if (m_cursor > m_selstart)
3969 internalDeselect();
3970 m_textDirty = true;
3971 }
3972}
3973
3982bool QQuickTextInputPrivate::separateSelection()
3983{
3984 if (hasSelectedText()) {
3985 separate();
3986 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
3987 return true;
3988 } else {
3989 return false;
3990 }
3991}
3992
3999void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
4000{
4001 int delimiter = maskFields.indexOf(QLatin1Char(';'));
4002 if (maskFields.isEmpty() || delimiter == 0) {
4003 if (m_maskData) {
4004 m_maskData.reset(nullptr);
4005 m_maxLength = 32767;
4006 internalSetText(QString());
4007 }
4008 return;
4009 }
4010
4011 if (delimiter == -1) {
4012 m_blank = QLatin1Char(' ');
4013 m_inputMask = maskFields;
4014 } else {
4015 m_inputMask = maskFields.left(delimiter);
4016 m_blank = (delimiter + 1 < maskFields.size()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
4017 }
4018
4019 // calculate m_maxLength / m_maskData length
4020 m_maxLength = 0;
4021 QChar c = u'\0';
4022 for (int i=0; i<m_inputMask.size(); i++) {
4023 c = m_inputMask.at(i);
4024 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
4025 m_maxLength++;
4026 continue;
4027 }
4028 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
4029 c != QLatin1Char('<') && c != QLatin1Char('>') &&
4030 c != QLatin1Char('{') && c != QLatin1Char('}') &&
4031 c != QLatin1Char('[') && c != QLatin1Char(']'))
4032 m_maxLength++;
4033 }
4034
4035 m_maskData.reset(new MaskInputData[m_maxLength]);
4036
4038 c = u'\0';
4039 bool s;
4040 bool escape = false;
4041 int index = 0;
4042 for (int i = 0; i < m_inputMask.size(); i++) {
4043 c = m_inputMask.at(i);
4044 if (escape) {
4045 s = true;
4046 m_maskData[index].maskChar = c;
4047 m_maskData[index].separator = s;
4048 m_maskData[index].caseMode = m;
4049 index++;
4050 escape = false;
4051 } else if (c == QLatin1Char('<')) {
4053 } else if (c == QLatin1Char('>')) {
4055 } else if (c == QLatin1Char('!')) {
4057 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
4058 switch (c.unicode()) {
4059 case 'A':
4060 case 'a':
4061 case 'N':
4062 case 'n':
4063 case 'X':
4064 case 'x':
4065 case '9':
4066 case '0':
4067 case 'D':
4068 case 'd':
4069 case '#':
4070 case 'H':
4071 case 'h':
4072 case 'B':
4073 case 'b':
4074 s = false;
4075 break;
4076 case '\\':
4077 escape = true;
4078 Q_FALLTHROUGH();
4079 default:
4080 s = true;
4081 break;
4082 }
4083
4084 if (!escape) {
4085 m_maskData[index].maskChar = c;
4086 m_maskData[index].separator = s;
4087 m_maskData[index].caseMode = m;
4088 index++;
4089 }
4090 }
4091 }
4092 internalSetText(m_text);
4093}
4094
4095
4101bool QQuickTextInputPrivate::isValidInput(QChar key, QChar mask) const
4102{
4103 switch (mask.unicode()) {
4104 case 'A':
4105 if (key.isLetter())
4106 return true;
4107 break;
4108 case 'a':
4109 if (key.isLetter() || key == m_blank)
4110 return true;
4111 break;
4112 case 'N':
4113 if (key.isLetterOrNumber())
4114 return true;
4115 break;
4116 case 'n':
4117 if (key.isLetterOrNumber() || key == m_blank)
4118 return true;
4119 break;
4120 case 'X':
4121 if (key.isPrint() && key != m_blank)
4122 return true;
4123 break;
4124 case 'x':
4125 if (key.isPrint() || key == m_blank)
4126 return true;
4127 break;
4128 case '9':
4129 if (key.isNumber())
4130 return true;
4131 break;
4132 case '0':
4133 if (key.isNumber() || key == m_blank)
4134 return true;
4135 break;
4136 case 'D':
4137 if (key.isNumber() && key.digitValue() > 0)
4138 return true;
4139 break;
4140 case 'd':
4141 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
4142 return true;
4143 break;
4144 case '#':
4145 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
4146 return true;
4147 break;
4148 case 'B':
4149 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
4150 return true;
4151 break;
4152 case 'b':
4153 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
4154 return true;
4155 break;
4156 case 'H':
4157 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
4158 return true;
4159 break;
4160 case 'h':
4161 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
4162 return true;
4163 break;
4164 default:
4165 break;
4166 }
4167 return false;
4168}
4169
4178QQuickTextInputPrivate::ValidatorState QQuickTextInputPrivate::hasAcceptableInput(const QString &str) const
4179{
4180#if QT_CONFIG(validator)
4181 QString textCopy = str;
4182 int cursorCopy = m_cursor;
4183 if (m_validator) {
4184 QValidator::State state = m_validator->validate(textCopy, cursorCopy);
4186 return ValidatorState(state);
4187 }
4188#endif
4189
4190 if (!m_maskData)
4191 return AcceptableInput;
4192
4193 if (str.size() != m_maxLength)
4194 return InvalidInput;
4195
4196 for (int i=0; i < m_maxLength; ++i) {
4197 if (m_maskData[i].separator) {
4198 if (str.at(i) != m_maskData[i].maskChar)
4199 return InvalidInput;
4200 } else {
4201 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
4202 return InvalidInput;
4203 }
4204 }
4205 return AcceptableInput;
4206}
4207
4216QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool clear) const
4217{
4218 if (pos >= (uint)m_maxLength)
4219 return QString::fromLatin1("");
4220
4221 QString fill;
4222 fill = clear ? clearString(0, m_maxLength) : m_text;
4223
4224 int strIndex = 0;
4226 int i = pos;
4227 while (i < m_maxLength) {
4228 if (strIndex < str.size()) {
4229 if (m_maskData[i].separator) {
4230 s += m_maskData[i].maskChar;
4231 if (str[strIndex] == m_maskData[i].maskChar)
4232 strIndex++;
4233 ++i;
4234 } else {
4235 if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
4236 switch (m_maskData[i].caseMode) {
4238 s += str[strIndex].toUpper();
4239 break;
4241 s += str[strIndex].toLower();
4242 break;
4243 default:
4244 s += str[strIndex];
4245 }
4246 ++i;
4247 } else {
4248 // search for separator first
4249 int n = findInMask(i, true, true, str[strIndex]);
4250 if (n != -1) {
4251 if (str.size() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
4252 s += QStringView{fill}.mid(i, n-i+1);
4253 i = n + 1; // update i to find + 1
4254 }
4255 } else {
4256 // search for valid m_blank if not
4257 n = findInMask(i, true, false, str[strIndex]);
4258 if (n != -1) {
4259 s += QStringView{fill}.mid(i, n-i);
4260 switch (m_maskData[n].caseMode) {
4262 s += str[strIndex].toUpper();
4263 break;
4265 s += str[strIndex].toLower();
4266 break;
4267 default:
4268 s += str[strIndex];
4269 }
4270 i = n + 1; // updates i to find + 1
4271 }
4272 }
4273 }
4274 ++strIndex;
4275 }
4276 } else
4277 break;
4278 }
4279
4280 return s;
4281}
4282
4283
4284
4291QString QQuickTextInputPrivate::clearString(uint pos, uint len) const
4292{
4293 if (pos >= (uint)m_maxLength)
4294 return QString();
4295
4296 QString s;
4297 int end = qMin((uint)m_maxLength, pos + len);
4298 for (int i = pos; i < end; ++i)
4299 if (m_maskData[i].separator)
4300 s += m_maskData[i].maskChar;
4301 else
4302 s += m_blank;
4303
4304 return s;
4305}
4306
4313QString QQuickTextInputPrivate::stripString(const QString &str) const
4314{
4315 if (!m_maskData)
4316 return str;
4317
4318 QString s;
4319 int end = qMin(m_maxLength, str.size());
4320 for (int i = 0; i < end; ++i) {
4321 if (m_maskData[i].separator)
4322 s += m_maskData[i].maskChar;
4323 else if (str[i] != m_blank)
4324 s += str[i];
4325 }
4326
4327 return s;
4328}
4329
4334int QQuickTextInputPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
4335{
4336 if (pos >= m_maxLength || pos < 0)
4337 return -1;
4338
4339 int end = forward ? m_maxLength : -1;
4340 int step = forward ? 1 : -1;
4341 int i = pos;
4342
4343 while (i != end) {
4344 if (findSeparator) {
4345 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
4346 return i;
4347 } else {
4348 if (!m_maskData[i].separator) {
4349 if (searchChar.isNull())
4350 return i;
4351 else if (isValidInput(searchChar, m_maskData[i].maskChar))
4352 return i;
4353 }
4354 }
4355 i += step;
4356 }
4357 return -1;
4358}
4359
4360void QQuickTextInputPrivate::internalUndo(int until)
4361{
4362 if (!isUndoAvailable())
4363 return;
4365 internalDeselect();
4366 while (m_undoState && m_undoState > until) {
4367 Command& cmd = m_history[--m_undoState];
4368 switch (cmd.type) {
4369 case Insert:
4370 m_text.remove(cmd.pos, 1);
4371 m_cursor = cmd.pos;
4372 break;
4373 case SetSelection:
4374 m_selstart = cmd.selStart;
4375 m_selend = cmd.selEnd;
4376 m_cursor = cmd.pos;
4377 break;
4378 case Remove:
4379 case RemoveSelection:
4380 m_text.insert(cmd.pos, cmd.uc);
4381 m_cursor = cmd.pos + 1;
4382 break;
4383 case Delete:
4384 case DeleteSelection:
4385 m_text.insert(cmd.pos, cmd.uc);
4386 m_cursor = cmd.pos;
4387 break;
4388 case Separator:
4389 continue;
4390 }
4391 if (until < 0 && m_undoState) {
4392 Command& next = m_history[m_undoState-1];
4393 if (next.type != cmd.type
4394 && next.type < RemoveSelection
4395 && (cmd.type < RemoveSelection || next.type == Separator)) {
4396 break;
4397 }
4398 }
4399 }
4400 separate();
4401 m_textDirty = true;
4402}
4403
4404void QQuickTextInputPrivate::internalRedo()
4405{
4406 if (!isRedoAvailable())
4407 return;
4408 internalDeselect();
4409 while (m_undoState < m_history.size()) {
4410 Command& cmd = m_history[m_undoState++];
4411 switch (cmd.type) {
4412 case Insert:
4413 m_text.insert(cmd.pos, cmd.uc);
4414 m_cursor = cmd.pos + 1;
4415 break;
4416 case SetSelection:
4417 m_selstart = cmd.selStart;
4418 m_selend = cmd.selEnd;
4419 m_cursor = cmd.pos;
4420 break;
4421 case Remove:
4422 case Delete:
4423 case RemoveSelection:
4424 case DeleteSelection:
4425 m_text.remove(cmd.pos, 1);
4426 m_selstart = cmd.selStart;
4427 m_selend = cmd.selEnd;
4428 m_cursor = cmd.pos;
4429 break;
4430 case Separator:
4431 m_selstart = cmd.selStart;
4432 m_selend = cmd.selEnd;
4433 m_cursor = cmd.pos;
4434 break;
4435 }
4436 if (m_undoState < m_history.size()) {
4437 Command& next = m_history[m_undoState];
4438 if (next.type != cmd.type
4439 && cmd.type < RemoveSelection
4440 && next.type != Separator
4441 && (next.type < RemoveSelection || cmd.type == Separator)) {
4442 break;
4443 }
4444 }
4445 }
4446 m_textDirty = true;
4447}
4448
4449void QQuickTextInputPrivate::emitUndoRedoChanged()
4450{
4451 Q_Q(QQuickTextInput);
4452 const bool previousUndo = canUndo;
4453 const bool previousRedo = canRedo;
4454
4457
4458 if (previousUndo != canUndo)
4459 emit q->canUndoChanged();
4460 if (previousRedo != canRedo)
4461 emit q->canRedoChanged();
4462}
4463
4470bool QQuickTextInputPrivate::emitCursorPositionChanged()
4471{
4472 Q_Q(QQuickTextInput);
4473 if (m_cursor != m_lastCursorPos) {
4475
4476 q->updateCursorRectangle();
4477 emit q->cursorPositionChanged();
4478
4479 if (!hasSelectedText()) {
4482 emit q->selectionStartChanged();
4483 }
4484 if (lastSelectionEnd != m_cursor) {
4486 emit q->selectionEndChanged();
4487 }
4488 }
4489
4490#if QT_CONFIG(accessibility)
4491 if (QAccessible::isActive()) {
4492 if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
4493 QAccessibleTextCursorEvent ev(acc, m_cursor);
4494 QAccessible::updateAccessibility(&ev);
4495 }
4496 }
4497#endif
4498
4499 return true;
4500 }
4501 return false;
4502}
4503
4504
4518
4520{
4521 Q_Q(QQuickTextInput);
4522
4523 if (m_blinkTimer) {
4524 q->killTimer(m_blinkTimer);
4525 m_blinkTimer = 0;
4526 }
4527
4529 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
4530 if (flashTime >= 2)
4531 m_blinkTimer = q->startTimer(flashTime / 2);
4532 }
4533
4534 m_blinkStatus = 1;
4536 q->polish();
4537 q->update();
4538}
4539
4541{
4542 Q_D(QQuickTextInput);
4543 if (event->timerId() == d->m_blinkTimer) {
4544 d->m_blinkStatus = !d->m_blinkStatus;
4546 polish();
4547 update();
4548 } else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
4549 d->m_passwordEchoTimer.stop();
4550 d->updateDisplayText();
4551 updateCursorRectangle();
4552 }
4553}
4554
4556{
4557 Q_Q(QQuickTextInput);
4558
4559 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
4560 if (hasAcceptableInput(m_text) == AcceptableInput || fixup()) {
4561
4563 inputMethod->commit();
4564
4565 if (activeFocus) {
4566 // If we lost focus after hiding the virtual keyboard, we've already emitted
4567 // editingFinished from handleFocusEvent. Otherwise we emit it now.
4568 emit q->editingFinished();
4569 }
4570
4571 emit q->accepted();
4572 }
4573 event->ignore();
4574 return;
4575 }
4576
4577 if (m_blinkEnabled)
4579
4582 && !m_readOnly
4583 && !event->text().isEmpty()
4584 && !(event->modifiers() & Qt::ControlModifier)) {
4585 // Clear the edit and reset to normal echo mode while editing; the
4586 // echo mode switches back when the edit loses focus
4587 // ### resets current content. dubious code; you can
4588 // navigate with keys up, down, back, and select(?), but if you press
4589 // "left" or "right" it clears?
4591 clear();
4592 }
4593
4594 bool unknown = false;
4595#if QT_CONFIG(shortcut)
4596 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
4597#endif
4598
4599 if (false) {
4600 }
4601#if QT_CONFIG(shortcut)
4602 else if (event == QKeySequence::Undo) {
4603 q->undo();
4604 }
4605 else if (event == QKeySequence::Redo) {
4606 q->redo();
4607 }
4608 else if (event == QKeySequence::SelectAll) {
4609 selectAll();
4610 }
4611#if QT_CONFIG(clipboard)
4612 else if (event == QKeySequence::Copy) {
4613 copy();
4614 }
4615 else if (event == QKeySequence::Paste) {
4616 if (!m_readOnly) {
4618 paste(mode);
4619 }
4620 }
4621 else if (event == QKeySequence::Cut) {
4622 q->cut();
4623 }
4625 if (!m_readOnly)
4626 deleteEndOfLine();
4627 }
4628#endif // clipboard
4630 home(0);
4631 }
4633 end(0);
4634 }
4636 home(1);
4637 }
4639 end(1);
4640 }
4641 else if (event == QKeySequence::MoveToNextChar) {
4642 if (hasSelectedText()) {
4643 moveCursor(selectionEnd(), false);
4644 } else {
4645 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4646 }
4647 }
4648 else if (event == QKeySequence::SelectNextChar) {
4649 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
4650 }
4652 if (hasSelectedText()) {
4653 moveCursor(selectionStart(), false);
4654 } else {
4655 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4656 }
4657 }
4659 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
4660 }
4661 else if (event == QKeySequence::MoveToNextWord) {
4664 else
4665 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
4666 }
4670 else if (!m_readOnly) {
4671 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
4672 }
4673 }
4674 else if (event == QKeySequence::SelectNextWord) {
4677 else
4678 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
4679 }
4683 else
4684 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
4685 }
4686 else if (event == QKeySequence::Delete) {
4687 if (!m_readOnly)
4688 del();
4689 }
4691 if (!m_readOnly)
4692 deleteEndOfWord();
4693 }
4695 if (!m_readOnly)
4696 deleteStartOfWord();
4698 if (!m_readOnly) {
4699 selectAll();
4700#if QT_CONFIG(clipboard)
4701 copy();
4702#endif
4703 del();
4704 }
4705 }
4706#endif // shortcut
4707 else {
4708 bool handled = false;
4709 if (event->modifiers() & Qt::ControlModifier) {
4710 switch (event->key()) {
4711 case Qt::Key_Backspace:
4712 if (!m_readOnly)
4713 deleteStartOfWord();
4714 break;
4715 default:
4716 if (!handled)
4717 unknown = true;
4718 }
4719 } else { // ### check for *no* modifier
4720 switch (event->key()) {
4721 case Qt::Key_Backspace:
4722 if (!m_readOnly) {
4723 backspace();
4724 }
4725 break;
4726 default:
4727 if (!handled)
4728 unknown = true;
4729 }
4730 }
4731 }
4732
4733 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
4735 unknown = false;
4736 }
4737
4738 if (unknown && !m_readOnly) {
4740 if (overwriteMode
4741 // no need to call del() if we have a selection, insert
4742 // does it already
4743 && !hasSelectedText()
4744 && !(m_cursor == q_func()->text().size())) {
4745 del();
4746 }
4747
4748 insert(event->text());
4749 event->accept();
4750 return;
4751 }
4752 }
4753
4754 if (unknown)
4755 event->ignore();
4756 else
4757 event->accept();
4758}
4759
4766void QQuickTextInputPrivate::deleteStartOfWord()
4767{
4768 int priorState = m_undoState;
4769 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4770 separate();
4771 cursorWordBackward(true);
4772 addCommand(cmd);
4773 removeSelectedText();
4774 finishChange(priorState);
4775}
4776
4783void QQuickTextInputPrivate::deleteEndOfWord()
4784{
4785 int priorState = m_undoState;
4786 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4787 separate();
4788 cursorWordForward(true);
4789 // moveCursor (sometimes) calls separate() so we need to add the command after that so the
4790 // cursor position and selection are restored in the same undo operation as the remove.
4791 addCommand(cmd);
4792 removeSelectedText();
4793 finishChange(priorState);
4794}
4795
4802void QQuickTextInputPrivate::deleteEndOfLine()
4803{
4804 int priorState = m_undoState;
4805 Command cmd(SetSelection, m_cursor, u'\0', m_selstart, m_selend);
4806 separate();
4808 addCommand(cmd);
4809 removeSelectedText();
4810 finishChange(priorState);
4811}
4812
4822void QQuickTextInput::ensureVisible(int position)
4823{
4824 Q_D(QQuickTextInput);
4825 d->ensureVisible(position);
4826 updateCursorRectangle(false);
4827}
4828
4840void QQuickTextInput::clear()
4841{
4842 Q_D(QQuickTextInput);
4843 d->cancelInput();
4844 d->clear();
4845}
4846
4871{
4872 Q_D(const QQuickTextInput);
4873 return d->padding();
4874}
4875
4877{
4878 Q_D(QQuickTextInput);
4879 if (qFuzzyCompare(d->padding(), padding))
4880 return;
4881
4882 d->extra.value().padding = padding;
4883 d->updateLayout();
4884 updateCursorRectangle();
4885 emit paddingChanged();
4886 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
4887 emit topPaddingChanged();
4888 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
4889 emit leftPaddingChanged();
4890 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
4891 emit rightPaddingChanged();
4892 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
4893 emit bottomPaddingChanged();
4894}
4895
4897{
4898 setPadding(0);
4899}
4900
4902{
4903 Q_D(const QQuickTextInput);
4904 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
4905 return d->extra->topPadding;
4906 return d->padding();
4907}
4908
4910{
4911 Q_D(QQuickTextInput);
4912 d->setTopPadding(padding);
4913}
4914
4916{
4917 Q_D(QQuickTextInput);
4918 d->setTopPadding(0, true);
4919}
4920
4922{
4923 Q_D(const QQuickTextInput);
4924 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
4925 return d->extra->leftPadding;
4926 return d->padding();
4927}
4928
4930{
4931 Q_D(QQuickTextInput);
4932 d->setLeftPadding(padding);
4933}
4934
4936{
4937 Q_D(QQuickTextInput);
4938 d->setLeftPadding(0, true);
4939}
4940
4942{
4943 Q_D(const QQuickTextInput);
4944 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
4945 return d->extra->rightPadding;
4946 return d->padding();
4947}
4948
4950{
4951 Q_D(QQuickTextInput);
4952 d->setRightPadding(padding);
4953}
4954
4956{
4957 Q_D(QQuickTextInput);
4958 d->setRightPadding(0, true);
4959}
4960
4962{
4963 Q_D(const QQuickTextInput);
4964 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
4965 return d->extra->bottomPadding;
4966 return d->padding();
4967}
4968
4970{
4971 Q_D(QQuickTextInput);
4972 d->setBottomPadding(padding);
4973}
4974
4976{
4977 Q_D(QQuickTextInput);
4978 d->setBottomPadding(0, true);
4979}
4980
4981#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
4982void QQuickTextInput::setOldSelectionDefault()
4983{
4984 Q_D(QQuickTextInput);
4985 d->selectByMouse = false;
4986 d->selectByTouchDrag = true;
4987 qCDebug(lcQuickTextInput, "pre-6.4 behavior chosen: selectByMouse defaults false; if enabled, touchscreen acts like a mouse");
4988}
4989
4990// TODO in 6.7.0: remove the note about versions prior to 6.4 in selectByMouse() documentation
4991QQuickPre64TextInput::QQuickPre64TextInput(QQuickItem *parent)
4993{
4994 setOldSelectionDefault();
4995}
4996#endif
4997
4999
5000#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
The QClipboard class provides access to the window system clipboard.
Definition qclipboard.h:20
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
void accept()
Sets the accept flag of the event object, the equivalent of calling setAccepted(true).
Definition qcoreevent.h:310
The QFocusEvent class contains event parameters for widget focus events.
Definition qevent.h:470
\reentrant \inmodule QtGui
\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:22
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:625
The QInputMethod class provides access to the active text input method.
void commit()
Commits the word user is currently composing to the editor.
The QKeyEvent class describes a key event.
Definition qevent.h:424
static constexpr Policy Preferred
static constexpr Policy Fixed
qsizetype size() const noexcept
Definition qlist.h:397
qsizetype length() const noexcept
Definition qlist.h:399
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.
QString text() const
Returns a plain text (MIME type text/plain) representation of the data.
\inmodule QtGui
Definition qevent.h:196
QObject * parent
Definition qobject.h:73
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:299
\inmodule QtCore
Definition qobject.h:103
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:1389
\inmodule QtCore\reentrant
Definition qpoint.h:217
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:338
\inmodule QtCore\reentrant
Definition qpoint.h:25
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)
void setSizePolicy(const QLayoutPolicy::Policy &horizontalPolicy, const QLayoutPolicy::Policy &verticalPolicy)
QString state() const
QQuickAnchorLine top() const
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
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:72
qreal y
Defines the item's y position relative to its parent.
Definition qquickitem.h:73
bool hasActiveFocus() const
QSizeF size() const
virtual void itemChange(ItemChange, const ItemChangeData &)
Called when change occurs for this item.
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::...
bool smooth
\qmlproperty bool QtQuick::Item::smooth
Definition qquickitem.h:112
virtual QRectF clipRect() const
Returns the rectangular area within this item that is currently visible in \l viewportItem(),...
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:144
@ ItemDevicePixelRatioHasChanged
Definition qquickitem.h:154
virtual void focusInEvent(QFocusEvent *)
This event handler can be reimplemented in a subclass to receive focus-in events for an item.
@ ItemObservesViewport
Definition qquickitem.h:138
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)
void itemChange(ItemChange change, const ItemChangeData &value) override
Called when change occurs for this item.
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
Q_INVOKABLE void positionAt(QQmlV4FunctionPtr args) const
\qmlmethod int QtQuick::TextInput::positionAt(real x, real y, CursorPosition position)
void setWrapMode(WrapMode w)
void fontChanged(const QFont &font)
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)
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:484
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:498
void setSelectionTextColor(QColor selectionTextColor) override
Sets the color of the selection text to selectionTextColor when any part of the text is marked as sel...
void setTextStyle(TextStyle textStyle) override
Sets the style of the rendered text to textStyle.
void clear() override
Clears the contents of the node, deleting nodes and other data that represents the layouts and docume...
void setFiltering(QSGTexture::Filtering filtering) override
Sets the sampling mode used when scaling images that are part of the displayed text to filtering.
void setRenderType(RenderType renderType) override
Sets the type of glyph node in use to renderType.
void setColor(QColor color) override
Sets the main color to use when rendering the text to color.
void setViewport(const QRectF &viewport) override
Sets the bounding rect of the viewport where the text is displayed to viewport.
void setSelectionColor(QColor selectionColor) override
Sets the color of the selection background to color when any part of the text is marked as selected.
void setCursor(const QRectF &rect, const QColor &color)
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
void addTextLayout(QPointF position, QTextLayout *layout, int selectionStart=-1, int selectionCount=-1, int lineStart=0, int lineCount=-1)
Adds the contents of layout to the text node at position.
Definition qsgtextnode.h:67
RenderType
This enum type describes type of glyph node used for rendering the text.
Definition qsgtextnode.h:29
void setMatrix(const QMatrix4x4 &matrix)
Sets this transform node's matrix to matrix.
Definition qsgnode.cpp:1162
\inmodule QtCore
Definition qsize.h:208
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:335
\inmodule QtCore
Definition qstringview.h:78
constexpr QStringView left(qsizetype n) const noexcept
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:296
QString & fill(QChar c, qsizetype size=-1)
Sets every character in the string to character ch.
Definition qstring.cpp:6358
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1246
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
QString & insert(qsizetype i, QChar c)
Definition qstring.cpp:3132
QString toLower() const &
Definition qstring.h:435
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1240
QString & append(QChar c)
Definition qstring.cpp:3252
bool isRightToLeft() const
Returns true if the string is read right to left.
Definition qstring.cpp:9307
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:3466
QString toUpper() const &
Definition qstring.h:439
void cursorFlashTimeChanged(int cursorFlashTime)
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:366
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:65
QString str
[2]
QString text
QCursor cursor
void textChanged(const QString &newText)
rect
[4]
uint alignment
direction
short next
Definition keywords.cpp:445
EGLint EGLint * formats
Combined button and popup list for selecting options.
Definition qcompare.h:63
InputMethodQuery
@ ImMaximumTextLength
@ ImTextBeforeCursor
@ ImAnchorRectangle
@ ImSurroundingText
@ ImCursorPosition
@ ImEnterKeyType
@ ImCurrentSelection
@ ImAbsolutePosition
@ ImReadOnly
@ ImFont
@ ImAnchorPosition
@ ImCursorRectangle
@ ImHints
@ ImEnabled
@ ImTextAfterCursor
@ AlignHorizontal_Mask
Definition qnamespace.h:151
@ AlignAbsolute
Definition qnamespace.h:150
@ LeftButton
Definition qnamespace.h:58
@ MiddleButton
Definition qnamespace.h:60
LayoutDirection
@ LeftToRight
@ LayoutDirectionAuto
@ RightToLeft
@ ImhNone
@ ImhNoPredictiveText
@ ImhSensitiveData
@ ImhHiddenText
@ ImhNoAutoUppercase
@ Key_Escape
Definition qnamespace.h:663
@ Key_Return
Definition qnamespace.h:667
@ Key_Right
Definition qnamespace.h:679
@ Key_Enter
Definition qnamespace.h:668
@ Key_Backspace
Definition qnamespace.h:666
@ Key_Direction_L
Definition qnamespace.h:731
@ Key_Left
Definition qnamespace.h:677
@ Key_Up
Definition qnamespace.h:678
@ Key_Down
Definition qnamespace.h:680
@ Key_Delete
Definition qnamespace.h:670
@ Key_Direction_R
Definition qnamespace.h:732
@ Key_Home
Definition qnamespace.h:675
@ Key_End
Definition qnamespace.h:676
@ 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:333
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define qGuiApp
#define qWarning
Definition qlogging.h:166
#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:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
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
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLfloat GLfloat f
GLint GLsizei width
GLuint color
[2]
GLenum type
GLint GLint bottom
GLboolean enable
GLuint start
GLenum GLuint GLintptr offset
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLint y
struct _cl_event * event
GLdouble s
[6]
Definition qopenglext.h:235
GLboolean reset
GLuint res
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint GLenum option
GLenum GLsizei len
#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
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
#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:34
double qreal
Definition qtypes.h:187
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:18
\inmodule QtQuick
Definition qquickitem.h:159