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>
26
29 m_filteringEnabled(false),
30 m_cursorSwitched(false),
31 m_sideRects(NSides),
32 m_canvas(canvas)
33{
34 connect(canvas, &KisCanvas2::sigCanvasStateChanged,
36}
37
38inline void KisInfinityManager::addDecoration(const QRect &areaRect, const QPointF &handlePoint, qreal angle, Side side)
39{
40 QTransform t;
41 t.rotate(angle);
42 t = t * QTransform::fromTranslate(handlePoint.x(), handlePoint.y());
44
45 m_decorationPath.addRect(areaRect);
46 m_sideRects[side] = areaRect;
47}
48
50{
51 const QRect imageRect = m_canvas->coordinatesConverter()->imageRectInWidgetPixels().toAlignedRect();
52 const QRect widgetRect = m_canvas->canvasWidget()->rect();
53
54 KisConfig cfg(true);
55 qreal vastScrolling = cfg.vastScrolling();
56
57 int xReserve = vastScrolling * widgetRect.width();
58 int yReserve = vastScrolling * widgetRect.height();
59
60 int xThreshold = imageRect.width() - 0.4 * xReserve;
61 int yThreshold = imageRect.height() - 0.4 * yReserve;
62
63 const int stripeWidth = 48;
64
65 int xCut = widgetRect.width() - stripeWidth;
66 int yCut = widgetRect.height() - stripeWidth;
67
68 m_decorationPath = QPainterPath();
69 m_decorationPath.setFillRule(Qt::WindingFill);
70
71 m_handleTransform.clear();
72
73 m_sideRects.clear();
74 m_sideRects.resize(NSides);
75
76 bool visible = false;
77
78 if (imageRect.x() <= -xThreshold) {
79 QRect areaRect(widgetRect.adjusted(xCut, 0, 0, 0));
80 QPointF pt = areaRect.center() + QPointF(-0.1 * stripeWidth, 0);
81 addDecoration(areaRect, pt, 0, Right);
82 visible = true;
83 }
84
85 if (imageRect.y() <= -yThreshold) {
86 QRect areaRect(widgetRect.adjusted(0, yCut, 0, 0));
87 QPointF pt = areaRect.center() + QPointF(0, -0.1 * stripeWidth);
88 addDecoration(areaRect, pt, 90, Bottom);
89 visible = true;
90 }
91
92 if (imageRect.right() > widgetRect.width() + xThreshold) {
93 QRect areaRect(widgetRect.adjusted(0, 0, -xCut, 0));
94 QPointF pt = areaRect.center() + QPointF(0.1 * stripeWidth, 0);
95 addDecoration(areaRect, pt, 180, Left);
96 visible = true;
97 }
98
99 if (imageRect.bottom() > widgetRect.height() + yThreshold) {
100 QRect areaRect(widgetRect.adjusted(0, 0, 0, -yCut));
101 QPointF pt = areaRect.center() + QPointF(0, 0.1 * stripeWidth);
102 addDecoration(areaRect, pt, 270, Top);
103 visible = true;
104 }
105
106 if (!m_filteringEnabled && visible && this->visible()) {
107 KisInputManager *inputManager = m_canvas->globalInputManager();
108 if (inputManager) {
109 inputManager->attachPriorityEventFilter(this);
110 }
111
112 m_filteringEnabled = true;
113 }
114
115 if (m_filteringEnabled && (!visible || !this->visible())) {
116 KisInputManager *inputManager = m_canvas->globalInputManager();
117 if (inputManager) {
118 inputManager->detachPriorityEventFilter(this);
119 }
120
121 m_filteringEnabled = false;
122 }
123}
124
125void KisInfinityManager::drawDecoration(QPainter& gc, const QRectF& updateArea, const KisCoordinatesConverter *converter, KisCanvas2 *canvas)
126{
127 Q_UNUSED(updateArea);
128 Q_UNUSED(converter);
129 Q_UNUSED(canvas);
130
131 if (!m_filteringEnabled) return;
132
133 gc.save();
134 gc.setTransform(QTransform(), false);
135
136 KisConfig cfg(true);
137 QColor color = cfg.canvasBorderColor();
138 KoColor c;
139 c.fromQColor(color.darker(115));
140 QColor darkerColor = canvas->displayRendererInterface()->convertColorToDisplayColorSpace(c);
141 gc.fillPath(m_decorationPath, darkerColor);
142 c.fromQColor(color);
144
145 QPainterPath p = KisAlgebra2D::smallArrow();
146
147 Q_FOREACH (const QTransform &t, m_handleTransform) {
148 gc.fillPath(t.map(p), color);
149 }
150
151 gc.restore();
152}
153
154inline int expandLeft(int x0, int x1, int maxExpand)
155{
156 return qMax(x0 - maxExpand, qMin(x0, x1));
157}
158
159inline int expandRight(int x0, int x1, int maxExpand)
160{
161 return qMin(x0 + maxExpand, qMax(x0, x1));
162}
163
164inline QPoint getPointFromEvent(QEvent *event)
165{
166 QPoint result;
167
168 if (event->type() == QEvent::MouseMove ||
169 event->type() == QEvent::MouseButtonPress ||
170 event->type() == QEvent::MouseButtonRelease ||
171 event->type() == QEvent::Enter) {
172
173 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
174 result = mouseEvent->pos();
175
176 } else if (event->type() == QEvent::TabletMove ||
177 event->type() == QEvent::TabletPress ||
178 event->type() == QEvent::TabletRelease) {
179
180 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
181 result = tabletEvent->pos();
182 }
183
184 return result;
185}
186
187inline Qt::MouseButton getButtonFromEvent(QEvent *event)
188{
189 Qt::MouseButton button = Qt::NoButton;
190
191 if (event->type() == QEvent::MouseMove ||
192 event->type() == QEvent::MouseButtonPress ||
193 event->type() == QEvent::MouseButtonRelease) {
194
195 QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
196 button = mouseEvent->button();
197
198 } else if (event->type() == QEvent::TabletMove ||
199 event->type() == QEvent::TabletPress ||
200 event->type() == QEvent::TabletRelease) {
201
202 QTabletEvent *tabletEvent = static_cast<QTabletEvent*>(event);
203 button = tabletEvent->button();
204 }
205
206 return button;
207}
208
209bool KisInfinityManager::eventFilter(QObject *obj, QEvent *event)
210{
217 if (m_canvas == NULL || obj != m_canvas->canvasWidget()) return false;
218
220
221 bool retval = false;
222
223 switch (event->type()) {
224 case QEvent::Enter:
225 case QEvent::MouseMove:
226 case QEvent::TabletMove: {
227 QPoint pos = getPointFromEvent(event);
228
229 if (m_decorationPath.contains(pos)) {
230 if (!m_cursorSwitched) {
231 m_oldCursor = m_canvas->canvasWidget()->cursor();
232 m_cursorSwitched = true;
233 }
234 m_canvas->canvasWidget()->setCursor(Qt::PointingHandCursor);
235 retval = true;
236 } else if (m_cursorSwitched) {
237 m_canvas->canvasWidget()->setCursor(m_oldCursor);
238 m_cursorSwitched = false;
239 }
240 break;
241 }
242 case QEvent::Leave: {
243 if (m_cursorSwitched) {
244 m_canvas->canvasWidget()->setCursor(m_oldCursor);
245 m_cursorSwitched = false;
246 }
247 break;
248 }
249 case QEvent::MouseButtonPress:
250 case QEvent::TabletPress: {
251 Qt::MouseButton button = getButtonFromEvent(event);
252 retval = button == Qt::LeftButton && m_cursorSwitched;
253
254 if (button == Qt::RightButton) {
256 }
257
258 break;
259 }
260 case QEvent::MouseButtonRelease:
261 case QEvent::TabletRelease: {
262 Qt::MouseButton button = getButtonFromEvent(event);
263 retval = button == Qt::LeftButton && m_cursorSwitched;
264
265 if (retval) {
266 QPoint pos = getPointFromEvent(event);
267
268 const KisCoordinatesConverter *converter = m_canvas->coordinatesConverter();
269 QRect widgetRect = converter->widgetToImage(m_canvas->canvasWidget()->rect()).toAlignedRect();
270 KisImageWSP image = view()->image();
271
272 QRect cropRect = image->bounds();
273
274 const int hLimit = cropRect.width();
275 const int vLimit = cropRect.height();
276
277 if (m_sideRects[Right].contains(pos)) {
278 cropRect.setRight(expandRight(cropRect.right(), widgetRect.right(), hLimit));
279 }
280 if (m_sideRects[Bottom].contains(pos)) {
281 cropRect.setBottom(expandRight(cropRect.bottom(), widgetRect.bottom(), vLimit));
282 }
283 if (m_sideRects[Left].contains(pos)) {
284 cropRect.setLeft(expandLeft(cropRect.left(), widgetRect.left(), hLimit));
285 }
286 if (m_sideRects[Top].contains(pos)) {
287 cropRect.setTop(expandLeft(cropRect.top(), widgetRect.top(), vLimit));
288 }
289
290 image->resizeImage(cropRect);
291
292 // since resizing the image can cause the cursor to end up on the canvas without a move event,
293 // it can get stuck in an overridden state until it is changed by another event,
294 // and we don't want that.
295 if (m_cursorSwitched) {
296 m_canvas->canvasWidget()->setCursor(m_oldCursor);
297 m_cursorSwitched = false;
298 }
299 }
300 break;
301 }
302 default:
303 break;
304 }
305
306 return !retval ? KisCanvasDecoration::eventFilter(obj, event) : true;
307}
const Params2D p
void sigCanvasStateChanged()
KoColorDisplayRendererInterface * displayRendererInterface() const override
displayRendererInterface The display renderer interface has a number of color conversion functions wh...
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:866
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
virtual QColor convertColorToDisplayColorSpace(const KoColor color) const =0
convertColorToDisplayColorSpace
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
#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()