Krita Source Code Documentation
Loading...
Searching...
No Matches
KoCanvasControllerWidget.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 *
3 * SPDX-FileCopyrightText: 2006, 2008-2009 Thomas Zander <zander@kde.org>
4 * SPDX-FileCopyrightText: 2006 Peter Simonsson <peter.simonsson@gmail.com>
5 * SPDX-FileCopyrightText: 2006, 2009 Thorsten Zachmann <zachmann@kde.org>
6 * SPDX-FileCopyrightText: 2007-2010 Boudewijn Rempt <boud@valdyas.org>
7 * SPDX-FileCopyrightText: 2007 C. Boemann <cbo@boemann.dk>
8 * SPDX-FileCopyrightText: 2006-2008 Jan Hambrecht <jaham@gmx.net>
9 *
10 * SPDX-License-Identifier: LGPL-2.0-or-later
11 */
12
15
17#include "KoShape.h"
18#include "KoViewConverter.h"
19#include <KoZoomHandler.h>
20#include "KoCanvasBase.h"
22#include "KoCanvasSupervisor.h"
23#include "KoToolManager_p.h"
24
25#include <FlakeDebug.h>
26#include <QMouseEvent>
27#include <QPainter>
28#include <QScrollBar>
29#include <QEvent>
30#include <QTimer>
31
32#include <QOpenGLWidget>
33#include <KisCanvasState.h>
35
36#include <math.h>
37#include <kis_debug.h>
38
39void KoCanvasControllerWidget::Private::activate()
40{
41 if (!observerProvider) {
42 return;
43 }
44 KoCanvasBase *canvas = q->canvas();
45 Q_FOREACH (KoCanvasObserverBase *docker, observerProvider->canvasObservers()) {
46 KoCanvasObserverBase *observer = dynamic_cast<KoCanvasObserverBase*>(docker);
47 if (observer) {
48 observer->setObservedCanvas(canvas);
49 }
50 }
51}
52
53void KoCanvasControllerWidget::Private::unsetCanvas()
54{
55 if (!observerProvider) {
56 return;
57 }
58 Q_FOREACH (KoCanvasObserverBase *docker, observerProvider->canvasObservers()) {
59 KoCanvasObserverBase *observer = dynamic_cast<KoCanvasObserverBase*>(docker);
60 if (observer) {
61 if (observer->observedCanvas() == q->canvas()) {
62 observer->unsetObservedCanvas();
63 }
64 }
65 }
66}
67
70 : QAbstractScrollArea(parent)
71 , KoCanvasController(actionCollection)
72 , d(new Private(this, observerProvider))
73{
74 // We need to set this as QDeclarativeView sets them a bit different from QAbstractScrollArea
75 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
76
77 // And then our own Viewport
78 d->viewportWidget = new Viewport(this);
79 setViewport(d->viewportWidget);
80 d->viewportWidget->setFocusPolicy(Qt::NoFocus);
81 setFocusPolicy(Qt::NoFocus);
82 setFrameStyle(0);
83
84 //setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
85 setAutoFillBackground(false);
86 /*
87 Fixes: apps starting at zero zoom.
88 Details: Since the document is set on the mainwindow before loading commences the inial show/layout can choose
89 to set the document to be very small, even to be zero pixels tall. Setting a sane minimum size on the
90 widget means we no longer get rounding errors in zooming and we no longer end up with zero-zoom.
91 Note: KoPage apps should probably startup with a sane document size; for Krita that's impossible
92 */
93 setMinimumSize(QSize(50, 50));
94 setMouseTracking(true);
95}
96
101
103{
104 d->activate();
105}
106
108{
109 Q_UNUSED(dx);
110 Q_UNUSED(dy);
111
112 const KisCanvasState oldCanvasState = canvasState();
113
114 const QPoint pt(horizontalScrollBar()->value(), verticalScrollBar()->value());
115 if (oldCanvasState.documentOffset == pt) return;
116
118
119 const KisCanvasState newCanvasState = canvasState();
120
121 emitSignals(oldCanvasState, newCanvasState);
122}
123
125{
126 const KisCanvasState oldCanvasState = canvasState();
127
128 updateCanvasWidgetSizeInternal(event->size());
129
130 const KisCanvasState newCanvasState = canvasState();
131
132 // jcall resize on the subordinate widget
133 d->viewportWidget->resetLayout();
134
135 emitSignals(oldCanvasState, newCanvasState);
136}
137
139{
140 if (d->canvas) {
141 d->unsetCanvas();
142 proxyObject->emitCanvasRemoved(this);
144 d->canvas->canvasWidget()->removeEventFilter(this);
145 }
146
147 d->canvas = canvas;
148
149 if (d->canvas) {
152
153 proxyObject->emitCanvasSet(this);
154 QTimer::singleShot(0, this, SLOT(activate()));
155 }
156}
157
159{
160 if (d->canvas.isNull()) return 0;
161 return d->canvas;
162}
163
165{
166 if (d->viewportWidget->canvas()) {
167 widget->setCursor(d->viewportWidget->canvas()->cursor());
168 d->viewportWidget->canvas()->removeEventFilter(this);
169 }
170
171 d->viewportWidget->setCanvas(widget);
172 setFocusProxy(d->canvas->canvasWidget());
173}
174
176{
177 if (oldState.documentOffsetF != newState.documentOffsetF) {
178 proxyObject->emitCanvasOffsetChanged();
179 }
180
181 if (oldState.documentOffsetF != newState.documentOffsetF) {
182 proxyObject->emitMoveDocumentOffset(oldState.documentOffsetF, newState.documentOffsetF);
183 }
184
185 if (oldState.canvasSize != newState.canvasSize) {
186 // TODO: should we remove this signal?
187 proxyObject->emitSizeChanged(newState.canvasSize.toSize());
188 }
189
190 if (oldState.documentOffset != newState.documentOffset ||
191 oldState.minimumOffset != newState.minimumOffset ||
192 oldState.maximumOffset != newState.maximumOffset) {
193
195 }
196
197 if (!qFuzzyCompare(oldState.effectiveZoom, newState.effectiveZoom)) {
198 proxyObject->emitEffectiveZoomChanged(newState.effectiveZoom);
199 }
200
201 if (oldState.zoomState() != newState.zoomState()) {
202 proxyObject->emitZoomStateChanged(newState.zoomState());
203 }
204
205 if (!qFuzzyCompare(oldState.rotation, newState.rotation)) {
206 proxyObject->emitDocumentRotationChanged(newState.rotation);
207 }
208
209 if (oldState.mirrorHorizontally != newState.mirrorHorizontally
210 || oldState.mirrorVertically != newState.mirrorVertically) {
211
212 proxyObject->emitDocumentMirrorStatusChanged(newState.mirrorHorizontally, newState.mirrorVertically);
213 }
214
215 if (oldState.imageRectInWidgetPixels != newState.imageRectInWidgetPixels) {
216 proxyObject->emitDocumentRectInWidgetPixelsChanged(newState.imageRectInWidgetPixels);
217 }
218
219 if (oldState != newState) {
220 proxyObject->emitCanvasStateChanged();
221 }
222}
223
224void KoCanvasControllerWidget::zoomTo(const QRect &viewRect)
225{
226 const KisCanvasState oldCanvasState = canvasState();
227
228 zoomToInternal(viewRect);
229
230 const KisCanvasState newCanvasState = canvasState();
231
232 emitSignals(oldCanvasState, newCanvasState);
233}
234
236{
237 QPoint sourcePoint = scrollBarValue();
238 setScrollBarValue(sourcePoint + distance);
239}
240
242{
243 pan(QPoint(0, verticalScrollBar()->singleStep()));
244}
245
247{
248 pan(QPoint(0, -verticalScrollBar()->singleStep()));
249}
250
252{
253 pan(QPoint(horizontalScrollBar()->singleStep(), 0));
254}
255
257{
258 pan(QPoint(-horizontalScrollBar()->singleStep(), 0));
259}
260
262{
263 QPainter gc(viewport());
264 d->viewportWidget->handlePaintEvent(gc, event);
265}
266
268{
269 d->viewportWidget->handleDragEnterEvent(event);
270}
271
273{
274 d->viewportWidget->handleDropEvent(event);
275}
276
278{
279 d->viewportWidget->handleDragMoveEvent(event);
280}
281
283{
284 d->viewportWidget->handleDragLeaveEvent(event);
285}
286
288{
289 KoZoomHandler *zoomHandler = dynamic_cast<KoZoomHandler*>(d->canvas->viewConverter());
291 setZoom(mode, zoom, zoomHandler->resolutionX(), zoomHandler->resolutionY(), std::nullopt);
292}
293
295{
296 KoZoomHandler *zoomHandler = dynamic_cast<KoZoomHandler*>(d->canvas->viewConverter());
298 setZoom(mode, zoom, zoomHandler->resolutionX(), zoomHandler->resolutionY(), stillPoint);
299}
300
301void KoCanvasControllerWidget::setZoom(KoZoomMode::Mode mode, qreal zoom, qreal resolutionX, qreal resolutionY)
302{
303 setZoom(mode, zoom, resolutionX, resolutionY, std::nullopt);
304}
305
306void KoCanvasControllerWidget::setZoom(KoZoomMode::Mode mode, qreal zoom, qreal resolutionX, qreal resolutionY, const std::optional<KoViewTransformStillPoint> &stillPoint)
307{
308 const KisCanvasState oldCanvasState = canvasState();
309 updateCanvasZoomInternal(mode, zoom, resolutionX, resolutionY, stillPoint);
310 const KisCanvasState newCanvasState = canvasState();
311
312 emitSignals(oldCanvasState, newCanvasState);
313}
314
316{
317 // we always return false meaning the canvas takes keyboard focus, but never gives it away.
318 return false;
319}
320
322 // Workaround: Don't let QAbstractScrollArea handle Gesture events. Because
323 // Qt's detection of touch point positions is a bit buggy, it is handled
324 // with custom algorithms in the KisInputManager. But we must also not let
325 // the corresponding event propagate to the parent QAbstractScrollArea.
326 if (event->type() == QEvent::Gesture) {
327 return false;
328 }
329 return QAbstractScrollArea::viewportEvent(event);
330}
331
333{
334 QScrollBar * hBar = horizontalScrollBar();
335 QScrollBar * vBar = verticalScrollBar();
336
337 return QPoint(hBar->value(), vBar->value());
338}
339
341{
342 QScrollBar * hBar = horizontalScrollBar();
343 QScrollBar * vBar = verticalScrollBar();
344
345 hBar->setValue(value.x());
346 vBar->setValue(value.y());
347}
348
353
354//have to include this because of Q_PRIVATE_SLOT
355#include "moc_KoCanvasControllerWidget.cpp"
float value(const T *src, size_t ch)
qreal distance(const QPointF &p1, const QPointF &p2)
KisAbstractCanvasWidget * canvasWidget
const KoViewConverter * viewConverter() const override
QRectF imageRectInWidgetPixels
KoZoomState zoomState() const
QPointF documentOffsetF
A container for a set of QAction objects.
void setCanvasController(KoCanvasController *controller)
called by KoCanvasController to set the controller that handles this canvas.
void resizeEvent(QResizeEvent *resizeEvent) override
reimplemented from QWidget
void scrollContentsBy(int dx, int dy) override
bool viewportEvent(QEvent *event) override
reimplemented from QAbstractScrollArea
virtual void updateCanvasOffsetInternal(const QPointF &newOffset)=0
virtual void activate()
Reimplemented from KoCanvasController.
KoCanvasControllerWidget(KisKActionCollection *actionCollection, KoCanvasSupervisor *observerProvider, QWidget *parent=0)
bool focusNextPrevChild(bool next) override
reimplemented from QWidget
void dragMoveEvent(QDragMoveEvent *event) override
reimplemented from QWidget
void zoomTo(const QRect &rect) override
zoom so that rect is exactly visible (as close as possible)
void paintEvent(QPaintEvent *event) override
reimplemented from QWidget
void pan(const QPoint &distance) override
virtual void zoomToInternal(const QRect &viewRect)=0
QPoint scrollBarValue() const override
void setCanvas(KoCanvasBase *canvas) override
void setZoom(KoZoomMode::Mode mode, qreal zoom) override
void dragEnterEvent(QDragEnterEvent *event) override
reimplemented from QWidget
void setScrollBarValue(const QPoint &value) override
KoCanvasControllerWidget::Private * priv()
virtual void changeCanvasWidget(QWidget *widget)
virtual void updateCanvasWidgetSizeInternal(const QSize &newSize)=0
virtual void updateCanvasZoomInternal(KoZoomMode::Mode mode, qreal zoom, qreal resolutionX, qreal resolutionY, const std::optional< KoViewTransformStillPoint > &docStillPoint)=0
QPointer< KoCanvasBase > canvas
void emitSignals(const KisCanvasState &oldState, const KisCanvasState &newState)
void dropEvent(QDropEvent *event) override
reimplemented from QWidget
void dragLeaveEvent(QDragLeaveEvent *event) override
reimplemented from QWidget
virtual KisCanvasState canvasState() const =0
QPointer< KoCanvasControllerProxyObject > proxyObject
virtual void resetScrollBars()=0
KoCanvasBase * observedCanvas() const
void setObservedCanvas(KoCanvasBase *canvas)
qreal resolutionX() const
qreal resolutionY() const
static bool qFuzzyCompare(half p1, half p2)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
KisCanvas2 * canvas