1 /*
2 * %kadu copyright begin%
3 * Copyright 2011 Piotr Galiszewski (piotr.galiszewski@kadu.im)
4 * Copyright 2011 Piotr Dąbrowski (ultr@ultr.pl)
5 * Copyright 2013, 2014 Bartosz Brachaczek (b.brachaczek@gmail.com)
6 * Copyright 2011, 2013, 2014 Rafał Przemysław Malinowski (rafal.przemyslaw.malinowski@gmail.com)
7 * %kadu copyright end%
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include <math.h>
24
25 #include <QtCore/QBuffer>
26 #include <QtCore/QTimer>
27 #include <QtGui/QCursor>
28 #include <QtGui/QResizeEvent>
29 #include <QtWidgets/QGraphicsPixmapItem>
30 #include <QtWidgets/QGraphicsProxyWidget>
31
32 #include "gui/graphics-items/selection-frame-item.h"
33 #include "gui/widgets/screenshot-tool-box.h"
34
35 #include "crop-image-widget.h"
36
37 #define HANDLER_SIZE 10
38 #define HANDLER_HALF_SIZE (HANDLER_SIZE/2)
39 #define TOOLBOX_PADDING 10
40
CropImageWidget(QWidget * parent)41 CropImageWidget::CropImageWidget(QWidget *parent) :
42 QGraphicsView(parent), IsMouseButtonPressed(false)
43 {
44 setContentsMargins(0, 0, 0, 0);
45 setFrameShape(NoFrame);
46 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
47 setInteractive(true);
48 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
49
50 QGraphicsScene *graphicsScene = new QGraphicsScene(this);
51 setScene(graphicsScene);
52
53 PixmapItem = new QGraphicsPixmapItem();
54 PixmapItem->setCursor(Qt::CrossCursor);
55 PixmapItem->setPos(0, 0);
56
57 scene()->addItem(PixmapItem);
58
59 SelectionFrame = new SelectionFrameItem();
60 SelectionFrame->setPos(0, 0);
61 SelectionFrame->setSize(size());
62
63 scene()->addItem(SelectionFrame);
64
65 ToolBox = new ScreenshotToolBox();
66 connect(ToolBox, SIGNAL(crop()), this, SLOT(crop()));
67 connect(ToolBox, SIGNAL(cancel()), this, SIGNAL(canceled()));
68
69 ToolBoxTimer = new QTimer(this);
70 connect(ToolBoxTimer, SIGNAL(timeout()), this, SLOT(updateToolBoxFileSizeHint()));
71 ToolBoxTimer->start(1000);
72
73 ToolBoxProxy = new QGraphicsProxyWidget();
74 ToolBoxProxy->setWidget(ToolBox);
75 scene()->addItem(ToolBoxProxy);
76
77 TopLeftHandler = new HandlerRectItem(HandlerTopLeft, HANDLER_SIZE);
78 TopLeftHandler->setCursor(Qt::SizeFDiagCursor);
79 connect(TopLeftHandler, SIGNAL(movedTo(HandlerType,int,int)), this, SLOT(handlerMovedTo(HandlerType,int,int)));
80 scene()->addItem(TopLeftHandler);
81
82 TopHandler = new HandlerRectItem(HandlerTop, HANDLER_SIZE);
83 TopHandler->setCursor(Qt::SizeVerCursor);
84 connect(TopHandler, SIGNAL(movedTo(HandlerType,int,int)), this, SLOT(handlerMovedTo(HandlerType,int,int)));
85 scene()->addItem(TopHandler);
86
87 TopRightHandler = new HandlerRectItem(HandlerTopRight, HANDLER_SIZE);
88 TopRightHandler->setCursor(Qt::SizeBDiagCursor);
89 connect(TopRightHandler, SIGNAL(movedTo(HandlerType,int,int)), this, SLOT(handlerMovedTo(HandlerType,int,int)));
90 scene()->addItem(TopRightHandler);
91
92 LeftHandler = new HandlerRectItem(HandlerLeft, HANDLER_SIZE);
93 LeftHandler->setCursor(Qt::SizeHorCursor);
94 connect(LeftHandler, SIGNAL(movedTo(HandlerType,int,int)), this, SLOT(handlerMovedTo(HandlerType,int,int)));
95 scene()->addItem(LeftHandler);
96
97 RightHandler = new HandlerRectItem(HandlerRight, HANDLER_SIZE);
98 RightHandler->setCursor(Qt::SizeHorCursor);
99 connect(RightHandler, SIGNAL(movedTo(HandlerType,int,int)), this, SLOT(handlerMovedTo(HandlerType,int,int)));
100 scene()->addItem(RightHandler);
101
102 BottomLeftHandler = new HandlerRectItem(HandlerBottomLeft, HANDLER_SIZE);
103 BottomLeftHandler->setCursor(Qt::SizeBDiagCursor);
104 connect(BottomLeftHandler, SIGNAL(movedTo(HandlerType,int,int)), this, SLOT(handlerMovedTo(HandlerType,int,int)));
105 scene()->addItem(BottomLeftHandler);
106
107 BottomHandler = new HandlerRectItem(HandlerBottom, HANDLER_SIZE);
108 BottomHandler->setCursor(Qt::SizeVerCursor);
109 connect(BottomHandler, SIGNAL(movedTo(HandlerType,int,int)), this, SLOT(handlerMovedTo(HandlerType,int,int)));
110 scene()->addItem(BottomHandler);
111
112 BottomRightHandler = new HandlerRectItem(HandlerBottomRight, HANDLER_SIZE);
113 BottomRightHandler->setCursor(Qt::SizeFDiagCursor);
114 connect(BottomRightHandler, SIGNAL(movedTo(HandlerType,int,int)), this, SLOT(handlerMovedTo(HandlerType,int,int)));
115 scene()->addItem(BottomRightHandler);
116
117 CropRect.setTopLeft(QPoint(0, 0));
118 CropRect.setSize(size());
119 updateCropRectDisplay();
120 }
121
~CropImageWidget()122 CropImageWidget::~CropImageWidget()
123 {
124 }
125
normalizeCropRect()126 void CropImageWidget::normalizeCropRect()
127 {
128 CropRect = CropRect.normalized();
129 updateCropRectDisplay();
130 }
131
updateCropRectDisplay()132 void CropImageWidget::updateCropRectDisplay()
133 {
134 QRect normalized = CropRect.normalized();
135 SelectionFrame->setSelection(normalized);
136
137 // workaround for wrong cursor on negative coordinates
138 TopLeftHandler->setPos(CropRect.left() - HANDLER_HALF_SIZE, CropRect.top() - HANDLER_HALF_SIZE);
139 TopHandler->setPos(normalized.center().x() - HANDLER_HALF_SIZE, CropRect.top() - HANDLER_HALF_SIZE);
140 TopRightHandler->setPos(CropRect.right() - HANDLER_HALF_SIZE, CropRect.top() - HANDLER_HALF_SIZE);
141 LeftHandler->setPos(CropRect.left() - HANDLER_HALF_SIZE, normalized.center().y() - HANDLER_HALF_SIZE);
142 RightHandler->setPos(CropRect.right() - HANDLER_HALF_SIZE, normalized.center().y() - HANDLER_HALF_SIZE);
143 BottomLeftHandler->setPos(CropRect.left() - HANDLER_HALF_SIZE, CropRect.bottom() - HANDLER_HALF_SIZE);
144 BottomHandler->setPos(normalized.center().x() - HANDLER_HALF_SIZE, CropRect.bottom() - HANDLER_HALF_SIZE);
145 BottomRightHandler->setPos(CropRect.right() - HANDLER_HALF_SIZE, CropRect.bottom() - HANDLER_HALF_SIZE);
146
147 ToolBox->setGeometry(QString("%1x%2").arg(normalized.width()).arg(normalized.height()));
148
149 int left = normalized.right() + TOOLBOX_PADDING;
150 if (left + ToolBox->width() > width())
151 left = normalized.left() - TOOLBOX_PADDING - ToolBox->width();
152 if (left < 0)
153 left = normalized.center().x() - ToolBox->width() / 2;
154
155 int top = normalized.bottom() + TOOLBOX_PADDING;
156 if (top + ToolBox->height() > height())
157 top = normalized.top() - TOOLBOX_PADDING - ToolBox->height();
158 if (top < 0)
159 top = normalized.center().y() - ToolBox->height() / 2;
160
161 ToolBoxProxy->setPos(left, top);
162
163 scene()->update(scene()->sceneRect());
164 }
165
croppedPixmap()166 QPixmap CropImageWidget::croppedPixmap()
167 {
168 if (CropRect.normalized().isEmpty())
169 return QPixmap();
170 return PixmapItem->pixmap().copy(CropRect.normalized());
171 }
172
handlerMovedTo(HandlerType type,int x,int y)173 void CropImageWidget::handlerMovedTo(HandlerType type, int x, int y)
174 {
175 if (type == HandlerTopLeft || type == HandlerTop || type == HandlerTopRight)
176 CropRect.setTop(y);
177 else if (type == HandlerBottomLeft || type == HandlerBottom || type == HandlerBottomRight)
178 CropRect.setBottom(y);
179
180 if (type == HandlerTopLeft || type == HandlerLeft || type == HandlerBottomLeft)
181 CropRect.setLeft(x);
182 else if (type == HandlerTopRight || type == HandlerRight || type == HandlerBottomRight)
183 CropRect.setRight(x);
184
185 updateCropRectDisplay();
186 }
187
crop()188 void CropImageWidget::crop()
189 {
190 emit pixmapCropped(croppedPixmap());
191 }
192
updateToolBoxFileSizeHint()193 void CropImageWidget::updateToolBoxFileSizeHint()
194 {
195 if (CropRect.normalized() == OldCropRect)
196 return;
197 OldCropRect = CropRect.normalized();
198
199 QBuffer buffer;
200 QPixmap pixmap = croppedPixmap();
201
202 if (pixmap.isNull())
203 {
204 ToolBox->setFileSize("0 KiB");
205 return;
206 }
207
208 bool ret = pixmap.save(&buffer, "png");
209
210 if (ret)
211 ToolBox->setFileSize(QString::number(ceil(1.0 * buffer.size() / 1024.0)) + " KiB");
212 }
213
keyPressEvent(QKeyEvent * e)214 void CropImageWidget::keyPressEvent(QKeyEvent *e)
215 {
216 if (e->key() == Qt::Key_Escape)
217 {
218 emit canceled();
219 e->accept();
220 }
221 else
222 QWidget::keyPressEvent(e);
223 }
224
mousePressEvent(QMouseEvent * event)225 void CropImageWidget::mousePressEvent(QMouseEvent *event)
226 {
227 QGraphicsView::mousePressEvent(event);
228 if (event->isAccepted())
229 return;
230
231 if (event->button() != Qt::LeftButton)
232 return;
233
234 IsMouseButtonPressed = true;
235 WasDoubleClick = false;
236
237 NewTopLeft = event->pos();
238
239 updateCropRectDisplay();
240 }
241
mouseReleaseEvent(QMouseEvent * event)242 void CropImageWidget::mouseReleaseEvent(QMouseEvent *event)
243 {
244 QGraphicsView::mouseReleaseEvent(event);
245 normalizeCropRect();
246
247 if (!IsMouseButtonPressed)
248 return;
249
250 if (event->button() != Qt::LeftButton)
251 return;
252
253 IsMouseButtonPressed = false;
254
255 CropRect.setTopLeft(NewTopLeft);
256 CropRect.setBottomRight(event->pos());
257 normalizeCropRect();
258 updateToolBoxFileSizeHint();
259 }
260
mouseMoveEvent(QMouseEvent * event)261 void CropImageWidget::mouseMoveEvent(QMouseEvent *event)
262 {
263 QGraphicsView::mouseMoveEvent(event);
264
265 if (!IsMouseButtonPressed)
266 return;
267
268 CropRect.setTopLeft(NewTopLeft);
269 CropRect.setBottomRight(event->pos());
270 normalizeCropRect();
271 }
272
resizeEvent(QResizeEvent * event)273 void CropImageWidget::resizeEvent(QResizeEvent *event)
274 {
275 SelectionFrame->setSize(event->size());
276 QGraphicsView::resizeEvent(event);
277
278 scene()->setSceneRect(QRectF(0, 0, event->size().width(), event->size().height()));
279 }
280
showEvent(QShowEvent * event)281 void CropImageWidget::showEvent(QShowEvent *event)
282 {
283 QGraphicsView::showEvent(event);
284
285 setCropRect(frameGeometry());
286 }
287
setPixmap(QPixmap pixmap)288 void CropImageWidget::setPixmap(QPixmap pixmap)
289 {
290 PixmapItem->setPixmap(pixmap);
291 }
292
setCropRect(const QRect & cropRect)293 void CropImageWidget::setCropRect(const QRect &cropRect)
294 {
295 CropRect = cropRect.normalized();
296 updateCropRectDisplay();
297 }
298
299 #include "moc_crop-image-widget.cpp"
300