]> git.lyx.org Git - lyx.git/blob - src/mathed/math_hullinset.C
c18072ee95b478768724854fec65a0dc7ae0de87
[lyx.git] / src / mathed / math_hullinset.C
1 /**
2  * \file math_hullinset.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "math_hullinset.h"
14 #include "math_mathmlstream.h"
15 #include "math_streamstr.h"
16 #include "math_cursor.h"
17 #include "math_support.h"
18 #include "math_extern.h"
19 #include "math_charinset.h"
20 #include "textpainter.h"
21 #include "BufferView.h"
22 #include "dispatchresult.h"
23 #include "debug.h"
24 #include "funcrequest.h"
25 #include "gettext.h"
26 #include "LaTeXFeatures.h"
27 #include "LColor.h"
28 #include "lyxrc.h"
29
30 #include "frontends/Alert.h"
31
32 #include "support/std_sstream.h"
33
34
35 using lyx::support::trim;
36
37 using std::endl;
38 using std::max;
39
40 using std::string;
41 using std::auto_ptr;
42 using std::istringstream;
43 using std::ostringstream;
44 using std::pair;
45
46
47 namespace {
48
49         int getCols(string const & type)
50         {
51                 if (type == "eqnarray")
52                         return 3;
53                 if (type == "align")
54                         return 2;
55                 if (type == "flalign")
56                         return 2;
57                 if (type == "alignat")
58                         return 2;
59                 if (type == "xalignat")
60                         return 2;
61                 if (type == "xxalignat")
62                         return 2;
63                 return 1;
64         }
65
66
67         // returns position of first relation operator in the array
68         // used for "intelligent splitting"
69         MathArray::size_type firstRelOp(MathArray const & ar)
70         {
71                 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
72                         if ((*it)->isRelOp())
73                                 return it - ar.begin();
74                 return ar.size();
75         }
76
77
78         char const * star(bool numbered)
79         {
80                 return numbered ? "" : "*";
81         }
82
83
84         int typecode(string const & s)
85         {
86                 if (s == "none")      return 0;
87                 if (s == "simple")    return 1;
88                 if (s == "equation")  return 2;
89                 if (s == "eqnarray")  return 3;
90                 if (s == "align")     return 4;
91                 if (s == "alignat")   return 5;
92                 if (s == "xalignat")  return 6;
93                 if (s == "xxalignat") return 7;
94                 if (s == "multline")  return 8;
95                 if (s == "gather")    return 9;
96                 if (s == "flalign")   return 10;
97                 lyxerr << "unknown hull type '" << s << "'" << endl;
98                 return 0;
99         }
100
101         bool smaller(string const & s, string const & t)
102         {
103                 return typecode(s) < typecode(t);
104         }
105
106
107 } // end anon namespace
108
109
110 MathHullInset::MathHullInset()
111         : MathGridInset(1, 1), type_("none"), nonum_(1), label_(1)
112 {
113         setDefaults();
114 }
115
116
117 MathHullInset::MathHullInset(string const & type)
118         : MathGridInset(getCols(type), 1), type_(type), nonum_(1), label_(1)
119 {
120         setDefaults();
121 }
122
123
124 auto_ptr<InsetBase> MathHullInset::clone() const
125 {
126         return auto_ptr<InsetBase>(new MathHullInset(*this));
127 }
128
129
130 MathInset::mode_type MathHullInset::currentMode() const
131 {
132         if (type_ == "none")
133                 return UNDECIDED_MODE;
134         // definitely math mode ...
135         return MATH_MODE;
136 }
137
138
139 bool MathHullInset::idxFirst(LCursor & cur) const
140 {
141         cur.idx() = 0;
142         cur.pos() = 0;
143         return true;
144 }
145
146
147 bool MathHullInset::idxLast(LCursor & cur) const
148 {
149         cur.idx() = nargs() - 1;
150         cur.pos() = cur.lastpos();
151         return true;
152 }
153
154
155 char MathHullInset::defaultColAlign(col_type col)
156 {
157         if (type_ == "eqnarray")
158                 return "rcl"[col];
159         if (typecode(type_) >= typecode("align"))
160                 return "rl"[col & 1];
161         return 'c';
162 }
163
164
165 int MathHullInset::defaultColSpace(col_type col)
166 {
167         if (type_ == "align" || type_ == "alignat")
168                 return 0;
169         if (type_ == "xalignat")
170                 return (col & 1) ? 20 : 0;
171         if (type_ == "xxalignat" || type_ == "flalign")
172                 return (col & 1) ? 40 : 0;
173         return 0;
174 }
175
176
177 char const * MathHullInset::standardFont() const
178 {
179         if (type_ == "none")
180                 return "lyxnochange";
181         return "mathnormal";
182 }
183
184
185 void MathHullInset::metrics(MetricsInfo & mi, Dimension & dim) const
186 {
187         FontSetChanger dummy1(mi.base, standardFont());
188         StyleChanger dummy2(mi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
189
190         // let the cells adjust themselves
191         MathGridInset::metrics(mi);
192
193         if (display()) {
194                 dim_.asc += 12;
195                 dim_.des += 12;
196         }
197
198         if (numberedType()) {
199                 FontSetChanger dummy(mi.base, "mathbf");
200                 int l = 0;
201                 for (row_type row = 0; row < nrows(); ++row)
202                         l = max(l, mathed_string_width(mi.base.font, nicelabel(row)));
203
204                 if (l)
205                         dim_.wid += 30 + l;
206         }
207
208         // make it at least as high as the current font
209         int asc = 0;
210         int des = 0;
211         math_font_max_dim(mi.base.font, asc, des);
212         dim_.asc = max(dim_.asc, asc);
213         dim_.des = max(dim_.des, des);
214
215         // for markers
216         metricsMarkers2();
217         dim = dim_;
218 }
219
220
221 void MathHullInset::draw(PainterInfo & pi, int x, int y) const
222 {
223         FontSetChanger dummy1(pi.base, standardFont());
224         StyleChanger dummy2(pi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
225         MathGridInset::draw(pi, x + 1, y);
226
227         if (numberedType()) {
228                 int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
229                 for (row_type row = 0; row < nrows(); ++row) {
230                         int const yy = y + rowinfo_[row].offset_;
231                         FontSetChanger dummy(pi.base, "mathrm");
232                         drawStr(pi, pi.base.font, xx, yy, nicelabel(row));
233                 }
234         }
235
236         drawMarkers2(pi, x, y);
237 }
238
239
240 void MathHullInset::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
241 {
242         if (display()) {
243                 MathGridInset::metricsT(mi, dim);
244         } else {
245                 ostringstream os;
246                 WriteStream wi(os, false, true);
247                 write(wi);
248                 dim.wid = os.str().size();
249                 dim.asc = 1;
250                 dim.des = 0;
251         }
252 }
253
254
255 void MathHullInset::drawT(TextPainter & pain, int x, int y) const
256 {
257         if (display()) {
258                 MathGridInset::drawT(pain, x, y);
259         } else {
260                 ostringstream os;
261                 WriteStream wi(os, false, true);
262                 write(wi);
263                 pain.draw(x, y, os.str().c_str());
264         }
265 }
266
267
268 string MathHullInset::label(row_type row) const
269 {
270         row_type n = nrows();
271         BOOST_ASSERT(row < n);
272         return label_[row];
273 }
274
275
276 void MathHullInset::label(row_type row, string const & label)
277 {
278         //lyxerr << "setting label '" << label << "' for row " << row << endl;
279         label_[row] = label;
280 }
281
282
283 void MathHullInset::numbered(row_type row, bool num)
284 {
285         nonum_[row] = !num;
286 }
287
288
289 bool MathHullInset::numbered(row_type row) const
290 {
291         return !nonum_[row];
292 }
293
294
295 bool MathHullInset::ams() const
296 {
297         return
298                 type_ == "align" ||
299                 type_ == "flalign" ||
300                 type_ == "multline" ||
301                 type_ == "gather" ||
302                 type_ == "alignat" ||
303                 type_ == "xalignat" ||
304                 type_ == "xxalignat";
305 }
306
307
308 bool MathHullInset::display() const
309 {
310         return type_ != "simple" && type_ != "none";
311 }
312
313
314 void MathHullInset::getLabelList(Buffer const &,
315                                  std::vector<string> & labels) const
316 {
317         for (row_type row = 0; row < nrows(); ++row)
318                 if (!label_[row].empty() && nonum_[row] != 1)
319                         labels.push_back(label_[row]);
320 }
321
322
323 bool MathHullInset::numberedType() const
324 {
325         if (type_ == "none")
326                 return false;
327         if (type_ == "simple")
328                 return false;
329         if (type_ == "xxalignat")
330                 return false;
331         for (row_type row = 0; row < nrows(); ++row)
332                 if (!nonum_[row])
333                         return true;
334         return false;
335 }
336
337
338 void MathHullInset::validate(LaTeXFeatures & features) const
339 {
340         if (ams())
341                 features.require("amsmath");
342
343
344         // Validation is necessary only if not using AMS math.
345         // To be safe, we will always run mathedvalidate.
346         //if (features.amsstyle)
347         //  return;
348
349         features.require("boldsymbol");
350         //features.binom      = true;
351
352         MathGridInset::validate(features);
353 }
354
355
356 void MathHullInset::header_write(WriteStream & os) const
357 {
358         bool n = numberedType();
359
360         if (type_ == "none")
361                 ;
362
363         else if (type_ == "simple") {
364                 os << '$';
365                 if (cell(0).empty())
366                         os << ' ';
367         }
368
369         else if (type_ == "equation") {
370                 if (n)
371                         os << "\\begin{equation" << star(n) << "}\n";
372                 else
373                         os << "\\[\n";
374         }
375
376         else if (type_ == "eqnarray" || type_ == "align" || type_ == "flalign"
377                  || type_ == "gather" || type_ == "multline")
378                         os << "\\begin{" << type_ << star(n) << "}\n";
379
380         else if (type_ == "alignat" || type_ == "xalignat")
381                 os << "\\begin{" << type_ << star(n) << '}'
382                   << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
383
384         else if (type_ == "xxalignat")
385                 os << "\\begin{" << type_ << '}'
386                   << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
387
388         else
389                 os << "\\begin{unknown" << star(n) << '}';
390 }
391
392
393 void MathHullInset::footer_write(WriteStream & os) const
394 {
395         bool n = numberedType();
396
397         if (type_ == "none")
398                 os << "\n";
399
400         else if (type_ == "simple")
401                 os << '$';
402
403         else if (type_ == "equation")
404                 if (n)
405                         os << "\\end{equation" << star(n) << "}\n";
406                 else
407                         os << "\\]\n";
408
409         else if (type_ == "eqnarray" || type_ == "align" || type_ == "flalign"
410                  || type_ == "alignat" || type_ == "xalignat"
411                  || type_ == "gather" || type_ == "multline")
412                 os << "\\end{" << type_ << star(n) << "}\n";
413
414         else if (type_ == "xxalignat")
415                 os << "\\end{" << type_ << "}\n";
416
417         else
418                 os << "\\end{unknown" << star(n) << '}';
419 }
420
421
422 bool MathHullInset::colChangeOK() const
423 {
424         return
425                 type_ == "align" || type_ == "flalign" ||type_ == "alignat" ||
426                 type_ == "xalignat" || type_ == "xxalignat";
427 }
428
429
430 void MathHullInset::addRow(row_type row)
431 {
432         nonum_.insert(nonum_.begin() + row + 1, !numberedType());
433         label_.insert(label_.begin() + row + 1, string());
434         MathGridInset::addRow(row);
435 }
436
437
438 void MathHullInset::swapRow(row_type row)
439 {
440         if (nrows() == 1)
441                 return;
442         if (row + 1 == nrows())
443                 --row;
444         std::swap(nonum_[row], nonum_[row + 1]);
445         std::swap(label_[row], label_[row + 1]);
446         MathGridInset::swapRow(row);
447 }
448
449
450 void MathHullInset::delRow(row_type row)
451 {
452         if (nrows() <= 1)
453                 return;
454         MathGridInset::delRow(row);
455         nonum_.erase(nonum_.begin() + row);
456         label_.erase(label_.begin() + row);
457 }
458
459
460 void MathHullInset::addCol(col_type col)
461 {
462         if (colChangeOK())
463                 MathGridInset::addCol(col);
464         else
465                 lyxerr << "Can't change number of columns in '" << type_ << "'" << endl;
466 }
467
468
469 void MathHullInset::delCol(col_type col)
470 {
471         if (colChangeOK())
472                 MathGridInset::delCol(col);
473         else
474                 lyxerr << "Can't change number of columns in '" << type_ << "'" << endl;
475 }
476
477
478 string MathHullInset::nicelabel(row_type row) const
479 {
480         if (nonum_[row])
481                 return string();
482         if (label_[row].empty())
483                 return string("(#)");
484         return '(' + label_[row] + ')';
485 }
486
487
488 void MathHullInset::glueall()
489 {
490         MathArray ar;
491         for (idx_type i = 0; i < nargs(); ++i)
492                 ar.append(cell(i));
493         *this = MathHullInset("simple");
494         cell(0) = ar;
495         setDefaults();
496 }
497
498
499 string const & MathHullInset::getType() const
500 {
501         return type_;
502 }
503
504
505 void MathHullInset::setType(string const & type)
506 {
507         type_ = type;
508         setDefaults();
509 }
510
511
512
513 void MathHullInset::mutate(string const & newtype)
514 {
515         lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl;
516
517         // we try to move along the chain
518         // none <-> simple <-> equation <-> eqnarray
519
520         if (newtype == "dump") {
521                 dump();
522         }
523
524         else if (newtype == type_) {
525                 // done
526         }
527
528         else if (type_ == "none") {
529                 setType("simple");
530                 numbered(0, false);
531                 mutate(newtype);
532         }
533
534         else if (type_ == "simple") {
535                 if (newtype == "none") {
536                         setType("none");
537                 } else {
538                         setType("equation");
539                         numbered(0, false);
540                         mutate(newtype);
541                 }
542         }
543
544         else if (type_ == "equation") {
545                 if (smaller(newtype, type_)) {
546                         setType("simple");
547                         mutate(newtype);
548                 } else if (newtype == "eqnarray") {
549                         MathGridInset::addCol(1);
550                         MathGridInset::addCol(1);
551
552                         // split it "nicely" on the firest relop
553                         pos_type pos = firstRelOp(cell(0));
554                         cell(1) = MathArray(cell(0).begin() + pos, cell(0).end());
555                         cell(0).erase(pos, cell(0).size());
556
557                         if (cell(1).size()) {
558                                 cell(2) = MathArray(cell(1).begin() + 1, cell(1).end());
559                                 cell(1).erase(1, cell(1).size());
560                         }
561                         setType("eqnarray");
562                         mutate(newtype);
563                 } else if (newtype == "multline" || newtype == "gather") {
564                         setType(newtype);
565                         numbered(0, false);
566                 } else {
567                         MathGridInset::addCol(1);
568                         // split it "nicely"
569                         pos_type pos = firstRelOp(cell(0));
570                         cell(1) = cell(0);
571                         cell(0).erase(pos, cell(0).size());
572                         cell(1).erase(0, pos);
573                         setType("align");
574                         mutate(newtype);
575                 }
576         }
577
578         else if (type_ == "eqnarray") {
579                 if (smaller(newtype, type_)) {
580                         // set correct (no)numbering
581                         bool allnonum = true;
582                         for (row_type row = 0; row < nrows(); ++row)
583                                 if (!nonum_[row])
584                                         allnonum = false;
585
586                         // set first non-empty label
587                         string label;
588                         for (row_type row = 0; row < nrows(); ++row) {
589                                 if (!label_[row].empty()) {
590                                         label = label_[row];
591                                         break;
592                                 }
593                         }
594
595                         glueall();
596                         nonum_[0] = allnonum;
597                         label_[0] = label;
598                         mutate(newtype);
599                 } else { // align & Co.
600                         for (row_type row = 0; row < nrows(); ++row) {
601                                 idx_type c = 3 * row + 1;
602                                 cell(c).append(cell(c + 1));
603                         }
604                         MathGridInset::delCol(2);
605                         setType("align");
606                         mutate(newtype);
607                 }
608         }
609
610         else if (type_ == "align") {
611                 if (smaller(newtype, type_)) {
612                         MathGridInset::addCol(1);
613                         setType("eqnarray");
614                         mutate(newtype);
615                 } else {
616                         setType(newtype);
617                 }
618         }
619
620         else if (type_ == "multline") {
621                 if (newtype == "gather" || newtype == "align" ||
622                     newtype == "xalignat" || newtype == "xxalignat" || newtype == "flalign")
623                         setType(newtype);
624                 else if (newtype == "eqnarray") {
625                         MathGridInset::addCol(1);
626                         MathGridInset::addCol(1);
627                         setType("eqnarray");
628                 } else {
629                         lyxerr << "mutation from '" << type_
630                                 << "' to '" << newtype << "' not implemented" << endl;
631                 }
632         }
633
634         else if (type_ == "gather") {
635                 if (newtype == "multline") {
636                         setType("multline");
637                 } else {
638                         lyxerr << "mutation from '" << type_
639                                 << "' to '" << newtype << "' not implemented" << endl;
640                 }
641         }
642
643         else {
644                 lyxerr << "mutation from '" << type_
645                                          << "' to '" << newtype << "' not implemented" << endl;
646         }
647 }
648
649
650 string MathHullInset::eolString(row_type row, bool fragile) const
651 {
652         string res;
653         if (numberedType()) {
654                 if (!label_[row].empty() && !nonum_[row])
655                         res += "\\label{" + label_[row] + '}';
656                 if (nonum_[row] && (type_ != "multline"))
657                         res += "\\nonumber ";
658         }
659         return res + MathGridInset::eolString(row, fragile);
660 }
661
662
663 void MathHullInset::write(WriteStream & os) const
664 {
665         header_write(os);
666         MathGridInset::write(os);
667         footer_write(os);
668 }
669
670
671 void MathHullInset::normalize(NormalStream & os) const
672 {
673         os << "[formula " << type_ << ' ';
674         MathGridInset::normalize(os);
675         os << "] ";
676 }
677
678
679 void MathHullInset::mathmlize(MathMLStream & os) const
680 {
681         MathGridInset::mathmlize(os);
682 }
683
684
685 void MathHullInset::infoize(std::ostream & os) const
686 {
687         os << "Type: " << type_;
688 }
689
690
691 void MathHullInset::check() const
692 {
693         BOOST_ASSERT(nonum_.size() == nrows());
694         BOOST_ASSERT(label_.size() == nrows());
695 }
696
697
698 void MathHullInset::doExtern(LCursor & cur, FuncRequest const & func)
699 {
700         string lang;
701         string extra;
702         istringstream iss(func.argument.c_str());
703         iss >> lang >> extra;
704         if (extra.empty())
705                 extra = "noextra";
706
707 #ifdef WITH_WARNINGS
708 #warning temporarily disabled
709         //if (selection()) {
710         //      MathArray ar;
711         //      selGet(ar);
712         //      lyxerr << "use selection: " << ar << endl;
713         //      insert(pipeThroughExtern(lang, extra, ar));
714         //      return;
715         //}
716 #endif
717
718         MathArray eq;
719         eq.push_back(MathAtom(new MathCharInset('=')));
720
721         // go to first item in line
722         cur.idx() -= cur.idx() % ncols();
723         cur.pos() = 0;
724
725         if (getType() == "simple") {
726                 size_type pos = cur.cell().find_last(eq);
727                 MathArray ar;
728                 if (mathcursor && mathcursor->selection()) {
729                         asArray(mathcursor->grabAndEraseSelection(cur), ar);
730                 } else if (pos == cur.cell().size()) {
731                         ar = cur.cell();
732                         lyxerr << "use whole cell: " << ar << endl;
733                 } else {
734                         ar = MathArray(cur.cell().begin() + pos + 1, cur.cell().end());
735                         lyxerr << "use partial cell form pos: " << pos << endl;
736                 }
737                 cur.cell().append(eq);
738                 cur.cell().append(pipeThroughExtern(lang, extra, ar));
739                 cur.pos() = cur.lastpos();
740                 return;
741         }
742
743         if (getType() == "equation") {
744                 lyxerr << "use equation inset" << endl;
745                 mutate("eqnarray");
746                 MathArray & ar = cur.cell();
747                 lyxerr << "use cell: " << ar << endl;
748                 ++cur.idx();
749                 cur.cell() = eq;
750                 ++cur.idx();
751                 cur.cell() = pipeThroughExtern(lang, extra, ar);
752                 // move to end of line
753                 cur.pos() = cur.lastpos();
754                 return;
755         }
756
757         {
758                 lyxerr << "use eqnarray" << endl;
759                 cur.idx() += 2 - cur.idx() % ncols();
760                 cur.pos() = 0;
761                 MathArray ar = cur.cell();
762                 lyxerr << "use cell: " << ar << endl;
763 #ifdef WITH_WARNINGS
764 #warning temporarily disabled
765 #endif
766                 addRow(cur.row());
767                 ++cur.idx();
768                 ++cur.idx();
769                 cur.cell() = eq;
770                 ++cur.idx();
771                 cur.cell() = pipeThroughExtern(lang, extra, ar);
772                 cur.pos() = cur.lastpos();
773         }
774 }
775
776
777 DispatchResult
778 MathHullInset::priv_dispatch(BufferView & bv, FuncRequest const & cmd)
779 {
780         CursorSlice & cur = cursorTip(bv);
781         switch (cmd.action) {
782
783                 case LFUN_BREAKLINE:
784                         if (type_ == "simple" || type_ == "equation") {
785                                 mutate("eqnarray");
786                                 cur.idx() = 1;
787                                 cur.pos() = 0;
788                                 return DispatchResult(true, FINISHED);
789                         }
790                         return MathGridInset::priv_dispatch(bv, cmd);
791
792                 case LFUN_MATH_NUMBER:
793                         //lyxerr << "toggling all numbers" << endl;
794                         if (display()) {
795                                 //recordUndo(bv, Undo::INSERT);
796                                 bool old = numberedType();
797                                 if (type_ == "multline")
798                                         numbered(nrows() - 1, !old);
799                                 else
800                                         for (row_type row = 0; row < nrows(); ++row)
801                                                 numbered(row, !old);
802                                 //bv->owner()->message(old ? _("No number") : _("Number"));
803                         }
804                         return DispatchResult(true, true);
805
806                 case LFUN_MATH_NONUMBER:
807                         if (display()) {
808                                 row_type r = (type_ == "multline") ? nrows() - 1 : cur.row();
809                                 //recordUndo(bv, Undo::INSERT);
810                                 bool old = numbered(r);
811                                 //bv->owner()->message(old ? _("No number") : _("Number"));
812                                 numbered(r, !old);
813                         }
814                         return DispatchResult(true, true);
815
816                 case LFUN_INSERT_LABEL: {
817                         row_type r = (type_ == "multline") ? nrows() - 1 : cur.row();
818                         string old_label = label(r);
819                         string new_label = cmd.argument;
820
821                         if (new_label.empty()) {
822                                 string const default_label =
823                                         (lyxrc.label_init_length >= 0) ? "eq:" : "";
824                                 pair<bool, string> const res = old_label.empty()
825                                         ? Alert::askForText(_("Enter new label to insert:"), default_label)
826                                         : Alert::askForText(_("Enter label:"), old_label);
827                                 if (!res.first)
828                                         return DispatchResult(false);
829                                 new_label = trim(res.second);
830                         }
831
832                         //if (new_label == old_label)
833                         //      break;  // Nothing to do
834
835                         if (!new_label.empty())
836                                 numbered(r, true);
837                         label(r, new_label);
838                         return DispatchResult(true, true);
839                 }
840
841                 case LFUN_MATH_EXTERN:
842                         doExtern(bv.fullCursor(), cmd);
843                         return DispatchResult(true, FINISHED);
844
845                 case LFUN_MATH_MUTATE: {
846                         lyxerr << "Hull: MUTATE: " << cmd.argument << endl;
847                         row_type r = cur.row();
848                         col_type c = cur.col();
849                         mutate(cmd.argument);
850                         cur.idx() = r * ncols() + c;
851                         if (cur.idx() >= nargs())
852                                 cur.idx() = nargs() - 1;
853                         if (cur.pos() > cur.lastpos())
854                                 cur.pos() = cur.lastpos();
855                         return DispatchResult(true, FINISHED);
856                 }
857
858                 case LFUN_MATH_DISPLAY: {
859                         mutate(type_ == "simple" ? "equation" : "simple");
860                         cur.idx() = 0;
861                         cur.pos() = cur.lastpos();
862                         return DispatchResult(true, FINISHED);
863                 }
864
865                 default:
866                         return MathGridInset::priv_dispatch(bv, cmd);
867         }
868 }
869
870
871 string MathHullInset::fileInsetLabel() const
872 {
873         return "Formula";
874 }