1 /* This file is part of the KDE project
2    Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
3    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4    Copyright (C) 2004, Nicolas GOUTTE <goutte@kde.org>
5    Copyright (C) 2010 Thomas Zander <zander@kde.org>
6    Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
7 
8    This library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Library General Public
10    License as published by the Free Software Foundation; either
11    version 2 of the License, or (at your option) any later version.
12 
13    This library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Library General Public License for more details.
17 
18    You should have received a copy of the GNU Library General Public License
19    along with this library; see the file COPYING.LIB.  If not, write to
20    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22 */
23 
24 #ifndef KOUNIT_H
25 #define KOUNIT_H
26 
27 // Calligra
28 #include "koodf_export.h"
29 // Qt
30 #include <QString>
31 #include <QDebug>
32 #include <QMetaType>
33 // std
34 #include <math.h> // for floor
35 
36 class QStringList;
37 
38 // 1 inch ^= 72 pt
39 // 1 inch ^= 25.399956 mm (-pedantic ;p)
40 // 1 pt = 1/12 pi
41 // 1 pt ^= 0.0077880997 cc
42 // 1 cc = 12 dd
43 // Note: I don't use division but multiplication with the inverse value
44 // because it's faster ;p (Werner)
45 #define POINT_TO_MM(px) qreal((px)*0.352777167)
46 #define MM_TO_POINT(mm) qreal((mm)*2.83465058)
47 #define POINT_TO_CM(px) qreal((px)*0.0352777167)
48 #define CM_TO_POINT(cm) qreal((cm)*28.3465058)
49 #define POINT_TO_DM(px) qreal((px)*0.00352777167)
50 #define DM_TO_POINT(dm) qreal((dm)*283.465058)
51 #define POINT_TO_INCH(px) qreal((px)*0.01388888888889)
52 #define INCH_TO_POINT(inch) qreal((inch)*72.0)
53 #define MM_TO_INCH(mm) qreal((mm)*0.039370147)
54 #define INCH_TO_MM(inch) qreal((inch)*25.399956)
55 #define POINT_TO_PI(px) qreal((px)*0.083333333)
56 #define POINT_TO_CC(px) qreal((px)*0.077880997)
57 #define PI_TO_POINT(pi) qreal((pi)*12)
58 #define CC_TO_POINT(cc) qreal((cc)*12.840103)
59 /**
60  * %Calligra stores everything in pt (using "qreal") internally.
61  * When displaying a value to the user, the value is converted to the user's unit
62  * of choice, and rounded to a reasonable precision to avoid 0.999999
63  *
64  * For implementing the selection of a unit type in the UI use the *ForUi() methods.
65  * They ensure the same order of the unit types in all places, with the order not
66  * bound to the order in the enum (so ABI-compatible extension is possible) and
67  * with the order and scope of listed types controlled by the @c ListOptions parameter.
68  */
69 class KOODF_EXPORT KoUnit
70 {
71 public:
72     /** Length units supported by Calligra. */
73     enum Type {
74         Millimeter = 0,
75         Point,  ///< Postscript point, 1/72th of an Inco
76         Inch,
77         Centimeter,
78         Decimeter,
79         Pica,
80         Cicero,
81         Pixel,
82         TypeCount ///< @internal
83     };
84 
85     /// Used to control the scope of the unit types listed in the UI
86     enum ListOption {
87         ListAll = 0,
88         HidePixel = 1,
89         HideMask = HidePixel
90     };
91      Q_DECLARE_FLAGS(ListOptions, ListOption)
92 
93     /** Returns a KoUnit instance with the type at the @p index of the UI list with the given @p listOptions. */
94     static KoUnit fromListForUi(int index, ListOptions listOptions = ListAll, qreal factor = 1.0);
95 
96     /// Convert a unit symbol string into a KoUnit
97     /// @param symbol symbol to convert
98     /// @param ok if set, it will be true if the unit was known, false if unknown
99     static KoUnit fromSymbol(const QString &symbol, bool *ok = 0);
100 
101     /** Construction requires initialization. The factor is for variable factor units like pixel */
102     explicit KoUnit(Type unit = Point, qreal factor = 1.0) {
103         m_type = unit;
104         m_pixelConversion = factor;
105     }
106 
107     KoUnit& operator=(Type unit) {
108         m_type = unit; m_pixelConversion = 1.0; return *this;
109     }
110 
111     bool operator!=(const KoUnit &other) const {
112         return !operator==(other);
113     }
114 
115     bool operator==(const KoUnit &other) const {
116         return m_type == other.m_type &&
117             (m_type != Pixel ||
118              qFuzzyCompare(m_pixelConversion, other.m_pixelConversion));
119     }
120 
type()121     KoUnit::Type type() const {
122         return m_type;
123     }
124 
setFactor(qreal factor)125     void setFactor(qreal factor) {
126         m_pixelConversion = factor;
127     }
128     /**
129      * Prepare ptValue to be displayed in pt
130      * This method will round to 0.001 precision
131      */
toPoint(qreal ptValue)132     static qreal toPoint(qreal ptValue) {
133         // No conversion, only rounding (to 0.001 precision)
134         return floor(ptValue * 1000.0) / 1000.0;
135     }
136 
137     /**
138      * Prepare ptValue to be displayed in mm
139      * This method will round to 0.0001 precision, use POINT_TO_MM() for lossless conversion.
140      */
toMillimeter(qreal ptValue)141     static qreal toMillimeter(qreal ptValue) {
142         // "mm" values are rounded to 0.0001 millimeters
143         return floor(POINT_TO_MM(ptValue) * 10000.0) / 10000.0;
144     }
145 
146     /**
147      * Prepare ptValue to be displayed in cm
148      * This method will round to 0.0001 precision, use POINT_TO_CM() for lossless conversion.
149      */
toCentimeter(qreal ptValue)150     static qreal toCentimeter(qreal ptValue) {
151         return floor(POINT_TO_CM(ptValue) * 10000.0) / 10000.0;
152     }
153 
154     /**
155      * Prepare ptValue to be displayed in dm
156      * This method will round to 0.0001 precision, use POINT_TO_DM() for lossless conversion.
157      */
toDecimeter(qreal ptValue)158     static qreal toDecimeter(qreal ptValue) {
159         return floor(POINT_TO_DM(ptValue) * 10000.0) / 10000.0;
160     }
161 
162     /**
163      * Prepare ptValue to be displayed in inch
164      * This method will round to 0.00001 precision, use POINT_TO_INCH() for lossless conversion.
165      */
toInch(qreal ptValue)166     static qreal toInch(qreal ptValue) {
167         // "in" values are rounded to 0.00001 inches
168         return floor(POINT_TO_INCH(ptValue) * 100000.0) / 100000.0;
169     }
170 
171     /**
172      * Prepare ptValue to be displayed in pica
173      * This method will round to 0.00001 precision, use POINT_TO_PI() for lossless conversion.
174      */
toPica(qreal ptValue)175     static qreal toPica(qreal ptValue) {
176         // "pi" values are rounded to 0.00001 inches
177         return floor(POINT_TO_PI(ptValue) * 100000.0) / 100000.0;
178     }
179 
180     /**
181      * Prepare ptValue to be displayed in cicero
182      * This method will round to 0.00001 precision, use POINT_TO_CC() for lossless conversion.
183      */
toCicero(qreal ptValue)184     static qreal toCicero(qreal ptValue) {
185         // "cc" values are rounded to 0.00001 inches
186         return floor(POINT_TO_CC(ptValue) * 100000.0) / 100000.0;
187     }
188 
189     /**
190      * convert the given value directly from one unit to another
191      */
192     static qreal convertFromUnitToUnit(const qreal value, const KoUnit &fromUnit, const KoUnit &toUnit, qreal factor = 1.0);
193 
194 
195     /**
196      * This method is the one to use to display a value in a dialog
197      * \return the value @p ptValue converted to unit and rounded, ready to be displayed
198      */
199     qreal toUserValue(qreal ptValue) const;
200 
201     /**
202      * Convert the value @p ptValue to a given unit @p unit
203      * Unlike KoUnit::ptToUnit the return value remains unrounded, so that it can be used in complex calculation
204      * \return the converted value
205      */
206     static qreal ptToUnit(const qreal ptValue, const KoUnit &unit);
207 
208     /// This method is the one to use to display a value in a dialog
209     /// @return the value @p ptValue converted the unit and rounded, ready to be displayed
210     QString toUserStringValue(qreal ptValue) const;
211 
212     /// This method is the one to use to read a value from a dialog
213     /// @return the value converted to points for internal use
214     qreal fromUserValue(qreal value) const;
215 
216     /// This method is the one to use to read a value from a dialog
217     /// @param value value entered by the user
218     /// @param ok if set, the pointed bool is set to true if the value could be
219     /// converted to a qreal, and to false otherwise.
220     /// @return the value converted to points for internal use
221     qreal fromUserValue(const QString &value, bool *ok = 0) const;
222 
223     /// Get the description string of the given unit
224     static QString unitDescription(KoUnit::Type type);
225 
226     /// Get the symbol string of the unit
227     QString symbol() const;
228 
229     /// Returns the list of unit types for the UI, controlled with the given @p listOptions.
230     static QStringList listOfUnitNameForUi(ListOptions listOptions = ListAll);
231 
232     /// Get the index of this unit in the list of unit types for the UI,
233     /// if it is controlled with the given @p listOptions.
234     int indexInListForUi(ListOptions listOptions = ListAll) const;
235 
236     /// parse common %Calligra and Odf values, like "10cm", "5mm" to pt
237     static qreal parseValue(const QString &value, qreal defaultVal = 0.0);
238 
239     /// parse an angle to its value in degrees
240     static qreal parseAngle(const QString &value, qreal defaultVal = 0.0);
241 
toString()242     QString toString() const {
243         return symbol();
244     }
245 
246     /**
247      * Get an approximate scale of a unit vector that was converted by
248      * the transformation.
249      *
250      * Please note that exact values are guaranteed only for
251      * combinations of Translate, Rotation and Uniform Scale
252      * matrices. For combinations having shears and perspective the
253      * value will be average for the point near CS origin.
254      */
255     static qreal approxTransformScale(const QTransform &t);
256 
257     /**
258      * Adjust the unit by pixel transformation applied to the
259      * describing object. It multiplies the pixel coefficient by the
260      * average scale of the matrix.
261      */
262     void adjustByPixelTransform(const QTransform &t);
263 
264 private:
265     Type m_type;
266     qreal m_pixelConversion;
267 };
268 
269 #ifndef QT_NO_DEBUG_STREAM
270 KOODF_EXPORT QDebug operator<<(QDebug, const KoUnit &);
271 #endif
272 
273 Q_DECLARE_METATYPE(KoUnit)
274 Q_DECLARE_OPERATORS_FOR_FLAGS(KoUnit::ListOptions)
275 
276 #endif
277