1/*
2 SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
3 SPDX-FileCopyrightText: 2015 Luca Beltrame <lbeltrame@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "qpixmapitem.h"
9
10#include <QPainter>
11#include <QQuickWindow>
12
13QPixmapItem::QPixmapItem(QQuickItem *parent)
14 : QQuickPaintedItem(parent)
15 , m_fillMode(QPixmapItem::Stretch)
16{
17 setFlag(flag: ItemHasContents, enabled: true);
18}
19
20QPixmapItem::~QPixmapItem()
21{
22}
23
24void QPixmapItem::setPixmap(const QPixmap &pixmap)
25{
26 bool oldPixmapNull = m_pixmap.isNull();
27 m_pixmap = pixmap;
28 updatePaintedRect();
29 update();
30 Q_EMIT nativeWidthChanged();
31 Q_EMIT nativeHeightChanged();
32 Q_EMIT pixmapChanged();
33 if (oldPixmapNull != m_pixmap.isNull()) {
34 Q_EMIT nullChanged();
35 }
36}
37
38QPixmap QPixmapItem::pixmap() const
39{
40 return m_pixmap;
41}
42
43void QPixmapItem::resetPixmap()
44{
45 setPixmap(QPixmap());
46}
47
48int QPixmapItem::nativeWidth() const
49{
50 return m_pixmap.size().width() / m_pixmap.devicePixelRatio();
51}
52
53int QPixmapItem::nativeHeight() const
54{
55 return m_pixmap.size().height() / m_pixmap.devicePixelRatio();
56}
57
58QPixmapItem::FillMode QPixmapItem::fillMode() const
59{
60 return m_fillMode;
61}
62
63void QPixmapItem::setFillMode(QPixmapItem::FillMode mode)
64{
65 if (mode == m_fillMode) {
66 return;
67 }
68
69 m_fillMode = mode;
70 updatePaintedRect();
71 update();
72 Q_EMIT fillModeChanged();
73}
74
75void QPixmapItem::paint(QPainter *painter)
76{
77 if (m_pixmap.isNull()) {
78 return;
79 }
80 painter->save();
81 painter->setRenderHint(hint: QPainter::Antialiasing, on: smooth());
82 painter->setRenderHint(hint: QPainter::SmoothPixmapTransform, on: smooth());
83
84 if (m_fillMode == TileVertically) {
85 painter->scale(sx: width() / (qreal)m_pixmap.width(), sy: 1);
86 }
87
88 if (m_fillMode == TileHorizontally) {
89 painter->scale(sx: 1, sy: height() / (qreal)m_pixmap.height());
90 }
91
92 if (m_fillMode >= Tile) {
93 painter->drawTiledPixmap(rect: m_paintedRect, pm: m_pixmap);
94 } else {
95 painter->drawPixmap(targetRect: m_paintedRect, pixmap: m_pixmap, sourceRect: m_pixmap.rect());
96 }
97
98 painter->restore();
99}
100
101bool QPixmapItem::isNull() const
102{
103 return m_pixmap.isNull();
104}
105
106int QPixmapItem::paintedWidth() const
107{
108 if (m_pixmap.isNull()) {
109 return 0;
110 }
111
112 return m_paintedRect.width();
113}
114
115int QPixmapItem::paintedHeight() const
116{
117 if (m_pixmap.isNull()) {
118 return 0;
119 }
120
121 return m_paintedRect.height();
122}
123
124void QPixmapItem::updatePaintedRect()
125{
126 if (m_pixmap.isNull()) {
127 return;
128 }
129
130 QRectF sourceRect = m_paintedRect;
131
132 QRectF destRect;
133 QRectF bounds = boundingRect();
134
135 auto posAdjusted = [this](const QPointF point) {
136 auto w = window();
137 if (!w) {
138 return point;
139 }
140 const auto effectiveDpr = w->effectiveDevicePixelRatio();
141 QPointF globalPixelPos = mapToScene(point) * effectiveDpr;
142 QPointF posAdjust = QPointF(globalPixelPos.x() - std::round(x: globalPixelPos.x()), globalPixelPos.y() - std::round(x: globalPixelPos.y())) / effectiveDpr;
143 return (point - posAdjust);
144 };
145
146 switch (m_fillMode) {
147 case PreserveAspectFit: {
148 QSizeF scaled = m_pixmap.size();
149 scaled.scale(s: boundingRect().size(), mode: Qt::KeepAspectRatio);
150 destRect = QRectF(QPoint(0, 0), scaled);
151 destRect.moveCenter(p: posAdjusted(bounds.center()));
152 break;
153 }
154 case PreserveAspectCrop: {
155 QSizeF scaled = m_pixmap.size();
156 scaled.scale(s: boundingRect().size(), mode: Qt::KeepAspectRatioByExpanding);
157 destRect = QRectF(QPoint(0, 0), scaled);
158 destRect.moveCenter(p: posAdjusted(bounds.center()));
159 break;
160 }
161 case TileVertically: {
162 destRect = bounds.toRect();
163 destRect.setWidth(destRect.width() / (width() / (qreal)m_pixmap.width()));
164 break;
165 }
166 case TileHorizontally: {
167 destRect = bounds.toRect();
168 destRect.setHeight(destRect.height() / (height() / (qreal)m_pixmap.height()));
169 break;
170 }
171 case Stretch:
172 case Tile:
173 default:
174 destRect = bounds.toRect();
175 }
176
177 if (destRect != sourceRect) {
178 m_paintedRect = destRect.toRect();
179 Q_EMIT paintedHeightChanged();
180 Q_EMIT paintedWidthChanged();
181 }
182}
183
184void QPixmapItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
185{
186 QQuickPaintedItem::geometryChange(newGeometry, oldGeometry);
187 updatePaintedRect();
188}
189
190#include "moc_qpixmapitem.cpp"
191

source code of kdeclarative/src/qmlcontrols/kquickcontrolsaddons/qpixmapitem.cpp