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