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