1 /*
2  *  Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
3  *  Copyright (c) 2011 Lukáš Tvrdý <lukast.dev@gmail.com>
4  *
5  *  This library is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU Lesser General Public License as published by
7  *  the Free Software Foundation; version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #ifndef _KIS_DYNAMIC_SENSOR_H_
21 #define _KIS_DYNAMIC_SENSOR_H_
22 
23 #include <kritapaintop_export.h>
24 
25 #include <QObject>
26 
27 #include <KoID.h>
28 
29 #include <klocalizedstring.h>
30 
31 #include "kis_serializable_configuration.h"
32 #include "kis_curve_label.h"
33 #include <kis_cubic_curve.h>
34 #include <kis_shared_ptr.h>
35 #include <kis_shared.h>
36 
37 
38 class QWidget;
39 class KisPaintInformation;
40 
41 const KoID FuzzyPerDabId("fuzzy", ki18nc("Context: dynamic sensors", "Fuzzy Dab")); ///< generate a random number
42 const KoID FuzzyPerStrokeId("fuzzystroke", ki18nc("Context: dynamic sensors", "Fuzzy Stroke")); ///< generate a random number
43 const KoID SpeedId("speed", ki18nc("Context: dynamic sensors", "Speed")); ///< generate a number depending on the speed of the cursor
44 const KoID FadeId("fade", ki18nc("Context: dynamic sensors", "Fade")); ///< generate a number that increase every time you call it (e.g. per dab)
45 const KoID DistanceId("distance", ki18nc("Context: dynamic sensors", "Distance")); ///< generate a number that increase with distance
46 const KoID TimeId("time", ki18nc("Context: dynamic sensors", "Time")); ///< generate a number that increase with time
47 const KoID DrawingAngleId("drawingangle", ki18nc("Context: dynamic sensors", "Drawing angle")); ///< number depending on the angle
48 const KoID RotationId("rotation", ki18nc("Context: dynamic sensors", "Rotation")); ///< rotation coming from the device
49 const KoID PressureId("pressure", ki18nc("Context: dynamic sensors", "Pressure")); ///< number depending on the pressure
50 const KoID PressureInId("pressurein", ki18nc("Context: dynamic sensors", "PressureIn")); ///< number depending on the pressure
51 const KoID XTiltId("xtilt", ki18nc("Context: dynamic sensors", "X-Tilt")); ///< number depending on X-tilt
52 const KoID YTiltId("ytilt", ki18nc("Context: dynamic sensors", "Y-Tilt")); ///< number depending on Y-tilt
53 
54 /**
55  * "TiltDirection" and "TiltElevation" parameters are written to
56  * preset files as "ascension" and "declination" to keep backward
57  * compatibility with older presets from the days when they were called
58  * differently.
59  */
60 const KoID TiltDirectionId("ascension", ki18nc("Context: dynamic sensors", "Tilt direction")); /// < number depending on the X and Y tilt, tilt direction is 0 when stylus nib points to you and changes clockwise from -180 to +180.
61 const KoID TiltElevationId("declination", ki18nc("Context: dynamic sensors", "Tilt elevation")); /// < tilt elevation is 90 when stylus is perpendicular to tablet and 0 when it's parallel to tablet
62 
63 const KoID PerspectiveId("perspective", ki18nc("Context: dynamic sensors", "Perspective")); ///< number depending on the distance on the perspective grid
64 const KoID TangentialPressureId("tangentialpressure", ki18nc("Context: dynamic sensors", "Tangential pressure")); ///< the wheel on an airbrush device
65 const KoID SensorsListId("sensorslist", "SHOULD NOT APPEAR IN THE UI !"); ///< this a non user-visible sensor that can store a list of other sensors, and multiply their output
66 
67 class KisDynamicSensor;
68 typedef KisSharedPtr<KisDynamicSensor> KisDynamicSensorSP;
69 
70 enum DynamicSensorType {
71     FUZZY_PER_DAB,
72     FUZZY_PER_STROKE,
73     SPEED,
74     FADE,
75     DISTANCE,
76     TIME,
77     ANGLE,
78     ROTATION,
79     PRESSURE,
80     XTILT,
81     YTILT,
82     TILT_DIRECTION,
83     TILT_ELEVATATION,
84     PERSPECTIVE,
85     TANGENTIAL_PRESSURE,
86     SENSORS_LIST,
87     PRESSURE_IN,
88     UNKNOWN = 255
89 };
90 
91 /**
92  * Sensors are used to extract from KisPaintInformation a single
93  * double value which can be used to control the parameters of
94  * a brush.
95  */
96 class PAINTOP_EXPORT KisDynamicSensor : public KisSerializableConfiguration
97 {
98 
99 public:
100     enum ParameterSign {
101         NegativeParameter = -1,
102         UnSignedParameter = 0,
103         PositiveParameter = 1
104     };
105 
106 protected:
107     KisDynamicSensor(DynamicSensorType type);
108 
109 public:
110 
111     ~KisDynamicSensor() override;
112 
113     /**
114      * @return the value of this sensor for the given KisPaintInformation
115      */
116     qreal parameter(const KisPaintInformation& info);
117     /**
118      * @return the value of this sensor for the given KisPaintInformation
119      * curve -- a custom, temporary curve that should be used instead of the one for the sensor
120      * customCurve -- if it's a new curve or not; should always be true if the function is called from outside
121      * (aka not in parameter(info) function)
122      */
123     qreal parameter(const KisPaintInformation& info, const KisCubicCurve curve, const bool customCurve);
124 
125     /**
126      * This function is call before beginning a stroke to reset the sensor.
127      * Default implementation does nothing.
128      */
129     virtual void reset();
130 
131     /**
132      * @param parent the parent QWidget
133      * @param selector is a \ref QWidget that contains a signal called "parametersChanged()"
134      */
135     virtual QWidget* createConfigurationWidget(QWidget* parent, QWidget* selector);
136 
137     /**
138      * Creates a sensor from its identifier.
139      */
140     static KisDynamicSensorSP id2Sensor(const KoID& id, const QString &parentOptionName);
id2Sensor(const QString & s,const QString & parentOptionName)141     static KisDynamicSensorSP id2Sensor(const QString& s, const QString &parentOptionName) {
142         return id2Sensor(KoID(s), parentOptionName);
143     }
144 
145     static DynamicSensorType id2Type(const KoID& id);
id2Type(const QString & s)146     static DynamicSensorType id2Type(const QString& s) {
147         return id2Type(KoID(s));
148     }
149 
150     /**
151      * type2Sensor creates a new sensor for the give type
152      */
153     static KisDynamicSensorSP type2Sensor(DynamicSensorType sensorType, const QString &parentOptionName);
154 
155     static QString minimumLabel(DynamicSensorType sensorType);
156     static QString maximumLabel(DynamicSensorType sensorType, int max = -1);
157     static int minimumValue(DynamicSensorType sensorType);
158     static int maximumValue(DynamicSensorType sensorType, int max = -1);
159     static QString valueSuffix(DynamicSensorType sensorType);
160 
161     static KisDynamicSensorSP createFromXML(const QString&, const QString &parentOptionName);
162     static KisDynamicSensorSP createFromXML(const QDomElement&, const QString &parentOptionName);
163 
164     /**
165      * @return the list of sensors
166      */
167     static QList<KoID> sensorsIds();
168     static QList<DynamicSensorType> sensorsTypes();
169 
170     /**
171      * @return the identifier of this sensor
172      */
173     static QString id(DynamicSensorType sensorType);
174 
175     using KisSerializableConfiguration::fromXML;
176     using KisSerializableConfiguration::toXML;
177 
178     void toXML(QDomDocument&, QDomElement&) const override;
179     void fromXML(const QDomElement&) override;
180 
181     void setCurve(const KisCubicCurve& curve);
182     const KisCubicCurve& curve() const;
183     void removeCurve();
184     bool hasCustomCurve() const;
185 
186     void setActive(bool active);
187     bool isActive() const;
188 
189     virtual bool dependsOnCanvasRotation() const;
190 
191     virtual bool isAdditive() const;
192     virtual bool isAbsoluteRotation() const;
193 
sensorType()194     inline DynamicSensorType sensorType() const { return m_type; }
195 
196 
197     /**
198      * @return the currently set length or -1 if not relevant
199      */
length()200     int length() { return m_length; }
201 
202 
203 public:
scalingToAdditive(qreal x)204     static inline qreal scalingToAdditive(qreal x) {
205         return -1.0 + 2.0 * x;
206     }
207 
additiveToScaling(qreal x)208     static inline qreal additiveToScaling(qreal x) {
209         return 0.5 * (1.0 + x);
210     }
211 
212 protected:
213 
214     virtual qreal value(const KisPaintInformation& info) = 0;
215 
216     int m_length;
217 
218 private:
219 
220     Q_DISABLE_COPY(KisDynamicSensor)
221 
222     DynamicSensorType m_type;
223     bool m_customCurve;
224     KisCubicCurve m_curve;
225     bool m_active;
226 
227 };
228 
229 #endif
230