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
137 updateCanvasWidgetSizeInternal(event->size(), this->devicePixelRatioF());
138
139 const KisCanvasState newCanvasState = canvasState();
140
141 // jcall resize on the subordinate widget
142 d->viewportWidget->resetLayout();
143
144 emitSignals(oldCanvasState, newCanvasState);
145}
146
148{
149 if (d->canvas) {
150 d->unsetCanvas();
151 proxyObject->emitCanvasRemoved(this);
153 d->canvas->canvasWidget()->removeEventFilter(this);
154 }
155
156 d->canvas = canvas;
157
158 if (d->canvas) {
161
162 proxyObject->emitCanvasSet(this);
163 QTimer::singleShot(0, this, SLOT(activate()));
164 }
165}
166
168{
169 if (d->canvas.isNull()) return 0;
170 return d->canvas;
171}
172
174{
175 if (d->viewportWidget->canvas()) {
176 widget->setCursor(d->viewportWidget->canvas()->cursor());
177 d->viewportWidget->canvas()->removeEventFilter(this);
178 }
179
180 d->viewportWidget->setCanvas(widget);
181 setFocusProxy(d->canvas->canvasWidget());
182}
183
185{
186 if (oldState.documentOffsetF != newState.documentOffsetF) {
187 proxyObject->emitCanvasOffsetChanged();
188 }
189
190 if (oldState.documentOffsetF != newState.documentOffsetF) {
191 proxyObject->emitMoveDocumentOffset(oldState.documentOffsetF, newState.documentOffsetF);
192 }
193
194 if (oldState.canvasSize != newState.canvasSize) {
195 // TODO: should we remove this signal?
196 proxyObject->emitSizeChanged(newState.canvasSize.toSize());
197 }
198
199 if (oldState.documentOffset != newState.documentOffset ||
200 oldState.minimumOffset != newState.minimumOffset ||
201 oldState.maximumOffset != newState.maximumOffset) {
202
204 }
205
206 if (!qFuzzyCompare(oldState.effectiveZoom, newState.effectiveZoom)) {
207 proxyObject->emitEffectiveZoomChanged(newState.effectiveZoom);
208 }
209
210 if (oldState.zoomState() != newState.zoomState()) {
211 proxyObject->emitZoomStateChanged(newState.zoomState());
212 }
213
214 if (!qFuzzyCompare(oldState.rotation, newState.rotation)) {
215 proxyObject->emitDocumentRotationChanged(newState.rotation);
216 }
217
218 if (oldState.mirrorHorizontally != newState.mirrorHorizontally
219 || oldState.mirrorVertically != newState.mirrorVertically) {
220
221 proxyObject->emitDocumentMirrorStatusChanged(newState.mirrorHorizontally, newState.mirrorVertically);
222 }
223
224 if (oldState.imageRectInWidgetPixels != newState.imageRectInWidgetPixels) {
225 proxyObject->emitDocumentRectInWidgetPixelsChanged(newState.imageRectInWidgetPixels);
226 }
227
228 if (oldState != newState) {
229 proxyObject->emitCanvasStateChanged();
230 }
231}
232
233void KoCanvasControllerWidget::zoomTo(const QRect &viewRect)
234{
235 const KisCanvasState oldCanvasState = canvasState();
236
237 zoomToInternal(viewRect);
238
239 const KisCanvasState newCanvasState = canvasState();
240
241 emitSignals(oldCanvasState, newCanvasState);
242}
243
245{
246 QPoint sourcePoint = scrollBarValue();
247 setScrollBarValue(sourcePoint + distance);
248}
249
251{
252 pan(QPoint(0, verticalScrollBar()->singleStep()));
253}
254
256{
257 pan(QPoint(0, -verticalScrollBar()->singleStep()));
258}
259
261{
262 pan(QPoint(horizontalScrollBar()->singleStep(), 0));
263}
264
266{
267 pan(QPoint(-horizontalScrollBar()->singleStep(), 0));
268}
269
271{
272 QPainter gc(viewport());
273 d->viewportWidget->handlePaintEvent(gc, event);
274}
275
277{
278 d->viewportWidget->handleDragEnterEvent(event);
279}
280
282{
283 d->viewportWidget->handleDropEvent(event);
284}
285
287{
288 d->viewportWidget->handleDragMoveEvent(event);
289}
290
292{
293 d->viewportWidget->handleDragLeaveEvent(event);
294}
295
297{
298 KoZoomHandler *zoomHandler = dynamic_cast<KoZoomHandler*>(d->canvas->viewConverter());
300 setZoom(mode, zoom, zoomHandler->resolutionX(), zoomHandler->resolutionY(), std::nullopt);
301}
302
304{
305 KoZoomHandler *zoomHandler = dynamic_cast<KoZoomHandler*>(d->canvas->viewConverter());
307 setZoom(mode, zoom, zoomHandler->resolutionX(), zoomHandler->resolutionY(), stillPoint);
308}
309
310void KoCanvasControllerWidget::setZoom(KoZoomMode::Mode mode, qreal zoom, qreal resolutionX, qreal resolutionY)
311{
312 setZoom(mode, zoom, resolutionX, resolutionY, std::nullopt);
313}
314
315void KoCanvasControllerWidget::setZoom(KoZoomMode::Mode mode, qreal zoom, qreal resolutionX, qreal resolutionY, const std::optional<KoViewTransformStillPoint> &stillPoint)
316{
317 const KisCanvasState oldCanvasState = canvasState();
318 updateCanvasZoomInternal(mode, zoom, resolutionX, resolutionY, stillPoint);
319 const KisCanvasState newCanvasState = canvasState();
320
321 emitSignals(oldCanvasState, newCanvasState);
322}
323
325{
326 // we always return false meaning the canvas takes keyboard focus, but never gives it away.
327 return false;
328}
329
331 // Workaround: Don't let QAbstractScrollArea handle Gesture events. Because
332 // Qt's detection of touch point positions is a bit buggy, it is handled
333 // with custom algorithms in the KisInputManager. But we must also not let
334 // the corresponding event propagate to the parent QAbstractScrollArea.
335 if (event->type() == QEvent::Gesture) {
336 return false;
337 }
338 return QAbstractScrollArea::viewportEvent(event);
339}
340
342{
343 QScrollBar * hBar = horizontalScrollBar();
344 QScrollBar * vBar = verticalScrollBar();
345
346 return QPoint(hBar->value(), vBar->value());
347}
348
350{
351 QScrollBar * hBar = horizontalScrollBar();
352 QScrollBar * vBar = verticalScrollBar();
353
354 hBar->setValue(value.x());
355 vBar->setValue(value.y());
356}
357
362
363//have to include this because of Q_PRIVATE_SLOT
364#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
virtual void updateCanvasWidgetSizeInternal(const QSize &newSize, qreal devicePixelRatio)=0
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 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