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