2 * \file InsetMathSideset.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
9 * Full author contact details are available in file CREDITS.
14 #include "BufferView.h"
16 #include "DispatchResult.h"
17 #include "FuncRequest.h"
18 #include "FuncStatus.h"
19 #include "InsetMathSideset.h"
20 #include "InsetMathSymbol.h"
21 #include "LaTeXFeatures.h"
23 #include "MathStream.h"
24 #include "MathSupport.h"
26 #include "support/debug.h"
28 #include "support/lassert.h"
35 /// x spacing between the nucleus and the scripts
42 InsetMathSideset::InsetMathSideset(Buffer * buf)
43 : InsetMathNest(buf, 5)
47 InsetMathSideset::InsetMathSideset(Buffer * buf, MathAtom const & at)
48 : InsetMathNest(buf, 5)
54 Inset * InsetMathSideset::clone() const
56 return new InsetMathSideset(*this);
60 bool InsetMathSideset::idxFirst(Cursor & cur) const
68 bool InsetMathSideset::idxLast(Cursor & cur) const
71 cur.pos() = nuc().size();
76 int InsetMathSideset::dybt(BufferView const & bv, int asc, int des, bool top) const
78 bool isCharBox = nuc().empty() ? false : isAlphaSymbol(nuc().back());
79 int dasc = max(bl().dimension(bv).ascent(), br().dimension(bv).ascent());
80 int slevel = nuc().slevel();
81 int ascdrop = dasc - slevel;
82 int desdrop = isCharBox ? 0 : des + nuc().sshift();
83 int mindes = nuc().mindes();
84 des = max(desdrop, ascdrop);
85 des = max(mindes, des);
86 int minasc = nuc().minasc();
87 ascdrop = isCharBox ? 0 : asc - min(tl().mindes(), tr().mindes());
88 int udes = max(bl().dimension(bv).descent(), tr().dimension(bv).descent());
89 asc = udes + nuc().sshift();
90 asc = max(ascdrop, asc);
91 asc = max(minasc, asc);
92 int del = asc - udes - dasc;
95 del = slevel - asc + udes;
100 des = max(des, newdes);
102 return top ? asc : des;
106 int InsetMathSideset::dyb(BufferView const & bv) const
109 int des = max(bl().dimension(bv).ascent(), br().dimension(bv).ascent());
111 des = dybt(bv, na, nd, false);
116 int InsetMathSideset::dyt(BufferView const & bv) const
119 int asc = max(tl().dimension(bv).descent(), tr().dimension(bv).descent());
121 asc = dybt(bv, na, nd, true);
126 int InsetMathSideset::dxr(BufferView const & bv) const
128 return dxn(bv) + nwid(bv) + dx;
132 int InsetMathSideset::dxn(BufferView const & bv) const
134 Dimension const dimb = bl().dimension(bv);
135 Dimension const dimt = tl().dimension(bv);
136 return max(dimb.width(), dimt.width()) + dx;
140 int InsetMathSideset::nwid(BufferView const & bv) const
142 return nuc().dimension(bv).width();
146 int InsetMathSideset::nasc(BufferView const & bv) const
148 return nuc().dimension(bv).ascent();
152 int InsetMathSideset::ndes(BufferView const & bv) const
154 return nuc().dimension(bv).descent();
158 int InsetMathSideset::nker(BufferView const * bv) const
160 int const kerning = nuc().kerning(bv);
161 return max(kerning, 0);
165 void InsetMathSideset::metrics(MetricsInfo & mi, Dimension & dim) const
172 nuc().metrics(mi, dimn);
173 ScriptChanger dummy(mi.base);
174 bl().metrics(mi, dimbl);
175 tl().metrics(mi, dimtl);
176 br().metrics(mi, dimbr);
177 tr().metrics(mi, dimtr);
179 BufferView & bv = *mi.base.bv;
180 // FIXME: data copying... not very efficient.
182 dim.wid = nwid(bv) + nker(mi.base.bv) + 2 * dx;
183 dim.wid += max(dimbl.width(), dimtl.width());
184 dim.wid += max(dimbr.width(), dimtr.width());
186 int asc = dyt(bv) + max(dimtl.ascent(), dimtr.ascent());
187 dim.asc = max(na, asc);
189 int des = dyb(bv) + max(dimbl.descent(), dimbr.descent());
190 dim.des = max(nd, des);
195 void InsetMathSideset::draw(PainterInfo & pi, int x, int y) const
197 BufferView & bv = *pi.base.bv;
198 nuc().draw(pi, x + dxn(bv), y);
199 ScriptChanger dummy(pi.base);
200 bl().draw(pi, x , y + dyb(bv));
201 tl().draw(pi, x , y - dyt(bv));
202 br().draw(pi, x + dxr(bv), y + dyb(bv));
203 tr().draw(pi, x + dxr(bv), y - dyt(bv));
204 drawMarkers(pi, x, y);
208 void InsetMathSideset::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
210 bl().metricsT(mi, dim);
211 tl().metricsT(mi, dim);
212 br().metricsT(mi, dim);
213 tr().metricsT(mi, dim);
214 nuc().metricsT(mi, dim);
218 void InsetMathSideset::drawT(TextPainter & pain, int x, int y) const
221 nuc().drawT(pain, x + 1, y);
222 bl().drawT(pain, x + 1, y + 1 /*dy0()*/);
223 tl().drawT(pain, x + 1, y - 1 /*dy1()*/);
224 br().drawT(pain, x + 1, y + 1 /*dy0()*/);
225 tr().drawT(pain, x + 1, y - 1 /*dy1()*/);
230 bool InsetMathSideset::idxForward(Cursor &) const
236 bool InsetMathSideset::idxBackward(Cursor &) const
242 bool InsetMathSideset::idxUpDown(Cursor & cur, bool up) const
245 if (cur.idx() == 0) {
246 // go up/down only if in the last position
247 // or in the first position
248 if (cur.pos() == cur.lastpos() || cur.pos() == 0) {
250 cur.idx() = up ? 2 : 1;
252 cur.idx() = up ? 4 : 3;
260 if (cur.idx() == 2 || cur.idx() == 4) {
261 // can't go further up
264 // otherwise go to first or last position in the nucleus
269 cur.pos() = cur.lastpos();
274 if (cur.idx() == 1 || cur.idx() == 3) {
275 // can't go further down
278 // otherwise go to first or last position in the nucleus
283 cur.pos() = cur.lastpos();
291 void InsetMathSideset::write(WriteStream & os) const
293 MathEnsurer ensurer(os);
296 for (int i = 0; i < 2; ++i) {
298 if (!cell(2*i+1).empty())
299 os << "_{" << cell(2*i+1) << '}';
300 if (!cell(2*i+2).empty())
301 os << "^{" << cell(2*i+2) << '}';
304 os << '{' << nuc() << '}';
306 if (lock_ && !os.latex())
311 void InsetMathSideset::normalize(NormalStream & os) const
333 void InsetMathSideset::mathmlize(MathStream & os) const
335 os << MTag("mmultiscripts");
340 os << MTag("mrow") << nuc() << ETag("mrow");
345 os << MTag("mrow") << br() << ETag("mrow");
349 os << MTag("mrow") << tr() << ETag("mrow");
354 os << MTag("mrow") << bl() << ETag("mrow");
358 os << MTag("mrow") << tl() << ETag("mrow");
360 os << ETag("mmultiscripts");
364 void InsetMathSideset::htmlize(HtmlStream & os) const
366 bool const havebl = !bl().empty();
367 bool const havetl = !tl().empty();
368 bool const havebr = !br().empty();
369 bool const havetr = !tr().empty();
371 if (havebl && havetl)
372 os << MTag("span", "class='scripts'")
373 << MTag("span") << tl() << ETag("span")
374 << MTag("span") << bl() << ETag("span")
377 os << MTag("sub", "class='math'") << bl() << ETag("sub");
379 os << MTag("sup", "class='math'") << tl() << ETag("sup");
384 if (havebr && havetr)
385 os << MTag("span", "class='scripts'")
386 << MTag("span") << tr() << ETag("span")
387 << MTag("span") << br() << ETag("span")
390 os << MTag("sub", "class='math'") << br() << ETag("sub");
392 os << MTag("sup", "class='math'") << tr() << ETag("sup");
396 void InsetMathSideset::infoize(odocstream & os) const
402 // the idea for dual scripts came from the eLyXer code
403 void InsetMathSideset::validate(LaTeXFeatures & features) const
405 if (features.runparams().math_flavor == OutputParams::MathAsHTML)
406 features.addCSSSnippet(
407 "span.scripts{display: inline-block; vertical-align: middle; text-align:center; font-size: 75%;}\n"
408 "span.scripts span {display: block;}\n"
409 "sub.math{font-size: 75%;}\n"
410 "sup.math{font-size: 75%;}");
411 features.require("amsmath");
412 InsetMathNest::validate(features);