File indexing completed on 2024-05-19 04:29:03
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 compass. 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 //copy SharedData from an assistant to this 0101 void copySharedData(KisPaintingAssistantSP assistant); 0102 0103 0104 /** 0105 * Adjust the position given in parameter. 0106 * @param point the coordinates in point in the document reference 0107 * @param strokeBegin the coordinates of the beginning of the stroke 0108 * @param snapToAny because now assistants can be composited out of multiple inside assistants. 0109 * snapToAny true means that you can use any of the inside assistant, while it being false 0110 * means you should use the last used one. The logic determining when it happens (first stroke etc.) 0111 * is in the decoration, so those two options are enough. 0112 * @param moveThresholdPt the threshold for the "move" of the cursor measured in pt 0113 * (usually equals to 2px in screen coordinates converted to pt) 0114 */ 0115 virtual QPointF adjustPosition(const QPointF& point, const QPointF& strokeBegin, bool snapToAny, qreal moveThresholdPt) = 0; 0116 virtual void adjustLine(QPointF& point, QPointF& strokeBegin) = 0; 0117 virtual void endStroke(); 0118 virtual void setAdjustedBrushPosition(const QPointF position); 0119 virtual void setFollowBrushPosition(bool follow); 0120 virtual QPointF getDefaultEditorPosition() const = 0; // Returns standard editor widget position for this assistant 0121 virtual QPointF getEditorPosition() const; // Returns editor widget position in document-space coordinates. 0122 virtual int numHandles() const = 0; 0123 0124 /** 0125 * @brief canBeLocal 0126 * @return if the assistant can be potentially a "local assistant" (limited to rectangular area) or not 0127 */ 0128 virtual bool canBeLocal() const; 0129 /** 0130 * @brief isLocal 0131 * @return if the assistant is limited to a rectangular area or not 0132 */ 0133 bool isLocal() const; 0134 /** 0135 * @brief setLocal 0136 * @param value set the indication if the assistant is limited to a rectangular area or not 0137 */ 0138 void setLocal(bool value); 0139 0140 /** 0141 * @brief isLocked 0142 * @return if the assistant is locked (= cannot be moved, or edited in any way), or not 0143 */ 0144 bool isLocked(); 0145 /** 0146 * @brief setLocked 0147 * @param value set the indication if the assistant is locked (= cannot be moved, or edited in any way) or not 0148 */ 0149 void setLocked(bool value); 0150 /** 0151 * @brief isDuplicating 0152 * @return If the duplication button is pressed 0153 */ 0154 /*The duplication button must be depressed when the user clicks it. This getter function indicates to the 0155 render function when the button is clicked*/ 0156 bool isDuplicating(); 0157 /** 0158 * @brief setDuplicating 0159 * @param value setter function sets the indication that the duplication button is pressed 0160 */ 0161 void setDuplicating(bool value); 0162 0163 QPointF editorWidgetOffset(); 0164 void setEditorWidgetOffset(QPointF offset); 0165 0166 void replaceHandle(KisPaintingAssistantHandleSP _handle, KisPaintingAssistantHandleSP _with); 0167 void addHandle(KisPaintingAssistantHandleSP handle, HandleType type); 0168 0169 QPointF viewportConstrainedEditorPosition(const KisCoordinatesConverter* converter, const QSize editorSize); 0170 0171 QColor effectiveAssistantColor() const; 0172 bool useCustomColor(); 0173 void setUseCustomColor(bool useCustomColor); 0174 void setAssistantCustomColor(QColor color); 0175 QColor assistantCustomColor(); 0176 void setAssistantGlobalColorCache(const QColor &color); 0177 0178 virtual void drawAssistant(QPainter& gc, const QRectF& updateRect, const KisCoordinatesConverter *converter, bool cached, KisCanvas2 *canvas=0, bool assistantVisible=true, bool previewVisible=true); 0179 void uncache(); 0180 const QList<KisPaintingAssistantHandleSP>& handles() const; 0181 QList<KisPaintingAssistantHandleSP> handles(); 0182 const QList<KisPaintingAssistantHandleSP>& sideHandles() const; 0183 QList<KisPaintingAssistantHandleSP> sideHandles(); 0184 0185 QByteArray saveXml( QMap<KisPaintingAssistantHandleSP, int> &handleMap); 0186 virtual void saveCustomXml(QXmlStreamWriter* xml); //in case specific assistants have custom properties (like vanishing point) 0187 0188 void loadXml(KoStore *store, QMap<int, KisPaintingAssistantHandleSP> &handleMap, QString path); 0189 virtual bool loadCustomXml(QXmlStreamReader* xml); 0190 0191 void saveXmlList(QDomDocument& doc, QDomElement& assistantsElement, int count); 0192 void findPerspectiveAssistantHandleLocation(); 0193 KisPaintingAssistantHandleSP oppHandleOne(); 0194 0195 /** 0196 * Get the topLeft, bottomLeft, topRight and BottomRight corners of the assistant 0197 * Some assistants like the perspective grid have custom logic built around certain handles 0198 */ 0199 const KisPaintingAssistantHandleSP topLeft() const; 0200 KisPaintingAssistantHandleSP topLeft(); 0201 const KisPaintingAssistantHandleSP topRight() const; 0202 KisPaintingAssistantHandleSP topRight(); 0203 const KisPaintingAssistantHandleSP bottomLeft() const; 0204 KisPaintingAssistantHandleSP bottomLeft(); 0205 const KisPaintingAssistantHandleSP bottomRight() const; 0206 KisPaintingAssistantHandleSP bottomRight(); 0207 const KisPaintingAssistantHandleSP topMiddle() const; 0208 KisPaintingAssistantHandleSP topMiddle(); 0209 const KisPaintingAssistantHandleSP rightMiddle() const; 0210 KisPaintingAssistantHandleSP rightMiddle(); 0211 const KisPaintingAssistantHandleSP leftMiddle() const; 0212 KisPaintingAssistantHandleSP leftMiddle(); 0213 const KisPaintingAssistantHandleSP bottomMiddle() const; 0214 KisPaintingAssistantHandleSP bottomMiddle(); 0215 0216 0217 // calculates whether a point is near one of the corner points of the assistant 0218 // returns: a corner point from the perspective assistant if the given node is close 0219 // only called once in code when calculating the perspective assistant 0220 KisPaintingAssistantHandleSP closestCornerHandleFromPoint(QPointF point); 0221 0222 // determines if two points are close to each other 0223 // only used by the nodeNearPoint function (perspective grid assistant). 0224 bool areTwoPointsClose(const QPointF& pointOne, const QPointF& pointTwo); 0225 0226 /// determines if the assistant has enough handles to be considered created 0227 /// new assistants get in a "creation" phase where they are currently being made on the canvas 0228 /// it will return false if we are in the middle of creating the assistant. 0229 virtual bool isAssistantComplete() const; 0230 0231 /// Transform the assistant using the given \p transform. Please note that \p transform 0232 /// should be in 'document' coordinate system. 0233 /// Used with image-wide transformations. 0234 virtual void transform(const QTransform &transform); 0235 0236 public: 0237 /** 0238 * This will render the final output. The drawCache does rendering most of the time so be sure to check that 0239 */ 0240 void drawPath(QPainter& painter, const QPainterPath& path, bool drawActive=true); 0241 void drawPreview(QPainter& painter, const QPainterPath& path); 0242 // draw a path in a red color, signalizing incorrect state 0243 void drawError(QPainter& painter, const QPainterPath& path); 0244 // draw a vanishing point marker 0245 void drawX(QPainter& painter, const QPointF& pt); 0246 static double norm2(const QPointF& p); 0247 0248 void setDecorationThickness(int thickness); 0249 0250 protected: 0251 explicit KisPaintingAssistant(const KisPaintingAssistant &rhs, QMap<KisPaintingAssistantHandleSP, KisPaintingAssistantHandleSP> &handleMap); 0252 0253 virtual QRect boundingRect() const; 0254 0255 /// performance layer where the graphics can be drawn from a cache instead of generated every render update 0256 virtual void drawCache(QPainter& gc, const KisCoordinatesConverter *converter, bool assistantVisible=true) = 0; 0257 0258 void initHandles(QList<KisPaintingAssistantHandleSP> _handles); 0259 QList<KisPaintingAssistantHandleSP> m_handles; 0260 0261 QPointF pixelToView(const QPoint pixelCoords) const; 0262 /** 0263 * @brief Query the effective brush position to be used for preview lines. 0264 * This is inteded to be used for painting the dynamic preview lines for assistants 0265 * that feature them. Affected by setAdjustedBrushPosition() and setFollowBrushPosition(). 0266 * @return the effective brush (cursor) position in widget coordinates 0267 */ 0268 QPointF effectiveBrushPosition(const KisCoordinatesConverter *converter, KisCanvas2 *canvas) const; 0269 0270 /** 0271 * @brief firstLocalHandle 0272 * Note: this doesn't guarantee it will be the topleft corner! 0273 * For that, use getLocalRect().topLeft() 0274 * The only purpose of those functions to exist is to be able to 0275 * put getLocalRect() function in the KisPaintingAssistant 0276 * instead of reimplementing it in every specific assistant. 0277 * @return the first handle of the rectangle of the limited area 0278 */ 0279 virtual KisPaintingAssistantHandleSP firstLocalHandle() const; 0280 /** 0281 * @brief secondLocalHandle 0282 * Note: this doesn't guarantee it will be the bottomRight corner! 0283 * For that, use getLocalRect().bottomRight() 0284 * (and remember that for QRect bottomRight() works differently than for QRectF, 0285 * so don't convert to QRect before accessing the corner) 0286 * @return 0287 */ 0288 virtual KisPaintingAssistantHandleSP secondLocalHandle() const; 0289 /** 0290 * @brief getLocalRect 0291 * The function deals with local handles not being topLeft and bottomRight 0292 * gracefully and returns a correct rectangle. 0293 * Thanks to that the user can place handles in a "wrong" order or move them around 0294 * but the local rectangle will still be correct. 0295 * @return the rectangle of the area that the assistant is limited to 0296 */ 0297 QRectF getLocalRect() const; 0298 0299 0300 public: 0301 /// clones the list of assistants 0302 /// the originally shared handles will still be shared 0303 /// the cloned assistants do not share any handle with the original assistants 0304 static QList<KisPaintingAssistantSP> cloneAssistantList(const QList<KisPaintingAssistantSP> &list); 0305 0306 protected: 0307 bool m_hasBeenInsideLocalRect {false}; 0308 0309 private: 0310 struct Private; 0311 Private* const d; 0312 0313 }; 0314 0315 /** 0316 * Allow to create a painting assistant. 0317 */ 0318 class KRITAUI_EXPORT KisPaintingAssistantFactory 0319 { 0320 public: 0321 KisPaintingAssistantFactory(); 0322 virtual ~KisPaintingAssistantFactory(); 0323 virtual QString id() const = 0; 0324 virtual QString name() const = 0; 0325 virtual KisPaintingAssistant* createPaintingAssistant() const = 0; 0326 0327 }; 0328 0329 class KRITAUI_EXPORT KisPaintingAssistantFactoryRegistry : public KoGenericRegistry<KisPaintingAssistantFactory*> 0330 { 0331 public: 0332 KisPaintingAssistantFactoryRegistry(); 0333 ~KisPaintingAssistantFactoryRegistry() override; 0334 0335 static KisPaintingAssistantFactoryRegistry* instance(); 0336 0337 }; 0338 0339 #endif