Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquicktextarea.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 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// Qt-Security score:significant reason:default
4
12
13#include <QtQml/qqmlinfo.h>
14#include <QtQuick/private/qquickitem_p.h>
15#include <QtQuick/private/qquickclipnode_p.h>
16#include <QtQuick/private/qquickflickable_p.h>
17
18#if QT_CONFIG(accessibility)
19#include <QtQuick/private/qquickaccessibleattached_p.h>
20#endif
21
23
24using namespace Qt::StringLiterals;
25
26/*!
27 \qmltype TextArea
28 \inherits TextEdit
29//! \nativetype QQuickTextArea
30 \inqmlmodule QtQuick.Controls
31 \since 5.7
32 \ingroup qtquickcontrols-input
33 \brief Multi-line text input area.
34
35 TextArea is a multi-line text editor. TextArea extends TextEdit with
36 a \l {placeholderText}{placeholder text} functionality, and adds decoration.
37
38 \image qtquickcontrols-textarea.png
39 {Text area for multiline text input}
40
41 \code
42 TextArea {
43 placeholderText: qsTr("Enter description")
44 }
45 \endcode
46
47 TextArea is not scrollable by itself. Especially on screen-size constrained
48 platforms, it is often preferable to make entire application pages scrollable.
49 On such a scrollable page, a non-scrollable TextArea might behave better than
50 nested scrollable controls. Notice, however, that in such a scenario, the background
51 decoration of the TextArea scrolls together with the rest of the scrollable
52 content.
53
54 \section2 Scrollable TextArea
55
56 If you want to make a TextArea scrollable, for example, when it covers
57 an entire application page, it can be placed inside a \l ScrollView.
58
59 \image qtquickcontrols-textarea-scrollable.png
60 {Scrollable text area with scroll bars}
61
62 \snippet qtquickcontrols-textarea-scrollable.qml 1
63
64 A TextArea that is placed inside a \l ScrollView does the following:
65
66 \list
67 \li Sets the content size automatically
68 \li Ensures that the background decoration stays in place
69 \li Clips the content
70 \endlist
71
72 \section2 Tab Focus
73
74 By default, pressing the tab key while TextArea has
75 \l {Item::activeFocus}{active focus} results in a tab character being input
76 into the control itself. To make tab pass active focus onto another item,
77 use the attached \l KeyNavigation properties:
78
79 \code
80 TextField {
81 id: textField
82 }
83
84 TextArea {
85 KeyNavigation.priority: KeyNavigation.BeforeItem
86 KeyNavigation.tab: textField
87 }
88 \endcode
89
90 \sa TextField, {Customizing TextArea}, {Input Controls}
91*/
92
93/*!
94 \qmlsignal QtQuick.Controls::TextArea::pressAndHold(MouseEvent event)
95
96 This signal is emitted when there is a long press (the delay depends on the platform plugin).
97 The \a event parameter provides information about the press, including the x and y
98 coordinates of the press, and which button is pressed.
99
100 \sa pressed, released
101*/
102
103/*!
104 \qmlsignal QtQuick.Controls::TextArea::pressed(MouseEvent event)
105 \since QtQuick.Controls 2.1 (Qt 5.8)
106
107 This signal is emitted when the text area is pressed by the user.
108 The \a event parameter provides information about the press,
109 including the x and y coordinates of the press, and which button is pressed.
110
111 \sa released, pressAndHold
112*/
113
114/*!
115 \qmlsignal QtQuick.Controls::TextArea::released(MouseEvent event)
116 \since QtQuick.Controls 2.1 (Qt 5.8)
117
118 This signal is emitted when the text area is released by the user.
119 The \a event parameter provides information about the release,
120 including the x and y coordinates of the press, and which button
121 is pressed.
122
123 \sa pressed, pressAndHold
124*/
125
126QQuickTextAreaPrivate::QQuickTextAreaPrivate()
127{
128#if QT_CONFIG(accessibility)
129 setAccessible();
130#endif
131}
132
136
137void QQuickTextAreaPrivate::setTopInset(qreal value, bool reset)
138{
139 Q_Q(QQuickTextArea);
140 const QMarginsF oldInset = getInset();
141 extra.value().topInset = value;
142 extra.value().hasTopInset = !reset;
143 if (!qFuzzyCompare(oldInset.top(), value)) {
144 emit q->topInsetChanged();
145 q->insetChange(getInset(), oldInset);
146 }
147}
148
149void QQuickTextAreaPrivate::setLeftInset(qreal value, bool reset)
150{
151 Q_Q(QQuickTextArea);
152 const QMarginsF oldInset = getInset();
153 extra.value().leftInset = value;
154 extra.value().hasLeftInset = !reset;
155 if (!qFuzzyCompare(oldInset.left(), value)) {
156 emit q->leftInsetChanged();
157 q->insetChange(getInset(), oldInset);
158 }
159}
160
161void QQuickTextAreaPrivate::setRightInset(qreal value, bool reset)
162{
163 Q_Q(QQuickTextArea);
164 const QMarginsF oldInset = getInset();
165 extra.value().rightInset = value;
166 extra.value().hasRightInset = !reset;
167 if (!qFuzzyCompare(oldInset.right(), value)) {
168 emit q->rightInsetChanged();
169 q->insetChange(getInset(), oldInset);
170 }
171}
172
173void QQuickTextAreaPrivate::setBottomInset(qreal value, bool reset)
174{
175 Q_Q(QQuickTextArea);
176 const QMarginsF oldInset = getInset();
177 extra.value().bottomInset = value;
178 extra.value().hasBottomInset = !reset;
179 if (!qFuzzyCompare(oldInset.bottom(), value)) {
180 emit q->bottomInsetChanged();
181 q->insetChange(getInset(), oldInset);
182 }
183}
184
186{
187 if (!background)
188 return;
189
190 resizingBackground = true;
191
192 // When using the attached property TextArea.flickable, we reparent the background out
193 // of TextArea and into the Flickable since we don't want the background to move while
194 // flicking. This means that the size of the background should also follow the size of
195 // the Flickable rather than the size of the TextArea.
196 const auto flickable = qobject_cast<QQuickFlickable *>(background->parentItem());
197
198 QQuickItemPrivate *p = QQuickItemPrivate::get(background);
199 if (((!p->widthValid() || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(background->x()))
200 || (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) {
201 const qreal bgWidth = flickable ? flickable->width() : width;
202 background->setX(getLeftInset());
203 background->setWidth(bgWidth - getLeftInset() - getRightInset());
204 }
205
206 if (((!p->heightValid() || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y()))
207 || (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) {
208 const qreal bgHeight = flickable ? flickable->height() : height;
209 background->setY(getTopInset());
210 background->setHeight(bgHeight - getTopInset() - getBottomInset());
211 }
212
213 resizingBackground = false;
214}
215
216/*!
217 \internal
218
219 Determine which font is implicitly imposed on this control by its ancestors
220 and QGuiApplication::font, resolve this against its own font (attributes from
221 the implicit font are copied over). Then propagate this font to this
222 control's children.
223*/
225{
226 Q_Q(QQuickTextArea);
227 inheritFont(QQuickControlPrivate::parentFont(q));
228}
229
230void QQuickTextAreaPrivate::inheritFont(const QFont &font)
231{
232 QFont parentFont = extra.isAllocated() ? extra->requestedFont.resolve(font) : font;
233 parentFont.setResolveMask(extra.isAllocated() ? extra->requestedFont.resolveMask() | font.resolveMask() : font.resolveMask());
234
235 const QFont defaultFont = QQuickTheme::font(QQuickTheme::TextArea);
236 QFont resolvedFont = parentFont.resolve(defaultFont);
237
238 setFont_helper(resolvedFont);
239}
240
241/*!
242 \internal
243
244 Assign \a font to this control, and propagate it to all children.
245*/
246void QQuickTextAreaPrivate::updateFont(const QFont &font)
247{
248 Q_Q(QQuickTextArea);
249 QFont oldFont = sourceFont;
250 q->QQuickTextEdit::setFont(font);
251
252 QQuickControlPrivate::updateFontRecur(q, font);
253
254 if (oldFont != font)
255 emit q->fontChanged();
256}
257
258#if QT_CONFIG(quicktemplates2_hover)
259void QQuickTextAreaPrivate::updateHoverEnabled(bool enabled, bool xplicit)
260{
261 Q_Q(QQuickTextArea);
262 if (!xplicit && explicitHoverEnabled)
263 return;
264
265 bool wasEnabled = q->isHoverEnabled();
266 explicitHoverEnabled = xplicit;
267 if (wasEnabled != enabled) {
268 q->setAcceptHoverEvents(enabled);
269 QQuickControlPrivate::updateHoverEnabledRecur(q, enabled);
270 emit q->hoverEnabledChanged();
271 }
272}
273#endif
274
275void QQuickTextAreaPrivate::attachFlickable(QQuickFlickable *item)
276{
277 Q_Q(QQuickTextArea);
278 flickable = item;
279 q->setParentItem(flickable->contentItem());
280
281 if (background)
282 background->setParentItem(flickable);
283
284 QObjectPrivate::connect(q, &QQuickTextArea::contentSizeChanged, this, &QQuickTextAreaPrivate::resizeFlickableContent);
285 QObjectPrivate::connect(q, &QQuickTextEdit::cursorRectangleChanged, this, &QQuickTextAreaPrivate::ensureCursorVisible);
286
287 QObject::connect(flickable, &QQuickFlickable::contentXChanged, q, &QQuickItem::update);
288 QObject::connect(flickable, &QQuickFlickable::contentYChanged, q, &QQuickItem::update);
289
290 QQuickItemPrivate::get(flickable)->updateOrAddGeometryChangeListener(this, QQuickGeometryChange::Size);
291 QQuickItemPrivate::get(flickable)->addItemChangeListener(this, QQuickItemPrivate::Destroyed);
292 QObjectPrivate::connect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
293 QObjectPrivate::connect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
294
296}
297
299{
300 Q_Q(QQuickTextArea);
301 q->setParentItem(nullptr);
302 if (background && background->parentItem() == flickable)
303 background->setParentItem(q);
304
305 QObjectPrivate::disconnect(q, &QQuickTextArea::contentSizeChanged, this, &QQuickTextAreaPrivate::resizeFlickableContent);
306 QObjectPrivate::disconnect(q, &QQuickTextEdit::cursorRectangleChanged, this, &QQuickTextAreaPrivate::ensureCursorVisible);
307
308 QObject::disconnect(flickable, &QQuickFlickable::contentXChanged, q, &QQuickItem::update);
309 QObject::disconnect(flickable, &QQuickFlickable::contentYChanged, q, &QQuickItem::update);
310
311 QQuickItemPrivate::get(flickable)->updateOrRemoveGeometryChangeListener(this, QQuickGeometryChange::Nothing);
312 QQuickItemPrivate::get(flickable)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed);
313 QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
314 QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
315
316 flickable = nullptr;
317
319}
320
322{
323 Q_Q(QQuickTextArea);
324 if (!flickable)
325 return;
326
327 const qreal cx = flickable->contentX();
328 const qreal cy = flickable->contentY();
329 const qreal w = flickable->width();
330 const qreal h = flickable->height();
331
332 const qreal tp = q->topPadding();
333 const qreal lp = q->leftPadding();
334 const QRectF cr = q->cursorRectangle();
335
336 if (cr.left() <= cx + lp) {
337 flickable->setContentX(cr.left() - lp);
338 } else {
339 // calculate the rectangle of the next character and ensure that
340 // it's visible if it's on the same line with the cursor
341 const qreal rp = q->rightPadding();
342 const QRectF nr = q->cursorPosition() < q->length() ? q->positionToRectangle(q->cursorPosition() + 1) : QRectF();
343 if (qFuzzyCompare(nr.y(), cr.y()) && nr.right() >= cx + lp + w - rp)
344 flickable->setContentX(nr.right() - w + rp);
345 else if (cr.right() >= cx + lp + w - rp)
346 flickable->setContentX(cr.right() - w + rp);
347 }
348
349 if (cr.top() <= cy + tp) {
350 flickable->setContentY(cr.top() - tp);
351 } else {
352 const qreal bp = q->bottomPadding();
353 if (cr.bottom() >= cy + tp + h - bp && cr.bottom() <= flickable->contentHeight())
354 flickable->setContentY(cr.bottom() - h + bp);
355 }
356}
357
359{
360 Q_Q(QQuickTextArea);
361 if (!flickable)
362 return;
363
364 const qreal w = wrapMode == QQuickTextArea::NoWrap ? qMax(flickable->width(), flickable->contentWidth()) : flickable->width();
365 const qreal h = qMax(flickable->height(), flickable->contentHeight());
366 q->setSize(QSizeF(w, h));
367
369}
370
372{
373 Q_Q(QQuickTextArea);
374 if (!flickable)
375 return;
376
377 flickable->setContentWidth(q->implicitWidth());
378 flickable->setContentHeight(q->implicitHeight());
379}
380
381void QQuickTextAreaPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
382{
383 Q_UNUSED(diff);
384 if (!resizingBackground && item == background) {
385 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
386 // Only set hasBackgroundWidth/Height if it was a width/height change,
387 // otherwise we're prevented from setting a width/height in the future.
388 if (change.widthChange())
389 extra.value().hasBackgroundWidth = p->widthValid();
390 if (change.heightChange())
391 extra.value().hasBackgroundHeight = p->heightValid();
392 }
393
394 if (flickable)
396 else
398}
399
401{
402 return QQuickItemPrivate::getImplicitWidth();
403}
404
406{
407 return QQuickItemPrivate::getImplicitHeight();
408}
409
411{
412 Q_Q(QQuickTextArea);
413 QQuickItemPrivate::implicitWidthChanged();
414 emit q->implicitWidthChanged3();
415}
416
418{
419 Q_Q(QQuickTextArea);
420 QQuickItemPrivate::implicitHeightChanged();
421 emit q->implicitHeightChanged3();
422}
423
424#if QT_CONFIG(accessibility)
425void QQuickTextAreaPrivate::accessibilityActiveChanged(bool active)
426{
427 QQuickTextEditPrivate::accessibilityActiveChanged(active);
428 if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(q_func()))
429 accessibleAttached->setDescriptionImplicitly(placeholder);
430}
431#endif
432
434{
435 Q_Q(QQuickTextArea);
436 quickCancelDeferred(q, backgroundName());
437}
438
440{
441 Q_Q(QQuickTextArea);
442 if (background.wasExecuted())
443 return;
444
445 if (!background || complete)
446 quickBeginDeferred(q, backgroundName(), background);
447 if (complete)
448 quickCompleteDeferred(q, backgroundName(), background);
449}
450
452{
453 Q_Q(QQuickTextArea);
454 if (item == background)
455 emit q->implicitBackgroundWidthChanged();
456}
457
459{
460 Q_Q(QQuickTextArea);
461 if (item == background)
462 emit q->implicitBackgroundHeightChanged();
463}
464
466{
467 Q_Q(QQuickTextArea);
468 if (item == background) {
469 background = nullptr;
470 emit q->implicitBackgroundWidthChanged();
471 emit q->implicitBackgroundHeightChanged();
472 } else if (item == flickable) {
474 }
475}
476
478{
479 return QQuickTheme::palette(QQuickTheme::TextArea);
480}
481
483{
484 Q_Q(QQuickTextArea);
485 const auto focusReasonChanged = QQuickItemPrivate::setLastFocusChangeReason(reason);
486 if (focusReasonChanged)
487 emit q->focusReasonChanged();
488
489 return focusReasonChanged;
490}
491
492QQuickTextArea::QQuickTextArea(QQuickItem *parent)
493 : QQuickTextEdit(*(new QQuickTextAreaPrivate), parent)
494{
495 Q_D(QQuickTextArea);
496 setActiveFocusOnTab(true);
497 setAcceptedMouseButtons(Qt::AllButtons);
498 d->setImplicitResizeEnabled(false);
499 d->pressHandler.control = this;
500
501#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
502 if (qEnvironmentVariable("QT_QUICK_CONTROLS_TEXT_SELECTION_BEHAVIOR") == u"old"_s)
503 QQuickTextEdit::setOldSelectionDefault();
504#endif
505}
506
507QQuickTextArea::~QQuickTextArea()
508{
509 Q_D(QQuickTextArea);
510 if (d->flickable)
511 d->detachFlickable();
512 QQuickControlPrivate::removeImplicitSizeListener(d->background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
513}
514
515QQuickTextAreaAttached *QQuickTextArea::qmlAttachedProperties(QObject *object)
516{
517 return new QQuickTextAreaAttached(object);
518}
519
520QFont QQuickTextArea::font() const
521{
522 Q_D(const QQuickTextArea);
523 QFont font = QQuickTextEdit::font();
524 // The resolve mask should inherit from the requestedFont
525 font.setResolveMask(d->extra.value().requestedFont.resolveMask());
526 return font;
527}
528
529void QQuickTextArea::setFont(const QFont &font)
530{
531 Q_D(QQuickTextArea);
532 if (d->extra.value().requestedFont.resolveMask() == font.resolveMask() && d->extra.value().requestedFont == font)
533 return;
534
535 d->extra.value().requestedFont = font;
536 d->resolveFont();
537}
538
539/*!
540 \qmlproperty Item QtQuick.Controls::TextArea::background
541
542 This property holds the background item.
543
544 \input qquickcontrol-background.qdocinc notes
545
546 \sa {Customizing TextArea}
547*/
548QQuickItem *QQuickTextArea::background() const
549{
550 QQuickTextAreaPrivate *d = const_cast<QQuickTextAreaPrivate *>(d_func());
551 if (!d->background)
552 d->executeBackground();
553 return d->background;
554}
555
556void QQuickTextArea::setBackground(QQuickItem *background)
557{
558 Q_D(QQuickTextArea);
559 if (d->background == background)
560 return;
561
562 QQuickControlPrivate::warnIfCustomizationNotSupported(this, background, QStringLiteral("background"));
563
564 if (!d->background.isExecuting())
565 d->cancelBackground();
566
567 const qreal oldImplicitBackgroundWidth = implicitBackgroundWidth();
568 const qreal oldImplicitBackgroundHeight = implicitBackgroundHeight();
569
570 if (d->extra.isAllocated()) {
571 d->extra.value().hasBackgroundWidth = false;
572 d->extra.value().hasBackgroundHeight = false;
573 }
574
575 QQuickControlPrivate::removeImplicitSizeListener(d->background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
576 QQuickControlPrivate::hideOldItem(d->background);
577 d->background = background;
578
579 if (background) {
580 QQuickItemPrivate *p = QQuickItemPrivate::get(background);
581 if (p->widthValid() || p->heightValid()) {
582 d->extra.value().hasBackgroundWidth = p->widthValid();
583 d->extra.value().hasBackgroundHeight = p->heightValid();
584 }
585 if (d->flickable)
586 background->setParentItem(d->flickable);
587 else
588 background->setParentItem(this);
589 if (qFuzzyIsNull(background->z()))
590 background->setZ(-1);
591 if (isComponentComplete())
592 d->resizeBackground();
593 QQuickControlPrivate::addImplicitSizeListener(background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
594 }
595
596 if (!qFuzzyCompare(oldImplicitBackgroundWidth, implicitBackgroundWidth()))
597 emit implicitBackgroundWidthChanged();
598 if (!qFuzzyCompare(oldImplicitBackgroundHeight, implicitBackgroundHeight()))
599 emit implicitBackgroundHeightChanged();
600 if (!d->background.isExecuting())
601 emit backgroundChanged();
602}
603
604/*!
605 \qmlproperty string QtQuick.Controls::TextArea::placeholderText
606
607 This property holds the short hint that is displayed in the text area before
608 the user enters a value.
609*/
610QString QQuickTextArea::placeholderText() const
611{
612 Q_D(const QQuickTextArea);
613 return d->placeholder;
614}
615
616void QQuickTextArea::setPlaceholderText(const QString &text)
617{
618 Q_D(QQuickTextArea);
619 if (d->placeholder == text)
620 return;
621
622 d->placeholder = text;
623#if QT_CONFIG(accessibility)
624 if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(this))
625 accessibleAttached->setDescriptionImplicitly(text);
626#endif
627 emit placeholderTextChanged();
628}
629
630/*!
631 \qmlproperty color QtQuick.Controls::TextArea::placeholderTextColor
632 \since QtQuick.Controls 2.5 (Qt 5.12)
633
634 This property holds the color of placeholderText.
635
636 \sa placeholderText
637*/
638QColor QQuickTextArea::placeholderTextColor() const
639{
640 Q_D(const QQuickTextArea);
641 return d->placeholderColor;
642}
643
644void QQuickTextArea::setPlaceholderTextColor(const QColor &color)
645{
646 Q_D(QQuickTextArea);
647 if (d->placeholderColor == color)
648 return;
649
650 d->placeholderColor = color;
651 emit placeholderTextColorChanged();
652}
653
654/*!
655 \qmlproperty enumeration QtQuick.Controls::TextArea::focusReason
656
657 This property holds the reason of the last focus change.
658
659 \note This property does not indicate whether the item has \l {Item::activeFocus}
660 {active focus}, but the reason why the item either gained or lost focus.
661
662 \value Qt.MouseFocusReason A mouse action occurred.
663 \value Qt.TabFocusReason The Tab key was pressed.
664 \value Qt.BacktabFocusReason A Backtab occurred. The input for this may include the Shift or Control keys; e.g. Shift+Tab.
665 \value Qt.ActiveWindowFocusReason The window system made this window either active or inactive.
666 \value Qt.PopupFocusReason The application opened/closed a pop-up that grabbed/released the keyboard focus.
667 \value Qt.ShortcutFocusReason The user typed a label's buddy shortcut
668 \value Qt.MenuBarFocusReason The menu bar took focus.
669 \value Qt.OtherFocusReason Another reason, usually application-specific.
670
671 \note Prefer \l {QtQuick.Controls::Control::focusReason} to this property.
672*/
673Qt::FocusReason QQuickTextArea::focusReason() const
674{
675 Q_D(const QQuickTextArea);
676 return d->lastFocusChangeReason();
677}
678
679void QQuickTextArea::setFocusReason(Qt::FocusReason reason)
680{
681 Q_D(QQuickTextArea);
682 d->setLastFocusChangeReason(reason);
683}
684
685
686bool QQuickTextArea::contains(const QPointF &point) const
687{
688 Q_D(const QQuickTextArea);
689 if (d->flickable && !d->flickable->contains(d->flickable->mapFromItem(this, point)))
690 return false;
691 return QQuickTextEdit::contains(point);
692}
693
694/*!
695 \since QtQuick.Controls 2.1 (Qt 5.8)
696 \qmlproperty bool QtQuick.Controls::TextArea::hovered
697 \readonly
698
699 This property holds whether the text area is hovered.
700
701 \sa hoverEnabled
702*/
703bool QQuickTextArea::isHovered() const
704{
705#if QT_CONFIG(quicktemplates2_hover)
706 Q_D(const QQuickTextArea);
707 return d->hovered;
708#else
709 return false;
710#endif
711}
712
713void QQuickTextArea::setHovered(bool hovered)
714{
715#if QT_CONFIG(quicktemplates2_hover)
716 Q_D(QQuickTextArea);
717 if (hovered == d->hovered)
718 return;
719
720 d->hovered = hovered;
721 emit hoveredChanged();
722 QQuickToolTipAttachedPrivate::maybeSetVisibleImplicitly(this, hovered);
723#else
724 Q_UNUSED(hovered);
725#endif
726}
727
728/*!
729 \since QtQuick.Controls 2.1 (Qt 5.8)
730 \qmlproperty bool QtQuick.Controls::TextArea::hoverEnabled
731
732 This property determines whether the text area accepts hover events. The default value is \c true.
733
734 \sa hovered
735*/
736bool QQuickTextArea::isHoverEnabled() const
737{
738#if QT_CONFIG(quicktemplates2_hover)
739 Q_D(const QQuickTextArea);
740 return d->hoverEnabled;
741#else
742 return false;
743#endif
744}
745
746void QQuickTextArea::setHoverEnabled(bool enabled)
747{
748#if QT_CONFIG(quicktemplates2_hover)
749 Q_D(QQuickTextArea);
750 if (d->explicitHoverEnabled && enabled == d->hoverEnabled)
751 return;
752
753 d->updateHoverEnabled(enabled, true); // explicit=true
754#else
755 Q_UNUSED(enabled);
756#endif
757}
758
759void QQuickTextArea::resetHoverEnabled()
760{
761#if QT_CONFIG(quicktemplates2_hover)
762 Q_D(QQuickTextArea);
763 if (!d->explicitHoverEnabled)
764 return;
765
766 d->explicitHoverEnabled = false;
767 d->updateHoverEnabled(QQuickControlPrivate::calcHoverEnabled(d->parentItem), false); // explicit=false
768#endif
769}
770
771/*!
772 \since QtQuick.Controls 2.5 (Qt 5.12)
773 \qmlproperty real QtQuick.Controls::TextArea::implicitBackgroundWidth
774 \readonly
775
776 This property holds the implicit background width.
777
778 The value is equal to \c {background ? background.implicitWidth : 0}.
779
780 \sa implicitBackgroundHeight
781*/
782qreal QQuickTextArea::implicitBackgroundWidth() const
783{
784 Q_D(const QQuickTextArea);
785 if (!d->background)
786 return 0;
787 return d->background->implicitWidth();
788}
789
790/*!
791 \since QtQuick.Controls 2.5 (Qt 5.12)
792 \qmlproperty real QtQuick.Controls::TextArea::implicitBackgroundHeight
793 \readonly
794
795 This property holds the implicit background height.
796
797 The value is equal to \c {background ? background.implicitHeight : 0}.
798
799 \sa implicitBackgroundWidth
800*/
801qreal QQuickTextArea::implicitBackgroundHeight() const
802{
803 Q_D(const QQuickTextArea);
804 if (!d->background)
805 return 0;
806 return d->background->implicitHeight();
807}
808
809/*!
810 \since QtQuick.Controls 2.5 (Qt 5.12)
811 \qmlproperty real QtQuick.Controls::TextArea::topInset
812
813 This property holds the top inset for the background.
814
815 \sa {Control Layout}, bottomInset
816*/
817qreal QQuickTextArea::topInset() const
818{
819 Q_D(const QQuickTextArea);
820 return d->getTopInset();
821}
822
823void QQuickTextArea::setTopInset(qreal inset)
824{
825 Q_D(QQuickTextArea);
826 d->setTopInset(inset);
827}
828
829void QQuickTextArea::resetTopInset()
830{
831 Q_D(QQuickTextArea);
832 d->setTopInset(0, true);
833}
834
835/*!
836 \since QtQuick.Controls 2.5 (Qt 5.12)
837 \qmlproperty real QtQuick.Controls::TextArea::leftInset
838
839 This property holds the left inset for the background.
840
841 \sa {Control Layout}, rightInset
842*/
843qreal QQuickTextArea::leftInset() const
844{
845 Q_D(const QQuickTextArea);
846 return d->getLeftInset();
847}
848
849void QQuickTextArea::setLeftInset(qreal inset)
850{
851 Q_D(QQuickTextArea);
852 d->setLeftInset(inset);
853}
854
855void QQuickTextArea::resetLeftInset()
856{
857 Q_D(QQuickTextArea);
858 d->setLeftInset(0, true);
859}
860
861/*!
862 \since QtQuick.Controls 2.5 (Qt 5.12)
863 \qmlproperty real QtQuick.Controls::TextArea::rightInset
864
865 This property holds the right inset for the background.
866
867 \sa {Control Layout}, leftInset
868*/
869qreal QQuickTextArea::rightInset() const
870{
871 Q_D(const QQuickTextArea);
872 return d->getRightInset();
873}
874
875void QQuickTextArea::setRightInset(qreal inset)
876{
877 Q_D(QQuickTextArea);
878 d->setRightInset(inset);
879}
880
881void QQuickTextArea::resetRightInset()
882{
883 Q_D(QQuickTextArea);
884 d->setRightInset(0, true);
885}
886
887/*!
888 \since QtQuick.Controls 2.5 (Qt 5.12)
889 \qmlproperty real QtQuick.Controls::TextArea::bottomInset
890
891 This property holds the bottom inset for the background.
892
893 \sa {Control Layout}, topInset
894*/
895qreal QQuickTextArea::bottomInset() const
896{
897 Q_D(const QQuickTextArea);
898 return d->getBottomInset();
899}
900
901void QQuickTextArea::setBottomInset(qreal inset)
902{
903 Q_D(QQuickTextArea);
904 d->setBottomInset(inset);
905}
906
907void QQuickTextArea::resetBottomInset()
908{
909 Q_D(QQuickTextArea);
910 d->setBottomInset(0, true);
911}
912
913void QQuickTextArea::classBegin()
914{
915 Q_D(QQuickTextArea);
916 QQuickTextEdit::classBegin();
917 d->resolveFont();
918}
919
920void QQuickTextArea::componentComplete()
921{
922 Q_D(QQuickTextArea);
923 d->executeBackground(true);
924 QQuickTextEdit::componentComplete();
925 d->resizeBackground();
926#if QT_CONFIG(quicktemplates2_hover)
927 if (!d->explicitHoverEnabled)
928 setAcceptHoverEvents(QQuickControlPrivate::calcHoverEnabled(d->parentItem));
929#endif
930}
931
932void QQuickTextArea::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
933{
934 Q_D(QQuickTextArea);
935 QQuickTextEdit::itemChange(change, value);
936 switch (change) {
937 case ItemEnabledHasChanged:
938 break;
939 case ItemSceneChange:
940 case ItemParentHasChanged:
941 if ((change == ItemParentHasChanged && value.item) || (change == ItemSceneChange && value.window)) {
942 d->resolveFont();
943#if QT_CONFIG(quicktemplates2_hover)
944 if (!d->explicitHoverEnabled)
945 d->updateHoverEnabled(QQuickControlPrivate::calcHoverEnabled(d->parentItem), false); // explicit=false
946#endif
947 if (change == ItemParentHasChanged) {
948 QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(value.item->parentItem());
949 if (flickable) {
950 QQuickScrollView *scrollView = qobject_cast<QQuickScrollView *>(flickable->parentItem());
951 if (scrollView)
952 d->attachFlickable(flickable);
953 }
954 }
955 }
956 break;
957 default:
958 break;
959 }
960}
961
962void QQuickTextArea::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
963{
964 Q_D(QQuickTextArea);
965 QQuickTextEdit::geometryChange(newGeometry, oldGeometry);
966 d->resizeBackground();
967}
968
969void QQuickTextArea::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
970{
971 Q_D(QQuickTextArea);
972 Q_UNUSED(newInset);
973 Q_UNUSED(oldInset);
974 d->resizeBackground();
975}
976
977QSGNode *QQuickTextArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
978{
979 Q_D(QQuickTextArea);
980 QQuickDefaultClipNode *clipNode = static_cast<QQuickDefaultClipNode *>(oldNode);
981 if (!clipNode)
982 clipNode = new QQuickDefaultClipNode(QRectF());
983
984 QQuickItem *clipper = this;
985 if (d->flickable)
986 clipper = d->flickable;
987
988 const QRectF cr = clipper->clipRect().adjusted(
989 leftPadding(), topPadding(),
990 (!d->cursorItem && effectiveHAlign() == HAlignment::AlignRight ? 1 : 0) - rightPadding(),
991 -bottomPadding());
992
993 clipNode->setRect(!d->flickable ? cr : cr.translated(d->flickable->contentX(), d->flickable->contentY()));
994 clipNode->update();
995
996 QSGNode *textNode = QQuickTextEdit::updatePaintNode(clipNode->firstChild(), data);
997 if (!textNode->parent())
998 clipNode->appendChildNode(textNode);
999
1000 if (d->cursorItem) {
1001 QQuickDefaultClipNode *cursorNode = QQuickItemPrivate::get(d->cursorItem)->clipNode();
1002 if (cursorNode)
1003 cursorNode->setClipRect(d->cursorItem->mapRectFromItem(clipper, cr));
1004 }
1005
1006 return clipNode;
1007}
1008
1009void QQuickTextArea::focusInEvent(QFocusEvent *event)
1010{
1011 QQuickTextEdit::focusInEvent(event);
1012}
1013
1014void QQuickTextArea::focusOutEvent(QFocusEvent *event)
1015{
1016 QQuickTextEdit::focusOutEvent(event);
1017}
1018
1019#if QT_CONFIG(quicktemplates2_hover)
1020void QQuickTextArea::hoverEnterEvent(QHoverEvent *event)
1021{
1022 Q_D(QQuickTextArea);
1023 QQuickTextEdit::hoverEnterEvent(event);
1024 setHovered(d->hoverEnabled);
1025 event->ignore();
1026}
1027
1028void QQuickTextArea::hoverLeaveEvent(QHoverEvent *event)
1029{
1030 QQuickTextEdit::hoverLeaveEvent(event);
1031 setHovered(false);
1032 event->ignore();
1033}
1034#endif
1035
1036void QQuickTextArea::mousePressEvent(QMouseEvent *event)
1037{
1038 Q_D(QQuickTextArea);
1039 d->pressHandler.mousePressEvent(event);
1040 if (d->pressHandler.isActive()) {
1041 if (d->pressHandler.delayedMousePressEvent) {
1042 QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent.get());
1043 d->pressHandler.clearDelayedMouseEvent();
1044 }
1045 // Calling the base class implementation will result in QQuickTextControl's
1046 // press handler being called, which ignores events that aren't Qt::LeftButton.
1047 const bool wasAccepted = event->isAccepted();
1048 QQuickTextEdit::mousePressEvent(event);
1049 if (wasAccepted)
1050 event->accept();
1051 }
1052}
1053
1054void QQuickTextArea::mouseMoveEvent(QMouseEvent *event)
1055{
1056 Q_D(QQuickTextArea);
1057 d->pressHandler.mouseMoveEvent(event);
1058 if (d->pressHandler.isActive()) {
1059 if (d->pressHandler.delayedMousePressEvent) {
1060 QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent.get());
1061 d->pressHandler.clearDelayedMouseEvent();
1062 }
1063 QQuickTextEdit::mouseMoveEvent(event);
1064 }
1065}
1066
1067void QQuickTextArea::mouseReleaseEvent(QMouseEvent *event)
1068{
1069 Q_D(QQuickTextArea);
1070 d->pressHandler.mouseReleaseEvent(event);
1071 if (d->pressHandler.isActive()) {
1072 if (d->pressHandler.delayedMousePressEvent) {
1073 QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent.get());
1074 d->pressHandler.clearDelayedMouseEvent();
1075 }
1076 QQuickTextEdit::mouseReleaseEvent(event);
1077 }
1078}
1079
1080void QQuickTextArea::mouseDoubleClickEvent(QMouseEvent *event)
1081{
1082 Q_D(QQuickTextArea);
1083 if (d->pressHandler.delayedMousePressEvent) {
1084 QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent.get());
1085 d->pressHandler.clearDelayedMouseEvent();
1086 }
1087 QQuickTextEdit::mouseDoubleClickEvent(event);
1088}
1089
1090void QQuickTextArea::timerEvent(QTimerEvent *event)
1091{
1092 Q_D(QQuickTextArea);
1093 if (event->timerId() == d->pressHandler.timer.timerId())
1094 d->pressHandler.timerEvent(event);
1095 else
1096 QQuickTextEdit::timerEvent(event);
1097}
1098
1100{
1101public:
1103};
1104
1105QQuickTextAreaAttached::QQuickTextAreaAttached(QObject *parent)
1106 : QObject(*(new QQuickTextAreaAttachedPrivate), parent)
1107{
1108}
1109
1110/*!
1111 \qmlattachedproperty TextArea QtQuick.Controls::TextArea::flickable
1112
1113 This property attaches a text area to a \l Flickable.
1114
1115 \sa ScrollBar, ScrollIndicator, {Scrollable TextArea}
1116*/
1117QQuickTextArea *QQuickTextAreaAttached::flickable() const
1118{
1119 Q_D(const QQuickTextAreaAttached);
1120 return d->control;
1121}
1122
1123void QQuickTextAreaAttached::setFlickable(QQuickTextArea *control)
1124{
1125 Q_D(QQuickTextAreaAttached);
1126 QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(parent());
1127 if (!flickable) {
1128 qmlWarning(parent()) << "TextArea attached property must be attached to an object deriving from Flickable";
1129 return;
1130 }
1131
1132 if (d->control == control)
1133 return;
1134
1135 if (d->control)
1136 QQuickTextAreaPrivate::get(d->control)->detachFlickable();
1137
1138 d->control = control;
1139
1140 if (control)
1141 QQuickTextAreaPrivate::get(control)->attachFlickable(flickable);
1142
1143 emit flickableChanged();
1144}
1145
1146QT_END_NAMESPACE
1147
1148#include "moc_qquicktextarea_p.cpp"
void implicitWidthChanged() override
qreal getImplicitWidth() const override
bool setLastFocusChangeReason(Qt::FocusReason reason) override
QQuickFlickable * flickable
void setTopInset(qreal value, bool reset=false)
void setLeftInset(qreal value, bool reset=false)
void setRightInset(qreal value, bool reset=false)
void executeBackground(bool complete=false)
void updateFont(const QFont &font)
void setBottomInset(qreal value, bool reset=false)
void itemDestroyed(QQuickItem *item) override
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override
void itemImplicitWidthChanged(QQuickItem *item) override
void attachFlickable(QQuickFlickable *flickable)
void inheritFont(const QFont &font)
qreal getImplicitHeight() const override
void itemImplicitHeightChanged(QQuickItem *item) override
QPalette defaultPalette() const override
void implicitHeightChanged() override
Combined button and popup list for selecting options.