X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_matrixinset.C;h=4fa1ebd1f10c906d02d9809b933d45848cc59df9;hb=dff2911bda426ad439e6475f62183cedd7044801;hp=9d344f0d9a30144f5112ce6a4bc5c1aa715ded05;hpb=2be247f6ef5e35f27a41d92a88790357875c66bd;p=features.git diff --git a/src/mathed/math_matrixinset.C b/src/mathed/math_matrixinset.C index 9d344f0d9a..4fa1ebd1f1 100644 --- a/src/mathed/math_matrixinset.C +++ b/src/mathed/math_matrixinset.C @@ -1,276 +1,670 @@ -#include - #ifdef __GNUG__ #pragma implementation #endif +#include + #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 * 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_ != 0) { - MathedRowSt * ro = 0; - MathedRowSt * mrow = mt->row_; + 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(); +} + + +MathInset * MathMatrixInset::clone() const +{ + return new MathMatrixInset(*this); } -MathMatrixInset::~MathMatrixInset() +char MathMatrixInset::defaultColAlign(col_type col) { - MathedRowSt * r = row_; - while (r) { - MathedRowSt * q = r->getNext(); - delete r; - r = q; + 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_) { - // lyxerr << " MIDA "; - MathedXIter it(this); - row_ = it.adjustVerticalSt(); - } - - // Clean the arrays - MathedRowSt * cxrow = row_; - while (cxrow) { - for (int i = 0; i <= nc_; ++i) - cxrow->setTab(i, 0); - cxrow = cxrow->getNext(); - } - - // Basic metrics - MathParInset::Metrics(); - - if (nc_ <= 1 && !row_->getNext()) { - row_->ascent(ascent); - row_->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 const MathMatrixInset::getLabelList() const +{ + std::vector 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_; - MathedRowSt * cprow = 0; - int h = 0; - while (cxrow) { - for (int i = 0; i < nc_; ++i) { - if (cxrow == row_ || 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_) ? - 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_->getBaseline(); - break; - case 'b': - ascent = h - hl; - break; - default: - ascent = (row_->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_; - 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_) - 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_) - 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"; } }