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 watchChanges(label);
119 beginClass(label);
120 label->setObjectName(QStringLiteral("label"));
121 label->setFont(font);
122 label->setColor(color);
123 label->setElideMode(QQuickText::ElideRight);
124 const int valign = alignment & Qt::AlignVertical_Mask;
125 label->setVAlign(static_cast<QQuickText::VAlignment>(valign));
126 const int halign = alignment & Qt::AlignHorizontal_Mask;
127 label->setHAlign(static_cast<QQuickText::HAlignment>(halign));
128 label->setText(text);
129 if (componentComplete)
130 completeComponent(label);
131 return true;
132}
133
134bool QQuickIconLabelPrivate::destroyLabel()
135{
136 if (!label)
137 return false;
138
139 unwatchChanges(label);
140 delete label;
141 label = nullptr;
142 return true;
143}
144
145bool QQuickIconLabelPrivate::updateLabel()
146{
147 if (!hasText())
148 return destroyLabel();
149 return createLabel();
150}
151
152void QQuickIconLabelPrivate::syncLabel()
153{
154 if (!label)
155 return;
156
157 label->setText(text);
158}
159
160void QQuickIconLabelPrivate::updateOrSyncLabel()
161{
162 if (updateLabel()) {
163 if (componentComplete) {
164 updateImplicitSize();
165 layout();
166 }
167 } else {
168 syncLabel();
169 }
170}
171
172void QQuickIconLabelPrivate::updateImplicitSize()
173{
174 Q_Q(QQuickIconLabel);
175 const bool showIcon = image && hasIcon();
176 const bool showText = label && hasText();
177 const qreal horizontalPadding = leftPadding + rightPadding;
178 const qreal verticalPadding = topPadding + bottomPadding;
179 const qreal iconImplicitWidth = showIcon ? image->implicitWidth() : 0;
180 const qreal iconImplicitHeight = showIcon ? image->implicitHeight() : 0;
181 const qreal textImplicitWidth = showText ? label->implicitWidth() : 0;
182 const qreal textImplicitHeight = showText ? label->implicitHeight() : 0;
183 const qreal effectiveSpacing = showText && showIcon && image->implicitWidth() > 0 ? spacing : 0;
184 const qreal implicitWidth = display == QQuickIconLabel::TextBesideIcon ? iconImplicitWidth + textImplicitWidth + effectiveSpacing
185 : qMax(iconImplicitWidth, textImplicitWidth);
186 const qreal implicitHeight = display == QQuickIconLabel::TextUnderIcon ? iconImplicitHeight + textImplicitHeight + effectiveSpacing
187 : qMax(iconImplicitHeight, textImplicitHeight);
188 q->setImplicitSize(implicitWidth + horizontalPadding, implicitHeight + verticalPadding);
189}
190
191// adapted from QStyle::alignedRect()
192QRectF QQuickIconLabelPrivate::alignedRect(bool mirrored, Qt::Alignment alignment,
193 const QSizeF &size, const QRectF &rectangle)
194{
195 alignment = QGuiApplicationPrivate::visualAlignment(mirrored ? Qt::RightToLeft : Qt::LeftToRight, alignment);
196 qreal x = rectangle.x();
197 qreal y = rectangle.y();
198 const qreal w = size.width();
199 const qreal h = size.height();
200 if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
201 y += rectangle.height() / 2 - h / 2;
202 else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
203 y += rectangle.height() - h;
204 if ((alignment & Qt::AlignRight) == Qt::AlignRight)
205 x += rectangle.width() - w;
206 else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
207 x += rectangle.width() / 2 - w / 2;
208 return QRectF(x, y, w, h);
209}
210
211void QQuickIconLabelPrivate::layout()
212{
213 Q_Q(QQuickIconLabel);
214 if (!componentComplete)
215 return;
216
217 const qreal availableWidth = width - leftPadding - rightPadding;
218 const qreal availableHeight = height - topPadding - bottomPadding;
219
220 switch (display) {
221 case QQuickIconLabel::IconOnly:
222 if (image) {
223 const QRectF iconRect = alignedRect(mirrored, alignment,
224 QSizeF(qMin(image->implicitWidth(), availableWidth),
225 qMin(image->implicitHeight(), availableHeight)),
226 QRectF(leftPadding, topPadding, availableWidth, availableHeight));
227 image->setSize(iconRect.size());
228 image->snapPositionTo(iconRect.topLeft());
229 }
230 break;
231 case QQuickIconLabel::TextOnly:
232 if (label) {
233 const QRectF textRect = alignedRect(mirrored, alignment,
234 QSizeF(qMin(label->implicitWidth(), availableWidth),
235 qMin(label->implicitHeight(), availableHeight)),
236 QRectF(leftPadding, topPadding, availableWidth, availableHeight));
237 label->setSize(textRect.size());
238 label->setPosition(textRect.topLeft());
239 }
240 break;
241
242 case QQuickIconLabel::TextUnderIcon: {
243 // Work out the sizes first, as the positions depend on them.
244 QSizeF iconSize;
245 QSizeF textSize;
246 if (image) {
247 iconSize.setWidth(qMin(image->implicitWidth(), availableWidth));
248 iconSize.setHeight(qMin(image->implicitHeight(), availableHeight));
249 }
250 qreal effectiveSpacing = 0;
251 if (label) {
252 if (!iconSize.isEmpty())
253 effectiveSpacing = spacing;
254 textSize.setWidth(qMin(label->implicitWidth(), availableWidth));
255 textSize.setHeight(qMin(label->implicitHeight(), availableHeight - iconSize.height() - effectiveSpacing));
256 }
257
258 QRectF combinedRect = alignedRect(mirrored, alignment,
259 QSizeF(qMax(iconSize.width(), textSize.width()),
260 iconSize.height() + effectiveSpacing + textSize.height()),
261 QRectF(leftPadding, topPadding, availableWidth, availableHeight));
262 if (image) {
263 QRectF iconRect = alignedRect(mirrored, Qt::AlignHCenter | Qt::AlignTop, iconSize, combinedRect);
264 image->setSize(iconRect.size());
265 image->snapPositionTo(iconRect.topLeft());
266 }
267 if (label) {
268 QRectF textRect = alignedRect(mirrored, Qt::AlignHCenter | Qt::AlignBottom, textSize, combinedRect);
269 label->setSize(textRect.size());
270 label->setPosition(textRect.topLeft());
271 }
272 break;
273 }
274
275 case QQuickIconLabel::TextBesideIcon:
276 default:
277 // Work out the sizes first, as the positions depend on them.
278 QSizeF iconSize(0, 0);
279 QSizeF textSize(0, 0);
280 if (image) {
281 iconSize.setWidth(qMin(image->implicitWidth(), availableWidth));
282 iconSize.setHeight(qMin(image->implicitHeight(), availableHeight));
283 }
284 qreal effectiveSpacing = 0;
285 if (label) {
286 if (!iconSize.isEmpty())
287 effectiveSpacing = spacing;
288 textSize.setWidth(qMin(label->implicitWidth(), availableWidth - iconSize.width() - effectiveSpacing));
289 textSize.setHeight(qMin(label->implicitHeight(), availableHeight));
290 }
291
292 const QRectF combinedRect = alignedRect(mirrored, alignment,
293 QSizeF(iconSize.width() + effectiveSpacing + textSize.width(),
294 qMax(iconSize.height(), textSize.height())),
295 QRectF(leftPadding, topPadding, availableWidth, availableHeight));
296 if (image) {
297 const QRectF iconRect = alignedRect(mirrored, Qt::AlignLeft | Qt::AlignVCenter, iconSize, combinedRect);
298 image->setSize(iconRect.size());
299 image->snapPositionTo(iconRect.topLeft());
300 }
301 if (label) {
302 const QRectF textRect = alignedRect(mirrored, Qt::AlignRight | Qt::AlignVCenter, textSize, combinedRect);
303 label->setSize(textRect.size());
304 label->setPosition(textRect.topLeft());
305 }
306 break;
307 }
308
309 q->setBaselineOffset(label ? label->y() + label->baselineOffset() : 0);
310}
311
313 QQuickItemPrivate::ImplicitWidth
314 | QQuickItemPrivate::ImplicitHeight
315 | QQuickItemPrivate::Destroyed;
316
317void QQuickIconLabelPrivate::watchChanges(QQuickItem *item)
318{
319 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
320 itemPrivate->addItemChangeListener(this, itemChangeTypes);
321}
322
323void QQuickIconLabelPrivate::unwatchChanges(QQuickItem* item)
324{
325 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
326 itemPrivate->removeItemChangeListener(this, itemChangeTypes);
327}
328
329void QQuickIconLabelPrivate::itemImplicitWidthChanged(QQuickItem *)
330{
331 updateImplicitSize();
332 layout();
333}
334
335void QQuickIconLabelPrivate::itemImplicitHeightChanged(QQuickItem *)
336{
337 updateImplicitSize();
338 layout();
339}
340
341void QQuickIconLabelPrivate::itemDestroyed(QQuickItem *item)
342{
343 unwatchChanges(item);
344 if (item == image)
345 image = nullptr;
346 else if (item == label)
347 label = nullptr;
348}
349
350void QQuickIconLabelPrivate::textChange()
351{
352}
353
354void QQuickIconLabelPrivate::displayChange()
355{
356}
357
358QQuickIconLabel::QQuickIconLabel(QQuickItem *parent)
359 : QQuickItem(*(new QQuickIconLabelPrivate), parent)
360{
361}
362
363QQuickIconLabel::QQuickIconLabel(QQuickIconLabelPrivate &dd, QQuickItem *parent)
364 : QQuickItem(dd, parent)
365{
366}
367
368QQuickIconLabel::~QQuickIconLabel()
369{
370 Q_D(QQuickIconLabel);
371 if (d->image)
372 d->unwatchChanges(d->image);
373 if (d->label)
374 d->unwatchChanges(d->label);
375}
376
377QQuickIcon QQuickIconLabel::icon() const
378{
379 Q_D(const QQuickIconLabel);
380 return d->icon;
381}
382
383void QQuickIconLabel::setIcon(const QQuickIcon &icon)
384{
385 Q_D(QQuickIconLabel);
386 if (d->icon == icon)
387 return;
388
389 d->icon = icon;
390 d->icon.ensureRelativeSourceResolved(this);
391 d->updateOrSyncImage();
392}
393
394/*!
395 \internal
396
397 The icon property of the control always takes precedence over that of an
398 action's (see 146bc9517c56feda4eba34282d3cc53bd47b6267). However, styles
399 also need to be able to set their default icon color.
400
401 This property allows styles to specify a color for the image without
402 overriding any potential action's icon:
403
404 \code
405 contentItem: IconLabel {
406 icon: control.icon
407 defaultIconColor: "tomato
408 }
409 \endcode
410
411 If icon.color was explicitly set, it is used instead.
413QColor QQuickIconLabel::defaultIconColor() const
414{
415 Q_D(const QQuickIconLabel);
416 return d->defaultIconColor;
417}
419void QQuickIconLabel::setDefaultIconColor(const QColor &defaultIconColor)
420{
421 Q_D(QQuickIconLabel);
422 d->defaultIconColor = defaultIconColor;
423 d->syncImage();
424 emit defaultIconColorChanged();
425}
427QString QQuickIconLabel::text() const
428{
429 Q_D(const QQuickIconLabel);
430 return d->text;
431}
433void QQuickIconLabel::setText(const QString &text)
434{
435 Q_D(QQuickIconLabel);
436 if (d->text == text)
437 return;
438
439 d->text = text;
440 d->textChange();
441 d->updateOrSyncLabel();
442}
444QFont QQuickIconLabel::font() const
445{
446 Q_D(const QQuickIconLabel);
447 return d->font;
448}
450void QQuickIconLabel::setFont(const QFont &font)
451{
452 Q_D(QQuickIconLabel);
453 if (d->font == font)
454 return;
455
456 d->font = font;
457 if (d->label)
458 d->label->setFont(font);
459}
461QColor QQuickIconLabel::color() const
462{
463 Q_D(const QQuickIconLabel);
464 return d->color;
465}
467void QQuickIconLabel::setColor(const QColor &color)
468{
469 Q_D(QQuickIconLabel);
470 if (d->color == color)
471 return;
472
473 d->color = color;
474 if (d->label)
475 d->label->setColor(color);
476}
478QQuickIconLabel::Display QQuickIconLabel::display() const
479{
480 Q_D(const QQuickIconLabel);
481 return d->display;
482}
484void QQuickIconLabel::setDisplay(Display display)
485{
486 Q_D(QQuickIconLabel);
487 if (d->display == display)
488 return;
489
490 d->display = display;
491 d->displayChange();
492 d->updateImage();
493 d->updateLabel();
494 d->updateImplicitSize();
495 d->layout();
496}
498qreal QQuickIconLabel::spacing() const
499{
500 Q_D(const QQuickIconLabel);
501 return d->spacing;
502}
504void QQuickIconLabel::setSpacing(qreal spacing)
505{
506 Q_D(QQuickIconLabel);
507 if (qFuzzyCompare(d->spacing, spacing))
508 return;
509
510 d->spacing = spacing;
511 if (d->image && d->label) {
512 d->updateImplicitSize();
513 d->layout();
514 }
515}
517bool QQuickIconLabel::isMirrored() const
518{
519 Q_D(const QQuickIconLabel);
520 return d->mirrored;
521}
523void QQuickIconLabel::setMirrored(bool mirrored)
524{
525 Q_D(QQuickIconLabel);
526 if (d->mirrored == mirrored)
527 return;
528
529 d->mirrored = mirrored;
530 d->layout();
531}
533Qt::Alignment QQuickIconLabel::alignment() const
534{
535 Q_D(const QQuickIconLabel);
536 return d->alignment;
537}
539void QQuickIconLabel::setAlignment(Qt::Alignment alignment)
540{
541 Q_D(QQuickIconLabel);
542 const int valign = alignment & Qt::AlignVertical_Mask;
543 const int halign = alignment & Qt::AlignHorizontal_Mask;
544 const uint align = (valign ? valign : Qt::AlignVCenter) | (halign ? halign : Qt::AlignHCenter);
545 if (d->alignment == align)
546 return;
547
548 d->alignment = static_cast<Qt::Alignment>(align);
549 if (d->label) {
550 d->label->setVAlign(static_cast<QQuickText::VAlignment>(valign));
551 d->label->setHAlign(static_cast<QQuickText::HAlignment>(halign));
552 }
553 if (d->image) {
554 d->image->setVerticalAlignment(static_cast<QQuickImage::VAlignment>(valign));
555 d->image->setHorizontalAlignment(static_cast<QQuickImage::HAlignment>(halign));
556 }
557 d->layout();
558}
560qreal QQuickIconLabel::topPadding() const
561{
562 Q_D(const QQuickIconLabel);
563 return d->topPadding;
564}
566void QQuickIconLabel::setTopPadding(qreal padding)
567{
568 Q_D(QQuickIconLabel);
569 if (qFuzzyCompare(d->topPadding, padding))
570 return;
571
572 d->topPadding = padding;
573 d->updateImplicitSize();
574 d->layout();
575}
577void QQuickIconLabel::resetTopPadding()
578{
579 setTopPadding(0);
580}
582qreal QQuickIconLabel::leftPadding() const
583{
584 Q_D(const QQuickIconLabel);
585 return d->leftPadding;
586}
588void QQuickIconLabel::setLeftPadding(qreal padding)
589{
590 Q_D(QQuickIconLabel);
591 if (qFuzzyCompare(d->leftPadding, padding))
592 return;
593
594 d->leftPadding = padding;
595 d->updateImplicitSize();
596 d->layout();
597}
599void QQuickIconLabel::resetLeftPadding()
600{
601 setLeftPadding(0);
602}
604qreal QQuickIconLabel::rightPadding() const
605{
606 Q_D(const QQuickIconLabel);
607 return d->rightPadding;
608}
610void QQuickIconLabel::setRightPadding(qreal padding)
611{
612 Q_D(QQuickIconLabel);
613 if (qFuzzyCompare(d->rightPadding, padding))
614 return;
615
616 d->rightPadding = padding;
617 d->updateImplicitSize();
618 d->layout();
619}
621void QQuickIconLabel::resetRightPadding()
622{
623 setRightPadding(0);
624}
626qreal QQuickIconLabel::bottomPadding() const
627{
628 Q_D(const QQuickIconLabel);
629 return d->bottomPadding;
630}
632void QQuickIconLabel::setBottomPadding(qreal padding)
633{
634 Q_D(QQuickIconLabel);
635 if (qFuzzyCompare(d->bottomPadding, padding))
636 return;
637
638 d->bottomPadding = padding;
639 d->updateImplicitSize();
640 d->layout();
641}
643void QQuickIconLabel::resetBottomPadding()
644{
645 setBottomPadding(0);
646}
648void QQuickIconLabel::componentComplete()
649{
650 Q_D(QQuickIconLabel);
651 if (d->image)
652 QQuickIconLabelPrivate::completeComponent(d->image);
653 if (d->label)
654 QQuickIconLabelPrivate::completeComponent(d->label);
655 QQuickItem::componentComplete();
656 d->layout();
657
658 // Any items declared as children of us will be parented before the label and icon image,
659 // so they will be drawn below us. This is not intuitive, so move us to the bottom of the pile.
660 const auto paintOrderChildItems = QQuickItemPrivate::get(this)->paintOrderChildItems();
661 const auto bottomMostFosterChildIt = std::find_if(paintOrderChildItems.constBegin(),
662 paintOrderChildItems.constEnd(), [d](QQuickItem *item) {
663 return item != d->label && item != d->image;
664 });
665 if (bottomMostFosterChildIt != paintOrderChildItems.constEnd()) {
666 const QQuickItem *bottomMostFosterChild = *bottomMostFosterChildIt;
667 if (d->label)
668 d->label->stackBefore(bottomMostFosterChild);
669 if (d->image)
670 d->image->stackBefore(bottomMostFosterChild);
671 }
672}
674void QQuickIconLabel::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
675{
676 Q_D(QQuickIconLabel);
677 QQuickItem::geometryChange(newGeometry, oldGeometry);
678 d->layout();
679}
680
681QT_END_NAMESPACE
682
683#include "moc_qquickiconlabel_p.cpp"
Combined button and popup list for selecting options.
static const QQuickItemPrivate::ChangeTypes itemChangeTypes