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