2003-08-19 13:00:56 +00:00
|
|
|
/**
|
2017-07-05 12:31:28 +00:00
|
|
|
* \file InsetMathMacro.cpp
|
2003-08-19 13:00:56 +00:00
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
* Licence details can be found in the file COPYING.
|
1999-09-27 18:44:28 +00:00
|
|
|
*
|
2003-08-19 13:00:56 +00:00
|
|
|
* \author Alejandro Aguilar Sierra
|
2008-11-14 15:58:50 +00:00
|
|
|
* \author André Pönitz
|
2007-11-01 11:13:07 +00:00
|
|
|
* \author Stefan Schimanski
|
1999-09-27 18:44:28 +00:00
|
|
|
*
|
2003-08-19 13:00:56 +00:00
|
|
|
* Full author contact details are available in file CREDITS.
|
1999-09-27 18:44:28 +00:00
|
|
|
*/
|
|
|
|
|
2003-08-02 11:30:30 +00:00
|
|
|
#include <config.h>
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
#include "InsetMathMacro.h"
|
2008-03-15 00:22:54 +00:00
|
|
|
|
2008-10-07 16:24:07 +00:00
|
|
|
#include "InsetMathChar.h"
|
2008-03-15 00:22:54 +00:00
|
|
|
#include "MathCompletionList.h"
|
2006-09-17 09:14:18 +00:00
|
|
|
#include "MathExtern.h"
|
2009-07-09 15:21:21 +00:00
|
|
|
#include "MathFactory.h"
|
2006-10-22 10:15:23 +00:00
|
|
|
#include "MathStream.h"
|
2008-03-15 00:22:54 +00:00
|
|
|
#include "MathSupport.h"
|
2004-04-13 06:27:29 +00:00
|
|
|
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Buffer.h"
|
2007-11-01 11:13:07 +00:00
|
|
|
#include "BufferView.h"
|
2008-01-14 21:53:49 +00:00
|
|
|
#include "CoordCache.h"
|
2007-04-26 14:56:30 +00:00
|
|
|
#include "Cursor.h"
|
2007-11-01 11:13:07 +00:00
|
|
|
#include "FuncStatus.h"
|
|
|
|
#include "FuncRequest.h"
|
2008-02-21 19:42:34 +00:00
|
|
|
#include "LaTeXFeatures.h"
|
2010-02-09 16:11:13 +00:00
|
|
|
#include "LyX.h"
|
2008-02-21 19:42:34 +00:00
|
|
|
#include "LyXRC.h"
|
2016-06-04 08:41:13 +00:00
|
|
|
#include "MetricsInfo.h"
|
2007-11-01 11:13:07 +00:00
|
|
|
|
2005-07-17 10:31:44 +00:00
|
|
|
#include "frontends/Painter.h"
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2008-02-18 07:14:42 +00:00
|
|
|
#include "support/debug.h"
|
2013-04-25 21:27:10 +00:00
|
|
|
#include "support/gettext.h"
|
2008-06-19 09:16:05 +00:00
|
|
|
#include "support/lassert.h"
|
2014-11-14 17:18:30 +00:00
|
|
|
#include "support/lstrings.h"
|
2016-11-28 12:13:36 +00:00
|
|
|
#include "support/RefChanger.h"
|
2008-06-19 09:16:05 +00:00
|
|
|
#include "support/textutils.h"
|
2008-02-18 07:14:42 +00:00
|
|
|
|
2008-05-06 10:36:32 +00:00
|
|
|
#include <ostream>
|
2007-11-01 11:13:07 +00:00
|
|
|
#include <vector>
|
2006-10-21 00:16:43 +00:00
|
|
|
|
2014-11-14 17:18:30 +00:00
|
|
|
using namespace lyx::support;
|
2007-12-12 10:16:00 +00:00
|
|
|
using namespace std;
|
2006-08-13 22:54:59 +00:00
|
|
|
|
2007-12-12 10:16:00 +00:00
|
|
|
namespace lyx {
|
2002-02-16 15:59:55 +00:00
|
|
|
|
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
/// A proxy for the macro values
|
2017-07-05 12:31:28 +00:00
|
|
|
class InsetArgumentProxy : public InsetMath {
|
2007-04-17 16:52:43 +00:00
|
|
|
public:
|
|
|
|
///
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetArgumentProxy(InsetMathMacro * mathMacro, size_t idx)
|
2007-05-24 16:29:40 +00:00
|
|
|
: mathMacro_(mathMacro), idx_(idx) {}
|
2007-04-17 16:52:43 +00:00
|
|
|
///
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetArgumentProxy(InsetMathMacro * mathMacro, size_t idx, docstring const & def)
|
2014-12-29 20:13:42 +00:00
|
|
|
: mathMacro_(mathMacro), idx_(idx)
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
|
|
|
asArray(def, def_);
|
|
|
|
}
|
|
|
|
///
|
2017-07-05 12:31:28 +00:00
|
|
|
void setOwner(InsetMathMacro * mathMacro) { mathMacro_ = mathMacro; }
|
2015-04-02 19:35:05 +00:00
|
|
|
///
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro const * owner() { return mathMacro_; }
|
2015-10-03 15:41:25 +00:00
|
|
|
///
|
2017-02-08 15:42:14 +00:00
|
|
|
marker_type marker(BufferView const *) const { return NO_MARKER; }
|
2017-01-06 08:52:10 +00:00
|
|
|
///
|
2009-11-15 12:30:26 +00:00
|
|
|
InsetCode lyxCode() const { return ARGUMENT_PROXY_CODE; }
|
2016-11-28 12:13:36 +00:00
|
|
|
/// The math data to use for display
|
|
|
|
MathData const & displayCell(BufferView const * bv) const
|
|
|
|
{
|
|
|
|
// handle default macro arguments
|
|
|
|
bool use_def_arg = !mathMacro_->editMetrics(bv)
|
|
|
|
&& mathMacro_->cell(idx_).empty();
|
|
|
|
return use_def_arg ? def_ : mathMacro_->cell(idx_);
|
|
|
|
}
|
2009-11-15 12:30:26 +00:00
|
|
|
///
|
2016-10-04 22:25:38 +00:00
|
|
|
bool addToMathRow(MathRow & mrow, MetricsInfo & mi) const
|
2016-11-16 14:07:00 +00:00
|
|
|
{
|
2016-10-04 22:25:38 +00:00
|
|
|
// macro arguments are in macros
|
2016-11-28 12:13:36 +00:00
|
|
|
LATTEST(mathMacro_->nesting() > 0);
|
|
|
|
/// The macro nesting can change display of insets. Change it locally.
|
2017-01-09 17:23:17 +00:00
|
|
|
Changer chg = make_change(mi.base.macro_nesting,
|
|
|
|
mathMacro_->nesting() == 1 ? 0 : mathMacro_->nesting());
|
2016-10-04 22:25:38 +00:00
|
|
|
|
2017-02-01 16:46:53 +00:00
|
|
|
MathRow::Element e_beg(mi, MathRow::BEGIN);
|
2017-02-01 14:20:06 +00:00
|
|
|
e_beg.inset = this;
|
2016-10-04 22:25:38 +00:00
|
|
|
e_beg.ar = &mathMacro_->cell(idx_);
|
|
|
|
mrow.push_back(e_beg);
|
2016-11-16 14:07:00 +00:00
|
|
|
|
|
|
|
mathMacro_->macro()->unlock();
|
2016-11-28 12:13:36 +00:00
|
|
|
bool has_contents = displayCell(mi.base.bv).addToMathRow(mrow, mi);
|
2016-11-16 14:07:00 +00:00
|
|
|
mathMacro_->macro()->lock();
|
|
|
|
|
2016-10-04 22:25:38 +00:00
|
|
|
// if there was no contents, and the contents is editable,
|
|
|
|
// then we insert a box instead.
|
2016-11-28 12:13:36 +00:00
|
|
|
if (!has_contents && mathMacro_->nesting() == 1) {
|
2016-12-02 14:58:39 +00:00
|
|
|
// mathclass is ord because it should be spaced as a normal atom
|
2017-01-05 12:25:28 +00:00
|
|
|
MathRow::Element e(mi, MathRow::BOX, MC_ORD);
|
2016-10-04 22:25:38 +00:00
|
|
|
e.color = Color_mathline;
|
|
|
|
mrow.push_back(e);
|
|
|
|
has_contents = true;
|
|
|
|
}
|
2016-11-16 14:07:00 +00:00
|
|
|
|
2017-02-01 16:46:53 +00:00
|
|
|
MathRow::Element e_end(mi, MathRow::END);
|
2017-02-01 14:20:06 +00:00
|
|
|
e_end.inset = this;
|
2016-10-04 22:25:38 +00:00
|
|
|
e_end.ar = &mathMacro_->cell(idx_);
|
|
|
|
mrow.push_back(e_end);
|
|
|
|
|
|
|
|
return has_contents;
|
2016-11-16 14:07:00 +00:00
|
|
|
}
|
|
|
|
///
|
2017-02-01 14:20:06 +00:00
|
|
|
void beforeMetrics() const
|
|
|
|
{
|
|
|
|
mathMacro_->macro()->unlock();
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2016-12-02 15:19:02 +00:00
|
|
|
///
|
2017-02-01 14:20:06 +00:00
|
|
|
void afterMetrics() const
|
2016-12-02 15:19:02 +00:00
|
|
|
{
|
2017-02-01 14:20:06 +00:00
|
|
|
mathMacro_->macro()->lock();
|
|
|
|
}
|
|
|
|
///
|
|
|
|
void beforeDraw(PainterInfo const & pi) const
|
|
|
|
{
|
|
|
|
// if the macro is being edited, then the painter is in
|
|
|
|
// monochrome mode.
|
|
|
|
if (mathMacro_->editMetrics(pi.base.bv))
|
|
|
|
pi.pain.leaveMonochromeMode();
|
|
|
|
}
|
|
|
|
///
|
|
|
|
void afterDraw(PainterInfo const & pi) const
|
|
|
|
{
|
|
|
|
if (mathMacro_->editMetrics(pi.base.bv))
|
|
|
|
pi.pain.enterMonochromeMode(Color_mathbg, Color_mathmacroblend);
|
|
|
|
}
|
|
|
|
///
|
|
|
|
void metrics(MetricsInfo &, Dimension &) const {
|
2017-07-05 12:31:28 +00:00
|
|
|
// This should never be invoked, since InsetArgumentProxy insets are linearized
|
2017-02-01 14:20:06 +00:00
|
|
|
LATTEST(false);
|
2016-12-02 15:19:02 +00:00
|
|
|
}
|
|
|
|
///
|
|
|
|
void draw(PainterInfo &, int, int) const {
|
2017-07-05 12:31:28 +00:00
|
|
|
// This should never be invoked, since InsetArgumentProxy insets are linearized
|
2016-12-02 15:19:02 +00:00
|
|
|
LATTEST(false);
|
|
|
|
}
|
2017-02-01 14:20:06 +00:00
|
|
|
///
|
|
|
|
int kerning(BufferView const * bv) const
|
|
|
|
{
|
|
|
|
return displayCell(bv).kerning(bv);
|
|
|
|
}
|
2015-03-29 11:53:01 +00:00
|
|
|
// write(), normalize(), infoize() and infoize2() are not needed since
|
2017-07-05 12:31:28 +00:00
|
|
|
// InsetMathMacro uses the definition and not the expanded cells.
|
2015-03-29 11:53:01 +00:00
|
|
|
///
|
2015-04-02 19:35:05 +00:00
|
|
|
void maple(MapleStream & ms) const { ms << mathMacro_->cell(idx_); }
|
2015-03-29 11:53:01 +00:00
|
|
|
///
|
2015-04-02 19:35:05 +00:00
|
|
|
void maxima(MaximaStream & ms) const { ms << mathMacro_->cell(idx_); }
|
2015-03-29 11:53:01 +00:00
|
|
|
///
|
2015-04-02 19:35:05 +00:00
|
|
|
void mathematica(MathematicaStream & ms) const { ms << mathMacro_->cell(idx_); }
|
2009-11-15 12:30:26 +00:00
|
|
|
///
|
2015-04-02 19:35:05 +00:00
|
|
|
void mathmlize(MathStream & ms) const { ms << mathMacro_->cell(idx_); }
|
2007-11-01 11:13:07 +00:00
|
|
|
///
|
2015-04-02 19:35:05 +00:00
|
|
|
void htmlize(HtmlStream & ms) const { ms << mathMacro_->cell(idx_); }
|
2010-03-30 00:18:24 +00:00
|
|
|
///
|
2015-04-02 19:35:05 +00:00
|
|
|
void octave(OctaveStream & os) const { os << mathMacro_->cell(idx_); }
|
2017-01-03 19:17:20 +00:00
|
|
|
///
|
|
|
|
MathClass mathClass() const
|
|
|
|
{
|
|
|
|
return MC_UNKNOWN;
|
|
|
|
// This can be refined once the pointer issues are fixed. I did not
|
|
|
|
// notice any immediate crash with the following code, but it is risky
|
|
|
|
// nevertheless:
|
|
|
|
//return mathMacro_->cell(idx_).mathClass();
|
|
|
|
}
|
2007-05-28 22:27:45 +00:00
|
|
|
|
2007-04-17 16:52:43 +00:00
|
|
|
private:
|
2007-11-01 11:13:07 +00:00
|
|
|
///
|
2014-12-29 20:13:42 +00:00
|
|
|
Inset * clone() const
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2017-07-05 12:31:28 +00:00
|
|
|
return new InsetArgumentProxy(*this);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
///
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro * mathMacro_;
|
2007-11-01 11:13:07 +00:00
|
|
|
///
|
2007-05-24 16:29:40 +00:00
|
|
|
size_t idx_;
|
2007-11-01 11:13:07 +00:00
|
|
|
///
|
|
|
|
MathData def_;
|
2007-04-17 16:52:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
/// Private implementation of InsetMathMacro
|
|
|
|
class InsetMathMacro::Private {
|
2015-04-02 19:20:32 +00:00
|
|
|
public:
|
|
|
|
Private(Buffer * buf, docstring const & name)
|
|
|
|
: name_(name), displayMode_(DISPLAY_INIT),
|
|
|
|
expanded_(buf), definition_(buf), attachedArgsNum_(0),
|
|
|
|
optionals_(0), nextFoldMode_(true), macroBackup_(buf),
|
|
|
|
macro_(0), needsUpdate_(false), isUpdating_(false),
|
2017-03-01 15:31:00 +00:00
|
|
|
appetite_(9), nesting_(0)
|
2015-04-02 19:20:32 +00:00
|
|
|
{
|
|
|
|
}
|
2015-04-02 19:35:05 +00:00
|
|
|
/// Update the pointers to our owner of all expanded macros.
|
|
|
|
/// This needs to be called every time a copy of the owner is created
|
|
|
|
/// (bug 9418).
|
2017-07-05 12:31:28 +00:00
|
|
|
void updateChildren(InsetMathMacro * owner);
|
2015-10-03 15:41:25 +00:00
|
|
|
/// Recursively update the pointers of all expanded macros
|
|
|
|
/// appearing in the arguments of the current macro
|
2017-07-05 12:31:28 +00:00
|
|
|
void updateNestedChildren(InsetMathMacro * owner, InsetMathNest * ni);
|
2015-04-02 19:20:32 +00:00
|
|
|
/// name of macro
|
|
|
|
docstring name_;
|
|
|
|
/// current display mode
|
|
|
|
DisplayMode displayMode_;
|
|
|
|
/// expanded macro with ArgumentProxies
|
|
|
|
MathData expanded_;
|
|
|
|
/// macro definition with #1,#2,.. insets
|
|
|
|
MathData definition_;
|
|
|
|
/// number of arguments that were really attached
|
|
|
|
size_t attachedArgsNum_;
|
|
|
|
/// optional argument attached? (only in DISPLAY_NORMAL mode)
|
|
|
|
size_t optionals_;
|
|
|
|
/// fold mode to be set in next metrics call?
|
|
|
|
bool nextFoldMode_;
|
|
|
|
/// if macro_ == true, then here is a copy of the macro
|
|
|
|
/// don't use it for locking
|
|
|
|
MacroData macroBackup_;
|
|
|
|
/// if macroNotFound_ == false, then here is a reference to the macro
|
|
|
|
/// this might invalidate after metrics was called
|
|
|
|
MacroData const * macro_;
|
|
|
|
///
|
|
|
|
mutable std::map<BufferView const *, bool> editing_;
|
|
|
|
///
|
|
|
|
std::string requires_;
|
|
|
|
/// update macro representation
|
|
|
|
bool needsUpdate_;
|
|
|
|
///
|
|
|
|
bool isUpdating_;
|
|
|
|
/// maximal number of arguments the macro is greedy for
|
|
|
|
size_t appetite_;
|
2016-11-28 12:13:36 +00:00
|
|
|
/// Level of nesting in macros (including this one)
|
|
|
|
int nesting_;
|
2015-04-02 19:20:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::Private::updateChildren(InsetMathMacro * owner)
|
2015-04-02 19:35:05 +00:00
|
|
|
{
|
|
|
|
for (size_t i = 0; i < expanded_.size(); ++i) {
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetArgumentProxy * p = dynamic_cast<InsetArgumentProxy *>(expanded_[i].nucleus());
|
2015-04-02 19:35:05 +00:00
|
|
|
if (p)
|
|
|
|
p->setOwner(owner);
|
2015-10-03 15:41:25 +00:00
|
|
|
|
|
|
|
InsetMathNest * ni = expanded_[i].nucleus()->asNestInset();
|
|
|
|
if (ni)
|
|
|
|
updateNestedChildren(owner, ni);
|
2015-04-02 19:35:05 +00:00
|
|
|
}
|
2015-06-30 17:27:38 +00:00
|
|
|
|
2015-10-03 15:41:25 +00:00
|
|
|
if (macro_) {
|
|
|
|
// The macro_ pointer is updated when MathData::metrics() is
|
|
|
|
// called. However, when instant preview is on or the macro is
|
|
|
|
// not on screen, MathData::metrics() is not called and we may
|
|
|
|
// have a dangling pointer. As a safety measure, when a macro
|
|
|
|
// is copied, always let macro_ point to the backup copy of the
|
|
|
|
// MacroData structure. This backup is updated every time the
|
|
|
|
// macro is changed, so it will not become stale.
|
2015-07-05 18:44:54 +00:00
|
|
|
macro_ = ¯oBackup_;
|
2015-06-30 17:27:38 +00:00
|
|
|
}
|
2015-04-02 19:35:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::Private::updateNestedChildren(InsetMathMacro * owner, InsetMathNest * ni)
|
2015-10-03 15:41:25 +00:00
|
|
|
{
|
|
|
|
for (size_t i = 0; i < ni->nargs(); ++i) {
|
|
|
|
MathData & ar = ni->cell(i);
|
|
|
|
for (size_t j = 0; j < ar.size(); ++j) {
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetArgumentProxy * ap = dynamic_cast
|
|
|
|
<InsetArgumentProxy *>(ar[j].nucleus());
|
2015-10-03 15:41:25 +00:00
|
|
|
if (ap) {
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro::Private * md = ap->owner()->d;
|
2015-10-03 15:41:25 +00:00
|
|
|
if (md->macro_)
|
|
|
|
md->macro_ = &md->macroBackup_;
|
|
|
|
ap->setOwner(owner);
|
|
|
|
}
|
|
|
|
InsetMathNest * imn = ar[j].nucleus()->asNestInset();
|
|
|
|
if (imn)
|
|
|
|
updateNestedChildren(owner, imn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro::InsetMathMacro(Buffer * buf, docstring const & name)
|
2015-04-02 19:20:32 +00:00
|
|
|
: InsetMathNest(buf, 0), d(new Private(buf, name))
|
2001-07-12 11:55:57 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro::InsetMathMacro(InsetMathMacro const & that)
|
2015-04-02 19:20:32 +00:00
|
|
|
: InsetMathNest(that), d(new Private(*that.d))
|
|
|
|
{
|
2015-10-03 15:41:25 +00:00
|
|
|
setBuffer(*that.buffer_);
|
2015-04-02 19:35:05 +00:00
|
|
|
d->updateChildren(this);
|
2015-04-02 19:20:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro & InsetMathMacro::operator=(InsetMathMacro const & that)
|
2015-04-02 19:20:32 +00:00
|
|
|
{
|
|
|
|
if (&that == this)
|
|
|
|
return *this;
|
|
|
|
InsetMathNest::operator=(that);
|
|
|
|
*d = *that.d;
|
2015-04-02 19:35:05 +00:00
|
|
|
d->updateChildren(this);
|
2015-04-02 19:20:32 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro::~InsetMathMacro()
|
2015-04-02 19:20:32 +00:00
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::addToMathRow(MathRow & mrow, MetricsInfo & mi) const
|
2016-11-16 14:07:00 +00:00
|
|
|
{
|
|
|
|
// set edit mode for which we will have calculated row.
|
|
|
|
// This is the same as what is done in metrics().
|
|
|
|
d->editing_[mi.base.bv] = editMode(mi.base.bv);
|
|
|
|
|
2017-02-01 10:53:23 +00:00
|
|
|
// For now we do not linearize in the following cases (can be improved)
|
|
|
|
// - display mode different from normal
|
|
|
|
// - editing with parameter list
|
|
|
|
// - editing with box around macro
|
2017-07-05 12:31:28 +00:00
|
|
|
if (displayMode() != InsetMathMacro::DISPLAY_NORMAL
|
2017-02-08 15:42:14 +00:00
|
|
|
|| (d->editing_[mi.base.bv] && lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_LIST))
|
2016-10-04 22:25:38 +00:00
|
|
|
return InsetMath::addToMathRow(mrow, mi);
|
2016-11-16 14:07:00 +00:00
|
|
|
|
2017-01-06 08:52:10 +00:00
|
|
|
/// The macro nesting can change display of insets. Change it locally.
|
|
|
|
Changer chg = make_change(mi.base.macro_nesting, d->nesting_);
|
|
|
|
|
2017-02-01 16:46:53 +00:00
|
|
|
MathRow::Element e_beg(mi, MathRow::BEGIN);
|
2017-01-06 08:52:10 +00:00
|
|
|
e_beg.inset = this;
|
2017-02-08 15:42:14 +00:00
|
|
|
e_beg.marker = (d->nesting_ == 1) ? marker(mi.base.bv) : NO_MARKER;
|
2016-10-04 22:25:38 +00:00
|
|
|
mrow.push_back(e_beg);
|
2016-11-16 14:07:00 +00:00
|
|
|
|
2016-10-04 22:25:38 +00:00
|
|
|
d->macro_->lock();
|
|
|
|
bool has_contents = d->expanded_.addToMathRow(mrow, mi);
|
|
|
|
d->macro_->unlock();
|
|
|
|
|
|
|
|
// if there was no contents and the array is editable, then we
|
|
|
|
// insert a grey box instead.
|
2016-11-14 17:01:56 +00:00
|
|
|
if (!has_contents && mi.base.macro_nesting == 1) {
|
2016-12-02 14:58:39 +00:00
|
|
|
// mathclass is unknown because it is irrelevant for spacing
|
2017-01-05 12:25:28 +00:00
|
|
|
MathRow::Element e(mi, MathRow::BOX);
|
2016-10-04 22:25:38 +00:00
|
|
|
e.color = Color_mathmacroblend;
|
|
|
|
mrow.push_back(e);
|
|
|
|
has_contents = true;
|
2016-11-16 14:07:00 +00:00
|
|
|
}
|
2016-10-04 22:25:38 +00:00
|
|
|
|
2017-02-01 16:46:53 +00:00
|
|
|
MathRow::Element e_end(mi, MathRow::END);
|
2017-02-01 14:20:06 +00:00
|
|
|
e_end.inset = this;
|
2017-02-08 15:42:14 +00:00
|
|
|
e_end.marker = (d->nesting_ == 1) ? marker(mi.base.bv) : NO_MARKER;
|
2016-10-04 22:25:38 +00:00
|
|
|
mrow.push_back(e_end);
|
|
|
|
|
|
|
|
return has_contents;
|
2016-11-16 14:07:00 +00:00
|
|
|
}
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::beforeMetrics() const
|
2017-02-01 14:20:06 +00:00
|
|
|
{
|
|
|
|
d->macro_->lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::afterMetrics() const
|
2017-02-01 14:20:06 +00:00
|
|
|
{
|
|
|
|
d->macro_->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::beforeDraw(PainterInfo const & pi) const
|
2017-02-01 14:20:06 +00:00
|
|
|
{
|
|
|
|
if (d->editing_[pi.base.bv])
|
|
|
|
pi.pain.enterMonochromeMode(Color_mathbg, Color_mathmacroblend);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::afterDraw(PainterInfo const & pi) const
|
2017-02-01 14:20:06 +00:00
|
|
|
{
|
|
|
|
if (d->editing_[pi.base.bv])
|
|
|
|
pi.pain.leaveMonochromeMode();
|
|
|
|
}
|
|
|
|
|
2016-11-16 14:07:00 +00:00
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
Inset * InsetMathMacro::clone() const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro * copy = new InsetMathMacro(*this);
|
2015-04-02 19:20:32 +00:00
|
|
|
copy->d->needsUpdate_ = true;
|
|
|
|
//copy->d->expanded_.clear();
|
2007-11-01 11:13:07 +00:00
|
|
|
return copy;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
2001-08-09 09:19:18 +00:00
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::normalize(NormalStream & os) const
|
2011-04-01 20:03:15 +00:00
|
|
|
{
|
|
|
|
os << "[macro " << name();
|
|
|
|
for (size_t i = 0; i < nargs(); ++i)
|
|
|
|
os << ' ' << cell(i);
|
|
|
|
os << ']';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro::DisplayMode InsetMathMacro::displayMode() const
|
2015-04-02 19:20:32 +00:00
|
|
|
{
|
|
|
|
return d->displayMode_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::extraBraces() const
|
2015-04-02 19:20:32 +00:00
|
|
|
{
|
|
|
|
return d->displayMode_ == DISPLAY_NORMAL && arity() > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
docstring InsetMathMacro::name() const
|
2001-08-08 17:26:30 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->displayMode_ == DISPLAY_UNFOLDED)
|
2007-11-01 11:13:07 +00:00
|
|
|
return asString(cell(0));
|
2008-06-19 09:16:05 +00:00
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
return d->name_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
docstring InsetMathMacro::macroName() const
|
2015-04-02 19:20:32 +00:00
|
|
|
{
|
|
|
|
return d->name_;
|
2001-08-08 17:26:30 +00:00
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2001-08-09 09:19:18 +00:00
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
int InsetMathMacro::nesting() const
|
2016-11-28 12:13:36 +00:00
|
|
|
{
|
|
|
|
return d->nesting_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::cursorPos(BufferView const & bv,
|
2006-10-17 16:23:27 +00:00
|
|
|
CursorSlice const & sl, bool boundary, int & x, int & y) const
|
2005-10-05 21:19:32 +00:00
|
|
|
{
|
2006-09-16 18:11:38 +00:00
|
|
|
// We may have 0 arguments, but InsetMathNest requires at least one.
|
2005-10-05 21:19:32 +00:00
|
|
|
if (nargs() > 0)
|
2006-10-17 16:23:27 +00:00
|
|
|
InsetMathNest::cursorPos(bv, sl, boundary, x, y);
|
2005-10-05 21:19:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::editMode(BufferView const * bv) const {
|
2007-11-01 11:13:07 +00:00
|
|
|
// find this in cursor trace
|
2007-12-24 10:54:39 +00:00
|
|
|
Cursor const & cur = bv->cursor();
|
2007-11-01 11:13:07 +00:00
|
|
|
for (size_t i = 0; i != cur.depth(); ++i)
|
|
|
|
if (&cur[i].inset() == this) {
|
|
|
|
// look if there is no other macro in edit mode above
|
|
|
|
++i;
|
|
|
|
for (; i != cur.depth(); ++i) {
|
2010-10-27 07:04:58 +00:00
|
|
|
InsetMath * im = cur[i].asInsetMath();
|
|
|
|
if (im) {
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro const * macro = im->asMacro();
|
2010-10-27 07:04:58 +00:00
|
|
|
if (macro && macro->displayMode() == DISPLAY_NORMAL)
|
|
|
|
return false;
|
|
|
|
}
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ok, none found, I am the highest one
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
MacroData const * InsetMathMacro::macro() const
|
2015-04-02 19:20:32 +00:00
|
|
|
{
|
|
|
|
return d->macro_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::editMetrics(BufferView const * bv) const
|
2007-12-24 10:54:39 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
return d->editing_[bv];
|
2007-12-24 10:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMath::marker_type InsetMathMacro::marker(BufferView const * bv) const
|
2017-01-06 08:52:10 +00:00
|
|
|
{
|
2017-02-08 15:42:14 +00:00
|
|
|
if (nargs() == 0)
|
|
|
|
return NO_MARKER;
|
|
|
|
|
2017-01-06 08:52:10 +00:00
|
|
|
switch (d->displayMode_) {
|
|
|
|
case DISPLAY_INIT:
|
|
|
|
case DISPLAY_INTERACTIVE_INIT:
|
|
|
|
return NO_MARKER;
|
|
|
|
case DISPLAY_UNFOLDED:
|
|
|
|
return MARKER;
|
2017-02-08 15:42:14 +00:00
|
|
|
case DISPLAY_NORMAL:
|
2017-01-06 08:52:10 +00:00
|
|
|
switch (lyxrc.macro_edit_style) {
|
2017-02-08 15:42:14 +00:00
|
|
|
case LyXRC::MACRO_EDIT_INLINE:
|
2017-06-12 15:09:58 +00:00
|
|
|
return MARKER2;
|
2017-02-08 15:42:14 +00:00
|
|
|
case LyXRC::MACRO_EDIT_INLINE_BOX:
|
2017-06-12 15:09:58 +00:00
|
|
|
return d->editing_[bv] ? BOX_MARKER : MARKER2;
|
2017-01-06 08:52:10 +00:00
|
|
|
case LyXRC::MACRO_EDIT_LIST:
|
|
|
|
return MARKER2;
|
|
|
|
}
|
|
|
|
}
|
2017-02-08 15:42:14 +00:00
|
|
|
// please gcc 4.6
|
|
|
|
return NO_MARKER;
|
2017-01-06 08:52:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
|
2002-03-25 12:11:25 +00:00
|
|
|
{
|
2016-11-28 12:13:36 +00:00
|
|
|
/// The macro nesting can change display of insets. Change it locally.
|
|
|
|
Changer chg = make_change(mi.base.macro_nesting, d->nesting_);
|
2016-10-04 22:25:38 +00:00
|
|
|
|
2007-12-24 10:54:39 +00:00
|
|
|
// set edit mode for which we will have calculated metrics. But only
|
2015-04-02 19:20:32 +00:00
|
|
|
d->editing_[mi.base.bv] = editMode(mi.base.bv);
|
2007-12-22 14:39:47 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// calculate new metrics according to display mode
|
2015-04-02 19:35:05 +00:00
|
|
|
if (d->displayMode_ == DISPLAY_INIT || d->displayMode_ == DISPLAY_INTERACTIVE_INIT) {
|
2016-11-23 22:05:01 +00:00
|
|
|
Changer dummy = mi.base.changeFontSet("lyxtex");
|
2007-11-01 11:13:07 +00:00
|
|
|
mathed_string_dim(mi.base.font, from_ascii("\\") + name(), dim);
|
2015-04-02 19:20:32 +00:00
|
|
|
} else if (d->displayMode_ == DISPLAY_UNFOLDED) {
|
2016-11-23 22:05:01 +00:00
|
|
|
Changer dummy = mi.base.changeFontSet("lyxtex");
|
2007-11-01 11:13:07 +00:00
|
|
|
cell(0).metrics(mi, dim);
|
|
|
|
Dimension bsdim;
|
|
|
|
mathed_string_dim(mi.base.font, from_ascii("\\"), bsdim);
|
|
|
|
dim.wid += bsdim.width() + 1;
|
2007-12-12 19:28:07 +00:00
|
|
|
dim.asc = max(bsdim.ascent(), dim.ascent());
|
|
|
|
dim.des = max(bsdim.descent(), dim.descent());
|
2014-12-29 20:13:42 +00:00
|
|
|
} else if (lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_LIST
|
2015-04-02 19:20:32 +00:00
|
|
|
&& d->editing_[mi.base.bv]) {
|
2008-01-25 22:02:38 +00:00
|
|
|
// Macro will be edited in a old-style list mode here:
|
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
LBUFERR(d->macro_);
|
2008-01-25 22:02:38 +00:00
|
|
|
Dimension fontDim;
|
|
|
|
FontInfo labelFont = sane_font;
|
|
|
|
math_font_max_dim(labelFont, fontDim.asc, fontDim.des);
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
// get dimension of components of list view
|
|
|
|
Dimension nameDim;
|
|
|
|
nameDim.wid = mathed_string_width(mi.base.font, from_ascii("Macro \\") + name() + ": ");
|
|
|
|
nameDim.asc = fontDim.asc;
|
|
|
|
nameDim.des = fontDim.des;
|
|
|
|
|
|
|
|
Dimension argDim;
|
|
|
|
argDim.wid = mathed_string_width(labelFont, from_ascii("#9: "));
|
|
|
|
argDim.asc = fontDim.asc;
|
|
|
|
argDim.des = fontDim.des;
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
Dimension defDim;
|
2015-04-02 19:20:32 +00:00
|
|
|
d->definition_.metrics(mi, defDim);
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
// add them up
|
|
|
|
dim.wid = nameDim.wid + defDim.wid;
|
|
|
|
dim.asc = max(nameDim.asc, defDim.asc);
|
|
|
|
dim.des = max(nameDim.des, defDim.des);
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
for (idx_type i = 0; i < nargs(); ++i) {
|
|
|
|
Dimension cdim;
|
|
|
|
cell(i).metrics(mi, cdim);
|
|
|
|
dim.des += max(argDim.height(), cdim.height()) + 1;
|
|
|
|
dim.wid = max(dim.wid, argDim.wid + cdim.wid);
|
|
|
|
}
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
// make space for box and markers, 2 pixels
|
|
|
|
dim.asc += 1;
|
|
|
|
dim.des += 1;
|
|
|
|
dim.wid += 2;
|
2004-04-13 13:54:58 +00:00
|
|
|
} else {
|
2017-02-08 15:42:14 +00:00
|
|
|
// We should not be here, since the macro is linearized in this case.
|
|
|
|
LBUFERR(false);
|
2004-04-13 13:54:58 +00:00
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
int InsetMathMacro::kerning(BufferView const * bv) const {
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->displayMode_ == DISPLAY_NORMAL && !d->editing_[bv])
|
|
|
|
return d->expanded_.kerning(bv);
|
2007-11-01 11:13:07 +00:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::updateMacro(MacroContext const & mc)
|
2000-02-10 17:53:36 +00:00
|
|
|
{
|
2007-12-21 20:42:46 +00:00
|
|
|
if (validName()) {
|
2015-04-02 19:20:32 +00:00
|
|
|
d->macro_ = mc.get(name());
|
|
|
|
if (d->macro_ && d->macroBackup_ != *d->macro_) {
|
|
|
|
d->macroBackup_ = *d->macro_;
|
|
|
|
d->needsUpdate_ = true;
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2004-04-13 13:54:58 +00:00
|
|
|
} else {
|
2015-04-02 19:20:32 +00:00
|
|
|
d->macro_ = 0;
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
2007-05-28 22:27:45 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
class InsetMathMacro::UpdateLocker
|
2014-03-05 23:45:42 +00:00
|
|
|
{
|
|
|
|
public:
|
2017-07-05 12:31:28 +00:00
|
|
|
explicit UpdateLocker(InsetMathMacro & mm) : mac(mm)
|
2014-03-05 23:45:42 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
mac.d->isUpdating_ = true;
|
2014-03-05 23:45:42 +00:00
|
|
|
}
|
2015-04-02 19:20:32 +00:00
|
|
|
~UpdateLocker() { mac.d->isUpdating_ = false; }
|
2014-03-05 23:45:42 +00:00
|
|
|
private:
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro & mac;
|
2014-03-05 23:45:42 +00:00
|
|
|
};
|
2014-11-17 10:52:14 +00:00
|
|
|
/** Avoid wrong usage of UpdateLocker.
|
|
|
|
To avoid wrong usage:
|
|
|
|
UpdateLocker(...); // wrong
|
|
|
|
UpdateLocker locker(...); // right
|
|
|
|
*/
|
|
|
|
#define UpdateLocker(x) unnamed_UpdateLocker;
|
|
|
|
// Tip gotten from Bobby Schmidt's column in C/C++ Users Journal
|
2014-03-05 23:45:42 +00:00
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::updateRepresentation(Cursor * cur, MacroContext const & mc,
|
2016-11-28 12:13:36 +00:00
|
|
|
UpdateType utype, int nesting)
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2014-11-14 20:30:42 +00:00
|
|
|
// block recursive calls (bug 8999)
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->isUpdating_)
|
2014-03-05 23:45:42 +00:00
|
|
|
return;
|
|
|
|
|
2014-07-05 17:12:09 +00:00
|
|
|
UpdateLocker locker(*this);
|
2014-03-05 23:45:42 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// known macro?
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->macro_ == 0)
|
2007-12-21 20:42:46 +00:00
|
|
|
return;
|
|
|
|
|
2016-11-28 12:13:36 +00:00
|
|
|
// remember nesting level of this macro
|
|
|
|
d->nesting_ = nesting;
|
|
|
|
|
2007-12-21 20:42:46 +00:00
|
|
|
// update requires
|
2015-04-02 19:20:32 +00:00
|
|
|
d->requires_ = d->macro_->requires();
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
if (!d->needsUpdate_
|
2010-01-11 18:25:26 +00:00
|
|
|
// non-normal mode? We are done!
|
2015-04-02 19:20:32 +00:00
|
|
|
|| (d->displayMode_ != DISPLAY_NORMAL))
|
2007-12-21 20:42:46 +00:00
|
|
|
return;
|
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
d->needsUpdate_ = false;
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-03-04 14:57:46 +00:00
|
|
|
// get default values of macro
|
2015-04-02 19:20:32 +00:00
|
|
|
vector<docstring> const & defaults = d->macro_->defaults();
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-03-04 14:57:46 +00:00
|
|
|
// create MathMacroArgumentValue objects pointing to the cells of the macro
|
|
|
|
vector<MathData> values(nargs());
|
|
|
|
for (size_t i = 0; i < nargs(); ++i) {
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetArgumentProxy * proxy;
|
2014-12-29 20:13:42 +00:00
|
|
|
if (i < defaults.size())
|
2017-07-05 12:31:28 +00:00
|
|
|
proxy = new InsetArgumentProxy(this, i, defaults[i]);
|
2008-03-04 14:57:46 +00:00
|
|
|
else
|
2017-07-05 12:31:28 +00:00
|
|
|
proxy = new InsetArgumentProxy(this, i);
|
2008-03-04 14:57:46 +00:00
|
|
|
values[i].insert(0, MathAtom(proxy));
|
2008-01-14 21:53:49 +00:00
|
|
|
}
|
2008-03-04 14:57:46 +00:00
|
|
|
// expanding macro with the values
|
2014-11-14 20:30:42 +00:00
|
|
|
// Only update the argument macros if anything was expanded, otherwise
|
|
|
|
// we would get an endless loop (bug 9140). UpdateLocker does not work
|
2017-07-05 12:31:28 +00:00
|
|
|
// in this case, since MacroData::expand() creates new InsetMathMacro
|
2014-11-14 20:30:42 +00:00
|
|
|
// objects, so this would be a different recursion path than the one
|
|
|
|
// protected by UpdateLocker.
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->macro_->expand(values, d->expanded_)) {
|
|
|
|
if (utype == OutputUpdate && !d->expanded_.empty())
|
2016-11-28 12:13:36 +00:00
|
|
|
d->expanded_.updateMacros(cur, mc, utype, nesting);
|
2014-11-14 20:30:42 +00:00
|
|
|
}
|
2009-11-15 12:30:26 +00:00
|
|
|
// get definition for list edit mode
|
2015-04-02 19:20:32 +00:00
|
|
|
docstring const & display = d->macro_->display();
|
2016-10-31 14:23:20 +00:00
|
|
|
asArray(display.empty() ? d->macro_->definition() : display,
|
2017-04-02 22:26:49 +00:00
|
|
|
d->definition_, Parse::QUIET | Parse::MACRODEF);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::draw(PainterInfo & pi, int x, int y) const
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
|
|
|
Dimension const dim = dimension(*pi.base.bv);
|
|
|
|
|
|
|
|
int expx = x;
|
|
|
|
int expy = y;
|
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->displayMode_ == DISPLAY_INIT || d->displayMode_ == DISPLAY_INTERACTIVE_INIT) {
|
2016-05-23 21:30:23 +00:00
|
|
|
Changer dummy = pi.base.changeFontSet("lyxtex");
|
2008-07-05 23:29:48 +00:00
|
|
|
pi.pain.text(x, y, from_ascii("\\") + name(), pi.base.font);
|
2015-04-02 19:20:32 +00:00
|
|
|
} else if (d->displayMode_ == DISPLAY_UNFOLDED) {
|
2016-05-23 21:30:23 +00:00
|
|
|
Changer dummy = pi.base.changeFontSet("lyxtex");
|
2008-07-05 23:29:48 +00:00
|
|
|
pi.pain.text(x, y, from_ascii("\\"), pi.base.font);
|
|
|
|
x += mathed_string_width(pi.base.font, from_ascii("\\")) + 1;
|
|
|
|
cell(0).draw(pi, x, y);
|
2008-01-25 22:02:38 +00:00
|
|
|
} else if (lyxrc.macro_edit_style == LyXRC::MACRO_EDIT_LIST
|
2017-01-06 08:52:10 +00:00
|
|
|
&& d->editing_[pi.base.bv]) {
|
2008-01-25 22:02:38 +00:00
|
|
|
// Macro will be edited in a old-style list mode here:
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-10-29 08:03:26 +00:00
|
|
|
CoordCache const & coords = pi.base.bv->coordCache();
|
2008-01-25 22:02:38 +00:00
|
|
|
FontInfo const & labelFont = sane_font;
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2017-01-06 08:52:10 +00:00
|
|
|
// box needs one pixel
|
|
|
|
x += 1;
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
// get maximal font height
|
|
|
|
Dimension fontDim;
|
|
|
|
math_font_max_dim(pi.base.font, fontDim.asc, fontDim.des);
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
// draw label
|
|
|
|
docstring label = from_ascii("Macro \\") + name() + from_ascii(": ");
|
|
|
|
pi.pain.text(x, y, label, labelFont);
|
|
|
|
x += mathed_string_width(labelFont, label);
|
|
|
|
|
|
|
|
// draw definition
|
2015-04-02 19:20:32 +00:00
|
|
|
d->definition_.draw(pi, x, y);
|
|
|
|
Dimension const & defDim = coords.getArrays().dim(&d->definition_);
|
2008-01-25 22:02:38 +00:00
|
|
|
y += max(fontDim.des, defDim.des);
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
// draw parameters
|
|
|
|
docstring str = from_ascii("#9");
|
|
|
|
int strw1 = mathed_string_width(labelFont, from_ascii("#9"));
|
|
|
|
int strw2 = mathed_string_width(labelFont, from_ascii(": "));
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
for (idx_type i = 0; i < nargs(); ++i) {
|
|
|
|
// position of label
|
2008-10-29 08:03:26 +00:00
|
|
|
Dimension const & cdim = coords.getArrays().dim(&cell(i));
|
2017-01-06 08:52:10 +00:00
|
|
|
x = expx + 1;
|
2008-01-25 22:02:38 +00:00
|
|
|
y += max(fontDim.asc, cdim.asc) + 1;
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
// draw label
|
|
|
|
str[1] = '1' + i;
|
|
|
|
pi.pain.text(x, y, str, labelFont);
|
|
|
|
x += strw1;
|
|
|
|
pi.pain.text(x, y, from_ascii(":"), labelFont);
|
|
|
|
x += strw2;
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
// draw paramter
|
|
|
|
cell(i).draw(pi, x, y);
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-01-25 22:02:38 +00:00
|
|
|
// next line
|
|
|
|
y += max(fontDim.des, cdim.des);
|
|
|
|
}
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2017-02-02 13:33:38 +00:00
|
|
|
pi.pain.rectangle(expx, expy - dim.asc + 1, dim.wid - 1,
|
2008-01-25 22:02:38 +00:00
|
|
|
dim.height() - 2, Color_mathmacroframe);
|
2007-11-01 11:13:07 +00:00
|
|
|
} else {
|
2017-02-08 15:42:14 +00:00
|
|
|
// We should not be here, since the macro is linearized in this case.
|
|
|
|
LBUFERR(false);
|
2004-04-13 13:54:58 +00:00
|
|
|
}
|
2007-11-01 11:13:07 +00:00
|
|
|
|
2008-01-14 21:53:49 +00:00
|
|
|
// edit mode changed?
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->editing_[pi.base.bv] != editMode(pi.base.bv))
|
2010-07-08 20:04:35 +00:00
|
|
|
pi.base.bv->cursor().screenUpdateFlags(Update::SinglePar);
|
2001-04-24 16:13:38 +00:00
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2001-04-25 15:43:57 +00:00
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::setDisplayMode(InsetMathMacro::DisplayMode mode, int appetite)
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->displayMode_ != mode) {
|
2007-11-01 11:13:07 +00:00
|
|
|
// transfer name if changing from or to DISPLAY_UNFOLDED
|
|
|
|
if (mode == DISPLAY_UNFOLDED) {
|
|
|
|
cells_.resize(1);
|
2015-04-02 19:20:32 +00:00
|
|
|
asArray(d->name_, cell(0));
|
|
|
|
} else if (d->displayMode_ == DISPLAY_UNFOLDED) {
|
|
|
|
d->name_ = asString(cell(0));
|
2007-11-01 11:13:07 +00:00
|
|
|
cells_.resize(0);
|
|
|
|
}
|
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
d->displayMode_ = mode;
|
|
|
|
d->needsUpdate_ = true;
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-03-04 14:49:03 +00:00
|
|
|
// the interactive init mode is non-greedy by default
|
|
|
|
if (appetite == -1)
|
2015-04-02 19:20:32 +00:00
|
|
|
d->appetite_ = (mode == DISPLAY_INTERACTIVE_INIT) ? 0 : 9;
|
2008-03-04 14:49:03 +00:00
|
|
|
else
|
2015-04-02 19:20:32 +00:00
|
|
|
d->appetite_ = size_t(appetite);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro::DisplayMode InsetMathMacro::computeDisplayMode() const
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->nextFoldMode_ == true && d->macro_ && !d->macro_->locked())
|
2007-11-01 11:13:07 +00:00
|
|
|
return DISPLAY_NORMAL;
|
|
|
|
else
|
|
|
|
return DISPLAY_UNFOLDED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::validName() const
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
|
|
|
docstring n = name();
|
|
|
|
|
2012-10-21 19:14:16 +00:00
|
|
|
if (n.empty())
|
2007-11-01 11:13:07 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// converting back and force doesn't swallow anything?
|
|
|
|
/*MathData ma;
|
|
|
|
asArray(n, ma);
|
|
|
|
if (asString(ma) != n)
|
|
|
|
return false;*/
|
|
|
|
|
|
|
|
// valid characters?
|
|
|
|
for (size_t i = 0; i<n.size(); ++i) {
|
2008-02-27 10:43:29 +00:00
|
|
|
if (!(n[i] >= 'a' && n[i] <= 'z')
|
|
|
|
&& !(n[i] >= 'A' && n[i] <= 'Z')
|
2014-12-29 20:13:42 +00:00
|
|
|
&& n[i] != '*')
|
2007-11-01 11:13:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
size_t InsetMathMacro::arity() const
|
2015-05-17 15:27:12 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->displayMode_ == DISPLAY_NORMAL )
|
|
|
|
return cells_.size();
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
size_t InsetMathMacro::optionals() const
|
2015-04-02 19:20:32 +00:00
|
|
|
{
|
|
|
|
return d->optionals_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::setOptionals(int n)
|
2015-04-02 19:20:32 +00:00
|
|
|
{
|
|
|
|
if (n <= int(nargs()))
|
|
|
|
d->optionals_ = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
size_t InsetMathMacro::appetite() const
|
2015-04-02 19:20:32 +00:00
|
|
|
{
|
|
|
|
return d->appetite_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
MathClass InsetMathMacro::mathClass() const
|
2016-12-12 00:51:45 +00:00
|
|
|
{
|
2017-01-03 19:17:20 +00:00
|
|
|
// This can be just a heuristic, since it is only considered for display
|
|
|
|
// when the macro is not linearised. Therefore it affects:
|
|
|
|
// * The spacing of the inset while being edited,
|
|
|
|
// * Intelligent splitting
|
|
|
|
// * Cursor word movement (Ctrl-Arrow).
|
2016-12-12 00:51:45 +00:00
|
|
|
if (MacroData const * m = macroBackup()) {
|
2017-01-03 19:17:20 +00:00
|
|
|
// If it is a global macro and is defined explicitly
|
2016-12-12 00:51:45 +00:00
|
|
|
if (m->symbol()) {
|
2017-01-07 13:38:00 +00:00
|
|
|
MathClass mc = string_to_class(m->symbol()->extra);
|
2016-12-12 00:51:45 +00:00
|
|
|
if (mc != MC_UNKNOWN)
|
|
|
|
return mc;
|
|
|
|
}
|
|
|
|
}
|
2017-01-03 19:17:20 +00:00
|
|
|
// Otherwise guess from the expanded macro
|
|
|
|
return d->expanded_.mathClass();
|
2016-12-12 00:51:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMath::mode_type InsetMathMacro::currentMode() const
|
2016-09-24 23:11:16 +00:00
|
|
|
{
|
2017-10-08 21:21:10 +00:00
|
|
|
// User defined macros are always assumed to be mathmode macros.
|
|
|
|
// Only the global macros defined in lib/symbols may be textmode.
|
|
|
|
if (MacroData const * m = macroBackup()) {
|
|
|
|
if (m->symbol() && m->symbol()->extra == "textmode")
|
|
|
|
return TEXT_MODE;
|
|
|
|
else
|
|
|
|
return MATH_MODE;
|
|
|
|
}
|
|
|
|
// Unknown macros are undecided.
|
2016-12-12 00:17:41 +00:00
|
|
|
return UNDECIDED_MODE;
|
|
|
|
}
|
|
|
|
|
2016-09-24 23:11:16 +00:00
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
MacroData const * InsetMathMacro::macroBackup() const
|
2016-12-12 00:17:41 +00:00
|
|
|
{
|
|
|
|
if (macro())
|
|
|
|
return &d->macroBackup_;
|
|
|
|
if (MacroData const * data = MacroTable::globalMacros().get(name()))
|
|
|
|
return data;
|
|
|
|
return nullptr;
|
2016-09-24 23:11:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::validate(LaTeXFeatures & features) const
|
2001-07-13 14:54:56 +00:00
|
|
|
{
|
2015-06-24 22:49:15 +00:00
|
|
|
// Immediately after a document is loaded, in some cases the MacroData
|
|
|
|
// of the global macros defined in the lib/symbols file may still not
|
|
|
|
// be known to the macro machinery because it will be set only after
|
|
|
|
// the first call to updateMacros(). This is not a problem unless
|
|
|
|
// instant preview is on for math, in which case we will be missing
|
|
|
|
// the corresponding requirements.
|
|
|
|
// In this case, we get the required info from the global macro table.
|
2015-04-02 19:20:32 +00:00
|
|
|
if (!d->requires_.empty())
|
|
|
|
features.require(d->requires_);
|
2015-06-24 22:49:15 +00:00
|
|
|
else if (!d->macro_) {
|
|
|
|
// Update requires for known global macros.
|
|
|
|
MacroData const * data = MacroTable::globalMacros().get(name());
|
|
|
|
if (data && !data->requires().empty())
|
|
|
|
features.require(data->requires());
|
|
|
|
}
|
2007-05-04 15:30:27 +00:00
|
|
|
|
2008-10-23 00:48:06 +00:00
|
|
|
if (name() == "binom")
|
|
|
|
features.require("binom");
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-03-26 12:55:36 +00:00
|
|
|
// validate the cells and the definition
|
|
|
|
if (displayMode() == DISPLAY_NORMAL) {
|
2015-04-02 19:20:32 +00:00
|
|
|
d->definition_.validate(features);
|
2008-03-26 12:55:36 +00:00
|
|
|
InsetMathNest::validate(features);
|
|
|
|
}
|
2001-07-13 14:54:56 +00:00
|
|
|
}
|
2001-11-16 08:26:41 +00:00
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::edit(Cursor & cur, bool front, EntryDirection entry_from)
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2010-07-08 20:04:35 +00:00
|
|
|
cur.screenUpdateFlags(Update::SinglePar);
|
2008-02-10 19:52:45 +00:00
|
|
|
InsetMathNest::edit(cur, front, entry_from);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
Inset * InsetMathMacro::editXY(Cursor & cur, int x, int y)
|
2005-10-05 21:19:32 +00:00
|
|
|
{
|
2006-09-16 18:11:38 +00:00
|
|
|
// We may have 0 arguments, but InsetMathNest requires at least one.
|
2007-04-17 16:49:17 +00:00
|
|
|
if (nargs() > 0) {
|
2010-07-08 20:04:35 +00:00
|
|
|
cur.screenUpdateFlags(Update::SinglePar);
|
2014-12-29 20:13:42 +00:00
|
|
|
return InsetMathNest::editXY(cur, x, y);
|
2007-11-01 11:13:07 +00:00
|
|
|
} else
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::removeArgument(Inset::pos_type pos) {
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->displayMode_ == DISPLAY_NORMAL) {
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(size_t(pos) < cells_.size(), return);
|
2007-11-01 11:13:07 +00:00
|
|
|
cells_.erase(cells_.begin() + pos);
|
2015-04-02 19:20:32 +00:00
|
|
|
if (size_t(pos) < d->attachedArgsNum_)
|
|
|
|
--d->attachedArgsNum_;
|
|
|
|
if (size_t(pos) < d->optionals_) {
|
|
|
|
--d->optionals_;
|
2007-04-17 16:49:17 +00:00
|
|
|
}
|
2007-11-01 11:13:07 +00:00
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
d->needsUpdate_ = true;
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::insertArgument(Inset::pos_type pos) {
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->displayMode_ == DISPLAY_NORMAL) {
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(size_t(pos) <= cells_.size(), return);
|
2007-11-01 11:13:07 +00:00
|
|
|
cells_.insert(cells_.begin() + pos, MathData());
|
2015-04-02 19:20:32 +00:00
|
|
|
if (size_t(pos) < d->attachedArgsNum_)
|
|
|
|
++d->attachedArgsNum_;
|
|
|
|
if (size_t(pos) < d->optionals_)
|
|
|
|
++d->optionals_;
|
2007-11-01 11:13:07 +00:00
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
d->needsUpdate_ = true;
|
2007-04-17 16:49:17 +00:00
|
|
|
}
|
2005-10-05 21:19:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::detachArguments(vector<MathData> & args, bool strip)
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
LASSERT(d->displayMode_ == DISPLAY_NORMAL, return);
|
2007-11-01 11:13:07 +00:00
|
|
|
args = cells_;
|
|
|
|
|
|
|
|
// strip off empty cells, but not more than arity-attachedArgsNum_
|
|
|
|
if (strip) {
|
|
|
|
size_t i;
|
2015-04-02 19:20:32 +00:00
|
|
|
for (i = cells_.size(); i > d->attachedArgsNum_; --i)
|
2007-11-01 11:13:07 +00:00
|
|
|
if (!cell(i - 1).empty()) break;
|
|
|
|
args.resize(i);
|
|
|
|
}
|
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
d->attachedArgsNum_ = 0;
|
|
|
|
d->expanded_ = MathData();
|
2007-11-01 11:13:07 +00:00
|
|
|
cells_.resize(0);
|
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
d->needsUpdate_ = true;
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::attachArguments(vector<MathData> const & args, size_t arity, int optionals)
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
LASSERT(d->displayMode_ == DISPLAY_NORMAL, return);
|
2007-11-01 11:13:07 +00:00
|
|
|
cells_ = args;
|
2015-04-02 19:20:32 +00:00
|
|
|
d->attachedArgsNum_ = args.size();
|
2007-11-01 11:13:07 +00:00
|
|
|
cells_.resize(arity);
|
2015-04-02 19:20:32 +00:00
|
|
|
d->expanded_ = MathData();
|
|
|
|
d->optionals_ = optionals;
|
2007-11-01 11:13:07 +00:00
|
|
|
|
2015-04-02 19:20:32 +00:00
|
|
|
d->needsUpdate_ = true;
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::idxFirst(Cursor & cur) const
|
2007-04-16 14:42:53 +00:00
|
|
|
{
|
2010-07-08 20:04:35 +00:00
|
|
|
cur.screenUpdateFlags(Update::SinglePar);
|
2007-04-16 14:42:53 +00:00
|
|
|
return InsetMathNest::idxFirst(cur);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::idxLast(Cursor & cur) const
|
2007-04-16 14:42:53 +00:00
|
|
|
{
|
2010-07-08 20:04:35 +00:00
|
|
|
cur.screenUpdateFlags(Update::SinglePar);
|
2007-04-16 14:42:53 +00:00
|
|
|
return InsetMathNest::idxLast(cur);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::notifyCursorLeaves(Cursor const & old, Cursor & cur)
|
2007-06-14 20:57:56 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->displayMode_ == DISPLAY_UNFOLDED) {
|
2009-07-09 15:21:21 +00:00
|
|
|
docstring const & unfolded_name = name();
|
2015-04-02 19:20:32 +00:00
|
|
|
if (unfolded_name != d->name_) {
|
2009-07-09 15:21:21 +00:00
|
|
|
// The macro name was changed
|
2009-11-16 13:31:01 +00:00
|
|
|
Cursor inset_cursor = old;
|
|
|
|
int macroSlice = inset_cursor.find(this);
|
2013-04-25 21:27:10 +00:00
|
|
|
// returning true means the cursor is "now" invalid,
|
|
|
|
// which it was.
|
|
|
|
LASSERT(macroSlice != -1, return true);
|
2009-11-16 13:31:01 +00:00
|
|
|
inset_cursor.cutOff(macroSlice);
|
|
|
|
inset_cursor.recordUndoInset();
|
|
|
|
inset_cursor.pop();
|
|
|
|
inset_cursor.cell().erase(inset_cursor.pos());
|
|
|
|
inset_cursor.cell().insert(inset_cursor.pos(),
|
2009-11-15 23:54:45 +00:00
|
|
|
createInsetMath(unfolded_name, cur.buffer()));
|
2010-10-28 11:13:47 +00:00
|
|
|
cur.resetAnchor();
|
2010-10-13 17:28:55 +00:00
|
|
|
cur.screenUpdateFlags(cur.result().screenUpdate() | Update::SinglePar);
|
2009-07-09 15:21:21 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2010-07-08 20:04:35 +00:00
|
|
|
cur.screenUpdateFlags(Update::Force);
|
2008-02-22 20:45:18 +00:00
|
|
|
return InsetMathNest::notifyCursorLeaves(old, cur);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::fold(Cursor & cur)
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
if (!d->nextFoldMode_) {
|
|
|
|
d->nextFoldMode_ = true;
|
2010-07-08 20:04:35 +00:00
|
|
|
cur.screenUpdateFlags(Update::SinglePar);
|
2007-06-14 20:57:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::unfold(Cursor & cur)
|
2007-04-16 14:42:53 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->nextFoldMode_) {
|
|
|
|
d->nextFoldMode_ = false;
|
2010-07-08 20:04:35 +00:00
|
|
|
cur.screenUpdateFlags(Update::SinglePar);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2007-04-16 14:42:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::folded() const
|
2001-11-16 08:26:41 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
return d->nextFoldMode_;
|
2001-11-16 08:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::write(WriteStream & os) const
|
2001-11-16 08:29:11 +00:00
|
|
|
{
|
2017-10-08 21:21:10 +00:00
|
|
|
mode_type mode = currentMode();
|
|
|
|
MathEnsurer ensurer(os, mode == MATH_MODE, true, mode == TEXT_MODE);
|
2008-06-16 01:21:17 +00:00
|
|
|
|
2007-12-21 20:42:46 +00:00
|
|
|
// non-normal mode
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->displayMode_ != DISPLAY_NORMAL) {
|
2008-06-16 01:21:17 +00:00
|
|
|
os << "\\" << name();
|
2008-06-19 09:16:05 +00:00
|
|
|
if (name().size() != 1 || isAlphaASCII(name()[0]))
|
|
|
|
os.pendingSpace(true);
|
2007-12-21 20:42:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// normal mode
|
2013-04-25 21:27:10 +00:00
|
|
|
// we should be ok to continue even if this fails.
|
2015-04-02 19:20:32 +00:00
|
|
|
LATTEST(d->macro_);
|
2007-12-21 20:42:46 +00:00
|
|
|
|
Fix display and output of math macros with optional arguments
This is a long standing issue, present since the new math macros
inception in version 1.6. It manifests as a display issue when a
macro with optional arguments appears in the optional argument of
another macro. In this case the display is messed up and it is
difficult, if not impossible, changing the arguments as they do not
appear on screen as related to a specific macro instance. It also
manifests as latex errors when compiling, even if the latex output
is formally correct, due to limitations of the xargs package used
to output the macros. Most probably, both aspects have the same
root cause, as simply enclosing in braces the macro and its
parameters solves both issues. However, when reloading a document,
lyx strips the outer braces enclosing a macro argument, thus
frustrating this possible workaround.
This commit solves the display issue by correctly accounting for
macros with optional arguments nested in the argument of another
macro, and circumvents the xargs package limitations causing errors
by enclosing in braces the macros with optional arguments appearing
in the argument of an outer macro when they are output. This means
that when loading an old document with such macros and saving it
again, the macro representation is updated and will have these
additional braces. However, as such braces are stripped by lyx on
loading, there is no risk that they accumulate.
See also this thread:
http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg197828.html
2016-12-01 17:02:47 +00:00
|
|
|
// We may already be in the argument of a macro
|
|
|
|
bool const inside_macro = os.insideMacro();
|
|
|
|
os.insideMacro(true);
|
|
|
|
|
|
|
|
// Enclose in braces to avoid latex errors with xargs if we have
|
|
|
|
// optional arguments and are in the optional argument of a macro
|
|
|
|
if (d->optionals_ && inside_macro)
|
|
|
|
os << '{';
|
|
|
|
|
2014-02-22 15:30:55 +00:00
|
|
|
// Always protect macros in a fragile environment
|
|
|
|
if (os.fragile())
|
2007-12-21 20:43:50 +00:00
|
|
|
os << "\\protect";
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2007-12-21 20:42:46 +00:00
|
|
|
os << "\\" << name();
|
|
|
|
bool first = true;
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2007-12-23 16:31:37 +00:00
|
|
|
// Optional arguments:
|
|
|
|
// First find last non-empty optional argument
|
|
|
|
idx_type emptyOptFrom = 0;
|
|
|
|
idx_type i = 0;
|
2015-04-02 19:20:32 +00:00
|
|
|
for (; i < cells_.size() && i < d->optionals_; ++i) {
|
2007-12-23 16:31:37 +00:00
|
|
|
if (!cell(i).empty())
|
|
|
|
emptyOptFrom = i + 1;
|
|
|
|
}
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2007-12-23 16:31:37 +00:00
|
|
|
// print out optionals
|
|
|
|
for (i=0; i < cells_.size() && i < emptyOptFrom; ++i) {
|
|
|
|
first = false;
|
|
|
|
os << "[" << cell(i) << "]";
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2007-12-23 16:31:37 +00:00
|
|
|
// skip the tailing empty optionals
|
2015-04-02 19:20:32 +00:00
|
|
|
i = d->optionals_;
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2009-11-15 12:30:26 +00:00
|
|
|
// Print remaining arguments
|
2007-12-21 20:42:46 +00:00
|
|
|
for (; i < cells_.size(); ++i) {
|
2014-12-29 20:13:42 +00:00
|
|
|
if (cell(i).size() == 1
|
2008-10-07 16:24:07 +00:00
|
|
|
&& cell(i)[0].nucleus()->asCharInset()
|
2012-12-30 10:58:21 +00:00
|
|
|
&& isASCII(cell(i)[0].nucleus()->asCharInset()->getChar())) {
|
2007-12-21 20:42:46 +00:00
|
|
|
if (first)
|
|
|
|
os << " ";
|
|
|
|
os << cell(i);
|
|
|
|
} else
|
|
|
|
os << "{" << cell(i) << "}";
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
Fix display and output of math macros with optional arguments
This is a long standing issue, present since the new math macros
inception in version 1.6. It manifests as a display issue when a
macro with optional arguments appears in the optional argument of
another macro. In this case the display is messed up and it is
difficult, if not impossible, changing the arguments as they do not
appear on screen as related to a specific macro instance. It also
manifests as latex errors when compiling, even if the latex output
is formally correct, due to limitations of the xargs package used
to output the macros. Most probably, both aspects have the same
root cause, as simply enclosing in braces the macro and its
parameters solves both issues. However, when reloading a document,
lyx strips the outer braces enclosing a macro argument, thus
frustrating this possible workaround.
This commit solves the display issue by correctly accounting for
macros with optional arguments nested in the argument of another
macro, and circumvents the xargs package limitations causing errors
by enclosing in braces the macros with optional arguments appearing
in the argument of an outer macro when they are output. This means
that when loading an old document with such macros and saving it
again, the macro representation is updated and will have these
additional braces. However, as such braces are stripped by lyx on
loading, there is no risk that they accumulate.
See also this thread:
http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg197828.html
2016-12-01 17:02:47 +00:00
|
|
|
// Close the opened brace or add space if there was no argument
|
|
|
|
if (d->optionals_ && inside_macro)
|
|
|
|
os << '}';
|
|
|
|
else if (first)
|
2007-12-21 20:42:46 +00:00
|
|
|
os.pendingSpace(true);
|
Fix display and output of math macros with optional arguments
This is a long standing issue, present since the new math macros
inception in version 1.6. It manifests as a display issue when a
macro with optional arguments appears in the optional argument of
another macro. In this case the display is messed up and it is
difficult, if not impossible, changing the arguments as they do not
appear on screen as related to a specific macro instance. It also
manifests as latex errors when compiling, even if the latex output
is formally correct, due to limitations of the xargs package used
to output the macros. Most probably, both aspects have the same
root cause, as simply enclosing in braces the macro and its
parameters solves both issues. However, when reloading a document,
lyx strips the outer braces enclosing a macro argument, thus
frustrating this possible workaround.
This commit solves the display issue by correctly accounting for
macros with optional arguments nested in the argument of another
macro, and circumvents the xargs package limitations causing errors
by enclosing in braces the macros with optional arguments appearing
in the argument of an outer macro when they are output. This means
that when loading an old document with such macros and saving it
again, the macro representation is updated and will have these
additional braces. However, as such braces are stripped by lyx on
loading, there is no risk that they accumulate.
See also this thread:
http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg197828.html
2016-12-01 17:02:47 +00:00
|
|
|
|
|
|
|
os.insideMacro(inside_macro);
|
2001-11-16 08:29:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::maple(MapleStream & os) const
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
lyx::maple(d->expanded_, os);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::maxima(MaximaStream & os) const
|
2015-03-29 11:53:01 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
lyx::maxima(d->expanded_, os);
|
2015-03-29 11:53:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::mathematica(MathematicaStream & os) const
|
2015-03-29 11:53:01 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
lyx::mathematica(d->expanded_, os);
|
2015-03-29 11:53:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::mathmlize(MathStream & os) const
|
2001-11-16 08:29:11 +00:00
|
|
|
{
|
2015-02-16 21:33:48 +00:00
|
|
|
// macro_ is 0 if this is an unknown macro
|
2015-04-02 19:20:32 +00:00
|
|
|
LATTEST(d->macro_ || d->displayMode_ != DISPLAY_NORMAL);
|
|
|
|
if (d->macro_) {
|
|
|
|
docstring const xmlname = d->macro_->xmlname();
|
2014-12-29 20:13:42 +00:00
|
|
|
if (!xmlname.empty()) {
|
2015-04-02 19:20:32 +00:00
|
|
|
char const * type = d->macro_->MathMLtype();
|
2016-05-22 15:32:04 +00:00
|
|
|
os << '<' << type << "> " << xmlname << " </"
|
2014-12-29 20:13:42 +00:00
|
|
|
<< type << '>';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->expanded_.empty()) {
|
2011-04-01 20:15:43 +00:00
|
|
|
// this means that we do not recognize the macro
|
|
|
|
throw MathExportException();
|
|
|
|
}
|
2015-04-02 19:20:32 +00:00
|
|
|
os << d->expanded_;
|
2001-11-16 08:26:41 +00:00
|
|
|
}
|
2001-12-11 11:33:43 +00:00
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::htmlize(HtmlStream & os) const
|
2010-03-30 00:18:24 +00:00
|
|
|
{
|
2015-02-16 21:33:48 +00:00
|
|
|
// macro_ is 0 if this is an unknown macro
|
2015-04-02 19:20:32 +00:00
|
|
|
LATTEST(d->macro_ || d->displayMode_ != DISPLAY_NORMAL);
|
|
|
|
if (d->macro_) {
|
|
|
|
docstring const xmlname = d->macro_->xmlname();
|
2014-12-29 20:13:42 +00:00
|
|
|
if (!xmlname.empty()) {
|
|
|
|
os << ' ' << xmlname << ' ';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-04-02 19:20:32 +00:00
|
|
|
if (d->expanded_.empty()) {
|
2011-04-01 20:15:43 +00:00
|
|
|
// this means that we do not recognize the macro
|
|
|
|
throw MathExportException();
|
|
|
|
}
|
2015-04-02 19:20:32 +00:00
|
|
|
os << d->expanded_;
|
2010-03-30 00:18:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::octave(OctaveStream & os) const
|
2007-04-17 16:49:17 +00:00
|
|
|
{
|
2015-04-02 19:20:32 +00:00
|
|
|
lyx::octave(d->expanded_, os);
|
2007-04-17 16:49:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::infoize(odocstream & os) const
|
2003-01-07 11:24:43 +00:00
|
|
|
{
|
2014-11-14 17:18:30 +00:00
|
|
|
os << bformat(_("Macro: %1$s"), name());
|
2003-01-07 11:24:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::infoize2(odocstream & os) const
|
2003-01-07 11:24:43 +00:00
|
|
|
{
|
2014-11-14 17:18:30 +00:00
|
|
|
os << bformat(_("Macro: %1$s"), name());
|
2003-01-07 11:24:43 +00:00
|
|
|
}
|
2006-10-21 00:16:43 +00:00
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::completionSupported(Cursor const & cur) const
|
2008-02-21 19:42:34 +00:00
|
|
|
{
|
2008-02-21 19:45:36 +00:00
|
|
|
if (displayMode() != DISPLAY_UNFOLDED)
|
|
|
|
return InsetMathNest::completionSupported(cur);
|
|
|
|
|
2008-02-21 19:42:34 +00:00
|
|
|
return lyxrc.completion_popup_math
|
|
|
|
&& displayMode() == DISPLAY_UNFOLDED
|
|
|
|
&& cur.bv().cursor().pos() == int(name().size());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::inlineCompletionSupported(Cursor const & cur) const
|
2008-02-21 19:42:34 +00:00
|
|
|
{
|
2008-02-21 19:45:36 +00:00
|
|
|
if (displayMode() != DISPLAY_UNFOLDED)
|
|
|
|
return InsetMathNest::inlineCompletionSupported(cur);
|
|
|
|
|
2008-02-21 19:42:34 +00:00
|
|
|
return lyxrc.completion_inline_math
|
|
|
|
&& displayMode() == DISPLAY_UNFOLDED
|
|
|
|
&& cur.bv().cursor().pos() == int(name().size());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::automaticInlineCompletion() const
|
2008-02-21 19:42:34 +00:00
|
|
|
{
|
2008-02-21 19:45:36 +00:00
|
|
|
if (displayMode() != DISPLAY_UNFOLDED)
|
|
|
|
return InsetMathNest::automaticInlineCompletion();
|
|
|
|
|
2008-02-21 19:42:34 +00:00
|
|
|
return lyxrc.completion_inline_math;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::automaticPopupCompletion() const
|
2008-02-21 19:42:34 +00:00
|
|
|
{
|
2008-02-21 19:45:36 +00:00
|
|
|
if (displayMode() != DISPLAY_UNFOLDED)
|
|
|
|
return InsetMathNest::automaticPopupCompletion();
|
|
|
|
|
2008-02-21 19:42:34 +00:00
|
|
|
return lyxrc.completion_popup_math;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-29 20:13:42 +00:00
|
|
|
CompletionList const *
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro::createCompletionList(Cursor const & cur) const
|
2008-02-21 19:42:34 +00:00
|
|
|
{
|
2008-02-21 19:45:36 +00:00
|
|
|
if (displayMode() != DISPLAY_UNFOLDED)
|
2008-02-22 21:11:19 +00:00
|
|
|
return InsetMathNest::createCompletionList(cur);
|
2008-02-21 19:45:36 +00:00
|
|
|
|
2008-02-21 23:36:02 +00:00
|
|
|
return new MathCompletionList(cur.bv().cursor());
|
2008-02-21 19:42:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
docstring InsetMathMacro::completionPrefix(Cursor const & cur) const
|
2008-02-21 19:42:34 +00:00
|
|
|
{
|
2008-02-21 19:45:36 +00:00
|
|
|
if (displayMode() != DISPLAY_UNFOLDED)
|
|
|
|
return InsetMathNest::completionPrefix(cur);
|
|
|
|
|
2008-02-21 19:42:34 +00:00
|
|
|
if (!completionSupported(cur))
|
|
|
|
return docstring();
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-02-21 19:42:34 +00:00
|
|
|
return "\\" + name();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
bool InsetMathMacro::insertCompletion(Cursor & cur, docstring const & s,
|
2008-02-21 19:42:34 +00:00
|
|
|
bool finished)
|
|
|
|
{
|
2008-02-21 19:45:36 +00:00
|
|
|
if (displayMode() != DISPLAY_UNFOLDED)
|
|
|
|
return InsetMathNest::insertCompletion(cur, s, finished);
|
|
|
|
|
|
|
|
if (!completionSupported(cur))
|
2008-02-21 19:42:34 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// append completion
|
|
|
|
docstring newName = name() + s;
|
|
|
|
asArray(newName, cell(0));
|
|
|
|
cur.bv().cursor().pos() = name().size();
|
2010-07-08 20:04:35 +00:00
|
|
|
cur.screenUpdateFlags(Update::SinglePar);
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-02-21 19:42:34 +00:00
|
|
|
// finish macro
|
|
|
|
if (finished) {
|
|
|
|
cur.bv().cursor().pop();
|
|
|
|
++cur.bv().cursor().pos();
|
2010-07-08 20:04:35 +00:00
|
|
|
cur.screenUpdateFlags(Update::SinglePar);
|
2008-02-21 19:42:34 +00:00
|
|
|
}
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-02-21 19:42:34 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-05 12:31:28 +00:00
|
|
|
void InsetMathMacro::completionPosAndDim(Cursor const & cur, int & x, int & y,
|
2008-02-21 19:42:34 +00:00
|
|
|
Dimension & dim) const
|
|
|
|
{
|
2008-02-21 19:45:36 +00:00
|
|
|
if (displayMode() != DISPLAY_UNFOLDED)
|
|
|
|
InsetMathNest::completionPosAndDim(cur, x, y, dim);
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-02-21 19:42:34 +00:00
|
|
|
// get inset dimensions
|
|
|
|
dim = cur.bv().coordCache().insets().dim(this);
|
2008-02-21 19:45:05 +00:00
|
|
|
// FIXME: these 3 are no accurate, but should depend on the font.
|
|
|
|
// Now the popup jumps down if you enter a char with descent > 0.
|
|
|
|
dim.des += 3;
|
|
|
|
dim.asc += 3;
|
2014-12-29 20:13:42 +00:00
|
|
|
|
2008-02-21 19:45:05 +00:00
|
|
|
// and position
|
2008-02-21 19:42:34 +00:00
|
|
|
Point xy
|
|
|
|
= cur.bv().coordCache().insets().xy(this);
|
|
|
|
x = xy.x_;
|
|
|
|
y = xy.y_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-02 03:18:52 +00:00
|
|
|
void InsetMathMacro::setBuffer(Buffer & buffer)
|
|
|
|
{
|
|
|
|
d->definition_.setBuffer(buffer);
|
|
|
|
InsetMathNest::setBuffer(buffer);
|
|
|
|
}
|
|
|
|
|
2006-10-21 00:16:43 +00:00
|
|
|
} // namespace lyx
|