#include "MathMacroTemplate.h"
#include "DocIterator.h"
+#include "LaTeXFeatures.h"
#include "InsetMathBrace.h"
#include "InsetMathChar.h"
#include "InsetMathSqrt.h"
#include "BufferView.h"
#include "Color.h"
#include "Cursor.h"
-#include "support/debug.h"
#include "DispatchResult.h"
#include "FuncRequest.h"
#include "FuncStatus.h"
-#include "support/gettext.h"
#include "Lexer.h"
#include "Undo.h"
-#include "frontends/FontMetrics.h"
#include "frontends/Painter.h"
#include "support/convert.h"
+#include "support/debug.h"
+#include "support/gettext.h"
#include "support/docstream.h"
#include "support/lstrings.h"
-#include "support/debug.h"
-
#include <sstream>
using namespace std;
class InsetLabelBox : public InsetMathNest {
public:
///
- InsetLabelBox(MathAtom const & atom, docstring label,
- MathMacroTemplate const & parent, bool frame = false);
- InsetLabelBox(docstring label, MathMacroTemplate const & parent,
- bool frame = false);
+ InsetLabelBox(MathAtom const & atom, docstring label,
+ MathMacroTemplate const & parent, bool frame = false);
+ InsetLabelBox(docstring label, MathMacroTemplate const & parent,
+ bool frame = false);
///
void metrics(MetricsInfo & mi, Dimension & dim) const;
///
void draw(PainterInfo &, int x, int y) const;
-
+
protected:
///
MathMacroTemplate const & parent_;
};
-InsetLabelBox::InsetLabelBox(MathAtom const & atom, docstring label,
- MathMacroTemplate const & parent, bool frame)
-: InsetMathNest(1), parent_(parent), label_(label), frame_(frame)
+InsetLabelBox::InsetLabelBox(MathAtom const & atom, docstring label,
+ MathMacroTemplate const & parent, bool frame)
+ : InsetMathNest(1), parent_(parent), label_(label), frame_(frame)
{
cell(0).insert(0, atom);
}
InsetLabelBox::InsetLabelBox(docstring label,
- MathMacroTemplate const & parent, bool frame)
-: InsetMathNest(1), parent_(parent), label_(label), frame_(frame)
+ MathMacroTemplate const & parent, bool frame)
+ : InsetMathNest(1), parent_(parent), label_(label), frame_(frame)
{
}
-
-Inset * InsetLabelBox::clone() const
+
+Inset * InsetLabelBox::clone() const
{
return new InsetLabelBox(*this);
}
-void InsetLabelBox::metrics(MetricsInfo & mi, Dimension & dim) const
+void InsetLabelBox::metrics(MetricsInfo & mi, Dimension & dim) const
{
// kernel
cell(0).metrics(mi, dim);
dim.asc += 5;
dim.des += 5;
}
-
+
// adjust to common height in main metrics phase
if (!parent_.premetrics()) {
dim.asc = max(dim.asc, parent_.commonLabelBoxAscent());
dim.des = max(dim.des, parent_.commonLabelBoxDescent());
}
-
+
// label
if (parent_.editing(mi.base.bv) && label_.length() > 0) {
// grey
FontInfo font = sane_font;
font.setSize(FONT_SIZE_TINY);
font.setColor(Color_mathmacrolabel);
-
+
// make space for label and box
int lwid = mathed_string_width(font, label_);
int maxasc;
int maxdes;
- math_font_max_dim(font, maxasc, maxdes);
-
+ math_font_max_dim(font, maxasc, maxdes);
+
dim.wid = max(dim.wid, lwid + 2);
// space for the label
if (!parent_.premetrics())
dim.des += maxasc + maxdes + 1;
}
-
- setDimCache(mi, dim);
}
-void InsetLabelBox::draw(PainterInfo & pi, int x, int y) const
+void InsetLabelBox::draw(PainterInfo & pi, int x, int y) const
{
Dimension const dim = dimension(*pi.base.bv);
Dimension const cdim = cell(0).dimension(*pi.base.bv);
-
+
// kernel
cell(0).draw(pi, x + (dim.wid - cdim.wid) / 2, y);
-
+
// label
if (parent_.editing(pi.base.bv) && label_.length() > 0) {
// grey
FontInfo font = sane_font;
font.setSize(FONT_SIZE_TINY);
font.setColor(Color_mathmacrolabel);
-
+
// make space for label and box
int lwid = mathed_string_width(font, label_);
int maxasc;
int maxdes;
math_font_max_dim(font, maxasc, maxdes);
-
+
if (lwid < dim.wid)
pi.pain.text(x + (dim.wid - lwid) / 2, y + dim.des - maxdes, label_, font);
else
pi.pain.text(x, y + dim.des - maxdes, label_, font);
}
-
+
// draw frame
int boxHeight = parent_.commonLabelBoxAscent() + parent_.commonLabelBoxDescent();
if (frame_) {
- pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
- dim.wid - 2, boxHeight - 2,
- Color_mathline);
+ pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
+ dim.wid - 2, boxHeight - 2,
+ Color_mathline);
}
}
class DisplayLabelBox : public InsetLabelBox {
public:
///
- DisplayLabelBox(MathAtom const & atom, docstring label,
- MathMacroTemplate const & parent);
-
+ DisplayLabelBox(MathAtom const & atom, docstring label,
+ MathMacroTemplate const & parent);
+
///
void metrics(MetricsInfo & mi, Dimension & dim) const;
///
void draw(PainterInfo &, int x, int y) const;
-
+
protected:
///
Inset * clone() const;
};
-DisplayLabelBox::DisplayLabelBox(MathAtom const & atom,
- docstring label,
- MathMacroTemplate const & parent)
+DisplayLabelBox::DisplayLabelBox(MathAtom const & atom,
+ docstring label,
+ MathMacroTemplate const & parent)
: InsetLabelBox(atom, label, parent, true)
{
}
-
-
-
-Inset * DisplayLabelBox::clone() const
+
+
+
+Inset * DisplayLabelBox::clone() const
{
return new DisplayLabelBox(*this);
}
-
-
+
+
void DisplayLabelBox::metrics(MetricsInfo & mi, Dimension & dim) const
{
InsetLabelBox::metrics(mi, dim);
if (!parent_.editing(mi.base.bv)
- && parent_.cell(parent_.displayIdx()).empty()) {
+ && parent_.cell(parent_.displayIdx()).empty()) {
dim.wid = 0;
dim.asc = 0;
dim.des = 0;
- setDimCache(mi, dim);
}
}
-
+
void DisplayLabelBox::draw(PainterInfo & pi, int x, int y) const
{
if (parent_.editing(pi.base.bv)
- || !parent_.cell(parent_.displayIdx()).empty()) {
+ || !parent_.cell(parent_.displayIdx()).empty()) {
InsetLabelBox::draw(pi, x, y);
} else {
bool enabled = pi.pain.isDrawingEnabled();
pi.pain.setDrawingEnabled(enabled);
}
}
-
+
//////////////////////////////////////////////////////////////////////
void metrics(MetricsInfo & mi, Dimension & dim) const;
///
void draw(PainterInfo &, int x, int y) const;
-
+
private:
///
Inset * clone() const;
};
-Inset * InsetMathWrapper::clone() const
+Inset * InsetMathWrapper::clone() const
{
return new InsetMathWrapper(*this);
}
-void InsetMathWrapper::metrics(MetricsInfo & mi, Dimension & dim) const
+void InsetMathWrapper::metrics(MetricsInfo & mi, Dimension & dim) const
{
value_->metrics(mi, dim);
//metricsMarkers2(dim);
}
-void InsetMathWrapper::draw(PainterInfo & pi, int x, int y) const
+void InsetMathWrapper::draw(PainterInfo & pi, int x, int y) const
{
value_->draw(pi, x, y);
//drawMarkers(pi, x, y);
}
+///////////////////////////////////////////////////////////////////////
+class InsetColoredCell : public InsetMathNest {
+public:
+ ///
+ InsetColoredCell(ColorCode min, ColorCode max);
+ ///
+ InsetColoredCell(ColorCode min, ColorCode max, MathAtom const & atom);
+ ///
+ void draw(PainterInfo &, int x, int y) const;
+ ///
+ void metrics(MetricsInfo & mi, Dimension & dim) const;
+
+protected:
+ ///
+ Inset * clone() const;
+ ///
+ ColorCode min_;
+ ///
+ ColorCode max_;
+};
+
+
+InsetColoredCell::InsetColoredCell(ColorCode min, ColorCode max)
+ : InsetMathNest(1), min_(min), max_(max)
+{
+}
+
+
+InsetColoredCell::InsetColoredCell(ColorCode min, ColorCode max, MathAtom const & atom)
+ : InsetMathNest(1), min_(min), max_(max)
+{
+ cell(0).insert(0, atom);
+}
+
+
+Inset * InsetColoredCell::clone() const
+{
+ return new InsetColoredCell(*this);
+}
+
+
+void InsetColoredCell::metrics(MetricsInfo & mi, Dimension & dim) const
+{
+ cell(0).metrics(mi, dim);
+}
+
+
+void InsetColoredCell::draw(PainterInfo & pi, int x, int y) const
+{
+ pi.pain.enterMonochromeMode(min_, max_);
+ cell(0).draw(pi, x, y);
+ pi.pain.leaveMonochromeMode();
+}
+
+
///////////////////////////////////////////////////////////////////////
class InsetNameWrapper : public InsetMathWrapper {
void metrics(MetricsInfo & mi, Dimension & dim) const;
///
void draw(PainterInfo &, int x, int y) const;
-
+
private:
///
MathMacroTemplate const & parent_;
};
-InsetNameWrapper::InsetNameWrapper(MathData const * value,
- MathMacroTemplate const & parent)
- : InsetMathWrapper(value), parent_(parent)
+InsetNameWrapper::InsetNameWrapper(MathData const * value,
+ MathMacroTemplate const & parent)
+ : InsetMathWrapper(value), parent_(parent)
{
}
-Inset * InsetNameWrapper::clone() const
+Inset * InsetNameWrapper::clone() const
{
return new InsetNameWrapper(*this);
}
-void InsetNameWrapper::metrics(MetricsInfo & mi, Dimension & dim) const
+void InsetNameWrapper::metrics(MetricsInfo & mi, Dimension & dim) const
{
InsetMathWrapper::metrics(mi, dim);
dim.wid += mathed_string_width(mi.base.font, from_ascii("\\"));
}
-void InsetNameWrapper::draw(PainterInfo & pi, int x, int y) const
+void InsetNameWrapper::draw(PainterInfo & pi, int x, int y) const
{
// create fonts
PainterInfo namepi = pi;
if (parent_.validMacro())
namepi.base.font.setColor(Color_latex);
else
- namepi.base.font.setColor(Color_error);
-
+ namepi.base.font.setColor(Color_error);
+
// draw backslash
pi.pain.text(x, y, from_ascii("\\"), namepi.base.font);
x += mathed_string_width(namepi.base.font, from_ascii("\\"));
-
+
// draw name
InsetMathWrapper::draw(namepi, x, y);
}
-
+
///////////////////////////////////////////////////////////////////////
-
-
+
+
MathMacroTemplate::MathMacroTemplate()
- : InsetMathNest(3), numargs_(0), optionals_(0),
+ : InsetMathNest(3), numargs_(0), argsInLook_(0), optionals_(0),
type_(MacroTypeNewcommand), lookOutdated_(true)
{
initMath();
MathMacroTemplate::MathMacroTemplate(docstring const & name, int numargs,
- int optionals, MacroType type,
- vector<MathData> const & optionalValues,
+ int optionals, MacroType type,
+ vector<MathData> const & optionalValues,
MathData const & def, MathData const & display)
- : InsetMathNest(optionals + 3), numargs_(numargs),
+ : InsetMathNest(optionals + 3), numargs_(numargs), argsInLook_(numargs),
optionals_(optionals), optionalValues_(optionalValues),
type_(type), lookOutdated_(true)
{
if (numargs_ > 9)
lyxerr << "MathMacroTemplate::MathMacroTemplate: wrong # of arguments: "
<< numargs_ << endl;
-
+
asArray(name, cell(0));
optionalValues_.resize(9);
- for (int i = 0; i < optionals_; ++i)
+ for (int i = 0; i < optionals_; ++i)
cell(optIdx(i)) = optionalValues_[i];
cell(defIdx()) = def;
cell(displayIdx()) = display;
Inset * MathMacroTemplate::clone() const
{
- return new MathMacroTemplate(*this);
+ MathMacroTemplate * inset = new MathMacroTemplate(*this);
+ // the parent pointers of the proxy insets above will point to
+ // to the old template. Hence, the look must be updated.
+ inset->updateLook();
+ return inset;
}
redefinition_ = mc.get(name()) != 0;
}
-
+
void MathMacroTemplate::updateLook() const
{
lookOutdated_ = true;
}
-void MathMacroTemplate::createLook() const
+void MathMacroTemplate::createLook(int args) const
{
look_.clear();
+ argsInLook_ = args;
// \foo
look_.push_back(MathAtom(new InsetLabelBox(_("Name"), *this, false)));
MathData & nameData = look_[look_.size() - 1].nucleus()->cell(0);
nameData.push_back(MathAtom(new InsetNameWrapper(&cell(0), *this)));
-
+
// [#1][#2]
int i = 0;
if (optionals_ > 0) {
look_.push_back(MathAtom(new InsetLabelBox(_("optional"), *this, false)));
- MathData & optData = look_[look_.size() - 1].nucleus()->cell(0);
-
+
+ MathData * optData = &look_[look_.size() - 1].nucleus()->cell(0);
for (; i < optionals_; ++i) {
- optData.push_back(MathAtom(new InsetMathChar('[')));
- optData.push_back(MathAtom(new InsetMathWrapper(&cell(1 + i))));
- optData.push_back(MathAtom(new InsetMathChar(']')));
+ // color it light grey, if it is to be removed when the cursor leaves
+ if (i == argsInLook_) {
+ optData->push_back(MathAtom(
+ new InsetColoredCell(Color_mathbg, Color_mathmacrooldarg)));
+ optData = &(*optData)[optData->size() - 1].nucleus()->cell(0);
+ }
+
+ optData->push_back(MathAtom(new InsetMathChar('[')));
+ optData->push_back(MathAtom(new InsetMathWrapper(&cell(1 + i))));
+ optData->push_back(MathAtom(new InsetMathChar(']')));
}
}
-
+
// {#3}{#4}
for (; i < numargs_; ++i) {
MathData arg;
arg.push_back(MathAtom(new MathMacroArgument(i + 1)));
- look_.push_back(MathAtom(new InsetMathBrace(arg)));
+ if (i >= argsInLook_) {
+ look_.push_back(MathAtom(new InsetColoredCell(
+ Color_mathbg, Color_mathmacrooldarg,
+ MathAtom(new InsetMathBrace(arg)))));
+ } else
+ look_.push_back(MathAtom(new InsetMathBrace(arg)));
+ }
+ for (; i < argsInLook_; ++i) {
+ MathData arg;
+ arg.push_back(MathAtom(new MathMacroArgument(i + 1)));
+ look_.push_back(MathAtom(new InsetColoredCell(
+ Color_mathbg, Color_mathmacronewarg,
+ MathAtom(new InsetMathBrace(arg)))));
}
// :=
new DisplayLabelBox(MathAtom(
new InsetMathWrapper(&cell(displayIdx()))), _("LyX"), *this)));
}
-
+
void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
{
FontSetChanger dummy1(mi.base, from_ascii("mathnormal"));
StyleChanger dummy2(mi.base, LM_ST_TEXT);
-
+
// valid macro?
MacroData const * macro = 0;
if (validName()) {
// updateToContext() - avoids another lookup
redefinition_ = macro != 0;
}
-
+
// update look?
- if (lookOutdated_) {
+ int argsInDef = maxArgumentInDefinition();
+ if (lookOutdated_ || argsInDef != argsInLook_) {
lookOutdated_ = false;
- createLook();
+ createLook(argsInDef);
}
-
+
/// metrics for inset contents
if (macro)
- macro->lock();
-
+ macro->lock();
+
// first phase, premetric:
premetrics_ = true;
look_.metrics(mi, dim);
labelBoxAscent_ = dim.asc;
labelBoxDescent_ = dim.des;
-
+
// second phase, main metric:
premetrics_ = false;
look_.metrics(mi, dim);
-
+
if (macro)
macro->unlock();
-
+
dim.wid += 6;
dim.des += 2;
dim.asc += 2;
-
+
setDimCache(mi, dim);
}
{
FontSetChanger dummy1(pi.base, from_ascii("mathnormal"));
StyleChanger dummy2(pi.base, LM_ST_TEXT);
-
+
setPosCache(pi, x, y);
Dimension const dim = dimension(*pi.base.bv);
int const a = y - dim.asc + 1;
int const w = dim.wid - 2;
int const h = dim.height() - 2;
- pi.pain.rectangle(x, a, w, h, Color_mathframe);
-
+ pi.pain.rectangle(x, a, w, h, Color_mathframe);
+
// just to be sure: set some dummy values for coord cache
- for (idx_type i = 0; i < nargs(); ++i) {
+ for (idx_type i = 0; i < nargs(); ++i)
cell(i).setXY(*pi.base.bv, x, y);
- }
-
+
// draw contents
look_.draw(pi, x + 3, y);
}
-
-void MathMacroTemplate::edit(Cursor & cur, bool left)
+
+void MathMacroTemplate::edit(Cursor & cur, bool front, EntryDirection entry_from)
{
updateLook();
- cur.updateFlags(Update::Force);
- InsetMathNest::edit(cur, left);
+ cur.updateFlags(Update::SinglePar);
+ InsetMathNest::edit(cur, front, entry_from);
}
-
-
-Inset * MathMacroTemplate::editXY(Cursor & cur, int x, int y)
+
+
+bool MathMacroTemplate::notifyCursorLeaves(Cursor const & old, Cursor & cur)
{
- Inset * ret = InsetMathNest::editXY(cur, x, y);
-/* if (!editing_ && editing(cur.bv())) {
-
- cur.updateFlags(Update::Force);
- }*/
- return ret;
-}
-
+ // find this in cursor old
+ Cursor insetCur = old;
+ int scriptSlice = insetCur.find(this);
+ BOOST_ASSERT(scriptSlice != -1);
+ insetCur.cutOff(scriptSlice);
-bool MathMacroTemplate::notifyCursorLeaves(Cursor & cur)
-{
+ commitEditChanges(insetCur);
updateLook();
cur.updateFlags(Update::Force);
- return InsetMathNest::notifyCursorLeaves(cur);
+ return InsetMathNest::notifyCursorLeaves(old, cur);
}
-
+
void MathMacroTemplate::removeArguments(Cursor & cur, int from, int to) {
for (DocIterator it = doc_iterator_begin(*this); it; it.forwardChar()) {
if (!it.nextInset())
- continue;
+ continue;
if (it.nextInset()->lyxCode() != MATHMACROARG_CODE)
- continue;
+ continue;
MathMacroArgument * arg = static_cast<MathMacroArgument*>(it.nextInset());
int n = arg->number() - 1;
if (from <= n && n <= to) {
int cellSlice = cur.find(it.cell());
if (cellSlice != -1 && cur[cellSlice].pos() > it.pos())
- --cur[cellSlice].pos();
+ --cur[cellSlice].pos();
it.cell().erase(it.pos());
}
}
-
+
updateLook();
}
void MathMacroTemplate::shiftArguments(size_t from, int by) {
for (DocIterator it = doc_iterator_begin(*this); it; it.forwardChar()) {
if (!it.nextInset())
- continue;
+ continue;
if (it.nextInset()->lyxCode() != MATHMACROARG_CODE)
- continue;
+ continue;
MathMacroArgument * arg = static_cast<MathMacroArgument*>(it.nextInset());
- if (arg->number() >= from + 1)
+ if (arg->number() >= int(from) + 1)
arg->setNumber(arg->number() + by);
}
}
+int MathMacroTemplate::maxArgumentInDefinition() const
+{
+ int maxArg = 0;
+ MathMacroTemplate * nonConst = const_cast<MathMacroTemplate *>(this);
+ DocIterator it = doc_iterator_begin(*nonConst);
+ it.idx() = defIdx();
+ for (; it; it.forwardChar()) {
+ if (!it.nextInset())
+ continue;
+ if (it.nextInset()->lyxCode() != MATHMACROARG_CODE)
+ continue;
+ MathMacroArgument * arg = static_cast<MathMacroArgument*>(it.nextInset());
+ maxArg = std::max(int(arg->number()), maxArg);
+ }
+ return maxArg;
+}
+
+
+void MathMacroTemplate::insertMissingArguments(int maxArg)
+{
+ bool found[9] = { false, false, false, false, false, false, false, false, false };
+ idx_type idx = cell(displayIdx()).empty() ? defIdx() : displayIdx();
+
+ // search for #n macros arguments
+ DocIterator it = doc_iterator_begin(*this);
+ it.idx() = idx;
+ for (; it && it[0].idx() == idx; it.forwardChar()) {
+ if (!it.nextInset())
+ continue;
+ if (it.nextInset()->lyxCode() != MATHMACROARG_CODE)
+ continue;
+ MathMacroArgument * arg = static_cast<MathMacroArgument*>(it.nextInset());
+ found[arg->number() - 1] = true;
+ }
+
+ // add missing ones
+ for (int i = 0; i < maxArg; ++i) {
+ if (found[i])
+ continue;
+
+ cell(idx).push_back(MathAtom(new MathMacroArgument(i + 1)));
+ }
+}
+
+
+void MathMacroTemplate::changeArity(Cursor & cur, int newNumArg)
+{
+ // remove parameter which do not appear anymore in the definition
+ for (int i = numargs_; i > newNumArg; --i)
+ removeParameter(cur, numargs_ - 1, false);
+
+ // add missing parameter
+ for (int i = numargs_; i < newNumArg; ++i)
+ insertParameter(cur, numargs_, false, false);
+}
+
+
+void MathMacroTemplate::commitEditChanges(Cursor & cur)
+{
+ int argsInDef = maxArgumentInDefinition();
+ if (argsInDef != numargs_) {
+ cur.recordUndoFullDocument();
+ changeArity(cur, argsInDef);
+ }
+ insertMissingArguments(argsInDef);
+}
+
+
// FIXME: factorize those functions here with a functional style, maybe using Boost's function
// objects?
// in front of macro instance?
Inset * inset = dit.nextInset();
- if (inset) {
- InsetMath * insetMath = inset->asInsetMath();
- if (insetMath) {
- MathMacro * macro = insetMath->asMacro();
- if (macro && macro->name() == name && macro->folded()) {
- // found macro instance
- if (insert)
- macro->insertArgument(n);
- else
- macro->removeArgument(n);
- }
- }
+ if (!inset)
+ continue;
+ InsetMath * insetMath = inset->asInsetMath();
+ if (!insetMath)
+ continue;
+
+ MathMacro * macro = insetMath->asMacro();
+ if (macro && macro->name() == name && macro->folded()) {
+ // found macro instance
+ if (insert)
+ macro->insertArgument(n);
+ else
+ macro->removeArgument(n);
}
}
}
// in front of macro instance?
Inset * inset = dit.nextInset();
- if (inset) {
- InsetMath * insetMath = inset->asInsetMath();
- if (insetMath) {
- MathMacro * macro = insetMath->asMacro();
- if (macro && macro->name() == name && macro->folded()) {
- // found macro instance
- macro->setOptionals(optionals);
- }
- }
+ if (!inset)
+ continue;
+ InsetMath * insetMath = inset->asInsetMath();
+ if (!insetMath)
+ continue;
+ MathMacro * macro = insetMath->asMacro();
+ if (macro && macro->name() == name && macro->folded()) {
+ // found macro instance
+ macro->setOptionals(optionals);
}
}
}
template<class F>
-void fixMacroInstancesFunctional(Cursor const & from,
+void fixMacroInstancesFunctional(Cursor const & from,
docstring const & name, F & fix) {
Cursor dit = from;
// in front of macro instance?
Inset * inset = dit.nextInset();
- if (inset) {
- InsetMath * insetMath = inset->asInsetMath();
- if (insetMath) {
- MathMacro * macro = insetMath->asMacro();
- if (macro && macro->name() == name && macro->folded())
- F(macro);
- }
- }
+ if (!inset)
+ continue;
+ InsetMath * insetMath = inset->asInsetMath();
+ if (!insetMath)
+ continue;
+ MathMacro * macro = insetMath->asMacro();
+ if (macro && macro->name() == name && macro->folded())
+ F(macro);
}
}
-void MathMacroTemplate::insertParameter(Cursor & cur, int pos, bool greedy)
+void MathMacroTemplate::insertParameter(Cursor & cur, int pos, bool greedy, bool addarg)
{
if (pos <= numargs_ && pos >= optionals_ && numargs_ < 9) {
++numargs_;
- shiftArguments(pos, 1);
-
+
// append example #n
- cell(defIdx()).push_back(MathAtom(new MathMacroArgument(pos + 1)));
- if (!cell(displayIdx()).empty())
- cell(displayIdx()).push_back(MathAtom(new MathMacroArgument(pos + 1)));
+ if (addarg) {
+ shiftArguments(pos, 1);
+
+ cell(defIdx()).push_back(MathAtom(new MathMacroArgument(pos + 1)));
+ if (!cell(displayIdx()).empty())
+ cell(displayIdx()).push_back(MathAtom(new MathMacroArgument(pos + 1)));
+ }
if (!greedy) {
Cursor dit = cur;
dit.leaveInset(*this);
// TODO: this was dit.forwardPosNoDescend before. Check that this is the same
dit.top().forwardPos();
-
+
// fix macro instances
fixMacroInstancesAddRemove(dit, name(), pos, true);
}
void MathMacroTemplate::makeNonOptional(Cursor & cur) {
if (numargs_ > 0 && optionals_ > 0) {
--optionals_;
-
- // store default value for later if the use changes his mind
+
+ // store default value for later if the user changes his mind
optionalValues_[optionals_] = cell(optIdx(optionals_));
cells_.erase(cells_.begin() + optIdx(optionals_));
string const arg = to_utf8(cmd.argument());
switch (cmd.action) {
- case LFUN_MATH_MACRO_ADD_PARAM:
+ case LFUN_MATH_MACRO_ADD_PARAM:
if (numargs_ < 9) {
+ commitEditChanges(cur);
cur.recordUndoFullDocument();
size_t pos = numargs_;
if (arg.size() != 0)
break;
- case LFUN_MATH_MACRO_REMOVE_PARAM:
+ case LFUN_MATH_MACRO_REMOVE_PARAM:
if (numargs_ > 0) {
+ commitEditChanges(cur);
cur.recordUndoFullDocument();
size_t pos = numargs_ - 1;
if (arg.size() != 0)
case LFUN_MATH_MACRO_APPEND_GREEDY_PARAM:
if (numargs_ < 9) {
+ commitEditChanges(cur);
cur.recordUndoFullDocument();
insertParameter(cur, numargs_, true);
}
case LFUN_MATH_MACRO_REMOVE_GREEDY_PARAM:
if (numargs_ > 0) {
+ commitEditChanges(cur);
cur.recordUndoFullDocument();
removeParameter(cur, numargs_ - 1, true);
}
break;
case LFUN_MATH_MACRO_MAKE_OPTIONAL:
+ commitEditChanges(cur);
cur.recordUndoFullDocument();
makeOptional(cur);
break;
case LFUN_MATH_MACRO_MAKE_NONOPTIONAL:
+ commitEditChanges(cur);
cur.recordUndoFullDocument();
makeNonOptional(cur);
break;
case LFUN_MATH_MACRO_ADD_OPTIONAL_PARAM:
if (numargs_ < 9) {
+ commitEditChanges(cur);
cur.recordUndoFullDocument();
insertParameter(cur, optionals_);
makeOptional(cur);
case LFUN_MATH_MACRO_REMOVE_OPTIONAL_PARAM:
if (optionals_ > 0) {
+ commitEditChanges(cur);
cur.recordUndoFullDocument();
removeParameter(cur, optionals_ - 1);
} break;
case LFUN_MATH_MACRO_ADD_GREEDY_OPTIONAL_PARAM:
if (numargs_ == optionals_) {
+ commitEditChanges(cur);
cur.recordUndoFullDocument();
insertParameter(cur, 0, true);
makeOptional(cur);
int num = numargs_ + 1;
if (arg.size() != 0)
num = convert<int>(arg);
- bool on = (num >= optionals_
+ bool on = (num >= optionals_
&& numargs_ < 9 && num <= numargs_ + 1);
flag.enabled(on);
break;
}
case LFUN_MATH_MACRO_MAKE_OPTIONAL:
- flag.enabled(numargs_ > 0
- && optionals_ < numargs_
+ flag.enabled(numargs_ > 0
+ && optionals_ < numargs_
&& type_ != MacroTypeDef);
break;
case LFUN_MATH_MACRO_MAKE_NONOPTIONAL:
- flag.enabled(optionals_ > 0
+ flag.enabled(optionals_ > 0
&& type_ != MacroTypeDef);
break;
break;
case LFUN_MATH_MACRO_ADD_GREEDY_OPTIONAL_PARAM:
- flag.enabled(numargs_ == 0
+ flag.enabled(numargs_ == 0
&& type_ != MacroTypeDef);
break;
}
-void MathMacroTemplate::read(Buffer const &, Lexer & lex)
+void MathMacroTemplate::read(Lexer & lex)
{
MathData ar;
mathed_parse_cell(ar, lex.getStream());
return;
}
operator=( *(ar[0]->asMacroTemplate()) );
-
+
updateLook();
}
-void MathMacroTemplate::write(Buffer const &, ostream & os) const
+void MathMacroTemplate::write(ostream & os) const
{
odocstringstream oss;
WriteStream wi(oss, false, false);
void MathMacroTemplate::write(WriteStream & os, bool overwriteRedefinition) const
{
- if (type_ == MacroTypeDef) {
- os << "\\def\\" << name().c_str();
- for (int i = 1; i <= numargs_; ++i)
- os << '#' << i;
+ if (os.latex()) {
+ if (optionals_ > 0) {
+ // macros with optionals use the xargs package, e.g.:
+ // \newcommandx{\foo}[2][usedefault, addprefix=\global,1=default]{#1,#2}
+ if (redefinition_ && !overwriteRedefinition)
+ os << "\\renewcommandx";
+ else
+ os << "\\newcommandx";
+
+ os << "\\" << name().c_str()
+ << "[" << numargs_ << "]"
+ << "[usedefault, addprefix=\\global";
+ for (int i = 0; i < optionals_; ++i) {
+ docstring optValue = asString(cell(optIdx(i)));
+ if (optValue.find(']') != docstring::npos
+ || optValue.find(',') != docstring::npos)
+ os << ", " << i + 1 << "="
+ << "{" << cell(optIdx(i)) << "}";
+ else
+ os << ", " << i + 1 << "="
+ << cell(optIdx(i));
+ }
+ os << "]";
+ } else {
+ // macros without optionals use standard _global_ \def macros:
+ // \global\def\foo#1#2{#1,#2}
+ os << "\\global\\def\\" << name().c_str();
+ docstring param = from_ascii("#0");
+ for (int i = 1; i <= numargs_; ++i) {
+ param[1] = '0' + i;
+ os << param;
+ }
+ }
} else {
- // newcommand or renewcommand
+ // in LyX output we use some pseudo syntax which is implementation
+ // independent, e.g.
+ // \newcommand{\foo}[2][default}{#1,#2}
if (redefinition_ && !overwriteRedefinition)
os << "\\renewcommand";
else
os << "{\\" << name().c_str() << '}';
if (numargs_ > 0)
os << '[' << numargs_ << ']';
-
- // optional values
- if (os.latex()) {
- // in latex only one optional possible, simulate the others
- if (optionals_ >= 1) {
- docstring optValue = asString(cell(optIdx(0)));
- if (optValue.find(']') != docstring::npos)
- os << "[{" << cell(optIdx(0)) << "}]";
- else
- os << "[" << cell(optIdx(0)) << "]";
- }
- } else {
- // in lyx we handle all optionals as real optionals
- for (int i = 0; i < optionals_; ++i) {
- docstring optValue = asString(cell(optIdx(i)));
- if (optValue.find(']') != docstring::npos)
- os << "[{" << cell(optIdx(i)) << "}]";
- else
- os << "[" << cell(optIdx(i)) << "]";
- }
+
+ for (int i = 0; i < optionals_; ++i) {
+ docstring optValue = asString(cell(optIdx(i)));
+ if (optValue.find(']') != docstring::npos)
+ os << "[{" << cell(optIdx(i)) << "}]";
+ else
+ os << "[" << cell(optIdx(i)) << "]";
}
}
}
-int MathMacroTemplate::plaintext(Buffer const & buf, odocstream & os,
+int MathMacroTemplate::plaintext(odocstream & os,
OutputParams const &) const
{
- static docstring const str = '[' + buf.B_("math macro") + ']';
+ static docstring const str = '[' + buffer().B_("math macro") + ']';
os << str;
return str.size();
// valid characters?
for (size_t i = 0; i < n.size(); ++i) {
- if (!(n[i] >= 'a' && n[i] <= 'z') &&
- !(n[i] >= 'A' && n[i] <= 'Z'))
+ if (!(n[i] >= 'a' && n[i] <= 'z')
+ && !(n[i] >= 'A' && n[i] <= 'Z')
+ && n[i] != '*')
return false;
}
continue;
}
}
-
+
// throw cell away
data.erase(i);
}
return data.size() > 0;
}
+
+void MathMacroTemplate::validate(LaTeXFeatures & features) const
+{
+ // we need global optional macro arguments. They are not available
+ // with \def, and \newcommand does not support global macros. So we
+ // are bound to xargs also for the single-optional-parameter case.
+ if (optionals_ > 0)
+ features.require("xargs");
+}
void MathMacroTemplate::getDefaults(vector<docstring> & defaults) const
{
defaults.resize(numargs_);
for (int i = 0; i < optionals_; ++i)
- defaults[i] = asString(cell(optIdx(i)));
+ defaults[i] = asString(cell(optIdx(i)));
}
return optionals_;
}
-
+
void MathMacroTemplate::infoize(odocstream & os) const
{
os << "Math Macro: \\" << name();
}
+
+docstring MathMacroTemplate::contextMenu(BufferView const &, int, int) const
+{
+ return from_ascii("context-math-macro-definition");
+}
+
} // namespace lyx