Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_infinity_manager.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2013 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QPainter>
10
11#include <klocalizedstring.h>
12
13#include <KoCanvasController.h>
14
15#include <kis_debug.h>
16#include <KisViewManager.h>
17#include <kis_canvas2.h>
19#include <kis_config.h>
20#include <KisDocument.h>
21#include <kis_image.h>
23#include <KisView.h>
24#include <kis_algebra_2d.h>
25
28 m_filteringEnabled(false),
29 m_cursorSwitched(false),
30 m_sideRects(NSides),
31 m_canvas(canvas)
32{
35}
36
37inline void KisInfinityManager::addDecoration(const QRect &areaRect, const QPointF &handlePoint, qreal angle, Side side)
38{
39 QTransform t;
40 t.rotate(angle);
41 t = t * QTransform::fromTranslate(handlePoint.x(), handlePoint.y());
43
44 m_decorationPath.addRect(areaRect);
45 m_sideRects[side] = areaRect;
46}
47
49{
50 const QRect imageRect = m_canvas->coordinatesConverter()->imageRectInWidgetPixels().toAlignedRect();
51 const QRect widgetRect = m_canvas->canvasWidget()->rect();
52
53 KisConfig cfg(true);
54 qreal vastScrolling = cfg.vastScrolling();
55
56 int xReserve = vastScrolling * widgetRect.width();
57 int yReserve = vastScrolling * widgetRect.height();
58
59 int xThreshold = imageRect.width() - 0.4 * xReserve;
60 int yThreshold = imageRect.height() - 0.4 * yReserve;
61
62 const int stripeWidth = 48;
63
64 int xCut = widgetRect.width() - stripeWidth;
65 int yCut = widgetRect.height() - stripeWidth;
66
67 m_decorationPath = QPainterPath();
68 m_decorationPath.setFillRule(Qt::WindingFill);
69
70 m_handleTransform.clear();
71
72 m_sideRects.clear();
73 m_sideRects.resize(NSides);
74
75 bool visible = false;
76
77 if (imageRect.x() <= -xThreshold) {
78 QRect areaRect(widgetRect.adjusted(xCut, 0, 0, 0));
79 QPointF pt = areaRect.center() + QPointF(-0.1 * stripeWidth, 0);
80 addDecoration(areaRect, pt, 0, Right);
81 visible = true;
82 }
83
84 if (imageRect.y() <= -yThreshold) {
85 QRect areaRect(widgetRect.adjusted(0, yCut, 0, 0));
86 QPointF pt = areaRect.center() + QPointF(0, -0.1 * stripeWidth);
87 addDecoration(areaRect, pt, 90, Bottom);
88 visible = true;
89 }
90
91 if (imageRect.right() > widgetRect.width() + xThreshold) {
92 QRect areaRect(widgetRect.adjusted(0, 0, -xCut, 0));
93 QPointF pt = areaRect.center() + QPointF(0.1 * stripeWidth, 0);
94 addDecoration(areaRect, pt, 180, Left);
95 visible = true;
96 }
97
98 if (imageRect.bottom() > widgetRect.height() + yThreshold) {
99 QRect areaRect(widgetRect.adjusted(0, 0, 0, -yCut));
100 QPointF pt = areaRect.center() + QPointF(0, 0.1 * stripeWidth);
101 addDecoration(areaRect, pt, 270, Top);
102 visible = true;
103 }
104
105 if (!m_filteringEnabled && visible && this->visible()) {
106 KisInputManager *inputManager = m_canvas->globalInputManager();
107 if (inputManager) {
108 inputManager->attachPriorityEventFilter(this);
109 }
110
111 m_filteringEnabled = true;
112 }
113
114 if (m_filteringEnabled && (!visible || !this->visible())) {
115 KisInputManager *inputManager = m_canvas->globalInputManager();
116 if (inputManager) {
117 inputManager->detachPriorityEventFilter(this);
118 }
119
120 m_filteringEnabled = false;
121 }
122}
123
124void KisInfinityManager::drawDecoration(QPainter& gc, const QRectF& updateArea, const KisCoordinatesConverter *converter, KisCanvas2 *canvas)
125{
126 Q_UNUSED(updateArea);
127 Q_UNUSED(converter);
128 Q_UNUSED(canvas);
129
130 if (!m_filteringEnabled) return;
131
132 gc.save();
133 gc.setTransform(QTransform(), false);
134
135 KisConfig cfg(true);
136 QColor color = cfg.canvasBorderColor();
137 gc.fillPath(m_decorationPath, color.darker(115));
138
139 QPainterPath p = KisAlgebra2D::smallArrow();
140
141 Q_FOREACH (const QTransform &t, m_handleTransform) {
142 gc.fillPath(t.map(p), color);
143 }
144
145 gc.restore();
146}
147
148inline int expandLeft(int x0, int x1, int maxExpand)
149{
150 return qMax(x0 - maxExpand, qMin(x0, x1));
151}
152
153inline int expandRight(int x0, int x1, int maxExpand)
154{
155 return qMin(x0 + maxExpand, qMax(x0, x1));
156}
157
158inline QPoint getPointFromEvent(QEvent *event)
159{
160 QPoint result;
161
162 if (event->type() == QEvent::MouseMove ||
163 event->type() == QEvent::MouseButtonPress ||
164 event->type() == QEvent::MouseButtonRelease ||
165 event->type() == QEvent::Enter) {
166
167 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
168 result = mouseEvent->pos();
169
170 } else if (event->type() == QEvent::TabletMove ||
171 event->type() == QEvent::TabletPress ||
172 event->type() == QEvent::TabletRelease) {
173
174 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
175 result = tabletEvent->pos();
176 }
177
178 return result;
179}
180
181inline Qt::MouseButton getButtonFromEvent(QEvent *event)
182{
183 Qt::MouseButton button = Qt::NoButton;
184
185 if (event->type() == QEvent::MouseMove ||
186 event->type() == QEvent::MouseButtonPress ||
187 event->type() == QEvent::MouseButtonRelease) {
188
189 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
190 button = mouseEvent->button();
191
192 } else if (event->type() == QEvent::TabletMove ||
193 event->type() == QEvent::TabletPress ||
194 event->type() == QEvent::TabletRelease) {
195
196 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
197 button = tabletEvent->button();
198 }
199
200 return button;
201}
202
203bool KisInfinityManager::eventFilter(QObject *obj, QEvent *event)
204{
211 if (m_canvas == NULL || obj != m_canvas->canvasWidget()) return false;
212
214
215 bool retval = false;
216
217 switch (event->type()) {
218 case QEvent::Enter:
219 case QEvent::MouseMove:
220 case QEvent::TabletMove: {
221 QPoint pos = getPointFromEvent(event);
222
223 if (m_decorationPath.contains(pos)) {
224 if (!m_cursorSwitched) {
225 m_oldCursor = m_canvas->canvasWidget()->cursor();
226 m_cursorSwitched = true;
227 }
228 m_canvas->canvasWidget()->setCursor(Qt::PointingHandCursor);
229 retval = true;
230 } else if (m_cursorSwitched) {
231 m_canvas->canvasWidget()->setCursor(m_oldCursor);
232 m_cursorSwitched = false;
233 }
234 break;
235 }
236 case QEvent::Leave: {
237 if (m_cursorSwitched) {
238 m_canvas->canvasWidget()->setCursor(m_oldCursor);
239 m_cursorSwitched = false;
240 }
241 break;
242 }
243 case QEvent::MouseButtonPress:
244 case QEvent::TabletPress: {
245 Qt::MouseButton button = getButtonFromEvent(event);
246 retval = button == Qt::LeftButton && m_cursorSwitched;
247
248 if (button == Qt::RightButton) {
250 }
251
252 break;
253 }
254 case QEvent::MouseButtonRelease:
255 case QEvent::TabletRelease: {
256 Qt::MouseButton button = getButtonFromEvent(event);
257 retval = button == Qt::LeftButton && m_cursorSwitched;
258
259 if (retval) {
260 QPoint pos = getPointFromEvent(event);
261
262 const KisCoordinatesConverter *converter = m_canvas->coordinatesConverter();
263 QRect widgetRect = converter->widgetToImage(m_canvas->canvasWidget()->rect()).toAlignedRect();
264 KisImageWSP image = view()->image();
265
266 QRect cropRect = image->bounds();
267
268 const int hLimit = cropRect.width();
269 const int vLimit = cropRect.height();
270
271 if (m_sideRects[Right].contains(pos)) {
272 cropRect.setRight(expandRight(cropRect.right(), widgetRect.right(), hLimit));
273 }
274 if (m_sideRects[Bottom].contains(pos)) {
275 cropRect.setBottom(expandRight(cropRect.bottom(), widgetRect.bottom(), vLimit));
276 }
277 if (m_sideRects[Left].contains(pos)) {
278 cropRect.setLeft(expandLeft(cropRect.left(), widgetRect.left(), hLimit));
279 }
280 if (m_sideRects[Top].contains(pos)) {
281 cropRect.setTop(expandLeft(cropRect.top(), widgetRect.top(), vLimit));
282 }
283
284 image->resizeImage(cropRect);
285
286 // since resizing the image can cause the cursor to end up on the canvas without a move event,
287 // it can get stuck in an overridden state until it is changed by another event,
288 // and we don't want that.
289 if (m_cursorSwitched) {
290 m_canvas->canvasWidget()->setCursor(m_oldCursor);
291 m_cursorSwitched = false;
292 }
293 }
294 break;
295 }
296 default:
297 break;
298 }
299
300 return !retval ? KisCanvasDecoration::eventFilter(obj, event) : true;
301}
const Params2D p
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void sigCanvasStateChanged()
QPointer< KisView > view() const
qreal vastScrolling(bool defaultValue=false) const
QColor canvasBorderColor(bool defaultValue=false) const
_Private::Traits< T >::Result widgetToImage(const T &obj) const
void resizeImage(const QRect &newRect)
start asynchronous operation on resizing the image
Definition kis_image.cc:865
QRect bounds() const override
bool eventFilter(QObject *obj, QEvent *event) override
QPointer< KisCanvas2 > m_canvas
void drawDecoration(QPainter &gc, const QRectF &updateArea, const KisCoordinatesConverter *converter, KisCanvas2 *canvas) override
KisInfinityManager(QPointer< KisView >view, KisCanvas2 *canvas)
QVector< QTransform > m_handleTransform
QVector< QRect > m_sideRects
void addDecoration(const QRect &areaRect, const QPointF &handlePoint, qreal angle, Side side)
Central object to manage canvas input.
void detachPriorityEventFilter(QObject *filter)
detachPriorityEventFilter
void attachPriorityEventFilter(QObject *filter, int priority=0)
attachPriorityEventFilter
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
int expandLeft(int x0, int x1, int maxExpand)
QPoint getPointFromEvent(QEvent *event)
int expandRight(int x0, int x1, int maxExpand)
Qt::MouseButton getButtonFromEvent(QEvent *event)
static const QString INFINITY_DECORATION_ID
QString button(const QWheelEvent &ev)
QPainterPath smallArrow()