]> git.lyx.org Git - features.git/blobdiff - src/mathed/math_matrixinset.C
write \mathrm{x}\mathrm{y} as \mathrm{xy} again
[features.git] / src / mathed / math_matrixinset.C
index 21ad67b89cc6103823e3b1334ccaa214ef08583e..4fa1ebd1f10c906d02d9809b933d45848cc59df9 100644 (file)
-#include <config.h>
-
 #ifdef __GNUG__
 #pragma implementation
 #endif
 
+#include <vector>
+
 #include "math_matrixinset.h"
-#include "math_rowst.h"
-#include "math_xiter.h"
+#include "support.h"
+#include "debug.h"
 #include "support/LOstream.h"
+#include "Painter.h"
+#include "LaTeXFeatures.h"
 
-using std::ostream;
 
-extern int number_of_newlines;
+namespace {
 
-MathMatrixInset::MathMatrixInset(int m, int n, short st)
-       : MathParInset(st, "array", LM_OT_MATRIX), nc_(m), nr_(0), ws_(m),
-         v_align_(0), h_align_(nc_, 'c'), row_(0)
-{
-       flag = 15;
-       if (n > 0) {
-               row_ = new MathedRowSt(nc_ + 1);
-               MathedXIter it(this);
-               for (int j = 1; j < n; ++j) it.addRow();
-               nr_ = n;
-               if (nr_ == 1 && nc_ > 1) {
-                       for (int j = 0; j < nc_ - 1; ++j) 
-                               it.insert('T', LM_TC_TAB);
+       int getCols(MathInsetTypes type)
+       {
+               switch (type) {
+                       case LM_OT_EQNARRAY:
+                               return 3;
+                       case LM_OT_ALIGN:
+                       case LM_OT_ALIGNAT:
+                       case LM_OT_XALIGNAT:
+                       case LM_OT_XXALIGNAT:
+                               return 2;
+                       default:;
                }
-       } else if (n < 0) {
-               row_ = new MathedRowSt(nc_ + 1);
-               nr_ = 1;
+               return 1;
+       }
+
+
+       // returns position of first relation operator in the array
+       // used for "intelligent splitting"
+       int firstRelOp(MathArray const & ar)
+       {
+               for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
+                       if ((*it)->isRelOp())
+                               return it - ar.begin();
+               return ar.size();
        }
+
+
+       char const * star(bool numbered)
+       {
+               return numbered ? "" : "*";
+       }
+
+       MathInsetTypes typecode(string const & s)
+       {
+               if (s == "equation")  return LM_OT_EQUATION;
+               if (s == "display")   return LM_OT_EQUATION;
+               if (s == "eqnarray")  return LM_OT_EQNARRAY;
+               if (s == "align")     return LM_OT_ALIGN;
+               if (s == "alignat")   return LM_OT_ALIGNAT;
+               if (s == "xalignat")  return LM_OT_XALIGNAT;
+               if (s == "xxalignat") return LM_OT_XXALIGNAT;
+               if (s == "multline")  return LM_OT_MULTLINE;
+               if (s == "gather")    return LM_OT_GATHER;
+               return LM_OT_SIMPLE;
+       }       
+
+
+       string normalName(MathInsetTypes t)
+       {
+               switch (t) {
+                       case LM_OT_EQUATION:  return "equation";
+                       case LM_OT_EQNARRAY:  return "eqnarray";
+                       case LM_OT_ALIGN:     return "align";
+                       case LM_OT_ALIGNAT:   return "alignat";
+                       case LM_OT_XALIGNAT:  return "xalignat";
+                       case LM_OT_XXALIGNAT: return "xxalignat";
+                       case LM_OT_MULTLINE:  return "multline";
+                       case LM_OT_GATHER:    return "gather";
+                       case LM_OT_SIMPLE:    return "simple";
+                       default: break;
+               }
+               return "unknown";
+       }       
+
+} // end anon namespace
+
+
+MathMatrixInset::MathMatrixInset()
+       : MathGridInset(1, 1), objtype_(LM_OT_SIMPLE), nonum_(1), label_(1)
+{
+       setDefaults();
 }
 
 
-MathMatrixInset::MathMatrixInset(MathMatrixInset const & mt)
-       : MathParInset(mt.GetStyle(), mt.GetName(), mt.GetType()),
-         nc_(mt.nc_), nr_(0), ws_(mt.nc_),
-         v_align_(mt.v_align_), h_align_(mt.h_align_)
+MathMatrixInset::MathMatrixInset(MathInsetTypes t)
+       : MathGridInset(getCols(t), 1), objtype_(t), nonum_(1), label_(1)
 {
-       array = mt.GetData();
-       if (mt.row_.data_ != 0) {
-               MathedRowSt * ro = 0;
-               MathedRowSt * mrow = mt.row_.data_;
+       setDefaults();
+}
 
-               while (mrow) {
-                       MathedRowSt * r = new MathedRowSt(nc_ + 1);
-                       r->setNumbered(mrow->isNumbered());
-                       //if (mrow->label) 
-                       r->setLabel(mrow->getLabel());
-                       if (!ro) 
-                               row_ = r;
-                       else
-                               ro->setNext(r);
-                       mrow = mrow->getNext();
-                       ro = r;
-                       ++nr_;
-               }
-       } else   
-               row_ = 0;
-       flag = mt.flag;
+
+MathMatrixInset::MathMatrixInset(MathInsetTypes t, col_type cols)
+       : MathGridInset(cols, 1), objtype_(t), nonum_(1), label_(1)
+{
+       setDefaults();
 }
 
 
-MathMatrixInset::~MathMatrixInset()
+MathInset * MathMatrixInset::clone() const
 {
-       MathedRowSt * r = row_.data_;
-       while (r) {
-               MathedRowSt * q = r->getNext();
-               delete r;
-               r = q;
+       return new MathMatrixInset(*this);
+}
+
+
+char MathMatrixInset::defaultColAlign(col_type col)
+{
+       switch (getType()) {
+               case LM_OT_ALIGN:
+               case LM_OT_ALIGNAT:
+               case LM_OT_XALIGNAT:
+               case LM_OT_XXALIGNAT:
+                       return "rl"[col & 1];
+               case LM_OT_EQNARRAY:
+                       return "rcl"[col];
+               default:;
        }
+       return 'c';
 }
 
 
-MathedInset * MathMatrixInset::Clone()
+int MathMatrixInset::defaultColSpace(col_type col)
 {
-       return new MathMatrixInset(*this);
+       switch (getType()) {
+               case LM_OT_ALIGN:
+               case LM_OT_ALIGNAT:
+                       return 0;
+               case LM_OT_XALIGNAT:
+                       return (col & 1) ? 20 : 0;
+               case LM_OT_XXALIGNAT:
+                       return (col & 1) ? 40 : 0;
+               default:;
+       }
+       return 10;
 }
 
 
-void MathMatrixInset::SetAlign(char vv, string const & hh)
+void MathMatrixInset::metrics(MathMetricsInfo const & mi) const
 {
-       v_align_ = vv;
-       h_align_ = hh.substr(0, nc_); // usr just h_align = hh; perhaps
+       mi_ = mi;
+       mi_.style = (getType() == LM_OT_SIMPLE) ? LM_ST_TEXT : LM_ST_DISPLAY;
+
+       // let the cells adjust themselves
+       MathGridInset::metrics(mi_);
+
+       if (display()) {
+               ascent_  += 12;
+               descent_ += 12;
+       }       
+
+       if (numberedType()) {
+               int l = 0;
+               for (row_type row = 0; row < nrows(); ++row)
+                       l = std::max(l, mathed_string_width(LM_TC_BF, mi_, nicelabel(row)));
+
+               if (l)
+                       width_ += 30 + l;
+       }
+
+       // make it at least as high as the current font
+       int asc = 0;
+       int des = 0;
+       math_font_max_dim(LM_TC_TEXTRM, mi_, asc, des);
+       ascent_  = std::max(ascent_,  asc);
+       descent_ = std::max(descent_, des);
 }
 
 
-// Check the number of tabs and crs
-void MathMatrixInset::setData(MathedArray const & a)
+void MathMatrixInset::draw(Painter & pain, int x, int y) const
 {
-       array = a;
+       MathGridInset::draw(pain, x, y);
 
-       MathedIter it(&array);
-       int nn = nc_ - 1;
-       nr_ = 1;
-       // count tabs per row
-       while (it.OK()) {
-               if (it.IsTab()) {
-                       if (nn < 0) { 
-                               it.Delete();
-                               continue;
-                       } else {
-                               // it.Next();
-                               --nn;
-                       }
+       if (numberedType()) {
+               int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
+               for (row_type row = 0; row < nrows(); ++row) {
+                       int const yy = y + rowinfo_[row].offset_;
+                       drawStr(pain, LM_TC_BF, mi_, xx, yy, nicelabel(row));
                }
-               if (it.IsCR()) {
-                       while (nn > 0) {
-                               it.insert(' ', LM_TC_TAB);
-                               --nn;
-                       }
-                       nn = nc_ - 1;
-                       ++nr_;
+       }
+}
+
+
+void MathMatrixInset::write(MathWriteInfo & os) const
+{
+  header_write(os.os);
+
+       bool n = numberedType();
+
+       for (row_type row = 0; row < nrows(); ++row) {
+               for (col_type col = 0; col < ncols(); ++col) 
+                       os << cell(index(row, col)) << eocString(col);
+               if (n) {
+                       if (!label_[row].empty())
+                               os << "\\label{" << label_[row] << "}";
+                       if (nonum_[row])
+                               os << "\\nonumber ";
                }
-               it.Next();
+               os << eolString(row);
        }
-       it.Reset();
-       
-       // Automatically inserts tabs around bops
-       // DISABLED because it's very easy to insert tabs 
+
+  footer_write(os.os);
 }
 
 
-void MathMatrixInset::draw(Painter & pain, int x, int baseline)
+void MathMatrixInset::writeNormal(std::ostream & os) const
 {
-       MathParInset::draw(pain, x, baseline);
+       os << "[formula " << normalName(getType()) << " ";
+       MathGridInset::writeNormal(os);
+       os << "] ";
 }
 
 
 
-void MathMatrixInset::Metrics()
+string MathMatrixInset::label(row_type row) const
 {
-       if (!row_.data_) {
-               // lyxerr << " MIDA ";
-               MathedXIter it(this);
-               row_ = it.adjustVerticalSt();
-       } 
-       
-       // Clean the arrays      
-       MathedRowSt * cxrow = row_.data_;
-       while (cxrow) {   
-               for (int i = 0; i <= nc_; ++i)
-                       cxrow->setTab(i, 0);
-               cxrow = cxrow->getNext();
-       }
-       
-       // Basic metrics
-       MathParInset::Metrics();
-       
-       if (nc_ <= 1 && !row_.data_->getNext()) {
-               row_.data_->ascent(ascent);
-               row_.data_->descent(descent);
+       return label_[row];
+}
+
+
+void MathMatrixInset::label(row_type row, string const & label)
+{
+       label_[row] = label; 
+}
+
+
+void MathMatrixInset::numbered(row_type row, bool num)
+{
+       nonum_[row] = !num; 
+}
+
+
+bool MathMatrixInset::numbered(row_type row) const
+{
+       return !nonum_[row];
+}
+
+
+bool MathMatrixInset::ams() const
+{
+       return true;
+
+       return 
+               objtype_ == LM_OT_ALIGN ||
+               objtype_ == LM_OT_MULTLINE ||
+               objtype_ == LM_OT_GATHER ||
+               objtype_ == LM_OT_ALIGNAT ||
+               objtype_ == LM_OT_XALIGNAT ||
+               objtype_ == LM_OT_XXALIGNAT;
+}
+
+
+bool MathMatrixInset::display() const
+{
+       return getType() != LM_OT_SIMPLE;
+}
+
+
+std::vector<string> const MathMatrixInset::getLabelList() const
+{
+       std::vector<string> res;
+       for (row_type row = 0; row < nrows(); ++row)
+               if (!label_[row].empty() && nonum_[row] != 1)
+                       res.push_back(label_[row]);
+       return res;
+}
+
+
+bool MathMatrixInset::numberedType() const
+{
+       if (getType() == LM_OT_SIMPLE || getType() == LM_OT_XXALIGNAT)
+               return false;
+       for (row_type row = 0; row < nrows(); ++row)
+               if (!nonum_[row])
+                       return true;
+       return false;
+}
+
+
+void MathMatrixInset::validate(LaTeXFeatures & features) const
+{
+       features.amsstyle = ams();
+
+       // Validation is necessary only if not using AMS math.
+       // To be safe, we will always run mathedvalidate.
+       //if (features.amsstyle)
+       //  return;
+
+       features.boldsymbol = true;
+       //features.binom      = true;
+
+       MathNestInset::validate(features);
+}
+
+
+void MathMatrixInset::header_write(std::ostream & os) const
+{
+       bool n = numberedType();
+
+       switch (getType()) {
+               case LM_OT_SIMPLE:
+                       os << '$';
+                       if (cell(0).empty())
+                               os << ' ';
+                       break;
+
+               case LM_OT_EQUATION:
+                       if (n)
+                               os << "\\begin{equation" << star(n) << "}\n"; 
+                       else
+                               os << "\\[\n"; 
+                       break;
+
+               case LM_OT_EQNARRAY:
+                       os << "\\begin{eqnarray" << star(n) << "}\n";
+                       break;
+
+               case LM_OT_ALIGN:
+                       os << "\\begin{align" << star(n) << "}\n";
+                       break;
+
+               case LM_OT_ALIGNAT:
+                       os << "\\begin{alignat" << star(n) << "}" << "{" << ncols()/2 << "}\n";
+                       break;
+
+               case LM_OT_XALIGNAT:
+                       os << "\\begin{xalignat" << star(n) << "}" << "{" << ncols()/2 << "}\n";
+                       break;
+
+               case LM_OT_XXALIGNAT:
+                       os << "\\begin{xxalignat}" << "{" << ncols()/2 << "}\n";
+                       break;
+
+               case LM_OT_MULTLINE:
+                       os << "\\begin{multline}\n";
+                       break;
+
+               case LM_OT_GATHER:
+                       os << "\\begin{gather}\n";
+                       break;
+
+               default:
+                       os << "\\begin{unknown" << star(n) << "}";
        }
-       
-       // Vertical positions of each row
-       cxrow = row_.data_;     
-       MathedRowSt * cprow = 0;
-       int h = 0;
-       while (cxrow) {
-               for (int i = 0; i < nc_; ++i) {
-                       if (cxrow == row_.data_ || ws_[i] < cxrow->getTab(i))
-                               ws_[i] = cxrow->getTab(i);
-                       if (cxrow->getNext() == 0 && ws_[i] == 0)
-                               ws_[i] = df_width;
-               }
-               
-               cxrow->setBaseline((cxrow == row_.data_) ?
-                                  cxrow->ascent() :
-                                  cxrow->ascent() + cprow->descent()
-                                  + MATH_ROWSEP + cprow->getBaseline());
-               h += cxrow->ascent() + cxrow->descent() + MATH_ROWSEP;  
-               cprow = cxrow;
-               cxrow = cxrow->getNext();
+}
+
+
+void MathMatrixInset::footer_write(std::ostream & os) const
+{
+       bool n = numberedType();
+
+       switch (getType()) {
+               case LM_OT_SIMPLE:
+                       os << '$';
+                       break;
+
+               case LM_OT_EQUATION:
+                       if (n)
+                               os << "\\end{equation" << star(n) << "}\n"; 
+                       else
+                               os << "\\]\n"; 
+                       break;
+
+               case LM_OT_EQNARRAY:
+                       os << "\n\\end{eqnarray" << star(n) << "}\n";
+                       break;
+
+               case LM_OT_ALIGN:
+                       os << "\n\\end{align" << star(n) << "}\n";
+                       break;
+
+               case LM_OT_ALIGNAT:
+                       os << "\n\\end{alignat" << star(n) << "}\n";
+                       break;
+
+               case LM_OT_XALIGNAT:
+                       os << "\n\\end{xalignat" << star(n) << "}\n";
+                       break;
+
+               case LM_OT_XXALIGNAT:
+                       os << "\n\\end{xxalignat}\n";
+                       break;
+
+               case LM_OT_MULTLINE:
+                       os << "\n\\end{multline}\n";
+                       break;
+
+               case LM_OT_GATHER:
+                       os << "\n\\end{gather}\n";
+                       break;
+
+               default:
+                       os << "\\end{unknown" << star(n) << "}";
        }
-       
-       int const hl = Descent();
-       h -= MATH_ROWSEP;
-       
-       //  Compute vertical align
-       switch (v_align_) {
-       case 't':
-               ascent = row_.data_->getBaseline();
-               break;
-       case 'b':
-               ascent = h - hl;
-               break;
-       default:
-               ascent = (row_.data_->getNext()) ? h / 2 : h - hl;
-               break;
+}
+
+
+void MathMatrixInset::addRow(row_type row) 
+{
+       nonum_.insert(nonum_.begin() + row + 1, !numberedType());
+       label_.insert(label_.begin() + row + 1, string());
+       MathGridInset::addRow(row);
+}
+
+
+void MathMatrixInset::appendRow()
+{
+       nonum_.push_back(!numberedType());
+       label_.push_back(string());
+       MathGridInset::appendRow();
+}
+
+
+void MathMatrixInset::delRow(row_type row) 
+{
+       MathGridInset::delRow(row);
+       nonum_.erase(nonum_.begin() + row);
+       label_.erase(label_.begin() + row);
+}
+
+
+void MathMatrixInset::addCol(col_type col)
+{
+       switch (getType()) {
+               case LM_OT_EQUATION:
+                       mutate(LM_OT_EQNARRAY);
+                       break;
+
+               case LM_OT_EQNARRAY:
+                       mutate(LM_OT_ALIGN);
+                       addCol(col);
+                       break;
+
+               case LM_OT_ALIGN:
+                       mutate(LM_OT_ALIGNAT);
+                       addCol(col);
+                       break;
+
+               case LM_OT_ALIGNAT:
+               case LM_OT_XALIGNAT:
+               case LM_OT_XXALIGNAT:
+                       MathGridInset::addCol(col);
+                       MathGridInset::addCol(col + 1);
+                       break;
+
+               default:
+                       break;
        }
-       descent = h - ascent + 2;
-       
-       // Increase ws_[i] for 'R' columns (except the first one)
-       for (int i = 1; i < nc_; ++i)
-               if (h_align_[i] == 'R')
-                       ws_[i] += 10 * df_width;
-       // Increase ws_[i] for 'C' column
-       if (h_align_[0] == 'C')
-               if (ws_[0] < 7 * workWidth / 8)
-                       ws_[0] = 7 * workWidth / 8;
-       
-       // Adjust local tabs
-       cxrow = row_.data_;
-       width = MATH_COLSEP;
-       while (cxrow) {   
-               int rg = MATH_COLSEP;
-               int lf = 0;
-               for (int i = 0; i < nc_; ++i) {
-                       bool isvoid = false;
-                       if (cxrow->getTab(i) <= 0) {
-                               cxrow->setTab(i, df_width);
-                               isvoid = true;
-                       }
-                       switch (h_align_[i]) {
-                       case 'l':
-                               lf = 0;
-                               break;
-                       case 'c':
-                               lf = (ws_[i] - cxrow->getTab(i))/2; 
-                               break;
-                       case 'r':
-                       case 'R':
-                               lf = ws_[i] - cxrow->getTab(i);
-                               break;
-                       case 'C':
-                               if (cxrow == row_.data_)
-                                       lf = 0;
-                               else if (!cxrow->getNext())
-                                       lf = ws_[i] - cxrow->getTab(i);
-                               else
-                                       lf = (ws_[i] - cxrow->getTab(i))/2; 
-                               break;
-                       }
-                       int const ww = (isvoid) ? lf : lf + cxrow->getTab(i);
-                       cxrow->setTab(i, lf + rg);
-                       rg = ws_[i] - ww + MATH_COLSEP;
-                       if (cxrow == row_.data_)
-                               width += ws_[i] + MATH_COLSEP;
-               }
-               cxrow->setBaseline(cxrow->getBaseline() - ascent);
-               cxrow = cxrow->getNext();
+}
+
+
+void MathMatrixInset::delCol(col_type col)
+{
+       switch (getType()) {
+               case LM_OT_ALIGNAT:
+               case LM_OT_XALIGNAT:
+               case LM_OT_XXALIGNAT:
+                       MathGridInset::delCol(col + 1);
+                       MathGridInset::delCol(col);
+                       break;
+               default:
+                       break;
        }
 }
 
 
-void MathMatrixInset::Write(ostream & os, bool fragile)
+string MathMatrixInset::nicelabel(row_type row) const
 {
-       if (GetType() == LM_OT_MATRIX) {
-               if (fragile)
-                       os << "\\protect";
-               os << "\\begin{"
-                  << name
-                  << '}';
-               if (v_align_ == 't' || v_align_ == 'b') {
-                       os << '['
-                          << char(v_align_)
-                          << ']';
-               }
-               os << '{'
-                  << h_align_
-                  << "}\n";
-               ++number_of_newlines;
+       if (nonum_[row])
+               return string();
+       if (label_[row].empty())
+               return string("(#)");
+       return "(" + label_[row] + ")";
+}
+
+
+void MathMatrixInset::mutate(string const & newtype)
+{
+       if (newtype == "dump") {
+               dump();
+               return;
        }
-       MathParInset::Write(os, fragile);
-       if (GetType() == LM_OT_MATRIX){
-               os << "\n";
-               if (fragile)
-                       os << "\\protect";
-               os << "\\end{"
-                  << name
-                  << '}';
-               ++number_of_newlines;
+       //lyxerr << "mutating from '" << getType() << "' to '" << newtype << "'\n";
+       mutate(typecode(newtype));
+}
+
+
+void MathMatrixInset::glueall()
+{
+       MathArray ar;
+       for (idx_type i = 0; i < nargs(); ++i)
+               ar.push_back(cell(i));
+       *this = MathMatrixInset(LM_OT_SIMPLE);
+       cell(0) = ar;
+}
+
+
+MathInsetTypes MathMatrixInset::getType() const
+{
+       return objtype_;
+}
+
+
+void MathMatrixInset::setType(MathInsetTypes t)
+{
+       objtype_ = t;
+       setDefaults();
+}
+
+
+
+void MathMatrixInset::mutate(MathInsetTypes newtype)
+{
+       //lyxerr << "mutating from '" << getType() << "' to '" << newtype << "'\n";
+
+       if (newtype == getType())
+               return;
+
+       switch (getType()) {
+               case LM_OT_SIMPLE:
+                       setType(LM_OT_EQUATION);
+                       numbered(0, false);
+                       mutate(newtype);
+                       break;
+
+               case LM_OT_EQUATION:
+                       switch (newtype) {
+                               case LM_OT_SIMPLE:
+                                       setType(LM_OT_SIMPLE);
+                                       break;
+
+                               case LM_OT_ALIGN: 
+                               case LM_OT_ALIGNAT:
+                               case LM_OT_XALIGNAT:
+                               case LM_OT_XXALIGNAT: {
+
+                                       MathGridInset::addCol(1);
+
+                                       // split it "nicely"
+                                       pos_type pos = firstRelOp(cell(0));     
+                                       cell(1) = cell(0);
+                                       cell(0).erase(pos, cell(0).size());
+                                       cell(1).erase(0, pos);
+                                       setType(LM_OT_ALIGN);
+                                       mutate(newtype);
+                                       break;
+                               }
+
+                               case LM_OT_EQNARRAY:
+                               default:
+                                       MathGridInset::addCol(1);
+                                       MathGridInset::addCol(1);
+
+                                       // split it "nicely" on the firest relop
+                                       pos_type pos = firstRelOp(cell(0));     
+                                       cell(1) = cell(0);
+                                       cell(0).erase(pos, cell(0).size());
+                                       cell(1).erase(0, pos);
+
+                                       if (cell(1).size()) {
+                                               cell(2) = cell(1);
+                                               cell(1).erase(1, cell(1).size());
+                                               cell(2).erase(0);
+                                       }
+
+                                       setType(LM_OT_EQNARRAY);
+                                       mutate(newtype);
+                                       break;
+                               }
+                       break;
+
+               case LM_OT_EQNARRAY:
+                       switch (newtype) {
+                               case LM_OT_SIMPLE:
+                               case LM_OT_EQUATION: {
+                                       // set correct (no)numbering
+                                       bool allnonum = true;
+                                       for (row_type row = 0; row < nrows(); ++row) {
+                                               if (!nonum_[row])
+                                                       allnonum = false;
+                                       }
+
+                                       // set first non-empty label
+                                       string label;
+                                       for (row_type row = 0; row < nrows(); ++row) {
+                                               if (!label_[row].empty()) {
+                                                       label = label_[row];
+                                                       break;
+                                               }
+                                       }
+
+                                       glueall();
+
+                                       nonum_[0] = allnonum;
+                                       label_[0] = label;
+                                       mutate(newtype);
+                                       break;
+                               }
+
+                               case LM_OT_ALIGN:
+                               case LM_OT_ALIGNAT:
+                               case LM_OT_XALIGNAT:
+                               case LM_OT_XXALIGNAT:
+                               default: {
+                                       for (row_type row = 0; row < nrows(); ++row) {
+                                               idx_type c = 3 * row + 1;
+                                               cell(c).push_back(cell(c + 1));
+                                       }
+                                       MathGridInset::delCol(2);
+                                       setType(LM_OT_ALIGN);
+                                       mutate(newtype);
+                                       break;
+                               }
+                       }
+                       break;
+
+               case LM_OT_ALIGN:
+                       switch (newtype) {
+                               case LM_OT_SIMPLE:
+                               case LM_OT_EQUATION:
+                               case LM_OT_EQNARRAY:
+                                       MathGridInset::addCol(1);
+                                       setType(LM_OT_EQNARRAY);
+                                       mutate(newtype);
+                                       break;
+                               
+                               case LM_OT_ALIGNAT:
+                               case LM_OT_XALIGNAT:
+                               case LM_OT_XXALIGNAT:
+                                       setType(newtype);
+                                       break;
+
+                               default:
+                                       lyxerr << "mutation from '" << getType()
+                                               << "' to '" << newtype << "' not implemented\n";
+                                       break;
+                       }
+                       break;
+
+               case LM_OT_MULTLINE:
+                       switch (newtype) {
+                               case LM_OT_GATHER:
+                                       setType(LM_OT_GATHER);
+                                       break;
+                               default:
+                                       lyxerr << "mutation from '" << getType()
+                                               << "' to '" << newtype << "' not implemented\n";
+                                       break;
+                       }
+
+               case LM_OT_GATHER:
+                       switch (newtype) {
+                               case LM_OT_MULTLINE:
+                                       setType(LM_OT_MULTLINE);
+                                       break;
+                               default:
+                                       lyxerr << "mutation from '" << getType()
+                                               << "' to '" << newtype << "' not implemented\n";
+                                       break;
+                       }
+
+               default:
+                       lyxerr << "mutation from '" << getType()
+                               << "' to '" << newtype << "' not implemented\n";
        }
 }