]> git.lyx.org Git - lyx.git/blob - src/Length.cpp
* fr.po: Update from Jean-Pierre Chretien
[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
21 #include "support/docstream.h"
22
23 #include <sstream>
24 #include <iomanip>
25
26 using namespace std;
27
28 namespace lyx {
29
30
31 /////////////////////////////////////////////////////////////////////
32 //
33 // Length
34 //
35 /////////////////////////////////////////////////////////////////////
36
37 Length::Length()
38         : val_(0), unit_(Length::UNIT_NONE)
39 {}
40
41
42 Length::Length(double v, Length::UNIT u)
43         : val_(v), unit_(u)
44 {}
45
46
47 Length::Length(string const & data)
48         : val_(0), unit_(Length::PT)
49 {
50         Length tmp;
51
52         if (!isValidLength(data, &tmp))
53                 return; // should raise an exception
54
55         val_  = tmp.val_;
56         unit_ = tmp.unit_;
57 }
58
59
60 void Length::swap(Length & rhs)
61 {
62         std::swap(val_, rhs.val_);
63         std::swap(unit_, rhs.unit_);
64 }
65
66
67 string const Length::asString() const
68 {
69         ostringstream os;
70         if (unit_ != UNIT_NONE)
71                 os << 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 << val_ << unit_name[unit_]; // setw?
81         return os.str();
82 }
83
84
85 string const Length::asLatexString() const
86 {
87         ostringstream os;
88         switch (unit_) {
89         case PTW:
90                 os << val_ / 100.0 << "\\textwidth";
91                 break;
92         case PCW:
93                 os << val_ / 100.0 << "\\columnwidth";
94                 break;
95         case PPW:
96                 os << val_ / 100.0 << "\\paperwidth";
97                 break;
98         case PLW:
99                 os << val_ / 100.0 << "\\linewidth";
100                 break;
101         case PTH:
102                 os << val_ / 100.0 << "\\textheight";
103                 break;
104         case PPH:
105                 os << val_ / 100.0 << "\\paperheight";
106                 break;
107         case UNIT_NONE:
108                 break;
109         default:
110                 os << 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 << val_ << "pt";
126                 break;
127         case MM:
128         case CM:
129         case PC:
130         case IN:
131         case EX:
132         case EM:
133                 os << val_ << unit_name[unit_];
134                 break;
135         case CC:
136                 os << val_/12.0 << "pt";
137                 break;
138         case MU:
139                 os << 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 << 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 = (em_width_base > 0)
204                 ? em_width_base
205                 : 10*(dpi/72.27)*zoom;
206         // A different estimate for em_width is
207         // theFontMetrics(FontInfo(sane_font)).width('M')
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 result = 0.0;
216
217         switch (unit_) {
218         case Length::SP:
219                 // Scaled point: sp = 1/65536 pt
220                 result = zoom * dpi * val_
221                         / (72.27 * 65536); // 4736286.7
222                 break;
223         case Length::PT:
224                 // Point: 1 pt = 1/72.27 inch
225                 result = zoom * dpi * val_
226                         / 72.27; // 72.27
227                 break;
228         case Length::BP:
229                 // Big point: 1 bp = 1/72 inch
230                 result = zoom * dpi * val_
231                         / 72; // 72
232                 break;
233         case Length::DD:
234                 // Didot: 1157dd = 1238 pt?
235                 result = zoom * dpi * val_
236                         / (72.27 / (0.376 * 2.845)); // 67.559735
237                 break;
238         case Length::MM:
239                 // Millimeter: 1 mm = 1/25.4 inch
240                 result = zoom * dpi * val_
241                         / 25.4; // 25.4
242                 break;
243         case Length::PC:
244                 // Pica: 1 pc = 12 pt
245                 result = zoom * dpi * val_
246                         / (72.27 / 12); // 6.0225
247                 break;
248         case Length::CC:
249                 // Cicero: 1 cc = 12 dd
250                 result = zoom * dpi * val_
251                         / (72.27 / (12 * 0.376 * 2.845)); // 5.6299779
252                 break;
253         case Length::CM:
254                 // Centimeter: 1 cm = 1/2.54 inch
255                 result = zoom * dpi * val_
256                         / 2.54; // 2.54
257                 break;
258         case Length::IN:
259                 // Inch
260                 result = zoom * dpi * val_;
261                 break;
262         case Length::EX:
263                 // Ex: The height of an "x"
264                 // 0.4305 is the ration between 1ex and 1em in cmr10
265                 result = val_ * em_width * 0.4305;
266                 break;
267         case Length::EM:
268                 // Em: The width of an "m"
269                 result = val_ * em_width;
270                 break;
271         case Length::MU:
272                 // math unit = 1/18em
273                 result = val_ * em_width / 18;
274                 break;
275         case Length::PCW: // Always % of workarea
276         case Length::PTW:
277         case Length::PLW:
278                 result = val_ * text_width / 100;
279                 break;
280         case Length::PPW:
281                 // paperwidth/textwidth is 1.7 for A4 paper with default margins
282                 result = val_ * text_width * 1.7 / 100;
283                 break;
284         case Length::PTH:
285                 result = val_ * text_width * 1.787 / 100;
286                 break;
287         case Length::PPH:
288                 result = val_ * text_width * 2.2 / 100;
289                 break;
290         case Length::UNIT_NONE:
291                 result = 0;  // this cannot happen
292                 break;
293         }
294         return static_cast<int>(result + ((result >= 0) ? 0.5 : -0.5));
295 }
296
297
298 int Length::inBP() const
299 {
300         // return any Length value as a one with
301         // the PostScript point, called bp (big points)
302         double result = 0.0;
303         switch (unit_) {
304         case Length::CM:
305                 // 1bp = 0.2835cm
306                 result = val_ * 28.346;
307                 break;
308         case Length::MM:
309                 // 1bp = 0.02835mm
310                 result = val_ * 2.8346;
311                 break;
312         case Length::IN:
313                 // 1pt = 1/72in
314                 result = val_ * 72.0;
315                 break;
316         default:
317                 // no other than bp possible
318                 result = val_;
319                 break;
320         }
321         return static_cast<int>(result + 0.5);
322 }
323
324
325 Length::UNIT Length::defaultUnit()
326 {
327         return lyxrc.default_length_unit;
328 }
329
330
331
332 bool operator==(Length const & l1, Length const & l2)
333 {
334         return l1.value() == l2.value() && l1.unit() == l2.unit();
335 }
336
337
338 bool operator!=(Length const & l1, Length const & l2)
339 {
340         return !(l1 == l2);
341 }
342
343
344 /////////////////////////////////////////////////////////////////////
345 //
346 // GlueLength
347 //
348 /////////////////////////////////////////////////////////////////////
349
350
351 GlueLength::GlueLength(Length const & len)
352         : len_(len)
353 {}
354
355
356 GlueLength::GlueLength(Length const & len, Length const & plus,
357                 Length const & minus)
358         : len_(len), plus_(plus), minus_(minus)
359 {}
360
361
362 GlueLength::GlueLength(string const & data)
363 {
364         isValidGlueLength(data, this);
365 }
366
367
368 string const GlueLength::asString() const
369 {
370         if (len_.empty())
371                 return string();
372
373         ostringstream buffer;
374
375         buffer << len_.value();
376
377         if (plus_.zero() && minus_.zero()) {
378                 buffer << unit_name[len_.unit()];
379                 return buffer.str();
380         }
381
382         // just len and plus
383         if (minus_.zero()) {
384                 if (len_.unit() != plus_.unit())
385                         buffer << unit_name[len_.unit()];
386                 buffer << '+' << plus_.value();
387                 buffer << unit_name[plus_.unit()];
388                 return buffer.str();
389         }
390
391         // just len and minus
392         if (plus_.zero()) {
393                 if (len_.unit() != minus_.unit())
394                         buffer << unit_name[len_.unit()];
395                 buffer << '-' << minus_.value();
396                 buffer << unit_name[minus_.unit()];
397                 return buffer.str();
398         }
399
400         // ok, len, plus AND minus
401
402         // len+-
403         if (minus_ == plus_) {
404                 if (len_.unit() != minus_.unit())
405                         buffer << unit_name[len_.unit()];
406                 buffer << "+-" << minus_.value();
407                 buffer << unit_name[minus_.unit()];
408                 return buffer.str();
409         }
410
411         // this is so rare a case, why bother minimising units ?
412
413         buffer << unit_name[len_.unit()];
414         buffer << '+' << plus_.value() << unit_name[plus_.unit()];
415         buffer << '-' << minus_.value() << unit_name[minus_.unit()];
416
417         return buffer.str();
418 }
419
420
421 string const GlueLength::asLatexString() const
422 {
423         ostringstream buffer;
424         // use Length::asLatexString() to handle also the percent lengths
425         buffer << len_.Length::asLatexString();
426         if (!plus_.zero())
427                 buffer << " plus " << plus_.Length::asLatexString();
428         if (!minus_.zero())
429                 buffer << " minus " << minus_.Length::asLatexString();
430         return buffer.str();
431 }
432
433
434 Length const & GlueLength::len() const
435 {
436         return len_;
437 }
438
439
440 Length const & GlueLength::plus() const
441 {
442         return plus_;
443 }
444
445
446 Length const & GlueLength::minus() const
447 {
448         return minus_;
449 }
450
451
452 bool operator==(GlueLength const & l1, GlueLength const & l2)
453 {
454         return l1.len() == l2.len()
455                  && l1.plus() == l2.plus()
456                  && l1.minus() == l2.minus();
457 }
458
459
460 bool operator!=(GlueLength const & l1, GlueLength const & l2)
461 {
462         return !(l1 == l2);
463 }
464
465
466 } // namespace lyx