File indexing completed on 2024-04-28 04:20:28
0001 0002 /* 0003 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org> 0004 All rights reserved. 0005 0006 Redistribution and use in source and binary forms, with or without 0007 modification, are permitted provided that the following conditions 0008 are met: 0009 0010 1. Redistributions of source code must retain the above copyright 0011 notice, this list of conditions and the following disclaimer. 0012 2. Redistributions in binary form must reproduce the above copyright 0013 notice, this list of conditions and the following disclaimer in the 0014 documentation and/or other materials provided with the distribution. 0015 0016 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0017 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0018 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0019 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0020 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0021 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0022 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0023 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0025 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0026 */ 0027 0028 0029 #ifndef KP_VIEW_H 0030 #define KP_VIEW_H 0031 0032 0033 #include <QWidget> 0034 0035 #include "kpDefs.h" 0036 0037 0038 class QDragEnterEvent; 0039 class QDragLeaveEvent; 0040 class QEvent; 0041 class QFocusEvent; 0042 class QKeyEvent; 0043 class QMouseEvent; 0044 class QPaintEvent; 0045 class QResizeEvent; 0046 0047 class kpAbstractSelection; 0048 class kpDocument; 0049 class kpTextSelection; 0050 class kpTool; 0051 class kpToolToolBar; 0052 class kpViewManager; 0053 class kpViewScrollableContainer; 0054 0055 0056 /** 0057 * @short Abstract base class for all views. 0058 * 0059 * This is the abstract base class for all views. A view is a widget that 0060 * renders a possibly zoomed onscreen representation of a document. 0061 * 0062 * 1 view corresponds to 1 document. 0063 * 1 document corresponds to 0 or more views. 0064 * 0065 * @see kpViewManager 0066 * 0067 * @author Clarence Dang <dang@kde.org> 0068 */ 0069 class kpView : public QWidget 0070 { 0071 Q_OBJECT 0072 0073 public: 0074 /** 0075 * Constructs a view. 0076 * 0077 * @param document The document this view is representing. 0078 * @param toolToolBar The tool tool bar. 0079 * @param viewManager The view manager. 0080 * @param buddyView The view this view watches over (e.g. a thumbnail 0081 * view would watch over the main view). May be 0. 0082 * See for example, highlightBuddyViewRectangle(). 0083 * @param scrollableContainer This view's scrollable container. 0084 * May be 0. 0085 * 0086 * You must call adjustEnvironment() at the end of your constructor. 0087 */ 0088 kpView (kpDocument *document, 0089 kpToolToolBar *toolToolBar, 0090 kpViewManager *viewManager, 0091 kpView *buddyView, 0092 kpViewScrollableContainer *scrollableContainer, 0093 QWidget *parent); 0094 0095 /** 0096 * Destructs this view. Informs the viewManager() that the mouse 0097 * cursor is no longer above this view. 0098 */ 0099 ~kpView () override; 0100 0101 0102 // 0103 // Constants (enforced by methods) 0104 // 0105 static const int MinZoomLevel, MaxZoomLevel; 0106 0107 0108 /** 0109 * @returns the document. 0110 */ 0111 kpDocument *document () const; 0112 0113 protected: 0114 /** 0115 * @returns the document's selection. 0116 */ 0117 kpAbstractSelection *selection () const; 0118 0119 kpTextSelection *textSelection () const; 0120 0121 public: 0122 /** 0123 * @returns the tool tool bar. 0124 */ 0125 kpToolToolBar *toolToolBar () const; 0126 0127 protected: 0128 /** 0129 * @returns the currently selected tool. 0130 */ 0131 kpTool *tool () const; 0132 0133 public: 0134 /** 0135 * @returns the view manager. 0136 */ 0137 kpViewManager *viewManager () const; 0138 0139 /** 0140 * @returns the buddy view. 0141 */ 0142 kpView *buddyView () const; 0143 0144 /** 0145 * @returns the buddyView()'s scrollable container. 0146 */ 0147 kpViewScrollableContainer *buddyViewScrollableContainer () const; 0148 0149 /** 0150 * @returns this view's scrollable container. 0151 */ 0152 kpViewScrollableContainer *scrollableContainer () const; 0153 0154 0155 /** 0156 * @returns the horizontal zoom level (100 is unzoomed). 0157 */ 0158 int zoomLevelX (void) const; 0159 0160 /** 0161 * @returns the vertical zoom level (100 is unzoomed). 0162 */ 0163 int zoomLevelY (void) const; 0164 0165 /** 0166 * Sets the horizontal and vertical zoom levels. 0167 * 0168 * @param hzoom Horizontal zoom level. 0169 * @param vzoom Vertical zoom level. 0170 * 0171 * This method automatically bounds <hzoom> and <vzoom> to be between 0172 * MinZoomLevel and MaxZoomLevel inclusive. 0173 * 0174 * If reimplementing, you must call this base implementation. 0175 */ 0176 virtual void setZoomLevel (int hzoom, int vzoom); 0177 0178 0179 /** 0180 * @returns in views coordinates, where the top-left document() pixel 0181 * will be rendered (default: (0,0)). 0182 */ 0183 QPoint origin () const; 0184 0185 /** 0186 * Sets the origin. 0187 * 0188 * @param origin New origin. 0189 * 0190 * If reimplementing, you must call this base implementation. 0191 */ 0192 virtual void setOrigin (const QPoint &origin); 0193 0194 0195 /** 0196 * @returns whether at this zoom level, the grid can be enabled. 0197 * This is based on whether the grid can be sensibly rendered. 0198 */ 0199 bool canShowGrid () const; 0200 0201 /** 0202 * @returns whether the grid is currently shown. 0203 */ 0204 bool isGridShown () const; 0205 0206 /** 0207 * Turns on/off the grid. 0208 * 0209 * @param yes Whether to enable the grid. 0210 */ 0211 void showGrid (bool yes = true); 0212 0213 0214 /** 0215 * @returns whether to draw a rectangle highlighting the area of 0216 * buddyView() visible through buddyViewScrollableContainer(). 0217 */ 0218 bool isBuddyViewScrollableContainerRectangleShown () const; 0219 0220 /** 0221 * Turns on/off the rectangle highlighting the area of buddyView() 0222 * visible through buddyViewScrollableContainer() and redraws. 0223 * 0224 * @param yes Whether to turn on the rectangle. 0225 */ 0226 void showBuddyViewScrollableContainerRectangle (bool yes = true); 0227 0228 protected: 0229 /** 0230 * @returns the current rectangle highlighting the area of buddyView() 0231 * visible through buddyViewScrollableContainer(), that is being 0232 * rendered by this view. 0233 */ 0234 QRect buddyViewScrollableContainerRectangle () const; 0235 0236 protected Q_SLOTS: 0237 /** 0238 * Updates the buddyViewScrollableContainerRectangle() and redraws 0239 * appropriately. 0240 * 0241 * This is already connected to zoomLevelChanged() and originChanged(); 0242 * buddyView() and buddyViewScrollableContainer() signals. There is probably no 0243 * need to call this function directly. 0244 */ 0245 void updateBuddyViewScrollableContainerRectangle (); 0246 0247 0248 public: 0249 0250 /** 0251 * @param viewX Horizontal position in view coordinates. 0252 * 0253 * @returns viewX transformed to document coordinates, based on the 0254 * origin() and zoomLevelX(). 0255 */ 0256 double transformViewToDocX (double viewX) const; 0257 0258 /** 0259 * @param viewY Vertical position in view coordinates. 0260 * 0261 * @returns viewY transformed to document coordinates, based on the 0262 * origin() and zoomLevelY(). 0263 */ 0264 double transformViewToDocY (double viewY) const; 0265 0266 /** 0267 * @param viewPoint Position in view coordinates. 0268 * 0269 * @returns viewPoint transformed to document coordinates, based on the 0270 * origin(), zoomLevelX() and zoomLevelY(). 0271 */ 0272 QPoint transformViewToDoc (const QPoint &viewPoint) const; 0273 0274 /** 0275 * @param viewRect Rectangle in view coordinates. 0276 * 0277 * @returns viewRect transformed to document coordinates based on the 0278 * origin(), zoomLevelX() and zoomLevelY(). 0279 * 0280 * For bounding rectangles, you should use this function instead of 0281 * transformViewToDocX(), transformViewToDocY() or 0282 * transformViewToDoc(const QPoint &) which act on coordinates only. 0283 */ 0284 QRect transformViewToDoc (const QRect &viewRect) const; 0285 0286 0287 /** 0288 * @param docX Horizontal position in document coordinates. 0289 * 0290 * @returns docX transformed to view coordinates, based on the origin() 0291 * and zoomLevelX(). 0292 */ 0293 double transformDocToViewX (double docX) const; 0294 0295 /** 0296 * @param docY Vertical position in document coordinates. 0297 * 0298 * @returns docY transformed to view coordinates, based on the origin() 0299 * and zoomLevelY(). 0300 */ 0301 double transformDocToViewY (double docY) const; 0302 0303 /** 0304 * @param docPoint Position in document coordinates. 0305 * 0306 * @returns docPoint transformed to view coordinates, based on the 0307 * origin(), zoomLevelX(), zoomLevelY(). 0308 */ 0309 QPoint transformDocToView (const QPoint &docPoint) const; 0310 0311 /** 0312 * @param docRect Rectangle in document coordinates. 0313 * 0314 * @return docRect transformed to view coordinates, based on the 0315 * origin(), zoomLevelX() and zoomLevelY(). 0316 * 0317 * For bounding rectangles, you should use this function instead of 0318 * transformDocToViewX(), transformDocToViewY() or 0319 * transformDocToView(const QPoint &) which act on coordinates only. 0320 */ 0321 QRect transformDocToView (const QRect &docRect) const; 0322 0323 0324 /** 0325 * @param viewPoint Position in view coordinates. 0326 * @param otherView View whose coordinate system the return value will 0327 * be in. 0328 * 0329 * @returns viewPoint transformed to the coordinate system of 0330 * @param otherView based on this and otherView's origin(), 0331 * zoomLevelX() and zoomLevelY(). This has less rounding 0332 * error than otherView->transformDocToView (transformViewToDoc (viewPoint)). 0333 */ 0334 QPoint transformViewToOtherView (const QPoint &viewPoint, 0335 const kpView *otherView); 0336 0337 0338 /** 0339 * @returns the approximate view width required to display the entire 0340 * document(), based on the zoom level only. 0341 */ 0342 int zoomedDocWidth () const; 0343 0344 /** 0345 * @returns the approximate view height required to display the entire 0346 * document(), based on the zoom level only. 0347 */ 0348 int zoomedDocHeight () const; 0349 0350 0351 protected: 0352 /** 0353 * Updates the viewManager() on whether or not the mouse is directly 0354 * above this view. Among other things, this ensures the brush cursor 0355 * is updated. 0356 * 0357 * This should be called in event handlers. 0358 * 0359 * @param yes Whether the mouse is directly above this view. 0360 */ 0361 void setHasMouse (bool yes = true); 0362 0363 0364 public: 0365 /** 0366 * Adds a region (in view coordinates) to the dirty area that is 0367 * repainted when the parent @ref kpViewManager is set not to queue 0368 * updates. 0369 * 0370 * @param region Region (in view coordinates) that needs repainting. 0371 */ 0372 void addToQueuedArea (const QRegion ®ion); 0373 0374 /** 0375 * Convenience function. Same as above. 0376 * 0377 * Adds a rectangle (in view coordinates) to the dirty area that is 0378 * repainted when the parent @ref kpViewManager is set not to queue 0379 * updates. 0380 * 0381 * @param rect Rectangle (in view coordinates) that needs repainting. 0382 */ 0383 void addToQueuedArea (const QRect &rect); 0384 0385 /** 0386 * Removes the dirty region that has been queued for updating. 0387 * Does not update the view. 0388 */ 0389 void invalidateQueuedArea (); 0390 0391 /** 0392 * Updates the part of the view described by dirty region and then 0393 * calls invalidateQueuedArea(). Does nothing if @ref kpViewManager 0394 * is set to queue updates. 0395 */ 0396 void updateQueuedArea (); 0397 0398 QVariant inputMethodQuery (Qt::InputMethodQuery query) const override; 0399 0400 public Q_SLOTS: 0401 /** 0402 * Call this when the "environment" (e.g. document size) changes. The 0403 * environment is defined by the caller and should be based on the type 0404 * of view. For instance, an unzoomed thumbnail view would also 0405 * include in its environment the contents position of an associated 0406 * scrollable container. 0407 * 0408 * This is never called by the kpView base class. 0409 * 0410 * Implementors should change whatever state is necessary for their 0411 * type of view. For instance, an unzoomed view would resize itself; 0412 * a zoomed thumbnail would change the zoom level. 0413 */ 0414 virtual void adjustToEnvironment () = 0; 0415 0416 0417 public: 0418 // If <returnViewPoint> is not KP_INVALID_POINT, it spits it back. 0419 // Else, it returns the current mouse position in view coordinates. 0420 // REFACTOR: Seems like a bad API. 0421 QPoint mouseViewPoint (const QPoint &returnViewPoint = KP_INVALID_POINT) const; 0422 0423 0424 Q_SIGNALS: 0425 /** 0426 * Emitted after all zooming code has been executed. 0427 * 0428 * @param zoomLevelX New zoomLevelX() 0429 * @param zoomLevelY New zoomLevelY() 0430 */ 0431 void zoomLevelChanged (int zoomLevelX, int zoomLevelY); 0432 0433 /** 0434 * Emitted after all resizing code has been executed. 0435 * 0436 * @param size New view size. 0437 */ 0438 void sizeChanged (const QSize &size); 0439 0440 /** 0441 * Convenience signal - same as above. 0442 * 0443 * Emitted after all resizing code has been executed. 0444 * 0445 * @param width New view width. 0446 * @param height New view height. 0447 */ 0448 void sizeChanged (int width, int height); 0449 0450 /** 0451 * Emitted after all origin changing code has been executed. 0452 * 0453 * @param origin The new origin. 0454 */ 0455 void originChanged (const QPoint &origin); 0456 0457 0458 0459 // 0460 // Selections 0461 // 0462 0463 public: 0464 QRect selectionViewRect () const; 0465 0466 // (if <viewPoint> is KP_INVALID_POINT, it uses QCursor::pos()) 0467 0468 QPoint mouseViewPointRelativeToSelection (const QPoint &viewPoint = KP_INVALID_POINT) const; 0469 bool mouseOnSelection (const QPoint &viewPoint = KP_INVALID_POINT) const; 0470 0471 int textSelectionMoveBorderAtomicSize () const; 0472 bool mouseOnSelectionToMove (const QPoint &viewPoint = KP_INVALID_POINT) const; 0473 0474 protected: 0475 bool selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (int atomicSize) const; 0476 public: 0477 int selectionResizeHandleAtomicSize () const; 0478 bool selectionLargeEnoughToHaveResizeHandles () const; 0479 0480 QRegion selectionResizeHandlesViewRegion (bool forRenderer = false) const; 0481 0482 enum SelectionResizeType 0483 { 0484 None = 0, 0485 Left = 1, 0486 Right = 2, 0487 Top = 4, 0488 Bottom = 8 0489 }; 0490 0491 // Returns a bitwise OR of the SelectionResizeType's 0492 int mouseOnSelectionResizeHandle (const QPoint &viewPoint = KP_INVALID_POINT) const; 0493 0494 bool mouseOnSelectionToSelectText (const QPoint &viewPoint = KP_INVALID_POINT) const; 0495 0496 0497 // 0498 // Events 0499 // 0500 0501 protected: 0502 void mouseMoveEvent (QMouseEvent *e) override; 0503 void mousePressEvent (QMouseEvent *e) override; 0504 void mouseReleaseEvent (QMouseEvent *e) override; 0505 public: 0506 // (needs to be public as it may also get event from 0507 // QScrollView::contentsWheelEvent()) 0508 void wheelEvent (QWheelEvent *e) override; 0509 0510 0511 protected: 0512 void keyPressEvent (QKeyEvent *e) override; 0513 void keyReleaseEvent (QKeyEvent *e) override; 0514 0515 protected: 0516 void inputMethodEvent (QInputMethodEvent *e) override; 0517 0518 protected: 0519 bool event (QEvent *e) override; 0520 0521 0522 protected: 0523 void focusInEvent (QFocusEvent *e) override; 0524 void focusOutEvent (QFocusEvent *e) override; 0525 0526 0527 protected: 0528 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0529 void enterEvent (QEnterEvent *e) override; 0530 #else 0531 void enterEvent (QEvent *e) override; 0532 #endif 0533 void leaveEvent (QEvent *e) override; 0534 0535 0536 protected: 0537 void dragEnterEvent (QDragEnterEvent *) override; 0538 void dragLeaveEvent (QDragLeaveEvent *) override; 0539 0540 0541 protected: 0542 void resizeEvent (QResizeEvent *e) override; 0543 0544 0545 // 0546 // Painting 0547 // 0548 0549 protected: 0550 // Returns the document rectangle that, when scaled to the view, 0551 // is "guaranteed" to at least cover <viewRect> and possibly more 0552 // ("guaranteed" in quotes because it doesn't seem so reliable for 0553 // zoom levels that aren't multiples of 100%). 0554 QRect paintEventGetDocRect (const QRect &viewRect) const; 0555 public: 0556 /** 0557 * Draws an opaque background representing transparency. 0558 * 0559 * Currently, it draws a checkerboard which, if it were to be drawn 0560 * in its entirety, is tiled from <patternOrigin>. 0561 * 0562 * @param painter Painter. 0563 * @param patternOrigin Logical top-left point of the checkerboard, 0564 * relative to the painter, if it were to be 0565 * drawn in its entirety. 0566 * @param viewRect Rectangle to paint in relative to the painter. 0567 * @param isPreview Whether the view is for a preview as opposed to 0568 * e.g. editing. If set, this function may render 0569 * slightly differently. 0570 */ 0571 static void drawTransparentBackground (QPainter *painter, 0572 const QPoint &patternOrigin, 0573 const QRect &viewRect, 0574 bool isPreview = false); 0575 protected: 0576 // Draws a checkerboard that looks static even if the view is scrollable. 0577 void paintEventDrawCheckerBoard (QPainter *painter, 0578 const QRect &viewRect); 0579 0580 // Draws the selection and its border onto <destPixmap>. 0581 // <destPixmap> is the part of the document given by <docRect>. 0582 void paintEventDrawSelection (QImage *destPixmap, const QRect &docRect); 0583 0584 // Draws the parts of the selection's resize handles that are inside 0585 // <clipRect> onto the view 0586 void paintEventDrawSelectionResizeHandles (const QRect &clipRect); 0587 void paintEventDrawTempImage (QImage *destPixmap, const QRect &docRect); 0588 0589 // Draws the parts of the grid lines that are inside <viewRect> on 0590 // <painter>. 0591 void paintEventDrawGridLines (QPainter *painter, const QRect &viewRect); 0592 0593 void paintEventDrawDoc_Unclipped (const QRect &viewRect); 0594 void paintEvent (QPaintEvent *e) override; 0595 0596 0597 private: 0598 struct kpViewPrivate *d; 0599 }; 0600 0601 0602 #endif // KP_VIEW_H