lyx_mirror/src/mathed/InsetMathStackrel.cpp
Enrico Forestieri 1bdba953a5 Fix cursor left/right navigation in overset, underset, and stackrel
Before this commit, navigating with the cursor was visiting either
the nucleus or the script depending on the direction (left or right)
of the cursor movement. Now the 2.3.x behavior of always going through
the nucleus is restored (at least for overset and underset, as stackrel
seems to behave oddly also in 2.3.x).
2018-11-12 19:05:09 +01:00

196 lines
4.8 KiB
C++

/**
* \file InsetMathStackrel.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author André Pönitz
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "InsetMathStackrel.h"
#include "MathData.h"
#include "MathStream.h"
#include "Cursor.h"
#include "LaTeXFeatures.h"
#include "MetricsInfo.h"
#include "support/lassert.h"
using namespace std;
namespace lyx {
InsetMathStackrel::InsetMathStackrel(Buffer * buf, bool sub)
: InsetMathFracBase(buf, sub ? 3 : 2)
{}
Inset * InsetMathStackrel::clone() const
{
return new InsetMathStackrel(*this);
}
bool InsetMathStackrel::idxUpDown(Cursor & cur, bool up) const
{
idx_type const npos = 1234; // impossible number
idx_type target = npos;
if (up) {
idx_type const targets[] = { 1, npos, 0 };
target = targets[cur.idx()];
} else {
idx_type const targets[] = { 2, 0, npos };
target = targets[cur.idx()];
}
if (target == npos || target == nargs())
return false;
cur.idx() = target;
cur.pos() = cell(target).x2pos(&cur.bv(), cur.x_target());
return true;
}
bool InsetMathStackrel::idxFirst(Cursor & cur) const
{
LASSERT(&cur.inset() == this, return false);
cur.idx() = 0;
cur.pos() = 0;
return true;
}
bool InsetMathStackrel::idxLast(Cursor & cur) const
{
LASSERT(&cur.inset() == this, return false);
cur.idx() = 0;
cur.pos() = cur.lastpos();
return true;
}
MathClass InsetMathStackrel::mathClass() const
{
// FIXME: update this when/if \stackbin is supported
return MC_REL;
}
void InsetMathStackrel::metrics(MetricsInfo & mi, Dimension & dim) const
{
Changer dummy2 = mi.base.changeEnsureMath();
Dimension dim0;
cell(0).metrics(mi, dim0);
Changer dummy = mi.base.changeScript();
Dimension dim1;
cell(1).metrics(mi, dim1);
if (nargs() > 2) {
Dimension dim2;
cell(2).metrics(mi, dim2);
dim.wid = max(max(dim1.width(), dim0.width()), dim2.width()) + 4;
dim.asc = dim0.ascent() + dim1.height() + 4;
dim.des = dim0.descent() + dim2.height() + dim2.descent() + 1;
} else {
dim.wid = max(dim1.width(), dim0.width()) + 4;
dim.asc = dim0.ascent() + dim1.height() + 4;
dim.des = dim0.descent();
}
}
void InsetMathStackrel::draw(PainterInfo & pi, int x, int y) const
{
Changer dummy2 = pi.base.changeEnsureMath();
Dimension const dim = dimension(*pi.base.bv);
Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
Dimension const & dim1 = cell(1).dimension(*pi.base.bv);
int m = x + dim.width() / 2;
int yo = y - dim0.ascent() - dim1.descent() - 1;
cell(0).draw(pi, m - dim0.width() / 2, y);
Changer dummy = pi.base.changeScript();
cell(1).draw(pi, m - dim1.width() / 2, yo);
if (nargs() > 2) {
Dimension const & dim2 = cell(2).dimension(*pi.base.bv);
int y2 = y + dim0.descent() + dim2.ascent() + 1;
cell(2).draw(pi, m - dim2.width() / 2, y2);
}
}
void InsetMathStackrel::write(WriteStream & os) const
{
MathEnsurer ensurer(os);
os << "\\stackrel";
if (nargs() > 2)
os << '[' << cell(2) << ']';
os << '{' << cell(1) << "}{" << cell(0) << '}';
}
void InsetMathStackrel::normalize(NormalStream & os) const
{
os << "[stackrel " << cell(1) << ' ' << cell(0);
if (nargs() > 2)
os << ' ' << cell(2);
os << ']';
}
void InsetMathStackrel::mathmlize(MathStream & ms) const
{
if (nargs() > 2)
ms << "<munderover>" << cell(0) << cell(2) << cell(1) << "</munderover>";
else
ms << "<mover accent='false'>" << cell(0) << cell(1) << "</mover>";
}
void InsetMathStackrel::htmlize(HtmlStream & os) const
{
if (nargs() > 2) {
os << MTag("span", "class='underoverset'")
<< MTag("span", "class='top'") << cell(1) << ETag("span")
<< MTag("span") << cell(0) << ETag("span")
<< MTag("span", "class='bottom'") << cell(2) << ETag("span");
} else {
// at the moment, this is exactly the same as overset
os << MTag("span", "class='overset'")
<< MTag("span", "class='top'") << cell(1) << ETag("span")
<< MTag("span") << cell(0) << ETag("span");
}
os << ETag("span");
}
void InsetMathStackrel::validate(LaTeXFeatures & features) const
{
if (features.runparams().math_flavor == OutputParams::MathAsHTML) {
if (nargs() > 2) {
// FIXME: "vertical-align: middle" works only if the
// height of sub and super script is approximately equal.
features.addCSSSnippet(
"span.underoverset{display: inline-block; vertical-align: middle; text-align:center;}\n"
"span.underoverset span {display: block;}\n"
"span.bottom{font-size: 66%;}\n"
"span.top{font-size: 66%;}");
} else {
// from overset
features.addCSSSnippet(
"span.overset{display: inline-block; vertical-align: bottom; text-align:center;}\n"
"span.overset span {display: block;}\n"
"span.top{font-size: 66%;}");
}
}
if (nargs() > 2)
features.require("stackrel");
InsetMathNest::validate(features);
}
} // namespace lyx