]> git.lyx.org Git - lyx.git/blob - src/Length.cpp
Fix cppcheck variable scope warnings
[lyx.git] / src / Length.cpp
1 /**
2  * \file Length.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Matthias Ettrich
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Angus Leeming
10  * \author John Levon
11  * \author Dekel Tsur
12  *
13  * Full author contact details are available in file CREDITS.
14  */
15
16 #include <config.h>
17
18 #include "Length.h"
19 #include "LyXRC.h"
20 #include "MetricsInfo.h"
21
22 #include "frontends/FontMetrics.h"
23
24 #include "support/docstream.h"
25 #include "support/lstrings.h"
26
27 #include <sstream>
28 #include <iomanip>
29
30 using namespace std;
31 using namespace lyx::support;
32
33 namespace lyx {
34
35
36 /////////////////////////////////////////////////////////////////////
37 //
38 // Length
39 //
40 /////////////////////////////////////////////////////////////////////
41
42 Length::Length()
43         : val_(0), unit_(Length::UNIT_NONE)
44 {}
45
46
47 Length::Length(double v, Length::UNIT u)
48         : val_(v), unit_(u)
49 {}
50
51
52 Length::Length(string const & data)
53         : val_(0), unit_(Length::PT)
54 {
55         Length tmp;
56
57         if (!isValidLength(data, &tmp))
58                 return; // should raise an exception
59
60         val_  = tmp.val_;
61         unit_ = tmp.unit_;
62 }
63
64
65 string const Length::asString() const
66 {
67         ostringstream os;
68         if (unit_ != UNIT_NONE)
69                 os << formatFPNumber(val_) << unit_name[unit_]; // setw?
70         return os.str();
71 }
72
73
74 docstring const Length::asDocstring() const
75 {
76         odocstringstream os;
77         if (unit_ != UNIT_NONE)
78                 os << formatFPNumber(val_) << unit_name[unit_]; // setw?
79         return os.str();
80 }
81
82
83 string const Length::asLatexString() const
84 {
85         ostringstream os;
86         // Do not allow scientific notation (e.g. 1.2e+03), since this is not valid
87         // LaTeX (bug 9416)
88         switch (unit_) {
89         case PTW:
90                 os << formatFPNumber(val_ / 100.0) << "\\textwidth";
91                 break;
92         case PCW:
93                 os << formatFPNumber(val_ / 100.0) << "\\columnwidth";
94                 break;
95         case PPW:
96                 os << formatFPNumber(val_ / 100.0) << "\\paperwidth";
97                 break;
98         case PLW:
99                 os << formatFPNumber(val_ / 100.0) << "\\linewidth";
100                 break;
101         case PTH:
102                 os << formatFPNumber(val_ / 100.0) << "\\textheight";
103                 break;
104         case PPH:
105                 os << formatFPNumber(val_ / 100.0) << "\\paperheight";
106                 break;
107         case UNIT_NONE:
108                 break;
109         default:
110                 os << formatFPNumber(val_) << unit_name[unit_];
111           break;
112         }
113         return os.str();
114 }
115
116
117 string const Length::asHTMLString() const
118 {
119         ostringstream os;
120         switch (unit_) {
121         case PT:
122         case BP:
123         case DD:
124                 // close enough
125                 os << formatFPNumber(val_) << "pt";
126                 break;
127         case MM:
128         case CM:
129         case PC:
130         case IN:
131         case EX:
132         case EM:
133                 os << formatFPNumber(val_) << unit_name[unit_];
134                 break;
135         case CC:
136                 os << formatFPNumber(val_ / 12.0) << "pt";
137                 break;
138         case MU:
139                 os << formatFPNumber(val_ / 18.0) << "em";
140                 break;
141         case PTW:
142         case PPW:
143         case PLW:
144         case PCW:
145         case PTH:
146         case PPH:
147                 // what it's a percentage of probably won't make sense for HTML,
148                 // so we'll assume people have chosen these appropriately
149                 os << formatFPNumber(val_) << '%';
150                 break;
151         case SP:
152         case UNIT_NONE:
153                 break;
154         }
155         return os.str();
156 }
157
158
159 double Length::value() const
160 {
161         return val_;
162 }
163
164
165 Length::UNIT Length::unit() const
166 {
167         return unit_;
168 }
169
170
171 void Length::value(double v)
172 {
173         val_ = v;
174 }
175
176
177 void Length::unit(Length::UNIT u)
178 {
179         unit_ = u;
180 }
181
182
183 bool Length::zero() const
184 {
185         return val_ == 0.0;
186 }
187
188
189 bool Length::empty() const
190 {
191         return unit_ == Length::UNIT_NONE;
192 }
193
194
195 int Length::inPixels(int text_width, int em_width_base) const
196 {
197         // Zoom factor specified by user in percent
198         double const zoom = lyxrc.zoom / 100.0; // [percent]
199
200         // DPI setting for monitor: pixels/inch
201         double const dpi = lyxrc.dpi; // screen resolution [pixels/inch]
202
203         double const em_width_in = (em_width_base > 0)
204                 ? em_width_base / (zoom * dpi)
205                 : 10.0/72.27;
206         // A different estimate for em_width is
207         // theFontMetrics(FontInfo(sane_font)).em()
208         // but this estimate might not be more accurate as the screen font
209         // is different then the latex font.
210
211         // Pixel values are scaled so that the ratio
212         // between lengths and font sizes on the screen
213         // is the same as on paper.
214
215         double const text_width_in = text_width / (zoom * dpi);
216         double const result = zoom * dpi * inInch(text_width_in, em_width_in);
217         return static_cast<int>(result + ((result >= 0) ? 0.5 : -0.5));
218 }
219
220
221 double Length::inInch(double text_width, double em_width) const
222 {
223         double result = 0.0;
224
225         switch (unit_) {
226         case Length::SP:
227                 // Scaled point: sp = 1/65536 pt
228                 result = val_ / (72.27 * 65536); // 4736286.7
229                 break;
230         case Length::PT:
231                 // Point: 1 pt = 1/72.27 inch
232                 result = val_ / 72.27; // 72.27
233                 break;
234         case Length::BP:
235                 // Big point: 1 bp = 1/72 inch
236                 result = val_ / 72; // 72
237                 break;
238         case Length::DD:
239                 // Didot: 1157dd = 1238 pt?
240                 result = val_ / (72.27 / (0.376 * 2.845)); // 67.559735
241                 break;
242         case Length::MM:
243                 // Millimeter: 1 mm = 1/25.4 inch
244                 result = val_ / 25.4; // 25.4
245                 break;
246         case Length::PC:
247                 // Pica: 1 pc = 12 pt
248                 result = val_ / (72.27 / 12); // 6.0225
249                 break;
250         case Length::CC:
251                 // Cicero: 1 cc = 12 dd
252                 result = val_
253                         / (72.27 / (12 * 0.376 * 2.845)); // 5.6299779
254                 break;
255         case Length::CM:
256                 // Centimeter: 1 cm = 1/2.54 inch
257                 result = val_ / 2.54; // 2.54
258                 break;
259         case Length::IN:
260                 // Inch
261                 result = val_;
262                 break;
263         case Length::EX:
264                 // Ex: The height of an "x"
265                 // 0.4305 is the ration between 1ex and 1em in cmr10
266                 result = val_ * em_width * 0.4305;
267                 break;
268         case Length::EM:
269                 // Em: The width of an "m"
270                 result = val_ * em_width;
271                 break;
272         case Length::MU:
273                 // math unit = 1/18em
274                 result = val_ * em_width / 18;
275                 break;
276         case Length::PCW: // Always % of workarea
277         case Length::PTW:
278         case Length::PLW:
279                 result = val_ * text_width / 100;
280                 break;
281         case Length::PPW:
282                 // paperwidth/textwidth is 1.7 for A4 paper with default margins
283                 result = val_ * text_width * 1.7 / 100;
284                 break;
285         case Length::PTH:
286                 result = val_ * text_width * 1.787 / 100;
287                 break;
288         case Length::PPH:
289                 result = val_ * text_width * 2.2 / 100;
290                 break;
291         case Length::UNIT_NONE:
292                 result = 0;  // this cannot happen
293                 break;
294         }
295         return result;
296 }
297
298
299 int Length::inPixels(MetricsBase const & base) const
300 {
301         return inPixels(base.textwidth, theFontMetrics(base.font).em());
302 }
303
304
305 int Length::inBP() const
306 {
307         // return any Length value as a one with
308         // the PostScript point, called bp (big points)
309
310         double const text_width_in = 210.0 / 2.54; // assume A4
311         double const em_width_in = 10.0 / 72.27;
312         double result = 72.0 * inInch(text_width_in, em_width_in);
313         return static_cast<int>(result + 0.5);
314 }
315
316
317 Length::UNIT Length::defaultUnit()
318 {
319         return lyxrc.default_length_unit;
320 }
321
322
323
324 bool operator==(Length const & l1, Length const & l2)
325 {
326         return l1.value() == l2.value() && l1.unit() == l2.unit();
327 }
328
329
330 bool operator!=(Length const & l1, Length const & l2)
331 {
332         return !(l1 == l2);
333 }
334
335
336 /////////////////////////////////////////////////////////////////////
337 //
338 // GlueLength
339 //
340 /////////////////////////////////////////////////////////////////////
341
342
343 GlueLength::GlueLength(Length const & len)
344         : len_(len)
345 {}
346
347
348 GlueLength::GlueLength(Length const & len, Length const & plus,
349                 Length const & minus)
350         : len_(len), plus_(plus), minus_(minus)
351 {}
352
353
354 GlueLength::GlueLength(string const & data)
355 {
356         isValidGlueLength(data, this);
357 }
358
359
360 string const GlueLength::asString() const
361 {
362         if (len_.empty())
363                 return string();
364
365         ostringstream buffer;
366
367         buffer << formatFPNumber(len_.value());
368
369         if (plus_.zero() && minus_.zero()) {
370                 buffer << unit_name[len_.unit()];
371                 return buffer.str();
372         }
373
374         // just len and plus
375         if (minus_.zero()) {
376                 if (len_.unit() != plus_.unit())
377                         buffer << unit_name[len_.unit()];
378                 buffer << '+' << formatFPNumber(plus_.value());
379                 buffer << unit_name[plus_.unit()];
380                 return buffer.str();
381         }
382
383         // just len and minus
384         if (plus_.zero()) {
385                 if (len_.unit() != minus_.unit())
386                         buffer << unit_name[len_.unit()];
387                 buffer << '-' << formatFPNumber(minus_.value());
388                 buffer << unit_name[minus_.unit()];
389                 return buffer.str();
390         }
391
392         // ok, len, plus AND minus
393
394         // len+-
395         if (minus_ == plus_) {
396                 if (len_.unit() != minus_.unit())
397                         buffer << unit_name[len_.unit()];
398                 buffer << "+-" << formatFPNumber(minus_.value());
399                 buffer << unit_name[minus_.unit()];
400                 return buffer.str();
401         }
402
403         // this is so rare a case, why bother minimising units ?
404
405         buffer << unit_name[len_.unit()];
406         buffer << '+' << formatFPNumber(plus_.value()) << unit_name[plus_.unit()];
407         buffer << '-' << formatFPNumber(minus_.value()) << unit_name[minus_.unit()];
408
409         return buffer.str();
410 }
411
412
413 string const GlueLength::asLatexString() const
414 {
415         ostringstream buffer;
416         // use Length::asLatexString() to handle also the percent lengths
417         buffer << len_.Length::asLatexString();
418         if (!plus_.zero())
419                 buffer << " plus " << plus_.Length::asLatexString();
420         if (!minus_.zero())
421                 buffer << " minus " << minus_.Length::asLatexString();
422         return buffer.str();
423 }
424
425
426 Length const & GlueLength::len() const
427 {
428         return len_;
429 }
430
431
432 Length const & GlueLength::plus() const
433 {
434         return plus_;
435 }
436
437
438 Length const & GlueLength::minus() const
439 {
440         return minus_;
441 }
442
443
444 bool operator==(GlueLength const & l1, GlueLength const & l2)
445 {
446         return l1.len() == l2.len()
447                  && l1.plus() == l2.plus()
448                  && l1.minus() == l2.minus();
449 }
450
451
452 bool operator!=(GlueLength const & l1, GlueLength const & l2)
453 {
454         return !(l1 == l2);
455 }
456
457
458 } // namespace lyx