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