1 /*
2 Copyright © 2015-2019 by The qTox Project Contributors
3
4 This file is part of qTox, a Qt-based graphical interface for Tox.
5
6 qTox is libre software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 qTox is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with qTox. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "movablewidget.h"
21 #include <QGraphicsOpacityEffect>
22 #include <QMouseEvent>
23 #include <cmath>
24
MovableWidget(QWidget * parent)25 MovableWidget::MovableWidget(QWidget* parent)
26 : QWidget(parent)
27 {
28 setMinimumHeight(64);
29 setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
30 actualSize = minimumSize();
31 boundaryRect = QRect(0, 0, 0, 0);
32 setRatio(1.0f);
33 resize(minimumSize());
34 actualPos = QPoint(0, 0);
35 }
36
resetBoundary(QRect newBoundary)37 void MovableWidget::resetBoundary(QRect newBoundary)
38 {
39 boundaryRect = newBoundary;
40 resize(QSize(round(actualSize.width()), round(actualSize.height())));
41
42 QPoint moveTo = QPoint(round(actualPos.x()), round(actualPos.y()));
43 checkBoundary(moveTo);
44 move(moveTo);
45 actualPos = moveTo;
46 }
47
setBoundary(QRect newBoundary)48 void MovableWidget::setBoundary(QRect newBoundary)
49 {
50 if (boundaryRect.isNull()) {
51 boundaryRect = newBoundary;
52 return;
53 }
54
55 float changeX = newBoundary.width() / static_cast<float>(boundaryRect.width());
56 float changeY = newBoundary.height() / static_cast<float>(boundaryRect.height());
57
58 float percentageX = (x() - boundaryRect.x()) / static_cast<float>(boundaryRect.width() - width());
59 float percentageY =
60 (y() - boundaryRect.y()) / static_cast<float>(boundaryRect.height() - height());
61
62 actualSize.setWidth(actualSize.width() * changeX);
63 actualSize.setHeight(actualSize.height() * changeY);
64
65 if (actualSize.width() == 0)
66 actualSize.setWidth(1);
67
68 if (actualSize.height() == 0)
69 actualSize.setHeight(1);
70
71 resize(QSize(round(actualSize.width()), round(actualSize.height())));
72
73 actualPos = QPointF(percentageX * (newBoundary.width() - width()),
74 percentageY * (newBoundary.height() - height()));
75 actualPos += QPointF(newBoundary.topLeft());
76
77 QPoint moveTo = QPoint(round(actualPos.x()), round(actualPos.y()));
78 move(moveTo);
79
80 boundaryRect = newBoundary;
81 }
82
getRatio() const83 float MovableWidget::getRatio() const
84 {
85 return ratio;
86 }
87
setRatio(float r)88 void MovableWidget::setRatio(float r)
89 {
90 ratio = r;
91 resize(width(), width() / ratio);
92 QPoint position = QPoint(actualPos.x(), actualPos.y());
93 checkBoundary(position);
94 move(position);
95
96 actualPos = pos();
97 actualSize = size();
98 }
99
mousePressEvent(QMouseEvent * event)100 void MovableWidget::mousePressEvent(QMouseEvent* event)
101 {
102 if (event->buttons() & Qt::LeftButton) {
103 if (!(mode & Resize))
104 mode |= Moving;
105
106 lastPoint = event->globalPos();
107 }
108 }
109
mouseMoveEvent(QMouseEvent * event)110 void MovableWidget::mouseMoveEvent(QMouseEvent* event)
111 {
112 if (mode & Moving) {
113 QPoint moveTo = pos() - (lastPoint - event->globalPos());
114 checkBoundary(moveTo);
115
116 move(moveTo);
117 lastPoint = event->globalPos();
118
119 actualPos = pos();
120 } else {
121 if (!(event->buttons() & Qt::LeftButton)) {
122 if (event->x() < 6)
123 mode |= ResizeLeft;
124 else
125 mode &= ~ResizeLeft;
126
127 if (event->y() < 6)
128 mode |= ResizeUp;
129 else
130 mode &= ~ResizeUp;
131
132 if (event->x() > width() - 6)
133 mode |= ResizeRight;
134 else
135 mode &= ~ResizeRight;
136
137 if (event->y() > height() - 6)
138 mode |= ResizeDown;
139 else
140 mode &= ~ResizeDown;
141 }
142
143 if (mode & Resize) {
144 const Modes ResizeUpRight = ResizeUp | ResizeRight;
145 const Modes ResizeUpLeft = ResizeUp | ResizeLeft;
146 const Modes ResizeDownRight = ResizeDown | ResizeRight;
147 const Modes ResizeDownLeft = ResizeDown | ResizeLeft;
148
149 if ((mode & ResizeUpRight) == ResizeUpRight || (mode & ResizeDownLeft) == ResizeDownLeft)
150 setCursor(Qt::SizeBDiagCursor);
151 else if ((mode & ResizeUpLeft) == ResizeUpLeft || (mode & ResizeDownRight) == ResizeDownRight)
152 setCursor(Qt::SizeFDiagCursor);
153 else if (mode & (ResizeLeft | ResizeRight))
154 setCursor(Qt::SizeHorCursor);
155 else
156 setCursor(Qt::SizeVerCursor);
157
158 if (event->buttons() & Qt::LeftButton) {
159 QPoint lastPosition = pos();
160 QPoint displacement = lastPoint - event->globalPos();
161 QSize lastSize = size();
162
163
164 if (mode & ResizeUp) {
165 lastSize.setHeight(height() + displacement.y());
166
167 if (lastSize.height() > maximumHeight())
168 lastPosition.setY(y() - displacement.y()
169 + (lastSize.height() - maximumHeight()));
170 else
171 lastPosition.setY(y() - displacement.y());
172 }
173
174 if (mode & ResizeLeft) {
175 lastSize.setWidth(width() + displacement.x());
176 if (lastSize.width() > maximumWidth())
177 lastPosition.setX(x() - displacement.x() + (lastSize.width() - maximumWidth()));
178 else
179 lastPosition.setX(x() - displacement.x());
180 }
181
182 if (mode & ResizeRight)
183 lastSize.setWidth(width() - displacement.x());
184
185 if (mode & ResizeDown)
186 lastSize.setHeight(height() - displacement.y());
187
188 if (lastSize.height() > maximumHeight())
189 lastSize.setHeight(maximumHeight());
190
191 if (lastSize.width() > maximumWidth())
192 lastSize.setWidth(maximumWidth());
193
194 if (mode & (ResizeLeft | ResizeRight)) {
195 if (mode & (ResizeUp | ResizeDown)) {
196 int height = lastSize.width() / getRatio();
197
198 if (!(mode & ResizeDown))
199 lastPosition.setY(lastPosition.y() - (height - lastSize.height()));
200
201 resize(lastSize.width(), height);
202
203 if (lastSize.width() < minimumWidth())
204 lastPosition.setX(pos().x());
205
206 if (height < minimumHeight())
207 lastPosition.setY(pos().y());
208 } else {
209 resize(lastSize.width(), lastSize.width() / getRatio());
210 }
211 } else {
212 resize(lastSize.height() * getRatio(), lastSize.height());
213 }
214
215 updateGeometry();
216
217 checkBoundary(lastPosition);
218
219 move(lastPosition);
220
221 lastPoint = event->globalPos();
222 actualSize = size();
223 actualPos = pos();
224 }
225 } else {
226 unsetCursor();
227 }
228 }
229 }
230
mouseReleaseEvent(QMouseEvent * event)231 void MovableWidget::mouseReleaseEvent(QMouseEvent* event)
232 {
233 if (!(event->buttons() & Qt::LeftButton))
234 mode = 0;
235 }
236
mouseDoubleClickEvent(QMouseEvent * event)237 void MovableWidget::mouseDoubleClickEvent(QMouseEvent* event)
238 {
239 if (!(event->buttons() & Qt::LeftButton))
240 return;
241
242 if (!graphicsEffect()) {
243 QGraphicsOpacityEffect* opacityEffect = new QGraphicsOpacityEffect(this);
244 opacityEffect->setOpacity(0.5);
245 setGraphicsEffect(opacityEffect);
246 } else {
247 setGraphicsEffect(nullptr);
248 }
249 }
250
checkBoundary(QPoint & point) const251 void MovableWidget::checkBoundary(QPoint& point) const
252 {
253 int x1, y1, x2, y2;
254 boundaryRect.getCoords(&x1, &y1, &x2, &y2);
255
256 if (point.x() < boundaryRect.left())
257 point.setX(boundaryRect.left());
258
259 if (point.y() < boundaryRect.top())
260 point.setY(boundaryRect.top());
261
262 if (point.x() + width() > boundaryRect.right() + 1)
263 point.setX(boundaryRect.right() - width() + 1);
264
265 if (point.y() + height() > boundaryRect.bottom() + 1)
266 point.setY(boundaryRect.bottom() - height() + 1);
267 }
268