1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qquicklabel_p.h"
38#include "qquicklabel_p_p.h"
39#include "qquickcontrol_p.h"
40#include "qquickcontrol_p_p.h"
41#include "qquickdeferredexecute_p_p.h"
42
43#include <QtQuick/private/qquickitem_p.h>
44#include <QtQuick/private/qquicktext_p.h>
45
46#if QT_CONFIG(accessibility)
47#include <QtQuick/private/qquickaccessibleattached_p.h>
48#endif
49
50QT_BEGIN_NAMESPACE
51
52/*!
53 \qmltype Label
54 \inherits Text
55//! \instantiates QQuickLabel
56 \inqmlmodule QtQuick.Controls
57 \since 5.7
58 \ingroup text
59 \brief Styled text label with inherited font.
60
61 Label extends \l Text with styling and \l {Control::font}{font}
62 inheritance. The default colors and font are style specific. Label
63 can also have a visual \l background item.
64
65 \image qtquickcontrols2-label.png
66
67 \snippet qtquickcontrols2-label.qml 1
68
69 You can use the properties of \l Text to change the appearance of the text as desired:
70
71 \qml
72 Label {
73 text: "Hello world"
74 font.pixelSize: 22
75 font.italic: true
76 }
77 \endqml
78
79 \sa {Customizing Label}
80*/
81
82QQuickLabelPrivate::QQuickLabelPrivate()
83{
84#if QT_CONFIG(accessibility)
85 QAccessible::installActivationObserver(this);
86#endif
87}
88
89QQuickLabelPrivate::~QQuickLabelPrivate()
90{
91#if QT_CONFIG(accessibility)
92 QAccessible::removeActivationObserver(this);
93#endif
94}
95
96void QQuickLabelPrivate::setTopInset(qreal value, bool reset)
97{
98 Q_Q(QQuickLabel);
99 const QMarginsF oldInset = getInset();
100 extra.value().topInset = value;
101 extra.value().hasTopInset = !reset;
102 if (!qFuzzyCompare(p1: oldInset.top(), p2: value)) {
103 emit q->topInsetChanged();
104 q->insetChange(newInset: getInset(), oldInset);
105 }
106}
107
108void QQuickLabelPrivate::setLeftInset(qreal value, bool reset)
109{
110 Q_Q(QQuickLabel);
111 const QMarginsF oldInset = getInset();
112 extra.value().leftInset = value;
113 extra.value().hasLeftInset = !reset;
114 if (!qFuzzyCompare(p1: oldInset.left(), p2: value)) {
115 emit q->leftInsetChanged();
116 q->insetChange(newInset: getInset(), oldInset);
117 }
118}
119
120void QQuickLabelPrivate::setRightInset(qreal value, bool reset)
121{
122 Q_Q(QQuickLabel);
123 const QMarginsF oldInset = getInset();
124 extra.value().rightInset = value;
125 extra.value().hasRightInset = !reset;
126 if (!qFuzzyCompare(p1: oldInset.right(), p2: value)) {
127 emit q->rightInsetChanged();
128 q->insetChange(newInset: getInset(), oldInset);
129 }
130}
131
132void QQuickLabelPrivate::setBottomInset(qreal value, bool reset)
133{
134 Q_Q(QQuickLabel);
135 const QMarginsF oldInset = getInset();
136 extra.value().bottomInset = value;
137 extra.value().hasBottomInset = !reset;
138 if (!qFuzzyCompare(p1: oldInset.bottom(), p2: value)) {
139 emit q->bottomInsetChanged();
140 q->insetChange(newInset: getInset(), oldInset);
141 }
142}
143
144void QQuickLabelPrivate::resizeBackground()
145{
146 if (!background)
147 return;
148
149 resizingBackground = true;
150
151 QQuickItemPrivate *p = QQuickItemPrivate::get(item: background);
152 if (((!p->widthValid || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(d: background->x()))
153 || (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) {
154 background->setX(getLeftInset());
155 background->setWidth(width - getLeftInset() - getRightInset());
156 }
157 if (((!p->heightValid || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(d: background->y()))
158 || (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) {
159 background->setY(getTopInset());
160 background->setHeight(height - getTopInset() - getBottomInset());
161 }
162
163 resizingBackground = false;
164}
165
166/*!
167 \internal
168
169 Determine which font is implicitly imposed on this control by its ancestors
170 and QGuiApplication::font, resolve this against its own font (attributes from
171 the implicit font are copied over). Then propagate this font to this
172 control's children.
173*/
174void QQuickLabelPrivate::resolveFont()
175{
176 Q_Q(QQuickLabel);
177 inheritFont(font: QQuickControlPrivate::parentFont(item: q));
178}
179
180void QQuickLabelPrivate::inheritFont(const QFont &font)
181{
182 QFont parentFont = extra.isAllocated() ? extra->requestedFont.resolve(font) : font;
183 parentFont.resolve(mask: extra.isAllocated() ? extra->requestedFont.resolve() | font.resolve() : font.resolve());
184
185 const QFont defaultFont = QQuickTheme::font(scope: QQuickTheme::Label);
186 QFont resolvedFont = parentFont.resolve(defaultFont);
187 // See comment in QQuickControlPrivate::inheritFont
188 if (defaultFont.families().isEmpty())
189 resolvedFont.setFamilies(QStringList());
190
191 setFont_helper(resolvedFont);
192}
193
194/*!
195 \internal
196
197 Assign \a font to this control, and propagate it to all children.
198*/
199void QQuickLabelPrivate::updateFont(const QFont &font)
200{
201 Q_Q(QQuickLabel);
202 QFont oldFont = sourceFont;
203 q->QQuickText::setFont(font);
204
205 QQuickControlPrivate::updateFontRecur(item: q, font);
206
207 if (oldFont != font)
208 emit q->fontChanged();
209}
210
211/*!
212 \internal
213
214 Determine which palette is implicitly imposed on this control by its ancestors
215 and QGuiApplication::palette, resolve this against its own palette (attributes from
216 the implicit palette are copied over). Then propagate this palette to this
217 control's children.
218*/
219void QQuickLabelPrivate::resolvePalette()
220{
221 Q_Q(QQuickLabel);
222 inheritPalette(palette: QQuickControlPrivate::parentPalette(item: q));
223}
224
225void QQuickLabelPrivate::inheritPalette(const QPalette &palette)
226{
227 QPalette parentPalette = extra.isAllocated() ? extra->requestedPalette.resolve(palette) : palette;
228 parentPalette.resolve(mask: extra.isAllocated() ? extra->requestedPalette.resolve() | palette.resolve() : palette.resolve());
229
230 const QPalette defaultPalette = QQuickTheme::palette(scope: QQuickTheme::Label);
231 const QPalette resolvedPalette = parentPalette.resolve(defaultPalette);
232
233 setPalette_helper(resolvedPalette);
234}
235
236void QQuickLabelPrivate::updatePalette(const QPalette &palette)
237{
238 Q_Q(QQuickLabel);
239 QPalette oldPalette = resolvedPalette;
240 resolvedPalette = palette;
241
242 QQuickControlPrivate::updatePaletteRecur(item: q, palette);
243
244 if (oldPalette != palette)
245 emit q->paletteChanged();
246}
247
248void QQuickLabelPrivate::textChanged(const QString &text)
249{
250#if QT_CONFIG(accessibility)
251 maybeSetAccessibleName(name: text);
252#else
253 Q_UNUSED(text)
254#endif
255}
256
257#if QT_CONFIG(accessibility)
258void QQuickLabelPrivate::accessibilityActiveChanged(bool active)
259{
260 if (!active)
261 return;
262
263 Q_Q(QQuickLabel);
264 QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(object: qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj: q, create: true));
265 Q_ASSERT(accessibleAttached);
266 accessibleAttached->setRole(accessibleRole());
267 maybeSetAccessibleName(name: text);
268}
269
270QAccessible::Role QQuickLabelPrivate::accessibleRole() const
271{
272 return QAccessible::StaticText;
273}
274
275void QQuickLabelPrivate::maybeSetAccessibleName(const QString &name)
276{
277 Q_Q(QQuickLabel);
278 auto accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
279 object: qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj: q, create: true));
280 if (accessibleAttached) {
281 if (!accessibleAttached->wasNameExplicitlySet())
282 accessibleAttached->setNameImplicitly(name);
283 }
284}
285#endif
286
287static inline QString backgroundName() { return QStringLiteral("background"); }
288
289void QQuickLabelPrivate::cancelBackground()
290{
291 Q_Q(QQuickLabel);
292 quickCancelDeferred(object: q, property: backgroundName());
293}
294
295void QQuickLabelPrivate::executeBackground(bool complete)
296{
297 Q_Q(QQuickLabel);
298 if (background.wasExecuted())
299 return;
300
301 if (!background || complete)
302 quickBeginDeferred(object: q, property: backgroundName(), delegate&: background);
303 if (complete)
304 quickCompleteDeferred(object: q, property: backgroundName(), delegate&: background);
305}
306
307void QQuickLabelPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
308{
309 Q_UNUSED(diff);
310 if (resizingBackground || item != background || !change.sizeChange())
311 return;
312
313 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
314 extra.value().hasBackgroundWidth = p->widthValid;
315 extra.value().hasBackgroundHeight = p->heightValid;
316 resizeBackground();
317}
318
319void QQuickLabelPrivate::itemImplicitWidthChanged(QQuickItem *item)
320{
321 Q_Q(QQuickLabel);
322 if (item == background)
323 emit q->implicitBackgroundWidthChanged();
324}
325
326void QQuickLabelPrivate::itemImplicitHeightChanged(QQuickItem *item)
327{
328 Q_Q(QQuickLabel);
329 if (item == background)
330 emit q->implicitBackgroundHeightChanged();
331}
332
333void QQuickLabelPrivate::itemDestroyed(QQuickItem *item)
334{
335 Q_Q(QQuickLabel);
336 if (item == background) {
337 background = nullptr;
338 emit q->implicitBackgroundWidthChanged();
339 emit q->implicitBackgroundHeightChanged();
340 }
341}
342
343QQuickLabel::QQuickLabel(QQuickItem *parent)
344 : QQuickText(*(new QQuickLabelPrivate), parent)
345{
346 Q_D(QQuickLabel);
347 QObjectPrivate::connect(sender: this, signal: &QQuickText::textChanged, receiverPrivate: d, slot: &QQuickLabelPrivate::textChanged);
348}
349
350QQuickLabel::~QQuickLabel()
351{
352 Q_D(QQuickLabel);
353 QQuickControlPrivate::removeImplicitSizeListener(item: d->background, listener: d, changes: QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
354}
355
356QFont QQuickLabel::font() const
357{
358 return QQuickText::font();
359}
360
361void QQuickLabel::setFont(const QFont &font)
362{
363 Q_D(QQuickLabel);
364 if (d->extra.value().requestedFont.resolve() == font.resolve() && d->extra.value().requestedFont == font)
365 return;
366
367 d->extra.value().requestedFont = font;
368 d->resolveFont();
369}
370
371/*!
372 \qmlproperty Item QtQuick.Controls::Label::background
373
374 This property holds the background item.
375
376 \note If the background item has no explicit size specified, it automatically
377 follows the control's size. In most cases, there is no need to specify
378 width or height for a background item.
379
380 \sa {Customizing Label}
381*/
382QQuickItem *QQuickLabel::background() const
383{
384 QQuickLabelPrivate *d = const_cast<QQuickLabelPrivate *>(d_func());
385 if (!d->background)
386 d->executeBackground();
387 return d->background;
388}
389
390void QQuickLabel::setBackground(QQuickItem *background)
391{
392 Q_D(QQuickLabel);
393 if (d->background == background)
394 return;
395
396 if (!d->background.isExecuting())
397 d->cancelBackground();
398
399 const qreal oldImplicitBackgroundWidth = implicitBackgroundWidth();
400 const qreal oldImplicitBackgroundHeight = implicitBackgroundHeight();
401
402 if (d->extra.isAllocated()) {
403 d->extra.value().hasBackgroundWidth = false;
404 d->extra.value().hasBackgroundHeight = false;
405 }
406
407 QQuickControlPrivate::removeImplicitSizeListener(item: d->background, listener: d, changes: QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
408 QQuickControlPrivate::hideOldItem(item: d->background);
409 d->background = background;
410
411 if (background) {
412 background->setParentItem(this);
413 if (qFuzzyIsNull(d: background->z()))
414 background->setZ(-1);
415 QQuickItemPrivate *p = QQuickItemPrivate::get(item: background);
416 if (p->widthValid || p->heightValid) {
417 d->extra.value().hasBackgroundWidth = p->widthValid;
418 d->extra.value().hasBackgroundHeight = p->heightValid;
419 }
420 if (isComponentComplete())
421 d->resizeBackground();
422 QQuickControlPrivate::addImplicitSizeListener(item: background, listener: d, changes: QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
423 }
424
425 if (!qFuzzyCompare(p1: oldImplicitBackgroundWidth, p2: implicitBackgroundWidth()))
426 emit implicitBackgroundWidthChanged();
427 if (!qFuzzyCompare(p1: oldImplicitBackgroundHeight, p2: implicitBackgroundHeight()))
428 emit implicitBackgroundHeightChanged();
429 if (!d->background.isExecuting())
430 emit backgroundChanged();
431}
432
433/*!
434 \since QtQuick.Controls 2.3 (Qt 5.10)
435 \qmlproperty palette QtQuick.Controls::Label::palette
436
437 This property holds the palette currently set for the label.
438
439 \sa Control::palette
440*/
441QPalette QQuickLabel::palette() const
442{
443 Q_D(const QQuickLabel);
444 QPalette palette = d->resolvedPalette;
445 if (!isEnabled())
446 palette.setCurrentColorGroup(QPalette::Disabled);
447 return palette;
448}
449
450void QQuickLabel::setPalette(const QPalette &palette)
451{
452 Q_D(QQuickLabel);
453 if (d->extra.value().requestedPalette.resolve() == palette.resolve() && d->extra.value().requestedPalette == palette)
454 return;
455
456 d->extra.value().requestedPalette = palette;
457 d->resolvePalette();
458}
459
460void QQuickLabel::resetPalette()
461{
462 setPalette(QPalette());
463}
464
465/*!
466 \since QtQuick.Controls 2.5 (Qt 5.12)
467 \qmlproperty real QtQuick.Controls::Label::implicitBackgroundWidth
468 \readonly
469
470 This property holds the implicit background width.
471
472 The value is equal to \c {background ? background.implicitWidth : 0}.
473
474 \sa implicitBackgroundHeight
475*/
476qreal QQuickLabel::implicitBackgroundWidth() const
477{
478 Q_D(const QQuickLabel);
479 if (!d->background)
480 return 0;
481 return d->background->implicitWidth();
482}
483
484/*!
485 \since QtQuick.Controls 2.5 (Qt 5.12)
486 \qmlproperty real QtQuick.Controls::Label::implicitBackgroundHeight
487 \readonly
488
489 This property holds the implicit background height.
490
491 The value is equal to \c {background ? background.implicitHeight : 0}.
492
493 \sa implicitBackgroundWidth
494*/
495qreal QQuickLabel::implicitBackgroundHeight() const
496{
497 Q_D(const QQuickLabel);
498 if (!d->background)
499 return 0;
500 return d->background->implicitHeight();
501}
502
503/*!
504 \since QtQuick.Controls 2.5 (Qt 5.12)
505 \qmlproperty real QtQuick.Controls::Label::topInset
506
507 This property holds the top inset for the background.
508
509 \sa {Control Layout}, bottomInset
510*/
511qreal QQuickLabel::topInset() const
512{
513 Q_D(const QQuickLabel);
514 return d->getTopInset();
515}
516
517void QQuickLabel::setTopInset(qreal inset)
518{
519 Q_D(QQuickLabel);
520 d->setTopInset(value: inset);
521}
522
523void QQuickLabel::resetTopInset()
524{
525 Q_D(QQuickLabel);
526 d->setTopInset(value: 0, reset: true);
527}
528
529/*!
530 \since QtQuick.Controls 2.5 (Qt 5.12)
531 \qmlproperty real QtQuick.Controls::Label::leftInset
532
533 This property holds the left inset for the background.
534
535 \sa {Control Layout}, rightInset
536*/
537qreal QQuickLabel::leftInset() const
538{
539 Q_D(const QQuickLabel);
540 return d->getLeftInset();
541}
542
543void QQuickLabel::setLeftInset(qreal inset)
544{
545 Q_D(QQuickLabel);
546 d->setLeftInset(value: inset);
547}
548
549void QQuickLabel::resetLeftInset()
550{
551 Q_D(QQuickLabel);
552 d->setLeftInset(value: 0, reset: true);
553}
554
555/*!
556 \since QtQuick.Controls 2.5 (Qt 5.12)
557 \qmlproperty real QtQuick.Controls::Label::rightInset
558
559 This property holds the right inset for the background.
560
561 \sa {Control Layout}, leftInset
562*/
563qreal QQuickLabel::rightInset() const
564{
565 Q_D(const QQuickLabel);
566 return d->getRightInset();
567}
568
569void QQuickLabel::setRightInset(qreal inset)
570{
571 Q_D(QQuickLabel);
572 d->setRightInset(value: inset);
573}
574
575void QQuickLabel::resetRightInset()
576{
577 Q_D(QQuickLabel);
578 d->setRightInset(value: 0, reset: true);
579}
580
581/*!
582 \since QtQuick.Controls 2.5 (Qt 5.12)
583 \qmlproperty real QtQuick.Controls::Label::bottomInset
584
585 This property holds the bottom inset for the background.
586
587 \sa {Control Layout}, topInset
588*/
589qreal QQuickLabel::bottomInset() const
590{
591 Q_D(const QQuickLabel);
592 return d->getBottomInset();
593}
594
595void QQuickLabel::setBottomInset(qreal inset)
596{
597 Q_D(QQuickLabel);
598 d->setBottomInset(value: inset);
599}
600
601void QQuickLabel::resetBottomInset()
602{
603 Q_D(QQuickLabel);
604 d->setBottomInset(value: 0, reset: true);
605}
606
607void QQuickLabel::classBegin()
608{
609 Q_D(QQuickLabel);
610 QQuickText::classBegin();
611 d->resolveFont();
612 d->resolvePalette();
613}
614
615void QQuickLabel::componentComplete()
616{
617 Q_D(QQuickLabel);
618 d->executeBackground(complete: true);
619 QQuickText::componentComplete();
620 d->resizeBackground();
621#if QT_CONFIG(accessibility)
622 if (QAccessible::isActive())
623 d->accessibilityActiveChanged(active: true);
624#endif
625}
626
627void QQuickLabel::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
628{
629 Q_D(QQuickLabel);
630 QQuickText::itemChange(change, value);
631 switch (change) {
632 case ItemEnabledHasChanged:
633 emit paletteChanged();
634 break;
635 case ItemSceneChange:
636 case ItemParentHasChanged:
637 if ((change == ItemParentHasChanged && value.item) || (change == ItemSceneChange && value.window)) {
638 d->resolveFont();
639 d->resolvePalette();
640 }
641 break;
642 default:
643 break;
644 }
645}
646
647void QQuickLabel::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
648{
649 Q_D(QQuickLabel);
650 QQuickText::geometryChanged(newGeometry, oldGeometry);
651 d->resizeBackground();
652}
653
654void QQuickLabel::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
655{
656 Q_D(QQuickLabel);
657 Q_UNUSED(newInset);
658 Q_UNUSED(oldInset);
659 d->resizeBackground();
660}
661
662QT_END_NAMESPACE
663

source code of qtquickcontrols2/src/quicktemplates2/qquicklabel.cpp