+ // add missing parameter
+ for (int i = numargs_; i < newNumArg; ++i)
+ insertParameter(cur, inset_pos, numargs_, false, false);
+}
+
+
+///
+class AddRemoveMacroInstanceFix
+{
+public:
+ ///
+ AddRemoveMacroInstanceFix(int n, bool insert) : n_(n), insert_(insert) {}
+ ///
+ void operator()(MathMacro * macro) {
+ if (macro->folded()) {
+ if (insert_)
+ macro->insertArgument(n_);
+ else
+ macro->removeArgument(n_);
+ }
+ }
+
+private:
+ ///
+ int n_;
+ ///
+ bool insert_;
+};
+
+
+///
+class OptionalsMacroInstanceFix
+{
+public:
+ ///
+ OptionalsMacroInstanceFix(int optionals) : optionals_(optionals) {}
+ ///
+ void operator()(MathMacro * macro) {
+ macro->setOptionals(optionals_);
+ }
+
+private:
+ ///
+ int optionals_;
+};
+
+
+///
+class NullMacroInstanceFix
+{
+public:
+ ///
+ void operator()(MathMacro * ) {}
+};
+
+
+template<class F>
+void fixMacroInstances(Cursor & cur, DocIterator const & inset_pos,
+ docstring const & name, F & fix)
+{
+ // goto position behind macro template
+ DocIterator dit = inset_pos;
+ dit.pop_back();
+ dit.top().forwardPos();
+
+ // remember hull to trigger preview reload
+ DocIterator hull(dit.buffer());
+ bool preview_reload_needed = false;
+
+ // iterate over all positions until macro is redefined
+ for (; dit; dit.forwardPos()) {
+ // left the outer hull?
+ if (!hull.empty() && dit.depth() == hull.depth()) {
+ // reload the preview if necessary
+ if (preview_reload_needed) {
+ InsetMathHull * inset_hull =
+ hull.nextInset()->asInsetMath()->asHullInset();
+ LASSERT(inset_hull, /**/);
+ inset_hull->reloadPreview(hull);
+ cur.screenUpdateFlags(Update::Force);
+ preview_reload_needed = false;
+ }
+ hull.clear();
+ }
+
+ // only until a macro is redefined
+ if (dit.inset().lyxCode() == MATHMACRO_CODE) {
+ MathMacroTemplate const & macroTemplate
+ = static_cast<MathMacroTemplate const &>(dit.inset());
+ if (macroTemplate.name() == name)
+ break;
+ }
+
+ // in front of macro instance?
+ Inset * inset = dit.nextInset();
+ if (!inset)
+ continue;
+ InsetMath * insetMath = inset->asInsetMath();
+ if (!insetMath)
+ continue;
+
+ // in front of outer hull?
+ InsetMathHull * inset_hull = insetMath->asHullInset();
+ if (inset_hull && hull.empty()) {
+ // remember this for later preview reload
+ hull = dit;
+ }
+
+ MathMacro * macro = insetMath->asMacro();
+ if (macro && macro->name() == name && macro->folded()) {
+ fix(macro);
+ if (RenderPreview::status() == LyXRC::PREVIEW_ON)
+ preview_reload_needed = true;
+ }
+ }
+}
+
+
+void MathMacroTemplate::commitEditChanges(Cursor & cur,
+ DocIterator const & inset_pos)
+{
+ int args_in_def = maxArgumentInDefinition();
+ if (args_in_def != numargs_) {
+ cur.recordUndoFullDocument();
+ changeArity(cur, inset_pos, args_in_def);
+ }
+ insertMissingArguments(args_in_def);
+
+ // make sure the preview are up to date
+ NullMacroInstanceFix fix;
+ fixMacroInstances(cur, inset_pos, name(), fix);
+}
+
+
+void MathMacroTemplate::insertParameter(Cursor & cur,
+ DocIterator const & inset_pos, int pos, bool greedy, bool addarg)
+{
+ if (pos <= numargs_ && pos >= optionals_ && numargs_ < 9) {
+ ++numargs_;
+
+ // append example #n
+ 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) {
+ // fix macro instances
+ AddRemoveMacroInstanceFix fix(pos, true);
+ fixMacroInstances(cur, inset_pos, name(), fix);
+ }
+ }
+
+ updateLook();
+}
+
+
+void MathMacroTemplate::removeParameter(Cursor & cur,
+ DocIterator const & inset_pos, int pos, bool greedy)
+{
+ if (pos < numargs_ && pos >= 0) {
+ --numargs_;
+ removeArguments(cur, inset_pos, pos, pos);
+ shiftArguments(pos + 1, -1);
+
+ // removed optional parameter?
+ if (pos < optionals_) {
+ --optionals_;
+ optionalValues_[pos] = cell(optIdx(pos));
+ cells_.erase(cells_.begin() + optIdx(pos));
+
+ // fix cursor
+ int macroSlice = cur.find(this);
+ if (macroSlice != -1) {
+ if (cur[macroSlice].idx() == optIdx(pos)) {
+ cur.cutOff(macroSlice);
+ cur[macroSlice].idx() = 1;
+ cur[macroSlice].pos() = 0;
+ } else if (cur[macroSlice].idx() > optIdx(pos))
+ --cur[macroSlice].idx();
+ }
+ }
+
+ if (!greedy) {
+ // fix macro instances
+ AddRemoveMacroInstanceFix fix(pos, false);
+ fixMacroInstances(cur, inset_pos, name(), fix);
+ }
+ }
+
+ updateLook();
+}
+
+
+void MathMacroTemplate::makeOptional(Cursor & cur,
+ DocIterator const & inset_pos)
+{
+ if (numargs_ > 0 && optionals_ < numargs_) {
+ ++optionals_;
+ cells_.insert(cells_.begin() + optIdx(optionals_ - 1), optionalValues_[optionals_ - 1]);
+ // fix cursor
+ int macroSlice = cur.find(this);
+ if (macroSlice != -1 && cur[macroSlice].idx() >= optIdx(optionals_ - 1))
+ ++cur[macroSlice].idx();
+
+ // fix macro instances
+ OptionalsMacroInstanceFix fix(optionals_);
+ fixMacroInstances(cur, inset_pos, name(), fix);
+ }
+
+ updateLook();
+}
+
+
+void MathMacroTemplate::makeNonOptional(Cursor & cur,
+ DocIterator const & inset_pos)
+{
+ if (numargs_ > 0 && optionals_ > 0) {
+ --optionals_;
+
+ // store default value for later if the user changes his mind
+ optionalValues_[optionals_] = cell(optIdx(optionals_));
+ cells_.erase(cells_.begin() + optIdx(optionals_));
+
+ // fix cursor
+ int macroSlice = cur.find(this);
+ if (macroSlice != -1) {
+ if (cur[macroSlice].idx() > optIdx(optionals_))
+ --cur[macroSlice].idx();
+ else if (cur[macroSlice].idx() == optIdx(optionals_)) {
+ cur.cutOff(macroSlice);
+ cur[macroSlice].idx() = optIdx(optionals_);
+ cur[macroSlice].pos() = 0;
+ }
+ }
+
+ // fix macro instances
+ OptionalsMacroInstanceFix fix(optionals_);
+ fixMacroInstances(cur, inset_pos, name(), fix);
+ }
+
+ updateLook();
+}
+
+
+void MathMacroTemplate::doDispatch(Cursor & cur, FuncRequest & cmd)
+{
+ string const arg = to_utf8(cmd.argument());
+ switch (cmd.action()) {
+
+ case LFUN_MATH_MACRO_ADD_PARAM:
+ if (numargs_ < 9) {
+ commitEditChanges(cur, cur);
+ cur.recordUndoFullDocument();
+ size_t pos = numargs_;
+ if (arg.size() != 0)
+ pos = (size_t)convert<int>(arg) - 1; // it is checked for >=0 in getStatus
+ insertParameter(cur, cur, pos);
+ }
+ break;
+
+
+ case LFUN_MATH_MACRO_REMOVE_PARAM:
+ if (numargs_ > 0) {
+ commitEditChanges(cur, cur);
+ cur.recordUndoFullDocument();
+ size_t pos = numargs_ - 1;
+ if (arg.size() != 0)
+ pos = (size_t)convert<int>(arg) - 1; // it is checked for >=0 in getStatus
+ removeParameter(cur, cur, pos);
+ }
+ break;
+
+ case LFUN_MATH_MACRO_APPEND_GREEDY_PARAM:
+ if (numargs_ < 9) {
+ commitEditChanges(cur, cur);
+ cur.recordUndoFullDocument();
+ insertParameter(cur, cur, numargs_, true);
+ }
+ break;
+
+ case LFUN_MATH_MACRO_REMOVE_GREEDY_PARAM:
+ if (numargs_ > 0) {
+ commitEditChanges(cur, cur);
+ cur.recordUndoFullDocument();
+ removeParameter(cur, cur, numargs_ - 1, true);
+ }
+ break;
+
+ case LFUN_MATH_MACRO_MAKE_OPTIONAL:
+ commitEditChanges(cur, cur);
+ cur.recordUndoFullDocument();
+ makeOptional(cur, cur);
+ break;
+
+ case LFUN_MATH_MACRO_MAKE_NONOPTIONAL:
+ commitEditChanges(cur, cur);
+ cur.recordUndoFullDocument();
+ makeNonOptional(cur, cur);
+ break;
+
+ case LFUN_MATH_MACRO_ADD_OPTIONAL_PARAM:
+ if (numargs_ < 9) {
+ commitEditChanges(cur, cur);
+ cur.recordUndoFullDocument();
+ insertParameter(cur, cur, optionals_);
+ makeOptional(cur, cur);
+ }
+ break;
+
+ case LFUN_MATH_MACRO_REMOVE_OPTIONAL_PARAM:
+ if (optionals_ > 0) {
+ commitEditChanges(cur, cur);
+ cur.recordUndoFullDocument();
+ removeParameter(cur, cur, optionals_ - 1);
+ } break;
+
+ case LFUN_MATH_MACRO_ADD_GREEDY_OPTIONAL_PARAM:
+ if (numargs_ == optionals_) {
+ commitEditChanges(cur, cur);
+ cur.recordUndoFullDocument();
+ insertParameter(cur, cur, 0, true);
+ makeOptional(cur, cur);
+ }
+ break;
+
+ default:
+ InsetMathNest::doDispatch(cur, cmd);
+ break;
+ }