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
qlabel.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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 "qpainter.h"
5#include "qevent.h"
6#include "qstyle.h"
7#include "qstyleoption.h"
8#include "qlabel_p.h"
9#include "private/qstylesheetstyle_p.h"
10#include <qmath.h>
11
12#if QT_CONFIG(abstractbutton)
13#include "qabstractbutton.h"
14#endif
15#if QT_CONFIG(accessibility)
16#include <qaccessible.h>
17#endif
18
20
21using namespace Qt::StringLiterals;
22
23QLabelPrivate::QLabelPrivate()
24 : QFramePrivate(),
25 valid_hints(false),
26 scaledcontents(false),
27 textLayoutDirty(false),
28 textDirty(false),
29 isTextLabel(false),
30 hasShortcut(false),
31#ifndef QT_NO_CURSOR
32 validCursor(false),
33 onAnchor(false),
34#endif
35 openExternalLinks(false)
36{
37}
38
39QLabelPrivate::~QLabelPrivate()
40{
41}
42
43/*!
44 \class QLabel
45 \brief The QLabel widget provides a text or image display.
46
47 \ingroup basicwidgets
48 \inmodule QtWidgets
49
50 \image fusion-label.png
51
52 QLabel is used for displaying text or an image. No user
53 interaction functionality is provided. The visual appearance of
54 the label can be configured in various ways, and it can be used
55 for specifying a focus mnemonic key for another widget.
56
57 A QLabel can contain any of the following content types:
58
59 \table
60 \header \li Content \li Setting
61 \row \li Plain text
62 \li Pass a QString to setText().
63 \row \li Rich text
64 \li Pass a QString that contains rich text to setText().
65 \row \li A pixmap
66 \li Pass a QPixmap to setPixmap().
67 \row \li A movie
68 \li Pass a QMovie to setMovie().
69 \row \li A number
70 \li Pass an \e int or a \e double to setNum(), which converts
71 the number to plain text.
72 \row \li Nothing
73 \li The same as an empty plain text. This is the default. Set
74 by clear().
75 \endtable
76
77 \warning When passing a QString to the constructor or calling setText(),
78 make sure to sanitize your input, as QLabel tries to guess whether it
79 displays the text as plain text or as rich text, a subset of HTML 4
80 markup. You may want to call
81 setTextFormat() explicitly, e.g. in case you expect the text to be in
82 plain format but cannot control the text source (for instance when
83 displaying data loaded from the Web).
84
85 When the content is changed using any of these functions, any
86 previous content is cleared.
87
88 By default, labels display \l{alignment}{left-aligned, vertically-centered}
89 text and images, where any tabs in the text to be displayed are
90 \l{Qt::TextExpandTabs}{automatically expanded}. However, the look
91 of a QLabel can be adjusted and fine-tuned in several ways.
92
93 The positioning of the content within the QLabel widget area can
94 be tuned with setAlignment() and setIndent(). Text content can
95 also wrap lines along word boundaries with setWordWrap(). For
96 example, this code sets up a sunken panel with a two-line text in
97 the bottom right corner (both lines being flush with the right
98 side of the label):
99
100 \snippet code/src_gui_widgets_qlabel.cpp 0
101
102 The properties and functions QLabel inherits from QFrame can also
103 be used to specify the widget frame to be used for any given label.
104
105 A QLabel is often used as a label for an interactive widget. For
106 this use QLabel provides a useful mechanism for adding an
107 mnemonic (see QKeySequence) that will set the keyboard focus to
108 the other widget (called the QLabel's "buddy"). For example:
109
110 \snippet code/src_gui_widgets_qlabel.cpp 1
111
112 In this example, keyboard focus is transferred to the label's
113 buddy (the QLineEdit) when the user presses Alt+P. If the buddy
114 was a button (inheriting from QAbstractButton), triggering the
115 mnemonic would emulate a button click.
116
117 \sa QLineEdit, QTextEdit, QPixmap, QMovie
118*/
119
120#ifndef QT_NO_PICTURE
121/*!
122 \fn QPicture QLabel::picture(Qt::ReturnByValueConstant) const
123 \deprecated Use the overload without argument instead.
124 \since 5.15
125
126 Returns the label's picture.
127
128 Previously, Qt provided a version of \c picture() which returned the picture
129 by-pointer. That version is now removed. This overload allowed to
130 explicitly differentiate between the by-pointer function and the by-value.
131*/
132
133/*!
134 \since 6.0
135
136 Returns the label's picture.
137*/
138QPicture QLabel::picture() const
139{
140 Q_D(const QLabel);
141 if (d->picture)
142 return *(d->picture);
143 return QPicture();
144}
145#endif // QT_NO_PICTURE
146
147
148/*!
149 Constructs an empty label.
150
151 The \a parent and widget flag \a f, arguments are passed
152 to the QFrame constructor.
153
154 \sa setAlignment(), setFrameStyle(), setIndent()
155*/
156QLabel::QLabel(QWidget *parent, Qt::WindowFlags f)
157 : QFrame(*new QLabelPrivate(), parent, f)
158{
159 Q_D(QLabel);
160 d->init();
161}
162
163/*!
164 Constructs a label that displays the text, \a text.
165
166 The \a parent and widget flag \a f, arguments are passed
167 to the QFrame constructor.
168
169 \sa setText(), setAlignment(), setFrameStyle(), setIndent()
170*/
171QLabel::QLabel(const QString &text, QWidget *parent, Qt::WindowFlags f)
172 : QLabel(parent, f)
173{
174 setText(text);
175}
176
177
178
179/*!
180 Destroys the label.
181*/
182
183QLabel::~QLabel()
184{
185 Q_D(QLabel);
186 d->clearContents();
187}
188
189void QLabelPrivate::init()
190{
191 Q_Q(QLabel);
192
193 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred,
194 QSizePolicy::Label));
195 setLayoutItemMargins(QStyle::SE_LabelLayoutItem);
196}
197
198
199/*!
200 \property QLabel::text
201 \brief the label's text
202
203 If no text has been set this will return an empty string. Setting
204 the text clears any previous content.
205
206 The text will be interpreted either as plain text or as rich
207 text, depending on the text format setting; see setTextFormat().
208 The default setting is Qt::AutoText; i.e. QLabel will try to
209 auto-detect the format of the text set.
210 See \l {Supported HTML Subset} for the definition of rich text.
211
212 If a buddy has been set, the buddy mnemonic key is updated
213 from the new text.
214
215 Note that QLabel is well-suited to display small rich text
216 documents, such as small documents that get their document
217 specific settings (font, text color, link color) from the label's
218 palette and font properties. For large documents, use QTextEdit
219 in read-only mode instead. QTextEdit can also provide a scroll bar
220 when necessary.
221
222 \note This function enables mouse tracking if \a text contains rich
223 text.
224
225 \sa setTextFormat(), setBuddy(), alignment
226*/
227
228void QLabel::setText(const QString &text)
229{
230 Q_D(QLabel);
231 if (d->text == text)
232 return;
233
234 QWidgetTextControl *oldControl = d->control;
235 d->control = nullptr;
236
237 d->clearContents();
238 d->text = text;
239 d->isTextLabel = true;
240 d->textDirty = true;
241 if (d->textformat == Qt::AutoText) {
242 if (Qt::mightBeRichText(d->text))
243 d->effectiveTextFormat = Qt::RichText;
244 else
245 d->effectiveTextFormat = Qt::PlainText;
246 } else {
247 d->effectiveTextFormat = d->textformat;
248 }
249
250 d->control = oldControl;
251
252 if (d->needTextControl()) {
253 d->ensureTextControl();
254 } else {
255 delete d->control;
256 d->control = nullptr;
257 }
258
259 if (d->effectiveTextFormat != Qt::PlainText) {
260 setMouseTracking(true);
261 } else {
262 // Note: mouse tracking not disabled intentionally
263 }
264
265#ifndef QT_NO_SHORTCUT
266 if (d->buddy)
267 d->updateShortcut();
268#endif
269
270 d->updateLabel();
271
272#if QT_CONFIG(accessibility)
273 if (accessibleName().isEmpty()) {
274 QAccessibleEvent event(this, QAccessible::NameChanged);
275 QAccessible::updateAccessibility(&event);
276 }
277#endif
278}
279
280QString QLabel::text() const
281{
282 Q_D(const QLabel);
283 return d->text;
284}
285
286/*!
287 Clears any label contents.
288*/
289
290void QLabel::clear()
291{
292 Q_D(QLabel);
293 d->clearContents();
294 d->updateLabel();
295}
296
297/*!
298 \property QLabel::pixmap
299 \brief the label's pixmap.
300
301 Setting the pixmap clears any previous content. The buddy
302 shortcut, if any, is disabled.
303*/
304void QLabel::setPixmap(const QPixmap &pixmap)
305{
306 Q_D(QLabel);
307 if (d->icon && d->icon->availableSizes().contains(pixmap.size()) &&
308 d->icon->pixmap(pixmap.size()).cacheKey() == pixmap.cacheKey())
309 return;
310 d->clearContents();
311 d->icon = QIcon(pixmap);
312 d->pixmapSize = pixmap.deviceIndependentSize().toSize();
313 d->updateLabel();
314}
315
316QPixmap QLabel::pixmap() const
317{
318 Q_D(const QLabel);
319 return d->icon ? d->icon->pixmap(d->pixmapSize) : QPixmap();
320}
321
322/*!
323 \fn QPixmap QLabel::pixmap(Qt::ReturnByValueConstant) const
324
325 \deprecated Use the overload without argument instead.
326 \since 5.15
327
328 Returns the label's pixmap.
329
330 Previously, Qt provided a version of \c pixmap() which returned the pixmap
331 by-pointer. That version has now been removed. This overload allowed to
332 explicitly differentiate between the by-pointer function and the by-value.
333
334 \code
335 QPixmap pixmapVal = label->pixmap(Qt::ReturnByValue);
336 \endcode
337*/
338
339#ifndef QT_NO_PICTURE
340/*!
341 Sets the label contents to \a picture. Any previous content is
342 cleared.
343
344 The buddy shortcut, if any, is disabled.
345
346 \sa picture(), setBuddy()
347*/
348
349void QLabel::setPicture(const QPicture &picture)
350{
351 Q_D(QLabel);
352 d->clearContents();
353 d->picture = picture;
354
355 d->updateLabel();
356}
357#endif // QT_NO_PICTURE
358
359/*!
360 Sets the label contents to plain text containing the textual
361 representation of integer \a num. Any previous content is cleared.
362 Does nothing if the integer's string representation is the same as
363 the current contents of the label.
364
365 The buddy shortcut, if any, is disabled.
366
367 \sa setText(), QString::setNum(), setBuddy()
368*/
369
370void QLabel::setNum(int num)
371{
372 setText(QString::number(num));
373}
374
375/*!
376 \overload
377
378 Sets the label contents to plain text containing the textual
379 representation of double \a num. Any previous content is cleared.
380 Does nothing if the double's string representation is the same as
381 the current contents of the label.
382
383 The buddy shortcut, if any, is disabled.
384
385 \sa setText(), QString::setNum(), setBuddy()
386*/
387
388void QLabel::setNum(double num)
389{
390 setText(QString::number(num));
391}
392
393/*!
394 \property QLabel::alignment
395 \brief the alignment of the label's contents
396
397 By default, the contents of the label are left-aligned and vertically-centered.
398
399 \sa text
400*/
401
402void QLabel::setAlignment(Qt::Alignment alignment)
403{
404 Q_D(QLabel);
405 if (alignment == (d->align & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask)))
406 return;
407 d->align = (d->align & ~(Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask))
408 | (alignment & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask));
409
410 d->updateLabel();
411}
412
413
414Qt::Alignment QLabel::alignment() const
415{
416 Q_D(const QLabel);
417 return QFlag(d->align & (Qt::AlignVertical_Mask|Qt::AlignHorizontal_Mask));
418}
419
420
421/*!
422 \property QLabel::wordWrap
423 \brief the label's word-wrapping policy
424
425 If this property is \c true then label text is wrapped where
426 necessary at word-breaks; otherwise it is not wrapped at all.
427
428 By default, word wrap is disabled.
429
430 \sa text
431*/
432void QLabel::setWordWrap(bool on)
433{
434 Q_D(QLabel);
435 if (on)
436 d->align |= Qt::TextWordWrap;
437 else
438 d->align &= ~Qt::TextWordWrap;
439
440 d->updateLabel();
441}
442
443bool QLabel::wordWrap() const
444{
445 Q_D(const QLabel);
446 return d->align & Qt::TextWordWrap;
447}
448
449/*!
450 \property QLabel::indent
451 \brief the label's text indent in pixels
452
453 If a label displays text, the indent applies to the left edge if
454 alignment() is Qt::AlignLeft, to the right edge if alignment() is
455 Qt::AlignRight, to the top edge if alignment() is Qt::AlignTop, and
456 to the bottom edge if alignment() is Qt::AlignBottom.
457
458 If indent is negative, or if no indent has been set, the label
459 computes the effective indent as follows: If frameWidth() is 0,
460 the effective indent becomes 0. If frameWidth() is greater than 0,
461 the effective indent becomes half the width of the "x" character
462 of the widget's current font().
463
464 By default, the indent is -1, meaning that an effective indent is
465 calculating in the manner described above.
466
467 \sa alignment, margin, frameWidth(), font()
468*/
469
470void QLabel::setIndent(int indent)
471{
472 Q_D(QLabel);
473 d->indent = indent;
474 d->updateLabel();
475}
476
477int QLabel::indent() const
478{
479 Q_D(const QLabel);
480 return d->indent;
481}
482
483
484/*!
485 \property QLabel::margin
486 \brief the width of the margin
487
488 The margin is the distance between the innermost pixel of the
489 frame and the outermost pixel of contents.
490
491 The default margin is 0.
492
493 \sa indent
494*/
495int QLabel::margin() const
496{
497 Q_D(const QLabel);
498 return d->margin;
499}
500
501void QLabel::setMargin(int margin)
502{
503 Q_D(QLabel);
504 if (d->margin == margin)
505 return;
506 d->margin = margin;
507 d->updateLabel();
508}
509
510/*!
511 Returns the size that will be used if the width of the label is \a
512 w. If \a w is -1, the sizeHint() is returned. If \a w is 0 minimumSizeHint() is returned
513*/
514QSize QLabelPrivate::sizeForWidth(int w) const
515{
516 Q_Q(const QLabel);
517 if (q->minimumWidth() > 0)
518 w = qMax(w, q->minimumWidth());
519 QSize contentsMargin(leftmargin + rightmargin, topmargin + bottommargin);
520
521 QRect br;
522
523 int hextra = 2 * margin;
524 int vextra = hextra;
525 QFontMetrics fm = q->fontMetrics();
526
527 if (icon && !icon->isNull()) {
528 br = QRect(QPoint(0, 0), pixmapSize);
529#ifndef QT_NO_PICTURE
530 } else if (picture && !picture->isNull()) {
531 br = picture->boundingRect();
532#endif
533#if QT_CONFIG(movie)
534 } else if (movie && !movie->currentPixmap().isNull()) {
535 br = movie->currentPixmap().rect();
536 br.setSize(movie->currentPixmap().deviceIndependentSize().toSize());
537#endif
538 } else if (isTextLabel) {
539 int align = QStyle::visualAlignment(textDirection(), QFlag(this->align));
540 // Add indentation
541 int m = indent;
542
543 if (m < 0 && q->frameWidth()) // no indent, but we do have a frame
544 m = fm.horizontalAdvance(u'x') - margin*2;
545 if (m > 0) {
546 if ((align & Qt::AlignLeft) || (align & Qt::AlignRight))
547 hextra += m;
548 if ((align & Qt::AlignTop) || (align & Qt::AlignBottom))
549 vextra += m;
550 }
551
552 if (control) {
553 ensureTextLayouted();
554 const qreal oldTextWidth = control->textWidth();
555 // Calculate the length of document if w is the width
556 if (align & Qt::TextWordWrap) {
557 if (w >= 0) {
558 w = qMax(w-hextra-contentsMargin.width(), 0); // strip margin and indent
559 control->setTextWidth(w);
560 } else {
561 control->adjustSize();
562 }
563 } else {
564 control->setTextWidth(-1);
565 }
566
567 QSizeF controlSize = control->size();
568 br = QRect(QPoint(0, 0), QSize(qCeil(controlSize.width()), qCeil(controlSize.height())));
569
570 // restore state
571 control->setTextWidth(oldTextWidth);
572 } else {
573 // Turn off center alignment in order to avoid rounding errors for centering,
574 // since centering involves a division by 2. At the end, all we want is the size.
575 int flags = align & ~(Qt::AlignVCenter | Qt::AlignHCenter);
576 if (hasShortcut) {
577 flags |= Qt::TextShowMnemonic;
578 QStyleOption opt;
579 opt.initFrom(q);
580 if (!q->style()->styleHint(QStyle::SH_UnderlineShortcut, &opt, q))
581 flags |= Qt::TextHideMnemonic;
582 }
583
584 bool tryWidth = (w < 0) && (align & Qt::TextWordWrap);
585 if (tryWidth)
586 w = qMin(fm.averageCharWidth() * 80, q->maximumSize().width());
587 else if (w < 0)
588 w = 2000;
589 w -= (hextra + contentsMargin.width());
590 br = fm.boundingRect(0, 0, w ,2000, flags, text);
591 if (tryWidth && br.height() < 4*fm.lineSpacing() && br.width() > w/2)
592 br = fm.boundingRect(0, 0, w/2, 2000, flags, text);
593 if (tryWidth && br.height() < 2*fm.lineSpacing() && br.width() > w/4)
594 br = fm.boundingRect(0, 0, w/4, 2000, flags, text);
595 }
596 } else {
597 br = QRect(QPoint(0, 0), QSize(fm.averageCharWidth(), fm.lineSpacing()));
598 }
599
600 const QSize contentsSize(br.width() + hextra, br.height() + vextra);
601 return (contentsSize + contentsMargin).expandedTo(q->minimumSize());
602}
603
604
605/*!
606 \reimp
607*/
608
609int QLabel::heightForWidth(int w) const
610{
611 Q_D(const QLabel);
612 if (d->isTextLabel)
613 return d->sizeForWidth(w).height();
614 return QWidget::heightForWidth(w);
615}
616
617/*!
618 \property QLabel::openExternalLinks
619 \since 4.2
620
621 Specifies whether QLabel should automatically open links using
622 QDesktopServices::openUrl() instead of emitting the
623 linkActivated() signal.
624
625 \b{Note:} The textInteractionFlags set on the label need to include
626 either LinksAccessibleByMouse or LinksAccessibleByKeyboard.
627
628 The default value is false.
629
630 \sa textInteractionFlags()
631*/
632bool QLabel::openExternalLinks() const
633{
634 Q_D(const QLabel);
635 return d->openExternalLinks;
636}
637
638void QLabel::setOpenExternalLinks(bool open)
639{
640 Q_D(QLabel);
641 d->openExternalLinks = open;
642 if (d->control)
643 d->control->setOpenExternalLinks(open);
644}
645
646/*!
647 \property QLabel::textInteractionFlags
648 \since 4.2
649
650 Specifies how the label should interact with user input if it displays text.
651
652 If the flags contain Qt::LinksAccessibleByKeyboard the focus policy is also
653 automatically set to Qt::StrongFocus. If Qt::TextSelectableByKeyboard is set
654 then the focus policy is set to Qt::ClickFocus.
655
656 The default value is Qt::LinksAccessibleByMouse.
657*/
658void QLabel::setTextInteractionFlags(Qt::TextInteractionFlags flags)
659{
660 Q_D(QLabel);
661 if (d->textInteractionFlags == flags)
662 return;
663 d->textInteractionFlags = flags;
664 if (flags & Qt::LinksAccessibleByKeyboard)
665 setFocusPolicy(Qt::StrongFocus);
666 else if (flags & (Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse))
667 setFocusPolicy(Qt::ClickFocus);
668 else
669 setFocusPolicy(Qt::NoFocus);
670
671 if (d->needTextControl()) {
672 d->ensureTextControl();
673 } else {
674 delete d->control;
675 d->control = nullptr;
676 }
677
678 if (d->control)
679 d->control->setTextInteractionFlags(d->textInteractionFlags);
680}
681
682Qt::TextInteractionFlags QLabel::textInteractionFlags() const
683{
684 Q_D(const QLabel);
685 return d->textInteractionFlags;
686}
687
688/*!
689 Selects text from position \a start and for \a length characters.
690
691 \sa selectedText()
692
693 \b{Note:} The textInteractionFlags set on the label need to include
694 either TextSelectableByMouse or TextSelectableByKeyboard.
695
696 \since 4.7
697*/
698void QLabel::setSelection(int start, int length)
699{
700 Q_D(QLabel);
701 if (d->control) {
702 d->ensureTextPopulated();
703 QTextCursor cursor = d->control->textCursor();
704 cursor.setPosition(start);
705 cursor.setPosition(start + length, QTextCursor::KeepAnchor);
706 d->control->setTextCursor(cursor);
707 }
708}
709
710/*!
711 \property QLabel::hasSelectedText
712 \brief whether there is any text selected
713
714 hasSelectedText() returns \c true if some or all of the text has been
715 selected by the user; otherwise returns \c false.
716
717 By default, this property is \c false.
718
719 \sa selectedText()
720
721 \b{Note:} The textInteractionFlags set on the label need to include
722 either TextSelectableByMouse or TextSelectableByKeyboard.
723
724 \since 4.7
725*/
726bool QLabel::hasSelectedText() const
727{
728 Q_D(const QLabel);
729 if (d->control)
730 return d->control->textCursor().hasSelection();
731 return false;
732}
733
734/*!
735 \property QLabel::selectedText
736 \brief the selected text
737
738 If there is no selected text this property's value is
739 an empty string.
740
741 By default, this property contains an empty string.
742
743 \sa hasSelectedText()
744
745 \b{Note:} The textInteractionFlags set on the label need to include
746 either TextSelectableByMouse or TextSelectableByKeyboard.
747
748 \since 4.7
749*/
750QString QLabel::selectedText() const
751{
752 Q_D(const QLabel);
753 if (d->control)
754 return d->control->textCursor().selectedText();
755 return QString();
756}
757
758/*!
759 selectionStart() returns the index of the first selected character in the
760 label or -1 if no text is selected.
761
762 \sa selectedText()
763
764 \b{Note:} The textInteractionFlags set on the label need to include
765 either TextSelectableByMouse or TextSelectableByKeyboard.
766
767 \since 4.7
768*/
769int QLabel::selectionStart() const
770{
771 Q_D(const QLabel);
772 if (d->control && d->control->textCursor().hasSelection())
773 return d->control->textCursor().selectionStart();
774 return -1;
775}
776
777/*!\reimp
778*/
779QSize QLabel::sizeHint() const
780{
781 Q_D(const QLabel);
782 if (!d->valid_hints)
783 (void) QLabel::minimumSizeHint();
784 return d->sh;
785}
786
787/*!
788 \reimp
789*/
790QSize QLabel::minimumSizeHint() const
791{
792 Q_D(const QLabel);
793 if (d->valid_hints) {
794 if (d->sizePolicy == sizePolicy())
795 return d->msh;
796 }
797
798 ensurePolished();
799 d->valid_hints = true;
800 d->sh = d->sizeForWidth(-1); // wrap ? golden ratio : min doc size
801 QSize msh(-1, -1);
802
803 if (!d->isTextLabel) {
804 msh = d->sh;
805 } else {
806 msh.rheight() = d->sizeForWidth(QWIDGETSIZE_MAX).height(); // height for one line
807 msh.rwidth() = d->sizeForWidth(0).width(); // wrap ? size of biggest word : min doc size
808 if (d->sh.height() < msh.height())
809 msh.rheight() = d->sh.height();
810 }
811 d->msh = msh;
812 d->sizePolicy = sizePolicy();
813 return msh;
814}
815
816/*!\reimp
817*/
818void QLabel::mousePressEvent(QMouseEvent *ev)
819{
820 Q_D(QLabel);
821 d->sendControlEvent(ev);
822}
823
824/*!\reimp
825*/
826void QLabel::mouseMoveEvent(QMouseEvent *ev)
827{
828 Q_D(QLabel);
829 d->sendControlEvent(ev);
830}
831
832/*!\reimp
833*/
834void QLabel::mouseReleaseEvent(QMouseEvent *ev)
835{
836 Q_D(QLabel);
837 d->sendControlEvent(ev);
838}
839
840#ifndef QT_NO_CONTEXTMENU
841/*!\reimp
842*/
843void QLabel::contextMenuEvent(QContextMenuEvent *ev)
844{
845 Q_D(QLabel);
846 if (!d->isTextLabel) {
847 ev->ignore();
848 return;
849 }
850 QMenu *menu = d->createStandardContextMenu(ev->pos());
851 if (!menu) {
852 ev->ignore();
853 return;
854 }
855 ev->accept();
856 menu->setAttribute(Qt::WA_DeleteOnClose);
857 menu->popup(ev->globalPos());
858}
859#endif // QT_NO_CONTEXTMENU
860
861/*!
862 \reimp
863*/
864void QLabel::focusInEvent(QFocusEvent *ev)
865{
866 Q_D(QLabel);
867 if (d->isTextLabel) {
868 d->ensureTextControl();
869 d->sendControlEvent(ev);
870 }
871 QFrame::focusInEvent(ev);
872}
873
874/*!
875 \reimp
876*/
877void QLabel::focusOutEvent(QFocusEvent *ev)
878{
879 Q_D(QLabel);
880 if (d->control) {
881 d->sendControlEvent(ev);
882 QTextCursor cursor = d->control->textCursor();
883 Qt::FocusReason reason = ev->reason();
884 if (reason != Qt::ActiveWindowFocusReason
885 && reason != Qt::PopupFocusReason
886 && cursor.hasSelection()) {
887 cursor.clearSelection();
888 d->control->setTextCursor(cursor);
889 }
890 }
891
892 QFrame::focusOutEvent(ev);
893}
894
895/*!\reimp
896*/
897bool QLabel::focusNextPrevChild(bool next)
898{
899 Q_D(QLabel);
900 if (d->control && d->control->setFocusToNextOrPreviousAnchor(next))
901 return true;
902 return QFrame::focusNextPrevChild(next);
903}
904
905/*!\reimp
906*/
907void QLabel::keyPressEvent(QKeyEvent *ev)
908{
909 Q_D(QLabel);
910 d->sendControlEvent(ev);
911}
912
913/*!\reimp
914*/
915bool QLabel::event(QEvent *e)
916{
917 Q_D(QLabel);
918 QEvent::Type type = e->type();
919
920#ifndef QT_NO_SHORTCUT
921 if (type == QEvent::Shortcut) {
922 QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
923 if (se->shortcutId() == d->shortcutId) {
924 QWidget *w = d->buddy;
925 if (!w)
926 return QFrame::event(e);
927 if (w->focusPolicy() != Qt::NoFocus)
928 w->setFocus(Qt::ShortcutFocusReason);
929#if QT_CONFIG(abstractbutton)
930 QAbstractButton *button = qobject_cast<QAbstractButton *>(w);
931 if (button && !se->isAmbiguous())
932 button->animateClick();
933 else
934#endif
935 window()->setAttribute(Qt::WA_KeyboardFocusChange);
936 return true;
937 }
938 } else
939#endif
940 if (type == QEvent::Resize) {
941 if (d->control)
942 d->textLayoutDirty = true;
943 } else if (e->type() == QEvent::StyleChange
944#ifdef Q_OS_MAC
945 || e->type() == QEvent::MacSizeChange
946#endif
947 ) {
948 d->setLayoutItemMargins(QStyle::SE_LabelLayoutItem);
949 d->updateLabel();
950 } else if (type == QEvent::Polish) {
951 if (d->needTextControl())
952 d->ensureTextControl();
953 }
954
955 return QFrame::event(e);
956}
957
958/*!\reimp
959*/
960void QLabel::paintEvent(QPaintEvent *)
961{
962 Q_D(QLabel);
963 QStyle *style = QWidget::style();
964 QPainter painter(this);
965 drawFrame(&painter);
966 QRect cr = contentsRect();
967 cr.adjust(d->margin, d->margin, -d->margin, -d->margin);
968 int align = QStyle::visualAlignment(d->isTextLabel ? d->textDirection()
969 : layoutDirection(), QFlag(d->align));
970
971#if QT_CONFIG(movie)
972 if (d->movie && !d->movie->currentPixmap().isNull()) {
973 if (d->scaledcontents)
974 style->drawItemPixmap(&painter, cr, align, d->movie->currentPixmap().scaled(cr.size()));
975 else
976 style->drawItemPixmap(&painter, cr, align, d->movie->currentPixmap());
977 }
978 else
979#endif
980 if (d->isTextLabel) {
981 QRectF lr = d->layoutRect().toAlignedRect();
982 QStyleOption opt;
983 opt.initFrom(this);
984#ifndef QT_NO_STYLE_STYLESHEET
985 if (QStyleSheetStyle* cssStyle = qt_styleSheet(style))
986 cssStyle->styleSheetPalette(this, &opt, &opt.palette);
987#endif
988 if (d->control) {
989#ifndef QT_NO_SHORTCUT
990 const bool underline = static_cast<bool>(style->styleHint(QStyle::SH_UnderlineShortcut,
991 nullptr, this, nullptr));
992 if (d->shortcutId != 0
993 && underline != d->shortcutCursor.charFormat().fontUnderline()) {
994 QTextCharFormat fmt;
995 fmt.setFontUnderline(underline);
996 d->shortcutCursor.mergeCharFormat(fmt);
997 }
998#endif
999 d->ensureTextLayouted();
1000
1001 QAbstractTextDocumentLayout::PaintContext context;
1002 // Adjust the palette
1003 context.palette = opt.palette;
1004
1005 if (foregroundRole() != QPalette::Text && isEnabled())
1006 context.palette.setColor(QPalette::Text, context.palette.color(foregroundRole()));
1007
1008 painter.save();
1009 painter.translate(lr.topLeft());
1010 painter.setClipRect(lr.translated(-lr.x(), -lr.y()));
1011 d->control->setPalette(context.palette);
1012 d->control->drawContents(&painter, QRectF(), this);
1013 painter.restore();
1014 } else {
1015 int flags = align | (d->textDirection() == Qt::LeftToRight ? Qt::TextForceLeftToRight
1016 : Qt::TextForceRightToLeft);
1017 if (d->hasShortcut) {
1018 flags |= Qt::TextShowMnemonic;
1019 if (!style->styleHint(QStyle::SH_UnderlineShortcut, &opt, this))
1020 flags |= Qt::TextHideMnemonic;
1021 }
1022 style->drawItemText(&painter, lr.toRect(), flags, opt.palette, isEnabled(), d->text, foregroundRole());
1023 }
1024 } else
1025#ifndef QT_NO_PICTURE
1026 if (d->picture) {
1027 QRect br = d->picture->boundingRect();
1028 int rw = br.width();
1029 int rh = br.height();
1030 if (d->scaledcontents) {
1031 painter.save();
1032 painter.translate(cr.x(), cr.y());
1033 painter.scale((double)cr.width()/rw, (double)cr.height()/rh);
1034 painter.drawPicture(-br.x(), -br.y(), *d->picture);
1035 painter.restore();
1036 } else {
1037 int xo = 0;
1038 int yo = 0;
1039 if (align & Qt::AlignVCenter)
1040 yo = (cr.height()-rh)/2;
1041 else if (align & Qt::AlignBottom)
1042 yo = cr.height()-rh;
1043 if (align & Qt::AlignRight)
1044 xo = cr.width()-rw;
1045 else if (align & Qt::AlignHCenter)
1046 xo = (cr.width()-rw)/2;
1047 painter.drawPicture(cr.x()+xo-br.x(), cr.y()+yo-br.y(), *d->picture);
1048 }
1049 } else
1050#endif
1051 if (d->icon && !d->icon->isNull()) {
1052 const qreal dpr = devicePixelRatio();
1053 const QSize size = d->scaledcontents ? cr.size() : d->pixmapSize;
1054 const auto mode = isEnabled() ? QIcon::Normal : QIcon::Disabled;
1055 QPixmap pix = d->icon->pixmap(size, dpr, mode);
1056 if (d->scaledcontents && pix.size() != size * dpr) {
1057 pix = pix.scaled(size * dpr, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1058 pix.setDevicePixelRatio(dpr);
1059 d->icon->addPixmap(pix, mode);
1060 }
1061 QStyleOption opt;
1062 opt.initFrom(this);
1063 style->drawItemPixmap(&painter, cr, align, pix);
1064 }
1065}
1066
1067
1068/*!
1069 Updates the label, but not the frame.
1070*/
1071
1072void QLabelPrivate::updateLabel()
1073{
1074 Q_Q(QLabel);
1075 valid_hints = false;
1076
1077 if (isTextLabel) {
1078 QSizePolicy policy = q->sizePolicy();
1079 const bool wrap = align & Qt::TextWordWrap;
1080 policy.setHeightForWidth(wrap);
1081 if (policy != q->sizePolicy()) // ### should be replaced by WA_WState_OwnSizePolicy idiom
1082 q->setSizePolicy(policy);
1083 textLayoutDirty = true;
1084 }
1085 q->updateGeometry();
1086 q->update(q->contentsRect());
1087}
1088
1089#ifndef QT_NO_SHORTCUT
1090/*!
1091 Sets this label's buddy to \a buddy.
1092
1093 When the user presses the shortcut key indicated by this label,
1094 the keyboard focus is transferred to the label's buddy widget.
1095
1096 The buddy mechanism is only available for QLabels that contain
1097 text in which one character is prefixed with an ampersand, '&'.
1098 This character is set as the shortcut key. See the \l
1099 QKeySequence::mnemonic() documentation for details (to display an
1100 actual ampersand, use '&&').
1101
1102 In a dialog, you might create two data entry widgets and a label
1103 for each, and set up the geometry layout so each label is just to
1104 the left of its data entry widget (its "buddy"), for example:
1105 \snippet code/src_gui_widgets_qlabel.cpp 2
1106
1107 With the code above, the focus jumps to the Name field when the
1108 user presses Alt+N, and to the Phone field when the user presses
1109 Alt+P.
1110
1111 To unset a previously set buddy, call this function with \a buddy
1112 set to nullptr.
1113
1114 \sa buddy(), setText(), QShortcut, setAlignment()
1115*/
1116
1117void QLabel::setBuddy(QWidget *buddy)
1118{
1119 Q_D(QLabel);
1120
1121 if (d->buddy)
1122 QObjectPrivate::disconnect(d->buddy, &QObject::destroyed,
1123 d, &QLabelPrivate::buddyDeleted);
1124
1125 d->buddy = buddy;
1126
1127 if (buddy)
1128 QObjectPrivate::connect(buddy, &QObject::destroyed,
1129 d, &QLabelPrivate::buddyDeleted);
1130
1131 if (d->isTextLabel) {
1132 if (d->shortcutId)
1133 releaseShortcut(d->shortcutId);
1134 d->shortcutId = 0;
1135 d->textDirty = true;
1136 if (buddy)
1137 d->updateShortcut(); // grab new shortcut
1138 d->updateLabel();
1139 }
1140}
1141
1142
1143/*!
1144 Returns this label's buddy, or nullptr if no buddy is currently set.
1145
1146 \sa setBuddy()
1147*/
1148
1149QWidget * QLabel::buddy() const
1150{
1151 Q_D(const QLabel);
1152 return d->buddy;
1153}
1154
1155void QLabelPrivate::updateShortcut()
1156{
1157 Q_Q(QLabel);
1158 Q_ASSERT(shortcutId == 0);
1159 // Introduce an extra boolean to indicate the presence of a shortcut in the
1160 // text. We cannot use the shortcutId itself because on the mac mnemonics are
1161 // off by default, so QKeySequence::mnemonic always returns an empty sequence.
1162 // But then we do want to hide the ampersands, so we can't use shortcutId.
1163 hasShortcut = false;
1164
1165 if (!text.contains(u'&'))
1166 return;
1167 hasShortcut = true;
1168 shortcutId = q->grabShortcut(QKeySequence::mnemonic(text));
1169}
1170
1171
1172void QLabelPrivate::buddyDeleted()
1173{
1174 Q_Q(QLabel);
1175 q->setBuddy(nullptr);
1176}
1177
1178#endif // QT_NO_SHORTCUT
1179
1180#if QT_CONFIG(movie)
1181void QLabelPrivate::movieUpdated(const QRect &rect)
1182{
1183 Q_Q(QLabel);
1184 if (movie && movie->isValid()) {
1185 QRect r;
1186 if (scaledcontents) {
1187 QRect cr = q->contentsRect();
1188 QRect pixmapRect(cr.topLeft(), movie->currentPixmap().size());
1189 if (pixmapRect.isEmpty())
1190 return;
1191 r.setRect(cr.left(), cr.top(),
1192 (rect.width() * cr.width()) / pixmapRect.width(),
1193 (rect.height() * cr.height()) / pixmapRect.height());
1194 } else {
1195 r = q->style()->itemPixmapRect(q->contentsRect(), align, movie->currentPixmap());
1196 r.translate(rect.x(), rect.y());
1197 r.setWidth(qMin(r.width(), rect.width()));
1198 r.setHeight(qMin(r.height(), rect.height()));
1199 }
1200 q->update(r);
1201 }
1202}
1203
1204void QLabelPrivate::movieResized(const QSize &size)
1205{
1206 Q_Q(QLabel);
1207 q->update(); //we need to refresh the whole background in case the new size is smaller
1208 valid_hints = false;
1209 movieUpdated(QRect(QPoint(0,0), size));
1210 q->updateGeometry();
1211}
1212
1213/*!
1214 Sets the label contents to \a movie. Any previous content is
1215 cleared. The label does NOT take ownership of the movie.
1216
1217 The buddy shortcut, if any, is disabled.
1218
1219 \sa movie(), setBuddy()
1220*/
1221
1222void QLabel::setMovie(QMovie *movie)
1223{
1224 Q_D(QLabel);
1225 d->clearContents();
1226
1227 if (!movie)
1228 return;
1229
1230 d->movie = movie;
1231 d->movieConnections = {
1232 QObjectPrivate::connect(movie, &QMovie::resized, d, &QLabelPrivate::movieResized),
1233 QObjectPrivate::connect(movie, &QMovie::updated, d, &QLabelPrivate::movieUpdated),
1234 };
1235
1236 // Assume that if the movie is running,
1237 // resize/update signals will come soon enough
1238 if (movie->state() != QMovie::Running)
1239 d->updateLabel();
1240}
1241
1242#endif // QT_CONFIG(movie)
1243
1244/*!
1245 \internal
1246
1247 Clears any contents, without updating/repainting the label.
1248*/
1249
1250void QLabelPrivate::clearContents()
1251{
1252 delete control;
1253 control = nullptr;
1254 isTextLabel = false;
1255 hasShortcut = false;
1256
1257#ifndef QT_NO_PICTURE
1258 picture.reset();
1259#endif
1260 icon.reset();
1261 pixmapSize = QSize();
1262
1263 text.clear();
1264 Q_Q(QLabel);
1265#ifndef QT_NO_SHORTCUT
1266 if (shortcutId)
1267 q->releaseShortcut(shortcutId);
1268 shortcutId = 0;
1269#endif
1270#if QT_CONFIG(movie)
1271 for (const auto &conn : std::as_const(movieConnections))
1272 QObject::disconnect(conn);
1273 movie = nullptr;
1274#endif
1275#ifndef QT_NO_CURSOR
1276 if (onAnchor) {
1277 if (validCursor)
1278 q->setCursor(cursor);
1279 else
1280 q->unsetCursor();
1281 }
1282 validCursor = false;
1283 onAnchor = false;
1284#endif
1285}
1286
1287
1288#if QT_CONFIG(movie)
1289
1290/*!
1291 Returns a pointer to the label's movie, or nullptr if no movie has been
1292 set.
1293
1294 \sa setMovie()
1295*/
1296
1297QMovie *QLabel::movie() const
1298{
1299 Q_D(const QLabel);
1300 return d->movie;
1301}
1302
1303#endif // QT_CONFIG(movie)
1304
1305/*!
1306 \property QLabel::textFormat
1307 \brief the label's text format
1308
1309 See the Qt::TextFormat enum for an explanation of the possible
1310 options.
1311
1312 The default format is Qt::AutoText.
1313
1314 \sa text()
1315*/
1316
1317Qt::TextFormat QLabel::textFormat() const
1318{
1319 Q_D(const QLabel);
1320 return d->textformat;
1321}
1322
1323void QLabel::setTextFormat(Qt::TextFormat format)
1324{
1325 Q_D(QLabel);
1326 if (format != d->textformat) {
1327 d->textformat = format;
1328 QString t = d->text;
1329 if (!t.isNull()) {
1330 d->text.clear();
1331 setText(t);
1332 }
1333 }
1334}
1335
1336/*!
1337 \since 6.1
1338
1339 Returns the resource provider for rich text of this label.
1340*/
1341QTextDocument::ResourceProvider QLabel::resourceProvider() const
1342{
1343 Q_D(const QLabel);
1344 return d->control ? d->control->document()->resourceProvider() : d->resourceProvider;
1345}
1346
1347/*!
1348 \since 6.1
1349
1350 Sets the \a provider of resources for rich text of this label.
1351
1352 \note The label \e{does not} take ownership of the \a provider.
1353*/
1354void QLabel::setResourceProvider(const QTextDocument::ResourceProvider &provider)
1355{
1356 Q_D(QLabel);
1357 d->resourceProvider = provider;
1358 if (d->control != nullptr)
1359 d->control->document()->setResourceProvider(provider);
1360}
1361
1362/*!
1363 \reimp
1364*/
1365void QLabel::changeEvent(QEvent *ev)
1366{
1367 Q_D(QLabel);
1368 if (ev->type() == QEvent::FontChange || ev->type() == QEvent::ApplicationFontChange) {
1369 if (d->isTextLabel) {
1370 if (d->control)
1371 d->control->document()->setDefaultFont(font());
1372 d->updateLabel();
1373 }
1374 } else if (ev->type() == QEvent::PaletteChange && d->control) {
1375 d->control->setPalette(palette());
1376 } else if (ev->type() == QEvent::ContentsRectChange) {
1377 d->updateLabel();
1378 }
1379 QFrame::changeEvent(ev);
1380}
1381
1382/*!
1383 \property QLabel::scaledContents
1384 \brief whether the label will scale its contents to fill all
1385 available space.
1386
1387 When enabled and the label shows a pixmap, it will scale the
1388 pixmap to fill the available space.
1389
1390 This property's default is false.
1391*/
1392bool QLabel::hasScaledContents() const
1393{
1394 Q_D(const QLabel);
1395 return d->scaledcontents;
1396}
1397
1398void QLabel::setScaledContents(bool enable)
1399{
1400 Q_D(QLabel);
1401 if ((bool)d->scaledcontents == enable)
1402 return;
1403 d->scaledcontents = enable;
1404 update(contentsRect());
1405}
1406
1407Qt::LayoutDirection QLabelPrivate::textDirection() const
1408{
1409 if (control) {
1410 QTextOption opt = control->document()->defaultTextOption();
1411 return opt.textDirection();
1412 }
1413
1414 return text.isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight;
1415}
1416
1417
1418// Returns the rect that is available for us to draw the document
1419QRect QLabelPrivate::documentRect() const
1420{
1421 Q_Q(const QLabel);
1422 Q_ASSERT_X(isTextLabel, "documentRect", "document rect called for label that is not a text label!");
1423 QRect cr = q->contentsRect();
1424 cr.adjust(margin, margin, -margin, -margin);
1425 const int align = QStyle::visualAlignment(isTextLabel ? textDirection()
1426 : q->layoutDirection(), QFlag(this->align));
1427 int m = indent;
1428 if (m < 0 && q->frameWidth()) // no indent, but we do have a frame
1429 m = q->fontMetrics().horizontalAdvance(u'x') / 2 - margin;
1430 if (m > 0) {
1431 if (align & Qt::AlignLeft)
1432 cr.setLeft(cr.left() + m);
1433 if (align & Qt::AlignRight)
1434 cr.setRight(cr.right() - m);
1435 if (align & Qt::AlignTop)
1436 cr.setTop(cr.top() + m);
1437 if (align & Qt::AlignBottom)
1438 cr.setBottom(cr.bottom() - m);
1439 }
1440 return cr;
1441}
1442
1443void QLabelPrivate::ensureTextPopulated() const
1444{
1445 if (!textDirty)
1446 return;
1447 if (control) {
1448 QTextDocument *doc = control->document();
1449 if (textDirty) {
1450 if (effectiveTextFormat == Qt::PlainText) {
1451 doc->setPlainText(text);
1452#if QT_CONFIG(texthtmlparser)
1453 } else if (effectiveTextFormat == Qt::RichText) {
1454 doc->setHtml(text);
1455#endif
1456#if QT_CONFIG(textmarkdownreader)
1457 } else if (effectiveTextFormat == Qt::MarkdownText) {
1458 doc->setMarkdown(text);
1459#endif
1460 } else {
1461 doc->setPlainText(text);
1462 }
1463 doc->setUndoRedoEnabled(false);
1464
1465#ifndef QT_NO_SHORTCUT
1466 if (hasShortcut) {
1467 // Underline the first character that follows an ampersand (and remove the others ampersands)
1468 int from = 0;
1469 bool found = false;
1470 QTextCursor cursor;
1471 while (!(cursor = control->document()->find(("&"_L1), from)).isNull()) {
1472 cursor.deleteChar(); // remove the ampersand
1473 cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
1474 from = cursor.position();
1475 if (!found && cursor.selectedText() != "&"_L1) { //not a second &
1476 found = true;
1477 shortcutCursor = cursor;
1478 }
1479 }
1480 }
1481#endif
1482 }
1483 }
1484 textDirty = false;
1485}
1486
1487void QLabelPrivate::ensureTextLayouted() const
1488{
1489 if (!textLayoutDirty)
1490 return;
1491 ensureTextPopulated();
1492 if (control) {
1493 QTextDocument *doc = control->document();
1494 QTextOption opt = doc->defaultTextOption();
1495
1496 opt.setAlignment(QFlag(this->align));
1497
1498 if (this->align & Qt::TextWordWrap)
1499 opt.setWrapMode(QTextOption::WordWrap);
1500 else
1501 opt.setWrapMode(QTextOption::ManualWrap);
1502
1503 doc->setDefaultTextOption(opt);
1504
1505 QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
1506 fmt.setMargin(0);
1507 doc->rootFrame()->setFrameFormat(fmt);
1508 doc->setTextWidth(documentRect().width());
1509 }
1510 textLayoutDirty = false;
1511}
1512
1513void QLabelPrivate::ensureTextControl() const
1514{
1515 Q_Q(const QLabel);
1516 if (!isTextLabel)
1517 return;
1518 if (!control) {
1519 control = new QWidgetTextControl(const_cast<QLabel *>(q));
1520 control->document()->setUndoRedoEnabled(false);
1521 control->document()->setDefaultFont(q->font());
1522 if (resourceProvider != nullptr)
1523 control->document()->setResourceProvider(resourceProvider);
1524 control->setTextInteractionFlags(textInteractionFlags);
1525 control->setOpenExternalLinks(openExternalLinks);
1526 control->setPalette(q->palette());
1527 control->setFocus(q->hasFocus());
1528 QObject::connect(control, &QWidgetTextControl::updateRequest,
1529 q, qOverload<>(&QLabel::update));
1530 QObject::connect(control, &QWidgetTextControl::linkActivated,
1531 q, &QLabel::linkActivated);
1532 QObjectPrivate::connect(control, &QWidgetTextControl::linkHovered,
1533 this, &QLabelPrivate::linkHovered);
1534 textLayoutDirty = true;
1535 textDirty = true;
1536 }
1537}
1538
1539void QLabelPrivate::sendControlEvent(QEvent *e)
1540{
1541 Q_Q(QLabel);
1542 if (!isTextLabel || !control || textInteractionFlags == Qt::NoTextInteraction) {
1543 e->ignore();
1544 return;
1545 }
1546 control->processEvent(e, -layoutRect().topLeft(), q);
1547}
1548
1549void QLabelPrivate::linkHovered(const QString &anchor)
1550{
1551 Q_Q(QLabel);
1552#ifndef QT_NO_CURSOR
1553 if (anchor.isEmpty()) { // restore cursor
1554 if (validCursor)
1555 q->setCursor(cursor);
1556 else
1557 q->unsetCursor();
1558 onAnchor = false;
1559 } else if (!onAnchor) {
1560 validCursor = q->testAttribute(Qt::WA_SetCursor);
1561 if (validCursor) {
1562 cursor = q->cursor();
1563 }
1564 q->setCursor(Qt::PointingHandCursor);
1565 onAnchor = true;
1566 }
1567#endif
1568 emit q->linkHovered(anchor);
1569}
1570
1571// Return the layout rect - this is the rect that is given to the layout painting code
1572// This may be different from the document rect since vertical alignment is not
1573// done by the text layout code
1574QRectF QLabelPrivate::layoutRect() const
1575{
1576 QRectF cr = documentRect();
1577 if (!control)
1578 return cr;
1579 ensureTextLayouted();
1580 // Calculate y position manually
1581 qreal rh = control->document()->documentLayout()->documentSize().height();
1582 qreal yo = 0;
1583 if (align & Qt::AlignVCenter)
1584 yo = qMax((cr.height()-rh)/2, qreal(0));
1585 else if (align & Qt::AlignBottom)
1586 yo = qMax(cr.height()-rh, qreal(0));
1587 return QRectF(cr.x(), yo + cr.y(), cr.width(), cr.height());
1588}
1589
1590// Returns the point in the document rect adjusted with p
1591QPoint QLabelPrivate::layoutPoint(const QPoint& p) const
1592{
1593 QRect lr = layoutRect().toRect();
1594 return p - lr.topLeft();
1595}
1596
1597#ifndef QT_NO_CONTEXTMENU
1598QMenu *QLabelPrivate::createStandardContextMenu(const QPoint &pos)
1599{
1600 if (!control)
1601 return nullptr;
1602
1603 const QPoint p = layoutPoint(pos);
1604 return control->createStandardContextMenu(p, q_func());
1605}
1606#endif
1607
1608/*!
1609 \fn void QLabel::linkHovered(const QString &link)
1610 \since 4.2
1611
1612 This signal is emitted when the user hovers over a link. The URL
1613 referred to by the anchor is passed in \a link.
1614
1615 \sa linkActivated()
1616*/
1617
1618
1619/*!
1620 \fn void QLabel::linkActivated(const QString &link)
1621 \since 4.2
1622
1623 This signal is emitted when the user clicks a link. The URL
1624 referred to by the anchor is passed in \a link.
1625
1626 \sa linkHovered()
1627*/
1628
1629QT_END_NAMESPACE
1630
1631#include "moc_qlabel.cpp"
Combined button and popup list for selecting options.