forked from openkylin/kolourpaint
603 lines
18 KiB
C
603 lines
18 KiB
C
|
|
||
|
/*
|
||
|
Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
|
||
|
All rights reserved.
|
||
|
|
||
|
Redistribution and use in source and binary forms, with or without
|
||
|
modification, are permitted provided that the following conditions
|
||
|
are met:
|
||
|
|
||
|
1. Redistributions of source code must retain the above copyright
|
||
|
notice, this list of conditions and the following disclaimer.
|
||
|
2. Redistributions in binary form must reproduce the above copyright
|
||
|
notice, this list of conditions and the following disclaimer in the
|
||
|
documentation and/or other materials provided with the distribution.
|
||
|
|
||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
|
||
|
#ifndef KP_VIEW_H
|
||
|
#define KP_VIEW_H
|
||
|
|
||
|
|
||
|
#include <QWidget>
|
||
|
|
||
|
#include "kpDefs.h"
|
||
|
|
||
|
|
||
|
class QDragEnterEvent;
|
||
|
class QDragLeaveEvent;
|
||
|
class QEvent;
|
||
|
class QFocusEvent;
|
||
|
class QKeyEvent;
|
||
|
class QMouseEvent;
|
||
|
class QPaintEvent;
|
||
|
class QResizeEvent;
|
||
|
|
||
|
class kpAbstractSelection;
|
||
|
class kpDocument;
|
||
|
class kpTextSelection;
|
||
|
class kpTool;
|
||
|
class kpToolToolBar;
|
||
|
class kpViewManager;
|
||
|
class kpViewScrollableContainer;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @short Abstract base class for all views.
|
||
|
*
|
||
|
* This is the abstract base class for all views. A view is a widget that
|
||
|
* renders a possibly zoomed onscreen representation of a document.
|
||
|
*
|
||
|
* 1 view corresponds to 1 document.
|
||
|
* 1 document corresponds to 0 or more views.
|
||
|
*
|
||
|
* @see kpViewManager
|
||
|
*
|
||
|
* @author Clarence Dang <dang@kde.org>
|
||
|
*/
|
||
|
class kpView : public QWidget
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
|
||
|
public:
|
||
|
/**
|
||
|
* Constructs a view.
|
||
|
*
|
||
|
* @param document The document this view is representing.
|
||
|
* @param toolToolBar The tool tool bar.
|
||
|
* @param viewManager The view manager.
|
||
|
* @param buddyView The view this view watches over (e.g. a thumbnail
|
||
|
* view would watch over the main view). May be 0.
|
||
|
* See for example, highlightBuddyViewRectangle().
|
||
|
* @param scrollableContainer This view's scrollable container.
|
||
|
* May be 0.
|
||
|
*
|
||
|
* You must call adjustEnvironment() at the end of your constructor.
|
||
|
*/
|
||
|
kpView (kpDocument *document,
|
||
|
kpToolToolBar *toolToolBar,
|
||
|
kpViewManager *viewManager,
|
||
|
kpView *buddyView,
|
||
|
kpViewScrollableContainer *scrollableContainer,
|
||
|
QWidget *parent);
|
||
|
|
||
|
/**
|
||
|
* Destructs this view. Informs the viewManager() that the mouse
|
||
|
* cursor is no longer above this view.
|
||
|
*/
|
||
|
~kpView () override;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Constants (enforced by methods)
|
||
|
//
|
||
|
static const int MinZoomLevel, MaxZoomLevel;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @returns the document.
|
||
|
*/
|
||
|
kpDocument *document () const;
|
||
|
|
||
|
protected:
|
||
|
/**
|
||
|
* @returns the document's selection.
|
||
|
*/
|
||
|
kpAbstractSelection *selection () const;
|
||
|
|
||
|
kpTextSelection *textSelection () const;
|
||
|
|
||
|
public:
|
||
|
/**
|
||
|
* @returns the tool tool bar.
|
||
|
*/
|
||
|
kpToolToolBar *toolToolBar () const;
|
||
|
|
||
|
protected:
|
||
|
/**
|
||
|
* @returns the currently selected tool.
|
||
|
*/
|
||
|
kpTool *tool () const;
|
||
|
|
||
|
public:
|
||
|
/**
|
||
|
* @returns the view manager.
|
||
|
*/
|
||
|
kpViewManager *viewManager () const;
|
||
|
|
||
|
/**
|
||
|
* @returns the buddy view.
|
||
|
*/
|
||
|
kpView *buddyView () const;
|
||
|
|
||
|
/**
|
||
|
* @returns the buddyView()'s scrollable container.
|
||
|
*/
|
||
|
kpViewScrollableContainer *buddyViewScrollableContainer () const;
|
||
|
|
||
|
/**
|
||
|
* @returns this view's scrollable container.
|
||
|
*/
|
||
|
kpViewScrollableContainer *scrollableContainer () const;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @returns the horizontal zoom level (100 is unzoomed).
|
||
|
*/
|
||
|
int zoomLevelX (void) const;
|
||
|
|
||
|
/**
|
||
|
* @returns the vertical zoom level (100 is unzoomed).
|
||
|
*/
|
||
|
int zoomLevelY (void) const;
|
||
|
|
||
|
/**
|
||
|
* Sets the horizontal and vertical zoom levels.
|
||
|
*
|
||
|
* @param hzoom Horizontal zoom level.
|
||
|
* @param vzoom Vertical zoom level.
|
||
|
*
|
||
|
* This method automatically bounds <hzoom> and <vzoom> to be between
|
||
|
* MinZoomLevel and MaxZoomLevel inclusive.
|
||
|
*
|
||
|
* If reimplementing, you must call this base implementation.
|
||
|
*/
|
||
|
virtual void setZoomLevel (int hzoom, int vzoom);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @returns in views coordinates, where the top-left document() pixel
|
||
|
* will be rendered (default: (0,0)).
|
||
|
*/
|
||
|
QPoint origin () const;
|
||
|
|
||
|
/**
|
||
|
* Sets the origin.
|
||
|
*
|
||
|
* @param origin New origin.
|
||
|
*
|
||
|
* If reimplementing, you must call this base implementation.
|
||
|
*/
|
||
|
virtual void setOrigin (const QPoint &origin);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @returns whether at this zoom level, the grid can be enabled.
|
||
|
* This is based on whether the grid can be sensibly rendered.
|
||
|
*/
|
||
|
bool canShowGrid () const;
|
||
|
|
||
|
/**
|
||
|
* @returns whether the grid is currently shown.
|
||
|
*/
|
||
|
bool isGridShown () const;
|
||
|
|
||
|
/**
|
||
|
* Turns on/off the grid.
|
||
|
*
|
||
|
* @param yes Whether to enable the grid.
|
||
|
*/
|
||
|
void showGrid (bool yes = true);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @returns whether to draw a rectangle highlighting the area of
|
||
|
* buddyView() visible through buddyViewScrollableContainer().
|
||
|
*/
|
||
|
bool isBuddyViewScrollableContainerRectangleShown () const;
|
||
|
|
||
|
/**
|
||
|
* Turns on/off the rectangle highlighting the area of buddyView()
|
||
|
* visible through buddyViewScrollableContainer() and redraws.
|
||
|
*
|
||
|
* @param yes Whether to turn on the rectangle.
|
||
|
*/
|
||
|
void showBuddyViewScrollableContainerRectangle (bool yes = true);
|
||
|
|
||
|
protected:
|
||
|
/**
|
||
|
* @returns the current rectangle highlighting the area of buddyView()
|
||
|
* visible through buddyViewScrollableContainer(), that is being
|
||
|
* rendered by this view.
|
||
|
*/
|
||
|
QRect buddyViewScrollableContainerRectangle () const;
|
||
|
|
||
|
protected slots:
|
||
|
/**
|
||
|
* Updates the buddyViewScrollableContainerRectangle() and redraws
|
||
|
* appropriately.
|
||
|
*
|
||
|
* This is already connected to zoomLevelChanged() and originChanged();
|
||
|
* buddyView() and buddyViewScrollableContainer() signals. There is probably no
|
||
|
* need to call this function directly.
|
||
|
*/
|
||
|
void updateBuddyViewScrollableContainerRectangle ();
|
||
|
|
||
|
|
||
|
public:
|
||
|
|
||
|
/**
|
||
|
* @param viewX Horizontal position in view coordinates.
|
||
|
*
|
||
|
* @returns viewX transformed to document coordinates, based on the
|
||
|
* origin() and zoomLevelX().
|
||
|
*/
|
||
|
double transformViewToDocX (double viewX) const;
|
||
|
|
||
|
/**
|
||
|
* @param viewY Vertical position in view coordinates.
|
||
|
*
|
||
|
* @returns viewY transformed to document coordinates, based on the
|
||
|
* origin() and zoomLevelY().
|
||
|
*/
|
||
|
double transformViewToDocY (double viewY) const;
|
||
|
|
||
|
/**
|
||
|
* @param viewPoint Position in view coordinates.
|
||
|
*
|
||
|
* @returns viewPoint transformed to document coordinates, based on the
|
||
|
* origin(), zoomLevelX() and zoomLevelY().
|
||
|
*/
|
||
|
QPoint transformViewToDoc (const QPoint &viewPoint) const;
|
||
|
|
||
|
/**
|
||
|
* @param viewRect Rectangle in view coordinates.
|
||
|
*
|
||
|
* @returns viewRect transformed to document coordinates based on the
|
||
|
* origin(), zoomLevelX() and zoomLevelY().
|
||
|
*
|
||
|
* For bounding rectangles, you should use this function instead of
|
||
|
* transformViewToDocX(), transformViewToDocY() or
|
||
|
* transformViewToDoc(const QPoint &) which act on coordinates only.
|
||
|
*/
|
||
|
QRect transformViewToDoc (const QRect &viewRect) const;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @param docX Horizontal position in document coordinates.
|
||
|
*
|
||
|
* @returns docX transformed to view coordinates, based on the origin()
|
||
|
* and zoomLevelX().
|
||
|
*/
|
||
|
double transformDocToViewX (double docX) const;
|
||
|
|
||
|
/**
|
||
|
* @param docY Vertical position in document coordinates.
|
||
|
*
|
||
|
* @returns docY transformed to view coordinates, based on the origin()
|
||
|
* and zoomLevelY().
|
||
|
*/
|
||
|
double transformDocToViewY (double docY) const;
|
||
|
|
||
|
/**
|
||
|
* @param docPoint Position in document coordinates.
|
||
|
*
|
||
|
* @returns docPoint transformed to view coordinates, based on the
|
||
|
* origin(), zoomLevelX(), zoomLevelY().
|
||
|
*/
|
||
|
QPoint transformDocToView (const QPoint &docPoint) const;
|
||
|
|
||
|
/**
|
||
|
* @param docRect Rectangle in document coordinates.
|
||
|
*
|
||
|
* @return docRect transformed to view coordinates, based on the
|
||
|
* origin(), zoomLevelX() and zoomLevelY().
|
||
|
*
|
||
|
* For bounding rectangles, you should use this function instead of
|
||
|
* transformDocToViewX(), transformDocToViewY() or
|
||
|
* transformDocToView(const QPoint &) which act on coordinates only.
|
||
|
*/
|
||
|
QRect transformDocToView (const QRect &docRect) const;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @param viewPoint Position in view coordinates.
|
||
|
* @param otherView View whose coordinate system the return value will
|
||
|
* be in.
|
||
|
*
|
||
|
* @returns viewPoint transformed to the coordinate system of
|
||
|
* @param otherView based on this and otherView's origin(),
|
||
|
* zoomLevelX() and zoomLevelY(). This has less rounding
|
||
|
* error than otherView->transformDocToView (transformViewToDoc (viewPoint)).
|
||
|
*/
|
||
|
QPoint transformViewToOtherView (const QPoint &viewPoint,
|
||
|
const kpView *otherView);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @returns the approximate view width required to display the entire
|
||
|
* document(), based on the zoom level only.
|
||
|
*/
|
||
|
int zoomedDocWidth () const;
|
||
|
|
||
|
/**
|
||
|
* @returns the approximate view height required to display the entire
|
||
|
* document(), based on the zoom level only.
|
||
|
*/
|
||
|
int zoomedDocHeight () const;
|
||
|
|
||
|
|
||
|
protected:
|
||
|
/**
|
||
|
* Updates the viewManager() on whether or not the mouse is directly
|
||
|
* above this view. Among other things, this ensures the brush cursor
|
||
|
* is updated.
|
||
|
*
|
||
|
* This should be called in event handlers.
|
||
|
*
|
||
|
* @param yes Whether the mouse is directly above this view.
|
||
|
*/
|
||
|
void setHasMouse (bool yes = true);
|
||
|
|
||
|
|
||
|
public:
|
||
|
/**
|
||
|
* Adds a region (in view coordinates) to the dirty area that is
|
||
|
* repainted when the parent @ref kpViewManager is set not to queue
|
||
|
* updates.
|
||
|
*
|
||
|
* @param region Region (in view coordinates) that needs repainting.
|
||
|
*/
|
||
|
void addToQueuedArea (const QRegion ®ion);
|
||
|
|
||
|
/**
|
||
|
* Convenience function. Same as above.
|
||
|
*
|
||
|
* Adds a rectangle (in view coordinates) to the dirty area that is
|
||
|
* repainted when the parent @ref kpViewManager is set not to queue
|
||
|
* updates.
|
||
|
*
|
||
|
* @param rect Rectangle (in view coordinates) that needs repainting.
|
||
|
*/
|
||
|
void addToQueuedArea (const QRect &rect);
|
||
|
|
||
|
/**
|
||
|
* Removes the dirty region that has been queued for updating.
|
||
|
* Does not update the view.
|
||
|
*/
|
||
|
void invalidateQueuedArea ();
|
||
|
|
||
|
/**
|
||
|
* Updates the part of the view described by dirty region and then
|
||
|
* calls invalidateQueuedArea(). Does nothing if @ref kpViewManager
|
||
|
* is set to queue updates.
|
||
|
*/
|
||
|
void updateQueuedArea ();
|
||
|
|
||
|
QVariant inputMethodQuery (Qt::InputMethodQuery query) const override;
|
||
|
|
||
|
public slots:
|
||
|
/**
|
||
|
* Call this when the "environment" (e.g. document size) changes. The
|
||
|
* environment is defined by the caller and should be based on the type
|
||
|
* of view. For instance, an unzoomed thumbnail view would also
|
||
|
* include in its environment the contents position of an associated
|
||
|
* scrollable container.
|
||
|
*
|
||
|
* This is never called by the kpView base class.
|
||
|
*
|
||
|
* Implementors should change whatever state is necessary for their
|
||
|
* type of view. For instance, an unzoomed view would resize itself;
|
||
|
* a zoomed thumbnail would change the zoom level.
|
||
|
*/
|
||
|
virtual void adjustToEnvironment () = 0;
|
||
|
|
||
|
|
||
|
public:
|
||
|
// If <returnViewPoint> is not KP_INVALID_POINT, it spits it back.
|
||
|
// Else, it returns the current mouse position in view coordinates.
|
||
|
// REFACTOR: Seems like a bad API.
|
||
|
QPoint mouseViewPoint (const QPoint &returnViewPoint = KP_INVALID_POINT) const;
|
||
|
|
||
|
|
||
|
signals:
|
||
|
/**
|
||
|
* Emitted after all zooming code has been executed.
|
||
|
*
|
||
|
* @param zoomLevelX New zoomLevelX()
|
||
|
* @param zoomLevelY New zoomLevelY()
|
||
|
*/
|
||
|
void zoomLevelChanged (int zoomLevelX, int zoomLevelY);
|
||
|
|
||
|
/**
|
||
|
* Emitted after all resizing code has been executed.
|
||
|
*
|
||
|
* @param size New view size.
|
||
|
*/
|
||
|
void sizeChanged (const QSize &size);
|
||
|
|
||
|
/**
|
||
|
* Convenience signal - same as above.
|
||
|
*
|
||
|
* Emitted after all resizing code has been executed.
|
||
|
*
|
||
|
* @param width New view width.
|
||
|
* @param height New view height.
|
||
|
*/
|
||
|
void sizeChanged (int width, int height);
|
||
|
|
||
|
/**
|
||
|
* Emitted after all origin changing code has been executed.
|
||
|
*
|
||
|
* @param origin The new origin.
|
||
|
*/
|
||
|
void originChanged (const QPoint &origin);
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Selections
|
||
|
//
|
||
|
|
||
|
public:
|
||
|
QRect selectionViewRect () const;
|
||
|
|
||
|
// (if <viewPoint> is KP_INVALID_POINT, it uses QCursor::pos())
|
||
|
|
||
|
QPoint mouseViewPointRelativeToSelection (const QPoint &viewPoint = KP_INVALID_POINT) const;
|
||
|
bool mouseOnSelection (const QPoint &viewPoint = KP_INVALID_POINT) const;
|
||
|
|
||
|
int textSelectionMoveBorderAtomicSize () const;
|
||
|
bool mouseOnSelectionToMove (const QPoint &viewPoint = KP_INVALID_POINT) const;
|
||
|
|
||
|
protected:
|
||
|
bool selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (int atomicSize) const;
|
||
|
public:
|
||
|
int selectionResizeHandleAtomicSize () const;
|
||
|
bool selectionLargeEnoughToHaveResizeHandles () const;
|
||
|
|
||
|
QRegion selectionResizeHandlesViewRegion (bool forRenderer = false) const;
|
||
|
|
||
|
enum SelectionResizeType
|
||
|
{
|
||
|
None = 0,
|
||
|
Left = 1,
|
||
|
Right = 2,
|
||
|
Top = 4,
|
||
|
Bottom = 8
|
||
|
};
|
||
|
|
||
|
// Returns a bitwise OR of the SelectionResizeType's
|
||
|
int mouseOnSelectionResizeHandle (const QPoint &viewPoint = KP_INVALID_POINT) const;
|
||
|
|
||
|
bool mouseOnSelectionToSelectText (const QPoint &viewPoint = KP_INVALID_POINT) const;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Events
|
||
|
//
|
||
|
|
||
|
protected:
|
||
|
void mouseMoveEvent (QMouseEvent *e) override;
|
||
|
void mousePressEvent (QMouseEvent *e) override;
|
||
|
void mouseReleaseEvent (QMouseEvent *e) override;
|
||
|
public:
|
||
|
// (needs to be public as it may also get event from
|
||
|
// QScrollView::contentsWheelEvent())
|
||
|
void wheelEvent (QWheelEvent *e) override;
|
||
|
|
||
|
|
||
|
protected:
|
||
|
void keyPressEvent (QKeyEvent *e) override;
|
||
|
void keyReleaseEvent (QKeyEvent *e) override;
|
||
|
|
||
|
protected:
|
||
|
void inputMethodEvent (QInputMethodEvent *e) override;
|
||
|
|
||
|
protected:
|
||
|
bool event (QEvent *e) override;
|
||
|
|
||
|
|
||
|
protected:
|
||
|
void focusInEvent (QFocusEvent *e) override;
|
||
|
void focusOutEvent (QFocusEvent *e) override;
|
||
|
|
||
|
|
||
|
protected:
|
||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||
|
void enterEvent (QEnterEvent *e) override;
|
||
|
#else
|
||
|
void enterEvent (QEvent *e) override;
|
||
|
#endif
|
||
|
void leaveEvent (QEvent *e) override;
|
||
|
|
||
|
|
||
|
protected:
|
||
|
void dragEnterEvent (QDragEnterEvent *) override;
|
||
|
void dragLeaveEvent (QDragLeaveEvent *) override;
|
||
|
|
||
|
|
||
|
protected:
|
||
|
void resizeEvent (QResizeEvent *e) override;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Painting
|
||
|
//
|
||
|
|
||
|
protected:
|
||
|
// Returns the document rectangle that, when scaled to the view,
|
||
|
// is "guaranteed" to at least cover <viewRect> and possibly more
|
||
|
// ("guaranteed" in quotes because it doesn't seem so reliable for
|
||
|
// zoom levels that aren't multiples of 100%).
|
||
|
QRect paintEventGetDocRect (const QRect &viewRect) const;
|
||
|
public:
|
||
|
/**
|
||
|
* Draws an opaque background representing transparency.
|
||
|
*
|
||
|
* Currently, it draws a checkerboard which, if it were to be drawn
|
||
|
* in its entirety, is tiled from <patternOrigin>.
|
||
|
*
|
||
|
* @param painter Painter.
|
||
|
* @param patternOrigin Logical top-left point of the checkerboard,
|
||
|
* relative to the painter, if it were to be
|
||
|
* drawn in its entirety.
|
||
|
* @param viewRect Rectangle to paint in relative to the painter.
|
||
|
* @param isPreview Whether the view is for a preview as opposed to
|
||
|
* e.g. editing. If set, this function may render
|
||
|
* slightly differently.
|
||
|
*/
|
||
|
static void drawTransparentBackground (QPainter *painter,
|
||
|
const QPoint &patternOrigin,
|
||
|
const QRect &viewRect,
|
||
|
bool isPreview = false);
|
||
|
protected:
|
||
|
// Draws a checkerboard that looks static even if the view is scrollable.
|
||
|
void paintEventDrawCheckerBoard (QPainter *painter,
|
||
|
const QRect &viewRect);
|
||
|
|
||
|
// Draws the selection and its border onto <destPixmap>.
|
||
|
// <destPixmap> is the part of the document given by <docRect>.
|
||
|
void paintEventDrawSelection (QImage *destPixmap, const QRect &docRect);
|
||
|
|
||
|
// Draws the parts of the selection's resize handles that are inside
|
||
|
// <clipRect> onto the view
|
||
|
void paintEventDrawSelectionResizeHandles (const QRect &clipRect);
|
||
|
void paintEventDrawTempImage (QImage *destPixmap, const QRect &docRect);
|
||
|
|
||
|
// Draws the parts of the grid lines that are inside <viewRect> on
|
||
|
// <painter>.
|
||
|
void paintEventDrawGridLines (QPainter *painter, const QRect &viewRect);
|
||
|
|
||
|
void paintEventDrawDoc_Unclipped (const QRect &viewRect);
|
||
|
void paintEvent (QPaintEvent *e) override;
|
||
|
|
||
|
|
||
|
private:
|
||
|
struct kpViewPrivate *d;
|
||
|
};
|
||
|
|
||
|
|
||
|
#endif // KP_VIEW_H
|