]> git.lyx.org Git - lyx.git/blob - src/mathed/InsetMathGrid.cpp
e83eaeb9a7f75e499a69092740c1b64304836d8f
[lyx.git] / src / mathed / InsetMathGrid.cpp
1 /**
2  * \file InsetMathGrid.cpp
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 "InsetMathGrid.h"
14
15 #include "MathData.h"
16 #include "MathParser.h"
17 #include "MathStream.h"
18 #include "MetricsInfo.h"
19
20 #include "BufferView.h"
21 #include "CutAndPaste.h"
22 #include "FuncStatus.h"
23 #include "Cursor.h"
24 #include "support/debug.h"
25 #include "FuncRequest.h"
26 #include "support/gettext.h"
27
28 #include "frontends/Clipboard.h"
29 #include "frontends/Painter.h"
30
31 #include "support/lstrings.h"
32 #include "support/docstream.h"
33
34 #include <sstream>
35
36 using namespace std;
37
38 namespace lyx {
39
40 using support::bformat;
41
42 namespace {
43
44 docstring verboseHLine(int n)
45 {
46         docstring res;
47         for (int i = 0; i < n; ++i)
48                 res += "\\hline";
49         if (n)
50                 res += ' ';
51         return res;
52 }
53
54
55 int extractInt(istream & is)
56 {
57         int num = 1;
58         is >> num;
59         return (num == 0) ? 1 : num;
60 }
61
62 }
63
64
65 //////////////////////////////////////////////////////////////
66
67
68 InsetMathGrid::CellInfo::CellInfo()
69         : dummy_(false)
70 {}
71
72
73
74
75 //////////////////////////////////////////////////////////////
76
77
78 InsetMathGrid::RowInfo::RowInfo()
79         : lines_(0), skip_(0), allow_newpage_(true)
80 {}
81
82
83
84 int InsetMathGrid::RowInfo::skipPixels() const
85 {
86         return crskip_.inBP();
87 }
88
89
90
91 //////////////////////////////////////////////////////////////
92
93
94 InsetMathGrid::ColInfo::ColInfo()
95         : align_('c'), lines_(0)
96 {}
97
98
99 //////////////////////////////////////////////////////////////
100
101
102 InsetMathGrid::InsetMathGrid(char v, docstring const & h)
103         : InsetMathNest(guessColumns(h)),
104           rowinfo_(2),
105           colinfo_(guessColumns(h) + 1),
106           cellinfo_(1 * guessColumns(h))
107 {
108         setDefaults();
109         valign(v);
110         halign(h);
111         //lyxerr << "created grid with " << ncols() << " columns" << endl;
112 }
113
114
115 InsetMathGrid::InsetMathGrid()
116         : InsetMathNest(1),
117           rowinfo_(1 + 1),
118                 colinfo_(1 + 1),
119                 cellinfo_(1),
120                 v_align_('c')
121 {
122         setDefaults();
123 }
124
125
126 InsetMathGrid::InsetMathGrid(col_type m, row_type n)
127         : InsetMathNest(m * n),
128           rowinfo_(n + 1),
129                 colinfo_(m + 1),
130                 cellinfo_(m * n),
131                 v_align_('c')
132 {
133         setDefaults();
134 }
135
136
137 InsetMathGrid::InsetMathGrid(col_type m, row_type n, char v, docstring const & h)
138         : InsetMathNest(m * n),
139           rowinfo_(n + 1),
140           colinfo_(m + 1),
141                 cellinfo_(m * n),
142                 v_align_(v)
143 {
144         setDefaults();
145         valign(v);
146         halign(h);
147 }
148
149
150 Inset * InsetMathGrid::clone() const
151 {
152         return new InsetMathGrid(*this);
153 }
154
155
156 InsetMath::idx_type InsetMathGrid::index(row_type row, col_type col) const
157 {
158         return col + ncols() * row;
159 }
160
161
162 void InsetMathGrid::setDefaults()
163 {
164         if (ncols() <= 0)
165                 lyxerr << "positive number of columns expected" << endl;
166         //if (nrows() <= 0)
167         //      lyxerr << "positive number of rows expected" << endl;
168         for (col_type col = 0; col < ncols(); ++col) {
169                 colinfo_[col].align_ = defaultColAlign(col);
170                 colinfo_[col].skip_  = defaultColSpace(col);
171                 colinfo_[col].special_.clear();
172         }
173 }
174
175
176 void InsetMathGrid::halign(docstring const & hh)
177 {
178         col_type col = 0;
179         for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it) {
180                 char_type c = *it;
181                 if (c == '|') {
182                         colinfo_[col].lines_++;
183                 } else if ((c == 'p' || c == 'm' || c == 'b'||
184                             c == '!' || c == '@' || c == '>' || c == '<') &&
185                            it + 1 != hh.end() && *(it + 1) == '{') {
186                         // @{decl.} and p{width} are standard LaTeX, the
187                         // others are extensions by array.sty
188                         bool const newcolumn = c == 'p' || c == 'm' || c == 'b';
189                         if (newcolumn) {
190                                 // this declares a new column
191                                 if (col >= ncols())
192                                         // Only intercolumn stuff is allowed
193                                         // in the last dummy column
194                                         break;
195                                 colinfo_[col].align_ = 'l';
196                         } else {
197                                 // this is intercolumn stuff
198                                 if (colinfo_[col].special_.empty())
199                                         // Overtake possible lines
200                                         colinfo_[col].special_ = docstring(colinfo_[col].lines_, '|');
201                         }
202                         int brace_open = 0;
203                         int brace_close = 0;
204                         while (it != hh.end()) {
205                                 c = *it;
206                                 colinfo_[col].special_ += c;
207                                 if (c == '{')
208                                         ++brace_open;
209                                 else if (c == '}')
210                                         ++brace_close;
211                                 ++it;
212                                 if (brace_open > 0 && brace_open == brace_close)
213                                         break;
214                         }
215                         --it;
216                         if (newcolumn) {
217                                 colinfo_[col].lines_ = count(
218                                         colinfo_[col].special_.begin(),
219                                         colinfo_[col].special_.end(), '|');
220                                 LYXERR(Debug::MATHED, "special column separator: `"
221                                         << to_utf8(colinfo_[col].special_) << '\'');
222                                 ++col;
223                                 colinfo_[col].lines_ = 0;
224                                 colinfo_[col].special_.clear();
225                         }
226                 } else if (col >= ncols()) {
227                         // Only intercolumn stuff is allowed in the last
228                         // dummy column
229                         break;
230                 } else if (c == 'c' || c == 'l' || c == 'r') {
231                         colinfo_[col].align_ = static_cast<char>(c);
232                         if (!colinfo_[col].special_.empty()) {
233                                 colinfo_[col].special_ += c;
234                                 colinfo_[col].lines_ = count(
235                                                 colinfo_[col].special_.begin(),
236                                                 colinfo_[col].special_.end(), '|');
237                                 LYXERR(Debug::MATHED, "special column separator: `"
238                                         << to_utf8(colinfo_[col].special_) << '\'');
239                         }
240                         ++col;
241                         colinfo_[col].lines_ = 0;
242                         colinfo_[col].special_.clear();
243                 } else {
244                         lyxerr << "unknown column separator: '" << c << "'" << endl;
245                 }
246         }
247
248 /*
249         col_type n = hh.size();
250         if (n > ncols())
251                 n = ncols();
252         for (col_type col = 0; col < n; ++col)
253                 colinfo_[col].align_ = hh[col];
254 */
255 }
256
257
258 InsetMathGrid::col_type InsetMathGrid::guessColumns(docstring const & hh) const
259 {
260         col_type col = 0;
261         for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it)
262                 if (*it == 'c' || *it == 'l' || *it == 'r'||
263                     *it == 'p' || *it == 'm' || *it == 'b')
264                         ++col;
265         // let's have at least one column, even if we did not recognize its
266         // alignment
267         if (col == 0)
268                 col = 1;
269         return col;
270 }
271
272
273 void InsetMathGrid::halign(char h, col_type col)
274 {
275         colinfo_[col].align_ = h;
276         if (!colinfo_[col].special_.empty()) {
277                 char_type & c = colinfo_[col].special_[colinfo_[col].special_.size() - 1];
278                 if (c == 'l' || c == 'c' || c == 'r')
279                         c = h;
280         }
281         // FIXME: Change alignment of p, m and b columns, too
282 }
283
284
285 char InsetMathGrid::halign(col_type col) const
286 {
287         return colinfo_[col].align_;
288 }
289
290
291 docstring InsetMathGrid::halign() const
292 {
293         docstring res;
294         for (col_type col = 0; col < ncols(); ++col) {
295                 if (colinfo_[col].special_.empty()) {
296                         res += docstring(colinfo_[col].lines_, '|');
297                         res += colinfo_[col].align_;
298                 } else
299                         res += colinfo_[col].special_;
300         }
301         if (colinfo_[ncols()].special_.empty())
302                 return res + docstring(colinfo_[ncols()].lines_, '|');
303         return res + colinfo_[ncols()].special_;
304 }
305
306
307 void InsetMathGrid::valign(char c)
308 {
309         v_align_ = c;
310 }
311
312
313 char InsetMathGrid::valign() const
314 {
315         return v_align_;
316 }
317
318
319 InsetMathGrid::col_type InsetMathGrid::ncols() const
320 {
321         return colinfo_.size() - 1;
322 }
323
324
325 InsetMathGrid::row_type InsetMathGrid::nrows() const
326 {
327         return rowinfo_.size() - 1;
328 }
329
330
331 InsetMathGrid::col_type InsetMathGrid::col(idx_type idx) const
332 {
333         return idx % ncols();
334 }
335
336
337 InsetMathGrid::row_type InsetMathGrid::row(idx_type idx) const
338 {
339         return idx / ncols();
340 }
341
342
343 void InsetMathGrid::vcrskip(Length const & crskip, row_type row)
344 {
345         rowinfo_[row].crskip_ = crskip;
346 }
347
348
349 Length InsetMathGrid::vcrskip(row_type row) const
350 {
351         return rowinfo_[row].crskip_;
352 }
353
354
355 void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const
356 {
357         // let the cells adjust themselves
358         InsetMathNest::metrics(mi);
359
360         BufferView & bv = *mi.base.bv;
361
362         // compute absolute sizes of vertical structure
363         for (row_type row = 0; row < nrows(); ++row) {
364                 int asc  = 0;
365                 int desc = 0;
366                 for (col_type col = 0; col < ncols(); ++col) {
367                         Dimension const & dimc = cell(index(row, col)).dimension(bv);
368                         asc  = max(asc,  dimc.asc);
369                         desc = max(desc, dimc.des);
370                 }
371                 rowinfo_[row].ascent_  = asc;
372                 rowinfo_[row].descent_ = desc;
373         }
374         rowinfo_[0].ascent_       += hlinesep() * rowinfo_[0].lines_;
375         rowinfo_[nrows()].ascent_  = 0;
376         rowinfo_[nrows()].descent_ = 0;
377
378         // compute vertical offsets
379         rowinfo_[0].offset_ = 0;
380         for (row_type row = 1; row <= nrows(); ++row) {
381                 rowinfo_[row].offset_  =
382                         rowinfo_[row - 1].offset_  +
383                         rowinfo_[row - 1].descent_ +
384                         rowinfo_[row - 1].skipPixels() +
385                         rowsep() +
386                         rowinfo_[row].lines_ * hlinesep() +
387                         rowinfo_[row].ascent_;
388         }
389
390         // adjust vertical offset
391         int h = 0;
392         switch (v_align_) {
393                 case 't':
394                         h = 0;
395                         break;
396                 case 'b':
397                         h = rowinfo_[nrows() - 1].offset_;
398                         break;
399                 default:
400                         h = rowinfo_[nrows() - 1].offset_ / 2;
401         }
402         for (row_type row = 0; row <= nrows(); ++row)
403                 rowinfo_[row].offset_ -= h;
404
405
406         // compute absolute sizes of horizontal structure
407         for (col_type col = 0; col < ncols(); ++col) {
408                 int wid = 0;
409                 for (row_type row = 0; row < nrows(); ++row)
410                         wid = max(wid, cell(index(row, col)).dimension(bv).wid);
411                 colinfo_[col].width_ = wid;
412         }
413         colinfo_[ncols()].width_  = 0;
414
415         // compute horizontal offsets
416         colinfo_[0].offset_ = border();
417         for (col_type col = 1; col <= ncols(); ++col) {
418                 colinfo_[col].offset_ =
419                         colinfo_[col - 1].offset_ +
420                         colinfo_[col - 1].width_ +
421                         colinfo_[col - 1].skip_ +
422                         colsep() +
423                         colinfo_[col].lines_ * vlinesep();
424         }
425
426
427         dim.wid   =   colinfo_[ncols() - 1].offset_
428                        + colinfo_[ncols() - 1].width_
429                  + vlinesep() * colinfo_[ncols()].lines_
430                        + border();
431
432         dim.asc  = - rowinfo_[0].offset_
433                        + rowinfo_[0].ascent_
434                  + hlinesep() * rowinfo_[0].lines_
435                        + border();
436
437         dim.des =   rowinfo_[nrows() - 1].offset_
438                        + rowinfo_[nrows() - 1].descent_
439                  + hlinesep() * rowinfo_[nrows()].lines_
440                        + border();
441
442
443 /*
444         // Increase ws_[i] for 'R' columns (except the first one)
445         for (int i = 1; i < nc_; ++i)
446                 if (align_[i] == 'R')
447                         ws_[i] += 10 * df_width;
448         // Increase ws_[i] for 'C' column
449         if (align_[0] == 'C')
450                 if (ws_[0] < 7 * workwidth / 8)
451                         ws_[0] = 7 * workwidth / 8;
452
453         // Adjust local tabs
454         width = colsep();
455         for (cxrow = row_.begin(); cxrow; ++cxrow) {
456                 int rg = COLSEP;
457                 int lf = 0;
458                 for (int i = 0; i < nc_; ++i) {
459                         bool isvoid = false;
460                         if (cxrow->getTab(i) <= 0) {
461                                 cxrow->setTab(i, df_width);
462                                 isvoid = true;
463                         }
464                         switch (align_[i]) {
465                         case 'l':
466                                 lf = 0;
467                                 break;
468                         case 'c':
469                                 lf = (ws_[i] - cxrow->getTab(i))/2;
470                                 break;
471                         case 'r':
472                         case 'R':
473                                 lf = ws_[i] - cxrow->getTab(i);
474                                 break;
475                         case 'C':
476                                 if (cxrow == row_.begin())
477                                         lf = 0;
478                                 else if (cxrow.is_last())
479                                         lf = ws_[i] - cxrow->getTab(i);
480                                 else
481                                         lf = (ws_[i] - cxrow->getTab(i))/2;
482                                 break;
483                         }
484                         int const ww = (isvoid) ? lf : lf + cxrow->getTab(i);
485                         cxrow->setTab(i, lf + rg);
486                         rg = ws_[i] - ww + colsep();
487                         if (cxrow == row_.begin())
488                                 width += ws_[i] + colsep();
489                 }
490                 cxrow->setBaseline(cxrow->getBaseline() - ascent);
491         }
492 */
493         metricsMarkers2(dim);
494         // Cache the inset dimension. 
495         setDimCache(mi, dim);
496 }
497
498
499 void InsetMathGrid::draw(PainterInfo & pi, int x, int y) const
500 {
501         drawWithMargin(pi, x, y, 0, 0);
502 }
503
504
505 void InsetMathGrid::drawWithMargin(PainterInfo & pi, int x, int y,
506         int lmargin, int rmargin) const
507 {
508         Dimension const dim = dimension(*pi.base.bv);
509         BufferView const & bv = *pi.base.bv;
510
511         for (idx_type idx = 0; idx < nargs(); ++idx)
512                 cell(idx).draw(pi, x + lmargin + cellXOffset(bv, idx),
513                         y + cellYOffset(idx));
514
515         for (row_type row = 0; row <= nrows(); ++row)
516                 for (unsigned int i = 0; i < rowinfo_[row].lines_; ++i) {
517                         int yy = y + rowinfo_[row].offset_ - rowinfo_[row].ascent_
518                                 - i * hlinesep() - hlinesep()/2 - rowsep()/2;
519                         pi.pain.line(x + lmargin + 1, yy,
520                                      x + dim.width() - rmargin - 1, yy,
521                                      Color_foreground);
522                 }
523
524         for (col_type col = 0; col <= ncols(); ++col)
525                 for (unsigned int i = 0; i < colinfo_[col].lines_; ++i) {
526                         int xx = x + lmargin + colinfo_[col].offset_
527                                 - i * vlinesep() - vlinesep()/2 - colsep()/2;
528                         pi.pain.line(xx, y - dim.ascent() + 1,
529                                      xx, y + dim.descent() - 1,
530                                      Color_foreground);
531                 }
532         drawMarkers2(pi, x, y);
533 }
534
535
536 void InsetMathGrid::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
537 {
538         // let the cells adjust themselves
539         //InsetMathNest::metrics(mi);
540         for (idx_type i = 0; i < nargs(); ++i)
541                 cell(i).metricsT(mi, dim);
542
543         // compute absolute sizes of vertical structure
544         for (row_type row = 0; row < nrows(); ++row) {
545                 int asc  = 0;
546                 int desc = 0;
547                 for (col_type col = 0; col < ncols(); ++col) {
548                         //MathData const & c = cell(index(row, col));
549                         // FIXME: BROKEN!
550                         Dimension dimc;
551                         asc  = max(asc,  dimc.ascent());
552                         desc = max(desc, dimc.descent());
553                 }
554                 rowinfo_[row].ascent_  = asc;
555                 rowinfo_[row].descent_ = desc;
556         }
557         //rowinfo_[0].ascent_       += hlinesep() * rowinfo_[0].lines_;
558         rowinfo_[nrows()].ascent_  = 0;
559         rowinfo_[nrows()].descent_ = 0;
560
561         // compute vertical offsets
562         rowinfo_[0].offset_ = 0;
563         for (row_type row = 1; row <= nrows(); ++row) {
564                 rowinfo_[row].offset_  =
565                         rowinfo_[row - 1].offset_  +
566                         rowinfo_[row - 1].descent_ +
567                         //rowinfo_[row - 1].skipPixels() +
568                         1 + //rowsep() +
569                         //rowinfo_[row].lines_ * hlinesep() +
570                         rowinfo_[row].ascent_;
571         }
572
573         // adjust vertical offset
574         int h = 0;
575         switch (v_align_) {
576                 case 't':
577                         h = 0;
578                         break;
579                 case 'b':
580                         h = rowinfo_[nrows() - 1].offset_;
581                         break;
582                 default:
583                         h = rowinfo_[nrows() - 1].offset_ / 2;
584         }
585         for (row_type row = 0; row <= nrows(); ++row)
586                 rowinfo_[row].offset_ -= h;
587
588
589         // compute absolute sizes of horizontal structure
590         for (col_type col = 0; col < ncols(); ++col) {
591                 int wid = 0;
592                 for (row_type row = 0; row < nrows(); ++row) {
593                         // FIXME: BROKEN!
594                         //wid = max(wid, cell(index(row, col)).width());
595                 }
596                 colinfo_[col].width_ = wid;
597         }
598         colinfo_[ncols()].width_  = 0;
599
600         // compute horizontal offsets
601         colinfo_[0].offset_ = border();
602         for (col_type col = 1; col <= ncols(); ++col) {
603                 colinfo_[col].offset_ =
604                         colinfo_[col - 1].offset_ +
605                         colinfo_[col - 1].width_ +
606                         colinfo_[col - 1].skip_ +
607                         1 ; //colsep() +
608                         //colinfo_[col].lines_ * vlinesep();
609         }
610
611
612         dim.wid  =  colinfo_[ncols() - 1].offset_
613                        + colinfo_[ncols() - 1].width_
614                  //+ vlinesep() * colinfo_[ncols()].lines_
615                        + 2;
616
617         dim.asc  = -rowinfo_[0].offset_
618                        + rowinfo_[0].ascent_
619                  //+ hlinesep() * rowinfo_[0].lines_
620                        + 1;
621
622         dim.des  =  rowinfo_[nrows() - 1].offset_
623                        + rowinfo_[nrows() - 1].descent_
624                  //+ hlinesep() * rowinfo_[nrows()].lines_
625                        + 1;
626 }
627
628
629 void InsetMathGrid::drawT(TextPainter & pain, int x, int y) const
630 {
631 //      for (idx_type idx = 0; idx < nargs(); ++idx)
632 //              cell(idx).drawT(pain, x + cellXOffset(idx), y + cellYOffset(idx));
633 }
634
635
636 docstring InsetMathGrid::eolString(row_type row, bool emptyline, bool fragile) const
637 {
638         docstring eol;
639
640         if (!rowinfo_[row].crskip_.zero())
641                 eol += '[' + from_utf8(rowinfo_[row].crskip_.asLatexString()) + ']';
642         else if(!rowinfo_[row].allow_newpage_)
643                 eol += '*';
644
645         // make sure an upcoming '[' does not break anything
646         if (row + 1 < nrows()) {
647                 MathData const & c = cell(index(row + 1, 0));
648                 if (c.size() && c.front()->getChar() == '[')
649                         //eol += "[0pt]";
650                         eol += "{}";
651         }
652
653         // only add \\ if necessary
654         if (eol.empty() && row + 1 == nrows() && (nrows() == 1 || !emptyline))
655                 return docstring();
656
657         return (fragile ? "\\protect\\\\" : "\\\\") + eol;
658 }
659
660
661 docstring InsetMathGrid::eocString(col_type col, col_type lastcol) const
662 {
663         if (col + 1 == lastcol)
664                 return docstring();
665         return from_ascii(" & ");
666 }
667
668
669 void InsetMathGrid::addRow(row_type row)
670 {
671         rowinfo_.insert(rowinfo_.begin() + row + 1, RowInfo());
672         cells_.insert
673                 (cells_.begin() + (row + 1) * ncols(), ncols(), MathData());
674         cellinfo_.insert
675                 (cellinfo_.begin() + (row + 1) * ncols(), ncols(), CellInfo());
676 }
677
678
679 void InsetMathGrid::appendRow()
680 {
681         rowinfo_.push_back(RowInfo());
682         //cells_.insert(cells_.end(), ncols(), MathData());
683         for (col_type col = 0; col < ncols(); ++col) {
684                 cells_.push_back(cells_type::value_type());
685                 cellinfo_.push_back(CellInfo());
686         }
687 }
688
689
690 void InsetMathGrid::delRow(row_type row)
691 {
692         if (nrows() == 1)
693                 return;
694
695         cells_type::iterator it = cells_.begin() + row * ncols();
696         cells_.erase(it, it + ncols());
697
698         vector<CellInfo>::iterator jt = cellinfo_.begin() + row * ncols();
699         cellinfo_.erase(jt, jt + ncols());
700
701         rowinfo_.erase(rowinfo_.begin() + row);
702 }
703
704
705 void InsetMathGrid::copyRow(row_type row)
706 {
707         addRow(row);
708         for (col_type col = 0; col < ncols(); ++col)
709                 cells_[(row + 1) * ncols() + col] = cells_[row * ncols() + col];
710 }
711
712
713 void InsetMathGrid::swapRow(row_type row)
714 {
715         if (nrows() == 1)
716                 return;
717         if (row + 1 == nrows())
718                 --row;
719         for (col_type col = 0; col < ncols(); ++col)
720                 swap(cells_[row * ncols() + col], cells_[(row + 1) * ncols() + col]);
721 }
722
723
724 void InsetMathGrid::addCol(col_type newcol)
725 {
726         const col_type nc = ncols();
727         const row_type nr = nrows();
728         cells_type new_cells((nc + 1) * nr);
729         vector<CellInfo> new_cellinfo((nc + 1) * nr);
730
731         for (row_type row = 0; row < nr; ++row)
732                 for (col_type col = 0; col < nc; ++col) {
733                         new_cells[row * (nc + 1) + col + (col >= newcol)]
734                                 = cells_[row * nc + col];
735                         new_cellinfo[row * (nc + 1) + col + (col >= newcol)]
736                                 = cellinfo_[row * nc + col];
737                 }
738         swap(cells_, new_cells);
739         swap(cellinfo_, new_cellinfo);
740
741         ColInfo inf;
742         inf.skip_  = defaultColSpace(newcol);
743         inf.align_ = defaultColAlign(newcol);
744         colinfo_.insert(colinfo_.begin() + newcol, inf);
745 }
746
747
748 void InsetMathGrid::delCol(col_type col)
749 {
750         if (ncols() == 1)
751                 return;
752
753         cells_type tmpcells;
754         vector<CellInfo> tmpcellinfo;
755         for (col_type i = 0; i < nargs(); ++i)
756                 if (i % ncols() != col) {
757                         tmpcells.push_back(cells_[i]);
758                         tmpcellinfo.push_back(cellinfo_[i]);
759                 }
760         swap(cells_, tmpcells);
761         swap(cellinfo_, tmpcellinfo);
762
763         colinfo_.erase(colinfo_.begin() + col);
764 }
765
766
767 void InsetMathGrid::copyCol(col_type col)
768 {
769         addCol(col);
770         for (row_type row = 0; row < nrows(); ++row)
771                 cells_[row * ncols() + col + 1] = cells_[row * ncols() + col];
772 }
773
774
775 void InsetMathGrid::swapCol(col_type col)
776 {
777         if (ncols() == 1)
778                 return;
779         if (col + 1 == ncols())
780                 --col;
781         for (row_type row = 0; row < nrows(); ++row)
782                 swap(cells_[row * ncols() + col], cells_[row * ncols() + col + 1]);
783 }
784
785
786 int InsetMathGrid::cellXOffset(BufferView const & bv, idx_type idx) const
787 {
788         col_type c = col(idx);
789         int x = colinfo_[c].offset_;
790         char align = colinfo_[c].align_;
791         Dimension const & celldim = cell(idx).dimension(bv);
792         if (align == 'r' || align == 'R')
793                 x += colinfo_[c].width_ - celldim.wid;
794         if (align == 'c' || align == 'C')
795                 x += (colinfo_[c].width_ - celldim.wid) / 2;
796         return x;
797 }
798
799
800 int InsetMathGrid::cellYOffset(idx_type idx) const
801 {
802         return rowinfo_[row(idx)].offset_;
803 }
804
805
806 bool InsetMathGrid::idxUpDown(Cursor & cur, bool up) const
807 {
808         if (up) {
809                 if (cur.row() == 0)
810                         return false;
811                 cur.idx() -= ncols();
812         } else {
813                 if (cur.row() + 1 >= nrows())
814                         return false;
815                 cur.idx() += ncols();
816         }
817         cur.pos() = cur.cell().x2pos(cur.x_target() - cur.cell().xo(cur.bv()));
818         return true;
819 }
820
821
822 bool InsetMathGrid::idxBackward(Cursor & cur) const
823 {
824         // leave matrix if at the front edge
825         if (cur.col() == 0)
826                 return false;
827         --cur.idx();
828         cur.pos() = cur.lastpos();
829         return true;
830 }
831
832
833 bool InsetMathGrid::idxForward(Cursor & cur) const
834 {
835         // leave matrix if at the back edge
836         if (cur.col() + 1 == ncols())
837                 return false;
838         ++cur.idx();
839         cur.pos() = 0;
840         return true;
841 }
842
843
844 bool InsetMathGrid::idxFirst(Cursor & cur) const
845 {
846         switch (v_align_) {
847                 case 't':
848                         cur.idx() = 0;
849                         break;
850                 case 'b':
851                         cur.idx() = (nrows() - 1) * ncols();
852                         break;
853                 default:
854                         cur.idx() = ((nrows() - 1) / 2) * ncols();
855         }
856         cur.pos() = 0;
857         return true;
858 }
859
860
861 bool InsetMathGrid::idxLast(Cursor & cur) const
862 {
863         switch (v_align_) {
864                 case 't':
865                         cur.idx() = ncols() - 1;
866                         break;
867                 case 'b':
868                         cur.idx() = nargs() - 1;
869                         break;
870                 default:
871                         cur.idx() = ((nrows() - 1) / 2 + 1) * ncols() - 1;
872         }
873         cur.pos() = cur.lastpos();
874         return true;
875 }
876
877
878 bool InsetMathGrid::idxDelete(idx_type & idx)
879 {
880         // nothing to do if we have just one row
881         if (nrows() == 1)
882                 return false;
883
884         // nothing to do if we are in the middle of the last row of the inset
885         if (idx + ncols() > nargs())
886                 return false;
887
888         // try to delete entire sequence of ncols() empty cells if possible
889         for (idx_type i = idx; i < idx + ncols(); ++i)
890                 if (cell(i).size())
891                         return false;
892
893         // move cells if necessary
894         for (idx_type i = index(row(idx), 0); i < idx; ++i)
895                 swap(cell(i), cell(i + ncols()));
896
897         delRow(row(idx));
898
899         if (idx >= nargs())
900                 idx = nargs() - 1;
901
902         // undo effect of Ctrl-Tab (i.e. pull next cell)
903         //if (idx + 1 != nargs())
904         //      cell(idx).swap(cell(idx + 1));
905
906         // we handled the event..
907         return true;
908 }
909
910
911 // reimplement old behaviour when pressing Delete in the last position
912 // of a cell
913 void InsetMathGrid::idxGlue(idx_type idx)
914 {
915         col_type c = col(idx);
916         if (c + 1 == ncols()) {
917                 if (row(idx) + 1 != nrows()) {
918                         for (col_type cc = 0; cc < ncols(); ++cc)
919                                 cell(idx).append(cell(idx + cc + 1));
920                         delRow(row(idx) + 1);
921                 }
922         } else {
923                 cell(idx).append(cell(idx + 1));
924                 for (col_type cc = c + 2; cc < ncols(); ++cc)
925                         cell(idx - c + cc - 1) = cell(idx - c + cc);
926                 cell(idx - c + ncols() - 1).clear();
927         }
928 }
929
930
931 InsetMathGrid::RowInfo const & InsetMathGrid::rowinfo(row_type row) const
932 {
933         return rowinfo_[row];
934 }
935
936
937 InsetMathGrid::RowInfo & InsetMathGrid::rowinfo(row_type row)
938 {
939         return rowinfo_[row];
940 }
941
942
943 bool InsetMathGrid::idxBetween(idx_type idx, idx_type from, idx_type to) const
944 {
945         row_type const ri = row(idx);
946         row_type const r1 = min(row(from), row(to));
947         row_type const r2 = max(row(from), row(to));
948         col_type const ci = col(idx);
949         col_type const c1 = min(col(from), col(to));
950         col_type const c2 = max(col(from), col(to));
951         return r1 <= ri && ri <= r2 && c1 <= ci && ci <= c2;
952 }
953
954
955
956 void InsetMathGrid::normalize(NormalStream & os) const
957 {
958         os << "[grid ";
959         for (row_type row = 0; row < nrows(); ++row) {
960                 os << "[row ";
961                 for (col_type col = 0; col < ncols(); ++col)
962                         os << "[cell " << cell(index(row, col)) << ']';
963                 os << ']';
964         }
965         os << ']';
966 }
967
968
969 void InsetMathGrid::mathmlize(MathStream & os) const
970 {
971         os << MTag("mtable");
972         for (row_type row = 0; row < nrows(); ++row) {
973                 os << MTag("mtr");
974                 for (col_type col = 0; col < ncols(); ++col)
975                         os << cell(index(row, col));
976                 os << ETag("mtr");
977         }
978         os << ETag("mtable");
979 }
980
981
982 void InsetMathGrid::write(WriteStream & os) const
983 {
984         docstring eol;
985         for (row_type row = 0; row < nrows(); ++row) {
986                 os << verboseHLine(rowinfo_[row].lines_);
987                 // don't write & and empty cells at end of line
988                 col_type lastcol = 0;
989                 bool emptyline = true;
990                 for (col_type col = 0; col < ncols(); ++col)
991                         if (!cell(index(row, col)).empty()) {
992                                 lastcol = col + 1;
993                                 emptyline = false;
994                         }
995                 for (col_type col = 0; col < lastcol; ++col)
996                         os << cell(index(row, col)) << eocString(col, lastcol);
997                 eol = eolString(row, emptyline, os.fragile());
998                 os << eol;
999                 // append newline only if line wasn't completely empty
1000                 // and this was not the last line in the grid
1001                 if (!emptyline && row + 1 < nrows())
1002                         os << "\n";
1003         }
1004         docstring const s = verboseHLine(rowinfo_[nrows()].lines_);
1005         if (!s.empty()) {
1006                 if (eol.empty()) {
1007                         if (os.fragile())
1008                                 os << "\\protect";
1009                         os << "\\\\";
1010                 }
1011                 os << s;
1012         }
1013 }
1014
1015
1016 int InsetMathGrid::colsep() const
1017 {
1018         return 6;
1019 }
1020
1021
1022 int InsetMathGrid::rowsep() const
1023 {
1024         return 6;
1025 }
1026
1027
1028 int InsetMathGrid::hlinesep() const
1029 {
1030         return 3;
1031 }
1032
1033
1034 int InsetMathGrid::vlinesep() const
1035 {
1036         return 3;
1037 }
1038
1039
1040 int InsetMathGrid::border() const
1041 {
1042         return 1;
1043 }
1044
1045
1046 void InsetMathGrid::splitCell(Cursor & cur)
1047 {
1048         if (cur.idx() == cur.lastidx())
1049                 return;
1050         MathData ar = cur.cell();
1051         ar.erase(0, cur.pos());
1052         cur.cell().erase(cur.pos(), cur.lastpos());
1053         ++cur.idx();
1054         cur.pos() = 0;
1055         cur.cell().insert(0, ar);
1056 }
1057
1058
1059 void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
1060 {
1061         //lyxerr << "*** InsetMathGrid: request: " << cmd << endl;
1062         switch (cmd.action) {
1063
1064         // insert file functions
1065         case LFUN_LINE_DELETE:
1066                 // FIXME: We use recordUndoInset when a change reflects more
1067                 // than one cell, because recordUndo does not work for
1068                 // multiple cells. Unfortunately this puts the cursor in front
1069                 // of the inset after undo. This is (especilally for large
1070                 // grids) annoying.
1071                 cur.recordUndoInset();
1072                 //autocorrect_ = false;
1073                 //macroModeClose();
1074                 //if (selection_) {
1075                 //      selDel();
1076                 //      break;
1077                 //}
1078                 if (nrows() > 1)
1079                         delRow(cur.row());
1080                 if (cur.idx() > cur.lastidx())
1081                         cur.idx() = cur.lastidx();
1082                 if (cur.pos() > cur.lastpos())
1083                         cur.pos() = cur.lastpos();
1084                 break;
1085
1086         case LFUN_CELL_SPLIT:
1087                 cur.recordUndo();
1088                 splitCell(cur);
1089                 break;
1090
1091         case LFUN_CELL_BACKWARD:
1092                 // See below.
1093                 cur.selection() = false;
1094                 if (!idxPrev(cur)) {
1095                         cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
1096                         cur.undispatched();
1097                 }
1098                 break;
1099
1100         case LFUN_CELL_FORWARD:
1101                 // Can't handle selection by additional 'shift' as this is
1102                 // hard bound to LFUN_CELL_BACKWARD
1103                 cur.selection() = false;
1104                 if (!idxNext(cur)) {
1105                         cmd = FuncRequest(LFUN_FINISHED_FORWARD);
1106                         cur.undispatched();
1107                 }
1108                 break;
1109
1110         case LFUN_NEW_LINE: {
1111                 cur.recordUndoInset();
1112                 row_type const r = cur.row();
1113                 addRow(r);
1114
1115                 // split line
1116                 for (col_type c = col(cur.idx()) + 1; c < ncols(); ++c)
1117                         swap(cell(index(r, c)), cell(index(r + 1, c)));
1118
1119                 // split cell
1120                 splitCell(cur);
1121                 swap(cell(cur.idx()), cell(cur.idx() + ncols() - 1));
1122                 if (cur.idx() > 0)
1123                         --cur.idx();
1124                 cur.pos() = cur.lastpos();
1125
1126                 //mathcursor->normalize();
1127                 //cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
1128                 break;
1129         }
1130
1131         case LFUN_TABULAR_FEATURE: {
1132                 cur.recordUndoInset();
1133                 //lyxerr << "handling tabular-feature " << to_utf8(cmd.argument()) << endl;
1134                 istringstream is(to_utf8(cmd.argument()));
1135                 string s;
1136                 is >> s;
1137                 if (s == "valign-top")
1138                         valign('t');
1139                 else if (s == "valign-middle")
1140                         valign('c');
1141                 else if (s == "valign-bottom")
1142                         valign('b');
1143                 else if (s == "align-left")
1144                         halign('l', cur.col());
1145                 else if (s == "align-right")
1146                         halign('r', cur.col());
1147                 else if (s == "align-center")
1148                         halign('c', cur.col());
1149                 else if (s == "append-row")
1150                         for (int i = 0, n = extractInt(is); i < n; ++i)
1151                                 addRow(cur.row());
1152                 else if (s == "delete-row") {
1153                         cur.clearSelection(); // bug 4323
1154                         for (int i = 0, n = extractInt(is); i < n; ++i) {
1155                                 delRow(cur.row());
1156                                 if (cur.idx() >= nargs())
1157                                         cur.idx() -= ncols();
1158                         }
1159                         cur.pos() = 0; // trick, see below
1160                 }
1161                 else if (s == "copy-row") {
1162                         // Here (as later) we save the cursor col/row
1163                         // in order to restore it after operation.
1164                         row_type const r = cur.row();
1165                         col_type const c = cur.col();
1166                         for (int i = 0, n = extractInt(is); i < n; ++i)
1167                                 copyRow(cur.row());
1168                         cur.idx() = index(r, c);
1169                 }
1170                 else if (s == "swap-row") {
1171                         swapRow(cur.row());
1172                         // Trick to suppress same-idx-means-different-cell
1173                         // assertion crash:
1174                         cur.pos() = 0;
1175                 }
1176                 else if (s == "add-hline-above")
1177                         rowinfo_[cur.row()].lines_++;
1178                 else if (s == "add-hline-below")
1179                         rowinfo_[cur.row()+1].lines_++;
1180                 else if (s == "delete-hline-above")
1181                         rowinfo_[cur.row()].lines_--;
1182                 else if (s == "delete-hline-below")
1183                         rowinfo_[cur.row()+1].lines_--;
1184                 else if (s == "append-column") {
1185                         row_type const r = cur.row();
1186                         col_type const c = cur.col();
1187                         for (int i = 0, n = extractInt(is); i < n; ++i)
1188                                 addCol(cur.col() + 1);
1189                         cur.idx() = index(r, c);
1190                 }
1191                 else if (s == "delete-column") {
1192                         cur.clearSelection(); // bug 4323
1193                         row_type const r = cur.row();
1194                         col_type const c = cur.col();
1195                         for (int i = 0, n = extractInt(is); i < n; ++i)
1196                                 delCol(col(cur.idx()));
1197                         cur.idx() = index(r, min(c, cur.ncols() - 1));
1198                         cur.pos() = 0; // trick, see above
1199                 }
1200                 else if (s == "copy-column") {
1201                         row_type const r = cur.row();
1202                         col_type const c = cur.col();
1203                         copyCol(cur.col());
1204                         cur.idx() = index(r, c);
1205                 }
1206                 else if (s == "swap-column") {
1207                         swapCol(cur.col());
1208                         cur.pos() = 0; // trick, see above
1209                 }
1210                 else if (s == "add-vline-left") {
1211                         colinfo_[cur.col()].lines_++;
1212                         if (!colinfo_[cur.col()].special_.empty())
1213                                 colinfo_[cur.col()].special_ += '|';
1214                 }
1215                 else if (s == "add-vline-right") {
1216                         colinfo_[cur.col()+1].lines_++;
1217                         if (!colinfo_[cur.col()+1].special_.empty())
1218                                 colinfo_[cur.col()+1].special_.insert(0, 1, '|');
1219                 }
1220                 else if (s == "delete-vline-left") {
1221                         colinfo_[cur.col()].lines_--;
1222                         docstring & special = colinfo_[cur.col()].special_;
1223                         if (!special.empty()) {
1224                                 docstring::size_type i = special.rfind('|');
1225                                 BOOST_ASSERT(i != docstring::npos);
1226                                 special.erase(i, 1);
1227                         }
1228                 }
1229                 else if (s == "delete-vline-right") {
1230                         colinfo_[cur.col()+1].lines_--;
1231                         docstring & special = colinfo_[cur.col()+1].special_;
1232                         if (!special.empty()) {
1233                                 docstring::size_type i = special.find('|');
1234                                 BOOST_ASSERT(i != docstring::npos);
1235                                 special.erase(i, 1);
1236                         }
1237                 }
1238                 else {
1239                         cur.undispatched();
1240                         break;
1241                 }
1242                 // perhaps this should be FINISHED_BACKWARD -- just for clarity?
1243                 lyxerr << "returning FINISHED_LEFT" << endl;
1244                 break;
1245         }
1246
1247         case LFUN_PASTE: {
1248                 cur.message(_("Paste"));
1249                 cap::replaceSelection(cur);
1250                 docstring topaste;
1251                 if (cmd.argument().empty() && !theClipboard().isInternal())
1252                         topaste = theClipboard().getAsText();
1253                 else {
1254                         idocstringstream is(cmd.argument());
1255                         int n = 0;
1256                         is >> n;
1257                         topaste = cap::getSelection(cur.buffer(), n);
1258                 }
1259                 InsetMathGrid grid(1, 1);
1260                 if (!topaste.empty())
1261                         mathed_parse_normal(grid, topaste);
1262
1263                 if (grid.nargs() == 1) {
1264                         // single cell/part of cell
1265                         cur.recordUndo();
1266                         cur.cell().insert(cur.pos(), grid.cell(0));
1267                         cur.pos() += grid.cell(0).size();
1268                 } else {
1269                         // multiple cells
1270                         cur.recordUndoInset();
1271                         col_type const numcols =
1272                                 min(grid.ncols(), ncols() - col(cur.idx()));
1273                         row_type const numrows =
1274                                 min(grid.nrows(), nrows() - cur.row());
1275                         for (row_type r = 0; r < numrows; ++r) {
1276                                 for (col_type c = 0; c < numcols; ++c) {
1277                                         idx_type i = index(r + cur.row(), c + col(cur.idx()));
1278                                         cell(i).insert(0, grid.cell(grid.index(r, c)));
1279                                 }
1280                                 // append the left over horizontal cells to the last column
1281                                 idx_type i = index(r + cur.row(), ncols() - 1);
1282                                 for (InsetMath::col_type c = numcols; c < grid.ncols(); ++c)
1283                                         cell(i).append(grid.cell(grid.index(r, c)));
1284                         }
1285                         // append the left over vertical cells to the last _cell_
1286                         idx_type i = nargs() - 1;
1287                         for (row_type r = numrows; r < grid.nrows(); ++r)
1288                                 for (col_type c = 0; c < grid.ncols(); ++c)
1289                                         cell(i).append(grid.cell(grid.index(r, c)));
1290                 }
1291                 cur.clearSelection(); // bug 393
1292                 cur.finishUndo();
1293                 break;
1294         }
1295
1296         case LFUN_LINE_BEGIN_SELECT:
1297         case LFUN_LINE_BEGIN:
1298         case LFUN_WORD_BACKWARD_SELECT:
1299         case LFUN_WORD_BACKWARD:
1300         case LFUN_WORD_LEFT_SELECT:
1301         case LFUN_WORD_LEFT:
1302                 cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT ||
1303                                 cmd.action == LFUN_WORD_LEFT_SELECT ||
1304                                 cmd.action == LFUN_LINE_BEGIN_SELECT);
1305                 cur.macroModeClose();
1306                 if (cur.pos() != 0) {
1307                         cur.pos() = 0;
1308                 } else if (cur.idx() % cur.ncols() != 0) {
1309                         cur.idx() -= cur.idx() % cur.ncols();
1310                         cur.pos() = 0;
1311                 } else if (cur.idx() != 0) {
1312                         cur.idx() = 0;
1313                         cur.pos() = 0;
1314                 } else {
1315                         cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
1316                         cur.undispatched();
1317                 }
1318                 break;
1319
1320         case LFUN_WORD_FORWARD_SELECT:
1321         case LFUN_WORD_FORWARD:
1322         case LFUN_WORD_RIGHT_SELECT:
1323         case LFUN_WORD_RIGHT:
1324         case LFUN_LINE_END_SELECT:
1325         case LFUN_LINE_END:
1326                 cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT ||
1327                                 cmd.action == LFUN_WORD_RIGHT_SELECT ||
1328                                 cmd.action == LFUN_LINE_END_SELECT);
1329                 cur.macroModeClose();
1330                 cur.clearTargetX();
1331                 if (cur.pos() != cur.lastpos()) {
1332                         cur.pos() = cur.lastpos();
1333                 } else if ((cur.idx() + 1) % cur.ncols() != 0) {
1334                         cur.idx() += cur.ncols() - 1 - cur.idx() % cur.ncols();
1335                         cur.pos() = cur.lastpos();
1336                 } else if (cur.idx() != cur.lastidx()) {
1337                         cur.idx() = cur.lastidx();
1338                         cur.pos() = cur.lastpos();
1339                 } else {
1340                         cmd = FuncRequest(LFUN_FINISHED_FORWARD);
1341                         cur.undispatched();
1342                 }
1343                 break;
1344
1345         default:
1346                 InsetMathNest::doDispatch(cur, cmd);
1347         }
1348 }
1349
1350
1351 bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd,
1352                 FuncStatus & status) const
1353 {
1354         switch (cmd.action) {
1355         case LFUN_TABULAR_FEATURE: {
1356                 string const s = to_utf8(cmd.argument());
1357                 if (nrows() <= 1 && (s == "delete-row" || s == "swap-row")) {
1358                         status.enabled(false);
1359                         status.message(from_utf8(N_("Only one row")));
1360                         return true;
1361                 }
1362                 if (ncols() <= 1 &&
1363                     (s == "delete-column" || s == "swap-column")) {
1364                         status.enabled(false);
1365                         status.message(from_utf8(N_("Only one column")));
1366                         return true;
1367                 }
1368                 if ((rowinfo_[cur.row()].lines_ == 0 &&
1369                      s == "delete-hline-above") ||
1370                     (rowinfo_[cur.row() + 1].lines_ == 0 &&
1371                      s == "delete-hline-below")) {
1372                         status.enabled(false);
1373                         status.message(from_utf8(N_("No hline to delete")));
1374                         return true;
1375                 }
1376
1377                 if ((colinfo_[cur.col()].lines_ == 0 &&
1378                      s == "delete-vline-left") ||
1379                     (colinfo_[cur.col() + 1].lines_ == 0 &&
1380                      s == "delete-vline-right")) {
1381                         status.enabled(false);
1382                         status.message(from_utf8(N_("No vline to delete")));
1383                         return true;
1384                 }
1385                 if (s == "valign-top" || s == "valign-middle" ||
1386                     s == "valign-bottom" || s == "align-left" ||
1387                     s == "align-right" || s == "align-center" ||
1388                     s == "append-row" || s == "delete-row" ||
1389                     s == "copy-row" || s == "swap-row" ||
1390                     s == "add-hline-above" || s == "add-hline-below" ||
1391                     s == "delete-hline-above" || s == "delete-hline-below" ||
1392                     s == "append-column" || s == "delete-column" ||
1393                     s == "copy-column" || s == "swap-column" ||
1394                     s == "add-vline-left" || s == "add-vline-right" ||
1395                     s == "delete-vline-left" || s == "delete-vline-right")
1396                         status.enabled(true);
1397                 else {
1398                         status.enabled(false);
1399                         status.message(bformat(
1400                                 from_utf8(N_("Unknown tabular feature '%1$s'")), lyx::from_ascii(s)));
1401                 }
1402
1403                 status.setOnOff((s == "align-left" && halign(cur.col()) == 'l')
1404                            || (s == "align-right"   && halign(cur.col()) == 'r')
1405                            || (s == "align-center"  && halign(cur.col()) == 'c')
1406                            || (s == "valign-top"    && valign() == 't')
1407                            || (s == "valign-bottom" && valign() == 'b')
1408                            || (s == "valign-middle" && valign() == 'm'));
1409
1410 #if 0
1411                 // FIXME: What did this code do?
1412                 // Please check whether it is still needed!
1413                 // should be more precise
1414                 if (v_align_ == '\0') {
1415                         status.enable(true);
1416                         break;
1417                 }
1418                 if (cmd.argument().empty()) {
1419                         status.enable(false);
1420                         break;
1421                 }
1422                 if (!support::contains("tcb", cmd.argument()[0])) {
1423                         status.enable(false);
1424                         break;
1425                 }
1426                 status.setOnOff(cmd.argument()[0] == v_align_);
1427                 status.enabled(true);
1428 #endif
1429                 return true;
1430         }
1431
1432         case LFUN_CELL_SPLIT:
1433                 status.enabled(true);
1434                 return true;
1435
1436         case LFUN_CELL_BACKWARD:
1437         case LFUN_CELL_FORWARD:
1438                 status.enabled(true);
1439                 return true;
1440
1441         default:
1442                 return InsetMathNest::getStatus(cur, cmd, status);
1443         }
1444 }
1445
1446
1447 } // namespace lyx