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 &region);
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