File indexing completed on 2024-06-16 04:12:07

0001 /*
0002  *  SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KIS_PAINTOP_SETTINGS_H_
0008 #define KIS_PAINTOP_SETTINGS_H_
0009 
0010 #include "kis_types.h"
0011 #include "kritaimage_export.h"
0012 
0013 #include <QImage>
0014 #include <QScopedPointer>
0015 
0016 #include "kis_properties_configuration.h"
0017 #include <brushengine/kis_paint_information.h>
0018 #include <brushengine/kis_uniform_paintop_property.h>
0019 
0020 class KisPaintOpConfigWidget;
0021 class KisPaintOpPresetUpdateProxy;
0022 
0023 class KisResourcesInterface;
0024 using KisResourcesInterfaceSP = QSharedPointer<KisResourcesInterface>;
0025 
0026 class KoCanvasResourcesInterface;
0027 using KoCanvasResourcesInterfaceSP = QSharedPointer<KoCanvasResourcesInterface>;
0028 
0029 class KoResourceCacheInterface;
0030 using KoResourceCacheInterfaceSP = QSharedPointer<KoResourceCacheInterface>;
0031 
0032 class KisOptimizedBrushOutline;
0033 
0034 /**
0035  * Configuration property used to control whether airbrushing is enabled.
0036  */
0037 const QString AIRBRUSH_ENABLED = "PaintOpSettings/isAirbrushing";
0038 
0039 /**
0040  * Configuration property used to control airbrushing rate. The value should be in dabs per second.
0041  */
0042 const QString AIRBRUSH_RATE = "PaintOpSettings/rate";
0043 
0044 /**
0045  * Configuration property used to control whether airbrushing is configured to ignore distance-based
0046  * spacing.
0047  */
0048 const QString AIRBRUSH_IGNORE_SPACING = "PaintOpSettings/ignoreSpacing";
0049 
0050 /**
0051  * Configuration property used to control whether the spacing settings can be updated between
0052  * painted dabs.
0053  */
0054 const QString SPACING_USE_UPDATES = "PaintOpSettings/updateSpacingBetweenDabs";
0055 
0056 /**
0057  * This class is used to cache the settings for a paintop
0058  * between two creations. There is one KisPaintOpSettings per input device (mouse, tablet,
0059  * etc...).
0060  *
0061  * The settings may be stored in a preset. Note that if your
0062  * paintop's settings subclass has data that is not stored as a property, that data is not
0063  * saved and restored.
0064  *
0065  * The object also contains a pointer to its parent KisPaintOpPreset object.This is to control the DirtyPreset
0066  * property of KisPaintOpPreset. Whenever the settings are changed/modified from the original -- the preset is
0067  * set to dirty.
0068  */
0069 class KRITAIMAGE_EXPORT KisPaintOpSettings : public KisPropertiesConfiguration
0070 {
0071 public:
0072     struct UpdateListener {
0073         virtual ~UpdateListener();
0074         virtual void setDirty(bool value) = 0;
0075         virtual bool isDirty() const = 0;
0076         virtual void notifySettingsChanged() = 0;
0077     };
0078 
0079     using UpdateListenerSP = QSharedPointer<UpdateListener>;
0080     using UpdateListenerWSP = QWeakPointer<UpdateListener>;
0081 
0082 public:
0083 
0084     KisPaintOpSettings(KisResourcesInterfaceSP resourcesInterface);
0085     ~KisPaintOpSettings() override;
0086     KisPaintOpSettings(const KisPaintOpSettings &rhs);
0087 
0088     /**
0089      * This function is called by a tool when the mouse is pressed. It's useful if
0090      * the paintop needs mouse interaction for instance in the case of the clone op.
0091      * If the tool is supposed to ignore the event, the paint op should return true
0092      * and if the tool is supposed to use the event, return false.
0093      * See kis_tool_freehand:tryPickByPaintOp()
0094      */
0095     virtual bool mousePressEvent(const KisPaintInformation &paintInformation, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode);
0096     /**
0097      * This function is called by a tool when the mouse is released. It's useful if
0098      * the paintop needs mouse interaction for instance in the case of the clone op.
0099      * If the tool is supposed to ignore the event, the paint op should return true
0100      * and if the tool is supposed to use the event, return false.
0101      */
0102     virtual bool mouseReleaseEvent();
0103     /**
0104      * Clone the current settings object. Override this if your settings instance doesn't
0105      * store everything as properties.
0106      */
0107     virtual KisPaintOpSettingsSP clone() const;
0108 
0109     /**
0110      * Removes all the settings from the object while keeping the paintop id,
0111      * which is loaded to the object by the factory
0112      */
0113     virtual void resetSettings(const QStringList &preserveProperties = QStringList());
0114 
0115     /**
0116      * @return the node the paintop is working on.
0117      */
0118     KisNodeSP node() const;
0119 
0120     /**
0121      * Call this function when the paint op is selected or the tool is activated
0122      */
0123     virtual void activate();
0124 
0125     /**
0126      * XXX: Remove this after 2.0, when the paint operation (incremental/non incremental) will
0127      *      be completely handled in the paintop, not in the tool. This is a filthy hack to move
0128      *      the option to the right place, at least.
0129      * @return true if we paint incrementally, false if we paint like Photoshop. By default, paintops
0130      *      do not support non-incremental.
0131      */
0132     virtual bool paintIncremental() {
0133         return true;
0134     }
0135 
0136     /**
0137      * @return the composite op it to which the indirect painting device
0138      * should be initialized to. This is used by clone op to reset
0139      * the composite op to COMPOSITE_COPY
0140      */
0141     virtual QString indirectPaintingCompositeOp() const;
0142 
0143     /**
0144      * Whether this paintop wants to deposit paint even when not moving, i.e. the tool needs to
0145      * activate its timer. If this is true, painting updates need to be generated at regular
0146      * intervals even in the absence of input device events, e.g. when the cursor is not moving.
0147      *
0148      * The default implementation checks the property AIRBRUSH_ENABLED, defaulting to false if the
0149      * property is not found. This should be suitable for most paintops.
0150      */
0151     virtual bool isAirbrushing() const;
0152 
0153     /**
0154      * Indicates the minimum time interval that might be needed between airbrush dabs, in
0155      * milliseconds. A lower value means painting updates need to happen more frequently. This value
0156      * should be ignored if isAirbrushing() is false.
0157      *
0158      * The default implementation uses the property AIRBRUSH_RATE, defaulting to an interval of
0159      * one second if the property is not found. This should be suitable for most paintops.
0160      */
0161     virtual qreal airbrushInterval() const;
0162 
0163     /**
0164      * Indicates whether this configuration allows spacing information to be updated between painted
0165      * dabs during a stroke.
0166      */
0167     virtual bool useSpacingUpdates() const;
0168 
0169     /**
0170      * Indicates if the tool should call paintOp->doAsynchronousUpdate() in between
0171      * paintAt() calls to do the asynchronous rendering
0172      */
0173     virtual bool needsAsynchronousUpdates() const;
0174 
0175     /**
0176      * This structure defines the current mode for painting an outline.
0177      */
0178     struct OutlineMode {
0179         bool isVisible = false;
0180         bool forceCircle = false;
0181         bool showTiltDecoration = false;
0182         bool forceFullSize = false;
0183     };
0184 
0185     /**
0186      * Returns the brush outline in pixel coordinates. Tool is responsible for conversion into view coordinates.
0187      * Outline mode has to be passed to the paintop which builds the outline as some paintops have to paint outline
0188      * always like clone paintop indicating the duplicate position
0189      */
0190     virtual KisOptimizedBrushOutline brushOutline(const KisPaintInformation &info, const OutlineMode &mode, qreal alignForZoom);
0191 
0192     /**
0193     * Helpers for drawing the brush outline
0194     */
0195     static KisOptimizedBrushOutline ellipseOutline(qreal width, qreal height, qreal scale, qreal rotation);
0196 
0197     /**
0198      * Helper for drawing a triangle representing the tilt of the stylus.
0199      *
0200      * @param start is the offset from the brush's outline's bounding box
0201      * @param lengthScale is used for deciding the size of the triangle.
0202      * Brush diameter or width are common choices for this.
0203      * @param angle is the angle between the two sides of the triangle.
0204      */
0205     static QPainterPath makeTiltIndicator(KisPaintInformation const& info,
0206         QPointF const& start, qreal lengthScale, qreal angle);
0207 
0208     /**
0209      * Set paintop opacity directly in the properties
0210      */
0211     virtual void setPaintOpOpacity(qreal value);
0212 
0213     /**
0214      * Set paintop flow directly in the properties
0215      */
0216     void setPaintOpFlow(qreal value);
0217 
0218     /**
0219      * Set paintop fade directly in the properties
0220      */
0221     void setPaintOpFade(qreal value);
0222 
0223     /**
0224      * Set paintop scatter directly in the properties
0225      */
0226     void setPaintOpScatter(qreal value);
0227 
0228     /**
0229      * Set paintop composite mode directly in the properties
0230      */
0231     void setPaintOpCompositeOp(const QString &value);
0232 
0233     /**
0234      * @return opacity saved in the properties
0235      */
0236     virtual qreal paintOpOpacity();
0237 
0238     /**
0239      * @return flow saved in the properties
0240      */
0241     qreal paintOpFlow();
0242 
0243     /**
0244      * @return fade saved in the properties
0245      */
0246     qreal paintOpFade();
0247 
0248     /**
0249      * @return scatter saved in the properties
0250      */
0251     qreal paintOpScatter();
0252 
0253     /**
0254      * @return composite mode saved in the properties
0255      */
0256     QString paintOpCompositeOp();
0257 
0258     /**
0259      * Set paintop size directly in the properties
0260      */
0261     virtual void setPaintOpSize(qreal value) = 0;
0262 
0263     /**
0264      * @return size saved in the properties
0265      */
0266     virtual qreal paintOpSize() const = 0;
0267 
0268     /**
0269      * Set paintop angle (in degrees) directly in the properties.
0270      * Increasing the angle corresponds to a counter-clockwise rotation.
0271      */
0272     virtual void setPaintOpAngle(qreal value) = 0;
0273 
0274     /**
0275      * @return paintop angle (in degrees) saved in the properties
0276      */
0277     virtual qreal paintOpAngle() const = 0;
0278 
0279     /**
0280      * @return pattern size saved in the properties
0281      */
0282     virtual qreal paintOpPatternSize();
0283 
0284     void setEraserMode(bool value);
0285     bool eraserMode();
0286 
0287     qreal savedEraserSize() const;
0288     void setSavedEraserSize(qreal value);
0289     qreal savedBrushSize() const;
0290     void setSavedBrushSize(qreal value);
0291 
0292     qreal savedEraserOpacity() const;
0293     void setSavedEraserOpacity(qreal value);
0294     qreal savedBrushOpacity() const;
0295     void setSavedBrushOpacity(qreal value);
0296 
0297     QString effectivePaintOpCompositeOp();
0298 
0299     void setUpdateListener(UpdateListenerWSP listener);
0300 
0301     UpdateListenerWSP updateListener() const;
0302 
0303     /**
0304      * @return filename of the 3D brush model, empty if no brush is set
0305      */
0306     virtual QString modelName() const;
0307 
0308     /**
0309     * Set filename of 3D brush model. By default no brush is set
0310     */
0311     void setModelName(const QString & modelName);
0312 
0313     /// Check if the settings are valid, setting might be invalid through missing brushes etc
0314     /// Overwrite if the settings of a paintop can be invalid
0315     /// @return state of the settings, default implementation is true
0316     virtual bool isValid() const;
0317 
0318     /**
0319      * Overrides the method in KisPropertiesConfiguration to allow
0320      * onPropertyChanged() callback
0321      */
0322     void setProperty(const QString & name, const QVariant & value) override;
0323 
0324     virtual QList<KisUniformPaintOpPropertySP> uniformProperties(KisPaintOpSettingsSP settings, QPointer<KisPaintOpPresetUpdateProxy> updateProxy);
0325 
0326     static bool isLodUserAllowed(const KisPropertiesConfigurationSP config);
0327     static void setLodUserAllowed(KisPropertiesConfigurationSP config, bool value);
0328 
0329     virtual bool lodSizeThresholdSupported() const;
0330 
0331     qreal lodSizeThreshold() const;
0332     void setLodSizeThreshold(qreal value);
0333 
0334     /**
0335      * This function is called to set random offsets to the brush whenever the mouse is clicked. It is
0336      * specific to when the pattern option is set.
0337      *
0338      */
0339     virtual void setRandomOffset(const KisPaintInformation &paintInformation);
0340 
0341     /**
0342      * @return true if this preset demands a secondary masked brush running
0343      *         alongside it
0344      */
0345     bool hasMaskingSettings() const;
0346 
0347     /**
0348      * @return a newly created settings object representing a preset of the masking
0349      *         brush that should be run alongside the current brush
0350      */
0351     KisPaintOpSettingsSP createMaskingSettings() const;
0352 
0353     /**
0354      * @return a composite op id of the masked brush rendering algorithm.
0355      *
0356      * Please take into account that the brush itself always paints in alpha-
0357      * darken mode, but the final result is combined with this composite op.
0358      */
0359     QString maskingBrushCompositeOp() const;
0360 
0361     /**
0362      * @return resource interface that is used for loading linked resources
0363      */
0364     KisResourcesInterfaceSP resourcesInterface() const;
0365 
0366     /**
0367      * Set resource interface that will be used for loading linked resources
0368      */
0369     void setResourcesInterface(KisResourcesInterfaceSP resourcesInterface);
0370 
0371 
0372     virtual bool hasPatternSettings() const;
0373 
0374     virtual QList<int> requiredCanvasResources() const;
0375 
0376     KoCanvasResourcesInterfaceSP canvasResourcesInterface() const;
0377     void setCanvasResourcesInterface(KoCanvasResourcesInterfaceSP canvasResourcesInterface);
0378 
0379     virtual void setResourceCacheInterface(KoResourceCacheInterfaceSP cacheInterface);
0380     KoResourceCacheInterfaceSP resourceCacheInterface() const;
0381 
0382     virtual void regenerateResourceCache(KoResourceCacheInterfaceSP cacheInterface);
0383 
0384     quint64 sanityVersionCookie() const;
0385 
0386 protected:
0387 
0388     /**
0389      * The callback is called every time when a property changes
0390      */
0391     virtual void onPropertyChanged();
0392 
0393 private:
0394 
0395 
0396 
0397     struct Private;
0398     const QScopedPointer<Private> d;
0399 };
0400 
0401 #endif