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