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