]> git.lyx.org Git - lyx.git/blob - src/mathed/InsetMathDecoration.cpp
398e3a299ded6297afe61ab4261ea1d664a2355e
[lyx.git] / src / mathed / InsetMathDecoration.cpp
1 /**
2  * \file InsetMathDecoration.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author André Pönitz
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "InsetMathDecoration.h"
15
16 #include "MathData.h"
17 #include "MathParser.h"
18 #include "MathSupport.h"
19 #include "MathStream.h"
20 #include "MetricsInfo.h"
21
22 #include "LaTeXFeatures.h"
23
24 #include "support/debug.h"
25 #include "support/docstring.h"
26 #include "support/gettext.h"
27 #include "support/lassert.h"
28 #include "support/lstrings.h"
29
30 #include <algorithm>
31 #include <ostream>
32
33 using namespace lyx::support;
34
35 using namespace std;
36
37 namespace lyx {
38
39
40 InsetMathDecoration::InsetMathDecoration(Buffer * buf, latexkeys const * key)
41         : InsetMathNest(buf, 1), key_(key)
42 {
43 //      lyxerr << " creating deco " << key->name << endl;
44 }
45
46
47 Inset * InsetMathDecoration::clone() const
48 {
49         return new InsetMathDecoration(*this);
50 }
51
52
53 bool InsetMathDecoration::upper() const
54 {
55         return key_->name.substr(0, 5) != "under" && key_->name != "utilde";
56 }
57
58
59 MathClass InsetMathDecoration::mathClass() const
60 {
61         if (key_->name == "overbrace" || key_->name == "underbrace")
62                 return MC_OP;
63         return MC_ORD;
64 }
65
66
67 Limits InsetMathDecoration::defaultLimits(bool display) const
68 {
69         if (allowsLimitsChange() && display)
70                 return LIMITS;
71         else
72                 return NO_LIMITS;
73 }
74
75
76 bool InsetMathDecoration::protect() const
77 {
78         return
79                         key_->name == "overbrace" ||
80                         key_->name == "underbrace" ||
81                         key_->name == "overleftarrow" ||
82                         key_->name == "overrightarrow" ||
83                         key_->name == "overleftrightarrow" ||
84                         key_->name == "underleftarrow" ||
85                         key_->name == "underrightarrow" ||
86                         key_->name == "underleftrightarrow";
87 }
88
89
90 bool InsetMathDecoration::wide() const
91 {
92         return
93                         key_->name == "overline" ||
94                         key_->name == "underline" ||
95                         key_->name == "overbrace" ||
96                         key_->name == "underbrace" ||
97                         key_->name == "overleftarrow" ||
98                         key_->name == "overrightarrow" ||
99                         key_->name == "overleftrightarrow" ||
100                         key_->name == "widehat" ||
101                         key_->name == "widetilde" ||
102                         key_->name == "underleftarrow" ||
103                         key_->name == "underrightarrow" ||
104                         key_->name == "underleftrightarrow" ||
105                         key_->name == "undertilde" ||
106                         key_->name == "utilde";
107 }
108
109
110 InsetMath::mode_type InsetMathDecoration::currentMode() const
111 {
112         return key_->name == "underbar" ? TEXT_MODE : MATH_MODE;
113 }
114
115
116 void InsetMathDecoration::metrics(MetricsInfo & mi, Dimension & dim) const
117 {
118         Changer dummy = mi.base.changeEnsureMath(currentMode());
119
120         cell(0).metrics(mi, dim);
121
122         dh_  = 6; //mathed_char_height(LM_TC_VAR, mi, 'I', ascent_, descent_);
123         dw_  = 6; //mathed_char_width(LM_TC_VAR, mi, 'x');
124
125         if (upper()) {
126                 dy_ = -dim.asc - dh_;
127                 dim.asc += dh_ + 1;
128         } else {
129                 dy_ = dim.des + 1;
130                 dim.des += dh_ + 2;
131         }
132 }
133
134
135 void InsetMathDecoration::draw(PainterInfo & pi, int x, int y) const
136 {
137         Changer dummy = pi.base.changeEnsureMath(currentMode());
138
139         cell(0).draw(pi, x, y);
140         Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
141         if (wide())
142                 mathed_draw_deco(pi, x + 1, y + dy_, dim0.wid, dh_, key_->name);
143         else
144                 mathed_draw_deco(pi, x + 1 + (dim0.wid - dw_) / 2,
145                         y + dy_, dw_, dh_, key_->name);
146 }
147
148
149 void InsetMathDecoration::write(WriteStream & os) const
150 {
151         MathEnsurer ensurer(os);
152         if (os.fragile() && protect())
153                 os << "\\protect";
154         os << '\\' << key_->name << '{';
155         ModeSpecifier specifier(os, currentMode());
156         os << cell(0) << '}';
157         writeLimits(os);
158 }
159
160
161 void InsetMathDecoration::normalize(NormalStream & os) const
162 {
163         os << "[deco " << key_->name << ' ' <<  cell(0) << ']';
164 }
165
166
167 void InsetMathDecoration::infoize(odocstream & os) const
168 {
169         os << bformat(_("Decoration: %1$s"), key_->name);
170 }
171
172
173 namespace {
174         struct Attributes {
175                 Attributes() : over(false) {}
176                 Attributes(bool o, string const & t, string const & entity)
177                         : over(o), tag(t), entity(entity) {}
178                 bool over;
179                 string tag;
180                 string entity;
181         };
182
183         typedef map<string, Attributes> TranslationMap;
184
185         void buildTranslationMap(TranslationMap & t) {
186                 // the decorations we need to support are listed in lib/symbols
187                 t["acute"] = Attributes(true, "&acute;", "&#x00B4;");
188                 t["bar"]   = Attributes(true, "&OverBar;", "&#x00AF;");
189                 t["breve"] = Attributes(true, "&breve;", "&#x02D8;");
190                 t["check"] = Attributes(true, "&caron;", "&#x02C7;");
191                 t["ddddot"] = Attributes(true, "&DotDot;", "&#x20DC;");
192                 t["dddot"] = Attributes(true, "&TripleDot;", "&#x20DB;");
193                 t["ddot"] = Attributes(true, "&Dot;", "&#x00A8;");
194                 t["dot"] = Attributes(true, "&dot;", "&#x02D9;");
195                 t["grave"] = Attributes(true, "&grave;", "&#x0060;");
196                 t["hat"] = Attributes(true, "&circ;", "&#x02C6;");
197                 t["mathring"] = Attributes(true, "&ring;", "&#x02DA;");
198                 t["overbrace"] = Attributes(true, "&OverBrace;", "&#xFE37;");
199                 t["overleftarrow"] = Attributes(true, "&xlarr;", "&#x27F5;");
200                 t["overleftrightarrow"] = Attributes(true, "&xharr;", "&#x27F7;");
201                 t["overline"] = Attributes(true, "&macr;", "&#x00AF;");
202                 t["overrightarrow"] = Attributes(true, "&xrarr;", "&#x27F6;");
203                 t["tilde"] = Attributes(true, "&tilde;", "&#x02DC;");
204                 t["underbar"] = Attributes(false, "&UnderBar;", "&#x0332;");
205                 t["underbrace"] = Attributes(false, "&UnderBrace;", "&#xFE38;");
206                 t["underleftarrow"] = Attributes(false, "&xlarr;", "&#x27F5;");
207                 t["underleftrightarrow"] = Attributes(false, "&xharr;", "&#x27F7;");
208                 // this is the macron, again, but it works
209                 t["underline"] = Attributes(false, "&macr;", "&#x00AF;");
210                 t["underrightarrow"] = Attributes(false, "&xrarr;", "&#x27F6;");
211                 t["undertilde"] = Attributes(false, "&Tilde;", "&#x223C;");
212                 t["utilde"] = Attributes(false, "&Tilde;", "&#x223C;");
213                 t["vec"] = Attributes(true, "&rarr;", "&#x2192;");
214                 t["widehat"] = Attributes(true, "&Hat;", "&#x005E;");
215                 t["widetilde"] = Attributes(true, "&Tilde;", "&#x223C;");
216         }
217
218         TranslationMap const & translationMap() {
219                 static TranslationMap t;
220                 if (t.empty())
221                         buildTranslationMap(t);
222                 return t;
223         }
224 } // namespace
225
226 void InsetMathDecoration::mathmlize(MathMLStream & ms) const
227 {
228         TranslationMap const & t = translationMap();
229         TranslationMap::const_iterator cur = t.find(to_utf8(key_->name));
230         LASSERT(cur != t.end(), return);
231         char const * const outag = cur->second.over ? "mover" : "munder";
232         std::string decoration = ms.xmlMode() ? cur->second.entity : cur->second.tag;
233         ms << MTag(outag)
234            << MTag("mrow") << cell(0) << ETag("mrow")
235            << "<" << from_ascii(ms.namespacedTag("mo")) << " stretchy=\"true\">"
236            << from_ascii(decoration)
237            << "</" << from_ascii(ms.namespacedTag("mo")) << ">"
238            << ETag(outag);
239 }
240
241
242 void InsetMathDecoration::htmlize(HtmlStream & os) const
243 {
244         string const name = to_utf8(key_->name);
245         if (name == "bar") {
246                 os << MTag("span", "class='overbar'") << cell(0) << ETag("span");
247                 return;
248         }
249
250         if (name == "underbar" || name == "underline") {
251                 os << MTag("span", "class='underbar'") << cell(0) << ETag("span");
252                 return;
253         }
254
255         TranslationMap const & t = translationMap();
256         TranslationMap::const_iterator cur = t.find(name);
257         LASSERT(cur != t.end(), return);
258
259         bool symontop = cur->second.over;
260         string const symclass = symontop ? "symontop" : "symonbot";
261         os << MTag("span", "class='symbolpair " + symclass + "'")
262            << '\n';
263
264         if (symontop)
265                 os << MTag("span", "class='symbol'") << from_ascii(cur->second.tag);
266         else
267                 os << MTag("span", "class='base'") << cell(0);
268         os << ETag("span") << '\n';
269         if (symontop)
270                 os << MTag("span", "class='base'") << cell(0);
271         else
272                 os << MTag("span", "class='symbol'") << from_ascii(cur->second.tag);
273         os << ETag("span") << '\n' << ETag("span") << '\n';
274 }
275
276
277 // ideas borrowed from the eLyXer code
278 void InsetMathDecoration::validate(LaTeXFeatures & features) const
279 {
280         if (features.runparams().math_flavor == OutputParams::MathAsHTML) {
281                 string const name = to_utf8(key_->name);
282                 if (name == "bar") {
283                         features.addCSSSnippet("span.overbar{border-top: thin black solid;}");
284                 } else if (name == "underbar" || name == "underline") {
285                         features.addCSSSnippet("span.underbar{border-bottom: thin black solid;}");
286                 } else {
287                         features.addCSSSnippet(
288                                 "span.symbolpair{display: inline-block; text-align:center;}\n"
289                                 "span.symontop{vertical-align: top;}\n"
290                                 "span.symonbot{vertical-align: bottom;}\n"
291                                 "span.symbolpair span{display: block;}\n"
292                                 "span.symbol{height: 0.5ex;}");
293                 }
294         } else {
295                 if (!key_->required.empty())
296                         features.require(key_->required);
297         }
298         InsetMathNest::validate(features);
299 }
300
301 } // namespace lyx