A bit more re-organization.
[lyx.git] / src / mathed / InsetMathHull.cpp
blobd68e3bc74257015ae7fa05653b43e122df3624bd
1 /**
2 * \file InsetMathHull.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author André Pönitz
8 * Full author contact details are available in file CREDITS.
9 */
11 #include <config.h>
13 #include "InsetMathHull.h"
15 #include "InsetMathChar.h"
16 #include "InsetMathColor.h"
17 #include "MathExtern.h"
18 #include "MathFactory.h"
19 #include "MathStream.h"
20 #include "MathSupport.h"
22 #include "Buffer.h"
23 #include "BufferParams.h"
24 #include "BufferView.h"
25 #include "CutAndPaste.h"
26 #include "Encoding.h"
27 #include "FuncRequest.h"
28 #include "FuncStatus.h"
29 #include "LaTeXFeatures.h"
30 #include "LyXRC.h"
31 #include "sgml.h"
32 #include "TextPainter.h"
33 #include "TocBackend.h"
35 #include "insets/InsetLabel.h"
36 #include "insets/InsetRef.h"
37 #include "insets/RenderPreview.h"
39 #include "graphics/PreviewImage.h"
41 #include "frontends/Painter.h"
43 #include "support/lassert.h"
44 #include "support/debug.h"
45 #include "support/gettext.h"
46 #include "support/lstrings.h"
48 #include <sstream>
50 using namespace std;
51 using namespace lyx::support;
53 namespace lyx {
55 using cap::grabAndEraseSelection;
57 namespace {
59 int getCols(HullType type)
61 switch (type) {
62 case hullEqnArray:
63 return 3;
64 case hullAlign:
65 case hullFlAlign:
66 case hullAlignAt:
67 case hullXAlignAt:
68 case hullXXAlignAt:
69 return 2;
70 default:
71 return 1;
76 // returns position of first relation operator in the array
77 // used for "intelligent splitting"
78 size_t firstRelOp(MathData const & ar)
80 for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it)
81 if ((*it)->isRelOp())
82 return it - ar.begin();
83 return ar.size();
87 char const * star(bool numbered)
89 return numbered ? "" : "*";
93 } // end anon namespace
96 HullType hullType(docstring const & s)
98 if (s == "none") return hullNone;
99 if (s == "simple") return hullSimple;
100 if (s == "equation") return hullEquation;
101 if (s == "eqnarray") return hullEqnArray;
102 if (s == "align") return hullAlign;
103 if (s == "alignat") return hullAlignAt;
104 if (s == "xalignat") return hullXAlignAt;
105 if (s == "xxalignat") return hullXXAlignAt;
106 if (s == "multline") return hullMultline;
107 if (s == "gather") return hullGather;
108 if (s == "flalign") return hullFlAlign;
109 if (s == "regexp") return hullRegexp;
110 lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl;
111 return HullType(-1);
115 docstring hullName(HullType type)
117 switch (type) {
118 case hullNone: return from_ascii("none");
119 case hullSimple: return from_ascii("simple");
120 case hullEquation: return from_ascii("equation");
121 case hullEqnArray: return from_ascii("eqnarray");
122 case hullAlign: return from_ascii("align");
123 case hullAlignAt: return from_ascii("alignat");
124 case hullXAlignAt: return from_ascii("xalignat");
125 case hullXXAlignAt: return from_ascii("xxalignat");
126 case hullMultline: return from_ascii("multline");
127 case hullGather: return from_ascii("gather");
128 case hullFlAlign: return from_ascii("flalign");
129 case hullRegexp: return from_ascii("regexp");
130 default:
131 lyxerr << "unknown hull type '" << type << "'" << endl;
132 return from_ascii("none");
136 static InsetLabel * dummy_pointer = 0;
138 InsetMathHull::InsetMathHull(Buffer * buf)
139 : InsetMathGrid(buf, 1, 1), type_(hullNone), nonum_(1, false),
140 label_(1, dummy_pointer), preview_(new RenderPreview(this))
142 //lyxerr << "sizeof InsetMath: " << sizeof(InsetMath) << endl;
143 //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl;
144 //lyxerr << "sizeof InsetMathChar: " << sizeof(InsetMathChar) << endl;
145 //lyxerr << "sizeof FontInfo: " << sizeof(FontInfo) << endl;
146 buffer_ = buf;
147 initMath();
148 setDefaults();
152 InsetMathHull::InsetMathHull(Buffer * buf, HullType type)
153 : InsetMathGrid(buf, getCols(type), 1), type_(type), nonum_(1, false),
154 label_(1, dummy_pointer), preview_(new RenderPreview(this))
156 buffer_ = buf;
157 initMath();
158 setDefaults();
162 InsetMathHull::InsetMathHull(InsetMathHull const & other) : InsetMathGrid(other)
164 operator=(other);
168 InsetMathHull::~InsetMathHull()
170 for (size_t i = 0; i < label_.size(); ++i)
171 delete label_[i];
175 Inset * InsetMathHull::clone() const
177 return new InsetMathHull(*this);
181 InsetMathHull & InsetMathHull::operator=(InsetMathHull const & other)
183 if (this == &other)
184 return *this;
185 InsetMathGrid::operator=(other);
186 type_ = other.type_;
187 nonum_ = other.nonum_;
188 buffer_ = other.buffer_;
189 for (size_t i = 0; i < label_.size(); ++i)
190 delete label_[i];
191 label_ = other.label_;
192 for (size_t i = 0; i != label_.size(); ++i) {
193 if (label_[i])
194 label_[i] = new InsetLabel(*label_[i]);
196 preview_.reset(new RenderPreview(*other.preview_, this));
198 return *this;
202 void InsetMathHull::setBuffer(Buffer & buffer)
204 InsetMathGrid::setBuffer(buffer);
206 for (size_t i = 0; i != label_.size(); ++i) {
207 if (label_[i])
208 label_[i]->setBuffer(buffer);
213 void InsetMathHull::updateLabels(ParIterator const & it)
215 if (!buffer_) {
216 //FIXME: buffer_ should be set at creation for this inset! Problem is
217 // This inset is created at too many places (see Parser::parse1() in
218 // MathParser.cpp).
219 return;
221 for (size_t i = 0; i != label_.size(); ++i) {
222 if (label_[i])
223 label_[i]->updateLabels(it);
228 void InsetMathHull::addToToc(DocIterator const & pit)
230 if (!buffer_) {
231 //FIXME: buffer_ should be set at creation for this inset! Problem is
232 // This inset is created at too many places (see Parser::parse1() in
233 // MathParser.cpp).
234 return;
237 Toc & toc = buffer().tocBackend().toc("equation");
239 for (row_type row = 0; row != nrows(); ++row) {
240 if (nonum_[row])
241 continue;
242 if (label_[row])
243 label_[row]->addToToc(pit);
244 toc.push_back(TocItem(pit, 0, nicelabel(row)));
249 Inset * InsetMathHull::editXY(Cursor & cur, int x, int y)
251 if (use_preview_) {
252 edit(cur, true);
253 return this;
255 return InsetMathNest::editXY(cur, x, y);
259 InsetMath::mode_type InsetMathHull::currentMode() const
261 if (type_ == hullNone)
262 return UNDECIDED_MODE;
263 // definitely math mode ...
264 return MATH_MODE;
268 bool InsetMathHull::idxFirst(Cursor & cur) const
270 cur.idx() = 0;
271 cur.pos() = 0;
272 return true;
276 bool InsetMathHull::idxLast(Cursor & cur) const
278 cur.idx() = nargs() - 1;
279 cur.pos() = cur.lastpos();
280 return true;
284 char InsetMathHull::defaultColAlign(col_type col)
286 if (type_ == hullEqnArray)
287 return "rcl"[col];
288 if (type_ == hullGather)
289 return 'c';
290 if (type_ >= hullAlign)
291 return "rl"[col & 1];
292 return 'c';
296 int InsetMathHull::defaultColSpace(col_type col)
298 if (type_ == hullAlign || type_ == hullAlignAt)
299 return 0;
300 if (type_ == hullXAlignAt)
301 return (col & 1) ? 20 : 0;
302 if (type_ == hullXXAlignAt || type_ == hullFlAlign)
303 return (col & 1) ? 40 : 0;
304 return 0;
308 docstring InsetMathHull::standardFont() const
310 return from_ascii(type_ == hullNone ? "lyxnochange" : "mathnormal");
314 bool InsetMathHull::previewState(BufferView * bv) const
316 if (!editing(bv) && RenderPreview::status() == LyXRC::PREVIEW_ON) {
317 graphics::PreviewImage const * pimage =
318 preview_->getPreviewImage(bv->buffer());
319 return pimage && pimage->image();
321 return false;
325 void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const
327 if (previewState(mi.base.bv)) {
328 preview_->metrics(mi, dim);
329 // insert a one pixel gap in front of the formula
330 dim.wid += 1;
331 if (display())
332 dim.des += displayMargin();
333 // Cache the inset dimension.
334 setDimCache(mi, dim);
335 return;
338 FontSetChanger dummy1(mi.base, standardFont());
339 StyleChanger dummy2(mi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
341 // let the cells adjust themselves
342 InsetMathGrid::metrics(mi, dim);
344 if (display()) {
345 dim.asc += displayMargin();
346 dim.des += displayMargin();
349 if (numberedType()) {
350 FontSetChanger dummy(mi.base, from_ascii("mathbf"));
351 int l = 0;
352 for (row_type row = 0; row < nrows(); ++row)
353 l = max(l, mathed_string_width(mi.base.font, nicelabel(row)));
355 if (l)
356 dim.wid += 30 + l;
359 // make it at least as high as the current font
360 int asc = 0;
361 int des = 0;
362 math_font_max_dim(mi.base.font, asc, des);
363 dim.asc = max(dim.asc, asc);
364 dim.des = max(dim.des, des);
365 // Cache the inset dimension.
366 // FIXME: This will overwrite InsetMathGrid dimension, is that OK?
367 setDimCache(mi, dim);
371 void InsetMathHull::drawBackground(PainterInfo & pi, int x, int y) const
373 Dimension const dim = dimension(*pi.base.bv);
374 pi.pain.fillRectangle(x + 1, y - dim.asc + 1, dim.wid - 2,
375 dim.asc + dim.des - 1, pi.backgroundColor(this));
379 void InsetMathHull::draw(PainterInfo & pi, int x, int y) const
381 use_preview_ = previewState(pi.base.bv);
383 if (use_preview_) {
384 // one pixel gap in front
385 preview_->draw(pi, x + 1, y);
386 setPosCache(pi, x, y);
387 return;
390 FontSetChanger dummy1(pi.base, standardFont());
391 StyleChanger dummy2(pi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
392 InsetMathGrid::draw(pi, x + 1, y);
394 if (numberedType()) {
395 int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
396 for (row_type row = 0; row < nrows(); ++row) {
397 int const yy = y + rowinfo_[row].offset_;
398 FontSetChanger dummy(pi.base, from_ascii("mathrm"));
399 docstring const nl = nicelabel(row);
400 pi.draw(xx, yy, nl);
403 setPosCache(pi, x, y);
407 void InsetMathHull::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
409 if (display()) {
410 InsetMathGrid::metricsT(mi, dim);
411 } else {
412 odocstringstream os;
413 WriteStream wi(os, false, true, WriteStream::wsDefault);
414 write(wi);
415 dim.wid = os.str().size();
416 dim.asc = 1;
417 dim.des = 0;
422 void InsetMathHull::drawT(TextPainter & pain, int x, int y) const
424 if (display()) {
425 InsetMathGrid::drawT(pain, x, y);
426 } else {
427 odocstringstream os;
428 WriteStream wi(os, false, true, WriteStream::wsDefault);
429 write(wi);
430 pain.draw(x, y, os.str().c_str());
435 static docstring latexString(InsetMathHull const & inset)
437 odocstringstream ls;
438 // This has to be static, because a preview snippet or a math
439 // macro containing math in text mode (such as $\text{$\phi$}$ or
440 // \newcommand{\xxx}{\text{$\phi$}}) gets processed twice. The
441 // first time as a whole, and the second time only the inner math.
442 // In this last case inset.buffer() would be invalid.
443 static Encoding const * encoding = 0;
444 if (inset.isBufferValid())
445 encoding = &(inset.buffer().params().encoding());
446 WriteStream wi(ls, false, true, WriteStream::wsPreview, encoding);
447 inset.write(wi);
448 return ls.str();
452 void InsetMathHull::initUnicodeMath() const
454 // Trigger classification of the unicode symbols in this inset
455 docstring const dummy = latexString(*this);
459 void InsetMathHull::addPreview(graphics::PreviewLoader & ploader) const
461 if (RenderPreview::status() == LyXRC::PREVIEW_ON) {
462 docstring const snippet = latexString(*this);
463 preview_->addPreview(snippet, ploader);
468 bool InsetMathHull::notifyCursorLeaves(Cursor const & /*old*/, Cursor & cur)
470 if (RenderPreview::status() == LyXRC::PREVIEW_ON) {
471 Buffer const * buffer = cur.buffer();
472 docstring const snippet = latexString(*this);
473 preview_->addPreview(snippet, *buffer);
474 preview_->startLoading(*buffer);
475 cur.updateFlags(Update::Force);
477 return false;
481 docstring InsetMathHull::label(row_type row) const
483 LASSERT(row < nrows(), /**/);
484 if (InsetLabel * il = label_[row])
485 return il->screenLabel();
486 return docstring();
490 void InsetMathHull::label(row_type row, docstring const & label)
492 //lyxerr << "setting label '" << label << "' for row " << row << endl;
493 if (label_[row]) {
494 if (label.empty()) {
495 delete label_[row];
496 label_[row] = dummy_pointer;
497 // We need an update of the Buffer reference cache.
498 // This is achieved by updateLabels().
499 if (buffer_)
500 buffer().updateLabels();
501 } else {
502 if (buffer_)
503 label_[row]->updateCommand(label);
504 else
505 label_[row]->setParam("name", label);
507 return;
509 InsetCommandParams p(LABEL_CODE);
510 p["name"] = label;
511 label_[row] = new InsetLabel(buffer_, p);
512 if (buffer_)
513 label_[row]->setBuffer(buffer());
517 void InsetMathHull::numbered(row_type row, bool num)
519 nonum_[row] = !num;
520 if (nonum_[row] && label_[row]) {
521 delete label_[row];
522 label_[row] = 0;
523 if (!buffer_) {
524 // The buffer is set at the end of readInset.
525 // When parsing the inset, buffer_ is 0.
526 return;
528 // We need an update of the Buffer reference cache.
529 // This is achieved by updateLabels().
530 buffer().updateLabels();
535 bool InsetMathHull::numbered(row_type row) const
537 return !nonum_[row];
541 bool InsetMathHull::ams() const
543 return type_ == hullAlign
544 || type_ == hullFlAlign
545 || type_ == hullMultline
546 || type_ == hullGather
547 || type_ == hullAlignAt
548 || type_ == hullXAlignAt
549 || type_ == hullXXAlignAt;
553 Inset::DisplayType InsetMathHull::display() const
555 if (type_ == hullSimple || type_ == hullNone || type_ == hullRegexp)
556 return Inline;
557 return AlignCenter;
560 bool InsetMathHull::numberedType() const
562 if (type_ == hullNone)
563 return false;
564 if (type_ == hullSimple)
565 return false;
566 if (type_ == hullXXAlignAt)
567 return false;
568 if (type_ == hullRegexp)
569 return false;
570 for (row_type row = 0; row < nrows(); ++row)
571 if (!nonum_[row])
572 return true;
573 return false;
577 void InsetMathHull::validate(LaTeXFeatures & features) const
579 if (ams())
580 features.require("amsmath");
582 // Validation is necessary only if not using AMS math.
583 // To be safe, we will always run mathedvalidate.
584 //if (features.amsstyle)
585 // return;
587 //features.binom = true;
589 InsetMathGrid::validate(features);
593 void InsetMathHull::header_write(WriteStream & os) const
595 bool n = numberedType();
597 switch(type_) {
598 case hullNone:
599 break;
601 case hullSimple:
602 os << '$';
603 if (cell(0).empty())
604 os << ' ';
605 break;
607 case hullEquation:
608 if (n)
609 os << "\\begin{equation" << star(n) << "}\n";
610 else
611 os << "\\[\n";
612 break;
614 case hullEqnArray:
615 case hullAlign:
616 case hullFlAlign:
617 case hullGather:
618 case hullMultline:
619 os << "\\begin{" << hullName(type_) << star(n) << "}\n";
620 break;
622 case hullAlignAt:
623 case hullXAlignAt:
624 os << "\\begin{" << hullName(type_) << star(n) << '}'
625 << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
626 break;
628 case hullXXAlignAt:
629 os << "\\begin{" << hullName(type_) << '}'
630 << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
631 break;
633 case hullRegexp:
634 os << "\\regexp{";
635 break;
637 default:
638 os << "\\begin{unknown" << star(n) << '}';
639 break;
644 void InsetMathHull::footer_write(WriteStream & os) const
646 bool n = numberedType();
648 switch(type_) {
649 case hullNone:
650 os << "\n";
651 break;
653 case hullSimple:
654 os << '$';
655 break;
657 case hullEquation:
658 if (n)
659 os << "\\end{equation" << star(n) << "}\n";
660 else
661 os << "\\]\n";
662 break;
664 case hullEqnArray:
665 case hullAlign:
666 case hullFlAlign:
667 case hullAlignAt:
668 case hullXAlignAt:
669 case hullGather:
670 case hullMultline:
671 os << "\\end{" << hullName(type_) << star(n) << "}\n";
672 break;
674 case hullXXAlignAt:
675 os << "\\end{" << hullName(type_) << "}\n";
676 break;
678 case hullRegexp:
679 os << "}";
680 break;
682 default:
683 os << "\\end{unknown" << star(n) << '}';
684 break;
689 bool InsetMathHull::rowChangeOK() const
691 return
692 type_ == hullEqnArray || type_ == hullAlign ||
693 type_ == hullFlAlign || type_ == hullAlignAt ||
694 type_ == hullXAlignAt || type_ == hullXXAlignAt ||
695 type_ == hullGather || type_ == hullMultline;
699 bool InsetMathHull::colChangeOK() const
701 return
702 type_ == hullAlign || type_ == hullFlAlign ||type_ == hullAlignAt ||
703 type_ == hullXAlignAt || type_ == hullXXAlignAt;
707 void InsetMathHull::addRow(row_type row)
709 if (!rowChangeOK())
710 return;
712 bool numbered = numberedType();
713 docstring lab;
714 if (type_ == hullMultline) {
715 if (row + 1 == nrows()) {
716 nonum_[row] = true;
717 lab = label(row);
718 } else
719 numbered = false;
722 nonum_.insert(nonum_.begin() + row + 1, !numbered);
723 label_.insert(label_.begin() + row + 1, dummy_pointer);
724 if (!lab.empty())
725 label(row + 1, lab);
726 InsetMathGrid::addRow(row);
730 void InsetMathHull::swapRow(row_type row)
732 if (nrows() <= 1)
733 return;
734 if (row + 1 == nrows())
735 --row;
736 // gcc implements the standard std::vector<bool> which is *not* a container:
737 // http://www.gotw.ca/publications/N1185.pdf
738 // As a results, it doesn't like this:
739 // swap(nonum_[row], nonum_[row + 1]);
740 // so we do it manually:
741 bool const b = nonum_[row];
742 nonum_[row] = nonum_[row + 1];
743 nonum_[row + 1] = b;
744 swap(label_[row], label_[row + 1]);
745 InsetMathGrid::swapRow(row);
749 void InsetMathHull::delRow(row_type row)
751 if (nrows() <= 1 || !rowChangeOK())
752 return;
753 if (row + 1 == nrows() && type_ == hullMultline) {
754 bool const b = nonum_[row - 1];
755 nonum_[row - 1] = nonum_[row];
756 nonum_[row] = b;
757 swap(label_[row - 1], label_[row]);
758 InsetMathGrid::delRow(row);
759 return;
761 InsetMathGrid::delRow(row);
762 // The last dummy row has no number info nor a label.
763 // Test nrows() + 1 because we have already erased the row.
764 if (row == nrows() + 1)
765 row--;
766 nonum_.erase(nonum_.begin() + row);
767 delete label_[row];
768 label_.erase(label_.begin() + row);
772 void InsetMathHull::addCol(col_type col)
774 if (!colChangeOK())
775 return;
776 InsetMathGrid::addCol(col);
780 void InsetMathHull::delCol(col_type col)
782 if (ncols() <= 1 || !colChangeOK())
783 return;
784 InsetMathGrid::delCol(col);
788 docstring InsetMathHull::nicelabel(row_type row) const
790 if (nonum_[row])
791 return docstring();
792 if (!label_[row])
793 return from_ascii("(#)");
794 return '(' + label_[row]->screenLabel() + from_ascii(", #)");
798 void InsetMathHull::glueall()
800 MathData ar;
801 for (idx_type i = 0; i < nargs(); ++i)
802 ar.append(cell(i));
803 *this = InsetMathHull(buffer_, hullSimple);
804 cell(0) = ar;
805 setDefaults();
809 void InsetMathHull::splitTo2Cols()
811 LASSERT(ncols() == 1, /**/);
812 InsetMathGrid::addCol(1);
813 for (row_type row = 0; row < nrows(); ++row) {
814 idx_type const i = 2 * row;
815 pos_type pos = firstRelOp(cell(i));
816 cell(i + 1) = MathData(buffer_, cell(i).begin() + pos, cell(i).end());
817 cell(i).erase(pos, cell(i).size());
822 void InsetMathHull::splitTo3Cols()
824 LASSERT(ncols() < 3, /**/);
825 if (ncols() < 2)
826 splitTo2Cols();
827 InsetMathGrid::addCol(2);
828 for (row_type row = 0; row < nrows(); ++row) {
829 idx_type const i = 3 * row + 1;
830 if (cell(i).size()) {
831 cell(i + 1) = MathData(buffer_, cell(i).begin() + 1, cell(i).end());
832 cell(i).erase(1, cell(i).size());
838 void InsetMathHull::changeCols(col_type cols)
840 if (ncols() == cols)
841 return;
842 else if (ncols() < cols) {
843 // split columns
844 if (cols < 3)
845 splitTo2Cols();
846 else {
847 splitTo3Cols();
848 while (ncols() < cols)
849 InsetMathGrid::addCol(ncols());
851 return;
854 // combine columns
855 for (row_type row = 0; row < nrows(); ++row) {
856 idx_type const i = row * ncols();
857 for (col_type col = cols; col < ncols(); ++col) {
858 cell(i + cols - 1).append(cell(i + col));
861 // delete columns
862 while (ncols() > cols) {
863 InsetMathGrid::delCol(ncols() - 1);
868 HullType InsetMathHull::getType() const
870 return type_;
874 void InsetMathHull::setType(HullType type)
876 type_ = type;
877 setDefaults();
881 void InsetMathHull::mutate(HullType newtype)
883 //lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl;
885 // we try to move along the chain
886 // none <-> simple <-> equation <-> eqnarray -> *align* -> multline, gather -+
887 // ^ |
888 // +-------------------------------------+
889 // we use eqnarray as intermediate type for mutations that are not
890 // directly supported because it handles labels and numbering for
891 // "down mutation".
893 if (newtype == type_) {
894 // done
897 else if (newtype < hullNone) {
898 // unknown type
899 dump();
902 else if (type_ == hullNone) {
903 setType(hullSimple);
904 numbered(0, false);
905 mutate(newtype);
908 else if (type_ == hullSimple) {
909 if (newtype == hullNone) {
910 setType(hullNone);
911 numbered(0, false);
912 } else {
913 setType(hullEquation);
914 numbered(0, false);
915 mutate(newtype);
919 else if (type_ == hullEquation) {
920 if (newtype < type_) {
921 setType(hullSimple);
922 numbered(0, false);
923 mutate(newtype);
924 } else if (newtype == hullEqnArray) {
925 // split it "nicely" on the first relop
926 splitTo3Cols();
927 setType(hullEqnArray);
928 } else if (newtype == hullMultline || newtype == hullGather) {
929 setType(newtype);
930 } else {
931 // split it "nicely"
932 splitTo2Cols();
933 setType(hullAlign);
934 mutate(newtype);
938 else if (type_ == hullEqnArray) {
939 if (newtype < type_) {
940 // set correct (no)numbering
941 nonum_[0] = true;
942 for (row_type row = 0; row < nrows(); ++row) {
943 if (!nonum_[row]) {
944 nonum_[0] = false;
945 break;
949 // set first non-empty label
950 for (row_type row = 0; row < nrows(); ++row) {
951 if (label_[row]) {
952 label_[0] = label_[row];
953 break;
957 glueall();
958 mutate(newtype);
959 } else { // align & Co.
960 changeCols(2);
961 setType(hullAlign);
962 mutate(newtype);
966 else if (type_ == hullAlign || type_ == hullAlignAt ||
967 type_ == hullXAlignAt || type_ == hullFlAlign) {
968 if (newtype < hullAlign) {
969 changeCols(3);
970 setType(hullEqnArray);
971 mutate(newtype);
972 } else if (newtype == hullGather || newtype == hullMultline) {
973 changeCols(1);
974 setType(newtype);
975 } else if (newtype == hullXXAlignAt) {
976 for (row_type row = 0; row < nrows(); ++row)
977 numbered(row, false);
978 setType(newtype);
979 } else {
980 setType(newtype);
984 else if (type_ == hullXXAlignAt) {
985 for (row_type row = 0; row < nrows(); ++row)
986 numbered(row, false);
987 if (newtype < hullAlign) {
988 changeCols(3);
989 setType(hullEqnArray);
990 mutate(newtype);
991 } else if (newtype == hullGather || newtype == hullMultline) {
992 changeCols(1);
993 setType(newtype);
994 } else {
995 setType(newtype);
999 else if (type_ == hullMultline || type_ == hullGather) {
1000 if (newtype == hullGather || newtype == hullMultline)
1001 setType(newtype);
1002 else if (newtype == hullAlign || newtype == hullFlAlign ||
1003 newtype == hullAlignAt || newtype == hullXAlignAt) {
1004 splitTo2Cols();
1005 setType(newtype);
1006 } else if (newtype == hullXXAlignAt) {
1007 splitTo2Cols();
1008 for (row_type row = 0; row < nrows(); ++row)
1009 numbered(row, false);
1010 setType(newtype);
1011 } else {
1012 splitTo3Cols();
1013 setType(hullEqnArray);
1014 mutate(newtype);
1018 else {
1019 lyxerr << "mutation from '" << to_utf8(hullName(type_))
1020 << "' to '" << to_utf8(hullName(newtype))
1021 << "' not implemented" << endl;
1026 docstring InsetMathHull::eolString(row_type row, bool fragile) const
1028 docstring res;
1029 if (numberedType()) {
1030 if (label_[row] && !nonum_[row])
1031 res += "\\label{" + label_[row]->getParam("name") + '}';
1032 if (nonum_[row] && (type_ != hullMultline))
1033 res += "\\nonumber ";
1035 return res + InsetMathGrid::eolString(row, fragile);
1039 void InsetMathHull::write(WriteStream & os) const
1041 ModeSpecifier specifier(os, MATH_MODE);
1042 header_write(os);
1043 InsetMathGrid::write(os);
1044 footer_write(os);
1048 void InsetMathHull::normalize(NormalStream & os) const
1050 os << "[formula " << hullName(type_) << ' ';
1051 InsetMathGrid::normalize(os);
1052 os << "] ";
1056 void InsetMathHull::mathmlize(MathStream & os) const
1058 InsetMathGrid::mathmlize(os);
1062 void InsetMathHull::infoize(odocstream & os) const
1064 os << "Type: " << hullName(type_);
1068 void InsetMathHull::check() const
1070 LASSERT(nonum_.size() == nrows(), /**/);
1071 LASSERT(label_.size() == nrows(), /**/);
1075 void InsetMathHull::doExtern(Cursor & cur, FuncRequest & func)
1077 docstring dlang;
1078 docstring extra;
1079 idocstringstream iss(func.argument());
1080 iss >> dlang >> extra;
1081 if (extra.empty())
1082 extra = from_ascii("noextra");
1083 string const lang = to_ascii(dlang);
1085 // FIXME: temporarily disabled
1086 //if (cur.selection()) {
1087 // MathData ar;
1088 // selGet(cur.ar);
1089 // lyxerr << "use selection: " << ar << endl;
1090 // insert(pipeThroughExtern(lang, extra, ar));
1091 // return;
1094 MathData eq;
1095 eq.push_back(MathAtom(new InsetMathChar('=')));
1097 // go to first item in line
1098 cur.idx() -= cur.idx() % ncols();
1099 cur.pos() = 0;
1101 if (getType() == hullSimple) {
1102 size_type pos = cur.cell().find_last(eq);
1103 MathData ar;
1104 if (cur.inMathed() && cur.selection()) {
1105 asArray(grabAndEraseSelection(cur), ar);
1106 } else if (pos == cur.cell().size()) {
1107 ar = cur.cell();
1108 lyxerr << "use whole cell: " << ar << endl;
1109 } else {
1110 ar = MathData(buffer_, cur.cell().begin() + pos + 1, cur.cell().end());
1111 lyxerr << "use partial cell form pos: " << pos << endl;
1113 cur.cell().append(eq);
1114 cur.cell().append(pipeThroughExtern(lang, extra, ar));
1115 cur.pos() = cur.lastpos();
1116 return;
1119 if (getType() == hullEquation) {
1120 lyxerr << "use equation inset" << endl;
1121 mutate(hullEqnArray);
1122 MathData & ar = cur.cell();
1123 lyxerr << "use cell: " << ar << endl;
1124 ++cur.idx();
1125 cur.cell() = eq;
1126 ++cur.idx();
1127 cur.cell() = pipeThroughExtern(lang, extra, ar);
1128 // move to end of line
1129 cur.pos() = cur.lastpos();
1130 return;
1134 lyxerr << "use eqnarray" << endl;
1135 cur.idx() += 2 - cur.idx() % ncols();
1136 cur.pos() = 0;
1137 MathData ar = cur.cell();
1138 lyxerr << "use cell: " << ar << endl;
1139 // FIXME: temporarily disabled
1140 addRow(cur.row());
1141 ++cur.idx();
1142 ++cur.idx();
1143 cur.cell() = eq;
1144 ++cur.idx();
1145 cur.cell() = pipeThroughExtern(lang, extra, ar);
1146 cur.pos() = cur.lastpos();
1151 void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
1153 //lyxerr << "action: " << cmd.action << endl;
1154 switch (cmd.action) {
1156 case LFUN_FINISHED_BACKWARD:
1157 case LFUN_FINISHED_FORWARD:
1158 case LFUN_FINISHED_RIGHT:
1159 case LFUN_FINISHED_LEFT:
1160 //lyxerr << "action: " << cmd.action << endl;
1161 InsetMathGrid::doDispatch(cur, cmd);
1162 cur.undispatched();
1163 break;
1165 case LFUN_BREAK_PARAGRAPH:
1166 // just swallow this
1167 break;
1169 case LFUN_NEWLINE_INSERT:
1170 // some magic for the common case
1171 if (type_ == hullSimple || type_ == hullEquation) {
1172 cur.recordUndoInset();
1173 bool const align =
1174 cur.bv().buffer().params().use_amsmath == BufferParams::package_on;
1175 mutate(align ? hullAlign : hullEqnArray);
1176 cur.idx() = nrows() * ncols() - 1;
1177 cur.pos() = cur.lastpos();
1179 InsetMathGrid::doDispatch(cur, cmd);
1180 break;
1182 case LFUN_MATH_NUMBER_TOGGLE: {
1183 //lyxerr << "toggling all numbers" << endl;
1184 cur.recordUndoInset();
1185 bool old = numberedType();
1186 if (type_ == hullMultline)
1187 numbered(nrows() - 1, !old);
1188 else
1189 for (row_type row = 0; row < nrows(); ++row)
1190 numbered(row, !old);
1192 cur.message(old ? _("No number") : _("Number"));
1193 break;
1196 case LFUN_MATH_NUMBER_LINE_TOGGLE: {
1197 cur.recordUndoInset();
1198 row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
1199 bool old = numbered(r);
1200 cur.message(old ? _("No number") : _("Number"));
1201 numbered(r, !old);
1202 break;
1205 case LFUN_LABEL_INSERT: {
1206 cur.recordUndoInset();
1207 row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
1208 docstring old_label = label(r);
1209 docstring const default_label = from_ascii(
1210 (lyxrc.label_init_length >= 0) ? "eq:" : "");
1211 if (old_label.empty())
1212 old_label = default_label;
1214 InsetCommandParams p(LABEL_CODE);
1215 p["name"] = cmd.argument().empty() ? old_label : cmd.argument();
1216 string const data = InsetCommand::params2string("label", p);
1218 if (cmd.argument().empty())
1219 cur.bv().showDialog("label", data);
1220 else {
1221 FuncRequest fr(LFUN_INSET_INSERT, data);
1222 dispatch(cur, fr);
1224 break;
1227 case LFUN_LABEL_COPY_AS_REF: {
1228 row_type row;
1229 if (cmd.argument().empty() && &cur.inset() == this)
1230 // if there is no argument and we're inside math, we retrieve
1231 // the row number from the cursor position.
1232 row = (type_ == hullMultline) ? nrows() - 1 : cur.row();
1233 else {
1234 // if there is an argument, find the corresponding label, else
1235 // check whether there is at least one label.
1236 for (row = 0; row != nrows(); ++row)
1237 if (!nonum_[row] && label_[row]
1238 && (cmd.argument().empty() || label(row) == cmd.argument()))
1239 break;
1242 if (row == nrows())
1243 break;
1245 InsetCommandParams p(REF_CODE, "ref");
1246 p["reference"] = label(row);
1247 cap::clearSelection();
1248 cap::copyInset(cur, new InsetRef(buffer_, p), label(row));
1249 break;
1252 case LFUN_WORD_DELETE_FORWARD:
1253 case LFUN_CHAR_DELETE_FORWARD:
1254 if (col(cur.idx()) + 1 == ncols()
1255 && cur.pos() == cur.lastpos()
1256 && !cur.selection()) {
1257 if (!label(row(cur.idx())).empty()) {
1258 cur.recordUndoInset();
1259 label(row(cur.idx()), docstring());
1260 } else if (numbered(row(cur.idx()))) {
1261 cur.recordUndoInset();
1262 numbered(row(cur.idx()), false);
1263 } else {
1264 InsetMathGrid::doDispatch(cur, cmd);
1265 return;
1267 } else {
1268 InsetMathGrid::doDispatch(cur, cmd);
1269 return;
1271 break;
1273 case LFUN_INSET_INSERT: {
1274 //lyxerr << "arg: " << to_utf8(cmd.argument()) << endl;
1275 // FIXME: this should be cleaned up to use InsetLabel methods directly.
1276 string const name = cmd.getArg(0);
1277 if (name == "label") {
1278 InsetCommandParams p(LABEL_CODE);
1279 InsetCommand::string2params(name, to_utf8(cmd.argument()), p);
1280 docstring str = p["name"];
1281 cur.recordUndoInset();
1282 row_type const r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
1283 str = trim(str);
1284 if (!str.empty())
1285 numbered(r, true);
1286 docstring old = label(r);
1287 if (str != old) {
1288 if (label_[r])
1289 // The label will take care of the reference update.
1290 label(r, str);
1291 else {
1292 label(r, str);
1293 // Newly created inset so initialize it.
1294 label_[r]->initView();
1297 break;
1299 InsetMathGrid::doDispatch(cur, cmd);
1300 return;
1303 case LFUN_MATH_EXTERN:
1304 cur.recordUndoInset();
1305 doExtern(cur, cmd);
1306 break;
1308 case LFUN_MATH_MUTATE: {
1309 cur.recordUndoInset();
1310 row_type row = cur.row();
1311 col_type col = cur.col();
1312 mutate(hullType(cmd.argument()));
1313 cur.idx() = row * ncols() + col;
1314 if (cur.idx() > cur.lastidx()) {
1315 cur.idx() = cur.lastidx();
1316 cur.pos() = cur.lastpos();
1318 if (cur.pos() > cur.lastpos())
1319 cur.pos() = cur.lastpos();
1321 // FIXME: find some more clever handling of the selection,
1322 // i.e. preserve it.
1323 cur.clearSelection();
1324 //cur.dispatched(FINISHED);
1325 break;
1328 case LFUN_MATH_DISPLAY: {
1329 cur.recordUndoInset();
1330 mutate(type_ == hullSimple ? hullEquation : hullSimple);
1331 cur.idx() = 0;
1332 cur.pos() = cur.lastpos();
1333 //cur.dispatched(FINISHED);
1334 break;
1337 default:
1338 InsetMathGrid::doDispatch(cur, cmd);
1339 break;
1344 bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd,
1345 FuncStatus & status) const
1347 switch (cmd.action) {
1348 case LFUN_FINISHED_BACKWARD:
1349 case LFUN_FINISHED_FORWARD:
1350 case LFUN_FINISHED_RIGHT:
1351 case LFUN_FINISHED_LEFT:
1352 case LFUN_UP:
1353 case LFUN_DOWN:
1354 case LFUN_NEWLINE_INSERT:
1355 case LFUN_MATH_EXTERN:
1356 case LFUN_MATH_DISPLAY:
1357 // we handle these
1358 status.setEnabled(true);
1359 return true;
1361 case LFUN_MATH_MUTATE: {
1362 HullType ht = hullType(cmd.argument());
1363 status.setOnOff(type_ == ht);
1364 status.setEnabled(true);
1365 return true;
1368 case LFUN_MATH_NUMBER_TOGGLE:
1369 // FIXME: what is the right test, this or the one of
1370 // LABEL_INSERT?
1371 status.setEnabled(display());
1372 status.setOnOff(numberedType());
1373 return true;
1375 case LFUN_MATH_NUMBER_LINE_TOGGLE: {
1376 // FIXME: what is the right test, this or the one of
1377 // LABEL_INSERT?
1378 bool const enable = (type_ == hullMultline)
1379 ? (nrows() - 1 == cur.row())
1380 : display() != Inline && nrows() > 1;
1381 row_type const r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
1382 status.setEnabled(enable);
1383 status.setOnOff(enable && numbered(r));
1384 return true;
1387 case LFUN_LABEL_INSERT:
1388 status.setEnabled(type_ != hullSimple);
1389 return true;
1391 case LFUN_LABEL_COPY_AS_REF: {
1392 bool enabled = false;
1393 row_type row;
1394 if (cmd.argument().empty() && &cur.inset() == this) {
1395 // if there is no argument and we're inside math, we retrieve
1396 // the row number from the cursor position.
1397 row = (type_ == hullMultline) ? nrows() - 1 : cur.row();
1398 enabled = numberedType() && label_[row] && !nonum_[row];
1399 } else {
1400 // if there is an argument, find the corresponding label, else
1401 // check whether there is at least one label.
1402 for (row_type row = 0; row != nrows(); ++row) {
1403 if (!nonum_[row] && label_[row] &&
1404 (cmd.argument().empty() || label(row) == cmd.argument())) {
1405 enabled = true;
1406 break;
1410 status.setEnabled(enabled);
1411 return true;
1414 case LFUN_INSET_INSERT:
1415 if (cmd.getArg(0) == "label") {
1416 status.setEnabled(type_ != hullSimple);
1417 return true;
1419 return InsetMathGrid::getStatus(cur, cmd, status);
1421 case LFUN_TABULAR_FEATURE: {
1422 istringstream is(to_utf8(cmd.argument()));
1423 string s;
1424 is >> s;
1425 if (!rowChangeOK()
1426 && (s == "append-row"
1427 || s == "delete-row"
1428 || s == "copy-row")) {
1429 status.message(bformat(
1430 from_utf8(N_("Can't change number of rows in '%1$s'")),
1431 hullName(type_)));
1432 status.setEnabled(false);
1433 return true;
1435 if (!colChangeOK()
1436 && (s == "append-column"
1437 || s == "delete-column"
1438 || s == "copy-column")) {
1439 status.message(bformat(
1440 from_utf8(N_("Can't change number of columns in '%1$s'")),
1441 hullName(type_)));
1442 status.setEnabled(false);
1443 return true;
1445 if ((type_ == hullSimple
1446 || type_ == hullEquation
1447 || type_ == hullNone) &&
1448 (s == "add-hline-above" || s == "add-hline-below")) {
1449 status.message(bformat(
1450 from_utf8(N_("Can't add horizontal grid lines in '%1$s'")),
1451 hullName(type_)));
1452 status.setEnabled(false);
1453 return true;
1455 if (s == "add-vline-left" || s == "add-vline-right") {
1456 status.message(bformat(
1457 from_utf8(N_("Can't add vertical grid lines in '%1$s'")),
1458 hullName(type_)));
1459 status.setEnabled(false);
1460 return true;
1462 if (s == "valign-top" || s == "valign-middle"
1463 || s == "valign-bottom" || s == "align-left"
1464 || s == "align-center" || s == "align-right") {
1465 status.setEnabled(false);
1466 return true;
1468 return InsetMathGrid::getStatus(cur, cmd, status);
1471 default:
1472 return InsetMathGrid::getStatus(cur, cmd, status);
1475 // This cannot really happen, but inserted to shut-up gcc
1476 return InsetMathGrid::getStatus(cur, cmd, status);
1480 /////////////////////////////////////////////////////////////////////
1484 // simply scrap this function if you want
1485 void InsetMathHull::mutateToText()
1487 #if 0
1488 // translate to latex
1489 ostringstream os;
1490 latex(os, false, false);
1491 string str = os.str();
1493 // insert this text
1494 Text * lt = view_->cursor().innerText();
1495 string::const_iterator cit = str.begin();
1496 string::const_iterator end = str.end();
1497 for (; cit != end; ++cit)
1498 view_->getIntl()->getTransManager().TranslateAndInsert(*cit, lt);
1500 // remove ourselves
1501 //dispatch(LFUN_ESCAPE);
1502 #endif
1506 void InsetMathHull::handleFont(Cursor & cur, docstring const & arg,
1507 docstring const & font)
1509 // this whole function is a hack and won't work for incremental font
1510 // changes...
1511 cur.recordUndo();
1512 if (cur.inset().asInsetMath()->name() == font)
1513 cur.handleFont(to_utf8(font));
1514 else {
1515 cur.handleNest(createInsetMath(font, cur.buffer()));
1516 cur.insert(arg);
1521 void InsetMathHull::handleFont2(Cursor & cur, docstring const & arg)
1523 cur.recordUndo();
1524 Font font;
1525 bool b;
1526 font.fromString(to_utf8(arg), b);
1527 if (font.fontInfo().color() != Color_inherit) {
1528 MathAtom at = MathAtom(new InsetMathColor(buffer_, true, font.fontInfo().color()));
1529 cur.handleNest(at, 0);
1534 void InsetMathHull::edit(Cursor & cur, bool front, EntryDirection entry_from)
1536 cur.push(*this);
1537 bool enter_front = (entry_from == Inset::ENTRY_DIRECTION_LEFT ||
1538 (entry_from == Inset::ENTRY_DIRECTION_IGNORE && front));
1539 enter_front ? idxFirst(cur) : idxLast(cur);
1540 // The inset formula dimension is not necessarily the same as the
1541 // one of the instant preview image, so we have to indicate to the
1542 // BufferView that a metrics update is needed.
1543 cur.updateFlags(Update::Force);
1547 void InsetMathHull::revealCodes(Cursor & cur) const
1549 if (!cur.inMathed())
1550 return;
1551 odocstringstream os;
1552 cur.info(os);
1553 cur.message(os.str());
1555 // write something to the minibuffer
1556 // translate to latex
1557 cur.markInsert(bv);
1558 ostringstream os;
1559 write(os);
1560 string str = os.str();
1561 cur.markErase(bv);
1562 string::size_type pos = 0;
1563 string res;
1564 for (string::iterator it = str.begin(); it != str.end(); ++it) {
1565 if (*it == '\n')
1566 res += ' ';
1567 else if (*it == '\0') {
1568 res += " -X- ";
1569 pos = it - str.begin();
1571 else
1572 res += *it;
1574 if (pos > 30)
1575 res = res.substr(pos - 30);
1576 if (res.size() > 60)
1577 res = res.substr(0, 60);
1578 cur.message(res);
1583 /////////////////////////////////////////////////////////////////////
1586 #if 0
1587 bool InsetMathHull::searchForward(BufferView * bv, string const & str,
1588 bool, bool)
1590 // FIXME: completely broken
1591 static InsetMathHull * lastformula = 0;
1592 static CursorBase current = DocIterator(ibegin(nucleus()));
1593 static MathData ar;
1594 static string laststr;
1596 if (lastformula != this || laststr != str) {
1597 //lyxerr << "reset lastformula to " << this << endl;
1598 lastformula = this;
1599 laststr = str;
1600 current = ibegin(nucleus());
1601 ar.clear();
1602 mathed_parse_cell(ar, str, Parse::NORMAL, &buffer());
1603 } else {
1604 increment(current);
1606 //lyxerr << "searching '" << str << "' in " << this << ar << endl;
1608 for (DocIterator it = current; it != iend(nucleus()); increment(it)) {
1609 CursorSlice & top = it.back();
1610 MathData const & a = top.asInsetMath()->cell(top.idx_);
1611 if (a.matchpart(ar, top.pos_)) {
1612 bv->cursor().setSelection(it, ar.size());
1613 current = it;
1614 top.pos_ += ar.size();
1615 bv->update();
1616 return true;
1620 //lyxerr << "not found!" << endl;
1621 lastformula = 0;
1622 return false;
1624 #endif
1627 void InsetMathHull::write(ostream & os) const
1629 odocstringstream oss;
1630 WriteStream wi(oss, false, false, WriteStream::wsDefault);
1631 oss << "Formula ";
1632 write(wi);
1633 os << to_utf8(oss.str());
1637 void InsetMathHull::read(Lexer & lex)
1639 MathAtom at;
1640 mathed_parse_normal(buffer_, at, lex, Parse::TRACKMACRO);
1641 operator=(*at->asHullInset());
1645 bool InsetMathHull::readQuiet(Lexer & lex)
1647 MathAtom at;
1648 bool success = mathed_parse_normal(buffer_, at, lex, Parse::QUIET);
1649 if (success)
1650 operator=(*at->asHullInset());
1651 return success;
1655 int InsetMathHull::plaintext(odocstream & os, OutputParams const &) const
1657 if (0 && display()) {
1658 Dimension dim;
1659 TextMetricsInfo mi;
1660 metricsT(mi, dim);
1661 TextPainter tpain(dim.width(), dim.height());
1662 drawT(tpain, 0, dim.ascent());
1663 tpain.show(os, 3);
1664 // reset metrics cache to "real" values
1665 //metrics();
1666 return tpain.textheight();
1667 } else {
1668 odocstringstream oss;
1669 Encoding const * const enc = encodings.fromLyXName("utf8");
1670 WriteStream wi(oss, false, true, WriteStream::wsDefault, enc);
1671 // Fix Bug #6139
1672 if (type_ == hullRegexp)
1673 write(wi);
1674 else
1675 wi << cell(0);
1676 docstring const str = oss.str();
1677 os << str;
1678 return str.size();
1683 int InsetMathHull::docbook(odocstream & os, OutputParams const & runparams) const
1685 MathStream ms(os);
1686 int res = 0;
1687 docstring name;
1688 if (getType() == hullSimple)
1689 name = from_ascii("inlineequation");
1690 else
1691 name = from_ascii("informalequation");
1693 docstring bname = name;
1694 if (!label(0).empty())
1695 bname += " id='" + sgml::cleanID(buffer(), runparams, label(0)) + "'";
1697 ++ms.tab(); ms.cr(); ms.os() << '<' << bname << '>';
1699 odocstringstream ls;
1700 if (runparams.flavor == OutputParams::XML) {
1701 ms << MTag("alt role='tex' ");
1702 // Workaround for db2latex: db2latex always includes equations with
1703 // \ensuremath{} or \begin{display}\end{display}
1704 // so we strip LyX' math environment
1705 WriteStream wi(ls, false, false, WriteStream::wsDefault, runparams.encoding);
1706 InsetMathGrid::write(wi);
1707 ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&amp;"), "<", "&lt;"));
1708 ms << ETag("alt");
1709 ms << MTag("math");
1710 ms << ETag("alt");
1711 ms << MTag("math");
1712 InsetMathGrid::mathmlize(ms);
1713 ms << ETag("math");
1714 } else {
1715 ms << MTag("alt role='tex'");
1716 res = latex(ls, runparams);
1717 ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&amp;"), "<", "&lt;"));
1718 ms << ETag("alt");
1721 ms << from_ascii("<graphic fileref=\"eqn/");
1722 if (!label(0).empty())
1723 ms << sgml::cleanID(buffer(), runparams, label(0));
1724 else
1725 ms << sgml::uniqueID(from_ascii("anon"));
1727 if (runparams.flavor == OutputParams::XML)
1728 ms << from_ascii("\"/>");
1729 else
1730 ms << from_ascii("\">");
1732 ms.cr(); --ms.tab(); ms.os() << "</" << name << '>';
1734 return ms.line() + res;
1738 void InsetMathHull::tocString(odocstream & os) const
1740 plaintext(os, OutputParams(0));
1744 docstring InsetMathHull::contextMenu(BufferView const &, int, int) const
1746 return from_ascii("context-math");
1750 } // namespace lyx