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
qquickiconlabel.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
9
10#include <QtGui/private/qguiapplication_p.h>
11#include <QtQuick/private/qquickitem_p.h>
12#include <QtQuick/private/qquicktext_p.h>
13#include <QtQuickTemplates2/private/qquickicon_p.h>
14#include <QtQuickTemplates2/private/qquickicon_p_p.h>
15
17
18void QQuickIconLabelPrivate::beginClass(QQuickItem *item)
19{
20 if (QQmlParserStatus *parserStatus = qobject_cast<QQmlParserStatus *>(item))
21 parserStatus->classBegin();
22}
23
24void QQuickIconLabelPrivate::completeComponent(QQuickItem *item)
25{
26 if (QQmlParserStatus *parserStatus = qobject_cast<QQmlParserStatus *>(item))
27 parserStatus->componentComplete();
28}
29
30QQuickIconLabelPrivate::~QQuickIconLabelPrivate() = default;
31
32bool QQuickIconLabelPrivate::hasIcon() const
33{
34 return display != QQuickIconLabel::TextOnly && !icon.isEmpty();
35}
36
37bool QQuickIconLabelPrivate::hasText() const
38{
39 return display != QQuickIconLabel::IconOnly && !text.isEmpty();
40}
41
42bool QQuickIconLabelPrivate::createImage()
43{
44 Q_Q(QQuickIconLabel);
45 if (image)
46 return false;
47
48 image = new QQuickIconImage(q);
49 watchChanges(image);
50 beginClass(image);
51 image->setObjectName(QStringLiteral("image"));
52 image->setName(icon.name());
53 image->setSource(icon.resolvedSource());
54 image->setSourceSize(QSize(icon.width(), icon.height()));
55 const bool explicitColor = QQuickIconPrivate::isResolved(icon, QQuickIconPrivate::ColorResolved);
56 image->setColor(explicitColor ? icon.color() : defaultIconColor);
57 image->setCache(icon.cache());
58 QQmlEngine::setContextForObject(image, qmlContext(q));
59 if (componentComplete)
60 completeComponent(image);
61 return true;
62}
63
64bool QQuickIconLabelPrivate::destroyImage()
65{
66 if (!image)
67 return false;
68
69 unwatchChanges(image);
70 delete image;
71 image = nullptr;
72 return true;
73}
74
75bool QQuickIconLabelPrivate::updateImage()
76{
77 if (!hasIcon())
78 return destroyImage();
79 return createImage();
80}
81
82void QQuickIconLabelPrivate::syncImage()
83{
84 if (!image || icon.isEmpty())
85 return;
86
87 image->setName(icon.name());
88 image->setSource(icon.resolvedSource());
89 image->setSourceSize(QSize(icon.width(), icon.height()));
90 const bool explicitColor = QQuickIconPrivate::isResolved(icon, QQuickIconPrivate::ColorResolved);
91 image->setColor(explicitColor ? icon.color() : defaultIconColor);
92 image->setCache(icon.cache());
93 const int valign = alignment & Qt::AlignVertical_Mask;
94 image->setVerticalAlignment(static_cast<QQuickImage::VAlignment>(valign));
95 const int halign = alignment & Qt::AlignHorizontal_Mask;
96 image->setHorizontalAlignment(static_cast<QQuickImage::HAlignment>(halign));
97}
98
99void QQuickIconLabelPrivate::updateOrSyncImage()
100{
101 if (updateImage()) {
102 if (componentComplete) {
103 updateImplicitSize();
104 layout();
105 }
106 } else {
107 syncImage();
108 }
109}
110
111bool QQuickIconLabelPrivate::createLabel()
112{
113 Q_Q(QQuickIconLabel);
114 if (label)
115 return false;
116
117 label = new QQuickMnemonicLabel(q);
118 label->setMnemonicEnabled(mnemonicEnabled);
119 watchChanges(label);
120 beginClass(label);
121 label->setObjectName(QStringLiteral("label"));
122 label->setFont(font);
123 label->setColor(color);
124 label->setElideMode(QQuickText::ElideRight);
125 const int valign = alignment & Qt::AlignVertical_Mask;
126 label->setVAlign(static_cast<QQuickText::VAlignment>(valign));
127 const int halign = alignment & Qt::AlignHorizontal_Mask;
128 label->setHAlign(static_cast<QQuickText::HAlignment>(halign));
129 label->setText(text);
130 if (componentComplete)
131 completeComponent(label);
132 return true;
133}
134
135bool QQuickIconLabelPrivate::destroyLabel()
136{
137 if (!label)
138 return false;
139
140 unwatchChanges(label);
141 delete label;
142 label = nullptr;
143 return true;
144}
145
146bool QQuickIconLabelPrivate::updateLabel()
147{
148 if (!hasText())
149 return destroyLabel();
150 return createLabel();
151}
152
153void QQuickIconLabelPrivate::syncLabel()
154{
155 if (!label)
156 return;
157
158 label->setText(text);
159}
160
161void QQuickIconLabelPrivate::updateOrSyncLabel()
162{
163 if (updateLabel()) {
164 if (componentComplete) {
165 updateImplicitSize();
166 layout();
167 }
168 } else {
169 syncLabel();
170 }
171}
172
173void QQuickIconLabelPrivate::updateImplicitSize()
174{
175 Q_Q(QQuickIconLabel);
176 const bool showIcon = image && hasIcon();
177 const bool showText = label && hasText();
178 const qreal horizontalPadding = leftPadding + rightPadding;
179 const qreal verticalPadding = topPadding + bottomPadding;
180 const qreal iconImplicitWidth = showIcon ? image->implicitWidth() : 0;
181 const qreal iconImplicitHeight = showIcon ? image->implicitHeight() : 0;
182 const qreal textImplicitWidth = showText ? label->implicitWidth() : 0;
183 const qreal textImplicitHeight = showText ? label->implicitHeight() : 0;
184 const qreal effectiveSpacing = showText && showIcon && image->implicitWidth() > 0 ? spacing : 0;
185 const qreal implicitWidth = display == QQuickIconLabel::TextBesideIcon ? iconImplicitWidth + textImplicitWidth + effectiveSpacing
186 : qMax(iconImplicitWidth, textImplicitWidth);
187 const qreal implicitHeight = display == QQuickIconLabel::TextUnderIcon ? iconImplicitHeight + textImplicitHeight + effectiveSpacing
188 : qMax(iconImplicitHeight, textImplicitHeight);
189 q->setImplicitSize(implicitWidth + horizontalPadding, implicitHeight + verticalPadding);
190}
191
192// adapted from QStyle::alignedRect()
193QRectF QQuickIconLabelPrivate::alignedRect(bool mirrored, Qt::Alignment alignment,
194 const QSizeF &size, const QRectF &rectangle)
195{
196 alignment = QGuiApplicationPrivate::visualAlignment(mirrored ? Qt::RightToLeft : Qt::LeftToRight, alignment);
197 qreal x = rectangle.x();
198 qreal y = rectangle.y();
199 const qreal w = size.width();
200 const qreal h = size.height();
201 if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
202 y += rectangle.height() / 2 - h / 2;
203 else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
204 y += rectangle.height() - h;
205 if ((alignment & Qt::AlignRight) == Qt::AlignRight)
206 x += rectangle.width() - w;
207 else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
208 x += rectangle.width() / 2 - w / 2;
209 return QRectF(x, y, w, h);
210}
211
212void QQuickIconLabelPrivate::layout()
213{
214 Q_Q(QQuickIconLabel);
215 if (!componentComplete)
216 return;
217
218 const qreal availableWidth = width - leftPadding - rightPadding;
219 const qreal availableHeight = height - topPadding - bottomPadding;
220
221 switch (display) {
222 case QQuickIconLabel::IconOnly:
223 if (image) {
224 const QRectF iconRect = alignedRect(mirrored, alignment,
225 QSizeF(qMin(image->implicitWidth(), availableWidth),
226 qMin(image->implicitHeight(), availableHeight)),
227 QRectF(leftPadding, topPadding, availableWidth, availableHeight));
228 image->setSize(iconRect.size());
229 image->snapPositionTo(iconRect.topLeft());
230 }
231 break;
232 case QQuickIconLabel::TextOnly:
233 if (label) {
234 const QRectF textRect = alignedRect(mirrored, alignment,
235 QSizeF(qMin(label->implicitWidth(), availableWidth),
236 qMin(label->implicitHeight(), availableHeight)),
237 QRectF(leftPadding, topPadding, availableWidth, availableHeight));
238 label->setSize(textRect.size());
239 label->setPosition(textRect.topLeft());
240 }
241 break;
242
243 case QQuickIconLabel::TextUnderIcon: {
244 // Work out the sizes first, as the positions depend on them.
245 QSizeF iconSize;
246 QSizeF textSize;
247 if (image) {
248 iconSize.setWidth(qMin(image->implicitWidth(), availableWidth));
249 iconSize.setHeight(qMin(image->implicitHeight(), availableHeight));
250 }
251 qreal effectiveSpacing = 0;
252 if (label) {
253 if (!iconSize.isEmpty())
254 effectiveSpacing = spacing;
255 textSize.setWidth(qMin(label->implicitWidth(), availableWidth));
256 textSize.setHeight(qMin(label->implicitHeight(), availableHeight - iconSize.height() - effectiveSpacing));
257 }
258
259 QRectF combinedRect = alignedRect(mirrored, alignment,
260 QSizeF(qMax(iconSize.width(), textSize.width()),
261 iconSize.height() + effectiveSpacing + textSize.height()),
262 QRectF(leftPadding, topPadding, availableWidth, availableHeight));
263 if (image) {
264 QRectF iconRect = alignedRect(mirrored, Qt::AlignHCenter | Qt::AlignTop, iconSize, combinedRect);
265 image->setSize(iconRect.size());
266 image->snapPositionTo(iconRect.topLeft());
267 }
268 if (label) {
269 QRectF textRect = alignedRect(mirrored, Qt::AlignHCenter | Qt::AlignBottom, textSize, combinedRect);
270 label->setSize(textRect.size());
271 label->setPosition(textRect.topLeft());
272 }
273 break;
274 }
275
276 case QQuickIconLabel::TextBesideIcon:
277 default:
278 // Work out the sizes first, as the positions depend on them.
279 QSizeF iconSize(0, 0);
280 QSizeF textSize(0, 0);
281 if (image) {
282 iconSize.setWidth(qMin(image->implicitWidth(), availableWidth));
283 iconSize.setHeight(qMin(image->implicitHeight(), availableHeight));
284 }
285 qreal effectiveSpacing = 0;
286 if (label) {
287 if (!iconSize.isEmpty())
288 effectiveSpacing = spacing;
289 textSize.setWidth(qMin(label->implicitWidth(), availableWidth - iconSize.width() - effectiveSpacing));
290 textSize.setHeight(qMin(label->implicitHeight(), availableHeight));
291 }
292
293 const QRectF combinedRect = alignedRect(mirrored, alignment,
294 QSizeF(iconSize.width() + effectiveSpacing + textSize.width(),
295 qMax(iconSize.height(), textSize.height())),
296 QRectF(leftPadding, topPadding, availableWidth, availableHeight));
297 if (image) {
298 const QRectF iconRect = alignedRect(mirrored, Qt::AlignLeft | Qt::AlignVCenter, iconSize, combinedRect);
299 image->setSize(iconRect.size());
300 image->snapPositionTo(iconRect.topLeft());
301 }
302 if (label) {
303 const QRectF textRect = alignedRect(mirrored, Qt::AlignRight | Qt::AlignVCenter, textSize, combinedRect);
304 label->setSize(textRect.size());
305 label->setPosition(textRect.topLeft());
306 }
307 break;
308 }
309
310 q->setBaselineOffset(label ? label->y() + label->baselineOffset() : 0);
311}
312
314 QQuickItemPrivate::ImplicitWidth
315 | QQuickItemPrivate::ImplicitHeight
316 | QQuickItemPrivate::Destroyed;
317
318void QQuickIconLabelPrivate::watchChanges(QQuickItem *item)
319{
320 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
321 itemPrivate->addItemChangeListener(this, itemChangeTypes);
322}
323
324void QQuickIconLabelPrivate::unwatchChanges(QQuickItem* item)
325{
326 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
327 itemPrivate->removeItemChangeListener(this, itemChangeTypes);
328}
329
330void QQuickIconLabelPrivate::itemImplicitWidthChanged(QQuickItem *)
331{
332 updateImplicitSize();
333 layout();
334}
335
336void QQuickIconLabelPrivate::itemImplicitHeightChanged(QQuickItem *)
337{
338 updateImplicitSize();
339 layout();
340}
341
342void QQuickIconLabelPrivate::itemDestroyed(QQuickItem *item)
343{
344 unwatchChanges(item);
345 if (item == image)
346 image = nullptr;
347 else if (item == label)
348 label = nullptr;
349}
350
351void QQuickIconLabelPrivate::textChange()
352{
353}
354
355void QQuickIconLabelPrivate::displayChange()
356{
357}
358
359QQuickIconLabel::QQuickIconLabel(QQuickItem *parent)
360 : QQuickItem(*(new QQuickIconLabelPrivate), parent)
361{
362}
363
364QQuickIconLabel::QQuickIconLabel(QQuickIconLabelPrivate &dd, QQuickItem *parent)
365 : QQuickItem(dd, parent)
366{
367}
368
369QQuickIconLabel::~QQuickIconLabel()
370{
371 Q_D(QQuickIconLabel);
372 if (d->image)
373 d->unwatchChanges(d->image);
374 if (d->label)
375 d->unwatchChanges(d->label);
376}
377
378QQuickIcon QQuickIconLabel::icon() const
379{
380 Q_D(const QQuickIconLabel);
381 return d->icon;
382}
383
384void QQuickIconLabel::setIcon(const QQuickIcon &icon)
385{
386 Q_D(QQuickIconLabel);
387 if (d->icon == icon)
388 return;
389
390 d->icon = icon;
391 d->icon.ensureRelativeSourceResolved(this);
392 d->updateOrSyncImage();
393}
394
395/*!
396 \internal
397
398 The icon property of the control always takes precedence over that of an
399 action's (see 146bc9517c56feda4eba34282d3cc53bd47b6267). However, styles
400 also need to be able to set their default icon color.
401
402 This property allows styles to specify a color for the image without
403 overriding any potential action's icon:
404
405 \code
406 contentItem: IconLabel {
407 icon: control.icon
408 defaultIconColor: "tomato
409 }
410 \endcode
411
412 If icon.color was explicitly set, it is used instead.
414QColor QQuickIconLabel::defaultIconColor() const
415{
416 Q_D(const QQuickIconLabel);
417 return d->defaultIconColor;
418}
420void QQuickIconLabel::setDefaultIconColor(const QColor &defaultIconColor)
421{
422 Q_D(QQuickIconLabel);
423 d->defaultIconColor = defaultIconColor;
424 d->syncImage();
425 emit defaultIconColorChanged();
426}
428QString QQuickIconLabel::text() const
429{
430 Q_D(const QQuickIconLabel);
431 return d->text;
432}
434void QQuickIconLabel::setText(const QString &text)
435{
436 Q_D(QQuickIconLabel);
437 if (d->text == text)
438 return;
439
440 d->text = text;
441 d->textChange();
442 d->updateOrSyncLabel();
443}
445QFont QQuickIconLabel::font() const
446{
447 Q_D(const QQuickIconLabel);
448 return d->font;
449}
451void QQuickIconLabel::setFont(const QFont &font)
452{
453 Q_D(QQuickIconLabel);
454 if (d->font == font)
455 return;
456
457 d->font = font;
458 if (d->label)
459 d->label->setFont(font);
460}
462QColor QQuickIconLabel::color() const
463{
464 Q_D(const QQuickIconLabel);
465 return d->color;
466}
468void QQuickIconLabel::setColor(const QColor &color)
469{
470 Q_D(QQuickIconLabel);
471 if (d->color == color)
472 return;
473
474 d->color = color;
475 if (d->label)
476 d->label->setColor(color);
477}
479QQuickIconLabel::Display QQuickIconLabel::display() const
480{
481 Q_D(const QQuickIconLabel);
482 return d->display;
483}
485void QQuickIconLabel::setDisplay(Display display)
486{
487 Q_D(QQuickIconLabel);
488 if (d->display == display)
489 return;
490
491 d->display = display;
492 d->displayChange();
493 d->updateImage();
494 d->updateLabel();
495 d->updateImplicitSize();
496 d->layout();
497}
499qreal QQuickIconLabel::spacing() const
500{
501 Q_D(const QQuickIconLabel);
502 return d->spacing;
503}
505void QQuickIconLabel::setSpacing(qreal spacing)
506{
507 Q_D(QQuickIconLabel);
508 if (qFuzzyCompare(d->spacing, spacing))
509 return;
510
511 d->spacing = spacing;
512 if (d->image && d->label) {
513 d->updateImplicitSize();
514 d->layout();
515 }
516}
518bool QQuickIconLabel::isMirrored() const
519{
520 Q_D(const QQuickIconLabel);
521 return d->mirrored;
522}
524void QQuickIconLabel::setMirrored(bool mirrored)
525{
526 Q_D(QQuickIconLabel);
527 if (d->mirrored == mirrored)
528 return;
529
530 d->mirrored = mirrored;
531 d->layout();
532}
534Qt::Alignment QQuickIconLabel::alignment() const
535{
536 Q_D(const QQuickIconLabel);
537 return d->alignment;
538}
540void QQuickIconLabel::setAlignment(Qt::Alignment alignment)
541{
542 Q_D(QQuickIconLabel);
543 const int valign = alignment & Qt::AlignVertical_Mask;
544 const int halign = alignment & Qt::AlignHorizontal_Mask;
545 const uint align = (valign ? valign : Qt::AlignVCenter) | (halign ? halign : Qt::AlignHCenter);
546 if (d->alignment == align)
547 return;
548
549 d->alignment = static_cast<Qt::Alignment>(align);
550 if (d->label) {
551 d->label->setVAlign(static_cast<QQuickText::VAlignment>(valign));
552 d->label->setHAlign(static_cast<QQuickText::HAlignment>(halign));
553 }
554 if (d->image) {
555 d->image->setVerticalAlignment(static_cast<QQuickImage::VAlignment>(valign));
556 d->image->setHorizontalAlignment(static_cast<QQuickImage::HAlignment>(halign));
557 }
558 d->layout();
559}
561qreal QQuickIconLabel::topPadding() const
562{
563 Q_D(const QQuickIconLabel);
564 return d->topPadding;
565}
567void QQuickIconLabel::setTopPadding(qreal padding)
568{
569 Q_D(QQuickIconLabel);
570 if (qFuzzyCompare(d->topPadding, padding))
571 return;
572
573 d->topPadding = padding;
574 d->updateImplicitSize();
575 d->layout();
576}
578void QQuickIconLabel::resetTopPadding()
579{
580 setTopPadding(0);
581}
583qreal QQuickIconLabel::leftPadding() const
584{
585 Q_D(const QQuickIconLabel);
586 return d->leftPadding;
587}
589void QQuickIconLabel::setLeftPadding(qreal padding)
590{
591 Q_D(QQuickIconLabel);
592 if (qFuzzyCompare(d->leftPadding, padding))
593 return;
594
595 d->leftPadding = padding;
596 d->updateImplicitSize();
597 d->layout();
598}
600void QQuickIconLabel::resetLeftPadding()
601{
602 setLeftPadding(0);
603}
605qreal QQuickIconLabel::rightPadding() const
606{
607 Q_D(const QQuickIconLabel);
608 return d->rightPadding;
609}
611void QQuickIconLabel::setRightPadding(qreal padding)
612{
613 Q_D(QQuickIconLabel);
614 if (qFuzzyCompare(d->rightPadding, padding))
615 return;
616
617 d->rightPadding = padding;
618 d->updateImplicitSize();
619 d->layout();
620}
622void QQuickIconLabel::resetRightPadding()
623{
624 setRightPadding(0);
625}
627qreal QQuickIconLabel::bottomPadding() const
628{
629 Q_D(const QQuickIconLabel);
630 return d->bottomPadding;
631}
633void QQuickIconLabel::setBottomPadding(qreal padding)
634{
635 Q_D(QQuickIconLabel);
636 if (qFuzzyCompare(d->bottomPadding, padding))
637 return;
638
639 d->bottomPadding = padding;
640 d->updateImplicitSize();
641 d->layout();
642}
644void QQuickIconLabel::resetBottomPadding()
645{
646 setBottomPadding(0);
647}
648
649/*!
650 \internal
651
652 This property determines whether \c "&" in \l text is treated as a
653 mnemonic marker (\c true) or displayed literally (\c false).
654
655 It is forwarded directly to the underlying QQuickMnemonicLabel's own
656 \l {QQuickMnemonicLabel::mnemonicEnabled}{mnemonicEnabled} property.
657 See its documentation for the effect this has on the displayed text.
659bool QQuickIconLabel::isMnemonicEnabled() const
660{
661 Q_D(const QQuickIconLabel);
662 return d->mnemonicEnabled;
663}
665void QQuickIconLabel::setMnemonicEnabled(bool mnemonicEnabled)
666{
667 Q_D(QQuickIconLabel);
668 if (d->mnemonicEnabled == mnemonicEnabled)
669 return;
670
671 d->mnemonicEnabled = mnemonicEnabled;
672 if (d->label)
673 d->label->setMnemonicEnabled(mnemonicEnabled);
674 d->updateImplicitSize();
675 d->layout();
676}
678void QQuickIconLabel::componentComplete()
679{
680 Q_D(QQuickIconLabel);
681 if (d->image)
682 QQuickIconLabelPrivate::completeComponent(d->image);
683 if (d->label)
684 QQuickIconLabelPrivate::completeComponent(d->label);
685 QQuickItem::componentComplete();
686 d->layout();
687
688 // Any items declared as children of us will be parented before the label and icon image,
689 // so they will be drawn below us. This is not intuitive, so move us to the bottom of the pile.
690 const auto paintOrderChildItems = QQuickItemPrivate::get(this)->paintOrderChildItems();
691 const auto bottomMostFosterChildIt = std::find_if(paintOrderChildItems.constBegin(),
692 paintOrderChildItems.constEnd(), [d](QQuickItem *item) {
693 return item != d->label && item != d->image;
694 });
695 if (bottomMostFosterChildIt != paintOrderChildItems.constEnd()) {
696 const QQuickItem *bottomMostFosterChild = *bottomMostFosterChildIt;
697 if (d->label)
698 d->label->stackBefore(bottomMostFosterChild);
699 if (d->image)
700 d->image->stackBefore(bottomMostFosterChild);
701 }
702}
704void QQuickIconLabel::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
705{
706 Q_D(QQuickIconLabel);
707 QQuickItem::geometryChange(newGeometry, oldGeometry);
708 d->layout();
709}
710
711QT_END_NAMESPACE
712
713#include "moc_qquickiconlabel_p.cpp"
Combined button and popup list for selecting options.
static const QQuickItemPrivate::ChangeTypes itemChangeTypes