]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/MathMacroTemplate.cpp
* src/frontends/GuiDocument.{cpp,h}:
[lyx.git] / src / mathed / MathMacroTemplate.cpp
index 93ad7e328905a5909b5a6a55c141de23f90c655c..b7ecb9bbc535511fec76a8662dddf88af316d60b 100644 (file)
@@ -13,6 +13,7 @@
 #include "MathMacroTemplate.h"
 
 #include "DocIterator.h"
+#include "LaTeXFeatures.h"
 #include "InsetMathBrace.h"
 #include "InsetMathChar.h"
 #include "InsetMathSqrt.h"
@@ -24,6 +25,7 @@
 #include "MathMacroArgument.h"
 
 #include "Buffer.h"
+#include "BufferView.h"
 #include "Color.h"
 #include "Cursor.h"
 #include "support/debug.h"
@@ -51,6 +53,191 @@ namespace lyx {
 
 using support::bformat;
 
+//////////////////////////////////////////////////////////////////////
+
+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);
+       ///
+       void metrics(MetricsInfo & mi, Dimension & dim) const;
+       ///
+       void draw(PainterInfo &, int x, int y) const;
+
+protected:
+       ///
+       MathMacroTemplate const & parent_;
+       ///
+       Inset * clone() const;
+       ///
+       docstring const label_;
+       ///
+       bool 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)
+{
+}
+
+
+Inset * InsetLabelBox::clone() const
+{
+       return new InsetLabelBox(*this);
+}
+
+
+void InsetLabelBox::metrics(MetricsInfo & mi, Dimension & dim) const
+{
+       // kernel
+       cell(0).metrics(mi, dim);
+
+       // frame
+       if (frame_) {
+               dim.wid += 6;
+               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);
+
+               dim.wid = max(dim.wid, lwid + 2);
+
+               // space for the label
+               if (!parent_.premetrics())
+                       dim.des += maxasc + maxdes + 1;
+       }
+}
+
+
+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);
+       }
+}
+
+
+//////////////////////////////////////////////////////////////////////
+
+class DisplayLabelBox : public InsetLabelBox {
+public:
+       ///
+       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)
+       : InsetLabelBox(atom, label, parent, true)
+{
+}
+
+
+
+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()) {
+               dim.wid = 0;
+               dim.asc = 0;
+               dim.des = 0;
+       }
+}
+
+
+void DisplayLabelBox::draw(PainterInfo & pi, int x, int y) const
+{
+       if (parent_.editing(pi.base.bv)
+           || !parent_.cell(parent_.displayIdx()).empty()) {
+               InsetLabelBox::draw(pi, x, y);
+       } else {
+               bool enabled = pi.pain.isDrawingEnabled();
+               pi.pain.setDrawingEnabled(false);
+               InsetLabelBox::draw(pi, x, y);
+               pi.pain.setDrawingEnabled(enabled);
+       }
+}
+
+
+//////////////////////////////////////////////////////////////////////
 
 class InsetMathWrapper : public InsetMath {
 public:
@@ -60,7 +247,7 @@ public:
        void metrics(MetricsInfo & mi, Dimension & dim) const;
        ///
        void draw(PainterInfo &, int x, int y) const;
-       
+
 private:
        ///
        Inset * clone() const;
@@ -69,60 +256,122 @@ private:
 };
 
 
-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 InsetNameWrapper : public InsetMathWrapper {
+public:
+       ///
+       InsetNameWrapper(MathData const * value, MathMacroTemplate const & parent);
+       ///
+       void metrics(MetricsInfo & mi, Dimension & dim) const;
+       ///
+       void draw(PainterInfo &, int x, int y) const;
+
+private:
+       ///
+       MathMacroTemplate const & parent_;
+       ///
+       Inset * clone() const;
+};
+
+
+InsetNameWrapper::InsetNameWrapper(MathData const * value,
+                                  MathMacroTemplate const & parent)
+       : InsetMathWrapper(value), parent_(parent)
+{
+}
+
+
+Inset * InsetNameWrapper::clone() const
+{
+       return new InsetNameWrapper(*this);
+}
+
+
+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
+{
+       // create fonts
+       PainterInfo namepi = pi;
+       if (parent_.validMacro())
+               namepi.base.font.setColor(Color_latex);
+       else
+               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), 
-         type_(MacroTypeNewcommand)
+       : InsetMathNest(3), numargs_(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),
          optionals_(optionals), optionalValues_(optionalValues),
-         type_(type)
+         type_(type), lookOutdated_(true)
 {
        initMath();
 
        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;
+
+       updateLook();
 }
 
 
 MathMacroTemplate::MathMacroTemplate(docstring const & str)
        : InsetMathNest(3), numargs_(0), optionals_(0),
-       type_(MacroTypeNewcommand)
+       type_(MacroTypeNewcommand), lookOutdated_(true)
 {
        initMath();
 
@@ -137,12 +386,18 @@ MathMacroTemplate::MathMacroTemplate(docstring const & str)
                return;
        }
        operator=( *(ar[0]->asMacroTemplate()) );
+
+       updateLook();
 }
 
 
 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;
 }
 
 
@@ -158,6 +413,57 @@ void MathMacroTemplate::updateToContext(MacroContext const & mc) const
 }
 
 
+void MathMacroTemplate::updateLook() const
+{
+       lookOutdated_ = true;
+}
+
+
+void MathMacroTemplate::createLook() const
+{
+       look_.clear();
+
+       // \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);
+
+               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(']')));
+               }
+       }
+
+       // {#3}{#4}
+       for (; i < numargs_; ++i) {
+               MathData arg;
+               arg.push_back(MathAtom(new MathMacroArgument(i + 1)));
+               look_.push_back(MathAtom(new InsetMathBrace(arg)));
+       }
+
+       // :=
+       look_.push_back(MathAtom(new InsetMathChar(':')));
+       look_.push_back(MathAtom(new InsetMathChar('=')));
+
+       // definition
+       look_.push_back(MathAtom(
+               new InsetLabelBox(MathAtom(
+                       new InsetMathWrapper(&cell(defIdx()))), _("TeX"), *this,        true)));
+
+       // display
+       look_.push_back(MathAtom(
+               new DisplayLabelBox(MathAtom(
+                       new InsetMathWrapper(&cell(displayIdx()))), _("LyX"), *this)));
+}
+
+
 void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
 {
        FontSetChanger dummy1(mi.base, from_ascii("mathnormal"));
@@ -172,60 +478,32 @@ void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
                redefinition_ = macro != 0;
        }
 
-       // create label "{#1}{#2}:="
-       label_.clear();
-       int i = 0;
-       for (; i < optionals_; ++i) {
-               label_.push_back(MathAtom(new InsetMathChar('[')));
-               label_.push_back(MathAtom(new InsetMathWrapper(&cell(1 + i))));
-               label_.push_back(MathAtom(new InsetMathChar(']')));
+       // update look?
+       if (lookOutdated_) {
+               lookOutdated_ = false;
+               createLook();
        }
-       for (; i < numargs_; ++i) {
-               MathData arg;
-               arg.push_back(MathAtom(new MathMacroArgument(i + 1)));
-               label_.push_back(MathAtom(new InsetMathBrace(arg)));
-       }
-       label_.push_back(MathAtom(new InsetMathChar(':')));
-       label_.push_back(MathAtom(new InsetMathChar('=')));
 
-       // do metrics
+       /// metrics for inset contents
        if (macro)
                macro->lock();
 
-       Dimension dim0;
-       Dimension labeldim;
-       Dimension defdim;
-       Dimension dspdim;
-       
-       cell(0).metrics(mi, dim0);
-       label_.metrics(mi, labeldim);
-       cell(defIdx()).metrics(mi, defdim);
-       cell(displayIdx()).metrics(mi, dspdim);
+       // 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();
 
-       // calculate metrics taking all cells and labels into account
-       dim.wid = 2 + mathed_string_width(mi.base.font, from_ascii("\\")) +
-               dim0.width() + 
-               labeldim.width() +
-               defdim.width() + 16 + dspdim.width() + 2;       
-
-       dim.asc = dim0.ascent();
-       dim.asc = max(dim.asc, labeldim.ascent());
-       dim.asc = max(dim.asc, defdim.ascent());
-       dim.asc = max(dim.asc, dspdim.ascent());
-
-       dim.des = dim0.descent();
-       dim.des = max(dim.des, labeldim.descent());
-       dim.des = max(dim.des, defdim.descent());
-       dim.des = max(dim.des, dspdim.descent());
-
-       // make the name cell vertically centered, and 5 pixel lines margin
-       int real_asc = dim.asc - dim0.ascent() / 2;
-       int real_des = dim.des + dim0.ascent() / 2;
-       dim.asc = max(real_asc, real_des) + dim0.ascent() / 2 + 5;
-       dim.des = max(real_asc, real_des) - dim0.ascent() / 2 + 5;
+       dim.wid += 6;
+       dim.des += 2;
+       dim.asc += 2;
 
        setDimCache(mi, dim);
 }
@@ -239,77 +517,71 @@ void MathMacroTemplate::draw(PainterInfo & pi, int x, int y) const
        setPosCache(pi, x, y);
        Dimension const dim = dimension(*pi.base.bv);
 
-       // create fonts
-       bool valid = validMacro();
-       FontInfo font = pi.base.font;
-       if (valid)
-               font.setColor(Color_latex);
-       else
-               font.setColor(Color_error);             
-
        // draw outer frame
        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); 
-       x += 4;
+       pi.pain.rectangle(x, a, w, h, Color_mathframe);
 
-       // draw backslash
-       pi.pain.text(x, y, from_ascii("\\"), font);
-       x += mathed_string_width(font, from_ascii("\\"));
+       // just to be sure: set some dummy values for coord cache
+       for (idx_type i = 0; i < nargs(); ++i) {
+               cell(i).setXY(*pi.base.bv, x, y);
+       }
 
-       // draw name
-       PainterInfo namepi = pi;
-       namepi.base.font  = font;       
-       cell(0).draw(namepi, x, y);
-       x += cell(0).dimension(*pi.base.bv).width();
+       // draw contents
+       look_.draw(pi, x + 3, y);
+}
 
-       // draw label
-       label_.draw(pi, x, y);
-       x += label_.dimension(*pi.base.bv).width();
-       // draw definition
-       cell(defIdx()).draw(pi, x + 2, y);
-       int const w1 = cell(defIdx()).dimension(*pi.base.bv).width();
-       pi.pain.rectangle(x, y - dim.ascent() + 3, w1 + 4, dim.height() - 6, Color_mathline);
-       x += w1 + 8;
 
-       // draw display
-       cell(displayIdx()).draw(pi, x + 2, y);
-       int const w2 = cell(displayIdx()).dimension(*pi.base.bv).width();
-       pi.pain.rectangle(x, y - dim.ascent() + 3, w2 + 4, dim.height() - 6, Color_mathline);
+void MathMacroTemplate::edit(Cursor & cur, bool left)
+{
+       updateLook();
+       cur.updateFlags(Update::Force);
+       InsetMathNest::edit(cur, left);
+}
+
+
+bool MathMacroTemplate::notifyCursorLeaves(Cursor & cur)
+{
+       updateLook();
+       cur.updateFlags(Update::Force);
+       return InsetMathNest::notifyCursorLeaves(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)
                        arg->setNumber(arg->number() + by);
        }
+
+       updateLook();
 }
 
 
@@ -330,18 +602,19 @@ void fixMacroInstancesAddRemove(Cursor const & from, docstring const & name, int
 
                // 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);
                }
        }
 }
@@ -361,22 +634,22 @@ void fixMacroInstancesOptional(Cursor const & from, docstring const & name, int
 
                // 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;
 
@@ -391,19 +664,19 @@ void fixMacroInstancesFunctional(Cursor const & 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)
 {
        if (pos <= numargs_ && pos >= optionals_ && numargs_ < 9) {
                ++numargs_;
@@ -419,11 +692,13 @@ void MathMacroTemplate::insertParameter(Cursor & cur, int pos, bool greedy)
                        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);
                }
        }
+
+       updateLook();
 }
 
 
@@ -463,6 +738,8 @@ void MathMacroTemplate::removeParameter(Cursor & cur, int pos, bool greedy)
                        fixMacroInstancesAddRemove(dit, name(), pos, false);
                }
        }
+
+       updateLook();
 }
 
 
@@ -482,13 +759,15 @@ void MathMacroTemplate::makeOptional(Cursor & cur) {
                dit.top().forwardPos();
                fixMacroInstancesOptional(dit, name(), optionals_);
        }
+
+       updateLook();
 }
 
 
 void MathMacroTemplate::makeNonOptional(Cursor & cur) {
        if (numargs_ > 0 && optionals_ > 0) {
                --optionals_;
-               
+
                // store default value for later if the use changes his mind
                optionalValues_[optionals_] = cell(optIdx(optionals_));
                cells_.erase(cells_.begin() + optIdx(optionals_));
@@ -512,6 +791,8 @@ void MathMacroTemplate::makeNonOptional(Cursor & cur) {
                dit.top().forwardPos();
                fixMacroInstancesOptional(dit, name(), optionals_);
        }
+
+       updateLook();
 }
 
 
@@ -520,7 +801,7 @@ void MathMacroTemplate::doDispatch(Cursor & cur, FuncRequest & cmd)
        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) {
                        cur.recordUndoFullDocument();
                        size_t pos = numargs_;
@@ -531,7 +812,7 @@ void MathMacroTemplate::doDispatch(Cursor & cur, FuncRequest & cmd)
                break;
 
 
-       case LFUN_MATH_MACRO_REMOVE_PARAM: 
+       case LFUN_MATH_MACRO_REMOVE_PARAM:
                if (numargs_ > 0) {
                        cur.recordUndoFullDocument();
                        size_t pos = numargs_ - 1;
@@ -604,7 +885,7 @@ bool MathMacroTemplate::getStatus(Cursor & /*cur*/, FuncRequest const & cmd,
                        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;
@@ -623,13 +904,13 @@ bool MathMacroTemplate::getStatus(Cursor & /*cur*/, FuncRequest const & cmd,
                }
 
                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;
 
@@ -642,10 +923,10 @@ bool MathMacroTemplate::getStatus(Cursor & /*cur*/, FuncRequest const & cmd,
                        break;
 
                case LFUN_MATH_MACRO_ADD_GREEDY_OPTIONAL_PARAM:
-                       flag.enabled(numargs_ == 0 
+                       flag.enabled(numargs_ == 0
                                     && type_ != MacroTypeDef);
                        break;
-                       
+
                case LFUN_IN_MATHMACROTEMPLATE:
                        flag.enabled();
                        break;
@@ -668,6 +949,8 @@ void MathMacroTemplate::read(Buffer const &, Lexer & lex)
                return;
        }
        operator=( *(ar[0]->asMacroTemplate()) );
+
+       updateLook();
 }
 
 
@@ -689,40 +972,26 @@ void MathMacroTemplate::write(WriteStream & os) const
 
 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;
-       } else {
-               // newcommand or renewcommand
+       // newcommand or renewcommand
+       if (os.latex() && optionals_ > 1)
+               os << "\\newlyxcommand";
+       else {
                if (redefinition_ && !overwriteRedefinition)
                        os << "\\renewcommand";
                else
                        os << "\\newcommand";
-               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)) << "]";
-                       }
-               }
+       }
+       os << "{\\" << name().c_str() << '}';
+       if (numargs_ > 0)
+               os << '[' << numargs_ << ']';
+
+       // optional values
+       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)) << "]";
        }
 
        os << "{" << cell(defIdx()) << "}";
@@ -765,7 +1034,7 @@ bool MathMacroTemplate::validName() const
        // valid characters?
        for (size_t i = 0; i < n.size(); ++i) {
                if (!(n[i] >= 'a' && n[i] <= 'z') &&
-                               !(n[i] >= 'A' && n[i] <= 'Z')) 
+                               !(n[i] >= 'A' && n[i] <= 'Z'))
                        return false;
        }
 
@@ -795,7 +1064,7 @@ bool MathMacroTemplate::fixNameAndCheckIfValid()
                                continue;
                        }
                }
-               
+
                // throw cell away
                data.erase(i);
        }
@@ -804,12 +1073,19 @@ bool MathMacroTemplate::fixNameAndCheckIfValid()
        return data.size() > 0;
 }
 
+       
+void MathMacroTemplate::validate(LaTeXFeatures & features) const
+{
+       if (optionals_ > 1) {
+               features.require("newlyxcommand");
+       }
+}
 
 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)));
 }
 
 
@@ -836,4 +1112,10 @@ size_t MathMacroTemplate::numOptionals() const
        return optionals_;
 }
 
+
+void MathMacroTemplate::infoize(odocstream & os) const
+{
+       os << "Math Macro: \\" << name();
+}
+
 } // namespace lyx