]> git.lyx.org Git - lyx.git/blob - src/mathed/math_gridinset.C
change output to uses streams instead of strings
[lyx.git] / src / mathed / math_gridinset.C
1 #ifdef __GNUG__
2 #pragma implementation
3 #endif
4
5 #include "math_gridinset.h"
6 #include "lyxfont.h"
7 #include "support/LOstream.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);
270                 os << eolString(row);
271         }
272 }
273
274
275 void MathGridInset::writeNormal(std::ostream & 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 ";
282                         cell(index(row, col)).writeNormal(os);
283                         os << "]";
284                 }
285                 os << "]";
286         }
287         os << "]";
288 }
289
290
291 string MathGridInset::eolString(row_type row) const
292 {
293         if (row + 1 == nrows()) 
294                 return "";
295
296         if (rowinfo_[row].skip_.value() != 0)
297                 return "\\\\[" + rowinfo_[row].skip_.asLatexString() + "]\n";
298
299         // make sure an upcoming '[' does not break anything
300         MathArray const & c = cell(index(row + 1, 0));
301         if (c.size() && (*c.begin())->getChar() == '[')
302                 return "\\\\[0pt]\n";
303
304         return "\\\\\n";
305 }
306
307
308 string MathGridInset::eocString(col_type col) const
309 {
310         if (col + 1 == ncols())
311                 return "";
312         return " & ";
313 }
314
315
316 void MathGridInset::addRow(row_type row)
317 {
318         rowinfo_.insert(rowinfo_.begin() + row + 1, RowInfo());
319         cells_.insert(cells_.begin() + (row + 1) * ncols(), ncols(), MathXArray());
320 }
321
322
323 void MathGridInset::appendRow()
324 {
325         rowinfo_.push_back(RowInfo());
326         for (col_type col = 0; col < ncols(); ++col)
327                 cells_.push_back(cells_type::value_type());
328 }
329
330
331 void MathGridInset::delRow(row_type row)
332 {
333         if (nrows() == 1)
334                 return;
335
336         cells_type::iterator it = cells_.begin() + row * ncols(); 
337         cells_.erase(it, it + ncols());
338
339         rowinfo_.erase(rowinfo_.begin() + row);
340 }
341
342
343 void MathGridInset::addCol(col_type newcol)
344 {
345         const col_type nc = ncols();
346         const row_type nr = nrows();
347         cells_type new_cells((nc + 1) * nr);
348         
349         for (row_type row = 0; row < nr; ++row)
350                 for (col_type col = 0; col < nc; ++col)
351                         new_cells[row * (nc + 1) + col + (col > newcol)]
352                                 = cells_[row * nc + col];
353         std::swap(cells_, new_cells);
354
355         ColInfo inf;
356         inf.skip_  = defaultColSpace(newcol);
357         inf.align_ = defaultColAlign(newcol);
358         colinfo_.insert(colinfo_.begin() + newcol, inf);
359 }
360
361
362 void MathGridInset::delCol(col_type col)
363 {
364         if (ncols() == 1)
365                 return;
366
367         cells_type tmpcells;
368         for (col_type i = 0; i < nargs(); ++i) 
369                 if (i % ncols() != col)
370                         tmpcells.push_back(cells_[i]);
371         std::swap(cells_, tmpcells);
372
373         colinfo_.erase(colinfo_.begin() + col);
374 }
375
376
377 int MathGridInset::cellXOffset(idx_type idx) const
378 {
379         col_type c = col(idx);
380         int x = colinfo_[c].offset_;
381         char align = colinfo_[c].align_;
382         if (align == 'r' || align == 'R')
383                 x += colinfo_[c].width_ - xcell(idx).width(); 
384         if (align == 'c' || align == 'C')
385                 x += (colinfo_[c].width_ - xcell(idx).width()) / 2; 
386         return x;
387 }
388
389
390 int MathGridInset::cellYOffset(idx_type idx) const
391 {
392         return rowinfo_[row(idx)].offset_;
393 }
394
395
396 bool MathGridInset::idxUp(idx_type & idx, pos_type & pos) const
397 {
398         if (idx < ncols())
399                 return false;
400         int x = cellXOffset(idx) + xcell(idx).pos2x(pos);
401         idx -= ncols();
402         pos = xcell(idx).x2pos(x - cellXOffset(idx));
403         return true;
404 }
405
406         
407 bool MathGridInset::idxDown(idx_type & idx, pos_type & pos) const
408 {
409         if (idx >= ncols() * (nrows() - 1))
410                 return false;
411         int x = cellXOffset(idx) + xcell(idx).pos2x(pos);
412         idx += ncols();
413         pos = xcell(idx).x2pos(x - cellXOffset(idx));
414         return true;
415 }
416         
417         
418 bool MathGridInset::idxLeft(idx_type & idx, pos_type & pos) const
419 {
420         // leave matrix if on the left hand edge
421         if (col(idx) == 0)
422                 return false;
423         idx--;
424         pos = cell(idx).size();
425         return true;
426 }
427         
428         
429 bool MathGridInset::idxRight(idx_type & idx, pos_type & pos) const
430 {
431         // leave matrix if on the right hand edge
432         if (col(idx) == ncols() - 1)
433                 return false;
434         idx++;
435         pos = 0;
436         return true;
437 }
438
439
440 bool MathGridInset::idxFirst(idx_type & idx, pos_type & pos) const
441 {
442         switch (v_align_) {
443                 case 't':
444                         idx = 0;
445                         break;
446                 case 'b':
447                         idx = (nrows() - 1) * ncols();
448                         break;
449                 default: 
450                         idx = (nrows() / 2) * ncols();
451         }
452         pos = 0;
453         return true;
454 }
455
456
457 bool MathGridInset::idxLast(idx_type & idx, pos_type & pos) const
458 {
459         switch (v_align_) {
460                 case 't':
461                         idx = ncols() - 1;
462                         break;
463                 case 'b':
464                         idx = nargs() - 1;
465                         break;
466                 default:
467                         idx = (nrows() / 2 + 1) * ncols() - 1;
468         }
469         pos = cell(idx).size();
470         return true;
471 }
472
473
474 bool MathGridInset::idxHome(idx_type & idx, pos_type & pos) const
475 {
476         if (pos > 0) {
477                 pos = 0;
478                 return true;
479         }
480         if (col(idx) > 0) {
481                 idx -= idx % ncols();
482                 pos = 0;
483                 return true;
484         }
485         if (idx > 0) {
486                 idx = 0;
487                 pos = 0;
488                 return true;
489         }
490         return false;
491 }
492
493
494 bool MathGridInset::idxEnd(idx_type & idx, pos_type & pos) const
495 {
496         if (pos < cell(idx).size()) {
497                 pos = cell(idx).size();
498                 return true;
499         }
500         if (col(idx) < ncols() - 1) {
501                 idx = idx - idx % ncols() + ncols() - 1;
502                 pos = cell(idx).size();
503                 return true;
504         }
505         if (idx < nargs() - 1) {
506                 idx = nargs() - 1;
507                 pos = cell(idx).size();
508                 return true;
509         }
510         return false;
511 }
512
513
514 void MathGridInset::idxDelete(idx_type & idx, bool & popit, bool & deleteit)
515 {
516         popit    = false;
517         deleteit = false;
518
519         // delete entire sequence of ncols() empty cells if possible
520         if (idx <= index(nrows() - 1, 0))       {
521                 bool deleterow = true;
522                 for (idx_type i = idx; i < idx + ncols(); ++i)
523                         if (cell(i).size()) {
524                                 deleterow = false;
525                                 break;
526                         }
527
528                 if (deleterow) {
529                         // move cells if necessary
530                         for (idx_type i = index(row(idx), 0); i < idx; ++i)
531                                 cell(i).swap(cell(i + ncols()));
532                         
533                         delRow(row(idx));
534
535                         if (idx >= nargs())
536                                 idx = nargs() - 1;
537                         return;
538                 }
539         }
540
541         // undo effect of Ctrl-Tab (i.e. pull next cell)
542         //if (idx != nargs() - 1) 
543         //      cell(idx).swap(cell(idx + 1));
544 }
545
546
547 void MathGridInset::idxDeleteRange(idx_type /*from*/, idx_type /*to*/)
548 {
549 // leave this unimplemented unless someone wants to have it.
550 /*
551         int n = (to - from) / ncols();
552         int r = from / ncols();
553
554         if (n >= 1) {
555                 cells_type::iterator it = cells_.begin() + from;
556                 cells_.erase(it, it + n * ncols());
557                 rowinfo_.erase(rowinfo_.begin() + r, rowinfo_.begin() + r + n);
558         }
559 */
560 }
561
562
563 MathGridInset::RowInfo const & MathGridInset::rowinfo(row_type row) const
564 {
565         return rowinfo_[row];
566 }
567
568
569 MathGridInset::RowInfo & MathGridInset::rowinfo(row_type row)
570 {
571         return rowinfo_[row];
572 }
573
574
575 std::vector<MathInset::idx_type>
576         MathGridInset::idxBetween(idx_type from, idx_type to) const
577 {
578         row_type r1 = std::min(row(from), row(to));
579         row_type r2 = std::max(row(from), row(to));
580         col_type c1 = std::min(col(from), col(to));
581         col_type c2 = std::max(col(from), col(to));
582         std::vector<idx_type> res;
583         for (row_type i = r1; i <= r2; ++i)
584                 for (col_type j = c1; j <= c2; ++j)
585                         res.push_back(index(i, j));
586         return res;
587 }
588
589
590 void MathGridInset::octavize(OctaveStream & os) const
591 {
592         os << '[';
593         for (row_type row = 0; row < nrows(); ++row) {
594                 if (row)
595                         os << ';';
596                 os << '[';
597                 for (col_type col = 0; col < ncols(); ++col) 
598                         os << cell(index(row, col)) << ' ';
599                 os <<']';
600         }
601         os <<']';
602 }
603
604
605 void MathGridInset::maplize(MapleStream & os) const
606 {
607         os << "array([";
608         for (row_type row = 0; row < nrows(); ++row) {
609                 if (row)
610                         os << ',';
611                 os << '[';
612                 for (col_type col = 0; col < ncols(); ++col) {
613                         if (col)
614                                 os << ',';
615                         os << cell(index(row, col));
616                 }
617                 os << ']';
618         }
619         os << "])";
620 }
621