1 /**
2  * \file InsetMathBox.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  * \author Ling Li (InsetMathMakebox)
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11 
12 #include <config.h>
13 
14 #include "InsetMathBox.h"
15 
16 #include "LaTeXFeatures.h"
17 #include "MathData.h"
18 #include "MathStream.h"
19 #include "MathSupport.h"
20 #include "MetricsInfo.h"
21 
22 #include "support/gettext.h"
23 #include "support/lstrings.h"
24 
25 #include "frontends/Painter.h"
26 
27 #include <algorithm>
28 #include <ostream>
29 
30 using namespace lyx::support;
31 
32 namespace lyx {
33 
34 /////////////////////////////////////////////////////////////////////
35 //
36 // InsetMathBox
37 //
38 /////////////////////////////////////////////////////////////////////
39 
InsetMathBox(Buffer * buf,docstring const & name)40 InsetMathBox::InsetMathBox(Buffer * buf, docstring const & name)
41 	: InsetMathNest(buf, 1), name_(name)
42 {}
43 
44 
write(WriteStream & os) const45 void InsetMathBox::write(WriteStream & os) const
46 {
47 	ModeSpecifier specifier(os, TEXT_MODE);
48 	os << '\\' << name_ << '{' << cell(0) << '}';
49 }
50 
51 
normalize(NormalStream & os) const52 void InsetMathBox::normalize(NormalStream & os) const
53 {
54 	os << '[' << name_ << ' ';
55 	//text_->write(buffer(), os);
56 	os << "] ";
57 }
58 
59 
mathmlize(MathStream & ms) const60 void InsetMathBox::mathmlize(MathStream & ms) const
61 {
62 	// FIXME XHTML
63 	// Need to do something special for tags here.
64 	// Probably will have to involve deferring them, which
65 	// means returning something from this routine.
66 	SetMode textmode(ms, true);
67 	ms << MTag("mstyle", "class='mathbox'")
68 	   << cell(0)
69 	   << ETag("mstyle");
70 }
71 
72 
htmlize(HtmlStream & ms) const73 void InsetMathBox::htmlize(HtmlStream & ms) const
74 {
75 	SetHTMLMode textmode(ms, true);
76 	ms << MTag("span", "class='mathbox'")
77 	   << cell(0)
78 	   << ETag("span");
79 }
80 
81 
metrics(MetricsInfo & mi,Dimension & dim) const82 void InsetMathBox::metrics(MetricsInfo & mi, Dimension & dim) const
83 {
84 	Changer dummy = mi.base.changeFontSet("textnormal");
85 	cell(0).metrics(mi, dim);
86 }
87 
88 
draw(PainterInfo & pi,int x,int y) const89 void InsetMathBox::draw(PainterInfo & pi, int x, int y) const
90 {
91 	Changer dummy = pi.base.changeFontSet("textnormal");
92 	cell(0).draw(pi, x, y);
93 }
94 
95 
infoize(odocstream & os) const96 void InsetMathBox::infoize(odocstream & os) const
97 {
98 	os << bformat(_("Box: %1$s"), name_);
99 }
100 
101 
validate(LaTeXFeatures & features) const102 void InsetMathBox::validate(LaTeXFeatures & features) const
103 {
104 	// FIXME XHTML
105 	// It'd be better to be able to get this from an InsetLayout, but at present
106 	// InsetLayouts do not seem really to work for things that aren't InsetTexts.
107 	if (features.runparams().math_flavor == OutputParams::MathAsMathML)
108 		features.addCSSSnippet("mstyle.mathbox { font-style: normal; }");
109 	else if (features.runparams().math_flavor == OutputParams::MathAsHTML)
110 		features.addCSSSnippet("span.mathbox { font-style: normal; }");
111 
112 	if (name_ == "tag" || name_ == "tag*")
113 		features.require("amsmath");
114 
115 	InsetMathNest::validate(features);
116 }
117 
118 
119 
120 /////////////////////////////////////////////////////////////////////
121 //
122 // InsetMathFBox
123 //
124 /////////////////////////////////////////////////////////////////////
125 
126 
InsetMathFBox(Buffer * buf)127 InsetMathFBox::InsetMathFBox(Buffer * buf)
128 	: InsetMathNest(buf, 1)
129 {}
130 
131 
metrics(MetricsInfo & mi,Dimension & dim) const132 void InsetMathFBox::metrics(MetricsInfo & mi, Dimension & dim) const
133 {
134 	Changer dummy = mi.base.changeFontSet("textnormal");
135 	cell(0).metrics(mi, dim);
136 	// 1 pixel space, 1 frame, 1 space
137 	dim.wid += 2 * 3;
138 	dim.asc += 3;
139 	dim.des += 3;
140 }
141 
142 
draw(PainterInfo & pi,int x,int y) const143 void InsetMathFBox::draw(PainterInfo & pi, int x, int y) const
144 {
145 	Dimension const dim = dimension(*pi.base.bv);
146 	pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
147 		dim.width() - 2, dim.height() - 2, Color_foreground);
148 	Changer dummy = pi.base.changeFontSet("textnormal");
149 	cell(0).draw(pi, x + 3, y);
150 }
151 
152 
write(WriteStream & os) const153 void InsetMathFBox::write(WriteStream & os) const
154 {
155 	ModeSpecifier specifier(os, TEXT_MODE);
156 	os << "\\fbox{" << cell(0) << '}';
157 }
158 
159 
normalize(NormalStream & os) const160 void InsetMathFBox::normalize(NormalStream & os) const
161 {
162 	os << "[fbox " << cell(0) << ']';
163 }
164 
165 
mathmlize(MathStream & ms) const166 void InsetMathFBox::mathmlize(MathStream & ms) const
167 {
168 	SetMode textmode(ms, true);
169 	ms << MTag("mstyle", "class='fbox'")
170 	   << cell(0)
171 	   << ETag("mstyle");
172 }
173 
174 
htmlize(HtmlStream & ms) const175 void InsetMathFBox::htmlize(HtmlStream & ms) const
176 {
177 	SetHTMLMode textmode(ms, true);
178 	ms << MTag("span", "class='fbox'")
179 	   << cell(0)
180 	   << ETag("span");
181 }
182 
183 
infoize(odocstream & os) const184 void InsetMathFBox::infoize(odocstream & os) const
185 {
186 	os << "FBox: ";
187 }
188 
189 
validate(LaTeXFeatures & features) const190 void InsetMathFBox::validate(LaTeXFeatures & features) const
191 {
192 	// FIXME XHTML
193 	// It'd be better to be able to get this from an InsetLayout, but at present
194 	// InsetLayouts do not seem really to work for things that aren't InsetTexts.
195 	if (features.runparams().math_flavor == OutputParams::MathAsMathML)
196 		features.addCSSSnippet(
197 			"mstyle.fbox { border: 1px solid black; font-style: normal; padding: 0.5ex; }");
198 	else if (features.runparams().math_flavor == OutputParams::MathAsHTML)
199 		features.addCSSSnippet(
200 			"span.fbox { border: 1px solid black; font-style: normal; padding: 0.5ex; }");
201 
202 	cell(0).validate(features);
203 	InsetMathNest::validate(features);
204 }
205 
206 
207 
208 /////////////////////////////////////////////////////////////////////
209 //
210 // InsetMathMakebox
211 //
212 /////////////////////////////////////////////////////////////////////
213 
214 
InsetMathMakebox(Buffer * buf,bool framebox)215 InsetMathMakebox::InsetMathMakebox(Buffer * buf, bool framebox)
216 	: InsetMathNest(buf, 3), framebox_(framebox)
217 {}
218 
219 
metrics(MetricsInfo & mi,Dimension & dim) const220 void InsetMathMakebox::metrics(MetricsInfo & mi, Dimension & dim) const
221 {
222 	Changer dummy = mi.base.changeFontSet("textnormal");
223 
224 	Dimension wdim;
225 	static docstring bracket = from_ascii("[");
226 	metricsStrRedBlack(mi, wdim, bracket);
227 	int w = wdim.wid;
228 
229 	Dimension dim0;
230 	Dimension dim1;
231 	Dimension dim2;
232 	cell(0).metrics(mi, dim0);
233 	cell(1).metrics(mi, dim1);
234 	cell(2).metrics(mi, dim2);
235 
236 	dim.wid = w + dim0.wid + w + w + dim1.wid + w + 2 + dim2.wid;
237 	dim.asc = std::max(std::max(wdim.asc, dim0.asc), std::max(dim1.asc, dim2.asc));
238 	dim.des = std::max(std::max(wdim.des, dim0.des), std::max(dim1.des, dim2.des));
239 
240 	if (framebox_) {
241 		dim.wid += 4;
242 		dim.asc += 3;
243 		dim.des += 2;
244 	} else {
245 		dim.asc += 1;
246 		dim.des += 1;
247 	}
248 }
249 
250 
draw(PainterInfo & pi,int x,int y) const251 void InsetMathMakebox::draw(PainterInfo & pi, int x, int y) const
252 {
253 	Changer dummy = pi.base.changeFontSet("textnormal");
254 	BufferView const & bv = *pi.base.bv;
255 	int w = mathed_char_width(pi.base.font, '[');
256 
257 	if (framebox_) {
258 		Dimension const dim = dimension(*pi.base.bv);
259 		pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
260 				  dim.width() - 2, dim.height() - 2, Color_foreground);
261 		x += 2;
262 	}
263 
264 	drawStrBlack(pi, x, y, from_ascii("["));
265 	x += w;
266 	cell(0).draw(pi, x, y);
267 	x += cell(0).dimension(bv).wid;
268 	drawStrBlack(pi, x, y, from_ascii("]"));
269 	x += w;
270 
271 	drawStrBlack(pi, x, y, from_ascii("["));
272 	x += w;
273 	cell(1).draw(pi, x, y);
274 	x += cell(1).dimension(bv).wid;
275 	drawStrBlack(pi, x, y, from_ascii("]"));
276 	x += w + 2;
277 
278 	cell(2).draw(pi, x, y);
279 }
280 
281 
write(WriteStream & os) const282 void InsetMathMakebox::write(WriteStream & os) const
283 {
284 	ModeSpecifier specifier(os, TEXT_MODE);
285 	os << (framebox_ ? "\\framebox" : "\\makebox");
286 	if (!cell(0).empty() || !os.latex()) {
287 		os << '[' << cell(0) << ']';
288 		if (!cell(1).empty() || !os.latex())
289 			os << '[' << cell(1) << ']';
290 	}
291 	os << '{' << cell(2) << '}';
292 }
293 
294 
normalize(NormalStream & os) const295 void InsetMathMakebox::normalize(NormalStream & os) const
296 {
297 	os << (framebox_ ? "[framebox " : "[makebox ")
298 	   << cell(0) << ' ' << cell(1) << ' ' << cell(2) << ']';
299 }
300 
301 
infoize(odocstream & os) const302 void InsetMathMakebox::infoize(odocstream & os) const
303 {
304 	os << (framebox_ ? "Framebox" : "Makebox")
305 	   << " (width: " << cell(0)
306 	   << " pos: " << cell(1) << ")";
307 }
308 
309 
mathmlize(MathStream & ms) const310 void InsetMathMakebox::mathmlize(MathStream & ms) const
311 {
312 	// FIXME We could do something with the other arguments.
313 	std::string const cssclass = framebox_ ? "framebox" : "makebox";
314 	SetMode textmode(ms, true);
315 	ms << MTag("mstyle", "class='" + cssclass + "'")
316 	   << cell(2)
317 	   << ETag("mstyle");
318 }
319 
320 
htmlize(HtmlStream & ms) const321 void InsetMathMakebox::htmlize(HtmlStream & ms) const
322 {
323 	// FIXME We could do something with the other arguments.
324 	SetHTMLMode textmode(ms, true);
325 	std::string const cssclass = framebox_ ? "framebox" : "makebox";
326 	ms << MTag("span", "class='" + cssclass + "'")
327 	   << cell(2)
328 	   << ETag("span");
329 }
330 
331 
validate(LaTeXFeatures & features) const332 void InsetMathMakebox::validate(LaTeXFeatures & features) const
333 {
334 	// FIXME XHTML
335 	// It'd be better to be able to get this from an InsetLayout, but at present
336 	// InsetLayouts do not seem really to work for things that aren't InsetTexts.
337 	if (features.runparams().math_flavor == OutputParams::MathAsMathML)
338 		features.addCSSSnippet("mstyle.framebox { border: 1px solid black; }");
339 	else if (features.runparams().math_flavor == OutputParams::MathAsHTML)
340 		features.addCSSSnippet("span.framebox { border: 1px solid black; }");
341 	InsetMathNest::validate(features);
342 }
343 
344 
345 /////////////////////////////////////////////////////////////////////
346 //
347 // InsetMathBoxed
348 //
349 /////////////////////////////////////////////////////////////////////
350 
InsetMathBoxed(Buffer * buf)351 InsetMathBoxed::InsetMathBoxed(Buffer * buf)
352 	: InsetMathNest(buf, 1)
353 {}
354 
355 
metrics(MetricsInfo & mi,Dimension & dim) const356 void InsetMathBoxed::metrics(MetricsInfo & mi, Dimension & dim) const
357 {
358 	cell(0).metrics(mi, dim);
359 	// 1 pixel space, 1 frame, 1 space
360 	dim.wid += 2 * 3;
361 	dim.asc += 3;
362 	dim.des += 3;
363 }
364 
365 
draw(PainterInfo & pi,int x,int y) const366 void InsetMathBoxed::draw(PainterInfo & pi, int x, int y) const
367 {
368 	Dimension const dim = dimension(*pi.base.bv);
369 	pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
370 		dim.width() - 2, dim.height() - 2, Color_foreground);
371 	cell(0).draw(pi, x + 3, y);
372 }
373 
374 
write(WriteStream & os) const375 void InsetMathBoxed::write(WriteStream & os) const
376 {
377 	ModeSpecifier specifier(os, MATH_MODE);
378 	os << "\\boxed{" << cell(0) << '}';
379 }
380 
381 
normalize(NormalStream & os) const382 void InsetMathBoxed::normalize(NormalStream & os) const
383 {
384 	os << "[boxed " << cell(0) << ']';
385 }
386 
387 
infoize(odocstream & os) const388 void InsetMathBoxed::infoize(odocstream & os) const
389 {
390 	os << "Boxed: ";
391 }
392 
393 
mathmlize(MathStream & ms) const394 void InsetMathBoxed::mathmlize(MathStream & ms) const
395 {
396 	ms << MTag("mstyle", "class='boxed'")
397 	   << cell(0)
398 	   << ETag("mstyle");
399 }
400 
401 
htmlize(HtmlStream & ms) const402 void InsetMathBoxed::htmlize(HtmlStream & ms) const
403 {
404 	ms << MTag("span", "class='boxed'")
405 	   << cell(0)
406 		 << ETag("span");
407 }
408 
409 
validate(LaTeXFeatures & features) const410 void InsetMathBoxed::validate(LaTeXFeatures & features) const
411 {
412 	features.require("amsmath");
413 
414 	// FIXME XHTML
415 	// It'd be better to be able to get this from an InsetLayout, but at present
416 	// InsetLayouts do not seem really to work for things that aren't InsetTexts.
417 	if (features.runparams().math_flavor == OutputParams::MathAsMathML)
418 		features.addCSSSnippet("mstyle.boxed { border: 1px solid black; }");
419 	else if (features.runparams().math_flavor == OutputParams::MathAsHTML)
420 		features.addCSSSnippet("span.boxed { border: 1px solid black; }");
421 
422 	InsetMathNest::validate(features);
423 }
424 
425 
426 } // namespace lyx
427