1 /*
2  * Copyright (C) 2020 Damir Porobic <damir.porobic@gmx.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "SnippingAreaResizer.h"
21 
SnippingAreaResizer(KsnipConfig * config,QObject * parent)22 SnippingAreaResizer::SnippingAreaResizer(KsnipConfig *config, QObject *parent) :
23 	QObject(parent),
24 	mConfig(config),
25 	mIsActive(false),
26 	mIsGrabbed(false),
27 	mGrabbedHandleIndex(-1),
28 	mControlPressed(false),
29 	mAltPressed(false)
30 {
31 
32 	const auto width = 15;
33 	mHandles.append(QRectF(0, 0, width, width));
34 	mHandles.append(QRectF(0, 0, width, width));
35 	mHandles.append(QRectF(0, 0, width, width));
36 	mHandles.append(QRectF(0, 0, width, width));
37 	mHandles.append(QRectF(0, 0, width, width));
38 	mHandles.append(QRectF(0, 0, width, width));
39 	mHandles.append(QRectF(0, 0, width, width));
40 	mHandles.append(QRectF(0, 0, width, width));
41 }
42 
activate(const QRectF & rect,const QPointF & pos)43 void SnippingAreaResizer::activate(const QRectF &rect, const QPointF &pos)
44 {
45 	mIsActive = true;
46 	mCurrentRect = rect;
47 	mColor = mConfig->snippingAdornerColor();
48 	updateHandlePositions();
49 	updateCursor(pos.toPoint());
50 }
51 
deactivate()52 void SnippingAreaResizer::deactivate()
53 {
54 	mIsActive = false;
55 	mIsGrabbed = false;
56 	mGrabbedHandleIndex = -1;
57 }
58 
paint(QPainter * painter)59 void SnippingAreaResizer::paint(QPainter *painter)
60 {
61 	if(mIsActive) {
62 		painter->setRenderHint(QPainter::Antialiasing);
63 		painter->setBrush(Qt::NoBrush);
64 		painter->setPen(QPen(mColor, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin));
65 		painter->drawRect(mCurrentRect);
66 		painter->setBrush(mColor);
67 		for(const auto handle : mHandles) {
68 			painter->drawEllipse(handle);
69 		}
70 	}
71 }
72 
isActive() const73 bool SnippingAreaResizer::isActive() const
74 {
75 	return mIsActive;
76 }
77 
handleMousePress(QMouseEvent * event)78 void SnippingAreaResizer::handleMousePress(QMouseEvent *event)
79 {
80 	if(mIsActive) {
81 		auto pos = event->pos();
82 		for(const auto handle : mHandles) {
83 			if(handle.contains(pos)) {
84 				mIsGrabbed = true;
85 				mGrabOffset = pos - handle.center();
86 				mGrabbedHandleIndex = mHandles.indexOf(handle);
87 				break;
88 			}
89 		}
90 
91 		if(!mIsGrabbed && mCurrentRect.contains(pos)) {
92 			mIsGrabbed = true;
93 			mGrabOffset = pos - mCurrentRect.topLeft();
94 		}
95 	}
96 }
97 
handleMouseRelease(QMouseEvent * event)98 void SnippingAreaResizer::handleMouseRelease(QMouseEvent *event)
99 {
100 	Q_UNUSED(event)
101 
102 	if(mIsActive && mIsGrabbed) {
103 		mIsGrabbed = false;
104 		mGrabOffset = {};
105 		mGrabbedHandleIndex = -1;
106 	}
107 }
108 
handleMouseMove(QMouseEvent * event)109 void SnippingAreaResizer::handleMouseMove(QMouseEvent *event)
110 {
111 	if (mIsActive) {
112 		if (mIsGrabbed) {
113 			updateCurrentRect(event->pos());
114 		} else {
115 			updateCursor(event->pos());
116 		}
117 	}
118 }
119 
handleKeyPress(QKeyEvent * event)120 void SnippingAreaResizer::handleKeyPress(QKeyEvent *event)
121 {
122 	if (event->key() == Qt::Key_Control) {
123 		mControlPressed = true;
124 	} else if (event->key() == Qt::Key_Alt) {
125 		mAltPressed = true;
126 	}
127 
128 	if (mIsActive) {
129 		arrowKeyPressed(event);
130 		notifyRectChanged();
131 	}
132 }
133 
arrowKeyPressed(const QKeyEvent * event)134 void SnippingAreaResizer::arrowKeyPressed(const QKeyEvent *event)
135 {
136 	if (event->key() == Qt::Key_Up) {
137 		arrowUpPressed();
138 	} else if (event->key() == Qt::Key_Down) {
139 		arrowDownPressed();
140 	} else if (event->key() == Qt::Key_Left) {
141 		arrowLeftPressed();
142 	} else if (event->key() == Qt::Key_Right) {
143 		arrowRightPressed();
144 	}
145 }
146 
handleKeyRelease(QKeyEvent * event)147 void SnippingAreaResizer::handleKeyRelease(QKeyEvent *event)
148 {
149 	if(event->key() == Qt::Key_Control) {
150 		mControlPressed = false;
151 	} else if(event->key() == Qt::Key_Alt) {
152 		mAltPressed = false;
153 	}
154 }
155 
updateCursor(const QPoint & pos)156 void SnippingAreaResizer::updateCursor(const QPoint &pos)
157 {
158 	if (mHandles[1].contains(pos) || mHandles[5].contains(pos)) {
159 		emit cursorChanged(Qt::SizeVerCursor);
160 	} else if (mHandles[3].contains(pos) || mHandles[7].contains(pos)) {
161 		emit cursorChanged(Qt::SizeHorCursor);
162 	} else if (mHandles[0].contains(pos) || mHandles[2].contains(pos) || mHandles[4].contains(pos) || mHandles[6].contains(pos) || mCurrentRect.contains(pos)) {
163 		emit cursorChanged(Qt::SizeAllCursor);
164 	} else {
165 		emit cursorChanged(Qt::ArrowCursor);
166 	}
167 }
168 
updateCurrentRect(const QPoint & point)169 void SnippingAreaResizer::updateCurrentRect(const QPoint &point)
170 {
171 	if(mGrabbedHandleIndex == -1){
172 		mCurrentRect.moveTo(point - mGrabOffset);
173 	} else if(mGrabbedHandleIndex == 0){
174 		mCurrentRect.setTopLeft(point - mGrabOffset);
175 	} else if(mGrabbedHandleIndex == 1){
176 		mCurrentRect.setTop((point - mGrabOffset).y());
177 	} else if(mGrabbedHandleIndex == 2){
178 		mCurrentRect.setTopRight(point - mGrabOffset);
179 	} else if(mGrabbedHandleIndex == 3){
180 		mCurrentRect.setRight((point - mGrabOffset).x());
181 	} else if(mGrabbedHandleIndex == 4){
182 		mCurrentRect.setBottomRight(point - mGrabOffset);
183 	} else if(mGrabbedHandleIndex == 5){
184 		mCurrentRect.setBottom((point - mGrabOffset).y());
185 	} else if(mGrabbedHandleIndex == 6){
186 		mCurrentRect.setBottomLeft(point - mGrabOffset);
187 	} else if(mGrabbedHandleIndex == 7){
188 		mCurrentRect.setLeft((point - mGrabOffset).x());
189 	}
190 
191 	notifyRectChanged();
192 }
193 
notifyRectChanged()194 void SnippingAreaResizer::notifyRectChanged()
195 {
196 	updateHandlePositions();
197 	emit rectChanged(mCurrentRect.normalized());
198 }
199 
updateHandlePositions()200 void SnippingAreaResizer::updateHandlePositions()
201 {
202 	mHandles[0].moveCenter(RectHelper::topLeft(mCurrentRect));
203 	mHandles[1].moveCenter(RectHelper::top(mCurrentRect));
204 	mHandles[2].moveCenter(RectHelper::topRight(mCurrentRect));
205 	mHandles[3].moveCenter(RectHelper::right(mCurrentRect));
206 	mHandles[4].moveCenter(RectHelper::bottomRight(mCurrentRect));
207 	mHandles[5].moveCenter(RectHelper::bottom(mCurrentRect));
208 	mHandles[6].moveCenter(RectHelper::bottomLeft(mCurrentRect));
209 	mHandles[7].moveCenter(RectHelper::left(mCurrentRect));
210 }
211 
arrowRightPressed()212 void SnippingAreaResizer::arrowRightPressed()
213 {
214 	if (mControlPressed) {
215 		mCurrentRect.setLeft(mCurrentRect.left() + 1);
216 	} else if (mAltPressed) {
217 		mCurrentRect.setRight(mCurrentRect.right() + 1);
218 	} else {
219 		mCurrentRect.moveRight(mCurrentRect.right() + 1);
220 	}
221 }
222 
arrowLeftPressed()223 void SnippingAreaResizer::arrowLeftPressed()
224 {
225 	if (mControlPressed) {
226 		mCurrentRect.setLeft(mCurrentRect.left() - 1);
227 	} else if (mAltPressed) {
228 		mCurrentRect.setRight(mCurrentRect.right() - 1);
229 	} else {
230 		mCurrentRect.moveLeft(mCurrentRect.left() - 1);
231 	}
232 }
233 
arrowDownPressed()234 void SnippingAreaResizer::arrowDownPressed()
235 {
236 	if (mControlPressed) {
237 		mCurrentRect.setTop(mCurrentRect.top() + 1);
238 	} else if (mAltPressed) {
239 		mCurrentRect.setBottom(mCurrentRect.bottom() + 1);
240 	} else {
241 		mCurrentRect.moveBottom(mCurrentRect.bottom() + 1);
242 	}
243 }
244 
arrowUpPressed()245 void SnippingAreaResizer::arrowUpPressed()
246 {
247 	if (mControlPressed) {
248 		mCurrentRect.setTop(mCurrentRect.top() - 1);
249 	} else if (mAltPressed) {
250 		mCurrentRect.setBottom(mCurrentRect.bottom() - 1);
251 	} else {
252 		mCurrentRect.moveTop(mCurrentRect.top() - 1);
253 	}
254 }
255