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