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