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