2 * \file InsetMathBox.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
7 * \author Ling Li (InsetMathMakebox)
9 * Full author contact details are available in file CREDITS.
14 #include "InsetMathBox.h"
16 #include "LaTeXFeatures.h"
18 #include "MathStream.h"
19 #include "MathSupport.h"
20 #include "MetricsInfo.h"
22 #include "support/gettext.h"
23 #include "support/lstrings.h"
25 #include "frontends/Painter.h"
31 using namespace lyx::support;
35 /////////////////////////////////////////////////////////////////////
39 /////////////////////////////////////////////////////////////////////
41 InsetMathBox::InsetMathBox(Buffer * buf, docstring const & name)
42 : InsetMathNest(buf, 1), name_(name)
46 void InsetMathBox::write(TeXMathStream & os) const
48 ModeSpecifier specifier(os, TEXT_MODE);
49 os << '\\' << name_ << '{' << cell(0) << '}';
53 void InsetMathBox::normalize(NormalStream & os) const
55 os << '[' << name_ << ' ';
56 //text_->write(buffer(), os);
62 void splitAndWrapInMText(MathMLStream & ms, MathData const & cell,
63 const std::string & attributes)
65 // First, generate the inset into a string of its own.
66 docstring inset_contents;
68 odocstringstream ostmp;
69 MathMLStream mstmp(ostmp, ms.xmlns());
71 SetMode textmode(mstmp, true);
74 inset_contents = ostmp.str();
77 // No tags are allowed within <m:mtext>: split the string if there are tags.
78 std::vector<docstring> parts;
80 std::size_t angle_pos = inset_contents.find('<');
81 if (angle_pos == docstring::npos)
85 // - prefix: pure text, no tag
86 // - tag to split: something like <m:mn>1</m:mn> or more complicated
87 // (like nested tags), with or without name space
88 // - rest to be taken care of in the next iteration
90 // Push the part before the tag.
91 parts.emplace_back(inset_contents.substr(0, angle_pos));
92 inset_contents = inset_contents.substr(angle_pos);
93 // Now, inset_contents starts with the tag to isolate, so that
94 // inset_contents[0] == '<'
96 // Push the tag, up to its end. Process: find the tag name (either
97 // before > or the first attribute of the tag), then the matching end
98 // tag, then proceed with pushing.
99 const std::size_t tag_name_end =
100 std::min(inset_contents.find(' ', 1), inset_contents.find('>', 1));
101 const std::size_t tag_name_length = tag_name_end - 1;
102 const docstring tag_name = inset_contents.substr(1, tag_name_length);
104 const std::size_t end_tag_start =
105 inset_contents.find(tag_name, tag_name_end + 1);
106 const std::size_t end_tag = inset_contents.find('>', end_tag_start);
108 parts.emplace_back(inset_contents.substr(0, end_tag + 1));
109 inset_contents = inset_contents.substr(end_tag + 1);
111 parts.emplace_back(inset_contents);
113 // Finally, output the complete inset: escape the test in <m:mtext>, leave
114 // the other tags untouched.
115 ms << MTag("mrow", attributes);
116 for (std::size_t i = 0; i < parts.size(); i += 2) {
120 if (parts.size() > i + 1)
128 void InsetMathBox::mathmlize(MathMLStream & ms) const
131 // Need to do something special for tags here.
132 // Probably will have to involve deferring them, which
133 // means returning something from this routine.
134 splitAndWrapInMText(ms, cell(0), "class='mathbox'");
138 void InsetMathBox::htmlize(HtmlStream & ms) const
140 SetHTMLMode textmode(ms, true);
141 ms << MTag("span", "class='mathbox'")
147 void InsetMathBox::metrics(MetricsInfo & mi, Dimension & dim) const
149 Changer dummy = mi.base.changeFontSet("textnormal");
150 cell(0).metrics(mi, dim);
154 void InsetMathBox::draw(PainterInfo & pi, int x, int y) const
156 Changer dummy = pi.base.changeFontSet("textnormal");
157 cell(0).draw(pi, x, y);
161 void InsetMathBox::infoize(odocstream & os) const
163 os << bformat(_("Box: %1$s"), name_);
167 void InsetMathBox::validate(LaTeXFeatures & features) const
170 // It'd be better to be able to get this from an InsetLayout, but at present
171 // InsetLayouts do not seem really to work for things that aren't InsetTexts.
172 if (features.runparams().math_flavor == OutputParams::MathAsMathML)
173 features.addCSSSnippet("mtext.mathbox { font-style: normal; }");
174 else if (features.runparams().math_flavor == OutputParams::MathAsHTML)
175 features.addCSSSnippet("span.mathbox { font-style: normal; }");
177 if (name_ == "tag" || name_ == "tag*")
178 features.require("amsmath");
180 InsetMathNest::validate(features);
185 /////////////////////////////////////////////////////////////////////
189 /////////////////////////////////////////////////////////////////////
192 InsetMathFBox::InsetMathFBox(Buffer * buf)
193 : InsetMathNest(buf, 1)
197 void InsetMathFBox::metrics(MetricsInfo & mi, Dimension & dim) const
199 Changer dummy = mi.base.changeFontSet("textnormal");
200 cell(0).metrics(mi, dim);
201 // 1 pixel space, 1 frame, 1 space
208 void InsetMathFBox::draw(PainterInfo & pi, int x, int y) const
210 Dimension const dim = dimension(*pi.base.bv);
211 pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
212 dim.width() - 2, dim.height() - 2, Color_foreground);
213 Changer dummy = pi.base.changeFontSet("textnormal");
214 cell(0).draw(pi, x + 3, y);
218 void InsetMathFBox::write(TeXMathStream & os) const
220 ModeSpecifier specifier(os, TEXT_MODE);
221 os << "\\fbox{" << cell(0) << '}';
225 void InsetMathFBox::normalize(NormalStream & os) const
227 os << "[fbox " << cell(0) << ']';
231 void InsetMathFBox::mathmlize(MathMLStream & ms) const
233 splitAndWrapInMText(ms, cell(0), "class='fbox'");
237 void InsetMathFBox::htmlize(HtmlStream & ms) const
239 SetHTMLMode textmode(ms, true);
240 ms << MTag("span", "class='fbox'")
246 void InsetMathFBox::infoize(odocstream & os) const
252 void InsetMathFBox::validate(LaTeXFeatures & features) const
255 // It'd be better to be able to get this from an InsetLayout, but at present
256 // InsetLayouts do not seem really to work for things that aren't InsetTexts.
257 if (features.runparams().math_flavor == OutputParams::MathAsMathML)
258 features.addCSSSnippet(
259 "mtext.fbox { border: 1px solid black; font-style: normal; padding: 0.5ex; }");
260 else if (features.runparams().math_flavor == OutputParams::MathAsHTML)
261 features.addCSSSnippet(
262 "span.fbox { border: 1px solid black; font-style: normal; padding: 0.5ex; }");
264 cell(0).validate(features);
265 InsetMathNest::validate(features);
270 /////////////////////////////////////////////////////////////////////
274 /////////////////////////////////////////////////////////////////////
277 InsetMathMakebox::InsetMathMakebox(Buffer * buf, bool framebox)
278 : InsetMathNest(buf, 3), framebox_(framebox)
282 void InsetMathMakebox::metrics(MetricsInfo & mi, Dimension & dim) const
284 Changer dummy = mi.base.changeFontSet("textnormal");
287 static docstring bracket = from_ascii("[");
288 metricsStrRedBlack(mi, wdim, bracket);
294 cell(0).metrics(mi, dim0);
295 cell(1).metrics(mi, dim1);
296 cell(2).metrics(mi, dim2);
298 dim.wid = w + dim0.wid + w + w + dim1.wid + w + 2 + dim2.wid;
299 dim.asc = std::max(std::max(wdim.asc, dim0.asc), std::max(dim1.asc, dim2.asc));
300 dim.des = std::max(std::max(wdim.des, dim0.des), std::max(dim1.des, dim2.des));
313 void InsetMathMakebox::draw(PainterInfo & pi, int x, int y) const
315 Changer dummy = pi.base.changeFontSet("textnormal");
316 BufferView const & bv = *pi.base.bv;
317 int w = mathed_char_width(pi.base.font, '[');
320 Dimension const dim = dimension(*pi.base.bv);
321 pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
322 dim.width() - 2, dim.height() - 2, Color_foreground);
326 drawStrBlack(pi, x, y, from_ascii("["));
328 cell(0).draw(pi, x, y);
329 x += cell(0).dimension(bv).wid;
330 drawStrBlack(pi, x, y, from_ascii("]"));
333 drawStrBlack(pi, x, y, from_ascii("["));
335 cell(1).draw(pi, x, y);
336 x += cell(1).dimension(bv).wid;
337 drawStrBlack(pi, x, y, from_ascii("]"));
340 cell(2).draw(pi, x, y);
344 void InsetMathMakebox::write(TeXMathStream & os) const
346 ModeSpecifier specifier(os, TEXT_MODE);
347 os << (framebox_ ? "\\framebox" : "\\makebox");
348 if (!cell(0).empty() || !os.latex()) {
349 os << '[' << cell(0) << ']';
350 if (!cell(1).empty() || !os.latex())
351 os << '[' << cell(1) << ']';
353 os << '{' << cell(2) << '}';
357 void InsetMathMakebox::normalize(NormalStream & os) const
359 os << (framebox_ ? "[framebox " : "[makebox ")
360 << cell(0) << ' ' << cell(1) << ' ' << cell(2) << ']';
364 void InsetMathMakebox::infoize(odocstream & os) const
366 os << (framebox_ ? "Framebox" : "Makebox")
367 << " (width: " << cell(0)
368 << " pos: " << cell(1) << ")";
372 void InsetMathMakebox::mathmlize(MathMLStream & ms) const
374 // FIXME We could do something with the other arguments.
375 std::string const cssclass = framebox_ ? "framebox" : "makebox";
376 splitAndWrapInMText(ms, cell(2), "class='" + cssclass + "'");
380 void InsetMathMakebox::htmlize(HtmlStream & ms) const
382 // FIXME We could do something with the other arguments.
383 SetHTMLMode textmode(ms, true);
384 std::string const cssclass = framebox_ ? "framebox" : "makebox";
385 ms << MTag("span", "class='" + cssclass + "'")
391 void InsetMathMakebox::validate(LaTeXFeatures & features) const
394 // It'd be better to be able to get this from an InsetLayout, but at present
395 // InsetLayouts do not seem really to work for things that aren't InsetTexts.
396 if (features.runparams().math_flavor == OutputParams::MathAsMathML)
397 features.addCSSSnippet("mtext.framebox { border: 1px solid black; }");
398 else if (features.runparams().math_flavor == OutputParams::MathAsHTML)
399 features.addCSSSnippet("span.framebox { border: 1px solid black; }");
400 InsetMathNest::validate(features);
404 /////////////////////////////////////////////////////////////////////
408 /////////////////////////////////////////////////////////////////////
410 InsetMathBoxed::InsetMathBoxed(Buffer * buf)
411 : InsetMathNest(buf, 1)
415 void InsetMathBoxed::metrics(MetricsInfo & mi, Dimension & dim) const
417 cell(0).metrics(mi, dim);
418 // 1 pixel space, 1 frame, 1 space
425 void InsetMathBoxed::draw(PainterInfo & pi, int x, int y) const
427 Dimension const dim = dimension(*pi.base.bv);
428 pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
429 dim.width() - 2, dim.height() - 2, Color_foreground);
430 cell(0).draw(pi, x + 3, y);
434 void InsetMathBoxed::write(TeXMathStream & os) const
436 ModeSpecifier specifier(os, MATH_MODE);
437 os << "\\boxed{" << cell(0) << '}';
441 void InsetMathBoxed::normalize(NormalStream & os) const
443 os << "[boxed " << cell(0) << ']';
447 void InsetMathBoxed::infoize(odocstream & os) const
453 void InsetMathBoxed::mathmlize(MathMLStream & ms) const
455 splitAndWrapInMText(ms, cell(0), "class='boxed'");
459 void InsetMathBoxed::htmlize(HtmlStream & ms) const
461 ms << MTag("span", "class='boxed'")
467 void InsetMathBoxed::validate(LaTeXFeatures & features) const
469 features.require("amsmath");
472 // It'd be better to be able to get this from an InsetLayout, but at present
473 // InsetLayouts do not seem really to work for things that aren't InsetTexts.
474 if (features.runparams().math_flavor == OutputParams::MathAsMathML)
475 features.addCSSSnippet("mtext.boxed { border: 1px solid black; }");
476 else if (features.runparams().math_flavor == OutputParams::MathAsHTML)
477 features.addCSSSnippet("span.boxed { border: 1px solid black; }");
479 InsetMathNest::validate(features);