File indexing completed on 2024-05-12 16:01:37

0001 /*
0002  *  SPDX-FileCopyrightText: 2008 Cyrille Berger <cberger@cberger.net>
0003  *  SPDX-FileCopyrightText: 2017 Scott Petrovic <scottpetrovic@gmail.com>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #ifndef _KIS_PAINTING_ASSISTANT_H_
0009 #define _KIS_PAINTING_ASSISTANT_H_
0010 
0011 #include <QString>
0012 #include <QPointF>
0013 #include <QRect>
0014 #include <QFile>
0015 #include <QObject>
0016 #include <QColor>
0017 #include <QXmlStreamWriter>
0018 #include <QMap>
0019 
0020 #include <kritaui_export.h>
0021 #include <kis_shared.h>
0022 #include <kis_types.h>
0023 
0024 class QPainter;
0025 class QRect;
0026 class QRectF;
0027 class KoStore;
0028 class KisCoordinatesConverter;
0029 class KisCanvas2;
0030 class QDomDocument;
0031 class QDomElement;
0032 
0033 #include <kis_shared_ptr.h>
0034 #include <KoGenericRegistry.h>
0035 
0036 class KisPaintingAssistantHandle;
0037 typedef KisSharedPtr<KisPaintingAssistantHandle> KisPaintingAssistantHandleSP;
0038 class KisPaintingAssistant;
0039 class QPainterPath;
0040 
0041 enum HandleType {
0042     NORMAL,
0043     SIDE,
0044     CORNER,
0045     VANISHING_POINT,
0046     ANCHOR
0047 };
0048 
0049 
0050 /**
0051   * Represent an handle of the assistant, used to edit the parameters
0052   * of an assistants. Handles can be shared between assistants.
0053   */
0054 class KRITAUI_EXPORT KisPaintingAssistantHandle : public QPointF, public KisShared
0055 {
0056     friend class KisPaintingAssistant;
0057 
0058 public:
0059     KisPaintingAssistantHandle(double x, double y);
0060     explicit KisPaintingAssistantHandle(QPointF p);
0061     KisPaintingAssistantHandle(const KisPaintingAssistantHandle&);
0062     ~KisPaintingAssistantHandle();
0063     void mergeWith(KisPaintingAssistantHandleSP);
0064     void uncache();
0065     KisPaintingAssistantHandle& operator=(const QPointF&);
0066     void setType(char type);
0067     char handleType() const;
0068 
0069     /**
0070      * Returns the pointer to the "chief" assistant,
0071      * which is supposed to handle transformations of the
0072      * handle, when all the assistants are transformed
0073      */
0074     KisPaintingAssistant* chiefAssistant() const;
0075 
0076 private:
0077     void registerAssistant(KisPaintingAssistant*);
0078     void unregisterAssistant(KisPaintingAssistant*);
0079     bool containsAssistant(KisPaintingAssistant*) const;
0080 
0081 private:
0082     struct Private;
0083     Private* const d;
0084 };
0085 
0086 /**
0087  * A KisPaintingAssistant is an object that assist the drawing on the canvas.
0088  * With this class you can implement virtual equivalent to ruler or compas.
0089  */
0090 class KRITAUI_EXPORT KisPaintingAssistant
0091 {
0092 public:
0093     KisPaintingAssistant(const QString& id, const QString& name);
0094     virtual ~KisPaintingAssistant();
0095     virtual KisPaintingAssistantSP clone(QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> &handleMap) const = 0;
0096     const QString& id() const;
0097     const QString& name() const;
0098     bool isSnappingActive() const;
0099     void setSnappingActive(bool set);
0100 
0101 
0102     /**
0103      * Adjust the position given in parameter.
0104      * @param point the coordinates in point in the document reference
0105      * @param strokeBegin the coordinates of the beginning of the stroke
0106      * @param snapToAny because now assistants can be composited out of multiple inside assistants.
0107      *         snapToAny true means that you can use any of the inside assistant, while it being false
0108      *         means you should use the last used one. The logic determining when it happens (first stroke etc.)
0109      *         is in the decoration, so those two options are enough.
0110      */
0111     virtual QPointF adjustPosition(const QPointF& point, const QPointF& strokeBegin, bool snapToAny) = 0;
0112     virtual void endStroke() {}
0113     virtual void setAdjustedBrushPosition(const QPointF position) { Q_UNUSED(position) }
0114     virtual void setFollowBrushPosition(bool follow) { Q_UNUSED(follow) }
0115     virtual QPointF getEditorPosition() const = 0; // Returns editor widget position in document-space coordinates.
0116     virtual int numHandles() const = 0;
0117 
0118     /**
0119      * @brief canBeLocal
0120      * @return if the assistant can be potentially a "local assistant" (limited to rectangular area) or not
0121      */
0122     virtual bool canBeLocal() const;
0123     /**
0124      * @brief isLocal
0125      * @return if the assistant is limited to a rectangular area or not
0126      */
0127     bool isLocal() const;
0128     /**
0129      * @brief setLocal
0130      * @param value set the indication if the assistant is limited to a rectangular area or not
0131      */
0132     void setLocal(bool value);
0133 
0134     void replaceHandle(KisPaintingAssistantHandleSP _handle, KisPaintingAssistantHandleSP _with);
0135     void addHandle(KisPaintingAssistantHandleSP handle, HandleType type);
0136 
0137     QPointF viewportConstrainedEditorPosition(const KisCoordinatesConverter* converter, const QSize editorSize);
0138 
0139     QColor effectiveAssistantColor() const;
0140     bool useCustomColor();
0141     void setUseCustomColor(bool useCustomColor);
0142     void setAssistantCustomColor(QColor color);
0143     QColor assistantCustomColor();
0144     void setAssistantGlobalColorCache(const QColor &color);
0145 
0146     virtual void drawAssistant(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter *converter, bool cached = true,KisCanvas2 *canvas=0, bool assistantVisible=true, bool previewVisible=true);
0147     void uncache();
0148     const QList<KisPaintingAssistantHandleSP>& handles() const;
0149     QList<KisPaintingAssistantHandleSP> handles();
0150     const QList<KisPaintingAssistantHandleSP>& sideHandles() const;
0151     QList<KisPaintingAssistantHandleSP> sideHandles();
0152 
0153     QByteArray saveXml( QMap<KisPaintingAssistantHandleSP, int> &handleMap);
0154     virtual void saveCustomXml(QXmlStreamWriter* xml); //in case specific assistants have custom properties (like vanishing point)
0155 
0156     void loadXml(KoStore *store, QMap<int, KisPaintingAssistantHandleSP> &handleMap, QString path);
0157     virtual bool loadCustomXml(QXmlStreamReader* xml);
0158 
0159     void saveXmlList(QDomDocument& doc, QDomElement& ssistantsElement, int count);
0160     void findPerspectiveAssistantHandleLocation();
0161     KisPaintingAssistantHandleSP oppHandleOne();
0162 
0163     /**
0164       * Get the topLeft, bottomLeft, topRight and BottomRight corners of the assistant
0165       * Some assistants like the perspective grid have custom logic built around certain handles
0166       */
0167     const KisPaintingAssistantHandleSP topLeft() const;
0168     KisPaintingAssistantHandleSP topLeft();
0169     const KisPaintingAssistantHandleSP topRight() const;
0170     KisPaintingAssistantHandleSP topRight();
0171     const KisPaintingAssistantHandleSP bottomLeft() const;
0172     KisPaintingAssistantHandleSP bottomLeft();
0173     const KisPaintingAssistantHandleSP bottomRight() const;
0174     KisPaintingAssistantHandleSP bottomRight();
0175     const KisPaintingAssistantHandleSP topMiddle() const;
0176     KisPaintingAssistantHandleSP topMiddle();
0177     const KisPaintingAssistantHandleSP rightMiddle() const;
0178     KisPaintingAssistantHandleSP rightMiddle();
0179     const KisPaintingAssistantHandleSP leftMiddle() const;
0180     KisPaintingAssistantHandleSP leftMiddle();
0181     const KisPaintingAssistantHandleSP bottomMiddle() const;
0182     KisPaintingAssistantHandleSP bottomMiddle();
0183 
0184 
0185     // calculates whether a point is near one of the corner points of the assistant
0186     // returns: a corner point from the perspective assistant if the given node is close
0187     // only called once in code when calculating the perspective assistant
0188     KisPaintingAssistantHandleSP closestCornerHandleFromPoint(QPointF point);
0189 
0190     // determines if two points are close to each other
0191     // only used by the nodeNearPoint function (perspective grid assistant).
0192     bool areTwoPointsClose(const QPointF& pointOne, const QPointF& pointTwo);
0193 
0194     /// determines if the assistant has enough handles to be considered created
0195     /// new assistants get in a "creation" phase where they are currently being made on the canvas
0196     /// it will return false if we are in the middle of creating the assistant.
0197     virtual bool isAssistantComplete() const;
0198 
0199     /// Transform the assistant using the given \p transform. Please note that \p transform
0200     /// should be in 'document' coordinate system.
0201     /// Used with image-wide transformations.
0202     virtual void transform(const QTransform &transform);
0203 
0204 public:
0205     /**
0206      * This will render the final output. The drawCache does rendering most of the time so be sure to check that
0207      */
0208     void drawPath(QPainter& painter, const QPainterPath& path, bool drawActive=true);
0209     void drawPreview(QPainter& painter, const QPainterPath& path);
0210     static double norm2(const QPointF& p);
0211 
0212 protected:
0213     explicit KisPaintingAssistant(const KisPaintingAssistant &rhs, QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> &handleMap);
0214 
0215     virtual QRect boundingRect() const;
0216 
0217     /// performance layer where the graphics can be drawn from a cache instead of generated every render update
0218     virtual void drawCache(QPainter& gc, const KisCoordinatesConverter *converter, bool assistantVisible=true) = 0;
0219 
0220     void initHandles(QList<KisPaintingAssistantHandleSP> _handles);
0221     QList<KisPaintingAssistantHandleSP> m_handles;
0222 
0223     QPointF pixelToView(const QPoint pixelCoords) const;
0224 
0225     /**
0226      * @brief firstLocalHandle
0227      * Note: this doesn't guarantee it will be the topleft corner!
0228      * For that, use getLocalRect().topLeft()
0229      * The only purpose of those functions to exist is to be able to
0230      * put getLocalRect() function in the KisPaintingAssistant
0231      * instead of reimplementing it in every specific assistant.
0232      * @return the first handle of the rectangle of the limited area
0233      */
0234     virtual KisPaintingAssistantHandleSP firstLocalHandle() const;
0235     /**
0236      * @brief secondLocalHandle
0237      * Note: this doesn't guarantee it will be the bottomRight corner!
0238      * For that, use getLocalRect().bottomRight()
0239      * (and remember that for QRect bottomRight() works differently than for QRectF,
0240      * so don't convert to QRect before accessing the corner)
0241      * @return
0242      */
0243     virtual KisPaintingAssistantHandleSP secondLocalHandle() const;
0244     /**
0245      * @brief getLocalRect
0246      * The function deals with local handles not being topLeft and bottomRight
0247      * gracefully and returns a correct rectangle.
0248      * Thanks to that the user can place handles in a "wrong" order or move them around
0249      * but the local rectangle will still be correct.
0250      * @return the rectangle of the area that the assistant is limited to
0251      */
0252     QRectF getLocalRect() const;
0253 
0254 
0255 public:
0256     /// clones the list of assistants
0257     /// the originally shared handles will still be shared
0258     /// the cloned assistants do not share any handle with the original assistants
0259     static QList<KisPaintingAssistantSP> cloneAssistantList(const QList<KisPaintingAssistantSP> &list);
0260 
0261 private:
0262     struct Private;
0263     Private* const d;
0264 
0265 };
0266 
0267 /**
0268  * Allow to create a painting assistant.
0269  */
0270 class KRITAUI_EXPORT KisPaintingAssistantFactory
0271 {
0272 public:
0273     KisPaintingAssistantFactory();
0274     virtual ~KisPaintingAssistantFactory();
0275     virtual QString id() const = 0;
0276     virtual QString name() const = 0;
0277     virtual KisPaintingAssistant* createPaintingAssistant() const = 0;
0278 
0279 };
0280 
0281 class KRITAUI_EXPORT KisPaintingAssistantFactoryRegistry : public KoGenericRegistry<KisPaintingAssistantFactory*>
0282 {
0283   public:
0284     KisPaintingAssistantFactoryRegistry();
0285     ~KisPaintingAssistantFactoryRegistry() override;
0286 
0287     static KisPaintingAssistantFactoryRegistry* instance();
0288 
0289 };
0290 
0291 #endif