xref: /core/svtools/source/misc/unitconv.cxx (revision ec11b733)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <svtools/unitconv.hxx>
21 #include <tools/debug.hxx>
22 #include <vcl/outdev.hxx>
23 #include <vcl/weld.hxx>
24 
25 void SetFieldUnit(weld::MetricSpinButton& rField, FieldUnit eUnit, bool bAll)
26 {
27     int nMin, nMax;
28     rField.get_range(nMin, nMax, FieldUnit::TWIP);
29     int nValue = rField.get_value(FieldUnit::TWIP);
30     nMin = rField.denormalize(nMin);
31     nMax = rField.denormalize(nMax);
32     nValue = rField.denormalize(nValue);
33 
34     if (!bAll)
35     {
36         switch (eUnit)
37         {
38             case FieldUnit::M:
39             case FieldUnit::KM:
40                 eUnit = FieldUnit::CM;
41                 break;
42             case FieldUnit::FOOT:
43             case FieldUnit::MILE:
44                 eUnit = FieldUnit::INCH;
45                 break;
46             default: //prevent warning
47                 break;
48         }
49     }
50 
51     rField.set_unit(eUnit);
52 
53     if (FieldUnit::POINT == eUnit)
54     {
55         if (rField.get_digits() > 1)
56             rField.set_digits(1);
57     }
58     else
59         rField.set_digits(2);
60 
61     switch (eUnit)
62     {
63         // _CHAR and _LINE sets the step of "char" and "line" unit, they are same as FieldUnit::MM
64         case FieldUnit::CHAR:
65         case FieldUnit::LINE:
66         case FieldUnit::MM:
67             rField.set_increments(50, 500, eUnit);
68             break;
69         case FieldUnit::INCH:
70             rField.set_increments(2, 20, eUnit);
71             break;
72         default:
73             rField.set_increments(10, 100, eUnit);
74             break;
75     }
76 
77     if (!bAll)
78     {
79         nMin = rField.normalize(nMin);
80         nMax = rField.normalize(nMax);
81         rField.set_range(nMin, nMax, FieldUnit::TWIP);
82     }
83 
84     rField.set_value(rField.normalize(nValue), FieldUnit::TWIP);
85 }
86 
87 void SetMetricValue(weld::MetricSpinButton& rField, int nCoreValue, MapUnit eUnit)
88 {
89     auto nVal = OutputDevice::LogicToLogic(nCoreValue, eUnit, MapUnit::Map100thMM);
90     nVal = rField.normalize(nVal);
91     rField.set_value(nVal, FieldUnit::MM_100TH);
92 }
93 
94 int GetCoreValue(const weld::MetricSpinButton& rField, MapUnit eUnit)
95 {
96     int nVal = rField.get_value(FieldUnit::MM_100TH);
97     // avoid rounding issues
98     const int nSizeMask = 0xff000000;
99     bool bRoundBefore = true;
100     if( nVal >= 0 )
101     {
102         if( (nVal & nSizeMask) == 0 )
103             bRoundBefore = false;
104     }
105     else
106     {
107         if( ((-nVal) & nSizeMask ) == 0 )
108             bRoundBefore = false;
109     }
110     if( bRoundBefore )
111         nVal = rField.denormalize( nVal );
112     auto nUnitVal = OutputDevice::LogicToLogic(nVal, MapUnit::Map100thMM, eUnit);
113     if (!bRoundBefore)
114         nUnitVal = rField.denormalize(nUnitVal);
115     return nUnitVal;
116 }
117 
118 long CalcToUnit( float nIn, MapUnit eUnit )
119 {
120     // nIn is in Points
121 
122     DBG_ASSERT( eUnit == MapUnit::MapTwip       ||
123                 eUnit == MapUnit::Map100thMM   ||
124                 eUnit == MapUnit::Map10thMM    ||
125                 eUnit == MapUnit::MapMM         ||
126                 eUnit == MapUnit::MapCM, "this unit is not implemented" );
127 
128     float nTmp = nIn;
129 
130     if ( MapUnit::MapTwip != eUnit )
131         nTmp = nIn * 10 / 567;
132 
133     switch ( eUnit )
134     {
135         case MapUnit::Map100thMM:  nTmp *= 100; break;
136         case MapUnit::Map10thMM:   nTmp *= 10;  break;
137         case MapUnit::MapMM:                     break;
138         case MapUnit::MapCM:        nTmp /= 10;  break;
139         default: ;//prevent warning
140     }
141 
142     nTmp *= 20;
143     long nRet = static_cast<long>(nTmp);
144     return nRet;
145 //! return (long)(nTmp * 20);
146 }
147 
148 
149 long ItemToControl( long nIn, MapUnit eItem, FieldUnit eCtrl )
150 {
151     long nOut = 0;
152 
153     switch ( eItem )
154     {
155         case MapUnit::Map100thMM:
156         case MapUnit::Map10thMM:
157         case MapUnit::MapMM:
158         {
159             if ( eItem == MapUnit::Map10thMM )
160                 nIn /= 10;
161             else if ( eItem == MapUnit::Map100thMM )
162                 nIn /= 100;
163             nOut = TransformMetric( nIn, FieldUnit::MM, eCtrl );
164         }
165         break;
166 
167         case MapUnit::MapCM:
168         {
169             nOut = TransformMetric( nIn, FieldUnit::CM, eCtrl );
170         }
171         break;
172 
173         case MapUnit::Map1000thInch:
174         case MapUnit::Map100thInch:
175         case MapUnit::Map10thInch:
176         case MapUnit::MapInch:
177         {
178             if ( eItem == MapUnit::Map10thInch )
179                 nIn /= 10;
180             else if ( eItem == MapUnit::Map100thInch )
181                 nIn /= 100;
182             else if ( eItem == MapUnit::Map1000thInch )
183                 nIn /= 1000;
184             nOut = TransformMetric( nIn, FieldUnit::INCH, eCtrl );
185         }
186         break;
187 
188         case MapUnit::MapPoint:
189         {
190             nOut = TransformMetric( nIn, FieldUnit::POINT, eCtrl );
191         }
192         break;
193 
194         case MapUnit::MapTwip:
195         {
196             nOut = TransformMetric( nIn, FieldUnit::TWIP, eCtrl );
197         }
198         break;
199         default: ;//prevent warning
200     }
201     return nOut;
202 }
203 
204 
205 long ControlToItem( long nIn, FieldUnit eCtrl, MapUnit eItem )
206 {
207     return ItemToControl( nIn, eItem, eCtrl );
208 }
209 
210 
211 FieldUnit MapToFieldUnit( const MapUnit eUnit )
212 {
213     switch ( eUnit )
214     {
215         case MapUnit::Map100thMM:
216         case MapUnit::Map10thMM:
217         case MapUnit::MapMM:
218             return FieldUnit::MM;
219 
220         case MapUnit::MapCM:
221             return FieldUnit::CM;
222 
223         case MapUnit::Map1000thInch:
224         case MapUnit::Map100thInch:
225         case MapUnit::Map10thInch:
226         case MapUnit::MapInch:
227             return FieldUnit::INCH;
228 
229         case MapUnit::MapPoint:
230             return FieldUnit::POINT;
231 
232         case MapUnit::MapTwip:
233             return FieldUnit::TWIP;
234         default: ;//prevent warning
235     }
236     return FieldUnit::NONE;
237 }
238 
239 
240 long CalcToPoint( long nIn, MapUnit eUnit, sal_uInt16 nFactor )
241 {
242     DBG_ASSERT( eUnit == MapUnit::MapTwip       ||
243                 eUnit == MapUnit::Map100thMM   ||
244                 eUnit == MapUnit::Map10thMM    ||
245                 eUnit == MapUnit::MapMM         ||
246                 eUnit == MapUnit::MapCM, "this unit is not implemented" );
247 
248     long nRet = 0;
249 
250     if ( MapUnit::MapTwip == eUnit )
251         nRet = nIn;
252     else
253         nRet = nIn * 567;
254 
255     switch ( eUnit )
256     {
257         case MapUnit::Map100thMM:  nRet /= 100; break;
258         case MapUnit::Map10thMM:   nRet /= 10;  break;
259         case MapUnit::MapMM:                     break;
260         case MapUnit::MapCM:        nRet *= 10;  break;
261         default: ;//prevent warning
262     }
263 
264     // round up if necessary
265     if ( MapUnit::MapTwip != eUnit )
266     {
267         long nTmp = nRet % 10;
268 
269         if ( nTmp >= 4 )
270             nRet += 10 - nTmp;
271         nRet /= 10;
272     }
273     return nRet * nFactor / 20;
274 }
275 
276 
277 static long CMToTwips( long nIn )
278 {
279     long nRet = 0;
280 
281     if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
282         nRet = nIn * 567;
283     return nRet;
284 }
285 
286 
287 static long MMToTwips( long nIn )
288 {
289     long nRet = 0;
290 
291     if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
292         nRet = nIn * 567 / 10;
293     return nRet;
294 }
295 
296 
297 static long InchToTwips( long nIn )
298 {
299     long nRet = 0;
300 
301     if ( nIn <= ( LONG_MAX / 1440 ) && nIn >= ( LONG_MIN / 1440 ) )
302         nRet = nIn * 1440;
303     return nRet;
304 }
305 
306 
307 long PointToTwips( long nIn )
308 {
309     long nRet = 0;
310 
311     if ( nIn <= ( LONG_MAX / 20 ) && nIn >= ( LONG_MIN / 20 ) )
312         nRet = nIn * 20;
313     return nRet;
314 }
315 
316 
317 static long PicaToTwips( long nIn )
318 {
319     long nRet = 0;
320 
321     if ( nIn <= ( LONG_MAX / 240 ) && nIn >= ( LONG_MIN / 240 ) )
322         nRet = nIn * 240;
323     return nRet;
324 }
325 
326 
327 static long TwipsToCM( long nIn )
328 {
329     long nRet = nIn / 567;
330     return nRet;
331 }
332 
333 
334 static long InchToCM( long nIn )
335 {
336     long nRet = 0;
337 
338     if ( nIn <= ( LONG_MAX / 254 ) && nIn >= ( LONG_MIN / 254 ) )
339         nRet = nIn * 254 / 100;
340     return nRet;
341 }
342 
343 
344 static long MMToCM( long nIn )
345 {
346     long nRet = nIn / 10;
347     return nRet;
348 }
349 
350 
351 static long PointToCM( long nIn )
352 {
353     long nRet = 0;
354 
355     if ( nIn <= ( LONG_MAX / 20 ) && nIn >= ( LONG_MIN / 20 ) )
356         nRet = nIn * 20 / 567;
357     return nRet;
358 }
359 
360 
361 static long PicaToCM( long nIn)
362 {
363     long nRet = 0;
364 
365     if ( nIn <= ( LONG_MAX / 12 / 20 ) && nIn >= ( LONG_MIN / 12 / 20 ) )
366         nRet = nIn * 12 * 20 / 567;
367     return nRet;
368 }
369 
370 
371 static long TwipsToMM( long nIn )
372 {
373     long nRet = 0;
374 
375     if ( nIn <= ( LONG_MAX / 10 ) && nIn >= ( LONG_MIN / 10 ) )
376         nRet = nIn * 10 / 566;
377     return nRet;
378 }
379 
380 
381 static long CMToMM( long nIn )
382 {
383     long nRet = 0;
384 
385     if ( nIn <= ( LONG_MAX / 10 ) && nIn >= ( LONG_MIN / 10 ) )
386         nRet = nIn * 10;
387     return nRet;
388 }
389 
390 
391 static long InchToMM( long nIn )
392 {
393     long nRet = 0;
394 
395     if ( nIn <= ( LONG_MAX / 254 ) && nIn >= ( LONG_MIN / 254 ) )
396         nRet = nIn * 254 / 10;
397     return nRet;
398 }
399 
400 
401 static long PointToMM( long nIn )
402 {
403     long nRet = 0;
404 
405     if ( nIn <= ( LONG_MAX / 200 ) && nIn >= ( LONG_MIN / 200 ) )
406         nRet = nIn * 200 / 567;
407     return nRet;
408 }
409 
410 
411 static long PicaToMM( long nIn )
412 {
413     long nRet = 0;
414 
415     if ( nIn <= ( LONG_MAX / 12 / 200 ) && nIn >= ( LONG_MIN / 12 / 200 ) )
416         nRet = nIn * 12 * 200 / 567;
417     return nRet;
418 }
419 
420 
421 static long TwipsToInch( long nIn )
422 {
423     long nRet = nIn / 1440;
424     return nRet;
425 }
426 
427 
428 static long CMToInch( long nIn )
429 {
430     long nRet = 0;
431 
432     if ( nIn <= ( LONG_MAX / 100 ) && nIn >= ( LONG_MIN / 100 ) )
433         nRet = nIn * 100 / 254;
434     return nRet;
435 }
436 
437 
438 static long MMToInch( long nIn )
439 {
440     long nRet = 0;
441 
442     if ( nIn <= ( LONG_MAX / 10 ) && nIn >= ( LONG_MIN / 10 ) )
443         nRet = nIn * 10 / 254;
444     return nRet;
445 }
446 
447 
448 static long PointToInch( long nIn )
449 {
450     long nRet = nIn / 72;
451     return nRet;
452 }
453 
454 
455 static long PicaToInch( long nIn )
456 {
457     long nRet = nIn / 6;
458     return nRet;
459 }
460 
461 
462 static long TwipsToPoint( long nIn )
463 {
464     long nRet = nIn / 20;
465     return nRet;
466 }
467 
468 
469 static long InchToPoint( long nIn )
470 {
471     long nRet = 0;
472 
473     if ( nIn <= ( LONG_MAX / 72 ) && nIn >= ( LONG_MIN / 72 ) )
474         nRet = nIn * 72;
475     return nRet;
476 }
477 
478 
479 static long CMToPoint( long nIn )
480 {
481     long nRet = 0;
482 
483     if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
484         nRet = nIn * 567 / 20;
485     return nRet;
486 }
487 
488 
489 static long MMToPoint( long nIn )
490 {
491     long nRet = 0;
492 
493     if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
494         nRet = nIn * 567 / 200;
495     return nRet;
496 }
497 
498 
499 static long PicaToPoint( long nIn )
500 {
501     long nRet = nIn / 12;
502     return nRet;
503 }
504 
505 
506 static long TwipsToPica( long nIn )
507 {
508     long nRet = nIn / 240;
509     return nRet;
510 }
511 
512 
513 static long InchToPica( long nIn )
514 {
515     long nRet = 0;
516 
517     if ( nIn <= ( LONG_MAX / 6 ) && nIn >= ( LONG_MIN / 6 ) )
518         nRet = nIn * 6;
519     return nRet;
520 }
521 
522 
523 static long PointToPica( long nIn )
524 {
525     long nRet = 0;
526 
527     if ( nIn <= ( LONG_MAX / 12 ) && nIn >= ( LONG_MIN / 12 ) )
528         nRet = nIn * 12;
529     return nRet;
530 }
531 
532 
533 static long CMToPica( long nIn )
534 {
535     long nRet = 0;
536 
537     if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
538         nRet = nIn * 567 / 20 / 12;
539     return nRet;
540 }
541 
542 
543 static long MMToPica( long nIn )
544 {
545     long nRet = 0;
546 
547     if ( nIn <= ( LONG_MAX / 567 ) && nIn >= ( LONG_MIN / 567 ) )
548         nRet = nIn * 567 / 200 / 12;
549     return nRet;
550 }
551 
552 
553 static long Nothing( long nIn )
554 {
555     long nRet = nIn;
556     return nRet;
557 }
558 
559 FUNC_CONVERT const ConvertTable[6][6] =
560 {
561 //  CM,         MM          INCH         POINT        PICAS=32     TWIPS
562     { Nothing,  CMToMM,     CMToInch,    CMToPoint,   CMToPica,    CMToTwips },
563     { MMToCM,       Nothing,    MMToInch,    MMToPoint,   MMToPica,    MMToTwips },
564     { InchToCM, InchToMM,   Nothing,     InchToPoint, InchToPica,  InchToTwips },
565     { PointToCM,    PointToMM,  PointToInch, Nothing,     PointToPica, PointToTwips },
566     { PicaToCM, PicaToMM,   PicaToInch,  PicaToPoint, Nothing,     PicaToTwips },
567     { TwipsToCM,    TwipsToMM,  TwipsToInch, TwipsToPoint,TwipsToPica, Nothing }
568 };
569 
570 
571 long TransformMetric( long nVal, FieldUnit aOld, FieldUnit aNew )
572 {
573     if ( aOld == FieldUnit::NONE   || aNew == FieldUnit::NONE ||
574          aOld == FieldUnit::CUSTOM || aNew == FieldUnit::CUSTOM )
575     {
576         return nVal;
577     }
578 
579     sal_uInt16 nOld = 0;
580     sal_uInt16 nNew = 0;
581 
582     switch ( aOld )
583     {
584         case FieldUnit::CM:
585             nOld = 0; break;
586         case FieldUnit::MM:
587             nOld = 1; break;
588         case FieldUnit::INCH:
589             nOld = 2; break;
590         case FieldUnit::POINT:
591             nOld = 3; break;
592         case FieldUnit::PICA:
593             nOld = 4; break;
594         case FieldUnit::TWIP:
595             nOld = 5; break;
596         default: ;//prevent warning
597     }
598 
599     switch ( aNew )
600     {
601         case FieldUnit::CM:
602             nNew = 0; break;
603         case FieldUnit::MM:
604             nNew = 1; break;
605         case FieldUnit::INCH:
606             nNew = 2; break;
607         case FieldUnit::POINT:
608             nNew = 3; break;
609         case FieldUnit::PICA:
610             nNew = 4; break;
611         case FieldUnit::TWIP:
612             nNew = 5; break;
613         default: ;//prevent warning
614     }
615     return ConvertTable[nOld][nNew]( nVal );
616 }
617 
618 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
619