1 /************************************************************************
2  *
3  * This file is part of SuperCollider Qt GUI.
4  *
5  * Copyright 2013 Jakob Leben (jakob.leben@gmail.com)
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  ************************************************************************/
21 
22 #pragma once
23 
24 #include <QImage>
25 #include <QPixmap>
26 #include <QPainter>
27 #include <QSharedPointer>
28 #include <QMetaType>
29 #include <cassert>
30 
31 namespace QtCollider {
32 
33 class Image {
34     enum State { Null, ImageState, PixmapState };
35 
36 public:
Image()37     Image(): transformationMode(Qt::SmoothTransformation), m_state(Null), m_painting(false) {}
38 
setImage(const QImage & image)39     void setImage(const QImage& image) {
40         assert(!m_painting);
41         m_pixmap = QPixmap();
42         m_image = image;
43         m_state = ImageState;
44     }
45 
setPixmap(const QPixmap & pixmap)46     void setPixmap(const QPixmap& pixmap) {
47         assert(!m_painting);
48         m_image = QImage();
49         m_pixmap = pixmap;
50         m_state = PixmapState;
51     }
52 
image()53     QImage& image() {
54         if (m_state == ImageState)
55             return m_image;
56         assert(!m_painting);
57         if (m_state == PixmapState) {
58             m_image = m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
59             m_image.setDevicePixelRatio(m_pixmap.devicePixelRatio());
60             m_pixmap = QPixmap();
61         }
62         m_state = ImageState;
63         return m_image;
64     }
65 
pixmap()66     QPixmap& pixmap() {
67         assert(!m_painting);
68         if (m_state == PixmapState)
69             return m_pixmap;
70         if (m_state == ImageState) {
71             m_pixmap = QPixmap::fromImage(m_image);
72             m_pixmap.setDevicePixelRatio(m_image.devicePixelRatio());
73             m_image = QImage();
74         }
75         m_state = PixmapState;
76         return m_pixmap;
77     }
78 
clear()79     void clear() {
80         assert(!m_painting);
81         m_image = QImage();
82         m_pixmap = QPixmap();
83         m_state = Null;
84     }
85 
isNull()86     bool isNull() const { return m_state == Null; }
87 
width()88     int width() const {
89         switch (m_state) {
90         case ImageState:
91             return m_image.width();
92         case PixmapState:
93             return m_pixmap.width();
94         default:
95             return 0;
96         }
97     }
98 
height()99     int height() const {
100         switch (m_state) {
101         case ImageState:
102             return m_image.height();
103         case PixmapState:
104             return m_pixmap.height();
105         default:
106             return 0;
107         }
108     }
109 
rect()110     QRect rect() const {
111         switch (m_state) {
112         case ImageState:
113             return m_image.rect();
114         case PixmapState:
115             return m_pixmap.rect();
116         default:
117             return QRect();
118         }
119     }
120 
resize(const QSize & new_size,int resize_mode)121     void resize(const QSize& new_size, int resize_mode) {
122         assert(!m_painting);
123 
124         if (m_state == Null)
125             return;
126 
127         switch (resize_mode) {
128         case 0: {
129             if (m_state == ImageState) {
130                 QImage new_image(new_size, QImage::Format_ARGB32_Premultiplied);
131                 new_image.setDevicePixelRatio(m_image.devicePixelRatio());
132                 new_image.fill(Qt::transparent);
133                 QPainter painter(&new_image);
134                 painter.drawImage(QPointF(0, 0), m_image);
135                 painter.end();
136                 m_image = new_image;
137             } else {
138                 QPixmap new_pixmap(new_size);
139                 new_pixmap.setDevicePixelRatio(m_pixmap.devicePixelRatio());
140                 new_pixmap.fill(Qt::transparent);
141                 QPainter painter(&new_pixmap);
142                 painter.drawPixmap(QPointF(0, 0), m_pixmap);
143                 painter.end();
144                 m_pixmap = new_pixmap;
145             }
146             break;
147         }
148         case 1:
149         case 2:
150         case 3: {
151             Qt::AspectRatioMode aspectRatioMode = (Qt::AspectRatioMode)(resize_mode - 1);
152             if (m_state == ImageState) {
153                 m_image = m_image.scaled(new_size, aspectRatioMode, transformationMode);
154             } else {
155                 m_pixmap = m_pixmap.scaled(new_size, aspectRatioMode, transformationMode);
156             }
157             break;
158         }
159         default:
160             break;
161         }
162     }
163 
getDevicePixelRatio()164     qreal getDevicePixelRatio() const {
165         switch (m_state) {
166         case ImageState:
167             return m_image.devicePixelRatio();
168         case PixmapState:
169             return m_pixmap.devicePixelRatio();
170         default:
171             return 1;
172         }
173     }
174 
setDevicePixelRatio(qreal ratio)175     void setDevicePixelRatio(qreal ratio) {
176         switch (m_state) {
177         case ImageState:
178             m_image.setDevicePixelRatio(ratio);
179         case PixmapState:
180             m_pixmap.setDevicePixelRatio(ratio);
181         default:
182             break;
183         }
184     }
185 
isPainting()186     bool isPainting() const { return m_painting; }
setPainting(bool painting)187     void setPainting(bool painting) { m_painting = painting; }
188 
189     Qt::TransformationMode transformationMode;
190 
191 private:
192     QImage m_image;
193     QPixmap m_pixmap;
194     State m_state;
195     bool m_painting;
196 };
197 
198 typedef QSharedPointer<QtCollider::Image> SharedImage;
199 
200 } // namespace QtCollider
201 
202 Q_DECLARE_METATYPE(QtCollider::SharedImage);
203