]> git.lyx.org Git - lyx.git/blob - src/mathed/math_gridinset.C
don't #include too much stuff in .h
[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 "lyxfont.h"
8 #include "debug.h"
9
10
11 namespace {
12
13 ///
14 int const MATH_COLSEP = 10;
15 ///
16 int const MATH_ROWSEP = 10;
17 ///
18 int const MATH_BORDER = 2;
19
20 }
21
22
23 ////////////////////////////////////////////////////////////// 
24
25
26 MathGridInset::RowInfo::RowInfo()
27         : upperline_(false), lowerline_(false)
28 {}
29
30
31
32 int MathGridInset::RowInfo::skipPixels() const
33 {
34 #ifdef WITH_WARNINGS
35 #warning fix this once the interface to LyXLength has improved
36 #endif
37         return int(skip_.value());
38 }
39
40
41
42 ////////////////////////////////////////////////////////////// 
43
44
45 MathGridInset::ColInfo::ColInfo()
46         : align_('c'), leftline_(false), rightline_(false), skip_(MATH_COLSEP)
47 {}
48
49
50 ////////////////////////////////////////////////////////////// 
51
52
53 MathGridInset::MathGridInset(col_type m, row_type n)
54         : MathNestInset(m * n), rowinfo_(n), colinfo_(m), v_align_('c')
55 {
56         setDefaults();
57 }
58
59
60 MathGridInset::MathGridInset(int m, int n, char v, string const & h)
61         : MathNestInset(m * n), rowinfo_(n), colinfo_(m), v_align_(v)
62 {
63         setDefaults();
64         valign(v);
65         halign(h);
66 }
67
68
69 MathInset::idx_type MathGridInset::index(row_type row, col_type col) const
70 {
71         return col + ncols() * row;
72 }
73
74
75 void MathGridInset::setDefaults()
76 {
77         if (ncols() <= 0)
78                 lyxerr << "positve number of columns expected\n";
79         if (nrows() <= 0)
80                 lyxerr << "positve number of rows expected\n";
81         for (col_type col = 0; col < ncols(); ++col) {
82                 colinfo_[col].align_ = defaultColAlign(col);
83                 colinfo_[col].skip_  = defaultColSpace(col);
84         }
85 }
86
87
88 void MathGridInset::halign(string const & hh)
89 {
90         col_type n = hh.size();
91         if (n > ncols())
92                 n = ncols();
93         for (col_type col = 0; col < n; ++col)
94                 colinfo_[col].align_ = hh[col];
95 }
96
97
98 void MathGridInset::halign(char h, col_type col)
99 {
100         colinfo_[col].align_ = h;
101 }
102
103
104 char MathGridInset::halign(col_type col) const
105 {
106         return colinfo_[col].align_;
107 }
108
109
110
111 void MathGridInset::valign(char c)
112 {
113         v_align_ = c;
114 }
115
116
117 char MathGridInset::valign() const
118 {
119         return v_align_;
120 }
121
122
123
124 void MathGridInset::vskip(LyXLength const & skip, row_type row)
125 {
126         rowinfo_[row].skip_ = skip;
127 }
128
129
130 LyXLength MathGridInset::vskip(row_type row) const
131 {
132         return rowinfo_[row].skip_;
133 }
134
135
136 void MathGridInset::metrics(MathMetricsInfo const & mi) const
137 {
138         // let the cells adjust themselves
139         MathNestInset::metrics(mi);
140
141         // adjust vertical structure
142         for (row_type row = 0; row < nrows(); ++row) {
143                 int asc  = 0;
144                 int desc = 0;
145                 for (col_type col = 0; col < ncols(); ++col) {
146                         MathXArray const & c = xcell(index(row, col));
147                         asc  = std::max(asc,  c.ascent());
148                         desc = std::max(desc, c.descent());
149                 }
150                 rowinfo_[row].ascent_  = asc;
151                 rowinfo_[row].descent_ = desc;
152
153                 if (row) 
154                         rowinfo_[row].offset_ = 
155                                 rowinfo_[row - 1].offset_ +
156                                 rowinfo_[row - 1].descent_ +
157                                 rowinfo_[row - 1].skipPixels() +
158                                 MATH_ROWSEP +
159                                 rowinfo_[row].ascent_;
160                 else 
161                         rowinfo_[row].offset_ = 0;
162         }
163
164         // adjust vertical offset
165         int h = 0;
166         switch (v_align_) {
167         case 't':
168                 h = 0;
169                 break;
170         case 'b':
171                 h = rowinfo_.back().offset_;
172                 break;
173         default:
174                 h = rowinfo_.back().offset_ / 2;
175         }
176
177         for (row_type row = 0; row < nrows(); ++row) {
178                 rowinfo_[row].offset_ -= h;
179                 rowinfo_[row].offset_ += MATH_BORDER;
180         }
181         
182         // adjust horizontal structure
183         for (col_type col = 0; col < ncols(); ++col) {
184                 int wid  = 0;
185                 for (row_type row = 0; row < nrows(); ++row) 
186                         wid = std::max(wid, xcell(index(row, col)).width());
187                 colinfo_[col].width_  = wid;
188                 colinfo_[col].offset_ = colinfo_[col].width_;
189
190                 if (col) 
191                         colinfo_[col].offset_ =
192                                 colinfo_[col - 1].offset_ +
193                                 colinfo_[col - 1].width_ + 
194                                 colinfo_[col - 1].skip_;
195                 else
196                         colinfo_[col].offset_ = 0;
197
198                 colinfo_[col].offset_ += MATH_BORDER;
199         }
200
201         width_   =   colinfo_.back().offset_  + colinfo_.back().width_;
202         ascent_  = - rowinfo_.front().offset_ + rowinfo_.front().ascent_;
203         descent_ =   rowinfo_.back().offset_  + rowinfo_.back().descent_;
204         
205 /*      
206         // Increase ws_[i] for 'R' columns (except the first one)
207         for (int i = 1; i < nc_; ++i)
208                 if (align_[i] == 'R')
209                         ws_[i] += 10 * df_width;
210         // Increase ws_[i] for 'C' column
211         if (align_[0] == 'C')
212                 if (ws_[0] < 7 * workwidth / 8)
213                         ws_[0] = 7 * workwidth / 8;
214         
215         // Adjust local tabs
216         width = MATH_COLSEP;
217         for (cxrow = row_.begin(); cxrow; ++cxrow) {   
218                 int rg = MATH_COLSEP;
219                 int lf = 0;
220                 for (int i = 0; i < nc_; ++i) {
221                         bool isvoid = false;
222                         if (cxrow->getTab(i) <= 0) {
223                                 cxrow->setTab(i, df_width);
224                                 isvoid = true;
225                         }
226                         switch (align_[i]) {
227                         case 'l':
228                                 lf = 0;
229                                 break;
230                         case 'c':
231                                 lf = (ws_[i] - cxrow->getTab(i))/2; 
232                                 break;
233                         case 'r':
234                         case 'R':
235                                 lf = ws_[i] - cxrow->getTab(i);
236                                 break;
237                         case 'C':
238                                 if (cxrow == row_.begin())
239                                         lf = 0;
240                                 else if (cxrow.is_last())
241                                         lf = ws_[i] - cxrow->getTab(i);
242                                 else
243                                         lf = (ws_[i] - cxrow->getTab(i))/2; 
244                                 break;
245                         }
246                         int const ww = (isvoid) ? lf : lf + cxrow->getTab(i);
247                         cxrow->setTab(i, lf + rg);
248                         rg = ws_[i] - ww + MATH_COLSEP;
249                         if (cxrow == row_.begin())
250                                 width += ws_[i] + MATH_COLSEP;
251                 }
252                 cxrow->setBaseline(cxrow->getBaseline() - ascent);
253         }
254 */
255 }
256
257
258 void MathGridInset::draw(Painter & pain, int x, int y) const
259 {
260         for (idx_type idx = 0; idx < nargs(); ++idx)
261                 xcell(idx).draw(pain, x + cellXOffset(idx), y + cellYOffset(idx));
262 }
263
264
265 void MathGridInset::write(MathWriteInfo & os) const
266 {
267         for (row_type row = 0; row < nrows(); ++row) {
268                 for (col_type col = 0; col < ncols(); ++col) 
269                         os << cell(index(row, col)) << eocString(col).c_str();
270                 os << eolString(row).c_str();
271         }
272 }
273
274
275 void MathGridInset::writeNormal(NormalStream & os) const
276 {
277         os << "[grid ";
278         for (row_type row = 0; row < nrows(); ++row) {
279                 os << "[row ";
280                 for (col_type col = 0; col < ncols(); ++col)
281                         os << "[cell " << cell(index(row, col)) << ']';
282                 os << ']';
283         }
284         os << ']';
285 }
286
287
288 string MathGridInset::eolString(row_type row) const
289 {
290         if (row + 1 == nrows()) 
291                 return "";
292
293         if (rowinfo_[row].skip_.value() != 0)
294                 return "\\\\[" + rowinfo_[row].skip_.asLatexString() + "]\n";
295
296         // make sure an upcoming '[' does not break anything
297         MathArray const & c = cell(index(row + 1, 0));
298         if (c.size() && (*c.begin())->getChar() == '[')
299                 return "\\\\[0pt]\n";
300
301         return "\\\\\n";
302 }
303
304
305 string MathGridInset::eocString(col_type col) const
306 {
307         if (col + 1 == ncols())
308                 return "";
309         return " & ";
310 }
311
312
313 void MathGridInset::addRow(row_type row)
314 {
315         rowinfo_.insert(rowinfo_.begin() + row + 1, RowInfo());
316         cells_.insert(cells_.begin() + (row + 1) * ncols(), ncols(), MathXArray());
317 }
318
319
320 void MathGridInset::appendRow()
321 {
322         rowinfo_.push_back(RowInfo());
323         for (col_type col = 0; col < ncols(); ++col)
324                 cells_.push_back(cells_type::value_type());
325 }
326
327
328 void MathGridInset::delRow(row_type row)
329 {
330         if (nrows() == 1)
331                 return;
332
333         cells_type::iterator it = cells_.begin() + row * ncols(); 
334         cells_.erase(it, it + ncols());
335
336         rowinfo_.erase(rowinfo_.begin() + row);
337 }
338
339
340 void MathGridInset::addCol(col_type newcol)
341 {
342         const col_type nc = ncols();
343         const row_type nr = nrows();
344         cells_type new_cells((nc + 1) * nr);
345         
346         for (row_type row = 0; row < nr; ++row)
347                 for (col_type col = 0; col < nc; ++col)
348                         new_cells[row * (nc + 1) + col + (col > newcol)]
349                                 = cells_[row * nc + col];
350         std::swap(cells_, new_cells);
351
352         ColInfo inf;
353         inf.skip_  = defaultColSpace(newcol);
354         inf.align_ = defaultColAlign(newcol);
355         colinfo_.insert(colinfo_.begin() + newcol, inf);
356 }
357
358
359 void MathGridInset::delCol(col_type col)
360 {
361         if (ncols() == 1)
362                 return;
363
364         cells_type tmpcells;
365         for (col_type i = 0; i < nargs(); ++i) 
366                 if (i % ncols() != col)
367                         tmpcells.push_back(cells_[i]);
368         std::swap(cells_, tmpcells);
369
370         colinfo_.erase(colinfo_.begin() + col);
371 }
372
373
374 int MathGridInset::cellXOffset(idx_type idx) const
375 {
376         col_type c = col(idx);
377         int x = colinfo_[c].offset_;
378         char align = colinfo_[c].align_;
379         if (align == 'r' || align == 'R')
380                 x += colinfo_[c].width_ - xcell(idx).width(); 
381         if (align == 'c' || align == 'C')
382                 x += (colinfo_[c].width_ - xcell(idx).width()) / 2; 
383         return x;
384 }
385
386
387 int MathGridInset::cellYOffset(idx_type idx) const
388 {
389         return rowinfo_[row(idx)].offset_;
390 }
391
392
393 bool MathGridInset::idxUp(idx_type & idx, pos_type & pos) const
394 {
395         if (idx < ncols())
396                 return false;
397         int x = cellXOffset(idx) + xcell(idx).pos2x(pos);
398         idx -= ncols();
399         pos = xcell(idx).x2pos(x - cellXOffset(idx));
400         return true;
401 }
402
403         
404 bool MathGridInset::idxDown(idx_type & idx, pos_type & pos) const
405 {
406         if (idx >= ncols() * (nrows() - 1))
407                 return false;
408         int x = cellXOffset(idx) + xcell(idx).pos2x(pos);
409         idx += ncols();
410         pos = xcell(idx).x2pos(x - cellXOffset(idx));
411         return true;
412 }
413         
414         
415 bool MathGridInset::idxLeft(idx_type & idx, pos_type & pos) const
416 {
417         // leave matrix if on the left hand edge
418         if (col(idx) == 0)
419                 return false;
420         idx--;
421         pos = cell(idx).size();
422         return true;
423 }
424         
425         
426 bool MathGridInset::idxRight(idx_type & idx, pos_type & pos) const
427 {
428         // leave matrix if on the right hand edge
429         if (col(idx) == ncols() - 1)
430                 return false;
431         idx++;
432         pos = 0;
433         return true;
434 }
435
436
437 bool MathGridInset::idxFirst(idx_type & idx, pos_type & pos) const
438 {
439         switch (v_align_) {
440                 case 't':
441                         idx = 0;
442                         break;
443                 case 'b':
444                         idx = (nrows() - 1) * ncols();
445                         break;
446                 default: 
447                         idx = (nrows() / 2) * ncols();
448         }
449         pos = 0;
450         return true;
451 }
452
453
454 bool MathGridInset::idxLast(idx_type & idx, pos_type & pos) const
455 {
456         switch (v_align_) {
457                 case 't':
458                         idx = ncols() - 1;
459                         break;
460                 case 'b':
461                         idx = nargs() - 1;
462                         break;
463                 default:
464                         idx = (nrows() / 2 + 1) * ncols() - 1;
465         }
466         pos = cell(idx).size();
467         return true;
468 }
469
470
471 bool MathGridInset::idxHome(idx_type & idx, pos_type & pos) const
472 {
473         if (pos > 0) {
474                 pos = 0;
475                 return true;
476         }
477         if (col(idx) > 0) {
478                 idx -= idx % ncols();
479                 pos = 0;
480                 return true;
481         }
482         if (idx > 0) {
483                 idx = 0;
484                 pos = 0;
485                 return true;
486         }
487         return false;
488 }
489
490
491 bool MathGridInset::idxEnd(idx_type & idx, pos_type & pos) const
492 {
493         if (pos < cell(idx).size()) {
494                 pos = cell(idx).size();
495                 return true;
496         }
497         if (col(idx) < ncols() - 1) {
498                 idx = idx - idx % ncols() + ncols() - 1;
499                 pos = cell(idx).size();
500                 return true;
501         }
502         if (idx < nargs() - 1) {
503                 idx = nargs() - 1;
504                 pos = cell(idx).size();
505                 return true;
506         }
507         return false;
508 }
509
510
511 void MathGridInset::idxDelete(idx_type & idx, bool & popit, bool & deleteit)
512 {
513         popit    = false;
514         deleteit = false;
515
516         // delete entire sequence of ncols() empty cells if possible
517         if (idx <= index(nrows() - 1, 0))       {
518                 bool deleterow = true;
519                 for (idx_type i = idx; i < idx + ncols(); ++i)
520                         if (cell(i).size()) {
521                                 deleterow = false;
522                                 break;
523                         }
524
525                 if (deleterow) {
526                         // move cells if necessary
527                         for (idx_type i = index(row(idx), 0); i < idx; ++i)
528                                 cell(i).swap(cell(i + ncols()));
529                         
530                         delRow(row(idx));
531
532                         if (idx >= nargs())
533                                 idx = nargs() - 1;
534                         return;
535                 }
536         }
537
538         // undo effect of Ctrl-Tab (i.e. pull next cell)
539         //if (idx != nargs() - 1) 
540         //      cell(idx).swap(cell(idx + 1));
541 }
542
543
544 void MathGridInset::idxDeleteRange(idx_type /*from*/, idx_type /*to*/)
545 {
546 // leave this unimplemented unless someone wants to have it.
547 /*
548         int n = (to - from) / ncols();
549         int r = from / ncols();
550
551         if (n >= 1) {
552                 cells_type::iterator it = cells_.begin() + from;
553                 cells_.erase(it, it + n * ncols());
554                 rowinfo_.erase(rowinfo_.begin() + r, rowinfo_.begin() + r + n);
555         }
556 */
557 }
558
559
560 MathGridInset::RowInfo const & MathGridInset::rowinfo(row_type row) const
561 {
562         return rowinfo_[row];
563 }
564
565
566 MathGridInset::RowInfo & MathGridInset::rowinfo(row_type row)
567 {
568         return rowinfo_[row];
569 }
570
571
572 std::vector<MathInset::idx_type>
573         MathGridInset::idxBetween(idx_type from, idx_type to) const
574 {
575         row_type r1 = std::min(row(from), row(to));
576         row_type r2 = std::max(row(from), row(to));
577         col_type c1 = std::min(col(from), col(to));
578         col_type c2 = std::max(col(from), col(to));
579         std::vector<idx_type> res;
580         for (row_type i = r1; i <= r2; ++i)
581                 for (col_type j = c1; j <= c2; ++j)
582                         res.push_back(index(i, j));
583         return res;
584 }
585
586
587 void MathGridInset::maplize(MapleStream & os) const
588 {
589         os << "array([";
590         for (row_type row = 0; row < nrows(); ++row) {
591                 if (row)
592                         os << ',';
593                 os << '[';
594                 for (col_type col = 0; col < ncols(); ++col) {
595                         if (col)
596                                 os << ',';
597                         os << cell(index(row, col));
598                 }
599                 os << ']';
600         }
601         os << "])";
602 }
603
604
605 void MathGridInset::mathmlize(MathMLStream & os) const
606 {
607         os << MTag("mtable");
608         for (row_type row = 0; row < nrows(); ++row) {
609                 os << MTag("mtr");
610                 for (col_type col = 0; col < ncols(); ++col) 
611                         os << cell(index(row, col));
612                 os << ETag("mtr");
613         }
614         os << ETag("mtable");
615 }
616
617
618 void MathGridInset::octavize(OctaveStream & os) const
619 {
620         os << '[';
621         for (row_type row = 0; row < nrows(); ++row) {
622                 if (row)
623                         os << ';';
624                 os << '[';
625                 for (col_type col = 0; col < ncols(); ++col) 
626                         os << cell(index(row, col)) << ' ';
627                 os << ']';
628         }
629         os << ']';
630 }