2 * \file InsetMathRoot.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alejandro Aguilar Sierra
9 * Full author contact details are available in file CREDITS.
14 #include "InsetMathRoot.h"
16 #include "MathStream.h"
17 #include "MathSupport.h"
20 #include "LaTeXFeatures.h"
21 #include "MetricsInfo.h"
23 #include "frontends/Painter.h"
30 using namespace frontend;
32 InsetMathRoot::InsetMathRoot(Buffer * buf)
33 : InsetMathNest(buf, 2)
37 Inset * InsetMathRoot::clone() const
39 return new InsetMathRoot(*this);
43 void mathed_root_metrics(MetricsInfo & mi, MathData const & nucleus,
44 MathData const * root, Dimension & dim)
46 Changer dummy = mi.base.changeEnsureMath();
49 Changer script = mi.base.font.changeStyle(LM_ST_SCRIPTSCRIPT);
50 // make sure that the dim is high enough for any character
51 root->metrics(mi, dimr, false);
55 nucleus.metrics(mi, dimn);
57 // Some room for the decoration
58 // The width of left decoration was 9 pixels with a 10em font
59 int const w = 9 * mathed_font_em(mi.base.font) / 10;
60 /* See rule 11 in Appendix G of Rhe TeXbook for the computation of the spacing
62 * FIXME more work is needed to implement properly rule 11.
63 * * Ideally, we should use sqrt glyphs from the math fonts. Note
64 that then we would get rule thickness from there.
65 * * The positioning of the root MathData is arbitrary. It should
66 * follow the definition of \root...\of... in The Texbook in
67 * Apprendix B page 360.
70 int const t = mi.base.solidLineThickness();
71 int const x_height = mathed_font_x_height(mi.base.font);
72 int const phi = (mi.base.font.style() == LM_ST_DISPLAY) ? x_height : t;
73 // first part is the spacing, second part is the line width
74 // itself, and last one is the spacing above.
75 int const space_above = (t + phi / 4) + t + t;
76 int const a = dimn.ascent();
77 int const d = dimn.descent();
78 // Not sure what the 1 stands for, it is needed to have some spacing at small sizes.
79 dim.asc = max(dimr.ascent() + (d - a) / 2, a + space_above) + 1;
80 dim.des = max(dimr.descent() - (d - a) / 2, d);
81 dim.wid = max(dimr.width() + 3 * w / 8, w) + dimn.width();
85 void InsetMathRoot::metrics(MetricsInfo & mi, Dimension & dim) const
87 mathed_root_metrics(mi, cell(1), &cell(0), dim);
91 void mathed_draw_root(PainterInfo & pi, int x, int y, MathData const & nucleus,
92 MathData const * root, Dimension const & dim)
94 Changer dummy = pi.base.changeEnsureMath();
95 // The width of left decoration was 9 pixels with a 10em font
96 int const w = 9 * mathed_font_em(pi.base.font) / 10;
97 // the height of the hook was 5 with a 10em font
98 int const h = 5 * mathed_font_em(pi.base.font) / 10;
99 int const a = dim.ascent();
100 int const d = dim.descent();
101 int const t = pi.base.solidLineThickness();
102 Dimension const dimn = nucleus.dimension(*pi.base.bv);
103 // the width of the left part of the root
104 int const wl = dim.width() - dimn.width();
107 Changer script = pi.base.font.changeStyle(LM_ST_SCRIPTSCRIPT);
108 Dimension const dimr = root->dimension(*pi.base.bv);
109 int const root_offset = wl - 3 * w / 8 - dimr.width();
110 root->draw(pi, x + root_offset, y + (d - a)/2);
113 nucleus.draw(pi, x + wl, y);
116 pi.pain.line(x + dim.width(), y - a + 2 * t,
117 x + wl, y - a + 2 * t, pi.base.font.color(),
118 Painter::line_solid, t);
119 xp[0] = x + wl; yp[0] = y - a + 2 * t + 1;
120 xp[1] = x + wl - w / 2; yp[1] = y + d;
121 xp[2] = x + wl - w + h / 4; yp[2] = y + d - h;
122 xp[3] = x + wl - w; yp[3] = y + d - h + h / 4;
123 pi.pain.lines(xp, yp, 4, pi.base.font.color(),
124 Painter::fill_none, Painter::line_solid, t);
128 void InsetMathRoot::draw(PainterInfo & pi, int x, int y) const
130 mathed_draw_root(pi, x, y, cell(1), &cell(0), dimension(*pi.base.bv));
134 void InsetMathRoot::write(WriteStream & os) const
136 MathEnsurer ensurer(os);
137 os << "\\sqrt[" << cell(0) << "]{" << cell(1) << '}';
141 void InsetMathRoot::normalize(NormalStream & os) const
143 os << "[root " << cell(0) << ' ' << cell(1) << ']';
147 bool InsetMathRoot::idxUpDown(Cursor & cur, bool up) const
149 Cursor::idx_type const target = up ? 0 : 1;
150 if (cur.idx() == target)
153 cur.pos() = up ? cur.lastpos() : 0;
158 void InsetMathRoot::maple(MapleStream & os) const
160 os << '(' << cell(1) << ")^(1/(" << cell(0) <<"))";
164 void InsetMathRoot::mathematica(MathematicaStream & os) const
166 os << '(' << cell(1) << ")^(1/(" << cell(0) <<"))";
170 void InsetMathRoot::octave(OctaveStream & os) const
172 os << '(' << cell(1) << ")^(1/(" << cell(0) <<"))";
176 void InsetMathRoot::mathmlize(MathStream & os) const
178 os << MTag("mroot") << cell(1) << cell(0) << ETag("mroot");
182 void InsetMathRoot::htmlize(HtmlStream & os) const
184 os << MTag("span", "class='root'")
185 << MTag("sup") << cell(0) << ETag("sup")
186 << from_ascii("√")
187 << MTag("span", "class='rootof'") << cell(1) << ETag("span")
192 void InsetMathRoot::validate(LaTeXFeatures & features) const
194 if (features.runparams().math_flavor == OutputParams::MathAsHTML)
195 features.addCSSSnippet(
196 "span.rootof{border-top: thin solid black;}\n"
197 "span.root sup{font-size: 75%;}");
198 InsetMathNest::validate(features);