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