7 #include "math_hullinset.h"
8 #include "math_mathmlstream.h"
9 #include "math_streamstr.h"
10 #include "math_support.h"
12 #include "textpainter.h"
13 #include "funcrequest.h"
15 #include "LaTeXFeatures.h"
16 #include "support/LAssert.h"
17 #include "frontends/Painter.h"
19 #include "frontends/Alert.h"
22 #include "BufferView.h"
32 int getCols(string const & type)
34 if (type == "eqnarray")
38 if (type == "alignat")
40 if (type == "xalignat")
42 if (type == "xxalignat")
48 // returns position of first relation operator in the array
49 // used for "intelligent splitting"
50 MathArray::size_type firstRelOp(MathArray const & ar)
52 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
54 return it - ar.begin();
59 char const * star(bool numbered)
61 return numbered ? "" : "*";
65 int typecode(string const & s)
67 if (s == "none") return 0;
68 if (s == "simple") return 1;
69 if (s == "equation") return 2;
70 if (s == "eqnarray") return 3;
71 if (s == "align") return 4;
72 if (s == "alignat") return 5;
73 if (s == "xalignat") return 6;
74 if (s == "xxalignat") return 7;
75 if (s == "multline") return 8;
76 if (s == "gather") return 9;
77 lyxerr << "unknown hull type '" << s << "'\n";
81 bool smaller(string const & s, string const & t)
83 return typecode(s) < typecode(t);
87 } // end anon namespace
90 MathHullInset::MathHullInset()
91 : MathGridInset(1, 1), type_("none"), nonum_(1), label_(1)
97 MathHullInset::MathHullInset(string const & type)
98 : MathGridInset(getCols(type), 1), type_(type), nonum_(1), label_(1)
104 MathInset * MathHullInset::clone() const
106 return new MathHullInset(*this);
110 MathInset::mode_type MathHullInset::currentMode() const
113 return UNDECIDED_MODE;
114 // definitely math mode ...
119 bool MathHullInset::idxFirst(idx_type & idx, pos_type & pos) const
127 bool MathHullInset::idxLast(idx_type & idx, pos_type & pos) const
130 pos = cell(idx).size();
135 char MathHullInset::defaultColAlign(col_type col)
137 if (type_ == "eqnarray")
139 if (typecode(type_) >= typecode("align"))
140 return "rl"[col & 1];
145 int MathHullInset::defaultColSpace(col_type col)
147 if (type_ == "align" || type_ == "alignat")
149 if (type_ == "xalignat")
150 return (col & 1) ? 20 : 0;
151 if (type_ == "xxalignat")
152 return (col & 1) ? 40 : 0;
157 char const * MathHullInset::standardFont() const
160 return "lyxnochange";
165 void MathHullInset::metrics(MathMetricsInfo & mi) const
167 MathFontSetChanger dummy1(mi.base, standardFont());
168 MathStyleChanger dummy2(mi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
170 // let the cells adjust themselves
171 MathGridInset::metrics(mi);
178 if (numberedType()) {
179 MathFontSetChanger dummy(mi.base, "mathbf");
181 for (row_type row = 0; row < nrows(); ++row)
182 l = max(l, mathed_string_width(mi.base.font, nicelabel(row)));
188 // make it at least as high as the current font
191 math_font_max_dim(mi.base.font, asc, des);
192 dim_.a = max(dim_.a, asc);
193 dim_.d = max(dim_.d, des);
200 void MathHullInset::draw(MathPainterInfo & pi, int x, int y) const
202 MathFontSetChanger dummy1(pi.base, standardFont());
203 MathStyleChanger dummy2(pi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
204 MathGridInset::draw(pi, x + 1, y);
206 if (numberedType()) {
207 int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
208 for (row_type row = 0; row < nrows(); ++row) {
209 int const yy = y + rowinfo_[row].offset_;
210 MathFontSetChanger dummy(pi.base, "mathrm");
211 drawStr(pi, pi.base.font, xx, yy, nicelabel(row));
215 drawMarkers2(pi, x, y);
219 void MathHullInset::metricsT(TextMetricsInfo const & mi) const
222 MathGridInset::metricsT(mi);
225 WriteStream wi(os, false, true);
227 dim_.w = os.str().size();
234 void MathHullInset::drawT(TextPainter & pain, int x, int y) const
237 MathGridInset::drawT(pain, x, y);
240 WriteStream wi(os, false, true);
242 pain.draw(x, y, os.str().c_str());
247 string MathHullInset::label(row_type row) const
249 row_type n = nrows();
250 lyx::Assert(row < n);
255 void MathHullInset::label(row_type row, string const & label)
257 //lyxerr << "setting label '" << label << "' for row " << row << endl;
262 void MathHullInset::numbered(row_type row, bool num)
268 bool MathHullInset::numbered(row_type row) const
274 bool MathHullInset::ams() const
278 type_ == "multline" ||
280 type_ == "alignat" ||
281 type_ == "xalignat" ||
282 type_ == "xxalignat";
286 bool MathHullInset::display() const
288 return type_ != "simple" && type_ != "none";
292 void MathHullInset::getLabelList(std::vector<string> & labels) const
294 for (row_type row = 0; row < nrows(); ++row)
295 if (!label_[row].empty() && nonum_[row] != 1)
296 labels.push_back(label_[row]);
300 bool MathHullInset::numberedType() const
304 if (type_ == "simple")
306 if (type_ == "xxalignat")
308 for (row_type row = 0; row < nrows(); ++row)
315 void MathHullInset::validate(LaTeXFeatures & features) const
318 features.require("amsmath");
321 // Validation is necessary only if not using AMS math.
322 // To be safe, we will always run mathedvalidate.
323 //if (features.amsstyle)
326 features.require("boldsymbol");
327 //features.binom = true;
329 MathNestInset::validate(features);
333 void MathHullInset::header_write(WriteStream & os) const
335 bool n = numberedType();
340 else if (type_ == "simple") {
346 else if (type_ == "equation") {
348 os << "\\begin{equation" << star(n) << "}\n";
353 else if (type_ == "eqnarray" || type_ == "align")
354 os << "\\begin{" << type_ << star(n) << "}\n";
356 else if (type_ == "alignat" || type_ == "xalignat")
357 os << "\\begin{" << type_ << star(n) << "}"
358 << "{" << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
360 else if (type_ == "xxalignat")
361 os << "\\begin{" << type_ << "}"
362 << "{" << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
364 else if (type_ == "multline" || type_ == "gather")
365 os << "\\begin{" << type_ << "}\n";
368 os << "\\begin{unknown" << star(n) << "}";
372 void MathHullInset::footer_write(WriteStream & os) const
374 bool n = numberedType();
379 else if (type_ == "simple")
382 else if (type_ == "equation")
384 os << "\\end{equation" << star(n) << "}\n";
388 else if (type_ == "eqnarray" || type_ == "align" || type_ == "alignat"
389 || type_ == "xalignat")
390 os << "\n\\end{" << type_ << star(n) << "}\n";
392 else if (type_ == "xxalignat" || type_ == "multline" || type_ == "gather")
393 os << "\n\\end{" << type_ << "}\n";
396 os << "\\end{unknown" << star(n) << "}";
400 void MathHullInset::addRow(row_type row)
402 nonum_.insert(nonum_.begin() + row + 1, !numberedType());
403 label_.insert(label_.begin() + row + 1, string());
404 MathGridInset::addRow(row);
408 void MathHullInset::delRow(row_type row)
410 MathGridInset::delRow(row);
411 nonum_.erase(nonum_.begin() + row);
412 label_.erase(label_.begin() + row);
416 void MathHullInset::addFancyCol(col_type col)
418 if (type_ == "equation")
421 else if (type_ == "eqnarray") {
426 else if (type_ == "align" || type_ == "alignat"
427 || type_ == "xalignat" || type_ == "xxalignat")
428 MathGridInset::addCol(col);
432 void MathHullInset::delFancyCol(col_type col)
434 if (type_ == "alignat" || type_ == "xalignat" || type_ == "xxalignat")
435 MathGridInset::delCol(col);
439 string MathHullInset::nicelabel(row_type row) const
443 if (label_[row].empty())
444 return string("(#)");
445 return "(" + label_[row] + ")";
449 void MathHullInset::glueall()
452 for (idx_type i = 0; i < nargs(); ++i)
454 *this = MathHullInset("simple");
460 string const & MathHullInset::getType() const
466 void MathHullInset::setType(string const & type)
474 void MathHullInset::mutate(string const & newtype)
476 //lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'\n";
478 // we try to move along the chain
479 // none <-> simple <-> equation <-> eqnarray
481 if (newtype == "dump") {
485 else if (newtype == type_) {
489 else if (type_ == "none") {
495 else if (type_ == "simple") {
496 if (newtype == "none") {
505 else if (type_ == "equation") {
506 if (smaller(newtype, type_)) {
509 } else if (newtype == "eqnarray") {
510 MathGridInset::addCol(1);
511 MathGridInset::addCol(1);
513 // split it "nicely" on the firest relop
514 pos_type pos = firstRelOp(cell(0));
515 cell(1) = MathArray(cell(0).begin() + pos, cell(0).end());
516 cell(0).erase(pos, cell(0).size());
518 if (cell(1).size()) {
519 cell(2) = MathArray(cell(1).begin() + 1, cell(1).end());
520 cell(1).erase(1, cell(1).size());
524 } else if (newtype == "multline" || newtype == "gather") {
528 MathGridInset::addCol(1);
530 pos_type pos = firstRelOp(cell(0));
532 cell(0).erase(pos, cell(0).size());
533 cell(1).erase(0, pos);
539 else if (type_ == "eqnarray") {
540 if (smaller(newtype, type_)) {
541 // set correct (no)numbering
542 bool allnonum = true;
543 for (row_type row = 0; row < nrows(); ++row)
547 // set first non-empty label
549 for (row_type row = 0; row < nrows(); ++row) {
550 if (!label_[row].empty()) {
557 nonum_[0] = allnonum;
560 } else { // align & Co.
561 for (row_type row = 0; row < nrows(); ++row) {
562 idx_type c = 3 * row + 1;
563 cell(c).append(cell(c + 1));
565 MathGridInset::delCol(2);
571 else if (type_ == "align") {
572 if (smaller(newtype, type_)) {
573 MathGridInset::addCol(1);
581 else if (type_ == "multline") {
582 if (newtype == "gather") {
585 lyxerr << "mutation from '" << type_
586 << "' to '" << newtype << "' not implemented"
591 else if (type_ == "gather") {
592 if (newtype == "multline") {
595 lyxerr << "mutation from '" << type_
596 << "' to '" << newtype << "' not implemented" << endl;
601 lyxerr << "mutation from '" << type_
602 << "' to '" << newtype << "' not implemented" << endl;
607 void MathHullInset::write(WriteStream & os) const
611 bool n = numberedType();
613 for (row_type row = 0; row < nrows(); ++row) {
614 for (col_type col = 0; col < ncols(); ++col)
615 os << cell(index(row, col)) << eocString(col);
617 if (!label_[row].empty())
618 os << "\\label{" << label_[row] << "}";
622 os << eolString(row);
629 void MathHullInset::normalize(NormalStream & os) const
631 os << "[formula " << type_ << " ";
632 MathGridInset::normalize(os);
637 void MathHullInset::mathmlize(MathMLStream & os) const
639 MathGridInset::mathmlize(os);
643 void MathHullInset::infoize(std::ostream & os) const
645 os << "Type: " << type_;
649 void MathHullInset::check() const
651 lyx::Assert(nonum_.size() == nrows());
652 lyx::Assert(label_.size() == nrows());
656 MathInset::result_type MathHullInset::dispatch
657 (FuncRequest const & cmd, idx_type & idx, pos_type & pos)
659 switch (cmd.action) {
662 if (type_ == "simple" || type_ == "equation") {
666 return DISPATCHED_POP;
668 return MathGridInset::dispatch(cmd, idx, pos);
670 case LFUN_MATH_NUMBER:
671 //lyxerr << "toggling all numbers\n";
673 //bv->lockedInsetStoreUndo(Undo::INSERT);
674 bool old = numberedType();
675 for (row_type row = 0; row < nrows(); ++row)
677 //bv->owner()->message(old ? _("No number") : _("Number"));
678 //updateLocal(bv, true);
682 case LFUN_MATH_NONUMBER:
684 //bv->lockedInsetStoreUndo(Undo::INSERT);
685 bool old = numbered(row(idx));
686 //bv->owner()->message(old ? _("No number") : _("Number"));
687 numbered(row(idx), !old);
688 //updateLocal(bv, true);
692 case LFUN_INSERT_LABEL: {
693 row_type r = row(idx);
694 string old_label = label(r);
695 string new_label = cmd.argument;
697 if (new_label.empty()) {
698 string const default_label =
699 (lyxrc.label_init_length >= 0) ? "eq:" : "";
700 pair<bool, string> const res = old_label.empty()
701 ? Alert::askForText(_("Enter new label to insert:"), default_label)
702 : Alert::askForText(_("Enter label:"), old_label);
705 new_label = trim(res.second);
708 //if (new_label == old_label)
709 // break; // Nothing to do
711 if (!new_label.empty())
714 #warning FIXME: please check you really mean repaint() ... is it needed,
715 #warning and if so, should it be update() instead ?
716 if (!new_label.empty()
717 && cmd.view()->ChangeRefsIfUnique(old_label, new_label))
718 cmd.view()->repaint();
724 case LFUN_MATH_HALIGN:
725 case LFUN_MATH_VALIGN:
726 // we explicitly don't want the default behaviour here
730 return MathGridInset::dispatch(cmd, idx, pos);