]> git.lyx.org Git - lyx.git/blob - src/mathed/math_gridinset.C
use stream-like syntax for LaTeX output
[lyx.git] / src / mathed / math_gridinset.C
1 #ifdef __GNUG__
2 #pragma implementation
3 #endif
4
5 #include "math_gridinset.h"
6 #include "support/LOstream.h"
7 #include "debug.h"
8
9
10 namespace {
11
12 ///
13 int const MATH_COLSEP = 10;
14 ///
15 int const MATH_ROWSEP = 10;
16 ///
17 int const MATH_BORDER = 2;
18
19 }
20
21
22 ////////////////////////////////////////////////////////////// 
23
24
25 MathGridInset::RowInfo::RowInfo()
26         : upperline_(false), lowerline_(false)
27 {}
28
29
30
31 int MathGridInset::RowInfo::skipPixels() const
32 {
33 #ifdef WITH_WARNINGS
34 #warning fix this once the interface to LyXLength has improved
35 #endif
36         return int(skip_.value());
37 }
38
39
40
41 ////////////////////////////////////////////////////////////// 
42
43
44 MathGridInset::ColInfo::ColInfo()
45         : align_('c'), leftline_(false), rightline_(false), skip_(MATH_COLSEP)
46 {}
47
48
49 ////////////////////////////////////////////////////////////// 
50
51
52 MathGridInset::MathGridInset(col_type m, row_type n)
53         : MathNestInset(m * n), rowinfo_(n), colinfo_(m), v_align_('c')
54 {
55         setDefaults();
56 }
57
58
59 MathGridInset::MathGridInset(int m, int n, char v, string const & h)
60         : MathNestInset(m * n), rowinfo_(n), colinfo_(m), v_align_(v)
61 {
62         setDefaults();
63         valign(v);
64         halign(h);
65 }
66
67
68 MathInset::idx_type MathGridInset::index(row_type row, col_type col) const
69 {
70         return col + ncols() * row;
71 }
72
73
74 void MathGridInset::setDefaults()
75 {
76         if (ncols() <= 0)
77                 lyxerr << "positve number of columns expected\n";
78         if (nrows() <= 0)
79                 lyxerr << "positve number of rows expected\n";
80         for (col_type col = 0; col < ncols(); ++col) {
81                 colinfo_[col].align_ = defaultColAlign(col);
82                 colinfo_[col].skip_  = defaultColSpace(col);
83         }
84 }
85
86
87 void MathGridInset::halign(string const & hh)
88 {
89         col_type n = hh.size();
90         if (n > ncols())
91                 n = ncols();
92         for (col_type col = 0; col < n; ++col)
93                 colinfo_[col].align_ = hh[col];
94 }
95
96
97 void MathGridInset::halign(char h, col_type col)
98 {
99         colinfo_[col].align_ = h;
100 }
101
102
103 char MathGridInset::halign(col_type col) const
104 {
105         return colinfo_[col].align_;
106 }
107
108
109
110 void MathGridInset::valign(char c)
111 {
112         v_align_ = c;
113 }
114
115
116 char MathGridInset::valign() const
117 {
118         return v_align_;
119 }
120
121
122
123 void MathGridInset::vskip(LyXLength const & skip, row_type row)
124 {
125         rowinfo_[row].skip_ = skip;
126 }
127
128
129 LyXLength MathGridInset::vskip(row_type row) const
130 {
131         return rowinfo_[row].skip_;
132 }
133
134
135 void MathGridInset::metrics(MathMetricsInfo const & st) const
136 {
137         // let the cells adjust themselves
138         MathNestInset::metrics(st);
139         size_ = st;
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         xo(x);
261         yo(y);
262         for (idx_type idx = 0; idx < nargs(); ++idx)
263                 xcell(idx).draw(pain, x + cellXOffset(idx), y + cellYOffset(idx));
264 }
265
266
267 void MathGridInset::write(MathWriteInfo & os) const
268 {
269         for (row_type row = 0; row < nrows(); ++row) {
270                 for (col_type col = 0; col < ncols(); ++col) 
271                         os << cell(index(row, col)) << eocString(col);
272                 os << eolString(row);
273         }
274 }
275
276
277 void MathGridInset::writeNormal(std::ostream & os) const
278 {
279         os << "[grid ";
280         for (row_type row = 0; row < nrows(); ++row) {
281                 os << "[row ";
282                 for (col_type col = 0; col < ncols(); ++col) {
283                         os << "[cell ";
284                         cell(index(row, col)).writeNormal(os);
285                         os << "]";
286                 }
287                 os << "]";
288         }
289         os << "]";
290 }
291
292
293 string MathGridInset::eolString(row_type row) const
294 {
295         if (row + 1 == nrows()) 
296                 return "";
297
298         if (rowinfo_[row].skip_.value() != 0)
299                 return "\\\\[" + rowinfo_[row].skip_.asLatexString() + "]\n";
300
301         // make sure an upcoming '[' does not break anything
302         MathArray const & c = cell(index(row + 1, 0));
303         if (c.size() && (*c.begin())->getChar() == '[')
304                 return "\\\\[0pt]\n";
305
306         return "\\\\\n";
307 }
308
309
310 string MathGridInset::eocString(col_type col) const
311 {
312         if (col + 1 == ncols())
313                 return "";
314         return " & ";
315 }
316
317
318 void MathGridInset::addRow(row_type row)
319 {
320         rowinfo_.insert(rowinfo_.begin() + row + 1, RowInfo());
321         cells_.insert(cells_.begin() + (row + 1) * ncols(), ncols(), MathXArray());
322 }
323
324
325 void MathGridInset::appendRow()
326 {
327         rowinfo_.push_back(RowInfo());
328         for (col_type col = 0; col < ncols(); ++col)
329                 cells_.push_back(cells_type::value_type());
330 }
331
332
333 void MathGridInset::delRow(row_type row)
334 {
335         if (nrows() == 1)
336                 return;
337
338         cells_type::iterator it = cells_.begin() + row * ncols(); 
339         cells_.erase(it, it + ncols());
340
341         rowinfo_.erase(rowinfo_.begin() + row);
342 }
343
344
345 void MathGridInset::addCol(col_type newcol)
346 {
347         const col_type nc = ncols();
348         const row_type nr = nrows();
349         cells_type new_cells((nc + 1) * nr);
350         
351         for (row_type row = 0; row < nr; ++row)
352                 for (col_type col = 0; col < nc; ++col)
353                         new_cells[row * (nc + 1) + col + (col > newcol)]
354                                 = cells_[row * nc + col];
355         std::swap(cells_, new_cells);
356
357         ColInfo inf;
358         inf.skip_  = defaultColSpace(newcol);
359         inf.align_ = defaultColAlign(newcol);
360         colinfo_.insert(colinfo_.begin() + newcol, inf);
361 }
362
363
364 void MathGridInset::delCol(col_type col)
365 {
366         if (ncols() == 1)
367                 return;
368
369         cells_type tmpcells;
370         for (col_type i = 0; i < nargs(); ++i) 
371                 if (i % ncols() != col)
372                         tmpcells.push_back(cells_[i]);
373         std::swap(cells_, tmpcells);
374
375         colinfo_.erase(colinfo_.begin() + col);
376 }
377
378
379 int MathGridInset::cellXOffset(idx_type idx) const
380 {
381         col_type c = col(idx);
382         int x = colinfo_[c].offset_;
383         char align = colinfo_[c].align_;
384         if (align == 'r' || align == 'R')
385                 x += colinfo_[c].width_ - xcell(idx).width(); 
386         if (align == 'c' || align == 'C')
387                 x += (colinfo_[c].width_ - xcell(idx).width()) / 2; 
388         return x;
389 }
390
391
392 int MathGridInset::cellYOffset(idx_type idx) const
393 {
394         return rowinfo_[row(idx)].offset_;
395 }
396
397
398 bool MathGridInset::idxUp(idx_type & idx, pos_type & pos) const
399 {
400         if (idx < ncols())
401                 return false;
402         int x = cellXOffset(idx) + xcell(idx).pos2x(pos);
403         idx -= ncols();
404         pos = xcell(idx).x2pos(x - cellXOffset(idx));
405         return true;
406 }
407
408         
409 bool MathGridInset::idxDown(idx_type & idx, pos_type & pos) const
410 {
411         if (idx >= ncols() * (nrows() - 1))
412                 return false;
413         int x = cellXOffset(idx) + xcell(idx).pos2x(pos);
414         idx += ncols();
415         pos = xcell(idx).x2pos(x - cellXOffset(idx));
416         return true;
417 }
418         
419         
420 bool MathGridInset::idxLeft(idx_type & idx, pos_type & pos) const
421 {
422         // leave matrix if on the left hand edge
423         if (col(idx) == 0)
424                 return false;
425         idx--;
426         pos = cell(idx).size();
427         return true;
428 }
429         
430         
431 bool MathGridInset::idxRight(idx_type & idx, pos_type & pos) const
432 {
433         // leave matrix if on the right hand edge
434         if (col(idx) == ncols() - 1)
435                 return false;
436         idx++;
437         pos = 0;
438         return true;
439 }
440
441
442 bool MathGridInset::idxFirst(idx_type & idx, pos_type & pos) const
443 {
444         switch (v_align_) {
445                 case 't':
446                         idx = 0;
447                         break;
448                 case 'b':
449                         idx = (nrows() - 1) * ncols();
450                         break;
451                 default: 
452                         idx = (nrows() / 2) * ncols();
453         }
454         pos = 0;
455         return true;
456 }
457
458
459 bool MathGridInset::idxLast(idx_type & idx, pos_type & pos) const
460 {
461         switch (v_align_) {
462                 case 't':
463                         idx = ncols() - 1;
464                         break;
465                 case 'b':
466                         idx = nargs() - 1;
467                         break;
468                 default:
469                         idx = (nrows() / 2 + 1) * ncols() - 1;
470         }
471         pos = cell(idx).size();
472         return true;
473 }
474
475
476 void MathGridInset::idxDelete(idx_type & idx, bool & popit, bool & deleteit)
477 {
478         popit    = false;
479         deleteit = false;
480
481         // delete entire sequence of ncols() empty cells if possible
482         if (idx <= index(nrows() - 1, 0))       {
483                 bool deleterow = true;
484                 for (idx_type i = idx; i < idx + ncols(); ++i)
485                         if (cell(i).size()) {
486                                 deleterow = false;
487                                 break;
488                         }
489
490                 if (deleterow) {
491                         // move cells if necessary
492                         for (idx_type i = index(row(idx), 0); i < idx; ++i)
493                                 cell(i).swap(cell(i + ncols()));
494                         
495                         delRow(row(idx));
496
497                         if (idx >= nargs())
498                                 idx = nargs() - 1;
499                         return;
500                 }
501         }
502
503         // undo effect of Ctrl-Tab (i.e. pull next cell)
504         //if (idx != nargs() - 1) 
505         //      cell(idx).swap(cell(idx + 1));
506 }
507
508
509 void MathGridInset::idxDeleteRange(idx_type /*from*/, idx_type /*to*/)
510 {
511 // leave this unimplemented unless someone wants to have it.
512 /*
513         int n = (to - from) / ncols();
514         int r = from / ncols();
515
516         if (n >= 1) {
517                 cells_type::iterator it = cells_.begin() + from;
518                 cells_.erase(it, it + n * ncols());
519                 rowinfo_.erase(rowinfo_.begin() + r, rowinfo_.begin() + r + n);
520         }
521 */
522 }
523
524
525 MathGridInset::RowInfo const & MathGridInset::rowinfo(row_type row) const
526 {
527         return rowinfo_[row];
528 }
529
530
531 MathGridInset::RowInfo & MathGridInset::rowinfo(row_type row)
532 {
533         return rowinfo_[row];
534 }
535
536
537 std::vector<MathInset::idx_type>
538         MathGridInset::idxBetween(idx_type from, idx_type to) const
539 {
540         row_type r1 = std::min(row(from), row(to));
541         row_type r2 = std::max(row(from), row(to));
542         col_type c1 = std::min(col(from), col(to));
543         col_type c2 = std::max(col(from), col(to));
544         std::vector<idx_type> res;
545         for (row_type i = r1; i <= r2; ++i)
546                 for (col_type j = c1; j <= c2; ++j)
547                         res.push_back(index(i, j));
548         return res;
549 }