mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 05:16:21 +00:00
Implement properly \limits and \nolimits
These are now properties of insets that can be operators : InsetMathSymbols, InsetMathDecoration (for over/underbrace) and InsetMathMacro (for its contents). Each of these has a limit_ member that allows to remember a limit forcing and a member defaultLimits() that indicates what to do in the absence of such forcing. Moreover the write() method calls writeLimits(). This allows to simplify the definitions of integrals in lib/symbols by defining the integrals as macros of their "op" version, as it is done in the style files. Also, many hardcoded assumptions can now be removed. The handling of LFUN_MATH_LIMITS is now done in InsetNest, which tries successively to apply the limit change to (1) the character after cursor, (2) the character before cursor and (3) the character at the end of the inset (useful for script insets?) The new code allows to define \newcommand\int{\intop\limits} but not \newcommand\makelimits#1{#1\limits} It is also possible to type explicitly \limits or \nolimits to modify a symbol.
This commit is contained in:
parent
1dbc50a30d
commit
f96b99dcb3
50
lib/symbols
50
lib/symbols
@ -1029,70 +1029,60 @@ tbond cmsy 180 186 mathord x x
|
||||
# If the wasysym integrals are really wanted then one has to load the package
|
||||
# manually and disable automatic loading of amsmath and esint.
|
||||
iffont esint
|
||||
int esint 001|002 0 mathop ∫ ∫ esint|amsmath
|
||||
intop esint 001|002 0 mathop ∫ ∫ esint
|
||||
iint esint 003|004 0 mathop ∬ ∬ esint|amsmath
|
||||
iintop esint 003|004 0 mathop ∬ ∬ esint
|
||||
iiint esint 005|006 0 mathop ∭ ∭ esint|amsmath
|
||||
iiintop esint 005|006 0 mathop ∭ ∭ esint
|
||||
iiiint esint 007|008 0 mathop ⨌ ⨌ esint|amsmath
|
||||
iiiintop esint 007|008 0 mathop ⨌ ⨌ esint
|
||||
#9 codepoint forbidden in qt4, 10,12,13 in qt5
|
||||
oint esint 043|044 0 mathop ∮ ∮ esint
|
||||
ointop esint 043|044 0 mathop ∮ ∮ esint
|
||||
oiint esint 045|046 0 mathop ∯ ∯ esint
|
||||
oiintop esint 045|046 0 mathop ∯ ∯ esint
|
||||
sqint esint 015|016 0 mathop ⨖ ⨖ esint
|
||||
sqintop esint 015|016 0 mathop ⨖ ⨖ esint
|
||||
sqiint esint 017|018 0 mathop x esint
|
||||
sqiintop esint 017|017 0 mathop x esint
|
||||
dotsint esint 041|042 0 mathop ∫⋯∫ ∫⋯∫ esint
|
||||
dotsintop esint 041|042 0 mathop ∫⋯∫ ∫⋯∫ esint
|
||||
ointctrclockwise esint 023|024 0 mathop ∳ ∳ esint
|
||||
ointctrclockwiseop esint 023|024 0 mathop ∳ ∳ esint
|
||||
ointclockwise esint 025|026 0 mathop ∲ ∲ esint
|
||||
ointclockwiseop esint 025|026 0 mathop ∲ ∲ esint
|
||||
else
|
||||
int cmex 82|90 242 mathop ∫ ∫ esint|amsmath
|
||||
intop cmex 82|90 242 mathop ∫ ∫ esint
|
||||
iint wasy 115|120 0 mathop ∬ ∬ esint|amsmath
|
||||
iintop wasy 115|120 0 mathop &Int ∬ esint
|
||||
iiint wasy 116|121 0 mathop ∭ ∭ esint|amsmath
|
||||
iiintop wasy 116|121 0 mathop ∭ ∭ esint
|
||||
\def\iiiint{\int\kern-6mu\int\kern-6mu\int\kern-6mu\int} esint|amsmath
|
||||
\def\iiiintop{\int\kern-6mu\int\kern-6mu\int\kern-6mu\int} esint
|
||||
\def\dotsint{\int\kern-3mu\cdots\kern-3mu\int} esint
|
||||
\def\dotsintop{\int\kern-3mu\cdots\kern-3mu\int} esint
|
||||
oint cmex 72|73 0 mathop ∮ ∮ esint
|
||||
ointop cmex 72|73 0 mathop ∮ ∮ esint
|
||||
oiint wasy 118|123 0 mathop ∯ ∯ esint
|
||||
oiintop wasy 118|123 0 mathop ∯ ∯ esint
|
||||
\def\sqint{\square\kern-17mu\int\kern6mu} esint
|
||||
\def\sqintop{\square\kern-17mu\int\kern6mu} esint
|
||||
\def\sqiint{\square\kern-20mu\iint\kern3mu} esint
|
||||
\def\sqiintop{\square\kern-20mu\iint\kern3mu} esint
|
||||
\def\ointctrclockwise{\circlearrowleft\kern-21mu\int\kern6mu} esint
|
||||
\def\dotsintop{\int\kern-3mu\cdots\kern-3mu\int} esint
|
||||
\def\ointctrclockwiseop{\circlearrowleft\kern-21mu\int\kern6mu} esint
|
||||
\def\ointclockwise{\circlearrowright\kern-21mu\int\kern6mu} esint
|
||||
\def\ointclockwiseop{\circlearrowright\kern-21mu\int\kern6mu} esint
|
||||
endif
|
||||
\def\int{\intop\nolimits} mathop ∫ ∫ esint|amsmath
|
||||
\def\iint{\iintop\nolimits} mathop ∬ ∬ esint|amsmath
|
||||
\def\iiint{\iiintop\nolimits} mathop ∭ ∭ esint|amsmath
|
||||
\def\iiiint{\iiiintop\nolimits} mathop ⨌ ⨌ esint|amsmath
|
||||
\def\oint{\ointop\nolimits} mathop ∮ ∮ esint
|
||||
\def\oiint{\oiintop\nolimits} mathop ∯ ∯ esint
|
||||
\def\sqint{\sqintop\nolimits} mathop ⨖ ⨖ esint
|
||||
\def\sqiint{\sqiintop\nolimits} mathop x esint
|
||||
\def\dotsint{\dotsintop\nolimits} mathop ∫⋯∫ ∫⋯∫
|
||||
\def\ointctrclockwise{\ointctrclockwise\nolimits} mathop ∲ ∲ esint
|
||||
\def\ointclockwise{\ointclockwise\nolimits} mathop ∲ ∲ esint
|
||||
|
||||
varointclockwise esint 027|028 0 mathop ∲ ∲ esint
|
||||
varointclockwiseop esint 027|028 0 mathop ∲ ∲ esint
|
||||
varointctrclockwise esint 029|030 0 mathop ∳ ∳ esint
|
||||
varointctrclockwiseop esint 029|030 0 mathop ∳ ∳ esint
|
||||
fint esint 031|032 0 mathop ⨏ ⨏ esint
|
||||
fintop esint 031|032 0 mathop ⨏ ⨏ esint
|
||||
varoiint esint 033|034 0 mathop ∯ ∯ esint
|
||||
varoiintop esint 033|034 0 mathop ∯ ∯ esint
|
||||
landupint esint 035|036 0 mathop x x esint
|
||||
landupintop esint 035|036 0 mathop x x esint
|
||||
landdownint esint 037|038 0 mathop x x esint
|
||||
landdownintop esint 037|038 0 mathop x x esint
|
||||
|
||||
\def\varointclockwise{\varointclockwiseop\limits} mathop ∲ ∲ esint
|
||||
\def\varointctrclockwise{\varointctrclockwiseop\limits} mathop ∳ ∳ esint
|
||||
\def\fint{\fintop\limits} mathop ⨏ ⨏ esint
|
||||
\def\varoiint{\varoiintop\limits} mathop ∯ ∯ esint
|
||||
\def\landupint{\landupintop\limits} mathop x x esint
|
||||
\def\landdownint{\landdownintop\limits} mathop x x esint
|
||||
|
||||
|
||||
# From the amsmath package:
|
||||
\def\idotsint{\int\kern-3mu\cdots\kern-3mu\int} amsmath
|
||||
\def\idotsint{\int\kern-3mu\cdots\kern-3mu\int\limits} amsmath
|
||||
|
||||
|
||||
log lyxblacktext 0 0 func x x
|
||||
|
@ -52,12 +52,6 @@ MathData const & InsetMath::cell(idx_type) const
|
||||
}
|
||||
|
||||
|
||||
MathClass InsetMath::mathClass() const
|
||||
{
|
||||
return MC_ORD;
|
||||
}
|
||||
|
||||
|
||||
InsetMath::marker_type InsetMath::marker(BufferView const *) const
|
||||
{
|
||||
return nargs() > 0 ? MARKER : NO_MARKER;
|
||||
@ -74,6 +68,19 @@ bool InsetMath::addToMathRow(MathRow & mrow, MetricsInfo & mi) const
|
||||
}
|
||||
|
||||
|
||||
/// write LaTeX and LyX code
|
||||
void InsetMath::writeLimits(WriteStream & os) const
|
||||
{
|
||||
if (limits() == LIMITS) {
|
||||
os << "\\limits";
|
||||
os.pendingSpace(true);
|
||||
} else if (limits() == NO_LIMITS) {
|
||||
os << "\\nolimits ";
|
||||
os.pendingSpace(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InsetMath::dump() const
|
||||
{
|
||||
lyxerr << "---------------------------------------------" << endl;
|
||||
|
@ -39,6 +39,17 @@ enum HullType {
|
||||
HullType hullType(docstring const & name);
|
||||
docstring hullName(HullType type);
|
||||
|
||||
|
||||
enum Limits {
|
||||
// what is obtained with \c \\nolimits
|
||||
NO_LIMITS = -1,
|
||||
// the default
|
||||
AUTO_LIMITS = 0,
|
||||
// what is obtained with \c \\limits
|
||||
LIMITS = 1
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Abstract base class for all math objects. A math insets is for use of the
|
||||
@ -173,7 +184,7 @@ public:
|
||||
virtual InsetMathSpecialChar const * asSpecialCharInset() const { return nullptr; }
|
||||
|
||||
/// The class of the math object (used primarily for spacing)
|
||||
virtual MathClass mathClass() const;
|
||||
virtual MathClass mathClass() const { return MC_ORD; }
|
||||
/// Add this inset to a math row. Return true if contents got added
|
||||
virtual bool addToMathRow(MathRow &, MetricsInfo & mi) const;
|
||||
/// Hook that is run before metrics computation starts
|
||||
@ -185,15 +196,22 @@ public:
|
||||
/// Hook that is run after drawing
|
||||
virtual void afterDraw(PainterInfo const &) const {}
|
||||
|
||||
/// identifies things that can get scripts
|
||||
virtual bool isScriptable() const { return false; }
|
||||
/// will this get written as a single block in {..}
|
||||
virtual bool extraBraces() const { return false; }
|
||||
|
||||
/// return the content as char if the inset is able to do so
|
||||
virtual char_type getChar() const { return 0; }
|
||||
/// identifies things that can get \limits or \nolimits
|
||||
virtual bool takesLimits() const { return false; }
|
||||
|
||||
/// Whether the inset allows \(no)limits
|
||||
bool allowsLimitsChange() const { return mathClass() == MC_OP; }
|
||||
/// The default limits value
|
||||
virtual Limits defaultLimits() const { return NO_LIMITS; }
|
||||
/// whether the inset has limit-like sub/superscript
|
||||
virtual Limits limits() const { return AUTO_LIMITS; }
|
||||
/// sets types of sub/superscripts
|
||||
virtual void limits(Limits) {}
|
||||
/// write limits status for LaTeX and LyX code
|
||||
void writeLimits(WriteStream & os) const;
|
||||
|
||||
/// replace things by other things
|
||||
virtual void replace(ReplaceData &) {}
|
||||
|
@ -38,7 +38,7 @@ namespace lyx {
|
||||
|
||||
|
||||
InsetMathDecoration::InsetMathDecoration(Buffer * buf, latexkeys const * key)
|
||||
: InsetMathNest(buf, 1), key_(key), dh_(0), dy_(0), dw_(0)
|
||||
: InsetMathNest(buf, 1), key_(key)
|
||||
{
|
||||
// lyxerr << " creating deco " << key->name << endl;
|
||||
}
|
||||
@ -64,12 +64,6 @@ MathClass InsetMathDecoration::mathClass() const
|
||||
}
|
||||
|
||||
|
||||
bool InsetMathDecoration::isScriptable() const
|
||||
{
|
||||
return mathClass() == MC_OP;
|
||||
}
|
||||
|
||||
|
||||
bool InsetMathDecoration::protect() const
|
||||
{
|
||||
return
|
||||
@ -151,6 +145,7 @@ void InsetMathDecoration::write(WriteStream & os) const
|
||||
os << '\\' << key_->name << '{';
|
||||
ModeSpecifier specifier(os, currentMode());
|
||||
os << cell(0) << '}';
|
||||
writeLimits(os);
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,8 +39,12 @@ public:
|
||||
void infoize(odocstream & os) const;
|
||||
///
|
||||
MathClass mathClass() const;
|
||||
///
|
||||
bool isScriptable() const;
|
||||
/// The default limits value
|
||||
Limits defaultLimits() const { return allowsLimitsChange() ? LIMITS : NO_LIMITS; }
|
||||
/// whether the inset has limit-like sub/superscript
|
||||
Limits limits() const { return limits_; }
|
||||
/// sets types of sub/superscripts
|
||||
void limits(Limits lim) { limits_ = lim; }
|
||||
///
|
||||
void validate(LaTeXFeatures & features) const;
|
||||
///
|
||||
@ -60,12 +64,15 @@ private:
|
||||
|
||||
///
|
||||
latexkeys const * key_;
|
||||
///
|
||||
Limits limits_ = AUTO_LIMITS;
|
||||
// FIXME: this should depend on BufferView
|
||||
/// height cache of deco
|
||||
mutable int dh_;
|
||||
mutable int dh_ = 0;
|
||||
/// vertical offset cache of deco
|
||||
mutable int dy_;
|
||||
mutable int dy_ = 0;
|
||||
/// width for non-wide deco
|
||||
mutable int dw_;
|
||||
mutable int dw_ = 0;
|
||||
};
|
||||
|
||||
} // namespace lyx
|
||||
|
@ -371,6 +371,38 @@ bool InsetMathMacro::addToMathRow(MathRow & mrow, MetricsInfo & mi) const
|
||||
return has_contents;
|
||||
}
|
||||
|
||||
/// Whether the inset allows \(no)limits
|
||||
bool InsetMathMacro::allowsLimitsChange() const
|
||||
{
|
||||
// similar to the code in mathClass(), except that we search for
|
||||
// the right-side class.
|
||||
MathClass mc = MC_UNKNOWN;
|
||||
if (MacroData const * m = macroBackup()) {
|
||||
// If it is a global macro and is defined explicitly
|
||||
if (m->symbol())
|
||||
mc = string_to_class(m->symbol()->extra);
|
||||
}
|
||||
// Otherwise guess from the expanded macro
|
||||
if (mc == MC_UNKNOWN)
|
||||
mc = d->expanded_.lastMathClass();
|
||||
|
||||
return mc == MC_OP;
|
||||
}
|
||||
|
||||
|
||||
Limits InsetMathMacro::defaultLimits() const
|
||||
{
|
||||
if (d->expanded_.empty())
|
||||
return NO_LIMITS;
|
||||
// Guess from the expanded macro
|
||||
InsetMath const * in = d->expanded_.back().nucleus();
|
||||
Limits const lim = in->limits() == AUTO_LIMITS
|
||||
? in->defaultLimits() : in->limits();
|
||||
LATTEST(lim != AUTO_LIMITS);
|
||||
return lim;
|
||||
}
|
||||
|
||||
|
||||
void InsetMathMacro::beforeMetrics() const
|
||||
{
|
||||
d->macro_->lock();
|
||||
@ -1155,6 +1187,9 @@ void InsetMathMacro::write(WriteStream & os) const
|
||||
// add space if there was no argument
|
||||
if (first)
|
||||
os.pendingSpace(true);
|
||||
|
||||
// write \(no)limits modifiers if relevant
|
||||
writeLimits(os);
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,6 +41,16 @@ public:
|
||||
/// If the macro is in normal edit mode, dissolve its contents in
|
||||
/// the row. Otherwise, just insert the inset.
|
||||
bool addToMathRow(MathRow &, MetricsInfo & mi) const;
|
||||
|
||||
/// Whether the inset allows \(no)limits
|
||||
bool allowsLimitsChange() const;
|
||||
/// The default limits value
|
||||
Limits defaultLimits() const;
|
||||
/// whether the inset has limit-like sub/superscript
|
||||
Limits limits() const { return limits_; }
|
||||
/// sets types of sub/superscripts
|
||||
void limits(Limits lim) { limits_ = lim; }
|
||||
|
||||
///
|
||||
void beforeMetrics() const;
|
||||
///
|
||||
@ -184,6 +194,9 @@ private:
|
||||
///
|
||||
bool editMode(BufferView const * bv) const;
|
||||
|
||||
///
|
||||
Limits limits_ = AUTO_LIMITS;
|
||||
|
||||
///
|
||||
class Private;
|
||||
///
|
||||
|
@ -518,7 +518,6 @@ void InsetMathNest::handleFont2(Cursor & cur, docstring const & arg)
|
||||
// FIXME: support other font changes here as well?
|
||||
}
|
||||
|
||||
|
||||
void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
|
||||
{
|
||||
//LYXERR0("InsetMathNest: request: " << cmd);
|
||||
@ -1277,6 +1276,32 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
|
||||
}
|
||||
break;
|
||||
|
||||
case LFUN_MATH_LIMITS: {
|
||||
InsetMath * in = 0;
|
||||
if (cur.pos() < cur.lastpos() && cur.nextMath().allowsLimitsChange())
|
||||
in = &cur.nextMath();
|
||||
else if (cur.pos() > 0 && cur.prevMath().allowsLimitsChange())
|
||||
in = &cur.prevMath();
|
||||
else if (cur.lastpos() > 0 && cur.cell().back()->allowsLimitsChange())
|
||||
in = cur.cell().back().nucleus();
|
||||
// only when nucleus allows this
|
||||
if (!in)
|
||||
return;
|
||||
cur.recordUndoInset();
|
||||
if (!cmd.argument().empty()) {
|
||||
if (cmd.argument() == "limits")
|
||||
in->limits(LIMITS);
|
||||
else if (cmd.argument() == "nolimits")
|
||||
in->limits(NO_LIMITS);
|
||||
else
|
||||
in->limits(AUTO_LIMITS);
|
||||
} else if (in->limits() == AUTO_LIMITS)
|
||||
in->limits(in->defaultLimits() == LIMITS ? NO_LIMITS : LIMITS);
|
||||
else
|
||||
in->limits(AUTO_LIMITS);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
InsetMath::doDispatch(cur, cmd);
|
||||
break;
|
||||
@ -1457,6 +1482,29 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd,
|
||||
break;
|
||||
}
|
||||
|
||||
case LFUN_MATH_LIMITS: {
|
||||
InsetMath * in = 0;
|
||||
if (cur.pos() < cur.lastpos() && cur.nextMath().allowsLimitsChange())
|
||||
in = &cur.nextMath();
|
||||
else if (cur.pos() > 0 && cur.prevMath().allowsLimitsChange())
|
||||
in = &cur.prevMath();
|
||||
else if (cur.lastpos() > 0 && cur.cell().back()->allowsLimitsChange())
|
||||
in = cur.cell().back().nucleus();
|
||||
if (in) {
|
||||
if (!cmd.argument().empty()) {
|
||||
if (cmd.argument() == "limits")
|
||||
flag.setOnOff(in->limits() == LIMITS);
|
||||
else if (cmd.argument() == "nolimits")
|
||||
flag.setOnOff(in->limits() == NO_LIMITS);
|
||||
else
|
||||
flag.setOnOff(in->limits() == AUTO_LIMITS);
|
||||
}
|
||||
flag.setEnabled(true);
|
||||
} else
|
||||
flag.setEnabled(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = false;
|
||||
break;
|
||||
@ -1858,6 +1906,15 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
|
||||
|
||||
bool InsetMathNest::interpretString(Cursor & cur, docstring const & str)
|
||||
{
|
||||
if (str == "\\limits" || str == "\\nolimits") {
|
||||
if (cur.pos() > 0 && cur.prevMath().allowsLimitsChange()) {
|
||||
cur.prevMath().limits(str == "\\limits" ? LIMITS : NO_LIMITS);
|
||||
return true;
|
||||
} else {
|
||||
cur.message(bformat(_("Cannot apply %1$s here."), str));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Create a InsetMathBig from cur.cell()[cur.pos() - 1] and t if
|
||||
// possible
|
||||
if (!cur.empty() && cur.pos() > 0 &&
|
||||
|
@ -13,16 +13,12 @@
|
||||
#include "InsetMathScript.h"
|
||||
|
||||
#include "InsetMathBrace.h"
|
||||
#include "InsetMathSymbol.h"
|
||||
#include "MathData.h"
|
||||
#include "MathStream.h"
|
||||
#include "MathSupport.h"
|
||||
|
||||
#include "BufferView.h"
|
||||
#include "Cursor.h"
|
||||
#include "DispatchResult.h"
|
||||
#include "FuncRequest.h"
|
||||
#include "FuncStatus.h"
|
||||
#include "LaTeXFeatures.h"
|
||||
#include "MetricsInfo.h"
|
||||
|
||||
@ -37,17 +33,17 @@ namespace lyx {
|
||||
|
||||
|
||||
InsetMathScript::InsetMathScript(Buffer * buf)
|
||||
: InsetMathNest(buf, 1), cell_1_is_up_(false), limits_(0)
|
||||
: InsetMathNest(buf, 1), cell_1_is_up_(false)
|
||||
{}
|
||||
|
||||
|
||||
InsetMathScript::InsetMathScript(Buffer * buf, bool up)
|
||||
: InsetMathNest(buf, 2), cell_1_is_up_(up), limits_(0)
|
||||
: InsetMathNest(buf, 2), cell_1_is_up_(up)
|
||||
{}
|
||||
|
||||
|
||||
InsetMathScript::InsetMathScript(Buffer * buf, MathAtom const & at, bool up)
|
||||
: InsetMathNest(buf, 2), cell_1_is_up_(up), limits_(0)
|
||||
: InsetMathNest(buf, 2), cell_1_is_up_(up)
|
||||
{
|
||||
LATTEST(nargs() >= 1);
|
||||
cell(0).push_back(at);
|
||||
@ -179,7 +175,7 @@ int InsetMathScript::dy0(BufferView const & bv) const
|
||||
if (!hasDown())
|
||||
return nd;
|
||||
int des = down().dimension(bv).ascent();
|
||||
if (hasLimits())
|
||||
if (has_limits_)
|
||||
des += nd + 2;
|
||||
else {
|
||||
int na = nasc(bv);
|
||||
@ -195,7 +191,7 @@ int InsetMathScript::dy1(BufferView const & bv) const
|
||||
if (!hasUp())
|
||||
return na;
|
||||
int asc = up().dimension(bv).descent();
|
||||
if (hasLimits())
|
||||
if (has_limits_)
|
||||
asc += na + 2;
|
||||
else {
|
||||
int nd = ndes(bv);
|
||||
@ -210,7 +206,7 @@ int InsetMathScript::dx0(BufferView const & bv) const
|
||||
{
|
||||
LASSERT(hasDown(), return 0);
|
||||
Dimension const dim = dimension(bv);
|
||||
return hasLimits() ? (dim.wid - down().dimension(bv).width()) / 2
|
||||
return has_limits_ ? (dim.wid - down().dimension(bv).width()) / 2
|
||||
: nwid(bv) + min(nker(&bv), 0);
|
||||
}
|
||||
|
||||
@ -219,7 +215,7 @@ int InsetMathScript::dx1(BufferView const & bv) const
|
||||
{
|
||||
LASSERT(hasUp(), return 0);
|
||||
Dimension const dim = dimension(bv);
|
||||
return hasLimits() ? (dim.wid - up().dimension(bv).width()) / 2
|
||||
return has_limits_ ? (dim.wid - up().dimension(bv).width()) / 2
|
||||
: nwid(bv) + max(nker(&bv), 0);
|
||||
}
|
||||
|
||||
@ -227,7 +223,7 @@ int InsetMathScript::dx1(BufferView const & bv) const
|
||||
int InsetMathScript::dxx(BufferView const & bv) const
|
||||
{
|
||||
Dimension const dim = dimension(bv);
|
||||
return hasLimits() ? (dim.wid - nwid(bv)) / 2 : 0;
|
||||
return has_limits_ ? (dim.wid - nwid(bv)) / 2 : 0;
|
||||
}
|
||||
|
||||
|
||||
@ -275,16 +271,21 @@ MathClass InsetMathScript::mathClass() const
|
||||
|
||||
void InsetMathScript::metrics(MetricsInfo & mi, Dimension & dim) const
|
||||
{
|
||||
Changer dummy2 = mi.base.changeEnsureMath();
|
||||
Dimension dim0;
|
||||
Dimension dim1;
|
||||
Dimension dim2;
|
||||
cell(0).metrics(mi, dim0);
|
||||
Changer dummy = mi.base.changeScript();
|
||||
if (nargs() > 1)
|
||||
cell(1).metrics(mi, dim1, !hasLimits());
|
||||
if (nargs() > 2)
|
||||
cell(2).metrics(mi, dim2, !hasLimits());
|
||||
{
|
||||
// Keeps the changers local
|
||||
Changer dummy2 = mi.base.changeEnsureMath();
|
||||
cell(0).metrics(mi, dim0);
|
||||
Changer dummy = mi.base.changeScript();
|
||||
if (nargs() > 1)
|
||||
cell(1).metrics(mi, dim1, !has_limits_);
|
||||
if (nargs() > 2)
|
||||
cell(2).metrics(mi, dim2, !has_limits_);
|
||||
}
|
||||
// we store this, because it is much easier
|
||||
has_limits_ = hasLimits(mi.base.font);
|
||||
|
||||
dim.wid = 0;
|
||||
BufferView & bv = *mi.base.bv;
|
||||
@ -296,7 +297,7 @@ void InsetMathScript::metrics(MetricsInfo & mi, Dimension & dim) const
|
||||
if (hasDown())
|
||||
dimdown = down().dimension(bv);
|
||||
|
||||
if (hasLimits()) {
|
||||
if (has_limits_) {
|
||||
dim.wid = nwid(bv);
|
||||
if (hasUp())
|
||||
dim.wid = max(dim.wid, dimup.width());
|
||||
@ -365,47 +366,17 @@ void InsetMathScript::drawT(TextPainter & pain, int x, int y) const
|
||||
}
|
||||
|
||||
|
||||
// FIXME: See InsetMathSymbol::takesLimits, which seems to attempt the
|
||||
// same in a hardcoded way. takeLimits use is currently commented out in
|
||||
// InsetMathScript::metrics. It seems that the mathop test is general
|
||||
// enough, but only time will tell.
|
||||
bool InsetMathScript::allowsLimits() const
|
||||
bool InsetMathScript::hasLimits(FontInfo const & font) const
|
||||
{
|
||||
if (font.style() != DISPLAY_STYLE)
|
||||
return false;
|
||||
if (nuc().empty())
|
||||
return false;
|
||||
// Only makes sense for insets of mathop class
|
||||
if (nuc().back()->mathClass() != MC_OP)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool InsetMathScript::hasLimits() const
|
||||
{
|
||||
// obvious cases
|
||||
if (limits_ == 1)
|
||||
return true;
|
||||
if (limits_ == -1)
|
||||
return false;
|
||||
|
||||
// we can only display limits if the nucleus wants some
|
||||
if (!allowsLimits())
|
||||
return false;
|
||||
// FIXME: this is some hardcoding done in InsetMathSymbol::metrics.
|
||||
if (!nuc().back()->isScriptable())
|
||||
return false;
|
||||
|
||||
if (nuc().back()->asSymbolInset()) {
|
||||
// \intop is an alias for \int\limits, \ointop == \oint\limits
|
||||
if (nuc().back()->asSymbolInset()->name().find(from_ascii("intop")) != string::npos)
|
||||
return true;
|
||||
// per default \int has limits beside the \int even in displayed formulas
|
||||
if (nuc().back()->asSymbolInset()->name().find(from_ascii("int")) != string::npos)
|
||||
return false;
|
||||
}
|
||||
|
||||
// assume "real" limits for everything else
|
||||
return true;
|
||||
Limits const lim = nuc().back()->limits() == AUTO_LIMITS
|
||||
? nuc().back()->defaultLimits() : nuc().back()->limits();
|
||||
LASSERT(lim != AUTO_LIMITS, return false);
|
||||
return lim == LIMITS;
|
||||
}
|
||||
|
||||
|
||||
@ -481,7 +452,8 @@ bool InsetMathScript::idxUpDown(Cursor & cur, bool up) const
|
||||
return false;
|
||||
// go up/down only if in the last position
|
||||
// or in the first position of something with displayed limits
|
||||
if (cur.pos() == cur.lastpos() || (cur.pos() == 0 && hasLimits())) {
|
||||
if (cur.pos() == cur.lastpos()
|
||||
|| (cur.pos() == 0 && has_limits_)) {
|
||||
cur.idx() = idxOfScript(up);
|
||||
cur.pos() = 0;
|
||||
return true;
|
||||
@ -519,20 +491,12 @@ void InsetMathScript::write(WriteStream & os) const
|
||||
{
|
||||
MathEnsurer ensurer(os);
|
||||
|
||||
if (!nuc().empty()) {
|
||||
if (!nuc().empty())
|
||||
os << nuc();
|
||||
//if (nuc().back()->takesLimits()) {
|
||||
if (limits_ == -1)
|
||||
os << "\\nolimits ";
|
||||
if (limits_ == 1)
|
||||
os << "\\limits ";
|
||||
//}
|
||||
} else {
|
||||
if (os.firstitem())
|
||||
LYXERR(Debug::MATHED, "suppressing {} when writing");
|
||||
else
|
||||
os << "{}";
|
||||
}
|
||||
else if (os.firstitem())
|
||||
LYXERR(Debug::MATHED, "suppressing {} when writing");
|
||||
else
|
||||
os << "{}";
|
||||
|
||||
if (hasDown() /*&& !down().empty()*/)
|
||||
os << "_{" << down() << '}';
|
||||
@ -616,7 +580,8 @@ void InsetMathScript::mathmlize(MathStream & ms) const
|
||||
{
|
||||
bool d = hasDown() && !down().empty();
|
||||
bool u = hasUp() && !up().empty();
|
||||
bool l = hasLimits();
|
||||
// FIXME: the MathStream should be able to give us this information
|
||||
bool l = has_limits_;
|
||||
|
||||
if (u && d)
|
||||
ms << MTag(l ? "munderover" : "msubsup");
|
||||
@ -680,8 +645,7 @@ void InsetMathScript::infoize(odocstream & os) const
|
||||
|
||||
void InsetMathScript::infoize2(odocstream & os) const
|
||||
{
|
||||
if (limits_)
|
||||
os << from_ascii(limits_ == 1 ? ", Displayed limits" : ", Inlined limits");
|
||||
os << from_ascii(has_limits_ == 1 ? ", Displayed limits" : ", Inlined limits");
|
||||
}
|
||||
|
||||
|
||||
@ -745,57 +709,6 @@ bool InsetMathScript::notifyCursorLeaves(Cursor const & old, Cursor & cur)
|
||||
}
|
||||
|
||||
|
||||
void InsetMathScript::doDispatch(Cursor & cur, FuncRequest & cmd)
|
||||
{
|
||||
//LYXERR("InsetMathScript: request: " << cmd);
|
||||
|
||||
if (cmd.action() == LFUN_MATH_LIMITS) {
|
||||
// only when nucleus allows this
|
||||
if (!allowsLimits())
|
||||
return;
|
||||
cur.recordUndoInset();
|
||||
if (!cmd.argument().empty()) {
|
||||
if (cmd.argument() == "limits")
|
||||
limits_ = 1;
|
||||
else if (cmd.argument() == "nolimits")
|
||||
limits_ = -1;
|
||||
else
|
||||
limits_ = 0;
|
||||
} else if (limits_ == 0)
|
||||
limits_ = hasLimits() ? -1 : 1;
|
||||
else
|
||||
limits_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
InsetMathNest::doDispatch(cur, cmd);
|
||||
}
|
||||
|
||||
|
||||
bool InsetMathScript::getStatus(Cursor & cur, FuncRequest const & cmd,
|
||||
FuncStatus & flag) const
|
||||
{
|
||||
if (cmd.action() == LFUN_MATH_LIMITS) {
|
||||
// only when nucleus allows this
|
||||
if (allowsLimits()) {
|
||||
if (!cmd.argument().empty()) {
|
||||
if (cmd.argument() == "limits")
|
||||
flag.setOnOff(limits_ == 1);
|
||||
else if (cmd.argument() == "nolimits")
|
||||
flag.setOnOff(limits_ == -1);
|
||||
else
|
||||
flag.setOnOff(limits_ == 0);
|
||||
}
|
||||
flag.setEnabled(true);
|
||||
} else
|
||||
flag.setEnabled(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
return InsetMathNest::getStatus(cur, cmd, flag);
|
||||
}
|
||||
|
||||
|
||||
// the idea for dual scripts came from the eLyXer code
|
||||
void InsetMathScript::validate(LaTeXFeatures & features) const
|
||||
{
|
||||
|
@ -72,10 +72,6 @@ public:
|
||||
///
|
||||
InsetMathScript * asScriptInset();
|
||||
|
||||
/// set limits
|
||||
void limits(int lim) { limits_ = lim; }
|
||||
/// get limits
|
||||
int limits() const { return limits_; }
|
||||
/// returns subscript. Always run 'hasDown' or 'has(false)' before!
|
||||
MathData const & down() const;
|
||||
/// returns subscript. Always run 'hasDown' or 'has(false)' before!
|
||||
@ -108,11 +104,6 @@ public:
|
||||
InsetCode lyxCode() const { return MATH_SCRIPT_CODE; }
|
||||
///
|
||||
void validate(LaTeXFeatures &features) const;
|
||||
protected:
|
||||
virtual void doDispatch(Cursor & cur, FuncRequest & cmd);
|
||||
/// do we want to handle this event?
|
||||
bool getStatus(Cursor & cur, FuncRequest const & cmd,
|
||||
FuncStatus & status) const;
|
||||
private:
|
||||
virtual Inset * clone() const;
|
||||
/// returns x offset for main part
|
||||
@ -138,17 +129,15 @@ private:
|
||||
/// shifts the superscript to the right, and a negative value shifts the
|
||||
/// subscript to the left.
|
||||
int nker(BufferView const * bv) const;
|
||||
/// can one change how scripts are drawn?
|
||||
bool allowsLimits() const;
|
||||
/// where do we have to draw the scripts?
|
||||
bool hasLimits() const;
|
||||
/// do we we have to draw the scripts above/below nucleus?
|
||||
bool hasLimits(FontInfo const &) const;
|
||||
/// clean up empty cells and return true if a cell has been deleted.
|
||||
bool notifyCursorLeaves(Cursor const & old, Cursor & cur);
|
||||
|
||||
/// possible subscript (index 0) and superscript (index 1)
|
||||
bool cell_1_is_up_;
|
||||
/// 1 - "limits", -1 - "nolimits", 0 - "default"
|
||||
int limits_;
|
||||
/// remember whether we are in display mode (used by mathml output)
|
||||
mutable bool has_limits_ = false;
|
||||
};
|
||||
|
||||
|
||||
|
@ -27,22 +27,22 @@
|
||||
#include "support/textutils.h"
|
||||
#include "support/unique_ptr.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace lyx {
|
||||
|
||||
InsetMathSymbol::InsetMathSymbol(latexkeys const * l)
|
||||
: sym_(l), h_(0), kerning_(0), scriptable_(false)
|
||||
: sym_(l)
|
||||
{}
|
||||
|
||||
|
||||
InsetMathSymbol::InsetMathSymbol(char const * name)
|
||||
: sym_(in_word_set(from_ascii(name))), h_(0),
|
||||
kerning_(0), scriptable_(false)
|
||||
: sym_(in_word_set(from_ascii(name)))
|
||||
{}
|
||||
|
||||
|
||||
InsetMathSymbol::InsetMathSymbol(docstring const & name)
|
||||
: sym_(in_word_set(name)), h_(0), kerning_(0), scriptable_(false)
|
||||
: sym_(in_word_set(name))
|
||||
{}
|
||||
|
||||
|
||||
@ -58,6 +58,14 @@ docstring InsetMathSymbol::name() const
|
||||
}
|
||||
|
||||
|
||||
/// The default limits value
|
||||
Limits InsetMathSymbol::defaultLimits() const
|
||||
{
|
||||
return (allowsLimitsChange() && sym_->extra != "func")
|
||||
? LIMITS : NO_LIMITS;
|
||||
}
|
||||
|
||||
|
||||
void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const
|
||||
{
|
||||
mathedSymbolDim(mi.base, dim, sym_);
|
||||
@ -82,16 +90,6 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const
|
||||
dim.asc += h_;
|
||||
dim.des -= h_;
|
||||
}
|
||||
|
||||
// set scriptable_
|
||||
//FIXME: get rid of that? Only "funclim" probably, along with
|
||||
// class==MC_OP. The issue is to implement \limits properly.
|
||||
scriptable_ = false;
|
||||
if (mi.base.font.style() == DISPLAY_STYLE)
|
||||
if (sym_->inset == "cmex" || sym_->inset == "esint" ||
|
||||
sym_->extra == "funclim" ||
|
||||
(sym_->inset == "stmry" && sym_->extra == "mathop"))
|
||||
scriptable_ = true;
|
||||
}
|
||||
|
||||
|
||||
@ -122,23 +120,6 @@ MathClass InsetMathSymbol::mathClass() const
|
||||
}
|
||||
|
||||
|
||||
bool InsetMathSymbol::isScriptable() const
|
||||
{
|
||||
return scriptable_;
|
||||
}
|
||||
|
||||
|
||||
bool InsetMathSymbol::takesLimits() const
|
||||
{
|
||||
return
|
||||
sym_->inset == "cmex" ||
|
||||
sym_->inset == "lyxboldsymb" ||
|
||||
sym_->inset == "esint" ||
|
||||
sym_->extra == "funclim" ||
|
||||
(sym_->inset == "stmry" && sym_->extra == "mathop");
|
||||
}
|
||||
|
||||
|
||||
void InsetMathSymbol::normalize(NormalStream & os) const
|
||||
{
|
||||
os << "[symbol " << name() << ']';
|
||||
@ -242,6 +223,7 @@ void InsetMathSymbol::write(WriteStream & os) const
|
||||
return;
|
||||
|
||||
os.pendingSpace(true);
|
||||
writeLimits(os);
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,9 +19,7 @@ namespace lyx {
|
||||
class latexkeys;
|
||||
|
||||
|
||||
/** "normal" symbols that don't take limits and don't grow in displayed
|
||||
* formulae.
|
||||
*/
|
||||
// \xxx symbols that may take limits or grow in displayed formulæ.
|
||||
class InsetMathSymbol : public InsetMath {
|
||||
public:
|
||||
///
|
||||
@ -43,10 +41,12 @@ public:
|
||||
MathClass mathClass() const;
|
||||
///
|
||||
bool isOrdAlpha() const;
|
||||
/// do we take scripts?
|
||||
bool isScriptable() const;
|
||||
/// do we take \limits or \nolimits?
|
||||
bool takesLimits() const;
|
||||
/// The default limits value
|
||||
Limits defaultLimits() const;
|
||||
/// whether the inset has limit-like sub/superscript
|
||||
Limits limits() const { return limits_; }
|
||||
/// sets types of sub/superscripts
|
||||
void limits(Limits lim) { limits_ = lim; }
|
||||
/// identifies SymbolInset as such
|
||||
InsetMathSymbol const * asSymbolInset() const { return this; }
|
||||
/// the LaTeX name of the symbol (without the backslash)
|
||||
@ -83,11 +83,14 @@ private:
|
||||
///
|
||||
latexkeys const * sym_;
|
||||
///
|
||||
mutable int h_;
|
||||
/// cached superscript kerning
|
||||
mutable int kerning_;
|
||||
Limits limits_ = AUTO_LIMITS;
|
||||
|
||||
// FIXME: these depend on BufferView
|
||||
|
||||
///
|
||||
mutable bool scriptable_;
|
||||
mutable int h_ = 0;
|
||||
/// cached superscript kerning
|
||||
mutable int kerning_ = 0;
|
||||
};
|
||||
|
||||
} // namespace lyx
|
||||
|
@ -966,6 +966,18 @@ MathClass MathData::mathClass() const
|
||||
}
|
||||
|
||||
|
||||
MathClass MathData::lastMathClass() const
|
||||
{
|
||||
MathClass res = MC_ORD;
|
||||
for (MathAtom const & at : *this) {
|
||||
MathClass mc = at->mathClass();
|
||||
if (mc != MC_UNKNOWN)
|
||||
return res = mc;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
ostream & operator<<(ostream & os, MathData const & ar)
|
||||
{
|
||||
odocstringstream oss;
|
||||
|
@ -140,8 +140,10 @@ public:
|
||||
void metricsT(TextMetricsInfo const & mi, Dimension & dim) const;
|
||||
/// redraw cell using cache metrics information
|
||||
void drawT(TextPainter & pi, int x, int y) const;
|
||||
/// approximate the math class of the data
|
||||
/// approximate mathclass of the data
|
||||
MathClass mathClass() const;
|
||||
/// math class of last interesting element
|
||||
MathClass lastMathClass() const;
|
||||
|
||||
/// access to cached x coordinate of last drawing
|
||||
int xo(BufferView const & bv) const;
|
||||
|
@ -797,7 +797,6 @@ void Parser::parse2(MathAtom & at, const unsigned flags, const mode_type mode,
|
||||
bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
|
||||
const mode_type mode, const bool numbered)
|
||||
{
|
||||
int limits = 0;
|
||||
InsetMathGrid::row_type cellrow = 0;
|
||||
InsetMathGrid::col_type cellcol = 0;
|
||||
MathData * cell = &grid.cell(grid.index(cellrow, cellcol));
|
||||
@ -1006,10 +1005,6 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
|
||||
p->nuc().erase(0);
|
||||
|
||||
parse(p->cell(p->idxOfScript(up)), FLAG_ITEM, mode);
|
||||
if (limits) {
|
||||
p->limits(limits);
|
||||
limits = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else if (t.character() == ']' && (flags & FLAG_BRACK_LAST)) {
|
||||
@ -1408,9 +1403,8 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
|
||||
}
|
||||
|
||||
else if (t.cs() == "limits" || t.cs() == "nolimits") {
|
||||
CatCode const cat = nextToken().cat();
|
||||
if (cat == catSuper || cat == catSub)
|
||||
limits = t.cs() == "limits" ? 1 : -1;
|
||||
if (!cell->empty())
|
||||
cell->back()->limits(t.cs() == "limits" ? LIMITS : NO_LIMITS);
|
||||
else {
|
||||
MathAtom at = createInsetMath(t.cs(), buf);
|
||||
cell->push_back(at);
|
||||
|
Loading…
Reference in New Issue
Block a user