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