1 /*
2  *  Copyright (c) 2007 Boudewijn Rempt <boud@valdyas.org>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #ifndef KIS_PAINTOP_SETTINGS_H_
20 #define KIS_PAINTOP_SETTINGS_H_
21 
22 #include "kis_types.h"
23 #include "kritaimage_export.h"
24 
25 #include <QImage>
26 #include <QScopedPointer>
27 
28 #include "kis_properties_configuration.h"
29 #include <brushengine/kis_paint_information.h>
30 #include <brushengine/kis_uniform_paintop_property.h>
31 
32 
33 
34 class KisPaintOpConfigWidget;
35 class KisPaintopSettingsUpdateProxy;
36 
37 /**
38  * Configuration property used to control whether airbrushing is enabled.
39  */
40 const QString AIRBRUSH_ENABLED = "PaintOpSettings/isAirbrushing";
41 
42 /**
43  * Configuration property used to control airbrushing rate. The value should be in dabs per second.
44  */
45 const QString AIRBRUSH_RATE = "PaintOpSettings/rate";
46 
47 /**
48  * Configuration property used to control whether airbrushing is configured to ignore distance-based
49  * spacing.
50  */
51 const QString AIRBRUSH_IGNORE_SPACING = "PaintOpSettings/ignoreSpacing";
52 
53 /**
54  * Configuration property used to control whether the spacing settings can be updated between
55  * painted dabs.
56  */
57 const QString SPACING_USE_UPDATES = "PaintOpSettings/updateSpacingBetweenDabs";
58 
59 /**
60  * This class is used to cache the settings for a paintop
61  * between two creations. There is one KisPaintOpSettings per input device (mouse, tablet,
62  * etc...).
63  *
64  * The settings may be stored in a preset. Note that if your
65  * paintop's settings subclass has data that is not stored as a property, that data is not
66  * saved and restored.
67  *
68  * The object also contains a pointer to its parent KisPaintOpPreset object.This is to control the DirtyPreset
69  * property of KisPaintOpPreset. Whenever the settings are changed/modified from the original -- the preset is
70  * set to dirty.
71  */
72 class KRITAIMAGE_EXPORT KisPaintOpSettings : public KisPropertiesConfiguration
73 {
74 
75 public:
76 
77     KisPaintOpSettings();
78     ~KisPaintOpSettings() override;
79     KisPaintOpSettings(const KisPaintOpSettings &rhs);
80 
81     /**
82      *
83      */
84     void setOptionsWidget(KisPaintOpConfigWidget* widget);
85 
86     /**
87      * This function is called by a tool when the mouse is pressed. It's useful if
88      * the paintop needs mouse interaction for instance in the case of the clone op.
89      * If the tool is supposed to ignore the event, the paint op should return true
90      * and if the tool is supposed to use the event, return false.
91      * See kis_tool_freehand:tryPickByPaintOp()
92      */
93     virtual bool mousePressEvent(const KisPaintInformation &paintInformation, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode);
94     /**
95      * This function is called by a tool when the mouse is released. It's useful if
96      * the paintop needs mouse interaction for instance in the case of the clone op.
97      * If the tool is supposed to ignore the event, the paint op should return true
98      * and if the tool is supposed to use the event, return false.
99      */
100     virtual bool mouseReleaseEvent();
101     /**
102      * Clone the current settings object. Override this if your settings instance doesn't
103      * store everything as properties.
104      */
105     virtual KisPaintOpSettingsSP clone() const;
106 
107     /**
108      * Removes all the settings from the object while keeping the paintop id,
109      * which is loaded to the object by the factory
110      */
111     void resetSettings(const QStringList &preserveProperties = QStringList());
112 
113     /**
114      * @return the node the paintop is working on.
115      */
116     KisNodeSP node() const;
117 
118     /**
119      * Call this function when the paint op is selected or the tool is activated
120      */
121     virtual void activate();
122 
123     /**
124      * XXX: Remove this after 2.0, when the paint operation (incremental/non incremental) will
125      *      be completely handled in the paintop, not in the tool. This is a filthy hack to move
126      *      the option to the right place, at least.
127      * @return true if we paint incrementally, false if we paint like Photoshop. By default, paintops
128      *      do not support non-incremental.
129      */
paintIncremental()130     virtual bool paintIncremental() {
131         return true;
132     }
133 
134     /**
135      * @return the composite op it to which the indirect painting device
136      * should be initialized to. This is used by clone op to reset
137      * the composite op to COMPOSITE_COPY
138      */
139     virtual QString indirectPaintingCompositeOp() const;
140 
141     /**
142      * Whether this paintop wants to deposit paint even when not moving, i.e. the tool needs to
143      * activate its timer. If this is true, painting updates need to be generated at regular
144      * intervals even in the absence of input device events, e.g. when the cursor is not moving.
145      *
146      * The default implementation checks the property AIRBRUSH_ENABLED, defaulting to false if the
147      * property is not found. This should be suitable for most paintops.
148      */
149     virtual bool isAirbrushing() const;
150 
151     /**
152      * Indicates the minimum time interval that might be needed between airbrush dabs, in
153      * milliseconds. A lower value means painting updates need to happen more frequently. This value
154      * should be ignored if isAirbrushing() is false.
155      *
156      * The default implementation uses the property AIRBRUSH_RATE, defaulting to an interval of
157      * one second if the property is not found. This should be suitable for most paintops.
158      */
159     virtual qreal airbrushInterval() const;
160 
161     /**
162      * Indicates whether this configuration allows spacing information to be updated between painted
163      * dabs during a stroke.
164      */
165     virtual bool useSpacingUpdates() const;
166 
167     /**
168      * Indicates if the tool should call paintOp->doAsynchronousUpdate() inbetween
169      * paintAt() calls to do the asynchronous rendering
170      */
171     virtual bool needsAsynchronousUpdates() const;
172 
173     /**
174      * This structure defines the current mode for painting an outline.
175      */
176     struct OutlineMode {
177         bool isVisible = false;
178         bool forceCircle = false;
179         bool showTiltDecoration = false;
180         bool forceFullSize = false;
181     };
182 
183     /**
184      * Returns the brush outline in pixel coordinates. Tool is responsible for conversion into view coordinates.
185      * Outline mode has to be passed to the paintop which builds the outline as some paintops have to paint outline
186      * always like clone paintop indicating the duplicate position
187      */
188     virtual QPainterPath brushOutline(const KisPaintInformation &info, const OutlineMode &mode, qreal alignForZoom);
189 
190     /**
191     * Helpers for drawing the brush outline
192     */
193     static QPainterPath ellipseOutline(qreal width, qreal height, qreal scale, qreal rotation);
194 
195     /**
196      * Helper for drawing a triangle representing the tilt of the stylus.
197      *
198      * @param start is the offset from the brush's outline's bounding box
199      * @param lengthScale is used for deciding the size of the triangle.
200      * Brush diameter or width are common choices for this.
201      * @param angle is the angle between the two sides of the triangle.
202      */
203     static QPainterPath makeTiltIndicator(KisPaintInformation const& info,
204         QPointF const& start, qreal lengthScale, qreal angle);
205 
206     /**
207      * Set paintop opacity directly in the properties
208      */
209     void setPaintOpOpacity(qreal value);
210 
211     /**
212      * Set paintop flow directly in the properties
213      */
214     void setPaintOpFlow(qreal value);
215 
216     /**
217      * Set paintop composite mode directly in the properties
218      */
219     void setPaintOpCompositeOp(const QString &value);
220 
221     /**
222      * @return opacity saved in the properties
223      */
224     qreal paintOpOpacity();
225 
226     /**
227      * @return flow saved in the properties
228      */
229     qreal paintOpFlow();
230 
231     /**
232      * @return composite mode saved in the properties
233      */
234     QString paintOpCompositeOp();
235 
236     /**
237      * Set paintop size directly in the properties
238      */
239     virtual void setPaintOpSize(qreal value) = 0;
240 
241     /**
242      * @return size saved in the properties
243      */
244     virtual qreal paintOpSize() const = 0;
245 
246     /**
247      * @return pattern size saved in the properties
248      */
249     virtual qreal paintOpPatternSize();
250 
251     void setEraserMode(bool value);
252     bool eraserMode();
253 
254     qreal savedEraserSize() const;
255     void setSavedEraserSize(qreal value);
256     qreal savedBrushSize() const;
257     void setSavedBrushSize(qreal value);
258 
259     qreal savedEraserOpacity() const;
260     void setSavedEraserOpacity(qreal value);
261     qreal savedBrushOpacity() const;
262     void setSavedBrushOpacity(qreal value);
263 
264     QString effectivePaintOpCompositeOp();
265 
266     void setPreset(KisPaintOpPresetWSP preset);
267 
268     KisPaintOpPresetWSP preset() const;
269 
270     /**
271      * @return filename of the 3D brush model, empty if no brush is set
272      */
273     virtual QString modelName() const;
274 
275     /**
276     * Set filename of 3D brush model. By default no brush is set
277     */
278     void setModelName(const QString & modelName);
279 
280     /// Check if the settings are valid, setting might be invalid through missing brushes etc
281     /// Overwrite if the settings of a paintop can be invalid
282     /// @return state of the settings, default implementation is true
283     virtual bool isValid() const;
284 
285     /// Check if the settings are loadable, that might the case if we can fallback to something
286     /// Overwrite if the settings can do some kind of fallback
287     /// @return loadable state of the settings, by default implementation return the same as isValid()
288     virtual bool isLoadable();
289 
290     /**
291      * Overrides the method in KisPropertiesCofiguration to allow
292      * onPropertyChanged() callback
293      */
294     void setProperty(const QString & name, const QVariant & value) override;
295 
296     virtual QList<KisUniformPaintOpPropertySP> uniformProperties(KisPaintOpSettingsSP settings);
297 
298     static bool isLodUserAllowed(const KisPropertiesConfigurationSP config);
299     static void setLodUserAllowed(KisPropertiesConfigurationSP config, bool value);
300 
301     virtual bool lodSizeThresholdSupported() const;
302 
303     qreal lodSizeThreshold() const;
304     void setLodSizeThreshold(qreal value);
305 
306     /**
307     * @return the option widget of the paintop (can be 0 is no option widgets is set)
308     */
309     KisPaintOpConfigWidget* optionsWidget() const;
310 
311 
312     /**
313      * This function is called to set random offsets to the brush whenever the mouse is clicked. It is
314      * specific to when the pattern option is set.
315      *
316      */
317     virtual void setRandomOffset(const KisPaintInformation &paintInformation);
318 
319     /**
320      * @return true if this preset demands a secondary masked brush running
321      *         alongside it
322      */
323     bool hasMaskingSettings() const;
324 
325     /**
326      * @return a newly created settings object representing a preset of the masking
327      *         brush that should be run alongside the current brush
328      */
329     KisPaintOpSettingsSP createMaskingSettings() const;
330 
331     /**
332      * @return a composite op id of the masked brush rendering algorithm.
333      *
334      * Please take into account that the brush itself always paints in alpha-
335      * darken mode, but the final result is combined with this composite op.
336      */
337     QString maskingBrushCompositeOp() const;
338 
339     virtual bool hasPatternSettings() const;
340 
341 protected:
342 
343     /**
344      * The callback is called every time when a property changes
345      */
346     virtual void onPropertyChanged();
347 
348 private:
349 
350 
351 
352     struct Private;
353     const QScopedPointer<Private> d;
354 };
355 
356 #endif
357