File indexing completed on 2024-05-12 15:56:49

0001 /* This file is part of the KDE project
0002 
0003    SPDX-FileCopyrightText: 2006-2008 Thorsten Zachmann <zachmann@kde.org>
0004    SPDX-FileCopyrightText: 2007, 2009 Thomas Zander <zander@kde.org>
0005 
0006    SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #ifndef KOSHAPEMANAGER_H
0010 #define KOSHAPEMANAGER_H
0011 
0012 #include <QList>
0013 #include <QObject>
0014 #include <QSet>
0015 #include <QRect>
0016 
0017 #include "KoFlake.h"
0018 #include "kritaflake_export.h"
0019 
0020 #include <memory>
0021 #include <vector>
0022 
0023 class KoShape;
0024 class KoSelection;
0025 class KoViewConverter;
0026 class KoCanvasBase;
0027 class KoPointerEvent;
0028 
0029 class QPainter;
0030 class QPointF;
0031 class QRectF;
0032 
0033 /**
0034  * The shape manager hold a list of all shape which are in scope.
0035  * There is one shape manager per canvas. This makes the shape manager
0036  * different from QGraphicsScene, which contains the datamodel for all
0037  * graphics items: KoShapeManager only contains the subset of shapes
0038  * that are shown in its canvas.
0039  *
0040  * The selection in the different views can be different.
0041  */
0042 class KRITAFLAKE_EXPORT KoShapeManager : public QObject
0043 {
0044     Q_OBJECT
0045 
0046 public:
0047     /// enum for add()
0048     enum Repaint {
0049         PaintShapeOnAdd,    ///< Causes each shapes 'update()' to be called after being added to the shapeManager
0050         AddWithoutRepaint   ///< Avoids each shapes 'update()' to be called for faster addition when its possible.
0051     };
0052 
0053     /**
0054      * Constructor.
0055      */
0056     explicit KoShapeManager(KoCanvasBase *canvas);
0057     /**
0058      * Constructor that takes a list of shapes, convenience version.
0059      * @param shapes the shapes to start out with, see also setShapes()
0060      * @param canvas the canvas this shape manager is working on.
0061      */
0062     KoShapeManager(KoCanvasBase *canvas, const QList<KoShape *> &shapes);
0063     ~KoShapeManager() override;
0064 
0065 
0066     /**
0067      * Remove all previously owned shapes and make the argument list the new shapes
0068      * to be managed by this manager.
0069      * @param shapes the new shapes to manage.
0070      * @param repaint if true it will trigger a repaint of the shapes
0071      */
0072     void setShapes(const QList<KoShape *> &shapes, Repaint repaint = PaintShapeOnAdd);
0073 
0074     /// returns the list of maintained shapes
0075     QList<KoShape*> shapes() const;
0076 
0077     /**
0078      * Get a list of all shapes that don't have a parent.
0079      */
0080     QList<KoShape*> topLevelShapes() const;
0081 
0082 public Q_SLOTS:
0083     /**
0084      * Add a KoShape to be displayed and managed by this manager.
0085      * This will trigger a repaint of the shape.
0086      * @param shape the shape to add
0087      * @param repaint if true it will trigger a repaint of the shape
0088      */
0089     void addShape(KoShape *shape, KoShapeManager::Repaint repaint = PaintShapeOnAdd);
0090 
0091 
0092     /**
0093      * Remove a KoShape from this manager
0094      * @param shape the shape to remove
0095      */
0096     void remove(KoShape *shape);
0097 
0098 public:
0099     /// return the selection shapes for this shapeManager
0100     KoSelection *selection() const;
0101 
0102     struct PaintJob {
0103         using ShapesStorage = std::vector<std::unique_ptr<KoShape>>;
0104         using SharedSafeStorage = std::shared_ptr<ShapesStorage>;
0105 
0106         PaintJob() = default;
0107         PaintJob(QRectF _docUpdateRect, QRect _viewUpdateRect)
0108             : docUpdateRect(_docUpdateRect),
0109               viewUpdateRect(_viewUpdateRect)
0110         {
0111         }
0112 
0113         bool isEmpty() const {
0114             return shapes.isEmpty();
0115         }
0116 
0117         QRectF docUpdateRect;
0118         QRect viewUpdateRect;
0119 
0120         QList<KoShape*> shapes;
0121         SharedSafeStorage allClonedShapes;
0122     };
0123 
0124     struct PaintJobsOrder
0125     {
0126         QRect uncroppedViewUpdateRect;
0127         QList<PaintJob> jobs;
0128 
0129         inline void clear() {
0130             jobs.clear();
0131             uncroppedViewUpdateRect = QRect();
0132         }
0133 
0134         inline bool isEmpty() const {
0135             return jobs.isEmpty();
0136         }
0137     };
0138 
0139     /**
0140      * The update signals are usually emitted when the owned of the manager
0141      * calls to preparePaintJobs() in the beginning of the rendering cycle.
0142      * This way we avoid too many signals to be emitted. But some of the
0143      * canvases (e.g. KisShapeSelectionCanvas) doesn't do any rendering (yet?),
0144      * so the signals should be emitted explicitly.
0145      */
0146     void explicitlyIssueShapeChangedSignals();
0147 
0148     /**
0149      * Prepare a shallow copy of all the shapes and the jobs to be rendered
0150      * asynchronoursly later. The copies are stored in jobs, so that the user
0151      * could later pass these jobs into paintJob() in a separate thread.
0152      *
0153      * @param jobs a list of rects that are going to be updated. docUpdateRect
0154      *             and viewUpdateRect should be preinitialized by the caller.
0155      * @param excludeRoot the root shape which should not be copied. It is basically
0156      *                    a hack to avoid copying of KisShapeLayer, which is not
0157      *                    copiable.
0158      * \see paintJob()
0159      * \see a comment in KisShapeLayerCanvas::slotStartAsyncRepaint()
0160      */
0161     void preparePaintJobs(PaintJobsOrder &jobsOrder, KoShape *excludeRoot);
0162 
0163     /**
0164      * Render a \p job on \p painter. No mutable internals of the shape
0165      * manager are accessed, so calling this method is safe in multithreading
0166      * environment.
0167      *
0168      * @param painter a painter to paint on. Clip rect of the painter is expected to be setup correctly.
0169      * @param job a job to paint.
0170      * @param forPrint not used in Krita.
0171      *
0172      * \see preparePaintJobs
0173      */
0174     void paintJob(QPainter &painter, const KoShapeManager::PaintJob &job);
0175 
0176     /**
0177      * Paint all shapes and their selection handles etc.
0178      * @param painter the painter to paint to.
0179      * @param forPrint if true, make sure only actual content is drawn and no decorations.
0180      * @param converter to convert between document and view coordinates.
0181      */
0182     void paint(QPainter &painter);
0183 
0184     /**
0185      * Returns the shape located at a specific point in the document.
0186      * If more than one shape is located at the specific point, the given selection type
0187      * controls which of them is returned.
0188      * @param position the position in the document coordinate system.
0189      * @param selection controls which shape is returned when more than one shape is at the specific point
0190      * @param omitHiddenShapes if true, only visible shapes are considered
0191      */
0192     KoShape *shapeAt(const QPointF &position, KoFlake::ShapeSelection selection = KoFlake::ShapeOnTop, bool omitHiddenShapes = true);
0193 
0194     /**
0195      * Returns the shapes which intersects the specific rect in the document.
0196      * @param rect the rectangle in the document coordinate system.
0197      * @param omitHiddenShapes if @c true, only visible shapes are considered
0198      * @param containedMode if @c true use contained mode
0199      */
0200     QList<KoShape *> shapesAt(const QRectF &rect, bool omitHiddenShapes = true, bool containedMode = false);
0201 
0202     /**
0203      * Request a repaint to be queued.
0204      * The repaint will be restricted to the parameters rectangle, which is expected to be
0205      * in points (the document coordinates system of KoShape) and it is expected to be
0206      * normalized and based in the global coordinates, not any local coordinates.
0207      * <p>This method will return immediately and only request a repaint. Successive calls
0208      * will be merged into an appropriate repaint action.
0209      * @param rect the rectangle (in pt) to queue for repaint.
0210      * @param shape the shape that is going to be redrawn; only needed when selectionHandles=true
0211      * @param selectionHandles if true; find out if the shape is selected and repaint its
0212      *   selection handles at the same time.
0213      */
0214     void update(const QRectF &rect, const KoShape *shape = 0, bool selectionHandles = false);
0215 
0216     /**
0217      * Block all updates initiated with update() call. The incoming updates will
0218      * be dropped completely.
0219      */
0220     void setUpdatesBlocked(bool value);
0221 
0222     /**
0223      * \see setUpdatesBlocked()
0224      */
0225     bool updatesBlocked() const;
0226 
0227     /**
0228      * Update the tree for finding the shapes.
0229      * This will remove the shape from the tree and will reinsert it again.
0230      * The update to the tree will be posponed until it is needed so that successive calls
0231      * will be merged into one.
0232      * @param shape the shape to updated its position in the tree.
0233      */
0234     void notifyShapeChanged(KoShape *shape);
0235 
0236     /**
0237      * @brief renderSingleShape renders a shape on \p painter. This method includes all the
0238      * needed steps for painting a single shape: setting transformations, clipping and masking.
0239      */
0240     static void renderSingleShape(KoShape *shape, QPainter &painter);
0241 
0242     /**
0243      * A special interface for KoShape to use during shape destruction. Don't use this
0244      * interface directly unless you are KoShape.
0245      */
0246     struct ShapeInterface {
0247         ShapeInterface(KoShapeManager *_q);
0248 
0249         /**
0250          * Called by a shape when it is destructed. Please note that you cannot access
0251          * any shape's method type or information during this call because the shape might be
0252          * semi-destroyed.
0253          */
0254         void notifyShapeDestructed(KoShape *shape);
0255 
0256     protected:
0257         KoShapeManager *q;
0258     };
0259 
0260     ShapeInterface* shapeInterface();
0261 
0262 Q_SIGNALS:
0263     /// emitted when the selection is changed
0264     void selectionChanged();
0265     /// emitted when an object in the selection is changed (moved/rotated etc)
0266     void selectionContentChanged();
0267     /// emitted when any object changed (moved/rotated etc)
0268     void contentChanged();
0269 
0270 private:
0271     KoCanvasBase *canvas();
0272 
0273 
0274     class Private;
0275     Private * const d;
0276     Q_PRIVATE_SLOT(d, void updateTree())
0277     Q_PRIVATE_SLOT(d, void forwardCompressedUdpate())
0278 };
0279 
0280 #endif