]> git.lyx.org Git - lyx.git/blob - src/mathed/math_gridinset.C
fix #456
[lyx.git] / src / mathed / math_gridinset.C
1 #ifdef __GNUG__
2 #pragma implementation
3 #endif
4
5 #include "math_gridinset.h"
6 #include "math_mathmlstream.h"
7 #include "math_streamstr.h"
8 #include "lyxfont.h"
9 #include "frontends/Painter.h"
10 #include "debug.h"
11
12
13 using std::swap;
14 using std::max;
15 using std::min;
16 using std::vector;
17
18
19 namespace {
20
21 string verboseHLine(int n)
22 {
23         string res;
24         for (int i = 0; i < n; ++i)
25                 res += "\\hline";
26         return res + ' ';
27 }
28
29 }
30
31 //////////////////////////////////////////////////////////////
32
33
34 MathGridInset::CellInfo::CellInfo()
35         : dummy_(false)
36 {}
37
38
39
40
41 //////////////////////////////////////////////////////////////
42
43
44 MathGridInset::RowInfo::RowInfo()
45         : lines_(0), skip_(0)
46 {}
47
48
49
50 int MathGridInset::RowInfo::skipPixels() const
51 {
52 #ifdef WITH_WARNINGS
53 #warning fix this once the interface to LyXLength has improved
54 #endif
55         return int(crskip_.value());
56 }
57
58
59
60 //////////////////////////////////////////////////////////////
61
62
63 MathGridInset::ColInfo::ColInfo()
64         : align_('c'), leftline_(false), rightline_(false), lines_(0)
65 {}
66
67
68 //////////////////////////////////////////////////////////////
69
70
71 MathGridInset::MathGridInset(char v, string const & h)
72         : MathNestInset(guessColumns(h)),
73           rowinfo_(2),
74           colinfo_(guessColumns(h) + 1),
75           cellinfo_(1 * guessColumns(h))
76 {
77         setDefaults();
78         valign(v);
79         halign(h);
80 }
81
82
83 MathGridInset::MathGridInset()
84         : MathNestInset(1),
85           rowinfo_(1 + 1),
86                 colinfo_(1 + 1),
87                 cellinfo_(1),
88                 v_align_('c')
89 {
90         setDefaults();
91 }
92
93
94 MathGridInset::MathGridInset(col_type m, row_type n)
95         : MathNestInset(m * n),
96           rowinfo_(n + 1),
97                 colinfo_(m + 1),
98                 cellinfo_(m * n),
99                 v_align_('c')
100 {
101         setDefaults();
102 }
103
104
105 MathGridInset::MathGridInset(col_type m, row_type n, char v, string const & h)
106         : MathNestInset(m * n),
107           rowinfo_(n + 1),
108           colinfo_(m + 1),
109                 cellinfo_(m * n),
110                 v_align_(v)
111 {
112         setDefaults();
113         valign(v);
114         halign(h);
115 }
116
117
118 MathInset * MathGridInset::clone() const
119 {
120         return new MathGridInset(*this);
121 }
122
123
124 MathInset::idx_type MathGridInset::index(row_type row, col_type col) const
125 {
126         return col + ncols() * row;
127 }
128
129
130 void MathGridInset::setDefaults()
131 {
132         if (ncols() <= 0)
133                 lyxerr << "positive number of columns expected\n";
134         if (nrows() <= 0)
135                 lyxerr << "positive number of rows expected\n";
136         for (col_type col = 0; col < ncols(); ++col) {
137                 colinfo_[col].align_ = defaultColAlign(col);
138                 colinfo_[col].skip_  = defaultColSpace(col);
139         }
140 }
141
142
143 void MathGridInset::halign(string const & hh)
144 {
145         col_type col = 0;
146         for (string::const_iterator it = hh.begin(); it != hh.end(); ++it) {
147                 char c = *it;
148                 if (c == '|') {
149                         colinfo_[col].lines_++;
150                 } else if (c == 'c' || c == 'l' || c == 'r') {
151                         colinfo_[col].align_ = c;
152                         ++col;
153                         colinfo_[col].lines_ = 0;
154                 } else {
155                         lyxerr << "unkown column separator: '" << c << "'\n";
156                 }
157         }
158
159 /*
160         col_type n = hh.size();
161         if (n > ncols())
162                 n = ncols();
163         for (col_type col = 0; col < n; ++col)
164                 colinfo_[col].align_ = hh[col];
165 */
166 }
167
168
169 MathGridInset::col_type MathGridInset::guessColumns(string const & hh) const
170 {
171         col_type col = 0;
172         for (string::const_iterator it = hh.begin(); it != hh.end(); ++it)
173                 if (*it == 'c' || *it == 'l' || *it == 'r')
174                         ++col;
175         return col;
176 }
177
178
179 void MathGridInset::halign(char h, col_type col)
180 {
181         colinfo_[col].align_ = h;
182 }
183
184
185 char MathGridInset::halign(col_type col) const
186 {
187         return colinfo_[col].align_;
188 }
189
190
191 string MathGridInset::halign() const
192 {
193         string res;
194         for (col_type col = 0; col < ncols(); ++col) {
195                 res += string(colinfo_[col].lines_, '|');
196                 res += colinfo_[col].align_;
197         }
198         return res + string(colinfo_[ncols()].lines_, '|');
199 }
200
201
202 void MathGridInset::valign(char c)
203 {
204         v_align_ = c;
205 }
206
207
208 char MathGridInset::valign() const
209 {
210         return v_align_;
211 }
212
213
214 MathGridInset::col_type MathGridInset::ncols() const
215 {
216         return colinfo_.size() - 1;
217 }
218
219
220 MathGridInset::row_type MathGridInset::nrows() const
221 {
222         return rowinfo_.size() - 1;
223 }
224
225
226 MathGridInset::col_type MathGridInset::col(idx_type idx) const
227 {
228         return idx % ncols();
229 }
230
231
232 MathGridInset::row_type MathGridInset::row(idx_type idx) const
233 {
234         return idx / ncols();
235 }
236
237
238 void MathGridInset::vcrskip(LyXLength const & crskip, row_type row)
239 {
240         rowinfo_[row].crskip_ = crskip;
241 }
242
243
244 LyXLength MathGridInset::vcrskip(row_type row) const
245 {
246         return rowinfo_[row].crskip_;
247 }
248
249
250 void MathGridInset::metrics(MathMetricsInfo & mi) const
251 {
252         // let the cells adjust themselves
253         MathNestInset::metrics(mi);
254
255         // compute absolute sizes of vertical structure
256         for (row_type row = 0; row < nrows(); ++row) {
257                 int asc  = 0;
258                 int desc = 0;
259                 for (col_type col = 0; col < ncols(); ++col) {
260                         MathXArray const & c = xcell(index(row, col));
261                         asc  = max(asc,  c.ascent());
262                         desc = max(desc, c.descent());
263                 }
264                 rowinfo_[row].ascent_  = asc;
265                 rowinfo_[row].descent_ = desc;
266         }
267         rowinfo_[0].ascent_       += hlinesep() * rowinfo_[0].lines_;
268         rowinfo_[nrows()].ascent_  = 0;
269         rowinfo_[nrows()].descent_ = 0;
270
271         // compute vertical offsets
272         rowinfo_[0].offset_ = 0;
273         for (row_type row = 1; row <= nrows(); ++row) {
274                 rowinfo_[row].offset_  =
275                         rowinfo_[row - 1].offset_  +
276                         rowinfo_[row - 1].descent_ +
277                         rowinfo_[row - 1].skipPixels() +
278                         rowsep() +
279                         rowinfo_[row].lines_ * hlinesep() +
280                         rowinfo_[row].ascent_;
281         }
282
283         // adjust vertical offset
284         int h = 0;
285         switch (v_align_) {
286                 case 't':
287                         h = 0;
288                         break;
289                 case 'b':
290                         h = rowinfo_[nrows() - 1].offset_;
291                         break;
292                 default:
293                         h = rowinfo_[nrows() - 1].offset_ / 2;
294         }
295         for (row_type row = 0; row <= nrows(); ++row)
296                 rowinfo_[row].offset_ -= h;
297
298
299         // compute absolute sizes of horizontal structure
300         for (col_type col = 0; col < ncols(); ++col) {
301                 int wid = 0;
302                 for (row_type row = 0; row < nrows(); ++row)
303                         wid = max(wid, xcell(index(row, col)).width());
304                 colinfo_[col].width_ = wid;
305         }
306         colinfo_[ncols()].width_  = 0;
307
308         // compute horizontal offsets
309         colinfo_[0].offset_ = border();
310         for (col_type col = 1; col <= ncols(); ++col) {
311                 colinfo_[col].offset_ =
312                         colinfo_[col - 1].offset_ +
313                         colinfo_[col - 1].width_ +
314                         colinfo_[col - 1].skip_ +
315                         colsep() +
316                         colinfo_[col].lines_ * vlinesep();
317         }
318
319
320         width_   =   colinfo_[ncols() - 1].offset_
321                        + colinfo_[ncols() - 1].width_
322                  + vlinesep() * colinfo_[ncols()].lines_
323                        + border();
324
325         ascent_  = - rowinfo_[0].offset_
326                        + rowinfo_[0].ascent_
327                  + hlinesep() * rowinfo_[0].lines_
328                        + border();
329
330         descent_ =   rowinfo_[nrows() - 1].offset_
331                        + rowinfo_[nrows() - 1].descent_
332                  + hlinesep() * rowinfo_[nrows()].lines_
333                        + border();
334
335
336 /*
337         // Increase ws_[i] for 'R' columns (except the first one)
338         for (int i = 1; i < nc_; ++i)
339                 if (align_[i] == 'R')
340                         ws_[i] += 10 * df_width;
341         // Increase ws_[i] for 'C' column
342         if (align_[0] == 'C')
343                 if (ws_[0] < 7 * workwidth / 8)
344                         ws_[0] = 7 * workwidth / 8;
345
346         // Adjust local tabs
347         width = colsep();
348         for (cxrow = row_.begin(); cxrow; ++cxrow) {
349                 int rg = COLSEP;
350                 int lf = 0;
351                 for (int i = 0; i < nc_; ++i) {
352                         bool isvoid = false;
353                         if (cxrow->getTab(i) <= 0) {
354                                 cxrow->setTab(i, df_width);
355                                 isvoid = true;
356                         }
357                         switch (align_[i]) {
358                         case 'l':
359                                 lf = 0;
360                                 break;
361                         case 'c':
362                                 lf = (ws_[i] - cxrow->getTab(i))/2;
363                                 break;
364                         case 'r':
365                         case 'R':
366                                 lf = ws_[i] - cxrow->getTab(i);
367                                 break;
368                         case 'C':
369                                 if (cxrow == row_.begin())
370                                         lf = 0;
371                                 else if (cxrow.is_last())
372                                         lf = ws_[i] - cxrow->getTab(i);
373                                 else
374                                         lf = (ws_[i] - cxrow->getTab(i))/2;
375                                 break;
376                         }
377                         int const ww = (isvoid) ? lf : lf + cxrow->getTab(i);
378                         cxrow->setTab(i, lf + rg);
379                         rg = ws_[i] - ww + colsep();
380                         if (cxrow == row_.begin())
381                                 width += ws_[i] + colsep();
382                 }
383                 cxrow->setBaseline(cxrow->getBaseline() - ascent);
384         }
385 */
386 }
387
388
389 void MathGridInset::draw(MathPainterInfo & pi, int x, int y) const
390 {
391         for (idx_type idx = 0; idx < nargs(); ++idx)
392                 xcell(idx).draw(pi, x + cellXOffset(idx), y + cellYOffset(idx));
393
394         for (row_type row = 0; row <= nrows(); ++row)
395                 for (int i = 0; i < rowinfo_[row].lines_; ++i) {
396                         int yy = y + rowinfo_[row].offset_ - rowinfo_[row].ascent_
397                                 - i * hlinesep() - hlinesep()/2 - rowsep()/2;
398                         pi.pain.line(x + 1, yy, x + width_ - 1, yy);
399                 }
400
401         for (col_type col = 0; col <= ncols(); ++col)
402                 for (int i = 0; i < colinfo_[col].lines_; ++i) {
403                         int xx = x + colinfo_[col].offset_
404                                 - i * vlinesep() - vlinesep()/2 - colsep()/2;
405                         pi.pain.line(xx, y - ascent_ + 1, xx, y + descent_ - 1);
406                 }
407 }
408
409
410 void MathGridInset::metricsT(TextMetricsInfo const & mi) const
411 {
412         // let the cells adjust themselves
413         //MathNestInset::metrics(mi);
414         for (idx_type i = 0; i < nargs(); ++i)
415                 xcell(i).metricsT(mi);
416
417         // compute absolute sizes of vertical structure
418         for (row_type row = 0; row < nrows(); ++row) {
419                 int asc  = 0;
420                 int desc = 0;
421                 for (col_type col = 0; col < ncols(); ++col) {
422                         MathXArray const & c = xcell(index(row, col));
423                         asc  = max(asc,  c.ascent());
424                         desc = max(desc, c.descent());
425                 }
426                 rowinfo_[row].ascent_  = asc;
427                 rowinfo_[row].descent_ = desc;
428         }
429         //rowinfo_[0].ascent_       += hlinesep() * rowinfo_[0].lines_;
430         rowinfo_[nrows()].ascent_  = 0;
431         rowinfo_[nrows()].descent_ = 0;
432
433         // compute vertical offsets
434         rowinfo_[0].offset_ = 0;
435         for (row_type row = 1; row <= nrows(); ++row) {
436                 rowinfo_[row].offset_  =
437                         rowinfo_[row - 1].offset_  +
438                         rowinfo_[row - 1].descent_ +
439                         //rowinfo_[row - 1].skipPixels() +
440                         1 + //rowsep() +
441                         //rowinfo_[row].lines_ * hlinesep() +
442                         rowinfo_[row].ascent_;
443         }
444
445         // adjust vertical offset
446         int h = 0;
447         switch (v_align_) {
448                 case 't':
449                         h = 0;
450                         break;
451                 case 'b':
452                         h = rowinfo_[nrows() - 1].offset_;
453                         break;
454                 default:
455                         h = rowinfo_[nrows() - 1].offset_ / 2;
456         }
457         for (row_type row = 0; row <= nrows(); ++row)
458                 rowinfo_[row].offset_ -= h;
459
460
461         // compute absolute sizes of horizontal structure
462         for (col_type col = 0; col < ncols(); ++col) {
463                 int wid = 0;
464                 for (row_type row = 0; row < nrows(); ++row)
465                         wid = max(wid, xcell(index(row, col)).width());
466                 colinfo_[col].width_ = wid;
467         }
468         colinfo_[ncols()].width_  = 0;
469
470         // compute horizontal offsets
471         colinfo_[0].offset_ = border();
472         for (col_type col = 1; col <= ncols(); ++col) {
473                 colinfo_[col].offset_ =
474                         colinfo_[col - 1].offset_ +
475                         colinfo_[col - 1].width_ +
476                         colinfo_[col - 1].skip_ +
477                         1 ; //colsep() +
478                         //colinfo_[col].lines_ * vlinesep();
479         }
480
481
482         width_   =   colinfo_[ncols() - 1].offset_
483                        + colinfo_[ncols() - 1].width_
484                  //+ vlinesep() * colinfo_[ncols()].lines_
485                        + 2;
486
487         ascent_  = - rowinfo_[0].offset_
488                        + rowinfo_[0].ascent_
489                  //+ hlinesep() * rowinfo_[0].lines_
490                        + 1;
491
492         descent_ =   rowinfo_[nrows() - 1].offset_
493                        + rowinfo_[nrows() - 1].descent_
494                  //+ hlinesep() * rowinfo_[nrows()].lines_
495                        + 1;
496
497 }
498
499
500 void MathGridInset::drawT(TextPainter & pain, int x, int y) const
501 {
502         for (idx_type idx = 0; idx < nargs(); ++idx)
503                 xcell(idx).drawT(pain, x + cellXOffset(idx), y + cellYOffset(idx));
504 }
505
506
507 string MathGridInset::eolString(row_type row, bool fragile) const
508 {
509         string eol;
510
511         if (!rowinfo_[row].crskip_.zero())
512                 eol += "[" + rowinfo_[row].crskip_.asLatexString() + "]";
513
514         // make sure an upcoming '[' does not break anything
515         if (row + 1 < nrows()) {
516                 MathArray const & c = cell(index(row + 1, 0));
517                 if (c.size() && c.front()->getChar() == '[')
518                         //eol += "[0pt]";
519                         eol += "{}";
520         }
521
522         // only add \\ if necessary
523         if (eol.empty() && row + 1 == nrows())
524                 return string();
525
526         return (fragile ? "\\protect\\\\" : "\\\\") + eol + '\n';
527 }
528
529
530 string MathGridInset::eocString(col_type col) const
531 {
532         if (col + 1 == ncols())
533                 return string();
534         return " & ";
535 }
536
537
538 void MathGridInset::addRow(row_type row)
539 {
540         rowinfo_.insert(rowinfo_.begin() + row + 1, RowInfo());
541         cells_.insert
542                 (cells_.begin() + (row + 1) * ncols(), ncols(), MathXArray());
543         cellinfo_.insert
544                 (cellinfo_.begin() + (row + 1) * ncols(), ncols(), CellInfo());
545 }
546
547
548 void MathGridInset::appendRow()
549 {
550         rowinfo_.push_back(RowInfo());
551         //cells_.insert(cells_.end(), ncols(), MathXArray());
552         for (col_type col = 0; col < ncols(); ++col) {
553                 cells_.push_back(cells_type::value_type());
554                 cellinfo_.push_back(CellInfo());
555         }
556 }
557
558
559 void MathGridInset::delRow(row_type row)
560 {
561         if (nrows() == 1)
562                 return;
563
564         cells_type::iterator it = cells_.begin() + row * ncols();
565         cells_.erase(it, it + ncols());
566
567         vector<CellInfo>::iterator jt = cellinfo_.begin() + row * ncols();
568         cellinfo_.erase(jt, jt + ncols());
569
570         rowinfo_.erase(rowinfo_.begin() + row);
571 }
572
573
574 void MathGridInset::addCol(col_type newcol)
575 {
576         const col_type nc = ncols();
577         const row_type nr = nrows();
578         cells_type new_cells((nc + 1) * nr);
579         vector<CellInfo> new_cellinfo((nc + 1) * nr);
580
581         for (row_type row = 0; row < nr; ++row)
582                 for (col_type col = 0; col < nc; ++col) {
583                         new_cells[row * (nc + 1) + col + (col > newcol)]
584                                 = cells_[row * nc + col];
585                         new_cellinfo[row * (nc + 1) + col + (col > newcol)]
586                                 = cellinfo_[row * nc + col];
587                 }
588         swap(cells_, new_cells);
589         swap(cellinfo_, new_cellinfo);
590
591         ColInfo inf;
592         inf.skip_  = defaultColSpace(newcol);
593         inf.align_ = defaultColAlign(newcol);
594         colinfo_.insert(colinfo_.begin() + newcol, inf);
595 }
596
597
598 void MathGridInset::delCol(col_type col)
599 {
600         if (ncols() == 1)
601                 return;
602
603         cells_type tmpcells;
604         vector<CellInfo> tmpcellinfo;
605         for (col_type i = 0; i < nargs(); ++i)
606                 if (i % ncols() != col) {
607                         tmpcells.push_back(cells_[i]);
608                         tmpcellinfo.push_back(cellinfo_[i]);
609                 }
610         swap(cells_, tmpcells);
611         swap(cellinfo_, tmpcellinfo);
612
613         colinfo_.erase(colinfo_.begin() + col);
614 }
615
616
617 int MathGridInset::cellXOffset(idx_type idx) const
618 {
619         col_type c = col(idx);
620         int x = colinfo_[c].offset_;
621         char align = colinfo_[c].align_;
622         if (align == 'r' || align == 'R')
623                 x += colinfo_[c].width_ - xcell(idx).width();
624         if (align == 'c' || align == 'C')
625                 x += (colinfo_[c].width_ - xcell(idx).width()) / 2;
626         return x;
627 }
628
629
630 int MathGridInset::cellYOffset(idx_type idx) const
631 {
632         return rowinfo_[row(idx)].offset_;
633 }
634
635
636 bool MathGridInset::idxUpDown(idx_type & idx, bool up) const
637 {
638         if (up) {
639                 if (idx < ncols())
640                         return false;
641                 idx -= ncols();
642                 return true;
643         } else {
644                 if (idx >= ncols() * (nrows() - 1))
645                         return false;
646                 idx += ncols();
647                 return true;
648         }
649 }
650
651
652 bool MathGridInset::idxLeft(idx_type & idx, pos_type & pos) const
653 {
654         // leave matrix if on the left hand edge
655         if (col(idx) == 0)
656                 return false;
657         --idx;
658         pos = cell(idx).size();
659         return true;
660 }
661
662
663 bool MathGridInset::idxRight(idx_type & idx, pos_type & pos) const
664 {
665         // leave matrix if on the right hand edge
666         if (col(idx) + 1 == ncols())
667                 return false;
668         ++idx;
669         pos = 0;
670         return true;
671 }
672
673
674 bool MathGridInset::idxFirst(idx_type & idx, pos_type & pos) const
675 {
676         switch (v_align_) {
677                 case 't':
678                         idx = 0;
679                         break;
680                 case 'b':
681                         idx = (nrows() - 1) * ncols();
682                         break;
683                 default:
684                         idx = ((nrows() - 1) / 2) * ncols();
685         }
686         pos = 0;
687         return true;
688 }
689
690
691 bool MathGridInset::idxLast(idx_type & idx, pos_type & pos) const
692 {
693         switch (v_align_) {
694                 case 't':
695                         idx = ncols() - 1;
696                         break;
697                 case 'b':
698                         idx = nargs() - 1;
699                         break;
700                 default:
701                         idx = ((nrows() - 1) / 2 + 1) * ncols() - 1;
702         }
703         pos = cell(idx).size();
704         return true;
705 }
706
707
708 bool MathGridInset::idxHome(idx_type & idx, pos_type & pos) const
709 {
710         if (pos > 0) {
711                 pos = 0;
712                 return true;
713         }
714         if (col(idx) > 0) {
715                 idx -= idx % ncols();
716                 pos = 0;
717                 return true;
718         }
719         if (idx > 0) {
720                 idx = 0;
721                 pos = 0;
722                 return true;
723         }
724         return false;
725 }
726
727
728 bool MathGridInset::idxEnd(idx_type & idx, pos_type & pos) const
729 {
730         if (pos < cell(idx).size()) {
731                 pos = cell(idx).size();
732                 return true;
733         }
734         if (col(idx) < ncols() - 1) {
735                 idx = idx - idx % ncols() + ncols() - 1;
736                 pos = cell(idx).size();
737                 return true;
738         }
739         if (idx < nargs() - 1) {
740                 idx = nargs() - 1;
741                 pos = cell(idx).size();
742                 return true;
743         }
744         return false;
745 }
746
747
748 bool MathGridInset::idxDelete(idx_type & idx)
749 {
750         // nothing to do if we have just one row
751         if (nrows() == 1)
752                 return false;
753
754         // nothing to do if we are in the middle of the last row of the inset
755         if (idx + ncols() > nargs())
756                 return false;
757
758         // try to delete entire sequence of ncols() empty cells if possible
759         for (idx_type i = idx; i < idx + ncols(); ++i)
760                 if (cell(i).size())
761                         return false;
762
763         // move cells if necessary
764         for (idx_type i = index(row(idx), 0); i < idx; ++i)
765                 cell(i).swap(cell(i + ncols()));
766
767         delRow(row(idx));
768
769         if (idx >= nargs())
770                 idx = nargs() - 1;
771
772         // undo effect of Ctrl-Tab (i.e. pull next cell)
773         //if (idx + 1 != nargs())
774         //      cell(idx).swap(cell(idx + 1));
775
776         // we handled the event..
777         return true;
778 }
779
780
781 // reimplement old behaviour when pressing Delete in the last position
782 // of a cell
783 void MathGridInset::idxGlue(idx_type idx)
784 {
785         col_type c = col(idx);
786         if (c + 1 == ncols()) {
787                 if (row(idx) + 1 != nrows()) {
788                         for (col_type cc = 0; cc < ncols(); ++cc)
789                                 cell(idx).push_back(cell(idx + cc + 1));
790                         delRow(row(idx) + 1);
791                 }
792         } else {
793                 cell(idx).push_back(cell(idx + 1));
794                 for (col_type cc = c + 2; cc < ncols(); ++cc)
795                         cell(idx - c + cc - 1) = cell(idx - c + cc);
796                 cell(idx - c + ncols() - 1).erase();
797         }
798 }
799
800
801 MathGridInset::RowInfo const & MathGridInset::rowinfo(row_type row) const
802 {
803         return rowinfo_[row];
804 }
805
806
807 MathGridInset::RowInfo & MathGridInset::rowinfo(row_type row)
808 {
809         return rowinfo_[row];
810 }
811
812
813 vector<MathInset::idx_type>
814         MathGridInset::idxBetween(idx_type from, idx_type to) const
815 {
816         row_type r1 = min(row(from), row(to));
817         row_type r2 = max(row(from), row(to));
818         col_type c1 = min(col(from), col(to));
819         col_type c2 = max(col(from), col(to));
820         vector<idx_type> res;
821         for (row_type i = r1; i <= r2; ++i)
822                 for (col_type j = c1; j <= c2; ++j)
823                         res.push_back(index(i, j));
824         return res;
825 }
826
827
828
829 void MathGridInset::normalize(NormalStream & os) const
830 {
831         os << "[grid ";
832         for (row_type row = 0; row < nrows(); ++row) {
833                 os << "[row ";
834                 for (col_type col = 0; col < ncols(); ++col)
835                         os << "[cell " << cell(index(row, col)) << ']';
836                 os << ']';
837         }
838         os << ']';
839 }
840
841
842 void MathGridInset::mathmlize(MathMLStream & os) const
843 {
844         os << MTag("mtable");
845         for (row_type row = 0; row < nrows(); ++row) {
846                 os << MTag("mtr");
847                 for (col_type col = 0; col < ncols(); ++col)
848                         os << cell(index(row, col));
849                 os << ETag("mtr");
850         }
851         os << ETag("mtable");
852 }
853
854
855 void MathGridInset::write(WriteStream & os) const
856 {
857         for (row_type row = 0; row < nrows(); ++row) {
858                 os << verboseHLine(rowinfo_[row].lines_);
859                 for (col_type col = 0; col < ncols(); ++col)
860                         os << cell(index(row, col)) << eocString(col);
861                 os << eolString(row, os.fragile());
862         }
863         string const s = verboseHLine(rowinfo_[nrows()].lines_);
864         if (!s.empty() && s != " ") {
865                 if (os.fragile())
866                         os << "\\protect";
867                 os << "\\\\" << s;
868         }
869 }
870
871
872 int MathGridInset::colsep() const
873 {
874         return 6;
875 }
876
877
878 int MathGridInset::rowsep() const
879 {
880         return 6;
881 }
882
883
884 int MathGridInset::hlinesep() const
885 {
886         return 3;
887 }
888
889
890 int MathGridInset::vlinesep() const
891 {
892         return 3;
893 }
894
895
896 int MathGridInset::border() const
897 {
898         return 1;
899 }
900