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