1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8     begin                : Jan 2005
9     copyright            : (C) 2005 by Craig Bradney
10     email                : cbradney@zip.com.au
11  ***************************************************************************/
12 
13 /***************************************************************************
14  *                                                                         *
15  *   This program is free software; you can redistribute it and/or modify  *
16  *   it under the terms of the GNU General Public License as published by  *
17  *   the Free Software Foundation; either version 2 of the License, or     *
18  *   (at your option) any later version.                                   *
19  *                                                                         *
20  ***************************************************************************/
21 
22 #include <cmath>
23 #include <QLocale>
24 #include <QString>
25 #include <QObject>
26 #include "localemgr.h"
27 #include "scribuscore.h"
28 #include "units.h"
29 
30 /*!
31  * @brief Returns the ratio to points for the selected unit of measure. Ratios are for: PT, MM, IN, P, CM, C. DEG and PCT return 1.0 as they will never convert
32  */
unitGetRatioFromIndex(const int index)33 double unitGetRatioFromIndex(const int index)
34 {
35 	//PT, MM, IN, P, CM, C (Cicero)
36 	//NOTE: Calling functions that divide by this value will crash on divide by 0. They shouldn't be getting
37 	// a zero value if they are accessing here with a correct index.
38 	if (index<UNITMIN || index>UNITMAX)
39 		return 0;
40 	//                  PT,          MM,         IN,   P,           CM,           C,           °,   %
41 	double ratio[] = { 1.0, 25.4 / 72.0, 1.0 / 72.0, 1.0,  2.54 / 72.0, 25.4 / 72.0 / 4.512, 1.0, 1.0 };
42 	return ratio[index];
43 }
44 
unitGetBaseFromIndex(const int index)45 int SCRIBUS_API unitGetBaseFromIndex(const int index)
46 {
47 	if (index == SC_P)
48 		return 12;
49 	return 10;
50 }
51 
52 /*!
53  * @brief Strip the text from a value and return the double value for the unit
54  */
unitValueFromString(const QString & value)55 double unitValueFromString(const QString& value)
56 {
57 	QString lowerValue = value.toLower();
58 	QString dbl = "0.0";
59 	if (lowerValue.indexOf("pt") != -1)
60 	{
61 		dbl = lowerValue.remove("pt");
62 	}
63 	else if (lowerValue.indexOf("mm") != -1)
64 	{
65 		dbl = lowerValue.remove("mm");
66 	}
67 	else if (lowerValue.indexOf("in") != -1)
68 	{
69 		dbl = lowerValue.remove("in");
70 	}
71 	else if (lowerValue.indexOf("p") != -1)
72 	{
73 		dbl = lowerValue.remove("p");
74 	}
75 	else if (lowerValue.indexOf("cm") != -1)
76 	{
77 		dbl = lowerValue.remove("cm");
78 	}
79 	else if (lowerValue.indexOf("°") != -1)
80 	{
81 		dbl = lowerValue.remove("°");
82 	}
83 	else if (lowerValue.indexOf("%") != -1)
84 	{
85 		dbl = lowerValue.remove("%");
86 	}
87 	else
88 		dbl = "0.0";
89 
90 	dbl = dbl.trimmed();
91 	return dbl.toDouble();
92 }
93 
94 /*!
95  * @brief Strip the text from a value and return the Unit index for the value
96  */
unitIndexFromString(const QString & value)97 scUnit unitIndexFromString(const QString& value)
98 {
99 	QString lowerValue = value.toLower();
100 	scUnit retVal;
101 	if (lowerValue.indexOf("pt") != -1)
102 	{
103 		retVal = SC_PT;
104 	}
105 	else if (lowerValue.indexOf("mm") != -1)
106 	{
107 		retVal = SC_MM;
108 	}
109 	else if (lowerValue.indexOf("in") != -1)
110 	{
111 		retVal = SC_IN;
112 	}
113 	else if (lowerValue.indexOf("p") != -1)
114 	{
115 		retVal = SC_P;
116 	}
117 	else if (lowerValue.indexOf("cm") != -1)
118 	{
119 		retVal = SC_CM;
120 	}
121 	else if (lowerValue.indexOf("c") != -1)
122 	{
123 		retVal = SC_C;
124 	}
125 	else if (lowerValue.indexOf("°") != -1)
126 	{
127 		retVal = SC_DEGREES;
128 	}
129 	else if (lowerValue.indexOf("%") != -1)
130 	{
131 		retVal = SC_PERCENT;
132 	}
133 	else
134 		retVal = SC_PT;
135 	return retVal;
136 }
137 
138 /*!
139  * @brief Returns the suffix used in GUI widgets
140  */
unitGetSuffixFromIndex(const int index)141 QString unitGetSuffixFromIndex(const int index)
142 {
143 	if (index == SC_P)
144 		return QString();
145 	return QString(" %1").arg(unitGetStrFromIndex(index));
146 }
147 
148 /*!
149  * @brief Returns a general suffix for each of the units
150  */
unitGetStrFromIndex(const int index)151 QString unitGetStrFromIndex(const int index)
152 {
153 	if (index < UNITMIN || index > UNITMAX)
154 		return QString();
155 	QString suffix[] = {
156 						QObject::tr("pt"),
157 						QObject::tr("mm"),
158 						QObject::tr("in"),
159 						QObject::tr("p"),
160 						QObject::tr("cm"),
161 						QObject::tr("c"),
162 						QObject::tr("\302\260", "degrees, unicode 0xB0"), //degree
163 						QObject::tr("%")
164 						};
165 	return suffix[index];
166 }
167 
168 /*!
169  * @brief Returns a general untranslated suffix for each of the units
170  */
unitGetUntranslatedStrFromIndex(const int index)171 QString unitGetUntranslatedStrFromIndex(const int index)
172 {
173 	if (index < UNITMIN || index > UNITMAX)
174 		return QString();
175 	QString suffix[] = { "pt", "mm", "in", "p", "cm", "c", "\xB0", "%" };
176 	return suffix[index];
177 }
178 /*!
179  * @brief Returns the decimals for the units
180  */
unitGetDecimalsFromIndex(const int index)181 int unitGetDecimalsFromIndex(const int index)
182 {
183 	if (index < UNITMIN || index > UNITMAX)
184 		return 0;
185 	//                      PT,   MM,    IN,   P,    CM,     C,   °,   %
186 	int decimalPoints[] = {100, 1000, 10000, 100, 10000, 10000, 100, 100};
187 	return decimalPoints[index];
188 }
189 
190 /*!
191  * @brief Returns the precision for the units
192  */
unitGetPrecisionFromIndex(const int index)193 int unitGetPrecisionFromIndex(const int index)
194 {
195 	if (index < UNITMIN || index > UNITMAX)
196 		return 0;
197 	//                PT,MM,IN, P,CM, C, °, %
198 	int precision[] = {2, 3, 4, 2, 4, 4, 2, 2};
199 	return precision[index];
200 }
201 
202 /*!
203  * @brief Returns a QStringList of the units for use in QComboBoxes etc
204  */
unitGetTextUnitList()205 QStringList unitGetTextUnitList()
206 {
207 	QStringList suffixList;
208 	suffixList.append( QObject::tr( "Points (pt)" ) );
209 	suffixList.append( QObject::tr( "Millimeters (mm)" ) );
210 	suffixList.append( QObject::tr( "Inches (in)" ) );
211 	suffixList.append( QObject::tr( "Picas (p)" ) );
212 	suffixList.append( QObject::tr( "Centimeters (cm)" ) );
213 	suffixList.append( QObject::tr( "Cicero (c)" ) );
214 	//Here for completeness, don't use!
215 	//suffixList.append( QObject::tr( "°" ) );
216 	//suffixList.append( QObject::tr( "%" ) );
217 	return QStringList(suffixList);
218 }
219 
220 /*!
221  * @brief Returns the maximum index of the units we have now
222  */
unitGetMaxIndex()223 int unitGetMaxIndex()
224 {
225 	return UNITMAX;
226 }
227 
228 /*!
229  * @brief Returns the pts value from the mm value supplied
230  */
mm2pts(double mm)231 double mm2pts(double mm)
232 {
233 	return mm / unitGetRatioFromIndex(SC_MM);
234 }
235 
236 /*!
237  * @brief Returns the pts value from the in value supplied
238  */
in2pts(double in)239 double in2pts(double in)
240 {
241 	return in / unitGetRatioFromIndex(SC_IN);
242 }
243 
244 /*!
245  * @brief Returns the pts value from the pica value supplied
246  */
p2pts(double p)247 double p2pts(double p)
248 {
249 	return p / unitGetRatioFromIndex(SC_P);
250 }
251 
252 /*!
253  * @brief Returns the pts value from the cm value supplied
254  */
cm2pts(double cm)255 double cm2pts(double cm)
256 {
257 	return cm / unitGetRatioFromIndex(SC_CM);
258 }
259 
260 /*!
261  * @brief Returns the pts value from the cm value supplied
262  */
c2pts(double c)263 double c2pts(double c)
264 {
265 	return c / unitGetRatioFromIndex(SC_C);
266 }
267 
268 /*!
269  * @brief Returns the mm value from the pt value supplied
270  */
pts2mm(double pts)271 double pts2mm(double pts)
272 {
273 	return pts * unitGetRatioFromIndex(SC_MM);
274 }
275 
276 /*!
277  * @brief Returns the in value from the pt value supplied
278  */
pts2in(double pts)279 double pts2in(double pts)
280 {
281 	return pts * unitGetRatioFromIndex(SC_IN);
282 }
283 
284 /*!
285  * @brief Returns the pica value from the pt value supplied
286  */
pts2p(double pts)287 double pts2p(double pts)
288 {
289 	return pts * unitGetRatioFromIndex(SC_P);
290 }
291 
292 /*!
293  * @brief Returns the cm value from the pt value supplied
294  */
pts2cm(double pts)295 double pts2cm(double pts)
296 {
297 	return pts * unitGetRatioFromIndex(SC_CM);
298 }
299 
300 /*!
301  * @brief Returns the c value from the pt value supplied
302  */
pts2c(double pts)303 double pts2c(double pts)
304 {
305 	return pts * unitGetRatioFromIndex(SC_C);
306 }
307 
308 /*!
309  * @brief Returns the value from the pt value supplied based on unit index
310  */
pts2value(double unitValue,int unit)311 double pts2value(double unitValue, int unit)
312 {
313 	double ret = 0.0;
314 	switch (unit)
315 	{
316 		case SC_PT:
317 		case SC_P:
318 		case SC_DEG:
319 		case SC_PCT:
320 			ret = unitValue; //don't multiply by 1
321 			break;
322 		default:
323 			ret = unitValue * unitGetRatioFromIndex(unit);
324 			break;
325 	}
326 	return ret;
327 }
328 
329 /*!
330  * @brief Returns the pt value from the value supplied based on unit index
331  */
value2pts(double unitValue,int unit)332 double value2pts(double unitValue, int unit)
333 {
334 	double ret = 0.0;
335 	switch (unit)
336 	{
337 		case SC_PT:
338 		case SC_P:
339 		case SC_DEG:
340 		case SC_PCT:
341 			ret = unitValue; // don't divide by 1
342 			break;
343 		default:
344 			ret = unitValue / unitGetRatioFromIndex(unit);
345 			break;
346 	}
347 	return ret;
348 }
349 
350 /*!
351  * @brief Returns the secondary unit value from the value supplied based on primary unit
352  */
value2value(double unitValue,int primaryUnit,int secondaryUnit)353 double value2value(double unitValue, int primaryUnit, int secondaryUnit)
354 {
355 	if (primaryUnit==secondaryUnit)
356 		return unitValue;
357 
358 	//Can make this not convert to points at a later stage, for now, the function exists and works.
359 	double pts = primaryUnit == 0 ? unitValue : unitValue / unitGetRatioFromIndex(primaryUnit);
360 	double ret = secondaryUnit == 0 ? pts : pts * unitGetRatioFromIndex(secondaryUnit);
361 	return ret;
362 }
363 
value2String(double unitValue,int unitIndex,bool round2Precision,bool appendSuffix)364 QString value2String(double unitValue, int unitIndex, bool round2Precision, bool appendSuffix)
365 {
366 	QString s;
367 
368 	if (unitIndex == SC_PICAS)
369 	{
370 		int i = (static_cast<int>(unitValue))/12;
371 		double d = fabs(fmod(unitValue, 12));
372 		QString prefix((i == 0 && unitValue < 0.0) ? "-" : "");
373 		s=QString("%1%2%3%4").arg(prefix).arg(i).arg(unitGetStrFromIndex(unitIndex)).arg(d);
374 	}
375 	else
376 	{
377 		if (round2Precision)
378 			s=LocaleManager::instance().userPreferredLocale().toString(pts2value(unitValue, unitIndex), 'f', unitGetPrecisionFromIndex(unitIndex));
379 		else
380 			s=LocaleManager::instance().userPreferredLocale().toString(pts2value(unitValue, unitIndex));
381 		if (appendSuffix)
382 			s += " " + unitGetStrFromIndex(unitIndex);
383 	}
384 	return s;
385 }
386 
387 /*!
388  * @brief Sets up iteration value 1 for vruler, hruler and tabruler
389  */
unitRulerGetIter1FromIndex(const int index)390 double unitRulerGetIter1FromIndex(const int index)
391 {
392 	if (!unitValidForDocUnit(index))
393 		return 0;
394 	//                 PT,           MM,   IN,    P,          CM,                   C,    °,    %
395 	double iter[] = {10.0, 720.0 / 25.4, 18.0, 12.0, 72.0 / 25.4, 72.0 / 25.4 * 4.512, 10.0, 10.0};
396 	return iter[index];
397 }
398 
399 /*!
400  * @brief Sets up iteration value 2 for vruler, hruler and tabruler
401  */
unitRulerGetIter2FromIndex(const int index)402 double unitRulerGetIter2FromIndex(const int index)
403 {
404 	if (!unitValidForDocUnit(index))
405 		return 0;
406 	//                  PT,            MM,   IN,     P,           CM,                    C,     °,     %
407 	double iter[] = {100.0, 7200.0 / 25.4, 72.0, 120.0, 720.0 / 25.4, 720.0 / 25.4 * 4.512, 100.0, 100.0};
408 	return iter[index];
409 }
410 
unitValidForDocUnit(const int index)411 bool unitValidForDocUnit(const int index)
412 {
413 	if (index < UNITMIN || index > UNITMAX)
414 		return false;
415 	if (index == SC_DEGREES || index == SC_PERCENT)
416 		return false;
417 	return true;
418 }
419