55 #include <QAbstractTextDocumentLayout> |
55 #include <QAbstractTextDocumentLayout> |
56 #include <qmath.h> |
56 #include <qmath.h> |
57 |
57 |
58 QT_BEGIN_NAMESPACE |
58 QT_BEGIN_NAMESPACE |
59 |
59 |
|
60 extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled; |
|
61 |
60 class QTextDocumentWithImageResources : public QTextDocument { |
62 class QTextDocumentWithImageResources : public QTextDocument { |
61 Q_OBJECT |
63 Q_OBJECT |
62 |
64 |
63 public: |
65 public: |
64 QTextDocumentWithImageResources(QDeclarativeText *parent) : |
66 QTextDocumentWithImageResources(QDeclarativeText *parent); |
65 QTextDocument(parent), |
67 virtual ~QTextDocumentWithImageResources(); |
66 outstanding(0) |
68 |
67 { |
69 void setText(const QString &); |
68 } |
|
69 |
|
70 int resourcesLoading() const { return outstanding; } |
70 int resourcesLoading() const { return outstanding; } |
71 |
71 |
72 protected: |
72 protected: |
73 QVariant loadResource(int type, const QUrl &name) |
73 QVariant loadResource(int type, const QUrl &name); |
74 { |
|
75 QUrl url = qmlContext(parent())->resolvedUrl(name); |
|
76 |
|
77 if (type == QTextDocument::ImageResource) { |
|
78 QPixmap pm; |
|
79 QString errorString; |
|
80 QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(url, &pm, &errorString, 0, false, 0, 0); |
|
81 if (status == QDeclarativePixmapReply::Ready) |
|
82 return pm; |
|
83 if (status == QDeclarativePixmapReply::Error) { |
|
84 if (!errors.contains(url)) { |
|
85 errors.insert(url); |
|
86 qmlInfo(parent()) << errorString; |
|
87 } |
|
88 } else { |
|
89 QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(parent()), url); |
|
90 connect(reply, SIGNAL(finished()), this, SLOT(requestFinished())); |
|
91 outstanding++; |
|
92 } |
|
93 } |
|
94 |
|
95 return QTextDocument::loadResource(type,url); // The *resolved* URL |
|
96 } |
|
97 |
74 |
98 private slots: |
75 private slots: |
99 void requestFinished() |
76 void requestFinished(); |
100 { |
|
101 outstanding--; |
|
102 if (outstanding == 0) |
|
103 static_cast<QDeclarativeText*>(parent())->reloadWithResources(); |
|
104 } |
|
105 |
77 |
106 private: |
78 private: |
|
79 QHash<QUrl, QDeclarativePixmap *> m_resources; |
|
80 |
107 int outstanding; |
81 int outstanding; |
108 static QSet<QUrl> errors; |
82 static QSet<QUrl> errors; |
109 }; |
83 }; |
|
84 |
|
85 QTextDocumentWithImageResources::QTextDocumentWithImageResources(QDeclarativeText *parent) |
|
86 : QTextDocument(parent), outstanding(0) |
|
87 { |
|
88 } |
|
89 |
|
90 QTextDocumentWithImageResources::~QTextDocumentWithImageResources() |
|
91 { |
|
92 if (!m_resources.isEmpty()) |
|
93 qDeleteAll(m_resources); |
|
94 } |
|
95 |
|
96 QVariant QTextDocumentWithImageResources::loadResource(int type, const QUrl &name) |
|
97 { |
|
98 QDeclarativeContext *context = qmlContext(parent()); |
|
99 QUrl url = context->resolvedUrl(name); |
|
100 |
|
101 if (type == QTextDocument::ImageResource) { |
|
102 QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url); |
|
103 |
|
104 if (iter == m_resources.end()) { |
|
105 QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url); |
|
106 iter = m_resources.insert(name, p); |
|
107 |
|
108 if (p->isLoading()) { |
|
109 p->connectFinished(this, SLOT(requestFinished())); |
|
110 outstanding++; |
|
111 } |
|
112 } |
|
113 |
|
114 QDeclarativePixmap *p = *iter; |
|
115 if (p->isReady()) { |
|
116 return p->pixmap(); |
|
117 } else if (p->isError()) { |
|
118 if (!errors.contains(url)) { |
|
119 errors.insert(url); |
|
120 qmlInfo(parent()) << p->error(); |
|
121 } |
|
122 } |
|
123 } |
|
124 |
|
125 return QTextDocument::loadResource(type,url); // The *resolved* URL |
|
126 } |
|
127 |
|
128 void QTextDocumentWithImageResources::requestFinished() |
|
129 { |
|
130 outstanding--; |
|
131 if (outstanding == 0) { |
|
132 QDeclarativeText *textItem = static_cast<QDeclarativeText*>(parent()); |
|
133 QString text = textItem->text(); |
|
134 #ifndef QT_NO_TEXTHTMLPARSER |
|
135 setHtml(text); |
|
136 #else |
|
137 setPlainText(text); |
|
138 #endif |
|
139 QDeclarativeTextPrivate *d = QDeclarativeTextPrivate::get(textItem); |
|
140 d->updateLayout(); |
|
141 d->markImgDirty(); |
|
142 } |
|
143 } |
|
144 |
|
145 void QTextDocumentWithImageResources::setText(const QString &text) |
|
146 { |
|
147 if (!m_resources.isEmpty()) { |
|
148 qWarning("CLEAR"); |
|
149 qDeleteAll(m_resources); |
|
150 m_resources.clear(); |
|
151 outstanding = 0; |
|
152 } |
|
153 |
|
154 #ifndef QT_NO_TEXTHTMLPARSER |
|
155 setHtml(text); |
|
156 #else |
|
157 setPlainText(text); |
|
158 #endif |
|
159 } |
110 |
160 |
111 QSet<QUrl> QTextDocumentWithImageResources::errors; |
161 QSet<QUrl> QTextDocumentWithImageResources::errors; |
112 |
162 |
113 /*! |
163 /*! |
114 \qmlclass Text QDeclarativeText |
164 \qmlclass Text QDeclarativeText |
124 \endqml |
174 \endqml |
125 |
175 |
126 \image declarative-text.png |
176 \image declarative-text.png |
127 |
177 |
128 If height and width are not explicitly set, Text will attempt to determine how |
178 If height and width are not explicitly set, Text will attempt to determine how |
129 much room is needed and set it accordingly. Unless \c wrapMode is set, it will always |
179 much room is needed and set it accordingly. Unless \l wrapMode is set, it will always |
130 prefer width to height (all text will be placed on a single line). |
180 prefer width to height (all text will be placed on a single line). |
131 |
181 |
132 The \c elide property can alternatively be used to fit a single line of |
182 The \l elide property can alternatively be used to fit a single line of |
133 plain text to a set width. |
183 plain text to a set width. |
134 |
184 |
135 Note that the \l{Supported HTML Subset} is limited. Also, if the text contains |
185 Note that the \l{Supported HTML Subset} is limited. Also, if the text contains |
136 HTML img tags that load remote images, the text is reloaded. |
186 HTML img tags that load remote images, the text is reloaded. |
137 |
187 |
138 Text provides read-only text. For editable text, see \l TextEdit. |
188 Text provides read-only text. For editable text, see \l TextEdit. |
|
189 |
|
190 \sa {declarative/text/fonts}{Fonts example} |
139 */ |
191 */ |
140 |
192 |
141 /*! |
193 /*! |
142 \internal |
194 \internal |
143 \class QDeclarativeText |
195 \class QDeclarativeText |
159 much room is needed and set it accordingly. Unless \c wrapMode is set, it will always |
211 much room is needed and set it accordingly. Unless \c wrapMode is set, it will always |
160 prefer width to height (all text will be placed on a single line). |
212 prefer width to height (all text will be placed on a single line). |
161 |
213 |
162 The \c elide property can alternatively be used to fit a line of plain text to a set width. |
214 The \c elide property can alternatively be used to fit a line of plain text to a set width. |
163 |
215 |
164 A QDeclarativeText object can be instantiated in Qml using the tag \c Text. |
216 A QDeclarativeText object can be instantiated in QML using the tag \c Text. |
165 */ |
217 */ |
166 QDeclarativeText::QDeclarativeText(QDeclarativeItem *parent) |
218 QDeclarativeText::QDeclarativeText(QDeclarativeItem *parent) |
167 : QDeclarativeItem(*(new QDeclarativeTextPrivate), parent) |
219 : QDeclarativeItem(*(new QDeclarativeTextPrivate), parent) |
168 { |
220 { |
169 } |
221 } |
487 Q_D(QDeclarativeText); |
535 Q_D(QDeclarativeText); |
488 if (d->vAlign == align) |
536 if (d->vAlign == align) |
489 return; |
537 return; |
490 |
538 |
491 d->vAlign = align; |
539 d->vAlign = align; |
|
540 update(); |
492 emit verticalAlignmentChanged(align); |
541 emit verticalAlignmentChanged(align); |
493 } |
542 } |
494 |
543 |
495 /*! |
544 /*! |
496 \qmlproperty enumeration Text::wrapMode |
545 \qmlproperty enumeration Text::wrapMode |
497 |
546 |
498 Set this property to wrap the text to the Text item's width. The text will only |
547 Set this property to wrap the text to the Text item's width. The text will only |
499 wrap if an explicit width has been set. wrapMode can be one of: |
548 wrap if an explicit width has been set. wrapMode can be one of: |
500 |
549 |
501 \list |
550 \list |
502 \o Text.NoWrap - no wrapping will be performed. |
551 \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width. |
503 \o Text.WordWrap - wrapping is done on word boundaries. If the text cannot be |
552 \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width. |
504 word-wrapped to the specified width it will be partially drawn outside of the item's bounds. |
553 \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word. |
505 If this is undesirable then enable clipping on the item (Item::clip). |
554 \o Text.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word. |
506 \o Text.WrapAnywhere - Text can be wrapped at any point on a line, even if it occurs in the middle of a word. |
|
507 \o Text.WrapAtWordBoundaryOrAnywhere - If possible, wrapping occurs at a word boundary; otherwise it |
|
508 will occur at the appropriate point on the line, even in the middle of a word. |
|
509 \endlist |
555 \endlist |
510 |
|
511 The default is Text.NoWrap. |
|
512 */ |
556 */ |
513 QDeclarativeText::WrapMode QDeclarativeText::wrapMode() const |
557 QDeclarativeText::WrapMode QDeclarativeText::wrapMode() const |
514 { |
558 { |
515 Q_D(const QDeclarativeText); |
559 Q_D(const QDeclarativeText); |
516 return d->wrapMode; |
560 return d->wrapMode; |
536 The way the text property should be displayed. |
580 The way the text property should be displayed. |
537 |
581 |
538 Supported text formats are: |
582 Supported text formats are: |
539 |
583 |
540 \list |
584 \list |
541 \o Text.AutoText |
585 \o Text.AutoText (default) |
542 \o Text.PlainText |
586 \o Text.PlainText |
543 \o Text.RichText |
587 \o Text.RichText |
544 \o Text.StyledText |
588 \o Text.StyledText |
545 \endlist |
589 \endlist |
546 |
590 |
547 The default is Text.AutoText. If the text format is Text.AutoText the text element |
591 If the text format is \c Text.AutoText the text element |
548 will automatically determine whether the text should be treated as |
592 will automatically determine whether the text should be treated as |
549 rich text. This determination is made using Qt::mightBeRichText(). |
593 rich text. This determination is made using Qt::mightBeRichText(). |
550 |
594 |
551 Text.StyledText is an optimized format supporting some basic text |
595 Text.StyledText is an optimized format supporting some basic text |
552 styling markup, in the style of html 3.2: |
596 styling markup, in the style of html 3.2: |
656 d->updateLayout(); |
700 d->updateLayout(); |
657 d->markImgDirty(); |
701 d->markImgDirty(); |
658 emit elideModeChanged(d->elideMode); |
702 emit elideModeChanged(d->elideMode); |
659 } |
703 } |
660 |
704 |
|
705 QRectF QDeclarativeText::boundingRect() const |
|
706 { |
|
707 Q_D(const QDeclarativeText); |
|
708 |
|
709 int w = width(); |
|
710 int h = height(); |
|
711 |
|
712 int x = 0; |
|
713 int y = 0; |
|
714 |
|
715 QSize size = d->cachedLayoutSize; |
|
716 if (d->style != Normal) |
|
717 size += QSize(2,2); |
|
718 |
|
719 // Could include font max left/right bearings to either side of rectangle. |
|
720 |
|
721 switch (d->hAlign) { |
|
722 case AlignLeft: |
|
723 x = 0; |
|
724 break; |
|
725 case AlignRight: |
|
726 x = w - size.width(); |
|
727 break; |
|
728 case AlignHCenter: |
|
729 x = (w - size.width()) / 2; |
|
730 break; |
|
731 } |
|
732 |
|
733 switch (d->vAlign) { |
|
734 case AlignTop: |
|
735 y = 0; |
|
736 break; |
|
737 case AlignBottom: |
|
738 y = h - size.height(); |
|
739 break; |
|
740 case AlignVCenter: |
|
741 y = (h - size.height()) / 2; |
|
742 break; |
|
743 } |
|
744 |
|
745 return QRectF(x,y,size.width(),size.height()); |
|
746 } |
|
747 |
661 void QDeclarativeText::geometryChanged(const QRectF &newGeometry, |
748 void QDeclarativeText::geometryChanged(const QRectF &newGeometry, |
662 const QRectF &oldGeometry) |
749 const QRectF &oldGeometry) |
663 { |
750 { |
664 Q_D(QDeclarativeText); |
751 Q_D(QDeclarativeText); |
665 if (newGeometry.width() != oldGeometry.width()) { |
752 if (!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width()) { |
666 if (d->wrapMode != QDeclarativeText::NoWrap || d->elideMode != QDeclarativeText::ElideNone) { |
753 if (d->wrapMode != QDeclarativeText::NoWrap || d->elideMode != QDeclarativeText::ElideNone) { |
667 //re-elide if needed |
754 //re-elide if needed |
668 if (d->singleline && d->elideMode != QDeclarativeText::ElideNone && |
755 if (d->singleline && d->elideMode != QDeclarativeText::ElideNone && |
669 isComponentComplete() && widthValid()) { |
756 isComponentComplete() && widthValid()) { |
670 |
757 |
706 } else { |
793 } else { |
707 dirty = true; |
794 dirty = true; |
708 } |
795 } |
709 } |
796 } |
710 |
797 |
|
798 |
711 void QDeclarativeTextPrivate::updateSize() |
799 void QDeclarativeTextPrivate::updateSize() |
712 { |
800 { |
713 Q_Q(QDeclarativeText); |
801 Q_Q(QDeclarativeText); |
714 if (q->isComponentComplete()) { |
802 if (q->isComponentComplete()) { |
715 QFontMetrics fm(font); |
803 QFontMetrics fm(font); |
716 if (text.isEmpty()) { |
804 if (text.isEmpty()) { |
717 q->setImplicitHeight(fm.height()); |
805 q->setImplicitHeight(fm.height()); |
|
806 emit q->paintedSizeChanged(); |
718 return; |
807 return; |
719 } |
808 } |
720 |
809 |
721 int dy = q->height(); |
810 int dy = q->height(); |
722 QSize size(0, 0); |
811 QSize size(0, 0); |
723 |
812 |
724 //setup instance of QTextLayout for all cases other than richtext |
813 //setup instance of QTextLayout for all cases other than richtext |
725 if (!richText) { |
814 if (!richText) { |
726 size = setupTextLayout(&layout); |
815 size = setupTextLayout(&layout); |
727 cachedLayoutSize = size; |
816 if (cachedLayoutSize != size) { |
|
817 q->prepareGeometryChange(); |
|
818 cachedLayoutSize = size; |
|
819 } |
728 dy -= size.height(); |
820 dy -= size.height(); |
729 } else { |
821 } else { |
730 singleline = false; // richtext can't elide or be optimized for single-line case |
822 singleline = false; // richtext can't elide or be optimized for single-line case |
731 ensureDoc(); |
823 ensureDoc(); |
732 doc->setDefaultFont(font); |
824 doc->setDefaultFont(font); |
736 if (wrapMode != QDeclarativeText::NoWrap && q->widthValid()) |
828 if (wrapMode != QDeclarativeText::NoWrap && q->widthValid()) |
737 doc->setTextWidth(q->width()); |
829 doc->setTextWidth(q->width()); |
738 else |
830 else |
739 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug) |
831 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug) |
740 dy -= (int)doc->size().height(); |
832 dy -= (int)doc->size().height(); |
741 cachedLayoutSize = doc->size().toSize(); |
833 q->prepareGeometryChange(); |
|
834 QSize dsize = doc->size().toSize(); |
|
835 if (dsize != cachedLayoutSize) { |
|
836 q->prepareGeometryChange(); |
|
837 cachedLayoutSize = dsize; |
|
838 } |
|
839 size = QSize(int(doc->idealWidth()),dsize.height()); |
742 } |
840 } |
743 int yoff = 0; |
841 int yoff = 0; |
744 |
842 |
745 if (q->heightValid()) { |
843 if (q->heightValid()) { |
746 if (vAlign == QDeclarativeText::AlignBottom) |
844 if (vAlign == QDeclarativeText::AlignBottom) |
749 yoff = dy/2; |
847 yoff = dy/2; |
750 } |
848 } |
751 q->setBaselineOffset(fm.ascent() + yoff); |
849 q->setBaselineOffset(fm.ascent() + yoff); |
752 |
850 |
753 //### need to comfirm cost of always setting these for richText |
851 //### need to comfirm cost of always setting these for richText |
754 q->setImplicitWidth(richText ? (int)doc->idealWidth() : size.width()); |
852 internalWidthUpdate = true; |
755 q->setImplicitHeight(richText ? (int)doc->size().height() : size.height()); |
853 q->setImplicitWidth(size.width()); |
|
854 internalWidthUpdate = false; |
|
855 q->setImplicitHeight(size.height()); |
|
856 emit q->paintedSizeChanged(); |
756 } else { |
857 } else { |
757 dirty = true; |
858 dirty = true; |
758 } |
859 } |
759 } |
860 } |
|
861 |
|
862 /*! |
|
863 \qmlproperty real Text::paintedWidth |
|
864 |
|
865 Returns the width of the text, including width past the width |
|
866 which is covered due to insufficient wrapping if WrapMode is set. |
|
867 */ |
|
868 qreal QDeclarativeText::paintedWidth() const |
|
869 { |
|
870 return implicitWidth(); |
|
871 } |
|
872 |
|
873 /*! |
|
874 \qmlproperty real Text::paintedHeight |
|
875 |
|
876 Returns the height of the text, including height past the height |
|
877 which is covered due to there being more text than fits in the set height. |
|
878 */ |
|
879 qreal QDeclarativeText::paintedHeight() const |
|
880 { |
|
881 return implicitHeight(); |
|
882 } |
|
883 |
|
884 |
760 |
885 |
761 // ### text layout handling should be profiled and optimized as needed |
886 // ### text layout handling should be profiled and optimized as needed |
762 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine); |
887 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine); |
763 |
888 |
764 void QDeclarativeTextPrivate::drawOutline() |
889 void QDeclarativeTextPrivate::drawOutline() |
922 { |
1065 { |
923 if (!imgDirty) |
1066 if (!imgDirty) |
924 return; |
1067 return; |
925 |
1068 |
926 bool empty = text.isEmpty(); |
1069 bool empty = text.isEmpty(); |
|
1070 QPixmap newImgCache; |
927 if (empty) { |
1071 if (empty) { |
928 imgCache = QPixmap(); |
|
929 imgStyleCache = QPixmap(); |
1072 imgStyleCache = QPixmap(); |
930 } else if (richText) { |
1073 } else if (richText) { |
931 imgCache = richTextImage(false); |
1074 newImgCache = richTextImage(false); |
932 if (style != QDeclarativeText::Normal) |
1075 if (style != QDeclarativeText::Normal) |
933 imgStyleCache = richTextImage(true); //### should use styleColor |
1076 imgStyleCache = richTextImage(true); //### should use styleColor |
934 } else { |
1077 } else { |
935 imgCache = wrappedTextImage(false); |
1078 newImgCache = wrappedTextImage(false); |
936 if (style != QDeclarativeText::Normal) |
1079 if (style != QDeclarativeText::Normal) |
937 imgStyleCache = wrappedTextImage(true); //### should use styleColor |
1080 imgStyleCache = wrappedTextImage(true); //### should use styleColor |
938 } |
1081 } |
|
1082 if (imgCache.size() != newImgCache.size()) |
|
1083 q_func()->prepareGeometryChange(); |
|
1084 imgCache = newImgCache; |
939 if (!empty) |
1085 if (!empty) |
940 switch (style) { |
1086 switch (style) { |
941 case QDeclarativeText::Outline: |
1087 case QDeclarativeText::Outline: |
942 drawOutline(); |
1088 drawOutline(); |
943 break; |
1089 break; |
961 doc = new QTextDocumentWithImageResources(q); |
1107 doc = new QTextDocumentWithImageResources(q); |
962 doc->setDocumentMargin(0); |
1108 doc->setDocumentMargin(0); |
963 } |
1109 } |
964 } |
1110 } |
965 |
1111 |
966 void QDeclarativeText::reloadWithResources() |
|
967 { |
|
968 Q_D(QDeclarativeText); |
|
969 if (!d->richText) |
|
970 return; |
|
971 d->doc->setHtml(d->text); |
|
972 d->updateLayout(); |
|
973 d->markImgDirty(); |
|
974 } |
|
975 |
|
976 /*! |
1112 /*! |
977 Returns the number of resources (images) that are being loaded asynchronously. |
1113 Returns the number of resources (images) that are being loaded asynchronously. |
978 */ |
1114 */ |
979 int QDeclarativeText::resourcesLoading() const |
1115 int QDeclarativeText::resourcesLoading() const |
980 { |
1116 { |
981 Q_D(const QDeclarativeText); |
1117 Q_D(const QDeclarativeText); |
982 return d->doc ? d->doc->resourcesLoading() : 0; |
1118 return d->doc ? d->doc->resourcesLoading() : 0; |
983 } |
1119 } |
|
1120 |
|
1121 /*! |
|
1122 \qmlproperty bool Text::clip |
|
1123 This property holds whether the text is clipped. |
|
1124 |
|
1125 Note that if the text does not fit in the bounding rectangle it will be abruptly chopped. |
|
1126 |
|
1127 If you want to display potentially long text in a limited space, you probably want to use \c elide instead. |
|
1128 */ |
984 |
1129 |
985 void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) |
1130 void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) |
986 { |
1131 { |
987 Q_D(QDeclarativeText); |
1132 Q_D(QDeclarativeText); |
988 |
1133 |
994 bool oldAA = p->testRenderHint(QPainter::Antialiasing); |
1139 bool oldAA = p->testRenderHint(QPainter::Antialiasing); |
995 bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform); |
1140 bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform); |
996 if (d->smooth) |
1141 if (d->smooth) |
997 p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); |
1142 p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); |
998 |
1143 |
999 int w = width(); |
1144 QRect br = boundingRect().toRect(); |
1000 int h = height(); |
|
1001 |
|
1002 int x = 0; |
|
1003 int y = 0; |
|
1004 |
|
1005 switch (d->hAlign) { |
|
1006 case AlignLeft: |
|
1007 x = 0; |
|
1008 break; |
|
1009 case AlignRight: |
|
1010 x = w - d->imgCache.width(); |
|
1011 break; |
|
1012 case AlignHCenter: |
|
1013 x = (w - d->imgCache.width()) / 2; |
|
1014 break; |
|
1015 } |
|
1016 |
|
1017 switch (d->vAlign) { |
|
1018 case AlignTop: |
|
1019 y = 0; |
|
1020 break; |
|
1021 case AlignBottom: |
|
1022 y = h - d->imgCache.height(); |
|
1023 break; |
|
1024 case AlignVCenter: |
|
1025 y = (h - d->imgCache.height()) / 2; |
|
1026 break; |
|
1027 } |
|
1028 |
1145 |
1029 bool needClip = clip() && (d->imgCache.width() > width() || |
1146 bool needClip = clip() && (d->imgCache.width() > width() || |
1030 d->imgCache.height() > height()); |
1147 d->imgCache.height() > height()); |
1031 |
1148 |
1032 if (needClip) { |
|
1033 p->save(); |
|
1034 p->setClipRect(boundingRect(), Qt::IntersectClip); |
|
1035 } |
|
1036 p->drawPixmap(x, y, d->imgCache); |
|
1037 if (needClip) |
1149 if (needClip) |
1038 p->restore(); |
1150 p->drawPixmap(0, 0, width(), height(), d->imgCache, -br.x(), -br.y(), width(), height()); |
|
1151 else |
|
1152 p->drawPixmap(br.x(), br.y(), d->imgCache); |
1039 |
1153 |
1040 if (d->smooth) { |
1154 if (d->smooth) { |
1041 p->setRenderHint(QPainter::Antialiasing, oldAA); |
1155 p->setRenderHint(QPainter::Antialiasing, oldAA); |
1042 p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); |
1156 p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); |
1043 } |
1157 } |
1044 } else { |
1158 } else { |
1045 int h = height(); |
1159 qreal y = boundingRect().y(); |
1046 int y = 0; |
1160 |
1047 |
|
1048 switch (d->vAlign) { |
|
1049 case AlignTop: |
|
1050 y = 0; |
|
1051 break; |
|
1052 case AlignBottom: |
|
1053 y = h - d->cachedLayoutSize.height(); |
|
1054 break; |
|
1055 case AlignVCenter: |
|
1056 y = (h - d->cachedLayoutSize.height()) / 2; |
|
1057 break; |
|
1058 } |
|
1059 bool needClip = !clip() && (d->cachedLayoutSize.width() > width() || |
1161 bool needClip = !clip() && (d->cachedLayoutSize.width() > width() || |
1060 d->cachedLayoutSize.height() > height()); |
1162 d->cachedLayoutSize.height() > height()); |
1061 |
1163 |
1062 if (needClip) { |
1164 if (needClip) { |
1063 p->save(); |
1165 p->save(); |
1064 p->setClipRect(boundingRect(), Qt::IntersectClip); |
1166 p->setClipRect(0, 0, width(), height(), Qt::IntersectClip); |
1065 } |
1167 } |
1066 if (d->richText) { |
1168 if (d->richText) { |
1067 QAbstractTextDocumentLayout::PaintContext context; |
1169 QAbstractTextDocumentLayout::PaintContext context; |
1068 context.palette.setColor(QPalette::Text, d->color); |
1170 context.palette.setColor(QPalette::Text, d->color); |
1069 p->translate(0, y); |
1171 p->translate(0, y); |