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
4#include "qquicklabel_p.h"
5#include "qquicklabel_p_p.h"
6#include "qquickcontrol_p.h"
7#include "qquickcontrol_p_p.h"
8#include "qquickdeferredexecute_p_p.h"
9
10#include <QtQuick/private/qquickitem_p.h>
11#include <QtQuick/private/qquicktext_p.h>
12
13#if QT_CONFIG(accessibility)
14#include <QtQuick/private/qquickaccessibleattached_p.h>
15#endif
16
17QT_BEGIN_NAMESPACE
18
19/*!
20 \qmltype Label
21 \inherits Text
22//! \instantiates QQuickLabel
23 \inqmlmodule QtQuick.Controls
24 \since 5.7
25 \ingroup text
26 \brief Styled text label with inherited font.
27
28 Label extends \l Text with styling and \l {Control::font}{font}
29 inheritance. The default colors and font are style specific. Label
30 can also have a visual \l background item.
31
32 \image qtquickcontrols-label.png
33
34 \snippet qtquickcontrols-label.qml 1
35
36 You can use the properties of \l Text to change the appearance of the text as desired:
37
38 \qml
39 Label {
40 text: "Hello world"
41 font.pixelSize: 22
42 font.italic: true
43 }
44 \endqml
45
46 \sa {Customizing Label}
47*/
48
49QQuickLabelPrivate::QQuickLabelPrivate()
50{
51#if QT_CONFIG(accessibility)
52 QAccessible::installActivationObserver(this);
53#endif
54}
55
56QQuickLabelPrivate::~QQuickLabelPrivate()
57{
58#if QT_CONFIG(accessibility)
59 QAccessible::removeActivationObserver(this);
60#endif
61}
62
63void QQuickLabelPrivate::setTopInset(qreal value, bool reset)
64{
65 Q_Q(QQuickLabel);
66 const QMarginsF oldInset = getInset();
67 extra.value().topInset = value;
68 extra.value().hasTopInset = !reset;
69 if (!qFuzzyCompare(p1: oldInset.top(), p2: value)) {
70 emit q->topInsetChanged();
71 q->insetChange(newInset: getInset(), oldInset);
72 }
73}
74
75void QQuickLabelPrivate::setLeftInset(qreal value, bool reset)
76{
77 Q_Q(QQuickLabel);
78 const QMarginsF oldInset = getInset();
79 extra.value().leftInset = value;
80 extra.value().hasLeftInset = !reset;
81 if (!qFuzzyCompare(p1: oldInset.left(), p2: value)) {
82 emit q->leftInsetChanged();
83 q->insetChange(newInset: getInset(), oldInset);
84 }
85}
86
87void QQuickLabelPrivate::setRightInset(qreal value, bool reset)
88{
89 Q_Q(QQuickLabel);
90 const QMarginsF oldInset = getInset();
91 extra.value().rightInset = value;
92 extra.value().hasRightInset = !reset;
93 if (!qFuzzyCompare(p1: oldInset.right(), p2: value)) {
94 emit q->rightInsetChanged();
95 q->insetChange(newInset: getInset(), oldInset);
96 }
97}
98
99void QQuickLabelPrivate::setBottomInset(qreal value, bool reset)
100{
101 Q_Q(QQuickLabel);
102 const QMarginsF oldInset = getInset();
103 extra.value().bottomInset = value;
104 extra.value().hasBottomInset = !reset;
105 if (!qFuzzyCompare(p1: oldInset.bottom(), p2: value)) {
106 emit q->bottomInsetChanged();
107 q->insetChange(newInset: getInset(), oldInset);
108 }
109}
110
111void QQuickLabelPrivate::resizeBackground()
112{
113 if (!background)
114 return;
115
116 resizingBackground = true;
117
118 QQuickItemPrivate *p = QQuickItemPrivate::get(item: background);
119 if (((!p->widthValid() || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(d: background->x()))
120 || (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) {
121 background->setX(getLeftInset());
122 background->setWidth(width - getLeftInset() - getRightInset());
123 }
124 if (((!p->heightValid() || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(d: background->y()))
125 || (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) {
126 background->setY(getTopInset());
127 background->setHeight(height - getTopInset() - getBottomInset());
128 }
129
130 resizingBackground = false;
131}
132
133/*!
134 \internal
135
136 Determine which font is implicitly imposed on this control by its ancestors
137 and QGuiApplication::font, resolve this against its own font (attributes from
138 the implicit font are copied over). Then propagate this font to this
139 control's children.
140*/
141void QQuickLabelPrivate::resolveFont()
142{
143 Q_Q(QQuickLabel);
144 inheritFont(font: QQuickControlPrivate::parentFont(item: q));
145}
146
147void QQuickLabelPrivate::inheritFont(const QFont &font)
148{
149 QFont parentFont = extra.isAllocated() ? extra->requestedFont.resolve(font) : font;
150 parentFont.setResolveMask(extra.isAllocated() ? extra->requestedFont.resolveMask() | font.resolveMask() : font.resolveMask());
151
152 const QFont defaultFont = QQuickTheme::font(scope: QQuickTheme::Label);
153 QFont resolvedFont = parentFont.resolve(defaultFont);
154
155 setFont_helper(resolvedFont);
156}
157
158/*!
159 \internal
160
161 Assign \a font to this control, and propagate it to all children.
162*/
163void QQuickLabelPrivate::updateFont(const QFont &font)
164{
165 Q_Q(QQuickLabel);
166 QFont oldFont = sourceFont;
167 q->QQuickText::setFont(font);
168
169 QQuickControlPrivate::updateFontRecur(item: q, font);
170
171 if (oldFont != font)
172 emit q->fontChanged();
173}
174
175void QQuickLabelPrivate::textChanged(const QString &text)
176{
177#if QT_CONFIG(accessibility)
178 maybeSetAccessibleName(name: text);
179#else
180 Q_UNUSED(text);
181#endif
182}
183
184#if QT_CONFIG(accessibility)
185void QQuickLabelPrivate::accessibilityActiveChanged(bool active)
186{
187 if (!active)
188 return;
189
190 Q_Q(QQuickLabel);
191 QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(object: qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj: q, create: true));
192 Q_ASSERT(accessibleAttached);
193 accessibleAttached->setRole(effectiveAccessibleRole());
194 maybeSetAccessibleName(name: text);
195}
196
197QAccessible::Role QQuickLabelPrivate::accessibleRole() const
198{
199 return QAccessible::StaticText;
200}
201
202void QQuickLabelPrivate::maybeSetAccessibleName(const QString &name)
203{
204 Q_Q(QQuickLabel);
205 auto accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
206 object: qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj: q, create: true));
207 if (accessibleAttached) {
208 if (!accessibleAttached->wasNameExplicitlySet())
209 accessibleAttached->setNameImplicitly(name);
210 }
211}
212#endif
213
214void QQuickLabelPrivate::cancelBackground()
215{
216 Q_Q(QQuickLabel);
217 quickCancelDeferred(object: q, property: backgroundName());
218}
219
220void QQuickLabelPrivate::executeBackground(bool complete)
221{
222 Q_Q(QQuickLabel);
223 if (background.wasExecuted())
224 return;
225
226 if (!background || complete)
227 quickBeginDeferred(object: q, property: backgroundName(), delegate&: background);
228 if (complete)
229 quickCompleteDeferred(object: q, property: backgroundName(), delegate&: background);
230}
231
232void QQuickLabelPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
233{
234 Q_UNUSED(diff);
235 if (resizingBackground || item != background || !change.sizeChange())
236 return;
237
238 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
239 extra.value().hasBackgroundWidth = p->widthValid();
240 extra.value().hasBackgroundHeight = p->heightValid();
241 resizeBackground();
242}
243
244void QQuickLabelPrivate::itemImplicitWidthChanged(QQuickItem *item)
245{
246 Q_Q(QQuickLabel);
247 if (item == background)
248 emit q->implicitBackgroundWidthChanged();
249}
250
251void QQuickLabelPrivate::itemImplicitHeightChanged(QQuickItem *item)
252{
253 Q_Q(QQuickLabel);
254 if (item == background)
255 emit q->implicitBackgroundHeightChanged();
256}
257
258void QQuickLabelPrivate::itemDestroyed(QQuickItem *item)
259{
260 Q_Q(QQuickLabel);
261 if (item == background) {
262 background = nullptr;
263 emit q->implicitBackgroundWidthChanged();
264 emit q->implicitBackgroundHeightChanged();
265 }
266}
267
268QPalette QQuickLabelPrivate::defaultPalette() const
269{
270 return QQuickTheme::palette(scope: QQuickTheme::Label);
271}
272
273QQuickLabel::QQuickLabel(QQuickItem *parent)
274 : QQuickText(*(new QQuickLabelPrivate), parent)
275{
276 Q_D(QQuickLabel);
277 QObjectPrivate::connect(sender: this, signal: &QQuickText::textChanged, receiverPrivate: d, slot: &QQuickLabelPrivate::textChanged);
278}
279
280QQuickLabel::~QQuickLabel()
281{
282 Q_D(QQuickLabel);
283 QQuickControlPrivate::removeImplicitSizeListener(item: d->background, listener: d, changes: QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
284}
285
286QFont QQuickLabel::font() const
287{
288 Q_D(const QQuickLabel);
289 QFont font = QQuickText::font();
290 // The resolve mask should inherit from the requestedFont
291 font.setResolveMask(d->extra.value().requestedFont.resolveMask());
292 return font;
293}
294
295void QQuickLabel::setFont(const QFont &font)
296{
297 Q_D(QQuickLabel);
298 if (d->extra.value().requestedFont.resolveMask() == font.resolveMask() && d->extra.value().requestedFont == font)
299 return;
300
301 d->extra.value().requestedFont = font;
302 d->resolveFont();
303}
304
305/*!
306 \qmlproperty Item QtQuick.Controls::Label::background
307
308 This property holds the background item.
309
310 \note If the background item has no explicit size specified, it automatically
311 follows the control's size. In most cases, there is no need to specify
312 width or height for a background item.
313
314 \sa {Customizing Label}
315*/
316QQuickItem *QQuickLabel::background() const
317{
318 QQuickLabelPrivate *d = const_cast<QQuickLabelPrivate *>(d_func());
319 if (!d->background)
320 d->executeBackground();
321 return d->background;
322}
323
324void QQuickLabel::setBackground(QQuickItem *background)
325{
326 Q_D(QQuickLabel);
327 if (d->background == background)
328 return;
329
330 if (!d->background.isExecuting())
331 d->cancelBackground();
332
333 const qreal oldImplicitBackgroundWidth = implicitBackgroundWidth();
334 const qreal oldImplicitBackgroundHeight = implicitBackgroundHeight();
335
336 if (d->extra.isAllocated()) {
337 d->extra.value().hasBackgroundWidth = false;
338 d->extra.value().hasBackgroundHeight = false;
339 }
340
341 QQuickControlPrivate::removeImplicitSizeListener(item: d->background, listener: d, changes: QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
342 QQuickControlPrivate::hideOldItem(item: d->background);
343 d->background = background;
344
345 if (background) {
346 background->setParentItem(this);
347 if (qFuzzyIsNull(d: background->z()))
348 background->setZ(-1);
349 QQuickItemPrivate *p = QQuickItemPrivate::get(item: background);
350 if (p->widthValid() || p->heightValid()) {
351 d->extra.value().hasBackgroundWidth = p->widthValid();
352 d->extra.value().hasBackgroundHeight = p->heightValid();
353 }
354 if (isComponentComplete())
355 d->resizeBackground();
356 QQuickControlPrivate::addImplicitSizeListener(item: background, listener: d, changes: QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
357 }
358
359 if (!qFuzzyCompare(p1: oldImplicitBackgroundWidth, p2: implicitBackgroundWidth()))
360 emit implicitBackgroundWidthChanged();
361 if (!qFuzzyCompare(p1: oldImplicitBackgroundHeight, p2: implicitBackgroundHeight()))
362 emit implicitBackgroundHeightChanged();
363 if (!d->background.isExecuting())
364 emit backgroundChanged();
365}
366
367/*!
368 \since QtQuick.Controls 2.5 (Qt 5.12)
369 \qmlproperty real QtQuick.Controls::Label::implicitBackgroundWidth
370 \readonly
371
372 This property holds the implicit background width.
373
374 The value is equal to \c {background ? background.implicitWidth : 0}.
375
376 \sa implicitBackgroundHeight
377*/
378qreal QQuickLabel::implicitBackgroundWidth() const
379{
380 Q_D(const QQuickLabel);
381 if (!d->background)
382 return 0;
383 return d->background->implicitWidth();
384}
385
386/*!
387 \since QtQuick.Controls 2.5 (Qt 5.12)
388 \qmlproperty real QtQuick.Controls::Label::implicitBackgroundHeight
389 \readonly
390
391 This property holds the implicit background height.
392
393 The value is equal to \c {background ? background.implicitHeight : 0}.
394
395 \sa implicitBackgroundWidth
396*/
397qreal QQuickLabel::implicitBackgroundHeight() const
398{
399 Q_D(const QQuickLabel);
400 if (!d->background)
401 return 0;
402 return d->background->implicitHeight();
403}
404
405/*!
406 \since QtQuick.Controls 2.5 (Qt 5.12)
407 \qmlproperty real QtQuick.Controls::Label::topInset
408
409 This property holds the top inset for the background.
410
411 \sa {Control Layout}, bottomInset
412*/
413qreal QQuickLabel::topInset() const
414{
415 Q_D(const QQuickLabel);
416 return d->getTopInset();
417}
418
419void QQuickLabel::setTopInset(qreal inset)
420{
421 Q_D(QQuickLabel);
422 d->setTopInset(value: inset);
423}
424
425void QQuickLabel::resetTopInset()
426{
427 Q_D(QQuickLabel);
428 d->setTopInset(value: 0, reset: true);
429}
430
431/*!
432 \since QtQuick.Controls 2.5 (Qt 5.12)
433 \qmlproperty real QtQuick.Controls::Label::leftInset
434
435 This property holds the left inset for the background.
436
437 \sa {Control Layout}, rightInset
438*/
439qreal QQuickLabel::leftInset() const
440{
441 Q_D(const QQuickLabel);
442 return d->getLeftInset();
443}
444
445void QQuickLabel::setLeftInset(qreal inset)
446{
447 Q_D(QQuickLabel);
448 d->setLeftInset(value: inset);
449}
450
451void QQuickLabel::resetLeftInset()
452{
453 Q_D(QQuickLabel);
454 d->setLeftInset(value: 0, reset: true);
455}
456
457/*!
458 \since QtQuick.Controls 2.5 (Qt 5.12)
459 \qmlproperty real QtQuick.Controls::Label::rightInset
460
461 This property holds the right inset for the background.
462
463 \sa {Control Layout}, leftInset
464*/
465qreal QQuickLabel::rightInset() const
466{
467 Q_D(const QQuickLabel);
468 return d->getRightInset();
469}
470
471void QQuickLabel::setRightInset(qreal inset)
472{
473 Q_D(QQuickLabel);
474 d->setRightInset(value: inset);
475}
476
477void QQuickLabel::resetRightInset()
478{
479 Q_D(QQuickLabel);
480 d->setRightInset(value: 0, reset: true);
481}
482
483/*!
484 \since QtQuick.Controls 2.5 (Qt 5.12)
485 \qmlproperty real QtQuick.Controls::Label::bottomInset
486
487 This property holds the bottom inset for the background.
488
489 \sa {Control Layout}, topInset
490*/
491qreal QQuickLabel::bottomInset() const
492{
493 Q_D(const QQuickLabel);
494 return d->getBottomInset();
495}
496
497void QQuickLabel::setBottomInset(qreal inset)
498{
499 Q_D(QQuickLabel);
500 d->setBottomInset(value: inset);
501}
502
503void QQuickLabel::resetBottomInset()
504{
505 Q_D(QQuickLabel);
506 d->setBottomInset(value: 0, reset: true);
507}
508
509void QQuickLabel::classBegin()
510{
511 Q_D(QQuickLabel);
512 QQuickText::classBegin();
513 d->resolveFont();
514}
515
516void QQuickLabel::componentComplete()
517{
518 Q_D(QQuickLabel);
519 d->executeBackground(complete: true);
520 QQuickText::componentComplete();
521 d->resizeBackground();
522#if QT_CONFIG(accessibility)
523 if (QAccessible::isActive())
524 d->accessibilityActiveChanged(active: true);
525#endif
526}
527
528void QQuickLabel::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
529{
530 Q_D(QQuickLabel);
531 QQuickText::itemChange(change, value);
532 switch (change) {
533 case ItemEnabledHasChanged:
534 break;
535 case ItemSceneChange:
536 case ItemParentHasChanged:
537 if ((change == ItemParentHasChanged && value.item) || (change == ItemSceneChange && value.window)) {
538 d->resolveFont();
539 }
540 break;
541 default:
542 break;
543 }
544}
545
546void QQuickLabel::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
547{
548 Q_D(QQuickLabel);
549 QQuickText::geometryChange(newGeometry, oldGeometry);
550 d->resizeBackground();
551}
552
553void QQuickLabel::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
554{
555 Q_D(QQuickLabel);
556 Q_UNUSED(newInset);
557 Q_UNUSED(oldInset);
558 d->resizeBackground();
559}
560
561QT_END_NAMESPACE
562
563#include "moc_qquicklabel_p.cpp"
564

source code of qtdeclarative/src/quicktemplates/qquicklabel.cpp