1 /* This file is part of the KDE project 2 * Copyright (C) 2006, 2008 Thomas Zander <zander@kde.org> 3 * Copyright (C) 2007-2010 Boudewijn Rempt <boud@valdyas.org> 4 * Copyright (C) 2007-2008 C. Boemann <cbo@boemann.dk> 5 * Copyright (C) 2006-2007 Jan Hambrecht <jaham@gmx.net> 6 * Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org> 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 */ 23 24 #ifndef KOCANVASCONTROLLER_H 25 #define KOCANVASCONTROLLER_H 26 27 #include "kritaflake_export.h" 28 #include <QObject> 29 30 #include <QSize> 31 #include <QPoint> 32 #include <QPointF> 33 #include <QPointer> 34 35 class KActionCollection; 36 class QRect; 37 class QRectF; 38 39 40 class KoShape; 41 class KoCanvasBase; 42 class KoCanvasControllerProxyObject; 43 44 /** 45 * KoCanvasController is the base class for wrappers around your canvas 46 * that provides scrolling and zooming for your canvas. 47 * 48 * Flake does not provide a canvas, the application will have to 49 * implement a canvas themselves. You canvas can be QWidget-based 50 * or something we haven't invented yet -- as long the class that holds the canvas 51 * implements KoCanvasController, tools, scrolling and zooming will work. 52 * 53 * A KoCanvasController implementation acts as a decorator around the canvas widget 54 * and provides a way to scroll the canvas, allows the canvas to be centered 55 * in the viewArea and manages tool activation. 56 * 57 * <p>The using application can instantiate this class and add its 58 * canvas using the setCanvas() call. Which is designed so it can be 59 * called multiple times if you need to exchange one canvas 60 * widget for another, for instance, switching between a plain QWidget or a QOpenGLWidget. 61 * 62 * <p>There is _one_ KoCanvasController per canvas in your 63 * application. 64 * 65 * <p>The canvas widget is at most as big as the viewport of the scroll 66 * area, and when the view on the document is near its edges, smaller. 67 * In your canvas widget code, you can find the right place in your 68 * document in view coordinates (pixels) by adding the documentOffset 69 */ 70 class KRITAFLAKE_EXPORT KoCanvasController 71 { 72 public: 73 74 // proxy QObject: use this to connect to slots and signals. 75 QPointer<KoCanvasControllerProxyObject> proxyObject; 76 77 /** 78 * Constructor. 79 * @param actionCollection the action collection for this canvas 80 */ 81 explicit KoCanvasController(KActionCollection* actionCollection); 82 virtual ~KoCanvasController(); 83 84 public: 85 /** 86 * Returns the current margin that is used to pad the canvas with. 87 * This value is read from the KConfig property "canvasmargin" 88 */ 89 virtual int margin() const; 90 91 /** 92 * Set the new margin to pad the canvas with. 93 */ 94 virtual void setMargin(int margin); 95 96 /** 97 * compatibility with QAbstractScrollArea 98 */ 99 virtual void scrollContentsBy(int dx, int dy) = 0; 100 101 /** 102 * @return the size of the viewport 103 */ 104 virtual QSizeF viewportSize() const = 0; 105 106 /** 107 * Set the new canvas to be shown as a child 108 * Calling this will emit canvasRemoved() if there was a canvas before, and will emit 109 * canvasSet() with the new canvas. 110 * @param canvas the new canvas. The KoCanvasBase::canvas() will be called to retrieve the 111 * actual widget which will then be added as child of this one. 112 */ 113 virtual void setCanvas(KoCanvasBase *canvas) = 0; 114 115 /** 116 * Return the currently set canvas. The default implementation will return Null 117 * @return the currently set canvas 118 */ 119 virtual KoCanvasBase *canvas() const; 120 121 /** 122 * return the amount of pixels vertically visible of the child canvas. 123 * @return the amount of pixels vertically visible of the child canvas. 124 */ 125 virtual int visibleHeight() const = 0; 126 127 /** 128 * return the amount of pixels horizontally visible of the child canvas. 129 * @return the amount of pixels horizontally visible of the child canvas. 130 */ 131 virtual int visibleWidth() const = 0; 132 133 /** 134 * return the amount of pixels that are not visible on the left side of the canvas. 135 * The leftmost pixel that is shown is returned. 136 */ 137 virtual int canvasOffsetX() const = 0; 138 139 /** 140 * return the amount of pixels that are not visible on the top side of the canvas. 141 * The topmost pixel that is shown is returned. 142 */ 143 virtual int canvasOffsetY() const = 0; 144 145 /** 146 * @brief Scrolls the content of the canvas so that the given rect is visible. 147 * 148 * The rect is to be specified in view coordinates (pixels). The scrollbar positions 149 * are changed so that the centerpoint of the rectangle is centered if possible. 150 * 151 * @param rect the rectangle to make visible 152 * @param smooth if true the viewport translation will make be just enough to ensure visibility, no more. 153 * @see KoViewConverter::documentToView() 154 */ 155 virtual void ensureVisible(const QRectF &rect, bool smooth = false) = 0; 156 157 /** 158 * @brief Scrolls the content of the canvas so that the given shape is visible. 159 * 160 * This is just a wrapper function of the above function. 161 * 162 * @param shape the shape to make visible 163 */ 164 virtual void ensureVisible(KoShape *shape) = 0; 165 166 /** 167 * @brief zooms in around the center. 168 * 169 * The center must be specified in **widget** coordinates. The scrollbar positions 170 * are changed so that the center becomes center if possible. 171 * 172 * @param center the position to zoom in on 173 */ 174 virtual void zoomIn(const QPoint ¢er) = 0; 175 176 /** 177 * @brief zooms out around the center. 178 * 179 * The center must be specified in **widget** coordinates. The scrollbar positions 180 * are changed so that the center becomes center if possible. 181 * 182 * @param center the position to zoom out around 183 */ 184 virtual void zoomOut(const QPoint ¢er) = 0; 185 186 /** 187 * @brief zooms around the center. 188 * 189 * The center must be specified in **widget** coordinates. The scrollbar positions 190 * are changed so that the center becomes center if possible. 191 * 192 * @param center the position to zoom around 193 * @param zoom the zoom to apply 194 */ 195 virtual void zoomBy(const QPoint ¢er, qreal zoom) = 0; 196 197 /** 198 * @brief zoom so that rect is exactly visible (as close as possible) 199 * 200 * The rect must be specified in **widget** coordinates. The scrollbar positions 201 * are changed so that the center of the rect becomes center if possible. 202 * 203 * @param rect the rect in **widget** coordinates that should fit the view afterwards 204 */ 205 virtual void zoomTo(const QRect &rect) = 0; 206 207 /** 208 * @brief repositions the scrollbars so previous center is once again center 209 * 210 * The previous center is cached from when the user uses the scrollbars or zoomTo 211 * are called. zoomTo is mostly used when a zoom tool of sorts have marked an area 212 * to zoom in on 213 * 214 * The success of this method is limited by the size of thing. But we try our best. 215 */ 216 virtual void recenterPreferred() = 0; 217 218 /** 219 * Sets the preferred center point in view coordinates (pixels). 220 * @param viewPoint the new preferred center 221 */ 222 virtual void setPreferredCenter(const QPointF &viewPoint) = 0; 223 224 /// Returns the currently set preferred center point in view coordinates (pixels) 225 virtual QPointF preferredCenter() const = 0; 226 227 /** 228 * Move the canvas over the x and y distance of the parameter distance 229 * @param distance the distance in view coordinates (pixels). A positive distance means moving the canvas up/left. 230 */ 231 virtual void pan(const QPoint &distance) = 0; 232 233 /** 234 * Move the canvas up. This behaves the same as \sa pan() with a positive y coordinate. 235 */ 236 virtual void panUp() = 0; 237 238 /** 239 * Move the canvas down. This behaves the same as \sa pan() with a negative y coordinate. 240 */ 241 virtual void panDown() = 0; 242 243 /** 244 * Move the canvas to the left. This behaves the same as \sa pan() with a positive x coordinate. 245 */ 246 virtual void panLeft() = 0; 247 248 /** 249 * Move the canvas to the right. This behaves the same as \sa pan() with a negative x coordinate. 250 */ 251 virtual void panRight() = 0; 252 253 /** 254 * Get the position of the scrollbar 255 */ 256 virtual QPoint scrollBarValue() const = 0; 257 258 /** 259 * Set the position of the scrollbar 260 * @param value the new values of the scroll bars 261 */ 262 virtual void setScrollBarValue(const QPoint &value) = 0; 263 264 /** 265 * Update the range of scroll bars 266 */ 267 virtual void resetScrollBars() = 0; 268 269 /** 270 * Called when the size of your document in view coordinates (pixels) changes, for instance when zooming. 271 * 272 * @param newSize the new size, in view coordinates (pixels), of the document. 273 * @param recalculateCenter if true the offset in the document we center on after calling 274 * recenterPreferred() will be recalculated for the new document size so the visual offset stays the same. 275 */ 276 virtual void updateDocumentSize(const QSizeF &sz, bool recalculateCenter) = 0; 277 278 /** 279 * Set mouse wheel to zoom behaviour 280 * @param zoom if true wheel will zoom instead of scroll, control modifier will scroll 281 */ 282 virtual void setZoomWithWheel(bool zoom) = 0; 283 284 /** 285 * Set scroll area to be bigger than actual document. 286 * It allows the user to move the corner of the document 287 * to e.g. the center of the screen 288 * 289 * @param factor the coefficient, defining how much we can scroll out, 290 * measured in parts of the widget size. Null value means vast 291 * scrolling is disabled. 292 */ 293 virtual void setVastScrolling(qreal factor) = 0; 294 295 /** 296 * Returns the action collection for the window 297 * @returns action collection for this window, can be 0 298 */ 299 KActionCollection* actionCollection() const; 300 301 QPoint documentOffset() const; 302 303 /** 304 * @return the current position of the cursor fetched from QCursor::pos() and 305 * converted into document coordinates 306 */ 307 virtual QPointF currentCursorPosition() const = 0; 308 309 protected: 310 void setDocumentSize(const QSizeF &sz); 311 QSizeF documentSize() const; 312 313 void setPreferredCenterFractionX(qreal); 314 qreal preferredCenterFractionX() const; 315 316 void setPreferredCenterFractionY(qreal); 317 qreal preferredCenterFractionY() const; 318 319 void setDocumentOffset( QPoint &offset); 320 321 322 private: 323 class Private; 324 Private * const d; 325 }; 326 327 328 /** 329 * Workaround class for the problem that Qt does not allow two QObject base classes. 330 * KoCanvasController can be implemented by for instance QWidgets, so it cannot be 331 * a QObject directly. The interface of this class should be considered public interface 332 * for KoCanvasController. 333 */ 334 class KRITAFLAKE_EXPORT KoCanvasControllerProxyObject : public QObject 335 { 336 Q_OBJECT 337 Q_DISABLE_COPY(KoCanvasControllerProxyObject) 338 public: 339 explicit KoCanvasControllerProxyObject(KoCanvasController *canvasController, QObject *parent = 0); 340 341 public: 342 343 // Convenience methods to invoke the signals from subclasses 344 emitCanvasRemoved(KoCanvasController * canvasController)345 void emitCanvasRemoved(KoCanvasController *canvasController) { emit canvasRemoved(canvasController); } emitCanvasSet(KoCanvasController * canvasController)346 void emitCanvasSet(KoCanvasController *canvasController) { emit canvasSet(canvasController); } emitCanvasOffsetXChanged(int offset)347 void emitCanvasOffsetXChanged(int offset) { emit canvasOffsetXChanged(offset); } emitCanvasOffsetYChanged(int offset)348 void emitCanvasOffsetYChanged(int offset) { emit canvasOffsetYChanged(offset); } emitCanvasMousePositionChanged(const QPoint & position)349 void emitCanvasMousePositionChanged(const QPoint &position) { emit canvasMousePositionChanged(position); } emitDocumentMousePositionChanged(const QPointF & position)350 void emitDocumentMousePositionChanged(const QPointF &position) { emit documentMousePositionChanged(position); } emitSizeChanged(const QSize & size)351 void emitSizeChanged(const QSize &size) { emit sizeChanged(size); } emitMoveDocumentOffset(const QPoint & point)352 void emitMoveDocumentOffset(const QPoint &point) { emit moveDocumentOffset(point); } emitZoomRelative(const qreal factor,const QPointF & stillPoint)353 void emitZoomRelative(const qreal factor, const QPointF &stillPoint) { emit zoomRelative(factor, stillPoint); } 354 355 // Convenience method to retrieve the canvas controller for who needs to use QPointer canvasController()356 KoCanvasController *canvasController() const { return m_canvasController; } 357 358 Q_SIGNALS: 359 /** 360 * Emitted when a previously added canvas is about to be removed. 361 * @param canvasController this object 362 */ 363 void canvasRemoved(KoCanvasController *canvasController); 364 365 /** 366 * Emitted when a canvas is set on this widget 367 * @param canvasController this object 368 */ 369 void canvasSet(KoCanvasController *canvasController); 370 371 /** 372 * Emitted when canvasOffsetX() changes 373 * @param offset the new canvas offset 374 */ 375 void canvasOffsetXChanged(int offset); 376 377 /** 378 * Emitted when canvasOffsetY() changes 379 * @param offset the new canvas offset 380 */ 381 void canvasOffsetYChanged(int offset); 382 383 /** 384 * Emitted when the cursor is moved over the canvas widget. 385 * @param position the position in view coordinates (pixels). 386 */ 387 void canvasMousePositionChanged(const QPoint &position); 388 389 /** 390 * Emitted when the cursor is moved over the canvas widget. 391 * @param position the position in document coordinates. 392 * 393 * Use \ref canvasMousePositionChanged to get the position 394 * in view coordinates. 395 */ 396 void documentMousePositionChanged(const QPointF &position); 397 398 /** 399 * Emitted when the entire controller size changes 400 * @param size the size in widget pixels. 401 */ 402 void sizeChanged(const QSize &size); 403 404 /** 405 * Emitted whenever the document is scrolled. 406 * 407 * @param point the new top-left point from which the document should 408 * be drawn. 409 */ 410 void moveDocumentOffset(const QPoint &point); 411 412 /** 413 * Emitted when zoomRelativeToPoint have calculated a factor by which 414 * the zoom should change and the point which should stand still 415 * on screen. 416 * Someone needs to connect to this and take action 417 * 418 * @param factor by how much the zoom needs to change. 419 * @param stillPoint the point which will not change its position 420 * in widget during the zooming. It is measured in 421 * view coordinate system *before* zoom. 422 */ 423 void zoomRelative(const qreal factor, const QPointF &stillPoint); 424 425 public Q_SLOTS: 426 /** 427 * Call this slot whenever the size of your document in view coordinates (pixels) 428 * changes, for instance when zooming. 429 * @param newSize the new size, in view coordinates (pixels), of the document. 430 * @param recalculateCenter if true the offset in the document we center on after calling 431 * recenterPreferred() will be recalculated for the new document size so the visual offset stays the same. 432 */ 433 void updateDocumentSize(const QSize &newSize, bool recalculateCenter = true); 434 435 private: 436 KoCanvasController *m_canvasController; 437 }; 438 439 class KRITAFLAKE_EXPORT KoDummyCanvasController : public KoCanvasController { 440 441 public: 442 KoDummyCanvasController(KActionCollection * actionCollection)443 explicit KoDummyCanvasController(KActionCollection* actionCollection) 444 : KoCanvasController(actionCollection) 445 {} 446 ~KoDummyCanvasController()447 ~KoDummyCanvasController() override 448 {} 449 450 scrollContentsBy(int,int)451 void scrollContentsBy(int /*dx*/, int /*dy*/) override {} viewportSize()452 QSizeF viewportSize() const override { return QSizeF(); } setCanvas(KoCanvasBase * canvas)453 void setCanvas(KoCanvasBase *canvas) override {Q_UNUSED(canvas)} canvas()454 KoCanvasBase *canvas() const override {return 0;} visibleHeight()455 int visibleHeight() const override {return 0;} visibleWidth()456 int visibleWidth() const override {return 0;} canvasOffsetX()457 int canvasOffsetX() const override {return 0;} canvasOffsetY()458 int canvasOffsetY() const override {return 0;} 459 void ensureVisible(const QRectF &/*rect*/, bool /*smooth */ = false) override {} ensureVisible(KoShape * shape)460 void ensureVisible(KoShape *shape) override {Q_UNUSED(shape)} zoomIn(const QPoint &)461 void zoomIn(const QPoint &/*center*/) override {} zoomOut(const QPoint &)462 void zoomOut(const QPoint &/*center*/) override {} zoomBy(const QPoint &,qreal)463 void zoomBy(const QPoint &/*center*/, qreal /*zoom*/) override {} zoomTo(const QRect &)464 void zoomTo(const QRect &/*rect*/) override {} recenterPreferred()465 void recenterPreferred() override {} setPreferredCenter(const QPointF &)466 void setPreferredCenter(const QPointF &/*viewPoint*/) override {} preferredCenter()467 QPointF preferredCenter() const override {return QPointF();} pan(const QPoint &)468 void pan(const QPoint &/*distance*/) override {} panUp()469 void panUp() override {} panDown()470 void panDown() override {} panLeft()471 void panLeft() override {} panRight()472 void panRight() override {} scrollBarValue()473 QPoint scrollBarValue() const override {return QPoint();} setScrollBarValue(const QPoint &)474 void setScrollBarValue(const QPoint &/*value*/) override {} resetScrollBars()475 void resetScrollBars() override {} updateDocumentSize(const QSizeF &,bool)476 void updateDocumentSize(const QSizeF &/*sz*/, bool /*recalculateCenter*/) override {} setZoomWithWheel(bool)477 void setZoomWithWheel(bool /*zoom*/) override {} setVastScrolling(qreal)478 void setVastScrolling(qreal /*factor*/) override {} currentCursorPosition()479 QPointF currentCursorPosition() const override { return QPointF(); } 480 }; 481 482 #endif 483